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