blob: 82c68b1cc407e5d6de85db4ecc9ae7155ec8acd2 [file] [log] [blame]
Andrey Andreevc5536aa2012-11-01 17:33:58 +02001<?php
Derek Allard2067d1a2008-11-13 22:59:24 +00002/**
3 * CodeIgniter
4 *
Andrey Andreevfe9309d2015-01-09 17:48:58 +02005 * An open source application development framework for PHP
Derek Allard2067d1a2008-11-13 22:59:24 +00006 *
Andrey Andreevbdb96ca2014-10-28 00:13:31 +02007 * This content is released under the MIT License (MIT)
Andrey Andreevf9938a22012-01-07 22:10:47 +02008 *
Andrey Andreevcce6bd12018-01-09 11:32:02 +02009 * Copyright (c) 2014 - 2018, British Columbia Institute of Technology
Andrey Andreevf9938a22012-01-07 22:10:47 +020010 *
Andrey Andreevbdb96ca2014-10-28 00:13:31 +020011 * 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:
Derek Jonesf4a4bd82011-10-20 12:18:42 -050017 *
Andrey Andreevbdb96ca2014-10-28 00:13:31 +020018 * 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
Andrey Andreev1924e872016-01-11 12:55:34 +020031 * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
Andrey Andreevcce6bd12018-01-09 11:32:02 +020032 * @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
Andrey Andreevbdb96ca2014-10-28 00:13:31 +020033 * @license http://opensource.org/licenses/MIT MIT License
Andrey Andreevbd202c92016-01-11 12:50:18 +020034 * @link https://codeigniter.com
Andrey Andreevbdb96ca2014-10-28 00:13:31 +020035 * @since Version 1.0.0
Derek Allard2067d1a2008-11-13 22:59:24 +000036 * @filesource
37 */
Andrey Andreevc5536aa2012-11-01 17:33:58 +020038defined('BASEPATH') OR exit('No direct script access allowed');
Derek Allard2067d1a2008-11-13 22:59:24 +000039
Derek Allard2067d1a2008-11-13 22:59:24 +000040/**
Andrey Andreev3e9d2b82012-10-27 14:28:51 +030041 * Hooks Class
Derek Allard2067d1a2008-11-13 22:59:24 +000042 *
Derek Jones6f4d17f2010-03-02 13:34:23 -060043 * Provides a mechanism to extend the base system without hacking.
Derek Allard2067d1a2008-11-13 22:59:24 +000044 *
45 * @package CodeIgniter
46 * @subpackage Libraries
47 * @category Libraries
Derek Jonesf4a4bd82011-10-20 12:18:42 -050048 * @author EllisLab Dev Team
Andrey Andreevbd202c92016-01-11 12:50:18 +020049 * @link https://codeigniter.com/user_guide/general/hooks.html
Derek Allard2067d1a2008-11-13 22:59:24 +000050 */
51class CI_Hooks {
52
David Behler9b5df592011-08-14 21:04:17 +020053 /**
Alex Bilbief512b732012-06-16 11:15:19 +010054 * Determines whether hooks are enabled
David Behler9b5df592011-08-14 21:04:17 +020055 *
Andrey Andreev3e9d2b82012-10-27 14:28:51 +030056 * @var bool
David Behler9b5df592011-08-14 21:04:17 +020057 */
Andrey Andreev3e9d2b82012-10-27 14:28:51 +030058 public $enabled = FALSE;
Andrey Andreev92ebfb62012-05-17 12:49:24 +030059
David Behler9b5df592011-08-14 21:04:17 +020060 /**
61 * List of all hooks set in config/hooks.php
62 *
Andrey Andreev3e9d2b82012-10-27 14:28:51 +030063 * @var array
David Behler9b5df592011-08-14 21:04:17 +020064 */
Timothy Warren48a7fbb2012-04-23 11:58:16 -040065 public $hooks = array();
Andrey Andreev92ebfb62012-05-17 12:49:24 +030066
David Behler9b5df592011-08-14 21:04:17 +020067 /**
Marcos SF Filho0f667c92014-01-07 15:01:56 -020068 * Array with class objects to use hooks methods
69 *
70 * @var array
71 */
Marcos SF Filhobdfef072014-01-08 09:48:09 -020072 protected $_objects = array();
Marcos SF Filho0f667c92014-01-07 15:01:56 -020073
74 /**
Andrey Andreev3e9d2b82012-10-27 14:28:51 +030075 * In progress flag
76 *
Alex Bilbief512b732012-06-16 11:15:19 +010077 * Determines whether hook is in progress, used to prevent infinte loops
David Behler9b5df592011-08-14 21:04:17 +020078 *
Andrey Andreev3e9d2b82012-10-27 14:28:51 +030079 * @var bool
David Behler9b5df592011-08-14 21:04:17 +020080 */
Andrey Andreev3e9d2b82012-10-27 14:28:51 +030081 protected $_in_progress = FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +000082
Derek Allard2067d1a2008-11-13 22:59:24 +000083 /**
Andrey Andreev3e9d2b82012-10-27 14:28:51 +030084 * Class constructor
Derek Allard2067d1a2008-11-13 22:59:24 +000085 *
Derek Allard2067d1a2008-11-13 22:59:24 +000086 * @return void
Barry Mienydd671972010-10-04 16:33:58 +020087 */
Andrey Andreeva5dd2972012-03-26 14:43:01 +030088 public function __construct()
Barry Mienydd671972010-10-04 16:33:58 +020089 {
Derek Jonesc64ca012010-03-07 07:55:56 -060090 $CFG =& load_class('Config', 'core');
Andrey Andreev90726b82015-01-20 12:39:22 +020091 log_message('info', 'Hooks Class Initialized');
Andrey Andreeva5dd2972012-03-26 14:43:01 +030092
Derek Allard2067d1a2008-11-13 22:59:24 +000093 // If hooks are not enabled in the config file
94 // there is nothing else to do
Alex Bilbieed944a32012-06-02 11:07:47 +010095 if ($CFG->item('enable_hooks') === FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +000096 {
97 return;
98 }
99
100 // Grab the "hooks" definition file.
Andrey Andreev06879112013-01-29 15:05:02 +0200101 if (file_exists(APPPATH.'config/hooks.php'))
Greg Akerd96f8822011-12-27 16:23:47 -0600102 {
103 include(APPPATH.'config/hooks.php');
104 }
105
vlakoff4be16042015-01-04 17:16:20 +0100106 if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/hooks.php'))
107 {
108 include(APPPATH.'config/'.ENVIRONMENT.'/hooks.php');
109 }
110
Andrey Andreevf9938a22012-01-07 22:10:47 +0200111 // If there are no hooks, we're done.
Derek Allard2067d1a2008-11-13 22:59:24 +0000112 if ( ! isset($hook) OR ! is_array($hook))
113 {
114 return;
115 }
116
117 $this->hooks =& $hook;
118 $this->enabled = TRUE;
Barry Mienydd671972010-10-04 16:33:58 +0200119 }
120
Derek Allard2067d1a2008-11-13 22:59:24 +0000121 // --------------------------------------------------------------------
122
123 /**
124 * Call Hook
125 *
Andrey Andreevf9938a22012-01-07 22:10:47 +0200126 * Calls a particular hook. Called by CodeIgniter.php.
Derek Allard2067d1a2008-11-13 22:59:24 +0000127 *
Andrey Andreev3e9d2b82012-10-27 14:28:51 +0300128 * @uses CI_Hooks::_run_hook()
129 *
130 * @param string $which Hook name
131 * @return bool TRUE on success or FALSE on failure
Derek Allard2067d1a2008-11-13 22:59:24 +0000132 */
Andrey Andreeva5dd2972012-03-26 14:43:01 +0300133 public function call_hook($which = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000134 {
135 if ( ! $this->enabled OR ! isset($this->hooks[$which]))
136 {
137 return FALSE;
138 }
139
Andrey Andreev94293ad2014-06-12 11:33:43 +0300140 if (is_array($this->hooks[$which]) && ! isset($this->hooks[$which]['function']))
Derek Allard2067d1a2008-11-13 22:59:24 +0000141 {
142 foreach ($this->hooks[$which] as $val)
143 {
144 $this->_run_hook($val);
145 }
146 }
147 else
148 {
149 $this->_run_hook($this->hooks[$which]);
150 }
151
152 return TRUE;
153 }
154
155 // --------------------------------------------------------------------
156
157 /**
158 * Run Hook
159 *
160 * Runs a particular hook
161 *
Andrey Andreev3e9d2b82012-10-27 14:28:51 +0300162 * @param array $data Hook details
163 * @return bool TRUE on success or FALSE on failure
Derek Allard2067d1a2008-11-13 22:59:24 +0000164 */
Andrey Andreevf9938a22012-01-07 22:10:47 +0200165 protected function _run_hook($data)
Derek Allard2067d1a2008-11-13 22:59:24 +0000166 {
Andrey Andreev83514042014-03-06 00:28:55 +0200167 // Closures/lambda functions and array($object, 'method') callables
168 if (is_callable($data))
169 {
170 is_array($data)
171 ? $data[0]->{$data[1]}()
172 : $data();
173
174 return TRUE;
175 }
176 elseif ( ! is_array($data))
Derek Allard2067d1a2008-11-13 22:59:24 +0000177 {
178 return FALSE;
179 }
180
181 // -----------------------------------
182 // Safety - Prevents run-away loops
183 // -----------------------------------
184
185 // If the script being called happens to have the same
186 // hook call within it a loop can happen
Andrey Andreev3e9d2b82012-10-27 14:28:51 +0300187 if ($this->_in_progress === TRUE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000188 {
189 return;
190 }
191
192 // -----------------------------------
193 // Set file path
194 // -----------------------------------
195
Andrey Andreeva5dd2972012-03-26 14:43:01 +0300196 if ( ! isset($data['filepath'], $data['filename']))
Derek Allard2067d1a2008-11-13 22:59:24 +0000197 {
198 return FALSE;
199 }
200
201 $filepath = APPPATH.$data['filepath'].'/'.$data['filename'];
202
203 if ( ! file_exists($filepath))
204 {
205 return FALSE;
206 }
207
Andrey Andreev3e9d2b82012-10-27 14:28:51 +0300208 // Determine and class and/or function names
209 $class = empty($data['class']) ? FALSE : $data['class'];
210 $function = empty($data['function']) ? FALSE : $data['function'];
211 $params = isset($data['params']) ? $data['params'] : '';
Derek Allard2067d1a2008-11-13 22:59:24 +0000212
Andrey Andreevda8c7a52014-01-07 18:08:26 +0200213 if (empty($function))
Derek Allard2067d1a2008-11-13 22:59:24 +0000214 {
215 return FALSE;
216 }
217
Andrey Andreev3e9d2b82012-10-27 14:28:51 +0300218 // Set the _in_progress flag
219 $this->_in_progress = TRUE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000220
Derek Allard2067d1a2008-11-13 22:59:24 +0000221 // Call the requested class and/or function
Derek Allard2067d1a2008-11-13 22:59:24 +0000222 if ($class !== FALSE)
223 {
Marcos SF Filho0f667c92014-01-07 15:01:56 -0200224 // The object is stored?
Marcos SF Filhobdfef072014-01-08 09:48:09 -0200225 if (isset($this->_objects[$class]))
Derek Allard2067d1a2008-11-13 22:59:24 +0000226 {
Marcos SF Filhobdfef072014-01-08 09:48:09 -0200227 if (method_exists($this->_objects[$class], $function))
228 {
229 $this->_objects[$class]->$function($params);
230 }
231 else
232 {
233 return $this->_in_progress = FALSE;
234 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000235 }
Marcos SF Filho0f667c92014-01-07 15:01:56 -0200236 else
Marcos SF Filhobdfef072014-01-08 09:48:09 -0200237 {
Marcos SF Filho0f667c92014-01-07 15:01:56 -0200238 class_exists($class, FALSE) OR require_once($filepath);
Derek Allard2067d1a2008-11-13 22:59:24 +0000239
Marcos SF Filho0f667c92014-01-07 15:01:56 -0200240 if ( ! class_exists($class, FALSE) OR ! method_exists($class, $function))
241 {
242 return $this->_in_progress = FALSE;
243 }
Marcos SF Filhobdfef072014-01-08 09:48:09 -0200244
245 // Store the object and execute the method
246 $this->_objects[$class] = new $class();
247 $this->_objects[$class]->$function($params);
Marcos SF Filho0f667c92014-01-07 15:01:56 -0200248 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000249 }
250 else
251 {
Andrey Andreevda8c7a52014-01-07 18:08:26 +0200252 function_exists($function) OR require_once($filepath);
253
Derek Allard2067d1a2008-11-13 22:59:24 +0000254 if ( ! function_exists($function))
255 {
Andrey Andreevda8c7a52014-01-07 18:08:26 +0200256 return $this->_in_progress = FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000257 }
258
259 $function($params);
260 }
261
Andrey Andreev3e9d2b82012-10-27 14:28:51 +0300262 $this->_in_progress = FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000263 return TRUE;
264 }
265
266}