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