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

Revision 25729, 36.8 KB checked in by mistic100, 6 years ago (diff)

remove is_adviser() and get_email_address_as_display_text()

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