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 - 2018, 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 - 2018, 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 */ 38defined('BASEPATH') OR exit('No direct script access allowed'); 39 40/** 41 * CodeIgniter Driver Library Class 42 * 43 * This class enables you to create "Driver" libraries that add runtime ability 44 * to extend the capabilities of a class via additional driver objects 45 * 46 * @package CodeIgniter 47 * @subpackage Libraries 48 * @category Libraries 49 * @author EllisLab Dev Team 50 * @link 51 */ 52class CI_Driver_Library { 53 54 /** 55 * Array of drivers that are available to use with the driver class 56 * 57 * @var array 58 */ 59 protected $valid_drivers = array(); 60 61 /** 62 * Name of the current class - usually the driver class 63 * 64 * @var string 65 */ 66 protected $lib_name; 67 68 /** 69 * Get magic method 70 * 71 * The first time a child is used it won't exist, so we instantiate it 72 * subsequents calls will go straight to the proper child. 73 * 74 * @param string Child class name 75 * @return object Child class 76 */ 77 public function __get($child) 78 { 79 // Try to load the driver 80 return $this->load_driver($child); 81 } 82 83 /** 84 * Load driver 85 * 86 * Separate load_driver call to support explicit driver load by library or user 87 * 88 * @param string Driver name (w/o parent prefix) 89 * @return object Child class 90 */ 91 public function load_driver($child) 92 { 93 // Get CodeIgniter instance and subclass prefix 94 $prefix = config_item('subclass_prefix'); 95 96 if ( ! isset($this->lib_name)) 97 { 98 // Get library name without any prefix 99 $this->lib_name = str_replace(array('CI_', $prefix), '', get_class($this)); 100 } 101 102 // The child will be prefixed with the parent lib 103 $child_name = $this->lib_name.'_'.$child; 104 105 // See if requested child is a valid driver 106 if ( ! in_array($child, $this->valid_drivers)) 107 { 108 // The requested driver isn't valid! 109 $msg = 'Invalid driver requested: '.$child_name; 110 log_message('error', $msg); 111 show_error($msg); 112 } 113 114 // Get package paths and filename case variations to search 115 $CI = get_instance(); 116 $paths = $CI->load->get_package_paths(TRUE); 117 118 // Is there an extension? 119 $class_name = $prefix.$child_name; 120 $found = class_exists($class_name, FALSE); 121 if ( ! $found) 122 { 123 // Check for subclass file 124 foreach ($paths as $path) 125 { 126 // Does the file exist? 127 $file = $path.'libraries/'.$this->lib_name.'/drivers/'.$prefix.$child_name.'.php'; 128 if (file_exists($file)) 129 { 130 // Yes - require base class from BASEPATH 131 $basepath = BASEPATH.'libraries/'.$this->lib_name.'/drivers/'.$child_name.'.php'; 132 if ( ! file_exists($basepath)) 133 { 134 $msg = 'Unable to load the requested class: CI_'.$child_name; 135 log_message('error', $msg); 136 show_error($msg); 137 } 138 139 // Include both sources and mark found 140 include_once($basepath); 141 include_once($file); 142 $found = TRUE; 143 break; 144 } 145 } 146 } 147 148 // Do we need to search for the class? 149 if ( ! $found) 150 { 151 // Use standard class name 152 $class_name = 'CI_'.$child_name; 153 if ( ! class_exists($class_name, FALSE)) 154 { 155 // Check package paths 156 foreach ($paths as $path) 157 { 158 // Does the file exist? 159 $file = $path.'libraries/'.$this->lib_name.'/drivers/'.$child_name.'.php'; 160 if (file_exists($file)) 161 { 162 // Include source 163 include_once($file); 164 break; 165 } 166 } 167 } 168 } 169 170 // Did we finally find the class? 171 if ( ! class_exists($class_name, FALSE)) 172 { 173 if (class_exists($child_name, FALSE)) 174 { 175 $class_name = $child_name; 176 } 177 else 178 { 179 $msg = 'Unable to load the requested driver: '.$class_name; 180 log_message('error', $msg); 181 show_error($msg); 182 } 183 } 184 185 // Instantiate, decorate and add child 186 $obj = new $class_name(); 187 $obj->decorate($this); 188 $this->$child = $obj; 189 return $this->$child; 190 } 191 192} 193 194// -------------------------------------------------------------------------- 195 196/** 197 * CodeIgniter Driver Class 198 * 199 * This class enables you to create drivers for a Library based on the Driver Library. 200 * It handles the drivers' access to the parent library 201 * 202 * @package CodeIgniter 203 * @subpackage Libraries 204 * @category Libraries 205 * @author EllisLab Dev Team 206 * @link 207 */ 208class CI_Driver { 209 210 /** 211 * Instance of the parent class 212 * 213 * @var object 214 */ 215 protected $_parent; 216 217 /** 218 * List of methods in the parent class 219 * 220 * @var array 221 */ 222 protected $_methods = array(); 223 224 /** 225 * List of properties in the parent class 226 * 227 * @var array 228 */ 229 protected $_properties = array(); 230 231 /** 232 * Array of methods and properties for the parent class(es) 233 * 234 * @static 235 * @var array 236 */ 237 protected static $_reflections = array(); 238 239 /** 240 * Decorate 241 * 242 * Decorates the child with the parent driver lib's methods and properties 243 * 244 * @param object 245 * @return void 246 */ 247 public function decorate($parent) 248 { 249 $this->_parent = $parent; 250 251 // Lock down attributes to what is defined in the class 252 // and speed up references in magic methods 253 254 $class_name = get_class($parent); 255 256 if ( ! isset(self::$_reflections[$class_name])) 257 { 258 $r = new ReflectionObject($parent); 259 260 foreach ($r->getMethods() as $method) 261 { 262 if ($method->isPublic()) 263 { 264 $this->_methods[] = $method->getName(); 265 } 266 } 267 268 foreach ($r->getProperties() as $prop) 269 { 270 if ($prop->isPublic()) 271 { 272 $this->_properties[] = $prop->getName(); 273 } 274 } 275 276 self::$_reflections[$class_name] = array($this->_methods, $this->_properties); 277 } 278 else 279 { 280 list($this->_methods, $this->_properties) = self::$_reflections[$class_name]; 281 } 282 } 283 284 // -------------------------------------------------------------------- 285 286 /** 287 * __call magic method 288 * 289 * Handles access to the parent driver library's methods 290 * 291 * @param string 292 * @param array 293 * @return mixed 294 */ 295 public function __call($method, $args = array()) 296 { 297 if (in_array($method, $this->_methods)) 298 { 299 return call_user_func_array(array($this->_parent, $method), $args); 300 } 301 302 throw new BadMethodCallException('No such method: '.$method.'()'); 303 } 304 305 // -------------------------------------------------------------------- 306 307 /** 308 * __get magic method 309 * 310 * Handles reading of the parent driver library's properties 311 * 312 * @param string 313 * @return mixed 314 */ 315 public function __get($var) 316 { 317 if (in_array($var, $this->_properties)) 318 { 319 return $this->_parent->$var; 320 } 321 } 322 323 // -------------------------------------------------------------------- 324 325 /** 326 * __set magic method 327 * 328 * Handles writing to the parent driver library's properties 329 * 330 * @param string 331 * @param array 332 * @return mixed 333 */ 334 public function __set($var, $val) 335 { 336 if (in_array($var, $this->_properties)) 337 { 338 $this->_parent->$var = $val; 339 } 340 } 341 342} 343