Make WordPress Core

Ticket #6305: wp-db.2.php

File wp-db.2.php, 18.0 KB (added by westi, 18 years ago)

Update wp-db.php to not ping if the reconnect fails

Line 
1<?php
2//  WordPress DB Class
3
4//  ORIGINAL CODE FROM:
5//  Justin Vincent (justin@visunet.ie)
6//      http://php.justinvincent.com
7
8define('EZSQL_VERSION', 'WP1.25');
9define('OBJECT', 'OBJECT', true);
10define('OBJECT_K', 'OBJECT_K', false);
11define('ARRAY_A', 'ARRAY_A', false);
12define('ARRAY_N', 'ARRAY_N', false);
13
14if (!defined('SAVEQUERIES'))
15        define('SAVEQUERIES', false);
16
17class wpdb {
18
19        var $show_errors = false;
20        var $suppress_errors = false;
21        var $last_error = '';
22        var $num_queries = 0;
23        var $last_query;
24        var $col_info;
25        var $queries;
26        var $prefix = '';
27        var $ready = false;
28
29        // Our tables
30        var $posts;
31        var $users;
32        var $categories;
33        var $post2cat;
34        var $comments;
35        var $links;
36        var $options;
37        var $postmeta;
38        var $usermeta;
39        var $terms;
40        var $term_taxonomy;
41        var $term_relationships;
42        var $tables = array('users', 'usermeta', 'posts', 'categories', 'post2cat', 'comments', 'links', 'link2cat', 'options',
43                        'postmeta', 'terms', 'term_taxonomy', 'term_relationships');
44        var $charset;
45        var $collate;
46        var $db_user;
47        var $db_password;
48        var $db_name;
49        var $db_host;
50
51        /**
52         * Connects to the database server and selects a database
53         * @param string $dbuser
54         * @param string $dbpassword
55         * @param string $dbname
56         * @param string $dbhost
57         */
58        function wpdb($dbuser, $dbpassword, $dbname, $dbhost) {
59                return $this->__construct($dbuser, $dbpassword, $dbname, $dbhost);
60        }
61
62        function __construct($dbuser, $dbpassword, $dbname, $dbhost) {
63                register_shutdown_function(array(&$this, "__destruct"));
64
65                if ( defined('WP_DEBUG') and WP_DEBUG == true )
66                        $this->show_errors();
67
68                if ( defined('DB_CHARSET') )
69                        $this->charset = DB_CHARSET;
70
71                if ( defined('DB_COLLATE') )
72                        $this->collate = DB_COLLATE;
73
74                $this->db_user = $dbuser;
75                $this->db_password = $dbpassword;
76                $this->db_name = $dbname;
77                $this->db_host = $dbhost;
78
79                $this->connect_to_db();
80        }
81
82        function __destruct() {
83                return true;
84        }
85
86        function connect_to_db() {
87                $this->dbh = @mysql_connect($this->db_host, $this->db_user, $this->db_password, true);
88                if ( !$this->dbh ) {
89                        $this->bail("
90<h1>Error establishing a database connection</h1>
91<p>This either means that the username and password information in your <code>wp-config.php</code> file is incorrect or we can't contact the database server at <code>$dbhost</code>. This could mean your host's database server is down.</p>
92<ul>
93        <li>Are you sure you have the correct username and password?</li>
94        <li>Are you sure that you have typed the correct hostname?</li>
95        <li>Are you sure that the database server is running?</li>
96</ul>
97<p>If you're unsure what these terms mean you should probably contact your host. If you still need help you can always visit the <a href='http://wordpress.org/support/'>WordPress Support Forums</a>.</p>
98");
99                        return;
100                }
101
102                $this->ready = true;
103
104                if ( !empty($this->charset) && version_compare(mysql_get_server_info($this->dbh), '4.1.0', '>=') )
105                        $this->query("SET NAMES '$this->charset'");
106
107                $this->select($this->db_name);
108        }
109
110        function check_connection() {
111                $maxcount = 2;
112                $count = 0;
113
114                $ping = mysql_ping( $this->dbh ) ;
115
116                while ( !$ping && $count < $maxcount ) {
117                        @mysql_close($this->dbh);
118                        sleep(2);
119                        if ($this->connect_to_db() )
120                        {
121                                $ping = mysql_ping( $this->dbh ) ;
122
123                                if ( $ping )
124                                        break;
125                        }
126                        sleep(2);
127                        $count++;
128                }
129
130                if ( !$ping )
131                        $this->bail('Lost connection to server');
132        }
133 
134        function set_prefix($prefix) {
135
136                if ( preg_match('|[^a-z0-9_]|i', $prefix) )
137                        return new WP_Error('invalid_db_prefix', 'Invalid database prefix'); // No gettext here
138
139                $old_prefix = $this->prefix;
140                $this->prefix = $prefix;
141
142                foreach ( $this->tables as $table )
143                        $this->$table = $this->prefix . $table;
144
145                if ( defined('CUSTOM_USER_TABLE') )
146                        $this->users = CUSTOM_USER_TABLE;
147
148                if ( defined('CUSTOM_USER_META_TABLE') )
149                        $this->usermeta = CUSTOM_USER_META_TABLE;
150
151                return $old_prefix;
152        }
153
154        /**
155         * Selects a database using the current class's $this->dbh
156         * @param string $db name
157         */
158        function select($db) {
159                if (!@mysql_select_db($db, $this->dbh)) {
160                        $this->ready = false;
161                        $this->bail("
162<h1>Can&#8217;t select database</h1>
163<p>We were able to connect to the database server (which means your username and password is okay) but not able to select the <code>$db</code> database.</p>
164<ul>
165<li>Are you sure it exists?</li>
166<li>Does the user <code>".DB_USER."</code> have permission to use the <code>$db</code> database?</li>
167<li>On some systems the name of your database is prefixed with your username, so it would be like username_wordpress. Could that be the problem?</li>
168</ul>
169<p>If you don't know how to setup a database you should <strong>contact your host</strong>. If all else fails you may find help at the <a href='http://wordpress.org/support/'>WordPress Support Forums</a>.</p>");
170                        return;
171                }
172        }
173
174        /**
175         * Escapes content for insertion into the database, for security
176         *
177         * @param string $string
178         * @return string query safe string
179         */
180        function escape($string) {
181                return addslashes( $string );
182                // Disable rest for now, causing problems
183                /*
184                if( !$this->dbh || version_compare( phpversion(), '4.3.0' ) == '-1' )
185                        return mysql_escape_string( $string );
186                else
187                        return mysql_real_escape_string( $string, $this->dbh );
188                */
189        }
190
191        /**
192         * Escapes content by reference for insertion into the database, for security
193         * @param string $s
194         */
195        function escape_by_ref(&$s) {
196                $s = $this->escape($s);
197        }
198
199        /**
200         * Prepares a SQL query for safe use, using sprintf() syntax
201         */
202        function prepare($args=NULL) {
203                if ( NULL === $args )
204                        return;
205                $args = func_get_args();
206                $query = array_shift($args);
207                $query = str_replace("'%s'", '%s', $query); // in case someone mistakenly already singlequoted it
208                $query = str_replace('"%s"', '%s', $query); // doublequote unquoting
209                $query = str_replace('%s', "'%s'", $query); // quote the strings
210                array_walk($args, array(&$this, 'escape_by_ref'));
211                return @vsprintf($query, $args);
212        }
213
214        // ==================================================================
215        //      Print SQL/DB error.
216
217        function print_error($str = '') {
218                global $EZSQL_ERROR;
219
220                if (!$str) $str = mysql_error($this->dbh);
221                $EZSQL_ERROR[] =
222                array ('query' => $this->last_query, 'error_str' => $str);
223
224                if ( $this->suppress_errors )
225                        return false;
226
227                $error_str = "WordPress database error $str for query $this->last_query";
228                if ( $caller = $this->get_caller() )
229                        $error_str .= " made by $caller";
230
231                $log_error = true;
232                if ( ! function_exists('error_log') )
233                        $log_error = false;
234
235                $log_file = @ini_get('error_log');
236                if ( !empty($log_file) && ('syslog' != $log_file) && !is_writable($log_file) )
237                        $log_error = false;
238
239                if ( $log_error )
240                        @error_log($error_str, 0);
241
242                // Is error output turned on or not..
243                if ( !$this->show_errors )
244                        return false;
245
246                $str = htmlspecialchars($str, ENT_QUOTES);
247                $query = htmlspecialchars($this->last_query, ENT_QUOTES);
248
249                // If there is an error then take note of it
250                print "<div id='error'>
251                <p class='wpdberror'><strong>WordPress database error:</strong> [$str]<br />
252                <code>$query</code></p>
253                </div>";
254        }
255
256        // ==================================================================
257        //      Turn error handling on or off..
258
259        function show_errors( $show = true ) {
260                $errors = $this->show_errors;
261                $this->show_errors = $show;
262                return $errors;
263        }
264
265        function hide_errors() {
266                $show = $this->show_errors;
267                $this->show_errors = false;
268                return $show;
269        }
270
271        function suppress_errors( $suppress = true ) {
272                $errors = $this->suppress_errors;
273                $this->suppress_errors = $suppress;
274                return $errors;
275        }
276
277        // ==================================================================
278        //      Kill cached query results
279
280        function flush() {
281                $this->last_result = array();
282                $this->col_info = null;
283                $this->last_query = null;
284        }
285
286        // ==================================================================
287        //      Basic Query     - see docs for more detail
288
289        function query($query) {
290                if ( ! $this->ready )
291                        return false;
292
293                // filter the query, if filters are available
294                // NOTE: some queries are made before the plugins have been loaded, and thus cannot be filtered with this method
295                if ( function_exists('apply_filters') )
296                        $query = apply_filters('query', $query);
297
298                // initialise return
299                $return_val = 0;
300                $this->flush();
301
302                // Log how the function was called
303                $this->func_call = "\$db->query(\"$query\")";
304
305                // Keep track of the last query for debug..
306                $this->last_query = $query;
307
308                // Perform the query via std mysql_query function..
309                if (SAVEQUERIES)
310                        $this->timer_start();
311
312                $this->result = @mysql_query($query, $this->dbh);
313                ++$this->num_queries;
314
315                if (SAVEQUERIES)
316                        $this->queries[] = array( $query, $this->timer_stop(), $this->get_caller() );
317
318                // If there is an error then take note of it..
319                if ( $this->last_error = mysql_error($this->dbh) ) {
320                        $errno = mysql_errno();
321                        if ( 2006 == $errno || 2013 == $errno ) {
322                                $this->check_connection();
323                                $this->result = @mysql_query($query, $this->dbh);
324                                if ( $this->last_error = mysql_error($this->dbh) ) {
325                                        $this->print_error();
326                                        return false;
327                                }
328                        } else {
329                                $this->print_error();
330                                return false;
331                        }
332                }
333
334                if ( preg_match("/^\\s*(insert|delete|update|replace) /i",$query) ) {
335                        $this->rows_affected = mysql_affected_rows($this->dbh);
336                        // Take note of the insert_id
337                        if ( preg_match("/^\\s*(insert|replace) /i",$query) ) {
338                                $this->insert_id = mysql_insert_id($this->dbh);
339                        }
340                        // Return number of rows affected
341                        $return_val = $this->rows_affected;
342                } else {
343                        $i = 0;
344                        while ($i < @mysql_num_fields($this->result)) {
345                                $this->col_info[$i] = @mysql_fetch_field($this->result);
346                                $i++;
347                        }
348                        $num_rows = 0;
349                        while ( $row = @mysql_fetch_object($this->result) ) {
350                                $this->last_result[$num_rows] = $row;
351                                $num_rows++;
352                        }
353
354                        @mysql_free_result($this->result);
355
356                        // Log number of rows the query returned
357                        $this->num_rows = $num_rows;
358
359                        // Return number of rows selected
360                        $return_val = $this->num_rows;
361                }
362
363                return $return_val;
364        }
365
366        /**
367         * Insert an array of data into a table
368         * @param string $table WARNING: not sanitized!
369         * @param array $data should not already be SQL-escaped
370         * @return mixed results of $this->query()
371         */
372        function insert($table, $data) {
373                $data = add_magic_quotes($data);
374                $fields = array_keys($data);
375                return $this->query("INSERT INTO $table (`" . implode('`,`',$fields) . "`) VALUES ('".implode("','",$data)."')");
376        }
377
378        /**
379         * Update a row in the table with an array of data
380         * @param string $table WARNING: not sanitized!
381         * @param array $data should not already be SQL-escaped
382         * @param array $where a named array of WHERE column => value relationships.  Multiple member pairs will be joined with ANDs.  WARNING: the column names are not currently sanitized!
383         * @return mixed results of $this->query()
384         */
385        function update($table, $data, $where){
386                $data = add_magic_quotes($data);
387                $bits = $wheres = array();
388                foreach ( array_keys($data) as $k )
389                        $bits[] = "`$k` = '$data[$k]'";
390
391                if ( is_array( $where ) )
392                        foreach ( $where as $c => $v )
393                                $wheres[] = "$c = '" . $this->escape( $v ) . "'";
394                else
395                        return false;
396                return $this->query( "UPDATE $table SET " . implode( ', ', $bits ) . ' WHERE ' . implode( ' AND ', $wheres ) . ' LIMIT 1' );
397        }
398
399        /**
400         * Get one variable from the database
401         * @param string $query (can be null as well, for caching, see codex)
402         * @param int $x = 0 row num to return
403         * @param int $y = 0 col num to return
404         * @return mixed results
405         */
406        function get_var($query=null, $x = 0, $y = 0) {
407                $this->func_call = "\$db->get_var(\"$query\",$x,$y)";
408                if ( $query )
409                        $this->query($query);
410
411                // Extract var out of cached results based x,y vals
412                if ( !empty( $this->last_result[$y] ) ) {
413                        $values = array_values(get_object_vars($this->last_result[$y]));
414                }
415
416                // If there is a value return it else return null
417                return (isset($values[$x]) && $values[$x]!=='') ? $values[$x] : null;
418        }
419
420        /**
421         * Get one row from the database
422         * @param string $query
423         * @param string $output ARRAY_A | ARRAY_N | OBJECT
424         * @param int $y row num to return
425         * @return mixed results
426         */
427        function get_row($query = null, $output = OBJECT, $y = 0) {
428                $this->func_call = "\$db->get_row(\"$query\",$output,$y)";
429                if ( $query )
430                        $this->query($query);
431                else
432                        return null;
433
434                if ( !isset($this->last_result[$y]) )
435                        return null;
436
437                if ( $output == OBJECT ) {
438                        return $this->last_result[$y] ? $this->last_result[$y] : null;
439                } elseif ( $output == ARRAY_A ) {
440                        return $this->last_result[$y] ? get_object_vars($this->last_result[$y]) : null;
441                } elseif ( $output == ARRAY_N ) {
442                        return $this->last_result[$y] ? array_values(get_object_vars($this->last_result[$y])) : null;
443                } else {
444                        $this->print_error(" \$db->get_row(string query, output type, int offset) -- Output type must be one of: OBJECT, ARRAY_A, ARRAY_N");
445                }
446        }
447
448        /**
449         * Gets one column from the database
450         * @param string $query (can be null as well, for caching, see codex)
451         * @param int $x col num to return
452         * @return array results
453         */
454        function get_col($query = null , $x = 0) {
455                if ( $query )
456                        $this->query($query);
457
458                $new_array = array();
459                // Extract the column values
460                for ( $i=0; $i < count($this->last_result); $i++ ) {
461                        $new_array[$i] = $this->get_var(null, $x, $i);
462                }
463                return $new_array;
464        }
465
466        /**
467         * Return an entire result set from the database
468         * @param string $query (can also be null to pull from the cache)
469         * @param string $output ARRAY_A | ARRAY_N | OBJECT_K | OBJECT
470         * @return mixed results
471         */
472        function get_results($query = null, $output = OBJECT) {
473                $this->func_call = "\$db->get_results(\"$query\", $output)";
474
475                if ( $query )
476                        $this->query($query);
477                else
478                        return null;
479
480                if ( $output == OBJECT ) {
481                        // Return an integer-keyed array of row objects
482                        return $this->last_result;
483                } elseif ( $output == OBJECT_K ) {
484                        // Return an array of row objects with keys from column 1
485                        // (Duplicates are discarded)
486                        foreach ( $this->last_result as $row ) {
487                                $key = array_shift( get_object_vars( $row ) );
488                                if ( !isset( $new_array[ $key ] ) )
489                                        $new_array[ $key ] = $row;
490                        }
491                        return $new_array;
492                } elseif ( $output == ARRAY_A || $output == ARRAY_N ) {
493                        // Return an integer-keyed array of...
494                        if ( $this->last_result ) {
495                                $i = 0;
496                                foreach( $this->last_result as $row ) {
497                                        if ( $output == ARRAY_N ) {
498                                                // ...integer-keyed row arrays
499                                                $new_array[$i] = array_values( get_object_vars( $row ) );
500                                        } else {
501                                                // ...column name-keyed row arrays
502                                                $new_array[$i] = get_object_vars( $row );
503                                        }
504                                        ++$i;
505                                }
506                                return $new_array;
507                        }
508                }
509        }
510
511        /**
512         * Grabs column metadata from the last query
513         * @param string $info_type one of name, table, def, max_length, not_null, primary_key, multiple_key, unique_key, numeric, blob, type, unsigned, zerofill
514         * @param int $col_offset 0: col name. 1: which table the col's in. 2: col's max length. 3: if the col is numeric. 4: col's type
515         * @return mixed results
516         */
517        function get_col_info($info_type = 'name', $col_offset = -1) {
518                if ( $this->col_info ) {
519                        if ( $col_offset == -1 ) {
520                                $i = 0;
521                                foreach($this->col_info as $col ) {
522                                        $new_array[$i] = $col->{$info_type};
523                                        $i++;
524                                }
525                                return $new_array;
526                        } else {
527                                return $this->col_info[$col_offset]->{$info_type};
528                        }
529                }
530        }
531
532        /**
533         * Starts the timer, for debugging purposes
534         */
535        function timer_start() {
536                $mtime = microtime();
537                $mtime = explode(' ', $mtime);
538                $this->time_start = $mtime[1] + $mtime[0];
539                return true;
540        }
541
542        /**
543         * Stops the debugging timer
544         * @return int total time spent on the query, in milliseconds
545         */
546        function timer_stop() {
547                $mtime = microtime();
548                $mtime = explode(' ', $mtime);
549                $time_end = $mtime[1] + $mtime[0];
550                $time_total = $time_end - $this->time_start;
551                return $time_total;
552        }
553
554        /**
555         * Wraps fatal errors in a nice header and footer and dies.
556         * @param string $message
557         */
558        function bail($message) { // Just wraps errors in a nice header and footer
559                if ( !$this->show_errors ) {
560                        if ( class_exists('WP_Error') )
561                                $this->error = new WP_Error('500', $message);
562                        else
563                                $this->error = $message;
564                        return false;
565                }
566                wp_die($message);
567        }
568
569        /**
570         * Checks wether of not the database version is high enough to support the features WordPress uses
571         * @global $wp_version
572         */
573        function check_database_version()
574        {
575                global $wp_version;
576                // Make sure the server has MySQL 4.0
577                $mysql_version = preg_replace('|[^0-9\.]|', '', @mysql_get_server_info($this->dbh));
578                if ( version_compare($mysql_version, '4.0.0', '<') )
579                        return new WP_Error('database_version',sprintf(__('<strong>ERROR</strong>: WordPress %s requires MySQL 4.0.0 or higher'), $wp_version));
580        }
581
582        /**
583         * This function is called when WordPress is generating the table schema to determine wether or not the current database
584         * supports or needs the collation statements.
585         */
586        function supports_collation()
587        {
588                return ( version_compare(mysql_get_server_info($this->dbh), '4.1.0', '>=') );
589        }
590
591        /**
592         * Get the name of the function that called wpdb.
593         * @return string the name of the calling function
594         */
595        function get_caller() {
596                // requires PHP 4.3+
597                if ( !is_callable('debug_backtrace') )
598                        return '';
599
600                $bt = debug_backtrace();
601                $caller = '';
602
603                foreach ( $bt as $trace ) {
604                        if ( @$trace['class'] == __CLASS__ )
605                                continue;
606                        elseif ( strtolower(@$trace['function']) == 'call_user_func_array' )
607                                continue;
608                        elseif ( strtolower(@$trace['function']) == 'apply_filters' )
609                                continue;
610                        elseif ( strtolower(@$trace['function']) == 'do_action' )
611                                continue;
612
613                        $caller = $trace['function'];
614                        break;
615                }
616                return $caller;
617        }
618
619}
620
621if ( ! isset($wpdb) )
622        $wpdb = new wpdb(DB_USER, DB_PASSWORD, DB_NAME, DB_HOST);
623?>