Completed
Push — master ( 0dda59...7f247a )
by Peter
02:32
created
src/SphinxClient.php 4 patches
Doc Comments   +22 added lines patch added patch discarded remove patch
@@ -246,6 +246,9 @@  discard block
 block discarded – undo
246 246
 }
247 247
 
248 248
 // unpack 64-bit unsigned
249
+/**
250
+ * @param string $v
251
+ */
249 252
 function sphUnpackU64($v)
250 253
 {
251 254
     list($hi, $lo) = array_values(unpack("N*N*", $v));
@@ -312,6 +315,9 @@  discard block
 block discarded – undo
312 315
 }
313 316
 
314 317
 // unpack 64-bit signed
318
+/**
319
+ * @param string $v
320
+ */
315 321
 function sphUnpackI64($v)
316 322
 {
317 323
     list($hi, $lo) = array_values(unpack("N*N*", $v));
@@ -396,6 +402,9 @@  discard block
 block discarded – undo
396 402
     }
397 403
 }
398 404
 
405
+/**
406
+ * @param integer $bit
407
+ */
399 408
 function sphSetBit($flag, $bit, $on)
400 409
 {
401 410
     if ($on)
@@ -566,6 +575,10 @@  discard block
 block discarded – undo
566 575
     }
567 576
 
568 577
 
578
+    /**
579
+     * @param string $data
580
+     * @param integer $length
581
+     */
569 582
     function _Send($handle, $data, $length)
570 583
     {
571 584
         if (feof($handle) || fwrite($handle, $data, $length) !== $length)
@@ -669,6 +682,10 @@  discard block
 block discarded – undo
669 682
     }
670 683
 
671 684
     /// get and check response packet from searchd server
685
+
686
+    /**
687
+     * @param integer $client_ver
688
+     */
672 689
     function _GetResponse($fp, $client_ver)
673 690
     {
674 691
         $response = "";
@@ -1257,6 +1274,11 @@  discard block
 block discarded – undo
1257 1274
     }
1258 1275
 
1259 1276
     /// parse and return search query (or queries) response
1277
+
1278
+    /**
1279
+     * @param string $response
1280
+     * @param integer $nreqs
1281
+     */
1260 1282
     function _ParseSearchResponse($response, $nreqs)
1261 1283
     {
1262 1284
         $p = 0; // current position
Please login to merge, or discard this patch.
Braces   +3 added lines, -2 removed lines patch added patch discarded remove patch
@@ -1854,8 +1854,9 @@
 block discarded – undo
1854 1854
             $this->error = 'already connected';
1855 1855
             return false;
1856 1856
         }
1857
-        if (!($fp = $this->connect()))
1858
-            return false;
1857
+        if (!($fp = $this->connect())) {
1858
+                    return false;
1859
+        }
1859 1860
 
1860 1861
         // command, command version = 0, body length = 4, body = 1
1861 1862
         $req = pack('nnNN', SEARCHD_COMMAND_PERSIST, 0, 4, 1);
Please login to merge, or discard this patch.
Indentation   +1781 added lines, -1781 removed lines patch added patch discarded remove patch
@@ -140,1815 +140,1815 @@
 block discarded – undo
140 140
 /// pack 64-bit signed
141 141
 function sphPackI64($v)
142 142
 {
143
-    assert(is_numeric($v));
144
-
145
-    // x64
146
-    if (PHP_INT_SIZE >= 8) {
147
-        $v = (int)$v;
148
-        return pack('NN', $v >> 32, $v & 0xFFFFFFFF);
149
-    }
150
-
151
-    // x32, int
152
-    if (is_int($v)) {
153
-        return pack('NN', $v < 0 ? -1 : 0, $v);
154
-    }
155
-
156
-    // x32, bcmath
157
-    if (function_exists('bcmul')) {
158
-        if (bccomp($v, 0) == -1) {
159
-            $v = bcadd('18446744073709551616', $v);
160
-        }
161
-        $h = bcdiv($v, '4294967296', 0);
162
-        $l = bcmod($v, '4294967296');
163
-        return pack('NN', (float)$h, (float)$l); // conversion to float is intentional; int would lose 31st bit
164
-    }
165
-
166
-    // x32, no-bcmath
167
-    $p = max(0, strlen($v) - 13);
168
-    $lo = abs((float)substr($v, $p));
169
-    $hi = abs((float)substr($v, 0, $p));
170
-
171
-    $m = $lo + $hi * 1316134912.0; // (10 ^ 13) % (1 << 32) = 1316134912
172
-    $q = floor($m / 4294967296.0);
173
-    $l = $m - ($q * 4294967296.0);
174
-    $h = $hi * 2328.0 + $q; // (10 ^ 13) / (1 << 32) = 2328
175
-
176
-    if ($v < 0) {
177
-        if ($l == 0) {
178
-            $h = 4294967296.0 - $h;
179
-        } else {
180
-            $h = 4294967295.0 - $h;
181
-            $l = 4294967296.0 - $l;
182
-        }
183
-    }
184
-    return pack('NN', $h, $l);
143
+	assert(is_numeric($v));
144
+
145
+	// x64
146
+	if (PHP_INT_SIZE >= 8) {
147
+		$v = (int)$v;
148
+		return pack('NN', $v >> 32, $v & 0xFFFFFFFF);
149
+	}
150
+
151
+	// x32, int
152
+	if (is_int($v)) {
153
+		return pack('NN', $v < 0 ? -1 : 0, $v);
154
+	}
155
+
156
+	// x32, bcmath
157
+	if (function_exists('bcmul')) {
158
+		if (bccomp($v, 0) == -1) {
159
+			$v = bcadd('18446744073709551616', $v);
160
+		}
161
+		$h = bcdiv($v, '4294967296', 0);
162
+		$l = bcmod($v, '4294967296');
163
+		return pack('NN', (float)$h, (float)$l); // conversion to float is intentional; int would lose 31st bit
164
+	}
165
+
166
+	// x32, no-bcmath
167
+	$p = max(0, strlen($v) - 13);
168
+	$lo = abs((float)substr($v, $p));
169
+	$hi = abs((float)substr($v, 0, $p));
170
+
171
+	$m = $lo + $hi * 1316134912.0; // (10 ^ 13) % (1 << 32) = 1316134912
172
+	$q = floor($m / 4294967296.0);
173
+	$l = $m - ($q * 4294967296.0);
174
+	$h = $hi * 2328.0 + $q; // (10 ^ 13) / (1 << 32) = 2328
175
+
176
+	if ($v < 0) {
177
+		if ($l == 0) {
178
+			$h = 4294967296.0 - $h;
179
+		} else {
180
+			$h = 4294967295.0 - $h;
181
+			$l = 4294967296.0 - $l;
182
+		}
183
+	}
184
+	return pack('NN', $h, $l);
185 185
 }
186 186
 
187 187
 /// pack 64-bit unsigned
188 188
 function sphPackU64($v)
189 189
 {
190
-    assert(is_numeric($v));
191
-
192
-    // x64
193
-    if (PHP_INT_SIZE >= 8) {
194
-        assert($v >= 0);
195
-
196
-        // x64, int
197
-        if (is_int($v)) {
198
-            return pack('NN', $v >> 32, $v & 0xFFFFFFFF);
199
-        }
200
-
201
-        // x64, bcmath
202
-        if (function_exists('bcmul')) {
203
-            $h = bcdiv($v, 4294967296, 0);
204
-            $l = bcmod($v, 4294967296);
205
-            return pack('NN', $h, $l);
206
-        }
207
-
208
-        // x64, no-bcmath
209
-        $p = max(0, strlen($v) - 13);
210
-        $lo = (int)substr($v, $p);
211
-        $hi = (int)substr($v, 0, $p);
212
-
213
-        $m = $lo + $hi * 1316134912;
214
-        $l = $m % 4294967296;
215
-        $h = $hi * 2328 + (int)($m / 4294967296);
216
-
217
-        return pack('NN', $h, $l);
218
-    }
219
-
220
-    // x32, int
221
-    if (is_int($v)) {
222
-        return pack('NN', 0, $v);
223
-    }
224
-
225
-    // x32, bcmath
226
-    if (function_exists('bcmul')) {
227
-        $h = bcdiv($v, '4294967296', 0);
228
-        $l = bcmod($v, '4294967296');
229
-        return pack('NN', (float)$h, (float)$l); // conversion to float is intentional; int would lose 31st bit
230
-    }
231
-
232
-    // x32, no-bcmath
233
-    $p = max(0, strlen($v) - 13);
234
-    $lo = (float)substr($v, $p);
235
-    $hi = (float)substr($v, 0, $p);
236
-
237
-    $m = $lo + $hi * 1316134912.0;
238
-    $q = floor($m / 4294967296.0);
239
-    $l = $m - ($q * 4294967296.0);
240
-    $h = $hi * 2328.0 + $q;
241
-
242
-    return pack('NN', $h, $l);
190
+	assert(is_numeric($v));
191
+
192
+	// x64
193
+	if (PHP_INT_SIZE >= 8) {
194
+		assert($v >= 0);
195
+
196
+		// x64, int
197
+		if (is_int($v)) {
198
+			return pack('NN', $v >> 32, $v & 0xFFFFFFFF);
199
+		}
200
+
201
+		// x64, bcmath
202
+		if (function_exists('bcmul')) {
203
+			$h = bcdiv($v, 4294967296, 0);
204
+			$l = bcmod($v, 4294967296);
205
+			return pack('NN', $h, $l);
206
+		}
207
+
208
+		// x64, no-bcmath
209
+		$p = max(0, strlen($v) - 13);
210
+		$lo = (int)substr($v, $p);
211
+		$hi = (int)substr($v, 0, $p);
212
+
213
+		$m = $lo + $hi * 1316134912;
214
+		$l = $m % 4294967296;
215
+		$h = $hi * 2328 + (int)($m / 4294967296);
216
+
217
+		return pack('NN', $h, $l);
218
+	}
219
+
220
+	// x32, int
221
+	if (is_int($v)) {
222
+		return pack('NN', 0, $v);
223
+	}
224
+
225
+	// x32, bcmath
226
+	if (function_exists('bcmul')) {
227
+		$h = bcdiv($v, '4294967296', 0);
228
+		$l = bcmod($v, '4294967296');
229
+		return pack('NN', (float)$h, (float)$l); // conversion to float is intentional; int would lose 31st bit
230
+	}
231
+
232
+	// x32, no-bcmath
233
+	$p = max(0, strlen($v) - 13);
234
+	$lo = (float)substr($v, $p);
235
+	$hi = (float)substr($v, 0, $p);
236
+
237
+	$m = $lo + $hi * 1316134912.0;
238
+	$q = floor($m / 4294967296.0);
239
+	$l = $m - ($q * 4294967296.0);
240
+	$h = $hi * 2328.0 + $q;
241
+
242
+	return pack('NN', $h, $l);
243 243
 }
244 244
 
245 245
 // unpack 64-bit unsigned
246 246
 function sphUnpackU64($v)
247 247
 {
248
-    list($hi, $lo) = array_values(unpack('N*N*', $v));
249
-
250
-    if (PHP_INT_SIZE >= 8) {
251
-        if ($hi < 0) { // because php 5.2.2 to 5.2.5 is totally fucked up again
252
-            $hi += 1 << 32;
253
-        }
254
-        if ($lo < 0) {
255
-            $lo += 1 << 32;
256
-        }
257
-
258
-        // x64, int
259
-        if ($hi <= 2147483647) {
260
-            return ($hi << 32) + $lo;
261
-        }
262
-
263
-        // x64, bcmath
264
-        if (function_exists('bcmul')) {
265
-            return bcadd($lo, bcmul($hi, '4294967296'));
266
-        }
267
-
268
-        // x64, no-bcmath
269
-        $C = 100000;
270
-        $h = ((int)($hi / $C) << 32) + (int)($lo / $C);
271
-        $l = (($hi % $C) << 32) + ($lo % $C);
272
-        if ($l > $C) {
273
-            $h += (int)($l / $C);
274
-            $l  = $l % $C;
275
-        }
276
-
277
-        if ($h == 0) {
278
-            return $l;
279
-        }
280
-        return sprintf('%d%05d', $h, $l);
281
-    }
282
-
283
-    // x32, int
284
-    if ($hi == 0) {
285
-        if ($lo > 0) {
286
-            return $lo;
287
-        }
288
-        return sprintf('%u', $lo);
289
-    }
290
-
291
-    $hi = sprintf('%u', $hi);
292
-    $lo = sprintf('%u', $lo);
293
-
294
-    // x32, bcmath
295
-    if (function_exists('bcmul')) {
296
-        return bcadd($lo, bcmul($hi, '4294967296'));
297
-    }
298
-
299
-    // x32, no-bcmath
300
-    $hi = (float)$hi;
301
-    $lo = (float)$lo;
302
-
303
-    $q = floor($hi / 10000000.0);
304
-    $r = $hi - $q * 10000000.0;
305
-    $m = $lo + $r * 4967296.0;
306
-    $mq = floor($m / 10000000.0);
307
-    $l = $m - $mq * 10000000.0;
308
-    $h = $q * 4294967296.0 + $r * 429.0 + $mq;
309
-
310
-    $h = sprintf('%.0f', $h);
311
-    $l = sprintf('%07.0f', $l);
312
-    if ($h == '0') {
313
-        return sprintf('%.0f', (float)$l);
314
-    }
315
-    return $h . $l;
248
+	list($hi, $lo) = array_values(unpack('N*N*', $v));
249
+
250
+	if (PHP_INT_SIZE >= 8) {
251
+		if ($hi < 0) { // because php 5.2.2 to 5.2.5 is totally fucked up again
252
+			$hi += 1 << 32;
253
+		}
254
+		if ($lo < 0) {
255
+			$lo += 1 << 32;
256
+		}
257
+
258
+		// x64, int
259
+		if ($hi <= 2147483647) {
260
+			return ($hi << 32) + $lo;
261
+		}
262
+
263
+		// x64, bcmath
264
+		if (function_exists('bcmul')) {
265
+			return bcadd($lo, bcmul($hi, '4294967296'));
266
+		}
267
+
268
+		// x64, no-bcmath
269
+		$C = 100000;
270
+		$h = ((int)($hi / $C) << 32) + (int)($lo / $C);
271
+		$l = (($hi % $C) << 32) + ($lo % $C);
272
+		if ($l > $C) {
273
+			$h += (int)($l / $C);
274
+			$l  = $l % $C;
275
+		}
276
+
277
+		if ($h == 0) {
278
+			return $l;
279
+		}
280
+		return sprintf('%d%05d', $h, $l);
281
+	}
282
+
283
+	// x32, int
284
+	if ($hi == 0) {
285
+		if ($lo > 0) {
286
+			return $lo;
287
+		}
288
+		return sprintf('%u', $lo);
289
+	}
290
+
291
+	$hi = sprintf('%u', $hi);
292
+	$lo = sprintf('%u', $lo);
293
+
294
+	// x32, bcmath
295
+	if (function_exists('bcmul')) {
296
+		return bcadd($lo, bcmul($hi, '4294967296'));
297
+	}
298
+
299
+	// x32, no-bcmath
300
+	$hi = (float)$hi;
301
+	$lo = (float)$lo;
302
+
303
+	$q = floor($hi / 10000000.0);
304
+	$r = $hi - $q * 10000000.0;
305
+	$m = $lo + $r * 4967296.0;
306
+	$mq = floor($m / 10000000.0);
307
+	$l = $m - $mq * 10000000.0;
308
+	$h = $q * 4294967296.0 + $r * 429.0 + $mq;
309
+
310
+	$h = sprintf('%.0f', $h);
311
+	$l = sprintf('%07.0f', $l);
312
+	if ($h == '0') {
313
+		return sprintf('%.0f', (float)$l);
314
+	}
315
+	return $h . $l;
316 316
 }
317 317
 
318 318
 // unpack 64-bit signed
319 319
 function sphUnpackI64($v)
320 320
 {
321
-    list($hi, $lo) = array_values(unpack('N*N*', $v));
322
-
323
-    // x64
324
-    if (PHP_INT_SIZE >= 8) {
325
-        if ($hi < 0) { // because php 5.2.2 to 5.2.5 is totally fucked up again
326
-            $hi += 1 << 32;
327
-        }
328
-        if ($lo < 0) {
329
-            $lo += 1 << 32;
330
-        }
331
-
332
-        return ($hi << 32) + $lo;
333
-    }
334
-
335
-    if ($hi == 0) { // x32, int
336
-        if ($lo > 0) {
337
-            return $lo;
338
-        }
339
-        return sprintf('%u', $lo);
340
-    } elseif ($hi == -1) { // x32, int
341
-        if ($lo < 0) {
342
-            return $lo;
343
-        }
344
-        return sprintf('%.0f', $lo - 4294967296.0);
345
-    }
346
-
347
-    $neg = '';
348
-    $c = 0;
349
-    if ($hi < 0) {
350
-        $hi = ~$hi;
351
-        $lo = ~$lo;
352
-        $c = 1;
353
-        $neg = '-';
354
-    }
355
-
356
-    $hi = sprintf('%u', $hi);
357
-    $lo = sprintf('%u', $lo);
358
-
359
-    // x32, bcmath
360
-    if (function_exists('bcmul')) {
361
-        return $neg . bcadd(bcadd($lo, bcmul($hi, '4294967296')), $c);
362
-    }
363
-
364
-    // x32, no-bcmath
365
-    $hi = (float)$hi;
366
-    $lo = (float)$lo;
367
-
368
-    $q = floor($hi / 10000000.0);
369
-    $r = $hi - $q * 10000000.0;
370
-    $m = $lo + $r * 4967296.0;
371
-    $mq = floor($m / 10000000.0);
372
-    $l = $m - $mq * 10000000.0 + $c;
373
-    $h = $q * 4294967296.0 + $r * 429.0 + $mq;
374
-    if ($l == 10000000) {
375
-        $l = 0;
376
-        $h += 1;
377
-    }
378
-
379
-    $h = sprintf('%.0f', $h);
380
-    $l = sprintf('%07.0f', $l);
381
-    if ($h == '0') {
382
-        return $neg . sprintf('%.0f', (float)$l);
383
-    }
384
-    return $neg . $h . $l;
321
+	list($hi, $lo) = array_values(unpack('N*N*', $v));
322
+
323
+	// x64
324
+	if (PHP_INT_SIZE >= 8) {
325
+		if ($hi < 0) { // because php 5.2.2 to 5.2.5 is totally fucked up again
326
+			$hi += 1 << 32;
327
+		}
328
+		if ($lo < 0) {
329
+			$lo += 1 << 32;
330
+		}
331
+
332
+		return ($hi << 32) + $lo;
333
+	}
334
+
335
+	if ($hi == 0) { // x32, int
336
+		if ($lo > 0) {
337
+			return $lo;
338
+		}
339
+		return sprintf('%u', $lo);
340
+	} elseif ($hi == -1) { // x32, int
341
+		if ($lo < 0) {
342
+			return $lo;
343
+		}
344
+		return sprintf('%.0f', $lo - 4294967296.0);
345
+	}
346
+
347
+	$neg = '';
348
+	$c = 0;
349
+	if ($hi < 0) {
350
+		$hi = ~$hi;
351
+		$lo = ~$lo;
352
+		$c = 1;
353
+		$neg = '-';
354
+	}
355
+
356
+	$hi = sprintf('%u', $hi);
357
+	$lo = sprintf('%u', $lo);
358
+
359
+	// x32, bcmath
360
+	if (function_exists('bcmul')) {
361
+		return $neg . bcadd(bcadd($lo, bcmul($hi, '4294967296')), $c);
362
+	}
363
+
364
+	// x32, no-bcmath
365
+	$hi = (float)$hi;
366
+	$lo = (float)$lo;
367
+
368
+	$q = floor($hi / 10000000.0);
369
+	$r = $hi - $q * 10000000.0;
370
+	$m = $lo + $r * 4967296.0;
371
+	$mq = floor($m / 10000000.0);
372
+	$l = $m - $mq * 10000000.0 + $c;
373
+	$h = $q * 4294967296.0 + $r * 429.0 + $mq;
374
+	if ($l == 10000000) {
375
+		$l = 0;
376
+		$h += 1;
377
+	}
378
+
379
+	$h = sprintf('%.0f', $h);
380
+	$l = sprintf('%07.0f', $l);
381
+	if ($h == '0') {
382
+		return $neg . sprintf('%.0f', (float)$l);
383
+	}
384
+	return $neg . $h . $l;
385 385
 }
386 386
 
387 387
 
388 388
 function sphFixUint($value)
389 389
 {
390
-    if (PHP_INT_SIZE >= 8) {
391
-        // x64 route, workaround broken unpack() in 5.2.2+
392
-        if ($value < 0) {
393
-            $value += 1 << 32;
394
-        }
395
-        return $value;
396
-    } else {
397
-        // x32 route, workaround php signed/unsigned braindamage
398
-        return sprintf('%u', $value);
399
-    }
390
+	if (PHP_INT_SIZE >= 8) {
391
+		// x64 route, workaround broken unpack() in 5.2.2+
392
+		if ($value < 0) {
393
+			$value += 1 << 32;
394
+		}
395
+		return $value;
396
+	} else {
397
+		// x32 route, workaround php signed/unsigned braindamage
398
+		return sprintf('%u', $value);
399
+	}
400 400
 }
401 401
 
402 402
 function sphSetBit($flag, $bit, $on)
403 403
 {
404
-    if ($on) {
405
-        $flag |= 1 << $bit;
406
-    } else {
407
-        $reset = 16777215 ^ (1 << $bit);
408
-        $flag = $flag & $reset;
409
-    }
410
-    return $flag;
404
+	if ($on) {
405
+		$flag |= 1 << $bit;
406
+	} else {
407
+		$reset = 16777215 ^ (1 << $bit);
408
+		$flag = $flag & $reset;
409
+	}
410
+	return $flag;
411 411
 }
412 412
 
413 413
 
414 414
 /// sphinx searchd client class
415 415
 class SphinxClient
416 416
 {
417
-    protected $host; ///< searchd host (default is 'localhost')
418
-    protected $port; ///< searchd port (default is 9312)
419
-    protected $offset; ///< how many records to seek from result-set start (default is 0)
420
-    protected $limit; ///< how many records to return from result-set starting at offset (default is 20)
421
-    protected $mode; ///< query matching mode (default is SPH_MATCH_EXTENDED2)
422
-    protected $weights; ///< per-field weights (default is 1 for all fields)
423
-    protected $sort; ///< match sorting mode (default is SPH_SORT_RELEVANCE)
424
-    protected $sortby; ///< attribute to sort by (defualt is '')
425
-    protected $min_id; ///< min ID to match (default is 0, which means no limit)
426
-    protected $max_id; ///< max ID to match (default is 0, which means no limit)
427
-    protected $filters; ///< search filters
428
-    protected $groupby; ///< group-by attribute name
429
-    protected $groupfunc; ///< group-by function (to pre-process group-by attribute value with)
430
-    protected $groupsort; ///< group-by sorting clause (to sort groups in result set with)
431
-    protected $groupdistinct; ///< group-by count-distinct attribute
432
-    protected $maxmatches; ///< max matches to retrieve
433
-    protected $cutoff; ///< cutoff to stop searching at (default is 0)
434
-    protected $retrycount; ///< distributed retries count
435
-    protected $retrydelay; ///< distributed retries delay
436
-    protected $anchor; ///< geographical anchor point
437
-    protected $indexweights; ///< per-index weights
438
-    protected $ranker; ///< ranking mode (default is SPH_RANK_PROXIMITY_BM25)
439
-    protected $rankexpr; ///< ranking mode expression (for SPH_RANK_EXPR)
440
-    protected $maxquerytime; ///< max query time, milliseconds (default is 0, do not limit)
441
-    protected $fieldweights; ///< per-field-name weights
442
-    protected $overrides; ///< per-query attribute values overrides
443
-    protected $select; ///< select-list (attributes or expressions, with optional aliases)
444
-    protected $query_flags; ///< per-query various flags
445
-    protected $predictedtime; ///< per-query max_predicted_time
446
-    protected $outerorderby; ///< outer match sort by
447
-    protected $outeroffset; ///< outer offset
448
-    protected $outerlimit; ///< outer limit
449
-    protected $hasouter;
450
-
451
-    protected $error; ///< last error message
452
-    protected $warning; ///< last warning message
453
-    protected $connerror; ///< connection error vs remote error flag
454
-
455
-    protected $reqs; ///< requests array for multi-query
456
-    protected $mbenc; ///< stored mbstring encoding
457
-    protected $arrayresult; ///< whether $result['matches'] should be a hash or an array
458
-    protected $timeout; ///< connect timeout
459
-
460
-    /////////////////////////////////////////////////////////////////////////////
461
-    // common stuff
462
-    /////////////////////////////////////////////////////////////////////////////
463
-
464
-    /// create a new client object and fill defaults
465
-    public function __construct()
466
-    {
467
-        // per-client-object settings
468
-        $this->host = 'localhost';
469
-        $this->port = 9312;
470
-        $this->_path = false;
471
-        $this->_socket = false;
472
-
473
-        // per-query settings
474
-        $this->offset = 0;
475
-        $this->limit = 20;
476
-        $this->mode = SPH_MATCH_EXTENDED2;
477
-        $this->weights = array();
478
-        $this->sort = SPH_SORT_RELEVANCE;
479
-        $this->sortby = '';
480
-        $this->min_id = 0;
481
-        $this->max_id = 0;
482
-        $this->filters = array();
483
-        $this->groupby = '';
484
-        $this->groupfunc = SPH_GROUPBY_DAY;
485
-        $this->groupsort = '@group desc';
486
-        $this->groupdistinct = '';
487
-        $this->maxmatches = 1000;
488
-        $this->cutoff = 0;
489
-        $this->retrycount = 0;
490
-        $this->retrydelay = 0;
491
-        $this->anchor = array();
492
-        $this->indexweights = array();
493
-        $this->ranker = SPH_RANK_PROXIMITY_BM25;
494
-        $this->rankexpr = '';
495
-        $this->maxquerytime = 0;
496
-        $this->fieldweights = array();
497
-        $this->overrides = array();
498
-        $this->select = '*';
499
-        $this->query_flags = sphSetBit(0, 6, true); // default idf=tfidf_normalized
500
-        $this->predictedtime = 0;
501
-        $this->outerorderby = '';
502
-        $this->outeroffset = 0;
503
-        $this->outerlimit = 0;
504
-        $this->hasouter = false;
505
-
506
-        $this->error = ''; // per-reply fields (for single-query case)
507
-        $this->warning = '';
508
-        $this->connerror = false;
509
-
510
-        $this->reqs = array();// requests storage (for multi-query case)
511
-        $this->mbenc = '';
512
-        $this->arrayresult = false;
513
-        $this->timeout = 0;
514
-    }
515
-
516
-    public function __destruct()
517
-    {
518
-        if ($this->_socket !== false) {
519
-            fclose($this->_socket);
520
-        }
521
-    }
522
-
523
-    /// get last error message (string)
524
-    public function getLastError()
525
-    {
526
-        return $this->error;
527
-    }
528
-
529
-    /// get last warning message (string)
530
-    public function getLastWarning()
531
-    {
532
-        return $this->warning;
533
-    }
534
-
535
-    /// get last error flag (to tell network connection errors from searchd errors or broken responses)
536
-    public function isConnectError()
537
-    {
538
-        return $this->connerror;
539
-    }
540
-
541
-    /// set searchd host name (string) and port (integer)
542
-    public function setServer($host, $port = 0)
543
-    {
544
-        assert(is_string($host));
545
-        if ($host[0] == '/') {
546
-            $this->_path = 'unix://' . $host;
547
-            return;
548
-        }
549
-        if (substr($host, 0, 7) == 'unix://') {
550
-            $this->_path = $host;
551
-            return;
552
-        }
553
-
554
-        $this->host = $host;
555
-        $port = intval($port);
556
-        assert(0 <= $port && $port < 65536);
557
-        $this->port = $port == 0 ? 9312 : $port;
558
-        $this->_path = '';
559
-    }
560
-
561
-    /// set server connection timeout (0 to remove)
562
-    public function setConnectTimeout($timeout)
563
-    {
564
-        assert(is_numeric($timeout));
565
-        $this->timeout = $timeout;
566
-    }
567
-
568
-
569
-    protected function send($handle, $data, $length)
570
-    {
571
-        if (feof($handle) || fwrite($handle, $data, $length) !== $length) {
572
-            $this->error = 'connection unexpectedly closed (timed out?)';
573
-            $this->connerror = true;
574
-            return false;
575
-        }
576
-        return true;
577
-    }
578
-
579
-    /////////////////////////////////////////////////////////////////////////////
580
-
581
-    /// enter mbstring workaround mode
582
-    protected function mbPush()
583
-    {
584
-        $this->mbenc = '';
585
-        if (ini_get('mbstring.func_overload') & 2) {
586
-            $this->mbenc = mb_internal_encoding();
587
-            mb_internal_encoding('latin1');
588
-        }
589
-    }
590
-
591
-    /// leave mbstring workaround mode
592
-    protected function mbPop()
593
-    {
594
-        if ($this->mbenc) {
595
-            mb_internal_encoding($this->mbenc);
596
-        }
597
-    }
598
-
599
-    /// connect to searchd server
600
-    protected function connect()
601
-    {
602
-        if ($this->_socket !== false) {
603
-            // we are in persistent connection mode, so we have a socket
604
-            // however, need to check whether it's still alive
605
-            if (!@feof($this->_socket)) {
606
-                return $this->_socket;
607
-            }
608
-
609
-            // force reopen
610
-            $this->_socket = false;
611
-        }
612
-
613
-        $errno = 0;
614
-        $errstr = '';
615
-        $this->connerror = false;
616
-
617
-        if ($this->_path) {
618
-            $host = $this->_path;
619
-            $port = 0;
620
-        } else {
621
-            $host = $this->host;
622
-            $port = $this->port;
623
-        }
624
-
625
-        if ($this->timeout <= 0) {
626
-            $fp = @fsockopen($host, $port, $errno, $errstr);
627
-        } else {
628
-            $fp = @fsockopen($host, $port, $errno, $errstr, $this->timeout);
629
-        }
630
-
631
-        if (!$fp) {
632
-            if ($this->_path) {
633
-                $location = $this->_path;
634
-            } else {
635
-                $location = "{$this->host}:{$this->port}";
636
-            }
637
-
638
-            $errstr = trim($errstr);
639
-            $this->error = "connection to $location failed (errno=$errno, msg=$errstr)";
640
-            $this->connerror = true;
641
-            return false;
642
-        }
643
-
644
-        // send my version
645
-        // this is a subtle part. we must do it before (!) reading back from searchd.
646
-        // because otherwise under some conditions (reported on FreeBSD for instance)
647
-        // TCP stack could throttle write-write-read pattern because of Nagle.
648
-        if (!$this->send($fp, pack('N', 1), 4)) {
649
-            fclose($fp);
650
-            $this->error = 'failed to send client protocol version';
651
-            return false;
652
-        }
653
-
654
-        // check version
655
-        list(, $v) = unpack('N*', fread($fp, 4));
656
-        $v = (int)$v;
657
-        if ($v < 1) {
658
-            fclose($fp);
659
-            $this->error = "expected searchd protocol version 1+, got version '$v'";
660
-            return false;
661
-        }
662
-
663
-        return $fp;
664
-    }
665
-
666
-    /// get and check response packet from searchd server
667
-    protected function getResponse($fp, $client_ver)
668
-    {
669
-        $response = '';
670
-        $len = 0;
671
-
672
-        $header = fread($fp, 8);
673
-        if (strlen($header) == 8) {
674
-            list($status, $ver, $len) = array_values(unpack('n2a/Nb', $header));
675
-            $left = $len;
676
-            while ($left > 0 && !feof($fp)) {
677
-                $chunk = fread($fp, min(8192, $left));
678
-                if ($chunk) {
679
-                    $response .= $chunk;
680
-                    $left -= strlen($chunk);
681
-                }
682
-            }
683
-        }
684
-        if ($this->_socket === false) {
685
-            fclose($fp);
686
-        }
687
-
688
-        // check response
689
-        $read = strlen($response);
690
-        if (!$response || $read != $len) {
691
-            $this->error = $len
692
-                ? "failed to read searchd response (status=$status, ver=$ver, len=$len, read=$read)"
693
-                : 'received zero-sized searchd response';
694
-            return false;
695
-        }
696
-
697
-        // check status
698
-        if ($status == SEARCHD_WARNING) {
699
-            list(, $wlen) = unpack('N*', substr($response, 0, 4));
700
-            $this->warning = substr($response, 4, $wlen);
701
-            return substr($response, 4 + $wlen);
702
-        }
703
-        if ($status == SEARCHD_ERROR) {
704
-            $this->error = 'searchd error: ' . substr($response, 4);
705
-            return false;
706
-        }
707
-        if ($status == SEARCHD_RETRY) {
708
-            $this->error = 'temporary searchd error: ' . substr($response, 4);
709
-            return false;
710
-        }
711
-        if ($status != SEARCHD_OK) {
712
-            $this->error = "unknown status code '$status'";
713
-            return false;
714
-        }
715
-
716
-        // check version
717
-        if ($ver < $client_ver) {
718
-            $this->warning = sprintf(
719
-                'searchd command v.%d.%d older than client\'s v.%d.%d, some options might not work',
720
-                $ver >> 8,
721
-                $ver & 0xff,
722
-                $client_ver >> 8,
723
-                $client_ver & 0xff
724
-            );
725
-        }
726
-
727
-        return $response;
728
-    }
729
-
730
-    /////////////////////////////////////////////////////////////////////////////
731
-    // searching
732
-    /////////////////////////////////////////////////////////////////////////////
733
-
734
-    /// set offset and count into result set,
735
-    /// and optionally set max-matches and cutoff limits
736
-    public function setLimits($offset, $limit, $max = 0, $cutoff = 0)
737
-    {
738
-        assert(is_int($offset));
739
-        assert(is_int($limit));
740
-        assert($offset >= 0);
741
-        assert($limit > 0);
742
-        assert($max >= 0);
743
-        $this->offset = $offset;
744
-        $this->limit = $limit;
745
-        if ($max > 0) {
746
-            $this->maxmatches = $max;
747
-        }
748
-        if ($cutoff > 0) {
749
-            $this->cutoff = $cutoff;
750
-        }
751
-    }
752
-
753
-    /// set maximum query time, in milliseconds, per-index
754
-    /// integer, 0 means 'do not limit'
755
-    public function setMaxQueryTime($max)
756
-    {
757
-        assert(is_int($max));
758
-        assert($max >= 0);
759
-        $this->maxquerytime = $max;
760
-    }
761
-
762
-    /// set matching mode
763
-    public function setMatchMode($mode)
764
-    {
765
-        trigger_error(
766
-            'DEPRECATED: Do not call this method or, even better, use SphinxQL instead of an API',
767
-            E_USER_DEPRECATED
768
-        );
769
-        assert(
770
-            $mode == SPH_MATCH_ALL ||
771
-            $mode == SPH_MATCH_ANY ||
772
-            $mode == SPH_MATCH_PHRASE ||
773
-            $mode == SPH_MATCH_BOOLEAN ||
774
-            $mode == SPH_MATCH_EXTENDED ||
775
-            $mode == SPH_MATCH_FULLSCAN ||
776
-            $mode == SPH_MATCH_EXTENDED2
777
-        );
778
-        $this->mode = $mode;
779
-    }
780
-
781
-    /// set ranking mode
782
-    public function setRankingMode($ranker, $rankexpr='')
783
-    {
784
-        assert($ranker === 0 || $ranker >= 1 && $ranker < SPH_RANK_TOTAL);
785
-        assert(is_string($rankexpr));
786
-        $this->ranker = $ranker;
787
-        $this->rankexpr = $rankexpr;
788
-    }
789
-
790
-    /// set matches sorting mode
791
-    public function setSortMode($mode, $sortby = '')
792
-    {
793
-        assert (
794
-            $mode == SPH_SORT_RELEVANCE ||
795
-            $mode == SPH_SORT_ATTR_DESC ||
796
-            $mode == SPH_SORT_ATTR_ASC ||
797
-            $mode == SPH_SORT_TIME_SEGMENTS ||
798
-            $mode == SPH_SORT_EXTENDED ||
799
-            $mode == SPH_SORT_EXPR
800
-        );
801
-        assert(is_string($sortby));
802
-        assert($mode == SPH_SORT_RELEVANCE || strlen($sortby) > 0);
803
-
804
-        $this->sort = $mode;
805
-        $this->sortby = $sortby;
806
-    }
807
-
808
-    /**
809
-     * Bind per-field weights by order
810
-     *
811
-     * @deprecated use setFieldWeights() instead
812
-     */
813
-    public function setWeights()
814
-    {
815
-        throw new \RuntimeException('This method is now deprecated; please use setFieldWeights instead');
816
-    }
817
-
818
-    /// bind per-field weights by name
819
-    public function setFieldWeights($weights)
820
-    {
821
-        assert(is_array($weights));
822
-        foreach ($weights as $name => $weight) {
823
-            assert(is_string($name));
824
-            assert(is_int($weight));
825
-        }
826
-        $this->fieldweights = $weights;
827
-    }
828
-
829
-    /// bind per-index weights by name
830
-    public function setIndexWeights($weights)
831
-    {
832
-        assert(is_array($weights));
833
-        foreach ($weights as $index => $weight) {
834
-            assert(is_string($index));
835
-            assert(is_int($weight));
836
-        }
837
-        $this->indexweights = $weights;
838
-    }
839
-
840
-    /// set IDs range to match
841
-    /// only match records if document ID is beetwen $min and $max (inclusive)
842
-    public function setIDRange($min, $max)
843
-    {
844
-        assert(is_numeric($min));
845
-        assert(is_numeric($max));
846
-        assert($min <= $max);
847
-        $this->min_id = $min;
848
-        $this->max_id = $max;
849
-    }
850
-
851
-    /// set values set filter
852
-    /// only match records where $attribute value is in given set
853
-    public function setFilter($attribute, $values, $exclude = false)
854
-    {
855
-        assert(is_string($attribute));
856
-        assert(is_array($values));
857
-        assert(count($values));
858
-
859
-        if (is_array($values) && count($values)) {
860
-            foreach ($values as $value) {
861
-                assert(is_numeric($value));
862
-            }
863
-
864
-            $this->filters[] = array(
865
-                'type' => SPH_FILTER_VALUES,
866
-                'attr' => $attribute,
867
-                'exclude' => $exclude,
868
-                'values' => $values
869
-            );
870
-        }
871
-    }
872
-
873
-    /// set string filter
874
-    /// only match records where $attribute value is equal
875
-    public function setFilterString($attribute, $value, $exclude = false)
876
-    {
877
-        assert(is_string($attribute));
878
-        assert(is_string($value));
879
-        $this->filters[] = array(
880
-            'type' => SPH_FILTER_STRING,
881
-            'attr' => $attribute,
882
-            'exclude' => $exclude,
883
-            'value' => $value
884
-        );
885
-    }    
886
-
887
-    /// set range filter
888
-    /// only match records if $attribute value is beetwen $min and $max (inclusive)
889
-    public function setFilterRange($attribute, $min, $max, $exclude = false)
890
-    {
891
-        assert(is_string($attribute));
892
-        assert(is_numeric($min));
893
-        assert(is_numeric($max));
894
-        assert($min <= $max);
895
-
896
-        $this->filters[] = array(
897
-            'type' => SPH_FILTER_RANGE,
898
-            'attr' => $attribute,
899
-            'exclude' => $exclude,
900
-            'min' => $min,
901
-            'max' => $max
902
-        );
903
-    }
904
-
905
-    /// set float range filter
906
-    /// only match records if $attribute value is beetwen $min and $max (inclusive)
907
-    public function setFilterFloatRange($attribute, $min, $max, $exclude = false)
908
-    {
909
-        assert(is_string($attribute));
910
-        assert(is_float($min));
911
-        assert(is_float($max));
912
-        assert($min <= $max);
913
-
914
-        $this->filters[] = array(
915
-            'type' => SPH_FILTER_FLOATRANGE,
916
-            'attr' => $attribute,
917
-            'exclude' => $exclude,
918
-            'min' => $min,
919
-            'max' => $max
920
-        );
921
-    }
922
-
923
-    /// setup anchor point for geosphere distance calculations
924
-    /// required to use @geodist in filters and sorting
925
-    /// latitude and longitude must be in radians
926
-    public function setGeoAnchor($attrlat, $attrlong, $lat, $long)
927
-    {
928
-        assert(is_string($attrlat));
929
-        assert(is_string($attrlong));
930
-        assert(is_float($lat));
931
-        assert(is_float($long));
932
-
933
-        $this->anchor = array(
934
-            'attrlat' => $attrlat,
935
-            'attrlong' => $attrlong,
936
-            'lat' => $lat,
937
-            'long' => $long
938
-        );
939
-    }
940
-
941
-    /// set grouping attribute and function
942
-    public function setGroupBy($attribute, $func, $groupsort = '@group desc')
943
-    {
944
-        assert(is_string($attribute));
945
-        assert(is_string($groupsort));
946
-        assert(
947
-            $func == SPH_GROUPBY_DAY ||
948
-            $func == SPH_GROUPBY_WEEK ||
949
-            $func == SPH_GROUPBY_MONTH ||
950
-            $func == SPH_GROUPBY_YEAR ||
951
-            $func == SPH_GROUPBY_ATTR ||
952
-            $func == SPH_GROUPBY_ATTRPAIR
953
-        );
954
-
955
-        $this->groupby = $attribute;
956
-        $this->groupfunc = $func;
957
-        $this->groupsort = $groupsort;
958
-    }
959
-
960
-    /// set count-distinct attribute for group-by queries
961
-    public function setGroupDistinct($attribute)
962
-    {
963
-        assert(is_string($attribute));
964
-        $this->groupdistinct = $attribute;
965
-    }
966
-
967
-    /// set distributed retries count and delay
968
-    public function setRetries($count, $delay = 0)
969
-    {
970
-        assert(is_int($count) && $count >= 0);
971
-        assert(is_int($delay) && $delay >= 0);
972
-        $this->retrycount = $count;
973
-        $this->retrydelay = $delay;
974
-    }
975
-
976
-    /// set result set format (hash or array; hash by default)
977
-    /// PHP specific; needed for group-by-MVA result sets that may contain duplicate IDs
978
-    public function setArrayResult($arrayresult)
979
-    {
980
-        assert(is_bool($arrayresult));
981
-        $this->arrayresult = $arrayresult;
982
-    }
983
-
984
-    /// set attribute values override
985
-    /// there can be only one override per attribute
986
-    /// $values must be a hash that maps document IDs to attribute values
987
-    public function setOverride($attrname, $attrtype, $values)
988
-    {
989
-        trigger_error(
990
-            'DEPRECATED: Do not call this method. Use SphinxQL REMAP() function instead.',
991
-            E_USER_DEPRECATED
992
-        );
993
-        assert(is_string($attrname));
994
-        assert(in_array($attrtype, array(
995
-            SPH_ATTR_INTEGER,
996
-            SPH_ATTR_TIMESTAMP,
997
-            SPH_ATTR_BOOL,
998
-            SPH_ATTR_FLOAT,
999
-            SPH_ATTR_BIGINT
1000
-        )));
1001
-        assert(is_array($values));
1002
-
1003
-        $this->overrides[$attrname] = array(
1004
-            'attr' => $attrname,
1005
-            'type' => $attrtype,
1006
-            'values' => $values
1007
-        );
1008
-    }
1009
-
1010
-    /// set select-list (attributes or expressions), SQL-like syntax
1011
-    public function setSelect($select)
1012
-    {
1013
-        assert(is_string($select));
1014
-        $this->select = $select;
1015
-    }
1016
-
1017
-    public function setQueryFlag($flag_name, $flag_value)
1018
-    {
1019
-        $known_names = array(
1020
-            'reverse_scan',
1021
-            'sort_method',
1022
-            'max_predicted_time',
1023
-            'boolean_simplify',
1024
-            'idf',
1025
-            'global_idf',
1026
-            'low_priority'
1027
-        );
1028
-        $flags = array (
1029
-            'reverse_scan' => array(0, 1),
1030
-            'sort_method' => array('pq', 'kbuffer'),
1031
-            'max_predicted_time' => array(0),
1032
-            'boolean_simplify' => array(true, false),
1033
-            'idf' => array ('normalized', 'plain', 'tfidf_normalized', 'tfidf_unnormalized'),
1034
-            'global_idf' => array(true, false),
1035
-            'low_priority' => array(true, false)
1036
-        );
1037
-
1038
-        assert(isset($flag_name, $known_names));
1039
-        assert(
1040
-            in_array($flag_value, $flags[$flag_name], true) ||
1041
-            ($flag_name == 'max_predicted_time' && is_int($flag_value) && $flag_value >= 0)
1042
-        );
1043
-
1044
-        if ($flag_name == 'reverse_scan') {
1045
-            $this->query_flags = sphSetBit($this->query_flags, 0, $flag_value == 1);
1046
-        }
1047
-        if ($flag_name == 'sort_method') {
1048
-            $this->query_flags = sphSetBit($this->query_flags, 1, $flag_value == 'kbuffer');
1049
-        }
1050
-        if ($flag_name == 'max_predicted_time') {
1051
-            $this->query_flags = sphSetBit($this->query_flags, 2, $flag_value > 0);
1052
-            $this->predictedtime = (int)$flag_value;
1053
-        }
1054
-        if ($flag_name == 'boolean_simplify') {
1055
-            $this->query_flags = sphSetBit($this->query_flags, 3, $flag_value);
1056
-        }
1057
-        if ($flag_name == 'idf' && ($flag_value == 'normalized' || $flag_value == 'plain')) {
1058
-            $this->query_flags = sphSetBit($this->query_flags, 4, $flag_value == 'plain');
1059
-        }
1060
-        if ($flag_name == 'global_idf') {
1061
-            $this->query_flags = sphSetBit($this->query_flags, 5, $flag_value);
1062
-        }
1063
-        if ($flag_name == 'idf' && ($flag_value == 'tfidf_normalized' || $flag_value == 'tfidf_unnormalized')) {
1064
-            $this->query_flags = sphSetBit($this->query_flags, 6, $flag_value == 'tfidf_normalized');
1065
-        }
1066
-        if ($flag_name == 'low_priority') {
1067
-            $this->query_flags = sphSetBit($this->query_flags, 8, $flag_value);
1068
-        }
1069
-    }
1070
-
1071
-    /// set outer order by parameters
1072
-    public function setOuterSelect($orderby, $offset, $limit)
1073
-    {
1074
-        assert(is_string($orderby));
1075
-        assert(is_int($offset));
1076
-        assert(is_int($limit));
1077
-        assert($offset >= 0);
1078
-        assert($limit > 0);
1079
-
1080
-        $this->outerorderby = $orderby;
1081
-        $this->outeroffset = $offset;
1082
-        $this->outerlimit = $limit;
1083
-        $this->hasouter = true;
1084
-    }
1085
-
1086
-
1087
-    //////////////////////////////////////////////////////////////////////////////
1088
-
1089
-    /// clear all filters (for multi-queries)
1090
-    public function resetFilters()
1091
-    {
1092
-        $this->filters = array();
1093
-        $this->anchor = array();
1094
-    }
1095
-
1096
-    /// clear groupby settings (for multi-queries)
1097
-    public function resetGroupBy()
1098
-    {
1099
-        $this->groupby = '';
1100
-        $this->groupfunc = SPH_GROUPBY_DAY;
1101
-        $this->groupsort = '@group desc';
1102
-        $this->groupdistinct = '';
1103
-    }
1104
-
1105
-    /// clear all attribute value overrides (for multi-queries)
1106
-    public function resetOverrides()
1107
-    {
1108
-        $this->overrides = array();
1109
-    }
1110
-
1111
-    public function resetQueryFlag()
1112
-    {
1113
-        $this->query_flags = sphSetBit(0, 6, true); // default idf=tfidf_normalized
1114
-        $this->predictedtime = 0;
1115
-    }
1116
-
1117
-    public function resetOuterSelect()
1118
-    {
1119
-        $this->outerorderby = '';
1120
-        $this->outeroffset = 0;
1121
-        $this->outerlimit = 0;
1122
-        $this->hasouter = false;
1123
-    }
1124
-
1125
-    //////////////////////////////////////////////////////////////////////////////
1126
-
1127
-    /// connect to searchd server, run given search query through given indexes,
1128
-    /// and return the search results
1129
-    public function query($query, $index = '*', $comment = '')
1130
-    {
1131
-        assert(empty($this->reqs));
1132
-
1133
-        $this->addQuery($query, $index, $comment);
1134
-        $results = $this->runQueries();
1135
-        $this->reqs = array(); // just in case it failed too early
1136
-
1137
-        if (!is_array($results)) {
1138
-            return false; // probably network error; error message should be already filled
1139
-        }
1140
-
1141
-        $this->error = $results[0]['error'];
1142
-        $this->warning = $results[0]['warning'];
1143
-        if ($results[0]['status'] == SEARCHD_ERROR) {
1144
-            return false;
1145
-        } else {
1146
-            return $results[0];
1147
-        }
1148
-    }
1149
-
1150
-    /// helper to pack floats in network byte order
1151
-    protected function packFloat($f)
1152
-    {
1153
-        $t1 = pack('f', $f); // machine order
1154
-        list(, $t2) = unpack('L*', $t1); // int in machine order
1155
-        return pack('N', $t2);
1156
-    }
1157
-
1158
-    /// add query to multi-query batch
1159
-    /// returns index into results array from RunQueries() call
1160
-    public function addQuery($query, $index = '*', $comment = '')
1161
-    {
1162
-        // mbstring workaround
1163
-        $this->mbPush();
1164
-
1165
-        // build request
1166
-        $req = pack('NNNNN', $this->query_flags, $this->offset, $this->limit, $this->mode, $this->ranker);
1167
-        if ($this->ranker == SPH_RANK_EXPR) {
1168
-            $req .= pack('N', strlen($this->rankexpr)) . $this->rankexpr;
1169
-        }
1170
-        $req .= pack('N', $this->sort); // (deprecated) sort mode
1171
-        $req .= pack('N', strlen($this->sortby)) . $this->sortby;
1172
-        $req .= pack('N', strlen($query)) . $query; // query itself
1173
-        $req .= pack('N', count($this->weights)); // weights
1174
-        foreach ($this->weights as $weight) {
1175
-            $req .= pack('N', (int)$weight);
1176
-        }
1177
-        $req .= pack('N', strlen($index)) . $index; // indexes
1178
-        $req .= pack('N', 1); // id64 range marker
1179
-        $req .= sphPackU64($this->min_id) . sphPackU64($this->max_id); // id64 range
1180
-
1181
-        // filters
1182
-        $req .= pack('N', count($this->filters));
1183
-        foreach ($this->filters as $filter) {
1184
-            $req .= pack('N', strlen($filter['attr'])) . $filter['attr'];
1185
-            $req .= pack('N', $filter['type']);
1186
-            switch ($filter['type']) {
1187
-                case SPH_FILTER_VALUES:
1188
-                    $req .= pack('N', count($filter['values']));
1189
-                    foreach ($filter['values'] as $value) {
1190
-                        $req .= sphPackI64($value);
1191
-                    }
1192
-                    break;
1193
-                case SPH_FILTER_RANGE:
1194
-                    $req .= sphPackI64($filter['min']) . sphPackI64($filter['max']);
1195
-                    break;
1196
-                case SPH_FILTER_FLOATRANGE:
1197
-                    $req .= $this->packFloat($filter['min']) . $this->packFloat($filter['max']);
1198
-                    break;
1199
-                case SPH_FILTER_STRING:
1200
-                    $req .= pack('N', strlen($filter['value'])) . $filter['value'];
1201
-                    break;
1202
-                default:
1203
-                    assert(0 && 'internal error: unhandled filter type');
1204
-            }
1205
-            $req .= pack('N', $filter['exclude']);
1206
-        }
1207
-
1208
-        // group-by clause, max-matches count, group-sort clause, cutoff count
1209
-        $req .= pack('NN', $this->groupfunc, strlen($this->groupby)) . $this->groupby;
1210
-        $req .= pack('N', $this->maxmatches);
1211
-        $req .= pack('N', strlen($this->groupsort)) . $this->groupsort;
1212
-        $req .= pack('NNN', $this->cutoff, $this->retrycount, $this->retrydelay);
1213
-        $req .= pack('N', strlen($this->groupdistinct)) . $this->groupdistinct;
1214
-
1215
-        // anchor point
1216
-        if (empty($this->anchor)) {
1217
-            $req .= pack('N', 0);
1218
-        } else {
1219
-            $a =& $this->anchor;
1220
-            $req .= pack('N', 1);
1221
-            $req .= pack('N', strlen($a['attrlat'])) . $a['attrlat'];
1222
-            $req .= pack('N', strlen($a['attrlong'])) . $a['attrlong'];
1223
-            $req .= $this->packFloat($a['lat']) . $this->packFloat($a['long']);
1224
-        }
1225
-
1226
-        // per-index weights
1227
-        $req .= pack('N', count($this->indexweights));
1228
-        foreach ($this->indexweights as $idx => $weight) {
1229
-            $req .= pack('N', strlen($idx)) . $idx . pack('N', $weight);
1230
-        }
1231
-
1232
-        // max query time
1233
-        $req .= pack('N', $this->maxquerytime);
1234
-
1235
-        // per-field weights
1236
-        $req .= pack('N', count($this->fieldweights));
1237
-        foreach ($this->fieldweights as $field => $weight) {
1238
-            $req .= pack('N', strlen($field)) . $field . pack('N', $weight);
1239
-        }
1240
-
1241
-        // comment
1242
-        $req .= pack('N', strlen($comment)) . $comment;
1243
-
1244
-        // attribute overrides
1245
-        $req .= pack('N', count($this->overrides));
1246
-        foreach ($this->overrides as $key => $entry) {
1247
-            $req .= pack('N', strlen($entry['attr'])) . $entry['attr'];
1248
-            $req .= pack('NN', $entry['type'], count($entry['values']));
1249
-            foreach ($entry['values'] as $id => $val) {
1250
-                assert(is_numeric($id));
1251
-                assert(is_numeric($val));
1252
-
1253
-                $req .= sphPackU64($id);
1254
-                switch ($entry['type']) {
1255
-                    case SPH_ATTR_FLOAT:
1256
-                        $req .= $this->packFloat($val);
1257
-                        break;
1258
-                    case SPH_ATTR_BIGINT:
1259
-                        $req .= sphPackI64($val);
1260
-                        break;
1261
-                    default:
1262
-                        $req .= pack('N', $val);
1263
-                        break;
1264
-                }
1265
-            }
1266
-        }
1267
-
1268
-        // select-list
1269
-        $req .= pack('N', strlen($this->select)) . $this->select;
1270
-
1271
-        // max_predicted_time
1272
-        if ($this->predictedtime > 0) {
1273
-            $req .= pack('N', (int)$this->predictedtime);
1274
-        }
1275
-
1276
-        $req .= pack('N', strlen($this->outerorderby)) . $this->outerorderby;
1277
-        $req .= pack('NN', $this->outeroffset, $this->outerlimit);
1278
-        if ($this->hasouter) {
1279
-            $req .= pack('N', 1);
1280
-        } else {
1281
-            $req .= pack('N', 0);
1282
-        }
1283
-
1284
-        // mbstring workaround
1285
-        $this->mbPop();
1286
-
1287
-        // store request to requests array
1288
-        $this->reqs[] = $req;
1289
-        return count($this->reqs) - 1;
1290
-    }
1291
-
1292
-    /// connect to searchd, run queries batch, and return an array of result sets
1293
-    public function runQueries()
1294
-    {
1295
-        if (empty($this->reqs)) {
1296
-            $this->error = 'no queries defined, issue AddQuery() first';
1297
-            return false;
1298
-        }
1299
-
1300
-        // mbstring workaround
1301
-        $this->mbPush();
1302
-
1303
-        if (!($fp = $this->connect())) {
1304
-            $this->mbPop();
1305
-            return false;
1306
-        }
1307
-
1308
-        // send query, get response
1309
-        $nreqs = count($this->reqs);
1310
-        $req = join('', $this->reqs);
1311
-        $len = 8 + strlen($req);
1312
-        $req = pack('nnNNN', SEARCHD_COMMAND_SEARCH, VER_COMMAND_SEARCH, $len, 0, $nreqs) . $req; // add header
1313
-
1314
-        if (!$this->send($fp, $req, $len + 8) || !($response = $this->getResponse($fp, VER_COMMAND_SEARCH))) {
1315
-            $this->mbPop();
1316
-            return false;
1317
-        }
1318
-
1319
-        // query sent ok; we can reset reqs now
1320
-        $this->reqs = array();
1321
-
1322
-        // parse and return response
1323
-        return $this->parseSearchResponse($response, $nreqs);
1324
-    }
1325
-
1326
-    /// parse and return search query (or queries) response
1327
-    protected function parseSearchResponse($response, $nreqs)
1328
-    {
1329
-        $p = 0; // current position
1330
-        $max = strlen($response); // max position for checks, to protect against broken responses
1331
-
1332
-        $results = array();
1333
-        for ($ires = 0; $ires < $nreqs && $p < $max; $ires++) {
1334
-            $results[] = array();
1335
-            $result =& $results[$ires];
1336
-
1337
-            $result['error'] = '';
1338
-            $result['warning'] = '';
1339
-
1340
-            // extract status
1341
-            list(, $status) = unpack('N*', substr($response, $p, 4));
1342
-            $p += 4;
1343
-            $result['status'] = $status;
1344
-            if ($status != SEARCHD_OK) {
1345
-                list(, $len) = unpack('N*', substr($response, $p, 4));
1346
-                $p += 4;
1347
-                $message = substr($response, $p, $len);
1348
-                $p += $len;
1349
-
1350
-                if ($status == SEARCHD_WARNING) {
1351
-                    $result['warning'] = $message;
1352
-                } else {
1353
-                    $result['error'] = $message;
1354
-                    continue;
1355
-                }
1356
-            }
1357
-
1358
-            // read schema
1359
-            $fields = array();
1360
-            $attrs = array();
1361
-
1362
-            list(, $nfields) = unpack('N*', substr($response, $p, 4));
1363
-            $p += 4;
1364
-            while ($nfields --> 0 && $p < $max) {
1365
-                list(, $len) = unpack('N*', substr($response, $p, 4));
1366
-                $p += 4;
1367
-                $fields[] = substr($response, $p, $len);
1368
-                $p += $len;
1369
-            }
1370
-            $result['fields'] = $fields;
1371
-
1372
-            list(, $nattrs) = unpack('N*', substr($response, $p, 4));
1373
-            $p += 4;
1374
-            while ($nattrs --> 0 && $p < $max) {
1375
-                list(, $len) = unpack('N*', substr($response, $p, 4));
1376
-                $p += 4;
1377
-                $attr = substr($response, $p, $len);
1378
-                $p += $len;
1379
-                list(, $type) = unpack('N*', substr($response, $p, 4));
1380
-                $p += 4;
1381
-                $attrs[$attr] = $type;
1382
-            }
1383
-            $result['attrs'] = $attrs;
1384
-
1385
-            // read match count
1386
-            list(, $count) = unpack('N*', substr($response, $p, 4));
1387
-            $p += 4;
1388
-            list(, $id64) = unpack('N*', substr($response, $p, 4));
1389
-            $p += 4;
1390
-
1391
-            // read matches
1392
-            $idx = -1;
1393
-            while ($count --> 0 && $p < $max) {
1394
-                // index into result array
1395
-                $idx++;
1396
-
1397
-                // parse document id and weight
1398
-                if ($id64) {
1399
-                    $doc = sphUnpackU64(substr($response, $p, 8));
1400
-                    $p += 8;
1401
-                    list(,$weight) = unpack('N*', substr($response, $p, 4));
1402
-                    $p += 4;
1403
-                } else {
1404
-                    list($doc, $weight) = array_values(unpack('N*N*', substr($response, $p, 8)));
1405
-                    $p += 8;
1406
-                    $doc = sphFixUint($doc);
1407
-                }
1408
-                $weight = sprintf('%u', $weight);
1409
-
1410
-                // create match entry
1411
-                if ($this->arrayresult) {
1412
-                    $result['matches'][$idx] = array('id' => $doc, 'weight' => $weight);
1413
-                } else {
1414
-                    $result['matches'][$doc]['weight'] = $weight;
1415
-                }
1416
-
1417
-                // parse and create attributes
1418
-                $attrvals = array();
1419
-                foreach ($attrs as $attr => $type) {
1420
-                    // handle 64bit ints
1421
-                    if ($type == SPH_ATTR_BIGINT) {
1422
-                        $attrvals[$attr] = sphUnpackI64(substr($response, $p, 8));
1423
-                        $p += 8;
1424
-                        continue;
1425
-                    }
1426
-
1427
-                    // handle floats
1428
-                    if ($type == SPH_ATTR_FLOAT) {
1429
-                        list(, $uval) = unpack('N*', substr($response, $p, 4));
1430
-                        $p += 4;
1431
-                        list(, $fval) = unpack('f*', pack('L', $uval));
1432
-                        $attrvals[$attr] = $fval;
1433
-                        continue;
1434
-                    }
1435
-
1436
-                    // handle everything else as unsigned ints
1437
-                    list(, $val) = unpack('N*', substr($response, $p, 4));
1438
-                    $p += 4;
1439
-                    if ($type == SPH_ATTR_MULTI) {
1440
-                        $attrvals[$attr] = array();
1441
-                        $nvalues = $val;
1442
-                        while ($nvalues --> 0 && $p < $max) {
1443
-                            list(, $val) = unpack('N*', substr($response, $p, 4));
1444
-                            $p += 4;
1445
-                            $attrvals[$attr][] = sphFixUint($val);
1446
-                        }
1447
-                    } elseif ($type == SPH_ATTR_MULTI64) {
1448
-                        $attrvals[$attr] = array();
1449
-                        $nvalues = $val;
1450
-                        while ($nvalues > 0 && $p < $max) {
1451
-                            $attrvals[$attr][] = sphUnpackI64(substr($response, $p, 8));
1452
-                            $p += 8;
1453
-                            $nvalues -= 2;
1454
-                        }
1455
-                    } elseif ($type == SPH_ATTR_STRING) {
1456
-                        $attrvals[$attr] = substr($response, $p, $val);
1457
-                        $p += $val;
1458
-                    } elseif ($type == SPH_ATTR_FACTORS) {
1459
-                        $attrvals[$attr] = substr($response, $p, $val - 4);
1460
-                        $p += $val-4;
1461
-                    } else {
1462
-                        $attrvals[$attr] = sphFixUint($val);
1463
-                    }
1464
-                }
1465
-
1466
-                if ($this->arrayresult) {
1467
-                    $result['matches'][$idx]['attrs'] = $attrvals;
1468
-                } else {
1469
-                    $result['matches'][$doc]['attrs'] = $attrvals;
1470
-                }
1471
-            }
1472
-
1473
-            list($total, $total_found, $msecs, $words) = array_values(unpack('N*N*N*N*', substr($response, $p, 16)));
1474
-            $result['total'] = sprintf('%u', $total);
1475
-            $result['total_found'] = sprintf('%u', $total_found);
1476
-            $result['time'] = sprintf('%.3f', $msecs / 1000);
1477
-            $p += 16;
1478
-
1479
-            while ($words --> 0 && $p < $max) {
1480
-                list(, $len) = unpack('N*', substr($response, $p, 4));
1481
-                $p += 4;
1482
-                $word = substr($response, $p, $len);
1483
-                $p += $len;
1484
-                list($docs, $hits) = array_values(unpack('N*N*', substr($response, $p, 8)));
1485
-                $p += 8;
1486
-                $result['words'][$word] = array (
1487
-                    'docs' => sprintf('%u', $docs),
1488
-                    'hits' => sprintf('%u', $hits)
1489
-                );
1490
-            }
1491
-        }
1492
-
1493
-        $this->mbPop();
1494
-        return $results;
1495
-    }
1496
-
1497
-    /////////////////////////////////////////////////////////////////////////////
1498
-    // excerpts generation
1499
-    /////////////////////////////////////////////////////////////////////////////
1500
-
1501
-    /// connect to searchd server, and generate exceprts (snippets)
1502
-    /// of given documents for given query. returns false on failure,
1503
-    /// an array of snippets on success
1504
-    public function buildExcerpts($docs, $index, $words, $opts = array())
1505
-    {
1506
-        assert(is_array($docs));
1507
-        assert(is_string($index));
1508
-        assert(is_string($words));
1509
-        assert(is_array($opts));
1510
-
1511
-        $this->mbPush();
1512
-
1513
-        if (!($fp = $this->connect())) {
1514
-            $this->mbPop();
1515
-            return false;
1516
-        }
1517
-
1518
-        /////////////////
1519
-        // fixup options
1520
-        /////////////////
1521
-
1522
-        if (!isset($opts['before_match'])) {
1523
-            $opts['before_match'] = '<b>';
1524
-        }
1525
-        if (!isset($opts['after_match'])) {
1526
-            $opts['after_match'] = '</b>';
1527
-        }
1528
-        if (!isset($opts['chunk_separator'])) {
1529
-            $opts['chunk_separator'] = ' ... ';
1530
-        }
1531
-        if (!isset($opts['limit'])) {
1532
-            $opts['limit'] = 256;
1533
-        }
1534
-        if (!isset($opts['limit_passages'])) {
1535
-            $opts['limit_passages'] = 0;
1536
-        }
1537
-        if (!isset($opts['limit_words'])) {
1538
-            $opts['limit_words'] = 0;
1539
-        }
1540
-        if (!isset($opts['around'])) {
1541
-            $opts['around'] = 5;
1542
-        }
1543
-        if (!isset($opts['exact_phrase'])) {
1544
-            $opts['exact_phrase'] = false;
1545
-        }
1546
-        if (!isset($opts['single_passage'])) {
1547
-            $opts['single_passage'] = false;
1548
-        }
1549
-        if (!isset($opts['use_boundaries'])) {
1550
-            $opts['use_boundaries'] = false;
1551
-        }
1552
-        if (!isset($opts['weight_order'])) {
1553
-            $opts['weight_order'] = false;
1554
-        }
1555
-        if (!isset($opts['query_mode'])) {
1556
-            $opts['query_mode'] = false;
1557
-        }
1558
-        if (!isset($opts['force_all_words'])) {
1559
-            $opts['force_all_words'] = false;
1560
-        }
1561
-        if (!isset($opts['start_passage_id'])) {
1562
-            $opts['start_passage_id'] = 1;
1563
-        }
1564
-        if (!isset($opts['load_files'])) {
1565
-            $opts['load_files'] = false;
1566
-        }
1567
-        if (!isset($opts['html_strip_mode'])) {
1568
-            $opts['html_strip_mode'] = 'index';
1569
-        }
1570
-        if (!isset($opts['allow_empty'])) {
1571
-            $opts['allow_empty'] = false;
1572
-        }
1573
-        if (!isset($opts['passage_boundary'])) {
1574
-            $opts['passage_boundary'] = 'none';
1575
-        }
1576
-        if (!isset($opts['emit_zones'])) {
1577
-            $opts['emit_zones'] = false;
1578
-        }
1579
-        if (!isset($opts['load_files_scattered'])) {
1580
-            $opts['load_files_scattered'] = false;
1581
-        }
1582
-
1583
-
1584
-        /////////////////
1585
-        // build request
1586
-        /////////////////
1587
-
1588
-        // v.1.2 req
1589
-        $flags = 1; // remove spaces
1590
-        if ($opts['exact_phrase']) {
1591
-            $flags |= 2;
1592
-        }
1593
-        if ($opts['single_passage']) {
1594
-            $flags |= 4;
1595
-        }
1596
-        if ($opts['use_boundaries']) {
1597
-            $flags |= 8;
1598
-        }
1599
-        if ($opts['weight_order']) {
1600
-            $flags |= 16;
1601
-        }
1602
-        if ($opts['query_mode']) {
1603
-            $flags |= 32;
1604
-        }
1605
-        if ($opts['force_all_words']) {
1606
-            $flags |= 64;
1607
-        }
1608
-        if ($opts['load_files']) {
1609
-            $flags |= 128;
1610
-        }
1611
-        if ($opts['allow_empty']) {
1612
-            $flags |= 256;
1613
-        }
1614
-        if ($opts['emit_zones']) {
1615
-            $flags |= 512;
1616
-        }
1617
-        if ($opts['load_files_scattered']) {
1618
-            $flags |= 1024;
1619
-        }
1620
-        $req = pack('NN', 0, $flags); // mode=0, flags=$flags
1621
-        $req .= pack('N', strlen($index)) . $index; // req index
1622
-        $req .= pack('N', strlen($words)) . $words; // req words
1623
-
1624
-        // options
1625
-        $req .= pack('N', strlen($opts['before_match'])) . $opts['before_match'];
1626
-        $req .= pack('N', strlen($opts['after_match'])) . $opts['after_match'];
1627
-        $req .= pack('N', strlen($opts['chunk_separator'])) . $opts['chunk_separator'];
1628
-        $req .= pack('NN', (int)$opts['limit'], (int)$opts['around']);
1629
-        $req .= pack('NNN', (int)$opts['limit_passages'], (int)$opts['limit_words'], (int)$opts['start_passage_id']); // v.1.2
1630
-        $req .= pack('N', strlen($opts['html_strip_mode'])) . $opts['html_strip_mode'];
1631
-        $req .= pack('N', strlen($opts['passage_boundary'])) . $opts['passage_boundary'];
1632
-
1633
-        // documents
1634
-        $req .= pack('N', count($docs));
1635
-        foreach ($docs as $doc) {
1636
-            assert(is_string($doc));
1637
-            $req .= pack('N', strlen($doc)) . $doc;
1638
-        }
1639
-
1640
-        ////////////////////////////
1641
-        // send query, get response
1642
-        ////////////////////////////
1643
-
1644
-        $len = strlen($req);
1645
-        $req = pack('nnN', SEARCHD_COMMAND_EXCERPT, VER_COMMAND_EXCERPT, $len) . $req; // add header
1646
-        if (!$this->send($fp, $req, $len + 8) || !($response = $this->getResponse($fp, VER_COMMAND_EXCERPT))) {
1647
-            $this->mbPop();
1648
-            return false;
1649
-        }
1650
-
1651
-        //////////////////
1652
-        // parse response
1653
-        //////////////////
1654
-
1655
-        $pos = 0;
1656
-        $res = array();
1657
-        $rlen = strlen($response);
1658
-        $count = count($docs);
1659
-        while ($count--) {
1660
-            list(, $len) = unpack('N*', substr($response, $pos, 4));
1661
-            $pos += 4;
1662
-
1663
-            if ($pos + $len > $rlen) {
1664
-                $this->error = 'incomplete reply';
1665
-                $this->mbPop();
1666
-                return false;
1667
-            }
1668
-            $res[] = $len ? substr($response, $pos, $len) : '';
1669
-            $pos += $len;
1670
-        }
1671
-
1672
-        $this->mbPop();
1673
-        return $res;
1674
-    }
1675
-
1676
-
1677
-    /////////////////////////////////////////////////////////////////////////////
1678
-    // keyword generation
1679
-    /////////////////////////////////////////////////////////////////////////////
1680
-
1681
-    /// connect to searchd server, and generate keyword list for a given query
1682
-    /// returns false on failure,
1683
-    /// an array of words on success
1684
-    public function buildKeywords($query, $index, $hits)
1685
-    {
1686
-        assert(is_string($query));
1687
-        assert(is_string($index));
1688
-        assert(is_bool($hits));
1689
-
1690
-        $this->mbPush();
1691
-
1692
-        if (!($fp = $this->connect())) {
1693
-            $this->mbPop();
1694
-            return false;
1695
-        }
1696
-
1697
-        /////////////////
1698
-        // build request
1699
-        /////////////////
1700
-
1701
-        // v.1.0 req
1702
-        $req  = pack('N', strlen($query)) . $query; // req query
1703
-        $req .= pack('N', strlen($index)) . $index; // req index
1704
-        $req .= pack('N', (int)$hits);
1705
-
1706
-        ////////////////////////////
1707
-        // send query, get response
1708
-        ////////////////////////////
1709
-
1710
-        $len = strlen($req);
1711
-        $req = pack('nnN', SEARCHD_COMMAND_KEYWORDS, VER_COMMAND_KEYWORDS, $len) . $req; // add header
1712
-        if (!$this->send($fp, $req, $len + 8) || !($response = $this->getResponse($fp, VER_COMMAND_KEYWORDS))) {
1713
-            $this->mbPop();
1714
-            return false;
1715
-        }
1716
-
1717
-        //////////////////
1718
-        // parse response
1719
-        //////////////////
1720
-
1721
-        $pos = 0;
1722
-        $res = array();
1723
-        $rlen = strlen($response);
1724
-        list(, $nwords) = unpack('N*', substr($response, $pos, 4));
1725
-        $pos += 4;
1726
-        for ($i = 0; $i < $nwords; $i++) {
1727
-            list(, $len) = unpack('N*', substr($response, $pos, 4));
1728
-            $pos += 4;
1729
-            $tokenized = $len ? substr($response, $pos, $len) : '';
1730
-            $pos += $len;
1731
-
1732
-            list(, $len) = unpack('N*', substr($response, $pos, 4));
1733
-            $pos += 4;
1734
-            $normalized = $len ? substr($response, $pos, $len) : '';
1735
-            $pos += $len;
1736
-
1737
-            $res[] = array(
1738
-                'tokenized' => $tokenized,
1739
-                'normalized' => $normalized
1740
-            );
1741
-
1742
-            if ($hits) {
1743
-                list($ndocs, $nhits) = array_values(unpack('N*N*', substr($response, $pos, 8)));
1744
-                $pos += 8;
1745
-                $res[$i]['docs'] = $ndocs;
1746
-                $res[$i]['hits'] = $nhits;
1747
-            }
1748
-
1749
-            if ($pos > $rlen) {
1750
-                $this->error = 'incomplete reply';
1751
-                $this->mbPop();
1752
-                return false;
1753
-            }
1754
-        }
1755
-
1756
-        $this->mbPop();
1757
-        return $res;
1758
-    }
1759
-
1760
-    public function escapeString($string)
1761
-    {
1762
-        $from = array('\\', '(',')','|','-','!','@','~','"','&', '/', '^', '$', '=', '<');
1763
-        $to   = array('\\\\', '\(','\)','\|','\-','\!','\@','\~','\"', '\&', '\/', '\^', '\$', '\=', '\<');
1764
-
1765
-        return str_replace($from, $to, $string);
1766
-    }
1767
-
1768
-    /////////////////////////////////////////////////////////////////////////////
1769
-    // attribute updates
1770
-    /////////////////////////////////////////////////////////////////////////////
1771
-
1772
-    /// batch update given attributes in given rows in given indexes
1773
-    /// returns amount of updated documents (0 or more) on success, or -1 on failure
1774
-    public function updateAttributes($index, $attrs, $values, $mva = false, $ignorenonexistent = false)
1775
-    {
1776
-        // verify everything
1777
-        assert(is_string($index));
1778
-        assert(is_bool($mva));
1779
-        assert(is_bool($ignorenonexistent));
1780
-
1781
-        assert(is_array($attrs));
1782
-        foreach ($attrs as $attr) {
1783
-            assert(is_string($attr));
1784
-        }
1785
-
1786
-        assert(is_array($values));
1787
-        foreach ($values as $id => $entry) {
1788
-            assert(is_numeric($id));
1789
-            assert(is_array($entry));
1790
-            assert(count($entry) == count($attrs));
1791
-            foreach ($entry as $v) {
1792
-                if ($mva) {
1793
-                    assert(is_array($v));
1794
-                    foreach ($v as $vv) {
1795
-                        assert(is_int($vv));
1796
-                    }
1797
-                } else {
1798
-                    assert(is_int($v));
1799
-                }
1800
-            }
1801
-        }
1802
-
1803
-        // build request
1804
-        $this->mbPush();
1805
-        $req = pack('N', strlen($index)) . $index;
1806
-
1807
-        $req .= pack('N', count($attrs));
1808
-        $req .= pack('N', $ignorenonexistent ? 1 : 0);
1809
-        foreach ($attrs as $attr) {
1810
-            $req .= pack('N', strlen($attr)) . $attr;
1811
-            $req .= pack('N', $mva ? 1 : 0);
1812
-        }
1813
-
1814
-        $req .= pack('N', count($values));
1815
-        foreach ($values as $id => $entry) {
1816
-            $req .= sphPackU64($id);
1817
-            foreach ($entry as $v) {
1818
-                $req .= pack('N', $mva ? count($v) : $v);
1819
-                if ($mva) {
1820
-                    foreach ($v as $vv) {
1821
-                        $req .= pack('N', $vv);
1822
-                    }
1823
-                }
1824
-            }
1825
-        }
1826
-
1827
-        // connect, send query, get response
1828
-        if (!($fp = $this->connect())) {
1829
-            $this->mbPop();
1830
-            return -1;
1831
-        }
1832
-
1833
-        $len = strlen($req);
1834
-        $req = pack('nnN', SEARCHD_COMMAND_UPDATE, VER_COMMAND_UPDATE, $len) . $req; // add header
1835
-        if (!$this->send($fp, $req, $len + 8)) {
1836
-            $this->mbPop();
1837
-            return -1;
1838
-        }
1839
-
1840
-        if (!($response = $this->getResponse($fp, VER_COMMAND_UPDATE))) {
1841
-            $this->mbPop();
1842
-            return -1;
1843
-        }
1844
-
1845
-        // parse response
1846
-        list(, $updated) = unpack('N*', substr($response, 0, 4));
1847
-        $this->mbPop();
1848
-        return $updated;
1849
-    }
1850
-
1851
-    /////////////////////////////////////////////////////////////////////////////
1852
-    // persistent connections
1853
-    /////////////////////////////////////////////////////////////////////////////
1854
-
1855
-    public function open()
1856
-    {
1857
-        if ($this->_socket !== false) {
1858
-            $this->error = 'already connected';
1859
-            return false;
1860
-        }
1861
-        if (!($fp = $this->connect()))
1862
-            return false;
1863
-
1864
-        // command, command version = 0, body length = 4, body = 1
1865
-        $req = pack('nnNN', SEARCHD_COMMAND_PERSIST, 0, 4, 1);
1866
-        if (!$this->send($fp, $req, 12)) {
1867
-            return false;
1868
-        }
1869
-
1870
-        $this->_socket = $fp;
1871
-        return true;
1872
-    }
1873
-
1874
-    public function close()
1875
-    {
1876
-        if ($this->_socket === false) {
1877
-            $this->error = 'not connected';
1878
-            return false;
1879
-        }
1880
-
1881
-        fclose($this->_socket);
1882
-        $this->_socket = false;
1883
-
1884
-        return true;
1885
-    }
1886
-
1887
-    //////////////////////////////////////////////////////////////////////////
1888
-    // status
1889
-    //////////////////////////////////////////////////////////////////////////
1890
-
1891
-    public function status($session = false)
1892
-    {
1893
-        assert(is_bool($session));
1894
-
1895
-        $this->mbPush();
1896
-        if (!($fp = $this->connect())) {
1897
-            $this->mbPop();
1898
-            return false;
1899
-        }
1900
-
1901
-        $req = pack('nnNN', SEARCHD_COMMAND_STATUS, VER_COMMAND_STATUS, 4, $session ? 0 : 1); // len=4, body=1
1902
-        if (!$this->send($fp, $req, 12) || !($response = $this->getResponse($fp, VER_COMMAND_STATUS))) {
1903
-            $this->mbPop();
1904
-            return false;
1905
-        }
1906
-
1907
-        $res = substr($response, 4); // just ignore length, error handling, etc
1908
-        $p = 0;
1909
-        list($rows, $cols) = array_values(unpack('N*N*', substr($response, $p, 8)));
1910
-        $p += 8;
1911
-
1912
-        $res = array();
1913
-        for ($i = 0; $i < $rows; $i++) {
1914
-            for ($j = 0; $j < $cols; $j++) {
1915
-                list(, $len) = unpack('N*', substr($response, $p, 4));
1916
-                $p += 4;
1917
-                $res[$i][] = substr($response, $p, $len);
1918
-                $p += $len;
1919
-            }
1920
-        }
1921
-
1922
-        $this->mbPop();
1923
-        return $res;
1924
-    }
1925
-
1926
-    //////////////////////////////////////////////////////////////////////////
1927
-    // flush
1928
-    //////////////////////////////////////////////////////////////////////////
1929
-
1930
-    public function flushAttributes()
1931
-    {
1932
-        $this->mbPush();
1933
-        if (!($fp = $this->connect())) {
1934
-            $this->mbPop();
1935
-            return -1;
1936
-        }
1937
-
1938
-        $req = pack('nnN', SEARCHD_COMMAND_FLUSHATTRS, VER_COMMAND_FLUSHATTRS, 0); // len=0
1939
-        if (!$this->send($fp, $req, 8) || !($response = $this->getResponse($fp, VER_COMMAND_FLUSHATTRS))) {
1940
-            $this->mbPop();
1941
-            return -1;
1942
-        }
1943
-
1944
-        $tag = -1;
1945
-        if (strlen($response) == 4) {
1946
-            list(, $tag) = unpack('N*', $response);
1947
-        } else {
1948
-            $this->error = 'unexpected response length';
1949
-        }
1950
-
1951
-        $this->mbPop();
1952
-        return $tag;
1953
-    }
417
+	protected $host; ///< searchd host (default is 'localhost')
418
+	protected $port; ///< searchd port (default is 9312)
419
+	protected $offset; ///< how many records to seek from result-set start (default is 0)
420
+	protected $limit; ///< how many records to return from result-set starting at offset (default is 20)
421
+	protected $mode; ///< query matching mode (default is SPH_MATCH_EXTENDED2)
422
+	protected $weights; ///< per-field weights (default is 1 for all fields)
423
+	protected $sort; ///< match sorting mode (default is SPH_SORT_RELEVANCE)
424
+	protected $sortby; ///< attribute to sort by (defualt is '')
425
+	protected $min_id; ///< min ID to match (default is 0, which means no limit)
426
+	protected $max_id; ///< max ID to match (default is 0, which means no limit)
427
+	protected $filters; ///< search filters
428
+	protected $groupby; ///< group-by attribute name
429
+	protected $groupfunc; ///< group-by function (to pre-process group-by attribute value with)
430
+	protected $groupsort; ///< group-by sorting clause (to sort groups in result set with)
431
+	protected $groupdistinct; ///< group-by count-distinct attribute
432
+	protected $maxmatches; ///< max matches to retrieve
433
+	protected $cutoff; ///< cutoff to stop searching at (default is 0)
434
+	protected $retrycount; ///< distributed retries count
435
+	protected $retrydelay; ///< distributed retries delay
436
+	protected $anchor; ///< geographical anchor point
437
+	protected $indexweights; ///< per-index weights
438
+	protected $ranker; ///< ranking mode (default is SPH_RANK_PROXIMITY_BM25)
439
+	protected $rankexpr; ///< ranking mode expression (for SPH_RANK_EXPR)
440
+	protected $maxquerytime; ///< max query time, milliseconds (default is 0, do not limit)
441
+	protected $fieldweights; ///< per-field-name weights
442
+	protected $overrides; ///< per-query attribute values overrides
443
+	protected $select; ///< select-list (attributes or expressions, with optional aliases)
444
+	protected $query_flags; ///< per-query various flags
445
+	protected $predictedtime; ///< per-query max_predicted_time
446
+	protected $outerorderby; ///< outer match sort by
447
+	protected $outeroffset; ///< outer offset
448
+	protected $outerlimit; ///< outer limit
449
+	protected $hasouter;
450
+
451
+	protected $error; ///< last error message
452
+	protected $warning; ///< last warning message
453
+	protected $connerror; ///< connection error vs remote error flag
454
+
455
+	protected $reqs; ///< requests array for multi-query
456
+	protected $mbenc; ///< stored mbstring encoding
457
+	protected $arrayresult; ///< whether $result['matches'] should be a hash or an array
458
+	protected $timeout; ///< connect timeout
459
+
460
+	/////////////////////////////////////////////////////////////////////////////
461
+	// common stuff
462
+	/////////////////////////////////////////////////////////////////////////////
463
+
464
+	/// create a new client object and fill defaults
465
+	public function __construct()
466
+	{
467
+		// per-client-object settings
468
+		$this->host = 'localhost';
469
+		$this->port = 9312;
470
+		$this->_path = false;
471
+		$this->_socket = false;
472
+
473
+		// per-query settings
474
+		$this->offset = 0;
475
+		$this->limit = 20;
476
+		$this->mode = SPH_MATCH_EXTENDED2;
477
+		$this->weights = array();
478
+		$this->sort = SPH_SORT_RELEVANCE;
479
+		$this->sortby = '';
480
+		$this->min_id = 0;
481
+		$this->max_id = 0;
482
+		$this->filters = array();
483
+		$this->groupby = '';
484
+		$this->groupfunc = SPH_GROUPBY_DAY;
485
+		$this->groupsort = '@group desc';
486
+		$this->groupdistinct = '';
487
+		$this->maxmatches = 1000;
488
+		$this->cutoff = 0;
489
+		$this->retrycount = 0;
490
+		$this->retrydelay = 0;
491
+		$this->anchor = array();
492
+		$this->indexweights = array();
493
+		$this->ranker = SPH_RANK_PROXIMITY_BM25;
494
+		$this->rankexpr = '';
495
+		$this->maxquerytime = 0;
496
+		$this->fieldweights = array();
497
+		$this->overrides = array();
498
+		$this->select = '*';
499
+		$this->query_flags = sphSetBit(0, 6, true); // default idf=tfidf_normalized
500
+		$this->predictedtime = 0;
501
+		$this->outerorderby = '';
502
+		$this->outeroffset = 0;
503
+		$this->outerlimit = 0;
504
+		$this->hasouter = false;
505
+
506
+		$this->error = ''; // per-reply fields (for single-query case)
507
+		$this->warning = '';
508
+		$this->connerror = false;
509
+
510
+		$this->reqs = array();// requests storage (for multi-query case)
511
+		$this->mbenc = '';
512
+		$this->arrayresult = false;
513
+		$this->timeout = 0;
514
+	}
515
+
516
+	public function __destruct()
517
+	{
518
+		if ($this->_socket !== false) {
519
+			fclose($this->_socket);
520
+		}
521
+	}
522
+
523
+	/// get last error message (string)
524
+	public function getLastError()
525
+	{
526
+		return $this->error;
527
+	}
528
+
529
+	/// get last warning message (string)
530
+	public function getLastWarning()
531
+	{
532
+		return $this->warning;
533
+	}
534
+
535
+	/// get last error flag (to tell network connection errors from searchd errors or broken responses)
536
+	public function isConnectError()
537
+	{
538
+		return $this->connerror;
539
+	}
540
+
541
+	/// set searchd host name (string) and port (integer)
542
+	public function setServer($host, $port = 0)
543
+	{
544
+		assert(is_string($host));
545
+		if ($host[0] == '/') {
546
+			$this->_path = 'unix://' . $host;
547
+			return;
548
+		}
549
+		if (substr($host, 0, 7) == 'unix://') {
550
+			$this->_path = $host;
551
+			return;
552
+		}
553
+
554
+		$this->host = $host;
555
+		$port = intval($port);
556
+		assert(0 <= $port && $port < 65536);
557
+		$this->port = $port == 0 ? 9312 : $port;
558
+		$this->_path = '';
559
+	}
560
+
561
+	/// set server connection timeout (0 to remove)
562
+	public function setConnectTimeout($timeout)
563
+	{
564
+		assert(is_numeric($timeout));
565
+		$this->timeout = $timeout;
566
+	}
567
+
568
+
569
+	protected function send($handle, $data, $length)
570
+	{
571
+		if (feof($handle) || fwrite($handle, $data, $length) !== $length) {
572
+			$this->error = 'connection unexpectedly closed (timed out?)';
573
+			$this->connerror = true;
574
+			return false;
575
+		}
576
+		return true;
577
+	}
578
+
579
+	/////////////////////////////////////////////////////////////////////////////
580
+
581
+	/// enter mbstring workaround mode
582
+	protected function mbPush()
583
+	{
584
+		$this->mbenc = '';
585
+		if (ini_get('mbstring.func_overload') & 2) {
586
+			$this->mbenc = mb_internal_encoding();
587
+			mb_internal_encoding('latin1');
588
+		}
589
+	}
590
+
591
+	/// leave mbstring workaround mode
592
+	protected function mbPop()
593
+	{
594
+		if ($this->mbenc) {
595
+			mb_internal_encoding($this->mbenc);
596
+		}
597
+	}
598
+
599
+	/// connect to searchd server
600
+	protected function connect()
601
+	{
602
+		if ($this->_socket !== false) {
603
+			// we are in persistent connection mode, so we have a socket
604
+			// however, need to check whether it's still alive
605
+			if (!@feof($this->_socket)) {
606
+				return $this->_socket;
607
+			}
608
+
609
+			// force reopen
610
+			$this->_socket = false;
611
+		}
612
+
613
+		$errno = 0;
614
+		$errstr = '';
615
+		$this->connerror = false;
616
+
617
+		if ($this->_path) {
618
+			$host = $this->_path;
619
+			$port = 0;
620
+		} else {
621
+			$host = $this->host;
622
+			$port = $this->port;
623
+		}
624
+
625
+		if ($this->timeout <= 0) {
626
+			$fp = @fsockopen($host, $port, $errno, $errstr);
627
+		} else {
628
+			$fp = @fsockopen($host, $port, $errno, $errstr, $this->timeout);
629
+		}
630
+
631
+		if (!$fp) {
632
+			if ($this->_path) {
633
+				$location = $this->_path;
634
+			} else {
635
+				$location = "{$this->host}:{$this->port}";
636
+			}
637
+
638
+			$errstr = trim($errstr);
639
+			$this->error = "connection to $location failed (errno=$errno, msg=$errstr)";
640
+			$this->connerror = true;
641
+			return false;
642
+		}
643
+
644
+		// send my version
645
+		// this is a subtle part. we must do it before (!) reading back from searchd.
646
+		// because otherwise under some conditions (reported on FreeBSD for instance)
647
+		// TCP stack could throttle write-write-read pattern because of Nagle.
648
+		if (!$this->send($fp, pack('N', 1), 4)) {
649
+			fclose($fp);
650
+			$this->error = 'failed to send client protocol version';
651
+			return false;
652
+		}
653
+
654
+		// check version
655
+		list(, $v) = unpack('N*', fread($fp, 4));
656
+		$v = (int)$v;
657
+		if ($v < 1) {
658
+			fclose($fp);
659
+			$this->error = "expected searchd protocol version 1+, got version '$v'";
660
+			return false;
661
+		}
662
+
663
+		return $fp;
664
+	}
665
+
666
+	/// get and check response packet from searchd server
667
+	protected function getResponse($fp, $client_ver)
668
+	{
669
+		$response = '';
670
+		$len = 0;
671
+
672
+		$header = fread($fp, 8);
673
+		if (strlen($header) == 8) {
674
+			list($status, $ver, $len) = array_values(unpack('n2a/Nb', $header));
675
+			$left = $len;
676
+			while ($left > 0 && !feof($fp)) {
677
+				$chunk = fread($fp, min(8192, $left));
678
+				if ($chunk) {
679
+					$response .= $chunk;
680
+					$left -= strlen($chunk);
681
+				}
682
+			}
683
+		}
684
+		if ($this->_socket === false) {
685
+			fclose($fp);
686
+		}
687
+
688
+		// check response
689
+		$read = strlen($response);
690
+		if (!$response || $read != $len) {
691
+			$this->error = $len
692
+				? "failed to read searchd response (status=$status, ver=$ver, len=$len, read=$read)"
693
+				: 'received zero-sized searchd response';
694
+			return false;
695
+		}
696
+
697
+		// check status
698
+		if ($status == SEARCHD_WARNING) {
699
+			list(, $wlen) = unpack('N*', substr($response, 0, 4));
700
+			$this->warning = substr($response, 4, $wlen);
701
+			return substr($response, 4 + $wlen);
702
+		}
703
+		if ($status == SEARCHD_ERROR) {
704
+			$this->error = 'searchd error: ' . substr($response, 4);
705
+			return false;
706
+		}
707
+		if ($status == SEARCHD_RETRY) {
708
+			$this->error = 'temporary searchd error: ' . substr($response, 4);
709
+			return false;
710
+		}
711
+		if ($status != SEARCHD_OK) {
712
+			$this->error = "unknown status code '$status'";
713
+			return false;
714
+		}
715
+
716
+		// check version
717
+		if ($ver < $client_ver) {
718
+			$this->warning = sprintf(
719
+				'searchd command v.%d.%d older than client\'s v.%d.%d, some options might not work',
720
+				$ver >> 8,
721
+				$ver & 0xff,
722
+				$client_ver >> 8,
723
+				$client_ver & 0xff
724
+			);
725
+		}
726
+
727
+		return $response;
728
+	}
729
+
730
+	/////////////////////////////////////////////////////////////////////////////
731
+	// searching
732
+	/////////////////////////////////////////////////////////////////////////////
733
+
734
+	/// set offset and count into result set,
735
+	/// and optionally set max-matches and cutoff limits
736
+	public function setLimits($offset, $limit, $max = 0, $cutoff = 0)
737
+	{
738
+		assert(is_int($offset));
739
+		assert(is_int($limit));
740
+		assert($offset >= 0);
741
+		assert($limit > 0);
742
+		assert($max >= 0);
743
+		$this->offset = $offset;
744
+		$this->limit = $limit;
745
+		if ($max > 0) {
746
+			$this->maxmatches = $max;
747
+		}
748
+		if ($cutoff > 0) {
749
+			$this->cutoff = $cutoff;
750
+		}
751
+	}
752
+
753
+	/// set maximum query time, in milliseconds, per-index
754
+	/// integer, 0 means 'do not limit'
755
+	public function setMaxQueryTime($max)
756
+	{
757
+		assert(is_int($max));
758
+		assert($max >= 0);
759
+		$this->maxquerytime = $max;
760
+	}
761
+
762
+	/// set matching mode
763
+	public function setMatchMode($mode)
764
+	{
765
+		trigger_error(
766
+			'DEPRECATED: Do not call this method or, even better, use SphinxQL instead of an API',
767
+			E_USER_DEPRECATED
768
+		);
769
+		assert(
770
+			$mode == SPH_MATCH_ALL ||
771
+			$mode == SPH_MATCH_ANY ||
772
+			$mode == SPH_MATCH_PHRASE ||
773
+			$mode == SPH_MATCH_BOOLEAN ||
774
+			$mode == SPH_MATCH_EXTENDED ||
775
+			$mode == SPH_MATCH_FULLSCAN ||
776
+			$mode == SPH_MATCH_EXTENDED2
777
+		);
778
+		$this->mode = $mode;
779
+	}
780
+
781
+	/// set ranking mode
782
+	public function setRankingMode($ranker, $rankexpr='')
783
+	{
784
+		assert($ranker === 0 || $ranker >= 1 && $ranker < SPH_RANK_TOTAL);
785
+		assert(is_string($rankexpr));
786
+		$this->ranker = $ranker;
787
+		$this->rankexpr = $rankexpr;
788
+	}
789
+
790
+	/// set matches sorting mode
791
+	public function setSortMode($mode, $sortby = '')
792
+	{
793
+		assert (
794
+			$mode == SPH_SORT_RELEVANCE ||
795
+			$mode == SPH_SORT_ATTR_DESC ||
796
+			$mode == SPH_SORT_ATTR_ASC ||
797
+			$mode == SPH_SORT_TIME_SEGMENTS ||
798
+			$mode == SPH_SORT_EXTENDED ||
799
+			$mode == SPH_SORT_EXPR
800
+		);
801
+		assert(is_string($sortby));
802
+		assert($mode == SPH_SORT_RELEVANCE || strlen($sortby) > 0);
803
+
804
+		$this->sort = $mode;
805
+		$this->sortby = $sortby;
806
+	}
807
+
808
+	/**
809
+	 * Bind per-field weights by order
810
+	 *
811
+	 * @deprecated use setFieldWeights() instead
812
+	 */
813
+	public function setWeights()
814
+	{
815
+		throw new \RuntimeException('This method is now deprecated; please use setFieldWeights instead');
816
+	}
817
+
818
+	/// bind per-field weights by name
819
+	public function setFieldWeights($weights)
820
+	{
821
+		assert(is_array($weights));
822
+		foreach ($weights as $name => $weight) {
823
+			assert(is_string($name));
824
+			assert(is_int($weight));
825
+		}
826
+		$this->fieldweights = $weights;
827
+	}
828
+
829
+	/// bind per-index weights by name
830
+	public function setIndexWeights($weights)
831
+	{
832
+		assert(is_array($weights));
833
+		foreach ($weights as $index => $weight) {
834
+			assert(is_string($index));
835
+			assert(is_int($weight));
836
+		}
837
+		$this->indexweights = $weights;
838
+	}
839
+
840
+	/// set IDs range to match
841
+	/// only match records if document ID is beetwen $min and $max (inclusive)
842
+	public function setIDRange($min, $max)
843
+	{
844
+		assert(is_numeric($min));
845
+		assert(is_numeric($max));
846
+		assert($min <= $max);
847
+		$this->min_id = $min;
848
+		$this->max_id = $max;
849
+	}
850
+
851
+	/// set values set filter
852
+	/// only match records where $attribute value is in given set
853
+	public function setFilter($attribute, $values, $exclude = false)
854
+	{
855
+		assert(is_string($attribute));
856
+		assert(is_array($values));
857
+		assert(count($values));
858
+
859
+		if (is_array($values) && count($values)) {
860
+			foreach ($values as $value) {
861
+				assert(is_numeric($value));
862
+			}
863
+
864
+			$this->filters[] = array(
865
+				'type' => SPH_FILTER_VALUES,
866
+				'attr' => $attribute,
867
+				'exclude' => $exclude,
868
+				'values' => $values
869
+			);
870
+		}
871
+	}
872
+
873
+	/// set string filter
874
+	/// only match records where $attribute value is equal
875
+	public function setFilterString($attribute, $value, $exclude = false)
876
+	{
877
+		assert(is_string($attribute));
878
+		assert(is_string($value));
879
+		$this->filters[] = array(
880
+			'type' => SPH_FILTER_STRING,
881
+			'attr' => $attribute,
882
+			'exclude' => $exclude,
883
+			'value' => $value
884
+		);
885
+	}    
886
+
887
+	/// set range filter
888
+	/// only match records if $attribute value is beetwen $min and $max (inclusive)
889
+	public function setFilterRange($attribute, $min, $max, $exclude = false)
890
+	{
891
+		assert(is_string($attribute));
892
+		assert(is_numeric($min));
893
+		assert(is_numeric($max));
894
+		assert($min <= $max);
895
+
896
+		$this->filters[] = array(
897
+			'type' => SPH_FILTER_RANGE,
898
+			'attr' => $attribute,
899
+			'exclude' => $exclude,
900
+			'min' => $min,
901
+			'max' => $max
902
+		);
903
+	}
904
+
905
+	/// set float range filter
906
+	/// only match records if $attribute value is beetwen $min and $max (inclusive)
907
+	public function setFilterFloatRange($attribute, $min, $max, $exclude = false)
908
+	{
909
+		assert(is_string($attribute));
910
+		assert(is_float($min));
911
+		assert(is_float($max));
912
+		assert($min <= $max);
913
+
914
+		$this->filters[] = array(
915
+			'type' => SPH_FILTER_FLOATRANGE,
916
+			'attr' => $attribute,
917
+			'exclude' => $exclude,
918
+			'min' => $min,
919
+			'max' => $max
920
+		);
921
+	}
922
+
923
+	/// setup anchor point for geosphere distance calculations
924
+	/// required to use @geodist in filters and sorting
925
+	/// latitude and longitude must be in radians
926
+	public function setGeoAnchor($attrlat, $attrlong, $lat, $long)
927
+	{
928
+		assert(is_string($attrlat));
929
+		assert(is_string($attrlong));
930
+		assert(is_float($lat));
931
+		assert(is_float($long));
932
+
933
+		$this->anchor = array(
934
+			'attrlat' => $attrlat,
935
+			'attrlong' => $attrlong,
936
+			'lat' => $lat,
937
+			'long' => $long
938
+		);
939
+	}
940
+
941
+	/// set grouping attribute and function
942
+	public function setGroupBy($attribute, $func, $groupsort = '@group desc')
943
+	{
944
+		assert(is_string($attribute));
945
+		assert(is_string($groupsort));
946
+		assert(
947
+			$func == SPH_GROUPBY_DAY ||
948
+			$func == SPH_GROUPBY_WEEK ||
949
+			$func == SPH_GROUPBY_MONTH ||
950
+			$func == SPH_GROUPBY_YEAR ||
951
+			$func == SPH_GROUPBY_ATTR ||
952
+			$func == SPH_GROUPBY_ATTRPAIR
953
+		);
954
+
955
+		$this->groupby = $attribute;
956
+		$this->groupfunc = $func;
957
+		$this->groupsort = $groupsort;
958
+	}
959
+
960
+	/// set count-distinct attribute for group-by queries
961
+	public function setGroupDistinct($attribute)
962
+	{
963
+		assert(is_string($attribute));
964
+		$this->groupdistinct = $attribute;
965
+	}
966
+
967
+	/// set distributed retries count and delay
968
+	public function setRetries($count, $delay = 0)
969
+	{
970
+		assert(is_int($count) && $count >= 0);
971
+		assert(is_int($delay) && $delay >= 0);
972
+		$this->retrycount = $count;
973
+		$this->retrydelay = $delay;
974
+	}
975
+
976
+	/// set result set format (hash or array; hash by default)
977
+	/// PHP specific; needed for group-by-MVA result sets that may contain duplicate IDs
978
+	public function setArrayResult($arrayresult)
979
+	{
980
+		assert(is_bool($arrayresult));
981
+		$this->arrayresult = $arrayresult;
982
+	}
983
+
984
+	/// set attribute values override
985
+	/// there can be only one override per attribute
986
+	/// $values must be a hash that maps document IDs to attribute values
987
+	public function setOverride($attrname, $attrtype, $values)
988
+	{
989
+		trigger_error(
990
+			'DEPRECATED: Do not call this method. Use SphinxQL REMAP() function instead.',
991
+			E_USER_DEPRECATED
992
+		);
993
+		assert(is_string($attrname));
994
+		assert(in_array($attrtype, array(
995
+			SPH_ATTR_INTEGER,
996
+			SPH_ATTR_TIMESTAMP,
997
+			SPH_ATTR_BOOL,
998
+			SPH_ATTR_FLOAT,
999
+			SPH_ATTR_BIGINT
1000
+		)));
1001
+		assert(is_array($values));
1002
+
1003
+		$this->overrides[$attrname] = array(
1004
+			'attr' => $attrname,
1005
+			'type' => $attrtype,
1006
+			'values' => $values
1007
+		);
1008
+	}
1009
+
1010
+	/// set select-list (attributes or expressions), SQL-like syntax
1011
+	public function setSelect($select)
1012
+	{
1013
+		assert(is_string($select));
1014
+		$this->select = $select;
1015
+	}
1016
+
1017
+	public function setQueryFlag($flag_name, $flag_value)
1018
+	{
1019
+		$known_names = array(
1020
+			'reverse_scan',
1021
+			'sort_method',
1022
+			'max_predicted_time',
1023
+			'boolean_simplify',
1024
+			'idf',
1025
+			'global_idf',
1026
+			'low_priority'
1027
+		);
1028
+		$flags = array (
1029
+			'reverse_scan' => array(0, 1),
1030
+			'sort_method' => array('pq', 'kbuffer'),
1031
+			'max_predicted_time' => array(0),
1032
+			'boolean_simplify' => array(true, false),
1033
+			'idf' => array ('normalized', 'plain', 'tfidf_normalized', 'tfidf_unnormalized'),
1034
+			'global_idf' => array(true, false),
1035
+			'low_priority' => array(true, false)
1036
+		);
1037
+
1038
+		assert(isset($flag_name, $known_names));
1039
+		assert(
1040
+			in_array($flag_value, $flags[$flag_name], true) ||
1041
+			($flag_name == 'max_predicted_time' && is_int($flag_value) && $flag_value >= 0)
1042
+		);
1043
+
1044
+		if ($flag_name == 'reverse_scan') {
1045
+			$this->query_flags = sphSetBit($this->query_flags, 0, $flag_value == 1);
1046
+		}
1047
+		if ($flag_name == 'sort_method') {
1048
+			$this->query_flags = sphSetBit($this->query_flags, 1, $flag_value == 'kbuffer');
1049
+		}
1050
+		if ($flag_name == 'max_predicted_time') {
1051
+			$this->query_flags = sphSetBit($this->query_flags, 2, $flag_value > 0);
1052
+			$this->predictedtime = (int)$flag_value;
1053
+		}
1054
+		if ($flag_name == 'boolean_simplify') {
1055
+			$this->query_flags = sphSetBit($this->query_flags, 3, $flag_value);
1056
+		}
1057
+		if ($flag_name == 'idf' && ($flag_value == 'normalized' || $flag_value == 'plain')) {
1058
+			$this->query_flags = sphSetBit($this->query_flags, 4, $flag_value == 'plain');
1059
+		}
1060
+		if ($flag_name == 'global_idf') {
1061
+			$this->query_flags = sphSetBit($this->query_flags, 5, $flag_value);
1062
+		}
1063
+		if ($flag_name == 'idf' && ($flag_value == 'tfidf_normalized' || $flag_value == 'tfidf_unnormalized')) {
1064
+			$this->query_flags = sphSetBit($this->query_flags, 6, $flag_value == 'tfidf_normalized');
1065
+		}
1066
+		if ($flag_name == 'low_priority') {
1067
+			$this->query_flags = sphSetBit($this->query_flags, 8, $flag_value);
1068
+		}
1069
+	}
1070
+
1071
+	/// set outer order by parameters
1072
+	public function setOuterSelect($orderby, $offset, $limit)
1073
+	{
1074
+		assert(is_string($orderby));
1075
+		assert(is_int($offset));
1076
+		assert(is_int($limit));
1077
+		assert($offset >= 0);
1078
+		assert($limit > 0);
1079
+
1080
+		$this->outerorderby = $orderby;
1081
+		$this->outeroffset = $offset;
1082
+		$this->outerlimit = $limit;
1083
+		$this->hasouter = true;
1084
+	}
1085
+
1086
+
1087
+	//////////////////////////////////////////////////////////////////////////////
1088
+
1089
+	/// clear all filters (for multi-queries)
1090
+	public function resetFilters()
1091
+	{
1092
+		$this->filters = array();
1093
+		$this->anchor = array();
1094
+	}
1095
+
1096
+	/// clear groupby settings (for multi-queries)
1097
+	public function resetGroupBy()
1098
+	{
1099
+		$this->groupby = '';
1100
+		$this->groupfunc = SPH_GROUPBY_DAY;
1101
+		$this->groupsort = '@group desc';
1102
+		$this->groupdistinct = '';
1103
+	}
1104
+
1105
+	/// clear all attribute value overrides (for multi-queries)
1106
+	public function resetOverrides()
1107
+	{
1108
+		$this->overrides = array();
1109
+	}
1110
+
1111
+	public function resetQueryFlag()
1112
+	{
1113
+		$this->query_flags = sphSetBit(0, 6, true); // default idf=tfidf_normalized
1114
+		$this->predictedtime = 0;
1115
+	}
1116
+
1117
+	public function resetOuterSelect()
1118
+	{
1119
+		$this->outerorderby = '';
1120
+		$this->outeroffset = 0;
1121
+		$this->outerlimit = 0;
1122
+		$this->hasouter = false;
1123
+	}
1124
+
1125
+	//////////////////////////////////////////////////////////////////////////////
1126
+
1127
+	/// connect to searchd server, run given search query through given indexes,
1128
+	/// and return the search results
1129
+	public function query($query, $index = '*', $comment = '')
1130
+	{
1131
+		assert(empty($this->reqs));
1132
+
1133
+		$this->addQuery($query, $index, $comment);
1134
+		$results = $this->runQueries();
1135
+		$this->reqs = array(); // just in case it failed too early
1136
+
1137
+		if (!is_array($results)) {
1138
+			return false; // probably network error; error message should be already filled
1139
+		}
1140
+
1141
+		$this->error = $results[0]['error'];
1142
+		$this->warning = $results[0]['warning'];
1143
+		if ($results[0]['status'] == SEARCHD_ERROR) {
1144
+			return false;
1145
+		} else {
1146
+			return $results[0];
1147
+		}
1148
+	}
1149
+
1150
+	/// helper to pack floats in network byte order
1151
+	protected function packFloat($f)
1152
+	{
1153
+		$t1 = pack('f', $f); // machine order
1154
+		list(, $t2) = unpack('L*', $t1); // int in machine order
1155
+		return pack('N', $t2);
1156
+	}
1157
+
1158
+	/// add query to multi-query batch
1159
+	/// returns index into results array from RunQueries() call
1160
+	public function addQuery($query, $index = '*', $comment = '')
1161
+	{
1162
+		// mbstring workaround
1163
+		$this->mbPush();
1164
+
1165
+		// build request
1166
+		$req = pack('NNNNN', $this->query_flags, $this->offset, $this->limit, $this->mode, $this->ranker);
1167
+		if ($this->ranker == SPH_RANK_EXPR) {
1168
+			$req .= pack('N', strlen($this->rankexpr)) . $this->rankexpr;
1169
+		}
1170
+		$req .= pack('N', $this->sort); // (deprecated) sort mode
1171
+		$req .= pack('N', strlen($this->sortby)) . $this->sortby;
1172
+		$req .= pack('N', strlen($query)) . $query; // query itself
1173
+		$req .= pack('N', count($this->weights)); // weights
1174
+		foreach ($this->weights as $weight) {
1175
+			$req .= pack('N', (int)$weight);
1176
+		}
1177
+		$req .= pack('N', strlen($index)) . $index; // indexes
1178
+		$req .= pack('N', 1); // id64 range marker
1179
+		$req .= sphPackU64($this->min_id) . sphPackU64($this->max_id); // id64 range
1180
+
1181
+		// filters
1182
+		$req .= pack('N', count($this->filters));
1183
+		foreach ($this->filters as $filter) {
1184
+			$req .= pack('N', strlen($filter['attr'])) . $filter['attr'];
1185
+			$req .= pack('N', $filter['type']);
1186
+			switch ($filter['type']) {
1187
+				case SPH_FILTER_VALUES:
1188
+					$req .= pack('N', count($filter['values']));
1189
+					foreach ($filter['values'] as $value) {
1190
+						$req .= sphPackI64($value);
1191
+					}
1192
+					break;
1193
+				case SPH_FILTER_RANGE:
1194
+					$req .= sphPackI64($filter['min']) . sphPackI64($filter['max']);
1195
+					break;
1196
+				case SPH_FILTER_FLOATRANGE:
1197
+					$req .= $this->packFloat($filter['min']) . $this->packFloat($filter['max']);
1198
+					break;
1199
+				case SPH_FILTER_STRING:
1200
+					$req .= pack('N', strlen($filter['value'])) . $filter['value'];
1201
+					break;
1202
+				default:
1203
+					assert(0 && 'internal error: unhandled filter type');
1204
+			}
1205
+			$req .= pack('N', $filter['exclude']);
1206
+		}
1207
+
1208
+		// group-by clause, max-matches count, group-sort clause, cutoff count
1209
+		$req .= pack('NN', $this->groupfunc, strlen($this->groupby)) . $this->groupby;
1210
+		$req .= pack('N', $this->maxmatches);
1211
+		$req .= pack('N', strlen($this->groupsort)) . $this->groupsort;
1212
+		$req .= pack('NNN', $this->cutoff, $this->retrycount, $this->retrydelay);
1213
+		$req .= pack('N', strlen($this->groupdistinct)) . $this->groupdistinct;
1214
+
1215
+		// anchor point
1216
+		if (empty($this->anchor)) {
1217
+			$req .= pack('N', 0);
1218
+		} else {
1219
+			$a =& $this->anchor;
1220
+			$req .= pack('N', 1);
1221
+			$req .= pack('N', strlen($a['attrlat'])) . $a['attrlat'];
1222
+			$req .= pack('N', strlen($a['attrlong'])) . $a['attrlong'];
1223
+			$req .= $this->packFloat($a['lat']) . $this->packFloat($a['long']);
1224
+		}
1225
+
1226
+		// per-index weights
1227
+		$req .= pack('N', count($this->indexweights));
1228
+		foreach ($this->indexweights as $idx => $weight) {
1229
+			$req .= pack('N', strlen($idx)) . $idx . pack('N', $weight);
1230
+		}
1231
+
1232
+		// max query time
1233
+		$req .= pack('N', $this->maxquerytime);
1234
+
1235
+		// per-field weights
1236
+		$req .= pack('N', count($this->fieldweights));
1237
+		foreach ($this->fieldweights as $field => $weight) {
1238
+			$req .= pack('N', strlen($field)) . $field . pack('N', $weight);
1239
+		}
1240
+
1241
+		// comment
1242
+		$req .= pack('N', strlen($comment)) . $comment;
1243
+
1244
+		// attribute overrides
1245
+		$req .= pack('N', count($this->overrides));
1246
+		foreach ($this->overrides as $key => $entry) {
1247
+			$req .= pack('N', strlen($entry['attr'])) . $entry['attr'];
1248
+			$req .= pack('NN', $entry['type'], count($entry['values']));
1249
+			foreach ($entry['values'] as $id => $val) {
1250
+				assert(is_numeric($id));
1251
+				assert(is_numeric($val));
1252
+
1253
+				$req .= sphPackU64($id);
1254
+				switch ($entry['type']) {
1255
+					case SPH_ATTR_FLOAT:
1256
+						$req .= $this->packFloat($val);
1257
+						break;
1258
+					case SPH_ATTR_BIGINT:
1259
+						$req .= sphPackI64($val);
1260
+						break;
1261
+					default:
1262
+						$req .= pack('N', $val);
1263
+						break;
1264
+				}
1265
+			}
1266
+		}
1267
+
1268
+		// select-list
1269
+		$req .= pack('N', strlen($this->select)) . $this->select;
1270
+
1271
+		// max_predicted_time
1272
+		if ($this->predictedtime > 0) {
1273
+			$req .= pack('N', (int)$this->predictedtime);
1274
+		}
1275
+
1276
+		$req .= pack('N', strlen($this->outerorderby)) . $this->outerorderby;
1277
+		$req .= pack('NN', $this->outeroffset, $this->outerlimit);
1278
+		if ($this->hasouter) {
1279
+			$req .= pack('N', 1);
1280
+		} else {
1281
+			$req .= pack('N', 0);
1282
+		}
1283
+
1284
+		// mbstring workaround
1285
+		$this->mbPop();
1286
+
1287
+		// store request to requests array
1288
+		$this->reqs[] = $req;
1289
+		return count($this->reqs) - 1;
1290
+	}
1291
+
1292
+	/// connect to searchd, run queries batch, and return an array of result sets
1293
+	public function runQueries()
1294
+	{
1295
+		if (empty($this->reqs)) {
1296
+			$this->error = 'no queries defined, issue AddQuery() first';
1297
+			return false;
1298
+		}
1299
+
1300
+		// mbstring workaround
1301
+		$this->mbPush();
1302
+
1303
+		if (!($fp = $this->connect())) {
1304
+			$this->mbPop();
1305
+			return false;
1306
+		}
1307
+
1308
+		// send query, get response
1309
+		$nreqs = count($this->reqs);
1310
+		$req = join('', $this->reqs);
1311
+		$len = 8 + strlen($req);
1312
+		$req = pack('nnNNN', SEARCHD_COMMAND_SEARCH, VER_COMMAND_SEARCH, $len, 0, $nreqs) . $req; // add header
1313
+
1314
+		if (!$this->send($fp, $req, $len + 8) || !($response = $this->getResponse($fp, VER_COMMAND_SEARCH))) {
1315
+			$this->mbPop();
1316
+			return false;
1317
+		}
1318
+
1319
+		// query sent ok; we can reset reqs now
1320
+		$this->reqs = array();
1321
+
1322
+		// parse and return response
1323
+		return $this->parseSearchResponse($response, $nreqs);
1324
+	}
1325
+
1326
+	/// parse and return search query (or queries) response
1327
+	protected function parseSearchResponse($response, $nreqs)
1328
+	{
1329
+		$p = 0; // current position
1330
+		$max = strlen($response); // max position for checks, to protect against broken responses
1331
+
1332
+		$results = array();
1333
+		for ($ires = 0; $ires < $nreqs && $p < $max; $ires++) {
1334
+			$results[] = array();
1335
+			$result =& $results[$ires];
1336
+
1337
+			$result['error'] = '';
1338
+			$result['warning'] = '';
1339
+
1340
+			// extract status
1341
+			list(, $status) = unpack('N*', substr($response, $p, 4));
1342
+			$p += 4;
1343
+			$result['status'] = $status;
1344
+			if ($status != SEARCHD_OK) {
1345
+				list(, $len) = unpack('N*', substr($response, $p, 4));
1346
+				$p += 4;
1347
+				$message = substr($response, $p, $len);
1348
+				$p += $len;
1349
+
1350
+				if ($status == SEARCHD_WARNING) {
1351
+					$result['warning'] = $message;
1352
+				} else {
1353
+					$result['error'] = $message;
1354
+					continue;
1355
+				}
1356
+			}
1357
+
1358
+			// read schema
1359
+			$fields = array();
1360
+			$attrs = array();
1361
+
1362
+			list(, $nfields) = unpack('N*', substr($response, $p, 4));
1363
+			$p += 4;
1364
+			while ($nfields --> 0 && $p < $max) {
1365
+				list(, $len) = unpack('N*', substr($response, $p, 4));
1366
+				$p += 4;
1367
+				$fields[] = substr($response, $p, $len);
1368
+				$p += $len;
1369
+			}
1370
+			$result['fields'] = $fields;
1371
+
1372
+			list(, $nattrs) = unpack('N*', substr($response, $p, 4));
1373
+			$p += 4;
1374
+			while ($nattrs --> 0 && $p < $max) {
1375
+				list(, $len) = unpack('N*', substr($response, $p, 4));
1376
+				$p += 4;
1377
+				$attr = substr($response, $p, $len);
1378
+				$p += $len;
1379
+				list(, $type) = unpack('N*', substr($response, $p, 4));
1380
+				$p += 4;
1381
+				$attrs[$attr] = $type;
1382
+			}
1383
+			$result['attrs'] = $attrs;
1384
+
1385
+			// read match count
1386
+			list(, $count) = unpack('N*', substr($response, $p, 4));
1387
+			$p += 4;
1388
+			list(, $id64) = unpack('N*', substr($response, $p, 4));
1389
+			$p += 4;
1390
+
1391
+			// read matches
1392
+			$idx = -1;
1393
+			while ($count --> 0 && $p < $max) {
1394
+				// index into result array
1395
+				$idx++;
1396
+
1397
+				// parse document id and weight
1398
+				if ($id64) {
1399
+					$doc = sphUnpackU64(substr($response, $p, 8));
1400
+					$p += 8;
1401
+					list(,$weight) = unpack('N*', substr($response, $p, 4));
1402
+					$p += 4;
1403
+				} else {
1404
+					list($doc, $weight) = array_values(unpack('N*N*', substr($response, $p, 8)));
1405
+					$p += 8;
1406
+					$doc = sphFixUint($doc);
1407
+				}
1408
+				$weight = sprintf('%u', $weight);
1409
+
1410
+				// create match entry
1411
+				if ($this->arrayresult) {
1412
+					$result['matches'][$idx] = array('id' => $doc, 'weight' => $weight);
1413
+				} else {
1414
+					$result['matches'][$doc]['weight'] = $weight;
1415
+				}
1416
+
1417
+				// parse and create attributes
1418
+				$attrvals = array();
1419
+				foreach ($attrs as $attr => $type) {
1420
+					// handle 64bit ints
1421
+					if ($type == SPH_ATTR_BIGINT) {
1422
+						$attrvals[$attr] = sphUnpackI64(substr($response, $p, 8));
1423
+						$p += 8;
1424
+						continue;
1425
+					}
1426
+
1427
+					// handle floats
1428
+					if ($type == SPH_ATTR_FLOAT) {
1429
+						list(, $uval) = unpack('N*', substr($response, $p, 4));
1430
+						$p += 4;
1431
+						list(, $fval) = unpack('f*', pack('L', $uval));
1432
+						$attrvals[$attr] = $fval;
1433
+						continue;
1434
+					}
1435
+
1436
+					// handle everything else as unsigned ints
1437
+					list(, $val) = unpack('N*', substr($response, $p, 4));
1438
+					$p += 4;
1439
+					if ($type == SPH_ATTR_MULTI) {
1440
+						$attrvals[$attr] = array();
1441
+						$nvalues = $val;
1442
+						while ($nvalues --> 0 && $p < $max) {
1443
+							list(, $val) = unpack('N*', substr($response, $p, 4));
1444
+							$p += 4;
1445
+							$attrvals[$attr][] = sphFixUint($val);
1446
+						}
1447
+					} elseif ($type == SPH_ATTR_MULTI64) {
1448
+						$attrvals[$attr] = array();
1449
+						$nvalues = $val;
1450
+						while ($nvalues > 0 && $p < $max) {
1451
+							$attrvals[$attr][] = sphUnpackI64(substr($response, $p, 8));
1452
+							$p += 8;
1453
+							$nvalues -= 2;
1454
+						}
1455
+					} elseif ($type == SPH_ATTR_STRING) {
1456
+						$attrvals[$attr] = substr($response, $p, $val);
1457
+						$p += $val;
1458
+					} elseif ($type == SPH_ATTR_FACTORS) {
1459
+						$attrvals[$attr] = substr($response, $p, $val - 4);
1460
+						$p += $val-4;
1461
+					} else {
1462
+						$attrvals[$attr] = sphFixUint($val);
1463
+					}
1464
+				}
1465
+
1466
+				if ($this->arrayresult) {
1467
+					$result['matches'][$idx]['attrs'] = $attrvals;
1468
+				} else {
1469
+					$result['matches'][$doc]['attrs'] = $attrvals;
1470
+				}
1471
+			}
1472
+
1473
+			list($total, $total_found, $msecs, $words) = array_values(unpack('N*N*N*N*', substr($response, $p, 16)));
1474
+			$result['total'] = sprintf('%u', $total);
1475
+			$result['total_found'] = sprintf('%u', $total_found);
1476
+			$result['time'] = sprintf('%.3f', $msecs / 1000);
1477
+			$p += 16;
1478
+
1479
+			while ($words --> 0 && $p < $max) {
1480
+				list(, $len) = unpack('N*', substr($response, $p, 4));
1481
+				$p += 4;
1482
+				$word = substr($response, $p, $len);
1483
+				$p += $len;
1484
+				list($docs, $hits) = array_values(unpack('N*N*', substr($response, $p, 8)));
1485
+				$p += 8;
1486
+				$result['words'][$word] = array (
1487
+					'docs' => sprintf('%u', $docs),
1488
+					'hits' => sprintf('%u', $hits)
1489
+				);
1490
+			}
1491
+		}
1492
+
1493
+		$this->mbPop();
1494
+		return $results;
1495
+	}
1496
+
1497
+	/////////////////////////////////////////////////////////////////////////////
1498
+	// excerpts generation
1499
+	/////////////////////////////////////////////////////////////////////////////
1500
+
1501
+	/// connect to searchd server, and generate exceprts (snippets)
1502
+	/// of given documents for given query. returns false on failure,
1503
+	/// an array of snippets on success
1504
+	public function buildExcerpts($docs, $index, $words, $opts = array())
1505
+	{
1506
+		assert(is_array($docs));
1507
+		assert(is_string($index));
1508
+		assert(is_string($words));
1509
+		assert(is_array($opts));
1510
+
1511
+		$this->mbPush();
1512
+
1513
+		if (!($fp = $this->connect())) {
1514
+			$this->mbPop();
1515
+			return false;
1516
+		}
1517
+
1518
+		/////////////////
1519
+		// fixup options
1520
+		/////////////////
1521
+
1522
+		if (!isset($opts['before_match'])) {
1523
+			$opts['before_match'] = '<b>';
1524
+		}
1525
+		if (!isset($opts['after_match'])) {
1526
+			$opts['after_match'] = '</b>';
1527
+		}
1528
+		if (!isset($opts['chunk_separator'])) {
1529
+			$opts['chunk_separator'] = ' ... ';
1530
+		}
1531
+		if (!isset($opts['limit'])) {
1532
+			$opts['limit'] = 256;
1533
+		}
1534
+		if (!isset($opts['limit_passages'])) {
1535
+			$opts['limit_passages'] = 0;
1536
+		}
1537
+		if (!isset($opts['limit_words'])) {
1538
+			$opts['limit_words'] = 0;
1539
+		}
1540
+		if (!isset($opts['around'])) {
1541
+			$opts['around'] = 5;
1542
+		}
1543
+		if (!isset($opts['exact_phrase'])) {
1544
+			$opts['exact_phrase'] = false;
1545
+		}
1546
+		if (!isset($opts['single_passage'])) {
1547
+			$opts['single_passage'] = false;
1548
+		}
1549
+		if (!isset($opts['use_boundaries'])) {
1550
+			$opts['use_boundaries'] = false;
1551
+		}
1552
+		if (!isset($opts['weight_order'])) {
1553
+			$opts['weight_order'] = false;
1554
+		}
1555
+		if (!isset($opts['query_mode'])) {
1556
+			$opts['query_mode'] = false;
1557
+		}
1558
+		if (!isset($opts['force_all_words'])) {
1559
+			$opts['force_all_words'] = false;
1560
+		}
1561
+		if (!isset($opts['start_passage_id'])) {
1562
+			$opts['start_passage_id'] = 1;
1563
+		}
1564
+		if (!isset($opts['load_files'])) {
1565
+			$opts['load_files'] = false;
1566
+		}
1567
+		if (!isset($opts['html_strip_mode'])) {
1568
+			$opts['html_strip_mode'] = 'index';
1569
+		}
1570
+		if (!isset($opts['allow_empty'])) {
1571
+			$opts['allow_empty'] = false;
1572
+		}
1573
+		if (!isset($opts['passage_boundary'])) {
1574
+			$opts['passage_boundary'] = 'none';
1575
+		}
1576
+		if (!isset($opts['emit_zones'])) {
1577
+			$opts['emit_zones'] = false;
1578
+		}
1579
+		if (!isset($opts['load_files_scattered'])) {
1580
+			$opts['load_files_scattered'] = false;
1581
+		}
1582
+
1583
+
1584
+		/////////////////
1585
+		// build request
1586
+		/////////////////
1587
+
1588
+		// v.1.2 req
1589
+		$flags = 1; // remove spaces
1590
+		if ($opts['exact_phrase']) {
1591
+			$flags |= 2;
1592
+		}
1593
+		if ($opts['single_passage']) {
1594
+			$flags |= 4;
1595
+		}
1596
+		if ($opts['use_boundaries']) {
1597
+			$flags |= 8;
1598
+		}
1599
+		if ($opts['weight_order']) {
1600
+			$flags |= 16;
1601
+		}
1602
+		if ($opts['query_mode']) {
1603
+			$flags |= 32;
1604
+		}
1605
+		if ($opts['force_all_words']) {
1606
+			$flags |= 64;
1607
+		}
1608
+		if ($opts['load_files']) {
1609
+			$flags |= 128;
1610
+		}
1611
+		if ($opts['allow_empty']) {
1612
+			$flags |= 256;
1613
+		}
1614
+		if ($opts['emit_zones']) {
1615
+			$flags |= 512;
1616
+		}
1617
+		if ($opts['load_files_scattered']) {
1618
+			$flags |= 1024;
1619
+		}
1620
+		$req = pack('NN', 0, $flags); // mode=0, flags=$flags
1621
+		$req .= pack('N', strlen($index)) . $index; // req index
1622
+		$req .= pack('N', strlen($words)) . $words; // req words
1623
+
1624
+		// options
1625
+		$req .= pack('N', strlen($opts['before_match'])) . $opts['before_match'];
1626
+		$req .= pack('N', strlen($opts['after_match'])) . $opts['after_match'];
1627
+		$req .= pack('N', strlen($opts['chunk_separator'])) . $opts['chunk_separator'];
1628
+		$req .= pack('NN', (int)$opts['limit'], (int)$opts['around']);
1629
+		$req .= pack('NNN', (int)$opts['limit_passages'], (int)$opts['limit_words'], (int)$opts['start_passage_id']); // v.1.2
1630
+		$req .= pack('N', strlen($opts['html_strip_mode'])) . $opts['html_strip_mode'];
1631
+		$req .= pack('N', strlen($opts['passage_boundary'])) . $opts['passage_boundary'];
1632
+
1633
+		// documents
1634
+		$req .= pack('N', count($docs));
1635
+		foreach ($docs as $doc) {
1636
+			assert(is_string($doc));
1637
+			$req .= pack('N', strlen($doc)) . $doc;
1638
+		}
1639
+
1640
+		////////////////////////////
1641
+		// send query, get response
1642
+		////////////////////////////
1643
+
1644
+		$len = strlen($req);
1645
+		$req = pack('nnN', SEARCHD_COMMAND_EXCERPT, VER_COMMAND_EXCERPT, $len) . $req; // add header
1646
+		if (!$this->send($fp, $req, $len + 8) || !($response = $this->getResponse($fp, VER_COMMAND_EXCERPT))) {
1647
+			$this->mbPop();
1648
+			return false;
1649
+		}
1650
+
1651
+		//////////////////
1652
+		// parse response
1653
+		//////////////////
1654
+
1655
+		$pos = 0;
1656
+		$res = array();
1657
+		$rlen = strlen($response);
1658
+		$count = count($docs);
1659
+		while ($count--) {
1660
+			list(, $len) = unpack('N*', substr($response, $pos, 4));
1661
+			$pos += 4;
1662
+
1663
+			if ($pos + $len > $rlen) {
1664
+				$this->error = 'incomplete reply';
1665
+				$this->mbPop();
1666
+				return false;
1667
+			}
1668
+			$res[] = $len ? substr($response, $pos, $len) : '';
1669
+			$pos += $len;
1670
+		}
1671
+
1672
+		$this->mbPop();
1673
+		return $res;
1674
+	}
1675
+
1676
+
1677
+	/////////////////////////////////////////////////////////////////////////////
1678
+	// keyword generation
1679
+	/////////////////////////////////////////////////////////////////////////////
1680
+
1681
+	/// connect to searchd server, and generate keyword list for a given query
1682
+	/// returns false on failure,
1683
+	/// an array of words on success
1684
+	public function buildKeywords($query, $index, $hits)
1685
+	{
1686
+		assert(is_string($query));
1687
+		assert(is_string($index));
1688
+		assert(is_bool($hits));
1689
+
1690
+		$this->mbPush();
1691
+
1692
+		if (!($fp = $this->connect())) {
1693
+			$this->mbPop();
1694
+			return false;
1695
+		}
1696
+
1697
+		/////////////////
1698
+		// build request
1699
+		/////////////////
1700
+
1701
+		// v.1.0 req
1702
+		$req  = pack('N', strlen($query)) . $query; // req query
1703
+		$req .= pack('N', strlen($index)) . $index; // req index
1704
+		$req .= pack('N', (int)$hits);
1705
+
1706
+		////////////////////////////
1707
+		// send query, get response
1708
+		////////////////////////////
1709
+
1710
+		$len = strlen($req);
1711
+		$req = pack('nnN', SEARCHD_COMMAND_KEYWORDS, VER_COMMAND_KEYWORDS, $len) . $req; // add header
1712
+		if (!$this->send($fp, $req, $len + 8) || !($response = $this->getResponse($fp, VER_COMMAND_KEYWORDS))) {
1713
+			$this->mbPop();
1714
+			return false;
1715
+		}
1716
+
1717
+		//////////////////
1718
+		// parse response
1719
+		//////////////////
1720
+
1721
+		$pos = 0;
1722
+		$res = array();
1723
+		$rlen = strlen($response);
1724
+		list(, $nwords) = unpack('N*', substr($response, $pos, 4));
1725
+		$pos += 4;
1726
+		for ($i = 0; $i < $nwords; $i++) {
1727
+			list(, $len) = unpack('N*', substr($response, $pos, 4));
1728
+			$pos += 4;
1729
+			$tokenized = $len ? substr($response, $pos, $len) : '';
1730
+			$pos += $len;
1731
+
1732
+			list(, $len) = unpack('N*', substr($response, $pos, 4));
1733
+			$pos += 4;
1734
+			$normalized = $len ? substr($response, $pos, $len) : '';
1735
+			$pos += $len;
1736
+
1737
+			$res[] = array(
1738
+				'tokenized' => $tokenized,
1739
+				'normalized' => $normalized
1740
+			);
1741
+
1742
+			if ($hits) {
1743
+				list($ndocs, $nhits) = array_values(unpack('N*N*', substr($response, $pos, 8)));
1744
+				$pos += 8;
1745
+				$res[$i]['docs'] = $ndocs;
1746
+				$res[$i]['hits'] = $nhits;
1747
+			}
1748
+
1749
+			if ($pos > $rlen) {
1750
+				$this->error = 'incomplete reply';
1751
+				$this->mbPop();
1752
+				return false;
1753
+			}
1754
+		}
1755
+
1756
+		$this->mbPop();
1757
+		return $res;
1758
+	}
1759
+
1760
+	public function escapeString($string)
1761
+	{
1762
+		$from = array('\\', '(',')','|','-','!','@','~','"','&', '/', '^', '$', '=', '<');
1763
+		$to   = array('\\\\', '\(','\)','\|','\-','\!','\@','\~','\"', '\&', '\/', '\^', '\$', '\=', '\<');
1764
+
1765
+		return str_replace($from, $to, $string);
1766
+	}
1767
+
1768
+	/////////////////////////////////////////////////////////////////////////////
1769
+	// attribute updates
1770
+	/////////////////////////////////////////////////////////////////////////////
1771
+
1772
+	/// batch update given attributes in given rows in given indexes
1773
+	/// returns amount of updated documents (0 or more) on success, or -1 on failure
1774
+	public function updateAttributes($index, $attrs, $values, $mva = false, $ignorenonexistent = false)
1775
+	{
1776
+		// verify everything
1777
+		assert(is_string($index));
1778
+		assert(is_bool($mva));
1779
+		assert(is_bool($ignorenonexistent));
1780
+
1781
+		assert(is_array($attrs));
1782
+		foreach ($attrs as $attr) {
1783
+			assert(is_string($attr));
1784
+		}
1785
+
1786
+		assert(is_array($values));
1787
+		foreach ($values as $id => $entry) {
1788
+			assert(is_numeric($id));
1789
+			assert(is_array($entry));
1790
+			assert(count($entry) == count($attrs));
1791
+			foreach ($entry as $v) {
1792
+				if ($mva) {
1793
+					assert(is_array($v));
1794
+					foreach ($v as $vv) {
1795
+						assert(is_int($vv));
1796
+					}
1797
+				} else {
1798
+					assert(is_int($v));
1799
+				}
1800
+			}
1801
+		}
1802
+
1803
+		// build request
1804
+		$this->mbPush();
1805
+		$req = pack('N', strlen($index)) . $index;
1806
+
1807
+		$req .= pack('N', count($attrs));
1808
+		$req .= pack('N', $ignorenonexistent ? 1 : 0);
1809
+		foreach ($attrs as $attr) {
1810
+			$req .= pack('N', strlen($attr)) . $attr;
1811
+			$req .= pack('N', $mva ? 1 : 0);
1812
+		}
1813
+
1814
+		$req .= pack('N', count($values));
1815
+		foreach ($values as $id => $entry) {
1816
+			$req .= sphPackU64($id);
1817
+			foreach ($entry as $v) {
1818
+				$req .= pack('N', $mva ? count($v) : $v);
1819
+				if ($mva) {
1820
+					foreach ($v as $vv) {
1821
+						$req .= pack('N', $vv);
1822
+					}
1823
+				}
1824
+			}
1825
+		}
1826
+
1827
+		// connect, send query, get response
1828
+		if (!($fp = $this->connect())) {
1829
+			$this->mbPop();
1830
+			return -1;
1831
+		}
1832
+
1833
+		$len = strlen($req);
1834
+		$req = pack('nnN', SEARCHD_COMMAND_UPDATE, VER_COMMAND_UPDATE, $len) . $req; // add header
1835
+		if (!$this->send($fp, $req, $len + 8)) {
1836
+			$this->mbPop();
1837
+			return -1;
1838
+		}
1839
+
1840
+		if (!($response = $this->getResponse($fp, VER_COMMAND_UPDATE))) {
1841
+			$this->mbPop();
1842
+			return -1;
1843
+		}
1844
+
1845
+		// parse response
1846
+		list(, $updated) = unpack('N*', substr($response, 0, 4));
1847
+		$this->mbPop();
1848
+		return $updated;
1849
+	}
1850
+
1851
+	/////////////////////////////////////////////////////////////////////////////
1852
+	// persistent connections
1853
+	/////////////////////////////////////////////////////////////////////////////
1854
+
1855
+	public function open()
1856
+	{
1857
+		if ($this->_socket !== false) {
1858
+			$this->error = 'already connected';
1859
+			return false;
1860
+		}
1861
+		if (!($fp = $this->connect()))
1862
+			return false;
1863
+
1864
+		// command, command version = 0, body length = 4, body = 1
1865
+		$req = pack('nnNN', SEARCHD_COMMAND_PERSIST, 0, 4, 1);
1866
+		if (!$this->send($fp, $req, 12)) {
1867
+			return false;
1868
+		}
1869
+
1870
+		$this->_socket = $fp;
1871
+		return true;
1872
+	}
1873
+
1874
+	public function close()
1875
+	{
1876
+		if ($this->_socket === false) {
1877
+			$this->error = 'not connected';
1878
+			return false;
1879
+		}
1880
+
1881
+		fclose($this->_socket);
1882
+		$this->_socket = false;
1883
+
1884
+		return true;
1885
+	}
1886
+
1887
+	//////////////////////////////////////////////////////////////////////////
1888
+	// status
1889
+	//////////////////////////////////////////////////////////////////////////
1890
+
1891
+	public function status($session = false)
1892
+	{
1893
+		assert(is_bool($session));
1894
+
1895
+		$this->mbPush();
1896
+		if (!($fp = $this->connect())) {
1897
+			$this->mbPop();
1898
+			return false;
1899
+		}
1900
+
1901
+		$req = pack('nnNN', SEARCHD_COMMAND_STATUS, VER_COMMAND_STATUS, 4, $session ? 0 : 1); // len=4, body=1
1902
+		if (!$this->send($fp, $req, 12) || !($response = $this->getResponse($fp, VER_COMMAND_STATUS))) {
1903
+			$this->mbPop();
1904
+			return false;
1905
+		}
1906
+
1907
+		$res = substr($response, 4); // just ignore length, error handling, etc
1908
+		$p = 0;
1909
+		list($rows, $cols) = array_values(unpack('N*N*', substr($response, $p, 8)));
1910
+		$p += 8;
1911
+
1912
+		$res = array();
1913
+		for ($i = 0; $i < $rows; $i++) {
1914
+			for ($j = 0; $j < $cols; $j++) {
1915
+				list(, $len) = unpack('N*', substr($response, $p, 4));
1916
+				$p += 4;
1917
+				$res[$i][] = substr($response, $p, $len);
1918
+				$p += $len;
1919
+			}
1920
+		}
1921
+
1922
+		$this->mbPop();
1923
+		return $res;
1924
+	}
1925
+
1926
+	//////////////////////////////////////////////////////////////////////////
1927
+	// flush
1928
+	//////////////////////////////////////////////////////////////////////////
1929
+
1930
+	public function flushAttributes()
1931
+	{
1932
+		$this->mbPush();
1933
+		if (!($fp = $this->connect())) {
1934
+			$this->mbPop();
1935
+			return -1;
1936
+		}
1937
+
1938
+		$req = pack('nnN', SEARCHD_COMMAND_FLUSHATTRS, VER_COMMAND_FLUSHATTRS, 0); // len=0
1939
+		if (!$this->send($fp, $req, 8) || !($response = $this->getResponse($fp, VER_COMMAND_FLUSHATTRS))) {
1940
+			$this->mbPop();
1941
+			return -1;
1942
+		}
1943
+
1944
+		$tag = -1;
1945
+		if (strlen($response) == 4) {
1946
+			list(, $tag) = unpack('N*', $response);
1947
+		} else {
1948
+			$this->error = 'unexpected response length';
1949
+		}
1950
+
1951
+		$this->mbPop();
1952
+		return $tag;
1953
+	}
1954 1954
 }
Please login to merge, or discard this patch.
Spacing   +228 added lines, -228 removed lines patch added patch discarded remove patch
@@ -33,82 +33,82 @@  discard block
 block discarded – undo
33 33
 /////////////////////////////////////////////////////////////////////////////
34 34
 
35 35
 /// known searchd commands
36
-define('SEARCHD_COMMAND_SEARCH',     0);
37
-define('SEARCHD_COMMAND_EXCERPT',    1);
38
-define('SEARCHD_COMMAND_UPDATE',     2);
39
-define('SEARCHD_COMMAND_KEYWORDS',   3);
40
-define('SEARCHD_COMMAND_PERSIST',    4);
41
-define('SEARCHD_COMMAND_STATUS',     5);
36
+define('SEARCHD_COMMAND_SEARCH', 0);
37
+define('SEARCHD_COMMAND_EXCERPT', 1);
38
+define('SEARCHD_COMMAND_UPDATE', 2);
39
+define('SEARCHD_COMMAND_KEYWORDS', 3);
40
+define('SEARCHD_COMMAND_PERSIST', 4);
41
+define('SEARCHD_COMMAND_STATUS', 5);
42 42
 define('SEARCHD_COMMAND_FLUSHATTRS', 7);
43 43
 
44 44
 /// current client-side command implementation versions
45
-define('VER_COMMAND_SEARCH',     0x11E);
46
-define('VER_COMMAND_EXCERPT',    0x104);
47
-define('VER_COMMAND_UPDATE',     0x103);
48
-define('VER_COMMAND_KEYWORDS',   0x100);
49
-define('VER_COMMAND_STATUS',     0x101);
50
-define('VER_COMMAND_QUERY',      0x100);
45
+define('VER_COMMAND_SEARCH', 0x11E);
46
+define('VER_COMMAND_EXCERPT', 0x104);
47
+define('VER_COMMAND_UPDATE', 0x103);
48
+define('VER_COMMAND_KEYWORDS', 0x100);
49
+define('VER_COMMAND_STATUS', 0x101);
50
+define('VER_COMMAND_QUERY', 0x100);
51 51
 define('VER_COMMAND_FLUSHATTRS', 0x100);
52 52
 
53 53
 /// known searchd status codes
54
-define('SEARCHD_OK',      0);
55
-define('SEARCHD_ERROR',   1);
56
-define('SEARCHD_RETRY',   2);
54
+define('SEARCHD_OK', 0);
55
+define('SEARCHD_ERROR', 1);
56
+define('SEARCHD_RETRY', 2);
57 57
 define('SEARCHD_WARNING', 3);
58 58
 
59 59
 /// known match modes
60
-define('SPH_MATCH_ALL',       0);
61
-define('SPH_MATCH_ANY',       1);
62
-define('SPH_MATCH_PHRASE',    2);
63
-define('SPH_MATCH_BOOLEAN',   3);
64
-define('SPH_MATCH_EXTENDED',  4);
65
-define('SPH_MATCH_FULLSCAN',  5);
60
+define('SPH_MATCH_ALL', 0);
61
+define('SPH_MATCH_ANY', 1);
62
+define('SPH_MATCH_PHRASE', 2);
63
+define('SPH_MATCH_BOOLEAN', 3);
64
+define('SPH_MATCH_EXTENDED', 4);
65
+define('SPH_MATCH_FULLSCAN', 5);
66 66
 define('SPH_MATCH_EXTENDED2', 6); // extended engine V2 (TEMPORARY, WILL BE REMOVED)
67 67
 
68 68
 /// known ranking modes (ext2 only)
69 69
 define('SPH_RANK_PROXIMITY_BM25', 0); ///< default mode, phrase proximity major factor and BM25 minor one
70
-define('SPH_RANK_BM25',           1); ///< statistical mode, BM25 ranking only (faster but worse quality)
71
-define('SPH_RANK_NONE',           2); ///< no ranking, all matches get a weight of 1
72
-define('SPH_RANK_WORDCOUNT',      3); ///< simple word-count weighting, rank is a weighted sum of per-field keyword occurence counts
73
-define('SPH_RANK_PROXIMITY',      4);
74
-define('SPH_RANK_MATCHANY',       5);
75
-define('SPH_RANK_FIELDMASK',      6);
76
-define('SPH_RANK_SPH04',          7);
77
-define('SPH_RANK_EXPR',           8);
78
-define('SPH_RANK_TOTAL',          9);
70
+define('SPH_RANK_BM25', 1); ///< statistical mode, BM25 ranking only (faster but worse quality)
71
+define('SPH_RANK_NONE', 2); ///< no ranking, all matches get a weight of 1
72
+define('SPH_RANK_WORDCOUNT', 3); ///< simple word-count weighting, rank is a weighted sum of per-field keyword occurence counts
73
+define('SPH_RANK_PROXIMITY', 4);
74
+define('SPH_RANK_MATCHANY', 5);
75
+define('SPH_RANK_FIELDMASK', 6);
76
+define('SPH_RANK_SPH04', 7);
77
+define('SPH_RANK_EXPR', 8);
78
+define('SPH_RANK_TOTAL', 9);
79 79
 
80 80
 /// known sort modes
81
-define('SPH_SORT_RELEVANCE',     0);
82
-define('SPH_SORT_ATTR_DESC',     1);
83
-define('SPH_SORT_ATTR_ASC',      2);
81
+define('SPH_SORT_RELEVANCE', 0);
82
+define('SPH_SORT_ATTR_DESC', 1);
83
+define('SPH_SORT_ATTR_ASC', 2);
84 84
 define('SPH_SORT_TIME_SEGMENTS', 3);
85
-define('SPH_SORT_EXTENDED',      4);
86
-define('SPH_SORT_EXPR',          5);
85
+define('SPH_SORT_EXTENDED', 4);
86
+define('SPH_SORT_EXPR', 5);
87 87
 
88 88
 /// known filter types
89
-define('SPH_FILTER_VALUES',     0);
90
-define('SPH_FILTER_RANGE',      1);
89
+define('SPH_FILTER_VALUES', 0);
90
+define('SPH_FILTER_RANGE', 1);
91 91
 define('SPH_FILTER_FLOATRANGE', 2);
92
-define('SPH_FILTER_STRING',     3);
92
+define('SPH_FILTER_STRING', 3);
93 93
 
94 94
 /// known attribute types
95
-define('SPH_ATTR_INTEGER',   1);
95
+define('SPH_ATTR_INTEGER', 1);
96 96
 define('SPH_ATTR_TIMESTAMP', 2);
97
-define('SPH_ATTR_ORDINAL',   3);
98
-define('SPH_ATTR_BOOL',      4);
99
-define('SPH_ATTR_FLOAT',     5);
100
-define('SPH_ATTR_BIGINT',    6);
101
-define('SPH_ATTR_STRING',    7);
102
-define('SPH_ATTR_FACTORS',   1001);
103
-define('SPH_ATTR_MULTI',     0x40000001);
104
-define('SPH_ATTR_MULTI64',   0x40000002);
97
+define('SPH_ATTR_ORDINAL', 3);
98
+define('SPH_ATTR_BOOL', 4);
99
+define('SPH_ATTR_FLOAT', 5);
100
+define('SPH_ATTR_BIGINT', 6);
101
+define('SPH_ATTR_STRING', 7);
102
+define('SPH_ATTR_FACTORS', 1001);
103
+define('SPH_ATTR_MULTI', 0x40000001);
104
+define('SPH_ATTR_MULTI64', 0x40000002);
105 105
 
106 106
 /// known grouping functions
107
-define('SPH_GROUPBY_DAY',      0);
108
-define('SPH_GROUPBY_WEEK',     1);
109
-define('SPH_GROUPBY_MONTH',    2);
110
-define('SPH_GROUPBY_YEAR',     3);
111
-define('SPH_GROUPBY_ATTR',     4);
107
+define('SPH_GROUPBY_DAY', 0);
108
+define('SPH_GROUPBY_WEEK', 1);
109
+define('SPH_GROUPBY_MONTH', 2);
110
+define('SPH_GROUPBY_YEAR', 3);
111
+define('SPH_GROUPBY_ATTR', 4);
112 112
 define('SPH_GROUPBY_ATTRPAIR', 5);
113 113
 
114 114
 // important properties of PHP's integers:
@@ -143,19 +143,19 @@  discard block
 block discarded – undo
143 143
     assert(is_numeric($v));
144 144
 
145 145
     // x64
146
-    if (PHP_INT_SIZE >= 8) {
146
+    if (PHP_INT_SIZE>=8) {
147 147
         $v = (int)$v;
148 148
         return pack('NN', $v >> 32, $v & 0xFFFFFFFF);
149 149
     }
150 150
 
151 151
     // x32, int
152 152
     if (is_int($v)) {
153
-        return pack('NN', $v < 0 ? -1 : 0, $v);
153
+        return pack('NN', $v<0 ? -1 : 0, $v);
154 154
     }
155 155
 
156 156
     // x32, bcmath
157 157
     if (function_exists('bcmul')) {
158
-        if (bccomp($v, 0) == -1) {
158
+        if (bccomp($v, 0)==-1) {
159 159
             $v = bcadd('18446744073709551616', $v);
160 160
         }
161 161
         $h = bcdiv($v, '4294967296', 0);
@@ -173,8 +173,8 @@  discard block
 block discarded – undo
173 173
     $l = $m - ($q * 4294967296.0);
174 174
     $h = $hi * 2328.0 + $q; // (10 ^ 13) / (1 << 32) = 2328
175 175
 
176
-    if ($v < 0) {
177
-        if ($l == 0) {
176
+    if ($v<0) {
177
+        if ($l==0) {
178 178
             $h = 4294967296.0 - $h;
179 179
         } else {
180 180
             $h = 4294967295.0 - $h;
@@ -190,8 +190,8 @@  discard block
 block discarded – undo
190 190
     assert(is_numeric($v));
191 191
 
192 192
     // x64
193
-    if (PHP_INT_SIZE >= 8) {
194
-        assert($v >= 0);
193
+    if (PHP_INT_SIZE>=8) {
194
+        assert($v>=0);
195 195
 
196 196
         // x64, int
197 197
         if (is_int($v)) {
@@ -247,16 +247,16 @@  discard block
 block discarded – undo
247 247
 {
248 248
     list($hi, $lo) = array_values(unpack('N*N*', $v));
249 249
 
250
-    if (PHP_INT_SIZE >= 8) {
251
-        if ($hi < 0) { // because php 5.2.2 to 5.2.5 is totally fucked up again
250
+    if (PHP_INT_SIZE>=8) {
251
+        if ($hi<0) { // because php 5.2.2 to 5.2.5 is totally fucked up again
252 252
             $hi += 1 << 32;
253 253
         }
254
-        if ($lo < 0) {
254
+        if ($lo<0) {
255 255
             $lo += 1 << 32;
256 256
         }
257 257
 
258 258
         // x64, int
259
-        if ($hi <= 2147483647) {
259
+        if ($hi<=2147483647) {
260 260
             return ($hi << 32) + $lo;
261 261
         }
262 262
 
@@ -269,20 +269,20 @@  discard block
 block discarded – undo
269 269
         $C = 100000;
270 270
         $h = ((int)($hi / $C) << 32) + (int)($lo / $C);
271 271
         $l = (($hi % $C) << 32) + ($lo % $C);
272
-        if ($l > $C) {
272
+        if ($l>$C) {
273 273
             $h += (int)($l / $C);
274 274
             $l  = $l % $C;
275 275
         }
276 276
 
277
-        if ($h == 0) {
277
+        if ($h==0) {
278 278
             return $l;
279 279
         }
280 280
         return sprintf('%d%05d', $h, $l);
281 281
     }
282 282
 
283 283
     // x32, int
284
-    if ($hi == 0) {
285
-        if ($lo > 0) {
284
+    if ($hi==0) {
285
+        if ($lo>0) {
286 286
             return $lo;
287 287
         }
288 288
         return sprintf('%u', $lo);
@@ -309,10 +309,10 @@  discard block
 block discarded – undo
309 309
 
310 310
     $h = sprintf('%.0f', $h);
311 311
     $l = sprintf('%07.0f', $l);
312
-    if ($h == '0') {
312
+    if ($h=='0') {
313 313
         return sprintf('%.0f', (float)$l);
314 314
     }
315
-    return $h . $l;
315
+    return $h.$l;
316 316
 }
317 317
 
318 318
 // unpack 64-bit signed
@@ -321,24 +321,24 @@  discard block
 block discarded – undo
321 321
     list($hi, $lo) = array_values(unpack('N*N*', $v));
322 322
 
323 323
     // x64
324
-    if (PHP_INT_SIZE >= 8) {
325
-        if ($hi < 0) { // because php 5.2.2 to 5.2.5 is totally fucked up again
324
+    if (PHP_INT_SIZE>=8) {
325
+        if ($hi<0) { // because php 5.2.2 to 5.2.5 is totally fucked up again
326 326
             $hi += 1 << 32;
327 327
         }
328
-        if ($lo < 0) {
328
+        if ($lo<0) {
329 329
             $lo += 1 << 32;
330 330
         }
331 331
 
332 332
         return ($hi << 32) + $lo;
333 333
     }
334 334
 
335
-    if ($hi == 0) { // x32, int
336
-        if ($lo > 0) {
335
+    if ($hi==0) { // x32, int
336
+        if ($lo>0) {
337 337
             return $lo;
338 338
         }
339 339
         return sprintf('%u', $lo);
340
-    } elseif ($hi == -1) { // x32, int
341
-        if ($lo < 0) {
340
+    } elseif ($hi==-1) { // x32, int
341
+        if ($lo<0) {
342 342
             return $lo;
343 343
         }
344 344
         return sprintf('%.0f', $lo - 4294967296.0);
@@ -346,7 +346,7 @@  discard block
 block discarded – undo
346 346
 
347 347
     $neg = '';
348 348
     $c = 0;
349
-    if ($hi < 0) {
349
+    if ($hi<0) {
350 350
         $hi = ~$hi;
351 351
         $lo = ~$lo;
352 352
         $c = 1;
@@ -358,7 +358,7 @@  discard block
 block discarded – undo
358 358
 
359 359
     // x32, bcmath
360 360
     if (function_exists('bcmul')) {
361
-        return $neg . bcadd(bcadd($lo, bcmul($hi, '4294967296')), $c);
361
+        return $neg.bcadd(bcadd($lo, bcmul($hi, '4294967296')), $c);
362 362
     }
363 363
 
364 364
     // x32, no-bcmath
@@ -371,25 +371,25 @@  discard block
 block discarded – undo
371 371
     $mq = floor($m / 10000000.0);
372 372
     $l = $m - $mq * 10000000.0 + $c;
373 373
     $h = $q * 4294967296.0 + $r * 429.0 + $mq;
374
-    if ($l == 10000000) {
374
+    if ($l==10000000) {
375 375
         $l = 0;
376 376
         $h += 1;
377 377
     }
378 378
 
379 379
     $h = sprintf('%.0f', $h);
380 380
     $l = sprintf('%07.0f', $l);
381
-    if ($h == '0') {
382
-        return $neg . sprintf('%.0f', (float)$l);
381
+    if ($h=='0') {
382
+        return $neg.sprintf('%.0f', (float)$l);
383 383
     }
384
-    return $neg . $h . $l;
384
+    return $neg.$h.$l;
385 385
 }
386 386
 
387 387
 
388 388
 function sphFixUint($value)
389 389
 {
390
-    if (PHP_INT_SIZE >= 8) {
390
+    if (PHP_INT_SIZE>=8) {
391 391
         // x64 route, workaround broken unpack() in 5.2.2+
392
-        if ($value < 0) {
392
+        if ($value<0) {
393 393
             $value += 1 << 32;
394 394
         }
395 395
         return $value;
@@ -507,7 +507,7 @@  discard block
 block discarded – undo
507 507
         $this->warning = '';
508 508
         $this->connerror = false;
509 509
 
510
-        $this->reqs = array();// requests storage (for multi-query case)
510
+        $this->reqs = array(); // requests storage (for multi-query case)
511 511
         $this->mbenc = '';
512 512
         $this->arrayresult = false;
513 513
         $this->timeout = 0;
@@ -515,7 +515,7 @@  discard block
 block discarded – undo
515 515
 
516 516
     public function __destruct()
517 517
     {
518
-        if ($this->_socket !== false) {
518
+        if ($this->_socket!==false) {
519 519
             fclose($this->_socket);
520 520
         }
521 521
     }
@@ -542,19 +542,19 @@  discard block
 block discarded – undo
542 542
     public function setServer($host, $port = 0)
543 543
     {
544 544
         assert(is_string($host));
545
-        if ($host[0] == '/') {
546
-            $this->_path = 'unix://' . $host;
545
+        if ($host[0]=='/') {
546
+            $this->_path = 'unix://'.$host;
547 547
             return;
548 548
         }
549
-        if (substr($host, 0, 7) == 'unix://') {
549
+        if (substr($host, 0, 7)=='unix://') {
550 550
             $this->_path = $host;
551 551
             return;
552 552
         }
553 553
 
554 554
         $this->host = $host;
555 555
         $port = intval($port);
556
-        assert(0 <= $port && $port < 65536);
557
-        $this->port = $port == 0 ? 9312 : $port;
556
+        assert(0<=$port && $port<65536);
557
+        $this->port = $port==0 ? 9312 : $port;
558 558
         $this->_path = '';
559 559
     }
560 560
 
@@ -568,7 +568,7 @@  discard block
 block discarded – undo
568 568
 
569 569
     protected function send($handle, $data, $length)
570 570
     {
571
-        if (feof($handle) || fwrite($handle, $data, $length) !== $length) {
571
+        if (feof($handle) || fwrite($handle, $data, $length)!==$length) {
572 572
             $this->error = 'connection unexpectedly closed (timed out?)';
573 573
             $this->connerror = true;
574 574
             return false;
@@ -599,7 +599,7 @@  discard block
 block discarded – undo
599 599
     /// connect to searchd server
600 600
     protected function connect()
601 601
     {
602
-        if ($this->_socket !== false) {
602
+        if ($this->_socket!==false) {
603 603
             // we are in persistent connection mode, so we have a socket
604 604
             // however, need to check whether it's still alive
605 605
             if (!@feof($this->_socket)) {
@@ -622,7 +622,7 @@  discard block
 block discarded – undo
622 622
             $port = $this->port;
623 623
         }
624 624
 
625
-        if ($this->timeout <= 0) {
625
+        if ($this->timeout<=0) {
626 626
             $fp = @fsockopen($host, $port, $errno, $errstr);
627 627
         } else {
628 628
             $fp = @fsockopen($host, $port, $errno, $errstr, $this->timeout);
@@ -654,7 +654,7 @@  discard block
 block discarded – undo
654 654
         // check version
655 655
         list(, $v) = unpack('N*', fread($fp, 4));
656 656
         $v = (int)$v;
657
-        if ($v < 1) {
657
+        if ($v<1) {
658 658
             fclose($fp);
659 659
             $this->error = "expected searchd protocol version 1+, got version '$v'";
660 660
             return false;
@@ -670,10 +670,10 @@  discard block
 block discarded – undo
670 670
         $len = 0;
671 671
 
672 672
         $header = fread($fp, 8);
673
-        if (strlen($header) == 8) {
673
+        if (strlen($header)==8) {
674 674
             list($status, $ver, $len) = array_values(unpack('n2a/Nb', $header));
675 675
             $left = $len;
676
-            while ($left > 0 && !feof($fp)) {
676
+            while ($left>0 && !feof($fp)) {
677 677
                 $chunk = fread($fp, min(8192, $left));
678 678
                 if ($chunk) {
679 679
                     $response .= $chunk;
@@ -681,13 +681,13 @@  discard block
 block discarded – undo
681 681
                 }
682 682
             }
683 683
         }
684
-        if ($this->_socket === false) {
684
+        if ($this->_socket===false) {
685 685
             fclose($fp);
686 686
         }
687 687
 
688 688
         // check response
689 689
         $read = strlen($response);
690
-        if (!$response || $read != $len) {
690
+        if (!$response || $read!=$len) {
691 691
             $this->error = $len
692 692
                 ? "failed to read searchd response (status=$status, ver=$ver, len=$len, read=$read)"
693 693
                 : 'received zero-sized searchd response';
@@ -695,26 +695,26 @@  discard block
 block discarded – undo
695 695
         }
696 696
 
697 697
         // check status
698
-        if ($status == SEARCHD_WARNING) {
698
+        if ($status==SEARCHD_WARNING) {
699 699
             list(, $wlen) = unpack('N*', substr($response, 0, 4));
700 700
             $this->warning = substr($response, 4, $wlen);
701 701
             return substr($response, 4 + $wlen);
702 702
         }
703
-        if ($status == SEARCHD_ERROR) {
704
-            $this->error = 'searchd error: ' . substr($response, 4);
703
+        if ($status==SEARCHD_ERROR) {
704
+            $this->error = 'searchd error: '.substr($response, 4);
705 705
             return false;
706 706
         }
707
-        if ($status == SEARCHD_RETRY) {
708
-            $this->error = 'temporary searchd error: ' . substr($response, 4);
707
+        if ($status==SEARCHD_RETRY) {
708
+            $this->error = 'temporary searchd error: '.substr($response, 4);
709 709
             return false;
710 710
         }
711
-        if ($status != SEARCHD_OK) {
711
+        if ($status!=SEARCHD_OK) {
712 712
             $this->error = "unknown status code '$status'";
713 713
             return false;
714 714
         }
715 715
 
716 716
         // check version
717
-        if ($ver < $client_ver) {
717
+        if ($ver<$client_ver) {
718 718
             $this->warning = sprintf(
719 719
                 'searchd command v.%d.%d older than client\'s v.%d.%d, some options might not work',
720 720
                 $ver >> 8,
@@ -737,15 +737,15 @@  discard block
 block discarded – undo
737 737
     {
738 738
         assert(is_int($offset));
739 739
         assert(is_int($limit));
740
-        assert($offset >= 0);
741
-        assert($limit > 0);
742
-        assert($max >= 0);
740
+        assert($offset>=0);
741
+        assert($limit>0);
742
+        assert($max>=0);
743 743
         $this->offset = $offset;
744 744
         $this->limit = $limit;
745
-        if ($max > 0) {
745
+        if ($max>0) {
746 746
             $this->maxmatches = $max;
747 747
         }
748
-        if ($cutoff > 0) {
748
+        if ($cutoff>0) {
749 749
             $this->cutoff = $cutoff;
750 750
         }
751 751
     }
@@ -755,7 +755,7 @@  discard block
 block discarded – undo
755 755
     public function setMaxQueryTime($max)
756 756
     {
757 757
         assert(is_int($max));
758
-        assert($max >= 0);
758
+        assert($max>=0);
759 759
         $this->maxquerytime = $max;
760 760
     }
761 761
 
@@ -767,21 +767,21 @@  discard block
 block discarded – undo
767 767
             E_USER_DEPRECATED
768 768
         );
769 769
         assert(
770
-            $mode == SPH_MATCH_ALL ||
771
-            $mode == SPH_MATCH_ANY ||
772
-            $mode == SPH_MATCH_PHRASE ||
773
-            $mode == SPH_MATCH_BOOLEAN ||
774
-            $mode == SPH_MATCH_EXTENDED ||
775
-            $mode == SPH_MATCH_FULLSCAN ||
776
-            $mode == SPH_MATCH_EXTENDED2
770
+            $mode==SPH_MATCH_ALL ||
771
+            $mode==SPH_MATCH_ANY ||
772
+            $mode==SPH_MATCH_PHRASE ||
773
+            $mode==SPH_MATCH_BOOLEAN ||
774
+            $mode==SPH_MATCH_EXTENDED ||
775
+            $mode==SPH_MATCH_FULLSCAN ||
776
+            $mode==SPH_MATCH_EXTENDED2
777 777
         );
778 778
         $this->mode = $mode;
779 779
     }
780 780
 
781 781
     /// set ranking mode
782
-    public function setRankingMode($ranker, $rankexpr='')
782
+    public function setRankingMode($ranker, $rankexpr = '')
783 783
     {
784
-        assert($ranker === 0 || $ranker >= 1 && $ranker < SPH_RANK_TOTAL);
784
+        assert($ranker===0 || $ranker>=1 && $ranker<SPH_RANK_TOTAL);
785 785
         assert(is_string($rankexpr));
786 786
         $this->ranker = $ranker;
787 787
         $this->rankexpr = $rankexpr;
@@ -790,16 +790,16 @@  discard block
 block discarded – undo
790 790
     /// set matches sorting mode
791 791
     public function setSortMode($mode, $sortby = '')
792 792
     {
793
-        assert (
794
-            $mode == SPH_SORT_RELEVANCE ||
795
-            $mode == SPH_SORT_ATTR_DESC ||
796
-            $mode == SPH_SORT_ATTR_ASC ||
797
-            $mode == SPH_SORT_TIME_SEGMENTS ||
798
-            $mode == SPH_SORT_EXTENDED ||
799
-            $mode == SPH_SORT_EXPR
793
+        assert(
794
+            $mode==SPH_SORT_RELEVANCE ||
795
+            $mode==SPH_SORT_ATTR_DESC ||
796
+            $mode==SPH_SORT_ATTR_ASC ||
797
+            $mode==SPH_SORT_TIME_SEGMENTS ||
798
+            $mode==SPH_SORT_EXTENDED ||
799
+            $mode==SPH_SORT_EXPR
800 800
         );
801 801
         assert(is_string($sortby));
802
-        assert($mode == SPH_SORT_RELEVANCE || strlen($sortby) > 0);
802
+        assert($mode==SPH_SORT_RELEVANCE || strlen($sortby)>0);
803 803
 
804 804
         $this->sort = $mode;
805 805
         $this->sortby = $sortby;
@@ -843,7 +843,7 @@  discard block
 block discarded – undo
843 843
     {
844 844
         assert(is_numeric($min));
845 845
         assert(is_numeric($max));
846
-        assert($min <= $max);
846
+        assert($min<=$max);
847 847
         $this->min_id = $min;
848 848
         $this->max_id = $max;
849 849
     }
@@ -891,7 +891,7 @@  discard block
 block discarded – undo
891 891
         assert(is_string($attribute));
892 892
         assert(is_numeric($min));
893 893
         assert(is_numeric($max));
894
-        assert($min <= $max);
894
+        assert($min<=$max);
895 895
 
896 896
         $this->filters[] = array(
897 897
             'type' => SPH_FILTER_RANGE,
@@ -909,7 +909,7 @@  discard block
 block discarded – undo
909 909
         assert(is_string($attribute));
910 910
         assert(is_float($min));
911 911
         assert(is_float($max));
912
-        assert($min <= $max);
912
+        assert($min<=$max);
913 913
 
914 914
         $this->filters[] = array(
915 915
             'type' => SPH_FILTER_FLOATRANGE,
@@ -944,12 +944,12 @@  discard block
 block discarded – undo
944 944
         assert(is_string($attribute));
945 945
         assert(is_string($groupsort));
946 946
         assert(
947
-            $func == SPH_GROUPBY_DAY ||
948
-            $func == SPH_GROUPBY_WEEK ||
949
-            $func == SPH_GROUPBY_MONTH ||
950
-            $func == SPH_GROUPBY_YEAR ||
951
-            $func == SPH_GROUPBY_ATTR ||
952
-            $func == SPH_GROUPBY_ATTRPAIR
947
+            $func==SPH_GROUPBY_DAY ||
948
+            $func==SPH_GROUPBY_WEEK ||
949
+            $func==SPH_GROUPBY_MONTH ||
950
+            $func==SPH_GROUPBY_YEAR ||
951
+            $func==SPH_GROUPBY_ATTR ||
952
+            $func==SPH_GROUPBY_ATTRPAIR
953 953
         );
954 954
 
955 955
         $this->groupby = $attribute;
@@ -967,8 +967,8 @@  discard block
 block discarded – undo
967 967
     /// set distributed retries count and delay
968 968
     public function setRetries($count, $delay = 0)
969 969
     {
970
-        assert(is_int($count) && $count >= 0);
971
-        assert(is_int($delay) && $delay >= 0);
970
+        assert(is_int($count) && $count>=0);
971
+        assert(is_int($delay) && $delay>=0);
972 972
         $this->retrycount = $count;
973 973
         $this->retrydelay = $delay;
974 974
     }
@@ -1025,12 +1025,12 @@  discard block
 block discarded – undo
1025 1025
             'global_idf',
1026 1026
             'low_priority'
1027 1027
         );
1028
-        $flags = array (
1028
+        $flags = array(
1029 1029
             'reverse_scan' => array(0, 1),
1030 1030
             'sort_method' => array('pq', 'kbuffer'),
1031 1031
             'max_predicted_time' => array(0),
1032 1032
             'boolean_simplify' => array(true, false),
1033
-            'idf' => array ('normalized', 'plain', 'tfidf_normalized', 'tfidf_unnormalized'),
1033
+            'idf' => array('normalized', 'plain', 'tfidf_normalized', 'tfidf_unnormalized'),
1034 1034
             'global_idf' => array(true, false),
1035 1035
             'low_priority' => array(true, false)
1036 1036
         );
@@ -1038,32 +1038,32 @@  discard block
 block discarded – undo
1038 1038
         assert(isset($flag_name, $known_names));
1039 1039
         assert(
1040 1040
             in_array($flag_value, $flags[$flag_name], true) ||
1041
-            ($flag_name == 'max_predicted_time' && is_int($flag_value) && $flag_value >= 0)
1041
+            ($flag_name=='max_predicted_time' && is_int($flag_value) && $flag_value>=0)
1042 1042
         );
1043 1043
 
1044
-        if ($flag_name == 'reverse_scan') {
1045
-            $this->query_flags = sphSetBit($this->query_flags, 0, $flag_value == 1);
1044
+        if ($flag_name=='reverse_scan') {
1045
+            $this->query_flags = sphSetBit($this->query_flags, 0, $flag_value==1);
1046 1046
         }
1047
-        if ($flag_name == 'sort_method') {
1048
-            $this->query_flags = sphSetBit($this->query_flags, 1, $flag_value == 'kbuffer');
1047
+        if ($flag_name=='sort_method') {
1048
+            $this->query_flags = sphSetBit($this->query_flags, 1, $flag_value=='kbuffer');
1049 1049
         }
1050
-        if ($flag_name == 'max_predicted_time') {
1051
-            $this->query_flags = sphSetBit($this->query_flags, 2, $flag_value > 0);
1050
+        if ($flag_name=='max_predicted_time') {
1051
+            $this->query_flags = sphSetBit($this->query_flags, 2, $flag_value>0);
1052 1052
             $this->predictedtime = (int)$flag_value;
1053 1053
         }
1054
-        if ($flag_name == 'boolean_simplify') {
1054
+        if ($flag_name=='boolean_simplify') {
1055 1055
             $this->query_flags = sphSetBit($this->query_flags, 3, $flag_value);
1056 1056
         }
1057
-        if ($flag_name == 'idf' && ($flag_value == 'normalized' || $flag_value == 'plain')) {
1058
-            $this->query_flags = sphSetBit($this->query_flags, 4, $flag_value == 'plain');
1057
+        if ($flag_name=='idf' && ($flag_value=='normalized' || $flag_value=='plain')) {
1058
+            $this->query_flags = sphSetBit($this->query_flags, 4, $flag_value=='plain');
1059 1059
         }
1060
-        if ($flag_name == 'global_idf') {
1060
+        if ($flag_name=='global_idf') {
1061 1061
             $this->query_flags = sphSetBit($this->query_flags, 5, $flag_value);
1062 1062
         }
1063
-        if ($flag_name == 'idf' && ($flag_value == 'tfidf_normalized' || $flag_value == 'tfidf_unnormalized')) {
1064
-            $this->query_flags = sphSetBit($this->query_flags, 6, $flag_value == 'tfidf_normalized');
1063
+        if ($flag_name=='idf' && ($flag_value=='tfidf_normalized' || $flag_value=='tfidf_unnormalized')) {
1064
+            $this->query_flags = sphSetBit($this->query_flags, 6, $flag_value=='tfidf_normalized');
1065 1065
         }
1066
-        if ($flag_name == 'low_priority') {
1066
+        if ($flag_name=='low_priority') {
1067 1067
             $this->query_flags = sphSetBit($this->query_flags, 8, $flag_value);
1068 1068
         }
1069 1069
     }
@@ -1074,8 +1074,8 @@  discard block
 block discarded – undo
1074 1074
         assert(is_string($orderby));
1075 1075
         assert(is_int($offset));
1076 1076
         assert(is_int($limit));
1077
-        assert($offset >= 0);
1078
-        assert($limit > 0);
1077
+        assert($offset>=0);
1078
+        assert($limit>0);
1079 1079
 
1080 1080
         $this->outerorderby = $orderby;
1081 1081
         $this->outeroffset = $offset;
@@ -1140,7 +1140,7 @@  discard block
 block discarded – undo
1140 1140
 
1141 1141
         $this->error = $results[0]['error'];
1142 1142
         $this->warning = $results[0]['warning'];
1143
-        if ($results[0]['status'] == SEARCHD_ERROR) {
1143
+        if ($results[0]['status']==SEARCHD_ERROR) {
1144 1144
             return false;
1145 1145
         } else {
1146 1146
             return $results[0];
@@ -1164,24 +1164,24 @@  discard block
 block discarded – undo
1164 1164
 
1165 1165
         // build request
1166 1166
         $req = pack('NNNNN', $this->query_flags, $this->offset, $this->limit, $this->mode, $this->ranker);
1167
-        if ($this->ranker == SPH_RANK_EXPR) {
1168
-            $req .= pack('N', strlen($this->rankexpr)) . $this->rankexpr;
1167
+        if ($this->ranker==SPH_RANK_EXPR) {
1168
+            $req .= pack('N', strlen($this->rankexpr)).$this->rankexpr;
1169 1169
         }
1170 1170
         $req .= pack('N', $this->sort); // (deprecated) sort mode
1171
-        $req .= pack('N', strlen($this->sortby)) . $this->sortby;
1172
-        $req .= pack('N', strlen($query)) . $query; // query itself
1171
+        $req .= pack('N', strlen($this->sortby)).$this->sortby;
1172
+        $req .= pack('N', strlen($query)).$query; // query itself
1173 1173
         $req .= pack('N', count($this->weights)); // weights
1174 1174
         foreach ($this->weights as $weight) {
1175 1175
             $req .= pack('N', (int)$weight);
1176 1176
         }
1177
-        $req .= pack('N', strlen($index)) . $index; // indexes
1177
+        $req .= pack('N', strlen($index)).$index; // indexes
1178 1178
         $req .= pack('N', 1); // id64 range marker
1179
-        $req .= sphPackU64($this->min_id) . sphPackU64($this->max_id); // id64 range
1179
+        $req .= sphPackU64($this->min_id).sphPackU64($this->max_id); // id64 range
1180 1180
 
1181 1181
         // filters
1182 1182
         $req .= pack('N', count($this->filters));
1183 1183
         foreach ($this->filters as $filter) {
1184
-            $req .= pack('N', strlen($filter['attr'])) . $filter['attr'];
1184
+            $req .= pack('N', strlen($filter['attr'])).$filter['attr'];
1185 1185
             $req .= pack('N', $filter['type']);
1186 1186
             switch ($filter['type']) {
1187 1187
                 case SPH_FILTER_VALUES:
@@ -1191,13 +1191,13 @@  discard block
 block discarded – undo
1191 1191
                     }
1192 1192
                     break;
1193 1193
                 case SPH_FILTER_RANGE:
1194
-                    $req .= sphPackI64($filter['min']) . sphPackI64($filter['max']);
1194
+                    $req .= sphPackI64($filter['min']).sphPackI64($filter['max']);
1195 1195
                     break;
1196 1196
                 case SPH_FILTER_FLOATRANGE:
1197
-                    $req .= $this->packFloat($filter['min']) . $this->packFloat($filter['max']);
1197
+                    $req .= $this->packFloat($filter['min']).$this->packFloat($filter['max']);
1198 1198
                     break;
1199 1199
                 case SPH_FILTER_STRING:
1200
-                    $req .= pack('N', strlen($filter['value'])) . $filter['value'];
1200
+                    $req .= pack('N', strlen($filter['value'])).$filter['value'];
1201 1201
                     break;
1202 1202
                 default:
1203 1203
                     assert(0 && 'internal error: unhandled filter type');
@@ -1206,27 +1206,27 @@  discard block
 block discarded – undo
1206 1206
         }
1207 1207
 
1208 1208
         // group-by clause, max-matches count, group-sort clause, cutoff count
1209
-        $req .= pack('NN', $this->groupfunc, strlen($this->groupby)) . $this->groupby;
1209
+        $req .= pack('NN', $this->groupfunc, strlen($this->groupby)).$this->groupby;
1210 1210
         $req .= pack('N', $this->maxmatches);
1211
-        $req .= pack('N', strlen($this->groupsort)) . $this->groupsort;
1211
+        $req .= pack('N', strlen($this->groupsort)).$this->groupsort;
1212 1212
         $req .= pack('NNN', $this->cutoff, $this->retrycount, $this->retrydelay);
1213
-        $req .= pack('N', strlen($this->groupdistinct)) . $this->groupdistinct;
1213
+        $req .= pack('N', strlen($this->groupdistinct)).$this->groupdistinct;
1214 1214
 
1215 1215
         // anchor point
1216 1216
         if (empty($this->anchor)) {
1217 1217
             $req .= pack('N', 0);
1218 1218
         } else {
1219
-            $a =& $this->anchor;
1219
+            $a = & $this->anchor;
1220 1220
             $req .= pack('N', 1);
1221
-            $req .= pack('N', strlen($a['attrlat'])) . $a['attrlat'];
1222
-            $req .= pack('N', strlen($a['attrlong'])) . $a['attrlong'];
1223
-            $req .= $this->packFloat($a['lat']) . $this->packFloat($a['long']);
1221
+            $req .= pack('N', strlen($a['attrlat'])).$a['attrlat'];
1222
+            $req .= pack('N', strlen($a['attrlong'])).$a['attrlong'];
1223
+            $req .= $this->packFloat($a['lat']).$this->packFloat($a['long']);
1224 1224
         }
1225 1225
 
1226 1226
         // per-index weights
1227 1227
         $req .= pack('N', count($this->indexweights));
1228 1228
         foreach ($this->indexweights as $idx => $weight) {
1229
-            $req .= pack('N', strlen($idx)) . $idx . pack('N', $weight);
1229
+            $req .= pack('N', strlen($idx)).$idx.pack('N', $weight);
1230 1230
         }
1231 1231
 
1232 1232
         // max query time
@@ -1235,16 +1235,16 @@  discard block
 block discarded – undo
1235 1235
         // per-field weights
1236 1236
         $req .= pack('N', count($this->fieldweights));
1237 1237
         foreach ($this->fieldweights as $field => $weight) {
1238
-            $req .= pack('N', strlen($field)) . $field . pack('N', $weight);
1238
+            $req .= pack('N', strlen($field)).$field.pack('N', $weight);
1239 1239
         }
1240 1240
 
1241 1241
         // comment
1242
-        $req .= pack('N', strlen($comment)) . $comment;
1242
+        $req .= pack('N', strlen($comment)).$comment;
1243 1243
 
1244 1244
         // attribute overrides
1245 1245
         $req .= pack('N', count($this->overrides));
1246 1246
         foreach ($this->overrides as $key => $entry) {
1247
-            $req .= pack('N', strlen($entry['attr'])) . $entry['attr'];
1247
+            $req .= pack('N', strlen($entry['attr'])).$entry['attr'];
1248 1248
             $req .= pack('NN', $entry['type'], count($entry['values']));
1249 1249
             foreach ($entry['values'] as $id => $val) {
1250 1250
                 assert(is_numeric($id));
@@ -1266,14 +1266,14 @@  discard block
 block discarded – undo
1266 1266
         }
1267 1267
 
1268 1268
         // select-list
1269
-        $req .= pack('N', strlen($this->select)) . $this->select;
1269
+        $req .= pack('N', strlen($this->select)).$this->select;
1270 1270
 
1271 1271
         // max_predicted_time
1272
-        if ($this->predictedtime > 0) {
1272
+        if ($this->predictedtime>0) {
1273 1273
             $req .= pack('N', (int)$this->predictedtime);
1274 1274
         }
1275 1275
 
1276
-        $req .= pack('N', strlen($this->outerorderby)) . $this->outerorderby;
1276
+        $req .= pack('N', strlen($this->outerorderby)).$this->outerorderby;
1277 1277
         $req .= pack('NN', $this->outeroffset, $this->outerlimit);
1278 1278
         if ($this->hasouter) {
1279 1279
             $req .= pack('N', 1);
@@ -1309,7 +1309,7 @@  discard block
 block discarded – undo
1309 1309
         $nreqs = count($this->reqs);
1310 1310
         $req = join('', $this->reqs);
1311 1311
         $len = 8 + strlen($req);
1312
-        $req = pack('nnNNN', SEARCHD_COMMAND_SEARCH, VER_COMMAND_SEARCH, $len, 0, $nreqs) . $req; // add header
1312
+        $req = pack('nnNNN', SEARCHD_COMMAND_SEARCH, VER_COMMAND_SEARCH, $len, 0, $nreqs).$req; // add header
1313 1313
 
1314 1314
         if (!$this->send($fp, $req, $len + 8) || !($response = $this->getResponse($fp, VER_COMMAND_SEARCH))) {
1315 1315
             $this->mbPop();
@@ -1330,9 +1330,9 @@  discard block
 block discarded – undo
1330 1330
         $max = strlen($response); // max position for checks, to protect against broken responses
1331 1331
 
1332 1332
         $results = array();
1333
-        for ($ires = 0; $ires < $nreqs && $p < $max; $ires++) {
1333
+        for ($ires = 0; $ires<$nreqs && $p<$max; $ires++) {
1334 1334
             $results[] = array();
1335
-            $result =& $results[$ires];
1335
+            $result = & $results[$ires];
1336 1336
 
1337 1337
             $result['error'] = '';
1338 1338
             $result['warning'] = '';
@@ -1341,13 +1341,13 @@  discard block
 block discarded – undo
1341 1341
             list(, $status) = unpack('N*', substr($response, $p, 4));
1342 1342
             $p += 4;
1343 1343
             $result['status'] = $status;
1344
-            if ($status != SEARCHD_OK) {
1344
+            if ($status!=SEARCHD_OK) {
1345 1345
                 list(, $len) = unpack('N*', substr($response, $p, 4));
1346 1346
                 $p += 4;
1347 1347
                 $message = substr($response, $p, $len);
1348 1348
                 $p += $len;
1349 1349
 
1350
-                if ($status == SEARCHD_WARNING) {
1350
+                if ($status==SEARCHD_WARNING) {
1351 1351
                     $result['warning'] = $message;
1352 1352
                 } else {
1353 1353
                     $result['error'] = $message;
@@ -1361,7 +1361,7 @@  discard block
 block discarded – undo
1361 1361
 
1362 1362
             list(, $nfields) = unpack('N*', substr($response, $p, 4));
1363 1363
             $p += 4;
1364
-            while ($nfields --> 0 && $p < $max) {
1364
+            while ($nfields-->0 && $p<$max) {
1365 1365
                 list(, $len) = unpack('N*', substr($response, $p, 4));
1366 1366
                 $p += 4;
1367 1367
                 $fields[] = substr($response, $p, $len);
@@ -1371,7 +1371,7 @@  discard block
 block discarded – undo
1371 1371
 
1372 1372
             list(, $nattrs) = unpack('N*', substr($response, $p, 4));
1373 1373
             $p += 4;
1374
-            while ($nattrs --> 0 && $p < $max) {
1374
+            while ($nattrs-->0 && $p<$max) {
1375 1375
                 list(, $len) = unpack('N*', substr($response, $p, 4));
1376 1376
                 $p += 4;
1377 1377
                 $attr = substr($response, $p, $len);
@@ -1390,7 +1390,7 @@  discard block
 block discarded – undo
1390 1390
 
1391 1391
             // read matches
1392 1392
             $idx = -1;
1393
-            while ($count --> 0 && $p < $max) {
1393
+            while ($count-->0 && $p<$max) {
1394 1394
                 // index into result array
1395 1395
                 $idx++;
1396 1396
 
@@ -1418,14 +1418,14 @@  discard block
 block discarded – undo
1418 1418
                 $attrvals = array();
1419 1419
                 foreach ($attrs as $attr => $type) {
1420 1420
                     // handle 64bit ints
1421
-                    if ($type == SPH_ATTR_BIGINT) {
1421
+                    if ($type==SPH_ATTR_BIGINT) {
1422 1422
                         $attrvals[$attr] = sphUnpackI64(substr($response, $p, 8));
1423 1423
                         $p += 8;
1424 1424
                         continue;
1425 1425
                     }
1426 1426
 
1427 1427
                     // handle floats
1428
-                    if ($type == SPH_ATTR_FLOAT) {
1428
+                    if ($type==SPH_ATTR_FLOAT) {
1429 1429
                         list(, $uval) = unpack('N*', substr($response, $p, 4));
1430 1430
                         $p += 4;
1431 1431
                         list(, $fval) = unpack('f*', pack('L', $uval));
@@ -1436,28 +1436,28 @@  discard block
 block discarded – undo
1436 1436
                     // handle everything else as unsigned ints
1437 1437
                     list(, $val) = unpack('N*', substr($response, $p, 4));
1438 1438
                     $p += 4;
1439
-                    if ($type == SPH_ATTR_MULTI) {
1439
+                    if ($type==SPH_ATTR_MULTI) {
1440 1440
                         $attrvals[$attr] = array();
1441 1441
                         $nvalues = $val;
1442
-                        while ($nvalues --> 0 && $p < $max) {
1442
+                        while ($nvalues-->0 && $p<$max) {
1443 1443
                             list(, $val) = unpack('N*', substr($response, $p, 4));
1444 1444
                             $p += 4;
1445 1445
                             $attrvals[$attr][] = sphFixUint($val);
1446 1446
                         }
1447
-                    } elseif ($type == SPH_ATTR_MULTI64) {
1447
+                    } elseif ($type==SPH_ATTR_MULTI64) {
1448 1448
                         $attrvals[$attr] = array();
1449 1449
                         $nvalues = $val;
1450
-                        while ($nvalues > 0 && $p < $max) {
1450
+                        while ($nvalues>0 && $p<$max) {
1451 1451
                             $attrvals[$attr][] = sphUnpackI64(substr($response, $p, 8));
1452 1452
                             $p += 8;
1453 1453
                             $nvalues -= 2;
1454 1454
                         }
1455
-                    } elseif ($type == SPH_ATTR_STRING) {
1455
+                    } elseif ($type==SPH_ATTR_STRING) {
1456 1456
                         $attrvals[$attr] = substr($response, $p, $val);
1457 1457
                         $p += $val;
1458
-                    } elseif ($type == SPH_ATTR_FACTORS) {
1458
+                    } elseif ($type==SPH_ATTR_FACTORS) {
1459 1459
                         $attrvals[$attr] = substr($response, $p, $val - 4);
1460
-                        $p += $val-4;
1460
+                        $p += $val - 4;
1461 1461
                     } else {
1462 1462
                         $attrvals[$attr] = sphFixUint($val);
1463 1463
                     }
@@ -1476,14 +1476,14 @@  discard block
 block discarded – undo
1476 1476
             $result['time'] = sprintf('%.3f', $msecs / 1000);
1477 1477
             $p += 16;
1478 1478
 
1479
-            while ($words --> 0 && $p < $max) {
1479
+            while ($words-->0 && $p<$max) {
1480 1480
                 list(, $len) = unpack('N*', substr($response, $p, 4));
1481 1481
                 $p += 4;
1482 1482
                 $word = substr($response, $p, $len);
1483 1483
                 $p += $len;
1484 1484
                 list($docs, $hits) = array_values(unpack('N*N*', substr($response, $p, 8)));
1485 1485
                 $p += 8;
1486
-                $result['words'][$word] = array (
1486
+                $result['words'][$word] = array(
1487 1487
                     'docs' => sprintf('%u', $docs),
1488 1488
                     'hits' => sprintf('%u', $hits)
1489 1489
                 );
@@ -1618,23 +1618,23 @@  discard block
 block discarded – undo
1618 1618
             $flags |= 1024;
1619 1619
         }
1620 1620
         $req = pack('NN', 0, $flags); // mode=0, flags=$flags
1621
-        $req .= pack('N', strlen($index)) . $index; // req index
1622
-        $req .= pack('N', strlen($words)) . $words; // req words
1621
+        $req .= pack('N', strlen($index)).$index; // req index
1622
+        $req .= pack('N', strlen($words)).$words; // req words
1623 1623
 
1624 1624
         // options
1625
-        $req .= pack('N', strlen($opts['before_match'])) . $opts['before_match'];
1626
-        $req .= pack('N', strlen($opts['after_match'])) . $opts['after_match'];
1627
-        $req .= pack('N', strlen($opts['chunk_separator'])) . $opts['chunk_separator'];
1625
+        $req .= pack('N', strlen($opts['before_match'])).$opts['before_match'];
1626
+        $req .= pack('N', strlen($opts['after_match'])).$opts['after_match'];
1627
+        $req .= pack('N', strlen($opts['chunk_separator'])).$opts['chunk_separator'];
1628 1628
         $req .= pack('NN', (int)$opts['limit'], (int)$opts['around']);
1629 1629
         $req .= pack('NNN', (int)$opts['limit_passages'], (int)$opts['limit_words'], (int)$opts['start_passage_id']); // v.1.2
1630
-        $req .= pack('N', strlen($opts['html_strip_mode'])) . $opts['html_strip_mode'];
1631
-        $req .= pack('N', strlen($opts['passage_boundary'])) . $opts['passage_boundary'];
1630
+        $req .= pack('N', strlen($opts['html_strip_mode'])).$opts['html_strip_mode'];
1631
+        $req .= pack('N', strlen($opts['passage_boundary'])).$opts['passage_boundary'];
1632 1632
 
1633 1633
         // documents
1634 1634
         $req .= pack('N', count($docs));
1635 1635
         foreach ($docs as $doc) {
1636 1636
             assert(is_string($doc));
1637
-            $req .= pack('N', strlen($doc)) . $doc;
1637
+            $req .= pack('N', strlen($doc)).$doc;
1638 1638
         }
1639 1639
 
1640 1640
         ////////////////////////////
@@ -1642,7 +1642,7 @@  discard block
 block discarded – undo
1642 1642
         ////////////////////////////
1643 1643
 
1644 1644
         $len = strlen($req);
1645
-        $req = pack('nnN', SEARCHD_COMMAND_EXCERPT, VER_COMMAND_EXCERPT, $len) . $req; // add header
1645
+        $req = pack('nnN', SEARCHD_COMMAND_EXCERPT, VER_COMMAND_EXCERPT, $len).$req; // add header
1646 1646
         if (!$this->send($fp, $req, $len + 8) || !($response = $this->getResponse($fp, VER_COMMAND_EXCERPT))) {
1647 1647
             $this->mbPop();
1648 1648
             return false;
@@ -1660,7 +1660,7 @@  discard block
 block discarded – undo
1660 1660
             list(, $len) = unpack('N*', substr($response, $pos, 4));
1661 1661
             $pos += 4;
1662 1662
 
1663
-            if ($pos + $len > $rlen) {
1663
+            if ($pos + $len>$rlen) {
1664 1664
                 $this->error = 'incomplete reply';
1665 1665
                 $this->mbPop();
1666 1666
                 return false;
@@ -1699,8 +1699,8 @@  discard block
 block discarded – undo
1699 1699
         /////////////////
1700 1700
 
1701 1701
         // v.1.0 req
1702
-        $req  = pack('N', strlen($query)) . $query; // req query
1703
-        $req .= pack('N', strlen($index)) . $index; // req index
1702
+        $req  = pack('N', strlen($query)).$query; // req query
1703
+        $req .= pack('N', strlen($index)).$index; // req index
1704 1704
         $req .= pack('N', (int)$hits);
1705 1705
 
1706 1706
         ////////////////////////////
@@ -1708,7 +1708,7 @@  discard block
 block discarded – undo
1708 1708
         ////////////////////////////
1709 1709
 
1710 1710
         $len = strlen($req);
1711
-        $req = pack('nnN', SEARCHD_COMMAND_KEYWORDS, VER_COMMAND_KEYWORDS, $len) . $req; // add header
1711
+        $req = pack('nnN', SEARCHD_COMMAND_KEYWORDS, VER_COMMAND_KEYWORDS, $len).$req; // add header
1712 1712
         if (!$this->send($fp, $req, $len + 8) || !($response = $this->getResponse($fp, VER_COMMAND_KEYWORDS))) {
1713 1713
             $this->mbPop();
1714 1714
             return false;
@@ -1723,7 +1723,7 @@  discard block
 block discarded – undo
1723 1723
         $rlen = strlen($response);
1724 1724
         list(, $nwords) = unpack('N*', substr($response, $pos, 4));
1725 1725
         $pos += 4;
1726
-        for ($i = 0; $i < $nwords; $i++) {
1726
+        for ($i = 0; $i<$nwords; $i++) {
1727 1727
             list(, $len) = unpack('N*', substr($response, $pos, 4));
1728 1728
             $pos += 4;
1729 1729
             $tokenized = $len ? substr($response, $pos, $len) : '';
@@ -1746,7 +1746,7 @@  discard block
 block discarded – undo
1746 1746
                 $res[$i]['hits'] = $nhits;
1747 1747
             }
1748 1748
 
1749
-            if ($pos > $rlen) {
1749
+            if ($pos>$rlen) {
1750 1750
                 $this->error = 'incomplete reply';
1751 1751
                 $this->mbPop();
1752 1752
                 return false;
@@ -1759,8 +1759,8 @@  discard block
 block discarded – undo
1759 1759
 
1760 1760
     public function escapeString($string)
1761 1761
     {
1762
-        $from = array('\\', '(',')','|','-','!','@','~','"','&', '/', '^', '$', '=', '<');
1763
-        $to   = array('\\\\', '\(','\)','\|','\-','\!','\@','\~','\"', '\&', '\/', '\^', '\$', '\=', '\<');
1762
+        $from = array('\\', '(', ')', '|', '-', '!', '@', '~', '"', '&', '/', '^', '$', '=', '<');
1763
+        $to   = array('\\\\', '\(', '\)', '\|', '\-', '\!', '\@', '\~', '\"', '\&', '\/', '\^', '\$', '\=', '\<');
1764 1764
 
1765 1765
         return str_replace($from, $to, $string);
1766 1766
     }
@@ -1787,7 +1787,7 @@  discard block
 block discarded – undo
1787 1787
         foreach ($values as $id => $entry) {
1788 1788
             assert(is_numeric($id));
1789 1789
             assert(is_array($entry));
1790
-            assert(count($entry) == count($attrs));
1790
+            assert(count($entry)==count($attrs));
1791 1791
             foreach ($entry as $v) {
1792 1792
                 if ($mva) {
1793 1793
                     assert(is_array($v));
@@ -1802,12 +1802,12 @@  discard block
 block discarded – undo
1802 1802
 
1803 1803
         // build request
1804 1804
         $this->mbPush();
1805
-        $req = pack('N', strlen($index)) . $index;
1805
+        $req = pack('N', strlen($index)).$index;
1806 1806
 
1807 1807
         $req .= pack('N', count($attrs));
1808 1808
         $req .= pack('N', $ignorenonexistent ? 1 : 0);
1809 1809
         foreach ($attrs as $attr) {
1810
-            $req .= pack('N', strlen($attr)) . $attr;
1810
+            $req .= pack('N', strlen($attr)).$attr;
1811 1811
             $req .= pack('N', $mva ? 1 : 0);
1812 1812
         }
1813 1813
 
@@ -1831,7 +1831,7 @@  discard block
 block discarded – undo
1831 1831
         }
1832 1832
 
1833 1833
         $len = strlen($req);
1834
-        $req = pack('nnN', SEARCHD_COMMAND_UPDATE, VER_COMMAND_UPDATE, $len) . $req; // add header
1834
+        $req = pack('nnN', SEARCHD_COMMAND_UPDATE, VER_COMMAND_UPDATE, $len).$req; // add header
1835 1835
         if (!$this->send($fp, $req, $len + 8)) {
1836 1836
             $this->mbPop();
1837 1837
             return -1;
@@ -1854,7 +1854,7 @@  discard block
 block discarded – undo
1854 1854
 
1855 1855
     public function open()
1856 1856
     {
1857
-        if ($this->_socket !== false) {
1857
+        if ($this->_socket!==false) {
1858 1858
             $this->error = 'already connected';
1859 1859
             return false;
1860 1860
         }
@@ -1873,7 +1873,7 @@  discard block
 block discarded – undo
1873 1873
 
1874 1874
     public function close()
1875 1875
     {
1876
-        if ($this->_socket === false) {
1876
+        if ($this->_socket===false) {
1877 1877
             $this->error = 'not connected';
1878 1878
             return false;
1879 1879
         }
@@ -1910,8 +1910,8 @@  discard block
 block discarded – undo
1910 1910
         $p += 8;
1911 1911
 
1912 1912
         $res = array();
1913
-        for ($i = 0; $i < $rows; $i++) {
1914
-            for ($j = 0; $j < $cols; $j++) {
1913
+        for ($i = 0; $i<$rows; $i++) {
1914
+            for ($j = 0; $j<$cols; $j++) {
1915 1915
                 list(, $len) = unpack('N*', substr($response, $p, 4));
1916 1916
                 $p += 4;
1917 1917
                 $res[$i][] = substr($response, $p, $len);
@@ -1942,7 +1942,7 @@  discard block
 block discarded – undo
1942 1942
         }
1943 1943
 
1944 1944
         $tag = -1;
1945
-        if (strlen($response) == 4) {
1945
+        if (strlen($response)==4) {
1946 1946
             list(, $tag) = unpack('N*', $response);
1947 1947
         } else {
1948 1948
             $this->error = 'unexpected response length';
Please login to merge, or discard this patch.
src/test.php 2 patches
Indentation   +198 added lines, -198 removed lines patch added patch discarded remove patch
@@ -7,7 +7,7 @@  discard block
 block discarded – undo
7 7
 $file = __DIR__.'/../vendor/autoload.php';
8 8
 
9 9
 if (!file_exists($file)) {
10
-    throw new RuntimeException('Install dependencies to run test suite. "php composer.phar install --dev"');
10
+	throw new RuntimeException('Install dependencies to run test suite. "php composer.phar install --dev"');
11 11
 }
12 12
 
13 13
 require_once __DIR__.'/../vendor/autoload.php';
@@ -18,13 +18,13 @@  discard block
 block discarded – undo
18 18
 
19 19
 // for very old PHP versions, like at my home test server
20 20
 if (is_array($argv) && !isset($_SERVER['argv'])) {
21
-    $_SERVER['argv'] = $argv;
21
+	$_SERVER['argv'] = $argv;
22 22
 }
23 23
 unset($_SERVER['argv'][0]);
24 24
 
25 25
 // build query
26 26
 if (!is_array($_SERVER['argv']) || empty($_SERVER['argv'])) {
27
-    print <<<EOF
27
+	print <<<EOF
28 28
 Usage: php -f test.php [OPTIONS] query words
29 29
 
30 30
 Options are:
@@ -49,199 +49,199 @@  discard block
 block discarded – undo
49 49
 EOF;
50 50
 } else {
51 51
 
52
-    $args = array();
53
-    foreach ($_SERVER['argv'] as $arg) {
54
-        $args[] = $arg;
55
-    }
56
-
57
-    $cl = new SphinxClient();
58
-
59
-    $q = '';
60
-    $sql = '';
61
-    $mode = SPH_MATCH_ALL;
62
-    $host = 'localhost';
63
-    $port = 9312;
64
-    $index = '*';
65
-    $groupby = '';
66
-    $groupsort = '@group desc';
67
-    $filter = 'group_id';
68
-    $filtervals = array();
69
-    $distinct = '';
70
-    $sortby = '';
71
-    $sortexpr = '';
72
-    $limit = 20;
73
-    $ranker = SPH_RANK_PROXIMITY_BM25;
74
-    $select = '';
75
-    $count = count($args);
76
-
77
-    for ($i = 0; $i < $count; $i++) {
78
-        switch ($args[$i]) {
79
-            case '-h':
80
-            case '--host':
81
-                $host = $args[++$i];
82
-                break;
83
-            case '-p':
84
-            case '--port':
85
-                $port = (int)$args[++$i];
86
-                break;
87
-            case '-i':
88
-            case '--index':
89
-                $index = $args[++$i];
90
-                break;
91
-            case '-s':
92
-            case '--sortby':
93
-                $sortby = $args[++$i];
94
-                $sortexpr = '';
95
-                break;
96
-            case '-S':
97
-            case '--sortexpr':
98
-                $sortexpr = $args[++$i];
99
-                $sortby = '';
100
-                break;
101
-            case '-a':
102
-            case '--any':
103
-                $mode = SPH_MATCH_ANY;
104
-                break;
105
-            case '-b':
106
-            case '--boolean':
107
-                $mode = SPH_MATCH_BOOLEAN;
108
-                break;
109
-            case '-e':
110
-            case '--extended':
111
-                $mode = SPH_MATCH_EXTENDED;
112
-                break;
113
-            case '-e2':
114
-                $mode = SPH_MATCH_EXTENDED2;
115
-                break;
116
-            case '-ph':
117
-            case '--phrase':
118
-                $mode = SPH_MATCH_PHRASE;
119
-                break;
120
-            case '-f':
121
-            case '--filter':
122
-                $filter = $args[++$i];
123
-                break;
124
-            case '-v':
125
-            case '--value':
126
-                $filtervals[] = $args[++$i];
127
-                break;
128
-            case '-g':
129
-            case '--groupby':
130
-                $groupby = $args[++$i];
131
-                break;
132
-            case '-gs':
133
-            case '--groupsort':
134
-                $groupsort = $args[++$i];
135
-                break;
136
-            case '-d':
137
-            case '--distinct':
138
-                $distinct = $args[++$i];
139
-                break;
140
-            case '-l':
141
-            case '--limit':
142
-                $limit = (int)$args[++$i];
143
-                break;
144
-            case '--select':
145
-                $select = $args[++$i];
146
-                break;
147
-            case '-fr':
148
-            case '--filterrange':
149
-                $cl->setFilterRange($args[++$i], $args[++$i], $args[++$i]);
150
-                break;
151
-            case '-r':
152
-                switch (strtolower($args[++$i])) {
153
-                    case 'bm25':
154
-                        $ranker = SPH_RANK_BM25;
155
-                        break;
156
-                    case 'none':
157
-                        $ranker = SPH_RANK_NONE;
158
-                        break;
159
-                    case 'wordcount':
160
-                        $ranker = SPH_RANK_WORDCOUNT;
161
-                        break;
162
-                    case 'fieldmask':
163
-                        $ranker = SPH_RANK_FIELDMASK;
164
-                        break;
165
-                    case 'sph04':
166
-                        $ranker = SPH_RANK_SPH04;
167
-                        break;
168
-                }
169
-                break;
170
-            default:
171
-                $q .= $args[$i] . ' ';
172
-        }
173
-    }
174
-
175
-    ////////////
176
-    // do query
177
-    ////////////
178
-
179
-    $cl->setServer($host, $port);
180
-    $cl->setConnectTimeout(1);
181
-    $cl->setArrayResult(true);
182
-    $cl->setMatchMode($mode);
183
-    if (count($filtervals)) {
184
-        $cl->setFilter($filter, $filtervals);
185
-    }
186
-    if ($groupby) {
187
-        $cl->setGroupBy($groupby, SPH_GROUPBY_ATTR, $groupsort);
188
-    }
189
-    if ($sortby) {
190
-        $cl->setSortMode(SPH_SORT_EXTENDED, $sortby);
191
-    }
192
-    if ($sortexpr) {
193
-        $cl->setSortMode(SPH_SORT_EXPR, $sortexpr);
194
-    }
195
-    if ($distinct) {
196
-        $cl->setGroupDistinct($distinct);
197
-    }
198
-    if ($select) {
199
-        $cl->setSelect($select);
200
-    }
201
-    if ($limit) {
202
-        $cl->setLimits(0, $limit, ($limit > 1000) ? $limit : 1000);
203
-    }
204
-    $cl->setRankingMode($ranker);
205
-    $res = $cl->query($q, $index);
206
-
207
-    ////////////////
208
-    // print me out
209
-    ////////////////
210
-
211
-    if ($res === false) {
212
-        printf('Query failed: %s.' . PHP_EOL, $cl->getLastError());
213
-
214
-    } else {
215
-        if ($cl->getLastWarning()) {
216
-            printf('WARNING: %s' . PHP_EOL . PHP_EOL, $cl->getLastWarning());
217
-        }
218
-
219
-        print "Query '$q' retrieved {$res['total']} of {$res['total_found']} matches in {$res['time']} sec.\n";
220
-        print 'Query stats:' . PHP_EOL;
221
-        if (is_array($res['words'])) {
222
-            foreach ($res['words'] as $word => $info) {
223
-                print "    '$word' found {$info['hits']} times in {$info['docs']} documents\n";
224
-            }
225
-        }
226
-        print PHP_EOL;
227
-
228
-        if (is_array($res['matches'])) {
229
-            $n = 1;
230
-            print 'Matches:' . PHP_EOL;
231
-            foreach ($res['matches'] as $docinfo) {
232
-                print "$n. doc_id={$docinfo['id']}, weight={$docinfo['weight']}";
233
-                foreach ($res['attrs'] as $attrname => $attrtype) {
234
-                    $value = $docinfo['attrs'][$attrname];
235
-                    if ($attrtype == SPH_ATTR_MULTI || $attrtype == SPH_ATTR_MULTI64) {
236
-                        $value = '(' . join(',', $value) . ')';
237
-                    } elseif ($attrtype == SPH_ATTR_TIMESTAMP) {
238
-                        $value = date('Y-m-d H:i:s', $value);
239
-                    }
240
-                    print ", $attrname=$value";
241
-                }
242
-                print PHP_EOL;
243
-                $n++;
244
-            }
245
-        }
246
-    }
52
+	$args = array();
53
+	foreach ($_SERVER['argv'] as $arg) {
54
+		$args[] = $arg;
55
+	}
56
+
57
+	$cl = new SphinxClient();
58
+
59
+	$q = '';
60
+	$sql = '';
61
+	$mode = SPH_MATCH_ALL;
62
+	$host = 'localhost';
63
+	$port = 9312;
64
+	$index = '*';
65
+	$groupby = '';
66
+	$groupsort = '@group desc';
67
+	$filter = 'group_id';
68
+	$filtervals = array();
69
+	$distinct = '';
70
+	$sortby = '';
71
+	$sortexpr = '';
72
+	$limit = 20;
73
+	$ranker = SPH_RANK_PROXIMITY_BM25;
74
+	$select = '';
75
+	$count = count($args);
76
+
77
+	for ($i = 0; $i < $count; $i++) {
78
+		switch ($args[$i]) {
79
+			case '-h':
80
+			case '--host':
81
+				$host = $args[++$i];
82
+				break;
83
+			case '-p':
84
+			case '--port':
85
+				$port = (int)$args[++$i];
86
+				break;
87
+			case '-i':
88
+			case '--index':
89
+				$index = $args[++$i];
90
+				break;
91
+			case '-s':
92
+			case '--sortby':
93
+				$sortby = $args[++$i];
94
+				$sortexpr = '';
95
+				break;
96
+			case '-S':
97
+			case '--sortexpr':
98
+				$sortexpr = $args[++$i];
99
+				$sortby = '';
100
+				break;
101
+			case '-a':
102
+			case '--any':
103
+				$mode = SPH_MATCH_ANY;
104
+				break;
105
+			case '-b':
106
+			case '--boolean':
107
+				$mode = SPH_MATCH_BOOLEAN;
108
+				break;
109
+			case '-e':
110
+			case '--extended':
111
+				$mode = SPH_MATCH_EXTENDED;
112
+				break;
113
+			case '-e2':
114
+				$mode = SPH_MATCH_EXTENDED2;
115
+				break;
116
+			case '-ph':
117
+			case '--phrase':
118
+				$mode = SPH_MATCH_PHRASE;
119
+				break;
120
+			case '-f':
121
+			case '--filter':
122
+				$filter = $args[++$i];
123
+				break;
124
+			case '-v':
125
+			case '--value':
126
+				$filtervals[] = $args[++$i];
127
+				break;
128
+			case '-g':
129
+			case '--groupby':
130
+				$groupby = $args[++$i];
131
+				break;
132
+			case '-gs':
133
+			case '--groupsort':
134
+				$groupsort = $args[++$i];
135
+				break;
136
+			case '-d':
137
+			case '--distinct':
138
+				$distinct = $args[++$i];
139
+				break;
140
+			case '-l':
141
+			case '--limit':
142
+				$limit = (int)$args[++$i];
143
+				break;
144
+			case '--select':
145
+				$select = $args[++$i];
146
+				break;
147
+			case '-fr':
148
+			case '--filterrange':
149
+				$cl->setFilterRange($args[++$i], $args[++$i], $args[++$i]);
150
+				break;
151
+			case '-r':
152
+				switch (strtolower($args[++$i])) {
153
+					case 'bm25':
154
+						$ranker = SPH_RANK_BM25;
155
+						break;
156
+					case 'none':
157
+						$ranker = SPH_RANK_NONE;
158
+						break;
159
+					case 'wordcount':
160
+						$ranker = SPH_RANK_WORDCOUNT;
161
+						break;
162
+					case 'fieldmask':
163
+						$ranker = SPH_RANK_FIELDMASK;
164
+						break;
165
+					case 'sph04':
166
+						$ranker = SPH_RANK_SPH04;
167
+						break;
168
+				}
169
+				break;
170
+			default:
171
+				$q .= $args[$i] . ' ';
172
+		}
173
+	}
174
+
175
+	////////////
176
+	// do query
177
+	////////////
178
+
179
+	$cl->setServer($host, $port);
180
+	$cl->setConnectTimeout(1);
181
+	$cl->setArrayResult(true);
182
+	$cl->setMatchMode($mode);
183
+	if (count($filtervals)) {
184
+		$cl->setFilter($filter, $filtervals);
185
+	}
186
+	if ($groupby) {
187
+		$cl->setGroupBy($groupby, SPH_GROUPBY_ATTR, $groupsort);
188
+	}
189
+	if ($sortby) {
190
+		$cl->setSortMode(SPH_SORT_EXTENDED, $sortby);
191
+	}
192
+	if ($sortexpr) {
193
+		$cl->setSortMode(SPH_SORT_EXPR, $sortexpr);
194
+	}
195
+	if ($distinct) {
196
+		$cl->setGroupDistinct($distinct);
197
+	}
198
+	if ($select) {
199
+		$cl->setSelect($select);
200
+	}
201
+	if ($limit) {
202
+		$cl->setLimits(0, $limit, ($limit > 1000) ? $limit : 1000);
203
+	}
204
+	$cl->setRankingMode($ranker);
205
+	$res = $cl->query($q, $index);
206
+
207
+	////////////////
208
+	// print me out
209
+	////////////////
210
+
211
+	if ($res === false) {
212
+		printf('Query failed: %s.' . PHP_EOL, $cl->getLastError());
213
+
214
+	} else {
215
+		if ($cl->getLastWarning()) {
216
+			printf('WARNING: %s' . PHP_EOL . PHP_EOL, $cl->getLastWarning());
217
+		}
218
+
219
+		print "Query '$q' retrieved {$res['total']} of {$res['total_found']} matches in {$res['time']} sec.\n";
220
+		print 'Query stats:' . PHP_EOL;
221
+		if (is_array($res['words'])) {
222
+			foreach ($res['words'] as $word => $info) {
223
+				print "    '$word' found {$info['hits']} times in {$info['docs']} documents\n";
224
+			}
225
+		}
226
+		print PHP_EOL;
227
+
228
+		if (is_array($res['matches'])) {
229
+			$n = 1;
230
+			print 'Matches:' . PHP_EOL;
231
+			foreach ($res['matches'] as $docinfo) {
232
+				print "$n. doc_id={$docinfo['id']}, weight={$docinfo['weight']}";
233
+				foreach ($res['attrs'] as $attrname => $attrtype) {
234
+					$value = $docinfo['attrs'][$attrname];
235
+					if ($attrtype == SPH_ATTR_MULTI || $attrtype == SPH_ATTR_MULTI64) {
236
+						$value = '(' . join(',', $value) . ')';
237
+					} elseif ($attrtype == SPH_ATTR_TIMESTAMP) {
238
+						$value = date('Y-m-d H:i:s', $value);
239
+					}
240
+					print ", $attrname=$value";
241
+				}
242
+				print PHP_EOL;
243
+				$n++;
244
+			}
245
+		}
246
+	}
247 247
 }
248 248
\ No newline at end of file
Please login to merge, or discard this patch.
Spacing   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -74,7 +74,7 @@  discard block
 block discarded – undo
74 74
     $select = '';
75 75
     $count = count($args);
76 76
 
77
-    for ($i = 0; $i < $count; $i++) {
77
+    for ($i = 0; $i<$count; $i++) {
78 78
         switch ($args[$i]) {
79 79
             case '-h':
80 80
             case '--host':
@@ -168,7 +168,7 @@  discard block
 block discarded – undo
168 168
                 }
169 169
                 break;
170 170
             default:
171
-                $q .= $args[$i] . ' ';
171
+                $q .= $args[$i].' ';
172 172
         }
173 173
     }
174 174
 
@@ -199,7 +199,7 @@  discard block
 block discarded – undo
199 199
         $cl->setSelect($select);
200 200
     }
201 201
     if ($limit) {
202
-        $cl->setLimits(0, $limit, ($limit > 1000) ? $limit : 1000);
202
+        $cl->setLimits(0, $limit, ($limit>1000) ? $limit : 1000);
203 203
     }
204 204
     $cl->setRankingMode($ranker);
205 205
     $res = $cl->query($q, $index);
@@ -208,16 +208,16 @@  discard block
 block discarded – undo
208 208
     // print me out
209 209
     ////////////////
210 210
 
211
-    if ($res === false) {
212
-        printf('Query failed: %s.' . PHP_EOL, $cl->getLastError());
211
+    if ($res===false) {
212
+        printf('Query failed: %s.'.PHP_EOL, $cl->getLastError());
213 213
 
214 214
     } else {
215 215
         if ($cl->getLastWarning()) {
216
-            printf('WARNING: %s' . PHP_EOL . PHP_EOL, $cl->getLastWarning());
216
+            printf('WARNING: %s'.PHP_EOL.PHP_EOL, $cl->getLastWarning());
217 217
         }
218 218
 
219 219
         print "Query '$q' retrieved {$res['total']} of {$res['total_found']} matches in {$res['time']} sec.\n";
220
-        print 'Query stats:' . PHP_EOL;
220
+        print 'Query stats:'.PHP_EOL;
221 221
         if (is_array($res['words'])) {
222 222
             foreach ($res['words'] as $word => $info) {
223 223
                 print "    '$word' found {$info['hits']} times in {$info['docs']} documents\n";
@@ -227,14 +227,14 @@  discard block
 block discarded – undo
227 227
 
228 228
         if (is_array($res['matches'])) {
229 229
             $n = 1;
230
-            print 'Matches:' . PHP_EOL;
230
+            print 'Matches:'.PHP_EOL;
231 231
             foreach ($res['matches'] as $docinfo) {
232 232
                 print "$n. doc_id={$docinfo['id']}, weight={$docinfo['weight']}";
233 233
                 foreach ($res['attrs'] as $attrname => $attrtype) {
234 234
                     $value = $docinfo['attrs'][$attrname];
235
-                    if ($attrtype == SPH_ATTR_MULTI || $attrtype == SPH_ATTR_MULTI64) {
236
-                        $value = '(' . join(',', $value) . ')';
237
-                    } elseif ($attrtype == SPH_ATTR_TIMESTAMP) {
235
+                    if ($attrtype==SPH_ATTR_MULTI || $attrtype==SPH_ATTR_MULTI64) {
236
+                        $value = '('.join(',', $value).')';
237
+                    } elseif ($attrtype==SPH_ATTR_TIMESTAMP) {
238 238
                         $value = date('Y-m-d H:i:s', $value);
239 239
                     }
240 240
                     print ", $attrname=$value";
Please login to merge, or discard this patch.