You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用PHP通过APNs发送iOS推送通知遇阻求助

Hey there, let's figure out why your PHP APNs push isn't working. Looking at your code, I spot a few key issues that are likely causing the failure:

1. Incorrect SSL Context Option

Your stream_context_set_option call uses the wrong key for the certificate. Instead of certificate.cer, the correct key is local_cert — this is a common typo that breaks the SSL handshake with APNs.

2. Potential Certificate Path & Format Issues

  • Make sure your certificate.pem file is in the correct location relative to your script, or use an absolute path to avoid path resolution problems.
  • Ensure the PEM file includes both the certificate and private key (you can combine them with cat cert.pem key.pem > certificate.pem if you have separate files).

3. Outdated Binary Protocol

The legacy binary protocol (port 2195) you're using is deprecated by Apple. It's far more reliable to switch to the HTTP/2 API, which also provides clearer error messages for debugging.

4. Missing Error Checking

Your code doesn't verify if the fwrite operation succeeded, nor does it read the error response APNs sends when something goes wrong. This makes it nearly impossible to diagnose failures.


Fixed Code for Legacy Binary Protocol

First, let's fix your existing code to get the old protocol working:

// APNs Push testen auf Token
$deviceToken = $_GET['key']; // Device-Token
// Payload erstellen und JSON codieren
$payload['aps'] = array('alert' => 'TitleText', 'badge' => 1, 'sound' => 'default');
$payload = json_encode($payload);
$apnsHost = 'gateway.sandbox.push.apple.com';
$apnsPort = 2195;
// Use absolute path to your PEM file to avoid path issues
$apnsCert = __DIR__ . '/certificate.pem';

// Stream erstellen - FIXED: use 'local_cert' instead of 'certificate.cer'
$streamContext = stream_context_create();
stream_context_set_option($streamContext, 'ssl', 'local_cert', $apnsCert);
// Uncomment below if your certificate has a passphrase
// stream_context_set_option($streamContext, 'ssl', 'passphrase', 'your_cert_passphrase');

$apns = stream_socket_client(
    'ssl://' . $apnsHost . ':' . $apnsPort,
    $error,
    $errorString,
    2,
    STREAM_CLIENT_CONNECT,
    $streamContext
);

if ($apns) {
    // Nachricht erstellen und senden
    $deviceTokenClean = str_replace(' ', '', $deviceToken);
    $apnsMessage = chr(0) . chr(0) . chr(32) . pack('H*', $deviceTokenClean) . chr(0) . chr(strlen($payload)) . $payload;
    
    // Check if message was written successfully
    $bytesWritten = fwrite($apns, $apnsMessage);
    if ($bytesWritten === false) {
        echo "Failed to send message to APNs";
    } elseif ($bytesWritten != strlen($apnsMessage)) {
        echo "Only sent $bytesWritten of " . strlen($apnsMessage) . " total bytes";
    } else {
        echo "Push notification sent successfully!";
    }

    // Read APNs error response (if any)
    $errorResponse = fread($apns, 6);
    if ($errorResponse) {
        $errorCode = ord($errorResponse[2]);
        echo "<br>APNs Error Code: $errorCode";
        // Reference Apple's docs for error code meanings
    }

    // Verbindung schliessen
    fclose($apns);
} else {
    echo "Fehler beim Verbinden mit APNs!";
    var_dump($error);
    var_dump($errorString);
}

Recommended: Switch to HTTP/2 API (Modern Approach)

Apple strongly recommends using the HTTP/2 API for APNs. Here's a working example using cURL (ensure your PHP installation has cURL with HTTP/2 support):

$deviceToken = $_GET['key'];
$payload = json_encode([
    'aps' => [
        'alert' => 'TitleText',
        'badge' => 1,
        'sound' => 'default'
    ]
]);

// Replace these with your Apple Developer credentials
$apnsAuthKey = __DIR__ . '/AuthKey_XXXXXX.p8'; // Path to your APNs auth key
$teamId = 'YOUR_APPLE_TEAM_ID'; // Your Developer Team ID
$keyId = 'YOUR_APNS_KEY_ID'; // The ID of your APNs auth key
$bundleId = 'com.yourcompany.yourapp'; // Your app's bundle ID

// Generate JWT token for APNs authentication
$header = json_encode(['alg' => 'ES256', 'kid' => $keyId]);
$payloadJwt = json_encode(['iss' => $teamId, 'iat' => time()]);
$base64Header = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($header));
$base64Payload = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($payloadJwt));
$signature = '';
openssl_sign("$base64Header.$base64Payload", $signature, file_get_contents($apnsAuthKey), 'sha256');
$base64Signature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature));
$jwt = "$base64Header.$base64Payload.$base64Signature";

// Send request via HTTP/2
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.sandbox.push.apple.com/3/device/$deviceToken");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'Authorization: bearer ' . $jwt,
    'apns-topic: ' . $bundleId
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if ($httpCode == 200) {
    echo "Push notification sent successfully!";
} else {
    echo "Error: HTTP Code $httpCode<br>Response: $response";
}

curl_close($ch);

内容的提问来源于stack exchange,提问作者Nils

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:39:39