PageRenderTime 54ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/system/expressionengine/modules/search/mod.search.php

https://bitbucket.org/studiobreakfast/sync
PHP | 1947 lines | 1255 code | 383 blank | 309 comment | 277 complexity | 5ed4f2fb365310f37e61bf6ccf178648 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
  2. /**
  3. * ExpressionEngine - by EllisLab
  4. *
  5. * @package ExpressionEngine
  6. * @author EllisLab Dev Team
  7. * @copyright Copyright (c) 2003 - 2012, EllisLab, Inc.
  8. * @license http://expressionengine.com/user_guide/license.html
  9. * @link http://expressionengine.com
  10. * @since Version 2.0
  11. * @filesource
  12. */
  13. // ------------------------------------------------------------------------
  14. /**
  15. * ExpressionEngine Search Module
  16. *
  17. * @package ExpressionEngine
  18. * @subpackage Modules
  19. * @category Modules
  20. * @author EllisLab Dev Team
  21. * @link http://expressionengine.com
  22. */
  23. class Search {
  24. var $min_length = 3; // Minimum length of search keywords
  25. var $cache_expire = 2; // How many hours should we keep search caches?
  26. var $keywords = "";
  27. var $text_format = 'xhtml'; // Excerpt text formatting
  28. var $html_format = 'all'; // Excerpt html formatting
  29. var $auto_links = 'y'; // Excerpt auto-linking: y/n
  30. var $allow_img_url = 'n'; // Excerpt - allow images: y/n
  31. var $channel_array = array();
  32. var $cat_array = array();
  33. var $fields = array();
  34. var $num_rows = 0;
  35. protected $_meta = array();
  36. /**
  37. * Constructor
  38. */
  39. public function __construct()
  40. {
  41. // Make a local reference to the ExpressionEngine super object
  42. $this->EE =& get_instance();
  43. }
  44. /**
  45. * Do Search
  46. */
  47. function do_search()
  48. {
  49. $this->EE->lang->loadfile('search');
  50. // Get hidden meta vars
  51. if (isset($_POST['meta']))
  52. {
  53. $this->_get_meta_vars();
  54. }
  55. /** ----------------------------------------
  56. /** Profile Exception
  57. /** ----------------------------------------*/
  58. // This is an exception to the normal search routine.
  59. // It permits us to search for all posts by a particular user's screen name
  60. // We look for the "mbr" $_GET variable. If it exsists it will
  61. // trigger our exception
  62. if ($this->EE->input->get_post('mbr'))
  63. {
  64. $this->_meta['result_page'] = ($this->EE->input->get_post('result_path') != '') ? $this->EE->input->get_post('result_path') : 'search/results';
  65. $_POST['keywords'] = '';
  66. $_POST['exact_match'] = 'y';
  67. $_POST['exact_keyword'] = 'n';
  68. }
  69. // RP can be used in a query string,
  70. // so we need to clean it a bit
  71. $this->_meta['result_page'] = str_replace(array('=', '&'), '', $this->_meta['result_page']);
  72. /** ----------------------------------------
  73. /** Pulldown Addition - Any, All, Exact
  74. /** ----------------------------------------*/
  75. if (isset($this->_meta['where']) && $this->_meta['where'] == 'exact')
  76. {
  77. $_POST['exact_keyword'] = 'y';
  78. }
  79. /** ----------------------------------------
  80. /** Do we have a search results page?
  81. /** ----------------------------------------*/
  82. // The search results template is specified as a parameter in the search form tag.
  83. // If the parameter is missing we'll issue an error since we don't know where to
  84. // show the results
  85. if ( ! isset($this->_meta['result_page']) OR $this->_meta['result_page'] == '')
  86. {
  87. return $this->EE->output->show_user_error('general', array(lang('search_path_error')));
  88. }
  89. /** ----------------------------------------
  90. /** Is the current user allowed to search?
  91. /** ----------------------------------------*/
  92. if ($this->EE->session->userdata('can_search') == 'n' AND $this->EE->session->userdata('group_id') != 1)
  93. {
  94. return $this->EE->output->show_user_error('general', array(lang('search_not_allowed')));
  95. }
  96. /** ----------------------------------------
  97. /** Flood control
  98. /** ----------------------------------------*/
  99. if ($this->EE->session->userdata['search_flood_control'] > 0 AND $this->EE->session->userdata['group_id'] != 1)
  100. {
  101. $cutoff = time() - $this->EE->session->userdata['search_flood_control'];
  102. $sql = "SELECT search_id FROM exp_search WHERE site_id = '".$this->EE->db->escape_str($this->EE->config->item('site_id'))."' AND search_date > '{$cutoff}' AND ";
  103. if ($this->EE->session->userdata['member_id'] != 0)
  104. {
  105. $sql .= "(member_id='".$this->EE->db->escape_str($this->EE->session->userdata('member_id'))."' OR ip_address='".$this->EE->db->escape_str($this->EE->input->ip_address())."')";
  106. }
  107. else
  108. {
  109. $sql .= "ip_address='".$this->EE->db->escape_str($this->EE->input->ip_address())."'";
  110. }
  111. $query = $this->EE->db->query($sql);
  112. $text = str_replace("%x", $this->EE->session->userdata['search_flood_control'], lang('search_time_not_expired'));
  113. if ($query->num_rows() > 0)
  114. {
  115. return $this->EE->output->show_user_error('general', array($text));
  116. }
  117. }
  118. /** ----------------------------------------
  119. /** Did the user submit any keywords?
  120. /** ----------------------------------------*/
  121. // We only require a keyword if the member name field is blank
  122. if ( ! isset($_GET['mbr']) OR ! is_numeric($_GET['mbr']))
  123. {
  124. if ( ! isset($_POST['member_name']) OR $_POST['member_name'] == '')
  125. {
  126. if ( ! isset($_POST['keywords']) OR $_POST['keywords'] == "")
  127. {
  128. return $this->EE->output->show_user_error('general', array(lang('search_no_keywords')));
  129. }
  130. }
  131. }
  132. /** ----------------------------------------
  133. /** Strip extraneous junk from keywords
  134. /** ----------------------------------------*/
  135. if ($_POST['keywords'] != "")
  136. {
  137. // Load the search helper so we can filter the keywords
  138. $this->EE->load->helper('search');
  139. $this->keywords = sanitize_search_terms($_POST['keywords']);
  140. /** ----------------------------------------
  141. /** Is the search term long enough?
  142. /** ----------------------------------------*/
  143. if (strlen($this->keywords) < $this->min_length)
  144. {
  145. $text = lang('search_min_length');
  146. $text = str_replace("%x", $this->min_length, $text);
  147. return $this->EE->output->show_user_error('general', array($text));
  148. }
  149. // Load the text helper
  150. $this->EE->load->helper('text');
  151. $this->keywords = ($this->EE->config->item('auto_convert_high_ascii') == 'y') ? ascii_to_entities($this->keywords) : $this->keywords;
  152. /** ----------------------------------------
  153. /** Remove "ignored" words
  154. /** ----------------------------------------*/
  155. if (( ! isset($_POST['exact_keyword']) OR $_POST['exact_keyword'] != 'y') && @include_once(APPPATH.'config/stopwords.php'))
  156. {
  157. $parts = explode('"', $this->keywords);
  158. $this->keywords = '';
  159. foreach($parts as $num => $part)
  160. {
  161. // The odd breaks contain quoted strings.
  162. if ($num % 2 == 0)
  163. {
  164. foreach ($ignore as $badword)
  165. {
  166. $part = preg_replace("/\b".preg_quote($badword, '/')."\b/i","", $part);
  167. }
  168. }
  169. $this->keywords .= ($num != 0) ? '"'.$part : $part;
  170. }
  171. if (trim($this->keywords) == '')
  172. {
  173. return $this->EE->output->show_user_error('general', array(lang('search_no_stopwords')));
  174. }
  175. }
  176. /** ----------------------------------------
  177. /** Log Search Terms
  178. /** ----------------------------------------*/
  179. $this->EE->functions->log_search_terms($this->keywords);
  180. }
  181. if (isset($_POST['member_name']) AND $_POST['member_name'] != "")
  182. {
  183. $_POST['member_name'] = $this->EE->security->xss_clean($_POST['member_name']);
  184. }
  185. /** ----------------------------------------
  186. /** Build and run query
  187. /** ----------------------------------------*/
  188. $original_keywords = $this->keywords;
  189. $mbr = ( ! isset($_GET['mbr'])) ? '' : $_GET['mbr'];
  190. $sql = $this->build_standard_query();
  191. /** ----------------------------------------
  192. /** No query results?
  193. /** ----------------------------------------*/
  194. if ($sql == FALSE)
  195. {
  196. if (isset($this->_meta['no_results_page']) AND $this->_meta['no_results_page'] != '')
  197. {
  198. $hash = $this->EE->functions->random('md5');
  199. $data = array(
  200. 'search_id' => $hash,
  201. 'search_date' => time(),
  202. 'member_id' => $this->EE->session->userdata('member_id'),
  203. 'keywords' => ($original_keywords != '') ? $original_keywords : $mbr,
  204. 'ip_address' => $this->EE->input->ip_address(),
  205. 'total_results' => 0,
  206. 'per_page' => 0,
  207. 'query' => '',
  208. 'custom_fields' => '',
  209. 'result_page' => '',
  210. 'site_id' => $this->EE->config->item('site_id')
  211. );
  212. $this->EE->db->query($this->EE->db->insert_string('exp_search', $data));
  213. return $this->EE->functions->redirect($this->EE->functions->create_url($this->EE->functions->extract_path("='".$this->_meta['no_results_page']."'")).'/'.$hash.'/');
  214. }
  215. else
  216. {
  217. return $this->EE->output->show_user_error('off', array(lang('search_no_result')), lang('search_result_heading'));
  218. }
  219. }
  220. /** ----------------------------------------
  221. /** If we have a result, cache it
  222. /** ----------------------------------------*/
  223. $hash = $this->EE->functions->random('md5');
  224. $sql = str_replace("\\", "\\\\", $sql);
  225. // This fixes a bug that occurs when a different table prefix is used
  226. $sql = str_replace('exp_', 'MDBMPREFIX', $sql);
  227. $data = array(
  228. 'search_id' => $hash,
  229. 'search_date' => time(),
  230. 'member_id' => $this->EE->session->userdata('member_id'),
  231. 'keywords' => ($original_keywords != '') ? $original_keywords : $mbr,
  232. 'ip_address' => $this->EE->input->ip_address(),
  233. 'total_results' => $this->num_rows,
  234. 'per_page' => (isset($_POST['RES']) AND is_numeric($_POST['RES']) AND $_POST['RES'] < 999 ) ? $_POST['RES'] : 50,
  235. 'query' => addslashes(serialize($sql)),
  236. 'custom_fields' => addslashes(serialize($this->fields)),
  237. 'result_page' => $this->_meta['result_page'],
  238. 'site_id' => $this->EE->config->item('site_id')
  239. );
  240. $this->EE->db->query($this->EE->db->insert_string('exp_search', $data));
  241. /** ----------------------------------------
  242. /** Redirect to search results page
  243. /** ----------------------------------------*/
  244. // Load the string helper
  245. $this->EE->load->helper('string');
  246. $path = $this->EE->functions->remove_double_slashes(
  247. $this->EE->functions->create_url(
  248. trim_slashes($this->_meta['result_page'])
  249. ).'/'.$hash.'/'
  250. );
  251. return $this->EE->functions->redirect($path);
  252. }
  253. // ------------------------------------------------------------------------
  254. /**
  255. * Build Meta Array
  256. *
  257. * This builds the array of parameters that are stored in a secure hash in a hidden input
  258. * on the search forms.
  259. */
  260. protected function _build_meta_array()
  261. {
  262. $meta = array(
  263. 'status' => $this->EE->TMPL->fetch_param('status', ''),
  264. 'channel' => $this->EE->TMPL->fetch_param('channel', ''),
  265. 'category' => $this->EE->TMPL->fetch_param('category', ''),
  266. 'search_in' => $this->EE->TMPL->fetch_param('search_in', ''),
  267. 'where' => $this->EE->TMPL->fetch_param('where', 'all'),
  268. 'show_expired' => $this->EE->TMPL->fetch_param('show_expired', ''),
  269. 'show_future_entries' => $this->EE->TMPL->fetch_param('show_future_entries'),
  270. 'result_page' => $this->EE->TMPL->fetch_param('result_page', 'search/results'),
  271. 'no_results_page' => $this->EE->TMPL->fetch_param('no_result_page', '')
  272. );
  273. $meta = serialize($meta);
  274. if ( function_exists('mcrypt_encrypt') )
  275. {
  276. $init_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
  277. $init_vect = mcrypt_create_iv($init_size, MCRYPT_RAND);
  278. $meta = mcrypt_encrypt(
  279. MCRYPT_RIJNDAEL_256,
  280. md5($this->EE->db->username.$this->EE->db->password),
  281. $meta,
  282. MCRYPT_MODE_ECB,
  283. $init_vect
  284. );
  285. }
  286. else
  287. {
  288. $meta = $meta.md5($this->EE->db->username.$this->EE->db->password.$meta);
  289. }
  290. return base64_encode($meta);
  291. }
  292. // ------------------------------------------------------------------------
  293. /**
  294. * get Meta vars
  295. *
  296. * Get the meta variables on the POSTed form.
  297. *
  298. */
  299. protected function _get_meta_vars()
  300. {
  301. // Get data from the meta input
  302. if ( function_exists('mcrypt_encrypt') )
  303. {
  304. $init_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
  305. $init_vect = mcrypt_create_iv($init_size, MCRYPT_RAND);
  306. $meta_array = rtrim(
  307. mcrypt_decrypt(
  308. MCRYPT_RIJNDAEL_256,
  309. md5($this->EE->db->username.$this->EE->db->password),
  310. base64_decode($_POST['meta']),
  311. MCRYPT_MODE_ECB,
  312. $init_vect
  313. ),
  314. "\0"
  315. );
  316. }
  317. else
  318. {
  319. $raw = base64_decode($_POST['meta']);
  320. $hash = substr($raw, -32);
  321. $meta_array = substr($raw, 0, -32);
  322. if ($hash != md5($this->EE->db->username.$this->EE->db->password.$meta_array))
  323. {
  324. $meta_array = '';
  325. }
  326. }
  327. $this->_meta = unserialize($meta_array);
  328. // Check for Advanced Form Inputs
  329. $valid_inputs = array('search_in', 'where');
  330. foreach ($valid_inputs as $current_input)
  331. {
  332. if (
  333. ( ! isset($this->_meta[$current_input]) OR $this->_meta[$current_input] === '') &&
  334. $this->EE->input->post($current_input)
  335. )
  336. {
  337. $this->_meta[$current_input] = $this->EE->input->post($current_input);
  338. }
  339. }
  340. }
  341. // ------------------------------------------------------------------------
  342. /** ---------------------------------------
  343. /** Create the search query
  344. /** ---------------------------------------*/
  345. function build_standard_query()
  346. {
  347. $this->EE->load->model('addons_model');
  348. $channel_array = array();
  349. /** ---------------------------------------
  350. /** Fetch the channel_id numbers
  351. /** ---------------------------------------*/
  352. // If $_POST['channel_id'] exists we know the request is coming from the
  353. // advanced search form. We set those values to the $channel_id_array
  354. if (isset($_POST['channel_id']) AND is_array($_POST['channel_id']))
  355. {
  356. $channel_id_array = $_POST['channel_id'];
  357. }
  358. // Since both the simple and advanced search form have
  359. // $_POST['channel'], then we can safely find all of the
  360. // channels available for searching
  361. // By doing this for the advanced search form, we can discover
  362. // Which channels we are or are not supposed to search for, when
  363. // "Any Channel" is chosen
  364. $sql = "SELECT channel_id FROM exp_channels WHERE site_id = '".$this->EE->db->escape_str($this->EE->config->item('site_id'))."'";
  365. if (isset($this->_meta['channel']) AND $this->_meta['channel'] != '')
  366. {
  367. $sql .= $this->EE->functions->sql_andor_string($this->_meta['channel'], 'channel_name');
  368. }
  369. $query = $this->EE->db->query($sql);
  370. // If channel's are specified and there NO valid channels returned? There can be no results!
  371. if ($query->num_rows() == 0)
  372. {
  373. return FALSE;
  374. }
  375. foreach ($query->result_array() as $row)
  376. {
  377. $channel_array[] = $row['channel_id'];
  378. }
  379. /** ------------------------------------------------------
  380. /** Find the Common Channel IDs for Advanced Search Form
  381. /** ------------------------------------------------------*/
  382. if (isset($channel_id_array) && $channel_id_array['0'] != 'null')
  383. {
  384. $channel_array = array_intersect($channel_id_array, $channel_array);
  385. }
  386. /** ----------------------------------------------
  387. /** Fetch the channel_id numbers (from Advanced search)
  388. /** ----------------------------------------------*/
  389. // We do this up-front since we use this same sub-query in two places
  390. $id_query = '';
  391. if (count($channel_array) > 0)
  392. {
  393. foreach ($channel_array as $val)
  394. {
  395. if ($val != 'null' AND $val != '')
  396. {
  397. $id_query .= " exp_channel_titles.channel_id = '".$this->EE->db->escape_str($val)."' OR";
  398. }
  399. }
  400. if ($id_query != '')
  401. {
  402. $id_query = substr($id_query, 0, -2);
  403. $id_query = ' AND ('.$id_query.') ';
  404. }
  405. }
  406. /** ----------------------------------------------
  407. /** Limit to a specific member? We do this now
  408. /** as there's a potential for this to bring the
  409. /** search to an end if it's not a valid member
  410. /** ----------------------------------------------*/
  411. $member_array = array();
  412. $member_ids = '';
  413. if (isset($_GET['mbr']) AND is_numeric($_GET['mbr']))
  414. {
  415. $query = $this->EE->db->select('member_id')->get_where('members', array(
  416. 'member_id' => $_GET['mbr']
  417. ));
  418. if ($query->num_rows() != 1)
  419. {
  420. return FALSE;
  421. }
  422. else
  423. {
  424. $member_array[] = $query->row('member_id');
  425. }
  426. }
  427. else
  428. {
  429. if ($this->EE->input->post('member_name') != '')
  430. {
  431. $this->EE->db->select('member_id');
  432. if ($this->EE->input->post('exact_match') == 'y')
  433. {
  434. $this->EE->db->where('screen_name', $this->EE->input->post('member_name'));
  435. }
  436. else
  437. {
  438. $this->EE->db->like('screen_name', $this->EE->input->post('member_name'));
  439. }
  440. $query = $this->EE->db->get('members');
  441. if ($query->num_rows() == 0)
  442. {
  443. return FALSE;
  444. }
  445. else
  446. {
  447. foreach ($query->result_array() as $row)
  448. {
  449. $member_array[] = $row['member_id'];
  450. }
  451. }
  452. }
  453. }
  454. // and turn it into a string now so we only implode once
  455. if (count($member_array) > 0)
  456. {
  457. $member_ids = ' IN ('.implode(',', $member_array).') ';
  458. }
  459. unset($member_array);
  460. /** ---------------------------------------
  461. /** Fetch the searchable field names
  462. /** ---------------------------------------*/
  463. $fields = array();
  464. // no need to do this unless there are keywords to search
  465. if (trim($this->keywords) != '')
  466. {
  467. $xql = "SELECT DISTINCT(field_group) FROM exp_channels WHERE site_id = '".$this->EE->db->escape_str($this->EE->config->item('site_id'))."'";
  468. if ($id_query != '')
  469. {
  470. $xql .= $id_query.' ';
  471. $xql = str_replace('exp_channel_titles.', '', $xql);
  472. }
  473. $query = $this->EE->db->query($xql);
  474. if ($query->num_rows() > 0)
  475. {
  476. $this->EE->db->select('field_id, field_name, field_search');
  477. // Build array of field groups
  478. $field_groups = array();
  479. foreach ($query->result_array() as $row)
  480. {
  481. $field_groups[] = $row['field_group'];
  482. }
  483. if (count($field_groups) > 0)
  484. {
  485. $this->EE->db->where_in('group_id', $field_groups);
  486. }
  487. $field_query = $this->EE->db->get('channel_fields');
  488. if ($field_query->num_rows() > 0)
  489. {
  490. foreach ($field_query->result_array() as $row)
  491. {
  492. if ($row['field_search'] == 'y')
  493. {
  494. $fields[] = $row['field_id'];
  495. }
  496. $this->fields[$row['field_name']] = array($row['field_id'], $row['field_search']);
  497. }
  498. }
  499. }
  500. }
  501. /** ---------------------------------------
  502. /** Build the main query
  503. /** ---------------------------------------*/
  504. $sql = "SELECT
  505. DISTINCT(exp_channel_titles.entry_id)
  506. FROM exp_channel_titles
  507. LEFT JOIN exp_channels ON exp_channel_titles.channel_id = exp_channels.channel_id
  508. LEFT JOIN exp_channel_data ON exp_channel_titles.entry_id = exp_channel_data.entry_id ";
  509. // is the comment module installed?
  510. if ($this->EE->addons_model->module_installed('comment'))
  511. {
  512. $sql .= "LEFT JOIN exp_comments ON exp_channel_titles.entry_id = exp_comments.entry_id ";
  513. }
  514. $sql .= "LEFT JOIN exp_category_posts ON exp_channel_titles.entry_id = exp_category_posts.entry_id
  515. LEFT JOIN exp_categories ON exp_category_posts.cat_id = exp_categories.cat_id
  516. WHERE exp_channels.site_id = '".$this->EE->db->escape_str($this->EE->config->item('site_id'))."' ";
  517. /** ----------------------------------------------
  518. /** We only select entries that have not expired
  519. /** ----------------------------------------------*/
  520. if ( ! isset($this->_meta['show_future_entries']) OR $this->_meta['show_future_entries'] != 'yes')
  521. {
  522. $sql .= "\nAND exp_channel_titles.entry_date < ".$this->EE->localize->now." ";
  523. }
  524. if ( ! isset($this->_meta['show_expired']) OR $this->_meta['show_expired'] != 'yes')
  525. {
  526. $sql .= "\nAND (exp_channel_titles.expiration_date = 0 OR exp_channel_titles.expiration_date > ".$this->EE->localize->now.") ";
  527. }
  528. /** ----------------------------------------------
  529. /** Add status declaration to the query
  530. /** ----------------------------------------------*/
  531. if (isset($this->_meta['status']) AND ($status = $this->_meta['status']) != '')
  532. {
  533. $status = str_replace('Open', 'open', $status);
  534. $status = str_replace('Closed', 'closed', $status);
  535. $sql .= $this->EE->functions->sql_andor_string($status, 'exp_channel_titles.status');
  536. // add exclusion for closed unless it was explicitly used
  537. if (strncasecmp($status, 'not ', 4) == 0)
  538. {
  539. $status = trim(substr($status, 3));
  540. }
  541. $stati = explode('|', $status);
  542. if ( ! in_array('closed', $stati))
  543. {
  544. $sql .= "\nAND exp_channel_titles.status != 'closed' ";
  545. }
  546. }
  547. else
  548. {
  549. $sql .= "AND exp_channel_titles.status = 'open' ";
  550. }
  551. /** ----------------------------------------------
  552. /** Set Date filtering
  553. /** ----------------------------------------------*/
  554. if (isset($_POST['date']) AND $_POST['date'] != 0)
  555. {
  556. $cutoff = $this->EE->localize->now - (60*60*24*$_POST['date']);
  557. if (isset($_POST['date_order']) AND $_POST['date_order'] == 'older')
  558. {
  559. $sql .= "AND exp_channel_titles.entry_date < ".$cutoff." ";
  560. }
  561. else
  562. {
  563. $sql .= "AND exp_channel_titles.entry_date > ".$cutoff." ";
  564. }
  565. }
  566. /** ----------------------------------------------
  567. /** Add keyword to the query
  568. /** ----------------------------------------------*/
  569. if (trim($this->keywords) != '')
  570. {
  571. // So it begins
  572. $sql .= "\nAND (";
  573. /** -----------------------------------------
  574. /** Process our Keywords into Search Terms
  575. /** -----------------------------------------*/
  576. $this->keywords = stripslashes($this->keywords);
  577. $terms = array();
  578. $criteria = (isset($this->_meta['where']) && $this->_meta['where'] == 'all') ? 'AND' : 'OR';
  579. if (preg_match_all("/\-*\"(.*?)\"/", $this->keywords, $matches))
  580. {
  581. for($m=0; $m < count($matches['1']); $m++)
  582. {
  583. $terms[] = trim(str_replace('"','',$matches['0'][$m]));
  584. $this->keywords = str_replace($matches['0'][$m],'', $this->keywords);
  585. }
  586. }
  587. if (trim($this->keywords) != '')
  588. {
  589. $terms = array_merge($terms, preg_split("/\s+/", trim($this->keywords)));
  590. }
  591. $not_and = (count($terms) > 2) ? ') AND (' : 'AND';
  592. rsort($terms);
  593. $terms_like = $this->EE->db->escape_like_str($terms);
  594. $terms = $this->EE->db->escape_str($terms);
  595. /** ----------------------------------
  596. /** Search in Title Field
  597. /** ----------------------------------*/
  598. if (count($terms) == 1 && isset($this->_meta['where']) && $this->_meta['where'] == 'word') // Exact word match
  599. {
  600. $sql .= "((exp_channel_titles.title = '".$terms['0']."' OR exp_channel_titles.title LIKE '".$terms_like['0']." %' OR exp_channel_titles.title LIKE '% ".$terms_like['0']." %') ";
  601. // and close up the member clause
  602. if ($member_ids != '')
  603. {
  604. $sql .= " AND (exp_channel_titles.author_id {$member_ids})) \n";
  605. }
  606. else
  607. {
  608. $sql .= ") \n";
  609. }
  610. }
  611. elseif ( ! isset($_POST['exact_keyword'])) // Any terms, all terms
  612. {
  613. $mysql_function = (substr($terms['0'], 0,1) == '-') ? 'NOT LIKE' : 'LIKE';
  614. $search_term = (substr($terms['0'], 0,1) == '-') ? substr($terms_like['0'], 1) : $terms_like['0'];
  615. // We have three parentheses in the beginning in case
  616. // there are any NOT LIKE's being used and to allow for a member clause
  617. $sql .= "\n(((exp_channel_titles.title $mysql_function '%".$search_term."%' ";
  618. for ($i=1; $i < count($terms); $i++)
  619. {
  620. $mysql_criteria = ($mysql_function == 'NOT LIKE' OR substr($terms[$i], 0,1) == '-') ? $not_and : $criteria;
  621. $mysql_function = (substr($terms[$i], 0,1) == '-') ? 'NOT LIKE' : 'LIKE';
  622. $search_term = (substr($terms[$i], 0,1) == '-') ? substr($terms_like[$i], 1) : $terms_like[$i];
  623. $sql .= "$mysql_criteria exp_channel_titles.title $mysql_function '%".$search_term."%' ";
  624. }
  625. $sql .= ")) ";
  626. // and close up the member clause
  627. if ($member_ids != '')
  628. {
  629. $sql .= " AND (exp_channel_titles.author_id {$member_ids})) \n";
  630. }
  631. else
  632. {
  633. $sql .= ") \n";
  634. }
  635. }
  636. else // exact phrase match
  637. {
  638. $search_term = (count($terms) == 1) ? $terms_like[0] : $this->EE->db->escape_str($this->keywords);
  639. $sql .= "(exp_channel_titles.title LIKE '%".$search_term."%' ";
  640. // and close up the member clause
  641. if ($member_ids != '')
  642. {
  643. $sql .= " AND (exp_channel_titles.author_id {$member_ids})) \n";
  644. }
  645. else
  646. {
  647. $sql .= ") \n";
  648. }
  649. }
  650. /** ----------------------------------
  651. /** Search in Searchable Fields
  652. /** ----------------------------------*/
  653. if (isset($this->_meta['search_in']) AND ($this->_meta['search_in'] == 'entries' OR $this->_meta['search_in'] == 'everywhere'))
  654. {
  655. if (count($terms) > 1 && isset($this->_meta['where']) && $this->_meta['where'] == 'all' && ! isset($_POST['exact_keyword']) && count($fields) > 0)
  656. {
  657. $concat_fields = "CAST(CONCAT_WS(' ', exp_channel_data.field_id_".implode(', exp_channel_data.field_id_', $fields).') AS CHAR)';
  658. $mysql_function = (substr($terms['0'], 0,1) == '-') ? 'NOT LIKE' : 'LIKE';
  659. $search_term = (substr($terms['0'], 0,1) == '-') ? substr($terms['0'], 1) : $terms['0'];
  660. // Since Title is always required in a search we use OR
  661. // And then three parentheses just like above in case
  662. // there are any NOT LIKE's being used and to allow for a member clause
  663. $sql .= "\nOR ((($concat_fields $mysql_function '%".$search_term."%' ";
  664. for ($i=1; $i < count($terms); $i++)
  665. {
  666. $mysql_criteria = ($mysql_function == 'NOT LIKE' OR substr($terms[$i], 0,1) == '-') ? $not_and : $criteria;
  667. $mysql_function = (substr($terms[$i], 0,1) == '-') ? 'NOT LIKE' : 'LIKE';
  668. $search_term = (substr($terms[$i], 0,1) == '-') ? substr($terms_like[$i], 1) : $terms_like[$i];
  669. $sql .= "$mysql_criteria $concat_fields $mysql_function '%".$search_term."%' ";
  670. }
  671. $sql .= ")) ";
  672. // and close up the member clause
  673. if ($member_ids != '')
  674. {
  675. $sql .= " AND (exp_channel_titles.author_id {$member_ids})) \n";
  676. }
  677. else
  678. {
  679. $sql .= ") \n";
  680. }
  681. }
  682. else
  683. {
  684. foreach ($fields as $val)
  685. {
  686. if (count($terms) == 1 && isset($this->_meta['where']) && $this->_meta['where'] == 'word')
  687. {
  688. $sql .= "\nOR ((exp_channel_data.field_id_".$val." LIKE '".$terms_like['0']." %' OR exp_channel_data.field_id_".$val." LIKE '% ".$terms_like['0']." %' OR exp_channel_data.field_id_".$val." LIKE '% ".$terms_like['0']." %' OR exp_channel_data.field_id_".$val." = '".$terms['0']."') ";
  689. // and close up the member clause
  690. if ($member_ids != '')
  691. {
  692. $sql .= " AND (exp_channel_titles.author_id {$member_ids})) ";
  693. }
  694. else
  695. {
  696. $sql .= ") ";
  697. }
  698. }
  699. elseif ( ! isset($_POST['exact_keyword']))
  700. {
  701. $mysql_function = (substr($terms['0'], 0,1) == '-') ? 'NOT LIKE' : 'LIKE';
  702. $search_term = (substr($terms['0'], 0,1) == '-') ? substr($terms_like['0'], 1) : $terms_like['0'];
  703. // Since Title is always required in a search we use OR
  704. // And then three parentheses just like above in case
  705. // there are any NOT LIKE's being used and to allow for a member clause
  706. $sql .= "\nOR (((exp_channel_data.field_id_".$val." $mysql_function '%".$search_term."%' ";
  707. for ($i=1; $i < count($terms); $i++)
  708. {
  709. $mysql_criteria = ($mysql_function == 'NOT LIKE' OR substr($terms[$i], 0,1) == '-') ? $not_and : $criteria;
  710. $mysql_function = (substr($terms[$i], 0,1) == '-') ? 'NOT LIKE' : 'LIKE';
  711. $search_term = (substr($terms[$i], 0,1) == '-') ? substr($terms_like[$i], 1) : $terms_like[$i];
  712. $sql .= "$mysql_criteria exp_channel_data.field_id_".$val." $mysql_function '%".$search_term."%' ";
  713. }
  714. $sql .= ")) ";
  715. // and close up the member clause
  716. if ($member_ids != '')
  717. {
  718. $sql .= " AND (exp_channel_titles.author_id {$member_ids})) \n";
  719. }
  720. else
  721. {
  722. // close up the extra parenthesis
  723. $sql .= ") \n";
  724. }
  725. }
  726. else
  727. {
  728. $search_term = (count($terms) == 1) ? $terms_like[0] : $this->EE->db->escape_str($this->keywords);
  729. $sql .= "\nOR (exp_channel_data.field_id_".$val." LIKE '%".$search_term."%' ";
  730. // and close up the member clause
  731. if ($member_ids != '')
  732. {
  733. $sql .= " AND (exp_channel_titles.author_id {$member_ids})) \n";
  734. }
  735. else
  736. {
  737. // close up the extra parenthesis
  738. $sql .= ") \n";
  739. }
  740. }
  741. }
  742. }
  743. }
  744. /** ----------------------------------
  745. /** Search in Comments
  746. /** ----------------------------------*/
  747. if (isset($this->_meta['search_in']) AND $this->_meta['search_in'] == 'everywhere' AND $this->EE->addons_model->module_installed('comment'))
  748. {
  749. if (count($terms) == 1 && isset($this->_meta['where']) && $this->_meta['where'] == 'word')
  750. {
  751. $sql .= " OR (exp_comments.comment LIKE '% ".$terms_like['0']." %' ";
  752. // and close up the member clause
  753. if ($member_ids != '')
  754. {
  755. $sql .= " AND (exp_comments.author_id {$member_ids})) \n";
  756. }
  757. else
  758. {
  759. // close up the extra parenthesis
  760. $sql .= ") \n";
  761. }
  762. }
  763. elseif ( ! isset($_POST['exact_keyword']))
  764. {
  765. $mysql_function = (substr($terms['0'], 0,1) == '-') ? 'NOT LIKE' : 'LIKE';
  766. $search_term = (substr($terms['0'], 0,1) == '-') ? substr($terms_like['0'], 1) : $terms_like['0'];
  767. // We have three parentheses in the beginning in case
  768. // there are any NOT LIKE's being used and to allow a member clause
  769. $sql .= "\nOR (((exp_comments.comment $mysql_function '%".$search_term."%' ";
  770. for ($i=1; $i < count($terms); $i++)
  771. {
  772. $mysql_criteria = ($mysql_function == 'NOT LIKE' OR substr($terms[$i], 0,1) == '-') ? $not_and : $criteria;
  773. $mysql_function = (substr($terms[$i], 0,1) == '-') ? 'NOT LIKE' : 'LIKE';
  774. $search_term = (substr($terms[$i], 0,1) == '-') ? substr($terms_like[$i], 1) : $terms_like[$i];
  775. $sql .= "$mysql_criteria exp_comments.comment $mysql_function '%".$search_term."%' ";
  776. }
  777. $sql .= ")) ";
  778. // and close up the member clause
  779. if ($member_ids != '')
  780. {
  781. $sql .= " AND (exp_comments.author_id {$member_ids})) \n";
  782. }
  783. else
  784. {
  785. // close up the extra parenthesis
  786. $sql .= ") \n";
  787. }
  788. }
  789. else
  790. {
  791. $search_term = (count($terms) == 1) ? $terms_like[0] : $this->EE->db->escape_str($this->keywords);
  792. $sql .= " OR ((exp_comments.comment LIKE '%".$search_term."%') ";
  793. // and close up the member clause
  794. if ($member_ids != '')
  795. {
  796. $sql .= " AND (exp_comments.author_id {$member_ids})) \n";
  797. }
  798. else
  799. {
  800. // close up the extra parenthesis
  801. $sql .= ") \n";
  802. }
  803. }
  804. }
  805. // So it ends
  806. $sql .= ") \n";
  807. }
  808. else
  809. {
  810. // there are no keywords at all. Do we still need a member search?
  811. if ($member_ids != '')
  812. {
  813. $sql .= "AND (exp_channel_titles.author_id {$member_ids} ";
  814. // searching comments too?
  815. if (isset($this->_meta['search_in']) AND $this->_meta['search_in'] == 'everywhere' AND $this->EE->addons_model->module_installed('comment'))
  816. {
  817. $sql .= " OR exp_comments.author_id {$member_ids}";
  818. }
  819. $sql .= ")";
  820. }
  821. }
  822. //exit($sql);
  823. /** ----------------------------------------------
  824. /** Limit query to a specific channel
  825. /** ----------------------------------------------*/
  826. if (count($channel_array) > 0)
  827. {
  828. $sql .= $id_query;
  829. }
  830. /** ----------------------------------------------
  831. /** Limit query to a specific category
  832. /** ----------------------------------------------*/
  833. // Check for different sets of category IDs, checking the parameters
  834. // first, then the $_POST
  835. if (isset($this->_meta['category']) AND $this->_meta['category'] != '' AND ! is_array($this->_meta['category']))
  836. {
  837. $this->_meta['category'] = explode('|', $this->_meta['category']);
  838. }
  839. else if (
  840. ( ! isset($this->_meta['category']) OR $this->_meta['category'] == '') AND
  841. (isset($_POST['cat_id']) AND is_array($_POST['cat_id']))
  842. )
  843. {
  844. $this->_meta['category'] = $_POST['cat_id'];
  845. }
  846. else
  847. {
  848. $this->_meta['category'] = '';
  849. }
  850. if (is_array($this->_meta['category']))
  851. {
  852. $temp = '';
  853. foreach ($this->_meta['category'] as $val)
  854. {
  855. if ($val != 'all' AND $val != '')
  856. {
  857. $temp .= " exp_categories.cat_id = '".$this->EE->db->escape_str($val)."' OR";
  858. }
  859. }
  860. if ($temp != '')
  861. {
  862. $temp = substr($temp, 0, -2);
  863. $sql .= ' AND ('.$temp.') ';
  864. }
  865. }
  866. /** ----------------------------------------------
  867. /** Are there results?
  868. /** ----------------------------------------------*/
  869. $query = $this->EE->db->query($sql);
  870. if ($query->num_rows() == 0)
  871. {
  872. return FALSE;
  873. }
  874. $this->num_rows = $query->num_rows();
  875. /** ----------------------------------------------
  876. /** Set sort order
  877. /** ----------------------------------------------*/
  878. $order_by = ( ! isset($_POST['order_by'])) ? 'date' : $_POST['order_by'];
  879. $orderby = ( ! isset($_POST['orderby'])) ? $order_by : $_POST['orderby'];
  880. $end = '';
  881. switch ($orderby)
  882. {
  883. case 'most_comments':
  884. $end .= " ORDER BY comment_total ";
  885. break;
  886. case 'recent_comment':
  887. $end .= " ORDER BY recent_comment_date ";
  888. break;
  889. case 'title':
  890. $end .= " ORDER BY title ";
  891. break;
  892. default:
  893. $end .= " ORDER BY entry_date ";
  894. break;
  895. }
  896. $order = ( ! isset($_POST['sort_order'])) ? 'desc' : $_POST['sort_order'];
  897. if ($order != 'asc' AND $order != 'desc')
  898. {
  899. $order = 'desc';
  900. }
  901. $end .= " ".$order;
  902. $sql = "SELECT DISTINCT(t.entry_id), t.entry_id, t.channel_id, t.forum_topic_id, t.author_id, t.ip_address, t.title, t.url_title, t.status, t.dst_enabled, t.view_count_one, t.view_count_two, t.view_count_three, t.view_count_four, t.allow_comments, t.comment_expiration_date, t.sticky, t.entry_date, t.year, t.month, t.day, t.entry_date, t.edit_date, t.expiration_date, t.recent_comment_date, t.comment_total, t.site_id as entry_site_id,
  903. w.channel_title, w.channel_name, w.search_results_url, w.search_excerpt, w.channel_url, w.comment_url, w.comment_moderate, w.channel_html_formatting, w.channel_allow_img_urls, w.channel_auto_link_urls, w.comment_system_enabled,
  904. m.username, m.email, m.url, m.screen_name, m.location, m.occupation, m.interests, m.aol_im, m.yahoo_im, m.msn_im, m.icq, m.signature, m.sig_img_filename, m.sig_img_width, m.sig_img_height, m.avatar_filename, m.avatar_width, m.avatar_height, m.photo_filename, m.photo_width, m.photo_height, m.group_id, m.member_id, m.bday_d, m.bday_m, m.bday_y, m.bio,
  905. md.*,
  906. wd.*
  907. FROM exp_channel_titles AS t
  908. LEFT JOIN exp_channels AS w ON t.channel_id = w.channel_id
  909. LEFT JOIN exp_channel_data AS wd ON t.entry_id = wd.entry_id
  910. LEFT JOIN exp_members AS m ON m.member_id = t.author_id
  911. LEFT JOIN exp_member_data AS md ON md.member_id = m.member_id
  912. WHERE t.entry_id IN (";
  913. foreach ($query->result_array() as $row)
  914. {
  915. $sql .= $row['entry_id'].',';
  916. }
  917. $sql = substr($sql, 0, -1).') '.$end;
  918. return $sql;
  919. }
  920. // ------------------------------------------------------------------------
  921. /** ----------------------------------------
  922. /** Total search results
  923. /** ----------------------------------------*/
  924. function total_results()
  925. {
  926. /** ----------------------------------------
  927. /** Check search ID number
  928. /** ----------------------------------------*/
  929. // If the QSTR variable is less than 32 characters long we
  930. // don't have a valid search ID number
  931. if (strlen($this->EE->uri->query_string) < 32)
  932. {
  933. return '';
  934. }
  935. /** ----------------------------------------
  936. /** Fetch ID number and page number
  937. /** ----------------------------------------*/
  938. $search_id = substr($this->EE->uri->query_string, 0, 32);
  939. /** ----------------------------------------
  940. /** Fetch the cached search query
  941. /** ----------------------------------------*/
  942. $query = $this->EE->db->query("SELECT total_results FROM exp_search WHERE search_id = '".$this->EE->db->escape_str($search_id)."'");
  943. if ($query->num_rows() == 1)
  944. {
  945. return $query->row('total_results') ;
  946. }
  947. else
  948. {
  949. return 0;
  950. }
  951. }
  952. /** ----------------------------------------
  953. /** Search keywords
  954. /** ----------------------------------------*/
  955. function keywords()
  956. {
  957. /** ----------------------------------------
  958. /** Check search ID number
  959. /** ----------------------------------------*/
  960. // If the QSTR variable is less than 32 characters long we
  961. // don't have a valid search ID number
  962. if (strlen($this->EE->uri->query_string) < 32)
  963. {
  964. return '';
  965. }
  966. /** ----------------------------------------
  967. /** Fetch ID number and page number
  968. /** ----------------------------------------*/
  969. $search_id = substr($this->EE->uri->query_string, 0, 32);
  970. /** ----------------------------------------
  971. /** Fetch the cached search query
  972. /** ----------------------------------------*/
  973. $query = $this->EE->db->query("SELECT keywords FROM exp_search WHERE search_id = '".$this->EE->db->escape_str($search_id)."'");
  974. if ($query->num_rows() == 1)
  975. {
  976. // Load the XML Helper
  977. $this->EE->load->helper('xml');
  978. return $this->EE->functions->encode_ee_tags(xml_convert($query->row('keywords')));
  979. }
  980. else
  981. {
  982. return '';
  983. }
  984. }
  985. /** ----------------------------------------
  986. /** Show search results
  987. /** ----------------------------------------*/
  988. function search_results()
  989. {
  990. // Fetch the search language file
  991. $this->EE->lang->loadfile('search');
  992. // Load Pagination Object
  993. $this->EE->load->library('pagination');
  994. $pagination = new Pagination_object(__CLASS__);
  995. // Capture Pagination Template
  996. $pagination->get_template();
  997. // Check to see if we're using old style pagination
  998. // TODO: Remove once old pagination is phased out
  999. $old_pagination = (strpos($this->EE->TMPL->template, LD.'if paginate'.RD) !== FALSE) ? TRUE : FALSE;
  1000. // If we are using old pagination, log it as deprecated
  1001. // TODO: Remove once old pagination is phased out
  1002. if ($old_pagination)
  1003. {
  1004. $this->EE->load->library('logger');
  1005. $this->EE->logger->developer('Deprecated template tag {if paginate}. Old style pagination in the Search Module has been deprecated in 2.4 and will be removed soon. Switch to the new Channel style pagination.', TRUE);
  1006. }
  1007. // Check search ID number
  1008. // If the QSTR variable is less than 32 characters long we
  1009. // don't have a valid search ID number
  1010. if (strlen($this->EE->uri->query_string) < 32)
  1011. {
  1012. return $this->EE->output->show_user_error(
  1013. 'off',
  1014. array(lang('search_no_result')),
  1015. lang('search_result_heading')
  1016. );
  1017. }
  1018. // Clear old search results
  1019. $this->EE->db->delete(
  1020. 'search',
  1021. array(
  1022. 'site_id' => $this->EE->config->item('site_id'),
  1023. 'search_date <' => $this->EE->localize->now - ($this->cache_expire * 3600)
  1024. )
  1025. );
  1026. // Fetch ID number and page number
  1027. $pagination->offset = 0;
  1028. $qstring = $this->EE->uri->query_string;
  1029. // Parse page number
  1030. if (preg_match("#^P(\d+)|/P(\d+)#", $qstring, $match))
  1031. {
  1032. $pagination->offset = (isset($match[2])) ? $match[2] : $match[1];
  1033. $search_id = trim_slashes(str_replace($match[0], '', $qstring));
  1034. }
  1035. else
  1036. {
  1037. $pagination->offset = 0;
  1038. $search_id = $qstring;
  1039. }
  1040. // If there is a slash in the search ID we'll kill everything after it.
  1041. $search_id = trim($search_id);
  1042. $search_id = preg_replace("#/.+#", "", $search_id);
  1043. // Fetch the cached search query
  1044. $query = $this->EE->db->get_where('search', array('search_id' => $search_id));
  1045. if ($query->num_rows() == 0 OR $query->row('total_results') == 0)
  1046. {
  1047. return $this->EE->output->show_user_error('off', array(lang('search_no_result')), lang('search_result_heading'));
  1048. }
  1049. $fields = ($query->row('custom_fields') == '') ? array() : unserialize(stripslashes($query->row('custom_fields') ));
  1050. $sql = unserialize(stripslashes($query->row('query')));
  1051. $sql = str_replace('MDBMPREFIX', 'exp_', $sql);
  1052. $pagination->per_page = (int) $query->row('per_page');
  1053. $res_page = $query->row('result_page');
  1054. // Run the search query
  1055. $query = $this->EE->db->query(preg_replace("/SELECT(.*?)\s+FROM\s+/is", 'SELECT COUNT(*) AS count FROM ', $sql));
  1056. if ($query->row('count') == 0)
  1057. {
  1058. return $this->EE->output->show_user_error('off', array(lang('search_no_result')), lang('search_result_heading'));
  1059. }
  1060. // Calculate total number of pages and add total rows
  1061. $pagination->current_page = ($pagination->offset / $pagination->per_page) + 1;
  1062. $pagination->total_rows = $query->row('count');
  1063. // Figure out total number of pages for old style pagination
  1064. // TODO: Remove once old pagination is phased out
  1065. if ($old_pagination)
  1066. {
  1067. $total_pages = intval($pagination->total_rows / $pagination->per_page);
  1068. if ($pagination->total_rows % $pagination->per_page)
  1069. {
  1070. $total_pages++;
  1071. }
  1072. $page_count = lang('page').' '.$pagination->current_page.' '.lang('of').' '.$total_pages;
  1073. $pager = '';
  1074. if ($pagination->total_rows > $pagination->per_page)
  1075. {
  1076. $this->EE->load->library('pagination');
  1077. $config = array(
  1078. 'base_url' => $this->EE->functions->create_url($res_page.'/'.$search_id, 0, 0),
  1079. 'prefix' => 'P',
  1080. 'total_rows' => $pagination->total_rows,
  1081. 'per_page' => $pagination->per_page,
  1082. 'cur_page' => $pagination->offset,
  1083. 'first_link' => lang('pag_first_link'),
  1084. 'last_link' => lang('pag_last_link'),
  1085. 'uri_segment' => 0 // Allows $config['cur_page'] to override
  1086. );
  1087. $this->EE->pagination->initialize($config);
  1088. $pager = $this->EE->pagination->create_links();
  1089. }
  1090. }
  1091. // Build pagination if enabled
  1092. if ($pagination->paginate === TRUE)
  1093. {
  1094. $pagination->build($pagination->total_rows);
  1095. }
  1096. // If we're paginating, old or new, limit the query and do it again
  1097. if ($pagination->paginate === TRUE OR $old_pagination)
  1098. {
  1099. $sql .= " LIMIT ".$pagination->offset.", ".$pagination->per_page;
  1100. }
  1101. else if ($pagination->per_page > 0)
  1102. {
  1103. $sql .= " LIMIT 0, ".$pagination->per_page;
  1104. }
  1105. else
  1106. {
  1107. $sql .= " LIMIT 0, 100";
  1108. }
  1109. $query = $this->EE->db->query($sql);
  1110. $output = '';
  1111. if ( ! class_exists('Channel'))
  1112. {
  1113. require PATH_MOD.'channel/mod.channel.php';
  1114. }
  1115. unset($this->EE->TMPL->var_single['auto_path']);
  1116. unset($this->EE->TMPL->var_single['excerpt']);
  1117. unset($this->EE->TMPL->var_single['id_auto_path']);
  1118. unset($this->EE->TMPL->var_single['full_text']);
  1119. unset($this->EE->TMPL->var_single['switch']);
  1120. foreach($this->EE->TMPL->var_single as $key => $value)
  1121. {
  1122. if (substr($key, 0, strlen('member_path')) == 'member_path')
  1123. {
  1124. unset($this->EE->TMPL->var_single[$key]);
  1125. }
  1126. }
  1127. $channel = new Channel;
  1128. // This allows the channel {absolute_count} variable to work
  1129. $channel->p_page = ($pagination->per_page * $pagination->current_page) - $pagination->per_page;
  1130. $channel->fetch_custom_channel_fields();
  1131. $channel->fetch_custom_member_fields();
  1132. $channel->query = $this->EE->db->query($sql);
  1133. if ($channel->query->num_rows() == 0)
  1134. {
  1135. return $this->EE->TMPL->no_results();
  1136. }
  1137. $this->EE->load->library('typography');
  1138. $this->EE->typography->initialize(array(
  1139. 'convert_curly' => FALSE,
  1140. 'encode_email' => FALSE
  1141. ));
  1142. $channel->fetch_categories();
  1143. $channel->parse_channel_entries();
  1144. $tagdata = $this->EE->TMPL->tagdata;
  1145. // Does the tag contain "related entries" that we need to parse out?
  1146. if (count($this->EE->TMPL->related_data) > 0 AND count($channel->related_entries) > 0)
  1147. {
  1148. $channel->parse_related_entries();
  1149. }
  1150. if (count($this->EE->TMPL->reverse_related_data) > 0 AND count($channel->reverse_related_entries) > 0)
  1151. {
  1152. $channel->parse_reverse_related_entries();
  1153. }
  1154. $output = $channel->return_data;
  1155. $this->EE->TMPL->tagdata = $tagdata;
  1156. // Fetch member path variable
  1157. // We do it here in case it's used in multiple places.
  1158. $m_paths = array();
  1159. if (preg_match_all("/".LD."member_path(\s*=.*?)".RD."/s", $this->EE->TMPL->tagdata, $matches))
  1160. {
  1161. for ($j = 0; $j < count($matches['0']); $j++)
  1162. {
  1163. $m_paths[] = array($matches['0'][$j], $this->EE->functions->extract_path($matches['1'][$j]));
  1164. }
  1165. }
  1166. // Fetch switch param
  1167. $switch1 = '';
  1168. $switch2 = '';
  1169. if ($switch = $this->EE->TMPL->fetch_param('switch'))
  1170. {
  1171. if (strpos($switch, '|') !== FALSE)
  1172. {
  1173. $x = explode("|", $switch);
  1174. $switch1 = $x['0'];
  1175. $switch2 = $x['1'];
  1176. }
  1177. else
  1178. {
  1179. $switch1 = $switch;
  1180. }
  1181. }
  1182. /** -----------------------------
  1183. /** Result Loop - Legacy!
  1184. /** -----------------------------*/
  1185. $i = 0;
  1186. foreach ($query->result_array() as $row)
  1187. {
  1188. if (isset($row['field_id_'.$row['search_excerpt']]) AND $row['field_id_'.$row['search_excerpt']])
  1189. {
  1190. $format = ( ! isset($row['field_ft_'.$row['search_excerpt']])) ? 'xhtml' : $row['field_ft_'.$row['search_excerpt']];
  1191. $full_text = $this->EE->typography->parse_type(
  1192. strip_tags($row['field_id_'.$row['search_excerpt']]),
  1193. array(
  1194. 'text_format' => $format,
  1195. 'html_format' => 'safe',
  1196. 'auto_links' => 'y',
  1197. 'allow_img_url' => 'n'
  1198. )
  1199. );
  1200. $excerpt = trim(strip_tags($full_text));
  1201. if (strpos($excerpt, "\r") !== FALSE OR strpos($excerpt, "\n") !== FALSE)
  1202. {
  1203. $excerpt = str_replace(array("\r\n", "\r", "\n"), " ", $excerpt);
  1204. }
  1205. $excerpt = $this->EE->functions->word_limiter($excerpt, 50);
  1206. }
  1207. else
  1208. {
  1209. $excerpt = '';
  1210. $full_text = '';
  1211. }
  1212. // Parse permalink path
  1213. $url = ($row['search_results_url'] != '') ? $row['search_results_url'] : $row['channel_url'];
  1214. $path = $this->EE->functions->remove_double_slashes($this->EE->functions->prep_query_string($url).'/'.$row['url_title']);
  1215. $idpath = $this->EE->functions->remove_double_slashes($this->EE->functions->prep_query_string($url).'/'.$row['entry_id']);
  1216. $switch = ($i++ % 2) ? $switch1 : $switch2;
  1217. $output = preg_replace("/".LD.'switch'.RD."/", $switch, $output, count(explode(LD.'switch'.RD, $this->EE->TMPL->tagdata)) - 1);
  1218. $output = preg_replace("/".LD.'auto_path'.RD."/", $path, $output, count(explode(LD.'auto_path'.RD, $this->EE->TMPL->tagdata)) - 1);
  1219. $output = preg_replace("/".LD.'id_auto_path'.RD."/", $idpath, $output, count(explode(LD.'id_auto_path'.RD, $this->EE->TMPL->tagdata)) - 1);
  1220. $output = preg_replace("/".LD.'excerpt'.RD."/", preg_quote($excerpt), $output, count(explode(LD.'excerpt'.RD, $this->EE->TMPL->tagdata)) - 1);
  1221. $output = preg_replace("/".LD.'full_text'.RD."/", preg_quote($full_text), $output, count(explode(LD.'full_text'.RD, $this->EE->TMPL->tagdata)) - 1);
  1222. // Parse member_path
  1223. if (count($m_paths) > 0)
  1224. {
  1225. foreach ($m_paths as $val)
  1226. {
  1227. $output = preg_replace(
  1228. "/".preg_quote($val['0'], '/')."/",
  1229. $this->EE->functions->create_url($val['1'].'/'.$row['member_id']),
  1230. $output,
  1231. 1
  1232. );
  1233. }
  1234. }
  1235. }
  1236. $this->EE->TMPL->tagdata = $output;
  1237. // Add new pagination
  1238. $this->EE->TMPL->tagdata = $pagination->render($this->EE->TMPL->tagdata);
  1239. // Parse lang variables
  1240. $swap = array(
  1241. 'lang:total_search_results' => lang('search_total_results'),
  1242. 'lang:search_engine' => lang('search_engine'),
  1243. 'lang:search_results' => lang('search_results'),
  1244. 'lang:search' => lang('search'),
  1245. 'lang:title' => lang('search_title'),
  1246. 'lang:channel' => lang('search_channel'),
  1247. 'lang:excerpt' => lang('search_excerpt'),
  1248. 'lang:author' => lang('search_author'),
  1249. 'lang:date' => lang('search_date'),
  1250. 'lang:total_comments' => lang('search_total_comments'),
  1251. 'lang:recent_comments' => lang('search_recent_comment_date'),
  1252. 'lang:keywords' => lang('search_keywords')
  1253. );
  1254. $this->EE->TMPL->template = $this->EE->functions->var_swap($this->EE->TMPL->template, $swap);
  1255. // Add Old Style Pagination
  1256. // TODO: Remove once old pagination is phased out
  1257. if ($old_pagination)
  1258. {
  1259. if ($pager == '')
  1260. {
  1261. $this->EE->TMPL->template = preg_replace(
  1262. "#".LD."if paginate".RD.".*?".LD."/if".RD."#s",
  1263. '',
  1264. $this->EE->TMPL->template
  1265. );
  1266. }
  1267. else
  1268. {
  1269. $this->EE->TMPL->template = preg_replace(
  1270. "#".LD."if paginate".RD."(.*?)".LD."/if".RD."#s",
  1271. "\\1",
  1272. $this->EE->TMPL->template
  1273. );
  1274. }
  1275. $this->EE->TMPL->template = str_replace(
  1276. LD.'paginate'.RD,
  1277. $pager,
  1278. $this->EE->TMPL->template
  1279. );
  1280. $this->EE->TMPL->template = str_replace(
  1281. LD.'page_count'.RD,
  1282. $page_count,
  1283. $this->EE->TMPL->template
  1284. );
  1285. }
  1286. return stripslashes($this->EE->TMPL->tagdata);
  1287. }
  1288. // --------------------------------------------------------------------------
  1289. /**
  1290. * Simple Search Form
  1291. *
  1292. * Generate the simple search form
  1293. */
  1294. function simple_form()
  1295. {
  1296. $meta = $this->_build_meta_array();
  1297. $data['hidden_fields'] = array(
  1298. 'ACT' => $this->EE->functions->fetch_action_id('Search', 'do_search'),
  1299. 'XID' => '',
  1300. 'RES' => $this->EE->TMPL->fetch_param('results'),
  1301. 'meta' => $meta
  1302. );
  1303. if ($this->EE->TMPL->fetch_param('name') !== FALSE &&
  1304. preg_match("#^[a-zA-Z0-9_\-]+$#i", $this->EE->TMPL->fetch_param('name')))
  1305. {
  1306. $data['name'] = $this->EE->TMPL->fetch_param('name');
  1307. }
  1308. if ($this->EE->TMPL->fetch_param('id') !== FALSE &&
  1309. preg_match("#^[a-zA-Z0-9_\-]+$#i", $this->EE->TMPL->fetch_param('id')))
  1310. {
  1311. $data['id'] = $this->EE->TMPL->fetch_param('id');
  1312. $this->EE->TMPL->log_item('Simple Search Form: The \'id\' parameter has been deprecated. Please use form_id');
  1313. }
  1314. else
  1315. {

Large files files are truncated, but you can click here to view the full file