mirror of
https://github.com/php/php-src.git
synced 2025-08-15 13:38:49 +02:00
Add dedicated StreamBucket class (#13111)
RFC: https://wiki.php.net/rfc/dedicated_stream_bucket
This commit is contained in:
parent
bc62b41126
commit
be2f454d6e
7 changed files with 103 additions and 30 deletions
|
@ -8,7 +8,7 @@ $standard = new ReflectionExtension('standard');
|
|||
var_dump($standard->getClassNames());
|
||||
?>
|
||||
--EXPECT--
|
||||
array(4) {
|
||||
array(5) {
|
||||
[0]=>
|
||||
string(22) "__PHP_Incomplete_Class"
|
||||
[1]=>
|
||||
|
@ -16,5 +16,7 @@ array(4) {
|
|||
[2]=>
|
||||
string(15) "php_user_filter"
|
||||
[3]=>
|
||||
string(12) "StreamBucket"
|
||||
[4]=>
|
||||
string(9) "Directory"
|
||||
}
|
||||
|
|
|
@ -3744,19 +3744,19 @@ function get_headers(string $url, bool $associative = false, $context = null): a
|
|||
* @param resource $brigade
|
||||
* @refcount 1
|
||||
*/
|
||||
function stream_bucket_make_writeable($brigade): ?object {}
|
||||
function stream_bucket_make_writeable($brigade): ?StreamBucket {}
|
||||
|
||||
/** @param resource $brigade */
|
||||
function stream_bucket_prepend($brigade, object $bucket): void {}
|
||||
function stream_bucket_prepend($brigade, StreamBucket $bucket): void {}
|
||||
|
||||
/** @param resource $brigade */
|
||||
function stream_bucket_append($brigade, object $bucket): void {}
|
||||
function stream_bucket_append($brigade, StreamBucket $bucket): void {}
|
||||
|
||||
/**
|
||||
* @param resource $stream
|
||||
* @refcount 1
|
||||
*/
|
||||
function stream_bucket_new($stream, string $buffer): object {}
|
||||
function stream_bucket_new($stream, string $buffer): StreamBucket {}
|
||||
|
||||
/**
|
||||
* @return array<int, string>
|
||||
|
|
8
ext/standard/basic_functions_arginfo.h
generated
8
ext/standard/basic_functions_arginfo.h
generated
|
@ -1,5 +1,5 @@
|
|||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 954bf48ac1f24a14fd7508c8bf4b781883398499 */
|
||||
* Stub hash: 1ef54fdebc6a206c4af3438130db0cd12a62c8b6 */
|
||||
|
||||
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)
|
||||
|
@ -2104,18 +2104,18 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_get_headers, 0, 1, MAY_BE_ARRAY|
|
|||
ZEND_ARG_INFO_WITH_DEFAULT_VALUE(0, context, "null")
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_stream_bucket_make_writeable, 0, 1, IS_OBJECT, 1)
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_stream_bucket_make_writeable, 0, 1, StreamBucket, 1)
|
||||
ZEND_ARG_INFO(0, brigade)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_stream_bucket_prepend, 0, 2, IS_VOID, 0)
|
||||
ZEND_ARG_INFO(0, brigade)
|
||||
ZEND_ARG_TYPE_INFO(0, bucket, IS_OBJECT, 0)
|
||||
ZEND_ARG_OBJ_INFO(0, bucket, StreamBucket, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_stream_bucket_append arginfo_stream_bucket_prepend
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_stream_bucket_new, 0, 2, IS_OBJECT, 0)
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_stream_bucket_new, 0, 2, StreamBucket, 0)
|
||||
ZEND_ARG_INFO(0, stream)
|
||||
ZEND_ARG_TYPE_INFO(0, buffer, IS_STRING, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
|
|
@ -4,6 +4,7 @@ Bug #39551 (Segfault with stream_bucket_new in user filter)
|
|||
<?php
|
||||
|
||||
$bucket = stream_bucket_new(fopen('php://temp', 'w+'), '');
|
||||
var_dump($bucket);
|
||||
|
||||
class bucketFilter extends php_user_filter {
|
||||
public function filter($in, $out, &$consumed, $closing ): int {
|
||||
|
@ -20,5 +21,15 @@ stream_get_contents($s);
|
|||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECT--
|
||||
--EXPECTF--
|
||||
object(StreamBucket)#%d (%d) {
|
||||
["bucket"]=>
|
||||
resource(%d) of type (userfilter.bucket)
|
||||
["data"]=>
|
||||
string(0) ""
|
||||
["datalen"]=>
|
||||
int(0)
|
||||
["dataLength"]=>
|
||||
int(0)
|
||||
}
|
||||
Done
|
||||
|
|
|
@ -61,6 +61,7 @@ PHP_METHOD(php_user_filter, onClose)
|
|||
}
|
||||
|
||||
static zend_class_entry *user_filter_class_entry;
|
||||
static zend_class_entry *stream_bucket_class_entry;
|
||||
|
||||
static ZEND_RSRC_DTOR_FUNC(php_bucket_dtor)
|
||||
{
|
||||
|
@ -75,6 +76,7 @@ PHP_MINIT_FUNCTION(user_filters)
|
|||
{
|
||||
/* init the filter class ancestor */
|
||||
user_filter_class_entry = register_class_php_user_filter();
|
||||
stream_bucket_class_entry = register_class_StreamBucket();
|
||||
|
||||
/* Filters will dispose of their brigades */
|
||||
le_bucket_brigade = zend_register_list_destructors_ex(NULL, NULL, PHP_STREAM_BRIGADE_RES_NAME, module_number);
|
||||
|
@ -351,16 +353,17 @@ PHP_FUNCTION(stream_bucket_make_writeable)
|
|||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
ZVAL_NULL(return_value);
|
||||
|
||||
if (brigade->head && (bucket = php_stream_bucket_make_writeable(brigade->head))) {
|
||||
ZVAL_RES(&zbucket, zend_register_resource(bucket, le_bucket));
|
||||
object_init(return_value);
|
||||
add_property_zval(return_value, "bucket", &zbucket);
|
||||
object_init_ex(return_value, stream_bucket_class_entry);
|
||||
zend_update_property(Z_OBJCE_P(return_value), Z_OBJ_P(return_value), ZEND_STRL("bucket"), &zbucket);
|
||||
/* add_property_zval increments the refcount which is unwanted here */
|
||||
zval_ptr_dtor(&zbucket);
|
||||
add_property_stringl(return_value, "data", bucket->buf, bucket->buflen);
|
||||
add_property_long(return_value, "datalen", bucket->buflen);
|
||||
zend_update_property_stringl(Z_OBJCE_P(return_value), Z_OBJ_P(return_value), ZEND_STRL("data"), bucket->buf, bucket->buflen);
|
||||
zend_update_property_long(Z_OBJCE_P(return_value), Z_OBJ_P(return_value), ZEND_STRL("datalen"), bucket->buflen);
|
||||
zend_update_property_long(Z_OBJCE_P(return_value), Z_OBJ_P(return_value), ZEND_STRL("dataLength"), bucket->buflen);
|
||||
} else {
|
||||
ZVAL_NULL(return_value);
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
@ -369,30 +372,32 @@ PHP_FUNCTION(stream_bucket_make_writeable)
|
|||
static void php_stream_bucket_attach(int append, INTERNAL_FUNCTION_PARAMETERS)
|
||||
{
|
||||
zval *zbrigade, *zobject;
|
||||
zval *pzbucket, *pzdata;
|
||||
zval *pzbucket, *pzdata, rv;
|
||||
php_stream_bucket_brigade *brigade;
|
||||
php_stream_bucket *bucket;
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(2, 2)
|
||||
Z_PARAM_RESOURCE(zbrigade)
|
||||
Z_PARAM_OBJECT(zobject)
|
||||
Z_PARAM_OBJECT_OF_CLASS(zobject, stream_bucket_class_entry)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
if (NULL == (pzbucket = zend_hash_str_find_deref(Z_OBJPROP_P(zobject), "bucket", sizeof("bucket")-1))) {
|
||||
if ((brigade = (php_stream_bucket_brigade*)zend_fetch_resource(
|
||||
Z_RES_P(zbrigade), PHP_STREAM_BRIGADE_RES_NAME, le_bucket_brigade)) == NULL) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
if (NULL == (pzbucket = zend_read_property(NULL, Z_OBJ_P(zobject), "bucket", sizeof("bucket")-1, false, &rv))) {
|
||||
zend_argument_value_error(2, "must be an object that has a \"bucket\" property");
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
if ((brigade = (php_stream_bucket_brigade*)zend_fetch_resource(
|
||||
Z_RES_P(zbrigade), PHP_STREAM_BRIGADE_RES_NAME, le_bucket_brigade)) == NULL) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
ZVAL_DEREF(pzbucket);
|
||||
|
||||
if ((bucket = (php_stream_bucket *)zend_fetch_resource_ex(pzbucket, PHP_STREAM_BUCKET_RES_NAME, le_bucket)) == NULL) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
if (NULL != (pzdata = zend_hash_str_find_deref(Z_OBJPROP_P(zobject), "data", sizeof("data")-1)) && Z_TYPE_P(pzdata) == IS_STRING) {
|
||||
if (NULL != (pzdata = zend_read_property(NULL, Z_OBJ_P(zobject), "data", sizeof("data")-1, false, &rv))) {
|
||||
ZVAL_DEREF(pzdata);
|
||||
if (!bucket->own_buf) {
|
||||
bucket = php_stream_bucket_make_writeable(bucket);
|
||||
}
|
||||
|
@ -454,12 +459,13 @@ PHP_FUNCTION(stream_bucket_new)
|
|||
bucket = php_stream_bucket_new(stream, pbuffer, buffer_len, 1, php_stream_is_persistent(stream));
|
||||
|
||||
ZVAL_RES(&zbucket, zend_register_resource(bucket, le_bucket));
|
||||
object_init(return_value);
|
||||
add_property_zval(return_value, "bucket", &zbucket);
|
||||
object_init_ex(return_value, stream_bucket_class_entry);
|
||||
zend_update_property(Z_OBJCE_P(return_value), Z_OBJ_P(return_value), ZEND_STRL("bucket"), &zbucket);
|
||||
/* add_property_zval increments the refcount which is unwanted here */
|
||||
zval_ptr_dtor(&zbucket);
|
||||
add_property_stringl(return_value, "data", bucket->buf, bucket->buflen);
|
||||
add_property_long(return_value, "datalen", bucket->buflen);
|
||||
zend_update_property_stringl(Z_OBJCE_P(return_value), Z_OBJ_P(return_value), ZEND_STRL("data"), bucket->buf, bucket->buflen);
|
||||
zend_update_property_long(Z_OBJCE_P(return_value), Z_OBJ_P(return_value), ZEND_STRL("datalen"), bucket->buflen);
|
||||
zend_update_property_long(Z_OBJCE_P(return_value), Z_OBJ_P(return_value), ZEND_STRL("dataLength"), bucket->buflen);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
|
|
@ -55,3 +55,18 @@ class php_user_filter
|
|||
/** @tentative-return-type */
|
||||
public function onClose(): void {}
|
||||
}
|
||||
|
||||
final class StreamBucket
|
||||
{
|
||||
/**
|
||||
* @var resource
|
||||
* @readonly
|
||||
*/
|
||||
public $bucket;
|
||||
/** @readonly */
|
||||
public string $data;
|
||||
/** @readonly */
|
||||
public int $datalen;
|
||||
/** @readonly */
|
||||
public int $dataLength;
|
||||
}
|
||||
|
|
41
ext/standard/user_filters_arginfo.h
generated
41
ext/standard/user_filters_arginfo.h
generated
|
@ -1,5 +1,5 @@
|
|||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 1c03251b4e0b22056da43bf86087d6996454d2a0 */
|
||||
* Stub hash: 33264435fe01a2cc9aa21a4a087dbbf3c4007206 */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_php_user_filter_filter, 0, 4, IS_LONG, 0)
|
||||
ZEND_ARG_INFO(0, in)
|
||||
|
@ -25,6 +25,10 @@ static const zend_function_entry class_php_user_filter_methods[] = {
|
|||
ZEND_FE_END
|
||||
};
|
||||
|
||||
static const zend_function_entry class_StreamBucket_methods[] = {
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
||||
static void register_user_filters_symbols(int module_number)
|
||||
{
|
||||
REGISTER_LONG_CONSTANT("PSFS_PASS_ON", PSFS_PASS_ON, CONST_PERSISTENT);
|
||||
|
@ -62,3 +66,38 @@ static zend_class_entry *register_class_php_user_filter(void)
|
|||
|
||||
return class_entry;
|
||||
}
|
||||
|
||||
static zend_class_entry *register_class_StreamBucket(void)
|
||||
{
|
||||
zend_class_entry ce, *class_entry;
|
||||
|
||||
INIT_CLASS_ENTRY(ce, "StreamBucket", class_StreamBucket_methods);
|
||||
class_entry = zend_register_internal_class_ex(&ce, NULL);
|
||||
class_entry->ce_flags |= ZEND_ACC_FINAL;
|
||||
|
||||
zval property_bucket_default_value;
|
||||
ZVAL_NULL(&property_bucket_default_value);
|
||||
zend_string *property_bucket_name = zend_string_init("bucket", sizeof("bucket") - 1, 1);
|
||||
zend_declare_typed_property(class_entry, property_bucket_name, &property_bucket_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_NONE(0));
|
||||
zend_string_release(property_bucket_name);
|
||||
|
||||
zval property_data_default_value;
|
||||
ZVAL_UNDEF(&property_data_default_value);
|
||||
zend_string *property_data_name = zend_string_init("data", sizeof("data") - 1, 1);
|
||||
zend_declare_typed_property(class_entry, property_data_name, &property_data_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
|
||||
zend_string_release(property_data_name);
|
||||
|
||||
zval property_datalen_default_value;
|
||||
ZVAL_UNDEF(&property_datalen_default_value);
|
||||
zend_string *property_datalen_name = zend_string_init("datalen", sizeof("datalen") - 1, 1);
|
||||
zend_declare_typed_property(class_entry, property_datalen_name, &property_datalen_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
|
||||
zend_string_release(property_datalen_name);
|
||||
|
||||
zval property_dataLength_default_value;
|
||||
ZVAL_UNDEF(&property_dataLength_default_value);
|
||||
zend_string *property_dataLength_name = zend_string_init("dataLength", sizeof("dataLength") - 1, 1);
|
||||
zend_declare_typed_property(class_entry, property_dataLength_name, &property_dataLength_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
|
||||
zend_string_release(property_dataLength_name);
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue