Файл: library/XenForo/Visitor.php
Строк: 669
<?php
/**
* Visitor Class
*
* @package XenForo_Core
*/
class XenForo_Visitor implements ArrayAccess
{
/**
* Instance manager.
*
* @var XenForo_Visitor
*/
protected static $_instance;
/**
* List of browser strings to check for in the {@link isBrowsingWith()} function.
*
* @var array
*/
protected static $_browsers = array(
'firefox' => 'Firefox',
'ie' => 'MSIE',
'webkit' => 'WebKit',
'opera' => 'Opera'
);
protected static $_setupOptions = null;
/**
* Array of user info.
*
* @var array
*/
protected $_user = array();
/**
* Language the user is using.
*
* @var array
*/
protected $_language = array();
/**
* Cache of node-specific permissions for this user.
*
* @var array
*/
protected $_nodePermissions = array();
/**
* List of admin permissions the user has. Note that this may not be populated
* until necessary.
*
* @var array|null
*/
protected $_adminPermissions = null;
/**
* Stores if user is a super admin.
*
* @var boolean|null
*/
protected $_isSuperAdmin = null;
/**
* Protected constructor. Use {@link getInstance()} instead.
*/
protected function __construct()
{
}
/**
* Gets the browsing user's info.
*
* @return XenForo_Visitor
*/
public static final function getInstance()
{
if (!self::$_instance)
{
self::setup(0); // setup sets the instance
}
return self::$_instance;
}
public static final function setInstance(XenForo_Visitor $v)
{
self::$_instance = $v;
}
/**
* Determines if we have a visitor instance setup.
*
* @return boolean
*/
public static function hasInstance()
{
return (self::$_instance ? true : false);
}
/**
* Returns the user ID of the current visiting user
*
* @return integer User ID
*/
public static function getUserId()
{
$object = self::getInstance();
return $object['user_id'];
}
public static function getVisitorSetupOptions()
{
return self::$_setupOptions;
}
/**
* Returns the permission combination ID of the current visiting user
*
* @return integer permission combination ID
*/
public static function getPermissionCombinationId()
{
$object = self::getInstance();
return $object['permission_combination_id'];
}
/**
* Gets the user info in array format (for areas that require actual arrays).
*
* @return array
*/
public function toArray()
{
return $this->_user;
}
/**
* Gets the user's language.
*
* @return array
*/
public function getLanguage()
{
return $this->_language;
}
/**
* Determines if the visitor has a specific permission.
*
* @param string $group Permission group
* @param string $permission
*
* @return boolean|int
*/
public function hasPermission($group, $permission)
{
return XenForo_Permission::hasPermission($this->_user['permissions'], $group, $permission);
}
/**
* Gets all global permissions for the visitor.
*
* @return array Format: [group][permission] => value
*/
public function getPermissions()
{
return $this->_user['permissions'];
}
/**
* Set the visitor's permissions for a particular node. Useful caching.
*
* @param integer $nodeId
* @param array|string $permissions Permissions (may be serialized)
*/
public function setNodePermissions($nodeId, $permissions)
{
if (is_string($permissions))
{
$permissions = XenForo_Permission::unserializePermissions($permissions);
}
if (is_array($permissions))
{
$this->_nodePermissions[$nodeId] = $permissions;
}
}
/**
* Returns true if there are node permissions cached for the specified node.
*
* @param integer $nodeId
*
* @return boolean
*/
public function hasNodePermissionsCached($nodeId)
{
return isset($this->_nodePermissions[$nodeId]);
}
/**
* Determines if the visitor has the specified permission on a specific node.
*
* @param integer $nodeId
* @param string $permission
*
* @return boolean
*/
public function hasNodePermission($nodeId, $permission)
{
return XenForo_Permission::hasContentPermission($this->getNodePermissions($nodeId), $permission);
}
/**
* Gets the visitor's permissions for a specific node. Permissions will be
* fetched if necessary.
*
* @param integer $nodeId
*
* @return array
*/
public function getNodePermissions($nodeId)
{
if (!isset($this->_nodePermissions[$nodeId]))
{
/* @var $permissionCacheModel XenForo_Model_PermissionCache */
$permissionCacheModel = XenForo_Model::create('XenForo_Model_PermissionCache');
$this->_nodePermissions[$nodeId] = $permissionCacheModel->getContentPermissionsForItem(
$this->_user['permission_combination_id'], 'node', $nodeId
);
}
return $this->_nodePermissions[$nodeId];
}
/**
* Get all cached node permissions for the visitor. Not all nodes may be present.
*
* @return array Format: [node id] => permissions
*/
public function getAllNodePermissions()
{
return $this->_nodePermissions;
}
/**
* Determines if the current user has the specified admin permission.
*
* @param string $permissionId
*
* @return boolean
*/
public function hasAdminPermission($permissionId)
{
if (empty($this->_user['user_id']) || empty($this->_user['is_admin']))
{
return false;
}
if ($this->isSuperAdmin())
{
return true;
}
if (!is_array($this->_adminPermissions))
{
$this->_adminPermissions = XenForo_Model::create('XenForo_Model_Admin')->getAdminPermissionCacheForUser(
$this->_user['user_id']
);
}
return !empty($this->_adminPermissions[$permissionId]);
}
/**
* Determines if current user is a super admin.
*
* @return boolean
*/
public function isSuperAdmin()
{
if ($this->_isSuperAdmin === null)
{
$superAdmins = preg_split(
'#s*,s*#', XenForo_Application::get('config')->superAdmins,
-1, PREG_SPLIT_NO_EMPTY
);
$this->_isSuperAdmin = in_array($this->_user['user_id'], $superAdmins);
}
return $this->_isSuperAdmin;
}
/**
* Returns true if the visitor should be shown a CAPTCHA.
*
* @return boolean
*/
public function showCaptcha()
{
return ($this->_user['user_id'] == 0); // TODO: permission
}
/**
* Returns true if visitor can run searches. Does not cover find new or user content searches.
*
* @return boolean
*/
public function canSearch()
{
// TODO: we should probably distinguish between search disabled and no permission to search
return ($this->hasPermission('general', 'search') && XenForo_Application::get('options')->enableSearch);
}
public function canFollow()
{
return ($this->_user['user_id'] && $this->_user['user_state'] == 'valid');
}
/**
* Returns true if visitor can upload/change their avatar.
*
* @return boolean
*/
public function canUploadAvatar()
{
return (
$this->_user['user_id']
&& $this->hasPermission('avatar', 'allowed')
&& $this->hasPermission('avatar', 'maxFileSize') != 0
);
}
/**
* Returns true if the visitor can edit his/her signature.
*
* @return boolean
*/
public function canEditSignature()
{
return ($this->_user['user_id']
&& $this->hasPermission('general', 'editSignature')
&& $this->hasPermission('signature', 'maxLines') != 0
);
}
/**
* @return bool
*/
public function canEditProfile()
{
return ($this->_user['user_id'] && $this->hasPermission('general', 'editProfile'));
}
/**
* Determines if the visitor can update his/hew status.
*
* @return boolean
*/
public function canUpdateStatus()
{
if (!$this->_user['user_id'])
{
return false;
}
return (
$this->_user['user_id']
&& $this->hasPermission('profilePost', 'view')
&& $this->hasPermission('profilePost', 'post')
);
}
public function canStartConversations()
{
return XenForo_Model::create('XenForo_Model_User')->canStartConversations($null, $this->_user);
}
/**
* Setup the visitor singleton.
*
* @param integer $userId User ID to setup as
* @param array $options
*
* @return XenForo_Visitor
*/
public static function setup($userId, array $options = array())
{
$userId = intval($userId);
$options = array_merge(array(
'languageId' => 0,
'permissionUserId' => 0
), $options);
/* @var $userModel XenForo_Model_User */
$userModel = XenForo_Model::create('XenForo_Model_User');
$class = XenForo_Application::resolveDynamicClass('XenForo_Visitor');
$object = new $class();
if ($userId && $user = $userModel->getVisitingUserById($userId))
{
if ($user['is_admin'] && $options['permissionUserId'])
{
// force permissions for testing
$user = $userModel->setPermissionsFromUserId($user, $options['permissionUserId']);
}
$object->_user = $user;
}
else
{
$object->_user = $userModel->getVisitingGuestUser();
if ($options['languageId'])
{
$object->_user['language_id'] = $options['languageId'];
}
}
$object->_user = $userModel->prepareUser($object->_user);
$object->_user['referer'] = !empty($options['referer']) ? $options['referer'] : null;
$object->_user['from_search'] = !empty($options['fromSearch']);
if (!empty($object->_user['ignored']))
{
$ignored = unserialize($object->_user['ignored']);
$object->_user['ignoredUsers'] = $ignored;
}
else
{
$object->_user['ignoredUsers'] = array();
}
if (!$object->_user['global_permission_cache'])
{
// force a rebuild if we don't have the perm cache
$perms = XenForo_Model::create('XenForo_Model_Permission')->rebuildPermissionCombinationById(
$object->_user['permission_combination_id']
);
$object->_user['permissions'] = $perms ? $perms : array();
}
else
{
$object->_user['permissions'] = XenForo_Permission::unserializePermissions($object->_user['global_permission_cache']);
}
$object->setVisitorLanguage($object->_user['language_id']);
XenForo_Locale::setDefaultTimeZone($object->_user['timezone']);
self::$_instance = $object;
self::$_setupOptions = $options;
XenForo_CodeEvent::fire('visitor_setup', array(&self::$_instance));
return self::$_instance;
}
public function setVisitorLanguage($languageId)
{
$languages = (XenForo_Application::isRegistered('languages')
? XenForo_Application::get('languages')
: XenForo_Model::create('XenForo_Model_Language')->getAllLanguagesForCache()
);
if ($languageId && !empty($languages[$languageId]))
{
$language = $languages[$languageId];
}
else
{
$defaultLanguageId = XenForo_Application::get('options')->defaultLanguageId;
if (!empty($languages[$defaultLanguageId]))
{
$language = $languages[$defaultLanguageId];
}
else
{
$language = reset($languages);
}
}
if (!$language)
{
return; // this probably shouldn't happen
}
if (empty($language['phrase_cache']))
{
$language['phrase_cache'] = array();
}
$this->_language = $language;
XenForo_Phrase::setLanguageId($language['language_id']);
XenForo_Phrase::setPhrases($language['phrase_cache']);
XenForo_Locale::setDefaultLanguage($language);
}
/**
* Checks to verify that the visitor is browsing with a particular user agent
*
* @param string $browser
*
* @return boolean
*/
public static function isBrowsingWith($browser)
{
if (!isset($_SERVER['HTTP_USER_AGENT']))
{
return false;
}
$ua = $_SERVER['HTTP_USER_AGENT'];
if ($browser == 'mobile')
{
if (self::isBrowsingWith('webkit'))
{
if (preg_match('# Mobile( Safari)?/#', $ua)) // iPhone, Android, etc
{
return true;
}
else if (preg_match('#NokiaN[^/]*#', $ua))
{
return true;
}
else if (strpos('SymbianOS', $ua) !== false)
{
return true;
}
else if (strpos('Silk-Accelerated', $ua) !== false) // Amazon Silk
{
return true;
}
}
else if (self::isBrowsingWith('opera') && preg_match('#Opera( |/)(Mini|8|9.[0-7])#', $ua))
{
// well, this may not be mobile, but is very old :)
return true;
}
else if (preg_match('#IEMobile/#', $ua))
{
return true;
}
else if (preg_match('#^BlackBerry#', $ua))
{
return true;
}
return false;
}
//TODO: Add version checking and more browsers
$browser = strtolower($browser);
if (array_key_exists($browser, self::$_browsers))
{
return (strpos($ua, self::$_browsers[$browser]) !== false);
}
else
{
return false;
}
}
/**
* Returns whether or not the specified user is being followed by the visitor
*
* @param integer $userId
*
* @return boolean
*/
public function isFollowing($userId)
{
if (!$this->_user['user_id'] || $userId == $this->_user['user_id'])
{
return false;
}
return XenForo_Model::create('XenForo_Model_User')->isFollowing($userId, $this->_user);
}
/**
* Returns whether or not the specified user is being ignored by the visitor
*
* @param integer $userId
*
* @return boolean
*/
public function isIgnoring($userId)
{
if (!$userId || !$this->_user['user_id'] || $userId == $this->_user['user_id'] || empty($this->_user['ignoredUsers']))
{
return false;
}
return isset($this->_user['ignoredUsers'][$userId]);
}
/**
* Determines if the visitor is a member of the specified user group
*
* @param integer $userGroupId
* @param boolean $includeSecondaryGroups
*
* @return boolean
*/
public function isMemberOf($userGroupId, $includeSecondaryGroups = true)
{
static $userModel = null;
if ($userModel === null)
{
$userModel = XenForo_Model::create('XenForo_Model_User');
}
return $userModel->isMemberOfUserGroup($this->_user, $userGroupId, $includeSecondaryGroups);
}
/**
* OO approach to getting a value from the visitor. Good if you want a single value in one line.
*
* @param string $name
*
* @return mixed False if the value can't be found
*/
public function get($name)
{
if (array_key_exists($name, $this->_user))
{
return $this->_user[$name];
}
else
{
return false;
}
}
/**
* For ArrayAccess.
*
* @param string $offset
*/
public function offsetExists($offset)
{
return isset($this->_user[$offset]);
}
/**
* For ArrayAccess.
*
* @param string $offset
*/
public function offsetGet($offset)
{
return $this->_user[$offset];
}
/**
* For ArrayAccess.
*
* @param string $offset
* @param mixed $value
*/
public function offsetSet($offset, $value)
{
$this->_user[$offset] = $value;
}
/**
* For ArrayAccess.
*
* @param string $offset
*/
public function offsetUnset($offset)
{
unset($this->_user[$offset]);
}
/**
* Magic method for array access
*/
public function __get($name)
{
return $this->get($name);
}
}