root / trunk / phpBB / includes / search / search.php

View | Annotate | Download (8 KB)

1
<?php
2
/**
3
*
4
* @package search
5
* @version $Id: search.php 8782 2008-08-23 17:20:55Z acydburn $
6
* @copyright (c) 2005 phpBB Group
7
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
8
*
9
*/
10
11
/**
12
* @ignore
13
*/
14
if (!defined('IN_PHPBB'))
15
{
16
        exit;
17
}
18
19
/**
20
* @ignore
21
*/
22
define('SEARCH_RESULT_NOT_IN_CACHE', 0);
23
define('SEARCH_RESULT_IN_CACHE', 1);
24
define('SEARCH_RESULT_INCOMPLETE', 2);
25
26
/**
27
* search_backend
28
* optional base class for search plugins providing simple caching based on ACM
29
* and functions to retrieve ignore_words and synonyms
30
* @package search
31
*/
32
class search_backend
33
{
34
        var $ignore_words = array();
35
        var $match_synonym = array();
36
        var $replace_synonym = array();
37
38
        function search_backend(&$error)
39
        {
40
                // This class cannot be used as a search plugin
41
                $error = true;
42
        }
43
44
        /**
45
        * Retrieves a language dependend list of words that should be ignored by the search
46
        */
47
        function get_ignore_words()
48
        {
49
                if (!sizeof($this->ignore_words))
50
                {
51
                        global $user, $phpEx;
52
53
                        $words = array();
54
55
                        if (file_exists("{$user->lang_path}{$user->lang_name}/search_ignore_words.$phpEx"))
56
                        {
57
                                // include the file containing ignore words
58
                                include("{$user->lang_path}{$user->lang_name}/search_ignore_words.$phpEx");
59
                        }
60
61
                        $this->ignore_words = $words;
62
                        unset($words);
63
                }
64
        }
65
66
        /**
67
        * Stores a list of synonyms that should be replaced in $this->match_synonym and $this->replace_synonym and caches them
68
        */
69
        function get_synonyms()
70
        {
71
                if (!sizeof($this->match_synonym))
72
                {
73
                        global $user, $phpEx;
74
75
                        $synonyms = array();
76
77
                        if (file_exists("{$user->lang_path}{$user->lang_name}/search_synonyms.$phpEx"))
78
                        {
79
                                // include the file containing synonyms
80
                                include("{$user->lang_path}{$user->lang_name}/search_synonyms.$phpEx");
81
                        }
82
83
                        $this->match_synonym = array_keys($synonyms);
84
                        $this->replace_synonym = array_values($synonyms);
85
86
                        unset($synonyms);
87
                }
88
        }
89
90
        /**
91
        * Retrieves cached search results
92
        *
93
        * @param int &$result_count will contain the number of all results for the search (not only for the current page)
94
        * @param array &$id_ary is filled with the ids belonging to the requested page that are stored in the cache
95
        *
96
        * @return int SEARCH_RESULT_NOT_IN_CACHE or SEARCH_RESULT_IN_CACHE or SEARCH_RESULT_INCOMPLETE
97
        */
98
        function obtain_ids($search_key, &$result_count, &$id_ary, $start, $per_page, $sort_dir)
99
        {
100
                global $cache;
101
102
                if (!($stored_ids = $cache->get('_search_results_' . $search_key)))
103
                {
104
                        // no search results cached for this search_key
105
                        return SEARCH_RESULT_NOT_IN_CACHE;
106
                }
107
                else
108
                {
109
                        $result_count = $stored_ids[-1];
110
                        $reverse_ids = ($stored_ids[-2] != $sort_dir) ? true : false;
111
                        $complete = true;
112
113
                        // change the start to the actual end of the current request if the sort direction differs
114
                        // from the dirction in the cache and reverse the ids later
115
                        if ($reverse_ids)
116
                        {
117
                                $start = $result_count - $start - $per_page;
118
119
                                // the user requested a page past the last index
120
                                if ($start < 0)
121
                                {
122
                                        return SEARCH_RESULT_NOT_IN_CACHE;
123
                                }
124
                        }
125
126
                        for ($i = $start, $n = $start + $per_page; ($i < $n) && ($i < $result_count); $i++)
127
                        {
128
                                if (!isset($stored_ids[$i]))
129
                                {
130
                                        $complete = false;
131
                                }
132
                                else
133
                                {
134
                                        $id_ary[] = $stored_ids[$i];
135
                                }
136
                        }
137
                        unset($stored_ids);
138
139
                        if ($reverse_ids)
140
                        {
141
                                $id_ary = array_reverse($id_ary);
142
                        }
143
144
                        if (!$complete)
145
                        {
146
                                return SEARCH_RESULT_INCOMPLETE;
147
                        }
148
                        return SEARCH_RESULT_IN_CACHE;
149
                }
150
        }
151
152
        /**
153
        * Caches post/topic ids
154
        *
155
        * @param array &$id_ary contains a list of post or topic ids that shall be cached, the first element
156
        *         must have the absolute index $start in the result set.
157
        */
158
        function save_ids($search_key, $keywords, $author_ary, $result_count, &$id_ary, $start, $sort_dir)
159
        {
160
                global $cache, $config, $db, $user;
161
162
                $length = min(sizeof($id_ary), $config['search_block_size']);
163
164
                // nothing to cache so exit
165
                if (!$length)
166
                {
167
                        return;
168
                }
169
170
                $store_ids = array_slice($id_ary, 0, $length);
171
172
                // create a new resultset if there is none for this search_key yet
173
                // or add the ids to the existing resultset
174
                if (!($store = $cache->get('_search_results_' . $search_key)))
175
                {
176
                        // add the current keywords to the recent searches in the cache which are listed on the search page
177
                        if (!empty($keywords) || sizeof($author_ary))
178
                        {
179
                                $sql = 'SELECT search_time
180
                                        FROM ' . SEARCH_RESULTS_TABLE . '
181
                                        WHERE search_key = \'' . $db->sql_escape($search_key) . '\'';
182
                                $result = $db->sql_query($sql);
183
184
                                if (!$db->sql_fetchrow($result))
185
                                {
186
                                        $sql_ary = array(
187
                                                'search_key'                => $search_key,
188
                                                'search_time'                => time(),
189
                                                'search_keywords'        => $keywords,
190
                                                'search_authors'        => ' ' . implode(' ', $author_ary) . ' '
191
                                        );
192
193
                                        $sql = 'INSERT INTO ' . SEARCH_RESULTS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
194
                                        $db->sql_query($sql);
195
                                }
196
                                $db->sql_freeresult($result);
197
                        }
198
199
                        $sql = 'UPDATE ' . USERS_TABLE . '
200
                                SET user_last_search = ' . time() . '
201
                                WHERE user_id = ' . $user->data['user_id'];
202
                        $db->sql_query($sql);
203
204
                        $store = array(-1 => $result_count, -2 => $sort_dir);
205
                        $id_range = range($start, $start + $length - 1);
206
                }
207
                else
208
                {
209
                        // we use one set of results for both sort directions so we have to calculate the indizes
210
                        // for the reversed array and we also have to reverse the ids themselves
211
                        if ($store[-2] != $sort_dir)
212
                        {
213
                                $store_ids = array_reverse($store_ids);
214
                                $id_range = range($store[-1] - $start - $length, $store[-1] - $start - 1);
215
                        }
216
                        else
217
                        {
218
                                $id_range = range($start, $start + $length - 1);
219
                        }
220
                }
221
222
                $store_ids = array_combine($id_range, $store_ids);
223
224
                // append the ids
225
                if (is_array($store_ids))
226
                {
227
                        $store += $store_ids;
228
229
                        // if the cache is too big
230
                        if (sizeof($store) - 2 > 20 * $config['search_block_size'])
231
                        {
232
                                // remove everything in front of two blocks in front of the current start index
233
                                for ($i = 0, $n = $id_range[0] - 2 * $config['search_block_size']; $i < $n; $i++)
234
                                {
235
                                        if (isset($store[$i]))
236
                                        {
237
                                                unset($store[$i]);
238
                                        }
239
                                }
240
241
                                // remove everything after two blocks after the current stop index
242
                                end($id_range);
243
                                for ($i = $store[-1] - 1, $n = current($id_range) + 2 * $config['search_block_size']; $i > $n; $i--)
244
                                {
245
                                        if (isset($store[$i]))
246
                                        {
247
                                                unset($store[$i]);
248
                                        }
249
                                }
250
                        }
251
                        $cache->put('_search_results_' . $search_key, $store, $config['search_store_results']);
252
253
                        $sql = 'UPDATE ' . SEARCH_RESULTS_TABLE . '
254
                                SET search_time = ' . time() . '
255
                                WHERE search_key = \'' . $db->sql_escape($search_key) . '\'';
256
                        $db->sql_query($sql);
257
                }
258
259
                unset($store);
260
                unset($store_ids);
261
                unset($id_range);
262
        }
263
264
        /**
265
        * Removes old entries from the search results table and removes searches with keywords that contain a word in $words.
266
        */
267
        function destroy_cache($words, $authors = false)
268
        {
269
                global $db, $cache, $config;
270
271
                // clear all searches that searched for the specified words
272
                if (sizeof($words))
273
                {
274
                        $sql_where = '';
275
                        foreach ($words as $word)
276
                        {
277
                                $sql_where .= " OR search_keywords " . $db->sql_like_expression($db->any_char . $word . $db->any_char);
278
                        }
279
280
                        $sql = 'SELECT search_key
281
                                FROM ' . SEARCH_RESULTS_TABLE . "
282
                                WHERE search_keywords LIKE '%*%' $sql_where";
283
                        $result = $db->sql_query($sql);
284
285
                        while ($row = $db->sql_fetchrow($result))
286
                        {
287
                                $cache->destroy('_search_results_' . $row['search_key']);
288
                        }
289
                        $db->sql_freeresult($result);
290
                }
291
292
                // clear all searches that searched for the specified authors
293
                if (is_array($authors) && sizeof($authors))
294
                {
295
                        $sql_where = '';
296
                        foreach ($authors as $author)
297
                        {
298
                                $sql_where .= (($sql_where) ? ' OR ' : '') . 'search_authors LIKE \'% ' . (int) $author . ' %\'';
299
                        }
300
301
                        $sql = 'SELECT search_key
302
                                FROM ' . SEARCH_RESULTS_TABLE . "
303
                                WHERE $sql_where";
304
                        $result = $db->sql_query($sql);
305
306
                        while ($row = $db->sql_fetchrow($result))
307
                        {
308
                                $cache->destroy('_search_results_' . $row['search_key']);
309
                        }
310
                        $db->sql_freeresult($result);
311
                }
312
313
                $sql = 'DELETE
314
                        FROM ' . SEARCH_RESULTS_TABLE . '
315
                        WHERE search_time < ' . (time() - $config['search_store_results']);
316
                $db->sql_query($sql);
317
        }
318
}
319
320
?>