[WordPress] WordPress関数が使えるバッチのサンプル

tanuki

Wordpressの共通関数を使えるバッチのサンプルを作ってみた。
最終的にはこのバッチを使ってAmazonのKindleストアでセール中のラノベ情報をWordpressのカスタム投稿に入れたいと思う。
とにかくもうセールを逃したくないっ。

主な機能
  • コマンドラインからの実行のみ許可
  • 引数のチェック
  • log4phpでログ出力
  • ロックファイルによる2重起動防止
  • WordPressの共通関数のロード

log4phpによりログをファイルに出力したいので
composerというパッケージ管理ツールを用いてインストールする。

まずはテーマフォルダ(wordpress/wp-content/themes/現在使用中のテーマフォルダ)に移動し、
composerをインストールする。

/// composerをインストール ///
# curl -s http://getcomposer.org/installer | php

引き続きlog4phpインストールの為のjsonファイルを作成し、composerコマンドを実行する。

/// log4phpのインストール用json ///
# vi composer.json
{
  "require": {
    "apache/log4php": "2.3.0"
  }
}

/// log4phpのインストール ///
# php composer.phar install

テーマフォルダ直下にvendorフォルダが作成されてそこにインストールされる。
ディレクトリ構成はこんな感じ

テーマフォルダ
├───batch_sample.php  - バッチサンプル
├───composer.json     - composerの設定ファイル
├───vendor            - composerでインストールした拡張モジュールの格納ディレクトリ
├───log4php.xml       - log4php設定ファイル
└───lock    
    └───batch_sample - 2重起動防止のロックファイル(起動中バッチのPIDが入ってる)

/var/log
└───wordpress      
    └───my-app.log    - ログファイル
<?php
/**
 * Template Name: バッチサンプル
 *
 * 引数1と引数2を受け取って現在の投稿件数を表示します。
 *
 * @package WordPress
 * @subpackage prj2501
 */

/*
| -------------------------------------------------------------------------
| コマンドラインからの実行のみ許可します。
| -------------------------------------------------------------------------
*/
(php_sapi_name() == 'cli') OR exit('ブラウザからのダイレクトアクセスは許可していません。');

/*
| -------------------------------------------------------------------------
| コマンドラインからの引数をチェックします。
| -------------------------------------------------------------------------
*/
// コマンドの使い方
$usage = <<<EOT
構文
  batch_sample.php [オプション]

オプション
  --arg1=引数1     一つ目の引数を指定します。
  --arg2=引数2     二つ目の引数を指定します。

EOT;

// 引数をマップに変換
$arry = arguments($argv);

// 引数のチェック
if (count($arry) < 2) {
  echo $usage;
  exit(1);  
}

$_ARGV = array();
foreach ($arry as $key => $value) {
  switch ($key) {
    case "arg1":
      $_ARGV['arg1'] = $value;
      break;
    case "arg2":
      $_ARGV['arg2'] = $value;
      break;
    default:
      echo $usage;
      exit(1);
   }
}

/*
| -------------------------------------------------------------------------
| WordPressの共通関数をロードします。
| -------------------------------------------------------------------------
*/
define('BASEPATH', '/usr/share/nginx/www.prj2501.red/html/wordpress');

define('WP_USE_THEMES', false);
require_once(BASEPATH.'/wp-load.php');
$template_path = get_template_directory( );

/*
| -------------------------------------------------------------------------
| Composerのパッケージをロードします。
| -------------------------------------------------------------------------
*/
$_SERVER = array(
  "HTTP_HOST" => "www.prj2501.red",
  "SERVER_NAME" => "www.prj2501.red",
  "REQUEST_URI" => "/wordpress",
  "REQUEST_METHOD" => "GET",
  "HTTP_USER_AGENT" => "prj2501"
);
require_once($template_path.'/vendor/autoload.php');

/** ログ */
Logger::configure($template_path.'/log4php.xml');
$basename = basename(__FILE__, '.php');

$log = Logger::getLogger($basename);

/*
| -------------------------------------------------------------------------
| 二重起動を防止します。
| -------------------------------------------------------------------------
*/
$pid_file = $template_path.'/lock/'.$basename;

if(file_exists($pid_file)){
  $pid = file_get_contents($pid_file);
  // kill -0はプロセスが存在すればなにも返さない(killもしない)
  system("kill -0 {$pid}", $retval);

  if ($retval) {
    unlink($pid_file);
    $log->info('PIDファイルを削除しました。PID='.$pid);
  } else {
    $log->error('既にバッチが起動中です。PID='.$pid);
    exit(1);
  }
}

// PIDファイルの作成
system('echo '.getmypid().' > '.$pid_file, $retval);
if ($retval) {
  $log->error('PIDファイルの作成に失敗しました。pid_file='.$pid_file);
  exit(1);
}

/*
| -------------------------------------------------------------------------
| メイン処理を行います。
| -------------------------------------------------------------------------
*/
$log->info($basename.'を開始します。');
$time_start = microtime(true);

$log->info('batch_sample.phpを引数1='.$_ARGV['arg1'].',引数2='.$_ARGV['arg2'].'で実行します。');

// $wpdbで投稿件数を取得
$sql =<<<EOT
SELECT COUNT(*) AS post_count
FROM $wpdb->posts
WHERE post_status = 'publish'
EOT;

$results = $wpdb->get_results($sql, OBJECT);
$log->info('投稿件数は'.$results[0]->post_count.'件です。');

// PIDファイル削除
unlink($pid_file);

// 処理時間の測定
$time_end = microtime(true);
$time = $time_end - $time_start;
$log->info($basename.'を終了します。処理時間='
    .sprintf("%02d:%02d",$time / 60, $time % 60)
    .'('.sprintf('%0.5f', $time).'秒)');

// 処理終了
exit(0);


/**
 * 引数をマップに変換します。
 * @param array $argv コマンドライン引数
 * @return array 引数マップ
 */
function arguments($argv) {
  $arry = array();
  foreach ($argv as $arg) {
    if (ereg('^--([^=]+)=(.*)', $arg, $reg)) {
      $arry[$reg[1]] = $reg[2];
    } elseif(ereg('^-([a-zA-Z0-9])', $arg, $reg)) {
      $arry[$reg[1]] = $reg[1];
    }
  }
  return $arry;
}

実行結果

/// 引数を入れなかったら説明が出る ///
# php batch_sample.php
構文
  batch_sample.php [オプション]

オプション
  --arg1=引数1     一つ目の引数を指定します。
  --arg2=引数2     二つ目の引数を指定します。


/// 正常動作 ///
# php batch_sample.php --arg1=value1 --arg2=value2
INFO - batch_sampleを開始します。
INFO - batch_sample.phpを引数1=value1,引数2=value2で実行します。
INFO - 投稿件数は83件です。
INFO - batch_sampleを終了します。処理時間=00:00(0.06450秒)


/// バッチのログ ///
# cat /var/log/wordpress/my_app.log
2016-02-20T00:29:36+00:00 batch_sample INFO  batch_sampleを開始します。
2016-02-20T00:29:36+00:00 batch_sample INFO  batch_sample.phpを引数1=value1,引数2=value2で実行します。
2016-02-20T00:29:36+00:00 batch_sample INFO  投稿件数は83件です。
2016-02-20T00:29:36+00:00 batch_sample INFO  batch_sampleを終了します。処理時間=00:00(0.06450秒)

log4php.xmlの中身

<?xml version="1.0" encoding="UTF-8"?>
<configuration xmlns="http://logging.apache.org/log4php/">
  <appender name="myConsoleAppender" class="LoggerAppenderConsole" />

  <appender name="default" class="LoggerAppenderRollingFile">
    <layout class="LoggerLayoutPattern">
      <param name="conversionPattern" value="%date %logger %-5level %msg%n" />
    </layout>

    <param name="file" value="/var/log/wordpress/my_app.log" />
    <param name="maxFileSize" value="1MB" />
    <param name="maxBackupIndex" value="5" />
  </appender>
  <root>
    <level value="DEBUG" />
    <appender_ref ref="default" />
    <appender_ref ref="myConsoleAppender" />
  </root>
</configuration>

cron設定で毎日10時に実行

# crontab -3
0 10 * * * /usr/bin/php /usr/share/nginx/www.prj2501.red/html/wordpress/wp-content/themes/twentyfourteen/batch_sample.php --arg1=value1 --arg2=value2