mirror of
				https://github.com/gtbu/Typesetter-5.3-p8.git
				synced 2025-11-04 06:48:27 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1233 lines
		
	
	
	
		
			28 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			1233 lines
		
	
	
	
		
			28 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
namespace gp\tool;
 | 
						|
 | 
						|
defined('is_running') or die('Not an entry point...');
 | 
						|
 | 
						|
 | 
						|
gp_defined('gp_lock_time',900); // = 15 minutes
 | 
						|
 | 
						|
 | 
						|
class Session{
 | 
						|
 | 
						|
	private static $singleton;
 | 
						|
	private $logged_in			= false;
 | 
						|
	private $session_id;
 | 
						|
	private $session_file;
 | 
						|
 | 
						|
 | 
						|
	public static function Init(){
 | 
						|
		return self::getInstance();
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Get singleton instance
 | 
						|
	 * @return \gp\tool\Session
 | 
						|
	 */
 | 
						|
	public static function getInstance(){
 | 
						|
		if( !isset(self::$singleton) ){
 | 
						|
			self::$singleton = new static();
 | 
						|
		}
 | 
						|
		return self::$singleton;
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
	public function __construct(){
 | 
						|
 | 
						|
		self::SetConstants();
 | 
						|
 | 
						|
		if( isset($_COOKIE[gp_session_cookie]) ){
 | 
						|
			self::CheckPosts();
 | 
						|
			$this->Start($_COOKIE[gp_session_cookie]);
 | 
						|
		}
 | 
						|
 | 
						|
		$cmd = \gp\tool::GetCommand();
 | 
						|
 | 
						|
		switch( $cmd ){
 | 
						|
			case 'logout':
 | 
						|
				$this->LogOut();
 | 
						|
				return;
 | 
						|
 | 
						|
			case 'login':
 | 
						|
				$this->LogIn();
 | 
						|
				return;
 | 
						|
		}
 | 
						|
 | 
						|
		if( $this->logged_in ){
 | 
						|
			$this->Prepare();
 | 
						|
		}
 | 
						|
 | 
						|
		if( $cmd === 'ClearErrors' ){
 | 
						|
			self::ClearErrors();
 | 
						|
		}
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
	public static function SetConstants(){
 | 
						|
		global $config;
 | 
						|
		gp_defined('gp_session_cookie',self::SessionCookie($config['gpuniq']));
 | 
						|
		gp_defined('gp_installation_cookie',self::SessionCookie('g-'.$config['gpuniq']));
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	public function LogIn(){
 | 
						|
		global $langmessage;
 | 
						|
 | 
						|
 | 
						|
		if( $this->logged_in ){
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		// check nonce
 | 
						|
		// expire the nonce after 10 minutes
 | 
						|
		$nonce = $_POST['login_nonce'];
 | 
						|
		if( !\gp\tool\Nonce::Verify('login_nonce', $nonce, true, 300) ){
 | 
						|
			msg($langmessage['OOPS'] . ' (Expired Nonce)');
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		if( !self::HasCookies() ){
 | 
						|
			msg($langmessage['COOKIES_REQUIRED']);
 | 
						|
			return false;
 | 
						|
		}
 | 
						|
 | 
						|
		//delete the entry in $sessions if we're going to create another one with login
 | 
						|
		if( isset($_COOKIE[gp_session_cookie]) ){
 | 
						|
			self::CleanSession($_COOKIE[gp_session_cookie]);
 | 
						|
		}
 | 
						|
 | 
						|
		$users		= \gp\tool\Files::Get('_site/users');
 | 
						|
		$username	= self::GetLoginUser($users, $nonce);
 | 
						|
 | 
						|
		if( $username === false ){
 | 
						|
			self::IncorrectLogin('1');
 | 
						|
			return false;
 | 
						|
		}
 | 
						|
		$users[$username] += array(
 | 
						|
			'attempts'	=> 0,
 | 
						|
			'granted'	=> '', // 'editing' will be set EditingValue()
 | 
						|
		);
 | 
						|
		$userinfo = $users[$username];
 | 
						|
 | 
						|
		//Check Attempts
 | 
						|
		if( $userinfo['attempts'] >= 5 ){
 | 
						|
			$timeDiff = (time() - $userinfo['lastattempt']) / 60; //minutes
 | 
						|
			if( $timeDiff < 10 ){
 | 
						|
				msg($langmessage['LOGIN_BLOCK'], ceil(10 - $timeDiff));
 | 
						|
				return false;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		//check against password sent to a user's email address from the forgot_password form
 | 
						|
		$passed = self::PasswordPassed($userinfo, $nonce);
 | 
						|
 | 
						|
		//if passwords don't match
 | 
						|
		if( $passed !== true ){
 | 
						|
			self::IncorrectLogin('2');
 | 
						|
			self::UpdateAttempts($users, $username);
 | 
						|
			return false;
 | 
						|
		}
 | 
						|
 | 
						|
		//will be saved in UpdateAttempts
 | 
						|
		if( isset($userinfo['newpass']) ){
 | 
						|
			unset($userinfo['newpass']);
 | 
						|
		}
 | 
						|
 | 
						|
		$session_id = self::create($userinfo, $username, $sessions);
 | 
						|
		if( !$session_id ){
 | 
						|
			msg($langmessage['OOPS'] . ' (Data Not Saved)');
 | 
						|
			self::UpdateAttempts($users, $username, true);
 | 
						|
			return false;
 | 
						|
		}
 | 
						|
 | 
						|
 | 
						|
		if( $this->Start($session_id, $sessions) ){
 | 
						|
			msg($langmessage['logged_in']);
 | 
						|
		}
 | 
						|
 | 
						|
 | 
						|
		//need to save the user info regardless of success or not
 | 
						|
		//also saves file_name in users.php
 | 
						|
		$users[$username] = $userinfo;
 | 
						|
		self::UpdateAttempts($users, $username, true);
 | 
						|
 | 
						|
		//redirect to prevent resubmission
 | 
						|
		$this->Redirect();
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Return true if we can confirm there are cookies
 | 
						|
	 * Return false and attempt to set a cookie otherwise
 | 
						|
	 *
 | 
						|
	 */
 | 
						|
	public static function HasCookies(){
 | 
						|
		global $config;
 | 
						|
 | 
						|
		self::SetConstants();
 | 
						|
 | 
						|
		if( array_key_exists(gp_session_cookie, $_COOKIE) ||
 | 
						|
			array_key_exists(gp_installation_cookie, $_COOKIE)
 | 
						|
			){
 | 
						|
			return true;
 | 
						|
		}
 | 
						|
 | 
						|
		\gp\tool\Session::cookie(gp_installation_cookie,'2');
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Redirect user after login
 | 
						|
	 *
 | 
						|
	 */
 | 
						|
	public function Redirect(){
 | 
						|
		global $gp_index;
 | 
						|
 | 
						|
		if( !$this->logged_in ){
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		$redirect = false;
 | 
						|
 | 
						|
		if( isset($_REQUEST['file']) ){
 | 
						|
			$redirect = \gp\tool::ArrayKey($_REQUEST['file'], $gp_index );
 | 
						|
		}
 | 
						|
 | 
						|
		if( $redirect === false ){
 | 
						|
			$redirect = 'Admin';
 | 
						|
		}
 | 
						|
 | 
						|
		$url = \gp\tool::GetUrl($redirect, '', false);
 | 
						|
		\gp\tool::Redirect($url);
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Return the username for the login request
 | 
						|
	 *
 | 
						|
	 */
 | 
						|
	public static function GetLoginUser( $users, $nonce ){
 | 
						|
 | 
						|
		$_POST += array(
 | 
						|
			'user_sha'		=> '',
 | 
						|
			'username'		=> '',
 | 
						|
			'login_nonce'	=> '',
 | 
						|
		);
 | 
						|
 | 
						|
		if( gp_require_encrypt && empty($_POST['user_sha']) ){
 | 
						|
			return false;
 | 
						|
		}
 | 
						|
 | 
						|
		foreach($users as $username => $info){
 | 
						|
			$sha_user = sha1($nonce.$username);
 | 
						|
 | 
						|
			if( !gp_require_encrypt
 | 
						|
				&& !empty($_POST['username'])
 | 
						|
				&& $_POST['username'] == $username
 | 
						|
				){
 | 
						|
					return $username;
 | 
						|
			}
 | 
						|
 | 
						|
			if( $sha_user === $_POST['user_sha'] ){
 | 
						|
				return $username;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Check the posted password
 | 
						|
	 * Check against reset password if set
 | 
						|
	 *
 | 
						|
	 */
 | 
						|
	public static function PasswordPassed(&$userinfo, $nonce){
 | 
						|
 | 
						|
		if( gp_require_encrypt && !empty($_POST['password']) ){
 | 
						|
			return false;
 | 
						|
		}
 | 
						|
 | 
						|
		//if not encrypted with js
 | 
						|
		if( !empty($_POST['password']) ){
 | 
						|
			$_POST['pass_md5']		= sha1($nonce . md5($_POST['password']));
 | 
						|
			$_POST['pass_sha']		= sha1($nonce . sha1($_POST['password']));
 | 
						|
			$_POST['pass_sha512']	= \gp\tool::hash($_POST['password'], 'sha512', 50);
 | 
						|
		}
 | 
						|
 | 
						|
		$pass_algo = self::PassAlgo($userinfo);
 | 
						|
 | 
						|
		if( !empty($userinfo['newpass']) && self::CheckPassword($userinfo['newpass'], $nonce, $pass_algo) ){
 | 
						|
			$userinfo['password'] = $userinfo['newpass'];
 | 
						|
			return true;
 | 
						|
		}
 | 
						|
 | 
						|
		//check password
 | 
						|
		if( self::CheckPassword($userinfo['password'], $nonce, $pass_algo) ){
 | 
						|
			return true;
 | 
						|
		}
 | 
						|
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Return the algorithm used by the user for passwords
 | 
						|
	 *
 | 
						|
	 */
 | 
						|
	public static function PassAlgo($userinfo){
 | 
						|
		global $config;
 | 
						|
 | 
						|
		if( isset($userinfo['passhash']) ){
 | 
						|
			return $userinfo['passhash'];
 | 
						|
		}
 | 
						|
		return $config['passhash'];
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Check password, choose between plaintext, md5 encrypted or sha-1 encrypted
 | 
						|
	 * @param string $user_pass
 | 
						|
	 * @param string $nonce
 | 
						|
	 * @param string $pass_algo Password hashing algorithm
 | 
						|
	 *
 | 
						|
	 */
 | 
						|
	public static function CheckPassword($user_pass, $nonce, $pass_algo){
 | 
						|
		global $config;
 | 
						|
 | 
						|
		$posted_pass = false;
 | 
						|
		switch($pass_algo){
 | 
						|
 | 
						|
			case 'md5':
 | 
						|
				$posted_pass = $_POST['pass_md5'];
 | 
						|
				$user_pass = sha1($nonce . $user_pass);
 | 
						|
			break;
 | 
						|
 | 
						|
			case 'sha1':
 | 
						|
				$posted_pass = $_POST['pass_sha'];
 | 
						|
				$user_pass = sha1($nonce . $user_pass);
 | 
						|
			break;
 | 
						|
 | 
						|
			case 'sha512':
 | 
						|
				//javascript only loops through sha512 50 times
 | 
						|
				$posted_pass = \gp\tool::hash($_POST['pass_sha512'], 'sha512', 950);
 | 
						|
			break;
 | 
						|
 | 
						|
			case 'password_hash':
 | 
						|
				if( !function_exists('password_verify') ){
 | 
						|
					msg('This version of PHP does not have password_verify(). '
 | 
						|
					. 'To fix, reset your password at /Admin_Preferences and '
 | 
						|
					. 'select "sha512" for the "Password Algorithm"');
 | 
						|
					return false;
 | 
						|
				}
 | 
						|
				return password_verify($_POST['pass_sha512'], $user_pass);
 | 
						|
 | 
						|
		}
 | 
						|
 | 
						|
		if( $posted_pass && $posted_pass === $user_pass ){
 | 
						|
			return true;
 | 
						|
		}
 | 
						|
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	public static function IncorrectLogin($i){
 | 
						|
		global $langmessage;
 | 
						|
		msg($langmessage['incorrect_login'] . ' (' . $i . ')');
 | 
						|
		$url = \gp\tool::GetUrl('Admin', 'cmd=forgotten');
 | 
						|
		msg($langmessage['forgotten_password'], $url);
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Set the value of $userinfo['file_name']
 | 
						|
	 *
 | 
						|
	 */
 | 
						|
	public static function SetSessionFileName($userinfo,$username){
 | 
						|
		global $dataDir;
 | 
						|
 | 
						|
		if( isset($userinfo['file_name']) ){
 | 
						|
			return $userinfo;
 | 
						|
		}
 | 
						|
 | 
						|
		do{
 | 
						|
			$new_file_name	= 'gpsess_' . \gp\tool::RandomString(40) . '.php';
 | 
						|
			$new_file		= $dataDir . '/data/_sessions/' . $new_file_name;
 | 
						|
		}while( \gp\tool\Files::Exists($new_file) );
 | 
						|
 | 
						|
		$userinfo['file_name']	= $new_file_name;
 | 
						|
 | 
						|
		return $userinfo;
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	public function LogOut(){
 | 
						|
		global $langmessage;
 | 
						|
 | 
						|
		if( empty($_GET['verified']) ){
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		if( !\gp\tool\Nonce::Verify('post', $_GET['verified'], true) ){
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		if( !$this->logged_in ){
 | 
						|
			return false;
 | 
						|
		}
 | 
						|
 | 
						|
		if( !isset($_COOKIE[gp_session_cookie]) ){
 | 
						|
			return false;
 | 
						|
		}
 | 
						|
 | 
						|
 | 
						|
		$session_id = $_COOKIE[gp_session_cookie];
 | 
						|
 | 
						|
		self::Unlock($session_id);
 | 
						|
		self::cookie(gp_session_cookie);
 | 
						|
		self::CleanSession($session_id);
 | 
						|
		$this->logged_in = false;
 | 
						|
 | 
						|
		msg($langmessage['LOGGED_OUT']);
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Remove the admin session lock
 | 
						|
	 *
 | 
						|
	 */
 | 
						|
	public static function Unlock($session_id){
 | 
						|
		return \gp\tool\Files::Unlock('admin', sha1(sha1($session_id)));
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	public static function CleanSession($session_id){
 | 
						|
		//remove the session_id from session_ids.php
 | 
						|
		$sessions = self::GetSessionIds();
 | 
						|
		unset($sessions[$session_id]);
 | 
						|
		self::SaveSessionIds($sessions);
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Set a session cookie
 | 
						|
	 * Attempt to use httponly if available
 | 
						|
	 *
 | 
						|
	 */
 | 
						|
	public static function Cookie($name, $value='', $expires = false){
 | 
						|
		global $dirPrefix;
 | 
						|
 | 
						|
		$cookiePath		= empty($dirPrefix) ? '/' : $dirPrefix;
 | 
						|
		$cookiePath		= \gp\tool::HrefEncode($cookiePath, false);
 | 
						|
		$secure			= (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on');
 | 
						|
		$domain			= \gp\tool::ServerName(true);
 | 
						|
 | 
						|
		if( !$domain || strpos($domain, '.') === false ){
 | 
						|
			$domain = '';
 | 
						|
		}
 | 
						|
 | 
						|
		if( strpos($domain, ':') !== false ){
 | 
						|
			$domain = substr($domain, 0, strrpos($domain, ':'));
 | 
						|
		}
 | 
						|
 | 
						|
		// expire if value is empty
 | 
						|
		// cookies are set with either www removed from the domain or with an empty string
 | 
						|
		if( empty($value) ){
 | 
						|
			$expires = time()-2592000;
 | 
						|
			setcookie($name, $value, $expires, $cookiePath, $domain, $secure, true);
 | 
						|
			setcookie($name, $value, $expires, $cookiePath, $domain, false, true);
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
 | 
						|
		// get expiration and set
 | 
						|
		if( $expires === false ){
 | 
						|
			$expires = time()+2592000; //30 days
 | 
						|
		}elseif( $expires === true ){
 | 
						|
			$expires = 0; //expire at end of session
 | 
						|
		}
 | 
						|
 | 
						|
		setcookie($name, $value, $expires, $cookiePath, $domain, $secure, true);
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Update the number of login attempts and the time of the last attempt for a $username
 | 
						|
	 *
 | 
						|
	 */
 | 
						|
	public static function UpdateAttempts($users,$username,$reset = false){
 | 
						|
		if( $reset ){
 | 
						|
			$users[$username]['attempts'] = 0;
 | 
						|
		}else{
 | 
						|
			$users[$username]['attempts']++;
 | 
						|
		}
 | 
						|
		$users[$username]['lastattempt'] = time();
 | 
						|
		\gp\tool\Files::SaveData('_site/users', 'users', $users);
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * called when a user logs in
 | 
						|
	 *
 | 
						|
	 */
 | 
						|
	public static function create(&$user_info, $username, &$sessions){
 | 
						|
		global $dataDir, $langmessage;
 | 
						|
 | 
						|
		//update the session files to .php files
 | 
						|
		//changes to $userinfo will be saved by UpdateAttempts() below
 | 
						|
		$user_info			= self::SetSessionFileName($user_info, $username);
 | 
						|
		$user_file_name		= $user_info['file_name'];
 | 
						|
		$user_file			= $dataDir . '/data/_sessions/' . $user_file_name;
 | 
						|
 | 
						|
 | 
						|
		//use an existing session_id if the new login matches an existing session (uid and file_name)
 | 
						|
		$sessions			= self::GetSessionIds();
 | 
						|
		$uid				= self::auth_browseruid();
 | 
						|
		$session_id			= false;
 | 
						|
		foreach($sessions as $sess_temp_id => $sess_temp_info){
 | 
						|
			if( isset($sess_temp_info['uid']) &&
 | 
						|
				$sess_temp_info['uid'] == $uid &&
 | 
						|
				$sess_temp_info['file_name'] == $user_file_name
 | 
						|
				){
 | 
						|
				$session_id = $sess_temp_id;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		//create a unique session id if needed
 | 
						|
		if( $session_id === false ){
 | 
						|
			do{
 | 
						|
				$session_id = \gp\tool::RandomString(40);
 | 
						|
			}while( isset($sessions[$session_id]) );
 | 
						|
		}
 | 
						|
 | 
						|
		$expires = !isset($_POST['remember']);
 | 
						|
		self::cookie(gp_session_cookie, $session_id, $expires);
 | 
						|
 | 
						|
		//save session id
 | 
						|
		$sessions[$session_id]					= array();
 | 
						|
		$sessions[$session_id]['file_name']		= $user_file_name;
 | 
						|
		$sessions[$session_id]['uid']			= $uid;
 | 
						|
		//$sessions[$session_id]['time'] = time(); //for session locking
 | 
						|
		if( !self::SaveSessionIds($sessions) ){
 | 
						|
			return false;
 | 
						|
		}
 | 
						|
 | 
						|
		//make sure the user's file exists
 | 
						|
		$new_data					= self::SessionData($user_file,$checksum);
 | 
						|
		$new_data['username']		= $username;
 | 
						|
		$new_data['granted']		= $user_info['granted'];
 | 
						|
 | 
						|
		if( isset($user_info['editing']) ){
 | 
						|
			$new_data['editing'] = $user_info['editing'];
 | 
						|
		}
 | 
						|
		\gp\admin\Tools::EditingValue($new_data);
 | 
						|
 | 
						|
		// may needt to extend the cookie life later
 | 
						|
		if( isset($_POST['remember']) ){
 | 
						|
			$new_data['remember'] = time();
 | 
						|
		}else{
 | 
						|
			unset($new_data['remember']);
 | 
						|
		}
 | 
						|
 | 
						|
		\gp\tool\Files::SaveData($user_file, 'gpAdmin', $new_data);
 | 
						|
		return $session_id;
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Return the contents of the session_ids.php data file
 | 
						|
	 * @return array array of all sessions
 | 
						|
	 */
 | 
						|
	public static function GetSessionIds(){
 | 
						|
		return \gp\tool\Files::Get('_site/session_ids', 'sessions');
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Save $sessions to the session_ids.php data file
 | 
						|
	 * @param $sessions array array of all sessions
 | 
						|
	 * @return bool
 | 
						|
	 */
 | 
						|
	public static function SaveSessionIds($sessions){
 | 
						|
 | 
						|
		while( $current = current($sessions) ){
 | 
						|
			$key = key($sessions);
 | 
						|
 | 
						|
			//delete if older than
 | 
						|
			if( isset($current['time']) && $current['time'] > 0 && ($current['time'] < (time() - 1209600)) ){
 | 
						|
			//if( $current['time'] < time() - 2592000 ){ //one month
 | 
						|
				unset($sessions[$key]);
 | 
						|
				$continue = true;
 | 
						|
			}else{
 | 
						|
				next($sessions);
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		//clean
 | 
						|
		return \gp\tool\Files::SaveData('_site/session_ids', 'sessions', $sessions);
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Determine if $session_id represents a valid session and if so start the session
 | 
						|
	 *
 | 
						|
	 */
 | 
						|
	public function Start($session_id, $sessions = false ){
 | 
						|
		global $langmessage, $dataDir;
 | 
						|
 | 
						|
		//get the session file
 | 
						|
		if( !$sessions ){
 | 
						|
			$sessions = self::GetSessionIds();
 | 
						|
			if( !isset($sessions[$session_id]) ){
 | 
						|
				self::cookie(gp_session_cookie); //make sure the cookie is deleted
 | 
						|
				msg($langmessage['Session Expired'] . ' (timeout)');
 | 
						|
				return false;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		$sess_info = $sessions[$session_id];
 | 
						|
 | 
						|
		//check ~ip, ~user agent ...
 | 
						|
		if( gp_browser_auth && !empty($sess_info['uid']) ){
 | 
						|
 | 
						|
			$auth_uid			= self::auth_browseruid();
 | 
						|
 | 
						|
			if( $sess_info['uid'] != $auth_uid ){
 | 
						|
				self::cookie(gp_session_cookie); //make sure the cookie is deleted
 | 
						|
				msg($langmessage['Session Expired'] . ' (browser auth)');
 | 
						|
				return false;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		$session_file = $dataDir . '/data/_sessions/' . $sess_info['file_name'];
 | 
						|
		if( ($session_file === false) || !\gp\tool\Files::Exists($session_file) ){
 | 
						|
			self::cookie(gp_session_cookie); //make sure the cookie is deleted
 | 
						|
			msg($langmessage['Session Expired'] . ' (invalid)');
 | 
						|
			return false;
 | 
						|
		}
 | 
						|
 | 
						|
		$this->session_id		= $session_id;
 | 
						|
		$this->session_file		= $session_file;
 | 
						|
		$this->logged_in		= true;
 | 
						|
 | 
						|
		return true;
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
	public function Prepare(){
 | 
						|
		global $langmessage, $wbMessageBuffer;
 | 
						|
		static $locked_message = false;
 | 
						|
 | 
						|
		//prevent browser caching when editing
 | 
						|
		Header( 'Last-Modified: ' . gmdate( 'D, j M Y H:i:s' ) . ' GMT' );
 | 
						|
		Header( 'Expires: ' . gmdate( 'D, j M Y H:i:s', time() ) . ' GMT' );
 | 
						|
		Header( 'Cache-Control: no-store, no-cache, must-revalidate'); // HTTP/1.1
 | 
						|
		Header( 'Cache-Control: post-check=0, pre-check=0', false );
 | 
						|
		Header( 'Pragma: no-cache' ); // HTTP/1.0
 | 
						|
 | 
						|
		$GLOBALS['gpAdmin'] = self::SessionData($this->session_file,$checksum);
 | 
						|
 | 
						|
		//lock to prevent conflicting edits
 | 
						|
		if( gp_lock_time > 0 &&
 | 
						|
			( !empty($GLOBALS['gpAdmin']['editing']) || !empty($GLOBALS['gpAdmin']['granted']) )
 | 
						|
			){
 | 
						|
			$expires = gp_lock_time;
 | 
						|
			if( !\gp\tool\Files::Lock('admin', sha1(sha1($this->session_id)), $expires) ){
 | 
						|
				msg($langmessage['site_locked'] . ' ' . sprintf($langmessage['lock_expires_in'], ceil($expires / 60)));
 | 
						|
				$locked_message = true;
 | 
						|
				$GLOBALS['gpAdmin']['locked'] = true;
 | 
						|
			}else{
 | 
						|
				unset($GLOBALS['gpAdmin']['locked']);
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		//extend cookie?
 | 
						|
		if( isset($GLOBALS['gpAdmin']['remember']) ){
 | 
						|
			$elapsed = time() - $GLOBALS['gpAdmin']['remember'];
 | 
						|
			if( $elapsed > 604800 ){ //7 days
 | 
						|
				$GLOBALS['gpAdmin']['remember'] = time();
 | 
						|
				self::cookie(gp_session_cookie, $this->session_id);
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		register_shutdown_function(array('\\gp\\tool\\Session', 'close'), $this->session_file, $checksum);
 | 
						|
 | 
						|
		//make sure forms have admin nonce
 | 
						|
		ob_start(array('\\gp\\tool\\Session', 'AdminBuffer'));
 | 
						|
 | 
						|
		\gp\tool\Output::$lang_values += array(
 | 
						|
			'cancel'					=>	'ca',
 | 
						|
			'update'					=>	'up',
 | 
						|
			'caption'					=>	'cp',
 | 
						|
			'Width'						=>	'Width',
 | 
						|
			'Height'					=>	'Height',
 | 
						|
			'save'						=>	'Save',
 | 
						|
			'Saved'						=>	'Saved',
 | 
						|
			'Saving'					=>	'Saving',
 | 
						|
			'Close'						=>	'Close',
 | 
						|
			'Page'						=>	'Page',
 | 
						|
			'theme_content'				=>	'Extra',
 | 
						|
			'Publish Draft'				=>	'PublishDraft',
 | 
						|
			'Publish'					=>	'Publish',
 | 
						|
			'Dismiss'					=>	'Dismiss',
 | 
						|
			'Dismiss Draft'				=>	'DismissDraft',
 | 
						|
			'Select Image'				=>	'SelectImage',
 | 
						|
			'edit'						=>	'edit',
 | 
						|
			'Expand Editor'				=>	'ExpandEditor',
 | 
						|
			'Shrink Editor'				=>	'ShrinkEditor',
 | 
						|
			'Hide Admin UI'				=>	'HideAdminUI',
 | 
						|
			'Show Admin UI'				=>	'ShowAdminUI',
 | 
						|
			'options'					=>	'options',
 | 
						|
			'Copy'						=>	'Copy',
 | 
						|
			'Copy to Clipboard'			=>	'CopyToClipboard',
 | 
						|
			'Manage Sections'			=>	'ManageSections',
 | 
						|
			'Sections'					=>	'Sections',
 | 
						|
			'Section Attributes'		=>	'SectionAttributes',
 | 
						|
			'Available Classes'			=>	'AvailableClasses',
 | 
						|
			'Attribute'					=>	'Attribute',
 | 
						|
			'Add Attribute'				=>	'AddAttribute',
 | 
						|
			'Value'						=>	'Value',
 | 
						|
			'Visibility'				=>	'Visibility',
 | 
						|
			'remove'					=>	'remove',
 | 
						|
			'delete'					=>	'del',
 | 
						|
			'Move Behind'				=>	'MoveBehind',
 | 
						|
			'Section %s'				=>	'Section',
 | 
						|
			'generic_delete_confirm'	=>	'generic_delete_confirm',
 | 
						|
			'Ctrl Key'					=>	'ctrlKey',
 | 
						|
			'Shift Key'					=>	'shiftKey',
 | 
						|
			'Alt Key'					=>	'altKey',
 | 
						|
		);
 | 
						|
 | 
						|
 | 
						|
		\gp\tool::LoadComponents('sortable, autocomplete, gp-admin, gp-admin-css, fontawesome, popper');
 | 
						|
		\gp\admin\Tools::VersionsAndCheckTime();
 | 
						|
 | 
						|
 | 
						|
		\gp\tool\Output::$inline_vars += array(
 | 
						|
			'gpRem' => \gp\admin\Tools::CanRemoteInstall(),
 | 
						|
		);
 | 
						|
 | 
						|
 | 
						|
		//prepend messages from message buffer
 | 
						|
		if( isset($GLOBALS['gpAdmin']['message_buffer']) && count($GLOBALS['gpAdmin']['message_buffer']) ){
 | 
						|
			$wbMessageBuffer = array_merge($GLOBALS['gpAdmin']['message_buffer'], $wbMessageBuffer);
 | 
						|
			unset($GLOBALS['gpAdmin']['message_buffer']);
 | 
						|
		}
 | 
						|
 | 
						|
		//alias
 | 
						|
		if( isset($_COOKIE['gp_alias']) ){
 | 
						|
			$GLOBALS['gpAdmin']['useralias'] = $_COOKIE['gp_alias'];
 | 
						|
		}else{
 | 
						|
			$GLOBALS['gpAdmin']['useralias'] = $GLOBALS['gpAdmin']['username'];
 | 
						|
		}
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Perform admin only changes to the content buffer
 | 
						|
	 * This will happen before \gp\tool\Output::BufferOut()
 | 
						|
	 *
 | 
						|
	 */
 | 
						|
	public static function AdminBuffer($buffer){
 | 
						|
		global $wbErrorBuffer, $gp_admin_html;
 | 
						|
 | 
						|
		//add $gp_admin_html to the document
 | 
						|
		if( strpos($buffer, '<!-- get_head_placeholder ' . gp_random . ' -->') !== false ){
 | 
						|
			$buffer = \gp\tool\Output::AddToBody(
 | 
						|
				$buffer,
 | 
						|
				'<div id="gp_admin_html">'
 | 
						|
					. $gp_admin_html . \gp\tool\Output::$editlinks
 | 
						|
					. '</div><div id="gp_admin_fixed"></div>'
 | 
						|
			);
 | 
						|
		}
 | 
						|
 | 
						|
		// Add a generic admin nonce field to each post form
 | 
						|
		// Admin nonces are also added with javascript if needed
 | 
						|
		$count = preg_match_all('#<form[^<>]*method=[\'"]post[\'"][^<>]*>#i', $buffer, $matches);
 | 
						|
		if( $count ){
 | 
						|
			$nonce = \gp\tool\Nonce::Create('post',true);
 | 
						|
			$matches[0] = array_unique($matches[0]);
 | 
						|
			foreach($matches[0] as $match){
 | 
						|
 | 
						|
				//make sure it's a local action
 | 
						|
				if( preg_match('#action=[\'"]([^\'"]+)[\'"]#i', $match, $sub_matches) ){
 | 
						|
					$action = $sub_matches[1];
 | 
						|
					if( substr($action, 0, 2) === '//' ){
 | 
						|
						continue;
 | 
						|
					}elseif( strpos($action, '://') ){
 | 
						|
						continue;
 | 
						|
					}
 | 
						|
				}
 | 
						|
				$replacement = '<input type="hidden" name="verified" value="' . $nonce . '"/>';
 | 
						|
				$pos	= strpos($buffer,$match)+strlen($match);
 | 
						|
				$buffer	= substr_replace($buffer, $replacement, $pos, 0);
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		return $buffer;
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Get the session data from a user session file
 | 
						|
	 * @param string $session_file The full path to the user's session file
 | 
						|
	 * @param string $checksum
 | 
						|
	 * @return array The user's session data
 | 
						|
	 */
 | 
						|
	public static function SessionData($session_file, &$checksum){
 | 
						|
 | 
						|
		$gpAdmin	= \gp\tool\Files::Get($session_file, 'gpAdmin');
 | 
						|
 | 
						|
		$checksum	= '';
 | 
						|
 | 
						|
		if( isset($gpAdmin['checksum']) ){
 | 
						|
			$checksum = $gpAdmin['checksum'];
 | 
						|
		}
 | 
						|
 | 
						|
		return $gpAdmin + self::gpui_defaults();
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	public static function gpui_defaults(){
 | 
						|
		return array(
 | 
						|
			'gpui_cmpct'	=> 0,
 | 
						|
			'gpui_tx'		=> 10,
 | 
						|
			'gpui_ty'		=> 39,
 | 
						|
			'gpui_ckx'		=> 20,
 | 
						|
			'gpui_cky'		=> 240,
 | 
						|
			'gpui_exp'		=> 1,
 | 
						|
			'gpui_vis'		=> 'cur',
 | 
						|
			'gpui_thw'		=> 250,
 | 
						|
		);
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Prevent XSS attacks for logged in users by
 | 
						|
	 * making sure the request contains a valid nonce
 | 
						|
	 *
 | 
						|
	 */
 | 
						|
	public static function CheckPosts(){
 | 
						|
 | 
						|
		if( count($_POST) == 0 ){
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		if( empty($_POST['verified']) ){
 | 
						|
			self::StripPost('XSS Verification Parameter Error');
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		if( !\gp\tool\Nonce::Verify('post', $_POST['verified'], true) ){
 | 
						|
			self::StripPost('XSS Verification Parameter Mismatch');
 | 
						|
			return;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Unset all $_POST values
 | 
						|
	 *
 | 
						|
	 */
 | 
						|
	public static function StripPost($message){
 | 
						|
		global $langmessage, $post_quarantine;
 | 
						|
		msg($langmessage['OOPS'] . ' (' . $message . ')');
 | 
						|
		$post_quarantine = $_POST;
 | 
						|
		foreach($_POST as $key => $value){
 | 
						|
			unset($_POST[$key]);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Save any changes to the $gpAdmin array
 | 
						|
	 * @param string $file Session file path
 | 
						|
	 * @param string $checksum_read The original checksum of the $gpAdmin array
 | 
						|
	 *
 | 
						|
	 */
 | 
						|
	public static function Close($file, $checksum_read){
 | 
						|
		global $gpAdmin;
 | 
						|
 | 
						|
		self::FatalNotices();
 | 
						|
		self::Cron();
 | 
						|
		self::LayoutInfo();
 | 
						|
 | 
						|
		unset($gpAdmin['checksum']);
 | 
						|
		$checksum = \gp\tool::ArrayHash($gpAdmin);
 | 
						|
 | 
						|
		//nothing changed
 | 
						|
		if( $checksum === $checksum_read ){
 | 
						|
			return;
 | 
						|
		}
 | 
						|
		if( !isset($gpAdmin['username']) ){
 | 
						|
			trigger_error('username not set');
 | 
						|
			die();
 | 
						|
		}
 | 
						|
 | 
						|
		$gpAdmin['checksum'] = $checksum; //store the new checksum
 | 
						|
		\gp\tool\Files::SaveData($file, 'gpAdmin', $gpAdmin);
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Update layout information if needed
 | 
						|
	 *
 | 
						|
	 */
 | 
						|
	public static function LayoutInfo(){
 | 
						|
		global $page, $gpLayouts, $get_all_gadgets_called;
 | 
						|
 | 
						|
		if( !\gp\tool\Output::$template_included ){
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		$layout = $page->gpLayout;
 | 
						|
		if( !isset($gpLayouts[$layout]) ){
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		$layout_info =& $gpLayouts[$layout];
 | 
						|
 | 
						|
		//template.php file not modified
 | 
						|
		$template_file = realpath($page->theme_dir . '/template.php');
 | 
						|
		$template_mod = filemtime($template_file);
 | 
						|
		if( isset($layout_info['template_mod']) && $layout_info['template_mod'] >= $template_mod ){
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		$contents = ob_get_contents();
 | 
						|
 | 
						|
		//charset
 | 
						|
		if( strpos($contents, 'charset=') === false ){
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		//get just the head of the buffer to see if we need to add charset
 | 
						|
		$pos = strpos($contents, '</head');
 | 
						|
		unset($layout_info['doctype']);
 | 
						|
		if( $pos > 0 ){
 | 
						|
			$head = substr($contents, 0, $pos);
 | 
						|
			$layout_info['doctype'] = self::DoctypeMeta($head);
 | 
						|
		}
 | 
						|
		$layout_info['all_gadgets'] = $get_all_gadgets_called;
 | 
						|
 | 
						|
		//save
 | 
						|
		$layout_info['template_mod'] = $template_mod;
 | 
						|
		\gp\admin\Tools::SavePagesPHP();
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Determine if CMS needs to add a <meta charset> tag
 | 
						|
	 * Look at the beginning of the document to see what kind of doctype the current template is using
 | 
						|
	 * See http://www.w3schools.com/tags/tag_doctype.asp for description of different doctypes
 | 
						|
	 *
 | 
						|
	 */
 | 
						|
	public static function DoctypeMeta($doc_start){
 | 
						|
 | 
						|
		//charset already set
 | 
						|
		if( stripos($doc_start,'charset=') !== false ){
 | 
						|
			return '';
 | 
						|
		}
 | 
						|
 | 
						|
		// html5
 | 
						|
		// spec states this should be "the first element child of the head element"
 | 
						|
		if( stripos($doc_start, '<!doctype html>') !== false ){
 | 
						|
			return '<meta charset="UTF-8" />';
 | 
						|
		}
 | 
						|
		return '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Perform regular tasks
 | 
						|
	 * Once an hour only when admin is logged in
 | 
						|
	 *
 | 
						|
	 */
 | 
						|
	public static function Cron(){
 | 
						|
		$cron_info	= \gp\tool\Files::Get('_site/cron_info');
 | 
						|
		$file_stats	= \gp\tool\Files::$last_stats;
 | 
						|
 | 
						|
		$file_stats += array('modified' => 0);
 | 
						|
		if( (time() - $file_stats['modified']) < 3600 ){
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		self::CleanTemp();
 | 
						|
		\gp\tool\Files::SaveData('_site/cron_info', 'cron_info', $cron_info);
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Clean old files and folders from the temporary folder
 | 
						|
	 * Delete after 36 hours (129600 seconds)
 | 
						|
	 *
 | 
						|
	 */
 | 
						|
	public static function CleanTemp(){
 | 
						|
		global $dataDir;
 | 
						|
		$temp_folder = $dataDir . '/data/_temp';
 | 
						|
		$files = \gp\tool\Files::ReadDir($temp_folder, false);
 | 
						|
		foreach($files as $file){
 | 
						|
			if( $file == 'index.html'){
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
			$full_path = $temp_folder . '/' . $file;
 | 
						|
			$mtime = (int)filemtime($full_path);
 | 
						|
			$diff = time() - $mtime;
 | 
						|
			if( $diff < 129600 ){
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
			\gp\tool\Files::RmAll($full_path);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Output the UI variables as a Javascript Object
 | 
						|
	 *
 | 
						|
	 */
 | 
						|
	public static function GPUIVars(){
 | 
						|
		global $gpAdmin, $page, $config;
 | 
						|
 | 
						|
		$defaults	= self::gpui_defaults();
 | 
						|
		$js			= array();
 | 
						|
 | 
						|
		foreach($defaults as $key => $value){
 | 
						|
			if( isset($gpAdmin[$key]) ){
 | 
						|
				$value = $gpAdmin[$key];
 | 
						|
			}
 | 
						|
			$renamed_key		= substr($key, 5);
 | 
						|
			$js[$renamed_key]	= $value;
 | 
						|
		}
 | 
						|
 | 
						|
		//default layout (admin layout)
 | 
						|
		if( $page->gpLayout && $page->gpLayout == $config['gpLayout'] ){
 | 
						|
			$js['dlayout'] = true;
 | 
						|
		}else{
 | 
						|
			$js['dlayout'] = false;
 | 
						|
		}
 | 
						|
 | 
						|
		echo 'var gpui=' . json_encode($js) . ';';
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Code modified from dokuwiki
 | 
						|
	 * /dokuwiki/inc/auth.php
 | 
						|
	 *
 | 
						|
	 * Builds a pseudo UID from browser and IP data
 | 
						|
	 *
 | 
						|
	 * This is neither unique nor unfakable - still it adds some
 | 
						|
	 * security. Using the first part of the IP makes sure
 | 
						|
	 * proxy farms like AOLs are stil okay.
 | 
						|
	 *
 | 
						|
	 * @author  Andreas Gohr <andi@splitbrain.org>
 | 
						|
	 *
 | 
						|
	 * @return  string  a MD5 sum of various browser headers
 | 
						|
	 */
 | 
						|
	public static function auth_browseruid(){
 | 
						|
 | 
						|
		$uid = '';
 | 
						|
		if( isset($_SERVER['HTTP_USER_AGENT']) ){
 | 
						|
			$uid .= $_SERVER['HTTP_USER_AGENT'];
 | 
						|
		}
 | 
						|
		if( isset($_SERVER['HTTP_ACCEPT_ENCODING']) ){
 | 
						|
			$uid .= $_SERVER['HTTP_ACCEPT_ENCODING'];
 | 
						|
		}
 | 
						|
 | 
						|
		if( isset($_SERVER['HTTP_ACCEPT_CHARSET']) ){
 | 
						|
			$uid .= $_SERVER['HTTP_ACCEPT_CHARSET'];
 | 
						|
		}
 | 
						|
 | 
						|
		$ip = self::clientIP();
 | 
						|
		$uid .= substr($ip, 0, strpos($ip, '.'));
 | 
						|
 | 
						|
		//ie8 will report ACCEPT_LANGUAGE as en-us and en-US depending on the type of request (normal, ajax)
 | 
						|
		$uid = strtolower($uid);
 | 
						|
 | 
						|
		return md5($uid);
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Return the IP of the client
 | 
						|
	 * Modified from ClientIP method in Dokuwiki
 | 
						|
	 *
 | 
						|
	 * Honours X-Forwarded-For and X-Real-IP Proxy Headers
 | 
						|
	 *
 | 
						|
	 * Tries to return a routable public address, prefering the ones suplied in the X headers
 | 
						|
	 *
 | 
						|
	 */
 | 
						|
	public static function ClientIP(){
 | 
						|
		$ips = [];
 | 
						|
 | 
						|
		$add_ip = function($ips, $ip_key){
 | 
						|
 | 
						|
			if( !isset($_SERVER[$ip_key]) ){
 | 
						|
				return $ips;
 | 
						|
			}
 | 
						|
 | 
						|
			// some IPv4/v6 regexps borrowed from Feyd
 | 
						|
			// see: http://forums.devnetwork.net/viewtopic.php?f=38&t=53479
 | 
						|
			$dec_octet = '(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|[0-9])';
 | 
						|
			$hex_digit = '[A-Fa-f0-9]';
 | 
						|
			$h16 = "{$hex_digit}{1,4}";
 | 
						|
			$IPv4Address = "$dec_octet\\.$dec_octet\\.$dec_octet\\.$dec_octet";
 | 
						|
			$ls32 = "(?:$h16:$h16|$IPv4Address)";
 | 
						|
			$IPv6Address =
 | 
						|
				"(?:(?:{$IPv4Address})|(?:".
 | 
						|
				"(?:$h16:){6}$ls32" .
 | 
						|
				"|::(?:$h16:){5}$ls32" .
 | 
						|
				"|(?:$h16)?::(?:$h16:){4}$ls32" .
 | 
						|
				"|(?:(?:$h16:){0,1}$h16)?::(?:$h16:){3}$ls32" .
 | 
						|
				"|(?:(?:$h16:){0,2}$h16)?::(?:$h16:){2}$ls32" .
 | 
						|
				"|(?:(?:$h16:){0,3}$h16)?::(?:$h16:){1}$ls32" .
 | 
						|
				"|(?:(?:$h16:){0,4}$h16)?::$ls32" .
 | 
						|
				"|(?:(?:$h16:){0,5}$h16)?::$h16" .
 | 
						|
				"|(?:(?:$h16:){0,6}$h16)?::" .
 | 
						|
				")(?:\\/(?:12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))?)";
 | 
						|
 | 
						|
			$new_ips = explode(',',str_replace(' ','',$_SERVER[$ip_key]));
 | 
						|
 | 
						|
			// remove any non-IP stuff
 | 
						|
			foreach($new_ips as $ip){
 | 
						|
				if( preg_match("/^$IPv4Address$/",$ip,$match) || preg_match("/^$IPv6Address$/",$ip,$match)) {
 | 
						|
					$ips[] = $match[0];
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			return $ips;
 | 
						|
		};
 | 
						|
 | 
						|
		$ips = $add_ip($ips,'REMOTE_ADDR');
 | 
						|
		$ips = $add_ip($ips,'HTTP_X_FORWARDED_FOR');
 | 
						|
		$ips = $add_ip($ips,'HTTP_X_REAL_IP');
 | 
						|
		$ips = array_values(array_unique($ips));
 | 
						|
 | 
						|
		// for some strange reason we don't have a IP
 | 
						|
		if( empty($ips) ){
 | 
						|
			return '0.0.0.0';
 | 
						|
		}
 | 
						|
 | 
						|
		// decide which IP to use, trying to avoid local addresses
 | 
						|
		$ips = array_reverse($ips);
 | 
						|
		foreach($ips as $ip){
 | 
						|
			if( !preg_match('/^(::1|[fF][eE]80:|127\.|10\.|192\.168\.|172\.((1[6-9])|(2[0-9])|(3[0-1]))\.)/',$ip) ){
 | 
						|
				return $ip;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// use the first (last) address
 | 
						|
		return end($ips);
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Re-enable components that were disabled because of fatal errors
 | 
						|
	 *
 | 
						|
	 */
 | 
						|
	public static function ClearErrors(){
 | 
						|
		\gp\admin\Tools\Errors::ClearAll();
 | 
						|
		$title = \gp\tool::WhichPage();
 | 
						|
		\gp\tool::Redirect(\gp\tool::GetUrl($title, '', false));
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Notify the admin if there have been any fatal errors
 | 
						|
	 *
 | 
						|
	 */
 | 
						|
	public static function FatalNotices(){
 | 
						|
		global $dataDir, $page;
 | 
						|
 | 
						|
		if( !\gp\admin\Tools::HasPermission('Admin_Errors') ){
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		if( is_object($page)
 | 
						|
			&& property_exists($page, 'requested')
 | 
						|
			&& strpos($page->requested, 'Admin/Errors') !== false
 | 
						|
			){
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		$dir		= $dataDir . '/data/_site';
 | 
						|
		$files		= scandir($dir);
 | 
						|
		$has_fatal	= false;
 | 
						|
 | 
						|
		foreach($files as $file){
 | 
						|
			if( strpos($file, 'fatal_') === false ){
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
			$has_fatal = true;
 | 
						|
		}
 | 
						|
 | 
						|
		if( !$has_fatal ){
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		$msg = 'Warning: One or more components have caused fatal errors. <br/>';
 | 
						|
		$msg .= \gp\tool::Link(
 | 
						|
			'Admin/Errors',
 | 
						|
			'More Information',
 | 
						|
			'',
 | 
						|
			'style="white-space:nowrap"'
 | 
						|
		);
 | 
						|
 | 
						|
		$msg .= '   ';
 | 
						|
 | 
						|
		$msg .= \gp\tool::Link(
 | 
						|
			(isset($page) ? $page->requested : 'Admin'),
 | 
						|
			'Clear All Errors',
 | 
						|
			'cmd=ClearErrors',
 | 
						|
			'', //cannot be creq
 | 
						|
			'ClearErrors'
 | 
						|
		);
 | 
						|
 | 
						|
		msg($msg);
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	public static function SessionCookie($uniq){
 | 
						|
		return 'gpEasy_'.substr(sha1($uniq),12,12);
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
}
 |