Skip to content

Commit a011aa3

Browse files
committed
Allow filtered streams to be casted as fd for select
This removes the artificial limitation that is not necessary. The fact that some streams can have some data buffered is not a problem because the similar situation is already present for OpenSSL streams where OpenSSL can internally buffer data for the unprocessed part of the record.
1 parent d9d55f0 commit a011aa3

File tree

3 files changed

+92
-1
lines changed

3 files changed

+92
-1
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
--TEST--
2+
stream_select() base64-decode filter basic usage
3+
--FILE--
4+
<?php
5+
$file = fopen('php://temp', 'r+');
6+
7+
// Write complete base64 "Hello World"
8+
fwrite($file, 'SGVsbG8gV29ybGQ=');
9+
10+
stream_filter_append($file, 'convert.base64-decode');
11+
rewind($file);
12+
13+
$read = [$file];
14+
$write = null;
15+
$except = null;
16+
17+
$result = stream_select($read, $write, $except, 0);
18+
19+
if ($result !== false) {
20+
echo "stream_select succeeded\n";
21+
if (count($read) > 0) {
22+
echo fread($file, 1024) . "\n";
23+
}
24+
} else {
25+
echo "stream_select failed\n";
26+
}
27+
28+
fclose($file);
29+
?>
30+
--EXPECT--
31+
stream_select succeeded
32+
Hello World
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
--TEST--
2+
stream_select() base64-decode filter buffered data usage
3+
--FILE--
4+
<?php
5+
$domain = (strtoupper(substr(PHP_OS, 0, 3) == 'WIN') ? STREAM_PF_INET : STREAM_PF_UNIX);
6+
$pipes = stream_socket_pair($domain, STREAM_SOCK_STREAM, 0);
7+
if ($pipes === false) {
8+
die("Failed to create socket pair");
9+
}
10+
11+
list($read_pipe, $write_pipe) = $pipes;
12+
13+
stream_set_blocking($read_pipe, false);
14+
stream_filter_append($read_pipe, 'convert.base64-decode');
15+
16+
// Write incomplete base64 data: "SGVs" decodes to "Hel" but "SGVs" is incomplete
17+
fwrite($write_pipe, 'SGVs');
18+
fflush($write_pipe);
19+
20+
$read = [$read_pipe];
21+
$write = null;
22+
$except = null;
23+
24+
$result = fread($read_pipe, 1024);
25+
echo "Decoded content (before select): " . $result . "\n";
26+
27+
// Should succeed but stream should NOT be readable yet (data buffered in filter)
28+
$result = stream_select($read, $write, $except, 0, 1000);
29+
echo "After incomplete data - select result: " . $result . "\n";
30+
echo "After incomplete data - readable streams: " . count($read) . "\n";
31+
32+
// Now complete the base64 sequence: "SGVsbG8=" decodes to "Hello"
33+
fwrite($write_pipe, 'bG8=');
34+
fflush($write_pipe);
35+
36+
$read = [$read_pipe];
37+
$write = null;
38+
$except = null;
39+
40+
// Now stream should be readable
41+
$result = stream_select($read, $write, $except, 0, 1000);
42+
echo "After complete data - select result: " . $result . "\n";
43+
echo "After complete data - readable streams: " . count($read) . "\n";
44+
45+
if (count($read) > 0) {
46+
$content = fread($read_pipe, 1024);
47+
echo "Decoded content: " . $content . "\n";
48+
}
49+
50+
fclose($read_pipe);
51+
fclose($write_pipe);
52+
?>
53+
--EXPECT--
54+
Decoded content (before select): Hel
55+
After incomplete data - select result: 0
56+
After incomplete data - readable streams: 0
57+
After complete data - select result: 1
58+
After complete data - readable streams: 1
59+
Decoded content: lo

main/streams/cast.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ PHPAPI zend_result _php_stream_cast(php_stream *stream, int castas, void **ret,
297297
}
298298
}
299299

300-
if (php_stream_is_filtered(stream)) {
300+
if (php_stream_is_filtered(stream) && castas != PHP_STREAM_AS_FD_FOR_SELECT) {
301301
if (show_err) {
302302
php_error_docref(NULL, E_WARNING, "Cannot cast a filtered stream on this system");
303303
}

0 commit comments

Comments
 (0)