2012-04-07 36 views
16

Trong PHP, bạn sử dụng fread() như thế nào để kiểm tra xem có phản ứng lỗi khi gửi thông báo đẩy nâng cao không?Phản hồi lỗi đọc thông báo đẩy nâng cao PHP của PHP

Tôi đã đọc tài liệu của Apple, một vài bài đăng mơ hồ qua Google và một vài câu hỏi/câu trả lời ở đây trên SO nhưng điều này vẫn còn rất khó hiểu.

Dưới đây là những gì tôi nhìn: http://developer.apple.com/library/mac/#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/IPhoneOSClientImp/IPhoneOSClientImp.html Reading error from Apple enhanced push notification with PHP iPhone Push Notification - Error response problem

Tôi sẽ trả lời câu hỏi của riêng tôi dưới đây, dựa trên thực tế là: (1) Tôi thấy điều này một chủ đề rất khó hiểu, và (2) Tôi phải chia sẻ thông tin cùng với rất nhiều bản dùng thử và lỗi để làm cho nó hoạt động, và (3) bài đăng trên blog này nói rằng nó được khuyến khích: http://blog.stackoverflow.com/2011/07/its-ok-to-ask-and-answer-your-own-questions/

Trả lời

35

Khi bạn gửi một thông báo push, có một số vấn đề:

  • Nếu có một vấn đề, Apple sẽ ngắt kết nối bạn nhưng bạn không biết về nó. Khi bạn sử dụng các thông báo cơ bản, không có cách nào để biết liệu chúng có được gửi hay không. GIẢI PHÁP: Đây là toàn bộ điểm sử dụng thông báo nâng cao và sau đó kiểm tra phản hồi lỗi. Lưu ý rằng chúng tôi sẽ sử dụng "ORDER BY id" trong truy vấn cơ sở dữ liệu và sau đó sử dụng id làm mã định danh mà chúng tôi gửi trong thông báo. Bằng cách này, nếu có sự cố, chúng tôi biết chính xác hàng nào trong db gây ra sự cố (và do đó chúng tôi biết khi nào Apple ngắt kết nối chúng tôi và ngừng gửi thông báo). Sau đó chúng tôi có thể tiếp tục gửi thông báo Đẩy tới tất cả các hàng sau hàng gây ra sự cố, mà không phải gửi lại thông báo cho chúng tôi.

  • Apple KHÔNG gửi bất kỳ phản hồi nào nếu mọi thứ đều ổn, vì vậy điều này có thể khiến tập lệnh của bạn tạm dừng và đợi mãi trong khi fread() đang đợi dữ liệu không đến. GIẢI PHÁP: Cần đặt stream_set_blocking thành 0 để fread luôn trả về ngay lập tức. Lưu ý rằng điều này gây ra một vấn đề nhỏ mà fread có thể trở lại trước khi nó nhận được một phản ứng lỗi, nhưng xem workaround trong mã, mà chỉ là tạm dừng cho 1/2 một giây SAU tất cả gửi của bạn được thực hiện và sau đó kiểm tra fread một lần nữa .

  • Bạn có thể gửi nhiều thông báo đẩy nhanh hơn nhiều so với thông báo phản hồi lỗi để liên hệ lại với bạn. GIẢI PHÁP: Một lần nữa đây là cùng một workaround đề cập ở trên ... tạm dừng cho 1/2 một giây SAU KHI tất cả gửi của bạn được thực hiện và sau đó kiểm tra fread một lần nữa.

Đây là giải pháp của tôi khi sử dụng PHP, giải quyết tất cả các sự cố mà tôi gặp phải. Nó khá cơ bản nhưng hoàn thành công việc. Tôi đã thử nghiệm nó bằng cách gửi một vài thông báo cùng một lúc cũng như gửi 120.000 cùng một lúc.

<?php 
/* 
* Read Error Response when sending Apple Enhanced Push Notification 
* 
* This assumes your iOS devices have the proper code to add their device tokens 
* to the db and also the proper code to receive push notifications when sent. 
* 
*/ 

//database 
$host = "localhost"; 
$user = "my_db_username"; 
$pass = "my_db_password"; 
$dbname = "my_db_name"; 
$con = mysql_connect($host, $user, $pass); 
if (!$con) { 
    die('Could not connect to database: ' . mysql_error()); 
} else { 
    mysql_select_db($dbname, $con); 
} 

// IMPORTANT: make sure you ORDER BY id column 
$result = mysql_query("SELECT id,token FROM `device_tokens` ORDER BY id"); 

//Setup notification message 
$body = array(); 
$body['aps'] = array('alert' => 'My push notification message!'); 
$body['aps']['notifurl'] = 'http://www.myexampledomain.com'; 
$body['aps']['badge'] = 1; 

//Setup stream (connect to Apple Push Server) 
$ctx = stream_context_create(); 
stream_context_set_option($ctx, 'ssl', 'passphrase', 'password_for_apns.pem_file'); 
stream_context_set_option($ctx, 'ssl', 'local_cert', 'apns.pem'); 
$fp = stream_socket_client('ssl://gateway.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx); 
stream_set_blocking ($fp, 0); //This allows fread() to return right away when there are no errors. But it can also miss errors during last seconds of sending, as there is a delay before error is returned. Workaround is to pause briefly AFTER sending last notification, and then do one more fread() to see if anything else is there. 

if (!$fp) { 
    //ERROR 
    echo "Failed to connect (stream_socket_client): $err $errstrn"; 
} else { 
    $apple_expiry = time() + (90 * 24 * 60 * 60); //Keep push alive (waiting for delivery) for 90 days 

    //Loop thru tokens from database 
    while($row = mysql_fetch_array($result)) { 
     $apple_identifier = $row["id"]; 
     $deviceToken = $row["token"]; 
     $payload = json_encode($body); 
     //Enhanced Notification 
     $msg = pack("C", 1) . pack("N", $apple_identifier) . pack("N", $apple_expiry) . pack("n", 32) . pack('H*', str_replace(' ', '', $deviceToken)) . pack("n", strlen($payload)) . $payload; 
     //SEND PUSH 
     fwrite($fp, $msg); 
     //We can check if an error has been returned while we are sending, but we also need to check once more after we are done sending in case there was a delay with error response. 
     checkAppleErrorResponse($fp); 
    } 

    //Workaround to check if there were any errors during the last seconds of sending. 
    usleep(500000); //Pause for half a second. Note I tested this with up to a 5 minute pause, and the error message was still available to be retrieved 

    checkAppleErrorResponse($fp); 

    echo 'DONE!'; 

    mysql_close($con); 
    fclose($fp); 
} 

//FUNCTION to check if there is an error response from Apple 
//   Returns TRUE if there was and FALSE if there was not 
function checkAppleErrorResponse($fp) { 

    //byte1=always 8, byte2=StatusCode, bytes3,4,5,6=identifier(rowID). Should return nothing if OK. 
    $apple_error_response = fread($fp, 6); 
    //NOTE: Make sure you set stream_set_blocking($fp, 0) or else fread will pause your script and wait forever when there is no response to be sent. 

    if ($apple_error_response) { 
     //unpack the error response (first byte 'command" should always be 8) 
     $error_response = unpack('Ccommand/Cstatus_code/Nidentifier', $apple_error_response); 

     if ($error_response['status_code'] == '0') { 
      $error_response['status_code'] = '0-No errors encountered'; 
     } else if ($error_response['status_code'] == '1') { 
      $error_response['status_code'] = '1-Processing error'; 
     } else if ($error_response['status_code'] == '2') { 
      $error_response['status_code'] = '2-Missing device token'; 
     } else if ($error_response['status_code'] == '3') { 
      $error_response['status_code'] = '3-Missing topic'; 
     } else if ($error_response['status_code'] == '4') { 
      $error_response['status_code'] = '4-Missing payload'; 
     } else if ($error_response['status_code'] == '5') { 
      $error_response['status_code'] = '5-Invalid token size'; 
     } else if ($error_response['status_code'] == '6') { 
      $error_response['status_code'] = '6-Invalid topic size'; 
     } else if ($error_response['status_code'] == '7') { 
      $error_response['status_code'] = '7-Invalid payload size'; 
     } else if ($error_response['status_code'] == '8') { 
      $error_response['status_code'] = '8-Invalid token'; 
     } else if ($error_response['status_code'] == '255') { 
      $error_response['status_code'] = '255-None (unknown)'; 
     } else { 
      $error_response['status_code'] = $error_response['status_code'] . '-Not listed'; 
     } 

     echo '<br><b>+ + + + + + ERROR</b> Response Command:<b>' . $error_response['command'] . '</b>&nbsp;&nbsp;&nbsp;Identifier:<b>' . $error_response['identifier'] . '</b>&nbsp;&nbsp;&nbsp;Status:<b>' . $error_response['status_code'] . '</b><br>'; 
     echo 'Identifier is the rowID (index) in the database that caused the problem, and Apple will disconnect you from server. To continue sending Push Notifications, just start at the next rowID after this Identifier.<br>'; 

     return true; 
    } 
    return false; 
} 
?> 
+0

Xin chào. Tôi đã thực hiện bạn đang viết mã trong lớp pusher (làm việc) của tôi. Kỳ lạ tôi không bao giờ nhận được một phản ứng từ táo. '$ Apple_error_response' luôn sai. Nhưng một số tin nhắn push được phân phối, và một số chỉ thất bại. Bạn có biết tại sao tôi không nhận được phản hồi nào không? –

+0

Tôi đăng này gần một năm rưỡi trước và ngừng sử dụng các thông báo đẩy không lâu sau đó vì vậy tôi không thực sự nhớ tất cả các vấn đề tôi xử lý. Để gỡ lỗi tạo danh sách các thẻ mà bạn biết công việc sau đó sao chép mã thông báo và sửa đổi để chúng sẽ thất bại (vì vậy 5 được biết đến tốt & 5 được biết là xấu). Sau đó, một khi bạn đã chấp nhận thông báo đẩy trên thiết bị của mình và xác minh rằng bạn nhận được thông báo, hãy tắt thông báo đẩy trên thiết bị đó và xem điều gì xảy ra khi bạn cố gắng gửi lại mã thông báo đó. Ngoài ra, hãy kiểm tra tài liệu của Apple để đảm bảo rằng họ không thay đổi điều gì đó về cách máy chủ của họ phản hồi. – jsherk

+0

Cảm ơn câu trả lời của bạn. Tôi phải tăng thời gian ngủ lên một giây, sau đó nó hoạt động (chủ yếu). Nhưng tôi vẫn không chắc chắn nếu câu trả lời sẽ có trong thời gian này. Vì vậy, tôi đã thực hiện một vòng lặp mà kiểm tra cho một câu trả lời mỗi 50 miliseconds, và nếu nó đã không đến ở tất cả sau 5 giây nó trả về. –

2

Không chắc chắn nội dung của bạn nhưng bạn nên thử ApnsPHP nó cũng được thử nghiệm hoạt động hoàn toàn tốt đẹp và nó có thể xử lý tất cả có thể ngoại lệ và lỗi cho bạn.

Alternatives khác

https://github.com/sebastianborggrewe/PHP-Apple-Push-Notification-Server https://github.com/bortuzar/PHP-Mysql---Apple-Push-Notification-Server

đã kiểm tra 2 trong số 3 i ví dụ và đã làm không có vấn đề về triển khai và quản lý lỗi.

Cảm ơn

:)

+0

Cảm ơn các lựa chọn thay thế này. – jsherk

Các vấn đề liên quan