xref: /plugin/sphinxsearch-was/SphinxSearch.php (revision 134:2b68d17b7916)
1<?php
2/*
3 * To change this template, choose Tools | Templates
4 * and open the template in the editor.
5 */
6
7class SphinxSearch
8{
9    private $_sphinx = null;
10    private $_result = array();
11    private $_index = null;
12    private $_query = '';
13
14    private $_snippetSize = 256;
15    private $_aroundKeyword = 5;
16    private $_resultsPerPage = 10;
17
18    private $_titlePriority = 1;
19    private $_bodyPriority = 1;
20    private $_namespacePriority = 1;
21    private $_pagenamePriority = 1;
22
23    public function  __construct($host, $port, $index)
24    {
25        $this->_sphinx = new SphinxClient();
26        $this->_sphinx->SetServer($host, $port);
27        $this->_sphinx->SetMatchMode(SPH_MATCH_EXTENDED2);
28
29        $this->_index = $index;
30    }
31
32    public function setSearchAllQuery($keywords, $categories)
33    {
34        $keywords = $this->_sphinx->EscapeString($keywords);
35        $keywords = $this->_enableQuotesAndDefis($keywords);
36        $starKeyword = $this->starQuery($keywords);
37        $this->_query = "(@(namespace,pagename) $starKeyword) | (@(body,title) {$keywords})";
38    }
39
40    public function setSearchAllQueryWithCategoryFilter($keywords, $categories)
41    {
42        $keywords = $this->_sphinx->EscapeString($keywords);
43        $keywords = $this->_enableQuotesAndDefis($keywords);
44        $starKeyword = $this->starQuery($keywords);
45        if(strpos($categories, "-") === 0){
46            $categories = '-"'.substr($categories, 1).'"';
47        }
48        $this->_query = "(@(namespace,pagename) {$categories}) & ((@(body,title) {$keywords}) | (@(namespace,pagename) {$starKeyword}))";
49    }
50
51    public function setSearchCategoryQuery($keywords, $categories)
52    {
53        $keywords = $this->_sphinx->EscapeString($keywords);
54        $keywords = $this->_enableQuotesAndDefis($keywords);
55
56        $starKeyword = $this->starQuery($keywords);
57        if (!empty($categories)){
58            $this->_query = "(@(namespace,pagename) $categories $starKeyword)";
59        } else {
60            $this->_query = "(@(namespace,pagename) $starKeyword)";
61        }
62
63    }
64
65    public function setSearchOnlyPagename()
66    {
67    	$this->_query = "(@(pagename) {$this->_query})";
68    }
69
70    public function search($start, $resultsPerPage = 10)
71    {
72        $this->_resultsPerPage = $resultsPerPage;
73
74        $this->_sphinx->SetFieldWeights(array(
75            'namespace' => $this->_namespacePriority,
76            'pagename' => $this->_pagenamePriority,
77            'title' => $this->_titlePriority,
78            'body' => $this->_bodyPriority)
79        );
80
81        $this->_sphinx->SetLimits($start, $resultsPerPage+100, 1000);
82
83        $this->_result = $this->_sphinx->Query($this->_query, $this->_index);
84
85        if (empty($this->_result['matches'])) {
86            return false;
87	    }
88        return true;
89    }
90
91    public function getPages($keywords)
92    {
93        if (empty($this->_result['matches'])) {
94            return false;
95	    }
96
97        $pagesIdsAll = $this->getPagesIds();
98        $this->_offset = 0;
99        $counter = 0;
100        $tmpRes = array();
101        $pagesIds = array();
102        foreach($pagesIdsAll as $id => $pageData){
103            $this->_offset++;
104            if(auth_quickaclcheck($pageData['page']) >= AUTH_READ){
105                if(!isset($tmpRes[$pageData['page']])){
106                    $tmpRes[$pageData['page']] = 1;
107                    $counter++;
108                }
109                $pagesIds[$id] = $pageData;
110                if ($counter == $this->_resultsPerPage){
111                    break;
112                }
113            }
114        }
115        if (empty($pagesIds)){
116            return false;
117        }
118
119        $pagesList = array();
120        $body = array();
121        $titleText = array();
122        $category = array();
123        foreach ($pagesIds as $crc => $data){
124            if (empty($data['page'])){
125                continue;
126            }
127            if (!empty($data['hid'])){
128                $bodyHtml = p_render('xhtml',p_get_instructions(getSectionByTitleLevel($data['page'], $data['title'], true)),$info);
129            } else {
130                $bodyHtml = p_wiki_xhtml($data['page']);
131            }
132            $bodyHtml = preg_replace("#[\s]+?</li>#", "</li>;", $bodyHtml);
133            $bodyHtml = htmlspecialchars_decode($bodyHtml);
134            $body[$crc] = strip_tags($bodyHtml);
135            if(!empty($data['title_text'])){
136                $titleText[$crc] = strip_tags($data['title_text']);
137            } else {
138                $titleText[$crc] = $data['page'];
139            }
140            $category[$crc] = $data['page'];
141        }
142
143        //$starQuery = $this->starQuery($keywords);
144        $bodyExcerpt = $this->getExcerpt($body, $keywords);
145        $titleTextExcerpt = $this->getExcerpt($titleText, $keywords);
146        $i = 0;
147        $results = array();
148        foreach($body as $crc => $notused){
149            $results[$crc] = array(
150                'page' => $pagesIds[$crc]['page'],
151                'bodyExcerpt' => $bodyExcerpt[$i],
152                'titleTextExcerpt' => $titleTextExcerpt[$i],
153                'hid' => $pagesIds[$crc]['hid'],
154                'title' => $pagesIds[$crc]['title'],
155                'title_text' => $pagesIds[$crc]['title_text']
156            );
157            $i++;
158        }
159        return $results;
160    }
161
162    public function getPagesIds()
163    {
164        $pageMapper = new PageMapper();
165
166        return $pageMapper->getByCrc(array_keys($this->_result['matches']));
167    }
168
169    public function getOffset()
170    {
171        return $this->_offset;
172    }
173
174    public function getPageNames()
175    {
176        $pageIds = $this->getPagesIds();
177
178        $matchPages = array();
179        foreach ($pageIds as $page) {
180            if(auth_quickaclcheck($page['page']) < AUTH_READ){
181                continue;
182            }
183            /*if(auth_quickaclcheck($pageData['page']) >= AUTH_READ){
184                if(!isset($tmpRes[$pageData['page']])){
185                    $tmpRes[$pageData['page']] = 1;
186                    $counter++;
187                }
188                $pagesIds[$id] = $pageData;
189                if ($counter == $this->_resultsPerPage){
190                    break;
191                }
192            }*/
193
194            $matchPages[$page['page']] = $page['hid'];
195        }
196
197        return $matchPages;
198    }
199
200    public function getError()
201    {
202        return $this->_sphinx->GetLastError();
203    }
204
205    public function getTotalFound()
206    {
207        return !empty($this->_result['total_found'])?$this->_result['total_found'] : 0;
208    }
209
210    public function getExcerpt($data, $query)
211    {
212        return $this->_sphinx->BuildExcerpts($data, $this->_index, $query,
213                    array(
214                        'limit' => $this->_snippetSize,
215                        'around' => $this->_aroundKeyword,
216                        'weight_order' => 1,
217                        'sp' => 1
218                    )
219                );
220    }
221
222    public function starQuery($query)
223    {
224        $query = $this->removeStars($query);
225        $words = explode(" ", $query);
226        foreach($words as $id => $word){
227            $words[$id] = "*".$word."*";
228        }
229        return implode(" ", $words);
230    }
231
232    public function removeStars($query)
233    {
234        $words = explode(" ", $query);
235        foreach($words as $id => $word){
236            $words[$id] = trim($word, "*");
237        }
238        return implode(" ", $words);
239    }
240
241    public function getQuery()
242    {
243        return $this->_query;
244    }
245
246    public function setSnippetSize($symbols = 256)
247    {
248        $this->_snippetSize = $symbols;
249    }
250
251    public function setArroundWordsCount($words = 5)
252    {
253        $this->_aroundKeyword = $words;
254    }
255
256    public function setTitlePriority($priority)
257    {
258        $this->_titlePriority = $priority;
259    }
260
261    public function setBodyPriority($priority)
262    {
263        $this->_bodyPriority = $priority;
264    }
265
266    public function setNamespacePriority($priority)
267    {
268        $this->_namespacePriority = $priority;
269    }
270
271    public function setPagenamePriority($priority)
272    {
273        $this->_pagenamePriority = $priority;
274    }
275
276    private function _enableQuotesAndDefis($query)
277    {
278        $query = ' '. $query;
279        $quotesCount = count(explode('"', $query))-1;
280        if ($quotesCount && $quotesCount%2 == 0){
281            $query = str_replace('\"', '"', $query);
282        }
283        $query = preg_replace("#\s\\\-(\w)#ui", " -$1", $query);
284
285        $query = substr($query, 1);
286
287        return $query;
288    }
289}
290