package.xml0000644000076500000240000010677714704245235012033 0ustar mikestaff memcached pecl.php.net PHP extension for interfacing with memcached via libmemcached library This extension uses libmemcached library to provide API for communicating with memcached servers. Andrei Zmievski andrei andrei@php.net yes Mikko Koppanen mkoppanen mkoppanen@php.net yes Aaron Stone sodabrew aaron@serendipity.cx yes Remi Collet remi remi@php.net yes Michael Wallner mike mike@php.net yes 2024-10-17 3.3.0 3.3.0 stable stable PHP - Add #515 option to locally enforce payload size limit - Add #539 zstd support - Add #540 compression_level option - Mark password as a sensitive param for PHP 8.2 - Upgrade Windows libmemcached to v1.1.4 - Fix Windows PHP 8 compatibility - Fix #518 Windows msgpack support - Fix #522 signed integer overflow - Fix #523 incorrect PHP reflection type for Memcached::cas $cas_token - Fix #546 don't check key automatically, unless client-side verify_key is enabled - Fix #555 incompatible pointer types (32-bit) 7.0.0 1.4.0b1 igbinary 2.0 msgpack 2.0 memcached 2022-03-24 3.2.0 3.2.0 stable stable PHP - PHP 8.0 and 8.1 support - store_retry_count is no more set explicitly (#452) - fix MemcachedServer (libmemcached-awesome is recommended) - code cleanup - fix windows build 2019-12-03 3.1.5 3.0.0 stable stable PHP PHP 7.0 - 7.1 - 7.2 - 7.3 - 7.4 release of memcached extension. Note that support for libmemcached 0.x series has been discontinued and the oldest actively tested version is 1.0.8. It is highly recommended to use version 1.0.18 of libmemcached. Fixes * Fix build with PHP 7.4 release due to ulong typedef removal (#445) stable stable 3.1.4 3.0.0 2019-10-06 PHP 7.0 - 7.1 - 7.2 - 7.3 - 7.4 release of memcached extension. Note that support for libmemcached 0.x series has been discontinued and the oldest actively tested version is 1.0.8. It is highly recommended to use version 1.0.18 of libmemcached. Fixes * Test on PHP 7.4 as well as 8.0 (#440) * Fix segfault for unknown memcached flags (#431) * Update documented defaults for sess_lock_retries (#432) * Remove stray instances of the TSRMLS_CC macro for PHP 8 compatibility (#444) stable stable 3.1.3 3.0.0 2018-12-22 PHP 7.0 - 7.1 - 7.2 - 7.3 release of memcached extension. Note that support for libmemcached 0.x series has been discontinued and the oldest actively tested version is 1.0.8. It is highly recommended to use version 1.0.18 of libmemcached. Fixes * Fix --disable-memcached-session by ifdef-ing session INI handler callbacks (#396, #420) stable stable 3.1.2 3.0.0 2018-12-22 PHP 7.0 - 7.1 - 7.2 - 7.3 release of memcached extension. Note that support for libmemcached 0.x series has been discontinued and the oldest actively tested version is 1.0.8. It is highly recommended to use version 1.0.18 of libmemcached. Fixes * Fix --enable-memcached-protocol was set to yes by default, reverted to no (#418) stable stable 3.1.1 3.0.0 2018-12-21 PHP 7.0 - 7.1 - 7.2 - 7.3 release of memcached extension. Note that support for libmemcached 0.x series has been discontinued and the oldest actively tested version is 1.0.8. It is highly recommended to use version 1.0.18 of libmemcached. Fixes * Fix --disable-memcached-sasl and --disable-memcached-session replaced by --enable variants (#416) stable stable 3.1.0 3.0.0 2018-12-21 PHP 7.0 - 7.1 - 7.2 - 7.3 release of memcached extension. Note that support for libmemcached 0.x series has been discontinued and the oldest actively tested version is 1.0.8. It is highly recommended to use version 1.0.18 of libmemcached. New * Support for PHP 7.3 (#385, #390) * Add INI setting to choose session consistent hash (ketama or ketama_weighted) (#344, #392) * Add support for libmemcached encryption (#345, #381) * Add error reporting to session code (#165) * Expose build configuration via PECL (#383) Fixes * Fix hanging getStats() when binary protocol and non-blocking are both enabled (#348) * Fix session persistence by checking memcached behavior values before setting (#379) * Fix memcached.sess_persistent not working with memcached.sess_binary_protocol = On (#375) * Configure warns if libmemcached needs sasl.h (#341, #380) * Resolve various INI deviations in 3.0.3 (#351) * Turn off sess_binary_protocol by default with older libmemcached (#330) Changes * Impove Windows builds (#411) * Support Homebrew ZLIB path (#410) * Remove forgotten unused comment about -lpthread (#406) * Git ignore configure.ac (#405) * Replace obsolete macros AC_TRY_FOO with AC_FOO_IFELSE (#403) * Remove unused defines (#354) * Change session_lock and sess_prefix default ini values (#340, #350) * Use new fast_zpp parameter parsing API (#302, #311) stable stable 3.0.4 3.0.0 2017-11-20 PHP 7.0 - 7.1 - 7.2 release of memcached extension. Note that support for libmemcached 0.x series has been discontinued and the oldest actively tested version is 1.0.2. It is highly recommended to use version 1.0.18 of libmemcached. Fixes * Fix corrupted interned strings (#338) * Fix unit tests for compatibility with PHP 7.2 (#358, #359) * Fix \x0a in key name locks up connection and triggers a fatal timeout error (#339) * Fix missing optional parameter getStats($type) (#337) * Fix typo in skip message (#331) * Fix build warnings (#329) * Document GET_EXTENDED flag, add/rename other missing/misnamed constants (#335) stable stable 3.0.3 3.0.0 2017-02-19 PHP7 release of memcached extension. Note that support for libmemcached 0.x series has been discontinued and the oldest actively tested version is 1.0.2. It is highly recommended to use version 1.0.18 of libmemcached. Fixes * Fix crash when checking session data with older versions of libmemcached (#328) * Fix crash due to zend_mm_corrupted when fetching session data (#327) stable stable 3.0.2 3.0.0 2016-02-12 PHP7 release of memcached extension. Note that support for libmemcached 0.x series has been discontinued and the oldest actively tested version is 1.0.2. It is highly recommended to use version 1.0.18 of libmemcached. Fixes * Update warning for touch command in binary protocol mode with libmemcached below 1.0.18 (#322) * Add tests for 64-bit increment/decrement/incrementByKey/decrementByKey (#321) * Fix tests for 32-bit increment/decrement/incrementByKey/decrementByKey (#319) stable stable 3.0.1 3.0.0 2016-02-07 PHP7 release of memcached extension. Note that support for libmemcached 0.x series has been discontinued and the oldest actively tested version is 1.0.2. It is highly recommended to use version 1.0.18 of libmemcached. Fixes * Add API entries for flushBuffers() and getAllKeys() (#316) * Ignore specific errors from memcached_dump for getAllKeys() with newer memcached servers (#315) * Fix compiling with memcached binary protocol enabled (#312) * Restore php_libmemcached_compat with workaround for missing memcached_exists (#314) * Travis CI purge old versions of memcached and libmemcached (#309) stable stable 3.0.0 3.0.0 2016-01-27 PHP7 release of memcached extension. Note that support for libmemcached 0.x series has been discontinued and the oldest actively tested version is 1.0.2. It is highly recommended to use version 1.0.18 of libmemcached. API * The method signature of get, getByKey, getMulti, and getMultiByKey changed. * get* and getMulti* commands no longer take cas or user flags parameters. * get* and getMulti* commands now take the Memcached::GET_EXTENDED flag to retrieve user flags and cas tokens. * Fixes getStats command to return all stats from all servers * Fixes allKeys command behaviour * Fixes error where cache callback for get command was not setting expiration time properly * Added server type to server list * Remove use_sasl ini-variable and initialise sasl as needed * CAS tokens are returned as integers and they overflow to strings as needed Session handler * The session memcached protocol config name was changed, and the default protocol was changed from text to binary protocol. If your memcached setup does not support the binary protocol(e.g. if using tw * Session lock algorithm updated (new ini-values memcached.sess_lock_wait_min, memcached.sess_lock_wait_max and memcached.sess_lock_retries) * Session extension uses PHP allocators (still some work to do on the rest of the extension) * Ini-values take effect during session_start or session_regenerate_id * Fixes crash with session_regenerate_id (work-around for PHP bug) Tests * Fix several problematic tests alpha alpha 3.0.0a1 3.0.0 2016-02-22 PHP7 release of memcached extension. Note that support for libmemcached 0.x series has been discontinued and the oldest actively tested version is 1.0.2. It is highly recommended to use version 1.0.18 of libmemcached. Please note that this is a beta release and reporting any issues would be highly appreciated before we move closer to releasing stable version. API * get commands do not take cas or user flags parameters. * get and getMulti commands take Memcached::GET_EXTENDED flag to retrieve user flags and cas tokens * Fixes getStats command to return all stats from all servers * Fixes allKeys command behaviour * Fixes error where cache callback for get command was not setting expiration time properly * Added server type to server list * Remove use_sasl ini-variable and initialise sasl as needed * CAS tokens are returned as integers and they overflow to strings as needed Session handler * Session lock algorithm updated (new ini-values memcached.sess_lock_wait_min, memcached.sess_lock_wait_max and memcached.sess_lock_retries) * Session extension uses PHP allocators (still some work to do on the rest of the extension) * Ini-values take effect during session_start or session_regenerate_id * Fixes crash with session_regenerate_id (work-around for PHP bug) Tests * Fix several problematic tests stable stable 2.2.0 2.2.0 2014-04-01 - Added the OPT_SERVER_TIMEOUT_LIMIT behaviour beta stable 2.2.0RC1 2.2.0 2014-03-12 - Fixes incorrect size when compressing serialized objects - Fixes endianess of compressed values beta stable 2.2.0b1 2.2.0 2013-10-28 - Reinstate support for libememcached 0.x series - Added SASL support to session handler - Added Memcached::flushBuffers as per GH #78 - Fixes GH #54: Fixed UDP server adding with newer libmemcached - Fixed PHP bug #65334: (Segfault if uncompress value failed) - Fixes GH #14: get with cas token fails to fetch all results - Fixes GH #69: compiling on CentOS 6.4 with libmemcached 1.0.17 stable stable 2.1.0 2.1.0 2012-08-06 - Drop support for libmemcached 0.x series, now 1.0.x is required - Add support for virtual bucket distribution - Fix compilation against PHP 5.2 stable stable 2.0.1 2.0.1 2012-03-03 - Fix embedded version number to be not -dev stable stable 2.0.0 2.0.0 2012-03-02 - Add touch() and touchByKey() methods - Add resetServerList() and quit() methods - Support binary protocol in sessions - Make it work with libmemcached up to 1.0.4 - Test against PHP 5.4.0 beta beta 2.0.0b2 2.0.0b2 2011-06-24 - Add OPT_REMOVE_FAILED_SERVERS option. - Make it work with libmemcached up to 0.49. - Fix a case where invalid session ID could lock the script. - Improve session support: * Add support for libmemcached config string * Add persistence support via PERSISTENT=persistent_id prefix of the save_path - Add 3rd parameter to the __construct() that allows specification of libmemcached configuration string - Fix a possible crash in __construct() when using persistent connections - Add work-around a bug in libmemcached < 0.50 that causes truncation of last character of server key prefix - When using multiple servers implement transparent fail-over - Fix php_memc_cas_impl() implementation when server_key is not being used - Add support for incrementByKey() and decrementByKey() - Make increment/decrement initialize value when it is not available (when using binary protocol) beta beta 2.0.0b1 2.0.0b1 2011-03-12 - Change the return value for non-existing keys to be NULL rather than 'false', affects simple get only - Add fastlz library that provides better/faster payload compression - Add configure switch to enable/disable JSON serialization support - Add getAllKeys() method - Add deleteMulti() and deleteMultiByKey() methods - Add isPristine() and isPersistent() methods - Add setOptions() method to set multiple options at once - Add SERIALIZER_JSON_ARRAY type that decodes JSON payloads as arrays instead of objects - Add support for Unix domain socket connections - Add memcached.compression_threshold INI setting - Add memcached.compression_factor INI setting - Add memcached.compression_type INI setting - Implement a few speed optimizations - Many bug fixes and memory leaks plugged - Add several more tests - Add constants for libmemcached 0.37+: * Memcached::OPT_NUMBER_OF_REPLICAS * Memcached::OPT_RANDOMIZE_REPLICA_READ - Add 'on_new' callback to constructor - Add SASL support stable stable 1.0.2 1.0.2 2010-05-03 - Fix build for libmemcached-0.39 (memcached_server_list() issue) stable stable 1.0.1 1.0.1 2010-03-11 - Fix build for libmemcached-0.38. stable stable 1.0.0 1.0.0 2009-07-04 - First stable release. - Add getResultMessage() method. - Fix OPT_RECV_TIMEOUT definition. - Initialize Session lock wait to max execution time (if max execution time is unlimited, default to 30 seconds). beta beta 0.2.0 0.2.0 2009-06-04 - Refactor the way payload types are stored in memcached flags to optimize the structure and allow for future expansion. WARNING! You have to flush the cache when upgrading from an older version. - Add JSON serializer support, requires PHP 5.2.10+. - Add HAVE_JSON and HAVE_IGBINARY class constants that indicate whether the respective serializers are available. - Add 'flags' parameter to getMulti() and getMultiByKey(). - Add GET_PRESERVE_ORDER class constant that can be used with abovementioned flags parameter to make the order of the keys in the response match the request. - Fix an issue with retrieving 0-length payloads (FALSE boolean value). - Add several tests. beta beta 0.1.5 0.1.5 2009-03-31 - Implement getVersion(). - Add support for preserving boolean value types. - Fix crash when child class does not call constructor. - Fix bug #16084 (Crash when addServers is called with an associative array). - ZTS compilation fixes. beta beta 0.1.4 0.1.4 2009-02-13 - Fix compilation against PHP 5.3. - Add support for 'igbinary' serializer (Oleg Grenrus) beta beta 0.1.3 0.1.3 2009-02-06 - Bludgeon bug #15896 (Memcached setMulti error) into submission. beta beta 0.1.2 0.1.2 2009-02-06 - Fix bug #15896 (Memcached setMulti error). - Check for empty key in getServerByKey(). - Allow passing 'null' for callbacks. - get() with cas token fetching wasn't erroring out properly. - Rename certain parameters in the API to be more clear. - Allow only strings as the append/prepend value. - Remove expiration parameter from append/prepend. beta beta 0.1.1 0.1.1 2009-02-02 - Add OPT_LIBKETAMA_COMPATIBLE option. - Implement addServers() method. - Swap internal compressed and serialized flags to be compatible with other clients. beta beta 0.1.0 0.1.0 2009-01-29 - Initial PECL release memcached-3.3.0/tests/skipif.inc0000644000076500000240000000061214704245235015362 0ustar mikestaff --FILE-- --EXPECT-- memcached extension is available memcached-3.3.0/tests/version.phpt0000644000076500000240000000041514704245235015765 0ustar mikestaff--TEST-- Get version --SKIPIF-- --FILE-- getVersion ()); echo "OK" . PHP_EOL; ?> --EXPECTF-- array(1) { ["%s:%d"]=> string(%d) "%d.%d.%d" } OK memcached-3.3.0/tests/bug_16084.phpt0000644000076500000240000000065514704245235015625 0ustar mikestaff--TEST-- Memcached: Bug #16084 (Crash when addServers is called with an associative array) --SKIPIF-- --FILE-- array ( 'KEYHERE' => 'localhost', 11211, 3 ), ); $m = new memcached(); var_dump($m->addServers($servers)); $list = $m->getServerList(); var_dump ($list[0]["host"], $list[0]["port"]); echo "OK"; ?> --EXPECT-- bool(true) string(9) "localhost" int(11211) OK memcached-3.3.0/tests/bug_16959.phpt0000644000076500000240000000237314704245235015637 0ustar mikestaff--TEST-- Memcached: Bug #16959 (getMulti + BINARY_PROTOCOL problem) --SKIPIF-- --FILE-- true )); $cache->set('key_0', 'value0'); $cache->set('key_0_additional', 'value0_additional'); // -------------- NORMAL echo "NORMAL\n"; $keys = array( 'key_0', 'key_0_additional' ); $values = $cache->getMulti($keys); echo $cache->getResultMessage(), "\n"; echo "Values:\n"; foreach ($values as $k => $v) { var_dump($k); var_dump($v); var_dump($values[$k]); } // --------------- REVERSED KEY ORDER echo "REVERSED KEY ORDER\n"; $keys = array( 'key_0_additional', 'key_0' ); $values = $cache->getMulti($keys); echo $cache->getResultMessage(), "\n"; echo "Values:\n"; foreach ($values as $k => $v) { var_dump($k); var_dump($v); var_dump($values[$k]); } --EXPECT-- NORMAL SUCCESS Values: string(5) "key_0" string(6) "value0" string(6) "value0" string(16) "key_0_additional" string(17) "value0_additional" string(17) "value0_additional" REVERSED KEY ORDER SUCCESS Values: string(16) "key_0_additional" string(17) "value0_additional" string(17) "value0_additional" string(5) "key_0" string(6) "value0" string(6) "value0" memcached-3.3.0/tests/bug_17137.phpt0000644000076500000240000000163114704245235015620 0ustar mikestaff--TEST-- Change prefix, pecl bug #17137 --SKIPIF-- --FILE-- true, Memcached::OPT_PREFIX_KEY => 'prefix1', )); $memcache2 = memc_get_instance (array ( Memcached::OPT_BINARY_PROTOCOL => true, Memcached::OPT_PREFIX_KEY => 'prefix2', )); var_dump($memcache->getOption(Memcached::OPT_PREFIX_KEY)); var_dump($memcache->set('test', "val_prefix1", 120)); var_dump($memcache->get('test')); var_dump($memcache2->getOption(Memcached::OPT_PREFIX_KEY)); var_dump($memcache2->set('test', "val_prefix2", 120)); var_dump($memcache2->get('test')); var_dump($memcache->get('test')); --EXPECT-- string(7) "prefix1" bool(true) string(11) "val_prefix1" string(7) "prefix2" bool(true) string(11) "val_prefix2" string(11) "val_prefix1" memcached-3.3.0/tests/bug_18639.phpt0000644000076500000240000000062214704245235015627 0ustar mikestaff--TEST-- Memcached::getServerByKey(): Bug pecl#18639 (Segfault in getServerByKey) --SKIPIF-- --FILE-- set('test', 'test1')); var_dump($m->getServerByKey('1')); --EXPECTF-- bool(true) array(3) { ["host"]=> string(9) "%s" ["port"]=> int(%d) ["weight"]=> int(%r[01]%r) } memcached-3.3.0/tests/callback_exception.phpt0000644000076500000240000000160714704245235020116 0ustar mikestaff--TEST-- make sure that callback exception behaves correctly --SKIPIF-- --FILE-- --EXPECT-- success success empty_cb called success OK memcached-3.3.0/tests/callback_exception_2.phpt0000644000076500000240000000172014704245235020333 0ustar mikestaff--TEST-- Callback initializer throws and dies --SKIPIF-- --FILE-- isPersistent()); throw new RuntimeException('Cb exception'); } function init_cb_die($m, $id) { echo "ran quitting cb\n"; die("quit in cb"); } error_reporting(0); echo "cb with exception\n"; try { $m1 = new Memcached(null, 'init_cb'); } catch (RuntimeException $e) { echo $e->getMessage(), "\n"; } echo "cb persistent with exception\n"; try { $m2 = new Memcached('foo', 'init_cb'); } catch (RuntimeException $e) { echo $e->getMessage(), "\n"; } echo "cb persistent dies\n"; try { $m3 = new Memcached('bar', 'init_cb_die'); } catch (RuntimeException $e) { echo $e->getMessage(), "\n"; } echo "not run\n"; --EXPECT-- cb with exception ran throwing cb bool(false) Cb exception cb persistent with exception ran throwing cb bool(true) Cb exception cb persistent dies ran quitting cb quit in cb memcached-3.3.0/tests/cas.phpt0000644000076500000240000000062614704245235015052 0ustar mikestaff--TEST-- Memcached fetch cas & set cas --SKIPIF-- --FILE-- delete('cas_test'); $m->set('cas_test', 'hello'); $cas_token = $m->get('cas_test', null, Memcached::GET_EXTENDED)['cas']; $v = $m->cas($cas_token, 'cas_test', 0); if ($v != true) { echo "CAS failed"; } echo "OK\n"; ?> --EXPECT-- OKmemcached-3.3.0/tests/cas_multi.phpt0000644000076500000240000000176414704245235016270 0ustar mikestaff--TEST-- Memcached multi fetch cas & set cas --SKIPIF-- --FILE-- 1, 'cas_test_2' => 2, ); foreach ($data as $key => $v) { $m->delete($key); } $m->setMulti($data, 10); $actual = $m->getMulti(array_keys($data), Memcached::GET_EXTENDED); foreach ($actual as $key => $v) { if (is_null($v['cas'])) { echo "missing cas token(s)\n"; echo "data: "; var_dump($data); echo "actual data: "; var_dump($actual); return; } $v = $m->cas($v['cas'], $key, 11); if (!$v) { echo "Error setting key: $key value: 11 with CAS: ", $v['cas'], "\n"; return; } $v = $m->get($key); if ($v !== 11) { echo "Wanted $key to be 11, value is: "; var_dump($v); return; } } if (array_keys($actual) !== array_keys($data)) { echo "missing value(s)\n"; echo "data :"; var_dump($data); echo "actual data: "; var_dump($actual); return; } echo "OK\n"; ?> --EXPECT-- OKmemcached-3.3.0/tests/check_if_persistent.phpt0000644000076500000240000000143314704245235020314 0ustar mikestaff--TEST-- Check if persistent object is persistent --SKIPIF-- --FILE-- setOption(Memcached::OPT_PREFIX_KEY, "foo_"); var_dump($m1->isPersistent()); $m1 = new Memcached('id1'); var_dump($m1->isPersistent()); $m2 = new Memcached('id1'); var_dump($m2->isPersistent()); // this change affects $m1 $m2->setOption(Memcached::OPT_PREFIX_KEY, "bar_"); $m3 = new Memcached('id2'); var_dump($m3->isPersistent()); $m3 = new Memcached(); var_dump($m3->isPersistent()); // objects have the same resource, but they are not the same object. var_dump($m1 === $m2); var_dump($m1->getOption(Memcached::OPT_PREFIX_KEY)); --EXPECT-- bool(true) bool(true) bool(true) bool(true) bool(false) bool(false) string(4) "bar_" memcached-3.3.0/tests/check_if_pristine.phpt0000644000076500000240000000116514704245235017753 0ustar mikestaff--TEST-- Check if persistent object is new or an old persistent one --SKIPIF-- --FILE-- setOption(Memcached::OPT_PREFIX_KEY, "foo_"); var_dump($m1->isPristine()); $m1 = new Memcached('id1'); var_dump($m1->isPristine()); $m2 = new Memcached('id1'); var_dump($m2->isPristine()); // this change affects $m1 $m2->setOption(Memcached::OPT_PREFIX_KEY, "bar_"); $m3 = new Memcached('id2'); var_dump($m3->isPristine()); $m3 = new Memcached(); var_dump($m3->isPristine()); --EXPECT-- bool(true) bool(false) bool(false) bool(true) bool(true) memcached-3.3.0/tests/check_key.phpt0000644000076500000240000000737314704245235016237 0ustar mikestaff--TEST-- Memcached::checkKey() --SKIPIF-- --FILE-- false, Memcached::OPT_VERIFY_KEY => true )); $keys = [ 'foo', 'foo bar', str_repeat('a',65), str_repeat('b',250), str_repeat('c',251), 'Montréal', 'København', 'Düsseldorf', 'Kraków', 'İstanbul', 'ﺎﺨﺘﺑﺍﺭ PHP', '測試', 'Тестирование', 'پی ایچ پی کی جانچ ہو رہی ہے', 'Testataan PHP: tä', 'Að prófa PHP', 'د پی ایچ پی ازمول', 'Pruvà PHP' ]; foreach($keys as $key) { echo "Checking \"$key\"" . PHP_EOL; echo "MEMC_CHECK_KEY: "; var_dump($m->checkKey($key)); echo "libmemcached: "; var_dump($m->set($key, "this is a test")); var_dump($m->getResultMessage()); echo "\n"; } --EXPECT-- Checking "foo" MEMC_CHECK_KEY: bool(true) libmemcached: bool(true) string(7) "SUCCESS" Checking "foo bar" MEMC_CHECK_KEY: bool(false) libmemcached: bool(false) string(46) "A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE" Checking "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" MEMC_CHECK_KEY: bool(true) libmemcached: bool(true) string(7) "SUCCESS" Checking "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" MEMC_CHECK_KEY: bool(true) libmemcached: bool(true) string(7) "SUCCESS" Checking "ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" MEMC_CHECK_KEY: bool(false) libmemcached: bool(false) string(46) "A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE" Checking "Montréal" MEMC_CHECK_KEY: bool(false) libmemcached: bool(false) string(46) "A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE" Checking "København" MEMC_CHECK_KEY: bool(false) libmemcached: bool(false) string(46) "A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE" Checking "Düsseldorf" MEMC_CHECK_KEY: bool(false) libmemcached: bool(false) string(46) "A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE" Checking "Kraków" MEMC_CHECK_KEY: bool(false) libmemcached: bool(false) string(46) "A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE" Checking "İstanbul" MEMC_CHECK_KEY: bool(false) libmemcached: bool(false) string(46) "A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE" Checking "ﺎﺨﺘﺑﺍﺭ PHP" MEMC_CHECK_KEY: bool(false) libmemcached: bool(false) string(46) "A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE" Checking "測試" MEMC_CHECK_KEY: bool(false) libmemcached: bool(false) string(46) "A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE" Checking "Тестирование" MEMC_CHECK_KEY: bool(false) libmemcached: bool(false) string(46) "A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE" Checking "پی ایچ پی کی جانچ ہو رہی ہے" MEMC_CHECK_KEY: bool(false) libmemcached: bool(false) string(46) "A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE" Checking "Testataan PHP: tä" MEMC_CHECK_KEY: bool(false) libmemcached: bool(false) string(46) "A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE" Checking "Að prófa PHP" MEMC_CHECK_KEY: bool(false) libmemcached: bool(false) string(46) "A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE" Checking "د پی ایچ پی ازمول" MEMC_CHECK_KEY: bool(false) libmemcached: bool(false) string(46) "A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE" Checking "Pruvà PHP" MEMC_CHECK_KEY: bool(false) libmemcached: bool(false) string(46) "A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE" memcached-3.3.0/tests/clone.phpt0000644000076500000240000000050414704245235015377 0ustar mikestaff--TEST-- Test cloning --SKIPIF-- --FILE-- --FILE-- setOption(Memcached::OPT_COMPRESSION, false); } else { $m->setOption(Memcached::OPT_COMPRESSION, true); $m->setOption(Memcached::OPT_COMPRESSION_TYPE, get_compression($set_compression)); } $m->set($key, $value, 1800); $value_back = $m->get($key); var_dump($value === $value_back); } fetch_with_compression($m, 'hello01', $data, 'zlib', 1.3, 4); fetch_with_compression($m, 'hello02', $data, 'fastlz', 1.3, 4); fetch_with_compression($m, 'hello03', $data, '', 1.3, 4); fetch_with_compression($m, 'hello04', $short_data, 'zlib', 1.3, 4); fetch_with_compression($m, 'hello05', $short_data, 'fastlz', 1.3, 4); fetch_with_compression($m, 'hello06', $short_data, '', 1.3, 4); fetch_with_compression($m, 'hello11', $data, 'zlib', 0.3, 4); fetch_with_compression($m, 'hello12', $data, 'fastlz', 0.3, 4); fetch_with_compression($m, 'hello13', $data, '', 0.3, 4); fetch_with_compression($m, 'hello14', $short_data, 'zlib', 0.3, 4); fetch_with_compression($m, 'hello15', $short_data, 'fastlz', 0.3, 4); fetch_with_compression($m, 'hello16', $short_data, '', 0.3, 4); fetch_with_compression($m, 'hello21', $data, 'zlib', 1.3, 2000); fetch_with_compression($m, 'hello22', $data, 'fastlz', 1.3, 2000); fetch_with_compression($m, 'hello23', $data, '', 1.3, 2000); fetch_with_compression($m, 'hello24', $short_data, 'zlib', 1.3, 2000); fetch_with_compression($m, 'hello25', $short_data, 'fastlz', 1.3, 2000); fetch_with_compression($m, 'hello26', $short_data, '', 1.3, 2000); fetch_with_compression($m, 'hello31', $data, 'zlib', 0.3, 2000); fetch_with_compression($m, 'hello32', $data, 'fastlz', 0.3, 2000); fetch_with_compression($m, 'hello33', $data, '', 0.3, 2000); fetch_with_compression($m, 'hello34', $short_data, 'zlib', 0.3, 2000); fetch_with_compression($m, 'hello35', $short_data, 'fastlz', 0.3, 2000); fetch_with_compression($m, 'hello36', $short_data, '', 0.3, 2000); ?> --EXPECT-- len=[4877] set=[zlib] factor=[1.3] threshold=[4] bool(true) len=[4877] set=[fastlz] factor=[1.3] threshold=[4] bool(true) len=[4877] set=[] factor=[1.3] threshold=[4] bool(true) len=[7] set=[zlib] factor=[1.3] threshold=[4] bool(true) len=[7] set=[fastlz] factor=[1.3] threshold=[4] bool(true) len=[7] set=[] factor=[1.3] threshold=[4] bool(true) len=[4877] set=[zlib] factor=[0.3] threshold=[4] bool(true) len=[4877] set=[fastlz] factor=[0.3] threshold=[4] bool(true) len=[4877] set=[] factor=[0.3] threshold=[4] bool(true) len=[7] set=[zlib] factor=[0.3] threshold=[4] bool(true) len=[7] set=[fastlz] factor=[0.3] threshold=[4] bool(true) len=[7] set=[] factor=[0.3] threshold=[4] bool(true) len=[4877] set=[zlib] factor=[1.3] threshold=[2000] bool(true) len=[4877] set=[fastlz] factor=[1.3] threshold=[2000] bool(true) len=[4877] set=[] factor=[1.3] threshold=[2000] bool(true) len=[7] set=[zlib] factor=[1.3] threshold=[2000] bool(true) len=[7] set=[fastlz] factor=[1.3] threshold=[2000] bool(true) len=[7] set=[] factor=[1.3] threshold=[2000] bool(true) len=[4877] set=[zlib] factor=[0.3] threshold=[2000] bool(true) len=[4877] set=[fastlz] factor=[0.3] threshold=[2000] bool(true) len=[4877] set=[] factor=[0.3] threshold=[2000] bool(true) len=[7] set=[zlib] factor=[0.3] threshold=[2000] bool(true) len=[7] set=[fastlz] factor=[0.3] threshold=[2000] bool(true) len=[7] set=[] factor=[0.3] threshold=[2000] bool(true) memcached-3.3.0/tests/compression_types.phpt0000644000076500000240000000540614704245235020072 0ustar mikestaff--TEST-- Memcached compression test --SKIPIF-- --FILE-- setOption(Memcached::OPT_COMPRESSION, false); } else { $m->setOption(Memcached::OPT_COMPRESSION, true); $m->setOption(Memcached::OPT_COMPRESSION_TYPE, get_compression($set_compression)); } $m->set($key, $value, 1800); if (!$get_compression) { $m->setOption(Memcached::OPT_COMPRESSION, true); } else { $m->setOption(Memcached::OPT_COMPRESSION, true); $m->setOption(Memcached::OPT_COMPRESSION_TYPE, get_compression($get_compression)); } $value_back = $m->get($key); var_dump($value === $value_back); } fetch_with_compression($m, 'hello1', $data, 'zlib', 'zlib'); fetch_with_compression($m, 'hello2', $data, 'zlib', 'fastlz'); fetch_with_compression($m, 'hello3', $data, 'fastlz', 'fastlz'); fetch_with_compression($m, 'hello4', $data, 'fastlz', 'zlib'); fetch_with_compression($m, 'hello5', $data, '', 'zlib'); fetch_with_compression($m, 'hello6', $data, '', 'fastlz'); fetch_with_compression($m, 'hello7', $data, 'zlib', ''); fetch_with_compression($m, 'hello8', $data, 'fastlz', ''); fetch_with_compression($m, 'hello9', $data, '', ''); if (Memcached::HAVE_ZSTD) { fetch_with_compression($m, 'hello10', $data, 'zstd', 'zstd'); fetch_with_compression($m, 'hello11', $data, 'zstd', 'fastlz'); fetch_with_compression($m, 'hello12', $data, 'fastlz', 'zstd'); fetch_with_compression($m, 'hello13', $data, '', 'zstd'); fetch_with_compression($m, 'hello14', $data, 'zstd', ''); } else { echo << --EXPECT-- set=[zlib] get=[zlib] bool(true) set=[zlib] get=[fastlz] bool(true) set=[fastlz] get=[fastlz] bool(true) set=[fastlz] get=[zlib] bool(true) set=[] get=[zlib] bool(true) set=[] get=[fastlz] bool(true) set=[zlib] get=[] bool(true) set=[fastlz] get=[] bool(true) set=[] get=[] bool(true) set=[zstd] get=[zstd] bool(true) set=[zstd] get=[fastlz] bool(true) set=[fastlz] get=[zstd] bool(true) set=[] get=[zstd] bool(true) set=[zstd] get=[] bool(true) memcached-3.3.0/tests/conf_persist.phpt0000644000076500000240000000111714704245235016776 0ustar mikestaff--TEST-- Conf settings persist. --SKIPIF-- --FILE-- 'php' ), 'id1'); $m1->set('foo', 'bar'); for ($i = 1000; $i > 0; $i--) { $m1 = new Memcached('id1'); $rv = $m1->get('foo'); if ($rv !== 'bar') { echo "Expected bar got:"; var_dump($rv); die(); } $prefix = $m1->getOption(Memcached::OPT_PREFIX_KEY); if ($prefix !== 'php') { echo "Expected prefix php got:"; var_dump($prefix); die(); } } echo "OK\n"; ?> --EXPECT-- OKmemcached-3.3.0/tests/construct.phpt0000644000076500000240000000023214704245235016321 0ustar mikestaff--TEST-- Memcached constructor --SKIPIF-- --FILE-- --EXPECT-- Memcached memcached-3.3.0/tests/construct_persistent.phpt0000644000076500000240000000067714704245235020616 0ustar mikestaff--TEST-- persistent memcached connection --SKIPIF-- --FILE-- setOption(Memcached::OPT_PREFIX_KEY, 'php'); var_dump($m1->getOption(Memcached::OPT_PREFIX_KEY)); $m2 = new Memcached('id1'); var_dump($m1->getOption(Memcached::OPT_PREFIX_KEY)); $m3 = new Memcached(); var_dump($m3->getOption(Memcached::OPT_PREFIX_KEY)); ?> --EXPECT-- string(3) "php" string(3) "php" string(0) "" memcached-3.3.0/tests/deleted.phpt0000644000076500000240000000066314704245235015713 0ustar mikestaff--TEST-- Memcached store & fetch type correctness --SKIPIF-- --FILE-- set('eisaleeoo', "foo"); $m->delete('eisaleeoo'); $v = $m->get('eisaleeoo'); if ($v !== Memcached::GET_ERROR_RETURN_VALUE) { echo "Wanted: "; var_dump(Memcached::GET_ERROR_RETURN_VALUE); echo "Got: "; var_dump($v); } echo "OK\n"; ?> --EXPECT-- OKmemcached-3.3.0/tests/deletemulti.phpt0000644000076500000240000000314014704245235016613 0ustar mikestaff--TEST-- Delete multi --SKIPIF-- --FILE-- 'foo-data', 'bar' => 'bar-data', 'baz' => 'baz-data', 'lol' => 'lol-data', 'kek' => 'kek-data', ); $keys = array_keys($data); $null = null; $m->setMulti($data, 3600); /* Check that all keys were stored */ var_dump(has_all_keys($keys, $m->getMulti($keys))); /* Check that all keys get deleted */ $deleted = $m->deleteMulti($keys); var_dump(has_all_keys($keys, $deleted, true)); /* Try to get the deleted keys, should give empty array */ var_dump($m->getMulti($keys)); /* ---- same tests for byKey variants ---- */ $m->setMultiByKey("hi", $data, 3600); var_dump(has_all_keys($keys, $m->getMultiByKey('hi', $keys))); /* Check that all keys get deleted */ $deleted = $m->deleteMultiByKey('hi', $keys); var_dump(has_all_keys($keys, $deleted, true)); /* Try to get the deleted keys, should give empty array */ var_dump($m->getMultiByKey('hi', $keys)); /* Test deleting non-existent keys */ $keys = array(); $keys[] = "nothere"; $keys[] = "nothere2"; $retval = $m->deleteMulti($keys); foreach ($retval as $key => $value) { if ($value === Memcached::RES_NOTFOUND) { echo "$key NOT FOUND\n"; } } ?> --EXPECT-- bool(true) bool(true) array(0) { } bool(true) bool(true) array(0) { } nothere NOT FOUND nothere2 NOT FOUNDmemcached-3.3.0/tests/deletemultitypes.phpt0000644000076500000240000000061014704245235017677 0ustar mikestaff--TEST-- Delete multi key types --SKIPIF-- --FILE-- deleteMulti($keys); array_walk($keys, 'dump_types'); ?> --EXPECT-- integer string integer stringmemcached-3.3.0/tests/expire.phpt0000644000076500000240000000253614704245235015602 0ustar mikestaff--TEST-- Memcached store, fetch & touch expired key --SKIPIF-- --FILE-- set($key, "foo", 2); $v = $m->get($key); if (!$set || $v != 'foo') { echo "Error setting key to \"foo\" with 2s expiry.\n"; return; } sleep(1); $res = $m->touch($key, 2); $v = $m->get($key); if(!$res || $v != 'foo') { echo "Error touching key for another 2s expiry.\n"; var_dump($res); var_dump($m->getResultMessage()); var_dump($v); return; } sleep(3); $v = $m->get($key); if ($v !== Memcached::GET_ERROR_RETURN_VALUE) { echo "Wanted:\n"; var_dump(Memcached::GET_ERROR_RETURN_VALUE); echo "from get of expired value. Got:\n"; var_dump($v); return; } echo "All OK" . PHP_EOL; } $m = memc_get_instance (array ( Memcached::OPT_BINARY_PROTOCOL => true )); echo '-- binary protocol' . PHP_EOL; run_expiry_test ($m); $m = memc_get_instance (); echo '-- text protocol' . PHP_EOL; run_expiry_test ($m); echo "DONE TEST\n"; ?> --EXPECT-- -- binary protocol All OK -- text protocol All OK DONE TEST memcached-3.3.0/tests/flush_buffers.phpt0000644000076500000240000000104114704245235017131 0ustar mikestaff--TEST-- Test flushing buffers --SKIPIF-- --FILE-- 1, Memcached::OPT_BUFFER_WRITES => 1, )); $key = uniqid ('flush_key_'); var_dump ($m->set($key, 'test_val')); $m2 = memc_get_instance (); var_dump ($m2->get ($key)); var_dump ($m->flushBuffers ()); sleep (1); var_dump ($m2->get ($key)); echo "OK" . PHP_EOL; ?> --EXPECT-- bool(true) bool(false) bool(true) string(8) "test_val" OKmemcached-3.3.0/tests/getdelayed.phpt0000644000076500000240000000217114704245235016410 0ustar mikestaff--TEST-- Memcached getDelayed callback --SKIPIF-- --FILE-- 'foo-data', 'bar' => 'bar-data', 'baz' => 'baz-data', 'lol' => 'lol-data', 'kek' => 'kek-data', ); foreach ($data as $k => $v) { $m->set($k, $v, 3600); } function myfunc() { $datas = func_get_args(); if (isset($datas[1])) { var_dump($datas[1]); } } $m->getDelayed(array_keys($data), true, 'myfunc'); ?> --EXPECTF-- array(4) { ["key"]=> string(3) "foo" ["value"]=> string(8) "foo-data" ["cas"]=> int(%d) ["flags"]=> int(0) } array(4) { ["key"]=> string(3) "bar" ["value"]=> string(8) "bar-data" ["cas"]=> int(%d) ["flags"]=> int(0) } array(4) { ["key"]=> string(3) "baz" ["value"]=> string(8) "baz-data" ["cas"]=> int(%d) ["flags"]=> int(0) } array(4) { ["key"]=> string(3) "lol" ["value"]=> string(8) "lol-data" ["cas"]=> int(%d) ["flags"]=> int(0) } array(4) { ["key"]=> string(3) "kek" ["value"]=> string(8) "kek-data" ["cas"]=> int(%d) ["flags"]=> int(0) }memcached-3.3.0/tests/getserverlist.phpt0000644000076500000240000000176414704245235017212 0ustar mikestaff--TEST-- getServerList --SKIPIF-- --FILE-- array ( 'KEYHERE' => 'localhost', 11211, 3 ), ); $m = new memcached(); var_dump($m->getServerList()); $m->addServers($servers); var_dump($m->getServerList()); $m->addServers($servers); var_dump($m->getServerList()); $m = new memcached(); $m->addServer('127.0.0.1', 11211); var_dump($m->getServerList()); echo "OK"; ?> --EXPECT-- array(0) { } array(1) { [0]=> array(3) { ["host"]=> string(9) "localhost" ["port"]=> int(11211) ["type"]=> string(3) "TCP" } } array(2) { [0]=> array(3) { ["host"]=> string(9) "localhost" ["port"]=> int(11211) ["type"]=> string(3) "TCP" } [1]=> array(3) { ["host"]=> string(9) "localhost" ["port"]=> int(11211) ["type"]=> string(3) "TCP" } } array(1) { [0]=> array(3) { ["host"]=> string(9) "127.0.0.1" ["port"]=> int(11211) ["type"]=> string(3) "TCP" } } OKmemcached-3.3.0/tests/gh_21.phpt0000644000076500000240000000120214704245235015173 0ustar mikestaff--TEST-- Test for Github issue 21 --SKIPIF-- --FILE-- setOption(Memcached::OPT_BINARY_PROTOCOL, true); $m->addServers($newServers); $d = $m->get('foo'); $m->set('counter', 5); $n = $m->decrement('counter'); var_dump($n); $n = $m->decrement('counter', 10); var_dump($n); var_dump($m->get('counter')); $m->set('counter', 'abc'); $n = $m->increment('counter'); var_dump($n); ?> --EXPECT-- int(4) int(0) int(0) bool(false)memcached-3.3.0/tests/gh_77.phpt0000644000076500000240000000110414704245235015207 0ustar mikestaff--TEST-- Test for Github issue #77 --SKIPIF-- --FILE-- touch($key, 5); var_dump ($mc->getResultCode() == Memcached::RES_NOTFOUND); $mc->set($key, 1, 5); $mc->set($key, 1, 5); var_dump ($mc->getResultCode() == Memcached::RES_SUCCESS); echo "OK\n"; ?> --EXPECT-- bool(true) bool(true) OK memcached-3.3.0/tests/gh_90.phpt0000644000076500000240000000344214704245235015211 0ustar mikestaff--TEST-- Test for GH #90 --SKIPIF-- --FILE-- true )); // Create a key for use as a lock. If this key already exists, wait till it doesn't exist. { $key = 'LockKey'; $lockToken = mt_rand(0, mt_getrandmax()); //Random value for ownership verification while (true) { $casToken = null; $data = $memcached->get($key, $casToken); if ($memcached->getResultCode() == Memcached::RES_NOTFOUND) { if ($memcached->add($key, $lockToken, 5)) { break; } } elseif ($data === false) { if ($memcached->cas($casToken, $key, $lockToken, 5)) { break; } } //Sleep 10 milliseconds usleep(10 * 1000); } } //Do something here that requires exclusive access to this key //Effectively delete our key lock. { $casToken = null; if ($lockToken == $memcached->get($key, $casToken)) { $memcached->cas($casToken, $key, false, 1); } } //Create 10 keys and then increment them. The first value returned will be wrong. { $keyList = array(); for ($i = 0; $i < 10; $i++) { $keyList[] = $i . '_' . uniqid ('count_value_'); } $valueList = array(); foreach ($keyList as $key) { $valueList[$key] = $memcached->increment($key, 1, 1); } var_dump ($valueList); } --EXPECTF-- array(10) { ["0_%s"]=> int(1) ["1_%s"]=> int(1) ["2_%s"]=> int(1) ["3_%s"]=> int(1) ["4_%s"]=> int(1) ["5_%s"]=> int(1) ["6_%s"]=> int(1) ["7_%s"]=> int(1) ["8_%s"]=> int(1) ["9_%s"]=> int(1) } memcached-3.3.0/tests/gh_500.phpt0000644000076500000240000000075614704245235015272 0ustar mikestaff--TEST-- Test for Github issue 500 --SKIPIF-- --FILE-- addServers($newServers); $m->set('floatpoint', 100.2); $n = $m->get('floatpoint'); var_dump($n); $m->set('floatpoint_neg', -300.4); $n = $m->get('floatpoint_neg'); var_dump($n); ?> --EXPECT-- float(100.2) float(-300.4) memcached-3.3.0/tests/invoke_callback.phpt0000644000076500000240000000103414704245235017405 0ustar mikestaff--TEST-- Test that callback is invoked on new object --SKIPIF-- --FILE-- addServer(MEMC_SERVER_HOST, MEMC_SERVER_PORT); } $m = new Memcached('hi', 'my_func'); $m = new Memcached('hi', 'my_func'); var_dump($m->getServerList()); echo "OK\n"; --EXPECTF-- array(1) { [0]=> array(3) { ["host"]=> string(9) "%s" ["port"]=> int(%d) ["type"]=> string(3) "TCP" } } OK memcached-3.3.0/tests/invoke_callback_2.phpt0000644000076500000240000000275514704245235017641 0ustar mikestaff--TEST-- Use callback initializer --SKIPIF-- --FILE-- isPersistent()); var_dump($id); } function init_cb_fail($m, $id) { echo "configured, should not be called.\n"; } function init_cb_arg($m, $id) { var_dump(func_num_args()); var_dump($id); } function init_nopersist_cb($m, $id) { var_dump($m->isPersistent()); var_dump($id); } class Foo extends Memcached { function __construct($id = null) { parent::__construct($id, array($this, 'init')); } function init($obj, $id) { var_dump(func_num_args()); var_dump($this->isPristine()); var_dump($this->isPersistent()); var_dump($id); } } echo "cb call\n"; $m1 = new Memcached('foo1', 'init_cb'); echo "cb not run\n"; $m1 = new Memcached('foo1', 'init_cb_fail'); echo "cb arg without arg\n"; $m1 = new Memcached('foo3', 'init_cb_arg'); echo "cb arg not persistent\n"; $m1 = new Memcached(null, 'init_nopersist_cb'); echo "cb in object\n"; $m1 = new Foo(); echo "cb persistent in object\n"; $m1 = new Foo('baz'); echo "cb second persistent in object\n"; $m1 = new Foo('baz'); ?> --EXPECT-- cb call string(9) "Memcached" bool(true) string(4) "foo1" cb not run cb arg without arg int(2) string(4) "foo3" cb arg not persistent bool(false) NULL cb in object int(2) bool(true) bool(false) NULL cb persistent in object int(2) bool(true) bool(true) string(3) "baz" cb second persistent in object memcached-3.3.0/tests/invoke_callback_twice.phpt0000644000076500000240000000054514704245235020606 0ustar mikestaff--TEST-- Test that callback is invoked on new object only once --SKIPIF-- --FILE-- --FILE-- set($key, array( 'foo' => 'bar' ), 360); var_dump($m->get($key)); ?> --EXPECT-- array(1) { ["foo"]=> string(3) "bar" } memcached-3.3.0/tests/multi_order.phpt0000644000076500000240000000125614704245235016631 0ustar mikestaff--TEST-- Memcached GET_PRESERVE_ORDER flag in getMulti --SKIPIF-- --FILE-- addServer (MEMC_SERVER_HOST, MEMC_SERVER_PORT); $data = array( 'foo' => 'foo-data', 'bar' => 'bar-data', 'baz' => 'baz-data', 'lol' => 'lol-data', 'kek' => 'kek-data', ); //$m->setMulti($data, 3600); foreach ($data as $k => $v) { $m->set($k, $v, 3600); } $keys = array_keys($data); $keys[] = 'zoo'; $got = $m->getMulti($keys, Memcached::GET_PRESERVE_ORDER); foreach ($got as $k => $v) { echo "$k $v\n"; } ?> --EXPECT-- foo foo-data bar bar-data baz baz-data lol lol-data kek kek-data zoo memcached-3.3.0/tests/no-not-found.phpt0000644000076500000240000000072614704245235016630 0ustar mikestaff--TEST-- Test that correct return value is returned --SKIPIF-- --FILE-- addServer('localhost', 5555); // Server should not exist $result = $memcached->get('foo_not_exists'); var_dump ($result === Memcached::GET_ERROR_RETURN_VALUE); $result = $memcached->get('foo_not_exists'); var_dump ($result === Memcached::GET_ERROR_RETURN_VALUE); echo "OK\n"; ?> --EXPECT-- bool(true) bool(true) OK memcached-3.3.0/tests/options.phpt0000644000076500000240000000443214704245235015776 0ustar mikestaff--TEST-- Memcached options --SKIPIF-- --FILE-- setOption(Memcached::OPT_SERIALIZER, Memcached::SERIALIZER_PHP); var_dump($m->getOption(Memcached::OPT_COMPRESSION)); var_dump($m->getOption(Memcached::OPT_SERIALIZER)); var_dump($m->getOption(Memcached::OPT_SOCKET_SEND_SIZE)); $m->setOption(Memcached::OPT_PREFIX_KEY, "\x01"); var_dump($m->getOption(Memcached::OPT_HASH) == Memcached::HASH_DEFAULT); $m->setOption(Memcached::OPT_HASH, Memcached::HASH_MURMUR); var_dump($m->getOption(Memcached::OPT_HASH) == Memcached::HASH_MURMUR); $m->setOption(Memcached::OPT_COMPRESSION_TYPE, Memcached::COMPRESSION_ZLIB); var_dump($m->getOption(Memcached::OPT_COMPRESSION_TYPE) == Memcached::COMPRESSION_ZLIB); $m->setOption(Memcached::OPT_COMPRESSION_TYPE, Memcached::COMPRESSION_FASTLZ); var_dump($m->getOption(Memcached::OPT_COMPRESSION_TYPE) == Memcached::COMPRESSION_FASTLZ); var_dump($m->setOption(Memcached::OPT_COMPRESSION_TYPE, 0)); var_dump($m->getOption(Memcached::OPT_COMPRESSION_TYPE) == Memcached::COMPRESSION_FASTLZ); echo "item_size_limit setOption\n"; var_dump($m->setOption(Memcached::OPT_ITEM_SIZE_LIMIT, 0)); var_dump($m->getOption(Memcached::OPT_ITEM_SIZE_LIMIT) === 0); var_dump($m->setOption(Memcached::OPT_ITEM_SIZE_LIMIT, -1)); var_dump($m->setOption(Memcached::OPT_ITEM_SIZE_LIMIT, 1000000)); var_dump($m->getOption(Memcached::OPT_ITEM_SIZE_LIMIT) == 1000000); echo "item_size_limit ini\n"; ini_set('memcached.item_size_limit', '0'); $m = new Memcached(); var_dump($m->getOption(Memcached::OPT_ITEM_SIZE_LIMIT) === 0); ini_set('memcached.item_size_limit', '1000000'); $m = new Memcached(); var_dump($m->getOption(Memcached::OPT_ITEM_SIZE_LIMIT) == 1000000); ini_set('memcached.item_size_limit', null); $m = new Memcached(); var_dump($m->getOption(Memcached::OPT_ITEM_SIZE_LIMIT) === 0); ?> --EXPECTF-- bool(true) int(1) Warning: Memcached::getOption(): no servers defined in %s on line %d NULL Warning: Memcached::setOption(): bad key provided in %s on line %d bool(true) bool(true) bool(true) bool(true) bool(false) bool(true) item_size_limit setOption bool(true) bool(true) Warning: Memcached::setOption(): ITEM_SIZE_LIMIT must be >= 0 in %s on line %d bool(false) bool(true) bool(true) item_size_limit ini bool(true) bool(true) bool(true) memcached-3.3.0/tests/pr_75.phpt0000644000076500000240000000120414704245235015231 0ustar mikestaff--TEST-- Wrong return values for binary protocol --SKIPIF-- --FILE-- true )); $client->set('key1', 'value1'); echo "set result code: ".$client->getResultCode()."\n"; $value = $client->get('key1'); echo "got $value with result code: ".$client->getResultCode()."\n"; var_dump ($client->add('key2', 'value2')); echo "add result code: ".$client->getResultCode()."\n"; echo "OK\n"; ?> --EXPECT-- set result code: 0 got value1 with result code: 0 bool(true) add result code: 0 OKmemcached-3.3.0/tests/rescode.phpt0000644000076500000240000000344014704245235015725 0ustar mikestaff--TEST-- Memcached result codes. --SKIPIF-- --FILE-- getResultMessage(), "\n"; $m->addServer(MEMC_SERVER_HOST, MEMC_SERVER_PORT, 1); echo $m->getResultCode(), "\n"; echo $m->getResultMessage(), "\n"; $m->set('bar_foo', 10); echo $m->getResultMessage(), "\n"; $m->delete('bar_foo'); echo $m->getResultMessage(), "\n"; $m->delete('bar_foo'); echo $m->getResultCode(), "\n"; echo $m->getResultMessage(), "\n"; $m->set ('asdf_a', 'aa'); $m->getMulti(array('asdf_a', 'jkhjkhjkb', 'nbahsdgc')); echo $m->getResultMessage(), "\n"; $code = $m->getResultCode(); $m2 = new Memcached(); $m2->getMulti(array('asdf_a', 'jkhjkhjkb', 'nbahsdgc')); echo $m2->getResultCode(), "\n"; echo $m2->getResultMessage(), "\n"; $m2->addServer('127.0.0.1', 7312, 1); echo $m2->getResultCode(), "\n"; echo $m2->getResultMessage(), "\n"; $m2->delete('bar_foo'); echo $m2->getResultCode(), "\n"; echo $m2->getResultMessage(), "\n"; var_dump($m->getResultCode() == $code); $m = memc_get_instance (array (), 'test1'); $m2 = new Memcached('test1'); $m->delete('moikkamitakuuluu'); echo $m->getResultMessage(), "\n"; $m2->set('minapaasetannih', 10, 1); echo $m->getResultMessage(), "\n"; echo $m2->getResultMessage(), "\n"; $m->delete('bar_foo'); // clearly "NOT FOUND" $m->delete('bar_foo'); $res_m = $m->getResultMessage(); echo $res_m, "\n"; $m2->set('bar_foo', 10); echo $m->getResultMessage(), "\n"; echo $m2->getResultMessage(), "\n"; $m->delete('bar_foo'); echo $m->getResultMessage(), "\n"; ?> --EXPECTF-- SUCCESS %d SUCCESS SUCCESS SUCCESS %d NOT FOUND SUCCESS %d NO SERVERS DEFINED %d SUCCESS %d %rSYSTEM ERROR|WRITE FAILURE|CONNECTION FAILURE%r bool(true) NOT FOUND NOT FOUND SUCCESS NOT FOUND NOT FOUND SUCCESS SUCCESS memcached-3.3.0/tests/session_badconf_emptyprefix.phpt0000644000076500000240000000116514704245235022076 0ustar mikestaff--TEST-- Session bad configurations, prefix --SKIPIF-- --INI-- memcached.sess_locking = on memcached.sess_prefix = "memc.sess.key." session.save_handler = "memcached" --FILE-- --INI-- memcached.sess_locking = on memcached.sess_lock_wait = -1 memcached.sess_prefix = "memc.sess.key." session.save_path="127.0.0.1:51312" session.save_handler = memcached --FILE-- --INI-- session.save_handler = "memcached" session.save_path = "PERSISTENT=1 hello:11211,world:11211" --FILE-- --INI-- session.save_handler = memcached --FILE-- 70100) print "skip"; ?> --INI-- session.save_handler = memcached --FILE-- --INI-- session.save_handler = memcached --FILE-- --INI-- session.save_handler = memcached memcached.sess_binary_protocol = Off --FILE-- int(1) } array(0) { } memcached-3.3.0/tests/session_basic2.phpt0000644000076500000240000000132614704245235017210 0ustar mikestaff--TEST-- Session basic open, write, destroy --SKIPIF-- --INI-- session.save_handler = memcached memcached.sess_binary_protocol = Off --FILE-- TRUE]); $_SESSION['foo'] = 1; session_write_close(); $_SESSION = NULL; var_dump($_SESSION); session_start(); var_dump($_SESSION); session_write_close(); session_start(); session_destroy(); session_start(); var_dump($_SESSION); session_write_close(); --EXPECT-- NULL array(1) { ["foo"]=> int(1) } array(0) { } memcached-3.3.0/tests/session_basic3.phpt0000644000076500000240000000133714704245235017213 0ustar mikestaff--TEST-- Session basic open, write, destroy --SKIPIF-- --INI-- session.save_handler = memcached memcached.sess_binary_protocol = Off --FILE-- true ]); var_dump($_SESSION); session_write_close(); session_start(); session_destroy(); session_start(); var_dump($_SESSION); session_write_close(); --EXPECT-- NULL array(1) { ["foo"]=> int(1) } array(0) { } memcached-3.3.0/tests/session_persistent.phpt0000644000076500000240000000116614704245235020247 0ustar mikestaff--TEST-- Session persistent --SKIPIF-- --INI-- session.save_handler=memcached memcached.sess_persistent=1 --FILE-- --EXPECT-- array(1) { ["test"]=> bool(true) } memcached-3.3.0/tests/set_large.phpt0000644000076500000240000000057614704245235016255 0ustar mikestaff--TEST-- set large data --SKIPIF-- --FILE-- 0, )); $key = 'foobarbazDEADC0DE'; $value = str_repeat("foo bar", 1024 * 1024); var_dump($m->set($key, $value, 360)); var_dump($m->get($key) === $value); ?> --EXPECT-- bool(true) bool(true) memcached-3.3.0/tests/setoptions.phpt0000644000076500000240000000226214704245235016511 0ustar mikestaff--TEST-- Set options using setOptions --SKIPIF-- --FILE-- setOptions(array( Memcached::OPT_PREFIX_KEY => 'a_prefix', Memcached::OPT_SERIALIZER => Memcached::SERIALIZER_PHP, Memcached::OPT_COMPRESSION => 0, Memcached::OPT_LIBKETAMA_COMPATIBLE => 1, Memcached::OPT_CONNECT_TIMEOUT => 5000, Memcached::OPT_ITEM_SIZE_LIMIT => 1000000, ))); var_dump($m->getOption(Memcached::OPT_PREFIX_KEY) == 'a_prefix'); var_dump($m->getOption(Memcached::OPT_SERIALIZER) == Memcached::SERIALIZER_PHP); var_dump($m->getOption(Memcached::OPT_COMPRESSION) == 0); var_dump($m->getOption(Memcached::OPT_LIBKETAMA_COMPATIBLE) == 1); var_dump($m->getOption(Memcached::OPT_ITEM_SIZE_LIMIT) == 1000000); echo "test invalid options\n"; var_dump($m->setOptions(array( "asdf" => 123 ))); var_dump($m->setOptions(array( -1 => 123 ))); --EXPECTF-- bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) test invalid options Warning: Memcached::setOptions(): invalid configuration option in %s on line %d bool(false) Warning: Memcached::setOptions(): error setting memcached option: %s in %s on line %d bool(false) memcached-3.3.0/tests/touch_binary.phpt0000644000076500000240000000354314704245235016773 0ustar mikestaff--TEST-- Touch in binary mode --SKIPIF-- --FILE-- getConstants (); foreach ($c as $name => $value) { if (strpos ($name, 'RES_') === 0 && $value == $code) return $name; } } function status_print ($op, $mem, $expected) { $code = $mem->getResultcode(); if ($code == $expected) echo "{$op} status code as expected" . PHP_EOL; else { $expected = resolve_to_constant ($expected); $code = resolve_to_constant ($code); echo "{$op} status code mismatch, expected {$expected} but got {$code}" . PHP_EOL; } } include dirname (__FILE__) . '/config.inc'; $mem = memc_get_instance (array (Memcached::OPT_BINARY_PROTOCOL => true)); $key = uniqid ('touch_t_'); $mem->get($key); status_print ('get', $mem, Memcached::RES_NOTFOUND); $mem->set ($key, 1); status_print ('set', $mem, Memcached::RES_SUCCESS); $mem->get($key); status_print ('get', $mem, Memcached::RES_SUCCESS); $mem->touch ($key, 10); status_print ('touch', $mem, Memcached::RES_SUCCESS); $mem->get($key); status_print ('get', $mem, Memcached::RES_SUCCESS); $mem->get($key); status_print ('get', $mem, Memcached::RES_SUCCESS); echo "OK\n"; ?> --EXPECT-- get status code as expected set status code as expected get status code as expected touch status code as expected get status code as expected get status code as expected OK memcached-3.3.0/tests/types.inc0000644000076500000240000000540614704245235015247 0ustar mikestaff "1","b" => "2","c" => "3")), array('object_dummy', new testclass()), ); foreach ($data as $key => $value) { $m->delete($key); } foreach ($data as $types) { $key = $types [0]; $value = $types [1]; $m->set($key, $value); $actual = $m->get($key); if ($value !== $actual) { if (is_object($actual)) { if ($options['ignore_object_type']) { $value = (object) (array) $value; if ($value == $actual) continue; } if ($value == $actual && get_class($value) == get_class($actual)) continue; } echo "=== {$key} ===\n"; echo "Expected: "; var_dump($value); echo "Actual: "; var_dump($actual); } } $m->flush(); if (($actual = $m->get(uniqid ('random_key_'))) !== false) { echo "Expected: null"; echo "Actual: " . gettype($actual); } } function memc_types_test_multi ($m, $options) { $data = array( 'boolean_true' => true, 'boolean_false' => false, 'string' => "just a string", 'string_empty' => "", 'string_large' => str_repeat ('abcdef0123456789', 500), 'integer_positive_integer' => 10, 'integer_negative_integer' => -10, 'integer_zero_integer' => 0, 'float_positive1' => 3.912131, 'float_positive2' => 1.2131E+52, 'float_negative' => -42.123312, 'float_zero' => 0.0, 'null' => null, 'array_empty' => array(), 'array' => array(1,2,3,"foo"), 'object_array_empty' => (object)array(), 'object_array' => (object)array('a' => 1, 'b' => 2, 'c' => 3), 'object_dummy' => new testclass(), ); foreach ($data as $key => $value) { $m->delete($key); } $m->setMulti($data); $actual = $m->getMulti(array_keys($data)); foreach ($data as $key => $value) { if ($value !== $actual[$key]) { if (is_object($value)) { if ($options['ignore_object_type']) { $value = (object) (array) $value; if ($value == $actual[$key]) continue; } if ($value == $actual[$key] && get_class($value) == get_class($actual[$key])) continue; } echo "=== $key ===\n"; echo "Expected: "; var_dump($value); echo "Actual: "; var_dump($actual[$key]); } } } memcached-3.3.0/tests/types_igbinary.phpt0000644000076500000240000000070314704245235017330 0ustar mikestaff--TEST-- Memcached store & fetch type and value correctness using igbinary serializer --SKIPIF-- --FILE-- --EXPECT-- TEST DONE memcached-3.3.0/tests/types_igbinary_multi.phpt0000644000076500000240000000072514704245235020546 0ustar mikestaff--TEST-- Memcached multi store & multi fetch type and value correctness using igbinary serializer --SKIPIF-- --FILE-- --EXPECT-- TEST DONE memcached-3.3.0/tests/types_json.phpt0000644000076500000240000000066514704245235016504 0ustar mikestaff--TEST-- Memcached store & fetch type and value correctness using JSON serializer --SKIPIF-- --FILE-- --EXPECT-- TEST DONE memcached-3.3.0/tests/types_json_multi.phpt0000644000076500000240000000070714704245235017713 0ustar mikestaff--TEST-- Memcached multi store & multi fetch type and value correctness using JSON serializer --SKIPIF-- --FILE-- --EXPECT-- TEST DONE memcached-3.3.0/tests/types_msgpack.phpt0000644000076500000240000000076514704245235017161 0ustar mikestaff--TEST-- Memcached store & fetch type and value correctness using msgpack serializer --SKIPIF-- --FILE-- --EXPECT-- TEST DONE memcached-3.3.0/tests/types_msgpack_multi.phpt0000644000076500000240000000100114704245235020353 0ustar mikestaff--TEST-- Memcached multi store & fetch type and value correctness using msgpack serializer --SKIPIF-- --FILE-- --EXPECT-- TEST DONE memcached-3.3.0/tests/types_php.phpt0000644000076500000240000000053414704245235016315 0ustar mikestaff--TEST-- Memcached store & fetch type and value correctness using PHP serializer --SKIPIF-- --FILE-- --EXPECT-- TEST DONE memcached-3.3.0/tests/types_php_multi.phpt0000644000076500000240000000055014704245235017525 0ustar mikestaff--TEST-- Memcached multi store & fetch type and value correctness using PHP serializer --SKIPIF-- --FILE-- --EXPECT-- TEST DONE memcached-3.3.0/tests/undefined_set.phpt0000644000076500000240000000117114704245235017114 0ustar mikestaff--TEST-- Set with undefined key and value --SKIPIF-- --FILE-- 'bar'); // silent to hide: // Warning: Undefined variable // Deprecated: Memcached::set(): Passing null to parameter (PHP 8.1) $rv = @$m->set($no_key, $value, 360); var_dump($rv); $rv = @$m->set($key, $no_value, 360); var_dump($rv); $rv = @$m->set($no_key, $no_value, 360); var_dump($rv); $rv = @$m->set($key, $value, $no_time); var_dump($rv); ?> --EXPECTF-- bool(false) bool(true) bool(false) bool(true) memcached-3.3.0/tests/vbucket.phpt0000644000076500000240000000116314704245235015744 0ustar mikestaff--TEST-- Memcached virtual buckets --SKIPIF-- --FILE-- Memcached::DISTRIBUTION_VIRTUAL_BUCKET )); var_dump ($m->setBucket (array (1, 2, 3), null, 2)); var_dump ($m->setBucket (array (1,2,2), array (1,2,2), 2)); var_dump ($m->setBucket (array ('a', 'b', 'c'), null, 2)); echo "OK\n"; ?> --EXPECTF-- bool(true) bool(true) bool(true) OK memcached-3.3.0/tests/vbucket_error_7.phpt0000644000076500000240000000203714704245235017404 0ustar mikestaff--TEST-- Memcached virtual buckets --SKIPIF-- = 80000) die("skip PHP 7 only"); ?> --FILE-- Memcached::DISTRIBUTION_VIRTUAL_BUCKET )); var_dump ($m->setBucket (array (), null, 2)); var_dump ($m->setBucket (array (), array (), -1)); var_dump ($m->setBucket (null, array (), -1)); var_dump ($m->setBucket (array (-1), array (-1), 1)); echo "OK\n"; ?> --EXPECTF-- Warning: Memcached::setBucket(): server map cannot be empty in %s on line %d bool(false) Warning: Memcached::setBucket(): server map cannot be empty in %s on line %d bool(false) Warning: Memcached::setBucket() expects parameter 1 to be array, null given in %s on line %d NULL Warning: Memcached::setBucket(): the map must contain positive integers in %s on line %d bool(false) OK memcached-3.3.0/tests/vbucket_error_8.phpt0000644000076500000240000000212014704245235017376 0ustar mikestaff--TEST-- Memcached virtual buckets --SKIPIF-- --FILE-- Memcached::DISTRIBUTION_VIRTUAL_BUCKET )); var_dump ($m->setBucket (array (), null, 2)); var_dump ($m->setBucket (array (), array (), -1)); try { var_dump ($m->setBucket (null, array (), -1)); } catch (TypeError $e) { echo $e->getMessage() . PHP_EOL; } var_dump ($m->setBucket (array (-1), array (-1), 1)); echo "OK\n"; ?> --EXPECTF-- Warning: Memcached::setBucket(): server map cannot be empty in %s on line %d bool(false) Warning: Memcached::setBucket(): server map cannot be empty in %s on line %d bool(false) Memcached::setBucket(): Argument #1 ($host_map) must be of type array, null given Warning: Memcached::setBucket(): the map must contain positive integers in %s on line %d bool(false) OK memcached-3.3.0/tests/user-flags.phpt0000644000076500000240000000502414704245235016351 0ustar mikestaff--TEST-- Memcached user flags --SKIPIF-- --FILE-- get($key, null, Memcached::GET_EXTENDED)['flags']; } define ('FLAG_1', 1); define ('FLAG_2', 2); define ('FLAG_4', 4); define ('FLAG_32', 32); define ('FLAG_64', 64); define ('FLAG_TOO_LARGE', pow(2, 16)); include dirname (__FILE__) . '/config.inc'; $m = memc_get_instance (array (Memcached::OPT_BINARY_PROTOCOL => true)); $key = uniqid ('udf_test_'); // Set with flags off $m->set ($key, '1', 10); $v = $m->get($key, null, Memcached::GET_EXTENDED); var_dump($v); // Set flags on $m->setOption(Memcached::OPT_USER_FLAGS, FLAG_1); $m->set ($key, '1', 10); $m->get($key); check_flags(get_flags($m, $key), array(FLAG_1)); // Multiple flags $m->setOption(Memcached::OPT_USER_FLAGS, FLAG_1 | FLAG_2 | FLAG_4); $m->set ($key, '1', 10); $m->get($key); check_flags(get_flags($m, $key), array(FLAG_1, FLAG_2, FLAG_4)); // Even more flags $m->setOption(Memcached::OPT_USER_FLAGS, FLAG_1 | FLAG_2 | FLAG_4 | FLAG_32 | FLAG_64); $m->set ($key, '1', 10); $m->get($key); check_flags(get_flags($m, $key), array(FLAG_1, FLAG_2, FLAG_4, FLAG_32, FLAG_64)); // User flags with get multi $values = array( uniqid ('udf_test_multi_') => "first", uniqid ('udf_test_multi_') => "second", uniqid ('udf_test_multi_') => "third", ); $m->setOption(Memcached::OPT_USER_FLAGS, FLAG_2 | FLAG_4); $m->setMulti($values); $m->getMulti(array_keys($values)); $flags = $m->getMulti(array_keys($values), Memcached::GET_EXTENDED); foreach (array_keys($values) as $key) { check_flags($flags[$key]['flags'], array(FLAG_2, FLAG_4)); } // User flags with compression on $m->setOption(Memcached::OPT_USER_FLAGS, FLAG_1 | FLAG_2 | FLAG_4); $m->setOption(Memcached::OPT_COMPRESSION, true); $m->setOption(Memcached::OPT_COMPRESSION_TYPE, Memcached::COMPRESSION_FASTLZ); $m->set ($key, '1', 10); $m->get($key); check_flags(get_flags($m, $key), array(FLAG_1, FLAG_2, FLAG_4)); // Too large flags $m->setOption(Memcached::OPT_USER_FLAGS, FLAG_TOO_LARGE); echo "DONE TEST\n"; ?> --EXPECTF-- array(3) { ["value"]=> string(1) "1" ["cas"]=> int(%d) ["flags"]=> int(0) } Flags OK Flags OK Flags OK Flags OK Flags OK Flags OK Flags OK Warning: Memcached::setOption(): MEMC_OPT_USER_FLAGS must be < 65535 in %s on line %d DONE TESTmemcached-3.3.0/tests/gh_93.phpt0000644000076500000240000000153714704245235015217 0ustar mikestaff--TEST-- Test for Github issue #93 (double and long overflow) --SKIPIF-- --FILE-- false )); function testOverflow($m, $value) { $m->delete('overflow'); if (true !== $m->set('overflow', $value)) { echo "Error storing 'overflow' variable\n"; return false; } if (true !== $m->prepend('overflow', str_repeat('0', 128))) { echo "Error prepending key\n"; return false; } $v = @$m->get('overflow'); if ($v !== $value) { // At least it doesn't segfault, so we're happy for now // echo "Error receiving 'overflow' variable\n"; // return false; return true; } return true; } if (!testOverflow($m, 10)) { return; } if (!testOverflow($m, 9.09)) { return; } echo "OK\n"; ?> --EXPECT-- OKmemcached-3.3.0/tests/add.phpt0000644000076500000240000000052514704245235015032 0ustar mikestaff--TEST-- Memcached::add() --SKIPIF-- --FILE-- delete('foo'); var_dump($m->add('foo', 1, 60)); var_dump($m->get('foo')); var_dump($m->add('foo', 2, 60)); var_dump($m->get('foo')); --EXPECT-- bool(true) int(1) bool(false) int(1) memcached-3.3.0/tests/bad_construct.phpt0000644000076500000240000000141514704245235017133 0ustar mikestaff--TEST-- Memcached construct with bad arguments --SKIPIF-- = 80000) die("skip PHP 7 only"); ?> --FILE-- setOption (Memcached::OPT_BINARY_PROTOCOL, true)); echo "OK" . PHP_EOL; --EXPECTF-- Warning: Memcached::__construct() expects parameter 1 to be string, object given in %s on line 3 Memcached::__construct() expects parameter 1 to be string, object given object(Memcached)#1 (0) { } Warning: Memcached::setOption(): Memcached constructor was not called in %s on line 14 NULL OK memcached-3.3.0/tests/bad_construct_8.phpt0000644000076500000240000000127514704245235017366 0ustar mikestaff--TEST-- Memcached construct with bad arguments --SKIPIF-- --FILE-- getMessage() . PHP_EOL; } class extended extends Memcached { public function __construct () { } } error_reporting(E_ALL); try { $extended = new extended (); var_dump ($extended->setOption (Memcached::OPT_BINARY_PROTOCOL, true)); } catch (Error $e) { echo $e->getMessage() . PHP_EOL; } echo "OK" . PHP_EOL; --EXPECTF-- Memcached::__construct(): Argument #1 ($persistent_id) must be of type ?string, stdClass given Memcached constructor was not called OK memcached-3.3.0/tests/append.phpt0000644000076500000240000000121314704245235015544 0ustar mikestaff--TEST-- Memcached::append() --SKIPIF-- --FILE-- delete('foo'); $m->setOption(Memcached::OPT_COMPRESSION, true); var_dump($m->append('foo', 'a')); echo error_get_last()["message"], "\n"; $m->setOption(Memcached::OPT_COMPRESSION, false); $m->delete('foo'); var_dump($m->append('foo', 'a')); var_dump($m->get('foo')); $m->set('foo', 'a'); var_dump($m->append('foo', 'b')); var_dump($m->get('foo')); --EXPECTF-- NULL %s: cannot append/prepend with compression turned on bool(false) bool(false) bool(true) string(2) "ab" memcached-3.3.0/tests/prepend.phpt0000644000076500000240000000117714704245235015743 0ustar mikestaff--TEST-- Memcached::prepend() --SKIPIF-- --FILE-- delete('foo'); $m->setOption(Memcached::OPT_COMPRESSION, true); var_dump($m->prepend('foo', 'a')); $m->setOption(Memcached::OPT_COMPRESSION, false); $m->delete('foo'); var_dump($m->prepend('foo', 'a')); var_dump($m->get('foo')); $m->set('foo', 'a'); var_dump($m->prepend('foo', 'b')); var_dump($m->get('foo')); --EXPECTF-- Warning: Memcached::prepend(): cannot append/prepend with compression turned on in %s on line %d NULL bool(false) bool(false) bool(true) string(2) "ba" memcached-3.3.0/tests/replace.phpt0000644000076500000240000000061614704245235015716 0ustar mikestaff--TEST-- Memcached::replace() --SKIPIF-- --FILE-- delete('foo'); var_dump($m->replace('foo', 'bar', 60)); var_dump($m->get('foo')); $m->set('foo', 'kef'); var_dump($m->replace('foo', 'bar', 60)); var_dump($m->get('foo')); --EXPECT-- bool(false) bool(false) bool(true) string(3) "bar" memcached-3.3.0/tests/getmulti.phpt0000644000076500000240000000154114704245235016133 0ustar mikestaff--TEST-- Memcached::getMulti() --SKIPIF-- --FILE-- setMulti($data)); $keys = array_keys($data); $keys['last'] = new Foo(); $v = $m->getMulti($keys); var_dump(is_array($v)); var_dump($m->getResultCode() == Memcached::RES_SUCCESS); if (is_array($v)) { foreach ($v as $key => $value) { if (!isset($data[$key]) or $value !== $data[$key]) { echo "mismatch \$data['$key'] = \n"; var_dump($data[$key]); var_dump($value); } } } else { echo "Result not an array\n"; } var_dump(is_object($keys['last'])); --EXPECT-- bool(true) bool(true) bool(true) bool(true) memcached-3.3.0/tests/setmulti.phpt0000644000076500000240000000222014704245235016142 0ustar mikestaff--TEST-- Memcached::setMulti() --SKIPIF-- --FILE-- deleteMulti($keys); echo "set keys: "; var_dump($m->setMulti($data, 10)); echo "get: "; $r = $m->getMulti($keys); var_dump($r); echo "Equal: "; var_dump($r === $data); --EXPECTF-- Data: array(%d) { ["foo"]=> string(3) "bar" [%i]=> string(7) "int-max" [%i]=> string(7) "int-min" [%i]=> string(7) "int-min" [0]=> string(4) "zero" [123]=> string(11) "onetwothree" [-123]=> string(14) "negonetwothree" } set keys: bool(true) get: array(%d) { ["foo"]=> string(3) "bar" [%i]=> string(7) "int-max" [%i]=> string(7) "int-min" [%i]=> string(7) "int-min" [0]=> string(4) "zero" [123]=> string(11) "onetwothree" [-123]=> string(14) "negonetwothree" } Equal: bool(true) memcached-3.3.0/tests/cachecallback.phpt0000644000076500000240000000226714704245235017027 0ustar mikestaff--TEST-- Memcached::get() with cache callback --SKIPIF-- --FILE-- delete($first_key); $m->delete($second_key); $m->delete($third_key); var_dump ( $m->get ($first_key, function (Memcached $memc, $key, &$value, &$expiration) { $value = "hello"; $expiration = 10; return true; }) ); var_dump ($m->get ($first_key)); var_dump ( $m->get ($second_key, function (Memcached $memc, $key, &$value, &$expiration) { $value = "hello"; $expiration = 10; return false; }) ); var_dump ($m->get ($second_key)); try { $m->get ($third_key, function (Memcached $memc, $key, &$value, &$expiration) { $value = "hello"; $expiration = 10; throw new Exception ('this is a test'); return true; }); } catch (Exception $e) { echo 'Got exception' . PHP_EOL; } var_dump ($m->get ($third_key)); echo "OK" . PHP_EOL; --EXPECT-- string(5) "hello" string(5) "hello" bool(false) bool(false) Got exception bool(false) OKmemcached-3.3.0/tests/incrdecr.phpt0000644000076500000240000000257214704245235016077 0ustar mikestaff--TEST-- Memcached::increment() Memcached::decrement() --SKIPIF-- --FILE-- delete('foo'); var_dump($m->increment('foo', 1)); var_dump($m->getResultCode()); var_dump($m->decrement('foo', 1)); var_dump($m->getResultCode()); var_dump($m->get('foo')); var_dump($m->getResultCode()); echo "Normal\n"; $m->set('foo', 1); var_dump($m->get('foo')); $m->increment('foo'); var_dump($m->get('foo')); $m->increment('foo', 2); var_dump($m->get('foo')); $m->decrement('foo'); var_dump($m->get('foo')); $m->decrement('foo', 2); var_dump($m->get('foo')); error_reporting(0); echo "Negative offset\n"; error_clear_last(); $m->increment('foo', -1); echo error_get_last()["message"], "\n"; var_dump($m->get('foo')); error_clear_last(); $m->decrement('foo', -1); echo error_get_last()["message"], "\n"; var_dump($m->get('foo')); echo "Enormous offset\n"; $m->increment('foo', 0x7f000000); var_dump($m->get('foo')); $m->decrement('foo', 0x7f000000); var_dump($m->get('foo')); --EXPECT-- Not there bool(false) int(16) bool(false) int(16) bool(false) int(16) Normal int(1) int(2) int(4) int(3) int(1) Negative offset Memcached::increment(): offset cannot be a negative value int(1) Memcached::decrement(): offset cannot be a negative value int(1) Enormous offset int(2130706433) int(1) memcached-3.3.0/tests/incrdecr_64.phpt0000644000076500000240000000144714704245235016410 0ustar mikestaff--TEST-- 64-bit Memcached::increment() decrement() incrementByKey() decrementByKey() --SKIPIF-- --FILE-- set('foo', 1); var_dump($m->get('foo')); echo "Enormous offset 64-bit\n"; $m->increment('foo', 0x100000000); var_dump($m->get('foo')); $m->decrement('foo', 0x100000000); var_dump($m->get('foo')); echo "Enormous offset 64-bit by key\n"; $m->incrementByKey('foo', 'foo', 0x100000000); var_dump($m->get('foo')); $m->decrementByKey('foo', 'foo', 0x100000000); var_dump($m->get('foo')); --EXPECT-- Normal int(1) Enormous offset 64-bit int(4294967297) int(1) Enormous offset 64-bit by key int(4294967297) int(1) memcached-3.3.0/tests/incrdecr_initial.phpt0000644000076500000240000000215614704245235017606 0ustar mikestaff--TEST-- Memcached::increment() Memcached::decrement() with initial support --SKIPIF-- --FILE-- true )); $m->delete('foo'); var_dump($m->increment('foo', 1, 1)); var_dump($m->increment('foo', 0)); $m->delete('foo'); var_dump($m->increment('foo', 1, 1)); var_dump($m->increment('foo', 1, 1)); var_dump($m->increment('foo', 1, 1)); var_dump($m->decrement('foo', 1, 1)); var_dump($m->decrement('foo', 0)); $m->delete('foo'); $m->deleteByKey('foo', 'foo'); var_dump($m->incrementByKey('foo', 'foo', 1, 1)); var_dump($m->incrementByKey('foo', 'foo', 0)); $m->deleteByKey('foo', 'foo'); var_dump($m->incrementByKey('foo', 'foo', 1, 1)); var_dump($m->incrementByKey('foo', 'foo', 1, 1)); var_dump($m->incrementByKey('foo', 'foo', 1, 1)); var_dump($m->decrementByKey('foo', 'foo', 1, 1)); var_dump($m->decrementByKey('foo', 'foo', 0)); $m->deleteByKey('foo', 'foo'); --EXPECT-- int(1) int(1) int(1) int(2) int(3) int(2) int(2) int(1) int(1) int(1) int(2) int(3) int(2) int(2) memcached-3.3.0/tests/incrdecr_invalid_key.phpt0000644000076500000240000000045614704245235020454 0ustar mikestaff--TEST-- Memcached::increment() Memcached::decrement() with invalid key --SKIPIF-- --FILE-- increment('', 1)); var_dump($m->decrement('', 1)); ?> --EXPECT-- bool(false) bool(false) memcached-3.3.0/tests/incrdecr_bykey.phpt0000644000076500000240000000262114704245235017275 0ustar mikestaff--TEST-- Memcached::incrementByKey() Memcached::decrementByKey() --SKIPIF-- --FILE-- delete('foo'); var_dump($m->incrementByKey('foo', 'foo', 1)); var_dump($m->decrementByKey('foo', 'foo', 1)); var_dump($m->get('foo')); echo "Normal\n"; $m->set('foo', 1); var_dump($m->get('foo')); $m->incrementByKey('foo', 'foo'); var_dump($m->get('foo')); $m->incrementByKey('foo', 'foo', 2); var_dump($m->get('foo')); $m->decrementByKey('foo', 'foo'); var_dump($m->get('foo')); $m->decrementByKey('foo', 'foo', 2); var_dump($m->get('foo')); error_reporting(0); echo "Negative offset\n"; error_clear_last(); $m->incrementByKey('foo', 'foo', -1); echo error_get_last()["message"], "\n"; var_dump($m->get('foo')); error_clear_last(); $m->decrementByKey('foo', 'foo', -1); echo error_get_last()["message"], "\n"; var_dump($m->get('foo')); echo "Enormous offset\n"; $m->incrementByKey('foo', 'foo', 0x7f000000); var_dump($m->get('foo')); $m->decrementByKey('foo', 'foo', 0x7f000000); var_dump($m->get('foo')); --EXPECT-- Not there bool(false) bool(false) bool(false) Normal int(1) int(2) int(4) int(3) int(1) Negative offset Memcached::incrementByKey(): offset cannot be a negative value int(1) Memcached::decrementByKey(): offset cannot be a negative value int(1) Enormous offset int(2130706433) int(1) memcached-3.3.0/tests/invalid_options.phpt0000644000076500000240000000054414704245235017504 0ustar mikestaff--TEST-- Get version --SKIPIF-- --FILE-- setOption(500, 23423); var_dump ($m->getResultCode ()); echo "OK" . PHP_EOL; ?> --EXPECTF-- Warning: Memcached::setOption(): error setting memcached option: INVALID ARGUMENTS in %s on line %d int(38) OKmemcached-3.3.0/tests/keys_ascii.phpt0000644000076500000240000000601714704245235016427 0ustar mikestaff--TEST-- Test valid and invalid keys - ascii --SKIPIF-- --FILE-- false, Memcached::OPT_VERIFY_KEY => true )); echo 'ASCII: SPACES' . PHP_EOL; var_dump ($ascii->set ('ascii key with spaces', 'this is a test')); var_dump ($ascii->getResultCode () == Memcached::RES_BAD_KEY_PROVIDED); echo 'ASCII: NEWLINE' . PHP_EOL; var_dump ($ascii->set ('asciikeywithnewline' . PHP_EOL, 'this is a test')); var_dump ($ascii->getResultCode () == Memcached::RES_BAD_KEY_PROVIDED); echo 'ASCII: EMPTY' . PHP_EOL; var_dump ($ascii->set (''/*empty key*/, 'this is a test')); var_dump ($ascii->getResultCode () == Memcached::RES_BAD_KEY_PROVIDED); echo 'ASCII: TOO LONG' . PHP_EOL; var_dump ($ascii->set (str_repeat ('1234567890', 512), 'this is a test')); var_dump ($ascii->getResultCode () == Memcached::RES_BAD_KEY_PROVIDED); echo 'ASCII: GET' . PHP_EOL; for ($i=0;$i<32;$i++) { var_dump ($ascii->get ('asciikeywithnonprintablechar-' . chr($i) . '-here')); var_dump ($ascii->getResultCode () == Memcached::RES_BAD_KEY_PROVIDED); } echo 'ASCII: SET' . PHP_EOL; for ($i=0;$i<32;$i++) { var_dump ($ascii->set ('asciikeywithnonprintablechar-' . chr($i) . '-here', 'this is a test')); var_dump ($ascii->getResultCode () == Memcached::RES_BAD_KEY_PROVIDED); } echo 'OK' . PHP_EOL; --EXPECT-- ASCII: SPACES bool(false) bool(true) ASCII: NEWLINE bool(false) bool(true) ASCII: EMPTY bool(false) bool(true) ASCII: TOO LONG bool(false) bool(true) ASCII: GET bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) ASCII: SET bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) OK memcached-3.3.0/tests/keys_binary.phpt0000644000076500000240000000641014704245235016620 0ustar mikestaff--TEST-- Test valid and invalid keys - binary --SKIPIF-- --FILE-- true, )); echo 'BINARY: SPACES' . PHP_EOL; var_dump ($binary->set ('binary key with spaces', 'this is a test')); var_dump ($binary->getResultCode () == Memcached::RES_SUCCESS); echo 'BINARY: NEWLINE' . PHP_EOL; var_dump ($binary->set ('binarykeywithnewline' . PHP_EOL, 'this is a test')); var_dump ($binary->getResultCode () == Memcached::RES_BAD_KEY_PROVIDED); echo 'BINARY: EMPTY' . PHP_EOL; var_dump ($binary->set (''/*empty key*/, 'this is a test')); var_dump ($binary->getResultCode () == Memcached::RES_BAD_KEY_PROVIDED); echo 'BINARY: TOO LONG' . PHP_EOL; var_dump ($binary->set (str_repeat ('1234567890', 512), 'this is a test')); var_dump ($binary->getResultCode () == Memcached::RES_BAD_KEY_PROVIDED); echo 'BINARY: GET' . PHP_EOL; // Only newline fails in binary mode (char 10) for ($i=0;$i<32;$i++) { $binary->delete ('binarykeywithnonprintablechar-' . chr($i) . '-here'); var_dump ($binary->get ('binarykeywithnonprintablechar-' . chr($i) . '-here')); var_dump ($binary->getResultCode () == Memcached::RES_BAD_KEY_PROVIDED); } echo 'BINARY: SET' . PHP_EOL; // Only newline fails in binary mode (char 10) for ($i=0;$i<32;$i++) { var_dump ($binary->set ('binarykeywithnonprintablechar-' . chr($i) . '-here', 'this is a test')); var_dump ($binary->getResultCode () == Memcached::RES_BAD_KEY_PROVIDED); $binary->delete ('binarykeywithnonprintablechar-' . chr($i) . '-here'); } echo 'OK' . PHP_EOL; --EXPECT-- BINARY: SPACES bool(true) bool(true) BINARY: NEWLINE bool(false) bool(true) BINARY: EMPTY bool(false) bool(true) BINARY: TOO LONG bool(false) bool(true) BINARY: GET bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(true) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) BINARY: SET bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(false) bool(true) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) bool(true) bool(false) OK memcached-3.3.0/tests/testdata.res0000644000076500000240000001141514704245235015731 0ustar mikestaffLorem ipsum dolor sit amet, consectetur adipiscing elit. Ut malesuada purus vel diam congue condimentum. Vivamus diam erat, commodo eget lacinia venenatis, tempor at nulla. Praesent dapibus aliquam lectus. Aliquam erat volutpat. Praesent congue elementum ipsum, eu bibendum nisi ullamcorper nec. Aenean mattis metus quis libero hendrerit blandit accumsan nisi lacinia. Aenean varius sollicitudin nisl, tempor condimentum turpis congue id. Nunc vulputate purus non nunc dignissim tincidunt. Curabitur adipiscing est in ligula interdum a ultrices nibh ultricies. Aliquam a dapibus lectus. Ut eleifend, dui nec aliquam lobortis, quam est luctus lectus, nec hendrerit augue quam ac odio. Nam condimentum, ligula et rhoncus vulputate, lorem urna adipiscing mauris, non mollis velit arcu non urna. Donec sodales ultrices risus, sed hendrerit libero fringilla vitae. Maecenas magna nisl, vehicula scelerisque hendrerit id, fermentum at lorem. Curabitur eu nisl tincidunt arcu venenatis ultricies. Vivamus velit lorem, hendrerit non imperdiet sit amet, eleifend nec mauris. Donec eget condimentum purus. Cras sed lorem sagittis augue faucibus tincidunt. Pellentesque vitae lorem ac orci dignissim tempor. Maecenas diam elit, pulvinar sed gravida rutrum, ultrices vel mauris. In adipiscing placerat eros imperdiet euismod. Nunc quis ante non lectus dictum porta. Nullam orci felis, tristique ut posuere at, tempor sed eros. Pellentesque accumsan posuere magna eu condimentum. Phasellus adipiscing cursus fringilla. Donec diam ipsum, pharetra quis tempus sit amet, mollis in dolor. Pellentesque volutpat vestibulum nulla quis ultricies. Pellentesque scelerisque erat eu nulla ullamcorper tincidunt. Nullam commodo lobortis lacus, ac scelerisque diam dignissim eget. Cras eu metus sed tellus accumsan rutrum id ac nunc. Duis rutrum ipsum quis sapien dictum tincidunt. Duis gravida augue et sapien laoreet at pretium eros vulputate. Duis pulvinar lectus quis libero ultricies consequat a id felis. Morbi imperdiet venenatis ipsum eget ultricies. Vivamus fermentum urna sed massa tristique euismod. Pellentesque sed justo ut mi tincidunt luctus semper et elit. In hac habitasse platea dictumst. Praesent suscipit, elit quis fermentum luctus, magna dolor volutpat tellus, nec blandit nulla metus a lacus. Duis gravida, ipsum eu posuere congue, massa augue semper sapien, vel bibendum mi odio nec lectus. Vivamus lacinia urna vitae justo tincidunt dictum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nunc sed libero metus, in imperdiet nibh. Integer sapien mauris, pretium sed sodales at, blandit in lacus. Etiam a nisl semper enim pellentesque posuere vitae quis lectus. Etiam ut libero at tortor molestie feugiat non ut ligula. Suspendisse fermentum ipsum vel mauris aliquet convallis. Fusce velit turpis, sollicitudin sit amet luctus id, porta nec ipsum. Fusce consequat, risus vel congue sollicitudin, orci sem auctor nisl, eu consectetur neque tortor id neque. Nunc in odio velit. Duis vitae lacus elit, eu fringilla nulla. Phasellus non mi tellus, volutpat commodo lorem. Pellentesque vel ligula enim. Morbi suscipit, orci sed gravida convallis, nunc leo eleifend lacus, quis elementum dui mi nec risus. Mauris faucibus arcu scelerisque tellus semper dictum. Suspendisse vel posuere turpis. Curabitur ipsum ligula, auctor ut dignissim vel, scelerisque vel mauris. Vivamus est dolor, bibendum ac vestibulum a, congue id felis. Mauris rutrum pharetra tempus. Sed ornare congue purus, id adipiscing mi tincidunt at. Maecenas blandit, lorem in malesuada adipiscing, dolor arcu suscipit magna, ut mollis leo nibh non orci. Sed non massa ipsum, et lobortis tortor. Aliquam et egestas velit. Mauris ac sem eget elit imperdiet faucibus at non turpis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Praesent vel dui vitae enim imperdiet sodales. Maecenas a tristique mauris. Praesent consectetur risus sit amet lacus dictum ut egestas nibh lacinia. Mauris quam augue, fringilla ac pretium a, consectetur sed risus. Sed ullamcorper eleifend dolor, id tempor arcu sodales at. Vestibulum eget sagittis libero. Cras ornare dui ac ante pretium fringilla. Morbi eu tincidunt felis. Vivamus ultrices diam in eros elementum luctus. Aenean eu neque nibh. Mauris neque est, euismod ut rutrum nec, vehicula at magna. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce sit amet neque ac justo pretium laoreet. Duis non sapien ut eros tristique porttitor vel et lacus. Donec molestie nunc malesuada ante porta ac pretium magna dictum. Nam dolor orci, lacinia egestas ornare eget, viverra et mi. Vivamus convallis lobortis dui, ac sagittis urna mattis sit amet. Duis interdum, est sed dignissim blandit, metus elit scelerisque mauris, sit amet egestas velit arcu quis nunc. memcached-3.3.0/tests/config.inc0000644000076500000240000000364614704245235015354 0ustar mikestaffsetOptions ($opts) == false) echo "Failed to set options" . PHP_EOL; $memcached->addServer($host, $port); if ($memcached->flush() === false) { return NULL; } return $memcached; } function memc_get_instance (array $opts = array (), $persistent_id = null) { return memc_create_instance(MEMC_SERVER_HOST, MEMC_SERVER_PORT, $opts, $persistent_id); } function memc_get_sasl_instance (array $opts = array (), $persistent_id = null) { return memc_create_instance(MEMC_SASL_SERVER_HOST, MEMC_SASL_SERVER_PORT, $opts, $persistent_id); } function memc_run_test ($test_function, $options = array ()) { foreach ($options as $option_set) { $memc = memc_get_instance ($option_set ['options']); $test_function ($memc, $option_set); } echo "TEST DONE" . PHP_EOL; } function memc_create_combinations ($name, $serializer, $ignore_object_type = false) { return array ( array ( 'title' => "$name serializer, ascii protocol", 'options' => array ( Memcached::OPT_SERIALIZER => $serializer ), 'ignore_object_type' => $ignore_object_type ), array ( 'title' => "$name serializer, binary protocol", 'options' => array ( Memcached::OPT_BINARY_PROTOCOL => true, Memcached::OPT_SERIALIZER => $serializer ), 'ignore_object_type' => $ignore_object_type ), ); } function memc_get_version($memc) { $version = $memc->getVersion(); return array_pop($version); } memcached-3.3.0/tests/sasl_basic.phpt0000644000076500000240000000136514704245235016410 0ustar mikestaff--TEST-- Test SASL authentication --SKIPIF-- --INI-- memcached.use_sasl = on --FILE-- true )); var_dump ($m->setSaslAuthData (MEMC_SASL_USER, MEMC_SASL_PASS)); $key = uniqid ('sasl_test_'); var_dump ($m->set ($key, 'set using sasl')); var_dump ($m->get ($key)); echo "OK" . PHP_EOL; ?> --EXPECT-- bool(true) bool(true) string(14) "set using sasl" OK memcached-3.3.0/tests/set_encoding_key.phpt0000644000076500000240000000257014704245235017615 0ustar mikestaff--TEST-- Test libmemcached encryption --SKIPIF-- --FILE-- setEncodingKey("Hello")); var_dump ($m->set ($key, 'set using encoding')); var_dump ($m->get ($key)); echo "OK" . PHP_EOL; # Change the encryption key. The old value will be inaccessible. var_dump ($m->setEncodingKey("World")); var_dump ($m->get ($key)); echo "OK" . PHP_EOL; # Restore the original key to retrieve old values again. var_dump ($m->setEncodingKey("Hello")); var_dump ($m->get ($key)); echo "OK" . PHP_EOL; # With a new encoding key we can still write new values, # this works as expected with libmemcached 1.0.18 and higher. var_dump ($m->setEncodingKey("World")); var_dump ($m->get ($key)); var_dump ($m->set ($key, 'set using encoding')); var_dump ($m->get ($key)); echo "OK" . PHP_EOL; ?> --EXPECT-- bool(true) bool(true) string(18) "set using encoding" OK bool(true) bool(false) OK bool(true) string(18) "set using encoding" OK bool(true) bool(false) bool(true) string(18) "set using encoding" OK memcached-3.3.0/tests/set_encoding_key2.phpt0000644000076500000240000000200414704245235017667 0ustar mikestaff--TEST-- Test libmemcached encryption --SKIPIF-- = 0x01000018) die ("skip test for libmemcached lower than 1.0.18"); ?> --FILE-- setEncodingKey("Hello")); var_dump ($m->set ($key, 'set using encoding')); var_dump ($m->get ($key)); echo "OK" . PHP_EOL; # libmemcached < 1.0.18 goes into a bad state when the encoding key is changed, # so php-memcached warns and returns false when trying to change the key. var_dump ($m->setEncodingKey("World")); echo "OK" . PHP_EOL; ?> --EXPECTF-- bool(true) bool(true) string(18) "set using encoding" OK Warning: Memcached::setEncodingKey(): libmemcached versions less than 1.0.18 cannot change encoding key in %s on line %d bool(false) OK memcached-3.3.0/tests/getserverbykey.phpt0000644000076500000240000000177714704245235017366 0ustar mikestaff--TEST-- Memcached::getServerByKey() --SKIPIF-- --FILE-- getServerByKey("a")); $m->addServer('localhost', 11211, 1); $m->addServer('localhost', 11212, 1); $m->addServer('localhost', 11213, 1); $m->addServer('localhost', 11214, 1); $m->addServer('localhost', 11215, 1); var_dump($m->getServerByKey("")); echo $m->getResultMessage(), "\n"; var_dump($m->getServerByKey("a")); var_dump($m->getServerByKey("b")); var_dump($m->getServerByKey("c")); var_dump($m->getServerByKey("d")); --EXPECTF-- bool(false) bool(false) A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE array(%d) { ["host"]=> string(%d) "%s" ["port"]=> int(%d) ["weight"]=> int(0) } array(%d) { ["host"]=> string(%d) "%s" ["port"]=> int(%d) ["weight"]=> int(0) } array(%d) { ["host"]=> string(%d) "%s" ["port"]=> int(%d) ["weight"]=> int(0) } array(%d) { ["host"]=> string(%d) "%s" ["port"]=> int(%d) ["weight"]=> int(0) } memcached-3.3.0/tests/gh_155.phpt0000644000076500000240000000231414704245235015270 0ustar mikestaff--TEST-- Test for bug 155 --SKIPIF-- --FILE-- setOption(Memcached::OPT_BINARY_PROTOCOL, true); $m->addServer(MEMC_SERVER_HOST, MEMC_SERVER_PORT); $key = 'bug_155_' . uniqid(); $m->set ($key, 'test', time() + 86400); $m->get ($key); echo "GET: " . $m->getResultMessage() . PHP_EOL; $m->touch ($key, time() + 86400); echo "TOUCH: " . $m->getResultMessage() . PHP_EOL; $m->touch ($key, time() + 86400); echo "TOUCH: " . $m->getResultMessage() . PHP_EOL; $m->get ($key); echo "GET: " . $m->getResultMessage() . PHP_EOL; $m->get ($key); echo "GET: " . $m->getResultMessage() . PHP_EOL; echo "DONE" . PHP_EOL; --EXPECT-- GET: SUCCESS TOUCH: SUCCESS TOUCH: SUCCESS GET: SUCCESS GET: SUCCESS DONE memcached-3.3.0/tests/get_flags.phpt0000644000076500000240000000220114704245235016226 0ustar mikestaff--TEST-- Memcached::get/getMulti() flags --SKIPIF-- --FILE-- set ($key1, 'hello1', 20); $m->set ($key2, 'hello2', 20); $value = $m->get($key1); $extended = $m->get($key1, null, Memcached::GET_EXTENDED); var_dump ($value); var_dump ($extended); $values = $m->getMulti(array ($key1, $key2), Memcached::GET_PRESERVE_ORDER); $extended = $m->getMulti(array ($key1, $key2), Memcached::GET_EXTENDED | Memcached::GET_PRESERVE_ORDER); var_dump ($values); var_dump ($extended); echo "OK"; --EXPECTF-- string(6) "hello1" array(3) { ["value"]=> string(6) "hello1" ["cas"]=> int(%d) ["flags"]=> int(0) } array(2) { ["memc.test.%s"]=> string(6) "hello1" ["memc.test.%s"]=> string(6) "hello2" } array(2) { ["memc.test.%s"]=> array(3) { ["value"]=> string(6) "hello1" ["cas"]=> int(%d) ["flags"]=> int(0) } ["memc.test.%s"]=> array(3) { ["value"]=> string(6) "hello2" ["cas"]=> int(%d) ["flags"]=> int(0) } } OKmemcached-3.3.0/tests/session_lock.phpt0000644000076500000240000000275414704245235017003 0ustar mikestaff--TEST-- Session lock --SKIPIF-- = 70100) print "skip"; ?> --INI-- memcached.sess_locking = true memcached.sess_lock_wait_min = 500 memcached.sess_lock_wait_max = 1000 memcached.sess_lock_retries = 3 memcached.sess_prefix = "memc.test." # Turn off binary protocol while the test matrix has older versions of # libmemcached for which the extension warns of a broken touch command. memcached.sess_binary_protocol = Off session.save_handler = memcached --FILE-- addServer(MEMC_SERVER_HOST, MEMC_SERVER_PORT); ob_start(); ini_set ('session.save_path', MEMC_SERVER_HOST . ':' . MEMC_SERVER_PORT); session_start(); $session_id = session_id(); $_SESSION["test"] = "hello"; session_write_close(); session_start(); var_dump ($m->get ('memc.test.' . session_id())); var_dump ($m->get ('memc.test.lock.' . session_id())); session_write_close(); var_dump ($m->get ('memc.test.lock.' . session_id())); // Test lock min / max $m->set ('memc.test.lock.' . $session_id, '1'); $time_start = microtime(true); session_start(); $time = microtime(true) - $time_start; if (round ($time, 1) != 2.5) { echo "Waited longer than expected: $time" . PHP_EOL; } echo "OK"; --EXPECTF-- string(17) "test|s:5:"hello";" string(1) "1" bool(false) Warning: session_start(): Unable to clear session lock record in %s on line %d OK memcached-3.3.0/tests/session_lazy_warning.phpt0000644000076500000240000000200414704245235020543 0ustar mikestaff--TEST-- Session lazy binary warning old libmemcached --SKIPIF-- = 0x01000018) die ('skip too recent libmemcached'); ?> --INI-- session.save_handler = memcached memcached.sess_binary_protocol = On --FILE-- TRUE]); $_SESSION['foo'] = 1; session_write_close(); $_SESSION = NULL; var_dump($_SESSION); session_start(); var_dump($_SESSION); session_write_close(); session_start(); session_destroy(); session_start(); var_dump($_SESSION); session_write_close(); --EXPECTF-- NULL array(1) { ["foo"]=> int(1) } Warning: session_write_close(): using touch command with binary protocol is not recommended with libmemcached versions below 1.0.18, please use ascii protocol or upgrade libmemcached in %s on line %d array(0) { } memcached-3.3.0/tests/session_regenerate.phpt0000644000076500000240000000074514704245235020172 0ustar mikestaff--TEST-- Session regenerate --SKIPIF-- --INI-- session.save_handler = memcached --FILE-- --FILE-- getStats(); $key = MEMC_SERVER_HOST . ':' . MEMC_SERVER_PORT; var_dump (count ($stats) === 1); var_dump (isset ($stats[$key])); var_dump (count ($stats[$key]) > 0); var_dump (is_int ($stats[$key]['cmd_get'])); echo "OK"; ?> --EXPECT-- bool(true) bool(true) bool(true) bool(true) OK memcached-3.3.0/tests/stats_hang.phpt0000644000076500000240000000425514704245235016441 0ustar mikestaff--TEST-- Check stats does not hang on non-blocking binary protocol --SKIPIF-- --FILE-- setOption(Memcached::OPT_NO_BLOCK, true); $m->setOption(Memcached::OPT_BINARY_PROTOCOL, true); $stats = $m->getStats(); $conns1 = $stats[$key]['total_connections']; $stats = $m->getStats(); $conns2 = $stats[$key]['total_connections']; var_dump($conns1 == $conns2); var_dump($m->getOption(Memcached::OPT_NO_BLOCK)); var_dump($m->getOption(Memcached::OPT_BINARY_PROTOCOL)); echo "OK" . PHP_EOL; // If either or both options are false no need to reconnect $m->setOption(Memcached::OPT_NO_BLOCK, false); $m->setOption(Memcached::OPT_BINARY_PROTOCOL, true); $stats = $m->getStats(); $conns1 = $stats[$key]['total_connections']; $stats = $m->getStats(); $conns2 = $stats[$key]['total_connections']; var_dump($conns1 == $conns2); var_dump($m->getOption(Memcached::OPT_NO_BLOCK)); var_dump($m->getOption(Memcached::OPT_BINARY_PROTOCOL)); echo "OK" . PHP_EOL; // If either or both options are false no need to reconnect $m->setOption(Memcached::OPT_NO_BLOCK, true); $m->setOption(Memcached::OPT_BINARY_PROTOCOL, false); $stats = $m->getStats(); $conns1 = $stats[$key]['total_connections']; $stats = $m->getStats(); $conns2 = $stats[$key]['total_connections']; var_dump($conns1 == $conns2); var_dump($m->getOption(Memcached::OPT_NO_BLOCK)); var_dump($m->getOption(Memcached::OPT_BINARY_PROTOCOL)); echo "OK" . PHP_EOL; // If either or both options are false no need to reconnect $m->setOption(Memcached::OPT_NO_BLOCK, false); $m->setOption(Memcached::OPT_BINARY_PROTOCOL, false); $stats = $m->getStats(); $conns1 = $stats[$key]['total_connections']; $stats = $m->getStats(); $conns2 = $stats[$key]['total_connections']; var_dump($conns1 == $conns2); var_dump($m->getOption(Memcached::OPT_NO_BLOCK)); var_dump($m->getOption(Memcached::OPT_BINARY_PROTOCOL)); echo "OK" . PHP_EOL; ?> --EXPECT-- bool(false) int(1) int(1) OK bool(true) int(0) int(1) OK bool(true) int(1) int(0) OK bool(true) int(0) int(0) OK memcached-3.3.0/tests/default_behavior.phpt0000644000076500000240000000147214704245235017607 0ustar mikestaff--TEST-- Default behaviors --SKIPIF-- --FILE-- getOption(Memcached::OPT_DISTRIBUTION) == Memcached::DISTRIBUTION_MODULA); var_dump ($m->getOption(Memcached::OPT_BINARY_PROTOCOL) == false); var_dump ($m->getOption(Memcached::OPT_CONNECT_TIMEOUT) != 0); ini_set('memcached.default_consistent_hash', true); ini_set('memcached.default_binary_protocol', true); ini_set('memcached.default_connect_timeout', 1212); $m = new Memcached(); var_dump ($m->getOption(Memcached::OPT_DISTRIBUTION) == Memcached::DISTRIBUTION_CONSISTENT); var_dump ($m->getOption(Memcached::OPT_BINARY_PROTOCOL) == true); var_dump ($m->getOption(Memcached::OPT_CONNECT_TIMEOUT) == 1212); echo "OK"; ?> --EXPECT-- bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) OK memcached-3.3.0/tests/reset_keyprefix.phpt0000644000076500000240000000144014704245235017507 0ustar mikestaff--TEST-- Cannot reset OPT_PREFIX_KEY #293 --SKIPIF-- --FILE-- set('key1', 'abc'); var_dump($m->get('key1')); $m->setOption(Memcached::OPT_PREFIX_KEY, 'prefix'); var_dump($m->get('key1')); $m->setOption(Memcached::OPT_PREFIX_KEY, false); var_dump($m->get('key1')); $m->setOption(Memcached::OPT_PREFIX_KEY, 'prefix'); var_dump($m->get('key1')); $m->setOption(Memcached::OPT_PREFIX_KEY, ''); var_dump($m->get('key1')); $m->setOption(Memcached::OPT_PREFIX_KEY, 'prefix'); var_dump($m->get('key1')); $m->setOption(Memcached::OPT_PREFIX_KEY, null); var_dump($m->get('key1')); --EXPECTF-- string(3) "abc" bool(false) string(3) "abc" bool(false) string(3) "abc" bool(false) string(3) "abc"memcached-3.3.0/tests/session_lock-php71.phpt0000644000076500000240000000312614704245235017732 0ustar mikestaff--TEST-- Session lock --SKIPIF-- --INI-- memcached.sess_locking = true memcached.sess_lock_wait_min = 500 memcached.sess_lock_wait_max = 1000 memcached.sess_lock_retries = 3 memcached.sess_prefix = "memc.test." # Turn off binary protocol while the test matrix has older versions of # libmemcached for which the extension warns of a broken touch command. memcached.sess_binary_protocol = Off session.save_handler = memcached --FILE-- addServer(MEMC_SERVER_HOST, MEMC_SERVER_PORT); ob_start(); ini_set ('session.save_path', MEMC_SERVER_HOST . ':' . MEMC_SERVER_PORT); session_start(); $session_id = session_id(); $_SESSION["test"] = "hello"; session_write_close(); session_start(); var_dump ($m->get ('memc.test.' . session_id())); var_dump ($m->get ('memc.test.lock.' . session_id())); session_write_close(); var_dump ($m->get ('memc.test.lock.' . session_id())); // Test lock min / max $m->set ('memc.test.lock.' . $session_id, '1'); $time_start = microtime(true); session_start(); $time = microtime(true) - $time_start; if (round ($time, 1) != 2.5) { echo "Waited longer than expected: $time" . PHP_EOL; } echo "OK"; --EXPECTF-- string(17) "test|s:5:"hello";" string(1) "1" bool(false) Warning: session_start(): Unable to clear session lock record in %s on line %d Warning: session_start(): Failed to read session data: memcached (path: 127.0.0.1:11211) in %s on line %d OK memcached-3.3.0/tests/server.inc0000644000076500000240000000441214704245235015405 0ustar mikestaff STDIN, 1 => STDOUT, 2 => STDERR, ); $cmd = "{$php_executable} {$php_args} {$code} {$host}:{$port} "; if (substr(PHP_OS, 0, 3) == 'WIN') { $cmd = "{$php_executable} {$php_args} {$code} {$host}:{$port} "; $handle = proc_open(addslashes($cmd), $descriptorspec, $pipes, __DIR__, NULL, array("bypass_shell" => true, "suppress_errors" => true)); } else { $cmd = "exec {$cmd} 2>/dev/null"; $handle = proc_open($cmd, $descriptorspec, $pipes, __DIR__); } // note: even when server prints 'Listening on localhost:8964...Press Ctrl-C to quit.' // it might not be listening yet...need to wait until fsockopen() call returns $error = "Unable to connect to server\n"; for ($i=0; $i < getenv("VALGRIND") ? 1000 : 60; $i++) { usleep(50000); // 50ms per try $status = proc_get_status($handle); $fp = @fsockopen($host, $port); // Failure, the server is no longer running if (!($status && $status['running'])) { $error = "Server is not running {$status['command']}\n"; break; } // Success, Connected to servers if ($fp) { $error = ''; break; } } if ($fp) { fclose($fp); } if ($error) { echo $error; proc_terminate($handle); proc_close($handle); exit(1); } register_shutdown_function( function($handle) { if (is_resource($handle)) { proc_terminate($handle); proc_close($handle); } }, $handle ); return $handle; } function memcached_server_stop($handle) { $success = FALSE; if ($handle) { proc_terminate($handle); /* Wait for server to shutdown */ for ($i = 0; $i < 60; $i++) { $status = proc_get_status($handle); if (!($status && $status['running'])) { $success = TRUE; break; } usleep(50000); } proc_close($handle); } return $success; } memcached-3.3.0/tests/server.php0000644000076500000240000001127414704245235015427 0ustar mikestaffon (Memcached::ON_CONNECT, function ($remote_addr) { echo "Incoming connection from {$remote_addr}" . PHP_EOL; return Memcached::RESPONSE_SUCCESS; }); $server->on (Memcached::ON_ADD, function ($client_id, $key, $value, $flags, $expiration, &$cas) { echo "client_id=[$client_id]: Add key=[$key], value=[$value], flags=[$flags], expiration=[$expiration]" . PHP_EOL; $cas = 15; return Memcached::RESPONSE_SUCCESS; }); $server->on (Memcached::ON_APPEND, function ($client_id, $key, $value, $cas, &$result_cas) { echo "client_id=[$client_id]: Append key=[$key], value=[$value], cas=[$cas]" . PHP_EOL; return Memcached::RESPONSE_SUCCESS; }); $server->on (Memcached::ON_PREPEND, function ($client_id, $key, $value, $cas, &$result_cas) { echo "client_id=[$client_id]: Prepend key=[$key], value=[$value], cas=[$cas]" . PHP_EOL; return Memcached::RESPONSE_SUCCESS; }); $server->on (Memcached::ON_INCREMENT, function ($client_id, $key, $delta, $initial, $expiration, &$result, &$result_cas) { echo "client_id=[$client_id]: Incrementing key=[$key], delta=[$delta], initial=[$initial], expiration=[$expiration]" . PHP_EOL; return Memcached::RESPONSE_SUCCESS; }); $server->on (Memcached::ON_DECREMENT, function ($client_id, $key, $delta, $initial, $expiration, &$result, &$result_cas) { echo "client_id=[$client_id]: Decrementing key=[$key], delta=[$delta], initial=[$initial], expiration=[$expiration]" . PHP_EOL; return Memcached::RESPONSE_SUCCESS; }); $server->on (Memcached::ON_DELETE, function ($client_id, $key, $cas) { echo "client_id=[$client_id]: Delete key=[$key], cas=[$cas]" . PHP_EOL; return Memcached::RESPONSE_SUCCESS; }); $server->on (Memcached::ON_FLUSH, function ($client_id, $when) { echo "client_id=[$client_id]: Flush when=[$when]" . PHP_EOL; return Memcached::RESPONSE_SUCCESS; }); $server->on (Memcached::ON_GET, function ($client_id, $key, &$value, &$flags, &$cas) { echo "client_id=[$client_id]: Get key=[$key]" . PHP_EOL; $value = "Hello to you client!"; return Memcached::RESPONSE_SUCCESS; }); $server->on (Memcached::ON_NOOP, function ($client_id) { echo "client_id=[$client_id]: Noop" . PHP_EOL; return Memcached::RESPONSE_SUCCESS; }); $server->on (Memcached::ON_REPLACE, function ($client_id, $key, $value, $flags, $expiration, $cas, &$result_cas) { echo "client_id=[$client_id]: Replace key=[$key], value=[$value], flags=[$flags], expiration=[$expiration], cas=[$cas]" . PHP_EOL; return Memcached::RESPONSE_SUCCESS; }); $server->on (Memcached::ON_SET, function ($client_id, $key, $value, $flags, $expiration, $cas, &$result_cas) { echo "client_id=[$client_id]: Set key=[$key], value=[$value], flags=[$flags], expiration=[$expiration], cas=[$cas]" . PHP_EOL; return Memcached::RESPONSE_SUCCESS; }); $server->on (Memcached::ON_STAT, function ($client_id, $key, array &$values) { echo "client_id=[$client_id]: Stat key=[$key]" . PHP_EOL; if ($key === "scalar") { $values = "you want it, you get it"; } elseif ($key === "numeric array") { $values = [-1 => "one", "two", "three"]; } elseif ($key === "empty") { $values = []; } else { $values["key"] = $key; $values["foo"] = "bar"; } return Memcached::RESPONSE_SUCCESS; }); $server->on (Memcached::ON_VERSION, function ($client_id, &$value) { echo "client_id=[$client_id]: Version" . PHP_EOL; $value = "1.1.1"; return Memcached::RESPONSE_SUCCESS; }); $server->on (Memcached::ON_QUIT, function ($client_id) { echo "client_id=[$client_id]: Client quit" . PHP_EOL; return Memcached::RESPONSE_SUCCESS; }); $addr = ($_SERVER['argv'][1] ?? "127.0.0.1:3434"); echo "Listening on $addr" . PHP_EOL; $server->run($addr); memcached-3.3.0/tests/memcachedserver.phpt0000644000076500000240000000553014704245235017440 0ustar mikestaff--TEST-- MemcachedServer --SKIPIF-- --FILE-- setOption(Memcached::OPT_BINARY_PROTOCOL, true); $cache->setOption(Memcached::OPT_COMPRESSION, false); $cache->addServer('127.0.0.1', 3434); $cache->add("add_key", "hello", 500); $cache->append("append_key", "world"); $cache->prepend("prepend_key", "world"); $cache->increment("incr", 2, 1, 500); $cache->decrement("decr", 2, 1, 500); $cache->delete("delete_k"); $cache->flush(1); var_dump($cache->get('get_this')); $cache->set ('set_key', 'value 1', 100); $cache->replace ('replace_key', 'value 2', 200); var_dump($cache->getVersion()); var_dump($cache->getStats()); var_dump($cache->getStats("empty")); var_dump($cache->getStats("foobar")); var_dump($cache->getStats("scalar")); var_dump($cache->getStats("numeric array")); $cache->quit(); usleep(50000); memcached_server_stop($server); ?> Done --EXPECTF-- Listening on 127.0.0.1:3434 Incoming connection from 127.0.0.1:%s Incoming connection from 127.0.0.1:%s client_id=[%s]: Add key=[add_key], value=[hello], flags=[0], expiration=[500] client_id=[%s]: Append key=[append_key], value=[world], cas=[0] client_id=[%s]: Prepend key=[prepend_key], value=[world], cas=[0] client_id=[%s]: Incrementing key=[incr], delta=[2], initial=[1], expiration=[500] client_id=[%s]: Decrementing key=[decr], delta=[2], initial=[1], expiration=[500] client_id=[%s]: Delete key=[delete_k], cas=[0] client_id=[%s]: Flush when=[1] client_id=[%s]: Get key=[get_this] client_id=[%s]: Noop string(20) "Hello to you client!" client_id=[%s]: Set key=[set_key], value=[value 1], flags=[0], expiration=[100], cas=[0] client_id=[%s]: Replace key=[replace_key], value=[value 2], flags=[0], expiration=[200], cas=[0] client_id=[%s]: Version array(1) { ["127.0.0.1:3434"]=> string(5) "1.1.1" } client_id=[%s]: Stat key=[] array(1) { ["127.0.0.1:3434"]=> array(2) { ["key"]=> string(0) "" ["foo"]=> string(3) "bar" } } client_id=[%s]: Stat key=[empty] array(0) { } client_id=[%s]: Stat key=[foobar] array(1) { ["127.0.0.1:3434"]=> array(2) { ["key"]=> string(6) "foobar" ["foo"]=> string(3) "bar" } } client_id=[%s]: Stat key=[scalar] array(1) { ["127.0.0.1:3434"]=> array(1) { [0]=> string(%d) "you want it, you get it" } } client_id=[%s]: Stat key=[numeric array] array(1) { ["127.0.0.1:3434"]=> array(3) { [-1]=> string(3) "one" [0]=> string(3) "two" [1]=> string(5) "three" } } client_id=[%s]: Client quit Done memcached-3.3.0/tests/memcachedserver6.phpt0000644000076500000240000000551714704245235017533 0ustar mikestaff--TEST-- MemcachedServer --SKIPIF-- --FILE-- setOption(Memcached::OPT_BINARY_PROTOCOL, true); $cache->setOption(Memcached::OPT_COMPRESSION, false); $cache->addServer('[::1]', 3434); $cache->add("add_key", "hello", 500); $cache->append("append_key", "world"); $cache->prepend("prepend_key", "world"); $cache->increment("incr", 2, 1, 500); $cache->decrement("decr", 2, 1, 500); $cache->delete("delete_k"); $cache->flush(1); var_dump($cache->get('get_this')); $cache->set ('set_key', 'value 1', 100); $cache->replace ('replace_key', 'value 2', 200); var_dump($cache->getVersion()); var_dump($cache->getStats()); var_dump($cache->getStats("empty")); var_dump($cache->getStats("foobar")); var_dump($cache->getStats("scalar")); var_dump($cache->getStats("numeric array")); $cache->quit(); usleep(50000); memcached_server_stop($server); ?> Done --EXPECTF-- Listening on [::1]:3434 Incoming connection from [::1]:%s Incoming connection from [::1]:%s client_id=[%s]: Add key=[add_key], value=[hello], flags=[0], expiration=[500] client_id=[%s]: Append key=[append_key], value=[world], cas=[0] client_id=[%s]: Prepend key=[prepend_key], value=[world], cas=[0] client_id=[%s]: Incrementing key=[incr], delta=[2], initial=[1], expiration=[500] client_id=[%s]: Decrementing key=[decr], delta=[2], initial=[1], expiration=[500] client_id=[%s]: Delete key=[delete_k], cas=[0] client_id=[%s]: Flush when=[1] client_id=[%s]: Get key=[get_this] client_id=[%s]: Noop string(20) "Hello to you client!" client_id=[%s]: Set key=[set_key], value=[value 1], flags=[0], expiration=[100], cas=[0] client_id=[%s]: Replace key=[replace_key], value=[value 2], flags=[0], expiration=[200], cas=[0] client_id=[%s]: Version array(1) { ["[::1]:3434"]=> string(5) "1.1.1" } client_id=[%s]: Stat key=[] array(1) { ["[::1]:3434"]=> array(2) { ["key"]=> string(0) "" ["foo"]=> string(3) "bar" } } client_id=[%s]: Stat key=[empty] array(0) { } client_id=[%s]: Stat key=[foobar] array(1) { ["[::1]:3434"]=> array(2) { ["key"]=> string(6) "foobar" ["foo"]=> string(3) "bar" } } client_id=[%s]: Stat key=[scalar] array(1) { ["[::1]:3434"]=> array(1) { [0]=> string(%d) "you want it, you get it" } } client_id=[%s]: Stat key=[numeric array] array(1) { ["[::1]:3434"]=> array(3) { [-1]=> string(3) "one" [0]=> string(3) "two" [1]=> string(5) "three" } } client_id=[%s]: Client quit Done memcached-3.3.0/README.markdown0000644000076500000240000000365014704245235014746 0ustar mikestaffBuild Status ------------ ![Build Status](https://github.com/php-memcached-dev/php-memcached/actions/workflows/build-and-test.yml/badge.svg?branch=master) Description ----------- This is the [PECL memcached](https://pecl.php.net/package/memcached) extension, using the libmemcached library to connect to memcached servers. [memcached](https://memcached.org) is a high-performance, distributed memory object caching system, generic in nature, but intended for use in speeding up dynamic web applications by alleviating database load. Building -------- $ phpize $ ./configure $ make $ make test Dependencies ------------ php-memcached 3.x: * Supports PHP 7.0 - 8.3 or higher. * Requires libmemcached 1.x or higher. * Optionally supports igbinary 2.0 or higher. * Optionally supports msgpack 2.0 or higher. php-memcached 2.x: * Supports PHP 5.2 - 5.6. * Requires libmemcached 0.44 or higher. * Optionally supports igbinary 1.0 or higher. * Optionally supports msgpack 0.5 or higher. [libmemcached](http://libmemcached.org/libMemcached.html) or the new [libmemcached-awesome](https://github.com/awesomized/libmemcached) version 1.0.18 or higher is recommended for best performance and compatibility with memcached servers. [igbinary](https://github.com/igbinary/igbinary) is a faster and more compact binary serializer for PHP data structures. When installing php-memcached from source code, the igbinary module must be installed first so that php-memcached can access its C header files. Load both modules in your `php.ini` at runtime to begin using igbinary. [msgpack](https://msgpack.org) is a faster and more compact data structure representation that is interoperable with msgpack implementations for other languages. When installing php-memcached from source code, the msgpack module must be installed first so that php-memcached can access its C header files. Load both modules in your `php.ini` at runtime to begin using msgpack. memcached-3.3.0/CREDITS0000644000076500000240000000007314704245235013261 0ustar mikestaffmemcached Andrei Zmievski, Oleg Grenrus (igbinary support) memcached-3.3.0/LICENSE0000644000076500000240000000622214704245235013250 0ustar mikestaff-------------------------------------------------------------------- The PHP License, version 3.01 Copyright (c) 1999 - 2010 The PHP Group. All rights reserved. -------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name "PHP" must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact group@php.net. 4. Products derived from this software may not be called "PHP", nor may "PHP" appear in their name, without prior written permission from group@php.net. You may indicate that your software works in conjunction with PHP by saying "Foo for PHP" instead of calling it "PHP Foo" or "phpfoo" 5. The PHP Group may publish revised and/or new versions of the license from time to time. Each version will be given a distinguishing version number. Once covered code has been published under a particular version of the license, you may always continue to use it under the terms of that version. You may also choose to use such covered code under the terms of any subsequent version of the license published by the PHP Group. No one other than the PHP Group has the right to modify the terms applicable to covered code created under this License. 6. Redistributions of any form whatsoever must retain the following acknowledgment: "This product includes PHP software, freely available from ". THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------- This software consists of voluntary contributions made by many individuals on behalf of the PHP Group. The PHP Group can be contacted via Email at group@php.net. For more information on the PHP Group and the PHP project, please see . PHP includes the Zend Engine, freely available at . memcached-3.3.0/ChangeLog0000644000076500000240000002741714704245235014026 0ustar mikestaffmemcached extension changelog Version 3.1.5 (2019-12-03) -------------------------- * Fix build with PHP 7.4 release due to ulong typedef removal (#445) Version 3.1.4 (2019-10-06) -------------------------- * Test on PHP 7.4 as well as 8.0 (#440) * Fix segfault for unknown memcached flags (#431) * Update documented defaults for sess_lock_retries( #432) * Remove stray instances of the TSRMLS_CC macro for PHP 8 compatibility (#444) Version 3.1.3 (2018-12-24) -------------------------- * Fix --disable-memcached-session by ifdef-ing session INI handler callbacks (#396, #420) Version 3.1.2 (2018-12-22) -------------------------- * Fix --enable-memcached-protocol was set to yes by default, reverted to no (#418) Version 3.1.1 (2018-12-21) -------------------------- * Fix --disable-memcached-sasl and --disable-memcached-session replaced by --enable variants (#416) Version 3.1.0 (2018-12-21) -------------------------- New * Support for PHP 7.3 (#385, #390) * Add INI setting to choose session consistent hash (ketama or ketama_weighted) (#344, #392) * Add support for libmemcached encryption (#345, #381) * Add error reporting to session code (#165) * Expose build configuration via PECL (#383) Fixes * Fix hanging getStats() when binary protocol and non-blocking are both enabled (#348) * Fix session persistence by checking memcached behavior values before setting (#379) * Fix memcached.sess_persistent not working with memcached.sess_binary_protocol = On (#375) * Configure warns if libmemcached needs sasl.h (#341, #380) * Resolve various INI deviations in 3.0.3 (#351) * Turn off sess_binary_protocol by default with older libmemcached (#330) Changes * Impove Windows builds (#411) * Support Homebrew ZLIB path (#410) * Remove forgotten unused comment about -lpthread (#406) * Git ignore configure.ac (#405) * Replace obsolete macros AC_TRY_FOO with AC_FOO_IFELSE (#403) * Remove unused defines (#354) * Change session_lock and sess_prefix default ini values (#340, #350) * Use new fast_zpp parameter parsing API (#302, #311) Version 3.0.4 (2017-11-20) -------------------------- * Fix corrupted interned strings (#338) * Fix unit tests for compatibility with PHP 7.2 (#358, #359) * Fix \x0a in key name locks up connection and triggers a fatal timeout error (#339) * Fix missing optional parameter getStats($type) (#337) * Fix typo in skip message (#331) * Fix build warnings (#329) * Document GET_EXTENDED flag, add/rename other missing/misnamed constants (#335) Version 3.0.3 (2017-02-19) -------------------------- * Fix crash when checking session data with older versions of libmemcached (#328) * Fix crash due to zend_mm_corrupted when fetching session data (#327) Version 3.0.2 (2017-02-12) -------------------------- * Update warning for touch command in binary protocol mode with libmemcached < 1.0.18 (#322) * Add tests for 64-bit increment/decrement/incrementByKey/decrementByKey (#321) * Fix tests for 32-bit increment/decrement/incrementByKey/decrementByKey (#319) Version 3.0.1 (2017-02-07) -------------------------- * Add API entries for flushBuffers() and getAllKeys() (#316) * Ignore specific errors from memcached_dump for getAllKeys() with newer memcached servers (#315) * Fix compiling with memcached binary protocol enabled (#312) * Restore php_libmemcached_compat with workaround for missing memcached_exists (#314) * Travis CI purge old versions of memcached and libmemcached (#309) Version 3.0.0 (2017-01-27) -------------------------- * Support for PHP 7.0 and PHP 7.1 * Fix compiling with SASL disabled * Improved the test suite and Travis CI test runners * Fix small string compression / decompression * Fix increment/decrement with adjustments greater than 32-bit integers * Fix session.gc_maxlifetime to handle both relative and absolute times * Fix inability to reset OPT_PREFIX_KEY Version 3.0.0a1 (2016-02-22) ---------------------------- Dependencies * Support for PHP 7.0 * Requires libmemcached 1.0 or higher * Optional extension igbinary must 2.0 or higher * Optional extension msgpack must be 2.0 or higher API * The method signature of get, getByKey, getMulti, and getMultiByKey changed. * get* and getMulti* commands no longer take cas or user flags parameters. * get* and getMulti* commands now take the Memcached::GET_EXTENDED flag to retrieve user flags and cas tokens. * Fixes getStats command to return all stats from all servers * Fixes allKeys command behaviour * Fixes error where cache callback for get command was not setting expiration time properly * Added server type to server list * Remove use_sasl ini-variable and initialise sasl as needed * CAS tokens are returned as integers and they overflow to strings as needed Session handler * The session memcached protocol config name was changed, and the default protocol was changed from text to binary protocol. If your memcached setup does not support the binary protocol(e.g. if using twemproxy), then set memcached.sess_binary_protocol = Off. (Previously called memcached.sess_binary) * Session lock algorithm updated (new ini-values memcached.sess_lock_wait_min, memcached.sess_lock_wait_max and memcached.sess_lock_retries) * Session extension uses PHP allocators (still some work to do on the rest of the extension) * Ini-values take effect during session_start or session_regenerate_id * Fixes crash with session_regenerate_id (work-around for PHP bug) Tests * Fix several problematic tests Version 2.2.0 (2014-04-01) -------------------------- * Added the OPT_SERVER_TIMEOUT_LIMIT behaviour Version 2.2.0RC1 (2014-03-12) ----------------------------- * Added the OPT_SERVER_TIMEOUT_LIMIT behaviour * Fixes incorrect size when compressing serialized objects * Fixes endianess of compressed values Version 2.2.0b1 (2013-10-28) ---------------------------- * Reinstate support for libememcached 0.x series * Added SASL support to session handler * Added Memcached::flushBuffers as per GH #78 * Fixes GH #54: Fixed UDP server adding with newer libmemcached * Fixed PHP bug #65334: (Segfault if uncompress value failed) * Fixes GH #14: get with cas token fails to fetch all results * Fixes GH #68: memcached 2.1.0 requires libmemcached 1.0.10 * Fixes GH #69: compiling on CentOS 6.4 with libmemcached 1.0.17 * Merged PR #91: memcached.sess_lock_wait and memcached.sess_lock_max_wait * Added session handler settings: - memcached.sess_number_of_replicas - memcached.sess_randomize_replica_read - memcached.sess_remove_failed - memcached.sess_connect_timeout * Added support for memcached protocol handlers * Added Memcached::setBucket for virtual bucket support * Added support for msgpack serialization * Memcached::setSaslAuthData returns correct status on success * Added support for user-defined flags in set and get operations Version 2.1.0 (2012-08-06) -------------------------- * Drop support for libmemcached 0.x series, now 1.0.x is required * Add support for virtual bucket distribution * Fix compilation against PHP 5.2 Version 2.0.1 (2012-03-03) -------------------------- * Fix embedded version number to be not -dev Version 2.0.0 (2012-03-02) -------------------------- * Add touch() and touchByKey() methods * Add resetServerList() and quit() methods * Support binary protocol in sessions * Make it work with libmemcached up to 1.0.4 * Test against PHP 5.4.0 Version 2.0.0b2 (2011-06-24) ---------------------------- * Add OPT_REMOVE_FAILED_SERVERS option. * Make it work with libmemcached up to 0.49. * Fix a case where invalid session ID could lock the script. * Improve session support: - Add support for libmemcached config string - Add persistence support via PERSISTENT=persistent_id prefix of the save_path * Add 3rd parameter to the __construct() that allows specification of libmemcached configuration string * Fix a possible crash in __construct() when using persistent connections * Add work-around a bug in libmemcached < 0.50 that causes truncation of last character of server key prefix * When using multiple servers implement transparent fail-over * Fix php_memc_cas_impl() implementation when server_key is not being used * Add support for incrementByKey() and decrementByKey() * Make increment/decrement initialize value when it is not available (when using binary protocol) Version 2.0.0b1 (2011-03-12) ---------------------------- * Add fastlz library that provides better/faster payload compression * Add configure switch to enable/disable JSON serialization support * Add getAllKeys() method * Add deleteMulti() and deleteMultiByKey() methods * Add isPristine() and isPersistent() methods * Add setOptions() method to set multiple options at once * Add SERIALIZER_JSON_ARRAY type that decodes JSON payloads as arrays instead of objects * Add support for Unix domain socket connections * Add memcached.compression_threshold INI setting * Add memcached.compression_factor INI setting * Add memcached.compression_type INI setting * Implement a few speed optimizations * Many bug fixes and memory leaks plugged * Add several more tests * Add constants for libmemcached 0.37+: - Memcached::OPT_NUMBER_OF_REPLICAS - Memcached::OPT_RANDOMIZE_REPLICA_READ * Add 'on_new' callback to constructor * Add SASL support Version 1.0.2 (2010-05-03) -------------------------- * Fix build for libmemcached-0.39 (memcached_server_list() issue) Version 1.0.1 (2010-03-11) -------------------------- * Fix JSON API handling to account for PHP 5.2/5.3 version differences. * Add memcached.sess_locking, memcached.sess_lock_wait, and memcached.sess_prefix INI entries. * Add OPT_AUTO_EJECT_HOSTS option. Version 1.0.0 (2009-07-04) -------------------------- * First stable release. * Add getResultMessage() method. * Fix OPT_RECV_TIMEOUT definition. * Initialize Session lock wait to max execution time (if max execution time is unlimited, default to 30 seconds). Version 0.2.0 (2009-06-04) -------------------------- * Add JSON serializer support, requires PHP 5.2.10+. * Add HAVE_JSON and HAVE_IGBINARY class constants that indicate whether the respective serializers are available. * Add 'flags' parameter to getMulti() and getMultiByKey(). * Add GET_PRESERVE_ORDER class constant that can be used with abovementioned flags parameter to make the order of the keys in the response match the request. * Fix an issue with retrieving 0-length payloads (FALSE boolean value). * Refactor the way payload types are stored in memcached flags to optimize the structure and allow for future expansion. WARNING! You have to flush the cache when upgrading to this version. * Add several tests. Version 0.1.5 (2009-03-31) -------------------------- * Implement getVersion(). * Add support for preserving boolean value types. * Fix crash when child class does not call constructor. * Fix bug #16084 (Crash when addServers is called with an associative array). * ZTS compilation fixes. Version 0.1.4 (2009-02-13) -------------------------- * Fix compilation against PHP 5.3. * Add support for 'igbinary' serializer (Oleg Grenrus) Version 0.1.3 (2009-02-06) -------------------------- * Bludgeon bug #15896 (Memcached setMulti error) into submission. Version 0.1.2 (2009-02-06) -------------------------- * Fix bug #15896 (Memcached setMulti error). * Check for empty key in getServerByKey(). * Allow passing 'null' for callbacks. * get() with cas token fetching wasn't erroring out properly. * Rename certain parameters in the API to be more clear. * Allow only strings as the append/prepend value. * Remove expiration parameter from append/prepend. Version 0.1.1 (2009-02-02) -------------------------- * Add OPT_LIBKETAMA_COMPATIBLE option. * Implement addServers() method. * Swap internal compressed and serialized flags to be compatible with other clients. Version 0.1.0 (2009-01-29) -------------------------- * Initial release memcached-3.3.0/memcached-api.php0000644000076500000240000001606714704245235015441 0ustar mikestaff comp_len * factor ; ; the default value is 1.3 (23% space saving) ;memcached.compression_factor = "1.3" ; The compression threshold ; ; Do not compress serialized values below this threshold. ; the default is 2000 bytes ;memcached.compression_threshold = 2000 ; Set the default serializer for new memcached objects. ; valid values are: php, igbinary, json, json_array, msgpack ; ; json - standard php JSON encoding. This serializer ; is fast and compact but only works on UTF-8 ; encoded data and does not fully implement ; serializing. See the JSON extension. ; json_array - as json, but decodes into arrays ; php - the standard php serializer ; igbinary - a binary serializer ; msgpack - a cross-language binary serializer ; ; The default is igbinary if available, then msgpack if available, then php otherwise. ;memcached.serializer = "igbinary" ; The amount of retries for failed store commands. ; This mechanism allows transparent fail-over to secondary servers when ; set/increment/decrement/setMulti operations fail on the desired server in a multi-server ; environment. ; the default is 0 ;memcached.store_retry_count = 0 ; The maximum payload size in bytes that can be written. ; Writing a payload larger than the limit will result in RES_E2BIG error. ; Specifying 0 means no limit is enforced, though the server may still reject with RES_E2BIG. ; Default is 0. ;memcached.item_size_limit = 1000000 ; Sets the default for consistent hashing for new connections. ; (To configure consistent hashing for session connections, ; use memcached.sess_consistent_hash instead) ; ; If set to On, consistent hashing (libketama) is used ; for session handling. ; When consistent hashing is used, one can add or remove cache ; node(s) without messing up too much with existing keys ; default is Off ;memcached.default_consistent_hash = Off ; Sets the default memcached protocol for new connections. ; (To configure the memcached protocol for connections used by sessions, ; use memcached.sess_binary_protocol instead) ; ; If set to On, the memcached binary protocol is used by default. ; If set to Off, the memcached text protocol is used. ; Default is Off ;memcached.default_binary_protocol = Off ; Sets the default memcached connection timeout for new connections. ; (To configure the memcached connection timeout for sessions, ; use memcached.sess_connect_timeout instead) ; In non-blocking mode this changes the value of the timeout. ; during socket connection in milliseconds. Specifying -1 means an infinite timeout. ; Specifying 0 means using the memcached library's default connection timeout. ; Default is 0. ;memcached.default_connect_timeout = 0 memcached-3.3.0/fastlz/LICENSE0000644000076500000240000000231214704245235014547 0ustar mikestaffFastLZ - lightning-fast lossless compression library Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. memcached-3.3.0/config.m40000644000076500000240000003607714704245235013765 0ustar mikestaffdnl vim:se ts=2 sw=2 et: PHP_ARG_ENABLE(memcached, whether to enable memcached support, [ --enable-memcached Enable memcached support]) PHP_ARG_WITH(libmemcached-dir, for libmemcached, [ --with-libmemcached-dir=DIR Set the path to libmemcached install prefix.], yes) PHP_ARG_ENABLE(memcached-session, whether to enable memcached session handler support, [ --enable-memcached-session Enable memcached session handler support], yes, no) PHP_ARG_ENABLE(memcached-igbinary, whether to enable memcached igbinary serializer support, [ --enable-memcached-igbinary Enable memcached igbinary serializer support], no, no) PHP_ARG_ENABLE(memcached-json, whether to enable memcached json serializer support, [ --enable-memcached-json Enable memcached json serializer support], no, no) PHP_ARG_ENABLE(memcached-msgpack, whether to enable memcached msgpack serializer support, [ --enable-memcached-msgpack Enable memcached msgpack serializer support], no, no) PHP_ARG_ENABLE(memcached-sasl, whether to enable memcached sasl support, [ --enable-memcached-sasl Enable memcached sasl support], yes, no) PHP_ARG_ENABLE(memcached-protocol, whether to enable memcached protocol support, [ --enable-memcached-protocol Enable memcached protocol support], no, no) PHP_ARG_WITH(system-fastlz, whether to use system FastLZ library, [ --with-system-fastlz Use system FastLZ library], no, no) PHP_ARG_WITH(zstd, whether to use system zstd library, [ --with-zstd Use system zstd library], no, no) if test -z "$PHP_ZLIB_DIR"; then PHP_ARG_WITH(zlib-dir, for ZLIB, [ --with-zlib-dir=DIR Set the path to ZLIB install prefix.], no) fi if test -z "$PHP_DEBUG"; then AC_ARG_ENABLE(debug, [ --enable-debug Compile with debugging symbols],[ PHP_DEBUG=$enableval ],[ PHP_DEBUG=no ]) fi if test "$PHP_MEMCACHED" != "no"; then AC_PATH_PROG(PKG_CONFIG, pkg-config, no) if test "x$PKG_CONFIG" = "xno"; then AC_MSG_RESULT([pkg-config not found]) AC_MSG_ERROR([Please reinstall the pkg-config distribution]) fi dnl # zlib if test "$PHP_ZLIB_DIR" != "no" && test "$PHP_ZLIB_DIR" != "yes"; then if test -f "$PHP_ZLIB_DIR/include/zlib/zlib.h"; then PHP_ZLIB_DIR="$PHP_ZLIB_DIR" PHP_ZLIB_INCDIR="$PHP_ZLIB_DIR/include/zlib" elif test -f "$PHP_ZLIB_DIR/include/zlib.h"; then PHP_ZLIB_DIR="$PHP_ZLIB_DIR" PHP_ZLIB_INCDIR="$PHP_ZLIB_DIR/include" else AC_MSG_ERROR([Can't find ZLIB headers under "$PHP_ZLIB_DIR"]) fi else for i in /usr/local /usr/local/opt/zlib /usr; do if test -f "$i/include/zlib/zlib.h"; then PHP_ZLIB_DIR="$i" PHP_ZLIB_INCDIR="$i/include/zlib" elif test -f "$i/include/zlib.h"; then PHP_ZLIB_DIR="$i" PHP_ZLIB_INCDIR="$i/include" fi done fi AC_MSG_CHECKING([for zlib location]) if test "$PHP_ZLIB_DIR" != "no" && test "$PHP_ZLIB_DIR" != "yes"; then AC_MSG_RESULT([$PHP_ZLIB_DIR]) PHP_ADD_LIBRARY_WITH_PATH(z, $PHP_ZLIB_DIR/$PHP_LIBDIR, MEMCACHED_SHARED_LIBADD) PHP_ADD_INCLUDE($PHP_ZLIB_INCDIR) else AC_MSG_ERROR([memcached support requires ZLIB. Use --with-zlib-dir= to specify the prefix where ZLIB headers and library are located]) fi if test "$PHP_MEMCACHED_SESSION" != "no"; then AC_MSG_CHECKING([for session includes]) session_inc_path="" if test -f "$abs_srcdir/include/php/ext/session/php_session.h"; then session_inc_path="$abs_srcdir/include/php" elif test -f "$abs_srcdir/ext/session/php_session.h"; then session_inc_path="$abs_srcdir" elif test -f "$phpincludedir/ext/session/php_session.h"; then session_inc_path="$phpincludedir" else for i in php php4 php5 php6; do if test -f "$prefix/include/$i/ext/session/php_session.h"; then session_inc_path="$prefix/include/$i" fi done fi if test "$session_inc_path" = ""; then AC_MSG_ERROR([Cannot find php_session.h]) else AC_MSG_RESULT([$session_inc_path]) fi fi if test "$PHP_MEMCACHED_JSON" != "no"; then AC_MSG_CHECKING([for json includes]) json_inc_path="" if test -f "$abs_srcdir/include/php/ext/json/php_json.h"; then json_inc_path="$abs_srcdir/include/php" elif test -f "$abs_srcdir/ext/json/php_json.h"; then json_inc_path="$abs_srcdir" elif test -f "$phpincludedir/ext/json/php_json.h"; then json_inc_path="$phpincludedir" else for i in php php4 php5 php6; do if test -f "$prefix/include/$i/ext/json/php_json.h"; then json_inc_path="$prefix/include/$i" fi done fi if test "$json_inc_path" = ""; then AC_MSG_ERROR([Cannot find php_json.h]) else AC_DEFINE(HAVE_JSON_API,1,[Whether JSON API is available]) AC_MSG_RESULT([$json_inc_path]) fi fi if test "$PHP_MEMCACHED_IGBINARY" != "no"; then AC_MSG_CHECKING([for igbinary includes]) igbinary_inc_path="" if test -f "$abs_srcdir/include/php/ext/igbinary/igbinary.h"; then igbinary_inc_path="$abs_srcdir/include/php" elif test -f "$abs_srcdir/ext/igbinary/igbinary.h"; then igbinary_inc_path="$abs_srcdir" elif test -f "$phpincludedir/ext/session/igbinary.h"; then igbinary_inc_path="$phpincludedir" elif test -f "$phpincludedir/ext/igbinary/igbinary.h"; then igbinary_inc_path="$phpincludedir" else for i in php php4 php5 php6; do if test -f "$prefix/include/$i/ext/igbinary/igbinary.h"; then igbinary_inc_path="$prefix/include/$i" fi done fi if test "$igbinary_inc_path" = ""; then AC_MSG_ERROR([Cannot find igbinary.h]) else AC_MSG_RESULT([$igbinary_inc_path]) fi fi if test "$PHP_MEMCACHED_MSGPACK" != "no"; then AC_MSG_CHECKING([for msgpack includes]) msgpack_inc_path="" if test -f "$abs_srcdir/include/php/ext/msgpack/php_msgpack.h"; then msgpack_inc_path="$abs_srcdir/include/php" elif test -f "$abs_srcdir/ext/msgpack/php_msgpack.h"; then msgpack_inc_path="$abs_srcdir" elif test -f "$phpincludedir/ext/session/php_msgpack.h"; then msgpack_inc_path="$phpincludedir" elif test -f "$phpincludedir/ext/msgpack/php_msgpack.h"; then msgpack_inc_path="$phpincludedir" else for i in php php4 php5 php6; do if test -f "$prefix/include/$i/ext/msgpack/php_msgpack.h"; then msgpack_inc_path="$prefix/include/$i" fi done fi if test "$msgpack_inc_path" = ""; then AC_MSG_ERROR([Cannot find php_msgpack.h]) else AC_MSG_RESULT([$msgpack_inc_path]) fi fi AC_MSG_CHECKING([for memcached session support]) if test "$PHP_MEMCACHED_SESSION" != "no"; then AC_MSG_RESULT([enabled]) AC_DEFINE(HAVE_MEMCACHED_SESSION,1,[Whether memcache session handler is enabled]) SESSION_INCLUDES="-I$session_inc_path" ifdef([PHP_ADD_EXTENSION_DEP], [ PHP_ADD_EXTENSION_DEP(memcached, session) ]) else SESSION_INCLUDES="" AC_MSG_RESULT([disabled]) fi AC_MSG_CHECKING([for memcached igbinary support]) if test "$PHP_MEMCACHED_IGBINARY" != "no"; then AC_MSG_RESULT([enabled]) AC_DEFINE(HAVE_MEMCACHED_IGBINARY,1,[Whether memcache igbinary serializer is enabled]) IGBINARY_INCLUDES="-I$igbinary_inc_path" ifdef([PHP_ADD_EXTENSION_DEP], [ PHP_ADD_EXTENSION_DEP(memcached, igbinary) ]) else IGBINARY_INCLUDES="" AC_MSG_RESULT([disabled]) fi AC_MSG_CHECKING([for memcached msgpack support]) if test "$PHP_MEMCACHED_MSGPACK" != "no"; then AC_MSG_RESULT([enabled]) AC_DEFINE(HAVE_MEMCACHED_MSGPACK,1,[Whether memcache msgpack serializer is enabled]) MSGPACK_INCLUDES="-I$msgpack_inc_path" ifdef([PHP_ADD_EXTENSION_DEP], [ PHP_ADD_EXTENSION_DEP(memcached, msgpack) ]) else MSGPACK_INCLUDES="" AC_MSG_RESULT([disabled]) fi AC_MSG_CHECKING([for libmemcached location]) export ORIG_PKG_CONFIG_PATH="$PKG_CONFIG_PATH" if test "$PHP_LIBMEMCACHED_DIR" != "no" && test "$PHP_LIBMEMCACHED_DIR" != "yes"; then export PKG_CONFIG_PATH="$PHP_LIBMEMCACHED_DIR/$PHP_LIBDIR/pkgconfig" if test ! -f "$PHP_LIBMEMCACHED_DIR/include/libmemcached/memcached.h"; then AC_MSG_ERROR(Unable to find memcached.h under $PHP_LIBMEMCACHED_DIR) fi else export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/$PHP_LIBDIR/pkgconfig:/usr/$PHP_LIBDIR/pkgconfig:/opt/$PHP_LIBDIR/pkgconfig" fi if ! $PKG_CONFIG --exists libmemcached; then AC_MSG_ERROR([memcached support requires libmemcached. Use --with-libmemcached-dir= to specify the prefix where libmemcached headers and library are located]) else PHP_LIBMEMCACHED_VERSION=`$PKG_CONFIG libmemcached --modversion` PHP_LIBMEMCACHED_DIR=`$PKG_CONFIG libmemcached --variable=prefix` AC_MSG_RESULT([found version $PHP_LIBMEMCACHED_VERSION, under $PHP_LIBMEMCACHED_DIR]) PHP_LIBMEMCACHED_LIBS=`$PKG_CONFIG libmemcached --libs` PHP_LIBMEMCACHED_INCLUDES=`$PKG_CONFIG libmemcached --cflags` PHP_EVAL_LIBLINE($PHP_LIBMEMCACHED_LIBS, MEMCACHED_SHARED_LIBADD) PHP_EVAL_INCLINE($PHP_LIBMEMCACHED_INCLUDES) ORIG_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $INCLUDES" dnl # Always check if libmemcached was built with SASL support, dnl # because it will require sasl.h even if not used here. AC_CACHE_CHECK([for libmemcached sasl.h requirement], ac_cv_memc_sasl_support, [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ #if LIBMEMCACHED_WITH_SASL_SUPPORT /* yes */ #else # error "no sasl support" #endif ]])], [ac_cv_memc_sasl_support="yes"], [ac_cv_memc_sasl_support="no"] ) ]) if test "$ac_cv_memc_sasl_support" = "yes"; then AC_CHECK_HEADERS([sasl/sasl.h], [ac_cv_have_memc_sasl_h="yes"], [ac_cv_have_memc_sasl_h="no"]) fi dnl # If libmemcached requires sasl.h but we can't find sasl.h, that's a hard error dnl # regardless of the option --enable-memcached-sasl or --disable-memcached-sasl AC_MSG_CHECKING([whether to enable sasl support]) if test "$ac_cv_memc_sasl_support" = "yes" && test "$ac_cv_have_memc_sasl_h" = "no"; then AC_MSG_ERROR([no, libmemcached built with sasl required, but sasl.h not found.]) fi if test "$PHP_MEMCACHED_SASL" != "no"; then AC_MSG_RESULT(yes) if test "$ac_cv_memc_sasl_support" = "yes" && test "$ac_cv_have_memc_sasl_h" = "yes"; then PHP_CHECK_LIBRARY(sasl2, sasl_client_init, [PHP_ADD_LIBRARY(sasl2, 1, MEMCACHED_SHARED_LIBADD)]) AC_DEFINE(HAVE_MEMCACHED_SASL, 1, [Have SASL support]) else AC_MSG_ERROR([no, libmemcached built with sasl disabled. Run configure with --disable-memcached-sasl or update libmemcached with sasl support]) fi else AC_MSG_RESULT([no]) fi ORIG_CFLAGS="$CFLAGS" ORIG_LIBS="$LIBS" CFLAGS="$CFLAGS $PHP_LIBMEMCACHED_INCLUDES" LIBS="$LIBS $PHP_LIBMEMCACHED_LIBS" AC_CACHE_CHECK([whether memcached_exist is defined], ac_cv_have_memcached_exist, [ AC_LINK_IFELSE( [AC_LANG_PROGRAM([[#include ]], [[memcached_exist (NULL, NULL, 0);]])], [ac_cv_have_memcached_exist="yes"], [ac_cv_have_memcached_exist="no"]) ]) CFLAGS="$ORIG_CFLAGS" LIBS="$ORIG_LIBS" CFLAGS="$CFLAGS $PHP_LIBMEMCACHED_INCLUDES" LIBS="$LIBS $PHP_LIBMEMCACHED_LIBS" if test "$ac_cv_have_memcached_exist" = "yes"; then AC_DEFINE(HAVE_MEMCACHED_EXIST, [1], [Whether memcached_exist is defined]) fi AC_CACHE_CHECK([whether memcached_set_encoding_key is defined], ac_cv_have_memcached_set_encoding_key, [ AC_LINK_IFELSE( [AC_LANG_PROGRAM([[#include ]], [[memcached_set_encoding_key (NULL, NULL, 0);]])], [ac_cv_have_memcached_set_encoding_key="yes"], [ac_cv_have_memcached_set_encoding_key="no"]) ]) CFLAGS="$ORIG_CFLAGS" LIBS="$ORIG_LIBS" if test "$ac_cv_have_memcached_set_encoding_key" = "yes"; then AC_DEFINE(HAVE_MEMCACHED_SET_ENCODING_KEY, [1], [Whether memcached_set_encoding_key is defined]) fi PHP_MEMCACHED_FILES="php_memcached.c php_libmemcached_compat.c g_fmt.c" if test "$PHP_SYSTEM_FASTLZ" != "no"; then AC_CHECK_HEADERS([fastlz.h], [ac_cv_have_fastlz="yes"], [ac_cv_have_fastlz="no"]) PHP_CHECK_LIBRARY(fastlz, fastlz_compress, [PHP_ADD_LIBRARY(fastlz, 1, MEMCACHED_SHARED_LIBADD)], [AC_MSG_ERROR(FastLZ library not found)]) else ac_cv_have_fastlz="no" PHP_MEMCACHED_FILES="${PHP_MEMCACHED_FILES} fastlz/fastlz.c" fi if test "$PHP_ZSTD" != "no"; then AC_CHECK_HEADERS([zstd.h], [ac_cv_have_zstd="yes"], [ac_cv_have_zstd="no"]) PHP_CHECK_LIBRARY(zstd, ZSTD_compress, [PHP_ADD_LIBRARY(zstd, 1, MEMCACHED_SHARED_LIBADD)], [AC_MSG_ERROR(zstd library not found)]) fi if test "$PHP_MEMCACHED_SESSION" != "no"; then PHP_MEMCACHED_FILES="${PHP_MEMCACHED_FILES} php_memcached_session.c" fi LIBEVENT_INCLUDES="" AC_MSG_CHECKING([for memcached protocol support]) if test "$PHP_MEMCACHED_PROTOCOL" != "no"; then AC_MSG_RESULT([enabled]) AC_CACHE_CHECK([whether libmemcachedprotocol is usable], ac_cv_have_libmemcachedprotocol, [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[memcached_binary_protocol_callback_st s_test_impl; s_test_impl.interface.v1.delete_object = 0; ]])], [ac_cv_have_libmemcachedprotocol="yes"], [ac_cv_have_libmemcachedprotocol="no"] ) ]) if test "$ac_cv_have_libmemcachedprotocol" != "yes"; then AC_MSG_ERROR([Cannot enable libmemcached protocol]) fi PHP_ADD_LIBRARY_WITH_PATH(memcachedprotocol, $PHP_LIBMEMCACHED_DIR/$PHP_LIBDIR, MEMCACHED_SHARED_LIBADD) AC_MSG_CHECKING([for libevent]) if $PKG_CONFIG --exists libevent; then PHP_MEMCACHED_LIBEVENT_VERSION=`$PKG_CONFIG libevent --modversion` PHP_MEMCACHED_LIBEVENT_PREFIX=`$PKG_CONFIG libevent --variable=prefix` AC_MSG_RESULT([found version $PHP_MEMCACHED_LIBEVENT_VERSION, under $PHP_MEMCACHED_LIBEVENT_PREFIX]) LIBEVENT_LIBS=`$PKG_CONFIG libevent --libs` LIBEVENT_INCLUDES=`$PKG_CONFIG libevent --cflags` PHP_EVAL_LIBLINE($LIBEVENT_LIBS, MEMCACHED_SHARED_LIBADD) PHP_EVAL_INCLINE($LIBEVENT_INCLUDES) else AC_MSG_ERROR(Unable to find libevent installation) fi PHP_MEMCACHED_FILES="${PHP_MEMCACHED_FILES} php_memcached_server.c" AC_DEFINE(HAVE_MEMCACHED_PROTOCOL,1,[Whether memcached protocol is enabled]) else AC_MSG_RESULT([disabled]) fi CFLAGS="$ORIG_CFLAGS" export PKG_CONFIG_PATH="$ORIG_PKG_CONFIG_PATH" PHP_SUBST(MEMCACHED_SHARED_LIBADD) PHP_NEW_EXTENSION(memcached, $PHP_MEMCACHED_FILES, $ext_shared,,$SESSION_INCLUDES $IGBINARY_INCLUDES $LIBEVENT_INCLUDES $MSGPACK_INCLUDES) if test "ac_cv_have_fastlz" != "yes"; then PHP_ADD_BUILD_DIR($ext_builddir/fastlz, 1) fi ifdef([PHP_ADD_EXTENSION_DEP], [ PHP_ADD_EXTENSION_DEP(memcached, spl, true) ]) fi fi memcached-3.3.0/config.w320000644000076500000240000000355614704245235014054 0ustar mikestaff// vim:ft=javascript ARG_ENABLE('memcached', 'libmemcached extension', 'no'); ARG_ENABLE('memcached-session', 'whether to enable memcached session handler support', 'no'); ARG_ENABLE('memcached-igbinary', 'whether to enable memcached igbinary serializer support', 'no'); ARG_ENABLE('memcached-json', 'whether to enable memcached json serializer support', 'no'); ARG_ENABLE('memcached-msgpack', 'whether to enable memcached msgpack serializer support', 'no'); if (PHP_MEMCACHED == "yes") { if (!CHECK_LIB("memcached.lib;libmemcached.lib", "memcached", PHP_MEMCACHED)) { ERROR("memcached: library 'memcached' not found"); } if (!CHECK_HEADER_ADD_INCLUDE("libmemcached/memcached.h", "CFLAGS_MEMCACHED")) { ERROR("memcached: header 'libmemcached/memcached.h' not found"); } if (PHP_MEMCACHED_JSON != "no"){ AC_DEFINE("HAVE_JSON_API",1); } var memcached_extra_src = ""; if (PHP_MEMCACHED_SESSION != "no"){ AC_DEFINE("HAVE_MEMCACHED_SESSION",1); ADD_EXTENSION_DEP("memcached", "session", true) memcached_extra_src += " php_memcached_session.c"; } if (PHP_MEMCACHED_IGBINARY != "no"){ AC_DEFINE("HAVE_MEMCACHED_IGBINARY",1); ADD_EXTENSION_DEP("memcached", "igbinary", true); if (!CHECK_HEADER_ADD_INCLUDE("igbinary.h", "CFLAGS_MEMCACHED")) { ERROR("memcached: header 'igbinary.h' not found"); } } if (PHP_MEMCACHED_MSGPACK != "no"){ AC_DEFINE("HAVE_MEMCACHED_MSGPACK",1); ADD_EXTENSION_DEP("memcached", "msgpack", true); if (!CHECK_HEADER_ADD_INCLUDE("php_msgpack.h", "CFLAGS_MEMCACHED")) { ERROR("memcached: header 'php_msgpack.h' not found"); } } EXTENSION("memcached", "php_memcached.c php_libmemcached_compat.c g_fmt.c"+memcached_extra_src, null, " /DHAVE_SSIZE_T"); ADD_SOURCES(configure_module_dirname+"\\fastlz", "fastlz.c", "memcached"); AC_DEFINE("HAVE_MEMCACHED", 1, "memcached support"); AC_DEFINE("MEMCACHED_EXPORTS", 1) } memcached-3.3.0/php_memcached.c0000644000076500000240000040477214704245235015200 0ustar mikestaff/* +----------------------------------------------------------------------+ | Copyright (c) 2009-2010 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Andrei Zmievski | +----------------------------------------------------------------------+ */ /* TODO * - set LIBKETAMA_COMPATIBLE as the default? * - fix unserialize(serialize($memc)) */ #include "php_memcached.h" #include "php_memcached_private.h" #include "php_memcached_server.h" #include "g_fmt.h" #include #include #ifdef HAVE_MEMCACHED_SESSION # include "php_memcached_session.h" #endif #ifdef HAVE_FASTLZ_H #include #else #include "fastlz/fastlz.h" #endif #include #ifdef HAVE_ZSTD_H #include #endif #ifdef HAVE_JSON_API # include "ext/json/php_json.h" #endif #ifdef HAVE_MEMCACHED_IGBINARY #ifdef PHP_WIN32 //Windows extensions are generally built together, //so it wont be in the installed location #include "igbinary.h" #else # include "ext/igbinary/igbinary.h" #endif #endif #ifdef HAVE_MEMCACHED_MSGPACK # include "ext/msgpack/php_msgpack.h" #endif # include "ext/spl/spl_exceptions.h" static int le_memc; static int php_memc_list_entry(void) { return le_memc; } /**************************************** Protocol parameters ****************************************/ #define MEMC_OBJECT_KEY_MAX_LENGTH 250 /**************************************** Custom options ****************************************/ #define MEMC_OPT_COMPRESSION -1001 #define MEMC_OPT_PREFIX_KEY -1002 #define MEMC_OPT_SERIALIZER -1003 #define MEMC_OPT_COMPRESSION_TYPE -1004 #define MEMC_OPT_STORE_RETRY_COUNT -1005 #define MEMC_OPT_USER_FLAGS -1006 #define MEMC_OPT_COMPRESSION_LEVEL -1007 #define MEMC_OPT_ITEM_SIZE_LIMIT -1008 /**************************************** Custom result codes ****************************************/ #define MEMC_RES_PAYLOAD_FAILURE -1001 /**************************************** Payload value flags ****************************************/ #define MEMC_CREATE_MASK(start, n_bits) (((1U << n_bits) - 1) << start) #define MEMC_MASK_TYPE MEMC_CREATE_MASK(0, 4) #define MEMC_MASK_INTERNAL MEMC_CREATE_MASK(4, 12) #define MEMC_MASK_USER MEMC_CREATE_MASK(16, 16) #define MEMC_VAL_GET_TYPE(flags) ((flags) & MEMC_MASK_TYPE) #define MEMC_VAL_SET_TYPE(flags, type) ((flags) |= ((type) & MEMC_MASK_TYPE)) #define MEMC_VAL_IS_STRING 0 #define MEMC_VAL_IS_LONG 1 #define MEMC_VAL_IS_DOUBLE 2 #define MEMC_VAL_IS_BOOL 3 #define MEMC_VAL_IS_SERIALIZED 4 #define MEMC_VAL_IS_IGBINARY 5 #define MEMC_VAL_IS_JSON 6 #define MEMC_VAL_IS_MSGPACK 7 #define MEMC_VAL_COMPRESSED (1<<0) #define MEMC_VAL_COMPRESSION_ZLIB (1<<1) #define MEMC_VAL_COMPRESSION_FASTLZ (1<<2) #define MEMC_VAL_COMPRESSION_ZSTD (1<<3) #define MEMC_VAL_GET_FLAGS(internal_flags) (((internal_flags) & MEMC_MASK_INTERNAL) >> 4) #define MEMC_VAL_SET_FLAG(internal_flags, internal_flag) ((internal_flags) |= (((internal_flag) << 4) & MEMC_MASK_INTERNAL)) #define MEMC_VAL_HAS_FLAG(internal_flags, internal_flag) ((MEMC_VAL_GET_FLAGS(internal_flags) & (internal_flag)) == (internal_flag)) #define MEMC_VAL_DEL_FLAG(internal_flags, internal_flag) (internal_flags &= (~(((internal_flag) << 4) & MEMC_MASK_INTERNAL))) /**************************************** User-defined flags ****************************************/ #define MEMC_VAL_GET_USER_FLAGS(flags) ((flags & MEMC_MASK_USER) >> 16) #define MEMC_VAL_SET_USER_FLAGS(flags, udf_flags) ((flags) |= ((udf_flags << 16) & MEMC_MASK_USER)) #define MEMC_VAL_USER_FLAGS_MAX ((1 << 16) - 1) /**************************************** "get" operation flags ****************************************/ #define MEMC_GET_PRESERVE_ORDER 1 #define MEMC_GET_EXTENDED 2 /**************************************** Helper macros ****************************************/ #define RETURN_FROM_GET RETURN_FALSE /**************************************** Structures and definitions ****************************************/ typedef enum { MEMC_OP_SET, MEMC_OP_TOUCH, MEMC_OP_ADD, MEMC_OP_REPLACE, MEMC_OP_APPEND, MEMC_OP_PREPEND } php_memc_write_op; typedef struct { zend_bool is_persistent; zend_bool compression_enabled; zend_bool encoding_enabled; zend_long serializer; zend_long compression_type; zend_long compression_level; zend_long store_retry_count; zend_long set_udf_flags; zend_long item_size_limit; #ifdef HAVE_MEMCACHED_SASL zend_bool has_sasl_data; #endif } php_memc_user_data_t; typedef struct { memcached_st *memc; zend_bool is_pristine; int rescode; int memc_errno; zend_object zo; } php_memc_object_t; typedef struct { size_t num_valid_keys; const char **mkeys; size_t *mkeys_len; zend_string **strings; } php_memc_keys_t; typedef struct { zval *object; zend_fcall_info fci; zend_fcall_info_cache fcc; } php_memc_result_callback_ctx_t; static inline php_memc_object_t *php_memc_fetch_object(zend_object *obj) { return (php_memc_object_t *)((char *)obj - XtOffsetOf(php_memc_object_t, zo)); } #define Z_MEMC_OBJ_P(zv) php_memc_fetch_object(Z_OBJ_P(zv)); #define MEMC_METHOD_INIT_VARS \ zval* object = getThis(); \ php_memc_object_t* intern = NULL; \ php_memc_user_data_t* memc_user_data = NULL; #if PHP_VERSION_ID < 80000 #define MEMC_METHOD_FETCH_OBJECT \ intern = Z_MEMC_OBJ_P(object); \ if (!intern->memc) { \ php_error_docref(NULL, E_WARNING, "Memcached constructor was not called"); \ return; \ } \ memc_user_data = (php_memc_user_data_t *) memcached_get_user_data(intern->memc); \ (void)memc_user_data; /* avoid unused variable warning */ #else #define MEMC_METHOD_FETCH_OBJECT \ intern = Z_MEMC_OBJ_P(object); \ if (!intern->memc) { \ zend_throw_error(NULL, "Memcached constructor was not called"); \ RETURN_THROWS(); \ } \ memc_user_data = (php_memc_user_data_t *) memcached_get_user_data(intern->memc); \ (void)memc_user_data; /* avoid unused variable warning */ #endif static zend_bool s_memc_valid_key_binary(zend_string *key) { return memchr(ZSTR_VAL(key), '\n', ZSTR_LEN(key)) == NULL; } static uint32_t s_memc_object_key_max_length(php_memc_object_t *intern) { memcached_return retval; char *result; result = memcached_callback_get(intern->memc, MEMCACHED_CALLBACK_PREFIX_KEY, &retval); if (retval == MEMCACHED_SUCCESS && result) { return MEMC_OBJECT_KEY_MAX_LENGTH - strlen(result); } else { return MEMC_OBJECT_KEY_MAX_LENGTH; } } zend_bool s_memc_valid_key_ascii(zend_string *key, uint64_t verify_key) { const char *str = ZSTR_VAL(key); size_t i, len = ZSTR_LEN(key); if (verify_key) { for (i = 0; i < len; i++) { if (!isgraph(str[i]) || isspace(str[i])) return 0; } } else { /* if key verification is disabled, only check for spaces to avoid injection issues */ for (i = 0; i < len; i++) { if (isspace(str[i])) return 0; } } return 1; } #define MEMC_CHECK_KEY(intern, key) \ if (UNEXPECTED(ZSTR_LEN(key) == 0 || \ ZSTR_LEN(key) > s_memc_object_key_max_length(intern) || \ (memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) \ ? !s_memc_valid_key_binary(key) \ : !s_memc_valid_key_ascii(key, memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_VERIFY_KEY)) \ ))) { \ intern->rescode = MEMCACHED_BAD_KEY_PROVIDED; \ RETURN_FALSE; \ } #ifdef HAVE_MEMCACHED_PROTOCOL typedef struct { php_memc_proto_handler_t *handler; zend_object zo; } php_memc_server_t; static inline php_memc_server_t *php_memc_server_fetch_object(zend_object *obj) { return (php_memc_server_t *)((char *)obj - XtOffsetOf(php_memc_server_t, zo)); } #define Z_MEMC_SERVER_P(zv) php_memc_server_fetch_object(Z_OBJ_P(zv)) static zend_object_handlers memcached_server_object_handlers; static zend_class_entry *memcached_server_ce = NULL; #endif static zend_class_entry *memcached_ce = NULL; static zend_class_entry *memcached_exception_ce = NULL; static zend_object_handlers memcached_object_handlers; ZEND_DECLARE_MODULE_GLOBALS(php_memcached) #ifdef COMPILE_DL_MEMCACHED ZEND_GET_MODULE(memcached) #endif static PHP_INI_MH(OnUpdateCompressionType) { if (!new_value) { MEMC_G(compression_type) = COMPRESSION_TYPE_FASTLZ; } else if (!strcmp(ZSTR_VAL(new_value), "fastlz")) { MEMC_G(compression_type) = COMPRESSION_TYPE_FASTLZ; } else if (!strcmp(ZSTR_VAL(new_value), "zlib")) { MEMC_G(compression_type) = COMPRESSION_TYPE_ZLIB; #ifdef HAVE_ZSTD_H } else if (!strcmp(ZSTR_VAL(new_value), "zstd")) { MEMC_G(compression_type) = COMPRESSION_TYPE_ZSTD; #endif } else { return FAILURE; } return OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); } static PHP_INI_MH(OnUpdateSerializer) { if (!new_value) { MEMC_G(serializer_type) = SERIALIZER_DEFAULT; } else if (!strcmp(ZSTR_VAL(new_value), "php")) { MEMC_G(serializer_type) = SERIALIZER_PHP; #ifdef HAVE_MEMCACHED_IGBINARY } else if (!strcmp(ZSTR_VAL(new_value), "igbinary")) { MEMC_G(serializer_type) = SERIALIZER_IGBINARY; #endif // IGBINARY #ifdef HAVE_JSON_API } else if (!strcmp(ZSTR_VAL(new_value), "json")) { MEMC_G(serializer_type) = SERIALIZER_JSON; } else if (!strcmp(ZSTR_VAL(new_value), "json_array")) { MEMC_G(serializer_type) = SERIALIZER_JSON_ARRAY; #endif // JSON #ifdef HAVE_MEMCACHED_MSGPACK } else if (!strcmp(ZSTR_VAL(new_value), "msgpack")) { MEMC_G(serializer_type) = SERIALIZER_MSGPACK; #endif // msgpack } else { return FAILURE; } return OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); } #ifdef HAVE_MEMCACHED_SESSION static PHP_INI_MH(OnUpdateDeprecatedLockValue) { if (ZSTR_LEN(new_value) > 0 && strcmp(ZSTR_VAL(new_value), "not set")) { php_error_docref(NULL, E_DEPRECATED, "memcached.sess_lock_wait and memcached.sess_lock_max_wait are deprecated. Please update your configuration to use memcached.sess_lock_wait_min, memcached.sess_lock_wait_max and memcached.sess_lock_retries"); } return FAILURE; } static PHP_INI_MH(OnUpdateSessionPrefixString) { if (new_value && ZSTR_LEN(new_value) > 0) { if (ZSTR_LEN(new_value) > MEMCACHED_MAX_KEY) { php_error_docref(NULL, E_WARNING, "memcached.sess_prefix too long (max: %d)", MEMCACHED_MAX_KEY - 1); return FAILURE; } if (!s_memc_valid_key_ascii(new_value, 1)) { php_error_docref(NULL, E_WARNING, "memcached.sess_prefix cannot contain whitespace or control characters"); return FAILURE; } } return OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); } static PHP_INI_MH(OnUpdateConsistentHash) { if (!new_value) { MEMC_SESS_INI(consistent_hash_type) = MEMCACHED_BEHAVIOR_KETAMA; } else if (!strcmp(ZSTR_VAL(new_value), "ketama")) { MEMC_SESS_INI(consistent_hash_type) = MEMCACHED_BEHAVIOR_KETAMA; } else if (!strcmp(ZSTR_VAL(new_value), "ketama_weighted")) { MEMC_SESS_INI(consistent_hash_type) = MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED; } else { php_error_docref(NULL, E_WARNING, "memcached.sess_consistent_hash_type must be ketama or ketama_weighted"); return FAILURE; } return OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); } #endif // HAVE_MEMCACHED_SESSION #define MEMC_INI_ENTRY(key, default_value, update_fn, gkey) \ STD_PHP_INI_ENTRY("memcached."key, default_value, PHP_INI_ALL, update_fn, memc.gkey, zend_php_memcached_globals, php_memcached_globals) #define MEMC_INI_BOOL(key, default_value, update_fn, gkey) \ STD_PHP_INI_BOOLEAN("memcached."key, default_value, PHP_INI_ALL, update_fn, memc.gkey, zend_php_memcached_globals, php_memcached_globals) #define MEMC_INI_LINK(key, default_value, update_fn, gkey) \ STD_PHP_INI_ENTRY_EX("memcached."key, default_value, PHP_INI_ALL, update_fn, memc.gkey, zend_php_memcached_globals, php_memcached_globals, display_link_numbers) #define MEMC_SESSION_INI_ENTRY(key, default_value, update_fn, gkey) \ STD_PHP_INI_ENTRY("memcached.sess_"key, default_value, PHP_INI_ALL, update_fn, session.gkey, zend_php_memcached_globals, php_memcached_globals) #define MEMC_SESSION_INI_BOOL(key, default_value, update_fn, gkey) \ STD_PHP_INI_BOOLEAN("memcached.sess_"key, default_value, PHP_INI_ALL, update_fn, session.gkey, zend_php_memcached_globals, php_memcached_globals) #define MEMC_SESSION_INI_LINK(key, default_value, update_fn, gkey) \ STD_PHP_INI_ENTRY_EX("memcached.sess_"key, default_value, PHP_INI_ALL, update_fn, session.gkey, zend_php_memcached_globals, php_memcached_globals, display_link_numbers) /* {{{ INI entries */ PHP_INI_BEGIN() #ifdef HAVE_MEMCACHED_SESSION MEMC_SESSION_INI_BOOL ("locking", "1", OnUpdateBool, lock_enabled) MEMC_SESSION_INI_ENTRY("lock_wait_min", "150", OnUpdateLongGEZero, lock_wait_min) MEMC_SESSION_INI_ENTRY("lock_wait_max", "150", OnUpdateLongGEZero, lock_wait_max) MEMC_SESSION_INI_ENTRY("lock_retries", "5", OnUpdateLong, lock_retries) MEMC_SESSION_INI_ENTRY("lock_expire", "0", OnUpdateLongGEZero, lock_expiration) #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x01000018 MEMC_SESSION_INI_BOOL ("binary_protocol", "0", OnUpdateBool, binary_protocol_enabled) #else MEMC_SESSION_INI_BOOL ("binary_protocol", "1", OnUpdateBool, binary_protocol_enabled) #endif MEMC_SESSION_INI_BOOL ("consistent_hash", "1", OnUpdateBool, consistent_hash_enabled) MEMC_SESSION_INI_ENTRY("consistent_hash_type", "ketama", OnUpdateConsistentHash, consistent_hash_name) MEMC_SESSION_INI_ENTRY("number_of_replicas", "0", OnUpdateLongGEZero, number_of_replicas) MEMC_SESSION_INI_BOOL ("randomize_replica_read", "0", OnUpdateBool, randomize_replica_read_enabled) MEMC_SESSION_INI_BOOL ("remove_failed_servers", "0", OnUpdateBool, remove_failed_servers_enabled) MEMC_SESSION_INI_ENTRY("server_failure_limit", "0", OnUpdateLongGEZero, server_failure_limit) MEMC_SESSION_INI_LINK ("connect_timeout", "0", OnUpdateLong, connect_timeout) MEMC_SESSION_INI_ENTRY("sasl_username", "", OnUpdateString, sasl_username) MEMC_SESSION_INI_ENTRY("sasl_password", "", OnUpdateString, sasl_password) MEMC_SESSION_INI_BOOL ("persistent", "0", OnUpdateBool, persistent_enabled) MEMC_SESSION_INI_ENTRY("prefix", "memc.sess.key.", OnUpdateSessionPrefixString, prefix) /* Deprecated */ STD_PHP_INI_ENTRY("memcached.sess_lock_wait", "not set", PHP_INI_ALL, OnUpdateDeprecatedLockValue, no_effect, zend_php_memcached_globals, php_memcached_globals) STD_PHP_INI_ENTRY("memcached.sess_lock_max_wait", "not set", PHP_INI_ALL, OnUpdateDeprecatedLockValue, no_effect, zend_php_memcached_globals, php_memcached_globals) #endif MEMC_INI_ENTRY("compression_type", "fastlz", OnUpdateCompressionType, compression_name) MEMC_INI_ENTRY("compression_factor", "1.3", OnUpdateReal, compression_factor) MEMC_INI_ENTRY("compression_level", "3", OnUpdateLong, compression_level) MEMC_INI_ENTRY("compression_threshold", "2000", OnUpdateLong, compression_threshold) MEMC_INI_ENTRY("serializer", SERIALIZER_DEFAULT_NAME, OnUpdateSerializer, serializer_name) MEMC_INI_ENTRY("store_retry_count", "0", OnUpdateLong, store_retry_count) MEMC_INI_ENTRY("item_size_limit", "0", OnUpdateLongGEZero, item_size_limit) MEMC_INI_BOOL ("default_consistent_hash", "0", OnUpdateBool, default_behavior.consistent_hash_enabled) MEMC_INI_BOOL ("default_binary_protocol", "0", OnUpdateBool, default_behavior.binary_protocol_enabled) MEMC_INI_LINK ("default_connect_timeout", "0", OnUpdateLong, default_behavior.connect_timeout) PHP_INI_END() /* }}} */ #undef MEMC_INI_BOOL #undef MEMC_INI_LINK #undef MEMC_INI_ENTRY #undef MEMC_SESSION_INI_BOOL #undef MEMC_SESSION_INI_LINK #undef MEMC_SESSION_INI_ENTRY /**************************************** Forward declarations ****************************************/ static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key); static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key); static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool by_key); static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key); static void php_memc_delete_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key); static void php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key); static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key); /* Invoke PHP functions */ static zend_bool s_invoke_cache_callback(zval *zobject, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_bool with_cas, zend_string *key, zval *value); /* Iterate result sets */ typedef zend_bool (*php_memc_result_apply_fn)(php_memc_object_t *intern, zend_string *key, zval *value, zval *cas, uint32_t flags, void *context); static memcached_return php_memc_result_apply(php_memc_object_t *intern, php_memc_result_apply_fn result_apply_fn, zend_bool fetch_delay, void *context); static zend_bool php_memc_mget_apply(php_memc_object_t *intern, zend_string *server_key, php_memc_keys_t *keys, php_memc_result_apply_fn result_apply_fn, zend_bool with_cas, void *context); /* Callback functions for different server list iterations */ static memcached_return s_server_cursor_list_servers_cb(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context); static memcached_return s_server_cursor_version_cb(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context); static zend_bool s_memc_write_zval (php_memc_object_t *intern, php_memc_write_op op, zend_string *server_key, zend_string *key, zval *value, time_t expiration); static void php_memc_destroy(memcached_st *memc, php_memc_user_data_t *memc_user_data); static zend_bool s_memcached_result_to_zval(memcached_st *memc, memcached_result_st *result, zval *return_value); static zend_string *s_zval_to_payload(php_memc_object_t *intern, zval *value, uint32_t *flags); static void s_hash_to_keys(php_memc_keys_t *keys_out, HashTable *hash_in, zend_bool preserve_order, zval *return_value); static void s_clear_keys(php_memc_keys_t *keys); /**************************************** Exported helper functions ****************************************/ zend_bool php_memc_init_sasl_if_needed() { #ifdef HAVE_MEMCACHED_SASL if (MEMC_G(sasl_initialised)) { return 1; } if (sasl_client_init(NULL) != SASL_OK) { php_error_docref(NULL, E_ERROR, "Failed to initialize SASL library"); return 0; } return 1; #else php_error_docref(NULL, E_ERROR, "Memcached not built with sasl support"); return 0; #endif } char *php_memc_printable_func (zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) { char *buffer = NULL; if (fci->object) { spprintf (&buffer, 0, "%s::%s", ZSTR_VAL(fci->object->ce->name), ZSTR_VAL(fci_cache->function_handler->common.function_name)); } else { if (Z_TYPE (fci->function_name) == IS_OBJECT) { spprintf (&buffer, 0, "%s", ZSTR_VAL(Z_OBJCE(fci->function_name)->name)); } else { spprintf (&buffer, 0, "%s", Z_STRVAL(fci->function_name)); } } return buffer; } /**************************************** Handling error codes ****************************************/ static zend_bool s_memcached_return_is_error(memcached_return status, zend_bool strict) { zend_bool result = 0; switch (status) { case MEMCACHED_SUCCESS: case MEMCACHED_STORED: case MEMCACHED_DELETED: case MEMCACHED_STAT: case MEMCACHED_END: case MEMCACHED_BUFFERED: result = 0; break; case MEMCACHED_SOME_ERRORS: result = strict; break; default: result = 1; break; } return result; } static int s_memc_status_handle_result_code(php_memc_object_t *intern, memcached_return status) { intern->rescode = status; intern->memc_errno = 0; if (s_memcached_return_is_error(status, 1)) { intern->memc_errno = memcached_last_error_errno(intern->memc); return FAILURE; } return SUCCESS; } static void s_memc_set_status(php_memc_object_t *intern, memcached_return status, int memc_errno) { intern->rescode = status; intern->memc_errno = memc_errno; } static zend_bool s_memc_status_has_error(php_memc_object_t *intern) { return s_memcached_return_is_error(intern->rescode, 1); } static zend_bool s_memc_status_has_result_code(php_memc_object_t *intern, memcached_return status) { return intern->rescode == status; } /**************************************** Marshall cas tokens ****************************************/ static void s_uint64_to_zval (zval *target, uint64_t value) { if (value >= ((uint64_t) LONG_MAX)) { zend_string *buffer; #ifdef PRIu64 buffer = strpprintf (0, "%" PRIu64, value); #else /* Best effort */ buffer = strpprintf (0, "%llu", value); #endif ZVAL_STR(target, buffer); } else { ZVAL_LONG (target, (zend_long) value); } } static uint64_t s_zval_to_uint64 (zval *cas) { switch (Z_TYPE_P (cas)) { case IS_LONG: return (uint64_t) zval_get_long (cas); break; case IS_DOUBLE: if (Z_DVAL_P (cas) < 0.0) return 0; return (uint64_t) zval_get_double (cas); break; case IS_STRING: { uint64_t val; char *end; errno = 0; val = (uint64_t) strtoull (Z_STRVAL_P (cas), &end, 0); if (*end || (errno == ERANGE && val == UINT64_MAX) || (errno != 0 && val == 0)) { php_error_docref(NULL, E_ERROR, "Failed to unmarshall cas token"); return 0; } return val; } break; } return 0; } /**************************************** Iterate over memcached results and mget ****************************************/ static memcached_return php_memc_result_apply(php_memc_object_t *intern, php_memc_result_apply_fn result_apply_fn, zend_bool fetch_delay, void *context) { memcached_result_st result, *result_ptr; memcached_return rc, status = MEMCACHED_SUCCESS; memcached_result_create(intern->memc, &result); do { result_ptr = memcached_fetch_result(intern->memc, &result, &rc); if (s_memcached_return_is_error(rc, 0)) { status = rc; } /* nothing returned */ if (!result_ptr) { break; } else { zend_string *key; zval val, zcas; zend_bool retval; uint64_t cas; uint32_t flags; const char *res_key; size_t res_key_len; if (!s_memcached_result_to_zval(intern->memc, &result, &val)) { if (EG(exception)) { status = MEMC_RES_PAYLOAD_FAILURE; memcached_quit(intern->memc); break; } status = MEMCACHED_SOME_ERRORS; continue; } res_key = memcached_result_key_value(&result); res_key_len = memcached_result_key_length(&result); cas = memcached_result_cas(&result); flags = memcached_result_flags(&result); s_uint64_to_zval(&zcas, cas); key = zend_string_init (res_key, res_key_len, 0); retval = result_apply_fn(intern, key, &val, &zcas, flags, context); zend_string_release(key); zval_ptr_dtor(&val); zval_ptr_dtor(&zcas); /* Stop iterating on false */ if (!retval) { if (!fetch_delay) { /* Make sure we clear our results */ while (memcached_fetch_result(intern->memc, &result, &rc)) {} } break; } } } while (result_ptr != NULL); memcached_result_free(&result); return status; } static zend_bool php_memc_mget_apply(php_memc_object_t *intern, zend_string *server_key, php_memc_keys_t *keys, php_memc_result_apply_fn result_apply_fn, zend_bool with_cas, void *context) { memcached_return status; int mget_status; uint64_t orig_cas_flag = 0; // Reset status code s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); if (!keys->num_valid_keys) { intern->rescode = MEMCACHED_BAD_KEY_PROVIDED; return 0; } if (with_cas) { orig_cas_flag = memcached_behavior_get (intern->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS); if (!orig_cas_flag) { memcached_behavior_set (intern->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1); } } if (server_key) { status = memcached_mget_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), keys->mkeys, keys->mkeys_len, keys->num_valid_keys); } else { status = memcached_mget(intern->memc, keys->mkeys, keys->mkeys_len, keys->num_valid_keys); } /* Need to handle result code before restoring cas flags, would mess up errno */ mget_status = s_memc_status_handle_result_code(intern, status); if (with_cas && !orig_cas_flag) { memcached_behavior_set (intern->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, orig_cas_flag); } /* Return on failure codes */ if (mget_status == FAILURE) { return 0; } if (!result_apply_fn) { /* no callback, for example getDelayed */ return 1; } status = php_memc_result_apply(intern, result_apply_fn, 0, context); if (s_memc_status_handle_result_code(intern, status) == FAILURE) { return 0; } return 1; } /**************************************** Invoke callbacks ****************************************/ static zend_bool s_invoke_new_instance_cb(zval *object, zend_fcall_info *fci, zend_fcall_info_cache *fci_cache, zend_string *persistent_id) { zend_bool ret = 1; zval retval; zval params[2]; ZVAL_COPY(¶ms[0], object); if (persistent_id) { ZVAL_STR(¶ms[1], zend_string_copy(persistent_id)); } else { ZVAL_NULL(¶ms[1]); } fci->retval = &retval; fci->params = params; fci->param_count = 2; if (zend_call_function(fci, fci_cache) == FAILURE) { char *buf = php_memc_printable_func (fci, fci_cache); php_error_docref(NULL, E_WARNING, "Failed to invoke 'on_new' callback %s()", buf); efree (buf); ret = 0; } zval_ptr_dtor(¶ms[0]); zval_ptr_dtor(¶ms[1]); zval_ptr_dtor(&retval); return ret; } static zend_bool s_invoke_cache_callback(zval *zobject, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_bool with_cas, zend_string *key, zval *value) { zend_bool status = 0; zval params[4]; zval retval; php_memc_object_t *intern = Z_MEMC_OBJ_P(zobject); /* Prepare params */ ZVAL_COPY(¶ms[0], zobject); ZVAL_STR_COPY(¶ms[1], key); /* key */ ZVAL_NEW_REF(¶ms[2], value); /* value */ if (with_cas) { fci->param_count = 3; } else { ZVAL_NEW_EMPTY_REF(¶ms[3]); /* expiration */ ZVAL_NULL(Z_REFVAL(params[3])); fci->param_count = 4; } fci->retval = &retval; fci->params = params; if (zend_call_function(fci, fcc) == SUCCESS) { if (zend_is_true(&retval)) { time_t expiration; zval *val = Z_REFVAL(params[2]); if (with_cas) { if (Z_TYPE_P(val) == IS_ARRAY) { zval *rv = zend_hash_str_find(Z_ARRVAL_P(val), "value", sizeof("value") - 1); if (rv) { zval *cas = zend_hash_str_find(Z_ARRVAL_P(val), "cas", sizeof("cas") -1); expiration = cas? Z_LVAL_P(cas) : 0; status = s_memc_write_zval (intern, MEMC_OP_SET, NULL, key, rv, expiration); } /* memleak? zval_ptr_dtor(value); */ ZVAL_COPY(value, val); } } else { expiration = zval_get_long(Z_REFVAL(params[3])); status = s_memc_write_zval (intern, MEMC_OP_SET, NULL, key, val, expiration); /* memleak? zval_ptr_dtor(value); */ ZVAL_COPY(value, val); } } } else { s_memc_set_status(intern, MEMCACHED_NOTFOUND, 0); } zval_ptr_dtor(¶ms[0]); zval_ptr_dtor(¶ms[1]); zval_ptr_dtor(¶ms[2]); if (!with_cas) { zval_ptr_dtor(¶ms[3]); } zval_ptr_dtor(&retval); return status; } /**************************************** Wrapper for setting from zval ****************************************/ static zend_bool s_compress_value (php_memc_compression_type compression_type, zend_long compression_level, zend_string **payload_in, uint32_t *flags) { /* status */ zend_bool compress_status = 0; zend_string *payload = *payload_in; uint32_t compression_type_flag = 0; /* Additional 5% for the data */ size_t buffer_size = (size_t) (((double) ZSTR_LEN(payload) * 1.05) + 1.0); char *buffer = emalloc(buffer_size); /* Store compressed size here */ size_t compressed_size = 0; uint32_t original_size = ZSTR_LEN(payload); switch (compression_type) { case COMPRESSION_TYPE_FASTLZ: { compressed_size = fastlz_compress(ZSTR_VAL(payload), ZSTR_LEN(payload), buffer); if (compressed_size > 0) { compress_status = 1; compression_type_flag = MEMC_VAL_COMPRESSION_FASTLZ; } } break; #ifdef HAVE_ZSTD_H case COMPRESSION_TYPE_ZSTD: { compressed_size = ZSTD_compress((void *)buffer, buffer_size, ZSTR_VAL(payload), ZSTR_LEN(payload), compression_level); if (compression_level < -22) { compression_level = -22; } else if (compression_level > 22) { compression_level = 22; } if (!ZSTD_isError(compressed_size)) { compress_status = 1; compression_type_flag = MEMC_VAL_COMPRESSION_ZSTD; } } break; #endif case COMPRESSION_TYPE_ZLIB: { unsigned long cs = compressed_size = buffer_size; if (compression_level < 0) { compression_level = 0; } else if (compression_level > 9) { compression_level = 9; } int status = compress2((Bytef *) buffer, &cs, (Bytef *) ZSTR_VAL(payload), ZSTR_LEN(payload), compression_level); if (status == Z_OK) { compressed_size = cs; compress_status = 1; compression_type_flag = MEMC_VAL_COMPRESSION_ZLIB; } } break; default: compress_status = 0; break; } /* This means the value was too small to be compressed and ended up larger */ if (ZSTR_LEN(payload) <= (compressed_size * MEMC_G(compression_factor))) { compress_status = 0; } /* Replace the payload with the compressed copy */ if (compress_status) { MEMC_VAL_SET_FLAG(*flags, MEMC_VAL_COMPRESSED | compression_type_flag); payload = zend_string_realloc(payload, compressed_size + sizeof(uint32_t), 0); /* Copy the uin32_t at the beginning */ memcpy(ZSTR_VAL(payload), &original_size, sizeof(uint32_t)); memcpy(ZSTR_VAL(payload) + sizeof (uint32_t), buffer, compressed_size); efree(buffer); zend_string_forget_hash_val(payload); *payload_in = payload; return 1; } /* Original payload was not modified */ efree(buffer); return 0; } static zend_bool s_serialize_value (php_memc_serializer_type serializer, zval *value, smart_str *buf, uint32_t *flags) { switch (serializer) { /* Igbinary serialization */ #ifdef HAVE_MEMCACHED_IGBINARY case SERIALIZER_IGBINARY: { uint8_t *buffer; size_t buffer_len; if (igbinary_serialize(&buffer, &buffer_len, value) != 0) { php_error_docref(NULL, E_WARNING, "could not serialize value with igbinary"); return 0; } smart_str_appendl (buf, (char *)buffer, buffer_len); efree(buffer); MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_IGBINARY); } break; #endif /* JSON serialization */ #ifdef HAVE_JSON_API case SERIALIZER_JSON: case SERIALIZER_JSON_ARRAY: { php_json_encode(buf, value, 0); MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_JSON); } break; #endif /* msgpack serialization */ #ifdef HAVE_MEMCACHED_MSGPACK case SERIALIZER_MSGPACK: php_msgpack_serialize(buf, value); if (!buf->s) { php_error_docref(NULL, E_WARNING, "could not serialize value with msgpack"); return 0; } MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_MSGPACK); break; #endif /* PHP serialization */ default: { php_serialize_data_t var_hash; PHP_VAR_SERIALIZE_INIT(var_hash); php_var_serialize(buf, value, &var_hash); PHP_VAR_SERIALIZE_DESTROY(var_hash); if (!buf->s) { php_error_docref(NULL, E_WARNING, "could not serialize value"); return 0; } MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_SERIALIZED); } break; } /* Check for exceptions caused by serializers */ if (EG(exception) && buf->s->len) { return 0; } return 1; } static zend_string *s_zval_to_payload(php_memc_object_t *intern, zval *value, uint32_t *flags) { zend_string *payload; php_memc_user_data_t *memc_user_data = memcached_get_user_data(intern->memc); zend_bool should_compress = memc_user_data->compression_enabled; switch (Z_TYPE_P(value)) { case IS_STRING: payload = zval_get_string(value); MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_STRING); break; case IS_LONG: { smart_str buffer = {0}; smart_str_append_long (&buffer, Z_LVAL_P(value)); smart_str_0(&buffer); payload = buffer.s; MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_LONG); should_compress = 0; } break; case IS_DOUBLE: { char buffer[40]; php_memcached_g_fmt(buffer, Z_DVAL_P(value)); payload = zend_string_init (buffer, strlen (buffer), 0); MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_DOUBLE); should_compress = 0; } break; case IS_TRUE: payload = zend_string_init ("1", 1, 0); MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_BOOL); should_compress = 0; break; case IS_FALSE: payload = zend_string_alloc (0, 0); MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_BOOL); should_compress = 0; break; default: { smart_str buffer = {0}; if (!s_serialize_value (memc_user_data->serializer, value, &buffer, flags)) { smart_str_free(&buffer); return NULL; } payload = buffer.s; } break; } /* turn off compression for values below the threshold */ if (ZSTR_LEN(payload) == 0 || ZSTR_LEN(payload) < MEMC_G(compression_threshold)) { should_compress = 0; } /* If we have compression flag, compress the value */ if (should_compress) { /* s_compress_value() will always leave a valid payload, even if that payload * did not actually get compressed. The flags will be set according to the * to the compression type or no compression. * * No need to check the return value because the payload is always valid. */ (void)s_compress_value (memc_user_data->compression_type, memc_user_data->compression_level, &payload, flags); } if (memc_user_data->set_udf_flags >= 0) { MEMC_VAL_SET_USER_FLAGS(*flags, ((uint32_t) memc_user_data->set_udf_flags)); } return payload; } static zend_bool s_is_payload_too_big(php_memc_object_t *intern, zend_string *payload) { php_memc_user_data_t *memc_user_data = memcached_get_user_data(intern->memc); /* An item size limit of 0 implies no limit enforced */ if (memc_user_data->item_size_limit == 0) { return 0; } if (ZSTR_LEN(payload) > memc_user_data->item_size_limit) { return 1; } return 0; } static zend_bool s_should_retry_write (php_memc_object_t *intern, memcached_return status) { if (memcached_server_count (intern->memc) == 0) { return 0; } return s_memcached_return_is_error (status, 1); } static zend_bool s_memc_write_zval (php_memc_object_t *intern, php_memc_write_op op, zend_string *server_key, zend_string *key, zval *value, time_t expiration) { uint32_t flags = 0; zend_string *payload = NULL; memcached_return status = 0; php_memc_user_data_t *memc_user_data = memcached_get_user_data(intern->memc); zend_long retries = memc_user_data->store_retry_count; if (value) { payload = s_zval_to_payload(intern, value, &flags); if (!payload) { s_memc_set_status(intern, MEMC_RES_PAYLOAD_FAILURE, 0); return 0; } if (s_is_payload_too_big(intern, payload)) { s_memc_set_status(intern, MEMCACHED_E2BIG, 0); zend_string_release(payload); return 0; } } #define memc_write_using_fn(fn_name) payload ? fn_name(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), ZSTR_VAL(payload), ZSTR_LEN(payload), expiration, flags) : MEMC_RES_PAYLOAD_FAILURE; #define memc_write_using_fn_by_key(fn_name) payload ? fn_name(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), ZSTR_VAL(payload), ZSTR_LEN(payload), expiration, flags) : MEMC_RES_PAYLOAD_FAILURE; if (server_key) { switch (op) { case MEMC_OP_SET: status = memc_write_using_fn_by_key(memcached_set_by_key); break; case MEMC_OP_TOUCH: status = php_memcached_touch_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), expiration); break; case MEMC_OP_ADD: status = memc_write_using_fn_by_key(memcached_add_by_key); break; case MEMC_OP_REPLACE: status = memc_write_using_fn_by_key(memcached_replace_by_key); break; case MEMC_OP_APPEND: status = memc_write_using_fn_by_key(memcached_append_by_key); break; case MEMC_OP_PREPEND: status = memc_write_using_fn_by_key(memcached_prepend_by_key); break; } if (status == MEMCACHED_END) { status = MEMCACHED_SUCCESS; } } else { retry: switch (op) { case MEMC_OP_SET: status = memc_write_using_fn(memcached_set); break; case MEMC_OP_TOUCH: status = php_memcached_touch(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), expiration); break; case MEMC_OP_ADD: status = memc_write_using_fn(memcached_add); break; case MEMC_OP_REPLACE: status = memc_write_using_fn(memcached_replace); break; case MEMC_OP_APPEND: status = memc_write_using_fn(memcached_append); break; case MEMC_OP_PREPEND: status = memc_write_using_fn(memcached_prepend); break; } if (status == MEMCACHED_END) { status = MEMCACHED_SUCCESS; } } if (s_should_retry_write (intern, status) && retries-- > 0) { goto retry; } #undef memc_write_using_fn #undef memc_write_using_fn_by_key if (payload) { zend_string_release(payload); } if (s_memc_status_handle_result_code(intern, status) == FAILURE) { return 0; } return 1; } /**************************************** Methods ****************************************/ /* {{{ Memcached::__construct([string persistent_id[, callback on_new[, string connection_str]]])) Creates a Memcached object, optionally using persistent memcache connection */ static PHP_METHOD(Memcached, __construct) { php_memc_object_t *intern; php_memc_user_data_t *memc_user_data; zend_string *persistent_id = NULL; zend_string *conn_str = NULL; zend_string *plist_key = NULL; zend_fcall_info fci = {0}; zend_fcall_info_cache fci_cache; zend_bool is_persistent = 0; /* "|S!f!S" */ ZEND_PARSE_PARAMETERS_START(0, 3) Z_PARAM_OPTIONAL Z_PARAM_STR_EX(persistent_id, 1, 0) Z_PARAM_FUNC_EX(fci, fci_cache, 1, 0) Z_PARAM_STR(conn_str) ZEND_PARSE_PARAMETERS_END(); intern = Z_MEMC_OBJ_P(getThis()); intern->is_pristine = 1; if (persistent_id && persistent_id->len) { zend_resource *le; plist_key = zend_string_alloc(sizeof("memcached:id=") + persistent_id->len - 1, 0); snprintf(ZSTR_VAL(plist_key), plist_key->len + 1, "memcached:id=%s", ZSTR_VAL(persistent_id)); if ((le = zend_hash_find_ptr(&EG(persistent_list), plist_key)) != NULL) { if (le->type == php_memc_list_entry()) { intern->memc = le->ptr; intern->is_pristine = 0; zend_string_release (plist_key); return; } } is_persistent = 1; } if (conn_str && conn_str->len > 0) { intern->memc = memcached (ZSTR_VAL(conn_str), ZSTR_LEN(conn_str)); } else { intern->memc = memcached (NULL, 0); } if (!intern->memc) { php_error_docref(NULL, E_ERROR, "Failed to allocate memory for memcached structure"); /* never reached */ } memc_user_data = pecalloc (1, sizeof(*memc_user_data), is_persistent); memc_user_data->serializer = MEMC_G(serializer_type); memc_user_data->compression_type = MEMC_G(compression_type); memc_user_data->compression_level = MEMC_G(compression_level); memc_user_data->compression_enabled = 1; memc_user_data->encoding_enabled = 0; memc_user_data->store_retry_count = MEMC_G(store_retry_count); memc_user_data->set_udf_flags = -1; memc_user_data->item_size_limit = MEMC_G(item_size_limit); memc_user_data->is_persistent = is_persistent; memcached_set_user_data(intern->memc, memc_user_data); /* Set default behaviors */ if (MEMC_G(default_behavior.consistent_hash_enabled)) { memcached_return rc = memcached_behavior_set(intern->memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, MEMCACHED_DISTRIBUTION_CONSISTENT); if (rc != MEMCACHED_SUCCESS) { php_error_docref(NULL, E_WARNING, "Failed to turn on consistent hash: %s", memcached_strerror(intern->memc, rc)); } } if (MEMC_G(default_behavior.binary_protocol_enabled)) { memcached_return rc = memcached_behavior_set(intern->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1); if (rc != MEMCACHED_SUCCESS) { php_error_docref(NULL, E_WARNING, "Failed to turn on binary protocol: %s", memcached_strerror(intern->memc, rc)); } /* Also enable TCP_NODELAY when binary protocol is enabled */ rc = memcached_behavior_set(intern->memc, MEMCACHED_BEHAVIOR_TCP_NODELAY, 1); if (rc != MEMCACHED_SUCCESS) { php_error_docref(NULL, E_WARNING, "Failed to set TCP_NODELAY: %s", memcached_strerror(intern->memc, rc)); } } if (MEMC_G(default_behavior.connect_timeout)) { memcached_return rc = memcached_behavior_set(intern->memc, MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT, MEMC_G(default_behavior.connect_timeout)); if (rc != MEMCACHED_SUCCESS) { php_error_docref(NULL, E_WARNING, "Failed to set connect timeout: %s", memcached_strerror(intern->memc, rc)); } } if (fci.size) { if (!s_invoke_new_instance_cb(getThis(), &fci, &fci_cache, persistent_id) || EG(exception)) { /* error calling or exception thrown from callback */ if (plist_key) { zend_string_release(plist_key); } /* Setting intern->memc null prevents object destruction from freeing the memcached_st We free it manually here because it might be persistent and has not been registered to persistent_list yet */ php_memc_destroy(intern->memc, memc_user_data); intern->memc = NULL; return; } } if (plist_key) { zend_resource le; le.type = php_memc_list_entry(); le.ptr = intern->memc; GC_SET_REFCOUNT(&le, 1); /* plist_key is not a persistent allocated key, thus we use str_update here */ if (zend_hash_str_update_mem(&EG(persistent_list), ZSTR_VAL(plist_key), ZSTR_LEN(plist_key), &le, sizeof(le)) == NULL) { zend_string_release(plist_key); php_error_docref(NULL, E_ERROR, "could not register persistent entry"); /* not reached */ } zend_string_release(plist_key); } } /* }}} */ static void s_hash_to_keys(php_memc_keys_t *keys_out, HashTable *hash_in, zend_bool preserve_order, zval *return_value) { size_t idx = 0, alloc_count; zval *zv; keys_out->num_valid_keys = 0; alloc_count = zend_hash_num_elements(hash_in); if (!alloc_count) { return; } keys_out->mkeys = ecalloc (alloc_count, sizeof (char *)); keys_out->mkeys_len = ecalloc (alloc_count, sizeof (size_t)); keys_out->strings = ecalloc (alloc_count, sizeof (zend_string *)); ZEND_HASH_FOREACH_VAL(hash_in, zv) { zend_string *key = zval_get_string(zv); if (preserve_order && return_value) { add_assoc_null_ex(return_value, ZSTR_VAL(key), ZSTR_LEN(key)); } if (ZSTR_LEN(key) > 0 && ZSTR_LEN(key) < MEMCACHED_MAX_KEY) { keys_out->mkeys[idx] = ZSTR_VAL(key); keys_out->mkeys_len[idx] = ZSTR_LEN(key); keys_out->strings[idx] = key; idx++; } else { zend_string_release (key); } } ZEND_HASH_FOREACH_END(); if (!idx) { efree (keys_out->mkeys); efree (keys_out->mkeys_len); efree (keys_out->strings); } keys_out->num_valid_keys = idx; } static void s_key_to_keys(php_memc_keys_t *keys_out, zend_string *key) { zval zv_keys; array_init(&zv_keys); add_next_index_str(&zv_keys, zend_string_copy(key)); s_hash_to_keys(keys_out, Z_ARRVAL(zv_keys), 0, NULL); zval_ptr_dtor(&zv_keys); } static void s_clear_keys(php_memc_keys_t *keys) { size_t i; if (!keys->num_valid_keys) { return; } for (i = 0; i < keys->num_valid_keys; i++) { zend_string_release (keys->strings[i]); } efree(keys->strings); efree(keys->mkeys); efree(keys->mkeys_len); } typedef struct { zend_bool extended; zval *return_value; } php_memc_get_ctx_t; static zend_bool s_get_apply_fn(php_memc_object_t *intern, zend_string *key, zval *value, zval *cas, uint32_t flags, void *in_context) { php_memc_get_ctx_t *context = (php_memc_get_ctx_t *) in_context; if (context->extended) { Z_TRY_ADDREF_P(value); Z_TRY_ADDREF_P(cas); array_init (context->return_value); add_assoc_zval (context->return_value, "value", value); add_assoc_zval (context->return_value, "cas", cas); add_assoc_long (context->return_value, "flags", (zend_long) MEMC_VAL_GET_USER_FLAGS(flags)); } else { ZVAL_COPY(context->return_value, value); } return 0; /* Stop after one */ } static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { php_memc_get_ctx_t context = {0}; php_memc_keys_t keys = {0}; zend_long get_flags = 0; zend_string *key; zend_string *server_key = NULL; zend_bool mget_status; memcached_return status = MEMCACHED_SUCCESS; zend_fcall_info fci = empty_fcall_info; zend_fcall_info_cache fcc = empty_fcall_info_cache; MEMC_METHOD_INIT_VARS; if (by_key) { /* "SS|f!l" */ ZEND_PARSE_PARAMETERS_START(2, 4) Z_PARAM_STR(server_key) Z_PARAM_STR(key) Z_PARAM_OPTIONAL Z_PARAM_FUNC_EX(fci, fcc, 1, 0) Z_PARAM_LONG(get_flags) ZEND_PARSE_PARAMETERS_END(); } else { /* "S|f!l" */ ZEND_PARSE_PARAMETERS_START(1, 3) Z_PARAM_STR(key) Z_PARAM_OPTIONAL Z_PARAM_FUNC_EX(fci, fcc, 1, 0) Z_PARAM_LONG(get_flags) ZEND_PARSE_PARAMETERS_END(); } MEMC_METHOD_FETCH_OBJECT; s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); MEMC_CHECK_KEY(intern, key); context.extended = (get_flags & MEMC_GET_EXTENDED); context.return_value = return_value; s_key_to_keys(&keys, key); mget_status = php_memc_mget_apply(intern, server_key, &keys, s_get_apply_fn, context.extended, &context); s_clear_keys(&keys); if (!mget_status) { if (s_memc_status_has_result_code(intern, MEMCACHED_NOTFOUND) && fci.size > 0) { status = s_invoke_cache_callback(object, &fci, &fcc, context.extended, key, return_value); if (!status) { zval_ptr_dtor(return_value); RETURN_FROM_GET; } } } if (s_memc_status_has_error(intern)) { zval_ptr_dtor(return_value); RETURN_FROM_GET; } } /* {{{ Memcached::get(string key [, mixed callback [, int get_flags = 0]) Returns a value for the given key or false */ PHP_METHOD(Memcached, get) { php_memc_get_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); } /* }}} */ /* {{{ Memcached::getByKey(string server_key, string key [, mixed callback [, int get_flags = 0]) Returns a value for key from the server identified by the server key or false */ PHP_METHOD(Memcached, getByKey) { php_memc_get_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); } /* }}} */ static zend_bool s_get_multi_apply_fn(php_memc_object_t *intern, zend_string *key, zval *value, zval *cas, uint32_t flags, void *in_context) { php_memc_get_ctx_t *context = (php_memc_get_ctx_t *) in_context; Z_TRY_ADDREF_P(value); if (context->extended) { zval node; Z_TRY_ADDREF_P(cas); array_init(&node); add_assoc_zval(&node, "value", value); add_assoc_zval(&node, "cas", cas); add_assoc_long(&node, "flags", (zend_long) MEMC_VAL_GET_USER_FLAGS(flags)); zend_symtable_update(Z_ARRVAL_P(context->return_value), key, &node); } else { zend_symtable_update(Z_ARRVAL_P(context->return_value), key, value); } return 1; } /* {{{ -- php_memc_getMulti_impl */ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { php_memc_get_ctx_t context; php_memc_keys_t keys_out; zval *keys = NULL; zend_string *server_key = NULL; zend_long flags = 0; MEMC_METHOD_INIT_VARS; zend_bool retval, preserve_order; if (by_key) { /* "Sa|l" */ ZEND_PARSE_PARAMETERS_START(2, 3) Z_PARAM_STR(server_key) Z_PARAM_ARRAY(keys) Z_PARAM_OPTIONAL Z_PARAM_LONG(flags) ZEND_PARSE_PARAMETERS_END(); } else { /* "a|l" */ ZEND_PARSE_PARAMETERS_START(1, 2) Z_PARAM_ARRAY(keys) Z_PARAM_OPTIONAL Z_PARAM_LONG(flags) ZEND_PARSE_PARAMETERS_END(); } MEMC_METHOD_FETCH_OBJECT; array_init(return_value); if (zend_hash_num_elements(Z_ARRVAL_P(keys)) == 0) { /* BC compatible */ s_memc_set_status(intern, MEMCACHED_NOTFOUND, 0); return; } s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); preserve_order = (flags & MEMC_GET_PRESERVE_ORDER); s_hash_to_keys(&keys_out, Z_ARRVAL_P(keys), preserve_order, return_value); context.extended = (flags & MEMC_GET_EXTENDED); context.return_value = return_value; retval = php_memc_mget_apply(intern, server_key, &keys_out, s_get_multi_apply_fn, context.extended, &context); s_clear_keys(&keys_out); if (!retval && (s_memc_status_has_result_code(intern, MEMCACHED_NOTFOUND) || s_memc_status_has_result_code(intern, MEMCACHED_SOME_ERRORS))) { return; } if (!retval || EG(exception)) { zval_dtor(return_value); RETURN_FROM_GET; } } /* }}} */ /* {{{ Memcached::getMulti(array keys[, long flags = 0 ]) Returns values for the given keys or false */ PHP_METHOD(Memcached, getMulti) { php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); } /* }}} */ /* {{{ Memcached::getMultiByKey(string server_key, array keys[, long flags = 0 ]) Returns values for the given keys from the server identified by the server key or false */ PHP_METHOD(Memcached, getMultiByKey) { php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); } /* }}} */ /* {{{ Memcached::getDelayed(array keys [, bool with_cas [, mixed callback ] ]) Sends a request for the given keys and returns immediately */ PHP_METHOD(Memcached, getDelayed) { php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); } /* }}} */ /* {{{ Memcached::getDelayedByKey(string server_key, array keys [, bool with_cas [, mixed callback ] ]) Sends a request for the given keys from the server identified by the server key and returns immediately */ PHP_METHOD(Memcached, getDelayedByKey) { php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); } /* }}} */ static void s_create_result_array(zend_string *key, zval *value, zval *cas, uint32_t flags, zval *return_value) { Z_TRY_ADDREF_P(value); Z_TRY_ADDREF_P(cas); add_assoc_str_ex(return_value, ZEND_STRL("key"), zend_string_copy(key)); add_assoc_zval_ex(return_value, ZEND_STRL("value"), value); if (Z_LVAL_P(cas)) { /* BC compatible */ add_assoc_zval_ex(return_value, ZEND_STRL("cas"), cas); add_assoc_long_ex(return_value, ZEND_STRL("flags"), MEMC_VAL_GET_USER_FLAGS(flags)); } } static zend_bool s_result_callback_apply(php_memc_object_t *intern, zend_string *key, zval *value, zval *cas, uint32_t flags, void *in_context) { zend_bool status = 1; zval params[2]; zval retval; php_memc_result_callback_ctx_t *context = (php_memc_result_callback_ctx_t *) in_context; ZVAL_COPY(¶ms[0], context->object); array_init(¶ms[1]); s_create_result_array(key, value, cas, flags, ¶ms[1]); context->fci.retval = &retval; context->fci.params = params; context->fci.param_count = 2; if (zend_call_function(&context->fci, &context->fcc) == FAILURE) { php_error_docref(NULL, E_WARNING, "could not invoke result callback"); status = 0; } zval_ptr_dtor(&retval); zval_ptr_dtor(¶ms[0]); zval_ptr_dtor(¶ms[1]); return status; } /* {{{ -- php_memc_getDelayed_impl */ static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { php_memc_keys_t keys_out = {0}; zval *keys = NULL; zend_string *server_key = NULL; zend_bool with_cas = 0; zend_fcall_info fci = empty_fcall_info; zend_fcall_info_cache fcc = empty_fcall_info_cache; memcached_return status = MEMCACHED_SUCCESS; MEMC_METHOD_INIT_VARS; if (by_key) { /* "Sa/|bf!" */ ZEND_PARSE_PARAMETERS_START(2, 4) Z_PARAM_STR(server_key) Z_PARAM_ARRAY_EX(keys, 0, 1) Z_PARAM_OPTIONAL Z_PARAM_BOOL(with_cas) Z_PARAM_FUNC_EX(fci, fcc, 1, 0) ZEND_PARSE_PARAMETERS_END(); } else { /* "a/|bf!" */ ZEND_PARSE_PARAMETERS_START(1, 3) Z_PARAM_ARRAY_EX(keys, 0, 1) Z_PARAM_OPTIONAL Z_PARAM_BOOL(with_cas) Z_PARAM_FUNC_EX(fci, fcc, 1, 0) ZEND_PARSE_PARAMETERS_END(); } MEMC_METHOD_FETCH_OBJECT; s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); s_hash_to_keys(&keys_out, Z_ARRVAL_P(keys), 0, NULL); if (fci.size > 0) { php_memc_result_callback_ctx_t context = { getThis(), fci, fcc }; status = php_memc_mget_apply(intern, server_key, &keys_out, &s_result_callback_apply, with_cas, (void *) &context); } else { status = php_memc_mget_apply(intern, server_key, &keys_out, NULL, with_cas, NULL); } s_clear_keys(&keys_out); RETURN_BOOL(status); } /* }}} */ static zend_bool s_fetch_apply(php_memc_object_t *intern, zend_string *key, zval *value, zval *cas, uint32_t flags, void *in_context) { zval *return_value = (zval *) in_context; s_create_result_array(key, value, cas, flags, return_value); return 0; // stop iterating after one } /* {{{ Memcached::fetch() Returns the next result from a previous delayed request */ PHP_METHOD(Memcached, fetch) { memcached_return status = MEMCACHED_SUCCESS; MEMC_METHOD_INIT_VARS; if (zend_parse_parameters_none() == FAILURE) { return; } MEMC_METHOD_FETCH_OBJECT; s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); array_init(return_value); status = php_memc_result_apply(intern, s_fetch_apply, 1, return_value); if (s_memc_status_handle_result_code(intern, status) == FAILURE) { zval_ptr_dtor(return_value); RETURN_FROM_GET; } } /* }}} */ static zend_bool s_fetch_all_apply(php_memc_object_t *intern, zend_string *key, zval *value, zval *cas, uint32_t flags, void *in_context) { zval zv; zval *return_value = (zval *) in_context; array_init (&zv); s_create_result_array(key, value, cas, flags, &zv); add_next_index_zval(return_value, &zv); return 1; } /* {{{ Memcached::fetchAll() Returns all the results from a previous delayed request */ PHP_METHOD(Memcached, fetchAll) { memcached_return status = MEMCACHED_SUCCESS; MEMC_METHOD_INIT_VARS; if (zend_parse_parameters_none() == FAILURE) { return; } MEMC_METHOD_FETCH_OBJECT; s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); array_init(return_value); status = php_memc_result_apply(intern, s_fetch_all_apply, 0, return_value); if (s_memc_status_handle_result_code(intern, status) == FAILURE) { zval_dtor(return_value); RETURN_FALSE; } } /* }}} */ /* {{{ Memcached::set(string key, mixed value [, int expiration ]) Sets the value for the given key */ PHP_METHOD(Memcached, set) { php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_SET, 0); } /* }}} */ /* {{{ Memcached::setByKey(string server_key, string key, mixed value [, int expiration ]) Sets the value for the given key on the server identified by the server key */ PHP_METHOD(Memcached, setByKey) { php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_SET, 1); } /* }}} */ /* {{{ Memcached::touch(string key, [, int expiration ]) Sets a new expiration for the given key */ PHP_METHOD(Memcached, touch) { php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_TOUCH, 0); } /* }}} */ /* {{{ Memcached::touchbyKey(string key, [, int expiration ]) Sets a new expiration for the given key */ PHP_METHOD(Memcached, touchByKey) { php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_TOUCH, 1); } /* }}} */ /* {{{ Memcached::setMulti(array items [, int expiration ]) Sets the keys/values specified in the items array */ PHP_METHOD(Memcached, setMulti) { php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); } /* }}} */ /* {{{ Memcached::setMultiByKey(string server_key, array items [, int expiration ]) Sets the keys/values specified in the items array on the server identified by the given server key */ PHP_METHOD(Memcached, setMultiByKey) { php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); } /* }}} */ /* {{{ -- php_memc_setMulti_impl */ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { zval *entries; zend_string *server_key = NULL; zend_long expiration = 0; zval *value; zend_string *skey; zend_ulong num_key; int tmp_len = 0; MEMC_METHOD_INIT_VARS; if (by_key) { /* "Sa|ll" */ ZEND_PARSE_PARAMETERS_START(2, 3) Z_PARAM_STR(server_key) Z_PARAM_ARRAY(entries) Z_PARAM_OPTIONAL Z_PARAM_LONG(expiration) ZEND_PARSE_PARAMETERS_END(); } else { /* "a|ll" */ ZEND_PARSE_PARAMETERS_START(1, 2) Z_PARAM_ARRAY(entries) Z_PARAM_OPTIONAL Z_PARAM_LONG(expiration) ZEND_PARSE_PARAMETERS_END(); } MEMC_METHOD_FETCH_OBJECT; s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); ZEND_HASH_FOREACH_KEY_VAL (Z_ARRVAL_P(entries), num_key, skey, value) { zend_string *str_key = NULL; if (skey) { str_key = skey; } else { char tmp_key[64]; tmp_len = snprintf(tmp_key, sizeof(tmp_key) - 1, "%ld", (long)num_key); str_key = zend_string_init(tmp_key, tmp_len, 0); } /* If this failed to write a value, intern stores the error for the return value */ s_memc_write_zval (intern, MEMC_OP_SET, server_key, str_key, value, expiration); if (!skey) { zend_string_release (str_key); } } ZEND_HASH_FOREACH_END(); RETURN_BOOL(!s_memc_status_has_error(intern)); } /* }}} */ /* {{{ Memcached::add(string key, mixed value [, int expiration ]) Sets the value for the given key, failing if the key already exists */ PHP_METHOD(Memcached, add) { php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_ADD, 0); } /* }}} */ /* {{{ Memcached::addByKey(string server_key, string key, mixed value [, int expiration ]) Sets the value for the given key on the server identified by the sever key, failing if the key already exists */ PHP_METHOD(Memcached, addByKey) { php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_ADD, 1); } /* }}} */ /* {{{ Memcached::append(string key, mixed value) Appends the value to existing one for the key */ PHP_METHOD(Memcached, append) { php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_APPEND, 0); } /* }}} */ /* {{{ Memcached::appendByKey(string server_key, string key, mixed value) Appends the value to existing one for the key on the server identified by the server key */ PHP_METHOD(Memcached, appendByKey) { php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_APPEND, 1); } /* }}} */ /* {{{ Memcached::prepend(string key, mixed value) Prepends the value to existing one for the key */ PHP_METHOD(Memcached, prepend) { php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_PREPEND, 0); } /* }}} */ /* {{{ Memcached::prependByKey(string server_key, string key, mixed value) Prepends the value to existing one for the key on the server identified by the server key */ PHP_METHOD(Memcached, prependByKey) { php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_PREPEND, 1); } /* }}} */ /* {{{ Memcached::replace(string key, mixed value [, int expiration ]) Replaces the value for the given key, failing if the key doesn't exist */ PHP_METHOD(Memcached, replace) { php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_REPLACE, 0); } /* }}} */ /* {{{ Memcached::replaceByKey(string server_key, string key, mixed value [, int expiration ]) Replaces the value for the given key on the server identified by the server key, failing if the key doesn't exist */ PHP_METHOD(Memcached, replaceByKey) { php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_REPLACE, 1); } /* }}} */ /* {{{ -- php_memc_store_impl */ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool by_key) { zend_string *key; zend_string *server_key = NULL; zend_string *s_value; zval s_zvalue; zval *value = NULL; zend_long expiration = 0; MEMC_METHOD_INIT_VARS; if (by_key) { if (op == MEMC_OP_APPEND || op == MEMC_OP_PREPEND) { /* "SSS" */ ZEND_PARSE_PARAMETERS_START(3, 3) Z_PARAM_STR(server_key) Z_PARAM_STR(key) Z_PARAM_STR(s_value) ZEND_PARSE_PARAMETERS_END(); value = &s_zvalue; ZVAL_STR(value, s_value); } else if (op == MEMC_OP_TOUCH) { /* "SS|l" */ ZEND_PARSE_PARAMETERS_START(2, 3) Z_PARAM_STR(server_key) Z_PARAM_STR(key) Z_PARAM_OPTIONAL Z_PARAM_LONG(expiration) ZEND_PARSE_PARAMETERS_END(); } else { /* "SSz|l" */ ZEND_PARSE_PARAMETERS_START(3, 4) Z_PARAM_STR(server_key) Z_PARAM_STR(key) Z_PARAM_ZVAL(value) Z_PARAM_OPTIONAL Z_PARAM_LONG(expiration) ZEND_PARSE_PARAMETERS_END(); } } else { if (op == MEMC_OP_APPEND || op == MEMC_OP_PREPEND) { /* "SS" */ ZEND_PARSE_PARAMETERS_START(2, 2) Z_PARAM_STR(key) Z_PARAM_STR(s_value) ZEND_PARSE_PARAMETERS_END(); value = &s_zvalue; ZVAL_STR(value, s_value); } else if (op == MEMC_OP_TOUCH) { /* "S|l */ ZEND_PARSE_PARAMETERS_START(1, 2) Z_PARAM_STR(key) Z_PARAM_OPTIONAL Z_PARAM_LONG(expiration) ZEND_PARSE_PARAMETERS_END(); } else { /* "Sz|l" */ ZEND_PARSE_PARAMETERS_START(2, 3) Z_PARAM_STR(key) Z_PARAM_ZVAL(value) Z_PARAM_OPTIONAL Z_PARAM_LONG(expiration) ZEND_PARSE_PARAMETERS_END(); } } MEMC_METHOD_FETCH_OBJECT; s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); MEMC_CHECK_KEY(intern, key); if (memc_user_data->compression_enabled) { /* * When compression is enabled, we cannot do appends/prepends because that would * corrupt the compressed values. It is up to the user to fetch the value, * append/prepend new data, and store it again. */ if (op == MEMC_OP_APPEND || op == MEMC_OP_PREPEND) { php_error_docref(NULL, E_WARNING, "cannot append/prepend with compression turned on"); RETURN_NULL(); } } if (!s_memc_write_zval (intern, op, server_key, key, value, expiration)) { RETURN_FALSE; } RETURN_TRUE; } /* }}} */ /* {{{ -- php_memc_cas_impl */ static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { zval *zv_cas; uint64_t cas; zend_string *key; zend_string *server_key = NULL; zval *value; zend_long expiration = 0; zend_string *payload; uint32_t flags = 0; memcached_return status; MEMC_METHOD_INIT_VARS; if (by_key) { /* "zSSz|l" */ ZEND_PARSE_PARAMETERS_START(4, 5) Z_PARAM_ZVAL(zv_cas) Z_PARAM_STR(server_key) Z_PARAM_STR(key) Z_PARAM_ZVAL(value) Z_PARAM_OPTIONAL Z_PARAM_LONG(expiration) ZEND_PARSE_PARAMETERS_END(); } else { /* "zSz|l" */ ZEND_PARSE_PARAMETERS_START(3, 4) Z_PARAM_ZVAL(zv_cas) Z_PARAM_STR(key) Z_PARAM_ZVAL(value) Z_PARAM_OPTIONAL Z_PARAM_LONG(expiration) ZEND_PARSE_PARAMETERS_END(); } MEMC_METHOD_FETCH_OBJECT; s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); MEMC_CHECK_KEY(intern, key); cas = s_zval_to_uint64(zv_cas); payload = s_zval_to_payload(intern, value, &flags); if (payload == NULL) { intern->rescode = MEMC_RES_PAYLOAD_FAILURE; RETURN_FALSE; } if (s_is_payload_too_big(intern, payload)) { intern->rescode = MEMCACHED_E2BIG; zend_string_release(payload); RETURN_FALSE; } if (by_key) { status = memcached_cas_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), ZSTR_VAL(payload), ZSTR_LEN(payload), expiration, flags, cas); } else { status = memcached_cas(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), ZSTR_VAL(payload), ZSTR_LEN(payload), expiration, flags, cas); } zend_string_release(payload); if (s_memc_status_handle_result_code(intern, status) == FAILURE) { RETURN_FALSE; } RETURN_TRUE; } /* }}} */ /* {{{ Memcached::cas(double cas_token, string key, mixed value [, int expiration ]) Sets the value for the given key, failing if the cas_token doesn't match the one in memcache */ PHP_METHOD(Memcached, cas) { php_memc_cas_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); } /* }}} */ /* {{{ Memcached::casByKey(double cas_token, string server_key, string key, mixed value [, int expiration ]) Sets the value for the given key on the server identified by the server_key, failing if the cas_token doesn't match the one in memcache */ PHP_METHOD(Memcached, casByKey) { php_memc_cas_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); } /* }}} */ /* {{{ Memcached::delete(string key [, int time ]) Deletes the given key */ PHP_METHOD(Memcached, delete) { php_memc_delete_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); } /* }}} */ /* {{{ Memcached::deleteMulti(array keys [, int time ]) Deletes the given keys */ PHP_METHOD(Memcached, deleteMulti) { php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); } /* }}} */ /* {{{ Memcached::deleteByKey(string server_key, string key [, int time ]) Deletes the given key from the server identified by the server key */ PHP_METHOD(Memcached, deleteByKey) { php_memc_delete_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); } /* }}} */ /* {{{ Memcached::deleteMultiByKey(array keys [, int time ]) Deletes the given key from the server identified by the server key */ PHP_METHOD(Memcached, deleteMultiByKey) { php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); } /* }}} */ /* {{{ -- php_memc_delete_impl */ static void php_memc_delete_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { zend_string *key, *server_key; zend_long expiration = 0; memcached_return status; MEMC_METHOD_INIT_VARS; if (by_key) { /* "SS|l" */ ZEND_PARSE_PARAMETERS_START(2, 3) Z_PARAM_STR(server_key) Z_PARAM_STR(key) Z_PARAM_OPTIONAL Z_PARAM_LONG(expiration) ZEND_PARSE_PARAMETERS_END(); } else { /* "S|l" */ ZEND_PARSE_PARAMETERS_START(1, 2) Z_PARAM_STR(key) Z_PARAM_OPTIONAL Z_PARAM_LONG(expiration) ZEND_PARSE_PARAMETERS_END(); server_key = key; } MEMC_METHOD_FETCH_OBJECT; s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); MEMC_CHECK_KEY(intern, key); if (by_key) { status = memcached_delete_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), expiration); } else { status = memcached_delete(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), expiration); } if (s_memc_status_handle_result_code(intern, status) == FAILURE) { RETURN_FALSE; } RETURN_TRUE; } /* }}} */ /* {{{ -- php_memc_deleteMulti_impl */ static void php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { zval *entries, *zv, ret; zend_string *server_key = NULL; zend_long expiration = 0; zend_string *entry; memcached_return status; MEMC_METHOD_INIT_VARS; if (by_key) { /* "Sa/|l" */ ZEND_PARSE_PARAMETERS_START(2, 3) Z_PARAM_STR(server_key) Z_PARAM_ARRAY_EX(entries, 0, 1) Z_PARAM_OPTIONAL Z_PARAM_LONG(expiration) ZEND_PARSE_PARAMETERS_END(); } else { /* "a/|l" */ ZEND_PARSE_PARAMETERS_START(1, 2) Z_PARAM_ARRAY_EX(entries, 0, 1) Z_PARAM_OPTIONAL Z_PARAM_LONG(expiration) ZEND_PARSE_PARAMETERS_END(); } MEMC_METHOD_FETCH_OBJECT; s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); array_init(return_value); ZEND_HASH_FOREACH_VAL (Z_ARRVAL_P(entries), zv) { entry = zval_get_string(zv); if (ZSTR_LEN(entry) == 0) { zend_string_release(entry); continue; } if (by_key) { status = memcached_delete_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(entry), ZSTR_LEN(entry), expiration); } else { status = memcached_delete_by_key(intern->memc, ZSTR_VAL(entry), ZSTR_LEN(entry), ZSTR_VAL(entry), ZSTR_LEN(entry), expiration); } if (s_memc_status_handle_result_code(intern, status) == FAILURE) { ZVAL_LONG(&ret, status); } else { ZVAL_TRUE(&ret); } zend_symtable_update(Z_ARRVAL_P(return_value), entry, &ret); zend_string_release(entry); } ZEND_HASH_FOREACH_END(); return; } /* }}} */ /* {{{ -- php_memc_incdec_impl */ static void php_memc_incdec_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key, zend_bool incr) { zend_string *key, *server_key = NULL; zend_long offset = 1; zend_long expiry = 0; zend_long initial = 0; uint64_t value = UINT64_MAX; memcached_return status; int n_args = ZEND_NUM_ARGS(); MEMC_METHOD_INIT_VARS; if (!by_key) { /* "S|lll" */ ZEND_PARSE_PARAMETERS_START(1, 4) Z_PARAM_STR(key) Z_PARAM_OPTIONAL Z_PARAM_LONG(offset) Z_PARAM_LONG(initial) Z_PARAM_LONG(expiry) ZEND_PARSE_PARAMETERS_END(); } else { /* "SS|lll" */ ZEND_PARSE_PARAMETERS_START(2, 5) Z_PARAM_STR(server_key) Z_PARAM_STR(key) Z_PARAM_OPTIONAL Z_PARAM_LONG(offset) Z_PARAM_LONG(initial) Z_PARAM_LONG(expiry) ZEND_PARSE_PARAMETERS_END(); } MEMC_METHOD_FETCH_OBJECT; s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); MEMC_CHECK_KEY(intern, key); if (offset < 0) { php_error_docref(NULL, E_WARNING, "offset cannot be a negative value"); RETURN_FALSE; } if ((!by_key && n_args < 3) || (by_key && n_args < 4)) { if (by_key) { if (incr) { status = memcached_increment_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), offset, &value); } else { status = memcached_decrement_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), offset, &value); } } else { /* The libmemcached API has a quirk that memcached_increment() takes only a 32-bit * offset, but memcached_increment_by_key() and all other increment and decrement * functions take a 64-bit offset. The memcached protocol allows increment/decrement * greater than UINT_MAX, so we just work around memcached_increment() here. */ if (incr) { status = memcached_increment_by_key(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), ZSTR_VAL(key), ZSTR_LEN(key), offset, &value); } else { status = memcached_decrement_by_key(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), ZSTR_VAL(key), ZSTR_LEN(key), offset, &value); } } } else { zend_long retries = memc_user_data->store_retry_count; retry_inc_dec: if (!memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) { php_error_docref(NULL, E_WARNING, "Initial value is only supported with binary protocol"); RETURN_FALSE; } if (by_key) { if (incr) { status = memcached_increment_with_initial_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), offset, initial, (time_t)expiry, &value); } else { status = memcached_decrement_with_initial_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), offset, initial, (time_t)expiry, &value); } } else { if (incr) { status = memcached_increment_with_initial(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), offset, initial, (time_t)expiry, &value); } else { status = memcached_decrement_with_initial(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), offset, initial, (time_t)expiry, &value); } } if (s_should_retry_write(intern, status) && retries-- > 0) { goto retry_inc_dec; } } if (s_memc_status_handle_result_code(intern, status) == FAILURE) { RETURN_FALSE; } if (value == UINT64_MAX) { RETURN_FALSE; } RETURN_LONG((long)value); } /* }}} */ /* {{{ Memcached::increment(string key [, int delta [, initial_value [, expiry time ] ] ]) Increments the value for the given key by delta, defaulting to 1 */ PHP_METHOD(Memcached, increment) { php_memc_incdec_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 1); } /* }}} */ /* {{{ Memcached::decrement(string key [, int delta [, initial_value [, expiry time ] ] ]) Decrements the value for the given key by delta, defaulting to 1 */ PHP_METHOD(Memcached, decrement) { php_memc_incdec_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0); } /* }}} */ /* {{{ Memcached::decrementByKey(string server_key, string key [, int delta [, initial_value [, expiry time ] ] ]) Decrements by server the value for the given key by delta, defaulting to 1 */ PHP_METHOD(Memcached, decrementByKey) { php_memc_incdec_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 0); } /* }}} */ /* {{{ Memcached::increment(string server_key, string key [, int delta [, initial_value [, expiry time ] ] ]) Increments by server the value for the given key by delta, defaulting to 1 */ PHP_METHOD(Memcached, incrementByKey) { php_memc_incdec_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 1); } /* }}} */ /* {{{ Memcached::addServer(string hostname, int port [, int weight ]) Adds the given memcache server to the list */ PHP_METHOD(Memcached, addServer) { zend_string *host; zend_long port, weight = 0; memcached_return status; MEMC_METHOD_INIT_VARS; /* "Sa/|l" */ ZEND_PARSE_PARAMETERS_START(2, 3) Z_PARAM_STR(host) Z_PARAM_LONG(port) Z_PARAM_OPTIONAL Z_PARAM_LONG(weight) ZEND_PARSE_PARAMETERS_END(); MEMC_METHOD_FETCH_OBJECT; s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); status = memcached_server_add_with_weight(intern->memc, ZSTR_VAL(host), port, weight); if (s_memc_status_handle_result_code(intern, status) == FAILURE) { RETURN_FALSE; } RETURN_TRUE; } /* }}} */ /* {{{ Memcached::addServers(array servers) Adds the given memcache servers to the server list */ PHP_METHOD(Memcached, addServers) { zval *servers; zval *entry; zval *z_host, *z_port, *z_weight = NULL; HashPosition pos; int entry_size, i = 0; memcached_server_st *list = NULL; memcached_return status; MEMC_METHOD_INIT_VARS; /* "a/" */ ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY_EX(servers, 0, 1) ZEND_PARSE_PARAMETERS_END(); MEMC_METHOD_FETCH_OBJECT; s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); ZEND_HASH_FOREACH_VAL (Z_ARRVAL_P(servers), entry) { if (Z_TYPE_P(entry) != IS_ARRAY) { php_error_docref(NULL, E_WARNING, "server list entry #%d is not an array", i+1); i++; continue; } entry_size = zend_hash_num_elements(Z_ARRVAL_P(entry)); if (entry_size > 1) { zend_string *host; zend_long port; uint32_t weight; zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(entry), &pos); /* Check that we have a host */ if ((z_host = zend_hash_get_current_data_ex(Z_ARRVAL_P(entry), &pos)) == NULL) { php_error_docref(NULL, E_WARNING, "could not get server host for entry #%d", i+1); i++; continue; } /* Check that we have a port */ if (zend_hash_move_forward_ex(Z_ARRVAL_P(entry), &pos) == FAILURE || (z_port = zend_hash_get_current_data_ex(Z_ARRVAL_P(entry), &pos)) == NULL) { php_error_docref(NULL, E_WARNING, "could not get server port for entry #%d", i+1); i++; continue; } host = zval_get_string(z_host); port = zval_get_long(z_port); weight = 0; if (entry_size > 2) { /* Try to get weight */ if (zend_hash_move_forward_ex(Z_ARRVAL_P(entry), &pos) == FAILURE || (z_weight = zend_hash_get_current_data_ex(Z_ARRVAL_P(entry), &pos)) == NULL) { php_error_docref(NULL, E_WARNING, "could not get server weight for entry #%d", i+1); } weight = zval_get_long(z_weight); } list = memcached_server_list_append_with_weight(list, ZSTR_VAL(host), port, weight, &status); zend_string_release(host); if (s_memc_status_handle_result_code(intern, status) == SUCCESS) { i++; continue; } } i++; /* catch-all for all errors */ php_error_docref(NULL, E_WARNING, "could not add entry #%d to the server list", i + 1); } ZEND_HASH_FOREACH_END(); status = memcached_server_push(intern->memc, list); memcached_server_list_free(list); if (s_memc_status_handle_result_code(intern, status) == FAILURE) { RETURN_FALSE; } RETURN_TRUE; } /* }}} */ /* {{{ Memcached::getServerList() Returns the list of the memcache servers in use */ PHP_METHOD(Memcached, getServerList) { memcached_server_function callbacks[1]; MEMC_METHOD_INIT_VARS; if (zend_parse_parameters_none() == FAILURE) { return; } MEMC_METHOD_FETCH_OBJECT; callbacks[0] = s_server_cursor_list_servers_cb; array_init(return_value); memcached_server_cursor(intern->memc, callbacks, return_value, 1); } /* }}} */ /* {{{ Memcached::getServerByKey(string server_key) Returns the server identified by the given server key */ PHP_METHOD(Memcached, getServerByKey) { zend_string *server_key; php_memcached_instance_st server_instance; memcached_return error; MEMC_METHOD_INIT_VARS; /* "S" */ ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STR(server_key) ZEND_PARSE_PARAMETERS_END(); MEMC_METHOD_FETCH_OBJECT; s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); server_instance = memcached_server_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), &error); if (server_instance == NULL) { s_memc_status_handle_result_code(intern, error); RETURN_FALSE; } array_init(return_value); add_assoc_string(return_value, "host", (char*) memcached_server_name(server_instance)); add_assoc_long(return_value, "port", memcached_server_port(server_instance)); add_assoc_long(return_value, "weight", 0); } /* }}} */ /* {{{ Memcached::resetServerList() Reset the server list in use */ PHP_METHOD(Memcached, resetServerList) { MEMC_METHOD_INIT_VARS; if (zend_parse_parameters_none() == FAILURE) { return; } MEMC_METHOD_FETCH_OBJECT; memcached_servers_reset(intern->memc); RETURN_TRUE; } /* }}} */ /* {{{ Memcached::quit() Close any open connections */ PHP_METHOD(Memcached, quit) { MEMC_METHOD_INIT_VARS; if (zend_parse_parameters_none() == FAILURE) { return; } MEMC_METHOD_FETCH_OBJECT; memcached_quit(intern->memc); RETURN_TRUE; } /* }}} */ /* {{{ Memcached::flushBuffers() Flush and senf buffered commands */ PHP_METHOD(Memcached, flushBuffers) { MEMC_METHOD_INIT_VARS; if (zend_parse_parameters_none() == FAILURE) { return; } MEMC_METHOD_FETCH_OBJECT; RETURN_BOOL(memcached_flush_buffers(intern->memc) == MEMCACHED_SUCCESS); } /* }}} */ /* {{{ Memcached::getLastErrorMessage() Returns the last error message that occurred */ PHP_METHOD(Memcached, getLastErrorMessage) { MEMC_METHOD_INIT_VARS; if (zend_parse_parameters_none() == FAILURE) { return; } MEMC_METHOD_FETCH_OBJECT; RETURN_STRING(memcached_last_error_message(intern->memc)); } /* }}} */ /* {{{ Memcached::getLastErrorCode() Returns the last error code that occurred */ PHP_METHOD(Memcached, getLastErrorCode) { MEMC_METHOD_INIT_VARS; if (zend_parse_parameters_none() == FAILURE) { return; } MEMC_METHOD_FETCH_OBJECT; RETURN_LONG(memcached_last_error(intern->memc)); } /* }}} */ /* {{{ Memcached::getLastErrorErrno() Returns the last error errno that occurred */ PHP_METHOD(Memcached, getLastErrorErrno) { MEMC_METHOD_INIT_VARS; if (zend_parse_parameters_none() == FAILURE) { return; } MEMC_METHOD_FETCH_OBJECT; RETURN_LONG(memcached_last_error_errno(intern->memc)); } /* }}} */ /* {{{ Memcached::getLastDisconnectedServer() Returns the last disconnected server Was added in 0.34 according to libmemcached's Changelog */ PHP_METHOD(Memcached, getLastDisconnectedServer) { php_memcached_instance_st server_instance; MEMC_METHOD_INIT_VARS; if (zend_parse_parameters_none() == FAILURE) { return; } MEMC_METHOD_FETCH_OBJECT; server_instance = memcached_server_get_last_disconnect(intern->memc); if (server_instance == NULL) { RETURN_FALSE; } array_init(return_value); add_assoc_string(return_value, "host", (char*) memcached_server_name(server_instance)); add_assoc_long(return_value, "port", memcached_server_port(server_instance)); } /* }}} */ static zend_bool s_long_value(const char *str, zend_long *value) { char *end = (char *) str; errno = 0; *value = strtol(str, &end, 10); if (errno || str == end || *end != '\0') { return 0; } return 1; } static zend_bool s_double_value(const char *str, double *value) { char *end = (char *) str; errno = 0; *value = strtod(str, &end); if (errno || str == end || *end != '\0') { return 0; } return 1; } static memcached_return s_stat_execute_cb (php_memcached_instance_st instance, const char *key, size_t key_length, const char *value, size_t value_length, void *context) { zend_string *server_key; zend_long long_val; double d_val; char *buffer; zval *return_value = (zval *) context; zval *server_values; server_key = strpprintf(0, "%s:%d", memcached_server_name(instance), memcached_server_port(instance)); server_values = zend_hash_find(Z_ARRVAL_P(return_value), server_key); if (!server_values) { zval zv; array_init(&zv); server_values = zend_hash_add(Z_ARRVAL_P(return_value), server_key, &zv); } spprintf (&buffer, 0, "%.*s", (int)value_length, value); /* Check type */ if (s_long_value (buffer, &long_val)) { add_assoc_long(server_values, key, long_val); } else if (s_double_value (buffer, &d_val)) { add_assoc_double(server_values, key, d_val); } else { add_assoc_stringl_ex(server_values, key, key_length, (char*)value, value_length); } efree (buffer); zend_string_release(server_key); return MEMCACHED_SUCCESS; } /* {{{ Memcached::getStats() Returns statistics for the memcache servers */ PHP_METHOD(Memcached, getStats) { memcached_return status; char *args = NULL; zend_string *args_string = NULL; uint64_t orig_no_block, orig_protocol; MEMC_METHOD_INIT_VARS; /* "|S!" */ ZEND_PARSE_PARAMETERS_START(0, 1) Z_PARAM_OPTIONAL Z_PARAM_STR_EX(args_string, 1, 0) ZEND_PARSE_PARAMETERS_END(); MEMC_METHOD_FETCH_OBJECT; if (args_string) args = ZSTR_VAL(args_string); /* stats hangs in nonblocking mode, turn off during the call. Only change the * value if needed, because libmemcached reconnects for this behavior_set. */ orig_no_block = memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_NO_BLOCK); orig_protocol = memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL); if (orig_no_block && orig_protocol) memcached_behavior_set(intern->memc, MEMCACHED_BEHAVIOR_NO_BLOCK, 0); array_init(return_value); status = memcached_stat_execute(intern->memc, args, s_stat_execute_cb, return_value); if (orig_no_block && orig_protocol) memcached_behavior_set(intern->memc, MEMCACHED_BEHAVIOR_NO_BLOCK, orig_no_block); if (s_memc_status_handle_result_code(intern, status) == FAILURE) { zval_ptr_dtor(return_value); RETURN_FALSE; } } /* }}} */ /* {{{ Memcached::getVersion() Returns the version of each memcached server in the pool */ PHP_METHOD(Memcached, getVersion) { memcached_return status; memcached_server_function callbacks[1]; MEMC_METHOD_INIT_VARS; if (zend_parse_parameters_none() == FAILURE) { return; } MEMC_METHOD_FETCH_OBJECT; status = memcached_version(intern->memc); if (s_memc_status_handle_result_code(intern, status) == FAILURE) { RETURN_FALSE; } callbacks[0] = s_server_cursor_version_cb; array_init(return_value); status = memcached_server_cursor(intern->memc, callbacks, return_value, 1); if (s_memc_status_handle_result_code(intern, status) == FAILURE) { zval_dtor(return_value); RETURN_FALSE; } } /* }}} */ /* {{{ Memcached::getAllKeys() Returns the keys stored on all the servers */ static memcached_return s_dump_keys_cb(const memcached_st *ptr, const char *key, size_t key_length, void *in_context) { zval *return_value = (zval*) in_context; add_next_index_stringl(return_value, key, key_length); return MEMCACHED_SUCCESS; } PHP_METHOD(Memcached, getAllKeys) { memcached_return rc; memcached_dump_func callback[1]; MEMC_METHOD_INIT_VARS; if (zend_parse_parameters_none() == FAILURE) { return; } callback[0] = s_dump_keys_cb; MEMC_METHOD_FETCH_OBJECT; array_init(return_value); rc = memcached_dump(intern->memc, callback, return_value, 1); /* Ignore two errors. libmemcached has a hardcoded loop of 200 slab * classes that matches memcached < 1.4.24, at which version the server * has only 63 slabs and throws an error when requesting the 64th slab. * * In multi-server some non-deterministic number of elements will be dropped. */ if (rc != MEMCACHED_CLIENT_ERROR && rc != MEMCACHED_SERVER_ERROR && s_memc_status_handle_result_code(intern, rc) == FAILURE) { zval_dtor(return_value); RETURN_FALSE; } } /* }}} */ /* {{{ Memcached::flush([ int delay ]) Flushes the data on all the servers */ static PHP_METHOD(Memcached, flush) { zend_long delay = 0; memcached_return status; MEMC_METHOD_INIT_VARS; /* "|l" */ ZEND_PARSE_PARAMETERS_START(0, 1) Z_PARAM_OPTIONAL Z_PARAM_LONG(delay) ZEND_PARSE_PARAMETERS_END(); MEMC_METHOD_FETCH_OBJECT; s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); status = memcached_flush(intern->memc, delay); if (s_memc_status_handle_result_code(intern, status) == FAILURE) { RETURN_FALSE; } RETURN_TRUE; } /* }}} */ /* {{{ Memcached::getOption(int option) Returns the value for the given option constant */ static PHP_METHOD(Memcached, getOption) { zend_long option; uint64_t result; memcached_behavior flag; MEMC_METHOD_INIT_VARS; /* "l" */ ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_LONG(option) ZEND_PARSE_PARAMETERS_END(); MEMC_METHOD_FETCH_OBJECT; switch (option) { case MEMC_OPT_COMPRESSION_TYPE: RETURN_LONG(memc_user_data->compression_type); case MEMC_OPT_COMPRESSION_LEVEL: RETURN_LONG(memc_user_data->compression_level); case MEMC_OPT_COMPRESSION: RETURN_BOOL(memc_user_data->compression_enabled); case MEMC_OPT_ITEM_SIZE_LIMIT: RETURN_LONG(memc_user_data->item_size_limit); case MEMC_OPT_PREFIX_KEY: { memcached_return retval; char *result; result = memcached_callback_get(intern->memc, MEMCACHED_CALLBACK_PREFIX_KEY, &retval); if (retval == MEMCACHED_SUCCESS && result) { RETURN_STRING(result); } else { RETURN_EMPTY_STRING(); } } case MEMC_OPT_SERIALIZER: RETURN_LONG((long)memc_user_data->serializer); break; case MEMC_OPT_USER_FLAGS: RETURN_LONG(memc_user_data->set_udf_flags); break; case MEMC_OPT_STORE_RETRY_COUNT: RETURN_LONG((long)memc_user_data->store_retry_count); break; case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE: case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE: if (memcached_server_count(intern->memc) == 0) { php_error_docref(NULL, E_WARNING, "no servers defined"); return; } default: /* * Assume that it's a libmemcached behavior option. */ flag = (memcached_behavior) option; result = memcached_behavior_get(intern->memc, flag); RETURN_LONG((long)result); } } /* }}} */ static int php_memc_set_option(php_memc_object_t *intern, long option, zval *value) { zend_long lval; memcached_return rc = MEMCACHED_FAILURE; memcached_behavior flag; php_memc_user_data_t *memc_user_data = memcached_get_user_data(intern->memc); switch (option) { case MEMC_OPT_COMPRESSION: memc_user_data->compression_enabled = zval_get_long(value) ? 1 : 0; break; case MEMC_OPT_COMPRESSION_TYPE: lval = zval_get_long(value); if (lval == COMPRESSION_TYPE_FASTLZ || #ifdef HAVE_ZSTD_H lval == COMPRESSION_TYPE_ZSTD || #endif lval == COMPRESSION_TYPE_ZLIB) { memc_user_data->compression_type = lval; } else { /* invalid compression type */ intern->rescode = MEMCACHED_INVALID_ARGUMENTS; return 0; } break; case MEMC_OPT_COMPRESSION_LEVEL: lval = zval_get_long(value); memc_user_data->compression_level = lval; break; case MEMC_OPT_ITEM_SIZE_LIMIT: lval = zval_get_long(value); if (lval < 0) { php_error_docref(NULL, E_WARNING, "ITEM_SIZE_LIMIT must be >= 0"); return 0; } memc_user_data->item_size_limit = lval; break; case MEMC_OPT_PREFIX_KEY: { zend_string *str; char *key; str = zval_get_string(value); if (ZSTR_LEN(str) == 0) { key = NULL; } else { key = ZSTR_VAL(str); } if (memcached_callback_set(intern->memc, MEMCACHED_CALLBACK_PREFIX_KEY, key) == MEMCACHED_BAD_KEY_PROVIDED) { zend_string_release(str); intern->rescode = MEMCACHED_INVALID_ARGUMENTS; php_error_docref(NULL, E_WARNING, "bad key provided"); return 0; } zend_string_release(str); } break; case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED: flag = (memcached_behavior) option; lval = zval_get_long(value); rc = memcached_behavior_set(intern->memc, flag, (uint64_t)lval); if (s_memc_status_handle_result_code(intern, rc) == FAILURE) { php_error_docref(NULL, E_WARNING, "error setting memcached option: %s", memcached_strerror (intern->memc, rc)); return 0; } /* * This is necessary because libmemcached does not reset hash/distribution * options on false case, like it does for MEMCACHED_BEHAVIOR_KETAMA * (non-weighted) case. We have to clean up ourselves. */ if (!lval) { (void)memcached_behavior_set_key_hash(intern->memc, MEMCACHED_HASH_DEFAULT); (void)memcached_behavior_set_distribution_hash(intern->memc, MEMCACHED_HASH_DEFAULT); (void)memcached_behavior_set_distribution(intern->memc, MEMCACHED_DISTRIBUTION_MODULA); } break; case MEMC_OPT_SERIALIZER: { lval = zval_get_long(value); /* igbinary serializer */ #ifdef HAVE_MEMCACHED_IGBINARY if (lval == SERIALIZER_IGBINARY) { memc_user_data->serializer = SERIALIZER_IGBINARY; } else #endif #ifdef HAVE_JSON_API if (lval == SERIALIZER_JSON) { memc_user_data->serializer = SERIALIZER_JSON; } else if (lval == SERIALIZER_JSON_ARRAY) { memc_user_data->serializer = SERIALIZER_JSON_ARRAY; } else #endif /* msgpack serializer */ #ifdef HAVE_MEMCACHED_MSGPACK if (lval == SERIALIZER_MSGPACK) { memc_user_data->serializer = SERIALIZER_MSGPACK; } else #endif /* php serializer */ if (lval == SERIALIZER_PHP) { memc_user_data->serializer = SERIALIZER_PHP; } else { memc_user_data->serializer = SERIALIZER_PHP; intern->rescode = MEMCACHED_INVALID_ARGUMENTS; php_error_docref(NULL, E_WARNING, "invalid serializer provided"); return 0; } break; } case MEMC_OPT_USER_FLAGS: lval = zval_get_long(value); if (lval < 0) { memc_user_data->set_udf_flags = -1; return 1; } if (lval > MEMC_VAL_USER_FLAGS_MAX) { php_error_docref(NULL, E_WARNING, "MEMC_OPT_USER_FLAGS must be < %u", MEMC_VAL_USER_FLAGS_MAX); return 0; } memc_user_data->set_udf_flags = lval; break; case MEMC_OPT_STORE_RETRY_COUNT: lval = zval_get_long(value); memc_user_data->store_retry_count = lval; break; default: /* * Assume that it's a libmemcached behavior option. */ if (option < 0) { rc = MEMCACHED_INVALID_ARGUMENTS; } else { flag = (memcached_behavior) option; lval = zval_get_long(value); if (flag < MEMCACHED_BEHAVIOR_MAX) { // don't reset the option when the option value wasn't modified, // while the libmemcached may shutdown all connections. if (memcached_behavior_get(intern->memc, flag) == (uint64_t)lval) { return 1; } rc = memcached_behavior_set(intern->memc, flag, (uint64_t)lval); } else { rc = MEMCACHED_INVALID_ARGUMENTS; } } if (s_memc_status_handle_result_code(intern, rc) == FAILURE) { php_error_docref(NULL, E_WARNING, "error setting memcached option: %s", memcached_strerror (intern->memc, rc)); return 0; } break; } return 1; } static uint32_t *s_zval_to_uint32_array (zval *input, size_t *num_elements) { zval *pzval; uint32_t *retval; size_t i = 0; *num_elements = zend_hash_num_elements(Z_ARRVAL_P(input)); if (!*num_elements) { return NULL; } retval = ecalloc(*num_elements, sizeof(uint32_t)); ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(input), pzval) { zend_long value = 0; value = zval_get_long(pzval); if (value < 0) { php_error_docref(NULL, E_WARNING, "the map must contain positive integers"); efree (retval); *num_elements = 0; return NULL; } retval [i] = (uint32_t) value; i++; } ZEND_HASH_FOREACH_END(); return retval; } /* {{{ Memcached::setBucket(array host_map, array forward_map, integer replicas) Sets the memcached virtual buckets */ PHP_METHOD(Memcached, setBucket) { zval *zserver_map; zval *zforward_map = NULL; zend_long replicas = 0; zend_bool retval = 1; uint32_t *server_map = NULL, *forward_map = NULL; size_t server_map_len = 0, forward_map_len = 0; memcached_return rc; MEMC_METHOD_INIT_VARS; /* "aa!l" */ ZEND_PARSE_PARAMETERS_START(3, 3) Z_PARAM_ARRAY(zserver_map) Z_PARAM_ARRAY_EX(zforward_map, 1, 0) Z_PARAM_LONG(replicas) ZEND_PARSE_PARAMETERS_END(); MEMC_METHOD_FETCH_OBJECT; if (zend_hash_num_elements (Z_ARRVAL_P(zserver_map)) == 0) { php_error_docref(NULL, E_WARNING, "server map cannot be empty"); RETURN_FALSE; } if (zforward_map && zend_hash_num_elements (Z_ARRVAL_P(zserver_map)) != zend_hash_num_elements (Z_ARRVAL_P(zforward_map))) { php_error_docref(NULL, E_WARNING, "forward_map length must match the server_map length"); RETURN_FALSE; } if (replicas < 0) { php_error_docref(NULL, E_WARNING, "replicas must be larger than zero"); RETURN_FALSE; } server_map = s_zval_to_uint32_array (zserver_map, &server_map_len); if (!server_map) { RETURN_FALSE; } if (zforward_map) { forward_map = s_zval_to_uint32_array (zforward_map, &forward_map_len); if (!forward_map) { efree (server_map); RETURN_FALSE; } } rc = memcached_bucket_set (intern->memc, server_map, forward_map, (uint32_t) server_map_len, replicas); if (s_memc_status_handle_result_code(intern, rc) == FAILURE) { retval = 0; } efree(server_map); if (forward_map) { efree(forward_map); } RETURN_BOOL(retval); } /* }}} */ /* {{{ Memcached::setOptions(array options) Sets the value for the given option constant */ static PHP_METHOD(Memcached, setOptions) { zval *options; zend_bool ok = 1; zend_string *key; zend_ulong key_index; zval *value; MEMC_METHOD_INIT_VARS; /* "a" */ ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(options) ZEND_PARSE_PARAMETERS_END(); MEMC_METHOD_FETCH_OBJECT; ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(options), key_index, key, value) { if (key) { php_error_docref(NULL, E_WARNING, "invalid configuration option"); ok = 0; } else { if (!php_memc_set_option(intern, (long) key_index, value)) { ok = 0; } } } ZEND_HASH_FOREACH_END(); RETURN_BOOL(ok); } /* }}} */ /* {{{ Memcached::setOption(int option, mixed value) Sets the value for the given option constant */ static PHP_METHOD(Memcached, setOption) { zend_long option; zval *value; MEMC_METHOD_INIT_VARS; /* "lz/" */ ZEND_PARSE_PARAMETERS_START(2, 2) Z_PARAM_LONG(option) Z_PARAM_ZVAL_EX(value, 0, 1) ZEND_PARSE_PARAMETERS_END(); MEMC_METHOD_FETCH_OBJECT; RETURN_BOOL(php_memc_set_option(intern, option, value)); } /* }}} */ #ifdef HAVE_MEMCACHED_SASL /* {{{ Memcached::setSaslAuthData(string user, string pass) Sets sasl credentials */ static PHP_METHOD(Memcached, setSaslAuthData) { MEMC_METHOD_INIT_VARS; memcached_return status; zend_string *user, *pass; /* "SS/" */ ZEND_PARSE_PARAMETERS_START(2, 2) Z_PARAM_STR(user) Z_PARAM_STR(pass) ZEND_PARSE_PARAMETERS_END(); if (!php_memc_init_sasl_if_needed()) { RETURN_FALSE; } MEMC_METHOD_FETCH_OBJECT; if (!memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) { php_error_docref(NULL, E_WARNING, "SASL is only supported with binary protocol"); RETURN_FALSE; } memc_user_data->has_sasl_data = 1; status = memcached_set_sasl_auth_data(intern->memc, ZSTR_VAL(user), ZSTR_VAL(pass)); if (s_memc_status_handle_result_code(intern, status) == FAILURE) { RETURN_FALSE; } RETURN_TRUE; } /* }}} */ #endif /* HAVE_MEMCACHED_SASL */ #ifdef HAVE_MEMCACHED_SET_ENCODING_KEY /* {{{ Memcached::setEncodingKey(string key) Sets AES encryption key (libmemcached 1.0.6 and higher) */ static PHP_METHOD(Memcached, setEncodingKey) { MEMC_METHOD_INIT_VARS; memcached_return status; zend_string *key; /* "S" */ ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STR(key) ZEND_PARSE_PARAMETERS_END(); MEMC_METHOD_FETCH_OBJECT; // libmemcached < 1.0.18 cannot handle a change of encoding key. Warn about this and return false. #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x01000018 if (memc_user_data->encoding_enabled) { php_error_docref(NULL, E_WARNING, "libmemcached versions less than 1.0.18 cannot change encoding key"); RETURN_FALSE; } #endif status = memcached_set_encoding_key(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key)); if (s_memc_status_handle_result_code(intern, status) == FAILURE) { RETURN_FALSE; } memc_user_data->encoding_enabled = 1; RETURN_TRUE; } /* }}} */ #endif /* HAVE_MEMCACHED_SET_ENCODING_KEY */ /* {{{ Memcached::getResultCode() Returns the result code from the last operation */ static PHP_METHOD(Memcached, getResultCode) { MEMC_METHOD_INIT_VARS; if (zend_parse_parameters_none() == FAILURE) { return; } MEMC_METHOD_FETCH_OBJECT; RETURN_LONG(intern->rescode); } /* }}} */ /* {{{ Memcached::getResultMessage() Returns the result message from the last operation */ static PHP_METHOD(Memcached, getResultMessage) { MEMC_METHOD_INIT_VARS; if (zend_parse_parameters_none() == FAILURE) { return; } MEMC_METHOD_FETCH_OBJECT; switch (intern->rescode) { case MEMC_RES_PAYLOAD_FAILURE: RETURN_STRING("PAYLOAD FAILURE"); break; case MEMCACHED_ERRNO: case MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE: case MEMCACHED_UNKNOWN_READ_FAILURE: if (intern->memc_errno) { zend_string *str = strpprintf(0, "%s: %s", memcached_strerror(intern->memc, (memcached_return)intern->rescode), strerror(intern->memc_errno)); RETURN_STR(str); } /* Fall through */ default: RETURN_STRING(memcached_strerror(intern->memc, (memcached_return)intern->rescode)); break; } } /* }}} */ /* {{{ Memcached::isPersistent() Returns the true if instance uses a persistent connection */ static PHP_METHOD(Memcached, isPersistent) { MEMC_METHOD_INIT_VARS; if (zend_parse_parameters_none() == FAILURE) { return; } MEMC_METHOD_FETCH_OBJECT; RETURN_BOOL(memc_user_data->is_persistent); } /* }}} */ /* {{{ Memcached::isPristine() Returns the true if instance is recently created */ static PHP_METHOD(Memcached, isPristine) { MEMC_METHOD_INIT_VARS; if (zend_parse_parameters_none() == FAILURE) { return; } MEMC_METHOD_FETCH_OBJECT; RETURN_BOOL(intern->is_pristine); } /* }}} */ /* {{{ bool Memcached::checkKey(string key) Checks if a key is valid */ PHP_METHOD(Memcached, checkKey) { zend_string *key; MEMC_METHOD_INIT_VARS; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STR(key) ZEND_PARSE_PARAMETERS_END(); MEMC_METHOD_FETCH_OBJECT; s_memc_set_status(intern, MEMCACHED_SUCCESS, 0); MEMC_CHECK_KEY(intern, key); RETURN_TRUE; } /* }}} */ /**************************************** Internal support code ****************************************/ /* {{{ constructor/destructor */ static void php_memc_destroy(memcached_st *memc, php_memc_user_data_t *memc_user_data) { #ifdef HAVE_MEMCACHED_SASL if (memc_user_data->has_sasl_data) { memcached_destroy_sasl_auth_data(memc); } #endif memcached_free(memc); pefree(memc_user_data, memc_user_data->is_persistent); } static void php_memc_object_free_storage(zend_object *object) { php_memc_object_t *intern = php_memc_fetch_object(object); if (intern->memc) { php_memc_user_data_t *memc_user_data = memcached_get_user_data(intern->memc); if (!memc_user_data->is_persistent) { php_memc_destroy(intern->memc, memc_user_data); } } intern->memc = NULL; zend_object_std_dtor(&intern->zo); } static zend_object *php_memc_object_new(zend_class_entry *ce) { php_memc_object_t *intern = ecalloc(1, sizeof(php_memc_object_t) + zend_object_properties_size(ce)); zend_object_std_init(&intern->zo, ce); object_properties_init(&intern->zo, ce); intern->zo.handlers = &memcached_object_handlers; return &intern->zo; } #ifdef HAVE_MEMCACHED_PROTOCOL static void php_memc_server_free_storage(zend_object *object) { php_memc_server_t *intern = php_memc_server_fetch_object(object); php_memc_proto_handler_destroy(&intern->handler); zend_object_std_dtor(&intern->zo); } zend_object *php_memc_server_new(zend_class_entry *ce) { php_memc_server_t *intern; intern = ecalloc(1, sizeof(php_memc_server_t) + zend_object_properties_size(ce)); zend_object_std_init(&intern->zo, ce); object_properties_init(&intern->zo, ce); intern->zo.handlers = &memcached_server_object_handlers; intern->handler = php_memc_proto_handler_new(); return &intern->zo; } #endif ZEND_RSRC_DTOR_FUNC(php_memc_dtor) { if (res->ptr) { memcached_st *memc = (memcached_st *) res->ptr; php_memc_destroy(memc, memcached_get_user_data(memc)); res->ptr = NULL; } } /* }}} */ /* {{{ internal API functions */ static memcached_return s_server_cursor_list_servers_cb(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context) { zval array; zval *return_value = (zval *) in_context; array_init(&array); add_assoc_string(&array, "host", (char*)memcached_server_name(instance)); add_assoc_long(&array, "port", memcached_server_port(instance)); add_assoc_string(&array, "type", (char*)memcached_server_type(instance)); /* * API does not allow to get at this field. add_assoc_long(array, "weight", instance->weight); */ add_next_index_zval(return_value, &array); return MEMCACHED_SUCCESS; } static memcached_return s_server_cursor_version_cb(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context) { zend_string *address, *version; zval rv, *return_value = (zval *)in_context; #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x01000009 version = strpprintf(0, "%d.%d.%d", memcached_server_major_version(instance), memcached_server_minor_version(instance), memcached_server_micro_version(instance)); #else version = strpprintf(0, "%d.%d.%d", instance->major_version, instance->minor_version, instance->micro_version); #endif address = strpprintf(0, "%s:%d", memcached_server_name(instance), memcached_server_port(instance)); ZVAL_STR(&rv, version); zend_hash_add(Z_ARRVAL_P(return_value), address, &rv); zend_string_release(address); return MEMCACHED_SUCCESS; } static zend_string *s_decompress_value (const char *payload, size_t payload_len, uint32_t flags) { zend_string *buffer; uint32_t stored_length; unsigned long length; zend_bool decompress_status = 0; zend_bool is_fastlz = 0, is_zlib = 0, is_zstd = 0; if (payload_len < sizeof (uint32_t)) { return NULL; } is_fastlz = MEMC_VAL_HAS_FLAG(flags, MEMC_VAL_COMPRESSION_FASTLZ); is_zstd = MEMC_VAL_HAS_FLAG(flags, MEMC_VAL_COMPRESSION_ZSTD); is_zlib = MEMC_VAL_HAS_FLAG(flags, MEMC_VAL_COMPRESSION_ZLIB); #ifndef HAVE_ZSTD_H if (is_zstd) { php_error_docref(NULL, E_WARNING, "could not decompress value: value was compressed with zstd but zstd support has not been compiled in"); return NULL; } #endif if (!is_fastlz && !is_zlib && !is_zstd) { php_error_docref(NULL, E_WARNING, "could not decompress value: unrecognised compression type"); return NULL; } memcpy(&stored_length, payload, sizeof (uint32_t)); payload += sizeof (uint32_t); payload_len -= sizeof (uint32_t); buffer = zend_string_alloc (stored_length, 0); #ifdef HAVE_ZSTD_H if (is_zstd) { length = ZSTD_getFrameContentSize(payload, payload_len); if (length == ZSTD_CONTENTSIZE_ERROR) { php_error_docref(NULL, E_WARNING, "value was not compressed by zstd"); zend_string_release (buffer); return NULL; } else if (length == ZSTD_CONTENTSIZE_UNKNOWN) { php_error_docref(NULL, E_WARNING, "zstd streaming decompression not supported"); zend_string_release (buffer); return NULL; } decompress_status = !ZSTD_isError(ZSTD_decompress(&buffer->val, buffer->len, payload, payload_len)); } else #endif if (is_fastlz) { decompress_status = ((length = fastlz_decompress(payload, payload_len, &buffer->val, buffer->len)) > 0); } else if (is_zlib) { unsigned long ds = buffer->len; decompress_status = (uncompress((Bytef *) buffer->val, &ds, (Bytef *)payload, payload_len) == Z_OK); buffer->len = ds; } ZSTR_VAL(buffer)[stored_length] = '\0'; if (!decompress_status) { php_error_docref(NULL, E_WARNING, "could not decompress value"); zend_string_release (buffer); return NULL; } zend_string_forget_hash_val(buffer); return buffer; } static zend_bool s_unserialize_value (memcached_st *memc, int val_type, zend_string *payload, zval *return_value) { switch (val_type) { case MEMC_VAL_IS_SERIALIZED: { php_unserialize_data_t var_hash; const unsigned char *p, *max; p = (const unsigned char *) ZSTR_VAL(payload); max = p + ZSTR_LEN(payload); PHP_VAR_UNSERIALIZE_INIT(var_hash); if (!php_var_unserialize(return_value, &p, max, &var_hash)) { zval_ptr_dtor(return_value); ZVAL_FALSE(return_value); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); php_error_docref(NULL, E_WARNING, "could not unserialize value"); return 0; } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); } break; case MEMC_VAL_IS_IGBINARY: #ifdef HAVE_MEMCACHED_IGBINARY if (igbinary_unserialize((uint8_t *) ZSTR_VAL(payload), ZSTR_LEN(payload), return_value)) { ZVAL_FALSE(return_value); php_error_docref(NULL, E_WARNING, "could not unserialize value with igbinary"); return 0; } #else ZVAL_FALSE(return_value); php_error_docref(NULL, E_WARNING, "could not unserialize value, no igbinary support"); return 0; #endif break; case MEMC_VAL_IS_JSON: #ifdef HAVE_JSON_API { php_memc_user_data_t *memc_user_data = memcached_get_user_data(memc); php_json_decode(return_value, ZSTR_VAL(payload), ZSTR_LEN(payload), (memc_user_data->serializer == SERIALIZER_JSON_ARRAY), PHP_JSON_PARSER_DEFAULT_DEPTH); } #else ZVAL_FALSE(return_value); php_error_docref(NULL, E_WARNING, "could not unserialize value, no json support"); return 0; #endif break; case MEMC_VAL_IS_MSGPACK: #ifdef HAVE_MEMCACHED_MSGPACK php_msgpack_unserialize(return_value, ZSTR_VAL(payload), ZSTR_LEN(payload)); #else ZVAL_FALSE(return_value); php_error_docref(NULL, E_WARNING, "could not unserialize value, no msgpack support"); return 0; #endif break; } return 1; } static zend_bool s_memcached_result_to_zval(memcached_st *memc, memcached_result_st *result, zval *return_value) { zend_string *data; const char *payload; size_t payload_len; uint32_t flags; zend_bool retval = 1; payload = memcached_result_value(result); payload_len = memcached_result_length(result); flags = memcached_result_flags(result); if (!payload && payload_len > 0) { php_error_docref(NULL, E_WARNING, "Could not handle non-existing value of length %zu", payload_len); return 0; } if (MEMC_VAL_HAS_FLAG(flags, MEMC_VAL_COMPRESSED)) { data = s_decompress_value (payload, payload_len, flags); if (!data) { return 0; } } else { data = zend_string_init(payload, payload_len, 0); } switch (MEMC_VAL_GET_TYPE(flags)) { case MEMC_VAL_IS_STRING: ZVAL_STR_COPY(return_value, data); break; case MEMC_VAL_IS_LONG: ZVAL_LONG(return_value, strtol(ZSTR_VAL(data), NULL, 10)); break; case MEMC_VAL_IS_DOUBLE: { if (zend_string_equals_literal(data, "Infinity")) { ZVAL_DOUBLE(return_value, php_get_inf()); } else if (zend_string_equals_literal(data, "-Infinity")) { ZVAL_DOUBLE(return_value, -php_get_inf()); } else if (zend_string_equals_literal(data, "NaN")) { ZVAL_DOUBLE(return_value, php_get_nan()); } else { ZVAL_DOUBLE(return_value, zend_strtod(ZSTR_VAL(data), NULL)); } } break; case MEMC_VAL_IS_BOOL: ZVAL_BOOL(return_value, payload_len > 0 && ZSTR_VAL(data)[0] == '1'); break; case MEMC_VAL_IS_SERIALIZED: case MEMC_VAL_IS_IGBINARY: case MEMC_VAL_IS_JSON: case MEMC_VAL_IS_MSGPACK: retval = s_unserialize_value (memc, MEMC_VAL_GET_TYPE(flags), data, return_value); break; default: php_error_docref(NULL, E_WARNING, "unknown payload type"); retval = 0; break; } zend_string_release(data); return retval; } PHP_MEMCACHED_API zend_class_entry *php_memc_get_ce(void) { return memcached_ce; } PHP_MEMCACHED_API zend_class_entry *php_memc_get_exception(void) { return memcached_exception_ce; } PHP_MEMCACHED_API zend_class_entry *php_memc_get_exception_base(int root) { if (!root) { if (!spl_ce_RuntimeException) { zend_class_entry *pce; zval *pce_z; if ((pce_z = zend_hash_str_find(CG(class_table), "runtimeexception", sizeof("RuntimeException") - 1)) != NULL) { pce = Z_CE_P(pce_z); spl_ce_RuntimeException = pce; return pce; } } else { return spl_ce_RuntimeException; } } return zend_exception_get_default(); } #ifdef HAVE_MEMCACHED_PROTOCOL static void s_destroy_cb (zend_fcall_info *fci) { if (fci->size > 0) { zval_ptr_dtor(&fci->function_name); if (fci->object) { OBJ_RELEASE(fci->object); } } } static PHP_METHOD(MemcachedServer, run) { int i; zend_bool rc; zend_string *address; php_memc_server_t *intern; intern = Z_MEMC_SERVER_P(getThis()); /* "S" */ ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STR(address) ZEND_PARSE_PARAMETERS_END(); rc = php_memc_proto_handler_run(intern->handler, address); for (i = MEMC_SERVER_ON_MIN + 1; i < MEMC_SERVER_ON_MAX; i++) { s_destroy_cb(&MEMC_SERVER_G(callbacks) [i].fci); } RETURN_BOOL(rc); } static PHP_METHOD(MemcachedServer, on) { zend_long event; zend_fcall_info fci; zend_fcall_info_cache fci_cache; zend_bool rc = 0; /* "lf!" */ ZEND_PARSE_PARAMETERS_START(2, 2) Z_PARAM_LONG(event) Z_PARAM_FUNC_EX(fci, fci_cache, 1, 0) ZEND_PARSE_PARAMETERS_END(); if (event <= MEMC_SERVER_ON_MIN || event >= MEMC_SERVER_ON_MAX) { RETURN_FALSE; } if (fci.size > 0) { s_destroy_cb (&MEMC_SERVER_G(callbacks) [event].fci); MEMC_SERVER_G(callbacks) [event].fci = fci; MEMC_SERVER_G(callbacks) [event].fci_cache = fci_cache; Z_TRY_ADDREF(fci.function_name); if (fci.object) { GC_ADDREF(fci.object); } } RETURN_BOOL(rc); } #endif #if PHP_VERSION_ID < 80000 #include "php_memcached_legacy_arginfo.h" #else #include "zend_attributes.h" #include "php_memcached_arginfo.h" #endif /* {{{ memcached_module_entry */ #if ZEND_MODULE_API_NO >= 20050922 static const zend_module_dep memcached_deps[] = { #ifdef HAVE_MEMCACHED_SESSION ZEND_MOD_REQUIRED("session") #endif #ifdef HAVE_MEMCACHED_IGBINARY ZEND_MOD_REQUIRED("igbinary") #endif #ifdef HAVE_MEMCACHED_MSGPACK ZEND_MOD_REQUIRED("msgpack") #endif ZEND_MOD_REQUIRED("spl") ZEND_MOD_END }; #endif static PHP_GINIT_FUNCTION(php_memcached) { #ifdef HAVE_MEMCACHED_SESSION php_memcached_globals->session.lock_enabled = 0; php_memcached_globals->session.lock_wait_max = 150; php_memcached_globals->session.lock_wait_min = 150; php_memcached_globals->session.lock_retries = 200; php_memcached_globals->session.lock_expiration = 30; php_memcached_globals->session.binary_protocol_enabled = 1; php_memcached_globals->session.consistent_hash_enabled = 1; php_memcached_globals->session.consistent_hash_type = MEMCACHED_BEHAVIOR_KETAMA; php_memcached_globals->session.consistent_hash_name = NULL; php_memcached_globals->session.number_of_replicas = 0; php_memcached_globals->session.server_failure_limit = 1; php_memcached_globals->session.randomize_replica_read_enabled = 1; php_memcached_globals->session.remove_failed_servers_enabled = 1; php_memcached_globals->session.connect_timeout = 1000; php_memcached_globals->session.prefix = NULL; php_memcached_globals->session.persistent_enabled = 0; php_memcached_globals->session.sasl_username = NULL; php_memcached_globals->session.sasl_password = NULL; #endif #ifdef HAVE_MEMCACHED_PROTOCOL memset(&php_memcached_globals->server, 0, sizeof(php_memcached_globals->server)); #endif php_memcached_globals->memc.serializer_name = NULL; php_memcached_globals->memc.serializer_type = SERIALIZER_DEFAULT; php_memcached_globals->memc.compression_name = NULL; php_memcached_globals->memc.compression_threshold = 2000; php_memcached_globals->memc.compression_type = COMPRESSION_TYPE_FASTLZ; php_memcached_globals->memc.compression_factor = 1.30; php_memcached_globals->memc.compression_level = 6; php_memcached_globals->memc.store_retry_count = 2; php_memcached_globals->memc.item_size_limit = 0; php_memcached_globals->memc.sasl_initialised = 0; php_memcached_globals->no_effect = 0; /* Defaults for certain options */ php_memcached_globals->memc.default_behavior.consistent_hash_enabled = 0; php_memcached_globals->memc.default_behavior.binary_protocol_enabled = 0; php_memcached_globals->memc.default_behavior.connect_timeout = 0; } zend_module_entry memcached_module_entry = { STANDARD_MODULE_HEADER_EX, NULL, memcached_deps, "memcached", NULL, PHP_MINIT(memcached), PHP_MSHUTDOWN(memcached), NULL, NULL, PHP_MINFO(memcached), PHP_MEMCACHED_VERSION, PHP_MODULE_GLOBALS(php_memcached), PHP_GINIT(php_memcached), NULL, NULL, STANDARD_MODULE_PROPERTIES_EX }; /* }}} */ /* {{{ php_memc_register_constants */ static void php_memc_register_constants(INIT_FUNC_ARGS) { #define REGISTER_MEMC_CLASS_CONST_LONG(name, value) zend_declare_class_constant_long(php_memc_get_ce() , ZEND_STRS( #name ) - 1, value) #define REGISTER_MEMC_CLASS_CONST_BOOL(name, value) zend_declare_class_constant_bool(php_memc_get_ce() , ZEND_STRS( #name ) - 1, value) #define REGISTER_MEMC_CLASS_CONST_NULL(name) zend_declare_class_constant_null(php_memc_get_ce() , ZEND_STRS( #name ) - 1) /* * Class options */ REGISTER_MEMC_CLASS_CONST_LONG(LIBMEMCACHED_VERSION_HEX, LIBMEMCACHED_VERSION_HEX); REGISTER_MEMC_CLASS_CONST_LONG(OPT_COMPRESSION, MEMC_OPT_COMPRESSION); REGISTER_MEMC_CLASS_CONST_LONG(OPT_COMPRESSION_TYPE, MEMC_OPT_COMPRESSION_TYPE); REGISTER_MEMC_CLASS_CONST_LONG(OPT_COMPRESSION_LEVEL, MEMC_OPT_COMPRESSION_LEVEL); REGISTER_MEMC_CLASS_CONST_LONG(OPT_PREFIX_KEY, MEMC_OPT_PREFIX_KEY); REGISTER_MEMC_CLASS_CONST_LONG(OPT_SERIALIZER, MEMC_OPT_SERIALIZER); REGISTER_MEMC_CLASS_CONST_LONG(OPT_USER_FLAGS, MEMC_OPT_USER_FLAGS); REGISTER_MEMC_CLASS_CONST_LONG(OPT_STORE_RETRY_COUNT, MEMC_OPT_STORE_RETRY_COUNT); REGISTER_MEMC_CLASS_CONST_LONG(OPT_ITEM_SIZE_LIMIT, MEMC_OPT_ITEM_SIZE_LIMIT); /* * Indicate whether igbinary serializer is available */ #ifdef HAVE_MEMCACHED_IGBINARY REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_IGBINARY, 1); #else REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_IGBINARY, 0); #endif /* * Indicate whether zstd compression is available */ #ifdef HAVE_ZSTD_H REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_ZSTD, 1); #else REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_ZSTD, 0); #endif /* * Indicate whether json serializer is available */ #ifdef HAVE_JSON_API REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_JSON, 1); #else REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_JSON, 0); #endif /* * Indicate whether msgpack serializer is available */ #ifdef HAVE_MEMCACHED_MSGPACK REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_MSGPACK, 1); #else REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_MSGPACK, 0); #endif /* * Indicate whether set_encoding_key is available */ #ifdef HAVE_MEMCACHED_SET_ENCODING_KEY REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_ENCODING, 1); #else REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_ENCODING, 0); #endif #ifdef HAVE_MEMCACHED_SESSION REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_SESSION, 1); #else REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_SESSION, 0); #endif #ifdef HAVE_MEMCACHED_SASL REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_SASL, 1); #else REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_SASL, 0); #endif /* * libmemcached behavior options */ REGISTER_MEMC_CLASS_CONST_LONG(OPT_HASH, MEMCACHED_BEHAVIOR_HASH); REGISTER_MEMC_CLASS_CONST_LONG(HASH_DEFAULT, MEMCACHED_HASH_DEFAULT); REGISTER_MEMC_CLASS_CONST_LONG(HASH_MD5, MEMCACHED_HASH_MD5); REGISTER_MEMC_CLASS_CONST_LONG(HASH_CRC, MEMCACHED_HASH_CRC); REGISTER_MEMC_CLASS_CONST_LONG(HASH_FNV1_64, MEMCACHED_HASH_FNV1_64); REGISTER_MEMC_CLASS_CONST_LONG(HASH_FNV1A_64, MEMCACHED_HASH_FNV1A_64); REGISTER_MEMC_CLASS_CONST_LONG(HASH_FNV1_32, MEMCACHED_HASH_FNV1_32); REGISTER_MEMC_CLASS_CONST_LONG(HASH_FNV1A_32, MEMCACHED_HASH_FNV1A_32); REGISTER_MEMC_CLASS_CONST_LONG(HASH_HSIEH, MEMCACHED_HASH_HSIEH); REGISTER_MEMC_CLASS_CONST_LONG(HASH_MURMUR, MEMCACHED_HASH_MURMUR); REGISTER_MEMC_CLASS_CONST_LONG(OPT_DISTRIBUTION, MEMCACHED_BEHAVIOR_DISTRIBUTION); REGISTER_MEMC_CLASS_CONST_LONG(DISTRIBUTION_MODULA, MEMCACHED_DISTRIBUTION_MODULA); REGISTER_MEMC_CLASS_CONST_LONG(DISTRIBUTION_CONSISTENT, MEMCACHED_DISTRIBUTION_CONSISTENT); REGISTER_MEMC_CLASS_CONST_LONG(DISTRIBUTION_VIRTUAL_BUCKET, MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET); REGISTER_MEMC_CLASS_CONST_LONG(OPT_LIBKETAMA_COMPATIBLE, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED); REGISTER_MEMC_CLASS_CONST_LONG(OPT_LIBKETAMA_HASH, MEMCACHED_BEHAVIOR_KETAMA_HASH); REGISTER_MEMC_CLASS_CONST_LONG(OPT_TCP_KEEPALIVE, MEMCACHED_BEHAVIOR_TCP_KEEPALIVE); REGISTER_MEMC_CLASS_CONST_LONG(OPT_BUFFER_WRITES, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS); REGISTER_MEMC_CLASS_CONST_LONG(OPT_BINARY_PROTOCOL, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL); REGISTER_MEMC_CLASS_CONST_LONG(OPT_NO_BLOCK, MEMCACHED_BEHAVIOR_NO_BLOCK); REGISTER_MEMC_CLASS_CONST_LONG(OPT_TCP_NODELAY, MEMCACHED_BEHAVIOR_TCP_NODELAY); REGISTER_MEMC_CLASS_CONST_LONG(OPT_SOCKET_SEND_SIZE, MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE); REGISTER_MEMC_CLASS_CONST_LONG(OPT_SOCKET_RECV_SIZE, MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE); REGISTER_MEMC_CLASS_CONST_LONG(OPT_CONNECT_TIMEOUT, MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT); REGISTER_MEMC_CLASS_CONST_LONG(OPT_RETRY_TIMEOUT, MEMCACHED_BEHAVIOR_RETRY_TIMEOUT); #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x01000003 REGISTER_MEMC_CLASS_CONST_LONG(OPT_DEAD_TIMEOUT, MEMCACHED_BEHAVIOR_DEAD_TIMEOUT); #endif REGISTER_MEMC_CLASS_CONST_LONG(OPT_SEND_TIMEOUT, MEMCACHED_BEHAVIOR_SND_TIMEOUT); REGISTER_MEMC_CLASS_CONST_LONG(OPT_RECV_TIMEOUT, MEMCACHED_BEHAVIOR_RCV_TIMEOUT); REGISTER_MEMC_CLASS_CONST_LONG(OPT_POLL_TIMEOUT, MEMCACHED_BEHAVIOR_POLL_TIMEOUT); REGISTER_MEMC_CLASS_CONST_LONG(OPT_CACHE_LOOKUPS, MEMCACHED_BEHAVIOR_CACHE_LOOKUPS); REGISTER_MEMC_CLASS_CONST_LONG(OPT_SERVER_FAILURE_LIMIT, MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT); REGISTER_MEMC_CLASS_CONST_LONG(OPT_AUTO_EJECT_HOSTS, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS); REGISTER_MEMC_CLASS_CONST_LONG(OPT_HASH_WITH_PREFIX_KEY, MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY); REGISTER_MEMC_CLASS_CONST_LONG(OPT_NOREPLY, MEMCACHED_BEHAVIOR_NOREPLY); REGISTER_MEMC_CLASS_CONST_LONG(OPT_SORT_HOSTS, MEMCACHED_BEHAVIOR_SORT_HOSTS); REGISTER_MEMC_CLASS_CONST_LONG(OPT_VERIFY_KEY, MEMCACHED_BEHAVIOR_VERIFY_KEY); REGISTER_MEMC_CLASS_CONST_LONG(OPT_USE_UDP, MEMCACHED_BEHAVIOR_USE_UDP); REGISTER_MEMC_CLASS_CONST_LONG(OPT_NUMBER_OF_REPLICAS, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS); REGISTER_MEMC_CLASS_CONST_LONG(OPT_RANDOMIZE_REPLICA_READ, MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ); REGISTER_MEMC_CLASS_CONST_LONG(OPT_REMOVE_FAILED_SERVERS, MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS); #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x01000018 REGISTER_MEMC_CLASS_CONST_LONG(OPT_SERVER_TIMEOUT_LIMIT, MEMCACHED_BEHAVIOR_SERVER_TIMEOUT_LIMIT); #endif /* * libmemcached result codes */ REGISTER_MEMC_CLASS_CONST_LONG(RES_SUCCESS, MEMCACHED_SUCCESS); REGISTER_MEMC_CLASS_CONST_LONG(RES_FAILURE, MEMCACHED_FAILURE); REGISTER_MEMC_CLASS_CONST_LONG(RES_HOST_LOOKUP_FAILURE, MEMCACHED_HOST_LOOKUP_FAILURE); REGISTER_MEMC_CLASS_CONST_LONG(RES_CONNECTION_FAILURE, MEMCACHED_CONNECTION_FAILURE); REGISTER_MEMC_CLASS_CONST_LONG(RES_CONNECTION_BIND_FAILURE, MEMCACHED_CONNECTION_BIND_FAILURE); REGISTER_MEMC_CLASS_CONST_LONG(RES_WRITE_FAILURE, MEMCACHED_WRITE_FAILURE); REGISTER_MEMC_CLASS_CONST_LONG(RES_READ_FAILURE, MEMCACHED_READ_FAILURE); REGISTER_MEMC_CLASS_CONST_LONG(RES_UNKNOWN_READ_FAILURE, MEMCACHED_UNKNOWN_READ_FAILURE); REGISTER_MEMC_CLASS_CONST_LONG(RES_PROTOCOL_ERROR, MEMCACHED_PROTOCOL_ERROR); REGISTER_MEMC_CLASS_CONST_LONG(RES_CLIENT_ERROR, MEMCACHED_CLIENT_ERROR); REGISTER_MEMC_CLASS_CONST_LONG(RES_SERVER_ERROR, MEMCACHED_SERVER_ERROR); REGISTER_MEMC_CLASS_CONST_LONG(RES_DATA_EXISTS, MEMCACHED_DATA_EXISTS); REGISTER_MEMC_CLASS_CONST_LONG(RES_DATA_DOES_NOT_EXIST, MEMCACHED_DATA_DOES_NOT_EXIST); REGISTER_MEMC_CLASS_CONST_LONG(RES_NOTSTORED, MEMCACHED_NOTSTORED); REGISTER_MEMC_CLASS_CONST_LONG(RES_STORED, MEMCACHED_STORED); REGISTER_MEMC_CLASS_CONST_LONG(RES_NOTFOUND, MEMCACHED_NOTFOUND); REGISTER_MEMC_CLASS_CONST_LONG(RES_PARTIAL_READ, MEMCACHED_PARTIAL_READ); REGISTER_MEMC_CLASS_CONST_LONG(RES_SOME_ERRORS, MEMCACHED_SOME_ERRORS); REGISTER_MEMC_CLASS_CONST_LONG(RES_NO_SERVERS, MEMCACHED_NO_SERVERS); REGISTER_MEMC_CLASS_CONST_LONG(RES_END, MEMCACHED_END); REGISTER_MEMC_CLASS_CONST_LONG(RES_DELETED, MEMCACHED_DELETED); REGISTER_MEMC_CLASS_CONST_LONG(RES_VALUE, MEMCACHED_VALUE); REGISTER_MEMC_CLASS_CONST_LONG(RES_STAT, MEMCACHED_STAT); REGISTER_MEMC_CLASS_CONST_LONG(RES_ITEM, MEMCACHED_ITEM); REGISTER_MEMC_CLASS_CONST_LONG(RES_ERRNO, MEMCACHED_ERRNO); REGISTER_MEMC_CLASS_CONST_LONG(RES_FAIL_UNIX_SOCKET, MEMCACHED_FAIL_UNIX_SOCKET); REGISTER_MEMC_CLASS_CONST_LONG(RES_NOT_SUPPORTED, MEMCACHED_NOT_SUPPORTED); REGISTER_MEMC_CLASS_CONST_LONG(RES_NO_KEY_PROVIDED, MEMCACHED_NO_KEY_PROVIDED); REGISTER_MEMC_CLASS_CONST_LONG(RES_FETCH_NOTFINISHED, MEMCACHED_FETCH_NOTFINISHED); REGISTER_MEMC_CLASS_CONST_LONG(RES_TIMEOUT, MEMCACHED_TIMEOUT); REGISTER_MEMC_CLASS_CONST_LONG(RES_BUFFERED, MEMCACHED_BUFFERED); REGISTER_MEMC_CLASS_CONST_LONG(RES_BAD_KEY_PROVIDED, MEMCACHED_BAD_KEY_PROVIDED); REGISTER_MEMC_CLASS_CONST_LONG(RES_INVALID_HOST_PROTOCOL, MEMCACHED_INVALID_HOST_PROTOCOL); REGISTER_MEMC_CLASS_CONST_LONG(RES_SERVER_MARKED_DEAD, MEMCACHED_SERVER_MARKED_DEAD); REGISTER_MEMC_CLASS_CONST_LONG(RES_UNKNOWN_STAT_KEY, MEMCACHED_UNKNOWN_STAT_KEY); REGISTER_MEMC_CLASS_CONST_LONG(RES_INVALID_ARGUMENTS, MEMCACHED_INVALID_ARGUMENTS); REGISTER_MEMC_CLASS_CONST_LONG(RES_PARSE_ERROR, MEMCACHED_PARSE_ERROR); REGISTER_MEMC_CLASS_CONST_LONG(RES_PARSE_USER_ERROR, MEMCACHED_PARSE_USER_ERROR); REGISTER_MEMC_CLASS_CONST_LONG(RES_DEPRECATED, MEMCACHED_DEPRECATED); REGISTER_MEMC_CLASS_CONST_LONG(RES_IN_PROGRESS, MEMCACHED_IN_PROGRESS); REGISTER_MEMC_CLASS_CONST_LONG(RES_MAXIMUM_RETURN, MEMCACHED_MAXIMUM_RETURN); REGISTER_MEMC_CLASS_CONST_LONG(RES_MEMORY_ALLOCATION_FAILURE, MEMCACHED_MEMORY_ALLOCATION_FAILURE); REGISTER_MEMC_CLASS_CONST_LONG(RES_CONNECTION_SOCKET_CREATE_FAILURE, MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE); REGISTER_MEMC_CLASS_CONST_LONG(RES_E2BIG, MEMCACHED_E2BIG); REGISTER_MEMC_CLASS_CONST_LONG(RES_KEY_TOO_BIG, MEMCACHED_KEY_TOO_BIG); REGISTER_MEMC_CLASS_CONST_LONG(RES_SERVER_TEMPORARILY_DISABLED, MEMCACHED_SERVER_TEMPORARILY_DISABLED); #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x01000008 REGISTER_MEMC_CLASS_CONST_LONG(RES_SERVER_MEMORY_ALLOCATION_FAILURE, MEMCACHED_SERVER_MEMORY_ALLOCATION_FAILURE); #endif #ifdef HAVE_MEMCACHED_SASL REGISTER_MEMC_CLASS_CONST_LONG(RES_AUTH_PROBLEM, MEMCACHED_AUTH_PROBLEM); REGISTER_MEMC_CLASS_CONST_LONG(RES_AUTH_FAILURE, MEMCACHED_AUTH_FAILURE); REGISTER_MEMC_CLASS_CONST_LONG(RES_AUTH_CONTINUE, MEMCACHED_AUTH_CONTINUE); #endif /* * Our result codes. */ REGISTER_MEMC_CLASS_CONST_LONG(RES_PAYLOAD_FAILURE, MEMC_RES_PAYLOAD_FAILURE); /* * Serializer types. */ REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_PHP, SERIALIZER_PHP); REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_IGBINARY, SERIALIZER_IGBINARY); REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_JSON, SERIALIZER_JSON); REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_JSON_ARRAY, SERIALIZER_JSON_ARRAY); REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_MSGPACK, SERIALIZER_MSGPACK); /* * Compression types */ REGISTER_MEMC_CLASS_CONST_LONG(COMPRESSION_FASTLZ, COMPRESSION_TYPE_FASTLZ); REGISTER_MEMC_CLASS_CONST_LONG(COMPRESSION_ZLIB, COMPRESSION_TYPE_ZLIB); REGISTER_MEMC_CLASS_CONST_LONG(COMPRESSION_ZSTD, COMPRESSION_TYPE_ZSTD); /* * Flags. */ REGISTER_MEMC_CLASS_CONST_LONG(GET_PRESERVE_ORDER, MEMC_GET_PRESERVE_ORDER); REGISTER_MEMC_CLASS_CONST_LONG(GET_EXTENDED, MEMC_GET_EXTENDED); #ifdef HAVE_MEMCACHED_PROTOCOL /* * Server callbacks */ REGISTER_MEMC_CLASS_CONST_LONG(ON_CONNECT, MEMC_SERVER_ON_CONNECT); REGISTER_MEMC_CLASS_CONST_LONG(ON_ADD, MEMC_SERVER_ON_ADD); REGISTER_MEMC_CLASS_CONST_LONG(ON_APPEND, MEMC_SERVER_ON_APPEND); REGISTER_MEMC_CLASS_CONST_LONG(ON_DECREMENT, MEMC_SERVER_ON_DECREMENT); REGISTER_MEMC_CLASS_CONST_LONG(ON_DELETE, MEMC_SERVER_ON_DELETE); REGISTER_MEMC_CLASS_CONST_LONG(ON_FLUSH, MEMC_SERVER_ON_FLUSH); REGISTER_MEMC_CLASS_CONST_LONG(ON_GET, MEMC_SERVER_ON_GET); REGISTER_MEMC_CLASS_CONST_LONG(ON_INCREMENT, MEMC_SERVER_ON_INCREMENT); REGISTER_MEMC_CLASS_CONST_LONG(ON_NOOP, MEMC_SERVER_ON_NOOP); REGISTER_MEMC_CLASS_CONST_LONG(ON_PREPEND, MEMC_SERVER_ON_PREPEND); REGISTER_MEMC_CLASS_CONST_LONG(ON_QUIT, MEMC_SERVER_ON_QUIT); REGISTER_MEMC_CLASS_CONST_LONG(ON_REPLACE, MEMC_SERVER_ON_REPLACE); REGISTER_MEMC_CLASS_CONST_LONG(ON_SET, MEMC_SERVER_ON_SET); REGISTER_MEMC_CLASS_CONST_LONG(ON_STAT, MEMC_SERVER_ON_STAT); REGISTER_MEMC_CLASS_CONST_LONG(ON_VERSION, MEMC_SERVER_ON_VERSION); REGISTER_MEMC_CLASS_CONST_LONG(RESPONSE_SUCCESS, PROTOCOL_BINARY_RESPONSE_SUCCESS); REGISTER_MEMC_CLASS_CONST_LONG(RESPONSE_KEY_ENOENT, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT); REGISTER_MEMC_CLASS_CONST_LONG(RESPONSE_KEY_EEXISTS, PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS); REGISTER_MEMC_CLASS_CONST_LONG(RESPONSE_E2BIG, PROTOCOL_BINARY_RESPONSE_E2BIG); REGISTER_MEMC_CLASS_CONST_LONG(RESPONSE_EINVAL, PROTOCOL_BINARY_RESPONSE_EINVAL); REGISTER_MEMC_CLASS_CONST_LONG(RESPONSE_NOT_STORED, PROTOCOL_BINARY_RESPONSE_NOT_STORED); REGISTER_MEMC_CLASS_CONST_LONG(RESPONSE_DELTA_BADVAL, PROTOCOL_BINARY_RESPONSE_DELTA_BADVAL); REGISTER_MEMC_CLASS_CONST_LONG(RESPONSE_NOT_MY_VBUCKET, PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET); REGISTER_MEMC_CLASS_CONST_LONG(RESPONSE_AUTH_ERROR, PROTOCOL_BINARY_RESPONSE_AUTH_ERROR); REGISTER_MEMC_CLASS_CONST_LONG(RESPONSE_AUTH_CONTINUE, PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE); REGISTER_MEMC_CLASS_CONST_LONG(RESPONSE_UNKNOWN_COMMAND, PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND); REGISTER_MEMC_CLASS_CONST_LONG(RESPONSE_ENOMEM, PROTOCOL_BINARY_RESPONSE_ENOMEM); REGISTER_MEMC_CLASS_CONST_LONG(RESPONSE_NOT_SUPPORTED, PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED); REGISTER_MEMC_CLASS_CONST_LONG(RESPONSE_EINTERNAL, PROTOCOL_BINARY_RESPONSE_EINTERNAL); REGISTER_MEMC_CLASS_CONST_LONG(RESPONSE_EBUSY, PROTOCOL_BINARY_RESPONSE_EBUSY); REGISTER_MEMC_CLASS_CONST_LONG(RESPONSE_ETMPFAIL, PROTOCOL_BINARY_RESPONSE_ETMPFAIL); #endif /* * Return value from simple get errors */ REGISTER_MEMC_CLASS_CONST_BOOL(GET_ERROR_RETURN_VALUE, 0); #undef REGISTER_MEMC_CLASS_CONST_LONG #undef REGISTER_MEMC_CLASS_CONST_BOOL #undef REGISTER_MEMC_CLASS_CONST_NULL } /* }}} */ /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(memcached) { zend_class_entry ce; memcpy(&memcached_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); memcached_object_handlers.offset = XtOffsetOf(php_memc_object_t, zo); memcached_object_handlers.clone_obj = NULL; memcached_object_handlers.free_obj = php_memc_object_free_storage; le_memc = zend_register_list_destructors_ex(NULL, php_memc_dtor, "Memcached persistent connection", module_number); memcached_ce = register_class_Memcached(); memcached_ce->create_object = php_memc_object_new; #ifdef HAVE_MEMCACHED_PROTOCOL memcpy(&memcached_server_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); memcached_server_object_handlers.offset = XtOffsetOf(php_memc_server_t, zo); memcached_server_object_handlers.clone_obj = NULL; memcached_server_object_handlers.free_obj = php_memc_server_free_storage; memcached_server_ce = register_class_MemcachedServer(); memcached_server_ce->create_object = php_memc_server_new; #endif INIT_CLASS_ENTRY(ce, "MemcachedException", NULL); memcached_exception_ce = zend_register_internal_class_ex(&ce, php_memc_get_exception_base(0)); /* TODO * possibly declare custom exception property here */ php_memc_register_constants(INIT_FUNC_ARGS_PASSTHRU); REGISTER_INI_ENTRIES(); #ifdef HAVE_MEMCACHED_SESSION php_memc_session_minit(module_number); #endif return SUCCESS; } /* }}} */ /* {{{ PHP_MSHUTDOWN_FUNCTION */ PHP_MSHUTDOWN_FUNCTION(memcached) { #ifdef HAVE_MEMCACHED_SASL if (MEMC_G(sasl_initialised)) { sasl_done(); } #endif UNREGISTER_INI_ENTRIES(); return SUCCESS; } /* }}} */ /* {{{ PHP_MINFO_FUNCTION */ PHP_MINFO_FUNCTION(memcached) { php_info_print_table_start(); php_info_print_table_header(2, "memcached support", "enabled"); php_info_print_table_row(2, "Version", PHP_MEMCACHED_VERSION); #ifdef LIBMEMCACHED_AWESOME if (strcmp(LIBMEMCACHED_VERSION_STRING, memcached_lib_version())) { php_info_print_table_row(2, "libmemcached-awesome headers version", LIBMEMCACHED_VERSION_STRING); php_info_print_table_row(2, "libmemcached-awesome library version", memcached_lib_version()); } else { php_info_print_table_row(2, "libmemcached-awesome version", memcached_lib_version()); } #else if (strcmp(LIBMEMCACHED_VERSION_STRING, memcached_lib_version())) { php_info_print_table_row(2, "libmemcached headers version", LIBMEMCACHED_VERSION_STRING); php_info_print_table_row(2, "libmemcached library version", memcached_lib_version()); } else { php_info_print_table_row(2, "libmemcached version", memcached_lib_version()); } #endif #ifdef HAVE_MEMCACHED_SASL php_info_print_table_row(2, "SASL support", "yes"); #else php_info_print_table_row(2, "SASL support", "no"); #endif #ifdef HAVE_MEMCACHED_SESSION php_info_print_table_row(2, "Session support", "yes"); #else php_info_print_table_row(2, "Session support ", "no"); #endif #ifdef HAVE_MEMCACHED_IGBINARY php_info_print_table_row(2, "igbinary support", "yes"); #else php_info_print_table_row(2, "igbinary support", "no"); #endif #ifdef HAVE_JSON_API php_info_print_table_row(2, "json support", "yes"); #else php_info_print_table_row(2, "json support", "no"); #endif #ifdef HAVE_MEMCACHED_MSGPACK php_info_print_table_row(2, "msgpack support", "yes"); #else php_info_print_table_row(2, "msgpack support", "no"); #endif #ifdef HAVE_ZSTD_H php_info_print_table_row(2, "zstd support", "yes"); #else php_info_print_table_row(2, "zstd support", "no"); #endif php_info_print_table_end(); DISPLAY_INI_ENTRIES(); } /* }}} */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim: noet sw=4 ts=4 fdm=marker: */ memcached-3.3.0/php_memcached.h0000644000076500000240000000352614704245235015175 0ustar mikestaff/* +----------------------------------------------------------------------+ | Copyright (c) 2009 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.0 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_0.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Andrei Zmievski | +----------------------------------------------------------------------+ */ #ifndef PHP_MEMCACHED_H #define PHP_MEMCACHED_H #include "php.h" #include "Zend/zend_smart_str.h" #ifdef PHP_WIN32 #include "main/config.w32.h" #else #include "main/php_config.h" #endif #ifdef HAVE_CONFIG_H # include "config.h" #endif #define PHP_MEMCACHED_VERSION "3.3.0" #if defined(PHP_WIN32) && defined(MEMCACHED_EXPORTS) #define PHP_MEMCACHED_API __declspec(dllexport) #else #define PHP_MEMCACHED_API PHPAPI #endif PHP_MEMCACHED_API zend_class_entry *php_memc_get_ce(void); PHP_MEMCACHED_API zend_class_entry *php_memc_get_exception(void); PHP_MEMCACHED_API zend_class_entry *php_memc_get_exception_base(int root); extern zend_module_entry memcached_module_entry; #define phpext_memcached_ptr &memcached_module_entry #endif /* PHP_MEMCACHED_H */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ memcached-3.3.0/php_memcached.stub.php0000644000076500000240000001117614704245235016511 0ustar mikestaff= 80200) #if defined(HAVE_MEMCACHED_SASL) zend_add_parameter_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "setsaslauthdata", sizeof("setsaslauthdata") - 1), 1, ZSTR_KNOWN(ZEND_STR_SENSITIVEPARAMETER), 0); #endif #endif return class_entry; } #if defined(HAVE_MEMCACHED_PROTOCOL) static zend_class_entry *register_class_MemcachedServer(void) { zend_class_entry ce, *class_entry; INIT_CLASS_ENTRY(ce, "MemcachedServer", class_MemcachedServer_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); return class_entry; } #endif memcached-3.3.0/php_memcached_legacy_arginfo.h0000644000076500000240000004014314704245235020222 0ustar mikestaff/* This is a generated file, edit the .stub.php file instead. * Stub hash: 75604abd7f58655a9ebda6f0ea579840311c1f08 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached___construct, 0, 0, 0) ZEND_ARG_INFO(0, persistent_id) ZEND_ARG_INFO(0, callback) ZEND_ARG_INFO(0, connection_str) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_getResultCode, 0, 0, 0) ZEND_END_ARG_INFO() #define arginfo_class_Memcached_getResultMessage arginfo_class_Memcached_getResultCode ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_get, 0, 0, 1) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, cache_cb) ZEND_ARG_INFO(0, get_flags) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_getByKey, 0, 0, 2) ZEND_ARG_INFO(0, server_key) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, cache_cb) ZEND_ARG_INFO(0, get_flags) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_getMulti, 0, 0, 1) ZEND_ARG_INFO(0, keys) ZEND_ARG_INFO(0, get_flags) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_getMultiByKey, 0, 0, 2) ZEND_ARG_INFO(0, server_key) ZEND_ARG_INFO(0, keys) ZEND_ARG_INFO(0, get_flags) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_getDelayed, 0, 0, 1) ZEND_ARG_INFO(0, keys) ZEND_ARG_INFO(0, with_cas) ZEND_ARG_INFO(0, value_cb) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_getDelayedByKey, 0, 0, 2) ZEND_ARG_INFO(0, server_key) ZEND_ARG_INFO(0, keys) ZEND_ARG_INFO(0, with_cas) ZEND_ARG_INFO(0, value_cb) ZEND_END_ARG_INFO() #define arginfo_class_Memcached_fetch arginfo_class_Memcached_getResultCode #define arginfo_class_Memcached_fetchAll arginfo_class_Memcached_getResultCode ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_set, 0, 0, 2) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, value) ZEND_ARG_INFO(0, expiration) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_setByKey, 0, 0, 3) ZEND_ARG_INFO(0, server_key) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, value) ZEND_ARG_INFO(0, expiration) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_touch, 0, 0, 1) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, expiration) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_touchByKey, 0, 0, 2) ZEND_ARG_INFO(0, server_key) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, expiration) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_setMulti, 0, 0, 1) ZEND_ARG_INFO(0, items) ZEND_ARG_INFO(0, expiration) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_setMultiByKey, 0, 0, 2) ZEND_ARG_INFO(0, server_key) ZEND_ARG_INFO(0, items) ZEND_ARG_INFO(0, expiration) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_cas, 0, 0, 3) ZEND_ARG_INFO(0, cas_token) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, value) ZEND_ARG_INFO(0, expiration) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_casByKey, 0, 0, 4) ZEND_ARG_INFO(0, cas_token) ZEND_ARG_INFO(0, server_key) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, value) ZEND_ARG_INFO(0, expiration) ZEND_END_ARG_INFO() #define arginfo_class_Memcached_add arginfo_class_Memcached_set #define arginfo_class_Memcached_addByKey arginfo_class_Memcached_setByKey ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_append, 0, 0, 2) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_appendByKey, 0, 0, 3) ZEND_ARG_INFO(0, server_key) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO() #define arginfo_class_Memcached_prepend arginfo_class_Memcached_append #define arginfo_class_Memcached_prependByKey arginfo_class_Memcached_appendByKey #define arginfo_class_Memcached_replace arginfo_class_Memcached_set #define arginfo_class_Memcached_replaceByKey arginfo_class_Memcached_setByKey ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_delete, 0, 0, 1) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, time) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_deleteMulti, 0, 0, 1) ZEND_ARG_INFO(0, keys) ZEND_ARG_INFO(0, time) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_deleteByKey, 0, 0, 2) ZEND_ARG_INFO(0, server_key) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, time) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_deleteMultiByKey, 0, 0, 2) ZEND_ARG_INFO(0, server_key) ZEND_ARG_INFO(0, keys) ZEND_ARG_INFO(0, time) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_increment, 0, 0, 1) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, offset) ZEND_ARG_INFO(0, initial_value) ZEND_ARG_INFO(0, expiry) ZEND_END_ARG_INFO() #define arginfo_class_Memcached_decrement arginfo_class_Memcached_increment ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_incrementByKey, 0, 0, 2) ZEND_ARG_INFO(0, server_key) ZEND_ARG_INFO(0, key) ZEND_ARG_INFO(0, offset) ZEND_ARG_INFO(0, initial_value) ZEND_ARG_INFO(0, expiry) ZEND_END_ARG_INFO() #define arginfo_class_Memcached_decrementByKey arginfo_class_Memcached_incrementByKey ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_addServer, 0, 0, 2) ZEND_ARG_INFO(0, host) ZEND_ARG_INFO(0, port) ZEND_ARG_INFO(0, weight) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_addServers, 0, 0, 1) ZEND_ARG_INFO(0, servers) ZEND_END_ARG_INFO() #define arginfo_class_Memcached_getServerList arginfo_class_Memcached_getResultCode ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_getServerByKey, 0, 0, 1) ZEND_ARG_INFO(0, server_key) ZEND_END_ARG_INFO() #define arginfo_class_Memcached_resetServerList arginfo_class_Memcached_getResultCode #define arginfo_class_Memcached_quit arginfo_class_Memcached_getResultCode #define arginfo_class_Memcached_flushBuffers arginfo_class_Memcached_getResultCode #define arginfo_class_Memcached_getLastErrorMessage arginfo_class_Memcached_getResultCode #define arginfo_class_Memcached_getLastErrorCode arginfo_class_Memcached_getResultCode #define arginfo_class_Memcached_getLastErrorErrno arginfo_class_Memcached_getResultCode #define arginfo_class_Memcached_getLastDisconnectedServer arginfo_class_Memcached_getResultCode ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_getStats, 0, 0, 0) ZEND_ARG_INFO(0, type) ZEND_END_ARG_INFO() #define arginfo_class_Memcached_getVersion arginfo_class_Memcached_getResultCode #define arginfo_class_Memcached_getAllKeys arginfo_class_Memcached_getResultCode ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_flush, 0, 0, 0) ZEND_ARG_INFO(0, delay) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_getOption, 0, 0, 1) ZEND_ARG_INFO(0, option) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_setOption, 0, 0, 2) ZEND_ARG_INFO(0, option) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_setOptions, 0, 0, 1) ZEND_ARG_INFO(0, options) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_setBucket, 0, 0, 3) ZEND_ARG_INFO(0, host_map) ZEND_ARG_INFO(0, forward_map) ZEND_ARG_INFO(0, replicas) ZEND_END_ARG_INFO() #if defined(HAVE_MEMCACHED_SASL) ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_setSaslAuthData, 0, 0, 2) ZEND_ARG_INFO(0, username) ZEND_ARG_INFO(0, password) ZEND_END_ARG_INFO() #endif #if defined(HAVE_MEMCACHED_SET_ENCODING_KEY) ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_setEncodingKey, 0, 0, 1) ZEND_ARG_INFO(0, key) ZEND_END_ARG_INFO() #endif #define arginfo_class_Memcached_isPersistent arginfo_class_Memcached_getResultCode #define arginfo_class_Memcached_isPristine arginfo_class_Memcached_getResultCode ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Memcached_checkKey, 0, 0, 1) ZEND_ARG_INFO(0, key) ZEND_END_ARG_INFO() #if defined(HAVE_MEMCACHED_PROTOCOL) ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MemcachedServer_run, 0, 0, 1) ZEND_ARG_INFO(0, address) ZEND_END_ARG_INFO() #endif #if defined(HAVE_MEMCACHED_PROTOCOL) ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MemcachedServer_on, 0, 0, 2) ZEND_ARG_INFO(0, event) ZEND_ARG_INFO(0, callback) ZEND_END_ARG_INFO() #endif ZEND_METHOD(Memcached, __construct); ZEND_METHOD(Memcached, getResultCode); ZEND_METHOD(Memcached, getResultMessage); ZEND_METHOD(Memcached, get); ZEND_METHOD(Memcached, getByKey); ZEND_METHOD(Memcached, getMulti); ZEND_METHOD(Memcached, getMultiByKey); ZEND_METHOD(Memcached, getDelayed); ZEND_METHOD(Memcached, getDelayedByKey); ZEND_METHOD(Memcached, fetch); ZEND_METHOD(Memcached, fetchAll); ZEND_METHOD(Memcached, set); ZEND_METHOD(Memcached, setByKey); ZEND_METHOD(Memcached, touch); ZEND_METHOD(Memcached, touchByKey); ZEND_METHOD(Memcached, setMulti); ZEND_METHOD(Memcached, setMultiByKey); ZEND_METHOD(Memcached, cas); ZEND_METHOD(Memcached, casByKey); ZEND_METHOD(Memcached, add); ZEND_METHOD(Memcached, addByKey); ZEND_METHOD(Memcached, append); ZEND_METHOD(Memcached, appendByKey); ZEND_METHOD(Memcached, prepend); ZEND_METHOD(Memcached, prependByKey); ZEND_METHOD(Memcached, replace); ZEND_METHOD(Memcached, replaceByKey); ZEND_METHOD(Memcached, delete); ZEND_METHOD(Memcached, deleteMulti); ZEND_METHOD(Memcached, deleteByKey); ZEND_METHOD(Memcached, deleteMultiByKey); ZEND_METHOD(Memcached, increment); ZEND_METHOD(Memcached, decrement); ZEND_METHOD(Memcached, incrementByKey); ZEND_METHOD(Memcached, decrementByKey); ZEND_METHOD(Memcached, addServer); ZEND_METHOD(Memcached, addServers); ZEND_METHOD(Memcached, getServerList); ZEND_METHOD(Memcached, getServerByKey); ZEND_METHOD(Memcached, resetServerList); ZEND_METHOD(Memcached, quit); ZEND_METHOD(Memcached, flushBuffers); ZEND_METHOD(Memcached, getLastErrorMessage); ZEND_METHOD(Memcached, getLastErrorCode); ZEND_METHOD(Memcached, getLastErrorErrno); ZEND_METHOD(Memcached, getLastDisconnectedServer); ZEND_METHOD(Memcached, getStats); ZEND_METHOD(Memcached, getVersion); ZEND_METHOD(Memcached, getAllKeys); ZEND_METHOD(Memcached, flush); ZEND_METHOD(Memcached, getOption); ZEND_METHOD(Memcached, setOption); ZEND_METHOD(Memcached, setOptions); ZEND_METHOD(Memcached, setBucket); #if defined(HAVE_MEMCACHED_SASL) ZEND_METHOD(Memcached, setSaslAuthData); #endif #if defined(HAVE_MEMCACHED_SET_ENCODING_KEY) ZEND_METHOD(Memcached, setEncodingKey); #endif ZEND_METHOD(Memcached, isPersistent); ZEND_METHOD(Memcached, isPristine); ZEND_METHOD(Memcached, checkKey); #if defined(HAVE_MEMCACHED_PROTOCOL) ZEND_METHOD(MemcachedServer, run); #endif #if defined(HAVE_MEMCACHED_PROTOCOL) ZEND_METHOD(MemcachedServer, on); #endif static const zend_function_entry class_Memcached_methods[] = { ZEND_ME(Memcached, __construct, arginfo_class_Memcached___construct, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, getResultCode, arginfo_class_Memcached_getResultCode, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, getResultMessage, arginfo_class_Memcached_getResultMessage, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, get, arginfo_class_Memcached_get, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, getByKey, arginfo_class_Memcached_getByKey, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, getMulti, arginfo_class_Memcached_getMulti, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, getMultiByKey, arginfo_class_Memcached_getMultiByKey, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, getDelayed, arginfo_class_Memcached_getDelayed, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, getDelayedByKey, arginfo_class_Memcached_getDelayedByKey, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, fetch, arginfo_class_Memcached_fetch, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, fetchAll, arginfo_class_Memcached_fetchAll, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, set, arginfo_class_Memcached_set, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, setByKey, arginfo_class_Memcached_setByKey, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, touch, arginfo_class_Memcached_touch, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, touchByKey, arginfo_class_Memcached_touchByKey, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, setMulti, arginfo_class_Memcached_setMulti, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, setMultiByKey, arginfo_class_Memcached_setMultiByKey, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, cas, arginfo_class_Memcached_cas, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, casByKey, arginfo_class_Memcached_casByKey, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, add, arginfo_class_Memcached_add, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, addByKey, arginfo_class_Memcached_addByKey, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, append, arginfo_class_Memcached_append, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, appendByKey, arginfo_class_Memcached_appendByKey, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, prepend, arginfo_class_Memcached_prepend, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, prependByKey, arginfo_class_Memcached_prependByKey, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, replace, arginfo_class_Memcached_replace, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, replaceByKey, arginfo_class_Memcached_replaceByKey, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, delete, arginfo_class_Memcached_delete, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, deleteMulti, arginfo_class_Memcached_deleteMulti, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, deleteByKey, arginfo_class_Memcached_deleteByKey, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, deleteMultiByKey, arginfo_class_Memcached_deleteMultiByKey, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, increment, arginfo_class_Memcached_increment, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, decrement, arginfo_class_Memcached_decrement, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, incrementByKey, arginfo_class_Memcached_incrementByKey, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, decrementByKey, arginfo_class_Memcached_decrementByKey, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, addServer, arginfo_class_Memcached_addServer, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, addServers, arginfo_class_Memcached_addServers, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, getServerList, arginfo_class_Memcached_getServerList, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, getServerByKey, arginfo_class_Memcached_getServerByKey, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, resetServerList, arginfo_class_Memcached_resetServerList, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, quit, arginfo_class_Memcached_quit, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, flushBuffers, arginfo_class_Memcached_flushBuffers, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, getLastErrorMessage, arginfo_class_Memcached_getLastErrorMessage, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, getLastErrorCode, arginfo_class_Memcached_getLastErrorCode, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, getLastErrorErrno, arginfo_class_Memcached_getLastErrorErrno, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, getLastDisconnectedServer, arginfo_class_Memcached_getLastDisconnectedServer, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, getStats, arginfo_class_Memcached_getStats, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, getVersion, arginfo_class_Memcached_getVersion, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, getAllKeys, arginfo_class_Memcached_getAllKeys, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, flush, arginfo_class_Memcached_flush, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, getOption, arginfo_class_Memcached_getOption, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, setOption, arginfo_class_Memcached_setOption, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, setOptions, arginfo_class_Memcached_setOptions, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, setBucket, arginfo_class_Memcached_setBucket, ZEND_ACC_PUBLIC) #if defined(HAVE_MEMCACHED_SASL) ZEND_ME(Memcached, setSaslAuthData, arginfo_class_Memcached_setSaslAuthData, ZEND_ACC_PUBLIC) #endif #if defined(HAVE_MEMCACHED_SET_ENCODING_KEY) ZEND_ME(Memcached, setEncodingKey, arginfo_class_Memcached_setEncodingKey, ZEND_ACC_PUBLIC) #endif ZEND_ME(Memcached, isPersistent, arginfo_class_Memcached_isPersistent, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, isPristine, arginfo_class_Memcached_isPristine, ZEND_ACC_PUBLIC) ZEND_ME(Memcached, checkKey, arginfo_class_Memcached_checkKey, ZEND_ACC_PUBLIC) ZEND_FE_END }; #if defined(HAVE_MEMCACHED_PROTOCOL) static const zend_function_entry class_MemcachedServer_methods[] = { ZEND_ME(MemcachedServer, run, arginfo_class_MemcachedServer_run, ZEND_ACC_PUBLIC) ZEND_ME(MemcachedServer, on, arginfo_class_MemcachedServer_on, ZEND_ACC_PUBLIC) ZEND_FE_END }; #endif static zend_class_entry *register_class_Memcached(void) { zend_class_entry ce, *class_entry; INIT_CLASS_ENTRY(ce, "Memcached", class_Memcached_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); return class_entry; } #if defined(HAVE_MEMCACHED_PROTOCOL) static zend_class_entry *register_class_MemcachedServer(void) { zend_class_entry ce, *class_entry; INIT_CLASS_ENTRY(ce, "MemcachedServer", class_MemcachedServer_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); return class_entry; } #endif memcached-3.3.0/php_memcached_private.h0000644000076500000240000001515614704245235016731 0ustar mikestaff/* +----------------------------------------------------------------------+ | Copyright (c) 2009 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.0 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_0.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Andrei Zmievski | +----------------------------------------------------------------------+ */ #ifndef PHP_MEMCACHED_PRIVATE_H #define PHP_MEMCACHED_PRIVATE_H #ifdef PHP_WIN32 #include "main/config.w32.h" #else #include "main/php_config.h" #endif #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "php_libmemcached_compat.h" #include #include #include #include #ifdef ZTS # include "TSRM.h" #endif #include #include #include #include #include #include #include #include #ifdef PHP_WIN32 # if PHP_VERSION_ID >= 80000 # include #else # include "win32/php_stdint.h" #endif #else /* Used to store the size of the block */ # if defined(HAVE_INTTYPES_H) # include # elif defined(HAVE_STDINT_H) # include # endif #endif #ifndef HAVE_INT32_T # if SIZEOF_INT == 4 typedef int int32_t; # elif SIZEOF_LONG == 4 typedef long int int32_t; # endif #endif #ifndef HAVE_UINT32_T # if SIZEOF_INT == 4 typedef unsigned int uint32_t; # elif SIZEOF_LONG == 4 typedef unsigned long int uint32_t; # endif #endif /* Backwards compatibility for GC API change in PHP 7.3 */ #if PHP_VERSION_ID < 70300 # define GC_ADDREF(p) ++GC_REFCOUNT(p) # define GC_DELREF(p) --GC_REFCOUNT(p) # define GC_SET_REFCOUNT(p, rc) GC_REFCOUNT(p) = rc #endif /**************************************** Structures and definitions ****************************************/ typedef enum { SERIALIZER_PHP = 1, SERIALIZER_IGBINARY = 2, SERIALIZER_JSON = 3, SERIALIZER_JSON_ARRAY = 4, SERIALIZER_MSGPACK = 5 } php_memc_serializer_type; typedef enum { COMPRESSION_TYPE_ZLIB = 1, COMPRESSION_TYPE_FASTLZ = 2, COMPRESSION_TYPE_ZSTD = 3 } php_memc_compression_type; typedef struct { const char *name; php_memc_serializer_type type; } php_memc_serializer; #if defined(HAVE_MEMCACHED_IGBINARY) # define SERIALIZER_DEFAULT SERIALIZER_IGBINARY # define SERIALIZER_DEFAULT_NAME "igbinary" #elif defined(HAVE_MEMCACHED_MSGPACK) # define SERIALIZER_DEFAULT SERIALIZER_MSGPACK # define SERIALIZER_DEFAULT_NAME "msgpack" #else # define SERIALIZER_DEFAULT SERIALIZER_PHP # define SERIALIZER_DEFAULT_NAME "php" #endif /* HAVE_MEMCACHED_IGBINARY / HAVE_MEMCACHED_MSGPACK */ #ifdef HAVE_MEMCACHED_SASL # include #endif #ifdef HAVE_MEMCACHED_PROTOCOL typedef enum { MEMC_SERVER_ON_MIN = -1, MEMC_SERVER_ON_CONNECT = 0, MEMC_SERVER_ON_ADD = 1, MEMC_SERVER_ON_APPEND = 2, MEMC_SERVER_ON_DECREMENT = 3, MEMC_SERVER_ON_DELETE = 4, MEMC_SERVER_ON_FLUSH = 5, MEMC_SERVER_ON_GET = 6, MEMC_SERVER_ON_INCREMENT = 7, MEMC_SERVER_ON_NOOP = 8, MEMC_SERVER_ON_PREPEND = 9, MEMC_SERVER_ON_QUIT = 10, MEMC_SERVER_ON_REPLACE = 11, MEMC_SERVER_ON_SET = 12, MEMC_SERVER_ON_STAT = 13, MEMC_SERVER_ON_VERSION = 14, MEMC_SERVER_ON_MAX } php_memc_event_t; typedef struct { zend_fcall_info fci; zend_fcall_info_cache fci_cache; } php_memc_server_cb_t; #endif ZEND_BEGIN_MODULE_GLOBALS(php_memcached) #ifdef HAVE_MEMCACHED_SESSION /* Session related variables */ struct { zend_bool lock_enabled; zend_long lock_wait_max; zend_long lock_wait_min; zend_long lock_retries; zend_long lock_expiration; zend_bool binary_protocol_enabled; zend_bool consistent_hash_enabled; char *consistent_hash_name; int consistent_hash_type; zend_long server_failure_limit; zend_long number_of_replicas; zend_bool randomize_replica_read_enabled; zend_bool remove_failed_servers_enabled; zend_long connect_timeout; char *prefix; zend_bool persistent_enabled; char *sasl_username; char *sasl_password; } session; #endif struct { char *serializer_name; char *compression_name; zend_long compression_threshold; double compression_factor; zend_long store_retry_count; zend_long compression_level; zend_long item_size_limit; /* Converted values*/ php_memc_serializer_type serializer_type; php_memc_compression_type compression_type; /* Whether we have initialised sasl for this process */ zend_bool sasl_initialised; struct { zend_bool consistent_hash_enabled; zend_bool binary_protocol_enabled; zend_long connect_timeout; } default_behavior; } memc; /* For deprecated values */ zend_long no_effect; #ifdef HAVE_MEMCACHED_PROTOCOL struct { php_memc_server_cb_t callbacks [MEMC_SERVER_ON_MAX]; } server; #endif ZEND_END_MODULE_GLOBALS(php_memcached) /* Globals accessor macros */ #ifdef ZTS # define MEMC_G(v) TSRMG(php_memcached_globals_id, zend_php_memcached_globals *, memc.v) # define MEMC_SERVER_G(v) TSRMG(php_memcached_globals_id, zend_php_memcached_globals *, server.v) # define MEMC_SESS_INI(v) TSRMG(php_memcached_globals_id, zend_php_memcached_globals *, session.v) #else # define MEMC_G(v) (php_memcached_globals.memc.v) # define MEMC_SERVER_G(v) (php_memcached_globals.server.v) # define MEMC_SESS_INI(v) (php_memcached_globals.session.v) #endif #define MEMC_SESS_STR_INI(vv) ((MEMC_SESS_INI(vv) && *MEMC_SESS_INI(vv)) ? MEMC_SESS_INI(vv) : NULL) PHP_RINIT_FUNCTION(memcached); PHP_RSHUTDOWN_FUNCTION(memcached); PHP_MINIT_FUNCTION(memcached); PHP_MSHUTDOWN_FUNCTION(memcached); PHP_MINFO_FUNCTION(memcached); char *php_memc_printable_func (zend_fcall_info *fci, zend_fcall_info_cache *fci_cache); memcached_return php_memcached_exist (memcached_st *memc, zend_string *key); zend_bool php_memc_init_sasl_if_needed(); #endif /* PHP_MEMCACHED_PRIVATE_H */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ memcached-3.3.0/php_memcached_session.c0000644000076500000240000003420414704245235016730 0ustar mikestaff/* +----------------------------------------------------------------------+ | Copyright (c) 2009-2010 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Andrei Zmievski | +----------------------------------------------------------------------+ */ #include "php_memcached.h" #include "php_memcached_private.h" #include "php_memcached_session.h" #include "Zend/zend_smart_str_public.h" extern ZEND_DECLARE_MODULE_GLOBALS(php_memcached) #define REALTIME_MAXDELTA 60*60*24*30 ps_module ps_mod_memcached = { PS_MOD_UPDATE_TIMESTAMP(memcached) }; typedef struct { zend_bool is_persistent; zend_bool has_sasl_data; zend_bool is_locked; zend_string *lock_key; } php_memcached_user_data; #ifndef MIN # define MIN(a,b) (((a)<(b))?(a):(b)) #endif #ifndef MAX # define MAX(a,b) (((a)>(b))?(a):(b)) #endif static int le_memc_sess; static int s_memc_sess_list_entry(void) { return le_memc_sess; } static void s_destroy_mod_data(memcached_st *memc) { php_memcached_user_data *user_data = memcached_get_user_data(memc); #ifdef HAVE_MEMCACHED_SASL if (user_data->has_sasl_data) { memcached_destroy_sasl_auth_data(memc); } #endif memcached_free(memc); pefree(memc, user_data->is_persistent); pefree(user_data, user_data->is_persistent); } ZEND_RSRC_DTOR_FUNC(php_memc_sess_dtor) { if (res->ptr) { s_destroy_mod_data((memcached_st *) res->ptr); res->ptr = NULL; } } int php_memc_session_minit(int module_number) { le_memc_sess = zend_register_list_destructors_ex(NULL, php_memc_sess_dtor, "Memcached Sessions persistent connection", module_number); php_session_register_module(ps_memcached_ptr); return SUCCESS; } static time_t s_adjust_expiration(zend_long expiration) { if (expiration <= REALTIME_MAXDELTA) { return expiration; } else { return time(NULL) + expiration; } } static time_t s_lock_expiration() { if (MEMC_SESS_INI(lock_expiration) > 0) { return s_adjust_expiration(MEMC_SESS_INI(lock_expiration)); } else { zend_long max_execution_time = zend_ini_long(ZEND_STRL("max_execution_time"), 0); if (max_execution_time > 0) { return s_adjust_expiration(max_execution_time); } } return 0; } static time_t s_session_expiration(zend_long maxlifetime) { if (maxlifetime > 0) { return s_adjust_expiration(maxlifetime); } return 0; } static zend_bool s_lock_session(memcached_st *memc, zend_string *sid) { memcached_return rc; char *lock_key; size_t lock_key_len; time_t expiration; zend_long wait_time, retries; php_memcached_user_data *user_data = memcached_get_user_data(memc); lock_key_len = spprintf(&lock_key, 0, "lock.%s", sid->val); expiration = s_lock_expiration(); wait_time = MEMC_SESS_INI(lock_wait_min); retries = MEMC_SESS_INI(lock_retries); do { rc = memcached_add(memc, lock_key, lock_key_len, "1", sizeof ("1") - 1, expiration, 0); switch (rc) { case MEMCACHED_SUCCESS: user_data->lock_key = zend_string_init(lock_key, lock_key_len, user_data->is_persistent); user_data->is_locked = 1; break; case MEMCACHED_NOTSTORED: case MEMCACHED_DATA_EXISTS: if (retries > 0) { usleep(wait_time * 1000); wait_time = MIN(MEMC_SESS_INI(lock_wait_max), wait_time * 2); } break; default: php_error_docref(NULL, E_WARNING, "Failed to write session lock: %s", memcached_strerror (memc, rc)); break; } } while (!user_data->is_locked && retries-- > 0); efree(lock_key); return user_data->is_locked; } static void s_unlock_session(memcached_st *memc) { php_memcached_user_data *user_data = memcached_get_user_data(memc); if (user_data->is_locked) { memcached_delete(memc, user_data->lock_key->val, user_data->lock_key->len, 0); user_data->is_locked = 0; zend_string_release (user_data->lock_key); } } static zend_bool s_configure_from_ini_values(memcached_st *memc, zend_bool silent) { /* This macro looks like a function but returns errors directly */ #define check_set_behavior(behavior, value) \ { \ int b = (behavior); \ uint64_t v = (value); \ if (v != memcached_behavior_get(memc, b)) { \ memcached_return rc; \ if ((rc = memcached_behavior_set(memc, b, v)) != MEMCACHED_SUCCESS) { \ if (!silent) { \ php_error_docref(NULL, E_WARNING, "failed to initialise session memcached configuration: %s", memcached_strerror(memc, rc)); \ } \ return 0; \ } \ } \ } if (MEMC_SESS_INI(binary_protocol_enabled)) { check_set_behavior(MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1); /* Also enable TCP_NODELAY when binary protocol is enabled */ check_set_behavior(MEMCACHED_BEHAVIOR_TCP_NODELAY, 1); } if (MEMC_SESS_INI(consistent_hash_enabled)) { check_set_behavior(MEMC_SESS_INI(consistent_hash_type), 1); } if (MEMC_SESS_INI(server_failure_limit)) { check_set_behavior(MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT, MEMC_SESS_INI(server_failure_limit)); } if (MEMC_SESS_INI(number_of_replicas)) { check_set_behavior(MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, MEMC_SESS_INI(number_of_replicas)); } if (MEMC_SESS_INI(randomize_replica_read_enabled)) { check_set_behavior(MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ, 1); } if (MEMC_SESS_INI(remove_failed_servers_enabled)) { check_set_behavior(MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS, 1); } if (MEMC_SESS_INI(connect_timeout)) { check_set_behavior(MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT, MEMC_SESS_INI(connect_timeout)); } if (MEMC_SESS_STR_INI(prefix)) { memcached_callback_set(memc, MEMCACHED_CALLBACK_NAMESPACE, MEMC_SESS_STR_INI(prefix)); } if (MEMC_SESS_STR_INI(sasl_username) && MEMC_SESS_STR_INI(sasl_password)) { php_memcached_user_data *user_data; if (!php_memc_init_sasl_if_needed()) { return 0; } check_set_behavior(MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1); if (memcached_set_sasl_auth_data(memc, MEMC_SESS_STR_INI(sasl_username), MEMC_SESS_STR_INI(sasl_password)) == MEMCACHED_FAILURE) { php_error_docref(NULL, E_WARNING, "failed to set memcached session sasl credentials"); return 0; } user_data = memcached_get_user_data(memc); user_data->has_sasl_data = 1; } #undef check_set_behavior return 1; } static void *s_pemalloc_fn(const memcached_st *memc, size_t size, void *context) { zend_bool *is_persistent = memcached_get_user_data(memc); return pemalloc(size, *is_persistent); } static void s_pefree_fn(const memcached_st *memc, void *mem, void *context) { zend_bool *is_persistent = memcached_get_user_data(memc); return pefree(mem, *is_persistent); } static void *s_perealloc_fn(const memcached_st *memc, void *mem, const size_t size, void *context) { zend_bool *is_persistent = memcached_get_user_data(memc); return perealloc(mem, size, *is_persistent); } static void *s_pecalloc_fn(const memcached_st *memc, size_t nelem, const size_t elsize, void *context) { zend_bool *is_persistent = memcached_get_user_data(memc); return pecalloc(nelem, elsize, *is_persistent); } static memcached_st *s_init_mod_data (const memcached_server_list_st servers, zend_bool is_persistent) { void *buffer; php_memcached_user_data *user_data; memcached_st *memc; buffer = pecalloc(1, sizeof(memcached_st), is_persistent); memc = memcached_create (buffer); if (!memc) { php_error_docref(NULL, E_ERROR, "failed to allocate memcached structure"); /* not reached */ } memcached_set_memory_allocators(memc, s_pemalloc_fn, s_pefree_fn, s_perealloc_fn, s_pecalloc_fn, NULL); user_data = pecalloc(1, sizeof(php_memcached_user_data), is_persistent); user_data->is_persistent = is_persistent; user_data->has_sasl_data = 0; user_data->lock_key = NULL; user_data->is_locked = 0; memcached_set_user_data(memc, user_data); memcached_server_push (memc, servers); memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_VERIFY_KEY, 1); return memc; } PS_OPEN_FUNC(memcached) { memcached_st *memc = NULL; char *plist_key = NULL; size_t plist_key_len = 0; memcached_server_list_st servers; // Fail on incompatible PERSISTENT identifier (removed in php-memcached 3.0) if (strstr(save_path, "PERSISTENT=")) { php_error_docref(NULL, E_WARNING, "failed to parse session.save_path: PERSISTENT is replaced by memcached.sess_persistent = On"); PS_SET_MOD_DATA(NULL); return FAILURE; } // First parse servers servers = memcached_servers_parse(save_path); if (!servers) { php_error_docref(NULL, E_WARNING, "failed to parse session.save_path"); PS_SET_MOD_DATA(NULL); return FAILURE; } if (MEMC_SESS_INI(persistent_enabled)) { zend_resource *le_p; plist_key_len = spprintf(&plist_key, 0, "memc-session:%s", save_path); if ((le_p = zend_hash_str_find_ptr(&EG(persistent_list), plist_key, plist_key_len)) != NULL) { if (le_p->type == s_memc_sess_list_entry()) { memc = (memcached_st *) le_p->ptr; if (!s_configure_from_ini_values(memc, 1)) { // Remove existing plist entry zend_hash_str_del(&EG(persistent_list), plist_key, plist_key_len); memc = NULL; } else { efree(plist_key); PS_SET_MOD_DATA(memc); memcached_server_list_free(servers); return SUCCESS; } } } } memc = s_init_mod_data(servers, MEMC_SESS_INI(persistent_enabled)); memcached_server_list_free(servers); if (!s_configure_from_ini_values(memc, 0)) { if (plist_key) { efree(plist_key); } s_destroy_mod_data(memc); PS_SET_MOD_DATA(NULL); return FAILURE; } if (plist_key) { zend_resource le; le.type = s_memc_sess_list_entry(); le.ptr = memc; GC_SET_REFCOUNT(&le, 1); /* plist_key is not a persistent allocated key, thus we use str_update here */ if (zend_hash_str_update_mem(&EG(persistent_list), plist_key, plist_key_len, &le, sizeof(le)) == NULL) { php_error_docref(NULL, E_ERROR, "Could not register persistent entry for the memcached session"); /* not reached */ } efree(plist_key); } PS_SET_MOD_DATA(memc); return SUCCESS; } PS_CLOSE_FUNC(memcached) { php_memcached_user_data *user_data; memcached_st *memc = PS_GET_MOD_DATA(); if (!memc) { php_error_docref(NULL, E_WARNING, "Session is not allocated, check session.save_path value"); return FAILURE; } user_data = memcached_get_user_data(memc); if (user_data->is_locked) { s_unlock_session(memc); } if (!user_data->is_persistent) { s_destroy_mod_data(memc); } PS_SET_MOD_DATA(NULL); return SUCCESS; } PS_READ_FUNC(memcached) { char *payload = NULL; size_t payload_len = 0; uint32_t flags = 0; memcached_return status; memcached_st *memc = PS_GET_MOD_DATA(); if (!memc) { php_error_docref(NULL, E_WARNING, "Session is not allocated, check session.save_path value"); return FAILURE; } if (MEMC_SESS_INI(lock_enabled)) { if (!s_lock_session(memc, key)) { php_error_docref(NULL, E_WARNING, "Unable to clear session lock record"); return FAILURE; } } payload = memcached_get(memc, key->val, key->len, &payload_len, &flags, &status); if (status == MEMCACHED_SUCCESS) { zend_bool *is_persistent = memcached_get_user_data(memc); *val = zend_string_init(payload, payload_len, 0); pefree(payload, *is_persistent); return SUCCESS; } else if (status == MEMCACHED_NOTFOUND) { *val = ZSTR_EMPTY_ALLOC(); return SUCCESS; } else { php_error_docref(NULL, E_WARNING, "error getting session from memcached: %s", memcached_last_error_message(memc)); return FAILURE; } } PS_WRITE_FUNC(memcached) { zend_long retries = 1; memcached_st *memc = PS_GET_MOD_DATA(); time_t expiration = s_session_expiration(maxlifetime); if (!memc) { php_error_docref(NULL, E_WARNING, "Session is not allocated, check session.save_path value"); return FAILURE; } /* Set the number of write retry attempts to the number of replicas times the number of attempts to remove a server plus the initial write */ if (MEMC_SESS_INI(remove_failed_servers_enabled)) { zend_long replicas, failure_limit; replicas = memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS); failure_limit = memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT); retries = 1 + replicas * (failure_limit + 1); } do { if (memcached_set(memc, key->val, key->len, val->val, val->len, expiration, 0) == MEMCACHED_SUCCESS) { return SUCCESS; } else { php_error_docref(NULL, E_WARNING, "error saving session to memcached: %s", memcached_last_error_message(memc)); } } while (--retries > 0); return FAILURE; } PS_DESTROY_FUNC(memcached) { php_memcached_user_data *user_data; memcached_st *memc = PS_GET_MOD_DATA(); if (!memc) { php_error_docref(NULL, E_WARNING, "Session is not allocated, check session.save_path value"); return FAILURE; } memcached_delete(memc, key->val, key->len, 0); user_data = memcached_get_user_data(memc); if (user_data->is_locked) { s_unlock_session(memc); } return SUCCESS; } PS_GC_FUNC(memcached) { return SUCCESS; } PS_CREATE_SID_FUNC(memcached) { zend_string *sid; memcached_st *memc = PS_GET_MOD_DATA(); if (!memc) { sid = php_session_create_id(NULL); } else { int retries = 3; while (retries-- > 0) { sid = php_session_create_id((void **) &memc); if (memcached_add (memc, sid->val, sid->len, NULL, 0, s_lock_expiration(), 0) == MEMCACHED_SUCCESS) { break; } zend_string_release(sid); sid = NULL; } } return sid; } PS_VALIDATE_SID_FUNC(memcached) { memcached_st *memc = PS_GET_MOD_DATA(); if (php_memcached_exist(memc, key) == MEMCACHED_SUCCESS) { return SUCCESS; } else { return FAILURE; } } PS_UPDATE_TIMESTAMP_FUNC(memcached) { memcached_st *memc = PS_GET_MOD_DATA(); time_t expiration = s_session_expiration(maxlifetime); if (php_memcached_touch(memc, key->val, key->len, expiration) == MEMCACHED_FAILURE) { return FAILURE; } return SUCCESS; } /* }}} */ memcached-3.3.0/php_memcached_session.h0000644000076500000240000000310714704245235016733 0ustar mikestaff/* +----------------------------------------------------------------------+ | Copyright (c) 2009-2010 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Andrei Zmievski | +----------------------------------------------------------------------+ */ #ifndef PHP_MEMCACHED_SESSION_H #define PHP_MEMCACHED_SESSION_H /* session handler struct */ #include "ext/session/php_session.h" extern ps_module ps_mod_memcached; #define ps_memcached_ptr &ps_mod_memcached PS_FUNCS_UPDATE_TIMESTAMP(memcached); PS_OPEN_FUNC(memcached); PS_CLOSE_FUNC(memcached); PS_READ_FUNC(memcached); PS_WRITE_FUNC(memcached); PS_DESTROY_FUNC(memcached); PS_GC_FUNC(memcached); PS_CREATE_SID_FUNC(memcached); PS_VALIDATE_SID_FUNC(memcached); PS_UPDATE_TIMESTAMP_FUNC(memcached); /* Called from php_memcached.c */ int php_memc_session_minit(int module_number); #endif /* PHP_MEMCACHED_SESSION_H */ memcached-3.3.0/php_libmemcached_compat.h0000644000076500000240000000325314704245235017224 0ustar mikestaff/* +----------------------------------------------------------------------+ | Copyright (c) 2009 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.0 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_0.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Andrei Zmievski | +----------------------------------------------------------------------+ */ #ifndef PHP_LIBMEMCACHED_COMPAT #define PHP_LIBMEMCACHED_COMPAT /* this is the version(s) we support */ #include memcached_return php_memcached_exist (memcached_st *memc, zend_string *key); memcached_return php_memcached_touch(memcached_st *memc, const char *key, size_t key_len, time_t expiration); memcached_return php_memcached_touch_by_key(memcached_st *memc, const char *server_key, size_t server_key_len, const char *key, size_t key_len, time_t expiration); #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x01000017 typedef const memcached_instance_st * php_memcached_instance_st; #else typedef memcached_server_instance_st php_memcached_instance_st; #endif #endif memcached-3.3.0/php_libmemcached_compat.c0000644000076500000240000000521614704245235017220 0ustar mikestaff/* +----------------------------------------------------------------------+ | Copyright (c) 2009 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.0 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_0.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Andrei Zmievski | +----------------------------------------------------------------------+ */ #include "php_memcached.h" #include "php_memcached_private.h" #include "php_libmemcached_compat.h" memcached_return php_memcached_exist(memcached_st *memc, zend_string *key) { #ifdef HAVE_MEMCACHED_EXIST return memcached_exist(memc, key->val, key->len); #else memcached_return rc = MEMCACHED_SUCCESS; uint32_t flags = 0; size_t value_length = 0; char *value = NULL; value = memcached_get(memc, key->val, key->len, &value_length, &flags, &rc); if (value) { zend_bool *is_persistent = memcached_get_user_data(memc); pefree(value, *is_persistent); } return rc; #endif } memcached_return php_memcached_touch(memcached_st *memc, const char *key, size_t key_len, time_t expiration) { #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x01000018 if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) { php_error_docref(NULL, E_WARNING, "using touch command with binary protocol is not recommended with libmemcached versions below 1.0.18, please use ascii protocol or upgrade libmemcached"); } #endif return memcached_touch(memc, key, key_len, expiration); } memcached_return php_memcached_touch_by_key(memcached_st *memc, const char *server_key, size_t server_key_len, const char *key, size_t key_len, time_t expiration) { #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x01000018 if (memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) { php_error_docref(NULL, E_WARNING, "using touch command with binary protocol is not recommended with libmemcached versions below 1.0.18, please use ascii protocol or upgrade libmemcached"); } #endif return memcached_touch_by_key(memc, server_key, server_key_len, key, key_len, expiration); } memcached-3.3.0/php_memcached_server.h0000644000076500000240000000270114704245235016555 0ustar mikestaff/* +----------------------------------------------------------------------+ | Copyright (c) 2009-2013 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Mikko Koppanen | +----------------------------------------------------------------------+ */ #ifndef _PHP_MEMCACHED_SERVER_H_ # define _PHP_MEMCACHED_SERVER_H_ #ifdef HAVE_MEMCACHED_PROTOCOL #include /* Opaque structure */ typedef struct _php_memc_proto_handler_t php_memc_proto_handler_t; /* Functions */ php_memc_proto_handler_t *php_memc_proto_handler_new (); void php_memc_proto_handler_destroy (php_memc_proto_handler_t **ptr); zend_bool php_memc_proto_handler_run (php_memc_proto_handler_t *h, zend_string *address); #endif #endif memcached-3.3.0/php_memcached_server.c0000644000076500000240000006103114704245235016551 0ustar mikestaff/* +----------------------------------------------------------------------+ | Copyright (c) 2009-2013 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Mikko Koppanen | +----------------------------------------------------------------------+ */ #include "php_memcached.h" #include "php_memcached_private.h" #include "php_memcached_server.h" #include "php_network.h" #include #include #define MEMC_GET_CB(cb_type) (MEMC_SERVER_G(callbacks)[cb_type]) #define MEMC_HAS_CB(cb_type) (MEMC_GET_CB(cb_type).fci.size > 0) #define MEMC_MAKE_ZVAL_COOKIE(my_zcookie, my_ptr) \ do { \ zend_string *cookie_buf; \ cookie_buf = strpprintf(0, "%p", my_ptr); \ ZVAL_STR(&my_zcookie, cookie_buf); \ } while (0) #define MEMC_MAKE_RESULT_CAS(my_zresult_cas, my_result_cas) \ do { \ my_result_cas = 0; \ my_result_cas = zval_get_double(&my_zresult_cas); \ } while (0) ZEND_EXTERN_MODULE_GLOBALS(php_memcached) struct _php_memc_proto_handler_t { memcached_binary_protocol_callback_st callbacks; struct memcached_protocol_st *protocol_handle; struct event_base *event_base; }; typedef struct { struct memcached_protocol_client_st *protocol_client; struct event_base *event_base; zend_bool on_connect_invoked; } php_memc_client_t; static long s_invoke_php_callback (php_memc_server_cb_t *cb, zval *params, ssize_t param_count) { zval retval; cb->fci.retval = &retval; cb->fci.params = params; cb->fci.param_count = param_count; #if PHP_VERSION_ID < 80000 cb->fci.no_separation = 1; #endif if (zend_call_function(&(cb->fci), &(cb->fci_cache)) == FAILURE) { char *buf = php_memc_printable_func(&(cb->fci), &(cb->fci_cache)); php_error_docref(NULL, E_WARNING, "Failed to invoke callback %s()", buf); efree (buf); } return Z_ISUNDEF(retval) ? PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND : zval_get_long(&retval); } // memcached protocol callbacks static protocol_binary_response_status s_add_handler(const void *cookie, const void *key, uint16_t key_len, const void *data, uint32_t data_len, uint32_t flags, uint32_t exptime, uint64_t *result_cas) { protocol_binary_response_status retval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND; zval zcookie, zkey, zvalue, zflags, zexptime, zresult_cas; zval params[6]; if (!MEMC_HAS_CB(MEMC_SERVER_ON_ADD)) { return retval; } MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); ZVAL_STRINGL(&zkey, key, key_len); ZVAL_STRINGL(&zvalue, data, data_len); ZVAL_LONG(&zflags, flags); ZVAL_LONG(&zexptime, exptime); ZVAL_NULL(&zresult_cas); ZVAL_MAKE_REF(&zresult_cas); ZVAL_COPY(¶ms[0], &zcookie); ZVAL_COPY(¶ms[1], &zkey); ZVAL_COPY(¶ms[2], &zvalue); ZVAL_COPY(¶ms[3], &zflags); ZVAL_COPY(¶ms[4], &zexptime); ZVAL_COPY(¶ms[5], &zresult_cas); retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_ADD), params, 6); MEMC_MAKE_RESULT_CAS(zresult_cas, *result_cas); zval_ptr_dtor(¶ms[0]); zval_ptr_dtor(¶ms[1]); zval_ptr_dtor(¶ms[2]); zval_ptr_dtor(¶ms[3]); zval_ptr_dtor(¶ms[4]); zval_ptr_dtor(¶ms[5]); zval_ptr_dtor (&zcookie); zval_ptr_dtor (&zkey); zval_ptr_dtor (&zvalue); zval_ptr_dtor (&zflags); zval_ptr_dtor (&zexptime); zval_ptr_dtor (&zresult_cas); return retval; } static protocol_binary_response_status s_append_prepend_handler (php_memc_event_t event, const void *cookie, const void *key, uint16_t key_len, const void *data, uint32_t data_len, uint64_t cas, uint64_t *result_cas) { protocol_binary_response_status retval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND; zval zcookie, zkey, zvalue, zcas, zresult_cas; zval params[5]; if (!MEMC_HAS_CB(event)) { return retval; } MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); ZVAL_STRINGL(&zkey, key, key_len); ZVAL_STRINGL(&zvalue, data, data_len); ZVAL_DOUBLE(&zcas, cas); ZVAL_NULL(&zresult_cas); ZVAL_MAKE_REF(&zresult_cas); ZVAL_COPY(¶ms[0], &zcookie); ZVAL_COPY(¶ms[1], &zkey); ZVAL_COPY(¶ms[2], &zvalue); ZVAL_COPY(¶ms[3], &zcas); ZVAL_COPY(¶ms[4], &zresult_cas); retval = s_invoke_php_callback (&MEMC_GET_CB(event), params, 5); MEMC_MAKE_RESULT_CAS(zresult_cas, *result_cas); zval_ptr_dtor(¶ms[0]); zval_ptr_dtor(¶ms[1]); zval_ptr_dtor(¶ms[2]); zval_ptr_dtor(¶ms[3]); zval_ptr_dtor(¶ms[4]); zval_ptr_dtor (&zcookie); zval_ptr_dtor (&zkey); zval_ptr_dtor (&zvalue); zval_ptr_dtor (&zcas); zval_ptr_dtor (&zresult_cas); return retval; } static protocol_binary_response_status s_append_handler (const void *cookie, const void *key, uint16_t key_len, const void *data, uint32_t data_len, uint64_t cas, uint64_t *result_cas) { return s_append_prepend_handler (MEMC_SERVER_ON_APPEND, cookie, key, key_len, data, data_len, cas, result_cas); } static protocol_binary_response_status s_prepend_handler (const void *cookie, const void *key, uint16_t key_len, const void *data, uint32_t data_len, uint64_t cas, uint64_t *result_cas) { return s_append_prepend_handler (MEMC_SERVER_ON_PREPEND, cookie, key, key_len, data, data_len, cas, result_cas); } static protocol_binary_response_status s_incr_decr_handler (php_memc_event_t event, const void *cookie, const void *key, uint16_t key_len, uint64_t delta, uint64_t initial, uint32_t expiration, uint64_t *result, uint64_t *result_cas) { protocol_binary_response_status retval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND; zval zcookie, zkey, zdelta, zinital, zexpiration, zresult, zresult_cas; zval params[7]; if (!MEMC_HAS_CB(event)) { return retval; } MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); ZVAL_STRINGL(&zkey, key, key_len); ZVAL_LONG(&zdelta, (zend_long) delta); ZVAL_LONG(&zinital, (zend_long) initial); ZVAL_LONG(&zexpiration, (zend_long) expiration); ZVAL_LONG(&zresult, 0); ZVAL_MAKE_REF(&zresult); ZVAL_NULL(&zresult_cas); ZVAL_MAKE_REF(&zresult_cas); ZVAL_COPY(¶ms[0], &zcookie); ZVAL_COPY(¶ms[1], &zkey); ZVAL_COPY(¶ms[2], &zdelta); ZVAL_COPY(¶ms[3], &zinital); ZVAL_COPY(¶ms[4], &zexpiration); ZVAL_COPY(¶ms[5], &zresult); ZVAL_COPY(¶ms[6], &zresult_cas); retval = s_invoke_php_callback (&MEMC_GET_CB(event), params, 7); *result = (uint64_t)zval_get_long(&zresult); MEMC_MAKE_RESULT_CAS(zresult_cas, *result_cas); zval_ptr_dtor(¶ms[0]); zval_ptr_dtor(¶ms[1]); zval_ptr_dtor(¶ms[2]); zval_ptr_dtor(¶ms[3]); zval_ptr_dtor(¶ms[4]); zval_ptr_dtor(¶ms[5]); zval_ptr_dtor(¶ms[6]); zval_ptr_dtor (&zcookie); zval_ptr_dtor (&zkey); zval_ptr_dtor (&zdelta); zval_ptr_dtor (&zinital); zval_ptr_dtor (&zexpiration); zval_ptr_dtor (&zresult); zval_ptr_dtor (&zresult_cas); return retval; } static protocol_binary_response_status s_increment_handler (const void *cookie, const void *key, uint16_t key_len, uint64_t delta, uint64_t initial, uint32_t expiration, uint64_t *result, uint64_t *result_cas) { return s_incr_decr_handler (MEMC_SERVER_ON_INCREMENT, cookie, key, key_len, delta, initial, expiration, result, result_cas); } static protocol_binary_response_status s_decrement_handler (const void *cookie, const void *key, uint16_t key_len, uint64_t delta, uint64_t initial, uint32_t expiration, uint64_t *result, uint64_t *result_cas) { return s_incr_decr_handler (MEMC_SERVER_ON_DECREMENT, cookie, key, key_len, delta, initial, expiration, result, result_cas); } static protocol_binary_response_status s_delete_handler (const void *cookie, const void *key, uint16_t key_len, uint64_t cas) { protocol_binary_response_status retval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND; zval zcookie, zkey, zcas; zval params[3]; if (!MEMC_HAS_CB(MEMC_SERVER_ON_DELETE)) { return retval; } MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); ZVAL_STRINGL(&zkey, key, key_len); ZVAL_DOUBLE(&zcas, (double) cas); ZVAL_COPY(¶ms[0], &zcookie); ZVAL_COPY(¶ms[1], &zkey); ZVAL_COPY(¶ms[2], &zcas); retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_DELETE), params, 3); zval_ptr_dtor(¶ms[0]); zval_ptr_dtor(¶ms[1]); zval_ptr_dtor(¶ms[2]); zval_ptr_dtor(&zcookie); zval_ptr_dtor(&zkey); zval_ptr_dtor(&zcas); return retval; } static protocol_binary_response_status s_flush_handler(const void *cookie, uint32_t when) { protocol_binary_response_status retval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND; zval zcookie, zwhen; zval params[2]; if (!MEMC_HAS_CB(MEMC_SERVER_ON_FLUSH)) { return retval; } MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); ZVAL_LONG(&zwhen, when); ZVAL_COPY(¶ms[0], &zcookie); ZVAL_COPY(¶ms[1], &zwhen); retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_FLUSH), params, 2); zval_ptr_dtor(¶ms[0]); zval_ptr_dtor(¶ms[1]); zval_ptr_dtor(&zcookie); zval_ptr_dtor(&zwhen); return retval; } static protocol_binary_response_status s_get_handler (const void *cookie, const void *key, uint16_t key_len, memcached_binary_protocol_get_response_handler response_handler) { protocol_binary_response_status retval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND; zval zcookie, zkey, zvalue, zflags, zresult_cas; zval params[5]; if (!MEMC_HAS_CB(MEMC_SERVER_ON_GET)) { return retval; } MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); ZVAL_STRINGL(&zkey, key, key_len); ZVAL_NULL(&zvalue); ZVAL_MAKE_REF(&zvalue); ZVAL_NULL(&zflags); ZVAL_MAKE_REF(&zflags); ZVAL_NULL(&zresult_cas); ZVAL_MAKE_REF(&zresult_cas); ZVAL_COPY(¶ms[0], &zcookie); ZVAL_COPY(¶ms[1], &zkey); ZVAL_COPY(¶ms[2], &zvalue); ZVAL_COPY(¶ms[3], &zflags); ZVAL_COPY(¶ms[4], &zresult_cas); retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_GET), params, 5); /* Succeeded in getting the key */ if (retval == PROTOCOL_BINARY_RESPONSE_SUCCESS) { uint32_t flags = 0; uint64_t result_cas = 0; if (Z_TYPE(zvalue) == IS_NULL) { zval_ptr_dtor(¶ms[0]); zval_ptr_dtor(¶ms[1]); zval_ptr_dtor(¶ms[2]); zval_ptr_dtor(¶ms[3]); zval_ptr_dtor(¶ms[4]); zval_ptr_dtor(&zcookie); zval_ptr_dtor(&zkey); zval_ptr_dtor(&zvalue); zval_ptr_dtor(&zflags); zval_ptr_dtor(&zresult_cas); return PROTOCOL_BINARY_RESPONSE_KEY_ENOENT; } if (Z_TYPE(zvalue) != IS_STRING) { convert_to_string (&zvalue); } if (Z_TYPE(zflags) == IS_LONG) { flags = Z_LVAL(zflags); } MEMC_MAKE_RESULT_CAS(zresult_cas, result_cas); retval = response_handler(cookie, key, key_len, Z_STRVAL(zvalue), Z_STRLEN(zvalue), flags, result_cas); } zval_ptr_dtor(¶ms[0]); zval_ptr_dtor(¶ms[1]); zval_ptr_dtor(¶ms[2]); zval_ptr_dtor(¶ms[3]); zval_ptr_dtor(¶ms[4]); zval_ptr_dtor (&zcookie); zval_ptr_dtor (&zkey); zval_ptr_dtor (&zvalue); zval_ptr_dtor (&zflags); zval_ptr_dtor (&zresult_cas); return retval; } static protocol_binary_response_status s_noop_handler(const void *cookie) { protocol_binary_response_status retval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND; zval zcookie; zval params[1]; if (!MEMC_HAS_CB(MEMC_SERVER_ON_NOOP)) { return retval; } MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); ZVAL_COPY(¶ms[0], &zcookie); retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_NOOP), params, 1); zval_ptr_dtor(¶ms[0]); zval_ptr_dtor (&zcookie); return retval; } static protocol_binary_response_status s_quit_handler(const void *cookie) { zval params[1]; protocol_binary_response_status retval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND; zval zcookie; if (!MEMC_HAS_CB(MEMC_SERVER_ON_QUIT)) { return retval; } MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); ZVAL_COPY(¶ms[0], &zcookie); retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_QUIT), params, 1); zval_ptr_dtor(¶ms[0]); zval_ptr_dtor (&zcookie); return retval; } static protocol_binary_response_status s_set_replace_handler (php_memc_event_t event, const void *cookie, const void *key, uint16_t key_len, const void *data, uint32_t data_len, uint32_t flags, uint32_t expiration, uint64_t cas, uint64_t *result_cas) { protocol_binary_response_status retval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND; zval zcookie, zkey, zdata, zflags, zexpiration, zcas, zresult_cas; zval params[7]; if (!MEMC_HAS_CB(event)) { return retval; } MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); ZVAL_STRINGL(&zkey, key, key_len); ZVAL_STRINGL(&zdata, data, data_len); ZVAL_LONG(&zflags, (zend_long) flags); ZVAL_LONG(&zexpiration, (zend_long) expiration); ZVAL_DOUBLE(&zcas, (double) cas); ZVAL_NULL(&zresult_cas); ZVAL_MAKE_REF(&zresult_cas); ZVAL_COPY(¶ms[0], &zcookie); ZVAL_COPY(¶ms[1], &zkey); ZVAL_COPY(¶ms[2], &zdata); ZVAL_COPY(¶ms[3], &zflags); ZVAL_COPY(¶ms[4], &zexpiration); ZVAL_COPY(¶ms[5], &zcas); ZVAL_COPY(¶ms[6], &zresult_cas); retval = s_invoke_php_callback (&MEMC_GET_CB(event), params, 7); MEMC_MAKE_RESULT_CAS(zresult_cas, *result_cas); zval_ptr_dtor(¶ms[0]); zval_ptr_dtor(¶ms[1]); zval_ptr_dtor(¶ms[2]); zval_ptr_dtor(¶ms[3]); zval_ptr_dtor(¶ms[4]); zval_ptr_dtor(¶ms[5]); zval_ptr_dtor(¶ms[6]); zval_ptr_dtor (&zcookie); zval_ptr_dtor (&zkey); zval_ptr_dtor (&zdata); zval_ptr_dtor (&zflags); zval_ptr_dtor (&zexpiration); zval_ptr_dtor (&zcas); zval_ptr_dtor (&zresult_cas); return retval; } static protocol_binary_response_status s_replace_handler (const void *cookie, const void *key, uint16_t key_len, const void *data, uint32_t data_len, uint32_t flags, uint32_t expiration, uint64_t cas, uint64_t *result_cas) { return s_set_replace_handler (MEMC_SERVER_ON_REPLACE, cookie, key, key_len, data, data_len, flags, expiration, cas, result_cas); } static protocol_binary_response_status s_set_handler (const void *cookie, const void *key, uint16_t key_len, const void *data, uint32_t data_len, uint32_t flags, uint32_t expiration, uint64_t cas, uint64_t *result_cas) { return s_set_replace_handler (MEMC_SERVER_ON_SET, cookie, key, key_len, data, data_len, flags, expiration, cas, result_cas); } static protocol_binary_response_status s_stat_handler (const void *cookie, const void *key, uint16_t key_len, memcached_binary_protocol_stat_response_handler response_handler) { zval params[3]; protocol_binary_response_status retval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND; zval zcookie, zkey, zstats; if (!MEMC_HAS_CB(MEMC_SERVER_ON_STAT)) { return retval; } MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); if (key && key_len) { ZVAL_STRINGL(&zkey, key, key_len); } else { ZVAL_NULL(&zkey); } array_init(&zstats); ZVAL_MAKE_REF(&zstats); ZVAL_COPY(¶ms[0], &zcookie); ZVAL_COPY(¶ms[1], &zkey); ZVAL_COPY(¶ms[2], &zstats); retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_STAT), params, 3); if (retval == PROTOCOL_BINARY_RESPONSE_SUCCESS) { zval *zarray = &zstats; zend_string *key; zend_long idx; zval *val; ZVAL_DEREF(zarray); if (Z_TYPE_P(zarray) != IS_ARRAY) { convert_to_array(zarray); } ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(zarray), idx, key, val) { zend_string *val_str = zval_get_string(val); if (key) { retval = response_handler(cookie, key->val, key->len, val_str->val, val_str->len); } else { char buf[0x20], *ptr, *end = &buf[sizeof(buf) - 1]; ptr = zend_print_long_to_buf(end, idx); retval = response_handler(cookie, ptr, end - ptr, val_str->val, val_str->len); } zend_string_release(val_str); if (retval != PROTOCOL_BINARY_RESPONSE_SUCCESS) { break; } } ZEND_HASH_FOREACH_END(); } zval_ptr_dtor(¶ms[0]); zval_ptr_dtor(¶ms[1]); zval_ptr_dtor(¶ms[2]); zval_ptr_dtor (&zcookie); zval_ptr_dtor (&zkey); zval_ptr_dtor (&zstats); return retval; } static protocol_binary_response_status s_version_handler (const void *cookie, memcached_binary_protocol_version_response_handler response_handler) { zval params[2]; protocol_binary_response_status retval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND; zval zcookie, zversion; if (!MEMC_HAS_CB(MEMC_SERVER_ON_VERSION)) { return retval; } MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); ZVAL_NULL(&zversion); ZVAL_MAKE_REF(&zversion); ZVAL_COPY(¶ms[0], &zcookie); ZVAL_COPY(¶ms[1], &zversion); retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_VERSION), params, 2); if (retval == PROTOCOL_BINARY_RESPONSE_SUCCESS) { if (Z_TYPE(zversion) != IS_STRING) { convert_to_string(&zversion); } retval = response_handler (cookie, Z_STRVAL(zversion), (uint32_t) Z_STRLEN(zversion)); } zval_ptr_dtor(¶ms[0]); zval_ptr_dtor(¶ms[1]); zval_ptr_dtor (&zcookie); zval_ptr_dtor (&zversion); return retval; } // libevent callbacks static void s_handle_memcached_event (evutil_socket_t fd, short what, void *arg) { int rc; short flags = 0; php_memc_client_t *client = (php_memc_client_t *) arg; memcached_protocol_event_t events; if (!client->on_connect_invoked) { if (MEMC_HAS_CB(MEMC_SERVER_ON_CONNECT)) { zend_string *zremoteaddr_str; zval zremoteaddr; zval params[1]; protocol_binary_response_status retval; ZVAL_NULL(&zremoteaddr); if (SUCCESS == php_network_get_peer_name (fd, &zremoteaddr_str, NULL, NULL)) { ZVAL_STR(&zremoteaddr, zremoteaddr_str); } else { php_error_docref(NULL, E_WARNING, "getpeername failed: %s", strerror (errno)); } ZVAL_COPY(¶ms[0], &zremoteaddr); retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_CONNECT), params, 1); zval_ptr_dtor(¶ms[0]); zval_ptr_dtor(&zremoteaddr); if (retval != PROTOCOL_BINARY_RESPONSE_SUCCESS) { memcached_protocol_client_destroy (client->protocol_client); efree (client); evutil_closesocket (fd); return; } } client->on_connect_invoked = 1; } events = memcached_protocol_client_work (client->protocol_client); if (events & MEMCACHED_PROTOCOL_ERROR_EVENT) { memcached_protocol_client_destroy (client->protocol_client); efree (client); evutil_closesocket (fd); return; } if (events & MEMCACHED_PROTOCOL_WRITE_EVENT) { flags = EV_WRITE; } if (events & MEMCACHED_PROTOCOL_READ_EVENT) { flags |= EV_READ; } rc = event_base_once (client->event_base, fd, flags, s_handle_memcached_event, client, NULL); if (rc != 0) { php_error_docref (NULL, E_WARNING, "Failed to schedule events"); } } static void s_accept_cb (evutil_socket_t fd, short what, void *arg) { int rc; php_memc_client_t *client; struct sockaddr_storage addr; socklen_t addr_len; evutil_socket_t sock; php_memc_proto_handler_t *handler = (php_memc_proto_handler_t *) arg; /* Accept the connection */ addr_len = sizeof (addr); sock = accept (fd, (struct sockaddr *) &addr, &addr_len); if (sock == -1) { php_error_docref (NULL, E_WARNING, "Failed to accept the client: %s", strerror (errno)); return; } client = ecalloc (1, sizeof (php_memc_client_t)); client->protocol_client = memcached_protocol_create_client (handler->protocol_handle, sock); client->event_base = handler->event_base; client->on_connect_invoked = 0; if (!client->protocol_client) { php_error_docref (NULL, E_WARNING, "Failed to allocate protocol client"); efree (client); evutil_closesocket (sock); return; } // TODO: this should timeout rc = event_base_once (handler->event_base, sock, EV_READ, s_handle_memcached_event, client, NULL); if (rc != 0) { php_error_docref (NULL, E_WARNING, "Failed to add event for client"); memcached_protocol_client_destroy (client->protocol_client); efree (client); evutil_closesocket (sock); return; } } php_memc_proto_handler_t *php_memc_proto_handler_new () { php_memc_proto_handler_t *handler = ecalloc (1, sizeof (php_memc_proto_handler_t)); handler->protocol_handle = memcached_protocol_create_instance (); assert (handler->protocol_handle); memset (&handler->callbacks, 0, sizeof (memcached_binary_protocol_callback_st)); handler->callbacks.interface_version = MEMCACHED_PROTOCOL_HANDLER_V1; handler->callbacks.interface.v1.add = s_add_handler; handler->callbacks.interface.v1.append = s_append_handler; handler->callbacks.interface.v1.decrement = s_decrement_handler; handler->callbacks.interface.v1.delete_object = s_delete_handler; handler->callbacks.interface.v1.flush_object = s_flush_handler; handler->callbacks.interface.v1.get = s_get_handler; handler->callbacks.interface.v1.increment = s_increment_handler; handler->callbacks.interface.v1.noop = s_noop_handler; handler->callbacks.interface.v1.prepend = s_prepend_handler; handler->callbacks.interface.v1.quit = s_quit_handler; handler->callbacks.interface.v1.replace = s_replace_handler; handler->callbacks.interface.v1.set = s_set_handler; handler->callbacks.interface.v1.stat = s_stat_handler; handler->callbacks.interface.v1.version = s_version_handler; memcached_binary_protocol_set_callbacks(handler->protocol_handle, &handler->callbacks); return handler; } static evutil_socket_t s_create_listening_socket (const zend_string *spec) { evutil_socket_t sock; struct sockaddr_storage addr; socklen_t addr_len; int rc; addr_len = sizeof (struct sockaddr); if (SUCCESS != php_network_parse_network_address_with_port(spec->val, spec->len, (struct sockaddr *) &addr, &addr_len)) { php_error_docref(NULL, E_WARNING, "Failed to parse bind address: %s", spec->val); return -1; } sock = socket (addr.ss_family, SOCK_STREAM, 0); if (sock < 0) { php_error_docref(NULL, E_WARNING, "socket failed: %s", strerror (errno)); return -1; } rc = bind (sock, (struct sockaddr *) &addr, addr_len); if (rc < 0) { php_error_docref(NULL, E_WARNING, "bind failed: %s", strerror (errno)); return -1; } rc = listen (sock, 1024); if (rc < 0) { php_error_docref(NULL, E_WARNING, "listen failed: %s", strerror (errno)); return -1; } rc = evutil_make_socket_nonblocking (sock); if (rc != 0) { php_error_docref(NULL, E_WARNING, "failed to make socket non-blocking: %s", strerror (errno)); return -1; } rc = evutil_make_listen_socket_reuseable (sock); if (rc != 0) { php_error_docref(NULL, E_WARNING, "failed to make socket reuseable: %s", strerror (errno)); return -1; } rc = evutil_make_socket_closeonexec (sock); if (rc != 0) { php_error_docref(NULL, E_WARNING, "failed to make socket closeonexec: %s", strerror (errno)); return -1; } return sock; } zend_bool php_memc_proto_handler_run (php_memc_proto_handler_t *handler, zend_string *address) { struct event *accept_event; evutil_socket_t sock = s_create_listening_socket (address); if (sock == -1) { return 0; } handler->event_base = event_base_new(); if (!handler->event_base) { php_error_docref(NULL, E_ERROR, "failed to allocate memory: %s", strerror (errno)); } accept_event = event_new (handler->event_base, sock, EV_READ | EV_PERSIST, s_accept_cb, handler); if (!accept_event) { php_error_docref(NULL, E_ERROR, "failed to allocate memory: %s", strerror (errno)); } event_add (accept_event, NULL); switch (event_base_dispatch (handler->event_base)) { case -1: php_error_docref(NULL, E_ERROR, "event_base_dispatch() failed: %s", strerror (errno)); return 0; break; case 1: php_error_docref(NULL, E_ERROR, "no events registered"); return 0; break; default: return 1; break; } } void php_memc_proto_handler_destroy (php_memc_proto_handler_t **ptr) { php_memc_proto_handler_t *handler = *ptr; if (handler->protocol_handle) memcached_protocol_destroy_instance (handler->protocol_handle); efree (handler); *ptr = NULL; } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim: noet sw=4 ts=4 fdm=marker: */ memcached-3.3.0/g_fmt.c0000644000076500000240000000444714704245235013512 0ustar mikestaff/**************************************************************** * * The author of this software is David M. Gay. * * Copyright (c) 1991, 1996 by Lucent Technologies. * * Permission to use, copy, modify, and distribute this software for any * purpose without fee is hereby granted, provided that this entire notice * is included in all copies of any software which is or includes a copy * or modification of this software and in all copies of the supporting * documentation for such software. * * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. * ***************************************************************/ /* g_fmt(buf,x) stores the closest decimal approximation to x in buf; * it suffices to declare buf * char buf[32]; */ /* Modified for use with php in the memcached client extension. * * // Teddy Grenman , 2010-05-18. */ #include char *php_memcached_g_fmt(register char *b, double x) { register int i, k; register char *s; int decpt, j; #if PHP_VERSION_ID < 80100 int sign; #else bool sign; #endif char *b0, *s0, *se; b0 = b; #ifdef IGNORE_ZERO_SIGN if (!x) { *b++ = '0'; *b = 0; goto done; } #endif s = s0 = zend_dtoa(x, 0, 0, &decpt, &sign, &se); if (sign) *b++ = '-'; if (decpt == 9999) /* Infinity or Nan */ { while((*b++ = *s++)); goto done0; } if (decpt <= -4 || decpt > se - s + 5) { *b++ = *s++; if (*s) { *b++ = '.'; while((*b = *s++)) b++; } *b++ = 'e'; /* sprintf(b, "%+.2d", decpt - 1); */ if (--decpt < 0) { *b++ = '-'; decpt = -decpt; } else *b++ = '+'; for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10); for(;;) { i = decpt / k; *b++ = i + '0'; if (--j <= 0) break; decpt -= i*k; decpt *= 10; } *b = 0; } else if (decpt <= 0) { *b++ = '.'; for(; decpt < 0; decpt++) *b++ = '0'; while((*b++ = *s++)); } else { while((*b = *s++)) { b++; if (--decpt == 0 && *s) *b++ = '.'; } for(; decpt > 0; decpt--) *b++ = '0'; *b = 0; } done0: zend_freedtoa(s0); #ifdef IGNORE_ZERO_SIGN done: #endif return b0; } memcached-3.3.0/g_fmt.h0000644000076500000240000000223514704245235013510 0ustar mikestaff/**************************************************************** * * The author of this software is David M. Gay. * * Copyright (c) 1991, 1996 by Lucent Technologies. * * Permission to use, copy, modify, and distribute this software for any * purpose without fee is hereby granted, provided that this entire notice * is included in all copies of any software which is or includes a copy * or modification of this software and in all copies of the supporting * documentation for such software. * * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. * ***************************************************************/ /* g_fmt(buf,x) stores the closest decimal approximation to x in buf; * it suffices to declare buf * char buf[32]; */ /* Modified for use with php in the memcached client * extension by Teddy Grenman, 2010. */ #ifndef MEMC_G_FMT_H #define MEMC_G_FMT_H char *php_memcached_g_fmt(register char *b, double x); #endif memcached-3.3.0/fastlz/fastlz.c0000644000076500000240000003252014704245235015215 0ustar mikestaff/* FastLZ - lightning-fast lossless compression library Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #if !defined(FASTLZ__COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) /* * Always check for bound when decompressing. * Generally it is best to leave it defined. */ #define FASTLZ_SAFE /* * Give hints to the compiler for branch prediction optimization. */ #if defined(__GNUC__) && (__GNUC__ > 2) #define FASTLZ_EXPECT_CONDITIONAL(c) (__builtin_expect((c), 1)) #define FASTLZ_UNEXPECT_CONDITIONAL(c) (__builtin_expect((c), 0)) #else #define FASTLZ_EXPECT_CONDITIONAL(c) (c) #define FASTLZ_UNEXPECT_CONDITIONAL(c) (c) #endif /* * Use inlined functions for supported systems. */ #if defined(__GNUC__) || defined(__DMC__) || defined(__POCC__) || defined(__WATCOMC__) || defined(__SUNPRO_C) #define FASTLZ_INLINE inline #elif defined(__BORLANDC__) || defined(_MSC_VER) || defined(__LCC__) #define FASTLZ_INLINE __inline #else #define FASTLZ_INLINE #endif /* * Prevent accessing more than 8-bit at once, except on x86 architectures. */ #if !defined(FASTLZ_STRICT_ALIGN) #define FASTLZ_STRICT_ALIGN #if defined(__i386__) || defined(__386) /* GNU C, Sun Studio */ #undef FASTLZ_STRICT_ALIGN #elif defined(__i486__) || defined(__i586__) || defined(__i686__) /* GNU C */ #undef FASTLZ_STRICT_ALIGN #elif defined(_M_IX86) /* Intel, MSVC */ #undef FASTLZ_STRICT_ALIGN #elif defined(__386) #undef FASTLZ_STRICT_ALIGN #elif defined(_X86_) /* MinGW */ #undef FASTLZ_STRICT_ALIGN #elif defined(__I86__) /* Digital Mars */ #undef FASTLZ_STRICT_ALIGN #endif #endif /* * FIXME: use preprocessor magic to set this on different platforms! */ typedef unsigned char flzuint8; typedef unsigned short flzuint16; typedef unsigned int flzuint32; /* prototypes */ int fastlz_compress(const void* input, int length, void* output); int fastlz_compress_level(int level, const void* input, int length, void* output); int fastlz_decompress(const void* input, int length, void* output, int maxout); #define MAX_COPY 32 #define MAX_LEN 264 /* 256 + 8 */ #define MAX_DISTANCE 8192 #if !defined(FASTLZ_STRICT_ALIGN) #define FASTLZ_READU16(p) *((const flzuint16*)(p)) #else #define FASTLZ_READU16(p) ((p)[0] | (p)[1]<<8) #endif #define HASH_LOG 13 #define HASH_SIZE (1<< HASH_LOG) #define HASH_MASK (HASH_SIZE-1) #define HASH_FUNCTION(v,p) { v = FASTLZ_READU16(p); v ^= FASTLZ_READU16(p+1)^(v>>(16-HASH_LOG));v &= HASH_MASK; } #undef FASTLZ_LEVEL #define FASTLZ_LEVEL 1 #undef FASTLZ_COMPRESSOR #undef FASTLZ_DECOMPRESSOR #define FASTLZ_COMPRESSOR fastlz1_compress #define FASTLZ_DECOMPRESSOR fastlz1_decompress static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output); static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout); #include "fastlz.c" #undef FASTLZ_LEVEL #define FASTLZ_LEVEL 2 #undef MAX_DISTANCE #define MAX_DISTANCE 8191 #define MAX_FARDISTANCE (65535+MAX_DISTANCE-1) #undef FASTLZ_COMPRESSOR #undef FASTLZ_DECOMPRESSOR #define FASTLZ_COMPRESSOR fastlz2_compress #define FASTLZ_DECOMPRESSOR fastlz2_decompress static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output); static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout); #include "fastlz.c" int fastlz_compress(const void* input, int length, void* output) { /* for short block, choose fastlz1 */ if(length < 65536) return fastlz1_compress(input, length, output); /* else... */ return fastlz2_compress(input, length, output); } int fastlz_decompress(const void* input, int length, void* output, int maxout) { /* magic identifier for compression level */ int level = ((*(const flzuint8*)input) >> 5) + 1; if(level == 1) return fastlz1_decompress(input, length, output, maxout); if(level == 2) return fastlz2_decompress(input, length, output, maxout); /* unknown level, trigger error */ return 0; } int fastlz_compress_level(int level, const void* input, int length, void* output) { if(level == 1) return fastlz1_compress(input, length, output); if(level == 2) return fastlz2_compress(input, length, output); return 0; } #else /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */ static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output) { const flzuint8* ip = (const flzuint8*) input; const flzuint8* ip_bound = ip + length - 2; const flzuint8* ip_limit = ip + length - 12; flzuint8* op = (flzuint8*) output; const flzuint8* htab[HASH_SIZE]; const flzuint8** hslot; flzuint32 hval; flzuint32 copy; /* sanity check */ if(FASTLZ_UNEXPECT_CONDITIONAL(length < 4)) { if(length) { /* create literal copy only */ *op++ = length-1; ip_bound++; while(ip <= ip_bound) *op++ = *ip++; return length+1; } else return 0; } /* initializes hash table */ for (hslot = htab; hslot < htab + HASH_SIZE; hslot++) *hslot = ip; /* we start with literal copy */ copy = 2; *op++ = MAX_COPY-1; *op++ = *ip++; *op++ = *ip++; /* main loop */ while(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit)) { const flzuint8* ref; flzuint32 distance; /* minimum match length */ flzuint32 len = 3; /* comparison starting-point */ const flzuint8* anchor = ip; /* check for a run */ #if FASTLZ_LEVEL==2 if(ip[0] == ip[-1] && FASTLZ_READU16(ip-1)==FASTLZ_READU16(ip+1)) { distance = 1; ip += 3; ref = anchor - 1 + 3; goto match; } #endif /* find potential match */ HASH_FUNCTION(hval,ip); hslot = htab + hval; ref = htab[hval]; /* calculate distance to the match */ distance = anchor - ref; /* update hash table */ *hslot = anchor; /* is this a match? check the first 3 bytes */ if(distance==0 || #if FASTLZ_LEVEL==1 (distance >= MAX_DISTANCE) || #else (distance >= MAX_FARDISTANCE) || #endif *ref++ != *ip++ || *ref++!=*ip++ || *ref++!=*ip++) goto literal; #if FASTLZ_LEVEL==2 /* far, needs at least 5-byte match */ if(distance >= MAX_DISTANCE) { if(*ip++ != *ref++ || *ip++!= *ref++) goto literal; len += 2; } match: #endif /* last matched byte */ ip = anchor + len; /* distance is biased */ distance--; if(!distance) { /* zero distance means a run */ flzuint8 x = ip[-1]; while(ip < ip_bound) if(*ref++ != x) break; else ip++; } else for(;;) { /* safe because the outer check against ip limit */ if(*ref++ != *ip++) break; if(*ref++ != *ip++) break; if(*ref++ != *ip++) break; if(*ref++ != *ip++) break; if(*ref++ != *ip++) break; if(*ref++ != *ip++) break; if(*ref++ != *ip++) break; if(*ref++ != *ip++) break; while(ip < ip_bound) if(*ref++ != *ip++) break; break; } /* if we have copied something, adjust the copy count */ if(copy) /* copy is biased, '0' means 1 byte copy */ *(op-copy-1) = copy-1; else /* back, to overwrite the copy count */ op--; /* reset literal counter */ copy = 0; /* length is biased, '1' means a match of 3 bytes */ ip -= 3; len = ip - anchor; /* encode the match */ #if FASTLZ_LEVEL==2 if(distance < MAX_DISTANCE) { if(len < 7) { *op++ = (len << 5) + (distance >> 8); *op++ = (distance & 255); } else { *op++ = (7 << 5) + (distance >> 8); for(len-=7; len >= 255; len-= 255) *op++ = 255; *op++ = len; *op++ = (distance & 255); } } else { /* far away, but not yet in the another galaxy... */ if(len < 7) { distance -= MAX_DISTANCE; *op++ = (len << 5) + 31; *op++ = 255; *op++ = distance >> 8; *op++ = distance & 255; } else { distance -= MAX_DISTANCE; *op++ = (7 << 5) + 31; for(len-=7; len >= 255; len-= 255) *op++ = 255; *op++ = len; *op++ = 255; *op++ = distance >> 8; *op++ = distance & 255; } } #else if(FASTLZ_UNEXPECT_CONDITIONAL(len > MAX_LEN-2)) while(len > MAX_LEN-2) { *op++ = (7 << 5) + (distance >> 8); *op++ = MAX_LEN - 2 - 7 -2; *op++ = (distance & 255); len -= MAX_LEN-2; } if(len < 7) { *op++ = (len << 5) + (distance >> 8); *op++ = (distance & 255); } else { *op++ = (7 << 5) + (distance >> 8); *op++ = len - 7; *op++ = (distance & 255); } #endif /* update the hash at match boundary */ HASH_FUNCTION(hval,ip); htab[hval] = ip++; HASH_FUNCTION(hval,ip); htab[hval] = ip++; /* assuming literal copy */ *op++ = MAX_COPY-1; continue; literal: *op++ = *anchor++; ip = anchor; copy++; if(FASTLZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY)) { copy = 0; *op++ = MAX_COPY-1; } } /* left-over as literal copy */ ip_bound++; while(ip <= ip_bound) { *op++ = *ip++; copy++; if(copy == MAX_COPY) { copy = 0; *op++ = MAX_COPY-1; } } /* if we have copied something, adjust the copy length */ if(copy) *(op-copy-1) = copy-1; else op--; #if FASTLZ_LEVEL==2 /* marker for fastlz2 */ *(flzuint8*)output |= (1 << 5); #endif return op - (flzuint8*)output; } static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout) { const flzuint8* ip = (const flzuint8*) input; const flzuint8* ip_limit = ip + length; flzuint8* op = (flzuint8*) output; flzuint8* op_limit = op + maxout; flzuint32 ctrl = (*ip++) & 31; int loop = 1; do { const flzuint8* ref = op; flzuint32 len = ctrl >> 5; flzuint32 ofs = (ctrl & 31) << 8; if(ctrl >= 32) { #if FASTLZ_LEVEL==2 flzuint8 code; #endif len--; ref -= ofs; if (len == 7-1) #if FASTLZ_LEVEL==1 len += *ip++; ref -= *ip++; #else do { code = *ip++; len += code; } while (code==255); code = *ip++; ref -= code; /* match from 16-bit distance */ if(FASTLZ_UNEXPECT_CONDITIONAL(code==255)) if(FASTLZ_EXPECT_CONDITIONAL(ofs==(31 << 8))) { ofs = (*ip++) << 8; ofs += *ip++; ref = op - ofs - MAX_DISTANCE; } #endif #ifdef FASTLZ_SAFE if (FASTLZ_UNEXPECT_CONDITIONAL(op + len + 3 > op_limit)) return 0; if (FASTLZ_UNEXPECT_CONDITIONAL(ref-1 < (flzuint8 *)output)) return 0; #endif if(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit)) ctrl = *ip++; else loop = 0; if(ref == op) { /* optimize copy for a run */ flzuint8 b = ref[-1]; *op++ = b; *op++ = b; *op++ = b; for(; len; --len) *op++ = b; } else { #if !defined(FASTLZ_STRICT_ALIGN) const flzuint16* p; flzuint16* q; #endif /* copy from reference */ ref--; *op++ = *ref++; *op++ = *ref++; *op++ = *ref++; #if !defined(FASTLZ_STRICT_ALIGN) /* copy a byte, so that now it's word aligned */ if(len & 1) { *op++ = *ref++; len--; } /* copy 16-bit at once */ q = (flzuint16*) op; op += len; p = (const flzuint16*) ref; for(len>>=1; len > 4; len-=4) { *q++ = *p++; *q++ = *p++; *q++ = *p++; *q++ = *p++; } for(; len; --len) *q++ = *p++; #else for(; len; --len) *op++ = *ref++; #endif } } else { ctrl++; #ifdef FASTLZ_SAFE if (FASTLZ_UNEXPECT_CONDITIONAL(op + ctrl > op_limit)) return 0; if (FASTLZ_UNEXPECT_CONDITIONAL(ip + ctrl > ip_limit)) return 0; #endif *op++ = *ip++; for(--ctrl; ctrl; ctrl--) *op++ = *ip++; loop = FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit); if(loop) ctrl = *ip++; } } while(FASTLZ_EXPECT_CONDITIONAL(loop)); return op - (flzuint8*)output; } #endif /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */ memcached-3.3.0/fastlz/fastlz.h0000644000076500000240000000675614704245235015236 0ustar mikestaff/* FastLZ - lightning-fast lossless compression library Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef FASTLZ_H #define FASTLZ_H #define FASTLZ_VERSION 0x000100 #define FASTLZ_VERSION_MAJOR 0 #define FASTLZ_VERSION_MINOR 0 #define FASTLZ_VERSION_REVISION 0 #define FASTLZ_VERSION_STRING "0.1.0" #if defined (__cplusplus) extern "C" { #endif /** Compress a block of data in the input buffer and returns the size of compressed block. The size of input buffer is specified by length. The minimum input buffer size is 16. The output buffer must be at least 5% larger than the input buffer and can not be smaller than 66 bytes. If the input is not compressible, the return value might be larger than length (input buffer size). The input buffer and the output buffer can not overlap. */ int fastlz_compress(const void* input, int length, void* output); /** Decompress a block of compressed data and returns the size of the decompressed block. If error occurs, e.g. the compressed data is corrupted or the output buffer is not large enough, then 0 (zero) will be returned instead. The input buffer and the output buffer can not overlap. Decompression is memory safe and guaranteed not to write the output buffer more than what is specified in maxout. */ int fastlz_decompress(const void* input, int length, void* output, int maxout); /** Compress a block of data in the input buffer and returns the size of compressed block. The size of input buffer is specified by length. The minimum input buffer size is 16. The output buffer must be at least 5% larger than the input buffer and can not be smaller than 66 bytes. If the input is not compressible, the return value might be larger than length (input buffer size). The input buffer and the output buffer can not overlap. Compression level can be specified in parameter level. At the moment, only level 1 and level 2 are supported. Level 1 is the fastest compression and generally useful for short data. Level 2 is slightly slower but it gives better compression ratio. Note that the compressed data, regardless of the level, can always be decompressed using the function fastlz_decompress above. */ int fastlz_compress_level(int level, const void* input, int length, void* output); #if defined (__cplusplus) } #endif #endif /* FASTLZ_H */