pquery.sql.php 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. <?php
  2. /**
  3. * pQuery plugin for executing MySQL queries.
  4. *
  5. * @package pQuery
  6. */
  7. /**
  8. * @todo Documentation
  9. * @property $query Alias for {@link pQuery::variable}.
  10. */
  11. class pQuerySql extends pQuery implements pQueryExtension {
  12. const VARIABLE_PATTERN = '/\[\s*%s\s*\]/';
  13. static $accepts = array('string' => 'parse_query', 'resource');
  14. /**
  15. * The MySQL link identifier.
  16. *
  17. * @var resource
  18. */
  19. static $link;
  20. /**
  21. * The result of the current query.
  22. *
  23. * @var resource|bool
  24. */
  25. var $result;
  26. /**
  27. * Indicates whether the query has been executed yet.
  28. *
  29. * @var bool
  30. */
  31. var $executed;
  32. /**
  33. * Parse the given query string.
  34. */
  35. function parse_query() {
  36. $args = $this->arguments;
  37. if( !count($args) )
  38. return;
  39. // Replace variable indices by names equal to their indices
  40. if( !is_array($args[0]) )
  41. array_unshift($args, null);
  42. // Replace variables by their escaped values
  43. $this->set($args);
  44. }
  45. /**
  46. * Replace a set of variables with their (optionally escaped)
  47. * values in the current query.
  48. *
  49. * @param array $variables The variables to replace.
  50. * @param bool $escape Whether to escape the variable values.
  51. * @returns pQuerySql The current query object.
  52. */
  53. function replace_variables($variables, $escape) {
  54. $patterns = array_map('pQuerySql::variable_pattern', array_keys($variables));
  55. $escape && $variables = array_map('pQuerySql::escape', $variables);
  56. $this->variable = preg_replace($patterns, $variables, $this->variable);
  57. $this->executed = false;
  58. return $this;
  59. }
  60. /**
  61. * Replace a set of variables with their escaped values in the current query.
  62. *
  63. * @param array $variables The variables to replace.
  64. * @returns pQuerySql The current query object.
  65. */
  66. function set($variables) {
  67. return $this->replace_variables($variables, true);
  68. }
  69. /**
  70. * Replace a set of variables with their non-escaped values in the current query.
  71. *
  72. * @param array $variables The variables to replace.
  73. * @returns pQuerySql The current query object.
  74. */
  75. function set_plain($variables) {
  76. return $this->replace_variables($variables, false);
  77. }
  78. /**
  79. * Transform a variable name to a regex to be used as a replacement
  80. * pattern in a query.
  81. *
  82. * @param string $name The variable name to transform.
  83. * @returns string The variable's replacement pattern.
  84. */
  85. static function variable_pattern($name) {
  86. return sprintf(self::VARIABLE_PATTERN, $name);
  87. }
  88. /**
  89. * Execute the current query.
  90. *
  91. * @returns pQuerySql The current query object.
  92. */
  93. function execute() {
  94. self::assert_connection();
  95. //debug('query:', $this->query);
  96. $result = mysql_query($this->query, self::$link);
  97. if( !$result )
  98. return self::mysql_error();
  99. $this->result = $result;
  100. $this->executed = true;
  101. return $this;
  102. }
  103. /**
  104. * Fetch a row from the current result.
  105. *
  106. * @param string $type The format of the result row.
  107. * @returns mixed The fetched row in the requested format.
  108. */
  109. function fetch($type) {
  110. $this->assert_execution();
  111. if( !$this->result )
  112. return self::error('No valid result to fetch from.');
  113. $func = 'mysql_fetch_'.$type;
  114. if( !function_exists($func) )
  115. return self::error('Fetch type "%s" is not supported.', $type);
  116. return $func($this->result);
  117. }
  118. /**
  119. * Fetch all rows from the current result.
  120. *
  121. * @param string $type The format of the result rows.
  122. * @returns array The result set.
  123. */
  124. function fetch_all($type) {
  125. $results = array();
  126. while( ($row = $this->fetch($type)) !== false ) {
  127. $results[] = $row;
  128. }
  129. return $results;
  130. return $func($this->result);
  131. }
  132. /**
  133. * Getter for property 'query'.
  134. */
  135. function __get($name) {
  136. if( $name == 'query' )
  137. return $this->variable;
  138. }
  139. /**
  140. * Setter for property 'query'.
  141. */
  142. function __set($name, $value) {
  143. if( $name == 'query' )
  144. $this->variable = $value;
  145. }
  146. /**
  147. * Assert that the current query has been executed.
  148. */
  149. function assert_execution() {
  150. $this->executed || $this->execute();
  151. }
  152. /**
  153. * Assert that the MySQL connection is opened.
  154. *
  155. * @uses mysql_connect,mysql_select_db
  156. */
  157. static function assert_connection() {
  158. // Return if the connection has already been opened
  159. if( self::$link )
  160. return;
  161. if( !isset(Config::$sql) )
  162. return self::error('Could not connect to database: no MySQL config found.');
  163. // Connect to the database
  164. $c = Config::$sql;
  165. $link = @mysql_connect($c['host'], $c['username'], $c['password']);
  166. if( $link === false )
  167. return self::mysql_error();
  168. self::$link = $link;
  169. // Select the correct database
  170. if( !@mysql_select_db($c['dbname'], $link) )
  171. return self::mysql_error();
  172. }
  173. /**
  174. * Echo the latest MySQL error.
  175. */
  176. static function mysql_error() {
  177. self::error('MySQL error %d: %s.', mysql_errno(), mysql_error());
  178. }
  179. /**
  180. * Extention of {@link pQuery::error}, returning FALSE (useful in result loops).
  181. * Also, the current query is printed in DEBUG mode.
  182. *
  183. * @returns bool FALSE
  184. */
  185. static function error() {
  186. parent::error('MySQL error %d: %s.', mysql_errno(), mysql_error());
  187. if( DEBUG )
  188. echo $this->query;
  189. return false;
  190. }
  191. /**
  192. * Escape a string for safe use in a query.
  193. *
  194. * @param string $value The string to escape.
  195. * @uses mysql_real_escape_string
  196. */
  197. static function escape($value) {
  198. self::assert_connection();
  199. return mysql_real_escape_string($value, self::$link);
  200. }
  201. }
  202. /**
  203. * Shortcut constructor for {@link pQuerySql}.
  204. *
  205. * @returns pQuerySql A new pQuerySql instance.
  206. * @see pQuerySql::__construct
  207. */
  208. function _sql($query /* [ , $arg1, ... ] */) {
  209. $args = func_get_args();
  210. $query = array_shift($args);
  211. array_unshift($args, 'pQuerySql', $query);
  212. return call_user_func_array('pQuery::create', $args);
  213. }
  214. pQuery::extend('pQuerySql', 'sql');
  215. ?>