mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Fix GH-14402: Add support for serialization in SplPriorityQueue, SplMinHeap and SplMaxHeap (#19447)
This commit is contained in:
committed by
GitHub
parent
4bc060c0f3
commit
e6c07b004b
2
NEWS
2
NEWS
@@ -54,6 +54,8 @@ PHP NEWS
|
||||
(Girgias)
|
||||
. Fixed bug GH-19801 (leaks in var_dump() and debug_zval_dump()).
|
||||
(alexandre-daubois)
|
||||
. Fixed GH-14402 (SplPriorityQueue, SplMinHeap, and SplMaxHeap lost their
|
||||
data on serialize()). (alexandre-daubois)
|
||||
|
||||
- URI:
|
||||
. Fixed bug GH-19780 (InvalidUrlException should check $errors argument).
|
||||
|
||||
@@ -1070,6 +1070,247 @@ PHP_METHOD(SplPriorityQueue, __debugInfo)
|
||||
RETURN_ARR(spl_heap_object_get_debug_info(spl_ce_SplPriorityQueue, Z_OBJ_P(ZEND_THIS)));
|
||||
} /* }}} */
|
||||
|
||||
static void spl_heap_serialize_internal_state(zval *return_value, spl_heap_object *intern, bool is_pqueue)
|
||||
{
|
||||
zval heap_elements;
|
||||
int heap_count = intern->heap->count;
|
||||
|
||||
array_init(return_value);
|
||||
add_assoc_long(return_value, "flags", intern->flags);
|
||||
|
||||
array_init_size(&heap_elements, heap_count);
|
||||
|
||||
if (heap_count == 0) {
|
||||
add_assoc_zval(return_value, "heap_elements", &heap_elements);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int heap_idx = 0; heap_idx < heap_count; ++heap_idx) {
|
||||
if (is_pqueue) {
|
||||
spl_pqueue_elem *elem = spl_heap_elem(intern->heap, heap_idx);
|
||||
zval entry;
|
||||
array_init(&entry);
|
||||
add_assoc_zval_ex(&entry, "data", strlen("data"), &elem->data);
|
||||
Z_TRY_ADDREF(elem->data);
|
||||
add_assoc_zval_ex(&entry, "priority", strlen("priority"), &elem->priority);
|
||||
Z_TRY_ADDREF(elem->priority);
|
||||
zend_hash_next_index_insert(Z_ARRVAL(heap_elements), &entry);
|
||||
} else {
|
||||
zval *elem = spl_heap_elem(intern->heap, heap_idx);
|
||||
zend_hash_next_index_insert(Z_ARRVAL(heap_elements), elem);
|
||||
Z_TRY_ADDREF_P(elem);
|
||||
}
|
||||
}
|
||||
|
||||
add_assoc_zval(return_value, "heap_elements", &heap_elements);
|
||||
}
|
||||
|
||||
static zend_result spl_heap_unserialize_internal_state(HashTable *state_ht, spl_heap_object *intern, zval *this_ptr, bool is_pqueue)
|
||||
{
|
||||
zval *flags_val = zend_hash_str_find(state_ht, "flags", strlen("flags"));
|
||||
if (!flags_val || Z_TYPE_P(flags_val) != IS_LONG) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
zend_long flags_value = Z_LVAL_P(flags_val);
|
||||
|
||||
if (is_pqueue) {
|
||||
flags_value &= SPL_PQUEUE_EXTR_MASK;
|
||||
if (!flags_value) {
|
||||
return FAILURE;
|
||||
}
|
||||
} else if (flags_value != 0) { /* Regular heaps should not have user-visible flags */
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
intern->flags = (int) flags_value;
|
||||
|
||||
zval *heap_elements = zend_hash_str_find(state_ht, "heap_elements", strlen("heap_elements"));
|
||||
if (!heap_elements) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if (Z_TYPE_P(heap_elements) != IS_ARRAY) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(heap_elements), zval *val) {
|
||||
if (is_pqueue) {
|
||||
/* PriorityQueue elements are serialized as arrays with 'data' and 'priority' keys */
|
||||
if (Z_TYPE_P(val) != IS_ARRAY || zend_hash_num_elements(Z_ARRVAL_P(val)) != 2) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
zval *data_val = zend_hash_str_find(Z_ARRVAL_P(val), "data", strlen("data") );
|
||||
zval *priority_val = zend_hash_str_find(Z_ARRVAL_P(val), "priority", strlen("priority"));
|
||||
|
||||
if (!data_val || !priority_val) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
spl_pqueue_elem elem;
|
||||
ZVAL_COPY(&elem.data, data_val);
|
||||
ZVAL_COPY(&elem.priority, priority_val);
|
||||
spl_ptr_heap_insert(intern->heap, &elem, this_ptr);
|
||||
if (EG(exception)) {
|
||||
return FAILURE;
|
||||
}
|
||||
} else {
|
||||
Z_TRY_ADDREF_P(val);
|
||||
spl_ptr_heap_insert(intern->heap, val, this_ptr);
|
||||
if (EG(exception)) {
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
PHP_METHOD(SplPriorityQueue, __serialize)
|
||||
{
|
||||
spl_heap_object *intern = Z_SPLHEAP_P(ZEND_THIS);
|
||||
zval props, state;
|
||||
|
||||
ZEND_PARSE_PARAMETERS_NONE();
|
||||
|
||||
if (UNEXPECTED(spl_heap_consistency_validations(intern, false) != SUCCESS)) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
if (intern->heap->flags & SPL_HEAP_WRITE_LOCKED) {
|
||||
zend_throw_exception(spl_ce_RuntimeException, "Cannot serialize heap while it is being modified.", 0);
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
array_init(return_value);
|
||||
|
||||
ZVAL_ARR(&props, zend_std_get_properties(&intern->std));
|
||||
Z_TRY_ADDREF(props);
|
||||
zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &props);
|
||||
|
||||
spl_heap_serialize_internal_state(&state, intern, true);
|
||||
zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &state);
|
||||
}
|
||||
|
||||
PHP_METHOD(SplPriorityQueue, __unserialize)
|
||||
{
|
||||
HashTable *data;
|
||||
spl_heap_object *intern = Z_SPLHEAP_P(ZEND_THIS);
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(1, 1)
|
||||
Z_PARAM_ARRAY_HT(data)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
if (zend_hash_num_elements(data) != 2) {
|
||||
zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(intern->std.ce->name));
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
zval *props = zend_hash_index_find(data, 0);
|
||||
if (!props || Z_TYPE_P(props) != IS_ARRAY) {
|
||||
zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(intern->std.ce->name));
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
object_properties_load(&intern->std, Z_ARRVAL_P(props));
|
||||
if (EG(exception)) {
|
||||
zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(intern->std.ce->name));
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
zval *state = zend_hash_index_find(data, 1);
|
||||
if (!state || Z_TYPE_P(state) != IS_ARRAY) {
|
||||
zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(intern->std.ce->name));
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
if (spl_heap_unserialize_internal_state(Z_ARRVAL_P(state), intern, ZEND_THIS, true) != SUCCESS) {
|
||||
zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(intern->std.ce->name));
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
if (EG(exception)) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
if (UNEXPECTED(spl_heap_consistency_validations(intern, false) != SUCCESS)) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
}
|
||||
|
||||
PHP_METHOD(SplHeap, __serialize)
|
||||
{
|
||||
spl_heap_object *intern = Z_SPLHEAP_P(ZEND_THIS);
|
||||
zval props, state;
|
||||
|
||||
ZEND_PARSE_PARAMETERS_NONE();
|
||||
|
||||
if (UNEXPECTED(spl_heap_consistency_validations(intern, false) != SUCCESS)) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
if (intern->heap->flags & SPL_HEAP_WRITE_LOCKED) {
|
||||
zend_throw_exception(spl_ce_RuntimeException, "Cannot serialize heap while it is being modified.", 0);
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
array_init(return_value);
|
||||
|
||||
ZVAL_ARR(&props, zend_std_get_properties(&intern->std));
|
||||
Z_TRY_ADDREF(props);
|
||||
zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &props);
|
||||
|
||||
spl_heap_serialize_internal_state(&state, intern, false);
|
||||
zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &state);
|
||||
}
|
||||
|
||||
PHP_METHOD(SplHeap, __unserialize)
|
||||
{
|
||||
HashTable *data;
|
||||
spl_heap_object *intern = Z_SPLHEAP_P(ZEND_THIS);
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(1, 1)
|
||||
Z_PARAM_ARRAY_HT(data)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
if (zend_hash_num_elements(data) != 2) {
|
||||
zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(intern->std.ce->name));
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
zval *props = zend_hash_index_find(data, 0);
|
||||
if (!props || Z_TYPE_P(props) != IS_ARRAY) {
|
||||
zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(intern->std.ce->name));
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
object_properties_load(&intern->std, Z_ARRVAL_P(props));
|
||||
if (EG(exception)) {
|
||||
zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(intern->std.ce->name));
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
zval *state = zend_hash_index_find(data, 1);
|
||||
if (!state || Z_TYPE_P(state) != IS_ARRAY) {
|
||||
zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(intern->std.ce->name));
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
if (spl_heap_unserialize_internal_state(Z_ARRVAL_P(state), intern, ZEND_THIS, false) != SUCCESS) {
|
||||
zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(intern->std.ce->name));
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
if (EG(exception)) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
if (UNEXPECTED(spl_heap_consistency_validations(intern, false) != SUCCESS)) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
}
|
||||
|
||||
/* iterator handler table */
|
||||
static const zend_object_iterator_funcs spl_heap_it_funcs = {
|
||||
spl_heap_it_dtor,
|
||||
|
||||
@@ -82,6 +82,12 @@ class SplPriorityQueue implements Iterator, Countable
|
||||
|
||||
/** @tentative-return-type */
|
||||
public function __debugInfo(): array {}
|
||||
|
||||
/** @tentative-return-type */
|
||||
public function __serialize(): array {}
|
||||
|
||||
/** @tentative-return-type */
|
||||
public function __unserialize(array $data): void {}
|
||||
}
|
||||
|
||||
abstract class SplHeap implements Iterator, Countable
|
||||
@@ -127,6 +133,12 @@ abstract class SplHeap implements Iterator, Countable
|
||||
|
||||
/** @tentative-return-type */
|
||||
public function __debugInfo(): array {}
|
||||
|
||||
/** @tentative-return-type */
|
||||
public function __serialize(): array {}
|
||||
|
||||
/** @tentative-return-type */
|
||||
public function __unserialize(array $data): void {}
|
||||
}
|
||||
|
||||
class SplMinHeap extends SplHeap
|
||||
|
||||
20
ext/spl/spl_heap_arginfo.h
generated
20
ext/spl/spl_heap_arginfo.h
generated
@@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 47273e114c9c7089bf708a2f18f2e9e522abceb6 */
|
||||
* Stub hash: 3256398ed9e798f141fd3cb73370c0d8b2dbd0f1 */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_SplPriorityQueue_compare, 0, 2, IS_LONG, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, priority1, IS_MIXED, 0)
|
||||
@@ -47,6 +47,12 @@ ZEND_END_ARG_INFO()
|
||||
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_SplPriorityQueue___debugInfo, 0, 0, IS_ARRAY, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_class_SplPriorityQueue___serialize arginfo_class_SplPriorityQueue___debugInfo
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_SplPriorityQueue___unserialize, 0, 1, IS_VOID, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_class_SplHeap_extract arginfo_class_SplPriorityQueue_top
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_SplHeap_insert, 0, 1, IS_TRUE, 0)
|
||||
@@ -80,6 +86,10 @@ ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_class_SplHeap___debugInfo arginfo_class_SplPriorityQueue___debugInfo
|
||||
|
||||
#define arginfo_class_SplHeap___serialize arginfo_class_SplPriorityQueue___debugInfo
|
||||
|
||||
#define arginfo_class_SplHeap___unserialize arginfo_class_SplPriorityQueue___unserialize
|
||||
|
||||
#define arginfo_class_SplMinHeap_compare arginfo_class_SplHeap_compare
|
||||
|
||||
#define arginfo_class_SplMaxHeap_compare arginfo_class_SplHeap_compare
|
||||
@@ -100,11 +110,15 @@ ZEND_METHOD(SplHeap, recoverFromCorruption);
|
||||
ZEND_METHOD(SplHeap, isCorrupted);
|
||||
ZEND_METHOD(SplPriorityQueue, getExtractFlags);
|
||||
ZEND_METHOD(SplPriorityQueue, __debugInfo);
|
||||
ZEND_METHOD(SplPriorityQueue, __serialize);
|
||||
ZEND_METHOD(SplPriorityQueue, __unserialize);
|
||||
ZEND_METHOD(SplHeap, extract);
|
||||
ZEND_METHOD(SplHeap, insert);
|
||||
ZEND_METHOD(SplHeap, top);
|
||||
ZEND_METHOD(SplHeap, current);
|
||||
ZEND_METHOD(SplHeap, __debugInfo);
|
||||
ZEND_METHOD(SplHeap, __serialize);
|
||||
ZEND_METHOD(SplHeap, __unserialize);
|
||||
ZEND_METHOD(SplMinHeap, compare);
|
||||
ZEND_METHOD(SplMaxHeap, compare);
|
||||
|
||||
@@ -125,6 +139,8 @@ static const zend_function_entry class_SplPriorityQueue_methods[] = {
|
||||
ZEND_RAW_FENTRY("isCorrupted", zim_SplHeap_isCorrupted, arginfo_class_SplPriorityQueue_isCorrupted, ZEND_ACC_PUBLIC, NULL, NULL)
|
||||
ZEND_ME(SplPriorityQueue, getExtractFlags, arginfo_class_SplPriorityQueue_getExtractFlags, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(SplPriorityQueue, __debugInfo, arginfo_class_SplPriorityQueue___debugInfo, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(SplPriorityQueue, __serialize, arginfo_class_SplPriorityQueue___serialize, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(SplPriorityQueue, __unserialize, arginfo_class_SplPriorityQueue___unserialize, ZEND_ACC_PUBLIC)
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
||||
@@ -143,6 +159,8 @@ static const zend_function_entry class_SplHeap_methods[] = {
|
||||
ZEND_RAW_FENTRY("compare", NULL, arginfo_class_SplHeap_compare, ZEND_ACC_PROTECTED|ZEND_ACC_ABSTRACT, NULL, NULL)
|
||||
ZEND_ME(SplHeap, isCorrupted, arginfo_class_SplHeap_isCorrupted, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(SplHeap, __debugInfo, arginfo_class_SplHeap___debugInfo, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(SplHeap, __serialize, arginfo_class_SplHeap___serialize, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(SplHeap, __unserialize, arginfo_class_SplHeap___unserialize, ZEND_ACC_PUBLIC)
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
||||
|
||||
67
ext/spl/tests/SplHeap_serialize_corrupted.phpt
Normal file
67
ext/spl/tests/SplHeap_serialize_corrupted.phpt
Normal file
@@ -0,0 +1,67 @@
|
||||
--TEST--
|
||||
SplHeap and SplPriorityQueue serialization fails when corrupted
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class ThrowingHeap extends SplMaxHeap {
|
||||
public function compare($a, $b): int {
|
||||
if ($a === 'throw' || $b === 'throw') {
|
||||
throw new Exception('Comparison failed');
|
||||
}
|
||||
return parent::compare($a, $b);
|
||||
}
|
||||
}
|
||||
|
||||
$heap = new ThrowingHeap();
|
||||
$heap->insert(1);
|
||||
$heap->insert(2);
|
||||
|
||||
try {
|
||||
$heap->insert('throw');
|
||||
} catch (Exception $e) {
|
||||
// no-op, heap should now be corrupted
|
||||
}
|
||||
|
||||
echo "Heap is corrupted: " . ($heap->isCorrupted() ? 'YES' : 'NO') . "\n";
|
||||
|
||||
try {
|
||||
serialize($heap);
|
||||
echo "FAIL: Serialization should have thrown\n";
|
||||
} catch (Exception $e) {
|
||||
echo "Serialization failed: " . $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
class ThrowingPQ extends SplPriorityQueue {
|
||||
public function compare($priority1, $priority2): int {
|
||||
if ($priority1 === 'throw' || $priority2 === 'throw') {
|
||||
throw new Exception('Priority comparison failed');
|
||||
}
|
||||
return parent::compare($priority1, $priority2);
|
||||
}
|
||||
}
|
||||
|
||||
$pq = new ThrowingPQ();
|
||||
$pq->insert('data1', 1);
|
||||
$pq->insert('data2', 2);
|
||||
|
||||
try {
|
||||
$pq->insert('data3', 'throw');
|
||||
} catch (Exception $e) {
|
||||
// no-op, queue is corrupted
|
||||
}
|
||||
|
||||
echo "PriorityQueue is corrupted: " . ($pq->isCorrupted() ? 'YES' : 'NO') . "\n";
|
||||
|
||||
try {
|
||||
serialize($pq);
|
||||
echo "FAIL: PQ Serialization should have thrown\n";
|
||||
} catch (Exception $e) {
|
||||
echo "PQ Serialization failed: " . $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Heap is corrupted: YES
|
||||
Serialization failed: Heap is corrupted, heap properties are no longer ensured.
|
||||
PriorityQueue is corrupted: YES
|
||||
PQ Serialization failed: Heap is corrupted, heap properties are no longer ensured.
|
||||
84
ext/spl/tests/SplHeap_serialize_error_handling.phpt
Normal file
84
ext/spl/tests/SplHeap_serialize_error_handling.phpt
Normal file
@@ -0,0 +1,84 @@
|
||||
--TEST--
|
||||
SplHeap and SplPriorityQueue unserialization error handling
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
// Test malformed data cases
|
||||
$invalid_cases = [
|
||||
// Wrong array count
|
||||
[],
|
||||
[[], [], []],
|
||||
|
||||
// Invalid properties type
|
||||
['not_array', []],
|
||||
[123, []],
|
||||
|
||||
// Invalid state type
|
||||
[[], 'not_array'],
|
||||
[[], 123],
|
||||
|
||||
// Missing flags
|
||||
[[], []],
|
||||
|
||||
// Invalid flags type
|
||||
[[], ['flags' => 'not_int']],
|
||||
|
||||
// Missing heap_elements
|
||||
[[], ['flags' => 0]],
|
||||
|
||||
// Invalid heap_elements type
|
||||
[[], ['flags' => 0, 'heap_elements' => 'not_array']],
|
||||
[[], ['flags' => 0, 'heap_elements' => 123]],
|
||||
];
|
||||
|
||||
foreach ($invalid_cases as $i => $case) {
|
||||
try {
|
||||
$heap = new SplMaxHeap();
|
||||
$heap->__unserialize($case);
|
||||
echo "Case $i: UNEXPECTED SUCCESS\n";
|
||||
} catch (Exception $e) {
|
||||
echo "Case $i: " . $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
$pq_invalid_cases = [
|
||||
// Invalid flags for PQ
|
||||
[[], ['flags' => 0]],
|
||||
|
||||
// Invalid element structure
|
||||
[[], ['flags' => 1, 'heap_elements' => ['not_array']]],
|
||||
|
||||
// Missing data/priority keys
|
||||
[[], ['flags' => 1, 'heap_elements' => [['data' => 'test']]]],
|
||||
[[], ['flags' => 1, 'heap_elements' => [['priority' => 1]]]],
|
||||
[[], ['flags' => 1, 'heap_elements' => [[]]]],
|
||||
];
|
||||
|
||||
foreach ($pq_invalid_cases as $i => $case) {
|
||||
try {
|
||||
$pq = new SplPriorityQueue();
|
||||
$pq->__unserialize($case);
|
||||
echo "PQ Case $i: UNEXPECTED SUCCESS\n";
|
||||
} catch (Exception $e) {
|
||||
echo "PQ Case $i: " . $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Case 0: Invalid serialization data for SplMaxHeap object
|
||||
Case 1: Invalid serialization data for SplMaxHeap object
|
||||
Case 2: Invalid serialization data for SplMaxHeap object
|
||||
Case 3: Invalid serialization data for SplMaxHeap object
|
||||
Case 4: Invalid serialization data for SplMaxHeap object
|
||||
Case 5: Invalid serialization data for SplMaxHeap object
|
||||
Case 6: Invalid serialization data for SplMaxHeap object
|
||||
Case 7: Invalid serialization data for SplMaxHeap object
|
||||
Case 8: Invalid serialization data for SplMaxHeap object
|
||||
Case 9: Invalid serialization data for SplMaxHeap object
|
||||
Case 10: Invalid serialization data for SplMaxHeap object
|
||||
PQ Case 0: Invalid serialization data for SplPriorityQueue object
|
||||
PQ Case 1: Invalid serialization data for SplPriorityQueue object
|
||||
PQ Case 2: Invalid serialization data for SplPriorityQueue object
|
||||
PQ Case 3: Invalid serialization data for SplPriorityQueue object
|
||||
PQ Case 4: Invalid serialization data for SplPriorityQueue object
|
||||
131
ext/spl/tests/SplHeap_serialize_format.phpt
Normal file
131
ext/spl/tests/SplHeap_serialize_format.phpt
Normal file
@@ -0,0 +1,131 @@
|
||||
--TEST--
|
||||
SplHeap serialization binary format
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
// Test SplMaxHeap empty
|
||||
$heap = new SplMaxHeap();
|
||||
$s = serialize($heap);
|
||||
echo $s . "\n";
|
||||
var_dump(unserialize($s));
|
||||
|
||||
// Test SplMaxHeap with data
|
||||
$heap = new SplMaxHeap();
|
||||
$heap->insert(100);
|
||||
$heap->insert(50);
|
||||
$heap->insert(200);
|
||||
$s = serialize($heap);
|
||||
echo $s . "\n";
|
||||
$unserialized = unserialize($s);
|
||||
var_dump($unserialized);
|
||||
|
||||
// Test SplMinHeap
|
||||
$min = new SplMinHeap();
|
||||
$min->insert(30);
|
||||
$min->insert(10);
|
||||
$min->insert(20);
|
||||
$s = serialize($min);
|
||||
echo $s . "\n";
|
||||
var_dump(unserialize($s));
|
||||
|
||||
// Test SplPriorityQueue empty
|
||||
$pq = new SplPriorityQueue();
|
||||
$s = serialize($pq);
|
||||
echo $s . "\n";
|
||||
var_dump(unserialize($s));
|
||||
|
||||
// Test SplPriorityQueue with data
|
||||
$pq = new SplPriorityQueue();
|
||||
$pq->insert('low', 1);
|
||||
$pq->insert('high', 10);
|
||||
$pq->insert('medium', 5);
|
||||
$pq->setExtractFlags(SplPriorityQueue::EXTR_BOTH);
|
||||
$s = serialize($pq);
|
||||
echo $s . "\n";
|
||||
var_dump(unserialize($s));
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
O:10:"SplMaxHeap":2:{i:0;a:0:{}i:1;a:2:{s:5:"flags";i:0;s:13:"heap_elements";a:0:{}}}
|
||||
object(SplMaxHeap)#2 (3) {
|
||||
["flags":"SplHeap":private]=>
|
||||
int(0)
|
||||
["isCorrupted":"SplHeap":private]=>
|
||||
bool(false)
|
||||
["heap":"SplHeap":private]=>
|
||||
array(0) {
|
||||
}
|
||||
}
|
||||
O:10:"SplMaxHeap":2:{i:0;a:0:{}i:1;a:2:{s:5:"flags";i:0;s:13:"heap_elements";a:3:{i:0;i:200;i:1;i:50;i:2;i:100;}}}
|
||||
object(SplMaxHeap)#1 (3) {
|
||||
["flags":"SplHeap":private]=>
|
||||
int(0)
|
||||
["isCorrupted":"SplHeap":private]=>
|
||||
bool(false)
|
||||
["heap":"SplHeap":private]=>
|
||||
array(3) {
|
||||
[0]=>
|
||||
int(200)
|
||||
[1]=>
|
||||
int(50)
|
||||
[2]=>
|
||||
int(100)
|
||||
}
|
||||
}
|
||||
O:10:"SplMinHeap":2:{i:0;a:0:{}i:1;a:2:{s:5:"flags";i:0;s:13:"heap_elements";a:3:{i:0;i:10;i:1;i:30;i:2;i:20;}}}
|
||||
object(SplMinHeap)#4 (3) {
|
||||
["flags":"SplHeap":private]=>
|
||||
int(0)
|
||||
["isCorrupted":"SplHeap":private]=>
|
||||
bool(false)
|
||||
["heap":"SplHeap":private]=>
|
||||
array(3) {
|
||||
[0]=>
|
||||
int(10)
|
||||
[1]=>
|
||||
int(30)
|
||||
[2]=>
|
||||
int(20)
|
||||
}
|
||||
}
|
||||
O:16:"SplPriorityQueue":2:{i:0;a:0:{}i:1;a:2:{s:5:"flags";i:1;s:13:"heap_elements";a:0:{}}}
|
||||
object(SplPriorityQueue)#5 (3) {
|
||||
["flags":"SplPriorityQueue":private]=>
|
||||
int(1)
|
||||
["isCorrupted":"SplPriorityQueue":private]=>
|
||||
bool(false)
|
||||
["heap":"SplPriorityQueue":private]=>
|
||||
array(0) {
|
||||
}
|
||||
}
|
||||
O:16:"SplPriorityQueue":2:{i:0;a:0:{}i:1;a:2:{s:5:"flags";i:3;s:13:"heap_elements";a:3:{i:0;a:2:{s:4:"data";s:4:"high";s:8:"priority";i:10;}i:1;a:2:{s:4:"data";s:3:"low";s:8:"priority";i:1;}i:2;a:2:{s:4:"data";s:6:"medium";s:8:"priority";i:5;}}}}
|
||||
object(SplPriorityQueue)#4 (3) {
|
||||
["flags":"SplPriorityQueue":private]=>
|
||||
int(3)
|
||||
["isCorrupted":"SplPriorityQueue":private]=>
|
||||
bool(false)
|
||||
["heap":"SplPriorityQueue":private]=>
|
||||
array(3) {
|
||||
[0]=>
|
||||
array(2) {
|
||||
["data"]=>
|
||||
string(4) "high"
|
||||
["priority"]=>
|
||||
int(10)
|
||||
}
|
||||
[1]=>
|
||||
array(2) {
|
||||
["data"]=>
|
||||
string(3) "low"
|
||||
["priority"]=>
|
||||
int(1)
|
||||
}
|
||||
[2]=>
|
||||
array(2) {
|
||||
["data"]=>
|
||||
string(6) "medium"
|
||||
["priority"]=>
|
||||
int(5)
|
||||
}
|
||||
}
|
||||
}
|
||||
91
ext/spl/tests/SplHeap_serialize_indexed_format.phpt
Normal file
91
ext/spl/tests/SplHeap_serialize_indexed_format.phpt
Normal file
@@ -0,0 +1,91 @@
|
||||
--TEST--
|
||||
SplHeap serialization format - indexed array format prevents conflicts
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$heap = new SplMaxHeap();
|
||||
$heap->insert(100);
|
||||
$heap->insert(50);
|
||||
$heap->insert(200);
|
||||
|
||||
$serialized_data = $heap->__serialize();
|
||||
var_dump($serialized_data);
|
||||
|
||||
$pq = new SplPriorityQueue();
|
||||
$pq->insert('data', 10);
|
||||
$pq->setExtractFlags(SplPriorityQueue::EXTR_DATA);
|
||||
|
||||
$pq_data = $pq->__serialize();
|
||||
var_dump($pq_data);
|
||||
|
||||
class CustomHeap extends SplMaxHeap {
|
||||
public $flags = 'user_property';
|
||||
public $heap_elements = 'user_property';
|
||||
}
|
||||
|
||||
$custom = new CustomHeap();
|
||||
$custom->insert(42);
|
||||
|
||||
$custom_data = $custom->__serialize();
|
||||
var_dump($custom_data);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
array(2) {
|
||||
[0]=>
|
||||
array(0) {
|
||||
}
|
||||
[1]=>
|
||||
array(2) {
|
||||
["flags"]=>
|
||||
int(0)
|
||||
["heap_elements"]=>
|
||||
array(3) {
|
||||
[0]=>
|
||||
int(200)
|
||||
[1]=>
|
||||
int(50)
|
||||
[2]=>
|
||||
int(100)
|
||||
}
|
||||
}
|
||||
}
|
||||
array(2) {
|
||||
[0]=>
|
||||
array(0) {
|
||||
}
|
||||
[1]=>
|
||||
array(2) {
|
||||
["flags"]=>
|
||||
int(1)
|
||||
["heap_elements"]=>
|
||||
array(1) {
|
||||
[0]=>
|
||||
array(2) {
|
||||
["data"]=>
|
||||
string(4) "data"
|
||||
["priority"]=>
|
||||
int(10)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
array(2) {
|
||||
[0]=>
|
||||
array(2) {
|
||||
["flags"]=>
|
||||
UNKNOWN:0
|
||||
["heap_elements"]=>
|
||||
UNKNOWN:0
|
||||
}
|
||||
[1]=>
|
||||
array(2) {
|
||||
["flags"]=>
|
||||
int(0)
|
||||
["heap_elements"]=>
|
||||
array(1) {
|
||||
[0]=>
|
||||
int(42)
|
||||
}
|
||||
}
|
||||
}
|
||||
117
ext/spl/tests/SplHeap_serialize_inheritance_safety.phpt
Normal file
117
ext/spl/tests/SplHeap_serialize_inheritance_safety.phpt
Normal file
@@ -0,0 +1,117 @@
|
||||
--TEST--
|
||||
SplHeap and SplPriorityQueue inheritance safety with conflicting property names
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class CustomHeap extends SplMaxHeap {
|
||||
public $flags = 'user_flags_property';
|
||||
public $heap_elements = 'user_heap_elements_property';
|
||||
public $custom_prop = 'custom_value';
|
||||
protected $protected_prop = 'protected_value';
|
||||
private $private_prop = 'private_value';
|
||||
}
|
||||
|
||||
$heap = new CustomHeap();
|
||||
$heap->flags = 'modified_user_flags';
|
||||
$heap->heap_elements = 'modified_user_elements';
|
||||
$heap->custom_prop = 'modified_custom';
|
||||
|
||||
$heap->insert(100);
|
||||
$heap->insert(50);
|
||||
$heap->insert(200);
|
||||
|
||||
$serialized = serialize($heap);
|
||||
echo $serialized . "\n";
|
||||
$unserialized = unserialize($serialized);
|
||||
var_dump($unserialized);
|
||||
|
||||
class CustomPriorityQueue extends SplPriorityQueue {
|
||||
public $flags = 'user_flags_property';
|
||||
public $heap_elements = 'user_heap_elements_property';
|
||||
public $custom_data = 'custom_data_value';
|
||||
protected $protected_priority = 'protected_priority_value';
|
||||
}
|
||||
|
||||
$pq = new CustomPriorityQueue();
|
||||
$pq->flags = 'modified_user_flags';
|
||||
$pq->heap_elements = 'modified_user_elements';
|
||||
$pq->custom_data = 'modified_custom_data';
|
||||
|
||||
$pq->insert('low_priority', 1);
|
||||
$pq->insert('high_priority', 10);
|
||||
$pq->insert('medium_priority', 5);
|
||||
|
||||
$pq->setExtractFlags(SplPriorityQueue::EXTR_BOTH);
|
||||
|
||||
$serialized_pq = serialize($pq);
|
||||
echo $serialized_pq . "\n";
|
||||
$unserialized_pq = unserialize($serialized_pq);
|
||||
var_dump($unserialized_pq);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
O:10:"CustomHeap":2:{i:0;a:5:{s:5:"flags";s:19:"modified_user_flags";s:13:"heap_elements";s:22:"modified_user_elements";s:11:"custom_prop";s:15:"modified_custom";s:17:"%0*%0protected_prop";s:15:"protected_value";s:24:"%0CustomHeap%0private_prop";s:13:"private_value";}i:1;a:2:{s:5:"flags";i:0;s:13:"heap_elements";a:3:{i:0;i:200;i:1;i:50;i:2;i:100;}}}
|
||||
object(CustomHeap)#2 (8) {
|
||||
["flags"]=>
|
||||
string(19) "modified_user_flags"
|
||||
["heap_elements"]=>
|
||||
string(22) "modified_user_elements"
|
||||
["custom_prop"]=>
|
||||
string(15) "modified_custom"
|
||||
["protected_prop":protected]=>
|
||||
string(15) "protected_value"
|
||||
["private_prop":"CustomHeap":private]=>
|
||||
string(13) "private_value"
|
||||
["flags":"SplHeap":private]=>
|
||||
int(0)
|
||||
["isCorrupted":"SplHeap":private]=>
|
||||
bool(false)
|
||||
["heap":"SplHeap":private]=>
|
||||
array(3) {
|
||||
[0]=>
|
||||
int(200)
|
||||
[1]=>
|
||||
int(50)
|
||||
[2]=>
|
||||
int(100)
|
||||
}
|
||||
}
|
||||
O:19:"CustomPriorityQueue":2:{i:0;a:4:{s:5:"flags";s:19:"modified_user_flags";s:13:"heap_elements";s:22:"modified_user_elements";s:11:"custom_data";s:20:"modified_custom_data";s:21:"%0*%0protected_priority";s:24:"protected_priority_value";}i:1;a:2:{s:5:"flags";i:3;s:13:"heap_elements";a:3:{i:0;a:2:{s:4:"data";s:13:"high_priority";s:8:"priority";i:10;}i:1;a:2:{s:4:"data";s:12:"low_priority";s:8:"priority";i:1;}i:2;a:2:{s:4:"data";s:15:"medium_priority";s:8:"priority";i:5;}}}}
|
||||
object(CustomPriorityQueue)#4 (7) {
|
||||
["flags"]=>
|
||||
string(19) "modified_user_flags"
|
||||
["heap_elements"]=>
|
||||
string(22) "modified_user_elements"
|
||||
["custom_data"]=>
|
||||
string(20) "modified_custom_data"
|
||||
["protected_priority":protected]=>
|
||||
string(24) "protected_priority_value"
|
||||
["flags":"SplPriorityQueue":private]=>
|
||||
int(3)
|
||||
["isCorrupted":"SplPriorityQueue":private]=>
|
||||
bool(false)
|
||||
["heap":"SplPriorityQueue":private]=>
|
||||
array(3) {
|
||||
[0]=>
|
||||
array(2) {
|
||||
["data"]=>
|
||||
string(13) "high_priority"
|
||||
["priority"]=>
|
||||
int(10)
|
||||
}
|
||||
[1]=>
|
||||
array(2) {
|
||||
["data"]=>
|
||||
string(12) "low_priority"
|
||||
["priority"]=>
|
||||
int(1)
|
||||
}
|
||||
[2]=>
|
||||
array(2) {
|
||||
["data"]=>
|
||||
string(15) "medium_priority"
|
||||
["priority"]=>
|
||||
int(5)
|
||||
}
|
||||
}
|
||||
}
|
||||
89
ext/spl/tests/SplMaxHeap_serialize_complex.phpt
Normal file
89
ext/spl/tests/SplMaxHeap_serialize_complex.phpt
Normal file
@@ -0,0 +1,89 @@
|
||||
--TEST--
|
||||
SplMaxHeap serialization with complex data types
|
||||
--FILE--
|
||||
<?php
|
||||
$heap = new SplMaxHeap();
|
||||
$heap->insert(['type' => 'array1', 'value' => 10]);
|
||||
$heap->insert(['type' => 'array2', 'value' => 20]);
|
||||
$heap->insert(['type' => 'array3', 'value' => 5]);
|
||||
|
||||
$serialized = serialize($heap);
|
||||
echo $serialized . "\n";
|
||||
|
||||
$unserialized = unserialize($serialized);
|
||||
var_dump($unserialized);
|
||||
|
||||
class TestObj {
|
||||
public $val;
|
||||
public function __construct($v) { $this->val = $v; }
|
||||
}
|
||||
|
||||
$heap2 = new SplMaxHeap();
|
||||
$heap2->insert(new TestObj(30));
|
||||
$heap2->insert(new TestObj(10));
|
||||
$heap2->insert(new TestObj(20));
|
||||
|
||||
$serialized2 = serialize($heap2);
|
||||
echo $serialized2 . "\n";
|
||||
|
||||
$unserialized2 = unserialize($serialized2);
|
||||
var_dump($unserialized2);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
O:10:"SplMaxHeap":2:{i:0;a:0:{}i:1;a:2:{s:5:"flags";i:0;s:13:"heap_elements";a:3:{i:0;a:2:{s:4:"type";s:6:"array3";s:5:"value";i:5;}i:1;a:2:{s:4:"type";s:6:"array1";s:5:"value";i:10;}i:2;a:2:{s:4:"type";s:6:"array2";s:5:"value";i:20;}}}}
|
||||
object(SplMaxHeap)#2 (3) {
|
||||
["flags":"SplHeap":private]=>
|
||||
int(0)
|
||||
["isCorrupted":"SplHeap":private]=>
|
||||
bool(false)
|
||||
["heap":"SplHeap":private]=>
|
||||
array(3) {
|
||||
[0]=>
|
||||
array(2) {
|
||||
["type"]=>
|
||||
string(6) "array3"
|
||||
["value"]=>
|
||||
int(5)
|
||||
}
|
||||
[1]=>
|
||||
array(2) {
|
||||
["type"]=>
|
||||
string(6) "array1"
|
||||
["value"]=>
|
||||
int(10)
|
||||
}
|
||||
[2]=>
|
||||
array(2) {
|
||||
["type"]=>
|
||||
string(6) "array2"
|
||||
["value"]=>
|
||||
int(20)
|
||||
}
|
||||
}
|
||||
}
|
||||
O:10:"SplMaxHeap":2:{i:0;a:0:{}i:1;a:2:{s:5:"flags";i:0;s:13:"heap_elements";a:3:{i:0;O:7:"TestObj":1:{s:3:"val";i:30;}i:1;O:7:"TestObj":1:{s:3:"val";i:10;}i:2;O:7:"TestObj":1:{s:3:"val";i:20;}}}}
|
||||
object(SplMaxHeap)#7 (3) {
|
||||
["flags":"SplHeap":private]=>
|
||||
int(0)
|
||||
["isCorrupted":"SplHeap":private]=>
|
||||
bool(false)
|
||||
["heap":"SplHeap":private]=>
|
||||
array(3) {
|
||||
[0]=>
|
||||
object(TestObj)#8 (1) {
|
||||
["val"]=>
|
||||
int(30)
|
||||
}
|
||||
[1]=>
|
||||
object(TestObj)#9 (1) {
|
||||
["val"]=>
|
||||
int(10)
|
||||
}
|
||||
[2]=>
|
||||
object(TestObj)#10 (1) {
|
||||
["val"]=>
|
||||
int(20)
|
||||
}
|
||||
}
|
||||
}
|
||||
63
ext/spl/tests/SplMinHeap_serialize_complex.phpt
Normal file
63
ext/spl/tests/SplMinHeap_serialize_complex.phpt
Normal file
@@ -0,0 +1,63 @@
|
||||
--TEST--
|
||||
SplMinHeap serialization with nested arrays
|
||||
--FILE--
|
||||
<?php
|
||||
$heap = new SplMinHeap();
|
||||
$heap->insert(['name' => 'Alice', 'nested' => ['age' => 25, 'city' => 'NYC']]);
|
||||
$heap->insert(['name' => 'Bob', 'nested' => ['age' => 30, 'city' => 'LA']]);
|
||||
$heap->insert(['name' => 'Charlie', 'nested' => ['age' => 35, 'city' => 'SF']]);
|
||||
|
||||
$serialized = serialize($heap);
|
||||
echo $serialized . "\n";
|
||||
|
||||
$unserialized = unserialize($serialized);
|
||||
var_dump($unserialized);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
O:10:"SplMinHeap":2:{i:0;a:0:{}i:1;a:2:{s:5:"flags";i:0;s:13:"heap_elements";a:3:{i:0;a:2:{s:4:"name";s:5:"Alice";s:6:"nested";a:2:{s:3:"age";i:25;s:4:"city";s:3:"NYC";}}i:1;a:2:{s:4:"name";s:3:"Bob";s:6:"nested";a:2:{s:3:"age";i:30;s:4:"city";s:2:"LA";}}i:2;a:2:{s:4:"name";s:7:"Charlie";s:6:"nested";a:2:{s:3:"age";i:35;s:4:"city";s:2:"SF";}}}}}
|
||||
object(SplMinHeap)#2 (3) {
|
||||
["flags":"SplHeap":private]=>
|
||||
int(0)
|
||||
["isCorrupted":"SplHeap":private]=>
|
||||
bool(false)
|
||||
["heap":"SplHeap":private]=>
|
||||
array(3) {
|
||||
[0]=>
|
||||
array(2) {
|
||||
["name"]=>
|
||||
string(5) "Alice"
|
||||
["nested"]=>
|
||||
array(2) {
|
||||
["age"]=>
|
||||
int(25)
|
||||
["city"]=>
|
||||
string(3) "NYC"
|
||||
}
|
||||
}
|
||||
[1]=>
|
||||
array(2) {
|
||||
["name"]=>
|
||||
string(3) "Bob"
|
||||
["nested"]=>
|
||||
array(2) {
|
||||
["age"]=>
|
||||
int(30)
|
||||
["city"]=>
|
||||
string(2) "LA"
|
||||
}
|
||||
}
|
||||
[2]=>
|
||||
array(2) {
|
||||
["name"]=>
|
||||
string(7) "Charlie"
|
||||
["nested"]=>
|
||||
array(2) {
|
||||
["age"]=>
|
||||
int(35)
|
||||
["city"]=>
|
||||
string(2) "SF"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
113
ext/spl/tests/SplPriorityQueue_serialize_complex.phpt
Normal file
113
ext/spl/tests/SplPriorityQueue_serialize_complex.phpt
Normal file
@@ -0,0 +1,113 @@
|
||||
--TEST--
|
||||
SplPriorityQueue serialization with mixed data types and extract flags
|
||||
--FILE--
|
||||
<?php
|
||||
$queue = new SplPriorityQueue();
|
||||
$queue->setExtractFlags(SplPriorityQueue::EXTR_BOTH);
|
||||
|
||||
$array1 = ['name' => 'John', 'hobbies' => ['reading', 'gaming']];
|
||||
$queue->insert($array1, 10);
|
||||
|
||||
class TestClass {
|
||||
public $prop = 'test';
|
||||
}
|
||||
$obj1 = new TestClass();
|
||||
$queue->insert($obj1, 15);
|
||||
|
||||
$queue->insert(3.14159, 12);
|
||||
$queue->insert(true, 20);
|
||||
$queue->insert(null, 3);
|
||||
|
||||
$serialized = serialize($queue);
|
||||
echo $serialized . "\n";
|
||||
|
||||
$unserialized = unserialize($serialized);
|
||||
var_dump($unserialized);
|
||||
|
||||
$queue2 = new SplPriorityQueue();
|
||||
$queue2->setExtractFlags(SplPriorityQueue::EXTR_PRIORITY);
|
||||
$queue2->insert("data", 42);
|
||||
|
||||
$serialized2 = serialize($queue2);
|
||||
echo $serialized2 . "\n";
|
||||
|
||||
$unserialized2 = unserialize($serialized2);
|
||||
var_dump($unserialized2);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
O:16:"SplPriorityQueue":2:{i:0;a:0:{}i:1;a:2:{s:5:"flags";i:3;s:13:"heap_elements";a:5:{i:0;a:2:{s:4:"data";b:1;s:8:"priority";i:20;}i:1;a:2:{s:4:"data";O:9:"TestClass":1:{s:4:"prop";s:4:"test";}s:8:"priority";i:15;}i:2;a:2:{s:4:"data";d:3.14159;s:8:"priority";i:12;}i:3;a:2:{s:4:"data";a:2:{s:4:"name";s:4:"John";s:7:"hobbies";a:2:{i:0;s:7:"reading";i:1;s:6:"gaming";}}s:8:"priority";i:10;}i:4;a:2:{s:4:"data";N;s:8:"priority";i:3;}}}}
|
||||
object(SplPriorityQueue)#3 (3) {
|
||||
["flags":"SplPriorityQueue":private]=>
|
||||
int(3)
|
||||
["isCorrupted":"SplPriorityQueue":private]=>
|
||||
bool(false)
|
||||
["heap":"SplPriorityQueue":private]=>
|
||||
array(5) {
|
||||
[0]=>
|
||||
array(2) {
|
||||
["data"]=>
|
||||
bool(true)
|
||||
["priority"]=>
|
||||
int(20)
|
||||
}
|
||||
[1]=>
|
||||
array(2) {
|
||||
["data"]=>
|
||||
object(TestClass)#4 (1) {
|
||||
["prop"]=>
|
||||
string(4) "test"
|
||||
}
|
||||
["priority"]=>
|
||||
int(15)
|
||||
}
|
||||
[2]=>
|
||||
array(2) {
|
||||
["data"]=>
|
||||
float(3.14159)
|
||||
["priority"]=>
|
||||
int(12)
|
||||
}
|
||||
[3]=>
|
||||
array(2) {
|
||||
["data"]=>
|
||||
array(2) {
|
||||
["name"]=>
|
||||
string(4) "John"
|
||||
["hobbies"]=>
|
||||
array(2) {
|
||||
[0]=>
|
||||
string(7) "reading"
|
||||
[1]=>
|
||||
string(6) "gaming"
|
||||
}
|
||||
}
|
||||
["priority"]=>
|
||||
int(10)
|
||||
}
|
||||
[4]=>
|
||||
array(2) {
|
||||
["data"]=>
|
||||
NULL
|
||||
["priority"]=>
|
||||
int(3)
|
||||
}
|
||||
}
|
||||
}
|
||||
O:16:"SplPriorityQueue":2:{i:0;a:0:{}i:1;a:2:{s:5:"flags";i:2;s:13:"heap_elements";a:1:{i:0;a:2:{s:4:"data";s:4:"data";s:8:"priority";i:42;}}}}
|
||||
object(SplPriorityQueue)#6 (3) {
|
||||
["flags":"SplPriorityQueue":private]=>
|
||||
int(2)
|
||||
["isCorrupted":"SplPriorityQueue":private]=>
|
||||
bool(false)
|
||||
["heap":"SplPriorityQueue":private]=>
|
||||
array(1) {
|
||||
[0]=>
|
||||
array(2) {
|
||||
["data"]=>
|
||||
string(4) "data"
|
||||
["priority"]=>
|
||||
int(42)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
--TEST--
|
||||
SplPriorityQueue unserialization with invalid flags should throw exception
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
try {
|
||||
$data = [
|
||||
[],
|
||||
[
|
||||
'flags' => 4, // invalid flag value (4 & 3 = 0)
|
||||
'heap_elements' => []
|
||||
]
|
||||
];
|
||||
|
||||
$queue = new SplPriorityQueue();
|
||||
$queue->__unserialize($data);
|
||||
echo "Should have thrown exception for invalid flags\n";
|
||||
} catch (Exception $e) {
|
||||
echo "Exception thrown for invalid flags: " . $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
$data = [
|
||||
[],
|
||||
[
|
||||
'flags' => 0,
|
||||
'heap_elements' => []
|
||||
]
|
||||
];
|
||||
|
||||
$queue = new SplPriorityQueue();
|
||||
$queue->__unserialize($data);
|
||||
echo "Should have thrown exception for zero flags\n";
|
||||
} catch (Exception $e) {
|
||||
echo "Exception thrown for zero flags: " . $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
$data = [
|
||||
[],
|
||||
[
|
||||
'flags' => SplPriorityQueue::EXTR_DATA,
|
||||
'heap_elements' => []
|
||||
]
|
||||
];
|
||||
|
||||
$queue = new SplPriorityQueue();
|
||||
$queue->__unserialize($data);
|
||||
echo "Valid flags accepted\n";
|
||||
} catch (Exception $e) {
|
||||
echo "Valid flags rejected: " . $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
$data = [
|
||||
[],
|
||||
[
|
||||
'flags' => 999, // extra bits that should be masked to 3 (EXTR_BOTH)
|
||||
'heap_elements' => []
|
||||
]
|
||||
];
|
||||
|
||||
$queue = new SplPriorityQueue();
|
||||
$queue->__unserialize($data);
|
||||
|
||||
if ($queue->getExtractFlags() === SplPriorityQueue::EXTR_BOTH) {
|
||||
echo "Flags properly masked\n";
|
||||
} else {
|
||||
echo "Flags not properly masked, got: " . $queue->getExtractFlags() . "\n";
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
echo "Flags with extra bits should be masked: " . $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Exception thrown for invalid flags: Invalid serialization data for SplPriorityQueue object
|
||||
Exception thrown for zero flags: Invalid serialization data for SplPriorityQueue object
|
||||
Valid flags accepted
|
||||
Flags properly masked
|
||||
Reference in New Issue
Block a user