PHPとJPushを用いたカスタマイズ可能なプッシュ通知システムの構築

本稿では、外部ライブラリに依存せず、純粋なPHPとcronによるスケジュール実行で実装されたプッシュ通知基盤について解説します。極光推送(JPush)APIを直接呼び出し、ユーザー属性(性別・地域・端末種別)に基づくセグメント配信を可能にする設計を採用しています。

認証付きJPush送信関数

以下の関数は、AppKeyとMaster Secretを用いてBasic認証を行い、JSONペイロードを構築してJPush v3 APIへPOST送信します。iOS/Android双方に対応し、APNsの開発・本番環境切り替えもプログラム内で制御可能です。

/**
 * JPush経由でのプッシュ通知送信
 * @param array $target 対象指定(例: ['tag' => ['東京', '大阪']] または ['registration_id' => ['id1','id2']])
 * @param string $message 通知本文
 * @param array|string $platform プラットフォーム('all' or ['android','ios'])
 * @param string $payloadType 付加データタイプ(例: 'deep_link', 'web_url')
 * @param string $payloadValue 付加データ値(URLや識別子など)
 * @param int $ttl 離線保存時間(秒単位、デフォルト86400=24時間)
 * @return string APIレスポンスJSON文字列
 */
function sendPushNotification($target, $message, $platform = 'all', $payloadType = '', $payloadValue = '', $ttl = 86400) {
    $appKey = 'your_app_key_here';   // 実際のアプリケーションキーに置換
    $masterSecret = 'your_master_secret_here'; // 実際のマスターシークレットに置換

    $url = 'https://api.jpush.cn/v3/push';
    $authHeader = 'Authorization: Basic ' . base64_encode("{$appKey}:{$masterSecret}");
    
    $payload = [
        'platform' => $platform,
        'audience' => $target,
        'notification' => [
            'alert' => $message,
            'android' => [
                'alert' => $message,
                'extras' => ['payload_type' => $payloadType, 'payload_value' => $payloadValue]
            ],
            'ios' => [
                'alert' => $message,
                'badge' => '+1',
                'sound' => 'default',
                'extras' => ['payload_type' => $payloadType, 'payload_value' => $payloadValue]
            ]
        ],
        'message' => [
            'msg_content' => $message,
            'extras' => ['payload_type' => $payloadType, 'payload_value' => $payloadValue]
        ],
        'options' => [
            'sendno' => (int)microtime(true),
            'time_to_live' => $ttl,
            'apns_production' => false // 開発環境:false / 本番環境:true
        ]
    ];

    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => json_encode($payload),
        CURLOPT_HTTPHEADER => [$authHeader, 'Content-Type: application/json'],
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_SSL_VERIFYPEER => false,
        CURLOPT_SSL_VERIFYHOST => false,
        CURLOPT_TIMEOUT => 15
    ]);

    $response = curl_exec($ch);
    curl_close($ch);

    return $response;
}

ユーザー管理テーブル構造

端末登録情報とユーザー属性を関連付けるための主テーブルです。地理情報(緯度・経度)から自動生成した地域タグ(例: "新宿区")を用いて、位置ベースの配信が可能です。

CREATE TABLE `push_device_registry` (
  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `jpush_registration_id` VARCHAR(255) NOT NULL,
  `user_id` INT UNSIGNED NOT NULL,
  `device_platform` ENUM('android', 'ios', 'unknown') NOT NULL DEFAULT 'unknown',
  `opt_in_status` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '1=許諾, 0=拒否',
  `last_active_at` INT UNSIGNED NOT NULL,
  `gender` TINYINT(1) NULL COMMENT '1=male, 0=female',
  `longitude` DECIMAL(10,7) NULL,
  `latitude` DECIMAL(10,7) NULL,
  `region_tag` VARCHAR(64) NULL,
  INDEX `idx_user_platform` (`user_id`, `device_platform`),
  INDEX `idx_region` (`region_tag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

配信履歴とスケジュールタスクテーブル

通知の実行記録と、将来実行予定のタスクを分離管理します。cronジョブはv1_message_taskを定期的にスキャンし、実行時刻に達したタスクを処理します。

CREATE TABLE `push_delivery_log` (
  `log_id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `task_id` INT UNSIGNED NULL,
  `sender_id` INT UNSIGNED NOT NULL,
  `message_body` TEXT NOT NULL,
  `target_spec` JSON NOT NULL COMMENT '対象条件(JSON形式)',
  `platforms` JSON NOT NULL,
  `delivery_status` ENUM('pending','sent','failed') DEFAULT 'pending',
  `created_at` INT UNSIGNED NOT NULL,
  INDEX `idx_task` (`task_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `scheduled_push_tasks` (
  `task_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `task_name` VARCHAR(128) NOT NULL,
  `message_template` TEXT NOT NULL,
  `target_filter` JSON NOT NULL COMMENT 'WHERE条件相当(例: {"gender":1,"region_tag":"渋谷区"})',
  `execution_time` INT UNSIGNED NOT NULL COMMENT 'UNIXタイムスタンプ',
  `status` ENUM('pending','executed','cancelled') DEFAULT 'pending',
  INDEX `idx_scheduled` (`execution_time`, `status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

実行フローの概要

cronにより定期実行されるスクリプトは、scheduled_push_tasksから未実行かつ実行時刻を過ぎたレコードを抽出し、target_filterに基づきpush_device_registryから該当デバイスIDを取得します。その後、sendPushNotification()関数を呼び出して一括送信を行います。結果はpush_delivery_logに記録され、監査および再送判断に利用されます。

タグ: jpush PHP cron MySQL push-notification

7月6日 21:50 投稿