source: trunk/include/dblayer/functions_mysql.inc.php @ 19703

Last change on this file since 19703 was 19703, checked in by plg, 11 years ago

update Piwigo headers to 2013 (the end of the world didn't occur as expected on r12922)

File size: 16.9 KB
Line 
1<?php
2// +-----------------------------------------------------------------------+
3// | Piwigo - a PHP based photo gallery                                    |
4// +-----------------------------------------------------------------------+
5// | Copyright(C) 2008-2013 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  return mysql_get_server_info();
81}
82
83function pwg_query($query)
84{
85  global $conf,$page,$debug,$t2;
86
87  $start = microtime(true);
88  ($result = mysql_query($query)) or my_error($query, $conf['die_on_sql_error']);
89
90  $time = microtime(true) - $start;
91
92  if (!isset($page['count_queries']))
93  {
94    $page['count_queries'] = 0;
95    $page['queries_time'] = 0;
96  }
97
98  $page['count_queries']++;
99  $page['queries_time']+= $time;
100
101  if ($conf['show_queries'])
102  {
103    $output = '';
104    $output.= '<pre>['.$page['count_queries'].'] ';
105    $output.= "\n".$query;
106    $output.= "\n".'(this query time : ';
107    $output.= '<b>'.number_format($time, 3, '.', ' ').' s)</b>';
108    $output.= "\n".'(total SQL time  : ';
109    $output.= number_format($page['queries_time'], 3, '.', ' ').' s)';
110    $output.= "\n".'(total time      : ';
111    $output.= number_format( ($time+$start-$t2), 3, '.', ' ').' s)';
112    if ( $result!=null and preg_match('/\s*SELECT\s+/i',$query) )
113    {
114      $output.= "\n".'(num rows        : ';
115      $output.= mysql_num_rows($result).' )';
116    }
117    elseif ( $result!=null
118      and preg_match('/\s*INSERT|UPDATE|REPLACE|DELETE\s+/i',$query) )
119    {
120      $output.= "\n".'(affected rows   : ';
121      $output.= mysql_affected_rows().' )';
122    }
123    $output.= "</pre>\n";
124
125    $debug .= $output;
126  }
127
128  return $result;
129}
130
131function pwg_db_nextval($column, $table)
132{
133  $query = '
134SELECT IF(MAX('.$column.')+1 IS NULL, 1, MAX('.$column.')+1)
135  FROM '.$table;
136  list($next) = pwg_db_fetch_row(pwg_query($query));
137
138  return $next;
139}
140
141function pwg_db_changes($result) 
142{
143  return mysql_affected_rows();
144}
145
146function pwg_db_num_rows($result) 
147{
148  return mysql_num_rows($result);
149}
150
151function pwg_db_fetch_assoc($result)
152{
153  return mysql_fetch_assoc($result);
154}
155
156function pwg_db_fetch_row($result)
157{
158  return mysql_fetch_row($result);
159}
160
161function pwg_db_fetch_object($result)
162{
163  return mysql_fetch_object($result);
164}
165
166function pwg_db_free_result($result) 
167{
168  return mysql_free_result($result);
169}
170
171function pwg_db_real_escape_string($s)
172{
173  return mysql_real_escape_string($s);
174}
175
176function pwg_db_insert_id($table=null, $column='id')
177{
178  return mysql_insert_id();
179}
180
181function pwg_db_close($link=null)
182{
183  return mysql_close($link);
184}
185
186/**
187 *
188 * complex functions
189 *
190 */
191
192/**
193 * creates an array based on a query, this function is a very common pattern
194 * used here
195 *
196 * @param string $query
197 * @param string $fieldname optional
198 * @return array
199 */
200function array_from_query($query, $fieldname=false)
201{
202  $array = array();
203
204  $result = pwg_query($query);
205  if (false === $fieldname)
206  {
207    while ($row = mysql_fetch_assoc($result))
208    {
209      $array[] = $row;     
210    }
211  }
212  else
213  {
214    while ($row = mysql_fetch_assoc($result))
215    {
216      $array[] = $row[$fieldname];
217    }
218  }
219  return $array;
220}
221
222define('MASS_UPDATES_SKIP_EMPTY', 1);
223/**
224 * updates multiple lines in a table
225 *
226 * @param string table_name
227 * @param array dbfields
228 * @param array datas
229 * @param int flags - if MASS_UPDATES_SKIP_EMPTY - empty values do not overwrite existing ones
230 * @return void
231 */
232function mass_updates($tablename, $dbfields, $datas, $flags=0)
233{
234  if (count($datas) == 0)
235    return;
236 
237  // depending on the MySQL version, we use the multi table update or N update queries
238  if (count($datas) < 10)
239  {
240    foreach ($datas as $data)
241    {
242      $query = '
243UPDATE '.$tablename.'
244  SET ';
245      $is_first = true;
246      foreach ($dbfields['update'] as $key)
247      {
248        $separator = $is_first ? '' : ",\n    ";
249
250        if (isset($data[$key]) and $data[$key] != '')
251        {
252          $query.= $separator.$key.' = \''.$data[$key].'\'';
253        }
254        else
255        {
256          if ( $flags & MASS_UPDATES_SKIP_EMPTY )
257            continue; // next field
258          $query.= "$separator$key = NULL";
259        }
260        $is_first = false;
261      }
262      if (!$is_first)
263      {// only if one field at least updated
264        $query.= '
265  WHERE ';
266        $is_first = true;
267        foreach ($dbfields['primary'] as $key)
268        {
269          if (!$is_first)
270          {
271            $query.= ' AND ';
272          }
273          if ( isset($data[$key]) )
274          {
275            $query.= $key.' = \''.$data[$key].'\'';
276          }
277          else
278          {
279            $query.= $key.' IS NULL';
280          }
281          $is_first = false;
282        }
283        pwg_query($query);
284      }
285    } // foreach update
286  } // if mysql_ver or count<X
287  else
288  {
289    // creation of the temporary table
290    $query = '
291SHOW FULL COLUMNS FROM '.$tablename;
292    $result = pwg_query($query);
293    $columns = array();
294    $all_fields = array_merge($dbfields['primary'], $dbfields['update']);
295    while ($row = pwg_db_fetch_assoc($result))
296    {
297      if (in_array($row['Field'], $all_fields))
298      {
299        $column = $row['Field'];
300        $column.= ' '.$row['Type'];
301
302        $nullable = true;
303        if (!isset($row['Null']) or $row['Null'] == '' or $row['Null']=='NO')
304        {
305          $column.= ' NOT NULL';
306          $nullable = false;
307        }
308        if (isset($row['Default']))
309        {
310          $column.= " default '".$row['Default']."'";
311        }
312        elseif ($nullable)
313        {
314          $column.= " default NULL";
315        }
316        if (isset($row['Collation']) and $row['Collation'] != 'NULL')
317        {
318          $column.= " collate '".$row['Collation']."'";
319        }
320        array_push($columns, $column);
321      }
322    }
323
324    $temporary_tablename = $tablename.'_'.micro_seconds();
325
326    $query = '
327CREATE TABLE '.$temporary_tablename.'
328(
329  '.implode(",\n  ", $columns).',
330  UNIQUE KEY the_key ('.implode(',', $dbfields['primary']).')
331)';
332
333    pwg_query($query);
334    mass_inserts($temporary_tablename, $all_fields, $datas);
335    if ( $flags & MASS_UPDATES_SKIP_EMPTY )
336      $func_set = create_function('$s', 'return "t1.$s = IFNULL(t2.$s, t1.$s)";');
337    else
338      $func_set = create_function('$s', 'return "t1.$s = t2.$s";');
339
340    // update of images table by joining with temporary table
341    $query = '
342UPDATE '.$tablename.' AS t1, '.$temporary_tablename.' AS t2
343  SET '.
344      implode(
345        "\n    , ",
346        array_map($func_set,$dbfields['update'])
347        ).'
348  WHERE '.
349      implode(
350        "\n    AND ",
351        array_map(
352          create_function('$s', 'return "t1.$s = t2.$s";'),
353          $dbfields['primary']
354          )
355        );
356    pwg_query($query);
357    $query = '
358DROP TABLE '.$temporary_tablename;
359    pwg_query($query);
360  }
361}
362
363/**
364 * updates one line in a table
365 *
366 * @param string table_name
367 * @param array set_fields
368 * @param array where_fields
369 * @param int flags - if MASS_UPDATES_SKIP_EMPTY - empty values do not overwrite existing ones
370 * @return void
371 */
372function single_update($tablename, $set_fields, $where_fields, $flags=0)
373{
374  if (count($set_fields) == 0)
375  {
376    return;
377  }
378
379  $query = '
380UPDATE '.$tablename.'
381  SET ';
382  $is_first = true;
383  foreach ($set_fields as $key => $value)
384  {
385    $separator = $is_first ? '' : ",\n    ";
386
387    if (isset($value) and $value !== '')
388    {
389      $query.= $separator.$key.' = \''.$value.'\'';
390    }
391    else
392    {
393      if ( $flags & MASS_UPDATES_SKIP_EMPTY )
394        continue; // next field
395      $query.= "$separator$key = NULL";
396    }
397    $is_first = false;
398  }
399  if (!$is_first)
400  {// only if one field at least updated
401    $query.= '
402  WHERE ';
403    $is_first = true;
404    foreach ($where_fields as $key => $value)
405    {
406      if (!$is_first)
407      {
408        $query.= ' AND ';
409      }
410      if ( isset($value) )
411      {
412        $query.= $key.' = \''.$value.'\'';
413      }
414      else
415      {
416        $query.= $key.' IS NULL';
417      }
418      $is_first = false;
419    }
420    pwg_query($query);
421  }
422}
423
424
425/**
426 * inserts multiple lines in a table
427 *
428 * @param string table_name
429 * @param array dbfields
430 * @param array inserts
431 * @return void
432 */
433function mass_inserts($table_name, $dbfields, $datas, $options=array())
434{
435  $ignore = '';
436  if (isset($options['ignore']) and $options['ignore'])
437  {
438    $ignore = 'IGNORE';
439  }
440 
441  if (count($datas) != 0)
442  {
443    $first = true;
444
445    $query = 'SHOW VARIABLES LIKE \'max_allowed_packet\'';
446    list(, $packet_size) = pwg_db_fetch_row(pwg_query($query));
447    $packet_size = $packet_size - 2000; // The last list of values MUST not exceed 2000 character*/
448    $query = '';
449
450    foreach ($datas as $insert)
451    {
452      if (strlen($query) >= $packet_size)
453      {
454        pwg_query($query);
455        $first = true;
456      }
457
458      if ($first)
459      {
460        $query = '
461INSERT '.$ignore.' INTO '.$table_name.'
462  ('.implode(',', $dbfields).')
463  VALUES';
464        $first = false;
465      }
466      else
467      {
468        $query .= '
469  , ';
470      }
471
472      $query .= '(';
473      foreach ($dbfields as $field_id => $dbfield)
474      {
475        if ($field_id > 0)
476        {
477          $query .= ',';
478        }
479
480        if (!isset($insert[$dbfield]) or $insert[$dbfield] === '')
481        {
482          $query .= 'NULL';
483        }
484        else
485        {
486          $query .= "'".$insert[$dbfield]."'";
487        }
488      }
489      $query .= ')';
490    }
491    pwg_query($query);
492  }
493}
494
495/**
496 * inserts one line in a table
497 *
498 * @param string table_name
499 * @param array dbfields
500 * @param array insert
501 * @return void
502 */
503function single_insert($table_name, $data)
504{
505  if (count($data) != 0)
506  {
507    $query = '
508INSERT INTO '.$table_name.'
509  ('.implode(',', array_keys($data)).')
510  VALUES';
511
512    $query .= '(';
513    $is_first = true;
514    foreach ($data as $key => $value)
515    {
516      if (!$is_first)
517      {
518        $query .= ',';
519      }
520      else
521      {
522        $is_first = false;
523      }
524     
525      if ($value === '')
526      {
527        $query .= 'NULL';
528      }
529      else
530      {
531        $query .= "'".$value."'";
532      }
533    }
534    $query .= ')';
535   
536    pwg_query($query);
537  }
538}
539
540/**
541 * Do maintenance on all PWG tables
542 *
543 * @return none
544 */
545function do_maintenance_all_tables()
546{
547  global $prefixeTable, $page;
548
549  $all_tables = array();
550
551  // List all tables
552  $query = 'SHOW TABLES LIKE \''.$prefixeTable.'%\'';
553  $result = pwg_query($query);
554  while ($row = pwg_db_fetch_row($result))
555  {
556    array_push($all_tables, $row[0]);
557  }
558
559  // Repair all tables
560  $query = 'REPAIR TABLE '.implode(', ', $all_tables);
561  $mysql_rc = pwg_query($query);
562
563  // Re-Order all tables
564  foreach ($all_tables as $table_name)
565  {
566    $all_primary_key = array();
567
568    $query = 'DESC '.$table_name.';';
569    $result = pwg_query($query);
570    while ($row = pwg_db_fetch_assoc($result))
571    {
572      if ($row['Key'] == 'PRI')
573      {
574        array_push($all_primary_key, $row['Field']);
575      }
576    }
577
578    if (count($all_primary_key) != 0)
579    {
580      $query = 'ALTER TABLE '.$table_name.' ORDER BY '.implode(', ', $all_primary_key).';';
581      $mysql_rc = $mysql_rc && pwg_query($query);
582    }
583  }
584
585  // Optimize all tables
586  $query = 'OPTIMIZE TABLE '.implode(', ', $all_tables);
587  $mysql_rc = $mysql_rc && pwg_query($query);
588  if ($mysql_rc)
589  {
590    array_push(
591          $page['infos'],
592          l10n('All optimizations have been successfully completed.')
593          );
594  }
595  else
596  {
597    array_push(
598          $page['errors'],
599          l10n('Optimizations have been completed with some errors.')
600          );
601  }
602}
603
604function pwg_db_concat($array)
605{
606  $string = implode($array, ',');
607  return 'CONCAT('. $string.')';
608}
609
610function pwg_db_concat_ws($array, $separator)
611{
612  $string = implode($array, ',');
613  return 'CONCAT_WS(\''.$separator.'\','. $string.')';
614}
615
616function pwg_db_cast_to_text($string)
617{
618  return $string;
619}
620
621/**
622 * returns an array containing the possible values of an enum field
623 *
624 * @param string tablename
625 * @param string fieldname
626 */
627function get_enums($table, $field)
628{
629  // retrieving the properties of the table. Each line represents a field :
630  // columns are 'Field', 'Type'
631  $result = pwg_query('desc '.$table);
632  while ($row = pwg_db_fetch_assoc($result))
633  {
634    // we are only interested in the the field given in parameter for the
635    // function
636    if ($row['Field'] == $field)
637    {
638      // retrieving possible values of the enum field
639      // enum('blue','green','black')
640      $options = explode(',', substr($row['Type'], 5, -1));
641      foreach ($options as $i => $option)
642      {
643        $options[$i] = str_replace("'", '',$option);
644      }
645    }
646  }
647  pwg_db_free_result($result);
648  return $options;
649}
650
651/**
652 * Smartly checks if a variable is equivalent to true or false
653 *
654 * @param mixed input
655 * @return bool
656 */
657function get_boolean($input)
658{
659  if ('false' === strtolower($input))
660  {
661    return false;
662  }
663
664  return (bool)$input;
665}
666
667/**
668 * returns boolean string 'true' or 'false' if the given var is boolean
669 *
670 * @param mixed $var
671 * @return mixed
672 */
673function boolean_to_string($var)
674{
675  if (is_bool($var))
676  {
677    return $var ? 'true' : 'false';
678  }
679  else
680  {
681    return $var;
682  }
683}
684
685/**
686 *
687 * interval and date functions
688 *
689 */
690
691function pwg_db_get_recent_period_expression($period, $date='CURRENT_DATE')
692{
693  if ($date!='CURRENT_DATE')
694  {
695    $date = '\''.$date.'\'';
696  }
697
698  return 'SUBDATE('.$date.',INTERVAL '.$period.' DAY)';
699}
700
701function pwg_db_get_recent_period($period, $date='CURRENT_DATE')
702{
703  $query = '
704SELECT '.pwg_db_get_recent_period_expression($period);
705  list($d) = pwg_db_fetch_row(pwg_query($query));
706
707  return $d;
708}
709
710function pwg_db_get_flood_period_expression($seconds)
711{
712  return 'SUBDATE(now(), INTERVAL '.$seconds.' SECOND)';
713}
714
715function pwg_db_get_hour($date) 
716{
717  return 'hour('.$date.')';
718}
719
720function pwg_db_get_date_YYYYMM($date)
721{
722  return 'DATE_FORMAT('.$date.', \'%Y%m\')';
723}
724
725function pwg_db_get_date_MMDD($date)
726{
727  return 'DATE_FORMAT('.$date.', \'%m%d\')';
728}
729
730function pwg_db_get_year($date)
731{
732  return 'YEAR('.$date.')';
733}
734
735function pwg_db_get_month($date)
736{
737  return 'MONTH('.$date.')';
738}
739
740function pwg_db_get_week($date, $mode=null)
741{
742  if ($mode)
743  {
744    return 'WEEK('.$date.', '.$mode.')';
745  }
746  else
747  {
748    return 'WEEK('.$date.')';
749  }
750}
751
752function pwg_db_get_dayofmonth($date)
753{
754  return 'DAYOFMONTH('.$date.')';
755}
756
757function pwg_db_get_dayofweek($date)
758{
759  return 'DAYOFWEEK('.$date.')';
760}
761
762function pwg_db_get_weekday($date)
763{
764  return 'WEEKDAY('.$date.')';
765}
766
767function pwg_db_date_to_ts($date) 
768{
769  return 'UNIX_TIMESTAMP('.$date.')';
770}
771
772// my_error returns (or send to standard output) the message concerning the
773// error occured for the last mysql query.
774function my_error($header, $die)
775{
776  $error = "[mysql error ".mysql_errno().'] '.mysql_error()."\n";
777  $error .= $header;
778
779  if ($die)
780  {
781    fatal_error($error);
782  }
783  echo("<pre>");
784  trigger_error($error, E_USER_WARNING);
785  echo("</pre>");
786}
787
788?>
Note: See TracBrowser for help on using the repository browser.