├── README.md ├── config ├── autoload.php ├── constants.php └── database.php ├── core ├── MY_Controller.php ├── MY_Loader.php ├── MY_Model.php └── database │ ├── ActiveRecord.php │ ├── DB.php │ ├── DB_driver.php │ └── drivers │ └── mysql │ └── mysql_driver.php ├── helpers └── db_proxy_helper.php ├── libraries └── MY_Log.php └── models └── test_model.php /README.md: -------------------------------------------------------------------------------- 1 | CodeIgniter-mysql-proxy 2 | ======================= 3 | -------------------------------------------------------------------------------- /config/autoload.php: -------------------------------------------------------------------------------- 1 | array('default_slave'), 53 | ); 54 | 55 | $db['default_master']['hostname'] = '127.0.0.1'; 56 | $db['default_master']['username'] = 'root'; 57 | $db['default_master']['password'] = '123456'; 58 | $db['default_master']['database'] = 'test'; 59 | $db['default_master']['dbdriver'] = 'mysql'; 60 | $db['default_master']['dbprefix'] = ''; 61 | $db['default_master']['pconnect'] = FALSE; 62 | $db['default_master']['db_debug'] = FALSE; 63 | $db['default_master']['cache_on'] = FALSE; 64 | $db['default_master']['cachedir'] = ''; 65 | $db['default_master']['char_set'] = 'utf8'; 66 | $db['default_master']['dbcollat'] = 'utf8_general_ci'; 67 | $db['default_master']['swap_pre'] = ''; 68 | $db['default_master']['autoinit'] = FALSE; 69 | $db['default_master']['stricton'] = FALSE; 70 | 71 | $db['default_slave']['hostname'] = '127.0.0.1'; 72 | $db['default_slave']['username'] = 'root'; 73 | $db['default_slave']['password'] = '123456'; 74 | $db['default_slave']['database'] = 'test_slave'; 75 | $db['default_slave']['dbdriver'] = 'mysql'; 76 | $db['default_slave']['dbprefix'] = ''; 77 | $db['default_slave']['pconnect'] = FALSE; 78 | $db['default_slave']['db_debug'] = FALSE; 79 | $db['default_slave']['cache_on'] = FALSE; 80 | $db['default_slave']['cachedir'] = ''; 81 | $db['default_slave']['char_set'] = 'utf8'; 82 | $db['default_slave']['dbcollat'] = 'utf8_general_ci'; 83 | $db['default_slave']['swap_pre'] = ''; 84 | $db['default_slave']['autoinit'] = FALSE; 85 | $db['default_slave']['stricton'] = FALSE; 86 | 87 | 88 | /* End of file database.php */ 89 | /* Location: ./application/config/database.php */ -------------------------------------------------------------------------------- /core/MY_Controller.php: -------------------------------------------------------------------------------- 1 | $val) { 10 | if(substr($key, 0, 3) == 'db_' && is_object($this->{$key}) && method_exists($this->{$key}, 'close')) { 11 | $this->{$key}->close($key); 12 | } 13 | if(substr($key, 0, 5) == 'conn_' && is_resource($this->{$key})) { 14 | $this->db->_close($val); 15 | unset($this->{$key}); 16 | } 17 | } 18 | }); 19 | } 20 | } 21 | 22 | /* End of file MY_Controller.php */ 23 | /* Location: ./application/core/MY_Controller.php */ -------------------------------------------------------------------------------- /core/MY_Loader.php: -------------------------------------------------------------------------------- 1 | db) AND is_object($CI->db)) { 9 | return FALSE; 10 | } 11 | if(file_exists(APPPATH.'core/database/DB.php')) { 12 | require_once(APPPATH.'core/database/DB.php'); 13 | } else { 14 | require_once(BASEPATH.'database/DB.php'); 15 | } 16 | if ($return === TRUE) { 17 | return DB($params, $active_record); 18 | } 19 | $CI->db = ''; 20 | $CI->db =& DB($params, $active_record); 21 | } 22 | } 23 | 24 | /* End of file MY_Loader.php */ 25 | /* Location: ./application/core/MY_Loader.php */ -------------------------------------------------------------------------------- /core/MY_Model.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | */ 11 | class MY_Model extends ActiveRecord 12 | { 13 | public function __construct($group_name = '') 14 | { 15 | parent::__construct(); 16 | $this->initDb($group_name); 17 | } 18 | 19 | private function initDb($group_name = '') 20 | { 21 | $db_conn_name = $this->getDbName($group_name); 22 | $CI = & get_instance(); 23 | if(isset($CI->{$db_conn_name}) && is_object($CI->{$db_conn_name})) { 24 | $this->db = $CI->{$db_conn_name}; 25 | } else { 26 | $CI->{$db_conn_name} = $this->db = $this->load->database($group_name, TRUE); 27 | } 28 | } 29 | 30 | private function getDbName($group_name = '') 31 | { 32 | if($group_name == '') { 33 | $db_conn_name = 'db'; 34 | } else { 35 | $db_conn_name = 'db_'.$group_name; 36 | } 37 | return $db_conn_name; 38 | } 39 | } 40 | 41 | /* End of file MY_Model.php */ 42 | /* Location: ./application/core/MY_Model.php */ -------------------------------------------------------------------------------- /core/database/ActiveRecord.php: -------------------------------------------------------------------------------- 1 | db->set($data)->insert($this->tableName())) { 14 | return $this->db->insert_id(); 15 | } 16 | return FALSE; 17 | } 18 | 19 | /** 20 | * Update Record By Primary Key 21 | * 22 | * @param string $pk 23 | * @param array $attributes 24 | * @param array $where 25 | * @return boolean true for success, false for failure 26 | */ 27 | public function updateByPk($pk, $attributes, $where = array()) 28 | { 29 | $where[$this->primaryKey()] = $pk; 30 | return $this->updateAll($attributes, $where); 31 | } 32 | 33 | 34 | /** 35 | * Update Record 36 | * 37 | * @param array $attributes eg.updateAll(array('price' => array('price + 1', false)), array('id > ' => 2))) 38 | * @param array $where 39 | * @return bollean true for success, false for failure 40 | */ 41 | public function updateAll($attributes, $where = array()) 42 | { 43 | foreach($attributes as $key => $val) { 44 | if(is_array($val)) { 45 | $field_val = isset($val[0]) ? $val[0] : NULL; 46 | $escape = isset($val[1]) && !$val[1] ? false : true; 47 | $this->db->set($key, $field_val, $escape); 48 | unset($attributes[$key]); 49 | } 50 | } 51 | return $this->db->where($where)->update($this->tableName(), $attributes); 52 | } 53 | 54 | /** 55 | * Delete Record By Primary Key 56 | * 57 | * @param string $pk 58 | * @param array $where 59 | * @return boolean true for success, false for failure 60 | */ 61 | public function deleteByPk($pk, $where = array()) 62 | { 63 | $where[$this->primaryKey()] = $pk; 64 | return $this->deleteAll($where); 65 | } 66 | 67 | /** 68 | * Delete Record 69 | * 70 | * @param array $where 71 | * @return boolean true for success, false for failure 72 | */ 73 | public function deleteAll($where = array(), $limit = NULL) 74 | { 75 | return $this->db->delete($this->tableName(), $where, $limit); 76 | } 77 | 78 | /** 79 | * Find Data By Primary Key 80 | * 81 | * @param string $pk 82 | * @param array $where 83 | * @return array 84 | */ 85 | public function findByPk($pk, $where = array()) 86 | { 87 | $where[$this->primaryKey()] = $pk; 88 | $query = $this->db->from($this->tableName())->where($where)->get(); 89 | return $query->row_array(); 90 | } 91 | 92 | /** 93 | * Find Record By Attributes 94 | * 95 | * @param array $where 96 | * @return array 97 | */ 98 | public function findByAttributes($where = array()) 99 | { 100 | $query = $this->db->from($this->tableName())->where($where)->limit(1)->get(); 101 | return $query->row_array(); 102 | } 103 | 104 | /** 105 | * Find Record 106 | * 107 | * @param array $where fuzzy query eg.array('name LIKE' => "pp%") array('stat >' => '1') 108 | * @param int $limit 109 | * @param int $offset 110 | * @param string $sort 111 | * @return array 112 | */ 113 | public function findAll($where = array(), $limit = 0, $offset = 0, $sort = NULL) 114 | { 115 | $this->db->from($this->tableName())->where($where); 116 | if($sort !== NULL) { 117 | $this->db->order_by($sort); 118 | } 119 | if($limit > 0) { 120 | $this->db->limit($limit, $offset); 121 | } 122 | $query = $this->db->get(); 123 | 124 | return $query->result_array(); 125 | } 126 | 127 | /** 128 | * Count 129 | * 130 | * @param array $where 131 | * @return int 132 | */ 133 | public function count($where = array()) 134 | { 135 | return $this->db->from($this->tableName())->where($where)->count_all_results(); 136 | } 137 | 138 | /** 139 | * Query SQL 140 | * 141 | * @param string $sql eg.SELECT * FROM tbl_name WHERE id = ? AND status = ? AND author = ? 142 | * @param array $param array(3, 'live', 'Rick') 143 | * @return array 144 | */ 145 | public function query($sql, $param = array()) 146 | { 147 | $query = $this->db->query($sql, $param); 148 | return $query->result_array(); 149 | } 150 | 151 | /** 152 | * execute SQL 153 | * 154 | * @param string $sql eg. UPDATE `test` SET `stat` = 3 WHERE WHERE id = ? 155 | * @param array $param array(3) 156 | * @return boolean|int 157 | */ 158 | public function execute($sql, $param = array()) 159 | { 160 | if($this->db->query($sql, $param)) { 161 | return $this->db->affected_rows() ? $this->db->affected_rows() : true; 162 | } 163 | return false; 164 | } 165 | 166 | /** 167 | * Insert Batch 168 | * 169 | * @param array $data 170 | */ 171 | public function insertData($data) 172 | { 173 | if(is_array(current($data))) { 174 | return $this->db->insert_batch($this->tableName(), $data); 175 | } else { 176 | return $this->db->insert($this->tableName(), $data); 177 | } 178 | } 179 | 180 | /** 181 | * Upate Data 182 | * 183 | * @param array $data 184 | */ 185 | public function updateData($data, $key = 'id') 186 | { 187 | return $this->db->update_batch($this->tableName(), $data, $key); 188 | } 189 | 190 | /** 191 | * force master 192 | */ 193 | public function force_master() 194 | { 195 | if(method_exists($this->db, 'force_master')){ 196 | $this->db->force_master(); 197 | } 198 | return $this; 199 | } 200 | } 201 | 202 | /* End of file ActiveRecord.php */ 203 | /* Location: ./application/core/database/ActiveRecord.php */ -------------------------------------------------------------------------------- /core/database/DB.php: -------------------------------------------------------------------------------- 1 | $dns['scheme'], 77 | 'hostname' => (isset($dns['host'])) ? rawurldecode($dns['host']) : '', 78 | 'username' => (isset($dns['user'])) ? rawurldecode($dns['user']) : '', 79 | 'password' => (isset($dns['pass'])) ? rawurldecode($dns['pass']) : '', 80 | 'database' => (isset($dns['path'])) ? rawurldecode(substr($dns['path'], 1)) : '' 81 | ); 82 | 83 | // were additional config items set? 84 | if (isset($dns['query'])) 85 | { 86 | parse_str($dns['query'], $extra); 87 | 88 | foreach ($extra as $key => $val) 89 | { 90 | // booleans please 91 | if (strtoupper($val) == "TRUE") 92 | { 93 | $val = TRUE; 94 | } 95 | elseif (strtoupper($val) == "FALSE") 96 | { 97 | $val = FALSE; 98 | } 99 | 100 | $params[$key] = $val; 101 | } 102 | } 103 | } 104 | 105 | // No DB specified yet? Beat them senseless... 106 | if ( ! isset($params['dbdriver']) OR $params['dbdriver'] == '') 107 | { 108 | show_error('You have not selected a database type to connect to.'); 109 | } 110 | 111 | // Load the DB classes. Note: Since the active record class is optional 112 | // we need to dynamically create a class that extends proper parent class 113 | // based on whether we're using the active record class or not. 114 | // Kudos to Paul for discovering this clever use of eval() 115 | 116 | if ($active_record_override !== NULL) 117 | { 118 | $active_record = $active_record_override; 119 | } 120 | 121 | if(file_exists(APPPATH.'core/database/DB_driver.php')) { 122 | require_once(APPPATH.'core/database/DB_driver.php'); 123 | } else { 124 | require_once(BASEPATH.'database/DB_driver.php'); 125 | } 126 | 127 | if ( ! isset($active_record) OR $active_record == TRUE) 128 | { 129 | require_once(BASEPATH.'database/DB_active_rec.php'); 130 | 131 | if ( ! class_exists('CI_DB')) 132 | { 133 | eval('class CI_DB extends CI_DB_active_record { }'); 134 | } 135 | } 136 | else 137 | { 138 | if ( ! class_exists('CI_DB')) 139 | { 140 | eval('class CI_DB extends CI_DB_driver { }'); 141 | } 142 | } 143 | 144 | if(file_exists(APPPATH.'core/database/drivers/'.$params['dbdriver'].'/'.$params['dbdriver'].'_driver.php')) { 145 | require_once(APPPATH.'core/database/drivers/'.$params['dbdriver'].'/'.$params['dbdriver'].'_driver.php'); 146 | } else { 147 | require_once(BASEPATH.'database/drivers/'.$params['dbdriver'].'/'.$params['dbdriver'].'_driver.php'); 148 | } 149 | $params['group_name'] = $active_group; 150 | // Instantiate the DB adapter 151 | $driver = 'CI_DB_'.$params['dbdriver'].'_driver'; 152 | $DB = new $driver($params); 153 | 154 | if ($DB->autoinit == TRUE) 155 | { 156 | $DB->initialize(); 157 | } 158 | 159 | if (isset($params['stricton']) && $params['stricton'] == TRUE) 160 | { 161 | $DB->query('SET SESSION sql_mode="STRICT_ALL_TABLES"'); 162 | } 163 | 164 | return $DB; 165 | } 166 | 167 | 168 | 169 | /* End of file DB.php */ 170 | /* Location: ./system/database/DB.php */ -------------------------------------------------------------------------------- /core/database/DB_driver.php: -------------------------------------------------------------------------------- 1 | $val) 90 | { 91 | $this->$key = $val; 92 | } 93 | } 94 | 95 | log_message('debug', 'Database Driver Class Initialized'); 96 | } 97 | 98 | // -------------------------------------------------------------------- 99 | 100 | /** 101 | * Initialize Database Settings 102 | * 103 | * @access private Called by the constructor 104 | * @param mixed 105 | * @return void 106 | */ 107 | function initialize() 108 | { 109 | // If an existing connection resource is available 110 | // there is no need to connect and select the database 111 | if (is_resource($this->conn_id) OR is_object($this->conn_id)) 112 | { 113 | return TRUE; 114 | } 115 | 116 | // ---------------------------------------------------------------- 117 | 118 | // Connect to the database and set the connection ID 119 | $this->conn_id = ($this->pconnect == FALSE) ? $this->db_connect() : $this->db_pconnect(); 120 | 121 | // No connection resource? Throw an error 122 | if ( ! $this->conn_id) 123 | { 124 | log_message('error', 'Unable to connect to the database'); 125 | 126 | if ($this->db_debug) 127 | { 128 | $this->display_error('db_unable_to_connect'); 129 | } 130 | return FALSE; 131 | } 132 | 133 | // ---------------------------------------------------------------- 134 | 135 | // Select the DB... assuming a database name is specified in the config file 136 | if ($this->database != '') 137 | { 138 | if ( ! $this->db_select()) 139 | { 140 | log_message('error', 'Unable to select database: '.$this->database); 141 | 142 | if ($this->db_debug) 143 | { 144 | $this->display_error('db_unable_to_select', $this->database); 145 | } 146 | return FALSE; 147 | } 148 | else 149 | { 150 | // We've selected the DB. Now we set the character set 151 | if ( ! $this->db_set_charset($this->char_set, $this->dbcollat)) 152 | { 153 | return FALSE; 154 | } 155 | 156 | return TRUE; 157 | } 158 | } 159 | 160 | return TRUE; 161 | } 162 | 163 | // -------------------------------------------------------------------- 164 | 165 | /** 166 | * Set client character set 167 | * 168 | * @access public 169 | * @param string 170 | * @param string 171 | * @return resource 172 | */ 173 | function db_set_charset($charset, $collation) 174 | { 175 | if ( ! $this->_db_set_charset($this->char_set, $this->dbcollat)) 176 | { 177 | log_message('error', 'Unable to set database connection charset: '.$this->char_set); 178 | 179 | if ($this->db_debug) 180 | { 181 | $this->display_error('db_unable_to_set_charset', $this->char_set); 182 | } 183 | 184 | return FALSE; 185 | } 186 | 187 | return TRUE; 188 | } 189 | 190 | // -------------------------------------------------------------------- 191 | 192 | /** 193 | * The name of the platform in use (mysql, mssql, etc...) 194 | * 195 | * @access public 196 | * @return string 197 | */ 198 | function platform() 199 | { 200 | return $this->dbdriver; 201 | } 202 | 203 | // -------------------------------------------------------------------- 204 | 205 | /** 206 | * Database Version Number. Returns a string containing the 207 | * version of the database being used 208 | * 209 | * @access public 210 | * @return string 211 | */ 212 | function version() 213 | { 214 | if (FALSE === ($sql = $this->_version())) 215 | { 216 | if ($this->db_debug) 217 | { 218 | return $this->display_error('db_unsupported_function'); 219 | } 220 | return FALSE; 221 | } 222 | 223 | // Some DBs have functions that return the version, and don't run special 224 | // SQL queries per se. In these instances, just return the result. 225 | $driver_version_exceptions = array('oci8', 'sqlite', 'cubrid'); 226 | 227 | if (in_array($this->dbdriver, $driver_version_exceptions)) 228 | { 229 | return $sql; 230 | } 231 | else 232 | { 233 | $query = $this->query($sql); 234 | return $query->row('ver'); 235 | } 236 | } 237 | 238 | // -------------------------------------------------------------------- 239 | 240 | /** 241 | * Execute the query 242 | * 243 | * Accepts an SQL string as input and returns a result object upon 244 | * successful execution of a "read" type query. Returns boolean TRUE 245 | * upon successful execution of a "write" type query. Returns boolean 246 | * FALSE upon failure, and if the $db_debug variable is set to TRUE 247 | * will raise an error. 248 | * 249 | * @access public 250 | * @param string An SQL query string 251 | * @param array An array of binding data 252 | * @return mixed 253 | */ 254 | function query($sql, $binds = FALSE, $return_object = TRUE) 255 | { 256 | if ($sql == '') 257 | { 258 | if ($this->db_debug) 259 | { 260 | log_message('error', 'Invalid query: '.$sql); 261 | return $this->display_error('db_invalid_query'); 262 | } 263 | return FALSE; 264 | } 265 | 266 | // Verify table prefix and replace if necessary 267 | if ( ($this->dbprefix != '' AND $this->swap_pre != '') AND ($this->dbprefix != $this->swap_pre) ) 268 | { 269 | $sql = preg_replace("/(\W)".$this->swap_pre."(\S+?)/", "\\1".$this->dbprefix."\\2", $sql); 270 | } 271 | 272 | // Compile binds if needed 273 | if ($binds !== FALSE) 274 | { 275 | $sql = $this->compile_binds($sql, $binds); 276 | } 277 | 278 | // Is query caching enabled? If the query is a "read type" 279 | // we will load the caching class and return the previously 280 | // cached query if it exists 281 | if ($this->cache_on == TRUE AND stristr($sql, 'SELECT')) 282 | { 283 | if ($this->_cache_init()) 284 | { 285 | $this->load_rdriver(); 286 | if (FALSE !== ($cache = $this->CACHE->read($sql))) 287 | { 288 | return $cache; 289 | } 290 | } 291 | } 292 | 293 | // Save the query for debugging 294 | if ($this->save_queries == TRUE) 295 | { 296 | $this->queries[] = $sql; 297 | } 298 | 299 | // Start the Query Timer 300 | $time_start = list($sm, $ss) = explode(' ', microtime()); 301 | 302 | // Run the Query 303 | if (FALSE === ($this->result_id = $this->simple_query($sql))) 304 | { 305 | if ($this->save_queries == TRUE) 306 | { 307 | $this->query_times[] = 0; 308 | } 309 | 310 | // This will trigger a rollback if transactions are being used 311 | $this->_trans_status = FALSE; 312 | 313 | if ($this->db_debug) 314 | { 315 | // grab the error number and message now, as we might run some 316 | // additional queries before displaying the error 317 | $error_no = $this->_error_number(); 318 | $error_msg = $this->_error_message(); 319 | 320 | // We call this function in order to roll-back queries 321 | // if transactions are enabled. If we don't call this here 322 | // the error message will trigger an exit, causing the 323 | // transactions to remain in limbo. 324 | $this->trans_complete(); 325 | 326 | // Log and display errors 327 | log_message('error', 'Query error: '.$error_msg); 328 | return $this->display_error( 329 | array( 330 | 'Error Number: '.$error_no, 331 | $error_msg, 332 | $sql 333 | ) 334 | ); 335 | } 336 | 337 | return FALSE; 338 | } 339 | 340 | // Stop and aggregate the query time results 341 | $time_end = list($em, $es) = explode(' ', microtime()); 342 | $this->benchmark += ($em + $es) - ($sm + $ss); 343 | 344 | if ($this->save_queries == TRUE) 345 | { 346 | $this->query_times[] = ($em + $es) - ($sm + $ss); 347 | } 348 | 349 | // Increment the query counter 350 | $this->query_count++; 351 | 352 | // Was the query a "write" type? 353 | // If so we'll simply return true 354 | if ($this->is_write_type($sql) === TRUE) 355 | { 356 | // If caching is enabled we'll auto-cleanup any 357 | // existing files related to this particular URI 358 | if ($this->cache_on == TRUE AND $this->cache_autodel == TRUE AND $this->_cache_init()) 359 | { 360 | $this->CACHE->delete(); 361 | } 362 | 363 | return TRUE; 364 | } 365 | 366 | // Return TRUE if we don't need to create a result object 367 | // Currently only the Oracle driver uses this when stored 368 | // procedures are used 369 | if ($return_object !== TRUE) 370 | { 371 | return TRUE; 372 | } 373 | 374 | // Load and instantiate the result driver 375 | 376 | $driver = $this->load_rdriver(); 377 | $RES = new $driver(); 378 | $RES->conn_id = $this->conn_id; 379 | $RES->result_id = $this->result_id; 380 | 381 | if ($this->dbdriver == 'oci8') 382 | { 383 | $RES->stmt_id = $this->stmt_id; 384 | $RES->curs_id = NULL; 385 | $RES->limit_used = $this->limit_used; 386 | $this->stmt_id = FALSE; 387 | } 388 | 389 | // oci8 vars must be set before calling this 390 | $RES->num_rows = $RES->num_rows(); 391 | 392 | // Is query caching enabled? If so, we'll serialize the 393 | // result object and save it to a cache file. 394 | if ($this->cache_on == TRUE AND $this->_cache_init()) 395 | { 396 | // We'll create a new instance of the result object 397 | // only without the platform specific driver since 398 | // we can't use it with cached data (the query result 399 | // resource ID won't be any good once we've cached the 400 | // result object, so we'll have to compile the data 401 | // and save it) 402 | $CR = new CI_DB_result(); 403 | $CR->num_rows = $RES->num_rows(); 404 | $CR->result_object = $RES->result_object(); 405 | $CR->result_array = $RES->result_array(); 406 | 407 | // Reset these since cached objects can not utilize resource IDs. 408 | $CR->conn_id = NULL; 409 | $CR->result_id = NULL; 410 | 411 | $this->CACHE->write($sql, $CR); 412 | } 413 | 414 | return $RES; 415 | } 416 | 417 | // -------------------------------------------------------------------- 418 | 419 | /** 420 | * Load the result drivers 421 | * 422 | * @access public 423 | * @return string the name of the result class 424 | */ 425 | function load_rdriver() 426 | { 427 | $driver = 'CI_DB_'.$this->dbdriver.'_result'; 428 | 429 | if ( ! class_exists($driver)) 430 | { 431 | include_once(BASEPATH.'database/DB_result.php'); 432 | include_once(BASEPATH.'database/drivers/'.$this->dbdriver.'/'.$this->dbdriver.'_result.php'); 433 | } 434 | 435 | return $driver; 436 | } 437 | 438 | // -------------------------------------------------------------------- 439 | 440 | /** 441 | * Simple Query 442 | * This is a simplified version of the query() function. Internally 443 | * we only use it when running transaction commands since they do 444 | * not require all the features of the main query() function. 445 | * 446 | * @access public 447 | * @param string the sql query 448 | * @return mixed 449 | */ 450 | function simple_query($sql) 451 | { 452 | $proxy_setting = load_db_proxy_setting($this->group_name, $this->is_write_type($sql), $this->db_force_master); 453 | if(is_array($proxy_setting) && ! empty($proxy_setting)) { 454 | $proxy_setting_key = key($proxy_setting); 455 | $this->group_name = $proxy_setting_key; 456 | foreach($proxy_setting[$proxy_setting_key] as $key => $val) { 457 | $this->$key = $val; 458 | } 459 | $proxy_conn_id = 'conn_'.$proxy_setting_key; 460 | $CI = & get_instance(); 461 | if(isset($CI->$proxy_conn_id) && is_resource($CI->$proxy_conn_id)) { 462 | $this->conn_id = $CI->$proxy_conn_id; 463 | //$this->reconnect(); 464 | } else { 465 | //$this->_close($this->conn_id); 466 | $this->conn_id = false; 467 | $this->initialize(); 468 | $CI->$proxy_conn_id = $this->conn_id; 469 | } 470 | $this->reset_force_master(); 471 | } 472 | if ( ! $this->conn_id) 473 | { 474 | $this->initialize(); 475 | } 476 | if(defined('SQL_LOG_WRITE') && SQL_LOG_WRITE === true) { 477 | $CI = & get_instance(); 478 | $CI->load->library('log'); 479 | $CI->log->write("ip={$CI->input->ip_address()}; host={$this->hostname}; dbname={$this->database}; group={$this->group_name};\r\n".preg_replace("/\s+/", " ", $sql), 'sqllog/log'); 480 | } 481 | return $this->_execute($sql); 482 | } 483 | 484 | /** 485 | * 强制主库 486 | */ 487 | public function force_master() 488 | { 489 | $this->db_force_master = TRUE; 490 | } 491 | 492 | /** 493 | * 取消强制主库 494 | */ 495 | public function reset_force_master() 496 | { 497 | $this->db_force_master = FALSE; 498 | } 499 | 500 | // -------------------------------------------------------------------- 501 | 502 | /** 503 | * Disable Transactions 504 | * This permits transactions to be disabled at run-time. 505 | * 506 | * @access public 507 | * @return void 508 | */ 509 | function trans_off() 510 | { 511 | $this->trans_enabled = FALSE; 512 | } 513 | 514 | // -------------------------------------------------------------------- 515 | 516 | /** 517 | * Enable/disable Transaction Strict Mode 518 | * When strict mode is enabled, if you are running multiple groups of 519 | * transactions, if one group fails all groups will be rolled back. 520 | * If strict mode is disabled, each group is treated autonomously, meaning 521 | * a failure of one group will not affect any others 522 | * 523 | * @access public 524 | * @return void 525 | */ 526 | function trans_strict($mode = TRUE) 527 | { 528 | $this->trans_strict = is_bool($mode) ? $mode : TRUE; 529 | } 530 | 531 | // -------------------------------------------------------------------- 532 | 533 | /** 534 | * Start Transaction 535 | * 536 | * @access public 537 | * @return void 538 | */ 539 | function trans_start($test_mode = FALSE) 540 | { 541 | if ( ! $this->trans_enabled) 542 | { 543 | return FALSE; 544 | } 545 | 546 | // When transactions are nested we only begin/commit/rollback the outermost ones 547 | if ($this->_trans_depth > 0) 548 | { 549 | $this->_trans_depth += 1; 550 | return; 551 | } 552 | 553 | $this->trans_begin($test_mode); 554 | } 555 | 556 | // -------------------------------------------------------------------- 557 | 558 | /** 559 | * Complete Transaction 560 | * 561 | * @access public 562 | * @return bool 563 | */ 564 | function trans_complete() 565 | { 566 | if ( ! $this->trans_enabled) 567 | { 568 | return FALSE; 569 | } 570 | 571 | // When transactions are nested we only begin/commit/rollback the outermost ones 572 | if ($this->_trans_depth > 1) 573 | { 574 | $this->_trans_depth -= 1; 575 | return TRUE; 576 | } 577 | 578 | // The query() function will set this flag to FALSE in the event that a query failed 579 | if ($this->_trans_status === FALSE) 580 | { 581 | $this->trans_rollback(); 582 | 583 | // If we are NOT running in strict mode, we will reset 584 | // the _trans_status flag so that subsequent groups of transactions 585 | // will be permitted. 586 | if ($this->trans_strict === FALSE) 587 | { 588 | $this->_trans_status = TRUE; 589 | } 590 | 591 | log_message('debug', 'DB Transaction Failure'); 592 | return FALSE; 593 | } 594 | 595 | $this->trans_commit(); 596 | return TRUE; 597 | } 598 | 599 | // -------------------------------------------------------------------- 600 | 601 | /** 602 | * Lets you retrieve the transaction flag to determine if it has failed 603 | * 604 | * @access public 605 | * @return bool 606 | */ 607 | function trans_status() 608 | { 609 | return $this->_trans_status; 610 | } 611 | 612 | // -------------------------------------------------------------------- 613 | 614 | /** 615 | * Compile Bindings 616 | * 617 | * @access public 618 | * @param string the sql statement 619 | * @param array an array of bind data 620 | * @return string 621 | */ 622 | function compile_binds($sql, $binds) 623 | { 624 | if (strpos($sql, $this->bind_marker) === FALSE) 625 | { 626 | return $sql; 627 | } 628 | 629 | if ( ! is_array($binds)) 630 | { 631 | $binds = array($binds); 632 | } 633 | 634 | // Get the sql segments around the bind markers 635 | $segments = explode($this->bind_marker, $sql); 636 | 637 | // The count of bind should be 1 less then the count of segments 638 | // If there are more bind arguments trim it down 639 | if (count($binds) >= count($segments)) { 640 | $binds = array_slice($binds, 0, count($segments)-1); 641 | } 642 | 643 | // Construct the binded query 644 | $result = $segments[0]; 645 | $i = 0; 646 | foreach ($binds as $bind) 647 | { 648 | $result .= $this->escape($bind); 649 | $result .= $segments[++$i]; 650 | } 651 | 652 | return $result; 653 | } 654 | 655 | // -------------------------------------------------------------------- 656 | 657 | /** 658 | * Determines if a query is a "write" type. 659 | * 660 | * @access public 661 | * @param string An SQL query string 662 | * @return boolean 663 | */ 664 | function is_write_type($sql) 665 | { 666 | if ( ! preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD DATA|COPY|ALTER|GRANT|REVOKE|LOCK|UNLOCK)\s+/i', $sql)) 667 | { 668 | return FALSE; 669 | } 670 | return TRUE; 671 | } 672 | 673 | // -------------------------------------------------------------------- 674 | 675 | /** 676 | * Calculate the aggregate query elapsed time 677 | * 678 | * @access public 679 | * @param integer The number of decimal places 680 | * @return integer 681 | */ 682 | function elapsed_time($decimals = 6) 683 | { 684 | return number_format($this->benchmark, $decimals); 685 | } 686 | 687 | // -------------------------------------------------------------------- 688 | 689 | /** 690 | * Returns the total number of queries 691 | * 692 | * @access public 693 | * @return integer 694 | */ 695 | function total_queries() 696 | { 697 | return $this->query_count; 698 | } 699 | 700 | // -------------------------------------------------------------------- 701 | 702 | /** 703 | * Returns the last query that was executed 704 | * 705 | * @access public 706 | * @return void 707 | */ 708 | function last_query() 709 | { 710 | return end($this->queries); 711 | } 712 | 713 | // -------------------------------------------------------------------- 714 | 715 | /** 716 | * "Smart" Escape String 717 | * 718 | * Escapes data based on type 719 | * Sets boolean and null types 720 | * 721 | * @access public 722 | * @param string 723 | * @return mixed 724 | */ 725 | function escape($str) 726 | { 727 | if (is_string($str)) 728 | { 729 | $str = "'".$this->escape_str($str)."'"; 730 | } 731 | elseif (is_bool($str)) 732 | { 733 | $str = ($str === FALSE) ? 0 : 1; 734 | } 735 | elseif (is_null($str)) 736 | { 737 | $str = 'NULL'; 738 | } 739 | 740 | return $str; 741 | } 742 | 743 | // -------------------------------------------------------------------- 744 | 745 | /** 746 | * Escape LIKE String 747 | * 748 | * Calls the individual driver for platform 749 | * specific escaping for LIKE conditions 750 | * 751 | * @access public 752 | * @param string 753 | * @return mixed 754 | */ 755 | function escape_like_str($str) 756 | { 757 | return $this->escape_str($str, TRUE); 758 | } 759 | 760 | // -------------------------------------------------------------------- 761 | 762 | /** 763 | * Primary 764 | * 765 | * Retrieves the primary key. It assumes that the row in the first 766 | * position is the primary key 767 | * 768 | * @access public 769 | * @param string the table name 770 | * @return string 771 | */ 772 | function primary($table = '') 773 | { 774 | $fields = $this->list_fields($table); 775 | 776 | if ( ! is_array($fields)) 777 | { 778 | return FALSE; 779 | } 780 | 781 | return current($fields); 782 | } 783 | 784 | // -------------------------------------------------------------------- 785 | 786 | /** 787 | * Returns an array of table names 788 | * 789 | * @access public 790 | * @return array 791 | */ 792 | function list_tables($constrain_by_prefix = FALSE) 793 | { 794 | // Is there a cached result? 795 | if (isset($this->data_cache['table_names'])) 796 | { 797 | return $this->data_cache['table_names']; 798 | } 799 | 800 | if (FALSE === ($sql = $this->_list_tables($constrain_by_prefix))) 801 | { 802 | if ($this->db_debug) 803 | { 804 | return $this->display_error('db_unsupported_function'); 805 | } 806 | return FALSE; 807 | } 808 | 809 | $retval = array(); 810 | $query = $this->query($sql); 811 | 812 | if ($query->num_rows() > 0) 813 | { 814 | foreach ($query->result_array() as $row) 815 | { 816 | if (isset($row['TABLE_NAME'])) 817 | { 818 | $retval[] = $row['TABLE_NAME']; 819 | } 820 | else 821 | { 822 | $retval[] = array_shift($row); 823 | } 824 | } 825 | } 826 | 827 | $this->data_cache['table_names'] = $retval; 828 | return $this->data_cache['table_names']; 829 | } 830 | 831 | // -------------------------------------------------------------------- 832 | 833 | /** 834 | * Determine if a particular table exists 835 | * @access public 836 | * @return boolean 837 | */ 838 | function table_exists($table_name) 839 | { 840 | return ( ! in_array($this->_protect_identifiers($table_name, TRUE, FALSE, FALSE), $this->list_tables())) ? FALSE : TRUE; 841 | } 842 | 843 | // -------------------------------------------------------------------- 844 | 845 | /** 846 | * Fetch MySQL Field Names 847 | * 848 | * @access public 849 | * @param string the table name 850 | * @return array 851 | */ 852 | function list_fields($table = '') 853 | { 854 | // Is there a cached result? 855 | if (isset($this->data_cache['field_names'][$table])) 856 | { 857 | return $this->data_cache['field_names'][$table]; 858 | } 859 | 860 | if ($table == '') 861 | { 862 | if ($this->db_debug) 863 | { 864 | return $this->display_error('db_field_param_missing'); 865 | } 866 | return FALSE; 867 | } 868 | 869 | if (FALSE === ($sql = $this->_list_columns($table))) 870 | { 871 | if ($this->db_debug) 872 | { 873 | return $this->display_error('db_unsupported_function'); 874 | } 875 | return FALSE; 876 | } 877 | 878 | $query = $this->query($sql); 879 | 880 | $retval = array(); 881 | foreach ($query->result_array() as $row) 882 | { 883 | if (isset($row['COLUMN_NAME'])) 884 | { 885 | $retval[] = $row['COLUMN_NAME']; 886 | } 887 | else 888 | { 889 | $retval[] = current($row); 890 | } 891 | } 892 | 893 | $this->data_cache['field_names'][$table] = $retval; 894 | return $this->data_cache['field_names'][$table]; 895 | } 896 | 897 | // -------------------------------------------------------------------- 898 | 899 | /** 900 | * Determine if a particular field exists 901 | * @access public 902 | * @param string 903 | * @param string 904 | * @return boolean 905 | */ 906 | function field_exists($field_name, $table_name) 907 | { 908 | return ( ! in_array($field_name, $this->list_fields($table_name))) ? FALSE : TRUE; 909 | } 910 | 911 | // -------------------------------------------------------------------- 912 | 913 | /** 914 | * Returns an object with field data 915 | * 916 | * @access public 917 | * @param string the table name 918 | * @return object 919 | */ 920 | function field_data($table = '') 921 | { 922 | if ($table == '') 923 | { 924 | if ($this->db_debug) 925 | { 926 | return $this->display_error('db_field_param_missing'); 927 | } 928 | return FALSE; 929 | } 930 | 931 | $query = $this->query($this->_field_data($this->_protect_identifiers($table, TRUE, NULL, FALSE))); 932 | 933 | return $query->field_data(); 934 | } 935 | 936 | // -------------------------------------------------------------------- 937 | 938 | /** 939 | * Generate an insert string 940 | * 941 | * @access public 942 | * @param string the table upon which the query will be performed 943 | * @param array an associative array data of key/values 944 | * @return string 945 | */ 946 | function insert_string($table, $data) 947 | { 948 | $fields = array(); 949 | $values = array(); 950 | 951 | foreach ($data as $key => $val) 952 | { 953 | $fields[] = $this->_escape_identifiers($key); 954 | $values[] = $this->escape($val); 955 | } 956 | 957 | return $this->_insert($this->_protect_identifiers($table, TRUE, NULL, FALSE), $fields, $values); 958 | } 959 | 960 | // -------------------------------------------------------------------- 961 | 962 | /** 963 | * Generate an update string 964 | * 965 | * @access public 966 | * @param string the table upon which the query will be performed 967 | * @param array an associative array data of key/values 968 | * @param mixed the "where" statement 969 | * @return string 970 | */ 971 | function update_string($table, $data, $where) 972 | { 973 | if ($where == '') 974 | { 975 | return false; 976 | } 977 | 978 | $fields = array(); 979 | foreach ($data as $key => $val) 980 | { 981 | $fields[$this->_protect_identifiers($key)] = $this->escape($val); 982 | } 983 | 984 | if ( ! is_array($where)) 985 | { 986 | $dest = array($where); 987 | } 988 | else 989 | { 990 | $dest = array(); 991 | foreach ($where as $key => $val) 992 | { 993 | $prefix = (count($dest) == 0) ? '' : ' AND '; 994 | 995 | if ($val !== '') 996 | { 997 | if ( ! $this->_has_operator($key)) 998 | { 999 | $key .= ' ='; 1000 | } 1001 | 1002 | $val = ' '.$this->escape($val); 1003 | } 1004 | 1005 | $dest[] = $prefix.$key.$val; 1006 | } 1007 | } 1008 | 1009 | return $this->_update($this->_protect_identifiers($table, TRUE, NULL, FALSE), $fields, $dest); 1010 | } 1011 | 1012 | // -------------------------------------------------------------------- 1013 | 1014 | /** 1015 | * Tests whether the string has an SQL operator 1016 | * 1017 | * @access private 1018 | * @param string 1019 | * @return bool 1020 | */ 1021 | function _has_operator($str) 1022 | { 1023 | $str = trim($str); 1024 | if ( ! preg_match("/(\s|<|>|!|=|is null|is not null)/i", $str)) 1025 | { 1026 | return FALSE; 1027 | } 1028 | 1029 | return TRUE; 1030 | } 1031 | 1032 | // -------------------------------------------------------------------- 1033 | 1034 | /** 1035 | * Enables a native PHP function to be run, using a platform agnostic wrapper. 1036 | * 1037 | * @access public 1038 | * @param string the function name 1039 | * @param mixed any parameters needed by the function 1040 | * @return mixed 1041 | */ 1042 | function call_function($function) 1043 | { 1044 | $driver = ($this->dbdriver == 'postgre') ? 'pg_' : $this->dbdriver.'_'; 1045 | 1046 | if (FALSE === strpos($driver, $function)) 1047 | { 1048 | $function = $driver.$function; 1049 | } 1050 | 1051 | if ( ! function_exists($function)) 1052 | { 1053 | if ($this->db_debug) 1054 | { 1055 | return $this->display_error('db_unsupported_function'); 1056 | } 1057 | return FALSE; 1058 | } 1059 | else 1060 | { 1061 | $args = (func_num_args() > 1) ? array_splice(func_get_args(), 1) : null; 1062 | if (is_null($args)) 1063 | { 1064 | return call_user_func($function); 1065 | } 1066 | else 1067 | { 1068 | return call_user_func_array($function, $args); 1069 | } 1070 | } 1071 | } 1072 | 1073 | // -------------------------------------------------------------------- 1074 | 1075 | /** 1076 | * Set Cache Directory Path 1077 | * 1078 | * @access public 1079 | * @param string the path to the cache directory 1080 | * @return void 1081 | */ 1082 | function cache_set_path($path = '') 1083 | { 1084 | $this->cachedir = $path; 1085 | } 1086 | 1087 | // -------------------------------------------------------------------- 1088 | 1089 | /** 1090 | * Enable Query Caching 1091 | * 1092 | * @access public 1093 | * @return void 1094 | */ 1095 | function cache_on() 1096 | { 1097 | $this->cache_on = TRUE; 1098 | return TRUE; 1099 | } 1100 | 1101 | // -------------------------------------------------------------------- 1102 | 1103 | /** 1104 | * Disable Query Caching 1105 | * 1106 | * @access public 1107 | * @return void 1108 | */ 1109 | function cache_off() 1110 | { 1111 | $this->cache_on = FALSE; 1112 | return FALSE; 1113 | } 1114 | 1115 | 1116 | // -------------------------------------------------------------------- 1117 | 1118 | /** 1119 | * Delete the cache files associated with a particular URI 1120 | * 1121 | * @access public 1122 | * @return void 1123 | */ 1124 | function cache_delete($segment_one = '', $segment_two = '') 1125 | { 1126 | if ( ! $this->_cache_init()) 1127 | { 1128 | return FALSE; 1129 | } 1130 | return $this->CACHE->delete($segment_one, $segment_two); 1131 | } 1132 | 1133 | // -------------------------------------------------------------------- 1134 | 1135 | /** 1136 | * Delete All cache files 1137 | * 1138 | * @access public 1139 | * @return void 1140 | */ 1141 | function cache_delete_all() 1142 | { 1143 | if ( ! $this->_cache_init()) 1144 | { 1145 | return FALSE; 1146 | } 1147 | 1148 | return $this->CACHE->delete_all(); 1149 | } 1150 | 1151 | // -------------------------------------------------------------------- 1152 | 1153 | /** 1154 | * Initialize the Cache Class 1155 | * 1156 | * @access private 1157 | * @return void 1158 | */ 1159 | function _cache_init() 1160 | { 1161 | if (is_object($this->CACHE) AND class_exists('CI_DB_Cache')) 1162 | { 1163 | return TRUE; 1164 | } 1165 | 1166 | if ( ! class_exists('CI_DB_Cache')) 1167 | { 1168 | if ( ! @include(BASEPATH.'database/DB_cache.php')) 1169 | { 1170 | return $this->cache_off(); 1171 | } 1172 | } 1173 | 1174 | $this->CACHE = new CI_DB_Cache($this); // pass db object to support multiple db connections and returned db objects 1175 | return TRUE; 1176 | } 1177 | 1178 | // -------------------------------------------------------------------- 1179 | 1180 | /** 1181 | * Close DB Connection 1182 | * 1183 | * @access public 1184 | * @return void 1185 | */ 1186 | function close() 1187 | { 1188 | if (is_resource($this->conn_id) OR is_object($this->conn_id)) 1189 | { 1190 | $this->_close($this->conn_id); 1191 | } 1192 | $this->conn_id = FALSE; 1193 | 1194 | } 1195 | 1196 | // -------------------------------------------------------------------- 1197 | 1198 | /** 1199 | * Display an error message 1200 | * 1201 | * @access public 1202 | * @param string the error message 1203 | * @param string any "swap" values 1204 | * @param boolean whether to localize the message 1205 | * @return string sends the application/error_db.php template 1206 | */ 1207 | function display_error($error = '', $swap = '', $native = FALSE) 1208 | { 1209 | $LANG =& load_class('Lang', 'core'); 1210 | $LANG->load('db'); 1211 | 1212 | $heading = $LANG->line('db_error_heading'); 1213 | 1214 | if ($native == TRUE) 1215 | { 1216 | $message = $error; 1217 | } 1218 | else 1219 | { 1220 | $message = ( ! is_array($error)) ? array(str_replace('%s', $swap, $LANG->line($error))) : $error; 1221 | } 1222 | 1223 | // Find the most likely culprit of the error by going through 1224 | // the backtrace until the source file is no longer in the 1225 | // database folder. 1226 | 1227 | $trace = debug_backtrace(); 1228 | 1229 | foreach ($trace as $call) 1230 | { 1231 | if (isset($call['file']) && strpos($call['file'], BASEPATH.'database') === FALSE) 1232 | { 1233 | // Found it - use a relative path for safety 1234 | $message[] = 'Filename: '.str_replace(array(BASEPATH, APPPATH), '', $call['file']); 1235 | $message[] = 'Line Number: '.$call['line']; 1236 | 1237 | break; 1238 | } 1239 | } 1240 | 1241 | $error =& load_class('Exceptions', 'core'); 1242 | echo $error->show_error($heading, $message, 'error_db'); 1243 | exit; 1244 | } 1245 | 1246 | // -------------------------------------------------------------------- 1247 | 1248 | /** 1249 | * Protect Identifiers 1250 | * 1251 | * This function adds backticks if appropriate based on db type 1252 | * 1253 | * @access private 1254 | * @param mixed the item to escape 1255 | * @return mixed the item with backticks 1256 | */ 1257 | function protect_identifiers($item, $prefix_single = FALSE) 1258 | { 1259 | return $this->_protect_identifiers($item, $prefix_single); 1260 | } 1261 | 1262 | // -------------------------------------------------------------------- 1263 | 1264 | /** 1265 | * Protect Identifiers 1266 | * 1267 | * This function is used extensively by the Active Record class, and by 1268 | * a couple functions in this class. 1269 | * It takes a column or table name (optionally with an alias) and inserts 1270 | * the table prefix onto it. Some logic is necessary in order to deal with 1271 | * column names that include the path. Consider a query like this: 1272 | * 1273 | * SELECT * FROM hostname.database.table.column AS c FROM hostname.database.table 1274 | * 1275 | * Or a query with aliasing: 1276 | * 1277 | * SELECT m.member_id, m.member_name FROM members AS m 1278 | * 1279 | * Since the column name can include up to four segments (host, DB, table, column) 1280 | * or also have an alias prefix, we need to do a bit of work to figure this out and 1281 | * insert the table prefix (if it exists) in the proper position, and escape only 1282 | * the correct identifiers. 1283 | * 1284 | * @access private 1285 | * @param string 1286 | * @param bool 1287 | * @param mixed 1288 | * @param bool 1289 | * @return string 1290 | */ 1291 | function _protect_identifiers($item, $prefix_single = FALSE, $protect_identifiers = NULL, $field_exists = TRUE) 1292 | { 1293 | if ( ! is_bool($protect_identifiers)) 1294 | { 1295 | $protect_identifiers = $this->_protect_identifiers; 1296 | } 1297 | 1298 | if (is_array($item)) 1299 | { 1300 | $escaped_array = array(); 1301 | 1302 | foreach ($item as $k => $v) 1303 | { 1304 | $escaped_array[$this->_protect_identifiers($k)] = $this->_protect_identifiers($v); 1305 | } 1306 | 1307 | return $escaped_array; 1308 | } 1309 | 1310 | // Convert tabs or multiple spaces into single spaces 1311 | $item = preg_replace('/[\t ]+/', ' ', $item); 1312 | 1313 | // If the item has an alias declaration we remove it and set it aside. 1314 | // Basically we remove everything to the right of the first space 1315 | if (strpos($item, ' ') !== FALSE) 1316 | { 1317 | $alias = strstr($item, ' '); 1318 | $item = substr($item, 0, - strlen($alias)); 1319 | } 1320 | else 1321 | { 1322 | $alias = ''; 1323 | } 1324 | 1325 | // This is basically a bug fix for queries that use MAX, MIN, etc. 1326 | // If a parenthesis is found we know that we do not need to 1327 | // escape the data or add a prefix. There's probably a more graceful 1328 | // way to deal with this, but I'm not thinking of it -- Rick 1329 | if (strpos($item, '(') !== FALSE) 1330 | { 1331 | return $item.$alias; 1332 | } 1333 | 1334 | // Break the string apart if it contains periods, then insert the table prefix 1335 | // in the correct location, assuming the period doesn't indicate that we're dealing 1336 | // with an alias. While we're at it, we will escape the components 1337 | if (strpos($item, '.') !== FALSE) 1338 | { 1339 | $parts = explode('.', $item); 1340 | 1341 | // Does the first segment of the exploded item match 1342 | // one of the aliases previously identified? If so, 1343 | // we have nothing more to do other than escape the item 1344 | if (in_array($parts[0], $this->ar_aliased_tables)) 1345 | { 1346 | if ($protect_identifiers === TRUE) 1347 | { 1348 | foreach ($parts as $key => $val) 1349 | { 1350 | if ( ! in_array($val, $this->_reserved_identifiers)) 1351 | { 1352 | $parts[$key] = $this->_escape_identifiers($val); 1353 | } 1354 | } 1355 | 1356 | $item = implode('.', $parts); 1357 | } 1358 | return $item.$alias; 1359 | } 1360 | 1361 | // Is there a table prefix defined in the config file? If not, no need to do anything 1362 | if ($this->dbprefix != '') 1363 | { 1364 | // We now add the table prefix based on some logic. 1365 | // Do we have 4 segments (hostname.database.table.column)? 1366 | // If so, we add the table prefix to the column name in the 3rd segment. 1367 | if (isset($parts[3])) 1368 | { 1369 | $i = 2; 1370 | } 1371 | // Do we have 3 segments (database.table.column)? 1372 | // If so, we add the table prefix to the column name in 2nd position 1373 | elseif (isset($parts[2])) 1374 | { 1375 | $i = 1; 1376 | } 1377 | // Do we have 2 segments (table.column)? 1378 | // If so, we add the table prefix to the column name in 1st segment 1379 | else 1380 | { 1381 | $i = 0; 1382 | } 1383 | 1384 | // This flag is set when the supplied $item does not contain a field name. 1385 | // This can happen when this function is being called from a JOIN. 1386 | if ($field_exists == FALSE) 1387 | { 1388 | $i++; 1389 | } 1390 | 1391 | // Verify table prefix and replace if necessary 1392 | if ($this->swap_pre != '' && strncmp($parts[$i], $this->swap_pre, strlen($this->swap_pre)) === 0) 1393 | { 1394 | $parts[$i] = preg_replace("/^".$this->swap_pre."(\S+?)/", $this->dbprefix."\\1", $parts[$i]); 1395 | } 1396 | 1397 | // We only add the table prefix if it does not already exist 1398 | if (substr($parts[$i], 0, strlen($this->dbprefix)) != $this->dbprefix) 1399 | { 1400 | $parts[$i] = $this->dbprefix.$parts[$i]; 1401 | } 1402 | 1403 | // Put the parts back together 1404 | $item = implode('.', $parts); 1405 | } 1406 | 1407 | if ($protect_identifiers === TRUE) 1408 | { 1409 | $item = $this->_escape_identifiers($item); 1410 | } 1411 | 1412 | return $item.$alias; 1413 | } 1414 | 1415 | // Is there a table prefix? If not, no need to insert it 1416 | if ($this->dbprefix != '') 1417 | { 1418 | // Verify table prefix and replace if necessary 1419 | if ($this->swap_pre != '' && strncmp($item, $this->swap_pre, strlen($this->swap_pre)) === 0) 1420 | { 1421 | $item = preg_replace("/^".$this->swap_pre."(\S+?)/", $this->dbprefix."\\1", $item); 1422 | } 1423 | 1424 | // Do we prefix an item with no segments? 1425 | if ($prefix_single == TRUE AND substr($item, 0, strlen($this->dbprefix)) != $this->dbprefix) 1426 | { 1427 | $item = $this->dbprefix.$item; 1428 | } 1429 | } 1430 | 1431 | if ($protect_identifiers === TRUE AND ! in_array($item, $this->_reserved_identifiers)) 1432 | { 1433 | $item = $this->_escape_identifiers($item); 1434 | } 1435 | 1436 | return $item.$alias; 1437 | } 1438 | 1439 | // -------------------------------------------------------------------- 1440 | 1441 | /** 1442 | * Dummy method that allows Active Record class to be disabled 1443 | * 1444 | * This function is used extensively by every db driver. 1445 | * 1446 | * @return void 1447 | */ 1448 | protected function _reset_select() 1449 | { 1450 | } 1451 | 1452 | } 1453 | 1454 | /* End of file DB_driver.php */ 1455 | /* Location: ./system/database/DB_driver.php */ -------------------------------------------------------------------------------- /core/database/drivers/mysql/mysql_driver.php: -------------------------------------------------------------------------------- 1 | port != '') 69 | { 70 | $this->hostname .= ':'.$this->port; 71 | } 72 | 73 | $conn_id = @mysql_connect($this->hostname, $this->username, $this->password, TRUE); 74 | //echo date("Y-m-d H:i:s").' --> open host='.$this->hostname.';group_name='.$this->group_name.';conn='.$conn_id."\n"; 75 | return $conn_id; 76 | } 77 | 78 | // -------------------------------------------------------------------- 79 | 80 | /** 81 | * Persistent database connection 82 | * 83 | * @access private called by the base class 84 | * @return resource 85 | */ 86 | function db_pconnect() 87 | { 88 | if ($this->port != '') 89 | { 90 | $this->hostname .= ':'.$this->port; 91 | } 92 | 93 | return @mysql_pconnect($this->hostname, $this->username, $this->password); 94 | } 95 | 96 | // -------------------------------------------------------------------- 97 | 98 | /** 99 | * Reconnect 100 | * 101 | * Keep / reestablish the db connection if no queries have been 102 | * sent for a length of time exceeding the server's idle timeout 103 | * 104 | * @access public 105 | * @return void 106 | */ 107 | function reconnect() 108 | { 109 | if (mysql_ping($this->conn_id) === FALSE) 110 | { 111 | $this->conn_id = FALSE; 112 | } 113 | } 114 | 115 | // -------------------------------------------------------------------- 116 | 117 | /** 118 | * Select the database 119 | * 120 | * @access private called by the base class 121 | * @return resource 122 | */ 123 | function db_select() 124 | { 125 | return @mysql_select_db($this->database, $this->conn_id); 126 | } 127 | 128 | // -------------------------------------------------------------------- 129 | 130 | /** 131 | * Set client character set 132 | * 133 | * @access public 134 | * @param string 135 | * @param string 136 | * @return resource 137 | */ 138 | function db_set_charset($charset, $collation) 139 | { 140 | if ( ! isset($this->use_set_names)) 141 | { 142 | // mysql_set_charset() requires PHP >= 5.2.3 and MySQL >= 5.0.7, use SET NAMES as fallback 143 | $this->use_set_names = (version_compare(PHP_VERSION, '5.2.3', '>=') && version_compare(mysql_get_server_info(), '5.0.7', '>=')) ? FALSE : TRUE; 144 | } 145 | 146 | if ($this->use_set_names === TRUE) 147 | { 148 | return @mysql_query("SET NAMES '".$this->escape_str($charset)."' COLLATE '".$this->escape_str($collation)."'", $this->conn_id); 149 | } 150 | else 151 | { 152 | return @mysql_set_charset($charset, $this->conn_id); 153 | } 154 | } 155 | 156 | // -------------------------------------------------------------------- 157 | 158 | /** 159 | * Version number query string 160 | * 161 | * @access public 162 | * @return string 163 | */ 164 | function _version() 165 | { 166 | return "SELECT version() AS ver"; 167 | } 168 | 169 | // -------------------------------------------------------------------- 170 | 171 | /** 172 | * Execute the query 173 | * 174 | * @access private called by the base class 175 | * @param string an SQL query 176 | * @return resource 177 | */ 178 | function _execute($sql) 179 | { 180 | $sql = $this->_prep_query($sql); 181 | return @mysql_query($sql, $this->conn_id); 182 | } 183 | 184 | // -------------------------------------------------------------------- 185 | 186 | /** 187 | * Prep the query 188 | * 189 | * If needed, each database adapter can prep the query string 190 | * 191 | * @access private called by execute() 192 | * @param string an SQL query 193 | * @return string 194 | */ 195 | function _prep_query($sql) 196 | { 197 | // "DELETE FROM TABLE" returns 0 affected rows This hack modifies 198 | // the query so that it returns the number of affected rows 199 | if ($this->delete_hack === TRUE) 200 | { 201 | if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $sql)) 202 | { 203 | $sql = preg_replace("/^\s*DELETE\s+FROM\s+(\S+)\s*$/", "DELETE FROM \\1 WHERE 1=1", $sql); 204 | } 205 | } 206 | 207 | return $sql; 208 | } 209 | 210 | // -------------------------------------------------------------------- 211 | 212 | /** 213 | * Begin Transaction 214 | * 215 | * @access public 216 | * @return bool 217 | */ 218 | function trans_begin($test_mode = FALSE) 219 | { 220 | if ( ! $this->trans_enabled) 221 | { 222 | return TRUE; 223 | } 224 | 225 | // When transactions are nested we only begin/commit/rollback the outermost ones 226 | if ($this->_trans_depth > 0) 227 | { 228 | return TRUE; 229 | } 230 | 231 | // Reset the transaction failure flag. 232 | // If the $test_mode flag is set to TRUE transactions will be rolled back 233 | // even if the queries produce a successful result. 234 | $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE; 235 | 236 | $this->simple_query('SET AUTOCOMMIT=0'); 237 | $this->simple_query('START TRANSACTION'); // can also be BEGIN or BEGIN WORK 238 | return TRUE; 239 | } 240 | 241 | // -------------------------------------------------------------------- 242 | 243 | /** 244 | * Commit Transaction 245 | * 246 | * @access public 247 | * @return bool 248 | */ 249 | function trans_commit() 250 | { 251 | if ( ! $this->trans_enabled) 252 | { 253 | return TRUE; 254 | } 255 | 256 | // When transactions are nested we only begin/commit/rollback the outermost ones 257 | if ($this->_trans_depth > 0) 258 | { 259 | return TRUE; 260 | } 261 | 262 | $this->simple_query('COMMIT'); 263 | $this->simple_query('SET AUTOCOMMIT=1'); 264 | return TRUE; 265 | } 266 | 267 | // -------------------------------------------------------------------- 268 | 269 | /** 270 | * Rollback Transaction 271 | * 272 | * @access public 273 | * @return bool 274 | */ 275 | function trans_rollback() 276 | { 277 | if ( ! $this->trans_enabled) 278 | { 279 | return TRUE; 280 | } 281 | 282 | // When transactions are nested we only begin/commit/rollback the outermost ones 283 | if ($this->_trans_depth > 0) 284 | { 285 | return TRUE; 286 | } 287 | 288 | $this->simple_query('ROLLBACK'); 289 | $this->simple_query('SET AUTOCOMMIT=1'); 290 | return TRUE; 291 | } 292 | 293 | // -------------------------------------------------------------------- 294 | 295 | /** 296 | * Escape String 297 | * 298 | * @access public 299 | * @param string 300 | * @param bool whether or not the string will be used in a LIKE condition 301 | * @return string 302 | */ 303 | function escape_str($str, $like = FALSE) 304 | { 305 | if (is_array($str)) 306 | { 307 | foreach ($str as $key => $val) 308 | { 309 | $str[$key] = $this->escape_str($val, $like); 310 | } 311 | 312 | return $str; 313 | } 314 | 315 | if (function_exists('mysql_real_escape_string') AND is_resource($this->conn_id)) 316 | { 317 | $str = mysql_real_escape_string($str, $this->conn_id); 318 | } 319 | elseif (function_exists('mysql_escape_string')) 320 | { 321 | //$str = mysql_escape_string($str); 322 | $str = addslashes($str); 323 | } 324 | else 325 | { 326 | $str = addslashes($str); 327 | } 328 | 329 | // escape LIKE condition wildcards 330 | if ($like === TRUE) 331 | { 332 | $str = str_replace(array('%', '_'), array('\\%', '\\_'), $str); 333 | } 334 | 335 | return $str; 336 | } 337 | 338 | // -------------------------------------------------------------------- 339 | 340 | /** 341 | * Affected Rows 342 | * 343 | * @access public 344 | * @return integer 345 | */ 346 | function affected_rows() 347 | { 348 | return @mysql_affected_rows($this->conn_id); 349 | } 350 | 351 | // -------------------------------------------------------------------- 352 | 353 | /** 354 | * Insert ID 355 | * 356 | * @access public 357 | * @return integer 358 | */ 359 | function insert_id() 360 | { 361 | return @mysql_insert_id($this->conn_id); 362 | } 363 | 364 | // -------------------------------------------------------------------- 365 | 366 | /** 367 | * "Count All" query 368 | * 369 | * Generates a platform-specific query string that counts all records in 370 | * the specified database 371 | * 372 | * @access public 373 | * @param string 374 | * @return string 375 | */ 376 | function count_all($table = '') 377 | { 378 | if ($table == '') 379 | { 380 | return 0; 381 | } 382 | 383 | $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE)); 384 | 385 | if ($query->num_rows() == 0) 386 | { 387 | return 0; 388 | } 389 | 390 | $row = $query->row(); 391 | $this->_reset_select(); 392 | return (int) $row->numrows; 393 | } 394 | 395 | // -------------------------------------------------------------------- 396 | 397 | /** 398 | * List table query 399 | * 400 | * Generates a platform-specific query string so that the table names can be fetched 401 | * 402 | * @access private 403 | * @param boolean 404 | * @return string 405 | */ 406 | function _list_tables($prefix_limit = FALSE) 407 | { 408 | $sql = "SHOW TABLES FROM ".$this->_escape_char.$this->database.$this->_escape_char; 409 | 410 | if ($prefix_limit !== FALSE AND $this->dbprefix != '') 411 | { 412 | $sql .= " LIKE '".$this->escape_like_str($this->dbprefix)."%'"; 413 | } 414 | 415 | return $sql; 416 | } 417 | 418 | // -------------------------------------------------------------------- 419 | 420 | /** 421 | * Show column query 422 | * 423 | * Generates a platform-specific query string so that the column names can be fetched 424 | * 425 | * @access public 426 | * @param string the table name 427 | * @return string 428 | */ 429 | function _list_columns($table = '') 430 | { 431 | return "SHOW COLUMNS FROM ".$this->_protect_identifiers($table, TRUE, NULL, FALSE); 432 | } 433 | 434 | // -------------------------------------------------------------------- 435 | 436 | /** 437 | * Field data query 438 | * 439 | * Generates a platform-specific query so that the column data can be retrieved 440 | * 441 | * @access public 442 | * @param string the table name 443 | * @return object 444 | */ 445 | function _field_data($table) 446 | { 447 | return "DESCRIBE ".$table; 448 | } 449 | 450 | // -------------------------------------------------------------------- 451 | 452 | /** 453 | * The error message string 454 | * 455 | * @access private 456 | * @return string 457 | */ 458 | function _error_message() 459 | { 460 | return mysql_error($this->conn_id); 461 | } 462 | 463 | // -------------------------------------------------------------------- 464 | 465 | /** 466 | * The error message number 467 | * 468 | * @access private 469 | * @return integer 470 | */ 471 | function _error_number() 472 | { 473 | return mysql_errno($this->conn_id); 474 | } 475 | 476 | // -------------------------------------------------------------------- 477 | 478 | /** 479 | * Escape the SQL Identifiers 480 | * 481 | * This function escapes column and table names 482 | * 483 | * @access private 484 | * @param string 485 | * @return string 486 | */ 487 | function _escape_identifiers($item) 488 | { 489 | if ($this->_escape_char == '') 490 | { 491 | return $item; 492 | } 493 | 494 | foreach ($this->_reserved_identifiers as $id) 495 | { 496 | if (strpos($item, '.'.$id) !== FALSE) 497 | { 498 | $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item); 499 | 500 | // remove duplicates if the user already included the escape 501 | return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); 502 | } 503 | } 504 | 505 | if (strpos($item, '.') !== FALSE) 506 | { 507 | $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char; 508 | } 509 | else 510 | { 511 | $str = $this->_escape_char.$item.$this->_escape_char; 512 | } 513 | 514 | // remove duplicates if the user already included the escape 515 | return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); 516 | } 517 | 518 | // -------------------------------------------------------------------- 519 | 520 | /** 521 | * From Tables 522 | * 523 | * This function implicitly groups FROM tables so there is no confusion 524 | * about operator precedence in harmony with SQL standards 525 | * 526 | * @access public 527 | * @param type 528 | * @return type 529 | */ 530 | function _from_tables($tables) 531 | { 532 | if ( ! is_array($tables)) 533 | { 534 | $tables = array($tables); 535 | } 536 | 537 | return '('.implode(', ', $tables).')'; 538 | } 539 | 540 | // -------------------------------------------------------------------- 541 | 542 | /** 543 | * Insert statement 544 | * 545 | * Generates a platform-specific insert string from the supplied data 546 | * 547 | * @access public 548 | * @param string the table name 549 | * @param array the insert keys 550 | * @param array the insert values 551 | * @return string 552 | */ 553 | function _insert($table, $keys, $values) 554 | { 555 | return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")"; 556 | } 557 | 558 | // -------------------------------------------------------------------- 559 | 560 | 561 | /** 562 | * Replace statement 563 | * 564 | * Generates a platform-specific replace string from the supplied data 565 | * 566 | * @access public 567 | * @param string the table name 568 | * @param array the insert keys 569 | * @param array the insert values 570 | * @return string 571 | */ 572 | function _replace($table, $keys, $values) 573 | { 574 | return "REPLACE INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")"; 575 | } 576 | 577 | // -------------------------------------------------------------------- 578 | 579 | /** 580 | * Insert_batch statement 581 | * 582 | * Generates a platform-specific insert string from the supplied data 583 | * 584 | * @access public 585 | * @param string the table name 586 | * @param array the insert keys 587 | * @param array the insert values 588 | * @return string 589 | */ 590 | function _insert_batch($table, $keys, $values) 591 | { 592 | return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES ".implode(', ', $values); 593 | } 594 | 595 | // -------------------------------------------------------------------- 596 | 597 | 598 | /** 599 | * Update statement 600 | * 601 | * Generates a platform-specific update string from the supplied data 602 | * 603 | * @access public 604 | * @param string the table name 605 | * @param array the update data 606 | * @param array the where clause 607 | * @param array the orderby clause 608 | * @param array the limit clause 609 | * @return string 610 | */ 611 | function _update($table, $values, $where, $orderby = array(), $limit = FALSE) 612 | { 613 | foreach ($values as $key => $val) 614 | { 615 | $valstr[] = $key . ' = ' . $val; 616 | } 617 | 618 | $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; 619 | 620 | $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):''; 621 | 622 | $sql = "UPDATE ".$table." SET ".implode(', ', $valstr); 623 | 624 | $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : ''; 625 | 626 | $sql .= $orderby.$limit; 627 | 628 | return $sql; 629 | } 630 | 631 | // -------------------------------------------------------------------- 632 | 633 | 634 | /** 635 | * Update_Batch statement 636 | * 637 | * Generates a platform-specific batch update string from the supplied data 638 | * 639 | * @access public 640 | * @param string the table name 641 | * @param array the update data 642 | * @param array the where clause 643 | * @return string 644 | */ 645 | function _update_batch($table, $values, $index, $where = NULL) 646 | { 647 | $ids = array(); 648 | $where = ($where != '' AND count($where) >=1) ? implode(" ", $where).' AND ' : ''; 649 | 650 | foreach ($values as $key => $val) 651 | { 652 | $ids[] = $val[$index]; 653 | 654 | foreach (array_keys($val) as $field) 655 | { 656 | if ($field != $index) 657 | { 658 | $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field]; 659 | } 660 | } 661 | } 662 | 663 | $sql = "UPDATE ".$table." SET "; 664 | $cases = ''; 665 | 666 | foreach ($final as $k => $v) 667 | { 668 | $cases .= $k.' = CASE '."\n"; 669 | foreach ($v as $row) 670 | { 671 | $cases .= $row."\n"; 672 | } 673 | 674 | $cases .= 'ELSE '.$k.' END, '; 675 | } 676 | 677 | $sql .= substr($cases, 0, -2); 678 | 679 | $sql .= ' WHERE '.$where.$index.' IN ('.implode(',', $ids).')'; 680 | 681 | return $sql; 682 | } 683 | 684 | // -------------------------------------------------------------------- 685 | 686 | 687 | /** 688 | * Truncate statement 689 | * 690 | * Generates a platform-specific truncate string from the supplied data 691 | * If the database does not support the truncate() command 692 | * This function maps to "DELETE FROM table" 693 | * 694 | * @access public 695 | * @param string the table name 696 | * @return string 697 | */ 698 | function _truncate($table) 699 | { 700 | return "TRUNCATE ".$table; 701 | } 702 | 703 | // -------------------------------------------------------------------- 704 | 705 | /** 706 | * Delete statement 707 | * 708 | * Generates a platform-specific delete string from the supplied data 709 | * 710 | * @access public 711 | * @param string the table name 712 | * @param array the where clause 713 | * @param string the limit clause 714 | * @return string 715 | */ 716 | function _delete($table, $where = array(), $like = array(), $limit = FALSE) 717 | { 718 | $conditions = ''; 719 | 720 | if (count($where) > 0 OR count($like) > 0) 721 | { 722 | $conditions = "\nWHERE "; 723 | $conditions .= implode("\n", $this->ar_where); 724 | 725 | if (count($where) > 0 && count($like) > 0) 726 | { 727 | $conditions .= " AND "; 728 | } 729 | $conditions .= implode("\n", $like); 730 | } 731 | 732 | $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; 733 | 734 | return "DELETE FROM ".$table.$conditions.$limit; 735 | } 736 | 737 | // -------------------------------------------------------------------- 738 | 739 | /** 740 | * Limit string 741 | * 742 | * Generates a platform-specific LIMIT clause 743 | * 744 | * @access public 745 | * @param string the sql query string 746 | * @param integer the number of rows to limit the query to 747 | * @param integer the offset value 748 | * @return string 749 | */ 750 | function _limit($sql, $limit, $offset) 751 | { 752 | if ($offset == 0) 753 | { 754 | $offset = ''; 755 | } 756 | else 757 | { 758 | $offset .= ", "; 759 | } 760 | 761 | return $sql."LIMIT ".$offset.$limit; 762 | } 763 | 764 | // -------------------------------------------------------------------- 765 | 766 | /** 767 | * Close DB Connection 768 | * 769 | * @access public 770 | * @param resource 771 | * @return void 772 | */ 773 | function _close($conn_id) 774 | { 775 | //echo date("Y-m-d H:i:s").' --> close host='.$this->hostname.';group_name='.$this->group_name.';conn='.$conn_id."\n"; 776 | @mysql_close($conn_id); 777 | } 778 | 779 | } 780 | 781 | 782 | /* End of file mysql_driver.php */ 783 | /* Location: ./system/database/drivers/mysql/mysql_driver.php */ 784 | -------------------------------------------------------------------------------- /helpers/db_proxy_helper.php: -------------------------------------------------------------------------------- 1 | $val) { 19 | if($key == $group_name) { 20 | $db_proxy = true; 21 | $db_master_group = $group_name; 22 | break; 23 | } 24 | foreach($val as $v) { 25 | if($v == $group_name) { 26 | $db_proxy = true; 27 | $db_master_group = $key; 28 | break; 29 | } 30 | } 31 | if($db_proxy == true) { 32 | break; 33 | } 34 | } 35 | if(! $db_proxy) { 36 | return false; 37 | } 38 | if($is_write_query || $force_master) { 39 | return isset($db[$db_master_group]) ? array($db_master_group => $db[$db_master_group]) : false; 40 | } else { 41 | $CI = & get_instance(); 42 | foreach($_master_slave_relation[$db_master_group] as $val) { 43 | if(isset($CI->{'conn_'.$val}) && is_resource($CI->{'conn_'.$val})) { 44 | return array($val => $db[$val]); 45 | } 46 | } 47 | $rand_slave_id = array_rand($_master_slave_relation[$db_master_group]); 48 | $db_slave_group_name = $_master_slave_relation[$db_master_group][$rand_slave_id]; 49 | return isset($db[$db_slave_group_name]) ? array($db_slave_group_name => $db[$db_slave_group_name]) : false; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /libraries/MY_Log.php: -------------------------------------------------------------------------------- 1 | enable) { 13 | return false; 14 | } 15 | if(empty($filename)) { 16 | $filename = $this->filename; 17 | } 18 | $filename = trim($filename, "/"); 19 | if(empty($filename)) { 20 | $filename = 'MY_log-' . date('Y-m-d') . '.php'; 21 | } else { 22 | if(strpos($filename, '/') !== false) { 23 | $folder = $this->_log_path. substr($filename, 0, strrpos($filename, '/') + 1); 24 | if(! is_dir($folder)) { 25 | mkdir($folder, 0777, true); 26 | } 27 | } 28 | if(strtolower(substr($filename, -4)) != '.php') { 29 | $filename .= '-' . date('Y-m-d') . '.php'; 30 | } 31 | } 32 | 33 | $filepath = $this->_log_path . $filename; 34 | $message = ''; 35 | 36 | if(! file_exists($filepath)) { 37 | $message .= "<" . "?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); ?" . ">\n\n"; 38 | } 39 | 40 | if(! $fp = @fopen($filepath, FOPEN_WRITE_CREATE)) { 41 | return false; 42 | } 43 | $message .= date($this->_date_fmt) . ' --> ' . $msg . "\n"; 44 | flock($fp, LOCK_EX); 45 | fwrite($fp, $message); 46 | flock($fp, LOCK_UN); 47 | fclose($fp); 48 | return true; 49 | } 50 | } 51 | // END MY_Log Class 52 | 53 | /* End of file MY_Log.php */ 54 | /* Location: ./application/libraries/MY_Log.php */ -------------------------------------------------------------------------------- /models/test_model.php: -------------------------------------------------------------------------------- 1 |