top


総投稿数 本 
no_

スポンサーサイト

 --------
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
カテゴリ :スポンサー広告 トラックバック(-) コメント(-)
no_786

バックアップとレストア:ブラウザ画面での「バックアップ・レストア」ツールを作る必要にかられたのだが、さて ・・・ 【PHPでツール作成】

 2009-03-16
 久しぶりに、PHPでの開発の記録/メモ。

 ある事情から、次の条件で、
 ・データベース(MySQL) の
  バックアップ・レストアツールを作ることになった

  ・ブラウザ上で動く
  ・Javaなど使えず、PHP + HTML 実装
  ・MySQLデータベース
  ・セキュリティに関して考えられるだけの配慮

 で、どうしたか? その記録。

  追記に ▼

FC2ブログランキングにほんブログ村 IT技術ブログ Webサイト構築へブログ王ランキング人気ブログランキング人気ホームページランキングへ


more  ◇バックアップ・レストアツール
  【方法論考察】
  ※いろいろと方法はあるだろうが、単純に
   ・php からの
    ・データベース・テーブル情報の取得
    ・外部プログラムの実行
    によるツール をつくることにし
   ・セキュリティ
    (特に、コマンドインジェクション)に十分に
    注意してつくること・・・とする
 ◆基本仕様メモ◆
 1:情報の取得
  ・PHP から、mysql_list_tables を利用して
   テーブル情報を取得する
  ・このリストは、実行の際に
   ・コマンドインジェクション対策 として
    ・ホワイトリスト照合に利用する
 2:バックアップ対象の選択
  ・取得したテーブル情報を、フォーム・リストボックス
   で展開し、対象テーブルを選択指定 できるようにする
 3:バックアップ実行
  ・php から、mysqldump コマンドを実行し
   ・テーブル名前とタイムスタンプを組み合わせた
    ファイル名で保存する
 4:レストア
  ・php から、opendir 利用して
   保存されている、バックアップファイルをリスティング
   ・レストアさせる対象ファイルを指定し
   ・外部プログラムとして mysql コマンドを実行し
    レストアする


 ◆1:情報の取得
  ※PHP から、mysql_list_tables を利用
$cknum =0;
$tempArrays_dbtables=Array();
# dbオープン後
$result_temp = @mysql_list_tables('データベース名');
if (mysql_num_rows ($result_temp)>0) {
while ($i < mysql_num_rows($result_temp)) {
$temp_tbname = mysql_tablename($result_temp, $i);
# 条件により 一部のテーブル除く記述を行い
# if (!(ereg("条件",$temp_tbname))) {
array_push($tempArrays_dbtables,$temp_tbname);
$cknum ++;
# }
}
}
mysql_freeresult($result_temp);
 こんな感じ
 ・配列変数:$tempArrays_dbtables に
  対象テーブル名を格納

 ◆2:バックアップ対象
  ※HTMLで、リストボックスを利用し
   テーブル名の配列を展開。
   ・複数選択可能にする
<select name='set_tb1' multiple size=10>
<option value=''>▼バックアップするテーブル</option>
<? for($n_tb=0;$n_tb<sizeof($tempArrays_dbtables1);$n_tb++){ ?>
<option value='<? echo $tempArrays_dbtables[$n_tb]; ?>'><? echo $tempArrays_dbtables[$n_tb]; ?></option>
<? } ?>
</select>
 こんな感じ
 ・multiple size=10

 ◆3:バックアップ実行
  ※php から、外部コマンド mysqldump を実行
   させるわけだが、選択肢がいくつかある
   (基本的には、返り値の違い)

   ◇実行演算子  >>マニュアル
   ・バッククォート (``) の 中身をシェルコマンドとして実行
    !シングルクォートではない
    !出力が返される
(例)※マニュアル記載
<?php
$output = `ls -al`;
echo "<pre>$output</pre>";
?>

    ※方法としては簡単だな。
     これと同じ意味合いの方法で、

   ◇shell_exec( string $cmd )  >>マニュアル
   ・シェルによりコマンドを実行し、文字列として出力全体を返す
    !出力が返される:実行されたコマンドからの出力
(例)※マニュアル記載
<?php
$output = shell_exec('ls -lart');
echo "<pre>$output</pre>";
?>

    ※ただ、今回、mysqlgump をこれで行うと
     エラーが発生しているにも関わらず出力が行われなかった。
     (このエラーについては、後述)

   ◇exec( string $command [, array &$output [, int &$return_var ]] )  >>マニュアル
   ・外部プログラムを実行
    !引数 output が存在する場合、指定した配列は、
     コマンドからの出力の各行で埋められる(配列で返ってくる)
    !配列に既に何らかの要素が 含まれる場合は、
     exec() は配列の最後に追加される(困る場合は、事前に unset()
    !返り値は、コマンド結果の最後の行

   ◇passthru( string $command [, int &$return_var ] )  >>マニュアル
   ・外部プログラムを実行し、未整形の出力を表示
    !引数return_var が存在する場合、
     Unix コマンドのステータスがこの変数に書かれる
    !返り値は、無し

  ・・・ということで、今回は、「passthru」を採用
$timestamp_str = date('Ymd');
$sys_mysqldir="*****";
$from_table = "table名";
$to_dirfile = "*****".$timestamp_str."_".$from_table.".dump";
$command = $sys_mysqldir."mysqldump -u *** `db名` > '".$to_dirfile."'";
$rt_command = passthru($command,$return); # $rt_command には何も返らないけれども
 ※伏字ばかり多くて申し訳ない
 ・ここで、慎重にセキュリティ対策
 ・コマンドインジェクション対策として
  やはり、一番有効なのは「ホワイトリスト」方式だろう
  ・$from_table を生成するところで、あらかじめ得ている
   テーブルリスト内のものであるかの照合を行い、
  ・さらに escapeshellarg ( string $arg ) を利用して
   値をエスケープ処理を行う

  これで、問題なければ
  指定ディレクトリ(書き込み可能)に、
  「タイプスタンプ_テーブル名前.dump」ファイルが作成される

  4:レストア では、
  これを、リスティングし、フアイル指定して組み込む
  手続きを用意すればいいわけだ。
  では、

   ・・・ の、その前に

 ◆mysqldump のエラー
  ※今回、複数のデータベースでのテストの際、ある
   巨大なデータベースでエラーが発生。

   ・コマンドラインで操作した場合は
mysqldump: Got error: 1016: Can't open file: '*****.frm' (errno: 24) when using LOCK TABLES
 となる
   ・(ところが)上記、phpのブログラムでは、
    そこまで詳細な情報は得られず、
    引数return_var に格納されたのは、数値の 2 だった。
    (うまくいった場合には、0)

   ・この格納される値については、また調べるけれども、
    とにかく今回のエラー
    ・文意を考えると、該当のテーブルが使われている(?)
     ・・・ということだが、そんなはずはない。

    ・で、いろいろ調べてみると
     「テーブル数が、設定のリミットを越えている場合、この種のエラー」
     が出るらしい。
     >> [22 Aug 2006 18:36] Miguel Solorzano

   ・現在の設定(open_files_limit)を調べると、
    (デフォルトだと思うが) 
mysql> show variables like 'open_files_limit' ;
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| open_files_limit | 1024 |
+------------------+-------+
1 row in set (0.00 sec)


    ・実際のテーブル数は1106。確かに多い

    ・my.cnf の設定を変えて、
[mysqld]
open_files_limit=2048
 再挑戦 ・・・だめだ
    ※実際のテーブル数だけでなく、メッセージにあるように
     .frm ファイルなどの数も関係あるようだ。

    ・大きく変更
[mysqld]
open_files_limit=4096
 動いた。
    ※後は、パフォーマンスとの調整だな。

   さて、
    ・バックアップファイルはできた。
    ・後は、指定してレストア できる部分だ。
 ◆4:レストア
  ※php で、特定のバックアップ専用ディレクトリを走査し
   ファイルをリスティングする
$tempArryas =Array();
$dir = "*****";
$oknum=0;
if( $handle = opendir( $dir ) ) // ディレクトリハンドルを獲得
{
$tree = array();

while( false !== $file = readdir( $handle ) ) // ファイル名獲得
{
if( $file != "." && $file != ".." ){
if( is_dir( $dir."/".$file ) ){
}else{
$tree[ $file ] = $dir."/".$file;
if(file_exists($tree[ $file ])){
$tempArryas[$oknum]=$file;
$oknum++;
}
}
}
}
closedir( $handle ); // ディレクトリハンドルを閉じる
}
 こんな感じ

   これを、やはり、HTML・フォームの
   リストボックス利用して、選べるようにして、選んだ後、
   今度は、mysqldump ではなく、musql コマンドで
   組み込めるようにする。
# $set_dump_table にリストエリアからの値を代入し
# ここにもインジェクション対策は当然必要
$sys_mysqldir="*****";
$from_dirfile = "*****".$set_dump_table.".dump";
$command = $sys_mysqldir."mysql -u *** `db名` < '".$from_dirfile."'";
$rt_command = passthru($command,$return);


 ・・・という感じで作成。
 この作業により、改めて確認した知識は

  ・テーブル情報の取得
  ・外部プログラムの実行関連
  ・コマンドインジェクション対策へのホワイトリスト対応
  ・ファイル操作の方法とハンドリング
 ・・・だった。

 で、まぁここまで書いといてなんなのですが、
 オープンソースの
phpMyBackupPro
phpMyBackupPro ・phpMyBackupPro v.2.1 に
  加えて
 ・Japanese v.1.8 の
  日本語化ファイルが
  用意されている


 これ、便利そう、ですよね。
 (まだ、試してはいない・・・)
commentsコメント
comment_post












管理者にだけ表示を許可する
commentトラックバック
トラックバックURL:
http://metaboy.blog23.fc2.com/tb.php/786-de2d7ddc
ようこそ
Add to Google 創るmetaboy:RSSフィード
My Yahoo!に追加
最新記事のRSS | 問い合わせ

仕事検索、アルバイト検索、依頼仕事の検索ポータル - 仕事検索.COM - www.jobkensaku.com ツクルン

創るmetaboy - WEB創る、サイト創る、何創る - 創ったmetaboy

 

リンク集

 

最近の記事

 

ブロとも申請フォーム
Sponserd by

さくらのレンタルサーバ さくらのレンタルサーバ
大容量・高機能レンタルサーバー heteml 大容量・高機能レンタルサーバー heteml
XREA (ValueDomain)
お名前.com お名前.com
名づけてねっと名づけてねっと
ムームードメインムームードメイン

 

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。