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

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

bug 2865: correct handle of sockets for mysqli

File size: 17.6 KB
RevLine 
[20462]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;
[22182]39
[22184]40  // $host can be:
[22182]41  //
42  // $host = localhost
43  // $host = 1.2.3.4:3405
44  // $host = /path/to/socket
45
46  $port = null;
47  $socket = null;
[20462]48 
[22182]49  if (strpos($host, '/') === 0)
50  {
[24346]51    $socket = $host;
[22182]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);
[20462]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
[20510]174function pwg_db_fetch_array($result)
175{
176  return $result->fetch_array();
177}
178
[20462]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
[21088]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
[20462]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        array_push($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    array_push($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        array_push($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    array_push(
639          $page['infos'],
640          l10n('All optimizations have been successfully completed.')
641          );
642  }
643  else
644  {
645    array_push(
646          $page['errors'],
647          l10n('Optimizations have been completed with some errors.')
648          );
649  }
650}
651
652function pwg_db_concat($array)
653{
654  $string = implode($array, ',');
655  return 'CONCAT('. $string.')';
656}
657
658function pwg_db_concat_ws($array, $separator)
659{
660  $string = implode($array, ',');
661  return 'CONCAT_WS(\''.$separator.'\','. $string.')';
662}
663
664function pwg_db_cast_to_text($string)
665{
666  return $string;
667}
668
669/**
670 * returns an array containing the possible values of an enum field
671 *
672 * @param string tablename
673 * @param string fieldname
674 */
675function get_enums($table, $field)
676{
677  // retrieving the properties of the table. Each line represents a field :
678  // columns are 'Field', 'Type'
679  $result = pwg_query('desc '.$table);
680  while ($row = pwg_db_fetch_assoc($result))
681  {
682    // we are only interested in the the field given in parameter for the
683    // function
684    if ($row['Field'] == $field)
685    {
686      // retrieving possible values of the enum field
687      // enum('blue','green','black')
688      $options = explode(',', substr($row['Type'], 5, -1));
689      foreach ($options as $i => $option)
690      {
691        $options[$i] = str_replace("'", '',$option);
692      }
693    }
694  }
695  pwg_db_free_result($result);
696  return $options;
697}
698
699/**
700 * Smartly checks if a variable is equivalent to true or false
701 *
702 * @param mixed input
703 * @return bool
704 */
705function get_boolean($input)
706{
707  if ('false' === strtolower($input))
708  {
709    return false;
710  }
711
712  return (bool)$input;
713}
714
715/**
716 * returns boolean string 'true' or 'false' if the given var is boolean
717 *
718 * @param mixed $var
719 * @return mixed
720 */
721function boolean_to_string($var)
722{
723  if (is_bool($var))
724  {
725    return $var ? 'true' : 'false';
726  }
727  else
728  {
729    return $var;
730  }
731}
732
733/**
734 *
735 * interval and date functions
736 *
737 */
738
739function pwg_db_get_recent_period_expression($period, $date='CURRENT_DATE')
740{
741  if ($date!='CURRENT_DATE')
742  {
743    $date = '\''.$date.'\'';
744  }
745
746  return 'SUBDATE('.$date.',INTERVAL '.$period.' DAY)';
747}
748
749function pwg_db_get_recent_period($period, $date='CURRENT_DATE')
750{
751  $query = '
752SELECT '.pwg_db_get_recent_period_expression($period);
753  list($d) = pwg_db_fetch_row(pwg_query($query));
754
755  return $d;
756}
757
758function pwg_db_get_flood_period_expression($seconds)
759{
760  return 'SUBDATE(now(), INTERVAL '.$seconds.' SECOND)';
761}
762
763function pwg_db_get_hour($date) 
764{
765  return 'hour('.$date.')';
766}
767
768function pwg_db_get_date_YYYYMM($date)
769{
770  return 'DATE_FORMAT('.$date.', \'%Y%m\')';
771}
772
773function pwg_db_get_date_MMDD($date)
774{
775  return 'DATE_FORMAT('.$date.', \'%m%d\')';
776}
777
778function pwg_db_get_year($date)
779{
780  return 'YEAR('.$date.')';
781}
782
783function pwg_db_get_month($date)
784{
785  return 'MONTH('.$date.')';
786}
787
788function pwg_db_get_week($date, $mode=null)
789{
790  if ($mode)
791  {
792    return 'WEEK('.$date.', '.$mode.')';
793  }
794  else
795  {
796    return 'WEEK('.$date.')';
797  }
798}
799
800function pwg_db_get_dayofmonth($date)
801{
802  return 'DAYOFMONTH('.$date.')';
803}
804
805function pwg_db_get_dayofweek($date)
806{
807  return 'DAYOFWEEK('.$date.')';
808}
809
810function pwg_db_get_weekday($date)
811{
812  return 'WEEKDAY('.$date.')';
813}
814
815function pwg_db_date_to_ts($date) 
816{
817  return 'UNIX_TIMESTAMP('.$date.')';
818}
819
820// my_error returns (or send to standard output) the message concerning the
821// error occured for the last mysql query.
822function my_error($header, $die)
823{
824  global $mysqli;
825 
826  $error = "[mysql error ".$mysqli->errno.'] '.$mysqli->error."\n";
827  $error .= $header;
828
829  if ($die)
830  {
831    fatal_error($error);
832  }
833  echo("<pre>");
834  trigger_error($error, E_USER_WARNING);
835  echo("</pre>");
836}
837
838?>
Note: See TracBrowser for help on using the repository browser.