1<?php 2/** 3 * Zend Framework 4 * 5 * LICENSE 6 * 7 * This source file is subject to the new BSD license that is bundled 8 * with this package in the file LICENSE.txt. 9 * It is also available through the world-wide-web at this URL: 10 * http://framework.zend.com/license/new-bsd 11 * If you did not receive a copy of the license and are unable to 12 * obtain it through the world-wide-web, please send an email 13 * to license@zend.com so we can send you a copy immediately. 14 * 15 * @category Zend 16 * @package Zend_Db 17 * @subpackage Statement 18 * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) 19 * @license http://framework.zend.com/license/new-bsd New BSD License 20 * @version $Id: Mysqli.php 23775 2011-03-01 17:25:24Z ralph $ 21 */ 22 23 24/** 25 * @see Zend_Db_Statement 26 */ 27// require_once 'Zend/Db/Statement.php'; 28 29 30/** 31 * Extends for Mysqli 32 * 33 * @category Zend 34 * @package Zend_Db 35 * @subpackage Statement 36 * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) 37 * @license http://framework.zend.com/license/new-bsd New BSD License 38 */ 39class Zend_Db_Statement_Mysqli extends Zend_Db_Statement 40{ 41 42 /** 43 * Column names. 44 * 45 * @var array 46 */ 47 protected $_keys; 48 49 /** 50 * Fetched result values. 51 * 52 * @var array 53 */ 54 protected $_values; 55 56 /** 57 * @var array 58 */ 59 protected $_meta = null; 60 61 /** 62 * @param string $sql 63 * @return void 64 * @throws Zend_Db_Statement_Mysqli_Exception 65 */ 66 public function _prepare($sql) 67 { 68 $mysqli = $this->_adapter->getConnection(); 69 70 $this->_stmt = $mysqli->prepare($sql); 71 72 if ($this->_stmt === false || $mysqli->errno) { 73 /** 74 * @see Zend_Db_Statement_Mysqli_Exception 75 */ 76 // require_once 'Zend/Db/Statement/Mysqli/Exception.php'; 77 throw new Zend_Db_Statement_Mysqli_Exception("Mysqli prepare error: " . $mysqli->error, $mysqli->errno); 78 } 79 } 80 81 /** 82 * Binds a parameter to the specified variable name. 83 * 84 * @param mixed $parameter Name the parameter, either integer or string. 85 * @param mixed $variable Reference to PHP variable containing the value. 86 * @param mixed $type OPTIONAL Datatype of SQL parameter. 87 * @param mixed $length OPTIONAL Length of SQL parameter. 88 * @param mixed $options OPTIONAL Other options. 89 * @return bool 90 * @throws Zend_Db_Statement_Mysqli_Exception 91 */ 92 protected function _bindParam($parameter, &$variable, $type = null, $length = null, $options = null) 93 { 94 return true; 95 } 96 97 /** 98 * Closes the cursor and the statement. 99 * 100 * @return bool 101 */ 102 public function close() 103 { 104 if ($this->_stmt) { 105 $r = $this->_stmt->close(); 106 $this->_stmt = null; 107 return $r; 108 } 109 return false; 110 } 111 112 /** 113 * Closes the cursor, allowing the statement to be executed again. 114 * 115 * @return bool 116 */ 117 public function closeCursor() 118 { 119 if ($stmt = $this->_stmt) { 120 $mysqli = $this->_adapter->getConnection(); 121 while ($mysqli->more_results()) { 122 $mysqli->next_result(); 123 } 124 $this->_stmt->free_result(); 125 return $this->_stmt->reset(); 126 } 127 return false; 128 } 129 130 /** 131 * Returns the number of columns in the result set. 132 * Returns null if the statement has no result set metadata. 133 * 134 * @return int The number of columns. 135 */ 136 public function columnCount() 137 { 138 if (isset($this->_meta) && $this->_meta) { 139 return $this->_meta->field_count; 140 } 141 return 0; 142 } 143 144 /** 145 * Retrieves the error code, if any, associated with the last operation on 146 * the statement handle. 147 * 148 * @return string error code. 149 */ 150 public function errorCode() 151 { 152 if (!$this->_stmt) { 153 return false; 154 } 155 return substr($this->_stmt->sqlstate, 0, 5); 156 } 157 158 /** 159 * Retrieves an array of error information, if any, associated with the 160 * last operation on the statement handle. 161 * 162 * @return array 163 */ 164 public function errorInfo() 165 { 166 if (!$this->_stmt) { 167 return false; 168 } 169 return array( 170 substr($this->_stmt->sqlstate, 0, 5), 171 $this->_stmt->errno, 172 $this->_stmt->error, 173 ); 174 } 175 176 /** 177 * Executes a prepared statement. 178 * 179 * @param array $params OPTIONAL Values to bind to parameter placeholders. 180 * @return bool 181 * @throws Zend_Db_Statement_Mysqli_Exception 182 */ 183 public function _execute(array $params = null) 184 { 185 if (!$this->_stmt) { 186 return false; 187 } 188 189 // if no params were given as an argument to execute(), 190 // then default to the _bindParam array 191 if ($params === null) { 192 $params = $this->_bindParam; 193 } 194 // send $params as input parameters to the statement 195 if ($params) { 196 array_unshift($params, str_repeat('s', count($params))); 197 $stmtParams = array(); 198 foreach ($params as $k => &$value) { 199 $stmtParams[$k] = &$value; 200 } 201 call_user_func_array( 202 array($this->_stmt, 'bind_param'), 203 $stmtParams 204 ); 205 } 206 207 // execute the statement 208 $retval = $this->_stmt->execute(); 209 if ($retval === false) { 210 /** 211 * @see Zend_Db_Statement_Mysqli_Exception 212 */ 213 // require_once 'Zend/Db/Statement/Mysqli/Exception.php'; 214 throw new Zend_Db_Statement_Mysqli_Exception("Mysqli statement execute error : " . $this->_stmt->error, $this->_stmt->errno); 215 } 216 217 218 // retain metadata 219 if ($this->_meta === null) { 220 $this->_meta = $this->_stmt->result_metadata(); 221 if ($this->_stmt->errno) { 222 /** 223 * @see Zend_Db_Statement_Mysqli_Exception 224 */ 225 // require_once 'Zend/Db/Statement/Mysqli/Exception.php'; 226 throw new Zend_Db_Statement_Mysqli_Exception("Mysqli statement metadata error: " . $this->_stmt->error, $this->_stmt->errno); 227 } 228 } 229 230 // statements that have no result set do not return metadata 231 if ($this->_meta !== false) { 232 233 // get the column names that will result 234 $this->_keys = array(); 235 foreach ($this->_meta->fetch_fields() as $col) { 236 $this->_keys[] = $this->_adapter->foldCase($col->name); 237 } 238 239 // set up a binding space for result variables 240 $this->_values = array_fill(0, count($this->_keys), null); 241 242 // set up references to the result binding space. 243 // just passing $this->_values in the call_user_func_array() 244 // below won't work, you need references. 245 $refs = array(); 246 foreach ($this->_values as $i => &$f) { 247 $refs[$i] = &$f; 248 } 249 250 $this->_stmt->store_result(); 251 // bind to the result variables 252 call_user_func_array( 253 array($this->_stmt, 'bind_result'), 254 $this->_values 255 ); 256 } 257 return $retval; 258 } 259 260 261 /** 262 * Fetches a row from the result set. 263 * 264 * @param int $style OPTIONAL Fetch mode for this fetch operation. 265 * @param int $cursor OPTIONAL Absolute, relative, or other. 266 * @param int $offset OPTIONAL Number for absolute or relative cursors. 267 * @return mixed Array, object, or scalar depending on fetch mode. 268 * @throws Zend_Db_Statement_Mysqli_Exception 269 */ 270 public function fetch($style = null, $cursor = null, $offset = null) 271 { 272 if (!$this->_stmt) { 273 return false; 274 } 275 // fetch the next result 276 $retval = $this->_stmt->fetch(); 277 switch ($retval) { 278 case null: // end of data 279 case false: // error occurred 280 $this->_stmt->reset(); 281 return false; 282 default: 283 // fallthrough 284 } 285 286 // make sure we have a fetch mode 287 if ($style === null) { 288 $style = $this->_fetchMode; 289 } 290 291 // dereference the result values, otherwise things like fetchAll() 292 // return the same values for every entry (because of the reference). 293 $values = array(); 294 foreach ($this->_values as $key => $val) { 295 $values[] = $val; 296 } 297 298 $row = false; 299 switch ($style) { 300 case Zend_Db::FETCH_NUM: 301 $row = $values; 302 break; 303 case Zend_Db::FETCH_ASSOC: 304 $row = array_combine($this->_keys, $values); 305 break; 306 case Zend_Db::FETCH_BOTH: 307 $assoc = array_combine($this->_keys, $values); 308 $row = array_merge($values, $assoc); 309 break; 310 case Zend_Db::FETCH_OBJ: 311 $row = (object) array_combine($this->_keys, $values); 312 break; 313 case Zend_Db::FETCH_BOUND: 314 $assoc = array_combine($this->_keys, $values); 315 $row = array_merge($values, $assoc); 316 return $this->_fetchBound($row); 317 break; 318 default: 319 /** 320 * @see Zend_Db_Statement_Mysqli_Exception 321 */ 322 // require_once 'Zend/Db/Statement/Mysqli/Exception.php'; 323 throw new Zend_Db_Statement_Mysqli_Exception("Invalid fetch mode '$style' specified"); 324 break; 325 } 326 return $row; 327 } 328 329 /** 330 * Retrieves the next rowset (result set) for a SQL statement that has 331 * multiple result sets. An example is a stored procedure that returns 332 * the results of multiple queries. 333 * 334 * @return bool 335 * @throws Zend_Db_Statement_Mysqli_Exception 336 */ 337 public function nextRowset() 338 { 339 /** 340 * @see Zend_Db_Statement_Mysqli_Exception 341 */ 342 // require_once 'Zend/Db/Statement/Mysqli/Exception.php'; 343 throw new Zend_Db_Statement_Mysqli_Exception(__FUNCTION__.'() is not implemented'); 344 } 345 346 /** 347 * Returns the number of rows affected by the execution of the 348 * last INSERT, DELETE, or UPDATE statement executed by this 349 * statement object. 350 * 351 * @return int The number of rows affected. 352 */ 353 public function rowCount() 354 { 355 if (!$this->_adapter) { 356 return false; 357 } 358 $mysqli = $this->_adapter->getConnection(); 359 return $mysqli->affected_rows; 360 } 361 362} 363