/home/lnzliplg/public_html/alt-php81-pecl-igbinary_3.2.15-1.el8.zip
PKj�\O\��^	^	tests/igbinary_071_php8.phptnu�[���--TEST--
igbinary_unserialize with references to typed properties shall skip the references or fail
--SKIPIF--
<?php if (PHP_VERSION_ID < 80000) { echo "skip __serialize/__unserialize error message different in php < 8"; } ?>
--FILE--
<?php

class A {
	public int $a;
	public $b;
}

class B {
	public $a;
	public int $b;
}

class C {
	public int $a;
	public string $b;
}

class D {
    public int $a;
    public float $b;
}

class Z {
	public $a;
	public $b;
}
$a = new A();
$a->a = 1234;
$a->b = &$a->a;
var_dump(bin2hex($s = igbinary_serialize($a)));
var_dump(igbinary_unserialize($s));
echo "Test B\n";
$b = new B();
$b->a = -1234;
$b->b = &$b->a;
var_dump(bin2hex($s = igbinary_serialize($b)));
var_dump(igbinary_unserialize($s));

$z = new Z();
$z->a = null;
$z->b = &$z->a;
$s = igbinary_serialize($z);
try {
    var_dump(igbinary_unserialize(str_replace('Z', 'A', $s)));
} catch (TypeError $e) {
    echo $e->getMessage(), "\n";
}

try {
    var_dump(igbinary_unserialize(str_replace('Z', 'B', $s)));
} catch (TypeError $e) {
    echo $e->getMessage(), "\n";
}
$z = new Z();
$z->a = 1;
$z->b = &$z->a;
$s = igbinary_serialize($z);
try {
    var_dump(igbinary_unserialize(str_replace('Z', 'C', $s)));
} catch (TypeError $e) {
    echo $e->getMessage(), "\n";
}
$z = new Z();
$z->a = 'x';
$z->b = &$z->a;
$s = igbinary_serialize($z);
try {
    var_dump(igbinary_unserialize(str_replace('Z', 'C', $s)));
} catch (TypeError $e) {
    echo $e->getMessage(), "\n";
}
$z = new Z();
$z->a = 1;
$z->b = &$z->a;
$s = igbinary_serialize($z);
try {
    var_dump(igbinary_unserialize(str_replace('Z', 'D', $s)));
} catch (TypeError $e) {
    echo $e->getMessage(), "\n";
}
/*
try {
    var_dump(unserialize('O:1:"D":2:{s:1:"a";i:1;s:1:"b";R:2;}'));
} catch (TypeError $e) {
    echo $e->getMessage(), "\n";
}
 */

?>
--EXPECT--
string(44) "000000021701411402110161250804d2110162250101"
object(A)#2 (2) {
  ["a"]=>
  &int(1234)
  ["b"]=>
  &int(1234)
}
Test B
string(44) "000000021701421402110161250904d2110162250101"
object(B)#3 (2) {
  ["a"]=>
  &int(-1234)
  ["b"]=>
  &int(-1234)
}
Cannot assign null to property A::$a of type int
Cannot assign null to property B::$b of type int
Cannot assign int to property C::$b of type string
Cannot assign string to property C::$a of type int
Reference with value of type int held by property D::$a of type int is not compatible with property D::$b of type floatPKj�\���PPtests/__serialize_001.phptnu�[���--TEST--
__serialize() mechanism (001): Basics
--SKIPIF--
<?php if (PHP_VERSION_ID < 70400) { echo "skip __serialize/__unserialize not supported in php < 7.4 for compatibility with serialize()"; } ?>
--FILE--
<?php

class Test {
    public $prop;
    public $prop2;
    public function __serialize() {
        return ["value" => $this->prop, 42 => $this->prop2];
    }
    public function __unserialize(array $data) {
        $this->prop = $data["value"];
        $this->prop2 = $data[42];
    }
}

$test = new Test;
$test->prop = "foobar";
$test->prop2 = "barfoo";
var_dump(bin2hex($s = igbinary_serialize($test)));
var_dump(igbinary_unserialize($s));

?>
--EXPECT--
string(74) "000000021704546573741402110576616c75651106666f6f626172062a1106626172666f6f"
object(Test)#2 (2) {
  ["prop"]=>
  string(6) "foobar"
  ["prop2"]=>
  string(6) "barfoo"
}
PKj�\H��7yytests/igbinary_087.phptnu�[���--TEST--
Test serializing many values in __sleep
--SKIPIF--
<?php if (!extension_loaded("igbinary")) print "skip"; ?>
--FILE--
<?php
#[AllowDynamicProperties]
class X {
    public function __sleep() {
        $props = array_keys((array)$this);
        echo "Called __sleep props=" . count($props) . "\n";
        return $props;
    }
}
$x = new X();
for ($i = 0; $i < 300; $i++) {
    $x->{"p$i"} = "$i";
}
$ser = igbinary_serialize($x);
$unser = igbinary_unserialize($ser);
echo urlencode($ser), "\n";
var_dump($unser == $x);
unset($unser);
for ($i = 0; $i < 70000; $i++) {
    $x->{"p$i"} = "other$i";
}
var_dump(igbinary_unserialize(igbinary_serialize($x)) == $x);

?>
--EXPECT--
Called __sleep props=300
%00%00%00%02%17%01X%15%01%2C%11%02p0%11%010%11%02p1%11%011%11%02p2%11%012%11%02p3%11%013%11%02p4%11%014%11%02p5%11%015%11%02p6%11%016%11%02p7%11%017%11%02p8%11%018%11%02p9%11%019%11%03p10%11%0210%11%03p11%11%0211%11%03p12%11%0212%11%03p13%11%0213%11%03p14%11%0214%11%03p15%11%0215%11%03p16%11%0216%11%03p17%11%0217%11%03p18%11%0218%11%03p19%11%0219%11%03p20%11%0220%11%03p21%11%0221%11%03p22%11%0222%11%03p23%11%0223%11%03p24%11%0224%11%03p25%11%0225%11%03p26%11%0226%11%03p27%11%0227%11%03p28%11%0228%11%03p29%11%0229%11%03p30%11%0230%11%03p31%11%0231%11%03p32%11%0232%11%03p33%11%0233%11%03p34%11%0234%11%03p35%11%0235%11%03p36%11%0236%11%03p37%11%0237%11%03p38%11%0238%11%03p39%11%0239%11%03p40%11%0240%11%03p41%11%0241%11%03p42%11%0242%11%03p43%11%0243%11%03p44%11%0244%11%03p45%11%0245%11%03p46%11%0246%11%03p47%11%0247%11%03p48%11%0248%11%03p49%11%0249%11%03p50%11%0250%11%03p51%11%0251%11%03p52%11%0252%11%03p53%11%0253%11%03p54%11%0254%11%03p55%11%0255%11%03p56%11%0256%11%03p57%11%0257%11%03p58%11%0258%11%03p59%11%0259%11%03p60%11%0260%11%03p61%11%0261%11%03p62%11%0262%11%03p63%11%0263%11%03p64%11%0264%11%03p65%11%0265%11%03p66%11%0266%11%03p67%11%0267%11%03p68%11%0268%11%03p69%11%0269%11%03p70%11%0270%11%03p71%11%0271%11%03p72%11%0272%11%03p73%11%0273%11%03p74%11%0274%11%03p75%11%0275%11%03p76%11%0276%11%03p77%11%0277%11%03p78%11%0278%11%03p79%11%0279%11%03p80%11%0280%11%03p81%11%0281%11%03p82%11%0282%11%03p83%11%0283%11%03p84%11%0284%11%03p85%11%0285%11%03p86%11%0286%11%03p87%11%0287%11%03p88%11%0288%11%03p89%11%0289%11%03p90%11%0290%11%03p91%11%0291%11%03p92%11%0292%11%03p93%11%0293%11%03p94%11%0294%11%03p95%11%0295%11%03p96%11%0296%11%03p97%11%0297%11%03p98%11%0298%11%03p99%11%0299%11%04p100%11%03100%11%04p101%11%03101%11%04p102%11%03102%11%04p103%11%03103%11%04p104%11%03104%11%04p105%11%03105%11%04p106%11%03106%11%04p107%11%03107%11%04p108%11%03108%11%04p109%11%03109%11%04p110%11%03110%11%04p111%11%03111%11%04p112%11%03112%11%04p113%11%03113%11%04p114%11%03114%11%04p115%11%03115%11%04p116%11%03116%11%04p117%11%03117%11%04p118%11%03118%11%04p119%11%03119%11%04p120%11%03120%11%04p121%11%03121%11%04p122%11%03122%11%04p123%11%03123%11%04p124%11%03124%11%04p125%11%03125%11%04p126%11%03126%11%04p127%11%03127%11%04p128%11%03128%11%04p129%11%03129%11%04p130%11%03130%11%04p131%11%03131%11%04p132%11%03132%11%04p133%11%03133%11%04p134%11%03134%11%04p135%11%03135%11%04p136%11%03136%11%04p137%11%03137%11%04p138%11%03138%11%04p139%11%03139%11%04p140%11%03140%11%04p141%11%03141%11%04p142%11%03142%11%04p143%11%03143%11%04p144%11%03144%11%04p145%11%03145%11%04p146%11%03146%11%04p147%11%03147%11%04p148%11%03148%11%04p149%11%03149%11%04p150%11%03150%11%04p151%11%03151%11%04p152%11%03152%11%04p153%11%03153%11%04p154%11%03154%11%04p155%11%03155%11%04p156%11%03156%11%04p157%11%03157%11%04p158%11%03158%11%04p159%11%03159%11%04p160%11%03160%11%04p161%11%03161%11%04p162%11%03162%11%04p163%11%03163%11%04p164%11%03164%11%04p165%11%03165%11%04p166%11%03166%11%04p167%11%03167%11%04p168%11%03168%11%04p169%11%03169%11%04p170%11%03170%11%04p171%11%03171%11%04p172%11%03172%11%04p173%11%03173%11%04p174%11%03174%11%04p175%11%03175%11%04p176%11%03176%11%04p177%11%03177%11%04p178%11%03178%11%04p179%11%03179%11%04p180%11%03180%11%04p181%11%03181%11%04p182%11%03182%11%04p183%11%03183%11%04p184%11%03184%11%04p185%11%03185%11%04p186%11%03186%11%04p187%11%03187%11%04p188%11%03188%11%04p189%11%03189%11%04p190%11%03190%11%04p191%11%03191%11%04p192%11%03192%11%04p193%11%03193%11%04p194%11%03194%11%04p195%11%03195%11%04p196%11%03196%11%04p197%11%03197%11%04p198%11%03198%11%04p199%11%03199%11%04p200%11%03200%11%04p201%11%03201%11%04p202%11%03202%11%04p203%11%03203%11%04p204%11%03204%11%04p205%11%03205%11%04p206%11%03206%11%04p207%11%03207%11%04p208%11%03208%11%04p209%11%03209%11%04p210%11%03210%11%04p211%11%03211%11%04p212%11%03212%11%04p213%11%03213%11%04p214%11%03214%11%04p215%11%03215%11%04p216%11%03216%11%04p217%11%03217%11%04p218%11%03218%11%04p219%11%03219%11%04p220%11%03220%11%04p221%11%03221%11%04p222%11%03222%11%04p223%11%03223%11%04p224%11%03224%11%04p225%11%03225%11%04p226%11%03226%11%04p227%11%03227%11%04p228%11%03228%11%04p229%11%03229%11%04p230%11%03230%11%04p231%11%03231%11%04p232%11%03232%11%04p233%11%03233%11%04p234%11%03234%11%04p235%11%03235%11%04p236%11%03236%11%04p237%11%03237%11%04p238%11%03238%11%04p239%11%03239%11%04p240%11%03240%11%04p241%11%03241%11%04p242%11%03242%11%04p243%11%03243%11%04p244%11%03244%11%04p245%11%03245%11%04p246%11%03246%11%04p247%11%03247%11%04p248%11%03248%11%04p249%11%03249%11%04p250%11%03250%11%04p251%11%03251%11%04p252%11%03252%11%04p253%11%03253%11%04p254%11%03254%11%04p255%11%03255%11%04p256%11%03256%11%04p257%11%03257%11%04p258%11%03258%11%04p259%11%03259%11%04p260%11%03260%11%04p261%11%03261%11%04p262%11%03262%11%04p263%11%03263%11%04p264%11%03264%11%04p265%11%03265%11%04p266%11%03266%11%04p267%11%03267%11%04p268%11%03268%11%04p269%11%03269%11%04p270%11%03270%11%04p271%11%03271%11%04p272%11%03272%11%04p273%11%03273%11%04p274%11%03274%11%04p275%11%03275%11%04p276%11%03276%11%04p277%11%03277%11%04p278%11%03278%11%04p279%11%03279%11%04p280%11%03280%11%04p281%11%03281%11%04p282%11%03282%11%04p283%11%03283%11%04p284%11%03284%11%04p285%11%03285%11%04p286%11%03286%11%04p287%11%03287%11%04p288%11%03288%11%04p289%11%03289%11%04p290%11%03290%11%04p291%11%03291%11%04p292%11%03292%11%04p293%11%03293%11%04p294%11%03294%11%04p295%11%03295%11%04p296%11%03296%11%04p297%11%03297%11%04p298%11%03298%11%04p299%11%03299
bool(true)
Called __sleep props=70000
bool(true)PKj�\"���tests/igbinary_020.phptnu�[���--TEST--
Object test, incomplete class
--SKIPIF--
--FILE--
<?php
if(!extension_loaded('igbinary')) {
	dl('igbinary.' . PHP_SHLIB_SUFFIX);
}

if (PHP_VERSION_ID >= 80200) {
    // TODO undo workaround when #[AllowDynamicProperties] is added to __PHP_Incomplete_Class
    error_reporting(E_ALL & ~E_DEPRECATED);
}

function test($type, $variable, $test) {
	$serialized = pack('H*', $variable);
	$unserialized = igbinary_unserialize($serialized);

	echo $type, "\n";
	echo substr(bin2hex($serialized), 8), "\n";
	var_dump($unserialized);
//	echo "\n";
}

test('incom', '0000000217034f626a140211016106011101620602', false);

/*
 * you can add regression tests for your extension here
 *
 * the output of your test code has to be equal to the
 * text in the --EXPECT-- section below for the tests
 * to pass, differences between the output and the
 * expected text are interpreted as failure
 *
 * see TESTING.md for further information on
 * writing regression tests
 */
?>
--EXPECTF--
incom
17034f626a140211016106011101620602
object(__PHP_Incomplete_Class)#%d (3) {
  ["__PHP_Incomplete_Class_Name"]=>
  string(3) "Obj"
  ["a"]=>
  int(1)
  ["b"]=>
  int(2)
}
PKj�\6ğ��tests/igbinary_054.phptnu�[���--TEST--
__wakeup can add dynamic properties without affecting other objects
--FILE--
<?php

#[AllowDynamicProperties]
class Obj {
	// Testing $this->a being a dynamic property.

	function __construct($a) {
		$this->a = $a;
	}

	public function __wakeup() {
		echo "Calling __wakeup\n";
		for ($i = 0; $i < 10000; $i++) {
			$this->{'b' . $i} = 42;
		}
	}
}

function main() {
	$array = array("roh");  // array (not a reference, but should be copied on write)
	$a = new Obj($array);
	$b = new Obj($array);
	$c = new Obj(null);
	$variable = array($a, $b, $c);
	$serialized = igbinary_serialize($variable);
	printf("%s\n", bin2hex($serialized));
	$unserialized = igbinary_unserialize($serialized);
	echo "Called igbinary_unserialize\n";
	for ($a = 0; $a < 3; $a++) {
		for ($i = 0; $i < 10000; $i++) {
			if ($unserialized[$a]->{'b' . $i} !== 42) {
				echo "Fail $a b$i\n";
				return;
			}
			unset($unserialized[$a]->{'b' . $i});
		}
	}
	var_dump($unserialized);
}
main();
--EXPECTF--
000000021403060017034f626a1401110161140106001103726f6806011a0014010e01010206021a0014010e0100
Calling __wakeup
Calling __wakeup
Calling __wakeup
Called igbinary_unserialize
array(3) {
  [0]=>
  object(Obj)#%d (1) {
    ["a"]=>
    array(1) {
      [0]=>
      string(3) "roh"
    }
  }
  [1]=>
  object(Obj)#%d (1) {
    ["a"]=>
    array(1) {
      [0]=>
      string(3) "roh"
    }
  }
  [2]=>
  object(Obj)#%d (1) {
    ["a"]=>
    NULL
  }
}
PKj�\��+��
�
tests/__serialize_004.phptnu�[���--TEST--
__serialize() mechanism (004): Delayed __unserialize() calls
--SKIPIF--
<?php if (PHP_VERSION_ID < 70400) { echo "skip __serialize/__unserialize not supported in php < 7.4 for compatibility with serialize()\n"; } ?>
--FILE--
<?php

#[AllowDynamicProperties]
class Wakeup {
    public $data;
    public function __construct(array $data) {
        $this->data = $data;
    }
    public function __wakeup() {
        echo "__wakeup() called\n";
        var_dump($this->data);
        $this->woken_up = true;
    }
}

#[AllowDynamicProperties]
class Unserialize {
    public $data;
    public function __construct(array $data) {
        $this->data = $data;
    }
    public function __serialize() {
        return $this->data;
    }
    public function __unserialize(array $data) {
        $this->data = $data;
        echo "__unserialize() called\n";
        var_dump($this->data);
        $this->unserialized = true;
    }
}

$obj = new Wakeup([new Unserialize([new Wakeup([new Unserialize([])])])]);
var_dump(bin2hex($s = igbinary_serialize($obj)));
var_dump(igbinary_unserialize($s));

?>
--EXPECT--
string(110) "00000002170657616b657570140111046461746114010600170b556e73657269616c697a65140106001a0014010e01140106001a021400"
__unserialize() called
array(0) {
}
__wakeup() called
array(1) {
  [0]=>
  object(Unserialize)#8 (2) {
    ["data"]=>
    array(0) {
    }
    ["unserialized"]=>
    bool(true)
  }
}
__unserialize() called
array(1) {
  [0]=>
  object(Wakeup)#7 (2) {
    ["data"]=>
    array(1) {
      [0]=>
      object(Unserialize)#8 (2) {
        ["data"]=>
        array(0) {
        }
        ["unserialized"]=>
        bool(true)
      }
    }
    ["woken_up"]=>
    bool(true)
  }
}
__wakeup() called
array(1) {
  [0]=>
  object(Unserialize)#6 (2) {
    ["data"]=>
    array(1) {
      [0]=>
      object(Wakeup)#7 (2) {
        ["data"]=>
        array(1) {
          [0]=>
          object(Unserialize)#8 (2) {
            ["data"]=>
            array(0) {
            }
            ["unserialized"]=>
            bool(true)
          }
        }
        ["woken_up"]=>
        bool(true)
      }
    }
    ["unserialized"]=>
    bool(true)
  }
}
object(Wakeup)#5 (2) {
  ["data"]=>
  array(1) {
    [0]=>
    object(Unserialize)#6 (2) {
      ["data"]=>
      array(1) {
        [0]=>
        object(Wakeup)#7 (2) {
          ["data"]=>
          array(1) {
            [0]=>
            object(Unserialize)#8 (2) {
              ["data"]=>
              array(0) {
              }
              ["unserialized"]=>
              bool(true)
            }
          }
          ["woken_up"]=>
          bool(true)
        }
      }
      ["unserialized"]=>
      bool(true)
    }
  }
  ["woken_up"]=>
  bool(true)
}
PKj�\��z��tests/__serialize_009.phptnu�[���--TEST--
__serialize() mechanism (009): Object/reference ids should be the same whether or not __serialize is used.
--SKIPIF--
<?php if (PHP_VERSION_ID < 70400) { echo "skip __serialize/__unserialize not supported in php < 7.4 for compatibility with serialize()"; } ?>
--FILE--
<?php
class Vest {
    public $value;
    public function __construct($value) {
        $this->value = $value;
    }
}

class Test {
    public $prop;
    public function __construct($value) {
        $this->prop = $value;
    }
    public function __serialize() {
        return ["value" => $this->prop];
    }
    public function __unserialize(array $data) {
        $this->prop = $data["value"];
    }
}
$vest = new Vest('first');
$vest2 = new Vest(null);
$vest3 = new Vest($vest2);
$sv = igbinary_serialize([$vest, $vest2, $vest3, $vest, $vest2]);

$test = new Test('first');
$test2 = new Test(null);
$test3 = new Test($test2);
$s = igbinary_serialize([$test, $test2, $test3, $test, $test2]);
// The only difference in the serialization should be the first byte of the only occurrence of the class name.
var_dump(bin2hex($sv));
var_dump(bin2hex($s));
var_dump(igbinary_unserialize($s));
var_dump(igbinary_unserialize($sv));

?>
--EXPECT--
string(114) "00000002140506001704566573741401110576616c75651105666972737406011a0014010e010006021a0014010e0122020603220106042202"
string(114) "00000002140506001704546573741401110576616c75651105666972737406011a0014010e010006021a0014010e0122020603220106042202"
array(5) {
  [0]=>
  object(Test)#7 (1) {
    ["prop"]=>
    string(5) "first"
  }
  [1]=>
  object(Test)#8 (1) {
    ["prop"]=>
    NULL
  }
  [2]=>
  object(Test)#9 (1) {
    ["prop"]=>
    object(Test)#8 (1) {
      ["prop"]=>
      NULL
    }
  }
  [3]=>
  object(Test)#7 (1) {
    ["prop"]=>
    string(5) "first"
  }
  [4]=>
  object(Test)#8 (1) {
    ["prop"]=>
    NULL
  }
}
array(5) {
  [0]=>
  object(Vest)#8 (1) {
    ["value"]=>
    string(5) "first"
  }
  [1]=>
  object(Vest)#7 (1) {
    ["value"]=>
    NULL
  }
  [2]=>
  object(Vest)#9 (1) {
    ["value"]=>
    object(Vest)#7 (1) {
      ["value"]=>
      NULL
    }
  }
  [3]=>
  object(Vest)#8 (1) {
    ["value"]=>
    string(5) "first"
  }
  [4]=>
  object(Vest)#7 (1) {
    ["value"]=>
    NULL
  }
}
PKj�\�e
v��tests/igbinary_092.phptnu�[���--TEST--
Object test, unserialize_callback_func
--INI--
error_reporting=E_ALL
--FILE--
<?php
if(!extension_loaded('igbinary')) {
	dl('igbinary.' . PHP_SHLIB_SUFFIX);
}

function test($type, $variable, $test) {
    try {
        $serialized = pack('H*', $variable);
        $unserialized = igbinary_unserialize($serialized);

        echo $type, "\n";
        echo substr(bin2hex($serialized), 8), "\n";
        echo $test || $unserialized->b == 2 ? 'OK' : 'ERROR';
        echo "\n";
    } catch (Throwable $e) {
        printf("Caught %s: %s\n", get_class($e), $e->getMessage());
    }
}

class MyUnserializer {
    public static function handleUnserialize(string $class) {
        throw new RuntimeException('handleUnserialize: Class not found: ' . $class);
    }
}

ini_set('unserialize_callback_func', strtoupper('MyUnserializer::handleUnserialize'));
test('throwing_autoload', '0000000217034f626a140211016106011101620602', false);
?>
--EXPECTF--
Caught RuntimeException: handleUnserialize: Class not found: Obj
PKj�\��//tests/igbinary_051.phptnu�[���--TEST--
Object test, __wakeup (With multiple references)
--SKIPIF--
--FILE--
<?php
if(!extension_loaded('igbinary')) {
	dl('igbinary.' . PHP_SHLIB_SUFFIX);
}

class Obj {
	var $a;
	var $b;

	function __construct($a, $b) {
		$this->a = $a;
		$this->b = $b;
	}

	function __wakeup() {
		$this->b = $this->a * 3;
	}
}

function main() {
	$o = new Obj(1, 2);
	$variable = array(&$o, &$o);
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);

	echo substr(bin2hex($serialized), 8), "\n";
	echo $unserialized[0]->b === 3 && $unserialized[0]->a === 1 ? 'OK' : 'ERROR';
	echo "\n";
	$unserialized[0] = 'a';
	var_dump($unserialized);
}

main();
--EXPECT--
140206002517034f626a1402110161060111016206020601252201
OK
array(2) {
  [0]=>
  &string(1) "a"
  [1]=>
  &string(1) "a"
}
PKj�\Z�tests/igbinary_027.phptnu�[���--TEST--
Check for serialization handler
--SKIPIF--
<?php
if (!extension_loaded('session')) {
	exit('skip session extension not loaded');
}

ob_start();
phpinfo(INFO_MODULES);
$str = ob_get_clean();

$array = explode("\n", $str);
$array = preg_grep('/^igbinary session support.*yes/', $array);
if (!$array) {
	exit('skip igbinary session handler not available');
}


--FILE--
<?php

$output = '';

function open($path, $name) {
	return true;
}

function close() {
	return true;
}

function read($id) {
	global $output;
	$output .= "read\n";
	return pack('H*', '0000000214011103666f6f0601');
}

function write($id, $data) {
	global $output;
	$output .= "wrote: ";
	$output .= substr(bin2hex($data), 8). "\n";
	return true;
}

function destroy($id) {
	return true;
}

function gc($time) {
	return true;
}

class Foo {
}

class Bar {
}

ini_set('session.serialize_handler', 'igbinary');

session_set_save_handler('open', 'close', 'read', 'write', 'destroy', 'gc');


$db_object = new Foo();
$session_object = new Bar();

$v = session_start();
var_dump($v);
$_SESSION['test'] = "foobar";

session_write_close();

echo $output;

/*
 * you can add regression tests for your extension here
 *
 * the output of your test code has to be equal to the
 * text in the --EXPECT-- section below for the tests
 * to pass, differences between the output and the
 * expected text are interpreted as failure
 *
 * see TESTING.md for further information on
 * writing regression tests
 */
?>
--EXPECT--
bool(true)
read
wrote: 14021103666f6f06011104746573741106666f6f626172
PKj�\�H��VVtests/igbinary_084.phptnu�[���--TEST--
Properly free duplicate properties when unserializing invalid data
--FILE--
<?php
class Test {
    public $pub;
    public function __sleep() {
        // TODO: Could start detecting duplicates and emitting a notice as well
        return ["pub", "pub"];
    }
}
$t = new Test();
$t->pub = new Test();
$s = igbinary_serialize($t);
echo urlencode($s), "\n";
$unser = igbinary_unserialize($s);
var_dump($unser);
?>
--EXPECT--
%00%00%00%02%17%04Test%14%02%11%03pub%1A%00%14%02%0E%01%00%0E%01%00%0E%01%22%01
object(Test)#3 (1) {
  ["pub"]=>
  object(Test)#4 (1) {
    ["pub"]=>
    NULL
  }
}
PKj�\����tests/igbinary_003.phptnu�[���--TEST--
Check for bool serialisation
--INI--
; Note that php 8.1 deprecates using Serializable without __serialize/__unserialize but we are testing Serialize for igbinary. Suppress deprecations.
error_reporting=E_ALL & ~E_DEPRECATED
--FILE--
<?php
if(!extension_loaded('igbinary')) {
	dl('igbinary.' . PHP_SHLIB_SUFFIX);
}

function test($type, $variable) {
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);

	echo $type, "\n";
	echo substr(bin2hex($serialized), 8), "\n";
	echo $unserialized === $variable ? 'OK' : 'ERROR';
	echo "\n";
}

test('bool true',  true);
test('bool false', false);

/*
 * you can add regression tests for your extension here
 *
 * the output of your test code has to be equal to the
 * text in the --EXPECT-- section below for the tests
 * to pass, differences between the output and the
 * expected text are interpreted as failure
 *
 * see TESTING.md for further information on
 * writing regression tests
 */
?>
--EXPECT--
bool true
05
OK
bool false
04
OK
PKj�\E�A`��tests/igbinary_045c.phptnu�[���--TEST--
APCu serializer registration - more data types
--INI--
apc.enable_cli=1
apc.serializer=igbinary
--SKIPIF--
<?php
if (!extension_loaded('apcu')) {
	echo "skip APCu not loaded";
	return;
}

$ext = new ReflectionExtension('apcu');
if (version_compare($ext->getVersion(), '5.1.6') < 0) {
	echo "skip require APCu version 5.1.6 or above";
	return;
}
?>
--FILE--
<?php
echo ini_get('apc.serializer'), "\n";

class Bar {
	public $foo;
}

$a = new Bar;
$a->foo = $a;
apcu_store('objloop', $a);
unset($a);

var_dump(apcu_fetch('objloop'));

apcu_store('nullval', null);
var_dump(apcu_fetch('nullval'));

apcu_store('intval', 777);
var_dump(apcu_fetch('intval'));

$o = new stdClass();
$o->prop = 5;
$a = [$o, $o];
apcu_store('simplearrayval', $a);
$unserialized = apcu_fetch('simplearrayval');
var_dump($unserialized);
if ($unserialized[0] === $unserialized[1]) {
	echo "SAME\n";
} else {
	echo "DIFFERENT\n";
	printf("%s\n", bin2hex(igbinary_serialize($a)));
}
unset($o);
unset($a);
unset($unserialized);

$o = new stdClass();
$o->prop = 6;
$a = [&$o, &$o];
apcu_store('refarrayval', $a);
$unserialized = apcu_fetch('refarrayval');
var_dump($unserialized);
if ($unserialized[0] === $unserialized[1]) {
	echo "SAME\n";
} else {
	echo "DIFFERENT\n";
	printf("%s\n", bin2hex(igbinary_serialize($a)));
}
?>
--EXPECTF--
igbinary
object(Bar)#%d (1) {
  ["foo"]=>
  *RECURSION*
}
NULL
int(777)
array(2) {
  [0]=>
  object(stdClass)#%d (1) {
    ["prop"]=>
    int(5)
  }
  [1]=>
  object(stdClass)#%d (1) {
    ["prop"]=>
    int(5)
  }
}
SAME
array(2) {
  [0]=>
  &object(stdClass)#%d (1) {
    ["prop"]=>
    int(6)
  }
  [1]=>
  &object(stdClass)#%d (1) {
    ["prop"]=>
    int(6)
  }
}
SAME
PKj�\`��Oootests/igbinary_040.phptnu�[���--TEST--
b0rked random data test
--SKIPIF--
--FILE--
<?php

if(!extension_loaded('igbinary')) {
	dl('igbinary.' . PHP_SHLIB_SUFFIX);
}

function test() {
	$serialized = igbinary_serialize(null);
	$serialized = substr($serialized, 0, -1);

	$length = mt_rand(1, 255);
	for ($i = 0; $i < $length; ++$i) {
		$serialized .= chr(mt_rand(0, 255));
	}

	// if returned null everything is OK
	if (($unserialized = igbinary_unserialize($serialized)) === null) {
		return true;
	}

	error_reporting(E_ALL);
	// whole data is read?
	$reserialized = igbinary_serialize($unserialized);
	if ($serialized === $reserialized) {
		return true;
	}
	if (is_string($reserialized) && strlen($reserialized) < strlen($serialized) && strncmp($reserialized, $serialized, 0) === 0) {
		return true;
	}

	// igbinary should not unserialize an object for invalid data - if it does, print the unexpected value.
	echo bin2hex($serialized), "\n";
	echo bin2hex($reserialized), "\n";
	var_dump($unserialized);

	return false;
}

// Test that 100 deterministic random values don't unserialize as valid data
mt_srand(0xface);
for ($i = 0; $i < 100; ++$i) {
	error_reporting(E_ERROR | E_PARSE);
	if (!test()) break;
}
// Test that igbinary_unserialize warns if extra data is added and fails (suppressed in the above checks)
error_reporting(E_ALL);
echo "After testing 100 random values\n";
$result = igbinary_unserialize(igbinary_serialize(true) . "\x00");
// Should deliberately return null if extra data was seen
var_dump($result);
?>
--EXPECTF--
After testing 100 random values

Warning: igbinary_unserialize: received more data to unserialize than expected in %s on line 48
NULL
PKj�\¡�V	V	tests/igbinary_095.phptnu�[���--TEST--
Test handling php 8.1 readonly properties
--SKIPIF--
<?php if (PHP_VERSION_ID < 80100) { echo "skip readonly properties require php 8.1+\n"; } ?>
--FILE--
<?php
class X {
    public readonly mixed $var;

    public function __construct(
        public readonly int $a,
        private readonly ArrayAccess&Countable $intersection,
        protected readonly ?string $default = null,
    ) {
        $this->var = $intersection;
    }
}

class Y {
    public readonly mixed $var;

    public function __construct(
        public readonly int $a,
        private readonly ArrayAccess&Countable $intersection,
        protected readonly ?string $default = null,
    ) {
        $this->var = $intersection;
    }

    public function __serialize(): array {
        return [
            'a' => $this->a,
            'intersection' => $this->intersection,
            'default' => $this->default,
            'var' => $this->var,
        ];
    }
    public function __unserialize(array $data) {
        [
            'a' => $this->a,
            'intersection' => $this->intersection,
            'default' => $this->default,
            'var' => $this->var,
        ] = $data;
    }
}

$ser = igbinary_serialize(new X(1, new ArrayObject()));
echo urlencode($ser), "\n";
var_dump(igbinary_unserialize($ser));
$ser = igbinary_serialize(new Y(1, new ArrayObject()));
echo urlencode($ser), "\n";
var_dump(igbinary_unserialize($ser));
?>
--EXPECT--
%00%00%00%02%17%01X%14%04%11%03var%17%0BArrayObject%14%04%06%00%06%00%06%01%14%00%06%02%14%00%06%03%00%11%01a%06%01%11%0F%00X%00intersection%22%01%11%0A%00%2A%00default%00
object(X)#1 (4) {
  ["var"]=>
  object(ArrayObject)#2 (1) {
    ["storage":"ArrayObject":private]=>
    array(0) {
    }
  }
  ["a"]=>
  int(1)
  ["intersection":"X":private]=>
  object(ArrayObject)#2 (1) {
    ["storage":"ArrayObject":private]=>
    array(0) {
    }
  }
  ["default":protected]=>
  NULL
}
%00%00%00%02%17%01Y%14%04%11%01a%06%01%11%0Cintersection%17%0BArrayObject%14%04%06%00%06%00%06%01%14%00%06%02%14%00%06%03%00%11%07default%00%11%03var%22%01
object(Y)#1 (4) {
  ["var"]=>
  object(ArrayObject)#2 (1) {
    ["storage":"ArrayObject":private]=>
    array(0) {
    }
  }
  ["a"]=>
  int(1)
  ["intersection":"Y":private]=>
  object(ArrayObject)#2 (1) {
    ["storage":"ArrayObject":private]=>
    array(0) {
    }
  }
  ["default":protected]=>
  NULL
}
PKj�\��mGGtests/igbinary_005.phptnu�[���--TEST--
Check for double serialisation
--SKIPIF--
--FILE--
<?php
if(!extension_loaded('igbinary')) {
	dl('igbinary.' . PHP_SHLIB_SUFFIX);
}

function test($type, $variable) {
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);

	echo $type, "\n";
	echo substr(bin2hex($serialized), 8), "\n";
	echo $unserialized === $variable ? 'OK' : 'ERROR';
	echo "\n";
}

test('double: 123.456', 123.456);

/*
 * you can add regression tests for your extension here
 *
 * the output of your test code has to be equal to the
 * text in the --EXPECT-- section below for the tests
 * to pass, differences between the output and the
 * expected text are interpreted as failure
 *
 * see TESTING.md for further information on
 * writing regression tests
 */
?>
--EXPECT--
double: 123.456
0c405edd2f1a9fbe77
OK
PKj�\�'��QQtests/__serialize_012.phptnu�[���--TEST--
Test unserialization of classes derived from ArrayIterator
--SKIPIF--
<?php if (PHP_VERSION_ID < 70406) { echo "Skip requires php 7.4.6+"; } ?>
--FILE--
<?php
// based on bug45706.phpt from php-src
//
// NOTE: ArrayIterator::__debugInfo adds a fake private property that doesn't actually exist, which affects var_dump.
// This isn't a bug in the unserializer.
class Foo1 extends ArrayIterator
{
}
class Foo2 {
}
$x = array(new Foo1(),new Foo2);
$s = igbinary_serialize($x);
var_dump(igbinary_unserialize($s));
$s = str_replace("Foo", "Bar", $s);
$y = igbinary_unserialize($s);
var_dump($y);
--EXPECTF--
array(2) {
  [0]=>
  object(Foo1)#3 (1) {
    ["storage":"ArrayIterator":private]=>
    array(0) {
    }
  }
  [1]=>
  object(Foo2)#4 (0) {
  }
}
array(2) {
  [0]=>
  object(__PHP_Incomplete_Class)#4 (5) {
    ["__PHP_Incomplete_Class_Name"]=>
    string(4) "Bar1"
    ["0"]=>
    int(0)
    ["1"]=>
    array(0) {
    }
    ["2"]=>
    array(0) {
    }
    ["3"]=>
    NULL
  }
  [1]=>
  object(__PHP_Incomplete_Class)#3 (1) {
    ["__PHP_Incomplete_Class_Name"]=>
    string(4) "Bar2"
  }
}
PKj�\������tests/igbinary_033.phptnu�[���--TEST--
Object test, cyclic references
--SKIPIF--
<?php
if(!extension_loaded('igbinary')) {
	echo "skip no igbinary";
}
--FILE--
<?php

class Foo {
	public $parent;
	public $children;

	public function __construct() {
		$this->parent = null;
		$this->children = array();
	}

	public function addChild(Foo $obj) {
		$this->children[] = $obj;
		$obj->setParent($this);
	}

	public function setParent(Foo $obj) {
		$this->parent = $obj;
	}
}
error_reporting(E_ALL);

$obj1 = new Foo();

for ($i = 0; $i < 10; $i++) {
	$obj = new Foo();
	$obj1->addChild($obj);
}

$o = igbinary_unserialize(igbinary_serialize($obj1->children));

foreach ($obj1->children as $k => $v) {
	$obj_v = $v;
	$o_v = $o[$k];

	echo gettype($obj_v), "\t", gettype($o_v), "\n";
}
--EXPECT--
object	object
object	object
object	object
object	object
object	object
object	object
object	object
object	object
object	object
object	object
PKj�\g�5��tests/igbinary_053.phptnu�[���--TEST--
__wakeup can modify properties without affecting other objects
--FILE--
<?php

class Obj {
	private static $count = 1;

	public $a;

	function __construct($a) {
		$this->a = $a;
	}

	public function __wakeup() {
		echo "call wakeup\n";
		$this->a[] = "end";
	}
}

function main() {
	$array = ["test"];  // array (not a reference, but should be copied on write)
	$a = new Obj($array);
	$b = new Obj($array);
	$variable = [$a, $b];
	$serialized = igbinary_serialize($variable);
	printf("%s\n", bin2hex($serialized));
	$unserialized = igbinary_unserialize($serialized);
	var_dump($unserialized);
}
main();
--EXPECTF--
000000021402060017034f626a14011101611401060011047465737406011a0014010e010102
call wakeup
call wakeup
array(2) {
  [0]=>
  object(Obj)#%d (1) {
    ["a"]=>
    array(2) {
      [0]=>
      string(4) "test"
      [1]=>
      string(3) "end"
    }
  }
  [1]=>
  object(Obj)#%d (1) {
    ["a"]=>
    array(2) {
      [0]=>
      string(4) "test"
      [1]=>
      string(3) "end"
    }
  }
}
PKj�\�	pן�tests/__serialize_016_php8.phptnu�[���--TEST--
__serialize() mechanism (016): Properties are still typed after unserialization (references)
--SKIPIF--
<?php
if (PHP_VERSION_ID < 80000) { echo "skip __serialize/__unserialize error message different in php < 8"; }
if (PHP_VERSION_ID >= 90000) { echo "skip requires php < 9.0 when testing that the deprecation has no impact on igbinary functionality\n"; }
?>
--FILE--
<?php
declare(strict_types=1);

// Asserts that this will emit a warning about dynamic properties due to the lack of #[AllowDynamicProperties] in PHP 8.2+, and suppresses the warning
if (PHP_VERSION_ID >= 80200) { require_once __DIR__ . '/php82_suppress_dynamic_properties_warning.inc'; }

/** @property mixed $std undeclared dynamic property */
class Test {
    public int $i = 0;
    public ?string $s = 's';
    public object $o;
    public stdClass $stdClass;
    public array $a = [];
}
$t = new Test();
$t->i = 1;
$t->s = 'other';
$t->o = $t;
$t->std = (object)['key' => 'value'];
$t->a = [&$t->std, &$t->i, &$t->s, &$t->o];
$t->std->key = &$t->a;
var_dump($t);

var_dump(bin2hex($s = igbinary_serialize($t)));
$t2 = igbinary_unserialize($s);
var_dump($t2);
try {
    $t2->i = 'x';
} catch (Error $e) {
    echo "i: " . $e->getMessage() . "\n";
}
$t2->s = null;
try {
    $t2->s = false;
} catch (Error $e) {
    // The error message is "Cannot assign false" in php 8.3+
    echo "s: " . str_replace('false', 'bool', $e->getMessage()) . "\n";
}
$t2->s = 'other';
try {
    $t2->o = null;
} catch (Error $e) {
    echo "o: " . $e->getMessage() . "\n";
}
try {
    $t2->a = null;
} catch (Error $e) {
    echo "a: " . $e->getMessage() . "\n";
}
try {
    $t2->stdClass = $t;
} catch (Error $e) {
    echo "stdClass: " . $e->getMessage() . "\n";
}
try {
    $t2->a = $t2;
} catch (Error $e) {
    echo "a: " . $e->getMessage() . "\n";
}
var_dump($t2);
?>
--EXPECT--
object(Test)#1 (5) {
  ["i"]=>
  &int(1)
  ["s"]=>
  &string(5) "other"
  ["o"]=>
  *RECURSION*
  ["stdClass"]=>
  uninitialized(stdClass)
  ["a"]=>
  &array(4) {
    [0]=>
    &object(stdClass)#2 (1) {
      ["key"]=>
      *RECURSION*
    }
    [1]=>
    &int(1)
    [2]=>
    &string(5) "other"
    [3]=>
    *RECURSION*
  }
  ["std"]=>
  &object(stdClass)#2 (1) {
    ["key"]=>
    &array(4) {
      [0]=>
      *RECURSION*
      [1]=>
      &int(1)
      [2]=>
      &string(5) "other"
      [3]=>
      *RECURSION*
    }
  }
}
string(176) "0000000217045465737414061101692506011101732511056f7468657211016f252200001101612514040600251708737464436c617373140111036b65792501030601250101060225010206032522001103737464252204"
object(Test)#3 (5) {
  ["i"]=>
  &int(1)
  ["s"]=>
  &string(5) "other"
  ["o"]=>
  *RECURSION*
  ["stdClass"]=>
  uninitialized(stdClass)
  ["a"]=>
  &array(4) {
    [0]=>
    &object(stdClass)#4 (1) {
      ["key"]=>
      *RECURSION*
    }
    [1]=>
    &int(1)
    [2]=>
    &string(5) "other"
    [3]=>
    *RECURSION*
  }
  ["std"]=>
  &object(stdClass)#4 (1) {
    ["key"]=>
    &array(4) {
      [0]=>
      *RECURSION*
      [1]=>
      &int(1)
      [2]=>
      &string(5) "other"
      [3]=>
      *RECURSION*
    }
  }
}
i: Cannot assign string to property Test::$i of type int
s: Cannot assign bool to property Test::$s of type ?string
o: Cannot assign null to property Test::$o of type object
a: Cannot assign null to property Test::$a of type array
stdClass: Cannot assign Test to property Test::$stdClass of type stdClass
a: Cannot assign Test to property Test::$a of type array
object(Test)#3 (5) {
  ["i"]=>
  &int(1)
  ["s"]=>
  &string(5) "other"
  ["o"]=>
  *RECURSION*
  ["stdClass"]=>
  uninitialized(stdClass)
  ["a"]=>
  &array(4) {
    [0]=>
    &object(stdClass)#4 (1) {
      ["key"]=>
      *RECURSION*
    }
    [1]=>
    &int(1)
    [2]=>
    &string(5) "other"
    [3]=>
    *RECURSION*
  }
  ["std"]=>
  &object(stdClass)#4 (1) {
    ["key"]=>
    &array(4) {
      [0]=>
      *RECURSION*
      [1]=>
      &int(1)
      [2]=>
      &string(5) "other"
      [3]=>
      *RECURSION*
    }
  }
}
PKj�\���mmtests/igbinary_058.phptnu�[���--TEST--
Should not call __destruct if __wakeup throws an exception
--INI--
igbinary.compact_strings = On
--FILE--
<?php
class Thrower {
	public $id;
	public $throws;
	public $dynamic;
	public function __construct($id, $throws = false) {
		$this->id = $id;
		$this->throws = $throws;
		$this->dynamic = "original";
	}
	public function __wakeup() {
		printf("Calling __wakeup %s\n", $this->id);
		$this->dynamic = "copy";
		if ($this->throws) {
			throw new Exception("__wakeup threw");
		}
	}

	public function __destruct() {
		printf("Calling __destruct %s dynamic=%s\n", $this->id, $this->dynamic);
	}
}
function main() {
	$a = new Thrower("a", true);
	$serialized = igbinary_serialize($a);
	try {
		igbinary_unserialize($serialized);
	} catch (Exception $e) {
		printf("Caught %s\n", $e->getMessage());
	}
	$a = null;
	print("Done a\n");
	$b = new Thrower("b", false);
	$serialized = igbinary_serialize($b);
	$bCopy = igbinary_unserialize($serialized);
	print("Unserialized b\n");
	var_dump($bCopy);

	$bCopy = null;
	$b = null;
	print("Done b\n");
}
main();
--EXPECT--
Calling __wakeup a
Caught __wakeup threw
Calling __destruct a dynamic=original
Done a
Calling __wakeup b
Unserialized b
object(Thrower)#2 (3) {
  ["id"]=>
  string(1) "b"
  ["throws"]=>
  bool(false)
  ["dynamic"]=>
  string(4) "copy"
}
Calling __destruct b dynamic=copy
Calling __destruct b dynamic=original
Done b
PKj�\e�O��tests/igbinary_084b.phptnu�[���--TEST--
Properly free duplicate undeclared properties when unserializing invalid data
--SKIPIF--
<?php
if (PHP_VERSION_ID >= 90000) { echo "skip requires php < 9.0 when testing that the deprecation has no impact on igbinary functionality\n"; }
?>
--FILE--
<?php
if (PHP_VERSION_ID >= 80200) { require_once __DIR__ . '/php82_suppress_dynamic_properties_warning.inc'; }
class Test {
    public function __construct( ) {
        $this->pub = null;
    }

    public function __sleep() {
        // TODO: Could start detecting duplicates and emitting a notice as well
        return ["pub", "pub"];
    }
}
$t = new Test();
$t->pub = new Test();
$s = igbinary_serialize($t);
echo urlencode($s), "\n";
$unser = igbinary_unserialize($s);
var_dump($unser);
?>
--EXPECT--
%00%00%00%02%17%04Test%14%02%11%03pub%1A%00%14%02%0E%01%00%0E%01%00%0E%01%22%01
object(Test)#3 (1) {
  ["pub"]=>
  object(Test)#4 (1) {
    ["pub"]=>
    NULL
  }
}
PKj�\~-::tests/igbinary_076.phptnu�[���--TEST--
igbinary and edge cases unserializing array keys
--FILE--
<?php
set_error_handler(function ($errno, $errstr) {
    echo "$errstr\n";
});
var_dump(bin2hex($s = igbinary_serialize(['key' => true])));
// 3-byte string truncated in the middle of the array key
var_dump(igbinary_unserialize("\x00\x00\x00\x02\x14\x01\x11\x03\x6b\x65"));
// null instead of a string - skip over the entry
var_dump(igbinary_unserialize("\x00\x00\x00\x02\x14\x01\x00"));
?>
--EXPECTF--
string(24) "00000002140111036b657905"
igbinary_unserialize_chararray: end-of-data
NULL
array(0) {
}
PKj�\a���tests/__serialize_013.phptnu�[���--TEST--
__serialize() mechanism (013): Properties are still typed after unserialization
--SKIPIF--
<?php
if (PHP_VERSION_ID < 70400) { echo "skip __serialize/__unserialize not supported in php < 7.4 for compatibility with serialize()"; }
if (PHP_VERSION_ID >= 80000) { echo "skip different error message format"; }
?>
--FILE--
<?php
declare(strict_types=1);

class Test {
    public int $i = 0;
    public ?string $s = 's';
    public object $o;
    public stdClass $stdClass;
    public array $a = [];
}
$t = new Test();
$t->i = 1;
$t->s = 'other';
$t->o = $t;
$t->std = (object)['key' => 'value'];
$t->a = [$t->std];
var_dump($t);

var_dump(bin2hex($s = igbinary_serialize($t)));
$t2 = igbinary_unserialize($s);
var_dump($t2);
try {
    $t2->i = 'x';
} catch (Error $e) {
    echo "i: " . $e->getMessage() . "\n";
}
$t2->s = null;
try {
    $t2->s = false;
} catch (Error $e) {
    echo "s: " . $e->getMessage() . "\n";
}
$t2->s = 'other';
try {
    $t2->o = null;
} catch (Error $e) {
    echo "o: " . $e->getMessage() . "\n";
}
try {
    $t2->a = null;
} catch (Error $e) {
    echo "a: " . $e->getMessage() . "\n";
}
try {
    $t2->stdClass = $t;
} catch (Error $e) {
    echo "stdClass: " . $e->getMessage() . "\n";
}
try {
    $t2->a = $t2;
} catch (Error $e) {
    echo "a: " . $e->getMessage() . "\n";
}
var_dump($t2);
--EXPECT--
object(Test)#1 (5) {
  ["i"]=>
  int(1)
  ["s"]=>
  string(5) "other"
  ["o"]=>
  *RECURSION*
  ["stdClass"]=>
  uninitialized(stdClass)
  ["a"]=>
  array(1) {
    [0]=>
    object(stdClass)#2 (1) {
      ["key"]=>
      string(5) "value"
    }
  }
  ["std"]=>
  object(stdClass)#2 (1) {
    ["key"]=>
    string(5) "value"
  }
}
string(142) "000000021704546573741406110169060111017311056f7468657211016f220000110161140106001708737464436c617373140111036b6579110576616c756511037374642202"
object(Test)#3 (5) {
  ["i"]=>
  int(1)
  ["s"]=>
  string(5) "other"
  ["o"]=>
  *RECURSION*
  ["stdClass"]=>
  uninitialized(stdClass)
  ["a"]=>
  array(1) {
    [0]=>
    object(stdClass)#4 (1) {
      ["key"]=>
      string(5) "value"
    }
  }
  ["std"]=>
  object(stdClass)#4 (1) {
    ["key"]=>
    string(5) "value"
  }
}
i: Typed property Test::$i must be int, string used
s: Typed property Test::$s must be string or null, bool used
o: Typed property Test::$o must be object, null used
a: Typed property Test::$a must be array, null used
stdClass: Typed property Test::$stdClass must be an instance of stdClass, Test used
a: Typed property Test::$a must be array, Test used
object(Test)#3 (5) {
  ["i"]=>
  int(1)
  ["s"]=>
  string(5) "other"
  ["o"]=>
  *RECURSION*
  ["stdClass"]=>
  uninitialized(stdClass)
  ["a"]=>
  array(1) {
    [0]=>
    object(stdClass)#4 (1) {
      ["key"]=>
      string(5) "value"
    }
  }
  ["std"]=>
  object(stdClass)#4 (1) {
    ["key"]=>
    string(5) "value"
  }
}
PKj�\�����tests/igbinary_099.phptnu�[���--TEST--
Test PHP 8.2 deprecation of creation of dynamic properties
--SKIPIF--
<?php
if (!extension_loaded("igbinary")) print "skip\n";
if (PHP_VERSION_ID < 80200) print "skip php < 8.2\n";
?>
--FILE--
<?php
class C {
}

$c = new C();
$invalidValues = [
    "\x00\x00\x00\x02\x17\x01C\x14\x01\x11\x01a\x06\x08",
    "\x00\x00\x00\x02\x17\x01C\x14\x01\x11\x04\x00*\x00a\x06\x08",
];
foreach ($invalidValues as $invalid) {
    try {
        var_dump(igbinary_unserialize($invalid));
    } catch (Error $e) {
        printf("%s: %s\n", $e::class, $e->getMessage());
    }
}
--EXPECTF--
Deprecated: igbinary_unserialize(): Creation of dynamic property C::$a is deprecated in %sigbinary_099.php on line 12
object(C)#2 (1) {
  ["a"]=>
  int(8)
}

Deprecated: igbinary_unserialize(): Creation of dynamic property C::$a is deprecated in %sigbinary_099.php on line 12
object(C)#2 (1) {
  ["a":protected]=>
  int(8)
}
PKj�\��Ȁqqtests/igbinary_007.phptnu�[���--TEST--
Check for simple array serialization
--SKIPIF--
--FILE--
<?php
if(!extension_loaded('igbinary')) {
	dl('igbinary.' . PHP_SHLIB_SUFFIX);
}

function test($type, $variable) {
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);

	echo $type, "\n";
	echo substr(bin2hex($serialized), 8), "\n";
	echo $unserialized == $variable ? 'OK' : 'ERROR';
	echo "\n";
}

test('empty array:', array());
test('array(1, 2, 3)', array(1, 2, 3));
test('array(array(1, 2, 3), arr...', array(array(1, 2, 3), array(4, 5, 6), array(7, 8, 9)));

/*
 * you can add regression tests for your extension here
 *
 * the output of your test code has to be equal to the
 * text in the --EXPECT-- section below for the tests
 * to pass, differences between the output and the
 * expected text are interpreted as failure
 *
 * see TESTING.md for further information on
 * writing regression tests
 */
?>
--EXPECT--
empty array:
1400
OK
array(1, 2, 3)
1403060006010601060206020603
OK
array(array(1, 2, 3), arr...
1403060014030600060106010602060206030601140306000604060106050602060606021403060006070601060806020609
OK
PKj�\W�;�ggtests/igbinary_069.phptnu�[���--TEST--
Test serializing and unserializing many duplicate strings
--FILE--
<?php

function main() {
	$arr = array();
	// Just more than 2 ** 16
	$n = (2 ** 16) + 100;
	for ($i = 0; $i < $n; $i++) {
		$s = "$i";
		$arr[] = $s;
		$arr[] = $s;
	}
	$unser = igbinary_unserialize(igbinary_serialize($arr));
	var_export($arr === $unser);
}
main();
--EXPECT--
true
PKj�\�8eetests/igbinary_026_php8.phptnu�[���--TEST--
Cyclic array test
--INI--
report_memleaks=0
--SKIPIF--
<?php
if (!extension_loaded('igbinary')) {
	echo "skip no igbinary\n";
}
if (PHP_MAJOR_VERSION < 8) {
	echo "skip requires php 8.0+\n";
}
--FILE--
<?php

function test($type, $variable, $test) {
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);

	echo $type, "\n";
	echo substr(bin2hex($serialized), 8), "\n";
	echo !$test || $unserialized == $variable ? 'OK' : 'ERROR', "\n";
}

$a = array(
	'a' => array(
		'b' => 'c',
		'd' => 'e'
	),
);

$a['f'] = &$a;

test('array', $a, false);

$a = array("foo" => &$b);
$b = array(1, 2, $a);

$exp = $a;
$act = igbinary_unserialize(igbinary_serialize($a));

ob_start();
var_dump($exp);
$dump_exp = ob_get_clean();
ob_start();
var_dump($act);
$dump_act = ob_get_clean();

if ($dump_act !== $dump_exp) {
	echo "Var dump differs:\nActual:\n", $dump_act, "\nExpected:\n", $dump_exp, "\n";
} else {
	echo "Var dump OK\n";
}

$act['foo'][1] = 'test value';
$exp['foo'][1] = 'test value';
if ($act['foo'][1] !== $act['foo'][2]['foo'][1]) {
	echo "Recursive elements differ:\n";
	echo "Actual\n";
	var_dump($act);
	var_dump($act['foo']);
	echo "Expected\n";
	var_dump($exp);
	var_dump($exp['foo']);
}

?>
--EXPECT--
array
140211016114021101621101631101641101651101662514020e0001010e05250102
OK
Var dump differs:
Actual:
array(1) {
  ["foo"]=>
  &array(3) {
    [0]=>
    int(1)
    [1]=>
    int(2)
    [2]=>
    array(1) {
      ["foo"]=>
      *RECURSION*
    }
  }
}

Expected:
array(1) {
  ["foo"]=>
  &array(3) {
    [0]=>
    int(1)
    [1]=>
    int(2)
    [2]=>
    *RECURSION*
  }
}
PKj�\"���tests/igbinary_068.phptnu�[���--TEST--
Test serializing and unserializing PHP_INT_MIN
--FILE--
<?php

if (!defined('PHP_INT_MIN')) {
	define('PHP_INT_MIN', ~PHP_INT_MAX);
}
var_export(PHP_INT_MAX === igbinary_unserialize(igbinary_serialize(PHP_INT_MAX)));
echo "\n";

var_export(PHP_INT_MIN === igbinary_unserialize(igbinary_serialize(PHP_INT_MIN)));
echo "\n";
var_export(PHP_INT_MIN+1 === igbinary_unserialize(igbinary_serialize(PHP_INT_MIN + 1)));
echo "\n";
?>
--EXPECT--
true
true
true
PKj�\����tests/igbinary_096.phptnu�[���--TEST--
Test unserialization creates valid current()
--INI--
display_errors=stderr
error_reporting=E_ALL
--FILE--
<?php
$arr = [
	'one' => [
		'two' => [
			'three' => [
				'four'
			],
		],
	],
];
$test = current(current(current(current($arr))));

var_dump($test);

// Note: after unserialization the current is the last array element.
$arr2 = igbinary_unserialize(igbinary_serialize($arr));
$test2 = current(current(current(current($arr2))));

var_dump($test2);
?>
--EXPECT--
string(4) "four"
string(4) "four"PKj�\�E�ntests/igbinary_008.phptnu�[���--TEST--
Check for array+string serialization
--SKIPIF--
--FILE--
<?php
if(!extension_loaded('igbinary')) {
	dl('igbinary.' . PHP_SHLIB_SUFFIX);
}

function test($type, $variable) {
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);

	echo $type, "\n";
	echo substr(bin2hex($serialized), 8), "\n";
	if ($unserialized != $variable) {
		echo 'ERROR, expected: ';
		var_dump($variable);
		echo 'got: ';
		var_dump($unserialized);
	} else {
		echo 'OK';
	}
	echo "\n";
}

test('array("foo", "foo", "foo")', array("foo", "foo", "foo"));
test('array("one" => 1, "two" => 2))', array("one" => 1, "two" => 2));
test('array("kek" => "lol", "lol" => "kek")', array("kek" => "lol", "lol" => "kek"));
test('array("" => "empty")', array("" => "empty"));

?>
--EXPECT--
array("foo", "foo", "foo")
140306001103666f6f06010e0006020e00
OK
array("one" => 1, "two" => 2))
140211036f6e650601110374776f0602
OK
array("kek" => "lol", "lol" => "kek")
140211036b656b11036c6f6c0e010e00
OK
array("" => "empty")
14010d1105656d707479
OK
PKj�\�Ue�((tests/igbinary_048.phptnu�[���--TEST--
Object test, __set not called for private attr in extended class
--FILE--
<?php

class Bar {
    public $a = [];
    public $b = array();
    public $c = NULL;
    private $_d = NULL;
    public function __set($name,$value) {
        echo 'magic function called for ' . $name . ' with ' . var_export($value, true) . PHP_EOL;
    }
}

class Foo extends Bar {
    public $m;
}

$x = new Foo();
$x->a = [1, 2, 3];
$x->nonexistent = 'aaa';

igbinary_unserialize(igbinary_serialize($x));
--EXPECT--
magic function called for nonexistent with 'aaa'
PKj�\�(X�ddtests/igbinary_015c.phptnu�[���--TEST--
Check for serialization handler
--SKIPIF--
<?php
if (!extension_loaded('session')) {
	exit('skip session extension not loaded');
}

ob_start();
phpinfo(INFO_MODULES);
$str = ob_get_clean();

$array = explode("\n", $str);
$array = preg_grep('/^igbinary session support.*yes/', $array);
if (!$array) {
	exit('skip igbinary session handler not available');
}
?>
--FILE--
<?php

$output = '';

function open($path, $name) {
	return true;
}

function close() {
	return true;
}

function read($id) {
    global $output;
    $output .= "read($id)\n";
	return '';
}

function write($id, $data) {
	global $output;
	$output .= "write($id): data:(" . bin2hex($data) . ")\n";
	return true;
}

function destroy($id) {
	return true;
}

function gc($time) {
	return true;
}

ini_set('session.serialize_handler', 'igbinary');

session_set_save_handler('open', 'close', 'read', 'write', 'destroy', 'gc');
session_id('abcdef10231512dfaz_12311');

session_start();

// save an empty session
session_write_close();

// See https://github.com/igbinary/igbinary/issues/231
// - Redis expects a non-empty string to be serialized
// - When igbinary serializes data, many applications expect it to begin with \x00\x00\x00\x02.
// - \x14\x00 represents an array(0x14) of size 0 (0x00)
echo $output;
?>
--EXPECT--
read(abcdef10231512dfaz_12311)
write(abcdef10231512dfaz_12311): data:(000000021400)
PKj�\k�}Z��tests/igbinary_043.phptnu�[���--TEST--
Object serialization with compact strings
--SKIPIF--
<?php
	if (!extension_loaded("igbinary")) {
		print "skip";
	}
?>
--INI--
igbinary.compact_strings=Off
--FILE--
<?php
class Foo {
}

class Bar {
}


$expected_array = array();
for ($i = 0; $i < 10; $i++) {
	$expected_array['foo_' . $i] = new Foo;
	$expected_array['bar_' . $i] = new Bar;
}

$actual_array = igbinary_unserialize(igbinary_serialize($expected_array));

$error = 'OK';

foreach ($expected_array as $key => $object) {
	if (!isset($actual_array[$key])) {
		$error = 'ERROR';
		echo "Key $key is missing from result.\n";
		echo "Expected key/value:\n";
		var_dump($key, $object);
		var_dump($object);

		break;
	}

	if (!is_object($actual_array[$key]) ||
		get_class($object) !== get_class($actual_array[$key])) {
		$error = 'ERROR';
		echo "Array mismatch on $key\n";
		echo "Expected key/value:\n";
		var_dump($key, $object);
		echo "Actual key/value:\n";
		var_dump($key, $actual_array[$key]);

		break;
	}

}

echo $error, "\n";

--EXPECT--
OK
PKj�\ydy��tests/igbinary_089_32bit.phptnu�[���--TEST--
Test unserializing invalid 64-bit string header on 32-bit platform
--INI--
display_errors=stderr
error_reporting=E_ALL
--CONFLICTS--
high_memory
--SKIPIF--
<?php
if (!extension_loaded("igbinary")) print "skip\n";
if (PHP_INT_SIZE > 4) { print "skip requires 32-bit\n"; }
?>
--FILE--
<?php
$ser_invalid = hex2bin('0000000213fa56ea002a');
var_dump(igbinary_unserialize($ser_invalid));

?>
--EXPECTF--
Warning: igbinary_unserialize_chararray: %s in %sigbinary_089_32bit.php on line 3
NULLPKj�\���o++tests/igbinary_001.phptnu�[���--TEST--
Check for igbinary presence
--SKIPIF--
<?php if (!extension_loaded("igbinary")) print "skip"; ?>
--FILE--
<?php
echo "igbinary extension is available\n";
/*
 * you can add regression tests for your extension here
 *
 * the output of your test code has to be equal to the
 * text in the --EXPECT-- section below for the tests
 * to pass, differences between the output and the
 * expected text are interpreted as failure
 *
 * see TESTING.md for further information on
 * writing regression tests
 */
?>
--EXPECT--
igbinary extension is available
PKj�\�ILqtests/__serialize_014.phptnu�[���--TEST--
__serialize() mechanism (014): Uninitialized properties can be serialized and unserialized
--SKIPIF--
<?php
if (PHP_VERSION_ID < 70400) { echo "skip __serialize/__unserialize not supported in php < 7.4 for compatibility with serialize()"; }
if (PHP_VERSION_ID >= 80000) { echo "skip different error message format"; }
?>
--FILE--
<?php
class MyClass {
    public stdClass $o;
    public string $s;
    public ?int $i;
}
// 00000002               -- header
// 17 07 4d79436c617373   -- object of type "MyClass"
//   14 03 000000           -- with 3 uninitialized properties
$m = new MyClass();
var_dump($m);
var_dump(bin2hex($s = igbinary_serialize($m)));
var_dump(igbinary_unserialize($s));
$m = new MyClass();
$m->o = new stdClass();
unset($m->o);
$m->s = 'other';
unset($m->s);
$m->i = 42;
unset($m->i);
// Should have the same serialized representation.
var_dump($m);
var_dump(bin2hex($s = igbinary_serialize($m)));
try {
    $m->i = 'i';
} catch (TypeError $e) {
    echo $e->getMessage() . "\n";
}
--EXPECT--
object(MyClass)#1 (0) {
  ["o"]=>
  uninitialized(stdClass)
  ["s"]=>
  uninitialized(string)
  ["i"]=>
  uninitialized(?int)
}
string(36) "0000000217074d79436c6173731403000000"
object(MyClass)#2 (0) {
  ["o"]=>
  uninitialized(stdClass)
  ["s"]=>
  uninitialized(string)
  ["i"]=>
  uninitialized(?int)
}
object(MyClass)#2 (0) {
  ["o"]=>
  uninitialized(stdClass)
  ["s"]=>
  uninitialized(string)
  ["i"]=>
  uninitialized(?int)
}
string(36) "0000000217074d79436c6173731403000000"
Typed property MyClass::$i must be int or null, string used
PKj�\��U��tests/igbinary_enums_1.phptnu�[���--TEST--
Test unserializing valid enums
--SKIPIF--
<?php if (PHP_VERSION_ID < 80100) { echo "skip enums requires php 8.1"; } ?>
--FILE--
<?php

enum Suit {
    case Hearts;
    case Diamonds;
    case Spades;
    case Clubs;
}
$ser = igbinary_serialize(Suit::Hearts);
echo urlencode($ser), "\n";
var_dump(igbinary_unserialize($ser));
var_dump(igbinary_unserialize($ser));
$serArray = igbinary_serialize([Suit::Hearts, Suit::Diamonds, Suit::Spades, Suit::Clubs, Suit::Clubs, 'Diamonds' => 'Diamonds']);
echo urlencode($serArray), "\n";
var_dump(igbinary_unserialize($serArray));

?>
--EXPECT--
%00%00%00%02%17%04Suit%27%11%06Hearts
enum(Suit::Hearts)
enum(Suit::Hearts)
%00%00%00%02%14%06%06%00%17%04Suit%27%11%06Hearts%06%01%1A%00%27%11%08Diamonds%06%02%1A%00%27%11%06Spades%06%03%1A%00%27%11%05Clubs%06%04%22%04%0E%02%0E%02
array(6) {
  [0]=>
  enum(Suit::Hearts)
  [1]=>
  enum(Suit::Diamonds)
  [2]=>
  enum(Suit::Spades)
  [3]=>
  enum(Suit::Clubs)
  [4]=>
  enum(Suit::Clubs)
  ["Diamonds"]=>
  string(8) "Diamonds"
}
PKj�\G�k��tests/__serialize_007.phptnu�[���--TEST--
__serialize() mechanism (007): handle __unserialize throwing
--SKIPIF--
<?php if (PHP_VERSION_ID < 70400) { echo "skip __serialize/__unserialize not supported in php < 7.4 for compatibility with serialize()"; } ?>
--FILE--
<?php

class Test {
    public $prop;
    public $prop2;
    public function __serialize() {
        return [$this->prop, $this->prop2];
    }
    public function __unserialize(array $data) {
        $this->prop = $data[0];
        $this->prop2 = $data[1];
        throw new RuntimeException($this->prop);
    }

    public function __destruct() {
        // should not be called
        echo "Called destruct prop=$this->prop\n";
    }
}

$test = new Test;
$test->prop = 'XX';
$test->prop2 = [$test];
// 00000002          - igbinary header
// 17 04 54657374    - object of class with name "Test"
//   14 02           - 2 properties
//     06 00         - uint8(0) =>
//       11 02 5858  -   'XX'
//     06 01         - uint8(1) =>
//       14 01       -   array(size=2)
//         06 00     - uint8(0) =>
//         22 00     - igbinary_type_objref8 (pointer to the first referenceable item, i.e. the instance of "Test"
var_dump(bin2hex($s = igbinary_serialize($test)));
try {
    var_dump(igbinary_unserialize($s));
} catch (RuntimeException $e) {
    echo "Caught: {$e->getMessage()}\n";
}
$test->prop = 'not from igbinary_unserialize';

?>
--EXPECT--
string(52) "0000000217045465737414020600110258580601140106002200"
Caught: XX
Called destruct prop=not from igbinary_unserialize
PKj�\������tests/igbinary_090.phptnu�[���--TEST--
Check for handling of IS_INDIRECT in arrays
--FILE--
<?php
$globalVar = 123;
$otherGlobalVar = &$globalVar;

call_user_func(function () {
    $x = $GLOBALS;
    foreach ($x as $key => $value) {
        if (!in_array($key, ['globalVar', 'otherGlobalVar'])) {
            unset($x[$key]);
        }
    }
    var_dump($x);
    $ser = igbinary_serialize($x);
    echo urlencode($ser) . "\n";
    var_dump(igbinary_unserialize($ser));

});
--EXPECT--
array(2) {
  ["globalVar"]=>
  &int(123)
  ["otherGlobalVar"]=>
  &int(123)
}
%00%00%00%02%14%02%11%09globalVar%25%06%7B%11%0EotherGlobalVar%25%01%01
array(2) {
  ["globalVar"]=>
  &int(123)
  ["otherGlobalVar"]=>
  &int(123)
}
PKj�\��o�}}tests/igbinary_058b.phptnu�[���--TEST--
Should not call __destruct if __wakeup throws an exception (in arrays)
--INI--
igbinary.compact_strings = On
--FILE--
<?php
class Thrower {
	public $id;
	public $throws;
	public $dynamic;
	public function __construct($id, $throws = false) {
		$this->id = $id;
		$this->throws = $throws;
		$this->dynamic = "original";
	}
	public function __wakeup() {
		printf("Calling __wakeup %s\n", $this->id);
		$this->dynamic = "copy";
		if ($this->throws) {
			throw new Exception("__wakeup threw for id " . $this->id);
		}
	}

	public function __destruct() {
		printf("Calling __destruct %s dynamic=%s\n", $this->id, $this->dynamic);
	}
}
function main() {
	$values = [
		0      => new Thrower("a", false),
		'foo'  => 'last',
		'key1' => new Thrower("b", false),
		2      => new Thrower("c", true),
		'last' => new Thrower("d", false),
	];
	$serialized = igbinary_serialize($values);
	$values = null;
    printf("Going to unserialize\n");
	try {
		igbinary_unserialize($serialized);
	} catch (Exception $e) {
		printf("Caught %s\n", $e->getMessage());
	}
}
main();
--EXPECT--
Calling __destruct a dynamic=original
Calling __destruct b dynamic=original
Calling __destruct c dynamic=original
Calling __destruct d dynamic=original
Going to unserialize
Calling __wakeup a
Calling __wakeup b
Calling __wakeup c
Calling __destruct a dynamic=copy
Calling __destruct b dynamic=copy
Caught __wakeup threw for id c
PKj�\`�>l��tests/igbinary_063_php7.phptnu�[���--TEST--
Accessing unserialized numbers.
--SKIPIF--
<?php
if (!extension_loaded('igbinary')) {
    echo "skip no igbinary";
}
if (PHP_VERSION_ID >= 70200) {
    echo "Skip php 7.1 or 7.0 required";
}
?>
--FILE--
<?php

$data = (object)array(1,2,3, -1 => 'x', 1234 => 33);
var_dump($data);
$x = "1";
$y = 1;
$z = "1234";
$w = 1234;
var_dump(isset($data->{$x}) ? $data->{$x} : "unset");
error_reporting(0);
$str = igbinary_serialize($data);

$unserialized = igbinary_unserialize($str);
var_dump($unserialized);
var_dump(isset($unserialized->{$x}) ? $unserialized->{$x} : "unset str");
var_dump(isset($unserialized->{$y}) ? $unserialized->{$y} : "unset int");
var_dump(isset($unserialized->{$z}) ? $unserialized->{$z} : "unset str 1234");
var_dump(isset($unserialized->{$w}) ? $unserialized->{$w} : "unset int 1234");
var_dump(isset($unserialized->{-1}) ? $unserialized->{-1} : "unset int -1");
?>
--EXPECT--
object(stdClass)#1 (5) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
  [-1]=>
  string(1) "x"
  [1234]=>
  int(33)
}
string(5) "unset"
object(stdClass)#2 (5) {
  ["0"]=>
  int(1)
  ["1"]=>
  int(2)
  ["2"]=>
  int(3)
  ["-1"]=>
  string(1) "x"
  ["1234"]=>
  int(33)
}
int(2)
int(2)
int(33)
int(33)
string(1) "x"
PKj�\*���77tests/igbinary_enums_2.phptnu�[���--TEST--
Test unserializing valid and invalid enums
--SKIPIF--
<?php if (PHP_VERSION_ID < 80100) { echo "skip enums requires php 8.1"; } ?>
--FILE--
<?php

class ABCD {
}

enum Suit {
    case Hearts;
    case Diamonds;
    case Spades;
    case Clubs;
    const HEARTS = self::Hearts;
}
$arr = ['Hearts' => Suit::Hearts];
$arr[1] = &$arr['Hearts'];
$serArray = igbinary_serialize($arr);
// PHP 8.1 added support for %0 as a null byte in EXPECTF in https://github.com/php/php-src/pull/7069
// Igbinary's use case of urlencode on binary data is rare.
// So replace % with \x
echo str_replace(['\\', '%'], ['\\\\', '\x'], urlencode($serArray)), "\n";
$result = igbinary_unserialize($serArray);
var_dump($result);
$result[1] = 'new';
var_dump($result);
$serInvalid = str_replace('Hearts', 'HEARTS', $serArray);
var_dump(igbinary_unserialize($serInvalid));

$serInvalidConst = str_replace('Hearts', 'vvvvvv', $serArray);
var_dump(igbinary_unserialize($serInvalidConst));

$serMissingClass = str_replace('Suit', 'Club', $serArray);
var_dump(igbinary_unserialize($serMissingClass));

$serInvalidClass = str_replace('Suit', 'ABCD', $serArray);
var_dump(igbinary_unserialize($serInvalidClass));
?>
--EXPECTF--
\x00\x00\x00\x02\x14\x02\x11\x06Hearts\x25\x17\x04Suit\x27\x0E\x00\x06\x01\x25\x22\x01
array(2) {
  ["Hearts"]=>
  &enum(Suit::Hearts)
  [1]=>
  &enum(Suit::Hearts)
}
array(2) {
  ["Hearts"]=>
  &string(3) "new"
  [1]=>
  &string(3) "new"
}

Warning: igbinary_unserialize_object_enum_case: Suit::HEARTS is not an enum case in %s on line 25
NULL

Warning: igbinary_unserialize_object_enum_case: Undefined constant Suit::vvvvvv in %s on line 28
NULL

Warning: igbinary_unserialize_object_enum_case: Class 'Club' does not exist in %s on line 31
NULL

Warning: igbinary_unserialize_object_enum_case: Class 'ABCD' is not an enum in %s on line 34
NULLPKj�\C�(�""tests/igbinary_070.phptnu�[���--TEST--
__serialize() mechanism in igbinary
--SKIPIF--
<?php
if (PHP_VERSION_ID < 70400) {
    die('skip requires php 7.4+');
}
?>
--FILE--
<?php
class Test {
    public $prop;
    public $prop2;
    public function __serialize() {
        return ["value" => $this->prop, 42 => $this->prop2];
    }
    public function __unserialize(array $data) {
        $this->prop = 'unser' . $data["value"];
        $this->prop2 = 'unser' . $data[42];
    }
}
$test = new Test;
$test->prop = "foobar";
$test->prop2 = "barfoo";
$s = igbinary_serialize($test);
echo bin2hex($s) . "\n";
var_dump(igbinary_unserialize($s));
?>
--EXPECT--
000000021704546573741402110576616c75651106666f6f626172062a1106626172666f6f
object(Test)#2 (2) {
  ["prop"]=>
  string(11) "unserfoobar"
  ["prop2"]=>
  string(11) "unserbarfoo"
}
PKj�\.��M%%tests/igbinary_bug72134.phptnu�[���--TEST--
igbinary_unserialize regression test for segfault on 3rd call for objects with dynamic property
--FILE--
<?php
#[AllowDynamicProperties]
class Obj
{
    public $bar = "test";
}
$value = new Obj();
$value->i = 1;
$igb = igbinary_serialize($value);
for ($i=0; $i < 30; $i++)
{
    // This used to segfault at the third attempt
    echo igbinary_unserialize($igb)->bar . PHP_EOL;
}
--EXPECT--
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
test
PK j�\1��I66tests/igbinary_067.phptnu�[���--TEST--
Test serializing multiple reference groups to the same empty array
--SKIPIF--
<?php
if (!function_exists('json_encode')) { echo "skip requires json_encode\n"; }
?>
--FILE--
<?php

function dump($array) {
	echo count($array) . " values\n";
	foreach ($array as $k => $value) {
		echo "$k: " . json_encode($value) . "\n";
	}
}

function main() {
	$a = array();
	$b = $a;
	$c = $a;
	$value = array(&$b, $a, &$b, &$c, &$c);
	$ser = igbinary_serialize($value);
	echo bin2hex($ser) . "\n";
	$v = igbinary_unserialize($ser);
	dump($v);
	$v[0][] = 2;
	dump($v);
	$v[3][] = 3;
	dump($v);
	var_export($a);
}
main();
?>
--EXPECT--
000000021405060025140006011400060225010106032514000604250103
5 values
0: []
1: []
2: []
3: []
4: []
5 values
0: [2]
1: []
2: [2]
3: []
4: []
5 values
0: [2]
1: []
2: [2]
3: [3]
4: [3]
array (
)
PK j�\�=u�tests/__serialize_013_php8.phptnu�[���--TEST--
__serialize() mechanism (013): Properties are still typed after unserialization (php8)
--SKIPIF--
<?php if (PHP_VERSION_ID < 80000) { echo "skip __serialize/__unserialize error message different in php < 8"; } ?>
--FILE--
<?php
declare(strict_types=1);

/** @property mixed $std */
#[AllowDynamicProperties]
class Test {
    public int $i = 0;
    public ?string $s = 's';
    public object $o;
    public stdClass $stdClass;
    public array $a = [];
}
$t = new Test();
$t->i = 1;
$t->s = 'other';
$t->o = $t;
$t->std = (object)['key' => 'value'];
$t->a = [$t->std];
var_dump($t);

var_dump(bin2hex($s = igbinary_serialize($t)));
$t2 = igbinary_unserialize($s);
var_dump($t2);
try {
    $t2->i = 'x';
} catch (Error $e) {
    echo "i: " . $e->getMessage() . "\n";
}
$t2->s = null;
try {
    $t2->s = false;
} catch (Error $e) {
    echo "s: " . str_replace('false', 'bool', $e->getMessage()) . "\n";
}
$t2->s = 'other';
try {
    $t2->o = null;
} catch (Error $e) {
    echo "o: " . $e->getMessage() . "\n";
}
try {
    $t2->a = null;
} catch (Error $e) {
    echo "a: " . $e->getMessage() . "\n";
}
try {
    $t2->stdClass = $t;
} catch (Error $e) {
    echo "stdClass: " . $e->getMessage() . "\n";
}
try {
    $t2->a = $t2;
} catch (Error $e) {
    echo "a: " . $e->getMessage() . "\n";
}
var_dump($t2);
?>
--EXPECT--
object(Test)#1 (5) {
  ["i"]=>
  int(1)
  ["s"]=>
  string(5) "other"
  ["o"]=>
  *RECURSION*
  ["stdClass"]=>
  uninitialized(stdClass)
  ["a"]=>
  array(1) {
    [0]=>
    object(stdClass)#2 (1) {
      ["key"]=>
      string(5) "value"
    }
  }
  ["std"]=>
  object(stdClass)#2 (1) {
    ["key"]=>
    string(5) "value"
  }
}
string(142) "000000021704546573741406110169060111017311056f7468657211016f220000110161140106001708737464436c617373140111036b6579110576616c756511037374642202"
object(Test)#3 (5) {
  ["i"]=>
  int(1)
  ["s"]=>
  string(5) "other"
  ["o"]=>
  *RECURSION*
  ["stdClass"]=>
  uninitialized(stdClass)
  ["a"]=>
  array(1) {
    [0]=>
    object(stdClass)#4 (1) {
      ["key"]=>
      string(5) "value"
    }
  }
  ["std"]=>
  object(stdClass)#4 (1) {
    ["key"]=>
    string(5) "value"
  }
}
i: Cannot assign string to property Test::$i of type int
s: Cannot assign bool to property Test::$s of type ?string
o: Cannot assign null to property Test::$o of type object
a: Cannot assign null to property Test::$a of type array
stdClass: Cannot assign Test to property Test::$stdClass of type stdClass
a: Cannot assign Test to property Test::$a of type array
object(Test)#3 (5) {
  ["i"]=>
  int(1)
  ["s"]=>
  string(5) "other"
  ["o"]=>
  *RECURSION*
  ["stdClass"]=>
  uninitialized(stdClass)
  ["a"]=>
  array(1) {
    [0]=>
    object(stdClass)#4 (1) {
      ["key"]=>
      string(5) "value"
    }
  }
  ["std"]=>
  object(stdClass)#4 (1) {
    ["key"]=>
    string(5) "value"
  }
}
PK j�\���>tests/igbinary_031.phptnu�[���--TEST--
Object Serializable interface throws exceptions
--INI--
; Note that php 8.1 deprecates using Serializable without __serialize/__unserialize but we are testing Serialize for igbinary. Suppress deprecations.
error_reporting=E_ALL & ~E_DEPRECATED
--FILE--
<?php
if(!extension_loaded('igbinary')) {
	dl('igbinary.' . PHP_SHLIB_SUFFIX);
}

function test($variable) {
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);
}

class Obj implements Serializable {
	private static $count = 1;

	var $a;
	var $b;

	function __construct($a, $b) {
		$this->a = $a;
		$this->b = $b;
	}

	public function serialize() {
		$c = self::$count++;
		echo "call serialize, ", ($this->a ? "throw" : "no throw"),"\n";
		if ($this->a) {
			throw new Exception("exception in serialize $c");
		}
		return pack('NN', $this->a, $this->b);
	}

	public function unserialize($serialized) {
		$tmp = unpack('N*', $serialized);
		$this->__construct($tmp[1], $tmp[2]);
		$c = self::$count++;
		echo "call unserialize, ", ($this->b ? "throw" : "no throw"),"\n";
		if ($this->b) {
			throw new Exception("exception in unserialize $c");
		}
	}
}

$a = new Obj(1, 0);
$a = new Obj(0, 0);
$b = new Obj(0, 0);
$c = new Obj(1, 0);
$d = new Obj(0, 1);

echo "a, a, c\n";
try {
	test(array($a, $a, $c));
} catch (Exception $e) {
	if ($e->getPrevious()) {
		$e = $e->getPrevious();
	}

	echo $e->getMessage(), "\n";
}

echo "b, b, d\n";

try {
	test(array($b, $b, $d));
} catch (Exception $e) {
	if ($e->getPrevious()) {
		$e = $e->getPrevious();
	}

	echo $e->getMessage(), "\n";
}

--EXPECT--
a, a, c
call serialize, no throw
call serialize, throw
exception in serialize 2
b, b, d
call serialize, no throw
call serialize, no throw
call unserialize, no throw
call unserialize, throw
exception in unserialize 6
PK j�\k7z88tests/igbinary_081.phptnu�[���--TEST--
igbinary with reference group of size 1 created by array_walk_recursive
--FILE--
<?php
// Source: https://github.com/igbinary/igbinary/issues/268
//Data must be an array of at least depth 2
$data = [['hello', 'world']];
//Each leaf value must have been accessed
array_walk_recursive($data, function ($value) {});

//Then a second array must be constructed element-wise from the first
$data2 = [$data[0]];

//Then both arrays need to be serialized together
$a = [$data, $data2];
$ser1 = igbinary_serialize($a);
$b = igbinary_unserialize($ser1);

print serialize($a) . "\n";
print serialize($b) . "\n";
print bin2hex($ser1) . "\n";
print bin2hex(igbinary_serialize($b)) . "\n";
--EXPECT--
a:2:{i:0;a:1:{i:0;a:2:{i:0;s:5:"hello";i:1;s:5:"world";}}i:1;a:1:{i:0;a:2:{i:0;s:5:"hello";i:1;s:5:"world";}}}
a:2:{i:0;a:1:{i:0;a:2:{i:0;s:5:"hello";i:1;s:5:"world";}}i:1;a:1:{i:0;a:2:{i:0;s:5:"hello";i:1;s:5:"world";}}}
00000002140206001401060014020600110568656c6c6f06011105776f726c640601140106000102
00000002140206001401060014020600110568656c6c6f06011105776f726c640601140106000102
PK!j�\�[	[	tests/igbinary_028.phptnu�[���--TEST--
Serialize object into session, full set
--SKIPIF--
<?php
if (!extension_loaded('session')) {
	exit('skip session extension not loaded');
}

ob_start();
phpinfo(INFO_MODULES);
$str = ob_get_clean();

$array = explode("\n", $str);
$array = preg_grep('/^igbinary session support.*yes/', $array);
if (!$array) {
	exit('skip igbinary session handler not available');
}


--FILE--
<?php

class Foo {
	private static $s1 = array();
	protected static $s2 = array();
	public static $s3 = array();

	private $d1;
	protected $d2;
	public $d3;

	public function __construct($foo) {
		$this->d1 = $foo;
		$this->d2 = $foo;
		$this->d3 = $foo;
	}
}

class Bar {
	private static $s1 = array();
	protected static $s2 = array();
	public static $s3 = array();

	public $d1;
	private $d2;
	protected $d3;

	public function __construct() {
	}

	public function set($foo) {
		$this->d1 = $foo;
		$this->d2 = $foo;
		$this->d3 = $foo;
	}
}

if(!extension_loaded('igbinary')) {
	dl('igbinary.' . PHP_SHLIB_SUFFIX);
}

$output = '';

function open($path, $name) {
	return true;
}

function close() {
	return true;
}

function read($id) {
	global $output;
	$output .= "read\n";
	$a = new Bar();
	$b = new Foo($a);
	$a->set($b);
	$session = array('old' => $b);
	return igbinary_serialize($session);
}

function write($id, $data) {
	global $output;
	$output .= "write: ";
	$output .= substr(bin2hex($data), 8). "\n";
	return true;
}

function destroy($id) {
	return true;
}

function gc($time) {
	return true;
}

ini_set('session.serialize_handler', 'igbinary');

session_set_save_handler('open', 'close', 'read', 'write', 'destroy', 'gc');

session_start();

$_SESSION['test'] = "foobar";
$a = new Bar();
$b = new Foo($a);
$a->set($b);
$_SESSION['new'] = $a;

session_write_close();

echo $output;

/*
 * you can add regression tests for your extension here
 *
 * the output of your test code has to be equal to the
 * text in the --EXPECT-- section below for the tests
 * to pass, differences between the output and the
 * expected text are interpreted as failure
 *
 * see TESTING.md for further information on
 * writing regression tests
 */
?>
--EXPECT--
read
write: 140311036f6c641703466f6f1403110700466f6f0064311703426172140311026431220111070042617200643222011105002a00643322011105002a00643222021102643322021104746573741106666f6f62617211036e65771a0314030e041a0114030e0222030e0722030e0822030e0522040e062204
PK!j�\�ꞩ66tests/igbinary_049.phptnu�[���--TEST--
Correctly unserialize multiple references in arrays
--SKIPIF--
--INI--
igbinary.compact_strings = On
--FILE--
<?php
class Foo{}
$a = array("A");
$a[1] = &$a[0];
$a[2] = &$a[1];
$a[3] = &$a[2];
$a[4] = false;
$a[5] = &$a[4];
$a[6] = new Foo();
$a[7] = &$a[6];
$a[8] = &$a[7];
$a[9] = array(33);
$a[10] = new stdClass();
$a[10]->prop = &$a[8];
$a[11] = &$a[10];
$a[12] = $a[9];
$ig_ser = igbinary_serialize($a);
printf("ig_ser=%s\n", bin2hex($ig_ser));
$ig = igbinary_unserialize($ig_ser);
var_dump($ig);
$f = &$ig[3];
$f = 'V';
$g = &$ig[5];
$g = 'H';
$h = $ig[10];
$h->prop = 'S';
var_dump($ig);
--EXPECTF--
ig_ser=00000002140d0600251101410601250101060225010106032501010604250406052501020606251703466f6f1400060725220306082522030609140106000621060a251708737464436c6173731401110470726f70252203060b252205060c0104
array(13) {
  [0]=>
  &string(1) "A"
  [1]=>
  &string(1) "A"
  [2]=>
  &string(1) "A"
  [3]=>
  &string(1) "A"
  [4]=>
  &bool(false)
  [5]=>
  &bool(false)
  [6]=>
  &object(Foo)#%d (0) {
  }
  [7]=>
  &object(Foo)#%d (0) {
  }
  [8]=>
  &object(Foo)#%d (0) {
  }
  [9]=>
  array(1) {
    [0]=>
    int(33)
  }
  [10]=>
  &object(stdClass)#%d (1) {
    ["prop"]=>
    &object(Foo)#%d (0) {
    }
  }
  [11]=>
  &object(stdClass)#%d (1) {
    ["prop"]=>
    &object(Foo)#%d (0) {
    }
  }
  [12]=>
  array(1) {
    [0]=>
    int(33)
  }
}
array(13) {
  [0]=>
  &string(1) "V"
  [1]=>
  &string(1) "V"
  [2]=>
  &string(1) "V"
  [3]=>
  &string(1) "V"
  [4]=>
  &string(1) "H"
  [5]=>
  &string(1) "H"
  [6]=>
  &string(1) "S"
  [7]=>
  &string(1) "S"
  [8]=>
  &string(1) "S"
  [9]=>
  array(1) {
    [0]=>
    int(33)
  }
  [10]=>
  &object(stdClass)#%d (1) {
    ["prop"]=>
    &string(1) "S"
  }
  [11]=>
  &object(stdClass)#%d (1) {
    ["prop"]=>
    &string(1) "S"
  }
  [12]=>
  array(1) {
    [0]=>
    int(33)
  }
}
PK!j�\�lr��tests/__serialize_017.phptnu�[���--TEST--
__serialize() mechanism (001): Basics
--SKIPIF--
<?php if (PHP_VERSION_ID < 70400) { echo "skip __serialize/__unserialize not supported in php < 7.4 for compatibility with serialize()"; } ?>
--FILE--
<?php

class Test {
    public $prop;
    public function __serialize() {
        return ["prop" => $this->prop];
    }
    public function __unserialize(array $data) {
        echo "In __unserialize\n";
        if (!$data['prop']) {
            throw new RuntimeException("bad prop");
        }
    }
    public function __destruct() {
        echo "In __destruct\n";
    }
}

$test = new Test;
$test->prop = new Test();
var_dump(bin2hex($s = igbinary_serialize($test)));
try {
    igbinary_unserialize($s);
} catch (RuntimeException $e) {
    echo "Caught {$e->getMessage()}\n";
}

?>
--EXPECT--
string(50) "000000021704546573741401110470726f701a0014010e0100"
In __unserialize
Caught bad prop
In __destruct
In __destructPK!j�\|�����tests/__serialize_003.phptnu�[���--TEST--
__serialize() mechanism (003): Interoperability of different serialization mechanisms
--SKIPIF--
<?php if (PHP_VERSION_ID < 70400) { echo "skip __serialize/__unserialize not supported in php < 7.4 for compatibility with serialize()"; } ?>
--INI--
; Note that php 8.1 deprecates using Serializable without __serialize/__unserialize but we are testing Serialize for igbinary. Suppress deprecations.
error_reporting=E_ALL & ~E_DEPRECATED
--FILE--
<?php

class Vest implements Serializable {
    public function serialize() {
        echo "serialize() called\n";
        return "payload";
    }
    public function unserialize($payload) {
    }
}
class Test implements Serializable {
    public function __sleep() {
        echo "__sleep() called\n";
    }

    public function __wakeup() {
        echo "__wakeup() called\n";
    }

    public function __serialize() {
        echo "__serialize() called\n";
        return ["key" => "value"];
    }

    public function __unserialize(array $data) {
        echo "__unserialize() called\n";
        var_dump($data);
    }

    public function serialize() {
        echo "serialize() called\n";
        return "payload";
    }

    public function unserialize($payload) {
        echo "unserialize() called\n";
        var_dump($payload);
    }
}

$test = new Test;
var_dump(bin2hex($s = igbinary_serialize($test)));
var_dump(igbinary_unserialize($s));

var_dump(igbinary_unserialize(hex2bin('000000021704546573741d077061796c6f6164')));

?>
--EXPECT--
__serialize() called
string(48) "00000002170454657374140111036b6579110576616c7565"
__unserialize() called
array(1) {
  ["key"]=>
  string(5) "value"
}
object(Test)#2 (0) {
}
unserialize() called
string(7) "payload"
object(Test)#2 (0) {
}
PK"j�\�r�;��tests/igbinary_017.phptnu�[���--TEST--
Object test, __wakeup
--SKIPIF--
--FILE--
<?php
if(!extension_loaded('igbinary')) {
	dl('igbinary.' . PHP_SHLIB_SUFFIX);
}

function test($type, $variable, $test) {
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);

	echo $type, "\n";
	echo substr(bin2hex($serialized), 8), "\n";
	echo $test || $unserialized->b == 3 ? 'OK' : 'ERROR';
	echo "\n";
}

class Obj {
	var $a;
	var $b;

	function __construct($a, $b) {
		$this->a = $a;
		$this->b = $b;
	}

	function __wakeup() {
		$this->b = $this->a * 3;
	}
}

$o = new Obj(1, 2);


test('object', $o, false);

/*
 * you can add regression tests for your extension here
 *
 * the output of your test code has to be equal to the
 * text in the --EXPECT-- section below for the tests
 * to pass, differences between the output and the
 * expected text are interpreted as failure
 *
 * see TESTING.md for further information on
 * writing regression tests
 */
?>
--EXPECT--
object
17034f626a140211016106011101620602
OK
PK"j�\�x2��tests/igbinary_046c.phptnu�[���--TEST--
Correctly unserialize multiple array refs.
--SKIPIF--
--INI--
igbinary.compact_strings = On
--FILE--
<?php
$a = array(array());
$a[1] = &$a[0];
$a[2] = &$a[1];
$a[3] = &$a[2];
printf("%s\n", serialize($a));
$ig_ser = igbinary_serialize($a);
printf("%s\n", bin2hex($ig_ser));
$ig = igbinary_unserialize($ig_ser);
printf("%s\n", serialize($ig));
$f = &$ig[3];
$f = 'V';
var_dump($ig);
--EXPECT--
a:4:{i:0;a:0:{}i:1;R:2;i:2;R:2;i:3;R:2;}
0000000214040600251400060125010106022501010603250101
a:4:{i:0;a:0:{}i:1;R:2;i:2;R:2;i:3;R:2;}
array(4) {
  [0]=>
  &string(1) "V"
  [1]=>
  &string(1) "V"
  [2]=>
  &string(1) "V"
  [3]=>
  &string(1) "V"
}
PK"j�\"}���tests/igbinary_088.phptnu�[���--TEST--
Test serializing wrong values in __sleep
--SKIPIF--
<?php if (!extension_loaded("igbinary")) print "skip"; ?>
--FILE--
<?php
#[AllowDynamicProperties]
class X {
    public function __sleep() {
        return $this;
    }
}
$x = new X();
for ($i = 0; $i < 3; $i++) {
    $x->{"p$i"} = "name$i";
}
$ser = igbinary_serialize($x);
$unser = igbinary_unserialize($ser);
echo str_replace(['\\', '%'], ['\\\\', '\x'], urlencode($ser)), "\n";
var_dump($unser);

?>
--EXPECTF--
Notice: igbinary_serialize(): "name0" returned as member variable from __sleep() but does not exist in %s on line 12

Notice: igbinary_serialize(): "name1" returned as member variable from __sleep() but does not exist in %s on line 12

Notice: igbinary_serialize(): "name2" returned as member variable from __sleep() but does not exist in %s on line 12
\x00\x00\x00\x02\x17\x01X\x14\x03\x11\x05name0\x00\x11\x05name1\x00\x11\x05name2\x00
object(X)#2 (3) {
  ["name0"]=>
  NULL
  ["name1"]=>
  NULL
  ["name2"]=>
  NULL
}PK"j�\\V���tests/igbinary_075.phptnu�[���--TEST--
igbinary and not enough data for array
--FILE--
<?php
set_error_handler(function ($errno, $errstr) {
    echo "$errstr\n";
});
class X {}
var_dump(bin2hex($s = igbinary_serialize(new X())));
echo "One byte\n";
var_dump(igbinary_unserialize("\x00\x00\x00\x02\x17\x01\x58\x14"));
echo "Two byte\n";
var_dump(igbinary_unserialize("\x00\x00\x00\x02\x17\x01\x58\x15"));
igbinary_unserialize("\x00\x00\x00\x02\x17\x01\x58\x15\xff");
echo "Four byte\n";
var_dump(igbinary_unserialize("\x00\x00\x00\x02\x17\x01\x58\x16"));
igbinary_unserialize("\x00\x00\x00\x02\x17\x01\x58\x16\x00\x00\x01");
?>
--EXPECTF--
string(18) "000000021701581400"
One byte
igbinary_unserialize_object_properties: end-of-data
NULL
Two byte
igbinary_unserialize_object_properties: end-of-data
NULL
igbinary_unserialize_object_properties: end-of-data
Four byte
igbinary_unserialize_object_properties: end-of-data
NULL
igbinary_unserialize_object_properties: end-of-dataPK"j�\�q����tests/igbinary_062.phptnu�[���--TEST--
igbinary should not call __wakeup() if Serializable::unserialize was used to unserialize the object data (like `unserialize`)
--INI--
; Note that php 8.1 deprecates using Serializable without __serialize/__unserialize but we are testing Serialize for igbinary. Suppress deprecations.
error_reporting=E_ALL & ~E_DEPRECATED
--FILE--
<?php

class A implements Serializable {
   public $prop = 'value';
   public function serialize() {
       echo "In serialize " . $this->prop . "\n";
       return $this->prop;
   }
   public function unserialize($data) {
       echo "In unserialize $data\n";
       $this->prop = $data;
   }

   public function __wakeup() {
       echo "In __wakeup, unexpectedly\n";
   }
}

function testA() {
  $a = new A();
  $a->prop = 'other';
  $ser = serialize($a);
  $b = unserialize($ser);
  var_dump($b);

  $c = new A();
  $c->prop = 'igprop';
  $serC = igbinary_serialize($c);
  echo bin2hex($serC) . "\n";
  $d = igbinary_unserialize($serC);
  var_dump($d);

}

testA();
?>
--EXPECTF--
In serialize other
In unserialize other
object(A)#%d (1) {
  ["prop"]=>
  string(5) "other"
}
In serialize igprop
000000021701411d06696770726f70
In unserialize igprop
object(A)#%d (1) {
  ["prop"]=>
  string(6) "igprop"
}
PK#j�\Ծ��
�
tests/__serialize_016.phptnu�[���--TEST--
__serialize() mechanism (016): Properties are still typed after unserialization (references)
--SKIPIF--
<?php
if (PHP_VERSION_ID < 70400) { echo "skip __serialize/__unserialize not supported in php < 7.4 for compatibility with serialize()"; }
if (PHP_VERSION_ID >= 80000) { echo "skip different error message format"; }
?>
--FILE--
<?php
declare(strict_types=1);

class Test {
    public int $i = 0;
    public ?string $s = 's';
    public object $o;
    public stdClass $stdClass;
    public array $a = [];
}
$t = new Test();
$t->i = 1;
$t->s = 'other';
$t->o = $t;
$t->std = (object)['key' => 'value'];
$t->a = [&$t->std, &$t->i, &$t->s, &$t->o];
$t->std->key = &$t->a;
var_dump($t);

var_dump(bin2hex($s = igbinary_serialize($t)));
$t2 = igbinary_unserialize($s);
var_dump($t2);
try {
    $t2->i = 'x';
} catch (Error $e) {
    echo "i: " . $e->getMessage() . "\n";
}
$t2->s = null;
try {
    $t2->s = false;
} catch (Error $e) {
    echo "s: " . $e->getMessage() . "\n";
}
$t2->s = 'other';
try {
    $t2->o = null;
} catch (Error $e) {
    echo "o: " . $e->getMessage() . "\n";
}
try {
    $t2->a = null;
} catch (Error $e) {
    echo "a: " . $e->getMessage() . "\n";
}
try {
    $t2->stdClass = $t;
} catch (Error $e) {
    echo "stdClass: " . $e->getMessage() . "\n";
}
try {
    $t2->a = $t2;
} catch (Error $e) {
    echo "a: " . $e->getMessage() . "\n";
}
var_dump($t2);
--EXPECT--
object(Test)#1 (5) {
  ["i"]=>
  &int(1)
  ["s"]=>
  &string(5) "other"
  ["o"]=>
  *RECURSION*
  ["stdClass"]=>
  uninitialized(stdClass)
  ["a"]=>
  &array(4) {
    [0]=>
    &object(stdClass)#2 (1) {
      ["key"]=>
      *RECURSION*
    }
    [1]=>
    &int(1)
    [2]=>
    &string(5) "other"
    [3]=>
    *RECURSION*
  }
  ["std"]=>
  &object(stdClass)#2 (1) {
    ["key"]=>
    &array(4) {
      [0]=>
      *RECURSION*
      [1]=>
      &int(1)
      [2]=>
      &string(5) "other"
      [3]=>
      *RECURSION*
    }
  }
}
string(176) "0000000217045465737414061101692506011101732511056f7468657211016f252200001101612514040600251708737464436c617373140111036b65792501030601250101060225010206032522001103737464252204"
object(Test)#3 (5) {
  ["i"]=>
  &int(1)
  ["s"]=>
  &string(5) "other"
  ["o"]=>
  *RECURSION*
  ["stdClass"]=>
  uninitialized(stdClass)
  ["a"]=>
  &array(4) {
    [0]=>
    &object(stdClass)#4 (1) {
      ["key"]=>
      *RECURSION*
    }
    [1]=>
    &int(1)
    [2]=>
    &string(5) "other"
    [3]=>
    *RECURSION*
  }
  ["std"]=>
  &object(stdClass)#4 (1) {
    ["key"]=>
    &array(4) {
      [0]=>
      *RECURSION*
      [1]=>
      &int(1)
      [2]=>
      &string(5) "other"
      [3]=>
      *RECURSION*
    }
  }
}
i: Typed property Test::$i must be int, string used
s: Typed property Test::$s must be string or null, bool used
o: Typed property Test::$o must be object, null used
a: Typed property Test::$a must be array, null used
stdClass: Typed property Test::$stdClass must be an instance of stdClass, Test used
a: Typed property Test::$a must be array, Test used
object(Test)#3 (5) {
  ["i"]=>
  &int(1)
  ["s"]=>
  &string(5) "other"
  ["o"]=>
  *RECURSION*
  ["stdClass"]=>
  uninitialized(stdClass)
  ["a"]=>
  &array(4) {
    [0]=>
    &object(stdClass)#4 (1) {
      ["key"]=>
      *RECURSION*
    }
    [1]=>
    &int(1)
    [2]=>
    &string(5) "other"
    [3]=>
    *RECURSION*
  }
  ["std"]=>
  &object(stdClass)#4 (1) {
    ["key"]=>
    &array(4) {
      [0]=>
      *RECURSION*
      [1]=>
      &int(1)
      [2]=>
      &string(5) "other"
      [3]=>
      *RECURSION*
    }
  }
}PK#j�\�;��KKtests/igbinary_080.phptnu�[���--TEST--
igbinary with hash collision serializing strings
--FILE--
<?php
$var=['id'=>"3010480803", 'user_id'=>12346];
$serialized = igbinary_serialize($var);
$unserialized = igbinary_unserialize($serialized);
var_dump($unserialized);
$var=['id'=>"3010480803", 'user_id'=>"3010480804"];
$serialized = igbinary_serialize($var);
$unserialized = igbinary_unserialize($serialized);
var_dump($unserialized);
?>
--EXPECT--
array(2) {
  ["id"]=>
  string(10) "3010480803"
  ["user_id"]=>
  int(12346)
}
array(2) {
  ["id"]=>
  string(10) "3010480803"
  ["user_id"]=>
  string(10) "3010480804"
}
PK#j�\�,y�tests/igbinary_050.phptnu�[���--TEST--
Correctly unserialize cyclic object references
--SKIPIF--
--INI--
igbinary.compact_strings = On
--FILE--
<?php
$a = new stdClass();
$a->foo = &$a;
$a->bar = &$a;
$b = new stdClass();
$b->cyclic = &$a;
printf("%s\n", serialize($b));
$ig_ser = igbinary_serialize($b);
printf("%s\n", bin2hex($ig_ser));
$ig = igbinary_unserialize($ig_ser);
printf("%s\n", serialize($ig));
var_dump($ig);
$f = &$ig->cyclic->foo;
$f = 'V';
var_dump($ig);
// Note: While the php7 unserializer consistently makes a distinction between refs to an object and non-refs,
// the php5 serializer does not.
--EXPECTF--
O:8:"stdClass":1:{s:6:"cyclic";O:8:"stdClass":2:{s:3:"foo";R:2;s:3:"bar";R:2;}}
000000021708737464436c617373140111066379636c6963251a0014021103666f6f2522011103626172252201
O:8:"stdClass":1:{s:6:"cyclic";O:8:"stdClass":2:{s:3:"foo";R:2;s:3:"bar";R:2;}}
object(stdClass)#3 (1) {
  ["cyclic"]=>
  &object(stdClass)#4 (2) {
    ["foo"]=>
    *RECURSION*
    ["bar"]=>
    *RECURSION*
  }
}
object(stdClass)#3 (1) {
  ["cyclic"]=>
  &string(1) "V"
}
PK#j�\SH��tests/igbinary_064.phptnu�[���--TEST--
Works when there are hash collisions in strings when serializing.
--SKIPIF--
<?php
if(!extension_loaded('igbinary')) {
    echo "skip no igbinary";
}
?>
--FILE--
<?php

#[AllowDynamicProperties]
class Fy{
    public $EzFy = 2;
    public function __construct($x) {
        $this->x = $x;
    }
}
class Ez {
    public $FyEz = 'EzEz';
}

class G8 {
    public $FyG8;
}

$data = array(new Fy('G8G8'), new Fy('EzG8'), new Ez(), new G8(), new Ez(), 'G8' => new G8(), 'F8Ez' => new G8(), array(new G8()));
var_dump($data);
echo "\n";
$str = igbinary_serialize($data);
echo bin2hex($str) . "\n";
$unserialized = igbinary_unserialize($str);
var_dump($unserialized);
echo "\n";
var_export(serialize($data) === serialize($unserialized));
?>
--EXPECT--
array(8) {
  [0]=>
  object(Fy)#1 (2) {
    ["EzFy"]=>
    int(2)
    ["x"]=>
    string(4) "G8G8"
  }
  [1]=>
  object(Fy)#2 (2) {
    ["EzFy"]=>
    int(2)
    ["x"]=>
    string(4) "EzG8"
  }
  [2]=>
  object(Ez)#3 (1) {
    ["FyEz"]=>
    string(4) "EzEz"
  }
  [3]=>
  object(G8)#4 (1) {
    ["FyG8"]=>
    NULL
  }
  [4]=>
  object(Ez)#5 (1) {
    ["FyEz"]=>
    string(4) "EzEz"
  }
  ["G8"]=>
  object(G8)#6 (1) {
    ["FyG8"]=>
    NULL
  }
  ["F8Ez"]=>
  object(G8)#7 (1) {
    ["FyG8"]=>
    NULL
  }
  [5]=>
  array(1) {
    [0]=>
    object(G8)#8 (1) {
      ["FyG8"]=>
      NULL
    }
  }
}

00000002140806001702467914021104457a4679060211017811044738473806011a0014020e0106020e021104457a473806021702457a140111044679457a1104457a457a06031702473814011104467947380006041a0514010e060e070e081a0814010e090011044638457a1a0814010e09000605140106001a0814010e0900
array(8) {
  [0]=>
  object(Fy)#9 (2) {
    ["EzFy"]=>
    int(2)
    ["x"]=>
    string(4) "G8G8"
  }
  [1]=>
  object(Fy)#10 (2) {
    ["EzFy"]=>
    int(2)
    ["x"]=>
    string(4) "EzG8"
  }
  [2]=>
  object(Ez)#11 (1) {
    ["FyEz"]=>
    string(4) "EzEz"
  }
  [3]=>
  object(G8)#12 (1) {
    ["FyG8"]=>
    NULL
  }
  [4]=>
  object(Ez)#13 (1) {
    ["FyEz"]=>
    string(4) "EzEz"
  }
  ["G8"]=>
  object(G8)#14 (1) {
    ["FyG8"]=>
    NULL
  }
  ["F8Ez"]=>
  object(G8)#15 (1) {
    ["FyG8"]=>
    NULL
  }
  [5]=>
  array(1) {
    [0]=>
    object(G8)#16 (1) {
      ["FyG8"]=>
      NULL
    }
  }
}

true
PK$j�\_��tests/__serialize_010.phptnu�[���--TEST--
__serialize() mechanism (010): handle references in array returned by __serialize
--SKIPIF--
<?php if (PHP_VERSION_ID < 70400) { echo "skip __serialize/__unserialize not supported in php < 7.4 for compatibility with serialize()"; } ?>
--FILE--
<?php

class Test {
    public $prop;
    public $prop2;
    public function __serialize() {
        return [$this->prop, $this->prop2];
    }
    public function __unserialize(array $data) {
        $this->prop = $data[0];
        $this->prop2 = $data[1];
        if (!$this->prop) {
            throw new RuntimeException("Threw from __unserialize");
        }
    }

    public function __destruct() {
        // should not be called
        echo "Called destruct\n";
    }
}

$test = new Test;
$test->prop = &$test;
$test->prop2 = [&$test];
var_dump(bin2hex($s = igbinary_serialize($test)));
var_dump(igbinary_unserialize($s));
unset($test->prop);
$test->prop = false;
var_dump(bin2hex($s = igbinary_serialize($test)));
try {
    igbinary_unserialize($s);
} catch (RuntimeException $e) {
    echo "message={$e->getMessage()}\n";

}
echo "Calling gc_collect_cycles\n";
gc_collect_cycles();
echo "After call to gc_collect_cycles\n";

?>
--EXPECT--
string(50) "00000002170454657374140206002200060114010600252200"
object(Test)#2 (2) {
  ["prop"]=>
  *RECURSION*
  ["prop2"]=>
  array(1) {
    [0]=>
    *RECURSION*
  }
}
string(48) "000000021704546573741402060004060114010600252200"
message=Threw from __unserialize
Calling gc_collect_cycles
Called destruct
After call to gc_collect_cycles
Called destructPK$j�\
-$AA(tests/typed_property_ref_overwrite2.phptnu�[���--TEST--
Overwriting a typed property that is not yet a reference
--SKIPIF--
<?php if (PHP_VERSION_ID < 70400) die("skip php 7.4+"); ?>
--FILE--
<?php

class Test {
    public $drop;
    public ?Test $prop;
}
$orig = new Test();
$orig->drop = null;
$orig->prop = new Test();
$orig->prop->prop = &$orig->prop;
$ser = igbinary_serialize($orig);
echo urlencode($ser), "\n";

$ser2 = str_replace('drop', 'prop', $ser);
$result = igbinary_unserialize($ser2);
var_dump($result);
try {
    $result->prop = 1;
} catch (TypeError $e) {
    printf("Caught %s\n", get_class($e));
}

?>
--EXPECT--
%00%00%00%02%17%04Test%14%02%11%04drop%00%11%04prop%25%1A%00%14%02%0E%01%00%0E%02%25%22%01
object(Test)#3 (2) {
  ["drop"]=>
  NULL
  ["prop"]=>
  &object(Test)#4 (2) {
    ["drop"]=>
    NULL
    ["prop"]=>
    *RECURSION*
  }
}
Caught TypeError
PK$j�\�؏7��tests/igbinary_049b.phptnu�[���--TEST--
Correctly unserialize multiple references in objects
--SKIPIF--
--INI--
igbinary.compact_strings = On
--FILE--
<?php
class Foo{}
$a = new stdClass();
$a->x0 = NULL;
$a->x1 = &$a->x0;
$a->x2 = &$a->x1;
$a->x3 = &$a->x2;
$a->x4 = false;
$a->x5 = &$a->x4;
$a->x6 = new Foo();
$a->x7 = &$a->x6;
$a->x8 = &$a->x7;
$a->x9 = array(33);
$a->x10 = new stdClass();
$a->x10->prop = &$a->x8;
$a->x11 = &$a->x10;
$a->x12 = $a->x9;
$ig_ser = igbinary_serialize($a);
printf("ig_ser=%s\n", bin2hex($ig_ser));
$ig = igbinary_unserialize($ig_ser);
$f = &$ig->x3;
$f = 'V';
$g = &$ig->x5;
$g = 'H';
$h = $ig->x10;
$h->prop = 'S';
var_dump($ig);
--EXPECTF--
ig_ser=000000021708737464436c617373140d1102783025001102783125010111027832250101110278332501011102783425041102783525010211027836251703466f6f14001102783725220311027838252203110278391401060006211103783130251a001401110470726f70252203110378313125220511037831320104
object(stdClass)#%d (13) {
  ["x0"]=>
  &string(1) "V"
  ["x1"]=>
  &string(1) "V"
  ["x2"]=>
  &string(1) "V"
  ["x3"]=>
  &string(1) "V"
  ["x4"]=>
  &string(1) "H"
  ["x5"]=>
  &string(1) "H"
  ["x6"]=>
  &string(1) "S"
  ["x7"]=>
  &string(1) "S"
  ["x8"]=>
  &string(1) "S"
  ["x9"]=>
  array(1) {
    [0]=>
    int(33)
  }
  ["x10"]=>
  &object(stdClass)#%d (1) {
    ["prop"]=>
    &string(1) "S"
  }
  ["x11"]=>
  &object(stdClass)#%d (1) {
    ["prop"]=>
    &string(1) "S"
  }
  ["x12"]=>
  array(1) {
    [0]=>
    int(33)
  }
}
PK%j�\�0�"��tests/igbinary_029.phptnu�[���--TEST--
Igbinary module info
--SKIPIF--
<?php if (!extension_loaded("igbinary")) print "skip";

?>
--FILE--
<?php
ob_start();
phpinfo(INFO_MODULES);
$str = ob_get_clean();

$array = explode("\n", $str);
$array = preg_grep('/^igbinary/', $array);

echo implode("\n", $array);

--EXPECTF--
igbinary
igbinary support => enabled
igbinary version => %s
igbinary AP%s serializer ABI => %s
igbinary session support => %s
igbinary.compact_strings => %s => %s
PK%j�\C �H	H	$tests/typed_property_refs_php74.phptnu�[���--TEST--
unserialize with references to typed properties shall skip the references or fail
--SKIPIF--
<?php if (PHP_VERSION_ID < 70400 || PHP_VERSION_ID >= 80000) die("skip requires php 7.4 error message"); ?>
--FILE--
<?php

class X {
    public $a;
    public $b;
}

class A {
    public int $a;
    public $b;
}

class B {
    public $a;
    public int $b;
}

class E {
    public $a;
    public int $b;
}

class C {
    public int $a;
    public string $b;
}

class D {
    public int $a;
    public float $b;
}
function create_ser($value): string {
    $v = new X();
    $v->a = $value;
    $v->b = &$v->a;
    $ser = igbinary_serialize($v);
    printf("for %s: %s\n", var_export($value, true), urlencode($ser));
    return $ser;
}
$serInt = create_ser(1);
$serNull = create_ser(null);
$serStr = create_ser('x');
var_dump(igbinary_unserialize(str_replace('X', 'A', $serInt)));
var_dump(igbinary_unserialize(str_replace('X', 'B', $serInt)));
var_dump(igbinary_unserialize(str_replace('X', 'E', $serInt)));

try {
    var_dump(igbinary_unserialize(str_replace('X', 'A', $serNull)));
} catch (TypeError $e) {
    echo $e->getMessage(), "\n";
}
try {
    var_dump(igbinary_unserialize(str_replace('X', 'B', $serNull)));
} catch (TypeError $e) {
    echo $e->getMessage(), "\n";
}
try {
    var_dump(igbinary_unserialize(str_replace('X', 'C', $serInt)));
} catch (TypeError $e) {
    echo $e->getMessage(), "\n";
}
try {
    var_dump(igbinary_unserialize(str_replace('X', 'C', $serStr)));
} catch (TypeError $e) {
    echo $e->getMessage(), "\n";
}
try {
    var_dump(igbinary_unserialize(str_replace('X', 'D', $serInt)));
} catch (TypeError $e) {
    echo $e->getMessage(), "\n";
}

?>
--EXPECT--
for 1: %00%00%00%02%17%01X%14%02%11%01a%25%06%01%11%01b%25%01%01
for NULL: %00%00%00%02%17%01X%14%02%11%01a%25%00%11%01b%25%01%01
for 'x': %00%00%00%02%17%01X%14%02%11%01a%25%11%01x%11%01b%25%01%01
object(A)#1 (2) {
  ["a"]=>
  &int(1)
  ["b"]=>
  &int(1)
}
object(B)#1 (2) {
  ["a"]=>
  &int(1)
  ["b"]=>
  &int(1)
}
object(E)#1 (2) {
  ["a"]=>
  &int(1)
  ["b"]=>
  &int(1)
}
Typed property A::$a must be int, null used
Typed property B::$b must be int, null used
Typed property C::$b must be string, int used
Typed property C::$a must be int, string used
Reference with value of type int held by property D::$a of type int is not compatible with property D::$b of type float
PK%j�\�Ɗ�

tests/igbinary_079.phptnu�[���--TEST--
igbinary and many arrays
--FILE--
<?php
function generate_test_array(int $n) : array {
    $result = [];
    for ($i = 0; $i < $n; $i++) {
        $result[] = [$i];
    }
    // Validate that igbinary properly serializes and unserializes the references to arrays created earlier
    for ($i = 0; $i < $n; $i++) {
        $result[] = $result[$i];
    }
    return $result;
}
$small = generate_test_array(2);
var_dump(bin2hex($s = igbinary_serialize($small)));
var_dump(igbinary_unserialize($s));
$medium = generate_test_array(1 << 8);
var_dump(igbinary_unserialize(igbinary_serialize($medium)) === $medium);
$large = generate_test_array(1 << 16);
var_dump(igbinary_unserialize(igbinary_serialize($large)) === $large);
?>
--EXPECTF--
string(60) "000000021404060014010600060006011401060006010602010106030102"
array(4) {
  [0]=>
  array(1) {
    [0]=>
    int(0)
  }
  [1]=>
  array(1) {
    [0]=>
    int(1)
  }
  [2]=>
  array(1) {
    [0]=>
    int(0)
  }
  [3]=>
  array(1) {
    [0]=>
    int(1)
  }
}
bool(true)
bool(true)
PK&j�\l�oҺ�tests/igbinary_026b.phptnu�[���--TEST--
Cyclic array test 2
--INI--
report_memleaks=0
--SKIPIF--
<?php
if (!extension_loaded('igbinary')) {
	echo "skip no igbinary";
}
if (PHP_MAJOR_VERSION > 7) {
	echo "skip requires php 7.x\n";
}
--FILE--
<?php

$a = array("foo" => &$b);
$b = array(1, 2, $a);

/* all three statements below should produce same output however PHP stock
 * unserialize/serialize produces different output (5.2.16). I consider this is
 * a PHP bug. - Oleg Grenrus
 */

//$k = $a;
//$k = unserialize(serialize($a));
$k = igbinary_unserialize(igbinary_serialize($a));

function check($a, $k) {
	ob_start();
	var_dump($a);
	$a_str = ob_get_clean();
	ob_start();
	var_dump($k);
	$k_str = ob_get_clean();

	if ($a_str !== $k_str) {
		echo "Output differs\n";
		echo "Expected:\n", $a_str, "\n";
		echo "Actual:\n", $k_str, "\n";
	} else {
		echo "OK\n";
	}
}

check($a, $k);

$a["foo"][2]["foo"][1] = "b";
$k["foo"][2]["foo"][1] = "b";

check($a, $k);

?>
--EXPECT--
OK
OK
PK&j�\}�xu4	4	tests/__serialize_018.phptnu�[���--TEST--
__serialize() freed on unserialize exception without calling destructor.
--SKIPIF--
<?php if (PHP_VERSION_ID < 70400) { echo "skip __serialize/__unserialize not supported in php < 7.4 for compatibility with serialize()"; } ?>
--INI--
; Note that php 8.1 deprecates using Serializable without __serialize/__unserialize but we are testing Serialize for igbinary. Suppress deprecations.
error_reporting=E_ALL & ~E_DEPRECATED
--FILE--
<?php
class ThrowsInUnserialize implements Serializable {
    public function serialize() {
        return "test data";
    }

    public function unserialize($ser) {
        echo "Unserializing $ser\n";
        throw new Error($ser);
    }

    public function __destruct() {
        echo "In __destruct ThrowsInUnserialize\n";
    }
}

class Test {
    public $prop;
    public $prop2;
    public function __serialize() {
        return [0 => $this->prop, "value" => $this->prop2];
    }
    public function __unserialize(array $data) {
        echo "In __unserialize Test\n";
    }

    public function __destruct() {
        echo "In __destruct Test\n";
    }
}

$test = new Test;
$test->prop = new ThrowsInUnserialize();
$test->prop2 = "barfoo";
var_dump(bin2hex($s = igbinary_serialize($test)));
try {
    var_dump(igbinary_unserialize($s));
} catch (Error $e) {
    echo "Caught: {$e->getMessage()}\n";
}
gc_collect_cycles();
echo "After gc_collect_cycles\n";
unset($test);
gc_collect_cycles();

echo "And for serialize/unserialize\n";
$test = new Test;
$test->prop = new ThrowsInUnserialize();
$test->prop2 = "barfoo";

var_dump(bin2hex($s = serialize($test)));
try {
    var_dump(unserialize($s));
} catch (Error $e) {
    echo "Caught: {$e->getMessage()}\n";
}
?>
--EXPECT--
string(122) "000000021704546573741402060017135468726f7773496e556e73657269616c697a651d09746573742064617461110576616c75651106626172666f6f"
Unserializing test data
In __destruct ThrowsInUnserialize
Caught: test data
After gc_collect_cycles
In __destruct Test
In __destruct ThrowsInUnserialize
And for serialize/unserialize
string(168) "4f3a343a2254657374223a323a7b693a303b433a31393a225468726f7773496e556e73657269616c697a65223a393a7b7465737420646174617d733a353a2276616c7565223b733a363a22626172666f6f223b7d"
Unserializing test data
In __destruct ThrowsInUnserialize
Caught: test data
In __destruct Test
In __destruct ThrowsInUnserializePK&j�\��:MMtests/igbinary_015.phptnu�[���--TEST--
Check for serialization handler
--SKIPIF--
<?php
if (!extension_loaded('session')) {
	exit('skip session extension not loaded');
}

ob_start();
phpinfo(INFO_MODULES);
$str = ob_get_clean();

$array = explode("\n", $str);
$array = preg_grep('/^igbinary session support.*yes/', $array);
if (!$array) {
	exit('skip igbinary session handler not available');
}

--FILE--
<?php

$output = '';

function open($path, $name) {
	return true;
}

function close() {
	return true;
}

function read($id) {
	global $output;
	return pack('H*', '0000000214011103666f6f0601');
}

function write($id, $data) {
	global $output;
	$output .= substr(bin2hex($data), 8). "\n";
	return true;
}

function destroy($id) {
	return true;
}

function gc($time) {
	return true;
}

ini_set('session.serialize_handler', 'igbinary');

session_set_save_handler('open', 'close', 'read', 'write', 'destroy', 'gc');

session_start();

echo ++$_SESSION['foo'], "\n";

session_write_close();

echo $output;

/*
 * you can add regression tests for your extension here
 *
 * the output of your test code has to be equal to the
 * text in the --EXPECT-- section below for the tests
 * to pass, differences between the output and the
 * expected text are interpreted as failure
 *
 * see TESTING.md for further information on
 * writing regression tests
 */
?>
--EXPECT--
2
14011103666f6f0602
PK&j�\wZ���!tests/igbinary_enums_3_php83.phptnu�[���--TEST--
Test unserializing valid enums inferring value
--SKIPIF--
<?php if (PHP_VERSION_ID < 80300) { echo "skip non-compile time constant in enums requires php 8.3"; } ?>
--FILE--
<?php

enum X: string {
    case X = X;
}
$x = 'X';
define('X', "dynamic$x");
$value = urldecode('%00%00%00%02%17%01X%27%0E%00');
var_dump(igbinary_unserialize($value));
$ser = igbinary_serialize(X::X);
echo urlencode($ser), "\n";
var_dump(X::X->value);
?>
--EXPECT--
enum(X::X)
%00%00%00%02%17%01X%27%0E%00
string(8) "dynamicX"
PK'j�\�]4sstests/igbinary_034.phptnu�[���--TEST--
Unserialize invalid random data
--SKIPIF--
<?php
if(!extension_loaded('igbinary')) {
	echo "skip no igbinary";
}
--FILE--
<?php

$datas = array(
	87817,
	-1,
	array(1,2,3,"testing" => 10, "foo"),
	true,
	false,
	0.187182,
	"dakjdh98389\000",
	null,
	(object)array(1,2,3),
);

error_reporting(0);
foreach ($datas as $data) {
	$str = igbinary_serialize($data);
	$len = strlen($str);

	for ($j = 0; $j < 200; $j++) {
		for ($i = 0; $i < $len - 1; $i++) {
			$sub = substr($str, 0, $i);
			$sub .= mcrypt_create_iv(30, MCRYPT_DEV_URANDOM);
			$php_errormsg = null;
			$v = igbinary_unserialize($sub);
		}
	}
}

--EXPECT--
PK'j�\�s���tests/igbinary_009.phptnu�[���--TEST--
Check for reference serialisation
--SKIPIF--
<?php
if(!extension_loaded('igbinary')) {
	echo "skip no igbinary";
}
--FILE--
<?php

function test($type, $variable, $normalize = false) {
	// Canonicalize $variable
	if ($normalize) {
		$variable = unserialize(serialize($variable));
	}
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);


	$serialize_act = serialize($unserialized);
	$serialize_exp = serialize($variable);

	echo $type, "\n";
	echo substr(bin2hex($serialized), 8), "\n";
	echo $serialize_act === $serialize_exp ? 'OK' : 'ERROR', "\n";

	ob_start();
	var_dump($variable);
	$dump_exp = ob_get_clean();
	ob_start();
	var_dump($unserialized);
	$dump_act = ob_get_clean();

	if ($dump_act !== $dump_exp) {
		echo "But var dump differs:\nActual:\n", $dump_act, "\nExpected\n", $dump_exp, "\n";
		if ($normalize) {
			echo "(Was normalized)\n";
		}
	}

	if ($serialize_act !== $serialize_exp) {
		echo "But serialize differs:\nActual:\n", $serialize_act, "\nExpected:\n", $serialize_exp, "\n";
	}
}

$a = array('foo');

test('array($a, $a)', array($a, $a));
test('array(&$a, &$a)', array(&$a, &$a));

$a = array(null);
$b = array(&$a);
$a[0] = &$b;

test('cyclic $a = array(&array(&$a)) - normalized', $a, true);
--EXPECT--
array($a, $a)
14020600140106001103666f6f06010101
OK
array(&$a, &$a)
1402060025140106001103666f6f0601250101
OK
cyclic $a = array(&array(&$a)) - normalized
14010600251401060014010600250101
OK
PK'j�\�&L�KKtests/igbinary_091.phptnu�[���--TEST--
Check for handling of anonymous classes
--INI--
error_reporting=E_ALL & ~E_DEPRECATED
--FILE--
<?php
function check_serialize_throws($obj) {
    try {
        var_dump(serialize($obj));
    } catch (Throwable $e) {
        echo "Caught: " . $e->getMessage() . "\n";
    }
}
check_serialize_throws(new class () {});
// TODO: Update behavior based on https://bugs.php.net/bug.php?id=81111
/**
check_serialize_throws(new class () {
    public function __serialize() { return []; }
    public function __unserialize($value) { }
});
 */
check_serialize_throws(new class () implements Serializable {
    public function serialize() { return ''; }
    public function unserialize($ser) { return new self(); }
});
?>
--EXPECTF--
Caught: Serialization of 'class@anonymous' is not allowed
Caught: Serialization of '%s@anonymous' is not allowed
PK(j�\�*fftests/igbinary_021.phptnu�[���--TEST--
Object Serializable interface
--INI--
; Note that php 8.1 deprecates using Serializable without __serialize/__unserialize but we are testing Serialize for igbinary. Suppress deprecations.
error_reporting=E_ALL & ~E_DEPRECATED
--FILE--
<?php
if(!extension_loaded('igbinary')) {
	dl('igbinary.' . PHP_SHLIB_SUFFIX);
}

function test($type, $variable, $test) {
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);

	echo $type, "\n";
	echo substr(bin2hex($serialized), 8), "\n";
	echo $test || $unserialized == $variable ? 'OK' : 'ERROR';
	echo "\n";
}

class Obj implements Serializable {
	var $a;
	var $b;

	function __construct($a, $b) {
		$this->a = $a;
		$this->b = $b;
	}

	public function serialize() {
		return pack('NN', $this->a, $this->b);
	}

	public function unserialize($serialized) {
		$tmp = unpack('N*', $serialized);
		$this->__construct($tmp[1], $tmp[2]);
	}
}

$o = new Obj(1, 2);

test('object', $o, false);

/*
 * you can add regression tests for your extension here
 *
 * the output of your test code has to be equal to the
 * text in the --EXPECT-- section below for the tests
 * to pass, differences between the output and the
 * expected text are interpreted as failure
 *
 * see TESTING.md for further information on
 * writing regression tests
 */
?>
--EXPECT--
object
17034f626a1d080000000100000002
OK
PK(j�\��̝�tests/igbinary_055.phptnu�[���--TEST--
__wakeup can replace a copy of the object referring to the root node.
--FILE--
<?php

#[AllowDynamicProperties]
class Obj {
	function __construct($a) {
		$this->a = $a;
	}

	public function __wakeup() {
		echo "Calling __wakeup\n";
		$this->a = "replaced";
	}
}

$a = new stdClass();
$a->obj = new Obj($a);;
$serialized = igbinary_serialize($a);
printf("%s\n", bin2hex($serialized));
$unserialized = igbinary_unserialize($serialized);
var_dump($unserialized);
--EXPECTF--
000000021708737464436c617373140111036f626a17034f626a14011101612200
Calling __wakeup
object(stdClass)#%d (1) {
  ["obj"]=>
  object(Obj)#%d (1) {
    ["a"]=>
    string(8) "replaced"
  }
}
PK)j�\�����tests/__serialize_006.phptnu�[���--TEST--
__serialize() mechanism (006): DateTime
--SKIPIF--
<?php if (PHP_VERSION_ID < 70400) { echo "skip __serialize/__unserialize not supported in php < 7.4 for compatibility with serialize()"; } ?>
--FILE--
<?php

$dt = new DateTime('2019-12-08 12:34', new DateTimeZone('UTC'));
var_dump(bin2hex($s = igbinary_serialize($dt)));
var_dump(igbinary_unserialize($s));
$dt = new DateTime('2019-12-08 12:34', new DateTimeZone('Pacific/Nauru'));
var_dump(bin2hex($s = igbinary_serialize($dt)));
var_dump(igbinary_unserialize($s));

?>
--EXPECT--
string(164) "0000000217084461746554696d651403110464617465111a323031392d31322d30382031323a33343a30302e303030303030110d74696d657a6f6e655f747970650603110874696d657a6f6e651103555443"
object(DateTime)#2 (3) {
  ["date"]=>
  string(26) "2019-12-08 12:34:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(3) "UTC"
}
string(184) "0000000217084461746554696d651403110464617465111a323031392d31322d30382031323a33343a30302e303030303030110d74696d657a6f6e655f747970650603110874696d657a6f6e65110d506163696669632f4e61757275"
object(DateTime)#1 (3) {
  ["date"]=>
  string(26) "2019-12-08 12:34:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(13) "Pacific/Nauru"
}
PK)j�\�2��tests/igbinary_002.phptnu�[���--TEST--
Check for null serialisation
--SKIPIF--
--FILE--
<?php
if(!extension_loaded('igbinary')) {
	dl('igbinary.' . PHP_SHLIB_SUFFIX);
}

function test($type, $variable) {
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);

	echo $type, "\n";
	echo substr(bin2hex($serialized), 8), "\n";
	echo $unserialized === $variable ? 'OK' : 'ERROR';
	echo "\n";
}

test('null', null);

/*
 * you can add regression tests for your extension here
 *
 * the output of your test code has to be equal to the
 * text in the --EXPECT-- section below for the tests
 * to pass, differences between the output and the
 * expected text are interpreted as failure
 */
?>
--EXPECT--
null
00
OK
PK)j�\ŋ9�%%tests/igbinary_bug54662.phptnu�[���--TEST--
Nested objects cause segfault, php bug #54662
--SKIPIF--
<?php if (!extension_loaded("igbinary")) print "skip"; ?>
--FILE--
<?php
/**
 * Proof of concept, segmentation fault (spl_array.c/igbinary.c)
 * when using nested objects.
 *
 * @author Aleksey Korzun
 */

class Storage {
    public $storage = "a string";
}

$collection = new ArrayObject;
$collection->append(new Storage);

$ser = igbinary_serialize($collection);
$new_collection = igbinary_unserialize($ser);

var_dump($new_collection[0]->storage);
--EXPECT--
string(8) "a string"
PK*j�\nX��tests/igbinary_072.phptnu�[���--TEST--
igbinary and __PHP_INCOMPLETE_CLASS
--FILE--
<?php
// TODO: Remove temporary workaround for __PHP_Incomplete_Class missing #[AllowDynamicProperties]
if (PHP_VERSION_ID >= 80200) { require_once __DIR__ . '/php82_suppress_dynamic_properties_warning.inc'; }
class Test {}
function test_ser_unser($obj) {
    var_dump(bin2hex($s = igbinary_serialize($obj)));
    $s = str_replace('Test', 'Best', $s);
    $obj2 = igbinary_unserialize($s);
    var_dump($obj2);
    var_dump(bin2hex($s = igbinary_serialize($obj2)));
    var_dump(igbinary_unserialize($s));
}
test_ser_unser(new Test());
echo "Testing with properties\n";
$obj = new Test();
$obj->dynamicProp = 'value';
$obj->nullProp = null;
test_ser_unser($obj);
?>
--EXPECT--
string(24) "000000021704546573741400"
object(__PHP_Incomplete_Class)#2 (1) {
  ["__PHP_Incomplete_Class_Name"]=>
  string(4) "Best"
}
string(24) "000000021704426573741400"
object(__PHP_Incomplete_Class)#3 (1) {
  ["__PHP_Incomplete_Class_Name"]=>
  string(4) "Best"
}
Testing with properties
string(86) "000000021704546573741402110b64796e616d696350726f70110576616c756511086e756c6c50726f7000"
object(__PHP_Incomplete_Class)#1 (3) {
  ["__PHP_Incomplete_Class_Name"]=>
  string(4) "Best"
  ["dynamicProp"]=>
  string(5) "value"
  ["nullProp"]=>
  NULL
}
string(86) "000000021704426573741402110b64796e616d696350726f70110576616c756511086e756c6c50726f7000"
object(__PHP_Incomplete_Class)#3 (3) {
  ["__PHP_Incomplete_Class_Name"]=>
  string(4) "Best"
  ["dynamicProp"]=>
  string(5) "value"
  ["nullProp"]=>
  NULL
}PK*j�\0�Q��tests/igbinary_010.phptnu�[���--TEST--
Array test
--SKIPIF--
--FILE--
<?php
if(!extension_loaded('igbinary')) {
	dl('igbinary.' . PHP_SHLIB_SUFFIX);
}

function test($type, $variable, $test) {
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);

	echo $type, "\n";
	echo substr(bin2hex($serialized), 8), "\n";
	echo $test || $unserialized == $variable ? 'OK' : 'ERROR';
	echo "\n";
}

$a = array(
	'a' => array(
		'b' => 'c',
		'd' => 'e'
	),
	'f' => array(
		'g' => 'h'
	)
);

test('array', $a, false);

/*
 * you can add regression tests for your extension here
 *
 * the output of your test code has to be equal to the
 * text in the --EXPECT-- section below for the tests
 * to pass, differences between the output and the
 * expected text are interpreted as failure
 *
 * see TESTING.md for further information on
 * writing regression tests
 */
?>
--EXPECT--
array
140211016114021101621101631101641101651101661401110167110168
OK
PK+j�\����33tests/igbinary_041.phptnu�[���--TEST--
Check for double NaN, Inf, -Inf, 0, and -0. IEEE 754 doubles
--FILE--
<?php

function str2bin($bytestring) {
	$len = strlen($bytestring);
	$output = '';

	for ($i = 0; $i < $len; $i++) {
		$bin = decbin(ord($bytestring[$i]));
		$bin = str_pad($bin, 8, '0', STR_PAD_LEFT);
		$output .= $bin;
	}

	return $output;
}

function test($type, $variable) {
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);

	echo $type, ":\n";
	var_dump($variable);
	var_dump($unserialized);

	echo "   6         5         4         3         2         1\n";
	echo "3210987654321098765432109876543210987654321098765432109876543210\n";
	echo str2bin(substr($serialized, 5, 8)), "\n";
	echo "\n";
}

// exponent all-1, non zero mantissa
test('double NaN', NAN);

// sign 0, exp all-1, zero mantissa
test('double Inf', INF);

// sign 1, exp all-1, zero mantissa
test('double -Inf', -INF);

// sign 0, all-0
test('double 0.0', 0.0);

// sign 1, all-0
test('double -0.0', -1 * 0.0);

--EXPECTREGEX--
double NaN:
float\(NAN\)
float\(NAN\)
   6         5         4         3         2         1
3210987654321098765432109876543210987654321098765432109876543210
.111111111110*1.*

double Inf:
float\(INF\)
float\(INF\)
   6         5         4         3         2         1
3210987654321098765432109876543210987654321098765432109876543210
0111111111110000000000000000000000000000000000000000000000000000

double -Inf:
float\(-INF\)
float\(-INF\)
   6         5         4         3         2         1
3210987654321098765432109876543210987654321098765432109876543210
1111111111110000000000000000000000000000000000000000000000000000

double 0.0:
float\(0\)
float\(0\)
   6         5         4         3         2         1
3210987654321098765432109876543210987654321098765432109876543210
0000000000000000000000000000000000000000000000000000000000000000

double -0.0:
float\(-0\)
float\(-0\)
   6         5         4         3         2         1
3210987654321098765432109876543210987654321098765432109876543210
1000000000000000000000000000000000000000000000000000000000000000

PK+j�\N�.�{{tests/igbinary_032.phptnu�[���--TEST--
Object test, __sleep and __wakeup exceptions
--SKIPIF--
<?php
if(!extension_loaded('igbinary')) {
	echo "skip no igbinary";
}
--FILE--
<?php

function test($variable) {
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);
}

class Obj {
	private static $count = 0;
	var $a;
	var $b;

	function __construct($a, $b) {
		$this->a = $a;
		$this->b = $b;
	}

	function __sleep() {
		$c = self::$count++;
		if ($this->a) {
			throw new Exception("exception in __sleep $c");
		}
		return array('a', 'b');
	}

	function __wakeup() {
		$c = self::$count++;
		if ($this->b) {
			throw new Exception("exception in __wakeup $c");
		}
		$this->b = $this->a * 3;
	}
}


$a = new Obj(1, 0);
$b = new Obj(0, 1);
$c = new Obj(0, 0);

try {
	test($a);
} catch (Exception $e) {
	echo $e->getMessage(), "\n";
}

try {
	test($b);
} catch (Exception $e) {
	echo $e->getMessage(), "\n";
}

try {
	test($c);
} catch (Exception $e) {
	echo $e->getMessage(), "\n";
}

/*
 * you can add regression tests for your extension here
 *
 * the output of your test code has to be equal to the
 * text in the --EXPECT-- section below for the tests
 * to pass, differences between the output and the
 * expected text are interpreted as failure
 *
 * see TESTING.md for further information on
 * writing regression tests
 */
?>
--EXPECT--
exception in __sleep 0
exception in __wakeup 2
PK+j�\^�-X��tests/igbinary_052.phptnu�[���--TEST--
Object Serializable interface can be serialized in references
--INI--
; Note that php 8.1 deprecates using Serializable without __serialize/__unserialize but we are testing Serialize for igbinary. Suppress deprecations.
error_reporting=E_ALL & ~E_DEPRECATED
--FILE--
<?php
if(!extension_loaded('igbinary')) {
	dl('igbinary.' . PHP_SHLIB_SUFFIX);
}

function test($variable) {
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);
}

class Obj implements Serializable {
	private static $count = 1;

	public $a;
	public $b;

	function __construct($a, $b) {
		$this->a = $a;
		$this->b = $b;
	}

	public function serialize() {
		$c = self::$count++;
		echo "call serialize\n";
		return pack('NN', $this->a, $this->b);
	}

	public function unserialize($serialized) {
		$tmp = unpack('N*', $serialized);
		$this->__construct($tmp[1], $tmp[2]);
		$c = self::$count++;
		echo "call unserialize\n";
	}
}

function main() {
	$a = new Obj(1, 0);
	$b = new Obj(42, 43);
	$variable = array(&$a, &$a, $b);
	$serialized = igbinary_serialize($variable);
	printf("%s\n", bin2hex($serialized));
	$unserialized = igbinary_unserialize($serialized);
	var_dump($unserialized);
	$unserialized[0] = 'A';
	var_dump($unserialized[1]);
}
main();
--EXPECTF--
call serialize
call serialize
00000002140306002517034f626a1d080000000100000000060125220106021a001d080000002a0000002b
call unserialize
call unserialize
array(3) {
  [0]=>
  &object(Obj)#%d (2) {
    ["a"]=>
    int(1)
    ["b"]=>
    int(0)
  }
  [1]=>
  &object(Obj)#%d (2) {
    ["a"]=>
    int(1)
    ["b"]=>
    int(0)
  }
  [2]=>
  object(Obj)#%d (2) {
    ["a"]=>
    int(42)
    ["b"]=>
    int(43)
  }
}
string(1) "A"
PK,j�\�H�4	4	tests/typed_property_refs.phptnu�[���--TEST--
unserialize with references to typed properties shall skip the references or fail
--SKIPIF--
<?php if (PHP_VERSION_ID < 80000) die("skip requires php 8.0+"); ?>
--FILE--
<?php

class X {
    public $a;
    public $b;
}

class A {
    public int $a;
    public $b;
}

class B {
    public $a;
    public int $b;
}

class E {
    public $a;
    public int $b;
}

class C {
    public int $a;
    public string $b;
}

class D {
    public int $a;
    public float $b;
}
function create_ser($value): string {
    $v = new X();
    $v->a = $value;
    $v->b = &$v->a;
    $ser = igbinary_serialize($v);
    printf("for %s: %s\n", var_export($value, true), urlencode($ser));
    return $ser;
}
$serInt = create_ser(1);
$serNull = create_ser(null);
$serStr = create_ser('x');
var_dump(igbinary_unserialize(str_replace('X', 'A', $serInt)));
var_dump(igbinary_unserialize(str_replace('X', 'B', $serInt)));
var_dump(igbinary_unserialize(str_replace('X', 'E', $serInt)));

try {
    var_dump(igbinary_unserialize(str_replace('X', 'A', $serNull)));
} catch (TypeError $e) {
    echo $e->getMessage(), "\n";
}
try {
    var_dump(igbinary_unserialize(str_replace('X', 'B', $serNull)));
} catch (TypeError $e) {
    echo $e->getMessage(), "\n";
}
try {
    var_dump(igbinary_unserialize(str_replace('X', 'C', $serInt)));
} catch (TypeError $e) {
    echo $e->getMessage(), "\n";
}
try {
    var_dump(igbinary_unserialize(str_replace('X', 'C', $serStr)));
} catch (TypeError $e) {
    echo $e->getMessage(), "\n";
}
try {
    var_dump(igbinary_unserialize(str_replace('X', 'D', $serInt)));
} catch (TypeError $e) {
    echo $e->getMessage(), "\n";
}

?>
--EXPECT--
for 1: %00%00%00%02%17%01X%14%02%11%01a%25%06%01%11%01b%25%01%01
for NULL: %00%00%00%02%17%01X%14%02%11%01a%25%00%11%01b%25%01%01
for 'x': %00%00%00%02%17%01X%14%02%11%01a%25%11%01x%11%01b%25%01%01
object(A)#1 (2) {
  ["a"]=>
  &int(1)
  ["b"]=>
  &int(1)
}
object(B)#1 (2) {
  ["a"]=>
  &int(1)
  ["b"]=>
  &int(1)
}
object(E)#1 (2) {
  ["a"]=>
  &int(1)
  ["b"]=>
  &int(1)
}
Cannot assign null to property A::$a of type int
Cannot assign null to property B::$b of type int
Cannot assign int to property C::$b of type string
Cannot assign string to property C::$a of type int
Reference with value of type int held by property D::$a of type int is not compatible with property D::$b of type float
PK,j�\����tests/igbinary_094.phptnu�[���--TEST--
Test refusing to serialize/unserialize unserializable internal classes
--INI--
error_reporting=E_ALL
--SKIPIF--
<?php
if (PHP_VERSION_ID < 70400) { echo "skip CURLFile serialization forbidden in php 7.4, test requires 7.4+\n"; }
if (!extension_loaded('curl')) { echo "skip requires curl\n"; }
?>
--FILE--
<?php
// https://bugs.php.net/bug.php?id=81111
function check_serialize_throws($obj) {
    try {
        echo urlencode(igbinary_serialize($obj)), "\n";
    } catch (Throwable $e) {
        echo "Caught: " . $e->getMessage() . "\n";
    }
}
class Something extends CURLFile {
    public function __serialize() { return []; }
    public function __unserialize($value) { return new self('file'); }
}

check_serialize_throws(new CURLFile('file'));
check_serialize_throws(new Something('file'));
?>
--EXPECTF--
Caught: Serialization of 'CURLFile' is not allowed
Caught: Serialization of 'Something' is not allowed
PK,j�\j3����tests/igbinary_023.phptnu�[���--TEST--
Resource
--SKIPIF--
<?php
if (!extension_loaded("igbinary")) print "skip extension not loaded\n";
--FILE--
<?php

function test($type, $variable, $test) {
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);

	echo $type, "\n";
	echo substr(bin2hex($serialized), 8), "\n";
	echo $test || $unserialized === null ? 'OK' : 'FAIL';
	echo "\n";
}

$res = tmpfile();

test('resource', $res, false);

fclose($res);

test('resource', $res, false);

--EXPECTF--
Deprecated: igbinary_serialize(): Cannot serialize resource(stream) and resources may be converted to objects that cannot be serialized in future php releases. Serializing the value as null instead in %sigbinary_023.php on line 4
resource
00
OK

Deprecated: igbinary_serialize(): Cannot serialize resource(Unknown) and resources may be converted to objects that cannot be serialized in future php releases. Serializing the value as null instead in %sigbinary_023.php on line 4
resource
00
OK
PK-j�\�<h�OOtests/igbinary_078.phptnu�[���--TEST--
igbinary and large arrays
--FILE--
<?php
class BadSleep {
    public $prop = 'x';
    public function __construct($value) {
        $this->prop = $value;
    }
    public function __sleep() {
        return null;
    }
}
var_dump(bin2hex($s = igbinary_serialize(new BadSleep('override'))));
var_dump(igbinary_unserialize($s));
?>
--EXPECTF--
Notice: igbinary_serialize(): __sleep should return an array only containing the names of instance-variables to serialize in %s on line %d
string(32) "000000021708426164536c6565701400"
object(BadSleep)#1 (1) {
  ["prop"]=>
  string(1) "x"
}PK-j�\2�'tests/typed_property_ref_overwrite.phptnu�[���--TEST--
Overwriting a typed property reference
--SKIPIF--
<?php if (PHP_VERSION_ID < 70400) die("skip php 7.4+"); ?>
--FILE--
<?php

class Test {
    public ?object $prop;
    public $drop;
}
$orig = new Test();
$orig->prop = $orig;
$orig->drop = null;
$ser = igbinary_serialize($orig);
unset($orig);
gc_collect_cycles(); // also tests that igbinary properly marks unserialized data as a possible gc cycle root.

var_dump(igbinary_unserialize($ser));
gc_collect_cycles();

echo "Test overwrite reference group\n";
$ser2 = str_replace('drop', 'prop', $ser);
var_dump(igbinary_unserialize($ser2));

?>
--EXPECT--
object(Test)#1 (2) {
  ["prop"]=>
  *RECURSION*
  ["drop"]=>
  NULL
}
Test overwrite reference group
object(Test)#1 (2) {
  ["prop"]=>
  NULL
  ["drop"]=>
  NULL
}
PK-j�\����tests/igbinary_086.phptnu�[���--TEST--
Test serializing many different classes
--SKIPIF--
<?php if (!extension_loaded("igbinary")) print "skip"; ?>
--FILE--
<?php
$code = '';
// Test creating over 2**16 distinct names and deduplicating them
for ($i = 0; $i < 70000; $i += 100) {
    $code .= "class C$i{}\n";
}
eval($code);
$values = [];
for ($x = 0; $x < 2; $x++) {
    for ($i = 0; $i < 70000; $i++) {
        $name = "C$i";
        if ($i % 100 == 0) {
            $values[] = new $name();
        } else {
            $values[] = $name;
        }
    }
}
$ser = igbinary_serialize($values);
$unserialized = igbinary_unserialize($ser);
var_dump($unserialized == $values);
var_dump($values[0]);
var_dump($values[67800]);

?>
--EXPECT--
bool(true)
object(C0)#1 (0) {
}
object(C67800)#679 (0) {
}
PK.j�\!��k��tests/igbinary_089.phptnu�[���--TEST--
Test serializing string > 4G
--INI--
memory_limit=15G
display_errors=stderr
error_reporting=E_ALL
--CONFLICTS--
high_memory
--SKIPIF--
<?php
if (!extension_loaded("igbinary")) print "skip\n";
if (PHP_INT_SIZE <= 4) { print "skip requires 64-bit\n"; }
if (!getenv('IGBINARY_HIGH_MEMORY_TESTS')) { print "skip requires IGBINARY_HIGH_MEMORY_TESTS=1\n"; }
?>
--FILE--
<?php
ini_set('memory_limit', '15G');
$ser = igbinary_serialize(str_repeat('*', 4200000000));
echo "len=" . strlen($ser) . "\n";
echo bin2hex(substr($ser, 0, 20)) . "\n";
$unser = igbinary_unserialize($ser);
unset($ser);
var_dump($unser === str_repeat('*', 4200000000));
$ser_invalid = hex2bin('0000000213fa56ea002a');
var_dump(igbinary_unserialize($ser_invalid));

?>
--EXPECTF--
len=4200000009
0000000213fa56ea002a2a2a2a2a2a2a2a2a2a2a
bool(true)
Warning: igbinary_unserialize_chararray: end-of-data in %sigbinary_089.php on line 10
NULLPK.j�\�M�-�
�
tests/__serialize_011.phptnu�[���--TEST--
__unserializing deeply nested structures
--SKIPIF--
<?php if (PHP_VERSION_ID < 70400) { echo "Skip requires php 7.4+"; } ?>
--FILE--
<?php
// based on php-src test for Bug #78438 (Corruption when __unserializing deeply nested structures)

class Node
{
    public $childs = [];

    public function __serialize()
    {
        return [$this->childs];
    }

    public function __unserialize(array $data)
    {
        list($this->childs) = $data;
    }
}

function createTree ($width, $depth) {
    $root = new Node();

    $nextLevel = [$root];

    for ($level=1; $level<$depth; $level++) {
        $levelRoots = $nextLevel;
        $nextLevel = [];

        while (count($levelRoots) > 0) {
            $levelRoot = array_shift($levelRoots);

            for ($w = 0; $w < $width; $w++) {
                $tester = new Node();

                $levelRoot->childs[] = $tester;

                $nextLevel[] = $tester;
            }
        }
    }

    return $root;
}


$width = 3;
ob_implicit_flush();

foreach (range(1, 8) as $depth) {
    $tree = createTree($width, $depth);

    echo "Testcase tree $width x $depth".PHP_EOL;

    echo "> Serializing now".PHP_EOL;
    $serialized = igbinary_serialize($tree);

    echo "> Unserializing now".PHP_EOL;
    $tree = igbinary_unserialize($serialized);

    // Lets test whether all is ok!
    $expectedSize = ($width**$depth - 1)/($width-1);

    $nodes = [$tree];
    $count = 0;

    while (count($nodes) > 0) {
        $count++;

        $node = array_shift($nodes);
        foreach ($node->childs as $node) {
            $nodes[] = $node;
        }
    }

    echo "> Unserialized total node count was $count, expected $expectedSize: ".($expectedSize === $count ? 'CORRECT!' : 'INCORRECT');

    echo PHP_EOL;
    echo PHP_EOL;
}
?>
--EXPECT--
Testcase tree 3 x 1
> Serializing now
> Unserializing now
> Unserialized total node count was 1, expected 1: CORRECT!

Testcase tree 3 x 2
> Serializing now
> Unserializing now
> Unserialized total node count was 4, expected 4: CORRECT!

Testcase tree 3 x 3
> Serializing now
> Unserializing now
> Unserialized total node count was 13, expected 13: CORRECT!

Testcase tree 3 x 4
> Serializing now
> Unserializing now
> Unserialized total node count was 40, expected 40: CORRECT!

Testcase tree 3 x 5
> Serializing now
> Unserializing now
> Unserialized total node count was 121, expected 121: CORRECT!

Testcase tree 3 x 6
> Serializing now
> Unserializing now
> Unserialized total node count was 364, expected 364: CORRECT!

Testcase tree 3 x 7
> Serializing now
> Unserializing now
> Unserialized total node count was 1093, expected 1093: CORRECT!

Testcase tree 3 x 8
> Serializing now
> Unserializing now
> Unserialized total node count was 3280, expected 3280: CORRECT!
PK/j�\NW�U	U	tests/igbinary_077.phptnu�[���--TEST--
igbinary and large arrays
--FILE--
<?php
$a = range(0,255);
var_dump(bin2hex($s = igbinary_serialize($a)));
var_dump(igbinary_unserialize($s) === $a);
$largeArray = range(0, 1 << 16);
var_dump(igbinary_unserialize(igbinary_serialize($largeArray)) === $largeArray);
?>
--EXPECTF--
string(2062) "0000000215010006000600060106010602060206030603060406040605060506060606060706070608060806090609060a060a060b060b060c060c060d060d060e060e060f060f06100610061106110612061206130613061406140615061506160616061706170618061806190619061a061a061b061b061c061c061d061d061e061e061f061f06200620062106210622062206230623062406240625062506260626062706270628062806290629062a062a062b062b062c062c062d062d062e062e062f062f06300630063106310632063206330633063406340635063506360636063706370638063806390639063a063a063b063b063c063c063d063d063e063e063f063f06400640064106410642064206430643064406440645064506460646064706470648064806490649064a064a064b064b064c064c064d064d064e064e064f064f06500650065106510652065206530653065406540655065506560656065706570658065806590659065a065a065b065b065c065c065d065d065e065e065f065f06600660066106610662066206630663066406640665066506660666066706670668066806690669066a066a066b066b066c066c066d066d066e066e066f066f06700670067106710672067206730673067406740675067506760676067706770678067806790679067a067a067b067b067c067c067d067d067e067e067f067f06800680068106810682068206830683068406840685068506860686068706870688068806890689068a068a068b068b068c068c068d068d068e068e068f068f06900690069106910692069206930693069406940695069506960696069706970698069806990699069a069a069b069b069c069c069d069d069e069e069f069f06a006a006a106a106a206a206a306a306a406a406a506a506a606a606a706a706a806a806a906a906aa06aa06ab06ab06ac06ac06ad06ad06ae06ae06af06af06b006b006b106b106b206b206b306b306b406b406b506b506b606b606b706b706b806b806b906b906ba06ba06bb06bb06bc06bc06bd06bd06be06be06bf06bf06c006c006c106c106c206c206c306c306c406c406c506c506c606c606c706c706c806c806c906c906ca06ca06cb06cb06cc06cc06cd06cd06ce06ce06cf06cf06d006d006d106d106d206d206d306d306d406d406d506d506d606d606d706d706d806d806d906d906da06da06db06db06dc06dc06dd06dd06de06de06df06df06e006e006e106e106e206e206e306e306e406e406e506e506e606e606e706e706e806e806e906e906ea06ea06eb06eb06ec06ec06ed06ed06ee06ee06ef06ef06f006f006f106f106f206f206f306f306f406f406f506f506f606f606f706f706f806f806f906f906fa06fa06fb06fb06fc06fc06fd06fd06fe06fe06ff06ff"
bool(true)
bool(true)
PK/j�\�{Di��tests/igbinary_009b_php8.phptnu�[���--TEST--
Check for reference serialization in php 8 (Original example, not using var_dump)
--SKIPIF--
<?php
if (!extension_loaded('igbinary')) {
	echo "skip no igbinary";
}
if (PHP_MAJOR_VERSION < 8) {
	echo "skip requires php 8.0+\n";
}
--INI--
pcre.jit=0
--FILE--
<?php
error_reporting(E_ALL|E_STRICT);
// Verify that $type[0] is the same zval as $type[0][0][0], but different from $type[0]
function test_cyclic2($type, $variable) {
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);
	echo $type, "\n";
	echo substr(bin2hex($serialized), 8), "\n";
	// Can't use === or == on two recursive arrays in some cases
	echo array_keys($unserialized) === array_keys($variable) && array_keys($unserialized[0]) === array_keys($variable[0]) ? 'OK' : 'ERROR', "\n";
	ob_start();
	var_dump($variable);
	$dump_exp = ob_get_clean();
	ob_start();
	var_dump($unserialized);
	$dump_act = ob_get_clean();
	if (preg_replace('/&array/', 'array', $dump_act) !== preg_replace('/&array/', 'array', $dump_exp)) {
		echo "But var dump differs:\nActual:\n", $dump_act, "\nExpected\n", $dump_exp, "\n";
		echo "(Was normalized)\n";
	}

	if (!isset($unserialized[0]) || count($unserialized) != 1) {
		printf("Unexpected keys: %s\n", array_keys($unserialized));
		return;
	} else if (!is_array($unserialized)) {
		printf("\$a[0] is not an array, it is %s", gettype($unserialized));
		return;
	}
	// Set a key, check for the presence of the key 2 levels deeper (Should find it) and 1 level deeper (Should not find it)
	$unserialized[0]['test'] = 'foo';
	if ($unserialized[0][0][0]['test'] !== 'foo') {
		echo "Expected the unserialized array to be cyclic\n";
	}
	if (isset($unserialized[0][0]['test'])) {
		echo "Expected the unserialized array to be cyclic AND of cycle depth 2, but cycle depth is 1\n";
	}
}
$a = [null];
$b = [&$a];
$a[0] = &$b;
// 1401060025140106002514010600250101 could also be serialized as 14010600251401060014010600250101 if we normalized the references which only occurred once in the serialization
// (Replace middle &array(&$a) with array(&$array), i.e. second 2514 with 14)
test_cyclic2('cyclic $a = array(&array(&$a)) - testing functionality', $a);
unset($a);
$a = null;
$a = [[&$a]];
test_cyclic2('cyclic $a = array(array(&$a)); $a[0] - testing functionality', $a[0]);
// $a serializes as 140106001401060025140106000101 - This is a bug, probably exists in php5 as well.
--EXPECT--
cyclic $a = array(&array(&$a)) - testing functionality
1401060025140106002514010600250101
OK
But var dump differs:
Actual:
array(1) {
  [0]=>
  &array(1) {
    [0]=>
    array(1) {
      [0]=>
      *RECURSION*
    }
  }
}

Expected
array(1) {
  [0]=>
  &array(1) {
    [0]=>
    *RECURSION*
  }
}

(Was normalized)
cyclic $a = array(array(&$a)); $a[0] - testing functionality
14010600251401060014010600250101
OK
But var dump differs:
Actual:
array(1) {
  [0]=>
  &array(1) {
    [0]=>
    array(1) {
      [0]=>
      *RECURSION*
    }
  }
}

Expected
array(1) {
  [0]=>
  &array(1) {
    [0]=>
    *RECURSION*
  }
}

(Was normalized)PK/j�\�[����tests/igbinary_025b.phptnu�[���--TEST--
Object test, array of small objects with __sleep
--SKIPIF--
--FILE--
<?php
if(!extension_loaded('igbinary')) {
	dl('igbinary.' . PHP_SHLIB_SUFFIX);
}

function test($type, $variable, $test) {
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);

	var_dump($variable);
	var_dump($unserialized);
}

class Obj {
	private $c;

	function __construct($c) {
		$this->c = $c;
	}

	function __sleep() {
		return array('c');
	}
}

$obj = new Obj(4);

test('array', $obj, true);

?>
--EXPECT--
object(Obj)#1 (1) {
  ["c":"Obj":private]=>
  int(4)
}
object(Obj)#2 (1) {
  ["c":"Obj":private]=>
  int(4)
}
PK0j�\�ƀ�vvtests/igbinary_006.phptnu�[���--TEST--
Check for simple string serialization
--SKIPIF--
--FILE--
<?php
if(!extension_loaded('igbinary')) {
	dl('igbinary.' . PHP_SHLIB_SUFFIX);
}

function test($type, $variable) {
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);

	echo $type, "\n";
	echo substr(bin2hex($serialized), 8), "\n";
	echo $unserialized === $variable ? 'OK' : 'ERROR';
	echo "\n";
}

test('empty: ""', "");
test('string: "foobar"', "foobar");

/*
 * you can add regression tests for your extension here
 *
 * the output of your test code has to be equal to the
 * text in the --EXPECT-- section below for the tests
 * to pass, differences between the output and the
 * expected text are interpreted as failure
 *
 * see TESTING.md for further information on
 * writing regression tests
 */
?>
--EXPECT--
empty: ""
0d
OK
string: "foobar"
1106666f6f626172
OK
PK0j�\#eU���#tests/sleep_mangled_name_clash.phptnu�[���--TEST--
__sleep() returns properties clashing only after mangling
--FILE--
<?php
class Test {
    private $priv;
    public function __sleep() {
        return ["\0Test\0priv", "priv"];
    }
}
// igbinary currently does not emit a notice or check for duplicates
$s = igbinary_serialize(new Test);
echo urlencode($s), "\n";
var_dump(igbinary_unserialize($s));
?>
--EXPECT--
%00%00%00%02%17%04Test%14%02%11%0A%00Test%00priv%00%0E%01%00
object(Test)#1 (1) {
  ["priv":"Test":private]=>
  NULL
}
PK0j�\�~�ʘ�tests/igbinary_093.phptnu�[���--TEST--
Test refusing to serialize/unserialize unserializable anonymous classes
--INI--
error_reporting=E_ALL
--FILE--
<?php
// https://bugs.php.net/bug.php?id=81111
function check_serialize_throws($obj) {
    try {
        echo urlencode(igbinary_serialize($obj)), "\n";
    } catch (Throwable $e) {
        echo "Caught: " . $e->getMessage() . "\n";
    }
}

check_serialize_throws(new class () {
    public function __serialize() { return []; }
    public function __unserialize($value) { }
});
check_serialize_throws(function () { });

?>
--EXPECTF--
Caught: Serialization of 'class@anonymous' is not allowed
Caught: Serialization of 'Closure' is not allowed
PK0j�\X�瀳�tests/igbinary_030_php72.phptnu�[���--TEST--
Unserialize invalid data (php 7.2+)
--SKIPIF--
<?php
if (!extension_loaded('igbinary')) {
	echo "skip no igbinary";
}
if (PHP_VERSION_ID < 70200) {
    echo "Skip php 7.2+ required\n";
}
?>
--FILE--
<?php

$o = new stdClass();
$o->{"1"} = "manual";
$datas = array(
	87817,
	-1,
	array(1,2,3,"testing" => 10, "foo"),
	true,
	false,
	0.187182,
	"dakjdh98389\000",
	null,
	(object)array(1,2,3),
    $o,
);

error_reporting(0);
foreach ($datas as $data) {
	$str = igbinary_serialize($data);
	$len = strlen($str);

	// truncated
	for ($i = 0; $i < $len - 1; $i++) {
		$v = igbinary_unserialize(substr($str, 0, $i));
		if (is_object($data) && $v !== null && $v == $data) {
			continue;
		} elseif ($v !== null && $v != FALSE && $v !== $data) {
			echo "output at $i:\n";
			var_dump($v);
			echo "vs.\n";
			var_dump($data);
		}
	}

	// padded
	$str2 = $str . "98398afa\000y21_ ";
	$v = igbinary_unserialize($str2);
	if ($v !== NULL) {
		echo "Should return null with padding\n";
		var_dump($v);
	}
	$str3 = $str . "\x00";
	$v = igbinary_unserialize($str3);
	if ($v !== NULL) {
		echo "Should return null with single byte of padding\n";
		var_dump($v);
	}
}
echo "Success!\n";
?>
--EXPECT--
Success!
PK1j�\d}���tests/igbinary_022.phptnu�[���--TEST--
Object test, unserialize_callback_func (PHP < 8.2)
--SKIPIF--
<?php if (PHP_VERSION_ID >= 80200) echo "skip requires php < 8.2\n"; ?>
--INI--
error_reporting=E_ALL
unserialize_callback_func=autoload
--FILE--
<?php
if(!extension_loaded('igbinary')) {
	dl('igbinary.' . PHP_SHLIB_SUFFIX);
}

function test($type, $variable, $test) {
	$serialized = pack('H*', $variable);
	$unserialized = igbinary_unserialize($serialized);

	echo $type, "\n";
	echo substr(bin2hex($serialized), 8), "\n";
	echo $test || $unserialized->b == 2 ? 'OK' : 'ERROR';
	echo "\n";
}

function autoload($classname) {
	echo "Autoloading $classname\n";
	if (!class_exists(Obj::class)) {
		class Obj {
			var $a;
			var $b;

			function __construct($a, $b) {
				$this->a = $a;
				$this->b = $b;
			}
		}
	}
}

test('autoload', '0000000217034f626a140211016106011101620602', false);
test('autoload', '0000000217034f626b140211016106011101620602', false);
ini_set('unserialize_callback_func', strtolower('Missing_autoload'));
test('missing_autoload', '0000000217034f626c140211016106011101620602', false);

/*
 * you can add regression tests for your extension here
 *
 * the output of your test code has to be equal to the
 * text in the --EXPECT-- section below for the tests
 * to pass, differences between the output and the
 * expected text are interpreted as failure
 *
 * see TESTING.md for further information on
 * writing regression tests
 */
?>
--EXPECTF--
Autoloading Obj
autoload
17034f626a140211016106011101620602
OK
Autoloading Obk

%s: igbinary_unserialize(): Function autoload() hasn't defined the class it was called for in %sigbinary_022.php on line 8
autoload
17034f626b140211016106011101620602

%s: test(): %s to load the class definition %Sin %sigbinary_022.php on line 12
ERROR

%s: igbinary_unserialize(): defined (missing_autoload) but not found in %sigbinary_022.php on line 8
missing_autoload
17034f626c140211016106011101620602

%s: test(): %s to load the class definition %Sin %sigbinary_022.php on line 12
ERROR
PK1j�\��tests/__serialize_021.phptnu�[���--TEST--
__serialize() mechanism (021): Temporary references in serialized arrays should be properly deduplicated
--FILE--
<?php

// This test will also pass before php 7.4 - it will just not call __serialize in older php versions.
// (not a good example, the formats are incompatible)
class Test {
    /** @var int */
    public $i;

    public function __construct(int $i) {
        $this->i = $i;
    }

    public function __serialize() {
        $j = $this->i + 0x7700;
        return [&$j, &$j];
    }

    public function __unserialize(array $data) {
        list($this->i) = $data;
    }
}

$values = [];
for ($i = 0; $i < 256; $i++) {
    $values[] = new Test($i);
}
$ser = igbinary_serialize($values);
$result = igbinary_unserialize($ser);

printf("Count=%d\n", count($values));
$j = 0;
foreach ($values as $i => $v) {
    if ($i !== $j) {
        echo "Unexpected key $i, expected $j\n";
    }
    if ($v->i !== $j) {
        echo "Unexpected value {$v->i}, expected $j\n";
    }
    $j++;
}
echo "Done\n";

?>
--EXPECT--
Count=256
Done
PK1j�\�'���tests/__serialize_022.phptnu�[���--TEST--
__serialize() mechanism (021): Test __serialize without __unserialize
--SKIPIF--
<?php if (PHP_VERSION_ID < 70400) { echo "skip __serialize/__unserialize not supported in php < 7.4 for compatibility with serialize()"; } ?>
--FILE--
<?php
#[AllowDynamicProperties]
class Test {
    const SOME_CONST = ['key' => 'value'];

    public function __serialize() {
        return self::SOME_CONST;
    }

    public static function test_serialize() {
        $x = igbinary_serialize([self::SOME_CONST, new self(), new self()]);
        // aggressively reuses arrays
        echo urlencode($x), "\n";
        var_dump(igbinary_unserialize($x));
    }
}

Test::test_serialize();
?>
--EXPECT--
%00%00%00%02%14%03%06%00%14%01%11%03key%11%05value%06%01%17%04Test%14%01%0E%00%0E%01%06%02%1A%02%14%01%0E%00%0E%01
array(3) {
  [0]=>
  array(1) {
    ["key"]=>
    string(5) "value"
  }
  [1]=>
  object(Test)#2 (1) {
    ["key"]=>
    string(5) "value"
  }
  [2]=>
  object(Test)#1 (1) {
    ["key"]=>
    string(5) "value"
  }
}
PK2j�\~
x�%%tests/igbinary_047.phptnu�[���--TEST--
Check for serialization handler, SessionHandlerInterface
--SKIPIF--
<?php
if (!extension_loaded('session')) {
    exit('skip session extension not loaded');
}

ob_start();
phpinfo(INFO_MODULES);
$str = ob_get_clean();

$array = explode("\n", $str);
$array = preg_grep('/^igbinary session support.*yes/', $array);
if (!$array) {
    exit('skip igbinary session handler not available');
}
?>
--FILE--
<?php
// https://github.com/igbinary/igbinary/issues/23
// http://www.php.net/manual/en/class.sessionhandlerinterface.php
$output = '';

class S implements SessionHandlerInterface {
    public function open($path, $name): bool {
        return true;
    }

    public function close(): bool {
        return true;
    }

    public function read($id): string {
        global $output;
        $output .= "read\n";
        return pack('H*', '0000000214011103666f6f0601');
    }

    public function write($id, $data): bool {
        global $output;
        $output .= "wrote: ";
        $output .= substr(bin2hex($data), 8). "\n";
        return true;
    }

    public function destroy($id): bool {
        return true;
    }

    // > Returns the number of deleted sessions on success, or false on failure.
    // > Note this value is returned internally to PHP for processing.
    public function gc($time): int {
        return 0;
    }
}

class Foo {
}

class Bar {
}

ini_set('session.serialize_handler', 'igbinary');

$handler = new S();
session_set_save_handler($handler, true);

$db_object = new Foo();
$session_object = new Bar();

$v = session_start();
var_dump($v);
$_SESSION['test'] = "foobar";

session_write_close();

echo $output;

/*
 * you can add regression tests for your extension here
 *
 * the output of your test code has to be equal to the
 * text in the --EXPECT-- section below for the tests
 * to pass, differences between the output and the
 * expected text are interpreted as failure
 *
 * see TESTING.md for further information on
 * writing regression tests
 */
?>
--EXPECT--
bool(true)
read
wrote: 14021103666f6f06011104746573741106666f6f626172
PK2j�\AfFFtests/__serialize_005.phptnu�[���--TEST--
__serialize() mechanism (005): parent::__unserialize() is safe
--SKIPIF--
<?php if (PHP_VERSION_ID < 70400) { echo "skip __serialize/__unserialize not supported in php < 7.4 for compatibility with serialize()"; } ?>
--FILE--
<?php

// NOTE: PHP 8.1.0 changed the way property iteration is done to optimize memory usage(affects var_dump output order but not the correctness of igbinary).
// To work around this, declare all properties on the same class.
class A {
    private $data;
    protected $data2;
    public function __construct(array $data) {
        $this->data = $data;
    }
    public function __serialize() {
        return $this->data;
    }
    public function __unserialize(array $data) {
        $this->data = $data;
    }
}

class B extends A {
    public function __construct(array $data, array $data2) {
        parent::__construct($data);
        $this->data2 = $data2;
    }
    public function __serialize() {
        return [$this->data2, parent::__serialize()];
    }
    public function __unserialize(array $payload) {
        [$data2, $data] = $payload;
        parent::__unserialize($data);
        $this->data2 = $data2;
    }
}

$common = new stdClass;
$obj = new B([$common], [$common]);
var_dump(bin2hex($s = igbinary_serialize($obj)));
var_dump(igbinary_unserialize($s));

?>
--EXPECT--
string(70) "0000000217014214020600140106001708737464436c61737314000601140106002202"
object(B)#3 (2) {
  ["data":"A":private]=>
  array(1) {
    [0]=>
    object(stdClass)#4 (0) {
    }
  }
  ["data2":protected]=>
  array(1) {
    [0]=>
    object(stdClass)#4 (0) {
    }
  }
}
PK3j�\HbQմ�tests/__serialize_014_php8.phptnu�[���--TEST--
__serialize() mechanism (014): Uninitialized properties can be serialized and unserialized
--SKIPIF--
<?php if (PHP_VERSION_ID < 80000) { echo "skip __serialize/__unserialize error message different in php < 8"; } ?>
--FILE--
<?php
class MyClass {
    public stdClass $o;
    public string $s;
    public ?int $i;
}
// 00000002               -- header
// 17 07 4d79436c617373   -- object of type "MyClass"
//   14 03 000000           -- with 3 uninitialized properties
$m = new MyClass();
var_dump($m);
var_dump(bin2hex($s = igbinary_serialize($m)));
var_dump(igbinary_unserialize($s));
$m = new MyClass();
$m->o = new stdClass();
unset($m->o);
$m->s = 'other';
unset($m->s);
$m->i = 42;
unset($m->i);
// Should have the same serialized representation.
var_dump($m);
var_dump(bin2hex($s = igbinary_serialize($m)));
try {
    $m->i = 'i';
} catch (TypeError $e) {
    echo $e->getMessage() . "\n";
}
--EXPECT--
object(MyClass)#1 (0) {
  ["o"]=>
  uninitialized(stdClass)
  ["s"]=>
  uninitialized(string)
  ["i"]=>
  uninitialized(?int)
}
string(36) "0000000217074d79436c6173731403000000"
object(MyClass)#2 (0) {
  ["o"]=>
  uninitialized(stdClass)
  ["s"]=>
  uninitialized(string)
  ["i"]=>
  uninitialized(?int)
}
object(MyClass)#2 (0) {
  ["o"]=>
  uninitialized(stdClass)
  ["s"]=>
  uninitialized(string)
  ["i"]=>
  uninitialized(?int)
}
string(36) "0000000217074d79436c6173731403000000"
Cannot assign string to property MyClass::$i of type ?intPK3j�\���A�Atests/__serialize_020.phptnu�[���--TEST--
issue when serializing/deserializing nested objects with __serialize
--SKIPIF--
<?php if (PHP_VERSION_ID < 70100) { echo "skip uses php 7.1 syntax\n"; } ?>
--FILE--
<?php
// Based on bug report seen in a Symfony codebase - https://github.com/igbinary/igbinary/issues/287
// NOTE: This test would also pass in older php versions, where igbinary doesn't call __serialize,
// just because we're returning the same data we fetch.
// (However, the serialized data generated before/after 7.4 would be incompatible if saved to memcache, etc.)
class Event
{
}

class MessageEvents
{
    private $events = [];
    private $transports = [];

    public function add(MessageEvent $event): void
    {
        $this->events[] = $event;
        $this->transports[$event->getTransport()] = true;
    }

    public function getEvents(string $name = null): array
    {
        return $this->events;
    }
}

final class MessageEvent extends Event
{
    private $propagationStopped = false;
    private $message;
    private $envelope;
    private $transport;
    private $queued;

    public function __construct(RawMessage $message, Envelope $envelope, string $transport, bool $queued = false)
    {
        $this->message = $message;
        $this->envelope = $envelope;
        $this->transport = $transport;
        $this->queued = $queued;
    }

    public function getTransport(): string
    {
        return $this->transport;
    }

    public function getMessage(): RawMessage
    {
        return $this->message;
    }
}

class Envelope
{
    protected $sender;
    protected $recipients = [];
    protected $senderSet = false;
    protected $recipientsSet = false;
    protected $message;

    public function __construct(Address $sender, array $recipients)
    {
        $this->setSender($sender);
        $this->setRecipients($recipients);
    }

    public static function create(RawMessage $message): self
    {
        return new DelayedEnvelope($message);
    }

    public function setSender(Address $sender): void
    {
        $this->sender = $sender;
    }

    public function setRecipients(array $recipients): void
    {
        $this->recipients = [];
        foreach ($recipients as $recipient) {
            $this->recipients[] = new Address($recipient->getAddress());
        }
    }

    public function getRecipients(): array
    {
        return $this->recipients;
    }
}

final class DelayedEnvelope extends Envelope
{

    public function __construct(Message $message)
    {
        $this->message = $message;
    }

    public function setSender(Address $sender): void
    {
        parent::setSender($sender);

        $this->senderSet = true;
    }

    public function setRecipients(array $recipients): void
    {
        parent::setRecipients($recipients);

        $this->recipientsSet = parent::getRecipients();
    }
}

final class Address
{
    private $address;
    private $name;

    public function __construct(string $address, string $name = '')
    {
        $this->address = trim($address);
        $this->name = trim(str_replace(["\n", "\r"], '', $name));
    }

    /**
     * @param Address|string $address
     */
    public static function create($address): self
    {
        if ($address instanceof self) {
            return $address;
        }
        if (\is_string($address)) {
            if (false === strpos($address, '<')) {
                return new self($address);
            }

            return new self($matches['addrSpec'], trim($matches['displayName'], ' \'"'));
        }

        throw new InvalidArgumentException(sprintf('An address can be an instance of Address or a string ("%s" given).', get_debug_type($address)));
    }

    public static function createArray(array $addresses): array
    {
        $addrs = [];
        foreach ($addresses as $address) {
            $addrs[] = self::create($address);
        }

        return $addrs;
    }
}

abstract class AbstractHeader
{
    private static $encoder;

    private $name;
    private $lineLength = 76;
    private $lang;
    private $charset = 'utf-8';
    protected $addresses = [];

    public function __construct(string $name)
    {
        $this->name = $name;
    }

    public function getName()
    {
        return $this->name;
    }

}

final class Headers
{
    private $headers = [];
    private $lineLength = 76;

    public function __construct(...$headers)
    {
        foreach ($headers as $header) {
            $this->add($header);
        }
    }

    public function __clone()
    {
        foreach ($this->headers as $name => $collection) {
            foreach ($collection as $i => $header) {
                $this->headers[$name][$i] = clone $header;
            }
        }
    }

    public function addMailboxListHeader(string $name, array $addresses): self
    {
        return $this->add(new MailboxListHeader($name, Address::createArray($addresses)));
    }

    public function add($header): self
    {
        self::checkHeaderClass($header);

        $name = strtolower($header->getName());

        $this->headers[$name][] = $header;

        return $this;
    }

    public function get(string $name)
    {
        $name = strtolower($name);
        if (!isset($this->headers[$name])) {
            return null;
        }

        $values = array_values($this->headers[$name]);

        return array_shift($values);
    }

    public function all(string $name = null): iterable
    {
        if (null === $name) {
            foreach ($this->headers as $name => $collection) {
                foreach ($collection as $header) {
                    yield $name => $header;
                }
            }
        } elseif (isset($this->headers[strtolower($name)])) {
            foreach ($this->headers[strtolower($name)] as $header) {
                yield $header;
            }
        }
    }

    public static function checkHeaderClass($header): void
    {
        $name = strtolower($header->getName());
    }
}

final class MailboxListHeader extends AbstractHeader
{
    public function __construct(string $name, array $addresses)
    {
        parent::__construct($name);

        $this->addAddresses($addresses);
    }

    public function addAddresses(array $addresses)
    {
        foreach ($addresses as $address) {
            $this->addAddress($address);
        }
    }

    /**
     * @throws RfcComplianceException
     */
    public function addAddress(Address $address)
    {
        $this->addresses[] = $address;
    }
}

class RawMessage
{
    protected $message;
    protected $headers;
    protected $body;
    protected $text;
    protected $textCharset;
    protected $html;
    protected $htmlCharset;
    protected $attachments = [];

    public function __construct($message)
    {
        $this->message = $message;
    }

    public function __serialize(): array
    {
        return [$this->message];
    }

    public function __unserialize(array $data): void
    {
        [$this->message] = $data;
    }
}

class Message extends RawMessage
{

    public function __construct(Headers $headers = null, AbstractPart $body = null)
    {
        $this->headers = $headers ? clone $headers : new Headers();
        $this->body = $body;
    }

    public function __clone()
    {
        $this->headers = clone $this->headers;

        if (null !== $this->body) {
            $this->body = clone $this->body;
        }
    }

    public function getHeaders(): Headers { return $this->headers; }

    public function __serialize(): array
    {
        return [$this->headers];
    }

    public function __unserialize(array $data): void
    {
        [$this->headers] = $data;
    }
}


class Email extends Message
{
    public function to(...$addresses)
    {
        return $this->setListAddressHeaderBody('To', $addresses);
    }

    private function setListAddressHeaderBody(string $name, array $addresses)
    {
        $addresses = Address::createArray($addresses);
        $headers = $this->getHeaders();
        $headers->addMailboxListHeader($name, $addresses);

        return $this;
    }

    /**
     * @internal
     */
    public function __serialize(): array
    {
        return [$this->text, $this->textCharset, $this->html, $this->htmlCharset, $this->attachments, parent::__serialize()];
    }

    /**
     * @internal
     */
    public function __unserialize(array $data): void
    {
        [$this->text, $this->textCharset, $this->html, $this->htmlCharset, $this->attachments, $parentData] = $data;

        parent::__unserialize($parentData);
    }
}

$messageEvents = new MessageEvents();
$messageEvents->add(new MessageEvent($message1 = (new Email())->to('alice@example.com'), Envelope::create($message1), 'null://null'));
$messageEvents->add(new MessageEvent($message2 = (new Email())->to('bob@example.com'), Envelope::create($message2), 'null://null'));

var_dump($messageEvents); // Comment/uncomment to trigger the bug

var_dump('headers_before', $messageEvents->getEvents()[0]->getMessage()->getHeaders() === $messageEvents->getEvents()[1]->getMessage()->getHeaders());

$ser = igbinary_serialize($messageEvents);

$messageEvents = igbinary_unserialize($ser);

// should dump "false", but dumps "true" the "var_dump($messageEvents)" is not commented
var_dump('headers_after', $messageEvents->getEvents()[0]->getMessage()->getHeaders() === $messageEvents->getEvents()[1]->getMessage()->getHeaders());
?>
--EXPECT--
object(MessageEvents)#1 (2) {
  ["events":"MessageEvents":private]=>
  array(2) {
    [0]=>
    object(MessageEvent)#2 (5) {
      ["propagationStopped":"MessageEvent":private]=>
      bool(false)
      ["message":"MessageEvent":private]=>
      object(Email)#3 (8) {
        ["message":protected]=>
        NULL
        ["headers":protected]=>
        object(Headers)#4 (2) {
          ["headers":"Headers":private]=>
          array(1) {
            ["to"]=>
            array(1) {
              [0]=>
              object(MailboxListHeader)#6 (5) {
                ["name":"AbstractHeader":private]=>
                string(2) "To"
                ["lineLength":"AbstractHeader":private]=>
                int(76)
                ["lang":"AbstractHeader":private]=>
                NULL
                ["charset":"AbstractHeader":private]=>
                string(5) "utf-8"
                ["addresses":protected]=>
                array(1) {
                  [0]=>
                  object(Address)#5 (2) {
                    ["address":"Address":private]=>
                    string(17) "alice@example.com"
                    ["name":"Address":private]=>
                    string(0) ""
                  }
                }
              }
            }
          }
          ["lineLength":"Headers":private]=>
          int(76)
        }
        ["body":protected]=>
        NULL
        ["text":protected]=>
        NULL
        ["textCharset":protected]=>
        NULL
        ["html":protected]=>
        NULL
        ["htmlCharset":protected]=>
        NULL
        ["attachments":protected]=>
        array(0) {
        }
      }
      ["envelope":"MessageEvent":private]=>
      object(DelayedEnvelope)#7 (5) {
        ["sender":protected]=>
        NULL
        ["recipients":protected]=>
        array(0) {
        }
        ["senderSet":protected]=>
        bool(false)
        ["recipientsSet":protected]=>
        bool(false)
        ["message":protected]=>
        object(Email)#3 (8) {
          ["message":protected]=>
          NULL
          ["headers":protected]=>
          object(Headers)#4 (2) {
            ["headers":"Headers":private]=>
            array(1) {
              ["to"]=>
              array(1) {
                [0]=>
                object(MailboxListHeader)#6 (5) {
                  ["name":"AbstractHeader":private]=>
                  string(2) "To"
                  ["lineLength":"AbstractHeader":private]=>
                  int(76)
                  ["lang":"AbstractHeader":private]=>
                  NULL
                  ["charset":"AbstractHeader":private]=>
                  string(5) "utf-8"
                  ["addresses":protected]=>
                  array(1) {
                    [0]=>
                    object(Address)#5 (2) {
                      ["address":"Address":private]=>
                      string(17) "alice@example.com"
                      ["name":"Address":private]=>
                      string(0) ""
                    }
                  }
                }
              }
            }
            ["lineLength":"Headers":private]=>
            int(76)
          }
          ["body":protected]=>
          NULL
          ["text":protected]=>
          NULL
          ["textCharset":protected]=>
          NULL
          ["html":protected]=>
          NULL
          ["htmlCharset":protected]=>
          NULL
          ["attachments":protected]=>
          array(0) {
          }
        }
      }
      ["transport":"MessageEvent":private]=>
      string(11) "null://null"
      ["queued":"MessageEvent":private]=>
      bool(false)
    }
    [1]=>
    object(MessageEvent)#8 (5) {
      ["propagationStopped":"MessageEvent":private]=>
      bool(false)
      ["message":"MessageEvent":private]=>
      object(Email)#9 (8) {
        ["message":protected]=>
        NULL
        ["headers":protected]=>
        object(Headers)#10 (2) {
          ["headers":"Headers":private]=>
          array(1) {
            ["to"]=>
            array(1) {
              [0]=>
              object(MailboxListHeader)#12 (5) {
                ["name":"AbstractHeader":private]=>
                string(2) "To"
                ["lineLength":"AbstractHeader":private]=>
                int(76)
                ["lang":"AbstractHeader":private]=>
                NULL
                ["charset":"AbstractHeader":private]=>
                string(5) "utf-8"
                ["addresses":protected]=>
                array(1) {
                  [0]=>
                  object(Address)#11 (2) {
                    ["address":"Address":private]=>
                    string(15) "bob@example.com"
                    ["name":"Address":private]=>
                    string(0) ""
                  }
                }
              }
            }
          }
          ["lineLength":"Headers":private]=>
          int(76)
        }
        ["body":protected]=>
        NULL
        ["text":protected]=>
        NULL
        ["textCharset":protected]=>
        NULL
        ["html":protected]=>
        NULL
        ["htmlCharset":protected]=>
        NULL
        ["attachments":protected]=>
        array(0) {
        }
      }
      ["envelope":"MessageEvent":private]=>
      object(DelayedEnvelope)#13 (5) {
        ["sender":protected]=>
        NULL
        ["recipients":protected]=>
        array(0) {
        }
        ["senderSet":protected]=>
        bool(false)
        ["recipientsSet":protected]=>
        bool(false)
        ["message":protected]=>
        object(Email)#9 (8) {
          ["message":protected]=>
          NULL
          ["headers":protected]=>
          object(Headers)#10 (2) {
            ["headers":"Headers":private]=>
            array(1) {
              ["to"]=>
              array(1) {
                [0]=>
                object(MailboxListHeader)#12 (5) {
                  ["name":"AbstractHeader":private]=>
                  string(2) "To"
                  ["lineLength":"AbstractHeader":private]=>
                  int(76)
                  ["lang":"AbstractHeader":private]=>
                  NULL
                  ["charset":"AbstractHeader":private]=>
                  string(5) "utf-8"
                  ["addresses":protected]=>
                  array(1) {
                    [0]=>
                    object(Address)#11 (2) {
                      ["address":"Address":private]=>
                      string(15) "bob@example.com"
                      ["name":"Address":private]=>
                      string(0) ""
                    }
                  }
                }
              }
            }
            ["lineLength":"Headers":private]=>
            int(76)
          }
          ["body":protected]=>
          NULL
          ["text":protected]=>
          NULL
          ["textCharset":protected]=>
          NULL
          ["html":protected]=>
          NULL
          ["htmlCharset":protected]=>
          NULL
          ["attachments":protected]=>
          array(0) {
          }
        }
      }
      ["transport":"MessageEvent":private]=>
      string(11) "null://null"
      ["queued":"MessageEvent":private]=>
      bool(false)
    }
  }
  ["transports":"MessageEvents":private]=>
  array(1) {
    ["null://null"]=>
    bool(true)
  }
}
string(14) "headers_before"
bool(false)
string(13) "headers_after"
bool(false)PK3j�\s���tests/igbinary_014.phptnu�[���--TEST--
Object-Reference test
--SKIPIF--
--FILE--
<?php
if(!extension_loaded('igbinary')) {
	dl('igbinary.' . PHP_SHLIB_SUFFIX);
}

function test($type, $variable, $test) {
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);

	echo $type, "\n";
	echo substr(bin2hex($serialized), 8), "\n";
	echo $test || $unserialized == $variable ? 'OK' : 'ERROR';
	echo "\n";
}

class Obj {
	var $a;
	var $b;

	function __construct($a, $b) {
		$this->a = $a;
		$this->b = $b;
	}
}

$o = new Obj(1, 2);
$a = array(&$o, &$o);

test('object', $a, false);

--EXPECT--
object
140206002517034f626a1402110161060111016206020601252201
OK
PK4j�\�vTTtests/igbinary_026b_php8.phptnu�[���--TEST--
Cyclic array test 2
--INI--
report_memleaks=0
--SKIPIF--
<?php
if (!extension_loaded('igbinary')) {
	echo "skip no igbinary\n";
}
if (PHP_MAJOR_VERSION < 8) {
	echo "skip requires php 8\n";
}
--FILE--
<?php

$a = array("foo" => &$b);
$b = array(1, 2, $a);

/* all three statements below should produce same output however PHP stock
 * unserialize/serialize produces different output (5.2.16). I consider this is
 * a PHP bug. - Oleg Grenrus
 */

/* NOTE: This is different in php 8 because igbinary_unserialize() is declared to return a reference, not a value */

//$k = $a;
//$k = unserialize(serialize($a));
$k = igbinary_unserialize(igbinary_serialize($a));

function check($a, $k) {
	ob_start();
	var_dump($a);
	$a_str = ob_get_clean();
	ob_start();
	var_dump($k);
	$k_str = ob_get_clean();

	if ($a_str !== $k_str) {
		echo "Output differs\n";
		echo "Expected:\n", $a_str, "\n";
		echo "Actual:\n", $k_str, "\n";
	} else {
		echo "OK\n";
	}
}

check($a, $k);

$a["foo"][2]["foo"][1] = "b";
$k["foo"][2]["foo"][1] = "b";

check($a, $k);

?>
--EXPECT--
Output differs
Expected:
array(1) {
  ["foo"]=>
  &array(3) {
    [0]=>
    int(1)
    [1]=>
    int(2)
    [2]=>
    *RECURSION*
  }
}

Actual:
array(1) {
  ["foo"]=>
  &array(3) {
    [0]=>
    int(1)
    [1]=>
    int(2)
    [2]=>
    array(1) {
      ["foo"]=>
      *RECURSION*
    }
  }
}

OKPK4j�\�խ��tests/igbinary_073.phptnu�[���--TEST--
igbinary and large Serializable
--INI--
; Note that php 8.1 deprecates using Serializable without __serialize/__unserialize but we are testing Serialize for igbinary. Suppress deprecations.
error_reporting=E_ALL & ~E_DEPRECATED
--FILE--
<?php
class Test implements Serializable {
    public $prop;
    public function serialize() {
        return $this->prop;
    }
    public function unserialize($s) {
        $this->prop = $s;
    }
}
function var_export_normalized($value) {
    echo ltrim(var_export($value, true), "\\");
}
$t = new Test();
$t->prop = str_repeat('0', 256);
var_export_normalized(bin2hex($s = igbinary_serialize($t)));
echo "\n";
var_export_normalized(igbinary_unserialize($s));
echo "\n";
$t->prop = str_repeat('0', 1 << 16);
$t2 = igbinary_unserialize(igbinary_serialize($t));
var_dump($t2->prop === $t->prop);
?>
--EXPECT--
'000000021704546573741e010030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030'
Test::__set_state(array(
   'prop' => '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
))
bool(true)
PK4j�\�b@�yytests/igbinary_066.phptnu�[���--TEST--
Test serializing different empty arrays
--FILE--
<?php

// The serialization might be different based on php version and opcache settings.
// So, test the unserialization instead.
$a = array();
var_dump(igbinary_unserialize(igbinary_serialize(array('1st' => array(), '2nd' => array(), '3rd' => array()))));
echo "\n";
var_dump(igbinary_unserialize(igbinary_serialize(array('1st' => $a, '2nd' => $a, '3rd' => $a))));
echo "\n";
$result = igbinary_unserialize(igbinary_serialize(array('1st' => $a, '2nd' => &$a, '3rd' => &$a, '4th' => array())));
var_dump($result);
$result['2nd'][] = 2;
var_dump($result);
echo "\n";
?>
--EXPECT--
array(3) {
  ["1st"]=>
  array(0) {
  }
  ["2nd"]=>
  array(0) {
  }
  ["3rd"]=>
  array(0) {
  }
}

array(3) {
  ["1st"]=>
  array(0) {
  }
  ["2nd"]=>
  array(0) {
  }
  ["3rd"]=>
  array(0) {
  }
}

array(4) {
  ["1st"]=>
  array(0) {
  }
  ["2nd"]=>
  &array(0) {
  }
  ["3rd"]=>
  &array(0) {
  }
  ["4th"]=>
  array(0) {
  }
}
array(4) {
  ["1st"]=>
  array(0) {
  }
  ["2nd"]=>
  &array(1) {
    [0]=>
    int(2)
  }
  ["3rd"]=>
  &array(1) {
    [0]=>
    int(2)
  }
  ["4th"]=>
  array(0) {
  }
}
PK5j�\��'�tests/igbinary_012.phptnu�[���--TEST--
Object test
--INI--
; Note that php 8.1 deprecates using Serializable without __serialize/__unserialize but we are testing Serialize for igbinary. Suppress deprecations.
error_reporting=E_ALL & ~E_DEPRECATED
--FILE--
<?php
if(!extension_loaded('igbinary')) {
	dl('igbinary.' . PHP_SHLIB_SUFFIX);
}

function test($type, $variable) {
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);
//	$serialized = serialize($variable);
//	$unserialized = unserialize($serialized);

	echo $type, "\n";
	echo substr(bin2hex($serialized), 8), "\n";
//	echo $serialized, "\n";
	echo $unserialized == $variable ? 'OK' : 'ERROR';
	echo "\n";
}

class Obj {
	public $a;
	protected $b;
	private $c;

	function __construct($a, $b, $c) {
		$this->a = $a;
		$this->b = $b;
		$this->c = $c;
	}
}

$o = new Obj(1, 2, 3);


test('object', $o);

/*
 * you can add regression tests for your extension here
 *
 * the output of your test code has to be equal to the
 * text in the --EXPECT-- section below for the tests
 * to pass, differences between the output and the
 * expected text are interpreted as failure
 *
 * see TESTING.md for further information on
 * writing regression tests
 */
?>
--EXPECT--
object
17034f626a140311016106011104002a006206021106004f626a00630603
OK
PK5j�\�u��	�	tests/__serialize_015.phptnu�[���--TEST--
__serialize() mechanism (015): Uninitialized properties from __sleep should throw when serializing
--SKIPIF--
<?php
if (PHP_VERSION_ID < 70400) { echo "skip __serialize/__unserialize not supported in php < 7.4 for compatibility with igbinary_serialize()"; }
?>
--FILE--
<?php
error_reporting(E_ALL);
set_error_handler(function ($errno, $message) {
    echo $message . "\n";
});
class OSI {
    public stdClass $o;
    public string $s;
    public ?int $i;
    public float $f;
    public function __sleep() {
        return ['o', 's', 'i'];
    }
}
class SimplePublic {
    public ?int $i;
    public function __sleep() {
        return ['i'];
    }
}
class SimpleProtected {
    protected ?int $i;
    public function __sleep() {
        return ['i'];
    }
    public function __set($name, $value) {
        $this->$name = $value;
    }
}
class SimplePrivate {
    private ?int $i;
    public function __sleep() {
        return ['i'];
    }
    public function __set($name, $value) {
        $this->$name = $value;
    }
}
// 00000002               -- header
// 17 03 4d79436c617373   -- object of type "MyClass"
//   14 03 000000           -- with 3 uninitialized properties
$m = new OSI();
function try_serialize_invalid($o) {
    try {
        var_dump(bin2hex($s = igbinary_serialize($o)));
    } catch (Error $e) {
        printf("Caught %s: %s\n", get_class($e), $e->getMessage());
    }
}
// These should throw whether or not the uninitialized property is nullable.
try_serialize_invalid(new OSI());
try_serialize_invalid(new SimplePublic());
try_serialize_invalid(new SimpleProtected());
try_serialize_invalid(new SimplePrivate());
$s = new SimplePublic();
$s->i = null;
try_serialize_invalid($s);
$s = new SimpleProtected();
$s->i = 0;
try_serialize_invalid($s);
$s = new SimplePrivate();
$s->i = null;
try_serialize_invalid($s);

--EXPECT--
Caught Error: Typed property OSI::$o must not be accessed before initialization (in __sleep)
Caught Error: Typed property SimplePublic::$i must not be accessed before initialization (in __sleep)
Caught Error: Typed property SimpleProtected::$i must not be accessed before initialization (in __sleep)
Caught Error: Typed property SimplePrivate::$i must not be accessed before initialization (in __sleep)
string(48) "00000002170c53696d706c655075626c6963140111016900"
string(62) "00000002170f53696d706c6550726f74656374656414011104002a00690600"
string(80) "00000002170d53696d706c6550726976617465140111100053696d706c6550726976617465006900"
PK5j�\����tests/igbinary_082.phptnu�[���--TEST--
igbinary object with reference to ArrayObject
--FILE--
<?php
class TestClass {
  private $env;
  public function setEnv(ArrayObject &$e) {
    $this->env = &$e;
  }
}

$arrayObject = new ArrayObject();

$testClass = new TestClass();
$testClass->setEnv($arrayObject);

var_dump(igbinary_unserialize(igbinary_serialize($testClass)));
?>
--EXPECTF--
object(TestClass)#%d (1) {
  ["env":"TestClass":private]=>
  object(ArrayObject)#%d (1) {
    ["storage":"ArrayObject":private]=>
    array(0) {
    }
  }
}
PK6j�\��0Y��tests/igbinary_enums_3.phptnu�[���--TEST--
Test unserializing valid enums inferring value
--SKIPIF--
<?php if (PHP_VERSION_ID < 80100) { echo "skip enums requires php 8.1"; } ?>
--FILE--
<?php
enum X: string {
    const Y = 'a';
    case X = self::Y . 'b';
}
$value = urldecode('%00%00%00%02%17%01X%27%0E%00');
var_dump(igbinary_unserialize($value));
$ser = igbinary_serialize(X::X);
echo urlencode($ser), "\n";
var_dump(X::X->value);
?>
--EXPECT--
enum(X::X)
%00%00%00%02%17%01X%27%0E%00
string(2) "ab"
PK6j�\�u���tests/igbinary_046d.phptnu�[���--TEST--
Correctly unserialize multiple object refs and non-refs.
--INI--
igbinary.compact_strings = On
--FILE--
<?php
$a = array(new stdClass());
$a[1] = $a[0];
$a[2] = &$a[1];
$a[3] = $a[0];
var_dump($a);
printf("%s\n", serialize($a));
$ig_ser = igbinary_serialize($a);
printf("%s\n", bin2hex($ig_ser));
$ig = igbinary_unserialize($ig_ser);
printf("%s\n", serialize($ig));
var_dump($ig);
$f = &$ig[2];
$f = 'V';
var_dump($ig);
// Note: While the php7 unserializer consistently makes a distinction between refs to an object and non-refs,
// the php5 serializer does not.
--EXPECTF--
array(4) {
  [0]=>
  object(stdClass)#%d (0) {
  }
  [1]=>
  &object(stdClass)#%d (0) {
  }
  [2]=>
  &object(stdClass)#%d (0) {
  }
  [3]=>
  object(stdClass)#%d (0) {
  }
}
a:4:{i:0;O:8:"stdClass":0:{}i:1;R:2;i:2;R:2;i:3;r:2;}
00000002140406001708737464436c61737314000601252201060225220106032201
a:4:{i:0;O:8:"stdClass":0:{}i:1;R:2;i:2;R:2;i:3;r:2;}
array(4) {
  [0]=>
  object(stdClass)#%d (0) {
  }
  [1]=>
  &object(stdClass)#%d (0) {
  }
  [2]=>
  &object(stdClass)#%d (0) {
  }
  [3]=>
  object(stdClass)#%d (0) {
  }
}
array(4) {
  [0]=>
  object(stdClass)#%d (0) {
  }
  [1]=>
  &string(1) "V"
  [2]=>
  &string(1) "V"
  [3]=>
  object(stdClass)#%d (0) {
  }
}
PK6j�\�͹���tests/igbinary_098.phptnu�[���--TEST--
Test PHP 8.2 readonly classes
--SKIPIF--
<?php
if (!extension_loaded("igbinary")) print "skip\n";
if (PHP_VERSION_ID < 80200) print "skip php < 8.2\n";
?>
--FILE--
<?php
readonly class C {
    public int $a;
    public static function create() {
        $c = new C();
        $c->a = 8;
        return $c;
    }
}
$c = new C();
$ser = igbinary_serialize($c);
echo urlencode($ser), "\n";
var_dump(igbinary_unserialize($ser));
$c = C::create();
$ser = igbinary_serialize($c);
echo urlencode($ser), "\n";
var_dump(igbinary_unserialize($ser));
$invalid1 = str_replace('a', 'b', $ser);
try {
    var_dump(igbinary_unserialize($invalid1));
} catch (Error $e) {
    printf("%s: %s\n", $e::class, $e->getMessage());
}
--EXPECT--
%00%00%00%02%17%01C%14%01%00
object(C)#2 (0) {
  ["a"]=>
  uninitialized(int)
}
%00%00%00%02%17%01C%14%01%11%01a%06%08
object(C)#1 (1) {
  ["a"]=>
  int(8)
}
Error: Cannot create dynamic property C::$b in igbinary_unserialize
PK7j�\�\����0tests/typed_property_ref_assignment_failure.phptnu�[���--TEST--
Failure to assign ref to typed property
--SKIPIF--
<?php if (PHP_VERSION_ID < 70400) die("skip php 7.4+"); ?>
--FILE--
<?php

class Best {
    public $prop;
}
class Test {
    public int $prop;
}

$b = new Best();
$b->prop = new stdClass();
$b->prop->y = &$b->prop;
$ser = igbinary_serialize($b);
echo str_replace('%', '\\x', urlencode($ser)), "\n";

// Should reject stdClass reference
$ser2 = str_replace('Best', 'Test', $ser);
try {
    var_dump(igbinary_unserialize($ser2));
} catch (Error $e) {
    printf("Caught %s: %s\n", get_class($e), $e->getMessage());
}
?>
--EXPECTF--
\x00\x00\x00\x02\x17\x04Best\x14\x01\x11\x04prop\x25\x17\x08stdClass\x14\x01\x11\x01y\x25\x22\x01
Caught TypeError: %s property Test::$prop %s
PK7j�\e�4CCtests/igbinary_082_php74.phptnu�[���--TEST--
igbinary object with typed properties with reference to ArrayObject
--SKIPIF--
<?php if (PHP_VERSION_ID < 70400) die("skip test requires typed properties"); ?>
--INI--
; Note that php 8.1 deprecates using Serializable without __serialize/__unserialize but we are testing Serialize for igbinary. Suppress deprecations.
error_reporting=E_ALL & ~E_DEPRECATED
--FILE--
<?php
class TestClass {
  private ArrayAccess $env;
  public function setEnv(ArrayObject &$e) {
    $this->env = &$e;
  }
}

$arrayObject = new ArrayObject();

$testClass = new TestClass();
$testClass->setEnv($arrayObject);

var_dump(igbinary_unserialize(igbinary_serialize($testClass)));
?>
--EXPECTF--
object(TestClass)#%d (1) {
  ["env":"TestClass":private]=>
  object(ArrayObject)#%d (1) {
    ["storage":"ArrayObject":private]=>
    array(0) {
    }
  }
}
PK7j�\��q��tests/igbinary_022_php82.phptnu�[���--TEST--
Object test, unserialize_callback_func (PHP >= 8.2)
--SKIPIF--
<?php if (PHP_VERSION_ID < 80200) echo "skip requires php < 8.2\n"; ?>
--INI--
error_reporting=E_ALL
unserialize_callback_func=autoload
--FILE--
<?php
if(!extension_loaded('igbinary')) {
	dl('igbinary.' . PHP_SHLIB_SUFFIX);
}

function test(string $type, string $variable) {
	$serialized = pack('H*', $variable);
	try {
		$unserialized = igbinary_unserialize($serialized);
	} catch (Error $e) {
		echo $type, "\n";
		echo "Caught {$e->getMessage()}\n";
		return;
	}

	echo $type, "\n";
	echo substr(bin2hex($serialized), 8), "\n";
	var_dump($unserialized);
	// The read_property handler is set to incomplete_class_get_property,
	// making this always return null for __PHP_Incomplete_Class
	var_dump($unserialized->b);
	echo $unserialized->b == 2 ? 'OK' : 'ERROR';
	echo "\n";
}

function autoload($classname) {
	echo "Autoloading $classname\n";
	if (!class_exists(Obj::class)) {
		class Obj {
			var $a;
			var $b;

			function __construct($a, $b) {
				$this->a = $a;
				$this->b = $b;
			}
		}
	}
}

test('autoload', '0000000217034f626a140211016106011101620602');  // "Obj"
test('autoload', '0000000217034f626b140211016106011101620602');  // "Obk" failing to autoload
ini_set('unserialize_callback_func', strtolower('Missing_autoload'));
test('missing_autoload', '0000000217034f626c140211016106011101620602');  // Obk" with missing autoload function

/*
 * you can add regression tests for your extension here
 *
 * the output of your test code has to be equal to the
 * text in the --EXPECT-- section below for the tests
 * to pass, differences between the output and the
 * expected text are interpreted as failure
 *
 * see TESTING.md for further information on
 * writing regression tests
 */
?>
--EXPECTF--
Autoloading Obj
autoload
17034f626a140211016106011101620602
object(Obj)#1 (2) {
  ["a"]=>
  int(1)
  ["b"]=>
  int(2)
}
int(2)
OK
Autoloading Obk

Warning: igbinary_unserialize(): Function autoload() hasn't defined the class it was called for in %sigbinary_022_php82.php on line 9
autoload
17034f626b140211016106011101620602
object(__PHP_Incomplete_Class)#1 (3) {
  ["__PHP_Incomplete_Class_Name"]=>
  string(3) "Obk"
  ["a"]=>
  int(1)
  ["b"]=>
  int(2)
}

Warning: test(): The script tried to access a property on an incomplete object. Please ensure that the class definition "Obk" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition in %sigbinary_022_php82.php on line 21
NULL

Warning: test(): The script tried to access a property on an incomplete object. Please ensure that the class definition "Obk" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition in %sigbinary_022_php82.php on line 22
ERROR
missing_autoload
Caught Invalid callback missing_autoload, function "missing_autoload" not found or invalid function name
PK7j�\OT����tests/igbinary_024.phptnu�[���--TEST--
Recursive objects
--SKIPIF--
--INI--
error_reporting = E_NONE
--FILE--
<?php
if(!extension_loaded('igbinary')) {
	dl('igbinary.' . PHP_SHLIB_SUFFIX);
}

function test($type, $variable, $test) {
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);
//	$serialized = serialize($variable);
//	$unserialized = unserialize($serialized);

	echo $type, "\n";
	echo substr(bin2hex($serialized), 8), "\n";
//	echo $serialized, "\n";
	echo $test || $unserialized == $variable ? 'OK' : 'ERROR';
	echo "\n";
}

class Obj {
	public $a;
	protected $b;
	private $c;

	function __construct($a, $b, $c) {
		$this->a = $a;
		$this->b = $b;
		$this->c = $c;
	}
}

class Obj2 {
	public $aa;
	protected $bb;
	private $cc;
	private $obj;

	function __construct($a, $b, $c) {
		$this->a = $a;
		$this->b = $b;
		$this->c = $c;

		$this->obj = new Obj($a, $b, $c);
	}
}

class Obj3 {
	private $objs;

	function __construct($a, $b, $c) {
		$this->objs = array();

		for ($i = $a; $i < $c; $i += $b) {
			$this->objs[] = new Obj($a, $i, $c);
		}
	}
}

class Obj4 {
	private $a;
	private $obj;

	function __construct($a) {
		$this->a = $a;
	}

	public function set($obj) {
		$this->obj = $obj;
	}
}

$o2 = new Obj2(1, 2, 3);
test('objectrec', $o2, false);

$o3 = new Obj3(0, 1, 4);
test('objectrecarr', $o3, false);

$o4 = new Obj4(100);
$o4->set($o4);
test('objectselfrec', $o4, true);

/*
 * you can add regression tests for your extension here
 *
 * the output of your test code has to be equal to the
 * text in the --EXPECT-- section below for the tests
 * to pass, differences between the output and the
 * expected text are interpreted as failure
 *
 * see TESTING.md for further information on
 * writing regression tests
 */
?>
--EXPECT--
objectrec
17044f626a32140711026161001105002a006262001108004f626a32006363001109004f626a32006f626a17034f626a140311016106011104002a006206021106004f626a006306030e06060111016206021101630603
OK
objectrecarr
17044f626a331401110a004f626a33006f626a731404060017034f626a140311016106001104002a006206001106004f626a0063060406011a0214030e0306000e0406010e05060406021a0214030e0306000e0406020e05060406031a0214030e0306000e0406030e050604
OK
objectselfrec
17044f626a3414021107004f626a34006106641109004f626a34006f626a2200
OK
PK8j�\�L}ϥ�3tests/php82_suppress_dynamic_properties_warning.incnu�[���<?php
if (PHP_VERSION_ID < 80200) {
    return;
}
$totalErrors = 0;
function igbinary_suppress_dynamic_properties_warning($errno, $errstr): bool {
    if ($errno === E_DEPRECATED && str_contains($errstr, 'Creation of dynamic property')) {
        $GLOBALS['totalErrors']++;
        return true;
    }
    return false;
}
set_error_handler('igbinary_suppress_dynamic_properties_warning');

function igbinary_expect_warn_dynamic_properties(): void {
    if ($GLOBALS['totalErrors'] < 1) {
        echo "Expected this test to have at least one warning about creating dynamic properties in php 8.2\n";
    }
}
register_shutdown_function('igbinary_expect_warn_dynamic_properties');
PK8j�\ݿY��tests/igbinary_059.phptnu�[���--TEST--
igbinary_unserialize should never convert from packed array to hash when references exist (Bug #48)
--SKIPIF--
--FILE--
<?php
function main() {
	$result = array();
	// The default hash size is 16. If we start with 0, and aren't careful, the array would begin as a packed array,
	// and the references would be invalidated when key 50 (>= 16) is added (converted to a hash), causing a segfault.
	foreach (array(0, 50) as $i) {
	    $inner = new stdClass();
	    $inner->a = $i;
	    $result[0][0][$i] = $inner;
	    $result[1][] = $inner;
	}
	$serialized = igbinary_serialize($result);
	printf("%s\n", bin2hex(substr($serialized, 4)));
	flush();
	$unserialized = igbinary_unserialize($serialized);
	var_dump($unserialized);
}
main();
?>
--EXPECTF--
1402060014010600140206001708737464436c6173731401110161060006321a0014010e010632060114020600220306012204
array(2) {
  [0]=>
  array(1) {
    [0]=>
    array(2) {
      [0]=>
      object(stdClass)#%d (1) {
        ["a"]=>
        int(0)
      }
      [50]=>
      object(stdClass)#%d (1) {
        ["a"]=>
        int(50)
      }
    }
  }
  [1]=>
  array(2) {
    [0]=>
    object(stdClass)#%d (1) {
      ["a"]=>
      int(0)
    }
    [1]=>
    object(stdClass)#%d (1) {
      ["a"]=>
      int(50)
    }
  }
}
PK8j�\E��"��tests/igbinary_057.phptnu�[���--TEST--
Test serializing more strings than the capacity of the initial strings table.
--SKIPIF--
--FILE--
<?php
function main() {
	$array = array();
	for ($i = 0; $i < 2; $i++) {
		for ($c = 'a'; $c < 'z'; $c++) {
			$array[] = $c;
		}
	}
	$serialized = igbinary_serialize($array);
	printf("%s\n", bin2hex(substr($serialized, 4)));
	$unserialized = igbinary_unserialize($serialized);
	echo implode(',', $unserialized);
}
main();
?>
--EXPECT--
1432060011016106011101620602110163060311016406041101650605110166060611016706071101680608110169060911016a060a11016b060b11016c060c11016d060d11016e060e11016f060f11017006101101710611110172061211017306131101740614110175061511017606161101770617110178061811017906190e00061a0e01061b0e02061c0e03061d0e04061e0e05061f0e0606200e0706210e0806220e0906230e0a06240e0b06250e0c06260e0d06270e0e06280e0f06290e10062a0e11062b0e12062c0e13062d0e14062e0e15062f0e1606300e1706310e18
a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y
PK9j�\��=((tests/igbinary_045b.phptnu�[���--TEST--
APCu serializer registration
--SKIPIF--
<?php
if (!extension_loaded('apcu')) {
	echo "skip APCu not loaded";
}

$ext = new ReflectionExtension('apcu');
if (version_compare($ext->getVersion(), '4.0.2', '<')) {
	echo "skip require APCu version 4.0.2 or above";
}

--INI--
apc.enable_cli=1
apc.serializer=igbinary
--FILE--
<?php
echo ini_get('apc.serializer'), "\n";

class Bar {
	public $foo = 10;
}

$a = new Bar;
apcu_store('foo', $a);
unset($a);

var_dump(apcu_fetch('foo'));
--EXPECTF--
igbinary
object(Bar)#%d (1) {
  ["foo"]=>
  int(10)
}
PK9j�\��@���tests/__serialize_002.phptnu�[���--TEST--
__serialize() mechanism (002): TypeError on invalid return type
--SKIPIF--
<?php if (PHP_VERSION_ID < 70400) { echo "skip __serialize/__unserialize not supported in php < 7.4 for compatibility with serialize()"; } ?>
--FILE--
<?php

class Test {
    public function __serialize() {
        return $this;
    }
}

try {
    igbinary_serialize(new Test);
} catch (TypeError $e) {
    echo $e->getMessage(), "\n";
}

?>
--EXPECT--
Test::__serialize() must return an array
PK9j�\�tcctests/igbinary_015b.phptnu�[���--TEST--
Check for serialization handler, ini-directive
--SKIPIF--
<?php
if (!extension_loaded('session')) {
	exit('skip session extension not loaded');
}

ob_start();
phpinfo(INFO_MODULES);
$str = ob_get_clean();

$array = explode("\n", $str);
$array = preg_grep('/^igbinary session support.*yes/', $array);
if (!$array) {
	exit('skip igbinary session handler not available');
}

--INI--
--FILE--
<?php
ini_set('session.serialize_handler', 'igbinary');

$output = '';

function open($path, $name) {
	return true;
}

function close() {
	return true;
}

function read($id) {
	global $output;
	return pack('H*', '0000000214011103666f6f0601');
}

function write($id, $data) {
	global $output;
	$output .= substr(bin2hex($data), 8). "\n";
	return true;
}

function destroy($id) {
	return true;
}

function gc($time) {
	return true;
}

session_set_save_handler('open', 'close', 'read', 'write', 'destroy', 'gc');

session_start();

echo ++$_SESSION['foo'], "\n";

session_write_close();

echo $output;

/*
 * you can add regression tests for your extension here
 *
 * the output of your test code has to be equal to the
 * text in the --EXPECT-- section below for the tests
 * to pass, differences between the output and the
 * expected text are interpreted as failure
 *
 * see TESTING.md for further information on
 * writing regression tests
 */
?>
--EXPECT--
2
14011103666f6f0602
PK:j�\�$��tests/igbinary_048b.phptnu�[���--TEST--
Object test, __set not called for private attr in extended class
--FILE--
<?php

class Bar {
    public $a = [];
    public $b = array();
    public $c = NULL;
    private $_d = NULL;
    public function __set($name,$value) {
        echo 'magic function called for ' . $name . ' with ' . var_export($value, true) . PHP_EOL;
    }
}

class Foo extends Bar {
    public $m;
}

$x = new Foo();
$x->a = [1, 2, 3];
$x->nonexistent = 'aaa';

unserialize(serialize($x));
--EXPECT--
magic function called for nonexistent with 'aaa'
PK:j�\��+22tests/igbinary_085.phptnu�[���--TEST--
Properly free unexpected duplicate fields when unserializing arrays
--FILE--
<?php
// Duplicate fields wouldn't be created by calls to igbinary_serialize,
// but make sure to handle them when unserializing corrupt data.
$s = new stdClass();
$ser = igbinary_serialize(['xx' => $s, 'yy' => $s]);
echo urlencode($ser), "\n";
$result = igbinary_unserialize(str_replace('xx', 'yy', $ser));
var_dump($result);
$ser = igbinary_serialize([0x66 => $s, 0x77 => $s]);
echo urlencode($ser), "\n";
$result2 = igbinary_unserialize(str_replace("\x66", "\x77", $ser));
var_dump($result2);
?>
--EXPECT--
%00%00%00%02%14%02%11%02xx%17%08stdClass%14%00%11%02yy%22%01
array(1) {
  ["yy"]=>
  object(stdClass)#2 (0) {
  }
}
%00%00%00%02%14%02%06f%17%08stdClass%14%00%06w%22%01
array(1) {
  [119]=>
  object(stdClass)#3 (0) {
  }
}PK:j�\M���tests/igbinary_025.phptnu�[���--TEST--
Object test, array of objects with __sleep
--SKIPIF--
--FILE--
<?php
if(!extension_loaded('igbinary')) {
	dl('igbinary.' . PHP_SHLIB_SUFFIX);
}

function test($type, $variable, $test) {
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);

	var_dump($variable);
	var_dump($unserialized);
}

class Obj {
	public $a;
	protected $b;
	private $c;
	var $d;

	function __construct($a, $b, $c, $d) {
		$this->a = $a;
		$this->b = $b;
		$this->c = $c;
		$this->d = $d;
	}

	function __sleep() {
		return array('a', 'b', 'c');
	}

#	function __wakeup() {
#		$this->d = $this->a + $this->b + $this->c;
#	}
}

$array = array(
	new Obj("aa", "bb", "cc", "dd"),
	new Obj("ee", "ff", "gg", "hh"),
	new Obj(1, 2, 3, 4),
);


test('array', $array, true);

?>
--EXPECTREGEX--
array\(3\) {
  \[0\]=>
  object\(Obj\)#1 \(4\) {
    \["a"\]=>
    string\(2\) "aa"
    \[("b":protected|"b:protected")\]=>
    string\(2\) "bb"
    \["?c"?:("Obj":)?private"?\]=>
    string\(2\) "cc"
    \["d"\]=>
    string\(2\) "dd"
  }
  \[1\]=>
  object\(Obj\)#2 \(4\) {
    \["a"\]=>
    string\(2\) "ee"
    \["?b"?:protected"?\]=>
    string\(2\) "ff"
    \["?c"?:("Obj":)?private"?\]=>
    string\(2\) "gg"
    \["d"\]=>
    string\(2\) "hh"
  }
  \[2\]=>
  object\(Obj\)#3 \(4\) {
    \["a"\]=>
    int\(1\)
    \["?b"?:protected"?\]=>
    int\(2\)
    \["?c"?:("Obj":)?private"?\]=>
    int\(3\)
    \["d"\]=>
    int\(4\)
  }
}
array\(3\) {
  \[0\]=>
  object\(Obj\)#4 \(4\) {
    \["a"\]=>
    string\(2\) "aa"
    \["?b"?:protected"?\]=>
    string\(2\) "bb"
    \["?c"?:("Obj":)?private"?\]=>
    string\(2\) "cc"
    \["d"\]=>
    NULL
  }
  \[1\]=>
  object\(Obj\)#5 \(4\) {
    \["a"\]=>
    string\(2\) "ee"
    \["?b"?:protected"?\]=>
    string\(2\) "ff"
    \["?c"?:("Obj":)?private"?\]=>
    string\(2\) "gg"
    \["d"\]=>
    NULL
  }
  \[2\]=>
  object\(Obj\)#6 \(4\) {
    \["a"\]=>
    int\(1\)
    \["?b"?:protected"?\]=>
    int\(2\)
    \["?c"?:("Obj":)?private"?\]=>
    int\(3\)
    \["d"\]=>
    NULL
  }
}
PK;j�\����tests/igbinary_083.phptnu�[���--TEST--
igbinary object with reference to ArrayObject
--INI--
; Note that php 8.1 deprecates using Serializable without __serialize/__unserialize but we are testing Serialize for igbinary. Suppress deprecations.
error_reporting=E_ALL & ~E_DEPRECATED
--FILE--
<?php

class UnSerializable implements Serializable
{
    public function serialize() {
        echo "Called serialize\n";
    }
    public function unserialize($serialized) {
        echo "Called unserialize\n";
    }
}

$unser = new UnSerializable();
$arr = [$unser];
$arr[1] = &$arr[0];
$arr[2] = 'endcap';
$arr[3] = &$arr[2];

$data = igbinary_serialize($arr);
echo urlencode($data) . PHP_EOL;
$recovered = igbinary_unserialize($data);
var_dump($recovered);
?>
--EXPECT--
Called serialize
%00%00%00%02%14%04%06%00%25%00%06%01%25%22%01%06%02%25%11%06endcap%06%03%25%01%02
array(4) {
  [0]=>
  &NULL
  [1]=>
  &NULL
  [2]=>
  &string(6) "endcap"
  [3]=>
  &string(6) "endcap"
}PK;j�\��S���tests/igbinary_046b.phptnu�[���--TEST--
Correctly unserialize multiple object refs.
--SKIPIF--
--INI--
igbinary.compact_strings = On
--FILE--
<?php
$a = array(new stdClass());
$a[1] = &$a[0];
$a[2] = &$a[1];
$a[3] = &$a[2];
printf("%s\n", serialize($a));
$ig_ser = igbinary_serialize($a);
printf("%s\n", bin2hex($ig_ser));
$ig = igbinary_unserialize($ig_ser);
printf("%s\n", serialize($ig));
$f = &$ig[3];
$f = 'V';
var_dump($ig);
--EXPECT--
a:4:{i:0;O:8:"stdClass":0:{}i:1;R:2;i:2;R:2;i:3;R:2;}
0000000214040600251708737464436c6173731400060125220106022522010603252201
a:4:{i:0;O:8:"stdClass":0:{}i:1;R:2;i:2;R:2;i:3;R:2;}
array(4) {
  [0]=>
  &string(1) "V"
  [1]=>
  &string(1) "V"
  [2]=>
  &string(1) "V"
  [3]=>
  &string(1) "V"
}
PK;j�\�q��tests/igbinary_016.phptnu�[���--TEST--
Object test, __sleep
--SKIPIF--
--FILE--
<?php
if(!extension_loaded('igbinary')) {
	dl('igbinary.' . PHP_SHLIB_SUFFIX);
}

function test($type, $variable, $test) {
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);

	echo $type, "\n";
	echo substr(bin2hex($serialized), 8), "\n";
	echo $test || $unserialized == $variable ? 'OK' : 'ERROR';
	echo "\n";
}

class Obj {
	public $a;
	protected $b;
	private $c;
	var $d;

	function __construct($a, $b, $c, $d) {
		$this->a = $a;
		$this->b = $b;
		$this->c = $c;
		$this->d = $d;
	}

	function __sleep() {
		return array('a', 'b', 'c');
	}

#	function __wakeup() {
#		$this->d = $this->a + $this->b + $this->c;
#	}
}

$o = new Obj(1, 2, 3, 4);


test('object', $o, true);

/*
 * you can add regression tests for your extension here
 *
 * the output of your test code has to be equal to the
 * text in the --EXPECT-- section below for the tests
 * to pass, differences between the output and the
 * expected text are interpreted as failure
 *
 * see TESTING.md for further information on
 * writing regression tests
 */
?>
--EXPECT--
object
17034f626a140311016106011104002a006206021106004f626a00630603
OK
PK;j�\���99tests/igbinary_097.phptnu�[���--TEST--
Test serialize globals
--SKIPIF--
<?php
if (!extension_loaded("igbinary")) print "skip\n";
if (PHP_VERSION_ID >= 80100) print "skip php >= 8.1\n"; // https://wiki.php.net/rfc/restrict_globals_usage
?>
--FILE--
<?php
call_user_func(function () {
    foreach ($GLOBALS as $key => $_) {
        if ($key !== 'GLOBALS') {
            unset($GLOBALS[$key]);
        }
    }
    $ser = igbinary_serialize($GLOBALS);
    echo urlencode($ser) . "\n";
    var_dump(igbinary_unserialize($ser));
    $GLOBALS['globalVar'] = new stdClass();
    $ser = igbinary_serialize($GLOBALS);
    echo urlencode($ser) . "\n";
    var_dump(igbinary_unserialize($ser));
});
--EXPECTF--
%00%00%00%02%14%01%11%07GLOBALS%14%01%0E%00%01%01
array(1) {
  ["GLOBALS"]=>
  array(1) {
    ["GLOBALS"]=>
    *RECURSION*
  }
}
%00%00%00%02%14%02%11%07GLOBALS%14%02%0E%00%01%01%11%09globalVar%17%08stdClass%14%00%0E%01%22%02
array(2) {
  ["GLOBALS"]=>
  array(2) {
    ["GLOBALS"]=>
    *RECURSION*
    ["globalVar"]=>
    object(stdClass)#3 (0) {
    }
  }
  ["globalVar"]=>
  object(stdClass)#3 (0) {
  }
}
PK<j�\c#�ѐ�tests/igbinary_044.phptnu�[���--TEST--
Check for double extremes
--FILE--
<?php

function str2bin($bytestring) {
	$len = strlen($bytestring);
	$output = '';

	for ($i = 0; $i < $len; $i++) {
		$bin = decbin(ord($bytestring[$i]));
		$bin = str_pad($bin, 8, '0', STR_PAD_LEFT);
		$output .= $bin;
	}

	return $output;
}

function test($type, $variable, $validOutputs = null) {
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);

	echo $type, ":\n";
	var_dump($variable);
	var_dump($unserialized);

	echo "   6         5         4         3         2         1\n";
	echo "3210987654321098765432109876543210987654321098765432109876543210\n";
	$output = substr($serialized, 5, 8);
	$binOutput = str2bin($output);
	if ($validOutputs === null) {
		echo $binOutput, "\n";
	} else {
		echo in_array($binOutput, $validOutputs) ? "ACCEPTABLE" : ("UNACCEPTABLE : " . $binOutput);
		echo "\n";
	}
	echo "\n";
}

// subnormal number
test('double subnormal', -4.944584125e-314);

// max subnormal: sign 0, exponent 0, all 1 double
// http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
test('double 1 max subnormal', 2.2250738585072010e-308);
test('double 2 max subnormal', 2.2250738585072011e-308);
$validOutputs = array('0000000000010000000000000000000000000000000000000000000000000000',
                      '0000000000001111111111111111111111111111111111111111111111111111');
test('double 3 max subnormal', 2.2250738585072012e-308, $validOutputs);
test('double 4 max subnormal', 2.2250738585072013e-308, $validOutputs);
test('double 5 max subnormal', 2.2250738585072014e-308);

// min subnormal number
test('double min subnormal', -4.9406564584124654e-324);

// big double
test('double big', -1.79769e308);

// max double, sign 0, exponent all-1 - 1, mantissa all-1
test('double max',  1.7976931348623157e308);

// small double
test('double small', -2.225e-308);
// min double, sign 1, exponent all-1 - 1, mantissa all-1
test('double min',  -1.7976931348623157e308);


--EXPECTF--
double subnormal:
float(-4.944584125%S-314)
float(-4.944584125%S-314)
   6         5         4         3         2         1
3210987654321098765432109876543210987654321098765432109876543210
1000000000000000000000000000001001010100100001010011000101110110

double 1 max subnormal:
float(2.2250738585072%SE-308)
float(2.2250738585072%SE-308)
   6         5         4         3         2         1
3210987654321098765432109876543210987654321098765432109876543210
0000000000001111111111111111111111111111111111111111111111111111

double 2 max subnormal:
float(2.2250738585072%SE-308)
float(2.2250738585072%SE-308)
   6         5         4         3         2         1
3210987654321098765432109876543210987654321098765432109876543210
0000000000001111111111111111111111111111111111111111111111111111

double 3 max subnormal:
float(2.2250738585072%SE-308)
float(2.2250738585072%SE-308)
   6         5         4         3         2         1
3210987654321098765432109876543210987654321098765432109876543210
ACCEPTABLE

double 4 max subnormal:
float(2.2250738585072%SE-308)
float(2.2250738585072%SE-308)
   6         5         4         3         2         1
3210987654321098765432109876543210987654321098765432109876543210
ACCEPTABLE

double 5 max subnormal:
float(2.2250738585072%SE-308)
float(2.2250738585072%SE-308)
   6         5         4         3         2         1
3210987654321098765432109876543210987654321098765432109876543210
0000000000010000000000000000000000000000000000000000000000000000

double min subnormal:
float(-%SE-324)
float(-%SE-324)
   6         5         4         3         2         1
3210987654321098765432109876543210987654321098765432109876543210
1000000000000000000000000000000000000000000000000000000000000001

double big:
float(-1.79769E+308)
float(-1.79769E+308)
   6         5         4         3         2         1
3210987654321098765432109876543210987654321098765432109876543210
1111111111101111111111111111110001010111110010101000001010101110

double max:
float(1.7976931348623%SE+308)
float(1.7976931348623%SE+308)
   6         5         4         3         2         1
3210987654321098765432109876543210987654321098765432109876543210
0111111111101111111111111111111111111111111111111111111111111111

double small:
float(-2.225E-308)
float(-2.225E-308)
   6         5         4         3         2         1
3210987654321098765432109876543210987654321098765432109876543210
1000000000001111111111111101110100110001101000000000110001101101

double min:
float(-1.7976931348623%SE+308)
float(-1.7976931348623%SE+308)
   6         5         4         3         2         1
3210987654321098765432109876543210987654321098765432109876543210
1111111111101111111111111111111111111111111111111111111111111111
PK<j�\��3G��tests/igbinary_030_php7.phptnu�[���--TEST--
Unserialize invalid data
--SKIPIF--
<?php
if(!extension_loaded('igbinary')) {
	echo "skip no igbinary";
}
if (PHP_VERSION_ID >= 70200) {
    echo "Skip php 7.1 or 7.0 required\n";
}
?>
--FILE--
<?php

$o = new stdClass();
$o->{"1"} = "manual";

$datas = array(
	87817,
	-1,
	array(1,2,3,"testing" => 10, "foo"),
	true,
	false,
	0.187182,
	"dakjdh98389\000",
	null,
	(object)array(1,2,3),
    $o,
);

error_reporting(0);
foreach ($datas as $data) {
	$str = igbinary_serialize($data);
	$len = strlen($str);

	// truncated
	for ($i = 0; $i < $len - 1; $i++) {
		$v = igbinary_unserialize(substr($str, 0, $i));
		if (is_object($data) && $v !== null && $v == $data) {
			continue;
		} elseif ($v !== null && $v != FALSE && $v !== $data) {
			echo "output at $i:\n";
			var_dump($v);
			echo "vs.\n";
			var_dump($data);
		}
	}

	// padded
	$str2 = $str . "98398afa\000y21_ ";
	$v = igbinary_unserialize($str2);
	if ($v !== NULL) {
		echo "Should return null with padding\n";
		var_dump($v);
	}
	$str3 = $str . "\x00";
	$v = igbinary_unserialize($str3);
	if ($v !== NULL) {
		echo "Should return null with single byte of padding\n";
		var_dump($v);
	}
}
echo "Success!\n";
?>
--EXPECT--
Success!
PK<j�\Kl\�WWtests/igbinary_004.phptnu�[���--TEST--
Check for integer serialisation
--SKIPIF--
--FILE--
<?php
if(!extension_loaded('igbinary')) {
	dl('igbinary.' . PHP_SHLIB_SUFFIX);
}

function test($type, $variable) {
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);

	echo $type, "\n";
	echo substr(bin2hex($serialized), 8), "\n";
	echo $unserialized === $variable ? 'OK' : 'ERROR';
	echo "\n";
}

test('zero: 0', 0);
test('small: 1',  1);
test('small: -1',  -1);
test('medium: 1000', 1000);
test('medium: -1000', -1000);
test('large: 100000', 100000);
test('large: -100000', -100000);

/*
 * you can add regression tests for your extension here
 *
 * the output of your test code has to be equal to the
 * text in the --EXPECT-- section below for the tests
 * to pass, differences between the output and the
 * expected text are interpreted as failure
 *
 * see TESTING.md for further information on
 * writing regression tests
 */
?>
--EXPECT--
zero: 0
0600
OK
small: 1
0601
OK
small: -1
0701
OK
medium: 1000
0803e8
OK
medium: -1000
0903e8
OK
large: 100000
0a000186a0
OK
large: -100000
0b000186a0
OK
PK=j�\I�~w��tests/igbinary_063_php72.phptnu�[���--TEST--
Accessing unserialized numbers.
--SKIPIF--
<?php
if(!extension_loaded('igbinary')) {
	echo "skip no igbinary";
}
if (PHP_VERSION_ID < 70200) {
    echo "Skip php 7.2+ required";
}
?>
--FILE--
<?php

$data = (object)array(1,2,3, -1 => 'x', 1234 => 33);
var_dump($data);
$x = "1";
$y = 1;
$z = "1234";
$w = 1234;
var_dump(isset($data->{$x}) ? $data->{$x} : "unset");
error_reporting(0);
$str = igbinary_serialize($data);

$unserialized = igbinary_unserialize($str);
var_dump($unserialized);
var_dump(isset($unserialized->{$x}) ? $unserialized->{$x} : "unset str");
var_dump(isset($unserialized->{$y}) ? $unserialized->{$y} : "unset int");
var_dump(isset($unserialized->{$z}) ? $unserialized->{$z} : "unset str 1234");
var_dump(isset($unserialized->{$w}) ? $unserialized->{$w} : "unset int 1234");
var_dump(isset($unserialized->{-1}) ? $unserialized->{-1} : "unset int -1");
?>
--EXPECT--
object(stdClass)#1 (5) {
  ["0"]=>
  int(1)
  ["1"]=>
  int(2)
  ["2"]=>
  int(3)
  ["-1"]=>
  string(1) "x"
  ["1234"]=>
  int(33)
}
int(2)
object(stdClass)#2 (5) {
  ["0"]=>
  int(1)
  ["1"]=>
  int(2)
  ["2"]=>
  int(3)
  ["-1"]=>
  string(1) "x"
  ["1234"]=>
  int(33)
}
int(2)
int(2)
int(33)
int(33)
string(1) "x"
PK=j�\�3^�	�	tests/igbinary_071.phptnu�[���--TEST--
igbinary_unserialize with references to typed properties shall skip the references or fail
--SKIPIF--
<?php
if (PHP_VERSION_ID < 70400) { echo "skip __serialize/__unserialize not supported in php < 7.4 for compatibility with serialize()"; }
if (PHP_VERSION_ID >= 80000) { echo "skip different error message format"; }
?>
--FILE--
<?php

class A {
	public int $a;
	public $b;
}

class B {
	public $a;
	public int $b;
}

class C {
	public int $a;
	public string $b;
}

class D {
    public int $a;
    public float $b;
}

class Z {
	public $a;
	public $b;
}
$a = new A();
$a->a = 1234;
$a->b = &$a->a;
var_dump(bin2hex($s = igbinary_serialize($a)));
var_dump(igbinary_unserialize($s));
echo "Test B\n";
$b = new B();
$b->a = -1234;
$b->b = &$b->a;
var_dump(bin2hex($s = igbinary_serialize($b)));
var_dump(igbinary_unserialize($s));

$z = new Z();
$z->a = null;
$z->b = &$z->a;
$s = igbinary_serialize($z);
try {
    var_dump(igbinary_unserialize(str_replace('Z', 'A', $s)));
} catch (TypeError $e) {
    echo $e->getMessage(), "\n";
}

try {
    var_dump(igbinary_unserialize(str_replace('Z', 'B', $s)));
} catch (TypeError $e) {
    echo $e->getMessage(), "\n";
}
$z = new Z();
$z->a = 1;
$z->b = &$z->a;
$s = igbinary_serialize($z);
try {
    var_dump(igbinary_unserialize(str_replace('Z', 'C', $s)));
} catch (TypeError $e) {
    echo $e->getMessage(), "\n";
}
$z = new Z();
$z->a = 'x';
$z->b = &$z->a;
$s = igbinary_serialize($z);
try {
    var_dump(igbinary_unserialize(str_replace('Z', 'C', $s)));
} catch (TypeError $e) {
    echo $e->getMessage(), "\n";
}
$z = new Z();
$z->a = 1;
$z->b = &$z->a;
$s = igbinary_serialize($z);
try {
    var_dump(igbinary_unserialize(str_replace('Z', 'D', $s)));
} catch (TypeError $e) {
    echo $e->getMessage(), "\n";
}
/*
try {
    var_dump(unserialize('O:1:"D":2:{s:1:"a";i:1;s:1:"b";R:2;}'));
} catch (TypeError $e) {
    echo $e->getMessage(), "\n";
}
 */

?>
--EXPECT--
string(44) "000000021701411402110161250804d2110162250101"
object(A)#2 (2) {
  ["a"]=>
  &int(1234)
  ["b"]=>
  &int(1234)
}
Test B
string(44) "000000021701421402110161250904d2110162250101"
object(B)#3 (2) {
  ["a"]=>
  &int(-1234)
  ["b"]=>
  &int(-1234)
}
Typed property A::$a must be int, null used
Typed property B::$b must be int, null used
Typed property C::$b must be string, int used
Typed property C::$a must be int, string used
Reference with value of type int held by property D::$a of type int is not compatible with property D::$b of type float
PK=j�\�O,�tests/igbinary_065.phptnu�[���--TEST--
Don't emit zval has unknown type 0 (IS_UNDEF)
--FILE--
<?php
function var_export_normalized($value) { echo ltrim(var_export($value, true), "\\"); }
class MyClass {
    public $kept = 2;
    public $x;
    protected $y;
    private $z;
    protected $set = 2;
    private $priv = 2;
    private $omitted = 'myVal';

    public function __sleep() {
        unset($this->x);
        unset($this->y);
        unset($this->z);
        $this->set = 'setVal';
        $this->priv = null;
        $this->omitted = 'otherVal';

        return ['kept', 'x', 'y', 'z', 'set', 'priv'];
    }
}
error_reporting(E_ALL);
// TODO: emit 'Notice: igbinary_serialize(): "x" returned as member variable from __sleep() but does not exist' instead.
$serialized = igbinary_serialize(new MyClass());
echo bin2hex($serialized) . "\n";
var_export_normalized(igbinary_unserialize($serialized));
echo "\n";
?>
--EXPECTF--
Notice: igbinary_serialize(): "x" returned as member variable from __sleep() but does not exist in %s on line 25

Notice: igbinary_serialize(): "y" returned as member variable from __sleep() but does not exist in %s on line 25

Notice: igbinary_serialize(): "z" returned as member variable from __sleep() but does not exist in %s on line 25
0000000217074d79436c617373140611046b6570740602110178001104002a007900110a004d79436c617373007a001106002a00736574110673657456616c110d004d79436c617373007072697600
MyClass::__set_state(array(
   'kept' => 2,
   'x' => NULL,
   'y' => NULL,
   'z' => NULL,
   'set' => 'setVal',
   'priv' => NULL,
   'omitted' => 'myVal',
))
PK@j�\Pl�HHtests/igbinary_018.phptnu�[���--TEST--
Object test, __sleep error cases
--SKIPIF--
--FILE--
<?php
if(!extension_loaded('igbinary')) {
	dl('igbinary.' . PHP_SHLIB_SUFFIX);
}

error_reporting(0);

function test($type, $variable, $test) {
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);

	echo $type, "\n";
	echo substr(bin2hex($serialized), 8), "\n";
	echo $test || $unserialized == $variable ? 'OK' : 'ERROR';
	echo "\n";
}

class Obj {
	var $a;
	var $b;

	function __construct($a, $b) {
		$this->a = $a;
		$this->b = $b;
	}

	function __sleep() {
		return array('c');
	}

#	function __wakeup() {
#		$this->b = $this->a * 3;
#	}
}

class Opj {
	var $a;
	var $b;

	function __construct($a, $b) {
		$this->a = $a;
		$this->b = $b;
	}

	function __sleep() {
		return array(1);
	}

#	function __wakeup() {
#
#	}
}

$o = new Obj(1, 2);
$p = new Opj(1, 2);

test('nonexisting', $o, true);
test('wrong', $p, true);

/*
 * you can add regression tests for your extension here
 *
 * the output of your test code has to be equal to the
 * text in the --EXPECT-- section below for the tests
 * to pass, differences between the output and the
 * expected text are interpreted as failure
 *
 * see TESTING.md for further information on
 * writing regression tests
 */
?>
--EXPECT--
nonexisting
17034f626a140111016300
OK
wrong
17034f706a140100
OK
PK@j�\uu�)tests/igbinary_013.phptnu�[���--TEST--
Object-Array test
--SKIPIF--
--FILE--
<?php
if(!extension_loaded('igbinary')) {
	dl('igbinary.' . PHP_SHLIB_SUFFIX);
}

function test($type, $variable, $test) {
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);

	echo $type, "\n";
	echo substr(bin2hex($serialized), 8), "\n";
	echo $test || $unserialized == $variable ? 'OK' : 'ERROR';
	echo "\n";
}

class Obj {
	var $a;
	var $b;

	function __construct($a, $b) {
		$this->a = $a;
		$this->b = $b;
	}
}

$o = array(new Obj(1, 2), new Obj(3, 4));


test('object', $o, false);

/*
 * you can add regression tests for your extension here
 *
 * the output of your test code has to be equal to the
 * text in the --EXPECT-- section below for the tests
 * to pass, differences between the output and the
 * expected text are interpreted as failure
 *
 * see TESTING.md for further information on
 * writing regression tests
 */
?>
--EXPECT--
object
1402060017034f626a14021101610601110162060206011a0014020e0106030e020604
OK
PK@j�\6E��00tests/igbinary_074.phptnu�[���--TEST--
igbinary and not enough data for array
--FILE--
<?php
echo "One byte\n";
igbinary_unserialize("\x00\x00\x00\x02\x14");
echo "Two byte\n";
igbinary_unserialize("\x00\x00\x00\x02\x15\x01");
igbinary_unserialize("\x00\x00\x00\x02\x15");
igbinary_unserialize("\x00\x00\x00\x02\x15\x00\x01");
echo "Four byte\n";
igbinary_unserialize("\x00\x00\x00\x02\x16\x00");
igbinary_unserialize("\x00\x00\x00\x02\x16\x00\x00\x01");
igbinary_unserialize("\x00\x00\x00\x02\x16\x00\x00\x00\x01");
?>
--EXPECTF--
One byte

Warning: igbinary_unserialize_array: end-of-data in %s on line 3
Two byte

Warning: igbinary_unserialize_array: end-of-data in %s on line 5

Warning: igbinary_unserialize_array: end-of-data in %s on line 6

Warning: igbinary_unserialize_array: data size 0 smaller that requested array length 1. in %s on line 7
Four byte

Warning: igbinary_unserialize_array: end-of-data in %s on line 9

Warning: igbinary_unserialize_array: end-of-data in %s on line 10

Warning: igbinary_unserialize_array: data size 0 smaller that requested array length 1. in %s on line 11
PKAj�\ؖy���tests/igbinary_046.phptnu�[���--TEST--
Correctly unserialize scalar refs.
--INI--
igbinary.compact_strings = On
--FILE--
<?php
$a = array("A");
$a[1] = &$a[0];
$a[2] = &$a[1];
$a[3] = &$a[2];

$ig_ser = igbinary_serialize($a);
echo bin2hex($ig_ser) . "\n";
$ig = igbinary_unserialize($ig_ser);
$f = &$ig[3];
$f = 'V';
var_dump($ig);
--EXPECT--
000000021404060025110141060125010106022501010603250101
array(4) {
  [0]=>
  &string(1) "V"
  [1]=>
  &string(1) "V"
  [2]=>
  &string(1) "V"
  [3]=>
  &string(1) "V"
}
PKAj�\G1��

tests/igbinary_026.phptnu�[���--TEST--
Cyclic array test
--INI--
report_memleaks=0
--SKIPIF--
<?php
if (!extension_loaded('igbinary')) {
	echo "skip no igbinary";
}
if (PHP_MAJOR_VERSION > 7) {
	echo "skip requires php 7.x\n";
}
--FILE--
<?php

function test($type, $variable, $test) {
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);

	echo $type, "\n";
	echo substr(bin2hex($serialized), 8), "\n";
	echo !$test || $unserialized == $variable ? 'OK' : 'ERROR', "\n";
}

$a = array(
	'a' => array(
		'b' => 'c',
		'd' => 'e'
	),
);

$a['f'] = &$a;

test('array', $a, false);

$a = array("foo" => &$b);
$b = array(1, 2, $a);

$exp = $a;
$act = igbinary_unserialize(igbinary_serialize($a));

ob_start();
var_dump($exp);
$dump_exp = ob_get_clean();
ob_start();
var_dump($act);
$dump_act = ob_get_clean();

if ($dump_act !== $dump_exp) {
	echo "Var dump differs:\n", $dump_act, "\n", $dump_exp, "\n";
} else {
	echo "Var dump OK\n";
}

$act['foo'][1] = 'test value';
$exp['foo'][1] = 'test value';
if ($act['foo'][1] !== $act['foo'][2]['foo'][1]) {
	echo "Recursive elements differ:\n";
	var_dump($act);
	var_dump($act['foo']);
	var_dump($exp);
	var_dump($exp['foo']);
}

?>
--EXPECT--
array
140211016114021101621101631101641101651101662514020e0001010e05250102
OK
Var dump OK
PKAj�\�a�99tests/__serialize_008.phptnu�[���--TEST--
__serialize() mechanism (007): handle __destruct of returned data
--SKIPIF--
<?php if (PHP_VERSION_ID < 70400) { echo "skip __serialize/__unserialize not supported in php < 7.4 for compatibility with serialize()\n"; } ?>
<?php if (PHP_VERSION_ID >= 90000) { echo "skip requires php < 9.0 when testing that the deprecation has no impact on igbinary functionality\n"; } ?>
--FILE--
<?php
if (PHP_VERSION_ID >= 80200) { require_once __DIR__ . '/php82_suppress_dynamic_properties_warning.inc'; }

class DestructorThrows {
    public function __construct(string $val) {
        $this->val = $val;
    }
    public function __destruct() {
        echo "DestructorThrows called val=$this->val\n";
        throw new RuntimeException($this->val);
    }
}

class Xyz {
    public $Xyz;
    public function __serialize() {
        return [new DestructorThrows($this->Xyz)];
    }
    public function __unserialize(array $data) {
        $this->Xyz = $data[0];
    }

    public function __destruct() {
        // should not be called
        echo "Called destruct prop=$this->Xyz\n";
    }
}

$test = new Xyz;
$test->Xyz = 'Xyz';

try {
    var_dump(bin2hex($s = igbinary_serialize($test)));
} catch (RuntimeException $e) {
    echo "message={$e->getMessage()}\n";
}
unset($test);

$test = new Xyz;
$test->Xyz = '';
try {
    var_dump(bin2hex($s = igbinary_serialize($test)));
} catch (RuntimeException $e) {
    echo "message={$e->getMessage()}\n";
}
?>
--EXPECT--
DestructorThrows called val=Xyz
message=Xyz
DestructorThrows called val=
Called destruct prop=Xyz
message=
Called destruct prop=
PKAj�\�g�S1
1
tests/igbinary_009b.phptnu�[���--TEST--
Check for reference serialization (Original example, not using var_dump)
--SKIPIF--
<?php
if (!extension_loaded('igbinary')) {
	echo "skip no igbinary";
}
if (PHP_MAJOR_VERSION > 7) {
	echo "skip requires php 7.x\n";
}
--INI--
pcre.jit=0
--FILE--
<?php
error_reporting(E_ALL|E_STRICT);
// Verify that $type[0] is the same zval as $type[0][0][0], but different from $type[0]
function test_cyclic2($type, $variable) {
	$serialized = igbinary_serialize($variable);
	$unserialized = igbinary_unserialize($serialized);
	echo $type, "\n";
	echo substr(bin2hex($serialized), 8), "\n";
	// Can't use === or == on two recursive arrays in some cases
	echo array_keys($unserialized) === array_keys($variable) && array_keys($unserialized[0]) === array_keys($variable[0]) ? 'OK' : 'ERROR', "\n";
	ob_start();
	var_dump($variable);
	$dump_exp = ob_get_clean();
	ob_start();
	var_dump($unserialized);
	$dump_act = ob_get_clean();
	if (preg_replace('/&array/', 'array', $dump_act) !== preg_replace('/&array/', 'array', $dump_exp)) {
		echo "But var dump differs:\nActual:\n", $dump_act, "\nExpected\n", $dump_exp, "\n";
		echo "(Was normalized)\n";
	}

	if (!isset($unserialized[0]) || count($unserialized) != 1) {
		printf("Unexpected keys: %s\n", array_keys($unserialized));
		return;
	} else if (!is_array($unserialized)) {
		printf("\$a[0] is not an array, it is %s", gettype($unserialized));
		return;
	}
	// Set a key, check for the presence of the key 2 levels deeper (Should find it) and 1 level deeper (Should not find it)
	$unserialized[0]['test'] = 'foo';
	if ($unserialized[0][0][0]['test'] !== 'foo') {
		echo "Expected the unserialized array to be cyclic\n";
	}
	if (isset($unserialized[0][0]['test'])) {
		echo "Expected the unserialized array to be cyclic AND of cycle depth 2, but cycle depth is 1\n";
	}
}
$a = [null];
$b = [&$a];
$a[0] = &$b;
// 1401060025140106002514010600250101 could also be serialized as 14010600251401060014010600250101 if we normalized the references which only occurred once in the serialization
// (Replace middle &array(&$a) with array(&$array), i.e. second 2514 with 14)
test_cyclic2('cyclic $a = array(&array(&$a)) - testing functionality', $a);
unset($a);
$a = null;
$a = [[&$a]];
test_cyclic2('cyclic $a = array(array(&$a)); $a[0] - testing functionality', $a[0]);
// $a serializes as 140106001401060025140106000101 - This is a bug, probably exists in php5 as well.
--EXPECT--
cyclic $a = array(&array(&$a)) - testing functionality
1401060025140106002514010600250101
OK
cyclic $a = array(array(&$a)); $a[0] - testing functionality
14010600251401060014010600250101
OK
PKBj�\��MMtests/__serialize_019.phptnu�[���--TEST--
__serialize() freed on unserialize exception without calling destructor.
--SKIPIF--
<?php if (PHP_VERSION_ID < 70400) { echo "skip __serialize/__unserialize not supported in php < 7.4 for compatibility with serialize()"; } ?>
--FILE--
<?php

class Test {
    public $prop;
    public $prop2;
    public function __serialize() {
        return [0 => $this->prop, "value" => $this->prop2];
    }
    public function __unserialize(array $data) {
        echo "In __unserialize Test\n";
        $this->prop = $data[0];
        $this->prop2 = $data['value'];
        unset($data[0]);
        unset($data['value']);
    }

    public function __destruct() {
        echo "In __destruct Test\n";
    }
}

$obj = new stdClass();
$testObj = new Test();
$testObj->prop = 123;
$testObj->prop2 = ['xyz'];
$obj->test = 'bar';
$obj->value = &$testObj;

var_dump(bin2hex($s = igbinary_serialize($obj)));
var_dump(igbinary_unserialize($s));
echo "Done\n";
?>
--EXPECT--
string(116) "000000021708737464436c61737314021104746573741103626172110576616c75652517045465737414020600067b0e0314010600110378797a"
In __unserialize Test
object(stdClass)#3 (2) {
  ["test"]=>
  string(3) "bar"
  ["value"]=>
  object(Test)#4 (2) {
    ["prop"]=>
    int(123)
    ["prop2"]=>
    array(1) {
      [0]=>
      string(3) "xyz"
    }
  }
}
In __destruct Test
Done
In __destruct Test
PKj�\O\��^	^	tests/igbinary_071_php8.phptnu�[���PKj�\���PP�	tests/__serialize_001.phptnu�[���PKj�\H��7yyD
tests/igbinary_087.phptnu�[���PKj�\"��Ņ�&tests/igbinary_020.phptnu�[���PKj�\6ğ���*tests/igbinary_054.phptnu�[���PKj�\��+��
�
�0tests/__serialize_004.phptnu�[���PKj�\��z���;tests/__serialize_009.phptnu�[���PKj�\�e
v���Dtests/igbinary_092.phptnu�[���PKj�\��//Itests/igbinary_051.phptnu�[���PKj�\Z�{Ltests/igbinary_027.phptnu�[���PKj�\�H��VV�Rtests/igbinary_084.phptnu�[���PKj�\����qUtests/igbinary_003.phptnu�[���PKj�\E�A`���Ytests/igbinary_045c.phptnu�[���PKj�\`��Ooo�`tests/igbinary_040.phptnu�[���PKj�\¡�V	V	\gtests/igbinary_095.phptnu�[���PKj�\��mGG�ptests/igbinary_005.phptnu�[���PKj�\�'��QQ�ttests/__serialize_012.phptnu�[���PKj�\������"ytests/igbinary_033.phptnu�[���PKj�\g�5���|tests/igbinary_053.phptnu�[���PKj�\�	pן�(�tests/__serialize_016_php8.phptnu�[���PKj�\���mm�tests/igbinary_058.phptnu�[���PKj�\e�O��ʖtests/igbinary_084b.phptnu�[���PKj�\~-::��tests/igbinary_076.phptnu�[���PKj�\a���5�tests/__serialize_013.phptnu�[���PKj�\�������tests/igbinary_099.phptnu�[���PKj�\��Ȁqqk�tests/igbinary_007.phptnu�[���PKj�\W�;�gg#�tests/igbinary_069.phptnu�[���PKj�\�8eeѲtests/igbinary_026_php8.phptnu�[���PKj�\"�����tests/igbinary_068.phptnu�[���PKj�\������tests/igbinary_096.phptnu�[���PKj�\�E�n޽tests/igbinary_008.phptnu�[���PKj�\�Ue�((C�tests/igbinary_048.phptnu�[���PKj�\�(X�dd��tests/igbinary_015c.phptnu�[���PKj�\k�}Z��^�tests/igbinary_043.phptnu�[���PKj�\ydy����tests/igbinary_089_32bit.phptnu�[���PKj�\���o++��tests/igbinary_001.phptnu�[���PKj�\�ILqN�tests/__serialize_014.phptnu�[���PKj�\��U����tests/igbinary_enums_1.phptnu�[���PKj�\G�k���tests/__serialize_007.phptnu�[���PKj�\������7�tests/igbinary_090.phptnu�[���PKj�\��o�}}*�tests/igbinary_058b.phptnu�[���PKj�\`�>l����tests/igbinary_063_php7.phptnu�[���PKj�\*���77�tests/igbinary_enums_2.phptnu�[���PKj�\C�(�""��tests/igbinary_070.phptnu�[���PKj�\.��M%%�tests/igbinary_bug72134.phptnu�[���PK j�\1��I66a�tests/igbinary_067.phptnu�[���PK j�\�=u��tests/__serialize_013_php8.phptnu�[���PK j�\���>Dtests/igbinary_031.phptnu�[���PK j�\k7z88�tests/igbinary_081.phptnu�[���PK!j�\�[	[	%tests/igbinary_028.phptnu�[���PK!j�\�ꞩ66�#tests/igbinary_049.phptnu�[���PK!j�\�lr��D+tests/__serialize_017.phptnu�[���PK!j�\|�����1/tests/__serialize_003.phptnu�[���PK"j�\�r�;��K6tests/igbinary_017.phptnu�[���PK"j�\�x2���:tests/igbinary_046c.phptnu�[���PK"j�\"}���`=tests/igbinary_088.phptnu�[���PK"j�\\V����Atests/igbinary_075.phptnu�[���PK"j�\�q�����Etests/igbinary_062.phptnu�[���PK#j�\Ծ��
�
�Jtests/__serialize_016.phptnu�[���PK#j�\�;��KK�Xtests/igbinary_080.phptnu�[���PK#j�\�,y�\[tests/igbinary_050.phptnu�[���PK#j�\SH���_tests/igbinary_064.phptnu�[���PK$j�\_���htests/__serialize_010.phptnu�[���PK$j�\
-$AA(otests/typed_property_ref_overwrite2.phptnu�[���PK$j�\�؏7���rtests/igbinary_049b.phptnu�[���PK%j�\�0�"���xtests/igbinary_029.phptnu�[���PK%j�\C �H	H	$�ztests/typed_property_refs_php74.phptnu�[���PK%j�\�Ɗ�

G�tests/igbinary_079.phptnu�[���PK&j�\l�oҺ���tests/igbinary_026b.phptnu�[���PK&j�\}�xu4	4	��tests/__serialize_018.phptnu�[���PK&j�\��:MM�tests/igbinary_015.phptnu�[���PK&j�\wZ���!��tests/igbinary_enums_3_php83.phptnu�[���PK'j�\�]4ss��tests/igbinary_034.phptnu�[���PK'j�\�s�����tests/igbinary_009.phptnu�[���PK'j�\�&L�KK¦tests/igbinary_091.phptnu�[���PK(j�\�*ffT�tests/igbinary_021.phptnu�[���PK(j�\��̝��tests/igbinary_055.phptnu�[���PK)j�\������tests/__serialize_006.phptnu�[���PK)j�\�2����tests/igbinary_002.phptnu�[���PK)j�\ŋ9�%%�tests/igbinary_bug54662.phptnu�[���PK*j�\nX����tests/igbinary_072.phptnu�[���PK*j�\0�Q����tests/igbinary_010.phptnu�[���PK+j�\����33��tests/igbinary_041.phptnu�[���PK+j�\N�.�{{H�tests/igbinary_032.phptnu�[���PK+j�\^�-X��
�tests/igbinary_052.phptnu�[���PK,j�\�H�4	4	��tests/typed_property_refs.phptnu�[���PK,j�\������tests/igbinary_094.phptnu�[���PK,j�\j3����d�tests/igbinary_023.phptnu�[���PK-j�\�<h�OO��tests/igbinary_078.phptnu�[���PK-j�\2�'(�tests/typed_property_ref_overwrite.phptnu�[���PK-j�\������tests/igbinary_086.phptnu�[���PK.j�\!��k���tests/igbinary_089.phptnu�[���PK.j�\�M�-�
�
��tests/__serialize_011.phptnu�[���PK/j�\NW�U	U	�tests/igbinary_077.phptnu�[���PK/j�\�{Di��itests/igbinary_009b_php8.phptnu�[���PK/j�\�[�����tests/igbinary_025b.phptnu�[���PK0j�\�ƀ�vv}tests/igbinary_006.phptnu�[���PK0j�\#eU���#:#tests/sleep_mangled_name_clash.phptnu�[���PK0j�\�~�ʘ�{%tests/igbinary_093.phptnu�[���PK0j�\X�瀳�Z(tests/igbinary_030_php72.phptnu�[���PK1j�\d}���Z-tests/igbinary_022.phptnu�[���PK1j�\���5tests/__serialize_021.phptnu�[���PK1j�\�'����9tests/__serialize_022.phptnu�[���PK2j�\~
x�%%+>tests/igbinary_047.phptnu�[���PK2j�\AfFF�Ftests/__serialize_005.phptnu�[���PK3j�\HbQմ�'Mtests/__serialize_014_php8.phptnu�[���PK3j�\���A�A*Stests/__serialize_020.phptnu�[���PK3j�\s���)�tests/igbinary_014.phptnu�[���PK4j�\�vTT�tests/igbinary_026b_php8.phptnu�[���PK4j�\�խ����tests/igbinary_073.phptnu�[���PK4j�\�b@�yy��tests/igbinary_066.phptnu�[���PK5j�\��'�\�tests/igbinary_012.phptnu�[���PK5j�\�u��	�	��tests/__serialize_015.phptnu�[���PK5j�\����ȸtests/igbinary_082.phptnu�[���PK6j�\��0Y���tests/igbinary_enums_3.phptnu�[���PK6j�\�u���1�tests/igbinary_046d.phptnu�[���PK6j�\�͹���_�tests/igbinary_098.phptnu�[���PK7j�\�\����0b�tests/typed_property_ref_assignment_failure.phptnu�[���PK7j�\e�4CC��tests/igbinary_082_php74.phptnu�[���PK7j�\��q��/�tests/igbinary_022_php82.phptnu�[���PK7j�\OT����1�tests/igbinary_024.phptnu�[���PK8j�\�L}ϥ�3]�tests/php82_suppress_dynamic_properties_warning.incnu�[���PK8j�\ݿY��e�tests/igbinary_059.phptnu�[���PK8j�\E��"����tests/igbinary_057.phptnu�[���PK9j�\��=((��tests/igbinary_045b.phptnu�[���PK9j�\��@���?�tests/__serialize_002.phptnu�[���PK9j�\�tccg�tests/igbinary_015b.phptnu�[���PK:j�\�$���tests/igbinary_048b.phptnu�[���PK:j�\��+22p�tests/igbinary_085.phptnu�[���PK:j�\M����tests/igbinary_025.phptnu�[���PK;j�\����5tests/igbinary_083.phptnu�[���PK;j�\��S���'tests/igbinary_046b.phptnu�[���PK;j�\�q��0tests/igbinary_016.phptnu�[���PK;j�\���99,tests/igbinary_097.phptnu�[���PK<j�\c#�ѐ��tests/igbinary_044.phptnu�[���PK<j�\��3G���*tests/igbinary_030_php7.phptnu�[���PK<j�\Kl\�WW~/tests/igbinary_004.phptnu�[���PK=j�\I�~w��4tests/igbinary_063_php72.phptnu�[���PK=j�\�3^�	�	'9tests/igbinary_071.phptnu�[���PK=j�\�O,�!Ctests/igbinary_065.phptnu�[���PK@j�\Pl�HH�Itests/igbinary_018.phptnu�[���PK@j�\uu�)Otests/igbinary_013.phptnu�[���PK@j�\6E��00ZStests/igbinary_074.phptnu�[���PKAj�\ؖy����Wtests/igbinary_046.phptnu�[���PKAj�\G1��

�Ytests/igbinary_026.phptnu�[���PKAj�\�a�99K_tests/__serialize_008.phptnu�[���PKAj�\�g�S1
1
�etests/igbinary_009b.phptnu�[���PKBj�\��MMGptests/__serialize_019.phptnu�[���PK���3�u