├── .gitignore ├── .travis.yml ├── COPYING ├── CREDITS ├── ChangeLog ├── EXPERIMENTAL ├── Makefile.bench ├── NEWS ├── README.md ├── apc_serializer.h ├── benchmark ├── .gitignore ├── bench.php ├── l10n-en.ser ├── run-bench.php ├── serialize-objectarray.b.php ├── serialize-scalar-int.b.php ├── serialize-scalararray.b.php ├── serialize-stringarray.b.php ├── unserialize-objectarray.b.php ├── unserialize-scalar-int.b.php ├── unserialize-scalararray.b.php └── unserialize-stringarray.b.php ├── config.m4 ├── config.w32 ├── hash.h ├── hash_si.c ├── ig_win32.h ├── igbinary.c ├── igbinary.h ├── igbinary.php ├── igbinary.php.ini ├── igbinary.spec ├── package.xml ├── php_igbinary.h ├── tags.sh └── tests ├── igbinary_001.phpt ├── igbinary_002.phpt ├── igbinary_003.phpt ├── igbinary_004.phpt ├── igbinary_005.phpt ├── igbinary_006.phpt ├── igbinary_007.phpt ├── igbinary_008.phpt ├── igbinary_009.phpt ├── igbinary_010.phpt ├── igbinary_012.phpt ├── igbinary_013.phpt ├── igbinary_014.phpt ├── igbinary_015.phpt ├── igbinary_015b.phpt ├── igbinary_016.phpt ├── igbinary_017.phpt ├── igbinary_018.phpt ├── igbinary_019.phpt ├── igbinary_020.phpt ├── igbinary_021.phpt ├── igbinary_022.phpt ├── igbinary_023.phpt ├── igbinary_024.phpt ├── igbinary_025.phpt ├── igbinary_026.phpt ├── igbinary_026b.phpt ├── igbinary_027.phpt ├── igbinary_028.phpt ├── igbinary_029.phpt ├── igbinary_030.phpt ├── igbinary_031.phpt ├── igbinary_032.phpt ├── igbinary_033.phpt ├── igbinary_034.phpt ├── igbinary_040.phpt ├── igbinary_041.phpt ├── igbinary_042.phpt ├── igbinary_043.phpt ├── igbinary_044.phpt ├── igbinary_045.phpt ├── igbinary_045b.phpt ├── igbinary_046.phpt ├── igbinary_047.phpt ├── igbinary_bug54662.phpt └── igbinary_unserialize_v1_compatible.phpt /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.lo 3 | *.la 4 | .deps 5 | .libs 6 | Makefile 7 | Makefile.fragments 8 | Makefile.global 9 | Makefile.objects 10 | acinclude.m4 11 | aclocal.m4 12 | autom4te.cache 13 | build 14 | config.cache 15 | config.guess 16 | config.h 17 | config.h.in 18 | config.log 19 | config.nice 20 | config.status 21 | config.sub 22 | configure 23 | configure.in 24 | conftest 25 | conftest.c 26 | include 27 | install-sh 28 | libtool 29 | ltmain.sh 30 | missing 31 | mkinstalldirs 32 | modules 33 | scan_makefile_in.awk 34 | *.dsw 35 | *.plg 36 | *.opt 37 | *.ncb 38 | Release 39 | Release_inline 40 | Debug 41 | Release_TS 42 | Release_TSDbg 43 | Release_TS_inline 44 | Debug_TS 45 | run-tests.php 46 | cscope.out 47 | tests/*.out 48 | tests/*.php 49 | tests/*.mem 50 | tests/*.diff 51 | tests/*.log 52 | tests/*.exp 53 | tests/*.sh 54 | tmp-php.ini 55 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | php: 3 | - 5.6 4 | - 5.5 5 | - 5.4 6 | - 5.3 7 | - 5.2 8 | 9 | env: 10 | - CC=clang CFLAGS="" 11 | - CC=clang CFLAGS="-g -O0" 12 | - CC=gcc-4.6 CFLAGS="" 13 | - CC=gcc-4.6 CFLAGS="-g -O0 -fstack-protector -fstack-protector-all" 14 | - CC=gcc-4.6 CFLAGS="-g" VALGRIND=1 15 | 16 | install: 17 | - if [ "$VALGRIND" -eq 1 ]; then sudo apt-get install valgrind; export TEST_PHP_ARGS="-m"; fi 18 | - sudo apt-get install $CC 19 | - $CC --version 20 | 21 | script: 22 | - phpize 23 | - ./configure --enable-igbinary 24 | # Fix not failing makes in php 5.2 and 5.3 25 | - perl -i -pe 's/\-\@if/\@if/' Makefile 26 | - make 27 | - REPORT_EXIT_STATUS=1 NO_INTERACTION=1 make test 28 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008 Sulake Dynamoid Oy, 2008-2014 Oleg Grenrus, Teddy Grenman, 2 | igbinary contributors 3 | 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | - Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | - Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | - Neither the name of the 'igbinary' nor the names of its contributors may 17 | be used to endorse or promote products derived from this software without 18 | specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 | THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | igbinary is written for IRC-Galleria by Sulake Dynamoid Oy and its employees. 2 | 3 | Author 4 | * Oleg Grenrus 5 | 6 | Contributors 7 | * Teddy Grenman (fixes, tests, docs) 8 | * Kari Lavikka (docs) 9 | * Pierre Joye (Windows support) 10 | * Mikko Koppanen (PECL and RPM spec files) 11 | 12 | Other 13 | * Original hash functions - Bob Jenkins 14 | 15 | --- 16 | 17 | http://irc-galleria.net/ - a finnish social networking site 18 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 2008-06-29 Oleg Grenrus 2 | * config.m4: fixed CFLAGS 3 | * igbinary.c: do not init object & string hashes if serializing scalars. 4 | unserialize_callback_func support. 5 | igbinary_serialize and igbinary_unserialize for the external use. 6 | * intbinary.h: header for external use 7 | * tests/022.phpt: unserialize_callback_func test 8 | * tests/023.phpt: resource serializes to null test 9 | * tests/002.phpt tests/003.phpt tests/004.phpt tests/005.phpt tests/006.phpt: == -> === 10 | * tests/015b.phpt: pointed out http://bugs.net/bug.php?id=45406 11 | -------------------------------------------------------------------------------- /EXPERIMENTAL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phadej/igbinary/a0316ffc8bab7e628c3679dac0ec6b78ded52f12/EXPERIMENTAL -------------------------------------------------------------------------------- /Makefile.bench: -------------------------------------------------------------------------------- 1 | benchmark: all 2 | -@if test ! -z "$(PHP_EXECUTABLE)" && test -x "$(PHP_EXECUTABLE)"; then \ 3 | cd benchmark; \ 4 | BENCH_PHP_EXECUTABLE="$(PHP_EXECUTABLE)" \ 5 | BENCH_PHP_ARGS="-n -d extension_dir=$(top_builddir)/modules/ $(PHP_TEST_SHARED_EXTENSIONS)" \ 6 | $(PHP_EXECUTABLE) -n ./run-bench.php; \ 7 | else \ 8 | echo "ERROR: Cannot run tests without CLI sapi."; \ 9 | fi 10 | 11 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | 1.2.2 xxxx-xx-xx 2 | ======== 3 | * TBD 4 | 5 | 1.2.1 2014-08-29 6 | ======== 7 | * Compatible with PHP 5.2 - 5.6 8 | 9 | 1.2.0 2014-08-28 10 | ======== 11 | * PECL bug #22614, igbinary_unserialize(FALSE) must return FALSE 12 | * PHP bug #54662, unserializing nested objects cause crash 13 | * Other fixes 14 | 15 | 1.1.1 2011-01-17 16 | ======== 17 | * Critical crash fix. Thanks to Ilia Alshanetsky for spotting and fixing. 18 | 19 | 1.1.0 2011-01-17 20 | ======== 21 | * New ini setting to disable duplicate string compacting 22 | * APC serializer registration (APC 3.1.7 beta) 23 | * Windows support (PHP 5.3) 24 | * Updated serialized binary format (1.1 reads 1.0.x format) 25 | * Minor performance improvements 26 | * Bug fixes 27 | * New source repository at https://github.com/igbinary/igbinary 28 | 29 | 1.0.2 30 | ======== 31 | * Bug fix release 32 | 33 | 1.0.1 2008-07-05 34 | ======== 35 | * unserialize_callback_func support 36 | * slight speedup when serializing scalars 37 | 38 | 1.0.0 2008-06-25 39 | ======== 40 | * Public version 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | igbinary 2 | ======== 3 | 4 | [![Build Status](https://travis-ci.org/igbinary/igbinary.svg?branch=master)](https://travis-ci.org/igbinary/igbinary) 5 | 6 | Igbinary is a drop in replacement for the standard php serializer. Instead of 7 | time and space consuming textual representation, igbinary stores php data 8 | structures in compact binary form. Savings are significant when using 9 | memcached or similar memory based storages for serialized data. About 50% 10 | reduction in storage requirement can be expected. Specific number depends on 11 | your data. 12 | 13 | Unserialization performance is at least on par with the standard PHP serializer. 14 | Serialization performance depends on the "compact_strings" option which enables 15 | duplicate string tracking. String are inserted to a hash table which adds some 16 | overhead. In usual scenarios this does not have much significance since usage 17 | pattern is "serialize rarely, unserialize often". With "compact_strings" 18 | option igbinary is usually a bit slower than the standard serializer. Without 19 | it, a bit faster. 20 | 21 | Features 22 | -------- 23 | 24 | - Supports same data types as the standard PHP serializer: null, bool, int, 25 | float, string, array and objects. 26 | - `__autoload` & `unserialize_callback_func` 27 | - `__sleep` & `__wakeup` 28 | - Serializable -interface 29 | - Data portability between platforms (32/64bit, endianess) 30 | - Tested on Linux amd64, Linux ARM, Mac OSX x86, HP-UX PA-RISC and NetBSD sparc64 31 | - Hooks up to APC opcode cache as a serialization handler (APC 3.1.7+) 32 | - Compatible with PHP 5.2 – 5.6 33 | 34 | Implementation details 35 | ---------------------- 36 | 37 | Storing complex PHP data structures like arrays of associative arrays 38 | with the standard PHP serializer is not very space efficient. The main 39 | reasons in order of significance are (at least in our applications): 40 | 41 | 1. Array keys are repeated redundantly. 42 | 2. Numerical values are plain text. 43 | 3. Human readability adds some overhead. 44 | 45 | Igbinary uses two specific strategies to minimize the size of the serialized 46 | output. 47 | 48 | 1. Repetitive strings are stored only once. Collections of objects benefit 49 | significantly from this. See "compact_strings" option. 50 | 51 | 2. Numerical values are stored in the smallest primitive data type 52 | available: 53 | *123* = `int8_t`, 54 | *1234* = `int16_t`, 55 | *123456* = `int32_t` 56 | ... and so on. 57 | 58 | 3. ( Well, it is not human readable ;) 59 | 60 | How to use 61 | ---------- 62 | 63 | Add the following lines to your php.ini: 64 | 65 | ; Load igbinary extension 66 | extension=igbinary.so 67 | 68 | ; Use igbinary as session serializer 69 | session.serialize_handler=igbinary 70 | 71 | ; Enable or disable compacting of duplicate strings 72 | ; The default is On. 73 | igbinary.compact_strings=On 74 | 75 | ; Use igbinary as serializer in APC cache (3.1.7 or later) 76 | ;apc.serializer=igbinary 77 | 78 | .. and in your php code replace serialize and unserialize function calls 79 | with `igbinary_serialize` and `igbinary_unserialize`. 80 | 81 | Installing 82 | ---------- 83 | 84 | Note: 85 | Sometimes phpize must be substituted with phpize5. In such cases the following 86 | option must be given to configure script: "--with-php-config=.../php-config5" 87 | 88 | 1. `phpize` 89 | 2. `./configure: 90 | - With GCC: `./configure CFLAGS="-O2 -g" --enable-igbinary` 91 | - With ICC (Intel C Compiler) `./configure CFLAGS=" -no-prec-div -O3 -xO -unroll2 -g" CC=icc --enable-igbinary` 92 | - With clang: `./configure CC=clang CFLAGS="-O0 -g" --enable-igbinary` 93 | 3. `make` 94 | 4. `make test` 95 | 5. `make install` 96 | 6. igbinary.so is installed to the default extension directory 97 | 98 | ### To run APCu test 99 | 100 | ``` 101 | # go to modules directory 102 | cd modules 103 | 104 | # ... and create symlink to apcu extension 105 | # it will be loaded during test suite 106 | /opt/lib/php/extensions/no-debug-non-zts-20121212/apcu.so 107 | ``` 108 | 109 | Similar approach should work for APC. 110 | 111 | Bugs & Contributions 112 | -------------------- 113 | 114 | Mailing list for bug reports and other development discussion can be found 115 | at http://groups.google.com/group/igbinary 116 | 117 | Fill bug reports at 118 | https://github.com/igbinary/igbinary/issues 119 | 120 | The preferred ways for contributions are pull requests and email patches 121 | (in git format). Feel free to fork at http://github.com/igbinary/igbinary 122 | 123 | Utilizing in other extensions 124 | ----------------------------- 125 | 126 | Igbinary can be called from other extensions fairly easily. Igbinary installs 127 | its header file to _ext/igbinary/igbinary.h_. There are just two straighforward 128 | functions: `igbinary_serialize` and `igbinary_unserialize`. Look at _igbinary.h_ for 129 | prototypes and usage. 130 | 131 | Add `PHP_ADD_EXTENSION_DEP(yourextension, igbinary)` to your _config.m4_ in case 132 | someone wants to compile both of them statically into php. 133 | 134 | Trivia 135 | ------ 136 | 137 | Where does the name "igbinary" come from? There was once a similar project 138 | called fbinary but it has disappeared from the Internet a long time ago. Its 139 | architecture wasn't particularly clean either. IG is an abbreviation for a 140 | finnish social networking site IRC-Galleria (http://irc-galleria.net/) 141 | 142 | 143 | -------------------------------------------------------------------------------- /apc_serializer.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | APC | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2006-2011 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Gopal Vijayaraghavan | 16 | +----------------------------------------------------------------------+ 17 | 18 | */ 19 | 20 | /* $Id: $ */ 21 | 22 | #ifndef APC_SERIALIZER_H 23 | #define APC_SERIALIZER_H 24 | 25 | /* this is a shipped .h file, do not include any other header in this file */ 26 | #define APC_SERIALIZER_NAME(module) module##_apc_serializer 27 | #define APC_UNSERIALIZER_NAME(module) module##_apc_unserializer 28 | 29 | #define APC_SERIALIZER_ARGS unsigned char **buf, size_t *buf_len, const zval *value, void *config TSRMLS_DC 30 | #define APC_UNSERIALIZER_ARGS zval **value, unsigned char *buf, size_t buf_len, void *config TSRMLS_DC 31 | 32 | typedef int (*apc_serialize_t)(APC_SERIALIZER_ARGS); 33 | typedef int (*apc_unserialize_t)(APC_UNSERIALIZER_ARGS); 34 | 35 | typedef int (*apc_register_serializer_t)(const char* name, 36 | apc_serialize_t serialize, 37 | apc_unserialize_t unserialize, 38 | void *config TSRMLS_DC); 39 | 40 | /* 41 | * ABI version for constant hooks. Increment this any time you make any changes 42 | * to any function in this file. 43 | */ 44 | #define APC_SERIALIZER_ABI "0" 45 | #define APC_SERIALIZER_CONSTANT "\000apc_register_serializer-" APC_SERIALIZER_ABI 46 | 47 | #if !defined(APC_UNUSED) 48 | # if defined(__GNUC__) 49 | # define APC_UNUSED __attribute__((unused)) 50 | # else 51 | # define APC_UNUSED 52 | # endif 53 | #endif 54 | 55 | static APC_UNUSED int apc_register_serializer(const char* name, 56 | apc_serialize_t serialize, 57 | apc_unserialize_t unserialize, 58 | void *config TSRMLS_DC) 59 | { 60 | zval *apc_magic_constant = NULL; 61 | (void)config; 62 | 63 | ALLOC_INIT_ZVAL(apc_magic_constant); 64 | 65 | if (zend_get_constant(APC_SERIALIZER_CONSTANT, sizeof(APC_SERIALIZER_CONSTANT)-1, apc_magic_constant TSRMLS_CC)) { 66 | if(apc_magic_constant) { 67 | apc_register_serializer_t register_func = (apc_register_serializer_t)(Z_LVAL_P(apc_magic_constant)); 68 | if(register_func) { 69 | zval_dtor(apc_magic_constant); 70 | return register_func(name, serialize, unserialize, NULL TSRMLS_CC); 71 | } 72 | } 73 | } 74 | 75 | zval_dtor(apc_magic_constant); 76 | 77 | return 0; 78 | } 79 | 80 | #endif 81 | 82 | /* 83 | * Local variables: 84 | * tab-width: 4 85 | * c-basic-offset: 4 86 | * End: 87 | * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker 88 | * vim<600: expandtab sw=4 ts=4 sts=4 89 | */ 90 | -------------------------------------------------------------------------------- /benchmark/.gitignore: -------------------------------------------------------------------------------- 1 | *.txt 2 | -------------------------------------------------------------------------------- /benchmark/bench.php: -------------------------------------------------------------------------------- 1 | name = $name; 19 | } 20 | 21 | private function getResourceUsage() { 22 | $rusage = getrusage(); 23 | $time = $rusage['ru_utime.tv_sec'] * 1000000 + $rusage['ru_utime.tv_usec']; 24 | $time += $rusage['ru_stime.tv_sec'] * 1000000 + $rusage['ru_stime.tv_usec']; 25 | 26 | return $time; 27 | } 28 | 29 | public function start() { 30 | if ($this->started) { 31 | throw new RuntimeException("Already started."); 32 | } 33 | $this->startTime = microtime(true); 34 | $this->stopTime = $this->startTime; 35 | 36 | $rusage = getrusage(); 37 | 38 | $this->startUsage = $this->getResourceUsage(); 39 | $this->stopUsage = $this->startUsage; 40 | $this->started = true; 41 | } 42 | 43 | public function stop($i = 1) { 44 | if (!$this->started) { 45 | throw new RuntimeException("Not started."); 46 | } 47 | 48 | $this->stopTime = microtime(true); 49 | $this->stopUsage = $this->getResourceUsage(); 50 | 51 | $this->iterations = (int)$i; 52 | $this->started = false; 53 | } 54 | 55 | public function writeHeader() { 56 | $header = implode("\t", array( 57 | 'name', 'start time', 'iterations', 'duration', 'rusage', 58 | )); 59 | echo $header, "\n"; 60 | $this->headerWritten = true; 61 | } 62 | 63 | public function write() { 64 | if ($this->started) { 65 | $this->stop(); 66 | } 67 | 68 | if (!$this->headerWritten) { 69 | $this->writeHeader(); 70 | } 71 | 72 | printf("%s\t%.6f\t%d\t%.8f\t%.6f\n", 73 | $this->name, 74 | $this->startTime, 75 | $this->iterations, 76 | $this->stopTime - $this->startTime, 77 | $this->stopUsage - $this->startUsage); 78 | } 79 | } 80 | 81 | 82 | -------------------------------------------------------------------------------- /benchmark/run-bench.php: -------------------------------------------------------------------------------- 1 | getBasename(); 13 | $name = $fileInfo->getBasename('.b.php'); 14 | 15 | if (!preg_match('/\.b\.php$/', $fn)) { 16 | continue; 17 | } 18 | 19 | $file = $fileInfo->openFile(); 20 | $file->setFlags(SplFileObject::DROP_NEW_LINE | SplFileObject::SKIP_EMPTY); 21 | 22 | $desc = $fn; 23 | foreach ($file as $line) { 24 | if (preg_match('/Description:\s*(.*)/', $line, $m)) { 25 | $desc = trim($m[1]); 26 | } 27 | } 28 | 29 | fwrite($stderr, str_pad($desc, 50, '.')); 30 | $start = microtime(true); 31 | 32 | $php = getenv('BENCH_PHP_EXECUTABLE'); 33 | if ($php === false) { 34 | $php = 'php'; 35 | } 36 | 37 | $args = getenv('BENCH_PHP_ARGS'); 38 | if ($args === false) { 39 | $args = ''; 40 | } 41 | 42 | $output = shell_exec($php . ' ' . $args . ' ' . $fileInfo->getFilename()); 43 | 44 | $stop = microtime(true); 45 | fprintf($stderr, "DONE %.2fs\n", $stop - $start); 46 | 47 | file_put_contents($benchBaseName . '-' . $name . '.txt', $output); 48 | } 49 | -------------------------------------------------------------------------------- /benchmark/serialize-objectarray.b.php: -------------------------------------------------------------------------------- 1 | i = $i; 19 | 20 | $array[] = $o; 21 | } 22 | 23 | for ($i = 0; $i < 40; $i++) { 24 | $b->start(); 25 | for ($j = 0; $j < 2000; $j++) { 26 | $ser = igbinary_serialize($array); 27 | } 28 | $b->stop($j); 29 | $b->write(); 30 | } 31 | -------------------------------------------------------------------------------- /benchmark/serialize-scalar-int.b.php: -------------------------------------------------------------------------------- 1 | start(); 13 | for ($j = 0; $j < 3500000; $j++) { 14 | $ser = igbinary_serialize($var); 15 | } 16 | $b->stop($j); 17 | $b->write(); 18 | } 19 | -------------------------------------------------------------------------------- /benchmark/serialize-scalararray.b.php: -------------------------------------------------------------------------------- 1 | start(); 29 | for ($j = 0; $j < 12000; $j++) { 30 | $ser = igbinary_serialize($array); 31 | } 32 | $b->stop($j); 33 | $b->write(); 34 | } 35 | -------------------------------------------------------------------------------- /benchmark/serialize-stringarray.b.php: -------------------------------------------------------------------------------- 1 | start(); 13 | for ($j = 0; $j < 360; $j++) { 14 | $ser = igbinary_serialize($array); 15 | } 16 | $b->stop($j); 17 | $b->write(); 18 | } 19 | -------------------------------------------------------------------------------- /benchmark/unserialize-objectarray.b.php: -------------------------------------------------------------------------------- 1 | i = $i; 19 | 20 | $array[] = $o; 21 | } 22 | $ser = igbinary_serialize($array); 23 | 24 | for ($i = 0; $i < 40; $i++) { 25 | $b->start(); 26 | for ($j = 0; $j < 540; $j++) { 27 | $array = igbinary_unserialize($ser); 28 | } 29 | $b->stop($j); 30 | $b->write(); 31 | } 32 | -------------------------------------------------------------------------------- /benchmark/unserialize-scalar-int.b.php: -------------------------------------------------------------------------------- 1 | start(); 13 | for ($j = 0; $j < 3600000; $j++) { 14 | $var = igbinary_unserialize($ser); 15 | } 16 | $b->stop($j); 17 | $b->write(); 18 | } 19 | -------------------------------------------------------------------------------- /benchmark/unserialize-scalararray.b.php: -------------------------------------------------------------------------------- 1 | start(); 30 | for ($j = 0; $j < 5800; $j++) { 31 | $array = igbinary_unserialize($ser); 32 | } 33 | $b->stop($j); 34 | $b->write(); 35 | } 36 | -------------------------------------------------------------------------------- /benchmark/unserialize-stringarray.b.php: -------------------------------------------------------------------------------- 1 | start(); 13 | for ($j = 0; $j < 500; $j++) { 14 | $array = igbinary_unserialize($ser); 15 | } 16 | $b->stop($j); 17 | $b->write(); 18 | } 19 | -------------------------------------------------------------------------------- /config.m4: -------------------------------------------------------------------------------- 1 | dnl config.m4 for extension igbinary 2 | 3 | dnl Comments in this file start with the string 'dnl'. 4 | dnl Remove where necessary. This file will not work 5 | dnl without editing. 6 | 7 | dnl If your extension references something external, use with: 8 | 9 | dnl PHP_ARG_WITH(igbinary, for igbinary support, 10 | dnl Make sure that the comment is aligned: 11 | dnl [ --with-igbinary Include igbinary support]) 12 | 13 | dnl Otherwise use enable: 14 | 15 | PHP_ARG_ENABLE(igbinary, whether to enable igbinary support, 16 | [ --enable-igbinary Enable igbinary support]) 17 | 18 | if test "$PHP_IGBINARY" != "no"; then 19 | AC_CHECK_HEADERS([stdbool.h],, AC_MSG_ERROR([stdbool.h not exists])) 20 | AC_CHECK_HEADERS([stddef.h],, AC_MSG_ERROR([stddef.h not exists])) 21 | AC_CHECK_HEADERS([stdint.h],, AC_MSG_ERROR([stdint.h not exists])) 22 | 23 | AC_MSG_CHECKING([for APC/APCU includes]) 24 | if test -f "$phpincludedir/ext/apcu/apc_serializer.h"; then 25 | apc_inc_path="$phpincludedir" 26 | AC_MSG_RESULT([APCU in $apc_inc_path]) 27 | AC_DEFINE(HAVE_APCU_SUPPORT,1,[Whether to enable apcu support]) 28 | elif test -f "$phpincludedir/ext/apc/apc_serializer.h"; then 29 | apc_inc_path="$phpincludedir" 30 | AC_MSG_RESULT([APC in $apc_inc_path]) 31 | AC_DEFINE(HAVE_APC_SUPPORT,1,[Whether to enable apc support]) 32 | elif test -f "${srcdir}/apc_serializer.h"; then 33 | AC_MSG_RESULT([apc_serializer.h bundled]) 34 | AC_DEFINE(HAVE_APC_SUPPORT,1,[Whether to enable apc support]) 35 | AC_DEFINE(USE_BUNDLED_APC,1,[Whether to use bundled apc includes]) 36 | else 37 | AC_MSG_RESULT([not found]) 38 | fi 39 | 40 | AC_CHECK_SIZEOF([long]) 41 | 42 | dnl GCC 43 | AC_MSG_CHECKING(compiler type) 44 | if test ! -z "`$CC --version | grep -i GCC`"; then 45 | AC_MSG_RESULT(gcc) 46 | if test -z "`echo $CFLAGS | grep -- -O0`"; then 47 | PHP_IGBINARY_CFLAGS="-Wall -Wpointer-arith -Wmissing-prototypes -Wstrict-prototypes -Wcast-align -Wshadow -Wwrite-strings -Wswitch -Winline -finline-limit=10000 --param large-function-growth=10000 --param inline-unit-growth=10000" 48 | fi 49 | elif test ! -z "`$CC --version | grep -i ICC`"; then 50 | AC_MSG_RESULT(icc) 51 | if test -z "`echo $CFLAGS | grep -- -O0`"; then 52 | PHP_IGBINARY_CFLAGS="-no-prec-div -O3 -x0 -unroll2" 53 | fi 54 | elif test ! -z "`$CC --version | grep -i CLANG`"; then 55 | AC_MSG_RESULT(clang) 56 | if test -z "`echo $CFLAGS | grep -- -O0`"; then 57 | PHP_IGBINARY_CFLAGS="-Wall -O2" 58 | fi 59 | else 60 | AC_MSG_RESULT(other) 61 | fi 62 | 63 | PHP_ADD_MAKEFILE_FRAGMENT(Makefile.bench) 64 | PHP_INSTALL_HEADERS([ext/igbinary], [igbinary.h]) 65 | PHP_NEW_EXTENSION(igbinary, igbinary.c hash_si.c, $ext_shared,, $PHP_IGBINARY_CFLAGS) 66 | PHP_ADD_EXTENSION_DEP(igbinary, session, true) 67 | PHP_SUBST(IGBINARY_SHARED_LIBADD) 68 | fi 69 | -------------------------------------------------------------------------------- /config.w32: -------------------------------------------------------------------------------- 1 | // $Id$ 2 | // vim:ft=javascript 3 | 4 | ARG_ENABLE("igbinary", "whether to enable igbinary support", "no"); 5 | 6 | if (PHP_IGBINARY == "yes") { 7 | res = CHECK_HEADER_ADD_INCLUDE("apc_serializer.h", "CFLAGS_IGBINARY", "..\\pecl\\apc;ext\\apc"); 8 | if (res) { 9 | AC_DEFINE('HAVE_APC_SUPPORT', 1, 'Whether to enable apc support') 10 | } 11 | EXTENSION("igbinary", "igbinary.c hash_si.c"); 12 | AC_DEFINE('HAVE_IGBINARY', 1, 'Have igbinary support', false); 13 | ADD_EXTENSION_DEP('igbinary', 'session'); 14 | } 15 | -------------------------------------------------------------------------------- /hash.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | See COPYING file for further copyright information | 4 | +----------------------------------------------------------------------+ 5 | | Author: Oleg Grenrus | 6 | | See CREDITS for contributors | 7 | +----------------------------------------------------------------------+ 8 | */ 9 | 10 | #ifndef HASH_H 11 | #define HASH_H 12 | 13 | #include 14 | 15 | #ifdef PHP_WIN32 16 | # include "ig_win32.h" 17 | #else 18 | # include /* defines uint32_t etc */ 19 | #endif 20 | 21 | #include 22 | 23 | /** Key/value pair of hash_si. 24 | * @author Oleg Grenrus 25 | * @see hash_si 26 | */ 27 | struct hash_si_pair 28 | { 29 | char *key; /**< Pointer to key. */ 30 | size_t key_len; /**< Key length. */ 31 | uint32_t value; /**< Value. */ 32 | }; 33 | 34 | /** Hash-array. 35 | * Like c++ map. 36 | * Current implementation uses linear probing. 37 | * @author Oleg Grenrus 38 | */ 39 | struct hash_si { 40 | size_t size; /**< Allocated size of array. */ 41 | size_t used; /**< Used size of array. */ 42 | struct hash_si_pair *data; /**< Pointer to array or pairs of data. */ 43 | }; 44 | 45 | /** Inits hash_si structure. 46 | * @param h pointer to hash_si struct. 47 | * @param size initial size of the hash array. 48 | * @return 0 on success, 1 else. 49 | */ 50 | int hash_si_init (struct hash_si *h, size_t size); 51 | 52 | /** Frees hash_si structure. 53 | * Doesn't call free(h). 54 | * @param h pointer to hash_si struct. 55 | */ 56 | void hash_si_deinit (struct hash_si *h); 57 | 58 | /** Inserts value into hash_si. 59 | * @param h Pointer to hash_si struct. 60 | * @param key Pointer to key. 61 | * @param key_len Key length. 62 | * @param value Value. 63 | * @return 0 on success, 1 or 2 else. 64 | */ 65 | int hash_si_insert (struct hash_si *h, const char *key, size_t key_len, uint32_t value); 66 | 67 | /** Finds value from hash_si. 68 | * Value returned thru value param. 69 | * @param h Pointer to hash_si struct. 70 | * @param key Pointer to key. 71 | * @param key_len Key length. 72 | * @param[out] value Found value. 73 | * @return 0 if found, 1 if not. 74 | */ 75 | int hash_si_find (struct hash_si *h, const char *key, size_t key_len, uint32_t * value); 76 | 77 | /** Remove value from hash_si. 78 | * Removed value is available thru value param. 79 | * @param h Pointer to hash_si struct. 80 | * @param key Pointer to key. 81 | * @param key_len Key length. 82 | * @param[out] value Removed value. 83 | * @return 0 ivalue removed, 1 if not existed. 84 | */ 85 | int hash_si_remove (struct hash_si *h, const char *key, size_t key_len, uint32_t * value); 86 | 87 | /** Travarses hash_si. 88 | * Calls traverse_function on every item. Traverse function should not modify hash 89 | * @param h Pointer to hash_si struct. 90 | * @param traverse_function Function to call on every item of hash_si. 91 | */ 92 | void hash_si_traverse (struct hash_si *h, int (*traverse_function) (const char *key, size_t key_len, uint32_t value)); 93 | 94 | /** Returns size of hash_si. 95 | * @param h Pointer to hash_si struct. 96 | * @return Size of hash_si. 97 | */ 98 | size_t hash_si_size (struct hash_si *h); 99 | 100 | /** Returns capacity of hash_si. 101 | * @param h Pointer to hash_si struct. 102 | * @return Capacity of hash_si. 103 | */ 104 | size_t hash_si_capacity (struct hash_si *h); 105 | 106 | #endif /* HASH_H */ 107 | -------------------------------------------------------------------------------- /hash_si.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | See COPYING file for further copyright information | 4 | +----------------------------------------------------------------------+ 5 | | Author: Oleg Grenrus | 6 | | See CREDITS for contributors | 7 | +----------------------------------------------------------------------+ 8 | */ 9 | 10 | #ifdef PHP_WIN32 11 | # include "ig_win32.h" 12 | #endif 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | #include "hash.h" 21 | #include "zend.h" 22 | 23 | /* {{{ nextpow2 */ 24 | /** Next power of 2. 25 | * @param n Integer. 26 | * @return next to n power of 2 . 27 | */ 28 | inline static uint32_t nextpow2(uint32_t n) { 29 | uint32_t m = 1; 30 | while (m < n) { 31 | m = m << 1; 32 | } 33 | 34 | return m; 35 | } 36 | /* }}} */ 37 | /* {{{ hash_si_init */ 38 | int hash_si_init(struct hash_si *h, size_t size) { 39 | size = nextpow2(size); 40 | 41 | h->size = size; 42 | h->used = 0; 43 | h->data = (struct hash_si_pair *) malloc(sizeof(struct hash_si_pair) * size); 44 | if (h->data == NULL) { 45 | return 1; 46 | } 47 | 48 | memset(h->data, 0, sizeof(struct hash_si_pair) * size); 49 | 50 | return 0; 51 | } 52 | /* }}} */ 53 | /* {{{ hash_si_deinit */ 54 | void hash_si_deinit(struct hash_si *h) { 55 | size_t i; 56 | 57 | for (i = 0; i < h->size; i++) { 58 | if (h->data[i].key != NULL) { 59 | free(h->data[i].key); 60 | } 61 | } 62 | 63 | free(h->data); 64 | 65 | h->size = 0; 66 | h->used = 0; 67 | } 68 | /* }}} */ 69 | /* {{{ _hash_si_find */ 70 | /** Returns index of key, or where it should be. 71 | * @param h Pointer to hash_si struct. 72 | * @param key Pointer to key. 73 | * @param key_len Key length. 74 | * @return index. 75 | */ 76 | inline static size_t _hash_si_find(struct hash_si *h, const char *key, size_t key_len) { 77 | uint32_t hv; 78 | size_t size; 79 | 80 | assert(h != NULL); 81 | 82 | size = h->size; 83 | hv = zend_inline_hash_func(key, key_len) & (h->size-1); 84 | 85 | while (size > 0 && 86 | h->data[hv].key != NULL && 87 | (h->data[hv].key_len != key_len || memcmp(h->data[hv].key, key, key_len) != 0)) { 88 | /* linear prob */ 89 | hv = (hv + 1) & (h->size-1); 90 | size--; 91 | } 92 | 93 | return hv; 94 | } 95 | /* }}} */ 96 | /* {{{ hash_si_remove */ 97 | int hash_si_remove(struct hash_si *h, const char *key, size_t key_len, uint32_t *value) { 98 | uint32_t hv; 99 | uint32_t j, k; 100 | 101 | assert(h != NULL); 102 | 103 | hv = _hash_si_find(h, key, key_len); 104 | 105 | /* dont exists */ 106 | if (h->data[hv].key == NULL) { 107 | return 1; 108 | } 109 | 110 | h->used--; 111 | 112 | free(h->data[hv].key); 113 | 114 | if (value != NULL) 115 | *value = h->data[hv].value; 116 | 117 | j = (hv + 1) & (h->size-1); 118 | while (h->data[j].key != NULL) { 119 | k = zend_inline_hash_func(h->data[j].key, strlen(h->data[j].key)) & (h->size-1); 120 | if ((j > hv && (k <= hv || k > j)) || (j < hv && (k <= hv && k > j))) { 121 | h->data[hv].key = h->data[j].key; 122 | h->data[hv].key_len = h->data[j].key_len; 123 | h->data[hv].value = h->data[j].value; 124 | 125 | hv = j; 126 | } 127 | j = (j + 1) & (h->size-1); 128 | } 129 | h->data[hv].key = NULL; 130 | 131 | 132 | return 0; 133 | /* 134 | * loop 135 | * j := (j+1) modulo num_slots 136 | * if slot[j] is unoccupied 137 | * exit loop 138 | * k := hash(slot[j].key) modulo num_slots 139 | * if (j > i and (k <= i or k > j)) or 140 | * (j < i and (k <= i and k > j)) (note 2) 141 | * slot[i] := slot[j] 142 | * i := j 143 | * mark slot[i] as unoccupied 144 | * 145 | * For all records in a cluster, there must be no vacant slots between their natural 146 | * hash position and their current position (else lookups will terminate before finding 147 | * the record). At this point in the pseudocode, i is a vacant slot that might be 148 | * invalidating this property for subsequent records in the cluster. j is such a 149 | * subsequent record. k is the raw hash where the record at j would naturally land in 150 | * the hash table if there were no collisions. This test is asking if the record at j 151 | * is invalidly positioned with respect to the required properties of a cluster now 152 | * that i is vacant. 153 | * 154 | * Another technique for removal is simply to mark the slot as deleted. However 155 | * this eventually requires rebuilding the table simply to remove deleted records. 156 | * The methods above provide O(1) updating and removal of existing records, with 157 | * occasional rebuilding if the high water mark of the table size grows. 158 | */ 159 | } 160 | /* }}} */ 161 | /* {{{ hash_si_rehash */ 162 | /** Rehash/resize hash_si. 163 | * @param h Pointer to hash_si struct. 164 | */ 165 | inline static void hash_si_rehash(struct hash_si *h) { 166 | uint32_t hv; 167 | size_t i; 168 | struct hash_si newh; 169 | 170 | assert(h != NULL); 171 | 172 | hash_si_init(&newh, h->size * 2); 173 | 174 | for (i = 0; i < h->size; i++) { 175 | if (h->data[i].key != NULL) { 176 | hv = _hash_si_find(&newh, h->data[i].key, h->data[i].key_len); 177 | newh.data[hv].key = h->data[i].key; 178 | newh.data[hv].key_len = h->data[i].key_len; 179 | newh.data[hv].value = h->data[i].value; 180 | } 181 | } 182 | 183 | free(h->data); 184 | h->data = newh.data; 185 | h->size *= 2; 186 | } 187 | /* }}} */ 188 | /* {{{ hash_si_insert */ 189 | int hash_si_insert(struct hash_si *h, const char *key, size_t key_len, uint32_t value) { 190 | uint32_t hv; 191 | 192 | if (h->size / 4 * 3 < h->used + 1) { 193 | hash_si_rehash(h); 194 | } 195 | 196 | hv = _hash_si_find(h, key, key_len); 197 | 198 | if (h->data[hv].key == NULL) { 199 | h->data[hv].key = (char *) malloc(key_len + 1); 200 | if (h->data[hv].key == NULL) { 201 | return 1; 202 | } 203 | memcpy(h->data[hv].key, key, key_len); 204 | h->data[hv].key[key_len] = '\0'; 205 | h->data[hv].key_len = key_len; 206 | 207 | h->used++; 208 | } else { 209 | return 2; 210 | } 211 | 212 | h->data[hv].value = value; 213 | 214 | return 0; 215 | } 216 | /* }}} */ 217 | /* {{{ hash_si_find */ 218 | int hash_si_find(struct hash_si *h, const char *key, size_t key_len, uint32_t *value) { 219 | uint32_t hv; 220 | 221 | assert(h != NULL); 222 | 223 | hv = _hash_si_find(h, key, key_len); 224 | 225 | if (h->data[hv].key == NULL) { 226 | return 1; 227 | } else { 228 | *value = h->data[hv].value; 229 | return 0; 230 | } 231 | } 232 | /* }}} */ 233 | /* {{{ hash_si_traverse */ 234 | void hash_si_traverse(struct hash_si *h, int (*traverse_function) (const char *key, size_t key_len, uint32_t value)) { 235 | size_t i; 236 | 237 | assert(h != NULL && traverse_function != NULL); 238 | 239 | for (i = 0; i < h->size; i++) { 240 | if (h->data[i].key != NULL && traverse_function(h->data[i].key, h->data[i].key_len, h->data[i].value) != 1) { 241 | return; 242 | } 243 | } 244 | } 245 | /* }}} */ 246 | /* {{{ hash_si_size */ 247 | size_t hash_si_size(struct hash_si *h) { 248 | assert(h != NULL); 249 | 250 | return h->used; 251 | } 252 | /* }}} */ 253 | /* {{{ hash_si_capacity */ 254 | size_t hash_si_capacity(struct hash_si *h) { 255 | assert(h != NULL); 256 | 257 | return h->size; 258 | } 259 | /* }}} */ 260 | 261 | /* 262 | * Local variables: 263 | * tab-width: 2 264 | * c-basic-offset: 4 265 | * End: 266 | * vim600: noet sw=4 ts=4 fdm=marker 267 | * vim<600: noet sw=4 ts=4 268 | */ 269 | -------------------------------------------------------------------------------- /ig_win32.h: -------------------------------------------------------------------------------- 1 | #ifndef _IG_WIN32_H 2 | #define _IG_WIN32_H 3 | 4 | #if PHP_WIN32 5 | # include "win32/php_stdint.h" 6 | # ifndef inline 7 | # define inline __inline 8 | # endif 9 | 10 | # ifndef __cplusplus 11 | # if !0 12 | typedef enum { false = 0, true = 1 } _Bool; 13 | # endif 14 | # else 15 | typedef bool _Bool; 16 | # endif 17 | # define bool _Bool 18 | 19 | # define false 0 20 | # define true 1 21 | # define __bool_true_false_are_defined 1 22 | #endif 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /igbinary.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | See COPYING file for further copyright information | 4 | +----------------------------------------------------------------------+ 5 | | Author: Oleg Grenrus | 6 | | See CREDITS for contributors | 7 | +----------------------------------------------------------------------+ 8 | */ 9 | 10 | #ifdef HAVE_CONFIG_H 11 | #include "config.h" 12 | #endif 13 | 14 | #ifdef PHP_WIN32 15 | # include "ig_win32.h" 16 | #endif 17 | 18 | #include "php.h" 19 | #include "php_ini.h" 20 | #include "zend_dynamic_array.h" 21 | #include "zend_alloc.h" 22 | #include "ext/standard/info.h" 23 | #include "ext/standard/php_var.h" 24 | 25 | #if HAVE_PHP_SESSION 26 | # include "ext/session/php_session.h" 27 | #endif /* HAVE_PHP_SESSION */ 28 | 29 | #include "ext/standard/php_incomplete_class.h" 30 | 31 | #if defined(HAVE_APCU_SUPPORT) 32 | # include "ext/apcu/apc_serializer.h" 33 | #elif defined(HAVE_APC_SUPPORT) 34 | # if USE_BUNDLED_APC 35 | # include "apc_serializer.h" 36 | # else 37 | # include "ext/apc/apc_serializer.h" 38 | # endif 39 | #endif /* HAVE_APCU_SUPPORT || HAVE_APC_SUPPORT */ 40 | 41 | #include "php_igbinary.h" 42 | 43 | #include "igbinary.h" 44 | 45 | #include 46 | 47 | #ifndef PHP_WIN32 48 | # include 49 | # include 50 | # include 51 | #endif 52 | 53 | 54 | #include 55 | #include "hash.h" 56 | 57 | #if HAVE_PHP_SESSION 58 | /** Session serializer function prototypes. */ 59 | PS_SERIALIZER_FUNCS(igbinary); 60 | #endif /* HAVE_PHP_SESSION */ 61 | 62 | #if defined(HAVE_APC_SUPPORT) || defined(HAVE_APCU_SUPPORT) 63 | /** Apc serializer function prototypes */ 64 | static int APC_SERIALIZER_NAME(igbinary) (APC_SERIALIZER_ARGS); 65 | static int APC_UNSERIALIZER_NAME(igbinary) (APC_UNSERIALIZER_ARGS); 66 | #endif 67 | 68 | /* {{{ Types */ 69 | enum igbinary_type { 70 | /* 00 */ igbinary_type_null, /**< Null. */ 71 | 72 | /* 01 */ igbinary_type_ref8, /**< Array reference. */ 73 | /* 02 */ igbinary_type_ref16, /**< Array reference. */ 74 | /* 03 */ igbinary_type_ref32, /**< Array reference. */ 75 | 76 | /* 04 */ igbinary_type_bool_false, /**< Boolean true. */ 77 | /* 05 */ igbinary_type_bool_true, /**< Boolean false. */ 78 | 79 | /* 06 */ igbinary_type_long8p, /**< Long 8bit positive. */ 80 | /* 07 */ igbinary_type_long8n, /**< Long 8bit negative. */ 81 | /* 08 */ igbinary_type_long16p, /**< Long 16bit positive. */ 82 | /* 09 */ igbinary_type_long16n, /**< Long 16bit negative. */ 83 | /* 0a */ igbinary_type_long32p, /**< Long 32bit positive. */ 84 | /* 0b */ igbinary_type_long32n, /**< Long 32bit negative. */ 85 | 86 | /* 0c */ igbinary_type_double, /**< Double. */ 87 | 88 | /* 0d */ igbinary_type_string_empty, /**< Empty string. */ 89 | 90 | /* 0e */ igbinary_type_string_id8, /**< String id. */ 91 | /* 0f */ igbinary_type_string_id16, /**< String id. */ 92 | /* 10 */ igbinary_type_string_id32, /**< String id. */ 93 | 94 | /* 11 */ igbinary_type_string8, /**< String. */ 95 | /* 12 */ igbinary_type_string16, /**< String. */ 96 | /* 13 */ igbinary_type_string32, /**< String. */ 97 | 98 | /* 14 */ igbinary_type_array8, /**< Array. */ 99 | /* 15 */ igbinary_type_array16, /**< Array. */ 100 | /* 16 */ igbinary_type_array32, /**< Array. */ 101 | 102 | /* 17 */ igbinary_type_object8, /**< Object. */ 103 | /* 18 */ igbinary_type_object16, /**< Object. */ 104 | /* 19 */ igbinary_type_object32, /**< Object. */ 105 | 106 | /* 1a */ igbinary_type_object_id8, /**< Object string id. */ 107 | /* 1b */ igbinary_type_object_id16, /**< Object string id. */ 108 | /* 1c */ igbinary_type_object_id32, /**< Object string id. */ 109 | 110 | /* 1d */ igbinary_type_object_ser8, /**< Object serialized data. */ 111 | /* 1e */ igbinary_type_object_ser16, /**< Object serialized data. */ 112 | /* 1f */ igbinary_type_object_ser32, /**< Object serialized data. */ 113 | 114 | /* 20 */ igbinary_type_long64p, /**< Long 64bit positive. */ 115 | /* 21 */ igbinary_type_long64n, /**< Long 64bit negative. */ 116 | 117 | /* 22 */ igbinary_type_objref8, /**< Object reference. */ 118 | /* 23 */ igbinary_type_objref16, /**< Object reference. */ 119 | /* 24 */ igbinary_type_objref32, /**< Object reference. */ 120 | 121 | /* 25 */ igbinary_type_ref, /**< Simple reference */ 122 | }; 123 | 124 | /** Serializer data. 125 | * @author Oleg Grenrus 126 | */ 127 | struct igbinary_serialize_data { 128 | uint8_t *buffer; /**< Buffer. */ 129 | size_t buffer_size; /**< Buffer size. */ 130 | size_t buffer_capacity; /**< Buffer capacity. */ 131 | bool scalar; /**< Serializing scalar. */ 132 | bool compact_strings; /**< Check for duplicate strings. */ 133 | struct hash_si strings; /**< Hash of already serialized strings. */ 134 | struct hash_si objects; /**< Hash of already serialized objects. */ 135 | int string_count; /**< Serialized string count, used for back referencing */ 136 | int error; /**< Error number. Not used. */ 137 | struct igbinary_memory_manager mm; /**< Memory management functions. */ 138 | }; 139 | 140 | /** String/len pair for the igbinary_unserializer_data. 141 | * @author Oleg Grenrus 142 | * @see igbinary_unserialize_data. 143 | */ 144 | struct igbinary_unserialize_string_pair { 145 | char *data; /**< Data. */ 146 | size_t len; /**< Data length. */ 147 | }; 148 | 149 | /** Unserializer data. 150 | * @author Oleg Grenrus 151 | */ 152 | struct igbinary_unserialize_data { 153 | uint8_t *buffer; /**< Buffer. */ 154 | size_t buffer_size; /**< Buffer size. */ 155 | size_t buffer_offset; /**< Current read offset. */ 156 | 157 | struct igbinary_unserialize_string_pair *strings; /**< Unserialized strings. */ 158 | size_t strings_count; /**< Unserialized string count. */ 159 | size_t strings_capacity; /**< Unserialized string array capacity. */ 160 | 161 | void **references; /**< Unserialized Arrays/Objects. */ 162 | size_t references_count; /**< Unserialized array/objects count. */ 163 | size_t references_capacity; /**< Unserialized array/object array capacity. */ 164 | 165 | int error; /**< Error number. Not used. */ 166 | smart_str string0_buf; /**< Temporary buffer for strings */ 167 | }; 168 | /* }}} */ 169 | /* {{{ Memory allocator wrapper prototypes */ 170 | static inline void *igbinary_mm_wrapper_malloc(size_t size, void *context); 171 | static inline void *igbinary_mm_wrapper_realloc(void *ptr, size_t size, void *context); 172 | static inline void igbinary_mm_wrapper_free(void *ptr, void *context); 173 | /* }}} */ 174 | /* {{{ Serializing functions prototypes */ 175 | inline static int igbinary_serialize_data_init(struct igbinary_serialize_data *igsd, bool scalar, struct igbinary_memory_manager *memory_manager TSRMLS_DC); 176 | inline static void igbinary_serialize_data_deinit(struct igbinary_serialize_data *igsd, int free_buffer TSRMLS_DC); 177 | 178 | inline static int igbinary_serialize_header(struct igbinary_serialize_data *igsd TSRMLS_DC); 179 | 180 | inline static int igbinary_serialize8(struct igbinary_serialize_data *igsd, uint8_t i TSRMLS_DC); 181 | inline static int igbinary_serialize16(struct igbinary_serialize_data *igsd, uint16_t i TSRMLS_DC); 182 | inline static int igbinary_serialize32(struct igbinary_serialize_data *igsd, uint32_t i TSRMLS_DC); 183 | inline static int igbinary_serialize64(struct igbinary_serialize_data *igsd, uint64_t i TSRMLS_DC); 184 | 185 | inline static int igbinary_serialize_null(struct igbinary_serialize_data *igsd TSRMLS_DC); 186 | inline static int igbinary_serialize_bool(struct igbinary_serialize_data *igsd, int b TSRMLS_DC); 187 | inline static int igbinary_serialize_long(struct igbinary_serialize_data *igsd, long l TSRMLS_DC); 188 | inline static int igbinary_serialize_double(struct igbinary_serialize_data *igsd, double d TSRMLS_DC); 189 | inline static int igbinary_serialize_string(struct igbinary_serialize_data *igsd, char *s, size_t len TSRMLS_DC); 190 | inline static int igbinary_serialize_chararray(struct igbinary_serialize_data *igsd, const char *s, size_t len TSRMLS_DC); 191 | 192 | inline static int igbinary_serialize_array(struct igbinary_serialize_data *igsd, zval *z, bool object, bool incomplete_class TSRMLS_DC); 193 | inline static int igbinary_serialize_array_ref(struct igbinary_serialize_data *igsd, zval *z, bool object TSRMLS_DC); 194 | inline static int igbinary_serialize_array_sleep(struct igbinary_serialize_data *igsd, zval *z, HashTable *ht, zend_class_entry *ce, bool incomplete_class TSRMLS_DC); 195 | inline static int igbinary_serialize_object_name(struct igbinary_serialize_data *igsd, const char *name, size_t name_len TSRMLS_DC); 196 | inline static int igbinary_serialize_object(struct igbinary_serialize_data *igsd, zval *z TSRMLS_DC); 197 | 198 | static int igbinary_serialize_zval(struct igbinary_serialize_data *igsd, zval *z TSRMLS_DC); 199 | /* }}} */ 200 | /* {{{ Unserializing functions prototypes */ 201 | inline static int igbinary_unserialize_data_init(struct igbinary_unserialize_data *igsd TSRMLS_DC); 202 | inline static void igbinary_unserialize_data_deinit(struct igbinary_unserialize_data *igsd TSRMLS_DC); 203 | 204 | inline static int igbinary_unserialize_header(struct igbinary_unserialize_data *igsd TSRMLS_DC); 205 | 206 | inline static uint8_t igbinary_unserialize8(struct igbinary_unserialize_data *igsd TSRMLS_DC); 207 | inline static uint16_t igbinary_unserialize16(struct igbinary_unserialize_data *igsd TSRMLS_DC); 208 | inline static uint32_t igbinary_unserialize32(struct igbinary_unserialize_data *igsd TSRMLS_DC); 209 | inline static uint64_t igbinary_unserialize64(struct igbinary_unserialize_data *igsd TSRMLS_DC); 210 | 211 | inline static int igbinary_unserialize_long(struct igbinary_unserialize_data *igsd, enum igbinary_type t, long *ret TSRMLS_DC); 212 | inline static int igbinary_unserialize_double(struct igbinary_unserialize_data *igsd, enum igbinary_type t, double *ret TSRMLS_DC); 213 | inline static int igbinary_unserialize_string(struct igbinary_unserialize_data *igsd, enum igbinary_type t, char **s, size_t *len TSRMLS_DC); 214 | inline static int igbinary_unserialize_chararray(struct igbinary_unserialize_data *igsd, enum igbinary_type t, char **s, size_t *len TSRMLS_DC); 215 | 216 | inline static int igbinary_unserialize_array(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval **z, int object TSRMLS_DC); 217 | inline static int igbinary_unserialize_object(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval **z TSRMLS_DC); 218 | inline static int igbinary_unserialize_object_ser(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval **z, zend_class_entry *ce TSRMLS_DC); 219 | inline static int igbinary_unserialize_ref(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval **z TSRMLS_DC); 220 | 221 | static int igbinary_unserialize_zval(struct igbinary_unserialize_data *igsd, zval **z TSRMLS_DC); 222 | /* }}} */ 223 | /* {{{ arginfo */ 224 | ZEND_BEGIN_ARG_INFO_EX(arginfo_igbinary_serialize, 0, 0, 1) 225 | ZEND_ARG_INFO(0, value) 226 | ZEND_END_ARG_INFO() 227 | 228 | ZEND_BEGIN_ARG_INFO_EX(arginfo_igbinary_unserialize, 0, 0, 1) 229 | ZEND_ARG_INFO(0, str) 230 | ZEND_END_ARG_INFO() 231 | /* }}} */ 232 | /* {{{ igbinary_functions[] */ 233 | /** Exported php functions. */ 234 | zend_function_entry igbinary_functions[] = { 235 | PHP_FE(igbinary_serialize, arginfo_igbinary_serialize) 236 | PHP_FE(igbinary_unserialize, arginfo_igbinary_unserialize) 237 | {NULL, NULL, NULL} 238 | }; 239 | /* }}} */ 240 | 241 | /* {{{ igbinary dependencies */ 242 | #if ZEND_MODULE_API_NO >= 20050922 243 | static const zend_module_dep igbinary_module_deps[] = { 244 | ZEND_MOD_REQUIRED("standard") 245 | #ifdef HAVE_PHP_SESSION 246 | ZEND_MOD_REQUIRED("session") 247 | #endif 248 | #if defined(HAVE_APCU_SUPPORT) 249 | ZEND_MOD_OPTIONAL("apcu") 250 | #elif defined(HAVE_APC_SUPPORT) 251 | ZEND_MOD_OPTIONAL("apc") 252 | #endif 253 | {NULL, NULL, NULL} 254 | }; 255 | #endif 256 | /* }}} */ 257 | 258 | /* {{{ igbinary_module_entry */ 259 | zend_module_entry igbinary_module_entry = { 260 | #if ZEND_MODULE_API_NO >= 20050922 261 | STANDARD_MODULE_HEADER_EX, NULL, 262 | igbinary_module_deps, 263 | #elif ZEND_MODULE_API_NO >= 20010901 264 | STANDARD_MODULE_HEADER, 265 | #endif 266 | "igbinary", 267 | igbinary_functions, 268 | PHP_MINIT(igbinary), 269 | PHP_MSHUTDOWN(igbinary), 270 | NULL, 271 | NULL, 272 | PHP_MINFO(igbinary), 273 | #if ZEND_MODULE_API_NO >= 20010901 274 | PHP_IGBINARY_VERSION, /* Replace with version number for your extension */ 275 | #endif 276 | STANDARD_MODULE_PROPERTIES 277 | }; 278 | /* }}} */ 279 | 280 | ZEND_DECLARE_MODULE_GLOBALS(igbinary) 281 | 282 | /* {{{ ZEND_GET_MODULE */ 283 | #ifdef COMPILE_DL_IGBINARY 284 | ZEND_GET_MODULE(igbinary) 285 | #endif 286 | /* }}} */ 287 | 288 | /* {{{ INI entries */ 289 | PHP_INI_BEGIN() 290 | STD_PHP_INI_BOOLEAN("igbinary.compact_strings", "1", PHP_INI_ALL, OnUpdateBool, compact_strings, zend_igbinary_globals, igbinary_globals) 291 | PHP_INI_END() 292 | /* }}} */ 293 | 294 | /* {{{ php_igbinary_init_globals */ 295 | static void php_igbinary_init_globals(zend_igbinary_globals *igbinary_globals) { 296 | igbinary_globals->compact_strings = 1; 297 | } 298 | /* }}} */ 299 | 300 | /* {{{ PHP_MINIT_FUNCTION */ 301 | PHP_MINIT_FUNCTION(igbinary) { 302 | (void) type; 303 | (void) module_number; 304 | ZEND_INIT_MODULE_GLOBALS(igbinary, php_igbinary_init_globals, NULL); 305 | 306 | #if HAVE_PHP_SESSION 307 | php_session_register_serializer("igbinary", 308 | PS_SERIALIZER_ENCODE_NAME(igbinary), 309 | PS_SERIALIZER_DECODE_NAME(igbinary)); 310 | #endif 311 | 312 | #if defined(HAVE_APC_SUPPORT) || defined(HAVE_APCU_SUPPORT) 313 | apc_register_serializer("igbinary", 314 | APC_SERIALIZER_NAME(igbinary), 315 | APC_UNSERIALIZER_NAME(igbinary), 316 | NULL TSRMLS_CC); 317 | #endif 318 | 319 | REGISTER_INI_ENTRIES(); 320 | 321 | return SUCCESS; 322 | } 323 | /* }}} */ 324 | /* {{{ PHP_MSHUTDOWN_FUNCTION */ 325 | PHP_MSHUTDOWN_FUNCTION(igbinary) { 326 | (void) type; 327 | (void) module_number; 328 | 329 | #ifdef ZTS 330 | ts_free_id(igbinary_globals_id); 331 | #endif 332 | 333 | /* 334 | * unregister serializer? 335 | */ 336 | UNREGISTER_INI_ENTRIES(); 337 | 338 | return SUCCESS; 339 | } 340 | /* }}} */ 341 | /* {{{ PHP_MINFO_FUNCTION */ 342 | PHP_MINFO_FUNCTION(igbinary) { 343 | (void) zend_module; 344 | php_info_print_table_start(); 345 | php_info_print_table_row(2, "igbinary support", "enabled"); 346 | php_info_print_table_row(2, "igbinary version", PHP_IGBINARY_VERSION); 347 | #if defined(HAVE_APCU_SUPPORT) 348 | php_info_print_table_row(2, "igbinary APCU serializer ABI", APC_SERIALIZER_ABI); 349 | #elif defined(HAVE_APC_SUPPORT) 350 | php_info_print_table_row(2, "igbinary APC serializer ABI", APC_SERIALIZER_ABI); 351 | #else 352 | php_info_print_table_row(2, "igbinary APC serializer ABI", "no"); 353 | #endif 354 | #if HAVE_PHP_SESSION 355 | php_info_print_table_row(2, "igbinary session support", "yes"); 356 | #else 357 | php_info_print_table_row(2, "igbinary session support", "no"); 358 | #endif 359 | php_info_print_table_end(); 360 | 361 | DISPLAY_INI_ENTRIES(); 362 | } 363 | /* }}} */ 364 | /* {{{ Memory allocator wrappers */ 365 | static inline void *igbinary_mm_wrapper_malloc(size_t size, void *context) 366 | { 367 | return emalloc(size); 368 | } 369 | 370 | static inline void *igbinary_mm_wrapper_realloc(void *ptr, size_t size, void *context) 371 | { 372 | return erealloc(ptr, size); 373 | } 374 | 375 | static inline void igbinary_mm_wrapper_free(void *ptr, void *context) 376 | { 377 | return efree(ptr); 378 | } 379 | /* }}} */ 380 | /* {{{ int igbinary_serialize(uint8_t**, size_t*, zval*) */ 381 | IGBINARY_API int igbinary_serialize(uint8_t **ret, size_t *ret_len, zval *z TSRMLS_DC) { 382 | return igbinary_serialize_ex(ret, ret_len, z, NULL TSRMLS_CC); 383 | } 384 | /* }}} */ 385 | /* {{{ int igbinary_serialize_ex(uint8_t**, size_t*, zval*, igbinary_memory_manager*) */ 386 | IGBINARY_API int igbinary_serialize_ex(uint8_t **ret, size_t *ret_len, zval *z, struct igbinary_memory_manager *memory_manager TSRMLS_DC) { 387 | struct igbinary_serialize_data igsd; 388 | uint8_t *tmpbuf; 389 | 390 | if (igbinary_serialize_data_init(&igsd, Z_TYPE_P(z) != IS_OBJECT && Z_TYPE_P(z) != IS_ARRAY, memory_manager TSRMLS_CC)) { 391 | zend_error(E_WARNING, "igbinary_serialize: cannot init igsd"); 392 | return 1; 393 | } 394 | 395 | if (igbinary_serialize_header(&igsd TSRMLS_CC) != 0) { 396 | zend_error(E_WARNING, "igbinary_serialize: cannot write header"); 397 | igbinary_serialize_data_deinit(&igsd, 1 TSRMLS_CC); 398 | return 1; 399 | } 400 | 401 | if (igbinary_serialize_zval(&igsd, z TSRMLS_CC) != 0) { 402 | igbinary_serialize_data_deinit(&igsd, 1 TSRMLS_CC); 403 | return 1; 404 | } 405 | 406 | /* Explicit nul termination */ 407 | if (igbinary_serialize8(&igsd, 0 TSRMLS_CC) != 0) { 408 | igbinary_serialize_data_deinit(&igsd, 1 TSRMLS_CC); 409 | return 1; 410 | } 411 | 412 | /* shrink buffer to the real length, ignore errors */ 413 | tmpbuf = (uint8_t *) igsd.mm.realloc(igsd.buffer, igsd.buffer_size, igsd.mm.context); 414 | if (tmpbuf != NULL) { 415 | igsd.buffer = tmpbuf; 416 | } 417 | 418 | /* Set return values */ 419 | *ret_len = igsd.buffer_size - 1; 420 | *ret = igsd.buffer; 421 | 422 | igbinary_serialize_data_deinit(&igsd, 0 TSRMLS_CC); 423 | 424 | return 0; 425 | } 426 | /* }}} */ 427 | /* {{{ int igbinary_unserialize(const uint8_t *, size_t, zval **) */ 428 | IGBINARY_API int igbinary_unserialize(const uint8_t *buf, size_t buf_len, zval **z TSRMLS_DC) { 429 | struct igbinary_unserialize_data igsd; 430 | 431 | igbinary_unserialize_data_init(&igsd TSRMLS_CC); 432 | 433 | igsd.buffer = (uint8_t *) buf; 434 | igsd.buffer_size = buf_len; 435 | 436 | if (igbinary_unserialize_header(&igsd TSRMLS_CC)) { 437 | igbinary_unserialize_data_deinit(&igsd TSRMLS_CC); 438 | return 1; 439 | } 440 | 441 | if (igbinary_unserialize_zval(&igsd, z TSRMLS_CC)) { 442 | igbinary_unserialize_data_deinit(&igsd TSRMLS_CC); 443 | return 1; 444 | } 445 | 446 | igbinary_unserialize_data_deinit(&igsd TSRMLS_CC); 447 | 448 | return 0; 449 | } 450 | /* }}} */ 451 | /* {{{ proto string igbinary_unserialize(mixed value) */ 452 | PHP_FUNCTION(igbinary_unserialize) { 453 | char *string; 454 | int string_len; 455 | 456 | (void) return_value_ptr; 457 | (void) this_ptr; 458 | (void) return_value_used; 459 | 460 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &string, &string_len) == FAILURE) { 461 | RETURN_NULL(); 462 | } 463 | 464 | if (string_len <= 0) { 465 | RETURN_FALSE; 466 | } 467 | 468 | if (igbinary_unserialize((uint8_t *) string, string_len, &return_value TSRMLS_CC) != 0) { 469 | RETURN_NULL(); 470 | } 471 | } 472 | /* }}} */ 473 | /* {{{ proto mixed igbinary_serialize(string value) */ 474 | PHP_FUNCTION(igbinary_serialize) { 475 | zval *z; 476 | uint8_t *string; 477 | size_t string_len; 478 | 479 | (void) return_value_ptr; 480 | (void) this_ptr; 481 | (void) return_value_used; 482 | 483 | 484 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &z) == FAILURE) { 485 | RETURN_NULL(); 486 | } 487 | 488 | if (igbinary_serialize(&string, &string_len, z TSRMLS_CC) != 0) { 489 | RETURN_NULL(); 490 | } 491 | 492 | RETVAL_STRINGL((char *)string, string_len, 0); 493 | } 494 | /* }}} */ 495 | #ifdef HAVE_PHP_SESSION 496 | /* {{{ Serializer encode function */ 497 | PS_SERIALIZER_ENCODE_FUNC(igbinary) 498 | { 499 | struct igbinary_serialize_data igsd; 500 | uint8_t *tmpbuf; 501 | 502 | if (igbinary_serialize_data_init(&igsd, false, NULL TSRMLS_CC)) { 503 | zend_error(E_WARNING, "igbinary_serialize: cannot init igsd"); 504 | return FAILURE; 505 | } 506 | 507 | if (igbinary_serialize_header(&igsd TSRMLS_CC) != 0) { 508 | zend_error(E_WARNING, "igbinary_serialize: cannot write header"); 509 | igbinary_serialize_data_deinit(&igsd, 1 TSRMLS_CC); 510 | return FAILURE; 511 | } 512 | 513 | if (igbinary_serialize_array(&igsd, PS(http_session_vars), false, false TSRMLS_CC) != 0) { 514 | igbinary_serialize_data_deinit(&igsd, 1 TSRMLS_CC); 515 | return FAILURE; 516 | } 517 | 518 | if (igbinary_serialize8(&igsd, 0 TSRMLS_CC) != 0) { 519 | igbinary_serialize_data_deinit(&igsd, 1 TSRMLS_CC); 520 | return FAILURE; 521 | } 522 | 523 | /* shrink buffer to the real length, ignore errors */ 524 | tmpbuf = (uint8_t *)igsd.mm.realloc(igsd.buffer, igsd.buffer_size, igsd.mm.context); 525 | if (tmpbuf != NULL) { 526 | igsd.buffer = tmpbuf; 527 | } 528 | 529 | *newstr = (char *)igsd.buffer; 530 | if (newlen) { 531 | *newlen = igsd.buffer_size - 1; 532 | } 533 | 534 | igbinary_serialize_data_deinit(&igsd, 0 TSRMLS_CC); 535 | 536 | return SUCCESS; 537 | } 538 | /* }}} */ 539 | /* {{{ Serializer decode function */ 540 | PS_SERIALIZER_DECODE_FUNC(igbinary) { 541 | HashPosition tmp_hash_pos; 542 | HashTable *tmp_hash; 543 | char *key_str; 544 | ulong key_long; 545 | int tmp_int; 546 | uint key_len; 547 | zval *z; 548 | zval **d; 549 | 550 | struct igbinary_unserialize_data igsd; 551 | 552 | if (!val || vallen==0) 553 | return SUCCESS; 554 | 555 | if (igbinary_unserialize_data_init(&igsd TSRMLS_CC) != 0) { 556 | return FAILURE; 557 | } 558 | 559 | igsd.buffer = (uint8_t *)val; 560 | igsd.buffer_size = vallen; 561 | 562 | if (igbinary_unserialize_header(&igsd TSRMLS_CC)) { 563 | igbinary_unserialize_data_deinit(&igsd TSRMLS_CC); 564 | return FAILURE; 565 | } 566 | 567 | ALLOC_INIT_ZVAL(z); 568 | if (igbinary_unserialize_zval(&igsd, &z TSRMLS_CC)) { 569 | igbinary_unserialize_data_deinit(&igsd TSRMLS_CC); 570 | zval_dtor(z); 571 | FREE_ZVAL(z); 572 | return FAILURE; 573 | } 574 | 575 | igbinary_unserialize_data_deinit(&igsd TSRMLS_CC); 576 | 577 | tmp_hash = HASH_OF(z); 578 | 579 | zend_hash_internal_pointer_reset_ex(tmp_hash, &tmp_hash_pos); 580 | while (zend_hash_get_current_data_ex(tmp_hash, (void *) &d, &tmp_hash_pos) == SUCCESS) { 581 | tmp_int = zend_hash_get_current_key_ex(tmp_hash, &key_str, &key_len, &key_long, 0, &tmp_hash_pos); 582 | 583 | switch (tmp_int) { 584 | case HASH_KEY_IS_LONG: 585 | /* ??? */ 586 | break; 587 | case HASH_KEY_IS_STRING: 588 | php_set_session_var(key_str, key_len-1, *d, NULL TSRMLS_CC); 589 | php_add_session_var(key_str, key_len-1 TSRMLS_CC); 590 | break; 591 | } 592 | zend_hash_move_forward_ex(tmp_hash, &tmp_hash_pos); 593 | } 594 | zval_dtor(z); 595 | FREE_ZVAL(z); 596 | 597 | return SUCCESS; 598 | } 599 | /* }}} */ 600 | #endif /* HAVE_PHP_SESSION */ 601 | 602 | #if defined(HAVE_APC_SUPPORT) || defined(HAVE_APCU_SUPPORT) 603 | /* {{{ apc_serialize function */ 604 | static int APC_SERIALIZER_NAME(igbinary) ( APC_SERIALIZER_ARGS ) { 605 | (void)config; 606 | 607 | if (igbinary_serialize(buf, buf_len, (zval *)value TSRMLS_CC) == 0) { 608 | /* flipped semantics */ 609 | return 1; 610 | } 611 | return 0; 612 | } 613 | /* }}} */ 614 | /* {{{ apc_unserialize function */ 615 | static int APC_UNSERIALIZER_NAME(igbinary) ( APC_UNSERIALIZER_ARGS ) { 616 | (void)config; 617 | 618 | if (igbinary_unserialize(buf, buf_len, value TSRMLS_CC) == 0) { 619 | /* flipped semantics */ 620 | return 1; 621 | } 622 | zval_dtor(*value); 623 | (*value)->type = IS_NULL; 624 | return 0; 625 | } 626 | /* }}} */ 627 | #endif 628 | 629 | /* {{{ igbinary_serialize_data_init */ 630 | /** Inits igbinary_serialize_data. */ 631 | inline static int igbinary_serialize_data_init(struct igbinary_serialize_data *igsd, bool scalar, struct igbinary_memory_manager *memory_manager TSRMLS_DC) { 632 | int r = 0; 633 | 634 | if (memory_manager == NULL) { 635 | igsd->mm.alloc = igbinary_mm_wrapper_malloc; 636 | igsd->mm.realloc = igbinary_mm_wrapper_realloc; 637 | igsd->mm.free = igbinary_mm_wrapper_free; 638 | igsd->mm.context = NULL; 639 | } else { 640 | igsd->mm = *memory_manager; 641 | } 642 | 643 | igsd->buffer = NULL; 644 | igsd->buffer_size = 0; 645 | igsd->buffer_capacity = 32; 646 | igsd->string_count = 0; 647 | igsd->error = 0; 648 | 649 | igsd->buffer = (uint8_t *) igsd->mm.alloc(igsd->buffer_capacity, igsd->mm.context); 650 | if (igsd->buffer == NULL) { 651 | return 1; 652 | } 653 | 654 | igsd->scalar = scalar; 655 | if (!igsd->scalar) { 656 | hash_si_init(&igsd->strings, 16); 657 | hash_si_init(&igsd->objects, 16); 658 | } 659 | 660 | igsd->compact_strings = (bool)IGBINARY_G(compact_strings); 661 | 662 | return r; 663 | } 664 | /* }}} */ 665 | /* {{{ igbinary_serialize_data_deinit */ 666 | /** Deinits igbinary_serialize_data. */ 667 | inline static void igbinary_serialize_data_deinit(struct igbinary_serialize_data *igsd, int free_buffer TSRMLS_DC) { 668 | if (free_buffer && igsd->buffer) { 669 | igsd->mm.free(igsd->buffer, igsd->mm.context); 670 | } 671 | 672 | if (!igsd->scalar) { 673 | hash_si_deinit(&igsd->strings); 674 | hash_si_deinit(&igsd->objects); 675 | } 676 | } 677 | /* }}} */ 678 | /* {{{ igbinary_serialize_header */ 679 | /** Serializes header. */ 680 | inline static int igbinary_serialize_header(struct igbinary_serialize_data *igsd TSRMLS_DC) { 681 | return igbinary_serialize32(igsd, IGBINARY_FORMAT_VERSION TSRMLS_CC); /* version */ 682 | } 683 | /* }}} */ 684 | /* {{{ igbinary_serialize_resize */ 685 | /** Expands igbinary_serialize_data. */ 686 | inline static int igbinary_serialize_resize(struct igbinary_serialize_data *igsd, size_t size TSRMLS_DC) { 687 | if (igsd->buffer_size + size < igsd->buffer_capacity) { 688 | return 0; 689 | } 690 | 691 | while (igsd->buffer_size + size >= igsd->buffer_capacity) { 692 | igsd->buffer_capacity *= 2; 693 | } 694 | 695 | igsd->buffer = (uint8_t *) igsd->mm.realloc(igsd->buffer, igsd->buffer_capacity, igsd->mm.context); 696 | if (igsd->buffer == NULL) 697 | return 1; 698 | 699 | return 0; 700 | } 701 | /* }}} */ 702 | /* {{{ igbinary_serialize8 */ 703 | /** Serialize 8bit value. */ 704 | inline static int igbinary_serialize8(struct igbinary_serialize_data *igsd, uint8_t i TSRMLS_DC) { 705 | if (igbinary_serialize_resize(igsd, 1 TSRMLS_CC)) { 706 | return 1; 707 | } 708 | 709 | igsd->buffer[igsd->buffer_size++] = i; 710 | return 0; 711 | } 712 | /* }}} */ 713 | /* {{{ igbinary_serialize16 */ 714 | /** Serialize 16bit value. */ 715 | inline static int igbinary_serialize16(struct igbinary_serialize_data *igsd, uint16_t i TSRMLS_DC) { 716 | if (igbinary_serialize_resize(igsd, 2 TSRMLS_CC)) { 717 | return 1; 718 | } 719 | 720 | igsd->buffer[igsd->buffer_size++] = (uint8_t) (i >> 8 & 0xff); 721 | igsd->buffer[igsd->buffer_size++] = (uint8_t) (i & 0xff); 722 | 723 | return 0; 724 | } 725 | /* }}} */ 726 | /* {{{ igbinary_serialize32 */ 727 | /** Serialize 32bit value. */ 728 | inline static int igbinary_serialize32(struct igbinary_serialize_data *igsd, uint32_t i TSRMLS_DC) { 729 | if (igbinary_serialize_resize(igsd, 4 TSRMLS_CC)) { 730 | return 1; 731 | } 732 | 733 | igsd->buffer[igsd->buffer_size++] = (uint8_t) (i >> 24 & 0xff); 734 | igsd->buffer[igsd->buffer_size++] = (uint8_t) (i >> 16 & 0xff); 735 | igsd->buffer[igsd->buffer_size++] = (uint8_t) (i >> 8 & 0xff); 736 | igsd->buffer[igsd->buffer_size++] = (uint8_t) (i & 0xff); 737 | 738 | return 0; 739 | } 740 | /* }}} */ 741 | /* {{{ igbinary_serialize64 */ 742 | /** Serialize 64bit value. */ 743 | inline static int igbinary_serialize64(struct igbinary_serialize_data *igsd, uint64_t i TSRMLS_DC) { 744 | if (igbinary_serialize_resize(igsd, 8 TSRMLS_CC)) { 745 | return 1; 746 | } 747 | 748 | igsd->buffer[igsd->buffer_size++] = (uint8_t) (i >> 56 & 0xff); 749 | igsd->buffer[igsd->buffer_size++] = (uint8_t) (i >> 48 & 0xff); 750 | igsd->buffer[igsd->buffer_size++] = (uint8_t) (i >> 40 & 0xff); 751 | igsd->buffer[igsd->buffer_size++] = (uint8_t) (i >> 32 & 0xff); 752 | igsd->buffer[igsd->buffer_size++] = (uint8_t) (i >> 24 & 0xff); 753 | igsd->buffer[igsd->buffer_size++] = (uint8_t) (i >> 16 & 0xff); 754 | igsd->buffer[igsd->buffer_size++] = (uint8_t) (i >> 8 & 0xff); 755 | igsd->buffer[igsd->buffer_size++] = (uint8_t) (i & 0xff); 756 | 757 | return 0; 758 | } 759 | /* }}} */ 760 | /* {{{ igbinary_serialize_null */ 761 | /** Serializes null. */ 762 | inline static int igbinary_serialize_null(struct igbinary_serialize_data *igsd TSRMLS_DC) { 763 | return igbinary_serialize8(igsd, igbinary_type_null TSRMLS_CC); 764 | } 765 | /* }}} */ 766 | /* {{{ igbinary_serialize_bool */ 767 | /** Serializes bool. */ 768 | inline static int igbinary_serialize_bool(struct igbinary_serialize_data *igsd, int b TSRMLS_DC) { 769 | return igbinary_serialize8(igsd, (uint8_t) (b ? igbinary_type_bool_true : igbinary_type_bool_false) TSRMLS_CC); 770 | } 771 | /* }}} */ 772 | /* {{{ igbinary_serialize_long */ 773 | /** Serializes long. */ 774 | inline static int igbinary_serialize_long(struct igbinary_serialize_data *igsd, long l TSRMLS_DC) { 775 | long k = l >= 0 ? l : -l; 776 | bool p = l >= 0 ? true : false; 777 | 778 | /* -LONG_MIN is 0 otherwise. */ 779 | if (l == LONG_MIN) { 780 | #if SIZEOF_LONG == 8 781 | if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_long64n TSRMLS_CC) != 0) { 782 | return 1; 783 | } 784 | 785 | if (igbinary_serialize64(igsd, (uint64_t) 0x8000000000000000 TSRMLS_CC) != 0) { 786 | return 1; 787 | } 788 | #elif SIZEOF_LONG == 4 789 | if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_long32n TSRMLS_CC) != 0) { 790 | return 1; 791 | } 792 | if (igbinary_serialize32(igsd, (uint32_t) 0x80000000 TSRMLS_CC) != 0) { 793 | return 1; 794 | } 795 | #else 796 | #error "Strange sizeof(long)." 797 | #endif 798 | return 0; 799 | } 800 | 801 | if (k <= 0xff) { 802 | if (igbinary_serialize8(igsd, (uint8_t) (p ? igbinary_type_long8p : igbinary_type_long8n) TSRMLS_CC) != 0) { 803 | return 1; 804 | } 805 | 806 | if (igbinary_serialize8(igsd, (uint8_t) k TSRMLS_CC) != 0) { 807 | return 1; 808 | } 809 | } else if (k <= 0xffff) { 810 | if (igbinary_serialize8(igsd, (uint8_t) (p ? igbinary_type_long16p : igbinary_type_long16n) TSRMLS_CC) != 0) { 811 | return 1; 812 | } 813 | 814 | if (igbinary_serialize16(igsd, (uint16_t) k TSRMLS_CC) != 0) { 815 | return 1; 816 | } 817 | #if SIZEOF_LONG == 8 818 | } else if (k <= 0xffffffff) { 819 | if (igbinary_serialize8(igsd, (uint8_t) (p ? igbinary_type_long32p : igbinary_type_long32n) TSRMLS_CC) != 0) { 820 | return 1; 821 | } 822 | 823 | if (igbinary_serialize32(igsd, (uint32_t) k TSRMLS_CC) != 0) { 824 | return 1; 825 | } 826 | } else { 827 | if (igbinary_serialize8(igsd, (uint8_t) (p ? igbinary_type_long64p : igbinary_type_long64n) TSRMLS_CC) != 0) { 828 | return 1; 829 | } 830 | if (igbinary_serialize64(igsd, (uint64_t) k TSRMLS_CC) != 0) { 831 | return 1; 832 | } 833 | } 834 | #elif SIZEOF_LONG == 4 835 | } else { 836 | if (igbinary_serialize8(igsd, (uint8_t) (p ? igbinary_type_long32p : igbinary_type_long32n) TSRMLS_CC) != 0) { 837 | return 1; 838 | } 839 | if (igbinary_serialize32(igsd, (uint32_t) k TSRMLS_CC) != 0) { 840 | return 1; 841 | } 842 | } 843 | #else 844 | #error "Strange sizeof(long)." 845 | #endif 846 | 847 | return 0; 848 | } 849 | /* }}} */ 850 | /* {{{ igbinary_serialize_double */ 851 | /** Serializes double. */ 852 | inline static int igbinary_serialize_double(struct igbinary_serialize_data *igsd, double d TSRMLS_DC) { 853 | union { 854 | double d; 855 | uint64_t u; 856 | } u; 857 | 858 | if (igbinary_serialize8(igsd, igbinary_type_double TSRMLS_CC) != 0) { 859 | return 1; 860 | } 861 | 862 | u.d = d; 863 | 864 | return igbinary_serialize64(igsd, u.u TSRMLS_CC); 865 | } 866 | /* }}} */ 867 | /* {{{ igbinary_serialize_string */ 868 | /** Serializes string. 869 | * Serializes each string once, after first time uses pointers. 870 | */ 871 | inline static int igbinary_serialize_string(struct igbinary_serialize_data *igsd, char *s, size_t len TSRMLS_DC) { 872 | uint32_t t; 873 | uint32_t *i = &t; 874 | 875 | if (len == 0) { 876 | if (igbinary_serialize8(igsd, igbinary_type_string_empty TSRMLS_CC) != 0) { 877 | return 1; 878 | } 879 | 880 | return 0; 881 | } 882 | 883 | if (igsd->scalar || !igsd->compact_strings || hash_si_find(&igsd->strings, s, len, i) == 1) { 884 | if (!igsd->scalar && igsd->compact_strings) { 885 | hash_si_insert(&igsd->strings, s, len, igsd->string_count); 886 | } 887 | 888 | igsd->string_count += 1; 889 | 890 | if (igbinary_serialize_chararray(igsd, s, len TSRMLS_CC) != 0) { 891 | return 1; 892 | } 893 | } else { 894 | if (*i <= 0xff) { 895 | if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_string_id8 TSRMLS_CC) != 0) { 896 | return 1; 897 | } 898 | 899 | if (igbinary_serialize8(igsd, (uint8_t) *i TSRMLS_CC) != 0) { 900 | return 1; 901 | } 902 | } else if (*i <= 0xffff) { 903 | if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_string_id16 TSRMLS_CC) != 0) { 904 | return 1; 905 | } 906 | 907 | if (igbinary_serialize16(igsd, (uint16_t) *i TSRMLS_CC) != 0) { 908 | return 1; 909 | } 910 | } else { 911 | if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_string_id32 TSRMLS_CC) != 0) { 912 | return 1; 913 | } 914 | 915 | if (igbinary_serialize32(igsd, (uint32_t) *i TSRMLS_CC) != 0) { 916 | return 1; 917 | } 918 | } 919 | } 920 | 921 | return 0; 922 | } 923 | /* }}} */ 924 | /* {{{ igbinary_serialize_chararray */ 925 | /** Serializes string data. */ 926 | inline static int igbinary_serialize_chararray(struct igbinary_serialize_data *igsd, const char *s, size_t len TSRMLS_DC) { 927 | if (len <= 0xff) { 928 | if (igbinary_serialize8(igsd, igbinary_type_string8 TSRMLS_CC) != 0) { 929 | return 1; 930 | } 931 | 932 | if (igbinary_serialize8(igsd, len TSRMLS_CC) != 0) { 933 | return 1; 934 | } 935 | } else if (len <= 0xffff) { 936 | if (igbinary_serialize8(igsd, igbinary_type_string16 TSRMLS_CC) != 0) { 937 | return 1; 938 | } 939 | 940 | if (igbinary_serialize16(igsd, len TSRMLS_CC) != 0) { 941 | return 1; 942 | } 943 | } else { 944 | if (igbinary_serialize8(igsd, igbinary_type_string32 TSRMLS_CC) != 0) { 945 | return 1; 946 | } 947 | 948 | if (igbinary_serialize32(igsd, len TSRMLS_CC) != 0) { 949 | return 1; 950 | } 951 | } 952 | 953 | if (igbinary_serialize_resize(igsd, len TSRMLS_CC)) { 954 | return 1; 955 | } 956 | 957 | memcpy(igsd->buffer+igsd->buffer_size, s, len); 958 | igsd->buffer_size += len; 959 | 960 | return 0; 961 | } 962 | /* }}} */ 963 | /* {{{ igbinay_serialize_array */ 964 | /** Serializes array or objects inner properties. */ 965 | inline static int igbinary_serialize_array(struct igbinary_serialize_data *igsd, zval *z, bool object, bool incomplete_class TSRMLS_DC) { 966 | HashTable *h; 967 | HashPosition pos; 968 | size_t n; 969 | zval **d; 970 | 971 | char *key; 972 | uint key_len; 973 | int key_type; 974 | ulong key_index; 975 | 976 | /* hash */ 977 | h = object ? Z_OBJPROP_P(z) : HASH_OF(z); 978 | 979 | /* hash size */ 980 | n = h ? zend_hash_num_elements(h) : 0; 981 | 982 | /* incomplete class magic member */ 983 | if (n > 0 && incomplete_class) { 984 | --n; 985 | } 986 | 987 | if (!object && igbinary_serialize_array_ref(igsd, z, object TSRMLS_CC) == 0) { 988 | return 0; 989 | } 990 | 991 | if (n <= 0xff) { 992 | if (igbinary_serialize8(igsd, igbinary_type_array8 TSRMLS_CC) != 0) { 993 | return 1; 994 | } 995 | 996 | if (igbinary_serialize8(igsd, n TSRMLS_CC) != 0) { 997 | return 1; 998 | } 999 | } else if (n <= 0xffff) { 1000 | if (igbinary_serialize8(igsd, igbinary_type_array16 TSRMLS_CC) != 0) { 1001 | return 1; 1002 | } 1003 | 1004 | if (igbinary_serialize16(igsd, n TSRMLS_CC) != 0) { 1005 | return 1; 1006 | } 1007 | } else { 1008 | if (igbinary_serialize8(igsd, igbinary_type_array32 TSRMLS_CC) != 0) { 1009 | return 1; 1010 | } 1011 | 1012 | if (igbinary_serialize32(igsd, n TSRMLS_CC) != 0) { 1013 | return 1; 1014 | } 1015 | } 1016 | 1017 | if (n == 0) { 1018 | return 0; 1019 | } 1020 | 1021 | /* serialize properties. */ 1022 | zend_hash_internal_pointer_reset_ex(h, &pos); 1023 | for (;; zend_hash_move_forward_ex(h, &pos)) { 1024 | key_type = zend_hash_get_current_key_ex(h, &key, &key_len, &key_index, 0, &pos); 1025 | 1026 | /* last */ 1027 | if (key_type == HASH_KEY_NON_EXISTANT) { 1028 | break; 1029 | } 1030 | 1031 | /* skip magic member in incomplete classes */ 1032 | if (incomplete_class && strcmp(key, MAGIC_MEMBER) == 0) { 1033 | continue; 1034 | } 1035 | 1036 | switch (key_type) { 1037 | case HASH_KEY_IS_LONG: 1038 | if (igbinary_serialize_long(igsd, key_index TSRMLS_CC) != 0) { 1039 | return 1; 1040 | } 1041 | break; 1042 | 1043 | case HASH_KEY_IS_STRING: 1044 | if (igbinary_serialize_string(igsd, key, key_len-1 TSRMLS_CC) != 0) { 1045 | return 1; 1046 | } 1047 | break; 1048 | 1049 | default: 1050 | zend_error(E_ERROR, "igbinary_serialize_array: key is not string nor array"); 1051 | /* not reached */ 1052 | return 1; 1053 | } 1054 | 1055 | /* we should still add element even if it's not OK, 1056 | * since we already wrote the length of the array before */ 1057 | if (zend_hash_get_current_data_ex(h, (void *) &d, &pos) != SUCCESS || d == NULL) { 1058 | if (igbinary_serialize_null(igsd TSRMLS_CC)) { 1059 | return 1; 1060 | } 1061 | } else { 1062 | if (igbinary_serialize_zval(igsd, *d TSRMLS_CC)) { 1063 | return 1; 1064 | } 1065 | } 1066 | } 1067 | 1068 | return 0; 1069 | } 1070 | /* }}} */ 1071 | /* {{{ igbinary_serialize_array_ref */ 1072 | /** Serializes array reference. */ 1073 | inline static int igbinary_serialize_array_ref(struct igbinary_serialize_data *igsd, zval *z, bool object TSRMLS_DC) { 1074 | uint32_t t = 0; 1075 | uint32_t *i = &t; 1076 | union { 1077 | zval *z; 1078 | struct { 1079 | zend_class_entry *ce; 1080 | zend_object_handle handle; 1081 | } obj; 1082 | } key = { 0 }; 1083 | 1084 | if (object && Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get_class_entry) { 1085 | key.obj.ce = Z_OBJCE_P(z); 1086 | key.obj.handle = Z_OBJ_HANDLE_P(z); 1087 | } else { 1088 | key.z = z; 1089 | } 1090 | 1091 | if (hash_si_find(&igsd->objects, (char *)&key, sizeof(key), i) == 1) { 1092 | t = hash_si_size(&igsd->objects); 1093 | hash_si_insert(&igsd->objects, (char *)&key, sizeof(key), t); 1094 | return 1; 1095 | } else { 1096 | enum igbinary_type type; 1097 | if (*i <= 0xff) { 1098 | type = object ? igbinary_type_objref8 : igbinary_type_ref8; 1099 | if (igbinary_serialize8(igsd, (uint8_t) type TSRMLS_CC) != 0) { 1100 | return 1; 1101 | } 1102 | 1103 | if (igbinary_serialize8(igsd, (uint8_t) *i TSRMLS_CC) != 0) { 1104 | return 1; 1105 | } 1106 | } else if (*i <= 0xffff) { 1107 | type = object ? igbinary_type_objref16 : igbinary_type_ref16; 1108 | if (igbinary_serialize8(igsd, (uint8_t) type TSRMLS_CC) != 0) { 1109 | return 1; 1110 | } 1111 | 1112 | if (igbinary_serialize16(igsd, (uint16_t) *i TSRMLS_CC) != 0) { 1113 | return 1; 1114 | } 1115 | } else { 1116 | type = object ? igbinary_type_objref32 : igbinary_type_ref32; 1117 | if (igbinary_serialize8(igsd, (uint8_t) type TSRMLS_CC) != 0) { 1118 | return 1; 1119 | } 1120 | 1121 | if (igbinary_serialize32(igsd, (uint32_t) *i TSRMLS_CC) != 0) { 1122 | return 1; 1123 | } 1124 | } 1125 | 1126 | return 0; 1127 | } 1128 | 1129 | return 1; 1130 | } 1131 | /* }}} */ 1132 | /* {{{ igbinary_serialize_array_sleep */ 1133 | /** Serializes object's properties array with __sleep -function. */ 1134 | inline static int igbinary_serialize_array_sleep(struct igbinary_serialize_data *igsd, zval *z, HashTable *h, zend_class_entry *ce, bool incomplete_class TSRMLS_DC) { 1135 | HashPosition pos; 1136 | size_t n = zend_hash_num_elements(h); 1137 | zval **d; 1138 | zval **v; 1139 | 1140 | char *key; 1141 | uint key_len; 1142 | int key_type; 1143 | ulong key_index; 1144 | 1145 | /* Decrease array size by one, because of magic member (with class name) */ 1146 | if (n > 0 && incomplete_class) { 1147 | --n; 1148 | } 1149 | 1150 | /* Serialize array id. */ 1151 | if (n <= 0xff) { 1152 | if (igbinary_serialize8(igsd, igbinary_type_array8 TSRMLS_CC) != 0) { 1153 | return 1; 1154 | } 1155 | 1156 | if (igbinary_serialize8(igsd, n TSRMLS_CC) != 0) { 1157 | return 1; 1158 | } 1159 | } else if (n <= 0xffff) { 1160 | if (igbinary_serialize8(igsd, igbinary_type_array16 TSRMLS_CC) != 0) { 1161 | return 1; 1162 | } 1163 | 1164 | if (igbinary_serialize16(igsd, n TSRMLS_CC) != 0) { 1165 | return 1; 1166 | } 1167 | } else { 1168 | if (igbinary_serialize8(igsd, igbinary_type_array32 TSRMLS_CC) != 0) { 1169 | return 1; 1170 | } 1171 | 1172 | if (igbinary_serialize32(igsd, n TSRMLS_CC) != 0) { 1173 | return 1; 1174 | } 1175 | } 1176 | 1177 | if (n == 0) { 1178 | return 0; 1179 | } 1180 | 1181 | zend_hash_internal_pointer_reset_ex(h, &pos); 1182 | 1183 | for (;; zend_hash_move_forward_ex(h, &pos)) { 1184 | key_type = zend_hash_get_current_key_ex(h, &key, &key_len, &key_index, 0, &pos); 1185 | 1186 | /* last */ 1187 | if (key_type == HASH_KEY_NON_EXISTANT) { 1188 | break; 1189 | } 1190 | 1191 | /* skip magic member in incomplete classes */ 1192 | if (incomplete_class && strcmp(key, MAGIC_MEMBER) == 0) { 1193 | continue; 1194 | } 1195 | 1196 | if (zend_hash_get_current_data_ex(h, (void *) &d, &pos) != SUCCESS || d == NULL || Z_TYPE_PP(d) != IS_STRING) { 1197 | php_error_docref(NULL TSRMLS_CC, E_NOTICE, "__sleep should return an array only " 1198 | "containing the names of instance-variables to " 1199 | "serialize"); 1200 | 1201 | /* we should still add element even if it's not OK, 1202 | * since we already wrote the length of the array before 1203 | * serialize null as key-value pair */ 1204 | if (igbinary_serialize_null(igsd TSRMLS_CC) != 0) { 1205 | return 1; 1206 | } 1207 | } else { 1208 | 1209 | if (zend_hash_find(Z_OBJPROP_P(z), Z_STRVAL_PP(d), Z_STRLEN_PP(d) + 1, (void *) &v) == SUCCESS) { 1210 | if (igbinary_serialize_string(igsd, Z_STRVAL_PP(d), Z_STRLEN_PP(d) TSRMLS_CC) != 0) { 1211 | return 1; 1212 | } 1213 | 1214 | if (igbinary_serialize_zval(igsd, *v TSRMLS_CC) != 0) { 1215 | return 1; 1216 | } 1217 | } else if (ce) { 1218 | char *prot_name = NULL; 1219 | char *priv_name = NULL; 1220 | int prop_name_length; 1221 | 1222 | do { 1223 | /* try private */ 1224 | zend_mangle_property_name(&priv_name, &prop_name_length, ce->name, ce->name_length, 1225 | Z_STRVAL_PP(d), Z_STRLEN_PP(d), ce->type & ZEND_INTERNAL_CLASS); 1226 | if (zend_hash_find(Z_OBJPROP_P(z), priv_name, prop_name_length+1, (void *) &v) == SUCCESS) { 1227 | if (igbinary_serialize_string(igsd, priv_name, prop_name_length TSRMLS_CC) != 0) { 1228 | efree(priv_name); 1229 | return 1; 1230 | } 1231 | 1232 | efree(priv_name); 1233 | if (igbinary_serialize_zval(igsd, *v TSRMLS_CC) != 0) { 1234 | return 1; 1235 | } 1236 | break; 1237 | } 1238 | efree(priv_name); 1239 | 1240 | /* try protected */ 1241 | zend_mangle_property_name(&prot_name, &prop_name_length, "*", 1, 1242 | Z_STRVAL_PP(d), Z_STRLEN_PP(d), ce->type & ZEND_INTERNAL_CLASS); 1243 | if (zend_hash_find(Z_OBJPROP_P(z), prot_name, prop_name_length+1, (void *) &v) == SUCCESS) { 1244 | if (igbinary_serialize_string(igsd, prot_name, prop_name_length TSRMLS_CC) != 0) { 1245 | efree(prot_name); 1246 | return 1; 1247 | } 1248 | 1249 | efree(prot_name); 1250 | if (igbinary_serialize_zval(igsd, *v TSRMLS_CC) != 0) { 1251 | return 1; 1252 | } 1253 | break; 1254 | } 1255 | efree(prot_name); 1256 | 1257 | /* no win */ 1258 | php_error_docref(NULL TSRMLS_CC, E_NOTICE, "\"%s\" returned as member variable from __sleep() but does not exist", Z_STRVAL_PP(d)); 1259 | if (igbinary_serialize_string(igsd, Z_STRVAL_PP(d), Z_STRLEN_PP(d) TSRMLS_CC) != 0) { 1260 | return 1; 1261 | } 1262 | 1263 | if (igbinary_serialize_null(igsd TSRMLS_CC) != 0) { 1264 | return 1; 1265 | } 1266 | } while (0); 1267 | 1268 | } else { 1269 | // if all else fails, just serialize the value in anyway. 1270 | if (igbinary_serialize_string(igsd, Z_STRVAL_PP(d), Z_STRLEN_PP(d) TSRMLS_CC) != 0) { 1271 | return 1; 1272 | } 1273 | 1274 | if (igbinary_serialize_zval(igsd, *v TSRMLS_CC) != 0) { 1275 | return 1; 1276 | } 1277 | } 1278 | } 1279 | } 1280 | 1281 | return 0; 1282 | } 1283 | /* }}} */ 1284 | /* {{{ igbinary_serialize_object_name */ 1285 | /** Serialize object name. */ 1286 | inline static int igbinary_serialize_object_name(struct igbinary_serialize_data *igsd, const char *class_name, size_t name_len TSRMLS_DC) { 1287 | uint32_t t; 1288 | uint32_t *i = &t; 1289 | 1290 | if (hash_si_find(&igsd->strings, class_name, name_len, i) == 1) { 1291 | hash_si_insert(&igsd->strings, class_name, name_len, igsd->string_count); 1292 | igsd->string_count += 1; 1293 | 1294 | if (name_len <= 0xff) { 1295 | if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object8 TSRMLS_CC) != 0) { 1296 | return 1; 1297 | } 1298 | 1299 | if (igbinary_serialize8(igsd, (uint8_t) name_len TSRMLS_CC) != 0) { 1300 | return 1; 1301 | } 1302 | } else if (name_len <= 0xffff) { 1303 | if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object16 TSRMLS_CC) != 0) { 1304 | return 1; 1305 | } 1306 | 1307 | if (igbinary_serialize16(igsd, (uint16_t) name_len TSRMLS_CC) != 0) { 1308 | return 1; 1309 | } 1310 | } else { 1311 | if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object32 TSRMLS_CC) != 0) { 1312 | return 1; 1313 | } 1314 | 1315 | if (igbinary_serialize32(igsd, (uint32_t) name_len TSRMLS_CC) != 0) { 1316 | return 1; 1317 | } 1318 | } 1319 | 1320 | if (igbinary_serialize_resize(igsd, name_len TSRMLS_CC)) { 1321 | return 1; 1322 | } 1323 | 1324 | memcpy(igsd->buffer+igsd->buffer_size, class_name, name_len); 1325 | igsd->buffer_size += name_len; 1326 | } else { 1327 | /* already serialized string */ 1328 | if (*i <= 0xff) { 1329 | if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object_id8 TSRMLS_CC) != 0) { 1330 | return 1; 1331 | } 1332 | 1333 | if (igbinary_serialize8(igsd, (uint8_t) *i TSRMLS_CC) != 0) { 1334 | return 1; 1335 | } 1336 | } else if (*i <= 0xffff) { 1337 | if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object_id16 TSRMLS_CC) != 0) { 1338 | return 1; 1339 | } 1340 | 1341 | if (igbinary_serialize16(igsd, (uint16_t) *i TSRMLS_CC) != 0) { 1342 | return 1; 1343 | } 1344 | } else { 1345 | if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object_id32 TSRMLS_CC) != 0) { 1346 | return 1; 1347 | } 1348 | 1349 | if (igbinary_serialize32(igsd, (uint32_t) *i TSRMLS_CC) != 0) { 1350 | return 1; 1351 | } 1352 | } 1353 | } 1354 | 1355 | return 0; 1356 | } 1357 | /* }}} */ 1358 | /* {{{ igbinary_serialize_object */ 1359 | /** Serialize object. 1360 | * @see ext/standard/var.c 1361 | * */ 1362 | inline static int igbinary_serialize_object(struct igbinary_serialize_data *igsd, zval *z TSRMLS_DC) { 1363 | zend_class_entry *ce; 1364 | 1365 | zval f; 1366 | zval *h = NULL; 1367 | 1368 | int r = 0; 1369 | 1370 | unsigned char *serialized_data = NULL; 1371 | zend_uint serialized_len; 1372 | 1373 | PHP_CLASS_ATTRIBUTES; 1374 | 1375 | if (igbinary_serialize_array_ref(igsd, z, true TSRMLS_CC) == 0) { 1376 | return r; 1377 | } 1378 | 1379 | ce = Z_OBJCE_P(z); 1380 | 1381 | /* custom serializer */ 1382 | if (ce && ce->serialize != NULL) { 1383 | if (ce->serialize(z, &serialized_data, &serialized_len, (zend_serialize_data *)NULL TSRMLS_CC) == SUCCESS && !EG(exception)) { 1384 | if (igbinary_serialize_object_name(igsd, ce->name, ce->name_length TSRMLS_CC) != 0) { 1385 | if (serialized_data) { 1386 | efree(serialized_data); 1387 | } 1388 | return 1; 1389 | } 1390 | 1391 | 1392 | if (serialized_len <= 0xff) { 1393 | if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object_ser8 TSRMLS_CC) != 0) { 1394 | if (serialized_data) { 1395 | efree(serialized_data); 1396 | } 1397 | return 1; 1398 | } 1399 | 1400 | if (igbinary_serialize8(igsd, (uint8_t) serialized_len TSRMLS_CC) != 0) { 1401 | if (serialized_data) { 1402 | efree(serialized_data); 1403 | } 1404 | return 1; 1405 | } 1406 | } else if (serialized_len <= 0xffff) { 1407 | if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object_ser16 TSRMLS_CC) != 0) { 1408 | if (serialized_data) { 1409 | efree(serialized_data); 1410 | } 1411 | return 1; 1412 | } 1413 | 1414 | if (igbinary_serialize16(igsd, (uint16_t) serialized_len TSRMLS_CC) != 0) { 1415 | if (serialized_data) { 1416 | efree(serialized_data); 1417 | } 1418 | return 1; 1419 | } 1420 | } else { 1421 | if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object_ser32 TSRMLS_CC) != 0) { 1422 | if (serialized_data) { 1423 | efree(serialized_data); 1424 | } 1425 | return 1; 1426 | } 1427 | 1428 | if (igbinary_serialize32(igsd, (uint32_t) serialized_len TSRMLS_CC) != 0) { 1429 | if (serialized_data) { 1430 | efree(serialized_data); 1431 | } 1432 | return 1; 1433 | } 1434 | } 1435 | 1436 | if (igbinary_serialize_resize(igsd, serialized_len TSRMLS_CC)) { 1437 | if (serialized_data) { 1438 | efree(serialized_data); 1439 | } 1440 | 1441 | return 1; 1442 | } 1443 | 1444 | memcpy(igsd->buffer+igsd->buffer_size, serialized_data, serialized_len); 1445 | igsd->buffer_size += serialized_len; 1446 | } else if (EG(exception)) { 1447 | /* exception, return failure */ 1448 | r = 1; 1449 | } else { 1450 | /* Serialization callback failed, assume null output */ 1451 | r = igbinary_serialize_null(igsd TSRMLS_CC); 1452 | } 1453 | 1454 | if (serialized_data) { 1455 | efree(serialized_data); 1456 | } 1457 | 1458 | return r; 1459 | } 1460 | 1461 | /* serialize class name */ 1462 | PHP_SET_CLASS_ATTRIBUTES(z); 1463 | if (igbinary_serialize_object_name(igsd, class_name, name_len TSRMLS_CC) != 0) { 1464 | PHP_CLEANUP_CLASS_ATTRIBUTES(); 1465 | return 1; 1466 | } 1467 | PHP_CLEANUP_CLASS_ATTRIBUTES(); 1468 | 1469 | if (ce && ce != PHP_IC_ENTRY && zend_hash_exists(&ce->function_table, "__sleep", sizeof("__sleep"))) { 1470 | /* function name string */ 1471 | INIT_PZVAL(&f); 1472 | ZVAL_STRINGL(&f, "__sleep", sizeof("__sleep") - 1, 0); 1473 | 1474 | /* calling z->__sleep */ 1475 | r = call_user_function_ex(CG(function_table), &z, &f, &h, 0, 0, 1, NULL TSRMLS_CC); 1476 | 1477 | if (r == SUCCESS && !EG(exception)) { 1478 | r = 0; 1479 | 1480 | if (h) { 1481 | if (Z_TYPE_P(h) == IS_ARRAY) { 1482 | r = igbinary_serialize_array_sleep(igsd, z, HASH_OF(h), ce, incomplete_class TSRMLS_CC); 1483 | } else { 1484 | php_error_docref(NULL TSRMLS_CC, E_NOTICE, "__sleep should return an array only " 1485 | "containing the names of instance-variables to " 1486 | "serialize"); 1487 | 1488 | /* empty array */ 1489 | r = igbinary_serialize8(igsd, igbinary_type_array8 TSRMLS_CC); 1490 | if (r == 0) { 1491 | r = igbinary_serialize8(igsd, 0 TSRMLS_CC); 1492 | } 1493 | } 1494 | } 1495 | } else { 1496 | r = 1; 1497 | } 1498 | 1499 | /* cleanup */ 1500 | if (h) { 1501 | zval_ptr_dtor(&h); 1502 | } 1503 | 1504 | return r; 1505 | } else { 1506 | return igbinary_serialize_array(igsd, z, true, incomplete_class TSRMLS_CC); 1507 | } 1508 | } 1509 | /* }}} */ 1510 | /* {{{ igbinary_serialize_zval */ 1511 | /** Serialize zval. */ 1512 | static int igbinary_serialize_zval(struct igbinary_serialize_data *igsd, zval *z TSRMLS_DC) { 1513 | if (Z_ISREF_P(z)) { 1514 | if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_ref TSRMLS_CC) != 0) { 1515 | return 1; 1516 | } 1517 | 1518 | /* Complex types serialize a reference, scalars do not... */ 1519 | /* FIXME: Absolutely wrong level to check this. */ 1520 | switch (Z_TYPE_P(z)) { 1521 | case IS_RESOURCE: 1522 | case IS_STRING: 1523 | case IS_LONG: 1524 | case IS_NULL: 1525 | case IS_BOOL: 1526 | case IS_DOUBLE: 1527 | /* Serialize a reference if zval already added */ 1528 | if (igbinary_serialize_array_ref(igsd, z, false TSRMLS_CC) == 0) { 1529 | return 0; 1530 | } 1531 | /* otherwise fall through */ 1532 | } 1533 | } 1534 | switch (Z_TYPE_P(z)) { 1535 | case IS_RESOURCE: 1536 | return igbinary_serialize_null(igsd TSRMLS_CC); 1537 | case IS_OBJECT: 1538 | return igbinary_serialize_object(igsd, z TSRMLS_CC); 1539 | case IS_ARRAY: 1540 | return igbinary_serialize_array(igsd, z, false, false TSRMLS_CC); 1541 | case IS_STRING: 1542 | return igbinary_serialize_string(igsd, Z_STRVAL_P(z), Z_STRLEN_P(z) TSRMLS_CC); 1543 | case IS_LONG: 1544 | return igbinary_serialize_long(igsd, Z_LVAL_P(z) TSRMLS_CC); 1545 | case IS_NULL: 1546 | return igbinary_serialize_null(igsd TSRMLS_CC); 1547 | case IS_BOOL: 1548 | return igbinary_serialize_bool(igsd, Z_LVAL_P(z) ? 1 : 0 TSRMLS_CC); 1549 | case IS_DOUBLE: 1550 | return igbinary_serialize_double(igsd, Z_DVAL_P(z) TSRMLS_CC); 1551 | default: 1552 | zend_error(E_ERROR, "igbinary_serialize_zval: zval has unknown type %d", (int)Z_TYPE_P(z)); 1553 | /* not reached */ 1554 | return 1; 1555 | } 1556 | 1557 | return 0; 1558 | } 1559 | /* }}} */ 1560 | /* {{{ igbinary_unserialize_data_init */ 1561 | /** Inits igbinary_unserialize_data_init. */ 1562 | inline static int igbinary_unserialize_data_init(struct igbinary_unserialize_data *igsd TSRMLS_DC) { 1563 | smart_str empty_str = { 0 }; 1564 | 1565 | igsd->buffer = NULL; 1566 | igsd->buffer_size = 0; 1567 | igsd->buffer_offset = 0; 1568 | 1569 | igsd->strings = NULL; 1570 | igsd->strings_count = 0; 1571 | igsd->strings_capacity = 4; 1572 | igsd->string0_buf = empty_str; 1573 | 1574 | igsd->error = 0; 1575 | igsd->references = NULL; 1576 | igsd->references_count = 0; 1577 | igsd->references_capacity = 4; 1578 | 1579 | igsd->references = (void **) emalloc(sizeof(void *) * igsd->references_capacity); 1580 | if (igsd->references == NULL) { 1581 | return 1; 1582 | } 1583 | 1584 | igsd->strings = (struct igbinary_unserialize_string_pair *) emalloc(sizeof(struct igbinary_unserialize_string_pair) * igsd->strings_capacity); 1585 | if (igsd->strings == NULL) { 1586 | efree(igsd->references); 1587 | return 1; 1588 | } 1589 | 1590 | return 0; 1591 | } 1592 | /* }}} */ 1593 | /* {{{ igbinary_unserialize_data_deinit */ 1594 | /** Deinits igbinary_unserialize_data_init. */ 1595 | inline static void igbinary_unserialize_data_deinit(struct igbinary_unserialize_data *igsd TSRMLS_DC) { 1596 | if (igsd->strings) { 1597 | efree(igsd->strings); 1598 | } 1599 | 1600 | if (igsd->references) { 1601 | efree(igsd->references); 1602 | } 1603 | 1604 | smart_str_free(&igsd->string0_buf); 1605 | 1606 | return; 1607 | } 1608 | /* }}} */ 1609 | /* {{{ igbinary_unserialize_header */ 1610 | /** Unserialize header. Check for version. */ 1611 | inline static int igbinary_unserialize_header(struct igbinary_unserialize_data *igsd TSRMLS_DC) { 1612 | uint32_t version; 1613 | 1614 | if (igsd->buffer_offset + 4 >= igsd->buffer_size) { 1615 | return 1; 1616 | } 1617 | 1618 | version = igbinary_unserialize32(igsd TSRMLS_CC); 1619 | 1620 | /* Support older version 1 and the current format 2 */ 1621 | if (version == IGBINARY_FORMAT_VERSION || version == 0x00000001) { 1622 | return 0; 1623 | } else { 1624 | zend_error(E_WARNING, "igbinary_unserialize_header: unsupported version: %u, should be %u or %u", (unsigned int) version, 0x00000001, (unsigned int) IGBINARY_FORMAT_VERSION); 1625 | return 1; 1626 | } 1627 | } 1628 | /* }}} */ 1629 | /* {{{ igbinary_unserialize8 */ 1630 | /** Unserialize 8bit value. */ 1631 | inline static uint8_t igbinary_unserialize8(struct igbinary_unserialize_data *igsd TSRMLS_DC) { 1632 | uint8_t ret = 0; 1633 | ret = igsd->buffer[igsd->buffer_offset++]; 1634 | return ret; 1635 | } 1636 | /* }}} */ 1637 | /* {{{ igbinary_unserialize16 */ 1638 | /** Unserialize 16bit value. */ 1639 | inline static uint16_t igbinary_unserialize16(struct igbinary_unserialize_data *igsd TSRMLS_DC) { 1640 | uint16_t ret = 0; 1641 | ret |= ((uint16_t) igsd->buffer[igsd->buffer_offset++] << 8); 1642 | ret |= ((uint16_t) igsd->buffer[igsd->buffer_offset++] << 0); 1643 | return ret; 1644 | } 1645 | /* }}} */ 1646 | /* {{{ igbinary_unserialize32 */ 1647 | /** Unserialize 32bit value. */ 1648 | inline static uint32_t igbinary_unserialize32(struct igbinary_unserialize_data *igsd TSRMLS_DC) { 1649 | uint32_t ret = 0; 1650 | ret |= ((uint32_t) igsd->buffer[igsd->buffer_offset++] << 24); 1651 | ret |= ((uint32_t) igsd->buffer[igsd->buffer_offset++] << 16); 1652 | ret |= ((uint32_t) igsd->buffer[igsd->buffer_offset++] << 8); 1653 | ret |= ((uint32_t) igsd->buffer[igsd->buffer_offset++] << 0); 1654 | return ret; 1655 | } 1656 | /* }}} */ 1657 | /* {{{ igbinary_unserialize64 */ 1658 | /** Unserialize 64bit value. */ 1659 | inline static uint64_t igbinary_unserialize64(struct igbinary_unserialize_data *igsd TSRMLS_DC) { 1660 | uint64_t ret = 0; 1661 | ret |= ((uint64_t) igsd->buffer[igsd->buffer_offset++] << 56); 1662 | ret |= ((uint64_t) igsd->buffer[igsd->buffer_offset++] << 48); 1663 | ret |= ((uint64_t) igsd->buffer[igsd->buffer_offset++] << 40); 1664 | ret |= ((uint64_t) igsd->buffer[igsd->buffer_offset++] << 32); 1665 | ret |= ((uint64_t) igsd->buffer[igsd->buffer_offset++] << 24); 1666 | ret |= ((uint64_t) igsd->buffer[igsd->buffer_offset++] << 16); 1667 | ret |= ((uint64_t) igsd->buffer[igsd->buffer_offset++] << 8); 1668 | ret |= ((uint64_t) igsd->buffer[igsd->buffer_offset++] << 0); 1669 | return ret; 1670 | } 1671 | /* }}} */ 1672 | /* {{{ igbinary_unserialize_long */ 1673 | /** Unserializes long */ 1674 | inline static int igbinary_unserialize_long(struct igbinary_unserialize_data *igsd, enum igbinary_type t, long *ret TSRMLS_DC) { 1675 | uint32_t tmp32; 1676 | #if SIZEOF_LONG == 8 1677 | uint64_t tmp64; 1678 | #endif 1679 | 1680 | if (t == igbinary_type_long8p || t == igbinary_type_long8n) { 1681 | if (igsd->buffer_offset + 1 > igsd->buffer_size) { 1682 | zend_error(E_WARNING, "igbinary_unserialize_long: end-of-data"); 1683 | return 1; 1684 | } 1685 | 1686 | *ret = (long) (t == igbinary_type_long8n ? -1 : 1) * igbinary_unserialize8(igsd TSRMLS_CC); 1687 | } else if (t == igbinary_type_long16p || t == igbinary_type_long16n) { 1688 | if (igsd->buffer_offset + 2 > igsd->buffer_size) { 1689 | zend_error(E_WARNING, "igbinary_unserialize_long: end-of-data"); 1690 | return 1; 1691 | } 1692 | 1693 | *ret = (long) (t == igbinary_type_long16n ? -1 : 1) * igbinary_unserialize16(igsd TSRMLS_CC); 1694 | } else if (t == igbinary_type_long32p || t == igbinary_type_long32n) { 1695 | if (igsd->buffer_offset + 4 > igsd->buffer_size) { 1696 | zend_error(E_WARNING, "igbinary_unserialize_long: end-of-data"); 1697 | return 1; 1698 | } 1699 | 1700 | /* check for boundaries */ 1701 | tmp32 = igbinary_unserialize32(igsd TSRMLS_CC); 1702 | #if SIZEOF_LONG == 4 1703 | if (tmp32 > 0x80000000 || (tmp32 == 0x80000000 && t == igbinary_type_long32p)) { 1704 | zend_error(E_WARNING, "igbinary_unserialize_long: 64bit long on 32bit platform?"); 1705 | tmp32 = 0; /* t == igbinary_type_long32p ? LONG_MAX : LONG_MIN; */ 1706 | } 1707 | #endif 1708 | *ret = (long) (t == igbinary_type_long32n ? -1 : 1) * tmp32; 1709 | } else if (t == igbinary_type_long64p || t == igbinary_type_long64n) { 1710 | #if SIZEOF_LONG == 8 1711 | if (igsd->buffer_offset + 8 > igsd->buffer_size) { 1712 | zend_error(E_WARNING, "igbinary_unserialize_long: end-of-data"); 1713 | return 1; 1714 | } 1715 | 1716 | /* check for boundaries */ 1717 | tmp64 = igbinary_unserialize64(igsd TSRMLS_CC); 1718 | if (tmp64 > 0x8000000000000000 || (tmp64 == 0x8000000000000000 && t == igbinary_type_long64p)) { 1719 | zend_error(E_WARNING, "igbinary_unserialize_long: too big 64bit long."); 1720 | tmp64 = 0; /* t == igbinary_type_long64p ? LONG_MAX : LONG_MIN */; 1721 | } 1722 | 1723 | *ret = (long) (t == igbinary_type_long64n ? -1 : 1) * tmp64; 1724 | #elif SIZEOF_LONG == 4 1725 | /* can't put 64bit long into 32bit one, placeholder zero */ 1726 | *ret = 0; 1727 | igbinary_unserialize64(igsd TSRMLS_CC); 1728 | zend_error(E_WARNING, "igbinary_unserialize_long: 64bit long on 32bit platform"); 1729 | #else 1730 | #error "Strange sizeof(long)." 1731 | #endif 1732 | } else { 1733 | *ret = 0; 1734 | zend_error(E_WARNING, "igbinary_unserialize_long: unknown type '%02x', position %zu", t, igsd->buffer_offset); 1735 | return 1; 1736 | } 1737 | 1738 | return 0; 1739 | } 1740 | /* }}} */ 1741 | /* {{{ igbinary_unserialize_double */ 1742 | /** Unserializes double. */ 1743 | inline static int igbinary_unserialize_double(struct igbinary_unserialize_data *igsd, enum igbinary_type t, double *ret TSRMLS_DC) { 1744 | union { 1745 | double d; 1746 | uint64_t u; 1747 | } u; 1748 | 1749 | (void) t; 1750 | 1751 | if (igsd->buffer_offset + 8 > igsd->buffer_size) { 1752 | zend_error(E_WARNING, "igbinary_unserialize_double: end-of-data"); 1753 | return 1; 1754 | } 1755 | 1756 | 1757 | u.u = igbinary_unserialize64(igsd TSRMLS_CC); 1758 | 1759 | *ret = u.d; 1760 | 1761 | return 0; 1762 | } 1763 | /* }}} */ 1764 | /* {{{ igbinary_unserialize_string */ 1765 | /** Unserializes string. Unserializes both actual string or by string id. */ 1766 | inline static int igbinary_unserialize_string(struct igbinary_unserialize_data *igsd, enum igbinary_type t, char **s, size_t *len TSRMLS_DC) { 1767 | size_t i; 1768 | if (t == igbinary_type_string_id8 || t == igbinary_type_object_id8) { 1769 | if (igsd->buffer_offset + 1 > igsd->buffer_size) { 1770 | zend_error(E_WARNING, "igbinary_unserialize_string: end-of-data"); 1771 | return 1; 1772 | } 1773 | i = igbinary_unserialize8(igsd TSRMLS_CC); 1774 | } else if (t == igbinary_type_string_id16 || t == igbinary_type_object_id16) { 1775 | if (igsd->buffer_offset + 2 > igsd->buffer_size) { 1776 | zend_error(E_WARNING, "igbinary_unserialize_string: end-of-data"); 1777 | return 1; 1778 | } 1779 | i = igbinary_unserialize16(igsd TSRMLS_CC); 1780 | } else if (t == igbinary_type_string_id32 || t == igbinary_type_object_id32) { 1781 | if (igsd->buffer_offset + 4 > igsd->buffer_size) { 1782 | zend_error(E_WARNING, "igbinary_unserialize_string: end-of-data"); 1783 | return 1; 1784 | } 1785 | i = igbinary_unserialize32(igsd TSRMLS_CC); 1786 | } else { 1787 | zend_error(E_WARNING, "igbinary_unserialize_string: unknown type '%02x', position %zu", t, igsd->buffer_offset); 1788 | return 1; 1789 | } 1790 | 1791 | if (i >= igsd->strings_count) { 1792 | zend_error(E_WARNING, "igbinary_unserialize_string: string index is out-of-bounds"); 1793 | return 1; 1794 | } 1795 | 1796 | *s = igsd->strings[i].data; 1797 | *len = igsd->strings[i].len; 1798 | 1799 | return 0; 1800 | } 1801 | /* }}} */ 1802 | /* {{{ igbinary_unserialize_chararray */ 1803 | /** Unserializes chararray of string. */ 1804 | inline static int igbinary_unserialize_chararray(struct igbinary_unserialize_data *igsd, enum igbinary_type t, char **s, size_t *len TSRMLS_DC) { 1805 | size_t l; 1806 | 1807 | if (t == igbinary_type_string8 || t == igbinary_type_object8) { 1808 | if (igsd->buffer_offset + 1 > igsd->buffer_size) { 1809 | zend_error(E_WARNING, "igbinary_unserialize_chararray: end-of-data"); 1810 | return 1; 1811 | } 1812 | l = igbinary_unserialize8(igsd TSRMLS_CC); 1813 | if (igsd->buffer_offset + l > igsd->buffer_size) { 1814 | zend_error(E_WARNING, "igbinary_unserialize_chararray: end-of-data"); 1815 | return 1; 1816 | } 1817 | } else if (t == igbinary_type_string16 || t == igbinary_type_object16) { 1818 | if (igsd->buffer_offset + 2 > igsd->buffer_size) { 1819 | zend_error(E_WARNING, "igbinary_unserialize_chararray: end-of-data"); 1820 | return 1; 1821 | } 1822 | l = igbinary_unserialize16(igsd TSRMLS_CC); 1823 | if (igsd->buffer_offset + l > igsd->buffer_size) { 1824 | zend_error(E_WARNING, "igbinary_unserialize_chararray: end-of-data"); 1825 | return 1; 1826 | } 1827 | } else if (t == igbinary_type_string32 || t == igbinary_type_object32) { 1828 | if (igsd->buffer_offset + 4 > igsd->buffer_size) { 1829 | zend_error(E_WARNING, "igbinary_unserialize_chararray: end-of-data"); 1830 | return 1; 1831 | } 1832 | l = igbinary_unserialize32(igsd TSRMLS_CC); 1833 | if (igsd->buffer_offset + l > igsd->buffer_size) { 1834 | zend_error(E_WARNING, "igbinary_unserialize_chararray: end-of-data"); 1835 | return 1; 1836 | } 1837 | } else { 1838 | zend_error(E_WARNING, "igbinary_unserialize_chararray: unknown type '%02x', position %zu", t, igsd->buffer_offset); 1839 | return 1; 1840 | } 1841 | 1842 | if (igsd->strings_count + 1 > igsd->strings_capacity) { 1843 | while (igsd->strings_count + 1 > igsd->strings_capacity) { 1844 | igsd->strings_capacity *= 2; 1845 | } 1846 | 1847 | igsd->strings = (struct igbinary_unserialize_string_pair *) erealloc(igsd->strings, sizeof(struct igbinary_unserialize_string_pair) * igsd->strings_capacity); 1848 | if (igsd->strings == NULL) { 1849 | return 1; 1850 | } 1851 | } 1852 | 1853 | igsd->strings[igsd->strings_count].data = (char *) (igsd->buffer + igsd->buffer_offset); 1854 | igsd->strings[igsd->strings_count].len = l; 1855 | 1856 | igsd->buffer_offset += l; 1857 | 1858 | if (igsd->strings[igsd->strings_count].data == NULL) { 1859 | return 1; 1860 | } 1861 | 1862 | *len = igsd->strings[igsd->strings_count].len; 1863 | *s = igsd->strings[igsd->strings_count].data; 1864 | 1865 | igsd->strings_count += 1; 1866 | 1867 | return 0; 1868 | } 1869 | /* }}} */ 1870 | /* {{{ igbinary_unserialize_array */ 1871 | /** Unserializes array. */ 1872 | inline static int igbinary_unserialize_array(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval **z, int object TSRMLS_DC) { 1873 | size_t n; 1874 | size_t i; 1875 | 1876 | zval *v = NULL; 1877 | /* zval *old_v; */ 1878 | 1879 | char *key; 1880 | size_t key_len = 0; 1881 | long key_index = 0; 1882 | 1883 | enum igbinary_type key_type; 1884 | 1885 | HashTable *h; 1886 | 1887 | if (t == igbinary_type_array8) { 1888 | if (igsd->buffer_offset + 1 > igsd->buffer_size) { 1889 | zend_error(E_WARNING, "igbinary_unserialize_array: end-of-data"); 1890 | return 1; 1891 | } 1892 | n = igbinary_unserialize8(igsd TSRMLS_CC); 1893 | } else if (t == igbinary_type_array16) { 1894 | if (igsd->buffer_offset + 2 > igsd->buffer_size) { 1895 | zend_error(E_WARNING, "igbinary_unserialize_array: end-of-data"); 1896 | return 1; 1897 | } 1898 | n = igbinary_unserialize16(igsd TSRMLS_CC); 1899 | } else if (t == igbinary_type_array32) { 1900 | if (igsd->buffer_offset + 4 > igsd->buffer_size) { 1901 | zend_error(E_WARNING, "igbinary_unserialize_array: end-of-data"); 1902 | return 1; 1903 | } 1904 | n = igbinary_unserialize32(igsd TSRMLS_CC); 1905 | } else { 1906 | zend_error(E_WARNING, "igbinary_unserialize_array: unknown type '%02x', position %zu", t, igsd->buffer_offset); 1907 | return 1; 1908 | } 1909 | 1910 | // n cannot be larger than the number of minimum "objects" in the array 1911 | if (n > igsd->buffer_size - igsd->buffer_offset) { 1912 | zend_error(E_WARNING, "%s: data size %zu smaller that requested array length %zu.", "igbinary_unserialize_array", igsd->buffer_size - igsd->buffer_offset, n); 1913 | return 1; 1914 | } 1915 | 1916 | if (!object) { 1917 | Z_TYPE_PP(z) = IS_ARRAY; 1918 | ALLOC_HASHTABLE(Z_ARRVAL_PP(z)); 1919 | zend_hash_init(Z_ARRVAL_PP(z), n + 1, NULL, ZVAL_PTR_DTOR, 0); 1920 | 1921 | /* references */ 1922 | if (igsd->references_count + 1 >= igsd->references_capacity) { 1923 | while (igsd->references_count + 1 >= igsd->references_capacity) { 1924 | igsd->references_capacity *= 2; 1925 | } 1926 | 1927 | igsd->references = (void **) erealloc(igsd->references, sizeof(void *) * igsd->references_capacity); 1928 | if (igsd->references == NULL) 1929 | return 1; 1930 | } 1931 | 1932 | igsd->references[igsd->references_count++] = (void *) *z; 1933 | } 1934 | 1935 | /* empty array */ 1936 | if (n == 0) { 1937 | return 0; 1938 | } 1939 | 1940 | h = HASH_OF(*z); 1941 | 1942 | for (i = 0; i < n; i++) { 1943 | key = NULL; 1944 | 1945 | if (igsd->buffer_offset + 1 > igsd->buffer_size) { 1946 | zend_error(E_WARNING, "igbinary_unserialize_array: end-of-data"); 1947 | zval_dtor(*z); 1948 | ZVAL_NULL(*z); 1949 | return 1; 1950 | } 1951 | 1952 | key_type = (enum igbinary_type) igbinary_unserialize8(igsd TSRMLS_CC); 1953 | 1954 | switch (key_type) { 1955 | case igbinary_type_long8p: 1956 | case igbinary_type_long8n: 1957 | case igbinary_type_long16p: 1958 | case igbinary_type_long16n: 1959 | case igbinary_type_long32p: 1960 | case igbinary_type_long32n: 1961 | case igbinary_type_long64p: 1962 | case igbinary_type_long64n: 1963 | if (igbinary_unserialize_long(igsd, key_type, &key_index TSRMLS_CC)) { 1964 | zval_dtor(*z); 1965 | ZVAL_NULL(*z); 1966 | return 1; 1967 | } 1968 | break; 1969 | case igbinary_type_string_id8: 1970 | case igbinary_type_string_id16: 1971 | case igbinary_type_string_id32: 1972 | if (igbinary_unserialize_string(igsd, key_type, &key, &key_len TSRMLS_CC)) { 1973 | zval_dtor(*z); 1974 | ZVAL_NULL(*z); 1975 | return 1; 1976 | } 1977 | break; 1978 | case igbinary_type_string8: 1979 | case igbinary_type_string16: 1980 | case igbinary_type_string32: 1981 | if (igbinary_unserialize_chararray(igsd, key_type, &key, &key_len TSRMLS_CC)) { 1982 | zval_dtor(*z); 1983 | ZVAL_NULL(*z); 1984 | return 1; 1985 | } 1986 | break; 1987 | case igbinary_type_string_empty: 1988 | key = ""; 1989 | key_len = 0; 1990 | break; 1991 | case igbinary_type_null: 1992 | continue; 1993 | default: 1994 | zend_error(E_WARNING, "igbinary_unserialize_array: unknown key type '%02x', position %zu", key_type, igsd->buffer_offset); 1995 | zval_dtor(*z); 1996 | ZVAL_NULL(*z); 1997 | return 1; 1998 | } 1999 | 2000 | 2001 | ALLOC_INIT_ZVAL(v); 2002 | if (igbinary_unserialize_zval(igsd, &v TSRMLS_CC)) { 2003 | zval_dtor(*z); 2004 | ZVAL_NULL(*z); 2005 | zval_ptr_dtor(&v); 2006 | return 1; 2007 | } 2008 | 2009 | if (key) { 2010 | /* Keys must include a terminating null. */ 2011 | /* Ensure buffer starts at the beginning. */ 2012 | igsd->string0_buf.len = 0; 2013 | smart_str_appendl(&igsd->string0_buf, key, key_len); 2014 | smart_str_0(&igsd->string0_buf); 2015 | /* 2016 | if (zend_symtable_find(h, key, key_len + 1, (void **)&old_v) == SUCCESS) { 2017 | var_push_dtor(var_hash, old_v); 2018 | } 2019 | */ 2020 | zend_symtable_update(h, igsd->string0_buf.c, igsd->string0_buf.len + 1, &v, sizeof(v), NULL); 2021 | } else { 2022 | /* 2023 | if (zend_hash_index_find(h, key_index, (void **)&old_v) == SUCCESS) { 2024 | var_push_dtor(var_hash, old_v); 2025 | } 2026 | */ 2027 | zend_hash_index_update(h, key_index, &v, sizeof(v), NULL); 2028 | } 2029 | } 2030 | 2031 | return 0; 2032 | } 2033 | /* }}} */ 2034 | /* {{{ igbinary_unserialize_object_ser */ 2035 | /** Unserializes object's property array of objects implementing Serializable -interface. */ 2036 | inline static int igbinary_unserialize_object_ser(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval **z, zend_class_entry *ce TSRMLS_DC) { 2037 | size_t n; 2038 | int ret; 2039 | php_unserialize_data_t var_hash; 2040 | 2041 | if (ce->unserialize == NULL) { 2042 | zend_error(E_WARNING, "Class %s has no unserializer", ce->name); 2043 | return 1; 2044 | } 2045 | 2046 | if (t == igbinary_type_object_ser8) { 2047 | if (igsd->buffer_offset + 1 > igsd->buffer_size) { 2048 | zend_error(E_WARNING, "igbinary_unserialize_object_ser: end-of-data"); 2049 | return 1; 2050 | } 2051 | n = igbinary_unserialize8(igsd TSRMLS_CC); 2052 | } else if (t == igbinary_type_object_ser16) { 2053 | if (igsd->buffer_offset + 2 > igsd->buffer_size) { 2054 | zend_error(E_WARNING, "igbinary_unserialize_object_ser: end-of-data"); 2055 | return 1; 2056 | } 2057 | n = igbinary_unserialize16(igsd TSRMLS_CC); 2058 | } else if (t == igbinary_type_object_ser32) { 2059 | if (igsd->buffer_offset + 4 > igsd->buffer_size) { 2060 | zend_error(E_WARNING, "igbinary_unserialize_object_ser: end-of-data"); 2061 | return 1; 2062 | } 2063 | n = igbinary_unserialize32(igsd TSRMLS_CC); 2064 | } else { 2065 | zend_error(E_WARNING, "igbinary_unserialize_object_ser: unknown type '%02x', position %zu", t, igsd->buffer_offset); 2066 | return 1; 2067 | } 2068 | 2069 | if (igsd->buffer_offset + n > igsd->buffer_size) { 2070 | zend_error(E_WARNING, "igbinary_unserialize_object_ser: end-of-data"); 2071 | return 1; 2072 | } 2073 | 2074 | PHP_VAR_UNSERIALIZE_INIT(var_hash); 2075 | ret = ce->unserialize(z, ce, 2076 | (const unsigned char*)(igsd->buffer + igsd->buffer_offset), n, 2077 | (zend_unserialize_data *)&var_hash TSRMLS_CC); 2078 | PHP_VAR_UNSERIALIZE_DESTROY(var_hash); 2079 | 2080 | if (ret != SUCCESS || EG(exception)) { 2081 | return 1; 2082 | } 2083 | 2084 | igsd->buffer_offset += n; 2085 | 2086 | return 0; 2087 | } 2088 | /* }}} */ 2089 | /* {{{ igbinary_unserialize_object */ 2090 | /** Unserialize object. 2091 | * @see ext/standard/var_unserializer.c 2092 | */ 2093 | inline static int igbinary_unserialize_object(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval **z TSRMLS_DC) { 2094 | zend_class_entry *ce; 2095 | zend_class_entry **pce; 2096 | 2097 | zval *h = NULL; 2098 | zval f; 2099 | 2100 | char *name = NULL; 2101 | size_t name_len = 0; 2102 | 2103 | int r; 2104 | 2105 | bool incomplete_class = false; 2106 | 2107 | zval *user_func; 2108 | zval *retval_ptr; 2109 | zval **args[1]; 2110 | zval *arg_func_name; 2111 | 2112 | if (t == igbinary_type_object8 || t == igbinary_type_object16 || t == igbinary_type_object32) { 2113 | if (igbinary_unserialize_chararray(igsd, t, &name, &name_len TSRMLS_CC)) { 2114 | return 1; 2115 | } 2116 | } else if (t == igbinary_type_object_id8 || t == igbinary_type_object_id16 || t == igbinary_type_object_id32) { 2117 | if (igbinary_unserialize_string(igsd, t, &name, &name_len TSRMLS_CC)) { 2118 | return 1; 2119 | } 2120 | } else { 2121 | zend_error(E_WARNING, "igbinary_unserialize_object: unknown object type '%02x', position %zu", t, igsd->buffer_offset); 2122 | return 1; 2123 | } 2124 | 2125 | do { 2126 | /* Try to find class directly */ 2127 | if (zend_lookup_class(name, name_len, &pce TSRMLS_CC) == SUCCESS) { 2128 | ce = *pce; 2129 | break; 2130 | } 2131 | 2132 | /* Check for unserialize callback */ 2133 | if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) { 2134 | incomplete_class = 1; 2135 | ce = PHP_IC_ENTRY; 2136 | break; 2137 | } 2138 | 2139 | /* Call unserialize callback */ 2140 | MAKE_STD_ZVAL(user_func); 2141 | ZVAL_STRING(user_func, PG(unserialize_callback_func), 1); 2142 | args[0] = &arg_func_name; 2143 | MAKE_STD_ZVAL(arg_func_name); 2144 | ZVAL_STRING(arg_func_name, name, 1); 2145 | if (call_user_function_ex(CG(function_table), NULL, user_func, &retval_ptr, 1, args, 0, NULL TSRMLS_CC) != SUCCESS) { 2146 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "defined (%s) but not found", name); 2147 | incomplete_class = 1; 2148 | ce = PHP_IC_ENTRY; 2149 | zval_ptr_dtor(&user_func); 2150 | zval_ptr_dtor(&arg_func_name); 2151 | break; 2152 | } 2153 | if (retval_ptr) { 2154 | zval_ptr_dtor(&retval_ptr); 2155 | } 2156 | 2157 | /* The callback function may have defined the class */ 2158 | if (zend_lookup_class(name, name_len, &pce TSRMLS_CC) == SUCCESS) { 2159 | ce = *pce; 2160 | } else { 2161 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Function %s() hasn't defined the class it was called for", name); 2162 | incomplete_class = true; 2163 | ce = PHP_IC_ENTRY; 2164 | } 2165 | 2166 | zval_ptr_dtor(&user_func); 2167 | zval_ptr_dtor(&arg_func_name); 2168 | } while (0); 2169 | 2170 | /* previous user function call may have raised an exception */ 2171 | if (EG(exception)) { 2172 | return 1; 2173 | } 2174 | 2175 | object_init_ex(*z, ce); 2176 | 2177 | /* reference */ 2178 | if (igsd->references_count + 1 >= igsd->references_capacity) { 2179 | while (igsd->references_count + 1 >= igsd->references_capacity) { 2180 | igsd->references_capacity *= 2; 2181 | } 2182 | 2183 | igsd->references = (void **) erealloc(igsd->references, sizeof(void *) * igsd->references_capacity); 2184 | if (igsd->references == NULL) 2185 | return 1; 2186 | } 2187 | 2188 | igsd->references[igsd->references_count++] = (void *) *z; 2189 | 2190 | /* store incomplete class name */ 2191 | if (incomplete_class) { 2192 | php_store_class_name(*z, name, name_len); 2193 | } 2194 | 2195 | t = (enum igbinary_type) igbinary_unserialize8(igsd TSRMLS_CC); 2196 | switch (t) { 2197 | case igbinary_type_array8: 2198 | case igbinary_type_array16: 2199 | case igbinary_type_array32: 2200 | r = igbinary_unserialize_array(igsd, t, z, 1 TSRMLS_CC); 2201 | break; 2202 | case igbinary_type_object_ser8: 2203 | case igbinary_type_object_ser16: 2204 | case igbinary_type_object_ser32: 2205 | r = igbinary_unserialize_object_ser(igsd, t, z, ce TSRMLS_CC); 2206 | break; 2207 | default: 2208 | zend_error(E_WARNING, "igbinary_unserialize_object: unknown object inner type '%02x', position %zu", t, igsd->buffer_offset); 2209 | return 1; 2210 | } 2211 | 2212 | if (r) { 2213 | return r; 2214 | } 2215 | 2216 | if (Z_OBJCE_PP(z) != PHP_IC_ENTRY && zend_hash_exists(&Z_OBJCE_PP(z)->function_table, "__wakeup", sizeof("__wakeup"))) { 2217 | INIT_PZVAL(&f); 2218 | ZVAL_STRINGL(&f, "__wakeup", sizeof("__wakeup") - 1, 0); 2219 | call_user_function_ex(CG(function_table), z, &f, &h, 0, 0, 1, NULL TSRMLS_CC); 2220 | 2221 | if (h) { 2222 | zval_ptr_dtor(&h); 2223 | } 2224 | 2225 | if (EG(exception)) { 2226 | r = 1; 2227 | } 2228 | } 2229 | 2230 | return r; 2231 | } 2232 | /* }}} */ 2233 | /* {{{ igbinary_unserialize_ref */ 2234 | /** Unserializes array or object by reference. */ 2235 | inline static int igbinary_unserialize_ref(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval **z TSRMLS_DC) { 2236 | size_t n; 2237 | 2238 | if (t == igbinary_type_ref8 || t == igbinary_type_objref8) { 2239 | if (igsd->buffer_offset + 1 > igsd->buffer_size) { 2240 | zend_error(E_WARNING, "igbinary_unserialize_ref: end-of-data"); 2241 | return 1; 2242 | } 2243 | n = igbinary_unserialize8(igsd TSRMLS_CC); 2244 | } else if (t == igbinary_type_ref16 || t == igbinary_type_objref16) { 2245 | if (igsd->buffer_offset + 2 > igsd->buffer_size) { 2246 | zend_error(E_WARNING, "igbinary_unserialize_ref: end-of-data"); 2247 | return 1; 2248 | } 2249 | n = igbinary_unserialize16(igsd TSRMLS_CC); 2250 | } else if (t == igbinary_type_ref32 || t == igbinary_type_objref32) { 2251 | if (igsd->buffer_offset + 4 > igsd->buffer_size) { 2252 | zend_error(E_WARNING, "igbinary_unserialize_ref: end-of-data"); 2253 | return 1; 2254 | } 2255 | n = igbinary_unserialize32(igsd TSRMLS_CC); 2256 | } else { 2257 | zend_error(E_WARNING, "igbinary_unserialize_ref: unknown type '%02x', position %zu", t, igsd->buffer_offset); 2258 | return 1; 2259 | } 2260 | 2261 | if (n >= igsd->references_count) { 2262 | zend_error(E_WARNING, "igbinary_unserialize_ref: invalid reference"); 2263 | return 1; 2264 | } 2265 | 2266 | if (*z != NULL) { 2267 | zval_ptr_dtor(z); 2268 | } 2269 | 2270 | *z = igsd->references[n]; 2271 | Z_ADDREF_PP(z); 2272 | 2273 | if (t == igbinary_type_objref8 || t == igbinary_type_objref16 || t == igbinary_type_objref32) { 2274 | Z_SET_ISREF_TO_PP(z, false); 2275 | } 2276 | 2277 | return 0; 2278 | } 2279 | /* }}} */ 2280 | /* {{{ igbinary_unserialize_zval */ 2281 | /** Unserialize zval. */ 2282 | static int igbinary_unserialize_zval(struct igbinary_unserialize_data *igsd, zval **z TSRMLS_DC) { 2283 | enum igbinary_type t; 2284 | 2285 | long tmp_long; 2286 | double tmp_double; 2287 | char *tmp_chararray; 2288 | size_t tmp_size_t; 2289 | 2290 | if (igsd->buffer_offset + 1 > igsd->buffer_size) { 2291 | zend_error(E_WARNING, "igbinary_unserialize_zval: end-of-data"); 2292 | return 1; 2293 | } 2294 | 2295 | t = (enum igbinary_type) igbinary_unserialize8(igsd TSRMLS_CC); 2296 | 2297 | switch (t) { 2298 | case igbinary_type_ref: 2299 | if (igbinary_unserialize_zval(igsd, z TSRMLS_CC)) { 2300 | return 1; 2301 | } 2302 | /* Scalar types should be added to the references hash */ 2303 | /* unless they're already added */ 2304 | /* in references list: marked as ref */ 2305 | if (!Z_ISREF_PP(z)) switch (Z_TYPE_PP(z)) { 2306 | case IS_STRING: 2307 | case IS_LONG: 2308 | case IS_NULL: 2309 | case IS_DOUBLE: 2310 | case IS_BOOL: 2311 | /* reference */ 2312 | if (igsd->references_count + 1 >= igsd->references_capacity) { 2313 | while (igsd->references_count + 1 >= igsd->references_capacity) { 2314 | igsd->references_capacity *= 2; 2315 | } 2316 | 2317 | igsd->references = (void **) erealloc(igsd->references, sizeof(void *) * igsd->references_capacity); 2318 | if (igsd->references == NULL) 2319 | return 1; 2320 | } 2321 | 2322 | igsd->references[igsd->references_count++] = (void *) *z; 2323 | } 2324 | Z_SET_ISREF_TO_PP(z, true); 2325 | break; 2326 | case igbinary_type_objref8: 2327 | case igbinary_type_objref16: 2328 | case igbinary_type_objref32: 2329 | case igbinary_type_ref8: 2330 | case igbinary_type_ref16: 2331 | case igbinary_type_ref32: 2332 | if (igbinary_unserialize_ref(igsd, t, z TSRMLS_CC)) { 2333 | return 1; 2334 | } 2335 | break; 2336 | case igbinary_type_object8: 2337 | case igbinary_type_object16: 2338 | case igbinary_type_object32: 2339 | case igbinary_type_object_id8: 2340 | case igbinary_type_object_id16: 2341 | case igbinary_type_object_id32: 2342 | if (igbinary_unserialize_object(igsd, t, z TSRMLS_CC)) { 2343 | return 1; 2344 | } 2345 | break; 2346 | case igbinary_type_array8: 2347 | case igbinary_type_array16: 2348 | case igbinary_type_array32: 2349 | if (igbinary_unserialize_array(igsd, t, z, 0 TSRMLS_CC)) { 2350 | return 1; 2351 | } 2352 | break; 2353 | case igbinary_type_string_empty: 2354 | ZVAL_EMPTY_STRING(*z); 2355 | break; 2356 | case igbinary_type_string_id8: 2357 | case igbinary_type_string_id16: 2358 | case igbinary_type_string_id32: 2359 | if (igbinary_unserialize_string(igsd, t, &tmp_chararray, &tmp_size_t TSRMLS_CC)) { 2360 | return 1; 2361 | } 2362 | ZVAL_STRINGL(*z, tmp_chararray, tmp_size_t, 1); 2363 | break; 2364 | case igbinary_type_string8: 2365 | case igbinary_type_string16: 2366 | case igbinary_type_string32: 2367 | if (igbinary_unserialize_chararray(igsd, t, &tmp_chararray, &tmp_size_t TSRMLS_CC)) { 2368 | return 1; 2369 | } 2370 | ZVAL_STRINGL(*z, tmp_chararray, tmp_size_t, 1); 2371 | break; 2372 | case igbinary_type_long8p: 2373 | case igbinary_type_long8n: 2374 | case igbinary_type_long16p: 2375 | case igbinary_type_long16n: 2376 | case igbinary_type_long32p: 2377 | case igbinary_type_long32n: 2378 | case igbinary_type_long64p: 2379 | case igbinary_type_long64n: 2380 | if (igbinary_unserialize_long(igsd, t, &tmp_long TSRMLS_CC)) { 2381 | return 1; 2382 | } 2383 | ZVAL_LONG(*z, tmp_long); 2384 | break; 2385 | case igbinary_type_null: 2386 | ZVAL_NULL(*z); 2387 | break; 2388 | case igbinary_type_bool_false: 2389 | ZVAL_BOOL(*z, 0); 2390 | break; 2391 | case igbinary_type_bool_true: 2392 | ZVAL_BOOL(*z, 1); 2393 | break; 2394 | case igbinary_type_double: 2395 | if (igbinary_unserialize_double(igsd, t, &tmp_double TSRMLS_CC)) { 2396 | return 1; 2397 | } 2398 | ZVAL_DOUBLE(*z, tmp_double); 2399 | break; 2400 | default: 2401 | zend_error(E_WARNING, "igbinary_unserialize_zval: unknown type '%02x', position %zu", t, igsd->buffer_offset); 2402 | return 1; 2403 | } 2404 | 2405 | return 0; 2406 | } 2407 | /* }}} */ 2408 | 2409 | /* 2410 | * Local variables: 2411 | * tab-width: 2 2412 | * c-basic-offset: 4 2413 | * End: 2414 | * vim600: noet sw=4 ts=4 fdm=marker 2415 | * vim<600: noet sw=4 ts=4 2416 | */ 2417 | -------------------------------------------------------------------------------- /igbinary.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | See COPYING file for further copyright information | 4 | +----------------------------------------------------------------------+ 5 | | Author: Oleg Grenrus | 6 | | See CREDITS for contributors | 7 | +----------------------------------------------------------------------+ 8 | */ 9 | 10 | #ifndef IGBINARY_H 11 | #define IGBINARY_H 12 | #ifdef PHP_WIN32 13 | # include "ig_win32.h" 14 | #else 15 | # include 16 | #endif 17 | #include "php.h" 18 | 19 | #ifdef PHP_WIN32 20 | # if defined(IGBINARY_EXPORTS) || (!defined(COMPILE_DL_IGBINARY)) 21 | # define IGBINARY_API __declspec(dllexport) 22 | # elif defined(COMPILE_DL_IGBINARY) 23 | # define IGBINARY_API __declspec(dllimport) 24 | # else 25 | # define IGBINARY_API /* nothing special */ 26 | # endif 27 | #elif defined(__GNUC__) && __GNUC__ >= 4 28 | # define IGBINARY_API __attribute__ ((visibility("default"))) 29 | #else 30 | # define IGBINARY_API /* nothing special */ 31 | #endif 32 | 33 | #define PHP_IGBINARY_VERSION "1.2.2-dev" 34 | 35 | /** Struct that contains pointers to memory allocation and deallocation functions. 36 | * @see igbinary_serialize_data 37 | */ 38 | struct igbinary_memory_manager { 39 | void *(*alloc)(size_t size, void *context); 40 | void *(*realloc)(void *ptr, size_t new_size, void *context); 41 | void (*free)(void *ptr, void *context); 42 | void *context; 43 | }; 44 | 45 | /** Serialize zval. 46 | * Return buffer is allocated by this function with emalloc. 47 | * @param[out] ret Return buffer 48 | * @param[out] ret_len Size of return buffer 49 | * @param[in] z Variable to be serialized 50 | * @return 0 on success, 1 elsewhere. 51 | */ 52 | IGBINARY_API int igbinary_serialize(uint8_t **ret, size_t *ret_len, zval *z TSRMLS_DC); 53 | 54 | /** Serialize zval. 55 | * Return buffer is allocated by this function with emalloc. 56 | * @param[out] ret Return buffer 57 | * @param[out] ret_len Size of return buffer 58 | * @param[in] z Variable to be serialized 59 | * @param[in] memory_manager Pointer to the structure that contains memory allocation functions. 60 | * @return 0 on success, 1 elsewhere. 61 | */ 62 | IGBINARY_API int igbinary_serialize_ex(uint8_t **ret, size_t *ret_len, zval *z, struct igbinary_memory_manager *memory_manager TSRMLS_DC); 63 | 64 | /** Unserialize to zval. 65 | * @param[in] buf Buffer with serialized data. 66 | * @param[in] buf_len Buffer length. 67 | * @param[out] z Unserialized zval 68 | * @return 0 on success, 1 elsewhere. 69 | */ 70 | IGBINARY_API int igbinary_unserialize(const uint8_t *buf, size_t buf_len, zval **z TSRMLS_DC); 71 | 72 | #endif /* IGBINARY_H */ 73 | -------------------------------------------------------------------------------- /igbinary.php: -------------------------------------------------------------------------------- 1 | 29 | * @version 1.0.0 30 | * @package igbinary 31 | */ 32 | 33 | /** Generates a storable representation of a value. 34 | * This is useful for storing or passing PHP values around without losing their type and structure. 35 | * To make the serialized string into a PHP value again, use {@link igbinary_unserialize}. 36 | * 37 | * igbinary_serialize() handles all types, except the resource-type. 38 | * You can even serialize() arrays that contain references to itself. 39 | * Circular references inside the array/object you are serialize()ing will also be stored. 40 | * 41 | * If object implements {@link http://www.php.net/~helly/php/ext/spl/interfaceSerializable.html Serializable} -interface, 42 | * PHP will call the member function serialize to get serialized representation of object. 43 | * 44 | * When serializing objects, PHP will attempt to call the member function __sleep prior to serialization. 45 | * This is to allow the object to do any last minute clean-up, etc. prior to being serialized. 46 | * Likewise, when the object is restored using unserialize() the __wakeup member function is called. 47 | * 48 | * @param mixed $value The value to be serialized. 49 | * @return string Returns a string containing a byte-stream representation of value that can be stored anywhere. 50 | * @link http://www.php.net/serialize PHP default serialize 51 | */ 52 | function igbinary_serialize($value); 53 | 54 | /** Creates a PHP value from a stored representation. 55 | * igbinary_unserialize() takes a single serialized variable and converts it back into a PHP value. 56 | * 57 | * If the variable being unserialized is an object, after successfully reconstructing the object 58 | * PHP will automatically attempt to call the __wakeup() member function (if it exists). 59 | * In case the passed string is not unserializeable, NULL is returned and E_WARNING is issued. 60 | * 61 | * @param string $str The serialized string. 62 | * @return mixed The converted value is returned, and can be a boolean, integer, float, string, array or object. 63 | * @link http://www.php.net/manual/en/function.unserialize.php PHP default unserialize 64 | * @link http://www.php.net/~helly/php/ext/spl/interfaceSerializable.html Serializable 65 | */ 66 | function igbinary_unserialize($str); 67 | 68 | ?> 69 | -------------------------------------------------------------------------------- /igbinary.php.ini: -------------------------------------------------------------------------------- 1 | [igbinary] 2 | extension=igbinary.so 3 | 4 | ; Enable or disable compacting of duplicate strings 5 | ; The default is On. 6 | ;igbinary.compact_strings=On 7 | -------------------------------------------------------------------------------- /igbinary.spec: -------------------------------------------------------------------------------- 1 | # Define version and release number 2 | %define version 1.0.2 3 | %define release 1 4 | 5 | Name: php-igbinary 6 | Version: %{version} 7 | Release: %{release}%{?dist} 8 | Packager: Mikko Koppanen 9 | Summary: PHP igbinary extension 10 | License: PHP Style License (http://opensource.dynamoid.com/#license) 11 | Group: Web/Applications 12 | URL: http://opensource.dynamoid.com/ 13 | # pear package creates .tgz file and the original source was .tar.gz 14 | Source: http://opensource.dynamoid.com/igbinary-%{version}.tgz 15 | Prefix: %{_prefix} 16 | Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root 17 | BuildRequires: php-devel, make, gcc, /usr/bin/phpize 18 | 19 | %description 20 | Igbinary is a drop in replacement for the standard PHP serializer. 21 | Instead of time and space consuming textual representation, 22 | igbinary stores PHP data structures in a compact binary form. 23 | 24 | %prep 25 | %setup -q -n igbinary-%{version} 26 | 27 | %build 28 | /usr/bin/phpize && %configure && %{__make} %{?_smp_mflags} 29 | 30 | # Clean the buildroot so that it does not contain any stuff from previous builds 31 | [ "%{buildroot}" != "/" ] && %{__rm} -rf %{buildroot} 32 | 33 | # Install the extension 34 | %{__make} install INSTALL_ROOT=%{buildroot} 35 | 36 | # Create the ini location 37 | %{__mkdir} -p %{buildroot}/etc/php.d 38 | 39 | # Preliminary extension ini 40 | echo "extension=igbinary.so" > %{buildroot}/%{_sysconfdir}/php.d/igbinary.ini 41 | 42 | %clean 43 | [ "%{buildroot}" != "/" ] && %{__rm} -rf %{buildroot} 44 | 45 | %files 46 | %{_libdir}/php/modules/igbinary.so 47 | %{_sysconfdir}/php.d/igbinary.ini 48 | %{_includedir}/php/ext/igbinary/igbinary.h 49 | 50 | %changelog 51 | * Fri Oct 02 2009 Mikko Koppanen 52 | - Initial spec file 53 | -------------------------------------------------------------------------------- /package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | igbinary 4 | pecl.php.net 5 | igbinary extension 6 | Igbinary is a drop in replacement for the standard php serializer. Instead of 7 | time and space consuming textual representation, igbinary stores php data 8 | structures in a compact binary form. Savings are significant when using 9 | memcached or similar memory based storages for serialized data. 10 | 11 | Oleg Grenrus 12 | phadej 13 | oleg.grenrus@iki.fi 14 | yes 15 | 16 | 17 | Pierre Joye 18 | pajoye 19 | pierre@php.net 20 | yes 21 | 22 | 23 | Teddy Grenman 24 | tricky 25 | teddy.pecl@luuseri.com 26 | yes 27 | 28 | 2014-08-29 29 | 30 | 31 | 1.2.2-dev 32 | 1.1.1 33 | 34 | 35 | stable 36 | stable 37 | 38 | New BSD 39 | 40 | - Compatible with PHP 5.2 - 5.6 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 5.2.0 117 | 118 | 119 | 1.4.0b1 120 | 121 | 122 | 123 | igbinary 124 | 125 | 126 | 127 | 2014-08-29 128 | 129 | 130 | 1.2.1 131 | 1.1.1 132 | 133 | 134 | stable 135 | stable 136 | 137 | New BSD 138 | 139 | - Compatible with PHP 5.2 - 5.6 140 | 141 | 142 | 143 | 2014-08-29 144 | 145 | 146 | 1.2.0 147 | 1.1.1 148 | 149 | 150 | stable 151 | stable 152 | 153 | New BSD 154 | 155 | - PECL bug #22614, igbinary_unserialize(FALSE) must return FALSE 156 | - PHP bug #54662, unserializing nested objects cause crash 157 | - Other fixes 158 | 159 | 160 | 161 | 2011-03-14 162 | 163 | 164 | 1.1.1 165 | 1.1.1 166 | 167 | 168 | stable 169 | stable 170 | 171 | New BSD 172 | 173 | - Initial PECL release 174 | 175 | 176 | 177 | 2009-09-02 178 | 179 | 1.0.2 180 | 1.0.2 181 | 182 | 183 | stable 184 | stable 185 | 186 | PHP like license 187 | 188 | - Use Z_ADDREF_PP or Z_ADDREF et al. when increasing refcount. 189 | 190 | 191 | 192 | 193 | -------------------------------------------------------------------------------- /php_igbinary.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | See COPYING file for further copyright information | 4 | +----------------------------------------------------------------------+ 5 | | Author: Oleg Grenrus | 6 | | See CREDITS for contributors | 7 | +----------------------------------------------------------------------+ 8 | */ 9 | 10 | #ifndef PHP_IGBINARY_H 11 | #define PHP_IGBINARY_H 12 | 13 | /** Module entry of igbinary. */ 14 | extern zend_module_entry igbinary_module_entry; 15 | #define phpext_igbinary_ptr &igbinary_module_entry 16 | 17 | #ifdef PHP_WIN32 18 | #define PHP_IGBINARY_API __declspec(dllexport) 19 | #else 20 | #define PHP_IGBINARY_API 21 | #endif 22 | 23 | ZEND_BEGIN_MODULE_GLOBALS(igbinary) 24 | zend_bool compact_strings; 25 | ZEND_END_MODULE_GLOBALS(igbinary) 26 | 27 | #ifdef ZTS 28 | #include "TSRM.h" 29 | #endif 30 | 31 | #include "ext/standard/php_smart_str.h" 32 | 33 | /** Module init function. */ 34 | PHP_MINIT_FUNCTION(igbinary); 35 | 36 | /** Module shutdown function. */ 37 | PHP_MSHUTDOWN_FUNCTION(igbinary); 38 | 39 | /** Request init function. */ 40 | PHP_RINIT_FUNCTION(igbinary); 41 | 42 | /** Request shutdown function. */ 43 | PHP_RSHUTDOWN_FUNCTION(igbinary); 44 | 45 | /** Module info function for phpinfo(). */ 46 | PHP_MINFO_FUNCTION(igbinary); 47 | 48 | /** string igbinary_serialize(mixed value). 49 | * Returns the binary serialized value. 50 | */ 51 | PHP_FUNCTION(igbinary_serialize); 52 | 53 | /** mixed igbinary_unserialize(string data). 54 | * Unserializes the given inputstring (value). 55 | */ 56 | PHP_FUNCTION(igbinary_unserialize); 57 | 58 | #ifdef ZTS 59 | #define IGBINARY_G(v) TSRMG(igbinary_globals_id, zend_igbinary_globals *, v) 60 | #else 61 | #define IGBINARY_G(v) (igbinary_globals.v) 62 | #endif 63 | 64 | /** Binary protocol version of igbinary. */ 65 | #define IGBINARY_FORMAT_VERSION 0x00000002 66 | 67 | /** Backport macros from php 5.3 */ 68 | #ifndef Z_ISREF_P 69 | #define Z_ISREF_P(pz) PZVAL_IS_REF(pz) 70 | #endif 71 | 72 | #ifndef Z_ISREF_PP 73 | #define Z_ISREF_PP(ppz) Z_ISREF_P(*(ppz)) 74 | #endif 75 | 76 | #ifndef Z_SET_ISREF_TO_P 77 | #define Z_SET_ISREF_TO_P(pz, isref) (Z_ISREF_P(pz) = (isref)) 78 | #endif 79 | 80 | #ifndef Z_SET_ISREF_TO_PP 81 | #define Z_SET_ISREF_TO_PP(ppz, isref) Z_SET_ISREF_TO_P(*(ppz), isref) 82 | #endif 83 | 84 | #ifndef Z_ADDREF_P 85 | #define Z_ADDREF_P(pz) ZVAL_ADDREF(pz) 86 | #endif 87 | 88 | #ifndef Z_ADDREF_PP 89 | #define Z_ADDREF_PP(ppz) Z_ADDREF_P(*(ppz)) 90 | #endif 91 | #endif /* PHP_IGBINARY_H */ 92 | 93 | 94 | /* 95 | * Local variables: 96 | * tab-width: 2 97 | * c-basic-offset: 0 98 | * End: 99 | * vim600: noet sw=2 ts=2 fdm=marker 100 | * vim<600: noet sw=2 ts=2 101 | */ 102 | -------------------------------------------------------------------------------- /tags.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # This generates the tags file for vim or emacs. (vim -t igbinary_serialize8) 4 | # 5 | # Try with "vim -t igbinary_serialize8" 6 | # 7 | 8 | find . -name "*.h" -o -name "*.c" | ctags-exuberant --language-force=c -L - 9 | -------------------------------------------------------------------------------- /tests/igbinary_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for igbinary presence 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 20 | --EXPECT-- 21 | igbinary extension is available 22 | -------------------------------------------------------------------------------- /tests/igbinary_002.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for null serialisation 3 | --SKIPIF-- 4 | --FILE-- 5 | 34 | --EXPECT-- 35 | null 36 | 00 37 | OK 38 | -------------------------------------------------------------------------------- /tests/igbinary_003.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for bool serialisation 3 | --SKIPIF-- 4 | --FILE-- 5 | 35 | --EXPECT-- 36 | bool true 37 | 05 38 | OK 39 | bool false 40 | 04 41 | OK 42 | -------------------------------------------------------------------------------- /tests/igbinary_004.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for integer serialisation 3 | --SKIPIF-- 4 | --FILE-- 5 | 40 | --EXPECT-- 41 | zero: 0 42 | 0600 43 | OK 44 | small: 1 45 | 0601 46 | OK 47 | small: -1 48 | 0701 49 | OK 50 | medium: 1000 51 | 0803e8 52 | OK 53 | medium: -1000 54 | 0903e8 55 | OK 56 | large: 100000 57 | 0a000186a0 58 | OK 59 | large: -100000 60 | 0b000186a0 61 | OK 62 | -------------------------------------------------------------------------------- /tests/igbinary_005.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for double serialisation 3 | --SKIPIF-- 4 | --FILE-- 5 | 34 | --EXPECT-- 35 | double: 123.456 36 | 0c405edd2f1a9fbe77 37 | OK 38 | -------------------------------------------------------------------------------- /tests/igbinary_006.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for simple string serialization 3 | --SKIPIF-- 4 | --FILE-- 5 | 35 | --EXPECT-- 36 | empty: "" 37 | 0d 38 | OK 39 | string: "foobar" 40 | 1106666f6f626172 41 | OK 42 | -------------------------------------------------------------------------------- /tests/igbinary_007.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for simple array serialization 3 | --SKIPIF-- 4 | --FILE-- 5 | 36 | --EXPECT-- 37 | empty array: 38 | 1400 39 | OK 40 | array(1, 2, 3) 41 | 1403060006010601060206020603 42 | OK 43 | array(array(1, 2, 3), arr... 44 | 1403060014030600060106010602060206030601140306000604060106050602060606021403060006070601060806020609 45 | OK 46 | -------------------------------------------------------------------------------- /tests/igbinary_008.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for array+string serialization 3 | --SKIPIF-- 4 | --FILE-- 5 | 1, "two" => 2))', array("one" => 1, "two" => 2)); 29 | test('array("kek" => "lol", "lol" => "kek")', array("kek" => "lol", "lol" => "kek")); 30 | test('array("" => "empty")', array("" => "empty")); 31 | 32 | ?> 33 | --EXPECT-- 34 | array("foo", "foo", "foo") 35 | 140306001103666f6f06010e0006020e00 36 | OK 37 | array("one" => 1, "two" => 2)) 38 | 140211036f6e650601110374776f0602 39 | OK 40 | array("kek" => "lol", "lol" => "kek") 41 | 140211036b656b11036c6f6c0e010e00 42 | OK 43 | array("" => "empty") 44 | 14010d1105656d707479 45 | OK 46 | -------------------------------------------------------------------------------- /tests/igbinary_009.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for reference serialisation 3 | --INI-- 4 | report_memleaks=0 5 | --SKIPIF-- 6 | array( 22 | 'b' => 'c', 23 | 'd' => 'e' 24 | ), 25 | 'f' => array( 26 | 'g' => 'h' 27 | ) 28 | ); 29 | 30 | test('array', $a, false); 31 | 32 | /* 33 | * you can add regression tests for your extension here 34 | * 35 | * the output of your test code has to be equal to the 36 | * text in the --EXPECT-- section below for the tests 37 | * to pass, differences between the output and the 38 | * expected text are interpreted as failure 39 | * 40 | * see php5/README.TESTING for further information on 41 | * writing regression tests 42 | */ 43 | ?> 44 | --EXPECT-- 45 | array 46 | 140211016114021101621101631101641101651101661401110167110168 47 | OK 48 | -------------------------------------------------------------------------------- /tests/igbinary_012.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Object test 3 | --SKIPIF-- 4 | --FILE-- 5 | a = $a; 30 | $this->b = $b; 31 | $this->c = $c; 32 | } 33 | } 34 | 35 | $o = new Obj(1, 2, 3); 36 | 37 | 38 | test('object', $o, false); 39 | 40 | /* 41 | * you can add regression tests for your extension here 42 | * 43 | * the output of your test code has to be equal to the 44 | * text in the --EXPECT-- section below for the tests 45 | * to pass, differences between the output and the 46 | * expected text are interpreted as failure 47 | * 48 | * see php5/README.TESTING for further information on 49 | * writing regression tests 50 | */ 51 | ?> 52 | --EXPECT-- 53 | object 54 | 17034f626a140311016106011104002a006206021106004f626a00630603 55 | OK 56 | -------------------------------------------------------------------------------- /tests/igbinary_013.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Object-Array test 3 | --SKIPIF-- 4 | --FILE-- 5 | a = $a; 26 | $this->b = $b; 27 | } 28 | } 29 | 30 | $o = array(new Obj(1, 2), new Obj(3, 4)); 31 | 32 | 33 | test('object', $o, false); 34 | 35 | /* 36 | * you can add regression tests for your extension here 37 | * 38 | * the output of your test code has to be equal to the 39 | * text in the --EXPECT-- section below for the tests 40 | * to pass, differences between the output and the 41 | * expected text are interpreted as failure 42 | * 43 | * see php5/README.TESTING for further information on 44 | * writing regression tests 45 | */ 46 | ?> 47 | --EXPECT-- 48 | object 49 | 1402060017034f626a14021101610601110162060206011a0014020e0106030e020604 50 | OK 51 | -------------------------------------------------------------------------------- /tests/igbinary_014.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Object-Reference test 3 | --SKIPIF-- 4 | --FILE-- 5 | a = $a; 26 | $this->b = $b; 27 | } 28 | } 29 | 30 | $o = new Obj(1, 2); 31 | $a = array(&$o, &$o); 32 | 33 | test('object', $a, false); 34 | 35 | --EXPECT-- 36 | object 37 | 140206002517034f626a1402110161060111016206020601252201 38 | OK 39 | -------------------------------------------------------------------------------- /tests/igbinary_015.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for serialization handler 3 | --SKIPIF-- 4 | 75 | --EXPECT-- 76 | 2 77 | 14011103666f6f0602 78 | -------------------------------------------------------------------------------- /tests/igbinary_015b.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for serialization handler, ini-directive 3 | --SKIPIF-- 4 | 75 | --EXPECT-- 76 | 2 77 | 14011103666f6f0602 78 | -------------------------------------------------------------------------------- /tests/igbinary_016.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Object test, __sleep 3 | --SKIPIF-- 4 | --FILE-- 5 | a = $a; 28 | $this->b = $b; 29 | $this->c = $c; 30 | $this->d = $d; 31 | } 32 | 33 | function __sleep() { 34 | return array('a', 'b', 'c'); 35 | } 36 | 37 | # function __wakeup() { 38 | # $this->d = $this->a + $this->b + $this->c; 39 | # } 40 | } 41 | 42 | $o = new Obj(1, 2, 3, 4); 43 | 44 | 45 | test('object', $o, true); 46 | 47 | /* 48 | * you can add regression tests for your extension here 49 | * 50 | * the output of your test code has to be equal to the 51 | * text in the --EXPECT-- section below for the tests 52 | * to pass, differences between the output and the 53 | * expected text are interpreted as failure 54 | * 55 | * see php5/README.TESTING for further information on 56 | * writing regression tests 57 | */ 58 | ?> 59 | --EXPECT-- 60 | object 61 | 17034f626a140311016106011104002a006206021106004f626a00630603 62 | OK 63 | -------------------------------------------------------------------------------- /tests/igbinary_017.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Object test, __wakeup 3 | --SKIPIF-- 4 | --FILE-- 5 | b == 3 ? 'OK' : 'ERROR'; 17 | echo "\n"; 18 | } 19 | 20 | class Obj { 21 | var $a; 22 | var $b; 23 | 24 | function __construct($a, $b) { 25 | $this->a = $a; 26 | $this->b = $b; 27 | } 28 | 29 | function __wakeup() { 30 | $this->b = $this->a * 3; 31 | } 32 | } 33 | 34 | $o = new Obj(1, 2); 35 | 36 | 37 | test('object', $o, false); 38 | 39 | /* 40 | * you can add regression tests for your extension here 41 | * 42 | * the output of your test code has to be equal to the 43 | * text in the --EXPECT-- section below for the tests 44 | * to pass, differences between the output and the 45 | * expected text are interpreted as failure 46 | * 47 | * see php5/README.TESTING for further information on 48 | * writing regression tests 49 | */ 50 | ?> 51 | --EXPECT-- 52 | object 53 | 17034f626a140211016106011101620602 54 | OK 55 | -------------------------------------------------------------------------------- /tests/igbinary_018.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Object test, __sleep error cases 3 | --SKIPIF-- 4 | --FILE-- 5 | a = $a; 28 | $this->b = $b; 29 | } 30 | 31 | function __sleep() { 32 | return array('c'); 33 | } 34 | 35 | # function __wakeup() { 36 | # $this->b = $this->a * 3; 37 | # } 38 | } 39 | 40 | class Opj { 41 | var $a; 42 | var $b; 43 | 44 | function __construct($a, $b) { 45 | $this->a = $a; 46 | $this->b = $b; 47 | } 48 | 49 | function __sleep() { 50 | return array(1); 51 | } 52 | 53 | # function __wakeup() { 54 | # 55 | # } 56 | } 57 | 58 | $o = new Obj(1, 2); 59 | $p = new Opj(1, 2); 60 | 61 | test('nonexisting', $o, true); 62 | test('wrong', $p, true); 63 | 64 | /* 65 | * you can add regression tests for your extension here 66 | * 67 | * the output of your test code has to be equal to the 68 | * text in the --EXPECT-- section below for the tests 69 | * to pass, differences between the output and the 70 | * expected text are interpreted as failure 71 | * 72 | * see php5/README.TESTING for further information on 73 | * writing regression tests 74 | */ 75 | ?> 76 | --EXPECT-- 77 | nonexisting 78 | 17034f626a140111016300 79 | OK 80 | wrong 81 | 17034f706a140100 82 | OK 83 | -------------------------------------------------------------------------------- /tests/igbinary_019.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Object test, __autoload 3 | --SKIPIF-- 4 | --FILE-- 5 | b == 2 ? 'OK' : 'ERROR'; 17 | echo "\n"; 18 | } 19 | 20 | function __autoload($classname) { 21 | class Obj { 22 | var $a; 23 | var $b; 24 | 25 | function __construct($a, $b) { 26 | $this->a = $a; 27 | $this->b = $b; 28 | } 29 | } 30 | } 31 | 32 | test('autoload', '0000000217034f626a140211016106011101620602', false); 33 | 34 | /* 35 | * you can add regression tests for your extension here 36 | * 37 | * the output of your test code has to be equal to the 38 | * text in the --EXPECT-- section below for the tests 39 | * to pass, differences between the output and the 40 | * expected text are interpreted as failure 41 | * 42 | * see php5/README.TESTING for further information on 43 | * writing regression tests 44 | */ 45 | ?> 46 | --EXPECT-- 47 | autoload 48 | 17034f626a140211016106011101620602 49 | OK 50 | -------------------------------------------------------------------------------- /tests/igbinary_020.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Object test, incomplete class 3 | --SKIPIF-- 4 | --FILE-- 5 | 34 | --EXPECTF-- 35 | incom 36 | 17034f626a140211016106011101620602 37 | object(__PHP_Incomplete_Class)#%d (3) { 38 | ["__PHP_Incomplete_Class_Name"]=> 39 | string(3) "Obj" 40 | ["a"]=> 41 | int(1) 42 | ["b"]=> 43 | int(2) 44 | } 45 | -------------------------------------------------------------------------------- /tests/igbinary_021.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Object Serializable interface 3 | --SKIPIF-- 4 | --FILE-- 5 | a = $a; 26 | $this->b = $b; 27 | } 28 | 29 | public function serialize() { 30 | return pack('NN', $this->a, $this->b); 31 | } 32 | 33 | public function unserialize($serialized) { 34 | $tmp = unpack('N*', $serialized); 35 | $this->__construct($tmp[1], $tmp[2]); 36 | } 37 | } 38 | 39 | $o = new Obj(1, 2); 40 | 41 | test('object', $o, false); 42 | 43 | /* 44 | * you can add regression tests for your extension here 45 | * 46 | * the output of your test code has to be equal to the 47 | * text in the --EXPECT-- section below for the tests 48 | * to pass, differences between the output and the 49 | * expected text are interpreted as failure 50 | * 51 | * see php5/README.TESTING for further information on 52 | * writing regression tests 53 | */ 54 | ?> 55 | --EXPECT-- 56 | object 57 | 17034f626a1d080000000100000002 58 | OK 59 | -------------------------------------------------------------------------------- /tests/igbinary_022.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Object test, unserialize_callback_func 3 | --SKIPIF-- 4 | --INI-- 5 | unserialize_callback_func=autoload 6 | --FILE-- 7 | b == 2 ? 'OK' : 'ERROR'; 19 | echo "\n"; 20 | } 21 | 22 | function autoload($classname) { 23 | class Obj { 24 | var $a; 25 | var $b; 26 | 27 | function __construct($a, $b) { 28 | $this->a = $a; 29 | $this->b = $b; 30 | } 31 | } 32 | } 33 | 34 | test('autoload', '0000000217034f626a140211016106011101620602', false); 35 | 36 | /* 37 | * you can add regression tests for your extension here 38 | * 39 | * the output of your test code has to be equal to the 40 | * text in the --EXPECT-- section below for the tests 41 | * to pass, differences between the output and the 42 | * expected text are interpreted as failure 43 | * 44 | * see php5/README.TESTING for further information on 45 | * writing regression tests 46 | */ 47 | ?> 48 | --EXPECT-- 49 | autoload 50 | 17034f626a140211016106011101620602 51 | OK 52 | -------------------------------------------------------------------------------- /tests/igbinary_023.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Resource 3 | --SKIPIF-- 4 | a = $a; 32 | $this->b = $b; 33 | $this->c = $c; 34 | } 35 | } 36 | 37 | class Obj2 { 38 | public $aa; 39 | protected $bb; 40 | private $cc; 41 | private $obj; 42 | 43 | function __construct($a, $b, $c) { 44 | $this->a = $a; 45 | $this->b = $b; 46 | $this->c = $c; 47 | 48 | $this->obj = new Obj($a, $b, $c); 49 | } 50 | } 51 | 52 | class Obj3 { 53 | private $objs; 54 | 55 | function __construct($a, $b, $c) { 56 | $this->objs = array(); 57 | 58 | for ($i = $a; $i < $c; $i += $b) { 59 | $this->objs[] = new Obj($a, $i, $c); 60 | } 61 | } 62 | } 63 | 64 | class Obj4 { 65 | private $a; 66 | private $obj; 67 | 68 | function __construct($a) { 69 | $this->a = $a; 70 | } 71 | 72 | public function set($obj) { 73 | $this->obj = $obj; 74 | } 75 | } 76 | 77 | $o2 = new Obj2(1, 2, 3); 78 | test('objectrec', $o2, false); 79 | 80 | $o3 = new Obj3(0, 1, 4); 81 | test('objectrecarr', $o3, false); 82 | 83 | $o4 = new Obj4(100); 84 | $o4->set($o4); 85 | test('objectselfrec', $o4, true); 86 | 87 | /* 88 | * you can add regression tests for your extension here 89 | * 90 | * the output of your test code has to be equal to the 91 | * text in the --EXPECT-- section below for the tests 92 | * to pass, differences between the output and the 93 | * expected text are interpreted as failure 94 | * 95 | * see php5/README.TESTING for further information on 96 | * writing regression tests 97 | */ 98 | ?> 99 | --EXPECT-- 100 | objectrec 101 | 17044f626a32140711026161001105002a006262001108004f626a32006363001109004f626a32006f626a17034f626a140311016106011104002a006206021106004f626a006306030e06060111016206021101630603 102 | OK 103 | objectrecarr 104 | 17044f626a331401110a004f626a33006f626a731404060017034f626a140311016106001104002a006206001106004f626a0063060406011a0214030e0306000e0406010e05060406021a0214030e0306000e0406020e05060406031a0214030e0306000e0406030e050604 105 | OK 106 | objectselfrec 107 | 17044f626a3414021107004f626a34006106641109004f626a34006f626a2200 108 | OK 109 | -------------------------------------------------------------------------------- /tests/igbinary_025.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Object test, array of objects with __sleep 3 | --SKIPIF-- 4 | --FILE-- 5 | a = $a; 26 | $this->b = $b; 27 | $this->c = $c; 28 | $this->d = $d; 29 | } 30 | 31 | function __sleep() { 32 | return array('a', 'b', 'c'); 33 | } 34 | 35 | # function __wakeup() { 36 | # $this->d = $this->a + $this->b + $this->c; 37 | # } 38 | } 39 | 40 | $array = array( 41 | new Obj("aa", "bb", "cc", "dd"), 42 | new Obj("ee", "ff", "gg", "hh"), 43 | new Obj(1, 2, 3, 4), 44 | ); 45 | 46 | 47 | test('array', $array, true); 48 | 49 | ?> 50 | --EXPECTREGEX-- 51 | array\(3\) { 52 | \[0\]=> 53 | object\(Obj\)#1 \(4\) { 54 | \["a"\]=> 55 | string\(2\) "aa" 56 | \[("b":protected|"b:protected")\]=> 57 | string\(2\) "bb" 58 | \["?c"?:("Obj":)?private"?\]=> 59 | string\(2\) "cc" 60 | \["d"\]=> 61 | string\(2\) "dd" 62 | } 63 | \[1\]=> 64 | object\(Obj\)#2 \(4\) { 65 | \["a"\]=> 66 | string\(2\) "ee" 67 | \["?b"?:protected"?\]=> 68 | string\(2\) "ff" 69 | \["?c"?:("Obj":)?private"?\]=> 70 | string\(2\) "gg" 71 | \["d"\]=> 72 | string\(2\) "hh" 73 | } 74 | \[2\]=> 75 | object\(Obj\)#3 \(4\) { 76 | \["a"\]=> 77 | int\(1\) 78 | \["?b"?:protected"?\]=> 79 | int\(2\) 80 | \["?c"?:("Obj":)?private"?\]=> 81 | int\(3\) 82 | \["d"\]=> 83 | int\(4\) 84 | } 85 | } 86 | array\(3\) { 87 | \[0\]=> 88 | object\(Obj\)#4 \(4\) { 89 | \["a"\]=> 90 | string\(2\) "aa" 91 | \["?b"?:protected"?\]=> 92 | string\(2\) "bb" 93 | \["?c"?:("Obj":)?private"?\]=> 94 | string\(2\) "cc" 95 | \["d"\]=> 96 | NULL 97 | } 98 | \[1\]=> 99 | object\(Obj\)#5 \(4\) { 100 | \["a"\]=> 101 | string\(2\) "ee" 102 | \["?b"?:protected"?\]=> 103 | string\(2\) "ff" 104 | \["?c"?:("Obj":)?private"?\]=> 105 | string\(2\) "gg" 106 | \["d"\]=> 107 | NULL 108 | } 109 | \[2\]=> 110 | object\(Obj\)#6 \(4\) { 111 | \["a"\]=> 112 | int\(1\) 113 | \["?b"?:protected"?\]=> 114 | int\(2\) 115 | \["?c"?:("Obj":)?private"?\]=> 116 | int\(3\) 117 | \["d"\]=> 118 | NULL 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /tests/igbinary_026.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Cyclic array test 3 | --INI-- 4 | report_memleaks=0 5 | --SKIPIF-- 6 | array( 24 | 'b' => 'c', 25 | 'd' => 'e' 26 | ), 27 | ); 28 | 29 | $a['f'] = &$a; 30 | 31 | test('array', $a, false); 32 | 33 | $a = array("foo" => &$b); 34 | $b = array(1, 2, $a); 35 | 36 | $exp = $a; 37 | $act = igbinary_unserialize(igbinary_serialize($a)); 38 | 39 | $dump_exp = print_r($exp, true); 40 | $dump_act = print_r($act, true); 41 | 42 | if ($dump_act !== $dump_exp) { 43 | echo "Var dump differs:\n", $dump_act, "\n", $dump_exp, "\n"; 44 | } else { 45 | echo "Var dump OK\n"; 46 | } 47 | 48 | $act['foo'][1] = 'test value'; 49 | $exp['foo'][1] = 'test value'; 50 | if ($act['foo'][1] !== $act['foo'][2]['foo'][1]) { 51 | echo "Recursive elements differ:\n"; 52 | var_dump($act); 53 | var_dump($act['foo']); 54 | var_dump($exp); 55 | var_dump($exp['foo']); 56 | } 57 | 58 | ?> 59 | --EXPECT-- 60 | array 61 | 140211016114021101621101631101641101651101662514020e0001010e05250102 62 | OK 63 | Var dump OK 64 | -------------------------------------------------------------------------------- /tests/igbinary_026b.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Cyclic array test 2 3 | --INI-- 4 | report_memleaks=0 5 | --SKIPIF-- 6 | &$b); 19 | $b = array(1, 2, $a); 20 | 21 | /* all three statements below should produce same output however PHP stock 22 | * unserialize/serialize produces different output (5.2.16). I consider this is 23 | * a PHP bug. - Oleg Grenrus 24 | */ 25 | 26 | //$k = $a; 27 | //$k = unserialize(serialize($a)); 28 | $k = igbinary_unserialize(igbinary_serialize($a)); 29 | 30 | function check($a, $k) { 31 | $a_str = print_r($a, true); 32 | $k_str = print_r($k, true); 33 | 34 | if ($a_str !== $k_str) { 35 | echo "Output differs\n"; 36 | echo "Expected:\n", $a_str, "\n"; 37 | echo "Actual:\n", $k_str, "\n"; 38 | } else { 39 | echo "OK\n"; 40 | } 41 | } 42 | 43 | check($a, $k); 44 | 45 | $a["foo"][2]["foo"][1] = "b"; 46 | $k["foo"][2]["foo"][1] = "b"; 47 | 48 | check($a, $k); 49 | 50 | ?> 51 | --EXPECT-- 52 | OK 53 | OK 54 | -------------------------------------------------------------------------------- /tests/igbinary_027.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for serialization handler 3 | --SKIPIF-- 4 | 88 | --EXPECT-- 89 | bool(true) 90 | read 91 | wrote: 14021103666f6f06011104746573741106666f6f626172 92 | -------------------------------------------------------------------------------- /tests/igbinary_028.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Serialize object into session, full set 3 | --SKIPIF-- 4 | d1 = $foo; 34 | $this->d2 = $foo; 35 | $this->d3 = $foo; 36 | } 37 | } 38 | 39 | class Bar { 40 | private static $s1 = array(); 41 | protected static $s2 = array(); 42 | public static $s3 = array(); 43 | 44 | public $d1; 45 | private $d2; 46 | protected $d3; 47 | 48 | public function __construct() { 49 | } 50 | 51 | public function set($foo) { 52 | $this->d1 = $foo; 53 | $this->d2 = $foo; 54 | $this->d3 = $foo; 55 | } 56 | } 57 | 58 | if(!extension_loaded('igbinary')) { 59 | dl('igbinary.' . PHP_SHLIB_SUFFIX); 60 | } 61 | 62 | $output = ''; 63 | 64 | function open($path, $name) { 65 | return true; 66 | } 67 | 68 | function close() { 69 | return true; 70 | } 71 | 72 | function read($id) { 73 | global $output; 74 | $output .= "read\n"; 75 | $a = new Bar(); 76 | $b = new Foo($a); 77 | $a->set($b); 78 | $session = array('old' => $b); 79 | return igbinary_serialize($session); 80 | } 81 | 82 | function write($id, $data) { 83 | global $output; 84 | $output .= "write: "; 85 | $output .= substr(bin2hex($data), 8). "\n"; 86 | return true; 87 | } 88 | 89 | function destroy($id) { 90 | return true; 91 | } 92 | 93 | function gc($time) { 94 | return true; 95 | } 96 | 97 | ini_set('session.serialize_handler', 'igbinary'); 98 | 99 | session_set_save_handler('open', 'close', 'read', 'write', 'destroy', 'gc'); 100 | 101 | session_start(); 102 | 103 | $_SESSION['test'] = "foobar"; 104 | $a = new Bar(); 105 | $b = new Foo($a); 106 | $a->set($b); 107 | $_SESSION['new'] = $a; 108 | 109 | session_write_close(); 110 | 111 | echo $output; 112 | 113 | /* 114 | * you can add regression tests for your extension here 115 | * 116 | * the output of your test code has to be equal to the 117 | * text in the --EXPECT-- section below for the tests 118 | * to pass, differences between the output and the 119 | * expected text are interpreted as failure 120 | * 121 | * see php5/README.TESTING for further information on 122 | * writing regression tests 123 | */ 124 | ?> 125 | --EXPECT-- 126 | read 127 | write: 140311036f6c641703466f6f1403110700466f6f0064311703426172140311026431220111070042617200643222011105002a00643322011105002a00643222021102643322021104746573741106666f6f62617211036e65771a0314030e041a0114030e0222030e0722030e0822030e0522040e062204 128 | -------------------------------------------------------------------------------- /tests/igbinary_029.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Igbinary module info 3 | --SKIPIF-- 4 | 7 | --FILE-- 8 | enabled 21 | igbinary version => %s 22 | igbinary AP%s serializer ABI => %s 23 | igbinary session support => %s 24 | igbinary.compact_strings => %s => %s 25 | -------------------------------------------------------------------------------- /tests/igbinary_030.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Unserialize invalid data 3 | --SKIPIF-- 4 | 10, "foo"), 15 | true, 16 | false, 17 | 0.187182, 18 | "dakjdh98389\000", 19 | null, 20 | (object)array(1,2,3), 21 | ); 22 | 23 | error_reporting(0); 24 | foreach ($datas as $data) { 25 | $str = igbinary_serialize($data); 26 | $len = strlen($str); 27 | 28 | // truncated 29 | for ($i = 0; $i < $len - 1; $i++) { 30 | $v = igbinary_unserialize(substr($str, 0, $i)); 31 | if (is_object($data) && $v !== null && $v == $data) { 32 | continue; 33 | } elseif ($v !== null && $v != FALSE && $v !== $data) { 34 | echo "output at $i:\n"; 35 | var_dump($v); 36 | echo "vs.\n"; 37 | var_dump($data); 38 | } 39 | } 40 | 41 | // padded 42 | $str .= "98398afa\000y21_ "; 43 | $v = igbinary_unserialize($str); 44 | if ($v !== $data && !(is_object($data) && $v == $data)) { 45 | echo "padded should get original\n"; 46 | var_dump($v); 47 | echo "vs.\n"; 48 | var_dump($data); 49 | } 50 | } 51 | 52 | --EXPECT-- 53 | -------------------------------------------------------------------------------- /tests/igbinary_031.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Object Serializable interface throws exceptions 3 | --SKIPIF-- 4 | --FILE-- 5 | a = $a; 23 | $this->b = $b; 24 | } 25 | 26 | public function serialize() { 27 | $c = self::$count++; 28 | echo "call serialize, ", ($this->a ? "throw" : "no throw"),"\n"; 29 | if ($this->a) { 30 | throw new Exception("exception in serialize $c"); 31 | } 32 | return pack('NN', $this->a, $this->b); 33 | } 34 | 35 | public function unserialize($serialized) { 36 | $tmp = unpack('N*', $serialized); 37 | $this->__construct($tmp[1], $tmp[2]); 38 | $c = self::$count++; 39 | echo "call unserialize, ", ($this->b ? "throw" : "no throw"),"\n"; 40 | if ($this->b) { 41 | throw new Exception("exception in unserialize $c"); 42 | } 43 | } 44 | } 45 | 46 | $a = new Obj(1, 0); 47 | $a = new Obj(0, 0); 48 | $b = new Obj(0, 0); 49 | $c = new Obj(1, 0); 50 | $d = new Obj(0, 1); 51 | 52 | echo "a, a, c\n"; 53 | try { 54 | test(array($a, $a, $c)); 55 | } catch (Exception $e) { 56 | if (version_compare(phpversion(), "5.3.0", ">=")) { 57 | if ($e->getPrevious()) { 58 | $e = $e->getPrevious(); 59 | } 60 | } 61 | 62 | echo $e->getMessage(), "\n"; 63 | } 64 | 65 | echo "b, b, d\n"; 66 | 67 | try { 68 | test(array($b, $b, $d)); 69 | } catch (Exception $e) { 70 | if (version_compare(phpversion(), "5.3.0", ">=")) { 71 | if ($e->getPrevious()) { 72 | $e = $e->getPrevious(); 73 | } 74 | } 75 | 76 | echo $e->getMessage(), "\n"; 77 | } 78 | 79 | --EXPECT-- 80 | a, a, c 81 | call serialize, no throw 82 | call serialize, throw 83 | exception in serialize 2 84 | b, b, d 85 | call serialize, no throw 86 | call serialize, no throw 87 | call unserialize, no throw 88 | call unserialize, throw 89 | exception in unserialize 6 90 | -------------------------------------------------------------------------------- /tests/igbinary_032.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Object test, __sleep and __wakeup exceptions 3 | --SKIPIF-- 4 | a = $a; 23 | $this->b = $b; 24 | } 25 | 26 | function __sleep() { 27 | $c = self::$count++; 28 | if ($this->a) { 29 | throw new Exception("exception in __sleep $c"); 30 | } 31 | return array('a', 'b'); 32 | } 33 | 34 | function __wakeup() { 35 | $c = self::$count++; 36 | if ($this->b) { 37 | throw new Exception("exception in __wakeup $c"); 38 | } 39 | $this->b = $this->a * 3; 40 | } 41 | } 42 | 43 | 44 | $a = new Obj(1, 0); 45 | $b = new Obj(0, 1); 46 | $c = new Obj(0, 0); 47 | 48 | try { 49 | test($a); 50 | } catch (Exception $e) { 51 | echo $e->getMessage(), "\n"; 52 | } 53 | 54 | try { 55 | test($b); 56 | } catch (Exception $e) { 57 | echo $e->getMessage(), "\n"; 58 | } 59 | 60 | try { 61 | test($c); 62 | } catch (Exception $e) { 63 | echo $e->getMessage(), "\n"; 64 | } 65 | 66 | /* 67 | * you can add regression tests for your extension here 68 | * 69 | * the output of your test code has to be equal to the 70 | * text in the --EXPECT-- section below for the tests 71 | * to pass, differences between the output and the 72 | * expected text are interpreted as failure 73 | * 74 | * see php5/README.TESTING for further information on 75 | * writing regression tests 76 | */ 77 | ?> 78 | --EXPECT-- 79 | exception in __sleep 0 80 | exception in __wakeup 2 81 | -------------------------------------------------------------------------------- /tests/igbinary_033.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Object test, cyclic references 3 | --SKIPIF-- 4 | parent = null; 17 | $this->children = array(); 18 | } 19 | 20 | public function addChild(Foo $obj) { 21 | $this->children[] = $obj; 22 | $obj->setParent($this); 23 | } 24 | 25 | public function setParent(Foo $obj) { 26 | $this->parent = $obj; 27 | } 28 | } 29 | 30 | $obj1 = new Foo(); 31 | 32 | for ($i = 0; $i < 10; $i++) { 33 | $obj = new Foo(); 34 | $obj1->addChild($obj); 35 | } 36 | 37 | $o = igbinary_unserialize(igbinary_serialize($obj1->children)); 38 | 39 | foreach ($obj1->children as $k => $v) { 40 | $obj_v = $v; 41 | $o_v = $o[$k]; 42 | 43 | echo gettype($obj_v), "\t", gettype($o_v), "\n"; 44 | } 45 | --EXPECT-- 46 | object object 47 | object object 48 | object object 49 | object object 50 | object object 51 | object object 52 | object object 53 | object object 54 | object object 55 | object object 56 | -------------------------------------------------------------------------------- /tests/igbinary_034.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Unserialize invalid random data 3 | --SKIPIF-- 4 | 10, "foo"), 15 | true, 16 | false, 17 | 0.187182, 18 | "dakjdh98389\000", 19 | null, 20 | (object)array(1,2,3), 21 | ); 22 | 23 | error_reporting(0); 24 | foreach ($datas as $data) { 25 | $str = igbinary_serialize($data); 26 | $len = strlen($str); 27 | 28 | for ($j = 0; $j < 200; $j++) { 29 | for ($i = 0; $i < $len - 1; $i++) { 30 | $sub = substr($str, 0, $i); 31 | $sub .= mcrypt_create_iv(30, MCRYPT_DEV_URANDOM); 32 | $php_errormsg = null; 33 | $v = igbinary_unserialize($sub); 34 | } 35 | } 36 | } 37 | 38 | --EXPECT-- 39 | -------------------------------------------------------------------------------- /tests/igbinary_040.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | b0rked random data test 3 | --SKIPIF-- 4 | --FILE-- 5 | 43 | --EXPECT-- 44 | -------------------------------------------------------------------------------- /tests/igbinary_041.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for double NaN, Inf, -Inf, 0, and -0. IEEE 754 doubles 3 | --FILE-- 4 | 9 | --INI-- 10 | igbinary.compact_strings=Off 11 | --FILE-- 12 | $object) { 31 | if (!isset($actual_array[$key])) { 32 | $error = 'ERROR'; 33 | echo "Key $key is missing from result.\n"; 34 | echo "Expected key/value:\n"; 35 | var_dump($key, $object); 36 | var_dump($object); 37 | 38 | break; 39 | } 40 | 41 | if (!is_object($actual_array[$key]) || 42 | get_class($object) !== get_class($actual_array[$key])) { 43 | $error = 'ERROR'; 44 | echo "Array mismatch on $key\n"; 45 | echo "Expected key/value:\n"; 46 | var_dump($key, $object); 47 | echo "Actual key/value:\n"; 48 | var_dump($key, $actual_array[$key]); 49 | 50 | break; 51 | } 52 | 53 | } 54 | 55 | echo $error, "\n"; 56 | 57 | --EXPECT-- 58 | OK 59 | -------------------------------------------------------------------------------- /tests/igbinary_044.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for double extremes 3 | --FILE-- 4 | getVersion(), '3.1.7', '<')) { 11 | echo "skip require APC version 3.1.7 or above"; 12 | } 13 | 14 | --INI-- 15 | apc.enable_cli=1 16 | apc.serializer=igbinary 17 | --FILE-- 18 | 34 | int(10) 35 | } 36 | -------------------------------------------------------------------------------- /tests/igbinary_045b.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | APCu serializer registration 3 | --SKIPIF-- 4 | getVersion(), '4.0.2', '<')) { 11 | echo "skip require APCu version 4.0.2 or above"; 12 | } 13 | 14 | --INI-- 15 | apc.enable_cli=1 16 | apc.serializer=igbinary 17 | --FILE-- 18 | 34 | int(10) 35 | } 36 | -------------------------------------------------------------------------------- /tests/igbinary_046.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Correctly unserialize scalar refs. 3 | --SKIPIF-- 4 | --INI-- 5 | igbinary.compact_strings = On 6 | --FILE-- 7 | 21 | &string(1) "V" 22 | [1]=> 23 | &string(1) "V" 24 | [2]=> 25 | &string(1) "V" 26 | [3]=> 27 | &string(1) "V" 28 | } 29 | -------------------------------------------------------------------------------- /tests/igbinary_047.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for serialization handler, SessionHandlerInterface 3 | --SKIPIF-- 4 | = 5.4.0) 6 | if (version_compare(phpversion(), "5.4.0", "<")) { 7 | exit("skip php version less than 5.4.x"); 8 | } 9 | 10 | if (!extension_loaded('session')) { 11 | exit('skip session extension not loaded'); 12 | } 13 | 14 | ob_start(); 15 | phpinfo(INFO_MODULES); 16 | $str = ob_get_clean(); 17 | 18 | $array = explode("\n", $str); 19 | $array = preg_grep('/^igbinary session support.*yes/', $array); 20 | if (!$array) { 21 | exit('skip igbinary session handler not available'); 22 | } 23 | 24 | 25 | --FILE-- 26 | 96 | --EXPECT-- 97 | bool(true) 98 | read 99 | wrote: 14021103666f6f06011104746573741106666f6f626172 100 | -------------------------------------------------------------------------------- /tests/igbinary_bug54662.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Nested objects cause segfault, php bug #54662 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | append(new Storage); 22 | 23 | $ser = igbinary_serialize($collection); 24 | $new_collection = igbinary_unserialize($ser); 25 | 26 | var_dump($new_collection[0]->storage); 27 | --EXPECT-- 28 | string(8) "a string" 29 | -------------------------------------------------------------------------------- /tests/igbinary_unserialize_v1_compatible.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Unserialize backwards compatible with v1. 3 | --SKIPIF-- 4 | --FILE-- 5 | 'b:1;', 9 | 'type' => 'boolean', 10 | 'description' => 'bool true', 11 | 'data' => 'AAAAAQU=', 12 | 'version' => 1, 13 | ), 14 | array( 15 | 'var' => 'b:0;', 16 | 'type' => 'boolean', 17 | 'description' => 'bool false', 18 | 'data' => 'AAAAAQQ=', 19 | 'version' => 1, 20 | ), 21 | array( 22 | 'var' => 'd:1.2881887378882661554513333612703718245029449462890625;', 23 | 'type' => 'double', 24 | 'description' => 'double', 25 | 'data' => 'AAAAAQw/9Jxry0Tj0Q==', 26 | 'version' => 1, 27 | ), 28 | array( 29 | 'var' => 'i:29913;', 30 | 'type' => 'integer', 31 | 'description' => 'int', 32 | 'data' => 'AAAAAQh02Q==', 33 | 'version' => 1, 34 | ), 35 | array( 36 | 'var' => 'N;', 37 | 'type' => 'NULL', 38 | 'description' => 'null', 39 | 'data' => 'AAAAAQA=', 40 | 'version' => 1, 41 | ), 42 | array( 43 | 'var' => 's:0:"";', 44 | 'type' => 'string', 45 | 'description' => 'string', 46 | 'data' => 'AAAAAQ0=', 47 | 'version' => 1, 48 | ), 49 | array( 50 | 'var' => 's:13:"asdf' . "\0" . 'asdfasdf";', 51 | 'type' => 'string', 52 | 'description' => 'string', 53 | 'data' => 'AAAAARENYXNkZgBhc2RmYXNkZg==', 54 | 'version' => 1, 55 | ), 56 | array( 57 | 'var' => 'a:4:{i:0;i:1;i:1;i:2;i:2;i:3;i:3;i:4;}', 58 | 'type' => 'array', 59 | 'description' => 'array', 60 | 'data' => 'AAAAARQEBgAGAQYBBgIGAgYDBgMGBA==', 61 | 'version' => 1, 62 | ), 63 | array( 64 | 'var' => 'O:8:"stdClass":4:{i:0;i:1;i:1;i:2;i:2;i:3;i:3;i:4;}', 65 | 'var_e' => (object)array(1, 2, 3, 4), 66 | 'type' => 'object', 67 | 'description' => 'object', 68 | 'data' => 'AAAAARcIc3RkQ2xhc3MUBAYABgEGAQYCBgIGAwYDBgQ=', 69 | 'version' => 1, 70 | ), 71 | array( 72 | 'var' => 'a:2:{i:0;a:3:{i:0;s:1:"a";i:1;s:1:"b";i:2;s:1:"c";}i:1;R:2;}', 73 | 'type' => 'array', 74 | 'description' => 'reference', 75 | 'data' => 'AAAAARQCBgAUAwYAEQFhBgERAWIGAhEBYwYBAQE=', 76 | 'version' => 1, 77 | ), 78 | ); 79 | 80 | $all_passed = true; 81 | foreach ($data as $item) { 82 | if (isset($item['var_e'])) { 83 | $var = $item['var_e']; 84 | } else { 85 | $var = unserialize($item['var']); 86 | } 87 | $unserialized = igbinary_unserialize(base64_decode($item['data'])); 88 | 89 | ob_start(); 90 | var_dump($var); 91 | $dump_expected = ob_get_clean(); 92 | 93 | ob_start(); 94 | var_dump($unserialized); 95 | $dump_actual = ob_get_clean(); 96 | 97 | // replace all object ids to 0 98 | $dump_expected = preg_replace('/#\d+/', '#0', $dump_expected); 99 | $dump_actual = preg_replace('/#\d+/', '#0', $dump_actual); 100 | 101 | if ($dump_expected !== $dump_actual) { 102 | if ($item['description'] == 'reference') { 103 | echo "reference deserialization works, but the result is not a reference.\n"; 104 | continue; 105 | } 106 | 107 | echo "Differing unserialized: {$item['description']}\n"; 108 | echo "Expected:\n", $dump_expected, "\n"; 109 | echo "Actual:\n", $dump_actual, "\n"; 110 | } 111 | } 112 | 113 | echo $all_passed ? 'OK' : 'ERROR', "\n"; 114 | 115 | --EXPECT-- 116 | reference deserialization works, but the result is not a reference. 117 | OK 118 | --------------------------------------------------------------------------------