<commit_before><?php
/** @package    verysimple::Phreeze */

/** import supporting libraries */
require_once("verysimple/HTTP/RequestUtil.php");
require_once("verysimple/HTTP/Context.php");
require_once("Phreezer.php");
require_once("Criteria.php");
require_once("IRouter.php");
require_once("GenericRouter.php");
require_once("verysimple/Authentication/IAuthenticatable.php");

/**
 * Controller is a base controller object used for an MVC pattern
 * This controller uses Phreeze ORM and RenderEngine Template Engine
 * This controller could be extended to use a differente ORM and
 * Rendering engine as long as they implement compatible functions.
 *
 * @package    verysimple::Phreeze
 * @author     VerySimple Inc.
 * @copyright  1997-2011 VerySimple, Inc.
 * @license    http://www.gnu.org/licenses/lgpl.html  LGPL
 * @version    3.1
 */
abstract class Controller
{
	protected $Phreezer;
	protected $RenderEngine;

	/**
	 * @var string ModelName is used by the base Controller class for certain functions in which
	 * require knowledge of what Model is being used.  For example, when validating user input.
	 * This may be defined in Init() if any of thes base Controller features will be used.
	 */
	protected $ModelName;

	protected $Context;

	/** @deprecated use RenderEngine */
	protected $Smarty;

	private $_router;
	private $_cu;
	public $GUID;
	public $DebugOutput = "";
	public $UnitTestMode = false;
	public $CaptureOutputMode = false;
	
	private $_terminate = false;

	/** Prefix this to the name of the view templates */
	static $SmartyViewPrefix = "View";

	/** the default mode used when calling 'Redirect' */
	static $DefaultRedirectMode = "client";

	/**
	 * Constructor initializes the controller.  This method cannot be overriden.  If you need
	 * to do something during construction, add it to Init
	 *
	 * @param Phreezer $phreezer Object persistance engine
	 * @param IRenderEngine $renderEngine rendering engine
	 * @param Context (optional) a context object for persisting the state of the current page
	 * @param Router (optional) a custom writer for URL formatting
	 */
	final function __construct(Phreezer &$phreezer, &$renderEngine, &$context = null, IRouter &$router = null)
	{
		$this->Phreezer =& $phreezer;
		$this->RenderEngine =& $renderEngine;

		// for backwards compatibility
		$this->Smarty =& $renderEngine;

		$ra = RequestUtil::GetRemoteHost();
		$this->GUID = $this->Phreezer->DataAdapter->GetDBName() . "_" . str_replace(".","_", $ra);

		$this->_router = $router ? $router : new GenericRouter();

		if ($context)
		{
			$this->Context =& $context;
		}
		else
		{
			$this->Context = new Context();
			$this->Context->GUID = "CTX_" . $this->GUID;
		}

		if ($this->RenderEngine)
		{
			// assign some variables globally for the views
			$this->Assign("CURRENT_USER",$this->GetCurrentUser());
			$this->Assign("URL",$this->GetRouter());
			$this->Assign("BROWSER_DEVICE",$this->GetDevice());
	
			// if feedback was persisted, set it
			$this->Assign("feedback",$this->Context->Get("feedback"));
			$this->Context->Set("feedback",null);
		}

		$this->Init();
	}
	
	/**
	 * Calling Terminate in Init will tell the dispatcher to halt execution
	 * without calling the requested method/route
	 */
	protected function Terminate()
	{
		$this->_terminate = true;
	}
	
	/**
	 * Returns true if Terminate() has been fired
	 * @return bool
	 */
	public function IsTerminated()
	{
		return $this->_terminate;
	}

	/**
	 * Returns the router object used to convert url/uri to controller method
	 * @return IRouter
	 */
	protected function GetRouter()
	{
		return $this->_router;
	}

	/**
	 * Init is called by the base constructor immediately after construction.
	 * This method must be implemented and provided an oportunity to
	 * set any class-wide variables such as ModelName, implement
	 * authentication for this Controller or any other class-wide initialization
	 */
	abstract protected function Init();

	/**
	 * Requires 401 Authentication.  If authentication fails, this function
	 * terminates with a 401 header.  If success, sets CurrentUser and returns null.
	 * @param IAuthenticatable any IAuthenticatable object
	 * @param string http realm (basically the login message shown to the user)
	 * @param string username querystring field (optional) if provided, the username can be passed via querystring instead of through the auth headers
	 * @param string password querystring field (optional) if provided, the password can be passed via querystring instead of through the auth headers
	 */
	protected function Require401Authentication(IAuthenticatable $authenticatable, $realm = "Login Required", $qs_username_field = "", $qs_password_field = "")
	{
		require_once("verysimple/Authentication/Auth401.php");
		
		$user = $this->Get401Authentication($authenticatable,$qs_username_field, $qs_password_field);

		// we only want to output 401 headers if the user is not already authenticated
		if (!$user)
		{
			if( $this->Get401AuthUsername($qs_username_field) )
			{
				// a username was provided, which means login failed
				Auth401::OutputHeaders("Invalid Login");
			}
			else
			{
				// no username provided, which means prompt for username
				Auth401::OutputHeaders($realm);
			}
		}
	}
	
	/**
	 * Start observing messages from Phreeze.  If no observer is provided, then
	 * an ObserveToBrowser will be used and debug messages will be output to the browser
	 * @param IObserver $observer
	 * @param bool $with_styles if true then basic styles will be output to the browser
	 */
	protected function StartObserving($observer = null, $with_styles = true)
	{
		if ($observer == null)
		{
			require_once "ObserveToBrowser.php";
			$observer = new ObserveToBrowser();
		}
		
		if ($with_styles)
		{
			$this->PrintOut("<style>.debug, .query, .info {font-family: courier new; border-bottom: solid 1px #999;} .debug {color: blue;} .query {color: green;}</style>");
		}
		
		$this->Phreezer->AttachObserver($observer);
	}

	/**
	 * accept username passed in either headers or querystring.  if a querystring parameter name is
	 * provided, that will be checked first before the 401 auth headers
	 * @param string $qs_username_field the querystring parameter to check for username (optional)
	 */<commit_msg>added controller methods for CSRF protection<commit_after><?php
/** @package    verysimple::Phreeze */

/** import supporting libraries */
require_once("verysimple/HTTP/RequestUtil.php");
require_once("verysimple/HTTP/Context.php");
require_once("Phreezer.php");
require_once("Criteria.php");
require_once("IRouter.php");
require_once("GenericRouter.php");
require_once("verysimple/Authentication/IAuthenticatable.php");

/**
 * Controller is a base controller object used for an MVC pattern
 * This controller uses Phreeze ORM and RenderEngine Template Engine
 * This controller could be extended to use a differente ORM and
 * Rendering engine as long as they implement compatible functions.
 *
 * @package    verysimple::Phreeze
 * @author     VerySimple Inc.
 * @copyright  1997-2011 VerySimple, Inc.
 * @license    http://www.gnu.org/licenses/lgpl.html  LGPL
 * @version    3.1
 */
abstract class Controller
{
	protected $Phreezer;
	protected $RenderEngine;

	/**
	 * @var string ModelName is used by the base Controller class for certain functions in which
	 * require knowledge of what Model is being used.  For example, when validating user input.
	 * This may be defined in Init() if any of thes base Controller features will be used.
	 */
	protected $ModelName;

	protected $Context;

	/** @deprecated use RenderEngine */
	protected $Smarty;

	private $_router;
	private $_cu;
	public $GUID;
	public $DebugOutput = "";
	public $UnitTestMode = false;
	public $CaptureOutputMode = false;
	
	private $_terminate = false;

	/** Prefix this to the name of the view templates */
	static $SmartyViewPrefix = "View";

	/** the default mode used when calling 'Redirect' */
	static $DefaultRedirectMode = "client";

	/**
	 * Constructor initializes the controller.  This method cannot be overriden.  If you need
	 * to do something during construction, add it to Init
	 *
	 * @param Phreezer $phreezer Object persistance engine
	 * @param IRenderEngine $renderEngine rendering engine
	 * @param Context (optional) a context object for persisting the state of the current page
	 * @param Router (optional) a custom writer for URL formatting
	 */
	final function __construct(Phreezer &$phreezer, &$renderEngine, &$context = null, IRouter &$router = null)
	{
		$this->Phreezer =& $phreezer;
		$this->RenderEngine =& $renderEngine;

		// for backwards compatibility
		$this->Smarty =& $renderEngine;

		$ra = RequestUtil::GetRemoteHost();
		$this->GUID = $this->Phreezer->DataAdapter->GetDBName() . "_" . str_replace(".","_", $ra);

		$this->_router = $router ? $router : new GenericRouter();

		if ($context)
		{
			$this->Context =& $context;
		}
		else
		{
			$this->Context = new Context();
			$this->Context->GUID = "CTX_" . $this->GUID;
		}

		if ($this->RenderEngine)
		{
			// assign some variables globally for the views
			$this->Assign("CURRENT_USER",$this->GetCurrentUser());
			$this->Assign("URL",$this->GetRouter());
			$this->Assign("BROWSER_DEVICE",$this->GetDevice());
	
			// if feedback was persisted, set it
			$this->Assign("feedback",$this->Context->Get("feedback"));
			$this->Context->Set("feedback",null);
		}

		$this->Init();
	}
	
	/**
	 * Calling Terminate in Init will tell the dispatcher to halt execution
	 * without calling the requested method/route
	 */
	protected function Terminate()
	{
		$this->_terminate = true;
	}
	
	/**
	 * Returns true if Terminate() has been fired
	 * @return bool
	 */
	public function IsTerminated()
	{
		return $this->_terminate;
	}

	/**
	 * Returns the router object used to convert url/uri to controller method
	 * @return IRouter
	 */
	protected function GetRouter()
	{
		return $this->_router;
	}

	/**
	 * Init is called by the base constructor immediately after construction.
	 * This method must be implemented and provided an oportunity to
	 * set any class-wide variables such as ModelName, implement
	 * authentication for this Controller or any other class-wide initialization
	 */
	abstract protected function Init();

	/**
	 * Requires 401 Authentication.  If authentication fails, this function
	 * terminates with a 401 header.  If success, sets CurrentUser and returns null.
	 * @param IAuthenticatable any IAuthenticatable object
	 * @param string http realm (basically the login message shown to the user)
	 * @param string username querystring field (optional) if provided, the username can be passed via querystring instead of through the auth headers
	 * @param string password querystring field (optional) if provided, the password can be passed via querystring instead of through the auth headers
	 */
	protected function Require401Authentication(IAuthenticatable $authenticatable, $realm = "Login Required", $qs_username_field = "", $qs_password_field = "")
	{
		require_once("verysimple/Authentication/Auth401.php");
		
		$user = $this->Get401Authentication($authenticatable,$qs_username_field, $qs_password_field);

		// we only want to output 401 headers if the user is not already authenticated
		if (!$user)
		{
			if( $this->Get401AuthUsername($qs_username_field) )
			{
				// a username was provided, which means login failed
				Auth401::OutputHeaders("Invalid Login");
			}
			else
			{
				// no username provided, which means prompt for username
				Auth401::OutputHeaders($realm);
			}
		}
	}
	
	/**
	 * Assign the current CSRFToken to the view layer
	 * @param string $varname the view varname to use for assignment
	 */
	protected function AssignCSRFToken($varname = 'CSRFToken')
	{
		$this->Assign($varname, $this->GetCSRFToken());
	}
	
	/**
	 * Returns a stored CSRF Token from the session.  If no token exists, then generate
	 * one and save it to the session.
	 *
	 * @return string
	 */
	protected function GetCSRFToken()
	{
		$token = $this->Context->Get('X-CSRFToken');
	
		if (!$token)
		{
			$token = md5(rand(1111111111,9999999999).microtime());
			$this->Context->Set('X-CSRFToken',$token);
		}
	
		return $token;
	}
	
	/**
	 * Verify that X-CSRFToken was sent in the request headers and matches the session token
	 * If not an Exception with be thrown.  If no exception is thrown then the token
	 * is verified.
	 * @param string the name of the header variable that contains the token
	 * @throws Exception if token is not provided or does not match
	 */
	protected function VerifyCSRFToken($headerName = 'X-CSRFToken')
	{
		// check that a CSRF token is present in the request
		$headers = RequestUtil::GetHeaders();
	
		if (array_key_exists($headerName, $headers))
		{
			if ($this->GetCSRFToken() != $headers[$headerName])
			{
				throw new Exception('Invalid CSRFToken');
			}
		}
		else
		{
			throw new Exception('Missing CSRFToken');
		}
	}
	
	/**
	 * Start observing messages from Phreeze.  If no observer is provided, then
	 * an ObserveToBrowser will be used and debug messages will be output to the browser
	 * @param IObserver $observer
	 * @param bool $with_styles if true then basic styles will be output to the browser
	 */
	protected function StartObserving($observer = null, $with_styles = true)
	{
		if ($observer == null)
		{
			require_once "ObserveToBrowser.php";
			$observer = new ObserveToBrowser();
		}
		
		if ($with_styles)
		{
			$this->PrintOut("<style>.debug, .query, .info {font-family: courier new; border-bottom: solid 1px #999;} .debug {color: blue;} .query {color: green;}</style>");
		}
		
		$this->Phreezer->AttachObserver($observer);
	}

	/**
	 * accept username passed in either headers or querystring.  if a querystring parameter name is
	 * provided, that will be checked first before the 401 auth headers
	 * @param string $qs_username_field the querystring parameter to check for username (optional)
	 */
{'fraction_non_alphanumeric': 0.11084770114942528, 'fraction_numerical': 0.007830459770114942, 'mean_word_length': 3.989605734767025, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 82, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7574157', 'n_tokens_mistral': 4382, 'n_tokens_neox': 3875, 'n_words': 1389}