true, Memcached::OPT_SERIALIZER => Memcached::SERIALIZER_PHP, Memcached::OPT_PREFIX_KEY => '', Memcached::OPT_HASH => Memcached::HASH_DEFAULT, Memcached::OPT_DISTRIBUTION => Memcached::DISTRIBUTION_MODULA, Memcached::OPT_LIBKETAMA_COMPATIBLE => false, Memcached::OPT_BUFFER_WRITES => false, Memcached::OPT_BINARY_PROTOCOL => false, Memcached::OPT_NO_BLOCK => false, Memcached::OPT_TCP_NODELAY => false, // This two is a value by guess Memcached::OPT_SOCKET_SEND_SIZE => 32767, Memcached::OPT_SOCKET_RECV_SIZE => 65535, Memcached::OPT_CONNECT_TIMEOUT => 1000, Memcached::OPT_RETRY_TIMEOUT => 0, Memcached::OPT_SEND_TIMEOUT => 0, Memcached::OPT_RECV_TIMEOUT => 0, Memcached::OPT_POLL_TIMEOUT => 1000, Memcached::OPT_CACHE_LOOKUPS => false, Memcached::OPT_SERVER_FAILURE_LIMIT => 0, ); /** * Last result code * * @var int */ protected $resultCode = 0; /** * Last result message * * @var string */ protected $resultMessage = ''; /** * Server list array/pool * * I added array index. * * array ( * host:port:weight => array( * host, * port, * weight, * ) * ) * * @var array */ protected $server = array(); /** * Socket connect handle * * Point to last successful connect, ignore others * @var resource */ protected $socket = null; public function getVersion() { return ['localhost:11211' => '1.4.5']; } //may check: https://raw.githubusercontent.com/GoogleCloudPlatform/python-compat-runtime/master/appengine-compat/exported_appengine_sdk/php/sdk/google/appengine/runtime/Memcached.php public function setMulti() { die('TODO'); } public function getMulti() { //TODO die('TODO'); } /** * Add a serer to the server pool * * @param string $host * @param int $port * @param int $weight * @return boolean */ public function addServer($host, $port = 11211, $weight = 0) { $key = $this->getServerKey($host, $port, $weight); if (isset($this->server[$key])) { // Dup $this->resultCode = Memcached::RES_FAILURE; $this->resultMessage = 'Server duplicate.'; return false; } else { $this->server[$key] = array( 'host' => $host, 'port' => $port, 'weight' => $weight, ); $this->connect(); return true; } } /** * Add multiple servers to the server pool * * @param array $servers * @return boolean */ public function addServers($servers) { foreach ((array)$servers as $svr) { $host = array_shift($svr); $port = array_shift($svr); if (is_null($port)) { $port = 11211; } $weight = array_shift($svr); if (is_null($weight)) { $weight = 0; } $this->addServer($host, $port, $weight); } return true; } /** * Connect to memcached server * * @return boolean */ protected function connect() { $rs = false; foreach ((array)$this->server as $svr) { $error = 0; $errstr = ''; $rs = @fsockopen($svr['host'], $svr['port'], $error, $errstr); if ($rs) { $this->socket = $rs; } else { $key = $this->getServerKey( $svr['host'], $svr['port'], $svr['weight'] ); $s = "Connect to $key error:" . PHP_EOL . " [$error] $errstr"; error_log($s); } } if (is_null($this->socket)) { $this->resultCode = Memcached::RES_FAILURE; $this->resultMessage = 'No server avaliable.'; return false; } else { $this->resultCode = Memcached::RES_SUCCESS; $this->resultMessage = ''; return true; } } /** * Delete an item * * @param string $key * @param int $time Ignored * @return boolean */ public function delete($key, $time = 0) { $keyString = $this->getKey($key); $this->writeSocket("delete $keyString"); $s = $this->readSocket(); if ('DELETED' == $s) { $this->resultCode = Memcached::RES_SUCCESS; $this->resultMessage = ''; return true; } else { $this->resultCode = Memcached::RES_NOTFOUND; $this->resultMessage = 'Delete fail, key not exists.'; return false; } } /** * Retrieve an item * * @param string $key * @param callable $cache_cb Ignored * @param float $cas_token Ignored * @return mixed */ public function get($key, $cache_cb = null, $cas_token = null) { $keyString = $this->getKey($key); $this->writeSocket("get $keyString"); $s = $this->readSocket(); if (is_null($s) || 'VALUE' != substr($s, 0, 5)) { $this->resultCode = Memcached::RES_FAILURE; $this->resultMessage = 'Get fail.'; return false; } else { $s_result = ''; $s = $this->readSocket(); while ('END' != $s) { $s_result .= $s; $s = $this->readSocket(); } $this->resultCode = Memcached::RES_SUCCESS; $this->resultMessage = ''; return unserialize($s_result); } } /** * Get item key * * @param string $key * @return string */ public function getKey($key) { return addslashes($this->option[Memcached::OPT_PREFIX_KEY]) . $key; } /** * Get a memcached option value * * @param int $option * @return mixed */ public function getOption($option) { if (isset($this->option[$option])) { $this->resultCode = Memcached::RES_SUCCESS; $this->resultMessage = ''; return $this->option[$option]; } else { $this->resultCode = Memcached::RES_FAILURE; $this->resultMessage = 'Option not seted.'; return false; } } /** * Return the result code of the last operation * * @return int */ public function getResultCode() { return $this->resultCode; } /** * Return the message describing the result of the last opteration * * @return string */ public function getResultMessage() { return $this->resultMessage; } /** * Get key of server array * * @param string $host * @param int $port * @param int $weight * @return string */ protected function getServerKey($host, $port = 11211, $weight = 0) { return "$host:$port:$weight"; } /** * Get list array of servers * * @see $server * @return array */ public function getServerList() { return $this->server; } /** * Read from socket * * @return string|null */ protected function readSocket() { if (is_null($this->socket)) { return null; } return trim(fgets($this->socket)); } /** * Store an item * * @param string $key * @param mixed $val * @param int $expt * @return boolean */ public function set($key, $val, $expt = 0) { $valueString = serialize($val); $keyString = $this->getKey($key); $this->writeSocket( "set $keyString 0 $expt " . strlen($valueString) ); $s = $this->writeSocket($valueString, true); if ('STORED' == $s) { $this->resultCode = Memcached::RES_SUCCESS; $this->resultMessage = ''; return true; } else { $this->resultCode = Memcached::RES_FAILURE; $this->resultMessage = 'Set fail.'; return false; } } /** * Set a memcached option * * @param int $option * @param mixed $value * @return boolean */ public function setOption($option, $value) { $this->option[$option] = $value; return true; } /** * Set memcached options * * @param array $options * @return bollean */ public function setOptions($options) { $this->option = array_merge($this->option, $options); return true; } /** * Increment numeric item's value * * @param string $key The key of the item to increment. * @param int $offset The amount by which to increment the item's value. * @param int $initial_value The value to set the item to if it doesn't currently exist. * @param int $expiry The expiry time to set on the item. * * @return mixed Returns new item's value on success or FALSE on failure. */ public function increment($key, $offset = 1, $initial_value = 0, $expiry = 0) { if (($prevVal = $this->get($key))) { if (!is_numeric($prevVal)) { return false; } $newVal = $prevVal + $offset; } else { $newVal = $initial_value; } $this->set($key, $newVal, $expiry); return $newVal; } /** * Write data to socket * * @param string $cmd * @param boolean $result Need result/response * @return mixed */ protected function writeSocket($cmd, $result = false) { if (is_null($this->socket)) { return false; } fwrite($this->socket, $cmd . "\r\n"); if (true == $result) { return $this->readSocket(); } return true; } }