Skip to content

main/streams: Add Fast ZPP specifier to retrieve stream context #17964

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 9 commits into
base: master
Choose a base branch
from
14 changes: 8 additions & 6 deletions ext/hash/hash.c
Original file line number Diff line number Diff line change
@@ -746,21 +746,23 @@ PHP_FUNCTION(hash_update_stream)
/* {{{ Pump data into the hashing algorithm from a file */
PHP_FUNCTION(hash_update_file)
{
zval *zhash, *zcontext = NULL;
zend_object *hash_obj;
php_hashcontext_object *hash;
php_stream_context *context = NULL;
php_stream *stream;
zend_string *filename;
char buf[1024];
ssize_t n;

if (zend_parse_parameters(ZEND_NUM_ARGS(), "OP|r!", &zhash, php_hashcontext_ce, &filename, &zcontext) == FAILURE) {
RETURN_THROWS();
}
ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_OBJ_OF_CLASS(hash_obj, php_hashcontext_ce)
Z_PARAM_PATH_STR(filename)
Z_PARAM_OPTIONAL
PHP_Z_PARAM_STREAM_CONTEXT_OR_NULL_AS_DEFAULT_CONTEXT(context)
ZEND_PARSE_PARAMETERS_END();

hash = php_hashcontext_from_object(Z_OBJ_P(zhash));
hash = php_hashcontext_from_object(hash_obj);
PHP_HASHCONTEXT_VERIFY(hash);
context = php_stream_context_from_zval(zcontext, 0);

stream = php_stream_open_wrapper_ex(ZSTR_VAL(filename), "rb", REPORT_ERRORS, NULL, context);
if (!stream) {
54 changes: 27 additions & 27 deletions ext/phar/func_interceptors.c
Original file line number Diff line number Diff line change
@@ -24,7 +24,7 @@ PHP_FUNCTION(phar_opendir) /* {{{ */
{
char *filename;
size_t filename_len;
zval *zcontext = NULL;
php_stream_context *context = NULL;

if (!PHAR_G(intercepted)) {
goto skip_phar;
@@ -35,9 +35,11 @@ PHP_FUNCTION(phar_opendir) /* {{{ */
goto skip_phar;
}

if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|r!", &filename, &filename_len, &zcontext) == FAILURE) {
RETURN_THROWS();
}
ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_QUIET, 1, 2)
Z_PARAM_PATH(filename, filename_len)
Z_PARAM_OPTIONAL
PHP_Z_PARAM_STREAM_CONTEXT_OR_NULL_AS_DEFAULT_CONTEXT(context)
ZEND_PARSE_PARAMETERS_END_EX(goto skip_phar;);

if (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://")) {
char *arch, *entry;
@@ -51,7 +53,6 @@ PHP_FUNCTION(phar_opendir) /* {{{ */
}

if (SUCCESS == phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), &arch, &arch_len, &entry, &entry_len, 2, 0)) {
php_stream_context *context = NULL;
php_stream *stream;
char *name;

@@ -69,9 +70,7 @@ PHP_FUNCTION(phar_opendir) /* {{{ */
}
efree(entry);
efree(arch);
if (zcontext) {
context = php_stream_context_from_zval(zcontext, 0);
}

stream = php_stream_opendir(name, REPORT_ERRORS, context);
efree(name);
if (!stream) {
@@ -163,7 +162,7 @@ PHP_FUNCTION(phar_file_get_contents) /* {{{ */
zend_long offset = -1;
zend_long maxlen;
bool maxlen_is_null = 1;
zval *zcontext = NULL;
php_stream_context *context = NULL;

if (!PHAR_G(intercepted)) {
goto skip_phar;
@@ -175,9 +174,14 @@ PHP_FUNCTION(phar_file_get_contents) /* {{{ */
}

/* Parse arguments */
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "P|br!ll!", &filename, &use_include_path, &zcontext, &offset, &maxlen, &maxlen_is_null) == FAILURE) {
goto skip_phar;
}
ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_QUIET, 1, 5)
Z_PARAM_PATH_STR(filename)
Z_PARAM_OPTIONAL
Z_PARAM_BOOL(use_include_path)
PHP_Z_PARAM_STREAM_CONTEXT_OR_NULL_AS_DEFAULT_CONTEXT(context)
Z_PARAM_LONG(offset)
Z_PARAM_LONG_OR_NULL(maxlen, maxlen_is_null)
ZEND_PARSE_PARAMETERS_END_EX(goto skip_phar;);

if (maxlen_is_null) {
maxlen = (ssize_t) PHP_STREAM_COPY_ALL;
@@ -192,13 +196,7 @@ PHP_FUNCTION(phar_file_get_contents) /* {{{ */
goto skip_phar;
}

php_stream_context *context = NULL;
php_stream *stream;

if (zcontext) {
context = php_stream_context_from_zval(zcontext, 0);
}
stream = php_stream_open_wrapper_ex(ZSTR_VAL(name), "rb", 0 | REPORT_ERRORS, NULL, context);
php_stream *stream = php_stream_open_wrapper_ex(ZSTR_VAL(name), "rb", 0 | REPORT_ERRORS, NULL, context);

zend_string_release_ex(name, false);

@@ -236,7 +234,7 @@ PHP_FUNCTION(phar_readfile) /* {{{ */
{
zend_string *filename;
bool use_include_path = 0;
zval *zcontext = NULL;
php_stream_context *context = NULL;

if (!PHAR_G(intercepted)) {
goto skip_phar;
@@ -246,19 +244,21 @@ PHP_FUNCTION(phar_readfile) /* {{{ */
&& !HT_IS_INITIALIZED(&cached_phars)) {
goto skip_phar;
}
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "P|br!", &filename, &use_include_path, &zcontext) == FAILURE) {
goto skip_phar;
}

ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_QUIET, 1, 3)
Z_PARAM_PATH_STR(filename)
Z_PARAM_OPTIONAL
Z_PARAM_BOOL(use_include_path)
PHP_Z_PARAM_STREAM_CONTEXT_OR_NULL_AS_DEFAULT_CONTEXT(context)
ZEND_PARSE_PARAMETERS_END_EX(goto skip_phar;);

if (use_include_path || (!IS_ABSOLUTE_PATH(ZSTR_VAL(filename), ZSTR_LEN(filename)) && !strstr(ZSTR_VAL(filename), "://"))) {
zend_string *name = phar_get_name_for_relative_paths(filename, use_include_path);
if (!name) {
goto skip_phar;
}

php_stream *stream;
php_stream_context *context = php_stream_context_from_zval(zcontext, 0);

stream = php_stream_open_wrapper_ex(ZSTR_VAL(name), "rb", 0 | REPORT_ERRORS, NULL, context);
php_stream *stream = php_stream_open_wrapper_ex(ZSTR_VAL(name), "rb", 0 | REPORT_ERRORS, NULL, context);

zend_string_release_ex(name, false);
if (stream == NULL) {
8 changes: 4 additions & 4 deletions ext/simplexml/tests/gh12929.phpt
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ try {
file_get_contents($scheme . "://x");
} catch (Error $e) {
echo $e->getMessage(), "\n";
echo $e->getPrevious()->getMessage(), "\n";
var_dump($e->getPrevious());
}

$scheme = "foo2";
@@ -19,11 +19,11 @@ try {
file_get_contents($scheme . "://x");
} catch (Error $e) {
echo $e->getMessage(), "\n";
echo $e->getPrevious()->getMessage(), "\n";
var_dump($e->getPrevious());
}
?>
--EXPECT--
It's not possible to assign a complex type to properties, resource given
SimpleXMLElement is not properly initialized
It's not possible to assign a complex type to properties, resource given
NULL
SimpleXMLElement is not properly initialized
NULL
2 changes: 1 addition & 1 deletion ext/soap/soap.c
Original file line number Diff line number Diff line change
@@ -1309,7 +1309,7 @@ PHP_METHOD(SoapServer, handle)
*/

sapi_add_header("Content-Type: text/xml; charset=utf-8", sizeof("Content-Type: text/xml; charset=utf-8")-1, 1);
php_stream_context *context = php_stream_context_from_zval(NULL, false);
php_stream_context *context = php_stream_context_get_default(false);
php_stream *stream = php_stream_open_wrapper_ex(service->sdl->source, "rb", REPORT_ERRORS, NULL, context);
if (stream) {
php_stream_passthru(stream);
12 changes: 2 additions & 10 deletions ext/standard/dir.c
Original file line number Diff line number Diff line change
@@ -142,18 +142,15 @@ static void _php_do_opendir(INTERNAL_FUNCTION_PARAMETERS, int createobject)
{
char *dirname;
size_t dir_len;
zval *zcontext = NULL;
php_stream_context *context = NULL;
php_stream *dirp;

ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_PATH(dirname, dir_len)
Z_PARAM_OPTIONAL
Z_PARAM_RESOURCE_OR_NULL(zcontext)
PHP_Z_PARAM_STREAM_CONTEXT_OR_NULL_AS_DEFAULT_CONTEXT(context)
ZEND_PARSE_PARAMETERS_END();

context = php_stream_context_from_zval(zcontext, 0);

dirp = php_stream_opendir(dirname, REPORT_ERRORS, context);

if (dirp == NULL) {
@@ -469,25 +466,20 @@ PHP_FUNCTION(scandir)
zend_long flags = PHP_SCANDIR_SORT_ASCENDING;
zend_string **namelist;
int n, i;
zval *zcontext = NULL;
php_stream_context *context = NULL;

ZEND_PARSE_PARAMETERS_START(1, 3)
Z_PARAM_PATH(dirn, dirn_len)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(flags)
Z_PARAM_RESOURCE_OR_NULL(zcontext)
PHP_Z_PARAM_STREAM_CONTEXT_OR_NULL_AS_DEFAULT_CONTEXT(context)
ZEND_PARSE_PARAMETERS_END();

if (dirn_len < 1) {
zend_argument_must_not_be_empty_error(1);
RETURN_THROWS();
}

if (zcontext) {
context = php_stream_context_from_zval(zcontext, 0);
}

if (flags == PHP_SCANDIR_SORT_ASCENDING) {
n = php_stream_scandir(dirn, &namelist, context, (void *) php_stream_dirent_alphasort);
} else if (flags == PHP_SCANDIR_SORT_NONE) {
62 changes: 20 additions & 42 deletions ext/standard/file.c
Original file line number Diff line number Diff line change
@@ -382,7 +382,6 @@ PHP_FUNCTION(file_get_contents)
zend_long offset = 0;
zend_long maxlen;
bool maxlen_is_null = 1;
zval *zcontext = NULL;
php_stream_context *context = NULL;
zend_string *contents;

@@ -391,7 +390,7 @@ PHP_FUNCTION(file_get_contents)
Z_PARAM_PATH(filename, filename_len)
Z_PARAM_OPTIONAL
Z_PARAM_BOOL(use_include_path)
Z_PARAM_RESOURCE_OR_NULL(zcontext)
PHP_Z_PARAM_STREAM_CONTEXT_OR_NULL_AS_DEFAULT_CONTEXT(context)
Z_PARAM_LONG(offset)
Z_PARAM_LONG_OR_NULL(maxlen, maxlen_is_null)
ZEND_PARSE_PARAMETERS_END();
@@ -403,8 +402,6 @@ PHP_FUNCTION(file_get_contents)
RETURN_THROWS();
}

context = php_stream_context_from_zval(zcontext, 0);

stream = php_stream_open_wrapper_ex(filename, "rb",
(use_include_path ? USE_PATH : 0) | REPORT_ERRORS,
NULL, context);
@@ -443,7 +440,6 @@ PHP_FUNCTION(file_put_contents)
zval *data;
ssize_t numbytes = 0;
zend_long flags = 0;
zval *zcontext = NULL;
php_stream_context *context = NULL;
php_stream *srcstream = NULL;
char mode[3] = "wb";
@@ -453,14 +449,16 @@ PHP_FUNCTION(file_put_contents)
Z_PARAM_ZVAL(data)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(flags)
Z_PARAM_RESOURCE_OR_NULL(zcontext)
PHP_Z_PARAM_STREAM_CONTEXT_OR_NULL(context)
ZEND_PARSE_PARAMETERS_END();

if (Z_TYPE_P(data) == IS_RESOURCE) {
php_stream_from_zval(srcstream, data);
}

context = php_stream_context_from_zval(zcontext, flags & PHP_FILE_NO_DEFAULT_CONTEXT);
if (context == NULL) {
context = php_stream_context_get_default(flags & PHP_FILE_NO_DEFAULT_CONTEXT);
}

if (flags & PHP_FILE_APPEND) {
mode[0] = 'a';
@@ -589,7 +587,6 @@ PHP_FUNCTION(file)
bool include_new_line;
bool skip_blank_lines;
php_stream *stream;
zval *zcontext = NULL;
php_stream_context *context = NULL;
zend_string *target_buf;

@@ -598,7 +595,7 @@ PHP_FUNCTION(file)
Z_PARAM_PATH(filename, filename_len)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(flags)
Z_PARAM_RESOURCE_OR_NULL(zcontext)
PHP_Z_PARAM_STREAM_CONTEXT_OR_NULL(context)
ZEND_PARSE_PARAMETERS_END();

if ((flags & ~(PHP_FILE_USE_INCLUDE_PATH | PHP_FILE_IGNORE_NEW_LINES | PHP_FILE_SKIP_EMPTY_LINES | PHP_FILE_NO_DEFAULT_CONTEXT)) != 0) {
@@ -610,7 +607,9 @@ PHP_FUNCTION(file)
include_new_line = !(flags & PHP_FILE_IGNORE_NEW_LINES);
skip_blank_lines = flags & PHP_FILE_SKIP_EMPTY_LINES;

context = php_stream_context_from_zval(zcontext, flags & PHP_FILE_NO_DEFAULT_CONTEXT);
if (context == NULL) {
context = php_stream_context_get_default(flags & PHP_FILE_NO_DEFAULT_CONTEXT);
}

stream = php_stream_open_wrapper_ex(filename, "rb", (use_include_path ? USE_PATH : 0) | REPORT_ERRORS, NULL, context);
if (!stream) {
@@ -723,7 +722,6 @@ PHP_FUNCTION(fopen)
char *filename, *mode;
size_t filename_len, mode_len;
bool use_include_path = 0;
zval *zcontext = NULL;
php_stream *stream;
php_stream_context *context = NULL;

@@ -732,11 +730,9 @@ PHP_FUNCTION(fopen)
Z_PARAM_STRING(mode, mode_len)
Z_PARAM_OPTIONAL
Z_PARAM_BOOL(use_include_path)
Z_PARAM_RESOURCE_OR_NULL(zcontext)
PHP_Z_PARAM_STREAM_CONTEXT_OR_NULL_AS_DEFAULT_CONTEXT(context)
ZEND_PARSE_PARAMETERS_END();

context = php_stream_context_from_zval(zcontext, 0);

stream = php_stream_open_wrapper_ex(filename, mode, (use_include_path ? USE_PATH : 0) | REPORT_ERRORS, NULL, context);

if (stream == NULL) {
@@ -1078,21 +1074,18 @@ PHP_FUNCTION(mkdir)
{
char *dir;
size_t dir_len;
zval *zcontext = NULL;
zend_long mode = 0777;
bool recursive = 0;
php_stream_context *context;
php_stream_context *context = NULL;

ZEND_PARSE_PARAMETERS_START(1, 4)
Z_PARAM_PATH(dir, dir_len)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(mode)
Z_PARAM_BOOL(recursive)
Z_PARAM_RESOURCE_OR_NULL(zcontext)
PHP_Z_PARAM_STREAM_CONTEXT_OR_NULL_AS_DEFAULT_CONTEXT(context)
ZEND_PARSE_PARAMETERS_END();

context = php_stream_context_from_zval(zcontext, 0);

RETURN_BOOL(php_stream_mkdir(dir, (int)mode, (recursive ? PHP_STREAM_MKDIR_RECURSIVE : 0) | REPORT_ERRORS, context));
}
/* }}} */
@@ -1102,17 +1095,14 @@ PHP_FUNCTION(rmdir)
{
char *dir;
size_t dir_len;
zval *zcontext = NULL;
php_stream_context *context;
php_stream_context *context = NULL;

ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_PATH(dir, dir_len)
Z_PARAM_OPTIONAL
Z_PARAM_RESOURCE_OR_NULL(zcontext)
PHP_Z_PARAM_STREAM_CONTEXT_OR_NULL_AS_DEFAULT_CONTEXT(context)
ZEND_PARSE_PARAMETERS_END();

context = php_stream_context_from_zval(zcontext, 0);

RETURN_BOOL(php_stream_rmdir(dir, REPORT_ERRORS, context));
}
/* }}} */
@@ -1124,19 +1114,16 @@ PHP_FUNCTION(readfile)
size_t filename_len;
size_t size = 0;
bool use_include_path = 0;
zval *zcontext = NULL;
php_stream *stream;
php_stream_context *context = NULL;

ZEND_PARSE_PARAMETERS_START(1, 3)
Z_PARAM_PATH(filename, filename_len)
Z_PARAM_OPTIONAL
Z_PARAM_BOOL(use_include_path)
Z_PARAM_RESOURCE_OR_NULL(zcontext)
PHP_Z_PARAM_STREAM_CONTEXT_OR_NULL_AS_DEFAULT_CONTEXT(context)
ZEND_PARSE_PARAMETERS_END();

context = php_stream_context_from_zval(zcontext, 0);

stream = php_stream_open_wrapper_ex(filename, "rb", (use_include_path ? USE_PATH : 0) | REPORT_ERRORS, NULL, context);
if (stream) {
size = php_stream_passthru(stream);
@@ -1196,15 +1183,14 @@ PHP_FUNCTION(rename)
{
char *old_name, *new_name;
size_t old_name_len, new_name_len;
zval *zcontext = NULL;
php_stream_wrapper *wrapper;
php_stream_context *context;
php_stream_context *context = NULL;

ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_PATH(old_name, old_name_len)
Z_PARAM_PATH(new_name, new_name_len)
Z_PARAM_OPTIONAL
Z_PARAM_RESOURCE_OR_NULL(zcontext)
PHP_Z_PARAM_STREAM_CONTEXT_OR_NULL_AS_DEFAULT_CONTEXT(context)
ZEND_PARSE_PARAMETERS_END();

wrapper = php_stream_locate_url_wrapper(old_name, NULL, 0);
@@ -1224,8 +1210,6 @@ PHP_FUNCTION(rename)
RETURN_FALSE;
}

context = php_stream_context_from_zval(zcontext, 0);

RETURN_BOOL(wrapper->wops->rename(wrapper, old_name, new_name, 0, context));
}
/* }}} */
@@ -1236,17 +1220,14 @@ PHP_FUNCTION(unlink)
char *filename;
size_t filename_len;
php_stream_wrapper *wrapper;
zval *zcontext = NULL;
php_stream_context *context = NULL;

ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_PATH(filename, filename_len)
Z_PARAM_OPTIONAL
Z_PARAM_RESOURCE_OR_NULL(zcontext)
PHP_Z_PARAM_STREAM_CONTEXT_OR_NULL_AS_DEFAULT_CONTEXT(context)
ZEND_PARSE_PARAMETERS_END();

context = php_stream_context_from_zval(zcontext, 0);

wrapper = php_stream_locate_url_wrapper(filename, NULL, 0);

if (!wrapper || !wrapper->wops) {
@@ -1408,22 +1389,19 @@ PHP_FUNCTION(copy)
{
char *source, *target;
size_t source_len, target_len;
zval *zcontext = NULL;
php_stream_context *context;
php_stream_context *context = NULL;

ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_PATH(source, source_len)
Z_PARAM_PATH(target, target_len)
Z_PARAM_OPTIONAL
Z_PARAM_RESOURCE_OR_NULL(zcontext)
PHP_Z_PARAM_STREAM_CONTEXT_OR_NULL_AS_DEFAULT_CONTEXT(context)
ZEND_PARSE_PARAMETERS_END();

if (php_stream_locate_url_wrapper(source, NULL, 0) == &php_plain_files_wrapper && php_check_open_basedir(source)) {
RETURN_FALSE;
}

context = php_stream_context_from_zval(zcontext, 0);

RETURN_BOOL(php_copy_file_ctx(source, target, 0, context) == SUCCESS);
}
/* }}} */
1 change: 0 additions & 1 deletion ext/standard/file.h
Original file line number Diff line number Diff line change
@@ -36,7 +36,6 @@ PHPAPI PHP_FUNCTION(fpassthru);

PHP_MINIT_FUNCTION(user_streams);

PHPAPI int php_le_stream_context(void);
PHPAPI zend_result php_copy_file(const char *src, const char *dest);
PHPAPI zend_result php_copy_file_ex(const char *src, const char *dest, int src_flags);
PHPAPI zend_result php_copy_file_ctx(const char *src, const char *dest, int src_flags, php_stream_context *ctx);
16 changes: 10 additions & 6 deletions ext/standard/streamsfuncs.c
Original file line number Diff line number Diff line change
@@ -96,7 +96,7 @@ PHP_FUNCTION(stream_socket_pair)
PHP_FUNCTION(stream_socket_client)
{
zend_string *host;
zval *zerrno = NULL, *zerrstr = NULL, *zcontext = NULL;
zval *zerrno = NULL, *zerrstr = NULL;
double timeout;
bool timeout_is_null = 1;
php_timeout_ull conv;
@@ -115,7 +115,7 @@ PHP_FUNCTION(stream_socket_client)
Z_PARAM_ZVAL(zerrstr)
Z_PARAM_DOUBLE_OR_NULL(timeout, timeout_is_null)
Z_PARAM_LONG(flags)
Z_PARAM_RESOURCE_OR_NULL(zcontext)
PHP_Z_PARAM_STREAM_CONTEXT_OR_NULL(context)
ZEND_PARSE_PARAMETERS_END();

RETVAL_FALSE;
@@ -127,7 +127,9 @@ PHP_FUNCTION(stream_socket_client)
RETURN_THROWS();
}

context = php_stream_context_from_zval(zcontext, flags & PHP_FILE_NO_DEFAULT_CONTEXT);
if (context == NULL) {
context = php_stream_context_get_default(flags & PHP_FILE_NO_DEFAULT_CONTEXT);
}

if (flags & PHP_STREAM_CLIENT_PERSISTENT) {
spprintf(&hashkey, 0, "stream_socket_client__%s", ZSTR_VAL(host));
@@ -200,7 +202,7 @@ PHP_FUNCTION(stream_socket_server)
{
char *host;
size_t host_len;
zval *zerrno = NULL, *zerrstr = NULL, *zcontext = NULL;
zval *zerrno = NULL, *zerrstr = NULL;
php_stream *stream = NULL;
int err = 0;
zend_long flags = STREAM_XPORT_BIND | STREAM_XPORT_LISTEN;
@@ -215,10 +217,12 @@ PHP_FUNCTION(stream_socket_server)
Z_PARAM_ZVAL(zerrno)
Z_PARAM_ZVAL(zerrstr)
Z_PARAM_LONG(flags)
Z_PARAM_RESOURCE_OR_NULL(zcontext)
PHP_Z_PARAM_STREAM_CONTEXT_OR_NULL(context)
ZEND_PARSE_PARAMETERS_END();

context = php_stream_context_from_zval(zcontext, flags & PHP_FILE_NO_DEFAULT_CONTEXT);
if (context == NULL) {
context = php_stream_context_get_default(flags & PHP_FILE_NO_DEFAULT_CONTEXT);
}

if (zerrno) {
ZEND_TRY_ASSIGN_REF_LONG(zerrno, 0);
18 changes: 14 additions & 4 deletions ext/standard/tests/file/file_get_contents_error.phpt
Original file line number Diff line number Diff line change
@@ -16,11 +16,18 @@ print( file_get_contents("/no/such/file/or/dir") );
create_files($file_path, 1, "text", 0755, 100, "w", "file_get_contents_error", 1, "byte");
$file_handle = fopen($file_path."/file_put_contents_error.tmp", "w");

echo "\n-- Testing invalid context resource --\n";
try {
file_get_contents($file_path."/file_get_contents_error1.tmp", FALSE, $file_handle);
} catch (Throwable $e) {
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
}

echo "\n-- Testing for invalid negative maxlen values --\n";
try {
file_get_contents($file_path."/file_get_contents_error1.tmp", FALSE, $file_handle, 0, -5);
} catch (ValueError $exception) {
echo $exception->getMessage() . "\n";
file_get_contents($file_path."/file_get_contents_error1.tmp", FALSE, null, 0, -5);
} catch (Throwable $e) {
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
}

delete_files($file_path, 1, "file_get_contents_error", 1);
@@ -46,7 +53,10 @@ if(file_exists($file_path."/file_put_contents1.tmp")) {

Warning: file_get_contents(/no/such/file/or/dir): Failed to open stream: No such file or directory in %s on line %d

-- Testing invalid context resource --
TypeError: file_get_contents(): supplied resource is not a valid Stream-Context resource

-- Testing for invalid negative maxlen values --
file_get_contents(): Argument #5 ($length) must be greater than or equal to 0
ValueError: file_get_contents(): Argument #5 ($length) must be greater than or equal to 0

*** Done ***
7 changes: 2 additions & 5 deletions ext/standard/url.c
Original file line number Diff line number Diff line change
@@ -671,18 +671,15 @@ PHP_FUNCTION(get_headers)
php_stream *stream;
zval *prev_val, *hdr = NULL;
bool format = 0;
zval *zcontext = NULL;
php_stream_context *context;
php_stream_context *context = NULL;

ZEND_PARSE_PARAMETERS_START(1, 3)
Z_PARAM_PATH(url, url_len)
Z_PARAM_OPTIONAL
Z_PARAM_BOOL(format)
Z_PARAM_RESOURCE_OR_NULL(zcontext)
PHP_Z_PARAM_STREAM_CONTEXT_OR_NULL_AS_DEFAULT_CONTEXT(context)
ZEND_PARSE_PARAMETERS_END();

context = php_stream_context_from_zval(zcontext, 0);

if (!(stream = php_stream_open_wrapper_ex(url, "r", REPORT_ERRORS | STREAM_USE_URL | STREAM_ONLY_GET_HEADERS, NULL, context))) {
RETURN_FALSE;
}
6 changes: 3 additions & 3 deletions ext/zlib/zlib.c
Original file line number Diff line number Diff line change
@@ -622,7 +622,7 @@ PHP_FUNCTION(gzfile)
}

/* using a stream here is a bit more efficient (resource wise) than php_gzopen_wrapper */
stream = php_stream_gzopen(NULL, filename, "rb", flags, NULL, php_stream_context_from_zval(NULL, false) STREAMS_CC);
stream = php_stream_gzopen(NULL, filename, "rb", flags, NULL, php_stream_context_get_default(false) STREAMS_CC);

if (!stream) {
/* Error reporting is already done by stream code */
@@ -660,7 +660,7 @@ PHP_FUNCTION(gzopen)
flags |= USE_PATH;
}

stream = php_stream_gzopen(NULL, filename, mode, flags, NULL, php_stream_context_from_zval(NULL, false) STREAMS_CC);
stream = php_stream_gzopen(NULL, filename, mode, flags, NULL, php_stream_context_get_default(false) STREAMS_CC);

if (!stream) {
RETURN_FALSE;
@@ -687,7 +687,7 @@ PHP_FUNCTION(readgzfile)
flags |= USE_PATH;
}

stream = php_stream_gzopen(NULL, filename, "rb", flags, NULL, php_stream_context_from_zval(NULL, false) STREAMS_CC);
stream = php_stream_gzopen(NULL, filename, "rb", flags, NULL, php_stream_context_get_default(false) STREAMS_CC);

if (!stream) {
RETURN_FALSE;
48 changes: 45 additions & 3 deletions main/streams/php_stream_context.h
Original file line number Diff line number Diff line change
@@ -25,14 +25,17 @@ typedef void (*php_stream_notification_func)(php_stream_context *context,

#define PHP_STREAM_NOTIFIER_PROGRESS 1

/* TODO: Remove dependence on ext/standard/file.h for the default context global */
#define php_stream_context_get_default(without_context) \
(without_context) ? NULL : FG(default_context) ? FG(default_context) : \
(FG(default_context) = php_stream_context_alloc())

/* Attempt to fetch context from the zval passed,
If no context was passed, use the default context
The default context has not yet been created, do it now. */
#define php_stream_context_from_zval(zcontext, nocontext) ( \
(zcontext) ? zend_fetch_resource_ex(zcontext, "Stream-Context", php_le_stream_context()) : \
(nocontext) ? NULL : \
FG(default_context) ? FG(default_context) : \
(FG(default_context) = php_stream_context_alloc()) )
php_stream_context_get_default(nocontext))

#define php_stream_context_to_zval(context, zval) { ZVAL_RES(zval, (context)->res); GC_ADDREF((context)->res); }

@@ -53,6 +56,7 @@ struct _php_stream_context {
};

BEGIN_EXTERN_C()
PHPAPI int php_le_stream_context(void);
PHPAPI void php_stream_context_free(php_stream_context *context);
PHPAPI php_stream_context *php_stream_context_alloc(void);
PHPAPI zval *php_stream_context_get_option(php_stream_context *context,
@@ -81,6 +85,44 @@ END_EXTERN_C()
#define PHP_STREAM_NOTIFY_SEVERITY_ERR 2

BEGIN_EXTERN_C()
static zend_always_inline bool php_stream_zend_parse_arg_into_stream_context(
zval *arg,
php_stream_context **destination_context_ptr,
bool check_null,
php_stream_context *default_context
) {
if (EXPECTED(Z_TYPE_P(arg) == IS_RESOURCE)) {
*destination_context_ptr = (php_stream_context*)zend_fetch_resource_ex(arg, "Stream-Context", php_le_stream_context());
if (UNEXPECTED(*destination_context_ptr == NULL)) {
return false;
}
} else if (check_null && EXPECTED(Z_TYPE_P(arg) == IS_NULL)) {
if (default_context) {
*destination_context_ptr = default_context;
} else {
*destination_context_ptr = NULL;
}
} else {
return false;
}
return true;
}

#define PHP_Z_PARAM_STREAM_CONTEXT_EX(destination_context_ptr, check_null, null_as_default_context) \
Z_PARAM_PROLOGUE(0, 0); \
php_stream_context *php_param_default_context = php_stream_context_get_default(null_as_default_context); \
if (UNEXPECTED(!php_stream_zend_parse_arg_into_stream_context(_arg, &destination_context_ptr, check_null, php_param_default_context))) { \
_error_code = ZPP_ERROR_FAILURE; \
if (!EG(exception)) { \
_expected_type = check_null ? Z_EXPECTED_RESOURCE_OR_NULL : Z_EXPECTED_RESOURCE; \
_error_code = ZPP_ERROR_WRONG_ARG; \
} \
break; \
}
#define PHP_Z_PARAM_STREAM_CONTEXT(dest) PHP_Z_PARAM_STREAM_CONTEXT_EX(dest, false, false)
#define PHP_Z_PARAM_STREAM_CONTEXT_OR_NULL(dest) PHP_Z_PARAM_STREAM_CONTEXT_EX(dest, true, false)
#define PHP_Z_PARAM_STREAM_CONTEXT_OR_NULL_AS_DEFAULT_CONTEXT(dest) PHP_Z_PARAM_STREAM_CONTEXT_EX(dest, true, true)

PHPAPI void php_stream_notification_notify(php_stream_context *context, int notifycode, int severity,
char *xmsg, int xcode, size_t bytes_sofar, size_t bytes_max, void * ptr);
PHPAPI php_stream_context *php_stream_context_set(php_stream *stream, php_stream_context *context);