includes/sessions.php
changeset 541 acb7e23b6ffa
parent 536 218a627eb53e
child 542 5841df0ab575
equal deleted inserted replaced
540:1e4b759da336 541:acb7e23b6ffa
   146    * Regex that defines a valid username, minus the ^ and $, these are added later
   146    * Regex that defines a valid username, minus the ^ and $, these are added later
   147    * @var string
   147    * @var string
   148    */
   148    */
   149    
   149    
   150   var $valid_username = '([^<>&\?\'"%\n\r\t\a\/]+)';
   150   var $valid_username = '([^<>&\?\'"%\n\r\t\a\/]+)';
       
   151   
       
   152   /**
       
   153    * The current user's user title. Defaults to NULL.
       
   154    * @var string
       
   155    */
       
   156   
       
   157   var $user_title = null;
   151    
   158    
   152   /**
   159   /**
   153    * What we're allowed to do as far as permissions go. This changes based on the value of the "auth" URI param.
   160    * What we're allowed to do as far as permissions go. This changes based on the value of the "auth" URI param.
   154    * @var string
   161    * @var string
   155    */
   162    */
   244    * Associative array to track group modship.
   251    * Associative array to track group modship.
   245    * @var array
   252    * @var array
   246    */
   253    */
   247    
   254    
   248   var $group_mod = Array();
   255   var $group_mod = Array();
       
   256   
       
   257   /**
       
   258    * A constant array of user-level-to-rank default associations.
       
   259    * @var array
       
   260    */
       
   261   
       
   262   var $level_rank_table = array(
       
   263       USER_LEVEL_ADMIN  => RANK_ID_ADMIN,
       
   264       USER_LEVEL_MOD    => RANK_ID_MOD,
       
   265       USER_LEVEL_MEMBER => RANK_ID_MEMBER,
       
   266       USER_LEVEL_CHPREF => RANK_ID_MEMBER,
       
   267       USER_LEVEL_GUEST  => RANK_ID_GUEST
       
   268     );
   249   
   269   
   250   # Basic functions
   270   # Basic functions
   251    
   271    
   252   /**
   272   /**
   253    * Constructor.
   273    * Constructor.
   466         $this->password_hash = $userdata['password'];
   486         $this->password_hash = $userdata['password'];
   467         $this->user_level =    intval($userdata['user_level']);
   487         $this->user_level =    intval($userdata['user_level']);
   468         $this->real_name =     $userdata['real_name'];
   488         $this->real_name =     $userdata['real_name'];
   469         $this->email =         $userdata['email'];
   489         $this->email =         $userdata['email'];
   470         $this->unread_pms =    $userdata['num_pms'];
   490         $this->unread_pms =    $userdata['num_pms'];
       
   491         $this->user_title =    $userdata['user_title'];
   471         if(!$this->compat)
   492         if(!$this->compat)
   472         {
   493         {
   473           $this->theme =         $userdata['theme'];
   494           $this->theme =         $userdata['theme'];
   474           $this->style =         $userdata['style'];
   495           $this->style =         $userdata['style'];
   475           $this->signature =     $userdata['signature'];
   496           $this->signature =     $userdata['signature'];
  1230     }
  1251     }
  1231     $keyhash = md5($key);
  1252     $keyhash = md5($key);
  1232     $salt = $db->escape($keydata[3]);
  1253     $salt = $db->escape($keydata[3]);
  1233     // using a normal call to $db->sql_query to avoid failing on errors here
  1254     // using a normal call to $db->sql_query to avoid failing on errors here
  1234     $query = $db->sql_query('SELECT u.user_id AS uid,u.username,u.password,u.email,u.real_name,u.user_level,u.theme,u.style,u.signature,' . "\n"
  1255     $query = $db->sql_query('SELECT u.user_id AS uid,u.username,u.password,u.email,u.real_name,u.user_level,u.theme,u.style,u.signature,' . "\n"
  1235                              . '    u.reg_time,u.account_active,u.activation_key,u.user_lang,k.source_ip,k.time,k.auth_level,COUNT(p.message_id) AS num_pms,' . "\n"
  1256                              . '    u.reg_time,u.account_active,u.activation_key,u.user_lang,u.user_title,k.source_ip,k.time,k.auth_level,COUNT(p.message_id) AS num_pms,' . "\n"
  1236                              . '    u.user_timezone, x.* FROM '.table_prefix.'session_keys AS k' . "\n"
  1257                              . '    u.user_timezone, x.* FROM '.table_prefix.'session_keys AS k' . "\n"
  1237                              . '  LEFT JOIN '.table_prefix.'users AS u' . "\n"
  1258                              . '  LEFT JOIN '.table_prefix.'users AS u' . "\n"
  1238                              . '    ON ( u.user_id=k.user_id )' . "\n"
  1259                              . '    ON ( u.user_id=k.user_id )' . "\n"
  1239                              . '  LEFT JOIN '.table_prefix.'users_extra AS x' . "\n"
  1260                              . '  LEFT JOIN '.table_prefix.'users_extra AS x' . "\n"
  1240                              . '    ON ( u.user_id=x.user_id OR x.user_id IS NULL )' . "\n"
  1261                              . '    ON ( u.user_id=x.user_id OR x.user_id IS NULL )' . "\n"
  2350       }
  2371       }
  2351     }
  2372     }
  2352     
  2373     
  2353     // Yay! We're done
  2374     // Yay! We're done
  2354     return 'success';
  2375     return 'success';
       
  2376   }
       
  2377   
       
  2378   #
       
  2379   # USER RANKS
       
  2380   #
       
  2381   
       
  2382   /**
       
  2383    * SYNOPSIS OF THE RANK SYSTEM
       
  2384    * Enano's rank logic calculates a user's rank based on a precedence scale. The way things are checked is:
       
  2385    *   1. Check to see if the user has a specific rank assigned. Use that if possible.
       
  2386    *   2. Check the user's primary group to see if it specifies a rank. Use that if possible.
       
  2387    *   3. Check the other groups a user is in. If one that has a custom rank is encountered, use that rank.
       
  2388    *   4. See if the user's user level has a specific rank hard-coded to be associated with it. (Always overrideable as can be seen above)
       
  2389    *   5. Use the "member" rank
       
  2390    */
       
  2391   
       
  2392   /**
       
  2393    * Generates a textual SQL query for fetching rank data to be sent to calculate_user_rank().
       
  2394    * @param string Text to append, possibly a WHERE clause or so
       
  2395    * @return string
       
  2396    */
       
  2397   
       
  2398   function generate_rank_sql($append = '')
       
  2399   {
       
  2400     // Generate level-to-rank associations
       
  2401     $assoc = array();
       
  2402     foreach ( $this->level_rank_table as $level => $rank )
       
  2403     {
       
  2404       $assoc[] = "        ( u.user_level = $level AND rl.rank_id = $rank )";
       
  2405     }
       
  2406     $assoc = implode(" OR\n", $assoc) . "\n";
       
  2407     
       
  2408     $gid_col = ( ENANO_DBLAYER == 'PGSQL' ) ?
       
  2409       'array_to_string(array_accum(m.group_id), \',\') AS group_list' :
       
  2410       'GROUP_CONCAT(m.group_id) AS group_list';
       
  2411     
       
  2412     // The actual query
       
  2413     $sql = "SELECT u.user_id, u.username, u.user_level, u.user_group, u.user_rank, u.user_title, g.group_rank,\n"
       
  2414          . "       COALESCE(ru.rank_id,    rg.rank_id,    rl.rank_id,    rd.rank_id   ) AS rank_id,\n"
       
  2415          . "       COALESCE(ru.rank_title, rg.rank_title, rl.rank_title, rd.rank_title) AS rank_title,\n"
       
  2416          . "       COALESCE(ru.rank_style, rg.rank_style, rl.rank_style, rd.rank_style) AS rank_style,\n"
       
  2417          . "       ( ru.rank_id IS NULL AND rg.rank_id IS NULL ) AS using_default,"
       
  2418          . "       ( ru.rank_id IS NULL AND rg.rank_id IS NOT NULL ) AS using_group,"
       
  2419          . "       $gid_col\n"
       
  2420          . "  FROM " . table_prefix . "users AS u\n"
       
  2421          . "  LEFT JOIN groups AS g\n"
       
  2422          . "    ON ( g.group_id = u.user_group )\n"
       
  2423          . "  LEFT JOIN " . table_prefix . "group_members AS m\n"
       
  2424          . "    ON ( u.user_id = m.user_id )\n"
       
  2425          . "  LEFT JOIN ranks AS ru\n"
       
  2426          . "    ON ( u.user_rank = ru.rank_id )\n"
       
  2427          . "  LEFT JOIN ranks AS rg\n"
       
  2428          . "    ON ( g.group_rank = rg.rank_id )\n"
       
  2429          . "  LEFT JOIN ranks AS rl\n"
       
  2430          . "    ON (\n"
       
  2431          . $assoc
       
  2432          . "      )\n"
       
  2433          . "  LEFT JOIN ranks AS rd\n"
       
  2434          . "    ON ( rd.rank_id = 1 )\n"
       
  2435          . "  GROUP BY u.user_id, u.username, u.user_level, u.user_group, u.user_rank, u.user_title, g.group_rank,\n"
       
  2436          . "       ru.rank_id, ru.rank_title, ru.rank_style,rg.rank_id, rg.rank_title, rg.rank_style,\n"
       
  2437          . "       rl.rank_id, rl.rank_title, rl.rank_style,rd.rank_id, rd.rank_title, rd.rank_style$append;";
       
  2438     
       
  2439     return $sql;
       
  2440   }
       
  2441   
       
  2442   /**
       
  2443    * Returns an associative array with a user's rank information.
       
  2444    * The array will contain the following values:
       
  2445    *   username: string  The user's username
       
  2446    *   user_id:  integer Numerical user ID
       
  2447    *   rank_id:  integer Numerical rank ID
       
  2448    *   rank:     string  The user's current rank
       
  2449    *   title:    string  The user's custom user title if applicable; should be displayed one line below the rank
       
  2450    *   style:    string  CSS for the username
       
  2451    * @param int|string Username *or* user ID
       
  2452    * @return array or false on failure
       
  2453    */
       
  2454   
       
  2455   function get_user_rank($id)
       
  2456   {
       
  2457     global $db, $session, $paths, $template, $plugins; // Common objects
       
  2458     global $lang;
       
  2459     global $user_ranks;
       
  2460     // cache info if possible
       
  2461     static $_cache = array();
       
  2462     
       
  2463     if ( is_int($id) )
       
  2464       $col = "user_id = $id";
       
  2465     else if ( is_string($id) )
       
  2466       $col = ENANO_SQLFUNC_LOWERCASE . "(username) = " . ENANO_SQLFUNC_LOWERCASE . "('" . $db->escape($id) . "')";
       
  2467     else
       
  2468       // invalid parameter
       
  2469       return false;
       
  2470       
       
  2471     // check the cache
       
  2472     if ( isset($_cache[$id]) )
       
  2473       return $_cache[$id];
       
  2474     
       
  2475     // check the disk cache
       
  2476     if ( is_int($id) )
       
  2477     {
       
  2478       if ( isset($user_ranks[$id]) )
       
  2479       {
       
  2480         $_cache[$id] =& $user_ranks[$id];
       
  2481         return $user_ranks[$id];
       
  2482       }
       
  2483     }
       
  2484     else if ( is_string($id) )
       
  2485     {
       
  2486       foreach ( $user_ranks as $key => $valarray )
       
  2487       {
       
  2488         if ( is_string($key) && strtolower($key) == strtolower($id) )
       
  2489         {
       
  2490           $_cache[$id] = $valarray;
       
  2491           return $valarray;
       
  2492         }
       
  2493       }
       
  2494     }
       
  2495     
       
  2496     $sql = $this->generate_rank_sql("\n  WHERE $col");
       
  2497     
       
  2498     $q = $this->sql($sql);
       
  2499     // any results?
       
  2500     if ( $db->numrows() < 1 )
       
  2501     {
       
  2502       // nuttin'.
       
  2503       $db->free_result();
       
  2504       $_cache[$id] = false;
       
  2505       return false;
       
  2506     }
       
  2507     
       
  2508     // Found something.
       
  2509     $row = $db->fetchrow();
       
  2510     $db->free_result();
       
  2511     
       
  2512     $row = $this->calculate_user_rank($row);
       
  2513     
       
  2514     $_cache[$id] = $row;
       
  2515     return $row;
       
  2516   }
       
  2517   
       
  2518   /**
       
  2519    * Performs the actual rank calculation based on the contents of a row.
       
  2520    * @param array
       
  2521    * @return array
       
  2522    */
       
  2523   
       
  2524   function calculate_user_rank($row)
       
  2525   {
       
  2526     global $db, $session, $paths, $template, $plugins; // Common objects
       
  2527     global $lang;
       
  2528     
       
  2529     static $rank_cache = array();
       
  2530     static $group_ranks = array();
       
  2531     
       
  2532     // try to cache that rank info
       
  2533     if ( !isset($rank_cache[ intval($row['rank_id']) ]) && $row['rank_id'] )
       
  2534     {
       
  2535       $rank_cache[ intval($row['rank_id']) ] = array(
       
  2536           'rank_id' => intval($row['rank_id']),
       
  2537           'rank_title' => intval($row['rank_title']),
       
  2538           'rank_style' => intval($row['rank_style'])
       
  2539         );
       
  2540     }
       
  2541     // cache group info (if appropriate)
       
  2542     if ( $row['using_group'] && !isset($group_ranks[ intval($row['user_group']) ]) )
       
  2543     {
       
  2544       $group_ranks[ intval($row['user_group']) ] = intval($row['group_rank_id']);
       
  2545     }
       
  2546     
       
  2547     // sanitize and process the as-of-yet rank data
       
  2548     $row['rank_id'] = intval($row["rank_id"]);
       
  2549     $row['rank_title'] = $row["rank_title"];
       
  2550     
       
  2551     // if we're falling back to some default, then see if we can use one of the user's other groups
       
  2552     if ( $row['using_default'] && !empty($row['group_list']) )
       
  2553     {
       
  2554       $group_list = explode(',', $row['group_list']);
       
  2555       if ( array_walk($group_list, 'intval') )
       
  2556       {
       
  2557         // go through the group list and see if any of them has a rank assigned
       
  2558         foreach ( $group_list as $group_id )
       
  2559         {
       
  2560           // cached in RAM? Preferably use that.
       
  2561           if ( !isset($group_ranks[$group_id]) )
       
  2562           {
       
  2563             // Not cached - grab it
       
  2564             $q = $this->sql('SELECT group_rank FROM ' . table_prefix . "groups WHERE group_id = $group_id;");
       
  2565             if ( $db->numrows() < 1 )
       
  2566             {
       
  2567               $db->free_result();
       
  2568               continue;
       
  2569             }
       
  2570             list($result) = $db->fetchrow_num();
       
  2571             $db->free_result();
       
  2572             
       
  2573             if ( $result === null || $result < 1 )
       
  2574             {
       
  2575               $group_ranks[$group_id] = false;
       
  2576             }
       
  2577             else
       
  2578             {
       
  2579               $group_ranks[$group_id] = intval($result);
       
  2580             }
       
  2581           }
       
  2582           // we've got it now
       
  2583           if ( $group_ranks[$group_id] )
       
  2584           {
       
  2585             // found a group with a rank assigned
       
  2586             // so get the rank info
       
  2587             $rank_id =& $group_ranks[$group_id];
       
  2588             if ( !isset($rank_cache[$rank_id]) )
       
  2589             {
       
  2590               $q = $this->sql('SELECT rank_id, rank_title, rank_style FROM ' . table_prefix . "ranks WHERE rank_id = $rank_id;");
       
  2591               if ( $db->numrows() < 1 )
       
  2592               {
       
  2593                 $db->free_result();
       
  2594                 continue;
       
  2595               }
       
  2596               $rank_cache[$rank_id] = $db->fetchrow();
       
  2597               $db->free_result();
       
  2598             }
       
  2599             // set the final rank parameters
       
  2600             // die("found member-of-group exception with uid {$row['user_id']} gid $group_id rid $rank_id rt {$rank_cache[$rank_id]['rank_title']}");
       
  2601             $row['rank_id'] = $rank_id;
       
  2602             $row['rank_title'] = $rank_cache[$rank_id]['rank_title'];
       
  2603             $row['rank_style'] = $rank_cache[$rank_id]['rank_style'];
       
  2604             break;
       
  2605           }
       
  2606         }
       
  2607       }
       
  2608     }
       
  2609     
       
  2610     if ( $row['user_title'] === NULL )
       
  2611       $row['user_title'] = false;
       
  2612     
       
  2613     $row['user_id'] = intval($row['user_id']);
       
  2614     $row['user_level'] = intval($row['user_level']);
       
  2615     $row['user_group'] = intval($row['user_group']);
       
  2616     
       
  2617     unset($row['user_rank'], $row['group_rank'], $row['group_list'], $row['using_default'], $row['using_group'], $row['user_level'], $row['user_group'], $row['username']);
       
  2618     return $row;
  2355   }
  2619   }
  2356   
  2620   
  2357   #
  2621   #
  2358   # Access Control Lists
  2622   # Access Control Lists
  2359   #
  2623   #
  3654 }
  3918 }
  3655 
  3919 
  3656 // Once a week
  3920 // Once a week
  3657 register_cron_task('cron_clean_old_admin_keys', 168);
  3921 register_cron_task('cron_clean_old_admin_keys', 168);
  3658 
  3922 
       
  3923 /**
       
  3924  * Cron task - regenerate cached user rank information
       
  3925  */
       
  3926 
       
  3927 register_cron_task('generate_ranks_cache', 0.25);
       
  3928 
  3659 ?>
  3929 ?>