PHPでファイルとDB(PostgreSQL)をバックアップ

レンタルサーバーでも自動バックアップのサービスを提供しているところも増えてきましたが、安価なプランでは使えない場合もあります。
(実際、このブログで使っているVALUE SERVERではビジネスプランでしか提供されていません)

とはいえ、安価な月額180円のエコプランでもcronジョブ(Windowsでいうタスクスケジューラーのようなもの)なら10個まで登録できたりするので、PHP等で任意のディレクトリへファイルをコピーしたり、データーベースのバックアップをしたりするスクリプトを組めば良いでしょう。

参考になるか微妙ですが、実際にうちでやっている例をご紹介。

PHPで対象ディレクトリをバックアップする例

■PHPスクリプト例

$target = '/virtual/アカウント名/public_html/';
$backup = '/virtual/アカウント名/backup/';
backup_dir($target, $backup.date("Ymd").'_files.zip');

/************************************************
 * 特定ディレクトリのバックアップ処理
 ************************************************/
function backup_dir($target, $zipfile)
{
    //カレントディレクトリをバックアップ対象のディレクトリへ移動する
    chdir($target);
    system("zip -r {$zipfile} . > /dev/null");
}

※VALUE SERVERでは/virtual/の下にアカウント名のディレクトリが割り当てられるため適宜修正してください

わざわざ例にするほどかよっ!というくらいシンプルですが、

  1. chdir関数でバックアップ対象のディレクトリへ移動
  2. ファイル名に日付(YYYYMMDD)の付いたZIPファイルへ圧縮する

だけです。

zipコマンドの -r はサブディレクトリも含めて圧縮するというオプションで、対象ディレクトリは “.” カレントディレクトリを指定しています。

/dev/nullへリダイレクトしているのはサーバー側の仕組みによってはコマンドラインに表示されたメッセージを管理者へメールする設定になっていたりするためですね。

この例には載せていませんが、バックアップの失敗や、サイトが正常動作しているかの確認は別のスクリプトを定期実行して確認しているため、ここでコマンドラインの表示をメールしてもらわなくても良いという考えです。

また、サイトの作りによって違いますが、毎回public_html以下を全部バックアップする必要はあまりないので、通常はよく更新されるディレクトリだけ対象にしてバックアップを取っています。
(例えば、掲示板を運営していたらそのログや添付画像が格納されるディレクトリとか)

それから、こんな単純なコードでもわざわざbackup_dirを関数化しているのは1つのアカウントで複数のサイトを運営しているためです。うちの場合は運営しているサイトの数だけzipファイルを作って、最後にまとめてFTPでダウンロードしています。

PHPでPostgreSQLをバックアップする例

■PHPスクリプト例

$backup = '/virtual/アカウント名/backup/';
//カレントディレクトリをバックアップ用パスにする
chdir($backup);
//PostgreSQLをバックアップし、YYYYMMDD_スキーマ名.zipを作る
backup_db('データベース名', 'パスワード', 'public');

function backup_db($dbname, $dbpass, $schema)
{
    //DBダンプ実行
    $filename = date("Ymd").'_'.$schema;
    putenv("PGPASSWORD={$dbpass}");
    system("/usr/bin/pg_dump --schema={$schema} --encoding=UTF-8 --column-inserts --no-owner --username={$dbname} --file={$filename}.sql {$dbname}");
    putenv("PGPASSWORD=");
    //圧縮
    system("zip {$filename}.zip {$filename}.sql > /dev/null");
    //元ファイル削除
    unlink("{$filename}.sql");
}

MySQLの場合はmysqldumpコマンドに直接パスワードを渡すことができるので、PHPでもそのまま指定すれば良いだけですが、PostgreSQLの場合はpg_dumpコマンドにパスワードを指定するオプションがないため、ちょっと悩む人もいるかも知れませんね。

PostgreSQLの場合は環境変数PGPASSWORDを参照するので、pg_dumpコマンド実行前にputenv関数で環境変数にパスワードを設定してあげればOKです。

また、上述の例ではpg_dumpに下記のようなオプションも付けていますが、お好みで。

––schemaスキーマを指定
––column-inserts列名を付けたINSERT文を出力する
––no-owner所有権を設定するコマンドを出力しない

うちの場合はよくレンタルサーバーを変更しますし、そのときにPostgreSQLからMySQLへデータベースも変更、なんてこともよくやるので、なるべく綺麗なINSERT文を出力しておきたいですし、所有権コマンドを出力しないのもそのためです。

あと書いておいて何ですがスキーマの指定については不要かも知れませんね。

以前は用途ごと、あるいはサイトごとにスキーマをわけて管理していましたが、MySQLにはスキーマの概念がないですし、よくあるオープンソースでもプレフィックス(WordPressならwp_とか)をテーブル名に付ける習慣があるようなので、PostgreSQLを使うときもpublicしか使わないことが多くなりました。

まとめ

もしかしたら、シェルスクリプトでも出来るようなことなのかも知れませんが、うちはPHPで実行しています。

というのも、ローカルにテスト環境を作る場合もWindows版のApacheとPHPを使ったほうが楽だったりしますし、そんなときシェルスクリプトだとWindows上で動かすために(cygwinとかの)また一工夫必要になってしまうんですよね。

なので、PHPで出来ることならPHPで実装しておき、Linux上でもWindows上でも動作するようにしてしまえ、と考えてこうした自動バックアップ処理なんかもPHPで組んでいます。

更に、レンタルサーバーのプランによってはcronジョブが1つしか登録できないというケースもありますし、そんなときPHPで全部やっておいたほうが、何かと融通が利くと思うのです。上述の例ではファイルのバックアップとデータベースのバックアップをそれぞれ別個に紹介していますが、実際は1つのスクリプト内で全部済ませています。

最後に、backup用ディレクトリに置いたzipファイルをFTPでダウンロードする処理もあるのですが、これはまた機会があれば別記事で紹介できればと思います。