[security][CVE-2022-27809] Builtins should always take int64_t, not int
[hiphop-php.git] / hphp / runtime / ext / memcached / ext_memcached.cpp
blob30546d5ca564e30fcd66b979018d6a100de66e17
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010 Hyves (http://www.hyves.nl) |
6 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
7 | Copyright (c) 1997-2010 The PHP Group |
8 +----------------------------------------------------------------------+
9 | This source file is subject to version 3.01 of the PHP license, |
10 | that is bundled with this package in the file LICENSE, and is |
11 | available through the world-wide-web at the following url: |
12 | http://www.php.net/license/3_01.txt |
13 | If you did not receive a copy of the PHP license and are unable to |
14 | obtain it through the world-wide-web, please send a note to |
15 | license@php.net so we can mail you a copy immediately. |
16 +----------------------------------------------------------------------+
19 #include "hphp/runtime/base/array-init.h"
20 #include "hphp/runtime/base/array-iterator.h"
21 #include "hphp/runtime/ext/extension.h"
22 #include "hphp/runtime/vm/native-data.h"
23 #include "hphp/runtime/ext/memcached/libmemcached_portability.h"
24 #include "hphp/runtime/base/builtin-functions.h"
25 #include "hphp/runtime/ext/json/ext_json.h"
26 #include "hphp/util/rds-local.h"
27 #include <map>
28 #include <memory>
29 #include <vector>
30 #include <fastlz.h>
31 #include <zlib.h>
33 #include "hphp/system/systemlib.h"
35 namespace HPHP {
36 ///////////////////////////////////////////////////////////////////////////////
38 // Payload value flags
39 #define MEMC_VAL_TYPE_MASK 0xf
41 #define MEMC_VAL_IS_STRING 0
42 #define MEMC_VAL_IS_LONG 1
43 #define MEMC_VAL_IS_DOUBLE 2
44 #define MEMC_VAL_IS_BOOL 3
45 #define MEMC_VAL_IS_SERIALIZED 4
46 #define MEMC_VAL_IS_IGBINARY 5
47 #define MEMC_VAL_IS_JSON 6
49 #define MEMC_VAL_COMPRESSED (1<<4)
50 #define MEMC_VAL_COMPRESSION_ZLIB (1<<5)
51 #define MEMC_VAL_COMPRESSION_FASTLZ (1<<6)
53 #define MEMC_COMPRESS_THRESHOLD 100
55 #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x00052000
56 # define MEMCACHED_SERVER_TEMPORARILY_DISABLED (1024 << 2)
57 #endif
59 #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x01000002
60 # define HAVE_MEMCACHED_TOUCH 1
61 #endif
63 // Class options
64 const int64_t q_Memcached$$OPT_COMPRESSION = -1001;
65 const int64_t q_Memcached$$OPT_PREFIX_KEY = -1002;
66 const int64_t q_Memcached$$OPT_SERIALIZER = -1003;
68 // Our result codes
69 const int64_t q_Memcached$$RES_PAYLOAD_FAILURE = -1001;
71 // Serializer types
72 const int64_t q_Memcached$$SERIALIZER_PHP = 1;
73 const int64_t q_Memcached$$SERIALIZER_IGBINARY = 2;
74 const int64_t q_Memcached$$SERIALIZER_JSON = 3;
76 // Flags
77 const int64_t q_Memcached$$GET_PRESERVE_ORDER = 1;
79 // Keys
80 const StaticString
81 s_key("key"),
82 s_value("value"),
83 s_cas("cas");
85 // INI settings
86 struct MEMCACHEDGlobals final {
87 std::string sess_prefix;
90 static RDS_LOCAL_NO_CHECK(MEMCACHEDGlobals*, s_memcached_globals){nullptr};
91 #define MEMCACHEDG(name) (*s_memcached_globals)->name
93 namespace {
94 struct MemcachedResultWrapper {
95 memcached_result_st value;
96 explicit MemcachedResultWrapper(memcached_st *memcached) {
97 memcached_result_create(memcached, &value);
99 ~MemcachedResultWrapper() {
100 memcached_result_free(&value);
106 * Since libmemcachd is in C, we cannot use lambda functions as lambda functions
107 * are special typed and normally passed by templated types.
109 static memcached_return_t memcached_dump_callback(const memcached_st*,
110 const char* key,
111 size_t len, void* context) {
112 ((Array*)context)->append(Variant{makeStaticString(key, len)});
113 return MEMCACHED_SUCCESS;
116 const StaticString s_MemcachedData("MemcachedData");
118 struct MemcachedData {
119 struct Impl {
120 Impl() :
121 compression(true),
122 serializer(q_Memcached$$SERIALIZER_PHP),
123 rescode(MEMCACHED_SUCCESS) {
124 memcached_create(&memcached);
126 ~Impl() {
127 memcached_free(&memcached);
130 memcached_st memcached;
131 bool compression;
132 int serializer;
133 int rescode;
134 bool is_persistent;
135 bool is_pristine;
137 MemcachedData() {}
138 ~MemcachedData() {}
140 typedef std::shared_ptr<Impl> ImplPtr;
141 ImplPtr m_impl;
143 bool handleError(memcached_return status) {
144 switch (status) {
145 case MEMCACHED_SUCCESS:
146 case MEMCACHED_STORED:
147 case MEMCACHED_DELETED:
148 case MEMCACHED_STAT:
149 return true;
150 case MEMCACHED_END:
151 case MEMCACHED_BUFFERED:
152 m_impl->rescode = status;
153 return true;
154 default:
155 m_impl->rescode = status;
156 return false;
159 void toPayload(const Variant& value, std::vector<char> &payload,
160 uint32_t &flags) {
161 String encoded;
162 if (value.isString() || value.isNumeric()) {
163 encoded = value.toString();
164 if (value.isString()) flags = MEMC_VAL_IS_STRING;
165 else if (value.isInteger()) flags = MEMC_VAL_IS_LONG;
166 else if (value.isDouble()) flags = MEMC_VAL_IS_DOUBLE;
167 else if (value.isBoolean()) flags = MEMC_VAL_IS_BOOL;
168 else not_reached();
169 } else {
170 switch (m_impl->serializer) {
171 case q_Memcached$$SERIALIZER_JSON:
172 encoded = Variant::attach(HHVM_FN(json_encode)(value)).toString();
173 flags = MEMC_VAL_IS_JSON;
174 break;
175 default:
176 encoded = f_serialize(value);
177 flags = MEMC_VAL_IS_SERIALIZED;
178 break;
182 if (m_impl->compression && encoded.length() >= MEMC_COMPRESS_THRESHOLD) {
183 unsigned long payloadCompLength = compressBound(encoded.length());
184 payload.resize(payloadCompLength);
185 if (compress((Bytef*)payload.data(), &payloadCompLength,
186 (const Bytef*)encoded.data(), encoded.length()) == Z_OK) {
187 payload.resize(payloadCompLength);
188 flags |= MEMC_VAL_COMPRESSED;
189 return;
191 raise_warning("could not compress value");
194 payload.resize(0);
195 payload.insert(payload.end(),
196 encoded.data(), encoded.data() + encoded.length());
198 bool toObject(Variant& value, const memcached_result_st &result) {
199 const char *payload = memcached_result_value(&result);
200 size_t payloadLength = memcached_result_length(&result);
201 uint32_t flags = memcached_result_flags(&result);
203 String decompPayload;
204 if (flags & MEMC_VAL_COMPRESSED) {
205 bool done = false;
206 std::vector<char> buffer;
207 unsigned long bufferSize;
208 uint32_t maxLength;
209 int status;
211 /* new-style */
212 if ((flags & MEMC_VAL_COMPRESSION_FASTLZ ||
213 flags & MEMC_VAL_COMPRESSION_ZLIB)
214 && payloadLength > sizeof(uint32_t)) {
215 memcpy(&maxLength, payload, sizeof(uint32_t));
216 if (maxLength < std::numeric_limits<uint32_t>::max()) {
217 buffer.resize(maxLength + 1);
218 payloadLength -= sizeof(uint32_t);
219 payload += sizeof(uint32_t);
220 bufferSize = maxLength;
222 if (flags & MEMC_VAL_COMPRESSION_FASTLZ) {
223 bufferSize = fastlz_decompress(payload, payloadLength,
224 buffer.data(), maxLength);
225 done = (bufferSize > 0);
226 } else if (flags & MEMC_VAL_COMPRESSION_ZLIB) {
227 status = uncompress((Bytef *)buffer.data(), &bufferSize,
228 (const Bytef *)payload, (uLong)payloadLength);
229 done = (status == Z_OK);
234 /* old-style */
235 if (!done) {
236 for (int factor = 1; factor <= 16; ++factor) {
237 if (payloadLength >=
238 std::numeric_limits<unsigned long>::max() / (1 << factor)) {
239 break;
241 bufferSize = payloadLength * (1 << factor) + 1;
242 buffer.resize(bufferSize);
243 status = uncompress((Bytef*)buffer.data(), &bufferSize,
244 (const Bytef*)payload, (uLong)payloadLength);
245 if (status == Z_OK) {
246 done = true;
247 break;
248 } else if (status != Z_BUF_ERROR) {
249 break;
253 if (!done) {
254 raise_warning("could not uncompress value");
255 return false;
257 decompPayload =
258 String::attach(StringData::Make(buffer.data(), bufferSize, CopyString));
259 } else {
260 decompPayload =
261 String::attach(StringData::Make(payload, payloadLength, CopyString));
264 switch (flags & MEMC_VAL_TYPE_MASK) {
265 case MEMC_VAL_IS_STRING:
266 value = decompPayload;
267 break;
268 case MEMC_VAL_IS_LONG:
269 value = decompPayload.toInt64();
270 break;
271 case MEMC_VAL_IS_DOUBLE:
272 value = decompPayload.toDouble();
273 break;
274 case MEMC_VAL_IS_BOOL:
275 value = decompPayload.toBoolean();
276 break;
277 case MEMC_VAL_IS_JSON:
278 value = Variant::attach(HHVM_FN(json_decode)(decompPayload));
279 break;
280 case MEMC_VAL_IS_SERIALIZED:
281 value = unserialize_from_string(
282 decompPayload,
283 VariableUnserializer::Type::Serialize
285 break;
286 case MEMC_VAL_IS_IGBINARY:
287 raise_warning("could not unserialize value, no igbinary support");
288 return false;
289 default:
290 raise_warning("unknown payload type");
291 return false;
293 return true;
295 bool getMultiImpl(const String& server_key, const Array& keys, bool enableCas,
296 Array *returnValue) {
297 std::vector<const char*> keysCopy;
298 keysCopy.reserve(keys.size());
299 std::vector<size_t> keysLengthCopy;
300 keysLengthCopy.reserve(keys.size());
301 for (ArrayIter iter(keys); iter; ++iter) {
302 Variant vKey = iter.second();
303 if (!vKey.isString()) continue;
304 StringData *key = vKey.getStringData();
305 if (key->empty()) continue;
306 keysCopy.push_back(key->data());
307 keysLengthCopy.push_back(key->size());
308 if (returnValue) returnValue->set(String(key), init_null(), true);
310 if (keysCopy.size() == 0) {
311 m_impl->rescode = MEMCACHED_BAD_KEY_PROVIDED;
312 return false;
315 memcached_behavior_set(&m_impl->memcached, MEMCACHED_BEHAVIOR_SUPPORT_CAS,
316 enableCas ? 1 : 0);
317 const char *myServerKey = server_key.empty() ? nullptr : server_key.c_str();
318 size_t myServerKeyLen = server_key.length();
319 return handleError(memcached_mget_by_key(&m_impl->memcached,
320 myServerKey, myServerKeyLen, keysCopy.data(), keysLengthCopy.data(),
321 keysCopy.size()));
323 bool fetchImpl(memcached_result_st &result, Array &item) {
324 memcached_return status;
325 if (!memcached_fetch_result(&m_impl->memcached, &result, &status)) {
326 handleError(status);
327 return false;
330 Variant value;
331 if (!toObject(value, result)) {
332 m_impl->rescode = q_Memcached$$RES_PAYLOAD_FAILURE;
333 return false;
336 const char *key = memcached_result_key_value(&result);
337 size_t keyLength = memcached_result_key_length(&result);
338 String sKey(key, keyLength, CopyString);
339 double cas = (double) memcached_result_cas(&result);
341 item = make_dict_array(s_key, sKey, s_value, value, s_cas, cas);
342 return true;
344 typedef memcached_return_t (*SetOperation)(memcached_st *,
345 const char *, size_t, const char *, size_t, const char *, size_t,
346 time_t, uint32_t);
348 bool setOperationImpl(SetOperation op, const String& server_key,
349 const String& key, const Variant& value,
350 int expiration) {
351 m_impl->rescode = MEMCACHED_SUCCESS;
352 if (key.empty()) {
353 m_impl->rescode = MEMCACHED_BAD_KEY_PROVIDED;
354 return false;
357 std::vector<char> payload; uint32_t flags;
358 toPayload(value, payload, flags);
360 const String& myServerKey = server_key.empty() ? key : server_key;
361 return handleError(op(&m_impl->memcached, myServerKey.c_str(),
362 myServerKey.length(), key.c_str(), key.length(),
363 payload.data(), payload.size(), expiration, flags));
366 Variant incDecOp(bool isInc,
367 const StringData* server_key, const StringData* key,
368 int64_t offset, const Variant& initial_value, int64_t expiry) {
369 m_impl->rescode = MEMCACHED_SUCCESS;
370 if (key->empty() || strchr(key->data(), ' ')) {
371 m_impl->rescode = MEMCACHED_BAD_KEY_PROVIDED;
372 return false;
374 if (offset < 0) {
375 raise_warning("offset has to be >= 0");
376 return false;
379 // Dispatch to the correct memcached_* function depending on initial_value,
380 // server_key, and isInc.
381 uint64_t value;
382 memcached_return_t status;
384 bool use_initial = initial_value.isInteger();
385 auto mc = &m_impl->memcached;
386 if (use_initial) {
387 if (!isBinaryProtocol()) {
388 raise_warning("Initial value is only supported with binary protocol");
389 return false;
392 if (server_key) {
393 if (isInc) {
394 status = memcached_increment_with_initial_by_key(
396 server_key->data(), server_key->size(), key->data(), key->size(),
397 offset, initial_value.asInt64Val(), expiry, &value);
398 } else {
399 status = memcached_decrement_with_initial_by_key(
401 server_key->data(), server_key->size(), key->data(), key->size(),
402 offset, initial_value.asInt64Val(), expiry, &value);
404 } else {
405 if (isInc) {
406 status = memcached_increment_with_initial(
407 mc, key->data(), key->size(),
408 offset, initial_value.asInt64Val(), expiry, &value);
409 } else {
410 status = memcached_decrement_with_initial(
411 mc, key->data(), key->size(),
412 offset, initial_value.asInt64Val(), expiry, &value);
415 } else {
416 if (server_key) {
417 if (isInc) {
418 status = memcached_increment_by_key(
420 server_key->data(), server_key->size(), key->data(), key->size(),
421 offset, &value);
422 } else {
423 status = memcached_decrement_by_key(
425 server_key->data(), server_key->size(), key->data(), key->size(),
426 offset, &value);
428 } else {
429 if (isInc) {
430 status = memcached_increment(
431 mc, key->data(), key->size(), offset, &value);
432 } else {
433 status = memcached_decrement(
434 mc, key->data(), key->size(), offset, &value);
439 if (!handleError(status)) return false;
440 return (int64_t)value;
443 bool isBinaryProtocol() {
444 return memcached_behavior_get(&m_impl->memcached,
445 MEMCACHED_BEHAVIOR_BINARY_PROTOCOL);
448 typedef std::map<std::string, ImplPtr> ImplMap;
449 static RDS_LOCAL(ImplMap, s_persistentMap);
452 void HHVM_METHOD(Memcached, __construct,
453 const Variant& persistent_id /*= null*/) {
454 auto data = Native::data<MemcachedData>(this_);
455 if (persistent_id.isNull()) {
456 data->m_impl.reset(new MemcachedData::Impl);
457 data->m_impl->is_persistent = false;
458 data->m_impl->is_pristine = true;
459 } else {
460 bool is_pristine = false;
461 MemcachedData::ImplPtr &impl = (*data->s_persistentMap)[
462 persistent_id.toString().toCppString()
464 if (!impl) {
465 impl.reset(new MemcachedData::Impl);
466 is_pristine = true;
468 data->m_impl = impl;
469 data->m_impl->is_persistent = true;
470 data->m_impl->is_pristine = is_pristine;
474 bool HHVM_METHOD(Memcached, quit) {
475 auto data = Native::data<MemcachedData>(this_);
476 memcached_quit(&data->m_impl->memcached);
477 return true;
480 Variant HHVM_METHOD(Memcached, getallkeys) {
481 auto data = Native::data<MemcachedData>(this_);
482 memcached_dump_fn callbacks[] = {
483 &memcached_dump_callback,
486 Array allKeys;
487 memcached_return status = memcached_dump(&data->m_impl->memcached, callbacks,
488 &allKeys,
489 sizeof(callbacks) /
490 sizeof(memcached_dump_fn));
491 if (!data->handleError(status)) {
492 return false;
495 return allKeys;
498 namespace {
499 Variant getByKeyImpl(ObjectData* const this_, const String& server_key,
500 const String& key, const Variant& cache_cb,
501 Variant* cas_token) {
502 auto data = Native::data<MemcachedData>(this_);
503 data->m_impl->rescode = MEMCACHED_SUCCESS;
504 if (key.empty()) {
505 data->m_impl->rescode = MEMCACHED_BAD_KEY_PROVIDED;
506 return false;
509 memcached_behavior_set(&data->m_impl->memcached,
510 MEMCACHED_BEHAVIOR_SUPPORT_CAS,
511 cas_token ? 1 : 0);
512 const char *myServerKey = server_key.empty() ? nullptr : server_key.c_str();
513 size_t myServerKeyLen = server_key.length();
514 const char *myKey = key.c_str();
515 size_t myKeyLen = key.length();
516 memcached_return status = memcached_mget_by_key(&data->m_impl->memcached,
517 myServerKey, myServerKeyLen, &myKey, &myKeyLen, 1);
518 if (!data->handleError(status)) return false;
520 Variant returnValue;
521 MemcachedResultWrapper result(&data->m_impl->memcached);
522 if (!memcached_fetch_result(&data->m_impl->memcached,
523 &result.value, &status)) {
524 if (status == MEMCACHED_END) status = MEMCACHED_NOTFOUND;
525 if (status == MEMCACHED_NOTFOUND && !cache_cb.isNull()) {
526 raise_warning("Memcached::getbykey() no longer supports callbacks");
528 data->handleError(status);
529 return false;
532 if (!data->toObject(returnValue, result.value)) {
533 data->m_impl->rescode = q_Memcached$$RES_PAYLOAD_FAILURE;
534 return false;
536 if (cas_token) {
537 *cas_token = (double) memcached_result_cas(&result.value);
539 return returnValue;
542 Variant getMultiByKeyImpl(ObjectData* const this_, const String& server_key,
543 const Array& keys, Variant* cas_tokens, int flags) {
544 auto data = Native::data<MemcachedData>(this_);
545 data->m_impl->rescode = MEMCACHED_SUCCESS;
547 bool preserveOrder = flags & q_Memcached$$GET_PRESERVE_ORDER;
548 Array returnValue = Array::CreateDict();
549 if (!data->getMultiImpl(server_key, keys, cas_tokens,
550 preserveOrder ? &returnValue : nullptr)) {
551 return false;
554 Array cas_tokens_arr;
555 SCOPE_EXIT {
556 if (cas_tokens) {
557 *cas_tokens = cas_tokens_arr;
561 MemcachedResultWrapper result(&data->m_impl->memcached);
562 memcached_return status;
563 while (memcached_fetch_result(&data->m_impl->memcached, &result.value,
564 &status)) {
565 if (status != MEMCACHED_SUCCESS) {
566 status = MEMCACHED_SOME_ERRORS;
567 data->handleError(status);
568 continue;
570 Variant value;
571 if (!data->toObject(value, result.value)) {
572 data->m_impl->rescode = q_Memcached$$RES_PAYLOAD_FAILURE;
573 return false;
575 const char *key = memcached_result_key_value(&result.value);
576 size_t keyLength = memcached_result_key_length(&result.value);
577 String sKey(key, keyLength, CopyString);
578 returnValue.set(sKey, value, true);
579 if (cas_tokens) {
580 double cas = (double) memcached_result_cas(&result.value);
581 cas_tokens_arr.set(sKey, cas, true);
584 return returnValue;
586 } // anonymous namespace
588 Variant HHVM_METHOD(Memcached, getbykey, const String& server_key,
589 const String& key,
590 const Variant& cache_cb /*= null*/) {
591 return getByKeyImpl(this_, server_key, key, cache_cb, nullptr);
594 Variant HHVM_METHOD(Memcached, getbykeywithcastoken,
595 const String& server_key,
596 const String& key,
597 const Variant& cache_cb,
598 Variant& cas_token) {
599 return getByKeyImpl(this_, server_key, key, cache_cb, &cas_token);
602 Variant HHVM_METHOD(Memcached, getmultibykey, const String& server_key,
603 const Array& keys,
604 int64_t flags /*= 0*/) {
605 return getMultiByKeyImpl(this_, server_key, keys, nullptr, flags);
608 Variant HHVM_METHOD(Memcached, getmultibykeywithcastokens,
609 const String& server_key,
610 const Array& keys,
611 Variant& cas_tokens,
612 int64_t flags /*= 0*/) {
613 return getMultiByKeyImpl(this_, server_key, keys, &cas_tokens, flags);
616 bool HHVM_METHOD(Memcached, getdelayedbykey, const String& server_key,
617 const Array& keys, bool with_cas /*= false*/,
618 const Variant& value_cb /*= uninit_variant*/) {
619 auto data = Native::data<MemcachedData>(this_);
620 data->m_impl->rescode = MEMCACHED_SUCCESS;
622 if (!data->getMultiImpl(server_key, keys, with_cas, nullptr)) return false;
623 if (value_cb.isNull()) return true;
625 MemcachedResultWrapper result(&data->m_impl->memcached); Array item;
626 while (data->fetchImpl(result.value, item)) {
627 vm_call_user_func(value_cb, make_vec_array(Variant(this_), item));
630 if (data->m_impl->rescode != MEMCACHED_END) return false;
631 data->m_impl->rescode = MEMCACHED_SUCCESS;
632 return true;
635 Variant HHVM_METHOD(Memcached, fetch) {
636 auto data = Native::data<MemcachedData>(this_);
637 data->m_impl->rescode = MEMCACHED_SUCCESS;
639 MemcachedResultWrapper result(&data->m_impl->memcached); Array item;
640 if (!data->fetchImpl(result.value, item)) return false;
642 return item;
645 Variant HHVM_METHOD(Memcached, fetchall) {
646 auto data = Native::data<MemcachedData>(this_);
647 data->m_impl->rescode = MEMCACHED_SUCCESS;
649 Array returnValue;
650 MemcachedResultWrapper result(&data->m_impl->memcached); Array item;
651 while (data->fetchImpl(result.value, item)) {
652 returnValue.append(item);
655 if (data->m_impl->rescode != MEMCACHED_END) return false;
656 return returnValue;
659 bool HHVM_METHOD(Memcached, setbykey, const String& server_key,
660 const String& key, const Variant& value,
661 int64_t expiration /*= 0*/) {
662 auto data = Native::data<MemcachedData>(this_);
663 return data->setOperationImpl(memcached_set_by_key, server_key, key, value,
664 expiration);
667 bool HHVM_METHOD(Memcached, addbykey, const String& server_key,
668 const String& key, const Variant& value,
669 int64_t expiration /*= 0*/) {
670 auto data = Native::data<MemcachedData>(this_);
671 return data->setOperationImpl(memcached_add_by_key, server_key, key, value,
672 expiration);
675 bool HHVM_METHOD(Memcached, appendbykey, const String& server_key,
676 const String& key,
677 const String& value) {
678 auto data = Native::data<MemcachedData>(this_);
679 if (data->m_impl->compression) {
680 raise_warning("cannot append/prepend with compression turned on");
681 return false;
683 return data->setOperationImpl(memcached_append_by_key, server_key, key,
684 value, 0);
687 bool HHVM_METHOD(Memcached, prependbykey, const String& server_key,
688 const String& key,
689 const String& value) {
690 auto data = Native::data<MemcachedData>(this_);
691 if (data->m_impl->compression) {
692 raise_warning("cannot append/prepend with compression turned on");
693 return false;
695 return data->setOperationImpl(memcached_prepend_by_key, server_key, key,
696 value, 0);
699 bool HHVM_METHOD(Memcached, replacebykey, const String& server_key,
700 const String& key,
701 const Variant& value,
702 int64_t expiration /*= 0*/) {
703 auto data = Native::data<MemcachedData>(this_);
704 return data->setOperationImpl(memcached_replace_by_key, server_key, key,
705 value, expiration);
708 bool HHVM_METHOD(Memcached, casbykey, double cas_token,
709 const String& server_key,
710 const String& key,
711 const Variant& value,
712 int64_t expiration /*= 0*/) {
713 auto data = Native::data<MemcachedData>(this_);
714 data->m_impl->rescode = MEMCACHED_SUCCESS;
715 if (key.empty()) {
716 data->m_impl->rescode = MEMCACHED_BAD_KEY_PROVIDED;
717 return false;
720 std::vector<char> payload; uint32_t flags;
721 data->toPayload(value, payload, flags);
723 const String& myServerKey = server_key.empty() ? key : server_key;
724 return data->handleError(memcached_cas_by_key(&data->m_impl->memcached,
725 myServerKey.c_str(), myServerKey.length(), key.c_str(), key.length(),
726 payload.data(), payload.size(), expiration, flags, (uint64_t)cas_token));
729 bool HHVM_METHOD(Memcached, deletebykey, const String& server_key,
730 const String& key,
731 int64_t time /*= 0*/) {
732 auto data = Native::data<MemcachedData>(this_);
733 data->m_impl->rescode = MEMCACHED_SUCCESS;
734 if (key.empty()) {
735 data->m_impl->rescode = MEMCACHED_BAD_KEY_PROVIDED;
736 return false;
739 const String& myServerKey = server_key.empty() ? key : server_key;
740 return data->handleError(memcached_delete_by_key(&data->m_impl->memcached,
741 myServerKey.c_str(), myServerKey.length(),
742 key.c_str(), key.length(), time));
745 Variant HHVM_METHOD(Memcached, deletemultibykey, const String& server_key,
746 const Array& keys,
747 int64_t time /*= 0*/) {
748 auto data = Native::data<MemcachedData>(this_);
749 data->m_impl->rescode = MEMCACHED_SUCCESS;
751 memcached_return status_memcached;
752 bool status;
753 Array returnValue = Array::CreateDict();
754 for (ArrayIter iter(keys); iter; ++iter) {
755 Variant vKey = iter.second();
756 if (!vKey.isString()) continue;
757 const String& key = vKey.toString();
758 if (key.empty()) continue;
759 const String& myServerKey = server_key.empty() ? key : server_key;
760 status_memcached = memcached_delete_by_key(&data->m_impl->memcached,
761 myServerKey.c_str(), myServerKey.length(),
762 key.c_str(), key.length(), time);
764 status = data->handleError(status_memcached);
765 if (!status) {
766 returnValue.set(key, status_memcached, true);
767 } else {
768 returnValue.set(key, status, true);
771 return returnValue;
774 Variant HHVM_METHOD(Memcached, increment,
775 const String& key,
776 int64_t offset /* = 1 */,
777 const Variant& initial_value /* = false */,
778 int64_t expiry /* = 0 */) {
779 return Native::data<MemcachedData>(this_)->incDecOp(
780 true, nullptr, key.get(), offset, initial_value, expiry);
783 Variant HHVM_METHOD(Memcached, incrementbykey,
784 const String& server_key,
785 const String& key,
786 int64_t offset /* = 1 */,
787 const Variant& initial_value /* = false */,
788 int64_t expiry /* = 0 */) {
789 return Native::data<MemcachedData>(this_)->incDecOp(
790 true, server_key.get(), key.get(), offset, initial_value, expiry);
793 Variant HHVM_METHOD(Memcached, decrement,
794 const String& key,
795 int64_t offset /* = 1 */,
796 const Variant& initial_value /* = false */,
797 int64_t expiry /* = 0 */) {
798 return Native::data<MemcachedData>(this_)->incDecOp(
799 false, nullptr, key.get(), offset, initial_value, expiry);
802 Variant HHVM_METHOD(Memcached, decrementbykey,
803 const String& server_key,
804 const String& key,
805 int64_t offset /* = 1 */,
806 const Variant& initial_value /* = false */,
807 int64_t expiry /* = 0 */) {
808 return Native::data<MemcachedData>(this_)->incDecOp(
809 false, server_key.get(), key.get(), offset, initial_value, expiry);
812 bool HHVM_METHOD(Memcached, addserver, const String& host, int64_t port,
813 int64_t weight /*= 0*/) {
814 auto data = Native::data<MemcachedData>(this_);
815 data->m_impl->rescode = MEMCACHED_SUCCESS;
816 if (!host.empty() && host[0] == '/') {
817 return data->handleError(memcached_server_add_unix_socket_with_weight(
818 &data->m_impl->memcached, host.c_str(), weight));
819 } else {
820 return data->handleError(memcached_server_add_with_weight(
821 &data->m_impl->memcached, host.c_str(), port, weight
826 namespace {
828 const StaticString s_host("host"), s_port("port");
829 #ifdef LMCD_SERVER_QUERY_INCLUDES_WEIGHT
830 const StaticString s_weight("weight");
831 #endif
833 memcached_return_t
834 doServerListCallback(const memcached_st* /*ptr*/,
835 LMCD_SERVER_CALLBACK_INSTANCE_TYPE server, void* context) {
836 Array *returnValue = (Array*) context;
837 const char* hostname = LMCD_SERVER_HOSTNAME(server);
838 in_port_t port = LMCD_SERVER_PORT(server);
839 #ifdef LMCD_SERVER_QUERY_INCLUDES_WEIGHT
840 returnValue->append(make_dict_array(
841 s_host, String(hostname, CopyString),
842 s_port, (int32_t)port,
843 s_weight, (int32_t)server->weight
845 #else
846 returnValue->append(make_dict_array(
847 s_host, String(hostname, CopyString),
848 s_port, (int32_t)port
850 #endif
851 return MEMCACHED_SUCCESS;
855 Array HHVM_METHOD(Memcached, getserverlist) {
856 auto data = Native::data<MemcachedData>(this_);
857 Array returnValue = Array::CreateVec();
858 memcached_server_function callbacks[] = { doServerListCallback };
859 memcached_server_cursor(&data->m_impl->memcached, callbacks, &returnValue, 1);
860 return returnValue;
863 bool HHVM_METHOD(Memcached, resetserverlist) {
864 auto data = Native::data<MemcachedData>(this_);
865 memcached_servers_reset(&data->m_impl->memcached);
866 return true;
869 Variant HHVM_METHOD(Memcached, getserverbykey, const String& server_key) {
870 auto data = Native::data<MemcachedData>(this_);
871 data->m_impl->rescode = MEMCACHED_SUCCESS;
872 if (server_key.empty()) {
873 data->m_impl->rescode = MEMCACHED_BAD_KEY_PROVIDED;
874 return false;
877 memcached_return_t error;
878 LMCD_SERVER_BY_KEY_INSTANCE_TYPE server = memcached_server_by_key(
879 &data->m_impl->memcached, server_key.c_str(), server_key.size(), &error);
880 if (!server) {
881 data->handleError(error);
882 return false;
885 const char* hostname = LMCD_SERVER_HOSTNAME(server);
886 in_port_t port = LMCD_SERVER_PORT(server);
887 #ifdef LMCD_SERVER_QUERY_INCLUDES_WEIGHT
888 return make_dict_array(
889 s_host, String(hostname, CopyString),
890 s_port, (int32_t)port,
891 s_weight, (int32_t)server->weight
893 #else
894 return make_dict_array(
895 s_host, String(hostname, CopyString),
896 s_port, (int32_t)port
898 #endif
901 namespace {
902 struct StatsContext {
903 memcached_stat_st *stats;
904 Array returnValue;
907 const StaticString
908 s_pid("pid"),
909 s_uptime("uptime"),
910 s_threads("threads"),
911 s_time("time"),
912 s_pointer_size("pointer_size"),
913 s_rusage_user_seconds("rusage_user_seconds"),
914 s_rusage_user_microseconds("rusage_user_microseconds"),
915 s_rusage_system_seconds("rusage_system_seconds"),
916 s_rusage_system_microseconds("rusage_system_microseconds"),
917 s_curr_items("curr_items"),
918 s_total_items("total_items"),
919 s_limit_maxbytes("limit_maxbytes"),
920 s_curr_connections("curr_connections"),
921 s_total_connections("total_connections"),
922 s_connection_structures("connection_structures"),
923 s_bytes("bytes"),
924 s_cmd_get("cmd_get"),
925 s_cmd_set("cmd_set"),
926 s_get_hits("get_hits"),
927 s_get_misses("get_misses"),
928 s_evictions("evictions"),
929 s_bytes_read("bytes_read"),
930 s_bytes_written("bytes_written"),
931 s_version("version");
933 memcached_return_t
934 doStatsCallback(const memcached_st* /*ptr*/,
935 LMCD_SERVER_CALLBACK_INSTANCE_TYPE server, void* inContext) {
936 StatsContext *context = (StatsContext*) inContext;
937 char key[NI_MAXHOST + 6];
938 const char* hostname = LMCD_SERVER_HOSTNAME(server);
939 in_port_t port = LMCD_SERVER_PORT(server);
940 snprintf(key, sizeof(key), "%s:%d", hostname, port);
941 memcached_stat_st *stats = context->stats;
942 ssize_t i = context->returnValue.size();
944 context->returnValue.set(String(key, CopyString),
945 make_dict_array(
946 s_pid, (int64_t)stats[i].pid,
947 s_uptime, (int64_t)stats[i].uptime,
948 s_threads, (int64_t)stats[i].threads,
949 s_time, (int64_t)stats[i].time,
950 s_pointer_size, (int64_t)stats[i].pointer_size,
951 s_rusage_user_seconds, (int64_t)stats[i].rusage_user_seconds,
952 s_rusage_user_microseconds, (int64_t)stats[i]
953 .rusage_user_microseconds,
954 s_rusage_system_seconds, (int64_t)stats[i].rusage_system_seconds,
955 s_rusage_system_microseconds, (int64_t)stats[i]
956 .rusage_system_microseconds,
957 s_curr_items, (int64_t)stats[i].curr_items,
958 s_total_items, (int64_t)stats[i].total_items,
959 s_limit_maxbytes, (int64_t)stats[i].limit_maxbytes,
960 s_curr_connections, (int64_t)stats[i].curr_connections,
961 s_total_connections, (int64_t)stats[i].total_connections,
962 s_connection_structures, (int64_t)stats[i].connection_structures,
963 s_bytes, (int64_t)stats[i].bytes,
964 s_cmd_get, (int64_t)stats[i].cmd_get,
965 s_cmd_set, (int64_t)stats[i].cmd_set,
966 s_get_hits, (int64_t)stats[i].get_hits,
967 s_get_misses, (int64_t)stats[i].get_misses,
968 s_evictions, (int64_t)stats[i].evictions,
969 s_bytes_read, (int64_t)stats[i].bytes_read,
970 s_bytes_written, (int64_t)stats[i].bytes_written,
971 s_version, String(stats[i].version, CopyString)
975 return MEMCACHED_SUCCESS;
979 Variant HHVM_METHOD(Memcached, getstats) {
980 auto data = Native::data<MemcachedData>(this_);
981 memcached_return_t error;
982 memcached_stat_st *stats = memcached_stat(&data->m_impl->memcached,
983 nullptr, &error);
984 if (!stats) {
985 data->handleError(error);
986 return false;
989 memcached_server_function callbacks[] = { doStatsCallback };
990 StatsContext context; context.stats = stats;
991 memcached_server_cursor(&data->m_impl->memcached, callbacks, &context, 1);
993 memcached_stat_free(&data->m_impl->memcached, stats);
994 return context.returnValue;
997 namespace {
998 memcached_return_t
999 doVersionCallback(const memcached_st* /*ptr*/,
1000 LMCD_SERVER_CALLBACK_INSTANCE_TYPE server, void* context) {
1001 Array *returnValue = (Array*) context;
1002 char key[NI_MAXHOST + 6], version[16];
1004 const char* hostname = LMCD_SERVER_HOSTNAME(server);
1005 in_port_t port = LMCD_SERVER_PORT(server);
1006 uint8_t majorVersion = LMCD_SERVER_MAJOR_VERSION(server);
1007 uint8_t minorVersion = LMCD_SERVER_MINOR_VERSION(server);
1008 uint8_t microVersion = LMCD_SERVER_MICRO_VERSION(server);
1010 // libmemcached starting with 0.46 use UINT8_MAX as the default version, not 0
1011 #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX <= 0x00045000
1012 if (majorVersion == 0 && minorVersion == 0 && microVersion == 0) {
1013 majorVersion = UINT8_MAX;
1014 minorVersion = UINT8_MAX;
1015 microVersion = UINT8_MAX;
1017 #endif
1019 snprintf(key, sizeof(key), "%s:%d", hostname, port);
1020 snprintf(version, sizeof(version), "%" PRIu8 ".%" PRIu8 ".%" PRIu8,
1021 majorVersion, minorVersion, microVersion);
1022 returnValue->set(String(key, CopyString), String(version, CopyString));
1023 return MEMCACHED_SUCCESS;
1027 Variant HHVM_METHOD(Memcached, getversion) {
1028 auto data = Native::data<MemcachedData>(this_);
1029 memcached_version(&data->m_impl->memcached);
1031 Array returnValue = Array::CreateDict();
1032 memcached_server_function callbacks[] = { doVersionCallback };
1033 memcached_server_cursor(&data->m_impl->memcached, callbacks, &returnValue, 1);
1034 return returnValue;
1037 bool HHVM_METHOD(Memcached, flush, int64_t delay /*= 0*/) {
1038 auto data = Native::data<MemcachedData>(this_);
1039 return data->handleError(memcached_flush(&data->m_impl->memcached, delay));
1042 Variant HHVM_METHOD(Memcached, getoption, int64_t option) {
1043 auto data = Native::data<MemcachedData>(this_);
1044 switch (option) {
1045 case q_Memcached$$OPT_COMPRESSION:
1046 return data->m_impl->compression;
1048 case q_Memcached$$OPT_PREFIX_KEY:
1050 memcached_return retval;
1051 char *result = (char*) memcached_callback_get(&data->m_impl->memcached,
1052 MEMCACHED_CALLBACK_PREFIX_KEY, &retval);
1053 if (retval == MEMCACHED_SUCCESS && result) {
1054 return String(result, CopyString);
1056 else return empty_string_variant();
1059 case q_Memcached$$OPT_SERIALIZER:
1060 return data->m_impl->serializer;
1062 case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE:
1063 case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE:
1064 if (memcached_server_count(&data->m_impl->memcached) == 0) {
1065 raise_warning("no servers defined");
1066 return init_null();
1068 // fall through
1070 default:
1071 // Assume that it's a libmemcached behavior option
1072 return (int64_t) memcached_behavior_get(&data->m_impl->memcached,
1073 (memcached_behavior_t)option);
1077 bool HHVM_METHOD(Memcached, setoption, int64_t option, const Variant& value) {
1078 auto data = Native::data<MemcachedData>(this_);
1079 switch (option) {
1080 case q_Memcached$$OPT_COMPRESSION:
1081 data->m_impl->compression = value.toBoolean();
1082 break;
1084 case q_Memcached$$OPT_PREFIX_KEY:
1086 String sValue = value.toString();
1087 char *key = const_cast<char*>(sValue.empty() ? nullptr : sValue.c_str());
1088 if (memcached_callback_set(&data->m_impl->memcached,
1089 MEMCACHED_CALLBACK_PREFIX_KEY, key) == MEMCACHED_BAD_KEY_PROVIDED) {
1090 raise_warning("bad key provided");
1091 return false;
1093 break;
1096 case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED:
1098 uint64_t lValue = value.toInt64();
1099 if (memcached_behavior_set(&data->m_impl->memcached,
1100 MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, lValue) == MEMCACHED_FAILURE) {
1101 raise_warning("error setting memcached option");
1102 return false;
1105 /* This is necessary because libmemcached doesn't reset hash/distribution
1106 * options on false case, like it does for MEMCACHED_BEHAVIOR_KETAMA
1107 * (non-weighted) case. We have to clean up ourselves.
1109 if (!lValue) {
1110 memcached_behavior_set_key_hash(&data->m_impl->memcached,
1111 MEMCACHED_HASH_DEFAULT);
1112 memcached_behavior_set_distribution_hash(&data->m_impl->memcached,
1113 MEMCACHED_HASH_DEFAULT);
1114 memcached_behavior_set_distribution(&data->m_impl->memcached,
1115 MEMCACHED_DISTRIBUTION_MODULA);
1117 break;
1120 case q_Memcached$$OPT_SERIALIZER:
1122 int iValue = value.toInt32(10);
1123 switch (iValue) {
1124 case q_Memcached$$SERIALIZER_PHP:
1125 case q_Memcached$$SERIALIZER_JSON:
1126 data->m_impl->serializer = iValue;
1127 break;
1128 default:
1129 data->m_impl->serializer = q_Memcached$$SERIALIZER_PHP;
1130 raise_warning("invalid serializer provided");
1131 return false;
1133 break;
1136 default:
1138 if ((option < 0) || (option >= MEMCACHED_BEHAVIOR_MAX)) {
1139 raise_warning("error setting memcached option");
1140 return false;
1143 // Assume that it's a libmemcached behavior option
1144 uint64_t lValue = value.toInt64();
1145 if (memcached_behavior_set(&data->m_impl->memcached,
1146 (memcached_behavior_t)option, lValue) == MEMCACHED_FAILURE) {
1147 raise_warning("error setting memcached option");
1148 return false;
1150 break;
1153 return true;
1156 int64_t HHVM_METHOD(Memcached, getresultcode) {
1157 auto data = Native::data<MemcachedData>(this_);
1158 return data->m_impl->rescode;
1161 String HHVM_METHOD(Memcached, getresultmessage) {
1162 auto data = Native::data<MemcachedData>(this_);
1163 if (data->m_impl->rescode == q_Memcached$$RES_PAYLOAD_FAILURE) {
1164 return "PAYLOAD FAILURE";
1165 } else {
1166 return memcached_strerror(&data->m_impl->memcached,
1167 (memcached_return_t)data->m_impl->rescode);
1171 bool HHVM_METHOD(Memcached, ispersistent) {
1172 auto data = Native::data<MemcachedData>(this_);
1173 return data->m_impl->is_persistent;
1176 bool HHVM_METHOD(Memcached, ispristine) {
1177 auto data = Native::data<MemcachedData>(this_);
1178 return data->m_impl->is_pristine;
1181 bool HHVM_METHOD(Memcached, touchbykey,
1182 ATTRIBUTE_UNUSED const String& server_key,
1183 ATTRIBUTE_UNUSED const String& key,
1184 ATTRIBUTE_UNUSED int64_t expiration /*= 0*/) {
1186 #ifndef HAVE_MEMCACHED_TOUCH
1187 throw_not_supported(__func__, "Not Implemented in libmemcached versions below"
1188 " 1.0.2");
1189 return false;
1190 #else
1191 auto data = Native::data<MemcachedData>(this_);
1192 data->m_impl->rescode = MEMCACHED_SUCCESS;
1193 if (key.empty()) {
1194 data->m_impl->rescode = MEMCACHED_BAD_KEY_PROVIDED;
1195 return false;
1198 #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX < 0x01000016
1199 if (memcached_behavior_get(&data->m_impl->memcached,
1200 MEMCACHED_BEHAVIOR_BINARY_PROTOCOL)) {
1201 raise_warning("using touch command with binary protocol is not "
1202 "recommended with libmemcached versions below 1.0.16");
1204 #endif
1206 memcached_return_t status;
1207 const String& myServerKey = server_key.empty() ? key : server_key;
1208 status = memcached_touch_by_key(&data->m_impl->memcached,
1209 myServerKey.c_str(), myServerKey.length(),
1210 key.c_str(), key.length(), expiration);
1212 if (!data->handleError(status)) return false;
1213 data->m_impl->rescode = MEMCACHED_SUCCESS;
1214 return true;
1215 #endif
1218 ///////////////////////////////////////////////////////////////////////////////
1220 RDS_LOCAL(MemcachedData::ImplMap, MemcachedData::s_persistentMap);
1222 const StaticString s_Memcached("Memcached");
1224 struct MemcachedExtension final : Extension {
1225 MemcachedExtension() : Extension("memcached", "2.2.0b1") {}
1226 void threadInit() override {
1227 *s_memcached_globals = new MEMCACHEDGlobals;
1228 assertx(*s_memcached_globals);
1230 IniSetting::Bind(this, IniSetting::PHP_INI_ALL,
1231 "memcached.sess_prefix", &MEMCACHEDG(sess_prefix));
1234 void threadShutdown() override {
1235 delete *s_memcached_globals;
1236 *s_memcached_globals = nullptr;
1239 void moduleInit() override {
1240 HHVM_ME(Memcached, __construct);
1241 HHVM_ME(Memcached, quit);
1242 HHVM_ME(Memcached, getallkeys);
1243 HHVM_ME(Memcached, getbykey);
1244 HHVM_ME(Memcached, getbykeywithcastoken);
1245 HHVM_ME(Memcached, getmultibykey);
1246 HHVM_ME(Memcached, getmultibykeywithcastokens);
1247 HHVM_ME(Memcached, getdelayedbykey);
1248 HHVM_ME(Memcached, fetch);
1249 HHVM_ME(Memcached, fetchall);
1250 HHVM_ME(Memcached, setbykey);
1251 HHVM_ME(Memcached, addbykey);
1252 HHVM_ME(Memcached, appendbykey);
1253 HHVM_ME(Memcached, prependbykey);
1254 HHVM_ME(Memcached, replacebykey);
1255 HHVM_ME(Memcached, casbykey);
1256 HHVM_ME(Memcached, deletebykey);
1257 HHVM_ME(Memcached, deletemultibykey);
1258 HHVM_ME(Memcached, increment);
1259 HHVM_ME(Memcached, incrementbykey);
1260 HHVM_ME(Memcached, decrement);
1261 HHVM_ME(Memcached, decrementbykey);
1262 HHVM_ME(Memcached, addserver);
1263 HHVM_ME(Memcached, getserverlist);
1264 HHVM_ME(Memcached, resetserverlist);
1265 HHVM_ME(Memcached, getserverbykey);
1266 HHVM_ME(Memcached, getstats);
1267 HHVM_ME(Memcached, getversion);
1268 HHVM_ME(Memcached, flush);
1269 HHVM_ME(Memcached, getoption);
1270 HHVM_ME(Memcached, setoption);
1271 HHVM_ME(Memcached, getresultcode);
1272 HHVM_ME(Memcached, getresultmessage);
1273 HHVM_ME(Memcached, ispersistent);
1274 HHVM_ME(Memcached, ispristine);
1275 HHVM_ME(Memcached, touchbykey);
1277 Native::registerNativeDataInfo<MemcachedData>(s_MemcachedData.get());
1279 HHVM_RCC_BOOL(Memcached, HAVE_IGBINARY, false);
1280 HHVM_RCC_BOOL(Memcached, HAVE_JSON, true);
1282 HHVM_RCC_INT(Memcached, DISTRIBUTION_CONSISTENT,
1283 MEMCACHED_DISTRIBUTION_CONSISTENT);
1284 HHVM_RCC_INT(Memcached, DISTRIBUTION_CONSISTENT_KETAMA,
1285 MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA);
1286 #ifdef MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED
1287 HHVM_RCC_INT(Memcached, DISTRIBUTION_CONSISTENT_WEIGHTED,
1288 MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED);
1289 #endif
1290 HHVM_RCC_INT(Memcached, DISTRIBUTION_MODULA, MEMCACHED_DISTRIBUTION_MODULA);
1291 HHVM_RCC_INT(Memcached, GET_PRESERVE_ORDER,
1292 q_Memcached$$GET_PRESERVE_ORDER);
1293 HHVM_RCC_INT(Memcached, HASH_CRC, MEMCACHED_HASH_CRC);
1294 HHVM_RCC_INT(Memcached, HASH_DEFAULT, MEMCACHED_HASH_DEFAULT);
1295 HHVM_RCC_INT(Memcached, HASH_FNV1_32, MEMCACHED_HASH_FNV1_32);
1296 HHVM_RCC_INT(Memcached, HASH_FNV1_64, MEMCACHED_HASH_FNV1_64);
1297 HHVM_RCC_INT(Memcached, HASH_FNV1A_32, MEMCACHED_HASH_FNV1A_32);
1298 HHVM_RCC_INT(Memcached, HASH_FNV1A_64, MEMCACHED_HASH_FNV1A_64);
1299 HHVM_RCC_INT(Memcached, HASH_HSIEH, MEMCACHED_HASH_HSIEH);
1300 HHVM_RCC_INT(Memcached, HASH_MD5, MEMCACHED_HASH_MD5);
1301 HHVM_RCC_INT(Memcached, HASH_MURMUR, MEMCACHED_HASH_MURMUR);
1302 HHVM_RCC_INT(Memcached, OPT_BINARY_PROTOCOL,
1303 MEMCACHED_BEHAVIOR_BINARY_PROTOCOL);
1304 HHVM_RCC_INT(Memcached, OPT_BUFFER_WRITES,
1305 MEMCACHED_BEHAVIOR_BUFFER_REQUESTS);
1306 HHVM_RCC_INT(Memcached, OPT_CACHE_LOOKUPS,
1307 MEMCACHED_BEHAVIOR_CACHE_LOOKUPS);
1308 HHVM_RCC_INT(Memcached, OPT_COMPRESSION, q_Memcached$$OPT_COMPRESSION);
1309 HHVM_RCC_INT(Memcached, OPT_CONNECT_TIMEOUT,
1310 MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT);
1311 HHVM_RCC_INT(Memcached, OPT_DISTRIBUTION, MEMCACHED_BEHAVIOR_DISTRIBUTION);
1312 HHVM_RCC_INT(Memcached, OPT_HASH, MEMCACHED_BEHAVIOR_HASH);
1313 HHVM_RCC_INT(Memcached, OPT_LIBKETAMA_COMPATIBLE,
1314 MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED);
1315 HHVM_RCC_INT(Memcached, OPT_LIBKETAMA_HASH, MEMCACHED_BEHAVIOR_KETAMA_HASH);
1316 HHVM_RCC_INT(Memcached, OPT_NO_BLOCK, MEMCACHED_BEHAVIOR_NO_BLOCK);
1317 HHVM_RCC_INT(Memcached, OPT_POLL_TIMEOUT, MEMCACHED_BEHAVIOR_POLL_TIMEOUT);
1318 HHVM_RCC_INT(Memcached, OPT_PREFIX_KEY, q_Memcached$$OPT_PREFIX_KEY);
1319 HHVM_RCC_INT(Memcached, OPT_HASH_WITH_PREFIX_KEY,
1320 MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY);
1321 HHVM_RCC_INT(Memcached, OPT_RECV_TIMEOUT, MEMCACHED_BEHAVIOR_RCV_TIMEOUT);
1322 HHVM_RCC_INT(Memcached, OPT_RETRY_TIMEOUT,
1323 MEMCACHED_BEHAVIOR_RETRY_TIMEOUT);
1324 HHVM_RCC_INT(Memcached, OPT_SEND_TIMEOUT, MEMCACHED_BEHAVIOR_SND_TIMEOUT);
1325 HHVM_RCC_INT(Memcached, OPT_SERIALIZER, q_Memcached$$OPT_SERIALIZER);
1326 HHVM_RCC_INT(Memcached, OPT_SERVER_FAILURE_LIMIT,
1327 MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT);
1328 HHVM_RCC_INT(Memcached, OPT_SOCKET_RECV_SIZE,
1329 MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE);
1330 HHVM_RCC_INT(Memcached, OPT_SOCKET_SEND_SIZE,
1331 MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE);
1332 HHVM_RCC_INT(Memcached, OPT_TCP_NODELAY, MEMCACHED_BEHAVIOR_TCP_NODELAY);
1333 HHVM_RCC_INT(Memcached, RES_BAD_KEY_PROVIDED, MEMCACHED_BAD_KEY_PROVIDED);
1334 HHVM_RCC_INT(Memcached, RES_BUFFERED, MEMCACHED_BUFFERED);
1335 HHVM_RCC_INT(Memcached, RES_CLIENT_ERROR, MEMCACHED_CLIENT_ERROR);
1336 HHVM_RCC_INT(Memcached, RES_CONNECTION_SOCKET_CREATE_FAILURE,
1337 MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE);
1338 HHVM_RCC_INT(Memcached, RES_DATA_EXISTS, MEMCACHED_DATA_EXISTS);
1339 HHVM_RCC_INT(Memcached, RES_END, MEMCACHED_END);
1340 HHVM_RCC_INT(Memcached, RES_ERRNO, MEMCACHED_ERRNO);
1341 HHVM_RCC_INT(Memcached, RES_FAILURE, MEMCACHED_FAILURE);
1342 HHVM_RCC_INT(Memcached, RES_HOST_LOOKUP_FAILURE,
1343 MEMCACHED_HOST_LOOKUP_FAILURE);
1344 HHVM_RCC_INT(Memcached, RES_INVALID_HOST_PROTOCOL,
1345 MEMCACHED_INVALID_HOST_PROTOCOL);
1346 HHVM_RCC_INT(Memcached, RES_NO_SERVERS, MEMCACHED_NO_SERVERS);
1347 HHVM_RCC_INT(Memcached, RES_NOT_SUPPORTED, MEMCACHED_NOT_SUPPORTED);
1348 HHVM_RCC_INT(Memcached, RES_NOTFOUND, MEMCACHED_NOTFOUND);
1349 HHVM_RCC_INT(Memcached, RES_NOTSTORED, MEMCACHED_NOTSTORED);
1350 HHVM_RCC_INT(Memcached, RES_PARTIAL_READ, MEMCACHED_PARTIAL_READ);
1351 HHVM_RCC_INT(Memcached, RES_PAYLOAD_FAILURE,
1352 q_Memcached$$RES_PAYLOAD_FAILURE);
1353 HHVM_RCC_INT(Memcached, RES_PROTOCOL_ERROR, MEMCACHED_PROTOCOL_ERROR);
1354 HHVM_RCC_INT(Memcached, RES_SERVER_ERROR, MEMCACHED_SERVER_ERROR);
1355 HHVM_RCC_INT(Memcached, RES_SOME_ERRORS, MEMCACHED_SOME_ERRORS);
1356 HHVM_RCC_INT(Memcached, RES_SUCCESS, MEMCACHED_SUCCESS);
1357 HHVM_RCC_INT(Memcached, RES_TIMEOUT, MEMCACHED_TIMEOUT);
1358 HHVM_RCC_INT(Memcached, RES_UNKNOWN_READ_FAILURE,
1359 MEMCACHED_UNKNOWN_READ_FAILURE);
1360 HHVM_RCC_INT(Memcached, RES_WRITE_FAILURE, MEMCACHED_WRITE_FAILURE);
1361 HHVM_RCC_INT(Memcached, SERIALIZER_IGBINARY,
1362 q_Memcached$$SERIALIZER_IGBINARY);
1363 HHVM_RCC_INT(Memcached, SERIALIZER_JSON, q_Memcached$$SERIALIZER_JSON);
1364 HHVM_RCC_INT(Memcached, SERIALIZER_PHP, q_Memcached$$SERIALIZER_PHP);
1365 HHVM_RCC_INT(Memcached, OPT_VERIFY_KEY, MEMCACHED_BEHAVIOR_VERIFY_KEY);
1366 HHVM_RCC_INT(Memcached, OPT_SORT_HOSTS, MEMCACHED_BEHAVIOR_SORT_HOSTS);
1367 HHVM_RCC_INT(Memcached, RES_SERVER_MARKED_DEAD,
1368 MEMCACHED_SERVER_MARKED_DEAD);
1369 #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x00049000
1370 HHVM_RCC_INT(Memcached, OPT_REMOVE_FAILED_SERVERS,
1371 MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS);
1372 #endif
1373 #if defined(LIBMEMCACHED_VERSION_HEX) && LIBMEMCACHED_VERSION_HEX >= 0x01000003
1374 HHVM_RCC_INT(Memcached, OPT_DEAD_TIMEOUT, MEMCACHED_BEHAVIOR_DEAD_TIMEOUT);
1375 #endif
1376 HHVM_RCC_INT(Memcached, RES_SERVER_TEMPORARILY_DISABLED,
1377 MEMCACHED_SERVER_TEMPORARILY_DISABLED);
1378 HHVM_RCC_INT(Memcached, LIBMEMCACHED_VERSION_HEX, LIBMEMCACHED_VERSION_HEX);
1379 HHVM_RCC_BOOL(Memcached, GET_ERROR_RETURN_VALUE, false);
1382 loadSystemlib();
1384 } s_memcached_extension;