1<?php 2/** 3 * A Horde_Injector:: based factory for creating Horde_Db_Adapter objects. 4 * 5 * PHP version 5 6 * 7 * @category Horde 8 * @package Core 9 * @author Michael Slusarz <slusarz@horde.org> 10 * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 11 */ 12 13/** 14 * A Horde_Injector:: based factory for creating Horde_Db_Adapter objects. 15 * 16 * Copyright 2010-2017 Horde LLC (http://www.horde.org/) 17 * 18 * See the enclosed file COPYING for license information (LGPL). If you 19 * did not receive this file, see http://www.horde.org/licenses/lgpl21. 20 * 21 * @category Horde 22 * @package Core 23 * @author Michael Slusarz <slusarz@horde.org> 24 * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 25 */ 26class Horde_Core_Factory_Db extends Horde_Core_Factory_Base 27{ 28 /** 29 * Instances. 30 * 31 * @var array 32 */ 33 private $_instances = array(); 34 35 /** 36 * Returns the DB instance. 37 * 38 * @param string $app The application. 39 * @param string|array $backend The backend, see Horde::getDriverConfig(). 40 * If this is an array, this is used as the 41 * configuration array. 42 * 43 * @return Horde_Db_Adapter The singleton instance. 44 * @throws Horde_Exception 45 * @throws Horde_Db_Exception 46 */ 47 public function create($app = 'horde', $backend = null) 48 { 49 global $registry; 50 51 $pushed = ($app == 'horde') 52 ? false 53 : $registry->pushApp($app); 54 55 $config = is_array($backend) 56 ? $backend 57 : $this->getConfig($backend); 58 59 /* Prevent DSN from getting polluted (this only applies to non-custom 60 * auth type connections. All other custom sql configurations MUST be 61 * cleansed prior to passing to the factory (at least until Horde 5). 62 * @todo Fix with Horde 6. */ 63 if (!is_array($backend) && ($backend == 'auth')) { 64 unset( 65 $config['count_bad_logins'], 66 $config['cyradmin'], 67 $config['cyrhost'], 68 $config['cyrpass'], 69 $config['cyrport'], 70 $config['domain_field'], 71 $config['driverconfig'], 72 $config['encryption'], 73 $config['folders'], 74 $config['hidden_accounts'], 75 $config['login_block'], 76 $config['login_block_count'], 77 $config['login_block_time'], 78 $config['password_field'], 79 $config['query_auth'], 80 $config['query_add'], 81 $config['query_getpw'], 82 $config['query_update'], 83 $config['query_resetpassword'], 84 $config['query_remove'], 85 $config['query_list'], 86 $config['query_exists'], 87 $config['show_encryption'], 88 $config['table'], 89 $config['userhierarchy'], 90 $config['username_field'] 91 ); 92 } 93 unset($config['umask']); 94 95 $e = null; 96 97 ksort($config); 98 $sig = hash('md5', serialize($config)); 99 100 /* Determine if we are using the base SQL config. */ 101 if (isset($config['driverconfig']) && 102 ($config['driverconfig'] == 'horde')) { 103 $this->_instances[$sig] = $this->create(); 104 } elseif (!isset($this->_instances[$sig])) { 105 try { 106 $this->_createDb($config, $sig); 107 } catch (Horde_Exception $e) {} 108 } 109 110 if ($pushed) { 111 $registry->popApp(); 112 } 113 114 if ($e) { 115 throw $e; 116 } 117 118 return $this->_instances[$sig]; 119 } 120 121 /** 122 */ 123 public function getConfig($backend) 124 { 125 return Horde::getDriverConfig($backend, 'sql'); 126 } 127 128 /** 129 */ 130 public function createDb($config) 131 { 132 return $this->_createDb($config); 133 } 134 135 /** 136 * @param string $sig Save instance under this signature key. 137 * @param boolean $cache Add default cache to driver? 138 */ 139 protected function _createDb($config, $sig = null, $cache = true) 140 { 141 unset($config['driverconfig']); 142 $logqueries = !empty($config['logqueries']); 143 unset($config['logqueries']); 144 145 // Split read? 146 if (!empty($config['splitread'])) { 147 $read_config = $config['read']; 148 unset($config['read'], $config['splitread']); 149 $ob = new Horde_Db_Adapter_SplitRead( 150 $this->_createDb(array_merge($config, $read_config), null, false), 151 $this->_createDb($config, null, false) 152 ); 153 154 /* Don't attach logger to base split read object. */ 155 $config['logger'] = true; 156 } else { 157 if (isset($config['adapter'])) { 158 $class = $this->_getDriverName($config['adapter'], 'Horde_Db_Adapter'); 159 unset($config['adapter']); 160 } elseif (empty($config['phptype'])) { 161 throw new Horde_Exception('The database configuration is missing.'); 162 } else { 163 switch ($config['phptype']) { 164 case 'mysqli': 165 $class = 'Horde_Db_Adapter_Mysqli'; 166 break; 167 168 case 'mysql': 169 $class = extension_loaded('pdo_mysql') 170 ? 'Horde_Db_Adapter_Pdo_Mysql' 171 : 'Horde_Db_Adapter_Mysql'; 172 break; 173 174 case 'oci8': 175 $class = 'Horde_Db_Adapter_Oci8'; 176 break; 177 178 default: 179 $class = 'Horde_Db_Adapter_Pdo_' . Horde_String::ucfirst($config['phptype']); 180 break; 181 } 182 } 183 184 if (!empty($config['hostspec'])) { 185 $config['host'] = $config['hostspec']; 186 unset($config['hostspec']); 187 } 188 189 $ob = new $class($config); 190 } 191 192 if ($sig) { 193 $this->_instances[$sig] = $ob; 194 } 195 196 if ($cache && !isset($config['cache'])) { 197 /* Need to add cache ob here, after it is stored as an instance, 198 * or else we enter infinite bootstrapping loop. Bug #13439 */ 199 $ob->setCache($this->_injector->getInstance('Horde_Cache')); 200 } 201 202 /* Bug #13463: setting logger before cache causes intermittent issues 203 * with DB object during session shutdown. */ 204 if (!isset($config['logger'])) { 205 $ob->setLogger( 206 $this->_injector->getInstance('Horde_Log_Logger'), 207 $logqueries 208 ); 209 } 210 211 return $ob; 212 } 213 214} 215