mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Add tests for uncastable streams and dataloss streams (#10173)
And suppress the nonsensical warnings by passing the PHP_STREAM_CAST_INTERNAL flag.
This commit is contained in:
parent
4863d93c96
commit
39ef5ca31c
14 changed files with 346 additions and 25 deletions
|
@ -426,10 +426,15 @@ static int php_posix_stream_get_fd(zval *zfp, zend_long *fd) /* {{{ */
|
|||
if (stream == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if (php_stream_can_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT) == SUCCESS) {
|
||||
php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT, (void*)fd, 0);
|
||||
} else if (php_stream_can_cast(stream, PHP_STREAM_AS_FD) == SUCCESS) {
|
||||
php_stream_cast(stream, PHP_STREAM_AS_FD, (void*)fd, 0);
|
||||
|
||||
/* get the fd.
|
||||
* NB: Most other code will NOT use the PHP_STREAM_CAST_INTERNAL flag when casting.
|
||||
* It is only used here so that the buffered data warning is not displayed.
|
||||
*/
|
||||
if (php_stream_can_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL) == SUCCESS) {
|
||||
php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL, (void*)&fd, 0);
|
||||
} else if (php_stream_can_cast(stream, PHP_STREAM_AS_FD | PHP_STREAM_CAST_INTERNAL) == SUCCESS) {
|
||||
php_stream_cast(stream, PHP_STREAM_AS_FD | PHP_STREAM_CAST_INTERNAL, (void*)&fd, 0);
|
||||
} else {
|
||||
php_error_docref(NULL, E_WARNING, "Could not use stream of type '%s'",
|
||||
stream->ops->label);
|
||||
|
|
|
@ -15,7 +15,7 @@ try {
|
|||
} catch (\TypeError $e) {
|
||||
echo $e->getMessage() . "\n";
|
||||
}
|
||||
$fd = fopen(sys_get_temp_dir(), "r");
|
||||
$fd = fopen(__DIR__, "r");
|
||||
var_dump(posix_fpathconf($fd, POSIX_PC_PATH_MAX));
|
||||
fclose($fd);
|
||||
?>
|
||||
|
|
|
@ -2,15 +2,11 @@
|
|||
posix_isatty(): Basic tests
|
||||
--EXTENSIONS--
|
||||
posix
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!function_exists('posix_isatty')) die('skip posix_isatty() not found');
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
var_dump(posix_isatty(0));
|
||||
var_dump(posix_isatty(STDIN));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
bool(%s)
|
||||
--EXPECT--
|
||||
bool(false)
|
||||
|
|
33
ext/posix/tests/posix_isatty_no_warning_on_stream_cast.phpt
Normal file
33
ext/posix/tests/posix_isatty_no_warning_on_stream_cast.phpt
Normal file
|
@ -0,0 +1,33 @@
|
|||
--TEST--
|
||||
posix_isatty(): casting stream does not emit data loss and should not emit warnings
|
||||
--EXTENSIONS--
|
||||
posix
|
||||
--SKIPIF--
|
||||
<?php
|
||||
require __DIR__ . '/../../standard/tests/http/server.inc'; http_server_skipif();
|
||||
?>
|
||||
--INI--
|
||||
allow_url_fopen=1
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
require __DIR__ . '/../../standard/tests/http/server.inc';
|
||||
|
||||
$responses = array(
|
||||
"data://text/plain,HTTP/1.0 200 Ok\r\nSome: Header\r\nSome: Header\r\n\r\nBody",
|
||||
);
|
||||
|
||||
['pid' => $pid, 'uri' => $uri] = http_server($responses, $output);
|
||||
|
||||
/* Note: the warning is bogus in this case as no data actually gets lost,
|
||||
* but this checks that stream casting works */
|
||||
$handle = fopen($uri, 'r');
|
||||
var_dump(posix_isatty($handle));
|
||||
var_dump(fread($handle, 20));
|
||||
fclose($handle);
|
||||
|
||||
http_server_kill($pid);
|
||||
?>
|
||||
--EXPECT--
|
||||
bool(false)
|
||||
string(4) "Body"
|
20
ext/posix/tests/posix_isatty_non_castable_user_stream.phpt
Normal file
20
ext/posix/tests/posix_isatty_non_castable_user_stream.phpt
Normal file
|
@ -0,0 +1,20 @@
|
|||
--TEST--
|
||||
posix_isatty(): uncastable user stream
|
||||
--EXTENSIONS--
|
||||
posix
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
require dirname(__DIR__, 3) . '/tests/output/DummyStreamWrapper.inc';
|
||||
stream_wrapper_register('custom', DummyStreamWrapper::class);
|
||||
|
||||
$fp = fopen("custom://myvar", "r+");
|
||||
var_dump(posix_isatty($fp));
|
||||
fclose($fp);
|
||||
|
||||
echo "Done";
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: posix_isatty(): Could not use stream of type 'user-space' in %s on line %d
|
||||
bool(false)
|
||||
Done
|
33
ext/posix/tests/posix_ttyname_no_warning_on_cast.phpt
Normal file
33
ext/posix/tests/posix_ttyname_no_warning_on_cast.phpt
Normal file
|
@ -0,0 +1,33 @@
|
|||
--TEST--
|
||||
posix_ttyname(): casting stream does not emit data loss and should not emit warnings
|
||||
--EXTENSIONS--
|
||||
posix
|
||||
--SKIPIF--
|
||||
<?php
|
||||
require __DIR__ . '/../../standard/tests/http/server.inc'; http_server_skipif();
|
||||
?>
|
||||
--INI--
|
||||
allow_url_fopen=1
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
require __DIR__ . '/../../standard/tests/http/server.inc';
|
||||
|
||||
$responses = array(
|
||||
"data://text/plain,HTTP/1.0 200 Ok\r\nSome: Header\r\nSome: Header\r\n\r\nBody",
|
||||
);
|
||||
|
||||
['pid' => $pid, 'uri' => $uri] = http_server($responses, $output);
|
||||
|
||||
/* Note: the warning is bogus in this case as no data actually gets lost,
|
||||
* but this checks that stream casting works */
|
||||
$handle = fopen($uri, 'r');
|
||||
var_dump(posix_ttyname($handle));
|
||||
var_dump(fread($handle, 20));
|
||||
fclose($handle);
|
||||
|
||||
http_server_kill($pid);
|
||||
?>
|
||||
--EXPECT--
|
||||
bool(false)
|
||||
string(4) "Body"
|
20
ext/posix/tests/posix_ttyname_non_castable_user_stream.phpt
Normal file
20
ext/posix/tests/posix_ttyname_non_castable_user_stream.phpt
Normal file
|
@ -0,0 +1,20 @@
|
|||
--TEST--
|
||||
posix_ttyname(): uncastable user stream
|
||||
--EXTENSIONS--
|
||||
posix
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
require dirname(__DIR__, 3) . '/tests/output/DummyStreamWrapper.inc';
|
||||
stream_wrapper_register('custom', DummyStreamWrapper::class);
|
||||
|
||||
$fp = fopen("custom://myvar", "r+");
|
||||
var_dump(posix_ttyname($fp));
|
||||
fclose($fp);
|
||||
|
||||
echo "Done";
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: posix_ttyname(): Could not use stream of type 'user-space' in %s on line %d
|
||||
bool(false)
|
||||
Done
|
|
@ -1645,10 +1645,14 @@ PHP_FUNCTION(stream_isatty)
|
|||
|
||||
php_stream_from_zval(stream, zsrc);
|
||||
|
||||
if (php_stream_can_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT) == SUCCESS) {
|
||||
php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT, (void*)&fileno, 0);
|
||||
} else if (php_stream_can_cast(stream, PHP_STREAM_AS_FD) == SUCCESS) {
|
||||
php_stream_cast(stream, PHP_STREAM_AS_FD, (void*)&fileno, 0);
|
||||
/* get the fd.
|
||||
* NB: Most other code will NOT use the PHP_STREAM_CAST_INTERNAL flag when casting.
|
||||
* It is only used here so that the buffered data warning is not displayed.
|
||||
*/
|
||||
if (php_stream_can_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL) == SUCCESS) {
|
||||
php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL, (void*)&fileno, 0);
|
||||
} else if (php_stream_can_cast(stream, PHP_STREAM_AS_FD | PHP_STREAM_CAST_INTERNAL) == SUCCESS) {
|
||||
php_stream_cast(stream, PHP_STREAM_AS_FD | PHP_STREAM_CAST_INTERNAL, (void*)&fileno, 0);
|
||||
} else {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
@ -1686,13 +1690,15 @@ PHP_FUNCTION(sapi_windows_vt100_support)
|
|||
|
||||
php_stream_from_zval(stream, zsrc);
|
||||
|
||||
if (php_stream_can_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT) == SUCCESS) {
|
||||
php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT, (void*)&fileno, 0);
|
||||
}
|
||||
else if (php_stream_can_cast(stream, PHP_STREAM_AS_FD) == SUCCESS) {
|
||||
php_stream_cast(stream, PHP_STREAM_AS_FD, (void*)&fileno, 0);
|
||||
}
|
||||
else {
|
||||
/* get the fd.
|
||||
* NB: Most other code will NOT use the PHP_STREAM_CAST_INTERNAL flag when casting.
|
||||
* It is only used here so that the buffered data warning is not displayed.
|
||||
*/
|
||||
if (php_stream_can_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL) == SUCCESS) {
|
||||
php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL, (void*)&fileno, 0);
|
||||
} else if (php_stream_can_cast(stream, PHP_STREAM_AS_FD | PHP_STREAM_CAST_INTERNAL) == SUCCESS) {
|
||||
php_stream_cast(stream, PHP_STREAM_AS_FD | PHP_STREAM_CAST_INTERNAL, (void*)&fileno, 0);
|
||||
} else {
|
||||
if (!enable_is_null) {
|
||||
php_error_docref(
|
||||
NULL,
|
||||
|
|
37
ext/standard/tests/streams/stream_cast_loses_data.phpt
Normal file
37
ext/standard/tests/streams/stream_cast_loses_data.phpt
Normal file
|
@ -0,0 +1,37 @@
|
|||
--TEST--
|
||||
Casting a stream can lose data and needs to emit a warning
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (PHP_OS_FAMILY === "Windows") die("skip non-Windows tests (popen cannot delete file as open in cmd.exe)");
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$tempnam = tempnam(sys_get_temp_dir(), 'test');
|
||||
|
||||
$stream = popen('echo 1; echo 2; rm ' . escapeshellarg($tempnam), 'r');
|
||||
|
||||
do {
|
||||
usleep(10);
|
||||
clearstatcache();
|
||||
} while (file_exists($tempnam));
|
||||
|
||||
// fills the read buffer with up to 8192 bytes
|
||||
fgets($stream);
|
||||
|
||||
// cast $stream and read fd until eof. Print each line that was read, prefixed with "proc open stdin:"
|
||||
$process = proc_open(
|
||||
'sed "s/^/proc open stdin:/"',
|
||||
[
|
||||
0 => $stream,
|
||||
1 => ['pipe', 'w'],
|
||||
],
|
||||
$pipes,
|
||||
);
|
||||
|
||||
var_dump(stream_get_contents($pipes[1]));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: proc_open(): 2 bytes of buffered data lost during stream conversion! in %s on line %d
|
||||
string(0) ""
|
61
tests/output/DummyStreamWrapper.inc
Normal file
61
tests/output/DummyStreamWrapper.inc
Normal file
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
class DummyStreamWrapper
|
||||
{
|
||||
/** @var resource|null */
|
||||
public $context;
|
||||
|
||||
/** @var resource|null */
|
||||
public $handle;
|
||||
|
||||
public function stream_cast(int $castAs)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function stream_close(): void { }
|
||||
|
||||
public function stream_open(string $path, string $mode, int $options = 0, ?string &$openedPath = null): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function stream_read(int $count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function stream_seek(int $offset, int $whence = SEEK_SET): bool
|
||||
{
|
||||
var_dump('stream_seek!');
|
||||
return true;
|
||||
}
|
||||
|
||||
public function stream_set_option(int $option, int $arg1, ?int $arg2): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function stream_stat()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function stream_tell()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function stream_truncate(int $newSize): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function stream_write(string $data) { }
|
||||
|
||||
|
||||
public function unlink(string $path): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
--TEST--
|
||||
sapi_windows_vt100_support(): casting stream does not emit data loss and should not emit warnings
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (PHP_OS_FAMILY !== "Windows") {
|
||||
die("skip Only for Windows systems");
|
||||
}
|
||||
require __DIR__ . '/../../ext/standard/tests/http/server.inc'; http_server_skipif();
|
||||
?>
|
||||
--INI--
|
||||
allow_url_fopen=1
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
require __DIR__ . '/../../ext/standard/tests/http/server.inc';
|
||||
|
||||
$responses = array(
|
||||
"data://text/plain,HTTP/1.0 200 Ok\r\nSome: Header\r\nSome: Header\r\n\r\nBody",
|
||||
);
|
||||
|
||||
['pid' => $pid, 'uri' => $uri] = http_server($responses, $output);
|
||||
|
||||
/* Note: the warning is bogus in this case as no data actually gets lost,
|
||||
* but this checks that stream casting works */
|
||||
$handle = fopen($uri, 'r');
|
||||
var_dump(sapi_windows_vt100_support($handle));
|
||||
var_dump(fread($handle, 20));
|
||||
fclose($handle);
|
||||
|
||||
http_server_kill($pid);
|
||||
?>
|
||||
--EXPECT--
|
||||
bool(false)
|
||||
string(4) "Body"
|
|
@ -0,0 +1,27 @@
|
|||
--TEST--
|
||||
sapi_windows_vt100_support(): uncastable user stream
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (PHP_OS_FAMILY !== "Windows") {
|
||||
die("skip Only for Windows systems");
|
||||
}
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
require __DIR__ . '/DummyStreamWrapper.inc';
|
||||
stream_wrapper_register('custom', DummyStreamWrapper::class);
|
||||
|
||||
$fp = fopen("custom://myvar", "r+");
|
||||
try {
|
||||
var_dump(sapi_windows_vt100_support($fp));
|
||||
} catch (\TypeError $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
fclose($fp);
|
||||
|
||||
echo "Done";
|
||||
?>
|
||||
--EXPECT--
|
||||
bool(false)
|
||||
Done
|
32
tests/output/stream_isatty_no_warning_on_cast.phpt
Normal file
32
tests/output/stream_isatty_no_warning_on_cast.phpt
Normal file
|
@ -0,0 +1,32 @@
|
|||
--TEST--
|
||||
stream_isatty(): casting stream does not emit data loss and should not emit warnings
|
||||
Bug GH-10092 (Internal stream casting should not emit lost bytes warning twice)
|
||||
--SKIPIF--
|
||||
<?php
|
||||
require __DIR__ . '/../../ext/standard/tests/http/server.inc'; http_server_skipif();
|
||||
?>
|
||||
--INI--
|
||||
allow_url_fopen=1
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
require __DIR__ . '/../../ext/standard/tests/http/server.inc';
|
||||
|
||||
$responses = array(
|
||||
"data://text/plain,HTTP/1.0 200 Ok\r\nSome: Header\r\nSome: Header\r\n\r\nBody",
|
||||
);
|
||||
|
||||
['pid' => $pid, 'uri' => $uri] = http_server($responses, $output);
|
||||
|
||||
/* Note: the warning is bogus in this case as no data actually gets lost,
|
||||
* but this checks that stream casting works */
|
||||
$handle = fopen($uri, 'r');
|
||||
var_dump(stream_isatty($handle));
|
||||
var_dump(fread($handle, 20));
|
||||
fclose($handle);
|
||||
|
||||
http_server_kill($pid);
|
||||
?>
|
||||
--EXPECT--
|
||||
bool(false)
|
||||
string(4) "Body"
|
17
tests/output/stream_isatty_non_castable_user_stream.phpt
Normal file
17
tests/output/stream_isatty_non_castable_user_stream.phpt
Normal file
|
@ -0,0 +1,17 @@
|
|||
--TEST--
|
||||
stream_isatty(): uncastable user stream
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
require __DIR__ . '/DummyStreamWrapper.inc';
|
||||
stream_wrapper_register('custom', DummyStreamWrapper::class);
|
||||
|
||||
$fp = fopen("custom://myvar", "r+");
|
||||
var_dump(stream_isatty($fp));
|
||||
fclose($fp);
|
||||
|
||||
echo "Done";
|
||||
?>
|
||||
--EXPECT--
|
||||
bool(false)
|
||||
Done
|
Loading…
Add table
Add a link
Reference in a new issue