Bug with multiple registration of filters fixed (see fix_filters.php for details)
[mailer.git] / inc / db / lib-mysql3.php
1 <?php
2 /************************************************************************
3  * MXChange v0.2.1                                    Start: 08/29/2004 *
4  * ===============                              Last change: 08/29/2004 *
5  *                                                                      *
6  * -------------------------------------------------------------------- *
7  * File              : lib-mysql3.php                                   *
8  * -------------------------------------------------------------------- *
9  * Short description : Database layer for MySQL +3.x server             *
10  * -------------------------------------------------------------------- *
11  * Kurzbeschreibung  : Datenbankschicht fuer MySQL +3.x Server          *
12  * -------------------------------------------------------------------- *
13  * $Revision::                                                        $ *
14  * $Date::                                                            $ *
15  * $Tag:: 0.2.1-FINAL                                                 $ *
16  * $Author::                                                          $ *
17  * Needs to be in all Files and every File needs "svn propset           *
18  * svn:keywords Date Revision" (autoprobset!) at least!!!!!!            *
19  * -------------------------------------------------------------------- *
20  * Copyright (c) 2003 - 2008 by Roland Haeder                           *
21  * For more information visit: http://www.mxchange.org                  *
22  *                                                                      *
23  * This program is free software; you can redistribute it and/or modify *
24  * it under the terms of the GNU General Public License as published by *
25  * the Free Software Foundation; either version 2 of the License, or    *
26  * (at your option) any later version.                                  *
27  *                                                                      *
28  * This program is distributed in the hope that it will be useful,      *
29  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
30  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
31  * GNU General Public License for more details.                         *
32  *                                                                      *
33  * You should have received a copy of the GNU General Public License    *
34  * along with this program; if not, write to the Free Software          *
35  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,               *
36  * MA  02110-1301  USA                                                  *
37  ************************************************************************/
38
39 // Some security stuff...
40 if (!defined('__SECURITY')) {
41         $INC = substr(dirname(__FILE__), 0, strpos(dirname(__FILE__), '/inc') + 4) . '/security.php';
42         require($INC);
43 }
44
45 // SQL queries
46 function SQL_QUERY ($sql_string, $F, $L) {
47         // Link is up?
48         if (!SQL_IS_LINK_UP()) {
49                 // We should not quietly ignore this!
50                 trigger_error(sprintf("Cannot query database: sql_string=%s,file=%s,line=%s",
51                         $sql_string,
52                         basename($F),
53                         $L
54                 ));
55
56                 // Return 'false' because it has failed
57                 return false;
58         } // END - if
59
60         // Remove \t, \n and \r from queries they may confuse some MySQL version I have heard
61         $sql_string = str_replace("\t", " ", str_replace("\n", " ", str_replace("\r", " ", $sql_string)));
62
63         // Replace {!_MYSQL_PREFIX!} with constant, closes #84. Thanks to profi-concept
64         $sql_string = str_replace("{!_MYSQL_PREFIX!}", getConfig('_MYSQL_PREFIX'), $sql_string);
65
66         // Replace {!_TABLE_TYPE!} with constant
67         $sql_string = str_replace("{!_TABLE_TYPE!}", getConfig('_TABLE_TYPE'), $sql_string);
68
69         // Starting time
70         $querytimeBefore = array_sum(explode(' ', microtime()));
71
72         // Run SQL command
73         //* DEBUG: */ print $sql_string."<br />\n";
74         $result = mysql_query($sql_string, SQL_GET_LINK())
75                 or addFatalMessage(__FUNCTION__, __LINE__, $F." (".$L."):".mysql_error()."<br />
76 Query string:<br />
77 ".$sql_string);
78         //* DEBUG: */ print __LINE__ . ': numRows=' . SQL_NUMROWS($result) . ',affected=' . SQL_AFFECTEDROWS() . "<br />\n";
79
80         // Ending time
81         $querytimeAfter = array_sum(explode(' ', microtime()));
82
83         // Calculate query time
84         $queryTime = $querytimeAfter - $querytimeBefore;
85
86         // Save last successfull query
87         setConfigEntry('db_last_query', $sql_string);
88
89         // Count this query
90         incrementConfigEntry('sql_count');
91
92         // Debug output
93         //* DEBUG: */ print "Query=<pre>".$sql_string."</pre>, affected=<strong>".SQL_AFFECTEDROWS()."</strong>, numrows=<strong>".SQL_NUMROWS($result)."</strong><br />\n";
94         if ((getOutputMode() != '1') && (getOutputMode() != '-1') && (isDebugModeEnabled()) && (getConfig('DEBUG_SQL') == 'Y')) {
95                 //
96                 // Debugging stuff...
97                 //
98                 $fp = fopen(constant('PATH') . 'inc/cache/mysql.log', 'a') or app_die(__FILE__, __LINE__, "Cannot write mysql.log!");
99                 if (!isset($GLOBALS['sql_first_entry'])) {
100                         // Write first entry
101                         fwrite($fp, 'Module=' . getModule() . "\n");
102                         $GLOBALS['sql_first_entry'] = true;
103                 } // END - if
104                 fwrite($fp, $F."(LINE=".$L."|NUM=".SQL_NUMROWS($result)."|AFFECTED=".SQL_AFFECTEDROWS()."|QUERYTIME:".$queryTime."): ".str_replace("\r", '', str_replace("\n", " ", $sql_string))."\n");
105                 fclose($fp);
106         } // END - if
107
108         // Count DB hits
109         if (!isConfigEntrySet('db_hits_run')) {
110                 // Count in dummy variable
111                 setConfigEntry('db_hits_run', 1);
112         } else {
113                 // Count to config array
114                 incrementConfigEntry('db_hits_run');
115         }
116
117         // Return the result
118         return $result;
119 }
120
121 // SQL num rows
122 function SQL_NUMROWS ($result) {
123         // Is the result a valid resource?
124         if (is_resource($result)) {
125                 // Get the count of rows from database
126                 $lines = mysql_num_rows($result);
127
128                 // Is the result empty? Then we have an error!
129                 if (empty($lines)) $lines = 0;
130         } else {
131                 // No resource given, no lines found!
132                 $lines = 0;
133         }
134         return $lines;
135 }
136
137 // SQL affected rows
138 function SQL_AFFECTEDROWS() {
139         // Valid link resource?
140         if (!SQL_IS_LINK_UP()) return false;
141
142         // Get affected rows
143         $lines = mysql_affected_rows(SQL_GET_LINK());
144
145         // Return it
146         return $lines;
147 }
148
149 // SQL fetch row
150 function SQL_FETCHROW ($result) {
151         // Is a result resource set?
152         if (!is_resource($result)) return false;
153
154         // Fetch the data and return it
155         return mysql_fetch_row($result);
156 }
157
158 // SQL fetch array
159 function SQL_FETCHARRAY($res, $nr=0, $remove_numerical=true) {
160         // Is a result resource set?
161         if (!is_resource($res)) return false;
162
163         // Initialize array
164         $row = array();
165
166         // Load row from database
167         $row = mysql_fetch_array($res);
168
169         // Return only arrays here
170         if (is_array($row)) {
171                 // Shall we remove numerical data here automatically?
172                 if ($remove_numerical) {
173                         // So let's remove all numerical elements to save memory!
174                         $max = count($row);
175                         for ($idx = 0; $idx < ($max / 2); $idx++) {
176                                 // Remove entry
177                                 unset($row[$idx]);
178                         } // END - for
179                 } // END - if
180
181                 // Return row
182                 return $row;
183         } else {
184                 // Return a false here...
185                 return false;
186         }
187 }
188
189 // SQL result
190 function SQL_RESULT ($res, $row, $field = 0) {
191         // Is $res valid?
192         if (!is_resource($res)) return false;
193
194         // Run the result command and return the result
195         $result = mysql_result($res, $row, $field);
196         return $result;
197 }
198
199 // SQL connect
200 function SQL_CONNECT ($host, $login, $password, $F, $L) {
201         // Try to connect
202         $connect = mysql_connect($host, $login, $password) or addFatalMessage(__FUNCTION__, __LINE__, $F." (".$L."):".mysql_error());
203
204         // Set the link resource
205         SQL_SET_LINK($connect);
206 }
207
208 // SQL select database
209 function SQL_SELECT_DB ($dbName, $F, $L) {
210         // Is there still a valid link? If not, skip it.
211         if (!SQL_IS_LINK_UP()) return false;
212
213         // Return the result
214         return mysql_select_db($dbName, SQL_GET_LINK()) or addFatalMessage(__FUNCTION__, __LINE__, $F." (".$L."):".mysql_error());
215 }
216
217 // SQL close link
218 function SQL_CLOSE ($F, $L) {
219         if (!SQL_IS_LINK_UP()) {
220                 // Skip double close
221                 return false;
222         } // END - if
223
224         // Do we need to update cache/db counter?
225         //* DEBUG: */ echo "DB=".getConfig('db_hits').",CACHE=".getConfig('cache_hits')."<br />\n";
226         if ((GET_EXT_VERSION('cache') >= '0.0.7') && (getConfig('db_hits') > 0) && (getConfig('cache_hits') > 0) && (isCacheInstanceValid())) {
227                 // Add new hits
228                 incrementConfigEntry('db_hits', getConfig('db_hits_run'));
229
230                 // Update counter for db/cache
231                 updateConfiguration(array('db_hits', 'cache_hits'), array(getConfig('db_hits'), getConfig('cache_hits')));
232         } // END - if
233
234         // Close database link and forget the link
235         $close = mysql_close(SQL_GET_LINK())
236                 or addFatalMessage(__FUNCTION__, __LINE__, $F . ' (' . $L . '):'.mysql_error());
237
238         // Close link
239         SQL_SET_LINK(null);
240
241         // Return the result
242         return $close;
243 }
244
245 // SQL free result
246 function SQL_FREERESULT ($result) {
247         if (!is_resource($result)) {
248                 // Abort here
249                 return false;
250         } // END - if
251
252         $res = mysql_free_result($result);
253         return $res;
254 }
255
256 // SQL string escaping
257 function SQL_QUERY_ESC ($qstring, $data, $F, $L, $run=true, $strip=true, $secure=true) {
258         // Link is there?
259         if (!SQL_IS_LINK_UP()) return false;
260
261         // Init variable
262         $query = 'failed';
263
264         if ($strip === true) {
265                 $strip = 'true';
266         } else {
267                 $strip = 'false';
268         }
269
270         if ($secure === true) {
271                 $secure = 'true';
272         } else {
273                 $secure = 'false';
274         }
275
276         $eval = "\$query = sprintf(\"".$qstring."\"";
277         foreach ($data as $var) {
278                 if ((!empty($var)) || ($var === 0)) {
279                         $eval .= ", SQL_ESCAPE(\"".$var."\", ".$secure.", ".$strip.")";
280                 } else {
281                         $eval .= ", ''";
282                 }
283         } // END - foreach
284         $eval .= ");";
285
286         // Debugging
287         //
288         //* DEBUG: */ $fp = fopen(constant('PATH')."inc/cache/escape_debug.log", 'a') or app_die(__FILE__, __LINE__, "Cannot write debug.log!");
289         //* DEBUG: */ fwrite($fp, $F.'('.$L."): ".str_replace("\r", '', str_replace("\n", " ", $eval))."\n");
290         //* DEBUG: */ fclose($fp);
291
292         // Run the code
293         eval($eval);
294
295         // Was the eval() command fine?
296         if ($query == 'failed') {
297                 // Something went wrong?
298                 debug_report_bug('eval=' . $eval);
299         } // END - if
300
301         if ($run === true) {
302                 // Run SQL query (default)
303                 return SQL_QUERY($query, $F, $L);
304         } else {
305                 // Return secured string
306                 return $query;
307         }
308 }
309
310 // Get ID from last INSERT command
311 function SQL_INSERTID () {
312         if (!SQL_IS_LINK_UP()) return false;
313         return mysql_insert_id();
314 }
315
316 // Escape a string for the database
317 function SQL_ESCAPE ($str, $secureString=true, $strip=true) {
318         // Secure string first? (which is the default behaviour!)
319         if ($secureString) {
320                 // Then do it here
321                 $str = secureString($str, $strip);
322         } // END - if
323
324         if (!SQL_IS_LINK_UP()) {
325                 // Fall-back to smartAddSlashes() when there is no link
326                 return smartAddSlashes($str);
327         } elseif (function_exists('mysql_real_escape_string')) {
328                 // The new and improved version
329                 //* DEBUG: */ print __FUNCTION__."(<font color=\"#0000aa\">".__LINE__."</font>):str={$str}<br />\n";
330                 return mysql_real_escape_string($str, SQL_GET_LINK());
331         } elseif (function_exists('mysql_escape_string')) {
332                 // The obsolete function
333                 return mysql_escape_string($str, SQL_GET_LINK());
334         } else {
335                 // If nothing else works, fall back to smartAddSlashes()
336                 return smartAddSlashes($str);
337         }
338 }
339
340 // SELECT query string from table, columns and so on... ;-)
341 function SQL_RESULT_FROM_ARRAY ($table, $columns, $idRow, $id, $F, $L) {
342         // Is columns an array?
343         if (!is_array($columns)) {
344                 // No array
345                 trigger_error(sprintf("columns is not array. %s!=array", gettype($columns)));
346         } // END  - if
347
348         // Prepare the SQL statement
349         $sql = "SELECT `".implode("`,`", $columns)."` FROM `{!_MYSQL_PREFIX!}_%s` WHERE `%s`='%s' LIMIT 1";
350
351         // Return the result
352         return SQL_QUERY_ESC($sql,
353                 array(
354                         $table,
355                         $idRow,
356                         bigintval($id),
357                 ), $F, $L
358         );
359 }
360
361 // ALTER TABLE wrapper function
362 function SQL_ALTER_TABLE ($sql, $F, $L) {
363         // This is the default result...
364         $result = false;
365
366         // Determine index/fulltext/unique word
367         $noIndex = (
368         (
369                 strpos($sql, 'INDEX') === false
370         ) && (
371                 strpos($sql, 'FULLTEXT') === false
372         ) && (
373                 strpos($sql, 'UNIQUE') === false
374         )
375         );
376
377         // Extract table name
378         $tableArray = explode(" ", $sql);
379         $tableName = str_replace('`', '', $tableArray[2]);
380
381         // Shall we add/drop?
382         if (((strpos($sql, 'ADD') !== false) || (strpos($sql, 'DROP') !== false)) && ($noIndex === true)) {
383                 // And column name as well
384                 $columnName = str_replace('`', '', $tableArray[4]);
385
386                 // Get column information
387                 $result = SQL_QUERY_ESC("SHOW COLUMNS FROM `%s` LIKE '%s'",
388                         array($tableName, $columnName), __FILE__, __LINE__);
389
390                 // Do we have no entry on ADD or an entry on DROP?
391                 // 123           4       4     3    3      4           4          32    23           4       4     3    3      4            4          321
392                 if (((SQL_NUMROWS($result) == 0) && (strpos($sql, 'ADD') !== false)) || ((SQL_NUMROWS($result) == 1) && (strpos($sql, 'DROP') !== false))) {
393                         // Do the query
394                         //* DEBUG: */ print __LINE__.':'.$sql."<br />\n";
395                         $result = SQL_QUERY($sql, $F, $L, false);
396                 } // END - if
397         } elseif ((getConfig('_TABLE_TYPE') == 'InnoDB') && (strpos($sql, 'FULLTEXT') !== false)) {
398                 // Skip this query silently
399                 //* DEBUG: */ DEBUG_LOG(__FUNCTION__, __LINE__, sprintf("Skipped FULLTEXT: sql=%s,file=%s,line=%s", $sql, $F, $L));
400         } elseif (!$noIndex) {
401                 // And column name as well
402                 $columnName = str_replace('`', '', $tableArray[4]);
403
404                 // Is this "UNIQUE" or so? FULLTEXT has been handled the elseif() block above
405                 if (in_array(strtoupper($columnName), array('INDEX', 'UNIQUE', 'KEY', 'FULLTEXT'))) {
406                         // Init loop
407                         $begin = 1; $columnName = ',';
408                         while (strpos($columnName, ',') !== false) {
409                                 // Use last
410                                 $columnName = str_replace('`', '', $tableArray[count($tableArray) - $begin]);
411                                 //* DEBUG: */ print __LINE__.':'.$columnName."----------------".$begin."<br />\n";
412
413                                 // Remove brackes
414                                 $columnName = str_replace('(', '', str_replace(')', '', $columnName));
415                                 //* DEBUG: */ print __LINE__.':'.$columnName."----------------".$begin."<br />\n";
416
417                                 // Continue
418                                 $begin++;
419                         } // END while
420                 } // END - if
421
422                 // Show indexes
423                 $result = SQL_QUERY_ESC("SHOW INDEX FROM `%s`",
424                         array($tableName), __FILE__, __LINE__);
425
426                 // Walk through all
427                 $skip = false;
428                 while ($content = SQL_FETCHARRAY($result)) {
429                         // Is it found?
430                         //* DEBUG: */ print "<pre>".print_r($content, true)."</pre>";
431                         if (($content['Column_name'] == $columnName) || ($content['Key_name'] == $columnName)) {
432                                 // Skip this query!
433                                 //* DEBUG: */ DEBUG_LOG(__FUNCTION__, __LINE__, sprintf("Skiped: %s", $sql));
434                                 $skip = true;
435                                 break;
436                         } // END - if
437                 } // END - while
438
439                 // Free result
440                 SQL_FREERESULT($result);
441
442                 // Shall we run it?
443                 if (!$skip) {
444                         // Send it to the SQL_QUERY() function
445                         //* DEBUG: */ print __LINE__.':'.$sql."<br />\n";
446                         $result = SQL_QUERY($sql, $F, $L, false);
447                 } // END - if
448         } else {
449                 // Other ALTER TABLE query
450                 //* DEBUG: */ print __LINE__.':'.$sql."<br />\n";
451                 $result = SQL_QUERY($sql, $F, $L, false);
452         }
453
454         // Return result
455         return $result;
456 }
457
458 // Getter for SQL link
459 function SQL_GET_LINK () {
460         // Init link
461         $link = null;
462
463         // Is it in the globals?
464         if (isset($GLOBALS['sql_link'])) {
465                 // Then take it
466                 $link = $GLOBALS['sql_link'];
467         } // END - if
468
469         // Return it
470         return $link;
471 }
472
473 // Setter for link
474 function SQL_SET_LINK ($link) {
475         // Is this a resource or null?
476         if ((!is_resource($link)) && (!is_null($link))) {
477                 // This should never happen!
478                 trigger_error(sprintf("link is not resource or null. Type: %s", gettype($link)));
479         } // END - if
480
481         // Set it
482         $GLOBALS['sql_link'] = $link;
483 }
484
485 // Checks if the link is up
486 function SQL_IS_LINK_UP () {
487         // Get the link
488         $link = SQL_GET_LINK();
489
490         // Return the result
491         return (is_resource($link));
492 }
493
494 //
495 ?>