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

Last change on this file since 20462 was 20462, checked in by mistic100, 11 years ago

feature:65 Add support for PHP mysqli extension, activated by default, remove returns of link_identifier

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