You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

266 lines
6.1 KiB

7 years ago
  1. <?php
  2. /**
  3. * CodeIgniter
  4. *
  5. * An open source application development framework for PHP
  6. *
  7. * This content is released under the MIT License (MIT)
  8. *
  9. * Copyright (c) 2014 - 2017, British Columbia Institute of Technology
  10. *
  11. * Permission is hereby granted, free of charge, to any person obtaining a copy
  12. * of this software and associated documentation files (the "Software"), to deal
  13. * in the Software without restriction, including without limitation the rights
  14. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15. * copies of the Software, and to permit persons to whom the Software is
  16. * furnished to do so, subject to the following conditions:
  17. *
  18. * The above copyright notice and this permission notice shall be included in
  19. * all copies or substantial portions of the Software.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  27. * THE SOFTWARE.
  28. *
  29. * @package CodeIgniter
  30. * @author EllisLab Dev Team
  31. * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
  32. * @copyright Copyright (c) 2014 - 2017, British Columbia Institute of Technology (http://bcit.ca/)
  33. * @license http://opensource.org/licenses/MIT MIT License
  34. * @link https://codeigniter.com
  35. * @since Version 1.0.0
  36. * @filesource
  37. */
  38. defined('BASEPATH') OR exit('No direct script access allowed');
  39. /**
  40. * Hooks Class
  41. *
  42. * Provides a mechanism to extend the base system without hacking.
  43. *
  44. * @package CodeIgniter
  45. * @subpackage Libraries
  46. * @category Libraries
  47. * @author EllisLab Dev Team
  48. * @link https://codeigniter.com/user_guide/general/hooks.html
  49. */
  50. class CI_Hooks {
  51. /**
  52. * Determines whether hooks are enabled
  53. *
  54. * @var bool
  55. */
  56. public $enabled = FALSE;
  57. /**
  58. * List of all hooks set in config/hooks.php
  59. *
  60. * @var array
  61. */
  62. public $hooks = array();
  63. /**
  64. * Array with class objects to use hooks methods
  65. *
  66. * @var array
  67. */
  68. protected $_objects = array();
  69. /**
  70. * In progress flag
  71. *
  72. * Determines whether hook is in progress, used to prevent infinte loops
  73. *
  74. * @var bool
  75. */
  76. protected $_in_progress = FALSE;
  77. /**
  78. * Class constructor
  79. *
  80. * @return void
  81. */
  82. public function __construct()
  83. {
  84. $CFG =& load_class('Config', 'core');
  85. log_message('info', 'Hooks Class Initialized');
  86. // If hooks are not enabled in the config file
  87. // there is nothing else to do
  88. if ($CFG->item('enable_hooks') === FALSE)
  89. {
  90. return;
  91. }
  92. // Grab the "hooks" definition file.
  93. if (file_exists(APPPATH.'config/hooks.php'))
  94. {
  95. include(APPPATH.'config/hooks.php');
  96. }
  97. if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/hooks.php'))
  98. {
  99. include(APPPATH.'config/'.ENVIRONMENT.'/hooks.php');
  100. }
  101. // If there are no hooks, we're done.
  102. if ( ! isset($hook) OR ! is_array($hook))
  103. {
  104. return;
  105. }
  106. $this->hooks =& $hook;
  107. $this->enabled = TRUE;
  108. }
  109. // --------------------------------------------------------------------
  110. /**
  111. * Call Hook
  112. *
  113. * Calls a particular hook. Called by CodeIgniter.php.
  114. *
  115. * @uses CI_Hooks::_run_hook()
  116. *
  117. * @param string $which Hook name
  118. * @return bool TRUE on success or FALSE on failure
  119. */
  120. public function call_hook($which = '')
  121. {
  122. if ( ! $this->enabled OR ! isset($this->hooks[$which]))
  123. {
  124. return FALSE;
  125. }
  126. if (is_array($this->hooks[$which]) && ! isset($this->hooks[$which]['function']))
  127. {
  128. foreach ($this->hooks[$which] as $val)
  129. {
  130. $this->_run_hook($val);
  131. }
  132. }
  133. else
  134. {
  135. $this->_run_hook($this->hooks[$which]);
  136. }
  137. return TRUE;
  138. }
  139. // --------------------------------------------------------------------
  140. /**
  141. * Run Hook
  142. *
  143. * Runs a particular hook
  144. *
  145. * @param array $data Hook details
  146. * @return bool TRUE on success or FALSE on failure
  147. */
  148. protected function _run_hook($data)
  149. {
  150. // Closures/lambda functions and array($object, 'method') callables
  151. if (is_callable($data))
  152. {
  153. is_array($data)
  154. ? $data[0]->{$data[1]}()
  155. : $data();
  156. return TRUE;
  157. }
  158. elseif ( ! is_array($data))
  159. {
  160. return FALSE;
  161. }
  162. // -----------------------------------
  163. // Safety - Prevents run-away loops
  164. // -----------------------------------
  165. // If the script being called happens to have the same
  166. // hook call within it a loop can happen
  167. if ($this->_in_progress === TRUE)
  168. {
  169. return;
  170. }
  171. // -----------------------------------
  172. // Set file path
  173. // -----------------------------------
  174. if ( ! isset($data['filepath'], $data['filename']))
  175. {
  176. return FALSE;
  177. }
  178. $filepath = APPPATH.$data['filepath'].'/'.$data['filename'];
  179. if ( ! file_exists($filepath))
  180. {
  181. return FALSE;
  182. }
  183. // Determine and class and/or function names
  184. $class = empty($data['class']) ? FALSE : $data['class'];
  185. $function = empty($data['function']) ? FALSE : $data['function'];
  186. $params = isset($data['params']) ? $data['params'] : '';
  187. if (empty($function))
  188. {
  189. return FALSE;
  190. }
  191. // Set the _in_progress flag
  192. $this->_in_progress = TRUE;
  193. // Call the requested class and/or function
  194. if ($class !== FALSE)
  195. {
  196. // The object is stored?
  197. if (isset($this->_objects[$class]))
  198. {
  199. if (method_exists($this->_objects[$class], $function))
  200. {
  201. $this->_objects[$class]->$function($params);
  202. }
  203. else
  204. {
  205. return $this->_in_progress = FALSE;
  206. }
  207. }
  208. else
  209. {
  210. class_exists($class, FALSE) OR require_once($filepath);
  211. if ( ! class_exists($class, FALSE) OR ! method_exists($class, $function))
  212. {
  213. return $this->_in_progress = FALSE;
  214. }
  215. // Store the object and execute the method
  216. $this->_objects[$class] = new $class();
  217. $this->_objects[$class]->$function($params);
  218. }
  219. }
  220. else
  221. {
  222. function_exists($function) OR require_once($filepath);
  223. if ( ! function_exists($function))
  224. {
  225. return $this->_in_progress = FALSE;
  226. }
  227. $function($params);
  228. }
  229. $this->_in_progress = FALSE;
  230. return TRUE;
  231. }
  232. }