Passed
Branch master (a3c0d0)
by Cody
02:54
created
plugins/af_comics/filters/af_comics_twp.php 1 patch
Indentation   +17 added lines, -17 removed lines patch added patch discarded remove patch
@@ -1,29 +1,29 @@
 block discarded – undo
1 1
 <?php
2 2
 class Af_Comics_Twp extends Af_ComicFilter {
3 3
 
4
-	public function supported() {
5
-		return array("Three Word Phrase");
6
-	}
4
+    public function supported() {
5
+        return array("Three Word Phrase");
6
+    }
7 7
 
8
-	public function process(&$article) {
8
+    public function process(&$article) {
9 9
 
10
-		if (strpos($article["link"], "threewordphrase.com") !== FALSE) {
10
+        if (strpos($article["link"], "threewordphrase.com") !== FALSE) {
11 11
 
12
-				$doc = new DOMDocument();
12
+                $doc = new DOMDocument();
13 13
 
14
-				if (@$doc->loadHTML(fetch_file_contents($article["link"]))) {
15
-					$xpath = new DOMXpath($doc);
14
+                if (@$doc->loadHTML(fetch_file_contents($article["link"]))) {
15
+                    $xpath = new DOMXpath($doc);
16 16
 
17
-					$basenode = $xpath->query("//td/center/img")->item(0);
17
+                    $basenode = $xpath->query("//td/center/img")->item(0);
18 18
 
19
-					if ($basenode) {
20
-						$article["content"] = $doc->saveHTML($basenode);
21
-					}
22
-				}
19
+                    if ($basenode) {
20
+                        $article["content"] = $doc->saveHTML($basenode);
21
+                    }
22
+                }
23 23
 
24
-			return true;
25
-		}
24
+            return true;
25
+        }
26 26
 
27
-		return false;
28
-	}
27
+        return false;
28
+    }
29 29
 }
Please login to merge, or discard this patch.
plugins/af_comics/filters/af_comics_dilbert.php 1 patch
Indentation   +50 added lines, -50 removed lines patch added patch discarded remove patch
@@ -2,72 +2,72 @@
 block discarded – undo
2 2
 
3 3
 class Af_Comics_Dilbert extends Af_ComicFilter {
4 4
 
5
-	public function supported() {
6
-		return array("Dilbert");
7
-	}
5
+    public function supported() {
6
+        return array("Dilbert");
7
+    }
8 8
 
9
-	public function process(&$article) {
10
-		if (strpos($article["link"], "dilbert.com") !== FALSE ||
11
-			strpos($article["link"], "/DilbertDailyStrip") !== FALSE) {
9
+    public function process(&$article) {
10
+        if (strpos($article["link"], "dilbert.com") !== FALSE ||
11
+            strpos($article["link"], "/DilbertDailyStrip") !== FALSE) {
12 12
 
13
-				$res = fetch_file_contents($article["link"], false, false, false,
14
-					 false, false, 0,
15
-					 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0");
13
+                $res = fetch_file_contents($article["link"], false, false, false,
14
+                        false, false, 0,
15
+                        "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0");
16 16
 
17
-				global $fetch_last_error_content;
17
+                global $fetch_last_error_content;
18 18
 
19
-				if (!$res && $fetch_last_error_content)
20
-					$res = $fetch_last_error_content;
19
+                if (!$res && $fetch_last_error_content)
20
+                    $res = $fetch_last_error_content;
21 21
 
22
-				$doc = new DOMDocument();
22
+                $doc = new DOMDocument();
23 23
 
24
-				if (@$doc->loadHTML($res)) {
25
-					$xpath = new DOMXPath($doc);
24
+                if (@$doc->loadHTML($res)) {
25
+                    $xpath = new DOMXPath($doc);
26 26
 
27
-					// Get the image container
28
-					$basenode = $xpath->query('(//div[@class="img-comic-container"]/a[@class="img-comic-link"])')->item(0);
27
+                    // Get the image container
28
+                    $basenode = $xpath->query('(//div[@class="img-comic-container"]/a[@class="img-comic-link"])')->item(0);
29 29
 
30
-					// Get the comic title
31
-					$comic_title = $xpath->query('(//span[@class="comic-title-name"])')->item(0)->textContent;
30
+                    // Get the comic title
31
+                    $comic_title = $xpath->query('(//span[@class="comic-title-name"])')->item(0)->textContent;
32 32
 
33
-					// Get tags from the article
34
-					$matches = $xpath->query('(//p[contains(@class, "comic-tags")][1]//a)');
35
-					$tags = array();
33
+                    // Get tags from the article
34
+                    $matches = $xpath->query('(//p[contains(@class, "comic-tags")][1]//a)');
35
+                    $tags = array();
36 36
 
37
-					foreach ($matches as $tag) {
38
-						// Only strings starting with a number sign are considered tags
39
-						if ( substr($tag->textContent, 0, 1) == '#' ) {
40
-							$tags[] = mb_strtolower(substr($tag->textContent, 1), 'utf-8');
41
-						}
42
-					}
37
+                    foreach ($matches as $tag) {
38
+                        // Only strings starting with a number sign are considered tags
39
+                        if ( substr($tag->textContent, 0, 1) == '#' ) {
40
+                            $tags[] = mb_strtolower(substr($tag->textContent, 1), 'utf-8');
41
+                        }
42
+                    }
43 43
 
44
-					// Get the current comics transcript and set it
45
-					// as the title so it will be visible on mousover
46
-					$transcript = $xpath->query('(//div[starts-with(@id, "js-toggle-transcript-")]//p)')->item(0);
47
-					if ($transcript) {
48
-						$basenode->setAttribute("title", $transcript->textContent);
49
-					}
44
+                    // Get the current comics transcript and set it
45
+                    // as the title so it will be visible on mousover
46
+                    $transcript = $xpath->query('(//div[starts-with(@id, "js-toggle-transcript-")]//p)')->item(0);
47
+                    if ($transcript) {
48
+                        $basenode->setAttribute("title", $transcript->textContent);
49
+                    }
50 50
 
51
-					if ($basenode) {
52
-						$article["content"] = $doc->saveHTML($basenode);
53
-					}
51
+                    if ($basenode) {
52
+                        $article["content"] = $doc->saveHTML($basenode);
53
+                    }
54 54
 
55
-					// Add comic title to article type if not empty (mostly Sunday strips)
56
-					if ($comic_title) {
57
-						$article["title"] = $article["title"] . " - " . $comic_title;
58
-					}
55
+                    // Add comic title to article type if not empty (mostly Sunday strips)
56
+                    if ($comic_title) {
57
+                        $article["title"] = $article["title"] . " - " . $comic_title;
58
+                    }
59 59
 
60
-					if (!empty($tags)) {
61
-						// Ignore existing tags and just replace them all
62
-						$article["tags"] = array_unique($tags);
63
-					}
60
+                    if (!empty($tags)) {
61
+                        // Ignore existing tags and just replace them all
62
+                        $article["tags"] = array_unique($tags);
63
+                    }
64 64
 
65
-				}
65
+                }
66 66
 
67
-			return true;
68
-		}
67
+            return true;
68
+        }
69 69
 
70
-		return false;
71
-	}
70
+        return false;
71
+    }
72 72
 }
73 73
 ?>
Please login to merge, or discard this patch.
plugins/af_comics/init.php 1 patch
Indentation   +131 added lines, -131 removed lines patch added patch discarded remove patch
@@ -1,187 +1,187 @@
 block discarded – undo
1 1
 <?php
2 2
 class Af_Comics extends Plugin {
3 3
 
4
-	private $host;
5
-	private $filters = array();
4
+    private $host;
5
+    private $filters = array();
6 6
 
7
-	public function about() {
8
-		return array(2.0,
9
-			"Fixes RSS feeds of assorted comic strips",
10
-			"fox");
11
-	}
7
+    public function about() {
8
+        return array(2.0,
9
+            "Fixes RSS feeds of assorted comic strips",
10
+            "fox");
11
+    }
12 12
 
13
-	public function init($host) {
14
-		$this->host = $host;
13
+    public function init($host) {
14
+        $this->host = $host;
15 15
 
16
-		$host->add_hook($host::HOOK_FETCH_FEED, $this);
17
-		$host->add_hook($host::HOOK_FEED_BASIC_INFO, $this);
18
-		$host->add_hook($host::HOOK_SUBSCRIBE_FEED, $this);
19
-		$host->add_hook($host::HOOK_ARTICLE_FILTER, $this);
20
-		$host->add_hook($host::HOOK_PREFS_TAB, $this);
16
+        $host->add_hook($host::HOOK_FETCH_FEED, $this);
17
+        $host->add_hook($host::HOOK_FEED_BASIC_INFO, $this);
18
+        $host->add_hook($host::HOOK_SUBSCRIBE_FEED, $this);
19
+        $host->add_hook($host::HOOK_ARTICLE_FILTER, $this);
20
+        $host->add_hook($host::HOOK_PREFS_TAB, $this);
21 21
 
22
-		require_once __DIR__ . "/filter_base.php";
22
+        require_once __DIR__ . "/filter_base.php";
23 23
 
24
-		$filters = array_merge(glob(__DIR__ . "/filters.local/*.php"), glob(__DIR__ . "/filters/*.php"));
25
-		$names = [];
24
+        $filters = array_merge(glob(__DIR__ . "/filters.local/*.php"), glob(__DIR__ . "/filters/*.php"));
25
+        $names = [];
26 26
 
27
-		foreach ($filters as $file) {
28
-			$filter_name = preg_replace("/\..*$/", "", basename($file));
27
+        foreach ($filters as $file) {
28
+            $filter_name = preg_replace("/\..*$/", "", basename($file));
29 29
 
30
-			if (array_search($filter_name, $names) === FALSE) {
31
-				if (!class_exists($filter_name)) {
32
-					require_once $file;
33
-				}
30
+            if (array_search($filter_name, $names) === FALSE) {
31
+                if (!class_exists($filter_name)) {
32
+                    require_once $file;
33
+                }
34 34
 
35
-				array_push($names, $filter_name);
35
+                array_push($names, $filter_name);
36 36
 
37
-				$filter = new $filter_name();
37
+                $filter = new $filter_name();
38 38
 
39
-				if (is_subclass_of($filter, "Af_ComicFilter")) {
40
-					array_push($this->filters, $filter);
41
-					array_push($names, $filter_name);
42
-				}
43
-			}
44
-		}
45
-	}
39
+                if (is_subclass_of($filter, "Af_ComicFilter")) {
40
+                    array_push($this->filters, $filter);
41
+                    array_push($names, $filter_name);
42
+                }
43
+            }
44
+        }
45
+    }
46 46
 
47
-	public function hook_prefs_tab($args) {
48
-		if ($args != "prefFeeds") return;
47
+    public function hook_prefs_tab($args) {
48
+        if ($args != "prefFeeds") return;
49 49
 
50
-		print "<div dojoType=\"dijit.layout.AccordionPane\"
50
+        print "<div dojoType=\"dijit.layout.AccordionPane\"
51 51
 			title=\"<i class='material-icons'>photo</i> ".__('Feeds supported by af_comics')."\">";
52 52
 
53
-		print "<p>" . __("The following comics are currently supported:") . "</p>";
53
+        print "<p>" . __("The following comics are currently supported:") . "</p>";
54 54
 
55
-		$comics = array("GoComics");
55
+        $comics = array("GoComics");
56 56
 
57
-		foreach ($this->filters as $f) {
58
-			foreach ($f->supported() as $comic) {
59
-				array_push($comics, $comic);
60
-			}
61
-		}
57
+        foreach ($this->filters as $f) {
58
+            foreach ($f->supported() as $comic) {
59
+                array_push($comics, $comic);
60
+            }
61
+        }
62 62
 
63
-		asort($comics);
63
+        asort($comics);
64 64
 
65
-		print "<ul class='panel panel-scrollable list list-unstyled'>";
66
-		foreach ($comics as $comic) {
67
-			print "<li>$comic</li>";
68
-		}
69
-		print "</ul>";
65
+        print "<ul class='panel panel-scrollable list list-unstyled'>";
66
+        foreach ($comics as $comic) {
67
+            print "<li>$comic</li>";
68
+        }
69
+        print "</ul>";
70 70
 
71
-		print "<p>".__("To subscribe to GoComics use the comic's regular web page as the feed URL (e.g. for the <em>Garfield</em> comic use <code>http://www.gocomics.com/garfield</code>).")."</p>";
71
+        print "<p>".__("To subscribe to GoComics use the comic's regular web page as the feed URL (e.g. for the <em>Garfield</em> comic use <code>http://www.gocomics.com/garfield</code>).")."</p>";
72 72
 
73
-		print "<p>".__('Drop any updated filters into <code>filters.local</code> in plugin directory.')."</p>";
73
+        print "<p>".__('Drop any updated filters into <code>filters.local</code> in plugin directory.')."</p>";
74 74
 
75
-		print "</div>";
76
-	}
75
+        print "</div>";
76
+    }
77 77
 
78
-	public function hook_article_filter($article) {
79
-		foreach ($this->filters as $f) {
80
-			if ($f->process($article))
81
-				break;
82
-		}
78
+    public function hook_article_filter($article) {
79
+        foreach ($this->filters as $f) {
80
+            if ($f->process($article))
81
+                break;
82
+        }
83 83
 
84
-		return $article;
85
-	}
84
+        return $article;
85
+    }
86 86
 
87
-	// GoComics dropped feed support so it needs to be handled when fetching the feed.
88
-	/**
89
-	 * @SuppressWarnings(PHPMD.UnusedFormalParameter)
90
-	 */
91
-	public function hook_fetch_feed($feed_data, $fetch_url, $owner_uid, $feed, $last_article_timestamp, $auth_login, $auth_pass) {
92
-		if ($auth_login || $auth_pass)
93
-			return $feed_data;
87
+    // GoComics dropped feed support so it needs to be handled when fetching the feed.
88
+    /**
89
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
90
+     */
91
+    public function hook_fetch_feed($feed_data, $fetch_url, $owner_uid, $feed, $last_article_timestamp, $auth_login, $auth_pass) {
92
+        if ($auth_login || $auth_pass)
93
+            return $feed_data;
94 94
 
95
-		if (preg_match('#^https?://(?:feeds\.feedburner\.com/uclick|www\.gocomics\.com)/([-a-z0-9]+)$#i', $fetch_url, $comic)) {
96
-			$site_url = 'https://www.gocomics.com/' . $comic[1];
95
+        if (preg_match('#^https?://(?:feeds\.feedburner\.com/uclick|www\.gocomics\.com)/([-a-z0-9]+)$#i', $fetch_url, $comic)) {
96
+            $site_url = 'https://www.gocomics.com/' . $comic[1];
97 97
 
98
-			$article_link = $site_url . date('/Y/m/d');
98
+            $article_link = $site_url . date('/Y/m/d');
99 99
 
100
-			$body = fetch_file_contents(array('url' => $article_link, 'type' => 'text/html', 'followlocation' => false));
100
+            $body = fetch_file_contents(array('url' => $article_link, 'type' => 'text/html', 'followlocation' => false));
101 101
 
102
-			require_once 'lib/MiniTemplator.class.php';
102
+            require_once 'lib/MiniTemplator.class.php';
103 103
 
104
-			$feed_title = htmlspecialchars($comic[1]);
105
-			$site_url = htmlspecialchars($site_url);
106
-			$article_link = htmlspecialchars($article_link);
104
+            $feed_title = htmlspecialchars($comic[1]);
105
+            $site_url = htmlspecialchars($site_url);
106
+            $article_link = htmlspecialchars($article_link);
107 107
 
108
-			$tpl = new MiniTemplator();
108
+            $tpl = new MiniTemplator();
109 109
 
110
-			$tpl->readTemplateFromFile('templates/generated_feed.txt');
110
+            $tpl->readTemplateFromFile('templates/generated_feed.txt');
111 111
 
112
-			$tpl->setVariable('FEED_TITLE', $feed_title, true);
113
-			$tpl->setVariable('VERSION', get_version(), true);
114
-			$tpl->setVariable('FEED_URL', htmlspecialchars($fetch_url), true);
115
-			$tpl->setVariable('SELF_URL', $site_url, true);
112
+            $tpl->setVariable('FEED_TITLE', $feed_title, true);
113
+            $tpl->setVariable('VERSION', get_version(), true);
114
+            $tpl->setVariable('FEED_URL', htmlspecialchars($fetch_url), true);
115
+            $tpl->setVariable('SELF_URL', $site_url, true);
116 116
 
117
-			if ($body) {
118
-				$doc = new DOMDocument();
117
+            if ($body) {
118
+                $doc = new DOMDocument();
119 119
 
120
-				if (@$doc->loadHTML($body)) {
121
-					$xpath = new DOMXPath($doc);
120
+                if (@$doc->loadHTML($body)) {
121
+                    $xpath = new DOMXPath($doc);
122 122
 
123
-					$node = $xpath->query('//picture[contains(@class, "item-comic-image")]/img')->item(0);
123
+                    $node = $xpath->query('//picture[contains(@class, "item-comic-image")]/img')->item(0);
124 124
 
125
-					if ($node) {
126
-						$title = $xpath->query('//h1')->item(0);
125
+                    if ($node) {
126
+                        $title = $xpath->query('//h1')->item(0);
127 127
 
128
-						if ($title) {
129
-							$title = clean(trim($title->nodeValue));
130
-						} else {
131
-							$title = date('l, F d, Y');
132
-						}
128
+                        if ($title) {
129
+                            $title = clean(trim($title->nodeValue));
130
+                        } else {
131
+                            $title = date('l, F d, Y');
132
+                        }
133 133
 
134
-						foreach (['srcset', 'sizes', 'data-srcset', 'width'] as $attr ) {
135
-							$node->removeAttribute($attr);
136
-						}
134
+                        foreach (['srcset', 'sizes', 'data-srcset', 'width'] as $attr ) {
135
+                            $node->removeAttribute($attr);
136
+                        }
137 137
 
138
-						$tpl->setVariable('ARTICLE_ID', $article_link, true);
139
-						$tpl->setVariable('ARTICLE_LINK', $article_link, true);
140
-						$tpl->setVariable('ARTICLE_UPDATED_ATOM', date('c', mktime(11, 0, 0)), true);
141
-						$tpl->setVariable('ARTICLE_TITLE', htmlspecialchars($title), true);
142
-						$tpl->setVariable('ARTICLE_EXCERPT', '', true);
143
-						$tpl->setVariable('ARTICLE_CONTENT', $doc->saveHTML($node), true);
138
+                        $tpl->setVariable('ARTICLE_ID', $article_link, true);
139
+                        $tpl->setVariable('ARTICLE_LINK', $article_link, true);
140
+                        $tpl->setVariable('ARTICLE_UPDATED_ATOM', date('c', mktime(11, 0, 0)), true);
141
+                        $tpl->setVariable('ARTICLE_TITLE', htmlspecialchars($title), true);
142
+                        $tpl->setVariable('ARTICLE_EXCERPT', '', true);
143
+                        $tpl->setVariable('ARTICLE_CONTENT', $doc->saveHTML($node), true);
144 144
 
145
-						$tpl->setVariable('ARTICLE_AUTHOR', '', true);
146
-						$tpl->setVariable('ARTICLE_SOURCE_LINK', $site_url, true);
147
-						$tpl->setVariable('ARTICLE_SOURCE_TITLE', $feed_title, true);
145
+                        $tpl->setVariable('ARTICLE_AUTHOR', '', true);
146
+                        $tpl->setVariable('ARTICLE_SOURCE_LINK', $site_url, true);
147
+                        $tpl->setVariable('ARTICLE_SOURCE_TITLE', $feed_title, true);
148 148
 
149
-						$tpl->addBlock('entry');
150
-					}
151
-				}
152
-			}
149
+                        $tpl->addBlock('entry');
150
+                    }
151
+                }
152
+            }
153 153
 
154
-			$tpl->addBlock('feed');
154
+            $tpl->addBlock('feed');
155 155
 
156
-			if ($tpl->generateOutputToString($tmp_data))
157
-				$feed_data = $tmp_data;
158
-		}
156
+            if ($tpl->generateOutputToString($tmp_data))
157
+                $feed_data = $tmp_data;
158
+        }
159 159
 
160
-		return $feed_data;
161
-	}
160
+        return $feed_data;
161
+    }
162 162
 
163
-	public function hook_subscribe_feed($contents, $url, $auth_login, $auth_pass) {
164
-		if ($auth_login || $auth_pass)
165
-			return $contents;
163
+    public function hook_subscribe_feed($contents, $url, $auth_login, $auth_pass) {
164
+        if ($auth_login || $auth_pass)
165
+            return $contents;
166 166
 
167
-		if (preg_match('#^https?://www\.gocomics\.com/([-a-z0-9]+)$#i', $url))
168
-			return '<?xml version="1.0" encoding="utf-8"?>'; // Get is_html() to return false.
167
+        if (preg_match('#^https?://www\.gocomics\.com/([-a-z0-9]+)$#i', $url))
168
+            return '<?xml version="1.0" encoding="utf-8"?>'; // Get is_html() to return false.
169 169
 
170
-		return $contents;
171
-	}
170
+        return $contents;
171
+    }
172 172
 
173
-	public function hook_feed_basic_info($basic_info, $fetch_url, $owner_uid, $feed, $auth_login, $auth_pass) {
174
-		if ($auth_login || $auth_pass)
175
-			return $basic_info;
173
+    public function hook_feed_basic_info($basic_info, $fetch_url, $owner_uid, $feed, $auth_login, $auth_pass) {
174
+        if ($auth_login || $auth_pass)
175
+            return $basic_info;
176 176
 
177
-		if (preg_match('#^https?://www\.gocomics\.com/([-a-z0-9]+)$#i', $fetch_url, $matches))
178
-			$basic_info = array('title' => ucfirst($matches[1]), 'site_url' => $matches[0]);
177
+        if (preg_match('#^https?://www\.gocomics\.com/([-a-z0-9]+)$#i', $fetch_url, $matches))
178
+            $basic_info = array('title' => ucfirst($matches[1]), 'site_url' => $matches[0]);
179 179
 
180
-		return $basic_info;
181
-	}
180
+        return $basic_info;
181
+    }
182 182
 
183
-	public function api_version() {
184
-		return 2;
185
-	}
183
+    public function api_version() {
184
+        return 2;
185
+    }
186 186
 
187 187
 }
Please login to merge, or discard this patch.
plugins/af_proxy_http/init.php 1 patch
Indentation   +180 added lines, -180 removed lines patch added patch discarded remove patch
@@ -1,219 +1,219 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 class Af_Proxy_Http extends Plugin {
3 3
 
4
-	/* @var PluginHost $host */
5
-	private $host;
4
+    /* @var PluginHost $host */
5
+    private $host;
6 6
 
7
-	/* @var DiskCache $cache */
8
-	private $cache;
7
+    /* @var DiskCache $cache */
8
+    private $cache;
9 9
 
10
-	public function about() {
11
-		return array(1.0,
12
-			"Loads media served over plain HTTP via built-in secure proxy",
13
-			"fox");
14
-	}
10
+    public function about() {
11
+        return array(1.0,
12
+            "Loads media served over plain HTTP via built-in secure proxy",
13
+            "fox");
14
+    }
15 15
 
16
-	private $ssl_known_whitelist = "imgur.com gfycat.com i.reddituploads.com pbs.twimg.com i.redd.it i.sli.mg media.tumblr.com";
16
+    private $ssl_known_whitelist = "imgur.com gfycat.com i.reddituploads.com pbs.twimg.com i.redd.it i.sli.mg media.tumblr.com";
17 17
 
18
-	public function is_public_method($method) {
19
-		return $method === "imgproxy";
20
-	}
18
+    public function is_public_method($method) {
19
+        return $method === "imgproxy";
20
+    }
21 21
 
22
-	public function init($host) {
23
-		$this->host = $host;
24
-		$this->cache = new DiskCache("images");
22
+    public function init($host) {
23
+        $this->host = $host;
24
+        $this->cache = new DiskCache("images");
25 25
 
26
-		$host->add_hook($host::HOOK_RENDER_ARTICLE, $this, 150);
27
-		$host->add_hook($host::HOOK_RENDER_ARTICLE_CDM, $this, 150);
28
-		$host->add_hook($host::HOOK_ENCLOSURE_ENTRY, $this);
26
+        $host->add_hook($host::HOOK_RENDER_ARTICLE, $this, 150);
27
+        $host->add_hook($host::HOOK_RENDER_ARTICLE_CDM, $this, 150);
28
+        $host->add_hook($host::HOOK_ENCLOSURE_ENTRY, $this);
29 29
 
30
-		$host->add_hook($host::HOOK_PREFS_TAB, $this);
31
-	}
30
+        $host->add_hook($host::HOOK_PREFS_TAB, $this);
31
+    }
32 32
 
33
-	public function hook_enclosure_entry($enc) {
34
-		if (preg_match("/image/", $enc["content_type"])) {
35
-			$proxy_all = $this->host->get($this, "proxy_all");
33
+    public function hook_enclosure_entry($enc) {
34
+        if (preg_match("/image/", $enc["content_type"])) {
35
+            $proxy_all = $this->host->get($this, "proxy_all");
36 36
 
37
-			$enc["content_url"] = $this->rewrite_url_if_needed($enc["content_url"], $proxy_all);
38
-		}
37
+            $enc["content_url"] = $this->rewrite_url_if_needed($enc["content_url"], $proxy_all);
38
+        }
39 39
 
40
-		return $enc;
41
-	}
40
+        return $enc;
41
+    }
42 42
 
43
-	public function hook_render_article($article) {
44
-		return $this->hook_render_article_cdm($article);
45
-	}
43
+    public function hook_render_article($article) {
44
+        return $this->hook_render_article_cdm($article);
45
+    }
46 46
 
47
-	public function imgproxy() {
47
+    public function imgproxy() {
48 48
 
49
-		$url = rewrite_relative_url(get_self_url_prefix(), $_REQUEST["url"]);
49
+        $url = rewrite_relative_url(get_self_url_prefix(), $_REQUEST["url"]);
50 50
 
51
-		// called without user context, let's just redirect to original URL
52
-		if (!$_SESSION["uid"]) {
53
-			header("Location: $url");
54
-			return;
55
-		}
51
+        // called without user context, let's just redirect to original URL
52
+        if (!$_SESSION["uid"]) {
53
+            header("Location: $url");
54
+            return;
55
+        }
56 56
 
57
-		$local_filename = sha1($url);
57
+        $local_filename = sha1($url);
58 58
 
59
-		if ($this->cache->exists($local_filename)) {
60
-			header("Location: " . $this->cache->getUrl($local_filename));
61
-			return;
62
-			//$this->cache->send($local_filename);
63
-		} else {
64
-			$data = fetch_file_contents(["url" => $url, "max_size" => MAX_CACHE_FILE_SIZE]);
59
+        if ($this->cache->exists($local_filename)) {
60
+            header("Location: " . $this->cache->getUrl($local_filename));
61
+            return;
62
+            //$this->cache->send($local_filename);
63
+        } else {
64
+            $data = fetch_file_contents(["url" => $url, "max_size" => MAX_CACHE_FILE_SIZE]);
65 65
 
66
-			if ($data) {
66
+            if ($data) {
67 67
 
68
-				$disable_cache = $this->host->get($this, "disable_cache");
68
+                $disable_cache = $this->host->get($this, "disable_cache");
69 69
 
70
-				if (!$disable_cache) {
71
-					if ($this->cache->put($local_filename, $data)) {
72
-						header("Location: " . $this->cache->getUrl($local_filename));
73
-						return;
74
-					}
75
-				}
70
+                if (!$disable_cache) {
71
+                    if ($this->cache->put($local_filename, $data)) {
72
+                        header("Location: " . $this->cache->getUrl($local_filename));
73
+                        return;
74
+                    }
75
+                }
76 76
 
77
-				print $data;
78
-			} else {
79
-				global $fetch_last_error;
80
-				global $fetch_last_error_code;
81
-				global $fetch_last_error_content;
77
+                print $data;
78
+            } else {
79
+                global $fetch_last_error;
80
+                global $fetch_last_error_code;
81
+                global $fetch_last_error_content;
82 82
 
83
-				if (function_exists("imagecreate") && !isset($_REQUEST["text"])) {
84
-					$img = imagecreate(450, 75);
83
+                if (function_exists("imagecreate") && !isset($_REQUEST["text"])) {
84
+                    $img = imagecreate(450, 75);
85 85
 
86
-					/*$bg =*/ imagecolorallocate($img, 255, 255, 255);
87
-					$textcolor = imagecolorallocate($img, 255, 0, 0);
86
+                    /*$bg =*/ imagecolorallocate($img, 255, 255, 255);
87
+                    $textcolor = imagecolorallocate($img, 255, 0, 0);
88 88
 
89
-					imagerectangle($img, 0, 0, 450-1, 75-1, $textcolor);
89
+                    imagerectangle($img, 0, 0, 450-1, 75-1, $textcolor);
90 90
 
91
-					imagestring($img, 5, 5, 5, "Proxy request failed", $textcolor);
92
-					imagestring($img, 5, 5, 30, truncate_middle($url, 46, "..."), $textcolor);
93
-					imagestring($img, 5, 5, 55, "HTTP Code: $fetch_last_error_code", $textcolor);
91
+                    imagestring($img, 5, 5, 5, "Proxy request failed", $textcolor);
92
+                    imagestring($img, 5, 5, 30, truncate_middle($url, 46, "..."), $textcolor);
93
+                    imagestring($img, 5, 5, 55, "HTTP Code: $fetch_last_error_code", $textcolor);
94 94
 
95
-					header("Content-type: image/png");
96
-					print imagepng($img);
97
-					imagedestroy($img);
95
+                    header("Content-type: image/png");
96
+                    print imagepng($img);
97
+                    imagedestroy($img);
98 98
 
99
-				} else {
100
-					header("Content-type: text/html");
99
+                } else {
100
+                    header("Content-type: text/html");
101 101
 
102
-					http_response_code(400);
102
+                    http_response_code(400);
103 103
 
104
-					print "<h1>Proxy request failed.</h1>";
105
-					print "<p>Fetch error $fetch_last_error ($fetch_last_error_code)</p>";
106
-					print "<p>URL: $url</p>";
107
-					print "<textarea cols='80' rows='25'>" . htmlspecialchars($fetch_last_error_content) . "</textarea>";
108
-				}
109
-			}
110
-		}
111
-	}
104
+                    print "<h1>Proxy request failed.</h1>";
105
+                    print "<p>Fetch error $fetch_last_error ($fetch_last_error_code)</p>";
106
+                    print "<p>URL: $url</p>";
107
+                    print "<textarea cols='80' rows='25'>" . htmlspecialchars($fetch_last_error_content) . "</textarea>";
108
+                }
109
+            }
110
+        }
111
+    }
112 112
 
113
-	private function rewrite_url_if_needed($url, $all_remote = false) {
114
-		/* we don't need to handle URLs where local cache already exists, tt-rss rewrites those automatically */
115
-		if (!$this->cache->exists(sha1($url))) {
113
+    private function rewrite_url_if_needed($url, $all_remote = false) {
114
+        /* we don't need to handle URLs where local cache already exists, tt-rss rewrites those automatically */
115
+        if (!$this->cache->exists(sha1($url))) {
116 116
 
117
-			$scheme = parse_url($url, PHP_URL_SCHEME);
117
+            $scheme = parse_url($url, PHP_URL_SCHEME);
118 118
 
119
-			if ($all_remote) {
120
-				$host = parse_url($url, PHP_URL_HOST);
121
-				$self_host = parse_url(get_self_url_prefix(), PHP_URL_HOST);
119
+            if ($all_remote) {
120
+                $host = parse_url($url, PHP_URL_HOST);
121
+                $self_host = parse_url(get_self_url_prefix(), PHP_URL_HOST);
122 122
 
123
-				$is_remote = $host != $self_host;
124
-			} else {
125
-				$is_remote = false;
126
-			}
123
+                $is_remote = $host != $self_host;
124
+            } else {
125
+                $is_remote = false;
126
+            }
127 127
 
128
-			if (($scheme != 'https' && $scheme != "") || $is_remote) {
129
-				if (strpos($url, "data:") !== 0) {
130
-					$parts = parse_url($url);
131
-
132
-					foreach (explode(" " , $this->ssl_known_whitelist) as $host) {
133
-						if (substr(strtolower($parts['host']), -strlen($host)) === strtolower($host)) {
134
-							$parts['scheme'] = 'https';
135
-							$url = build_url($parts);
136
-							if ($all_remote && $is_remote) {
137
-								break;
138
-							} else {
139
-								return $url;
140
-							}
141
-						}
142
-					}
128
+            if (($scheme != 'https' && $scheme != "") || $is_remote) {
129
+                if (strpos($url, "data:") !== 0) {
130
+                    $parts = parse_url($url);
143 131
 
144
-					return $this->host->get_public_method_url($this, "imgproxy", ["url" => $url]);
145
-				}
146
-			}
147
-		}
132
+                    foreach (explode(" " , $this->ssl_known_whitelist) as $host) {
133
+                        if (substr(strtolower($parts['host']), -strlen($host)) === strtolower($host)) {
134
+                            $parts['scheme'] = 'https';
135
+                            $url = build_url($parts);
136
+                            if ($all_remote && $is_remote) {
137
+                                break;
138
+                            } else {
139
+                                return $url;
140
+                            }
141
+                        }
142
+                    }
148 143
 
149
-		return $url;
150
-	}
144
+                    return $this->host->get_public_method_url($this, "imgproxy", ["url" => $url]);
145
+                }
146
+            }
147
+        }
151 148
 
152
-	/**
153
-	 * @SuppressWarnings(PHPMD.UnusedFormalParameter)
154
-	 */
155
-	public function hook_render_article_cdm($article, $api_mode = false) {
149
+        return $url;
150
+    }
156 151
 
157
-		$need_saving = false;
158
-		$proxy_all = $this->host->get($this, "proxy_all");
152
+    /**
153
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
154
+     */
155
+    public function hook_render_article_cdm($article, $api_mode = false) {
159 156
 
160
-		$doc = new DOMDocument();
161
-		if (@$doc->loadHTML('<?xml encoding="UTF-8">' . $article["content"])) {
162
-			$xpath = new DOMXPath($doc);
163
-			$imgs = $xpath->query("//img[@src]");
157
+        $need_saving = false;
158
+        $proxy_all = $this->host->get($this, "proxy_all");
164 159
 
165
-			foreach ($imgs as $img) {
166
-				$new_src = $this->rewrite_url_if_needed($img->getAttribute("src"), $proxy_all);
160
+        $doc = new DOMDocument();
161
+        if (@$doc->loadHTML('<?xml encoding="UTF-8">' . $article["content"])) {
162
+            $xpath = new DOMXPath($doc);
163
+            $imgs = $xpath->query("//img[@src]");
167 164
 
168
-				if ($new_src != $img->getAttribute("src")) {
169
-					$img->setAttribute("src", $new_src);
170
-					$img->removeAttribute("srcset");
165
+            foreach ($imgs as $img) {
166
+                $new_src = $this->rewrite_url_if_needed($img->getAttribute("src"), $proxy_all);
171 167
 
172
-					$need_saving = true;
173
-				}
174
-			}
168
+                if ($new_src != $img->getAttribute("src")) {
169
+                    $img->setAttribute("src", $new_src);
170
+                    $img->removeAttribute("srcset");
175 171
 
176
-			$vids = $xpath->query("(//video|//picture)");
172
+                    $need_saving = true;
173
+                }
174
+            }
177 175
 
178
-			foreach ($vids as $vid) {
179
-				if ($vid->hasAttribute("poster")) {
180
-					$new_src = $this->rewrite_url_if_needed($vid->getAttribute("poster"), $proxy_all);
176
+            $vids = $xpath->query("(//video|//picture)");
181 177
 
182
-					if ($new_src != $vid->getAttribute("poster")) {
183
-						$vid->setAttribute("poster", $new_src);
178
+            foreach ($vids as $vid) {
179
+                if ($vid->hasAttribute("poster")) {
180
+                    $new_src = $this->rewrite_url_if_needed($vid->getAttribute("poster"), $proxy_all);
184 181
 
185
-						$need_saving = true;
186
-					}
187
-				}
182
+                    if ($new_src != $vid->getAttribute("poster")) {
183
+                        $vid->setAttribute("poster", $new_src);
188 184
 
189
-				$vsrcs = $xpath->query("source", $vid);
185
+                        $need_saving = true;
186
+                    }
187
+                }
190 188
 
191
-				foreach ($vsrcs as $vsrc) {
192
-					$new_src = $this->rewrite_url_if_needed($vsrc->getAttribute("src"), $proxy_all);
189
+                $vsrcs = $xpath->query("source", $vid);
193 190
 
194
-					if ($new_src != $vsrc->getAttribute("src")) {
195
-						$vid->setAttribute("src", $new_src);
191
+                foreach ($vsrcs as $vsrc) {
192
+                    $new_src = $this->rewrite_url_if_needed($vsrc->getAttribute("src"), $proxy_all);
196 193
 
197
-						$need_saving = true;
198
-					}
199
-				}
200
-			}
201
-		}
194
+                    if ($new_src != $vsrc->getAttribute("src")) {
195
+                        $vid->setAttribute("src", $new_src);
202 196
 
203
-		if ($need_saving) $article["content"] = $doc->saveHTML();
197
+                        $need_saving = true;
198
+                    }
199
+                }
200
+            }
201
+        }
204 202
 
205
-		return $article;
206
-	}
203
+        if ($need_saving) $article["content"] = $doc->saveHTML();
204
+
205
+        return $article;
206
+    }
207 207
 
208
-	public function hook_prefs_tab($args) {
209
-		if ($args != "prefFeeds") return;
208
+    public function hook_prefs_tab($args) {
209
+        if ($args != "prefFeeds") return;
210 210
 
211
-		print "<div dojoType=\"dijit.layout.AccordionPane\"
211
+        print "<div dojoType=\"dijit.layout.AccordionPane\"
212 212
 			title=\"<i class='material-icons'>extension</i> ".__('Image proxy settings (af_proxy_http)')."\">";
213 213
 
214
-		print "<form dojoType=\"dijit.form.Form\">";
214
+        print "<form dojoType=\"dijit.form.Form\">";
215 215
 
216
-		print "<script type=\"dojo/method\" event=\"onSubmit\" args=\"evt\">
216
+        print "<script type=\"dojo/method\" event=\"onSubmit\" args=\"evt\">
217 217
 			evt.preventDefault();
218 218
 			if (this.validate()) {
219 219
 				console.log(dojo.objectToQuery(this.getValues()));
@@ -227,36 +227,36 @@  discard block
 block discarded – undo
227 227
 			}
228 228
 			</script>";
229 229
 
230
-		print_hidden("op", "pluginhandler");
231
-		print_hidden("method", "save");
232
-		print_hidden("plugin", "af_proxy_http");
230
+        print_hidden("op", "pluginhandler");
231
+        print_hidden("method", "save");
232
+        print_hidden("plugin", "af_proxy_http");
233 233
 
234
-		$proxy_all = $this->host->get($this, "proxy_all");
235
-		print_checkbox("proxy_all", $proxy_all);
236
-		print "&nbsp;<label for=\"proxy_all\">" . __("Enable proxy for all remote images.") . "</label><br/>";
234
+        $proxy_all = $this->host->get($this, "proxy_all");
235
+        print_checkbox("proxy_all", $proxy_all);
236
+        print "&nbsp;<label for=\"proxy_all\">" . __("Enable proxy for all remote images.") . "</label><br/>";
237 237
 
238
-		$disable_cache = $this->host->get($this, "disable_cache");
239
-		print_checkbox("disable_cache", $disable_cache);
240
-		print "&nbsp;<label for=\"disable_cache\">" . __("Don't cache files locally.") . "</label>";
238
+        $disable_cache = $this->host->get($this, "disable_cache");
239
+        print_checkbox("disable_cache", $disable_cache);
240
+        print "&nbsp;<label for=\"disable_cache\">" . __("Don't cache files locally.") . "</label>";
241 241
 
242
-		print "<p>"; print_button("submit", __("Save"));
242
+        print "<p>"; print_button("submit", __("Save"));
243 243
 
244
-		print "</form>";
244
+        print "</form>";
245 245
 
246
-		print "</div>";
247
-	}
246
+        print "</div>";
247
+    }
248 248
 
249
-	public function save() {
250
-		$proxy_all = checkbox_to_sql_bool($_POST["proxy_all"]);
251
-		$disable_cache = checkbox_to_sql_bool($_POST["disable_cache"]);
249
+    public function save() {
250
+        $proxy_all = checkbox_to_sql_bool($_POST["proxy_all"]);
251
+        $disable_cache = checkbox_to_sql_bool($_POST["disable_cache"]);
252 252
 
253
-		$this->host->set($this, "proxy_all", $proxy_all, false);
254
-		$this->host->set($this, "disable_cache", $disable_cache);
253
+        $this->host->set($this, "proxy_all", $proxy_all, false);
254
+        $this->host->set($this, "disable_cache", $disable_cache);
255 255
 
256
-		echo __("Configuration saved");
257
-	}
256
+        echo __("Configuration saved");
257
+    }
258 258
 
259
-	public function api_version() {
260
-		return 2;
261
-	}
259
+    public function api_version() {
260
+        return 2;
261
+    }
262 262
 }
Please login to merge, or discard this patch.
plugins/shorten_expanded/init.php 1 patch
Indentation   +18 added lines, -18 removed lines patch added patch discarded remove patch
@@ -1,28 +1,28 @@
 block discarded – undo
1 1
 <?php
2 2
 class Shorten_Expanded extends Plugin {
3
-	private $host;
3
+    private $host;
4 4
 
5
-	public function about() {
6
-		return array(1.0,
7
-			"Shorten overly long articles in CDM/expanded",
8
-			"fox");
9
-	}
5
+    public function about() {
6
+        return array(1.0,
7
+            "Shorten overly long articles in CDM/expanded",
8
+            "fox");
9
+    }
10 10
 
11
-	public function init($host) {
12
-		$this->host = $host;
11
+    public function init($host) {
12
+        $this->host = $host;
13 13
 
14
-	}
14
+    }
15 15
 
16
-	public function get_css() {
17
-		return file_get_contents(__DIR__ . "/init.css");
18
-	}
16
+    public function get_css() {
17
+        return file_get_contents(__DIR__ . "/init.css");
18
+    }
19 19
 
20
-	public function get_js() {
21
-		return file_get_contents(__DIR__ . "/init.js");
22
-	}
20
+    public function get_js() {
21
+        return file_get_contents(__DIR__ . "/init.js");
22
+    }
23 23
 
24
-	public function api_version() {
25
-		return 2;
26
-	}
24
+    public function api_version() {
25
+        return 2;
26
+    }
27 27
 
28 28
 }
Please login to merge, or discard this patch.
plugins/af_zz_vidmute/init.php 1 patch
Indentation   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -1,23 +1,23 @@
 block discarded – undo
1 1
 <?php
2 2
 class Af_Zz_VidMute extends Plugin {
3
-	private $host;
3
+    private $host;
4 4
 
5
-	public function about() {
6
-		return array(1.0,
7
-			"Mute audio in HTML5 videos",
8
-			"fox");
9
-	}
5
+    public function about() {
6
+        return array(1.0,
7
+            "Mute audio in HTML5 videos",
8
+            "fox");
9
+    }
10 10
 
11
-	public function init($host) {
12
-		$this->host = $host;
13
-	}
11
+    public function init($host) {
12
+        $this->host = $host;
13
+    }
14 14
 
15
-	public function get_js() {
16
-		return file_get_contents(__DIR__ . "/init.js");
17
-	}
15
+    public function get_js() {
16
+        return file_get_contents(__DIR__ . "/init.js");
17
+    }
18 18
 
19
-	public function api_version() {
20
-		return 2;
21
-	}
19
+    public function api_version() {
20
+        return 2;
21
+    }
22 22
 
23 23
 }
Please login to merge, or discard this patch.
plugins/af_fsckportal/init.php 1 patch
Indentation   +30 added lines, -30 removed lines patch added patch discarded remove patch
@@ -1,47 +1,47 @@
 block discarded – undo
1 1
 <?php
2 2
 class Af_Fsckportal extends Plugin {
3 3
 
4
-	private $host;
4
+    private $host;
5 5
 
6
-	public function about() {
7
-		return array(1.0,
8
-			"Remove feedsportal spamlinks from article content",
9
-			"fox");
10
-	}
6
+    public function about() {
7
+        return array(1.0,
8
+            "Remove feedsportal spamlinks from article content",
9
+            "fox");
10
+    }
11 11
 
12
-	public function init($host) {
13
-		$this->host = $host;
12
+    public function init($host) {
13
+        $this->host = $host;
14 14
 
15
-		$host->add_hook($host::HOOK_ARTICLE_FILTER, $this);
16
-	}
15
+        $host->add_hook($host::HOOK_ARTICLE_FILTER, $this);
16
+    }
17 17
 
18
-	public function hook_article_filter($article) {
18
+    public function hook_article_filter($article) {
19 19
 
20
-			$doc = new DOMDocument();
20
+            $doc = new DOMDocument();
21 21
 
22
-			@$doc->loadHTML('<?xml encoding="UTF-8">' . $article["content"]);
22
+            @$doc->loadHTML('<?xml encoding="UTF-8">' . $article["content"]);
23 23
 
24
-			if ($doc) {
25
-				$xpath = new DOMXPath($doc);
26
-				$entries = $xpath->query('(//img[@src]|//a[@href])');
24
+            if ($doc) {
25
+                $xpath = new DOMXPath($doc);
26
+                $entries = $xpath->query('(//img[@src]|//a[@href])');
27 27
 
28
-				foreach ($entries as $entry) {
29
-					if (preg_match("/feedsportal.com/", $entry->getAttribute("src"))) {
30
-						$entry->parentNode->removeChild($entry);
31
-					} else if (preg_match("/feedsportal.com/", $entry->getAttribute("href"))) {
32
-						$entry->parentNode->removeChild($entry);
33
-					}
34
-				}
28
+                foreach ($entries as $entry) {
29
+                    if (preg_match("/feedsportal.com/", $entry->getAttribute("src"))) {
30
+                        $entry->parentNode->removeChild($entry);
31
+                    } else if (preg_match("/feedsportal.com/", $entry->getAttribute("href"))) {
32
+                        $entry->parentNode->removeChild($entry);
33
+                    }
34
+                }
35 35
 
36
-				$article["content"] = $doc->saveHTML();
36
+                $article["content"] = $doc->saveHTML();
37 37
 
38
-		}
38
+        }
39 39
 
40
-		return $article;
41
-	}
40
+        return $article;
41
+    }
42 42
 
43
-	public function api_version() {
44
-		return 2;
45
-	}
43
+    public function api_version() {
44
+        return 2;
45
+    }
46 46
 
47 47
 }
Please login to merge, or discard this patch.
plugins/search_sphinx/init.php 1 patch
Indentation   +46 added lines, -46 removed lines patch added patch discarded remove patch
@@ -1,65 +1,65 @@
 block discarded – undo
1 1
 <?php
2 2
 
3 3
 class Search_Sphinx extends Plugin {
4
-	public function about() {
5
-		return array(1.0,
6
-			"Delegate searching for articles to Sphinx (don't forget to set options in config.php)",
7
-			"hoelzro",
8
-			true,
9
-			"https://git.tt-rss.org/fox/tt-rss/wiki/SphinxSearch");
10
-	}
4
+    public function about() {
5
+        return array(1.0,
6
+            "Delegate searching for articles to Sphinx (don't forget to set options in config.php)",
7
+            "hoelzro",
8
+            true,
9
+            "https://git.tt-rss.org/fox/tt-rss/wiki/SphinxSearch");
10
+    }
11 11
 
12
-	public function init($host) {
13
-		$host->add_hook($host::HOOK_SEARCH, $this);
12
+    public function init($host) {
13
+        $host->add_hook($host::HOOK_SEARCH, $this);
14 14
 
15
-		// idk if that would work but checking for the class being loaded is somehow not enough
16
-		if (class_exists("SphinxClient") && !defined('SEARCHD_COMMAND_SEARCH')) {
17
-			user_error("Your PHP has a separate systemwide Sphinx client installed which conflicts with the client library used by tt-rss. Either remove the system library or disable Sphinx support.");
18
-		}
15
+        // idk if that would work but checking for the class being loaded is somehow not enough
16
+        if (class_exists("SphinxClient") && !defined('SEARCHD_COMMAND_SEARCH')) {
17
+            user_error("Your PHP has a separate systemwide Sphinx client installed which conflicts with the client library used by tt-rss. Either remove the system library or disable Sphinx support.");
18
+        }
19 19
 
20
-		require_once __DIR__ . "/sphinxapi.php";
21
-	}
20
+        require_once __DIR__ . "/sphinxapi.php";
21
+    }
22 22
 
23
-	public function hook_search($search) {
24
-		$offset = 0;
25
-		$limit  = 500;
23
+    public function hook_search($search) {
24
+        $offset = 0;
25
+        $limit  = 500;
26 26
 
27
-		$sphinxClient = new SphinxClient();
27
+        $sphinxClient = new SphinxClient();
28 28
 
29
-		$sphinxpair = explode(":", SPHINX_SERVER, 2);
29
+        $sphinxpair = explode(":", SPHINX_SERVER, 2);
30 30
 
31
-		$sphinxClient->SetServer($sphinxpair[0], (int)$sphinxpair[1]);
32
-		$sphinxClient->SetConnectTimeout(1);
31
+        $sphinxClient->SetServer($sphinxpair[0], (int)$sphinxpair[1]);
32
+        $sphinxClient->SetConnectTimeout(1);
33 33
 
34
-		$sphinxClient->SetFieldWeights(array('title' => 70, 'content' => 30,
35
-			'feed_title' => 20));
34
+        $sphinxClient->SetFieldWeights(array('title' => 70, 'content' => 30,
35
+            'feed_title' => 20));
36 36
 
37
-		$sphinxClient->SetMatchMode(SPH_MATCH_EXTENDED2);
38
-		$sphinxClient->SetRankingMode(SPH_RANK_PROXIMITY_BM25);
39
-		$sphinxClient->SetLimits($offset, $limit, 1000);
40
-		$sphinxClient->SetArrayResult(false);
41
-		$sphinxClient->SetFilter('owner_uid', array($_SESSION['uid']));
37
+        $sphinxClient->SetMatchMode(SPH_MATCH_EXTENDED2);
38
+        $sphinxClient->SetRankingMode(SPH_RANK_PROXIMITY_BM25);
39
+        $sphinxClient->SetLimits($offset, $limit, 1000);
40
+        $sphinxClient->SetArrayResult(false);
41
+        $sphinxClient->SetFilter('owner_uid', array($_SESSION['uid']));
42 42
 
43
-		$result = $sphinxClient->Query($search, SPHINX_INDEX);
43
+        $result = $sphinxClient->Query($search, SPHINX_INDEX);
44 44
 
45
-		$ids = array();
45
+        $ids = array();
46 46
 
47
-		if (is_array($result['matches'])) {
48
-			foreach (array_keys($result['matches']) as $int_id) {
49
-				$ref_id = $result['matches'][$int_id]['attrs']['ref_id'];
50
-				array_push($ids, $ref_id);
51
-			}
52
-		}
47
+        if (is_array($result['matches'])) {
48
+            foreach (array_keys($result['matches']) as $int_id) {
49
+                $ref_id = $result['matches'][$int_id]['attrs']['ref_id'];
50
+                array_push($ids, $ref_id);
51
+            }
52
+        }
53 53
 
54
-		$ids = join(",", $ids);
54
+        $ids = join(",", $ids);
55 55
 
56
-		if ($ids)
57
-			return array("ref_id IN ($ids)", array());
58
-		else
59
-			return array("ref_id = -1", array());
60
-	}
56
+        if ($ids)
57
+            return array("ref_id IN ($ids)", array());
58
+        else
59
+            return array("ref_id = -1", array());
60
+    }
61 61
 
62
-	public function api_version() {
63
-		return 2;
64
-	}
62
+    public function api_version() {
63
+        return 2;
64
+    }
65 65
 }
Please login to merge, or discard this patch.
plugins/search_sphinx/sphinxapi.php 1 patch
Indentation   +1534 added lines, -1534 removed lines patch added patch discarded remove patch
@@ -123,1571 +123,1571 @@
 block discarded – undo
123 123
 /// pack 64-bit signed
124 124
 function sphPackI64 ( $v )
125 125
 {
126
-	assert ( is_numeric($v) );
127
-
128
-	// x64
129
-	if ( PHP_INT_SIZE>=8 )
130
-	{
131
-		$v = (int)$v;
132
-		return pack ( "NN", $v>>32, $v&0xFFFFFFFF );
133
-	}
134
-
135
-	// x32, int
136
-	if ( is_int($v) )
137
-		return pack ( "NN", $v < 0 ? -1 : 0, $v );
138
-
139
-	// x32, bcmath
140
-	if ( function_exists("bcmul") )
141
-	{
142
-		if ( bccomp ( $v, 0 ) == -1 )
143
-			$v = bcadd ( "18446744073709551616", $v );
144
-		$h = bcdiv ( $v, "4294967296", 0 );
145
-		$l = bcmod ( $v, "4294967296" );
146
-		return pack ( "NN", (float)$h, (float)$l ); // conversion to float is intentional; int would lose 31st bit
147
-	}
148
-
149
-	// x32, no-bcmath
150
-	$p = max(0, strlen($v) - 13);
151
-	$lo = abs((float)substr($v, $p));
152
-	$hi = abs((float)substr($v, 0, $p));
153
-
154
-	$m = $lo + $hi*1316134912.0; // (10 ^ 13) % (1 << 32) = 1316134912
155
-	$q = floor($m/4294967296.0);
156
-	$l = $m - ($q*4294967296.0);
157
-	$h = $hi*2328.0 + $q; // (10 ^ 13) / (1 << 32) = 2328
158
-
159
-	if ( $v<0 )
160
-	{
161
-		if ( $l==0 )
162
-			$h = 4294967296.0 - $h;
163
-		else
164
-		{
165
-			$h = 4294967295.0 - $h;
166
-			$l = 4294967296.0 - $l;
167
-		}
168
-	}
169
-	return pack ( "NN", $h, $l );
126
+    assert ( is_numeric($v) );
127
+
128
+    // x64
129
+    if ( PHP_INT_SIZE>=8 )
130
+    {
131
+        $v = (int)$v;
132
+        return pack ( "NN", $v>>32, $v&0xFFFFFFFF );
133
+    }
134
+
135
+    // x32, int
136
+    if ( is_int($v) )
137
+        return pack ( "NN", $v < 0 ? -1 : 0, $v );
138
+
139
+    // x32, bcmath
140
+    if ( function_exists("bcmul") )
141
+    {
142
+        if ( bccomp ( $v, 0 ) == -1 )
143
+            $v = bcadd ( "18446744073709551616", $v );
144
+        $h = bcdiv ( $v, "4294967296", 0 );
145
+        $l = bcmod ( $v, "4294967296" );
146
+        return pack ( "NN", (float)$h, (float)$l ); // conversion to float is intentional; int would lose 31st bit
147
+    }
148
+
149
+    // x32, no-bcmath
150
+    $p = max(0, strlen($v) - 13);
151
+    $lo = abs((float)substr($v, $p));
152
+    $hi = abs((float)substr($v, 0, $p));
153
+
154
+    $m = $lo + $hi*1316134912.0; // (10 ^ 13) % (1 << 32) = 1316134912
155
+    $q = floor($m/4294967296.0);
156
+    $l = $m - ($q*4294967296.0);
157
+    $h = $hi*2328.0 + $q; // (10 ^ 13) / (1 << 32) = 2328
158
+
159
+    if ( $v<0 )
160
+    {
161
+        if ( $l==0 )
162
+            $h = 4294967296.0 - $h;
163
+        else
164
+        {
165
+            $h = 4294967295.0 - $h;
166
+            $l = 4294967296.0 - $l;
167
+        }
168
+    }
169
+    return pack ( "NN", $h, $l );
170 170
 }
171 171
 
172 172
 /// pack 64-bit unsigned
173 173
 function sphPackU64 ( $v )
174 174
 {
175
-	assert ( is_numeric($v) );
176
-
177
-	// x64
178
-	if ( PHP_INT_SIZE>=8 )
179
-	{
180
-		assert ( $v>=0 );
181
-
182
-		// x64, int
183
-		if ( is_int($v) )
184
-			return pack ( "NN", $v>>32, $v&0xFFFFFFFF );
185
-
186
-		// x64, bcmath
187
-		if ( function_exists("bcmul") )
188
-		{
189
-			$h = bcdiv ( $v, 4294967296, 0 );
190
-			$l = bcmod ( $v, 4294967296 );
191
-			return pack ( "NN", $h, $l );
192
-		}
193
-
194
-		// x64, no-bcmath
195
-		$p = max ( 0, strlen($v) - 13 );
196
-		$lo = (int)substr ( $v, $p );
197
-		$hi = (int)substr ( $v, 0, $p );
198
-
199
-		$m = $lo + $hi*1316134912;
200
-		$l = $m % 4294967296;
201
-		$h = $hi*2328 + (int)($m/4294967296);
202
-
203
-		return pack ( "NN", $h, $l );
204
-	}
205
-
206
-	// x32, int
207
-	if ( is_int($v) )
208
-		return pack ( "NN", 0, $v );
209
-
210
-	// x32, bcmath
211
-	if ( function_exists("bcmul") )
212
-	{
213
-		$h = bcdiv ( $v, "4294967296", 0 );
214
-		$l = bcmod ( $v, "4294967296" );
215
-		return pack ( "NN", (float)$h, (float)$l ); // conversion to float is intentional; int would lose 31st bit
216
-	}
217
-
218
-	// x32, no-bcmath
219
-	$p = max(0, strlen($v) - 13);
220
-	$lo = (float)substr($v, $p);
221
-	$hi = (float)substr($v, 0, $p);
222
-
223
-	$m = $lo + $hi*1316134912.0;
224
-	$q = floor($m / 4294967296.0);
225
-	$l = $m - ($q * 4294967296.0);
226
-	$h = $hi*2328.0 + $q;
227
-
228
-	return pack ( "NN", $h, $l );
175
+    assert ( is_numeric($v) );
176
+
177
+    // x64
178
+    if ( PHP_INT_SIZE>=8 )
179
+    {
180
+        assert ( $v>=0 );
181
+
182
+        // x64, int
183
+        if ( is_int($v) )
184
+            return pack ( "NN", $v>>32, $v&0xFFFFFFFF );
185
+
186
+        // x64, bcmath
187
+        if ( function_exists("bcmul") )
188
+        {
189
+            $h = bcdiv ( $v, 4294967296, 0 );
190
+            $l = bcmod ( $v, 4294967296 );
191
+            return pack ( "NN", $h, $l );
192
+        }
193
+
194
+        // x64, no-bcmath
195
+        $p = max ( 0, strlen($v) - 13 );
196
+        $lo = (int)substr ( $v, $p );
197
+        $hi = (int)substr ( $v, 0, $p );
198
+
199
+        $m = $lo + $hi*1316134912;
200
+        $l = $m % 4294967296;
201
+        $h = $hi*2328 + (int)($m/4294967296);
202
+
203
+        return pack ( "NN", $h, $l );
204
+    }
205
+
206
+    // x32, int
207
+    if ( is_int($v) )
208
+        return pack ( "NN", 0, $v );
209
+
210
+    // x32, bcmath
211
+    if ( function_exists("bcmul") )
212
+    {
213
+        $h = bcdiv ( $v, "4294967296", 0 );
214
+        $l = bcmod ( $v, "4294967296" );
215
+        return pack ( "NN", (float)$h, (float)$l ); // conversion to float is intentional; int would lose 31st bit
216
+    }
217
+
218
+    // x32, no-bcmath
219
+    $p = max(0, strlen($v) - 13);
220
+    $lo = (float)substr($v, $p);
221
+    $hi = (float)substr($v, 0, $p);
222
+
223
+    $m = $lo + $hi*1316134912.0;
224
+    $q = floor($m / 4294967296.0);
225
+    $l = $m - ($q * 4294967296.0);
226
+    $h = $hi*2328.0 + $q;
227
+
228
+    return pack ( "NN", $h, $l );
229 229
 }
230 230
 
231 231
 // unpack 64-bit unsigned
232 232
 function sphUnpackU64 ( $v )
233 233
 {
234
-	list ( $hi, $lo ) = array_values ( unpack ( "N*N*", $v ) );
235
-
236
-	if ( PHP_INT_SIZE>=8 )
237
-	{
238
-		if ( $hi<0 ) $hi += (1<<32); // because php 5.2.2 to 5.2.5 is totally fucked up again
239
-		if ( $lo<0 ) $lo += (1<<32);
240
-
241
-		// x64, int
242
-		if ( $hi<=2147483647 )
243
-			return ($hi<<32) + $lo;
244
-
245
-		// x64, bcmath
246
-		if ( function_exists("bcmul") )
247
-			return bcadd ( $lo, bcmul ( $hi, "4294967296" ) );
248
-
249
-		// x64, no-bcmath
250
-		$C = 100000;
251
-		$h = ((int)($hi / $C) << 32) + (int)($lo / $C);
252
-		$l = (($hi % $C) << 32) + ($lo % $C);
253
-		if ( $l>$C )
254
-		{
255
-			$h += (int)($l / $C);
256
-			$l  = $l % $C;
257
-		}
258
-
259
-		if ( $h==0 )
260
-			return $l;
261
-		return sprintf ( "%d%05d", $h, $l );
262
-	}
263
-
264
-	// x32, int
265
-	if ( $hi==0 )
266
-	{
267
-		if ( $lo>0 )
268
-			return $lo;
269
-		return sprintf ( "%u", $lo );
270
-	}
271
-
272
-	$hi = sprintf ( "%u", $hi );
273
-	$lo = sprintf ( "%u", $lo );
274
-
275
-	// x32, bcmath
276
-	if ( function_exists("bcmul") )
277
-		return bcadd ( $lo, bcmul ( $hi, "4294967296" ) );
278
-
279
-	// x32, no-bcmath
280
-	$hi = (float)$hi;
281
-	$lo = (float)$lo;
282
-
283
-	$q = floor($hi/10000000.0);
284
-	$r = $hi - $q*10000000.0;
285
-	$m = $lo + $r*4967296.0;
286
-	$mq = floor($m/10000000.0);
287
-	$l = $m - $mq*10000000.0;
288
-	$h = $q*4294967296.0 + $r*429.0 + $mq;
289
-
290
-	$h = sprintf ( "%.0f", $h );
291
-	$l = sprintf ( "%07.0f", $l );
292
-	if ( $h=="0" )
293
-		return sprintf( "%.0f", (float)$l );
294
-	return $h . $l;
234
+    list ( $hi, $lo ) = array_values ( unpack ( "N*N*", $v ) );
235
+
236
+    if ( PHP_INT_SIZE>=8 )
237
+    {
238
+        if ( $hi<0 ) $hi += (1<<32); // because php 5.2.2 to 5.2.5 is totally fucked up again
239
+        if ( $lo<0 ) $lo += (1<<32);
240
+
241
+        // x64, int
242
+        if ( $hi<=2147483647 )
243
+            return ($hi<<32) + $lo;
244
+
245
+        // x64, bcmath
246
+        if ( function_exists("bcmul") )
247
+            return bcadd ( $lo, bcmul ( $hi, "4294967296" ) );
248
+
249
+        // x64, no-bcmath
250
+        $C = 100000;
251
+        $h = ((int)($hi / $C) << 32) + (int)($lo / $C);
252
+        $l = (($hi % $C) << 32) + ($lo % $C);
253
+        if ( $l>$C )
254
+        {
255
+            $h += (int)($l / $C);
256
+            $l  = $l % $C;
257
+        }
258
+
259
+        if ( $h==0 )
260
+            return $l;
261
+        return sprintf ( "%d%05d", $h, $l );
262
+    }
263
+
264
+    // x32, int
265
+    if ( $hi==0 )
266
+    {
267
+        if ( $lo>0 )
268
+            return $lo;
269
+        return sprintf ( "%u", $lo );
270
+    }
271
+
272
+    $hi = sprintf ( "%u", $hi );
273
+    $lo = sprintf ( "%u", $lo );
274
+
275
+    // x32, bcmath
276
+    if ( function_exists("bcmul") )
277
+        return bcadd ( $lo, bcmul ( $hi, "4294967296" ) );
278
+
279
+    // x32, no-bcmath
280
+    $hi = (float)$hi;
281
+    $lo = (float)$lo;
282
+
283
+    $q = floor($hi/10000000.0);
284
+    $r = $hi - $q*10000000.0;
285
+    $m = $lo + $r*4967296.0;
286
+    $mq = floor($m/10000000.0);
287
+    $l = $m - $mq*10000000.0;
288
+    $h = $q*4294967296.0 + $r*429.0 + $mq;
289
+
290
+    $h = sprintf ( "%.0f", $h );
291
+    $l = sprintf ( "%07.0f", $l );
292
+    if ( $h=="0" )
293
+        return sprintf( "%.0f", (float)$l );
294
+    return $h . $l;
295 295
 }
296 296
 
297 297
 // unpack 64-bit signed
298 298
 function sphUnpackI64 ( $v )
299 299
 {
300
-	list ( $hi, $lo ) = array_values ( unpack ( "N*N*", $v ) );
301
-
302
-	// x64
303
-	if ( PHP_INT_SIZE>=8 )
304
-	{
305
-		if ( $hi<0 ) $hi += (1<<32); // because php 5.2.2 to 5.2.5 is totally fucked up again
306
-		if ( $lo<0 ) $lo += (1<<32);
307
-
308
-		return ($hi<<32) + $lo;
309
-	}
310
-
311
-	// x32, int
312
-	if ( $hi==0 )
313
-	{
314
-		if ( $lo>0 )
315
-			return $lo;
316
-		return sprintf ( "%u", $lo );
317
-	}
318
-	// x32, int
319
-	elseif ( $hi==-1 )
320
-	{
321
-		if ( $lo<0 )
322
-			return $lo;
323
-		return sprintf ( "%.0f", $lo - 4294967296.0 );
324
-	}
325
-
326
-	$neg = "";
327
-	$c = 0;
328
-	if ( $hi<0 )
329
-	{
330
-		$hi = ~$hi;
331
-		$lo = ~$lo;
332
-		$c = 1;
333
-		$neg = "-";
334
-	}
335
-
336
-	$hi = sprintf ( "%u", $hi );
337
-	$lo = sprintf ( "%u", $lo );
338
-
339
-	// x32, bcmath
340
-	if ( function_exists("bcmul") )
341
-		return $neg . bcadd ( bcadd ( $lo, bcmul ( $hi, "4294967296" ) ), $c );
342
-
343
-	// x32, no-bcmath
344
-	$hi = (float)$hi;
345
-	$lo = (float)$lo;
346
-
347
-	$q = floor($hi/10000000.0);
348
-	$r = $hi - $q*10000000.0;
349
-	$m = $lo + $r*4967296.0;
350
-	$mq = floor($m/10000000.0);
351
-	$l = $m - $mq*10000000.0 + $c;
352
-	$h = $q*4294967296.0 + $r*429.0 + $mq;
353
-	if ( $l==10000000 )
354
-	{
355
-		$l = 0;
356
-		$h += 1;
357
-	}
358
-
359
-	$h = sprintf ( "%.0f", $h );
360
-	$l = sprintf ( "%07.0f", $l );
361
-	if ( $h=="0" )
362
-		return $neg . sprintf( "%.0f", (float)$l );
363
-	return $neg . $h . $l;
300
+    list ( $hi, $lo ) = array_values ( unpack ( "N*N*", $v ) );
301
+
302
+    // x64
303
+    if ( PHP_INT_SIZE>=8 )
304
+    {
305
+        if ( $hi<0 ) $hi += (1<<32); // because php 5.2.2 to 5.2.5 is totally fucked up again
306
+        if ( $lo<0 ) $lo += (1<<32);
307
+
308
+        return ($hi<<32) + $lo;
309
+    }
310
+
311
+    // x32, int
312
+    if ( $hi==0 )
313
+    {
314
+        if ( $lo>0 )
315
+            return $lo;
316
+        return sprintf ( "%u", $lo );
317
+    }
318
+    // x32, int
319
+    elseif ( $hi==-1 )
320
+    {
321
+        if ( $lo<0 )
322
+            return $lo;
323
+        return sprintf ( "%.0f", $lo - 4294967296.0 );
324
+    }
325
+
326
+    $neg = "";
327
+    $c = 0;
328
+    if ( $hi<0 )
329
+    {
330
+        $hi = ~$hi;
331
+        $lo = ~$lo;
332
+        $c = 1;
333
+        $neg = "-";
334
+    }
335
+
336
+    $hi = sprintf ( "%u", $hi );
337
+    $lo = sprintf ( "%u", $lo );
338
+
339
+    // x32, bcmath
340
+    if ( function_exists("bcmul") )
341
+        return $neg . bcadd ( bcadd ( $lo, bcmul ( $hi, "4294967296" ) ), $c );
342
+
343
+    // x32, no-bcmath
344
+    $hi = (float)$hi;
345
+    $lo = (float)$lo;
346
+
347
+    $q = floor($hi/10000000.0);
348
+    $r = $hi - $q*10000000.0;
349
+    $m = $lo + $r*4967296.0;
350
+    $mq = floor($m/10000000.0);
351
+    $l = $m - $mq*10000000.0 + $c;
352
+    $h = $q*4294967296.0 + $r*429.0 + $mq;
353
+    if ( $l==10000000 )
354
+    {
355
+        $l = 0;
356
+        $h += 1;
357
+    }
358
+
359
+    $h = sprintf ( "%.0f", $h );
360
+    $l = sprintf ( "%07.0f", $l );
361
+    if ( $h=="0" )
362
+        return $neg . sprintf( "%.0f", (float)$l );
363
+    return $neg . $h . $l;
364 364
 }
365 365
 
366 366
 
367 367
 function sphFixUint ( $value )
368 368
 {
369
-	if ( PHP_INT_SIZE>=8 )
370
-	{
371
-		// x64 route, workaround broken unpack() in 5.2.2+
372
-		if ( $value<0 ) $value += (1<<32);
373
-		return $value;
374
-	}
375
-	else
376
-	{
377
-		// x32 route, workaround php signed/unsigned braindamage
378
-		return sprintf ( "%u", $value );
379
-	}
369
+    if ( PHP_INT_SIZE>=8 )
370
+    {
371
+        // x64 route, workaround broken unpack() in 5.2.2+
372
+        if ( $value<0 ) $value += (1<<32);
373
+        return $value;
374
+    }
375
+    else
376
+    {
377
+        // x32 route, workaround php signed/unsigned braindamage
378
+        return sprintf ( "%u", $value );
379
+    }
380 380
 }
381 381
 
382 382
 
383 383
 /// sphinx searchd client class
384 384
 class SphinxClient
385 385
 {
386
-	var $_host;			///< searchd host (default is "localhost")
387
-	var $_port;			///< searchd port (default is 9312)
388
-	var $_offset;		///< how many records to seek from result-set start (default is 0)
389
-	var $_limit;		///< how many records to return from result-set starting at offset (default is 20)
390
-	var $_mode;			///< query matching mode (default is SPH_MATCH_ALL)
391
-	var $_weights;		///< per-field weights (default is 1 for all fields)
392
-	var $_sort;			///< match sorting mode (default is SPH_SORT_RELEVANCE)
393
-	var $_sortby;		///< attribute to sort by (defualt is "")
394
-	var $_min_id;		///< min ID to match (default is 0, which means no limit)
395
-	var $_max_id;		///< max ID to match (default is 0, which means no limit)
396
-	var $_filters;		///< search filters
397
-	var $_groupby;		///< group-by attribute name
398
-	var $_groupfunc;	///< group-by function (to pre-process group-by attribute value with)
399
-	var $_groupsort;	///< group-by sorting clause (to sort groups in result set with)
400
-	var $_groupdistinct;///< group-by count-distinct attribute
401
-	var $_maxmatches;	///< max matches to retrieve
402
-	var $_cutoff;		///< cutoff to stop searching at (default is 0)
403
-	var $_retrycount;	///< distributed retries count
404
-	var $_retrydelay;	///< distributed retries delay
405
-	var $_anchor;		///< geographical anchor point
406
-	var $_indexweights;	///< per-index weights
407
-	var $_ranker;		///< ranking mode (default is SPH_RANK_PROXIMITY_BM25)
408
-	var $_maxquerytime;	///< max query time, milliseconds (default is 0, do not limit)
409
-	var $_fieldweights;	///< per-field-name weights
410
-	var $_overrides;	///< per-query attribute values overrides
411
-	var $_select;		///< select-list (attributes or expressions, with optional aliases)
412
-
413
-	var $_error;		///< last error message
414
-	var $_warning;		///< last warning message
415
-	var $_connerror;		///< connection error vs remote error flag
416
-
417
-	var $_reqs;			///< requests array for multi-query
418
-	var $_mbenc;		///< stored mbstring encoding
419
-	var $_arrayresult;	///< whether $result["matches"] should be a hash or an array
420
-	var $_timeout;		///< connect timeout
421
-
422
-	/////////////////////////////////////////////////////////////////////////////
423
-	// common stuff
424
-	/////////////////////////////////////////////////////////////////////////////
425
-
426
-	/// create a new client object and fill defaults
427
-	public function __construct()
428
-	{
429
-		// per-client-object settings
430
-		$this->_host		= "localhost";
431
-		$this->_port		= 9312;
432
-		$this->_path		= false;
433
-		$this->_socket		= false;
434
-
435
-		// per-query settings
436
-		$this->_offset		= 0;
437
-		$this->_limit		= 20;
438
-		$this->_mode		= SPH_MATCH_ALL;
439
-		$this->_weights		= array ();
440
-		$this->_sort		= SPH_SORT_RELEVANCE;
441
-		$this->_sortby		= "";
442
-		$this->_min_id		= 0;
443
-		$this->_max_id		= 0;
444
-		$this->_filters		= array ();
445
-		$this->_groupby		= "";
446
-		$this->_groupfunc	= SPH_GROUPBY_DAY;
447
-		$this->_groupsort	= "@group desc";
448
-		$this->_groupdistinct= "";
449
-		$this->_maxmatches	= 1000;
450
-		$this->_cutoff		= 0;
451
-		$this->_retrycount	= 0;
452
-		$this->_retrydelay	= 0;
453
-		$this->_anchor		= array ();
454
-		$this->_indexweights= array ();
455
-		$this->_ranker		= SPH_RANK_PROXIMITY_BM25;
456
-		$this->_maxquerytime= 0;
457
-		$this->_fieldweights= array();
458
-		$this->_overrides 	= array();
459
-		$this->_select		= "*";
460
-
461
-		$this->_error		= ""; // per-reply fields (for single-query case)
462
-		$this->_warning		= "";
463
-		$this->_connerror	= false;
464
-
465
-		$this->_reqs		= array ();	// requests storage (for multi-query case)
466
-		$this->_mbenc		= "";
467
-		$this->_arrayresult	= false;
468
-		$this->_timeout		= 0;
469
-	}
470
-
471
-	public function __destruct()
472
-	{
473
-		if ( $this->_socket !== false )
474
-			fclose ( $this->_socket );
475
-	}
476
-
477
-	/// get last error message (string)
478
-	public function GetLastError ()
479
-	{
480
-		return $this->_error;
481
-	}
482
-
483
-	/// get last warning message (string)
484
-	public function GetLastWarning ()
485
-	{
486
-		return $this->_warning;
487
-	}
488
-
489
-	/// get last error flag (to tell network connection errors from searchd errors or broken responses)
490
-	public function IsConnectError()
491
-	{
492
-		return $this->_connerror;
493
-	}
494
-
495
-	/// set searchd host name (string) and port (integer)
496
-	public function SetServer ( $host, $port = 0 )
497
-	{
498
-		assert ( is_string($host) );
499
-		if ( $host[0] == '/')
500
-		{
501
-			$this->_path = 'unix://' . $host;
502
-			return;
503
-		}
504
-		if ( substr ( $host, 0, 7 )=="unix://" )
505
-		{
506
-			$this->_path = $host;
507
-			return;
508
-		}
509
-
510
-		assert ( is_int($port) );
511
-		$this->_host = $host;
512
-		$this->_port = $port;
513
-		$this->_path = '';
514
-
515
-	}
516
-
517
-	/// set server connection timeout (0 to remove)
518
-	public function SetConnectTimeout ( $timeout )
519
-	{
520
-		assert ( is_numeric($timeout) );
521
-		$this->_timeout = $timeout;
522
-	}
523
-
524
-
525
-	public function _Send ( $handle, $data, $length )
526
-	{
527
-		if ( feof($handle) || fwrite ( $handle, $data, $length ) !== $length )
528
-		{
529
-			$this->_error = 'connection unexpectedly closed (timed out?)';
530
-			$this->_connerror = true;
531
-			return false;
532
-		}
533
-		return true;
534
-	}
535
-
536
-	/////////////////////////////////////////////////////////////////////////////
537
-
538
-	/// enter mbstring workaround mode
539
-	public function _MBPush ()
540
-	{
541
-		$this->_mbenc = "";
542
-		if ( ini_get ( "mbstring.func_overload" ) & 2 )
543
-		{
544
-			$this->_mbenc = mb_internal_encoding();
545
-			mb_internal_encoding ( "latin1" );
546
-		}
386
+    var $_host;			///< searchd host (default is "localhost")
387
+    var $_port;			///< searchd port (default is 9312)
388
+    var $_offset;		///< how many records to seek from result-set start (default is 0)
389
+    var $_limit;		///< how many records to return from result-set starting at offset (default is 20)
390
+    var $_mode;			///< query matching mode (default is SPH_MATCH_ALL)
391
+    var $_weights;		///< per-field weights (default is 1 for all fields)
392
+    var $_sort;			///< match sorting mode (default is SPH_SORT_RELEVANCE)
393
+    var $_sortby;		///< attribute to sort by (defualt is "")
394
+    var $_min_id;		///< min ID to match (default is 0, which means no limit)
395
+    var $_max_id;		///< max ID to match (default is 0, which means no limit)
396
+    var $_filters;		///< search filters
397
+    var $_groupby;		///< group-by attribute name
398
+    var $_groupfunc;	///< group-by function (to pre-process group-by attribute value with)
399
+    var $_groupsort;	///< group-by sorting clause (to sort groups in result set with)
400
+    var $_groupdistinct;///< group-by count-distinct attribute
401
+    var $_maxmatches;	///< max matches to retrieve
402
+    var $_cutoff;		///< cutoff to stop searching at (default is 0)
403
+    var $_retrycount;	///< distributed retries count
404
+    var $_retrydelay;	///< distributed retries delay
405
+    var $_anchor;		///< geographical anchor point
406
+    var $_indexweights;	///< per-index weights
407
+    var $_ranker;		///< ranking mode (default is SPH_RANK_PROXIMITY_BM25)
408
+    var $_maxquerytime;	///< max query time, milliseconds (default is 0, do not limit)
409
+    var $_fieldweights;	///< per-field-name weights
410
+    var $_overrides;	///< per-query attribute values overrides
411
+    var $_select;		///< select-list (attributes or expressions, with optional aliases)
412
+
413
+    var $_error;		///< last error message
414
+    var $_warning;		///< last warning message
415
+    var $_connerror;		///< connection error vs remote error flag
416
+
417
+    var $_reqs;			///< requests array for multi-query
418
+    var $_mbenc;		///< stored mbstring encoding
419
+    var $_arrayresult;	///< whether $result["matches"] should be a hash or an array
420
+    var $_timeout;		///< connect timeout
421
+
422
+    /////////////////////////////////////////////////////////////////////////////
423
+    // common stuff
424
+    /////////////////////////////////////////////////////////////////////////////
425
+
426
+    /// create a new client object and fill defaults
427
+    public function __construct()
428
+    {
429
+        // per-client-object settings
430
+        $this->_host		= "localhost";
431
+        $this->_port		= 9312;
432
+        $this->_path		= false;
433
+        $this->_socket		= false;
434
+
435
+        // per-query settings
436
+        $this->_offset		= 0;
437
+        $this->_limit		= 20;
438
+        $this->_mode		= SPH_MATCH_ALL;
439
+        $this->_weights		= array ();
440
+        $this->_sort		= SPH_SORT_RELEVANCE;
441
+        $this->_sortby		= "";
442
+        $this->_min_id		= 0;
443
+        $this->_max_id		= 0;
444
+        $this->_filters		= array ();
445
+        $this->_groupby		= "";
446
+        $this->_groupfunc	= SPH_GROUPBY_DAY;
447
+        $this->_groupsort	= "@group desc";
448
+        $this->_groupdistinct= "";
449
+        $this->_maxmatches	= 1000;
450
+        $this->_cutoff		= 0;
451
+        $this->_retrycount	= 0;
452
+        $this->_retrydelay	= 0;
453
+        $this->_anchor		= array ();
454
+        $this->_indexweights= array ();
455
+        $this->_ranker		= SPH_RANK_PROXIMITY_BM25;
456
+        $this->_maxquerytime= 0;
457
+        $this->_fieldweights= array();
458
+        $this->_overrides 	= array();
459
+        $this->_select		= "*";
460
+
461
+        $this->_error		= ""; // per-reply fields (for single-query case)
462
+        $this->_warning		= "";
463
+        $this->_connerror	= false;
464
+
465
+        $this->_reqs		= array ();	// requests storage (for multi-query case)
466
+        $this->_mbenc		= "";
467
+        $this->_arrayresult	= false;
468
+        $this->_timeout		= 0;
469
+    }
470
+
471
+    public function __destruct()
472
+    {
473
+        if ( $this->_socket !== false )
474
+            fclose ( $this->_socket );
475
+    }
476
+
477
+    /// get last error message (string)
478
+    public function GetLastError ()
479
+    {
480
+        return $this->_error;
481
+    }
482
+
483
+    /// get last warning message (string)
484
+    public function GetLastWarning ()
485
+    {
486
+        return $this->_warning;
487
+    }
488
+
489
+    /// get last error flag (to tell network connection errors from searchd errors or broken responses)
490
+    public function IsConnectError()
491
+    {
492
+        return $this->_connerror;
493
+    }
494
+
495
+    /// set searchd host name (string) and port (integer)
496
+    public function SetServer ( $host, $port = 0 )
497
+    {
498
+        assert ( is_string($host) );
499
+        if ( $host[0] == '/')
500
+        {
501
+            $this->_path = 'unix://' . $host;
502
+            return;
503
+        }
504
+        if ( substr ( $host, 0, 7 )=="unix://" )
505
+        {
506
+            $this->_path = $host;
507
+            return;
508
+        }
509
+
510
+        assert ( is_int($port) );
511
+        $this->_host = $host;
512
+        $this->_port = $port;
513
+        $this->_path = '';
514
+
515
+    }
516
+
517
+    /// set server connection timeout (0 to remove)
518
+    public function SetConnectTimeout ( $timeout )
519
+    {
520
+        assert ( is_numeric($timeout) );
521
+        $this->_timeout = $timeout;
522
+    }
523
+
524
+
525
+    public function _Send ( $handle, $data, $length )
526
+    {
527
+        if ( feof($handle) || fwrite ( $handle, $data, $length ) !== $length )
528
+        {
529
+            $this->_error = 'connection unexpectedly closed (timed out?)';
530
+            $this->_connerror = true;
531
+            return false;
532
+        }
533
+        return true;
534
+    }
535
+
536
+    /////////////////////////////////////////////////////////////////////////////
537
+
538
+    /// enter mbstring workaround mode
539
+    public function _MBPush ()
540
+    {
541
+        $this->_mbenc = "";
542
+        if ( ini_get ( "mbstring.func_overload" ) & 2 )
543
+        {
544
+            $this->_mbenc = mb_internal_encoding();
545
+            mb_internal_encoding ( "latin1" );
546
+        }
547
+    }
548
+
549
+    /// leave mbstring workaround mode
550
+    public function _MBPop ()
551
+    {
552
+        if ( $this->_mbenc )
553
+            mb_internal_encoding ( $this->_mbenc );
554
+    }
555
+
556
+    /// connect to searchd server
557
+    public function _Connect ()
558
+    {
559
+        if ( $this->_socket!==false )
560
+        {
561
+            // we are in persistent connection mode, so we have a socket
562
+            // however, need to check whether it's still alive
563
+            if ( !@feof ( $this->_socket ) )
564
+                return $this->_socket;
565
+
566
+            // force reopen
567
+            $this->_socket = false;
568
+        }
569
+
570
+        $errno = 0;
571
+        $errstr = "";
572
+        $this->_connerror = false;
573
+
574
+        if ( $this->_path )
575
+        {
576
+            $host = $this->_path;
577
+            $port = 0;
578
+        }
579
+        else
580
+        {
581
+            $host = $this->_host;
582
+            $port = $this->_port;
583
+        }
584
+
585
+        if ( $this->_timeout<=0 )
586
+            $fp = @fsockopen ( $host, $port, $errno, $errstr );
587
+        else
588
+            $fp = @fsockopen ( $host, $port, $errno, $errstr, $this->_timeout );
589
+
590
+        if ( !$fp )
591
+        {
592
+            if ( $this->_path )
593
+                $location = $this->_path;
594
+            else
595
+                $location = "{$this->_host}:{$this->_port}";
596
+
597
+            $errstr = trim ( $errstr );
598
+            $this->_error = "connection to $location failed (errno=$errno, msg=$errstr)";
599
+            $this->_connerror = true;
600
+            return false;
601
+        }
602
+
603
+        // send my version
604
+        // this is a subtle part. we must do it before (!) reading back from searchd.
605
+        // because otherwise under some conditions (reported on FreeBSD for instance)
606
+        // TCP stack could throttle write-write-read pattern because of Nagle.
607
+        if ( !$this->_Send ( $fp, pack ( "N", 1 ), 4 ) )
608
+        {
609
+            fclose ( $fp );
610
+            $this->_error = "failed to send client protocol version";
611
+            return false;
612
+        }
613
+
614
+        // check version
615
+        list(,$v) = unpack ( "N*", fread ( $fp, 4 ) );
616
+        $v = (int)$v;
617
+        if ( $v<1 )
618
+        {
619
+            fclose ( $fp );
620
+            $this->_error = "expected searchd protocol version 1+, got version '$v'";
621
+            return false;
622
+        }
623
+
624
+        return $fp;
625
+    }
626
+
627
+    /// get and check response packet from searchd server
628
+    public function _GetResponse ( $fp, $client_ver )
629
+    {
630
+        $response = "";
631
+        $len = 0;
632
+
633
+        $header = fread ( $fp, 8 );
634
+        if ( strlen($header)==8 )
635
+        {
636
+            list ( $status, $ver, $len ) = array_values ( unpack ( "n2a/Nb", $header ) );
637
+            $left = $len;
638
+            while ( $left>0 && !feof($fp) )
639
+            {
640
+                $chunk = fread ( $fp, min ( 8192, $left ) );
641
+                if ( $chunk )
642
+                {
643
+                    $response .= $chunk;
644
+                    $left -= strlen($chunk);
645
+                }
646
+            }
647
+        }
648
+        if ( $this->_socket === false )
649
+            fclose ( $fp );
650
+
651
+        // check response
652
+        $read = strlen ( $response );
653
+        if ( !$response || $read!=$len )
654
+        {
655
+            $this->_error = $len
656
+                ? "failed to read searchd response (status=$status, ver=$ver, len=$len, read=$read)"
657
+                : "received zero-sized searchd response";
658
+            return false;
659
+        }
660
+
661
+        // check status
662
+        if ( $status==SEARCHD_WARNING )
663
+        {
664
+            list(,$wlen) = unpack ( "N*", substr ( $response, 0, 4 ) );
665
+            $this->_warning = substr ( $response, 4, $wlen );
666
+            return substr ( $response, 4+$wlen );
667
+        }
668
+        if ( $status==SEARCHD_ERROR )
669
+        {
670
+            $this->_error = "searchd error: " . substr ( $response, 4 );
671
+            return false;
672
+        }
673
+        if ( $status==SEARCHD_RETRY )
674
+        {
675
+            $this->_error = "temporary searchd error: " . substr ( $response, 4 );
676
+            return false;
677
+        }
678
+        if ( $status!=SEARCHD_OK )
679
+        {
680
+            $this->_error = "unknown status code '$status'";
681
+            return false;
682
+        }
683
+
684
+        // check version
685
+        if ( $ver<$client_ver )
686
+        {
687
+            $this->_warning = sprintf ( "searchd command v.%d.%d older than client's v.%d.%d, some options might not work",
688
+                $ver>>8, $ver&0xff, $client_ver>>8, $client_ver&0xff );
689
+        }
690
+
691
+        return $response;
692
+    }
693
+
694
+    /////////////////////////////////////////////////////////////////////////////
695
+    // searching
696
+    /////////////////////////////////////////////////////////////////////////////
697
+
698
+    /// set offset and count into result set,
699
+    /// and optionally set max-matches and cutoff limits
700
+    public function SetLimits ( $offset, $limit, $max=0, $cutoff=0 )
701
+    {
702
+        assert ( is_int($offset) );
703
+        assert ( is_int($limit) );
704
+        assert ( $offset>=0 );
705
+        assert ( $limit>0 );
706
+        assert ( $max>=0 );
707
+        $this->_offset = $offset;
708
+        $this->_limit = $limit;
709
+        if ( $max>0 )
710
+            $this->_maxmatches = $max;
711
+        if ( $cutoff>0 )
712
+            $this->_cutoff = $cutoff;
713
+    }
714
+
715
+    /// set maximum query time, in milliseconds, per-index
716
+    /// integer, 0 means "do not limit"
717
+    public function SetMaxQueryTime ( $max )
718
+    {
719
+        assert ( is_int($max) );
720
+        assert ( $max>=0 );
721
+        $this->_maxquerytime = $max;
722
+    }
723
+
724
+    /// set matching mode
725
+    public function SetMatchMode ( $mode )
726
+    {
727
+        assert ( $mode==SPH_MATCH_ALL
728
+            || $mode==SPH_MATCH_ANY
729
+            || $mode==SPH_MATCH_PHRASE
730
+            || $mode==SPH_MATCH_BOOLEAN
731
+            || $mode==SPH_MATCH_EXTENDED
732
+            || $mode==SPH_MATCH_FULLSCAN
733
+            || $mode==SPH_MATCH_EXTENDED2 );
734
+        $this->_mode = $mode;
735
+    }
736
+
737
+    /// set ranking mode
738
+    public function SetRankingMode ( $ranker )
739
+    {
740
+        assert ( $ranker>=0 && $ranker<SPH_RANK_TOTAL );
741
+        $this->_ranker = $ranker;
742
+    }
743
+
744
+    /// set matches sorting mode
745
+    public function SetSortMode ( $mode, $sortby="" )
746
+    {
747
+        assert (
748
+            $mode==SPH_SORT_RELEVANCE ||
749
+            $mode==SPH_SORT_ATTR_DESC ||
750
+            $mode==SPH_SORT_ATTR_ASC ||
751
+            $mode==SPH_SORT_TIME_SEGMENTS ||
752
+            $mode==SPH_SORT_EXTENDED ||
753
+            $mode==SPH_SORT_EXPR );
754
+        assert ( is_string($sortby) );
755
+        assert ( $mode==SPH_SORT_RELEVANCE || strlen($sortby)>0 );
756
+
757
+        $this->_sort = $mode;
758
+        $this->_sortby = $sortby;
759
+    }
760
+
761
+    /// bind per-field weights by order
762
+    /// DEPRECATED; use SetFieldWeights() instead
763
+    public function SetWeights ( $weights )
764
+    {
765
+        assert ( is_array($weights) );
766
+        foreach ( $weights as $weight )
767
+            assert ( is_int($weight) );
768
+
769
+        $this->_weights = $weights;
770
+    }
771
+
772
+    /// bind per-field weights by name
773
+    public function SetFieldWeights ( $weights )
774
+    {
775
+        assert ( is_array($weights) );
776
+        foreach ( $weights as $name=>$weight )
777
+        {
778
+            assert ( is_string($name) );
779
+            assert ( is_int($weight) );
780
+        }
781
+        $this->_fieldweights = $weights;
782
+    }
783
+
784
+    /// bind per-index weights by name
785
+    public function SetIndexWeights ( $weights )
786
+    {
787
+        assert ( is_array($weights) );
788
+        foreach ( $weights as $index=>$weight )
789
+        {
790
+            assert ( is_string($index) );
791
+            assert ( is_int($weight) );
792
+        }
793
+        $this->_indexweights = $weights;
794
+    }
795
+
796
+    /// set IDs range to match
797
+    /// only match records if document ID is beetwen $min and $max (inclusive)
798
+    public function SetIDRange ( $min, $max )
799
+    {
800
+        assert ( is_numeric($min) );
801
+        assert ( is_numeric($max) );
802
+        assert ( $min<=$max );
803
+        $this->_min_id = $min;
804
+        $this->_max_id = $max;
805
+    }
806
+
807
+    /// set values set filter
808
+    /// only match records where $attribute value is in given set
809
+    public function SetFilter ( $attribute, $values, $exclude=false )
810
+    {
811
+        assert ( is_string($attribute) );
812
+        assert ( is_array($values) );
813
+        assert ( count($values) );
814
+
815
+        if ( is_array($values) && count($values) )
816
+        {
817
+            foreach ( $values as $value )
818
+                assert ( is_numeric($value) );
819
+
820
+            $this->_filters[] = array ( "type"=>SPH_FILTER_VALUES, "attr"=>$attribute, "exclude"=>$exclude, "values"=>$values );
821
+        }
822
+    }
823
+
824
+    /// set range filter
825
+    /// only match records if $attribute value is beetwen $min and $max (inclusive)
826
+    public function SetFilterRange ( $attribute, $min, $max, $exclude=false )
827
+    {
828
+        assert ( is_string($attribute) );
829
+        assert ( is_numeric($min) );
830
+        assert ( is_numeric($max) );
831
+        assert ( $min<=$max );
832
+
833
+        $this->_filters[] = array ( "type"=>SPH_FILTER_RANGE, "attr"=>$attribute, "exclude"=>$exclude, "min"=>$min, "max"=>$max );
834
+    }
835
+
836
+    /// set float range filter
837
+    /// only match records if $attribute value is beetwen $min and $max (inclusive)
838
+    public function SetFilterFloatRange ( $attribute, $min, $max, $exclude=false )
839
+    {
840
+        assert ( is_string($attribute) );
841
+        assert ( is_float($min) );
842
+        assert ( is_float($max) );
843
+        assert ( $min<=$max );
844
+
845
+        $this->_filters[] = array ( "type"=>SPH_FILTER_FLOATRANGE, "attr"=>$attribute, "exclude"=>$exclude, "min"=>$min, "max"=>$max );
846
+    }
847
+
848
+    /// setup anchor point for geosphere distance calculations
849
+    /// required to use @geodist in filters and sorting
850
+    /// latitude and longitude must be in radians
851
+    public function SetGeoAnchor ( $attrlat, $attrlong, $lat, $long )
852
+    {
853
+        assert ( is_string($attrlat) );
854
+        assert ( is_string($attrlong) );
855
+        assert ( is_float($lat) );
856
+        assert ( is_float($long) );
857
+
858
+        $this->_anchor = array ( "attrlat"=>$attrlat, "attrlong"=>$attrlong, "lat"=>$lat, "long"=>$long );
859
+    }
860
+
861
+    /// set grouping attribute and function
862
+    public function SetGroupBy ( $attribute, $func, $groupsort="@group desc" )
863
+    {
864
+        assert ( is_string($attribute) );
865
+        assert ( is_string($groupsort) );
866
+        assert ( $func==SPH_GROUPBY_DAY
867
+            || $func==SPH_GROUPBY_WEEK
868
+            || $func==SPH_GROUPBY_MONTH
869
+            || $func==SPH_GROUPBY_YEAR
870
+            || $func==SPH_GROUPBY_ATTR
871
+            || $func==SPH_GROUPBY_ATTRPAIR );
872
+
873
+        $this->_groupby = $attribute;
874
+        $this->_groupfunc = $func;
875
+        $this->_groupsort = $groupsort;
876
+    }
877
+
878
+    /// set count-distinct attribute for group-by queries
879
+    public function SetGroupDistinct ( $attribute )
880
+    {
881
+        assert ( is_string($attribute) );
882
+        $this->_groupdistinct = $attribute;
883
+    }
884
+
885
+    /// set distributed retries count and delay
886
+    public function SetRetries ( $count, $delay=0 )
887
+    {
888
+        assert ( is_int($count) && $count>=0 );
889
+        assert ( is_int($delay) && $delay>=0 );
890
+        $this->_retrycount = $count;
891
+        $this->_retrydelay = $delay;
892
+    }
893
+
894
+    /// set result set format (hash or array; hash by default)
895
+    /// PHP specific; needed for group-by-MVA result sets that may contain duplicate IDs
896
+    public function SetArrayResult ( $arrayresult )
897
+    {
898
+        assert ( is_bool($arrayresult) );
899
+        $this->_arrayresult = $arrayresult;
900
+    }
901
+
902
+    /// set attribute values override
903
+    /// there can be only one override per attribute
904
+    /// $values must be a hash that maps document IDs to attribute values
905
+    public function SetOverride ( $attrname, $attrtype, $values )
906
+    {
907
+        assert ( is_string ( $attrname ) );
908
+        assert ( in_array ( $attrtype, array ( SPH_ATTR_INTEGER, SPH_ATTR_TIMESTAMP, SPH_ATTR_BOOL, SPH_ATTR_FLOAT, SPH_ATTR_BIGINT ) ) );
909
+        assert ( is_array ( $values ) );
910
+
911
+        $this->_overrides[$attrname] = array ( "attr"=>$attrname, "type"=>$attrtype, "values"=>$values );
912
+    }
913
+
914
+    /// set select-list (attributes or expressions), SQL-like syntax
915
+    public function SetSelect ( $select )
916
+    {
917
+        assert ( is_string ( $select ) );
918
+        $this->_select = $select;
919
+    }
920
+
921
+    //////////////////////////////////////////////////////////////////////////////
922
+
923
+    /// clear all filters (for multi-queries)
924
+    public function ResetFilters ()
925
+    {
926
+        $this->_filters = array();
927
+        $this->_anchor = array();
928
+    }
929
+
930
+    /// clear groupby settings (for multi-queries)
931
+    public function ResetGroupBy ()
932
+    {
933
+        $this->_groupby		= "";
934
+        $this->_groupfunc	= SPH_GROUPBY_DAY;
935
+        $this->_groupsort	= "@group desc";
936
+        $this->_groupdistinct= "";
547 937
     }
548 938
 
549
-	/// leave mbstring workaround mode
550
-	public function _MBPop ()
551
-	{
552
-		if ( $this->_mbenc )
553
-			mb_internal_encoding ( $this->_mbenc );
554
-	}
555
-
556
-	/// connect to searchd server
557
-	public function _Connect ()
558
-	{
559
-		if ( $this->_socket!==false )
560
-		{
561
-			// we are in persistent connection mode, so we have a socket
562
-			// however, need to check whether it's still alive
563
-			if ( !@feof ( $this->_socket ) )
564
-				return $this->_socket;
565
-
566
-			// force reopen
567
-			$this->_socket = false;
568
-		}
569
-
570
-		$errno = 0;
571
-		$errstr = "";
572
-		$this->_connerror = false;
573
-
574
-		if ( $this->_path )
575
-		{
576
-			$host = $this->_path;
577
-			$port = 0;
578
-		}
579
-		else
580
-		{
581
-			$host = $this->_host;
582
-			$port = $this->_port;
583
-		}
584
-
585
-		if ( $this->_timeout<=0 )
586
-			$fp = @fsockopen ( $host, $port, $errno, $errstr );
587
-		else
588
-			$fp = @fsockopen ( $host, $port, $errno, $errstr, $this->_timeout );
589
-
590
-		if ( !$fp )
591
-		{
592
-			if ( $this->_path )
593
-				$location = $this->_path;
594
-			else
595
-				$location = "{$this->_host}:{$this->_port}";
596
-
597
-			$errstr = trim ( $errstr );
598
-			$this->_error = "connection to $location failed (errno=$errno, msg=$errstr)";
599
-			$this->_connerror = true;
600
-			return false;
601
-		}
602
-
603
-		// send my version
604
-		// this is a subtle part. we must do it before (!) reading back from searchd.
605
-		// because otherwise under some conditions (reported on FreeBSD for instance)
606
-		// TCP stack could throttle write-write-read pattern because of Nagle.
607
-		if ( !$this->_Send ( $fp, pack ( "N", 1 ), 4 ) )
608
-		{
609
-			fclose ( $fp );
610
-			$this->_error = "failed to send client protocol version";
611
-			return false;
612
-		}
613
-
614
-		// check version
615
-		list(,$v) = unpack ( "N*", fread ( $fp, 4 ) );
616
-		$v = (int)$v;
617
-		if ( $v<1 )
618
-		{
619
-			fclose ( $fp );
620
-			$this->_error = "expected searchd protocol version 1+, got version '$v'";
621
-			return false;
622
-		}
623
-
624
-		return $fp;
625
-	}
626
-
627
-	/// get and check response packet from searchd server
628
-	public function _GetResponse ( $fp, $client_ver )
629
-	{
630
-		$response = "";
631
-		$len = 0;
632
-
633
-		$header = fread ( $fp, 8 );
634
-		if ( strlen($header)==8 )
635
-		{
636
-			list ( $status, $ver, $len ) = array_values ( unpack ( "n2a/Nb", $header ) );
637
-			$left = $len;
638
-			while ( $left>0 && !feof($fp) )
639
-			{
640
-				$chunk = fread ( $fp, min ( 8192, $left ) );
641
-				if ( $chunk )
642
-				{
643
-					$response .= $chunk;
644
-					$left -= strlen($chunk);
645
-				}
646
-			}
647
-		}
648
-		if ( $this->_socket === false )
649
-			fclose ( $fp );
650
-
651
-		// check response
652
-		$read = strlen ( $response );
653
-		if ( !$response || $read!=$len )
654
-		{
655
-			$this->_error = $len
656
-				? "failed to read searchd response (status=$status, ver=$ver, len=$len, read=$read)"
657
-				: "received zero-sized searchd response";
658
-			return false;
659
-		}
660
-
661
-		// check status
662
-		if ( $status==SEARCHD_WARNING )
663
-		{
664
-			list(,$wlen) = unpack ( "N*", substr ( $response, 0, 4 ) );
665
-			$this->_warning = substr ( $response, 4, $wlen );
666
-			return substr ( $response, 4+$wlen );
667
-		}
668
-		if ( $status==SEARCHD_ERROR )
669
-		{
670
-			$this->_error = "searchd error: " . substr ( $response, 4 );
671
-			return false;
672
-		}
673
-		if ( $status==SEARCHD_RETRY )
674
-		{
675
-			$this->_error = "temporary searchd error: " . substr ( $response, 4 );
676
-			return false;
677
-		}
678
-		if ( $status!=SEARCHD_OK )
679
-		{
680
-			$this->_error = "unknown status code '$status'";
681
-			return false;
682
-		}
683
-
684
-		// check version
685
-		if ( $ver<$client_ver )
686
-		{
687
-			$this->_warning = sprintf ( "searchd command v.%d.%d older than client's v.%d.%d, some options might not work",
688
-				$ver>>8, $ver&0xff, $client_ver>>8, $client_ver&0xff );
689
-		}
690
-
691
-		return $response;
692
-	}
693
-
694
-	/////////////////////////////////////////////////////////////////////////////
695
-	// searching
696
-	/////////////////////////////////////////////////////////////////////////////
697
-
698
-	/// set offset and count into result set,
699
-	/// and optionally set max-matches and cutoff limits
700
-	public function SetLimits ( $offset, $limit, $max=0, $cutoff=0 )
701
-	{
702
-		assert ( is_int($offset) );
703
-		assert ( is_int($limit) );
704
-		assert ( $offset>=0 );
705
-		assert ( $limit>0 );
706
-		assert ( $max>=0 );
707
-		$this->_offset = $offset;
708
-		$this->_limit = $limit;
709
-		if ( $max>0 )
710
-			$this->_maxmatches = $max;
711
-		if ( $cutoff>0 )
712
-			$this->_cutoff = $cutoff;
713
-	}
714
-
715
-	/// set maximum query time, in milliseconds, per-index
716
-	/// integer, 0 means "do not limit"
717
-	public function SetMaxQueryTime ( $max )
718
-	{
719
-		assert ( is_int($max) );
720
-		assert ( $max>=0 );
721
-		$this->_maxquerytime = $max;
722
-	}
723
-
724
-	/// set matching mode
725
-	public function SetMatchMode ( $mode )
726
-	{
727
-		assert ( $mode==SPH_MATCH_ALL
728
-			|| $mode==SPH_MATCH_ANY
729
-			|| $mode==SPH_MATCH_PHRASE
730
-			|| $mode==SPH_MATCH_BOOLEAN
731
-			|| $mode==SPH_MATCH_EXTENDED
732
-			|| $mode==SPH_MATCH_FULLSCAN
733
-			|| $mode==SPH_MATCH_EXTENDED2 );
734
-		$this->_mode = $mode;
735
-	}
736
-
737
-	/// set ranking mode
738
-	public function SetRankingMode ( $ranker )
739
-	{
740
-		assert ( $ranker>=0 && $ranker<SPH_RANK_TOTAL );
741
-		$this->_ranker = $ranker;
742
-	}
743
-
744
-	/// set matches sorting mode
745
-	public function SetSortMode ( $mode, $sortby="" )
746
-	{
747
-		assert (
748
-			$mode==SPH_SORT_RELEVANCE ||
749
-			$mode==SPH_SORT_ATTR_DESC ||
750
-			$mode==SPH_SORT_ATTR_ASC ||
751
-			$mode==SPH_SORT_TIME_SEGMENTS ||
752
-			$mode==SPH_SORT_EXTENDED ||
753
-			$mode==SPH_SORT_EXPR );
754
-		assert ( is_string($sortby) );
755
-		assert ( $mode==SPH_SORT_RELEVANCE || strlen($sortby)>0 );
756
-
757
-		$this->_sort = $mode;
758
-		$this->_sortby = $sortby;
759
-	}
760
-
761
-	/// bind per-field weights by order
762
-	/// DEPRECATED; use SetFieldWeights() instead
763
-	public function SetWeights ( $weights )
764
-	{
765
-		assert ( is_array($weights) );
766
-		foreach ( $weights as $weight )
767
-			assert ( is_int($weight) );
768
-
769
-		$this->_weights = $weights;
770
-	}
771
-
772
-	/// bind per-field weights by name
773
-	public function SetFieldWeights ( $weights )
774
-	{
775
-		assert ( is_array($weights) );
776
-		foreach ( $weights as $name=>$weight )
777
-		{
778
-			assert ( is_string($name) );
779
-			assert ( is_int($weight) );
780
-		}
781
-		$this->_fieldweights = $weights;
782
-	}
783
-
784
-	/// bind per-index weights by name
785
-	public function SetIndexWeights ( $weights )
786
-	{
787
-		assert ( is_array($weights) );
788
-		foreach ( $weights as $index=>$weight )
789
-		{
790
-			assert ( is_string($index) );
791
-			assert ( is_int($weight) );
792
-		}
793
-		$this->_indexweights = $weights;
794
-	}
795
-
796
-	/// set IDs range to match
797
-	/// only match records if document ID is beetwen $min and $max (inclusive)
798
-	public function SetIDRange ( $min, $max )
799
-	{
800
-		assert ( is_numeric($min) );
801
-		assert ( is_numeric($max) );
802
-		assert ( $min<=$max );
803
-		$this->_min_id = $min;
804
-		$this->_max_id = $max;
805
-	}
806
-
807
-	/// set values set filter
808
-	/// only match records where $attribute value is in given set
809
-	public function SetFilter ( $attribute, $values, $exclude=false )
810
-	{
811
-		assert ( is_string($attribute) );
812
-		assert ( is_array($values) );
813
-		assert ( count($values) );
814
-
815
-		if ( is_array($values) && count($values) )
816
-		{
817
-			foreach ( $values as $value )
818
-				assert ( is_numeric($value) );
819
-
820
-			$this->_filters[] = array ( "type"=>SPH_FILTER_VALUES, "attr"=>$attribute, "exclude"=>$exclude, "values"=>$values );
821
-		}
822
-	}
823
-
824
-	/// set range filter
825
-	/// only match records if $attribute value is beetwen $min and $max (inclusive)
826
-	public function SetFilterRange ( $attribute, $min, $max, $exclude=false )
827
-	{
828
-		assert ( is_string($attribute) );
829
-		assert ( is_numeric($min) );
830
-		assert ( is_numeric($max) );
831
-		assert ( $min<=$max );
832
-
833
-		$this->_filters[] = array ( "type"=>SPH_FILTER_RANGE, "attr"=>$attribute, "exclude"=>$exclude, "min"=>$min, "max"=>$max );
834
-	}
835
-
836
-	/// set float range filter
837
-	/// only match records if $attribute value is beetwen $min and $max (inclusive)
838
-	public function SetFilterFloatRange ( $attribute, $min, $max, $exclude=false )
839
-	{
840
-		assert ( is_string($attribute) );
841
-		assert ( is_float($min) );
842
-		assert ( is_float($max) );
843
-		assert ( $min<=$max );
844
-
845
-		$this->_filters[] = array ( "type"=>SPH_FILTER_FLOATRANGE, "attr"=>$attribute, "exclude"=>$exclude, "min"=>$min, "max"=>$max );
846
-	}
847
-
848
-	/// setup anchor point for geosphere distance calculations
849
-	/// required to use @geodist in filters and sorting
850
-	/// latitude and longitude must be in radians
851
-	public function SetGeoAnchor ( $attrlat, $attrlong, $lat, $long )
852
-	{
853
-		assert ( is_string($attrlat) );
854
-		assert ( is_string($attrlong) );
855
-		assert ( is_float($lat) );
856
-		assert ( is_float($long) );
857
-
858
-		$this->_anchor = array ( "attrlat"=>$attrlat, "attrlong"=>$attrlong, "lat"=>$lat, "long"=>$long );
859
-	}
860
-
861
-	/// set grouping attribute and function
862
-	public function SetGroupBy ( $attribute, $func, $groupsort="@group desc" )
863
-	{
864
-		assert ( is_string($attribute) );
865
-		assert ( is_string($groupsort) );
866
-		assert ( $func==SPH_GROUPBY_DAY
867
-			|| $func==SPH_GROUPBY_WEEK
868
-			|| $func==SPH_GROUPBY_MONTH
869
-			|| $func==SPH_GROUPBY_YEAR
870
-			|| $func==SPH_GROUPBY_ATTR
871
-			|| $func==SPH_GROUPBY_ATTRPAIR );
872
-
873
-		$this->_groupby = $attribute;
874
-		$this->_groupfunc = $func;
875
-		$this->_groupsort = $groupsort;
876
-	}
877
-
878
-	/// set count-distinct attribute for group-by queries
879
-	public function SetGroupDistinct ( $attribute )
880
-	{
881
-		assert ( is_string($attribute) );
882
-		$this->_groupdistinct = $attribute;
883
-	}
884
-
885
-	/// set distributed retries count and delay
886
-	public function SetRetries ( $count, $delay=0 )
887
-	{
888
-		assert ( is_int($count) && $count>=0 );
889
-		assert ( is_int($delay) && $delay>=0 );
890
-		$this->_retrycount = $count;
891
-		$this->_retrydelay = $delay;
892
-	}
893
-
894
-	/// set result set format (hash or array; hash by default)
895
-	/// PHP specific; needed for group-by-MVA result sets that may contain duplicate IDs
896
-	public function SetArrayResult ( $arrayresult )
897
-	{
898
-		assert ( is_bool($arrayresult) );
899
-		$this->_arrayresult = $arrayresult;
900
-	}
901
-
902
-	/// set attribute values override
903
-	/// there can be only one override per attribute
904
-	/// $values must be a hash that maps document IDs to attribute values
905
-	public function SetOverride ( $attrname, $attrtype, $values )
906
-	{
907
-		assert ( is_string ( $attrname ) );
908
-		assert ( in_array ( $attrtype, array ( SPH_ATTR_INTEGER, SPH_ATTR_TIMESTAMP, SPH_ATTR_BOOL, SPH_ATTR_FLOAT, SPH_ATTR_BIGINT ) ) );
909
-		assert ( is_array ( $values ) );
910
-
911
-		$this->_overrides[$attrname] = array ( "attr"=>$attrname, "type"=>$attrtype, "values"=>$values );
912
-	}
913
-
914
-	/// set select-list (attributes or expressions), SQL-like syntax
915
-	public function SetSelect ( $select )
916
-	{
917
-		assert ( is_string ( $select ) );
918
-		$this->_select = $select;
919
-	}
920
-
921
-	//////////////////////////////////////////////////////////////////////////////
922
-
923
-	/// clear all filters (for multi-queries)
924
-	public function ResetFilters ()
925
-	{
926
-		$this->_filters = array();
927
-		$this->_anchor = array();
928
-	}
929
-
930
-	/// clear groupby settings (for multi-queries)
931
-	public function ResetGroupBy ()
932
-	{
933
-		$this->_groupby		= "";
934
-		$this->_groupfunc	= SPH_GROUPBY_DAY;
935
-		$this->_groupsort	= "@group desc";
936
-		$this->_groupdistinct= "";
937
-	}
938
-
939
-	/// clear all attribute value overrides (for multi-queries)
940
-	public function ResetOverrides ()
939
+    /// clear all attribute value overrides (for multi-queries)
940
+    public function ResetOverrides ()
941 941
     {
942
-    	$this->_overrides = array ();
942
+        $this->_overrides = array ();
943 943
     }
944 944
 
945
-	//////////////////////////////////////////////////////////////////////////////
946
-
947
-	/// connect to searchd server, run given search query through given indexes,
948
-	/// and return the search results
949
-	public function Query ( $query, $index="*", $comment="" )
950
-	{
951
-		assert ( empty($this->_reqs) );
952
-
953
-		$this->AddQuery ( $query, $index, $comment );
954
-		$results = $this->RunQueries ();
955
-		$this->_reqs = array (); // just in case it failed too early
956
-
957
-		if ( !is_array($results) )
958
-			return false; // probably network error; error message should be already filled
959
-
960
-		$this->_error = $results[0]["error"];
961
-		$this->_warning = $results[0]["warning"];
962
-		if ( $results[0]["status"]==SEARCHD_ERROR )
963
-			return false;
964
-		else
965
-			return $results[0];
966
-	}
967
-
968
-	/// helper to pack floats in network byte order
969
-	public function _PackFloat ( $f )
970
-	{
971
-		$t1 = pack ( "f", $f ); // machine order
972
-		list(,$t2) = unpack ( "L*", $t1 ); // int in machine order
973
-		return pack ( "N", $t2 );
974
-	}
975
-
976
-	/**
977
-	 * @SuppressWarnings(unused)
978
-	 */
979
-
980
-	/// add query to multi-query batch
981
-	/// returns index into results array from RunQueries() call
982
-	public function AddQuery ( $query, $index="*", $comment="" )
983
-	{
984
-		// mbstring workaround
985
-		$this->_MBPush ();
986
-
987
-		// build request
988
-		$req = pack ( "NNNNN", $this->_offset, $this->_limit, $this->_mode, $this->_ranker, $this->_sort ); // mode and limits
989
-		$req .= pack ( "N", strlen($this->_sortby) ) . $this->_sortby;
990
-		$req .= pack ( "N", strlen($query) ) . $query; // query itself
991
-		$req .= pack ( "N", count($this->_weights) ); // weights
992
-		foreach ( $this->_weights as $weight )
993
-			$req .= pack ( "N", (int)$weight );
994
-		$req .= pack ( "N", strlen($index) ) . $index; // indexes
995
-		$req .= pack ( "N", 1 ); // id64 range marker
996
-		$req .= sphPackU64 ( $this->_min_id ) . sphPackU64 ( $this->_max_id ); // id64 range
997
-
998
-		// filters
999
-		$req .= pack ( "N", count($this->_filters) );
1000
-		foreach ( $this->_filters as $filter )
1001
-		{
1002
-			$req .= pack ( "N", strlen($filter["attr"]) ) . $filter["attr"];
1003
-			$req .= pack ( "N", $filter["type"] );
1004
-			switch ( $filter["type"] )
1005
-			{
1006
-				case SPH_FILTER_VALUES:
1007
-					$req .= pack ( "N", count($filter["values"]) );
1008
-					foreach ( $filter["values"] as $value )
1009
-						$req .= sphPackI64 ( $value );
1010
-					break;
1011
-
1012
-				case SPH_FILTER_RANGE:
1013
-					$req .= sphPackI64 ( $filter["min"] ) . sphPackI64 ( $filter["max"] );
1014
-					break;
1015
-
1016
-				case SPH_FILTER_FLOATRANGE:
1017
-					$req .= $this->_PackFloat ( $filter["min"] ) . $this->_PackFloat ( $filter["max"] );
1018
-					break;
1019
-
1020
-				default:
1021
-					assert ( 0 && "internal error: unhandled filter type" );
1022
-			}
1023
-			$req .= pack ( "N", $filter["exclude"] );
1024
-		}
1025
-
1026
-		// group-by clause, max-matches count, group-sort clause, cutoff count
1027
-		$req .= pack ( "NN", $this->_groupfunc, strlen($this->_groupby) ) . $this->_groupby;
1028
-		$req .= pack ( "N", $this->_maxmatches );
1029
-		$req .= pack ( "N", strlen($this->_groupsort) ) . $this->_groupsort;
1030
-		$req .= pack ( "NNN", $this->_cutoff, $this->_retrycount, $this->_retrydelay );
1031
-		$req .= pack ( "N", strlen($this->_groupdistinct) ) . $this->_groupdistinct;
1032
-
1033
-		// anchor point
1034
-		if ( empty($this->_anchor) )
1035
-		{
1036
-			$req .= pack ( "N", 0 );
1037
-		} else
1038
-		{
1039
-			$a =& $this->_anchor;
1040
-			$req .= pack ( "N", 1 );
1041
-			$req .= pack ( "N", strlen($a["attrlat"]) ) . $a["attrlat"];
1042
-			$req .= pack ( "N", strlen($a["attrlong"]) ) . $a["attrlong"];
1043
-			$req .= $this->_PackFloat ( $a["lat"] ) . $this->_PackFloat ( $a["long"] );
1044
-		}
1045
-
1046
-		// per-index weights
1047
-		$req .= pack ( "N", count($this->_indexweights) );
1048
-		foreach ( $this->_indexweights as $idx=>$weight )
1049
-			$req .= pack ( "N", strlen($idx) ) . $idx . pack ( "N", $weight );
1050
-
1051
-		// max query time
1052
-		$req .= pack ( "N", $this->_maxquerytime );
1053
-
1054
-		// per-field weights
1055
-		$req .= pack ( "N", count($this->_fieldweights) );
1056
-		foreach ( $this->_fieldweights as $field=>$weight )
1057
-			$req .= pack ( "N", strlen($field) ) . $field . pack ( "N", $weight );
1058
-
1059
-		// comment
1060
-		$req .= pack ( "N", strlen($comment) ) . $comment;
1061
-
1062
-		// attribute overrides
1063
-		$req .= pack ( "N", count($this->_overrides) );
1064
-		foreach ( $this->_overrides as $key => $entry )
1065
-		{
1066
-			$req .= pack ( "N", strlen($entry["attr"]) ) . $entry["attr"];
1067
-			$req .= pack ( "NN", $entry["type"], count($entry["values"]) );
1068
-			foreach ( $entry["values"] as $id=>$val )
1069
-			{
1070
-				assert ( is_numeric($id) );
1071
-				assert ( is_numeric($val) );
1072
-
1073
-				$req .= sphPackU64 ( $id );
1074
-				switch ( $entry["type"] )
1075
-				{
1076
-					case SPH_ATTR_FLOAT:	$req .= $this->_PackFloat ( $val ); break;
1077
-					case SPH_ATTR_BIGINT:	$req .= sphPackI64 ( $val ); break;
1078
-					default:				$req .= pack ( "N", $val ); break;
1079
-				}
1080
-			}
1081
-		}
1082
-
1083
-		// select-list
1084
-		$req .= pack ( "N", strlen($this->_select) ) . $this->_select;
1085
-
1086
-		// mbstring workaround
1087
-		$this->_MBPop ();
1088
-
1089
-		// store request to requests array
1090
-		$this->_reqs[] = $req;
1091
-		return count($this->_reqs)-1;
1092
-	}
1093
-
1094
-	/// connect to searchd, run queries batch, and return an array of result sets
1095
-	public function RunQueries ()
1096
-	{
1097
-		if ( empty($this->_reqs) )
1098
-		{
1099
-			$this->_error = "no queries defined, issue AddQuery() first";
1100
-			return false;
1101
-		}
1102
-
1103
-		// mbstring workaround
1104
-		$this->_MBPush ();
1105
-
1106
-		if (!( $fp = $this->_Connect() ))
1107
-		{
1108
-			$this->_MBPop ();
1109
-			return false;
1110
-		}
1111
-
1112
-		// send query, get response
1113
-		$nreqs = count($this->_reqs);
1114
-		$req = join ( "", $this->_reqs );
1115
-		$len = 8+strlen($req);
1116
-		$req = pack ( "nnNNN", SEARCHD_COMMAND_SEARCH, VER_COMMAND_SEARCH, $len, 0, $nreqs ) . $req; // add header
1117
-
1118
-		if ( !( $this->_Send ( $fp, $req, $len+8 ) ) ||
1119
-			 !( $response = $this->_GetResponse ( $fp, VER_COMMAND_SEARCH ) ) )
1120
-		{
1121
-			$this->_MBPop ();
1122
-			return false;
1123
-		}
1124
-
1125
-		// query sent ok; we can reset reqs now
1126
-		$this->_reqs = array ();
1127
-
1128
-		// parse and return response
1129
-		return $this->_ParseSearchResponse ( $response, $nreqs );
1130
-	}
1131
-
1132
-	/// parse and return search query (or queries) response
1133
-	public function _ParseSearchResponse ( $response, $nreqs )
1134
-	{
1135
-		$p = 0; // current position
1136
-		$max = strlen($response); // max position for checks, to protect against broken responses
1137
-
1138
-		$results = array ();
1139
-		for ( $ires=0; $ires<$nreqs && $p<$max; $ires++ )
1140
-		{
1141
-			$results[] = array();
1142
-			$result =& $results[$ires];
1143
-
1144
-			$result["error"] = "";
1145
-			$result["warning"] = "";
1146
-
1147
-			// extract status
1148
-			list(,$status) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1149
-			$result["status"] = $status;
1150
-			if ( $status!=SEARCHD_OK )
1151
-			{
1152
-				list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1153
-				$message = substr ( $response, $p, $len ); $p += $len;
1154
-
1155
-				if ( $status==SEARCHD_WARNING )
1156
-				{
1157
-					$result["warning"] = $message;
1158
-				} else
1159
-				{
1160
-					$result["error"] = $message;
1161
-					continue;
1162
-				}
1163
-			}
1164
-
1165
-			// read schema
1166
-			$fields = array ();
1167
-			$attrs = array ();
1168
-
1169
-			list(,$nfields) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1170
-			while ( $nfields-->0 && $p<$max )
1171
-			{
1172
-				list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1173
-				$fields[] = substr ( $response, $p, $len ); $p += $len;
1174
-			}
1175
-			$result["fields"] = $fields;
1176
-
1177
-			list(,$nattrs) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1178
-			while ( $nattrs-->0 && $p<$max  )
1179
-			{
1180
-				list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1181
-				$attr = substr ( $response, $p, $len ); $p += $len;
1182
-				list(,$type) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1183
-				$attrs[$attr] = $type;
1184
-			}
1185
-			$result["attrs"] = $attrs;
1186
-
1187
-			// read match count
1188
-			list(,$count) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1189
-			list(,$id64) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1190
-
1191
-			// read matches
1192
-			$idx = -1;
1193
-			while ( $count-->0 && $p<$max )
1194
-			{
1195
-				// index into result array
1196
-				$idx++;
1197
-
1198
-				// parse document id and weight
1199
-				if ( $id64 )
1200
-				{
1201
-					$doc = sphUnpackU64 ( substr ( $response, $p, 8 ) ); $p += 8;
1202
-					list(,$weight) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1203
-				}
1204
-				else
1205
-				{
1206
-					list ( $doc, $weight ) = array_values ( unpack ( "N*N*",
1207
-						substr ( $response, $p, 8 ) ) );
1208
-					$p += 8;
1209
-					$doc = sphFixUint($doc);
1210
-				}
1211
-				$weight = sprintf ( "%u", $weight );
1212
-
1213
-				// create match entry
1214
-				if ( $this->_arrayresult )
1215
-					$result["matches"][$idx] = array ( "id"=>$doc, "weight"=>$weight );
1216
-				else
1217
-					$result["matches"][$doc]["weight"] = $weight;
1218
-
1219
-				// parse and create attributes
1220
-				$attrvals = array ();
1221
-				foreach ( $attrs as $attr=>$type )
1222
-				{
1223
-					// handle 64bit ints
1224
-					if ( $type==SPH_ATTR_BIGINT )
1225
-					{
1226
-						$attrvals[$attr] = sphUnpackI64 ( substr ( $response, $p, 8 ) ); $p += 8;
1227
-						continue;
1228
-					}
1229
-
1230
-					// handle floats
1231
-					if ( $type==SPH_ATTR_FLOAT )
1232
-					{
1233
-						list(,$uval) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1234
-						list(,$fval) = unpack ( "f*", pack ( "L", $uval ) );
1235
-						$attrvals[$attr] = $fval;
1236
-						continue;
1237
-					}
1238
-
1239
-					// handle everything else as unsigned ints
1240
-					list(,$val) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1241
-					if ( $type & SPH_ATTR_MULTI )
1242
-					{
1243
-						$attrvals[$attr] = array ();
1244
-						$nvalues = $val;
1245
-						while ( $nvalues-->0 && $p<$max )
1246
-						{
1247
-							list(,$val) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1248
-							$attrvals[$attr][] = sphFixUint($val);
1249
-						}
1250
-					} else if ( $type==SPH_ATTR_STRING )
1251
-					{
1252
-						$attrvals[$attr] = substr ( $response, $p, $val );
1253
-						$p += $val;
1254
-					} else
1255
-					{
1256
-						$attrvals[$attr] = sphFixUint($val);
1257
-					}
1258
-				}
1259
-
1260
-				if ( $this->_arrayresult )
1261
-					$result["matches"][$idx]["attrs"] = $attrvals;
1262
-				else
1263
-					$result["matches"][$doc]["attrs"] = $attrvals;
1264
-			}
1265
-
1266
-			list ( $total, $total_found, $msecs, $words ) =
1267
-				array_values ( unpack ( "N*N*N*N*", substr ( $response, $p, 16 ) ) );
1268
-			$result["total"] = sprintf ( "%u", $total );
1269
-			$result["total_found"] = sprintf ( "%u", $total_found );
1270
-			$result["time"] = sprintf ( "%.3f", $msecs/1000 );
1271
-			$p += 16;
1272
-
1273
-			while ( $words-->0 && $p<$max )
1274
-			{
1275
-				list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1276
-				$word = substr ( $response, $p, $len ); $p += $len;
1277
-				list ( $docs, $hits ) = array_values ( unpack ( "N*N*", substr ( $response, $p, 8 ) ) ); $p += 8;
1278
-				$result["words"][$word] = array (
1279
-					"docs"=>sprintf ( "%u", $docs ),
1280
-					"hits"=>sprintf ( "%u", $hits ) );
1281
-			}
1282
-		}
1283
-
1284
-		$this->_MBPop ();
1285
-		return $results;
1286
-	}
1287
-
1288
-	/////////////////////////////////////////////////////////////////////////////
1289
-	// excerpts generation
1290
-	/////////////////////////////////////////////////////////////////////////////
1291
-
1292
-	/// connect to searchd server, and generate exceprts (snippets)
1293
-	/// of given documents for given query. returns false on failure,
1294
-	/// an array of snippets on success
1295
-	public function BuildExcerpts ( $docs, $index, $words, $opts=array() )
1296
-	{
1297
-		assert ( is_array($docs) );
1298
-		assert ( is_string($index) );
1299
-		assert ( is_string($words) );
1300
-		assert ( is_array($opts) );
1301
-
1302
-		$this->_MBPush ();
1303
-
1304
-		if (!( $fp = $this->_Connect() ))
1305
-		{
1306
-			$this->_MBPop();
1307
-			return false;
1308
-		}
1309
-
1310
-		/////////////////
1311
-		// fixup options
1312
-		/////////////////
1313
-
1314
-		if ( !isset($opts["before_match"]) )		$opts["before_match"] = "<b>";
1315
-		if ( !isset($opts["after_match"]) )			$opts["after_match"] = "</b>";
1316
-		if ( !isset($opts["chunk_separator"]) )		$opts["chunk_separator"] = " ... ";
1317
-		if ( !isset($opts["limit"]) )				$opts["limit"] = 256;
1318
-		if ( !isset($opts["limit_passages"]) )		$opts["limit_passages"] = 0;
1319
-		if ( !isset($opts["limit_words"]) )			$opts["limit_words"] = 0;
1320
-		if ( !isset($opts["around"]) )				$opts["around"] = 5;
1321
-		if ( !isset($opts["exact_phrase"]) )		$opts["exact_phrase"] = false;
1322
-		if ( !isset($opts["single_passage"]) )		$opts["single_passage"] = false;
1323
-		if ( !isset($opts["use_boundaries"]) )		$opts["use_boundaries"] = false;
1324
-		if ( !isset($opts["weight_order"]) )		$opts["weight_order"] = false;
1325
-		if ( !isset($opts["query_mode"]) )			$opts["query_mode"] = false;
1326
-		if ( !isset($opts["force_all_words"]) )		$opts["force_all_words"] = false;
1327
-		if ( !isset($opts["start_passage_id"]) )	$opts["start_passage_id"] = 1;
1328
-		if ( !isset($opts["load_files"]) )			$opts["load_files"] = false;
1329
-		if ( !isset($opts["html_strip_mode"]) )		$opts["html_strip_mode"] = "index";
1330
-		if ( !isset($opts["allow_empty"]) )			$opts["allow_empty"] = false;
1331
-		if ( !isset($opts["passage_boundary"]) )	$opts["passage_boundary"] = "none";
1332
-		if ( !isset($opts["emit_zones"]) )			$opts["emit_zones"] = false;
1333
-
1334
-		/////////////////
1335
-		// build request
1336
-		/////////////////
1337
-
1338
-		// v.1.2 req
1339
-		$flags = 1; // remove spaces
1340
-		if ( $opts["exact_phrase"] )	$flags |= 2;
1341
-		if ( $opts["single_passage"] )	$flags |= 4;
1342
-		if ( $opts["use_boundaries"] )	$flags |= 8;
1343
-		if ( $opts["weight_order"] )	$flags |= 16;
1344
-		if ( $opts["query_mode"] )		$flags |= 32;
1345
-		if ( $opts["force_all_words"] )	$flags |= 64;
1346
-		if ( $opts["load_files"] )		$flags |= 128;
1347
-		if ( $opts["allow_empty"] )		$flags |= 256;
1348
-		if ( $opts["emit_zones"] )		$flags |= 512;
1349
-		$req = pack ( "NN", 0, $flags ); // mode=0, flags=$flags
1350
-		$req .= pack ( "N", strlen($index) ) . $index; // req index
1351
-		$req .= pack ( "N", strlen($words) ) . $words; // req words
1352
-
1353
-		// options
1354
-		$req .= pack ( "N", strlen($opts["before_match"]) ) . $opts["before_match"];
1355
-		$req .= pack ( "N", strlen($opts["after_match"]) ) . $opts["after_match"];
1356
-		$req .= pack ( "N", strlen($opts["chunk_separator"]) ) . $opts["chunk_separator"];
1357
-		$req .= pack ( "NN", (int)$opts["limit"], (int)$opts["around"] );
1358
-		$req .= pack ( "NNN", (int)$opts["limit_passages"], (int)$opts["limit_words"], (int)$opts["start_passage_id"] ); // v.1.2
1359
-		$req .= pack ( "N", strlen($opts["html_strip_mode"]) ) . $opts["html_strip_mode"];
1360
-		$req .= pack ( "N", strlen($opts["passage_boundary"]) ) . $opts["passage_boundary"];
1361
-
1362
-		// documents
1363
-		$req .= pack ( "N", count($docs) );
1364
-		foreach ( $docs as $doc )
1365
-		{
1366
-			assert ( is_string($doc) );
1367
-			$req .= pack ( "N", strlen($doc) ) . $doc;
1368
-		}
1369
-
1370
-		////////////////////////////
1371
-		// send query, get response
1372
-		////////////////////////////
1373
-
1374
-		$len = strlen($req);
1375
-		$req = pack ( "nnN", SEARCHD_COMMAND_EXCERPT, VER_COMMAND_EXCERPT, $len ) . $req; // add header
1376
-		if ( !( $this->_Send ( $fp, $req, $len+8 ) ) ||
1377
-			 !( $response = $this->_GetResponse ( $fp, VER_COMMAND_EXCERPT ) ) )
1378
-		{
1379
-			$this->_MBPop ();
1380
-			return false;
1381
-		}
1382
-
1383
-		//////////////////
1384
-		// parse response
1385
-		//////////////////
1386
-
1387
-		$pos = 0;
1388
-		$res = array ();
1389
-		$rlen = strlen($response);
1390
-		for ( $i=0; $i<count($docs); $i++ )
1391
-		{
1392
-			list(,$len) = unpack ( "N*", substr ( $response, $pos, 4 ) );
1393
-			$pos += 4;
1394
-
1395
-			if ( $pos+$len > $rlen )
1396
-			{
1397
-				$this->_error = "incomplete reply";
1398
-				$this->_MBPop ();
1399
-				return false;
1400
-			}
1401
-			$res[] = $len ? substr ( $response, $pos, $len ) : "";
1402
-			$pos += $len;
1403
-		}
1404
-
1405
-		$this->_MBPop ();
1406
-		return $res;
1407
-	}
1408
-
1409
-
1410
-	/////////////////////////////////////////////////////////////////////////////
1411
-	// keyword generation
1412
-	/////////////////////////////////////////////////////////////////////////////
1413
-
1414
-	/// connect to searchd server, and generate keyword list for a given query
1415
-	/// returns false on failure,
1416
-	/// an array of words on success
1417
-	public function BuildKeywords ( $query, $index, $hits )
1418
-	{
1419
-		assert ( is_string($query) );
1420
-		assert ( is_string($index) );
1421
-		assert ( is_bool($hits) );
1422
-
1423
-		$this->_MBPush ();
1424
-
1425
-		if (!( $fp = $this->_Connect() ))
1426
-		{
1427
-			$this->_MBPop();
1428
-			return false;
1429
-		}
1430
-
1431
-		/////////////////
1432
-		// build request
1433
-		/////////////////
1434
-
1435
-		// v.1.0 req
1436
-		$req  = pack ( "N", strlen($query) ) . $query; // req query
1437
-		$req .= pack ( "N", strlen($index) ) . $index; // req index
1438
-		$req .= pack ( "N", (int)$hits );
1439
-
1440
-		////////////////////////////
1441
-		// send query, get response
1442
-		////////////////////////////
1443
-
1444
-		$len = strlen($req);
1445
-		$req = pack ( "nnN", SEARCHD_COMMAND_KEYWORDS, VER_COMMAND_KEYWORDS, $len ) . $req; // add header
1446
-		if ( !( $this->_Send ( $fp, $req, $len+8 ) ) ||
1447
-			 !( $response = $this->_GetResponse ( $fp, VER_COMMAND_KEYWORDS ) ) )
1448
-		{
1449
-			$this->_MBPop ();
1450
-			return false;
1451
-		}
1452
-
1453
-		//////////////////
1454
-		// parse response
1455
-		//////////////////
1456
-
1457
-		$pos = 0;
1458
-		$res = array ();
1459
-		$rlen = strlen($response);
1460
-		list(,$nwords) = unpack ( "N*", substr ( $response, $pos, 4 ) );
1461
-		$pos += 4;
1462
-		for ( $i=0; $i<$nwords; $i++ )
1463
-		{
1464
-			list(,$len) = unpack ( "N*", substr ( $response, $pos, 4 ) );	$pos += 4;
1465
-			$tokenized = $len ? substr ( $response, $pos, $len ) : "";
1466
-			$pos += $len;
1467
-
1468
-			list(,$len) = unpack ( "N*", substr ( $response, $pos, 4 ) );	$pos += 4;
1469
-			$normalized = $len ? substr ( $response, $pos, $len ) : "";
1470
-			$pos += $len;
1471
-
1472
-			$res[] = array ( "tokenized"=>$tokenized, "normalized"=>$normalized );
1473
-
1474
-			if ( $hits )
1475
-			{
1476
-				list($ndocs,$nhits) = array_values ( unpack ( "N*N*", substr ( $response, $pos, 8 ) ) );
1477
-				$pos += 8;
1478
-				$res [$i]["docs"] = $ndocs;
1479
-				$res [$i]["hits"] = $nhits;
1480
-			}
1481
-
1482
-			if ( $pos > $rlen )
1483
-			{
1484
-				$this->_error = "incomplete reply";
1485
-				$this->_MBPop ();
1486
-				return false;
1487
-			}
1488
-		}
1489
-
1490
-		$this->_MBPop ();
1491
-		return $res;
1492
-	}
1493
-
1494
-	public function EscapeString ( $string )
1495
-	{
1496
-		$from = array ( '\\', '(',')','|','-','!','@','~','"','&', '/', '^', '$', '=' );
1497
-		$to   = array ( '\\\\', '\(','\)','\|','\-','\!','\@','\~','\"', '\&', '\/', '\^', '\$', '\=' );
1498
-
1499
-		return str_replace ( $from, $to, $string );
1500
-	}
1501
-
1502
-	/////////////////////////////////////////////////////////////////////////////
1503
-	// attribute updates
1504
-	/////////////////////////////////////////////////////////////////////////////
1505
-
1506
-	/// batch update given attributes in given rows in given indexes
1507
-	/// returns amount of updated documents (0 or more) on success, or -1 on failure
1508
-	public function UpdateAttributes ( $index, $attrs, $values, $mva=false )
1509
-	{
1510
-		// verify everything
1511
-		assert ( is_string($index) );
1512
-		assert ( is_bool($mva) );
1513
-
1514
-		assert ( is_array($attrs) );
1515
-		foreach ( $attrs as $attr )
1516
-			assert ( is_string($attr) );
1517
-
1518
-		assert ( is_array($values) );
1519
-		foreach ( $values as $id=>$entry )
1520
-		{
1521
-			assert ( is_numeric($id) );
1522
-			assert ( is_array($entry) );
1523
-			assert ( count($entry)==count($attrs) );
1524
-			foreach ( $entry as $v )
1525
-			{
1526
-				if ( $mva )
1527
-				{
1528
-					assert ( is_array($v) );
1529
-					foreach ( $v as $vv )
1530
-						assert ( is_int($vv) );
1531
-				} else
1532
-					assert ( is_int($v) );
1533
-			}
1534
-		}
1535
-
1536
-		// build request
1537
-		$this->_MBPush ();
1538
-		$req = pack ( "N", strlen($index) ) . $index;
1539
-
1540
-		$req .= pack ( "N", count($attrs) );
1541
-		foreach ( $attrs as $attr )
1542
-		{
1543
-			$req .= pack ( "N", strlen($attr) ) . $attr;
1544
-			$req .= pack ( "N", $mva ? 1 : 0 );
1545
-		}
1546
-
1547
-		$req .= pack ( "N", count($values) );
1548
-		foreach ( $values as $id=>$entry )
1549
-		{
1550
-			$req .= sphPackU64 ( $id );
1551
-			foreach ( $entry as $v )
1552
-			{
1553
-				$req .= pack ( "N", $mva ? count($v) : $v );
1554
-				if ( $mva )
1555
-					foreach ( $v as $vv )
1556
-						$req .= pack ( "N", $vv );
1557
-			}
1558
-		}
1559
-
1560
-		// connect, send query, get response
1561
-		if (!( $fp = $this->_Connect() ))
1562
-		{
1563
-			$this->_MBPop ();
1564
-			return -1;
1565
-		}
1566
-
1567
-		$len = strlen($req);
1568
-		$req = pack ( "nnN", SEARCHD_COMMAND_UPDATE, VER_COMMAND_UPDATE, $len ) . $req; // add header
1569
-		if ( !$this->_Send ( $fp, $req, $len+8 ) )
1570
-		{
1571
-			$this->_MBPop ();
1572
-			return -1;
1573
-		}
1574
-
1575
-		if (!( $response = $this->_GetResponse ( $fp, VER_COMMAND_UPDATE ) ))
1576
-		{
1577
-			$this->_MBPop ();
1578
-			return -1;
1579
-		}
1580
-
1581
-		// parse response
1582
-		list(,$updated) = unpack ( "N*", substr ( $response, 0, 4 ) );
1583
-		$this->_MBPop ();
1584
-		return $updated;
1585
-	}
1586
-
1587
-	/////////////////////////////////////////////////////////////////////////////
1588
-	// persistent connections
1589
-	/////////////////////////////////////////////////////////////////////////////
1590
-
1591
-	public function Open()
1592
-	{
1593
-		if ( $this->_socket !== false )
1594
-		{
1595
-			$this->_error = 'already connected';
1596
-			return false;
1597
-		}
1598
-		if ( !$fp = $this->_Connect() )
1599
-			return false;
1600
-
1601
-		// command, command version = 0, body length = 4, body = 1
1602
-		$req = pack ( "nnNN", SEARCHD_COMMAND_PERSIST, 0, 4, 1 );
1603
-		if ( !$this->_Send ( $fp, $req, 12 ) )
1604
-			return false;
1605
-
1606
-		$this->_socket = $fp;
1607
-		return true;
1608
-	}
1609
-
1610
-	public function Close()
1611
-	{
1612
-		if ( $this->_socket === false )
1613
-		{
1614
-			$this->_error = 'not connected';
1615
-			return false;
1616
-		}
1617
-
1618
-		fclose ( $this->_socket );
1619
-		$this->_socket = false;
1620
-
1621
-		return true;
1622
-	}
1623
-
1624
-	//////////////////////////////////////////////////////////////////////////
1625
-	// status
1626
-	//////////////////////////////////////////////////////////////////////////
1627
-
1628
-	public function Status ()
1629
-	{
1630
-		$this->_MBPush ();
1631
-		if (!( $fp = $this->_Connect() ))
1632
-		{
1633
-			$this->_MBPop();
1634
-			return false;
1635
-		}
1636
-
1637
-		$req = pack ( "nnNN", SEARCHD_COMMAND_STATUS, VER_COMMAND_STATUS, 4, 1 ); // len=4, body=1
1638
-		if ( !( $this->_Send ( $fp, $req, 12 ) ) ||
1639
-			 !( $response = $this->_GetResponse ( $fp, VER_COMMAND_STATUS ) ) )
1640
-		{
1641
-			$this->_MBPop ();
1642
-			return false;
1643
-		}
1644
-
1645
-		$res = substr ( $response, 4 ); // just ignore length, error handling, etc
1646
-		$p = 0;
1647
-		list ( $rows, $cols ) = array_values ( unpack ( "N*N*", substr ( $response, $p, 8 ) ) ); $p += 8;
1648
-
1649
-		$res = array();
1650
-		for ( $i=0; $i<$rows; $i++ )
1651
-			for ( $j=0; $j<$cols; $j++ )
1652
-		{
1653
-			list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1654
-			$res[$i][] = substr ( $response, $p, $len ); $p += $len;
1655
-		}
1656
-
1657
-		$this->_MBPop ();
1658
-		return $res;
1659
-	}
1660
-
1661
-	//////////////////////////////////////////////////////////////////////////
1662
-	// flush
1663
-	//////////////////////////////////////////////////////////////////////////
1664
-
1665
-	public function FlushAttributes ()
1666
-	{
1667
-		$this->_MBPush ();
1668
-		if (!( $fp = $this->_Connect() ))
1669
-		{
1670
-			$this->_MBPop();
1671
-			return -1;
1672
-		}
1673
-
1674
-		$req = pack ( "nnN", SEARCHD_COMMAND_FLUSHATTRS, VER_COMMAND_FLUSHATTRS, 0 ); // len=0
1675
-		if ( !( $this->_Send ( $fp, $req, 8 ) ) ||
1676
-			 !( $response = $this->_GetResponse ( $fp, VER_COMMAND_FLUSHATTRS ) ) )
1677
-		{
1678
-			$this->_MBPop ();
1679
-			return -1;
1680
-		}
1681
-
1682
-		$tag = -1;
1683
-		if ( strlen($response)==4 )
1684
-			list(,$tag) = unpack ( "N*", $response );
1685
-		else
1686
-			$this->_error = "unexpected response length";
1687
-
1688
-		$this->_MBPop ();
1689
-		return $tag;
1690
-	}
945
+    //////////////////////////////////////////////////////////////////////////////
946
+
947
+    /// connect to searchd server, run given search query through given indexes,
948
+    /// and return the search results
949
+    public function Query ( $query, $index="*", $comment="" )
950
+    {
951
+        assert ( empty($this->_reqs) );
952
+
953
+        $this->AddQuery ( $query, $index, $comment );
954
+        $results = $this->RunQueries ();
955
+        $this->_reqs = array (); // just in case it failed too early
956
+
957
+        if ( !is_array($results) )
958
+            return false; // probably network error; error message should be already filled
959
+
960
+        $this->_error = $results[0]["error"];
961
+        $this->_warning = $results[0]["warning"];
962
+        if ( $results[0]["status"]==SEARCHD_ERROR )
963
+            return false;
964
+        else
965
+            return $results[0];
966
+    }
967
+
968
+    /// helper to pack floats in network byte order
969
+    public function _PackFloat ( $f )
970
+    {
971
+        $t1 = pack ( "f", $f ); // machine order
972
+        list(,$t2) = unpack ( "L*", $t1 ); // int in machine order
973
+        return pack ( "N", $t2 );
974
+    }
975
+
976
+    /**
977
+     * @SuppressWarnings(unused)
978
+     */
979
+
980
+    /// add query to multi-query batch
981
+    /// returns index into results array from RunQueries() call
982
+    public function AddQuery ( $query, $index="*", $comment="" )
983
+    {
984
+        // mbstring workaround
985
+        $this->_MBPush ();
986
+
987
+        // build request
988
+        $req = pack ( "NNNNN", $this->_offset, $this->_limit, $this->_mode, $this->_ranker, $this->_sort ); // mode and limits
989
+        $req .= pack ( "N", strlen($this->_sortby) ) . $this->_sortby;
990
+        $req .= pack ( "N", strlen($query) ) . $query; // query itself
991
+        $req .= pack ( "N", count($this->_weights) ); // weights
992
+        foreach ( $this->_weights as $weight )
993
+            $req .= pack ( "N", (int)$weight );
994
+        $req .= pack ( "N", strlen($index) ) . $index; // indexes
995
+        $req .= pack ( "N", 1 ); // id64 range marker
996
+        $req .= sphPackU64 ( $this->_min_id ) . sphPackU64 ( $this->_max_id ); // id64 range
997
+
998
+        // filters
999
+        $req .= pack ( "N", count($this->_filters) );
1000
+        foreach ( $this->_filters as $filter )
1001
+        {
1002
+            $req .= pack ( "N", strlen($filter["attr"]) ) . $filter["attr"];
1003
+            $req .= pack ( "N", $filter["type"] );
1004
+            switch ( $filter["type"] )
1005
+            {
1006
+                case SPH_FILTER_VALUES:
1007
+                    $req .= pack ( "N", count($filter["values"]) );
1008
+                    foreach ( $filter["values"] as $value )
1009
+                        $req .= sphPackI64 ( $value );
1010
+                    break;
1011
+
1012
+                case SPH_FILTER_RANGE:
1013
+                    $req .= sphPackI64 ( $filter["min"] ) . sphPackI64 ( $filter["max"] );
1014
+                    break;
1015
+
1016
+                case SPH_FILTER_FLOATRANGE:
1017
+                    $req .= $this->_PackFloat ( $filter["min"] ) . $this->_PackFloat ( $filter["max"] );
1018
+                    break;
1019
+
1020
+                default:
1021
+                    assert ( 0 && "internal error: unhandled filter type" );
1022
+            }
1023
+            $req .= pack ( "N", $filter["exclude"] );
1024
+        }
1025
+
1026
+        // group-by clause, max-matches count, group-sort clause, cutoff count
1027
+        $req .= pack ( "NN", $this->_groupfunc, strlen($this->_groupby) ) . $this->_groupby;
1028
+        $req .= pack ( "N", $this->_maxmatches );
1029
+        $req .= pack ( "N", strlen($this->_groupsort) ) . $this->_groupsort;
1030
+        $req .= pack ( "NNN", $this->_cutoff, $this->_retrycount, $this->_retrydelay );
1031
+        $req .= pack ( "N", strlen($this->_groupdistinct) ) . $this->_groupdistinct;
1032
+
1033
+        // anchor point
1034
+        if ( empty($this->_anchor) )
1035
+        {
1036
+            $req .= pack ( "N", 0 );
1037
+        } else
1038
+        {
1039
+            $a =& $this->_anchor;
1040
+            $req .= pack ( "N", 1 );
1041
+            $req .= pack ( "N", strlen($a["attrlat"]) ) . $a["attrlat"];
1042
+            $req .= pack ( "N", strlen($a["attrlong"]) ) . $a["attrlong"];
1043
+            $req .= $this->_PackFloat ( $a["lat"] ) . $this->_PackFloat ( $a["long"] );
1044
+        }
1045
+
1046
+        // per-index weights
1047
+        $req .= pack ( "N", count($this->_indexweights) );
1048
+        foreach ( $this->_indexweights as $idx=>$weight )
1049
+            $req .= pack ( "N", strlen($idx) ) . $idx . pack ( "N", $weight );
1050
+
1051
+        // max query time
1052
+        $req .= pack ( "N", $this->_maxquerytime );
1053
+
1054
+        // per-field weights
1055
+        $req .= pack ( "N", count($this->_fieldweights) );
1056
+        foreach ( $this->_fieldweights as $field=>$weight )
1057
+            $req .= pack ( "N", strlen($field) ) . $field . pack ( "N", $weight );
1058
+
1059
+        // comment
1060
+        $req .= pack ( "N", strlen($comment) ) . $comment;
1061
+
1062
+        // attribute overrides
1063
+        $req .= pack ( "N", count($this->_overrides) );
1064
+        foreach ( $this->_overrides as $key => $entry )
1065
+        {
1066
+            $req .= pack ( "N", strlen($entry["attr"]) ) . $entry["attr"];
1067
+            $req .= pack ( "NN", $entry["type"], count($entry["values"]) );
1068
+            foreach ( $entry["values"] as $id=>$val )
1069
+            {
1070
+                assert ( is_numeric($id) );
1071
+                assert ( is_numeric($val) );
1072
+
1073
+                $req .= sphPackU64 ( $id );
1074
+                switch ( $entry["type"] )
1075
+                {
1076
+                    case SPH_ATTR_FLOAT:	$req .= $this->_PackFloat ( $val ); break;
1077
+                    case SPH_ATTR_BIGINT:	$req .= sphPackI64 ( $val ); break;
1078
+                    default:				$req .= pack ( "N", $val ); break;
1079
+                }
1080
+            }
1081
+        }
1082
+
1083
+        // select-list
1084
+        $req .= pack ( "N", strlen($this->_select) ) . $this->_select;
1085
+
1086
+        // mbstring workaround
1087
+        $this->_MBPop ();
1088
+
1089
+        // store request to requests array
1090
+        $this->_reqs[] = $req;
1091
+        return count($this->_reqs)-1;
1092
+    }
1093
+
1094
+    /// connect to searchd, run queries batch, and return an array of result sets
1095
+    public function RunQueries ()
1096
+    {
1097
+        if ( empty($this->_reqs) )
1098
+        {
1099
+            $this->_error = "no queries defined, issue AddQuery() first";
1100
+            return false;
1101
+        }
1102
+
1103
+        // mbstring workaround
1104
+        $this->_MBPush ();
1105
+
1106
+        if (!( $fp = $this->_Connect() ))
1107
+        {
1108
+            $this->_MBPop ();
1109
+            return false;
1110
+        }
1111
+
1112
+        // send query, get response
1113
+        $nreqs = count($this->_reqs);
1114
+        $req = join ( "", $this->_reqs );
1115
+        $len = 8+strlen($req);
1116
+        $req = pack ( "nnNNN", SEARCHD_COMMAND_SEARCH, VER_COMMAND_SEARCH, $len, 0, $nreqs ) . $req; // add header
1117
+
1118
+        if ( !( $this->_Send ( $fp, $req, $len+8 ) ) ||
1119
+             !( $response = $this->_GetResponse ( $fp, VER_COMMAND_SEARCH ) ) )
1120
+        {
1121
+            $this->_MBPop ();
1122
+            return false;
1123
+        }
1124
+
1125
+        // query sent ok; we can reset reqs now
1126
+        $this->_reqs = array ();
1127
+
1128
+        // parse and return response
1129
+        return $this->_ParseSearchResponse ( $response, $nreqs );
1130
+    }
1131
+
1132
+    /// parse and return search query (or queries) response
1133
+    public function _ParseSearchResponse ( $response, $nreqs )
1134
+    {
1135
+        $p = 0; // current position
1136
+        $max = strlen($response); // max position for checks, to protect against broken responses
1137
+
1138
+        $results = array ();
1139
+        for ( $ires=0; $ires<$nreqs && $p<$max; $ires++ )
1140
+        {
1141
+            $results[] = array();
1142
+            $result =& $results[$ires];
1143
+
1144
+            $result["error"] = "";
1145
+            $result["warning"] = "";
1146
+
1147
+            // extract status
1148
+            list(,$status) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1149
+            $result["status"] = $status;
1150
+            if ( $status!=SEARCHD_OK )
1151
+            {
1152
+                list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1153
+                $message = substr ( $response, $p, $len ); $p += $len;
1154
+
1155
+                if ( $status==SEARCHD_WARNING )
1156
+                {
1157
+                    $result["warning"] = $message;
1158
+                } else
1159
+                {
1160
+                    $result["error"] = $message;
1161
+                    continue;
1162
+                }
1163
+            }
1164
+
1165
+            // read schema
1166
+            $fields = array ();
1167
+            $attrs = array ();
1168
+
1169
+            list(,$nfields) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1170
+            while ( $nfields-->0 && $p<$max )
1171
+            {
1172
+                list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1173
+                $fields[] = substr ( $response, $p, $len ); $p += $len;
1174
+            }
1175
+            $result["fields"] = $fields;
1176
+
1177
+            list(,$nattrs) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1178
+            while ( $nattrs-->0 && $p<$max  )
1179
+            {
1180
+                list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1181
+                $attr = substr ( $response, $p, $len ); $p += $len;
1182
+                list(,$type) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1183
+                $attrs[$attr] = $type;
1184
+            }
1185
+            $result["attrs"] = $attrs;
1186
+
1187
+            // read match count
1188
+            list(,$count) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1189
+            list(,$id64) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1190
+
1191
+            // read matches
1192
+            $idx = -1;
1193
+            while ( $count-->0 && $p<$max )
1194
+            {
1195
+                // index into result array
1196
+                $idx++;
1197
+
1198
+                // parse document id and weight
1199
+                if ( $id64 )
1200
+                {
1201
+                    $doc = sphUnpackU64 ( substr ( $response, $p, 8 ) ); $p += 8;
1202
+                    list(,$weight) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1203
+                }
1204
+                else
1205
+                {
1206
+                    list ( $doc, $weight ) = array_values ( unpack ( "N*N*",
1207
+                        substr ( $response, $p, 8 ) ) );
1208
+                    $p += 8;
1209
+                    $doc = sphFixUint($doc);
1210
+                }
1211
+                $weight = sprintf ( "%u", $weight );
1212
+
1213
+                // create match entry
1214
+                if ( $this->_arrayresult )
1215
+                    $result["matches"][$idx] = array ( "id"=>$doc, "weight"=>$weight );
1216
+                else
1217
+                    $result["matches"][$doc]["weight"] = $weight;
1218
+
1219
+                // parse and create attributes
1220
+                $attrvals = array ();
1221
+                foreach ( $attrs as $attr=>$type )
1222
+                {
1223
+                    // handle 64bit ints
1224
+                    if ( $type==SPH_ATTR_BIGINT )
1225
+                    {
1226
+                        $attrvals[$attr] = sphUnpackI64 ( substr ( $response, $p, 8 ) ); $p += 8;
1227
+                        continue;
1228
+                    }
1229
+
1230
+                    // handle floats
1231
+                    if ( $type==SPH_ATTR_FLOAT )
1232
+                    {
1233
+                        list(,$uval) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1234
+                        list(,$fval) = unpack ( "f*", pack ( "L", $uval ) );
1235
+                        $attrvals[$attr] = $fval;
1236
+                        continue;
1237
+                    }
1238
+
1239
+                    // handle everything else as unsigned ints
1240
+                    list(,$val) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1241
+                    if ( $type & SPH_ATTR_MULTI )
1242
+                    {
1243
+                        $attrvals[$attr] = array ();
1244
+                        $nvalues = $val;
1245
+                        while ( $nvalues-->0 && $p<$max )
1246
+                        {
1247
+                            list(,$val) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1248
+                            $attrvals[$attr][] = sphFixUint($val);
1249
+                        }
1250
+                    } else if ( $type==SPH_ATTR_STRING )
1251
+                    {
1252
+                        $attrvals[$attr] = substr ( $response, $p, $val );
1253
+                        $p += $val;
1254
+                    } else
1255
+                    {
1256
+                        $attrvals[$attr] = sphFixUint($val);
1257
+                    }
1258
+                }
1259
+
1260
+                if ( $this->_arrayresult )
1261
+                    $result["matches"][$idx]["attrs"] = $attrvals;
1262
+                else
1263
+                    $result["matches"][$doc]["attrs"] = $attrvals;
1264
+            }
1265
+
1266
+            list ( $total, $total_found, $msecs, $words ) =
1267
+                array_values ( unpack ( "N*N*N*N*", substr ( $response, $p, 16 ) ) );
1268
+            $result["total"] = sprintf ( "%u", $total );
1269
+            $result["total_found"] = sprintf ( "%u", $total_found );
1270
+            $result["time"] = sprintf ( "%.3f", $msecs/1000 );
1271
+            $p += 16;
1272
+
1273
+            while ( $words-->0 && $p<$max )
1274
+            {
1275
+                list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1276
+                $word = substr ( $response, $p, $len ); $p += $len;
1277
+                list ( $docs, $hits ) = array_values ( unpack ( "N*N*", substr ( $response, $p, 8 ) ) ); $p += 8;
1278
+                $result["words"][$word] = array (
1279
+                    "docs"=>sprintf ( "%u", $docs ),
1280
+                    "hits"=>sprintf ( "%u", $hits ) );
1281
+            }
1282
+        }
1283
+
1284
+        $this->_MBPop ();
1285
+        return $results;
1286
+    }
1287
+
1288
+    /////////////////////////////////////////////////////////////////////////////
1289
+    // excerpts generation
1290
+    /////////////////////////////////////////////////////////////////////////////
1291
+
1292
+    /// connect to searchd server, and generate exceprts (snippets)
1293
+    /// of given documents for given query. returns false on failure,
1294
+    /// an array of snippets on success
1295
+    public function BuildExcerpts ( $docs, $index, $words, $opts=array() )
1296
+    {
1297
+        assert ( is_array($docs) );
1298
+        assert ( is_string($index) );
1299
+        assert ( is_string($words) );
1300
+        assert ( is_array($opts) );
1301
+
1302
+        $this->_MBPush ();
1303
+
1304
+        if (!( $fp = $this->_Connect() ))
1305
+        {
1306
+            $this->_MBPop();
1307
+            return false;
1308
+        }
1309
+
1310
+        /////////////////
1311
+        // fixup options
1312
+        /////////////////
1313
+
1314
+        if ( !isset($opts["before_match"]) )		$opts["before_match"] = "<b>";
1315
+        if ( !isset($opts["after_match"]) )			$opts["after_match"] = "</b>";
1316
+        if ( !isset($opts["chunk_separator"]) )		$opts["chunk_separator"] = " ... ";
1317
+        if ( !isset($opts["limit"]) )				$opts["limit"] = 256;
1318
+        if ( !isset($opts["limit_passages"]) )		$opts["limit_passages"] = 0;
1319
+        if ( !isset($opts["limit_words"]) )			$opts["limit_words"] = 0;
1320
+        if ( !isset($opts["around"]) )				$opts["around"] = 5;
1321
+        if ( !isset($opts["exact_phrase"]) )		$opts["exact_phrase"] = false;
1322
+        if ( !isset($opts["single_passage"]) )		$opts["single_passage"] = false;
1323
+        if ( !isset($opts["use_boundaries"]) )		$opts["use_boundaries"] = false;
1324
+        if ( !isset($opts["weight_order"]) )		$opts["weight_order"] = false;
1325
+        if ( !isset($opts["query_mode"]) )			$opts["query_mode"] = false;
1326
+        if ( !isset($opts["force_all_words"]) )		$opts["force_all_words"] = false;
1327
+        if ( !isset($opts["start_passage_id"]) )	$opts["start_passage_id"] = 1;
1328
+        if ( !isset($opts["load_files"]) )			$opts["load_files"] = false;
1329
+        if ( !isset($opts["html_strip_mode"]) )		$opts["html_strip_mode"] = "index";
1330
+        if ( !isset($opts["allow_empty"]) )			$opts["allow_empty"] = false;
1331
+        if ( !isset($opts["passage_boundary"]) )	$opts["passage_boundary"] = "none";
1332
+        if ( !isset($opts["emit_zones"]) )			$opts["emit_zones"] = false;
1333
+
1334
+        /////////////////
1335
+        // build request
1336
+        /////////////////
1337
+
1338
+        // v.1.2 req
1339
+        $flags = 1; // remove spaces
1340
+        if ( $opts["exact_phrase"] )	$flags |= 2;
1341
+        if ( $opts["single_passage"] )	$flags |= 4;
1342
+        if ( $opts["use_boundaries"] )	$flags |= 8;
1343
+        if ( $opts["weight_order"] )	$flags |= 16;
1344
+        if ( $opts["query_mode"] )		$flags |= 32;
1345
+        if ( $opts["force_all_words"] )	$flags |= 64;
1346
+        if ( $opts["load_files"] )		$flags |= 128;
1347
+        if ( $opts["allow_empty"] )		$flags |= 256;
1348
+        if ( $opts["emit_zones"] )		$flags |= 512;
1349
+        $req = pack ( "NN", 0, $flags ); // mode=0, flags=$flags
1350
+        $req .= pack ( "N", strlen($index) ) . $index; // req index
1351
+        $req .= pack ( "N", strlen($words) ) . $words; // req words
1352
+
1353
+        // options
1354
+        $req .= pack ( "N", strlen($opts["before_match"]) ) . $opts["before_match"];
1355
+        $req .= pack ( "N", strlen($opts["after_match"]) ) . $opts["after_match"];
1356
+        $req .= pack ( "N", strlen($opts["chunk_separator"]) ) . $opts["chunk_separator"];
1357
+        $req .= pack ( "NN", (int)$opts["limit"], (int)$opts["around"] );
1358
+        $req .= pack ( "NNN", (int)$opts["limit_passages"], (int)$opts["limit_words"], (int)$opts["start_passage_id"] ); // v.1.2
1359
+        $req .= pack ( "N", strlen($opts["html_strip_mode"]) ) . $opts["html_strip_mode"];
1360
+        $req .= pack ( "N", strlen($opts["passage_boundary"]) ) . $opts["passage_boundary"];
1361
+
1362
+        // documents
1363
+        $req .= pack ( "N", count($docs) );
1364
+        foreach ( $docs as $doc )
1365
+        {
1366
+            assert ( is_string($doc) );
1367
+            $req .= pack ( "N", strlen($doc) ) . $doc;
1368
+        }
1369
+
1370
+        ////////////////////////////
1371
+        // send query, get response
1372
+        ////////////////////////////
1373
+
1374
+        $len = strlen($req);
1375
+        $req = pack ( "nnN", SEARCHD_COMMAND_EXCERPT, VER_COMMAND_EXCERPT, $len ) . $req; // add header
1376
+        if ( !( $this->_Send ( $fp, $req, $len+8 ) ) ||
1377
+             !( $response = $this->_GetResponse ( $fp, VER_COMMAND_EXCERPT ) ) )
1378
+        {
1379
+            $this->_MBPop ();
1380
+            return false;
1381
+        }
1382
+
1383
+        //////////////////
1384
+        // parse response
1385
+        //////////////////
1386
+
1387
+        $pos = 0;
1388
+        $res = array ();
1389
+        $rlen = strlen($response);
1390
+        for ( $i=0; $i<count($docs); $i++ )
1391
+        {
1392
+            list(,$len) = unpack ( "N*", substr ( $response, $pos, 4 ) );
1393
+            $pos += 4;
1394
+
1395
+            if ( $pos+$len > $rlen )
1396
+            {
1397
+                $this->_error = "incomplete reply";
1398
+                $this->_MBPop ();
1399
+                return false;
1400
+            }
1401
+            $res[] = $len ? substr ( $response, $pos, $len ) : "";
1402
+            $pos += $len;
1403
+        }
1404
+
1405
+        $this->_MBPop ();
1406
+        return $res;
1407
+    }
1408
+
1409
+
1410
+    /////////////////////////////////////////////////////////////////////////////
1411
+    // keyword generation
1412
+    /////////////////////////////////////////////////////////////////////////////
1413
+
1414
+    /// connect to searchd server, and generate keyword list for a given query
1415
+    /// returns false on failure,
1416
+    /// an array of words on success
1417
+    public function BuildKeywords ( $query, $index, $hits )
1418
+    {
1419
+        assert ( is_string($query) );
1420
+        assert ( is_string($index) );
1421
+        assert ( is_bool($hits) );
1422
+
1423
+        $this->_MBPush ();
1424
+
1425
+        if (!( $fp = $this->_Connect() ))
1426
+        {
1427
+            $this->_MBPop();
1428
+            return false;
1429
+        }
1430
+
1431
+        /////////////////
1432
+        // build request
1433
+        /////////////////
1434
+
1435
+        // v.1.0 req
1436
+        $req  = pack ( "N", strlen($query) ) . $query; // req query
1437
+        $req .= pack ( "N", strlen($index) ) . $index; // req index
1438
+        $req .= pack ( "N", (int)$hits );
1439
+
1440
+        ////////////////////////////
1441
+        // send query, get response
1442
+        ////////////////////////////
1443
+
1444
+        $len = strlen($req);
1445
+        $req = pack ( "nnN", SEARCHD_COMMAND_KEYWORDS, VER_COMMAND_KEYWORDS, $len ) . $req; // add header
1446
+        if ( !( $this->_Send ( $fp, $req, $len+8 ) ) ||
1447
+             !( $response = $this->_GetResponse ( $fp, VER_COMMAND_KEYWORDS ) ) )
1448
+        {
1449
+            $this->_MBPop ();
1450
+            return false;
1451
+        }
1452
+
1453
+        //////////////////
1454
+        // parse response
1455
+        //////////////////
1456
+
1457
+        $pos = 0;
1458
+        $res = array ();
1459
+        $rlen = strlen($response);
1460
+        list(,$nwords) = unpack ( "N*", substr ( $response, $pos, 4 ) );
1461
+        $pos += 4;
1462
+        for ( $i=0; $i<$nwords; $i++ )
1463
+        {
1464
+            list(,$len) = unpack ( "N*", substr ( $response, $pos, 4 ) );	$pos += 4;
1465
+            $tokenized = $len ? substr ( $response, $pos, $len ) : "";
1466
+            $pos += $len;
1467
+
1468
+            list(,$len) = unpack ( "N*", substr ( $response, $pos, 4 ) );	$pos += 4;
1469
+            $normalized = $len ? substr ( $response, $pos, $len ) : "";
1470
+            $pos += $len;
1471
+
1472
+            $res[] = array ( "tokenized"=>$tokenized, "normalized"=>$normalized );
1473
+
1474
+            if ( $hits )
1475
+            {
1476
+                list($ndocs,$nhits) = array_values ( unpack ( "N*N*", substr ( $response, $pos, 8 ) ) );
1477
+                $pos += 8;
1478
+                $res [$i]["docs"] = $ndocs;
1479
+                $res [$i]["hits"] = $nhits;
1480
+            }
1481
+
1482
+            if ( $pos > $rlen )
1483
+            {
1484
+                $this->_error = "incomplete reply";
1485
+                $this->_MBPop ();
1486
+                return false;
1487
+            }
1488
+        }
1489
+
1490
+        $this->_MBPop ();
1491
+        return $res;
1492
+    }
1493
+
1494
+    public function EscapeString ( $string )
1495
+    {
1496
+        $from = array ( '\\', '(',')','|','-','!','@','~','"','&', '/', '^', '$', '=' );
1497
+        $to   = array ( '\\\\', '\(','\)','\|','\-','\!','\@','\~','\"', '\&', '\/', '\^', '\$', '\=' );
1498
+
1499
+        return str_replace ( $from, $to, $string );
1500
+    }
1501
+
1502
+    /////////////////////////////////////////////////////////////////////////////
1503
+    // attribute updates
1504
+    /////////////////////////////////////////////////////////////////////////////
1505
+
1506
+    /// batch update given attributes in given rows in given indexes
1507
+    /// returns amount of updated documents (0 or more) on success, or -1 on failure
1508
+    public function UpdateAttributes ( $index, $attrs, $values, $mva=false )
1509
+    {
1510
+        // verify everything
1511
+        assert ( is_string($index) );
1512
+        assert ( is_bool($mva) );
1513
+
1514
+        assert ( is_array($attrs) );
1515
+        foreach ( $attrs as $attr )
1516
+            assert ( is_string($attr) );
1517
+
1518
+        assert ( is_array($values) );
1519
+        foreach ( $values as $id=>$entry )
1520
+        {
1521
+            assert ( is_numeric($id) );
1522
+            assert ( is_array($entry) );
1523
+            assert ( count($entry)==count($attrs) );
1524
+            foreach ( $entry as $v )
1525
+            {
1526
+                if ( $mva )
1527
+                {
1528
+                    assert ( is_array($v) );
1529
+                    foreach ( $v as $vv )
1530
+                        assert ( is_int($vv) );
1531
+                } else
1532
+                    assert ( is_int($v) );
1533
+            }
1534
+        }
1535
+
1536
+        // build request
1537
+        $this->_MBPush ();
1538
+        $req = pack ( "N", strlen($index) ) . $index;
1539
+
1540
+        $req .= pack ( "N", count($attrs) );
1541
+        foreach ( $attrs as $attr )
1542
+        {
1543
+            $req .= pack ( "N", strlen($attr) ) . $attr;
1544
+            $req .= pack ( "N", $mva ? 1 : 0 );
1545
+        }
1546
+
1547
+        $req .= pack ( "N", count($values) );
1548
+        foreach ( $values as $id=>$entry )
1549
+        {
1550
+            $req .= sphPackU64 ( $id );
1551
+            foreach ( $entry as $v )
1552
+            {
1553
+                $req .= pack ( "N", $mva ? count($v) : $v );
1554
+                if ( $mva )
1555
+                    foreach ( $v as $vv )
1556
+                        $req .= pack ( "N", $vv );
1557
+            }
1558
+        }
1559
+
1560
+        // connect, send query, get response
1561
+        if (!( $fp = $this->_Connect() ))
1562
+        {
1563
+            $this->_MBPop ();
1564
+            return -1;
1565
+        }
1566
+
1567
+        $len = strlen($req);
1568
+        $req = pack ( "nnN", SEARCHD_COMMAND_UPDATE, VER_COMMAND_UPDATE, $len ) . $req; // add header
1569
+        if ( !$this->_Send ( $fp, $req, $len+8 ) )
1570
+        {
1571
+            $this->_MBPop ();
1572
+            return -1;
1573
+        }
1574
+
1575
+        if (!( $response = $this->_GetResponse ( $fp, VER_COMMAND_UPDATE ) ))
1576
+        {
1577
+            $this->_MBPop ();
1578
+            return -1;
1579
+        }
1580
+
1581
+        // parse response
1582
+        list(,$updated) = unpack ( "N*", substr ( $response, 0, 4 ) );
1583
+        $this->_MBPop ();
1584
+        return $updated;
1585
+    }
1586
+
1587
+    /////////////////////////////////////////////////////////////////////////////
1588
+    // persistent connections
1589
+    /////////////////////////////////////////////////////////////////////////////
1590
+
1591
+    public function Open()
1592
+    {
1593
+        if ( $this->_socket !== false )
1594
+        {
1595
+            $this->_error = 'already connected';
1596
+            return false;
1597
+        }
1598
+        if ( !$fp = $this->_Connect() )
1599
+            return false;
1600
+
1601
+        // command, command version = 0, body length = 4, body = 1
1602
+        $req = pack ( "nnNN", SEARCHD_COMMAND_PERSIST, 0, 4, 1 );
1603
+        if ( !$this->_Send ( $fp, $req, 12 ) )
1604
+            return false;
1605
+
1606
+        $this->_socket = $fp;
1607
+        return true;
1608
+    }
1609
+
1610
+    public function Close()
1611
+    {
1612
+        if ( $this->_socket === false )
1613
+        {
1614
+            $this->_error = 'not connected';
1615
+            return false;
1616
+        }
1617
+
1618
+        fclose ( $this->_socket );
1619
+        $this->_socket = false;
1620
+
1621
+        return true;
1622
+    }
1623
+
1624
+    //////////////////////////////////////////////////////////////////////////
1625
+    // status
1626
+    //////////////////////////////////////////////////////////////////////////
1627
+
1628
+    public function Status ()
1629
+    {
1630
+        $this->_MBPush ();
1631
+        if (!( $fp = $this->_Connect() ))
1632
+        {
1633
+            $this->_MBPop();
1634
+            return false;
1635
+        }
1636
+
1637
+        $req = pack ( "nnNN", SEARCHD_COMMAND_STATUS, VER_COMMAND_STATUS, 4, 1 ); // len=4, body=1
1638
+        if ( !( $this->_Send ( $fp, $req, 12 ) ) ||
1639
+             !( $response = $this->_GetResponse ( $fp, VER_COMMAND_STATUS ) ) )
1640
+        {
1641
+            $this->_MBPop ();
1642
+            return false;
1643
+        }
1644
+
1645
+        $res = substr ( $response, 4 ); // just ignore length, error handling, etc
1646
+        $p = 0;
1647
+        list ( $rows, $cols ) = array_values ( unpack ( "N*N*", substr ( $response, $p, 8 ) ) ); $p += 8;
1648
+
1649
+        $res = array();
1650
+        for ( $i=0; $i<$rows; $i++ )
1651
+            for ( $j=0; $j<$cols; $j++ )
1652
+        {
1653
+            list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
1654
+            $res[$i][] = substr ( $response, $p, $len ); $p += $len;
1655
+        }
1656
+
1657
+        $this->_MBPop ();
1658
+        return $res;
1659
+    }
1660
+
1661
+    //////////////////////////////////////////////////////////////////////////
1662
+    // flush
1663
+    //////////////////////////////////////////////////////////////////////////
1664
+
1665
+    public function FlushAttributes ()
1666
+    {
1667
+        $this->_MBPush ();
1668
+        if (!( $fp = $this->_Connect() ))
1669
+        {
1670
+            $this->_MBPop();
1671
+            return -1;
1672
+        }
1673
+
1674
+        $req = pack ( "nnN", SEARCHD_COMMAND_FLUSHATTRS, VER_COMMAND_FLUSHATTRS, 0 ); // len=0
1675
+        if ( !( $this->_Send ( $fp, $req, 8 ) ) ||
1676
+             !( $response = $this->_GetResponse ( $fp, VER_COMMAND_FLUSHATTRS ) ) )
1677
+        {
1678
+            $this->_MBPop ();
1679
+            return -1;
1680
+        }
1681
+
1682
+        $tag = -1;
1683
+        if ( strlen($response)==4 )
1684
+            list(,$tag) = unpack ( "N*", $response );
1685
+        else
1686
+            $this->_error = "unexpected response length";
1687
+
1688
+        $this->_MBPop ();
1689
+        return $tag;
1690
+    }
1691 1691
 }
1692 1692
 
1693 1693
 //
Please login to merge, or discard this patch.