|  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #33781 add "stream_set_timeout" support for pipes
Submitted: 2005-07-20 09:40 UTC Modified: 2011-04-08 21:48 UTC
From: vesely at tana dot it Assigned:
Status: Open Package: Streams related
PHP Version: * OS: *
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
Block user comment
Status: Assign to:
Bug Type:
From: vesely at tana dot it
New email:
PHP Version: OS:


 [2005-07-20 09:40 UTC] vesely at tana dot it
When using the Apache module it is not possible
to use pcntl_alarm (why?). OTOH stream_set_timeout
does not work on the "pipe" in descriptorspec.

Of course, if the program really doesn't know _if_
there is any data to read, it should use stream_select
and fgetc in a loop. Frequently enough, the program
knows what it is doing and wants to sleep on fgets
until data is available on the pipe. If anything goes
wrong here, the two processes may hang waiting for
each other. Meanwhile, the user angrily reloads the
page knocking out yet another Apache's child...

"NEEDED: a timeout for stdout pipe, otherwise a fgets on
$pipes[1] can lag forever...)" has been for years in

The global script timeout is quite hard to manage from
an included function. stream_select and fgets is good
but is not bullet-proof. A request for a timer already
exists (bug #9676), hence I guess I should ask for some
"guarded-pipe" where the select-fgetc loop is coded in C
using a time limit that can be set via stream_set_timeout.
Is that cool?


Add a Patch

Pull Requests

Add a Pull Request


AllCommentsChangesGit/SVN commitsRelated reports
 [2005-07-20 14:54 UTC]
The simple solution is to NOT use fgets() when you're on a deadline, because of the greedy read semantic.

Use fread() instead, in conjunction with stream_select() (which is what is used internally to implement the timeout).

Here's an example from our test suite:

function system_with_timeout($commandline)
	$data = "";
	$proc = proc_open($commandline, array(
		0 => array('pipe', 'r'),
		1 => array('pipe', 'w'),
		2 => array('pipe', 'w')
		), $pipes, null, null, array("suppress_errors" => true));

	if (!$proc)
		return false;


	while (true) {
		/* hide errors from interrupted syscalls */
		$r = $pipes;
		$w = null;
		$e = null;
		$n = @stream_select($r, $w, $e, 60);

		if ($n === 0) {
			/* timed out */
			$data .= "\n ** ERROR: process timed out **\n";
			return $data;
		} else if ($n > 0) {
			$line = fread($pipes[1], 8192);
			if (strlen($line) == 0) {
				/* EOF */
			$data .= $line;
	$stat = proc_get_status($proc);
	if ($stat['signaled']) {
		$data .= "\nTermsig=".$stat['stopsig'];
	$code = proc_close($proc);
	return $data;
 [2005-07-21 08:55 UTC] vesely at tana dot it
I have a couple of notes on that example. The function
attempts to fread 8Kbytes, whilst a positive response from
stream_select only guarantees that 1 byte can be read w/o
blocking. Further, 60 secs is really eons.

I'm using this:

   function guarded_fgets($pipes)
      $line = "";
      $time = 2;
      $c = "c";
      while ($time >= 0 && ord($c) != 10)
         $read = array($pipes[1]);
         while (!feof($read[0]) &&
            ($n = stream_select($read, $w = NULL, $e = NULL, $time)) !== FALSE &&
            $n > 0 &&
            strlen($c = fgetc($read[0])) > 0 &&
            ord($c) != 10)
               $line .= $c;

      if (ord($c) != 10)
         // error handling

      return $line;
 [2011-04-08 21:48 UTC]
-Package: Feature/Change Request +Package: Streams related -Operating System: Unix +Operating System: * -PHP Version: 4.4.0 +PHP Version: *
PHP Copyright © 2001-2021 The PHP Group
All rights reserved.
Last updated: Sun Oct 24 07:03:34 2021 UTC