title: Only from PHP: Unable to connect APNS gateway.push.apple.com:2195
body: <p><em>It's a late night. I just spent 10 hours in google/stackoverflow search and experiments. And seems I hate Apple Push Notifications. I'm totally frustrated and will appreciate any help.</em></p>
  
  <p><em>Thank you.</em></p>
  
  <h2>The problem:</h2>
  
  <p>The PHP code for sending Apple Push Notifications, which successfully worked two weeks ago stopped to work now and throws following errors:</p>
  
  <pre><code>PHP Warning:  stream_socket_client(): Failed to enable crypto in /home/...
  PHP Warning:  stream_socket_client(): unable to connect to ssl://gateway.push.apple.com:2195 (Unknown error) in /home/...
  </code></pre>
  
  <p>It stopped to work on two separate servers, which are using separate scripts for APNs sending.</p>
  
  <h2>Environment:</h2>
  
  <p>Servers: CentOS 6.5 with PHP 5.4.32 and Ubuntu 14.04.3 with PHP 5.5.9</p>
  
  <p>APN: In production mode</p>
  
  <p>Certificates: tested with 700+ push notifications.</p>
  
  <p>One of the servers is using <a href="https://github.com/immobiliare/ApnsPHP" rel="noreferrer">https://github.com/immobiliare/ApnsPHP</a>, other - <a href="https://github.com/antongorodezkiy/wp-apn" rel="noreferrer">https://github.com/antongorodezkiy/wp-apn</a>, on localhost I tested simple file without using any third party code.</p>
  
  <h2>Investigation:</h2>
  
  <p>For all cases below I used the same active device token and the same production PEM certificate.</p>
  
  <h3>php</h3>
  
  <p>However, even this simple code <strong>doesn't work</strong> on both servers and localhost and return the same error as above:</p>
  
  <pre><code>$ctx = stream_context_create();
  stream_context_set_option($ctx, 'ssl', 'local_cert', '/absolute/path/to/apn_prod.pem');
  
  // Open a connection to the APNS server
  $fp = stream_socket_client(
      'ssl://gateway.push.apple.com:2195', $err,
      $errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
  </code></pre>
  
  <p>I also tried to play with <code>stream_context_set_option()</code> options, include <code>entrust_2048_ca.cer</code>, etc, and even some options from <a href="https://wiki.php.net/rfc/improved-tls-defaults" rel="noreferrer">this article</a>. Although provided code worked without any modifications before August 2015.</p>
  
  <h3>openssl</h3>
  
  <p><strong>Connection worked</strong> with openssl (<a href="https://developer.apple.com/library/mac/technotes/tn2265/_index.html" rel="noreferrer">link</a>):</p>
  
  <pre><code>openssl s_client -connect gateway.push.apple.com:2195 -cert /absolute/path/to/apn_prod.pem -debug -showcerts -CAfile /absolute/path/to/server-ca-cert.pem
  </code></pre>
  
  <p>And got with <code>CONNECTED(00000003)</code> and <code>Verify return code: 0 ( ok )</code>.</p>
  
  <h3>telnet</h3>
  
  <p><strong>Connection worked</strong> with telnet:</p>
  
  <pre><code>-sh-4.1$ telnet gateway.push.apple.com 2195
  Trying 17.172.233.150...
  Connected to gateway.push.apple.com.
  </code></pre>
  
  <h3><a href="http://libcapn.org/php-apn/" rel="noreferrer">pecl apn</a></h3>
  
  <p><strong>It didn't send push notification</strong>. I just tried to use adaptation of <a href="http://libcapn.org/php-apn/doc/html/examples.html" rel="noreferrer">sample code</a>, but got the error <code>Invalid token</code>. The token is active and same token I used everywhere and for Houston and Ruby too.</p>
  
  <h3><a href="https://github.com/nomad/Houston" rel="noreferrer">houston</a></h3>
  
  <p><strong>It worked</strong> with Houston</p>
  
  <pre><code>apn push "0346a53f...231d9d6abe11" -c /absolute/path/to/apn_prod.pem -m "Hello from the command line!" -e "production"
  </code></pre>
  
  <h3>ruby</h3>
  
  <p>I'm not a Ruby programmer (yet at least), but after success with Houston, I found and adapted Ruby code without Houston dependency.</p>
  
  <p>And <strong>it worked</strong>:</p>
  
  <pre><code>#!/usr/bin/env ruby
  
  require 'openssl'
  require 'socket'
  require 'json'
  
  token = "0346a53f...231d9d6abe11"
  cert = File.read("/absolute/path/to/apn_prod.pem")
  ctx = OpenSSL::SSL::SSLContext.new
  ctx.key = OpenSSL::PKey::RSA.new(cert, '') #set passphrase here, if any
  ctx.cert = OpenSSL::X509::Certificate.new(cert)
  
  sock = TCPSocket.new('gateway.push.apple.com', 2195) #development gateway
  ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
  ssl.connect
  
  payload = {"aps" =&gt; {"alert" =&gt; "Oh hai!", "badge" =&gt; 1, "sound" =&gt; 'default'}}
  json = payload.to_json()
  token =  [token.delete(' ')].pack('H*') #something like 2c0cad 01d1465 346786a9 3a07613f2 b03f0b94b6 8dde3993 d9017224 ad068d36
  apnsMessage = "\0\0 #{token}\0#{json.length.chr}#{json}"
  ssl.write(apnsMessage)
  
  ssl.close
  sock.close
  
  puts "End"
  </code></pre>
  
  <h1>Questions:</h1>
  
  <ol>
  <li>What's wrong with PHP? Is there some bug related to this issue? (I didn't find bug report though)</li>
  <li>Any ideas how to solve this issue?</li>
  <li>Any ideas what could be the difference in PHP and Ruby cases (I assume that Python or Perl could work fine too)? I even tried to read PHP sources, but without success to understand how <code>stream_socket_client()</code> implemented.</li>
  </ol>
  
  <h3><em>Please help.</em></h3>