.p12 转换而来,含客户端证书与私钥。
openssl pkcs12 -in cert.p12 -out ck.pem -nodes -clcerts
testpush.php<?php
// ===== 配置区 =====
$deviceToken = '6ad7b13fb05e6137a46a60ea421e50164b701671cc176f7033bb9ef438a8aef9'; // 去除空格
$passphrase = 'jetson'; // 证书密码
$message = 'A test message!'; // 推送文案
$badge = 4; // 角标数字
$sound = 'Duck.wav'; // 提示音文件名(需打包在 App 中)
$isSandbox = true; // true=沙箱/开发环境,false=生产环境
// ===================
// 1. 构建 APNs Payload
$body = [
'aps' => [
'alert' => $message,
'badge' => $badge,
'sound' => $sound,
],
// 可扩展自定义字段
'custom_key' => 'custom_value',
];
$payload = json_encode($body);
// 2. 创建 SSL 上下文
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'ck.pem');
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
// 3. 连接 APNs 网关
$gateway = $isSandbox
? 'ssl://gateway.sandbox.push.apple.com:2195'
: 'ssl://gateway.push.apple.com:2195';
$fp = stream_socket_client($gateway, $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx);
if (!$fp) {
exit("连接失败: $err $errstr\n");
}
echo "连接成功\n";
// 4. 组装二进制协议包 (APNs 二进制协议格式)
// Command(1) | Token Length(2) | Token(32) | Payload Length(2) | Payload
$token = pack('H*', str_replace(' ', '', $deviceToken));
$msg = chr(0) . pack('n', 32) . $token . pack('n', strlen($payload)) . $payload;
// 5. 发送
fwrite($fp, $msg);
echo "发送完成: $payload\n";
fclose($fp);
?>
| 环节 | 说明 |
|---|---|
| Payload 大小 | APNs 限制 4KB (iOS 8+) / 2KB (旧版),超长会被拒收。 |
| Token 格式 | 必须为 64 位十六进制,去除空格后用 pack('H*', ...) 转二进制。 |
| 证书路径 | local_cert 指向 ck.pem 绝对路径,确保 PHP 进程可读。 |
| 持久连接 | 生产环境建议使用 STREAM_CLIENT_PERSISTENT 复用连接,减少握手开销。 |
| 错误处理 | APNs 不返回即时响应,需另行部署 Feedback Service 或使用 HTTP/2 API 获取错误码。 |
Apple 2016 年推出基于 HTTP/2 的新 API,支持多路复用、即时响应、JWT 认证(无需证书文件)。PHP 可用 curl (>=7.46) 或 swoole/http2-client 实现。
<?php
// 简易 HTTP/2 推送示例 (需 PHP 7.0+ & curl 7.46+)
$apnsHost = 'api.sandbox.push.apple.com'; // 生产: api.push.apple.com
$url = "https://$apnsHost/3/device/$deviceToken";
$headers = [
'apns-topic: com.your.bundle.id',
'apns-priority: 10', // 立即送达
'authorization: bearer ' . getJwtToken(), // 需自行实现 JWT 签名
];
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
// $httpCode 200=成功, 410=Token失效, 400=Payload错误等
?>
JSON_UNESCAPED_UNICODE),且文件保存为 UTF-8。本文提供基于 TCP 二进制协议的经典实现,适合快速验证、老项目维护。新项目强烈建议迁移至 HTTP/2 API,享受更佳的可靠性、可观测性与无证书管理优势。