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