source: branches/2.0singleton/lib/DB.inc.php @ 135

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

Q - Finished integrating singleton methods into existing code. Renamed SessionCache? to Cache, and renamed methods in Cache and Prefs

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_NOTICE, __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 $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        return mysql_real_escape_string($string, $this->dbh);
215    }
216
217    /**
218     * A wrapper for mysql_query. Allows us to set the database link_identifier,
219     * to trap errors and ease debugging.
220     *
221     * @param  string  $query   The SQL query to execute
222     * @param  bool    $debug   If true, prints debugging info
223     * @return resource         Query identifier
224     */
225    function query($query, $debug=false)
226    {
227        $app =& App::getInstance();
228   
229        static $_query_count = 0;
230
231        if (!$this->_connected) {
232           return false;
233        }
234
235        $_query_count++;
236        $debugqry = preg_replace("/\n[\t ]+/", "\n", $query);
237        if ($this->getParam('db_always_debug') || $debug) {
238            echo "<!-- ----------------- Query $_query_count ---------------------\n$debugqry\n-->\n";
239        }
240
241        // Execute!
242        $qid = mysql_query($query, $this->dbh);
243
244        // Error checking.
245        if (!$qid || mysql_error($this->dbh)) {
246            if ($this->getParam('db_debug')) {
247                echo '<pre style="padding:2em; background:#ddd; font:9px monaco;">' . wordwrap(mysql_error($this->dbh)) . '<hr>' . htmlspecialchars($debugqry) . '</pre>';
248            } else {
249                echo _("This page is temporarily unavailable. It should be back up in a few minutes.");
250            }
251            $app->logMsg(sprintf('MySQL error %s: %s in query: %s', mysql_errno($this->dbh), mysql_error($this->dbh), $debugqry), LOG_EMERG, __FILE__, __LINE__);
252            if ($this->getParam('db_die_on_failure')) {
253                echo "\n\n<!-- Script execution stopped out of embarrassment. -->";
254                die;
255            }
256        }
257
258        return $qid;
259    }
260
261    /**
262     * Loads a list of tables in the current database into an array, and returns
263     * true if the requested table is found. Use this function to enable/disable
264     * funtionality based upon the current available db tables or to dynamically
265     * create tables if missing.
266     *
267     * @param  string $table    The name of the table to search.
268     * @param  bool   $strict   Get fresh table info (in case DB changed).
269     * @return bool    true if given $table exists.
270     */
271    function tableExists($table, $use_cached_results=true)
272    {
273        $app =& App::getInstance();
274   
275        if (!$this->_connected) {
276            return false;
277        }
278
279        if (!isset($this->existing_tables) || !$use_cached_results) {
280            $this->existing_tables = array();
281            $qid = $this->query("SHOW TABLES");
282            while (list($row) = mysql_fetch_row($qid)) {
283                $this->existing_tables[] = $row;
284            }
285        }
286        if (in_array($table, $this->existing_tables)) {
287            return true;
288        } else {
289            $app->logMsg(sprintf('nonexistent DB table: %s.%s', $this->getParam('db_name'), $table), LOG_ALERT, __FILE__, __LINE__);
290            return false;
291        }
292    }
293
294    /**
295     * Tests if the given array of columns exists in the specified table.
296     *
297     * @param  string $table    The name of the table to search.
298     * @param  array  $columns  An array of column names.
299     * @param  bool   $strict   Exact schema match, or are additional fields in the table okay?
300     * @param  bool   $strict   Get fresh table info (in case DB changed).
301     * @return bool    true if given $table exists.
302     */
303    function columnExists($table, $columns, $strict=true, $use_cached_results=true)
304    {
305        if (!$this->_connected) {
306            return false;
307        }
308
309        // Ensure the table exists.
310        if (!$this->tableExists($table, $use_cached_results)) {
311            return false;
312        }
313
314        // For single-value columns.
315        if (!is_array($columns)) {
316            $columns = array($columns);
317        }
318
319        if (!isset($this->table_columns[$table]) || !$use_cached_results) {
320            // Populate and cache array of current columns for this table.
321            $this->table_columns[$table] = array();
322            $qid = $this->query("DESCRIBE $table");
323            while ($row = mysql_fetch_row($qid)) {
324                $this->table_columns[$table][] = $row[0];
325            }
326        }
327
328        if ($strict) {
329            // Do an exact comparison of table schemas.
330            sort($columns);
331            sort($this->table_columns[$table]);
332            return $this->table_columns[$table] == $columns;
333        } else {
334            // Only check that the specified columns are available in the table.
335            $match_columns = array_intersect($this->table_columns[$table], $columns);
336            sort($columns);
337            sort($match_columns);
338            return $match_columns == $columns;
339        }
340    }
341
342    /**
343     * Reset cached items.
344     *
345     * @access  public
346     * @author  Quinn Comendant <quinn@strangecode.com>
347     * @since   28 Aug 2005 22:10:50
348     */
349    function resetCache()
350    {
351        $this->existing_tables = null;
352        $this->table_columns = null;
353    }
354
355} // End.
356
357?>
Note: See TracBrowser for help on using the repository browser.