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

Last change on this file since 27569 was 27388, checked in by rvelices, 10 years ago

more query2array and remove unnecessary tests in often called url functions

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