source: trunk/include/functions_user.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: 37.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
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            unset( $user_cache_cats[$cat['cat_id']] );
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', '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    image_access_type, image_access_list)
463  VALUES
464  ('.$userdata['id'].',\''.boolean_to_string($userdata['need_update']).'\','
465  .$userdata['cache_update_time'].',\''
466  .$userdata['forbidden_categories'].'\','.$userdata['nb_total_images'].',\''
467  .$userdata['image_access_type'].'\',\''.$userdata['image_access_list'].'\')';
468      pwg_query($query);
469    }
470  }
471
472  return $userdata;
473}
474
475/*
476 * deletes favorites of the current user if he's not allowed to see them
477 *
478 * @return void
479 */
480function check_user_favorites()
481{
482  global $user;
483
484  if ($user['forbidden_categories'] == '')
485  {
486    return;
487  }
488
489  // $filter['visible_categories'] and $filter['visible_images']
490  // must be not used because filter <> restriction
491  // retrieving images allowed : belonging to at least one authorized
492  // category
493  $query = '
494SELECT DISTINCT f.image_id
495  FROM '.FAVORITES_TABLE.' AS f INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic
496    ON f.image_id = ic.image_id
497  WHERE f.user_id = '.$user['id'].'
498'.get_sql_condition_FandF
499  (
500    array
501      (
502        'forbidden_categories' => 'ic.category_id',
503      ),
504    'AND'
505  ).'
506;';
507  $authorizeds = array_from_query($query, 'image_id');
508
509  $query = '
510SELECT image_id
511  FROM '.FAVORITES_TABLE.'
512  WHERE user_id = '.$user['id'].'
513;';
514  $favorites = array_from_query($query, 'image_id');
515
516  $to_deletes = array_diff($favorites, $authorizeds);
517  if (count($to_deletes) > 0)
518  {
519    $query = '
520DELETE FROM '.FAVORITES_TABLE.'
521  WHERE image_id IN ('.implode(',', $to_deletes).')
522    AND user_id = '.$user['id'].'
523;';
524    pwg_query($query);
525  }
526}
527
528/**
529 * calculates the list of forbidden categories for a given user
530 *
531 * Calculation is based on private categories minus categories authorized to
532 * the groups the user belongs to minus the categories directly authorized
533 * to the user. The list contains at least -1 to be compliant with queries
534 * such as "WHERE category_id NOT IN ($forbidden_categories)"
535 *
536 * @param int user_id
537 * @param string user_status
538 * @return string forbidden_categories
539 */
540function calculate_permissions($user_id, $user_status)
541{
542  $query = '
543SELECT id
544  FROM '.CATEGORIES_TABLE.'
545  WHERE status = \'private\'
546;';
547  $private_array = array_from_query($query, 'id');
548
549  // retrieve category ids directly authorized to the user
550  $query = '
551SELECT cat_id
552  FROM '.USER_ACCESS_TABLE.'
553  WHERE user_id = '.$user_id.'
554;';
555  $authorized_array = array_from_query($query, 'cat_id');
556
557  // retrieve category ids authorized to the groups the user belongs to
558  $query = '
559SELECT cat_id
560  FROM '.USER_GROUP_TABLE.' AS ug INNER JOIN '.GROUP_ACCESS_TABLE.' AS ga
561    ON ug.group_id = ga.group_id
562  WHERE ug.user_id = '.$user_id.'
563;';
564  $authorized_array =
565    array_merge(
566      $authorized_array,
567      array_from_query($query, 'cat_id')
568      );
569
570  // uniquify ids : some private categories might be authorized for the
571  // groups and for the user
572  $authorized_array = array_unique($authorized_array);
573
574  // only unauthorized private categories are forbidden
575  $forbidden_array = array_diff($private_array, $authorized_array);
576
577  // if user is not an admin, locked categories are forbidden
578  if (!is_admin($user_status))
579  {
580    $query = '
581SELECT id
582  FROM '.CATEGORIES_TABLE.'
583  WHERE visible = \'false\'
584;';
585    $result = pwg_query($query);
586    while ($row = pwg_db_fetch_assoc($result))
587    {
588      $forbidden_array[] = $row['id'];
589    }
590    $forbidden_array = array_unique($forbidden_array);
591  }
592
593  if ( empty($forbidden_array) )
594  {// at least, the list contains 0 value. This category does not exists so
595   // where clauses such as "WHERE category_id NOT IN(0)" will always be
596   // true.
597    $forbidden_array[] = 0;
598  }
599
600  return implode(',', $forbidden_array);
601}
602
603/**
604 * compute data of categories branches (one branch only)
605 */
606function compute_branch_cat_data(&$cats, &$list_cat_id, &$level, &$ref_level)
607{
608  $date = '';
609  $count_images = 0;
610  $count_categories = 0;
611  do
612  {
613    $cat_id = array_pop($list_cat_id);
614    if (!is_null($cat_id))
615    {
616      // Count images and categories
617      $cats[$cat_id]['count_images'] += $count_images;
618      $cats[$cat_id]['count_categories'] += $count_categories;
619      $count_images = $cats[$cat_id]['count_images'];
620      $count_categories = $cats[$cat_id]['count_categories'] + 1;
621
622      if ((empty($cats[$cat_id]['max_date_last'])) or ($cats[$cat_id]['max_date_last'] < $date))
623      {
624        $cats[$cat_id]['max_date_last'] = $date;
625      }
626      else
627      {
628        $date = $cats[$cat_id]['max_date_last'];
629      }
630      $ref_level = substr_count($cats[$cat_id]['global_rank'], '.') + 1;
631    }
632    else
633    {
634      $ref_level = 0;
635    }
636  } while ($level <= $ref_level);
637
638  // Last cat updating must be added to list for next branch
639  if ($ref_level <> 0)
640  {
641    $list_cat_id[] = $cat_id;
642  }
643}
644
645/**
646 * compute data of categories branches
647 */
648function compute_categories_data(&$cats)
649{
650  $ref_level = 0;
651  $level = 0;
652  $list_cat_id = array();
653
654  foreach ($cats as $id => $category)
655  {
656    // Compute
657    $level = substr_count($category['global_rank'], '.') + 1;
658    if ($level > $ref_level)
659    {
660      $list_cat_id[] = $id;
661    }
662    else
663    {
664      compute_branch_cat_data($cats, $list_cat_id, $level, $ref_level);
665      $list_cat_id[] = $id;
666    }
667    $ref_level = $level;
668  }
669
670  $level = 1;
671  compute_branch_cat_data($cats, $list_cat_id, $level, $ref_level);
672}
673
674/**
675 * get computed array of categories
676 *
677 * @param array userdata
678 * @param int filter_days number of recent days to filter on or null
679 * @return array
680 */
681function get_computed_categories($userdata, $filter_days=null)
682{
683  $query = 'SELECT c.id AS cat_id, global_rank';
684  // Count by date_available to avoid count null
685  $query .= ',
686  MAX(date_available) AS date_last, COUNT(date_available) AS nb_images
687FROM '.CATEGORIES_TABLE.' as c
688  LEFT JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON ic.category_id = c.id
689  LEFT JOIN '.IMAGES_TABLE.' AS i
690    ON ic.image_id = i.id
691      AND i.level<='.$userdata['level'];
692
693  if ( isset($filter_days) )
694  {
695    $query .= ' AND i.date_available > '.pwg_db_get_recent_period_expression($filter_days);
696  }
697
698  if ( !empty($userdata['forbidden_categories']) )
699  {
700    $query.= '
701  WHERE c.id NOT IN ('.$userdata['forbidden_categories'].')';
702  }
703
704  $query.= '
705  GROUP BY c.id, c.global_rank';
706
707  $result = pwg_query($query);
708
709  $cats = array();
710  while ($row = pwg_db_fetch_assoc($result))
711  {
712    $row['user_id'] = $userdata['id'];
713    $row['count_categories'] = 0;
714    $row['count_images'] = (int)$row['nb_images'];
715    $row['max_date_last'] = $row['date_last'];
716
717    $cats += array($row['cat_id'] => $row);
718  }
719  uasort($cats, 'global_rank_compare');
720
721  compute_categories_data($cats);
722
723  if ( isset($filter_days) )
724  {
725    $cat_tmp = $cats;
726    $cats = array();
727
728    foreach ($cat_tmp as $category)
729    {
730      if (!empty($category['max_date_last']))
731      {
732        // Re-init counters
733        $category['count_categories'] = 0;
734        $category['count_images'] = (int)$category['nb_images'];
735        // Keep category
736        $cats[$category['cat_id']] = $category;
737      }
738    }
739    // Compute a second time
740    compute_categories_data($cats);
741  }
742  return $cats;
743}
744
745/**
746 * returns user identifier thanks to his name, false if not found
747 *
748 * @param string username
749 * @param int user identifier
750 */
751function get_userid($username)
752{
753  global $conf;
754
755  $username = pwg_db_real_escape_string($username);
756
757  $query = '
758SELECT '.$conf['user_fields']['id'].'
759  FROM '.USERS_TABLE.'
760  WHERE '.$conf['user_fields']['username'].' = \''.$username.'\'
761;';
762  $result = pwg_query($query);
763
764  if (pwg_db_num_rows($result) == 0)
765  {
766    return false;
767  }
768  else
769  {
770    list($user_id) = pwg_db_fetch_row($result);
771    return $user_id;
772  }
773}
774
775function get_userid_by_email($email)
776{
777  global $conf;
778
779  $email = pwg_db_real_escape_string($email);
780
781  $query = '
782SELECT
783    '.$conf['user_fields']['id'].'
784  FROM '.USERS_TABLE.'
785  WHERE UPPER('.$conf['user_fields']['email'].') = UPPER(\''.$email.'\')
786;';
787  $result = pwg_query($query);
788
789  if (pwg_db_num_rows($result) == 0)
790  {
791    return false;
792  }
793  else
794  {
795    list($user_id) = pwg_db_fetch_row($result);
796    return $user_id;
797  }
798}
799
800/*
801 * Returns a array with default user value
802 *
803 * @param convert_str allows to convert string value if necessary
804 */
805function get_default_user_info($convert_str = true)
806{
807  global $cache, $conf;
808
809  if (!isset($cache['default_user']))
810  {
811    $query = 'SELECT * FROM '.USER_INFOS_TABLE.
812            ' WHERE user_id = '.$conf['default_user_id'].';';
813
814    $result = pwg_query($query);
815    $cache['default_user'] = pwg_db_fetch_assoc($result);
816
817    if ($cache['default_user'] !== false)
818    {
819      unset($cache['default_user']['user_id']);
820      unset($cache['default_user']['status']);
821      unset($cache['default_user']['registration_date']);
822    }
823  }
824
825  if (is_array($cache['default_user']) and $convert_str)
826  {
827    $default_user = $cache['default_user'];
828    foreach ($default_user as &$value)
829    {
830      // If the field is true or false, the variable is transformed into a boolean value.
831      if ($value == 'true')
832      {
833        $value = true;
834      }
835      elseif ($value == 'false')
836      {
837        $value = false;
838      }
839    }
840    return $default_user;
841  }
842  else
843  {
844    return $cache['default_user'];
845  }
846}
847
848/*
849 * Returns a default user value
850 *
851 * @param value_name: name of value
852 * @param sos_value: value used if don't exist value
853 */
854function get_default_user_value($value_name, $sos_value)
855{
856  $default_user = get_default_user_info(true);
857  if ($default_user === false or empty($default_user[$value_name]))
858  {
859    return $sos_value;
860  }
861  else
862  {
863   return $default_user[$value_name];
864  }
865}
866
867/*
868 * Returns the default template value
869 *
870 */
871function get_default_theme()
872{
873  $theme = get_default_user_value('theme', PHPWG_DEFAULT_TEMPLATE);
874  if (check_theme_installed($theme))
875  {
876    return $theme;
877  }
878
879  // let's find the first available theme
880  $active_themes = get_pwg_themes();
881  foreach (array_keys(get_pwg_themes()) as $theme_id)
882  {
883    return $theme_id;
884  }
885}
886
887/*
888 * Returns the default language value
889 *
890 */
891function get_default_language()
892{
893  return get_default_user_value('language', PHPWG_DEFAULT_LANGUAGE);
894}
895
896/**
897  * Returns true if the browser language value is set into param $lang
898  *
899  */
900function get_browser_language(&$lang)
901{
902  $browser_language = substr(@$_SERVER["HTTP_ACCEPT_LANGUAGE"], 0, 2);
903  foreach (get_languages() as $language_code => $language_name)
904  {
905    if (substr($language_code, 0, 2) == $browser_language)
906    {
907      $lang = $language_code;
908      return true;
909    }
910  }
911  return false;
912}
913
914/**
915 * add user informations based on default values
916 *
917 * @param int user_id / array of user_if
918 * @param array of values used to override default user values
919 */
920function create_user_infos($arg_id, $override_values = null)
921{
922  global $conf;
923
924  if (is_array($arg_id))
925  {
926    $user_ids = $arg_id;
927  }
928  else
929  {
930    $user_ids = array();
931    if (is_numeric($arg_id))
932    {
933      $user_ids[] = $arg_id;
934    }
935  }
936
937  if (!empty($user_ids))
938  {
939    $inserts = array();
940    list($dbnow) = pwg_db_fetch_row(pwg_query('SELECT NOW();'));
941
942    $default_user = get_default_user_info(false);
943    if ($default_user === false)
944    {
945      // Default on structure are used
946      $default_user = array();
947    }
948
949    if (!is_null($override_values))
950    {
951      $default_user = array_merge($default_user, $override_values);
952    }
953
954    foreach ($user_ids as $user_id)
955    {
956      $level= isset($default_user['level']) ? $default_user['level'] : 0;
957      if ($user_id == $conf['webmaster_id'])
958      {
959        $status = 'webmaster';
960        $level = max( $conf['available_permission_levels'] );
961      }
962      else if (($user_id == $conf['guest_id']) or
963               ($user_id == $conf['default_user_id']))
964      {
965        $status = 'guest';
966      }
967      else
968      {
969        $status = 'normal';
970      }
971
972      $insert = array_merge(
973        $default_user,
974        array(
975          'user_id' => $user_id,
976          'status' => $status,
977          'registration_date' => $dbnow,
978          'level' => $level
979          ));
980
981      $inserts[] = $insert;
982    }
983
984    mass_inserts(USER_INFOS_TABLE, array_keys($inserts[0]), $inserts);
985  }
986}
987
988/**
989 * returns the auto login key or false on error
990 * @param int user_id
991 * @param time_t time
992 * @param string [out] username
993*/
994function calculate_auto_login_key($user_id, $time, &$username)
995{
996  global $conf;
997  $query = '
998SELECT '.$conf['user_fields']['username'].' AS username
999  , '.$conf['user_fields']['password'].' AS password
1000FROM '.USERS_TABLE.'
1001WHERE '.$conf['user_fields']['id'].' = '.$user_id;
1002  $result = pwg_query($query);
1003  if (pwg_db_num_rows($result) > 0)
1004  {
1005    $row = pwg_db_fetch_assoc($result);
1006    $username = stripslashes($row['username']);
1007    $data = $time.$user_id.$username;
1008    $key = base64_encode( hash_hmac('sha1', $data, $conf['secret_key'].$row['password'],true) );
1009    return $key;
1010  }
1011  return false;
1012}
1013
1014/*
1015 * Performs all required actions for user login
1016 * @param int user_id
1017 * @param bool remember_me
1018 * @return void
1019*/
1020function log_user($user_id, $remember_me)
1021{
1022  global $conf, $user;
1023
1024  if ($remember_me and $conf['authorize_remembering'])
1025  {
1026    $now = time();
1027    $key = calculate_auto_login_key($user_id, $now, $username);
1028    if ($key!==false)
1029    {
1030      $cookie = $user_id.'-'.$now.'-'.$key;
1031      if (version_compare(PHP_VERSION, '5.2', '>=') )
1032      {
1033        setcookie($conf['remember_me_name'],
1034            $cookie,
1035            time()+$conf['remember_me_length'],
1036            cookie_path(),ini_get('session.cookie_domain'),ini_get('session.cookie_secure'),
1037            ini_get('session.cookie_httponly')
1038          );
1039      }
1040      else
1041      {
1042        setcookie($conf['remember_me_name'],
1043            $cookie,
1044            time()+$conf['remember_me_length'],
1045            cookie_path(),ini_get('session.cookie_domain'),ini_get('session.cookie_secure')
1046          );
1047      }
1048    }
1049  }
1050  else
1051  { // make sure we clean any remember me ...
1052    setcookie($conf['remember_me_name'], '', 0, cookie_path(),ini_get('session.cookie_domain'));
1053  }
1054  if ( session_id()!="" )
1055  { // we regenerate the session for security reasons
1056    // see http://www.acros.si/papers/session_fixation.pdf
1057    session_regenerate_id(true);
1058  }
1059  else
1060  {
1061    session_start();
1062  }
1063  $_SESSION['pwg_uid'] = (int)$user_id;
1064
1065  $user['id'] = $_SESSION['pwg_uid'];
1066}
1067
1068/*
1069 * Performs auto-connexion when cookie remember_me exists
1070 * @return true/false
1071*/
1072function auto_login() {
1073  global $conf;
1074
1075  if ( isset( $_COOKIE[$conf['remember_me_name']] ) )
1076  {
1077    $cookie = explode('-', stripslashes($_COOKIE[$conf['remember_me_name']]));
1078    if ( count($cookie)===3
1079        and is_numeric(@$cookie[0]) /*user id*/
1080        and is_numeric(@$cookie[1]) /*time*/
1081        and time()-$conf['remember_me_length']<=@$cookie[1]
1082        and time()>=@$cookie[1] /*cookie generated in the past*/ )
1083    {
1084      $key = calculate_auto_login_key( $cookie[0], $cookie[1], $username );
1085      if ($key!==false and $key===$cookie[2])
1086      {
1087        log_user($cookie[0], true);
1088        trigger_action('login_success', stripslashes($username));
1089        return true;
1090      }
1091    }
1092    setcookie($conf['remember_me_name'], '', 0, cookie_path(),ini_get('session.cookie_domain'));
1093  }
1094  return false;
1095}
1096
1097/**
1098 * hashes a password, with the PasswordHash class from phpass security
1099 * library. We use an "pwg_" prefix because function password_hash is
1100 * planned for PHP 5.5. Code inspired from Wordpress.
1101 *
1102 * @param string $password Plain text user password to hash
1103 * @return string The hash string of the password
1104 */
1105function pwg_password_hash($password)
1106{
1107  global $pwg_hasher;
1108
1109  if (empty($pwg_hasher))
1110  {
1111    require_once(PHPWG_ROOT_PATH.'include/passwordhash.class.php');
1112   
1113    // We use the portable hash feature from phpass because we can't be sure
1114    // Piwigo runs on PHP 5.3+ (and won't run on an older version in the
1115    // future)
1116    $pwg_hasher = new PasswordHash(13, true);
1117  }
1118 
1119  return $pwg_hasher->HashPassword($password);
1120}
1121
1122/**
1123 * Verifies a password, with the PasswordHash class from phpass security
1124 * library. We use an "pwg_" prefix because function password_verify is
1125 * planned for PHP 5.5. Code inspired from Wordpress.
1126 *
1127 * @param string $password Plain text user password to hash
1128 * @param string $hash may be md5 or phpass hashed password
1129 * @param integer $account_id only useful to update password hash from md5 to phpass
1130 * @return string The hash string of the password
1131 */
1132function pwg_password_verify($password, $hash, $user_id=null)
1133{
1134  global $conf, $pwg_hasher;
1135
1136  // If the password has not been hashed with the current algorithm.
1137  if (strpos('$P', $hash) !== 0)
1138  {
1139    if (!empty($conf['pass_convert']))
1140    {
1141      $check = ($hash == $conf['pass_convert']($password));
1142    }
1143    else
1144    {
1145      $check = ($hash == md5($password));
1146    }
1147   
1148    if ($check and isset($user_id) and !$conf['external_authentification'])
1149    {
1150      // Rehash using new hash.
1151      $hash = pwg_password_hash($password);
1152
1153      single_update(
1154        USERS_TABLE,
1155        array('password' => $hash),
1156        array('id' => $user_id)
1157        );
1158    }
1159  }
1160
1161  // If the stored hash is longer than an MD5, presume the
1162  // new style phpass portable hash.
1163  if (empty($pwg_hasher))
1164  {
1165    require_once(PHPWG_ROOT_PATH.'include/passwordhash.class.php');
1166   
1167    // We use the portable hash feature
1168    $pwg_hasher = new PasswordHash(13, true);
1169  }
1170
1171  return $pwg_hasher->CheckPassword($password, $hash);
1172}
1173
1174/**
1175 * Tries to login a user given username and password (must be MySql escaped)
1176 * return true on success
1177 */
1178function try_log_user($username, $password, $remember_me)
1179{
1180  // we force the session table to be clean
1181  pwg_session_gc();
1182
1183  global $conf;
1184  // retrieving the encrypted password of the login submitted
1185  $query = '
1186SELECT '.$conf['user_fields']['id'].' AS id,
1187       '.$conf['user_fields']['password'].' AS password
1188  FROM '.USERS_TABLE.'
1189  WHERE '.$conf['user_fields']['username'].' = \''.pwg_db_real_escape_string($username).'\'
1190;';
1191  $row = pwg_db_fetch_assoc(pwg_query($query));
1192  if ($conf['password_verify']($password, $row['password'], $row['id']))
1193  {
1194    log_user($row['id'], $remember_me);
1195    trigger_action('login_success', stripslashes($username));
1196    return true;
1197  }
1198  trigger_action('login_failure', stripslashes($username));
1199  return false;
1200}
1201
1202/** Performs all the cleanup on user logout */
1203function logout_user()
1204{
1205  global $conf;
1206  $_SESSION = array();
1207  session_unset();
1208  session_destroy();
1209  setcookie(session_name(),'',0,
1210      ini_get('session.cookie_path'),
1211      ini_get('session.cookie_domain')
1212    );
1213  setcookie($conf['remember_me_name'], '', 0, cookie_path(),ini_get('session.cookie_domain'));
1214}
1215
1216/*
1217 * Return user status used in this library
1218 * @return string
1219*/
1220function get_user_status($user_status)
1221{
1222  global $user;
1223
1224  if (empty($user_status))
1225  {
1226    if (isset($user['status']))
1227    {
1228      $user_status = $user['status'];
1229    }
1230    else
1231    {
1232      // swicth to default value
1233      $user_status = '';
1234    }
1235  }
1236  return $user_status;
1237}
1238
1239/*
1240 * Return access_type definition of user
1241 * Test does with user status
1242 * @return bool
1243*/
1244function get_access_type_status($user_status='')
1245{
1246  global $conf;
1247
1248  switch (get_user_status($user_status))
1249  {
1250    case 'guest':
1251    {
1252      $access_type_status =
1253        ($conf['guest_access'] ? ACCESS_GUEST : ACCESS_FREE);
1254      break;
1255    }
1256    case 'generic':
1257    {
1258      $access_type_status = ACCESS_GUEST;
1259      break;
1260    }
1261    case 'normal':
1262    {
1263      $access_type_status = ACCESS_CLASSIC;
1264      break;
1265    }
1266    case 'admin':
1267    {
1268      $access_type_status = ACCESS_ADMINISTRATOR;
1269      break;
1270    }
1271    case 'webmaster':
1272    {
1273      $access_type_status = ACCESS_WEBMASTER;
1274      break;
1275    }
1276    default:
1277    {
1278      $access_type_status = ACCESS_FREE;
1279      break;
1280    }
1281  }
1282
1283  return $access_type_status;
1284}
1285
1286/*
1287 * Return if user have access to access_type definition
1288 * Test does with user status
1289 * @return bool
1290*/
1291function is_autorize_status($access_type, $user_status = '')
1292{
1293  return (get_access_type_status($user_status) >= $access_type);
1294}
1295
1296/*
1297 * Check if user have access to access_type definition
1298 * Stop action if there are not access
1299 * Test does with user status
1300 * @return none
1301*/
1302function check_status($access_type, $user_status = '')
1303{
1304  if (!is_autorize_status($access_type, $user_status))
1305  {
1306    access_denied();
1307  }
1308}
1309
1310/*
1311 * Return if user is generic
1312 * @return bool
1313*/
1314 function is_generic($user_status = '')
1315{
1316  return get_user_status($user_status) == 'generic';
1317}
1318
1319/*
1320 * Return if user is only a guest
1321 * @return bool
1322*/
1323 function is_a_guest($user_status = '')
1324{
1325  return get_user_status($user_status) == 'guest';
1326}
1327
1328/*
1329 * Return if user is, at least, a classic user
1330 * @return bool
1331*/
1332 function is_classic_user($user_status = '')
1333{
1334  return is_autorize_status(ACCESS_CLASSIC, $user_status);
1335}
1336
1337/*
1338 * Return if user is, at least, an administrator
1339 * @return bool
1340*/
1341 function is_admin($user_status = '')
1342{
1343  return is_autorize_status(ACCESS_ADMINISTRATOR, $user_status);
1344}
1345
1346/*
1347 * Return if user is, at least, a webmaster
1348 * @return bool
1349*/
1350 function is_webmaster($user_status = '')
1351{
1352  return is_autorize_status(ACCESS_WEBMASTER, $user_status);
1353}
1354
1355/*
1356 * Adviser status is depreciated from piwigo 2.2
1357 * @return false
1358*/
1359function is_adviser()
1360{
1361  // TODO for Piwigo 2.4 : trigger a warning. We don't do it on Piwigo 2.3
1362  // to avoid changes for plugin contributors
1363  // trigger_error('call to obsolete function is_adviser', E_USER_WARNING);
1364  return false;
1365}
1366
1367/*
1368 * Return if current user can edit/delete/validate a comment
1369 * @param action edit/delete/validate
1370 * @return bool
1371 */
1372function can_manage_comment($action, $comment_author_id)
1373{
1374  global $user, $conf;
1375
1376  if (is_a_guest())
1377  {
1378    return false;
1379  }
1380
1381  if (!in_array($action, array('delete','edit', 'validate')))
1382  {
1383    return false;
1384  }
1385
1386  if (is_admin())
1387  {
1388    return true;
1389  }
1390
1391  if ('edit' == $action and $conf['user_can_edit_comment'])
1392  {
1393    if ($comment_author_id == $user['id']) {
1394      return true;
1395    }
1396  }
1397
1398  if ('delete' == $action and $conf['user_can_delete_comment'])
1399  {
1400    if ($comment_author_id == $user['id']) {
1401      return true;
1402    }
1403  }
1404
1405  return false;
1406}
1407
1408/*
1409 * Return mail address as display text
1410 * @return string
1411*/
1412function get_email_address_as_display_text($email_address)
1413{
1414  global $conf;
1415
1416  if (!isset($email_address) or (trim($email_address) == ''))
1417  {
1418    return '';
1419  }
1420  else
1421  {
1422    return $email_address;
1423  }
1424}
1425
1426/*
1427 * Compute sql where condition with restrict and filter data. "FandF" means
1428 * Forbidden and Filters.
1429 *
1430 * @param array condition_fields: read function body
1431 * @param string prefix_condition: prefixes sql if condition is not empty
1432 * @param boolean force_one_condition: use at least "1 = 1"
1433 *
1434 * @return string sql where/conditions
1435 */
1436function get_sql_condition_FandF(
1437  $condition_fields,
1438  $prefix_condition = null,
1439  $force_one_condition = false
1440  )
1441{
1442  global $user, $filter;
1443
1444  $sql_list = array();
1445
1446  foreach ($condition_fields as $condition => $field_name)
1447  {
1448    switch($condition)
1449    {
1450      case 'forbidden_categories':
1451      {
1452        if (!empty($user['forbidden_categories']))
1453        {
1454          $sql_list[] =
1455            $field_name.' NOT IN ('.$user['forbidden_categories'].')';
1456        }
1457        break;
1458      }
1459      case 'visible_categories':
1460      {
1461        if (!empty($filter['visible_categories']))
1462        {
1463          $sql_list[] =
1464            $field_name.' IN ('.$filter['visible_categories'].')';
1465        }
1466        break;
1467      }
1468      case 'visible_images':
1469        if (!empty($filter['visible_images']))
1470        {
1471          $sql_list[] =
1472            $field_name.' IN ('.$filter['visible_images'].')';
1473        }
1474        // note there is no break - visible include forbidden
1475      case 'forbidden_images':
1476        if (
1477            !empty($user['image_access_list'])
1478            or $user['image_access_type']!='NOT IN'
1479            )
1480        {
1481          $table_prefix=null;
1482          if ($field_name=='id')
1483          {
1484            $table_prefix = '';
1485          }
1486          elseif ($field_name=='i.id')
1487          {
1488            $table_prefix = 'i.';
1489          }
1490          if ( isset($table_prefix) )
1491          {
1492            $sql_list[]=$table_prefix.'level<='.$user['level'];
1493          }
1494          else if ( !empty($user['image_access_list']) and !empty($user['image_access_type']) )
1495          {
1496            $sql_list[]=$field_name.' '.$user['image_access_type']
1497                .' ('.$user['image_access_list'].')';
1498          }
1499        }
1500        break;
1501      default:
1502      {
1503        die('Unknow condition');
1504        break;
1505      }
1506    }
1507  }
1508
1509  if (count($sql_list) > 0)
1510  {
1511    $sql = '('.implode(' AND ', $sql_list).')';
1512  }
1513  else
1514  {
1515    $sql = $force_one_condition ? '1 = 1' : '';
1516  }
1517
1518  if (isset($prefix_condition) and !empty($sql))
1519  {
1520    $sql = $prefix_condition.' '.$sql;
1521  }
1522
1523  return $sql;
1524}
1525
1526/**
1527 * search an available activation_key
1528 *
1529 * @return string
1530 */
1531function get_user_activation_key()
1532{
1533  while (true)
1534  {
1535    $key = generate_key(20);
1536    $query = '
1537SELECT COUNT(*)
1538  FROM '.USER_INFOS_TABLE.'
1539  WHERE activation_key = \''.$key.'\'
1540;';
1541    list($count) = pwg_db_fetch_row(pwg_query($query));
1542    if (0 == $count)
1543    {
1544      return $key;
1545    }
1546  }
1547}
1548
1549?>
Note: See TracBrowser for help on using the repository browser.