PageRenderTime 65ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/system/expressionengine/libraries/Functions.php

https://bitbucket.org/studiobreakfast/sync
PHP | 2978 lines | 1902 code | 433 blank | 643 comment | 379 complexity | c3d150b95d4358ee3c721df715806c5c 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 Core Functions Class
  16. *
  17. * @package ExpressionEngine
  18. * @subpackage Core
  19. * @category Core
  20. * @author EllisLab Dev Team
  21. * @link http://expressionengine.com
  22. */
  23. class EE_Functions {
  24. var $seed = FALSE; // Whether we've seeded our rand() function. We only seed once per script execution
  25. var $cached_url = array();
  26. var $cached_path = array();
  27. var $cached_index = array();
  28. var $cached_captcha = '';
  29. var $template_map = array();
  30. var $template_type = '';
  31. var $action_ids = array();
  32. var $file_paths = array();
  33. var $conditional_debug = FALSE;
  34. var $catfields = array();
  35. /**
  36. * Constructor
  37. */
  38. function __construct()
  39. {
  40. // Make a local reference to the ExpressionEngine super object
  41. $this->EE =& get_instance();
  42. }
  43. // --------------------------------------------------------------------
  44. /**
  45. * Fetch base site index
  46. *
  47. * @access public
  48. * @param bool
  49. * @param bool
  50. * @return string
  51. */
  52. function fetch_site_index($add_slash = FALSE, $sess_id = TRUE)
  53. {
  54. if (isset($this->cached_index[$add_slash.$sess_id.$this->template_type]))
  55. {
  56. return $this->cached_index[$add_slash.$sess_id.$this->template_type];
  57. }
  58. $url = $this->EE->config->slash_item('site_url');
  59. $url .= $this->EE->config->item('site_index');
  60. if ($this->EE->config->item('force_query_string') == 'y')
  61. {
  62. $url .= '?';
  63. }
  64. if (is_object($this->EE->session) && $this->EE->session->userdata('session_id') != '' && REQ != 'CP' && $sess_id == TRUE &&
  65. $this->EE->config->item('user_session_type') != 'c' && $this->template_type == 'webpage')
  66. {
  67. $url .= "/S=".$this->EE->session->userdata('session_id')."/";
  68. }
  69. if ($add_slash == TRUE)
  70. {
  71. if (substr($url, -1) != '/')
  72. {
  73. $url .= "/";
  74. }
  75. }
  76. $this->cached_index[$add_slash.$sess_id.$this->template_type] = $url;
  77. return $url;
  78. }
  79. // --------------------------------------------------------------------
  80. /**
  81. * Create a custom URL
  82. *
  83. * The input to this function is parsed and added to the
  84. * full site URL to create a full URL/URI
  85. *
  86. * @access public
  87. * @param string
  88. * @param bool
  89. * @return string
  90. */
  91. function create_url($segment, $sess_id = TRUE)
  92. {
  93. // Since this function can be used via a callback
  94. // we'll fetch the segment if it's an array
  95. if (is_array($segment))
  96. {
  97. $segment = $segment[1];
  98. }
  99. if (isset($this->cached_url[$segment]))
  100. {
  101. return $this->cached_url[$segment];
  102. }
  103. $full_segment = $segment;
  104. $segment = str_replace(array("'", '"'), '', $segment);
  105. $segment = preg_replace("/(.+?(\/))index(\/)(.*?)/", "\\1\\2", $segment);
  106. $segment = preg_replace("/(.+?(\/))index$/", "\\1", $segment);
  107. // These are exceptions to the normal path rules
  108. if ($segment == '' OR strtolower($segment) == 'site_index')
  109. {
  110. return $this->fetch_site_index();
  111. }
  112. if (strtolower($segment) == 'logout')
  113. {
  114. $qs = ($this->EE->config->item('force_query_string') == 'y') ? '' : '?';
  115. return $this->fetch_site_index(0, 0).$qs.'ACT='.$this->fetch_action_id('Member', 'member_logout');
  116. }
  117. // END Specials
  118. // Load the string helper
  119. $this->EE->load->helper('string');
  120. $base = $this->fetch_site_index(0, $sess_id).'/'.trim_slashes($segment);
  121. $out = $this->remove_double_slashes($base);
  122. $this->cached_url[$full_segment] = $out;
  123. return $out;
  124. }
  125. // --------------------------------------------------------------------
  126. /**
  127. * Creates a url for Pages links
  128. *
  129. * @access public
  130. * @return string
  131. */
  132. function create_page_url($base_url, $segment, $trailing_slash = FALSE)
  133. {
  134. // Load the string helper
  135. $this->EE->load->helper('string');
  136. if ($this->EE->config->item('force_query_string') == 'y')
  137. {
  138. if (strpos($base_url, $this->EE->config->item('index_page') . '/') !== FALSE)
  139. {
  140. $base_url = rtrim($base_url, '/');
  141. }
  142. $base_url .= '?';
  143. }
  144. $base = $base_url.'/'.trim_slashes($segment);
  145. if (substr($base, -1) != '/' && $trailing_slash == TRUE)
  146. {
  147. $base .= '/';
  148. }
  149. $out = $this->remove_double_slashes($base);
  150. return $out;
  151. }
  152. // --------------------------------------------------------------------
  153. /**
  154. * Fetch site index with URI query string
  155. *
  156. * @access public
  157. * @return string
  158. */
  159. function fetch_current_uri()
  160. {
  161. return rtrim($this->remove_double_slashes($this->fetch_site_index(1).$this->EE->uri->uri_string), '/');
  162. }
  163. // --------------------------------------------------------------------
  164. /**
  165. * Prep Query String
  166. *
  167. * This function checks to see if "Force Query Strings" is on.
  168. * If so it adds a question mark to the URL if needed
  169. *
  170. * @access public
  171. * @param string
  172. * @return string
  173. */
  174. function prep_query_string($str)
  175. {
  176. if (stristr($str, '.php') && substr($str, -7) == '/index/')
  177. {
  178. $str = substr($str, 0, -6);
  179. }
  180. if (strpos($str, '?') === FALSE && $this->EE->config->item('force_query_string') == 'y')
  181. {
  182. if (stristr($str, '.php'))
  183. {
  184. $str = preg_replace("#(.+?)\.php(.*?)#", "\\1.php?\\2", $str);
  185. }
  186. else
  187. {
  188. $str .= "?";
  189. }
  190. }
  191. return $str;
  192. }
  193. // --------------------------------------------------------------------
  194. /**
  195. * Convert EE Tags to Entities
  196. *
  197. * @access public
  198. * @param string
  199. * @param bool
  200. * @return string
  201. */
  202. function encode_ee_tags($str, $convert_curly = FALSE)
  203. {
  204. if ($str != '' && strpos($str, '{') !== FALSE)
  205. {
  206. if ($convert_curly === TRUE)
  207. {
  208. $str = str_replace(array('{', '}'), array('&#123;', '&#125;'), $str);
  209. }
  210. else
  211. {
  212. $str = preg_replace("/\{(\/){0,1}exp:(.+?)\}/", "&#123;\\1exp:\\2&#125;", $str);
  213. $str = str_replace(array('{exp:', '{/exp'), array('&#123;exp:', '&#123;\exp'), $str);
  214. $str = preg_replace("/\{embed=(.+?)\}/", "&#123;embed=\\1&#125;", $str);
  215. $str = preg_replace("/\{path:(.+?)\}/", "&#123;path:\\1&#125;", $str);
  216. $str = preg_replace("/\{redirect=(.+?)\}/", "&#123;redirect=\\1&#125;", $str);
  217. }
  218. }
  219. return $str;
  220. }
  221. // --------------------------------------------------------------------
  222. /**
  223. * Remove duplicate slashes from URL
  224. *
  225. * With all the URL/URI parsing/building, there is the potential
  226. * to end up with double slashes. This is a clean-up function.
  227. *
  228. * @access public
  229. * @param string
  230. * @return string
  231. */
  232. function remove_double_slashes($str)
  233. {
  234. return preg_replace("#(^|[^:])//+#", "\\1/", $str);
  235. }
  236. // --------------------------------------------------------------------
  237. /**
  238. * Extract path info
  239. *
  240. * We use this to extract the template group/template name
  241. * from path variables, like {some_var path="channel/index"}
  242. *
  243. * @access public
  244. * @param string
  245. * @return string
  246. */
  247. function extract_path($str)
  248. {
  249. if (preg_match("#=(.*)#", $str, $match))
  250. {
  251. $match[1] = trim($match[1], '}');
  252. if (isset($this->cached_path[$match[1]]))
  253. {
  254. return $this->cached_path[$match[1]];
  255. }
  256. // Load the string helper
  257. $this->EE->load->helper('string');
  258. $path = trim_slashes(str_replace(array("'",'"'), "", $match[1]));
  259. if (substr($path, -6) == 'index/')
  260. {
  261. $path = str_replace('/index', '', $path);
  262. }
  263. if (substr($path, -5) == 'index')
  264. {
  265. $path = str_replace('/index', '', $path);
  266. }
  267. $this->cached_path[$match[1]] = $path;
  268. return $path;
  269. }
  270. else
  271. {
  272. return 'SITE_INDEX';
  273. }
  274. }
  275. // --------------------------------------------------------------------
  276. /**
  277. * Replace variables
  278. *
  279. * @access public
  280. * @param string
  281. * @param string
  282. * @return string
  283. */
  284. function var_swap($str, $data)
  285. {
  286. if ( ! is_array($data))
  287. {
  288. return FALSE;
  289. }
  290. foreach ($data as $key => $val)
  291. {
  292. $str = str_replace('{'.$key.'}', $val, $str);
  293. }
  294. return $str;
  295. }
  296. // --------------------------------------------------------------------
  297. /**
  298. * Redirect
  299. *
  300. * @access public
  301. * @param string
  302. * @return void
  303. */
  304. function redirect($location, $method = FALSE)
  305. {
  306. // Remove hard line breaks and carriage returns
  307. $location = str_replace(array("\n", "\r"), '', $location);
  308. // Remove any and all line breaks
  309. while (stripos($location, '%0d') !== FALSE OR stripos($location, '%0a') !== FALSE)
  310. {
  311. $location = str_ireplace(array('%0d', '%0a'), '', $location);
  312. }
  313. $location = str_replace('&amp;', '&', $this->insert_action_ids($location));
  314. if (count($this->EE->session->flashdata))
  315. {
  316. // Ajax requests don't redirect - serve the flashdata
  317. if ($this->EE->input->is_ajax_request())
  318. {
  319. // We want the data that would be available for the next request
  320. $this->EE->session->_age_flashdata();
  321. $this->EE->load->library('javascript');
  322. die($this->EE->javascript->generate_json(
  323. $this->EE->session->flashdata));
  324. }
  325. }
  326. if ($method === FALSE)
  327. {
  328. $method = $this->EE->config->item('redirect_method');
  329. }
  330. switch($method)
  331. {
  332. case 'refresh' : header("Refresh: 0;url=$location");
  333. break;
  334. default : header("Location: $location");
  335. break;
  336. }
  337. exit;
  338. }
  339. // --------------------------------------------------------------------
  340. /**
  341. * Convert a string into an encrypted hash
  342. * DEPRECATED 2.0
  343. *
  344. * @access public
  345. * @param string
  346. * @return string
  347. */
  348. function hash($str)
  349. {
  350. $this->EE->load->library('logger');
  351. $this->EE->logger->deprecated('2.0', 'Security_helper::do_hash');
  352. $this->EE->load->helper('security');
  353. return do_hash($str);
  354. }
  355. // --------------------------------------------------------------------
  356. /**
  357. * Random number/password generator
  358. *
  359. * @access public
  360. * @param string
  361. * @param int
  362. * @return string
  363. */
  364. function random($type = 'encrypt', $len = 8)
  365. {
  366. $this->EE->load->helper('string');
  367. return random_string($type, $len);
  368. }
  369. // --------------------------------------------------------------------
  370. /**
  371. * Form declaration
  372. *
  373. * This function is used by modules when they need to create forms
  374. *
  375. * @access public
  376. * @param string
  377. * @return string
  378. */
  379. function form_declaration($data)
  380. {
  381. // Load the form helper
  382. $this->EE->load->helper('form');
  383. $deft = array(
  384. 'hidden_fields' => array(),
  385. 'action' => '',
  386. 'id' => '',
  387. 'class' => '',
  388. 'secure' => TRUE,
  389. 'enctype' => '',
  390. 'onsubmit' => '',
  391. );
  392. foreach ($deft as $key => $val)
  393. {
  394. if ( ! isset($data[$key]))
  395. {
  396. $data[$key] = $val;
  397. }
  398. }
  399. if (is_array($data['hidden_fields']) && ! isset($data['hidden_fields']['site_id']))
  400. {
  401. $data['hidden_fields']['site_id'] = $this->EE->config->item('site_id');
  402. }
  403. // Add the CSRF Protection Hash
  404. if ($this->EE->config->item('csrf_protection') == TRUE )
  405. {
  406. $data['hidden_fields'][$this->EE->security->get_csrf_token_name()] = $this->EE->security->get_csrf_hash();
  407. }
  408. // -------------------------------------------
  409. // 'form_declaration_modify_data' hook.
  410. // - Modify the $data parameters before they are processed
  411. // - Added EE 1.4.0
  412. //
  413. if ($this->EE->extensions->active_hook('form_declaration_modify_data') === TRUE)
  414. {
  415. $data = $this->EE->extensions->call('form_declaration_modify_data', $data);
  416. }
  417. //
  418. // -------------------------------------------
  419. // -------------------------------------------
  420. // 'form_declaration_return' hook.
  421. // - Take control of the form_declaration function
  422. // - Added EE 1.4.0
  423. //
  424. if ($this->EE->extensions->active_hook('form_declaration_return') === TRUE)
  425. {
  426. $form = $this->EE->extensions->call('form_declaration_return', $data);
  427. if ($this->EE->extensions->end_script === TRUE) return $form;
  428. }
  429. //
  430. // -------------------------------------------
  431. if ($data['action'] == '')
  432. {
  433. $data['action'] = $this->fetch_site_index();
  434. }
  435. if ($data['onsubmit'] != '')
  436. {
  437. $data['onsubmit'] = 'onsubmit="'.trim($data['onsubmit']).'"';
  438. }
  439. if (substr($data['action'], -1) == '?')
  440. {
  441. $data['action'] = substr($data['action'], 0, -1);
  442. }
  443. $data['name'] = (isset($data['name']) && $data['name'] != '') ? 'name="'.$data['name'].'" ' : '';
  444. $data['id'] = ($data['id'] != '') ? 'id="'.$data['id'].'" ' : '';
  445. $data['class'] = ($data['class'] != '') ? 'class="'.$data['class'].'" ' : '';
  446. if ($data['enctype'] == 'multi' OR strtolower($data['enctype']) == 'multipart/form-data')
  447. {
  448. $data['enctype'] = 'enctype="multipart/form-data" ';
  449. }
  450. $form = '<form '.$data['id'].$data['class'].$data['name'].'method="post" action="'.$data['action'].'" '.$data['onsubmit'].' '.$data['enctype'].">\n";
  451. if ($data['secure'] == TRUE)
  452. {
  453. if ($this->EE->config->item('secure_forms') == 'y')
  454. {
  455. if ( ! isset($data['hidden_fields']['XID']))
  456. {
  457. $data['hidden_fields'] = array_merge(array('XID' => '{XID_HASH}'), $data['hidden_fields']);
  458. }
  459. elseif ($data['hidden_fields']['XID'] == '')
  460. {
  461. $data['hidden_fields']['XID'] = '{XID_HASH}';
  462. }
  463. }
  464. }
  465. if (is_array($data['hidden_fields']))
  466. {
  467. $form .= "<div class='hiddenFields'>\n";
  468. foreach ($data['hidden_fields'] as $key => $val)
  469. {
  470. $form .= '<input type="hidden" name="'.$key.'" value="'.form_prep($val).'" />'."\n";
  471. }
  472. $form .= "</div>\n\n";
  473. }
  474. return $form;
  475. }
  476. // --------------------------------------------------------------------
  477. /**
  478. * Form backtrack
  479. *
  480. * This function lets us return a user to a previously
  481. * visited page after submitting a form. The page
  482. * is determined by the offset that the admin
  483. * places in each form
  484. *
  485. * @access public
  486. * @param string
  487. * @return string
  488. */
  489. function form_backtrack($offset = '')
  490. {
  491. $ret = $this->fetch_site_index();
  492. if ($offset != '')
  493. {
  494. if (isset($this->EE->session->tracker[$offset]))
  495. {
  496. if ($this->EE->session->tracker[$offset] != 'index')
  497. {
  498. return $this->remove_double_slashes($this->fetch_site_index().'/'.$this->EE->session->tracker[$offset]);
  499. }
  500. }
  501. }
  502. if (isset($_POST['RET']))
  503. {
  504. if (strncmp($_POST['RET'], '-', 1) == 0)
  505. {
  506. $return = str_replace("-", "", $_POST['RET']);
  507. if (isset($this->EE->session->tracker[$return]))
  508. {
  509. if ($this->EE->session->tracker[$return] != 'index')
  510. {
  511. $ret = $this->fetch_site_index().'/'.$this->EE->session->tracker[$return];
  512. }
  513. }
  514. }
  515. else
  516. {
  517. if (strpos($_POST['RET'], '/') !== FALSE)
  518. {
  519. if (strncasecmp($_POST['RET'], 'http://', 7) == 0 OR
  520. strncasecmp($_POST['RET'], 'https://', 8) == 0 OR
  521. strncasecmp($_POST['RET'], 'www.', 4) == 0)
  522. {
  523. $ret = $_POST['RET'];
  524. }
  525. else
  526. {
  527. $ret = $this->create_url($_POST['RET']);
  528. }
  529. }
  530. else
  531. {
  532. $ret = $_POST['RET'];
  533. }
  534. }
  535. // We need to slug in the session ID if the admin is running
  536. // their site using sessions only. Normally the $this->EE->functions->fetch_site_index()
  537. // function adds the session ID automatically, except in cases when the
  538. // $_POST['RET'] variable is set. Since the login routine relies on the RET
  539. // info to know where to redirect back to we need to sandwich in the session ID.
  540. if ($this->EE->config->item('user_session_type') != 'c')
  541. {
  542. if ($this->EE->session->userdata['session_id'] != '' && ! stristr($ret, $this->EE->session->userdata['session_id']))
  543. {
  544. $url = $this->EE->config->slash_item('site_url');
  545. $url .= $this->EE->config->item('site_index');
  546. if ($this->EE->config->item('force_query_string') == 'y')
  547. {
  548. $url .= '?';
  549. }
  550. $sess_id = "/S=".$this->EE->session->userdata['session_id']."/";
  551. $ret = str_replace($url, $url.$sess_id, $ret);
  552. }
  553. }
  554. }
  555. return $this->remove_double_slashes($ret);
  556. }
  557. // --------------------------------------------------------------------
  558. /**
  559. * eval()
  560. *
  561. * Evaluates a string as PHP
  562. *
  563. * @access public
  564. * @param string
  565. * @return mixed
  566. */
  567. function evaluate($str)
  568. {
  569. return eval('?'.'>'.$str.'<?php ');
  570. }
  571. // --------------------------------------------------------------------
  572. /**
  573. * Encode email from template callback
  574. *
  575. * @access public
  576. * @param string
  577. * @return string
  578. */
  579. function encode_email($str)
  580. {
  581. if (isset($this->EE->session->cache['functions']['emails'][$str]))
  582. {
  583. return preg_replace("/(eeEncEmail_)\w+/", '\\1'.$this->EE->functions->random('alpha', 10), $this->EE->session->cache['functions']['emails'][$str]);
  584. }
  585. $email = (is_array($str)) ? trim($str[1]) : trim($str);
  586. $title = '';
  587. $email = str_replace(array('"', "'"), '', $email);
  588. if ($p = strpos($email, "title="))
  589. {
  590. $title = substr($email, $p + 6);
  591. $email = trim(substr($email, 0, $p));
  592. }
  593. $this->EE->load->library('typography');
  594. $this->EE->typography->initialize();
  595. $encoded = $this->EE->typography->encode_email($email, $title, TRUE);
  596. $this->EE->session->cache['functions']['emails'][$str] = $encoded;
  597. return $encoded;
  598. }
  599. // --------------------------------------------------------------------
  600. /**
  601. * Delete spam prevention hashes
  602. *
  603. * @access public
  604. * @return void
  605. */
  606. function clear_spam_hashes()
  607. {
  608. if ($this->EE->config->item('secure_forms') == 'y')
  609. {
  610. $this->EE->db->query("DELETE FROM exp_security_hashes WHERE date < UNIX_TIMESTAMP()-7200");
  611. }
  612. }
  613. // --------------------------------------------------------------------
  614. /**
  615. * Set Cookie
  616. *
  617. * @access public
  618. * @param string
  619. * @param string
  620. * @param string
  621. * @return void
  622. */
  623. function set_cookie($name = '', $value = '', $expire = '')
  624. {
  625. $data['name'] = $name;
  626. if ( ! is_numeric($expire))
  627. {
  628. $data['expire'] = time() - 86500;
  629. }
  630. else
  631. {
  632. if ($expire > 0)
  633. {
  634. $data['expire'] = time() + $expire;
  635. }
  636. else
  637. {
  638. $data['expire'] = 0;
  639. }
  640. }
  641. $data['prefix'] = ( ! $this->EE->config->item('cookie_prefix')) ? 'exp_' : $this->EE->config->item('cookie_prefix').'_';
  642. $data['path'] = ( ! $this->EE->config->item('cookie_path')) ? '/' : $this->EE->config->item('cookie_path');
  643. if (REQ == 'CP' && $this->EE->config->item('multiple_sites_enabled') == 'y')
  644. {
  645. $data['domain'] = $this->EE->config->cp_cookie_domain;
  646. }
  647. else
  648. {
  649. $data['domain'] = ( ! $this->EE->config->item('cookie_domain')) ? '' : $this->EE->config->item('cookie_domain');
  650. }
  651. $data['value'] = stripslashes($value);
  652. $data['secure_cookie'] = ($this->EE->config->item('cookie_secure') === TRUE) ? 1 : 0;
  653. if ($data['secure_cookie'])
  654. {
  655. $req = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : FALSE;
  656. if ( ! $req OR $req == 'off')
  657. {
  658. return FALSE;
  659. }
  660. }
  661. /* -------------------------------------------
  662. /* 'set_cookie_end' hook.
  663. /* - Take control of Cookie setting routine
  664. /* - Added EE 2.5.0
  665. */
  666. $this->EE->extensions->call('set_cookie_end', $data);
  667. if ($this->EE->extensions->end_script === TRUE) return;
  668. /*
  669. /* -------------------------------------------*/
  670. setcookie($data['prefix'].$data['name'], $data['value'], $data['expire'],
  671. $data['path'], $data['domain'], $data['secure_cookie']);
  672. }
  673. // --------------------------------------------------------------------
  674. /**
  675. * Character limiter
  676. *
  677. * @access public
  678. * @param string
  679. * @return string
  680. */
  681. function char_limiter($str, $num = 500)
  682. {
  683. if (strlen($str) < $num)
  684. {
  685. return $str;
  686. }
  687. $str = str_replace("\n", " ", $str);
  688. $str = preg_replace("/\s+/", " ", $str);
  689. if (strlen($str) <= $num)
  690. {
  691. return $str;
  692. }
  693. $str = trim($str);
  694. $out = "";
  695. foreach (explode(" ", trim($str)) as $val)
  696. {
  697. $out .= $val;
  698. if (strlen($out) >= $num)
  699. {
  700. return (strlen($out) == strlen($str)) ? $out : $out.'&#8230;';
  701. }
  702. $out .= ' ';
  703. }
  704. }
  705. // --------------------------------------------------------------------
  706. /**
  707. * Word limiter
  708. *
  709. * @access public
  710. * @param string
  711. * @return string
  712. */
  713. function word_limiter($str, $num = 100)
  714. {
  715. if (strlen($str) < $num)
  716. {
  717. return $str;
  718. }
  719. // allows the split to work properly with multi-byte Unicode characters
  720. if (is_php('4.3.2') === TRUE)
  721. {
  722. $word = preg_split('/\s/u', $str, -1, PREG_SPLIT_NO_EMPTY);
  723. }
  724. else
  725. {
  726. $word = preg_split('/\s/', $str, -1, PREG_SPLIT_NO_EMPTY);
  727. }
  728. if (count($word) <= $num)
  729. {
  730. return $str;
  731. }
  732. $str = "";
  733. for ($i = 0; $i < $num; $i++)
  734. {
  735. $str .= $word[$i]." ";
  736. }
  737. return trim($str).'&#8230;';
  738. }
  739. // --------------------------------------------------------------------
  740. /**
  741. * Fetch Email Template
  742. *
  743. * @access public
  744. * @param string
  745. * @return string
  746. */
  747. function fetch_email_template($name)
  748. {
  749. $query = $this->EE->db->query("SELECT template_name, data_title, template_data, enable_template FROM exp_specialty_templates WHERE site_id = '".$this->EE->db->escape_str($this->EE->config->item('site_id'))."' AND template_name = '".$this->EE->db->escape_str($name)."'");
  750. // Unlikely that this is necessary but it's possible a bad template request could
  751. // happen if a user hasn't run the update script.
  752. if ($query->num_rows() == 0)
  753. {
  754. return array('title' => '', 'data' => '');
  755. }
  756. if ($query->row('enable_template') == 'y')
  757. {
  758. return array('title' => $query->row('data_title') , 'data' => $query->row('template_data') );
  759. }
  760. if ($this->EE->session->userdata['language'] != '')
  761. {
  762. $user_lang = $this->EE->session->userdata['language'];
  763. }
  764. else
  765. {
  766. if ($this->EE->input->cookie('language'))
  767. {
  768. $user_lang = $this->EE->input->cookie('language');
  769. }
  770. elseif ($this->EE->config->item('deft_lang') != '')
  771. {
  772. $user_lang = $this->EE->config->item('deft_lang');
  773. }
  774. else
  775. {
  776. $user_lang = 'english';
  777. }
  778. }
  779. $user_lang = $this->EE->security->sanitize_filename($user_lang);
  780. if ( function_exists($name))
  781. {
  782. $title = $name.'_title';
  783. return array('title' => $title(), 'data' => $name());
  784. }
  785. else
  786. {
  787. if ( ! @include(APPPATH.'language/'.$user_lang.'/email_data.php'))
  788. {
  789. return array('title' => $query->row('data_title') , 'data' => $query->row('template_data') );
  790. }
  791. if (function_exists($name))
  792. {
  793. $title = $name.'_title';
  794. return array('title' => $title(), 'data' => $name());
  795. }
  796. else
  797. {
  798. return array('title' => $query->row('data_title') , 'data' => $query->row('template_data') );
  799. }
  800. }
  801. }
  802. // --------------------------------------------------------------------
  803. /**
  804. * Create character encoding menu
  805. *
  806. * DEPRECATED IN 2.0
  807. *
  808. * @access public
  809. * @param string
  810. * @param string
  811. * @param string
  812. * @return string
  813. */
  814. function encoding_menu($name, $selected = '')
  815. {
  816. $this->EE->load->library('logger');
  817. $this->EE->logger->deprecated('2.0');
  818. $file = APPPATH.'config/languages.php';
  819. if ( ! file_exists($file))
  820. {
  821. return FALSE;
  822. }
  823. require_once $file;
  824. $languages = array_flip($languages);
  825. $this->EE->load->helper('form');
  826. return form_dropdown($name, $languages, $selected);
  827. }
  828. // --------------------------------------------------------------------
  829. /**
  830. * Create Directory Map
  831. *
  832. * DEPRECATED IN 2.2
  833. *
  834. * @access public
  835. * @param string
  836. * @param bool
  837. * @return array
  838. */
  839. function create_directory_map($source_dir, $top_level_only = FALSE)
  840. {
  841. $this->EE->load->library('logger');
  842. $this->EE->logger->deprecated('2.2');
  843. if ( ! isset($filedata))
  844. $filedata = array();
  845. if ($fp = @opendir($source_dir))
  846. {
  847. while (FALSE !== ($file = readdir($fp)))
  848. {
  849. if (@is_dir($source_dir.$file) && substr($file, 0, 1) != '.' AND $top_level_only == FALSE)
  850. {
  851. $temp_array = array();
  852. $temp_array = $this->create_directory_map($source_dir.$file."/");
  853. $filedata[$file] = $temp_array;
  854. }
  855. elseif (substr($file, 0, 1) != "." && $file != 'index.html')
  856. {
  857. $filedata[] = $file;
  858. }
  859. }
  860. return $filedata;
  861. }
  862. }
  863. // --------------------------------------------------------------------
  864. /**
  865. * Create pull-down optios from dirctory map
  866. *
  867. * @access public
  868. * @param array
  869. * @param string
  870. * @return string
  871. */
  872. function render_map_as_select_options($zarray, $array_name = '')
  873. {
  874. foreach ($zarray as $key => $val)
  875. {
  876. if ( is_array($val))
  877. {
  878. if ($array_name != '')
  879. {
  880. $key = $array_name.'/'.$key;
  881. }
  882. $this->render_map_as_select_options($val, $key);
  883. }
  884. else
  885. {
  886. if ($array_name != '')
  887. {
  888. $val = $array_name.'/'.$val;
  889. }
  890. if (substr($val, -4) == '.php')
  891. {
  892. if ($val != 'theme_master.php')
  893. {
  894. $this->template_map[] = $val;
  895. }
  896. }
  897. }
  898. }
  899. }
  900. // --------------------------------------------------------------------
  901. /**
  902. * Fetch names of installed language packs
  903. *
  904. * DEPRECATED IN 2.0
  905. *
  906. * @access public
  907. * @param string
  908. * @return string
  909. */
  910. function language_pack_names($default)
  911. {
  912. $source_dir = APPPATH.'language/';
  913. $dirs = array();
  914. if ($fp = @opendir($source_dir))
  915. {
  916. while (FALSE !== ($file = readdir($fp)))
  917. {
  918. if (is_dir($source_dir.$file) && substr($file, 0, 1) != ".")
  919. {
  920. $dirs[] = $file;
  921. }
  922. }
  923. closedir($fp);
  924. }
  925. sort($dirs);
  926. $r = "<div class='default'>";
  927. $r .= "<select name='deft_lang' class='select'>\n";
  928. foreach ($dirs as $dir)
  929. {
  930. $selected = ($dir == $default) ? " selected='selected'" : '';
  931. $r .= "<option value='{$dir}'{$selected}>".ucfirst($dir)."</option>\n";
  932. }
  933. $r .= "</select>";
  934. $r .= "</div>";
  935. return $r;
  936. }
  937. // --------------------------------------------------------------------
  938. /**
  939. * Delete cache files
  940. *
  941. * @access public
  942. * @param string
  943. * @return string
  944. */
  945. function clear_caching($which, $sub_dir = '', $relationships=FALSE)
  946. {
  947. $actions = array('page', 'tag', 'db', 'sql', 'relationships', 'all');
  948. if ( ! in_array($which, $actions))
  949. {
  950. return;
  951. }
  952. /* -------------------------------------
  953. /* Disable Tag Caching
  954. /*
  955. /* All for you, Nevin! Disables tag caching, which if used unwisely
  956. /* on a high traffic site can lead to disastrous disk i/o
  957. /* This setting allows quick thinking admins to temporarily disable
  958. /* it without hacking or modifying folder permissions
  959. /*
  960. /* Hidden Configuration Variable
  961. /* - disable_tag_caching => Disable tag caching? (y/n)
  962. /* -------------------------------------*/
  963. if ($which == 'tag' && $this->EE->config->item('disable_tag_caching') == 'y')
  964. {
  965. return;
  966. }
  967. $db_path = '';
  968. if ($sub_dir != '')
  969. {
  970. if ($which == 'all' OR $which == 'db')
  971. {
  972. $segs = explode('/', str_replace($this->fetch_site_index(), '', $sub_dir));
  973. $segment_one = (isset($segs['0'])) ? $segs['0'] : 'default';
  974. $segment_two = (isset($segs['1'])) ? $segs['1'] : 'index';
  975. $db_path = '/'.$segment_one.'+'.$segment_two.'/';
  976. }
  977. $sub_dir = '/'.md5($sub_dir).'/';
  978. }
  979. switch ($which)
  980. {
  981. case 'page' : $this->delete_directory(APPPATH.'cache/page_cache'.$sub_dir);
  982. break;
  983. case 'db' : $this->delete_directory(APPPATH.'cache/db_cache_'.$this->EE->config->item('site_id').$db_path);
  984. break;
  985. case 'tag' : $this->delete_directory(APPPATH.'cache/tag_cache'.$sub_dir);
  986. break;
  987. case 'sql' : $this->delete_directory(APPPATH.'cache/sql_cache'.$sub_dir);
  988. break;
  989. case 'relationships' : $this->EE->db->query("UPDATE exp_relationships SET rel_data = '', reverse_rel_data = ''");
  990. break;
  991. case 'all' :
  992. $this->delete_directory(APPPATH.'cache/page_cache'.$sub_dir);
  993. $this->delete_directory(APPPATH.'cache/db_cache_'.$this->EE->config->item('site_id').$db_path);
  994. $this->delete_directory(APPPATH.'cache/sql_cache'.$sub_dir);
  995. if ($this->EE->config->item('disable_tag_caching') != 'y')
  996. {
  997. $this->delete_directory(APPPATH.'cache/tag_cache'.$sub_dir);
  998. }
  999. if ($relationships === TRUE)
  1000. {
  1001. $this->EE->db->query("UPDATE exp_relationships SET rel_data = '', reverse_rel_data = ''");
  1002. }
  1003. break;
  1004. }
  1005. }
  1006. // --------------------------------------------------------------------
  1007. /**
  1008. * Delete Direcories
  1009. *
  1010. * @access public
  1011. * @param string
  1012. * @param bool
  1013. * @return void
  1014. */
  1015. function delete_directory($path, $del_root = FALSE)
  1016. {
  1017. $path = rtrim($path, '/');
  1018. $path_delete = $path.'_delete';
  1019. if ( ! is_dir($path))
  1020. {
  1021. return FALSE;
  1022. }
  1023. // Delete temporary directory if it happens to exist from a previous attempt
  1024. if (is_dir($path_delete))
  1025. {
  1026. @exec("rm -r -f {$path_delete}");
  1027. }
  1028. // let's try this the sane way first
  1029. @exec("mv {$path} {$path_delete}", $out, $ret);
  1030. if (isset($ret) && $ret == 0)
  1031. {
  1032. if ($del_root === FALSE)
  1033. {
  1034. @mkdir($path, 0777);
  1035. if ($fp = @fopen($path.'/index.html', FOPEN_WRITE_CREATE_DESTRUCTIVE))
  1036. {
  1037. fclose($fp);
  1038. }
  1039. }
  1040. @exec("rm -r -f {$path_delete}");
  1041. }
  1042. else
  1043. {
  1044. if ( ! $current_dir = @opendir($path))
  1045. {
  1046. return;
  1047. }
  1048. while($filename = @readdir($current_dir))
  1049. {
  1050. if (@is_dir($path.'/'.$filename) and ($filename != "." and $filename != ".."))
  1051. {
  1052. $this->delete_directory($path.'/'.$filename, TRUE);
  1053. }
  1054. elseif($filename != "." and $filename != "..")
  1055. {
  1056. @unlink($path.'/'.$filename);
  1057. }
  1058. }
  1059. @closedir($current_dir);
  1060. if (substr($path, -6) == '_cache' && $fp = @fopen($path.'/index.html', FOPEN_WRITE_CREATE_DESTRUCTIVE))
  1061. {
  1062. fclose($fp);
  1063. }
  1064. if ($del_root == TRUE)
  1065. {
  1066. @rmdir($path);
  1067. }
  1068. }
  1069. }
  1070. // --------------------------------------------------------------------
  1071. /**
  1072. * Fetch allowed channels
  1073. *
  1074. * This function fetches the ID numbers of the
  1075. * channels assigned to the currently logged in user.
  1076. *
  1077. * @access public
  1078. * @param bool
  1079. * @return array
  1080. */
  1081. function fetch_assigned_channels($all_sites = FALSE)
  1082. {
  1083. $allowed_channels = array();
  1084. if (REQ == 'CP' AND isset($this->EE->session->userdata['assigned_channels']) && $all_sites === FALSE)
  1085. {
  1086. $allowed_channels = array_keys($this->EE->session->userdata['assigned_channels']);
  1087. }
  1088. elseif ($this->EE->session->userdata['group_id'] == 1)
  1089. {
  1090. if ($all_sites === TRUE)
  1091. {
  1092. $this->EE->db->select('channel_id');
  1093. $query = $this->EE->db->get('channels');
  1094. }
  1095. else
  1096. {
  1097. $this->EE->db->select('channel_id');
  1098. $this->EE->db->where('site_id', $this->EE->config->item('site_id'));
  1099. $query = $this->EE->db->get('channels');
  1100. }
  1101. if ($query->num_rows() > 0)
  1102. {
  1103. foreach ($query->result_array() as $row)
  1104. {
  1105. $allowed_channels[] = $row['channel_id'];
  1106. }
  1107. }
  1108. }
  1109. else
  1110. {
  1111. if ($all_sites === TRUE)
  1112. {
  1113. $result = $this->EE->db->query("SELECT exp_channel_member_groups.channel_id FROM exp_channel_member_groups
  1114. WHERE exp_channel_member_groups.group_id = '".$this->EE->db->escape_str($this->EE->session->userdata['group_id'])."'");
  1115. }
  1116. else
  1117. {
  1118. $result = $this->EE->db->query("SELECT exp_channels.channel_id FROM exp_channels, exp_channel_member_groups
  1119. WHERE exp_channels.channel_id = exp_channel_member_groups.channel_id
  1120. AND exp_channels.site_id = '".$this->EE->db->escape_str($this->EE->config->item('site_id'))."'
  1121. AND exp_channel_member_groups.group_id = '".$this->EE->db->escape_str($this->EE->session->userdata['group_id'])."'");
  1122. }
  1123. if ($result->num_rows() > 0)
  1124. {
  1125. foreach ($result->result_array() as $row)
  1126. {
  1127. $allowed_channels[] = $row['channel_id'];
  1128. }
  1129. }
  1130. }
  1131. return array_values($allowed_channels);
  1132. }
  1133. // --------------------------------------------------------------------
  1134. /**
  1135. * Log Search terms
  1136. *
  1137. * @access public
  1138. * @param string
  1139. * @param string
  1140. * @return void
  1141. */
  1142. function log_search_terms($terms = '', $type = 'site')
  1143. {
  1144. if ($terms == '' OR $this->EE->db->table_exists('exp_search_log') === FALSE)
  1145. return;
  1146. if ($this->EE->config->item('enable_search_log') == 'n')
  1147. return;
  1148. $this->EE->load->helper('xml');
  1149. $search_log = array(
  1150. 'member_id' => $this->EE->session->userdata('member_id'),
  1151. 'screen_name' => $this->EE->session->userdata('screen_name'),
  1152. 'ip_address' => $this->EE->input->ip_address(),
  1153. 'search_date' => $this->EE->localize->now,
  1154. 'search_type' => $type,
  1155. 'search_terms' => xml_convert($this->EE->functions->encode_ee_tags($this->EE->security->xss_clean($terms), TRUE)),
  1156. 'site_id' => $this->EE->config->item('site_id')
  1157. );
  1158. $this->EE->db->query($this->EE->db->insert_string('exp_search_log', $search_log));
  1159. // Prune Database
  1160. srand(time());
  1161. if ((rand() % 100) < 5)
  1162. {
  1163. $max = ( ! is_numeric($this->EE->config->item('max_logged_searches'))) ? 500 : $this->EE->config->item('max_logged_searches');
  1164. $query = $this->EE->db->query("SELECT MAX(id) as search_id FROM exp_search_log WHERE site_id = '".$this->EE->db->escape_str($this->EE->config->item('site_id'))."'");
  1165. $row = $query->row_array();
  1166. if (isset($row['search_id'] ) && $row['search_id'] > $max)
  1167. {
  1168. $this->EE->db->query("DELETE FROM exp_search_log WHERE site_id = '".$this->EE->db->escape_str($this->EE->config->item('site_id'))."' AND id < ".($row['search_id'] -$max)."");
  1169. }
  1170. }
  1171. }
  1172. // --------------------------------------------------------------------
  1173. /**
  1174. * Fetch Action ID
  1175. *
  1176. * @access public
  1177. * @param string
  1178. * @param string
  1179. * @return string
  1180. */
  1181. function fetch_action_id($class, $method)
  1182. {
  1183. if ($class == '' OR $method == '')
  1184. {
  1185. return FALSE;
  1186. }
  1187. $this->action_ids[ucfirst($class)][$method] = $method;
  1188. return LD.'AID:'.ucfirst($class).':'.$method.RD;
  1189. }
  1190. // --------------------------------------------------------------------
  1191. /**
  1192. * Insert Action IDs
  1193. *
  1194. * @access public
  1195. * @param string
  1196. * @return string
  1197. */
  1198. function insert_action_ids($str)
  1199. {
  1200. if (count($this->action_ids) == 0)
  1201. {
  1202. return $str;
  1203. }
  1204. $sql = "SELECT action_id, class, method FROM exp_actions WHERE";
  1205. foreach($this->action_ids as $key => $value)
  1206. {
  1207. foreach($value as $k => $v)
  1208. {
  1209. $sql .= " (class= '".$this->EE->db->escape_str($key)."' AND method = '".$this->EE->db->escape_str($v)."') OR";
  1210. }
  1211. }
  1212. $query = $this->EE->db->query(substr($sql, 0, -3));
  1213. if ($query->num_rows() > 0)
  1214. {
  1215. foreach($query->result_array() as $row)
  1216. {
  1217. $str = str_replace(LD.'AID:'.$row['class'].':'.$row['method'].RD, $row['action_id'], $str);
  1218. }
  1219. }
  1220. return $str;
  1221. }
  1222. // --------------------------------------------------------------------
  1223. /**
  1224. * Compile and cache relationship data
  1225. *
  1226. * This is used when submitting new channel entries or gallery posts.
  1227. * It serializes the related entry data. The reason it's in this
  1228. * file is because it gets called from the publish class and the
  1229. * gallery class so we need it somewhere that is accessible to both.
  1230. *
  1231. * @access public
  1232. * @param string
  1233. * @param bool
  1234. * @param bool
  1235. * @return void
  1236. */
  1237. function compile_relationship($data, $parent_entry = TRUE, $reverse = FALSE)
  1238. {
  1239. if ($data['type'] == 'channel' OR ($reverse === TRUE && $parent_entry === FALSE))
  1240. {
  1241. $sql = "SELECT 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,
  1242. w.channel_title, w.channel_name, w.channel_url, w.comment_url, w.comment_moderate, w.channel_html_formatting, w.channel_allow_img_urls, w.channel_auto_link_urls,
  1243. 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,
  1244. md.*,
  1245. wd.*
  1246. FROM exp_channel_titles AS t
  1247. LEFT JOIN exp_channels AS w ON t.channel_id = w.channel_id
  1248. LEFT JOIN exp_channel_data AS wd ON t.entry_id = wd.entry_id
  1249. LEFT JOIN exp_members AS m ON m.member_id = t.author_id
  1250. LEFT JOIN exp_member_data AS md ON md.member_id = m.member_id
  1251. WHERE t.entry_id = '".(($reverse === TRUE && $parent_entry === FALSE) ? $data['parent_id'] : $data['child_id'])."'";
  1252. $entry_query = $this->EE->db->query($sql);
  1253. // Is there a category group associated with this channel?
  1254. $query = $this->EE->db->query("SELECT cat_group FROM exp_channels WHERE channel_id = '".$entry_query->row('channel_id') ."'");
  1255. $cat_group = (trim($query->row('cat_group')) == '') ? FALSE : $query->row('cat_group');
  1256. $this->cat_array = array();
  1257. $cat_array = array();
  1258. if ($cat_group !== FALSE)
  1259. {
  1260. $this->get_categories($cat_group, ($reverse === TRUE && $parent_entry === FALSE) ? $data['parent_id'] : $data['child_id']);
  1261. }
  1262. $cat_array = $this->cat_array;
  1263. if ($parent_entry == TRUE)
  1264. {
  1265. $this->EE->db->query("INSERT INTO exp_relationships (rel_parent_id, rel_child_id, rel_type, rel_data, reverse_rel_data)
  1266. VALUES ('".$data['parent_id']."', '".$data['child_id']."', '".$data['type']."',
  1267. '".addslashes(serialize(array('query' => $entry_query, 'cats_fixed' => '1', 'categories' => $cat_array)))."', '')");
  1268. return $this->EE->db->insert_id();
  1269. }
  1270. else
  1271. {
  1272. if ($reverse === TRUE)
  1273. {
  1274. $this->EE->db->query("UPDATE exp_relationships
  1275. SET reverse_rel_data = '".addslashes(serialize(array('query' => $entry_query, 'cats_fixed' => '1', 'categories' => $cat_array)))."'
  1276. WHERE rel_type = '".$this->EE->db->escape_str($data['type'])."' AND rel_parent_id = '".$data['parent_id']."'");
  1277. }
  1278. else
  1279. {
  1280. $this->EE->db->query("UPDATE exp_relationships
  1281. SET rel_data = '".addslashes(serialize(array('query' => $entry_query, 'cats_fixed' => '1', 'categories' => $cat_array)))."'
  1282. WHERE rel_type = 'channel' AND rel_child_id = '".$data['child_id']."'");
  1283. }
  1284. }
  1285. }
  1286. }
  1287. // --------------------------------------------------------------------
  1288. /**
  1289. * Get Categories for Channel Entry/Entries
  1290. *
  1291. * @access public
  1292. * @param string
  1293. * @param string
  1294. * @return array
  1295. */
  1296. function get_categories($cat_group, $entry_id)
  1297. {
  1298. // fetch the custom category fields
  1299. $field_sqla = '';
  1300. $field_sqlb = '';
  1301. $query = $this->EE->db->query("SELECT field_id, field_name FROM exp_category_fields WHERE group_id IN ('".str_replace('|', "','", $this->EE->db->escape_str($cat_group))."')");
  1302. if ($query->num_rows() > 0)
  1303. {
  1304. foreach ($query->result_array() as $row)
  1305. {
  1306. $this->catfields[] = array('field_name' => $row['field_name'], 'field_id' => $row['field_id']);
  1307. }
  1308. $field_sqla = ", cg.field_html_formatting, fd.* ";
  1309. $field_sqlb = " LEFT JOIN exp_category_field_data AS fd ON fd.cat_id = c.cat_id
  1310. LEFT JOIN exp_category_groups AS cg ON cg.group_id = c.group_id";
  1311. }
  1312. $sql = "SELECT c.cat_name, c.cat_url_title, c.cat_id, c.cat_image, p.cat_id, c.parent_id, c.cat_description, c.group_id
  1313. {$field_sqla}
  1314. FROM (exp_categories AS c, exp_category_posts AS p)
  1315. {$field_sqlb}
  1316. WHERE c.group_id IN ('".str_replace('|', "','", $this->EE->db->escape_str($cat_group))."')
  1317. AND p.entry_id = '".$entry_id."'
  1318. AND c.cat_id = p.cat_id
  1319. ORDER BY c.parent_id, c.cat_order";
  1320. $sql = str_replace("\t", " ", $sql);
  1321. $query = $this->EE->db->query($sql);
  1322. $this->cat_array = array();
  1323. $parents = array();
  1324. if ($query->num_rows() > 0)
  1325. {
  1326. $this->temp_array = array();
  1327. foreach ($query->result_array() as $row)
  1328. {
  1329. $this->temp_array[$row['cat_id']] = array($row['cat_id'], $row['parent_id'], $row['cat_name'], $row['cat_image'], $row['cat_description'], $row['group_id'], $row['cat_url_title']);
  1330. if ($field_sqla != '')
  1331. {
  1332. foreach ($row as $k => $v)
  1333. {
  1334. if (strpos($k, 'field') !== FALSE)
  1335. {
  1336. $this->temp_array[$row['cat_id']][$k] = $v;
  1337. }
  1338. }
  1339. }
  1340. if ($row['parent_id'] > 0 && ! isset($this->temp_array[$row['parent_id']])) $parents[$row['parent_id']] = '';
  1341. unset($parents[$row['cat_id']]);
  1342. }
  1343. foreach($this->temp_array as $k => $v)
  1344. {
  1345. if (isset($parents[$v[1]])) $v[1] = 0;
  1346. if (0 == $v[1])
  1347. {
  1348. $this->cat_array[] = $v;
  1349. $this->process_subcategories($k);
  1350. }
  1351. }
  1352. unset($this->temp_array);
  1353. }
  1354. }
  1355. // --------------------------------------------------------------------
  1356. /**
  1357. * Process Subcategories
  1358. *
  1359. * @access public
  1360. * @param string
  1361. * @return void
  1362. */
  1363. function process_subcategories($parent_id)
  1364. {
  1365. foreach($this->temp_array as $key => $val)
  1366. {
  1367. if ($parent_id == $val[1])
  1368. {
  1369. $this->cat_array[] = $val;
  1370. $this->process_subcategories($key);
  1371. }
  1372. }
  1373. }
  1374. // --------------------------------------------------------------------
  1375. /**
  1376. * Add security hashes to forms
  1377. *
  1378. * @access public
  1379. * @param string
  1380. * @return string
  1381. */
  1382. function add_form_security_hash($str)
  1383. {
  1384. if ($this->EE->config->item('secure_forms') == 'y')
  1385. {
  1386. if (preg_match_all("/({XID_HASH})/", $str, $matches))
  1387. {
  1388. $db_reset = FALSE;
  1389. // Disable DB caching if it's currently set
  1390. if ($this->EE->db->cache_on == TRUE)
  1391. {
  1392. $this->EE->db->cache_off();
  1393. $db_reset = TRUE;
  1394. }
  1395. // Add security hashes
  1396. $sql = "INSERT INTO exp_security_hashes (date, ip_address, hash) VALUES";
  1397. foreach ($matches[1] as $val)
  1398. {
  1399. $hash = $this->random('encrypt');
  1400. $str = preg_replace("/{XID_HASH}/", $hash, $str, 1);
  1401. $sql .= "(UNIX_TIMESTAMP(), '".$this->EE->input->ip_address()."', '".$hash."'),";
  1402. }
  1403. $this->EE->db->query(substr($sql,0,-1));
  1404. // Re-enable DB caching
  1405. if ($db_reset == TRUE)
  1406. {
  1407. $this->EE->db->cache_on();
  1408. }
  1409. }
  1410. }
  1411. return $str;
  1412. }
  1413. // --------------------------------------------------------------------
  1414. /**
  1415. * Generate CAPTCHA
  1416. *
  1417. * @access public
  1418. * @param string
  1419. * @return string
  1420. */
  1421. function create_captcha($old_word = '')
  1422. {
  1423. if ($this->EE->config->item('captcha_require_members') == 'n' AND $this->EE->session->userdata['member_id'] != 0)
  1424. {
  1425. return '';
  1426. }
  1427. // -------------------------------------------
  1428. // 'create_captcha_start' hook.
  1429. // - Allows rewrite of how CAPTCHAs are created
  1430. //
  1431. if ($this->EE->extensions->active_hook('create_captcha_start') === TRUE)
  1432. {
  1433. $edata = $this->EE->extensions->call('create_captcha_start', $old_word);
  1434. if ($this->EE->extensions->end_script === TRUE) return $edata;
  1435. }
  1436. // -------------------------------------------
  1437. $img_path = $this->EE->config->slash_item('captcha_path', 1);
  1438. $img_url = $this->EE->config->slash_item('captcha_url');
  1439. $use_font = ($this->EE->config->item('captcha_font') == 'y') ? TRUE : FALSE;
  1440. $font_face = "texb.ttf";
  1441. $font_size = 16;
  1442. $expiration = 60*60*2; // 2 hours
  1443. $img_width = 140; // Image width
  1444. $img_height = 30; // Image height
  1445. if ($img_path == '' OR $img_url == '')
  1446. {
  1447. return FALSE;
  1448. }
  1449. if ( ! @is_dir($img_path))
  1450. {
  1451. return FALSE;
  1452. }
  1453. if ( ! is_really_writable($img_path))
  1454. {
  1455. return FALSE;
  1456. }
  1457. if ( ! file_exists(APPPATH.'config/captcha.php'))
  1458. {
  1459. return FALSE;
  1460. }
  1461. if ( ! extension_loaded('gd'))
  1462. {
  1463. return FALSE;
  1464. }
  1465. if (substr($img_url, -1) != '/') $img_url .= '/';
  1466. // Disable DB caching if it's currently set
  1467. $db_reset = FALSE;
  1468. if ($this->EE->db->cache_on == TRUE)
  1469. {
  1470. $this->EE->db->cache_off();
  1471. $db_reset = TRUE;
  1472. }
  1473. // Remove old images - add a bit of randomness so we aren't doing this every page access
  1474. list($usec, $sec) = explode(" ", microtime());
  1475. $now = ((float)$usec + (float)$sec);
  1476. if ((mt_rand() % 100) < $this->EE->session->gc_probability)
  1477. {
  1478. $old = time() - $expiration;
  1479. $this->EE->db->query("DELETE FROM exp_captcha WHERE date < ".$old);
  1480. $current_dir = @opendir($img_path);
  1481. while($filename = @readdir($current_dir))
  1482. {
  1483. if ($filename != "." and $filename != ".." and $filename != "index.html")
  1484. {
  1485. $name = str_replace(".jpg", "", $filename);
  1486. if (($name + $expiration) < $now)
  1487. {
  1488. @unlink($img_path.$filename);
  1489. }
  1490. }
  1491. }
  1492. @closedir($current_dir);
  1493. }
  1494. // Fetch and insert word
  1495. if ($old_word == '')
  1496. {
  1497. require APPPATH.'config/captcha.php';
  1498. $word = $words[array_rand($words)];
  1499. if ($this->EE->config->item('captcha_rand') == 'y')
  1500. {
  1501. $word .= $this->random('nozero', 2);
  1502. }
  1503. $this->EE->db->query("INSERT INTO exp_captcha (date, ip_address, word) VALUES (UNIX_TIMESTAMP(), '".$this->EE->input->ip_address()."', '".$this->EE->db->escape_str($word)."')");
  1504. }
  1505. else
  1506. {
  1507. $word = $old_word;
  1508. }
  1509. $this->cached_captcha = $word;
  1510. // Determine angle and position
  1511. $length = strlen($word);
  1512. $angle = ($length >= 6) ? rand(-($length-6), ($length-6)) : 0;
  1513. $x_axis = rand(6, (360/$length)-16);
  1514. $y_axis = ($angle >= 0 ) ? rand($img_height, $img_width) : rand(6, $img_height);
  1515. // Create image
  1516. $im = ImageCreate($img_width, $img_height);
  1517. // Assign colors
  1518. $bg_color = ImageColorAllocate($im, 255, 255, 255);
  1519. $border_color = ImageColorAllocate($im, 153, 102, 102);
  1520. $text_color = ImageColorAllocate($im, 204, 153, 153);
  1521. $grid_color = imagecolorallocate($im, 255, 182, 182);
  1522. $shadow_color = imagecolorallocate($im, 255, 240, 240);
  1523. // Create the rectangle
  1524. ImageFilledRectangle($im, 0, 0, $img_width, $img_height, $bg_color);
  1525. // Create the spiral pattern
  1526. $theta = 1;
  1527. $thetac = 6;
  1528. $radius = 12;
  1529. $circles = 20;
  1530. $points = 36;
  1531. for ($i = 0; $i < ($circles * $points) - 1; $i++)
  1532. {
  1533. $theta = $theta + $thetac;
  1534. $rad = $radius * ($i / $points );
  1535. $x = ($rad * cos($theta)) + $x_axis;
  1536. $y = ($rad * sin($theta)) + $y_axis;
  1537. $theta = $theta + $thetac;
  1538. $rad1 = $radius * (($i + 1) / $points);
  1539. $x1 = ($rad1 * cos($theta)) + $x_axis;
  1540. $y1 = ($rad1 * sin($theta )) + $y_axis;
  1541. imageline($im, $x, $y, $x1, $y1, $grid_color);
  1542. $theta = $theta - $thetac;
  1543. }
  1544. //imageline($im, $img_width, $img_height, 0, 0, $grid_color);
  1545. // Write the text
  1546. $font_path = APPPATH.'fonts/'.$font_face;
  1547. if ($use_font == TRUE)
  1548. {
  1549. if ( ! file_exists($font_path))
  1550. {
  1551. $use_font = FALSE;
  1552. }
  1553. }
  1554. if ($use_font == FALSE OR ! function_exists('imagettftext'))
  1555. {
  1556. $font_size = 5;
  1557. ImageString($im, $font_size, $x_axis, $img_height/3.8, $word, $text_color);
  1558. }
  1559. else
  1560. {
  1561. imagettftext($im, $font_size, $angle, $x_axis, $img_height/1.5, $text_color, $font_path, $word);
  1562. }
  1563. // Create the border
  1564. imagerectangle($im, 0, 0, $img_width-1, $img_height-1, $border_color);
  1565. // Generate the image
  1566. $img_name = $now.'.jpg';
  1567. ImageJPEG($im, $img_path.$img_name);
  1568. $img = "<img src=\"$img_url$img_name\" width=\"$img_width\" height=\"$img_height\" style=\"border:0;\" alt=\" \" />";
  1569. ImageDestroy($im);
  1570. // Re-enable DB caching
  1571. if ($db_reset == TRUE)
  1572. {
  1573. $this->EE->db->cache_on();
  1574. }
  1575. return $img;
  1576. }
  1577. // --------------------------------------------------------------------
  1578. /**
  1579. * SQL "AND" or "OR" string for conditional tag parameters
  1580. *
  1581. * This function lets us build a specific type of query
  1582. * needed when tags have conditional parameters:
  1583. *
  1584. * {exp:some_tag param="value1|value2|value3"}
  1585. *
  1586. * Or the parameter can contain "not":
  1587. *
  1588. * {exp:some_tag param="not value1|value2|value3"}
  1589. *
  1590. * This function explodes the pipes and constructs a series of AND
  1591. * conditions or OR conditions
  1592. *
  1593. * We should probably put this in the DB class but it's not
  1594. * something that is typically used
  1595. *
  1596. * @access public
  1597. * @param string
  1598. * @param string
  1599. * @param string
  1600. * @param bool
  1601. * @return string
  1602. */
  1603. function sql_andor_string($str, $field, $prefix = '', $null=FALSE)
  1604. {
  1605. if ($str == "" OR $field == "")
  1606. {
  1607. return '';
  1608. }
  1609. $str = trim($str);
  1610. $sql = '';
  1611. $not = '';
  1612. if ($prefix != '')
  1613. {
  1614. $prefix .= '.';
  1615. }
  1616. if (strpos($str, '|') !== FALSE)
  1617. {
  1618. $parts = preg_split('/\|/', $str, -1, PREG_SPLIT_NO_EMPTY);
  1619. $parts = array_map('trim', array_map(array($this->EE->db, 'escape_str'), $parts));
  1620. if (count($parts) > 0)
  1621. {
  1622. if (strncasecmp($parts[0], 'not ', 4) == 0)
  1623. {
  1624. $parts[0] = substr($parts[0], 4);
  1625. $not = 'NOT';
  1626. }
  1627. if ($null === TRUE)
  1628. {
  1629. $sql .= "AND ({$prefix}{$field} {$not} IN ('".implode("','", $parts)."') OR {$prefix}{$field} IS NULL)";
  1630. }
  1631. else
  1632. {
  1633. $sql .= "AND {$prefix}{$field} {$not} IN ('".implode("','", $parts)."')";
  1634. }
  1635. }
  1636. }
  1637. else
  1638. {
  1639. if (strncasecmp($str, 'not ', 4) == 0)
  1640. {
  1641. $str = trim(substr($str, 3));
  1642. $not = '!';
  1643. }
  1644. if ($null === TRUE)
  1645. {
  1646. $sql .= "AND ({$prefix}{$field} {$not}= '".$this->EE->db->escape_str($str)."' OR {$prefix}{$field} IS NULL)";
  1647. }
  1648. else
  1649. {
  1650. $sql .= "AND {$prefix}{$field} {$not}= '".$this->EE->db->escape_str($str)."'";
  1651. }
  1652. }
  1653. return $sql;
  1654. }
  1655. // --------------------------------------------------------------------
  1656. /**
  1657. * AR "AND" or "OR" string for conditional tag parameters
  1658. *
  1659. * This function lets us build a specific type of query
  1660. * needed when tags have conditional parameters:
  1661. *
  1662. * {exp:s…

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