Cron(クーロン)を使ってPHPを自動実行してると、
次みたいなサーバー変数が一切参照できなくなります。
- $_SERVER['DOCUMENT_ROOT']
- $_SERVER['HTTP_HOST']
いわゆるサーバー変数と呼ばれるもの
こういうのが参照できくなるって、かなり困りますよね...
そこでCron実行時でもサーバー変数を参照する方法についてまとめました。
このページの目次
$_SERVER の DOCUMENT_ROOT が空になる原因
まず Cron(クーロン) とは何かについて
正確にいうと cron は crontab とも呼ばれていて、
サーバー側(Unix系)で自動的に処理を行うコマンドのことです。
以下 Wikipedia からの引用
crontab
(クロンタブ、あるいはクローンタブ、クーロンタブとも)コマンドはUnix系オペレーティングシステム (OS) において、コマンドの定時実行のスケジュール管理を行うために用いられるコマンドである。標準入力からコマンド列を読み取り、crontabと呼ばれるファイルにそれを記録する。この記録を元に定時になると、その命令内容を読み取り、実行が行われる。cronという名称はギリシア語のクロノス (χρόνος) に由来するという説がある(Command Run ON の略という説も)。日本語ではクーロンという読みが慣習的に広く用いられているが、英語では通常クロンまたはクローンと発音する[1]。引用元 : crontab - Wikipedia
cronという名前の由来には諸説あるみたいですね。(なんで諸説あるんだろう・・・?)
あと日本語だと "クーロン" と呼んでるけど、英語だと "クロン" とか "クローン" という言い方が一般的な模様
まあそれはさておき、
問題なのは cron を使ってPHPを自動実行するとサーバー変数が参照できない事
例えば cron に登録したスクリプトで次コードを書いたとしましょう。
1 |
require_once $_SERVER['DOCUMENT_ROOT'] . '/fuga.php'; |
何の変哲もないありふれた書き方
でも cron で実行すると 次みたいな警告 が出て怒られてしまいます。
1 |
Warning: require_once(../fuga.php): failed to open stream: No such file or directory in /home/hogehoge/public_html/hoge.php on line 3 |
何でこういう警告が出るかというと、
Cronジョブはサーバー上で独立した状態で実行されるから
$_SERVER から参照できる変数はHTTP経由から呼ばれないとセットされないみたいですね。
なので HTTP_HOST とか HTTP_USER_AGENT の中身ももちろん参照不可です。
ですが、この問題の解決策は次で紹介するようにいくつかあります。
Cron実行時に DOCUMENT_ROOT を参照する2つの対処法
この問題の対処法として、自分が思いつくのは次の2つ
対処法1.Cronジョブのオプションから渡す
まず1つめ
Cronジョブを実行するコマンドから渡してあげるという対処法
つまりコマンドオプションにドメイン直下からのパスを指定してあげればいいんです。
具体的なやり方は次の通り
まず次みたいなコマンドを cron に登録するとしましょう。
1 |
/path/to/php.exe hoge.php --doc-root="path/to/docroot" |
上コマンドの --doc-root="path/to/docroot" という部分に注目
ここで $_SERVER['DOCUMENT_ROOT'] から本来取得できるパスを指定してください。
そして実際のスクリプト上では次みたいなコードを書けばOKです。
1 2 3 4 5 6 |
$longopts = ['doc-root::']; $opts = getopt( null, $longopts ); $document_root = $opts['doc-root']; if ( isset($document_root) ) { $_SERVER['DOCUMENT_ROOT'] = $document_root; } |
getopt関数を使えばコマンドオプションの値が参照できます。
詳しく知りたい方は次記事をご覧ください。
▼ PHPでのコマンドライン引数とかオプションの受け取り方
これでCron実行時でも DOCUMENT_ROOT が参照可能
もちろんオプションを増やせば HTTP_HOST とかも指定できます。
対処法2.dirname関数で現在のパスから取得する方法
2つ目の方法は dirname 関数から設定する方法
dirname関数は渡されたパスの親ディレクトリのパスを返す関数です。
つまり __FILE__ を渡せば、現在スクリプトが動いている親ディレクトリのパスが取得できるという訳
これを何回か使えば DOCUMENTO_ROOT を設定することができます。
例えばドメイン直下からのディレクトリ構成が次みたいなってるとしましょう。
- - root
- - hoge
- - hoge.php
- - piyo.php
- - hoge
そして hoge.php をCronジョブとして登録してるとします。
その場合、 hoge.php から DOCUMENT_ROOT は次コードで設定可能
1 |
$_SERVER['DOCUMENT_ROOT'] = dirname(dirname(__FILE__)); |
dirname関数を2回繰り返してます。
この繰り返し回数はドメイン直下からの深さによって変えてください。
ここまでのまとめ
ここまでで紹介した対処法は次の2つ
- Cronジョブのオプションに渡す方法
コマンド実行時に --doc-root="path/to/docroot" みたいな感じでオプションを付ける。PHPからは getopt 関数を使って取得し、 $_SERVER['DOCUMENT_ROOT'] に入れる
- dirname関数を繰り返す方法
例えば dirname(dirname(__FILE__)) みたいにドメイン直下からの深さに応じて、dirname関数を繰り返す。そしてその値を $_SERVER['DOCUMENT_ROOT'] に代入すればOK
Cronを実行してると サーバー変数はそのまま受け取れないので要注意です。
以上、CronでPHPを動かすとサーバー変数が参照できない対処法でした。