Prevent timeout in PHP - php

I am working on a PHP script that makes an API call to a external site. However, if this site is not available or the request times out, I would like my function to return false.
I have found following, but I am not sure on how to implement it on my script, since i use "file_get_contents" to retrieve the content of the external file call.
Limit execution time of an function or command PHP
$fp = fsockopen("www.example.com", 80);
if (!$fp) {
echo "Unable to open\n";
} else {
fwrite($fp, "GET / HTTP/1.0\r\n\r\n");
stream_set_timeout($fp, 2);
$res = fread($fp, 2000);
$info = stream_get_meta_data($fp);
fclose($fp);
if ($info['timed_out']) {
echo 'Connection timed out!';
} else {
echo $res;
}
}
(From: http://php.net/manual/en/function.stream-set-timeout.php)
How would you adress such an issue? Thanks!

I'd recommend using the cURL family of PHP functions. You can then set the timeout using curl_setopt():
curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,2); // two second timeout
This will cause the curl_exec() function to return FALSE after the timeout.
In general, using cURL is better than any of the file reading functions; it's more dependable, has more options and is not regarded as a security threat. Many sysadmins disable remote file reading, so using cURL will make your code more portable and secure.

<?php
$fp = fsockopen("www.example.com", 80);
if (!$fp) {
echo "Unable to open\n";
} else {
stream_set_timeout($fp, 2); // STREAM RESOURCE, NUMBER OF SECONDS TILL TIMEOUT
// GET YOUR FILE CONTENTS
}
?>

From the PHP manual for File_Get_Contents (comments):
<?php
$ctx = stream_context_create(array(
'http' => array(
'timeout' => 1
)
)
);
file_get_contents("http://example.com/", 0, $ctx);
?>

<?php
$fp = fsockopen("www.example.com", 80, $errno, $errstr, 4);
if ($fp) {
stream_set_timeout($fp, 2);
}

Related

Writing and Reading from a socket a second time

I connect to the whois server and am able to retrieve the availability of a domain name.
Somehow I am not able to get a response back using the same connection when I do a request of a different domain name.
<?php
$context = stream_context_create();
if($fp = stream_socket_client("tcp://whois.eu:43", $errno, $errstr, 30, STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT, $context)) {
stream_set_timeout($fp, 30);
$domains = array('test.eu','amaai.eu');
foreach($domains as $domain) {
fwrite($fp, $domain."\r\n");
$contents = '';
while (!feof($fp)) {
$contents .= fread($fp, 8192);
}
echo $domain.": ".$contents;
}
fclose($fp);
}
What am I missing?
I really want to use the same connection.
The WHOIS protocol only supports one query. The server closes the connection after sending a response. You need to reconnect for each query.

PHP stream_socket_client with timeout on wss (ssl:// port 443) not working

I think I came down to a very specific PHP bug, that the timeouts set by stream_set_timeout() doesn't get obeyed, ONLY if using SSL websockets.
I am able to reproduce it with the following simple script:
<?php
$context = stream_context_create();
$fp = stream_socket_client ("ssl://echo.websocket.org:443",$errno,$errstr,5,STREAM_CLIENT_CONNECT,$context);
stream_set_timeout($fp, 5);
if (!$fp) {
echo "Unable to open\n";
} else {
//fwrite($fp, "GET / HTTP/1.0\r\n\r\n");
stream_set_timeout($fp, 5);
$res = fread($fp, 2000);
$info = stream_get_meta_data($fp);
//fclose($fp);
if ($info['timed_out']) {
echo 'Connection timed out!';
} else {
echo $res;
}
}
If you switch out ssl://echo.websocket.org:443 with tcp://echo.websocket.org:80, the timeout gets triggered correctly after 5 seconds.
Is this a PHP bug or am I missing some sort of setting?

PHP fsockopen client doesn't receive sent data

I have the following (stripped-down) piece of code:
function curl_request_async($url, $params)
{
foreach ($params as $key => $val) {
$post_params[] = $key.'='.urlencode($val);
}
$post_string = implode('&', $post_params);
$parts=parse_url($url);
$fp = fsockopen($parts['host'],
isset($parts['port'])?$parts['port']:80,
$errno, $errstr, 30);
fwrite($fp, "$type ".$parts['path']." HTTP/1.1\r\n");
fwrite($fp, "Host: ".$parts['host']."\r\n");
fwrite($fp, "Content-Type: application/x-www-form-urlencoded\r\n");
fwrite($fp, "Content-Length: ".strlen($post_string)."\r\n");
fwrite($fp, "Connection: Close\r\n\r\n");
$bytes_written = fwrite($fp, $post_string);
var_dump($bytes_written, strlen($post_string));
// fread($fp, 1);
// fflush($fp);
fclose($fp);
}
The problem with this code is that I found no evidence the request reached the server called. The line var_dump($bytes_written, strlen($post_string)); outputted int(493) int(493), so it should have received all data, yet it didn't.
If I uncomment fread($fp, 1); it works without a problem. That could be working solution, but it doesn't seem to make sense. There has to be a better way!
My question then is two-fold: why does fread($fp, 1); fix my problem and is there a better solution?
your problem is probably that you wrote the server code in PHP, and you dont have ignore_user_abort=true by default (see http://php.net/manual/en/misc.configuration.php#ini.ignore-user-abort ), so when you close the connection, your server stop executing your php code, thus fread(fp,1) fix your problem - connection dont close before php start writing a response
you can use this code to make a server to test if its actually connecting or not -
<?php
error_reporting(E_ALL);
ini_set('display_errors',1);
$sck=socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
if($sck===FALSE){
die('socket_create failed!');
}
if(!socket_set_block($sck)){
die("socket_set_block failed!");
}
if(!socket_bind($sck, '0.0.0.0',1337)){
die("FAILED to bind to port 1337");
}
if(!socket_listen($sck,0)){
die("socket_listen failed!");
}
$fullFile='';
while((print('listening for connections!'.PHP_EOL)) && false!==($conn=socket_accept($sck))){
echo "new connection!".PHP_EOL;
echo "generating crypto iv..";
while(false!==($buffi=socket_recv($conn,$buff,1024,MSG_WAITALL))){
if($buffi===0){
break;//socket_recv's way of
//saying that the connection closed,
//apparently. the docs say it should return
// false, but it doesn't, it just infinitely returns int(0).
// at least on windows 7 x64 sp1.
}
$fullFile.=$buff;
echo "recieved ".strlen($fullFile)." bytes...".PHP_EOL;
$buff='';//do i need to clear it? or wiill recv do it for me?
}
echo "all bytes recieved (i guess, todo, socket_last_error confirm).";
echo PHP_EOL;var_dump($fullFule);
echo "done!".PHP_EOL;
}
die("should never reach this code...");
it will make a netcat-style server on http://127.0.0.1:1337
fread needs two parameters: a resource and a length number of bytes to read.
Right now you are only reading 1 byte. fread($fp, 1);
If you want to read the complete result, loop it until readed completely:
while(!feof($fp)){
echo fread($fp, 128);
}

How to limit http response time in php

I'm using some sites to detect my site visitor's country. I mean like this
$ip = $_SERVER['REMOTE_ADDR'];
$url1 = 'http://api.hostip.info/get_json.php?ip='.$ip;
$url2 = 'http://ip2country.sourceforge.net/ip2c.php?format=JSON&ip='.$ip;
Sometimes sites like sourgeforge taking too much time to load.
So can anyone tell how to limit the http response time.?
if url1 is down or not responded in x seconds then move to url2,url3,etc
$context = stream_context_create(array(
'http' => array(
'method' => 'GET',
, 'timeout' => 3
)
));
Then supply the stream context to fopen() or file_get_contents() etc...
http://php.net/manual/en/stream.contexts.php
http://php.net/manual/en/context.http.php
The manual calls that a "read timeout". I worry it may not include time for stuff like dns resolution + socket connection. I think the timeout before php tries reading from the stream may be governed by the default_socket_timeout setting.
You may want to consider curl, it seems a bit more specific, but I'm not sure if CURLOPT_TIMEOUT is inclusive of CURLOPT_CONNECTTIMEOUT.
$ch = curl_init();
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 2);
curl_setopt($ch, CURLOPT_TIMEOUT, 2);
http://php.net/manual/en/function.curl-setopt.php
If this is done using streams, you could use stream_set_timeout for this. A decent example from the php manual, it also describes more advanced ways of archieving this:
$fp = fsockopen("www.example.com", 80);
if (!$fp) {
echo "Unable to open\n";
} else {
fwrite($fp, "GET / HTTP/1.0\r\n\r\n");
stream_set_timeout($fp, 2);
$res = fread($fp, 2000);
$info = stream_get_meta_data($fp);
fclose($fp);
if ($info['timed_out']) {
echo 'Connection timed out!';
} else {
echo $res;
}
}
There is another solution, just download the DB and offer that service to yourself on a faster machine of your own:
IP to Geolocation db

Can I open socket in PHP from a specific IP (if the machine has two IPs)?

I'm using PHPMailer and it uses fsockopen to access the SMTP server.
But the machine has two IPs with different reverse DNS records. So in email headers I got the following:
Received: from one-server.tld (HELO another-server.tld) ...
I need to hide one-server.tld in favor of another-server.tld. But I need both IPs with their current RDNS settings.
I think its not possible using fsockopen. But its possible in curl, fopen and stream functions. What you need is stream_socket_client() function.
Here are some ways to achieve it.
Using context parameters which can be used in fopen function family and stream function family. See the example.
$opts = array(
'socket' => array(
'bindto' => '192.168.0.100:0',
),
);
// create the context...
$context = stream_context_create($opts);
$contents = fopen('http://www.example.com', 'r', false, $context);
Also stream_socket_client
$fp = stream_socket_client("tcp://www.example.com:80", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $opts);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
fwrite($fp, "GET / HTTP/1.0\r\nHost: www.example.com\r\nAccept: */*\r\n\r\n");
while (!feof($fp)) {
echo fgets($fp, 1024);
}
fclose($fp);
}
Using socket_bind. PHP.NET got a simple example here.

Categories