title: file_get_contents() does not timeout / return error with HTTPS urls
body: <p>I do not know why, but I have one specific URL that does not timeout (tested several thousand others without problems):</p>
  
  <pre><code>&lt;?php
  $url = 'https://....';
  $context = stream_context_create(array(
      'http' =&gt; array(
          'follow_location' =&gt; false,
          'timeout' =&gt; 2,
      )
  ));
  file_get_contents($url, false, $context);
  ?&gt;
  </code></pre>
  
  <p>If I set <code>follow_location</code> to <code>true</code> it works without problems.</p>
  
  <p><strong>Update 1</strong><br>
  The call of <code>file_get_contents</code> does not respect the <code>'timeout' =&gt; 2</code> and it does not respect PHP <code>max_execution_time</code>, but there seems to be a third timeout on the server itself. It returns an <code>Internal Server Error 500</code> after 10 (!) minutes.</p>
  
  <p><strong>Update 2</strong><br>
  I tried the same URL with cURL and there is no timeout problem but it returns <code>false</code>:</p>
  
  <pre><code>&lt;?php
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_HEADER, true);
  curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  $contents = curl_exec($ch);
  var_dump($contents);
  ?&gt;
  </code></pre>
  
  <p>What is needed to let cURL return false?</p>
  
  <p><strong>Update 3</strong><br>
  Ok now I catched it:</p>
  
  <pre><code>if ($contents === false) {
      echo curl_error($ch) . ' (' . curl_errno($ch) . ')' . PHP_EOL;
  }
  </code></pre>
  
  <p>returns:</p>
  
  <blockquote>
    <p>SSL certificate problem: unable to get local issuer certificate (60)</p>
  </blockquote>
  
  <p>This means every time this error occurs <code>file_get_contents()</code> does not respect an timeout if <code>follow_location</code> is set to <code>false</code>. Sounds like a bug for me.</p>
  
  <p><strong>Update 4</strong><br>
  As @huggilou suggested I tried several additional settings and after setting this I'm able to load the URL:</p>
  
  <pre><code>curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
  </code></pre>
  
  <p>Is there a similar setting for <code>file_get_contents()</code>?</p>
  
  <p><strong>Update 5</strong>  </p>
  
  <p>Now I tried the following:</p>
  
  <pre><code>$context = stream_context_create(array(
      'http' =&gt; array(
          'follow_location' =&gt; false,
          'timeout' =&gt; 2,
      ),
      'ssl' =&gt; array(
          'verify_peer' =&gt; false,
      ),
  ));
  echo file_get_contents($url, false, $context);
  </code></pre>
  
  <p>This caused the timeout problem. After that I changed <code>verify_peer</code> to <code>true</code> and got this result:</p>
  
  <blockquote>
    <p><br /> <b>Warning</b>:  file_get_contents(): SSL operation failed with
    code 1. OpenSSL Error messages: error:14090086:SSL
    routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed in
    <b>/usr/www/users//t051.php</b> on line <b>12</b><br /> <br />
    <b>Warning</b>:  file_get_contents(): Failed to enable crypto in
    <b>/usr/www/users//t051.php</b> on line <b>12</b><br /> <br />
    <b>Warning</b>:  file_get_contents(<a href="https://.." rel="nofollow noreferrer">https://..</a>.):
    failed to open stream: operation failed in
    <b>/usr/www/users//t051.php</b> on line <b>12</b><br /></p>
  </blockquote>
  
  <p>By that we know: <code>verfiy_peer</code> is set to <code>false</code> by default.</p>
  
  <p>And to remind: If I set <code>verify_peer</code> to <code>false</code> and <code>follow_location</code> to <code>true</code> the website is loaded!?</p>
  
  <p><strong>Update 6</strong><br>
  As @huggilou pointed to that:</p>
  
  <pre><code>&lt;?php
  $w = stream_get_wrappers();
  echo 'allow_url_fopen: ', ini_get('allow_url_fopen') ? 'yes':'no', PHP_EOL;
  echo 'openssl: ',  extension_loaded('openssl') ? 'yes':'no', PHP_EOL;
  echo 'http wrapper: ', in_array('http', $w) ? 'yes':'no', PHP_EOL;
  echo 'https wrapper: ', in_array('https', $w) ? 'yes':'no', PHP_EOL;
  echo 'wrappers: ', var_dump($w);
  ?&gt;
  </code></pre>
  
  <p>returns:</p>
  
  <pre><code>allow_url_fopen: yes
  openssl: yes
  http wrapper: yes
  https wrapper: yes
  wrappers: array(12) {
    [0]=&gt;
    string(5) "https"
    [1]=&gt;
    string(4) "ftps"
    [2]=&gt;
    string(13) "compress.zlib"
    [3]=&gt;
    string(14) "compress.bzip2"
    [4]=&gt;
    string(3) "php"
    [5]=&gt;
    string(4) "file"
    [6]=&gt;
    string(4) "glob"
    [7]=&gt;
    string(4) "data"
    [8]=&gt;
    string(4) "http"
    [9]=&gt;
    string(3) "ftp"
    [10]=&gt;
    string(4) "phar"
    [11]=&gt;
    string(3) "zip"
  }
  </code></pre>
  
  <p><strong>Update 7</strong><br>
  cURL returns for <a href="https://www.example.com/foo.html" rel="nofollow noreferrer">https://www.example.com/foo.html</a> this header:</p>
  
  <pre><code>string(138) "HTTP/1.1 301 Moved Permanently
  Location: http://example.com/foo.html
  Content-Length: 0
  Content-Type: text/html; charset=UTF-8
  
  "
  </code></pre>
  
  <p><strong>Update 8</strong><br>
  <a href="https://www.ssllabs.com/ssltest/analyze.html?d=example.com" rel="nofollow noreferrer">https://www.ssllabs.com/ssltest/analyze.html?d=example.com</a> returns:
  <img src="https://i.stack.imgur.com/XN3nY.png" alt="enter image description here"></p>
  
  <p><strong>Update 9</strong><br>
  I tried the same script and URL through a foreign server and there it works. Of course it needs <code>verify_peer</code> set to <code>false</code> to avoid the ssl certificate error posted in <strong>Update 5</strong>. I checked <code>phpinfo()</code>. There are some differences. But both use <code>SSL Version OpenSSL/1.0.1e</code> and <code>PHP Version 5.5.23</code> through <code>CGI/FastCGI</code>, but one setting on my server attracts my attention:</p>
  
  <pre><code>Registered Stream Socket Transports tcp, udp, unix, udg, ssl, sslv3, tls
  </code></pre>
  
  <p>The foreign server has in addition <code>sslv2</code>. Could that be the reason?</p>
  
  <p><strong>Update 10 - temporarily solved</strong><br>
  After exchanging some emails with my hosting provider a technician wanted to play around with a new script (<code>follow_location=false</code> and <code>verify_peer=false</code>) and executed it through the console:</p>
  
  <pre><code>php -d allow_url_fopen=On ./t052.php |less
  </code></pre>
  
  <p>Then he emailed me that he had no problem. I tested it by myself through the browser and suprisingly his and all my other test scripts work again?! He confirmed me that he did not change anything. This is really frustrating as it looks like a random behaviour now. As this project is still running and collecting URLs I will update my question if it happens again.</p>