source: trunk/include/functions_user.inc.php @ 24998

Last change on this file since 24998 was 22879, checked in by rvelices, 12 years ago

bug 2097: wrong number of sub-albums
bug 2098: make number of direct sub-albums available for each user

  • Property svn:eol-style set to LF
File size: 38.2 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
24// validate_mail_address:
25//   o verifies whether the given mail address has the
26//     right format. ie someone@domain.com "someone" can contain ".", "-" or
27//     even "_". Exactly as "domain". The extension doesn't have to be
28//     "com". The mail address can also be empty.
29//   o check if address could be empty
30//   o check if address is not used by a other user
31// If the mail address doesn't correspond, an error message is returned.
32//
33function validate_mail_address($user_id, $mail_address)
34{
35  global $conf;
36
37  if (empty($mail_address) and
38      !($conf['obligatory_user_mail_address'] and
39      in_array(script_basename(), array('register', 'profile'))))
40  {
41    return '';
42  }
43
44  if ( !email_check_format($mail_address) )
45  {
46    return l10n('mail address must be like xxx@yyy.eee (example : jack@altern.org)');
47  }
48
49  if (defined("PHPWG_INSTALLED") and !empty($mail_address))
50  {
51    $query = '
52SELECT count(*)
53FROM '.USERS_TABLE.'
54WHERE upper('.$conf['user_fields']['email'].') = upper(\''.$mail_address.'\')
55'.(is_numeric($user_id) ? 'AND '.$conf['user_fields']['id'].' != \''.$user_id.'\'' : '').'
56;';
57    list($count) = pwg_db_fetch_row(pwg_query($query));
58    if ($count != 0)
59    {
60      return l10n('this email address is already in use');
61    }
62  }
63}
64
65// validate_login_case:
66//   o check if login is not used by a other user
67// If the login doesn't correspond, an error message is returned.
68//
69function validate_login_case($login)
70{
71  global $conf;
72
73  if (defined("PHPWG_INSTALLED"))
74  {
75    $query = "
76SELECT ".$conf['user_fields']['username']."
77FROM ".USERS_TABLE."
78WHERE LOWER(".stripslashes($conf['user_fields']['username']).") = '".strtolower($login)."'
79;";
80
81    $count = pwg_db_num_rows(pwg_query($query));
82
83    if ($count > 0)
84    {
85      return l10n('this login is already used');
86    }
87  }
88}
89/**
90 * For test on username case sensitivity
91 *
92 * @param : $username typed in by user for identification
93 *
94 * @return : $username found in database
95 *
96 */
97function search_case_username($username)
98{
99  global $conf;
100
101  $username_lo = strtolower($username);
102
103  $SCU_users = array();
104
105  $q = pwg_query("
106    SELECT ".$conf['user_fields']['username']." AS username
107    FROM `".USERS_TABLE."`;
108  ");
109  while ($r = pwg_db_fetch_assoc($q))
110   $SCU_users[$r['username']] = strtolower($r['username']);
111   // $SCU_users is now an associative table where the key is the account as
112   // registered in the DB, and the value is this same account, in lower case
113
114  $users_found = array_keys($SCU_users, $username_lo);
115  // $users_found is now a table of which the values are all the accounts
116  // which can be written in lowercase the same way as $username
117  if (count($users_found) != 1) // If ambiguous, don't allow lowercase writing
118   return $username; // but normal writing will work
119  else
120   return $users_found[0];
121}
122function register_user($login, $password, $mail_address,
123  $with_notification = true, $errors = array())
124{
125  global $conf;
126
127  if ($login == '')
128  {
129    $errors[] = l10n('Please, enter a login');
130  }
131  if (preg_match('/^.* $/', $login))
132  {
133    $errors[] = l10n('login mustn\'t end with a space character');
134  }
135  if (preg_match('/^ .*$/', $login))
136  {
137    $errors[] = l10n('login mustn\'t start with a space character');
138  }
139  if (get_userid($login))
140  {
141    $errors[] = l10n('this login is already used');
142  }
143  if ($login != strip_tags($login))
144  {
145    $errors[] = l10n('html tags are not allowed in login');
146  }
147  $mail_error = validate_mail_address(null, $mail_address);
148  if ('' != $mail_error)
149  {
150    $errors[] = $mail_error;
151  }
152
153  if ($conf['insensitive_case_logon'] == true)
154  {
155    $login_error = validate_login_case($login);
156    if ($login_error != '')
157    {
158      $errors[] = $login_error;
159    }
160  }
161
162  $errors = trigger_event('register_user_check',
163              $errors,
164              array(
165                'username'=>$login,
166                'password'=>$password,
167                'email'=>$mail_address,
168              )
169            );
170
171  // if no error until here, registration of the user
172  if (count($errors) == 0)
173  {
174    // what will be the inserted id ?
175    $query = '
176SELECT MAX('.$conf['user_fields']['id'].') + 1
177  FROM '.USERS_TABLE.'
178;';
179    list($next_id) = pwg_db_fetch_row(pwg_query($query));
180
181    $insert =
182      array(
183        $conf['user_fields']['id'] => $next_id,
184        $conf['user_fields']['username'] => pwg_db_real_escape_string($login),
185        $conf['user_fields']['password'] => $conf['password_hash']($password),
186        $conf['user_fields']['email'] => $mail_address
187        );
188
189    mass_inserts(USERS_TABLE, array_keys($insert), array($insert));
190
191    // Assign by default groups
192    {
193      $query = '
194SELECT id
195  FROM '.GROUPS_TABLE.'
196  WHERE is_default = \''.boolean_to_string(true).'\'
197  ORDER BY id ASC
198;';
199      $result = pwg_query($query);
200
201      $inserts = array();
202      while ($row = pwg_db_fetch_assoc($result))
203      {
204          $inserts[] = array(
205            'user_id' => $next_id,
206            'group_id' => $row['id']
207          );
208      }
209    }
210
211    if (count($inserts) != 0)
212    {
213      mass_inserts(USER_GROUP_TABLE, array('user_id', 'group_id'), $inserts);
214    }
215
216    $override = null;
217    if ($with_notification and $conf['browser_language'])
218    {
219      if ( !get_browser_language($override['language']) )
220        $override=null;
221    }
222    create_user_infos($next_id, $override);
223
224    if ($with_notification and $conf['email_admin_on_new_user'])
225    {
226      include_once(PHPWG_ROOT_PATH.'include/functions_mail.inc.php');
227      $admin_url = get_absolute_root_url()
228                   .'admin.php?page=user_list&username='.$login;
229
230      $keyargs_content = array
231      (
232        get_l10n_args('User: %s', stripslashes($login)),
233        get_l10n_args('Email: %s', $_POST['mail_address']),
234        get_l10n_args('', ''),
235        get_l10n_args('Admin: %s', $admin_url)
236      );
237
238      pwg_mail_notification_admins
239      (
240        get_l10n_args('Registration of %s', stripslashes($login)),
241        $keyargs_content
242      );
243    }
244
245    trigger_action('register_user',
246      array(
247        'id'=>$next_id,
248        'username'=>$login,
249        'email'=>$mail_address,
250       )
251      );
252  }
253
254  return $errors;
255}
256
257function build_user( $user_id, $use_cache )
258{
259  global $conf;
260
261  $user['id'] = $user_id;
262  $user = array_merge( $user, getuserdata($user_id, $use_cache) );
263
264  if ($user['id'] == $conf['guest_id'] and $user['status'] <> 'guest')
265  {
266    $user['status'] = 'guest';
267    $user['internal_status']['guest_must_be_guest'] = true;
268  }
269
270  // Check user theme
271  if (!isset($user['theme_name']))
272  {
273    $user['theme'] = get_default_theme();
274  }
275
276  return $user;
277}
278
279/**
280 * find informations related to the user identifier
281 *
282 * @param int user identifier
283 * @param boolean use_cache
284 * @param array
285 */
286function getuserdata($user_id, $use_cache)
287{
288  global $conf;
289
290  // retrieve basic user data
291  $query = '
292SELECT ';
293  $is_first = true;
294  foreach ($conf['user_fields'] as $pwgfield => $dbfield)
295  {
296    if ($is_first)
297    {
298      $is_first = false;
299    }
300    else
301    {
302      $query.= '
303     , ';
304    }
305    $query.= $dbfield.' AS '.$pwgfield;
306  }
307  $query.= '
308  FROM '.USERS_TABLE.'
309  WHERE '.$conf['user_fields']['id'].' = \''.$user_id.'\'';
310
311  $row = pwg_db_fetch_assoc(pwg_query($query));
312
313  // retrieve additional user data ?
314  if ($conf['external_authentification'])
315  {
316    $query = '
317SELECT
318    COUNT(1) AS counter
319  FROM '.USER_INFOS_TABLE.' AS ui
320    LEFT JOIN '.USER_CACHE_TABLE.' AS uc ON ui.user_id = uc.user_id
321    LEFT JOIN '.THEMES_TABLE.' AS t ON t.id = ui.theme
322  WHERE ui.user_id = '.$user_id.'
323  GROUP BY ui.user_id
324;';
325    list($counter) = pwg_db_fetch_row(pwg_query($query));
326    if ($counter != 1)
327    {
328      create_user_infos($user_id);
329    }
330  }
331
332  // retrieve user info
333  $query = '
334SELECT
335    ui.*,
336    uc.*,
337    t.name AS theme_name
338  FROM '.USER_INFOS_TABLE.' AS ui
339    LEFT JOIN '.USER_CACHE_TABLE.' AS uc ON ui.user_id = uc.user_id
340    LEFT JOIN '.THEMES_TABLE.' AS t ON t.id = ui.theme
341  WHERE ui.user_id = '.$user_id.'
342;';
343
344  $result = pwg_query($query);
345  $user_infos_row = pwg_db_fetch_assoc($result);
346
347  // then merge basic + additional user data
348  $userdata = array_merge($row, $user_infos_row);
349
350  foreach ($userdata as &$value)
351  {
352      // If the field is true or false, the variable is transformed into a boolean value.
353      if ($value == 'true')
354      {
355        $value = true;
356      }
357      elseif ($value == 'false')
358      {
359        $value = false;
360      }
361  }
362  unset($value);
363
364  if ($use_cache)
365  {
366    if (!isset($userdata['need_update'])
367        or !is_bool($userdata['need_update'])
368        or $userdata['need_update'] == true)
369    {
370      $userdata['cache_update_time'] = time();
371
372      // Set need update are done
373      $userdata['need_update'] = false;
374
375      $userdata['forbidden_categories'] =
376        calculate_permissions($userdata['id'], $userdata['status']);
377
378      /* now we build the list of forbidden images (this list does not contain
379      images that are not in at least an authorized category)*/
380      $query = '
381SELECT DISTINCT(id)
382  FROM '.IMAGES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON id=image_id
383  WHERE category_id NOT IN ('.$userdata['forbidden_categories'].')
384    AND level>'.$userdata['level'];
385      $forbidden_ids = array_from_query($query, 'id');
386
387      if ( empty($forbidden_ids) )
388      {
389        $forbidden_ids[] = 0;
390      }
391      $userdata['image_access_type'] = 'NOT IN'; //TODO maybe later
392      $userdata['image_access_list'] = implode(',',$forbidden_ids);
393
394
395      $query = '
396SELECT COUNT(DISTINCT(image_id)) as total
397  FROM '.IMAGE_CATEGORY_TABLE.'
398  WHERE category_id NOT IN ('.$userdata['forbidden_categories'].')
399    AND image_id '.$userdata['image_access_type'].' ('.$userdata['image_access_list'].')';
400      list($userdata['nb_total_images']) = pwg_db_fetch_row(pwg_query($query));
401
402
403      // now we update user cache categories
404      $user_cache_cats = get_computed_categories($userdata, null);
405      if ( !is_admin($userdata['status']) )
406      { // for non admins we forbid categories with no image (feature 1053)
407        $forbidden_ids = array();
408        foreach ($user_cache_cats as $cat)
409        {
410          if ($cat['count_images']==0)
411          {
412            $forbidden_ids[] = $cat['cat_id'];
413            remove_computed_category($user_cache_cats, $cat);
414          }
415        }
416        if ( !empty($forbidden_ids) )
417        {
418          if ( empty($userdata['forbidden_categories']) )
419          {
420            $userdata['forbidden_categories'] = implode(',', $forbidden_ids);
421          }
422          else
423          {
424            $userdata['forbidden_categories'] .= ','.implode(',', $forbidden_ids);
425          }
426        }
427      }
428
429      // delete user cache
430      $query = '
431DELETE FROM '.USER_CACHE_CATEGORIES_TABLE.'
432  WHERE user_id = '.$userdata['id'];
433      pwg_query($query);
434
435      // Due to concurrency issues, we ask MySQL to ignore errors on
436      // insert. This may happen when cache needs refresh and that Piwigo is
437      // called "very simultaneously".
438      mass_inserts
439      (
440        USER_CACHE_CATEGORIES_TABLE,
441        array
442        (
443          'user_id', 'cat_id',
444          'date_last', 'max_date_last', 'nb_images', 'count_images', 'nb_categories', 'count_categories'
445        ),
446        $user_cache_cats,
447        array('ignore' => true)
448      );
449
450
451      // update user cache
452      $query = '
453DELETE FROM '.USER_CACHE_TABLE.'
454  WHERE user_id = '.$userdata['id'];
455      pwg_query($query);
456
457      // for the same reason as user_cache_categories, we ignore error on
458      // this insert
459      $query = '
460INSERT IGNORE INTO '.USER_CACHE_TABLE.'
461  (user_id, need_update, cache_update_time, forbidden_categories, nb_total_images,
462    last_photo_date,
463    image_access_type, image_access_list)
464  VALUES
465  ('.$userdata['id'].',\''.boolean_to_string($userdata['need_update']).'\','
466  .$userdata['cache_update_time'].',\''
467  .$userdata['forbidden_categories'].'\','.$userdata['nb_total_images'].','.
468  (empty($userdata['last_photo_date']) ? 'NULL': '\''.$userdata['last_photo_date'].'\'').
469  ',\''.$userdata['image_access_type'].'\',\''.$userdata['image_access_list'].'\')';
470      pwg_query($query);
471    }
472  }
473
474  return $userdata;
475}
476
477/*
478 * deletes favorites of the current user if he's not allowed to see them
479 *
480 * @return void
481 */
482function check_user_favorites()
483{
484  global $user;
485
486  if ($user['forbidden_categories'] == '')
487  {
488    return;
489  }
490
491  // $filter['visible_categories'] and $filter['visible_images']
492  // must be not used because filter <> restriction
493  // retrieving images allowed : belonging to at least one authorized
494  // category
495  $query = '
496SELECT DISTINCT f.image_id
497  FROM '.FAVORITES_TABLE.' AS f INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic
498    ON f.image_id = ic.image_id
499  WHERE f.user_id = '.$user['id'].'
500'.get_sql_condition_FandF
501  (
502    array
503      (
504        'forbidden_categories' => 'ic.category_id',
505      ),
506    'AND'
507  ).'
508;';
509  $authorizeds = array_from_query($query, 'image_id');
510
511  $query = '
512SELECT image_id
513  FROM '.FAVORITES_TABLE.'
514  WHERE user_id = '.$user['id'].'
515;';
516  $favorites = array_from_query($query, 'image_id');
517
518  $to_deletes = array_diff($favorites, $authorizeds);
519  if (count($to_deletes) > 0)
520  {
521    $query = '
522DELETE FROM '.FAVORITES_TABLE.'
523  WHERE image_id IN ('.implode(',', $to_deletes).')
524    AND user_id = '.$user['id'].'
525;';
526    pwg_query($query);
527  }
528}
529
530/**
531 * calculates the list of forbidden categories for a given user
532 *
533 * Calculation is based on private categories minus categories authorized to
534 * the groups the user belongs to minus the categories directly authorized
535 * to the user. The list contains at least -1 to be compliant with queries
536 * such as "WHERE category_id NOT IN ($forbidden_categories)"
537 *
538 * @param int user_id
539 * @param string user_status
540 * @return string forbidden_categories
541 */
542function calculate_permissions($user_id, $user_status)
543{
544  $query = '
545SELECT id
546  FROM '.CATEGORIES_TABLE.'
547  WHERE status = \'private\'
548;';
549  $private_array = array_from_query($query, 'id');
550
551  // retrieve category ids directly authorized to the user
552  $query = '
553SELECT cat_id
554  FROM '.USER_ACCESS_TABLE.'
555  WHERE user_id = '.$user_id.'
556;';
557  $authorized_array = array_from_query($query, 'cat_id');
558
559  // retrieve category ids authorized to the groups the user belongs to
560  $query = '
561SELECT cat_id
562  FROM '.USER_GROUP_TABLE.' AS ug INNER JOIN '.GROUP_ACCESS_TABLE.' AS ga
563    ON ug.group_id = ga.group_id
564  WHERE ug.user_id = '.$user_id.'
565;';
566  $authorized_array =
567    array_merge(
568      $authorized_array,
569      array_from_query($query, 'cat_id')
570      );
571
572  // uniquify ids : some private categories might be authorized for the
573  // groups and for the user
574  $authorized_array = array_unique($authorized_array);
575
576  // only unauthorized private categories are forbidden
577  $forbidden_array = array_diff($private_array, $authorized_array);
578
579  // if user is not an admin, locked categories are forbidden
580  if (!is_admin($user_status))
581  {
582    $query = '
583SELECT id
584  FROM '.CATEGORIES_TABLE.'
585  WHERE visible = \'false\'
586;';
587    $result = pwg_query($query);
588    while ($row = pwg_db_fetch_assoc($result))
589    {
590      $forbidden_array[] = $row['id'];
591    }
592    $forbidden_array = array_unique($forbidden_array);
593  }
594
595  if ( empty($forbidden_array) )
596  {// at least, the list contains 0 value. This category does not exists so
597   // where clauses such as "WHERE category_id NOT IN(0)" will always be
598   // true.
599    $forbidden_array[] = 0;
600  }
601
602  return implode(',', $forbidden_array);
603}
604
605
606/*update counters with a category removal*/
607function remove_computed_category(&$cats, $cat)
608{
609  if ( isset( $cats[$cat['id_uppercat']] ) )
610  {
611    $parent = & $cats[ $cat['id_uppercat'] ];
612    $parent['nb_categories']--;
613
614    do
615    {
616
617      $parent['count_images'] -= $cat['nb_images'];
618      $parent['count_categories'] -= 1+$cat['count_categories'];
619
620      if ( !isset( $cats[$parent['id_uppercat']] ) )
621        break;
622      $parent = & $cats[$parent['id_uppercat']];
623    }
624    while (true);
625  }
626
627  unset($cats[$cat['cat_id']]);
628}
629
630/**
631 * get computed array of categories
632 *
633 * @param array userdata
634 * @param int filter_days number of recent days to filter on or null
635 * @return array
636 */
637function get_computed_categories(&$userdata, $filter_days=null)
638{
639  $query = 'SELECT c.id AS cat_id, id_uppercat';
640  // Count by date_available to avoid count null
641  $query .= ',
642  MAX(date_available) AS date_last, COUNT(date_available) AS nb_images
643FROM '.CATEGORIES_TABLE.' as c
644  LEFT JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON ic.category_id = c.id
645  LEFT JOIN '.IMAGES_TABLE.' AS i
646    ON ic.image_id = i.id
647      AND i.level<='.$userdata['level'];
648
649  if ( isset($filter_days) )
650  {
651    $query .= ' AND i.date_available > '.pwg_db_get_recent_period_expression($filter_days);
652  }
653
654  if ( !empty($userdata['forbidden_categories']) )
655  {
656    $query.= '
657  WHERE c.id NOT IN ('.$userdata['forbidden_categories'].')';
658  }
659
660  $query.= '
661  GROUP BY c.id';
662
663  $result = pwg_query($query);
664
665  $userdata['last_photo_date'] = null;
666  $cats = array();
667  while ($row = pwg_db_fetch_assoc($result))
668  {
669    $row['user_id'] = $userdata['id'];
670    $row['nb_categories'] = 0;
671    $row['count_categories'] = 0;
672    $row['count_images'] = (int)$row['nb_images'];
673    $row['max_date_last'] = $row['date_last'];
674    if ($row['date_last'] > $userdata['last_photo_date'])
675    {
676      $userdata['last_photo_date'] = $row['date_last'];
677    }
678
679    $cats[$row['cat_id']] = $row;
680  }
681
682  foreach ($cats as $cat)
683  {
684    if ( !isset( $cat['id_uppercat'] ) )
685      continue;
686
687    $parent = & $cats[ $cat['id_uppercat'] ];
688    $parent['nb_categories']++;
689
690    do
691    {
692      $parent['count_images'] += $cat['nb_images'];
693      $parent['count_categories']++;
694
695      if ((empty($parent['max_date_last'])) or ($parent['max_date_last'] < $cat['date_last']))
696      {
697        $parent['max_date_last'] = $cat['date_last'];
698      }
699
700      if ( !isset( $parent['id_uppercat'] ) )
701        break;
702      $parent = & $cats[$parent['id_uppercat']];
703    }
704    while (true);
705    unset($parent);
706  }
707
708  if ( isset($filter_days) )
709  {
710    foreach ($cats as $category)
711    {
712      if (empty($category['max_date_last']))
713      {
714        remove_computed_category($cats, $category);
715      }
716    }
717  }
718  return $cats;
719}
720
721/**
722 * returns user identifier thanks to his name, false if not found
723 *
724 * @param string username
725 * @param int user identifier
726 */
727function get_userid($username)
728{
729  global $conf;
730
731  $username = pwg_db_real_escape_string($username);
732
733  $query = '
734SELECT '.$conf['user_fields']['id'].'
735  FROM '.USERS_TABLE.'
736  WHERE '.$conf['user_fields']['username'].' = \''.$username.'\'
737;';
738  $result = pwg_query($query);
739
740  if (pwg_db_num_rows($result) == 0)
741  {
742    return false;
743  }
744  else
745  {
746    list($user_id) = pwg_db_fetch_row($result);
747    return $user_id;
748  }
749}
750
751function get_userid_by_email($email)
752{
753  global $conf;
754
755  $email = pwg_db_real_escape_string($email);
756
757  $query = '
758SELECT
759    '.$conf['user_fields']['id'].'
760  FROM '.USERS_TABLE.'
761  WHERE UPPER('.$conf['user_fields']['email'].') = UPPER(\''.$email.'\')
762;';
763  $result = pwg_query($query);
764
765  if (pwg_db_num_rows($result) == 0)
766  {
767    return false;
768  }
769  else
770  {
771    list($user_id) = pwg_db_fetch_row($result);
772    return $user_id;
773  }
774}
775
776/*
777 * Returns a array with default user value
778 *
779 * @param convert_str allows to convert string value if necessary
780 */
781function get_default_user_info($convert_str = true)
782{
783  global $cache, $conf;
784
785  if (!isset($cache['default_user']))
786  {
787    $query = '
788SELECT *
789  FROM '.USER_INFOS_TABLE.'
790  WHERE user_id = '.$conf['default_user_id'].'
791;';
792
793    $result = pwg_query($query);
794
795    if (pwg_db_num_rows($result) > 0)
796    {
797      $cache['default_user'] = pwg_db_fetch_assoc($result);
798
799      unset($cache['default_user']['user_id']);
800      unset($cache['default_user']['status']);
801      unset($cache['default_user']['registration_date']);
802    }
803    else
804    {
805      $cache['default_user'] = false;
806    }
807  }
808
809  if (is_array($cache['default_user']) and $convert_str)
810  {
811    $default_user = $cache['default_user'];
812    foreach ($default_user as &$value)
813    {
814      // If the field is true or false, the variable is transformed into a boolean value.
815      if ($value == 'true')
816      {
817        $value = true;
818      }
819      elseif ($value == 'false')
820      {
821        $value = false;
822      }
823    }
824    return $default_user;
825  }
826  else
827  {
828    return $cache['default_user'];
829  }
830}
831
832/*
833 * Returns a default user value
834 *
835 * @param value_name: name of value
836 * @param sos_value: value used if don't exist value
837 */
838function get_default_user_value($value_name, $sos_value)
839{
840  $default_user = get_default_user_info(true);
841  if ($default_user === false or empty($default_user[$value_name]))
842  {
843    return $sos_value;
844  }
845  else
846  {
847   return $default_user[$value_name];
848  }
849}
850
851/*
852 * Returns the default template value
853 *
854 */
855function get_default_theme()
856{
857  $theme = get_default_user_value('theme', PHPWG_DEFAULT_TEMPLATE);
858  if (check_theme_installed($theme))
859  {
860    return $theme;
861  }
862
863  // let's find the first available theme
864  $active_themes = get_pwg_themes();
865  foreach (array_keys(get_pwg_themes()) as $theme_id)
866  {
867    return $theme_id;
868  }
869}
870
871/*
872 * Returns the default language value
873 *
874 */
875function get_default_language()
876{
877  return get_default_user_value('language', PHPWG_DEFAULT_LANGUAGE);
878}
879
880/**
881  * Returns true if the browser language value is set into param $lang
882  *
883  */
884function get_browser_language(&$lang)
885{
886  $browser_language = substr(@$_SERVER["HTTP_ACCEPT_LANGUAGE"], 0, 2);
887  foreach (get_languages() as $language_code => $language_name)
888  {
889    if (substr($language_code, 0, 2) == $browser_language)
890    {
891      $lang = $language_code;
892      return true;
893    }
894  }
895  return false;
896}
897
898/**
899 * add user informations based on default values
900 *
901 * @param int user_id / array of user_if
902 * @param array of values used to override default user values
903 */
904function create_user_infos($arg_id, $override_values = null)
905{
906  global $conf;
907
908  if (is_array($arg_id))
909  {
910    $user_ids = $arg_id;
911  }
912  else
913  {
914    $user_ids = array();
915    if (is_numeric($arg_id))
916    {
917      $user_ids[] = $arg_id;
918    }
919  }
920
921  if (!empty($user_ids))
922  {
923    $inserts = array();
924    list($dbnow) = pwg_db_fetch_row(pwg_query('SELECT NOW();'));
925
926    $default_user = get_default_user_info(false);
927    if ($default_user === false)
928    {
929      // Default on structure are used
930      $default_user = array();
931    }
932
933    if (!is_null($override_values))
934    {
935      $default_user = array_merge($default_user, $override_values);
936    }
937
938    foreach ($user_ids as $user_id)
939    {
940      $level= isset($default_user['level']) ? $default_user['level'] : 0;
941      if ($user_id == $conf['webmaster_id'])
942      {
943        $status = 'webmaster';
944        $level = max( $conf['available_permission_levels'] );
945      }
946      else if (($user_id == $conf['guest_id']) or
947               ($user_id == $conf['default_user_id']))
948      {
949        $status = 'guest';
950      }
951      else
952      {
953        $status = 'normal';
954      }
955
956      $insert = array_merge(
957        $default_user,
958        array(
959          'user_id' => $user_id,
960          'status' => $status,
961          'registration_date' => $dbnow,
962          'level' => $level
963          ));
964
965      $inserts[] = $insert;
966    }
967
968    mass_inserts(USER_INFOS_TABLE, array_keys($inserts[0]), $inserts);
969  }
970}
971
972/**
973 * returns the auto login key or false on error
974 * @param int user_id
975 * @param time_t time
976 * @param string [out] username
977*/
978function calculate_auto_login_key($user_id, $time, &$username)
979{
980  global $conf;
981  $query = '
982SELECT '.$conf['user_fields']['username'].' AS username
983  , '.$conf['user_fields']['password'].' AS password
984FROM '.USERS_TABLE.'
985WHERE '.$conf['user_fields']['id'].' = '.$user_id;
986  $result = pwg_query($query);
987  if (pwg_db_num_rows($result) > 0)
988  {
989    $row = pwg_db_fetch_assoc($result);
990    $username = stripslashes($row['username']);
991    $data = $time.$user_id.$username;
992    $key = base64_encode( hash_hmac('sha1', $data, $conf['secret_key'].$row['password'],true) );
993    return $key;
994  }
995  return false;
996}
997
998/*
999 * Performs all required actions for user login
1000 * @param int user_id
1001 * @param bool remember_me
1002 * @return void
1003*/
1004function log_user($user_id, $remember_me)
1005{
1006  global $conf, $user;
1007
1008  if ($remember_me and $conf['authorize_remembering'])
1009  {
1010    $now = time();
1011    $key = calculate_auto_login_key($user_id, $now, $username);
1012    if ($key!==false)
1013    {
1014      $cookie = $user_id.'-'.$now.'-'.$key;
1015      if (version_compare(PHP_VERSION, '5.2', '>=') )
1016      {
1017        setcookie($conf['remember_me_name'],
1018            $cookie,
1019            time()+$conf['remember_me_length'],
1020            cookie_path(),ini_get('session.cookie_domain'),ini_get('session.cookie_secure'),
1021            ini_get('session.cookie_httponly')
1022          );
1023      }
1024      else
1025      {
1026        setcookie($conf['remember_me_name'],
1027            $cookie,
1028            time()+$conf['remember_me_length'],
1029            cookie_path(),ini_get('session.cookie_domain'),ini_get('session.cookie_secure')
1030          );
1031      }
1032    }
1033  }
1034  else
1035  { // make sure we clean any remember me ...
1036    setcookie($conf['remember_me_name'], '', 0, cookie_path(),ini_get('session.cookie_domain'));
1037  }
1038  if ( session_id()!="" )
1039  { // we regenerate the session for security reasons
1040    // see http://www.acros.si/papers/session_fixation.pdf
1041    session_regenerate_id(true);
1042  }
1043  else
1044  {
1045    session_start();
1046  }
1047  $_SESSION['pwg_uid'] = (int)$user_id;
1048
1049  $user['id'] = $_SESSION['pwg_uid'];
1050  trigger_action('user_login', $user['id']);
1051}
1052
1053/*
1054 * Performs auto-connexion when cookie remember_me exists
1055 * @return true/false
1056*/
1057function auto_login() {
1058  global $conf;
1059
1060  if ( isset( $_COOKIE[$conf['remember_me_name']] ) )
1061  {
1062    $cookie = explode('-', stripslashes($_COOKIE[$conf['remember_me_name']]));
1063    if ( count($cookie)===3
1064        and is_numeric(@$cookie[0]) /*user id*/
1065        and is_numeric(@$cookie[1]) /*time*/
1066        and time()-$conf['remember_me_length']<=@$cookie[1]
1067        and time()>=@$cookie[1] /*cookie generated in the past*/ )
1068    {
1069      $key = calculate_auto_login_key( $cookie[0], $cookie[1], $username );
1070      if ($key!==false and $key===$cookie[2])
1071      {
1072        log_user($cookie[0], true);
1073        trigger_action('login_success', stripslashes($username));
1074        return true;
1075      }
1076    }
1077    setcookie($conf['remember_me_name'], '', 0, cookie_path(),ini_get('session.cookie_domain'));
1078  }
1079  return false;
1080}
1081
1082/**
1083 * hashes a password, with the PasswordHash class from phpass security
1084 * library. We use an "pwg_" prefix because function password_hash is
1085 * planned for PHP 5.5. Code inspired from Wordpress.
1086 *
1087 * @param string $password Plain text user password to hash
1088 * @return string The hash string of the password
1089 */
1090function pwg_password_hash($password)
1091{
1092  global $pwg_hasher;
1093
1094  if (empty($pwg_hasher))
1095  {
1096    require_once(PHPWG_ROOT_PATH.'include/passwordhash.class.php');
1097
1098    // We use the portable hash feature from phpass because we can't be sure
1099    // Piwigo runs on PHP 5.3+ (and won't run on an older version in the
1100    // future)
1101    $pwg_hasher = new PasswordHash(13, true);
1102  }
1103
1104  return $pwg_hasher->HashPassword($password);
1105}
1106
1107/**
1108 * Verifies a password, with the PasswordHash class from phpass security
1109 * library. We use an "pwg_" prefix because function password_verify is
1110 * planned for PHP 5.5. Code inspired from Wordpress.
1111 *
1112 * @param string $password Plain text user password to hash
1113 * @param string $hash may be md5 or phpass hashed password
1114 * @param integer $account_id only useful to update password hash from md5 to phpass
1115 * @return string The hash string of the password
1116 */
1117function pwg_password_verify($password, $hash, $user_id=null)
1118{
1119  global $conf, $pwg_hasher;
1120
1121  // If the password has not been hashed with the current algorithm.
1122  if (strpos('$P', $hash) !== 0)
1123  {
1124    if (!empty($conf['pass_convert']))
1125    {
1126      $check = ($hash == $conf['pass_convert']($password));
1127    }
1128    else
1129    {
1130      $check = ($hash == md5($password));
1131    }
1132
1133    if ($check)
1134    {
1135      if (!isset($user_id) or $conf['external_authentification'])
1136      {
1137        return true;
1138      }
1139     
1140      // Rehash using new hash.
1141      $hash = pwg_password_hash($password);
1142
1143      single_update(
1144        USERS_TABLE,
1145        array('password' => $hash),
1146        array('id' => $user_id)
1147        );
1148    }
1149  }
1150
1151  // If the stored hash is longer than an MD5, presume the
1152  // new style phpass portable hash.
1153  if (empty($pwg_hasher))
1154  {
1155    require_once(PHPWG_ROOT_PATH.'include/passwordhash.class.php');
1156
1157    // We use the portable hash feature
1158    $pwg_hasher = new PasswordHash(13, true);
1159  }
1160
1161  return $pwg_hasher->CheckPassword($password, $hash);
1162}
1163
1164/**
1165 * Tries to login a user given username and password (must be MySql escaped)
1166 * return true on success
1167 */
1168function try_log_user($username, $password, $remember_me)
1169{
1170  return trigger_event('try_log_user', false, $username, $password, $remember_me);
1171}
1172
1173add_event_handler('try_log_user', 'pwg_login', EVENT_HANDLER_PRIORITY_NEUTRAL, 4);
1174
1175function pwg_login($success, $username, $password, $remember_me)
1176{
1177  if ($success===true)
1178  {
1179    return true;
1180  }
1181
1182  // we force the session table to be clean
1183  pwg_session_gc();
1184
1185  global $conf;
1186  // retrieving the encrypted password of the login submitted
1187  $query = '
1188SELECT '.$conf['user_fields']['id'].' AS id,
1189       '.$conf['user_fields']['password'].' AS password
1190  FROM '.USERS_TABLE.'
1191  WHERE '.$conf['user_fields']['username'].' = \''.pwg_db_real_escape_string($username).'\'
1192;';
1193  $row = pwg_db_fetch_assoc(pwg_query($query));
1194  if ($conf['password_verify']($password, $row['password'], $row['id']))
1195  {
1196    log_user($row['id'], $remember_me);
1197    trigger_action('login_success', stripslashes($username));
1198    return true;
1199  }
1200  trigger_action('login_failure', stripslashes($username));
1201  return false;
1202}
1203
1204/** Performs all the cleanup on user logout */
1205function logout_user()
1206{
1207  global $conf;
1208
1209  trigger_action('user_logout', @$_SESSION['pwg_uid']);
1210
1211  $_SESSION = array();
1212  session_unset();
1213  session_destroy();
1214  setcookie(session_name(),'',0,
1215      ini_get('session.cookie_path'),
1216      ini_get('session.cookie_domain')
1217    );
1218  setcookie($conf['remember_me_name'], '', 0, cookie_path(),ini_get('session.cookie_domain'));
1219}
1220
1221/*
1222 * Return user status used in this library
1223 * @return string
1224*/
1225function get_user_status($user_status)
1226{
1227  global $user;
1228
1229  if (empty($user_status))
1230  {
1231    if (isset($user['status']))
1232    {
1233      $user_status = $user['status'];
1234    }
1235    else
1236    {
1237      // swicth to default value
1238      $user_status = '';
1239    }
1240  }
1241  return $user_status;
1242}
1243
1244/*
1245 * Return access_type definition of user
1246 * Test does with user status
1247 * @return bool
1248*/
1249function get_access_type_status($user_status='')
1250{
1251  global $conf;
1252
1253  switch (get_user_status($user_status))
1254  {
1255    case 'guest':
1256    {
1257      $access_type_status =
1258        ($conf['guest_access'] ? ACCESS_GUEST : ACCESS_FREE);
1259      break;
1260    }
1261    case 'generic':
1262    {
1263      $access_type_status = ACCESS_GUEST;
1264      break;
1265    }
1266    case 'normal':
1267    {
1268      $access_type_status = ACCESS_CLASSIC;
1269      break;
1270    }
1271    case 'admin':
1272    {
1273      $access_type_status = ACCESS_ADMINISTRATOR;
1274      break;
1275    }
1276    case 'webmaster':
1277    {
1278      $access_type_status = ACCESS_WEBMASTER;
1279      break;
1280    }
1281    default:
1282    {
1283      $access_type_status = ACCESS_FREE;
1284      break;
1285    }
1286  }
1287
1288  return $access_type_status;
1289}
1290
1291/*
1292 * Return if user have access to access_type definition
1293 * Test does with user status
1294 * @return bool
1295*/
1296function is_autorize_status($access_type, $user_status = '')
1297{
1298  return (get_access_type_status($user_status) >= $access_type);
1299}
1300
1301/*
1302 * Check if user have access to access_type definition
1303 * Stop action if there are not access
1304 * Test does with user status
1305 * @return none
1306*/
1307function check_status($access_type, $user_status = '')
1308{
1309  if (!is_autorize_status($access_type, $user_status))
1310  {
1311    access_denied();
1312  }
1313}
1314
1315/*
1316 * Return if user is generic
1317 * @return bool
1318*/
1319 function is_generic($user_status = '')
1320{
1321  return get_user_status($user_status) == 'generic';
1322}
1323
1324/*
1325 * Return if user is only a guest
1326 * @return bool
1327*/
1328 function is_a_guest($user_status = '')
1329{
1330  return get_user_status($user_status) == 'guest';
1331}
1332
1333/*
1334 * Return if user is, at least, a classic user
1335 * @return bool
1336*/
1337 function is_classic_user($user_status = '')
1338{
1339  return is_autorize_status(ACCESS_CLASSIC, $user_status);
1340}
1341
1342/*
1343 * Return if user is, at least, an administrator
1344 * @return bool
1345*/
1346 function is_admin($user_status = '')
1347{
1348  return is_autorize_status(ACCESS_ADMINISTRATOR, $user_status);
1349}
1350
1351/*
1352 * Return if user is, at least, a webmaster
1353 * @return bool
1354*/
1355 function is_webmaster($user_status = '')
1356{
1357  return is_autorize_status(ACCESS_WEBMASTER, $user_status);
1358}
1359
1360/*
1361 * Adviser status is depreciated from piwigo 2.2
1362 * @return false
1363*/
1364function is_adviser()
1365{
1366  // TODO for Piwigo 2.4 : trigger a warning. We don't do it on Piwigo 2.3
1367  // to avoid changes for plugin contributors
1368  // trigger_error('call to obsolete function is_adviser', E_USER_WARNING);
1369  return false;
1370}
1371
1372/*
1373 * Return if current user can edit/delete/validate a comment
1374 * @param action edit/delete/validate
1375 * @return bool
1376 */
1377function can_manage_comment($action, $comment_author_id)
1378{
1379  global $user, $conf;
1380
1381  if (is_a_guest())
1382  {
1383    return false;
1384  }
1385
1386  if (!in_array($action, array('delete','edit', 'validate')))
1387  {
1388    return false;
1389  }
1390
1391  if (is_admin())
1392  {
1393    return true;
1394  }
1395
1396  if ('edit' == $action and $conf['user_can_edit_comment'])
1397  {
1398    if ($comment_author_id == $user['id']) {
1399      return true;
1400    }
1401  }
1402
1403  if ('delete' == $action and $conf['user_can_delete_comment'])
1404  {
1405    if ($comment_author_id == $user['id']) {
1406      return true;
1407    }
1408  }
1409
1410  return false;
1411}
1412
1413/*
1414 * Return mail address as display text
1415 * @return string
1416*/
1417function get_email_address_as_display_text($email_address)
1418{
1419  global $conf;
1420
1421  if (!isset($email_address) or (trim($email_address) == ''))
1422  {
1423    return '';
1424  }
1425  else
1426  {
1427    return $email_address;
1428  }
1429}
1430
1431/*
1432 * Compute sql where condition with restrict and filter data. "FandF" means
1433 * Forbidden and Filters.
1434 *
1435 * @param array condition_fields: read function body
1436 * @param string prefix_condition: prefixes sql if condition is not empty
1437 * @param boolean force_one_condition: use at least "1 = 1"
1438 *
1439 * @return string sql where/conditions
1440 */
1441function get_sql_condition_FandF(
1442  $condition_fields,
1443  $prefix_condition = null,
1444  $force_one_condition = false
1445  )
1446{
1447  global $user, $filter;
1448
1449  $sql_list = array();
1450
1451  foreach ($condition_fields as $condition => $field_name)
1452  {
1453    switch($condition)
1454    {
1455      case 'forbidden_categories':
1456      {
1457        if (!empty($user['forbidden_categories']))
1458        {
1459          $sql_list[] =
1460            $field_name.' NOT IN ('.$user['forbidden_categories'].')';
1461        }
1462        break;
1463      }
1464      case 'visible_categories':
1465      {
1466        if (!empty($filter['visible_categories']))
1467        {
1468          $sql_list[] =
1469            $field_name.' IN ('.$filter['visible_categories'].')';
1470        }
1471        break;
1472      }
1473      case 'visible_images':
1474        if (!empty($filter['visible_images']))
1475        {
1476          $sql_list[] =
1477            $field_name.' IN ('.$filter['visible_images'].')';
1478        }
1479        // note there is no break - visible include forbidden
1480      case 'forbidden_images':
1481        if (
1482            !empty($user['image_access_list'])
1483            or $user['image_access_type']!='NOT IN'
1484            )
1485        {
1486          $table_prefix=null;
1487          if ($field_name=='id')
1488          {
1489            $table_prefix = '';
1490          }
1491          elseif ($field_name=='i.id')
1492          {
1493            $table_prefix = 'i.';
1494          }
1495          if ( isset($table_prefix) )
1496          {
1497            $sql_list[]=$table_prefix.'level<='.$user['level'];
1498          }
1499          elseif ( !empty($user['image_access_list']) and !empty($user['image_access_type']) )
1500          {
1501            $sql_list[]=$field_name.' '.$user['image_access_type']
1502                .' ('.$user['image_access_list'].')';
1503          }
1504        }
1505        break;
1506      default:
1507      {
1508        die('Unknow condition');
1509        break;
1510      }
1511    }
1512  }
1513
1514  if (count($sql_list) > 0)
1515  {
1516    $sql = '('.implode(' AND ', $sql_list).')';
1517  }
1518  else
1519  {
1520    $sql = $force_one_condition ? '1 = 1' : '';
1521  }
1522
1523  if (isset($prefix_condition) and !empty($sql))
1524  {
1525    $sql = $prefix_condition.' '.$sql;
1526  }
1527
1528  return $sql;
1529}
1530
1531/** @return the sql condition to show recent photos/albums based on user preferences and latest available photo.*/
1532function get_recent_photos_sql($db_field)
1533{
1534  global $user;
1535  if (!isset($user['last_photo_date']))
1536  {
1537    return '0=1';
1538  }
1539  return $db_field.'>=LEAST('
1540    .pwg_db_get_recent_period_expression($user['recent_period'])
1541    .','.pwg_db_get_recent_period_expression(1,$user['last_photo_date']).')';
1542}
1543
1544/**
1545 * search an available activation_key
1546 *
1547 * @return string
1548 */
1549function get_user_activation_key()
1550{
1551  while (true)
1552  {
1553    $key = generate_key(20);
1554    $query = '
1555SELECT COUNT(*)
1556  FROM '.USER_INFOS_TABLE.'
1557  WHERE activation_key = \''.$key.'\'
1558;';
1559    list($count) = pwg_db_fetch_row(pwg_query($query));
1560    if (0 == $count)
1561    {
1562      return $key;
1563    }
1564  }
1565}
1566
1567?>
Note: See TracBrowser for help on using the repository browser.