PHPのスニペットいろいろ

PHPでたまに必要になるよく使うコードを置いてます。

主に自分用です。
どこでも誰でも使えるものもあれば私(の環境)しか使えないものもあります。

三項演算子とかワンライナーで書けそうなところも、可読性と再利用性を優先してます。

スニペットとは「分かっている人が楽をするためのツール」です。
分からない人がコピペするためのものではありません。
コードの意味を理解してご利用ください。

基本の設定

// タイムゾーンを「東京」にする
date_default_timezone_set('Asia/Tokyo');

// ja にして utf-8 にする
mb_language('ja');
mb_regex_encoding('utf-8');
mb_internal_encoding('utf-8');

// X-Powered-Byを非表示
ini_set('expose_php', 0);

ini_set / ini_get

メモリ制限

// メモリ制限を 128M に変更
ini_set('memory_limit', '128M');

// 現在のメモリ制限値を取得
echo ini_get('memory_limit');

取得関係

サーバ名を取得

$server_name = ";
if (isset($_SERVER['SERVER_NAME'])) {
    $server_name = $_SERVER['SERVER_NAME'];
}

SSLの状態

$is_ssl = false;
if (isset($_SERVER['SERVER_PORT'])) {
    $is_ssl = $_SERVER['SERVER_PORT'] === '443';
}

ユーザーエージェント

$user_agent = 'unset';
if (isset($_SERVER['HTTP_USER_AGENT'])) {
    $user_agent = $_SERVER['HTTP_USER_AGENT'];
}

リモートアドレス

$remote_addr = '0.0.0.0';
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    $remote_addr = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
    if (isset($_SERVER['REMOTE_ADDR'])) {
        $remote_addr = $_SERVER['REMOTE_ADDR'];
    }
}

計測関係

マイクロ秒単位で掛かった時間を計測

高速化対応をするときには体感じゃなく、実際に計測しましょう。

// 開始時間
$start_microtime = microtime(true);

// 時間の掛かるなにか
sleep(1);

// 経過時間
$elapsed_time = microtime(true) -- $start_microtime;

// 表示
echo number_format($elapsed_time, 5);

メール関係

メールサーバを指定

mail() 関数とかでメールを送信するとき何も気にしないと、PHPが動いているマシンを使って送信しようとします。
開発用マシンとかだとメールサーバを用意してないから送信エラーになること、ありますね。
次のようにメールサーバとポートを指定して外部マシン経由で送信できるようになります。

ini_set('SMTP', 'メールサーバのIPアドレスまたはホスト名');
ini_set('smtp_port', 587);

変換

あらゆる変数を文字列に変換

ちょっと変数の中身を見たいなってときに、print_r とか var_dump とか ログに書き出したりすると思うんですが、そういうとき、どんな型の変数でも受け入れるように拡張したのを用意しておくと便利です。

/**
 * 変数を文字列に変換
 *
 * @param mixed $variable
 */
function toString($variable)
{
    if (is_null($variable)) {
        return '[NULL]';
    }

    if (is_bool($variable)) {
        return ($variable ? '[TRUE]' : '[FALSE]');
    }

    if (is_string($variable)) {
        return $variable;
    }

    if (is_float($variable)) {
        return '(float) ' . $variable;
    }

    if (is_int($variable)) {
        return '(int) ' . $variable;
    }

    return print_r($variable, true);
}

// 使用例
error_log(toString(null));
error_log(toString(true));
error_log(toString(false));
error_log(toString(123));
error_log(toString('123'));
error_log(toString(123.45));
error_log(toString('123.45'));
error_log(toString('こんにちわ'));
error_log(toString(array('A', 'B', 'C')));

エラー関係

エラー表示

すべてのエラーを出力対象にし、画面に表示します。
ちなみにこれだけではFatalなエラーは取れません。
フレームワークを使っている場合はフレームワークの初期化処理で設定されていることもあります。設定したのに効かないときはそのあたりをみましょう。

ini_set('display_errors', 1);
error_reporting(- 1);

エラーをログファイルに残す

エラーが発生すると多くの場合、httpdのエラーログ(/var/log/httpd/error_log)とかに書かれるんじゃないでしょうか。
次のようにしてログファイルの位置を設定できます。
ただこれだけだとローテーションとかもないので工夫が必要です。が、そのあたりは本項の範疇外なのでヒント程度にしときます。
あと、そもそもの話として、そもそも error_log に出てくるようなログはその原因から取り除くべきです。ので、そもそもローテーションなんていらんのです。

// error_log への記録を有効にする
ini_set('log_errors', 1);

// error_log したときの保存場所
// 保存場所のディレクトリは自前で準備
ini_set('error_log', __DIR__ . '/error.log');

// ログファイルを年月で分けてみるとか
ini_set('error_log', __DIR__ . '/error-' . date('Y-m-d') . '.log');

// エラーファイルへの書き込み
error_log('エラーだよ');

エラーを例外にして try / catch

PHPは、try / catch が使えるのですが素直に何も考えないと書くと「思ってるのと違う」ってなると思います。
「わざとエラーを出して、catchに来るはずなのになんで来ないのー」なんてことも。
ということで、PHPのエラーを「例外」(Exception)に変換するのがこちらです。

// エラーハンドラー、Fatalなエラーを Exception に変換する
set_error_handler(function ($errno, $errstr, $errfile, $errline)
{
    if (class_exists('\Exception')) {
        throw new \Exception($errfile . '[' . $errline . '] ErrorNo : ' . $errno . ' / ' . $errstr);
    }
});

// sample
try {
    $a = 10 / 0;  // ゼロ割
    // $a = $b;  // 未定義の変数($b)の使用
    // throw new Exception('エラー');  // 例外を投げる
} catch (Exception $e) {
    error_log(print_r($e, true), 0);
}

シャットダウンエラーの画面表示

PHPのエラーにはいくつか種類があります。
プログラムが動作しないレベルのエラーは「シャットダウンエラー」で行います。

例えば、パースエラー、関数とかIF文とかで閉じ括弧を忘れたとか。
例えば、Fatalエラー、同名の関数を二重に定義したとか。

こういう類のエラーは、処理を継続することができませんので発覚した時点で「シャットダウン」します。
そのため通常のエラーフローに行きませんので、ログを見ても何もでてきません。

メモリ制限に引っかかったときは、register_shutdown_function まで来ないので memory_limit も用意しています。エラーが出るはずなのに出ないときは memory_limit を増やして試してみます。

// ini_set('memory_limit', '128M');
register_shutdown_function(function ()
{
    if (is_callable('error_get_last')) {
        $e = error_get_last();
        if (! is_null($e)) {
            $s = print_r($e, true);
            // error_log($s, 0);
            $s = htmlspecialchars($s, ENT_QUOTES);
            echo '<pre>' . $s . '</pre>';
            exit();
        }
    }
});

変数の中身を画面に表示

変数は文字列でも配列でもオブジェクトでもOKです。
変数の中を見れたらよいので、echo の後その場でexit で良いと思います。

$data = '表示させたい変数';
echo '<pre style="border:solid 1px #aaa;background-color:#000;padding:1em;margin:1em 0;text-align:left;font-size:12px;line-height:1.2;">' . htmlspecialchars(print_r($data, true), ENT_QUOTES) . '</pre>';
// exit;

広告