<commit_before><?php
/**
 * @version    	$Id$
 * @category	Koowa
 * @package    	Koowa_Request
 * @copyright  	Copyright (C) 2007 - 2010 <NAME>. All rights reserved.
 * @license    	GNU GPLv3 <http://www.gnu.org/licenses/gpl.html>
 * @link 		http://www.nooku.org
 */

//Instantiate the request singleton
KRequest::instantiate();

/**
 * Request class
 *
 * @author      <NAME> <<EMAIL>>
 * @category    Koowa
 * @package     Koowa_Request
 * @uses        KFilter
 * @uses        KInflector
 * @uses        KFactory
 * @static
 */
class KRequest
{
    /**
     * URL of the request regardless of the server
     *
     * @var KHttpUrl
     */
    protected static $_url = null;

    /**
     * Base path of the request.
     *
     * @var KHttpUrl
     */
    protected static $_base = null;
    
    /**
     * Root path of the request.
     *
     * @var KHttpUrl
     */
    protected static $_root = null;

    /**
     * Referrer of the request
     *
     * @var KHttpUrl
     */
    protected static $_referrer = null;
    
    /**
     * The raw post or put content information
     *
     * @var array
     */
    protected static $_content = null;
    
    /**
     * The request accepts information
     *
     * @var array
     */
    protected static $_accept = null;
    
    
    /**
     * Constructor
     *
     * Prevent creating instances of this class by making the contructor private
     */
    final private function __construct(KConfig $config) 
    {
        $content = self::content();
        
        if(self::type() == 'HTTP')
        {
            $authorization = KRequest::get('server.HTTP_AUTHORIZATION', 'url');
	        if (strstr($authorization,"Basic")) 
	        {
	            $parts = explode(':',base64_decode(substr($authorization, 6)));
			
	            if (count($parts) == 2) 
			    {
				    KRequest::set('server.PHP_AUTH_USER', $parts[0]); 
				    KRequest::set('server.PHP_AUTH_PW'  , $parts[1]); 
			    }
		    }
        }
        
        if(!empty($content['data']))
        {
            if($content['type'] == 'application/x-www-form-urlencoded') 
            {
                if (in_array(self::method(), array('PUT', 'DELETE'))) 
                {
                    parse_str($content['data'], $GLOBALS['_'.self::method()]);
                    $GLOBALS['_REQUEST'] = array_merge($GLOBALS['_REQUEST'],  $GLOBALS['_'.self::method()]); 
                }
            }
            
            if($content['type'] == 'application/json') 
            {
                if(in_array(self::method(), array('POST', 'PUT', 'DELETE'))) 
                {
                    $GLOBALS['_'.self::method()] = json_decode($content['data'], true);
                    $GLOBALS['_REQUEST'] = array_merge($GLOBALS['_REQUEST'],  $GLOBALS['_'.self::method()]); 
                }
            }   
        }
     }
    
    /**
     * Clone 
     *
     * Prevent creating clones of this class
     */
    final private function __clone() { }
    
    /**
     * Force creation of a singleton
     *
     * @return void
     */
    public static function instantiate($config = array())
    {
        static $instance;
        
        if ($instance === NULL) 
        {
            if(!$config instanceof KConfig) {
                $config = new KConfig($config);
            }
            
            $instance = new self($config);
        }
        
        return $instance;
    }


    /**
     * Get sanitized data from the request.
     *
     * @param   string              Variable identifier, prefixed by hash name eg post.foo.bar
     * @param   mixed               Filter(s), can be a KFilter object, a filter name, an array of filter names or a filter identifier
     * @param   mixed               Default value when the variable doesn't exist
     * @throws  KRequestException   When an invalid filter was passed
     * @return  mixed               The sanitized data
     */
    public static function get($identifier, $filter, $default = null)
    {
        list($hash, $keys) = self::_parseIdentifier($identifier);
        
        $result = null;
        if(isset($GLOBALS['_'.$hash]))
        {
            $result = $GLOBALS['_'.$hash];
            foreach($keys as $key)
            {
                if(array_key_exists($key, $result)) {
                    $result = $result[$key];
                } else {
                    $result = null;
                    break;
                }
            }
        }
       
        
        // If the value is null return the default
        if(is_null($result)) {
            return $default;
        }
    
        // Handle magic quotes compatability
        if (get_magic_quotes_gpc() && !in_array($hash, array('FILES', 'SESSION'))) {
            $result = self::_stripSlashes( $result );
        }

        if(!($filter instanceof KFilterInterface)) {
            $filter = KFilter::factory($filter);
        }

        return $filter->sanitize($result);
    }

    /**
     * Set a variable in the request. Cookies and session data are stored persistently.
     *
     * @param   mixed   Variable identifier, prefixed by hash name eg post.foo.bar
     * @param   mixed   Variable value
     */
    public static function set($identifier, $value)
    {
        list($hash, $keys) = self::_parseIdentifier($identifier);

        // Add to _REQUEST hash if original hash is get, post, or cookies 
        if(in_array($hash, array('GET', 'POST', 'COOKIE'))) {
            self::set('request.'.implode('.', $keys), $value);
        }

        // Store cookies persistently
        if($hash == 'COOKIE')
        {
            // rewrite the $keys as foo[bar][bar]
            $ckeys = $keys; // get a copy
            $name = array_shift($ckeys);
            foreach($ckeys as $ckey) {
                $name .= '['.$ckey.']';
            }

            if(!setcookie($name, $value)) {
                throw new KRequestException("Couldn't set cookie, headers already sent.");
            }
        }
        
        // Store in $GLOBALS
        foreach(array_reverse($keys, true) as $key) {
            $value = array($key => $value);
        }
        
        $GLOBALS['_'.$hash] = KHelperArray::merge($GLOBALS['_'.$hash], $value);
    }

    /**
     * Check if a variable exists based on an identifier
     *
     * @param   string  Variable identifier, prefixed by hash name eg post.foo.bar
     * @return  boolean
     */
    public static function has($identifier)
    {
        list($hash, $keys) = self::_parseIdentifier($identifier);

        // find $var in the hashe
        foreach($keys as $key)
        {
            if(array_key_exists($key, $GLOBALS['_'.$hash])) {
                return true;;
            }
        }

        return false;
    }
    
    /**
     * Get the POST or PUT raw content information
     * 
     * The raw post data is not available with enctype="multipart/form-data".
     *  
     * @param   string  The content data to return. Can be 'type' or 'data'. 
     *                  If not set, all the data will be returned.
     * @return  array   An associative array with the content data. Valid keys are
     *                  'type' and 'data'
     */
    public static function content($key = null)
    {
        $result = '';
        
        if (!isset(self::$_content) && isset($_SERVER['CONTENT_TYPE'])) 
        {             
            $type = $_SERVER['CONTENT_TYPE']; 
                        
            // strip parameters from content-type like "; charset=UTF-8"             
            if (is_string($type)) 
            {                  
                if (preg_match('/^([^,\;]*)/', $type, $matches)) {                    
                    $type = $matches[1];                 
                }             
            }             
                
            self::$_content['type'] = $type;  
            
            
            $data = '';
            if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['CONTENT_LENGTH'] > 0) 
            {   
                $input = fopen('php://input', 'r');
                while ($chunk = fread($input, 1024)) {
                    $data .= $chunk;
                }

                fclose($input);
            }
            
            self::$_content['data'] = $data;
        }
            
        return isset($key) ? self::$_content[$key] : self::$_content;
    }
    
    /**
     * Get the accept request information 
     *
     * @param   string  The accept data to return. Can be 'format', 'encoding' or 'language'. 
     *                  If not set, all the accept data will be returned.
     * @return  array   An associative array with the content data. Valid keys are
     *                  'format', 'encoding' and 'language'
     */
    public static function accept($type = null)
    {
        if (!isset(self::$_accept) && isset($_SERVER['HTTP_ACCEPT'])) 
        {             
            $accept = KRequest::get('server.HTTP_ACCEPT', 'string');
            self::$_accept['format'] = self::_parseAccept($accept);
                            
            if (isset($_SERVER['HTTP_ACCEPT_ENCODING'])) 
            {   
                $accept = KRequest::get('server.HTTP_ACCEPT_ENCODING', 'string');
                self::$_accept['encoding'] = self::_parseAccept($accept);   
            }
            
            if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) 
            {   
                $accept = KRequest::get('server.HTTP_ACCEPT_LANGUAGE', 'string');
                self::$_accept['language'] = self::_parseAccept($accept);   
            }   
        }
            
        return $type ? self::$_accept[$type] : self::$_accept;
    }
    
    /**
     * Returns the HTTP referrer.
     * 
     * 'referer' a commonly used misspelling word for 'referrer'
     * @see     http://en.wikipedia.org/wiki/HTTP_referrer
     *
     * @param   boolean     Only allow internal url's
     * @return  KHttpUrl    A KHttpUrl object
     */
    public static function referrer($isInternal = true)
    {
        if(!isset(self::$_referrer))
        {
            if($referrer = KRequest::get('server.HTTP_REFERER', 'url')) 
            {
                self::$_referrer = KFactory::get('lib.koowa.http.url', array('url' => $referrer));
                
                if($isInternal)
                {
                    if(!KFactory::get('lib.koowa.filter.internalurl')->validate((string)self::$_referrer)) {
                        return null;
                    }
                }
            }
        }

        return self::$_referrer;
    }

    /**
     * Return the URI of the request regardless of the server
     *
     * @return  KHttpUrl    A KHttpUri object
     */
    public static function url()
    {
        if(!isset(self::$_url))
        {
            /*
             * Since we are assigning the URI from the server variables, we first need
             * to determine if we are running on apache or IIS.  If PHP_SELF and REQUEST_URI
             * are present, we will assume we are running on apache.
             */
            if (!empty ($_SERVER['PHP_SELF']) && !empty ($_SERVER['REQUEST_URI']))
            {
                /*
                 * To build the entire URI we need to prepend the protocol, and the http host
                 * to the URI string.
                 */
                $url = self::protocol().'://'. $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];

                /*
                 * Since we do not have REQUEST_URI to work with, we will assume we are
                 * running on IIS and will therefore need to work some magic with the SCRIPT_NAME and
                 * QUERY_STRING environment variables.
                 */
            }
            else
            {
                // IIS uses the SCRIPT_NAME variable instead of a REQUEST_URI variable
                $url = self::protocol().'://'. $_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'];

                // If the query string exists append it to the URI string
                if (isset($_SERVER['QUERY_STRING']) && !empty($_SERVER['QUERY_STRING'])) {
                    $url .= '?' . $_SERVER['QUERY_STRING'];
                }
            }
            
            // Sanitize the url since we can't trust the server var
            $url = KFactory::get('lib.koowa.filter.url')->sanitize($url);

            // Create the URI object
            self::$_url = KFactory::tmp('lib.koowa.http.url', array('url' => $url));

        }

        return self::$_url;
    }

    /**
     * Returns the base path of the request.
     *
     * @return  object  A KHttpUrl object
     */
    public static function base()
    {
        if(!isset(self::$_base))
        {
            // Get the base request path
            if (strpos(php_sapi_name(), 'cgi') !== false && !empty($_SERVER['REQUEST_URI'])) {
                //Apache CGI
                $path =  rtrim(dirname($_SERVER['PHP_SELF']), '/\\');
            } else {
                //Others
                $path =  rtrim(dirname($_SERVER['SCRIPT_NAME']), '/\\');
            }

            // Sanitize the url since we can't trust the server var         
            $path = KFactory::get('lib.koowa.filter.url')->sanitize($path);
                
            self::$_base = KFactory::tmp('lib.koowa.http.url', array('url' => $path));
        }
        
        return self::$_base;
    }
    
    /**
     * Returns the root path of the request.
     * 
     * In most case this value will be the same as KRequest::base however it can be
     * changed by pushing in a different value
     *
     * @return  object  A KHttpUrl object
     */
    public static function root($path = null)
    {
        if(!is_null($path)) 
        {
            if(!$path instanceof KhttpUrl) {
                $path = KFactory::tmp('lib.koowa.http.url', array('url' => $path));
            }
            
            self::$_root = $path;
        }
        
        if(is_null(self::$_root)) {
            self::$_root = self::$_base;
        }
        
        return self::$_root;
    }

    /**
     * Returns the current request protocol, based on $_SERVER['https']. In CLI
     * mode, NULL will be returned.
     *
     * @return  string
     */
    public static function protocol()
    {
        if (PHP_SAPI === 'cli') {
            return NULL;
        }

        if (isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && (strtolower($_SERVER['HTTPS']) != 'off')) {
            return 'https';
        } else {
            return 'http';
        }
    }

    /**
     * Returns current request method.
     *
     * @return  string
     */
    public static function method()
    {
        $method = '';
        
        if(PHP_SAPI != 'cli')
        {
            $method  =  strtoupper($_SERVER['REQUEST_METHOD']);

            if($method == 'POST')
            {
                if(isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) {
                    $method = strtoupper($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']);
                }
                
                if(self::has('post._method')) {
                    $method = strtoupper(self::get('post._method', 'cmd'));
                }
            }
        } 

        return $method;
    }

    /**
     * Return the current request transport type.
     *
     * @return  string
     */
    public static function type()
    {
        $type = 'HTTP';

        if(isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest') {
            $type = 'AJAX';
        }

        if( isset($_SERVER['HTTP_X_FLASH_VERSION'])) {
            $type = 'FLASH';
        }

        return $type;
    }
    
    /**
     * Return the request token
     *
     * @return  string  The request token or NULL if no token could be found
     */
    public static function token()
    {
        $token = null;
        
        if(self::has('server.HTTP_X_TOKEN')) {
            $token = self::get('server.HTTP_X_TOKEN', '<PASSWORD>');
        }
        
        if(self::has('request._token')) {<commit_msg>Added extra check to KRequest::type() to dected requests coming from Flash.<commit_after><?php
/**
 * @version    	$Id$
 * @category	Koowa
 * @package    	Koowa_Request
 * @copyright  	Copyright (C) 2007 - 2010 <NAME>. All rights reserved.
 * @license    	GNU GPLv3 <http://www.gnu.org/licenses/gpl.html>
 * @link 		http://www.nooku.org
 */

//Instantiate the request singleton
KRequest::instantiate();

/**
 * Request class
 *
 * @author      <NAME> <<EMAIL>>
 * @category    Koowa
 * @package     Koowa_Request
 * @uses        KFilter
 * @uses        KInflector
 * @uses        KFactory
 * @static
 */
class KRequest
{
    /**
     * URL of the request regardless of the server
     *
     * @var KHttpUrl
     */
    protected static $_url = null;

    /**
     * Base path of the request.
     *
     * @var KHttpUrl
     */
    protected static $_base = null;
    
    /**
     * Root path of the request.
     *
     * @var KHttpUrl
     */
    protected static $_root = null;

    /**
     * Referrer of the request
     *
     * @var KHttpUrl
     */
    protected static $_referrer = null;
    
    /**
     * The raw post or put content information
     *
     * @var array
     */
    protected static $_content = null;
    
    /**
     * The request accepts information
     *
     * @var array
     */
    protected static $_accept = null;
    
    
    /**
     * Constructor
     *
     * Prevent creating instances of this class by making the contructor private
     */
    final private function __construct(KConfig $config) 
    {
        $content = self::content();
        
        if(self::type() == 'HTTP')
        {
            $authorization = KRequest::get('server.HTTP_AUTHORIZATION', 'url');
	        if (strstr($authorization,"Basic")) 
	        {
	            $parts = explode(':',base64_decode(substr($authorization, 6)));
			
	            if (count($parts) == 2) 
			    {
				    KRequest::set('server.PHP_AUTH_USER', $parts[0]); 
				    KRequest::set('server.PHP_AUTH_PW'  , $parts[1]); 
			    }
		    }
        }
        
        if(!empty($content['data']))
        {
            if($content['type'] == 'application/x-www-form-urlencoded') 
            {
                if (in_array(self::method(), array('PUT', 'DELETE'))) 
                {
                    parse_str($content['data'], $GLOBALS['_'.self::method()]);
                    $GLOBALS['_REQUEST'] = array_merge($GLOBALS['_REQUEST'],  $GLOBALS['_'.self::method()]); 
                }
            }
            
            if($content['type'] == 'application/json') 
            {
                if(in_array(self::method(), array('POST', 'PUT', 'DELETE'))) 
                {
                    $GLOBALS['_'.self::method()] = json_decode($content['data'], true);
                    $GLOBALS['_REQUEST'] = array_merge($GLOBALS['_REQUEST'],  $GLOBALS['_'.self::method()]); 
                }
            }   
        }
     }
    
    /**
     * Clone 
     *
     * Prevent creating clones of this class
     */
    final private function __clone() { }
    
    /**
     * Force creation of a singleton
     *
     * @return void
     */
    public static function instantiate($config = array())
    {
        static $instance;
        
        if ($instance === NULL) 
        {
            if(!$config instanceof KConfig) {
                $config = new KConfig($config);
            }
            
            $instance = new self($config);
        }
        
        return $instance;
    }


    /**
     * Get sanitized data from the request.
     *
     * @param   string              Variable identifier, prefixed by hash name eg post.foo.bar
     * @param   mixed               Filter(s), can be a KFilter object, a filter name, an array of filter names or a filter identifier
     * @param   mixed               Default value when the variable doesn't exist
     * @throws  KRequestException   When an invalid filter was passed
     * @return  mixed               The sanitized data
     */
    public static function get($identifier, $filter, $default = null)
    {
        list($hash, $keys) = self::_parseIdentifier($identifier);
        
        $result = null;
        if(isset($GLOBALS['_'.$hash]))
        {
            $result = $GLOBALS['_'.$hash];
            foreach($keys as $key)
            {
                if(array_key_exists($key, $result)) {
                    $result = $result[$key];
                } else {
                    $result = null;
                    break;
                }
            }
        }
       
        
        // If the value is null return the default
        if(is_null($result)) {
            return $default;
        }
    
        // Handle magic quotes compatability
        if (get_magic_quotes_gpc() && !in_array($hash, array('FILES', 'SESSION'))) {
            $result = self::_stripSlashes( $result );
        }

        if(!($filter instanceof KFilterInterface)) {
            $filter = KFilter::factory($filter);
        }

        return $filter->sanitize($result);
    }

    /**
     * Set a variable in the request. Cookies and session data are stored persistently.
     *
     * @param   mixed   Variable identifier, prefixed by hash name eg post.foo.bar
     * @param   mixed   Variable value
     */
    public static function set($identifier, $value)
    {
        list($hash, $keys) = self::_parseIdentifier($identifier);

        // Add to _REQUEST hash if original hash is get, post, or cookies 
        if(in_array($hash, array('GET', 'POST', 'COOKIE'))) {
            self::set('request.'.implode('.', $keys), $value);
        }

        // Store cookies persistently
        if($hash == 'COOKIE')
        {
            // rewrite the $keys as foo[bar][bar]
            $ckeys = $keys; // get a copy
            $name = array_shift($ckeys);
            foreach($ckeys as $ckey) {
                $name .= '['.$ckey.']';
            }

            if(!setcookie($name, $value)) {
                throw new KRequestException("Couldn't set cookie, headers already sent.");
            }
        }
        
        // Store in $GLOBALS
        foreach(array_reverse($keys, true) as $key) {
            $value = array($key => $value);
        }
        
        $GLOBALS['_'.$hash] = KHelperArray::merge($GLOBALS['_'.$hash], $value);
    }

    /**
     * Check if a variable exists based on an identifier
     *
     * @param   string  Variable identifier, prefixed by hash name eg post.foo.bar
     * @return  boolean
     */
    public static function has($identifier)
    {
        list($hash, $keys) = self::_parseIdentifier($identifier);

        // find $var in the hashe
        foreach($keys as $key)
        {
            if(array_key_exists($key, $GLOBALS['_'.$hash])) {
                return true;;
            }
        }

        return false;
    }
    
    /**
     * Get the POST or PUT raw content information
     * 
     * The raw post data is not available with enctype="multipart/form-data".
     *  
     * @param   string  The content data to return. Can be 'type' or 'data'. 
     *                  If not set, all the data will be returned.
     * @return  array   An associative array with the content data. Valid keys are
     *                  'type' and 'data'
     */
    public static function content($key = null)
    {
        $result = '';
        
        if (!isset(self::$_content) && isset($_SERVER['CONTENT_TYPE'])) 
        {             
            $type = $_SERVER['CONTENT_TYPE']; 
                        
            // strip parameters from content-type like "; charset=UTF-8"             
            if (is_string($type)) 
            {                  
                if (preg_match('/^([^,\;]*)/', $type, $matches)) {                    
                    $type = $matches[1];                 
                }             
            }             
                
            self::$_content['type'] = $type;  
            
            
            $data = '';
            if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['CONTENT_LENGTH'] > 0) 
            {   
                $input = fopen('php://input', 'r');
                while ($chunk = fread($input, 1024)) {
                    $data .= $chunk;
                }

                fclose($input);
            }
            
            self::$_content['data'] = $data;
        }
            
        return isset($key) ? self::$_content[$key] : self::$_content;
    }
    
    /**
     * Get the accept request information 
     *
     * @param   string  The accept data to return. Can be 'format', 'encoding' or 'language'. 
     *                  If not set, all the accept data will be returned.
     * @return  array   An associative array with the content data. Valid keys are
     *                  'format', 'encoding' and 'language'
     */
    public static function accept($type = null)
    {
        if (!isset(self::$_accept) && isset($_SERVER['HTTP_ACCEPT'])) 
        {             
            $accept = KRequest::get('server.HTTP_ACCEPT', 'string');
            self::$_accept['format'] = self::_parseAccept($accept);
                            
            if (isset($_SERVER['HTTP_ACCEPT_ENCODING'])) 
            {   
                $accept = KRequest::get('server.HTTP_ACCEPT_ENCODING', 'string');
                self::$_accept['encoding'] = self::_parseAccept($accept);   
            }
            
            if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) 
            {   
                $accept = KRequest::get('server.HTTP_ACCEPT_LANGUAGE', 'string');
                self::$_accept['language'] = self::_parseAccept($accept);   
            }   
        }
            
        return $type ? self::$_accept[$type] : self::$_accept;
    }
    
    /**
     * Returns the HTTP referrer.
     * 
     * 'referer' a commonly used misspelling word for 'referrer'
     * @see     http://en.wikipedia.org/wiki/HTTP_referrer
     *
     * @param   boolean     Only allow internal url's
     * @return  KHttpUrl    A KHttpUrl object
     */
    public static function referrer($isInternal = true)
    {
        if(!isset(self::$_referrer))
        {
            if($referrer = KRequest::get('server.HTTP_REFERER', 'url')) 
            {
                self::$_referrer = KFactory::get('lib.koowa.http.url', array('url' => $referrer));
                
                if($isInternal)
                {
                    if(!KFactory::get('lib.koowa.filter.internalurl')->validate((string)self::$_referrer)) {
                        return null;
                    }
                }
            }
        }

        return self::$_referrer;
    }

    /**
     * Return the URI of the request regardless of the server
     *
     * @return  KHttpUrl    A KHttpUri object
     */
    public static function url()
    {
        if(!isset(self::$_url))
        {
            /*
             * Since we are assigning the URI from the server variables, we first need
             * to determine if we are running on apache or IIS.  If PHP_SELF and REQUEST_URI
             * are present, we will assume we are running on apache.
             */
            if (!empty ($_SERVER['PHP_SELF']) && !empty ($_SERVER['REQUEST_URI']))
            {
                /*
                 * To build the entire URI we need to prepend the protocol, and the http host
                 * to the URI string.
                 */
                $url = self::protocol().'://'. $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];

                /*
                 * Since we do not have REQUEST_URI to work with, we will assume we are
                 * running on IIS and will therefore need to work some magic with the SCRIPT_NAME and
                 * QUERY_STRING environment variables.
                 */
            }
            else
            {
                // IIS uses the SCRIPT_NAME variable instead of a REQUEST_URI variable
                $url = self::protocol().'://'. $_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'];

                // If the query string exists append it to the URI string
                if (isset($_SERVER['QUERY_STRING']) && !empty($_SERVER['QUERY_STRING'])) {
                    $url .= '?' . $_SERVER['QUERY_STRING'];
                }
            }
            
            // Sanitize the url since we can't trust the server var
            $url = KFactory::get('lib.koowa.filter.url')->sanitize($url);

            // Create the URI object
            self::$_url = KFactory::tmp('lib.koowa.http.url', array('url' => $url));

        }

        return self::$_url;
    }

    /**
     * Returns the base path of the request.
     *
     * @return  object  A KHttpUrl object
     */
    public static function base()
    {
        if(!isset(self::$_base))
        {
            // Get the base request path
            if (strpos(php_sapi_name(), 'cgi') !== false && !empty($_SERVER['REQUEST_URI'])) {
                //Apache CGI
                $path =  rtrim(dirname($_SERVER['PHP_SELF']), '/\\');
            } else {
                //Others
                $path =  rtrim(dirname($_SERVER['SCRIPT_NAME']), '/\\');
            }

            // Sanitize the url since we can't trust the server var         
            $path = KFactory::get('lib.koowa.filter.url')->sanitize($path);
                
            self::$_base = KFactory::tmp('lib.koowa.http.url', array('url' => $path));
        }
        
        return self::$_base;
    }
    
    /**
     * Returns the root path of the request.
     * 
     * In most case this value will be the same as KRequest::base however it can be
     * changed by pushing in a different value
     *
     * @return  object  A KHttpUrl object
     */
    public static function root($path = null)
    {
        if(!is_null($path)) 
        {
            if(!$path instanceof KhttpUrl) {
                $path = KFactory::tmp('lib.koowa.http.url', array('url' => $path));
            }
            
            self::$_root = $path;
        }
        
        if(is_null(self::$_root)) {
            self::$_root = self::$_base;
        }
        
        return self::$_root;
    }

    /**
     * Returns the current request protocol, based on $_SERVER['https']. In CLI
     * mode, NULL will be returned.
     *
     * @return  string
     */
    public static function protocol()
    {
        if (PHP_SAPI === 'cli') {
            return NULL;
        }

        if (isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && (strtolower($_SERVER['HTTPS']) != 'off')) {
            return 'https';
        } else {
            return 'http';
        }
    }

    /**
     * Returns current request method.
     *
     * @return  string
     */
    public static function method()
    {
        $method = '';
        
        if(PHP_SAPI != 'cli')
        {
            $method  =  strtoupper($_SERVER['REQUEST_METHOD']);

            if($method == 'POST')
            {
                if(isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) {
                    $method = strtoupper($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']);
                }
                
                if(self::has('post._method')) {
                    $method = strtoupper(self::get('post._method', 'cmd'));
                }
            }
        } 

        return $method;
    }

    /**
     * Return the current request transport type.
     *
     * @return  string
     */
    public static function type()
    {
        $type = 'HTTP';

        if(isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest') {
            $type = 'AJAX';
        }

        if( isset($_SERVER['HTTP_X_FLASH_VERSION'])) {
            $type = 'FLASH';
        }
        
        if(preg_match('/^(Shockwave|Adobe) Flash/', $_SERVER['HTTP_USER_AGENT']) == 1) {
             $type = 'FLASH';
        }

        return $type;
    }
    
    /**
     * Return the request token
     *
     * @return  string  The request token or NULL if no token could be found
     */
    public static function token()
    {
        $token = null;
        
        if(self::has('server.HTTP_X_TOKEN')) {
            $token = self::get('server.HTTP_X_TOKEN', '<PASSWORD>');
        }
        
        if(self::has('request._token')) {
{'fraction_non_alphanumeric': 0.13115460364352535, 'fraction_numerical': 0.0013847858197932052, 'mean_word_length': 1.487142201132711, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 6, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, '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': '3092582', 'n_tokens_mistral': 9212, 'n_tokens_neox': 8829, 'n_words': 2176}