source: trunk/include/functions.inc.php @ 19703

Last change on this file since 19703 was 19703, checked in by plg, 11 years ago

update Piwigo headers to 2013 (the end of the world didn't occur as expected on r12922)

  • Property svn:eol-style set to LF
File size: 42.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
24include_once( PHPWG_ROOT_PATH .'include/functions_user.inc.php' );
25include_once( PHPWG_ROOT_PATH .'include/functions_cookie.inc.php' );
26include_once( PHPWG_ROOT_PATH .'include/functions_session.inc.php' );
27include_once( PHPWG_ROOT_PATH .'include/functions_category.inc.php' );
28include_once( PHPWG_ROOT_PATH .'include/functions_html.inc.php' );
29include_once( PHPWG_ROOT_PATH .'include/functions_tag.inc.php' );
30include_once( PHPWG_ROOT_PATH .'include/functions_url.inc.php' );
31include_once( PHPWG_ROOT_PATH .'include/functions_plugins.inc.php' );
32include_once( PHPWG_ROOT_PATH .'include/derivative_params.inc.php');
33include_once( PHPWG_ROOT_PATH .'include/derivative_std_params.inc.php');
34include_once( PHPWG_ROOT_PATH .'include/derivative.inc.php');
35require_once( PHPWG_ROOT_PATH .'include/smarty/libs/Smarty.class.php');
36include_once( PHPWG_ROOT_PATH .'include/template.class.php');
37
38//----------------------------------------------------------- generic functions
39
40/**
41 * stupidly returns the current microsecond since Unix epoch
42 */
43function micro_seconds()
44{
45  $t1 = explode(' ', microtime());
46  $t2 = explode('.', $t1[0]);
47  $t2 = $t1[1].substr($t2[1], 0, 6);
48  return $t2;
49}
50
51// The function get_moment returns a float value coresponding to the number
52// of seconds since the unix epoch (1st January 1970) and the microseconds
53// are precised : e.g. 1052343429.89276600
54function get_moment()
55{
56  return microtime(true);
57}
58
59// The function get_elapsed_time returns the number of seconds (with 3
60// decimals precision) between the start time and the end time given.
61function get_elapsed_time( $start, $end )
62{
63  return number_format( $end - $start, 3, '.', ' ').' s';
64}
65
66// - The replace_space function replaces space and '-' characters
67//   by their HTML equivalent  &nbsb; and &minus;
68// - The function does not replace characters in HTML tags
69// - This function was created because IE5 does not respect the
70//   CSS "white-space: nowrap;" property unless space and minus
71//   characters are replaced like this function does.
72// - Example :
73//                 <div class="foo">My friend</div>
74//               ( 01234567891111111111222222222233 )
75//               (           0123456789012345678901 )
76// becomes :
77//             <div class="foo">My&nbsp;friend</div>
78function replace_space( $string )
79{
80  //return $string;
81  $return_string = '';
82  // $remaining is the rest of the string where to replace spaces characters
83  $remaining = $string;
84  // $start represents the position of the next '<' character
85  // $end   represents the position of the next '>' character
86  ; // -> 0
87  $end   = strpos ( $remaining, '>' ); // -> 16
88  // as long as a '<' and his friend '>' are found, we loop
89  while ( ($start=strpos( $remaining, '<' )) !==false
90        and ($end=strpos( $remaining, '>' )) !== false )
91  {
92    // $treatment is the part of the string to treat
93    // In the first loop of our example, this variable is empty, but in the
94    // second loop, it equals 'My friend'
95    $treatment = substr ( $remaining, 0, $start );
96    // Replacement of ' ' by his equivalent '&nbsp;'
97    $treatment = str_replace( ' ', '&nbsp;', $treatment );
98    $treatment = str_replace( '-', '&minus;', $treatment );
99    // composing the string to return by adding the treated string and the
100    // following HTML tag -> 'My&nbsp;friend</div>'
101    $return_string.= $treatment.substr( $remaining, $start, $end-$start+1 );
102    // the remaining string is deplaced to the part after the '>' of this
103    // loop
104    $remaining = substr ( $remaining, $end + 1, strlen( $remaining ) );
105  }
106  $treatment = str_replace( ' ', '&nbsp;', $remaining );
107  $treatment = str_replace( '-', '&minus;', $treatment );
108  $return_string.= $treatment;
109
110  return $return_string;
111}
112
113// get_extension returns the part of the string after the last "."
114function get_extension( $filename )
115{
116  return substr( strrchr( $filename, '.' ), 1, strlen ( $filename ) );
117}
118
119// get_filename_wo_extension returns the part of the string before the last
120// ".".
121// get_filename_wo_extension( 'test.tar.gz' ) -> 'test.tar'
122function get_filename_wo_extension( $filename )
123{
124  $pos = strrpos( $filename, '.' );
125  return ($pos===false) ? $filename : substr( $filename, 0, $pos);
126}
127
128define('MKGETDIR_NONE', 0);
129define('MKGETDIR_RECURSIVE', 1);
130define('MKGETDIR_DIE_ON_ERROR', 2);
131define('MKGETDIR_PROTECT_INDEX', 4);
132define('MKGETDIR_PROTECT_HTACCESS', 8);
133define('MKGETDIR_DEFAULT', 7);
134/**
135 * creates directory if not exists; ensures that directory is writable
136 * @param:
137 *  string $dir
138 *  int $flags combination of MKGETDIR_xxx
139 * @return bool false on error else true
140 */
141function mkgetdir($dir, $flags=MKGETDIR_DEFAULT)
142{
143  if ( !is_dir($dir) )
144  {
145    global $conf;
146    if (substr(PHP_OS, 0, 3) == 'WIN')
147    {
148      $dir = str_replace('/', DIRECTORY_SEPARATOR, $dir);
149    }
150    $umask = umask(0);
151    $mkd = @mkdir($dir, $conf['chmod_value'], ($flags&MKGETDIR_RECURSIVE) ? true:false );
152    umask($umask);
153    if ($mkd==false)
154    {
155      !($flags&MKGETDIR_DIE_ON_ERROR) or fatal_error( "$dir ".l10n('no write access'));
156      return false;
157    }
158    if( $flags&MKGETDIR_PROTECT_HTACCESS )
159    {
160      $file = $dir.'/.htaccess';
161      file_exists($file) or @file_put_contents( $file, 'deny from all' );
162    }
163    if( $flags&MKGETDIR_PROTECT_INDEX )
164    {
165      $file = $dir.'/index.htm';
166      file_exists($file) or @file_put_contents( $file, 'Not allowed!' );
167    }
168  }
169  if ( !is_writable($dir) )
170  {
171    !($flags&MKGETDIR_DIE_ON_ERROR) or fatal_error( "$dir ".l10n('no write access'));
172    return false;
173  }
174  return true;
175}
176
177/* Returns true if the string appears to be encoded in UTF-8. (from wordpress)
178 * @param string Str
179 */
180function seems_utf8($Str) {
181  // OBSOLETE !!!
182  return qualify_utf8($Str) >= 0;
183}
184
185/* returns 0 if $str is Ascii, 1 if utf-8, -1 otherwise */
186function qualify_utf8($Str)
187{
188  $ret = 0;
189  for ($i=0; $i<strlen($Str); $i++) {
190    if (ord($Str[$i]) < 0x80) continue; # 0bbbbbbb
191    $ret = 1;
192    if ((ord($Str[$i]) & 0xE0) == 0xC0) $n=1; # 110bbbbb
193    elseif ((ord($Str[$i]) & 0xF0) == 0xE0) $n=2; # 1110bbbb
194    elseif ((ord($Str[$i]) & 0xF8) == 0xF0) $n=3; # 11110bbb
195    elseif ((ord($Str[$i]) & 0xFC) == 0xF8) $n=4; # 111110bb
196    elseif ((ord($Str[$i]) & 0xFE) == 0xFC) $n=5; # 1111110b
197    else return -1; # Does not match any model
198    for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ?
199      if ((++$i == strlen($Str)) || ((ord($Str[$i]) & 0xC0) != 0x80))
200        return -1;
201    }
202  }
203  return $ret;
204}
205
206/* Remove accents from a UTF-8 or ISO-859-1 string (from wordpress)
207 * @param string sstring - an UTF-8 or ISO-8859-1 string
208 */
209function remove_accents($string)
210{
211  $utf = qualify_utf8($string);
212  if ( $utf == 0 )
213    return $string; // ascii
214
215  if ( $utf > 0 ) {
216    $chars = array(
217    // Decompositions for Latin-1 Supplement
218    "\xc3\x80"=>'A', "\xc3\x81"=>'A',
219    "\xc3\x82"=>'A', "\xc3\x83"=>'A',
220    "\xc3\x84"=>'A', "\xc3\x85"=>'A',
221    "\xc3\x87"=>'C', "\xc3\x88"=>'E',
222    "\xc3\x89"=>'E', "\xc3\x8a"=>'E',
223    "\xc3\x8b"=>'E', "\xc3\x8c"=>'I',
224    "\xc3\x8d"=>'I', "\xc3\x8e"=>'I',
225    "\xc3\x8f"=>'I', "\xc3\x91"=>'N',
226    "\xc3\x92"=>'O', "\xc3\x93"=>'O',
227    "\xc3\x94"=>'O', "\xc3\x95"=>'O',
228    "\xc3\x96"=>'O', "\xc3\x99"=>'U',
229    "\xc3\x9a"=>'U', "\xc3\x9b"=>'U',
230    "\xc3\x9c"=>'U', "\xc3\x9d"=>'Y',
231    "\xc3\x9f"=>'s', "\xc3\xa0"=>'a',
232    "\xc3\xa1"=>'a', "\xc3\xa2"=>'a',
233    "\xc3\xa3"=>'a', "\xc3\xa4"=>'a',
234    "\xc3\xa5"=>'a', "\xc3\xa7"=>'c',
235    "\xc3\xa8"=>'e', "\xc3\xa9"=>'e',
236    "\xc3\xaa"=>'e', "\xc3\xab"=>'e',
237    "\xc3\xac"=>'i', "\xc3\xad"=>'i',
238    "\xc3\xae"=>'i', "\xc3\xaf"=>'i',
239    "\xc3\xb1"=>'n', "\xc3\xb2"=>'o',
240    "\xc3\xb3"=>'o', "\xc3\xb4"=>'o',
241    "\xc3\xb5"=>'o', "\xc3\xb6"=>'o',
242    "\xc3\xb9"=>'u', "\xc3\xba"=>'u',
243    "\xc3\xbb"=>'u', "\xc3\xbc"=>'u',
244    "\xc3\xbd"=>'y', "\xc3\xbf"=>'y',
245    // Decompositions for Latin Extended-A
246    "\xc4\x80"=>'A', "\xc4\x81"=>'a',
247    "\xc4\x82"=>'A', "\xc4\x83"=>'a',
248    "\xc4\x84"=>'A', "\xc4\x85"=>'a',
249    "\xc4\x86"=>'C', "\xc4\x87"=>'c',
250    "\xc4\x88"=>'C', "\xc4\x89"=>'c',
251    "\xc4\x8a"=>'C', "\xc4\x8b"=>'c',
252    "\xc4\x8c"=>'C', "\xc4\x8d"=>'c',
253    "\xc4\x8e"=>'D', "\xc4\x8f"=>'d',
254    "\xc4\x90"=>'D', "\xc4\x91"=>'d',
255    "\xc4\x92"=>'E', "\xc4\x93"=>'e',
256    "\xc4\x94"=>'E', "\xc4\x95"=>'e',
257    "\xc4\x96"=>'E', "\xc4\x97"=>'e',
258    "\xc4\x98"=>'E', "\xc4\x99"=>'e',
259    "\xc4\x9a"=>'E', "\xc4\x9b"=>'e',
260    "\xc4\x9c"=>'G', "\xc4\x9d"=>'g',
261    "\xc4\x9e"=>'G', "\xc4\x9f"=>'g',
262    "\xc4\xa0"=>'G', "\xc4\xa1"=>'g',
263    "\xc4\xa2"=>'G', "\xc4\xa3"=>'g',
264    "\xc4\xa4"=>'H', "\xc4\xa5"=>'h',
265    "\xc4\xa6"=>'H', "\xc4\xa7"=>'h',
266    "\xc4\xa8"=>'I', "\xc4\xa9"=>'i',
267    "\xc4\xaa"=>'I', "\xc4\xab"=>'i',
268    "\xc4\xac"=>'I', "\xc4\xad"=>'i',
269    "\xc4\xae"=>'I', "\xc4\xaf"=>'i',
270    "\xc4\xb0"=>'I', "\xc4\xb1"=>'i',
271    "\xc4\xb2"=>'IJ', "\xc4\xb3"=>'ij',
272    "\xc4\xb4"=>'J', "\xc4\xb5"=>'j',
273    "\xc4\xb6"=>'K', "\xc4\xb7"=>'k',
274    "\xc4\xb8"=>'k', "\xc4\xb9"=>'L',
275    "\xc4\xba"=>'l', "\xc4\xbb"=>'L',
276    "\xc4\xbc"=>'l', "\xc4\xbd"=>'L',
277    "\xc4\xbe"=>'l', "\xc4\xbf"=>'L',
278    "\xc5\x80"=>'l', "\xc5\x81"=>'L',
279    "\xc5\x82"=>'l', "\xc5\x83"=>'N',
280    "\xc5\x84"=>'n', "\xc5\x85"=>'N',
281    "\xc5\x86"=>'n', "\xc5\x87"=>'N',
282    "\xc5\x88"=>'n', "\xc5\x89"=>'N',
283    "\xc5\x8a"=>'n', "\xc5\x8b"=>'N',
284    "\xc5\x8c"=>'O', "\xc5\x8d"=>'o',
285    "\xc5\x8e"=>'O', "\xc5\x8f"=>'o',
286    "\xc5\x90"=>'O', "\xc5\x91"=>'o',
287    "\xc5\x92"=>'OE', "\xc5\x93"=>'oe',
288    "\xc5\x94"=>'R', "\xc5\x95"=>'r',
289    "\xc5\x96"=>'R', "\xc5\x97"=>'r',
290    "\xc5\x98"=>'R', "\xc5\x99"=>'r',
291    "\xc5\x9a"=>'S', "\xc5\x9b"=>'s',
292    "\xc5\x9c"=>'S', "\xc5\x9d"=>'s',
293    "\xc5\x9e"=>'S', "\xc5\x9f"=>'s',
294    "\xc5\xa0"=>'S', "\xc5\xa1"=>'s',
295    "\xc5\xa2"=>'T', "\xc5\xa3"=>'t',
296    "\xc5\xa4"=>'T', "\xc5\xa5"=>'t',
297    "\xc5\xa6"=>'T', "\xc5\xa7"=>'t',
298    "\xc5\xa8"=>'U', "\xc5\xa9"=>'u',
299    "\xc5\xaa"=>'U', "\xc5\xab"=>'u',
300    "\xc5\xac"=>'U', "\xc5\xad"=>'u',
301    "\xc5\xae"=>'U', "\xc5\xaf"=>'u',
302    "\xc5\xb0"=>'U', "\xc5\xb1"=>'u',
303    "\xc5\xb2"=>'U', "\xc5\xb3"=>'u',
304    "\xc5\xb4"=>'W', "\xc5\xb5"=>'w',
305    "\xc5\xb6"=>'Y', "\xc5\xb7"=>'y',
306    "\xc5\xb8"=>'Y', "\xc5\xb9"=>'Z',
307    "\xc5\xba"=>'z', "\xc5\xbb"=>'Z',
308    "\xc5\xbc"=>'z', "\xc5\xbd"=>'Z',
309    "\xc5\xbe"=>'z', "\xc5\xbf"=>'s',
310    // Decompositions for Latin Extended-B
311    "\xc8\x98"=>'S', "\xc8\x99"=>'s',
312    "\xc8\x9a"=>'T', "\xc8\x9b"=>'t',
313    // Euro Sign
314    "\xe2\x82\xac"=>'E',
315    // GBP (Pound) Sign
316    "\xc2\xa3"=>'');
317
318    $string = strtr($string, $chars);
319  } else {
320    // Assume ISO-8859-1 if not UTF-8
321    $chars['in'] = chr(128).chr(131).chr(138).chr(142).chr(154).chr(158)
322      .chr(159).chr(162).chr(165).chr(181).chr(192).chr(193).chr(194)
323      .chr(195).chr(196).chr(197).chr(199).chr(200).chr(201).chr(202)
324      .chr(203).chr(204).chr(205).chr(206).chr(207).chr(209).chr(210)
325      .chr(211).chr(212).chr(213).chr(214).chr(216).chr(217).chr(218)
326      .chr(219).chr(220).chr(221).chr(224).chr(225).chr(226).chr(227)
327      .chr(228).chr(229).chr(231).chr(232).chr(233).chr(234).chr(235)
328      .chr(236).chr(237).chr(238).chr(239).chr(241).chr(242).chr(243)
329      .chr(244).chr(245).chr(246).chr(248).chr(249).chr(250).chr(251)
330      .chr(252).chr(253).chr(255);
331
332    $chars['out'] = "EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy";
333
334    $string = strtr($string, $chars['in'], $chars['out']);
335    $double_chars['in'] = array(chr(140), chr(156), chr(198), chr(208), chr(222), chr(223), chr(230), chr(240), chr(254));
336    $double_chars['out'] = array('OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th');
337    $string = str_replace($double_chars['in'], $double_chars['out'], $string);
338  }
339
340  return $string;
341}
342
343if (function_exists('mb_strtolower') && defined('PWG_CHARSET'))
344{
345  function transliterate($term)
346  {
347    return remove_accents( mb_strtolower($term, PWG_CHARSET) );
348  }
349}
350else
351{
352  function transliterate($term)
353  {
354    return remove_accents( strtolower($term) );
355  }
356}
357
358
359
360/**
361 * simplify a string to insert it into an URL
362 *
363 * @param string
364 * @return string
365 */
366function str2url($str)
367{
368  $str = $safe = transliterate($str);
369  $str = preg_replace('/[^\x80-\xffa-z0-9_\s\'\:\/\[\],-]/','',$str);
370  $str = preg_replace('/[\s\'\:\/\[\],-]+/',' ',trim($str));
371  $res = str_replace(' ','_',$str);
372
373  if (empty($res))
374  {
375    $res = str_replace(' ','_', $safe);
376  }
377
378  return $res;
379}
380
381//-------------------------------------------- Piwigo specific functions
382
383/**
384 * returns an array with a list of {language_code => language_name}
385 *
386 * @returns array
387 */
388function get_languages()
389{
390  $query = '
391SELECT id, name
392  FROM '.LANGUAGES_TABLE.'
393  ORDER BY name ASC
394;';
395  $result = pwg_query($query);
396
397  $languages = array();
398  while ($row = pwg_db_fetch_assoc($result))
399  {
400    if (is_dir(PHPWG_ROOT_PATH.'language/'.$row['id']))
401    {
402      $languages[ $row['id'] ] = $row['name'];
403    }
404  }
405
406  return $languages;
407}
408
409function pwg_log($image_id = null, $image_type = null)
410{
411  global $conf, $user, $page;
412
413  $do_log = $conf['log'];
414  if (is_admin())
415  {
416    $do_log = $conf['history_admin'];
417  }
418  if (is_a_guest())
419  {
420    $do_log = $conf['history_guest'];
421  }
422
423  $do_log = trigger_event('pwg_log_allowed', $do_log, $image_id, $image_type);
424
425  if (!$do_log)
426  {
427    return false;
428  }
429
430  $tags_string = null;
431  if ('tags'==@$page['section'])
432  {
433    $tags_string = implode(',', $page['tag_ids']);
434  }
435
436  $query = '
437INSERT INTO '.HISTORY_TABLE.'
438  (
439    date,
440    time,
441    user_id,
442    IP,
443    section,
444    category_id,
445    image_id,
446    image_type,
447    tag_ids
448  )
449  VALUES
450  (
451    CURRENT_DATE,
452    CURRENT_TIME,
453    '.$user['id'].',
454    \''.$_SERVER['REMOTE_ADDR'].'\',
455    '.(isset($page['section']) ? "'".$page['section']."'" : 'NULL').',
456    '.(isset($page['category']['id']) ? $page['category']['id'] : 'NULL').',
457    '.(isset($image_id) ? $image_id : 'NULL').',
458    '.(isset($image_type) ? "'".$image_type."'" : 'NULL').',
459    '.(isset($tags_string) ? "'".$tags_string."'" : 'NULL').'
460  )
461;';
462  pwg_query($query);
463
464  return true;
465}
466
467// format_date returns a formatted date for display. The date given in
468// argument must be an american format (2003-09-15). By option, you can show the time.
469// The output is internationalized.
470//
471// format_date( "2003-09-15", true ) -> "Monday 15 September 2003 21:52"
472function format_date($date, $show_time = false, $show_day_name = true)
473{
474  global $lang;
475
476  if (strpos($date, '0') == 0)
477  {
478    return l10n('N/A');
479  }
480
481  $ymdhms = array();
482  $tok = strtok( $date, '- :');
483  while ($tok !== false)
484  {
485    $ymdhms[] = $tok;
486    $tok = strtok('- :');
487  }
488
489  if ( count($ymdhms)<3 )
490  {
491    return false;
492  }
493
494  $formated_date = '';
495  // before 1970, Microsoft Windows can't mktime
496  if ($ymdhms[0] >= 1970 and $ymdhms[1] != 0 and $ymdhms[2] != 0)
497  {
498    // we ask midday because Windows think it's prior to midnight with a
499    // zero and refuse to work
500    $formated_date.= $lang['day'][date('w', mktime(12,0,0,$ymdhms[1],$ymdhms[2],$ymdhms[0]))];
501  }
502
503  if ($ymdhms[2] != 0)
504  {
505    $formated_date.= ' '.$ymdhms[2];
506  }
507
508  if ($ymdhms[1] != 0)
509  {
510    $formated_date.= ' '.$lang['month'][(int)$ymdhms[1]];
511  }
512
513  $formated_date.= ' '.$ymdhms[0];
514  if ($show_time and count($ymdhms)>=5 )
515  {
516    $formated_date.= ' '.$ymdhms[3].':'.$ymdhms[4];
517  }
518  return $formated_date;
519}
520
521/**
522 * Works out the time since the entry post, takes a an argument in unix time or datetime
523 */
524function time_since($original, $stop = 'minute')
525{
526  if (!is_int($original))
527  {
528    $ymdhms = array();
529    $tok = strtok($original, '- :');
530    while ($tok !== false)
531    {
532      $ymdhms[] = $tok;
533      $tok = strtok('- :');
534    }
535
536    if ($ymdhms[0] < 1970) return false;
537    if (!isset($ymdhms[3])) $ymdhms[3] = 12;
538    if (!isset($ymdhms[4])) $ymdhms[4] = 0;
539    if (!isset($ymdhms[5])) $ymdhms[5] = 0;
540    $original = mktime($ymdhms[3],$ymdhms[4],$ymdhms[5],$ymdhms[1],$ymdhms[2],$ymdhms[0]);
541  }
542
543  // array of time period chunks
544  $chunks = array(
545    'year' => 60 * 60 * 24 * 365,
546    'month' => 60 * 60 * 24 * 30,
547    'week' => 60 * 60 * 24 * 7,
548    'day' => 60 * 60 * 24,
549    'hour' => 60 * 60,
550    'minute' => 60,
551    'second' => 1,
552  );
553
554  $today = time(); /* Current unix time  */
555  $since = abs($today - $original);
556
557  $print = null;
558  foreach ($chunks as $name => $seconds)
559  {
560    if (($count = floor($since / $seconds)) != 0)
561    {
562      $print.= l10n_dec('%d '.$name, '%d '.$name.'s', $count);
563      $since-= $count*$seconds;
564    }
565    if (!empty($print) and $chunks[$name] <= $chunks[$stop])
566    {
567      break;
568    }
569  }
570
571  if ($today > $original)
572  {
573    $print = sprintf(l10n('%s ago'), $print);
574  }
575  else
576  {
577    $print = sprintf(l10n('%s in the future'), $print);
578  }
579
580  return $print;
581}
582
583function pwg_debug( $string )
584{
585  global $debug,$t2,$page;
586
587  $now = explode( ' ', microtime() );
588  $now2 = explode( '.', $now[0] );
589  $now2 = $now[1].'.'.$now2[1];
590  $time = number_format( $now2 - $t2, 3, '.', ' ').' s';
591  $debug .= '<p>';
592  $debug.= '['.$time.', ';
593  $debug.= $page['count_queries'].' queries] : '.$string;
594  $debug.= "</p>\n";
595}
596
597/**
598 * Redirects to the given URL (HTTP method)
599 *
600 * Note : once this function called, the execution doesn't go further
601 * (presence of an exit() instruction.
602 *
603 * @param string $url
604 * @return void
605 */
606function redirect_http( $url )
607{
608  if (ob_get_length () !== FALSE)
609  {
610    ob_clean();
611  }
612  // default url is on html format
613  $url = html_entity_decode($url);
614  header('Request-URI: '.$url);
615  header('Content-Location: '.$url);
616  header('Location: '.$url);
617  exit();
618}
619
620/**
621 * Redirects to the given URL (HTML method)
622 *
623 * Note : once this function called, the execution doesn't go further
624 * (presence of an exit() instruction.
625 *
626 * @param string $url
627 * @param string $title_msg
628 * @param integer $refreh_time
629 * @return void
630 */
631function redirect_html( $url , $msg = '', $refresh_time = 0)
632{
633  global $user, $template, $lang_info, $conf, $lang, $t2, $page, $debug;
634
635  if (!isset($lang_info) || !isset($template) )
636  {
637    $user = build_user( $conf['guest_id'], true);
638    load_language('common.lang');
639    trigger_action('loading_lang');
640    load_language('lang', PHPWG_ROOT_PATH.PWG_LOCAL_DIR, array('no_fallback'=>true, 'local'=>true) );
641    $template = new Template(PHPWG_ROOT_PATH.'themes', get_default_theme());
642  }
643        elseif (defined('IN_ADMIN') and IN_ADMIN)
644        {
645                $template = new Template(PHPWG_ROOT_PATH.'themes', get_default_theme());
646        }
647
648  if (empty($msg))
649  {
650    $msg = nl2br(l10n('Redirection...'));
651  }
652
653  $refresh = $refresh_time;
654  $url_link = $url;
655  $title = 'redirection';
656
657  $template->set_filenames( array( 'redirect' => 'redirect.tpl' ) );
658
659  include( PHPWG_ROOT_PATH.'include/page_header.php' );
660
661  $template->set_filenames( array( 'redirect' => 'redirect.tpl' ) );
662  $template->assign('REDIRECT_MSG', $msg);
663
664  $template->parse('redirect');
665
666  include( PHPWG_ROOT_PATH.'include/page_tail.php' );
667
668  exit();
669}
670
671/**
672 * Redirects to the given URL (Switch to HTTP method or HTML method)
673 *
674 * Note : once this function called, the execution doesn't go further
675 * (presence of an exit() instruction.
676 *
677 * @param string $url
678 * @param string $title_msg
679 * @param integer $refreh_time
680 * @return void
681 */
682function redirect( $url , $msg = '', $refresh_time = 0)
683{
684  global $conf;
685
686  // with RefeshTime <> 0, only html must be used
687  if ($conf['default_redirect_method']=='http'
688      and $refresh_time==0
689      and !headers_sent()
690    )
691  {
692    redirect_http($url);
693  }
694  else
695  {
696    redirect_html($url, $msg, $refresh_time);
697  }
698}
699
700/**
701 * returns $_SERVER['QUERY_STRING'] whitout keys given in parameters
702 *
703 * @param array $rejects
704 * @param boolean $escape - if true escape & to &amp; (for html)
705 * @returns string
706 */
707function get_query_string_diff($rejects=array(), $escape=true)
708{
709  if (empty($_SERVER['QUERY_STRING']))
710  {
711    return '';
712  }
713
714  $query_string = '';
715
716  $str = $_SERVER['QUERY_STRING'];
717  parse_str($str, $vars);
718
719  $is_first = true;
720  foreach ($vars as $key => $value)
721  {
722    if (!in_array($key, $rejects))
723    {
724      $query_string.= $is_first ? '?' : ($escape ? '&amp;' : '&' );
725      $is_first = false;
726      $query_string.= $key.'='.$value;
727    }
728  }
729
730  return $query_string;
731}
732
733function url_is_remote($url)
734{
735  if ( strncmp($url, 'http://', 7)==0
736    or strncmp($url, 'https://', 8)==0 )
737  {
738    return true;
739  }
740  return false;
741}
742
743/**
744 * returns available themes
745 */
746function get_pwg_themes($show_mobile=false)
747{
748  global $conf;
749
750  $themes = array();
751
752  $query = '
753SELECT
754    id,
755    name
756  FROM '.THEMES_TABLE.'
757  ORDER BY name ASC
758;';
759  $result = pwg_query($query);
760  while ($row = pwg_db_fetch_assoc($result))
761  {
762    if ($row['id'] == $conf['mobile_theme'])
763    {
764      if (!$show_mobile)
765      {
766        continue;
767      }
768      $row['name'] .= ' ('.l10n('Mobile').')';
769    }
770    if (check_theme_installed($row['id']))
771    {
772      $themes[ $row['id'] ] = $row['name'];
773    }
774  }
775
776  // plugins want remove some themes based on user status maybe?
777  $themes = trigger_event('get_pwg_themes', $themes);
778
779  return $themes;
780}
781
782function check_theme_installed($theme_id)
783{
784  global $conf;
785
786  return file_exists($conf['themes_dir'].'/'.$theme_id.'/'.'themeconf.inc.php');
787}
788
789/** Transforms an original path to its pwg representative */
790function original_to_representative($path, $representative_ext)
791{
792  $pos = strrpos($path, '/');
793  $path = substr_replace($path, 'pwg_representative/', $pos+1, 0);
794  $pos = strrpos($path, '.');
795  return substr_replace($path, $representative_ext, $pos+1);
796}
797
798/**
799 * @param element_info array containing element information from db;
800 * at least 'id', 'path' should be present
801 */
802function get_element_path($element_info)
803{
804  $path = $element_info['path'];
805  if ( !url_is_remote($path) )
806  {
807    $path = PHPWG_ROOT_PATH.$path;
808  }
809  return $path;
810}
811
812
813/**
814 * fill the current user caddie with given elements, if not already in
815 * caddie
816 *
817 * @param array elements_id
818 */
819function fill_caddie($elements_id)
820{
821  global $user;
822
823  $query = '
824SELECT element_id
825  FROM '.CADDIE_TABLE.'
826  WHERE user_id = '.$user['id'].'
827;';
828  $in_caddie = array_from_query($query, 'element_id');
829
830  $caddiables = array_diff($elements_id, $in_caddie);
831
832  $datas = array();
833
834  foreach ($caddiables as $caddiable)
835  {
836    array_push($datas, array('element_id' => $caddiable,
837                             'user_id' => $user['id']));
838  }
839
840  if (count($caddiables) > 0)
841  {
842    mass_inserts(CADDIE_TABLE, array('element_id','user_id'), $datas);
843  }
844}
845
846/**
847 * returns the element name from its filename
848 *
849 * @param string filename
850 * @return string name
851 */
852function get_name_from_file($filename)
853{
854  return str_replace('_',' ',get_filename_wo_extension($filename));
855}
856
857/**
858 * returns the corresponding value from $lang if existing. Else, the key is
859 * returned
860 *
861 * @param string key
862 * @return string
863 */
864function l10n($key)
865{
866  global $lang, $conf;
867
868  if ( ($val=@$lang[$key]) == null)
869  {
870    if ($conf['debug_l10n'] and !isset($lang[$key]) and !empty($key))
871    {
872      trigger_error('[l10n] language key "'.$key.'" is not defined', E_USER_WARNING);
873    }
874    $val = $key;
875  }
876  return $val;
877}
878
879/**
880 * returns the prinft value for strings including %d
881 * return is concorded with decimal value (singular, plural)
882 *
883 * @param singular string key
884 * @param plural string key
885 * @param decimal value
886 * @return string
887 */
888function l10n_dec($singular_fmt_key, $plural_fmt_key, $decimal)
889{
890  global $lang_info;
891
892  return
893    sprintf(
894      l10n((
895        (($decimal > 1) or ($decimal == 0 and $lang_info['zero_plural']))
896          ? $plural_fmt_key
897          : $singular_fmt_key
898        )), $decimal);
899}
900
901/*
902 * returns a single element to use with l10n_args
903 *
904 * @param string key: translation key
905 * @param mixed args: arguments to use on sprintf($key, args)
906 *   if args is a array, each values are used on sprintf
907 * @return string
908 */
909function get_l10n_args($key, $args)
910{
911  if (is_array($args))
912  {
913    $key_arg = array_merge(array($key), $args);
914  }
915  else
916  {
917    $key_arg = array($key,  $args);
918  }
919  return array('key_args' => $key_arg);
920}
921
922/*
923 * returns a string formated with l10n elements
924 *
925 * @param array $key_args: l10n_args element or array of l10n_args elements
926 * @param string $sep: used when translated elements are concatened
927 * @return string
928 */
929function l10n_args($key_args, $sep = "\n")
930{
931  if (is_array($key_args))
932  {
933    foreach ($key_args as $key => $element)
934    {
935      if (isset($result))
936      {
937        $result .= $sep;
938      }
939      else
940      {
941        $result = '';
942      }
943
944      if ($key === 'key_args')
945      {
946        array_unshift($element, l10n(array_shift($element))); // translate the key
947        $result .= call_user_func_array('sprintf', $element);
948      }
949      else
950      {
951        $result .= l10n_args($element, $sep);
952      }
953    }
954  }
955  else
956  {
957    fatal_error('l10n_args: Invalid arguments');
958  }
959
960  return $result;
961}
962
963/**
964 * returns the corresponding value from $themeconf if existing. Else, the
965 * key is returned
966 *
967 * @param string key
968 * @return string
969 */
970function get_themeconf($key)
971{
972  global $template;
973
974  return $template->get_themeconf($key);
975}
976
977/**
978 * Returns webmaster mail address depending on $conf['webmaster_id']
979 *
980 * @return string
981 */
982function get_webmaster_mail_address()
983{
984  global $conf;
985
986  $query = '
987SELECT '.$conf['user_fields']['email'].'
988  FROM '.USERS_TABLE.'
989  WHERE '.$conf['user_fields']['id'].' = '.$conf['webmaster_id'].'
990;';
991  list($email) = pwg_db_fetch_row(pwg_query($query));
992
993  return $email;
994}
995
996/**
997 * Add configuration parameters from database to global $conf array
998 *
999 * @return void
1000 */
1001function load_conf_from_db($condition = '')
1002{
1003  global $conf;
1004
1005  $query = '
1006SELECT param, value
1007 FROM '.CONFIG_TABLE.'
1008 '.(!empty($condition) ? 'WHERE '.$condition : '').'
1009;';
1010  $result = pwg_query($query);
1011
1012  if ((pwg_db_num_rows($result) == 0) and !empty($condition))
1013  {
1014    fatal_error('No configuration data');
1015  }
1016
1017  while ($row = pwg_db_fetch_assoc($result))
1018  {
1019    $val = isset($row['value']) ? $row['value'] : '';
1020    // If the field is true or false, the variable is transformed into a boolean value.
1021    if ($val == 'true')
1022    {
1023      $val = true;
1024    }
1025    elseif ($val == 'false')
1026    {
1027      $val = false;
1028    }
1029    $conf[ $row['param'] ] = $val;
1030  }
1031}
1032
1033function conf_update_param($param, $value)
1034{
1035  $query = '
1036SELECT
1037    param,
1038    value
1039  FROM '.CONFIG_TABLE.'
1040  WHERE param = \''.$param.'\'
1041;';
1042  $params = array_from_query($query, 'param');
1043
1044  if (count($params) == 0)
1045  {
1046    $query = '
1047INSERT
1048  INTO '.CONFIG_TABLE.'
1049  (param, value)
1050  VALUES(\''.$param.'\', \''.$value.'\')
1051;';
1052    pwg_query($query);
1053  }
1054  else
1055  {
1056    $query = '
1057UPDATE '.CONFIG_TABLE.'
1058  SET value = \''.$value.'\'
1059  WHERE param = \''.$param.'\'
1060;';
1061    pwg_query($query);
1062  }
1063}
1064
1065/**
1066 * Prepends and appends a string at each value of the given array.
1067 *
1068 * @param array
1069 * @param string prefix to each array values
1070 * @param string suffix to each array values
1071 */
1072function prepend_append_array_items($array, $prepend_str, $append_str)
1073{
1074  array_walk(
1075    $array,
1076    create_function('&$s', '$s = "'.$prepend_str.'".$s."'.$append_str.'";')
1077    );
1078
1079  return $array;
1080}
1081
1082/**
1083 * creates an hashed based on a query, this function is a very common
1084 * pattern used here. Among the selected columns fetched, choose one to be
1085 * the key, another one to be the value.
1086 *
1087 * @param string $query
1088 * @param string $keyname
1089 * @param string $valuename
1090 * @return array
1091 */
1092function simple_hash_from_query($query, $keyname, $valuename)
1093{
1094  $array = array();
1095
1096  $result = pwg_query($query);
1097  while ($row = pwg_db_fetch_assoc($result))
1098  {
1099    $array[ $row[$keyname] ] = $row[$valuename];
1100  }
1101
1102  return $array;
1103}
1104
1105/**
1106 * creates an hashed based on a query, this function is a very common
1107 * pattern used here. The key is given as parameter, the value is an associative
1108 * array.
1109 *
1110 * @param string $query
1111 * @param string $keyname
1112 * @return array
1113 */
1114function hash_from_query($query, $keyname)
1115{
1116  $array = array();
1117  $result = pwg_query($query);
1118  while ($row = pwg_db_fetch_assoc($result))
1119  {
1120    $array[ $row[$keyname] ] = $row;
1121  }
1122  return $array;
1123}
1124
1125/**
1126 * Return basename of the current script
1127 * Lower case convertion is applied on return value
1128 * Return value is without file extention ".php"
1129 *
1130 * @param void
1131 *
1132 * @return script basename
1133 */
1134function script_basename()
1135{
1136  global $conf;
1137
1138  foreach (array('SCRIPT_NAME', 'SCRIPT_FILENAME', 'PHP_SELF') as $value)
1139  {
1140    if (!empty($_SERVER[$value]))
1141    {
1142      $filename = strtolower($_SERVER[$value]);
1143      if ($conf['php_extension_in_urls'] and get_extension($filename)!=='php')
1144        continue;
1145      $basename = basename($filename, '.php');
1146      if (!empty($basename))
1147      {
1148        return $basename;
1149      }
1150    }
1151  }
1152  return '';
1153}
1154
1155/**
1156 * Return value for the current page define on $conf['filter_pages']
1157 * Îf value is not defined, default value are returned
1158 *
1159 * @param value name
1160 *
1161 * @return filter page value
1162 */
1163function get_filter_page_value($value_name)
1164{
1165  global $conf;
1166
1167  $page_name = script_basename();
1168
1169  if (isset($conf['filter_pages'][$page_name][$value_name]))
1170  {
1171    return $conf['filter_pages'][$page_name][$value_name];
1172  }
1173  else if (isset($conf['filter_pages']['default'][$value_name]))
1174  {
1175    return $conf['filter_pages']['default'][$value_name];
1176  }
1177  else
1178  {
1179    return null;
1180  }
1181}
1182
1183/**
1184 * returns the character set of data sent to browsers / received from forms
1185 */
1186function get_pwg_charset()
1187{
1188  $pwg_charset = 'utf-8';
1189  if (defined('PWG_CHARSET'))
1190  {
1191    $pwg_charset = PWG_CHARSET;
1192  }
1193  return $pwg_charset;
1194}
1195
1196/**
1197 * includes a language file or returns the content of a language file
1198 * availability of the file
1199 *
1200 * in descending order of preference:
1201 *   param language, user language, default language
1202 * Piwigo default language.
1203 *
1204 * @param string filename
1205 * @param string dirname
1206 * @param mixed options can contain
1207 *     language - language to load (if empty uses user language)
1208 *     return - if true the file content is returned otherwise the file is evaluated as php
1209 *     target_charset -
1210 *     no_fallback - the language must be respected
1211 *     local - if true, get local language file
1212 * @return boolean success status or a string if options['return'] is true
1213 */
1214function load_language($filename, $dirname = '',
1215    $options = array() )
1216{
1217  global $user;
1218
1219  if (! @$options['return'] )
1220  {
1221    $filename .= '.php'; //MAYBE to do .. load .po and .mo localization files
1222  }
1223  if (empty($dirname))
1224  {
1225    $dirname = PHPWG_ROOT_PATH;
1226  }
1227  $dirname .= 'language/';
1228
1229  $languages = array();
1230  if ( !empty($options['language']) )
1231  {
1232    $languages[] = $options['language'];
1233  }
1234  if ( !empty($user['language']) )
1235  {
1236    $languages[] = $user['language'];
1237  }
1238  if ( ! @$options['no_fallback'] )
1239  {
1240    if ( defined('PHPWG_INSTALLED') )
1241    {
1242      $languages[] = get_default_language();
1243    }
1244    $languages[] = PHPWG_DEFAULT_LANGUAGE;
1245  }
1246
1247  $languages = array_unique($languages);
1248
1249  /*Note: target charset is always utf-8
1250  if ( empty($options['target_charset']) )
1251  {
1252    $target_charset = get_pwg_charset();
1253  }
1254  else
1255  {
1256    $target_charset = $options['target_charset'];
1257  }
1258  $target_charset = strtolower($target_charset);*/
1259  $source_file    = '';
1260  foreach ($languages as $language)
1261  {
1262    $f = @$options['local'] ?
1263      $dirname.$language.'.'.$filename:
1264      $dirname.$language.'/'.$filename;
1265
1266    if (file_exists($f))
1267    {
1268      $source_file = $f;
1269      break;
1270    }
1271  }
1272
1273  if ( !empty($source_file) )
1274  {
1275    if (! @$options['return'] )
1276    {
1277      @include($source_file);
1278      $load_lang = @$lang;
1279      $load_lang_info = @$lang_info;
1280
1281      global $lang, $lang_info;
1282      if ( !isset($lang) ) $lang=array();
1283      if ( !isset($lang_info) ) $lang_info=array();
1284
1285      /* Note: target charset is always utf-8
1286      if ( 'utf-8'!=$target_charset)
1287      {
1288        if ( is_array($load_lang) )
1289        {
1290          foreach ($load_lang as $k => $v)
1291          {
1292            if ( is_array($v) )
1293            {
1294              $func = create_function('$v', 'return convert_charset($v, "utf-8", "'.$target_charset.'");' );
1295              $lang[$k] = array_map($func, $v);
1296            }
1297            else
1298              $lang[$k] = convert_charset($v, 'utf-8', $target_charset);
1299          }
1300        }
1301        if ( is_array($load_lang_info) )
1302        {
1303          foreach ($load_lang_info as $k => $v)
1304          {
1305            $lang_info[$k] = convert_charset($v, 'utf-8', $target_charset);
1306          }
1307        }
1308      }
1309      else
1310      {*/
1311        $lang = array_merge( $lang, (array)$load_lang );
1312        $lang_info = array_merge( $lang_info, (array)$load_lang_info );
1313      //}
1314      return true;
1315    }
1316    else
1317    {
1318      $content = @file_get_contents($source_file);
1319      //Note: target charset is always utf-8 $content = convert_charset($content, 'utf-8', $target_charset);
1320      return $content;
1321    }
1322  }
1323  return false;
1324}
1325
1326/**
1327 * converts a string from a character set to another character set
1328 * @param string str the string to be converted
1329 * @param string source_charset the character set in which the string is encoded
1330 * @param string dest_charset the destination character set
1331 */
1332function convert_charset($str, $source_charset, $dest_charset)
1333{
1334  if ($source_charset==$dest_charset)
1335    return $str;
1336  if ($source_charset=='iso-8859-1' and $dest_charset=='utf-8')
1337  {
1338    return utf8_encode($str);
1339  }
1340  if ($source_charset=='utf-8' and $dest_charset=='iso-8859-1')
1341  {
1342    return utf8_decode($str);
1343  }
1344  if (function_exists('iconv'))
1345  {
1346    return iconv($source_charset, $dest_charset, $str);
1347  }
1348  if (function_exists('mb_convert_encoding'))
1349  {
1350    return mb_convert_encoding( $str, $dest_charset, $source_charset );
1351  }
1352  return $str; //???
1353}
1354
1355/**
1356 * makes sure a index.htm protects the directory from browser file listing
1357 *
1358 * @param string dir directory
1359 */
1360function secure_directory($dir)
1361{
1362  $file = $dir.'/index.htm';
1363  if (!file_exists($file))
1364  {
1365    @file_put_contents($file, 'Not allowed!');
1366  }
1367}
1368
1369/**
1370 * returns a "secret key" that is to be sent back when a user posts a form
1371 *
1372 * @param int valid_after_seconds - key validity start time from now
1373 */
1374function get_ephemeral_key($valid_after_seconds, $aditionnal_data_to_hash = '')
1375{
1376        global $conf;
1377        $time = round(microtime(true), 1);
1378        return $time.':'.$valid_after_seconds.':'
1379                .hash_hmac(
1380                        'md5',
1381                        $time.substr($_SERVER['REMOTE_ADDR'],0,5).$valid_after_seconds.$aditionnal_data_to_hash,
1382                        $conf['secret_key']);
1383}
1384
1385function verify_ephemeral_key($key, $aditionnal_data_to_hash = '')
1386{
1387        global $conf;
1388        $time = microtime(true);
1389        $key = explode( ':', @$key );
1390        if ( count($key)!=3
1391                or $key[0]>$time-(float)$key[1] // page must have been retrieved more than X sec ago
1392                or $key[0]<$time-3600 // 60 minutes expiration
1393                or hash_hmac(
1394                          'md5', $key[0].substr($_SERVER['REMOTE_ADDR'],0,5).$key[1].$aditionnal_data_to_hash, $conf['secret_key']
1395                        ) != $key[2]
1396          )
1397        {
1398                return false;
1399        }
1400        return true;
1401}
1402
1403/**
1404 * return an array which will be sent to template to display navigation bar
1405 */
1406function create_navigation_bar($url, $nb_element, $start, $nb_element_page, $clean_url = false, $param_name='start')
1407{
1408  global $conf;
1409
1410  $navbar = array();
1411  $pages_around = $conf['paginate_pages_around'];
1412  $start_str = $clean_url ? '/'.$param_name.'-' : (strpos($url, '?')===false ? '?':'&amp;').$param_name.'=';
1413
1414  if (!isset($start) or !is_numeric($start) or (is_numeric($start) and $start < 0))
1415  {
1416    $start = 0;
1417  }
1418
1419  // navigation bar useful only if more than one page to display !
1420  if ($nb_element > $nb_element_page)
1421  {
1422    $url_start = $url.$start_str;
1423
1424    $cur_page = $navbar['CURRENT_PAGE'] = $start / $nb_element_page + 1;
1425    $maximum = ceil($nb_element / $nb_element_page);
1426
1427    $start = $nb_element_page * round( $start / $nb_element_page );
1428    $previous = $start - $nb_element_page;
1429    $next = $start + $nb_element_page;
1430    $last = ($maximum - 1) * $nb_element_page;
1431
1432    // link to first page and previous page?
1433    if ($cur_page != 1)
1434    {
1435      $navbar['URL_FIRST'] = $url;
1436      $navbar['URL_PREV'] = $previous > 0 ? $url_start.$previous : $url;
1437    }
1438    // link on next page and last page?
1439    if ($cur_page != $maximum)
1440    {
1441      $navbar['URL_NEXT'] = $url_start.($next < $last ? $next : $last);
1442      $navbar['URL_LAST'] = $url_start.$last;
1443    }
1444
1445    // pages to display
1446    $navbar['pages'] = array();
1447    $navbar['pages'][1] = $url;
1448    for ($i = max( floor($cur_page) - $pages_around , 2), $stop = min( ceil($cur_page) + $pages_around + 1, $maximum);
1449         $i < $stop; $i++)
1450    {
1451      $navbar['pages'][$i] = $url.$start_str.(($i - 1) * $nb_element_page);
1452    }
1453    $navbar['pages'][$maximum] = $url_start.$last;
1454  }
1455  return $navbar;
1456}
1457
1458/**
1459 * return an array which will be sent to template to display recent icon
1460 */
1461function get_icon($date, $is_child_date = false)
1462{
1463  global $cache, $user;
1464
1465  if (empty($date))
1466  {
1467    return false;
1468  }
1469
1470  if (!isset($cache['get_icon']['title']))
1471  {
1472    $cache['get_icon']['title'] = sprintf(
1473      l10n('photos posted during the last %d days'),
1474      $user['recent_period']
1475      );
1476  }
1477
1478  $icon = array(
1479    'TITLE' => $cache['get_icon']['title'],
1480    'IS_CHILD_DATE' => $is_child_date,
1481    );
1482
1483  if (isset($cache['get_icon'][$date]))
1484  {
1485    return $cache['get_icon'][$date] ? $icon : array();
1486  }
1487
1488  if (!isset($cache['get_icon']['sql_recent_date']))
1489  {
1490    // Use MySql date in order to standardize all recent "actions/queries"
1491    $cache['get_icon']['sql_recent_date'] = pwg_db_get_recent_period($user['recent_period']);
1492  }
1493
1494  $cache['get_icon'][$date] = $date > $cache['get_icon']['sql_recent_date'];
1495
1496  return $cache['get_icon'][$date] ? $icon : array();
1497}
1498
1499/**
1500 * check token comming from form posted or get params to prevent csrf attacks
1501 * if pwg_token is empty action doesn't require token
1502 * else pwg_token is compare to server token
1503 *
1504 * @return void access denied if token given is not equal to server token
1505 */
1506function check_pwg_token()
1507{
1508  if (!empty($_REQUEST['pwg_token']))
1509  {
1510    if (get_pwg_token() != $_REQUEST['pwg_token'])
1511    {
1512      access_denied();
1513    }
1514  }
1515  else
1516    bad_request('missing token');
1517}
1518
1519function get_pwg_token()
1520{
1521  global $conf;
1522
1523  return hash_hmac('md5', session_id(), $conf['secret_key']);
1524}
1525
1526/*
1527 * breaks the script execution if the given value doesn't match the given
1528 * pattern. This should happen only during hacking attempts.
1529 *
1530 * @param string param_name
1531 * @param array param_array
1532 * @param boolean is_array
1533 * @param string pattern
1534 *
1535 * @return void
1536 */
1537function check_input_parameter($param_name, $param_array, $is_array, $pattern)
1538{
1539  $param_value = null;
1540  if (isset($param_array[$param_name]))
1541  {
1542    $param_value = $param_array[$param_name];
1543  }
1544
1545  // it's ok if the input parameter is null
1546  if (empty($param_value))
1547  {
1548    return true;
1549  }
1550
1551  if ($is_array)
1552  {
1553    if (!is_array($param_value))
1554    {
1555      fatal_error('[Hacking attempt] the input parameter "'.$param_name.'" should be an array');
1556    }
1557
1558    foreach ($param_value as $item_to_check)
1559    {
1560      if (!preg_match($pattern, $item_to_check))
1561      {
1562        fatal_error('[Hacking attempt] an item is not valid in input parameter "'.$param_name.'"');
1563      }
1564    }
1565  }
1566  else
1567  {
1568    if (!preg_match($pattern, $param_value))
1569    {
1570      fatal_error('[Hacking attempt] the input parameter "'.$param_name.'" is not valid');
1571    }
1572  }
1573}
1574
1575
1576function get_privacy_level_options()
1577{
1578  global $conf;
1579
1580  $options = array();
1581  $label = '';
1582  foreach (array_reverse($conf['available_permission_levels']) as $level)
1583  {
1584    if (0 == $level)
1585    {
1586      $label = l10n('Everybody');
1587    }
1588    else
1589    {
1590      if (strlen($label))
1591      {
1592        $label .= ', ';
1593      }
1594      $label .= l10n( sprintf('Level %d',$level) );
1595    }
1596    $options[$level] = $label;
1597  }
1598  return $options;
1599}
1600
1601
1602/**
1603 * return the branch from the version. For example version 2.2.4 is for branch 2.2
1604 */
1605function get_branch_from_version($version)
1606{
1607  return implode('.', array_slice(explode('.', $version), 0, 2));
1608}
1609
1610/**
1611 * return the device type: mobile, tablet or desktop
1612 */
1613function get_device()
1614{
1615  $device = pwg_get_session_var('device');
1616
1617  if (is_null($device))
1618  {
1619    include_once(PHPWG_ROOT_PATH.'include/mdetect.php');
1620    $uagent_obj = new uagent_info();
1621    if ($uagent_obj->DetectSmartphone())
1622    {
1623      $device = 'mobile';
1624    }
1625    elseif ($uagent_obj->DetectTierTablet())
1626    {
1627      $device = 'tablet';
1628    }
1629    else
1630    {
1631      $device = 'desktop';
1632    }
1633    pwg_set_session_var('device', $device);
1634  }
1635
1636  return $device;
1637}
1638
1639/**
1640 * return true if mobile theme should be loaded
1641 */
1642function mobile_theme()
1643{
1644  global $conf;
1645
1646  if (empty($conf['mobile_theme']))
1647  {
1648    return false;
1649  }
1650
1651  if (isset($_GET['mobile']))
1652  {
1653    $is_mobile_theme = get_boolean($_GET['mobile']);
1654    pwg_set_session_var('mobile_theme', $is_mobile_theme);
1655  }
1656  else
1657  {
1658    $is_mobile_theme = pwg_get_session_var('mobile_theme');
1659  }
1660
1661  if (is_null($is_mobile_theme))
1662  {
1663    $is_mobile_theme = (get_device() == 'mobile');
1664    pwg_set_session_var('mobile_theme', $is_mobile_theme);
1665  }
1666
1667  return $is_mobile_theme;
1668}
1669
1670/**
1671 * check url format
1672 */
1673function url_check_format($url)
1674{
1675  if (version_compare(PHP_VERSION, '5.2.0') >= 0)
1676  {
1677    return filter_var($url, FILTER_VALIDATE_URL, FILTER_FLAG_SCHEME_REQUIRED | FILTER_FLAG_HOST_REQUIRED)!==false;
1678  }
1679  else
1680  {
1681    // http://mathiasbynens.be/demo/url-regex @imme_emosol
1682    return (bool)preg_match('@^https?://(-\.)?([^\s/?\.#-]+\.?)+(/[^\s]*)?$@iS', $url);
1683  }
1684}
1685
1686/**
1687 * check email format
1688 */
1689function email_check_format($mail_address)
1690{
1691  if (version_compare(PHP_VERSION, '5.2.0') >= 0)
1692  {
1693    return filter_var($mail_address, FILTER_VALIDATE_EMAIL)!==false;
1694  }
1695  else
1696  {
1697    $atom   = '[-a-z0-9!#$%&\'*+\\/=?^_`{|}~]';   // before  arobase
1698    $domain = '([a-z0-9]([-a-z0-9]*[a-z0-9]+)?)'; // domain name
1699    $regex = '/^' . $atom . '+' . '(\.' . $atom . '+)*' . '@' . '(' . $domain . '{1,63}\.)+' . $domain . '{2,63}$/i';
1700
1701    return (bool)preg_match($regex, $mail_address);
1702  }
1703}
1704?>
Note: See TracBrowser for help on using the repository browser.