diff --git a/.cvsignore b/.cvsignore deleted file mode 100644 index cc617d3d..00000000 --- a/.cvsignore +++ /dev/null @@ -1,46 +0,0 @@ -*.lo -*.la -.deps -.libs -Makefile -Makefile.fragments -Makefile.global -Makefile.objects -acinclude.m4 -aclocal.m4 -autom4te.cache -build -config.cache -config.guess -config.h -config.h.in -config.log -config.nice -config.status -config.sub -configure -configure.in -conftest -conftest.c -include -install-sh -libtool -ltmain.sh -missing -mkinstalldirs -modules -scan_makefile_in.awk -*.dsw -*.plg -*.opt -*.ncb -Release -Release_inline -Debug -Release_TS -Release_TSDbg -Release_TS_inline -Debug_TS -memcached*.tgz -run-tests.php -cscope.out diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..12301490 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml new file mode 100644 index 00000000..2e10b05b --- /dev/null +++ b/.github/workflows/build-and-test.yml @@ -0,0 +1,88 @@ + +name: Test on Ubuntu +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + continue-on-error: ${{ matrix.experimental }} + strategy: + fail-fast: false + matrix: + php: ['7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3'] + experimental: [false] + include: + - php: '8.4' + experimental: true + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: true + - name: Install PHP ${{ matrix.php }} + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: none, json, igbinary, msgpack + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install cmake memcached libsasl2-dev sasl2-bin zlib1g-dev + - name: Install libmemcached-dev + run: sudo apt-get install libmemcached-dev + - name: Start memcached daemons + run: | + export SASL_CONF_PATH="/tmp/sasl2" + mkdir "${SASL_CONF_PATH}" + export MEMCACHED_SASL_PWDB="${SASL_CONF_PATH}/sasldb2" + + # Create configuration + cat< "${SASL_CONF_PATH}/memcached.conf" + mech_list: PLAIN + plainlog_level: 5 + sasldb_path: ${MEMCACHED_SASL_PWDB} + EOF + + echo "test" | /usr/sbin/saslpasswd2 -c memcached -a memcached -f "${MEMCACHED_SASL_PWDB}" + + # Run normal memcached + memcached -d -p 11211 + + # Run memcached on port 11212 with SASL support + memcached -S -d -p 11212 + - name: Build extension + run: | + phpize + ./configure \ + --enable-memcached-protocol=no \ + --enable-memcached-sasl \ + --enable-memcached-json \ + --enable-memcached-msgpack \ + --enable-memcached-igbinary + make + sudo make install + - name: Create test configuration + run: | + cat< tests/config.inc.local + /dev/null - if [ $? != 0 ]; then - echo "Missing $file from package.xml" - retval=1; - fi - done - return $retval -} - -function install_libmemcached() { - - if test -d "${LIBMEMCACHED_PREFIX}" - then - echo "Using cached libmemcached: ${LIBMEMCACHED_PREFIX}" - return - fi - - wget "https://launchpad.net/libmemcached/1.0/${LIBMEMCACHED_VERSION}/+download/libmemcached-${LIBMEMCACHED_VERSION}.tar.gz" -O libmemcached-${LIBMEMCACHED_VERSION}.tar.gz - - tar xvfz libmemcached-${LIBMEMCACHED_VERSION}.tar.gz - pushd "libmemcached-${LIBMEMCACHED_VERSION}" - - local protocol_flag="" - if test "x$ENABLE_PROTOOCOL" = "xyes"; then - protocol_flag="--enable-libmemcachedprotocol" - fi - - ./configure --prefix="$LIBMEMCACHED_PREFIX" $protocol_flag LDFLAGS="-lpthread" - make - make install - popd -} - -function install_igbinary() { - git clone https://github.com/igbinary/igbinary.git - pushd igbinary - phpize - ./configure - make - make install - popd -} - -function install_msgpack() { - git clone https://github.com/msgpack/msgpack-php.git - pushd msgpack-php - phpize - ./configure - make - make install - popd -} - -function install_memcached() { - local prefix="${HOME}/cache/memcached-sasl-${MEMCACHED_VERSION}" - - if test -d "$prefix" - then - echo "Using cached memcached: ${prefix}" - return - fi - - wget http://www.memcached.org/files/memcached-${MEMCACHED_VERSION}.tar.gz -O memcached-${MEMCACHED_VERSION}.tar.gz - tar xfz memcached-${MEMCACHED_VERSION}.tar.gz - - pushd memcached-${MEMCACHED_VERSION} - ./configure --enable-sasl --enable-sasl-pwdb --prefix="${prefix}" - make - make install - popd -} - -function run_memcached() { - local prefix="${HOME}/cache/memcached-sasl-${MEMCACHED_VERSION}" - - export SASL_CONF_PATH="/tmp/sasl2" - - if test -d "${SASL_CONF_PATH}" - then - rm -rf "${SASL_CONF_PATH}" - fi - - mkdir "${SASL_CONF_PATH}" - export MEMCACHED_SASL_PWDB="${SASL_CONF_PATH}/sasldb2" - - # Create configuration - cat< "${SASL_CONF_PATH}/memcached.conf" -mech_list: PLAIN -plainlog_level: 5 -sasldb_path: ${MEMCACHED_SASL_PWDB} -EOF - - echo "test" | /usr/sbin/saslpasswd2 -c memcached -a memcached -f "${MEMCACHED_SASL_PWDB}" - - # Run normal memcached - "${prefix}/bin/memcached" -d -p 11211 - - # Run memcached on port 11212 with SASL support - "${prefix}/bin/memcached" -S -d -p 11212 -} - -function build_php_memcached() { - pear package - mkdir "$PHP_MEMCACHED_BUILD_DIR" - tar xfz "memcached-${PHP_MEMCACHED_VERSION}.tgz" -C "$PHP_MEMCACHED_BUILD_DIR" - pushd "${PHP_MEMCACHED_BUILD_DIR}/memcached-${PHP_MEMCACHED_VERSION}" - phpize - - local protocol_flag="" - if test "x$ENABLE_PROTOCOL" = "xyes"; then - protocol_flag="--enable-memcached-protocol" - fi - - local sasl_flag="--disable-memcached-sasl" - if test "x$ENABLE_SASL" = "xyes"; then - sasl_flag="--enable-memcached-sasl" - fi - - # ./configure --with-libmemcached-dir="$LIBMEMCACHED_PREFIX" $protocol_flag $sasl_flag - ./configure --with-libmemcached-dir="$LIBMEMCACHED_PREFIX" $protocol_flag $sasl_flag --enable-memcached-json --enable-memcached-msgpack --enable-memcached-igbinary - make - make install - popd -} - -function create_memcached_test_configuration() { -cat< "${PHP_MEMCACHED_BUILD_DIR}/memcached-${PHP_MEMCACHED_VERSION}/tests/config.inc.local" - " - exit 1 -fi - -if test "x$LIBMEMCACHED_VERSION" = "x"; then - echo "Usage: $0 " - exit 1 -fi - -if test "x$3" != "x"; then - MEMCACHED_VERSION=$3 -fi - -# the extension version -PHP_MEMCACHED_VERSION=$(php -r '$sxe = simplexml_load_file ("package.xml"); echo (string) $sxe->version->release;') - -# Libmemcached install dir -LIBMEMCACHED_PREFIX="${HOME}/cache/libmemcached-${LIBMEMCACHED_VERSION}" - -# Where to do the build -PHP_MEMCACHED_BUILD_DIR="/tmp/php-memcached-build" - -# Check whether to enable building with protoocol and sasl support -check_protocol_support -check_sasl_support - -echo "Enable protocol: $ENABLE_PROTOOCOL" -echo "Enable sasl: $ENABLE_SASL" - -set -e - -case $ACTION in - before_script) - # validate the package.xml - validate_package_xml || exit 1 - - # Install libmemcached version - install_libmemcached - - # Install igbinary extension - install_igbinary - - # Install msgpack extension - install_msgpack - - install_memcached - run_memcached - ;; - - script) - # Build the extension - build_php_memcached - - # Create configuration - if test "x$ENABLE_SASL" = "xyes"; then - create_memcached_test_configuration - fi - - # Run tests - set +e - run_memcached_tests || exit 1 - ;; - - *) - echo "Unknown action. Valid actions are: before_script and script" - exit 1 - ;; -esac - - - - - diff --git a/ChangeLog b/ChangeLog index 05f77181..31994e3b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,133 @@ memcached 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 diff --git a/README.markdown b/README.markdown index ae1b86db..38dbd5bc 100644 --- a/README.markdown +++ b/README.markdown @@ -1,15 +1,15 @@ Build Status ------------ -[![Build Status](https://travis-ci.org/php-memcached-dev/php-memcached.png?branch=php7)](https://travis-ci.org/php-memcached-dev/php-memcached) +![Build Status](https://github.com/php-memcached-dev/php-memcached/actions/workflows/build-and-test.yml/badge.svg?branch=master) Description ----------- -This extension uses libmemcached library to provide API for communicating with -memcached servers. +This is the [PECL memcached](https://pecl.php.net/package/memcached) extension, +using the libmemcached library to connect to memcached servers. -memcached 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. +[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 -------- @@ -19,8 +19,34 @@ Building $ make $ make test -Resources ---------- - * [libmemcached](http://libmemcached.org/libMemcached.html) - * [memcached](http://memcached.org/) - * [igbinary](https://github.com/igbinary/igbinary) +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. diff --git a/README.win32.txt b/README.win32.txt new file mode 100644 index 00000000..c717aa8a --- /dev/null +++ b/README.win32.txt @@ -0,0 +1,13 @@ +Build Steps for Windows +------------------------- + +Follow https://wiki.php.net/internals/windows/stepbystepbuild_sdk_2#building_pecl_extensions + +- Add igbinary module to pecl directory if support desired +- Download/Compile libmemcached & add to deps folders (includes & lib). Lib should be named memcache.lib + - Important for 32bit: libmemcached must be built with _USE_32BIT_TIME_T defined (confirmed on PHP 7.2, VC15) + - https://github.com/yshurik/libmemcached-win/tree/1.0.18 is confirmed working + - To use the dll on the releases page you'd likely need to change the header files to use __time64_t instead of time_t +- Enable all options desired: --enable-memcached=shared --enable-memcached-session --enable-memcached-json + - for igbinary, add --enable-memcached-igbinary --enable-igbinary=shared +- Run nmake \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 00000000..3356c89d --- /dev/null +++ b/composer.json @@ -0,0 +1,68 @@ +{ + "name": "php-memcached/php-memcached", + "type": "php-ext", + "license": "PHP-3.01", + "description": "memcached extension based on libmemcached library ", + "require": { + "php": ">= 7.0.0" + }, + "suggest": { + "ext-igbinary": "igbinary is a faster and more compact binary serializer for PHP data structures.", + "ext-msgpack": "msgpack is a faster and more compact data structure representation that is interoperable with msgpack implementations for other languages." + }, + "php-ext": { + "extension-name": "memcached", + "configure-options": [ + { + "name": "enable-memcached", + "description": "Enable memcached support" + }, + { + "name": "with-libmemcached-dir", + "description": "Set the path to libmemcached install prefix.", + "needs-value": true + }, + { + "name": "enable-memcached-session", + "description": "Enable memcached session handler support" + }, + { + "name": "enable-memcached-igbinary", + "description": "Enable memcached igbinary serializer support" + }, + { + "name": "enable-memcached-json", + "description": "Enable memcached json serializer support" + }, + { + "name": "enable-memcached-msgpack", + "description": "Enable memcached msgpack serializer support" + }, + { + "name": "enable-memcached-sasl", + "description": "Enable memcached sasl support" + }, + { + "name": "enable-memcached-protocol", + "description": "Enable memcached protocol support" + }, + { + "name": "with-system-fastlz", + "description": "Use system FastLZ library" + }, + { + "name": "with-zstd", + "description": "Use system zstd library" + }, + { + "name": "with-zlib-dir", + "description": "Set the path to ZLIB install prefix.", + "needs-value": true + }, + { + "name": "enable-debug", + "description": "Compile with debugging symbols" + } + ] + } +} diff --git a/config.m4 b/config.m4 index e6a2dfd0..0e4ef8cf 100644 --- a/config.m4 +++ b/config.m4 @@ -1,42 +1,43 @@ -dnl -dnl $ Id: $ dnl vim:se ts=2 sw=2 et: PHP_ARG_ENABLE(memcached, whether to enable memcached support, -[ --enable-memcached 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) +[ --with-libmemcached-dir=DIR Set the path to libmemcached install prefix.], yes) PHP_ARG_ENABLE(memcached-session, whether to enable memcached session handler support, -[ --disable-memcached-session Disable memcached session handler support], yes, no) +[ --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) +[ --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) +[ --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) +[ --enable-memcached-msgpack Enable memcached msgpack serializer support], no, no) PHP_ARG_ENABLE(memcached-sasl, whether to enable memcached sasl support, -[ --disable-memcached-sasl Disable memcached sasl support], yes, no) +[ --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 protocoll support], no, no) +[ --enable-memcached-protocol Enable memcached protocol support], no, no) -PHP_ARG_WITH(system-fastlz, whether to use system FastLZ bibrary, -[ --with-system-fastlz Use system FastLZ bibrary], 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) +[ --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],[ + [ --enable-debug Compile with debugging symbols],[ PHP_DEBUG=$enableval ],[ PHP_DEBUG=no ]) @@ -62,7 +63,7 @@ if test "$PHP_MEMCACHED" != "no"; then AC_MSG_ERROR([Can't find ZLIB headers under "$PHP_ZLIB_DIR"]) fi else - for i in /usr/local /usr; do + 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" @@ -184,7 +185,7 @@ if test "$PHP_MEMCACHED" != "no"; then else AC_MSG_RESULT([$msgpack_inc_path]) fi - fi + fi AC_MSG_CHECKING([for memcached session support]) if test "$PHP_MEMCACHED_SESSION" != "no"; then @@ -255,42 +256,42 @@ if test "$PHP_MEMCACHED" != "no"; then PHP_EVAL_LIBLINE($PHP_LIBMEMCACHED_LIBS, MEMCACHED_SHARED_LIBADD) PHP_EVAL_INCLINE($PHP_LIBMEMCACHED_INCLUDES) - # - # Added -lpthread here because AC_TRY_LINK tests on CentOS 6 seem to fail with undefined reference to pthread_once - # 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) - AC_CHECK_HEADERS([sasl/sasl.h], [ac_cv_have_memc_sasl_h="yes"], [ac_cv_have_memc_sasl_h="no"]) - - if test "$ac_cv_have_memc_sasl_h" = "yes"; then - - AC_CACHE_CHECK([whether libmemcached supports sasl], ac_cv_memc_sasl_support, [ - AC_TRY_COMPILE( - [ #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 - 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 sasl support is not enabled. Run configure with --disable-memcached-sasl to disable this check]) - fi + 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, sasl.h is not available. Run configure with --disable-memcached-sasl to disable this check]) + 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]) @@ -298,26 +299,43 @@ if test "$PHP_MEMCACHED" != "no"; then 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_TRY_LINK( - [ #include ], - [ memcached_exist (NULL, NULL, 0); ], - [ ac_cv_have_memcached_exist="yes" ], - [ ac_cv_have_memcached_exist="no" ] - ) + 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 @@ -330,6 +348,13 @@ if test "$PHP_MEMCACHED" != "no"; then 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 @@ -340,13 +365,12 @@ if test "$PHP_MEMCACHED" != "no"; then AC_MSG_RESULT([enabled]) AC_CACHE_CHECK([whether libmemcachedprotocol is usable], ac_cv_have_libmemcachedprotocol, [ - AC_TRY_COMPILE( - [ #include ], - [ memcached_binary_protocol_callback_st s_test_impl; + 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" ] + ]])], + [ac_cv_have_libmemcachedprotocol="yes"], + [ac_cv_have_libmemcachedprotocol="no"] ) ]) diff --git a/config.w32 b/config.w32 index 380a9a12..76d4ee3c 100644 --- a/config.w32 +++ b/config.w32 @@ -1,18 +1,50 @@ -// $ Id: $ // vim:ft=javascript -ARG_WITH('memcached', 'libmemcached extension', 'no'); +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", "memcached", PHP_MEMCACHED)) { + 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"); } - EXTENSION("memcached", "memcached.c"); + + 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) } diff --git a/g_fmt.c b/g_fmt.c index 73f82fd0..f456790c 100644 --- a/g_fmt.c +++ b/g_fmt.c @@ -27,12 +27,17 @@ * // Teddy Grenman , 2010-05-18. */ -#include +#include char *php_memcached_g_fmt(register char *b, double x) { register int i, k; register char *s; - int decpt, j, sign; + int decpt, j; +#if PHP_VERSION_ID < 80100 + int sign; +#else + bool sign; +#endif char *b0, *s0, *se; b0 = b; diff --git a/memcached-api.php b/memcached-api.php index d22d0cf9..8ab03d4c 100644 --- a/memcached-api.php +++ b/memcached-api.php @@ -10,13 +10,13 @@ class Memcached { */ const OPT_HASH; - - const OPT_HASH_DEFAULT; + + const HASH_DEFAULT; const HASH_MD5; const HASH_CRC; - + const HASH_FNV1_64; const HASH_FNV1A_64; @@ -34,12 +34,16 @@ class Memcached { const DISTRIBUTION_MODULA; const DISTRIBUTION_CONSISTENT; - + const DISTRIBUTION_VIRTUAL_BUCKET; - const LIBKETAMA_COMPATIBLE; + const OPT_LIBKETAMA_COMPATIBLE; + + const OPT_LIBKETAMA_HASH; - const OPT_BUFFER_REQUESTS; + const OPT_TCP_KEEPALIVE; + + const OPT_BUFFER_WRITES; const OPT_BINARY_PROTOCOL; @@ -57,9 +61,9 @@ class Memcached { const OPT_DEAD_TIMEOUT; - const OPT_SND_TIMEOUT; + const OPT_SEND_TIMEOUT; - const OPT_RCV_TIMEOUT; + const OPT_RECV_TIMEOUT; const OPT_POLL_TIMEOUT; @@ -71,22 +75,36 @@ class Memcached { const OPT_AUTO_EJECT_HOSTS; - const OPT_NUMBER_OF_REPLICAS; - const OPT_NOREPLY; const OPT_VERIFY_KEY; - + + const OPT_USE_UDP; + + const OPT_NUMBER_OF_REPLICAS; + const OPT_RANDOMIZE_REPLICA_READS; + const OPT_REMOVE_FAILED_SERVERS; /** - * Class parameters + * Supported serializers */ const HAVE_JSON; const HAVE_IGBINARY; + const HAVE_MSGPACK; + + const HAVE_ENCODING; + + /** + * Feature support + */ + const HAVE_SESSION; + + const HAVE_SASL; + /** * Class options. */ @@ -107,18 +125,24 @@ class Memcached { const SERIALIZER_JSON_ARRAY; + const SERIALIZER_MSGPACK; + /** * Compression types */ - const COMPRESSION_TYPE_FASTLZ; + const COMPRESSION_FASTLZ; - const COMPRESSION_TYPE_ZLIB; + const COMPRESSION_ZLIB; /** - * Flags + * Flags for get and getMulti operations. */ + // Whether to preserve key order in the result const GET_PRESERVE_ORDER; + // Whether to fetch CAS token as well (use "gets"). + const GET_EXTENDED; + /** * Return values */ @@ -186,23 +210,71 @@ class Memcached { const RES_CONNECTION_SOCKET_CREATE_FAILURE; + const RES_E2BIG; + + const RES_KEY_TOO_BIG; + + const RES_SERVER_TEMPORARILY_DISABLED; + + const RES_SERVER_MEMORY_ALLOCATION_FAILURE; + + const RES_AUTH_PROBLEM; + + const RES_AUTH_FAILURE; + + const RES_AUTH_CONTINUE; + + /** Server callbacks, if compiled with --memcached-protocol */ + const ON_CONNECT; + const ON_ADD; + const ON_APPEND; + const ON_DECREMENT; + const ON_DELETE; + const ON_FLUSH; + const ON_GET; + const ON_INCREMENT; + const ON_NOOP; + const ON_PREPEND; + const ON_QUIT; + const ON_REPLACE; + const ON_SET; + const ON_STAT; + const ON_VERSION; + /** Constants used when compiled with --memcached-protocol */ + const RESPONSE_SUCCESS; + const RESPONSE_KEY_ENOENT; + const RESPONSE_KEY_EEXISTS; + const RESPONSE_E2BIG; + const RESPONSE_EINVAL; + const RESPONSE_NOT_STORED; + const RESPONSE_DELTA_BADVAL; + const RESPONSE_NOT_MY_VBUCKET; + const RESPONSE_AUTH_ERROR; + const RESPONSE_AUTH_CONTINUE; + const RESPONSE_UNKNOWN_COMMAND; + const RESPONSE_ENOMEM; + const RESPONSE_NOT_SUPPORTED; + const RESPONSE_EINTERNAL; + const RESPONSE_EBUSY; + const RESPONSE_ETMPFAIL; + public function __construct( $persistent_id = '', $on_new_object_cb = null ) {} - - public function get( $key, $cache_cb = null, &$cas_token = null, &$udf_flags = null ) {} - public function getByKey( $server_key, $key, $cache_cb = null, &$cas_token = null, &$udf_flags = null ) {} + public function get( $key, callable $cache_cb = null, $flags = 0) {} + + public function getByKey( $server_key, $key, callable $cache_cb = null, $flags = 0 ) {} - public function getMulti( array $keys, &$cas_tokens = null, $flags = 0, &$udf_flags = null ) {} + public function getMulti( array $keys, $flags = 0) {} - public function getMultiByKey( $server_key, array $keys, &$cas_tokens = null, $flags = 0, &$udf_flags = null ) {} + public function getMultiByKey( $server_key, array $keys, $flags = 0) {} public function getDelayed( array $keys, $with_cas = null, $value_cb = null ) {} public function getDelayedByKey( $server_key, array $keys, $with_cas = null, $value_cb = null ) {} public function fetch( ) {} - + public function fetchAll( ) {} public function set( $key, $value, $expiration = 0, $udf_flags = 0 ) {} @@ -250,7 +322,7 @@ public function increment( $key, $offset = 1, $initial_value = 0, $expiry = 0) { public function decrement( $key, $offset = 1, $initial_value = 0, $expiry = 0) {} public function getOption( $option ) {} - + public function setOption( $option, $value ) {} public function setOptions( array $options ) {} @@ -275,8 +347,12 @@ public function getLastDisconnectedServer( ) {} public function flush( $delay = 0 ) {} - public function getStats( ) {} - + public function flushBuffers( ) {} + + public function getStats( $type = null ) {} + + public function getAllKeys( ) {} + public function getVersion( ) {} public function getResultCode( ) {} @@ -289,6 +365,8 @@ public function isPristine( ) {} public function setSaslAuthData( $username, $password ) {} + public function setEncodingKey( $key ) {} + } class MemcachedException extends Exception { diff --git a/memcached.ini b/memcached.ini index 59001aaf..5decf399 100644 --- a/memcached.ini +++ b/memcached.ini @@ -2,45 +2,38 @@ ; Use session locking ; valid values: On, Off ; the default is On -memcached.sess_locking = On - -; !! DEPRECATED AND REMOVED in 3.x !! -; memcached.sess_lock_wait = 150000 - -; !! DEPRECATED AND REMOVED in 3.x !! -; memcached.sess_lock_max_wait = 0; +;memcached.sess_locking = On ; The minimum time, in milliseconds, to wait between session lock attempts. ; This value is double on each lock retry until memcached.sess_lock_wait_max ; is reached, after which any further retries will take sess_lock_wait_max seconds. -; Default is 1000. -memcached.sess_lock_wait_min = 1000; +; Default is 150. +;memcached.sess_lock_wait_min = 150; ; The maximum time, in milliseconds, to wait between session lock attempts. -; Default is 2000. -memcached.sess_lock_wait_max = 2000; +; Default is 150. +;memcached.sess_lock_wait_max = 150; ; The number of times to retry locking the session lock, not including the first attempt. ; Default is 5. -memcached.sess_lock_retries = 5; +;memcached.sess_lock_retries = 5; ; The time, in seconds, before a lock should release itself. ; Setting to 0 results in the default behaviour, which is to -; use the memcached.sess_lock_max_wait setting. If that is -; also 0, max_execution_time will be used. -memcached.sess_lock_expire = 0; +; use PHP's max_execution_time. +;memcached.sess_lock_expire = 0; ; memcached session key prefix ; valid values are strings less than 219 bytes long ; the default value is "memc.sess.key." -memcached.sess_prefix = "memc.sess.key." +;memcached.sess_prefix = "memc.sess.key." ; Whether or not to re-use the memcached connections corresponding to the value(s) ; of session.save_path after the execution of the script ends. ; Don't use this if certain settings (e.g. SASL settings, sess_binary_protocol) would ; be overridden between requests. ; Default is Off. -memcached.sess_persistent = Off +;memcached.sess_persistent = Off ; memcached session consistent hash mode ; if set to On, consistent hashing (libketama) is used @@ -48,47 +41,59 @@ memcached.sess_persistent = Off ; When consistent hashing is used, one can add or remove cache ; node(s) without messing up too much with existing keys ; default is On -memcached.sess_consistent_hash = On +;memcached.sess_consistent_hash = On + +; memcached session consistent hash type +; if set to 'ketama', consistent hashing (libketama) is used +; for session handling (default for php-memcached 3.x) +; if set to 'ketama_weighted', weighted consistent hashing (libketama) is used +; for session handling (default for php-memcached 2.x) +;memcached.sess_consistent_hash_type = "ketama" ; Allow failed memcached server to automatically be removed. ; Default is Off. (In previous versions, this setting was called memcached.sess_remove_failed) -memcached.sess_remove_failed_servers = Off +;memcached.sess_remove_failed_servers = Off + +; Set this value to enable the server be removed after +; configured number of continuous times connection failure. +;memcached.sess_server_failure_limit = 0 ; Write data to a number of additional memcached servers ; This is "poor man's HA" as libmemcached calls it. -; If this value is positive and sess_remove_failed is enabled +; If this value is positive and sess_remove_failed_servers is enabled ; when a memcached server fails the session will continue to be available ; from a replica. However, if the failed memcache server ; becomes available again it will read the session from there ; which could have old data or no data at all -memcached.sess_number_of_replicas = 0 +;memcached.sess_number_of_replicas = 0 ; Use the memcached binary protocol for memcached sessions (Instead of the text protocol) ; libmemcached replicas work only if binary mode is enabled. ; However, certain proxies (such as twemproxy) will work only if the binary protocol is disabled. -; Default is On. In older versions of php-memcached, this setting was Off and was called memcached.sess_binary. -memcached.sess_binary_protocol = On +; In older versions of php-memcached, this setting was Off and was called memcached.sess_binary. +; Default is On with libmemcached 1.0.18 or newer. +; Default is Off with older version. +;memcached.sess_binary_protocol = On ; memcached session replica read randomize -memcached.sess_randomize_replica_read = Off +;memcached.sess_randomize_replica_read = Off ; memcached connect timeout value ; In non-blocking mode this changes the value of the timeout ; during socket connection in milliseconds. Specifying -1 means an infinite timeout. -memcached.sess_connect_timeout = 1000 +;memcached.sess_connect_timeout = 1000 ; Session SASL username ; Both username and password need to be set for SASL to be enabled -; In addition to this memcached.use_sasl needs to be on -memcached.sess_sasl_username = NULL +;memcached.sess_sasl_username = NULL ; Session SASL password -memcached.sess_sasl_password = NULL +;memcached.sess_sasl_password = NULL ; Set the compression type ; valid values are: fastlz, zlib ; the default is fastlz -memcached.compression_type = "fastlz" +;memcached.compression_type = "fastlz" ; Compression factor ; Store compressed value only if the compression @@ -98,13 +103,13 @@ memcached.compression_type = "fastlz" ; plain_len > comp_len * factor ; ; the default value is 1.3 (23% space saving) -memcached.compression_factor = "1.3" +;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 +;memcached.compression_threshold = 2000 ; Set the default serializer for new memcached objects. ; valid values are: php, igbinary, json, json_array, msgpack @@ -119,14 +124,20 @@ memcached.compression_threshold = 2000 ; msgpack - a cross-language binary serializer ; ; The default is igbinary if available, then msgpack if available, then php otherwise. -memcached.serializer = "igbinary" +;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 2 -memcached.store_retry_count = 2 +; 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, @@ -137,7 +148,7 @@ memcached.store_retry_count = 2 ; 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 +;memcached.default_consistent_hash = Off ; Sets the default memcached protocol for new connections. ; (To configure the memcached protocol for connections used by sessions, @@ -146,7 +157,7 @@ memcached.default_consistent_hash = Off ; 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 +;memcached.default_binary_protocol = Off ; Sets the default memcached connection timeout for new connections. ; (To configure the memcached connection timeout for sessions, @@ -155,4 +166,4 @@ memcached.default_binary_protocol = Off ; 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.default_connect_timeout = 0 diff --git a/package.xml b/package.xml index 244acfab..5565863e 100644 --- a/package.xml +++ b/package.xml @@ -21,40 +21,36 @@ http://pear.php.net/dtd/package-2.0.xsd"> mkoppanen@php.net yes - 2016-02-22 + + 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.0.0a1 - 3.0.0 + 3.3.1dev + 3.3.0 - alpha - alpha + beta + stable PHP -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 +- @@ -69,6 +65,9 @@ Tests + + + @@ -81,6 +80,7 @@ Tests + @@ -93,7 +93,9 @@ Tests + + @@ -108,6 +110,7 @@ Tests + @@ -119,11 +122,14 @@ Tests + + + @@ -138,10 +144,13 @@ Tests + + + @@ -149,21 +158,33 @@ Tests + - + + + + + + + + + + + + @@ -176,12 +197,347 @@ Tests 1.4.0b1 + + + igbinary + 2.0 + + + msgpack + 2.0 + + memcached - + + + + + + + + + + + 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) + + + + 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 diff --git a/php_libmemcached_compat.c b/php_libmemcached_compat.c index bd35d8fe..4e294647 100644 --- a/php_libmemcached_compat.c +++ b/php_libmemcached_compat.c @@ -18,20 +18,42 @@ #include "php_memcached_private.h" #include "php_libmemcached_compat.h" -memcached_return php_memcached_exist (memcached_st *memc, zend_string *key) +memcached_return php_memcached_exist(memcached_st *memc, zend_string *key) { #ifdef HAVE_MEMCACHED_EXIST - return memcached_exist (memc, key->val, key->len); + 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); + value = memcached_get(memc, key->val, key->len, &value_length, &flags, &rc); if (value) { - free (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); +} + diff --git a/php_libmemcached_compat.h b/php_libmemcached_compat.h index e740d310..42a409dc 100644 --- a/php_libmemcached_compat.h +++ b/php_libmemcached_compat.h @@ -22,35 +22,10 @@ memcached_return php_memcached_exist (memcached_st *memc, zend_string *key); -#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x00052000 -# define MEMCACHED_SERVER_TEMPORARILY_DISABLED (1024 << 2) -#endif - -#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x01000002 -# define HAVE_MEMCACHED_TOUCH 1 -#endif +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 -# define HAVE_MEMCACHED_INSTANCE_ST 1 -#endif - -#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x00049000 -# define HAVE_LIBMEMCACHED_CHECK_CONFIGURATION 1 -#endif - -#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x01000002 -# define HAVE_MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS 1 -#endif - -#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x00049000 -# define HAVE_LIBMEMCACHED_MEMCACHED 1 -#endif - -#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x01000018 -# define HAVE_MEMCACHED_BEHAVIOR_SERVER_TIMEOUT_LIMIT 1 -#endif - -#ifdef HAVE_MEMCACHED_INSTANCE_ST typedef const memcached_instance_st * php_memcached_instance_st; #else typedef memcached_server_instance_st php_memcached_instance_st; diff --git a/php_memcached.c b/php_memcached.c index e6b741ef..c8abb844 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -14,8 +14,6 @@ +----------------------------------------------------------------------+ */ -/* $ Id: $ */ - /* TODO * - set LIBKETAMA_COMPATIBLE as the default? * - fix unserialize(serialize($memc)) @@ -39,23 +37,29 @@ #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 -#ifdef ZTS -#define MEMC_G(v) TSRMG(php_memcached_globals_id, zend_php_memcached_globals *, memc.v) -#else -#define MEMC_G(v) (php_memcached_globals.memc.v) -#endif +# include "ext/spl/spl_exceptions.h" static int le_memc; @@ -77,6 +81,8 @@ static int php_memc_list_entry(void) { #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 @@ -86,7 +92,7 @@ static int php_memc_list_entry(void) { /**************************************** Payload value flags ****************************************/ -#define MEMC_CREATE_MASK(start, n_bits) (((1 << n_bits) - 1) << start) +#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) @@ -107,11 +113,12 @@ static int php_memc_list_entry(void) { #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) +#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 @@ -148,12 +155,15 @@ 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; @@ -194,27 +204,76 @@ static inline php_memc_object_t *php_memc_fetch_object(zend_object *obj) { 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); + 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; +} -#define MEMC_CHECK_KEY(intern, key) \ - if (UNEXPECTED(ZSTR_LEN(key) == 0 || \ - ZSTR_LEN(key) > MEMC_OBJECT_KEY_MAX_LENGTH || \ - (memcached_behavior_get(intern->memc, \ - MEMCACHED_BEHAVIOR_BINARY_PROTOCOL) ? \ - strchr(ZSTR_VAL(key), '\n') : \ - strchr(ZSTR_VAL(key), ' ')))) { \ - intern->rescode = MEMCACHED_BAD_KEY_PROVIDED; \ - RETURN_FALSE; \ +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; } +} -#ifdef HAVE_MEMCACHED_PROTOCOL +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; @@ -225,28 +284,14 @@ static inline php_memc_server_t *php_memc_server_fetch_object(zend_object *obj) } #define Z_MEMC_SERVER_P(zv) php_memc_server_fetch_object(Z_OBJ_P(zv)) -#ifdef ZTS -#define MEMC_SERVER_G(v) TSRMG(php_memcached_globals_id, zend_php_memcached_globals *, server.v) -#else -#define MEMC_SERVER_G(v) (php_memcached_globals.server.v) -#endif +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; -#ifdef HAVE_MEMCACHED_PROTOCOL -static zend_object_handlers memcached_server_object_handlers; -static zend_class_entry *memcached_server_ce = NULL; -#endif - -#ifdef HAVE_SPL -static zend_class_entry *spl_ce_RuntimeException = NULL; -#endif - ZEND_DECLARE_MODULE_GLOBALS(php_memcached) #ifdef COMPILE_DL_MEMCACHED @@ -261,6 +306,10 @@ static PHP_INI_MH(OnUpdateCompressionType) 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; } @@ -294,6 +343,7 @@ static PHP_INI_MH(OnUpdateSerializer) return OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); } +#ifdef HAVE_MEMCACHED_SESSION static PHP_INI_MH(OnUpdateDeprecatedLockValue) { @@ -307,49 +357,80 @@ static PHP_INI_MH(OnUpdateSessionPrefixString) { if (new_value && ZSTR_LEN(new_value) > 0) { - char *ptr = ZSTR_VAL(new_value); - - while (*ptr != '\0') { - if (isspace (*ptr++)) { - php_error_docref(NULL, E_WARNING, "memcached.sess_prefix cannot contain whitespace characters"); - return FAILURE; - } - } 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_ENTRY("locking", "1", OnUpdateBool, lock_enabled) - MEMC_SESSION_INI_ENTRY("lock_wait_min", "1000", OnUpdateLongGEZero, lock_wait_min) - MEMC_SESSION_INI_ENTRY("lock_wait_max", "2000", OnUpdateLongGEZero, lock_wait_max) + 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) - MEMC_SESSION_INI_ENTRY("binary_protocol", "1", OnUpdateBool, binary_protocol_enabled) - MEMC_SESSION_INI_ENTRY("consistent_hash", "1", OnUpdateBool, consistent_hash_enabled) +#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_ENTRY("randomize_replica_read", "0", OnUpdateLongGEZero, randomize_replica_read_enabled) - MEMC_SESSION_INI_ENTRY("remove_failed_servers", "0", OnUpdateBool, remove_failed_servers_enabled) + 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_ENTRY("connect_timeout", "0", OnUpdateLongGEZero, connect_timeout) + 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_ENTRY("prefix", "memc.sess.", OnUpdateSessionPrefixString, prefix) - MEMC_SESSION_INI_ENTRY("persistent", "0", OnUpdateBool, persistent_enabled) + 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) @@ -359,18 +440,24 @@ PHP_INI_BEGIN() 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", "2", OnUpdateLong, store_retry_count) + MEMC_INI_ENTRY("store_retry_count", "0", OnUpdateLong, store_retry_count) + MEMC_INI_ENTRY("item_size_limit", "0", OnUpdateLongGEZero, item_size_limit) - MEMC_INI_ENTRY("default_consistent_hash", "0", OnUpdateBool, default_behavior.consistent_hash_enabled) - MEMC_INI_ENTRY("default_binary_protocol", "0", OnUpdateBool, default_behavior.binary_protocol_enabled) - MEMC_INI_ENTRY("default_connect_timeout", "0", OnUpdateLongGEZero, default_behavior.connect_timeout) + 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 /**************************************** @@ -451,7 +538,7 @@ char *php_memc_printable_func (zend_fcall_info *fci, zend_fcall_info_cache *fci_ char *buffer = NULL; if (fci->object) { - spprintf (&buffer, 0, "%s::%s", ZSTR_VAL(fci->object->ce->name), fci_cache->function_handler->common.function_name); + 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)); @@ -816,11 +903,12 @@ zend_bool s_invoke_cache_callback(zval *zobject, zend_fcall_info *fci, zend_fcal ****************************************/ static -zend_bool s_compress_value (php_memc_compression_type compression_type, zend_string **payload_in, uint32_t *flags) +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); @@ -838,19 +926,46 @@ zend_bool s_compress_value (php_memc_compression_type compression_type, zend_str if (compressed_size > 0) { compress_status = 1; - MEMC_VAL_SET_FLAG(*flags, MEMC_VAL_COMPRESSION_FASTLZ); + 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: { - compressed_size = buffer_size; - int status = compress((Bytef *) buffer, &compressed_size, (Bytef *) ZSTR_VAL(payload), ZSTR_LEN(payload)); + 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; - MEMC_VAL_SET_FLAG(*flags, MEMC_VAL_COMPRESSION_ZLIB); + compression_type_flag = MEMC_VAL_COMPRESSION_ZLIB; } } break; @@ -860,30 +975,30 @@ zend_bool s_compress_value (php_memc_compression_type compression_type, zend_str break; } - if (!compress_status) { - php_error_docref(NULL, E_WARNING, "could not compress value"); - efree (buffer); - return 0; + /* 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; } - /* This means the value was too small to be compressed, still a success */ - if (compressed_size > (ZSTR_LEN(payload) * MEMC_G(compression_factor))) { - efree (buffer); - return 1; - } + /* 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); - MEMC_VAL_SET_FLAG(*flags, MEMC_VAL_COMPRESSED); + /* 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); - payload = zend_string_realloc(payload, compressed_size + sizeof(uint32_t), 0); + zend_string_forget_hash_val(payload); + *payload_in = payload; - /* 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); + return 1; + } - zend_string_forget_hash_val(payload); - *payload_in = payload; - return 1; + /* Original payload was not modified */ + efree(buffer); + return 0; } static @@ -904,7 +1019,7 @@ zend_bool s_serialize_value (php_memc_serializer_type serializer, zval *value, s php_error_docref(NULL, E_WARNING, "could not serialize value with igbinary"); return 0; } - smart_str_appendl (buf, buffer, buffer_len); + smart_str_appendl (buf, (char *)buffer, buffer_len); efree(buffer); MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_IGBINARY); } @@ -1024,7 +1139,6 @@ zend_string *s_zval_to_payload(php_memc_object_t *intern, zval *value, uint32_t } break; } - zend_string_forget_hash_val(payload); /* turn off compression for values below the threshold */ if (ZSTR_LEN(payload) == 0 || ZSTR_LEN(payload) < MEMC_G(compression_threshold)) { @@ -1033,11 +1147,13 @@ zend_string *s_zval_to_payload(php_memc_object_t *intern, zval *value, uint32_t /* If we have compression flag, compress the value */ if (should_compress) { - /* status */ - if (!s_compress_value (memc_user_data->compression_type, &payload, flags)) { - zend_string_release(payload); - return NULL; - } + /* 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) { @@ -1047,6 +1163,21 @@ zend_string *s_zval_to_payload(php_memc_object_t *intern, zval *value, uint32_t 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) { @@ -1062,7 +1193,7 @@ zend_bool s_memc_write_zval (php_memc_object_t *intern, php_memc_write_op op, ze { uint32_t flags = 0; zend_string *payload = NULL; - memcached_return status; + 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; @@ -1073,6 +1204,12 @@ zend_bool s_memc_write_zval (php_memc_object_t *intern, php_memc_write_op op, ze 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; @@ -1085,7 +1222,7 @@ zend_bool s_memc_write_zval (php_memc_object_t *intern, php_memc_write_op op, ze break; case MEMC_OP_TOUCH: - status = memcached_touch_by_key(intern->memc, ZSTR_VAL(server_key), ZSTR_LEN(server_key), ZSTR_VAL(key), ZSTR_LEN(key), expiration); + 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: @@ -1117,7 +1254,7 @@ zend_bool s_memc_write_zval (php_memc_object_t *intern, php_memc_write_op op, ze break; case MEMC_OP_TOUCH: - status = memcached_touch(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), expiration); + status = php_memcached_touch(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), expiration); break; case MEMC_OP_ADD: @@ -1178,9 +1315,13 @@ static PHP_METHOD(Memcached, __construct) zend_bool is_persistent = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S!f!S", &persistent_id, &fci, &fci_cache, &conn_str) == FAILURE) { - return; - } + /* "|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; @@ -1217,42 +1358,40 @@ static PHP_METHOD(Memcached, __construct) 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 */ - { -#ifdef mikko_0 - fprintf (stderr, "consistent_hash_enabled=%d binary_protocol_enabled=%d connect_timeout=%ld\n", - MEMC_G(default_behavior.consistent_hash_enabled), MEMC_G(default_behavior.binary_protocol_enabled), MEMC_G(default_behavior.connect_timeout)); -#endif - - memcached_return rc; - - if (MEMC_G(default_behavior.consistent_hash_enabled)) { - - 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.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)) { - 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)); - } + 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)) { - 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 (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)); } } @@ -1279,7 +1418,7 @@ static PHP_METHOD(Memcached, __construct) le.type = php_memc_list_entry(); le.ptr = intern->memc; - GC_REFCOUNT(&le) = 1; + 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) { @@ -1395,7 +1534,7 @@ zend_bool s_get_apply_fn(php_memc_object_t *intern, zend_string *key, zval *valu static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { - php_memc_get_ctx_t context = {}; + php_memc_get_ctx_t context = {0}; php_memc_keys_t keys = {0}; zend_long get_flags = 0; zend_string *key; @@ -1407,13 +1546,22 @@ void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) MEMC_METHOD_INIT_VARS; if (by_key) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|f!l", &server_key, &key, &fci, &fcc, &get_flags) == FAILURE) { - return; - } + /* "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 { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|f!l", &key, &fci, &fcc, &get_flags) == FAILURE) { - return; - } + /* "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; @@ -1478,7 +1626,7 @@ zend_bool s_get_multi_apply_fn(php_memc_object_t *intern, zend_string *key, zval 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); + zend_symtable_update(Z_ARRVAL_P(context->return_value), key, &node); } else { zend_symtable_update(Z_ARRVAL_P(context->return_value), key, value); @@ -1499,14 +1647,20 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke zend_bool retval, preserve_order; if (by_key) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sa|l", &server_key, - &keys, &flags) == FAILURE) { - return; - } + /* "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 { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|l", &keys, &flags) == FAILURE) { - return; - } + /* "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; @@ -1636,15 +1790,22 @@ static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ if (by_key) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sa/|bf!", &server_key, - &keys, &with_cas, &fci, &fcc) == FAILURE) { - return; - } + /* "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 { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|bf!", &keys, &with_cas, - &fci, &fcc) == FAILURE) { - return; - } + /* "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; @@ -1753,7 +1914,6 @@ PHP_METHOD(Memcached, setByKey) } /* }}} */ -#ifdef HAVE_MEMCACHED_TOUCH /* {{{ Memcached::touch(string key, [, int expiration ]) Sets a new expiration for the given key */ PHP_METHOD(Memcached, touch) @@ -1769,8 +1929,6 @@ PHP_METHOD(Memcached, touchByKey) php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_TOUCH, 1); } /* }}} */ -#endif - /* {{{ Memcached::setMulti(array items [, int expiration ]) Sets the keys/values specified in the items array */ @@ -1793,7 +1951,7 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke { zval *entries; zend_string *server_key = NULL; - time_t expiration = 0; + zend_long expiration = 0; zval *value; zend_string *skey; zend_ulong num_key; @@ -1801,14 +1959,20 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke MEMC_METHOD_INIT_VARS; if (by_key) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sa|ll", &server_key, - &entries, &expiration) == FAILURE) { - return; - } + /* "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 { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|ll", &entries, &expiration) == FAILURE) { - return; - } + /* "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; @@ -1827,9 +1991,8 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke str_key = zend_string_init(tmp_key, tmp_len, 0); } - if (!s_memc_write_zval (intern, MEMC_OP_SET, server_key, str_key, value, expiration)) { - php_error_docref(NULL, E_WARNING, "failed to set key %s", ZSTR_VAL(str_key)); - } + /* 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); @@ -1918,35 +2081,56 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool if (by_key) { if (op == MEMC_OP_APPEND || op == MEMC_OP_PREPEND) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "SSS", &server_key, &key, &s_value) == FAILURE) { - return; - } + /* "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) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|l", &server_key, &key, &expiration) == FAILURE) { - return; - } + /* "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 { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "SSz|l", &server_key, &key, &value, &expiration) == FAILURE) { - return; - } + /* "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) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &key, &s_value) == FAILURE) { - return; - } + /* "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) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|l", &key, &expiration) == FAILURE) { - return; - } + /* "S|l */ + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_STR(key) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(expiration) + ZEND_PARSE_PARAMETERS_END(); } else { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz|l", &key, &value, &expiration) == FAILURE) { - return; - } + /* "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(); } } @@ -1966,15 +2150,6 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool } } - - if (op == MEMC_OP_TOUCH) { -#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x01000016 - if (memcached_behavior_get(intern->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.16"); - } -#endif - } - if (!s_memc_write_zval (intern, op, server_key, key, value, expiration)) { RETURN_FALSE; } @@ -1990,22 +2165,31 @@ static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) zend_string *key; zend_string *server_key = NULL; zval *value; - time_t expiration = 0; + zend_long expiration = 0; zend_string *payload; uint32_t flags = 0; memcached_return status; MEMC_METHOD_INIT_VARS; if (by_key) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zSSz|ll", &zv_cas, &server_key, &key, - &value, &expiration) == FAILURE) { - return; - } + /* "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 { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zSz|ll", &zv_cas, &key, &value, - &expiration) == FAILURE) { - return; - } + /* "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; @@ -2020,6 +2204,12 @@ static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) 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 { @@ -2087,18 +2277,25 @@ PHP_METHOD(Memcached, deleteMultiByKey) static void php_memc_delete_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) { zend_string *key, *server_key; - time_t expiration = 0; + zend_long expiration = 0; memcached_return status; MEMC_METHOD_INIT_VARS; if (by_key) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|l", &server_key, &key, &expiration) == FAILURE) { - return; - } + /* "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 { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|l", &key, &expiration) == FAILURE) { - return; - } + /* "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; } @@ -2126,20 +2323,27 @@ static void php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by { zval *entries, *zv, ret; zend_string *server_key = NULL; - time_t expiration = 0; + zend_long expiration = 0; zend_string *entry; memcached_return status; MEMC_METHOD_INIT_VARS; if (by_key) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sa/|l", &server_key, &entries, &expiration) == FAILURE) { - return; - } + /* "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 { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/|l", &entries, &expiration) == FAILURE) { - return; - } + /* "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; @@ -2177,22 +2381,34 @@ static void php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by static void php_memc_incdec_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key, zend_bool incr) { zend_string *key, *server_key = NULL; - long offset = 1; - uint64_t value = UINT64_MAX, initial = 0; - time_t expiry = 0; + 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) { - if (zend_parse_parameters(n_args, "S|lll", &key, &offset, &initial, &expiry) == FAILURE) { - return; - } + /* "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 { - if (zend_parse_parameters(n_args, "SS|lll", &server_key, &key, &offset, &initial, &expiry) == FAILURE) { - return; - } + /* "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; @@ -2200,22 +2416,27 @@ static void php_memc_incdec_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key, MEMC_CHECK_KEY(intern, key); if (offset < 0) { - php_error_docref(NULL, E_WARNING, "offset has to be > 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), (unsigned int)offset, &value); + 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), (unsigned int)offset, &value); + 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(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), (unsigned int)offset, &value); + 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(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), (unsigned int)offset, &value); + status = memcached_decrement_by_key(intern->memc, ZSTR_VAL(key), ZSTR_LEN(key), ZSTR_VAL(key), ZSTR_LEN(key), offset, &value); } } @@ -2229,15 +2450,15 @@ static void php_memc_incdec_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key, } 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), (unsigned int)offset, initial, expiry, &value); + 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), (unsigned int)offset, initial, expiry, &value); + 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), (unsigned int)offset, initial, expiry, &value); + 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), (unsigned int)offset, initial, expiry, &value); + 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) { @@ -2294,28 +2515,22 @@ PHP_METHOD(Memcached, incrementByKey) PHP_METHOD(Memcached, addServer) { zend_string *host; - long port, weight = 0; + zend_long port, weight = 0; memcached_return status; MEMC_METHOD_INIT_VARS; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sl|l", &host, &port, &weight) == FAILURE) { - return; - } + /* "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); -#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x01000002 - if (ZSTR_VAL(host)[0] == '/') { /* unix domain socket */ - status = memcached_server_add_unix_socket_with_weight(intern->memc, ZSTR_VAL(host), weight); - } else if (memcached_behavior_get(intern->memc, MEMCACHED_BEHAVIOR_USE_UDP)) { - status = memcached_server_add_udp_with_weight(intern->memc, ZSTR_VAL(host), port, weight); - } else { - status = memcached_server_add_with_weight(intern->memc, ZSTR_VAL(host), port, weight); - } -#else status = memcached_server_add_with_weight(intern->memc, ZSTR_VAL(host), port, weight); -#endif if (s_memc_status_handle_result_code(intern, status) == FAILURE) { RETURN_FALSE; @@ -2338,9 +2553,10 @@ PHP_METHOD(Memcached, addServers) memcached_return status; MEMC_METHOD_INIT_VARS; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/", &servers) == FAILURE) { - return; - } + /* "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); @@ -2442,9 +2658,10 @@ PHP_METHOD(Memcached, getServerByKey) memcached_return error; MEMC_METHOD_INIT_VARS; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &server_key) == FAILURE) { - return; - } + /* "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); @@ -2511,7 +2728,6 @@ PHP_METHOD(Memcached, flushBuffers) } /* }}} */ -#ifdef HAVE_LIBMEMCACHED_CHECK_CONFIGURATION /* {{{ Memcached::getLastErrorMessage() Returns the last error message that occurred */ PHP_METHOD(Memcached, getLastErrorMessage) @@ -2559,7 +2775,6 @@ PHP_METHOD(Memcached, getLastErrorErrno) RETURN_LONG(memcached_last_error_errno(intern->memc)); } /* }}} */ -#endif /* {{{ Memcached::getLastDisconnectedServer() Returns the last disconnected server @@ -2637,7 +2852,7 @@ memcached_return s_stat_execute_cb (php_memcached_instance_st instance, const ch server_values = zend_hash_add(Z_ARRVAL_P(return_value), server_key, &zv); } - spprintf (&buffer, 0, "%.*s", value_length, value); + spprintf (&buffer, 0, "%.*s", (int)value_length, value); /* Check type */ if (s_long_value (buffer, &long_val)) { @@ -2660,16 +2875,35 @@ memcached_return s_stat_execute_cb (php_memcached_instance_st instance, const ch 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; - if (zend_parse_parameters_none() == FAILURE) { - return; - } + /* "|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, NULL, s_stat_execute_cb, 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; @@ -2734,7 +2968,15 @@ PHP_METHOD(Memcached, getAllKeys) array_init(return_value); rc = memcached_dump(intern->memc, callback, return_value, 1); - if (s_memc_status_handle_result_code(intern, rc) == FAILURE) { + + /* 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; } @@ -2745,13 +2987,15 @@ PHP_METHOD(Memcached, getAllKeys) Flushes the data on all the servers */ static PHP_METHOD(Memcached, flush) { - time_t delay = 0; + zend_long delay = 0; memcached_return status; MEMC_METHOD_INIT_VARS; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &delay) == FAILURE) { - return; - } + /* "|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); @@ -2769,14 +3013,15 @@ static PHP_METHOD(Memcached, flush) Returns the value for the given option constant */ static PHP_METHOD(Memcached, getOption) { - long option; + zend_long option; uint64_t result; memcached_behavior flag; MEMC_METHOD_INIT_VARS; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &option) == FAILURE) { - return; - } + /* "l" */ + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_LONG(option) + ZEND_PARSE_PARAMETERS_END(); MEMC_METHOD_FETCH_OBJECT; @@ -2784,9 +3029,15 @@ static PHP_METHOD(Memcached, getOption) 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; @@ -2794,11 +3045,7 @@ static PHP_METHOD(Memcached, getOption) result = memcached_callback_get(intern->memc, MEMCACHED_CALLBACK_PREFIX_KEY, &retval); if (retval == MEMCACHED_SUCCESS && result) { -#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX == 0x00049000 - RETURN_STRINGL(result, strlen(result)); -#else RETURN_STRING(result); -#endif } else { RETURN_EMPTY_STRING(); } @@ -2850,6 +3097,9 @@ int php_memc_set_option(php_memc_object_t *intern, long option, zval *value) 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 { @@ -2859,27 +3109,29 @@ int php_memc_set_option(php_memc_object_t *intern, long option, zval *value) } 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; -#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX == 0x00049000 - char tmp[MEMCACHED_PREFIX_KEY_MAX_SIZE - 1]; -#endif str = zval_get_string(value); - if (ZSTR_VAL(str) == 0) { + if (ZSTR_LEN(str) == 0) { key = NULL; } else { - /* - work-around a bug in libmemcached in version 0.49 that truncates the trailing - character of the key prefix, to avoid the issue we pad it with a '0' - */ -#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX == 0x00049000 - snprintf(tmp, sizeof(tmp), "%s0", ZSTR_VAL(str)); - key = tmp; -#else key = ZSTR_VAL(str); -#endif } if (memcached_callback_set(intern->memc, MEMCACHED_CALLBACK_PREFIX_KEY, key) == MEMCACHED_BAD_KEY_PROVIDED) { zend_string_release(str); @@ -2908,14 +3160,9 @@ int php_memc_set_option(php_memc_object_t *intern, long option, zval *value) * (non-weighted) case. We have to clean up ourselves. */ if (!lval) { -#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX > 0x00037000 - (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); -#else - intern->memc->hash = 0; - intern->memc->distribution = 0; -#endif + (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; @@ -2985,6 +3232,11 @@ int php_memc_set_option(php_memc_object_t *intern, long option, zval *value) 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 { @@ -3039,7 +3291,7 @@ PHP_METHOD(Memcached, setBucket) { zval *zserver_map; zval *zforward_map = NULL; - long replicas = 0; + zend_long replicas = 0; zend_bool retval = 1; uint32_t *server_map = NULL, *forward_map = NULL; @@ -3047,9 +3299,12 @@ PHP_METHOD(Memcached, setBucket) memcached_return rc; MEMC_METHOD_INIT_VARS; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "aa!l", &zserver_map, &zforward_map, &replicas) == FAILURE) { - return; - } + /* "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; @@ -3086,7 +3341,7 @@ PHP_METHOD(Memcached, setBucket) 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;; + retval = 0; } efree(server_map); @@ -3105,14 +3360,16 @@ static PHP_METHOD(Memcached, setOptions) zval *options; zend_bool ok = 1; zend_string *key; - ulong key_index; + zend_ulong key_index; zval *value; MEMC_METHOD_INIT_VARS; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &options) == FAILURE) { - return; - } + /* "a" */ + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ARRAY(options) + ZEND_PARSE_PARAMETERS_END(); + MEMC_METHOD_FETCH_OBJECT; @@ -3135,13 +3392,15 @@ static PHP_METHOD(Memcached, setOptions) Sets the value for the given option constant */ static PHP_METHOD(Memcached, setOption) { - long option; + zend_long option; zval *value; MEMC_METHOD_INIT_VARS; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz/", &option, &value) == FAILURE) { - return; - } + /* "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; @@ -3158,9 +3417,11 @@ static PHP_METHOD(Memcached, setSaslAuthData) memcached_return status; zend_string *user, *pass; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &user, &pass) == FAILURE) { - return; - } + /* "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; @@ -3183,6 +3444,42 @@ static PHP_METHOD(Memcached, setSaslAuthData) /* }}} */ #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) @@ -3265,6 +3562,24 @@ static PHP_METHOD(Memcached, isPristine) } /* }}} */ +/* {{{ 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 ****************************************/ @@ -3317,6 +3632,8 @@ 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); } @@ -3330,6 +3647,7 @@ zend_object *php_memc_server_new(zend_class_entry *ce) object_properties_init(&intern->zo, ce); intern->zo.handlers = &memcached_server_object_handlers; + intern->handler = php_memc_proto_handler_new(); return &intern->zo; } @@ -3384,7 +3702,7 @@ memcached_return s_server_cursor_version_cb(const memcached_st *ptr, php_memcach instance->micro_version); #endif - address = strpprintf(0, "%s:%d", memcached_server_name(instance), memcached_server_port(instance) - 1); + 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); @@ -3403,17 +3721,25 @@ zend_string *s_decompress_value (const char *payload, size_t payload_len, uint32 uint32_t stored_length; unsigned long length; zend_bool decompress_status = 0; - zend_bool is_fastlz = 0, is_zlib = 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); - if (!is_fastlz && !is_zlib) { - php_error_docref(NULL, E_WARNING, "could not decompress value: unrecognised encryption type"); +#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; } @@ -3424,11 +3750,31 @@ zend_string *s_decompress_value (const char *payload, size_t payload_len, uint32 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) { - decompress_status = (uncompress((Bytef *) buffer->val, &buffer->len, (Bytef *)payload, payload_len) == Z_OK); + 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'; @@ -3574,6 +3920,7 @@ zend_bool s_memcached_result_to_zval(memcached_st *memc, memcached_result_st *re default: php_error_docref(NULL, E_WARNING, "unknown payload type"); + retval = 0; break; } zend_string_release(data); @@ -3597,7 +3944,6 @@ zend_class_entry *php_memc_get_exception(void) PHP_MEMCACHED_API zend_class_entry *php_memc_get_exception_base(int root) { -#ifdef HAVE_SPL if (!root) { if (!spl_ce_RuntimeException) { zend_class_entry *pce; @@ -3614,7 +3960,7 @@ zend_class_entry *php_memc_get_exception_base(int root) return spl_ce_RuntimeException; } } -#endif + return zend_exception_get_default(); } @@ -3642,9 +3988,10 @@ PHP_METHOD(MemcachedServer, run) php_memc_server_t *intern; intern = Z_MEMC_SERVER_P(getThis()); - if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &address) == FAILURE) { - return; - } + /* "S" */ + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_STR(address) + ZEND_PARSE_PARAMETERS_END(); rc = php_memc_proto_handler_run(intern->handler, address); @@ -3658,14 +4005,16 @@ PHP_METHOD(MemcachedServer, run) static PHP_METHOD(MemcachedServer, on) { - long event; + zend_long event; zend_fcall_info fci; zend_fcall_info_cache fci_cache; zend_bool rc = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "lf!", &event, &fci, &fci_cache) == FAILURE) { - return; - } + /* "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; @@ -3679,7 +4028,7 @@ PHP_METHOD(MemcachedServer, on) Z_TRY_ADDREF(fci.function_name); if (fci.object) { - GC_REFCOUNT(fci.object)++; + GC_ADDREF(fci.object); } } RETURN_BOOL(rc); @@ -3687,389 +4036,11 @@ PHP_METHOD(MemcachedServer, on) #endif -/* {{{ methods arginfo */ -ZEND_BEGIN_ARG_INFO_EX(arginfo___construct, 0, 0, 0) - ZEND_ARG_INFO(0, persistent_id) - ZEND_ARG_INFO(0, callback) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_getResultCode, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_getResultMessage, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_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_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_getMulti, 0, 0, 1) - ZEND_ARG_ARRAY_INFO(0, keys, 0) - ZEND_ARG_INFO(0, get_flags) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_getMultiByKey, 0, 0, 2) - ZEND_ARG_INFO(0, server_key) - ZEND_ARG_ARRAY_INFO(0, keys, 0) - ZEND_ARG_INFO(0, get_flags) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_getDelayed, 0, 0, 1) - ZEND_ARG_ARRAY_INFO(0, keys, 0) - ZEND_ARG_INFO(0, with_cas) - ZEND_ARG_INFO(0, value_cb) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_getDelayedByKey, 0, 0, 2) - ZEND_ARG_INFO(0, server_key) - ZEND_ARG_ARRAY_INFO(0, keys, 0) - ZEND_ARG_INFO(0, with_cas) - ZEND_ARG_INFO(0, value_cb) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_fetch, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_fetchAll, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_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_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_touch, 0, 0, 2) - ZEND_ARG_INFO(0, key) - ZEND_ARG_INFO(0, expiration) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_touchByKey, 0, 0, 3) - 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_setMulti, 0, 0, 1) - ZEND_ARG_ARRAY_INFO(0, items, 0) - ZEND_ARG_INFO(0, expiration) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_setMultiByKey, 0, 0, 2) - ZEND_ARG_INFO(0, server_key) - ZEND_ARG_ARRAY_INFO(0, items, 0) - ZEND_ARG_INFO(0, expiration) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_add, 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_addByKey, 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_replace, 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_replaceByKey, 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_append, 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_appendByKey, 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_prepend, 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_prependByKey, 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_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_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() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_delete, 0, 0, 1) - ZEND_ARG_INFO(0, key) - ZEND_ARG_INFO(0, time) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_deleteMulti, 0, 0, 1) - ZEND_ARG_INFO(0, keys) - ZEND_ARG_INFO(0, time) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_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_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_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() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_decrement, 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() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_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() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_decrementByKey, 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() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_flush, 0, 0, 0) - ZEND_ARG_INFO(0, delay) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_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(arginfo_addServers, 0) - ZEND_ARG_ARRAY_INFO(0, servers, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_getServerList, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_resetServerList, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_quit, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_flushBuffers, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_getServerByKey, 0) - ZEND_ARG_INFO(0, server_key) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_getLastErrorMessage, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_getLastErrorCode, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_getLastErrorErrno, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_getLastDisconnectedServer, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_getOption, 0) - ZEND_ARG_INFO(0, option) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_setSaslAuthData, 0) - ZEND_ARG_INFO(0, username) - ZEND_ARG_INFO(0, password) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_setOption, 0) - ZEND_ARG_INFO(0, option) - ZEND_ARG_INFO(0, value) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_setOptions, 0) - ZEND_ARG_INFO(0, options) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_setBucket, 3) - ZEND_ARG_INFO(0, host_map) - ZEND_ARG_INFO(0, forward_map) - ZEND_ARG_INFO(0, replicas) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_getStats, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_getVersion, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_isPersistent, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_isPristine, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_getAllKeys, 0) -ZEND_END_ARG_INFO() -/* }}} */ - -/* {{{ memcached_class_methods */ -#define MEMC_ME(name, args) PHP_ME(Memcached, name, args, ZEND_ACC_PUBLIC) -static zend_function_entry memcached_class_methods[] = { - MEMC_ME(__construct, arginfo___construct) - - MEMC_ME(getResultCode, arginfo_getResultCode) - MEMC_ME(getResultMessage, arginfo_getResultMessage) - - MEMC_ME(get, arginfo_get) - MEMC_ME(getByKey, arginfo_getByKey) - MEMC_ME(getMulti, arginfo_getMulti) - MEMC_ME(getMultiByKey, arginfo_getMultiByKey) - MEMC_ME(getDelayed, arginfo_getDelayed) - MEMC_ME(getDelayedByKey, arginfo_getDelayedByKey) - MEMC_ME(fetch, arginfo_fetch) - MEMC_ME(fetchAll, arginfo_fetchAll) - - MEMC_ME(set, arginfo_set) - MEMC_ME(setByKey, arginfo_setByKey) -#ifdef HAVE_MEMCACHED_TOUCH - MEMC_ME(touch, arginfo_touch) - MEMC_ME(touchByKey, arginfo_touchByKey) -#endif - MEMC_ME(setMulti, arginfo_setMulti) - MEMC_ME(setMultiByKey, arginfo_setMultiByKey) - - MEMC_ME(cas, arginfo_cas) - MEMC_ME(casByKey, arginfo_casByKey) - MEMC_ME(add, arginfo_add) - MEMC_ME(addByKey, arginfo_addByKey) - MEMC_ME(append, arginfo_append) - MEMC_ME(appendByKey, arginfo_appendByKey) - MEMC_ME(prepend, arginfo_prepend) - MEMC_ME(prependByKey, arginfo_prependByKey) - MEMC_ME(replace, arginfo_replace) - MEMC_ME(replaceByKey, arginfo_replaceByKey) - MEMC_ME(delete, arginfo_delete) - MEMC_ME(deleteMulti, arginfo_deleteMulti) - MEMC_ME(deleteByKey, arginfo_deleteByKey) - MEMC_ME(deleteMultiByKey, arginfo_deleteMultiByKey) - - MEMC_ME(increment, arginfo_increment) - MEMC_ME(decrement, arginfo_decrement) - MEMC_ME(incrementByKey, arginfo_incrementByKey) - MEMC_ME(decrementByKey, arginfo_decrementByKey) - - MEMC_ME(addServer, arginfo_addServer) - MEMC_ME(addServers, arginfo_addServers) - MEMC_ME(getServerList, arginfo_getServerList) - MEMC_ME(getServerByKey, arginfo_getServerByKey) - MEMC_ME(resetServerList, arginfo_resetServerList) - MEMC_ME(quit, arginfo_quit) - MEMC_ME(flushBuffers, arginfo_flushBuffers) - -#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x00049000 - MEMC_ME(getLastErrorMessage, arginfo_getLastErrorMessage) - MEMC_ME(getLastErrorCode, arginfo_getLastErrorCode) - MEMC_ME(getLastErrorErrno, arginfo_getLastErrorErrno) -#endif - MEMC_ME(getLastDisconnectedServer, arginfo_getLastDisconnectedServer) - - MEMC_ME(getStats, arginfo_getStats) - MEMC_ME(getVersion, arginfo_getVersion) - MEMC_ME(getAllKeys, arginfo_getAllKeys) - - MEMC_ME(flush, arginfo_flush) - - MEMC_ME(getOption, arginfo_getOption) - MEMC_ME(setOption, arginfo_setOption) - MEMC_ME(setOptions, arginfo_setOptions) - MEMC_ME(setBucket, arginfo_setBucket) -#ifdef HAVE_MEMCACHED_SASL - MEMC_ME(setSaslAuthData, arginfo_setSaslAuthData) -#endif - MEMC_ME(isPersistent, arginfo_isPersistent) - MEMC_ME(isPristine, arginfo_isPristine) - { NULL, NULL, NULL } -}; -#undef MEMC_ME -/* }}} */ - -#ifdef HAVE_MEMCACHED_PROTOCOL -/* {{{ */ -#define MEMC_SE_ME(name, args) PHP_ME(MemcachedServer, name, args, ZEND_ACC_PUBLIC) -static -zend_function_entry memcached_server_class_methods[] = { - MEMC_SE_ME(run, NULL) - MEMC_SE_ME(on, NULL) - { NULL, NULL, NULL } -}; -#undef MEMC_SE_ME -/* }}} */ +#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 @@ -4086,10 +4057,8 @@ static const zend_module_dep memcached_deps[] = { #ifdef HAVE_MEMCACHED_MSGPACK ZEND_MOD_REQUIRED("msgpack") #endif -#ifdef HAVE_SPL ZEND_MOD_REQUIRED("spl") -#endif - {NULL, NULL, NULL} + ZEND_MOD_END }; #endif @@ -4097,14 +4066,15 @@ static PHP_GINIT_FUNCTION(php_memcached) { #ifdef HAVE_MEMCACHED_SESSION - php_memcached_globals->session.lock_enabled = 0; - php_memcached_globals->session.lock_wait_max = 2000; - php_memcached_globals->session.lock_wait_min = 1000; - php_memcached_globals->session.lock_retries = 5; + 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; @@ -4114,15 +4084,21 @@ PHP_GINIT_FUNCTION(php_memcached) 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; @@ -4167,49 +4143,69 @@ static void php_memc_register_constants(INIT_FUNC_ARGS) 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_LONG(HAVE_IGBINARY, 1); + 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_LONG(HAVE_IGBINARY, 0); + REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_ZSTD, 0); #endif /* * Indicate whether json serializer is available */ #ifdef HAVE_JSON_API - REGISTER_MEMC_CLASS_CONST_LONG(HAVE_JSON, 1); + REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_JSON, 1); #else - REGISTER_MEMC_CLASS_CONST_LONG(HAVE_JSON, 0); + REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_JSON, 0); #endif /* * Indicate whether msgpack serializer is available */ #ifdef HAVE_MEMCACHED_MSGPACK - REGISTER_MEMC_CLASS_CONST_LONG(HAVE_MSGPACK, 1); + 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_LONG(HAVE_MSGPACK, 0); + REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_ENCODING, 0); #endif #ifdef HAVE_MEMCACHED_SESSION - REGISTER_MEMC_CLASS_CONST_LONG(HAVE_SESSION, 1); + REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_SESSION, 1); #else - REGISTER_MEMC_CLASS_CONST_LONG(HAVE_SESSION, 0); + REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_SESSION, 0); #endif #ifdef HAVE_MEMCACHED_SASL - REGISTER_MEMC_CLASS_CONST_LONG(HAVE_SASL, 1); + REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_SASL, 1); #else - REGISTER_MEMC_CLASS_CONST_LONG(HAVE_SASL, 0); + REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_SASL, 0); #endif /* @@ -4229,9 +4225,7 @@ static void php_memc_register_constants(INIT_FUNC_ARGS) 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); -#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x00049000 REGISTER_MEMC_CLASS_CONST_LONG(DISTRIBUTION_VIRTUAL_BUCKET, MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET); -#endif 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); @@ -4257,14 +4251,10 @@ static void php_memc_register_constants(INIT_FUNC_ARGS) 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); -#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x00037000 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); -#endif -#ifdef HAVE_MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS REGISTER_MEMC_CLASS_CONST_LONG(OPT_REMOVE_FAILED_SERVERS, MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS); -#endif -#ifdef HAVE_MEMCACHED_BEHAVIOR_SERVER_TIMEOUT_LIMIT +#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x01000018 REGISTER_MEMC_CLASS_CONST_LONG(OPT_SERVER_TIMEOUT_LIMIT, MEMCACHED_BEHAVIOR_SERVER_TIMEOUT_LIMIT); #endif @@ -4272,34 +4262,47 @@ static void php_memc_register_constants(INIT_FUNC_ARGS) * 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_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_WRITE_FAILURE, MEMCACHED_WRITE_FAILURE); - REGISTER_MEMC_CLASS_CONST_LONG(RES_DATA_EXISTS, MEMCACHED_DATA_EXISTS); - REGISTER_MEMC_CLASS_CONST_LONG(RES_NOTSTORED, MEMCACHED_NOTSTORED); - 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_ERRNO, MEMCACHED_ERRNO); - REGISTER_MEMC_CLASS_CONST_LONG(RES_BUFFERED, MEMCACHED_BUFFERED); - REGISTER_MEMC_CLASS_CONST_LONG(RES_TIMEOUT, MEMCACHED_TIMEOUT); - REGISTER_MEMC_CLASS_CONST_LONG(RES_BAD_KEY_PROVIDED, MEMCACHED_BAD_KEY_PROVIDED); - REGISTER_MEMC_CLASS_CONST_LONG(RES_STORED, MEMCACHED_STORED); - REGISTER_MEMC_CLASS_CONST_LONG(RES_DELETED, MEMCACHED_DELETED); - REGISTER_MEMC_CLASS_CONST_LONG(RES_STAT, MEMCACHED_STAT); - REGISTER_MEMC_CLASS_CONST_LONG(RES_ITEM, MEMCACHED_ITEM); - REGISTER_MEMC_CLASS_CONST_LONG(RES_NOT_SUPPORTED, MEMCACHED_NOT_SUPPORTED); - REGISTER_MEMC_CLASS_CONST_LONG(RES_FETCH_NOTFINISHED, MEMCACHED_FETCH_NOTFINISHED); - 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_HOST_PROTOCOL, MEMCACHED_INVALID_HOST_PROTOCOL); + 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); @@ -4337,6 +4340,7 @@ static void php_memc_register_constants(INIT_FUNC_ARGS) */ 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. @@ -4382,12 +4386,15 @@ static void php_memc_register_constants(INIT_FUNC_ARGS) REGISTER_MEMC_CLASS_CONST_LONG(RESPONSE_ETMPFAIL, PROTOCOL_BINARY_RESPONSE_ETMPFAIL); #endif - #undef REGISTER_MEMC_CLASS_CONST_LONG - /* * 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 + } /* }}} */ @@ -4403,8 +4410,7 @@ PHP_MINIT_FUNCTION(memcached) le_memc = zend_register_list_destructors_ex(NULL, php_memc_dtor, "Memcached persistent connection", module_number); - INIT_CLASS_ENTRY(ce, "Memcached", memcached_class_methods); - memcached_ce = zend_register_internal_class(&ce); + memcached_ce = register_class_Memcached(); memcached_ce->create_object = php_memc_object_new; #ifdef HAVE_MEMCACHED_PROTOCOL @@ -4413,8 +4419,7 @@ PHP_MINIT_FUNCTION(memcached) memcached_server_object_handlers.clone_obj = NULL; memcached_server_object_handlers.free_obj = php_memc_server_free_storage; - INIT_CLASS_ENTRY(ce, "MemcachedServer", memcached_server_class_methods); - memcached_server_ce = zend_register_internal_class(&ce); + memcached_server_ce = register_class_MemcachedServer(); memcached_server_ce->create_object = php_memc_server_new; #endif @@ -4454,7 +4459,22 @@ 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); - php_info_print_table_row(2, "libmemcached version", memcached_lib_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"); @@ -4486,6 +4506,12 @@ PHP_MINFO_FUNCTION(memcached) 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(); diff --git a/php_memcached.h b/php_memcached.h index 9e466cb4..dfd19185 100644 --- a/php_memcached.h +++ b/php_memcached.h @@ -14,20 +14,23 @@ +----------------------------------------------------------------------+ */ -/* $ Id: $ */ - #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.0.0b1" +#define PHP_MEMCACHED_VERSION "3.3.1dev" #if defined(PHP_WIN32) && defined(MEMCACHED_EXPORTS) #define PHP_MEMCACHED_API __declspec(dllexport) diff --git a/php_memcached.stub.php b/php_memcached.stub.php new file mode 100644 index 00000000..7e85ef32 --- /dev/null +++ b/php_memcached.stub.php @@ -0,0 +1,95 @@ += 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 diff --git a/php_memcached_legacy_arginfo.h b/php_memcached_legacy_arginfo.h new file mode 100644 index 00000000..66d5bb91 --- /dev/null +++ b/php_memcached_legacy_arginfo.h @@ -0,0 +1,433 @@ +/* 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 diff --git a/php_memcached_private.h b/php_memcached_private.h index a04e19be..2c22ecba 100644 --- a/php_memcached_private.h +++ b/php_memcached_private.h @@ -14,12 +14,14 @@ +----------------------------------------------------------------------+ */ -/* $ Id: $ */ - #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" @@ -46,7 +48,11 @@ #include #ifdef PHP_WIN32 -# include "win32/php_stdint.h" + # 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) @@ -72,6 +78,13 @@ 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 ****************************************/ @@ -85,7 +98,8 @@ typedef enum { typedef enum { COMPRESSION_TYPE_ZLIB = 1, - COMPRESSION_TYPE_FASTLZ = 2 + COMPRESSION_TYPE_FASTLZ = 2, + COMPRESSION_TYPE_ZSTD = 3 } php_memc_compression_type; typedef struct { @@ -149,6 +163,8 @@ ZEND_BEGIN_MODULE_GLOBALS(php_memcached) 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; @@ -171,6 +187,8 @@ ZEND_BEGIN_MODULE_GLOBALS(php_memcached) 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; @@ -200,6 +218,19 @@ ZEND_BEGIN_MODULE_GLOBALS(php_memcached) 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); diff --git a/php_memcached_server.c b/php_memcached_server.c index 94305101..24c328f8 100644 --- a/php_memcached_server.c +++ b/php_memcached_server.c @@ -17,14 +17,13 @@ #include "php_memcached.h" #include "php_memcached_private.h" #include "php_memcached_server.h" +#include "php_network.h" #include -#undef NDEBUG -#undef _NDEBUG #include -#define MEMC_GET_CB(cb_type) (MEMC_G(server.callbacks)[cb_type]) +#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) \ @@ -37,7 +36,7 @@ #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); \ + my_result_cas = zval_get_double(&my_zresult_cas); \ } while (0) @@ -56,27 +55,24 @@ typedef struct { } php_memc_client_t; static -long s_invoke_php_callback (php_memc_server_cb_t *cb, zval ***params, ssize_t param_count) +long s_invoke_php_callback (php_memc_server_cb_t *cb, zval *params, ssize_t param_count) { - long retval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND; - zval *retval_ptr = NULL; + zval retval; - cb->fci.params = params; + cb->fci.retval = &retval; + cb->fci.params = params; cb->fci.param_count = param_count; - - /* Call the cb */ - cb->fci.no_separation = 1; - cb->fci.retval_ptr_ptr = &retval_ptr; +#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)); + 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); } - if (retval_ptr) { - retval = zval_get_long(retval_ptr); - } - return retval; + + return Z_ISUNDEF(retval) ? PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND : zval_get_long(&retval); } // memcached protocol callbacks @@ -99,6 +95,7 @@ protocol_binary_response_status s_add_handler(const void *cookie, const void *ke 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); @@ -145,6 +142,7 @@ protocol_binary_response_status s_append_prepend_handler (php_memc_event_t event 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); @@ -201,11 +199,13 @@ protocol_binary_response_status s_incr_decr_handler (php_memc_event_t event, con MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); ZVAL_STRINGL(&zkey, key, key_len); - ZVAL_LONG(&zdelta, (long) delta); - ZVAL_LONG(&zinital, (long) initial); - ZVAL_LONG(&zexpiration, (long) expiration); + 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); @@ -217,7 +217,7 @@ protocol_binary_response_status s_incr_decr_handler (php_memc_event_t event, con retval = s_invoke_php_callback (&MEMC_GET_CB(event), params, 7); - *result = (uint64_t)zval_get_long(zresult); + *result = (uint64_t)zval_get_long(&zresult); MEMC_MAKE_RESULT_CAS(zresult_cas, *result_cas); @@ -299,9 +299,10 @@ protocol_binary_response_status s_flush_handler(const void *cookie, uint32_t whe } MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); + ZVAL_LONG(&zwhen, when); ZVAL_COPY(¶ms[0], &zcookie); - ZVAL_COPY(¶ms[1], &zwhen) + ZVAL_COPY(¶ms[1], &zwhen); retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_FLUSH), params, 2); @@ -325,6 +326,13 @@ protocol_binary_response_status s_get_handler (const void *cookie, const void *k } 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); @@ -439,11 +447,12 @@ protocol_binary_response_status s_set_replace_handler (php_memc_event_t event, c MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); ZVAL_STRINGL(&zkey, key, key_len); - ZVAL_STRINGL(&zdata, ((char *) data), (int) data_len); - ZVAL_LONG(&zflags, (long) flags); - ZVAL_LONG(&zexpiration, (long) expiration); + 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); @@ -497,7 +506,7 @@ protocol_binary_response_status s_stat_handler (const void *cookie, const void * { zval params[3]; protocol_binary_response_status retval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND; - zval zcookie, zkey, zbody; + zval zcookie, zkey, zstats; if (!MEMC_HAS_CB(MEMC_SERVER_ON_STAT)) { return retval; @@ -505,25 +514,49 @@ protocol_binary_response_status s_stat_handler (const void *cookie, const void * MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); - ZVAL_STRINGL(&zkey, key, key_len); - ZVAL_NULL(&zbody); + 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], &zbody); + 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) { - if (Z_TYPE(zbody) == IS_NULL) { - retval = response_handler(cookie, NULL, 0, NULL, 0); + 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); } - else { - if (Z_TYPE(zbody) != IS_STRING) { - convert_to_string(&zbody); + + 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; } - retval = response_handler(cookie, key, key_len, Z_STRVAL(zbody), (uint32_t) Z_STRLEN(zbody)); } + ZEND_HASH_FOREACH_END(); } zval_ptr_dtor(¶ms[0]); @@ -531,7 +564,7 @@ protocol_binary_response_status s_stat_handler (const void *cookie, const void * zval_ptr_dtor(¶ms[2]); zval_ptr_dtor (&zcookie); zval_ptr_dtor (&zkey); - zval_ptr_dtor (&zbody); + zval_ptr_dtor (&zstats); return retval; } @@ -550,18 +583,18 @@ protocol_binary_response_status s_version_handler (const void *cookie, 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_P(zversion), (uint32_t) Z_STRLEN_P(zversion)); + retval = response_handler (cookie, Z_STRVAL(zversion), (uint32_t) Z_STRLEN(zversion)); } zval_ptr_dtor(¶ms[0]); @@ -584,31 +617,25 @@ void s_handle_memcached_event (evutil_socket_t fd, short what, void *arg) if (!client->on_connect_invoked) { if (MEMC_HAS_CB(MEMC_SERVER_ON_CONNECT)) { - zval zremoteip, zremoteport; - zval params[2]; + zend_string *zremoteaddr_str; + zval zremoteaddr; + zval params[1]; protocol_binary_response_status retval; - struct sockaddr_in addr_in; - socklen_t addr_in_len = sizeof(addr_in); + ZVAL_NULL(&zremoteaddr); - if (getpeername (fd, (struct sockaddr *) &addr_in, &addr_in_len) == 0) { - ZVAL_STRING(&zremoteip, inet_ntoa (addr_in.sin_addr), 1); - ZVAL_LONG(&zremoteport, ntohs (addr_in.sin_port)); + 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_NULL(&zremoteip); - ZVAL_NULL(&zremoteport); } - ZVAL_COPY(¶ms[0], &zremoteip); - ZVAL_COPY(¶ms[1], &zremoteport); + ZVAL_COPY(¶ms[0], &zremoteaddr); - retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_CONNECT), params, 2); + retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_CONNECT), params, 1); zval_ptr_dtor(¶ms[0]); - zval_ptr_dtor(¶ms[1]); - zval_ptr_dtor(&zremoteip); - zval_ptr_dtor(&zremoteport); + zval_ptr_dtor(&zremoteaddr); if (retval != PROTOCOL_BINARY_RESPONSE_SUCCESS) { memcached_protocol_client_destroy (client->protocol_client); @@ -717,22 +744,20 @@ php_memc_proto_handler_t *php_memc_proto_handler_new () } static -evutil_socket_t s_create_listening_socket (const char *spec) +evutil_socket_t s_create_listening_socket (const zend_string *spec) { evutil_socket_t sock; struct sockaddr_storage addr; - int addr_len; - + socklen_t addr_len; int rc; addr_len = sizeof (struct sockaddr); - rc = evutil_parse_sockaddr_port (spec, (struct sockaddr *) &addr, &addr_len); - if (rc != 0) { - php_error_docref(NULL, E_WARNING, "Failed to parse bind address"); + 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 (AF_INET, SOCK_STREAM, 0); + sock = socket (addr.ss_family, SOCK_STREAM, 0); if (sock < 0) { php_error_docref(NULL, E_WARNING, "socket failed: %s", strerror (errno)); return -1; @@ -773,7 +798,7 @@ evutil_socket_t s_create_listening_socket (const char *spec) 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->val); + evutil_socket_t sock = s_create_listening_socket (address); if (sock == -1) { return 0; diff --git a/php_memcached_session.c b/php_memcached_session.c index 42659fe5..e509cb84 100644 --- a/php_memcached_session.c +++ b/php_memcached_session.c @@ -22,9 +22,6 @@ extern ZEND_DECLARE_MODULE_GLOBALS(php_memcached) -#define MEMC_SESS_DEFAULT_LOCK_WAIT 150000 -#define MEMC_SESS_LOCK_EXPIRATION 30 - #define REALTIME_MAXDELTA 60*60*24*30 ps_module ps_mod_memcached = { @@ -46,14 +43,6 @@ typedef struct { # define MAX(a,b) (((a)>(b))?(a):(b)) #endif -#ifdef ZTS -#define MEMC_SESS_INI(v) TSRMG(php_memcached_globals_id, zend_php_memcached_globals *, session.v) -#else -#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) - static int le_memc_sess; @@ -113,7 +102,7 @@ time_t s_lock_expiration() return s_adjust_expiration(MEMC_SESS_INI(lock_expiration)); } else { - zend_long max_execution_time = zend_ini_long(ZEND_STRS("max_execution_time"), 0); + 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); } @@ -189,20 +178,30 @@ void s_unlock_session(memcached_st *memc) static zend_bool s_configure_from_ini_values(memcached_st *memc, zend_bool silent) { - memcached_return rc; - +/* This macro looks like a function but returns errors directly */ #define check_set_behavior(behavior, value) \ - if ((rc = memcached_behavior_set(memc, (behavior), (value))) != MEMCACHED_SUCCESS) { \ - if (!silent) { php_error_docref(NULL, E_WARNING, "failed to initialise session memcached configuration: %s", memcached_strerror(memc, rc)); } \ - return 0; \ - } +{ \ + 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(MEMCACHED_BEHAVIOR_KETAMA, 1); + check_set_behavior(MEMC_SESS_INI(consistent_hash_type), 1); } if (MEMC_SESS_INI(server_failure_limit)) { @@ -246,7 +245,7 @@ zend_bool s_configure_from_ini_values(memcached_st *memc, zend_bool silent) user_data->has_sasl_data = 1; } -#undef safe_set_behavior +#undef check_set_behavior return 1; } @@ -325,6 +324,13 @@ PS_OPEN_FUNC(memcached) 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); @@ -351,6 +357,7 @@ PS_OPEN_FUNC(memcached) else { efree(plist_key); PS_SET_MOD_DATA(memc); + memcached_server_list_free(servers); return SUCCESS; } } @@ -375,7 +382,7 @@ PS_OPEN_FUNC(memcached) le.type = s_memc_sess_list_entry(); le.ptr = memc; - GC_REFCOUNT(&le) = 1; + 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) { @@ -435,13 +442,15 @@ PS_READ_FUNC(memcached) 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); - efree(payload); + 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; } } @@ -470,6 +479,8 @@ PS_WRITE_FUNC(memcached) 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); @@ -539,7 +550,7 @@ PS_UPDATE_TIMESTAMP_FUNC(memcached) memcached_st *memc = PS_GET_MOD_DATA(); time_t expiration = s_session_expiration(maxlifetime); - if (memcached_touch(memc, key->val, key->len, expiration) == MEMCACHED_FAILURE) { + if (php_memcached_touch(memc, key->val, key->len, expiration) == MEMCACHED_FAILURE) { return FAILURE; } return SUCCESS; diff --git a/server-example/run-server.php b/server-example/run-server.php index a02c6a60..b7612c80 100644 --- a/server-example/run-server.php +++ b/server-example/run-server.php @@ -3,8 +3,8 @@ $server = new MemcachedServer(); $server->on (Memcached::ON_CONNECT, - function ($remote_ip, $remote_port) { - echo "Incoming connection from {$remote_ip}:{$remote_port}" . PHP_EOL; + function ($remote_addr) { + echo "Incoming connection from {$remote_addr}" . PHP_EOL; return Memcached::RESPONSE_SUCCESS; }); @@ -89,4 +89,4 @@ function ($client_id) { return Memcached::RESPONSE_SUCCESS; }); -$server->run ("127.0.0.1:3434"); \ No newline at end of file +$server->run ("127.0.0.1:3434"); diff --git a/tests/experimental/add_bykey.phpt b/tests/add_bykey.phpt similarity index 84% rename from tests/experimental/add_bykey.phpt rename to tests/add_bykey.phpt index 195fe96d..1c1521d2 100644 --- a/tests/experimental/add_bykey.phpt +++ b/tests/add_bykey.phpt @@ -1,10 +1,10 @@ --TEST-- Memcached::addByKey() --SKIPIF-- - + --FILE-- delete('foo'); @@ -15,7 +15,7 @@ echo $m->getResultMessage(), "\n"; var_dump($m->addByKey('foo', '', 1, 10)); echo $m->getResultMessage(), "\n"; // This is OK for the binary protocol -$rv = $m->addByKey('foo', ' asd ���', 1, 1); +$rv = $m->addByKey('foo', ' asd åäö', 1, 1); if ($m->getOption(Memcached::OPT_BINARY_PROTOCOL)) { if ($rv !== true and $m->getResultCode() !== Memcached::RES_SUCCESS) { var_dump($rv); diff --git a/tests/experimental/addserver_unixdomain.phpt b/tests/addserver_unixdomain.phpt similarity index 87% rename from tests/experimental/addserver_unixdomain.phpt rename to tests/addserver_unixdomain.phpt index 4848015d..7e16834c 100644 --- a/tests/experimental/addserver_unixdomain.phpt +++ b/tests/addserver_unixdomain.phpt @@ -1,7 +1,7 @@ --TEST-- Memcached::addServer() unix doamin socket --SKIPIF-- - + --CLEAN-- delete('foo'); $m->setOption(Memcached::OPT_COMPRESSION, true); var_dump($m->append('foo', 'a')); -echo $php_errormsg, "\n"; +echo error_get_last()["message"], "\n"; $m->setOption(Memcached::OPT_COMPRESSION, false); $m->delete('foo'); diff --git a/tests/experimental/append_bykey.phpt b/tests/append_bykey.phpt similarity index 78% rename from tests/experimental/append_bykey.phpt rename to tests/append_bykey.phpt index 0e182ca4..d02c257d 100644 --- a/tests/experimental/append_bykey.phpt +++ b/tests/append_bykey.phpt @@ -1,10 +1,10 @@ --TEST-- Memcached::appendByKey() --SKIPIF-- - + --FILE-- setOption(Memcached::OPT_COMPRESSION, false); diff --git a/tests/bad_construct.phpt b/tests/bad_construct.phpt index aa9b18c4..0c278796 100644 --- a/tests/bad_construct.phpt +++ b/tests/bad_construct.phpt @@ -1,12 +1,15 @@ --TEST-- Memcached construct with bad arguments --SKIPIF-- - += 80000) die("skip PHP 7 only"); +?> --FILE-- +--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 + diff --git a/tests/experimental/cas_bykey.phpt b/tests/cas_bykey.phpt similarity index 84% rename from tests/experimental/cas_bykey.phpt rename to tests/cas_bykey.phpt index 0a9da94e..32808813 100644 --- a/tests/experimental/cas_bykey.phpt +++ b/tests/cas_bykey.phpt @@ -1,10 +1,10 @@ --TEST-- Memcached::casByKey() --SKIPIF-- - + --FILE-- delete('cas_test'); diff --git a/tests/cas_e2big.phpt b/tests/cas_e2big.phpt new file mode 100644 index 00000000..99c3562b --- /dev/null +++ b/tests/cas_e2big.phpt @@ -0,0 +1,32 @@ +--TEST-- +set data exceeding size limit +--SKIPIF-- + +--FILE-- + 100, +)); + +$m->delete('cas_e2big_test'); + +$m->set('cas_e2big_test', 'hello'); +$result = $m->get('cas_e2big_test', null, Memcached::GET_EXTENDED); +var_dump(is_array($result) && isset($result['cas']) && isset($result['value']) && $result['value'] == 'hello'); + +$value = str_repeat('a large payload', 1024 * 1024); + +var_dump($m->cas($result['cas'], 'cas_e2big_test', $value, 360)); +var_dump($m->getResultCode() == Memcached::RES_E2BIG); +var_dump($m->getResultMessage() == 'ITEM TOO BIG'); +var_dump($m->get('cas_e2big_test') == 'hello'); +var_dump($m->getResultCode() == Memcached::RES_SUCCESS); +?> +--EXPECT-- +bool(true) +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) diff --git a/tests/experimental/cas_invalid_key.phpt b/tests/cas_invalid_key.phpt similarity index 55% rename from tests/experimental/cas_invalid_key.phpt rename to tests/cas_invalid_key.phpt index 6011c4b8..9cb7293c 100644 --- a/tests/experimental/cas_invalid_key.phpt +++ b/tests/cas_invalid_key.phpt @@ -1,17 +1,20 @@ --TEST-- Memcached::cas() with strange key --SKIPIF-- - + --FILE-- false, + Memcached::OPT_VERIFY_KEY => true +)); error_reporting(0); var_dump($m->cas(0, '', true, 10)); echo $m->getResultMessage(), "\n"; -var_dump($m->cas(0, ' �� jas kjjhask d ', true, 10)); # no spaces allowed +var_dump($m->cas(0, ' äö jas kjjhask d ', true, 10)); # no spaces allowed echo $m->getResultMessage(), "\n"; --EXPECTF-- diff --git a/tests/check_key.phpt b/tests/check_key.phpt new file mode 100644 index 00000000..74ec6214 --- /dev/null +++ b/tests/check_key.phpt @@ -0,0 +1,132 @@ +--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" + diff --git a/tests/compression_conditions.phpt b/tests/compression_conditions.phpt new file mode 100644 index 00000000..960058b6 --- /dev/null +++ b/tests/compression_conditions.phpt @@ -0,0 +1,125 @@ +--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); + + $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) diff --git a/tests/compression_types.phpt b/tests/compression_types.phpt index ce07aed5..81d7867c 100644 --- a/tests/compression_types.phpt +++ b/tests/compression_types.phpt @@ -15,6 +15,10 @@ function get_compression($name) { return Memcached::COMPRESSION_ZLIB; case 'fastlz': return Memcached::COMPRESSION_FASTLZ; + case 'zstd': + if (Memcached::HAVE_ZSTD) { + return Memcached::COMPRESSION_ZSTD; + } else return 0; default: echo "Strange compression type: $name\n"; return 0; @@ -54,6 +58,26 @@ 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] @@ -74,3 +98,13 @@ 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) diff --git a/tests/experimental/delete_bykey.phpt b/tests/delete_bykey.phpt similarity index 76% rename from tests/experimental/delete_bykey.phpt rename to tests/delete_bykey.phpt index 807af8ca..6aa589c5 100644 --- a/tests/experimental/delete_bykey.phpt +++ b/tests/delete_bykey.phpt @@ -1,11 +1,14 @@ --TEST-- Memcached::deleteByKey() --SKIPIF-- - + --FILE-- false, + Memcached::OPT_VERIFY_KEY => true +)); $m->setByKey('keffe', 'eisaleeoo', "foo"); var_dump($m->getByKey('keffe', 'eisaleeoo')); @@ -21,7 +24,7 @@ var_dump($m->deleteByKey('keffe', '')); echo $m->getResultMessage(), "\n"; var_dump($m->deleteByKey('', 'keffe')); echo $m->getResultMessage(), "\n"; -var_dump($m->deleteByKey('keffe', '���as�� �a�sd�f asdf')); # no spaces allowed +var_dump($m->deleteByKey('keffe', 'äöåasäö åaösdäf asdf')); # no spaces allowed echo $m->getResultMessage(), "\n"; --EXPECTF-- string(3) "foo" diff --git a/tests/experimental/deletemulti_nonstringkeys.phpt b/tests/deletemulti_nonstringkeys.phpt similarity index 87% rename from tests/experimental/deletemulti_nonstringkeys.phpt rename to tests/deletemulti_nonstringkeys.phpt index 2dac8920..8e275e9c 100644 --- a/tests/experimental/deletemulti_nonstringkeys.phpt +++ b/tests/deletemulti_nonstringkeys.phpt @@ -1,10 +1,10 @@ --TEST-- Delete multi with integer keys --SKIPIF-- - + --FILE-- ---FILE-- -set('foo', 1, 10); - -$cas = null; -var_dump($m->getByKey('foo', 'foo', null, $cas)); -var_dump($cas); -echo $m->getResultMessage(), "\n"; - -$cas = null; -var_dump($m->getByKey('', 'foo', null, $cas)); -var_dump($cas); -echo $m->getResultMessage(), "\n"; - -$m->set('bar', "asdf", 10); - -$cas = null; -var_dump($m->getByKey('foo', 'bar', null, $cas)); -var_dump($cas); -echo $m->getResultMessage(), "\n"; - -$m->delete('foo'); -$cas = null; -var_dump($m->getByKey(' � foo jkh a s ���', 'foo', null, $cas)); -var_dump($cas); -echo $m->getResultMessage(), "\n"; - -$cas = null; -var_dump($m->getByKey(' � foo jkh a s ���', '', null, $cas)); -var_dump($cas); -echo $m->getResultMessage(), "\n"; - -$m->delete('foo'); -$cas = null; -var_dump($m->getByKey('foo', 'foo', 'the_callback', $cas)); -var_dump($cas); -var_dump($m->getByKey('foo', 'foo')); ---EXPECTF-- -int(1) -float(%d) -SUCCESS -int(1) -float(%d) -SUCCESS -string(4) "asdf" -float(%d) -SUCCESS -bool(false) -float(0) -NOT FOUND -bool(false) -NULL -A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE -called -string(4) "1234" -float(0) -string(4) "1234" diff --git a/tests/experimental/getdelayed_cbthrows.phpt b/tests/experimental/getdelayed_cbthrows.phpt index 2b71b4b4..b0427ac9 100644 --- a/tests/experimental/getdelayed_cbthrows.phpt +++ b/tests/experimental/getdelayed_cbthrows.phpt @@ -24,7 +24,7 @@ error_reporting(0); try { $m->getDelayedByKey('kef', array_keys($data), false, 'myfunc'); } catch (Exception $e) { - echo $php_errormsg, "\n"; + echo error_get_last()["message"], "\n"; echo $e->getMessage(), "\n"; } diff --git a/tests/experimental/serializer/serializer_php_bad_serialize.phpt b/tests/experimental/serializer/serializer_php_bad_serialize.phpt index 81e88b0c..76d3daca 100644 --- a/tests/experimental/serializer/serializer_php_bad_serialize.phpt +++ b/tests/experimental/serializer/serializer_php_bad_serialize.phpt @@ -44,7 +44,7 @@ error_reporting(0); try { var_dump($m->set('foo', new Foo(), 10)); } catch (Exception $e) { - echo $php_errormsg, "\n"; + echo error_get_last()["message"], "\n"; echo $e->getMessage(), "\n"; } try { diff --git a/tests/experimental/serializer/serializer_php_bad_unserialize.phpt b/tests/experimental/serializer/serializer_php_bad_unserialize.phpt index 39d2cc37..341ddedc 100644 --- a/tests/experimental/serializer/serializer_php_bad_unserialize.phpt +++ b/tests/experimental/serializer/serializer_php_bad_unserialize.phpt @@ -40,7 +40,7 @@ var_dump($m->set('foo', new Foo(), 10)); try { var_dump($m->get('foo')); } catch (Exception $e) { - echo $php_errormsg, "\n"; + echo error_get_last()["message"], "\n"; echo $e->getMessage(), "\n"; } diff --git a/tests/experimental/setmulti_badserialize.phpt b/tests/experimental/setmulti_badserialize.phpt index 3bba314a..2d8dde53 100644 --- a/tests/experimental/setmulti_badserialize.phpt +++ b/tests/experimental/setmulti_badserialize.phpt @@ -36,12 +36,11 @@ try { } } - echo $php_errormsg, "\n"; + echo error_get_last()["message"], "\n"; echo $e->getMessage(), "\n"; } var_dump($m->getByKey('kef', 'foo')); --EXPECT-- -Memcached::setMultiByKey(): failed to set key foo 1234 int(10) diff --git a/tests/expire.phpt b/tests/expire.phpt index eac02408..d53309e7 100644 --- a/tests/expire.phpt +++ b/tests/expire.phpt @@ -1,12 +1,11 @@ --TEST-- Memcached store, fetch & touch expired key ---XFAIL-- -https://code.google.com/p/memcached/issues/detail?id=275 --SKIPIF-- --FILE-- + --FILE-- + --FILE-- serialize_throws) { + throw new Exception("1234"); + } + return ["1234"]; + } + + public function __unserialize($str) { + throw new Exception("123456"); + } } $data = new Foo(); @@ -42,7 +53,7 @@ var_dump($m->getDelayed(array('foo'), false)); try { var_dump($m->fetch()); } catch (Exception $e) { - echo $php_errormsg, "\n"; + echo error_get_last()["message"], "\n"; echo $e->getMessage(), "\n"; } diff --git a/tests/experimental/fetchall_badunserialize.phpt b/tests/fetchall_badunserialize.phpt similarity index 72% rename from tests/experimental/fetchall_badunserialize.phpt rename to tests/fetchall_badunserialize.phpt index e3ad3310..815c9e21 100644 --- a/tests/experimental/fetchall_badunserialize.phpt +++ b/tests/fetchall_badunserialize.phpt @@ -1,10 +1,10 @@ --TEST-- Memcached::fetch() with bad unserialize --SKIPIF-- - + --FILE-- serialize_throws) { + throw new Exception("1234"); + } + return ["1234"]; + } + + public function __unserialize($str) { + throw new Exception("123456"); + } } $data = new Foo(); @@ -42,7 +53,7 @@ var_dump($m->getDelayed(array('foo'), false)); try { var_dump($m->fetchAll()); } catch (Exception $e) { - echo $php_errormsg, "\n"; + echo error_get_last()["message"], "\n"; echo $e->getMessage(), "\n"; } diff --git a/tests/experimental/get.phpt b/tests/get.phpt similarity index 69% rename from tests/experimental/get.phpt rename to tests/get.phpt index 308bda98..722308f0 100644 --- a/tests/experimental/get.phpt +++ b/tests/get.phpt @@ -1,11 +1,14 @@ --TEST-- Memcached::get() --SKIPIF-- - + --FILE-- false, + Memcached::OPT_VERIFY_KEY => true +)); $m->delete('foo'); @@ -20,7 +23,7 @@ var_dump($m->get('foo')); echo $m->getResultMessage(), "\n"; $m->delete('foo'); -var_dump($m->get(' � foo jkh a s ���')); +var_dump($m->get(' ä foo jkh a s åäö')); echo $m->getResultMessage(), "\n"; --EXPECT-- bool(false) diff --git a/tests/experimental/get_bykey.phpt b/tests/get_bykey.phpt similarity index 75% rename from tests/experimental/get_bykey.phpt rename to tests/get_bykey.phpt index a392aaeb..704e8f04 100644 --- a/tests/experimental/get_bykey.phpt +++ b/tests/get_bykey.phpt @@ -1,10 +1,10 @@ --TEST-- Memcached::getByKey() --SKIPIF-- - + --FILE-- set('foo', 1, 10); @@ -20,7 +20,7 @@ var_dump($m->getByKey('foo', 'bar')); echo $m->getResultMessage(), "\n"; $m->delete('foo'); -var_dump($m->getByKey(' � foo jkh a s ���', 'foo')); +var_dump($m->getByKey(' ä foo jkh a s åäö', 'foo')); echo $m->getResultMessage(), "\n"; --EXPECTF-- diff --git a/tests/get_bykey_cas.phpt b/tests/get_bykey_cas.phpt new file mode 100644 index 00000000..90b566c4 --- /dev/null +++ b/tests/get_bykey_cas.phpt @@ -0,0 +1,61 @@ +--TEST-- +Memcached::getByKey() with CAS +--SKIPIF-- + +--FILE-- +set('foo', 1, 10); + +$v = $m->getByKey('foo', 'foo', null, Memcached::GET_EXTENDED); +var_dump($v['value']); +var_dump($v['cas']); +echo $m->getResultMessage(), "\n"; + +$v = $m->getByKey('', 'foo', null, Memcached::GET_EXTENDED); +var_dump($v['value']); +var_dump($v['cas']); +echo $m->getResultMessage(), "\n"; + +$m->set('bar', "asdf", 10); + +$v = $m->getByKey('foo', 'bar', null, Memcached::GET_EXTENDED); +var_dump($v['value']); +var_dump($v['cas']); +echo $m->getResultMessage(), "\n"; + +$m->delete('foo'); +var_dump($m->getByKey(' ä foo jkh a s åäö', 'foo', null, Memcached::GET_EXTENDED)); +echo $m->getResultMessage(), "\n"; + +var_dump($m->getByKey(' ä foo jkh a s åäö', '', null, Memcached::GET_EXTENDED)); +echo $m->getResultMessage(), "\n"; + +$m->delete('foo'); +var_dump($m->getByKey('foo', 'foo', 'the_callback', Memcached::GET_EXTENDED)); +var_dump($m->getByKey('foo', 'foo')); +--EXPECTF-- +int(1) +int(%d) +SUCCESS +int(1) +int(%d) +SUCCESS +string(4) "asdf" +int(%d) +SUCCESS +bool(false) +NOT FOUND +bool(false) +A BAD KEY WAS PROVIDED/CHARACTERS OUT OF RANGE +called +bool(false) +bool(false) \ No newline at end of file diff --git a/tests/experimental/getdelayed_badserver.phpt b/tests/getdelayed_badserver.phpt similarity index 87% rename from tests/experimental/getdelayed_badserver.phpt rename to tests/getdelayed_badserver.phpt index c4902174..5d274efb 100644 --- a/tests/experimental/getdelayed_badserver.phpt +++ b/tests/getdelayed_badserver.phpt @@ -1,7 +1,7 @@ --TEST-- Memcached::getDelayedByKey() with bad server --SKIPIF-- - + --FILE-- + --FILE-- serialize_throws) { + throw new Exception("1234"); + } + return ["1234"]; + } + + public function __unserialize($str) { + throw new Exception("123456"); + } } function mycb($memc, $key, $value) { @@ -45,7 +56,7 @@ error_reporting(0); try { var_dump($m->getDelayed(array('foo'), false, 'mycb')); } catch (Exception $e) { - echo $php_errormsg, "\n"; + echo error_get_last()["message"], "\n"; echo $e->getMessage(), "\n"; } diff --git a/tests/experimental/getdelayed_bykey.phpt b/tests/getdelayed_bykey.phpt similarity index 89% rename from tests/experimental/getdelayed_bykey.phpt rename to tests/getdelayed_bykey.phpt index a29f646b..442320a2 100644 --- a/tests/experimental/getdelayed_bykey.phpt +++ b/tests/getdelayed_bykey.phpt @@ -1,10 +1,10 @@ --TEST-- Memcached::getDelayedByKey() --SKIPIF-- - + --FILE-- + --FILE-- getDelayedByKey('kef', array_keys($data), true, 'myfunc'); ?> --EXPECTF-- -array(3) { +array(4) { ["key"]=> string(3) "foo" ["value"]=> string(8) "foo-data" ["cas"]=> - float(%d) + int(%d) + ["flags"]=> + int(0) } -array(3) { +array(4) { ["key"]=> string(3) "bar" ["value"]=> string(8) "bar-data" ["cas"]=> - float(%d) + int(%d) + ["flags"]=> + int(0) } -array(3) { +array(4) { ["key"]=> string(3) "baz" ["value"]=> string(8) "baz-data" ["cas"]=> - float(%d) + int(%d) + ["flags"]=> + int(0) } -array(3) { +array(4) { ["key"]=> string(3) "lol" ["value"]=> string(8) "lol-data" ["cas"]=> - float(%d) + int(%d) + ["flags"]=> + int(0) } -array(3) { +array(4) { ["key"]=> string(3) "kek" ["value"]=> string(8) "kek-data" ["cas"]=> - float(%d) + int(%d) + ["flags"]=> + int(0) } diff --git a/tests/experimental/getdelayed_nonstring_keys.phpt b/tests/getdelayed_nonstring_keys.phpt similarity index 90% rename from tests/experimental/getdelayed_nonstring_keys.phpt rename to tests/getdelayed_nonstring_keys.phpt index 81363f3b..005d0579 100644 --- a/tests/experimental/getdelayed_nonstring_keys.phpt +++ b/tests/getdelayed_nonstring_keys.phpt @@ -1,10 +1,10 @@ --TEST-- Memcached getDelayed non string keys --SKIPIF-- - + --FILE-- + --FILE-- getResultCode()) { } --EXPECTF-- -array(0) { -} +bool(false) NO SERVERS DEFINED -array(0) { -} +bool(false) %d: %s diff --git a/tests/experimental/getmulti_badunserialize.phpt b/tests/getmulti_badunserialize.phpt similarity index 73% rename from tests/experimental/getmulti_badunserialize.phpt rename to tests/getmulti_badunserialize.phpt index b33d5ccd..280feed3 100644 --- a/tests/experimental/getmulti_badunserialize.phpt +++ b/tests/getmulti_badunserialize.phpt @@ -1,10 +1,10 @@ --TEST-- Memcached::getMulti() with bad unserialize --SKIPIF-- - + --FILE-- set('bar', "12", 10)); @@ -32,7 +40,7 @@ error_reporting(0); try { var_dump($m->getMulti(array('bar', 'foo'))); } catch (Exception $e) { - echo $php_errormsg, "\n"; + echo error_get_last()["message"], "\n"; echo $e->getMessage(), "\n"; } diff --git a/tests/experimental/getmulti_bykey.phpt b/tests/getmulti_bykey.phpt similarity index 82% rename from tests/experimental/getmulti_bykey.phpt rename to tests/getmulti_bykey.phpt index 3f7a6f78..b615dc66 100644 --- a/tests/experimental/getmulti_bykey.phpt +++ b/tests/getmulti_bykey.phpt @@ -1,10 +1,10 @@ --TEST-- Memcached::getMultiByKey() --SKIPIF-- - + --FILE-- set('foo', 1, 10); diff --git a/tests/experimental/getmulti_empty.phpt b/tests/getmulti_empty.phpt similarity index 60% rename from tests/experimental/getmulti_empty.phpt rename to tests/getmulti_empty.phpt index 6279104d..3550e814 100644 --- a/tests/experimental/getmulti_empty.phpt +++ b/tests/getmulti_empty.phpt @@ -1,10 +1,10 @@ --TEST-- Memcached::getMulti() with empty array --SKIPIF-- - + --FILE-- getMulti(array()); diff --git a/tests/experimental/getmulti_partial_error.phpt b/tests/getmulti_partial_error.phpt similarity index 84% rename from tests/experimental/getmulti_partial_error.phpt rename to tests/getmulti_partial_error.phpt index fa392e9e..928f49f4 100644 --- a/tests/experimental/getmulti_partial_error.phpt +++ b/tests/getmulti_partial_error.phpt @@ -1,10 +1,10 @@ --TEST-- Memcached::getMulti() partial error --SKIPIF-- - + --FILE-- + --FILE-- getVersion()); -include dirname(dirname(__FILE__)) . "/config.inc"; +include dirname(__FILE__) . "/config.inc"; $m = memc_get_instance (); $stats = $m->getVersion(); diff --git a/tests/gh_155.phpt b/tests/gh_155.phpt index a5b61d00..699e8eca 100644 --- a/tests/gh_155.phpt +++ b/tests/gh_155.phpt @@ -4,7 +4,10 @@ Test for bug 155 --FILE-- setOption(Memcached::OPT_BINARY_PROTOCOL,true); +$m->setOption(Memcached::OPT_BINARY_PROTOCOL, true); $m->addServer(MEMC_SERVER_HOST, MEMC_SERVER_PORT); $key = 'bug_155_' . uniqid(); diff --git a/tests/gh_500.phpt b/tests/gh_500.phpt new file mode 100644 index 00000000..366138db --- /dev/null +++ b/tests/gh_500.phpt @@ -0,0 +1,25 @@ +--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) diff --git a/tests/gh_90.phpt b/tests/gh_90.phpt index 733b7615..2a16f603 100644 --- a/tests/gh_90.phpt +++ b/tests/gh_90.phpt @@ -12,7 +12,7 @@ $memcached = memc_get_instance (array ( // 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, pow(2, 32)); //Random value betwen 0 and 2^32 for ownership verification + $lockToken = mt_rand(0, mt_getrandmax()); //Random value for ownership verification while (true) { @@ -88,4 +88,4 @@ array(10) { int(1) ["9_%s"]=> int(1) -} \ No newline at end of file +} diff --git a/tests/incrdecr.phpt b/tests/incrdecr.phpt index fc640985..87b410c9 100644 --- a/tests/incrdecr.phpt +++ b/tests/incrdecr.phpt @@ -29,12 +29,23 @@ $m->decrement('foo', 2); var_dump($m->get('foo')); error_reporting(0); -echo "Invalid offset\n"; + +echo "Negative offset\n"; +error_clear_last(); $m->increment('foo', -1); -echo $php_errormsg, "\n"; +echo error_get_last()["message"], "\n"; var_dump($m->get('foo')); + +error_clear_last(); $m->decrement('foo', -1); -echo $php_errormsg, "\n"; +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-- @@ -51,8 +62,11 @@ int(2) int(4) int(3) int(1) -Invalid offset -Memcached::increment(): offset has to be > 0 +Negative offset +Memcached::increment(): offset cannot be a negative value +int(1) +Memcached::decrement(): offset cannot be a negative value int(1) -Memcached::decrement(): offset has to be > 0 +Enormous offset +int(2130706433) int(1) diff --git a/tests/incrdecr_64.phpt b/tests/incrdecr_64.phpt new file mode 100644 index 00000000..dfa32c6a --- /dev/null +++ b/tests/incrdecr_64.phpt @@ -0,0 +1,39 @@ +--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) diff --git a/tests/incrdecr_bykey.phpt b/tests/incrdecr_bykey.phpt index 9c2db8dd..ee089938 100644 --- a/tests/incrdecr_bykey.phpt +++ b/tests/incrdecr_bykey.phpt @@ -26,12 +26,23 @@ $m->decrementByKey('foo', 'foo', 2); var_dump($m->get('foo')); error_reporting(0); -echo "Invalid offset\n"; + +echo "Negative offset\n"; +error_clear_last(); $m->incrementByKey('foo', 'foo', -1); -echo $php_errormsg, "\n"; +echo error_get_last()["message"], "\n"; var_dump($m->get('foo')); + +error_clear_last(); $m->decrementByKey('foo', 'foo', -1); -echo $php_errormsg, "\n"; +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-- @@ -45,8 +56,11 @@ int(2) int(4) int(3) int(1) -Invalid offset -Memcached::incrementByKey(): offset has to be > 0 +Negative offset +Memcached::incrementByKey(): offset cannot be a negative value +int(1) +Memcached::decrementByKey(): offset cannot be a negative value int(1) -Memcached::decrementByKey(): offset has to be > 0 +Enormous offset +int(2130706433) int(1) diff --git a/tests/invoke_callback_2.phpt b/tests/invoke_callback_2.phpt index 07e84f94..9749ed18 100644 --- a/tests/invoke_callback_2.phpt +++ b/tests/invoke_callback_2.phpt @@ -18,9 +18,9 @@ function init_cb_fail($m, $id) { echo "configured, should not be called.\n"; } -function init_cb_arg($m, $id, $arg) { +function init_cb_arg($m, $id) { + var_dump(func_num_args()); var_dump($id); - var_dump($arg); } function init_nopersist_cb($m, $id) { @@ -33,15 +33,14 @@ class Foo extends Memcached { parent::__construct($id, array($this, 'init')); } - function init($obj, $id, $options) { + function init($obj, $id) { + var_dump(func_num_args()); var_dump($this->isPristine()); var_dump($this->isPersistent()); var_dump($id); } } -error_reporting(0); - echo "cb call\n"; $m1 = new Memcached('foo1', 'init_cb'); @@ -50,7 +49,6 @@ $m1 = new Memcached('foo1', 'init_cb_fail'); echo "cb arg without arg\n"; $m1 = new Memcached('foo3', 'init_cb_arg'); -echo $php_errormsg, "\n"; echo "cb arg not persistent\n"; $m1 = new Memcached(null, 'init_nopersist_cb'); @@ -63,7 +61,7 @@ $m1 = new Foo('baz'); echo "cb second persistent in object\n"; $m1 = new Foo('baz'); - +?> --EXPECT-- cb call string(9) "Memcached" @@ -71,17 +69,18 @@ bool(true) string(4) "foo1" cb not run cb arg without arg +int(2) string(4) "foo3" -NULL - 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" diff --git a/tests/keys.phpt b/tests/keys.phpt deleted file mode 100644 index 63cce0a3..00000000 --- a/tests/keys.phpt +++ /dev/null @@ -1,49 +0,0 @@ ---TEST-- -Test different kind of keys ---SKIPIF-- - ---FILE-- - true, - )); - -$ascii = memc_get_instance (); -$ascii->setOption(Memcached::OPT_VERIFY_KEY, 1); - -var_dump ($binary->set ('binary key with spaces', 'this is a test')); -var_dump ($binary->getResultCode () == Memcached::RES_SUCCESS); - -var_dump ($binary->set ('binarykeywithnewline' . PHP_EOL, 'this is a test')); -var_dump ($binary->getResultCode () == Memcached::RES_BAD_KEY_PROVIDED); - -var_dump ($ascii->set ('ascii key with spaces', 'this is a test')); -var_dump ($ascii->getResultCode () == Memcached::RES_BAD_KEY_PROVIDED); - -var_dump ($binary->set ('asciikeywithnewline' . PHP_EOL, 'this is a test')); -var_dump ($binary->getResultCode () == Memcached::RES_BAD_KEY_PROVIDED); - -var_dump ($ascii->set (''/*empty key*/, 'this is a test')); -var_dump ($ascii->getResultCode () == Memcached::RES_BAD_KEY_PROVIDED); - -var_dump ($ascii->set (str_repeat ('1234567890', 512), 'this is a test')); -var_dump ($ascii->getResultCode () == Memcached::RES_BAD_KEY_PROVIDED); - -echo "OK" . PHP_EOL; - ---EXPECT-- -bool(true) -bool(true) -bool(false) -bool(true) -bool(false) -bool(true) -bool(false) -bool(true) -bool(false) -bool(true) -bool(false) -bool(true) -OK diff --git a/tests/keys_ascii.phpt b/tests/keys_ascii.phpt new file mode 100644 index 00000000..e7846e99 --- /dev/null +++ b/tests/keys_ascii.phpt @@ -0,0 +1,187 @@ +--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 diff --git a/tests/keys_binary.phpt b/tests/keys_binary.phpt new file mode 100644 index 00000000..f0ae67bd --- /dev/null +++ b/tests/keys_binary.phpt @@ -0,0 +1,190 @@ +--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 diff --git a/tests/experimental/locale_float.phpt b/tests/locale_float.phpt similarity index 80% rename from tests/experimental/locale_float.phpt rename to tests/locale_float.phpt index c071d974..2f25ea73 100644 --- a/tests/experimental/locale_float.phpt +++ b/tests/locale_float.phpt @@ -2,14 +2,14 @@ Float should not consider locale --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 diff --git a/tests/memcachedserver6.phpt b/tests/memcachedserver6.phpt new file mode 100644 index 00000000..3d02b244 --- /dev/null +++ b/tests/memcachedserver6.phpt @@ -0,0 +1,118 @@ +--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 diff --git a/tests/experimental/moduleinfo.phpt b/tests/moduleinfo.phpt similarity index 86% rename from tests/experimental/moduleinfo.phpt rename to tests/moduleinfo.phpt index 8605c11a..51a5555e 100644 --- a/tests/experimental/moduleinfo.phpt +++ b/tests/moduleinfo.phpt @@ -2,7 +2,7 @@ Memcached::phpinfo() --SKIPIF-- --FILE-- diff --git a/tests/options.phpt b/tests/options.phpt index ce895385..a096c8f1 100644 --- a/tests/options.phpt +++ b/tests/options.phpt @@ -26,6 +26,26 @@ var_dump($m->getOption(Memcached::OPT_COMPRESSION_TYPE) == Memcached::COMPRESSIO 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) @@ -41,3 +61,15 @@ 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) diff --git a/tests/experimental/prepend_bykey.phpt b/tests/prepend_bykey.phpt similarity index 78% rename from tests/experimental/prepend_bykey.phpt rename to tests/prepend_bykey.phpt index 87d3fd38..482899de 100644 --- a/tests/experimental/prepend_bykey.phpt +++ b/tests/prepend_bykey.phpt @@ -1,10 +1,10 @@ --TEST-- Memcached::appendByKey() --SKIPIF-- - + --FILE-- setOption(Memcached::OPT_COMPRESSION, false); diff --git a/tests/experimental/replace_bykey.phpt b/tests/replace_bykey.phpt similarity index 77% rename from tests/experimental/replace_bykey.phpt rename to tests/replace_bykey.phpt index b2f72836..b844824c 100644 --- a/tests/experimental/replace_bykey.phpt +++ b/tests/replace_bykey.phpt @@ -1,16 +1,16 @@ --TEST-- Memcached::replaceByKey() --SKIPIF-- - + --FILE-- delete('foo'); var_dump($m->replaceByKey('kef', 'foo', 'bar', 60)); -echo $php_errormsg, "\n"; +echo error_get_last()["message"], "\n"; echo $m->getResultMessage(), "\n"; var_dump($m->getByKey('kef', 'foo')); diff --git a/tests/reset_keyprefix.phpt b/tests/reset_keyprefix.phpt new file mode 100644 index 00000000..385a21d5 --- /dev/null +++ b/tests/reset_keyprefix.phpt @@ -0,0 +1,38 @@ +--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" \ No newline at end of file diff --git a/tests/server.inc b/tests/server.inc new file mode 100644 index 00000000..9678f043 --- /dev/null +++ b/tests/server.inc @@ -0,0 +1,82 @@ + 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; +} diff --git a/tests/server.php b/tests/server.php new file mode 100644 index 00000000..9a50eb06 --- /dev/null +++ b/tests/server.php @@ -0,0 +1,111 @@ +on (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); diff --git a/tests/session_badconf_emptyprefix.phpt b/tests/session_badconf_emptyprefix.phpt index fd19f1df..f49a8417 100644 --- a/tests/session_badconf_emptyprefix.phpt +++ b/tests/session_badconf_emptyprefix.phpt @@ -24,5 +24,5 @@ session_write_close(); echo "OK"; --EXPECTF-- -Warning: ini_set(): memcached.sess_prefix cannot contain whitespace characters in %s on line %d +Warning: ini_set(): memcached.sess_prefix cannot contain whitespace or control characters in %s on line %d OK diff --git a/tests/session_badconf_persistent.phpt b/tests/session_badconf_persistent.phpt new file mode 100644 index 00000000..7deeb1e1 --- /dev/null +++ b/tests/session_badconf_persistent.phpt @@ -0,0 +1,25 @@ +--TEST-- +Session bad configurations, persistent +--SKIPIF-- + +--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 @@ -24,5 +25,5 @@ ini_set('session.save_path', ''); session_start(); session_write_close(); ---EXPECTF-- +--EXPECT-- session_start(): failed to parse session.save_path diff --git a/tests/session_basic.phpt b/tests/session_basic.phpt index 3fdb6bd7..0e8b3469 100644 --- a/tests/session_basic.phpt +++ b/tests/session_basic.phpt @@ -7,6 +7,7 @@ if (!Memcached::HAVE_SESSION) print "skip"; ?> --INI-- session.save_handler = memcached +memcached.sess_binary_protocol = Off --FILE-- --INI-- session.save_handler = memcached +memcached.sess_binary_protocol = Off --FILE-- --INI-- session.save_handler = memcached +memcached.sess_binary_protocol = Off --FILE-- = 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) { +} diff --git a/tests/session_lock-php71.phpt b/tests/session_lock-php71.phpt new file mode 100644 index 00000000..c0fceb67 --- /dev/null +++ b/tests/session_lock-php71.phpt @@ -0,0 +1,66 @@ +--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 diff --git a/tests/session_lock.phpt b/tests/session_lock.phpt index 79c32888..cedc83bb 100644 --- a/tests/session_lock.phpt +++ b/tests/session_lock.phpt @@ -4,6 +4,8 @@ Session lock = 70100) print "skip"; ?> --INI-- memcached.sess_locking = true @@ -12,6 +14,10 @@ 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-- diff --git a/tests/session_persistent.phpt b/tests/session_persistent.phpt new file mode 100644 index 00000000..e096f2b6 --- /dev/null +++ b/tests/session_persistent.phpt @@ -0,0 +1,28 @@ +--TEST-- +Session persistent +--SKIPIF-- + +--INI-- +session.save_handler=memcached +memcached.sess_persistent=1 +--FILE-- + +--EXPECT-- +array(1) { + ["test"]=> + bool(true) +} diff --git a/tests/experimental/set_bykey.phpt b/tests/set_bykey.phpt similarity index 83% rename from tests/experimental/set_bykey.phpt rename to tests/set_bykey.phpt index e1fec459..eb61159f 100644 --- a/tests/experimental/set_bykey.phpt +++ b/tests/set_bykey.phpt @@ -1,10 +1,10 @@ --TEST-- Memcached::setByKey() --SKIPIF-- - + --FILE-- setByKey('foo', 'foo', 1, 10)); @@ -14,7 +14,7 @@ echo $m->getResultMessage(), "\n"; var_dump($m->setByKey('foo', '', 1, 10)); echo $m->getResultMessage(), "\n"; // This is OK for the binary protocol -$rv = $m->setByKey('foo', ' asd ���', 1, 1); +$rv = $m->setByKey('foo', ' asd åäö', 1, 1); if ($m->getOption(Memcached::OPT_BINARY_PROTOCOL)) { if ($rv !== true and $m->getResultCode() !== Memcached::RES_SUCCESS) { var_dump($rv); diff --git a/tests/experimental/set_comp_below_factor.phpt b/tests/set_comp_below_factor.phpt similarity index 74% rename from tests/experimental/set_comp_below_factor.phpt rename to tests/set_comp_below_factor.phpt index 12e6d6a4..80d28006 100644 --- a/tests/experimental/set_comp_below_factor.phpt +++ b/tests/set_comp_below_factor.phpt @@ -1,10 +1,10 @@ --TEST-- Compress below factor and fail to plain. --SKIPIF-- - + --FILE-- + --FILE-- +--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 diff --git a/tests/set_encoding_key2.phpt b/tests/set_encoding_key2.phpt new file mode 100644 index 00000000..f8d21a16 --- /dev/null +++ b/tests/set_encoding_key2.phpt @@ -0,0 +1,37 @@ +--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 diff --git a/tests/experimental/set_invalid_serializer.phpt b/tests/set_invalid_serializer.phpt similarity index 92% rename from tests/experimental/set_invalid_serializer.phpt rename to tests/set_invalid_serializer.phpt index 5b47a2fe..6ca07e80 100644 --- a/tests/experimental/set_invalid_serializer.phpt +++ b/tests/set_invalid_serializer.phpt @@ -1,7 +1,7 @@ --TEST-- Set invalid serializer --SKIPIF-- - + --FILE-- 0, +)); $key = 'foobarbazDEADC0DE'; $value = str_repeat("foo bar", 1024 * 1024); diff --git a/tests/set_large_e2big.phpt b/tests/set_large_e2big.phpt new file mode 100644 index 00000000..498231e4 --- /dev/null +++ b/tests/set_large_e2big.phpt @@ -0,0 +1,27 @@ +--TEST-- +set data exceeding size limit +--SKIPIF-- + +--FILE-- + 100, +)); + +$m->delete('set_large_e2big_test'); + +$value = str_repeat('a large payload', 1024 * 1024); + +var_dump($m->set('set_large_e2big_test', $value)); +var_dump($m->getResultCode() == Memcached::RES_E2BIG); +var_dump($m->getResultMessage() == 'ITEM TOO BIG'); +var_dump($m->get('set_large_e2big_test') === false); +var_dump($m->getResultCode() == Memcached::RES_NOTFOUND); +?> +--EXPECT-- +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) diff --git a/tests/experimental/setget_zero_factor.phpt b/tests/setget_zero_factor.phpt similarity index 70% rename from tests/experimental/setget_zero_factor.phpt rename to tests/setget_zero_factor.phpt index bb5fb0dc..7d7634c2 100644 --- a/tests/experimental/setget_zero_factor.phpt +++ b/tests/setget_zero_factor.phpt @@ -1,10 +1,10 @@ --TEST-- Compress with 0 factor and get --SKIPIF-- - + --FILE-- + --FILE-- setOptions(array( 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"; @@ -36,6 +38,7 @@ bool(true) bool(true) bool(true) bool(true) +bool(true) test invalid options Warning: Memcached::setOptions(): invalid configuration option in %s on line %d diff --git a/tests/stats_hang.phpt b/tests/stats_hang.phpt new file mode 100644 index 00000000..181e15e0 --- /dev/null +++ b/tests/stats_hang.phpt @@ -0,0 +1,89 @@ +--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 diff --git a/tests/touch_binary.phpt b/tests/touch_binary.phpt index cc35e8fb..059ec74c 100644 --- a/tests/touch_binary.phpt +++ b/tests/touch_binary.phpt @@ -4,7 +4,10 @@ Touch in binary mode --FILE-- getResultcode(); if ($code == $expected) - echo "${op} status code as expected" . PHP_EOL; + 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; + echo "{$op} status code mismatch, expected {$expected} but got {$code}" . PHP_EOL; } } diff --git a/tests/undefined_set.phpt b/tests/undefined_set.phpt index 2e8b1c1c..581c9406 100644 --- a/tests/undefined_set.phpt +++ b/tests/undefined_set.phpt @@ -10,30 +10,25 @@ $m = memc_get_instance (); $key = 'foobarbazDEADC0DE'; $value = array('foo' => 'bar'); -$rv = $m->set($no_key, $value, 360); +// 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); +$rv = @$m->set($key, $no_value, 360); var_dump($rv); -$rv = $m->set($no_key, $no_value, 360); +$rv = @$m->set($no_key, $no_value, 360); var_dump($rv); -$rv = $m->set($key, $value, $no_time); +$rv = @$m->set($key, $value, $no_time); var_dump($rv); ?> --EXPECTF-- -Notice: Undefined variable: no_key in %s bool(false) - -Notice: Undefined variable: no_value in %s bool(true) - -Notice: Undefined variable: no_key in %s - -Notice: Undefined variable: no_value in %s bool(false) - -Notice: Undefined variable: no_time in %s bool(true) diff --git a/tests/vbucket.phpt b/tests/vbucket.phpt index f17eb94a..a691680d 100644 --- a/tests/vbucket.phpt +++ b/tests/vbucket.phpt @@ -18,14 +18,6 @@ var_dump ($m->setBucket (array (1,2,2), array (1,2,2), 2)); var_dump ($m->setBucket (array ('a', 'b', 'c'), null, 2)); -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"; ?> @@ -33,16 +25,4 @@ echo "OK\n"; bool(true) bool(true) bool(true) - -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 diff --git a/tests/vbucket_error_7.phpt b/tests/vbucket_error_7.phpt new file mode 100644 index 00000000..286534af --- /dev/null +++ b/tests/vbucket_error_7.phpt @@ -0,0 +1,40 @@ +--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 diff --git a/tests/vbucket_error_8.phpt b/tests/vbucket_error_8.phpt new file mode 100644 index 00000000..c8af2315 --- /dev/null +++ b/tests/vbucket_error_8.phpt @@ -0,0 +1,41 @@ +--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