Joomla Platform  13.1
Documentation des API du framework Joomla Platform
 Tout Classes Espaces de nommage Fichiers Fonctions Variables Pages
mysql.php
Aller à la documentation de ce fichier.
1 <?php
2 /**
3  * @package Joomla.Platform
4  * @subpackage Database
5  *
6  * @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
7  * @license GNU General Public License version 2 or later; see LICENSE
8  */
9 
10 defined('JPATH_PLATFORM') or die;
11 
12 /**
13  * MySQL database driver
14  *
15  * @package Joomla.Platform
16  * @subpackage Database
17  * @see http://dev.mysql.com/doc/
18  * @since 12.1
19  */
21 {
22  /**
23  * The name of the database driver.
24  *
25  * @var string
26  * @since 12.1
27  */
28  public $name = 'mysql';
29 
30  /**
31  * Constructor.
32  *
33  * @param array $options Array of database options with keys: host, user, password, database, select.
34  *
35  * @since 12.1
36  */
37  public function __construct($options)
38  {
39  // Get some basic values from the options.
40  $options['host'] = (isset($options['host'])) ? $options['host'] : 'localhost';
41  $options['user'] = (isset($options['user'])) ? $options['user'] : 'root';
42  $options['password'] = (isset($options['password'])) ? $options['password'] : '';
43  $options['database'] = (isset($options['database'])) ? $options['database'] : '';
44  $options['select'] = (isset($options['select'])) ? (bool) $options['select'] : true;
45 
46  // Finalize initialisation.
47  parent::__construct($options);
48  }
49 
50  /**
51  * Destructor.
52  *
53  * @since 12.1
54  */
55  public function __destruct()
56  {
57  $this->disconnect();
58  }
59 
60  /**
61  * Connects to the database if needed.
62  *
63  * @return void Returns void if the database connected successfully.
64  *
65  * @since 12.1
66  * @throws RuntimeException
67  */
68  public function connect()
69  {
70  if ($this->connection)
71  {
72  return;
73  }
74 
75  // Make sure the MySQL extension for PHP is installed and enabled.
76  if (!function_exists('mysql_connect'))
77  {
78  throw new RuntimeException('Could not connect to MySQL.');
79  }
80 
81  // Attempt to connect to the server.
82  if (!($this->connection = @ mysql_connect($this->options['host'], $this->options['user'], $this->options['password'], true)))
83  {
84  throw new RuntimeException('Could not connect to MySQL.');
85  }
86 
87  // Set sql_mode to non_strict mode
88  mysql_query("SET @@SESSION.sql_mode = '';", $this->connection);
89 
90  // If auto-select is enabled select the given database.
91  if ($this->options['select'] && !empty($this->options['database']))
92  {
93  $this->select($this->options['database']);
94  }
95 
96  // Set charactersets (needed for MySQL 4.1.2+).
97  $this->setUTF();
98 
99  // Turn MySQL profiling ON in debug mode:
100  if ($this->debug && $this->hasProfiling())
101  {
102  mysql_query("SET profiling = 1;", $this->connection);
103  }
104  }
105 
106  /**
107  * Disconnects the database.
108  *
109  * @return void
110  *
111  * @since 12.1
112  */
113  public function disconnect()
114  {
115  // Close the connection.
116  if (is_resource($this->connection))
117  {
118  foreach ($this->disconnectHandlers as $h)
119  {
120  call_user_func_array($h, array( &$this));
121  }
122 
123  mysql_close($this->connection);
124  }
125 
126  $this->connection = null;
127  }
128 
129  /**
130  * Method to escape a string for usage in an SQL statement.
131  *
132  * @param string $text The string to be escaped.
133  * @param boolean $extra Optional parameter to provide extra escaping.
134  *
135  * @return string The escaped string.
136  *
137  * @since 12.1
138  */
139  public function escape($text, $extra = false)
140  {
141  $this->connect();
142 
143  $result = mysql_real_escape_string($text, $this->getConnection());
144 
145  if ($extra)
146  {
147  $result = addcslashes($result, '%_');
148  }
149 
150  return $result;
151  }
152 
153  /**
154  * Test to see if the MySQL connector is available.
155  *
156  * @return boolean True on success, false otherwise.
157  *
158  * @since 12.1
159  */
160  public static function isSupported()
161  {
162  return (function_exists('mysql_connect'));
163  }
164 
165  /**
166  * Determines if the connection to the server is active.
167  *
168  * @return boolean True if connected to the database engine.
169  *
170  * @since 12.1
171  */
172  public function connected()
173  {
174  if (is_resource($this->connection))
175  {
176  return @mysql_ping($this->connection);
177  }
178 
179  return false;
180  }
181 
182  /**
183  * Get the number of affected rows for the previous executed SQL statement.
184  *
185  * @return integer The number of affected rows.
186  *
187  * @since 12.1
188  */
189  public function getAffectedRows()
190  {
191  $this->connect();
192 
193  return mysql_affected_rows($this->connection);
194  }
195 
196  /**
197  * Get the number of returned rows for the previous executed SQL statement.
198  *
199  * @param resource $cursor An optional database cursor resource to extract the row count from.
200  *
201  * @return integer The number of returned rows.
202  *
203  * @since 12.1
204  */
205  public function getNumRows($cursor = null)
206  {
207  $this->connect();
208 
209  return mysql_num_rows($cursor ? $cursor : $this->cursor);
210  }
211 
212  /**
213  * Get the version of the database connector.
214  *
215  * @return string The database connector version.
216  *
217  * @since 12.1
218  */
219  public function getVersion()
220  {
221  $this->connect();
222 
223  return mysql_get_server_info($this->connection);
224  }
225 
226  /**
227  * Method to get the auto-incremented value from the last INSERT statement.
228  *
229  * @return integer The value of the auto-increment field from the last inserted row.
230  *
231  * @since 12.1
232  */
233  public function insertid()
234  {
235  $this->connect();
236 
237  return mysql_insert_id($this->connection);
238  }
239 
240  /**
241  * Execute the SQL statement.
242  *
243  * @return mixed A database cursor resource on success, boolean false on failure.
244  *
245  * @since 12.1
246  * @throws RuntimeException
247  */
248  public function execute()
249  {
250  $this->connect();
251 
252  if (!is_resource($this->connection))
253  {
254  JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED', $this->errorNum, $this->errorMsg), JLog::ERROR, 'database');
255  throw new RuntimeException($this->errorMsg, $this->errorNum);
256  }
257 
258  // Take a local copy so that we don't modify the original query and cause issues later
259  $query = $this->replacePrefix((string) $this->sql);
260 
261  if (!($this->sql instanceof JDatabaseQuery) && ($this->limit > 0 || $this->offset > 0))
262  {
263  $query .= ' LIMIT ' . $this->offset . ', ' . $this->limit;
264  }
265 
266  // Increment the query counter.
267  $this->count++;
268 
269  // Reset the error values.
270  $this->errorNum = 0;
271  $this->errorMsg = '';
272 
273  // If debugging is enabled then let's log the query.
274  if ($this->debug)
275  {
276  // Add the query to the object queue.
277  $this->log[] = $query;
278 
279  JLog::add($query, JLog::DEBUG, 'databasequery');
280 
281  $this->timings[] = microtime(true);
282  }
283 
284  // Execute the query. Error suppression is used here to prevent warnings/notices that the connection has been lost.
285  $this->cursor = @mysql_query($query, $this->connection);
286 
287  if ($this->debug)
288  {
289  $this->timings[] = microtime(true);
290 
291  if (defined('DEBUG_BACKTRACE_IGNORE_ARGS'))
292  {
293  $this->callStacks[] = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
294  }
295  else
296  {
297  $this->callStacks[] = debug_backtrace();
298  }
299  }
300 
301  // If an error occurred handle it.
302  if (!$this->cursor)
303  {
304  // Check if the server was disconnected.
305  if (!$this->connected())
306  {
307  try
308  {
309  // Attempt to reconnect.
310  $this->connection = null;
311  $this->connect();
312  }
313  // If connect fails, ignore that exception and throw the normal exception.
314  catch (RuntimeException $e)
315  {
316  // Get the error number and message.
317  $this->errorNum = (int) mysql_errno($this->connection);
318  $this->errorMsg = (string) mysql_error($this->connection) . ' SQL=' . $query;
319 
320  // Throw the normal query exception.
321  JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED', $this->errorNum, $this->errorMsg), JLog::ERROR, 'databasequery');
322  throw new RuntimeException($this->errorMsg, $this->errorNum);
323  }
324 
325  // Since we were able to reconnect, run the query again.
326  return $this->execute();
327  }
328  // The server was not disconnected.
329  else
330  {
331  // Get the error number and message.
332  $this->errorNum = (int) mysql_errno($this->connection);
333  $this->errorMsg = (string) mysql_error($this->connection) . ' SQL=' . $query;
334 
335  // Throw the normal query exception.
336  JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED', $this->errorNum, $this->errorMsg), JLog::ERROR, 'databasequery');
337  throw new RuntimeException($this->errorMsg, $this->errorNum);
338  }
339  }
340 
341  return $this->cursor;
342  }
343 
344  /**
345  * Select a database for use.
346  *
347  * @param string $database The name of the database to select for use.
348  *
349  * @return boolean True if the database was successfully selected.
350  *
351  * @since 12.1
352  * @throws RuntimeException
353  */
354  public function select($database)
355  {
356  $this->connect();
357 
358  if (!$database)
359  {
360  return false;
361  }
362 
363  if (!mysql_select_db($database, $this->connection))
364  {
365  throw new RuntimeException('Could not connect to database');
366  }
367 
368  return true;
369  }
370 
371  /**
372  * Set the connection to use UTF-8 character encoding.
373  *
374  * @return boolean True on success.
375  *
376  * @since 12.1
377  */
378  public function setUTF()
379  {
380  $this->connect();
381 
382  return mysql_set_charset('utf8', $this->connection);
383  }
384 
385  /**
386  * Method to fetch a row from the result set cursor as an array.
387  *
388  * @param mixed $cursor The optional result set cursor from which to fetch the row.
389  *
390  * @return mixed Either the next row from the result set or false if there are no more rows.
391  *
392  * @since 12.1
393  */
394  protected function fetchArray($cursor = null)
395  {
396  return mysql_fetch_row($cursor ? $cursor : $this->cursor);
397  }
398 
399  /**
400  * Method to fetch a row from the result set cursor as an associative array.
401  *
402  * @param mixed $cursor The optional result set cursor from which to fetch the row.
403  *
404  * @return mixed Either the next row from the result set or false if there are no more rows.
405  *
406  * @since 12.1
407  */
408  protected function fetchAssoc($cursor = null)
409  {
410  return mysql_fetch_assoc($cursor ? $cursor : $this->cursor);
411  }
412 
413  /**
414  * Method to fetch a row from the result set cursor as an object.
415  *
416  * @param mixed $cursor The optional result set cursor from which to fetch the row.
417  * @param string $class The class name to use for the returned row object.
418  *
419  * @return mixed Either the next row from the result set or false if there are no more rows.
420  *
421  * @since 12.1
422  */
423  protected function fetchObject($cursor = null, $class = 'stdClass')
424  {
425  return mysql_fetch_object($cursor ? $cursor : $this->cursor, $class);
426  }
427 
428  /**
429  * Method to free up the memory used for the result set.
430  *
431  * @param mixed $cursor The optional result set cursor from which to fetch the row.
432  *
433  * @return void
434  *
435  * @since 12.1
436  */
437  protected function freeResult($cursor = null)
438  {
439  mysql_free_result($cursor ? $cursor : $this->cursor);
440  }
441 
442  /**
443  * Internal function to check if profiling is available
444  *
445  * @return boolean
446  *
447  * @since 3.1.3
448  */
449  private function hasProfiling()
450  {
451  try
452  {
453  $res = mysql_query("SHOW VARIABLES LIKE 'have_profiling'", $this->connection);
454  $row = mysql_fetch_assoc($res);
455 
456  return isset($row);
457  }
458  catch (Exception $e)
459  {
460  return false;
461  }
462  }
463 }