source: trunk/lib/DB.inc.php @ 156

Last change on this file since 156 was 156, checked in by scdev, 18 years ago

Q - Renamed tags/2.0 to 2.0.0 to indicate 2.0 "release", branched tags/2.0.1 to branches/2.0 to function as maintainanse branch for 2.0.* releases

File size: 10.9 KB
Line 
1<?php
2/**
3 * DB.inc.php
4 * code by strangecode :: www.strangecode.com :: this document contains copyrighted information
5 *
6 * Very lightweight DB semi-abstraction layer. Mainly to catch errors with mysql_query, with some goodies.
7 *
8 * @author  Quinn Comendant <quinn@strangecode.com>
9 * @version 2.1
10 */
11
12class DB {
13
14    // If $db->connect has successfully opened a db connection.
15    var $_connected = false;
16
17    // Database handle.
18    var $dbh;
19
20    // Hash of DB parameters.
21    var $_params = array();
22
23    // Default parameters.
24    var $_param_defaults = array(
25
26        // DB passwords should be set as apache environment variables in httpd.conf, readable only by root.
27        'db_server' => 'localhost',
28        'db_name' => null,
29        'db_user' => null,
30        'db_pass' => null,
31
32        // Display all SQL queries.
33        'db_always_debug' => false,
34
35        // Display db errors.
36        'db_debug' => false,
37       
38        // Script stops on db error.
39        'db_die_on_failure' => false,
40    );
41
42    // Translate between HTML and MySQL character set names.
43    var $mysql_character_sets = array(
44        'utf-8' => 'utf8',
45        'iso-8859-1' => 'latin1',
46    );
47
48    // Caches.
49    var $existing_tables;
50    var $table_columns;
51
52    /**
53     * This method enforces the singleton pattern for this class.
54     *
55     * @return  object  Reference to the global DB object.
56     * @access  public
57     * @static
58     */
59    function &getInstance()
60    {
61        static $instance = null;
62
63        if ($instance === null) {
64            $instance = new DB();
65        }
66
67        return $instance;
68    }
69
70    /**
71     * Set (or overwrite existing) parameters by passing an array of new parameters.
72     *
73     * @access public
74     *
75     * @param  array    $params     Array of parameters (key => val pairs).
76     */
77    function setParam($params)
78    {
79        $app =& App::getInstance();
80   
81        if (isset($params) && is_array($params)) {
82            // Merge new parameters with old overriding only those passed.
83            $this->_params = array_merge($this->_params, $params);
84        } else {
85            $app->logMsg(sprintf('Parameters are not an array: %s', $params), LOG_ERR, __FILE__, __LINE__);
86        }
87    }
88
89    /**
90     * Return the value of a parameter, if it exists.
91     *
92     * @access public
93     * @param string $param        Which parameter to return.
94     * @return mixed               Configured parameter value.
95     */
96    function getParam($param)
97    {
98        $app =& App::getInstance();
99   
100        if (isset($this->_params[$param])) {
101            return $this->_params[$param];
102        } else {
103            $app->logMsg(sprintf('Parameter is not set: %s', $param), LOG_DEBUG, __FILE__, __LINE__);
104            return null;
105        }
106    }
107
108    /**
109     * Connect to database with credentials in params.
110     *
111     * @access  public
112     * @author  Quinn Comendant <quinn@strangecode.com>
113     * @since   28 Aug 2005 14:02:49
114     */
115    function connect()
116    {
117        $app =& App::getInstance();
118   
119        if (!$this->getParam('db_name') || !$this->getParam('db_user') || !$this->getParam('db_pass')) {
120            $app->logMsg('Database credentials missing.', LOG_EMERG, __FILE__, __LINE__);
121            return false;
122        }
123
124        // Connect to database. Always create a new link to the server.
125        if ($this->dbh = mysql_connect($this->getParam('db_server'), $this->getParam('db_user'), $this->getParam('db_pass'), true)) {
126            // Select database
127            mysql_select_db($this->getParam('db_name'), $this->dbh);
128        }
129
130        // Test for connection errors.
131        if (!$this->dbh || mysql_error($this->dbh)) {
132            $mysql_error_msg = $this->dbh ? 'Codebase MySQL error: (' . mysql_errno($this->dbh) . ') ' . mysql_error($this->dbh) : 'Codebase MySQL error: Could not connect to server.';
133            $app->logMsg($mysql_error_msg, LOG_EMERG, __FILE__, __LINE__);
134
135            // Print helpful or pretty error?
136            if ($this->getParam('db_debug')) {
137                echo $mysql_error_msg . "\n";
138            }
139
140            // Die or continue without connection?
141            if ($this->getParam('db_die_on_failure')) {
142                echo "\n\n<!-- Script execution stopped out of embarrassment. -->";
143                die;
144            } else {
145                return false;
146            }
147        }
148
149        // DB connection success!
150        $this->_connected = true;
151
152        // Tell MySQL what character set we're useing. Available only on MySQL verions > 4.01.01.
153        $this->query("/*!40101 SET NAMES '" . $this->mysql_character_sets[strtolower($app->getParam('character_set'))] . "' */");
154
155        return true;
156    }
157
158    /**
159     * Close db connection.
160     *
161     * @access  public
162     * @author  Quinn Comendant <quinn@strangecode.com>
163     * @since   28 Aug 2005 14:32:01
164     */
165    function close()
166    {
167        if (!$this->_connected) {
168            return false;
169        }
170
171        return mysql_close($this->dbh);
172    }
173
174    /**
175     * Return the current database handler.
176     *
177     * @access  public
178     * @return  resource Current value of $this->dbh.
179     * @author  Quinn Comendant <quinn@strangecode.com>
180     * @since   20 Aug 2005 13:50:36
181     */
182    function getDBH()
183    {
184        if (!$this->_connected) {
185            return false;
186        }
187
188        return $this->dbh;
189    }
190
191    /**
192     * Returns connection status
193     *
194     * @access  public
195     * @author  Quinn Comendant <quinn@strangecode.com>
196     * @since   28 Aug 2005 14:58:09
197     */
198    function isConnected()
199    {
200        return (true === $this->_connected);
201    }
202   
203    /**
204     * Returns a properly escaped string using mysql_real_escape_string() with the current connection's charset.
205     *
206     * @access  public
207     * @param   string  $string     Input string to be sent as SQL query.
208     * @return  string              Escaped string from mysql_real_escape_string()
209     * @author  Quinn Comendant <quinn@strangecode.com>
210     * @since   06 Mar 2006 16:41:32
211     */
212    function escapeString($string)
213    {
214        if (!$this->_connected) {
215            return false;
216        }
217
218        return mysql_real_escape_string($string, $this->dbh);
219    }
220
221    /**
222     * A wrapper for mysql_query. Allows us to set the database link_identifier,
223     * to trap errors and ease debugging.
224     *
225     * @param  string  $query   The SQL query to execute
226     * @param  bool    $debug   If true, prints debugging info
227     * @return resource         Query identifier
228     */
229    function query($query, $debug=false)
230    {   
231        static $_query_count = 0;
232        $app =& App::getInstance();
233
234        if (!$this->_connected) {
235           return false;
236        }
237
238        $_query_count++;
239        $debugqry = preg_replace("/\n[\t ]+/", "\n", $query);
240        if ($this->getParam('db_always_debug') || $debug) {
241            echo "<!-- ----------------- Query $_query_count ---------------------\n$debugqry\n-->\n";
242        }
243
244        // Execute!
245        $qid = mysql_query($query, $this->dbh);
246
247        // Error checking.
248        if (!$qid || mysql_error($this->dbh)) {
249            if ($this->getParam('db_debug')) {
250                echo '<pre style="padding:2em; background:#ddd; font:9px monaco;">' . wordwrap(mysql_error($this->dbh)) . '<hr>' . htmlspecialchars($debugqry) . '</pre>';
251            } else {
252                echo _("This page is temporarily unavailable. It should be back up in a few minutes.");
253            }
254            $app->logMsg(sprintf('MySQL error %s: %s in query: %s', mysql_errno($this->dbh), mysql_error($this->dbh), $debugqry), LOG_EMERG, __FILE__, __LINE__);
255            if ($this->getParam('db_die_on_failure')) {
256                echo "\n\n<!-- Script execution stopped out of embarrassment. -->";
257                die;
258            }
259        }
260
261        return $qid;
262    }
263
264    /**
265     * Loads a list of tables in the current database into an array, and returns
266     * true if the requested table is found. Use this function to enable/disable
267     * funtionality based upon the current available db tables or to dynamically
268     * create tables if missing.
269     *
270     * @param  string $table    The name of the table to search.
271     * @param  bool   $strict   Get fresh table info (in case DB changed).
272     * @return bool    true if given $table exists.
273     */
274    function tableExists($table, $use_cached_results=true)
275    {
276        $app =& App::getInstance();
277   
278        if (!$this->_connected) {
279            return false;
280        }
281
282        if (!isset($this->existing_tables) || !$use_cached_results) {
283            $this->existing_tables = array();
284            $qid = $this->query("SHOW TABLES");
285            while (list($row) = mysql_fetch_row($qid)) {
286                $this->existing_tables[] = $row;
287            }
288        }
289        if (in_array($table, $this->existing_tables)) {
290            return true;
291        } else {
292            $app->logMsg(sprintf('Nonexistent DB table: %s.%s', $this->getParam('db_name'), $table), LOG_ALERT, __FILE__, __LINE__);
293            return false;
294        }
295    }
296
297    /**
298     * Tests if the given array of columns exists in the specified table.
299     *
300     * @param  string $table    The name of the table to search.
301     * @param  array  $columns  An array of column names.
302     * @param  bool   $strict   Exact schema match, or are additional fields in the table okay?
303     * @param  bool   $strict   Get fresh table info (in case DB changed).
304     * @return bool    true if given $table exists.
305     */
306    function columnExists($table, $columns, $strict=true, $use_cached_results=true)
307    {
308        if (!$this->_connected) {
309            return false;
310        }
311
312        // Ensure the table exists.
313        if (!$this->tableExists($table, $use_cached_results)) {
314            return false;
315        }
316
317        // For single-value columns.
318        if (!is_array($columns)) {
319            $columns = array($columns);
320        }
321
322        if (!isset($this->table_columns[$table]) || !$use_cached_results) {
323            // Populate and cache array of current columns for this table.
324            $this->table_columns[$table] = array();
325            $qid = $this->query("DESCRIBE $table");
326            while ($row = mysql_fetch_row($qid)) {
327                $this->table_columns[$table][] = $row[0];
328            }
329        }
330
331        if ($strict) {
332            // Do an exact comparison of table schemas.
333            sort($columns);
334            sort($this->table_columns[$table]);
335            return $this->table_columns[$table] == $columns;
336        } else {
337            // Only check that the specified columns are available in the table.
338            $match_columns = array_intersect($this->table_columns[$table], $columns);
339            sort($columns);
340            sort($match_columns);
341            return $match_columns == $columns;
342        }
343    }
344
345    /**
346     * Reset cached items.
347     *
348     * @access  public
349     * @author  Quinn Comendant <quinn@strangecode.com>
350     * @since   28 Aug 2005 22:10:50
351     */
352    function resetCache()
353    {
354        $this->existing_tables = null;
355        $this->table_columns = null;
356    }
357
358} // End.
359
360?>
Note: See TracBrowser for help on using the repository browser.