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 1db3dd44..31994e3b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,72 @@ 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) -------------------------- diff --git a/README.markdown b/README.markdown index f145c2df..38dbd5bc 100644 --- a/README.markdown +++ b/README.markdown @@ -1,6 +1,6 @@ Build Status ------------ -[![Build Status](https://travis-ci.org/php-memcached-dev/php-memcached.png)](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 ----------- @@ -23,7 +23,7 @@ Dependencies ------------ php-memcached 3.x: -* Supports PHP 7.0 - 7.1. +* 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. @@ -34,9 +34,10 @@ php-memcached 2.x: * Optionally supports igbinary 1.0 or higher. * Optionally supports msgpack 0.5 or higher. -[libmemcached](http://libmemcached.org/libMemcached.html) version 1.0.18 or -higher is recommended for best performance and compatibility with memcached -servers. +[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 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 b34c30bf..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 protocol 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 f5174e22..8ab03d4c 100644 --- a/memcached-api.php +++ b/memcached-api.php @@ -96,6 +96,8 @@ class Memcached { const HAVE_MSGPACK; + const HAVE_ENCODING; + /** * Feature support */ @@ -363,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 6d05da3c..5decf399 100644 --- a/memcached.ini +++ b/memcached.ini @@ -7,12 +7,12 @@ ; 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. @@ -20,8 +20,7 @@ ; 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. +; use PHP's max_execution_time. ;memcached.sess_lock_expire = 0; ; memcached session key prefix @@ -44,6 +43,13 @@ ; default is 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 @@ -54,7 +60,7 @@ ; 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 @@ -79,7 +85,6 @@ ; 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 ; Session SASL password @@ -125,8 +130,14 @@ ; 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, diff --git a/package.xml b/package.xml index 5e1961f7..5565863e 100644 --- a/package.xml +++ b/package.xml @@ -27,24 +27,30 @@ http://pear.php.net/dtd/package-2.0.xsd"> aaron@serendipity.cx yes - 2017-02-19 + + Remi Collet + remi + remi@php.net + yes + + + Michael Wallner + mike + mike@php.net + yes + + 2024-10-17 - 3.0.3 - 3.0.0 + 3.3.1dev + 3.3.0 - stable + 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. - -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) +- @@ -59,6 +65,9 @@ Fixes + + + @@ -84,6 +93,7 @@ Fixes + @@ -100,6 +110,7 @@ Fixes + @@ -111,6 +122,7 @@ Fixes + @@ -132,10 +144,13 @@ Fixes + + + @@ -153,6 +168,8 @@ Fixes + + @@ -160,9 +177,14 @@ Fixes + - + + + + + @@ -188,9 +210,253 @@ Fixes 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 diff --git a/php_memcached.c b/php_memcached.c index 65d11eb2..b78eb82a 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,18 +37,30 @@ #endif #include +#ifdef HAVE_ZSTD_H +#include +#endif + #ifdef HAVE_JSON_API # include "ext/json/php_json.h" #endif #ifdef HAVE_MEMCACHED_IGBINARY +#ifdef PHP_WIN32 +//Windows extensions are generally built together, +//so it wont be in the installed location +#include "igbinary.h" +#else # include "ext/igbinary/igbinary.h" #endif +#endif #ifdef HAVE_MEMCACHED_MSGPACK # include "ext/msgpack/php_msgpack.h" #endif +# include "ext/spl/spl_exceptions.h" + static int le_memc; static int php_memc_list_entry(void) { @@ -71,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 @@ -80,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) @@ -101,6 +113,7 @@ 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)) @@ -142,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; @@ -188,6 +204,7 @@ 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) { \ @@ -196,6 +213,16 @@ static inline php_memc_object_t *php_memc_fetch_object(zend_object *obj) { } \ 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) @@ -204,31 +231,49 @@ zend_bool s_memc_valid_key_binary(zend_string *key) } static -zend_bool s_memc_valid_key_ascii(zend_string *key) +uint32_t s_memc_object_key_max_length(php_memc_object_t *intern) { + memcached_return retval; + char *result; + + result = memcached_callback_get(intern->memc, MEMCACHED_CALLBACK_PREFIX_KEY, &retval); + if (retval == MEMCACHED_SUCCESS && result) { + return MEMC_OBJECT_KEY_MAX_LENGTH - strlen(result); + } else { + return MEMC_OBJECT_KEY_MAX_LENGTH; + } +} + +zend_bool s_memc_valid_key_ascii(zend_string *key, uint64_t verify_key) { const char *str = ZSTR_VAL(key); size_t i, len = ZSTR_LEN(key); - for (i = 0; i < len; i++) { - if (iscntrl(str[i]) || isspace(str[i])) - return 0; + 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) > MEMC_OBJECT_KEY_MAX_LENGTH || \ + 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) \ + : !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; @@ -247,10 +292,6 @@ static zend_class_entry *memcached_ce = NULL; static zend_class_entry *memcached_exception_ce = NULL; static zend_object_handlers memcached_object_handlers; -#ifdef HAVE_SPL -static zend_class_entry *spl_ce_RuntimeException = NULL; -#endif - ZEND_DECLARE_MODULE_GLOBALS(php_memcached) #ifdef COMPILE_DL_MEMCACHED @@ -265,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; } @@ -298,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) { @@ -315,7 +361,7 @@ PHP_INI_MH(OnUpdateSessionPrefixString) 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)) { + 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; } @@ -323,37 +369,68 @@ PHP_INI_MH(OnUpdateSessionPrefixString) 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) #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x01000018 - MEMC_SESSION_INI_ENTRY("binary_protocol", "0", OnUpdateBool, binary_protocol_enabled) + MEMC_SESSION_INI_BOOL ("binary_protocol", "0", OnUpdateBool, binary_protocol_enabled) #else - MEMC_SESSION_INI_ENTRY("binary_protocol", "1", OnUpdateBool, binary_protocol_enabled) + MEMC_SESSION_INI_BOOL ("binary_protocol", "1", OnUpdateBool, binary_protocol_enabled) #endif - MEMC_SESSION_INI_ENTRY("consistent_hash", "1", OnUpdateBool, consistent_hash_enabled) + 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) @@ -363,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 /**************************************** @@ -455,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)); @@ -820,7 +903,7 @@ 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; @@ -848,12 +931,39 @@ zend_bool s_compress_value (php_memc_compression_type compression_type, zend_str } 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; compression_type_flag = MEMC_VAL_COMPRESSION_ZLIB; } @@ -1043,7 +1153,7 @@ zend_string *s_zval_to_payload(php_memc_object_t *intern, zval *value, uint32_t * * No need to check the return value because the payload is always valid. */ - (void)s_compress_value (memc_user_data->compression_type, &payload, flags); + (void)s_compress_value (memc_user_data->compression_type, memc_user_data->compression_level, &payload, flags); } if (memc_user_data->set_udf_flags >= 0) { @@ -1053,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) { @@ -1079,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; @@ -1184,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; @@ -1223,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)); } } @@ -1285,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) { @@ -1401,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; @@ -1413,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; @@ -1484,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); @@ -1505,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; @@ -1642,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; @@ -1796,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; @@ -1804,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; @@ -1830,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); @@ -1921,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(); } } @@ -1984,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; @@ -2014,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 { @@ -2081,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; } @@ -2120,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; @@ -2172,21 +2382,33 @@ static void php_memc_incdec_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key, { zend_string *key, *server_key = NULL; zend_long offset = 1; - uint64_t value = UINT64_MAX, initial = 0; - time_t expiry = 0; + 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; @@ -2228,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), 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), 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), 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), 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) { @@ -2293,13 +2515,17 @@ 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); @@ -2327,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); @@ -2431,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); @@ -2624,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)) { @@ -2649,19 +2877,33 @@ 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(ZEND_NUM_ARGS(), "|S!", &args_string) == 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, 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; @@ -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; @@ -2846,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 { @@ -2855,6 +3109,20 @@ 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; @@ -2964,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 { @@ -3018,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; @@ -3026,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; @@ -3065,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); @@ -3084,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; @@ -3114,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; @@ -3137,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; @@ -3162,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) @@ -3244,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 ****************************************/ @@ -3296,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); } @@ -3309,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; } @@ -3382,16 +3721,24 @@ 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) { +#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; } @@ -3403,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'; @@ -3553,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); @@ -3576,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; @@ -3593,8 +3960,8 @@ zend_class_entry *php_memc_get_exception_base(int root) return spl_ce_RuntimeException; } } -#endif - return zend_exception_get_default(); + + return zend_ce_exception; } @@ -3621,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); @@ -3642,9 +4010,11 @@ PHP_METHOD(MemcachedServer, on) 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; @@ -3658,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); @@ -3666,386 +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_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_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_prepend, 0, 0, 2) - ZEND_ARG_INFO(0, key) - ZEND_ARG_INFO(0, value) -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_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_EX(arginfo_getStats, 0, 0, 0) - ZEND_ARG_INFO(0, type) -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() - -#ifdef HAVE_MEMCACHED_SASL -ZEND_BEGIN_ARG_INFO(arginfo_setSaslAuthData, 0) - ZEND_ARG_INFO(0, username) - ZEND_ARG_INFO(0, password) -ZEND_END_ARG_INFO() -#endif - -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_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) - - MEMC_ME(touch, arginfo_touch) - MEMC_ME(touchByKey, arginfo_touchByKey) - - 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) - - MEMC_ME(getLastErrorMessage, arginfo_getLastErrorMessage) - MEMC_ME(getLastErrorCode, arginfo_getLastErrorCode) - MEMC_ME(getLastErrorErrno, arginfo_getLastErrorErrno) - 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 @@ -4062,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 @@ -4073,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; @@ -4090,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; @@ -4143,11 +4143,13 @@ 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 @@ -4158,6 +4160,15 @@ static void php_memc_register_constants(INIT_FUNC_ARGS) REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_IGBINARY, 0); #endif + /* + * Indicate whether zstd compression is available + */ +#ifdef HAVE_ZSTD_H + REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_ZSTD, 1); +#else + REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_ZSTD, 0); +#endif + /* * Indicate whether json serializer is available */ @@ -4176,6 +4187,15 @@ static void php_memc_register_constants(INIT_FUNC_ARGS) REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_MSGPACK, 0); #endif + /* + * Indicate whether set_encoding_key is available + */ +#ifdef HAVE_MEMCACHED_SET_ENCODING_KEY + REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_ENCODING, 1); +#else + REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_ENCODING, 0); +#endif + #ifdef HAVE_MEMCACHED_SESSION REGISTER_MEMC_CLASS_CONST_BOOL(HAVE_SESSION, 1); #else @@ -4242,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); @@ -4307,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. @@ -4352,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 + } /* }}} */ @@ -4373,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 @@ -4383,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 @@ -4424,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"); @@ -4456,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 65a0349f..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.3" +#define PHP_MEMCACHED_VERSION "3.3.1dev" #if defined(PHP_WIN32) && defined(MEMCACHED_EXPORTS) #define PHP_MEMCACHED_API __declspec(dllexport) @@ -42,14 +45,6 @@ PHP_MEMCACHED_API zend_class_entry *php_memc_get_exception_base(int root); extern zend_module_entry memcached_module_entry; #define phpext_memcached_ptr &memcached_module_entry -#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) -#else -#define MEMC_G(v) (php_memcached_globals.memc.v) -#define MEMC_SERVER_G(v) (php_memcached_globals.server.v) -#endif - #endif /* PHP_MEMCACHED_H */ /* 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..b7d2a5e1 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" @@ -41,12 +43,20 @@ #include #include #include +#if PHP_VERSION_ID < 70200 #include +#else +#include +#endif #include #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 +82,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 +102,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 +167,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 +191,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 +222,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 4c0080e8..24c328f8 100644 --- a/php_memcached_server.c +++ b/php_memcached_server.c @@ -17,11 +17,10 @@ #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_SERVER_G(callbacks)[cb_type]) @@ -58,12 +57,14 @@ typedef struct { static long s_invoke_php_callback (php_memc_server_cb_t *cb, zval *params, ssize_t param_count) { - zval *retval = NULL; + zval retval; - cb->fci.retval = retval; + cb->fci.retval = &retval; cb->fci.params = params; cb->fci.param_count = param_count; +#if PHP_VERSION_ID < 80000 cb->fci.no_separation = 1; +#endif if (zend_call_function(&(cb->fci), &(cb->fci_cache)) == FAILURE) { char *buf = php_memc_printable_func(&(cb->fci), &(cb->fci_cache)); @@ -71,7 +72,7 @@ long s_invoke_php_callback (php_memc_server_cb_t *cb, zval *params, ssize_t para efree (buf); } - return retval == NULL ? PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND : zval_get_long(retval); + return Z_ISUNDEF(retval) ? PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND : zval_get_long(&retval); } // memcached protocol callbacks @@ -94,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); @@ -140,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); @@ -196,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); @@ -294,6 +299,7 @@ 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); @@ -320,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); @@ -434,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); @@ -492,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; @@ -500,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]); @@ -526,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; } @@ -545,12 +583,12 @@ 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); @@ -579,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)); - 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); @@ -712,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; @@ -768,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 afa973bb..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; @@ -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); @@ -376,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) { @@ -444,7 +450,7 @@ PS_READ_FUNC(memcached) *val = ZSTR_EMPTY_ALLOC(); return SUCCESS; } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "error getting session from memcached: %s", memcached_last_error_message(memc)); + php_error_docref(NULL, E_WARNING, "error getting session from memcached: %s", memcached_last_error_message(memc)); return FAILURE; } } @@ -474,7 +480,7 @@ PS_WRITE_FUNC(memcached) if (memcached_set(memc, key->val, key->len, val->val, val->len, expiration, 0) == MEMCACHED_SUCCESS) { return SUCCESS; } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "error saving session to memcached: %s", memcached_last_error_message(memc)); + php_error_docref(NULL, E_WARNING, "error saving session to memcached: %s", memcached_last_error_message(memc)); } } while (--retries > 0); 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-- + --FILE-- setOption(Memcached::OPT_COMPRESSION, false); diff --git a/tests/bad_construct.phpt b/tests/bad_construct.phpt index 0b740e00..0c278796 100644 --- a/tests/bad_construct.phpt +++ b/tests/bad_construct.phpt @@ -1,7 +1,10 @@ --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 index 749ebe8a..960058b6 100644 --- a/tests/compression_conditions.phpt +++ b/tests/compression_conditions.phpt @@ -21,6 +21,8 @@ function get_compression($name) { return Memcached::COMPRESSION_ZLIB; case 'fastlz': return Memcached::COMPRESSION_FASTLZ; + case 'zstd': + return Memcached::COMPRESSION_ZSTD; default: echo "Strange compression type: $name\n"; return 0; 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/setmulti_badserialize.phpt b/tests/experimental/setmulti_badserialize.phpt index eafc7772..2d8dde53 100644 --- a/tests/experimental/setmulti_badserialize.phpt +++ b/tests/experimental/setmulti_badserialize.phpt @@ -42,6 +42,5 @@ try { 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(); diff --git a/tests/experimental/fetchall_badunserialize.phpt b/tests/fetchall_badunserialize.phpt similarity index 76% rename from tests/experimental/fetchall_badunserialize.phpt rename to tests/fetchall_badunserialize.phpt index 5684763f..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(); 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) { 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 77% rename from tests/experimental/getmulti_badunserialize.phpt rename to tests/getmulti_badunserialize.phpt index 963e9730..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)); 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_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/keys_ascii.phpt b/tests/keys_ascii.phpt index f7e98894..e7846e99 100644 --- a/tests/keys_ascii.phpt +++ b/tests/keys_ascii.phpt @@ -8,11 +8,8 @@ Test valid and invalid keys - ascii include dirname (__FILE__) . '/config.inc'; $ascii = memc_get_instance (array ( Memcached::OPT_BINARY_PROTOCOL => false, - Memcached::OPT_VERIFY_KEY => false + Memcached::OPT_VERIFY_KEY => true )); -// libmemcached can verify keys, but these are tests are for our own -// function s_memc_valid_key_ascii, so explicitly disable the checks -// that libmemcached can perform. echo 'ASCII: SPACES' . PHP_EOL; var_dump ($ascii->set ('ascii key with spaces', 'this is a test')); 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 82% rename from tests/experimental/replace_bykey.phpt rename to tests/replace_bykey.phpt index cddf10f0..b844824c 100644 --- a/tests/experimental/replace_bykey.phpt +++ b/tests/replace_bykey.phpt @@ -1,10 +1,10 @@ --TEST-- Memcached::replaceByKey() --SKIPIF-- - + --FILE-- 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_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-- + + --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 382c1778..059ec74c 100644 --- a/tests/touch_binary.phpt +++ b/tests/touch_binary.phpt @@ -28,12 +28,12 @@ function status_print ($op, $mem, $expected) $code = $mem->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