Skip to content

Commit 32b9868

Browse files
author
Andrei Zmievski
committed
Refactor and add JSON serializer support.
JSON API is available only in PHP 5.2.10+, so need compile-time checks for that. Also, had to refactor the way value types are stored in flags to allow for better structure and future expansion, but this necessitates clearing of the cache on upgrading to this version.
1 parent b57ea9d commit 32b9868

File tree

2 files changed

+125
-71
lines changed

2 files changed

+125
-71
lines changed

php_memcached.c

Lines changed: 120 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@
4848
#ifdef HAVE_MEMCACHED_IGBINARY
4949
#include "ext/igbinary/igbinary.h"
5050
#endif
51+
#ifdef HAVE_MEMCACHED_IGBINARY
52+
#include "ext/json/php_json.h"
53+
#endif
5154

5255
/****************************************
5356
Custom options
@@ -64,12 +67,19 @@
6467
/****************************************
6568
Payload value flags
6669
****************************************/
67-
#define MEMC_VAL_SERIALIZED (1<<0)
68-
#define MEMC_VAL_COMPRESSED (1<<1)
69-
#define MEMC_VAL_IS_LONG (1<<2)
70-
#define MEMC_VAL_IS_DOUBLE (1<<3)
71-
#define MEMC_VAL_IGBINARY (1<<4)
72-
#define MEMC_VAL_IS_BOOL (1<<5)
70+
#define MEMC_VAL_TYPE_MASK 0xf
71+
#define MEMC_VAL_GET_TYPE(flags) ((flags) & MEMC_VAL_TYPE_MASK)
72+
#define MEMC_VAL_SET_TYPE(flags, type) ((flags) |= ((type) & MEMC_VAL_TYPE_MASK))
73+
74+
#define MEMC_VAL_IS_STRING 0
75+
#define MEMC_VAL_IS_LONG 1
76+
#define MEMC_VAL_IS_DOUBLE 2
77+
#define MEMC_VAL_IS_BOOL 3
78+
#define MEMC_VAL_IS_SERIALIZED 4
79+
#define MEMC_VAL_IS_IGBINARY 5
80+
#define MEMC_VAL_IS_JSON 6
81+
82+
#define MEMC_VAL_COMPRESSED (1<<4)
7383

7484
/****************************************
7585
"get" operation flags
@@ -117,6 +127,7 @@
117127
enum memcached_serializer {
118128
SERIALIZER_PHP = 1,
119129
SERIALIZER_IGBINARY = 2,
130+
SERIALIZER_JSON = 3,
120131
};
121132

122133
static int le_memc;
@@ -167,7 +178,7 @@ ZEND_GET_MODULE(memcached)
167178
****************************************/
168179
static int php_memc_list_entry(void);
169180
static int php_memc_handle_error(memcached_return status TSRMLS_DC);
170-
static char *php_memc_zval_to_payload(zval *value, size_t *payload_len, uint32_t *flags TSRMLS_DC);
181+
static char *php_memc_zval_to_payload(zval *value, size_t *payload_len, uint32_t *flags, enum memcached_serializer serializer TSRMLS_DC);
171182
static int php_memc_zval_from_payload(zval *value, char *payload, size_t payload_len, uint32_t flags TSRMLS_DC);
172183
static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key);
173184
static void php_memc_getMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key);
@@ -945,7 +956,7 @@ static void php_memc_setMulti_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_ke
945956
flags |= MEMC_VAL_COMPRESSED;
946957
}
947958

948-
payload = php_memc_zval_to_payload(*entry, &payload_len, &flags TSRMLS_CC);
959+
payload = php_memc_zval_to_payload(*entry, &payload_len, &flags, i_obj->serializer TSRMLS_CC);
949960
if (payload == NULL) {
950961
MEMC_G(rescode) = MEMC_RES_PAYLOAD_FAILURE;
951962
RETURN_FALSE;
@@ -1102,11 +1113,7 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool
11021113
flags |= MEMC_VAL_COMPRESSED;
11031114
}
11041115

1105-
if (i_obj->serializer == SERIALIZER_IGBINARY) {
1106-
flags |= MEMC_VAL_IGBINARY;
1107-
}
1108-
1109-
payload = php_memc_zval_to_payload(value, &payload_len, &flags TSRMLS_CC);
1116+
payload = php_memc_zval_to_payload(value, &payload_len, &flags, i_obj->serializer TSRMLS_CC);
11101117
if (op == MEMC_OP_APPEND || op == MEMC_OP_PREPEND) {
11111118
zval_ptr_dtor(&value);
11121119
}
@@ -1217,11 +1224,7 @@ static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key)
12171224
flags |= MEMC_VAL_COMPRESSED;
12181225
}
12191226

1220-
if (i_obj->serializer == SERIALIZER_IGBINARY) {
1221-
flags |= MEMC_VAL_IGBINARY;
1222-
}
1223-
1224-
payload = php_memc_zval_to_payload(value, &payload_len, &flags TSRMLS_CC);
1227+
payload = php_memc_zval_to_payload(value, &payload_len, &flags, i_obj->serializer TSRMLS_CC);
12251228
if (payload == NULL) {
12261229
MEMC_G(rescode) = MEMC_RES_PAYLOAD_FAILURE;
12271230
RETURN_FALSE;
@@ -1791,6 +1794,12 @@ static PHP_METHOD(Memcached, setOption)
17911794
i_obj->serializer = SERIALIZER_IGBINARY;
17921795
} else
17931796
#endif
1797+
#if HAVE_JSON_API
1798+
if (Z_LVAL_P(value) == SERIALIZER_JSON) {
1799+
i_obj->serializer = SERIALIZER_JSON;
1800+
} else
1801+
#endif
1802+
17941803
/* php serializer */
17951804
if (Z_LVAL_P(value) == SERIALIZER_PHP) {
17961805
i_obj->serializer = SERIALIZER_PHP;
@@ -1912,7 +1921,7 @@ static int php_memc_handle_error(memcached_return status TSRMLS_DC)
19121921
return result;
19131922
}
19141923

1915-
static char *php_memc_zval_to_payload(zval *value, size_t *payload_len, uint32_t *flags TSRMLS_DC)
1924+
static char *php_memc_zval_to_payload(zval *value, size_t *payload_len, uint32_t *flags, enum memcached_serializer serializer TSRMLS_DC)
19161925
{
19171926
char *payload;
19181927
smart_str buf = {0};
@@ -1921,7 +1930,7 @@ static char *php_memc_zval_to_payload(zval *value, size_t *payload_len, uint32_t
19211930

19221931
case IS_STRING:
19231932
smart_str_appendl(&buf, Z_STRVAL_P(value), Z_STRLEN_P(value));
1924-
*flags &= ~MEMC_VAL_IGBINARY;
1933+
MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_STRING);
19251934
break;
19261935

19271936
case IS_LONG:
@@ -1937,42 +1946,53 @@ static char *php_memc_zval_to_payload(zval *value, size_t *payload_len, uint32_t
19371946
zval_dtor(&value_copy);
19381947

19391948
*flags &= ~MEMC_VAL_COMPRESSED;
1940-
*flags &= ~MEMC_VAL_IGBINARY;
19411949
if (Z_TYPE_P(value) == IS_LONG) {
1942-
*flags |= MEMC_VAL_IS_LONG;
1950+
MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_LONG);
19431951
} else if (Z_TYPE_P(value) == IS_DOUBLE) {
1944-
*flags |= MEMC_VAL_IS_DOUBLE;
1952+
MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_DOUBLE);
19451953
} else if (Z_TYPE_P(value) == IS_BOOL) {
1946-
*flags |= MEMC_VAL_IS_BOOL;
1954+
MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_BOOL);
19471955
}
19481956
break;
19491957
}
19501958

19511959
default:
1952-
{
1960+
switch (serializer) {
19531961
#if HAVE_MEMCACHED_IGBINARY
1954-
if (*flags & MEMC_VAL_IGBINARY) {
1955-
igbinary_serialize((uint8_t **) &buf.c, &buf.len, value);
1962+
case SERIALIZER_IGBINARY:
1963+
igbinary_serialize((uint8_t **) &buf.c, &buf.len, value);
1964+
MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_IGBINARY);
1965+
break;
1966+
#endif
19561967

1957-
} else {
1968+
#if HAVE_JSON_API
1969+
case SERIALIZER_JSON:
1970+
{
1971+
php_json_encode(&buf, value TSRMLS_CC);
1972+
buf.c[buf.len] = 0;
1973+
MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_JSON);
1974+
break;
1975+
}
19581976
#endif
1959-
php_serialize_data_t var_hash;
1960-
PHP_VAR_SERIALIZE_INIT(var_hash);
1961-
php_var_serialize(&buf, &value, &var_hash TSRMLS_CC);
1962-
PHP_VAR_SERIALIZE_DESTROY(var_hash);
1963-
1964-
if (!buf.c) {
1965-
php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not serialize value");
1966-
smart_str_free(&buf);
1967-
return NULL;
1977+
default:
1978+
{
1979+
php_serialize_data_t var_hash;
1980+
PHP_VAR_SERIALIZE_INIT(var_hash);
1981+
php_var_serialize(&buf, &value, &var_hash TSRMLS_CC);
1982+
PHP_VAR_SERIALIZE_DESTROY(var_hash);
1983+
1984+
if (!buf.c) {
1985+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not serialize value");
1986+
smart_str_free(&buf);
1987+
return NULL;
1988+
}
1989+
1990+
MEMC_VAL_SET_TYPE(*flags, MEMC_VAL_IS_SERIALIZED);
1991+
break;
19681992
}
1969-
#if HAVE_MEMCACHED_IGBINARY
19701993
}
1971-
#endif
19721994

1973-
*flags |= MEMC_VAL_SERIALIZED;
19741995
break;
1975-
}
19761996
}
19771997

19781998
/* turn off compression for values below the threshold */
@@ -2051,25 +2071,31 @@ static int php_memc_zval_from_payload(zval *value, char *payload, size_t payload
20512071
}
20522072
}
20532073

2054-
if (flags & MEMC_VAL_SERIALIZED) {
2074+
payload[payload_len] = 0;
20552075

2056-
if (flags & MEMC_VAL_IGBINARY) {
2057-
#if HAVE_MEMCACHED_IGBINARY
2058-
if (igbinary_unserialize((uint8_t *)payload, payload_len, &value)) {
2059-
ZVAL_FALSE(value);
2076+
switch (MEMC_VAL_GET_TYPE(flags)) {
20602077

2061-
if (flags & MEMC_VAL_COMPRESSED) {
2062-
efree(payload);
2063-
}
2078+
case MEMC_VAL_IS_STRING:
2079+
ZVAL_STRINGL(value, payload, payload_len, 1);
2080+
break;
2081+
case MEMC_VAL_IS_LONG:
2082+
{
2083+
long lval = strtol(payload, NULL, 10);
2084+
ZVAL_LONG(value, lval);
2085+
break;
2086+
}
2087+
case MEMC_VAL_IS_DOUBLE:
2088+
{
2089+
double dval = zend_strtod(payload, NULL);
2090+
ZVAL_DOUBLE(value, dval);
2091+
break;
2092+
}
2093+
case MEMC_VAL_IS_BOOL:
2094+
ZVAL_BOOL(value, payload_len > 0 && payload[0] == '1');
2095+
break;
20642096

2065-
php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not unserialize value with igbinary");
2066-
return -1;
2067-
}
2068-
#else
2069-
php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not unserialize value, no igbinary support");
2070-
return -1;
2071-
#endif
2072-
} else {
2097+
case MEMC_VAL_IS_SERIALIZED:
2098+
{
20732099
const char *payload_tmp = payload;
20742100
php_unserialize_data_t var_hash;
20752101

@@ -2084,20 +2110,42 @@ static int php_memc_zval_from_payload(zval *value, char *payload, size_t payload
20842110
return -1;
20852111
}
20862112
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
2113+
break;
20872114
}
2088-
} else {
2089-
payload[payload_len] = 0;
2090-
if (flags & MEMC_VAL_IS_LONG) {
2091-
long lval = strtol(payload, NULL, 10);
2092-
ZVAL_LONG(value, lval);
2093-
} else if (flags & MEMC_VAL_IS_DOUBLE) {
2094-
double dval = zend_strtod(payload, NULL);
2095-
ZVAL_DOUBLE(value, dval);
2096-
} else if (flags & MEMC_VAL_IS_BOOL) {
2097-
ZVAL_BOOL(value, payload_len > 0 && payload[0] == '1');
2098-
} else {
2099-
ZVAL_STRINGL(value, payload, payload_len, 1);
2100-
}
2115+
2116+
case MEMC_VAL_IS_IGBINARY:
2117+
#if HAVE_MEMCACHED_IGBINARY
2118+
if (igbinary_unserialize((uint8_t *)payload, payload_len, &value)) {
2119+
ZVAL_FALSE(value);
2120+
2121+
if (flags & MEMC_VAL_COMPRESSED) {
2122+
efree(payload);
2123+
}
2124+
2125+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not unserialize value with igbinary");
2126+
return -1;
2127+
}
2128+
#else
2129+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not unserialize value, no igbinary support");
2130+
return -1;
2131+
#endif
2132+
break;
2133+
2134+
case MEMC_VAL_IS_JSON:
2135+
#if HAVE_JSON_API
2136+
php_json_decode(value, payload, payload_len, 0 TSRMLS_CC);
2137+
#else
2138+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not unserialize value, no json support");
2139+
return -1;
2140+
#endif
2141+
break;
2142+
2143+
default:
2144+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "unknown payload type");
2145+
if (flags & MEMC_VAL_COMPRESSED) {
2146+
efree(payload);
2147+
}
2148+
return -1;
21012149
}
21022150

21032151
if (flags & MEMC_VAL_COMPRESSED) {
@@ -2199,7 +2247,7 @@ static memcached_return php_memc_do_cache_callback(zval *memc_obj, zend_fcall_in
21992247

22002248
convert_to_boolean(retval);
22012249
if (Z_BVAL_P(retval) == 1) {
2202-
payload = php_memc_zval_to_payload(value, &payload_len, &flags TSRMLS_CC);
2250+
payload = php_memc_zval_to_payload(value, &payload_len, &flags, i_obj->serializer TSRMLS_CC);
22032251
if (payload == NULL) {
22042252
status = MEMC_RES_PAYLOAD_FAILURE;
22052253
} else {
@@ -2827,6 +2875,7 @@ static void php_memc_register_constants(INIT_FUNC_ARGS)
28272875
*/
28282876
REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_PHP, SERIALIZER_PHP);
28292877
REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_IGBINARY, SERIALIZER_IGBINARY);
2878+
REGISTER_MEMC_CLASS_CONST_LONG(SERIALIZER_JSON, SERIALIZER_JSON);
28302879

28312880
/*
28322881
* Flags.

php_memcached.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ extern ps_module ps_mod_memcached;
6666
PS_FUNCS(memcached);
6767
#endif
6868

69+
/* json serializer */
70+
#if (PHP_MAJOR_VERSION > 5) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 2) || (PHP_MAJOR_VERSION ==5 && PHP_MINOR_VERSION == 2 && PHP_RELEASE_VERSION > 9)
71+
#define HAVE_JSON_API 1
72+
#endif
73+
6974
#endif /* PHP_MEMCACHED_H */
7075

7176

0 commit comments

Comments
 (0)