带有 PHP 的 APNS 显示 SSL 损坏的管道错误

Posted

技术标签:

【中文标题】带有 PHP 的 APNS 显示 SSL 损坏的管道错误【英文标题】:APNS with PHP shows SSL broken pipe error 【发布时间】:2017-11-24 03:54:19 【问题描述】:

在我的项目中,大约有 500 个 ios 用户。向他们发送推送通知会显示以下错误。

Severity: Warning
Message:  fwrite(): SSL: Broken pipe
Message:  fwrite(): SSL operation failed with code 1. OpenSSL Error messages:
error:1409F07F:SSL routines:ssl3_write_pending:bad write retry

直到某些令牌工作正确,结果为整数,例如 181,因为从结果为 0 的第一个令牌开始显示上述错误。是由于令牌无效吗?。我无法区分生产和开发令牌。请帮助。提前致谢。 我的代码

public function connectApns()

            try

                $ctx = stream_context_create();
                stream_context_set_option($ctx, 'ssl', 'local_cert',$_SERVER['DOCUMENT_ROOT'].'/webservice/application/libraries/ck.pem');
                stream_context_set_option($ctx, 'ssl','passphrase', '1234');
                $this->fp = stream_socket_client('ssl://gateway.push.apple.com:2195', $err,$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);


                    if($this->fp)
                        return TRUE;
                    else
                        echo $errstr;
                        return FALSE;
                    
                
            catch(Exception $e1)

                echo $e1->getMessage();

            

        

    public function iOS($data,$columnName)

            $ids = array();
            $tokens = array();
            $sql = "SELECT user_id FROM tp_notification WHERE ";
            if($columnName == "job")
               $sql = $sql." job = 1"; 
            
            if($columnName == "hostel")
                $sql = $sql." hostel = 1";
            
            if($columnName == "event")
                $sql = $sql." event = 1";
            
            if($columnName == "bazar")
                $sql = $sql." bazar = 1";    
            
            if($columnName == "share")
                $sql = $sql." share = 1"; 
            
            if($columnName == "court")
                $sql = $sql." court = 1";
            
            if($columnName == "contest")
                $sql = $sql." contest = 1";
            
            if($columnName == "")

                $sql = "SELECT user_id FROM tp_notification";
            
            $query = $this->CI->db->query($sql);
            if($query)
                $mid_result = $query->result_array();
                foreach ($mid_result as $value)
                
                    $ids[] = $value['user_id'];
                
                if(count($ids) > 0)
                    $sql1 = "SELECT device_token FROM tp_user WHERE user_id IN ? AND device_type = ? AND user_active = ? ORDER BY user_id DESC";
                    $query1 = $this->CI->db->query($sql1,array($ids,'iOS',1));
                    if($query1)
                        $mid_result1 = $query1->result_array();
                        foreach ($mid_result1 as $key)
                        
                            $tokens[] = $key['device_token'];
                         
                       
                
            


            if(count($tokens) > 0)

                $isConnected = $this->connectApns();

                if ($isConnected)
                    for($i = 0; $i < count($tokens); $i++)


                        $sql5 = "SELECT badge FROM tp_user WHERE device_token = ?";
                        $query5 = $this->CI->db->query($sql5,array($tokens[$i]));
                        $badge = 0;
                        if($query5)
                            $mid_result5 = $query5->row();
                            $badge = $mid_result5->badge + 1;
                        
                        $body['aps'] = array(
                                        'alert' => array(
                                        'title' => $data['title'],
                                        'body' => $data['data'],
                                        'type'=>$data['type'],
                                        'id'=>$data['id']
                                        ),
                                        'content-available'=>1,
                                        'badge'=>$badge,
                                        'sound' => 'default'
                                    );
                        $deviceToken = $tokens[$i];

                        $payload = json_encode($body);
                        $msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;
                        try    
                                                        if(strlen($deviceToken) == 64)



                                                              $result = fwrite($this->fp, $msg, strlen($msg));





                            if($result)


                                $sql6 = "UPDATE tp_user SET badge=? WHERE device_token=?";
                                $query6 = $this->CI->db->query($sql6,array($badge,$tokens[$i]));

                               else

                                fclose($this->fp);  
                                sleep(5);
                                $this->connectApns();
                            
                         catch(Exception $e)

                            fclose($this->fp);  
                            sleep(3);
                            $this->connectApns();

                        



                    

                    fclose($this->fp);

                
            
        

【问题讨论】:

包含与您的问题相关的代码。 我的代码如上图 【参考方案1】:

定义常量

  define('Apple_HOST','gateway.push.apple.com');
  define('Apple_API_NOTI',"abc.pem");   // write here path  pem file

调用函数->

 sendPushIos("write here device token",array('alert' =>$message, 'badge' => 1, 'sound' => 'default','flag'=>$flag)) 

ios通知发送功能->

                function sendPushIos($dEvicetoken,$arrayY)
                            $apnsHost = Apple_HOST;
                            $apnsCert =Apple_API_NOTI;
                            $apnsPort = 2195;
                            $token=$dEvicetoken;
                            $streamContext = stream_context_create();
                            @stream_context_set_option($streamContext, 'ssl', 'local_cert', $apnsCert);
                            $apns = stream_socket_client('ssl://' . $apnsHost . ':' . $apnsPort, $error, $errorString, 2, STREAM_CLIENT_CONNECT, $streamContext);
                            $payload['aps'] =$arrayY;
                            $output = json_encode($payload);
                            $token = pack('H*', str_replace(' ', '', $token));
                            $apnsMessage = chr(0) . chr(0) . chr(32) . $token . chr(0) . chr(strlen($output)) . $output;
                    if(fwrite($apns, $apnsMessage))
                    
                        @socket_close($apns);
                        fclose($apns);
                         return TRUE;
                else
                        return FALSE;
                    
 

注意:2195端口必须打开

【讨论】:

很少有通知发送,对于那些结果大于0,然后结果变为0,然后显示ssl损坏管道错误。这个问题与SSL有关吗? 现在它可以工作了。我将 if(strlen($deviceToken)) 循环扩展到 try 的右括号之前。即到最后。

以上是关于带有 PHP 的 APNS 显示 SSL 损坏的管道错误的主要内容,如果未能解决你的问题,请参考以下文章

Worklight 推送通知 (APNS) 失败并出现 javax.net.ssl.SSLHandshakeException

从 ASPX/C# 页面发送 APNS,使用 SSL 进行身份验证

带有 PHP 的 iOS 13 APNS

iOS APNs 推送通知 - 开发

傻瓜的 APNS 反馈和 PHP

APNS - 通知推送 ios:对等 PHP 重置连接