|   | php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login | 
| 
  [2021-04-03 14:08 UTC] gilperon at gmail dot com
 Description:
------------
In any version of PHP (previous to 8) this bug didnt happen (I've been using it since 2010) but on PHP 8, the code below hangs indefinately. Tested on Windows 7, Windows 10, Centos 8 and Centos 7. The code below just tries to access an external API and, so far, I just managed to get this bug to happen on this specific URL below (from the API).
<?php
$response = file_get_contents("http://ws.correios.com.br/calculador/CalcPrecoPrazo.aspx?nCdEmpresa=&sDsSenha=&sCepOrigem=11661690&sCepDestino=88070-480&nVlPeso=1&nCdFormato=1&nVlComprimento=25&nVlAltura=3&nVlLargura=25&sCdMaoPropria=N&nVlValorDeclarado=0&sCdAvisoRecebimento=N&nCdServico=04014&nVlDiametro=0&StrRetorno=xml");
echo $response;
?>
BUT if I add a timeout, the code above works just fine:
<?php
$context = stream_context_create(array(
	"http" => array(
	
		"timeout" => 2
		
	)
));
$response = file_get_contents("http://ws.correios.com.br/calculador/CalcPrecoPrazo.aspx?nCdEmpresa=&sDsSenha=&sCepOrigem=11661690&sCepDestino=88070-480&nVlPeso=1&nCdFormato=1&nVlComprimento=25&nVlAltura=3&nVlLargura=25&sCdMaoPropria=N&nVlValorDeclarado=0&sCdAvisoRecebimento=N&nCdServico=04014&nVlDiametro=0&StrRetorno=xml",0,$context);
echo $response;
?>
I must say that using CURL works just fine, without any timeout, on any version of PHP. So this is a `file_get_contents` problem and the only way I am finding to solve this problem in the short term is using CURL.
Test script:
---------------
<?php
$response = file_get_contents("http://ws.correios.com.br/calculador/CalcPrecoPrazo.aspx?nCdEmpresa=&sDsSenha=&sCepOrigem=11661690&sCepDestino=88070-480&nVlPeso=1&nCdFormato=1&nVlComprimento=25&nVlAltura=3&nVlLargura=25&sCdMaoPropria=N&nVlValorDeclarado=0&sCdAvisoRecebimento=N&nCdServico=04014&nVlDiametro=0&StrRetorno=xml");
echo $response;
?>
Expected result:
----------------
Response should be printed.
Actual result:
--------------
The code hangs.
PatchesPull Requests
Pull requests: HistoryAllCommentsChangesGit/SVN commits             | |||||||||||||||||||||||||||||||||||||
|  Copyright © 2001-2025 The PHP Group All rights reserved. | Last updated: Fri Oct 31 19:00:02 2025 UTC | 
This bug is reproducible in macOS (v10.15.7) as well. And we can test it with a smaller script: ``` <?php $context = stream_context_create(['http' => ['timeout' => 2]]); echo file_get_contents("http://ws.correios.com.br/calculador/CalcPrecoPrazo.aspx?StrRetorno=xml", 0, $context); ```Actually, a smaller script "fixes" it not working in PHP 8.0: ``` <?php $context = stream_context_create(); echo file_get_contents("http://ws.correios.com.br/calculador/CalcPrecoPrazo.aspx?StrRetorno=xml", 0, $context); ``` @gilperon What is the value of your `default_socket_timeout` php.ini entry? That might explain why it is taking forever, because if the default of `60`, I waited and the scripted executed locally :)@carusogabriel@php.net the value of my `default_socket_timeout` is 60. I changed it to 5 seconds, restarted my server, and then I executed your code below: <?php $context = stream_context_create(); echo file_get_contents("http://ws.correios.com.br/calculador/CalcPrecoPrazo.aspx?StrRetorno=xml", 0, $context); ?> It always echoes nothing (blank string) after 5 seconds. However, the URL used above should return: <?xml version="1.0" encoding="ISO-8859-1" ?> <Servicos></Servicos> So setting `default_socket_timeout` to a smaller value does not work because the script still lasts all the time configured in `default_socket_timeout` and returns nothing.Setting the protocol back to 1.0 with the protocol version option appears to make it work on 8. I'll need to actually inspect the packets to have a deeper look. > But I am pretty sure it will start bothering many other devs as they > update their PHP to 8.x and start seeing their code breaking. To set your expectation, if this is a bug on the remote server, then it's unlikely we would write a hack around it. People can either use a workaround in their code, stay on PHP7, or ask the person who owns that site to fix it. It's not feasible to put work arounds in php core for all buggy servers out there. <?php $context = stream_context_create(array( "http" => array( "protocol_version" => "1.0" ) )); $response = file_get_contents("http://ws.correios.com.br/calculador/CalcPrecoPrazo.aspx?nCdEmpresa=&sDsSenha=&sCepOrigem=11661690&sCepDestino=88070-480&nVlPeso=1&nCdFormato=1&nVlComprimento=25&nVlAltura=3&nVlLargura=25&sCdMaoPropria=N&nVlValorDeclarado=0&sCdAvisoRecebimento=N&nCdServico=04014&nVlDiametro=0&StrRetorno=xml", 0, $context); echo "response length is " . strlen($response) . "\n";To confirm the below is enough to make this particular server respond in a way that PHP handles OK: diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c index da822d9160..7fdfa9448c 100644 --- a/ext/standard/http_fopen_wrapper.c +++ b/ext/standard/http_fopen_wrapper.c @@ -574,7 +574,7 @@ finish: * HTTP/1.0 to avoid issues when the server respond with a HTTP/1.1 * keep-alive response, which is the preferred response type. */ if ((have_header & HTTP_HEADER_CONNECTION) == 0) { - smart_str_appends(&req_buf, "Connection: close\r\n"); + smart_str_appends(&req_buf, "Connection: Close\r\n"); } if (context && However, the correct solution is probably to make the PHP implementation forcefully close connections when the server defaults to Keep-Alive behaviour.Simple reproduce script: php -r '$server = stream_socket_server("tcp://127.0.0.1:8080"); while ($client = stream_socket_accept($server)) { fwrite($client, "HTTP/1.1 200 OK\r\ncontent-length: 0\r\n\r\n"); }' php -r 'file_get_contents("http://127.0.0.1:8080/");'In my opinion, this is a PHP design problem for all versions. `file_get_content("http://*")` (php http stream wrapper) always depends on the behavior of the server. It always expects recv to return 0 and uses this to detect the end of the response. But, if the peer does not close the connection, it will wait for data forever. In this case, even if we set "Connection: close" when the protocol version is 1.1, the server still treats it as a persistent connection, although the server also has implementation problems, it did expose the problem of PHP. So we can reproduce this problem on almost all websites: <?php $context = stream_context_create(['http' => ['protocol_version' => 1.1, 'header' => ['Connection: keep-alive']]]); echo file_get_contents("http://www.baidu.com", 0, $context); // largest search engine in China // hang...Seems this (or a very similar) issue is back in PHP8.1.12 and 8.1.13. Super simple test case: <?php print file_get_contents('https'.'://'.'www'.'nrc'.'nl'); ?> It seems impossible to access the Dutch NRC website (national newspaper). This takes a very long time to run. It does eventually return. Accessing the same website from the cmdline via wget or curl is super fast. I've tested this on multiple PHP instances around the world, they all hang when running on PHP8.1.12 or 8.1.13. This same script ran fine (fast) on PHP 7.4.I can confirm this problem when using php inside a docker 4.15.0 container. try these docker commands (In my case, I call them inside WSL2 using Docker Desktop): This one works well (it returns fast): > docker run --rm php:7.3 php -d default_socket_timeout=10 -r "file_get_contents('https://github.com/');" while this one hits the timeout (in this case, 10 seconds) (remove spaces from url!): > docker run --rm php:7.3 php -d default_socket_timeout=10 -r "file_get_contents('https : // www . google . com /');" It's basically the same with PHP 7.4, 8.1, 8.2. However, with PHP 8.1 and 8.2, the command reaches twice the timeout - so it takes 20 seconds instead of 10! Not only file_get_contents() is affected by this problem, but also SoapClient::__construct(), for example.