]> git.saurik.com Git - redis.git/blob - client-libraries/php/redis.php
RANDOMKEY issue 26 fixed, generic test + regression added
[redis.git] / client-libraries / php / redis.php
1 <?php
2 /*******************************************************************************
3 * Redis PHP Bindings - http://code.google.com/p/redis/
4 *
5 * Copyright 2009 Ludovico Magnocavallo
6 * Released under the same license as Redis.
7 *
8 * Version: 0.1
9 *
10 * $Revision: 139 $
11 * $Date: 2009-03-15 22:59:40 +0100 (Dom, 15 Mar 2009) $
12 *
13 ******************************************************************************/
14
15
16 class Redis {
17
18 var $server;
19 var $port;
20 var $_sock;
21
22 function Redis($host, $port=6379) {
23 $this->host = $host;
24 $this->port = $port;
25 }
26
27 function connect() {
28 if ($this->_sock)
29 return;
30 if ($sock = fsockopen($this->host, $this->port, $errno, $errstr)) {
31 $this->_sock = $sock;
32 return;
33 }
34 $msg = "Cannot open socket to {$this->host}:{$this->port}";
35 if ($errno || $errmsg)
36 $msg .= "," . ($errno ? " error $errno" : "") . ($errmsg ? " $errmsg" : "");
37 trigger_error("$msg.", E_USER_ERROR);
38 }
39
40 function disconnect() {
41 if ($this->_sock)
42 @fclose($this->_sock);
43 $this->_sock = null;
44 }
45
46 function &ping() {
47 $this->connect();
48 $this->_write("PING\r\n");
49 return $this->_simple_response();
50 }
51
52 function &do_echo($s) {
53 $this->connect();
54 $this->_write("ECHO " . strlen($s) . "\r\n$s\r\n");
55 return $this->_get_value();
56 }
57
58 function &set($name, $value, $preserve=false) {
59 $this->connect();
60 $this->_write(
61 ($preserve ? 'SETNX' : 'SET') .
62 " $name " . strlen($value) . "\r\n$value\r\n"
63 );
64 return $preserve ? $this->_numeric_response() : $this->_simple_response();
65 }
66
67 function &get($name) {
68 $this->connect();
69 $this->_write("GET $name\r\n");
70 return $this->_get_value();
71 }
72
73 function &incr($name, $amount=1) {
74 $this->connect();
75 if ($amount == 1)
76 $this->_write("INCR $name\r\n");
77 else
78 $this->_write("INCRBY $name $amount\r\n");
79 return $this->_numeric_response();
80 }
81
82 function &decr($name, $amount=1) {
83 $this->connect();
84 if ($amount == 1)
85 $this->_write("DECR $name\r\n");
86 else
87 $this->_write("DECRBY $name $amount\r\n");
88 return $this->_numeric_response();
89 }
90
91 function &exists($name) {
92 $this->connect();
93 $this->_write("EXISTS $name\r\n");
94 return $this->_numeric_response();
95 }
96
97 function &delete($name) {
98 $this->connect();
99 $this->_write("DEL $name\r\n");
100 return $this->_numeric_response();
101 }
102
103 function &keys($pattern) {
104 $this->connect();
105 $this->_write("KEYS $pattern\r\n");
106 return explode(' ', $this->_get_value());
107 }
108
109 function &randomkey() {
110 $this->connect();
111 $this->_write("RANDOMKEY\r\n");
112 $s =& trim($this->_read());
113 $this->_check_for_error($s);
114 return $s;
115 }
116
117 function &rename($src, $dst, $preserve=False) {
118 $this->connect();
119 if ($preserve) {
120 $this->_write("RENAMENX $src $dst\r\n");
121 return $this->_numeric_response();
122 }
123 $this->_write("RENAME $src $dst\r\n");
124 return trim($this->_simple_response());
125 }
126
127 function &push($name, $value, $tail=true) {
128 // default is to append the element to the list
129 $this->connect();
130 $this->_write(
131 ($tail ? 'RPUSH' : 'LPUSH') .
132 " $name " . strlen($value) . "\r\n$value\r\n"
133 );
134 return $this->_simple_response();
135 }
136
137 function &ltrim($name, $start, $end) {
138 $this->connect();
139 $this->_write("LTRIM $name $start $end\r\n");
140 return $this->_simple_response();
141 }
142
143 function &lindex($name, $index) {
144 $this->connect();
145 $this->_write("LINDEX $name $index\r\n");
146 return $this->_get_value();
147 }
148
149 function &pop($name, $tail=true) {
150 $this->connect();
151 $this->_write(
152 ($tail ? 'RPOP' : 'LPOP') .
153 " $name\r\n"
154 );
155 return $this->_get_value();
156 }
157
158 function &llen($name) {
159 $this->connect();
160 $this->_write("LLEN $name\r\n");
161 return $this->_numeric_response();
162 }
163
164 function &lrange($name, $start, $end) {
165 $this->connect();
166 $this->_write("LRANGE $name $start $end\r\n");
167 return $this->_get_multi();
168 }
169
170 function &sort($name, $query=false) {
171 $this->connect();
172 if ($query === false) {
173 $this->_write("SORT $name\r\n");
174 } else {
175 $this->_write("SORT $name $query\r\n");
176 }
177 return $this->_get_multi();
178 }
179
180 function &lset($name, $value, $index) {
181 $this->connect();
182 $this->_write("LSET $name $index " . strlen($value) . "\r\n$value\r\n");
183 return $this->_simple_response();
184 }
185
186 function &sadd($name, $value) {
187 $this->connect();
188 $this->_write("SADD $name " . strlen($value) . "\r\n$value\r\n");
189 return $this->_numeric_response();
190 }
191
192 function &srem($name, $value) {
193 $this->connect();
194 $this->_write("SREM $name " . strlen($value) . "\r\n$value\r\n");
195 return $this->_numeric_response();
196 }
197
198 function &sismember($name, $value) {
199 $this->connect();
200 $this->_write("SISMEMBER $name " . strlen($value) . "\r\n$value\r\n");
201 return $this->_numeric_response();
202 }
203
204 function &sinter($sets) {
205 $this->connect();
206 $this->_write('SINTER ' . implode(' ', $sets) . "\r\n");
207 return $this->_get_multi();
208 }
209
210 function &smembers($name) {
211 $this->connect();
212 $this->_write("SMEMBERS $name\r\n");
213 return $this->_get_multi();
214 }
215
216 function &scard($name) {
217 $this->connect();
218 $this->_write("SCARD $name\r\n");
219 return $this->_numeric_response();
220 }
221
222 function &select_db($name) {
223 $this->connect();
224 $this->_write("SELECT $name\r\n");
225 return $this->_simple_response();
226 }
227
228 function &move($name, $db) {
229 $this->connect();
230 $this->_write("MOVE $name $db\r\n");
231 return $this->_numeric_response();
232 }
233
234 function &save($background=false) {
235 $this->connect();
236 $this->_write(($background ? "BGSAVE\r\n" : "SAVE\r\n"));
237 return $this->_simple_response();
238 }
239
240 function &lastsave() {
241 $this->connect();
242 $this->_write("LASTSAVE\r\n");
243 return $this->_numeric_response();
244 }
245
246 function &_write($s) {
247 while ($s) {
248 $i = fwrite($this->_sock, $s);
249 if ($i == 0)
250 break;
251 $s = substr($s, $i);
252 }
253 }
254
255 function &_read($len=1024) {
256 if ($s = fgets($this->_sock))
257 return $s;
258 $this->disconnect();
259 trigger_error("Cannot read from socket.", E_USER_ERROR);
260 }
261
262 function _check_for_error(&$s) {
263 if (!$s || $s[0] != '-')
264 return;
265 if (substr($s, 0, 4) == '-ERR')
266 trigger_error("Redis error: " . trim(substr($s, 4)), E_USER_ERROR);
267 trigger_error("Redis error: " . substr(trim($this->_read()), 5), E_USER_ERROR);
268 }
269
270 function &_simple_response() {
271 $s =& trim($this->_read());
272 if ($s[0] == '+')
273 return substr($s, 1);
274 if ($err =& $this->_check_for_error($s))
275 return $err;
276 trigger_error("Cannot parse first line '$s' for a simple response", E_USER_ERROR);
277 }
278
279 function &_numeric_response($allow_negative=True) {
280 $s =& trim($this->_read());
281 $i = (int)$s;
282 if ($i . '' == $s) {
283 if (!$allow_negative && $i < 0)
284 $this->_check_for_error($s);
285 return $i;
286 }
287 if ($s == 'nil')
288 return null;
289 trigger_error("Cannot parse '$s' as numeric response.");
290 }
291
292 function &_get_value() {
293 $s =& trim($this->_read());
294 if ($s == 'nil')
295 return '';
296 else if ($s[0] == '-')
297 $this->_check_for_error($s);
298 $i = (int)$s;
299 if ($i . '' != $s)
300 trigger_error("Cannot parse '$s' as data length.");
301 $buffer = '';
302 while ($i > 0) {
303 $s = $this->_read();
304 $l = strlen($s);
305 $i -= $l;
306 if ($l > $i) // ending crlf
307 $s = rtrim($s);
308 $buffer .= $s;
309 }
310 if ($i == 0) // let's restore the trailing crlf
311 $buffer .= $this->_read();
312 return $buffer;
313 }
314
315 function &_get_multi() {
316 $results = array();
317 $num =& $this->_numeric_response(false);
318 if ($num === false)
319 return $results;
320 while ($num) {
321 $results[] =& $this->_get_value();
322 $num -= 1;
323 }
324 return $results;
325 }
326
327 }
328
329
330 ?>