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