source: trunk/include/dblayer/functions_mysqli.inc.php @ 25018

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

remove all array_push (50% slower than []) + some changes missing for feature:2978

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