古い PHP を使うときに問題となりそうな箇所
あるバージョンの PHP を想定して書かれたコードをより古いバージョンの PHP で動作させないといけなくなったときに、問題になりそうな箇所を挙げる。
PHP 7.3 → 7.4
- 配列のスプレッド構文
$a = [1, 2]; $b = [0, ...$a, 3, 4];
- 矢印関数(ショートクロージャ)
array_map(fn($n) => $n * $n, $a);
- クラスのプロパティに対する型宣言
class C { protected int $id; }
PHP 7.0 → 7.1
- file_get_contents() の第4引数
$offset
のデフォルト値が-1
から0
に変更された
PHP 5.6 → 7.0
- 関数のプリミティブ型の型宣言
function getUserName(int $userId): ?string
- 無名関数の直接呼び出し
(function() { ... })()
- date() 関数や DateTime::format() でのフォーマット文字 v (ミリ秒) の追加
- Null 合体演算子
$user = $_GET['user'] ?? 'nobody'; // isset($_GET['user']) ? $_GET['user'] : 'nobody';
PHP 5.5 → 5.6
- 定数式
const ONE = 1; const TWO = ONE * 2;
- ... による可変個引数関数
function f($req, $opt = null, ...$params) { ... }
- ... による引数のアンパック
$arr = [2, 3]; f(1, ...$arr); // = f(1, 2, 3)
- 累乗演算子 ** および代入演算子 **=
- use function および use const
- php://input が2回以上オープンできるように
- hash_equals() 関数の追加
- 処理が厳格になったもの
- DateTime
- DateTimeImmutable::createFromMutable() の追加
- GMP
- PDO
- PDO::pgsqlGetNotify(), PDO::pgsqlGetPid() の追加
- Session
- session_abort(), session_reset() の追加
- Zip
- ZipArchive::setPassword() の追加
PHP 5.4 → 5.5
- ジェネレータが追加されました。 yield キーワードで利用します。
- try-catch ブロックで finally が使えるようになりました。
- 新しいパスワードハッシュ API … password_hash(), password_needs_rehash(), password_verify() など
- foreach で list() を使って、ネストした配列を個別の変数に展開できるようになりました。
- empty() が変数以外の任意の式に対応
- array リテラルと string リテラルのデリファレンス
- ::class によるクラス名の解決
- foreach が非スカラーのキーに対応
- array_column() 関数の追加
- DateTimeImmutable クラスの追加
- GD の改良
PHP 5.3 → 5.4
PHP 5.2 → 5.3
DateTime オブジェクトのタイムゾーンの設定
タイムゾーンを特に指定しない場合、 date_default_timezone_get() の値が使われる。
<?php $date = new DateTime; $tz = $date->getTimezone(); $tz->getName(); // Asia/Tokyo date_default_timezone_get(); // Asia/Tokyo $date->getTimestamp(); // 1410130800 $date->format('Y/m/d H:i:s'); // 2014/09/08 08:00:00
@ + UNIX タイムスタンプで初期化した場合
DateTime クラスのコンストラクタに、'@' + UNIX タイムスタンプ という文字列を指定した場合、そのオブジェクトのタイムゾーンは強制的に UTC となる。
<?php $date = new DateTime('@1410130800'); $tz = $date->getTimezone(); $tz->getName(); // +00:00 $date->getTimestamp(); // 1410130800 $date->format('Y/m/d H:i:s'); // 2014/09/07 23:00:00
一方 setTimestamp() でタイムスタンプを指定した場合は、そのオブジェクトが持っているタイムスタンプが受け継がれる。
<?php $date = new DateTime; $date->setTimestamp(1410130800); $tz = $date->getTimezone(); $tz->getName(); // Asia/Tokyo $date->getTimestamp(); // 1410130800 $date->format('Y/m/d H:i:s'); // 2014/09/08 08:00:00
ある地域の時刻を別の地域の時刻に変換する
変換元のタイムゾーンを指定してから時刻を表す文字列を解析し、変換先のタイムゾーンを指定して整形関数を使えばよい。
<?php $date = new DateTime('2014/09/08 08:00:00', new DateTimeZone('Europe/London')); $date->format('Y/m/d H:i:s'); // 2014/09/08 08:00:00 $date->setTimezone(new DateTimeZone('UTC')); $date->format('Y/m/d H:i:s'); // 2014/09/08 07:00:00 (夏時間のためロンドンの時刻は UTC より 1 時間進んでいる)
【旧版】Google Analytics API を PHP から使う
サービスから API を使えるよう設定を行う
この記事を参考に第6節「Google Analytics のビュー ID をメモする」までの手順を行う。
この手順で作成するものは次の通り。
- API プロジェクト(Facebook API では「アプリ」と呼ばれるものに相当)
- OAuth のサービスアカウント
- クライアント ID
- メール アドレス
- 秘密鍵
- 上記 OAuth クライアントと紐づいた Google Analytics ユーザー
Google API PHP Client を配置する
次のページから src 以下のファイルをダウンロードする。Git の使い方に詳しくなければ「Download ZIP」からまとめてダウンロードするとよい。
require/include で読み込み可能なディレクトリに Google というディレクトリを作り、その中にダウンロードした src 以下のファイルを配置する。
API を使う
毎回 API への接続条件を書くのは大変なので次のようなクラスを作った。新しい PHP Client ではこの部分で使うクラス名や関数名が変更されている。
<?php // my_google_analytics.php require_once 'Google/Client.php'; require_once 'Google/Auth/AssertionCredentials.php'; require_once 'Google/Service/Analytics.php'; class MyGoogleAnalytics { // クライアント ID const CLIENT_ID = 'XXXXXXXX.apps.googleusercontent.com'; // メール アドレス const SERVICE_ACCOUNT_NAME = 'XXXXXXXX@developer.gserviceaccount.com'; // 秘密鍵のファイル名 const KEY_FILE = 'XXXXXXXX-privatekey.p12'; private static $client; private static $service; public static function get() { if (! isset(self::$client)) { self::createClient(); } if (! isset(self::$service)) { self::$service = new Google_Service_Analytics(self::$client); } return self::$service; } private static function createClient() { self::$client = new Google_Client(); self::$client->setApplicationName('Suzume Kawaii Application'); self::$client->setClientId(self::CLIENT_ID); self::$client->setAssertionCredentials(new Google_Auth_AssertionCredentials( self::SERVICE_ACCOUNT_NAME, array('https://www.googleapis.com/auth/analytics.readonly'), file_get_contents(__DIR__ . '/' . self::KEY_FILE) )); } }
次のように MyGoogleAnalytics::get() を呼ぶだけですぐに API を呼び出すためのオブジェクトを生成できる。
<?php require_once 'my_google_analytics.php'; $ga = MyGoogleAnalytics::get(); $result = $ga->data_ga->get( 'ga:XXXXX', // XXXXX の部分は Analytics のビュー ID '2014-05-01', // 開始日 '2014-05-31', // 終了日 'ga:pageviews', // 主要指標 (metrics) array( 'dimensions' => 'ga:pageTitle,ga:pagePath', // 副指標 'sort' => '-ga:pageviews', // - を付けると降順ソート 'max-results' => 10, // 取得件数 )); print_r($result['rows']);
取得できるデータの種類
指標 metrics および dimension で指定できる項目はこのページで参照できる。
主な指標を挙げておく。
- Metrics
- ga:sessions セッション数
- ga:users ユーザ数
- ga:pageviews ページビュー
- Dimensions
- ga:userType 新規訪問/リピート訪問 (例: New Visitor, Returning Visitor)
- ga:medium 参照元の種類 (例: organic, referral, (none))
- ga:source 参照元 (例: google, yahoo, (direct), example.com)
デスクトップ/モバイル(スマートフォン)を判断するベストプラクティス
モバイル環境では通信の帯域が限られているため、内容を絞り込んだコンテンツを提供するのが定石となっている。
その判定を行うのに現在最も有効な方法は、HTTP リクエストに含まれる User-Agent ヘッダを参照する方法だ。数多くのアクセス解析ツールでも、ユーザの環境を判断するのに User-Agent ヘッダが用いられている。
さて、環境ごとの User-Agent を調べるのは骨の折れる作業である。そこで巨人の肩を借りることにする。
WPtouch Mobile Plugin から拝借する
「モバイル向け」などのキーワードで検索するとまず目についたのが Wordpress 用のプラグイン WPtouch Mobile Plugin である。このプラグインも例にもれず User-Agent ヘッダを用いてユーザ環境を判断している。
見たところ有償版の WPtouch Pro も含めそれなりのユーザ数がありそうなので、この仕組みを拝借しよう。
このプラグインをダウンロードして展開すると、 wptouch/core/mobile-user-agents.php にスマートフォンの User-Agent に含まれる文字列が列挙されている。12項目とシンプルにまとまっていて、判定の負荷も少なそうだ。
<?php /* Smartphones */ global $wptouch_smartphone_list; $wptouch_smartphone_list = array( array( 'iPhone' ), // iPhone array( 'iPod', 'Mobile' ), // iPod touch array( 'Android', 'Mobile' ), // Android devices array( 'Opera', 'Mini/7' ), // Opera Mini 7 array( 'BB', 'Mobile Safari' ), // BB10 devices ...
判定コードは次のように書ける。
<?php function is_mobile() { static $is_mobile; if (isset($is_mobile)) { return $is_mobile; } $useragent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : ''; foreach ($wptouch_smartphone_list as $substrs) { $matched = true; foreach ((array)$substrs as $substr) { $pattern = preg_quote($substr, '/'); if (! preg_match("/\\b$pattern\\b/i", $useragent)) { $matched = false; break; } } if ($matched) { $is_mobile = true; break; } } return $is_mobile; } if (is_mobile()) { ... } // モバイル用のコード else { ... } // デスクトップ用のコード
UTC時刻の文字列からローカル時刻を出力する
SQLite には日付型はないが、 CURRENT_TIMESTAMP で現在時刻を文字列として取得することができる。また、date などの関数で時刻の演算することもできる。
SELECT CURRENT_TIMESTAMP AS now , datetime('now', 'start of month') AS first_day , datetime('now', 'start of month', '+1 month', '-1 day') AS last_day ;
出力は次のようになる。
now => 2013-11-14 21:12:34 first_day => 2013-11-01 00:00:00 last_day => 2013-11-30 23:59:59
ただしここで出力される時刻は世界協定時 UTC に固定されているため、アプリケーション側でローカル時刻に変換する必要がある。
PHP の場合、この変換に PHP 5.2 から用意されている DateTime クラスを使うことができる。下記の例は UTC 時刻の文字列を受け取り、ローカル時刻の文字列を返す。
<?php function formatLocalDatetime($utcstr) { static $UTC, $Local; if (! isset($UTC)) { $UTC = new DateTimeZone('UTC'); $Local = new DateTimeZone(date_default_timezone_get()); } try { $date = new DateTime($utcstr, $UTC); $date->setTimeZone($Local); return $date->format('Y/m/d H:i:s'); } catch (Exception $e) { return ''; } } date_default_timezone_set('Asia/Tokyo'); echo formatLocalDateTime('2013-11-14 21:12:34'); // => 2013-11-15 06:12:34
単に UNIX 時間を取得する場合は $date->getTimestamp() でよい。