PHPだけで指定ディレクトリをバックアップしたいと思っています。


例えば
/web_site
 /html   ・・・一般公開用ディレクトリ
 /sysytem  ・・・PHPシステム用ディレクトリ
/backup ・・・バックアップ保存ディレクトリ
backup.php ・・・バックアップを実行するPHPファイル

というファイル構造でbackup.phpをcronなどで実行すると、/web_siteにあるファイル・ディレクトリがすべて/backupにコピーされていると言ったイメージです。

これまではopendir関数を使ってコピー元ディレクトリを開き、その中のファイルをcopy関数を使ってコピー先ディレクトリにコピーしてました。

しかし、もっと手軽に・完結・高速に出来る方法がないかと思い、質問します。
出来れば環境依存しない方法で、使える関数・ソース構造のヒントを教えていただければと思います。

回答の条件
  • URL必須
  • 1人2回まで
  • 登録:2007/03/23 06:21:48
  • 終了:2007/03/29 04:39:00

回答(5件)

id:Mook No.1

Mook回答回数1312ベストアンサー獲得回数3912007/03/23 12:12:30

ポイント50pt

cron ということは OS は Linux か UNIX だと思いますが、cron であればコマンドやシェルスクリプトで書けばよいと思うのですが、PHP で行いたいという理由は何でしょうか。


◆cron の方法

0 0 * * cp -r "/web_site" "/backup"

◆シェルスクリプト での方法

0 0 * * backup.sh

backup.sh

#!/bin/sh
    srcDir="/web_site"
    dstDir="/backup"
    cp -r "$srcDir" "$dstDir"

この利点は、スクリプトを単体で実行することができる点でしょうか。

◆php の方法(system)

(cron の起動部分は省略)

<?php
    define( "srcDir", "/web_site" );
    define( "dstDir", "/backup" );
    system( 'cp -r "'.srcDir.'" "'.dstDir.'"' );
?>

system 関数は、結局コマンドを呼び出すので、上記と変わりません。この php を呼び出す部分が冗長なだけ、シェルスクリプトより手間でしょうか。


◆php の方法(PHP 関数:PHP サンプルより)

<?php
    define( "srcDir", "/web_site" );
    define( "dstDir", "/backup" );
    dircopy( srcDir, dstDir );

    function dircopy($srcdir, $dstdir, $verbose = false) {
      $num = 0;
      if(!is_dir($dstdir)) mkdir($dstdir);
      if($curdir = opendir($srcdir)) {
       while($file = readdir($curdir)) {
         if($file != '.' && $file != '..') {
           $srcfile = $srcdir . '\\' . $file;
           $dstfile = $dstdir . '\\' . $file;
           if(is_file($srcfile)) {
             if(is_file($dstfile)) $ow = filemtime($srcfile) - filemtime($dstfile); else $ow = 1;
             if($ow > 0) {
               if($verbose) echo "Copying '$srcfile' to '$dstfile'...";
               if(copy($srcfile, $dstfile)) {
                 touch($dstfile, filemtime($srcfile)); $num++;
                 if($verbose) echo "OK\n";
               }
               else echo "Error: File '$srcfile' could not be copied!\n";
             }                 
           }
           else if(is_dir($srcfile)) {
             $num += dircopy($srcfile, $dstfile, $verbose);
           }
         }
       }
       closedir($curdir);
      }
      return $num;
    }
?>

この PHP 関数だけでやるメリットは、UNIX でも Windows でも動く点かもしれません(もちろんパスの記述方法は変わりますが)。

もっともWindows でコマンドでやるとしても、コピー程度であれば cp を xcopy に変えるだけですが。


注:上記全てに共通することですが、ファイルパスを””で囲う必要は必ずしもないですが、パス中にスペースが入る場合を考慮して、””を使用しています。

id:kt26

PHPのみで動かしたいと思ったのは、WEBシステムの管理ページなどから、手動(ボタンなどを押して)バックアップを実行したいからです。(それにcronが使えないサーバもありますし)

サーバはレンタルサーバを中心に考えていますので、Windowsは想定していません。

ただ、最後の「php の方法」で記述されているソースでは私の求めている「手軽に・完結・高速に」に当てはまるのでしょうか?

結局は、copy関数を使って一つずつファイルをコピーしていく方法と変わらない気もするのですが・・。(そういう方法しかないと言う事でしたら、それで納得します。他にもっと手軽に出来るのかな?っと思って質問しました)

2007/03/23 13:53:38
id:Mook No.2

Mook回答回数1312ベストアンサー獲得回数3912007/03/23 14:40:52

コメントが有効になっていれば、そちらで回答したい内容なのですが、無効なのでこちらで失礼します。

(こちらの開封ポイントはお返しいたします。)


PHP でやりたいという理由は納得しました。最初からその目的を書かれていると、判りやすかったかと思います。

(cron からと書かれている点からは、このような目的は推測できませんでした。)


>結局は、copy関数を使って一つずつファイルをコピーしていく方法と変わらない気もするのですが・・。

に関しては、まったくおっしゃる通りです。PHP 自身にはフォルダ単位でファイルをコピーする機能がないので、このような処理が必要になります。

「手軽に・簡潔に・高速に」にはそぐわないかもしれませんが、「保守性に優れた・汎用性のある」コード例だと思います。

(それでも、サブフォルダに関しては再帰呼出しをしていて、ただのループよりはスマートに書かれていると思いますが。)


パフォーマンスを求めるのでなければ(大量のファイルでなければ、それほど変わらないとは思いますが)、汎用性のあるコードを利用するのは大切なことかと思います。

PHP 基礎編3 - 標準ファイル

id:kt26

cronについてはあくまで「cronなど」という書き方にし、cronで動かす事を必須としていません。タイトルも「PHPだけ」として質問したつもりでしたが、誤解を招いた内容であれば、申し訳ありません。

また、失礼ですが貴方様の最後に記述されたコードを試しにテストしてみたのですが、PHP5のサーバでは問題なく動きますが、レンタルサーバなどのPHP4のサーバでは動きませんでした。

質問にも書きましたが、環境依存しない形であれば良かったのですが、このように「動く時・動かない時」というのが発生します。それが懸念するところであり、気になったのもあります。

とりあえず、他者様の意見もいただければと思います。

2007/03/23 15:14:57
id:kurukuru-neko No.3

kurukuru-neko回答回数1844ベストアンサー獲得回数1552007/03/23 20:00:44

>opendir関数を使ってコピー元

>ディレクトリを開き、その中のファイルを

>copy

使える機能はファイル操作とディレクトリー

操作程度の限定された条件では質問に

ある事が速度的な改善は期待できません。

バックアップを早くするのが目的であれば

話が違います。基本的に二回目以降は

差分でよいはずです。

コピー処理ではなく差分処理を考えた

方がよいと思います。

1.現在のファイル一覧作成

2.以前のバックアップ一覧と比較する

  1.にないファイルは削除、

  2.にないファイルは追加

  2.でコピーした後変更されたものは

    再度コピー

3.バックアップファイル一覧保存

ファイル一覧が面倒な場合は

コピー時コピー元と同じ最終更新時刻を

touch/属性をchmod/chown/chgrpで設定

するとする。

1.削除処理

  バックアップを全て調べて元の

  ファイルがない場合削除する。

  元のディレクトリーがない場合は、

  ディレクトリー以下全てを消す。

  

2.更新処理

  ディレクトリーを検索してコピーを

  する。 既にファイルがある場合

  ファイルの更新日付、ファイルサイズが

  一致している場合コピーをしない。

  コピーしたファイルの更新日付/権限を

  設定する。

http://jp.php.net/manual/ja/function.touch.php

id:kt26

>使える機能はファイル操作とディレクトリー操作程度の限定された条件では


限定していませんが・・・。というか、それは私が”これまでやってきた方法”を書いているだけで、おっしゃるようにそれだけでは速度改善が見込めないし、環境依存した場合どうしたらいいかと思い、質問した次第です。


出来れば、質問文をきちんとお読みいただければ良かったです。

2007/03/23 21:43:58
id:arcana No.4

arcana回答回数120ベストアンサー獲得回数102007/03/23 23:22:40

ポイント40pt

環境依存しない点に重点を置く場合は /bin/sh のシェルスクリプトで、

作成することが一番と思います。

Lunix でも UNIX 系でも sh が入っていないことはありませんしね。

Web からの実行であれば、Perl でも PHP でも exec や system 関数で、

その shell を呼び出せば良いだけですし。

※PHP の場合 SafeMode だと使用可能な関数に制限がありますが…


で、PHP の話ですが、kt26さんもご認識の通りに PHP の基本関数では、

ディレクトリを対象とした操作では、中身を一括で!ということは出来ません。

環境依存しますが、昔に PHP-users で、似た話題を見ました。

[PHP-users 26958] ディレクトリコピー


結論ですが。

【PHP で完結させたい場合】

kt26 さんも実践されている通りな手法しかない気がします。

但し、これには拘っていない様子なので。


【環境依存しない方向の場合】

/bin/sh でバックアップスクリプトを組む。

Perl or PHP から exec もしくは system などの外部呼び出し関数で、

バックアップスクリプトを呼び出す。

【極力簡素なソースに納める場合】

Perl or PHP 中に exec もしくは system などの外部呼び出し関数で、

直接 cp or tar などの OS 標準コマンドを呼び出してしまう。


今の要件だと、それぞれが別方向にあり、どこの中間を取れば良いのか、

迷ってしまうので、最低要件と付加価値を分けて箇条書き記載した方が

良かったかもしれません。

※Web から実行といった時点で、どこまでが環境依存の境界なのか、

 それとも無理ならそれは切り捨てて良いのか、などや

 手軽を重視すると、環境に依存しまくり…みたいなことが

 あると思いますので。

id:kt26

丁寧にご回答いただきありがとうございました。

PHP-usersで質問されている方と同じような悩みだと思います。

「セーフモードの場合は」などと要件を書いた方が良かったですね。失礼しました。

2007/03/24 00:20:54
id:kurukuru-neko No.5

kurukuru-neko回答回数1844ベストアンサー獲得回数1552007/03/23 23:54:49

ポイント10pt

>質問文をきちんとお読みいただければ

>良かったです。

読んだ上での回答です。

PHPはパッケージ(拡張モジュール)の塊です。

全部が使えるとは限りません。

http://pear.php.net/packages.php

サーバーでのパッケージの組込み状況

は事前に実行時にしか判断出来ません。

最悪条件を想定での方法として回答しました。

DB,アーカイブ、圧縮パッケージを

使う方法もあるかもしれませんが

組み込まれていない可能性があります。

http://pear.php.net/packages.php

PHPのコアに含まれる

http://jp.php.net/manual/ja/extensions.php

ディレクトリ関数

ファイルシステム関数

は最低限利用可能と思われます。

× 変数や型に関連する拡張 

× テキスト処理

× PHP の振る舞いを変更する

× セッション拡張

× その他の基本拡張

△ データベース拡張

△ ベンダ固有のデータベース拡張

× XML 操作

× Web サービス

× クレジットカード処理

× 数学的な拡張

× 暗号化拡張

× 自然言語と文字エンコーディングのサポート

△ ファイルシステムに関連する拡張

× プロセス処理拡張

× メールに関連する拡張

× 認証サービス

△ その他のサービス

△ 圧縮に関連する拡張

× カレンダーやイベントに関連する拡張

△:使える可能性多少ある

×:使えない

現状利用されている

ディレクトリ関数+ファイルシステム関数

だと圧縮か、DB等をアーカイブに利用する

方法くらいしか考えられない。

======================================

公開されているphpinfo

http://www.cpi.ad.jp/service/server/function/cgi/php.html

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません