Merge remote-tracking branch 'parent/master' into feature-udf

This commit is contained in:
Nicolas Van Eenaeme
2013-11-07 22:50:43 +01:00
28 changed files with 1114 additions and 342 deletions

43
.travis.yml Normal file
View File

@@ -0,0 +1,43 @@
language: php
php:
- 5.5
#- 5.4
#- 5.3
env:
- LIBMEMCACHED_VERSION=1.0.17
- LIBMEMCACHED_VERSION=1.0.16
- LIBMEMCACHED_VERSION=1.0.15
- LIBMEMCACHED_VERSION=1.0.14
- LIBMEMCACHED_VERSION=1.0.10
- LIBMEMCACHED_VERSION=1.0.8
- LIBMEMCACHED_VERSION=1.0.2
- LIBMEMCACHED_VERSION=0.53
- LIBMEMCACHED_VERSION=0.44
before_script:
- for file in tests/*.phpt; do grep $(basename $file) package.xml >/dev/null || (echo "Missing $file from package.xml" ; exit 1); done
- wget "https://launchpad.net/libmemcached/1.0/${LIBMEMCACHED_VERSION}/+download/libmemcached-${LIBMEMCACHED_VERSION}.tar.gz"
- tar xvfz libmemcached-${LIBMEMCACHED_VERSION}.tar.gz
- cd libmemcached-${LIBMEMCACHED_VERSION}
- ./configure --prefix="${HOME}/libmemcached-${LIBMEMCACHED_VERSION}" LDFLAGS="-lpthread"
- make
- make install
- cd ..
script:
- export PHP_MEMCACHED_VERSION=$(php -r '$sxe = simplexml_load_file ("package.xml"); echo (string) $sxe->version->release;')
- pear package
- mkdir /tmp/php-memcached-build
- tar xfz "memcached-${PHP_MEMCACHED_VERSION}.tgz" -C /tmp/php-memcached-build
- cd /tmp/php-memcached-build/memcached-${PHP_MEMCACHED_VERSION}
- phpize
- ./configure --with-libmemcached-dir="${HOME}/libmemcached-${LIBMEMCACHED_VERSION}"
- make
- export NO_INTERACTION=1
- export REPORT_EXIT_STATUS=1
- export TEST_PHP_EXECUTABLE=`which php`
- php run-tests.php -d extension=memcached.so -d extension_dir=modules -n ./tests/*.phpt
- for i in `ls tests/*.out 2>/dev/null`; do echo "-- START ${i}"; cat $i; echo ""; echo "-- END"; done

View File

@@ -1,5 +1,22 @@
memcached extension changelog
Version 2.2.0b1
---------------
* Reinstate support for libememcached 0.x series
* Added SASL support to session handler
* Added Memcached::flushBuffers as per GH #78
* Fixes GH #54: Fixed UDP server adding with newer libmemcached
* Fixed PHP bug #65334: (Segfault if uncompress value failed)
* Fixes GH #14: get with cas token fails to fetch all results
* Fixes GH #68: memcached 2.1.0 requires libmemcached 1.0.10
* Fixes GH #69: compiling on CentOS 6.4 with libmemcached 1.0.17
* Merged PR #91: memcached.sess_lock_wait and memcached.sess_lock_max_wait
* Added session handler settings:
- memcached.sess_number_of_replicas
- memcached.sess_randomize_replica_read
- memcached.sess_remove_failed
- memcached.sess_connect_timeout
Version 2.1.0
-------------
* Drop support for libmemcached 0.x series, now 1.0.x is required
@@ -41,8 +58,6 @@ Version 2.0.0b2
Version 2.0.0b1
---------------
* Change the return value for non-existing keys to be NULL rather than
'false', affects simple get only
* Add fastlz library that provides better/faster payload compression
* Add configure switch to enable/disable JSON serialization support
* Add getAllKeys() method

View File

@@ -1,3 +1,7 @@
Build Status
------------
[![Build Status](https://travis-ci.org/php-memcached-dev/php-memcached.png?branch=master)](https://travis-ci.org/php-memcached-dev/php-memcached)
Description
-----------
This extension uses libmemcached library to provide API for communicating with
@@ -7,8 +11,16 @@ memcached is a high-performance, distributed memory object caching system,
generic in nature, but intended for use in speeding up dynamic web applications
by alleviating database load.
Building
--------
$ phpize
$ ./configure
$ make
$ make test
Resources
---------
* [libmemcached](http://tangent.org/552/libmemcached.html)
* [memcached](http://www.danga.com/memcached/)
* [libmemcached](http://libmemcached.org/libMemcached.html)
* [memcached](http://memcached.org/)
* [igbinary](https://github.com/phadej/igbinary/)

101
config.m4
View File

@@ -18,7 +18,7 @@ PHP_ARG_ENABLE(memcached-json, whether to enable memcached json serializer suppo
[ --enable-memcached-json Enable memcached json serializer support], no, no)
PHP_ARG_ENABLE(memcached-sasl, whether to disable memcached sasl support,
[ --disable-memcached-sasl Disable memcached sasl support], no, no)
[ --disable-memcached-sasl Disable memcached sasl support], yes, no)
if test -z "$PHP_ZLIB_DIR"; then
PHP_ARG_WITH(zlib-dir, for ZLIB,
@@ -224,8 +224,8 @@ if test "$PHP_MEMCACHED" != "no"; then
AC_MSG_CHECKING([for libmemcached location])
if test "$PHP_LIBMEMCACHED_DIR" != "no" && test "$PHP_LIBMEMCACHED_DIR" != "yes"; then
if ! test -r "$PHP_LIBMEMCACHED_DIR/include/libmemcached-1.0/memcached.h"; then
AC_MSG_ERROR([Can't find libmemcached 1.0.x headers under "$PHP_LIBMEMCACHED_DIR"])
if ! test -r "$PHP_LIBMEMCACHED_DIR/include/libmemcached/memcached.h"; then
AC_MSG_ERROR([Can't find libmemcached headers under "$PHP_LIBMEMCACHED_DIR"])
fi
else
PHP_LIBMEMCACHED_DIR="no"
@@ -238,7 +238,7 @@ if test "$PHP_MEMCACHED" != "no"; then
fi
if test "$PHP_LIBMEMCACHED_DIR" = "no"; then
AC_MSG_ERROR([memcached support requires libmemcached 1.0.x. Use --with-libmemcached-dir=<DIR> to specify the prefix where libmemcached headers and library are located])
AC_MSG_ERROR([memcached support requires libmemcached. Use --with-libmemcached-dir=<DIR> to specify the prefix where libmemcached headers and library are located])
else
AC_MSG_RESULT([$PHP_LIBMEMCACHED_DIR])
@@ -246,9 +246,100 @@ if test "$PHP_MEMCACHED" != "no"; then
PHP_ADD_INCLUDE($PHP_LIBMEMCACHED_INCDIR)
PHP_ADD_LIBRARY_WITH_PATH(memcached, $PHP_LIBMEMCACHED_DIR/$PHP_LIBDIR, MEMCACHED_SHARED_LIBADD)
ORIG_CFLAGS="$CFLAGS"
ORIG_LIBS="$LIBS"
CFLAGS="$CFLAGS -I$PHP_LIBMEMCACHED_INCDIR"
#
# Added -lpthread here because AC_TRY_LINK tests on CentOS 6 seem to fail with undefined reference to pthread_once
#
LIBS="$LIBS -lpthread -lmemcached -L$PHP_LIBMEMCACHED_DIR/$PHP_LIBDIR"
AC_CACHE_CHECK([whether memcached_instance_st is defined], ac_cv_have_memcached_instance_st, [
AC_TRY_COMPILE(
[ #include <libmemcached/memcached.h> ],
[ const memcached_instance_st *instance = NULL; ],
[ ac_cv_have_memcached_instance_st="yes" ],
[ ac_cv_have_memcached_instance_st="no" ]
)
])
AC_CACHE_CHECK([whether MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS is defined], ac_cv_have_libmemcached_remove_failed_servers, [
AC_TRY_COMPILE(
[ #include <libmemcached/memcached.h> ],
[ MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS; ],
[ ac_cv_have_libmemcached_remove_failed_servers="yes" ],
[ ac_cv_have_libmemcached_remove_failed_servers="no" ]
)
])
AC_CACHE_CHECK([whether MEMCACHED_SERVER_TEMPORARILY_DISABLED is defined], ac_cv_have_libmemcached_server_temporarily_disabled, [
AC_TRY_COMPILE(
[ #include <libmemcached/memcached.h> ],
[ MEMCACHED_SERVER_TEMPORARILY_DISABLED; ],
[ ac_cv_have_libmemcached_server_temporarily_disabled="yes" ],
[ ac_cv_have_libmemcached_server_temporarily_disabled="no" ]
)
])
AC_CACHE_CHECK([whether memcached function exists], ac_cv_have_libmemcached_memcached, [
AC_TRY_LINK(
[ #include <libmemcached/memcached.h> ],
[ memcached("t", sizeof ("t")); ],
[ ac_cv_have_libmemcached_memcached="yes" ],
[ ac_cv_have_libmemcached_memcached="no" ]
)
])
AC_CACHE_CHECK([whether libmemcached_check_configuration function exists], ac_cv_have_libmemcached_check_configuration, [
AC_TRY_LINK(
[ #include <libmemcached/memcached.h> ],
[ libmemcached_check_configuration("", 1, "", 1); ],
[ ac_cv_have_libmemcached_check_configuration="yes" ],
[ ac_cv_have_libmemcached_check_configuration="no" ]
)
])
AC_CACHE_CHECK([whether memcached_touch function exists], ac_cv_have_libmemcached_touch, [
AC_TRY_LINK(
[ #include <libmemcached/memcached.h> ],
[ memcached_touch (NULL, NULL, 0, 0); ],
[ ac_cv_have_libmemcached_touch="yes" ],
[ ac_cv_have_libmemcached_touch="no" ]
)
])
CFLAGS="$ORIG_CFLAGS"
LIBS="$ORIG_LIBS"
if test "$ac_cv_have_memcached_instance_st" = "yes"; then
AC_DEFINE(HAVE_MEMCACHED_INSTANCE_ST, [1], [Whether memcached_instance_st is defined])
fi
if test "$ac_cv_have_libmemcached_remove_failed_servers" = "yes"; then
AC_DEFINE(HAVE_LIBMEMCACHED_REMOVE_FAILED_SERVERS, [1], [Whether MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS is defined])
fi
if test "$ac_cv_have_libmemcached_server_temporarily_disabled" = "yes"; then
AC_DEFINE(HAVE_LIBMEMCACHED_SERVER_TEMPORARILY_MARKER_DISABLED, [1], [Whether MEMCACHED_SERVER_TEMPORARILY_DISABLED is defined])
fi
if test "$ac_cv_have_libmemcached_memcached" = "yes"; then
AC_DEFINE(HAVE_LIBMEMCACHED_MEMCACHED, [1], [Whether memcached is defined])
fi
if test "$ac_cv_have_libmemcached_check_configuration" = "yes"; then
AC_DEFINE(HAVE_LIBMEMCACHED_CHECK_CONFIGURATION, [1], [Whether libmemcached_check_configuration is defined])
fi
if test "$ac_cv_have_libmemcached_touch" = "yes"; then
AC_DEFINE(HAVE_LIBMEMCACHED_TOUCH, [1], [Whether memcached_touch is defined])
fi
PHP_SUBST(MEMCACHED_SHARED_LIBADD)
PHP_MEMCACHED_FILES="php_memcached.c fastlz/fastlz.c g_fmt.c"
PHP_MEMCACHED_FILES="php_memcached.c php_libmemcached_compat.c fastlz/fastlz.c g_fmt.c"
if test "$PHP_MEMCACHED_SESSION" != "no"; then
PHP_MEMCACHED_FILES="${PHP_MEMCACHED_FILES} php_memcached_session.c"

View File

@@ -241,9 +241,9 @@ class Memcached {
public function deleteMultiByKey( $server_key, array $keys, $expiration = 0 ) {}
public function increment( $key, $offset = 1) {}
public function increment( $key, $offset = 1, $initial_value = 0, $expiry = 0) {}
public function decrement( $key, $offset = 1) {}
public function decrement( $key, $offset = 1, $initial_value = 0, $expiry = 0) {}
public function getOption( $option ) {}
@@ -281,6 +281,8 @@ class Memcached {
public function isPristine( ) {}
public function setSaslAuthData( $username, $password ) {}
}
class MemcachedException extends Exception {

View File

@@ -12,6 +12,18 @@ memcached.sess_locking = On
; the default is 150000
memcached.sess_lock_wait = 150000
; The maximum time, in seconds, to wait for a session lock
; before timing out.
; Setting to 0 results in default behavior, which is to
; use max_execution_time.
memcached.sess_lock_max_wait = 0;
; The time, in seconds, before a lock should release itself.
; Setting to 0 results in the default behaviour, which is to
; use the memcached.sess_lock_max_wait setting. If that is
; also 0, max_execution_time will be used.
memcached.sess_lock_expire = 0;
; memcached session key prefix
; valid values are strings less than 219 bytes long
; the default value is "memc.sess.key."
@@ -35,18 +47,28 @@ memcached.sess_remove_failed = 1
; from a replica. However, if the failed memcache server
; becomes available again it will read the session from there
; which could have old data or no data at all
memcached.sess_num_replicas = 0;
memcached.sess_number_of_replicas = 0
; memcached session binary mode
; libmemcached replicas only work if binary mode is enabled
memcached.sess_binary = Off
; memcached session number of replicas
memcached.sess_number_of_replicas = 0
; memcached session replica read randomize
memcached.sess_randomize_replica_read = Off
; memcached connect timeout value
; In non-blocking mode this changes the value of the timeout
; during socket connection in milliseconds. Specifying -1 means an infinite timeout.
memcached.sess_connect_timeout = 1000
; 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
memcached.sess_sasl_password = NULL
; Set the compression type
; valid values are: fastlz, zlib
; the default is fastlz
@@ -81,3 +103,9 @@ memcached.compression_threshold = 2000
;
; The default is igbinary if available and php otherwise.
memcached.serializer = "igbinary"
; Use SASL authentication for connections
; valid values: On, Off
; the default is Off
memcached.use_sasl = Off

View File

@@ -15,20 +15,37 @@ http://pear.php.net/dtd/package-2.0.xsd">
<email>andrei@php.net</email>
<active>yes</active>
</lead>
<date>2012-08-06</date>
<lead>
<name>Mikko Koppanen</name>
<user>mkoppanen</user>
<email>mkoppanen@php.net</email>
<active>yes</active>
</lead>
<date>2013-10-28</date>
<version>
<release>2.1.0</release>
<api>2.1.0</api>
<release>2.2.0b1</release>
<api>2.2.0</api>
</version>
<stability>
<release>stable</release>
<release>beta</release>
<api>stable</api>
</stability>
<license uri="http://www.php.net/license">PHP</license>
<notes>
- Drop support for libmemcached 0.x series, now 1.0.x is required
- Add support for virtual bucket distribution
- Fix compilation against PHP 5.2
- Reinstate support for libememcached 0.x series
- Added SASL support to session handler
- Added Memcached::flushBuffers as per GH #78
- Fixes GH #54: Fixed UDP server adding with newer libmemcached
- Fixed PHP bug #65334: (Segfault if uncompress value failed)
- Fixes GH #14: get with cas token fails to fetch all results
- Fixes GH #68: memcached 2.1.0 requires libmemcached 1.0.10
- Fixes GH #69: compiling on CentOS 6.4 with libmemcached 1.0.17
- Merged PR #91: More granular session locking support
- Added session handler settings:
* memcached.sess_number_of_replicas
* memcached.sess_randomize_replica_read
* memcached.sess_remove_failed
* memcached.sess_connect_timeout
</notes>
<contents>
<dir name="/">
@@ -46,11 +63,62 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file role='src' name='php_memcached_session.c'/>
<file role='src' name='php_memcached_session.h'/>
<file role='src' name='php_libmemcached_compat.h'/>
<file role='src' name='php_libmemcached_compat.c'/>
<file role='src' name='g_fmt.c'/>
<file role='src' name='g_fmt.h'/>
<file role='src' name='fastlz/fastlz.c'/>
<file role='src' name='fastlz/fastlz.h'/>
</dir> <!-- / -->
<dir name="tests">
<file role='test' name='001.phpt'/>
<file role='test' name='version.phpt'/>
<file role='test' name='bug_16084.phpt'/>
<file role='test' name='bug_16959.phpt'/>
<file role='test' name='bug_17137.phpt'/>
<file role='test' name='bug_18639.phpt'/>
<file role='test' name='callback_exception.phpt'/>
<file role='test' name='callback_exception_2.phpt'/>
<file role='test' name='cas.phpt'/>
<file role='test' name='cas_multi.phpt'/>
<file role='test' name='check_if_persistent.phpt'/>
<file role='test' name='check_if_pristine.phpt'/>
<file role='test' name='clone.phpt'/>
<file role='test' name='compression_types.phpt'/>
<file role='test' name='conf_persist.phpt'/>
<file role='test' name='construct.phpt'/>
<file role='test' name='construct_persistent.phpt'/>
<file role='test' name='deleted.phpt'/>
<file role='test' name='deletemulti.phpt'/>
<file role='test' name='deletemultitypes.phpt'/>
<file role='test' name='expire.phpt'/>
<file role='test' name='flush_buffers.phpt'/>
<file role='test' name='getdelayed.phpt'/>
<file role='test' name='getserverlist.phpt'/>
<file role='test' name='gh_21.phpt'/>
<file role='test' name='gh_77.phpt'/>
<file role='test' name='gh_90.phpt'/>
<file role='test' name='invoke_callback.phpt'/>
<file role='test' name='invoke_callback_2.phpt'/>
<file role='test' name='invoke_callback_twice.phpt'/>
<file role='test' name='localserver.phpt'/>
<file role='test' name='multi_order.phpt'/>
<file role='test' name='no-not-found.phpt'/>
<file role='test' name='options.phpt'/>
<file role='test' name='pr_75.phpt'/>
<file role='test' name='rescode.phpt'/>
<file role='test' name='session_badconf_emptyprefix.phpt'/>
<file role='test' name='session_badconf_locktime.phpt'/>
<file role='test' name='session_badconf_prefix.phpt'/>
<file role='test' name='session_badconf_servers.phpt'/>
<file role='test' name='session_basic.phpt'/>
<file role='test' name='set_large.phpt'/>
<file role='test' name='setoptions.phpt'/>
<file role='test' name='touch_binary.phpt'/>
<file role='test' name='types.phpt'/>
<file role='test' name='types_multi.phpt'/>
<file role='test' name='undefined_set.phpt'/>
<file role='test' name='testdata.res'/>
</dir>
</dir>
</contents>
<dependencies>
<required>
@@ -65,8 +133,24 @@ http://pear.php.net/dtd/package-2.0.xsd">
</required>
</dependencies>
<providesextension>memcached</providesextension>
<extsrcrelease/>
<extsrcrelease>
<configureoption name="with-libmemcached-dir" default="no" prompt="libmemcached directory"/>
</extsrcrelease>
<changelog>
<release>
<stability><release>beta</release><api>stable</api></stability>
<version><release>2.2.0b1</release><api>2.2.0</api></version>
<date>2013-10-28</date>
<notes>
- Reinstate support for libememcached 0.x series
- Added SASL support to session handler
- Added Memcached::flushBuffers as per GH #78
- Fixes GH #54: Fixed UDP server adding with newer libmemcached
- Fixed PHP bug #65334: (Segfault if uncompress value failed)
- Fixes GH #14: get with cas token fails to fetch all results
- Fixes GH #69: compiling on CentOS 6.4 with libmemcached 1.0.17
</notes>
</release>
<release>
<stability><release>stable</release><api>stable</api></stability>
<version><release>2.1.0</release><api>2.1.0</api></version>

50
php_libmemcached_compat.c Normal file
View File

@@ -0,0 +1,50 @@
/*
+----------------------------------------------------------------------+
| Copyright (c) 2009 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.0 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_0.txt. |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Andrei Zmievski <andrei@php.net> |
+----------------------------------------------------------------------+
*/
#include "php_libmemcached_compat.h"
memcached_st *php_memc_create_str (const char *str, size_t str_len)
{
#if HAVE_LIBMEMCACHED_MEMCACHED
return memcached (str, str_len);
#else
memcached_return rc;
memcached_st *memc;
memcached_server_st *servers;
memc = memcached_create(NULL);
if (!memc) {
return NULL;
}
servers = memcached_servers_parse (str);
if (!servers) {
memcached_free (memc);
return NULL;
}
rc = memcached_server_push (memc, servers);
memcached_server_free (servers);
if (rc != MEMCACHED_SUCCESS) {
memcached_free (memc);
return NULL;
}
return memc;
#endif
}

View File

@@ -1,7 +1,33 @@
/*
+----------------------------------------------------------------------+
| Copyright (c) 2009 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.0 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_0.txt. |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Andrei Zmievski <andrei@php.net> |
+----------------------------------------------------------------------+
*/
#ifndef PHP_LIBMEMCACHED_COMPAT
#define PHP_LIBMEMCACHED_COMPAT
/* this is the version(s) we support */
#include <libmemcached-1.0/memcached.h>
#include <libmemcached/memcached.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
memcached_st *php_memc_create_str (const char *str, size_t str_len);
#ifndef HAVE_LIBMEMCACHED_SERVER_TEMPORARILY_MARKER_DISABLED
# define MEMCACHED_SERVER_TEMPORARILY_DISABLED (1024 << 2)
#endif
#endif

View File

@@ -54,6 +54,13 @@
#include "fastlz/fastlz.h"
#include <zlib.h>
/* Compatibility with older versions */
#ifdef HAVE_MEMCACHED_INSTANCE_ST
typedef const memcached_instance_st * php_memcached_instance_st;
#else
typedef memcached_server_instance_st php_memcached_instance_st;
#endif
/* Used to store the size of the block */
#if defined(HAVE_INTTYPES_H)
#include <inttypes.h>
@@ -271,7 +278,7 @@ static PHP_INI_MH(OnUpdateSerializer)
MEMC_G(serializer) = SERIALIZER_DEFAULT;
} else if (!strcmp(new_value, "php")) {
MEMC_G(serializer) = SERIALIZER_PHP;
#ifdef HAVE_MEMCACHE_IGBINARY
#ifdef HAVE_MEMCACHED_IGBINARY
} else if (!strcmp(new_value, "igbinary")) {
MEMC_G(serializer) = SERIALIZER_IGBINARY;
#endif // IGBINARY
@@ -295,12 +302,17 @@ PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("memcached.sess_consistent_hash", "0", PHP_INI_ALL, OnUpdateBool, sess_consistent_hash_enabled, zend_php_memcached_globals, php_memcached_globals)
STD_PHP_INI_ENTRY("memcached.sess_binary", "0", PHP_INI_ALL, OnUpdateBool, sess_binary_enabled, zend_php_memcached_globals, php_memcached_globals)
STD_PHP_INI_ENTRY("memcached.sess_lock_wait", "150000", PHP_INI_ALL, OnUpdateLongGEZero,sess_lock_wait, zend_php_memcached_globals, php_memcached_globals)
STD_PHP_INI_ENTRY("memcached.sess_lock_max_wait", "0", PHP_INI_ALL, OnUpdateLongGEZero, sess_lock_max_wait, zend_php_memcached_globals, php_memcached_globals)
STD_PHP_INI_ENTRY("memcached.sess_lock_expire", "0", PHP_INI_ALL, OnUpdateLongGEZero, sess_lock_expire, zend_php_memcached_globals, php_memcached_globals)
STD_PHP_INI_ENTRY("memcached.sess_prefix", "memc.sess.key.", PHP_INI_ALL, OnUpdateString, sess_prefix, zend_php_memcached_globals, php_memcached_globals)
STD_PHP_INI_ENTRY("memcached.sess_number_of_replicas", "0", PHP_INI_ALL, OnUpdateLongGEZero, sess_number_of_replicas, zend_php_memcached_globals, php_memcached_globals)
STD_PHP_INI_ENTRY("memcached.sess_randomize_replica_read", "0", PHP_INI_ALL, OnUpdateBool, sess_randomize_replica_read, zend_php_memcached_globals, php_memcached_globals)
STD_PHP_INI_ENTRY("memcached.sess_consistent_hashing", "0", PHP_INI_ALL, OnUpdateBool, sess_consistent_hashing_enabled, zend_php_memcached_globals, php_memcached_globals)
STD_PHP_INI_ENTRY("memcached.sess_remove_failed", "0", PHP_INI_ALL, OnUpdateBool, sess_remove_failed_enabled, zend_php_memcached_globals, php_memcached_globals)
STD_PHP_INI_ENTRY("memcached.sess_connect_timeout", "1000", PHP_INI_ALL, OnUpdateLong, sess_connect_timeout, zend_php_memcached_globals, php_memcached_globals)
STD_PHP_INI_ENTRY("memcached.sess_sasl_username", "", PHP_INI_ALL, OnUpdateString, sess_sasl_username, zend_php_memcached_globals, php_memcached_globals)
STD_PHP_INI_ENTRY("memcached.sess_sasl_password", "", PHP_INI_ALL, OnUpdateString, sess_sasl_password, zend_php_memcached_globals, php_memcached_globals)
#endif
STD_PHP_INI_ENTRY("memcached.compression_type", "fastlz", PHP_INI_ALL, OnUpdateCompressionType, compression_type, zend_php_memcached_globals, php_memcached_globals)
STD_PHP_INI_ENTRY("memcached.compression_factor", "1.3", PHP_INI_ALL, OnUpdateReal, compression_factor, zend_php_memcached_globals, php_memcached_globals)
@@ -318,7 +330,7 @@ PHP_INI_END()
****************************************/
static int php_memc_handle_error(php_memc_t *i_obj, memcached_return status TSRMLS_DC);
static char *php_memc_zval_to_payload(zval *value, size_t *payload_len, uint32_t *flags, enum memcached_serializer serializer, enum memcached_compression_type compression_type TSRMLS_DC);
static int php_memc_zval_from_payload(zval *value, char *payload, size_t payload_len, uint32_t flags, enum memcached_serializer serializer TSRMLS_DC);
static int php_memc_zval_from_payload(zval *value, const char *payload, size_t payload_len, uint32_t flags, enum memcached_serializer serializer TSRMLS_DC);
static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key);
static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key);
static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool by_key);
@@ -328,9 +340,9 @@ static void php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by
static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key);
static memcached_return php_memc_do_cache_callback(zval *memc_obj, zend_fcall_info *fci, zend_fcall_info_cache *fcc, char *key, size_t key_len, zval *value TSRMLS_DC);
static int php_memc_do_result_callback(zval *memc_obj, zend_fcall_info *fci, zend_fcall_info_cache *fcc, memcached_result_st *result TSRMLS_DC);
static memcached_return php_memc_do_serverlist_callback(const memcached_st *ptr, memcached_server_instance_st instance, void *in_context);
static memcached_return php_memc_do_stats_callback(const memcached_st *ptr, memcached_server_instance_st instance, void *in_context);
static memcached_return php_memc_do_version_callback(const memcached_st *ptr, memcached_server_instance_st instance, void *in_context);
static memcached_return php_memc_do_serverlist_callback(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context);
static memcached_return php_memc_do_stats_callback(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context);
static memcached_return php_memc_do_version_callback(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context);
static void php_memc_destroy(struct memc_obj *m_obj, zend_bool persistent TSRMLS_DC);
/****************************************
@@ -429,17 +441,21 @@ static PHP_METHOD(Memcached, __construct)
}
if (conn_str) {
m_obj->memc = memcached(conn_str, conn_str_len);
m_obj->memc = php_memc_create_str(conn_str, conn_str_len);
if (!m_obj->memc) {
char error_buffer[1024];
if (plist_key) {
efree(plist_key);
}
#if HAVE_LIBMEMCACHED_CHECK_CONFIGURATION
if (libmemcached_check_configuration(conn_str, conn_str_len, error_buffer, sizeof(error_buffer)) != MEMCACHED_SUCCESS) {
php_error_docref(NULL TSRMLS_CC, E_ERROR, "configuration error %s", error_buffer);
} else {
php_error_docref(NULL TSRMLS_CC, E_ERROR, "could not allocate libmemcached structure");
}
#else
php_error_docref(NULL TSRMLS_CC, E_ERROR, "could not allocate libmemcached structure");
#endif
/* not reached */
}
} else {
@@ -521,7 +537,7 @@ static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key)
int key_len = 0;
char *server_key = NULL;
int server_key_len = 0;
char *payload = NULL;
const char *payload = NULL;
size_t payload_len = 0;
uint32_t flags = 0;
uint64_t cas = 0;
@@ -550,7 +566,7 @@ static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key)
MEMC_METHOD_FETCH_OBJECT;
i_obj->rescode = MEMCACHED_SUCCESS;
if (key_len == 0) {
if (key_len == 0 || strchr(key, ' ')) {
i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED;
RETURN_FROM_GET;
}
@@ -558,127 +574,88 @@ static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key)
keys[0] = key;
key_lens[0] = key_len;
if (cas_token && Z_TYPE_P(cas_token) != IS_NULL) {
uint64_t orig_cas_flag;
uint64_t orig_cas_flag;
orig_cas_flag = memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS);
/*
* Enable CAS support, but only if it is currently disabled.
*/
orig_cas_flag = memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS);
if (orig_cas_flag == 0) {
memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1);
}
/*
* Enable CAS support, but only if it is currently disabled.
*/
if (cas_token && Z_TYPE_P(cas_token) != IS_NULL && orig_cas_flag == 0) {
memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, 1);
}
status = memcached_mget_by_key(m_obj->memc, server_key, server_key_len, keys, key_lens, 1);
status = memcached_mget_by_key(m_obj->memc, server_key, server_key_len, keys, key_lens, 1);
if (orig_cas_flag == 0) {
memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, orig_cas_flag);
}
if (cas_token && Z_TYPE_P(cas_token) != IS_NULL && orig_cas_flag == 0) {
memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, orig_cas_flag);
}
if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
RETURN_FROM_GET;
}
if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
RETURN_FROM_GET;
}
status = MEMCACHED_SUCCESS;
memcached_result_create(m_obj->memc, &result);
if (memcached_fetch_result(m_obj->memc, &result, &status) == NULL) {
/* This is for historical reasons */
if (status == MEMCACHED_END)
status = MEMCACHED_NOTFOUND;
/*
* If the result wasn't found, and we have the read-through callback, invoke
* it to get the value. The CAS token will be 0, because we cannot generate it
* ourselves.
*/
if (status == MEMCACHED_NOTFOUND && fci.size != 0) {
status = php_memc_do_cache_callback(getThis(), &fci, &fcc, key, key_len,
return_value TSRMLS_CC);
ZVAL_DOUBLE(cas_token, 0);
}
if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
memcached_result_free(&result);
RETURN_FROM_GET;
}
/* if we have a callback, all processing is done */
if (fci.size != 0) {
memcached_result_free(&result);
return;
}
}
payload = memcached_result_value(&result);
payload_len = memcached_result_length(&result);
flags = memcached_result_flags(&result);
cas = memcached_result_cas(&result);
if (php_memc_zval_from_payload(return_value, payload, payload_len, flags, m_obj->serializer TSRMLS_CC) < 0) {
memcached_result_free(&result);
i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE;
RETURN_FROM_GET;
}
zval_dtor(cas_token);
ZVAL_DOUBLE(cas_token, (double)cas);
if (udf_flags) {
ZVAL_LONG(udf_flags, MEMC_UDF_GET(flags));
}
memcached_result_free(&result);
} else {
int rc;
zend_bool return_value_set = 0;
status = memcached_mget_by_key(m_obj->memc, server_key, server_key_len, keys, key_lens, 1);
payload = memcached_fetch(m_obj->memc, NULL, NULL, &payload_len, &flags, &status);
status = MEMCACHED_SUCCESS;
memcached_result_create(m_obj->memc, &result);
if (memcached_fetch_result(m_obj->memc, &result, &status) == NULL) {
/* This is for historical reasons */
if (status == MEMCACHED_END)
status = MEMCACHED_NOTFOUND;
/*
* If payload wasn't found and we have a read-through callback, invoke it to get
* the value. The callback will take care of storing the value back into memcache.
* The callback will set the return value.
*/
if (payload == NULL && status == MEMCACHED_NOTFOUND && fci.size != 0) {
size_t dummy_length;
uint32_t dummy_flags;
memcached_return dummy_status;
* If the result wasn't found, and we have the read-through callback, invoke
* it to get the value. The CAS token will be 0, because we cannot generate it
* ourselves.
*/
if (cas_token && status == MEMCACHED_NOTFOUND && fci.size != 0) {
status = php_memc_do_cache_callback(getThis(), &fci, &fcc, key, key_len,
return_value TSRMLS_CC);
return_value_set = 1;
(void)memcached_fetch(m_obj->memc, NULL, NULL, &dummy_length, &dummy_flags, &dummy_status);
ZVAL_DOUBLE(cas_token, 0);
}
if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
if (payload) {
free(payload);
}
memcached_result_free(&result);
RETURN_FROM_GET;
}
/* if memcached gave a value and there was no callback, payload may be NULL */
if (!return_value_set) {
rc = php_memc_zval_from_payload(return_value, payload, payload_len, flags, m_obj->serializer TSRMLS_CC);
free(payload);
if (rc < 0) {
i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE;
RETURN_FROM_GET;
}
}
if (udf_flags) {
ZVAL_LONG(udf_flags, MEMC_UDF_GET(flags));
/* if we have a callback, all processing is done */
if (fci.size != 0) {
memcached_result_free(&result);
return;
}
}
/* Fetch all remaining results */
memcached_result_st dummy_result;
memcached_return dummy_status = MEMCACHED_SUCCESS;
memcached_result_create(m_obj->memc, &dummy_result);
while (memcached_fetch_result(m_obj->memc, &dummy_result, &dummy_status) != NULL) {}
memcached_result_free(&dummy_result);
payload = memcached_result_value(&result);
payload_len = memcached_result_length(&result);
flags = memcached_result_flags(&result);
if (cas_token) {
cas = memcached_result_cas(&result);
}
if (php_memc_zval_from_payload(return_value, payload, payload_len, flags, m_obj->serializer TSRMLS_CC) < 0) {
memcached_result_free(&result);
i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE;
RETURN_FROM_GET;
}
if (cas_token) {
zval_dtor(cas_token);
ZVAL_DOUBLE(cas_token, (double)cas);
}
if (udf_flags) {
zval_dtor(udf_flags);
ZVAL_LONG(udf_flags, MEMC_UDF_GET(flags));
}
memcached_result_free(&result);
}
/* }}} */
@@ -706,11 +683,11 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke
int server_key_len = 0;
size_t num_keys = 0;
zval **entry = NULL;
char *payload = NULL;
const char *payload = NULL;
size_t payload_len = 0;
const char **mkeys = NULL;
size_t *mkeys_len = NULL;
char *res_key = NULL;
const char *tmp_key = NULL;
size_t res_key_len = 0;
uint32_t flags;
uint64_t cas = 0;
@@ -819,6 +796,8 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke
memcached_result_create(m_obj->memc, &result);
while ((memcached_fetch_result(m_obj->memc, &result, &status)) != NULL) {
char res_key [MEMCACHED_MAX_KEY];
if (status != MEMCACHED_SUCCESS) {
status = MEMCACHED_SOME_ERRORS;
php_memc_handle_error(i_obj, status TSRMLS_CC);
@@ -828,14 +807,15 @@ static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke
payload = memcached_result_value(&result);
payload_len = memcached_result_length(&result);
flags = memcached_result_flags(&result);
res_key = memcached_result_key_value(&result);
tmp_key = memcached_result_key_value(&result);
res_key_len = memcached_result_key_length(&result);
/*
* This may be a bug in libmemcached, the key is not null terminated
* whe using the binary protocol.
*/
res_key[res_key_len] = 0;
memcpy (res_key, tmp_key, res_key_len >= MEMCACHED_MAX_KEY ? MEMCACHED_MAX_KEY - 1 : res_key_len);
res_key [res_key_len] = '\0';
MAKE_STD_ZVAL(value);
@@ -1024,9 +1004,9 @@ static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_
Returns the next result from a previous delayed request */
PHP_METHOD(Memcached, fetch)
{
char *res_key = NULL;
const char *res_key = NULL;
size_t res_key_len = 0;
char *payload = NULL;
const char *payload = NULL;
size_t payload_len = 0;
zval *value;
uint32_t flags = 0;
@@ -1084,9 +1064,9 @@ PHP_METHOD(Memcached, fetch)
Returns all the results from a previous delayed request */
PHP_METHOD(Memcached, fetchAll)
{
char *res_key = NULL;
const char *res_key = NULL;
size_t res_key_len = 0;
char *payload = NULL;
const char *payload = NULL;
size_t payload_len = 0;
zval *value, *entry;
uint32_t flags;
@@ -1212,6 +1192,7 @@ PHP_METHOD(Memcached, setMultiByKey)
case MEMCACHED_TIMEOUT: \
case MEMCACHED_FAIL_UNIX_SOCKET: \
case MEMCACHED_SERVER_MARKED_DEAD: \
case MEMCACHED_SERVER_TEMPORARILY_DISABLED: \
if (memcached_server_count(m_obj->memc) > 0) { \
retry++; \
i_obj->rescode = 0; \
@@ -1392,7 +1373,7 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool
int s_value_len = 0;
zval s_zvalue;
zval *value;
time_t expiration = 0;
long expiration = 0;
uint32_t udf_flags = 0;
char *payload;
size_t payload_len;
@@ -1446,7 +1427,7 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool
MEMC_METHOD_FETCH_OBJECT;
i_obj->rescode = MEMCACHED_SUCCESS;
if (key_len == 0) {
if (key_len == 0 || strchr(key, ' ')) {
i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED;
RETURN_FALSE;
}
@@ -1477,10 +1458,11 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool
}
if (op == MEMC_OP_TOUCH) {
if (!memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "touch is only supported with binary protocol");
RETURN_FALSE;
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x01000016
if (memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "using touch command with binary protocol is not recommended with libmemcached versions below 1.0.16");
}
#endif
} else {
payload = php_memc_zval_to_payload(value, &payload_len, &flags, m_obj->serializer, m_obj->compression_type TSRMLS_CC);
if (payload == NULL) {
@@ -1498,7 +1480,7 @@ retry:
key_len, payload, payload_len, expiration, flags);
}
break;
#ifdef HAVE_LIBMEMCACHED_TOUCH
case MEMC_OP_TOUCH:
if (!server_key) {
status = memcached_touch(m_obj->memc, key, key_len, expiration);
@@ -1507,8 +1489,7 @@ retry:
key_len, expiration);
}
break;
#endif
case MEMC_OP_ADD:
if (!server_key) {
status = memcached_add(m_obj->memc, key, key_len, payload, payload_len, expiration, flags);
@@ -1597,7 +1578,7 @@ static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key)
MEMC_METHOD_FETCH_OBJECT;
i_obj->rescode = MEMCACHED_SUCCESS;
if (key_len == 0) {
if (key_len == 0 || strchr(key, ' ')) {
i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED;
RETURN_FALSE;
}
@@ -1716,7 +1697,7 @@ static void php_memc_delete_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key)
MEMC_METHOD_FETCH_OBJECT;
i_obj->rescode = MEMCACHED_SUCCESS;
if (key_len == 0) {
if (key_len == 0 || strchr(key, ' ')) {
i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED;
RETURN_FALSE;
}
@@ -1816,7 +1797,7 @@ static void php_memc_incdec_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key,
MEMC_METHOD_FETCH_OBJECT;
i_obj->rescode = MEMCACHED_SUCCESS;
if (key_len == 0) {
if (key_len == 0 || strchr(key, ' ')) {
i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED;
RETURN_FALSE;
}
@@ -1842,6 +1823,10 @@ retry:
}
}
} else {
if (!memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Initial value is only supported with binary protocol");
RETURN_FALSE;
}
if (by_key) {
if (incr) {
status = memcached_increment_with_initial_by_key(m_obj->memc, server_key, server_key_len, key, key_len, (unsigned int)offset, initial, expiry, &value);
@@ -1916,6 +1901,7 @@ PHP_METHOD(Memcached, addServer)
MEMC_METHOD_FETCH_OBJECT;
i_obj->rescode = MEMCACHED_SUCCESS;
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x01000002
if (host[0] == '/') { /* unix domain socket */
status = memcached_server_add_unix_socket_with_weight(m_obj->memc, host, weight);
} else if (memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_USE_UDP)) {
@@ -1923,6 +1909,9 @@ PHP_METHOD(Memcached, addServer)
} else {
status = memcached_server_add_with_weight(m_obj->memc, host, port, weight);
}
#else
status = memcached_server_add_with_weight(m_obj->memc, host, port, weight);
#endif
if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
RETURN_FALSE;
@@ -2044,7 +2033,7 @@ PHP_METHOD(Memcached, getServerByKey)
{
char *server_key;
int server_key_len;
memcached_server_instance_st *server_instance;
php_memcached_instance_st server_instance;
memcached_return error;
MEMC_METHOD_INIT_VARS;
@@ -2055,7 +2044,7 @@ PHP_METHOD(Memcached, getServerByKey)
MEMC_METHOD_FETCH_OBJECT;
i_obj->rescode = MEMCACHED_SUCCESS;
if (server_key_len == 0) {
if (server_key_len == 0 || strchr(server_key, ' ')) {
i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED;
RETURN_FALSE;
}
@@ -2107,6 +2096,22 @@ PHP_METHOD(Memcached, quit)
}
/* }}} */
/* {{{ Memcached::flushBuffers()
Flush and senf buffered commands */
PHP_METHOD(Memcached, flushBuffers)
{
memcached_return rc;
MEMC_METHOD_INIT_VARS;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
MEMC_METHOD_FETCH_OBJECT;
RETURN_BOOL(memcached_flush_buffers(m_obj->memc) == MEMCACHED_SUCCESS);
}
/* }}} */
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x00049000
/* {{{ Memcached::getLastErrorMessage()
Returns the last error message that occurred */
@@ -2162,7 +2167,7 @@ PHP_METHOD(Memcached, getLastErrorErrno)
Was added in 0.34 according to libmemcached's Changelog */
PHP_METHOD(Memcached, getLastDisconnectedServer)
{
memcached_server_instance_st *server_instance;
php_memcached_instance_st server_instance;
MEMC_METHOD_INIT_VARS;
if (zend_parse_parameters_none() == FAILURE) {
@@ -2370,6 +2375,7 @@ static PHP_METHOD(Memcached, getOption)
static int php_memc_set_option(php_memc_t *i_obj, long option, zval *value TSRMLS_DC)
{
memcached_return rc;
memcached_behavior flag;
struct memc_obj *m_obj = i_obj->obj;
@@ -2422,8 +2428,8 @@ static int php_memc_set_option(php_memc_t *i_obj, long option, zval *value TSRML
flag = (memcached_behavior) option;
convert_to_long(value);
if (memcached_behavior_set(m_obj->memc, flag, (uint64_t)Z_LVAL_P(value)) == MEMCACHED_FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "error setting memcached option");
if ((rc = memcached_behavior_set(m_obj->memc, flag, (uint64_t)Z_LVAL_P(value))) != MEMCACHED_SUCCESS) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "error setting memcached option: %s", memcached_strerror (m_obj->memc, rc));
return 0;
}
@@ -2477,18 +2483,12 @@ static int php_memc_set_option(php_memc_t *i_obj, long option, zval *value TSRML
*/
flag = (memcached_behavior) option;
convert_to_long(value);
if (flag < 0 ||
/* MEMCACHED_BEHAVIOR_MAX was added in somewhere around 0.36 or 0.37 */
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x00037000
flag >= MEMCACHED_BEHAVIOR_MAX ||
#endif
memcached_behavior_set(m_obj->memc, flag, (uint64_t)Z_LVAL_P(value)) != MEMCACHED_SUCCESS) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "error setting memcached option");
if (flag >= MEMCACHED_BEHAVIOR_MAX || (rc = memcached_behavior_set(m_obj->memc, flag, (uint64_t)Z_LVAL_P(value))) != MEMCACHED_SUCCESS) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "error setting memcached option: %s", memcached_strerror (m_obj->memc, rc));
return 0;
}
break;
}
return 1;
}
@@ -2567,12 +2567,18 @@ static PHP_METHOD(Memcached, setSaslAuthData)
return;
}
if (!MEMC_G(use_sasl)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "SASL support (memcached.use_sasl) isn't enabled in php.ini");
RETURN_FALSE;
}
MEMC_METHOD_FETCH_OBJECT;
if (!memcached_behavior_get(m_obj->memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "SASL is only supported with binary protocol");
RETURN_FALSE;
}
m_obj->has_sasl_data = 1;
RETURN_BOOL(memcached_set_sasl_auth_data(m_obj->memc, user, pass));
}
/* }}} */
@@ -2734,7 +2740,7 @@ ZEND_RSRC_DTOR_FUNC(php_memc_sess_dtor)
/* }}} */
/* {{{ internal API functions */
static memcached_return php_memc_do_serverlist_callback(const memcached_st *ptr, memcached_server_instance_st instance, void *in_context)
static memcached_return php_memc_do_serverlist_callback(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context)
{
struct callbackContext* context = (struct callbackContext*) in_context;
zval *array;
@@ -2752,7 +2758,7 @@ static memcached_return php_memc_do_serverlist_callback(const memcached_st *ptr,
return MEMCACHED_SUCCESS;
}
static memcached_return php_memc_do_stats_callback(const memcached_st *ptr, memcached_server_instance_st instance, void *in_context)
static memcached_return php_memc_do_stats_callback(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context)
{
char *hostport = NULL;
int hostport_len;
@@ -2796,7 +2802,7 @@ static memcached_return php_memc_do_stats_callback(const memcached_st *ptr, memc
return MEMCACHED_SUCCESS;
}
static memcached_return php_memc_do_version_callback(const memcached_st *ptr, memcached_server_instance_st instance, void *in_context)
static memcached_return php_memc_do_version_callback(const memcached_st *ptr, php_memcached_instance_st instance, void *in_context)
{
char *hostport = NULL;
char version[16];
@@ -2804,7 +2810,7 @@ static memcached_return php_memc_do_version_callback(const memcached_st *ptr, me
struct callbackContext* context = (struct callbackContext*) in_context;
hostport_len = spprintf(&hostport, 0, "%s:%d", memcached_server_name(instance), memcached_server_port(instance));
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x01000008
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x01000009
version_len = snprintf(version, sizeof(version), "%d.%d.%d",
memcached_server_major_version(instance),
memcached_server_minor_version(instance),
@@ -3026,20 +3032,72 @@ static char *php_memc_zval_to_payload(zval *value, size_t *payload_len, uint32_t
return payload;
}
static
char *s_handle_decompressed (const char *payload, size_t *payload_len, uint32_t flags TSRMLS_DC)
{
char *buffer;
uint32_t len;
unsigned long length;
zend_bool decompress_status = 0;
/* Stored with newer memcached extension? */
if (flags & MEMC_VAL_COMPRESSION_FASTLZ || flags & MEMC_VAL_COMPRESSION_ZLIB) {
/* This is copied from Ilia's patch */
memcpy(&len, payload, sizeof(uint32_t));
buffer = emalloc(len + 1);
*payload_len -= sizeof(uint32_t);
payload += sizeof(uint32_t);
length = len;
if (flags & MEMC_VAL_COMPRESSION_FASTLZ) {
decompress_status = ((length = fastlz_decompress(payload, *payload_len, buffer, len)) > 0);
} else if (flags & MEMC_VAL_COMPRESSION_ZLIB) {
decompress_status = (uncompress((Bytef *)buffer, &length, (Bytef *)payload, *payload_len) == Z_OK);
}
}
/* Fall back to 'old style decompression' */
if (!decompress_status) {
unsigned int factor = 1, maxfactor = 16;
int status;
do {
length = (unsigned long)*payload_len * (1 << factor++);
buffer = erealloc(buffer, length + 1);
memset(buffer, 0, length + 1);
status = uncompress((Bytef *)buffer, (uLongf *)&length, (const Bytef *)payload, *payload_len);
} while ((status==Z_BUF_ERROR) && (factor < maxfactor));
if (status == Z_OK) {
decompress_status = 1;
}
}
if (!decompress_status) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not decompress value");
efree(buffer);
return NULL;
}
buffer [length] = '\0';
*payload_len = length;
return buffer;
}
/* The caller MUST free the payload */
static int php_memc_zval_from_payload(zval *value, char *payload, size_t payload_len, uint32_t flags, enum memcached_serializer serializer TSRMLS_DC)
static int php_memc_zval_from_payload(zval *value, const char *payload_in, size_t payload_len, uint32_t flags, enum memcached_serializer serializer TSRMLS_DC)
{
/*
A NULL payload is completely valid if length is 0, it is simply empty.
*/
zend_bool payload_emalloc = 0;
char *buffer = NULL;
char *datas = NULL, *buffer = NULL, *pl = NULL;
if (payload == NULL && payload_len > 0) {
if (payload_in == NULL && payload_len > 0) {
ZVAL_FALSE(value);
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"Could not handle non-existing value of length %zu", payload_len);
return -1;
} else if (payload == NULL) {
} else if (payload_in == NULL) {
if (MEMC_VAL_GET_TYPE(flags) == MEMC_VAL_IS_BOOL) {
ZVAL_FALSE(value);
} else {
@@ -3049,91 +3107,63 @@ static int php_memc_zval_from_payload(zval *value, char *payload, size_t payload
}
if (flags & MEMC_VAL_COMPRESSED) {
uint32_t len;
unsigned long length;
zend_bool decompress_status = 0;
/* Stored with newer memcached extension? */
if (flags & MEMC_VAL_COMPRESSION_FASTLZ || flags & MEMC_VAL_COMPRESSION_ZLIB) {
/* This is copied from Ilia's patch */
memcpy(&len, payload, sizeof(uint32_t));
buffer = emalloc(len + 1);
payload_len -= sizeof(uint32_t);
payload += sizeof(uint32_t);
length = len;
if (flags & MEMC_VAL_COMPRESSION_FASTLZ) {
decompress_status = ((length = fastlz_decompress(payload, payload_len, buffer, len)) > 0);
} else if (flags & MEMC_VAL_COMPRESSION_ZLIB) {
decompress_status = (uncompress((Bytef *)buffer, &length, (Bytef *)payload, payload_len) == Z_OK);
}
}
/* Fall back to 'old style decompression' */
if (!decompress_status) {
unsigned int factor = 1, maxfactor = 16;
int status;
do {
length = (unsigned long)payload_len * (1 << factor++);
buffer = erealloc(buffer, length + 1);
memset(buffer, 0, length + 1);
status = uncompress((Bytef *)buffer, (uLongf *)&length, (const Bytef *)payload, payload_len);
} while ((status==Z_BUF_ERROR) && (factor < maxfactor));
if (status == Z_OK) {
decompress_status = 1;
}
}
if (!decompress_status) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not decompress value");
efree(buffer);
char *datas = s_handle_decompressed (payload_in, &payload_len, flags TSRMLS_CC);
if (!datas) {
ZVAL_FALSE(value);
return -1;
}
payload = buffer;
payload_len = length;
pl = datas;
payload_emalloc = 1;
} else {
pl = (char *) payload_in;
}
payload[payload_len] = 0;
switch (MEMC_VAL_GET_TYPE(flags)) {
case MEMC_VAL_IS_STRING:
if (payload_emalloc) {
ZVAL_STRINGL(value, payload, payload_len, 0);
ZVAL_STRINGL(value, pl, payload_len, 0);
payload_emalloc = 0;
} else {
ZVAL_STRINGL(value, payload, payload_len, 1);
ZVAL_STRINGL(value, pl, payload_len, 1);
}
break;
case MEMC_VAL_IS_LONG:
{
long lval = strtol(payload, NULL, 10);
char conv_buf [128];
memcpy (conv_buf, pl, payload_len);
conv_buf [payload_len] = '\0';
long lval = strtol(conv_buf, NULL, 10);
ZVAL_LONG(value, lval);
break;
}
case MEMC_VAL_IS_DOUBLE:
if (payload_len == 8 && memcmp(payload, "Infinity", 8) == 0) {
{
char conv_buf [128];
memcpy (conv_buf, pl, payload_len);
conv_buf [payload_len] = '\0';
if (payload_len == 8 && memcmp(conv_buf, "Infinity", 8) == 0) {
ZVAL_DOUBLE(value, php_get_inf());
} else if (payload_len == 9 && memcmp(payload, "-Infinity", 9) == 0) {
} else if (payload_len == 9 && memcmp(conv_buf, "-Infinity", 9) == 0) {
ZVAL_DOUBLE(value, -php_get_inf());
} else if (payload_len == 3 && memcmp(payload, "NaN", 3) == 0) {
} else if (payload_len == 3 && memcmp(conv_buf, "NaN", 3) == 0) {
ZVAL_DOUBLE(value, php_get_nan());
} else {
ZVAL_DOUBLE(value, zend_strtod(payload, NULL));
ZVAL_DOUBLE(value, zend_strtod(conv_buf, NULL));
}
}
break;
case MEMC_VAL_IS_BOOL:
ZVAL_BOOL(value, payload_len > 0 && payload[0] == '1');
ZVAL_BOOL(value, payload_len > 0 && pl[0] == '1');
break;
case MEMC_VAL_IS_SERIALIZED:
{
const char *payload_tmp = payload;
const char *payload_tmp = pl;
php_unserialize_data_t var_hash;
PHP_VAR_UNSERIALIZE_INIT(var_hash);
@@ -3149,12 +3179,13 @@ static int php_memc_zval_from_payload(zval *value, char *payload, size_t payload
case MEMC_VAL_IS_IGBINARY:
#ifdef HAVE_MEMCACHED_IGBINARY
if (igbinary_unserialize((uint8_t *)payload, payload_len, &value TSRMLS_CC)) {
if (igbinary_unserialize((uint8_t *)pl, payload_len, &value TSRMLS_CC)) {
ZVAL_FALSE(value);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not unserialize value with igbinary");
goto my_error;
}
#else
ZVAL_FALSE(value);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not unserialize value, no igbinary support");
goto my_error;
#endif
@@ -3163,30 +3194,32 @@ static int php_memc_zval_from_payload(zval *value, char *payload, size_t payload
case MEMC_VAL_IS_JSON:
#ifdef HAVE_JSON_API
# if HAVE_JSON_API_5_2
php_json_decode(value, payload, payload_len, (serializer == SERIALIZER_JSON_ARRAY) TSRMLS_CC);
php_json_decode(value, pl, payload_len, (serializer == SERIALIZER_JSON_ARRAY) TSRMLS_CC);
# elif HAVE_JSON_API_5_3
php_json_decode(value, payload, payload_len, (serializer == SERIALIZER_JSON_ARRAY), JSON_PARSER_DEFAULT_DEPTH TSRMLS_CC);
php_json_decode(value, pl, payload_len, (serializer == SERIALIZER_JSON_ARRAY), JSON_PARSER_DEFAULT_DEPTH TSRMLS_CC);
# endif
#else
ZVAL_FALSE(value);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not unserialize value, no json support");
goto my_error;
#endif
break;
default:
ZVAL_FALSE(value);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "unknown payload type");
goto my_error;
}
if (payload_emalloc) {
efree(payload);
efree(pl);
}
return 0;
my_error:
if (payload_emalloc) {
efree(payload);
efree(pl);
}
return -1;
}
@@ -3196,16 +3229,23 @@ static void php_memc_init_globals(zend_php_memcached_globals *php_memcached_glob
#ifdef HAVE_MEMCACHED_SESSION
MEMC_G(sess_locking_enabled) = 1;
MEMC_G(sess_binary_enabled) = 1;
MEMC_G(sess_consistent_hashing_enabled) = 0;
MEMC_G(sess_consistent_hash_enabled) = 0;
MEMC_G(sess_number_of_replicas) = 0;
MEMC_G(sess_remove_failed_enabled) = 0;
MEMC_G(sess_prefix) = NULL;
MEMC_G(sess_lock_wait) = 0;
MEMC_G(sess_lock_max_wait) = 0;
MEMC_G(sess_lock_expire) = 0;
MEMC_G(sess_locked) = 0;
MEMC_G(sess_lock_key) = NULL;
MEMC_G(sess_lock_key_len) = 0;
MEMC_G(sess_number_of_replicas) = 0;
MEMC_G(sess_randomize_replica_read) = 0;
MEMC_G(sess_connect_timeout) = 1000;
MEMC_G(sess_sasl_username) = NULL;
MEMC_G(sess_sasl_password) = NULL;
#if HAVE_MEMCACHED_SASL
MEMC_G(sess_sasl_data) = 0;
#endif
#endif
MEMC_G(serializer_name) = NULL;
MEMC_G(serializer) = SERIALIZER_DEFAULT;
@@ -3343,9 +3383,9 @@ static int php_memc_do_result_callback(zval *zmemc_obj, zend_fcall_info *fci,
zend_fcall_info_cache *fcc,
memcached_result_st *result TSRMLS_DC)
{
char *res_key = NULL;
const char *res_key = NULL;
size_t res_key_len = 0;
char *payload = NULL;
const char *payload = NULL;
size_t payload_len = 0;
zval *value, *retval = NULL;
uint64_t cas = 0;
@@ -3653,6 +3693,9 @@ 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()
@@ -3722,7 +3765,7 @@ static zend_function_entry memcached_class_methods[] = {
MEMC_ME(set, arginfo_set)
MEMC_ME(setByKey, arginfo_setByKey)
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x01000002
#if HAVE_LIBMEMCACHED_TOUCH
MEMC_ME(touch, arginfo_touch)
MEMC_ME(touchByKey, arginfo_touchByKey)
#endif
@@ -3755,6 +3798,8 @@ static zend_function_entry memcached_class_methods[] = {
MEMC_ME(getServerByKey, arginfo_getServerByKey)
MEMC_ME(resetServerList, arginfo_resetServerList)
MEMC_ME(quit, arginfo_quit)
MEMC_ME(flushBuffers, arginfo_flushBuffers)
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x00049000
MEMC_ME(getLastErrorMessage, arginfo_getLastErrorMessage)
@@ -3811,13 +3856,8 @@ zend_module_entry memcached_module_entry = {
NULL,
PHP_MINIT(memcached),
PHP_MSHUTDOWN(memcached),
#if HAVE_MEMCACHED_SASL
PHP_RINIT(memcached),
PHP_RSHUTDOWN(memcached),
#else
NULL,
NULL,
#endif
PHP_MINFO(memcached),
PHP_MEMCACHED_VERSION,
STANDARD_MODULE_PROPERTIES
@@ -3834,6 +3874,7 @@ static void php_memc_register_constants(INIT_FUNC_ARGS)
/*
* Class options
*/
REGISTER_MEMC_CLASS_CONST_LONG(LIBMEMCACHED_VERSION_HEX, LIBMEMCACHED_VERSION_HEX);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_COMPRESSION, MEMC_OPT_COMPRESSION);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_COMPRESSION_TYPE, MEMC_OPT_COMPRESSION_TYPE);
@@ -3919,7 +3960,7 @@ static void php_memc_register_constants(INIT_FUNC_ARGS)
REGISTER_MEMC_CLASS_CONST_LONG(OPT_NUMBER_OF_REPLICAS, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_RANDOMIZE_REPLICA_READ, MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ);
#endif
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x00049000
#if defined(HAVE_LIBMEMCACHED_REMOVE_FAILED_SERVERS) && HAVE_LIBMEMCACHED_REMOVE_FAILED_SERVERS
REGISTER_MEMC_CLASS_CONST_LONG(OPT_REMOVE_FAILED_SERVERS, MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS);
#endif
@@ -3996,27 +4037,6 @@ static void php_memc_register_constants(INIT_FUNC_ARGS)
}
/* }}} */
#if HAVE_MEMCACHED_SASL
PHP_RINIT_FUNCTION(memcached)
{
if (MEMC_G(use_sasl)) {
if (sasl_client_init(NULL) != SASL_OK) {
php_error_docref(NULL TSRMLS_CC, E_ERROR, "Failed to initialize SASL library");
}
}
return SUCCESS;
}
PHP_RSHUTDOWN_FUNCTION(memcached)
{
if (MEMC_G(use_sasl)) {
sasl_done();
}
return SUCCESS;
}
#endif
int php_memc_sess_list_entry(void)
{
return le_memc_sess;
@@ -4057,6 +4077,14 @@ PHP_MINIT_FUNCTION(memcached)
#endif
REGISTER_INI_ENTRIES();
#if HAVE_MEMCACHED_SASL
if (MEMC_G(use_sasl)) {
if (sasl_client_init(NULL) != SASL_OK) {
php_error_docref(NULL TSRMLS_CC, E_ERROR, "Failed to initialize SASL library");
return FAILURE;
}
}
#endif
return SUCCESS;
}
/* }}} */
@@ -4064,6 +4092,12 @@ PHP_MINIT_FUNCTION(memcached)
/* {{{ PHP_MSHUTDOWN_FUNCTION */
PHP_MSHUTDOWN_FUNCTION(memcached)
{
#if HAVE_MEMCACHED_SASL
if (MEMC_G(use_sasl)) {
sasl_done();
}
#endif
#ifdef ZTS
ts_free_id(php_memcached_globals_id);
#else
@@ -4083,6 +4117,12 @@ PHP_MINFO_FUNCTION(memcached)
php_info_print_table_row(2, "Version", PHP_MEMCACHED_VERSION);
php_info_print_table_row(2, "libmemcached version", memcached_lib_version());
#if HAVE_MEMCACHED_SASL
php_info_print_table_row(2, "SASL support", "yes");
#else
php_info_print_table_row(2, "SASL support", "no");
#endif
#ifdef HAVE_MEMCACHED_SESSION
php_info_print_table_row(2, "Session support", "yes");
#else

View File

@@ -62,6 +62,8 @@ ZEND_BEGIN_MODULE_GLOBALS(php_memcached)
#ifdef HAVE_MEMCACHED_SESSION
zend_bool sess_locking_enabled;
long sess_lock_wait;
long sess_lock_max_wait;
long sess_lock_expire;
char* sess_prefix;
zend_bool sess_locked;
char* sess_lock_key;
@@ -70,7 +72,15 @@ ZEND_BEGIN_MODULE_GLOBALS(php_memcached)
int sess_number_of_replicas;
zend_bool sess_randomize_replica_read;
zend_bool sess_remove_failed_enabled;
zend_bool sess_consistent_hashing_enabled;
long sess_connect_timeout;
zend_bool sess_consistent_hash_enabled;
zend_bool sess_binary_enabled;
char *sess_sasl_username;
char *sess_sasl_password;
#if HAVE_MEMCACHED_SASL
zend_bool sess_sasl_data;
#endif
#endif
char *serializer_name;
enum memcached_serializer serializer;
@@ -83,8 +93,6 @@ ZEND_BEGIN_MODULE_GLOBALS(php_memcached)
#if HAVE_MEMCACHED_SASL
bool use_sasl;
#endif
zend_bool sess_consistent_hash_enabled;
zend_bool sess_binary_enabled;
ZEND_END_MODULE_GLOBALS(php_memcached)
PHP_MEMCACHED_API zend_class_entry *php_memc_get_ce(void);
@@ -107,7 +115,7 @@ PHP_MINFO_FUNCTION(memcached);
typedef struct {
memcached_st *memc_sess;
zend_bool is_persisent;
zend_bool is_persistent;
} memcached_sess;
int php_memc_sess_list_entry(void);

View File

@@ -49,20 +49,25 @@ static int php_memc_sess_lock(memcached_st *memc, const char *key TSRMLS_DC)
int lock_key_len = 0;
unsigned long attempts;
long write_retry_attempts = 0;
long lock_maxwait;
long lock_maxwait = MEMC_G(sess_lock_max_wait);
long lock_wait = MEMC_G(sess_lock_wait);
long lock_expire = MEMC_G(sess_lock_expire);
time_t expiration;
memcached_return status;
/* set max timeout for session_start = max_execution_time. (c) Andrei Darashenka, Richter & Poweleit GmbH */
lock_maxwait = zend_ini_long(ZEND_STRS("max_execution_time"), 0);
if (lock_maxwait <= 0) {
lock_maxwait = MEMC_SESS_LOCK_EXPIRATION;
lock_maxwait = zend_ini_long(ZEND_STRS("max_execution_time"), 0);
if (lock_maxwait <= 0) {
lock_maxwait = MEMC_SESS_LOCK_EXPIRATION;
}
}
if (lock_wait == 0) {
lock_wait = MEMC_SESS_DEFAULT_LOCK_WAIT;
}
expiration = time(NULL) + lock_maxwait + 1;
if (lock_expire <= 0) {
lock_expire = lock_maxwait;
}
expiration = time(NULL) + lock_expire + 1;
attempts = (unsigned long)((1000000.0 / lock_wait) * lock_maxwait);
/* Set the number of write retry attempts to the number of replicas times the number of attempts to remove a server */
@@ -138,11 +143,11 @@ error:
}
p = e + 1;
memc_sess = pecalloc(sizeof(*memc_sess), 1, 1);
memc_sess->is_persisent = 1;
memc_sess->is_persistent = 1;
} else {
p = (char *)save_path;
memc_sess = ecalloc(sizeof(*memc_sess), 1);
memc_sess->is_persisent = 0;
memc_sess->is_persistent = 0;
}
if (!strstr(p, "--SERVER")) {
@@ -186,14 +191,19 @@ error:
php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to parse session.save_path");
}
} else {
memc_sess->memc_sess = memcached(p, strlen(p));
memc_sess->memc_sess = php_memc_create_str(p, strlen(p));
if (!memc_sess->memc_sess) {
#if HAVE_LIBMEMCACHED_CHECK_CONFIGURATION
char error_buffer[1024];
if (libmemcached_check_configuration(p, strlen(p), error_buffer, sizeof(error_buffer)) != MEMCACHED_SUCCESS) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "session.save_path configuration error %s", error_buffer);
} else {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to initialize memcached session storage");
}
#else
php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to initialize memcached session storage");
#endif
} else {
success:
PS_SET_MOD_DATA(memc_sess);
@@ -217,7 +227,28 @@ success:
return FAILURE;
}
}
#ifdef HAVE_MEMCACHED_SASL
if (MEMC_G(use_sasl)) {
/*
* Enable SASL support if username and password are set
*
*/
if (MEMC_G(sess_sasl_username) && MEMC_G(sess_sasl_password)) {
/* Force binary protocol */
if (memcached_behavior_set(memc_sess->memc_sess, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, (uint64_t) 1) == MEMCACHED_FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to set memcached session binary protocol");
return FAILURE;
}
if (memcached_set_sasl_auth_data(memc_sess->memc_sess, MEMC_G(sess_sasl_username), MEMC_G(sess_sasl_password)) == MEMCACHED_FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to set memcached session sasl credentials");
return FAILURE;
}
MEMC_G(sess_sasl_data) = 1;
}
}
#endif
if (MEMC_G(sess_number_of_replicas) > 0) {
if (memcached_behavior_set(memc_sess->memc_sess, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS, (uint64_t) MEMC_G(sess_number_of_replicas)) == MEMCACHED_FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to set memcached session number of replicas");
@@ -228,13 +259,11 @@ success:
}
}
if (MEMC_G(sess_consistent_hashing_enabled)) {
if (memcached_behavior_set(memc_sess->memc_sess, MEMCACHED_BEHAVIOR_KETAMA, (uint64_t) 1) == MEMCACHED_FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to set memcached consistent hashing");
return FAILURE;
}
if (memcached_behavior_set(memc_sess->memc_sess, MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT, (uint64_t) MEMC_G(sess_connect_timeout)) == MEMCACHED_FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to set memcached connection timeout");
return FAILURE;
}
#if HAVE_LIBMEMCACHED_REMOVE_FAILED_SERVERS
/* Allow libmemcached remove failed servers */
if (MEMC_G(sess_remove_failed_enabled)) {
if (memcached_behavior_set(memc_sess->memc_sess, MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS, (uint64_t) 1) == MEMCACHED_FAILURE) {
@@ -242,7 +271,7 @@ success:
return FAILURE;
}
}
#endif
return SUCCESS;
}
}
@@ -262,7 +291,12 @@ PS_CLOSE_FUNC(memcached)
php_memc_sess_unlock(memc_sess->memc_sess TSRMLS_CC);
}
if (memc_sess->memc_sess) {
if (!memc_sess->is_persisent) {
if (!memc_sess->is_persistent) {
#ifdef HAVE_MEMCACHED_SASL
if (MEMC_G(sess_sasl_data)) {
memcached_destroy_sasl_auth_data(memc_sess->memc_sess);
}
#endif
memcached_free(memc_sess->memc_sess);
efree(memc_sess);
}

View File

@@ -13,12 +13,10 @@ var_dump($m->getServerList());
bool(true)
array(1) {
[0]=>
array(3) {
array(2) {
["host"]=>
string(9) "localhost"
["port"]=>
int(11211)
["weight"]=>
int(3)
}
}

View File

@@ -8,8 +8,9 @@ $m = new Memcached();
$m->addServer('127.0.0.1', 11211, 1);
$m_udp = new Memcached();
$m_udp->addServer('127.0.0.1', 11211, 1);
$m_udp->setOption(Memcached::OPT_USE_UDP, true);
$m_udp->addServer('127.0.0.1', 11211, 1);
error_reporting(0);
@@ -23,18 +24,22 @@ echo $m_udp->getResultMessage(), "\n";
echo "\n";
echo "Set\n";
var_dump($m_udp->set('foo', "asdf", 10));
sleep (1);
echo $m_udp->getResultMessage(), "\n";
var_dump($m->get('foo'));
echo "\n";
echo "Delete found\n";
var_dump($m_udp->delete('foo'));
sleep (1);
echo $m_udp->getResultMessage(), "\n";
$m->get('foo');
echo $m->getResultMessage(), "\n";
--EXPECTF--
--EXPECT--
Delete not found
bool(true)
SUCCESS

View File

@@ -24,11 +24,12 @@ memcached.compression_threshold => %d => %d
memcached.compression_type => %s => %s
memcached.serializer => %s => %s
memcached.sess_binary => %d => %d
memcached.sess_connect_timeout => %d => %d
memcached.sess_consistent_hash => %d => %d
memcached.sess_consistent_hashing => %d => %d
memcached.sess_lock_wait => %d => %d
memcached.sess_locking => %d => %d
memcached.sess_number_of_replicas => %d => %d
memcached.sess_prefix => %s => %s
memcached.sess_randomize_replica_read => %d => %d
memcached.sess_remove_failed => %d => %d
memcached.sess_remove_failed => %d => %d
memcached.use_sasl => %d => %d

View File

@@ -1,50 +1,67 @@
--TEST--
Memcached store, fetch & touch expired key
--XFAIL--
https://code.google.com/p/memcached/issues/detail?id=275
--SKIPIF--
<?php if (!extension_loaded("memcached")) print "skip"; ?>
--FILE--
<?php
function run_expiry_test ($m) {
$key = uniqid ('will_expire_');
$set = $m->set($key, "foo", 2);
$v = $m->get($key);
if (!$set || $v != 'foo') {
echo "Error setting key to \"foo\" with 2s expiry.\n";
return;
}
sleep(1);
$res = $m->touch($key, 2);
$v = $m->get($key);
if(!$res || $v != 'foo') {
echo "Error touching key for another 2s expiry.\n";
var_dump($res);
var_dump($m->getResultMessage());
var_dump($v);
return;
}
sleep(3);
$v = $m->get($key);
if ($v !== Memcached::GET_ERROR_RETURN_VALUE) {
echo "Wanted:\n";
var_dump(Memcached::GET_ERROR_RETURN_VALUE);
echo "from get of expired value. Got:\n";
var_dump($v);
return;
}
echo "All OK" . PHP_EOL;
}
$m = new Memcached();
$m->setOption(Memcached::OPT_BINARY_PROTOCOL, true);
$m->addServer('127.0.0.1', 11211, 1);
$set = $m->set('will_expire', "foo", 2);
$v = $m->get('will_expire');
if (!$set || $v != 'foo') {
echo "Error setting will_expire to \"foo\" with 2s expiry.\n";
}
sleep(1);
$res = $m->touch('will_expire', 2);
$v = $m->get('will_expire');
if(!$res || $v != 'foo') {
echo "Error touching will_expire for another 2s expiry.\n";
var_dump($res);
var_dump($m->getResultMessage());
var_dump($v);
}
echo '-- binary protocol' . PHP_EOL;
run_expiry_test ($m);
sleep(3);
$v = $m->get('will_expire');
if ($v !== Memcached::GET_ERROR_RETURN_VALUE) {
echo "Wanted:\n";
var_dump(Memcached::GET_ERROR_RETURN_VALUE);
echo "from get of expired value. Got:\n";
var_dump($v);
}
// test with plaintext proto should throw error
$m = new Memcached();
$m->addServer('127.0.0.1', 11211, 1);
$set = $m->set('will_expire', "foo", 2);
$v = $m->touch('will_expire');
if($v !== false) {
echo "Touch with text protocol should return false.\n";
}
echo '-- text protocol' . PHP_EOL;
run_expiry_test ($m);
echo "OK\n";
echo "DONE TEST\n";
?>
--EXPECTF--
Warning: Memcached::touch(): touch is only supported with binary protocol in %s on line %d
OK
--EXPECT--
-- binary protocol
All OK
-- text protocol
All OK
DONE TEST

31
tests/flush_buffers.phpt Normal file
View File

@@ -0,0 +1,31 @@
--TEST--
Test flushing buffers
--SKIPIF--
<?php if (!extension_loaded("memcached")) print "skip"; ?>
--FILE--
<?php
$m = new Memcached();
$m->addServer('127.0.0.1', 11211);
$m->setOption(Memcached::OPT_NO_BLOCK, 1);
$m->setOption(Memcached::OPT_BUFFER_WRITES, 1);
$key = uniqid ('flush_key_');
var_dump ($m->set($key, 'test_val'));
$m2 = new Memcached();
$m2->addServer('127.0.0.1', 11211);
var_dump ($m2->get ($key));
var_dump ($m->flushBuffers ());
sleep (1);
var_dump ($m2->get ($key));
echo "OK" . PHP_EOL;
?>
--EXPECT--
bool(true)
bool(false)
bool(true)
string(8) "test_val"
OK

View File

@@ -20,43 +20,35 @@ array(0) {
}
array(1) {
[0]=>
array(3) {
array(2) {
["host"]=>
string(9) "localhost"
["port"]=>
int(11211)
["weight"]=>
int(3)
}
}
array(2) {
[0]=>
array(3) {
array(2) {
["host"]=>
string(9) "localhost"
["port"]=>
int(11211)
["weight"]=>
int(3)
}
[1]=>
array(3) {
array(2) {
["host"]=>
string(9) "localhost"
["port"]=>
int(11211)
["weight"]=>
int(3)
}
}
array(1) {
[0]=>
array(3) {
array(2) {
["host"]=>
string(9) "127.0.0.1"
["port"]=>
int(11211)
["weight"]=>
int(%r[01]%r)
}
}

34
tests/gh_21.phpt Normal file
View File

@@ -0,0 +1,34 @@
--TEST--
Test for Github issue 21
--SKIPIF--
<?php if (!extension_loaded("memcached")) print "skip"; ?>
--FILE--
<?php
$m = new Memcached();
$newServers = array(
array('127.0.0.1', 11211),
);
$m->setOption(Memcached::OPT_BINARY_PROTOCOL, true);
$m->addServers($newServers);
$d = $m->get('foo');
$m->set('counter', 5);
$n = $m->decrement('counter');
var_dump($n);
$n = $m->decrement('counter', 10);
var_dump($n);
var_dump($m->get('counter'));
$m->set('counter', 'abc');
$n = $m->increment('counter');
var_dump($n);
?>
--EXPECT--
int(4)
int(0)
int(0)
bool(false)

32
tests/gh_77.phpt Normal file
View File

@@ -0,0 +1,32 @@
--TEST--
Test for Github issue #77
--SKIPIF--
<?php if (!extension_loaded("memcached")) print "skip";
if (Memcached::LIBMEMCACHED_VERSION_HEX < 0x01000016) die ('skip too old libmemcached');
?>
--FILE--
<?php
$mc = new Memcached();
$mc->addServer('127.0.0.1', 11211, 1);
$key = uniqid ("this_does_not_exist_");
$mc = new \Memcached();
$mc->setOption(\Memcached::OPT_BINARY_PROTOCOL, true);
$mc->addServer("127.0.0.1", 11211);
$mc->touch($key, 5);
var_dump ($mc->getResultCode() == Memcached::RES_NOTFOUND);
$mc->set($key, 1, 5);
$mc->set($key, 1, 5);
var_dump ($mc->getResultCode() == Memcached::RES_SUCCESS);
echo "OK\n";
?>
--EXPECT--
bool(true)
bool(true)
OK

93
tests/gh_90.phpt Normal file
View File

@@ -0,0 +1,93 @@
--TEST--
Test for GH #90
--SKIPIF--
<?php if (!extension_loaded("memcached")) print "skip"; ?>
--FILE--
<?php
//Setup MemcacheD
{
$memcached = new Memcached();
$memcached->setOptions(array(memcached::OPT_BINARY_PROTOCOL => true));
$memcached->addServers(array(array('127.0.0.1', 11211, 100)));
}
// Create a key for use as a lock. If this key already exists, wait till it doesn't exist.
{
$key = 'LockKey';
$lockToken = mt_rand(0, pow(2, 32)); //Random value betwen 0 and 2^32 for ownership verification
while (true)
{
$casToken = null;
$data = $memcached->get($key, $casToken);
if ($memcached->getResultCode() == Memcached::RES_NOTFOUND)
{
if ($memcached->add($key, $lockToken, 5))
{
break;
}
}
elseif ($data === false)
{
if ($memcached->cas($casToken, $key, $lockToken, 5))
{
break;
}
}
//Sleep 10 milliseconds
usleep(10 * 1000);
}
}
//Do something here that requires exclusive access to this key
//Effectively delete our key lock.
{
$casToken = null;
if ($lockToken == $memcached->get($key, $casToken))
{
$memcached->cas($casToken, $key, false, 1);
}
}
//Create 10 keys and then increment them. The first value returned will be wrong.
{
$keyList = array();
for ($i = 0; $i < 10; $i++)
{
$keyList[] = $i . '_' . uniqid ('count_value_');
}
$valueList = array();
foreach ($keyList as $key)
{
$valueList[$key] = $memcached->increment($key, 1, 1);
}
var_dump ($valueList);
}
--EXPECTF--
array(10) {
["0_%s"]=>
int(1)
["1_%s"]=>
int(1)
["2_%s"]=>
int(1)
["3_%s"]=>
int(1)
["4_%s"]=>
int(1)
["5_%s"]=>
int(1)
["6_%s"]=>
int(1)
["7_%s"]=>
int(1)
["8_%s"]=>
int(1)
["9_%s"]=>
int(1)
}

View File

@@ -19,13 +19,11 @@ echo "OK\n";
--EXPECTF--
array(1) {
[0]=>
array(3) {
array(2) {
["host"]=>
string(9) "127.0.0.1"
["port"]=>
int(11211)
["weight"]=>
int(%r[01]%r)
}
}
OK

24
tests/no-not-found.phpt Normal file
View File

@@ -0,0 +1,24 @@
--TEST--
Test that correct return value is returned
--SKIPIF--
<?php if (!extension_loaded("memcached")) print "skip"; ?>
--FILE--
<?php
$memcached = new Memcached();
$memcached->addServer('localhost', 5555); // Server should not exist
$result = $memcached->get('foo_not_exists');
var_dump ($result === Memcached::GET_ERROR_RETURN_VALUE);
$cas = 7;
$result = $memcached->get('foo_not_exists', null, $cas);
var_dump ($result === Memcached::GET_ERROR_RETURN_VALUE);
echo "OK\n";
?>
--EXPECT--
bool(true)
bool(true)
OK

27
tests/pr_75.phpt Normal file
View File

@@ -0,0 +1,27 @@
--TEST--
Wrong return values for binary protocol
--SKIPIF--
<?php if (!extension_loaded("memcached")) print "skip"; ?>
--FILE--
<?php
$client = new Memcached();
$client->addServer ('127.0.0.1', 11211);
$client->setOption(Memcached::OPT_BINARY_PROTOCOL, true);
$client->set('key1', 'value1');
echo "set result code: ".$client->getResultCode()."\n";
$value = $client->get('key1');
echo "got $value with result code: ".$client->getResultCode()."\n";
$client->add('key2', 'value2');
echo "add result code: ".$client->getResultCode()."\n";
echo "OK\n";
?>
--EXPECT--
set result code: 0
got value1 with result code: 0
add result code: 0
OK

View File

@@ -43,4 +43,4 @@ test invalid options
bool(false)
%s::setOptions(): invalid configuration option
bool(false)
%s::setOptions(): error setting memcached option
%s::setOptions(): error setting memcached option: %s

69
tests/touch_binary.phpt Normal file
View File

@@ -0,0 +1,69 @@
--TEST--
Touch in binary mode
--SKIPIF--
<?php if (!extension_loaded("memcached")) print "skip";
if (Memcached::LIBMEMCACHED_VERSION_HEX < 0x01000016) die ('skip too old libmemcached');
?>
--FILE--
<?php
function resolve_to_constant ($code)
{
$refl = new ReflectionClass ('memcached');
$c = $refl->getConstants ();
foreach ($c as $name => $value) {
if (strpos ($name, 'RES_') === 0 && $value == $code)
return $name;
}
}
function status_print ($op, $mem, $expected)
{
$code = $mem->getResultcode();
if ($code == $expected)
echo "${op} status code as expected" . PHP_EOL;
else {
$expected = resolve_to_constant ($expected);
$code = resolve_to_constant ($code);
echo "${op} status code mismatch, expected ${expected} but got ${code}" . PHP_EOL;
}
}
$mem = new Memcached();
$mem->setOption(Memcached::OPT_BINARY_PROTOCOL,true);
$mem->addServer('127.0.0.1', 11211) or die ("Could not connect");
$key = uniqid ('touch_t_');
$mem->get($key);
status_print ('get', $mem, Memcached::RES_NOTFOUND);
$mem->set ($key, 1);
status_print ('set', $mem, Memcached::RES_SUCCESS);
$mem->get($key);
status_print ('get', $mem, Memcached::RES_SUCCESS);
$mem->touch ($key, 10);
status_print ('touch', $mem, Memcached::RES_SUCCESS);
$mem->get($key);
status_print ('get', $mem, Memcached::RES_SUCCESS);
$mem->get($key);
status_print ('get', $mem, Memcached::RES_SUCCESS);
echo "OK\n";
?>
--EXPECT--
get status code as expected
set status code as expected
get status code as expected
touch status code as expected
get status code as expected
get status code as expected
OK

View File

@@ -32,7 +32,7 @@ $data = array(
'array' => array(1,2,3,"foo"),
'object_array_empty' => (object)array(),
'object_array' => (object)array(1,2,3),
'object_array' => (object)array('a' => 1, 'b' => 2, 'c' => 3),
'object_dummy' => new testclass(),
);

18
tests/version.phpt Normal file
View File

@@ -0,0 +1,18 @@
--TEST--
Get version
--SKIPIF--
<?php if (!extension_loaded("memcached")) print "skip"; ?>
--FILE--
<?php
$m = new Memcached();
$m->addServer('127.0.0.1', 11211);
var_dump ($m->getVersion ());
echo "OK" . PHP_EOL;
?>
--EXPECTF--
array(1) {
["127.0.0.1:11211"]=>
string(6) "%d.%d.%d"
}
OK