SQLiteでWordPressを動かしても、自動バックアップを試みる

この記事は約7分で読めます。

WordPressのバックアップはBackWPupというプラグインが有名らしい。さくらインターネットでもおすすめだ。是非導入してみたいと色々調べたが、どうにもSQLiteだとまともに動かないらしい。BackWPupのソースやデータベースにパッチを当てるのもいいけど、勝手にアップデートされて肝心なときに復元できないのは困った事態になる。
有名では無くてもいいからSQLiteに対応しているバックアッププラグインは無いものか?と調べてみたが、全く情報がなかった。。。

SQLiteのデータベースファイルのバックアップは非常に簡単で、ファイルをコピーするだけで良いらしい。実際に何度かファイルコピーでバックアップをして、データベースの中身を見ているが、異常がおきたことは無い。せめてデータベースのファイルだけでも自動バックアップができないだろうか?と色々調べたが、どうにも自分で作るしかなさそうだ。。。

ということで、意を決して20年ぶりくらいにPHPのマニュアルと格闘しながら自動バックアップスクリプトを作ってみた。
さくらインターネットのライトプランはcronは使えない。代わりにWordPressに備わっているcronを利用することにする。この手の自作プログラムはテーマファイルにあるfunctions.phpに追加するのが一般的とのことだ。
自分の場合は、Cocoonテーマの./wp-content/themes/cocoon-child-master/functions.phpを編集した。ファイルの一番下にある
//以下に子テーマ用の関数を書く
から下に以下を追記する。

//以下に子テーマ用の関数を書く

//
//SQLite環境の簡易バックアップ
//
const NOUNO_AT_BAK_DIR = '/home/hogehoge/backup';  // バックアップ先
const NOUNO_AT_ZIP_ARC_GEN = 5;  // ZIP保存世代数

// バックアップ自動実行用関数
function nouno_auto_backup() {
  if (!file_exists(NOUNO_AT_BAK_DIR.'/database')) {
    mkdir(NOUNO_AT_BAK_DIR.'/database', 0705, true);
  }

  chdir(NOUNO_AT_BAK_DIR);

  unlink('./database/.ht.sqlite.bk7');  // 7日目を削除

  for($i=7;$i>1;$i--) {  // 7日分のみを保存
    rename('./database/.ht.sqlite.bk'.strval($i-1),'./database/.ht.sqlite.bk'.strval($i));
  }

  exec('cp '.WP_CONTENT_DIR.'/database/.ht.sqlite ./database/.ht.sqlite.bk1 > /dev/null 2>&1 &');  // SQLiteデータベース
  exec('rsync -au --delete '.WP_CONTENT_DIR.'/plugins ./ > /dev/null 2>&1 &');
  exec('rsync -au --delete '.WP_CONTENT_DIR.'/themes ./ > /dev/null 2>&1 &');
  exec('rsync -au --delete '.WP_CONTENT_DIR.'/uploads ./ > /dev/null 2>&1 &');
}
add_action ( 'nouno_auto_backup_cron', 'nouno_auto_backup' );
 
if ( !wp_next_scheduled( 'nouno_auto_backup_cron' ) ) {
  date_default_timezone_set('Asia/Tokyo');
  wp_schedule_event( strtotime('2024-08-27 03:15:00'), 'daily', 'nouno_auto_backup_cron');
}

// ZIPアーカイブ自動実行用関数
function nouno_auto_zip_archive() {
  if (!file_exists(NOUNO_AT_BAK_DIR.'/archive')) {
    mkdir(NOUNO_AT_BAK_DIR.'/archive', 0705, true);
  }

  chdir(NOUNO_AT_BAK_DIR);

  unlink('./archive/wp_backup_'.strval(NOUNO_AT_ZIP_ARC_GEN).'.zip');

  for($i=NOUNO_AT_ZIP_ARC_GEN;$i>1;$i--) {  // 世代分のみを保存
    rename('./archive/wp_backup_'.strval($i-1).'.zip','./archive/wp_backup_'.strval($i).'.zip');
  }

  exec('zip -n .jpg:.jpeg:.mp4:.mpg:.mpeg:.png:.gif:.webm:.webp ./archive/wp_backup_1.zip -r database plugins themes uploads > /dev/null 2>&1 &');

}
add_action ( 'nouno_auto_zip_archive_cron', 'nouno_auto_zip_archive' );

if ( !wp_next_scheduled( 'nouno_auto_zip_archive_cron' ) ) {
  date_default_timezone_set('Asia/Tokyo');
  wp_schedule_event( strtotime('2024-08-27 01:50:00'), 'weekly', 'nouno_auto_zip_archive_cron');
}

NOUNO_AT_BAK_DIRで指定したフォルダは、.htaccess等でアクセス制限が必要です。他人が閲覧可能になってしまいます
スケジュールの「2024-08-27」の日付は未来日付に変更してください。致命的エラーになることがあるようです。

機能的にはバックアップ先に、

  • SQLiteのデータベースについては、ファイル名を変更して7日分を毎日バックアップ保存
  • plugins,themes,uploads ディレクトリについて毎日上書バックアップ(世代管理はしない)
  • 毎週SQLiteのデータベースと、plugins,themes,uploadsについてzip圧縮して世代管理(今のところ5世代)

という簡単なものだ。NOUNO_AT_BAK_DIRで指定したディレクトリにバックアップデータが自動でコピーされる。簡単ではあるけれど、全く無いよりは全然良いだろう。結果としてデータベースについては毎日35日分、その他は毎週で5週分が履歴として保存され、それ以上は自動削除されるようになっている。保存期間の調整をしたければNOUNO_AT_ZIP_ARC_GENの数字を変更すれば良い。
一応、月に一回くらいは自分のPCへダウンロードしておくつもりだ。

このソースはもしかしたら「さくらインターネット」限定かもしれない。ファイルコピーにはOSの機能を使用している。「rsync」コマンドはサーバーを探検して見つけた物だ。さくらインターネットで使えるコマンド一覧を紹介しているが、ここに記載が無いしレンタルサーバコントロールにも記載がなかった。もしかしたら非公開なのかもしれない。
本当はファイルコピーコマンドの「cp -u」を使用して、新しいファイルか新規追加ファイルだけをコピーするようにして高速化を図りたかったが、FreeBSDの「cp」コマンドにはオプションが無いらしく、代わりに「rsync」を使っている。

バックアップだがOS側のコマンドを使う代わりに、変更の差分のみをコピーするので非常に高速だ(最初の一回目だけちょっと遅い)
しかもSQLite,plugins,themes,uploadsの各フォルダのバックアップコピーは、マルチプロセスで同時に行われる。そのため今のところ2~3秒でバックアップが終わる。さらにコピーが終わる前にWordPress側に制御を戻すのでレスポンスにも影響が無いはずである。

毎週のzip圧縮も同様で、画像や動画ファイルについては意図的に圧縮せずに高速化をしている。こちらも数秒で完了する。わざわざzip圧縮にしているのは自分のPCで扱いが楽なためだ。

手動で実行したい場合は「WP Crontrol」から、「今すぐ実行」を選べば良い。手抜きはしているけど、簡易的なバックアップシステムとしては十分かな?
ちなみにバックアップ時刻が微妙なのは、人気のBackWPupのデフォルトが3時ちょうどの実行なので、この時間は何処のサーバーも負荷が高いらしい。意図的にズラしてみた。

それにしてもWordPressをSQLiteで動かす紹介をしているサイトは多いのに、まともに動かす紹介をしているサイトは無いのだろう。。。
やっぱり優秀なエンジニアはお給料が良いから、わざわざSQLiteで苦労するようなことは無いのかな。。。

コメント