186

I am calling a series of links using the file_get_contents() method in a loop. Each link may take more than 15 minutes to process. Now, I worry about whether PHP's file_get_contents() has a timeout period?

If yes, it will time out with a call and move to next link. I don't want to call the next link without the prior one finishing.

So, please tell me whether file_get_contents() has a timeout period. The file which contains the file_get_contents() is set to set_time_limit() to zero (unlimited).

Chris Trudeau
  • 1,427
  • 3
  • 16
  • 20
Flora Clinton
  • 1,871
  • 2
  • 11
  • 3
  • Cross-Reference: [Handling delays when retrieving files from remote server in PHP](http://stackoverflow.com/q/1605063/367456) – hakre Jan 12 '14 at 09:54
  • I've experienced the same behaviour (timeout when querying URL on the same "server") inside a Visual Studio PHP project that uses the PHP Tools for Visual Studio extensions. [More information here](http://support.devsense.com/viewtopic.php?f=21&t=1916). – Uwe Keim Oct 31 '16 at 10:24
  • 1
    This happens also when using the [built-in PHP server to query an URL on the same website](https://bugs.php.net/bug.php?id=63102), because it is a single-threaded web server. – Uwe Keim Oct 31 '16 at 10:34
  • https://gist.github.com/sabarasaba/1387550 – Hayden Thring Jul 07 '21 at 09:41

6 Answers6

344

The default timeout is defined by default_socket_timeout ini-setting, which is 60 seconds. You can also change it on the fly:

ini_set('default_socket_timeout', 900); // 900 Seconds = 15 Minutes

Another way to set a timeout, would be to use stream_context_create to set the timeout as HTTP context options of the HTTP stream wrapper in use:

$ctx = stream_context_create(array('http'=>
    array(
        'timeout' => 1200,  //1200 Seconds is 20 Minutes
    )
));

echo file_get_contents('http://example.com/', false, $ctx);
fooquency
  • 1,575
  • 3
  • 16
  • 29
stewe
  • 41,820
  • 13
  • 79
  • 75
  • 10
    Can you give info about how to set timeout for https url? – Vinay May 29 '13 at 13:35
  • 11
    this thing is not working perfectly, if your value is 1200, its actually is 2400. i just test it. – TomSawyer Oct 26 '13 at 15:46
  • 20
    default_socket_timeout, stream_set_timeout, and stream_context_create timeout are all the timeout of every line read/write, not the whole connection timeout. – diyism Nov 04 '14 at 08:27
41

As @diyism mentioned, "default_socket_timeout, stream_set_timeout, and stream_context_create timeout are all the timeout of every line read/write, not the whole connection timeout." And the top answer by @stewe has failed me.

As an alternative to using file_get_contents, you can always use curl with a timeout.

So here's a working code that works for calling links.

$url='http://example.com/';
$ch=curl_init();
$timeout=5;

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);

$result=curl_exec($ch);
curl_close($ch);
echo $result;
fracz
  • 20,536
  • 18
  • 103
  • 149
Randell
  • 6,112
  • 6
  • 45
  • 70
  • 2
    This answer gives another approach to controlling the connect timeout (using `fsockopen` instead of `curl`): http://stackoverflow.com/a/3690321/1869825 – stevo Apr 07 '15 at 19:51
  • 2
    you should set both CURLOPT_CONNECTTIMEOUT and CURLOPT_TIMEOUT in curl. See http://stackoverflow.com/a/27776164/1863432 – bhelm May 02 '16 at 13:36
  • 2
    Is not a valid response, the question is for "file_get_contents". The response is great but inapropiate. – e-info128 Mar 23 '19 at 21:38
32

Yes! By passing a stream context in the third parameter:

Here with a timeout of 1s:

file_get_contents("https://abcedef.com", 0, stream_context_create(["http"=>["timeout"=>1]]));

Source in comment section of https://www.php.net/manual/en/function.file-get-contents.php

HTTP context options:

method
header
user_agent
content
request_fulluri
follow_location
max_redirects
protocol_version
timeout

Non HTTP stream contexts

Socket
FTP
SSL
CURL
Phar
Context (notifications callback)
Zip
NVRM
  • 11,480
  • 1
  • 88
  • 87
  • 2
    The answer with 286 rep didn't work, but yours did :) – VE7JRO Feb 17 '20 at 02:21
  • 5
    The timeout given in `stream_context_create` only works for connection timeout. If the server replies (sends some data) within the given timeout, but takes forever to send the rest of its payload, this timeout doesn't interrupt the slow transfer. – z80crew Apr 22 '20 at 12:43
6

It is worth noting that if changing default_socket_timeout on the fly, it might be useful to restore its value after your file_get_contents call:

$default_socket_timeout = ini_get('default_socket_timeout');
....
ini_set('default_socket_timeout', 10);
file_get_contents($url);
...
ini_set('default_socket_timeout', $default_socket_timeout);
Pascal Roget
  • 793
  • 9
  • 12
  • 1
    but you know that ini_set doesn't set the things permanently, right? so basically 4 half of your script is just useless – Flash Thunder Mar 03 '19 at 15:02
  • 3
    @FlashThunder Not if there is another call to file_get_contents later in the code that requires the previous timeout. Restoring settings changed on the fly for a specific bit of code after that code has executed is generally good practice. – Leigh Bicknell Mar 13 '19 at 12:38
  • 2
    @FlashThunder it is good practice to restore the socket_timeout value after a call so that subsequent calls to the same function **in the same script execution** use global settings. – Pascal Roget Aug 08 '19 at 14:14
  • isn't it better to use `ini_restore('default_socket_timeout');` instead? https://www.php.net/manual/en/function.ini-restore.php – MMMahdy-PAPION Feb 07 '21 at 15:07
1

For me work when i change my php.ini in my host:

; Default timeout for socket based streams (seconds)
default_socket_timeout = 300
Max
  • 526
  • 6
  • 12
-2

For prototyping, using curl from the shell with the -m parameter allow to pass milliseconds, and will work in both cases, either the connection didn't initiate, error 404, 500, bad url, or the whole data wasn't retrieved in full in the allowed time range, the timeout is always effective. Php won't ever hang out.

Simply don't pass unsanitized user data in the shell call.

system("curl -m 50 -X GET 'https://api.kraken.com/0/public/OHLC?pair=LTCUSDT&interval=60' -H  'accept: application/json' > data.json");
// This data had been refreshed in less than 50ms
var_dump(json_decode(file_get_contents("data.json"),true));
NVRM
  • 11,480
  • 1
  • 88
  • 87
  • never ever do that. Aside of opening a bunch of potential security holes, depending on context, you have a full curl API in every PHP installation. – John Jan 02 '21 at 16:02
  • I do that all the time since years for my personal scripts, and this has never cause issues. The key part is the `-m` param. Security holes, only if using unsanitized user data, as warned. This is btw the sole one liner that fully works on all this answers. Read again. – NVRM Jan 02 '21 at 22:51
  • PHP doesn't have curl built-in unlike what you are believing, you have to install the separated package `php-curl`. But shell curl is always available. – NVRM Jan 02 '21 at 23:06
  • The PHP environment of anyone asking this question does have libcurl available, anyone who doesn't probably doesn't need to ask that question. Using such shell executions is the dirtiest way you could write something. – John Jan 03 '21 at 00:45
  • `Using such shell executions is the dirtiest way you could write something` Ha ha are you serious with this statment. Basically saying that bash is dirty. Or Linux is dirty. See my other answer here for a pure php way. Still not as reliable as what I am showing here. – NVRM Mar 28 '21 at 13:58
  • I agree with @NVRM, as long as you know what you're doing there's nothing wrong with calling a shell script / bash from PHP. The only pain is that it's a bit trickier to process any output (STDOUT, STDERR) and the fact that's probably not portable. – Marco Nov 23 '21 at 17:45
  • However, it's always preferable to use direct API calls (such as `curl_*`), as these provide easier management of configuration etc. – Marco Nov 23 '21 at 17:53
  • Sure of course, it is not recommended, maybe *dirty*, but I left a proper way as answer on this page already `stream_context()`. Again calling the shell curl does solve the problem raised in the comment by @z80crew `timeout doesn't interrupt the slow transfer. ` . That's right, and using the `-m` param in the shell call to curl, as shown on this answer, is efficiently timing out as expected on every conditions. Also using php-curl does not enhance the single threading normal behaviour of PHP and may cause latencies. – NVRM Nov 23 '21 at 18:04
  • 2
    I don't think it's _dirty_, sometimes using the shell is the only way to access a third party module/program. – Marco Nov 23 '21 at 18:12