public function define_core_constants() {
        // Check minimal config job has been properly done
        $must_haves = array('YOURLS_DB_USER', 'YOURLS_DB_PASS', 'YOURLS_DB_NAME', 'YOURLS_DB_HOST', 'YOURLS_DB_PREFIX', 'YOURLS_SITE');
        foreach($must_haves as $must_have) {
            if (!defined($must_have)) {
                throw new ConfigException('Config is incomplete (missing at least '.$must_have.') Check config-sample.php and edit your config accordingly');
            }
        }

        /**
         * The following has an awful CRAP index and it would be much shorter reduced to something like
         * defining an array of ('YOURLS_SOMETHING' => 'default value') and then a simple loop over the
         * array, checking if $current is defined as a constant and otherwise define said constant with
         * its default value. I did not wrote it that way because that would make it difficult for code
         * parsers to identify which constants are defined and where. So, here it is, that long list of
         * if (!defined) define(). Ho and by the way, such beautiful comment, much right aligned, wow !
         */

        // physical path of YOURLS root
        if (!defined( 'YOURLS_ABSPATH' ))
            define('YOURLS_ABSPATH', $this->root);

        // physical path of includes directory
        if (!defined( 'YOURLS_INC' ))
            define('YOURLS_INC', YOURLS_ABSPATH.'/includes');

        // physical path of user directory
        if (!defined( 'YOURLS_USERDIR' ))
            define( 'YOURLS_USERDIR', YOURLS_ABSPATH.'/user' );

        // URL of user directory
        if (!defined( 'YOURLS_USERURL' ))
            define( 'YOURLS_USERURL', YOURLS_SITE.'/user' );

        // physical path of asset directory
        if( !defined( 'YOURLS_ASSETDIR' ) )
            define( 'YOURLS_ASSETDIR', YOURLS_ABSPATH.'/assets' );

        // URL of asset directory
        if( !defined( 'YOURLS_ASSETURL' ) )
            define( 'YOURLS_ASSETURL', YOURLS_SITE.'/assets' );

        // physical path of translations directory
        if (!defined( 'YOURLS_LANG_DIR' ))
            define( 'YOURLS_LANG_DIR', YOURLS_USERDIR.'/languages' );

        // physical path of plugins directory
        if (!defined( 'YOURLS_PLUGINDIR' ))
            define( 'YOURLS_PLUGINDIR', YOURLS_USERDIR.'/plugins' );

        // URL of plugins directory
        if (!defined( 'YOURLS_PLUGINURL' ))
            define( 'YOURLS_PLUGINURL', YOURLS_USERURL.'/plugins' );

        // physical path of themes directory
        if( !defined( 'YOURLS_THEMEDIR' ) )
            define( 'YOURLS_THEMEDIR', YOURLS_USERDIR.'/themes' );

        // URL of themes directory
        if( !defined( 'YOURLS_THEMEURL' ) )
            define( 'YOURLS_THEMEURL', YOURLS_USERURL.'/themes' );

        // physical path of pages directory
        if (!defined( 'YOURLS_PAGEDIR' ))
            define('YOURLS_PAGEDIR', YOURLS_ABSPATH.'/pages' );

        // table to store URLs
        if (!defined( 'YOURLS_DB_TABLE_URL' ))
            define( 'YOURLS_DB_TABLE_URL', YOURLS_DB_PREFIX.'url' );

        // table to store options
        if (!defined( 'YOURLS_DB_TABLE_OPTIONS' ))
            define( 'YOURLS_DB_TABLE_OPTIONS', YOURLS_DB_PREFIX.'options' );

        // table to store hits, for stats
        if (!defined( 'YOURLS_DB_TABLE_LOG' ))
            define( 'YOURLS_DB_TABLE_LOG', YOURLS_DB_PREFIX.'log' );

        // minimum delay in sec before a same IP can add another URL. Note: logged in users are not throttled down.
        if (!defined( 'YOURLS_FLOOD_DELAY_SECONDS' ))
            define( 'YOURLS_FLOOD_DELAY_SECONDS', 15 );

        // comma separated list of IPs that can bypass flood check.
        if (!defined( 'YOURLS_FLOOD_IP_WHITELIST' ))
            define( 'YOURLS_FLOOD_IP_WHITELIST', '' );

        // life span of an auth cookie in seconds (60*60*24*7 = 7 days)
        if (!defined( 'YOURLS_COOKIE_LIFE' ))
            define( 'YOURLS_COOKIE_LIFE', 60*60*24*7 );

        // life span of a nonce in seconds
        if (!defined( 'YOURLS_NONCE_LIFE' ))
            define( 'YOURLS_NONCE_LIFE', 43200 ); // 3600 * 12

        // if set to true, disable stat logging (no use for it, too busy servers, ...)
        if (!defined( 'YOURLS_NOSTATS' ))
            define( 'YOURLS_NOSTATS', false );

        // if set to true, force https:// in the admin area
        if (!defined( 'YOURLS_ADMIN_SSL' ))
            define( 'YOURLS_ADMIN_SSL', false );

        // if set to true, verbose debug infos. Will break things. Don't enable.
        if (!defined( 'YOURLS_DEBUG' ))
            define( 'YOURLS_DEBUG', false );

        // Error reporting
        if (defined( 'YOURLS_DEBUG' ) && YOURLS_DEBUG == true ) {
            error_reporting( -1 );
        } else {
            error_reporting( E_ERROR | E_PARSE );
        }
    }

Define core constants that have not been user defined in config.php

@since  1.7.3
@return void
@throws ConfigException

Define core constants that have not been user defined in config . php


public function set_emulate_state() {
        try {
            $this->is_emulate_prepare = $this->getAttribute(PDO::ATTR_EMULATE_PREPARES);
        } catch (\PDOException $e) {
            $this->is_emulate_prepare = false;
        }
    }

public function set_emulate_state ( ) { try { $ this -> is_emulate_prepare = $ this -> getAttribute ( PDO :: ATTR_EMULATE_PREPARES ) ; } catch ( \ PDOException $ e ) { $ this -> is_emulate_prepare = false ; } }

Check if we emulate prepare statements, and set bool flag accordingly

Check if current driver can PDO::getAttribute(PDO::ATTR_EMULATE_PREPARES)
Some combinations of PHP/MySQL don't support this function. See
https://travis-ci.org/YOURLS/YOURLS/jobs/271423782#L481

@since  1.7.3
@return void

Check if we emulate prepare statements and set bool flag accordingly


public function dead_or_error(\Exception $exception) {
        // Use any /user/db_error.php file
        if( file_exists( YOURLS_USERDIR . '/db_error.php' ) ) {
            include_once( YOURLS_USERDIR . '/db_error.php' );
            die();
        }

        $message  = yourls__( 'Incorrect DB config, or could not connect to DB' );
        $message .= '<br/>' . get_class($exception) .': ' . $exception->getMessage();

        yourls_die( yourls__( $message ), yourls__( 'Fatal error' ), 503 );
        die();
    }

Die with an error message

@since  1.7.3

@param \Exception $exception

@return void


public function get_queries() {
        $queries = $this->getProfiler()->getProfiles();

        if ($this->get_emulate_state()) {
            // keep queries if $query['function'] != 'prepare'
            $queries = array_filter($queries, function($query) {return $query['function'] !== 'prepare';});
        }

        return $queries;
    }

Return SQL queries performed

Aura\Sql\Profiler logs every PDO command issued. But depending on PDO::ATTR_EMULATE_PREPARES, some are
actually sent to the mysql server or not :
- if PDO::ATTR_EMULATE_PREPARES is true, prepare() statements are not sent to the server and are performed
internally, so they are removed from the logger
- if PDO::ATTR_EMULATE_PREPARES is false, prepare() statements are actually performed by the mysql server,
and count as an actual query

Resulting array is something like:
array (
0 => array (
'duration' => 1.0010569095611572265625,
'function' => 'connect',
'statement' => NULL,
'bind_values' => array (),
'trace' => ...back trace...,
),
// key index might not be sequential if 'prepare' function are filtered out
2 => array (
'duration' => 0.000999927520751953125,
'function' => 'perform',
'statement' => 'SELECT option_value FROM yourls_options WHERE option_name = :option_name LIMIT 1',
'bind_values' => array ( 'option_name' => 'test_option' ),
'trace' => ...back trace...,
),
);

@since  1.7.3
@return array


function register_globals() {
		$GLOBALS['weekday']         = $this->weekday;
		$GLOBALS['weekday_initial'] = $this->weekday_initial;
		$GLOBALS['weekday_abbrev']  = $this->weekday_abbrev;
		$GLOBALS['month']           = $this->month;
		$GLOBALS['month_abbrev']    = $this->month_abbrev;
	}

function register_globals ( ) { $ GLOBALS [ 'weekday' ] = $ this -> weekday ; $ GLOBALS [ 'weekday_initial' ] = $ this -> weekday_initial ; $ GLOBALS [ 'weekday_abbrev' ] = $ this -> weekday_abbrev ; $ GLOBALS [ 'month' ] = $ this -> month ; $ GLOBALS [ 'month_abbrev' ] = $ this -> month_abbrev ; }

Global variables are deprecated. For backwards compatibility only.

@deprecated For backwards compatibility only.
@access private

@since 1.6

Global variables are deprecated . For backwards compatibility only .


public function get_all_options() {
        // Get option values from DB
        $table = YOURLS_DB_TABLE_OPTIONS;
        $sql = "SELECT option_name, option_value FROM $table WHERE 1=1";

        try {
            $options = (array) $this->ydb->fetchPairs($sql);

        } catch ( PDOException $e ) {

            // We could not fetch value from the table. Let's check if the option table exists
            try {
                $check = $this->ydb->fetchAffected(sprintf("SHOW TABLES LIKE '%s'", $table));
                // Table doesn't exist
                if ($check ==0) {
                    return false;
                }

            // Error at this point means the database isn't readable
            } catch ( PDOException $e ) {
                $this->ydb->dead_or_error($e);
            }

        }

        // Unlikely scenario, but who knows: table exists, but is empty
        if (empty($options)) {
            return false;
        }

        foreach ($options as $name => $value) {
            $this->ydb->set_option($name, yourls_maybe_unserialize($value));
        }

        yourls_apply_filter('get_all_options', 'deprecated');

        return true;
    }

Read all options from DB at once, return bool

@since  1.7.3
@return bool    True on success, false on failure (eg table missing or empty)

Read all options from DB at once return bool


public function add($name, $value) {
        $name = trim((string)$name);
        if (empty($name)) {
            return false;
        }

        // Use clone to break object refs -- see commit 09b989d375bac65e692277f61a84fede2fb04ae3
        if (is_object($value)) {
            $value = clone $value;
        }

        // Make sure the option doesn't already exist
        if ($this->ydb->has_option($name)) {
            return false;
        }
        // if (false !== yourls_get_option($name)) {
            // return false;
        // }

        $table = YOURLS_DB_TABLE_OPTIONS;
        $_value = yourls_maybe_serialize($value);
        $sql  = "INSERT INTO $table (option_name, option_value) VALUES (:name, :value)";
        $bind = array('name' => $name, 'value' => $_value);
        $do   = $this->ydb->fetchAffected($sql, $bind);

        if($do !== 1) {
            // Something went wrong :(
            return false;
        }

        // Cache option value to save a DB query if needed later
        $this->ydb->set_option($name, $value);
        yourls_do_action('add_option', $name, $_value);

        return true;
    }

Add an option to the DB

@since  1.7.3
@param  string $name   Name of option to add. Expected to not be SQL-escaped.
@param  mixed  $value  Optional option value. Must be serializable if non-scalar. Expected to not be SQL-escaped.
@return bool           False if option was not added (eg already exists), true otherwise.


public function delete($name) {
        $name = trim((string)$name);
        if (empty($name)) {
            return false;
        }

        $table = YOURLS_DB_TABLE_OPTIONS;
        $sql = "DELETE FROM $table WHERE option_name = :name";
        $bind = array('name' => $name);
        $do   = $this->ydb->fetchAffected($sql, $bind);

        if($do !== 1) {
            // Something went wrong :(
            return false;
        }

        yourls_do_action('delete_option', $name);
        $this->ydb->delete_option($name);
        return true;
    }

Delete option from DB

@since  1.7.3
@param  string $name  Option name to delete. Expected to not be SQL-escaped.
@return bool          False if option was not deleted (eg not found), true otherwise.


public function addPlaceholder($placeholder, string $pattern = null): RouteCollectionInterface
	{
		if (! is_array($placeholder))
		{
			$placeholder = [$placeholder => $pattern];
		}

		$this->placeholders = array_merge($this->placeholders, $placeholder);

		return $this;
	}

public function addPlaceholder ( $ placeholder , string $ pattern = null ) : RouteCollectionInterface { if ( ! is_array ( $ placeholder ) ) { $ placeholder = [ $ placeholder => $ pattern ] ; } $ this -> placeholders = array_merge ( $ this -> placeholders , $ placeholder ) ; return $ this ; }

Registers a new constraint with the system. Constraints are used
by the routes as placeholders for regular expressions to make defining
the routes more human-friendly.

You can pass an associative array as $placeholder, and have
multiple placeholders added at once.

@param string|array $placeholder
@param string       $pattern

@return \CodeIgniter\Router\RouteCollectionInterface

Registers a new constraint with the system . Constraints are used by the routes as placeholders for regular expressions to make defining the routes more human - friendly .


public function setDefaultNamespace(string $value): RouteCollectionInterface
	{
		$this->defaultNamespace = filter_var($value, FILTER_SANITIZE_STRING);
		$this->defaultNamespace = rtrim($this->defaultNamespace, '\\') . '\\';

		return $this;
	}

public function setDefaultNamespace ( string $ value ) : RouteCollectionInterface { $ this -> defaultNamespace = filter_var ( $ value , FILTER_SANITIZE_STRING ) ; $ this -> defaultNamespace = rtrim ( $ this -> defaultNamespace , '\\' ) . '\\' ; return $ this ; }

Sets the default namespace to use for Controllers when no other
namespace has been specified.

@param $value

@return \CodeIgniter\Router\RouteCollectionInterface

Sets the default namespace to use for Controllers when no other namespace has been specified .


public function setDefaultController(string $value): RouteCollectionInterface
	{
		$this->defaultController = filter_var($value, FILTER_SANITIZE_STRING);

		return $this;
	}

public function setDefaultController ( string $ value ) : RouteCollectionInterface { $ this -> defaultController = filter_var ( $ value , FILTER_SANITIZE_STRING ) ; return $ this ; }

Sets the default controller to use when no other controller has been
specified.

@param $value

@return \CodeIgniter\Router\RouteCollectionInterface

Sets the default controller to use when no other controller has been specified .


public function setDefaultMethod(string $value): RouteCollectionInterface
	{
		$this->defaultMethod = filter_var($value, FILTER_SANITIZE_STRING);

		return $this;
	}

public function setDefaultMethod ( string $ value ) : RouteCollectionInterface { $ this -> defaultMethod = filter_var ( $ value , FILTER_SANITIZE_STRING ) ; return $ this ; }

Sets the default method to call on the controller when no other
method has been set in the route.

@param $value

@return \CodeIgniter\Router\RouteCollectionInterface

Sets the default method to call on the controller when no other method has been set in the route .


protected function discoverRoutes()
	{
		if ($this->didDiscover)
		{
			return;
		}

		// We need this var in local scope
		// so route files can access it.
		$routes = $this;

		if ($this->moduleConfig->shouldDiscover('routes'))
		{
			$files = $this->fileLocator->search('Config/Routes.php');

			foreach ($files as $file)
			{
				// Don't include our main file again...
				if ($file === APPPATH . 'Config/Routes.php')
				{
					continue;
				}

				include $file;
			}
		}

		$this->didDiscover = true;
	}

protected
function
discoverRoutes
(
)
{
if
(
$
this
->
didDiscover
)
{
return
;
}
// We need this var in local scope
// so route files can access it.
$
routes
=
$
this
;
if
(
$
this
->
moduleConfig
->
shouldDiscover
(
'routes'
)
)
{
$
files
=
$
this
->
fileLocator
->
search
(
'Config/Routes.php'
)
;
foreach
(
$
files
as
$
file
)
{
// Don't include our main file again...
if
(
$
file
===
APPPATH
.
'Config/Routes.php'
)
{
continue
;
}
include
$
file
;
}
}
$
this
->
didDiscover
=
true
;
}

Will attempt to discover any additional routes, either through
the local PSR4 namespaces, or through selected Composer packages.

Will attempt to discover any additional routes either through the local PSR4 namespaces or through selected Composer packages .


public function setDefaultConstraint(string $placeholder): RouteCollectionInterface
	{
		if (array_key_exists($placeholder, $this->placeholders))
		{
			$this->defaultPlaceholder = $placeholder;
		}

		return $this;
	}

public function setDefaultConstraint ( string $ placeholder ) : RouteCollectionInterface { if ( array_key_exists ( $ placeholder , $ this -> placeholders ) ) { $ this -> defaultPlaceholder = $ placeholder ; } return $ this ; }

Sets the default constraint to be used in the system. Typically
for use with the 'resource' method.

@param string $placeholder

@return RouteCollectionInterface

Sets the default constraint to be used in the system . Typically for use with the resource method .


public function getRoutes($verb = null): array
	{
		if (empty($verb))
		{
			$verb = $this->getHTTPVerb();
		}

		// Since this is the entry point for the Router,
		// take a moment to do any route discovery
		// we might need to do.
		$this->discoverRoutes();

		$routes = [];

		if (isset($this->routes[$verb]))
		{
			// Keep current verb's routes at the beginning so they're matched
			// before any of the generic, "add" routes.
			if (isset($this->routes['*']))
			{
				$extraRules = array_diff_key($this->routes['*'], $this->routes[$verb]);
				$collection = array_merge($this->routes[$verb], $extraRules);
			}
			foreach ($collection as $r)
			{
				$key          = key($r['route']);
				$routes[$key] = $r['route'][$key];
			}
		}

		return $routes;
	}

Returns the raw array of available routes.

@param mixed $verb

@return array

Returns the raw array of available routes .


public function getRoutesOptions(string $from = null): array
	{
		return $from ? $this->routesOptions[$from] ?? [] : $this->routesOptions;
	}

public function getRoutesOptions ( string $ from = null ) : array { return $ from ? $ this -> routesOptions [ $ from ] ?? [ ] : $ this -> routesOptions ; }

Returns one or all routes options

@param string $from

@return array


public function map(array $routes = [], array $options = null): RouteCollectionInterface
	{
		foreach ($routes as $from => $to)
		{
			$this->add($from, $to, $options);
		}

		return $this;
	}

public function map ( array $ routes = [ ] , array $ options = null ) : RouteCollectionInterface { foreach ( $ routes as $ from => $ to ) { $ this -> add ( $ from , $ to , $ options ) ; } return $ this ; }

A shortcut method to add a number of routes at a single time.
It does not allow any options to be set on the route, or to
define the method used.

@param array $routes
@param array $options

@return RouteCollectionInterface

A shortcut method to add a number of routes at a single time . It does not allow any options to be set on the route or to define the method used .


public function addRedirect(string $from, string $to, int $status = 302)
	{
		// Use the named route's pattern if this is a named route.
		if (array_key_exists($to, $this->routes['*']))
		{
			$to = $this->routes['*'][$to]['route'];
		}

		$this->create('*', $from, $to, ['redirect' => $status]);

		return $this;
	}

Adds a temporary redirect from one route to another. Used for
redirecting traffic from old, non-existing routes to the new
moved routes.

@param string  $from   The pattern to match against
@param string  $to     Either a route name or a URI to redirect to
@param integer $status The HTTP status code that should be returned with this redirect

@return RouteCollection

Adds a temporary redirect from one route to another . Used for redirecting traffic from old non - existing routes to the new moved routes .


public function isRedirect(string $from): bool
	{
		foreach ($this->routes['*'] as $name => $route)
		{
			// Named route?
			if ($name === $from || key($route['route']) === $from)
			{
				return isset($route['redirect']) && is_numeric($route['redirect']);
			}
		}

		return false;
	}

public
function
isRedirect
(
string
$
from
)
:
bool
{
foreach
(
$
this
->
routes
[
'*'
]
as
$
name
=>
$
route
)
{
// Named route?
if
(
$
name
===
$
from
||
key
(
$
route
[
'route'
]
)
===
$
from
)
{
return
isset
(
$
route
[
'redirect'
]
)
&&
is_numeric
(
$
route
[
'redirect'
]
)
;
}
}
return
false
;
}

Determines if the route is a redirecting route.

@param string $from

@return boolean

Determines if the route is a redirecting route .


public function getRedirectCode(string $from): int
	{
		foreach ($this->routes['*'] as $name => $route)
		{
			// Named route?
			if ($name === $from || key($route['route']) === $from)
			{
				return $route['redirect'] ?? 0;
			}
		}

		return 0;
	}

public
function
getRedirectCode
(
string
$
from
)
:
int
{
foreach
(
$
this
->
routes
[
'*'
]
as
$
name
=>
$
route
)
{
// Named route?
if
(
$
name
===
$
from
||
key
(
$
route
[
'route'
]
)
===
$
from
)
{
return
$
route
[
'redirect'
]
??
0
;
}
}
return
0
;
}

Grabs the HTTP status code from a redirecting Route.

@param string $from

@return integer

Grabs the HTTP status code from a redirecting Route .


public function match(array $verbs = [], string $from, $to, array $options = null): RouteCollectionInterface
	{
		foreach ($verbs as $verb)
		{
			$verb = strtolower($verb);

			$this->{$verb}($from, $to, $options);
		}

		return $this;
	}

public function match ( array $ verbs = [ ] , string $ from , $ to , array $ options = null ) : RouteCollectionInterface { foreach ( $ verbs as $ verb ) { $ verb = strtolower ( $ verb ) ; $ this -> { $ verb } ( $ from , $ to , $ options ) ; } return $ this ; }

Specifies a single route to match for multiple HTTP Verbs.

Example:
$route->match( ['get', 'post'], 'users/(:num)', 'users/$1);

@param array        $verbs
@param string       $from
@param string|array $to
@param array        $options

@return \CodeIgniter\Router\RouteCollectionInterface

Specifies a single route to match for multiple HTTP Verbs .


public function options(string $from, $to, array $options = null): RouteCollectionInterface
	{
		$this->create('options', $from, $to, $options);

		return $this;
	}

public function options ( string $ from , $ to , array $ options = null ) : RouteCollectionInterface { $ this -> create ( 'options' , $ from , $ to , $ options ) ; return $ this ; }

Specifies a route that is only available to OPTIONS requests.

@param string       $from
@param string|array $to
@param array        $options

@return \CodeIgniter\Router\RouteCollectionInterface

Specifies a route that is only available to OPTIONS requests .


public function environment(string $env, \Closure $callback): RouteCollectionInterface
	{
		if (ENVIRONMENT === $env)
		{
			$callback($this);
		}

		return $this;
	}

public function environment ( string $ env , \ Closure $ callback ) : RouteCollectionInterface { if ( ENVIRONMENT === $ env ) { $ callback ( $ this ) ; } return $ this ; }

Limits the routes to a specified ENVIRONMENT or they won't run.

@param string   $env
@param \Closure $callback

@return RouteCollectionInterface

Limits the routes to a specified ENVIRONMENT or they won t run .


public function reverseRoute(string $search, ...$params)
	{
		// Named routes get higher priority.
		foreach ($this->routes as $verb => $collection)
		{
			if (array_key_exists($search, $collection))
			{
				return $this->fillRouteParams(key($collection[$search]['route']), $params);
			}
		}

		// If it's not a named route, then loop over
		// all routes to find a match.
		foreach ($this->routes as $verb => $collection)
		{
			foreach ($collection as $route)
			{
				$from = key($route['route']);
				$to   = $route['route'][$from];

				// Lose any namespace slash at beginning of strings
				// to ensure more consistent match.
				$to     = ltrim($to, '\\');
				$search = ltrim($search, '\\');

				// If there's any chance of a match, then it will
				// be with $search at the beginning of the $to string.
				if (strpos($to, $search) !== 0)
				{
					continue;
				}

				// Ensure that the number of $params given here
				// matches the number of back-references in the route
				if (substr_count($to, '$') !== count($params))
				{
					continue;
				}

				return $this->fillRouteParams($from, $params);
			}
		}

		// If we're still here, then we did not find a match.
		return false;
	}

Attempts to look up a route based on it's destination.

If a route exists:

'path/(:any)/(:any)' => 'Controller::method/$1/$2'

This method allows you to know the Controller and method
and get the route that leads to it.

// Equals 'path/$param1/$param2'
reverseRoute('Controller::method', $param1, $param2);

@param string $search
@param array  ...$params

@return string|false

Attempts to look up a route based on it s destination .


private function determineCurrentSubdomain()
	{
		// We have to ensure that a scheme exists
		// on the URL else parse_url will mis-interpret
		// 'host' as the 'path'.
		$url = $_SERVER['HTTP_HOST'];
		if (strpos($url, 'http') !== 0)
		{
			$url = 'http://' . $url;
		}

		$parsedUrl = parse_url($url);

		$host = explode('.', $parsedUrl['host']);

		if ($host[0] === 'www')
		{
			unset($host[0]);
		}

		// Get rid of any domains, which will be the last
		unset($host[count($host)]);

		// Account for .co.uk, .co.nz, etc. domains
		if (end($host) === 'co')
		{
			$host = array_slice($host, 0, -1);
		}

		// If we only have 1 part left, then we don't have a sub-domain.
		if (count($host) === 1)
		{
			// Set it to false so we don't make it back here again.
			return false;
		}

		return array_shift($host);
	}

Examines the HTTP_HOST to get a best match for the subdomain. It
won't be perfect, but should work for our needs.

It's especially not perfect since it's possible to register a domain
with a period (.) as part of the domain name.

Examines the HTTP_HOST to get a best match for the subdomain . It won t be perfect but should work for our needs .


public function resetRoutes()
	{
		$this->routes = ['*' => []];
		foreach ($this->defaultHTTPMethods as $verb)
		{
			$this->routes[$verb] = [];
		}
	}

public function resetRoutes ( ) { $ this -> routes = [ '*' => [ ] ] ; foreach ( $ this -> defaultHTTPMethods as $ verb ) { $ this -> routes [ $ verb ] = [ ] ; } }

Reset the routes, so that a FeatureTestCase can provide the
explicit ones needed for it.

Reset the routes so that a FeatureTestCase can provide the explicit ones needed for it .


public function errorHandler(int $severity, string $message, string $file = null, int $line = null, $context = null)
	{
		if (! (error_reporting() & $severity))
		{
			return;
		}

		// Convert it to an exception and pass it along.
		throw new ErrorException($message, 0, $severity, $file, $line);
	}

Even in PHP7, some errors make it through to the errorHandler, so
convert these to Exceptions and let the exception handler log it and
display it.

This seems to be primarily when a user triggers it with trigger_error().

@param integer      $severity
@param string       $message
@param string|null  $file
@param integer|null $line
@param null         $context

@throws \ErrorException

Even in PHP7 some errors make it through to the errorHandler so convert these to Exceptions and let the exception handler log it and display it .


public function shutdownHandler()
	{
		$error = error_get_last();

		// If we've got an error that hasn't been displayed, then convert
		// it to an Exception and use the Exception handler to display it
		// to the user.
		if (! is_null($error))
		{
			// Fatal Error?
			if (in_array($error['type'], [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE]))
			{
				$this->exceptionHandler(new ErrorException($error['message'], $error['type'], 0, $error['file'], $error['line']));
			}
		}
	}

Checks to see if any errors have happened during shutdown that
need to be caught and handle them.

Checks to see if any errors have happened during shutdown that need to be caught and handle them .


protected function determineView(Throwable $exception, string $template_path): string
	{
		// Production environments should have a custom exception file.
		$view          = 'production.php';
		$template_path = rtrim($template_path, '/ ') . '/';

		if (str_ireplace(['off', 'none', 'no', 'false', 'null'], '', ini_get('display_errors')))
		{
			$view = 'error_exception.php';
		}

		// 404 Errors
		if ($exception instanceof PageNotFoundException)
		{
			return 'error_404.php';
		}

		// Allow for custom views based upon the status code
		else if (is_file($template_path . 'error_' . $exception->getCode() . '.php'))
		{
			return 'error_' . $exception->getCode() . '.php';
		}

		return $view;
	}

Determines the view to display based on the exception thrown,
whether an HTTP or CLI request, etc.

@param \Throwable $exception
@param string     $template_path

@return string       The path and filename of the view file to use

Determines the view to display based on the exception thrown whether an HTTP or CLI request etc .


protected function render(Throwable $exception, int $statusCode)
	{
		// Determine directory with views
		$path = $this->viewPath;
		if (empty($path))
		{
			$paths = new Paths();
			$path  = $paths->viewDirectory . '/errors/';
		}

		$path = is_cli()
			? $path . 'cli/'
			: $path . 'html/';

		// Determine the vew
		$view = $this->determineView($exception, $path);

		// Prepare the vars
		$vars = $this->collectVars($exception, $statusCode);
		extract($vars);

		// Render it
		if (ob_get_level() > $this->ob_level + 1)
		{
			ob_end_clean();
		}

		ob_start();
		include($path . $view);
		$buffer = ob_get_contents();
		ob_end_clean();
		echo $buffer;
	}

protected
function
render
(
Throwable
$
exception
,
int
$
statusCode
)
{
// Determine directory with views
$
path
=
$
this
->
viewPath
;
if
(
empty
(
$
path
)
)
{
$
paths
=
new
Paths
(
)
;
$
path
=
$
paths
->
viewDirectory
.
'/errors/'
;
}
$
path
=
is_cli
(
)
$
path
.
'cli/'
:
$
path
.
'html/'
;
// Determine the vew
$
view
=
$
this
->
determineView
(
$
exception
,
$
path
)
;
// Prepare the vars
$
vars
=
$
this
->
collectVars
(
$
exception
,
$
statusCode
)
;
extract
(
$
vars
)
;
// Render it
if
(
ob_get_level
(
)
>
$
this
->
ob_level
+
1
)
{
ob_end_clean
(
)
;
}
ob_start
(
)
;
include
(
$
path
.
$
view
)
;
$
buffer
=
ob_get_contents
(
)
;
ob_end_clean
(
)
;
echo
$
buffer
;
}

Given an exception and status code will display the error to the client.

@param \Throwable $exception
@param integer    $statusCode

Given an exception and status code will display the error to the client .


protected function collectVars(Throwable $exception, int $statusCode): array
	{
		return [
			'title'   => get_class($exception),
			'type'    => get_class($exception),
			'code'    => $statusCode,
			'message' => $exception->getMessage() ?? '(null)',
			'file'    => $exception->getFile(),
			'line'    => $exception->getLine(),
			'trace'   => $exception->getTrace(),
		];
	}

protected function collectVars ( Throwable $ exception , int $ statusCode ) : array { return [ 'title' => get_class ( $ exception ) , 'type' => get_class ( $ exception ) , 'code' => $ statusCode , 'message' => $ exception -> getMessage ( ) ?? '(null)' , 'file' => $ exception -> getFile ( ) , 'line' => $ exception -> getLine ( ) , 'trace' => $ exception -> getTrace ( ) , ] ; }

Gathers the variables that will be made available to the view.

@param \Throwable $exception
@param integer    $statusCode

@return array

Gathers the variables that will be made available to the view .


protected function determineCodes(Throwable $exception): array
	{
		$statusCode = abs($exception->getCode());

		if ($statusCode < 100 || $statusCode > 599)
		{
			$exitStatus = $statusCode + EXIT__AUTO_MIN; // 9 is EXIT__AUTO_MIN
			if ($exitStatus > EXIT__AUTO_MAX) // 125 is EXIT__AUTO_MAX
			{
				$exitStatus = EXIT_ERROR; // EXIT_ERROR
			}
			$statusCode = 500;
		}
		else
		{
			$exitStatus = 1; // EXIT_ERROR
		}

		return [
			$statusCode ?? 500,
			$exitStatus,
		];
	}

protected
function
determineCodes
(
Throwable
$
exception
)
:
array
{
$
statusCode
=
abs
(
$
exception
->
getCode
(
)
)
;
if
(
$
statusCode
<
100
||
$
statusCode
>
599
)
{
$
exitStatus
=
$
statusCode
+
EXIT__AUTO_MIN
;
// 9 is EXIT__AUTO_MIN
if
(
$
exitStatus
>
EXIT__AUTO_MAX
)
// 125 is EXIT__AUTO_MAX
{
$
exitStatus
=
EXIT_ERROR
;
// EXIT_ERROR
}
$
statusCode
=
500
;
}
else
{
$
exitStatus
=
1
;
// EXIT_ERROR
}
return
[
$
statusCode
??
500
,
$
exitStatus
,
]
;
}

Determines the HTTP status code and the exit status code for this request.

@param \Throwable $exception

@return array

Determines the HTTP status code and the exit status code for this request .


public static function describeMemory(int $bytes): string
	{
		if ($bytes < 1024)
		{
			return $bytes . 'B';
		}
		else if ($bytes < 1048576)
		{
			return round($bytes / 1024, 2) . 'KB';
		}

		return round($bytes / 1048576, 2) . 'MB';
	}

public static function describeMemory ( int $ bytes ) : string { if ( $ bytes < 1024 ) { return $ bytes . 'B' ; } else if ( $ bytes < 1048576 ) { return round ( $ bytes / 1024 , 2 ) . 'KB' ; } return round ( $ bytes / 1048576 , 2 ) . 'MB' ; }

Describes memory usage in real-world units. Intended for use
with memory_get_usage, etc.

@param $bytes

@return string

Describes memory usage in real - world units . Intended for use with memory_get_usage etc .


public static function highlightFile(string $file, int $lineNumber, int $lines = 15)
	{
		if (empty($file) || ! is_readable($file))
		{
			return false;
		}

		// Set our highlight colors:
		if (function_exists('ini_set'))
		{
			ini_set('highlight.comment', '#767a7e; font-style: italic');
			ini_set('highlight.default', '#c7c7c7');
			ini_set('highlight.html', '#06B');
			ini_set('highlight.keyword', '#f1ce61;');
			ini_set('highlight.string', '#869d6a');
		}

		try
		{
			$source = file_get_contents($file);
		}
		catch (Throwable $e)
		{
			return false;
		}

		$source = str_replace(["\r\n", "\r"], "\n", $source);
		$source = explode("\n", highlight_string($source, true));
		$source = str_replace('
', "\n", $source[1]);

		$source = explode("\n", str_replace("\r\n", "\n", $source));

		// Get just the part to show
		$start = $lineNumber - (int) round($lines / 2);
		$start = $start < 0 ? 0 : $start;

		// Get just the lines we need to display, while keeping line numbers...
		$source = array_splice($source, $start, $lines, true);

		// Used to format the line number in the source
		$format = '% ' . strlen($start + $lines) . 'd';

		$out = '';
		// Because the highlighting may have an uneven number
		// of open and close span tags on one line, we need
		// to ensure we can close them all to get the lines
		// showing correctly.
		$spans = 1;

		foreach ($source as $n => $row)
		{
			$spans += substr_count($row, '<span') - substr_count($row, '</span');
			$row    = str_replace(["\r", "\n"], ['', ''], $row);

			if (($n + $start + 1) === $lineNumber)
			{
				preg_match_all('#<[^>]+>#', $row, $tags);
				$out .= sprintf("{$format} %s\n%s", $n + $start + 1, strip_tags($row), implode('', $tags[0])
				);
			}
			else
			{
				$out .= sprintf('' . $format . ' %s', $n + $start + 1, $row) . "\n";
			}
		}

		if ($spans > 0)
		{
			$out .= str_repeat('', $spans);
		}

		return '
' . $out . '
';
	}

Creates a syntax-highlighted version of a PHP file.

@param string  $file
@param integer $lineNumber
@param integer $lines

@return boolean|string

Creates a syntax - highlighted version of a PHP file .


public function alpha_space(string $value = null): bool
	{
		if ($value === null)
		{
			return true;
		}

		return (bool) preg_match('/^[A-Z ]+$/i', $value);
	}

public
function
alpha_space
(
string
$
value
=
)
:
bool
{
if
(
$
value
===
)
{
return
true
;
}
return
(
bool
)
preg_match
(
'/^[A-Z ]+$/i'
,
$
value
)
;
}

Alpha with spaces.

@param string $value Value.

@return boolean True if alpha with spaces, else false.


public function regex_match(string $str = null, string $pattern, array $data): bool
	{
		if (strpos($pattern, '/') !== 0)
		{
			$pattern = "/{$pattern}/";
		}

		return (bool) preg_match($pattern, $str);
	}

public function regex_match ( string $ str = null , string $ pattern , array $ data ) : bool { if ( strpos ( $ pattern , '/' ) !== 0 ) { $ pattern = "/{$pattern}/" ; } return ( bool ) preg_match ( $ pattern , $ str ) ; }

Compares value against a regular expression pattern.

@param string $str
@param string $pattern
@param array  $data    Other field/value pairs

@return boolean

Compares value against a regular expression pattern .


public function valid_email(string $str = null): bool
	{
		if (function_exists('idn_to_ascii') && defined('INTL_IDNA_VARIANT_UTS46') && preg_match('#\A([^@]+)@(.+)\z#', $str, $matches))
		{
			$str = $matches[1] . '@' . idn_to_ascii($matches[2], 0, INTL_IDNA_VARIANT_UTS46);
		}

		return (bool) filter_var($str, FILTER_VALIDATE_EMAIL);
	}

public function valid_email ( string $ str = null ) : bool { if ( function_exists ( 'idn_to_ascii' ) && defined ( 'INTL_IDNA_VARIANT_UTS46' ) && preg_match ( '#\A([^@]+)@(.+)\z#' , $ str , $ matches ) ) { $ str = $ matches [ 1 ] . '@' . idn_to_ascii ( $ matches [ 2 ] , 0 , INTL_IDNA_VARIANT_UTS46 ) ; } return ( bool ) filter_var ( $ str , FILTER_VALIDATE_EMAIL ) ; }

Checks for a correctly formatted email address

@param string

@return boolean


public function valid_emails(string $str = null): bool
	{
		foreach (explode(',', $str) as $email)
		{
			$email = trim($email);
			if ($email === '')
			{
				return false;
			}

			if ($this->valid_email($email) === false)
			{
				return false;
			}
		}

		return true;
	}

public function valid_emails ( string $ str = null ) : bool { foreach ( explode ( ',' , $ str ) as $ email ) { $ email = trim ( $ email ) ; if ( $ email === '' ) { return false ; } if ( $ this -> valid_email ( $ email ) === false ) { return false ; } } return true ; }

Validate a comma-separated list of email addresses.

Example:
valid_emails[one@example.com,two@example.com]

@param string

@return boolean

Validate a comma - separated list of email addresses .


public function valid_url(string $str = null): bool
	{
		if (empty($str))
		{
			return false;
		}
		elseif (preg_match('/^(?:([^:]*)\:)?\/\/(.+)$/', $str, $matches))
		{
			if (! in_array($matches[1], ['http', 'https'], true))
			{
				return false;
			}

			$str = $matches[2];
		}

		$str = 'http://' . $str;

		return (filter_var($str, FILTER_VALIDATE_URL) !== false);
	}

public function valid_url ( string $ str = null ) : bool { if ( empty ( $ str ) ) { return false ; } elseif ( preg_match ( '/^(?:([^:]*)\:)?\/\/(.+)$/' , $ str , $ matches ) ) { if ( ! in_array ( $ matches [ 1 ] , [ 'http' , 'https' ] , true ) ) { return false ; } $ str = $ matches [ 2 ] ; } $ str = 'http://' . $ str ; return ( filter_var ( $ str , FILTER_VALIDATE_URL ) !== false ) ; }

Checks a URL to ensure it's formed correctly.

@param string $str

@return boolean

Checks a URL to ensure it s formed correctly .


public function valid_date(string $str = null, string $format = null): bool
	{
		if (empty($format))
		{
			return (bool) strtotime($str);
		}

		$date = \DateTime::createFromFormat($format, $str);

		return (bool) $date && \DateTime::getLastErrors()['warning_count'] === 0 && \DateTime::getLastErrors()['error_count'] === 0;
	}

public function valid_date ( string $ str = null , string $ format = null ) : bool { if ( empty ( $ format ) ) { return ( bool ) strtotime ( $ str ) ; } $ date = \ DateTime :: createFromFormat ( $ format , $ str ) ; return ( bool ) $ date && \ DateTime :: getLastErrors ( ) [ 'warning_count' ] === 0 && \ DateTime :: getLastErrors ( ) [ 'error_count' ] === 0 ; }

Checks for a valid date and matches a given date format

@param string $str
@param string $format

@return boolean


public static function forMoveFailed(string $source, string $target, string $error)
	{
		return new static(lang('HTTP.moveFailed', [$source, $target, $error]));
	}

public static function forMoveFailed ( string $ source , string $ target , string $ error ) { return new static ( lang ( 'HTTP.moveFailed' , [ $ source , $ target , $ error ] ) ) ; }

For Uploaded file move

@return \CodeIgniter\HTTP\Exceptions\HTTPException


public function valid_cc_number(string $ccNumber = null, string $type, array $data): bool
	{
		$type = strtolower($type);
		$info = null;

		// Get our card info based on provided name.
		foreach ($this->cards as $card)
		{
			if ($card['name'] === $type)
			{
				$info = $card;
				break;
			}
		}

		// If empty, it's not a card type we recognize, or invalid type.
		if (empty($info))
		{
			return false;
		}

		// Make sure we have a valid length
		if (strlen($ccNumber) === 0)
		{
			return false;
		}

		// Remove any spaces and dashes
		$ccNumber = str_replace([' ', '-'], '', $ccNumber);

		// Non-numeric values cannot be a number...duh
		if (! is_numeric($ccNumber))
		{
			return false;
		}

		// Make sure it's a valid length for this card
		$lengths = explode(',', $info['length']);

		if (! in_array(strlen($ccNumber), $lengths))
		{
			return false;
		}

		// Make sure it has a valid prefix
		$prefixes = explode(',', $info['prefixes']);

		$validPrefix = false;

		foreach ($prefixes as $prefix)
		{
			if (strpos($ccNumber, $prefix) === 0)
			{
							  $validPrefix = true;
							  break;
			}
		}

		if ($validPrefix === false)
		{
			return false;
		}

		// Still here? Then check the number against the Luhn algorithm, if required
		// @see https://en.wikipedia.org/wiki/Luhn_algorithm
		// @see https://gist.github.com/troelskn/1287893
		if ($info['checkdigit'] === true)
		{
			return $this->isValidLuhn($ccNumber);
		}

		return true;
	}

Verifies that a credit card number is valid and matches the known
formats for a wide number of credit card types. This does not verify
that the card is a valid card, only that the number is formatted correctly.

Example:
$rules = [
'cc_num' => 'valid_cc_number[visa]'
];

@param string $ccNumber
@param string $type
@param array  $data

@return boolean

Verifies that a credit card number is valid and matches the known formats for a wide number of credit card types . This does not verify that the card is a valid card only that the number is formatted correctly .


protected function isValidLuhn(string $number = null): bool
	{
		settype($number, 'string');

		$sumTable = [
			[
				0,
				1,
				2,
				3,
				4,
				5,
				6,
				7,
				8,
				9,
			],
			[
				0,
				2,
				4,
				6,
				8,
				1,
				3,
				5,
				7,
				9,
			],
		];

		$sum  = 0;
		$flip = 0;

		for ($i = strlen($number) - 1; $i >= 0; $i --)
		{
			$sum += $sumTable[$flip ++ & 0x1][$number[$i]];
		}

		return $sum % 10 === 0;
	}

protected function isValidLuhn ( string $ number = null ) : bool { settype ( $ number , 'string' ) ; $ sumTable = [ [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , ] , [ 0 , 2 , 4 , 6 , 8 , 1 , 3 , 5 , 7 , 9 , ] , ] ; $ sum = 0 ; $ flip = 0 ; for ( $ i = strlen ( $ number ) - 1 ; $ i >= 0 ; $ i -- ) { $ sum += $ sumTable [ $ flip ++ & 0x1 ] [ $ number [ $ i ] ] ; } return $ sum % 10 === 0 ; }

Checks the given number to see if the number passing a Luhn check.

@param string $number

@return boolean

Checks the given number to see if the number passing a Luhn check .


protected static function moveFile(string $source, string $destination): bool
	{
		$source = realpath($source);

		if (empty($source))
		{
			die('Cannot move file. Source path invalid.');
		}

		if (! is_file($source))
		{
			return false;
		}

		return copy($source, $destination);
	}

Move a file.

@param string $source
@param string $destination

@return boolean


public static function moveEscaper()
	{
		if (class_exists('\\Zend\\Escaper\\Escaper') && is_file(static::getClassFilePath('\\Zend\\Escaper\\Escaper')))
		{
			$base = basename(__DIR__) . '/' . static::$basePath . 'ZendEscaper';

			foreach ([$base, $base . '/Exception'] as $path)
			{
				if (! is_dir($path))
				{
					mkdir($path, 0755);
				}
			}

			$files = [
				static::getClassFilePath('\\Zend\\Escaper\\Exception\\ExceptionInterface')       => $base . '/Exception/ExceptionInterface.php',
				static::getClassFilePath('\\Zend\\Escaper\\Exception\\InvalidArgumentException') => $base . '/Exception/InvalidArgumentException.php',
				static::getClassFilePath('\\Zend\\Escaper\\Exception\\RuntimeException')         => $base . '/Exception/RuntimeException.php',
				static::getClassFilePath('\\Zend\\Escaper\\Escaper')                             => $base . '/Escaper.php',
			];

			foreach ($files as $source => $dest)
			{
				if (! static::moveFile($source, $dest))
				{
					die('Error moving: ' . $source);
				}
			}
		}
	}

Moves the Zend Escaper files into our base repo so that it's
available for packaged releases where the users don't user Composer.

@throws \ReflectionException

Moves the Zend Escaper files into our base repo so that it s available for packaged releases where the users don t user Composer .


public static function moveKint()
	{
		$filename = 'vendor/kint-php/kint/build/kint-aante-light.php';

		if (is_file($filename))
		{
			$base = basename(__DIR__) . '/' . static::$basePath . 'Kint';

			// Remove the contents of the previous Kint folder, if any.
			if (is_dir($base))
			{
				static::removeDir($base);
			}

			// Create Kint if it doesn't exist already
			if (! is_dir($base))
			{
				mkdir($base, 0755);
			}

			if (! static::moveFile($filename, $base . '/kint.php'))
			{
				die('Error moving: ' . $filename);
			}
		}
	}

Moves the Kint file into our base repo so that it's
available for packaged releases where the users don't user Composer.

Moves the Kint file into our base repo so that it s available for packaged releases where the users don t user Composer .


public function start()
	{
		if (is_cli() && ENVIRONMENT !== 'testing')
		{
			$this->logger->debug('Session: Initialization under CLI aborted.');

			return;
		}
		elseif ((bool) ini_get('session.auto_start'))
		{
			$this->logger->error('Session: session.auto_start is enabled in php.ini. Aborting.');

			return;
		}
		elseif (session_status() === PHP_SESSION_ACTIVE)
		{
			$this->logger->warning('Session: Sessions is enabled, and one exists.Please don\'t $session->start();');

			return;
		}

		if (! $this->driver instanceof \SessionHandlerInterface)
		{
			$this->logger->error("Session: Handler '" . $this->driver .
					"' doesn't implement SessionHandlerInterface. Aborting.");
		}

		$this->configure();

		$this->setSaveHandler();

		// Sanitize the cookie, because apparently PHP doesn't do that for userspace handlers
		if (isset($_COOKIE[$this->sessionCookieName]) && (
				! is_string($_COOKIE[$this->sessionCookieName]) || ! preg_match('#\A' . $this->sidRegexp . '\z#', $_COOKIE[$this->sessionCookieName])
				)
		)
		{
			unset($_COOKIE[$this->sessionCookieName]);
		}

		$this->startSession();

		// Is session ID auto-regeneration configured? (ignoring ajax requests)
		if ((empty($_SERVER['HTTP_X_REQUESTED_WITH']) ||
				strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) !== 'xmlhttprequest') && ($regenerate_time = $this->sessionTimeToUpdate) > 0
		)
		{
			if (! isset($_SESSION['__ci_last_regenerate']))
			{
				$_SESSION['__ci_last_regenerate'] = time();
			}
			elseif ($_SESSION['__ci_last_regenerate'] < (time() - $regenerate_time))
			{
				$this->regenerate((bool) $this->sessionRegenerateDestroy);
			}
		}
		// Another work-around ... PHP doesn't seem to send the session cookie
		// unless it is being currently created or regenerated
		elseif (isset($_COOKIE[$this->sessionCookieName]) && $_COOKIE[$this->sessionCookieName] === session_id())
		{
			$this->setCookie();
		}

		$this->initVars();

		$this->logger->info("Session: Class initialized using '" . $this->sessionDriverName . "' driver.");

		return $this;
	}

Initialize the session container and starts up the session.

@return mixed

Initialize the session container and starts up the session .


protected function configureSidLength()
	{
		$bits_per_character = (int) (ini_get('session.sid_bits_per_character') !== false
			? ini_get('session.sid_bits_per_character')
			: 4);
		$sid_length         = (int) (ini_get('session.sid_length') !== false
			? ini_get('session.sid_length')
			: 40);
		if (($sid_length * $bits_per_character) < 160)
		{
			$bits = ($sid_length * $bits_per_character);
			// Add as many more characters as necessary to reach at least 160 bits
			$sid_length += (int) ceil((160 % $bits) / $bits_per_character);
			ini_set('session.sid_length', $sid_length);
		}

		// Yes, 4,5,6 are the only known possible values as of 2016-10-27
		switch ($bits_per_character)
		{
			case 4:
				$this->sidRegexp = '[0-9a-f]';
				break;
			case 5:
				$this->sidRegexp = '[0-9a-v]';
				break;
			case 6:
				$this->sidRegexp = '[0-9a-zA-Z,-]';
				break;
		}

		$this->sidRegexp .= '{' . $sid_length . '}';
	}

Configure session ID length

To make life easier, we used to force SHA-1 and 4 bits per
character on everyone. And of course, someone was unhappy.

Then PHP 7.1 broke backwards-compatibility because ext/session
is such a mess that nobody wants to touch it with a pole stick,
and the one guy who does, nobody has the energy to argue with.

So we were forced to make changes, and OF COURSE something was
going to break and now we have this pile of shit. -- Narf

@return void


protected function initVars()
	{
		if (empty($_SESSION['__ci_vars']))
		{
			return;
		}

		$current_time = time();

		foreach ($_SESSION['__ci_vars'] as $key => &$value)
		{
			if ($value === 'new')
			{
				$_SESSION['__ci_vars'][$key] = 'old';
			}
			// Hacky, but 'old' will (implicitly) always be less than time() ;)
			// DO NOT move this above the 'new' check!
			elseif ($value < $current_time)
			{
				unset($_SESSION[$key], $_SESSION['__ci_vars'][$key]);
			}
		}

		if (empty($_SESSION['__ci_vars']))
		{
			unset($_SESSION['__ci_vars']);
		}
	}

Handle temporary variables

Clears old "flash" data, marks the new one for deletion and handles
"temp" data deletion.


public function set($data, $value = null)
	{
		if (is_array($data))
		{
			foreach ($data as $key => &$value)
			{
				if (is_int($key))
				{
					$_SESSION[$value] = null;
				}
				else
				{
					$_SESSION[$key] = $value;
				}
			}

			return;
		}

		$_SESSION[$data] = $value;
	}

public function set ( $ data , $ value = null ) { if ( is_array ( $ data ) ) { foreach ( $ data as $ key => & $ value ) { if ( is_int ( $ key ) ) { $ _SESSION [ $ value ] = null ; } else { $ _SESSION [ $ key ] = $ value ; } } return ; } $ _SESSION [ $ data ] = $ value ; }

Sets user data into the session.

If $data is a string, then it is interpreted as a session property
key, and  $value is expected to be non-null.

If $data is an array, it is expected to be an array of key/value pairs
to be set as session properties.

@param string|array $data  Property name or associative array of properties
@param string|array $value Property value if single key provided


public function get(string $key = null)
	{
		if (! empty($key) && $value = dot_array_search($key, $_SESSION))
		{
			return $value;
		}
		elseif (empty($_SESSION))
		{
			return [];
		}

		if (! empty($key))
		{
			return null;
		}

		$userdata = [];
		$_exclude = array_merge(
			['__ci_vars'], $this->getFlashKeys(), $this->getTempKeys()
		);

		$keys = array_keys($_SESSION);
		foreach ($keys as $key)
		{
			if (! in_array($key, $_exclude, true))
			{
				$userdata[$key] = $_SESSION[$key];
			}
		}

		return $userdata;
	}

public function get ( string $ key = null ) { if ( ! empty ( $ key ) && $ value = dot_array_search ( $ key , $ _SESSION ) ) { return $ value ; } elseif ( empty ( $ _SESSION ) ) { return [ ] ; } if ( ! empty ( $ key ) ) { return null ; } $ userdata = [ ] ; $ _exclude = array_merge ( [ '__ci_vars' ] , $ this -> getFlashKeys ( ) , $ this -> getTempKeys ( ) ) ; $ keys = array_keys ( $ _SESSION ) ; foreach ( $ keys as $ key ) { if ( ! in_array ( $ key , $ _exclude , true ) ) { $ userdata [ $ key ] = $ _SESSION [ $ key ] ; } } return $ userdata ; }

Get user data that has been set in the session.

If the property exists as "normal", returns it.
Otherwise, returns an array of any temp or flash data values with the
property key.

Replaces the legacy method $session->userdata();

@param  string $key Identifier of the session property to retrieve
@return array|null	The property value(s)

Get user data that has been set in the session .


public function push(string $key, array $data)
	{
		if ($this->has($key) && is_array($value = $this->get($key)))
			   {
			$this->set($key, array_merge($value, $data));
		}
	}

public function push ( string $ key , array $ data ) { if ( $ this -> has ( $ key ) && is_array ( $ value = $ this -> get ( $ key ) ) ) { $ this -> set ( $ key , array_merge ( $ value , $ data ) ) ; } }

Push new value onto session value that is array.

@param string $key  Identifier of the session property we are interested in.
@param array  $data value to be pushed to existing session key.

@return void

Push new value onto session value that is array .


public function remove($key)
	{
		if (is_array($key))
		{
			foreach ($key as $k)
			{
				unset($_SESSION[$k]);
			}

			return;
		}

		unset($_SESSION[$key]);
	}

public function remove ( $ key ) { if ( is_array ( $ key ) ) { foreach ( $ key as $ k ) { unset ( $ _SESSION [ $ k ] ) ; } return ; } unset ( $ _SESSION [ $ key ] ) ; }

Remove one or more session properties.

If $key is an array, it is interpreted as an array of string property
identifiers to remove. Otherwise, it is interpreted as the identifier
of a specific session property to remove.

@param string|array $key Identifier of the session property or properties to remove.


public function setFlashdata($data, $value = null)
	{
		$this->set($data, $value);
		$this->markAsFlashdata(is_array($data) ? array_keys($data) : $data);
	}

public function setFlashdata ( $ data , $ value = null ) { $ this -> set ( $ data , $ value ) ; $ this -> markAsFlashdata ( is_array ( $ data ) ? array_keys ( $ data ) : $ data ) ; }

Sets data into the session that will only last for a single request.
Perfect for use with single-use status update messages.

If $data is an array, it is interpreted as an associative array of
key/value pairs for flashdata properties.
Otherwise, it is interpreted as the identifier of a specific
flashdata property, with $value containing the property value.

@param array|string $data  Property identifier or associative array of properties
@param string|array $value Property value if $data is a scalar

Sets data into the session that will only last for a single request . Perfect for use with single - use status update messages .


public function getFlashdata(string $key = null)
	{
		if (isset($key))
		{
			return (isset($_SESSION['__ci_vars'], $_SESSION['__ci_vars'][$key], $_SESSION[$key]) &&
					! is_int($_SESSION['__ci_vars'][$key])) ? $_SESSION[$key] : null;
		}

		$flashdata = [];

		if (! empty($_SESSION['__ci_vars']))
		{
			foreach ($_SESSION['__ci_vars'] as $key => &$value)
			{
				is_int($value) || $flashdata[$key] = $_SESSION[$key];
			}
		}

		return $flashdata;
	}

public function getFlashdata ( string $ key = null ) { if ( isset ( $ key ) ) { return ( isset ( $ _SESSION [ '__ci_vars' ] , $ _SESSION [ '__ci_vars' ] [ $ key ] , $ _SESSION [ $ key ] ) && ! is_int ( $ _SESSION [ '__ci_vars' ] [ $ key ] ) ) ? $ _SESSION [ $ key ] : null ; } $ flashdata = [ ] ; if ( ! empty ( $ _SESSION [ '__ci_vars' ] ) ) { foreach ( $ _SESSION [ '__ci_vars' ] as $ key => & $ value ) { is_int ( $ value ) || $ flashdata [ $ key ] = $ _SESSION [ $ key ] ; } } return $ flashdata ; }

Retrieve one or more items of flash data from the session.

If the item key is null, return all flashdata.

@param  string $key Property identifier
@return array|null	The requested property value, or an associative array  of them

Retrieve one or more items of flash data from the session .


public function markAsFlashdata($key): bool
	{
		if (is_array($key))
		{
			for ($i = 0, $c = count($key); $i < $c; $i ++)
			{
				if (! isset($_SESSION[$key[$i]]))
				{
					return false;
				}
			}

			$new = array_fill_keys($key, 'new');

			$_SESSION['__ci_vars'] = isset($_SESSION['__ci_vars']) ? array_merge($_SESSION['__ci_vars'], $new) : $new;

			return true;
		}

		if (! isset($_SESSION[$key]))
		{
			return false;
		}

		$_SESSION['__ci_vars'][$key] = 'new';

		return true;
	}

public function markAsFlashdata ( $ key ) : bool { if ( is_array ( $ key ) ) { for ( $ i = 0 , $ c = count ( $ key ) ; $ i < $ c ; $ i ++ ) { if ( ! isset ( $ _SESSION [ $ key [ $ i ] ] ) ) { return false ; } } $ new = array_fill_keys ( $ key , 'new' ) ; $ _SESSION [ '__ci_vars' ] = isset ( $ _SESSION [ '__ci_vars' ] ) ? array_merge ( $ _SESSION [ '__ci_vars' ] , $ new ) : $ new ; return true ; } if ( ! isset ( $ _SESSION [ $ key ] ) ) { return false ; } $ _SESSION [ '__ci_vars' ] [ $ key ] = 'new' ; return true ; }

Mark a session property or properties as flashdata.

@param array|string $key Property identifier or array of them

@return boolean False if any of the properties are not already set

Mark a session property or properties as flashdata .


public function getFlashKeys(): array
	{
		if (! isset($_SESSION['__ci_vars']))
		{
			return [];
		}

		$keys = [];
		foreach (array_keys($_SESSION['__ci_vars']) as $key)
		{
			is_int($_SESSION['__ci_vars'][$key]) || $keys[] = $key;
		}

		return $keys;
	}

public function getFlashKeys ( ) : array { if ( ! isset ( $ _SESSION [ '__ci_vars' ] ) ) { return [ ] ; } $ keys = [ ] ; foreach ( array_keys ( $ _SESSION [ '__ci_vars' ] ) as $ key ) { is_int ( $ _SESSION [ '__ci_vars' ] [ $ key ] ) || $ keys [ ] = $ key ; } return $ keys ; }

Retrieve all of the keys for session data marked as flashdata.

@return array	The property names of all flashdata

Retrieve all of the keys for session data marked as flashdata .


public function setTempdata($data, $value = null, int $ttl = 300)
	{
		$this->set($data, $value);
		$this->markAsTempdata($data, $ttl);
	}

public function setTempdata ( $ data , $ value = null , int $ ttl = 300 ) { $ this -> set ( $ data , $ value ) ; $ this -> markAsTempdata ( $ data , $ ttl ) ; }

Sets new data into the session, and marks it as temporary data
with a set lifespan.

@param string|array $data  Session data key or associative array of items
@param null         $value Value to store
@param integer      $ttl   Time-to-live in seconds

Sets new data into the session and marks it as temporary data with a set lifespan .


public function getTempdata(string $key = null)
	{
		if (isset($key))
		{
			return (isset($_SESSION['__ci_vars'], $_SESSION['__ci_vars'][$key], $_SESSION[$key]) &&
					is_int($_SESSION['__ci_vars'][$key])) ? $_SESSION[$key] : null;
		}

		$tempdata = [];

		if (! empty($_SESSION['__ci_vars']))
		{
			foreach ($_SESSION['__ci_vars'] as $key => &$value)
			{
				is_int($value) && $tempdata[$key] = $_SESSION[$key];
			}
		}

		return $tempdata;
	}

public function getTempdata ( string $ key = null ) { if ( isset ( $ key ) ) { return ( isset ( $ _SESSION [ '__ci_vars' ] , $ _SESSION [ '__ci_vars' ] [ $ key ] , $ _SESSION [ $ key ] ) && is_int ( $ _SESSION [ '__ci_vars' ] [ $ key ] ) ) ? $ _SESSION [ $ key ] : null ; } $ tempdata = [ ] ; if ( ! empty ( $ _SESSION [ '__ci_vars' ] ) ) { foreach ( $ _SESSION [ '__ci_vars' ] as $ key => & $ value ) { is_int ( $ value ) && $ tempdata [ $ key ] = $ _SESSION [ $ key ] ; } } return $ tempdata ; }

Returns either a single piece of tempdata, or all temp data currently
in the session.

@param  string   $key   Session data key
@return mixed  Session data value or null if not found.

Returns either a single piece of tempdata or all temp data currently in the session .


public function markAsTempdata($key, int $ttl = 300): bool
	{
		$ttl += time();

		if (is_array($key))
		{
			$temp = [];

			foreach ($key as $k => $v)
			{
				// Do we have a key => ttl pair, or just a key?
				if (is_int($k))
				{
					$k = $v;
					$v = $ttl;
				}
				elseif (is_string($v))
				{
					$v = time() + $ttl;
				}
				else
				{
					$v += time();
				}

				if (! array_key_exists($k, $_SESSION))
				{
					return false;
				}

				$temp[$k] = $v;
			}

			$_SESSION['__ci_vars'] = isset($_SESSION['__ci_vars']) ? array_merge($_SESSION['__ci_vars'], $temp) : $temp;

			return true;
		}

		if (! isset($_SESSION[$key]))
		{
			return false;
		}

		$_SESSION['__ci_vars'][$key] = $ttl;

		return true;
	}

Mark one of more pieces of data as being temporary, meaning that
it has a set lifespan within the session.

@param string|array $key Property identifier or array of them
@param integer      $ttl Time to live, in seconds

@return boolean    False if any of the properties were not set

Mark one of more pieces of data as being temporary meaning that it has a set lifespan within the session .


public function unmarkTempdata($key)
	{
		if (empty($_SESSION['__ci_vars']))
		{
			return;
		}

		is_array($key) || $key = [$key];

		foreach ($key as $k)
		{
			if (isset($_SESSION['__ci_vars'][$k]) && is_int($_SESSION['__ci_vars'][$k]))
			{
				unset($_SESSION['__ci_vars'][$k]);
			}
		}

		if (empty($_SESSION['__ci_vars']))
		{
			unset($_SESSION['__ci_vars']);
		}
	}

public function unmarkTempdata ( $ key ) { if ( empty ( $ _SESSION [ '__ci_vars' ] ) ) { return ; } is_array ( $ key ) || $ key = [ $ key ] ; foreach ( $ key as $ k ) { if ( isset ( $ _SESSION [ '__ci_vars' ] [ $ k ] ) && is_int ( $ _SESSION [ '__ci_vars' ] [ $ k ] ) ) { unset ( $ _SESSION [ '__ci_vars' ] [ $ k ] ) ; } } if ( empty ( $ _SESSION [ '__ci_vars' ] ) ) { unset ( $ _SESSION [ '__ci_vars' ] ) ; } }

Unmarks temporary data in the session, effectively removing its
lifespan and allowing it to live as long as the session does.

@param string|array $key	Property identifier or array of them

Unmarks temporary data in the session effectively removing its lifespan and allowing it to live as long as the session does .


public function getTempKeys(): array
	{
		if (! isset($_SESSION['__ci_vars']))
		{
			return [];
		}

		$keys = [];
		foreach (array_keys($_SESSION['__ci_vars']) as $key)
		{
			is_int($_SESSION['__ci_vars'][$key]) && $keys[] = $key;
		}

		return $keys;
	}

public function getTempKeys ( ) : array { if ( ! isset ( $ _SESSION [ '__ci_vars' ] ) ) { return [ ] ; } $ keys = [ ] ; foreach ( array_keys ( $ _SESSION [ '__ci_vars' ] ) as $ key ) { is_int ( $ _SESSION [ '__ci_vars' ] [ $ key ] ) && $ keys [ ] = $ key ; } return $ keys ; }

Retrieve the keys of all session data that have been marked as temporary data.

@return array

Retrieve the keys of all session data that have been marked as temporary data .


protected function setCookie()
	{
		setcookie(
				$this->sessionCookieName, session_id(), (empty($this->sessionExpiration) ? 0 : time() + $this->sessionExpiration), $this->cookiePath, $this->cookieDomain, $this->cookieSecure, true
		);
	}

protected function setCookie ( ) { setcookie ( $ this -> sessionCookieName , session_id ( ) , ( empty ( $ this -> sessionExpiration ) ? 0 : time ( ) + $ this -> sessionExpiration ) , $ this -> cookiePath , $ this -> cookieDomain , $ this -> cookieSecure , true ) ; }

Takes care of setting the cookie on the client side.
Extracted for testing reasons.

Takes care of setting the cookie on the client side . Extracted for testing reasons .


public function check(string $key, int $capacity, int $seconds, int $cost = 1): bool
	{
		$tokenName = $this->prefix . $key;

		// Check to see if the bucket has even been created yet.
		if (($tokens = $this->cache->get($tokenName)) === false)
		{
			// If it hasn't been created, then we'll set it to the maximum
			// capacity - 1, and save it to the cache.
			$this->cache->save($tokenName, $capacity - $cost, $seconds);
			$this->cache->save($tokenName . 'Time', time());

			return true;
		}

		// If $tokens > 0, then we need to replenish the bucket
		// based on how long it's been since the last update.
		$throttleTime = $this->cache->get($tokenName . 'Time');
		$elapsed      = $this->time() - $throttleTime;
		// Number of tokens to add back per second
		$rate = $capacity / $seconds;

		// We must have a minimum wait of 1 second for a new token
		// Primarily stored to allow devs to report back to users.
		$this->tokenTime = max(1, $rate);

		// Add tokens based up on number per second that
		// should be refilled, then checked against capacity
		// to be sure the bucket didn't overflow.
		$tokens += $rate * $elapsed;
		$tokens  = $tokens > $capacity ? $capacity : $tokens;

		// If $tokens > 0, then we are save to perform the action, but
		// we need to decrement the number of available tokens.
		$response = false;

		if ($tokens > 0)
		{
			$response = true;

			$this->cache->save($tokenName, $tokens - $cost, $elapsed);
			$this->cache->save($tokenName . 'Time', time());
		}

		return $response;
	}

Restricts the number of requests made by a single IP address within
a set number of seconds.

Example:

if (! $throttler->check($request->ipAddress(), 60, MINUTE))
{
die('You submitted over 60 requests within a minute.');
}

@param string  $key      The name to use as the "bucket" name.
@param integer $capacity The number of requests the "bucket" can hold
@param integer $seconds  The time it takes the "bucket" to completely refill
@param integer $cost     The number of tokens this action uses.

@return   boolean
@internal param int $maxRequests

Restricts the number of requests made by a single IP address within a set number of seconds .


public static function guessTypeFromExtension(string $extension)
	{
		$extension = trim(strtolower($extension), '. ');

		if (! array_key_exists($extension, static::$mimes))
		{
			return null;
		}

		return is_array(static::$mimes[$extension]) ? static::$mimes[$extension][0] : static::$mimes[$extension];
	}

public
static
function
guessTypeFromExtension
(
string
$
extension
)
{
$
extension
=
trim
(
strtolower
(
$
extension
)
,
'. '
)
;
if
(
!
array_key_exists
(
$
extension
,
static
::
$
mimes
)
)
{
return
;
}
return
is_array
(
static
::
$
mimes
[
$
extension
]
)
static
::
$
mimes
[
$
extension
]
[
0
]
:
static
::
$
mimes
[
$
extension
]
;
}

Attempts to determine the best mime type for the given file extension.

@param string $extension

@return string|null The mime type found, or none if unable to determine.

Attempts to determine the best mime type for the given file extension .


public static function guessExtensionFromType(string $type, ?string $proposed_extension = null)
	{
		$type = trim(strtolower($type), '. ');

		$proposed_extension = trim(strtolower($proposed_extension));

		if (! is_null($proposed_extension) && array_key_exists($proposed_extension, static::$mimes) && in_array($type, is_string(static::$mimes[$proposed_extension]) ? [static::$mimes[$proposed_extension]] : static::$mimes[$proposed_extension]))
		{
			return $proposed_extension;
		}

		foreach (static::$mimes as $ext => $types)
		{
			if (is_string($types) && $types === $type)
			{
				return $ext;
			}
			else if (is_array($types) && in_array($type, $types))
			{
				return $ext;
			}
		}

		return null;
	}

public
static
function
guessExtensionFromType
(
string
$
type
,
string
$
proposed_extension
=
)
{
$
type
=
trim
(
strtolower
(
$
type
)
,
'. '
)
;
$
proposed_extension
=
trim
(
strtolower
(
$
proposed_extension
)
)
;
if
(
!
is_null
(
$
proposed_extension
)
&&
array_key_exists
(
$
proposed_extension
,
static
::
$
mimes
)
&&
in_array
(
$
type
,
is_string
(
static
::
$
mimes
[
$
proposed_extension
]
)
[
static
::
$
mimes
[
$
proposed_extension
]
]
:
static
::
$
mimes
[
$
proposed_extension
]
)
)
{
return
$
proposed_extension
;
}
foreach
(
static
::
$
mimes
as
$
ext
=>
$
types
)
{
if
(
is_string
(
$
types
)
&&
$
types
===
$
type
)
{
return
$
ext
;
}
else
if
(
is_array
(
$
types
)
&&
in_array
(
$
type
,
$
types
)
)
{
return
$
ext
;
}
}
return
;
}

Attempts to determine the best file extension for a given mime type.

@param string $type
@param string $proposed_extension - default extension (in case there is more than one with the same mime type)

@return string|null The extension determined, or null if unable to match.

Attempts to determine the best file extension for a given mime type .


public function to(string $uri, int $code = null, string $method = 'auto')
	{
		// If it appears to be a relative URL, then convert to full URL
		// for better security.
		if (strpos($uri, 'http') !== 0)
		{
			$url = current_url(true)->resolveRelativeURI($uri);
			$uri = (string)$url;
		}

		return $this->redirect($uri, $method, $code);
	}

Sets the URI to redirect to and, optionally, the HTTP status code to use.
If no code is provided it will be automatically determined.

@param string       $uri    The URI to redirect to
@param integer|null $code   HTTP status code
@param string       $method

@return $this

Sets the URI to redirect to and optionally the HTTP status code to use . If no code is provided it will be automatically determined .


public function route(string $route, array $params = [], int $code = 302, string $method = 'auto')
	{
		$routes = Services::routes(true);

		$route = $routes->reverseRoute($route, ...$params);

		if (! $route)
		{
			throw HTTPException::forInvalidRedirectRoute($route);
		}

		return $this->redirect(base_url($route), $method, $code);
	}

public function route ( string $ route , array $ params = [ ] , int $ code = 302 , string $ method = 'auto' ) { $ routes = Services :: routes ( true ) ; $ route = $ routes -> reverseRoute ( $ route , ... $ params ) ; if ( ! $ route ) { throw HTTPException :: forInvalidRedirectRoute ( $ route ) ; } return $ this -> redirect ( base_url ( $ route ) , $ method , $ code ) ; }

Sets the URI to redirect to but as a reverse-routed or named route
instead of a raw URI.

@param string       $route
@param array        $params
@param integer|null $code
@param string       $method

@return $this

Sets the URI to redirect to but as a reverse - routed or named route instead of a raw URI .


public function back(int $code = null, string $method = 'auto')
	{
		$this->ensureSession();

		return $this->redirect(previous_url(), $method, $code);
	}

public function back ( int $ code = null , string $ method = 'auto' ) { $ this -> ensureSession ( ) ; return $ this -> redirect ( previous_url ( ) , $ method , $ code ) ; }

Helper function to return to previous page.

Example:
return redirect()->back();

@param integer|null $code
@param string       $method

@return $this

Helper function to return to previous page .


public function with(string $key, $message)
	{
		$session = $this->ensureSession();

		$session->setFlashdata($key, $message);

		return $this;
	}

public function with ( string $ key , $ message ) { $ session = $ this -> ensureSession ( ) ; $ session -> setFlashdata ( $ key , $ message ) ; return $ this ; }

Adds a key and message to the session as Flashdata.

@param string       $key
@param string|array $message

@return $this

Adds a key and message to the session as Flashdata .


public function run(string $uri, string $position = 'before')
	{
		$this->initialize(strtolower($uri));

		foreach ($this->filters[$position] as $alias => $rules)
		{
			if (is_numeric($alias) && is_string($rules))
			{
				$alias = $rules;
			}

			if (! array_key_exists($alias, $this->config->aliases))
			{
				throw FilterException::forNoAlias($alias);
			}

			$class = new $this->config->aliases[$alias]();

			if (! $class instanceof FilterInterface)
			{
				throw FilterException::forIncorrectInterface(get_class($class));
			}

			if ($position === 'before')
			{
				$result = $class->before($this->request, $this->arguments[$alias] ?? null);

				if ($result instanceof RequestInterface)
				{
					$this->request = $result;
					continue;
				}

				// If the response object was sent back,
				// then send it and quit.
				if ($result instanceof ResponseInterface)
				{
					// short circuit - bypass any other filters
					return $result;
				}

				// Ignore an empty result
				if (empty($result))
				{
					continue;
				}

				return $result;
			}
			elseif ($position === 'after')
			{
				$result = $class->after($this->request, $this->response);

				if ($result instanceof ResponseInterface)
				{
					$this->response = $result;
					continue;
				}
			}
		}

		return $position === 'before' ? $this->request : $this->response;
	}

Runs through all of the filters for the specified
uri and position.

@param string $uri
@param string $position

@return \CodeIgniter\HTTP\RequestInterface|\CodeIgniter\HTTP\ResponseInterface|mixed
@throws \CodeIgniter\Filters\Exceptions\FilterException

Runs through all of the filters for the specified uri and position .


public function initialize(string $uri = null)
	{
		if ($this->initialized === true)
		{
			return $this;
		}

		$this->processGlobals($uri);
		$this->processMethods();
		$this->processFilters($uri);

		$this->initialized = true;

		return $this;
	}

public function initialize ( string $ uri = null ) { if ( $ this -> initialized === true ) { return $ this ; } $ this -> processGlobals ( $ uri ) ; $ this -> processMethods ( ) ; $ this -> processFilters ( $ uri ) ; $ this -> initialized = true ; return $ this ; }

Runs through our list of filters provided by the configuration
object to get them ready for use, including getting uri masks
to proper regex, removing those we can from the possibilities
based on HTTP method, etc.

The resulting $this->filters is an array of only filters
that should be applied to this request.

We go ahead an process the entire tree because we'll need to
run through both a before and after and don't want to double
process the rows.

@param string $uri

@return Filters

Runs through our list of filters provided by the configuration object to get them ready for use including getting uri masks to proper regex removing those we can from the possibilities based on HTTP method etc .


public function enableFilter(string $name, string $when = 'before')
	{
		// Get parameters and clean name
		if (strpos($name, ':') !== false)
		{
			list($name, $params) = explode(':', $name);

			$params = explode(',', $params);
			array_walk($params, function (&$item) {
				$item = trim($item);
			});

			$this->arguments[$name] = $params;
		}

		if (! array_key_exists($name, $this->config->aliases))
		{
			throw FilterException::forNoAlias($name);
		}

		if (! isset($this->filters[$when][$name]))
		{
			$this->filters[$when][] = $name;
		}

		return $this;
	}

public
function
enableFilter
(
string
$
name
,
string
$
when
=
'before'
)
{
// Get parameters and clean name
if
(
strpos
(
$
name
,
':'
)
!==
false
)
{
list
(
$
name
,
$
params
)
=
explode
(
':'
,
$
name
)
;
$
params
=
explode
(
','
,
$
params
)
;
array_walk
(
$
params
,
function
(
&
$
item
)
{
$
item
=
trim
(
$
item
)
;
}
)
;
$
this
->
arguments
[
$
name
]
=
$
params
;
}
if
(
!
array_key_exists
(
$
name
,
$
this
->
config
->
aliases
)
)
{
throw
FilterException
::
forNoAlias
(
$
name
)
;
}
if
(
!
isset
(
$
this
->
filters
[
$
when
]
[
$
name
]
)
)
{
$
this
->
filters
[
$
when
]
[
]
=
$
name
;
}
return
$
this
;
}

Ensures that a specific filter is on and enabled for the current request.

Filters can have "arguments". This is done by placing a colon immediately
after the filter name, followed by a comma-separated list of arguments that
are passed to the filter when executed.

@param string $name
@param string $when

@return \CodeIgniter\Filters\Filters

Ensures that a specific filter is on and enabled for the current request .


public function getArguments(string $key = null)
	{
		return is_null($key)
			? $this->arguments
			: $this->arguments[$key];
	}

public function getArguments ( string $ key = null ) { return is_null ( $ key ) ? $ this -> arguments : $ this -> arguments [ $ key ] ; }

Returns the arguments for a specified key, or all.

@return mixed

Returns the arguments for a specified key or all .


protected function format($object)
	{
		if (! is_object($object))
		{
			return $object;
		}

		// @todo Modify formatting of objects once we can view them in browser.
		$objectArray = (array) $object;

		$objectArray['___class_name'] = get_class($object);

		return $objectArray;
	}

Converts the object to display nicely in the Chrome Logger UI.

@param $object

@return array

Converts the object to display nicely in the Chrome Logger UI .


public function sendLogs(ResponseInterface &$response = null)
	{
		if (is_null($response))
		{
			$response = Services::response(null, true);
		}

		$data = base64_encode(utf8_encode(json_encode($this->json)));

		$response->setHeader($this->header, $data);
	}

public function sendLogs ( ResponseInterface & $ response = null ) { if ( is_null ( $ response ) ) { $ response = Services :: response ( null , true ) ; } $ data = base64_encode ( utf8_encode ( json_encode ( $ this -> json ) ) ) ; $ response -> setHeader ( $ this -> header , $ data ) ; }

Attaches the header and the content to the passed in request object.

@param ResponseInterface $response

Attaches the header and the content to the passed in request object .


public function detectLocale($config)
	{
		$this->locale = $this->defaultLocale = $config->defaultLocale;

		if (! $config->negotiateLocale)
		{
			return;
		}

		$this->setLocale($this->negotiate('language', $config->supportedLocales));
	}

public function detectLocale ( $ config ) { $ this -> locale = $ this -> defaultLocale = $ config -> defaultLocale ; if ( ! $ config -> negotiateLocale ) { return ; } $ this -> setLocale ( $ this -> negotiate ( 'language' , $ config -> supportedLocales ) ) ; }

Handles setting up the locale, perhaps auto-detecting through
content negotiation.

@param $config

Handles setting up the locale perhaps auto - detecting through content negotiation .


public function setLocale(string $locale)
	{
		// If it's not a valid locale, set it
		// to the default locale for the site.
		if (! in_array($locale, $this->validLocales))
		{
			$locale = $this->defaultLocale;
		}

		$this->locale = $locale;

		// If the intl extension is loaded, make sure
		// that we set the locale for it... if not, though,
		// don't worry about it.
		// this should not block code coverage thru unit testing
		// @codeCoverageIgnoreStart
		try
		{
			if (class_exists('\Locale', false))
			{
				\Locale::setDefault($locale);
			}
		}
		catch (\Exception $e)
		{
		}
		// @codeCoverageIgnoreEnd

		return $this;
	}

Sets the locale string for this request.

@param string $locale

@return IncomingRequest

Sets the locale string for this request .


public function isSecure(): bool
	{
		if (! empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off')
		{
			return true;
		}
		elseif (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')
		{
			return true;
		}
		elseif (! empty($_SERVER['HTTP_FRONT_END_HTTPS']) && strtolower($_SERVER['HTTP_FRONT_END_HTTPS']) !== 'off')
		{
			return true;
		}

		return false;
	}

public function isSecure ( ) : bool { if ( ! empty ( $ _SERVER [ 'HTTPS' ] ) && strtolower ( $ _SERVER [ 'HTTPS' ] ) !== 'off' ) { return true ; } elseif ( isset ( $ _SERVER [ 'HTTP_X_FORWARDED_PROTO' ] ) && $ _SERVER [ 'HTTP_X_FORWARDED_PROTO' ] === 'https' ) { return true ; } elseif ( ! empty ( $ _SERVER [ 'HTTP_FRONT_END_HTTPS' ] ) && strtolower ( $ _SERVER [ 'HTTP_FRONT_END_HTTPS' ] ) !== 'off' ) { return true ; } return false ; }

Attempts to detect if the current connection is secure through
a few different methods.

@return boolean

Attempts to detect if the current connection is secure through a few different methods .


public function getJSON(bool $assoc = false, int $depth = 512, int $options = 0)
	{
		return json_decode($this->body, $assoc, $depth, $options);
	}

public function getJSON ( bool $ assoc = false , int $ depth = 512 , int $ options = 0 ) { return json_decode ( $ this -> body , $ assoc , $ depth , $ options ) ; }

A convenience method that grabs the raw input stream and decodes
the JSON into an array.

If $assoc == true, then all objects in the response will be converted
to associative arrays.

@param boolean $assoc   Whether to return objects as associative arrays
@param integer $depth   How many levels deep to decode
@param integer $options Bitmask of options

@see http://php.net/manual/en/function.json-decode.php

@return mixed

A convenience method that grabs the raw input stream and decodes the JSON into an array .


public function getGet($index = null, $filter = null, $flags = null)
	{
		return $this->fetchGlobal('get', $index, $filter, $flags);
	}

public function getGet ( $ index = null , $ filter = null , $ flags = null ) { return $ this -> fetchGlobal ( 'get' , $ index , $ filter , $ flags ) ; }

Fetch an item from GET data.

@param string|array|null $index  Index for item to fetch from $_GET.
@param integer|null      $filter A filter name to apply.
@param mixed|null        $flags

@return mixed


public function getPost($index = null, $filter = null, $flags = null)
	{
		return $this->fetchGlobal('post', $index, $filter, $flags);
	}

public function getPost ( $ index = null , $ filter = null , $ flags = null ) { return $ this -> fetchGlobal ( 'post' , $ index , $ filter , $ flags ) ; }

Fetch an item from POST.

@param string|array|null $index  Index for item to fetch from $_POST.
@param integer|null      $filter A filter name to apply
@param mixed             $flags

@return mixed


public function getPostGet($index = null, $filter = null, $flags = null)
	{
		// Use $_POST directly here, since filter_has_var only
		// checks the initial POST data, not anything that might
		// have been added since.
		return isset($_POST[$index]) ? $this->getPost($index, $filter, $flags) : $this->getGet($index, $filter, $flags);
	}

Fetch an item from POST data with fallback to GET.

@param string|array|null $index  Index for item to fetch from $_POST or $_GET
@param integer|null      $filter A filter name to apply
@param mixed             $flags

@return mixed

Fetch an item from POST data with fallback to GET .


public function getGetPost($index = null, $filter = null, $flags = null)
	{
		// Use $_GET directly here, since filter_has_var only
		// checks the initial GET data, not anything that might
		// have been added since.
		return isset($_GET[$index]) ? $this->getGet($index, $filter, $flags) : $this->getPost($index, $filter, $flags);
	}

Fetch an item from GET data with fallback to POST.

@param string|array|null $index  Index for item to be fetched from $_GET or $_POST
@param integer|null      $filter A filter name to apply
@param mixed             $flags

@return mixed

Fetch an item from GET data with fallback to POST .


public function getCookie($index = null, $filter = null, $flags = null)
	{
		return $this->fetchGlobal('cookie', $index, $filter, $flags);
	}

public function getCookie ( $ index = null , $ filter = null , $ flags = null ) { return $ this -> fetchGlobal ( 'cookie' , $ index , $ filter , $ flags ) ; }

Fetch an item from the COOKIE array.

@param string|array|null $index  Index for item to be fetched from $_COOKIE
@param integer|null      $filter A filter name to be applied
@param mixed             $flags

@return mixed


public function getFiles(): array
	{
		if (is_null($this->files))
		{
			$this->files = new FileCollection();
		}

		return $this->files->all(); // return all files
	}

public
function
getFiles
(
)
:
array
{
if
(
is_null
(
$
this
->
files
)
)
{
$
this
->
files
=
new
FileCollection
(
)
;
}
return
$
this
->
files
->
all
(
)
;
// return all files
}

Returns an array of all files that have been uploaded with this
request. Each file is represented by an UploadedFile instance.

@return array

Returns an array of all files that have been uploaded with this request . Each file is represented by an UploadedFile instance .


public function getFile(string $fileID)
	{
		if (is_null($this->files))
		{
			$this->files = new FileCollection();
		}

		return $this->files->getFile($fileID);
	}

public function getFile ( string $ fileID ) { if ( is_null ( $ this -> files ) ) { $ this -> files = new FileCollection ( ) ; } return $ this -> files -> getFile ( $ fileID ) ; }

Retrieves a single file by the name of the input field used
to upload it.

@param string $fileID

@return UploadedFile|null

Retrieves a single file by the name of the input field used to upload it .


protected function detectURI(string $protocol, string $baseURL)
	{
		$this->uri->setPath($this->detectPath($protocol));

		// It's possible the user forgot a trailing slash on their
		// baseURL, so let's help them out.
		$baseURL = ! empty($baseURL) ? rtrim($baseURL, '/ ') . '/' : $baseURL;

		// Based on our baseURL provided by the developer (if set)
		// set our current domain name, scheme
		if (! empty($baseURL))
		{
			// We cannot add the path here, otherwise it's possible
			// that the routing will not work correctly if we are
			// within a sub-folder scheme. So it's modified in
			// the
			$this->uri->setScheme(parse_url($baseURL, PHP_URL_SCHEME));
			$this->uri->setHost(parse_url($baseURL, PHP_URL_HOST));
			$this->uri->setPort(parse_url($baseURL, PHP_URL_PORT));
			$this->uri->resolveRelativeURI(parse_url($baseURL, PHP_URL_PATH));
		}
		else
		{
			// @codeCoverageIgnoreStart
			if (! is_cli())
			{
				die('You have an empty or invalid base URL. The baseURL value must be set in Config\App.php, or through the .env file.');
			}
			// @codeCoverageIgnoreEnd
		}
	}

Sets up our URI object based on the information we have. This is
either provided by the user in the baseURL Config setting, or
determined from the environment as needed.

@param string $protocol
@param string $baseURL

Sets up our URI object based on the information we have . This is either provided by the user in the baseURL Config setting or determined from the environment as needed .


public function detectPath(string $protocol = ''): string
	{
		if (empty($protocol))
		{
			$protocol = 'REQUEST_URI';
		}

		switch ($protocol)
		{
			case 'REQUEST_URI':
				$path = $this->parseRequestURI();
				break;
			case 'QUERY_STRING':
				$path = $this->parseQueryString();
				break;
			case 'PATH_INFO':
			default:
				$path = $this->fetchGlobal('server', $protocol) ?? $this->parseRequestURI();
				break;
		}

		return $path;
	}

public function detectPath ( string $ protocol = '' ) : string { if ( empty ( $ protocol ) ) { $ protocol = 'REQUEST_URI' ; } switch ( $ protocol ) { case 'REQUEST_URI' : $ path = $ this -> parseRequestURI ( ) ; break ; case 'QUERY_STRING' : $ path = $ this -> parseQueryString ( ) ; break ; case 'PATH_INFO' : default : $ path = $ this -> fetchGlobal ( 'server' , $ protocol ) ?? $ this -> parseRequestURI ( ) ; break ; } return $ path ; }

Based on the URIProtocol Config setting, will attempt to
detect the path portion of the current URI.

@param string $protocol

@return string

Based on the URIProtocol Config setting will attempt to detect the path portion of the current URI .


public function negotiate(string $type, array $supported, bool $strictMatch = false): string
	{
		if (is_null($this->negotiator))
		{
			$this->negotiator = Services::negotiator($this, true);
		}

		switch (strtolower($type))
		{
			case 'media':
				return $this->negotiator->media($supported, $strictMatch);
			case 'charset':
				return $this->negotiator->charset($supported);
			case 'encoding':
				return $this->negotiator->encoding($supported);
			case 'language':
				return $this->negotiator->language($supported);
		}

		throw HTTPException::forInvalidNegotiationType($type);
	}

public function negotiate ( string $ type , array $ supported , bool $ strictMatch = false ) : string { if ( is_null ( $ this -> negotiator ) ) { $ this -> negotiator = Services :: negotiator ( $ this , true ) ; } switch ( strtolower ( $ type ) ) { case 'media' : return $ this -> negotiator -> media ( $ supported , $ strictMatch ) ; case 'charset' : return $ this -> negotiator -> charset ( $ supported ) ; case 'encoding' : return $ this -> negotiator -> encoding ( $ supported ) ; case 'language' : return $ this -> negotiator -> language ( $ supported ) ; } throw HTTPException :: forInvalidNegotiationType ( $ type ) ; }

Provides a convenient way to work with the Negotiate class
for content negotiation.

@param string  $type
@param array   $supported
@param boolean $strictMatch

@return string

Provides a convenient way to work with the Negotiate class for content negotiation .


protected function parseRequestURI(): string
	{
		if (! isset($_SERVER['REQUEST_URI'], $_SERVER['SCRIPT_NAME']))
		{
			return '';
		}

		// parse_url() returns false if no host is present, but the path or query string
		// contains a colon followed by a number
		$parts = parse_url('http://dummy' . $_SERVER['REQUEST_URI']);
		$query = $parts['query'] ?? '';
		$uri   = $parts['path'] ?? '';

		if (isset($_SERVER['SCRIPT_NAME'][0]))
		{
			// strip the script name from the beginning of the URI
			if (strpos($uri, $_SERVER['SCRIPT_NAME']) === 0)
			{
				$uri = (string) substr($uri, strlen($_SERVER['SCRIPT_NAME']));
			}
			// if the script is nested, strip the parent folder & script from the URI
			elseif (strpos($uri, $_SERVER['SCRIPT_NAME']) > 0)
			{
				$uri = (string) substr($uri, strpos($uri, $_SERVER['SCRIPT_NAME']) + strlen($_SERVER['SCRIPT_NAME']));
			}
			// or if index.php is implied
			elseif (strpos($uri, dirname($_SERVER['SCRIPT_NAME'])) === 0)
			{
				$uri = (string) substr($uri, strlen(dirname($_SERVER['SCRIPT_NAME'])));
			}
		}

		// This section ensures that even on servers that require the URI to contain the query string (Nginx) a correct
		// URI is found, and also fixes the QUERY_STRING getServer var and $_GET array.
		if (trim($uri, '/') === '' && strncmp($query, '/', 1) === 0)
		{
			$query                   = explode('?', $query, 2);
			$uri                     = $query[0];
			$_SERVER['QUERY_STRING'] = $query[1] ?? '';
		}
		else
		{
			$_SERVER['QUERY_STRING'] = $query;
		}

		parse_str($_SERVER['QUERY_STRING'], $_GET);

		if ($uri === '/' || $uri === '')
		{
			return '/';
		}

		return $this->removeRelativeDirectory($uri);
	}

Will parse the REQUEST_URI and automatically detect the URI from it,
fixing the query string if necessary.

@return string The URI it found.

Will parse the REQUEST_URI and automatically detect the URI from it fixing the query string if necessary .


protected function buildDSN()
	{
		$this->DSN === '' || $this->DSN = '';

		// If UNIX sockets are used, we shouldn't set a port
		if (strpos($this->hostname, '/') !== false)
		{
			$this->port = '';
		}

		$this->hostname === '' || $this->DSN = "host={$this->hostname} ";

		if (! empty($this->port) && ctype_digit($this->port))
		{
			$this->DSN .= "port={$this->port} ";
		}

		if ($this->username !== '')
		{
			$this->DSN .= "user={$this->username} ";

			// An empty password is valid!
			// password must be set to null to ignore it.

			$this->password === null || $this->DSN .= "password='{$this->password}' ";
		}

		$this->database === '' || $this->DSN .= "dbname={$this->database} ";

		// We don't have these options as elements in our standard configuration
		// array, but they might be set by parse_url() if the configuration was
		// provided via string> Example:
		//
		// postgre://username:password@localhost:5432/database?connect_timeout=5&sslmode=1
		foreach (['connect_timeout', 'options', 'sslmode', 'service'] as $key)
		{
			if (isset($this->{$key}) && is_string($this->{$key}) && $this->{$key} !== '')
			{
				$this->DSN .= "{$key}='{$this->{$key}}' ";
			}
		}

		$this->DSN = rtrim($this->DSN);
	}

Build a DSN from the provided parameters

@return void


public function getFormatter(string $mime)
	{
		if (! array_key_exists($mime, $this->formatters))
		{
			throw new \InvalidArgumentException('No Formatter defined for mime type: ' . $mime);
		}

		$class = $this->formatters[$mime];

		if (! class_exists($class))
		{
			throw new \BadMethodCallException($class . ' is not a valid Formatter.');
		}

		return new $class();
	}

public
function
getFormatter
(
string
$
mime
)
{
if
(
!
array_key_exists
(
$
mime
,
$
this
->
formatters
)
)
{
throw
new
\
InvalidArgumentException
(
'No Formatter defined for mime type: '
.
$
mime
)
;
}
$
class
=
$
this
->
formatters
[
$
mime
]
;
if
(
!
class_exists
(
$
class
)
)
{
throw
new
\
BadMethodCallException
(
$
class
.
' is not a valid Formatter.'
)
;
}
return
new
$
class
(
)
;
}

A Factory method to return the appropriate formatter for the given mime type.

@param string $mime

@return \CodeIgniter\Format\FormatterInterface

A Factory method to return the appropriate formatter for the given mime type .


public function before(RequestInterface $request)
	{
		$honeypot = Services::honeypot(new \Config\Honeypot());
		if ($honeypot->hasContent($request))
		{
			throw HoneypotException::isBot();
		}
	}

public function before ( RequestInterface $ request ) { $ honeypot = Services :: honeypot ( new \ Config \ Honeypot ( ) ) ; if ( $ honeypot -> hasContent ( $ request ) ) { throw HoneypotException :: isBot ( ) ; } }

Checks if Honeypot field is empty; if not
then the requester is a bot

@param \CodeIgniter\HTTP\RequestInterface $request

@return void

@throws \CodeIgniter\Honeypot\Exceptions\HoneypotException

Checks if Honeypot field is empty ; if not then the requester is a bot


public function after(RequestInterface $request, ResponseInterface $response)
	{
		$honeypot = Services::honeypot(new \Config\Honeypot());
		$honeypot->attachHoneypot($response);
	}

public function after ( RequestInterface $ request , ResponseInterface $ response ) { $ honeypot = Services :: honeypot ( new \ Config \ Honeypot ( ) ) ; $ honeypot -> attachHoneypot ( $ response ) ; }

Attach a honeypot to the current response.

@param  \CodeIgniter\HTTP\RequestInterface  $request
@param  \CodeIgniter\HTTP\ResponseInterface $response

@return void

Attach a honeypot to the current response .


public function _resize(bool $maintainRatio = false)
	{
		$source      = ! empty($this->resource) ? $this->resource : $this->image->getPathname();
		$destination = $this->getResourcePath();

		$escape = '\\';
		if (stripos(PHP_OS, 'WIN') === 0)
		{
			$escape = '';
		}

		$action = $maintainRatio === true ? ' -resize ' . $this->width . 'x' . $this->height . ' "' . $source . '" "' . $destination . '"' : ' -resize ' . $this->width . 'x' . $this->height . "{$escape}! \"" . $source . '" "' . $destination . '"';

		$this->process($action);

		return $this;
	}

public
function
_resize
(
bool
$
maintainRatio
=
false
)
{
$
source
=
!
empty
(
$
this
->
resource
)
$
this
->
resource
:
$
this
->
image
->
getPathname
(
)
;
$
destination
=
$
this
->
getResourcePath
(
)
;
$
escape
=
'\\'
;
if
(
stripos
(
PHP_OS
,
'WIN'
)
===
0
)
{
$
escape
=
''
;
}
$
action
=
$
maintainRatio
===
true
' -resize '
.
$
this
->
width
.
'x'
.
$
this
->
height
.
' "'
.
$
source
.
'" "'
.
$
destination
.
'"'
:
' -resize '
.
$
this
->
width
.
'x'
.
$
this
->
height
.
"{$escape}! \""
.
$
source
.
'" "'
.
$
destination
.
'"'
;
$
this
->
process
(
$
action
)
;
return
$
this
;
}

Handles the actual resizing of the image.

@param boolean $maintainRatio

@return ImageMagickHandler
@throws \Exception

Handles the actual resizing of the image .


public function _crop()
	{
		$source      = ! empty($this->resource) ? $this->resource : $this->image->getPathname();
		$destination = $this->getResourcePath();

		$action = ' -crop ' . $this->width . 'x' . $this->height . '+' . $this->xAxis . '+' . $this->yAxis . ' "' . $source . '" "' . $destination . '"';

		$this->process($action);

		return $this;
	}

public
function
_crop
(
)
{
$
source
=
!
empty
(
$
this
->
resource
)
$
this
->
resource
:
$
this
->
image
->
getPathname
(
)
;
$
destination
=
$
this
->
getResourcePath
(
)
;
$
action
=
' -crop '
.
$
this
->
width
.
'x'
.
$
this
->
height
.
'+'
.
$
this
->
xAxis
.
'+'
.
$
this
->
yAxis
.
' "'
.
$
source
.
'" "'
.
$
destination
.
'"'
;
$
this
->
process
(
$
action
)
;
return
$
this
;
}

Crops the image.

@return boolean|\CodeIgniter\Images\Handlers\ImageMagickHandler
@throws \Exception


public function getVersion(): string
	{
		$result = $this->process('-version');

		// The first line has the version in it...
		preg_match('/(ImageMagick\s[\S]+)/', $result[0], $matches);

		return str_replace('ImageMagick ', '', $matches[0]);
	}


protected function getResourcePath()
	{
		if (! is_null($this->resource))
		{
			return $this->resource;
		}

		$this->resource = WRITEPATH . 'cache/' . time() . '_' . bin2hex(random_bytes(10)) . '.png';

		return $this->resource;
	}

protected function getResourcePath ( ) { if ( ! is_null ( $ this -> resource ) ) { return $ this -> resource ; } $ this -> resource = WRITEPATH . 'cache/' . time ( ) . '_' . bin2hex ( random_bytes ( 10 ) ) . '.png' ; return $ this -> resource ; }

Get Image Resource

This simply creates an image resource handle
based on the type of image being processed.
Since ImageMagick is used on the cli, we need to
ensure we have a temporary file on the server
that we can use.

To ensure we can use all features, like transparency,
during the process, we'll use a PNG as the temp file type.

@return resource|boolean
@throws \Exception


public function addForeignKey(string $fieldName = '', string $tableName = '', string $tableField = '', string $onUpdate = '', string $onDelete = '')
	{
		if (! isset($this->fields[$fieldName]))
		{
			throw new DatabaseException(lang('Database.fieldNotExists', [$fieldName]));
		}

		$this->foreignKeys[$fieldName] = [
			'table'    => $tableName,
			'field'    => $tableField,
			'onDelete' => strtoupper($onDelete),
			'onUpdate' => strtoupper($onUpdate),
		];

		return $this;
	}

public function addForeignKey ( string $ fieldName = '' , string $ tableName = '' , string $ tableField = '' , string $ onUpdate = '' , string $ onDelete = '' ) { if ( ! isset ( $ this -> fields [ $ fieldName ] ) ) { throw new DatabaseException ( lang ( 'Database.fieldNotExists' , [ $ fieldName ] ) ) ; } $ this -> foreignKeys [ $ fieldName ] = [ 'table' => $ tableName , 'field' => $ tableField , 'onDelete' => strtoupper ( $ onDelete ) , 'onUpdate' => strtoupper ( $ onUpdate ) , ] ; return $ this ; }

Add Foreign Key

@param string  $fieldName
@param string  $tableName
@param string  $tableField
@param string  $onUpdate
@param string  $onDelete

@return \CodeIgniter\Database\Forge
@throws \CodeIgniter\Database\Exceptions\DatabaseException


public function dropForeignKey(string $table, string $foreign_name)
	{
		$sql = sprintf($this->dropConstraintStr, $this->db->escapeIdentifiers($this->db->DBPrefix . $table),
			$this->db->escapeIdentifiers($this->db->DBPrefix . $foreign_name));

		if ($sql === false)
		{
			if ($this->db->DBDebug)
			{
				throw new DatabaseException('This feature is not available for the database you are using.');
			}

			return false;
		}

		return $this->db->query($sql);
	}

Foreign Key Drop

@param string $table        Table name
@param string $foreign_name Foreign name

@return boolean|\CodeIgniter\Database\BaseResult|\CodeIgniter\Database\Query|false|mixed
@throws \CodeIgniter\Database\Exceptions\DatabaseException