diff --git a/ext/posix/posix.c b/ext/posix/posix.c index bfb542bad7539..4ba3588a63a1b 100644 --- a/ext/posix/posix.c +++ b/ext/posix/posix.c @@ -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); diff --git a/ext/posix/tests/posix_fpathconf.phpt b/ext/posix/tests/posix_fpathconf.phpt index cc388d5c0971f..c114094160116 100644 --- a/ext/posix/tests/posix_fpathconf.phpt +++ b/ext/posix/tests/posix_fpathconf.phpt @@ -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); ?> diff --git a/ext/posix/tests/posix_isatty.phpt b/ext/posix/tests/posix_isatty.phpt index 5132c04d35ee9..b913a53c3e91a 100644 --- a/ext/posix/tests/posix_isatty.phpt +++ b/ext/posix/tests/posix_isatty.phpt @@ -2,15 +2,11 @@ posix_isatty(): Basic tests --EXTENSIONS-- posix ---SKIPIF-- - --FILE-- ---EXPECTF-- -bool(%s) +--EXPECT-- +bool(false) diff --git a/ext/posix/tests/posix_isatty_no_warning_on_stream_cast.phpt b/ext/posix/tests/posix_isatty_no_warning_on_stream_cast.phpt new file mode 100644 index 0000000000000..d49ac4bdf274c --- /dev/null +++ b/ext/posix/tests/posix_isatty_no_warning_on_stream_cast.phpt @@ -0,0 +1,33 @@ +--TEST-- +posix_isatty(): casting stream does not emit data loss and should not emit warnings +--EXTENSIONS-- +posix +--SKIPIF-- + +--INI-- +allow_url_fopen=1 +--FILE-- + $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" diff --git a/ext/posix/tests/posix_isatty_non_castable_user_stream.phpt b/ext/posix/tests/posix_isatty_non_castable_user_stream.phpt new file mode 100644 index 0000000000000..422e2c6fe4bb7 --- /dev/null +++ b/ext/posix/tests/posix_isatty_non_castable_user_stream.phpt @@ -0,0 +1,20 @@ +--TEST-- +posix_isatty(): uncastable user stream +--EXTENSIONS-- +posix +--FILE-- + +--EXPECTF-- +Warning: posix_isatty(): Could not use stream of type 'user-space' in %s on line %d +bool(false) +Done diff --git a/ext/posix/tests/posix_ttyname_no_warning_on_cast.phpt b/ext/posix/tests/posix_ttyname_no_warning_on_cast.phpt new file mode 100644 index 0000000000000..596826c252588 --- /dev/null +++ b/ext/posix/tests/posix_ttyname_no_warning_on_cast.phpt @@ -0,0 +1,33 @@ +--TEST-- +posix_ttyname(): casting stream does not emit data loss and should not emit warnings +--EXTENSIONS-- +posix +--SKIPIF-- + +--INI-- +allow_url_fopen=1 +--FILE-- + $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" diff --git a/ext/posix/tests/posix_ttyname_non_castable_user_stream.phpt b/ext/posix/tests/posix_ttyname_non_castable_user_stream.phpt new file mode 100644 index 0000000000000..df81c0af0303c --- /dev/null +++ b/ext/posix/tests/posix_ttyname_non_castable_user_stream.phpt @@ -0,0 +1,20 @@ +--TEST-- +posix_ttyname(): uncastable user stream +--EXTENSIONS-- +posix +--FILE-- + +--EXPECTF-- +Warning: posix_ttyname(): Could not use stream of type 'user-space' in %s on line %d +bool(false) +Done diff --git a/ext/standard/streamsfuncs.c b/ext/standard/streamsfuncs.c index 53fa8d33dad6b..5cb91959e2acf 100644 --- a/ext/standard/streamsfuncs.c +++ b/ext/standard/streamsfuncs.c @@ -74,14 +74,14 @@ PHP_FUNCTION(stream_socket_pair) close(pair[0]); close(pair[1]); php_error_docref(NULL, E_WARNING, "Failed to open stream from socketpair"); - RETURN_FALSE; + RETURN_FALSE; } s2 = php_stream_sock_open_from_socket(pair[1], 0); if (s2 == NULL) { php_stream_free(s1, PHP_STREAM_FREE_CLOSE); close(pair[1]); php_error_docref(NULL, E_WARNING, "Failed to open stream from socketpair"); - RETURN_FALSE; + RETURN_FALSE; } array_init(return_value); @@ -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, diff --git a/ext/standard/tests/streams/stream_cast_loses_data.phpt b/ext/standard/tests/streams/stream_cast_loses_data.phpt new file mode 100644 index 0000000000000..c2bcf9fd5914f --- /dev/null +++ b/ext/standard/tests/streams/stream_cast_loses_data.phpt @@ -0,0 +1,37 @@ +--TEST-- +Casting a stream can lose data and needs to emit a warning +--SKIPIF-- + +--FILE-- + $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) "" diff --git a/tests/output/DummyStreamWrapper.inc b/tests/output/DummyStreamWrapper.inc new file mode 100644 index 0000000000000..664e07a884b2b --- /dev/null +++ b/tests/output/DummyStreamWrapper.inc @@ -0,0 +1,61 @@ + +--INI-- +allow_url_fopen=1 +--FILE-- + $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" diff --git a/tests/output/sapi_windows_vt100_support_non_castable_user_stream.phpt b/tests/output/sapi_windows_vt100_support_non_castable_user_stream.phpt new file mode 100644 index 0000000000000..b47a5fd51b6e5 --- /dev/null +++ b/tests/output/sapi_windows_vt100_support_non_castable_user_stream.phpt @@ -0,0 +1,27 @@ +--TEST-- +sapi_windows_vt100_support(): uncastable user stream +--SKIPIF-- + +--FILE-- +getMessage(), PHP_EOL; +} +fclose($fp); + +echo "Done"; +?> +--EXPECT-- +bool(false) +Done diff --git a/tests/output/stream_isatty_no_warning_on_cast.phpt b/tests/output/stream_isatty_no_warning_on_cast.phpt new file mode 100644 index 0000000000000..3f0e184134fa8 --- /dev/null +++ b/tests/output/stream_isatty_no_warning_on_cast.phpt @@ -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-- + +--INI-- +allow_url_fopen=1 +--FILE-- + $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" diff --git a/tests/output/stream_isatty_non_castable_user_stream.phpt b/tests/output/stream_isatty_non_castable_user_stream.phpt new file mode 100644 index 0000000000000..4c6c5b6503075 --- /dev/null +++ b/tests/output/stream_isatty_non_castable_user_stream.phpt @@ -0,0 +1,17 @@ +--TEST-- +stream_isatty(): uncastable user stream +--FILE-- + +--EXPECT-- +bool(false) +Done