Вход Регистрация
Файл: qa-include/qa-app-users.php
Строк: 1073
<?php

/*
    Question2Answer (c) Gideon Greenspan

    http://www.question2answer.org/

    
    File: qa-include/qa-app-users.php
    Version: See define()s at top of qa-include/qa-base.php
    Description: User management (application level) for basic user operations


    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    More about this license: http://www.question2answer.org/license.php
*/

    
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
        
header('Location: ../');
        exit;
    }

    
define('QA_USER_LEVEL_BASIC'0);
    
define('QA_USER_LEVEL_EXPERT'20);
    
define('QA_USER_LEVEL_EDITOR'50);
    
define('QA_USER_LEVEL_MODERATOR'80);
    
define('QA_USER_LEVEL_ADMIN'100);
    
define('QA_USER_LEVEL_SUPER'120);
    
    
define('QA_USER_FLAGS_EMAIL_CONFIRMED'1);
    
define('QA_USER_FLAGS_USER_BLOCKED'2);
    
define('QA_USER_FLAGS_SHOW_AVATAR'4);
    
define('QA_USER_FLAGS_SHOW_GRAVATAR'8);
    
define('QA_USER_FLAGS_NO_MESSAGES'16);
    
define('QA_USER_FLAGS_NO_MAILINGS'32);
    
define('QA_USER_FLAGS_WELCOME_NOTICE'64);
    
define('QA_USER_FLAGS_MUST_CONFIRM'128);
    
    
define('QA_FIELD_FLAGS_MULTI_LINE'1);
    
define('QA_FIELD_FLAGS_LINK_URL'2);

    
    if (
QA_FINAL_EXTERNAL_USERS) {

    
//    If we're using single sign-on integration (WordPress or otherwise), load PHP file for that

        
if (defined('QA_FINAL_WORDPRESS_INTEGRATE_PATH'))
            require_once 
QA_INCLUDE_DIR.'qa-external-users-wp.php';
        else
            require_once 
QA_EXTERNAL_DIR.'qa-external-users.php';
        

    
//    Access functions for user information
    
        
function qa_get_logged_in_user_cache()
    
/*
        Return array of information about the currently logged in user, cache to ensure only one call to external code
    */
        
{
            global 
$qa_cached_logged_in_user;
            
            if (!isset(
$qa_cached_logged_in_user)) {
                
$user=qa_get_logged_in_user();
                
$qa_cached_logged_in_user=isset($user) ? $user false// to save trying again
            
}
            
            return @
$qa_cached_logged_in_user;
        }
        
        
        function 
qa_get_logged_in_user_field($field)
    
/*
        Return $field of the currently logged in user, or null if not available
    */
        
{
            
$user=qa_get_logged_in_user_cache();
            
            return @
$user[$field];
        }


        function 
qa_get_logged_in_userid()
    
/*
        Return the userid of the currently logged in user, or null if none
    */
        
{
            return 
qa_get_logged_in_user_field('userid');
        }
        
        
        function 
qa_get_logged_in_points()
    
/*
        Return the number of points of the currently logged in user, or null if none is logged in
    */
        
{
            global 
$qa_cached_logged_in_points;
            
            if (!isset(
$qa_cached_logged_in_points)) {
                require_once 
QA_INCLUDE_DIR.'qa-db-selects.php'
                
                
$qa_cached_logged_in_points=qa_db_select_with_pending(qa_db_user_points_selectspec(qa_get_logged_in_userid(), true));
            }
            
            return 
$qa_cached_logged_in_points['points'];
        }
        
        
        function 
qa_get_external_avatar_html($userid$size$padding=false)
    
/*
        Return HTML to display for the avatar of $userid, constrained to $size pixels, with optional $padding to that size
    */
        
{
            if (
function_exists('qa_avatar_html_from_userid'))
                return 
qa_avatar_html_from_userid($userid$size$padding);
            else
                return 
null;
        }
        
        
    } else {
        
        function 
qa_start_session()
    
/*
        Open a PHP session if one isn't opened already
    */
        
{
            if (
qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__$args); }
        
            @
ini_set('session.gc_maxlifetime'86400); // worth a try, but won't help in shared hosting environment
            
@ini_set('session.use_trans_sid'false); // sessions need cookies to work, since we redirect after login
            
@ini_set('session.cookie_domain'QA_COOKIE_DOMAIN);

            if (!isset(
$_SESSION))
                
session_start();
        }
        
        
        function 
qa_session_var_suffix()
    
/*
        Returns a suffix to be used for names of session variables to prevent them being shared between multiple Q2A sites on the same server
    */
        
{
            if (
qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__$args); }
            
            
$prefix=defined('QA_MYSQL_USERS_PREFIX') ? QA_MYSQL_USERS_PREFIX QA_MYSQL_TABLE_PREFIX;
            
            return 
md5(QA_FINAL_MYSQL_HOSTNAME.'/'.QA_FINAL_MYSQL_USERNAME.'/'.QA_FINAL_MYSQL_PASSWORD.'/'.QA_FINAL_MYSQL_DATABASE.'/'.$prefix);
        }
        
        
        function 
qa_session_verify_code($userid)
    
/*
        Returns a verification code used to ensure that a user session can't be generated by another PHP script running on the same server
    */
        
{
            if (
qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__$args); }
        
            return 
sha1($userid.'/'.QA_MYSQL_TABLE_PREFIX.'/'.QA_FINAL_MYSQL_DATABASE.'/'.QA_FINAL_MYSQL_PASSWORD.'/'.QA_FINAL_MYSQL_USERNAME.'/'.QA_FINAL_MYSQL_HOSTNAME);
        }

        
        function 
qa_set_session_cookie($handle$sessioncode$remember)
    
/*
        Set cookie in browser for username $handle with $sessioncode (in database).
        Pass true if user checked 'Remember me' (either now or previously, as learned from cookie).
    */
        
{
            if (
qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__$args); }
        
            
// if $remember is true, store in browser for a month, otherwise store only until browser is closed
            
setcookie('qa_session'$handle.'/'.$sessioncode.'/'.($remember 0), $remember ? (time()+2592000) : 0'/'QA_COOKIE_DOMAIN);
        }

        
        function 
qa_clear_session_cookie()
    
/*
        Remove session cookie from browser
    */
        
{
            if (
qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__$args); }
        
            
setcookie('qa_session'false0'/'QA_COOKIE_DOMAIN);
        }
        
        
        function 
qa_set_session_user($userid$source)
    
/*
        Set the session variables to indicate that $userid is logged in from $source
    */
        
{
            if (
qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__$args); }
        
            
$suffix=qa_session_var_suffix();

            
$_SESSION['qa_session_userid_'.$suffix]=$userid;
            
$_SESSION['qa_session_source_'.$suffix]=$source;
            
$_SESSION['qa_session_verify_'.$suffix]=qa_session_verify_code($userid);
                
// prevents one account on a shared server being able to create a log in a user to Q2A on another account on same server
        
}
        
        
        function 
qa_clear_session_user()
    
/*
        Clear the session variables indicating that a user is logged in
    */
        
{
            if (
qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__$args); }
        
            
$suffix=qa_session_var_suffix();

            unset(
$_SESSION['qa_session_userid_'.$suffix]);
            unset(
$_SESSION['qa_session_source_'.$suffix]);
            unset(
$_SESSION['qa_session_verify_'.$suffix]);
        }

        
        function 
qa_set_logged_in_user($userid$handle=''$remember=false$source=null)
    
/*
        Call for successful log in by $userid and $handle or successful log out with $userid=null.
        $remember states if 'Remember me' was checked in the login form.
    */
        
{
            if (
qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__$args); }
        
            require_once 
QA_INCLUDE_DIR.'qa-app-cookies.php';
            
            
qa_start_session();

            if (isset(
$userid)) {
                
qa_set_session_user($userid$source);
                
                
// PHP sessions time out too quickly on the server side, so we also set a cookie as backup.
                // Logging in from a second browser will make the previous browser's 'Remember me' no longer
                // work - I'm not sure if this is the right behavior - could see it either way.

                
require_once QA_INCLUDE_DIR.'qa-db-selects.php';
                
                
$userinfo=qa_db_single_select(qa_db_user_account_selectspec($useridtrue));
                
                
// if we have logged in before, and are logging in the same way as before, we don't need to change the sessioncode/source
                // this means it will be possible to automatically log in (via cookies) to the same account from more than one browser
                
                
if (empty($userinfo['sessioncode']) || ($source!==$userinfo['sessionsource'])) {
                    
$sessioncode=qa_db_user_rand_sessioncode();
                    
qa_db_user_set($userid'sessioncode'$sessioncode);
                    
qa_db_user_set($userid'sessionsource'$source);
                } else
                    
$sessioncode=$userinfo['sessioncode'];
                
                
qa_db_user_logged_in($useridqa_remote_ip_address());
                
qa_set_session_cookie($handle$sessioncode$remember);
                
                
qa_report_event('u_login'$userid$userinfo['handle'], qa_cookie_get());

            } else {
                
$olduserid=qa_get_logged_in_userid();
                
$oldhandle=qa_get_logged_in_handle();

                
qa_clear_session_cookie();
                
qa_clear_session_user();

                
qa_report_event('u_logout'$olduserid$oldhandleqa_cookie_get());
            }
        }
        
        
        function 
qa_log_in_external_user($source$identifier$fields)
    
/*
        Call to log in a user based on an external identity provider $source with external $identifier
        A new user is created based on $fields if it's a new combination of $source and $identifier
    */
        
{
            if (
qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__$args); }
        
            require_once 
QA_INCLUDE_DIR.'qa-db-users.php';
            
            
$users=qa_db_user_login_find($source$identifier);
            
$countusers=count($users);
            
            if (
$countusers>1)
                
qa_fatal_error('External login mapped to more than one user'); // should never happen
            
            
if ($countusers// user exists so log them in
                
qa_set_logged_in_user($users[0]['userid'], $users[0]['handle'], false$source);
            
            else { 
// create and log in user
                
require_once QA_INCLUDE_DIR.'qa-app-users-edit.php';
                
                
qa_db_user_login_sync(true);
                
                
$users=qa_db_user_login_find($source$identifier); // check again after table is locked
                
                
if (count($users)==1) {
                    
qa_db_user_login_sync(false);
                    
qa_set_logged_in_user($users[0]['userid'], $users[0]['handle'], false$source);
                
                } else {
                    
$handle=qa_handle_make_valid(@$fields['handle']);
                
                    if (
strlen(@$fields['email'])) { // remove email address if it will cause a duplicate
                        
$emailusers=qa_db_user_find_by_email($fields['email']);
                        if (
count($emailusers)) {
                            unset(
$fields['email']);
                            unset(
$fields['confirmed']);
                        }
                    }
                    
                    
$userid=qa_create_new_user((string)@$fields['email'], null /* no password */$handle,
                        isset(
$fields['level']) ? $fields['level'] : QA_USER_LEVEL_BASIC, @$fields['confirmed']);
                    
                    
qa_db_user_login_add($userid$source$identifier);
                    
qa_db_user_login_sync(false);
                    
                    
$profilefields=array('name''location''website''about');
                    
                    foreach (
$profilefields as $fieldname)
                        if (
strlen(@$fields[$fieldname]))
                            
qa_db_user_profile_set($userid$fieldname$fields[$fieldname]);
                            
                    if (
strlen(@$fields['avatar']))
                        
qa_set_user_avatar($userid$fields['avatar']);
                            
                    
qa_set_logged_in_user($userid$handlefalse$source);
                }
            }
        }

        
        function 
qa_get_logged_in_userid()
    
/*
        Return the userid of the currently logged in user, or null if none logged in
    */
        
{
            if (
qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__$args); }
        
            global 
$qa_logged_in_userid_checked;
            
            
$suffix=qa_session_var_suffix();
            
            if (!
$qa_logged_in_userid_checked) { // only check once
                
qa_start_session(); // this will load logged in userid from the native PHP session, but that's not enough
                
                
$sessionuserid=@$_SESSION['qa_session_userid_'.$suffix];
                
                if (isset(
$sessionuserid)) // check verify code matches
                    
if (@$_SESSION['qa_session_verify_'.$suffix] != qa_session_verify_code($sessionuserid))
                        
qa_clear_session_user();
                
                if (!empty(
$_COOKIE['qa_session'])) {
                    @list(
$handle$sessioncode$remember)=explode('/'$_COOKIE['qa_session']);
                    
                    if (
$remember)
                        
qa_set_session_cookie($handle$sessioncode$remember); // extend 'remember me' cookies each time
    
                    
$sessioncode=trim($sessioncode); // trim to prevent passing in blank values to match uninitiated DB rows
    
                    // Try to recover session from the database if PHP session has timed out
                    
if ( (!isset($_SESSION['qa_session_userid_'.$suffix])) && (!empty($handle)) && (!empty($sessioncode)) ) {
                        require_once 
QA_INCLUDE_DIR.'qa-db-selects.php';
                        
                        
$userinfo=qa_db_single_select(qa_db_user_account_selectspec($handlefalse)); // don't get any pending
                        
                        
if (strtolower(trim($userinfo['sessioncode'])) == strtolower($sessioncode))
                            
qa_set_session_user($userinfo['userid'], $userinfo['sessionsource']);
                        else
                            
qa_clear_session_cookie(); // if cookie not valid, remove it to save future checks
                    
}
                }
                
                
$qa_logged_in_userid_checked=true;
            }
            
            return @
$_SESSION['qa_session_userid_'.$suffix];
        }
        
        
        function 
qa_get_logged_in_source()
    
/*
        Get the source of the currently logged in user, from call to qa_log_in_external_user() or null if logged in normally
    */
        
{
            if (
qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__$args); }
        
            
$userid=qa_get_logged_in_userid();
            
$suffix=qa_session_var_suffix();
            
            if (isset(
$userid))
                return @
$_SESSION['qa_session_source_'.$suffix];
        }
        
        
        function 
qa_get_logged_in_user_field($field)
    
/*
        Return $field of the currently logged in user, cache to ensure only one call to external code
    */
        
{
            if (
qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__$args); }
        
            global 
$qa_cached_logged_in_user;
            
            
$userid=qa_get_logged_in_userid();
            
            if (isset(
$userid) && !isset($qa_cached_logged_in_user)) {
                require_once 
QA_INCLUDE_DIR.'qa-db-selects.php';
                
$qa_cached_logged_in_user=qa_db_get_pending_result('loggedinuser'qa_db_user_account_selectspec($useridtrue));
                
                if (!isset(
$qa_cached_logged_in_user)) { // the user can no longer be found (should be because they're deleted)
                    
qa_clear_session_user();
                    
qa_fatal_error('The logged in user cannot be found');
                        
// it's too late here to proceed because the caller may already be branching based on whether someone is logged in
                
}                    
            }
            
            return @
$qa_cached_logged_in_user[$field];
        }
        
        
        function 
qa_get_logged_in_points()
    
/*
        Return the number of points of the currently logged in user, or null if none is logged in
    */
        
{
            if (
qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__$args); }
        
            return 
qa_get_logged_in_user_field('points');
        }

        
        function 
qa_get_mysql_user_column_type()
    
/*
        Return column type to use for users (if not using single sign-on integration)
    */
        
{
            return 
'INT UNSIGNED';
        }


        function 
qa_get_one_user_html($handle$microformats)
    
/*
        Return HTML to display for user with username $handle
    */
        
{
            if (
qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__$args); }
        
            return 
strlen($handle) ? ('<A HREF="'.qa_path_html('user/'.$handle).
                
'" CLASS="qa-user-link'.($microformats ' url nickname' '').'">'.qa_html($handle).'</A>') : '';
        }
        
        
        function 
qa_get_user_avatar_html($flags$email$handle$blobid$width$height$size$padding=false)
    
/*
        Return HTML to display for the user's avatar, constrained to $size pixels, with optional $padding to that size
        Pass the user's fields $flags, $email, $handle, and avatar $blobid, $width and $height
    */    
        
{
            if (
qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__$args); }
        
            require_once 
QA_INCLUDE_DIR.'qa-app-format.php';
            
            if (
qa_opt('avatar_allow_gravatar') && ($flags QA_USER_FLAGS_SHOW_GRAVATAR))
                
$html=qa_get_gravatar_html($email$size);
            elseif (
qa_opt('avatar_allow_upload') && (($flags QA_USER_FLAGS_SHOW_AVATAR)) && isset($blobid))
                
$html=qa_get_avatar_blob_html($blobid$width$height$size$padding);
            elseif ( (
qa_opt('avatar_allow_gravatar')||qa_opt('avatar_allow_upload')) && qa_opt('avatar_default_show') && strlen(qa_opt('avatar_default_blobid')) )
                
$html=qa_get_avatar_blob_html(qa_opt('avatar_default_blobid'), qa_opt('avatar_default_width'), qa_opt('avatar_default_height'), $size$padding);
            else
                
$html=null;
                
            return (isset(
$html) && strlen($handle)) ? ('<A HREF="'.qa_path_html('user/'.$handle).'" CLASS="qa-avatar-link">'.$html.'</A>') : $html;
        }
        

        function 
qa_get_user_email($userid)
    
/*
        Return email address for user $userid (if not using single sign-on integration)
    */
        
{
            
$userinfo=qa_db_select_with_pending(qa_db_user_account_selectspec($useridtrue));

            return 
$userinfo['email'];
        }
        

        function 
qa_user_report_action($userid$action)
    
/*
        Called after a database write $action performed by a user $userid
    */
        
{
            if (
qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__$args); }
        
            require_once 
QA_INCLUDE_DIR.'qa-db-users.php';
            
            
qa_db_user_written($useridqa_remote_ip_address());
        }

        
        function 
qa_user_level_string($level)
    
/*
        Return textual representation of the user $level
    */
        
{
            if (
qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__$args); }
        
            if (
$level>=QA_USER_LEVEL_SUPER)
                
$string='users/level_super';
            elseif (
$level>=QA_USER_LEVEL_ADMIN)
                
$string='users/level_admin';
            elseif (
$level>=QA_USER_LEVEL_MODERATOR)
                
$string='users/level_moderator';
            elseif (
$level>=QA_USER_LEVEL_EDITOR)
                
$string='users/level_editor';
            elseif (
$level>=QA_USER_LEVEL_EXPERT)
                
$string='users/level_expert';
            else
                
$string='users/registered_user';
            
            return 
qa_lang($string);
        }

        
        function 
qa_get_login_links($rooturl$tourl)
    
/*
        Return an array of links to login, register, email confirm and logout pages (if not using single sign-on integration)
    */
        
{
            return array(
                
'login' => qa_path('login', isset($tourl) ? array('to' => $tourl) : null$rooturl),
                
'register' => qa_path('register', isset($tourl) ? array('to' => $tourl) : null$rooturl),
                
'confirm' => qa_path('confirm'null$rooturl),
                
'logout' => qa_path('logout'null$rooturl),
            );
        }

    } 
// end of: if (QA_FINAL_EXTERNAL_USERS) { ... } else { ... }


    
function qa_is_logged_in()
/*
    Return whether someone is logged in at the moment
*/
    
{    
        
$userid=qa_get_logged_in_userid();
        return isset(
$userid);
    }
    
    
    function 
qa_get_logged_in_handle()
/*
    Return displayable handle/username of currently logged in user, or null if none
*/
    
{
        return 
qa_get_logged_in_user_field(QA_FINAL_EXTERNAL_USERS 'publicusername' 'handle');
    }


    function 
qa_get_logged_in_email()
/*
    Return email of currently logged in user, or null if none
*/
    
{
        return 
qa_get_logged_in_user_field('email');
    }


    function 
qa_get_logged_in_level()
/*
    Return level of currently logged in user, or null if none
*/
    
{
        return 
qa_get_logged_in_user_field('level');
    }

    
    function 
qa_get_logged_in_flags()
/*
    Return flags (see QA_USER_FLAGS_*) of currently logged in user, or null if none
*/
    
{
        if (
QA_FINAL_EXTERNAL_USERS)
            return 
qa_get_logged_in_user_field('blocked') ? QA_USER_FLAGS_USER_BLOCKED 0;
        else
            return 
qa_get_logged_in_user_field('flags');
    }

    
    function 
qa_userids_to_handles($userids)
/*
    Return an array mapping each userid in $userids to that user's handle (public username), or to null if not found
*/
    
{
        if (
QA_FINAL_EXTERNAL_USERS)
            
$rawuseridhandles=qa_get_public_from_userids($userids);
        
        else {
            require_once 
QA_INCLUDE_DIR.'qa-db-users.php';
            
$rawuseridhandles=qa_db_user_get_userid_handles($userids);
        }
        
        
$gotuseridhandles=array();
        foreach (
$userids as $userid)
            
$gotuseridhandles[$userid]=@$rawuseridhandles[$userid];
            
        return 
$gotuseridhandles;
    }
    
    
    function 
qa_handles_to_userids($handles$exactonly=false)
/*
    Return an array mapping each handle in $handles the user's userid, or null if not found. If $exactonly is true then
    $handles must have the correct case and accents. Otherwise, handles are case- and accent-insensitive, and the keys
    of the returned array will match the $handles provided, not necessary those in the DB.
*/
    
{
        require_once 
QA_INCLUDE_DIR.'qa-util-string.php';
        
        if (
QA_FINAL_EXTERNAL_USERS)
            
$rawhandleuserids=qa_get_userids_from_public($handles);

        else {
            require_once 
QA_INCLUDE_DIR.'qa-db-users.php';
            
$rawhandleuserids=qa_db_user_get_handle_userids($handles);
        }
        
        
$gothandleuserids=array();

        if (
$exactonly) { // only take the exact matches
            
foreach ($handles as $handle)
                
$gothandleuserids[$handle]=@$rawhandleuserids[$handle];
        
        } else { 
// normalize to lowercase without accents, and then find matches
            
$normhandleuserids=array();
            foreach (
$rawhandleuserids as $handle => $userid)
                
$normhandleuserids[qa_string_remove_accents(qa_strtolower($handle))]=$userid;
            
            foreach (
$handles as $handle)
                
$gothandleuserids[$handle]=@$normhandleuserids[qa_string_remove_accents(qa_strtolower($handle))];
        }
        
        return 
$gothandleuserids;
    }
    
    
    function 
qa_user_permit_error($permitoption=null$limitaction=null)
/*
    Check whether the logged in user has permission to perform $permitoption. If $permitoption is null, this simply
    checks whether the user is blocked. Optionally provide an $limitaction (see top of qa-app-limits.php) to also check
    against user or IP rate limits.

    Possible results, in order of priority (i.e. if more than one reason, the first will be given):
    'level' => a special privilege level (e.g. expert) or minimum number of points is required
    'login' => the user should login or register
    'userblock' => the user has been blocked
    'ipblock' => the ip address has been blocked
    'confirm' => the user should confirm their email address
    'limit' => the user or IP address has reached a rate limit (if $limitaction specified)
    false => the operation can go ahead
*/
    
{
        if (
qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__$args); }
        
        require_once 
QA_INCLUDE_DIR.'qa-app-limits.php';
        
        
$userid=qa_get_logged_in_userid();
        
$flags=qa_get_logged_in_flags();

        
$error=qa_permit_error($permitoption$useridqa_get_logged_in_level(), $flags);
        
        if ((!
$error) && qa_is_ip_blocked())
            
$error='ipblock';
            
        if ((!
$error) && isset($userid) && ($flags QA_USER_FLAGS_MUST_CONFIRM))
            
$error='confirm';
        
        if (isset(
$limitaction) && !$error)
            if (
qa_limits_remaining(qa_get_logged_in_userid(), $limitaction)<=0)
                
$error='limit';
        
        return 
$error;
    }
    
    
    function 
qa_permit_error($permitoption$userid$userlevel$userflags$userpoints=null)
/*
    Check whether $userid (null for no user) can perform $permitoption. Result as for qa_user_permit_error(...).
    If appropriate, pass the user's level in $userlevel, flags in $userflags and points in $userpoints.
    If $userid is currently logged in, you can set $userpoints=null to retrieve them only if necessary.
*/
    
{
        if (
qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__$args); }
        
        
$permit=isset($permitoption) ? qa_opt($permitoption) : QA_PERMIT_ALL;

        if (isset(
$userid) && (($permit==QA_PERMIT_POINTS) || ($permit==QA_PERMIT_POINTS_CONFIRMED)) ) { // deal with points threshold by converting as appropriate
            
if ( (!isset($userpoints)) && ($userid==qa_get_logged_in_userid()) )
                
$userpoints=qa_get_logged_in_points(); // allow late retrieval of points (to avoid unnecessary DB query when using external users)
        
            
if ($userpoints>=qa_opt($permitoption.'_points'))
                
$permit=($permit==QA_PERMIT_POINTS_CONFIRMED) ? QA_PERMIT_CONFIRMED QA_PERMIT_USERS// convert if user has enough points
            
else
                
$permit=QA_PERMIT_EXPERTS// otherwise, only special users pass
        
}
        
        return 
qa_permit_value_error($permit$userid$userlevel$userflags);
    }
    
    
    function 
qa_permit_value_error($permit$userid$userlevel$userflags)
/*
    Check whether $userid of level $userlevel with $userflags can reach the permission level in $permit
    (generally retrieved from an option, but not always). Result as for qa_user_permit_error(...).
*/
    
{
        if (
qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__$args); }
        
        if (
$permit>=QA_PERMIT_ALL)
            
$error=false;
            
        elseif (
$permit>=QA_PERMIT_USERS)
            
$error=isset($userid) ? false 'login';
            
        elseif (
$permit>=QA_PERMIT_CONFIRMED) {
            if (!isset(
$userid))
                
$error='login';
            
            elseif (
                
QA_FINAL_EXTERNAL_USERS || // not currently supported by single sign-on integration
                
($userlevel>=QA_USER_LEVEL_EXPERT) || // if user assigned to a higher level, no need
                
($userflags QA_USER_FLAGS_EMAIL_CONFIRMED) || // actual confirmation
                
(!qa_opt('confirm_user_emails')) // if this option off, we can't ask it of the user
            
)
                
$error=false;
            
            else
                
$error='confirm';

        } elseif (
$permit>=QA_PERMIT_EXPERTS)
            
$error=(isset($userid) && ($userlevel>=QA_USER_LEVEL_EXPERT)) ? false 'level';
            
        elseif (
$permit>=QA_PERMIT_EDITORS)
            
$error=(isset($userid) && ($userlevel>=QA_USER_LEVEL_EDITOR)) ? false 'level';
            
        elseif (
$permit>=QA_PERMIT_MODERATORS)
            
$error=(isset($userid) && ($userlevel>=QA_USER_LEVEL_MODERATOR)) ? false 'level';
            
        elseif (
$permit>=QA_PERMIT_ADMINS)
            
$error=(isset($userid) && ($userlevel>=QA_USER_LEVEL_ADMIN)) ? false 'level';
            
        else
            
$error=(isset($userid) && ($userlevel>=QA_USER_LEVEL_SUPER)) ? false 'level';
        
        if (isset(
$userid) && ($userflags QA_USER_FLAGS_USER_BLOCKED) && ($error!='level'))
            
$error='userblock';
        
        return 
$error;
    }
    
    
    function 
qa_user_use_captcha()
/*
    Return whether a captcha should be presented to the current user for writing posts
*/
    
{
        if (
qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__$args); }
        
        
$usecaptcha=false;
        
        if (
qa_get_logged_in_level() < QA_USER_LEVEL_EXPERT) { // experts and above aren't shown captchas
            
$userid=qa_get_logged_in_userid();
            
            if (
qa_opt('captcha_on_anon_post') && !isset($userid))
                
$usecaptcha=true;
            elseif (
qa_opt('confirm_user_emails') && qa_opt('captcha_on_unconfirmed') && !(qa_get_logged_in_flags() & QA_USER_FLAGS_EMAIL_CONFIRMED) )
                
$usecaptcha=true;
        }
        
        return 
$usecaptcha;
    }
    
    
    function 
qa_user_moderation_reason()
/*
    Return whether moderation is required for posts submitted by the current user. Possible results:
    'login' => moderation required because the user is not logged in
    'confirm' => moderation required because the user has not confirmed their email address
    'points' => moderation required because the user has insufficient points
    false => moderation is not required
*/
    
{
        if (
qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__$args); }
        
        
$reason=false;
        
        if (
            (
qa_get_logged_in_level() < QA_USER_LEVEL_EXPERT) && // experts and above aren't moderated
            
qa_user_permit_error('permit_moderate'// if the user can approve posts, no point in moderating theirs
        
) {
            
$userid=qa_get_logged_in_userid();
            
            if (isset(
$userid)) {
                if (
qa_opt('confirm_user_emails') && qa_opt('moderate_unconfirmed') && !(qa_get_logged_in_flags() & QA_USER_FLAGS_EMAIL_CONFIRMED) )
                    
$reason='confirm';
                elseif (
qa_opt('moderate_by_points') && (qa_get_logged_in_points() < qa_opt('moderate_points_limit')))
                    
$reason='points';
            
            } elseif (
qa_opt('moderate_anon_post'))
                
$reason='login';
        }
        
        return 
$reason;
    }
    
    
    function 
qa_user_userfield_label($userfield)
/*
    Return the label to display for $userfield as retrieved from the database, using default if no name set
*/
    
{
        if (isset(
$userfield['content']))
            return 
$userfield['content'];
        
        else {
            
$defaultlabels=array(
                
'name' => 'users/full_name',
                
'about' => 'users/about',
                
'location' => 'users/location',
                
'website' => 'users/website',
            );
            
            if (isset(
$defaultlabels[$userfield['title']]))
                return 
qa_lang($defaultlabels[$userfield['title']]);
        }
            
        return 
'';
    }
    

/*
    Omit PHP closing tag to help avoid accidental output
*/
Онлайн: 0
Реклама