]>
Commit | Line | Data |
---|---|---|
ed9b544e | 1 | <?php |
2 | /******************************************************************************* | |
3 | * Redis PHP Bindings - http://code.google.com/p/redis/ | |
4 | * | |
5 | * Copyright 2009 Ludovico Magnocavallo | |
8d03032a | 6 | * Copyright 2009 Salvatore Sanfilippo (ported it to PHP5, fixed some bug) |
ed9b544e | 7 | * Released under the same license as Redis. |
8 | * | |
9 | * Version: 0.1 | |
10 | * | |
11 | * $Revision: 139 $ | |
12 | * $Date: 2009-03-15 22:59:40 +0100 (Dom, 15 Mar 2009) $ | |
13 | * | |
14 | ******************************************************************************/ | |
15 | ||
16 | ||
17 | class Redis { | |
8d03032a | 18 | public $server; |
19 | public $port; | |
20 | private $_sock; | |
21 | ||
22 | public function __construct($host='localhost', $port=6379) { | |
ed9b544e | 23 | $this->host = $host; |
24 | $this->port = $port; | |
25 | } | |
26 | ||
8d03032a | 27 | public function connect() { |
28 | if ($this->_sock) return; | |
ed9b544e | 29 | if ($sock = fsockopen($this->host, $this->port, $errno, $errstr)) { |
30 | $this->_sock = $sock; | |
31 | return; | |
32 | } | |
33 | $msg = "Cannot open socket to {$this->host}:{$this->port}"; | |
34 | if ($errno || $errmsg) | |
8d03032a | 35 | $msg .= "," . ($errno ? " error $errno" : "") . |
36 | ($errmsg ? " $errmsg" : ""); | |
ed9b544e | 37 | trigger_error("$msg.", E_USER_ERROR); |
38 | } | |
39 | ||
8d03032a | 40 | public function disconnect() { |
41 | if ($this->_sock) @fclose($this->_sock); | |
ed9b544e | 42 | $this->_sock = null; |
43 | } | |
44 | ||
8d03032a | 45 | public function ping() { |
ed9b544e | 46 | $this->connect(); |
8d03032a | 47 | $this->write("PING\r\n"); |
bb7dcc1e | 48 | return $this->get_response(); |
ed9b544e | 49 | } |
50 | ||
8d03032a | 51 | public function do_echo($s) { |
ed9b544e | 52 | $this->connect(); |
8d03032a | 53 | $this->write("ECHO " . strlen($s) . "\r\n$s\r\n"); |
54 | return $this->get_response(); | |
ed9b544e | 55 | } |
56 | ||
8d03032a | 57 | public function set($name, $value, $preserve=false) { |
ed9b544e | 58 | $this->connect(); |
8d03032a | 59 | $this->write( |
ed9b544e | 60 | ($preserve ? 'SETNX' : 'SET') . |
61 | " $name " . strlen($value) . "\r\n$value\r\n" | |
62 | ); | |
bb7dcc1e | 63 | return $this->get_response(); |
ed9b544e | 64 | } |
65 | ||
8d03032a | 66 | public function get($name) { |
ed9b544e | 67 | $this->connect(); |
8d03032a | 68 | $this->write("GET $name\r\n"); |
69 | return $this->get_response(); | |
ed9b544e | 70 | } |
6f864e62 | 71 | |
72 | public function mget($keys) { | |
73 | $this->connect(); | |
74 | $this->write("MGET ".implode(" ",$keys)."\r\n"); | |
75 | return $this->get_response(); | |
76 | } | |
ed9b544e | 77 | |
8d03032a | 78 | public function incr($name, $amount=1) { |
ed9b544e | 79 | $this->connect(); |
80 | if ($amount == 1) | |
8d03032a | 81 | $this->write("INCR $name\r\n"); |
ed9b544e | 82 | else |
8d03032a | 83 | $this->write("INCRBY $name $amount\r\n"); |
bb7dcc1e | 84 | return $this->get_response(); |
ed9b544e | 85 | } |
86 | ||
8d03032a | 87 | public function decr($name, $amount=1) { |
ed9b544e | 88 | $this->connect(); |
89 | if ($amount == 1) | |
8d03032a | 90 | $this->write("DECR $name\r\n"); |
ed9b544e | 91 | else |
8d03032a | 92 | $this->write("DECRBY $name $amount\r\n"); |
bb7dcc1e | 93 | return $this->get_response(); |
ed9b544e | 94 | } |
95 | ||
8d03032a | 96 | public function exists($name) { |
ed9b544e | 97 | $this->connect(); |
8d03032a | 98 | $this->write("EXISTS $name\r\n"); |
bb7dcc1e | 99 | return $this->get_response(); |
ed9b544e | 100 | } |
101 | ||
8d03032a | 102 | public function delete($name) { |
ed9b544e | 103 | $this->connect(); |
8d03032a | 104 | $this->write("DEL $name\r\n"); |
bb7dcc1e | 105 | return $this->get_response(); |
ed9b544e | 106 | } |
107 | ||
8d03032a | 108 | public function keys($pattern) { |
ed9b544e | 109 | $this->connect(); |
8d03032a | 110 | $this->write("KEYS $pattern\r\n"); |
111 | return explode(' ', $this->get_response()); | |
ed9b544e | 112 | } |
113 | ||
8d03032a | 114 | public function randomkey() { |
ed9b544e | 115 | $this->connect(); |
8d03032a | 116 | $this->write("RANDOMKEY\r\n"); |
bb7dcc1e | 117 | return $this->get_response(); |
ed9b544e | 118 | } |
119 | ||
8d03032a | 120 | public function rename($src, $dst) { |
121 | $this->connect(); | |
122 | $this->write("RENAME $src $dst\r\n"); | |
123 | return $this->get_response(); | |
124 | } | |
125 | ||
126 | public function renamenx($src, $dst) { | |
ed9b544e | 127 | $this->connect(); |
8d03032a | 128 | $this->write("RENAMENX $src $dst\r\n"); |
bb7dcc1e | 129 | return $this->get_response(); |
ed9b544e | 130 | } |
131 | ||
8d03032a | 132 | public function expire($name, $time) { |
9a2944ac | 133 | $this->connect(); |
8d03032a | 134 | $this->write("EXPIRE $name $time\r\n"); |
9a2944ac LM |
135 | return $this->get_response(); |
136 | } | |
137 | ||
8d03032a | 138 | public function push($name, $value, $tail=true) { |
ed9b544e | 139 | // default is to append the element to the list |
140 | $this->connect(); | |
8d03032a | 141 | $this->write( |
ed9b544e | 142 | ($tail ? 'RPUSH' : 'LPUSH') . |
143 | " $name " . strlen($value) . "\r\n$value\r\n" | |
144 | ); | |
bb7dcc1e | 145 | return $this->get_response(); |
ed9b544e | 146 | } |
8d03032a | 147 | |
148 | public function lpush($name, $value) { | |
149 | return $this->push($name, $value, false); | |
150 | } | |
151 | ||
152 | public function rpush($name, $value) { | |
153 | return $this->push($name, $value, true); | |
154 | } | |
155 | ||
156 | public function ltrim($name, $start, $end) { | |
ed9b544e | 157 | $this->connect(); |
8d03032a | 158 | $this->write("LTRIM $name $start $end\r\n"); |
bb7dcc1e | 159 | return $this->get_response(); |
ed9b544e | 160 | } |
161 | ||
8d03032a | 162 | public function lindex($name, $index) { |
ed9b544e | 163 | $this->connect(); |
8d03032a | 164 | $this->write("LINDEX $name $index\r\n"); |
165 | return $this->get_response(); | |
ed9b544e | 166 | } |
167 | ||
8d03032a | 168 | public function pop($name, $tail=true) { |
ed9b544e | 169 | $this->connect(); |
8d03032a | 170 | $this->write( |
ed9b544e | 171 | ($tail ? 'RPOP' : 'LPOP') . |
172 | " $name\r\n" | |
173 | ); | |
8d03032a | 174 | return $this->get_response(); |
175 | } | |
176 | ||
177 | public function lpop($name, $value) { | |
178 | return $this->pop($name, $value, false); | |
179 | } | |
180 | ||
181 | public function rpop($name, $value) { | |
182 | return $this->pop($name, $value, true); | |
ed9b544e | 183 | } |
184 | ||
8d03032a | 185 | public function llen($name) { |
ed9b544e | 186 | $this->connect(); |
8d03032a | 187 | $this->write("LLEN $name\r\n"); |
bb7dcc1e | 188 | return $this->get_response(); |
ed9b544e | 189 | } |
190 | ||
8d03032a | 191 | public function lrange($name, $start, $end) { |
ed9b544e | 192 | $this->connect(); |
8d03032a | 193 | $this->write("LRANGE $name $start $end\r\n"); |
bb7dcc1e | 194 | return $this->get_response(); |
ed9b544e | 195 | } |
196 | ||
8d03032a | 197 | public function sort($name, $query=false) { |
ed9b544e | 198 | $this->connect(); |
8d03032a | 199 | $this->write($query == false ? "SORT $name\r\n" : "SORT $name $query\r\n"); |
bb7dcc1e | 200 | return $this->get_response(); |
ed9b544e | 201 | } |
202 | ||
8d03032a | 203 | public function lset($name, $value, $index) { |
ed9b544e | 204 | $this->connect(); |
8d03032a | 205 | $this->write("LSET $name $index " . strlen($value) . "\r\n$value\r\n"); |
bb7dcc1e | 206 | return $this->get_response(); |
ed9b544e | 207 | } |
208 | ||
8d03032a | 209 | public function sadd($name, $value) { |
ed9b544e | 210 | $this->connect(); |
8d03032a | 211 | $this->write("SADD $name " . strlen($value) . "\r\n$value\r\n"); |
bb7dcc1e | 212 | return $this->get_response(); |
ed9b544e | 213 | } |
214 | ||
8d03032a | 215 | public function srem($name, $value) { |
ed9b544e | 216 | $this->connect(); |
8d03032a | 217 | $this->write("SREM $name " . strlen($value) . "\r\n$value\r\n"); |
bb7dcc1e | 218 | return $this->get_response(); |
ed9b544e | 219 | } |
220 | ||
8d03032a | 221 | public function sismember($name, $value) { |
ed9b544e | 222 | $this->connect(); |
8d03032a | 223 | $this->write("SISMEMBER $name " . strlen($value) . "\r\n$value\r\n"); |
bb7dcc1e | 224 | return $this->get_response(); |
ed9b544e | 225 | } |
226 | ||
8d03032a | 227 | public function sinter($sets) { |
ed9b544e | 228 | $this->connect(); |
8d03032a | 229 | $this->write('SINTER ' . implode(' ', $sets) . "\r\n"); |
bb7dcc1e | 230 | return $this->get_response(); |
ed9b544e | 231 | } |
232 | ||
8d03032a | 233 | public function smembers($name) { |
ed9b544e | 234 | $this->connect(); |
8d03032a | 235 | $this->write("SMEMBERS $name\r\n"); |
bb7dcc1e | 236 | return $this->get_response(); |
ed9b544e | 237 | } |
238 | ||
8d03032a | 239 | public function scard($name) { |
ed9b544e | 240 | $this->connect(); |
8d03032a | 241 | $this->write("SCARD $name\r\n"); |
bb7dcc1e | 242 | return $this->get_response(); |
ed9b544e | 243 | } |
244 | ||
8d03032a | 245 | public function select_db($name) { |
ed9b544e | 246 | $this->connect(); |
8d03032a | 247 | $this->write("SELECT $name\r\n"); |
bb7dcc1e | 248 | return $this->get_response(); |
ed9b544e | 249 | } |
250 | ||
8d03032a | 251 | public function move($name, $db) { |
ed9b544e | 252 | $this->connect(); |
8d03032a | 253 | $this->write("MOVE $name $db\r\n"); |
bb7dcc1e | 254 | return $this->get_response(); |
ed9b544e | 255 | } |
256 | ||
8d03032a | 257 | public function save($background=false) { |
ed9b544e | 258 | $this->connect(); |
8d03032a | 259 | $this->write(($background ? "BGSAVE\r\n" : "SAVE\r\n")); |
bb7dcc1e | 260 | return $this->get_response(); |
ed9b544e | 261 | } |
262 | ||
8d03032a | 263 | public function bgsave($background=false) { |
264 | return $this->save(true); | |
265 | } | |
266 | ||
267 | public function lastsave() { | |
ed9b544e | 268 | $this->connect(); |
8d03032a | 269 | $this->write("LASTSAVE\r\n"); |
bb7dcc1e LM |
270 | return $this->get_response(); |
271 | } | |
272 | ||
8d03032a | 273 | public function flushdb($all=false) { |
bb7dcc1e | 274 | $this->connect(); |
8d03032a | 275 | $this->write($all ? "FLUSHALL\r\n" : "FLUSHDB\r\n"); |
bb7dcc1e LM |
276 | return $this->get_response(); |
277 | } | |
8d03032a | 278 | |
279 | public function flushall() { | |
280 | return $this->flush(true); | |
281 | } | |
bb7dcc1e | 282 | |
8d03032a | 283 | public function info() { |
bb7dcc1e | 284 | $this->connect(); |
8d03032a | 285 | $this->write("INFO\r\n"); |
bb7dcc1e LM |
286 | $info = array(); |
287 | $data =& $this->get_response(); | |
288 | foreach (explode("\r\n", $data) as $l) { | |
289 | if (!$l) | |
290 | continue; | |
291 | list($k, $v) = explode(':', $l, 2); | |
292 | $_v = strpos($v, '.') !== false ? (float)$v : (int)$v; | |
293 | $info[$k] = (string)$_v == $v ? $_v : $v; | |
294 | } | |
295 | return $info; | |
ed9b544e | 296 | } |
297 | ||
8d03032a | 298 | private function write($s) { |
ed9b544e | 299 | while ($s) { |
300 | $i = fwrite($this->_sock, $s); | |
bb7dcc1e | 301 | if ($i == 0) // || $i == strlen($s)) |
ed9b544e | 302 | break; |
303 | $s = substr($s, $i); | |
304 | } | |
305 | } | |
306 | ||
8d03032a | 307 | private function read($len=1024) { |
ed9b544e | 308 | if ($s = fgets($this->_sock)) |
309 | return $s; | |
310 | $this->disconnect(); | |
311 | trigger_error("Cannot read from socket.", E_USER_ERROR); | |
312 | } | |
313 | ||
8d03032a | 314 | private function get_response() { |
315 | $data = trim($this->read()); | |
bb7dcc1e LM |
316 | $c = $data[0]; |
317 | $data = substr($data, 1); | |
318 | switch ($c) { | |
319 | case '-': | |
8d03032a | 320 | trigger_error($data, E_USER_ERROR); |
bb7dcc1e LM |
321 | break; |
322 | case '+': | |
323 | return $data; | |
8d03032a | 324 | case ':': |
325 | $i = strpos($data, '.') !== false ? (int)$data : (float)$data; | |
326 | if ((string)$i != $data) | |
327 | trigger_error("Cannot convert data '$c$data' to integer", E_USER_ERROR); | |
328 | return $i; | |
329 | case '$': | |
330 | return $this->get_bulk_reply($c . $data); | |
bb7dcc1e LM |
331 | case '*': |
332 | $num = (int)$data; | |
333 | if ((string)$num != $data) | |
334 | trigger_error("Cannot convert multi-response header '$data' to integer", E_USER_ERROR); | |
335 | $result = array(); | |
336 | for ($i=0; $i<$num; $i++) | |
8d03032a | 337 | $result[] =& $this->get_response(); |
bb7dcc1e LM |
338 | return $result; |
339 | default: | |
8d03032a | 340 | trigger_error("Invalid reply type byte: '$c'"); |
ed9b544e | 341 | } |
bb7dcc1e LM |
342 | } |
343 | ||
8d03032a | 344 | private function get_bulk_reply($data=null) { |
bb7dcc1e | 345 | if ($data === null) |
8d03032a | 346 | $data = trim($this->read()); |
bb7dcc1e | 347 | if ($data == '$-1') |
ed9b544e | 348 | return null; |
bb7dcc1e LM |
349 | $c = $data[0]; |
350 | $data = substr($data, 1); | |
8d03032a | 351 | $bulklen = (int)$data; |
352 | if ((string)$bulklen != $data) | |
353 | trigger_error("Cannot convert bulk read header '$c$data' to integer", E_USER_ERROR); | |
bb7dcc1e LM |
354 | if ($c != '$') |
355 | trigger_error("Unkown response prefix for '$c$data'", E_USER_ERROR); | |
ed9b544e | 356 | $buffer = ''; |
8d03032a | 357 | while ($bulklen) { |
358 | $data = fread($this->_sock,$bulklen); | |
359 | $bulklen -= strlen($data); | |
bb7dcc1e | 360 | $buffer .= $data; |
ed9b544e | 361 | } |
8d03032a | 362 | $crlf = fread($this->_sock,2); |
363 | return $buffer; | |
ed9b544e | 364 | } |
8d03032a | 365 | } |
ed9b544e | 366 | |
975a5b6f | 367 | /* |
8d03032a | 368 | $r = new Redis(); |
975a5b6f | 369 | var_dump($r->set("foo","bar")); |
8d03032a | 370 | var_dump($r->get("foo")); |
371 | var_dump($r->info()); | |
975a5b6f | 372 | */ |
ed9b544e | 373 | |
374 | ?> |