source: branches/2.1/include/dblayer/functions_mysql.inc.php @ 6605

Last change on this file since 6605 was 6605, checked in by nikrou, 14 years ago

Bug 1744 fixed : Incorrect use of timezone with SQLite
Fixed anti-flood system.

Merge from trunk

File size: 14.9 KB
Line 
1<?php
2// +-----------------------------------------------------------------------+
3// | Piwigo - a PHP based picture gallery                                  |
4// +-----------------------------------------------------------------------+
5// | Copyright(C) 2008-2010 Piwigo Team                  http://piwigo.org |
6// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
7// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
8// +-----------------------------------------------------------------------+
9// | This program is free software; you can redistribute it and/or modify  |
10// | it under the terms of the GNU General Public License as published by  |
11// | the Free Software Foundation                                          |
12// |                                                                       |
13// | This program is distributed in the hope that it will be useful, but   |
14// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
15// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
16// | General Public License for more details.                              |
17// |                                                                       |
18// | You should have received a copy of the GNU General Public License     |
19// | along with this program; if not, write to the Free Software           |
20// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
21// | USA.                                                                  |
22// +-----------------------------------------------------------------------+
23
24define('DB_ENGINE', 'MySQL');
25define('REQUIRED_MYSQL_VERSION', '5.0.0');
26
27define('DB_REGEX_OPERATOR', 'REGEXP');
28define('DB_RANDOM_FUNCTION', 'RAND');
29
30/**
31 *
32 * simple functions
33 *
34 */
35
36function pwg_db_connect($host, $user, $password, $database)
37{ 
38  $link = @mysql_connect($host, $user, $password);
39  if (!$link)
40  {
41    throw new Exception("Can't connect to server");
42  }
43  if (mysql_select_db($database, $link))
44  {
45    return $link;
46  }
47  else
48  {
49    throw new Exception('Connection to server succeed, but it was impossible to connect to database');
50  }
51}
52
53function pwg_db_check_charset() 
54{
55  $db_charset = 'utf8';
56  if (defined('DB_CHARSET') and DB_CHARSET != '')
57  {
58    $db_charset = DB_CHARSET;
59  }
60  pwg_query('SET NAMES "'.$db_charset.'"');
61}
62
63function pwg_db_check_version()
64{
65  $current_mysql = pwg_get_db_version();
66  if (version_compare($current_mysql, REQUIRED_MYSQL_VERSION, '<'))
67  {
68    fatal_error(
69      sprintf(
70        'your MySQL version is too old, you have "%s" and you need at least "%s"',
71        $current_mysql,
72        REQUIRED_MYSQL_VERSION
73        )
74      );
75  }
76}
77
78function pwg_get_db_version() 
79{
80  list($mysql_version) = pwg_db_fetch_row(pwg_query('SELECT VERSION();'));
81 
82  return $mysql_version;
83}
84
85function pwg_query($query)
86{
87  global $conf,$page,$debug,$t2;
88
89  $start = get_moment();
90  ($result = mysql_query($query)) or my_error($query, $conf['die_on_sql_error']);
91
92  $time = get_moment() - $start;
93
94  if (!isset($page['count_queries']))
95  {
96    $page['count_queries'] = 0;
97    $page['queries_time'] = 0;
98  }
99
100  $page['count_queries']++;
101  $page['queries_time']+= $time;
102
103  if ($conf['show_queries'])
104  {
105    $output = '';
106    $output.= '<pre>['.$page['count_queries'].'] ';
107    $output.= "\n".$query;
108    $output.= "\n".'(this query time : ';
109    $output.= '<b>'.number_format($time, 3, '.', ' ').' s)</b>';
110    $output.= "\n".'(total SQL time  : ';
111    $output.= number_format($page['queries_time'], 3, '.', ' ').' s)';
112    $output.= "\n".'(total time      : ';
113    $output.= number_format( ($time+$start-$t2), 3, '.', ' ').' s)';
114    if ( $result!=null and preg_match('/\s*SELECT\s+/i',$query) )
115    {
116      $output.= "\n".'(num rows        : ';
117      $output.= mysql_num_rows($result).' )';
118    }
119    elseif ( $result!=null
120      and preg_match('/\s*INSERT|UPDATE|REPLACE|DELETE\s+/i',$query) )
121    {
122      $output.= "\n".'(affected rows   : ';
123      $output.= mysql_affected_rows().' )';
124    }
125    $output.= "</pre>\n";
126
127    $debug .= $output;
128  }
129
130  return $result;
131}
132
133function pwg_db_nextval($column, $table)
134{
135  $query = '
136SELECT IF(MAX('.$column.')+1 IS NULL, 1, MAX('.$column.')+1)
137  FROM '.$table;
138  list($next) = pwg_db_fetch_row(pwg_query($query));
139
140  return $next;
141}
142
143function pwg_db_changes($result) 
144{
145  return mysql_affected_rows();
146}
147
148function pwg_db_num_rows($result) 
149{
150  return mysql_num_rows($result);
151}
152
153function pwg_db_fetch_assoc($result)
154{
155  return mysql_fetch_assoc($result);
156}
157
158function pwg_db_fetch_row($result)
159{
160  return mysql_fetch_row($result);
161}
162
163function pwg_db_fetch_object($result)
164{
165  return mysql_fetch_object($result);
166}
167
168function pwg_db_free_result($result) 
169{
170  return mysql_free_result($result);
171}
172
173function pwg_db_real_escape_string($s)
174{
175  return mysql_real_escape_string($s);
176}
177
178function pwg_db_insert_id($table=null, $column='id')
179{
180  return mysql_insert_id();
181}
182
183/**
184 *
185 * complex functions
186 *
187 */
188
189/**
190 * creates an array based on a query, this function is a very common pattern
191 * used here
192 *
193 * @param string $query
194 * @param string $fieldname
195 * @return array
196 */
197function array_from_query($query, $fieldname)
198{
199  $array = array();
200
201  $result = pwg_query($query);
202  while ($row = mysql_fetch_assoc($result))
203  {
204    array_push($array, $row[$fieldname]);
205  }
206
207  return $array;
208}
209
210define('MASS_UPDATES_SKIP_EMPTY', 1);
211/**
212 * updates multiple lines in a table
213 *
214 * @param string table_name
215 * @param array dbfields
216 * @param array datas
217 * @param int flags - if MASS_UPDATES_SKIP_EMPTY - empty values do not overwrite existing ones
218 * @return void
219 */
220function mass_updates($tablename, $dbfields, $datas, $flags=0)
221{
222  if (count($datas) == 0)
223    return;
224  // depending on the MySQL version, we use the multi table update or N update queries
225  if (count($datas) < 10 or version_compare(mysql_get_server_info(), '4.0.4') < 0)
226  { // MySQL is prior to version 4.0.4, multi table update feature is not available
227    foreach ($datas as $data)
228    {
229      $query = '
230UPDATE '.$tablename.'
231  SET ';
232      $is_first = true;
233      foreach ($dbfields['update'] as $key)
234      {
235        $separator = $is_first ? '' : ",\n    ";
236
237        if (isset($data[$key]) and $data[$key] != '')
238        {
239          $query.= $separator.$key.' = \''.$data[$key].'\'';
240        }
241        else
242        {
243          if ($flags & MASS_UPDATES_SKIP_EMPTY )
244            continue; // next field
245          $query.= "$separator$key = NULL";
246        }
247        $is_first = false;
248      }
249      if (!$is_first)
250      {// only if one field at least updated
251        $query.= '
252  WHERE ';
253        $is_first = true;
254        foreach ($dbfields['primary'] as $key)
255        {
256          if (!$is_first)
257          {
258            $query.= ' AND ';
259          }
260          if ( isset($data[$key]) )
261          {
262            $query.= $key.' = \''.$data[$key].'\'';
263          }
264          else
265          {
266            $query.= $key.' IS NULL';
267          }
268          $is_first = false;
269        }
270        pwg_query($query);
271      }
272    } // foreach update
273  } // if mysql_ver or count<X
274  else
275  {
276    // creation of the temporary table
277    $query = '
278SHOW FULL COLUMNS FROM '.$tablename;
279    $result = pwg_query($query);
280    $columns = array();
281    $all_fields = array_merge($dbfields['primary'], $dbfields['update']);
282    while ($row = pwg_db_fetch_assoc($result))
283    {
284      if (in_array($row['Field'], $all_fields))
285      {
286        $column = $row['Field'];
287        $column.= ' '.$row['Type'];
288
289        $nullable = true;
290        if (!isset($row['Null']) or $row['Null'] == '' or $row['Null']=='NO')
291        {
292          $column.= ' NOT NULL';
293          $nullable = false;
294        }
295        if (isset($row['Default']))
296        {
297          $column.= " default '".$row['Default']."'";
298        }
299        elseif ($nullable)
300        {
301          $column.= " default NULL";
302        }
303        if (isset($row['Collation']) and $row['Collation'] != 'NULL')
304        {
305          $column.= " collate '".$row['Collation']."'";
306        }
307        array_push($columns, $column);
308      }
309    }
310
311    $temporary_tablename = $tablename.'_'.micro_seconds();
312
313    $query = '
314CREATE TABLE '.$temporary_tablename.'
315(
316  '.implode(",\n  ", $columns).',
317  UNIQUE KEY the_key ('.implode(',', $dbfields['primary']).')
318)';
319
320    pwg_query($query);
321    mass_inserts($temporary_tablename, $all_fields, $datas);
322    if ( $flags & MASS_UPDATES_SKIP_EMPTY )
323      $func_set = create_function('$s', 'return "t1.$s = IFNULL(t2.$s, t1.$s)";');
324    else
325      $func_set = create_function('$s', 'return "t1.$s = t2.$s";');
326
327    // update of images table by joining with temporary table
328    $query = '
329UPDATE '.$tablename.' AS t1, '.$temporary_tablename.' AS t2
330  SET '.
331      implode(
332        "\n    , ",
333        array_map($func_set,$dbfields['update'])
334        ).'
335  WHERE '.
336      implode(
337        "\n    AND ",
338        array_map(
339          create_function('$s', 'return "t1.$s = t2.$s";'),
340          $dbfields['primary']
341          )
342        );
343    pwg_query($query);
344    $query = '
345DROP TABLE '.$temporary_tablename;
346    pwg_query($query);
347  }
348}
349
350
351/**
352 * inserts multiple lines in a table
353 *
354 * @param string table_name
355 * @param array dbfields
356 * @param array inserts
357 * @return void
358 */
359function mass_inserts($table_name, $dbfields, $datas)
360{
361  if (count($datas) != 0)
362  {
363    $first = true;
364
365    $query = 'SHOW VARIABLES LIKE \'max_allowed_packet\'';
366    list(, $packet_size) = pwg_db_fetch_row(pwg_query($query));
367    $packet_size = $packet_size - 2000; // The last list of values MUST not exceed 2000 character*/
368    $query = '';
369
370    foreach ($datas as $insert)
371    {
372      if (strlen($query) >= $packet_size)
373      {
374        pwg_query($query);
375        $first = true;
376      }
377
378      if ($first)
379      {
380        $query = '
381INSERT INTO '.$table_name.'
382  ('.implode(',', $dbfields).')
383  VALUES';
384        $first = false;
385      }
386      else
387      {
388        $query .= '
389  , ';
390      }
391
392      $query .= '(';
393      foreach ($dbfields as $field_id => $dbfield)
394      {
395        if ($field_id > 0)
396        {
397          $query .= ',';
398        }
399
400        if (!isset($insert[$dbfield]) or $insert[$dbfield] === '')
401        {
402          $query .= 'NULL';
403        }
404        else
405        {
406          $query .= "'".$insert[$dbfield]."'";
407        }
408      }
409      $query .= ')';
410    }
411    pwg_query($query);
412  }
413}
414
415/**
416 * Do maintenance on all PWG tables
417 *
418 * @return none
419 */
420function do_maintenance_all_tables()
421{
422  global $prefixeTable, $page;
423
424  $all_tables = array();
425
426  // List all tables
427  $query = 'SHOW TABLES LIKE \''.$prefixeTable.'%\'';
428  $result = pwg_query($query);
429  while ($row = pwg_db_fetch_row($result))
430  {
431    array_push($all_tables, $row[0]);
432  }
433
434  // Repair all tables
435  $query = 'REPAIR TABLE '.implode(', ', $all_tables);
436  $mysql_rc = pwg_query($query);
437
438  // Re-Order all tables
439  foreach ($all_tables as $table_name)
440  {
441    $all_primary_key = array();
442
443    $query = 'DESC '.$table_name.';';
444    $result = pwg_query($query);
445    while ($row = pwg_db_fetch_assoc($result))
446    {
447      if ($row['Key'] == 'PRI')
448      {
449        array_push($all_primary_key, $row['Field']);
450      }
451    }
452
453    if (count($all_primary_key) != 0)
454    {
455      $query = 'ALTER TABLE '.$table_name.' ORDER BY '.implode(', ', $all_primary_key).';';
456      $mysql_rc = $mysql_rc && pwg_query($query);
457    }
458  }
459
460  // Optimize all tables
461  $query = 'OPTIMIZE TABLE '.implode(', ', $all_tables);
462  $mysql_rc = $mysql_rc && pwg_query($query);
463  if ($mysql_rc)
464  {
465    array_push(
466          $page['infos'],
467          l10n('All optimizations have been successfully completed.')
468          );
469  }
470  else
471  {
472    array_push(
473          $page['errors'],
474          l10n('Optimizations have been completed with some errors.')
475          );
476  }
477}
478
479function pwg_db_concat($array)
480{
481  $string = implode($array, ',');
482  return 'CONCAT('. $string.')';
483}
484
485function pwg_db_concat_ws($array, $separator)
486{
487  $string = implode($array, ',');
488  return 'CONCAT_WS(\''.$separator.'\','. $string.')';
489}
490
491function pwg_db_cast_to_text($string)
492{
493  return 'CAST('.$string.' AS CHAR)';
494}
495
496/**
497 * returns an array containing the possible values of an enum field
498 *
499 * @param string tablename
500 * @param string fieldname
501 */
502function get_enums($table, $field)
503{
504  // retrieving the properties of the table. Each line represents a field :
505  // columns are 'Field', 'Type'
506  $result = pwg_query('desc '.$table);
507  while ($row = pwg_db_fetch_assoc($result))
508  {
509    // we are only interested in the the field given in parameter for the
510    // function
511    if ($row['Field'] == $field)
512    {
513      // retrieving possible values of the enum field
514      // enum('blue','green','black')
515      $options = explode(',', substr($row['Type'], 5, -1));
516      foreach ($options as $i => $option)
517      {
518        $options[$i] = str_replace("'", '',$option);
519      }
520    }
521  }
522  pwg_db_free_result($result);
523  return $options;
524}
525
526// get_boolean transforms a string to a boolean value. If the string is
527// "false" (case insensitive), then the boolean value false is returned. In
528// any other case, true is returned.
529function get_boolean( $string )
530{
531  $boolean = true;
532  if ( 'false' == strtolower($string) )
533  {
534    $boolean = false;
535  }
536  return $boolean;
537}
538
539/**
540 * returns boolean string 'true' or 'false' if the given var is boolean
541 *
542 * @param mixed $var
543 * @return mixed
544 */
545function boolean_to_string($var)
546{
547  if (is_bool($var))
548  {
549    return $var ? 'true' : 'false';
550  }
551  else
552  {
553    return $var;
554  }
555}
556
557/**
558 *
559 * interval and date functions
560 *
561 */
562
563function pwg_db_get_recent_period_expression($period, $date='CURRENT_DATE')
564{
565  if ($date!='CURRENT_DATE')
566  {
567    $date = '\''.$date.'\'';
568  }
569
570  return 'SUBDATE('.$date.',INTERVAL '.$period.' DAY)';
571}
572
573function pwg_db_get_recent_period($period, $date='CURRENT_DATE')
574{
575  $query = '
576SELECT '.pwg_db_get_recent_period_expression($period);
577  list($d) = pwg_db_fetch_row(pwg_query($query));
578
579  return $d;
580}
581
582function pwg_db_get_flood_period_expression($seconds)
583{
584  return 'SUBDATE(now(), INTERVAL '.$seconds.' SECOND)';
585}
586
587function pwg_db_get_hour($date) 
588{
589  return 'hour('.$date.')';
590}
591
592function pwg_db_get_date_YYYYMM($date)
593{
594  return 'DATE_FORMAT('.$date.', \'%Y%m\')';
595}
596
597function pwg_db_get_date_MMDD($date)
598{
599  return 'DATE_FORMAT('.$date.', \'%m%d\')';
600}
601
602function pwg_db_get_year($date)
603{
604  return 'YEAR('.$date.')';
605}
606
607function pwg_db_get_month($date)
608{
609  return 'MONTH('.$date.')';
610}
611
612function pwg_db_get_week($date, $mode=null)
613{
614  if ($mode)
615  {
616    return 'WEEK('.$date.', '.$mode.')';
617  }
618  else
619  {
620    return 'WEEK('.$date.')';
621  }
622}
623
624function pwg_db_get_dayofmonth($date)
625{
626  return 'DAYOFMONTH('.$date.')';
627}
628
629function pwg_db_get_dayofweek($date)
630{
631  return 'DAYOFWEEK('.$date.')';
632}
633
634function pwg_db_get_weekday($date)
635{
636  return 'WEEKDAY('.$date.')';
637}
638
639// my_error returns (or send to standard output) the message concerning the
640// error occured for the last mysql query.
641function my_error($header, $die)
642{
643  $error = "[mysql error ".mysql_errno().'] '.mysql_error()."\n";
644  $error .= $header;
645
646  if ($die)
647  {
648    fatal_error($error);
649  }
650  echo("<pre>");
651  trigger_error($error, E_USER_WARNING);
652  echo("</pre>");
653}
654
655?>
Note: See TracBrowser for help on using the repository browser.