diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index 19ece98e05216..1fde37375a549 100644 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -3569,6 +3569,9 @@ function stream_isatty($stream): bool {} #ifdef PHP_WIN32 /** @param resource $stream */ function sapi_windows_vt100_support($stream, ?bool $enable = null): bool {} + +/** @param resource $stream */ +function sapi_windows_console_size($stream): array|bool {} #endif /** @param resource $stream */ diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index b84e9f8dd7087..721062a5becd5 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: e277d3a5699db6aeedb08642720be841dc37d683 */ + * Stub hash: af7ac72dbd92ef13bf975e9f66319e11554d9b95 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0) @@ -1987,6 +1987,10 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_sapi_windows_vt100_support, 0, 1 ZEND_ARG_INFO(0, stream) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, enable, _IS_BOOL, 1, "null") ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_sapi_windows_console_size, 0, 1, MAY_BE_ARRAY|MAY_BE_BOOL) + ZEND_ARG_INFO(0, stream) +ZEND_END_ARG_INFO() #endif #define arginfo_stream_set_chunk_size arginfo_stream_set_write_buffer @@ -2816,6 +2820,7 @@ ZEND_FUNCTION(stream_is_local); ZEND_FUNCTION(stream_isatty); #if defined(PHP_WIN32) ZEND_FUNCTION(sapi_windows_vt100_support); +ZEND_FUNCTION(sapi_windows_console_size); #endif ZEND_FUNCTION(stream_set_chunk_size); #if (defined(HAVE_SYS_TIME_H) || defined(PHP_WIN32)) @@ -3423,6 +3428,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(stream_isatty, arginfo_stream_isatty) #if defined(PHP_WIN32) ZEND_FE(sapi_windows_vt100_support, arginfo_sapi_windows_vt100_support) + ZEND_FE(sapi_windows_console_size, arginfo_sapi_windows_console_size) #endif ZEND_FE(stream_set_chunk_size, arginfo_stream_set_chunk_size) #if (defined(HAVE_SYS_TIME_H) || defined(PHP_WIN32)) diff --git a/ext/standard/streamsfuncs.c b/ext/standard/streamsfuncs.c index 1929075b60b71..6192c3c943551 100644 --- a/ext/standard/streamsfuncs.c +++ b/ext/standard/streamsfuncs.c @@ -1774,6 +1774,46 @@ PHP_FUNCTION(sapi_windows_vt100_support) } } } + +PHP_FUNCTION(sapi_windows_console_size) +{ + zval *zsrc; + php_stream *stream; + zend_long fileno; + int width, height; + zval zwidth, zheight; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_RESOURCE(zsrc) + ZEND_PARSE_PARAMETERS_END(); + + php_stream_from_zval(stream, zsrc); + + /* 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 { + php_error_docref(NULL, E_WARNING, "not able to analyze the specified stream"); + RETURN_FALSE; + } + + if (!php_win32_console_fileno_is_console(fileno)) { + RETURN_FALSE; + } + + if (!php_win32_console_size(fileno, &width, &height)) { + RETURN_FALSE; + } + + ZVAL_LONG(&zwidth, width); + ZVAL_LONG(&zheight, height); + RETURN_ARR(zend_new_pair(&zwidth, &zheight)); +} #endif #ifdef HAVE_SHUTDOWN diff --git a/win32/console.c b/win32/console.c index 9b485610888cc..ae74f8d82c9e9 100644 --- a/win32/console.c +++ b/win32/console.c @@ -114,3 +114,14 @@ PHP_WINUTIL_API BOOL php_win32_console_is_cli_sapi(void) return strlen(sapi_module.name) >= sizeof("cli") - 1 && !strncmp(sapi_module.name, "cli", sizeof("cli") - 1); }/*}}}*/ +PHP_WINUTIL_API BOOL php_win32_console_size(zend_long fileno, int *width, int *height) +{ + HANDLE handle = (HANDLE) _get_osfhandle(fileno); + CONSOLE_SCREEN_BUFFER_INFO csbi; + if (!GetConsoleScreenBufferInfo(handle, &csbi)) { + return 0; + } + *width = csbi.srWindow.Right - csbi.srWindow.Left + 1; + *height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; + return 1; +} diff --git a/win32/console.h b/win32/console.h index b3fae6166b73a..3651e48cc5a34 100644 --- a/win32/console.h +++ b/win32/console.h @@ -60,4 +60,7 @@ PHP_WINUTIL_API BOOL php_win32_console_is_own(void); /* Check whether the current SAPI is run on console. */ PHP_WINUTIL_API BOOL php_win32_console_is_cli_sapi(void); +/* Gets the width and height of a console. */ +PHP_WINUTIL_API BOOL php_win32_console_size(zend_long fileno, int *width, int *height); + #endif