PageRenderTime 47ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/library/Zend/Db/Statement.php

https://bitbucket.org/Ebozavrik/test-application
PHP | 508 lines | 219 code | 49 blank | 240 comment | 37 complexity | 5361c7eefdff6e0ed55aa92256471003 MD5 | raw file
  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-2012 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @version $Id: Statement.php 24790 2012-05-10 12:28:51Z mcleod@spaceweb.nl $
  21. */
  22. /**
  23. * @see Zend_Db
  24. */
  25. require_once 'Zend/Db.php';
  26. /**
  27. * @see Zend_Db_Statement_Interface
  28. */
  29. require_once 'Zend/Db/Statement/Interface.php';
  30. /**
  31. * Abstract class to emulate a PDOStatement for native database adapters.
  32. *
  33. * @category Zend
  34. * @package Zend_Db
  35. * @subpackage Statement
  36. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  37. * @license http://framework.zend.com/license/new-bsd New BSD License
  38. */
  39. abstract class Zend_Db_Statement implements Zend_Db_Statement_Interface
  40. {
  41. /**
  42. * @var resource|object The driver level statement object/resource
  43. */
  44. protected $_stmt = null;
  45. /**
  46. * @var Zend_Db_Adapter_Abstract
  47. */
  48. protected $_adapter = null;
  49. /**
  50. * The current fetch mode.
  51. *
  52. * @var integer
  53. */
  54. protected $_fetchMode = Zend_Db::FETCH_ASSOC;
  55. /**
  56. * Attributes.
  57. *
  58. * @var array
  59. */
  60. protected $_attribute = array();
  61. /**
  62. * Column result bindings.
  63. *
  64. * @var array
  65. */
  66. protected $_bindColumn = array();
  67. /**
  68. * Query parameter bindings; covers bindParam() and bindValue().
  69. *
  70. * @var array
  71. */
  72. protected $_bindParam = array();
  73. /**
  74. * SQL string split into an array at placeholders.
  75. *
  76. * @var array
  77. */
  78. protected $_sqlSplit = array();
  79. /**
  80. * Parameter placeholders in the SQL string by position in the split array.
  81. *
  82. * @var array
  83. */
  84. protected $_sqlParam = array();
  85. /**
  86. * @var Zend_Db_Profiler_Query
  87. */
  88. protected $_queryId = null;
  89. /**
  90. * Constructor for a statement.
  91. *
  92. * @param Zend_Db_Adapter_Abstract $adapter
  93. * @param mixed $sql Either a string or Zend_Db_Select.
  94. */
  95. public function __construct ($adapter, $sql)
  96. {
  97. $this->_adapter = $adapter;
  98. if ($sql instanceof Zend_Db_Select) {
  99. $sql = $sql->assemble();
  100. }
  101. $this->_parseParameters($sql);
  102. $this->_prepare($sql);
  103. $this->_queryId = $this->_adapter->getProfiler()->queryStart($sql);
  104. }
  105. /**
  106. * Internal method called by abstract statment constructor to setup
  107. * the driver level statement
  108. *
  109. * @return void
  110. */
  111. protected function _prepare ($sql)
  112. {
  113. return;
  114. }
  115. /**
  116. * @param string $sql
  117. *
  118. * @return void
  119. */
  120. protected function _parseParameters ($sql)
  121. {
  122. $sql = $this->_stripQuoted($sql);
  123. // split into text and params
  124. $this->_sqlSplit = preg_split('/(\?|\:[a-zA-Z0-9_]+)/',
  125. $sql, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
  126. // map params
  127. $this->_sqlParam = array();
  128. foreach ($this->_sqlSplit as $key => $val) {
  129. if ($val == '?') {
  130. if ($this->_adapter->supportsParameters('positional') === false) {
  131. /**
  132. * @see Zend_Db_Statement_Exception
  133. */
  134. require_once 'Zend/Db/Statement/Exception.php';
  135. throw new Zend_Db_Statement_Exception( "Invalid bind-variable position '$val'" );
  136. }
  137. } else if ($val[0] == ':') {
  138. if ($this->_adapter->supportsParameters('named') === false) {
  139. /**
  140. * @see Zend_Db_Statement_Exception
  141. */
  142. require_once 'Zend/Db/Statement/Exception.php';
  143. throw new Zend_Db_Statement_Exception( "Invalid bind-variable name '$val'" );
  144. }
  145. }
  146. $this->_sqlParam[] = $val;
  147. }
  148. // set up for binding
  149. $this->_bindParam = array();
  150. }
  151. /**
  152. * Remove parts of a SQL string that contain quoted strings
  153. * of values or identifiers.
  154. *
  155. * @param string $sql
  156. *
  157. * @return string
  158. */
  159. protected function _stripQuoted ($sql)
  160. {
  161. // get the character for value quoting
  162. // this should be '
  163. $q = $this->_adapter->quote('a');
  164. $q = $q[0];
  165. // get the value used as an escaped quote,
  166. // e.g. \' or ''
  167. $qe = $this->_adapter->quote($q);
  168. $qe = substr($qe, 1, 2);
  169. $qe = preg_quote($qe);
  170. $escapeChar = substr($qe, 0, 1);
  171. // remove 'foo\'bar'
  172. if (!empty( $q )) {
  173. $escapeChar = preg_quote($escapeChar);
  174. // this segfaults only after 65,000 characters instead of 9,000
  175. $sql = preg_replace("/$q([^$q{$escapeChar}]*|($qe)*)*$q/s", '', $sql);
  176. }
  177. // get a version of the SQL statement with all quoted
  178. // values and delimited identifiers stripped out
  179. // remove "foo\"bar"
  180. $sql = preg_replace("/\"(\\\\\"|[^\"])*\"/Us", '', $sql);
  181. // get the character for delimited id quotes,
  182. // this is usually " but in MySQL is `
  183. $d = $this->_adapter->quoteIdentifier('a');
  184. $d = $d[0];
  185. // get the value used as an escaped delimited id quote,
  186. // e.g. \" or "" or \`
  187. $de = $this->_adapter->quoteIdentifier($d);
  188. $de = substr($de, 1, 2);
  189. $de = preg_quote($de);
  190. // Note: $de and $d where never used..., now they are:
  191. $sql = preg_replace("/$d($de|\\\\{2}|[^$d])*$d/Us", '', $sql);
  192. return $sql;
  193. }
  194. /**
  195. * Bind a column of the statement result set to a PHP variable.
  196. *
  197. * @param string $column Name the column in the result set, either by
  198. * position or by name.
  199. * @param mixed $param Reference to the PHP variable containing the value.
  200. * @param mixed $type OPTIONAL
  201. *
  202. * @return bool
  203. */
  204. public function bindColumn ($column, &$param, $type = null)
  205. {
  206. $this->_bindColumn[$column] =& $param;
  207. return true;
  208. }
  209. /**
  210. * Binds a parameter to the specified variable name.
  211. *
  212. * @param mixed $parameter Name the parameter, either integer or string.
  213. * @param mixed $variable Reference to PHP variable containing the value.
  214. * @param mixed $type OPTIONAL Datatype of SQL parameter.
  215. * @param mixed $length OPTIONAL Length of SQL parameter.
  216. * @param mixed $options OPTIONAL Other options.
  217. *
  218. * @return bool
  219. */
  220. public function bindParam ($parameter, &$variable, $type = null, $length = null, $options = null)
  221. {
  222. if (!is_int($parameter) && !is_string($parameter)) {
  223. /**
  224. * @see Zend_Db_Statement_Exception
  225. */
  226. require_once 'Zend/Db/Statement/Exception.php';
  227. throw new Zend_Db_Statement_Exception( 'Invalid bind-variable position' );
  228. }
  229. $position = null;
  230. if (( $intval = (int)$parameter ) > 0 && $this->_adapter->supportsParameters('positional')) {
  231. if ($intval >= 1 || $intval <= count($this->_sqlParam)) {
  232. $position = $intval;
  233. }
  234. } else if ($this->_adapter->supportsParameters('named')) {
  235. if ($parameter[0] != ':') {
  236. $parameter = ':' . $parameter;
  237. }
  238. if (in_array($parameter, $this->_sqlParam) !== false) {
  239. $position = $parameter;
  240. }
  241. }
  242. if ($position === null) {
  243. /**
  244. * @see Zend_Db_Statement_Exception
  245. */
  246. require_once 'Zend/Db/Statement/Exception.php';
  247. throw new Zend_Db_Statement_Exception( "Invalid bind-variable position '$parameter'" );
  248. }
  249. // Finally we are assured that $position is valid
  250. $this->_bindParam[$position] =& $variable;
  251. return $this->_bindParam($position, $variable, $type, $length, $options);
  252. }
  253. /**
  254. * Binds a value to a parameter.
  255. *
  256. * @param mixed $parameter Name the parameter, either integer or string.
  257. * @param mixed $value Scalar value to bind to the parameter.
  258. * @param mixed $type OPTIONAL Datatype of the parameter.
  259. *
  260. * @return bool
  261. */
  262. public function bindValue ($parameter, $value, $type = null)
  263. {
  264. return $this->bindParam($parameter, $value, $type);
  265. }
  266. /**
  267. * Executes a prepared statement.
  268. *
  269. * @param array $params OPTIONAL Values to bind to parameter placeholders.
  270. *
  271. * @return bool
  272. */
  273. public function execute (array $params = null)
  274. {
  275. /*
  276. * Simple case - no query profiler to manage.
  277. */
  278. if ($this->_queryId === null) {
  279. return $this->_execute($params);
  280. }
  281. /*
  282. * Do the same thing, but with query profiler
  283. * management before and after the execute.
  284. */
  285. $prof = $this->_adapter->getProfiler();
  286. $qp = $prof->getQueryProfile($this->_queryId);
  287. if ($qp->hasEnded()) {
  288. $this->_queryId = $prof->queryClone($qp);
  289. $qp = $prof->getQueryProfile($this->_queryId);
  290. }
  291. if ($params !== null) {
  292. $qp->bindParams($params);
  293. } else {
  294. $qp->bindParams($this->_bindParam);
  295. }
  296. $qp->start($this->_queryId);
  297. $retval = $this->_execute($params);
  298. $prof->queryEnd($this->_queryId);
  299. return $retval;
  300. }
  301. /**
  302. * Returns an array containing all of the result set rows.
  303. *
  304. * @param int $style OPTIONAL Fetch mode.
  305. * @param int $col OPTIONAL Column number, if fetch mode is by column.
  306. *
  307. * @return array Collection of rows, each in a format by the fetch mode.
  308. */
  309. public function fetchAll ($style = null, $col = null)
  310. {
  311. $data = array();
  312. if ($style === Zend_Db::FETCH_COLUMN && $col === null) {
  313. $col = 0;
  314. }
  315. if ($col === null) {
  316. while ($row = $this->fetch($style)) {
  317. $data[] = $row;
  318. }
  319. } else {
  320. while (false !== ( $val = $this->fetchColumn($col) )) {
  321. $data[] = $val;
  322. }
  323. }
  324. return $data;
  325. }
  326. /**
  327. * Returns a single column from the next row of a result set.
  328. *
  329. * @param int $col OPTIONAL Position of the column to fetch.
  330. *
  331. * @return string One value from the next row of result set, or false.
  332. */
  333. public function fetchColumn ($col = 0)
  334. {
  335. $data = array();
  336. $col = (int)$col;
  337. $row = $this->fetch(Zend_Db::FETCH_NUM);
  338. if (!is_array($row)) {
  339. return false;
  340. }
  341. return $row[$col];
  342. }
  343. /**
  344. * Fetches the next row and returns it as an object.
  345. *
  346. * @param string $class OPTIONAL Name of the class to create.
  347. * @param array $config OPTIONAL Constructor arguments for the class.
  348. *
  349. * @return mixed One object instance of the specified class, or false.
  350. */
  351. public function fetchObject ($class = 'stdClass', array $config = array())
  352. {
  353. $obj = new $class( $config );
  354. $row = $this->fetch(Zend_Db::FETCH_ASSOC);
  355. if (!is_array($row)) {
  356. return false;
  357. }
  358. foreach ($row as $key => $val) {
  359. $obj->$key = $val;
  360. }
  361. return $obj;
  362. }
  363. /**
  364. * Retrieve a statement attribute.
  365. *
  366. * @param string $key Attribute name.
  367. *
  368. * @return mixed Attribute value.
  369. */
  370. public function getAttribute ($key)
  371. {
  372. if (array_key_exists($key, $this->_attribute)) {
  373. return $this->_attribute[$key];
  374. }
  375. }
  376. /**
  377. * Set a statement attribute.
  378. *
  379. * @param string $key Attribute name.
  380. * @param mixed $val Attribute value.
  381. *
  382. * @return bool
  383. */
  384. public function setAttribute ($key, $val)
  385. {
  386. $this->_attribute[$key] = $val;
  387. }
  388. /**
  389. * Set the default fetch mode for this statement.
  390. *
  391. * @param int $mode The fetch mode.
  392. *
  393. * @return bool
  394. * @throws Zend_Db_Statement_Exception
  395. */
  396. public function setFetchMode ($mode)
  397. {
  398. switch ($mode) {
  399. case Zend_Db::FETCH_NUM:
  400. case Zend_Db::FETCH_ASSOC:
  401. case Zend_Db::FETCH_BOTH:
  402. case Zend_Db::FETCH_OBJ:
  403. $this->_fetchMode = $mode;
  404. break;
  405. case Zend_Db::FETCH_BOUND:
  406. default:
  407. $this->closeCursor();
  408. /**
  409. * @see Zend_Db_Statement_Exception
  410. */
  411. require_once 'Zend/Db/Statement/Exception.php';
  412. throw new Zend_Db_Statement_Exception( 'invalid fetch mode' );
  413. break;
  414. }
  415. }
  416. /**
  417. * Helper function to map retrieved row
  418. * to bound column variables
  419. *
  420. * @param array $row
  421. *
  422. * @return bool True
  423. */
  424. public function _fetchBound ($row)
  425. {
  426. foreach ($row as $key => $value) {
  427. // bindColumn() takes 1-based integer positions
  428. // but fetch() returns 0-based integer indexes
  429. if (is_int($key)) {
  430. $key++;
  431. }
  432. // set results only to variables that were bound previously
  433. if (isset( $this->_bindColumn[$key] )) {
  434. $this->_bindColumn[$key] = $value;
  435. }
  436. }
  437. return true;
  438. }
  439. /**
  440. * Gets the Zend_Db_Adapter_Abstract for this
  441. * particular Zend_Db_Statement object.
  442. *
  443. * @return Zend_Db_Adapter_Abstract
  444. */
  445. public function getAdapter ()
  446. {
  447. return $this->_adapter;
  448. }
  449. /**
  450. * Gets the resource or object setup by the
  451. * _parse
  452. * @return unknown_type
  453. */
  454. public function getDriverStatement ()
  455. {
  456. return $this->_stmt;
  457. }
  458. }