Skip to content
Merged
8 changes: 8 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ PHP NEWS
error handler instead of emitting a warning and continuing with an empty
string. (Weilin Du)

- Reflection:
. Added ReflectionAttribute::inNamespace(),
ReflectionAttribute::getNamespaceName(), and
ReflectionAttribute::getShortName(). (Girgias)

- Standard:
. The following functions now raise a ValueError when the $filename argument
contains NUL bytes: fileperms(), fileinode(), filesize(), fileowner(),
Expand Down Expand Up @@ -79,6 +84,9 @@ PHP NEWS
- SOAP:
. Fixed header injection through the Content-Type context option, the
soapaction and the cookie names and values. (David Carlier)
. Fixed the SoapClient and SoapServer "classmap" option to reject arrays
containing integer keys, and made SoapClient throw TypeError/ValueError
for invalid "classmap" options. (Weilin Du, David Carlier)

- MBString:
. Fixed bug GH-22779 (mb_strrpos() returns the wrong position for a negative
Expand Down
8 changes: 8 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,11 @@ PHP 8.6 UPGRADE NOTES
system.

- SOAP:
. The "classmap" option of SoapClient and SoapServer now rejects arrays
containing integer keys. Previously, sparse integer-keyed and mixed-keyed
arrays could be accepted. SoapClient now throws TypeError for non-array
"classmap" options and ValueError for arrays containing integer keys, also
when the "exceptions" option is disabled.
. WSDL/XML Schema parsing now rejects out-of-range integer values for
occurrence constraints and integer restriction facets. Negative minOccurs
and maxOccurs values are rejected as well.
Expand Down Expand Up @@ -478,6 +483,9 @@ PHP 8.6 UPGRADE NOTES
RFC: https://wiki.php.net/rfc/isreadable-iswriteable
. ReflectionParameter::getDocComment()
RFC: https://wiki.php.net/rfc/parameter-doccomments
. ReflectionAttribute::inNamespace()
. ReflectionAttribute::getNamespaceName()
. ReflectionAttribute::getShortName()

- Standard:
. clamp() returns the given value if in range, else return the nearest
Expand Down
2 changes: 1 addition & 1 deletion ext/hash/php_hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ static inline void *php_hash_alloc_context(const php_hash_ops *ops) {
/* Zero out context memory so serialization doesn't expose internals */
if (ops->context_align > 0) {
size_t align = ops->context_align;
char *base = ecalloc(1, ops->context_size + align);
char *base = (char *) ecalloc(1, ops->context_size + align);
size_t offset = align - ((uintptr_t)base & (align - 1));
char *ptr = base + offset;
ptr[-1] = (char)offset;
Expand Down
52 changes: 52 additions & 0 deletions ext/reflection/php_reflection.c
Original file line number Diff line number Diff line change
Expand Up @@ -7370,6 +7370,58 @@ ZEND_METHOD(ReflectionAttribute, getName)
}
/* }}} */

/* Returns whether this attribute name comes from a namespace */
ZEND_METHOD(ReflectionAttribute, inNamespace)
{
reflection_object *intern;
attribute_reference *attr;

ZEND_PARSE_PARAMETERS_NONE();

GET_REFLECTION_OBJECT_PTR(attr);

const zend_string *name = attr->data->name;
const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
RETURN_BOOL(backslash);
}
/* }}} */

/* Returns the name of namespace where this attribute comes from */
ZEND_METHOD(ReflectionAttribute, getNamespaceName)
{
reflection_object *intern;
attribute_reference *attr;

ZEND_PARSE_PARAMETERS_NONE();

GET_REFLECTION_OBJECT_PTR(attr);

const zend_string *name = attr->data->name;
const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
if (backslash) {
RETURN_STRINGL(ZSTR_VAL(name), backslash - ZSTR_VAL(name));
}
RETURN_EMPTY_STRING();
}

/* Returns the short name of the attribute (without namespace part) */
ZEND_METHOD(ReflectionAttribute, getShortName)
{
reflection_object *intern;
attribute_reference *attr;

ZEND_PARSE_PARAMETERS_NONE();

GET_REFLECTION_OBJECT_PTR(attr);

zend_string *name = attr->data->name;
const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
if (backslash) {
RETURN_STRINGL(backslash + 1, ZSTR_LEN(name) - (backslash - ZSTR_VAL(name) + 1));
}
RETURN_STR_COPY(name);
}

/* {{{ Returns the target of the attribute */
ZEND_METHOD(ReflectionAttribute, getTarget)
{
Expand Down
3 changes: 3 additions & 0 deletions ext/reflection/php_reflection.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -849,6 +849,9 @@ class ReflectionAttribute implements Reflector
public string $name;

public function getName(): string {}
public function inNamespace(): bool {}
public function getNamespaceName(): string {}
public function getShortName(): string {}
public function getTarget(): int {}
public function isRepeated(): bool {}
public function getArguments(): array {}
Expand Down
14 changes: 13 additions & 1 deletion ext/reflection/php_reflection_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions ext/reflection/php_reflection_decl.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
--TEST--
ReflectionAttribute name and namespace methods
--FILE--
<?php

namespace {

#[Attribute]
class AttrNotNamespace {}

}

namespace A\B {

#[Attribute]
class AttrNamespace {}

class Foo {
#[\Attr]
public function fn1() {}

#[AttrNamespace]
public function fn2() {}
}

$rm = new \ReflectionMethod(Foo::class, "fn1");
$attribute = $rm->getAttributes()[0];

var_dump($attribute->inNamespace());
var_dump($attribute->getName());
var_dump($attribute->getNamespaceName());
var_dump($attribute->getShortName());

$rm = new \ReflectionMethod(Foo::class, "fn2");
$attribute = $rm->getAttributes()[0];

var_dump($attribute->inNamespace());
var_dump($attribute->getName());
var_dump($attribute->getNamespaceName());
var_dump($attribute->getShortName());
}

?>
--EXPECT--
bool(false)
string(4) "Attr"
string(0) ""
string(4) "Attr"
bool(true)
string(17) "A\B\AttrNamespace"
string(3) "A\B"
string(13) "AttrNamespace"
1 change: 1 addition & 0 deletions ext/snmp/snmp.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ function snmp_get_valueretrieval(): int {}

function snmp_read_mib(string $filename): bool {}

/** @not-serializable */
class SNMP
{
/** @cvalue SNMP_VERSION_1 */
Expand Down
4 changes: 2 additions & 2 deletions ext/snmp/snmp_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 6 additions & 22 deletions ext/snmp/tests/bug72479.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,12 @@ require_once(__DIR__.'/skipif.inc');
<?php
$arr = [1, [1, 2, 3, 4, 5], 3, 4, 5];
$poc = 'a:3:{i:1;N;i:2;O:4:"snmp":1:{s:11:"quick_print";'.serialize($arr).'}i:1;R:7;}';
$out = unserialize($poc);
gc_collect_cycles();
$fakezval = ptr2str(1122334455);
$fakezval .= ptr2str(0);
$fakezval .= "\x00\x00\x00\x00";
$fakezval .= "\x01";
$fakezval .= "\x00";
$fakezval .= "\x00\x00";
for ($i = 0; $i < 5; $i++) {
$v[$i] = $fakezval.$i;
}
var_dump($out[1]);

function ptr2str($ptr)
{
$out = '';
for ($i = 0; $i < 8; $i++) {
$out .= chr($ptr & 0xff);
$ptr >>= 8;
}
return $out;
try {
$out = unserialize($poc);
var_dump($out);
} catch (Exception $e) {
echo $e::class, ": ", $e->getMessage(), PHP_EOL;
}
?>
--EXPECT--
int(1)
Exception: Unserialization of 'SNMP' is not allowed
17 changes: 17 additions & 0 deletions ext/snmp/tests/gh21682.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--TEST--
GH-21682 (SNMP should not be serializable)
--EXTENSIONS--
snmp
--FILE--
<?php
$s = new SNMP(SNMP::VERSION_1, "localhost", "public");
try {
serialize($s);
echo "ERROR: should have thrown\n";
} catch (\Exception $e) {
echo $e::class, ": ", $e->getMessage(), PHP_EOL;
}
$s->close();
?>
--EXPECT--
Exception: Serialization of 'SNMP' is not allowed
2 changes: 1 addition & 1 deletion ext/soap/php_encoding.c
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ static xmlNodePtr master_to_xml_int(encodePtr encode, zval *data, int style, xml
zval *tmp;
zend_string *type_name;

ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(SOAP_GLOBAL(class_map), type_name, tmp) {
ZEND_HASH_FOREACH_STR_KEY_VAL(SOAP_GLOBAL(class_map), type_name, tmp) {
ZVAL_DEREF(tmp);
if (Z_TYPE_P(tmp) == IS_STRING &&
ZSTR_LEN(ce->name) == Z_STRLEN_P(tmp) &&
Expand Down
Loading