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

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

feature:65 add fetch_array SQL functions

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