package.xml 0000644 0000767 0000024 00000025176 12010120566 012326 0 ustar andrei staff
memcached
pecl.php.net
PHP extension for interfacing with memcached via libmemcached library
This extension uses libmemcached library to provide API for communicating with memcached servers.
Andrei Zmievski
andrei
andrei@php.net
yes
2012-08-07
2.1.0
2.1.0
stable
stable
PHP
- 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
5.2.0
6.0.0
6.0.0
1.4.0b1
memcached
stable
stable
2.1.0
2.1.0
2012-08-06
- Drop support for libmemcached 0.x series, now 1.0.x is required
- Add support for virtual bucket distribution
- Fix compilation against PHP 5.2
stable
stable
2.0.1
2.0.1
2012-03-03
- Fix embedded version number to be not -dev
stable
stable
2.0.0
2.0.0
2012-03-02
- Add touch() and touchByKey() methods
- Add resetServerList() and quit() methods
- Support binary protocol in sessions
- Make it work with libmemcached up to 1.0.4
- Test against PHP 5.4.0
beta
beta
2.0.0b2
2.0.0b2
2011-06-24
- Add OPT_REMOVE_FAILED_SERVERS option.
- Make it work with libmemcached up to 0.49.
- Fix a case where invalid session ID could lock the script.
- Improve session support:
* Add support for libmemcached config string
* Add persistence support via PERSISTENT=persistent_id prefix
of the save_path
- Add 3rd parameter to the __construct() that allows specification
of libmemcached configuration string
- Fix a possible crash in __construct() when using persistent
connections
- Add work-around a bug in libmemcached < 0.50 that causes truncation
of last character of server key prefix
- When using multiple servers implement transparent fail-over
- Fix php_memc_cas_impl() implementation when server_key is not being used
- Add support for incrementByKey() and decrementByKey()
- Make increment/decrement initialize value when it is not available (when
using binary protocol)
beta
beta
2.0.0b1
2.0.0b1
2011-03-12
- Change the return value for non-existing keys to be NULL rather than
'false', affects simple get only
- Add fastlz library that provides better/faster payload compression
- Add configure switch to enable/disable JSON serialization support
- Add getAllKeys() method
- Add deleteMulti() and deleteMultiByKey() methods
- Add isPristine() and isPersistent() methods
- Add setOptions() method to set multiple options at once
- Add SERIALIZER_JSON_ARRAY type that decodes JSON payloads as arrays
instead of objects
- Add support for Unix domain socket connections
- Add memcached.compression_threshold INI setting
- Add memcached.compression_factor INI setting
- Add memcached.compression_type INI setting
- Implement a few speed optimizations
- Many bug fixes and memory leaks plugged
- Add several more tests
- Add constants for libmemcached 0.37+:
* Memcached::OPT_NUMBER_OF_REPLICAS
* Memcached::OPT_RANDOMIZE_REPLICA_READ
- Add 'on_new' callback to constructor
- Add SASL support
stable
stable
1.0.2
1.0.2
2010-05-03
- Fix build for libmemcached-0.39 (memcached_server_list() issue)
stable
stable
1.0.1
1.0.1
2010-03-11
- Fix build for libmemcached-0.38.
stable
stable
1.0.0
1.0.0
2009-07-04
- First stable release.
- Add getResultMessage() method.
- Fix OPT_RECV_TIMEOUT definition.
- Initialize Session lock wait to max execution time (if max execution
time is unlimited, default to 30 seconds).
beta
beta
0.2.0
0.2.0
2009-06-04
- Refactor the way payload types are stored in memcached flags to optimize the structure
and allow for future expansion. WARNING! You have to flush the cache when upgrading from
an older version.
- Add JSON serializer support, requires PHP 5.2.10+.
- Add HAVE_JSON and HAVE_IGBINARY class constants that indicate whether the respective
serializers are available.
- Add 'flags' parameter to getMulti() and getMultiByKey().
- Add GET_PRESERVE_ORDER class constant that can be used with abovementioned flags
parameter to make the order of the keys in the response match the request.
- Fix an issue with retrieving 0-length payloads (FALSE boolean value).
- Add several tests.
beta
beta
0.1.5
0.1.5
2009-03-31
- Implement getVersion().
- Add support for preserving boolean value types.
- Fix crash when child class does not call constructor.
- Fix bug #16084 (Crash when addServers is called with an associative array).
- ZTS compilation fixes.
beta
beta
0.1.4
0.1.4
2009-02-13
- Fix compilation against PHP 5.3.
- Add support for 'igbinary' serializer (Oleg Grenrus)
beta
beta
0.1.3
0.1.3
2009-02-06
- Bludgeon bug #15896 (Memcached setMulti error) into submission.
beta
beta
0.1.2
0.1.2
2009-02-06
- Fix bug #15896 (Memcached setMulti error).
- Check for empty key in getServerByKey().
- Allow passing 'null' for callbacks.
- get() with cas token fetching wasn't erroring out properly.
- Rename certain parameters in the API to be more clear.
- Allow only strings as the append/prepend value.
- Remove expiration parameter from append/prepend.
beta
beta
0.1.1
0.1.1
2009-02-02
- Add OPT_LIBKETAMA_COMPATIBLE option.
- Implement addServers() method.
- Swap internal compressed and serialized flags to be compatible with other clients.
beta
beta
0.1.0
0.1.0
2009-01-29
- Initial PECL release
memcached-2.1.0/README.markdown 0000644 0000767 0000024 00000000744 12010120566 015246 0 ustar andrei staff Description
-----------
This extension uses libmemcached library to provide API for communicating with
memcached servers.
memcached is a high-performance, distributed memory object caching system,
generic in nature, but intended for use in speeding up dynamic web applications
by alleviating database load.
Resources
---------
* [libmemcached](http://tangent.org/552/libmemcached.html)
* [memcached](http://www.danga.com/memcached/)
* [igbinary](http://opensource.dynamoid.com/)
memcached-2.1.0/CREDITS 0000644 0000767 0000024 00000000073 12010120566 013560 0 ustar andrei staff memcached
Andrei Zmievski, Oleg Grenrus (igbinary support)
memcached-2.1.0/LICENSE 0000644 0000767 0000024 00000006222 12010120566 013547 0 ustar andrei staff --------------------------------------------------------------------
The PHP License, version 3.01
Copyright (c) 1999 - 2010 The PHP Group. All rights reserved.
--------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
modification, is permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
3. The name "PHP" must not be used to endorse or promote products
derived from this software without prior written permission. For
written permission, please contact group@php.net.
4. Products derived from this software may not be called "PHP", nor
may "PHP" appear in their name, without prior written permission
from group@php.net. You may indicate that your software works in
conjunction with PHP by saying "Foo for PHP" instead of calling
it "PHP Foo" or "phpfoo"
5. The PHP Group may publish revised and/or new versions of the
license from time to time. Each version will be given a
distinguishing version number.
Once covered code has been published under a particular version
of the license, you may always continue to use it under the terms
of that version. You may also choose to use such covered code
under the terms of any subsequent version of the license
published by the PHP Group. No one other than the PHP Group has
the right to modify the terms applicable to covered code created
under this License.
6. Redistributions of any form whatsoever must retain the following
acknowledgment:
"This product includes PHP software, freely available from
".
THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND
ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP
DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------
This software consists of voluntary contributions made by many
individuals on behalf of the PHP Group.
The PHP Group can be contacted via Email at group@php.net.
For more information on the PHP Group and the PHP project,
please see .
PHP includes the Zend Engine, freely available at
.
memcached-2.1.0/ChangeLog 0000644 0000767 0000024 00000011274 12010120566 014317 0 ustar andrei staff memcached extension changelog
Version 2.1.0
-------------
* Drop support for libmemcached 0.x series, now 1.0.x is required
* Add support for virtual bucket distribution
* Fix compilation against PHP 5.2
Version 2.0.1
-------------
* Fix embedded version number to be not -dev
Version 2.0.0
-------------
* Add touch() and touchByKey() methods
* Add resetServerList() and quit() methods
* Support binary protocol in sessions
* Make it work with libmemcached up to 1.0.4
* Test against PHP 5.4.0
Version 2.0.0b2
---------------
* Add OPT_REMOVE_FAILED_SERVERS option.
* Make it work with libmemcached up to 0.49.
* Fix a case where invalid session ID could lock the script.
* Improve session support:
- Add support for libmemcached config string
- Add persistence support via PERSISTENT=persistent_id prefix
of the save_path
* Add 3rd parameter to the __construct() that allows specification
of libmemcached configuration string
* Fix a possible crash in __construct() when using persistent
connections
* Add work-around a bug in libmemcached < 0.50 that causes truncation
of last character of server key prefix
* When using multiple servers implement transparent fail-over
* Fix php_memc_cas_impl() implementation when server_key is not being used
* Add support for incrementByKey() and decrementByKey()
* Make increment/decrement initialize value when it is not available (when
using binary protocol)
Version 2.0.0b1
---------------
* Change the return value for non-existing keys to be NULL rather than
'false', affects simple get only
* Add fastlz library that provides better/faster payload compression
* Add configure switch to enable/disable JSON serialization support
* Add getAllKeys() method
* Add deleteMulti() and deleteMultiByKey() methods
* Add isPristine() and isPersistent() methods
* Add setOptions() method to set multiple options at once
* Add SERIALIZER_JSON_ARRAY type that decodes JSON payloads as arrays
instead of objects
* Add support for Unix domain socket connections
* Add memcached.compression_threshold INI setting
* Add memcached.compression_factor INI setting
* Add memcached.compression_type INI setting
* Implement a few speed optimizations
* Many bug fixes and memory leaks plugged
* Add several more tests
* Add constants for libmemcached 0.37+:
- Memcached::OPT_NUMBER_OF_REPLICAS
- Memcached::OPT_RANDOMIZE_REPLICA_READ
* Add 'on_new' callback to constructor
* Add SASL support
Version 1.0.1
-------------
* Fix JSON API handling to account for PHP 5.2/5.3 version differences.
* Add memcached.sess_locking, memcached.sess_lock_wait, and
memcached.sess_prefix INI entries.
* Add OPT_AUTO_EJECT_HOSTS option.
Version 1.0.0
-------------
* First stable release.
* Add getResultMessage() method.
* Fix OPT_RECV_TIMEOUT definition.
* Initialize Session lock wait to max execution time (if max execution
time is unlimited, default to 30 seconds).
Version 0.2.0
-------------
* Add JSON serializer support, requires PHP 5.2.10+.
* Add HAVE_JSON and HAVE_IGBINARY class constants that indicate
whether the respective serializers are available.
* Add 'flags' parameter to getMulti() and getMultiByKey().
* Add GET_PRESERVE_ORDER class constant that can be used with
abovementioned flags parameter to make the order of the keys in the
response match the request.
* Fix an issue with retrieving 0-length payloads (FALSE boolean value).
* Refactor the way payload types are stored in memcached flags to optimize
the structure and allow for future expansion. WARNING! You have to flush
the cache when upgrading to this version.
* Add several tests.
Version 0.1.5
-------------
* Implement getVersion().
* Add support for preserving boolean value types.
* Fix crash when child class does not call constructor.
* Fix bug #16084 (Crash when addServers is called with an associative array).
* ZTS compilation fixes.
Version 0.1.4
-------------
* Fix compilation against PHP 5.3.
* Add support for 'igbinary' serializer (Oleg Grenrus)
Version 0.1.3
-------------
* Bludgeon bug #15896 (Memcached setMulti error) into submission.
Version 0.1.2
-------------
* Fix bug #15896 (Memcached setMulti error).
* Check for empty key in getServerByKey().
* Allow passing 'null' for callbacks.
* get() with cas token fetching wasn't erroring out properly.
* Rename certain parameters in the API to be more clear.
* Allow only strings as the append/prepend value.
* Remove expiration parameter from append/prepend.
Version 0.1.1
-------------
* Add OPT_LIBKETAMA_COMPATIBLE option.
* Implement addServers() method.
* Swap internal compressed and serialized flags to be compatible with other clients.
Version 0.1.0
-------------
* Initial release
memcached-2.1.0/memcached-api.php 0000644 0000767 0000024 00000011675 12010120566 015740 0 ustar andrei staff comp_len * factor
;
; the default value is 1.3 (23% space saving)
memcached.compression_factor = "1.3"
; The compression threshold
;
; Do not compress serialized values below this threshold.
; the default is 2000 bytes
memcached.compression_threshold = 2000
; Set the default serializer for new memcached objects.
; valid values are: php, igbinary, json, json_array
;
; json - standard php JSON encoding. This serializer
; is fast and compact but only works on UTF-8
; encoded data and does not fully implement
; serializing. See the JSON extension.
; json_array - as json, but decodes into arrays
; php - the standard php serializer
; igbinary - a binary serializer
;
; The default is igbinary if available and php otherwise.
memcached.serializer = "igbinary"
memcached-2.1.0/fastlz/LICENSE 0000644 0000767 0000024 00000002312 12010120566 015046 0 ustar andrei staff FastLZ - lightning-fast lossless compression library
Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
Copyright (C) 2005 Ariya Hidayat (ariya@kde.org)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
memcached-2.1.0/config.m4 0000644 0000767 0000024 00000022214 12010120566 014250 0 ustar andrei staff 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])
PHP_ARG_WITH(libmemcached-dir, for libmemcached,
[ --with-libmemcached-dir[=DIR] Set the path to libmemcached install prefix.], yes)
PHP_ARG_ENABLE(memcached-session, whether to enable memcached session handler support,
[ --disable-memcached-session Disable memcached session handler support], yes, no)
PHP_ARG_ENABLE(memcached-igbinary, whether to enable memcached igbinary serializer support,
[ --enable-memcached-igbinary Enable memcached igbinary serializer support], no, no)
PHP_ARG_ENABLE(memcached-json, whether to enable memcached json serializer support,
[ --enable-memcached-json Enable memcached json serializer support], no, no)
PHP_ARG_ENABLE(memcached-sasl, whether to disable memcached sasl support,
[ --disable-memcached-sasl Disable memcached sasl support], no, no)
if test -z "$PHP_ZLIB_DIR"; then
PHP_ARG_WITH(zlib-dir, for ZLIB,
[ --with-zlib-dir[=DIR] Set the path to ZLIB install prefix.], no)
fi
if test -z "$PHP_DEBUG"; then
AC_ARG_ENABLE(debug,
[ --enable-debug compile with debugging symbols],[
PHP_DEBUG=$enableval
],[ PHP_DEBUG=no
])
fi
if test "$PHP_MEMCACHED" != "no"; then
dnl # zlib
if test "$PHP_ZLIB_DIR" != "no" && test "$PHP_ZLIB_DIR" != "yes"; then
if test -f "$PHP_ZLIB_DIR/include/zlib/zlib.h"; then
PHP_ZLIB_DIR="$PHP_ZLIB_DIR"
PHP_ZLIB_INCDIR="$PHP_ZLIB_DIR/include/zlib"
elif test -f "$PHP_ZLIB_DIR/include/zlib.h"; then
PHP_ZLIB_DIR="$PHP_ZLIB_DIR"
PHP_ZLIB_INCDIR="$PHP_ZLIB_DIR/include"
else
AC_MSG_ERROR([Can't find ZLIB headers under "$PHP_ZLIB_DIR"])
fi
else
for i in /usr/local /usr; do
if test -f "$i/include/zlib/zlib.h"; then
PHP_ZLIB_DIR="$i"
PHP_ZLIB_INCDIR="$i/include/zlib"
elif test -f "$i/include/zlib.h"; then
PHP_ZLIB_DIR="$i"
PHP_ZLIB_INCDIR="$i/include"
fi
done
fi
AC_MSG_CHECKING([for zlib location])
if test "$PHP_ZLIB_DIR" != "no" && test "$PHP_ZLIB_DIR" != "yes"; then
AC_MSG_RESULT([$PHP_ZLIB_DIR])
PHP_ADD_LIBRARY_WITH_PATH(z, $PHP_ZLIB_DIR/$PHP_LIBDIR, MEMCACHED_SHARED_LIBADD)
PHP_ADD_INCLUDE($PHP_ZLIB_INCDIR)
else
AC_MSG_ERROR([memcached support requires ZLIB. Use --with-zlib-dir= to specify the prefix where ZLIB headers and library are located])
fi
if test "$PHP_MEMCACHED_SESSION" != "no"; then
AC_MSG_CHECKING([for session includes])
session_inc_path=""
if test -f "$abs_srcdir/include/php/ext/session/php_session.h"; then
session_inc_path="$abs_srcdir/include/php"
elif test -f "$abs_srcdir/ext/session/php_session.h"; then
session_inc_path="$abs_srcdir"
elif test -f "$phpincludedir/ext/session/php_session.h"; then
session_inc_path="$phpincludedir"
else
for i in php php4 php5 php6; do
if test -f "$prefix/include/$i/ext/session/php_session.h"; then
session_inc_path="$prefix/include/$i"
fi
done
fi
if test "$session_inc_path" = ""; then
AC_MSG_ERROR([Cannot find php_session.h])
else
AC_MSG_RESULT([$session_inc_path])
fi
fi
if test "$PHP_MEMCACHED_JSON" != "no"; then
AC_MSG_CHECKING([for json includes])
json_inc_path=""
tmp_version=$PHP_VERSION
if test -z "$tmp_version"; then
if test -z "$PHP_CONFIG"; then
AC_MSG_ERROR([php-config not found])
fi
PHP_MEMCACHED_VERSION_ORIG=`$PHP_CONFIG --version`;
else
PHP_MEMCACHED_VERSION_ORIG=$tmp_version
fi
if test -z $PHP_MEMCACHED_VERSION_ORIG; then
AC_MSG_ERROR([failed to detect PHP version, please report])
fi
PHP_MEMCACHED_VERSION_MASK=`echo ${PHP_MEMCACHED_VERSION_ORIG} | awk 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'`
if test $PHP_MEMCACHED_VERSION_MASK -ge 5003000; then
if test -f "$abs_srcdir/include/php/ext/json/php_json.h"; then
json_inc_path="$abs_srcdir/include/php"
elif test -f "$abs_srcdir/ext/json/php_json.h"; then
json_inc_path="$abs_srcdir"
elif test -f "$phpincludedir/ext/json/php_json.h"; then
json_inc_path="$phpincludedir"
else
for i in php php4 php5 php6; do
if test -f "$prefix/include/$i/ext/json/php_json.h"; then
json_inc_path="$prefix/include/$i"
fi
done
fi
if test "$json_inc_path" = ""; then
AC_MSG_ERROR([Cannot find php_json.h])
else
AC_DEFINE(HAVE_JSON_API,1,[Whether JSON API is available])
AC_DEFINE(HAVE_JSON_API_5_3,1,[Whether JSON API for PHP 5.3 is available])
AC_MSG_RESULT([$json_inc_path])
fi
elif test $PHP_MEMCACHED_VERSION_MASK -ge 5002009; then
dnl Check JSON for PHP 5.2.9+
if test -f "$abs_srcdir/include/php/ext/json/php_json.h"; then
json_inc_path="$abs_srcdir/include/php"
elif test -f "$abs_srcdir/ext/json/php_json.h"; then
json_inc_path="$abs_srcdir"
elif test -f "$phpincludedir/ext/json/php_json.h"; then
json_inc_path="$phpincludedir"
else
for i in php php4 php5 php6; do
if test -f "$prefix/include/$i/ext/json/php_json.h"; then
json_inc_path="$prefix/include/$i"
fi
done
fi
if test "$json_inc_path" = ""; then
AC_MSG_ERROR([Cannot find php_json.h])
else
AC_DEFINE(HAVE_JSON_API,1,[Whether JSON API is available])
AC_DEFINE(HAVE_JSON_API_5_2,1,[Whether JSON API for PHP 5.2 is available])
AC_MSG_RESULT([$json_inc_path])
fi
else
AC_MSG_RESULT([the PHP version does not support JSON serialization API])
fi
fi
if test "$PHP_MEMCACHED_IGBINARY" != "no"; then
AC_MSG_CHECKING([for igbinary includes])
igbinary_inc_path=""
if test -f "$abs_srcdir/include/php/ext/igbinary/igbinary.h"; then
igbinary_inc_path="$abs_srcdir/include/php"
elif test -f "$abs_srcdir/ext/igbinary/igbinary.h"; then
igbinary_inc_path="$abs_srcdir"
elif test -f "$phpincludedir/ext/session/igbinary.h"; then
igbinary_inc_path="$phpincludedir"
elif test -f "$phpincludedir/ext/igbinary/igbinary.h"; then
igbinary_inc_path="$phpincludedir"
else
for i in php php4 php5 php6; do
if test -f "$prefix/include/$i/ext/igbinary/igbinary.h"; then
igbinary_inc_path="$prefix/include/$i"
fi
done
fi
if test "$igbinary_inc_path" = ""; then
AC_MSG_ERROR([Cannot find igbinary.h])
else
AC_MSG_RESULT([$igbinary_inc_path])
fi
fi
AC_MSG_CHECKING([for memcached session support])
if test "$PHP_MEMCACHED_SESSION" != "no"; then
AC_MSG_RESULT([enabled])
AC_DEFINE(HAVE_MEMCACHED_SESSION,1,[Whether memcache session handler is enabled])
SESSION_INCLUDES="-I$session_inc_path"
ifdef([PHP_ADD_EXTENSION_DEP],
[
PHP_ADD_EXTENSION_DEP(memcached, session)
])
else
SESSION_INCLUDES=""
AC_MSG_RESULT([disabled])
fi
AC_MSG_CHECKING([for memcached igbinary support])
if test "$PHP_MEMCACHED_IGBINARY" != "no"; then
AC_MSG_RESULT([enabled])
AC_DEFINE(HAVE_MEMCACHED_IGBINARY,1,[Whether memcache igbinary serializer is enabled])
IGBINARY_INCLUDES="-I$igbinary_inc_path"
ifdef([PHP_ADD_EXTENSION_DEP],
[
PHP_ADD_EXTENSION_DEP(memcached, igbinary)
])
else
IGBINARY_INCLUDES=""
AC_MSG_RESULT([disabled])
fi
if test "$PHP_MEMCACHED_SASL" != "no"; then
AC_CHECK_HEADERS([sasl/sasl.h], [memcached_enable_sasl="yes"], [memcached_enable_sasl="no"])
AC_MSG_CHECKING([whether to enable sasl support])
AC_MSG_RESULT([$memcached_enable_sasl])
fi
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"])
fi
else
PHP_LIBMEMCACHED_DIR="no"
for i in /usr /usr/local; do
if test -r "$i/include/libmemcached/memcached.h"; then
PHP_LIBMEMCACHED_DIR=$i
break
fi
done
fi
if test "$PHP_LIBMEMCACHED_DIR" = "no"; then
AC_MSG_ERROR([memcached support requires libmemcached 1.0.x. Use --with-libmemcached-dir= to specify the prefix where libmemcached headers and library are located])
else
AC_MSG_RESULT([$PHP_LIBMEMCACHED_DIR])
PHP_LIBMEMCACHED_INCDIR="$PHP_LIBMEMCACHED_DIR/include"
PHP_ADD_INCLUDE($PHP_LIBMEMCACHED_INCDIR)
PHP_ADD_LIBRARY_WITH_PATH(memcached, $PHP_LIBMEMCACHED_DIR/$PHP_LIBDIR, MEMCACHED_SHARED_LIBADD)
PHP_SUBST(MEMCACHED_SHARED_LIBADD)
PHP_MEMCACHED_FILES="php_memcached.c fastlz/fastlz.c g_fmt.c"
if test "$PHP_MEMCACHED_SESSION" != "no"; then
PHP_MEMCACHED_FILES="${PHP_MEMCACHED_FILES} php_memcached_session.c"
fi
PHP_NEW_EXTENSION(memcached, $PHP_MEMCACHED_FILES, $ext_shared,,$SESSION_INCLUDES $IGBINARY_INCLUDES)
PHP_ADD_BUILD_DIR($ext_builddir/fastlz, 1)
ifdef([PHP_ADD_EXTENSION_DEP],
[
PHP_ADD_EXTENSION_DEP(memcached, spl, true)
])
fi
fi
memcached-2.1.0/config.w32 0000644 0000767 0000024 00000000760 12010120566 014345 0 ustar andrei staff // $ Id: $
// vim:ft=javascript
ARG_WITH('memcached', 'libmemcached extension', 'no');
if (PHP_MEMCACHED == "yes") {
if (!CHECK_LIB("memcached.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");
AC_DEFINE("HAVE_MEMCACHED", 1, "memcached support");
}
memcached-2.1.0/php_memcached.c 0000644 0000767 0000024 00000337160 12010120566 015473 0 ustar andrei staff /*
+----------------------------------------------------------------------+
| Copyright (c) 2009-2010 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt. |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Andrei Zmievski |
+----------------------------------------------------------------------+
*/
/* $ Id: $ */
/* TODO
* - set LIBKETAMA_COMPATIBLE as the default?
* - fix unserialize(serialize($memc))
* - ability to set binary protocol for sessions
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include
#include
#include
#include
#ifdef ZTS
#include "TSRM.h"
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include "php_memcached.h"
#include "g_fmt.h"
#ifdef HAVE_MEMCACHED_SESSION
# include "php_memcached_session.h"
#endif
#include "fastlz/fastlz.h"
#include
/* Used to store the size of the block */
#if defined(HAVE_INTTYPES_H)
#include
#elif defined(HAVE_STDINT_H)
#include
#endif
#ifdef PHP_WIN32
# include "win32/php_stdint.h"
#else
# ifndef HAVE_INT32_T
# if SIZEOF_INT == 4
typedef int int32_t;
# elif SIZEOF_LONG == 4
typedef long int int32_t;
# endif
# endif
# ifndef HAVE_UINT32_T
# if SIZEOF_INT == 4
typedef unsigned int uint32_t;
# elif SIZEOF_LONG == 4
typedef unsigned long int uint32_t;
# endif
# endif
#endif
#ifdef HAVE_JSON_API
# include "ext/json/php_json.h"
#endif
#ifdef HAVE_MEMCACHED_IGBINARY
# include "ext/igbinary/igbinary.h"
#endif
/*
* This is needed because PHP 5.3.[01] does not install JSON_parser.h by default. This
* constant will move into php_json.h in the future anyway.
*/
#ifndef JSON_PARSER_DEFAULT_DEPTH
#define JSON_PARSER_DEFAULT_DEPTH 512
#endif
/****************************************
Custom options
****************************************/
#define MEMC_OPT_COMPRESSION -1001
#define MEMC_OPT_PREFIX_KEY -1002
#define MEMC_OPT_SERIALIZER -1003
#define MEMC_OPT_COMPRESSION_TYPE -1004
/****************************************
Custom result codes
****************************************/
#define MEMC_RES_PAYLOAD_FAILURE -1001
/****************************************
Payload value flags
****************************************/
#define MEMC_VAL_TYPE_MASK 0xf
#define MEMC_VAL_GET_TYPE(flags) ((flags) & MEMC_VAL_TYPE_MASK)
#define MEMC_VAL_SET_TYPE(flags, type) ((flags) |= ((type) & MEMC_VAL_TYPE_MASK))
#define MEMC_VAL_IS_STRING 0
#define MEMC_VAL_IS_LONG 1
#define MEMC_VAL_IS_DOUBLE 2
#define MEMC_VAL_IS_BOOL 3
#define MEMC_VAL_IS_SERIALIZED 4
#define MEMC_VAL_IS_IGBINARY 5
#define MEMC_VAL_IS_JSON 6
#define MEMC_VAL_COMPRESSED (1<<4)
#define MEMC_VAL_COMPRESSION_ZLIB (1<<5)
#define MEMC_VAL_COMPRESSION_FASTLZ (1<<6)
/****************************************
"get" operation flags
****************************************/
#define MEMC_GET_PRESERVE_ORDER (1<<0)
/****************************************
Helper macros
****************************************/
#define MEMC_METHOD_INIT_VARS \
zval* object = getThis(); \
php_memc_t* i_obj = NULL; \
struct memc_obj* m_obj = NULL;
#define MEMC_METHOD_FETCH_OBJECT \
i_obj = (php_memc_t *) zend_object_store_get_object( object TSRMLS_CC ); \
m_obj = i_obj->obj; \
if (!m_obj) { \
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Memcached constructor was not called"); \
return; \
}
#ifndef DVAL_TO_LVAL
#ifdef _WIN64
# define DVAL_TO_LVAL(d, l) \
if ((d) > LONG_MAX) { \
(l) = (long)(unsigned long)(__int64) (d); \
} else { \
(l) = (long) (d); \
}
#else
# define DVAL_TO_LVAL(d, l) \
if ((d) > LONG_MAX) { \
(l) = (unsigned long) (d); \
} else { \
(l) = (long) (d); \
}
#endif
#endif
#define RETURN_FROM_GET RETURN_FALSE
#if (PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION < 3)
#define zend_parse_parameters_none() \
zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "")
#endif
/****************************************
Structures and definitions
****************************************/
enum memcached_compression_type {
COMPRESSION_TYPE_ZLIB = 1,
COMPRESSION_TYPE_FASTLZ = 2,
};
typedef struct {
zend_object zo;
struct memc_obj {
memcached_st *memc;
zend_bool compression;
enum memcached_serializer serializer;
enum memcached_compression_type compression_type;
#if HAVE_MEMCACHED_SASL
zend_bool has_sasl_data;
#endif
} *obj;
zend_bool is_persistent;
zend_bool is_pristine;
int rescode;
int memc_errno;
} php_memc_t;
enum {
MEMC_OP_SET,
MEMC_OP_TOUCH,
MEMC_OP_ADD,
MEMC_OP_REPLACE,
MEMC_OP_APPEND,
MEMC_OP_PREPEND
};
static zend_class_entry *memcached_ce = NULL;
static zend_class_entry *memcached_exception_ce = NULL;
static zend_object_handlers memcached_object_handlers;
struct callbackContext
{
zval *array;
zval *entry;
memcached_stat_st *stats; /* for use with functions that need stats */
void *return_value;
unsigned int i; /* for use with structures mapped against servers */
};
#if HAVE_SPL
static zend_class_entry *spl_ce_RuntimeException = NULL;
#endif
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 3)
const zend_fcall_info empty_fcall_info = { 0, NULL, NULL, NULL, NULL, 0, NULL, NULL, 0 };
#undef ZEND_BEGIN_ARG_INFO_EX
#define ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, return_reference, required_num_args) \
static zend_arg_info name[] = { \
{ NULL, 0, NULL, 0, 0, 0, pass_rest_by_reference, return_reference, required_num_args },
#endif
ZEND_DECLARE_MODULE_GLOBALS(php_memcached)
#ifdef COMPILE_DL_MEMCACHED
ZEND_GET_MODULE(memcached)
#endif
static PHP_INI_MH(OnUpdateCompressionType)
{
if (!new_value) {
MEMC_G(compression_type_real) = COMPRESSION_TYPE_FASTLZ;
} else if (!strcmp(new_value, "fastlz")) {
MEMC_G(compression_type_real) = COMPRESSION_TYPE_FASTLZ;
} else if (!strcmp(new_value, "zlib")) {
MEMC_G(compression_type_real) = COMPRESSION_TYPE_ZLIB;
} else {
return FAILURE;
}
return OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
}
static PHP_INI_MH(OnUpdateSerializer)
{
if (!new_value) {
MEMC_G(serializer) = SERIALIZER_DEFAULT;
} else if (!strcmp(new_value, "php")) {
MEMC_G(serializer) = SERIALIZER_PHP;
#ifdef HAVE_MEMCACHE_IGBINARY
} else if (!strcmp(new_value, "igbinary")) {
MEMC_G(serializer) = SERIALIZER_IGBINARY;
#endif // IGBINARY
#ifdef HAVE_JSON_API
} else if (!strcmp(new_value, "json")) {
MEMC_G(serializer) = SERIALIZER_JSON;
} else if (!strcmp(new_value, "json_array")) {
MEMC_G(serializer) = SERIALIZER_JSON_ARRAY;
#endif // JSON
} else {
return FAILURE;
}
return OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
}
/* {{{ INI entries */
PHP_INI_BEGIN()
#ifdef HAVE_MEMCACHED_SESSION
STD_PHP_INI_ENTRY("memcached.sess_locking", "1", PHP_INI_ALL, OnUpdateBool, sess_locking_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_prefix", "memc.sess.key.", PHP_INI_ALL, OnUpdateString, sess_prefix, 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)
STD_PHP_INI_ENTRY("memcached.compression_threshold", "2000", PHP_INI_ALL, OnUpdateLong, compression_threshold, zend_php_memcached_globals, php_memcached_globals)
STD_PHP_INI_ENTRY("memcached.serializer", SERIALIZER_DEFAULT_NAME, PHP_INI_ALL, OnUpdateSerializer, serializer_name, zend_php_memcached_globals, php_memcached_globals)
#if HAVE_MEMCACHED_SASL
STD_PHP_INI_ENTRY("memcached.use_sasl", "0", PHP_INI_SYSTEM, OnUpdateBool, use_sasl, zend_php_memcached_globals, php_memcached_globals)
#endif
PHP_INI_END()
/* }}} */
/****************************************
Forward declarations
****************************************/
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 void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key);
static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key);
static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool by_key);
static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key);
static void php_memc_delete_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key);
static void php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key);
static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key);
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 void php_memc_destroy(struct memc_obj *m_obj, zend_bool persistent TSRMLS_DC);
/****************************************
Method implementations
****************************************/
static zend_bool php_memcached_on_new_callback(zval *object, zend_fcall_info *fci, zend_fcall_info_cache *fci_cache, char *persistent_id, int persistent_id_len TSRMLS_DC)
{
zval pid_z;
zval *retval_ptr, *pid_z_ptr = &pid_z;
zval **params[2];
INIT_ZVAL(pid_z);
if (persistent_id) {
ZVAL_STRINGL(pid_z_ptr, persistent_id, persistent_id_len, 1);
}
/* Call the cb */
params[0] = &object;
params[1] = &pid_z_ptr;
fci->params = params;
fci->param_count = 2;
fci->retval_ptr_ptr = &retval_ptr;
fci->no_separation = 1;
if (zend_call_function(fci, fci_cache TSRMLS_CC) == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to invoke 'on_new' callback %s()", Z_STRVAL_P(fci->function_name));
return 0;
}
zval_dtor(pid_z_ptr);
if (retval_ptr) {
zval_ptr_dtor(&retval_ptr);
}
return 1;
}
static int le_memc, le_memc_sess;
static int php_memc_list_entry(void)
{
return le_memc;
}
/* {{{ Memcached::__construct([string persistent_id[, callback on_new[, string connection_str]]]))
Creates a Memcached object, optionally using persistent memcache connection */
static PHP_METHOD(Memcached, __construct)
{
zval *object = getThis();
php_memc_t *i_obj;
struct memc_obj *m_obj = NULL;
char *persistent_id = NULL, *conn_str = NULL;
int persistent_id_len, conn_str_len;
zend_bool is_persistent = 0;
char *plist_key = NULL;
int plist_key_len = 0;
zend_fcall_info fci = {0};
zend_fcall_info_cache fci_cache;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!f!s", &persistent_id, &persistent_id_len, &fci, &fci_cache, &conn_str, &conn_str_len) == FAILURE) {
ZVAL_NULL(object);
return;
}
i_obj = (php_memc_t *) zend_object_store_get_object(object TSRMLS_CC);
i_obj->is_pristine = 0;
if (persistent_id && *persistent_id) {
zend_rsrc_list_entry *le = NULL;
is_persistent = 1;
plist_key_len = spprintf(&plist_key, 0, "memcached:id=%s", persistent_id);
plist_key_len += 1;
if (zend_hash_find(&EG(persistent_list), plist_key, plist_key_len, (void *)&le) == SUCCESS) {
if (le->type == php_memc_list_entry()) {
m_obj = (struct memc_obj *) le->ptr;
}
}
i_obj->obj = m_obj;
}
i_obj->is_persistent = is_persistent;
if (!m_obj) {
m_obj = pecalloc(1, sizeof(*m_obj), is_persistent);
if (m_obj == NULL) {
if (plist_key) {
efree(plist_key);
}
php_error_docref(NULL TSRMLS_CC, E_ERROR, "out of memory: cannot allocate handle");
/* not reached */
}
if (conn_str) {
m_obj->memc = memcached(conn_str, conn_str_len);
if (!m_obj->memc) {
char error_buffer[1024];
if (plist_key) {
efree(plist_key);
}
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");
}
/* not reached */
}
} else {
m_obj->memc = memcached_create(NULL);
if (m_obj->memc == NULL) {
if (plist_key) {
efree(plist_key);
}
php_error_docref(NULL TSRMLS_CC, E_ERROR, "could not allocate libmemcached structure");
/* not reached */
}
}
m_obj->serializer = MEMC_G(serializer);
m_obj->compression_type = MEMC_G(compression_type_real);
m_obj->compression = 1;
i_obj->obj = m_obj;
i_obj->is_pristine = 1;
if (fci.size) { /* will be 0 when not available */
if (!php_memcached_on_new_callback(object, &fci, &fci_cache, persistent_id, persistent_id_len TSRMLS_CC) || EG(exception)) {
/* error calling or exception thrown from callback */
if (plist_key) {
efree(plist_key);
}
i_obj->obj = NULL;
if (is_persistent) {
php_memc_destroy(m_obj, is_persistent TSRMLS_CC);
}
return;
}
}
if (is_persistent) {
zend_rsrc_list_entry le;
le.type = php_memc_list_entry();
le.ptr = m_obj;
if (zend_hash_update(&EG(persistent_list), (char *)plist_key,
plist_key_len, (void *)&le, sizeof(le), NULL) == FAILURE) {
if (plist_key) {
efree(plist_key);
}
php_error_docref(NULL TSRMLS_CC, E_ERROR, "could not register persistent entry");
/* not reached */
}
}
}
if (plist_key) {
efree(plist_key);
}
}
/* }}} */
/* {{{ Memcached::get(string key [, mixed callback [, double &cas_token ] ])
Returns a value for the given key or false */
PHP_METHOD(Memcached, get)
{
php_memc_get_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
}
/* }}} */
/* {{{ Memcached::getByKey(string server_key, string key [, mixed callback [, double &cas_token ] ])
Returns a value for key from the server identified by the server key or false */
PHP_METHOD(Memcached, getByKey)
{
php_memc_get_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}
/* }}} */
/* {{{ -- php_memc_get_impl */
static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key)
{
char *key = NULL;
int key_len = 0;
char *server_key = NULL;
int server_key_len = 0;
char *payload = NULL;
size_t payload_len = 0;
uint32_t flags = 0;
uint64_t cas = 0;
const char* keys[1] = { NULL };
size_t key_lens[1] = { 0 };
zval *cas_token = NULL;
zend_fcall_info fci = empty_fcall_info;
zend_fcall_info_cache fcc = empty_fcall_info_cache;
memcached_result_st result;
memcached_return status = MEMCACHED_SUCCESS;
MEMC_METHOD_INIT_VARS;
if (by_key) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|f!z", &server_key,
&server_key_len, &key, &key_len, &fci, &fcc, &cas_token) == FAILURE) {
return;
}
} else {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|f!z", &key, &key_len,
&fci, &fcc, &cas_token) == FAILURE) {
return;
}
}
MEMC_METHOD_FETCH_OBJECT;
i_obj->rescode = MEMCACHED_SUCCESS;
if (key_len == 0) {
i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED;
RETURN_FROM_GET;
}
keys[0] = key;
key_lens[0] = key_len;
if (cas_token) {
uint64_t orig_cas_flag;
/*
* 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);
}
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 (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);
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);
/* 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;
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);
}
if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
if (payload) {
free(payload);
}
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;
}
}
}
}
/* }}} */
/* {{{ Memcached::getMulti(array keys [, array &cas_tokens ])
Returns values for the given keys or false */
PHP_METHOD(Memcached, getMulti)
{
php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
}
/* }}} */
/* {{{ Memcached::getMultiByKey(string server_key, array keys [, array &cas_tokens ])
Returns values for the given keys from the server identified by the server key or false */
PHP_METHOD(Memcached, getMultiByKey)
{
php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}
/* }}} */
/* {{{ -- php_memc_getMulti_impl */
static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key)
{
zval *keys = NULL;
char *server_key = NULL;
int server_key_len = 0;
size_t num_keys = 0;
zval **entry = NULL;
char *payload = NULL;
size_t payload_len = 0;
const char **mkeys = NULL;
size_t *mkeys_len = NULL;
char *res_key = NULL;
size_t res_key_len = 0;
uint32_t flags;
uint64_t cas = 0;
zval *cas_tokens = NULL;
uint64_t orig_cas_flag;
zval *value;
long get_flags = 0;
int i = 0;
zend_bool preserve_order;
memcached_result_st result;
memcached_return status = MEMCACHED_SUCCESS;
MEMC_METHOD_INIT_VARS;
if (by_key) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|zl", &server_key,
&server_key_len, &keys, &cas_tokens, &get_flags) == FAILURE) {
return;
}
} else {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/|zl", &keys, &cas_tokens, &get_flags) == FAILURE) {
return;
}
}
MEMC_METHOD_FETCH_OBJECT;
i_obj->rescode = MEMCACHED_SUCCESS;
preserve_order = (get_flags & MEMC_GET_PRESERVE_ORDER);
num_keys = zend_hash_num_elements(Z_ARRVAL_P(keys));
mkeys = safe_emalloc(num_keys, sizeof(*mkeys), 0);
mkeys_len = safe_emalloc(num_keys, sizeof(*mkeys_len), 0);
array_init(return_value);
/*
* Create the array of keys for libmemcached. If none of the keys were valid
* (strings), set bad key result code and return.
*/
for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(keys));
zend_hash_get_current_data(Z_ARRVAL_P(keys), (void**)&entry) == SUCCESS;
zend_hash_move_forward(Z_ARRVAL_P(keys))) {
if (Z_TYPE_PP(entry) != IS_STRING) {
convert_to_string_ex(entry);
}
if (Z_TYPE_PP(entry) == IS_STRING && Z_STRLEN_PP(entry) > 0) {
mkeys[i] = Z_STRVAL_PP(entry);
mkeys_len[i] = Z_STRLEN_PP(entry);
if (preserve_order) {
add_assoc_null_ex(return_value, mkeys[i], mkeys_len[i] + 1);
}
i++;
}
}
if (i == 0) {
i_obj->rescode = MEMCACHED_NOTFOUND;
efree(mkeys);
efree(mkeys_len);
return;
}
/*
* Enable CAS support, but only if it is currently disabled.
*/
if (cas_tokens) {
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);
}
}
status = memcached_mget_by_key(m_obj->memc, server_key, server_key_len, mkeys, mkeys_len, i);
/* Handle error, but ignore, there might still be some result */
php_memc_handle_error(i_obj, status TSRMLS_CC);
/*
* Restore the CAS support flag, but only if we had to turn it on.
*/
if (cas_tokens && orig_cas_flag == 0) {
memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, orig_cas_flag);
}
efree(mkeys);
efree(mkeys_len);
/*
* Iterate through the result set and create the result array. The CAS tokens are
* returned as doubles, because we cannot store potential 64-bit values in longs.
*/
if (cas_tokens) {
zval_dtor(cas_tokens);
array_init(cas_tokens);
}
memcached_result_create(m_obj->memc, &result);
while ((memcached_fetch_result(m_obj->memc, &result, &status)) != NULL) {
if (status != MEMCACHED_SUCCESS) {
status = MEMCACHED_SOME_ERRORS;
php_memc_handle_error(i_obj, status TSRMLS_CC);
continue;
}
payload = memcached_result_value(&result);
payload_len = memcached_result_length(&result);
flags = memcached_result_flags(&result);
res_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;
MAKE_STD_ZVAL(value);
if (php_memc_zval_from_payload(value, payload, payload_len, flags, m_obj->serializer TSRMLS_CC) < 0) {
zval_ptr_dtor(&value);
if (EG(exception)) {
status = MEMC_RES_PAYLOAD_FAILURE;
php_memc_handle_error(i_obj, status TSRMLS_CC);
memcached_quit(m_obj->memc);
break;
}
status = MEMCACHED_SOME_ERRORS;
i_obj->rescode = MEMCACHED_SOME_ERRORS;
continue;
}
add_assoc_zval_ex(return_value, res_key, res_key_len+1, value);
if (cas_tokens) {
cas = memcached_result_cas(&result);
add_assoc_double_ex(cas_tokens, res_key, res_key_len+1, (double)cas);
}
}
memcached_result_free(&result);
if (EG(exception)) {
/* XXX: cas_tokens should only be set on success, currently we're destructive */
if (cas_tokens) {
zval_dtor(cas_tokens);
ZVAL_NULL(cas_tokens);
}
zval_dtor(return_value);
RETURN_FALSE;
}
}
/* }}} */
/* {{{ Memcached::getDelayed(array keys [, bool with_cas [, mixed callback ] ])
Sends a request for the given keys and returns immediately */
PHP_METHOD(Memcached, getDelayed)
{
php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
}
/* }}} */
/* {{{ Memcached::getDelayedByKey(string server_key, array keys [, bool with_cas [, mixed callback ] ])
Sends a request for the given keys from the server identified by the server key and returns immediately */
PHP_METHOD(Memcached, getDelayedByKey)
{
php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}
/* }}} */
/* {{{ -- php_memc_getDelayed_impl */
static void php_memc_getDelayed_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key)
{
zval *keys = NULL;
char *server_key = NULL;
int server_key_len = 0;
zend_bool with_cas = 0;
size_t num_keys = 0;
zval **entry = NULL;
const char **mkeys = NULL;
size_t *mkeys_len = NULL;
uint64_t orig_cas_flag;
zend_fcall_info fci = empty_fcall_info;
zend_fcall_info_cache fcc = empty_fcall_info_cache;
int i = 0;
memcached_return status = MEMCACHED_SUCCESS;
MEMC_METHOD_INIT_VARS;
if (by_key) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|bf!", &server_key,
&server_key_len, &keys, &with_cas, &fci, &fcc) == FAILURE) {
return;
}
} else {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/|bf!", &keys, &with_cas,
&fci, &fcc) == FAILURE) {
return;
}
}
MEMC_METHOD_FETCH_OBJECT;
i_obj->rescode = MEMCACHED_SUCCESS;
/*
* Create the array of keys for libmemcached. If none of the keys were valid
* (strings), set bad key result code and return.
*/
num_keys = zend_hash_num_elements(Z_ARRVAL_P(keys));
mkeys = safe_emalloc(num_keys, sizeof(*mkeys), 0);
mkeys_len = safe_emalloc(num_keys, sizeof(*mkeys_len), 0);
for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(keys));
zend_hash_get_current_data(Z_ARRVAL_P(keys), (void**)&entry) == SUCCESS;
zend_hash_move_forward(Z_ARRVAL_P(keys))) {
if (Z_TYPE_PP(entry) != IS_STRING) {
convert_to_string_ex(entry);
}
if (Z_TYPE_PP(entry) == IS_STRING && Z_STRLEN_PP(entry) > 0) {
mkeys[i] = Z_STRVAL_PP(entry);
mkeys_len[i] = Z_STRLEN_PP(entry);
i++;
}
}
if (i == 0) {
i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED;
efree(mkeys);
efree(mkeys_len);
zval_dtor(return_value);
RETURN_FALSE;
}
/*
* Enable CAS support, but only if it is currently disabled.
*/
if (with_cas) {
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);
}
}
/*
* Issue the request, but collect results only if the result callback is provided.
*/
status = memcached_mget_by_key(m_obj->memc, server_key, server_key_len, mkeys, mkeys_len, i);
/*
* Restore the CAS support flag, but only if we had to turn it on.
*/
if (with_cas && orig_cas_flag == 0) {
memcached_behavior_set(m_obj->memc, MEMCACHED_BEHAVIOR_SUPPORT_CAS, orig_cas_flag);
}
efree(mkeys);
efree(mkeys_len);
if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
zval_dtor(return_value);
RETURN_FALSE;
}
if (fci.size != 0) {
/*
* We have a result callback. Iterate through the result set and invoke the
* callback for each one.
*/
memcached_result_st result;
memcached_result_create(m_obj->memc, &result);
while ((memcached_fetch_result(m_obj->memc, &result, &status)) != NULL) {
if (php_memc_do_result_callback(getThis(), &fci, &fcc, &result TSRMLS_CC) < 0) {
status = MEMCACHED_FAILURE;
break;
}
}
memcached_result_free(&result);
/* we successfully retrieved all rows */
if (status == MEMCACHED_END) {
status = MEMCACHED_SUCCESS;
}
if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
RETURN_FALSE;
}
}
RETURN_TRUE;
}
/* }}} */
/* {{{ Memcached::fetch()
Returns the next result from a previous delayed request */
PHP_METHOD(Memcached, fetch)
{
char *res_key = NULL;
size_t res_key_len = 0;
char *payload = NULL;
size_t payload_len = 0;
zval *value;
uint32_t flags = 0;
uint64_t cas = 0;
memcached_result_st result;
memcached_return status = MEMCACHED_SUCCESS;
MEMC_METHOD_INIT_VARS;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
MEMC_METHOD_FETCH_OBJECT;
i_obj->rescode = MEMCACHED_SUCCESS;
memcached_result_create(m_obj->memc, &result);
if ((memcached_fetch_result(m_obj->memc, &result, &status)) == NULL) {
php_memc_handle_error(i_obj, status TSRMLS_CC);
memcached_result_free(&result);
RETURN_FALSE;
}
payload = memcached_result_value(&result);
payload_len = memcached_result_length(&result);
flags = memcached_result_flags(&result);
res_key = memcached_result_key_value(&result);
res_key_len = memcached_result_key_length(&result);
cas = memcached_result_cas(&result);
MAKE_STD_ZVAL(value);
if (php_memc_zval_from_payload(value, payload, payload_len, flags, m_obj->serializer TSRMLS_CC) < 0) {
memcached_result_free(&result);
zval_ptr_dtor(&value);
i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE;
RETURN_FALSE;
}
array_init(return_value);
add_assoc_stringl_ex(return_value, ZEND_STRS("key"), res_key, res_key_len, 1);
add_assoc_zval_ex(return_value, ZEND_STRS("value"), value);
if (cas != 0) {
/* XXX: also check against ULLONG_MAX or memc_behavior */
add_assoc_double_ex(return_value, ZEND_STRS("cas"), (double)cas);
}
memcached_result_free(&result);
}
/* }}} */
/* {{{ Memcached::fetchAll()
Returns all the results from a previous delayed request */
PHP_METHOD(Memcached, fetchAll)
{
char *res_key = NULL;
size_t res_key_len = 0;
char *payload = NULL;
size_t payload_len = 0;
zval *value, *entry;
uint32_t flags;
uint64_t cas = 0;
memcached_result_st result;
memcached_return status = MEMCACHED_SUCCESS;
MEMC_METHOD_INIT_VARS;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
MEMC_METHOD_FETCH_OBJECT;
i_obj->rescode = MEMCACHED_SUCCESS;
array_init(return_value);
memcached_result_create(m_obj->memc, &result);
while ((memcached_fetch_result(m_obj->memc, &result, &status)) != NULL) {
payload = memcached_result_value(&result);
payload_len = memcached_result_length(&result);
flags = memcached_result_flags(&result);
res_key = memcached_result_key_value(&result);
res_key_len = memcached_result_key_length(&result);
cas = memcached_result_cas(&result);
MAKE_STD_ZVAL(value);
if (php_memc_zval_from_payload(value, payload, payload_len, flags, m_obj->serializer TSRMLS_CC) < 0) {
memcached_result_free(&result);
zval_ptr_dtor(&value);
zval_dtor(return_value);
i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE;
RETURN_FALSE;
}
MAKE_STD_ZVAL(entry);
array_init(entry);
add_assoc_stringl_ex(entry, ZEND_STRS("key"), res_key, res_key_len, 1);
add_assoc_zval_ex(entry, ZEND_STRS("value"), value);
if (cas != 0) {
/* XXX: also check against ULLONG_MAX or memc_behavior */
add_assoc_double_ex(entry, ZEND_STRS("cas"), (double)cas);
}
add_next_index_zval(return_value, entry);
}
memcached_result_free(&result);
if (status != MEMCACHED_END && php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
zval_dtor(return_value);
RETURN_FALSE;
}
}
/* }}} */
/* {{{ Memcached::set(string key, mixed value [, int expiration ])
Sets the value for the given key */
PHP_METHOD(Memcached, set)
{
php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_SET, 0);
}
/* }}} */
/* {{{ Memcached::setByKey(string server_key, string key, mixed value [, int expiration ])
Sets the value for the given key on the server identified by the server key */
PHP_METHOD(Memcached, setByKey)
{
php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_SET, 1);
}
/* }}} */
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x01000002
/* {{{ Memcached::touch(string key, [, int expiration ])
Sets a new expiration for the given key */
PHP_METHOD(Memcached, touch)
{
php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_TOUCH, 0);
}
/* }}} */
/* {{{ Memcached::touchbyKey(string key, [, int expiration ])
Sets a new expiration for the given key */
PHP_METHOD(Memcached, touchByKey)
{
php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_TOUCH, 1);
}
/* }}} */
#endif
/* {{{ Memcached::setMulti(array items [, int expiration ])
Sets the keys/values specified in the items array */
PHP_METHOD(Memcached, setMulti)
{
php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
}
/* }}} */
/* {{{ Memcached::setMultiByKey(string server_key, array items [, int expiration ])
Sets the keys/values specified in the items array on the server identified by the given server key */
PHP_METHOD(Memcached, setMultiByKey)
{
php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}
/* }}} */
#define PHP_MEMC_FAILOVER_RETRY \
if (!by_key && retry < 2) { \
switch (i_obj->rescode) { \
case MEMCACHED_HOST_LOOKUP_FAILURE: \
case MEMCACHED_CONNECTION_FAILURE: \
case MEMCACHED_CONNECTION_BIND_FAILURE: \
case MEMCACHED_WRITE_FAILURE: \
case MEMCACHED_READ_FAILURE: \
case MEMCACHED_UNKNOWN_READ_FAILURE: \
case MEMCACHED_PROTOCOL_ERROR: \
case MEMCACHED_SERVER_ERROR: \
case MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE: \
case MEMCACHED_TIMEOUT: \
case MEMCACHED_FAIL_UNIX_SOCKET: \
case MEMCACHED_SERVER_MARKED_DEAD: \
if (memcached_server_count(m_obj->memc) > 0) { \
retry++; \
goto retry; \
} \
break; \
} \
} \
/* {{{ -- php_memc_setMulti_impl */
static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key)
{
zval *entries;
char *server_key = NULL;
int server_key_len = 0;
time_t expiration = 0;
zval **entry;
char *str_key;
uint str_key_len;
ulong num_key;
char *payload;
size_t payload_len;
uint32_t flags = 0;
uint32_t retry = 0;
memcached_return status;
char tmp_key[MEMCACHED_MAX_KEY];
MEMC_METHOD_INIT_VARS;
if (by_key) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa|l", &server_key,
&server_key_len, &entries, &expiration) == FAILURE) {
return;
}
} else {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &entries, &expiration) == FAILURE) {
return;
}
}
MEMC_METHOD_FETCH_OBJECT;
i_obj->rescode = MEMCACHED_SUCCESS;
for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(entries));
zend_hash_get_current_data(Z_ARRVAL_P(entries), (void**)&entry) == SUCCESS;
zend_hash_move_forward(Z_ARRVAL_P(entries))) {
int key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(entries), &str_key, &str_key_len, &num_key, 0, NULL);
if (key_type == HASH_KEY_IS_LONG) {
/* Array keys are unsigned, but php integers are signed.
* Keys must be converted to signed strings that match
* php integers. */
assert(sizeof(tmp_key) >= sizeof(ZEND_TOSTR(LONG_MIN)));
str_key_len = sprintf(tmp_key, "%ld", (long)num_key) + 1;
str_key = (char *)tmp_key;
} else if (key_type != HASH_KEY_IS_STRING) {
continue;
}
flags = 0;
if (m_obj->compression) {
flags |= MEMC_VAL_COMPRESSED;
}
payload = php_memc_zval_to_payload(*entry, &payload_len, &flags, m_obj->serializer, m_obj->compression_type TSRMLS_CC);
if (payload == NULL) {
i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE;
RETURN_FALSE;
}
retry:
if (!by_key) {
status = memcached_set(m_obj->memc, str_key, str_key_len-1, payload, payload_len, expiration, flags);
} else {
status = memcached_set_by_key(m_obj->memc, server_key, server_key_len, str_key, str_key_len-1, payload, payload_len, expiration, flags);
}
if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
PHP_MEMC_FAILOVER_RETRY
efree(payload);
RETURN_FALSE;
}
efree(payload);
}
RETURN_TRUE;
}
/* }}} */
/* {{{ Memcached::add(string key, mixed value [, int expiration ])
Sets the value for the given key, failing if the key already exists */
PHP_METHOD(Memcached, add)
{
php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_ADD, 0);
}
/* }}} */
/* {{{ Memcached::addByKey(string server_key, string key, mixed value [, int expiration ])
Sets the value for the given key on the server identified by the sever key, failing if the key already exists */
PHP_METHOD(Memcached, addByKey)
{
php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_ADD, 1);
}
/* }}} */
/* {{{ Memcached::append(string key, mixed value)
Appends the value to existing one for the key */
PHP_METHOD(Memcached, append)
{
php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_APPEND, 0);
}
/* }}} */
/* {{{ Memcached::appendByKey(string server_key, string key, mixed value)
Appends the value to existing one for the key on the server identified by the server key */
PHP_METHOD(Memcached, appendByKey)
{
php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_APPEND, 1);
}
/* }}} */
/* {{{ Memcached::prepend(string key, mixed value)
Prepends the value to existing one for the key */
PHP_METHOD(Memcached, prepend)
{
php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_PREPEND, 0);
}
/* }}} */
/* {{{ Memcached::prependByKey(string server_key, string key, mixed value)
Prepends the value to existing one for the key on the server identified by the server key */
PHP_METHOD(Memcached, prependByKey)
{
php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_PREPEND, 1);
}
/* }}} */
/* {{{ Memcached::replace(string key, mixed value [, int expiration ])
Replaces the value for the given key, failing if the key doesn't exist */
PHP_METHOD(Memcached, replace)
{
php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_REPLACE, 0);
}
/* }}} */
/* {{{ Memcached::replaceByKey(string server_key, string key, mixed value [, int expiration ])
Replaces the value for the given key on the server identified by the server key, failing if the key doesn't exist */
PHP_METHOD(Memcached, replaceByKey)
{
php_memc_store_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, MEMC_OP_REPLACE, 1);
}
/* }}} */
/* {{{ -- php_memc_store_impl */
static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool by_key)
{
char *key = NULL;
int key_len = 0;
char *server_key = NULL;
int server_key_len = 0;
char *s_value = NULL;
int s_value_len = 0;
zval s_zvalue;
zval *value;
time_t expiration = 0;
char *payload;
size_t payload_len;
uint32_t flags = 0;
uint32_t retry = 0;
memcached_return status;
MEMC_METHOD_INIT_VARS;
if (by_key) {
if (op == MEMC_OP_APPEND || op == MEMC_OP_PREPEND) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss", &server_key,
&server_key_len, &key, &key_len, &s_value, &s_value_len) == FAILURE) {
return;
}
INIT_ZVAL(s_zvalue);
value = &s_zvalue;
ZVAL_STRINGL(value, s_value, s_value_len, 0);
} else if (op == MEMC_OP_TOUCH) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", &server_key,
&server_key_len, &key, &key_len, &expiration) == FAILURE) {
return;
}
} else {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssz|l", &server_key,
&server_key_len, &key, &key_len, &value, &expiration) == FAILURE) {
return;
}
}
} else {
if (op == MEMC_OP_APPEND || op == MEMC_OP_PREPEND) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &key, &key_len,
&s_value, &s_value_len) == FAILURE) {
return;
}
INIT_ZVAL(s_zvalue);
value = &s_zvalue;
ZVAL_STRINGL(value, s_value, s_value_len, 0);
} else if (op == MEMC_OP_TOUCH) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &key,
&key_len, &expiration) == FAILURE) {
return;
}
} else {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &key, &key_len,
&value, &expiration) == FAILURE) {
return;
}
}
}
MEMC_METHOD_FETCH_OBJECT;
i_obj->rescode = MEMCACHED_SUCCESS;
if (key_len == 0) {
i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED;
RETURN_FALSE;
}
if (m_obj->compression) {
/*
* When compression is enabled, we cannot do appends/prepends because that would
* corrupt the compressed values. It is up to the user to fetch the value,
* append/prepend new data, and store it again.
*/
if (op == MEMC_OP_APPEND || op == MEMC_OP_PREPEND) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot append/prepend with compression turned on");
return;
}
flags |= MEMC_VAL_COMPRESSED;
}
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;
}
} else {
payload = php_memc_zval_to_payload(value, &payload_len, &flags, m_obj->serializer, m_obj->compression_type TSRMLS_CC);
if (payload == NULL) {
i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE;
RETURN_FALSE;
}
}
retry:
switch (op) {
case MEMC_OP_SET:
if (!server_key) {
status = memcached_set(m_obj->memc, key, key_len, payload, payload_len, expiration, flags);
} else {
status = memcached_set_by_key(m_obj->memc, server_key, server_key_len, key,
key_len, payload, payload_len, expiration, flags);
}
break;
case MEMC_OP_TOUCH:
if (!server_key) {
status = memcached_touch(m_obj->memc, key, key_len, expiration);
} else {
status = memcached_touch_by_key(m_obj->memc, server_key, server_key_len, key,
key_len, expiration);
}
break;
case MEMC_OP_ADD:
if (!server_key) {
status = memcached_add(m_obj->memc, key, key_len, payload, payload_len, expiration, flags);
} else {
status = memcached_add_by_key(m_obj->memc, server_key, server_key_len, key,
key_len, payload, payload_len, expiration, flags);
}
break;
case MEMC_OP_REPLACE:
if (!server_key) {
status = memcached_replace(m_obj->memc, key, key_len, payload, payload_len, expiration, flags);
} else {
status = memcached_replace_by_key(m_obj->memc, server_key, server_key_len, key,
key_len, payload, payload_len, expiration, flags);
}
break;
case MEMC_OP_APPEND:
if (!server_key) {
status = memcached_append(m_obj->memc, key, key_len, payload, payload_len, expiration, flags);
} else {
status = memcached_append_by_key(m_obj->memc, server_key, server_key_len, key,
key_len, payload, payload_len, expiration, flags);
}
break;
case MEMC_OP_PREPEND:
if (!server_key) {
status = memcached_prepend(m_obj->memc, key, key_len, payload, payload_len, expiration, flags);
} else {
status = memcached_prepend_by_key(m_obj->memc, server_key, server_key_len, key,
key_len, payload, payload_len, expiration, flags);
}
break;
default:
/* not reached */
assert(0);
break;
}
if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
PHP_MEMC_FAILOVER_RETRY
RETVAL_FALSE;
} else {
RETVAL_TRUE;
}
if (op != MEMC_OP_TOUCH) {
efree(payload);
}
}
/* }}} */
/* {{{ -- php_memc_cas_impl */
static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key)
{
double cas_d;
uint64_t cas;
char *key = NULL;
int key_len = 0;
char *server_key = NULL;
int server_key_len = 0;
zval *value;
time_t expiration = 0;
char *payload;
size_t payload_len;
uint32_t flags = 0;
memcached_return status;
MEMC_METHOD_INIT_VARS;
if (by_key) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dssz|l", &cas_d, &server_key,
&server_key_len, &key, &key_len, &value, &expiration) == FAILURE) {
return;
}
} else {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dsz|l", &cas_d, &key, &key_len,
&value, &expiration) == FAILURE) {
return;
}
}
MEMC_METHOD_FETCH_OBJECT;
i_obj->rescode = MEMCACHED_SUCCESS;
if (key_len == 0) {
i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED;
RETURN_FALSE;
}
DVAL_TO_LVAL(cas_d, cas);
if (m_obj->compression) {
flags |= MEMC_VAL_COMPRESSED;
}
payload = php_memc_zval_to_payload(value, &payload_len, &flags, m_obj->serializer, m_obj->compression_type TSRMLS_CC);
if (payload == NULL) {
i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE;
RETURN_FALSE;
}
if (by_key) {
status = memcached_cas_by_key(m_obj->memc, server_key, server_key_len, key, key_len, payload, payload_len, expiration, flags, cas);
} else {
status = memcached_cas(m_obj->memc, key, key_len, payload, payload_len, expiration, flags, cas);
}
efree(payload);
if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
RETURN_FALSE;
}
RETURN_TRUE;
}
/* }}} */
/* {{{ Memcached::cas(double cas_token, string key, mixed value [, int expiration ])
Sets the value for the given key, failing if the cas_token doesn't match the one in memcache */
PHP_METHOD(Memcached, cas)
{
php_memc_cas_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
}
/* }}} */
/* {{{ Memcached::casByKey(double cas_token, string server_key, string key, mixed value [, int expiration ])
Sets the value for the given key on the server identified by the server_key, failing if the cas_token doesn't match the one in memcache */
PHP_METHOD(Memcached, casByKey)
{
php_memc_cas_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}
/* }}} */
/* {{{ Memcached::delete(string key [, int time ])
Deletes the given key */
PHP_METHOD(Memcached, delete)
{
php_memc_delete_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
}
/* }}} */
/* {{{ Memcached::deleteMulti(array keys [, int time ])
Deletes the given keys */
PHP_METHOD(Memcached, deleteMulti)
{
php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
}
/* }}} */
/* {{{ Memcached::deleteByKey(string server_key, string key [, int time ])
Deletes the given key from the server identified by the server key */
PHP_METHOD(Memcached, deleteByKey)
{
php_memc_delete_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}
/* }}} */
/* {{{ Memcached::deleteMultiByKey(array keys [, int time ])
Deletes the given key from the server identified by the server key */
PHP_METHOD(Memcached, deleteMultiByKey)
{
php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}
/* }}} */
/* {{{ -- php_memc_delete_impl */
static void php_memc_delete_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key)
{
char *key = NULL;
int key_len = 0;
char *server_key = NULL;
int server_key_len = 0;
time_t expiration = 0;
memcached_return status;
MEMC_METHOD_INIT_VARS;
if (by_key) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", &server_key,
&server_key_len, &key, &key_len, &expiration) == FAILURE) {
return;
}
} else {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &key, &key_len,
&expiration) == FAILURE) {
return;
}
server_key = key;
server_key_len = key_len;
}
MEMC_METHOD_FETCH_OBJECT;
i_obj->rescode = MEMCACHED_SUCCESS;
if (key_len == 0) {
i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED;
RETURN_FALSE;
}
status = memcached_delete_by_key(m_obj->memc, server_key, server_key_len, key,
key_len, expiration);
if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
RETURN_FALSE;
}
RETURN_TRUE;
}
/* }}} */
/* {{{ -- php_memc_deleteMulti_impl */
static void php_memc_deleteMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key)
{
zval *entries;
char *server_key = NULL;
int server_key_len = 0;
time_t expiration = 0;
zval **entry;
memcached_return status;
MEMC_METHOD_INIT_VARS;
if (by_key) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa/|l", &server_key,
&server_key_len, &entries, &expiration) == FAILURE) {
return;
}
} else {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/|l", &entries, &expiration) == FAILURE) {
return;
}
}
MEMC_METHOD_FETCH_OBJECT;
i_obj->rescode = MEMCACHED_SUCCESS;
array_init(return_value);
for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(entries));
zend_hash_get_current_data(Z_ARRVAL_P(entries), (void**)&entry) == SUCCESS;
zend_hash_move_forward(Z_ARRVAL_P(entries))) {
if (Z_TYPE_PP(entry) != IS_STRING) {
convert_to_string_ex(entry);
}
if (Z_STRLEN_PP(entry) == 0) {
continue;
}
if (!by_key) {
server_key = Z_STRVAL_PP(entry);
server_key_len = Z_STRLEN_PP(entry);
}
status = memcached_delete_by_key(m_obj->memc, server_key, server_key_len, Z_STRVAL_PP(entry), Z_STRLEN_PP(entry), expiration);
if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
add_assoc_long(return_value, Z_STRVAL_PP(entry), status);
} else {
add_assoc_bool(return_value, Z_STRVAL_PP(entry), 1);
}
}
return;
}
/* }}} */
/* {{{ -- php_memc_incdec_impl */
static void php_memc_incdec_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key, zend_bool incr)
{
char *key, *server_key;
int key_len, server_key_len;
long offset = 1;
uint64_t value, initial = 0;
time_t expiry = 0;
memcached_return status;
int n_args = ZEND_NUM_ARGS();
uint32_t retry = 0;
MEMC_METHOD_INIT_VARS;
if (!by_key) {
if (zend_parse_parameters(n_args TSRMLS_CC, "s|lll", &key, &key_len, &offset, &initial, &expiry) == FAILURE) {
return;
}
} else {
if (zend_parse_parameters(n_args TSRMLS_CC, "ss|lll", &server_key, &server_key_len, &key, &key_len, &offset, &initial, &expiry) == FAILURE) {
return;
}
}
MEMC_METHOD_FETCH_OBJECT;
i_obj->rescode = MEMCACHED_SUCCESS;
if (key_len == 0) {
i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED;
RETURN_FALSE;
}
if (offset < 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "offset has to be > 0");
RETURN_FALSE;
}
retry:
if ((!by_key && n_args < 3) || (by_key && n_args < 4)) {
if (by_key) {
if (incr) {
status = memcached_increment_by_key(m_obj->memc, server_key, server_key_len, key, key_len, (unsigned int)offset, &value);
} else {
status = memcached_decrement_by_key(m_obj->memc, server_key, server_key_len, key, key_len, (unsigned int)offset, &value);
}
} else {
if (incr) {
status = memcached_increment(m_obj->memc, key, key_len, (unsigned int)offset, &value);
} else {
status = memcached_decrement(m_obj->memc, key, key_len, (unsigned int)offset, &value);
}
}
} else {
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);
} else {
status = memcached_decrement_with_initial_by_key(m_obj->memc, server_key, server_key_len, key, key_len, (unsigned int)offset, initial, expiry, &value);
}
} else {
if (incr) {
status = memcached_increment_with_initial(m_obj->memc, key, key_len, (unsigned int)offset, initial, expiry, &value);
} else {
status = memcached_decrement_with_initial(m_obj->memc, key, key_len, (unsigned int)offset, initial, expiry, &value);
}
}
}
if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
PHP_MEMC_FAILOVER_RETRY
RETURN_FALSE;
}
RETURN_LONG((long)value);
}
/* }}} */
/* {{{ Memcached::increment(string key [, int delta [, initial_value [, expiry time ] ] ])
Increments the value for the given key by delta, defaulting to 1 */
PHP_METHOD(Memcached, increment)
{
php_memc_incdec_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 1);
}
/* }}} */
/* {{{ Memcached::decrement(string key [, int delta [, initial_value [, expiry time ] ] ])
Decrements the value for the given key by delta, defaulting to 1 */
PHP_METHOD(Memcached, decrement)
{
php_memc_incdec_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0);
}
/* }}} */
/* {{{ Memcached::decrementByKey(string server_key, string key [, int delta [, initial_value [, expiry time ] ] ])
Decrements by server the value for the given key by delta, defaulting to 1 */
PHP_METHOD(Memcached, decrementByKey)
{
php_memc_incdec_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 0);
}
/* }}} */
/* {{{ Memcached::increment(string server_key, string key [, int delta [, initial_value [, expiry time ] ] ])
Increments by server the value for the given key by delta, defaulting to 1 */
PHP_METHOD(Memcached, incrementByKey)
{
php_memc_incdec_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 1);
}
/* }}} */
/* {{{ Memcached::addServer(string hostname, int port [, int weight ])
Adds the given memcache server to the list */
PHP_METHOD(Memcached, addServer)
{
char *host;
int host_len;
long port, weight = 0;
memcached_return status;
MEMC_METHOD_INIT_VARS;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|l", &host, &host_len,
&port, &weight) == FAILURE) {
return;
}
MEMC_METHOD_FETCH_OBJECT;
i_obj->rescode = MEMCACHED_SUCCESS;
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)) {
status = memcached_server_add_udp_with_weight(m_obj->memc, host, port, weight);
} else {
status = memcached_server_add_with_weight(m_obj->memc, host, port, weight);
}
if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
RETURN_FALSE;
}
RETURN_TRUE;
}
/* }}} */
/* {{{ Memcached::addServers(array servers)
Adds the given memcache servers to the server list */
PHP_METHOD(Memcached, addServers)
{
zval *servers;
zval **entry;
zval **z_host, **z_port, **z_weight = NULL;
uint32_t weight = 0;
int entry_size, i = 0;
memcached_server_st *list = NULL;
memcached_return status;
MEMC_METHOD_INIT_VARS;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &servers) == FAILURE) {
return;
}
MEMC_METHOD_FETCH_OBJECT;
i_obj->rescode = MEMCACHED_SUCCESS;
for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(servers)), i = 0;
zend_hash_get_current_data(Z_ARRVAL_P(servers), (void **)&entry) == SUCCESS;
zend_hash_move_forward(Z_ARRVAL_P(servers)), i++) {
if (Z_TYPE_PP(entry) != IS_ARRAY) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "server list entry #%d is not an array", i+1);
continue;
}
entry_size = zend_hash_num_elements(Z_ARRVAL_PP(entry));
if (entry_size > 1) {
zend_hash_internal_pointer_reset(Z_ARRVAL_PP(entry));
/* Check that we have a host */
if (zend_hash_get_current_data(Z_ARRVAL_PP(entry), (void **)&z_host) == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not get server host for entry #%d", i+1);
continue;
}
/* Check that we have a port */
if (zend_hash_move_forward(Z_ARRVAL_PP(entry)) == FAILURE ||
zend_hash_get_current_data(Z_ARRVAL_PP(entry), (void **)&z_port) == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not get server port for entry #%d", i+1);
continue;
}
convert_to_string_ex(z_host);
convert_to_long_ex(z_port);
weight = 0;
if (entry_size > 2) {
/* Try to get weight */
if (zend_hash_move_forward(Z_ARRVAL_PP(entry)) == FAILURE ||
zend_hash_get_current_data(Z_ARRVAL_PP(entry), (void **)&z_weight) == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not get server weight for entry #%d", i+1);
}
convert_to_long_ex(z_weight);
weight = Z_LVAL_PP(z_weight);
}
list = memcached_server_list_append_with_weight(list, Z_STRVAL_PP(z_host),
Z_LVAL_PP(z_port), weight, &status);
if (php_memc_handle_error(i_obj, status TSRMLS_CC) == 0) {
continue;
}
}
/* catch-all for all errors */
php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not add entry #%d to the server list", i+1);
}
status = memcached_server_push(m_obj->memc, list);
memcached_server_list_free(list);
if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
RETURN_FALSE;
}
RETURN_TRUE;
}
/* }}} */
/* {{{ Memcached::getServerList()
Returns the list of the memcache servers in use */
PHP_METHOD(Memcached, getServerList)
{
struct callbackContext context = {0};
memcached_server_function callbacks[1];
MEMC_METHOD_INIT_VARS;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
MEMC_METHOD_FETCH_OBJECT;
callbacks[0] = php_memc_do_serverlist_callback;
array_init(return_value);
context.return_value = return_value;
memcached_server_cursor(m_obj->memc, callbacks, &context, 1);
}
/* }}} */
/* {{{ Memcached::getServerByKey(string server_key)
Returns the server identified by the given server key */
PHP_METHOD(Memcached, getServerByKey)
{
char *server_key;
int server_key_len;
memcached_server_st *server;
memcached_return error;
MEMC_METHOD_INIT_VARS;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &server_key, &server_key_len) == FAILURE) {
return;
}
MEMC_METHOD_FETCH_OBJECT;
i_obj->rescode = MEMCACHED_SUCCESS;
if (server_key_len == 0) {
i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED;
RETURN_FALSE;
}
server = memcached_server_by_key(m_obj->memc, server_key, server_key_len, &error);
if (server == NULL) {
php_memc_handle_error(i_obj, error TSRMLS_CC);
RETURN_FALSE;
}
array_init(return_value);
add_assoc_string(return_value, "host", server->hostname, 1);
add_assoc_long(return_value, "port", server->port);
add_assoc_long(return_value, "weight", server->weight);
}
/* }}} */
/* {{{ Memcached::resetServerList()
Reset the server list in use */
PHP_METHOD(Memcached, resetServerList)
{
MEMC_METHOD_INIT_VARS;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
MEMC_METHOD_FETCH_OBJECT;
memcached_servers_reset(m_obj->memc);
RETURN_TRUE;
}
/* }}} */
/* {{{ Memcached::quit()
Close any open connections */
PHP_METHOD(Memcached, quit)
{
MEMC_METHOD_INIT_VARS;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
MEMC_METHOD_FETCH_OBJECT;
memcached_quit(m_obj->memc);
RETURN_TRUE;
}
/* }}} */
/* {{{ Memcached::getStats()
Returns statistics for the memcache servers */
PHP_METHOD(Memcached, getStats)
{
memcached_stat_st *stats;
memcached_return status;
struct callbackContext context = {0};
memcached_server_function callbacks[1];
MEMC_METHOD_INIT_VARS;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
MEMC_METHOD_FETCH_OBJECT;
if (memcached_server_count(m_obj->memc) == 0) {
array_init(return_value);
return;
}
stats = memcached_stat(m_obj->memc, NULL, &status);
php_memc_handle_error(i_obj, status TSRMLS_CC);
if (stats == NULL) {
RETURN_FALSE;
} else if (status != MEMCACHED_SUCCESS && status != MEMCACHED_SOME_ERRORS) {
memcached_stat_free(m_obj->memc, stats);
RETURN_FALSE;
}
array_init(return_value);
callbacks[0] = php_memc_do_stats_callback;
context.i = 0;
context.stats = stats;
context.return_value = return_value;
memcached_server_cursor(m_obj->memc, callbacks, &context, 1);
memcached_stat_free(m_obj->memc, stats);
}
/* }}} */
/* {{{ Memcached::getVersion()
Returns the version of each memcached server in the pool */
PHP_METHOD(Memcached, getVersion)
{
memcached_return status = MEMCACHED_SUCCESS;
struct callbackContext context = {0};
memcached_server_function callbacks[1];
MEMC_METHOD_INIT_VARS;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
MEMC_METHOD_FETCH_OBJECT;
array_init(return_value);
status = memcached_version(m_obj->memc);
if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
zval_dtor(return_value);
RETURN_FALSE;
}
callbacks[0] = php_memc_do_version_callback;
context.return_value = return_value;
memcached_server_cursor(m_obj->memc, callbacks, &context, 1);
}
/* }}} */
/* {{{ Memcached::getAllKeys()
Returns the keys stored on all the servers */
static memcached_return php_memc_dump_func_callback(const memcached_st *ptr __attribute__((unused)), \
const char *key, size_t key_length, void *context)
{
zval *ctx = (zval*) context;
add_next_index_string(ctx, (char*) key, 1);
return MEMCACHED_SUCCESS;
}
PHP_METHOD(Memcached, getAllKeys)
{
memcached_return rc;
memcached_dump_func callback[1];
MEMC_METHOD_INIT_VARS;
callback[0] = php_memc_dump_func_callback;
MEMC_METHOD_FETCH_OBJECT;
array_init(return_value);
rc = memcached_dump(m_obj->memc, callback, return_value, 1);
if (php_memc_handle_error(i_obj, rc TSRMLS_CC) < 0) {
zval_dtor(return_value);
RETURN_FALSE;
}
}
/* }}} */
/* {{{ Memcached::flush([ int delay ])
Flushes the data on all the servers */
static PHP_METHOD(Memcached, flush)
{
time_t delay = 0;
memcached_return status;
MEMC_METHOD_INIT_VARS;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &delay) == FAILURE) {
return;
}
MEMC_METHOD_FETCH_OBJECT;
i_obj->rescode = MEMCACHED_SUCCESS;
status = memcached_flush(m_obj->memc, delay);
if (php_memc_handle_error(i_obj, status TSRMLS_CC) < 0) {
RETURN_FALSE;
}
RETURN_TRUE;
}
/* }}} */
/* {{{ Memcached::getOption(int option)
Returns the value for the given option constant */
static PHP_METHOD(Memcached, getOption)
{
long option;
uint64_t result;
memcached_behavior flag;
MEMC_METHOD_INIT_VARS;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &option) == FAILURE) {
return;
}
MEMC_METHOD_FETCH_OBJECT;
switch (option) {
case MEMC_OPT_COMPRESSION_TYPE:
RETURN_LONG(m_obj->compression_type);
case MEMC_OPT_COMPRESSION:
RETURN_BOOL(m_obj->compression);
case MEMC_OPT_PREFIX_KEY:
{
memcached_return retval;
char *result;
result = memcached_callback_get(m_obj->memc, MEMCACHED_CALLBACK_PREFIX_KEY, &retval);
if (retval == MEMCACHED_SUCCESS && result) {
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x00050000
RETURN_STRINGL(result, strlen(result) - 1, 1);
#else
RETURN_STRING(result, 1);
#endif
} else {
RETURN_EMPTY_STRING();
}
}
case MEMC_OPT_SERIALIZER:
RETURN_LONG((long)m_obj->serializer);
break;
case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE:
case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE:
if (memcached_server_count(m_obj->memc) == 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "no servers defined");
return;
}
default:
/*
* Assume that it's a libmemcached behavior option.
*/
flag = (memcached_behavior) option;
result = memcached_behavior_get(m_obj->memc, flag);
RETURN_LONG((long)result);
}
}
/* }}} */
static int php_memc_set_option(php_memc_t *i_obj, long option, zval *value TSRMLS_DC)
{
memcached_behavior flag;
struct memc_obj *m_obj = i_obj->obj;
switch (option) {
case MEMC_OPT_COMPRESSION:
convert_to_long(value);
m_obj->compression = Z_LVAL_P(value) ? 1 : 0;
break;
case MEMC_OPT_COMPRESSION_TYPE:
convert_to_long(value);
if (Z_LVAL_P(value) == COMPRESSION_TYPE_FASTLZ ||
Z_LVAL_P(value) == COMPRESSION_TYPE_ZLIB) {
m_obj->compression_type = Z_LVAL_P(value);
} else {
/* invalid compression type */
return 0;
}
break;
case MEMC_OPT_PREFIX_KEY:
{
char *key;
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x00050000
char tmp[MEMCACHED_PREFIX_KEY_MAX_SIZE - 1];
#endif
convert_to_string(value);
if (Z_STRLEN_P(value) == 0) {
key = NULL;
} else {
/*
work-around a bug in libmemcached prior to version 0.50 that truncates the trailing
character of the key prefix, to avoid the issue we pad it with a '0'
*/
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x00050000
snprintf(tmp, sizeof(tmp), "%s0", Z_STRVAL_P(value));
key = tmp;
#else
key = Z_STRVAL_P(value);
#endif
}
if (memcached_callback_set(m_obj->memc, MEMCACHED_CALLBACK_PREFIX_KEY, key) == MEMCACHED_BAD_KEY_PROVIDED) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "bad key provided");
return 0;
}
break;
}
case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED:
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");
return 0;
}
/*
* This is necessary because libmemcached does not reset hash/distribution
* options on false case, like it does for MEMCACHED_BEHAVIOR_KETAMA
* (non-weighted) case. We have to clean up ourselves.
*/
if (!Z_LVAL_P(value)) {
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX > 0x00037000
(void)memcached_behavior_set_key_hash(m_obj->memc, MEMCACHED_HASH_DEFAULT);
(void)memcached_behavior_set_distribution_hash(m_obj->memc, MEMCACHED_HASH_DEFAULT);
(void)memcached_behavior_set_distribution(m_obj->memc, MEMCACHED_DISTRIBUTION_MODULA);
#else
m_obj->memc->hash = 0;
m_obj->memc->distribution = 0;
#endif
}
break;
case MEMC_OPT_SERIALIZER:
{
convert_to_long(value);
/* igbinary serializer */
#ifdef HAVE_MEMCACHED_IGBINARY
if (Z_LVAL_P(value) == SERIALIZER_IGBINARY) {
m_obj->serializer = SERIALIZER_IGBINARY;
} else
#endif
#ifdef HAVE_JSON_API
if (Z_LVAL_P(value) == SERIALIZER_JSON) {
m_obj->serializer = SERIALIZER_JSON;
} else if (Z_LVAL_P(value) == SERIALIZER_JSON_ARRAY) {
m_obj->serializer = SERIALIZER_JSON_ARRAY;
} else
#endif
/* php serializer */
if (Z_LVAL_P(value) == SERIALIZER_PHP) {
m_obj->serializer = SERIALIZER_PHP;
} else {
m_obj->serializer = SERIALIZER_PHP;
php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid serializer provided");
return 0;
}
break;
}
default:
/*
* Assume that it's a libmemcached behavior option.
*/
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");
return 0;
}
break;
}
return 1;
}
/* {{{ Memcached::setOptions(array options)
Sets the value for the given option constant */
static PHP_METHOD(Memcached, setOptions)
{
zval *options;
zend_bool ok = 1;
uint key_len;
char *key;
ulong key_index;
zval **value;
MEMC_METHOD_INIT_VARS;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &options) == FAILURE) {
return;
}
MEMC_METHOD_FETCH_OBJECT;
for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(options));
zend_hash_get_current_data(Z_ARRVAL_P(options), (void *) &value) == SUCCESS;
zend_hash_move_forward(Z_ARRVAL_P(options))) {
if (zend_hash_get_current_key_ex(Z_ARRVAL_P(options), &key, &key_len, &key_index, 0, NULL) == HASH_KEY_IS_LONG) {
zval copy = **value;
zval_copy_ctor(©);
INIT_PZVAL(©);
if (!php_memc_set_option(i_obj, (long) key_index, © TSRMLS_CC)) {
ok = 0;
}
zval_dtor(©);
} else {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid configuration option");
ok = 0;
}
}
RETURN_BOOL(ok);
}
/* }}} */
/* {{{ Memcached::setOption(int option, mixed value)
Sets the value for the given option constant */
static PHP_METHOD(Memcached, setOption)
{
long option;
zval *value;
MEMC_METHOD_INIT_VARS;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz/", &option, &value) == FAILURE) {
return;
}
MEMC_METHOD_FETCH_OBJECT;
RETURN_BOOL(php_memc_set_option(i_obj, option, value TSRMLS_CC));
}
/* }}} */
#ifdef HAVE_MEMCACHED_SASL
/* {{{ Memcached::setSaslAuthData(string user, string pass)
Sets sasl credentials */
static PHP_METHOD(Memcached, setSaslAuthData)
{
MEMC_METHOD_INIT_VARS;
char *user, *pass;
int user_len, pass_len, rc;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &user, &user_len, &pass, &pass_len) == FAILURE) {
return;
}
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;
}
RETURN_BOOL(memcached_set_sasl_auth_data(m_obj->memc, user, pass));
}
/* }}} */
#endif /* HAVE_MEMCACHED_SASL */
/* {{{ Memcached::getResultCode()
Returns the result code from the last operation */
static PHP_METHOD(Memcached, getResultCode)
{
MEMC_METHOD_INIT_VARS;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
MEMC_METHOD_FETCH_OBJECT;
RETURN_LONG(i_obj->rescode);
}
/* }}} */
/* {{{ Memcached::getResultMessage()
Returns the result message from the last operation */
static PHP_METHOD(Memcached, getResultMessage)
{
MEMC_METHOD_INIT_VARS;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
MEMC_METHOD_FETCH_OBJECT;
switch (i_obj->rescode) {
case MEMC_RES_PAYLOAD_FAILURE:
RETURN_STRING("PAYLOAD FAILURE", 1);
break;
case MEMCACHED_ERRNO:
case MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE:
case MEMCACHED_UNKNOWN_READ_FAILURE:
if (i_obj->memc_errno) {
char *str;
int str_len;
str_len = spprintf(&str, 0, "%s: %s", memcached_strerror(m_obj->memc, (memcached_return)i_obj->rescode),
strerror(i_obj->memc_errno));
RETURN_STRINGL(str, str_len, 0);
}
/* Fall through */
default:
RETURN_STRING(memcached_strerror(m_obj->memc, (memcached_return)i_obj->rescode), 1);
break;
}
}
/* }}} */
/* {{{ Memcached::isPersistent()
Returns the true if instance uses a persistent connection */
static PHP_METHOD(Memcached, isPersistent)
{
MEMC_METHOD_INIT_VARS;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
MEMC_METHOD_FETCH_OBJECT;
RETURN_BOOL(i_obj->is_persistent);
}
/* }}} */
/* {{{ Memcached::isPristine()
Returns the true if instance is recently created */
static PHP_METHOD(Memcached, isPristine)
{
MEMC_METHOD_INIT_VARS;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
MEMC_METHOD_FETCH_OBJECT;
RETURN_BOOL(i_obj->is_pristine);
}
/* }}} */
/****************************************
Internal support code
****************************************/
/* {{{ constructor/destructor */
static void php_memc_destroy(struct memc_obj *m_obj, zend_bool persistent TSRMLS_DC)
{
#if HAVE_MEMCACHED_SASL
if (m_obj->has_sasl_data) {
memcached_destroy_sasl_auth_data(m_obj->memc);
}
#endif
if (m_obj->memc) {
memcached_free(m_obj->memc);
}
pefree(m_obj, persistent);
}
static void php_memc_free_storage(php_memc_t *i_obj TSRMLS_DC)
{
zend_object_std_dtor(&i_obj->zo TSRMLS_CC);
if (i_obj->obj && !i_obj->is_persistent) {
php_memc_destroy(i_obj->obj, 0 TSRMLS_CC);
}
i_obj->obj = NULL;
efree(i_obj);
}
zend_object_value php_memc_new(zend_class_entry *ce TSRMLS_DC)
{
zend_object_value retval;
php_memc_t *i_obj;
zval *tmp;
i_obj = ecalloc(1, sizeof(*i_obj));
zend_object_std_init( &i_obj->zo, ce TSRMLS_CC );
#if PHP_VERSION_ID >= 50400
object_properties_init( (zend_object *) i_obj, ce);
#else
zend_hash_copy(i_obj->zo.properties, &ce->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
#endif
retval.handle = zend_objects_store_put(i_obj, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t)php_memc_free_storage, NULL TSRMLS_CC);
retval.handlers = &memcached_object_handlers;
return retval;
}
ZEND_RSRC_DTOR_FUNC(php_memc_dtor)
{
if (rsrc->ptr) {
struct memc_obj *m_obj = (struct memc_obj *)rsrc->ptr;
php_memc_destroy(m_obj, 1 TSRMLS_CC);
rsrc->ptr = NULL;
}
}
ZEND_RSRC_DTOR_FUNC(php_memc_sess_dtor)
{
if (rsrc->ptr) {
memcached_sess *memc_sess = (memcached_sess *)rsrc->ptr;
memcached_free(memc_sess->memc_sess);
pefree(rsrc->ptr, 1);
rsrc->ptr = NULL;
}
}
/* }}} */
/* {{{ internal API functions */
static memcached_return php_memc_do_serverlist_callback(const memcached_st *ptr, memcached_server_instance_st instance, void *in_context)
{
struct callbackContext* context = (struct callbackContext*) in_context;
zval *array;
MAKE_STD_ZVAL(array);
array_init(array);
add_assoc_string(array, "host", memcached_server_name(instance), 1);
add_assoc_long(array, "port", memcached_server_port(instance));
/*
* API does not allow to get at this field.
add_assoc_long(array, "weight", instance->weight);
*/
add_next_index_zval(context->return_value, array);
return MEMCACHED_SUCCESS;
}
static memcached_return php_memc_do_stats_callback(const memcached_st *ptr, memcached_server_instance_st instance, void *in_context)
{
char *hostport = NULL;
int hostport_len;
struct callbackContext* context = (struct callbackContext*) in_context;
zval *entry;
hostport_len = spprintf(&hostport, 0, "%s:%d", memcached_server_name(instance), memcached_server_port(instance));
MAKE_STD_ZVAL(entry);
array_init(entry);
add_assoc_long(entry, "pid", context->stats[context->i].pid);
add_assoc_long(entry, "uptime", context->stats[context->i].uptime);
add_assoc_long(entry, "threads", context->stats[context->i].threads);
add_assoc_long(entry, "time", context->stats[context->i].time);
add_assoc_long(entry, "pointer_size", context->stats[context->i].pointer_size);
add_assoc_long(entry, "rusage_user_seconds", context->stats[context->i].rusage_user_seconds);
add_assoc_long(entry, "rusage_user_microseconds", context->stats[context->i].rusage_user_microseconds);
add_assoc_long(entry, "rusage_system_seconds", context->stats[context->i].rusage_system_seconds);
add_assoc_long(entry, "rusage_system_microseconds", context->stats[context->i].rusage_system_microseconds);
add_assoc_long(entry, "curr_items", context->stats[context->i].curr_items);
add_assoc_long(entry, "total_items", context->stats[context->i].total_items);
add_assoc_long(entry, "limit_maxbytes", context->stats[context->i].limit_maxbytes);
add_assoc_long(entry, "curr_connections", context->stats[context->i].curr_connections);
add_assoc_long(entry, "total_connections", context->stats[context->i].total_connections);
add_assoc_long(entry, "connection_structures", context->stats[context->i].connection_structures);
add_assoc_long(entry, "bytes", context->stats[context->i].bytes);
add_assoc_long(entry, "cmd_get", context->stats[context->i].cmd_get);
add_assoc_long(entry, "cmd_set", context->stats[context->i].cmd_set);
add_assoc_long(entry, "get_hits", context->stats[context->i].get_hits);
add_assoc_long(entry, "get_misses", context->stats[context->i].get_misses);
add_assoc_long(entry, "evictions", context->stats[context->i].evictions);
add_assoc_long(entry, "bytes_read", context->stats[context->i].bytes_read);
add_assoc_long(entry, "bytes_written", context->stats[context->i].bytes_written);
add_assoc_stringl(entry, "version", context->stats[context->i].version, strlen(context->stats[context->i].version), 1);
add_assoc_zval_ex(context->return_value, hostport, hostport_len+1, entry);
efree(hostport);
/* Increment the server count in our context structure. Failure to do so will cause only the stats for the last server to get displayed. */
context->i++;
return MEMCACHED_SUCCESS;
}
static memcached_return php_memc_do_version_callback(const memcached_st *ptr, memcached_server_instance_st instance, void *in_context)
{
char *hostport = NULL;
char version[16];
int hostport_len, version_len;
struct callbackContext* context = (struct callbackContext*) in_context;
hostport_len = spprintf(&hostport, 0, "%s:%d", memcached_server_name(instance), memcached_server_port(instance));
version_len = snprintf(version, sizeof(version), "%d.%d.%d",
memcached_server_major_version(instance),
memcached_server_minor_version(instance),
memcached_server_micro_version(instance));
add_assoc_stringl_ex(context->return_value, hostport, hostport_len+1, version, version_len, 1);
efree(hostport);
return MEMCACHED_SUCCESS;
}
static int php_memc_handle_error(php_memc_t *i_obj, memcached_return status TSRMLS_DC)
{
int result = 0;
switch (status) {
case MEMCACHED_SUCCESS:
case MEMCACHED_STORED:
case MEMCACHED_DELETED:
case MEMCACHED_STAT:
result = 0;
i_obj->memc_errno = 0;
break;
case MEMCACHED_END:
case MEMCACHED_BUFFERED:
i_obj->rescode = status;
i_obj->memc_errno = 0;
result = 0;
break;
case MEMCACHED_SOME_ERRORS:
i_obj->rescode = status;
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x00049000
i_obj->memc_errno = memcached_last_error_errno(i_obj->obj->memc);
#else
i_obj->memc_errno = i_obj->obj->memc->cached_errno; /* Hnngghgh! */
#endif
result = 0;
break;
default:
i_obj->rescode = status;
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x00049000
i_obj->memc_errno = memcached_last_error_errno(i_obj->obj->memc);
#else
i_obj->memc_errno = i_obj->obj->memc->cached_errno; /* Hnngghgh! */
#endif
result = -1;
break;
}
return result;
}
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)
{
char *payload;
char *p;
int l;
zend_bool buf_used = 0;
smart_str buf = {0};
char tmp[40] = {0};
switch (Z_TYPE_P(value)) {
case IS_STRING:
p = Z_STRVAL_P(value);
l = Z_STRLEN_P(value);
MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_STRING);
break;
case IS_LONG:
l = sprintf(tmp, "%ld", Z_LVAL_P(value));
p = tmp;
MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_LONG);
break;
case IS_DOUBLE:
php_memcached_g_fmt(tmp, Z_DVAL_P(value));
p = tmp;
l = strlen(tmp);
MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_DOUBLE);
break;
case IS_BOOL:
if (Z_BVAL_P(value)) {
l = 1;
tmp[0] = '1';
tmp[1] = '\0';
} else {
l = 0;
tmp[0] = '\0';
}
p = tmp;
MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_BOOL);
break;
default:
switch (serializer) {
#ifdef HAVE_MEMCACHED_IGBINARY
case SERIALIZER_IGBINARY:
if (igbinary_serialize((uint8_t **) &buf.c, &buf.len, value TSRMLS_CC) != 0) {
smart_str_free(&buf);
return NULL;
}
p = buf.c;
l = buf.len;
buf_used = 1;
MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_IGBINARY);
break;
#endif
#ifdef HAVE_JSON_API
case SERIALIZER_JSON:
case SERIALIZER_JSON_ARRAY:
{
#if HAVE_JSON_API_5_2
php_json_encode(&buf, value TSRMLS_CC);
#elif HAVE_JSON_API_5_3
php_json_encode(&buf, value, 0 TSRMLS_CC); /* options */
#endif
buf.c[buf.len] = 0;
p = buf.c;
l = buf.len;
buf_used = 1;
MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_JSON);
break;
}
#endif
default:
{
php_serialize_data_t var_hash;
PHP_VAR_SERIALIZE_INIT(var_hash);
php_var_serialize(&buf, &value, &var_hash TSRMLS_CC);
PHP_VAR_SERIALIZE_DESTROY(var_hash);
if (!buf.c) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not serialize value");
smart_str_free(&buf);
return NULL;
}
p = buf.c;
l = buf.len;
buf_used = 1;
MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_SERIALIZED);
break;
}
}
break;
}
/* Check for exceptions caused by serializers */
if (EG(exception) && buf_used) {
smart_str_free(&buf);
return NULL;
}
/* turn off compression for values below the threshold */
if ((*flags & MEMC_VAL_COMPRESSED) && l < MEMC_G(compression_threshold)) {
*flags &= ~MEMC_VAL_COMPRESSED;
}
if (*flags & MEMC_VAL_COMPRESSED) {
/* status */
zend_bool compress_status = 0;
/* Additional 5% for the data */
unsigned long payload_comp_len = (unsigned long)((l * 1.05) + 1);
char *payload_comp = emalloc(payload_comp_len + sizeof(uint32_t));
payload = payload_comp;
memcpy(payload_comp, &l, sizeof(uint32_t));
payload_comp += sizeof(uint32_t);
if (compression_type == COMPRESSION_TYPE_FASTLZ) {
compress_status = ((payload_comp_len = fastlz_compress(p, l, payload_comp)) > 0);
*flags |= MEMC_VAL_COMPRESSION_FASTLZ;
} else if (compression_type == COMPRESSION_TYPE_ZLIB) {
compress_status = (compress((Bytef *)payload_comp, &payload_comp_len, (Bytef *)p, l) == Z_OK);
*flags |= MEMC_VAL_COMPRESSION_ZLIB;
}
if (!compress_status) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not compress value");
efree(payload);
if (buf_used) {
smart_str_free(&buf);
}
return NULL;
}
/* Check that we are above ratio */
if (l > (payload_comp_len * MEMC_G(compression_factor))) {
*payload_len = payload_comp_len + sizeof(uint32_t);
payload[*payload_len] = 0;
} else {
/* Store plain value */
*flags &= ~MEMC_VAL_COMPRESSED;
*payload_len = l;
memcpy(payload, p, l);
payload[l] = 0;
}
} else {
*payload_len = l;
payload = estrndup(p, l);
}
if (buf_used) {
smart_str_free(&buf);
}
return payload;
}
/* 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)
{
/*
A NULL payload is completely valid if length is 0, it is simply empty.
*/
zend_bool payload_emalloc = 0;
char *buffer = NULL;
if (payload == NULL && payload_len > 0) {
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) {
if (MEMC_VAL_GET_TYPE(flags) == MEMC_VAL_IS_BOOL) {
ZVAL_FALSE(value);
} else {
ZVAL_EMPTY_STRING(value);
}
return 0;
}
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);
return -1;
}
payload = buffer;
payload_len = length;
payload_emalloc = 1;
}
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);
payload_emalloc = 0;
} else {
ZVAL_STRINGL(value, payload, payload_len, 1);
}
break;
case MEMC_VAL_IS_LONG:
{
long lval = strtol(payload, NULL, 10);
ZVAL_LONG(value, lval);
break;
}
case MEMC_VAL_IS_DOUBLE:
if (payload_len == 8 && memcmp(payload, "Infinity", 8) == 0) {
ZVAL_DOUBLE(value, php_get_inf());
} else if (payload_len == 9 && memcmp(payload, "-Infinity", 9) == 0) {
ZVAL_DOUBLE(value, -php_get_inf());
} else if (payload_len == 3 && memcmp(payload, "NaN", 3) == 0) {
ZVAL_DOUBLE(value, php_get_nan());
} else {
ZVAL_DOUBLE(value, zend_strtod(payload, NULL));
}
break;
case MEMC_VAL_IS_BOOL:
ZVAL_BOOL(value, payload_len > 0 && payload[0] == '1');
break;
case MEMC_VAL_IS_SERIALIZED:
{
const char *payload_tmp = payload;
php_unserialize_data_t var_hash;
PHP_VAR_UNSERIALIZE_INIT(var_hash);
if (!php_var_unserialize(&value, (const unsigned char **)&payload_tmp, (const unsigned char *)payload_tmp + payload_len, &var_hash TSRMLS_CC)) {
ZVAL_FALSE(value);
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not unserialize value");
goto my_error;
}
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
break;
}
case MEMC_VAL_IS_IGBINARY:
#ifdef HAVE_MEMCACHED_IGBINARY
if (igbinary_unserialize((uint8_t *)payload, 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
php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not unserialize value, no igbinary support");
goto my_error;
#endif
break;
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);
# elif HAVE_JSON_API_5_3
php_json_decode(value, payload, payload_len, (serializer == SERIALIZER_JSON_ARRAY), JSON_PARSER_DEFAULT_DEPTH TSRMLS_CC);
# endif
#else
php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not unserialize value, no json support");
goto my_error;
#endif
break;
default:
php_error_docref(NULL TSRMLS_CC, E_WARNING, "unknown payload type");
goto my_error;
}
if (payload_emalloc) {
efree(payload);
}
return 0;
my_error:
if (payload_emalloc) {
efree(payload);
}
return -1;
}
static void php_memc_init_globals(zend_php_memcached_globals *php_memcached_globals_p TSRMLS_DC)
{
#ifdef HAVE_MEMCACHED_SESSION
MEMC_G(sess_locking_enabled) = 1;
MEMC_G(sess_binary_enabled) = 1;
MEMC_G(sess_prefix) = NULL;
MEMC_G(sess_lock_wait) = 0;
MEMC_G(sess_locked) = 0;
MEMC_G(sess_lock_key) = NULL;
MEMC_G(sess_lock_key_len) = 0;
#endif
MEMC_G(serializer_name) = NULL;
MEMC_G(serializer) = SERIALIZER_DEFAULT;
MEMC_G(compression_type) = NULL;
MEMC_G(compression_type_real) = COMPRESSION_TYPE_FASTLZ;
MEMC_G(compression_factor) = 1.30;
#if HAVE_MEMCACHED_SASL
MEMC_G(use_sasl) = 0;
#endif
}
static void php_memc_destroy_globals(zend_php_memcached_globals *php_memcached_globals_p TSRMLS_DC)
{
}
PHP_MEMCACHED_API
zend_class_entry *php_memc_get_ce(void)
{
return memcached_ce;
}
PHP_MEMCACHED_API
zend_class_entry *php_memc_get_exception(void)
{
return memcached_exception_ce;
}
PHP_MEMCACHED_API
zend_class_entry *php_memc_get_exception_base(int root TSRMLS_DC)
{
#if HAVE_SPL
if (!root) {
if (!spl_ce_RuntimeException) {
zend_class_entry **pce;
if (zend_hash_find(CG(class_table), "runtimeexception",
sizeof("RuntimeException"), (void **) &pce) == SUCCESS) {
spl_ce_RuntimeException = *pce;
return *pce;
}
} else {
return spl_ce_RuntimeException;
}
}
#endif
#if (PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION < 2)
return zend_exception_get_default();
#else
return zend_exception_get_default(TSRMLS_C);
#endif
}
static memcached_return php_memc_do_cache_callback(zval *zmemc_obj, zend_fcall_info *fci,
zend_fcall_info_cache *fcc, char *key,
size_t key_len, zval *value TSRMLS_DC)
{
char *payload = NULL;
size_t payload_len = 0;
zval **params[4];
zval *retval;
zval *z_key;
zval *z_expiration;
uint32_t flags = 0;
memcached_return rc;
php_memc_t* i_obj;
memcached_return status = MEMCACHED_SUCCESS;
int result;
MAKE_STD_ZVAL(z_key);
MAKE_STD_ZVAL(z_expiration);
ZVAL_STRINGL(z_key, key, key_len, 1);
ZVAL_NULL(value);
ZVAL_LONG(z_expiration, 0);
params[0] = &zmemc_obj;
params[1] = &z_key;
params[2] = &value;
params[3] = &z_expiration;
fci->retval_ptr_ptr = &retval;
fci->params = params;
fci->param_count = sizeof(params) / sizeof(params[0]);
result = zend_call_function(fci, fcc TSRMLS_CC);
if (result == SUCCESS && retval) {
i_obj = (php_memc_t *) zend_object_store_get_object(zmemc_obj TSRMLS_CC);
struct memc_obj *m_obj = i_obj->obj;
if (zend_is_true(retval)) {
time_t expiration;
if (Z_TYPE_P(z_expiration) != IS_LONG) {
convert_to_long(z_expiration);
}
expiration = Z_LVAL_P(z_expiration);
payload = php_memc_zval_to_payload(value, &payload_len, &flags, m_obj->serializer, m_obj->compression_type TSRMLS_CC);
if (payload == NULL) {
status = (memcached_return)MEMC_RES_PAYLOAD_FAILURE;
} else {
rc = memcached_set(m_obj->memc, key, key_len, payload, payload_len, expiration, flags);
if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED) {
status = rc;
}
efree(payload);
}
} else {
status = MEMCACHED_NOTFOUND;
zval_dtor(value);
ZVAL_NULL(value);
}
} else {
if (result == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not invoke cache callback");
}
status = MEMCACHED_FAILURE;
zval_dtor(value);
ZVAL_NULL(value);
}
if (retval) {
zval_ptr_dtor(&retval);
}
zval_ptr_dtor(&z_key);
zval_ptr_dtor(&z_expiration);
return status;
}
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;
size_t res_key_len = 0;
char *payload = NULL;
size_t payload_len = 0;
zval *value, *retval = NULL;
uint64_t cas = 0;
zval **params[2];
zval *z_result;
uint32_t flags = 0;
int rc = 0;
php_memc_t *i_obj = NULL;
params[0] = &zmemc_obj;
params[1] = &z_result;
fci->retval_ptr_ptr = &retval;
fci->params = params;
fci->param_count = 2;
payload = memcached_result_value(result);
payload_len = memcached_result_length(result);
flags = memcached_result_flags(result);
res_key = memcached_result_key_value(result);
res_key_len = memcached_result_key_length(result);
cas = memcached_result_cas(result);
MAKE_STD_ZVAL(value);
i_obj = (php_memc_t *) zend_object_store_get_object(zmemc_obj TSRMLS_CC);
if (php_memc_zval_from_payload(value, payload, payload_len, flags, i_obj->obj->serializer TSRMLS_CC) < 0) {
zval_ptr_dtor(&value);
i_obj->rescode = MEMC_RES_PAYLOAD_FAILURE;
return -1;
}
MAKE_STD_ZVAL(z_result);
array_init(z_result);
add_assoc_stringl_ex(z_result, ZEND_STRS("key"), res_key, res_key_len, 1);
add_assoc_zval_ex(z_result, ZEND_STRS("value"), value);
if (cas != 0) {
add_assoc_double_ex(z_result, ZEND_STRS("cas"), (double)cas);
}
if (zend_call_function(fci, fcc TSRMLS_CC) == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not invoke result callback");
rc = -1;
}
if (retval) {
zval_ptr_dtor(&retval);
}
zval_ptr_dtor(&z_result);
return rc;
}
/* }}} */
/* {{{ 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(1, cas_token)
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(1, cas_token)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_getMulti, 0, 0, 1)
ZEND_ARG_ARRAY_INFO(0, keys, 0)
ZEND_ARG_INFO(1, cas_tokens)
ZEND_ARG_INFO(0, 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(1, cas_tokens)
ZEND_ARG_INFO(0, flags)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_getDelayed, 0, 0, 1)
ZEND_ARG_ARRAY_INFO(0, keys, 0)
ZEND_ARG_INFO(0, with_cas)
ZEND_ARG_INFO(0, value_cb)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_getDelayedByKey, 0, 0, 2)
ZEND_ARG_INFO(0, server_key)
ZEND_ARG_ARRAY_INFO(0, keys, 0)
ZEND_ARG_INFO(0, with_cas)
ZEND_ARG_INFO(0, value_cb)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_fetch, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_fetchAll, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_set, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, expiration)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_setByKey, 0, 0, 3)
ZEND_ARG_INFO(0, server_key)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, expiration)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_touch, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, expiration)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_touchByKey, 0, 0, 3)
ZEND_ARG_INFO(0, server_key)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, expiration)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_setMulti, 0, 0, 1)
ZEND_ARG_ARRAY_INFO(0, items, 0)
ZEND_ARG_INFO(0, expiration)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_setMultiByKey, 0, 0, 2)
ZEND_ARG_INFO(0, server_key)
ZEND_ARG_ARRAY_INFO(0, items, 0)
ZEND_ARG_INFO(0, expiration)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_add, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, expiration)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_addByKey, 0, 0, 3)
ZEND_ARG_INFO(0, server_key)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, expiration)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_replace, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, expiration)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_replaceByKey, 0, 0, 3)
ZEND_ARG_INFO(0, server_key)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, expiration)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_append, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, expiration)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_appendByKey, 0, 0, 3)
ZEND_ARG_INFO(0, server_key)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, expiration)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_prepend, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, expiration)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_prependByKey, 0, 0, 3)
ZEND_ARG_INFO(0, server_key)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, expiration)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_cas, 0, 0, 3)
ZEND_ARG_INFO(0, cas_token)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, expiration)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_casByKey, 0, 0, 4)
ZEND_ARG_INFO(0, cas_token)
ZEND_ARG_INFO(0, server_key)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, expiration)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_delete, 0, 0, 1)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, time)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_deleteMulti, 0, 0, 1)
ZEND_ARG_INFO(0, keys)
ZEND_ARG_INFO(0, time)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_deleteByKey, 0, 0, 2)
ZEND_ARG_INFO(0, server_key)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, time)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_deleteMultiByKey, 0, 0, 2)
ZEND_ARG_INFO(0, server_key)
ZEND_ARG_INFO(0, keys)
ZEND_ARG_INFO(0, time)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_increment, 0, 0, 1)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, offset)
ZEND_ARG_INFO(0, initial_value)
ZEND_ARG_INFO(0, expiry)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_decrement, 0, 0, 1)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, offset)
ZEND_ARG_INFO(0, initial_value)
ZEND_ARG_INFO(0, expiry)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_incrementByKey, 0, 0, 2)
ZEND_ARG_INFO(0, server_key)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, offset)
ZEND_ARG_INFO(0, initial_value)
ZEND_ARG_INFO(0, expiry)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_decrementByKey, 0, 0, 2)
ZEND_ARG_INFO(0, server_key)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, offset)
ZEND_ARG_INFO(0, initial_value)
ZEND_ARG_INFO(0, expiry)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_flush, 0, 0, 0)
ZEND_ARG_INFO(0, delay)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_addServer, 0, 0, 2)
ZEND_ARG_INFO(0, host)
ZEND_ARG_INFO(0, port)
ZEND_ARG_INFO(0, weight)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_addServers, 0)
ZEND_ARG_ARRAY_INFO(0, servers, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_getServerList, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_resetServerList, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_quit, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_getServerByKey, 0)
ZEND_ARG_INFO(0, server_key)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_getOption, 0)
ZEND_ARG_INFO(0, option)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_setSaslAuthData, 0)
ZEND_ARG_INFO(0, username)
ZEND_ARG_INFO(0, password)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_setOption, 0)
ZEND_ARG_INFO(0, option)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_setOptions, 0)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_getStats, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_getVersion, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_isPersistent, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_isPristine, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_getAllKeys, 0)
ZEND_END_ARG_INFO()
/* }}} */
/* {{{ memcached_class_methods */
#define MEMC_ME(name, args) PHP_ME(Memcached, name, args, ZEND_ACC_PUBLIC)
static zend_function_entry memcached_class_methods[] = {
MEMC_ME(__construct, arginfo___construct)
MEMC_ME(getResultCode, arginfo_getResultCode)
MEMC_ME(getResultMessage, arginfo_getResultMessage)
MEMC_ME(get, arginfo_get)
MEMC_ME(getByKey, arginfo_getByKey)
MEMC_ME(getMulti, arginfo_getMulti)
MEMC_ME(getMultiByKey, arginfo_getMultiByKey)
MEMC_ME(getDelayed, arginfo_getDelayed)
MEMC_ME(getDelayedByKey, arginfo_getDelayedByKey)
MEMC_ME(fetch, arginfo_fetch)
MEMC_ME(fetchAll, arginfo_fetchAll)
MEMC_ME(set, arginfo_set)
MEMC_ME(setByKey, arginfo_setByKey)
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x01000002
MEMC_ME(touch, arginfo_touch)
MEMC_ME(touchByKey, arginfo_touchByKey)
#endif
MEMC_ME(setMulti, arginfo_setMulti)
MEMC_ME(setMultiByKey, arginfo_setMultiByKey)
MEMC_ME(cas, arginfo_cas)
MEMC_ME(casByKey, arginfo_casByKey)
MEMC_ME(add, arginfo_add)
MEMC_ME(addByKey, arginfo_addByKey)
MEMC_ME(append, arginfo_append)
MEMC_ME(appendByKey, arginfo_appendByKey)
MEMC_ME(prepend, arginfo_prepend)
MEMC_ME(prependByKey, arginfo_prependByKey)
MEMC_ME(replace, arginfo_replace)
MEMC_ME(replaceByKey, arginfo_replaceByKey)
MEMC_ME(delete, arginfo_delete)
MEMC_ME(deleteMulti, arginfo_deleteMulti)
MEMC_ME(deleteByKey, arginfo_deleteByKey)
MEMC_ME(deleteMultiByKey, arginfo_deleteMultiByKey)
MEMC_ME(increment, arginfo_increment)
MEMC_ME(decrement, arginfo_decrement)
MEMC_ME(incrementByKey, arginfo_incrementByKey)
MEMC_ME(decrementByKey, arginfo_decrementByKey)
MEMC_ME(addServer, arginfo_addServer)
MEMC_ME(addServers, arginfo_addServers)
MEMC_ME(getServerList, arginfo_getServerList)
MEMC_ME(getServerByKey, arginfo_getServerByKey)
MEMC_ME(resetServerList, arginfo_resetServerList)
MEMC_ME(quit, arginfo_quit)
MEMC_ME(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)
#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
/* }}} */
/* {{{ memcached_module_entry
*/
#if ZEND_MODULE_API_NO >= 20050922
static const zend_module_dep memcached_deps[] = {
#ifdef HAVE_MEMCACHED_SESSION
ZEND_MOD_REQUIRED("session")
#endif
#ifdef HAVE_MEMCACHED_IGBINARY
ZEND_MOD_REQUIRED("igbinary")
#endif
#ifdef HAVE_SPL
ZEND_MOD_REQUIRED("spl")
#endif
{NULL, NULL, NULL}
};
#endif
zend_module_entry memcached_module_entry = {
#if ZEND_MODULE_API_NO >= 20050922
STANDARD_MODULE_HEADER_EX, NULL,
(zend_module_dep*)memcached_deps,
#else
STANDARD_MODULE_HEADER,
#endif
"memcached",
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
};
/* }}} */
/* {{{ php_memc_register_constants */
static void php_memc_register_constants(INIT_FUNC_ARGS)
{
#define REGISTER_MEMC_CLASS_CONST_LONG(name, value) zend_declare_class_constant_long(php_memc_get_ce() , ZEND_STRS( #name ) - 1, value TSRMLS_CC)
#define REGISTER_MEMC_CLASS_CONST_BOOL(name, value) zend_declare_class_constant_bool(php_memc_get_ce() , ZEND_STRS( #name ) - 1, value TSRMLS_CC)
#define REGISTER_MEMC_CLASS_CONST_NULL(name) zend_declare_class_constant_null(php_memc_get_ce() , ZEND_STRS( #name ) - 1 TSRMLS_CC)
/*
* Class options
*/
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_PREFIX_KEY, MEMC_OPT_PREFIX_KEY);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_SERIALIZER, MEMC_OPT_SERIALIZER);
/*
* Indicate whether igbinary serializer is available
*/
#ifdef HAVE_MEMCACHED_IGBINARY
REGISTER_MEMC_CLASS_CONST_LONG(HAVE_IGBINARY, 1);
#else
REGISTER_MEMC_CLASS_CONST_LONG(HAVE_IGBINARY, 0);
#endif
/*
* Indicate whether json serializer is available
*/
#ifdef HAVE_JSON_API
REGISTER_MEMC_CLASS_CONST_LONG(HAVE_JSON, 1);
#else
REGISTER_MEMC_CLASS_CONST_LONG(HAVE_JSON, 0);
#endif
#ifdef HAVE_MEMCACHED_SESSION
REGISTER_MEMC_CLASS_CONST_LONG(HAVE_SESSION, 1);
#else
REGISTER_MEMC_CLASS_CONST_LONG(HAVE_SESSION, 0);
#endif
#ifdef HAVE_MEMCACHED_SASL
REGISTER_MEMC_CLASS_CONST_LONG(HAVE_SASL, 1);
#else
REGISTER_MEMC_CLASS_CONST_LONG(HAVE_SASL, 0);
#endif
/*
* libmemcached behavior options
*/
REGISTER_MEMC_CLASS_CONST_LONG(OPT_HASH, MEMCACHED_BEHAVIOR_HASH);
REGISTER_MEMC_CLASS_CONST_LONG(HASH_DEFAULT, MEMCACHED_HASH_DEFAULT);
REGISTER_MEMC_CLASS_CONST_LONG(HASH_MD5, MEMCACHED_HASH_MD5);
REGISTER_MEMC_CLASS_CONST_LONG(HASH_CRC, MEMCACHED_HASH_CRC);
REGISTER_MEMC_CLASS_CONST_LONG(HASH_FNV1_64, MEMCACHED_HASH_FNV1_64);
REGISTER_MEMC_CLASS_CONST_LONG(HASH_FNV1A_64, MEMCACHED_HASH_FNV1A_64);
REGISTER_MEMC_CLASS_CONST_LONG(HASH_FNV1_32, MEMCACHED_HASH_FNV1_32);
REGISTER_MEMC_CLASS_CONST_LONG(HASH_FNV1A_32, MEMCACHED_HASH_FNV1A_32);
REGISTER_MEMC_CLASS_CONST_LONG(HASH_HSIEH, MEMCACHED_HASH_HSIEH);
REGISTER_MEMC_CLASS_CONST_LONG(HASH_MURMUR, MEMCACHED_HASH_MURMUR);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_DISTRIBUTION, MEMCACHED_BEHAVIOR_DISTRIBUTION);
REGISTER_MEMC_CLASS_CONST_LONG(DISTRIBUTION_MODULA, MEMCACHED_DISTRIBUTION_MODULA);
REGISTER_MEMC_CLASS_CONST_LONG(DISTRIBUTION_CONSISTENT, MEMCACHED_DISTRIBUTION_CONSISTENT);
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x00049000
REGISTER_MEMC_CLASS_CONST_LONG(DISTRIBUTION_VIRTUAL_BUCKET, MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET);
#endif
REGISTER_MEMC_CLASS_CONST_LONG(OPT_LIBKETAMA_COMPATIBLE, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_LIBKETAMA_HASH, MEMCACHED_BEHAVIOR_KETAMA_HASH);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_TCP_KEEPALIVE, MEMCACHED_BEHAVIOR_TCP_KEEPALIVE);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_BUFFER_WRITES, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_BINARY_PROTOCOL, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_NO_BLOCK, MEMCACHED_BEHAVIOR_NO_BLOCK);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_TCP_NODELAY, MEMCACHED_BEHAVIOR_TCP_NODELAY);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_SOCKET_SEND_SIZE, MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_SOCKET_RECV_SIZE, MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_CONNECT_TIMEOUT, MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_RETRY_TIMEOUT, MEMCACHED_BEHAVIOR_RETRY_TIMEOUT);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_SEND_TIMEOUT, MEMCACHED_BEHAVIOR_SND_TIMEOUT);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_RECV_TIMEOUT, MEMCACHED_BEHAVIOR_RCV_TIMEOUT);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_POLL_TIMEOUT, MEMCACHED_BEHAVIOR_POLL_TIMEOUT);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_CACHE_LOOKUPS, MEMCACHED_BEHAVIOR_CACHE_LOOKUPS);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_SERVER_FAILURE_LIMIT, MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_AUTO_EJECT_HOSTS, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_HASH_WITH_PREFIX_KEY, MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_NOREPLY, MEMCACHED_BEHAVIOR_NOREPLY);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_SORT_HOSTS, MEMCACHED_BEHAVIOR_SORT_HOSTS);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_VERIFY_KEY, MEMCACHED_BEHAVIOR_VERIFY_KEY);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_USE_UDP, MEMCACHED_BEHAVIOR_USE_UDP);
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x00037000
REGISTER_MEMC_CLASS_CONST_LONG(OPT_NUMBER_OF_REPLICAS, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS);
REGISTER_MEMC_CLASS_CONST_LONG(OPT_RANDOMIZE_REPLICA_READ, MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ);
#endif
#if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x00049000
REGISTER_MEMC_CLASS_CONST_LONG(OPT_REMOVE_FAILED_SERVERS, MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS);
#endif
/*
* libmemcached result codes
*/
REGISTER_MEMC_CLASS_CONST_LONG(RES_SUCCESS, MEMCACHED_SUCCESS);
REGISTER_MEMC_CLASS_CONST_LONG(RES_FAILURE, MEMCACHED_FAILURE);
REGISTER_MEMC_CLASS_CONST_LONG(RES_HOST_LOOKUP_FAILURE, MEMCACHED_HOST_LOOKUP_FAILURE);
REGISTER_MEMC_CLASS_CONST_LONG(RES_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_MEMORY_ALLOCATION_FAILURE, MEMCACHED_MEMORY_ALLOCATION_FAILURE);
REGISTER_MEMC_CLASS_CONST_LONG(RES_CONNECTION_SOCKET_CREATE_FAILURE, MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE);
#if HAVE_MEMCACHED_SASL
REGISTER_MEMC_CLASS_CONST_LONG(RES_AUTH_PROBLEM, MEMCACHED_AUTH_PROBLEM);
REGISTER_MEMC_CLASS_CONST_LONG(RES_AUTH_FAILURE, MEMCACHED_AUTH_FAILURE);
REGISTER_MEMC_CLASS_CONST_LONG(RES_AUTH_CONTINUE, MEMCACHED_AUTH_CONTINUE);
#endif
/*
* Our result codes.
*/
REGISTER_MEMC_CLASS_CONST_LONG(RES_PAYLOAD_FAILURE, MEMC_RES_PAYLOAD_FAILURE);
/*
* Serializer types.
*/
REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_PHP, SERIALIZER_PHP);
REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_IGBINARY, SERIALIZER_IGBINARY);
REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_JSON, SERIALIZER_JSON);
REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_JSON_ARRAY, SERIALIZER_JSON_ARRAY);
/*
* Compression types
*/
REGISTER_MEMC_CLASS_CONST_LONG(COMPRESSION_FASTLZ, COMPRESSION_TYPE_FASTLZ);
REGISTER_MEMC_CLASS_CONST_LONG(COMPRESSION_ZLIB, COMPRESSION_TYPE_ZLIB);
/*
* Flags.
*/
REGISTER_MEMC_CLASS_CONST_LONG(GET_PRESERVE_ORDER, MEMC_GET_PRESERVE_ORDER);
#undef REGISTER_MEMC_CLASS_CONST_LONG
/*
* Return value from simple get errors
*/
REGISTER_MEMC_CLASS_CONST_BOOL(GET_ERROR_RETURN_VALUE, 0);
}
/* }}} */
#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;
}
/* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(memcached)
{
zend_class_entry ce;
memcpy(&memcached_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
memcached_object_handlers.clone_obj = NULL;
le_memc = zend_register_list_destructors_ex(NULL, php_memc_dtor, "Memcached persistent connection", module_number);
le_memc_sess = zend_register_list_destructors_ex(NULL, php_memc_sess_dtor, "Memcached Sessions persistent connection", module_number);
INIT_CLASS_ENTRY(ce, "Memcached", memcached_class_methods);
memcached_ce = zend_register_internal_class(&ce TSRMLS_CC);
memcached_ce->create_object = php_memc_new;
INIT_CLASS_ENTRY(ce, "MemcachedException", NULL);
memcached_exception_ce = zend_register_internal_class_ex(&ce, php_memc_get_exception_base(0 TSRMLS_CC), NULL TSRMLS_CC);
/* TODO
* possibly declare custom exception property here
*/
php_memc_register_constants(INIT_FUNC_ARGS_PASSTHRU);
#ifdef ZTS
ts_allocate_id(&php_memcached_globals_id, sizeof(zend_php_memcached_globals),
(ts_allocate_ctor) php_memc_init_globals, (ts_allocate_dtor) php_memc_destroy_globals);
#else
php_memc_init_globals(&php_memcached_globals TSRMLS_CC);
#endif
#ifdef HAVE_MEMCACHED_SESSION
php_session_register_module(ps_memcached_ptr);
#endif
REGISTER_INI_ENTRIES();
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MSHUTDOWN_FUNCTION */
PHP_MSHUTDOWN_FUNCTION(memcached)
{
#ifdef ZTS
ts_free_id(php_memcached_globals_id);
#else
php_memc_destroy_globals(&php_memcached_globals TSRMLS_CC);
#endif
UNREGISTER_INI_ENTRIES();
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MINFO_FUNCTION */
PHP_MINFO_FUNCTION(memcached)
{
php_info_print_table_start();
php_info_print_table_header(2, "memcached support", "enabled");
php_info_print_table_row(2, "Version", PHP_MEMCACHED_VERSION);
php_info_print_table_row(2, "libmemcached version", memcached_lib_version());
#ifdef HAVE_MEMCACHED_SESSION
php_info_print_table_row(2, "Session support", "yes");
#else
php_info_print_table_row(2, "Session support ", "no");
#endif
#ifdef HAVE_MEMCACHED_IGBINARY
php_info_print_table_row(2, "igbinary support", "yes");
#else
php_info_print_table_row(2, "igbinary support", "no");
#endif
#ifdef HAVE_JSON_API
php_info_print_table_row(2, "json support", "yes");
#else
php_info_print_table_row(2, "json support", "no");
#endif
php_info_print_table_end();
DISPLAY_INI_ENTRIES();
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim: noet sw=4 ts=4 fdm=marker:
*/
memcached-2.1.0/php_memcached.h 0000644 0000767 0000024 00000006422 12010120566 015472 0 ustar andrei staff /*
+----------------------------------------------------------------------+
| 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 |
+----------------------------------------------------------------------+
*/
/* $ Id: $ */
#ifndef PHP_MEMCACHED_H
#define PHP_MEMCACHED_H
#include "php_libmemcached_compat.h"
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
extern zend_module_entry memcached_module_entry;
#define phpext_memcached_ptr &memcached_module_entry
#ifdef PHP_WIN32
#define PHP_MEMCACHED_API __declspec(dllexport)
#else
#define PHP_MEMCACHED_API
#endif
/****************************************
Structures and definitions
****************************************/
enum memcached_serializer {
SERIALIZER_PHP = 1,
SERIALIZER_IGBINARY = 2,
SERIALIZER_JSON = 3,
SERIALIZER_JSON_ARRAY = 4,
};
#ifdef HAVE_MEMCACHED_IGBINARY
#define SERIALIZER_DEFAULT SERIALIZER_IGBINARY
#define SERIALIZER_DEFAULT_NAME "igbinary"
#else
#define SERIALIZER_DEFAULT SERIALIZER_PHP
#define SERIALIZER_DEFAULT_NAME "php"
#endif /* HAVE_MEMCACHED_IGBINARY */
#if LIBMEMCACHED_WITH_SASL_SUPPORT
# if defined(HAVE_SASL_SASL_H)
# include
# define HAVE_MEMCACHED_SASL 1
# endif
#endif
ZEND_BEGIN_MODULE_GLOBALS(php_memcached)
#ifdef HAVE_MEMCACHED_SESSION
zend_bool sess_locking_enabled;
long sess_lock_wait;
char* sess_prefix;
zend_bool sess_locked;
char* sess_lock_key;
int sess_lock_key_len;
#endif
char *serializer_name;
enum memcached_serializer serializer;
char *compression_type;
int compression_type_real;
int compression_threshold;
double compression_factor;
#if HAVE_MEMCACHED_SASL
bool use_sasl;
#endif
zend_bool sess_binary_enabled;
ZEND_END_MODULE_GLOBALS(php_memcached)
PHP_MEMCACHED_API zend_class_entry *php_memc_get_ce(void);
PHP_MEMCACHED_API zend_class_entry *php_memc_get_exception(void);
PHP_MEMCACHED_API zend_class_entry *php_memc_get_exception_base(int root TSRMLS_DC);
PHP_RINIT_FUNCTION(memcached);
PHP_RSHUTDOWN_FUNCTION(memcached);
PHP_MINIT_FUNCTION(memcached);
PHP_MSHUTDOWN_FUNCTION(memcached);
PHP_MINFO_FUNCTION(memcached);
#define PHP_MEMCACHED_VERSION "2.1.0"
#ifdef ZTS
#define MEMC_G(v) TSRMG(php_memcached_globals_id, zend_php_memcached_globals *, v)
#else
#define MEMC_G(v) (php_memcached_globals.v)
#endif
typedef struct {
memcached_st *memc_sess;
zend_bool is_persisent;
} memcached_sess;
int php_memc_sess_list_entry(void);
#endif /* PHP_MEMCACHED_H */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
memcached-2.1.0/php_memcached_session.c 0000644 0000767 0000024 00000021013 12010120566 017221 0 ustar andrei staff /*
+----------------------------------------------------------------------+
| Copyright (c) 2009-2010 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt. |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Andrei Zmievski |
+----------------------------------------------------------------------+
*/
#include
#include
#include
#include
#ifdef ZTS
#include "TSRM.h"
#endif
#include
#include
#include
#include
#include
#include
#include
#include "php_memcached.h"
#include "php_memcached_session.h"
extern ZEND_DECLARE_MODULE_GLOBALS(php_memcached)
#define MEMC_SESS_DEFAULT_LOCK_WAIT 150000
#define MEMC_SESS_LOCK_EXPIRATION 30
ps_module ps_mod_memcached = {
PS_MOD(memcached)
};
static int php_memc_sess_lock(memcached_st *memc, const char *key TSRMLS_DC)
{
char *lock_key = NULL;
int lock_key_len = 0;
unsigned long attempts;
long lock_maxwait;
long lock_wait = MEMC_G(sess_lock_wait);
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;
}
if (lock_wait == 0) {
lock_wait = MEMC_SESS_DEFAULT_LOCK_WAIT;
}
expiration = time(NULL) + lock_maxwait + 1;
attempts = (unsigned long)((1000000.0 / lock_wait) * lock_maxwait);
lock_key_len = spprintf(&lock_key, 0, "lock.%s", key);
do {
status = memcached_add(memc, lock_key, lock_key_len, "1", sizeof("1")-1, expiration, 0);
if (status == MEMCACHED_SUCCESS) {
MEMC_G(sess_locked) = 1;
MEMC_G(sess_lock_key) = lock_key;
MEMC_G(sess_lock_key_len) = lock_key_len;
return 0;
} else if (status != MEMCACHED_NOTSTORED && status != MEMCACHED_DATA_EXISTS) {
break;
}
if (lock_wait > 0) {
usleep(lock_wait);
}
} while(--attempts > 0);
efree(lock_key);
return -1;
}
static void php_memc_sess_unlock(memcached_st *memc TSRMLS_DC)
{
if (MEMC_G(sess_locked)) {
memcached_delete(memc, MEMC_G(sess_lock_key), MEMC_G(sess_lock_key_len), 0);
MEMC_G(sess_locked) = 0;
efree(MEMC_G(sess_lock_key));
MEMC_G(sess_lock_key_len) = 0;
}
}
PS_OPEN_FUNC(memcached)
{
memcached_sess *memc_sess = PS_GET_MOD_DATA();
memcached_return status;
char *p, *plist_key = NULL;
int plist_key_len;
if (!strncmp((char *)save_path, "PERSISTENT=", sizeof("PERSISTENT=") - 1)) {
zend_rsrc_list_entry *le = NULL;
char *e;
p = (char *)save_path + sizeof("PERSISTENT=") - 1;
if (!*p) {
error:
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid persistent id for session storage");
return FAILURE;
}
if ((e = strchr(p, ' '))) {
plist_key_len = spprintf(&plist_key, 0, "memcached_sessions:id=%.*s", (int)(e - p), p);
} else {
goto error;
}
plist_key_len++;
if (zend_hash_find(&EG(persistent_list), plist_key, plist_key_len, (void *)&le) == SUCCESS) {
if (le->type == php_memc_sess_list_entry()) {
memc_sess = (memcached_sess *) le->ptr;
PS_SET_MOD_DATA(memc_sess);
return SUCCESS;
}
}
p = e + 1;
memc_sess = pecalloc(sizeof(*memc_sess), 1, 1);
memc_sess->is_persisent = 1;
} else {
p = (char *)save_path;
memc_sess = ecalloc(sizeof(*memc_sess), 1);
memc_sess->is_persisent = 0;
}
if (!strstr(p, "--SERVER")) {
memcached_server_st *servers = memcached_servers_parse(p);
if (servers) {
memc_sess->memc_sess = memcached_create(NULL);
if (memc_sess->memc_sess) {
status = memcached_server_push(memc_sess->memc_sess, servers);
memcached_server_list_free(servers);
if (memcached_callback_set(memc_sess->memc_sess, MEMCACHED_CALLBACK_PREFIX_KEY, MEMC_G(sess_prefix)) != MEMCACHED_SUCCESS) {
PS_SET_MOD_DATA(NULL);
if (plist_key) {
efree(plist_key);
}
memcached_free(memc_sess->memc_sess);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "bad memcached key prefix in memcached.sess_prefix");
return FAILURE;
}
if (status == MEMCACHED_SUCCESS) {
goto success;
}
} else {
memcached_server_list_free(servers);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not allocate libmemcached structure");
}
} else {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to parse session.save_path");
}
} else {
memc_sess->memc_sess = memcached(p, strlen(p));
if (!memc_sess->memc_sess) {
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 {
success:
PS_SET_MOD_DATA(memc_sess);
if (plist_key) {
zend_rsrc_list_entry le;
le.type = php_memc_sess_list_entry();
le.ptr = memc_sess;
if (zend_hash_update(&EG(persistent_list), (char *)plist_key, plist_key_len, (void *)&le, sizeof(le), NULL) == FAILURE) {
efree(plist_key);
php_error_docref(NULL TSRMLS_CC, E_ERROR, "could not register persistent entry");
}
efree(plist_key);
}
if (MEMC_G(sess_binary_enabled)) {
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;
}
}
return SUCCESS;
}
}
if (plist_key) {
efree(plist_key);
}
PS_SET_MOD_DATA(NULL);
return FAILURE;
}
PS_CLOSE_FUNC(memcached)
{
memcached_sess *memc_sess = PS_GET_MOD_DATA();
if (MEMC_G(sess_locking_enabled)) {
php_memc_sess_unlock(memc_sess->memc_sess TSRMLS_CC);
}
if (memc_sess->memc_sess) {
if (!memc_sess->is_persisent) {
memcached_free(memc_sess->memc_sess);
efree(memc_sess);
}
PS_SET_MOD_DATA(NULL);
}
return SUCCESS;
}
PS_READ_FUNC(memcached)
{
char *payload = NULL;
size_t payload_len = 0;
int key_len = strlen(key);
uint32_t flags = 0;
memcached_return status;
memcached_sess *memc_sess = PS_GET_MOD_DATA();
size_t key_length;
key_length = strlen(MEMC_G(sess_prefix)) + key_len + 5; // prefix + "lock."
if (!key_length || key_length >= MEMCACHED_MAX_KEY) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "The session id is too long or contains illegal characters");
PS(invalid_session_id) = 1;
return FAILURE;
}
if (MEMC_G(sess_locking_enabled)) {
if (php_memc_sess_lock(memc_sess->memc_sess, key TSRMLS_CC) < 0) {
return FAILURE;
}
}
payload = memcached_get(memc_sess->memc_sess, key, key_len, &payload_len, &flags, &status);
if (status == MEMCACHED_SUCCESS) {
*val = estrndup(payload, payload_len);
*vallen = payload_len;
free(payload);
return SUCCESS;
} else {
return FAILURE;
}
}
PS_WRITE_FUNC(memcached)
{
int key_len = strlen(key);
time_t expiration = 0;
memcached_return status;
memcached_sess *memc_sess = PS_GET_MOD_DATA();
size_t key_length;
key_length = strlen(MEMC_G(sess_prefix)) + key_len + 5; // prefix + "lock."
if (!key_length || key_length >= MEMCACHED_MAX_KEY) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "The session id is too long or contains illegal characters");
PS(invalid_session_id) = 1;
return FAILURE;
}
if (PS(gc_maxlifetime) > 0) {
expiration = PS(gc_maxlifetime);
}
status = memcached_set(memc_sess->memc_sess, key, key_len, val, vallen, expiration, 0);
if (status == MEMCACHED_SUCCESS) {
return SUCCESS;
} else {
return FAILURE;
}
}
PS_DESTROY_FUNC(memcached)
{
memcached_sess *memc_sess = PS_GET_MOD_DATA();
memcached_delete(memc_sess->memc_sess, key, strlen(key), 0);
if (MEMC_G(sess_locking_enabled)) {
php_memc_sess_unlock(memc_sess->memc_sess TSRMLS_CC);
}
return SUCCESS;
}
PS_GC_FUNC(memcached)
{
return SUCCESS;
}
/* }}} */
memcached-2.1.0/php_memcached_session.h 0000644 0000767 0000024 00000002577 12010120566 017244 0 ustar andrei staff /*
+----------------------------------------------------------------------+
| Copyright (c) 2009-2010 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt. |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Andrei Zmievski |
+----------------------------------------------------------------------+
*/
#ifndef PHP_MEMCACHED_SESSION_H
#define PHP_MEMCACHED_SESSION_H
/* session handler struct */
#include "ext/session/php_session.h"
extern ps_module ps_mod_memcached;
#define ps_memcached_ptr &ps_mod_memcached
PS_FUNCS(memcached);
PS_OPEN_FUNC(memcached);
PS_CLOSE_FUNC(memcached);
PS_READ_FUNC(memcached);
PS_WRITE_FUNC(memcached);
PS_DESTROY_FUNC(memcached);
PS_GC_FUNC(memcached);
#endif /* PHP_MEMCACHED_SESSION_H */
memcached-2.1.0/php_libmemcached_compat.h 0000644 0000767 0000024 00000000231 12010120566 017514 0 ustar andrei staff #ifndef PHP_LIBMEMCACHED_COMPAT
#define PHP_LIBMEMCACHED_COMPAT
/* this is the version(s) we support */
#include
#endif
memcached-2.1.0/g_fmt.c 0000644 0000767 0000024 00000004322 12010120566 014001 0 ustar andrei staff /****************************************************************
*
* The author of this software is David M. Gay.
*
* Copyright (c) 1991, 1996 by Lucent Technologies.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
*
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*
***************************************************************/
/* g_fmt(buf,x) stores the closest decimal approximation to x in buf;
* it suffices to declare buf
* char buf[32];
*/
/* Modified for use with php in the memcached client extension.
*
* // Teddy Grenman , 2010-05-18.
*/
#include
char *php_memcached_g_fmt(register char *b, double x) {
register int i, k;
register char *s;
int decpt, j, sign;
char *b0, *s0, *se;
b0 = b;
#ifdef IGNORE_ZERO_SIGN
if (!x) {
*b++ = '0';
*b = 0;
goto done;
}
#endif
s = s0 = zend_dtoa(x, 0, 0, &decpt, &sign, &se);
if (sign)
*b++ = '-';
if (decpt == 9999) /* Infinity or Nan */ {
while(*b++ = *s++);
goto done0;
}
if (decpt <= -4 || decpt > se - s + 5) {
*b++ = *s++;
if (*s) {
*b++ = '.';
while(*b = *s++)
b++;
}
*b++ = 'e';
/* sprintf(b, "%+.2d", decpt - 1); */
if (--decpt < 0) {
*b++ = '-';
decpt = -decpt;
}
else
*b++ = '+';
for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10);
for(;;) {
i = decpt / k;
*b++ = i + '0';
if (--j <= 0)
break;
decpt -= i*k;
decpt *= 10;
}
*b = 0;
} else if (decpt <= 0) {
*b++ = '.';
for(; decpt < 0; decpt++)
*b++ = '0';
while(*b++ = *s++);
} else {
while(*b = *s++) {
b++;
if (--decpt == 0 && *s)
*b++ = '.';
}
for(; decpt > 0; decpt--)
*b++ = '0';
*b = 0;
}
done0:
zend_freedtoa(s0);
done:
return b0;
}
memcached-2.1.0/g_fmt.h 0000644 0000767 0000024 00000002235 12010120566 014007 0 ustar andrei staff /****************************************************************
*
* The author of this software is David M. Gay.
*
* Copyright (c) 1991, 1996 by Lucent Technologies.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
*
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*
***************************************************************/
/* g_fmt(buf,x) stores the closest decimal approximation to x in buf;
* it suffices to declare buf
* char buf[32];
*/
/* Modified for use with php in the memcached client
* extension by Teddy Grenman, 2010.
*/
#ifndef MEMC_G_FMT_H
#define MEMC_G_FMT_H
char *php_memcached_g_fmt(register char *b, double x);
#endif
memcached-2.1.0/fastlz/fastlz.c 0000644 0000767 0000024 00000032520 12010120566 015514 0 ustar andrei staff /*
FastLZ - lightning-fast lossless compression library
Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
Copyright (C) 2005 Ariya Hidayat (ariya@kde.org)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#if !defined(FASTLZ__COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR)
/*
* Always check for bound when decompressing.
* Generally it is best to leave it defined.
*/
#define FASTLZ_SAFE
/*
* Give hints to the compiler for branch prediction optimization.
*/
#if defined(__GNUC__) && (__GNUC__ > 2)
#define FASTLZ_EXPECT_CONDITIONAL(c) (__builtin_expect((c), 1))
#define FASTLZ_UNEXPECT_CONDITIONAL(c) (__builtin_expect((c), 0))
#else
#define FASTLZ_EXPECT_CONDITIONAL(c) (c)
#define FASTLZ_UNEXPECT_CONDITIONAL(c) (c)
#endif
/*
* Use inlined functions for supported systems.
*/
#if defined(__GNUC__) || defined(__DMC__) || defined(__POCC__) || defined(__WATCOMC__) || defined(__SUNPRO_C)
#define FASTLZ_INLINE inline
#elif defined(__BORLANDC__) || defined(_MSC_VER) || defined(__LCC__)
#define FASTLZ_INLINE __inline
#else
#define FASTLZ_INLINE
#endif
/*
* Prevent accessing more than 8-bit at once, except on x86 architectures.
*/
#if !defined(FASTLZ_STRICT_ALIGN)
#define FASTLZ_STRICT_ALIGN
#if defined(__i386__) || defined(__386) /* GNU C, Sun Studio */
#undef FASTLZ_STRICT_ALIGN
#elif defined(__i486__) || defined(__i586__) || defined(__i686__) /* GNU C */
#undef FASTLZ_STRICT_ALIGN
#elif defined(_M_IX86) /* Intel, MSVC */
#undef FASTLZ_STRICT_ALIGN
#elif defined(__386)
#undef FASTLZ_STRICT_ALIGN
#elif defined(_X86_) /* MinGW */
#undef FASTLZ_STRICT_ALIGN
#elif defined(__I86__) /* Digital Mars */
#undef FASTLZ_STRICT_ALIGN
#endif
#endif
/*
* FIXME: use preprocessor magic to set this on different platforms!
*/
typedef unsigned char flzuint8;
typedef unsigned short flzuint16;
typedef unsigned int flzuint32;
/* prototypes */
int fastlz_compress(const void* input, int length, void* output);
int fastlz_compress_level(int level, const void* input, int length, void* output);
int fastlz_decompress(const void* input, int length, void* output, int maxout);
#define MAX_COPY 32
#define MAX_LEN 264 /* 256 + 8 */
#define MAX_DISTANCE 8192
#if !defined(FASTLZ_STRICT_ALIGN)
#define FASTLZ_READU16(p) *((const flzuint16*)(p))
#else
#define FASTLZ_READU16(p) ((p)[0] | (p)[1]<<8)
#endif
#define HASH_LOG 13
#define HASH_SIZE (1<< HASH_LOG)
#define HASH_MASK (HASH_SIZE-1)
#define HASH_FUNCTION(v,p) { v = FASTLZ_READU16(p); v ^= FASTLZ_READU16(p+1)^(v>>(16-HASH_LOG));v &= HASH_MASK; }
#undef FASTLZ_LEVEL
#define FASTLZ_LEVEL 1
#undef FASTLZ_COMPRESSOR
#undef FASTLZ_DECOMPRESSOR
#define FASTLZ_COMPRESSOR fastlz1_compress
#define FASTLZ_DECOMPRESSOR fastlz1_decompress
static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output);
static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout);
#include "fastlz.c"
#undef FASTLZ_LEVEL
#define FASTLZ_LEVEL 2
#undef MAX_DISTANCE
#define MAX_DISTANCE 8191
#define MAX_FARDISTANCE (65535+MAX_DISTANCE-1)
#undef FASTLZ_COMPRESSOR
#undef FASTLZ_DECOMPRESSOR
#define FASTLZ_COMPRESSOR fastlz2_compress
#define FASTLZ_DECOMPRESSOR fastlz2_decompress
static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output);
static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout);
#include "fastlz.c"
int fastlz_compress(const void* input, int length, void* output)
{
/* for short block, choose fastlz1 */
if(length < 65536)
return fastlz1_compress(input, length, output);
/* else... */
return fastlz2_compress(input, length, output);
}
int fastlz_decompress(const void* input, int length, void* output, int maxout)
{
/* magic identifier for compression level */
int level = ((*(const flzuint8*)input) >> 5) + 1;
if(level == 1)
return fastlz1_decompress(input, length, output, maxout);
if(level == 2)
return fastlz2_decompress(input, length, output, maxout);
/* unknown level, trigger error */
return 0;
}
int fastlz_compress_level(int level, const void* input, int length, void* output)
{
if(level == 1)
return fastlz1_compress(input, length, output);
if(level == 2)
return fastlz2_compress(input, length, output);
return 0;
}
#else /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */
static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output)
{
const flzuint8* ip = (const flzuint8*) input;
const flzuint8* ip_bound = ip + length - 2;
const flzuint8* ip_limit = ip + length - 12;
flzuint8* op = (flzuint8*) output;
const flzuint8* htab[HASH_SIZE];
const flzuint8** hslot;
flzuint32 hval;
flzuint32 copy;
/* sanity check */
if(FASTLZ_UNEXPECT_CONDITIONAL(length < 4))
{
if(length)
{
/* create literal copy only */
*op++ = length-1;
ip_bound++;
while(ip <= ip_bound)
*op++ = *ip++;
return length+1;
}
else
return 0;
}
/* initializes hash table */
for (hslot = htab; hslot < htab + HASH_SIZE; hslot++)
*hslot = ip;
/* we start with literal copy */
copy = 2;
*op++ = MAX_COPY-1;
*op++ = *ip++;
*op++ = *ip++;
/* main loop */
while(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit))
{
const flzuint8* ref;
flzuint32 distance;
/* minimum match length */
flzuint32 len = 3;
/* comparison starting-point */
const flzuint8* anchor = ip;
/* check for a run */
#if FASTLZ_LEVEL==2
if(ip[0] == ip[-1] && FASTLZ_READU16(ip-1)==FASTLZ_READU16(ip+1))
{
distance = 1;
ip += 3;
ref = anchor - 1 + 3;
goto match;
}
#endif
/* find potential match */
HASH_FUNCTION(hval,ip);
hslot = htab + hval;
ref = htab[hval];
/* calculate distance to the match */
distance = anchor - ref;
/* update hash table */
*hslot = anchor;
/* is this a match? check the first 3 bytes */
if(distance==0 ||
#if FASTLZ_LEVEL==1
(distance >= MAX_DISTANCE) ||
#else
(distance >= MAX_FARDISTANCE) ||
#endif
*ref++ != *ip++ || *ref++!=*ip++ || *ref++!=*ip++)
goto literal;
#if FASTLZ_LEVEL==2
/* far, needs at least 5-byte match */
if(distance >= MAX_DISTANCE)
{
if(*ip++ != *ref++ || *ip++!= *ref++)
goto literal;
len += 2;
}
match:
#endif
/* last matched byte */
ip = anchor + len;
/* distance is biased */
distance--;
if(!distance)
{
/* zero distance means a run */
flzuint8 x = ip[-1];
while(ip < ip_bound)
if(*ref++ != x) break; else ip++;
}
else
for(;;)
{
/* safe because the outer check against ip limit */
if(*ref++ != *ip++) break;
if(*ref++ != *ip++) break;
if(*ref++ != *ip++) break;
if(*ref++ != *ip++) break;
if(*ref++ != *ip++) break;
if(*ref++ != *ip++) break;
if(*ref++ != *ip++) break;
if(*ref++ != *ip++) break;
while(ip < ip_bound)
if(*ref++ != *ip++) break;
break;
}
/* if we have copied something, adjust the copy count */
if(copy)
/* copy is biased, '0' means 1 byte copy */
*(op-copy-1) = copy-1;
else
/* back, to overwrite the copy count */
op--;
/* reset literal counter */
copy = 0;
/* length is biased, '1' means a match of 3 bytes */
ip -= 3;
len = ip - anchor;
/* encode the match */
#if FASTLZ_LEVEL==2
if(distance < MAX_DISTANCE)
{
if(len < 7)
{
*op++ = (len << 5) + (distance >> 8);
*op++ = (distance & 255);
}
else
{
*op++ = (7 << 5) + (distance >> 8);
for(len-=7; len >= 255; len-= 255)
*op++ = 255;
*op++ = len;
*op++ = (distance & 255);
}
}
else
{
/* far away, but not yet in the another galaxy... */
if(len < 7)
{
distance -= MAX_DISTANCE;
*op++ = (len << 5) + 31;
*op++ = 255;
*op++ = distance >> 8;
*op++ = distance & 255;
}
else
{
distance -= MAX_DISTANCE;
*op++ = (7 << 5) + 31;
for(len-=7; len >= 255; len-= 255)
*op++ = 255;
*op++ = len;
*op++ = 255;
*op++ = distance >> 8;
*op++ = distance & 255;
}
}
#else
if(FASTLZ_UNEXPECT_CONDITIONAL(len > MAX_LEN-2))
while(len > MAX_LEN-2)
{
*op++ = (7 << 5) + (distance >> 8);
*op++ = MAX_LEN - 2 - 7 -2;
*op++ = (distance & 255);
len -= MAX_LEN-2;
}
if(len < 7)
{
*op++ = (len << 5) + (distance >> 8);
*op++ = (distance & 255);
}
else
{
*op++ = (7 << 5) + (distance >> 8);
*op++ = len - 7;
*op++ = (distance & 255);
}
#endif
/* update the hash at match boundary */
HASH_FUNCTION(hval,ip);
htab[hval] = ip++;
HASH_FUNCTION(hval,ip);
htab[hval] = ip++;
/* assuming literal copy */
*op++ = MAX_COPY-1;
continue;
literal:
*op++ = *anchor++;
ip = anchor;
copy++;
if(FASTLZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY))
{
copy = 0;
*op++ = MAX_COPY-1;
}
}
/* left-over as literal copy */
ip_bound++;
while(ip <= ip_bound)
{
*op++ = *ip++;
copy++;
if(copy == MAX_COPY)
{
copy = 0;
*op++ = MAX_COPY-1;
}
}
/* if we have copied something, adjust the copy length */
if(copy)
*(op-copy-1) = copy-1;
else
op--;
#if FASTLZ_LEVEL==2
/* marker for fastlz2 */
*(flzuint8*)output |= (1 << 5);
#endif
return op - (flzuint8*)output;
}
static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout)
{
const flzuint8* ip = (const flzuint8*) input;
const flzuint8* ip_limit = ip + length;
flzuint8* op = (flzuint8*) output;
flzuint8* op_limit = op + maxout;
flzuint32 ctrl = (*ip++) & 31;
int loop = 1;
do
{
const flzuint8* ref = op;
flzuint32 len = ctrl >> 5;
flzuint32 ofs = (ctrl & 31) << 8;
if(ctrl >= 32)
{
#if FASTLZ_LEVEL==2
flzuint8 code;
#endif
len--;
ref -= ofs;
if (len == 7-1)
#if FASTLZ_LEVEL==1
len += *ip++;
ref -= *ip++;
#else
do
{
code = *ip++;
len += code;
} while (code==255);
code = *ip++;
ref -= code;
/* match from 16-bit distance */
if(FASTLZ_UNEXPECT_CONDITIONAL(code==255))
if(FASTLZ_EXPECT_CONDITIONAL(ofs==(31 << 8)))
{
ofs = (*ip++) << 8;
ofs += *ip++;
ref = op - ofs - MAX_DISTANCE;
}
#endif
#ifdef FASTLZ_SAFE
if (FASTLZ_UNEXPECT_CONDITIONAL(op + len + 3 > op_limit))
return 0;
if (FASTLZ_UNEXPECT_CONDITIONAL(ref-1 < (flzuint8 *)output))
return 0;
#endif
if(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit))
ctrl = *ip++;
else
loop = 0;
if(ref == op)
{
/* optimize copy for a run */
flzuint8 b = ref[-1];
*op++ = b;
*op++ = b;
*op++ = b;
for(; len; --len)
*op++ = b;
}
else
{
#if !defined(FASTLZ_STRICT_ALIGN)
const flzuint16* p;
flzuint16* q;
#endif
/* copy from reference */
ref--;
*op++ = *ref++;
*op++ = *ref++;
*op++ = *ref++;
#if !defined(FASTLZ_STRICT_ALIGN)
/* copy a byte, so that now it's word aligned */
if(len & 1)
{
*op++ = *ref++;
len--;
}
/* copy 16-bit at once */
q = (flzuint16*) op;
op += len;
p = (const flzuint16*) ref;
for(len>>=1; len > 4; len-=4)
{
*q++ = *p++;
*q++ = *p++;
*q++ = *p++;
*q++ = *p++;
}
for(; len; --len)
*q++ = *p++;
#else
for(; len; --len)
*op++ = *ref++;
#endif
}
}
else
{
ctrl++;
#ifdef FASTLZ_SAFE
if (FASTLZ_UNEXPECT_CONDITIONAL(op + ctrl > op_limit))
return 0;
if (FASTLZ_UNEXPECT_CONDITIONAL(ip + ctrl > ip_limit))
return 0;
#endif
*op++ = *ip++;
for(--ctrl; ctrl; ctrl--)
*op++ = *ip++;
loop = FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit);
if(loop)
ctrl = *ip++;
}
}
while(FASTLZ_EXPECT_CONDITIONAL(loop));
return op - (flzuint8*)output;
}
#endif /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */
memcached-2.1.0/fastlz/fastlz.h 0000644 0000767 0000024 00000006756 12010120566 015535 0 ustar andrei staff /*
FastLZ - lightning-fast lossless compression library
Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
Copyright (C) 2005 Ariya Hidayat (ariya@kde.org)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef FASTLZ_H
#define FASTLZ_H
#define FASTLZ_VERSION 0x000100
#define FASTLZ_VERSION_MAJOR 0
#define FASTLZ_VERSION_MINOR 0
#define FASTLZ_VERSION_REVISION 0
#define FASTLZ_VERSION_STRING "0.1.0"
#if defined (__cplusplus)
extern "C" {
#endif
/**
Compress a block of data in the input buffer and returns the size of
compressed block. The size of input buffer is specified by length. The
minimum input buffer size is 16.
The output buffer must be at least 5% larger than the input buffer
and can not be smaller than 66 bytes.
If the input is not compressible, the return value might be larger than
length (input buffer size).
The input buffer and the output buffer can not overlap.
*/
int fastlz_compress(const void* input, int length, void* output);
/**
Decompress a block of compressed data and returns the size of the
decompressed block. If error occurs, e.g. the compressed data is
corrupted or the output buffer is not large enough, then 0 (zero)
will be returned instead.
The input buffer and the output buffer can not overlap.
Decompression is memory safe and guaranteed not to write the output buffer
more than what is specified in maxout.
*/
int fastlz_decompress(const void* input, int length, void* output, int maxout);
/**
Compress a block of data in the input buffer and returns the size of
compressed block. The size of input buffer is specified by length. The
minimum input buffer size is 16.
The output buffer must be at least 5% larger than the input buffer
and can not be smaller than 66 bytes.
If the input is not compressible, the return value might be larger than
length (input buffer size).
The input buffer and the output buffer can not overlap.
Compression level can be specified in parameter level. At the moment,
only level 1 and level 2 are supported.
Level 1 is the fastest compression and generally useful for short data.
Level 2 is slightly slower but it gives better compression ratio.
Note that the compressed data, regardless of the level, can always be
decompressed using the function fastlz_decompress above.
*/
int fastlz_compress_level(int level, const void* input, int length, void* output);
#if defined (__cplusplus)
}
#endif
#endif /* FASTLZ_H */