Memcached.class.php

Go to the documentation of this file.
00001 <?php
00002 /***************************************************************************
00003  *   Copyright (C) 2004-2007 by Konstantin V. Arkhipov                     *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU Lesser General Public License as        *
00007  *   published by the Free Software Foundation; either version 3 of the    *
00008  *   License, or (at your option) any later version.                       *
00009  *                                                                         *
00010  *   Inspired by the work of Ryan Gilfether <hotrodder@rocketmail.com>     *
00011  *   Copyright (c) 2003, under the GNU GPL license                         *
00012  *                                                                         *
00013  ***************************************************************************/
00014 /* $Id: Memcached.class.php 4687 2007-12-09 18:57:18Z voxus $ */
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             // flushing obligatory response - "OK\r\n"
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                 // strlen("\r\nEND\r\n") == 7
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 ?>

Generated on Sun Dec 9 21:56:23 2007 for onPHP by  doxygen 1.5.4