This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | if (!defined('BASEPATH')) { |
||
4 | exit('No direct script access allowed'); |
||
5 | } |
||
6 | |||
7 | /** |
||
8 | * Image CMS |
||
9 | * |
||
10 | * Search Module |
||
11 | * TODO: |
||
12 | * refresh cache after $search_ttl expry. |
||
13 | */ |
||
14 | class Search extends MY_Controller |
||
15 | { |
||
16 | |||
17 | public $search_ttl = 3600; //Search time to live in minutes. |
||
18 | |||
19 | public $table = ''; |
||
20 | |||
21 | public $cache_on = FALSE; |
||
22 | |||
23 | public $row_count = 15; |
||
24 | |||
25 | public $table_pk = 'content.id'; |
||
26 | |||
27 | public $search_tpl = 'search'; |
||
28 | |||
29 | public $query_hash = ''; |
||
30 | |||
31 | public $search_title = ''; |
||
32 | |||
33 | public $hash_prefix = ''; |
||
34 | |||
35 | public $hash_data = FALSE; |
||
36 | |||
37 | public $select = []; |
||
38 | |||
39 | public $title_delimiter = ' - '; |
||
40 | |||
41 | public $default_operator = 'where'; |
||
42 | |||
43 | public $min_s_len = 3; // Min. length to make search request. |
||
44 | |||
45 | private $where = []; |
||
46 | |||
47 | private $order_by = []; |
||
48 | |||
49 | private $search_table = 'search'; |
||
50 | |||
51 | public function __construct() { |
||
52 | parent::__construct(); |
||
53 | $lang = new MY_Lang(); |
||
54 | $lang->load('search'); |
||
55 | } |
||
56 | |||
57 | // Search pages |
||
58 | |||
59 | public function index($hash = '', $offset = 0) { |
||
60 | $this->template->registerMeta('ROBOTS', 'NOINDEX, NOFOLLOW'); |
||
61 | |||
62 | $offset = (int) $offset; |
||
63 | |||
64 | if ($hash != '') { |
||
65 | $hash_data = $this->query($hash, $offset); |
||
0 ignored issues
–
show
|
|||
66 | $s_text = $this->search_title; |
||
67 | } else { |
||
68 | $s_text = $this->getSearchText(); |
||
69 | } |
||
70 | |||
71 | $text_len = mb_strlen(trim($s_text), 'UTF-8'); |
||
72 | |||
73 | if ($text_len >= $this->min_s_len AND $text_len < 50) { |
||
74 | $config = [ |
||
75 | 'table' => 'content', |
||
76 | 'order_by' => ['publish_date' => 'DESC'], |
||
77 | 'select' => [ |
||
78 | 'content.*', |
||
79 | 'IF(route.parent_url <> \'\', concat(route.parent_url, \'/\', route.url), route.url) as full_url', |
||
80 | ], |
||
81 | ]; |
||
82 | |||
83 | $this->init($config); |
||
84 | |||
85 | $where = [ |
||
86 | [ |
||
87 | 'post_status' => 'publish', |
||
88 | 'operator' => 'WHERE', |
||
89 | ], |
||
90 | [ |
||
91 | 'publish_date <=' => 'UNIX_TIMESTAMP()', |
||
92 | 'backticks' => FALSE, |
||
93 | ], |
||
94 | [ |
||
95 | 'lang' => $this->config->item('cur_lang'), |
||
96 | ], |
||
97 | [ |
||
98 | 'group1' => '(title LIKE "%' . $this->db->escape_str($s_text) . '%" OR prev_text LIKE "%' . $this->db->escape_str($s_text) . '%" OR full_text LIKE "%' . $this->db->escape_str($s_text) . '%" )', |
||
99 | 'group' => TRUE, |
||
100 | ], |
||
101 | ]; |
||
102 | |||
103 | /** Data for categories in search * */ |
||
104 | $dataForFoundInCategories = $this->countSearchResults($where); |
||
105 | $dataForFoundInCategories = $dataForFoundInCategories->result_array(); |
||
106 | |||
107 | View Code Duplication | if ($hash == '') { |
|
108 | $result = $this->execute($where, $offset); |
||
109 | } else { |
||
110 | $result = $this->query($hash, $offset); |
||
111 | } |
||
112 | |||
113 | if (!$this->search_title) { |
||
114 | $this->search_title = $s_text; |
||
115 | } |
||
116 | |||
117 | //Pagination |
||
118 | if ($result['total_rows'] > $this->row_count) { |
||
119 | $this->load->library('Pagination'); |
||
120 | |||
121 | $paginationConfig['base_url'] = site_url('search/index/' . $result['hash'] . '/'); |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
$paginationConfig was never initialized. Although not strictly required by PHP, it is generally a good practice to add $paginationConfig = array(); before regardless.
Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code. Let’s take a look at an example: foreach ($collection as $item) {
$myArray['foo'] = $item->getFoo();
if ($item->hasBar()) {
$myArray['bar'] = $item->getBar();
}
// do something with $myArray
}
As you can see in this example, the array This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop. ![]() |
|||
122 | $paginationConfig['total_rows'] = $result['total_rows']; |
||
123 | $paginationConfig['per_page'] = $this->row_count; |
||
124 | $paginationConfig['uri_segment'] = 4; |
||
125 | include_once "./templates/{$this->config->item('template')}/paginations.php"; |
||
126 | $paginationConfig['page_query_string'] = FALSE; |
||
127 | |||
128 | $this->pagination->initialize($paginationConfig); |
||
129 | $this->template->assign('pagination', $this->pagination->create_links()); |
||
130 | } |
||
131 | //End pagination |
||
132 | } else { |
||
133 | $result = FALSE; |
||
134 | } |
||
135 | |||
136 | if ($result === FALSE) { |
||
137 | $data = FALSE; |
||
138 | } else { |
||
139 | $data = $result['query']->result_array(); |
||
140 | } |
||
141 | |||
142 | if (isset($s_text)) { |
||
143 | $this->template->assign('search_title', $s_text); |
||
144 | } |
||
145 | |||
146 | $data = $this->_highlight_text($data, $s_text); |
||
147 | |||
148 | $this->core->set_meta_tags([lang('Search', 'search'), $this->search_title]); |
||
149 | $this->core->core_data['data_type'] = 'search'; |
||
150 | $this->_display($data, $dataForFoundInCategories); |
||
151 | } |
||
152 | |||
153 | public function getSearchText() { |
||
154 | $text = $this->input->post('text') ? $this->input->post('text') : $this->input->get('text'); |
||
155 | return trim($text); |
||
156 | } |
||
157 | |||
158 | /** |
||
159 | * Highlight found text |
||
160 | * @param array $data Pages to highlight |
||
161 | * @param string $text |
||
162 | * @return array |
||
0 ignored issues
–
show
Should the return type not be
null|array ? Also, consider making the array more specific, something like array<String> , or String[] .
This check compares the return type specified in the If the return type contains the type array, this check recommends the use of
a more specific type like ![]() |
|||
163 | */ |
||
164 | protected function _highlight_text($data, $text) { |
||
165 | if (!$data) { |
||
166 | return; |
||
167 | } |
||
168 | $dataCount = count($data); |
||
169 | for ($i = 0; $i < $dataCount; $i++) { |
||
170 | $tempText = strip_tags($data[$i]['prev_text'] . ' ' . $data[$i]['full_text']); |
||
171 | $pos = mb_strpos($tempText, $text); |
||
172 | $length = mb_strlen($tempText, 'UTF-8'); |
||
173 | $start = $pos - 40; |
||
174 | $stop = $pos + 40; |
||
175 | if ($start < 0) { |
||
176 | $start = 0; |
||
177 | } |
||
178 | if ($stop > $length) { |
||
179 | $stop = $length; |
||
180 | } |
||
181 | |||
182 | $tempText = mb_substr($tempText, $start, $stop, 'UTF-8'); |
||
183 | $tempText = str_replace($text, '<mark>' . $text . '</mark>', $tempText); |
||
184 | $data[$i]['parsedText'] = '...' . mb_substr($tempText, 0, 500, 'utf-8') . '...'; |
||
185 | } |
||
186 | |||
187 | return $data; |
||
188 | } |
||
189 | |||
190 | // Init search settings |
||
191 | |||
192 | public function init($config = []) { |
||
193 | foreach ($config as $key => $val) { |
||
194 | if (isset($this->$key)) { |
||
195 | $this->$key = $val; |
||
196 | } else { |
||
197 | $m = 'set_' . $key; |
||
198 | |||
199 | if (method_exists($this, $m)) { |
||
200 | $this->$m($val); |
||
201 | } |
||
202 | } |
||
203 | } |
||
204 | } |
||
205 | |||
206 | public function clear() { |
||
207 | $this->search_ttl = 600; |
||
208 | $this->table = ''; |
||
209 | $this->cache_on = FALSE; |
||
210 | $this->default_operator = 'where'; |
||
211 | $this->where = []; |
||
212 | $this->order_by = []; |
||
213 | $this->search_table = 'search'; |
||
214 | $this->query_hash = ''; |
||
215 | $this->hash_data = FALSE; |
||
216 | } |
||
217 | |||
218 | // Search by hash |
||
219 | |||
220 | public function query($hash = '', $offset = 0) { |
||
221 | if (($hash_data = $this->hash_data($hash)) == FALSE) { |
||
222 | $this->load->module('core'); |
||
223 | $this->core->error_404(); |
||
224 | } |
||
225 | |||
226 | $this->table = $hash_data->table_name; |
||
227 | $this->hash = $hash_data->hash; |
||
228 | $this->order_by = unserialize($hash_data->order_by); |
||
229 | $this->select = unserialize($hash_data->select_array); |
||
230 | $this->search_title = $this->hash_data->search_title; |
||
231 | |||
232 | return $this->execute(unserialize($hash_data->where_array), $offset); |
||
233 | } |
||
234 | |||
235 | // Search |
||
236 | |||
237 | public function execute($where = [], $offset = 0) { |
||
238 | $collect_ids = FALSE; |
||
239 | |||
240 | if ($this->table == '') { |
||
241 | $error = lang('Error. Select or specify the table for search', 'search'); |
||
242 | return $error; |
||
243 | } |
||
244 | |||
245 | $this->query_hash = $this->generate_hash($where); |
||
246 | |||
247 | $hs = $this->hash_data(); |
||
248 | |||
249 | if ($this->hash_data->datetime + $this->search_ttl < time() AND $this->hash_data->datetime > 0) { |
||
250 | $refresh = TRUE; |
||
251 | $this->hash_data->datetime = time(); |
||
252 | } else { |
||
253 | $refresh = FALSE; |
||
254 | } |
||
255 | |||
256 | if ($hs == FALSE OR $refresh == TRUE) { |
||
257 | $collect_ids = TRUE; |
||
258 | |||
259 | if ($refresh == FALSE) { |
||
260 | // Store query data |
||
261 | if (!$this->search_title) { |
||
262 | $this->search_title = $this->getSearchText(); |
||
263 | } |
||
264 | |||
265 | $q_data = [ |
||
266 | 'hash' => $this->query_hash, |
||
267 | 'datetime' => time(), |
||
268 | 'where_array' => serialize($where), |
||
269 | 'select_array' => serialize($this->select), |
||
270 | 'table_name' => $this->table, |
||
271 | 'order_by' => serialize($this->order_by), |
||
272 | 'row_count' => $this->row_count, |
||
273 | 'search_title' => $this->search_title, |
||
274 | ]; |
||
275 | |||
276 | $this->db->insert($this->search_table, $q_data); |
||
277 | } |
||
278 | } else { |
||
279 | if (!is_array($this->hash_data->ids)) { |
||
280 | $this->hash_data->ids = unserialize($this->hash_data->ids); |
||
281 | } |
||
282 | |||
283 | $where = []; |
||
284 | $ids = []; |
||
285 | |||
286 | for ($i = $offset; $i < $offset + $this->row_count; $i++) { |
||
287 | if (isset($this->hash_data->ids[$i])) { |
||
288 | $ids[] = $this->hash_data->ids[$i]; |
||
289 | } |
||
290 | } |
||
291 | |||
292 | if (count($ids) > 0) { |
||
293 | $this->db->where_in($this->table_pk, $ids); |
||
294 | } else { |
||
295 | return FALSE; |
||
296 | } |
||
297 | } |
||
298 | |||
299 | // begin query |
||
300 | View Code Duplication | if (count($where) > 0) { |
|
301 | foreach ($where as $params) { |
||
302 | // Set search operator. (where, like, or_where, etc..) |
||
303 | if (isset($params['operator'])) { |
||
304 | $operator = strtolower($params['operator']); |
||
305 | unset($params['operator']); |
||
306 | } else { |
||
307 | $operator = $this->default_operator; |
||
308 | } |
||
309 | |||
310 | // Protect field names with backticks. |
||
311 | if (isset($params['backticks'])) { |
||
312 | $backticks = $params['backticks']; |
||
313 | unset($params['backticks']); |
||
314 | } else { |
||
315 | $backticks = TRUE; |
||
316 | } |
||
317 | |||
318 | if (isset($params['group']) AND $params['group'] == TRUE) { |
||
319 | $use_group = TRUE; |
||
320 | unset($params['group']); |
||
321 | } else { |
||
322 | $use_group = FALSE; |
||
323 | } |
||
324 | |||
325 | foreach ($params as $key => $val) { |
||
326 | if ($use_group == FALSE) { |
||
327 | $this->db->$operator($key, $val, $backticks); |
||
328 | } else { |
||
329 | $this->db->where($val); |
||
330 | } |
||
331 | } |
||
332 | } |
||
333 | } |
||
334 | |||
335 | // Set order_by params |
||
336 | if (count($this->order_by) > 0) { |
||
337 | foreach ($this->order_by as $key => $val) { |
||
338 | $this->db->order_by($key, $val); |
||
339 | } |
||
340 | } |
||
341 | |||
342 | // Add SELECT string |
||
343 | if (count($this->select) > 0) { |
||
344 | foreach ($this->select as $key => $val) { |
||
345 | $this->db->select($val, false); |
||
346 | } |
||
347 | } |
||
348 | |||
349 | if ($collect_ids == TRUE) { |
||
350 | $ids = []; |
||
351 | |||
352 | $this->db->select($this->table_pk); |
||
353 | $this->db->join('route', 'route.id=content.route_id'); |
||
354 | $query = $this->db->get($this->table)->result_array(); |
||
355 | |||
356 | foreach ($query as $row) { |
||
357 | $ids[] = $row['id']; |
||
358 | } |
||
359 | $this->db->where('hash', $this->query_hash); |
||
360 | $this->db->update('search', ['datetime' => time(), 'ids' => serialize($ids), 'total_rows' => count($ids)]); |
||
361 | |||
362 | return $this->execute($where, $offset); |
||
363 | } else { |
||
364 | if (!$this->search_title) { |
||
365 | $this->search_title = $this->input->post('text'); |
||
366 | } |
||
367 | $this->db->join('route', 'route.id=content.route_id'); |
||
368 | |||
369 | $data = [ |
||
370 | 'query' => $this->db->get($this->table), |
||
371 | 'total_rows' => $this->hash_data->total_rows, |
||
372 | 'hash' => $this->query_hash, |
||
373 | 'search_title' => $this->search_title, |
||
374 | ]; |
||
375 | |||
376 | return $data; |
||
377 | } |
||
378 | } |
||
379 | |||
380 | private function countSearchResults($where) { |
||
381 | // begin query |
||
382 | View Code Duplication | if (count($where) > 0) { |
|
383 | foreach ($where as $params) { |
||
384 | // Set search operator. (where, like, or_where, etc..) |
||
385 | if (isset($params['operator'])) { |
||
386 | $operator = strtolower($params['operator']); |
||
387 | unset($params['operator']); |
||
388 | } else { |
||
389 | $operator = $this->default_operator; |
||
390 | } |
||
391 | |||
392 | // Protect field names with backticks. |
||
393 | if (isset($params['backticks'])) { |
||
394 | $backticks = $params['backticks']; |
||
395 | unset($params['backticks']); |
||
396 | } else { |
||
397 | $backticks = TRUE; |
||
398 | } |
||
399 | |||
400 | if (isset($params['group']) AND $params['group'] == TRUE) { |
||
401 | $use_group = TRUE; |
||
402 | unset($params['group']); |
||
403 | } else { |
||
404 | $use_group = FALSE; |
||
405 | } |
||
406 | |||
407 | foreach ($params as $key => $val) { |
||
408 | if ($use_group == FALSE) { |
||
409 | $res = $this->db->$operator($key, $val, $backticks); |
||
410 | } else { |
||
411 | $res = $this->db->where($val); |
||
412 | } |
||
413 | } |
||
414 | } |
||
415 | } |
||
416 | |||
417 | return $res->get($this->table); |
||
418 | } |
||
419 | |||
420 | // Generate search hash |
||
421 | |||
422 | private function generate_hash($where = []) { |
||
423 | return sha1($this->hash_prefix . $this->table . serialize($this->order_by) . serialize($where) . $this->row_count . serialize($this->select)); |
||
424 | } |
||
425 | |||
426 | /** |
||
427 | * @return integer |
||
428 | */ |
||
429 | private function hash_data($hash = '') { |
||
430 | if ($hash == '') { |
||
431 | $hash = $this->query_hash; |
||
432 | } |
||
433 | |||
434 | if ($this->hash_data != FALSE) { |
||
435 | return $this->hash_data; |
||
436 | } |
||
437 | |||
438 | $this->db->limit(1); |
||
439 | $this->db->where('hash', $hash); |
||
440 | $query = $this->db->get($this->search_table); |
||
441 | |||
442 | if ($query->num_rows == 1) { |
||
443 | $this->hash_data = $query->row(); |
||
444 | return $query->row(); |
||
445 | } else { |
||
446 | return FALSE; |
||
447 | } |
||
448 | } |
||
449 | |||
450 | // Display search template file |
||
451 | |||
452 | public function _display($pages = [], $foundInCategories = null) { |
||
453 | /* * Prepare categories for search results * */ |
||
454 | $categoriesInSearchResults = null; |
||
455 | $tree = null; |
||
456 | $categories = []; |
||
457 | |||
458 | if ($foundInCategories != null) { |
||
459 | $this->load->library('lib_category'); |
||
460 | foreach ($foundInCategories as $key => $value) { |
||
461 | if (array_key_exists($value['category'], $categories)) { |
||
462 | $categories[$value['category']]['count'] ++; |
||
463 | } else { |
||
464 | $value['count'] = 1; |
||
465 | $categories[$value['category']] = $value; |
||
466 | } |
||
467 | } |
||
468 | |||
469 | $categoriesInSearchResults = $this->prepareCategoriesForSearchResults($categories); |
||
470 | $tree = $this->lib_category->build(); |
||
471 | $categoriesInfo = $this->lib_category->unsorted(); |
||
472 | } |
||
473 | |||
474 | if (count($pages) > 0) { |
||
475 | ($hook = get_hook('core_return_category_pages')) ? eval($hook) : NULL; |
||
0 ignored issues
–
show
The call to
get_hook() has too many arguments starting with 'core_return_category_pages' .
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the ![]() |
|||
476 | |||
477 | $this->template->add_array( |
||
478 | [ |
||
479 | 'items' => $pages, |
||
480 | 'categoriesInSearchResults' => $categoriesInSearchResults, |
||
481 | 'tree' => $tree, |
||
482 | 'countAll' => count($foundInCategories), |
||
483 | 'categoriesInfo' => $categoriesInfo, |
||
484 | ] |
||
485 | ); |
||
486 | } |
||
487 | |||
488 | $this->template->show($this->search_tpl); |
||
489 | } |
||
490 | |||
491 | /** |
||
492 | * Prepare categories for search results |
||
493 | * @param array $foundInCategories |
||
494 | * @return boolean|array |
||
495 | */ |
||
496 | private function prepareCategoriesForSearchResults($foundInCategories) { |
||
497 | $categoriesArray = []; |
||
498 | $categoriesAll = $this->lib_category->unsorted(); |
||
499 | foreach ($categoriesAll as $key => $value) { |
||
500 | /** Count of found pages in category * */ |
||
501 | if (array_key_exists($key, $foundInCategories)) { |
||
502 | $categoriesArray[$key] = $foundInCategories[$key]['count']; |
||
503 | } |
||
504 | /** For fetched pages * */ |
||
505 | $mainCategory = $key; |
||
506 | if (($fetchCategories = unserialize($categoriesAll[$mainCategory]['fetch_pages'])) != false) { |
||
507 | foreach ($foundInCategories as $page) { |
||
508 | if (in_array($page['category'], $fetchCategories)) { |
||
509 | if (array_key_exists($mainCategory, $categoriesArray)) { |
||
510 | $categoriesArray[$mainCategory] = $categoriesArray[$mainCategory] + $page['count']; |
||
511 | } else { |
||
512 | $categoriesArray[$mainCategory] = $page['count']; |
||
513 | } |
||
514 | } |
||
515 | } |
||
516 | } |
||
517 | } |
||
518 | return $categoriesArray; |
||
519 | } |
||
520 | |||
521 | // Create search table |
||
522 | |||
523 | public function _install() { |
||
524 | if ($this->dx_auth->is_admin() == FALSE) { |
||
525 | exit; |
||
526 | } |
||
527 | |||
528 | $this->load->dbforge(); |
||
529 | |||
530 | $fields = [ |
||
531 | 'id' => [ |
||
532 | 'type' => 'INT', |
||
533 | 'constraint' => 11, |
||
534 | 'auto_increment' => TRUE, |
||
535 | ], |
||
536 | 'hash' => [ |
||
537 | 'type' => 'VARCHAR', |
||
538 | 'constraint' => 264, |
||
539 | ], |
||
540 | 'datetime' => [ |
||
541 | 'type' => 'INT', |
||
542 | 'constraint' => 11, |
||
543 | ], |
||
544 | 'where_array' => ['type' => 'TEXT'], |
||
545 | 'select_array' => ['type' => 'TEXT'], |
||
546 | 'table_name' => [ |
||
547 | 'type' => 'VARCHAR', |
||
548 | 'constraint' => 100, |
||
549 | ], |
||
550 | 'order_by' => ['type' => 'TEXT'], |
||
551 | 'row_count' => [ |
||
552 | 'type' => 'INT', |
||
553 | 'constraint' => 11, |
||
554 | ], |
||
555 | 'total_rows' => [ |
||
556 | 'type' => 'INT', |
||
557 | 'constraint' => 11, |
||
558 | ], |
||
559 | 'ids' => ['type' => 'TEXT'], |
||
560 | 'search_title' => [ |
||
561 | 'type' => 'VARCHAR', |
||
562 | 'constraint' => '250', |
||
563 | ], |
||
564 | ]; |
||
565 | |||
566 | $this->dbforge->add_key('id', TRUE); |
||
567 | $this->dbforge->add_field($fields); |
||
568 | $this->dbforge->create_table('search', TRUE); |
||
569 | } |
||
570 | |||
571 | public function _deinstall() { |
||
572 | if ($this->dx_auth->is_admin() == FALSE) { |
||
573 | exit; |
||
574 | } |
||
575 | |||
576 | $this->load->dbforge(); |
||
577 | $this->dbforge->drop_table('search'); |
||
578 | } |
||
579 | |||
580 | } |
||
581 | |||
582 | /* End of file search.php */ |
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.
Both the
$myVar
assignment in line 1 and the$higher
assignment in line 2 are dead. The first because$myVar
is never used and the second because$higher
is always overwritten for every possible time line.