pquery.sql.php 5.6 KB

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