00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00023 final class Memcached extends CachePeer
00024 {
00025 const DEFAULT_PORT = 11211;
00026 const DEFAULT_HOST = '127.0.0.1';
00027 const DEFAULT_BUFFER = 16384;
00028
00029 private $link = null;
00030
00031 private $buffer = Memcached::DEFAULT_BUFFER;
00032
00036 public static function create(
00037 $host = Memcached::DEFAULT_HOST,
00038 $port = Memcached::DEFAULT_PORT,
00039 $buffer = Memcached::DEFAULT_BUFFER
00040 )
00041 {
00042 return new Memcached($host, $port, $buffer);
00043 }
00044
00045 public function __construct(
00046 $host = Memcached::DEFAULT_HOST,
00047 $port = Memcached::DEFAULT_PORT,
00048 $buffer = Memcached::DEFAULT_BUFFER
00049 )
00050 {
00051 try {
00052 $this->link = fsockopen($host, $port);
00053 $this->alive = true;
00054 } catch (BaseException $e) {
00055 return null;
00056 }
00057
00058 $this->buffer = $buffer;
00059
00060 stream_set_blocking($this->link, true);
00061 stream_set_timeout($this->link, 1);
00062 }
00063
00067 public function clean()
00068 {
00069 $this->sendRequest("flush_all\r\n");
00070
00071
00072 fread($this->link, 4);
00073
00074 return parent::clean();
00075 }
00076
00077 public function get($index)
00078 {
00079 if (!$this->link)
00080 return null;
00081
00082 $command = "get {$index}\r\n";
00083
00084 if (!$this->sendRequest($command))
00085 return null;
00086
00087 $buffer = null;
00088 $lenght = 0;
00089 $bytesRead = 0;
00090
00091 while ($line = fread($this->link, $this->buffer)) {
00092 if ($line === false)
00093 return null;
00094
00095 if ($lenght === 0) {
00096 $header = substr($line, 0, strpos($line, "\r\n"));
00097
00098 if ($header === 'ERROR')
00099 return null;
00100
00101 if ($header !== 'END') {
00102 $array = explode(' ', $header, 4);
00103
00104 if (count($array) <> 4)
00105 continue;
00106 else
00107 list(
00108 , $key, $flags, $bytes
00109 ) = explode(' ', $header);
00110
00111 if (
00112 is_string($key)
00113 && is_numeric($flags)
00114 && is_numeric($bytes)
00115 ) {
00116 $line =
00117 substr(
00118 $line,
00119 strpos($line, "\r\n") + 2,
00120 strlen($line)
00121 );
00122 } else
00123 return null;
00124
00125 $lenght = $bytes;
00126 } else
00127 return null;
00128 }
00129
00130 $bytesRead += strlen($line);
00131
00132 $buffer .= $line;
00133
00134
00135 if ($bytesRead == ($lenght + 7)) {
00136 $end = substr($buffer, $lenght + 2, 3);
00137
00138 if ($end === 'END') {
00139 $result = substr($buffer, 0, $lenght);
00140
00141 if ($flags & 2)
00142 $result = gzuncompress($result);
00143
00144 if ($flags & 1)
00145 $result = unserialize($result);
00146
00147 return $result;
00148 } else
00149 return null;
00150 }
00151 }
00152
00153 return null;
00154 }
00155
00156 public function delete($index, $time = null)
00157 {
00158 $command =
00159 $time
00160 ? "delete {$index} {$time}\r\n"
00161 : "delete {$index}\r\n";
00162
00163 if (!$this->sendRequest($command))
00164 return false;
00165
00166 try {
00167 $response = trim(fread($this->link, $this->buffer));
00168 } catch (BaseException $e) {
00169 return false;
00170 }
00171
00172 if ($response === 'DELETED')
00173 return true;
00174 else
00175 return false;
00176 }
00177
00178 protected function store(
00179 $method, $index, &$value, $expires = Cache::EXPIRES_MINIMUM
00180 )
00181 {
00182 if ($expires === Cache::DO_NOT_CACHE)
00183 return false;
00184
00185 $flags = 0;
00186
00187 if (!is_scalar($value) || $value === Cache::NOT_FOUND) {
00188 $packed = serialize($value);
00189 $flags |= 1;
00190
00191 if ($this->compress) {
00192 $compressed = gzcompress($packed);
00193
00194 if (strlen($compressed) < strlen($packed)) {
00195 $packed = $compressed;
00196 $flags |= 2;
00197 unset($compressed);
00198 }
00199 }
00200 } else
00201 $packed = $value;
00202
00203 $lenght = strlen($packed);
00204
00205 $command = "{$method} {$index} {$flags} {$expires} {$lenght}\r\n{$packed}\r\n";
00206
00207 if (!$this->sendRequest($command))
00208 return false;
00209
00210 $response = trim(fread($this->link, $this->buffer));
00211
00212 if ($response === 'STORED')
00213 return true;
00214
00215 return false;
00216 }
00217
00218 private function sendRequest($command)
00219 {
00220 $commandLenght = strlen($command);
00221
00222 if ($commandLenght > $this->buffer) {
00223 $offset = 0;
00224 while ($offset < $commandLenght) {
00225 try {
00226 $result = fwrite(
00227 $this->link,
00228 substr(
00229 $command,
00230 $offset,
00231 $this->buffer
00232 )
00233 );
00234 } catch (BaseException $e) {
00235 return $this->alive = false;
00236 }
00237
00238 if ($result !== false)
00239 $offset += $result;
00240 else
00241 return false;
00242 }
00243 } else {
00244 try {
00245 return (
00246 fwrite(
00247 $this->link,
00248 $command,
00249 $commandLenght
00250 ) === false
00251 ? false
00252 : true
00253 );
00254 } catch (BaseException $e) {
00255 return $this->alive = false;
00256 }
00257 }
00258
00259 return true;
00260 }
00261 }
00262 ?>