source: branches/2.3/include/functions_user.inc.php @ 12747

Last change on this file since 12747 was 12747, checked in by plg, 12 years ago

bug 2534 fixed: clean (as clean as possible with MySQL+MyISAM) handle of
concurrency on user cache refresh. No more error when regenerating several
thumbnails at once.

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