PHPerKaigi 2024

stream_set_timeout

(PHP 4 >= 4.3.0, PHP 5, PHP 7, PHP 8)

stream_set_timeoutストリームにタイムアウトを設定する

説明

stream_set_timeout(resource $stream, int $seconds, int $microseconds = 0): bool

stream にタイムアウトの値を設定します。 この値は、secondsmicroseconds の和で表されます。

ストリームがタイムアウトとなった場合は、 stream_get_meta_data() が返す配列のキー 'timed_out' の値が true に設定されます。エラーや警告が発生していなくても同様になります。

パラメータ

stream

対象となるストリーム。

seconds

設定したいタイムアウトの秒数部分。

microseconds

設定したいタイムアウトのマイクロ秒数部分。

戻り値

成功した場合に true を、失敗した場合に false を返します。

例1 stream_set_timeout() の例

<?php
$fp
= fsockopen("www.example.com", 80);
if (!
$fp) {
echo
"開けません\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;
}

}
?>

注意

注意:

この関数では、stream_socket_recvfrom() のような 高度な操作はできません。そのかわりに、timeout パラメータを指定して stream_select() を使用してください。

この関数は、以前は set_socket_timeout() 、その後は socket_set_timeout() と呼ばれたこともありましたが、 これらの利用は推奨されません。

参考

  • fsockopen() - インターネット接続もしくは Unix ドメインソケット接続をオープンする
  • fopen() - ファイルまたは URL をオープンする
add a note

User Contributed Notes 11 notes

up
24
hamishcool3 at yahoo dot co dot uk
13 years ago
In case anyone is puzzled, stream_set_timeout DOES NOT work for sockets created with socket_create or socket_accept. Use socket_set_option instead.

Instead of:
<?php
stream_set_timeout
($socket,$sec,$usec);
?>

Use:
<?php
socket_set_option
($socket, SOL_SOCKET, SO_RCVTIMEO, array('sec'=>$sec, 'usec'=>$usec));
socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, array('sec'=>$sec, 'usec'=>$usec));
?>
up
7
burninleo at gmx dot net
8 years ago
If the timeout fails, because the server remains completely silent, one may have to add stream_select() to make the timeout work. This may be much more efficient that a non-blocking reading operation.

<?php
stream_set_timeout
($c, $timeout);
$data = '';
$stR = array($this->smtp_conn);
$stW = null;
while (
is_resource($c) && !feof($c)) {
if (!
stream_select($stR, $stW, $stW, $timeout)) {
trigger_error('Timeout');
break;
}
$str = fgets($c, 515);
$data.= $str;

// Handling of "traditional" timeout
$info = stream_get_meta_data($c);
if (
$info['timed_out']) {
trigger_error('Timeout');
break;
}
}
?>

Background: We had issues with a SMTP server that was addresses unencrypted while expecting TLS encryption. The stream_set_timeout() alone did not work as expected and the script hung for an hour or more.
up
6
Martin Butt - martin at anti_spambutt.cx
16 years ago
Here is a working example for loops:

<?php
// Timeout in seconds
$timeout = 5;

$fp = fsockopen("www.server.com", 80, $errno, $errstr, $timeout);

if (
$fp) {
fwrite($fp, "GET /file.php HTTP/1.0\r\n");
fwrite($fp, "Host: www.server.com\r\n");
fwrite($fp, "Connection: Close\r\n\r\n");

stream_set_blocking($fp, TRUE);
stream_set_timeout($fp,$timeout);
$info = stream_get_meta_data($fp);

while ((!
feof($fp)) && (!$info['timed_out'])) {
$data .= fgets($fp, 4096);
$info = stream_get_meta_data($fp);
ob_flush;
flush();
}

if (
$info['timed_out']) {
echo
"Connection Timed Out!";
} else {
echo
$data;
}
}
?>
up
1
burninleo at gmx dot net
8 years ago
Another note alread states that blocking-reads may be an issue, if the counterpart responds very slowly - or not at all. The stream timeout may not work as expected in such a situation.

However, php.net provides very little information on how to use non-blocking reading operations. Here's a code sample:

<?php
stream_set_timeout
($c, $timeout);
$data = '';
while (
is_resource($c) && !feof($c)) {
// Use non-blocking reading for first loop
if (($data === '') and ($timeout > 0)) {
stream_set_blocking($c, false);
$endtimeOut = time() + $timeout;
$str = '';
while ((
time() < $endtimeOut) and (strlen($str) < 515) and !feof($c)) {
sleep(1); // Note: This may require tuning
$str.= fgets($c, 515);
}
// Handling first-read timeout
if (time() >= $endtimeOut) {
trigger_error('Timeout', E_USER_WARNING);
break;
}
stream_set_blocking($c, true);
} else {
$str = fgets($c, 515);
}
$data.= $str;

// Handling of "traditional" timeout
$info = stream_get_meta_data($c);
if (
$info['timed_out']) {
trigger_error('Timeout', E_USER_WARNING);
break;
}
}
?>
up
1
emailfire at gmail dot com
12 years ago
This function seems to have no effect when running as a CLI script, see http://bugs.php.net/bug.php?id=36030
up
1
ridera
19 years ago
I have found it required to add

"stream_set_blocking($fp, FALSE )"

prior to any fgets(), fread(), etc. to prevent the code from hanging up when remote files are called and the response is slow.
up
2
mildly dull at terriblyclever dot com
14 years ago
I didn't have much luck with the suggestions below (although I likely applied them wrong).
Instead, I used stream_context_create() and set an http option for timeout. I fed that context into file_get_contents() and voila!

To my desperate friend below: the https transport can also use the http stream context options. I haven't verified this works as I don't have a slow responding ssl to test on. But if you are still stressing, give the below a shot (you may need to modify a bit...)

<?php
$timeout
= 5*60;
$options = array(
'http'=>array(
'method'=>"GET",
'header'=>"Accept-language: en\r\n",
'timeout' => $timeout
)
);
$context = stream_context_create($options);
$contents = file_get_contents($source, false, $context);
?>

Yes...that is a 5 minute timeout.
up
1
alfi_ at yahoo dot com
17 years ago
If you are using fsockopen() to create a connection, first going to write into the stream and then waiting for the reply (e.g. simulating HTTP request with some extra headers), then stream_set_timeout() must be set only after the write - if it is before write, it has no effect on the read timeout :-(
Noticed at least on PHP/4.3.10
up
1
rtfm61 at yandex dot ru
18 years ago
stream_set_timeout() is not suitable for such files as UNIX-devices (/dev/...), i suggest to use select() instead with desirable timeout value - that works well.
up
-1
Dianoga (dianoga7 [at] 3dgo.net)
17 years ago
I have found that in order to actually stop the socket from timing out the script, you must call stream_get_meta_data and check for a timeout within the loop reading from the socket.

Example:

<?php
$sock
= fsockopen($host, 80, $errno, $errstr, 30);
if(!
$sock){
echo
"Unable to get server status";
}else{
$out = "GET /server.php HTTP/1.1\r\n";
$out .= "Host: $host\r\n";
$out .= "Connection: Close\r\n\r\n";

fwrite($sock, $out);

stream_set_blocking($fp, FALSE );
stream_set_timeout($sock, $timeout);
$info = stream_get_meta_data($sock);

while (!
feof($sock) && !$info['timed_out']) {
$file .= fgets($sock, 4096);
$info = stream_get_meta_data($sock);
}

fclose($sock);
?>
up
-10
jack.whoami
9 years ago
Just in case someone stumbles into my situation... I was trying to get the microseconds part to work and it just wasn't working as expected.

Assuming blocking mode is true and I use

<?php stream_set_timeout($s, 1, 0);?>

I get a 1s delay as expected. However when I do

<?php stream_set_timeout($s, 0, 500);?>

I expect a 500microsecond delay but I get no delays at all. However when i do this

<?php stream_set_timeout($s, 0, 500000);?>

I get a 500 microsecond delay which is what I was expecting
To Top