protected function splitRules(string $rules): array
	{
		$non_escape_bracket  = '((?<!\\\\)(?:\\\\\\\\)*[\[\]])';
		$pipe_not_in_bracket = sprintf(
			'/\|(?=(?:[^\[\]]*%s[^\[\]]*%s)*(?![^\[\]]*%s))/',
			$non_escape_bracket,
			$non_escape_bracket,
			$non_escape_bracket
		);

		$_rules = preg_split(
			$pipe_not_in_bracket,
			$rules
		);

		return array_unique($_rules);
	}

Split rules string by pipe operator.

@param string $rules

@return array


public function reset(): ValidationInterface
	{
		$this->data         = [];
		$this->rules        = [];
		$this->errors       = [];
		$this->customErrors = [];

		return $this;
	}

public function reset ( ) : ValidationInterface { $ this -> data = [ ] ; $ this -> rules = [ ] ; $ this -> errors = [ ] ; $ this -> customErrors = [ ] ; return $ this ; }

Resets the class to a blank slate. Should be called whenever
you need to process more than one array.

@return \CodeIgniter\Validation\ValidationInterface

Resets the class to a blank slate . Should be called whenever you need to process more than one array .


protected function arrayToXML(array $data, &$output)
	{
		foreach ($data as $key => $value)
		{
			if (is_array($value))
			{
				if (! is_numeric($key))
				{
					$subnode = $output->addChild("$key");
					$this->arrayToXML($value, $subnode);
				}
				else
				{
					$subnode = $output->addChild("item{$key}");
					$this->arrayToXML($value, $subnode);
				}
			}
			else
			{
				$output->addChild("$key", htmlspecialchars("$value"));
			}
		}
	}

protected function arrayToXML ( array $ data , & $ output ) { foreach ( $ data as $ key => $ value ) { if ( is_array ( $ value ) ) { if ( ! is_numeric ( $ key ) ) { $ subnode = $ output -> addChild ( "$key" ) ; $ this -> arrayToXML ( $ value , $ subnode ) ; } else { $ subnode = $ output -> addChild ( "item{$key}" ) ; $ this -> arrayToXML ( $ value , $ subnode ) ; } } else { $ output -> addChild ( "$key" , htmlspecialchars ( "$value" ) ) ; } } }

A recursive method to convert an array into a valid XML string.

Written by CodexWorld. Received permission by email on Nov 24, 2016 to use this code.

@see http://www.codexworld.com/convert-array-to-xml-in-php/

@param array             $data
@param \SimpleXMLElement $output

A recursive method to convert an array into a valid XML string .


protected function cleanFileNames(string $file): string
	{
		$file = str_replace(APPPATH, 'APPPATH/', $file);
		$file = str_replace(SYSTEMPATH, 'SYSTEMPATH/', $file);
		$file = str_replace(FCPATH, 'FCPATH/', $file);

		return $file;
	}

protected function cleanFileNames ( string $ file ) : string { $ file = str_replace ( APPPATH , 'APPPATH/' , $ file ) ; $ file = str_replace ( SYSTEMPATH , 'SYSTEMPATH/' , $ file ) ; $ file = str_replace ( FCPATH , 'FCPATH/' , $ file ) ; return $ file ; }

Cleans the paths of filenames by replacing APPPATH, SYSTEMPATH, FCPATH
with the actual var. i.e.

/var/www/site/app/Controllers/Home.php
becomes:
APPPATH/Controllers/Home.php

@param $file

@return string

Cleans the paths of filenames by replacing APPPATH SYSTEMPATH FCPATH with the actual var . i . e .


public function setURI(string $uri = null)
	{
		if (! is_null($uri))
		{
			$parts = parse_url($uri);

			if ($parts === false)
			{
				throw HTTPException::forUnableToParseURI($uri);
			}

			$this->applyParts($parts);
		}

		return $this;
	}

public function setURI ( string $ uri = null ) { if ( ! is_null ( $ uri ) ) { $ parts = parse_url ( $ uri ) ; if ( $ parts === false ) { throw HTTPException :: forUnableToParseURI ( $ uri ) ; } $ this -> applyParts ( $ parts ) ; } return $ this ; }

Sets and overwrites any current URI information.

@param string|null $uri

@return URI

Sets and overwrites any current URI information .


public function getUserInfo()
	{
		$userInfo = $this->user;

		if ($this->showPassword === true && ! empty($this->password))
		{
			$userInfo .= ':' . $this->password;
		}

		return $userInfo;
	}

public function getUserInfo ( ) { $ userInfo = $ this -> user ; if ( $ this -> showPassword === true && ! empty ( $ this -> password ) ) { $ userInfo .= ':' . $ this -> password ; } return $ userInfo ; }

Retrieve the user information component of the URI.

If no user information is present, this method MUST return an empty
string.

If a user is present in the URI, this will return that value;
additionally, if the password is also present, it will be appended to the
user value, with a colon (":") separating the values.

NOTE that be default, the password, if available, will NOT be shown
as a security measure as discussed in RFC 3986, Section 7.5. If you know
the password is not a security issue, you can force it to be shown
with $this->showPassword();

The trailing "@" character is not part of the user information and MUST
NOT be added.

@return string|null The URI user information, in "username[:password]" format.

Retrieve the user information component of the URI .


public function getQuery(array $options = []): string
	{
		$vars = $this->query;

		if (array_key_exists('except', $options))
		{
			if (! is_array($options['except']))
			{
				$options['except'] = [$options['except']];
			}

			foreach ($options['except'] as $var)
			{
				unset($vars[$var]);
			}
		}
		elseif (array_key_exists('only', $options))
		{
			$temp = [];

			if (! is_array($options['only']))
			{
				$options['only'] = [$options['only']];
			}

			foreach ($options['only'] as $var)
			{
				if (array_key_exists($var, $vars))
				{
					$temp[$var] = $vars[$var];
				}
			}

			$vars = $temp;
		}

		return empty($vars) ? '' : http_build_query($vars);
	}

public function getQuery ( array $ options = [ ] ) : string { $ vars = $ this -> query ; if ( array_key_exists ( 'except' , $ options ) ) { if ( ! is_array ( $ options [ 'except' ] ) ) { $ options [ 'except' ] = [ $ options [ 'except' ] ] ; } foreach ( $ options [ 'except' ] as $ var ) { unset ( $ vars [ $ var ] ) ; } } elseif ( array_key_exists ( 'only' , $ options ) ) { $ temp = [ ] ; if ( ! is_array ( $ options [ 'only' ] ) ) { $ options [ 'only' ] = [ $ options [ 'only' ] ] ; } foreach ( $ options [ 'only' ] as $ var ) { if ( array_key_exists ( $ var , $ vars ) ) { $ temp [ $ var ] = $ vars [ $ var ] ; } } $ vars = $ temp ; } return empty ( $ vars ) ? '' : http_build_query ( $ vars ) ; }

Retrieve the query string

@param array $options

@return string


public function getSegment(int $number): string
	{
		// The segment should treat the array as 1-based for the user
		// but we still have to deal with a zero-based array.
		$number -= 1;

		if ($number > count($this->segments))
		{
			throw HTTPException::forURISegmentOutOfRange($number);
		}

		return $this->segments[$number] ?? '';
	}

Returns the value of a specific segment of the URI path.

@param integer $number

@return string     The value of the segment. If no segment is found,
throws InvalidArgumentError

Returns the value of a specific segment of the URI path .


public function setSegment(int $number, $value)
	{
		// The segment should treat the array as 1-based for the user
		// but we still have to deal with a zero-based array.
		$number -= 1;

		if ($number > count($this->segments) + 1)
		{
			throw HTTPException::forURISegmentOutOfRange($number);
		}

		$this->segments[$number] = $value;
		$this->refreshPath();

		return $this;
	}

Set the value of a specific segment of the URI path.
Allows to set only existing segments or add new one.

@param integer $number
@param mixed   $value  (string or int)

@return $this

Set the value of a specific segment of the URI path . Allows to set only existing segments or add new one .


public static function createURIString(string $scheme = null, string $authority = null, string $path = null, string $query = null, string $fragment = null): string
	{
		$uri = '';
		if (! empty($scheme))
		{
			$uri .= $scheme . '://';
		}

		if (! empty($authority))
		{
			$uri .= $authority;
		}

		if ($path)
		{
			$uri .= substr($uri, -1, 1) !== '/' ? '/' . ltrim($path, '/') : $path;
		}

		if ($query)
		{
			$uri .= '?' . $query;
		}

		if ($fragment)
		{
			$uri .= '#' . $fragment;
		}

		return $uri;
	}

public static function createURIString ( string $ scheme = null , string $ authority = null , string $ path = null , string $ query = null , string $ fragment = null ) : string { $ uri = '' ; if ( ! empty ( $ scheme ) ) { $ uri .= $ scheme . '://' ; } if ( ! empty ( $ authority ) ) { $ uri .= $ authority ; } if ( $ path ) { $ uri .= substr ( $ uri , - 1 , 1 ) !== '/' ? '/' . ltrim ( $ path , '/' ) : $ path ; } if ( $ query ) { $ uri .= '?' . $ query ; } if ( $ fragment ) { $ uri .= '#' . $ fragment ; } return $ uri ; }

Builds a representation of the string from the component parts.

@param string $scheme
@param string $authority
@param string $path
@param string $query
@param string $fragment

@return string

Builds a representation of the string from the component parts .


public function setAuthority(string $str)
	{
		$parts = parse_url($str);

		if (empty($parts['host']) && ! empty($parts['path']))
		{
			$parts['host'] = $parts['path'];
			unset($parts['path']);
		}

		$this->applyParts($parts);

		return $this;
	}

public function setAuthority ( string $ str ) { $ parts = parse_url ( $ str ) ; if ( empty ( $ parts [ 'host' ] ) && ! empty ( $ parts [ 'path' ] ) ) { $ parts [ 'host' ] = $ parts [ 'path' ] ; unset ( $ parts [ 'path' ] ) ; } $ this -> applyParts ( $ parts ) ; return $ this ; }

Parses the given string an saves the appropriate authority pieces.

@param string $str

@return $this

Parses the given string an saves the appropriate authority pieces .


public function setScheme(string $str)
	{
		$str = strtolower($str);
		$str = preg_replace('#:(//)?$#', '', $str);

		$this->scheme = $str;

		return $this;
	}

public function setScheme ( string $ str ) { $ str = strtolower ( $ str ) ; $ str = preg_replace ( '#:(//)?$#' , '' , $ str ) ; $ this -> scheme = $ str ; return $ this ; }

Sets the scheme for this URI.

Because of the large number of valid schemes we cannot limit this
to only http or https.

@see https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml

@param $str

@return $this


public function setPort(int $port = null)
	{
		if (is_null($port))
		{
			return $this;
		}

		if ($port <= 0 || $port > 65535)
		{
			throw HTTPException::forInvalidPort($port);
		}

		$this->port = $port;

		return $this;
	}

public function setPort ( int $ port = null ) { if ( is_null ( $ port ) ) { return $ this ; } if ( $ port <= 0 || $ port > 65535 ) { throw HTTPException :: forInvalidPort ( $ port ) ; } $ this -> port = $ port ; return $ this ; }

Sets the port portion of the URI.

@param integer $port

@return $this


public function setPath(string $path)
	{
		$this->path = $this->filterPath($path);

		$this->segments = explode('/', $this->path);

		return $this;
	}

public function setPath ( string $ path ) { $ this -> path = $ this -> filterPath ( $ path ) ; $ this -> segments = explode ( '/' , $ this -> path ) ; return $ this ; }

Sets the path portion of the URI.

@param string $path

@return $this


public function refreshPath()
	{
		$this->path = $this->filterPath(implode('/', $this->segments));

		$this->segments = explode('/', $this->path);

		return $this;
	}

public function refreshPath ( ) { $ this -> path = $ this -> filterPath ( implode ( '/' , $ this -> segments ) ) ; $ this -> segments = explode ( '/' , $ this -> path ) ; return $ this ; }

Sets the path portion of the URI based on segments.

@param string $path

@return $this

Sets the path portion of the URI based on segments .


public function setQuery(string $query)
	{
		if (strpos($query, '#') !== false)
		{
			throw HTTPException::forMalformedQueryString();
		}

		// Can't have leading ?
		if (! empty($query) && strpos($query, '?') === 0)
		{
			$query = substr($query, 1);
		}

		$temp  = explode('&', $query);
		$parts = [];

		foreach ($temp as $index => $part)
		{
			list($key, $value) = $this->splitQueryPart($part);

			// Only 1 part?
			if (is_null($value))
			{
				$parts[$key] = null;
				continue;
			}

			// URL Decode the value to protect
			// from double-encoding a URL.
			// Especially useful with the Pager.
			$parts[$this->decode($key)] = $this->decode($value);
		}

		$this->query = $parts;

		return $this;
	}

public
function
setQuery
(
string
$
query
)
{
if
(
strpos
(
$
query
,
'#'
)
!==
false
)
{
throw
HTTPException
::
forMalformedQueryString
(
)
;
}
// Can't have leading ?
if
(
!
empty
(
$
query
)
&&
strpos
(
$
query
,
'?'
)
===
0
)
{
$
query
=
substr
(
$
query
,
1
)
;
}
$
temp
=
explode
(
'&'
,
$
query
)
;
$
parts
=
[
]
;
foreach
(
$
temp
as
$
index
=>
$
part
)
{
list
(
$
key
,
$
value
)
=
$
this
->
splitQueryPart
(
$
part
)
;
// Only 1 part?
if
(
is_null
(
$
value
)
)
{
$
parts
[
$
key
]
=
;
continue
;
}
// URL Decode the value to protect
// from double-encoding a URL.
// Especially useful with the Pager.
$
parts
[
$
this
->
decode
(
$
key
)
]
=
$
this
->
decode
(
$
value
)
;
}
$
this
->
query
=
$
parts
;
return
$
this
;
}

Sets the query portion of the URI, while attempting
to clean the various parts of the query keys and values.

@param string $query

@return $this

Sets the query portion of the URI while attempting to clean the various parts of the query keys and values .


protected function decode(string $value): string
	{
		if (empty($value))
		{
			return $value;
		}

		$decoded = urldecode($value);

		// This won't catch all cases, specifically
		// changing ' ' to '+' has the same length
		// but doesn't really matter for our cases here.
		return strlen($decoded) < strlen($value) ? $decoded : $value;
	}

Checks the value to see if it has been urlencoded and decodes it if so.
The urlencode check is not perfect but should catch most cases.

@param string $value

@return string

Checks the value to see if it has been urlencoded and decodes it if so . The urlencode check is not perfect but should catch most cases .


public function addQuery(string $key, $value = null)
	{
		$this->query[$key] = $value;

		return $this;
	}

public function addQuery ( string $ key , $ value = null ) { $ this -> query [ $ key ] = $ value ; return $ this ; }

Adds a single new element to the query vars.

@param string $key
@param mixed  $value

@return $this

Adds a single new element to the query vars .


public function keepQuery(...$params)
	{
		$temp = [];

		foreach ($this->query as $key => $value)
		{
			if (! in_array($key, $params))
			{
				continue;
			}

			$temp[$key] = $value;
		}

		$this->query = $temp;

		return $this;
	}

public function keepQuery ( ... $ params ) { $ temp = [ ] ; foreach ( $ this -> query as $ key => $ value ) { if ( ! in_array ( $ key , $ params ) ) { continue ; } $ temp [ $ key ] = $ value ; } $ this -> query = $ temp ; return $ this ; }

Filters the query variables so that only the keys passed in
are kept. The rest are removed from the object.

@param array ...$params

@return $this

Filters the query variables so that only the keys passed in are kept . The rest are removed from the object .


protected function filterPath(string $path = null): string
	{
		$orig = $path;

		// Decode/normalize percent-encoded chars so
		// we can always have matching for Routes, etc.
		$path = urldecode($path);

		// Remove dot segments
		$path = $this->removeDotSegments($path);

		// Fix up some leading slash edge cases...
		if (strpos($orig, './') === 0)
		{
			$path = '/' . $path;
		}
		if (strpos($orig, '../') === 0)
		{
			$path = '/' . $path;
		}

		// Encode characters
		$path = preg_replace_callback(
				'/(?:[^' . static::CHAR_UNRESERVED . ':@&=\+\$,\/;%]+|%(?![A-Fa-f0-9]{2}))/', function (array $matches) {
					return rawurlencode($matches[0]);
				}, $path
		);

		return $path;
	}

Encodes any dangerous characters, and removes dot segments.
While dot segments have valid uses according to the spec,
this URI class does not allow them.

@param $path

@return string

Encodes any dangerous characters and removes dot segments . While dot segments have valid uses according to the spec this URI class does not allow them .


protected function applyParts(array $parts)
	{
		if (! empty($parts['host']))
		{
			$this->host = $parts['host'];
		}
		if (! empty($parts['user']))
		{
			$this->user = $parts['user'];
		}
		if (! empty($parts['path']))
		{
			$this->path = $this->filterPath($parts['path']);
		}
		if (! empty($parts['query']))
		{
			$this->setQuery($parts['query']);
		}
		if (! empty($parts['fragment']))
		{
			$this->fragment = $parts['fragment'];
		}

		// Scheme
		if (isset($parts['scheme']))
		{
			$this->setScheme(rtrim($parts['scheme'], ':/'));
		}
		else
		{
			$this->setScheme('http');
		}

		// Port
		if (isset($parts['port']))
		{
			if (! is_null($parts['port']))
			{
				// Valid port numbers are enforced by earlier parse_url or setPort()
				$port       = $parts['port'];
				$this->port = $port;
			}
		}

		if (isset($parts['pass']))
		{
			$this->password = $parts['pass'];
		}

		// Populate our segments array
		if (! empty($parts['path']))
		{
			$this->segments = explode('/', trim($parts['path'], '/'));
		}
	}

Saves our parts from a parse_url call.

@param array $parts


public function resolveRelativeURI(string $uri)
	{
		/*
		 * NOTE: We don't use removeDotSegments in this
		 * algorithm since it's already done by this line!
		 */
		$relative = new URI();
		$relative->setURI($uri);

		if ($relative->getScheme() === $this->getScheme())
		{
			$relative->setScheme('');
		}

		$transformed = clone $relative;

		// 5.2.2 Transform References in a non-strict method (no scheme)
		if (! empty($relative->getAuthority()))
		{
			$transformed->setAuthority($relative->getAuthority())
					->setPath($relative->getPath())
					->setQuery($relative->getQuery());
		}
		else
		{
			if ($relative->getPath() === '')
			{
				$transformed->setPath($this->getPath());

				if ($relative->getQuery())
				{
					$transformed->setQuery($relative->getQuery());
				}
				else
				{
					$transformed->setQuery($this->getQuery());
				}
			}
			else
			{
				if (strpos($relative->getPath(), '/') === 0)
				{
					$transformed->setPath($relative->getPath());
				}
				else
				{
					$transformed->setPath($this->mergePaths($this, $relative));
				}

				$transformed->setQuery($relative->getQuery());
			}

			$transformed->setAuthority($this->getAuthority());
		}

		$transformed->setScheme($this->getScheme());

		$transformed->setFragment($relative->getFragment());

		return $transformed;
	}

Combines one URI string with this one based on the rules set out in
RFC 3986 Section 2

@see http://tools.ietf.org/html/rfc3986#section-5.2

@param string $uri

@return \CodeIgniter\HTTP\URI


protected function mergePaths(URI $base, URI $reference): string
	{
		if (! empty($base->getAuthority()) && empty($base->getPath()))
		{
			return '/' . ltrim($reference->getPath(), '/ ');
		}

		$path = explode('/', $base->getPath());

		if (empty($path[0]))
		{
			unset($path[0]);
		}

		array_pop($path);
		array_push($path, $reference->getPath());

		return implode('/', $path);
	}

protected
function
mergePaths
(
URI
$
base
,
URI
$
reference
)
:
string
{
if
(
!
empty
(
$
base
->
getAuthority
(
)
)
&&
empty
(
$
base
->
getPath
(
)
)
)
{
return
'/'
.
ltrim
(
$
reference
->
getPath
(
)
,
'/ '
)
;
}
$
path
=
explode
(
'/'
,
$
base
->
getPath
(
)
)
;
if
(
empty
(
$
path
[
0
]
)
)
{
unset
(
$
path
[
0
]
)
;
}
array_pop
(
$
path
)
;
array_push
(
$
path
,
$
reference
->
getPath
(
)
)
;
return
implode
(
'/'
,
$
path
)
;
}

Given 2 paths, will merge them according to rules set out in RFC 2986,
Section 5.2

@see http://tools.ietf.org/html/rfc3986#section-5.2.3

@param URI $base
@param URI $reference

@return string

Given 2 paths will merge them according to rules set out in RFC 2986 Section 5 . 2


public function removeDotSegments(string $path): string
	{
		if (empty($path) || $path === '/')
		{
			return $path;
		}

		$output = [];

		$input = explode('/', $path);

		if (empty($input[0]))
		{
			unset($input[0]);
			$input = array_values($input);
		}

		// This is not a perfect representation of the
		// RFC, but matches most cases and is pretty
		// much what Guzzle uses. Should be good enough
		// for almost every real use case.
		foreach ($input as $segment)
		{
			if ($segment === '..')
			{
				array_pop($output);
			}
			else if ($segment !== '.' && $segment !== '')
			{
				array_push($output, $segment);
			}
		}

		$output = implode('/', $output);
		$output = ltrim($output, '/ ');

		if ($output !== '/')
		{
			// Add leading slash if necessary
			if (strpos($path, '/') === 0)
			{
				$output = '/' . $output;
			}

			// Add trailing slash if necessary
			if (substr($path, -1, 1) === '/')
			{
				$output .= '/';
			}
		}

		return $output;
	}

Used when resolving and merging paths to correctly interpret and
remove single and double dot segments from the path per
RFC 3986 Section 5.2.4

@see http://tools.ietf.org/html/rfc3986#section-5.2.4

@param string $path

@return   string
@internal param \CodeIgniter\HTTP\URI $uri

Used when resolving and merging paths to correctly interpret and remove single and double dot segments from the path per RFC 3986 Section 5 . 2 . 4


public function appendValue($value = null)
	{
		if (! is_array($this->value))
		{
			$this->value = [$this->value];
		}

		$this->value[] = $value;

		return $this;
	}

public function appendValue ( $ value = null ) { if ( ! is_array ( $ this -> value ) ) { $ this -> value = [ $ this -> value ] ; } $ this -> value [ ] = $ value ; return $ this ; }

Appends a value to the list of values for this header. If the
header is a single value string, it will be converted to an array.

@param null $value

@return $this

Appends a value to the list of values for this header . If the header is a single value string it will be converted to an array .


public function prependValue($value = null)
	{
		if (! is_array($this->value))
		{
			$this->value = [$this->value];
		}

		array_unshift($this->value, $value);

		return $this;
	}

public function prependValue ( $ value = null ) { if ( ! is_array ( $ this -> value ) ) { $ this -> value = [ $ this -> value ] ; } array_unshift ( $ this -> value , $ value ) ; return $ this ; }

Prepends a value to the list of values for this header. If the
header is a single value string, it will be converted to an array.

@param null $value

@return $this

Prepends a value to the list of values for this header . If the header is a single value string it will be converted to an array .


public function getPrevious()
	{
		if (! $this->hasPrevious())
		{
			return null;
		}

		$uri = clone $this->uri;

		if ($this->segment === 0)
		{
			$uri->addQuery('page', $this->first - 1);
		}
		else
		{
			$uri->setSegment($this->segment, $this->first - 1);
		}

		return (string) $uri;
	}

public function getPrevious ( ) { if ( ! $ this -> hasPrevious ( ) ) { return null ; } $ uri = clone $ this -> uri ; if ( $ this -> segment === 0 ) { $ uri -> addQuery ( 'page' , $ this -> first - 1 ) ; } else { $ uri -> setSegment ( $ this -> segment , $ this -> first - 1 ) ; } return ( string ) $ uri ; }

Returns a URL to the "previous" page. The previous page is NOT the
page before the current page, but is the page just before the
"first" page.

You MUST call hasPrevious() first, or this value may be invalid.

@return string|null

Returns a URL to the previous page . The previous page is NOT the page before the current page but is the page just before the first page .


public function getNext()
	{
		if (! $this->hasNext())
		{
			return null;
		}

		$uri = clone $this->uri;

		if ($this->segment === 0)
		{
			$uri->addQuery('page', $this->last + 1);
		}
		else
		{
			$uri->setSegment($this->segment, $this->last + 1);
		}

		return (string) $uri;
	}

public function getNext ( ) { if ( ! $ this -> hasNext ( ) ) { return null ; } $ uri = clone $ this -> uri ; if ( $ this -> segment === 0 ) { $ uri -> addQuery ( 'page' , $ this -> last + 1 ) ; } else { $ uri -> setSegment ( $ this -> segment , $ this -> last + 1 ) ; } return ( string ) $ uri ; }

Returns a URL to the "next" page. The next page is NOT, the
page after the current page, but is the page that follows the
"last" page.

You MUST call hasNext() first, or this value may be invalid.

@return string|null

Returns a URL to the next page . The next page is NOT the page after the current page but is the page that follows the last page .


public function getFirst(): string
	{
		$uri = clone $this->uri;

		if ($this->segment === 0)
		{
			$uri->addQuery('page', 1);
		}
		else
		{
			$uri->setSegment($this->segment, 1);
		}

		return (string) $uri;
	}

public function getFirst ( ) : string { $ uri = clone $ this -> uri ; if ( $ this -> segment === 0 ) { $ uri -> addQuery ( 'page' , 1 ) ; } else { $ uri -> setSegment ( $ this -> segment , 1 ) ; } return ( string ) $ uri ; }

Returns the URI of the first page.

@return string


public function getLast(): string
	{
		$uri = clone $this->uri;

		if ($this->segment === 0)
		{
			$uri->addQuery('page', $this->pageCount);
		}
		else
		{
			$uri->setSegment($this->segment, $this->pageCount);
		}

		return (string) $uri;
	}

public function getLast ( ) : string { $ uri = clone $ this -> uri ; if ( $ this -> segment === 0 ) { $ uri -> addQuery ( 'page' , $ this -> pageCount ) ; } else { $ uri -> setSegment ( $ this -> segment , $ this -> pageCount ) ; } return ( string ) $ uri ; }

Returns the URI of the last page.

@return string


public function getCurrent(): string
	{
		$uri = clone $this->uri;

		if ($this->segment === 0)
		{
			$uri->addQuery('page', $this->current);
		}
		else
		{
			$uri->setSegment($this->segment, $this->current);
		}

		return (string) $uri;
	}

public function getCurrent ( ) : string { $ uri = clone $ this -> uri ; if ( $ this -> segment === 0 ) { $ uri -> addQuery ( 'page' , $ this -> current ) ; } else { $ uri -> setSegment ( $ this -> segment , $ this -> current ) ; } return ( string ) $ uri ; }

Returns the URI of the current page.

@return string


public function start(string $name, float $time = null)
	{
		$this->timers[strtolower($name)] = [
			'start' => ! empty($time) ? $time : microtime(true),
			'end'   => null,
		];

		return $this;
	}

public function start ( string $ name , float $ time = null ) { $ this -> timers [ strtolower ( $ name ) ] = [ 'start' => ! empty ( $ time ) ? $ time : microtime ( true ) , 'end' => null , ] ; return $ this ; }

Starts a timer running.

Multiple calls can be made to this method so that several
execution points can be measured.

@param string $name The name of this timer.
@param float  $time Allows user to provide time.

@return Timer


public function stop(string $name)
	{
		$name = strtolower($name);

		if (empty($this->timers[$name]))
		{
			throw new \RuntimeException('Cannot stop timer: invalid name given.');
		}

		$this->timers[$name]['end'] = microtime(true);

		return $this;
	}

Stops a running timer.

If the timer is not stopped before the timers() method is called,
it will be automatically stopped at that point.

@param string $name The name of this timer.

@return Timer


public function getElapsedTime(string $name, int $decimals = 4)
	{
		$name = strtolower($name);

		if (empty($this->timers[$name]))
		{
			return null;
		}

		$timer = $this->timers[$name];

		if (empty($timer['end']))
		{
			$timer['end'] = microtime(true);
		}

		return (float) number_format($timer['end'] - $timer['start'], $decimals);
	}

public function getElapsedTime ( string $ name , int $ decimals = 4 ) { $ name = strtolower ( $ name ) ; if ( empty ( $ this -> timers [ $ name ] ) ) { return null ; } $ timer = $ this -> timers [ $ name ] ; if ( empty ( $ timer [ 'end' ] ) ) { $ timer [ 'end' ] = microtime ( true ) ; } return ( float ) number_format ( $ timer [ 'end' ] - $ timer [ 'start' ] , $ decimals ) ; }

Returns the duration of a recorded timer.

@param string  $name     The name of the timer.
@param integer $decimals Number of decimal places.

@return null|float       Returns null if timer exists by that name.
Returns a float representing the number of
seconds elapsed while that timer was running.

Returns the duration of a recorded timer .


public function getTimers(int $decimals = 4): array
	{
		$timers = $this->timers;

		foreach ($timers as &$timer)
		{
			if (empty($timer['end']))
			{
				$timer['end'] = microtime(true);
			}

			$timer['duration'] = (float) number_format($timer['end'] - $timer['start'], $decimals);
		}

		return $timers;
	}

public function getTimers ( int $ decimals = 4 ) : array { $ timers = $ this -> timers ; foreach ( $ timers as & $ timer ) { if ( empty ( $ timer [ 'end' ] ) ) { $ timer [ 'end' ] = microtime ( true ) ; } $ timer [ 'duration' ] = ( float ) number_format ( $ timer [ 'end' ] - $ timer [ 'start' ] , $ decimals ) ; } return $ timers ; }

Returns the array of timers, with the duration pre-calculated for you.

@param integer $decimals Number of decimal places

@return array

Returns the array of timers with the duration pre - calculated for you .


public function addTableAlias(string $table)
	{
		if (! in_array($table, $this->aliasedTables))
		{
			$this->aliasedTables[] = $table;
		}

		return $this;
	}

public function addTableAlias ( string $ table ) { if ( ! in_array ( $ table , $ this -> aliasedTables ) ) { $ this -> aliasedTables [ ] = $ table ; } return $ this ; }

Add a table alias to our list.

@param string $table

@return $this


public function query(string $sql, $binds = null, bool $setEscapeFlags = true, string $queryClass = 'CodeIgniter\\Database\\Query')
	{
		if (empty($this->connID))
		{
			$this->initialize();
		}

		$resultClass = str_replace('Connection', 'Result', get_class($this));
		/**
		 * @var Query $query
		 */
		$query = new $queryClass($this);

		$query->setQuery($sql, $binds, $setEscapeFlags);

		if (! empty($this->swapPre) && ! empty($this->DBPrefix))
		{
			$query->swapPrefix($this->DBPrefix, $this->swapPre);
		}

		$startTime = microtime(true);

		// Always save the last query so we can use
		// the getLastQuery() method.
		$this->lastQuery = $query;

		// Run the query for real
		if (! $this->pretend && false === ($this->resultID = $this->simpleQuery($query->getQuery())))
		{
			$query->setDuration($startTime, $startTime);

			// This will trigger a rollback if transactions are being used
			if ($this->transDepth !== 0)
			{
				$this->transStatus = false;
			}

			if ($this->DBDebug)
			{
				// We call this function in order to roll-back queries
				// if transactions are enabled. If we don't call this here
				// the error message will trigger an exit, causing the
				// transactions to remain in limbo.
				while ($this->transDepth !== 0)
				{
					$transDepth = $this->transDepth;
					$this->transComplete();

					if ($transDepth === $this->transDepth)
					{
						log_message('error', 'Database: Failure during an automated transaction commit/rollback!');
						break;
					}
				}

				return false;
			}

			if (! $this->pretend)
			{
				// Let others do something with this query.
				Events::trigger('DBQuery', $query);
			}

			return new $resultClass($this->connID, $this->resultID);
		}

		$query->setDuration($startTime);

		if (! $this->pretend)
		{
			// Let others do something with this query
			Events::trigger('DBQuery', $query);
		}

		// If $pretend is true, then we just want to return
		// the actual query object here. There won't be
		// any results to return.
		return $this->pretend ? $query : new $resultClass($this->connID, $this->resultID);
	}

Orchestrates a query against the database. Queries must use
Database\Statement objects to store the query and build it.
This method works with the cache.

Should automatically handle different connections for read/write
queries if needed.

@param string  $sql
@param mixed   ...$binds
@param boolean $setEscapeFlags
@param string  $queryClass

@return BaseResult|Query|false

Orchestrates a query against the database . Queries must use Database \ Statement objects to store the query and build it . This method works with the cache .


public function simpleQuery(string $sql)
	{
		if (empty($this->connID))
		{
			$this->initialize();
		}

		return $this->execute($sql);
	}

public function simpleQuery ( string $ sql ) { if ( empty ( $ this -> connID ) ) { $ this -> initialize ( ) ; } return $ this -> execute ( $ sql ) ; }

Performs a basic query against the database. No binding or caching
is performed, nor are transactions handled. Simply takes a raw
query string and returns the database-specific result id.

@param string $sql

@return mixed

Performs a basic query against the database . No binding or caching is performed nor are transactions handled . Simply takes a raw query string and returns the database - specific result id .


public function table($tableName)
	{
		if (empty($tableName))
		{
			throw new DatabaseException('You must set the database table to be used with your query.');
		}

		$className = str_replace('Connection', 'Builder', get_class($this));

		return new $className($tableName, $this);
	}

Returns an instance of the query builder for this connection.

@param string|array $tableName

@return BaseBuilder
@throws DatabaseException

Returns an instance of the query builder for this connection .


public function prepare(\Closure $func, array $options = [])
	{
		if (empty($this->connID))
		{
			$this->initialize();
		}

		$this->pretend(true);

		$sql = $func($this);

		$this->pretend(false);

		if ($sql instanceof QueryInterface)
		{
			$sql = $sql->getOriginalQuery();
		}

		$class = str_ireplace('Connection', 'PreparedQuery', get_class($this));
		/**
		 * @var BasePreparedQuery $class
		 */
		$class = new $class($this);

		return $class->prepare($sql, $options);
	}

/**
		 * @var BasePreparedQuery $class
		 */

Creates a prepared statement with the database that can then
be used to execute multiple statements against. Within the
closure, you would build the query in any normal way, though
the Query Builder is the expected manner.

Example:
$stmt = $db->prepare(function($db)
{
return $db->table('users')
->where('id', 1)
->get();
})

@param \Closure $func
@param array    $options Passed to the prepare() method

@return BasePreparedQuery|null

Creates a prepared statement with the database that can then be used to execute multiple statements against . Within the closure you would build the query in any normal way though the Query Builder is the expected manner .


public function escapeIdentifiers($item)
	{
		if ($this->escapeChar === '' || empty($item) || in_array($item, $this->reservedIdentifiers))
		{
			return $item;
		}
		elseif (is_array($item))
		{
			foreach ($item as $key => $value)
			{
				$item[$key] = $this->escapeIdentifiers($value);
			}

			return $item;
		}
		// Avoid breaking functions and literal values inside queries
		elseif (ctype_digit($item) || $item[0] === "'" || ( $this->escapeChar !== '"' && $item[0] === '"') ||
				strpos($item, '(') !== false
		)
		{
			return $item;
		}

		static $preg_ec = [];

		if (empty($preg_ec))
		{
			if (is_array($this->escapeChar))
			{
				$preg_ec = [
					preg_quote($this->escapeChar[0], '/'),
					preg_quote($this->escapeChar[1], '/'),
					$this->escapeChar[0],
					$this->escapeChar[1],
				];
			}
			else
			{
				$preg_ec[0] = $preg_ec[1] = preg_quote($this->escapeChar, '/');
				$preg_ec[2] = $preg_ec[3] = $this->escapeChar;
			}
		}

		foreach ($this->reservedIdentifiers as $id)
		{
			if (strpos($item, '.' . $id) !== false)
			{
				return preg_replace('/' . $preg_ec[0] . '?([^' . $preg_ec[1] . '\.]+)' . $preg_ec[1] . '?\./i', $preg_ec[2] . '$1' . $preg_ec[3] . '.', $item);
			}
		}

		return preg_replace('/' . $preg_ec[0] . '?([^' . $preg_ec[1] . '\.]+)' . $preg_ec[1] . '?(\.)?/i', $preg_ec[2] . '$1' . $preg_ec[3] . '$2', $item);
	}

Escape the SQL Identifiers

This function escapes column and table names

@param mixed $item

@return mixed


public function callFunction(string $functionName, ...$params): bool
	{
		$driver = ($this->DBDriver === 'postgre' ? 'pg' : strtolower($this->DBDriver)) . '_';

		if (false === strpos($driver, $functionName))
		{
			$functionName = $driver . $functionName;
		}

		if (! function_exists($functionName))
		{
			if ($this->DBDebug)
			{
				throw new DatabaseException('This feature is not available for the database you are using.');
			}

			return false;
		}

		return $functionName(...$params);
	}

This function enables you to call PHP database functions that are not natively included
in CodeIgniter, in a platform independent manner.

@param string $functionName
@param array  ...$params

@return boolean
@throws DatabaseException

This function enables you to call PHP database functions that are not natively included in CodeIgniter in a platform independent manner .


public function listTables(bool $constrainByPrefix = false)
	{
		// Is there a cached result?
		if (isset($this->dataCache['table_names']) && $this->dataCache['table_names'])
		{
			return $this->dataCache['table_names'];
		}

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

		$this->dataCache['table_names'] = [];
		$query                          = $this->query($sql);

		foreach ($query->getResultArray() as $row)
		{
			// Do we know from which column to get the table name?
			if (! isset($key))
			{
				if (isset($row['table_name']))
				{
					$key = 'table_name';
				}
				elseif (isset($row['TABLE_NAME']))
				{
					$key = 'TABLE_NAME';
				}
				else
				{
					/* We have no other choice but to just get the first element's key.
					 * Due to array_shift() accepting its argument by reference, if
					 * E_STRICT is on, this would trigger a warning. So we'll have to
					 * assign it first.
					 */
					$key = array_keys($row);
					$key = array_shift($key);
				}
			}

			$this->dataCache['table_names'][] = $row[$key];
		}

		return $this->dataCache['table_names'];
	}

Returns an array of table names

@param  boolean $constrainByPrefix = FALSE
@return boolean|array
@throws \CodeIgniter\Database\Exceptions\DatabaseException


public function tableExists(string $tableName): bool
	{
		return in_array($this->protectIdentifiers($tableName, true, false, false), $this->listTables());
	}

public function tableExists ( string $ tableName ) : bool { return in_array ( $ this -> protectIdentifiers ( $ tableName , true , false , false ) , $ this -> listTables ( ) ) ; }

Determine if a particular table exists

@param  string $tableName
@return boolean


public function fieldExists(string $fieldName, string $tableName): bool
	{
		return in_array($fieldName, $this->getFieldNames($tableName));
	}

public function fieldExists ( string $ fieldName , string $ tableName ) : bool { return in_array ( $ fieldName , $ this -> getFieldNames ( $ tableName ) ) ; }

Determine if a particular field exists

@param  string   $fieldName
@param  string   $tableName
@return boolean


public function getFieldData(string $table)
	{
		$fields = $this->_fieldData($this->protectIdentifiers($table, true, false, false));

		return $fields ?? false;
	}

public function getFieldData ( string $ table ) { $ fields = $ this -> _fieldData ( $ this -> protectIdentifiers ( $ table , true , false , false ) ) ; return $ fields ?? false ; }

Returns an object with field data

@param  string $table the table name
@return array|false


public function getIndexData(string $table)
	{
		$fields = $this->_indexData($this->protectIdentifiers($table, true, false, false));

		return $fields ?? false;
	}

public function getIndexData ( string $ table ) { $ fields = $ this -> _indexData ( $ this -> protectIdentifiers ( $ table , true , false , false ) ) ; return $ fields ?? false ; }

Returns an object with key data

@param  string $table the table name
@return array|false


public function getForeignKeyData(string $table)
	{
		$fields = $this->_foreignKeyData($this->protectIdentifiers($table, true, false, false));

		return $fields ?? false;
	}

public function getForeignKeyData ( string $ table ) { $ fields = $ this -> _foreignKeyData ( $ this -> protectIdentifiers ( $ table , true , false , false ) ) ; return $ fields ?? false ; }

Returns an object with foreign key data

@param  string $table the table name
@return array|false


protected function getEnvValue(string $property, string $prefix, string $shortPrefix)
	{
		$shortPrefix = ltrim($shortPrefix, '\\');
		switch (true)
		{
			case array_key_exists("{$shortPrefix}.{$property}", $_ENV):
				return $_ENV["{$shortPrefix}.{$property}"];
				break;
			case array_key_exists("{$shortPrefix}.{$property}", $_SERVER):
				return $_SERVER["{$shortPrefix}.{$property}"];
				break;
			case array_key_exists("{$prefix}.{$property}", $_ENV):
				return $_ENV["{$prefix}.{$property}"];
				break;
			case array_key_exists("{$prefix}.{$property}", $_SERVER):
				return $_SERVER["{$prefix}.{$property}"];
				break;
			default:
				$value = getenv($property);
				return $value === false ? null : $value;
		}
	}

protected function getEnvValue ( string $ property , string $ prefix , string $ shortPrefix ) { $ shortPrefix = ltrim ( $ shortPrefix , '\\' ) ; switch ( true ) { case array_key_exists ( "{$shortPrefix}.{$property}" , $ _ENV ) : return $ _ENV [ "{$shortPrefix}.{$property}" ] ; break ; case array_key_exists ( "{$shortPrefix}.{$property}" , $ _SERVER ) : return $ _SERVER [ "{$shortPrefix}.{$property}" ] ; break ; case array_key_exists ( "{$prefix}.{$property}" , $ _ENV ) : return $ _ENV [ "{$prefix}.{$property}" ] ; break ; case array_key_exists ( "{$prefix}.{$property}" , $ _SERVER ) : return $ _SERVER [ "{$prefix}.{$property}" ] ; break ; default : $ value = getenv ( $ property ) ; return $ value === false ? null : $ value ; } }

Retrieve an environment-specific configuration setting

@param string $property
@param string $prefix
@param string $shortPrefix

@return mixed

Retrieve an environment - specific configuration setting


protected function registerProperties()
	{
		if (! static::$moduleConfig->shouldDiscover('registrars'))
		{
			return;
		}

		if (! static::$didDiscovery)
		{
			$locator         = \Config\Services::locator();
			$registrarsFiles = $locator->search('Config/Registrar.php');

			foreach ($registrarsFiles as $file)
			{
				$className = $locator->getClassname($file);
				static::$registrars[] = new $className();
			}

			static::$didDiscovery = true;
		}

		$shortName = (new \ReflectionClass($this))->getShortName();

		// Check the registrar class for a method named after this class' shortName
		foreach (static::$registrars as $callable)
		{
			// ignore non-applicable registrars
			if (! method_exists($callable, $shortName))
			{
				continue;
			}

			$properties = $callable::$shortName();

			if (! is_array($properties))
			{
				throw new \RuntimeException('Registrars must return an array of properties and their values.');
			}

			foreach ($properties as $property => $value)
			{
				if (isset($this->$property) && is_array($this->$property) && is_array($value))
				{
					$this->$property = array_merge($this->$property, $value);
				}
				else
				{
					$this->$property = $value;
				}
			}
		}
	}

Provides external libraries a simple way to register one or more
options into a config file.

@throws \ReflectionException

Provides external libraries a simple way to register one or more options into a config file .


protected function getItem(string $key)
	{
		if (! is_file($this->path . $key))
		{
			return false;
		}

		$data = unserialize(file_get_contents($this->path . $key));

		if ($data['ttl'] > 0 && time() > $data['time'] + $data['ttl'])
		{
			unlink($this->path . $key);

			return false;
		}

		return $data;
	}

protected function getItem ( string $ key ) { if ( ! is_file ( $ this -> path . $ key ) ) { return false ; } $ data = unserialize ( file_get_contents ( $ this -> path . $ key ) ) ; if ( $ data [ 'ttl' ] > 0 && time ( ) > $ data [ 'time' ] + $ data [ 'ttl' ] ) { unlink ( $ this -> path . $ key ) ; return false ; } return $ data ; }

Does the heavy lifting of actually retrieving the file and
verifying it's age.

@param string $key

@return boolean|mixed

Does the heavy lifting of actually retrieving the file and verifying it s age .


protected function writeFile($path, $data, $mode = 'wb')
	{
		if (($fp = @fopen($path, $mode)) === false)
		{
			return false;
		}

		flock($fp, LOCK_EX);

		for ($result = $written = 0, $length = strlen($data); $written < $length; $written += $result)
		{
			if (($result = fwrite($fp, substr($data, $written))) === false)
			{
				break;
			}
		}

		flock($fp, LOCK_UN);
		fclose($fp);

		return is_int($result);
	}

protected function writeFile ( $ path , $ data , $ mode = 'wb' ) { if ( ( $ fp = @ fopen ( $ path , $ mode ) ) === false ) { return false ; } flock ( $ fp , LOCK_EX ) ; for ( $ result = $ written = 0 , $ length = strlen ( $ data ) ; $ written < $ length ; $ written += $ result ) { if ( ( $ result = fwrite ( $ fp , substr ( $ data , $ written ) ) ) === false ) { break ; } } flock ( $ fp , LOCK_UN ) ; fclose ( $ fp ) ; return is_int ( $ result ) ; }

Writes a file to disk, or returns false if not successful.

@param $path
@param $data
@param string $mode

@return boolean

Writes a file to disk or returns false if not successful .


protected function getDirFileInfo(string $source_dir, bool $top_level_only = true, bool $_recursion = false)
	{
		static $_filedata = [];
		$relative_path    = $source_dir;

		if ($fp = @opendir($source_dir))
		{
			// reset the array and make sure $source_dir has a trailing slash on the initial call
			if ($_recursion === false)
			{
				$_filedata  = [];
				$source_dir = rtrim(realpath($source_dir), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
			}

			// Used to be foreach (scandir($source_dir, 1) as $file), but scandir() is simply not as fast
			while (false !== ($file = readdir($fp)))
			{
				if (is_dir($source_dir . $file) && $file[0] !== '.' && $top_level_only === false)
				{
					$this->getDirFileInfo($source_dir . $file . DIRECTORY_SEPARATOR, $top_level_only, true);
				}
				elseif ($file[0] !== '.')
				{
					$_filedata[$file]                  = $this->getFileInfo($source_dir . $file);
					$_filedata[$file]['relative_path'] = $relative_path;
				}
			}

			closedir($fp);

			return $_filedata;
		}

		return false;
	}

Get Directory File Information

Reads the specified directory and builds an array containing the filenames,
filesize, dates, and permissions

Any sub-folders contained within the specified path are read as well.

@param string  $source_dir     Path to source
@param boolean $top_level_only Look only at the top level directory specified?
@param boolean $_recursion     Internal variable to determine recursion status - do not use in calls

@return array|false


protected function getFileInfo(string $file, $returned_values = ['name', 'server_path', 'size', 'date'])
	{
		if (! is_file($file))
		{
			return false;
		}

		if (is_string($returned_values))
		{
			$returned_values = explode(',', $returned_values);
		}

		foreach ($returned_values as $key)
		{
			switch ($key)
			{
				case 'name':
					$fileInfo['name'] = basename($file);
					break;
				case 'server_path':
					$fileInfo['server_path'] = $file;
					break;
				case 'size':
					$fileInfo['size'] = filesize($file);
					break;
				case 'date':
					$fileInfo['date'] = filemtime($file);
					break;
				case 'readable':
					$fileInfo['readable'] = is_readable($file);
					break;
				case 'writable':
					$fileInfo['writable'] = is_writable($file);
					break;
				case 'executable':
					$fileInfo['executable'] = is_executable($file);
					break;
				case 'fileperms':
					$fileInfo['fileperms'] = fileperms($file);
					break;
			}
		}

		return $fileInfo;
	}

protected function getFileInfo ( string $ file , $ returned_values = [ 'name' , 'server_path' , 'size' , 'date' ] ) { if ( ! is_file ( $ file ) ) { return false ; } if ( is_string ( $ returned_values ) ) { $ returned_values = explode ( ',' , $ returned_values ) ; } foreach ( $ returned_values as $ key ) { switch ( $ key ) { case 'name' : $ fileInfo [ 'name' ] = basename ( $ file ) ; break ; case 'server_path' : $ fileInfo [ 'server_path' ] = $ file ; break ; case 'size' : $ fileInfo [ 'size' ] = filesize ( $ file ) ; break ; case 'date' : $ fileInfo [ 'date' ] = filemtime ( $ file ) ; break ; case 'readable' : $ fileInfo [ 'readable' ] = is_readable ( $ file ) ; break ; case 'writable' : $ fileInfo [ 'writable' ] = is_writable ( $ file ) ; break ; case 'executable' : $ fileInfo [ 'executable' ] = is_executable ( $ file ) ; break ; case 'fileperms' : $ fileInfo [ 'fileperms' ] = fileperms ( $ file ) ; break ; } } return $ fileInfo ; }

Get File Info

Given a file and path, returns the name, path, size, date modified
Second parameter allows you to explicitly declare what information you want returned
Options are: name, server_path, size, date, readable, writable, executable, fileperms
Returns FALSE if the file cannot be found.

@param string $file            Path to file
@param mixed  $returned_values Array or comma separated string of information returned

@return array|false


public function initialize()
	{
		// Set default timezone on the server
		date_default_timezone_set($this->config->appTimezone ?? 'UTC');

		// Setup Exception Handling
		Services::exceptions()
				->initialize();

		$this->detectEnvironment();
		$this->bootstrapEnvironment();

		if (CI_DEBUG)
		{
			require_once SYSTEMPATH . 'ThirdParty/Kint/kint.php';
		}
	}

public
function
initialize
(
)
{
// Set default timezone on the server
date_default_timezone_set
(
$
this
->
config
->
appTimezone
??
'UTC'
)
;
// Setup Exception Handling
Services
::
exceptions
(
)
->
initialize
(
)
;
$
this
->
detectEnvironment
(
)
;
$
this
->
bootstrapEnvironment
(
)
;
if
(
CI_DEBUG
)
{
require_once
SYSTEMPATH
.
'ThirdParty/Kint/kint.php'
;
}
}

Handles some basic app and environment setup.

Handles some basic app and environment setup .


public function run(RouteCollectionInterface $routes = null, bool $returnResponse = false)
	{
		$this->startBenchmark();

		$this->getRequestObject();
		$this->getResponseObject();

		$this->forceSecureAccess();

		$this->spoofRequestMethod();

		Events::trigger('pre_system');

		// Check for a cached page. Execution will stop
		// if the page has been cached.
		$cacheConfig = new Cache();
		$response    = $this->displayCache($cacheConfig);
		if ($response instanceof ResponseInterface)
		{
			if ($returnResponse)
			{
				return $response;
			}

			$this->response->pretend($this->useSafeOutput)->send();
			$this->callExit(EXIT_SUCCESS);
		}

		try
		{
			return $this->handleRequest($routes, $cacheConfig, $returnResponse);
		}
		catch (FilterException $e)
		{
			$logger = Services::logger();
			$logger->info('REDIRECTED ROUTE at ' . $e->getMessage());

			// If the route is a 'redirect' route, it throws
			// the exception with the $to as the message
			$this->response->redirect($e->getMessage(), 'auto', $e->getCode());
			$this->callExit(EXIT_SUCCESS);
		}
		catch (PageNotFoundException $e)
		{
			$this->display404errors($e);
		}
	}

Launch the application!

This is "the loop" if you will. The main entry point into the script
that gets the required class instances, fires off the filters,
tries to route the response, loads the controller and generally
makes all of the pieces work together.

@param \CodeIgniter\Router\RouteCollectionInterface $routes
@param boolean                                      $returnResponse

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


protected function handleRequest(RouteCollectionInterface $routes = null, $cacheConfig, bool $returnResponse = false)
	{
		$routeFilter = $this->tryToRouteIt($routes);

		// Run "before" filters
		$filters = Services::filters();

		// If any filters were specified within the routes file,
		// we need to ensure it's active for the current request
		if (! is_null($routeFilter))
		{
			$filters->enableFilter($routeFilter, 'before');
			$filters->enableFilter($routeFilter, 'after');
		}

		$uri = $this->request instanceof CLIRequest ? $this->request->getPath() : $this->request->uri->getPath();

		// Never run filters when running through Spark cli
		if (! defined('SPARKED'))
		{
			$possibleRedirect = $filters->run($uri, 'before');
			if ($possibleRedirect instanceof RedirectResponse)
			{
				return $possibleRedirect->send();
			}
			// If a Response instance is returned, the Response will be sent back to the client and script execution will stop
			if ($possibleRedirect instanceof ResponseInterface)
			{
				return $possibleRedirect->send();
			}
		}

		$returned = $this->startController();

		// Closure controller has run in startController().
		if (! is_callable($this->controller))
		{
			$controller = $this->createController();

			// Is there a "post_controller_constructor" event?
			Events::trigger('post_controller_constructor');

			$returned = $this->runController($controller);
		}
		else
		{
			$this->benchmark->stop('controller_constructor');
			$this->benchmark->stop('controller');
		}

		// If $returned is a string, then the controller output something,
		// probably a view, instead of echoing it directly. Send it along
		// so it can be used with the output.
		$this->gatherOutput($cacheConfig, $returned);

		// Never run filters when running through Spark cli
		if (! defined('SPARKED'))
		{
			$filters->setResponse($this->response);
			// Run "after" filters
			$response = $filters->run($uri, 'after');
		}
		else
		{
			$response = $this->response;
		}

		if ($response instanceof Response)
		{
			$this->response = $response;
		}

		// Save our current URI as the previous URI in the session
		// for safer, more accurate use with `previous_url()` helper function.
		$this->storePreviousURL($this->request->uri ?? $uri);

		unset($uri);

		if (! $returnResponse)
		{
			$this->sendResponse();
		}

		//--------------------------------------------------------------------
		// Is there a post-system event?
		//--------------------------------------------------------------------
		Events::trigger('post_system');

		return $this->response;
	}

Handles the main request logic and fires the controller.

@param \CodeIgniter\Router\RouteCollectionInterface $routes
@param $cacheConfig
@param boolean                                      $returnResponse

@return \CodeIgniter\HTTP\RequestInterface|\CodeIgniter\HTTP\Response|\CodeIgniter\HTTP\ResponseInterface|mixed
@throws \CodeIgniter\Router\Exceptions\RedirectException

Handles the main request logic and fires the controller .


protected function startBenchmark()
	{
		$this->startTime = microtime(true);

		$this->benchmark = Services::timer();
		$this->benchmark->start('total_execution', $this->startTime);
		$this->benchmark->start('bootstrap');
	}

protected function startBenchmark ( ) { $ this -> startTime = microtime ( true ) ; $ this -> benchmark = Services :: timer ( ) ; $ this -> benchmark -> start ( 'total_execution' , $ this -> startTime ) ; $ this -> benchmark -> start ( 'bootstrap' ) ; }

Start the Benchmark

The timer is used to display total script execution both in the
debug toolbar, and potentially on the displayed page.


protected function getResponseObject()
	{
		$this->response = Services::response($this->config);

		if (! is_cli() || ENVIRONMENT === 'testing')
		{
			$this->response->setProtocolVersion($this->request->getProtocolVersion());
		}

		// Assume success until proven otherwise.
		$this->response->setStatusCode(200);
	}

Get our Response object, and set some default values, including
the HTTP protocol version and a default successful response.

Get our Response object and set some default values including the HTTP protocol version and a default successful response .


protected function forceSecureAccess($duration = 31536000)
	{
		if ($this->config->forceGlobalSecureRequests !== true)
		{
			return;
		}

		force_https($duration, $this->request, $this->response);
	}

protected function forceSecureAccess ( $ duration = 31536000 ) { if ( $ this -> config -> forceGlobalSecureRequests !== true ) { return ; } force_https ( $ duration , $ this -> request , $ this -> response ) ; }

Force Secure Site Access? If the config value 'forceGlobalSecureRequests'
is true, will enforce that all requests to this site are made through
HTTPS. Will redirect the user to the current page with HTTPS, as well
as set the HTTP Strict Transport Security header for those browsers
that support it.

@param integer $duration How long the Strict Transport Security
should be enforced for this URL.

Force Secure Site Access? If the config value forceGlobalSecureRequests is true will enforce that all requests to this site are made through HTTPS . Will redirect the user to the current page with HTTPS as well as set the HTTP Strict Transport Security header for those browsers that support it .


public function displayCache($config)
	{
		if ($cachedResponse = cache()->get($this->generateCacheName($config)))
		{
			$cachedResponse = unserialize($cachedResponse);
			if (! is_array($cachedResponse) || ! isset($cachedResponse['output']) || ! isset($cachedResponse['headers']))
			{
				throw new Exception('Error unserializing page cache');
			}

			$headers = $cachedResponse['headers'];
			$output  = $cachedResponse['output'];

			// Clear all default headers
			foreach ($this->response->getHeaders() as $key => $val)
			{
				$this->response->removeHeader($key);
			}

			// Set cached headers
			foreach ($headers as $name => $value)
			{
				$this->response->setHeader($name, $value);
			}

			$output = $this->displayPerformanceMetrics($output);
			$this->response->setBody($output);

			return $this->response;
		}

		return false;
	}

public
function
displayCache
(
$
config
)
{
if
(
$
cachedResponse
=
cache
(
)
->
get
(
$
this
->
generateCacheName
(
$
config
)
)
)
{
$
cachedResponse
=
unserialize
(
$
cachedResponse
)
;
if
(
!
is_array
(
$
cachedResponse
)
||
!
isset
(
$
cachedResponse
[
'output'
]
)
||
!
isset
(
$
cachedResponse
[
'headers'
]
)
)
{
throw
new
Exception
(
'Error unserializing page cache'
)
;
}
$
headers
=
$
cachedResponse
[
'headers'
]
;
$
output
=
$
cachedResponse
[
'output'
]
;
// Clear all default headers
foreach
(
$
this
->
response
->
getHeaders
(
)
as
$
key
=>
$
val
)
{
$
this
->
response
->
removeHeader
(
$
key
)
;
}
// Set cached headers
foreach
(
$
headers
as
$
name
=>
$
value
)
{
$
this
->
response
->
setHeader
(
$
name
,
$
value
)
;
}
$
output
=
$
this
->
displayPerformanceMetrics
(
$
output
)
;
$
this
->
response
->
setBody
(
$
output
)
;
return
$
this
->
response
;
}
return
false
;
}

Determines if a response has been cached for the given URI.

@param \Config\Cache $config

@throws \Exception

@return boolean|\CodeIgniter\HTTP\ResponseInterface

Determines if a response has been cached for the given URI .


public function cachePage(Cache $config)
	{
		$headers = [];
		foreach ($this->response->getHeaders() as $header)
		{
			$headers[$header->getName()] = $header->getValueLine();
		}

		return cache()->save(
						$this->generateCacheName($config), serialize(['headers' => $headers, 'output' => $this->output]), static::$cacheTTL
		);
	}

public function cachePage ( Cache $ config ) { $ headers = [ ] ; foreach ( $ this -> response -> getHeaders ( ) as $ header ) { $ headers [ $ header -> getName ( ) ] = $ header -> getValueLine ( ) ; } return cache ( ) -> save ( $ this -> generateCacheName ( $ config ) , serialize ( [ 'headers' => $ headers , 'output' => $ this -> output ] ) , static :: $ cacheTTL ) ; }

Caches the full response from the current request. Used for
full-page caching for very high performance.

@param \Config\Cache $config

@return mixed

Caches the full response from the current request . Used for full - page caching for very high performance .


protected function generateCacheName($config): string
	{
		if (is_cli() && ! (ENVIRONMENT === 'testing'))
		{
			return md5($this->request->getPath());
		}

		$uri = $this->request->uri;

		if ($config->cacheQueryString)
		{
			$name = URI::createURIString(
							$uri->getScheme(), $uri->getAuthority(), $uri->getPath(), $uri->getQuery()
			);
		}
		else
		{
			$name = URI::createURIString(
							$uri->getScheme(), $uri->getAuthority(), $uri->getPath()
			);
		}

		return md5($name);
	}

protected function generateCacheName ( $ config ) : string { if ( is_cli ( ) && ! ( ENVIRONMENT === 'testing' ) ) { return md5 ( $ this -> request -> getPath ( ) ) ; } $ uri = $ this -> request -> uri ; if ( $ config -> cacheQueryString ) { $ name = URI :: createURIString ( $ uri -> getScheme ( ) , $ uri -> getAuthority ( ) , $ uri -> getPath ( ) , $ uri -> getQuery ( ) ) ; } else { $ name = URI :: createURIString ( $ uri -> getScheme ( ) , $ uri -> getAuthority ( ) , $ uri -> getPath ( ) ) ; } return md5 ( $ name ) ; }

Generates the cache name to use for our full-page caching.

@param $config

@return string

Generates the cache name to use for our full - page caching .


public function displayPerformanceMetrics(string $output): string
	{
		$this->totalTime = $this->benchmark->getElapsedTime('total_execution');

		$output = str_replace('{elapsed_time}', $this->totalTime, $output);

		return $output;
	}

public function displayPerformanceMetrics ( string $ output ) : string { $ this -> totalTime = $ this -> benchmark -> getElapsedTime ( 'total_execution' ) ; $ output = str_replace ( '{elapsed_time}' , $ this -> totalTime , $ output ) ; return $ output ; }

Replaces the memory_usage and elapsed_time tags.

@param string $output

@return string

Replaces the memory_usage and elapsed_time tags .


protected function tryToRouteIt(RouteCollectionInterface $routes = null)
	{
		if (empty($routes) || ! $routes instanceof RouteCollectionInterface)
		{
			require APPPATH . 'Config/Routes.php';
		}

		// $routes is defined in Config/Routes.php
		$this->router = Services::router($routes);

		$path = $this->determinePath();

		$this->benchmark->stop('bootstrap');
		$this->benchmark->start('routing');

		ob_start();

		$this->controller = $this->router->handle($path);
		$this->method     = $this->router->methodName();

		// If a {locale} segment was matched in the final route,
		// then we need to set the correct locale on our Request.
		if ($this->router->hasLocale())
		{
			$this->request->setLocale($this->router->getLocale());
		}

		$this->benchmark->stop('routing');

		return $this->router->getFilter();
	}

Try to Route It - As it sounds like, works with the router to
match a route against the current URI. If the route is a
"redirect route", will also handle the redirect.

@param RouteCollectionInterface $routes An collection interface to use in place
of the config file.

@return string
@throws \CodeIgniter\Router\Exceptions\RedirectException

Try to Route It - As it sounds like works with the router to match a route against the current URI . If the route is a redirect route will also handle the redirect .


protected function startController()
	{
		$this->benchmark->start('controller');
		$this->benchmark->start('controller_constructor');

		// Is it routed to a Closure?
		if (is_object($this->controller) && (get_class($this->controller) === 'Closure'))
		{
			$controller = $this->controller;
			return $controller(...$this->router->params());
		}

		// No controller specified - we don't know what to do now.
		if (empty($this->controller))
		{
			throw PageNotFoundException::forEmptyController();
		}

		// Try to autoload the class
		if (! class_exists($this->controller, true) || $this->method[0] === '_')
		{
			throw PageNotFoundException::forControllerNotFound($this->controller, $this->method);
		}
		else if (! method_exists($this->controller, '_remap') &&
				! is_callable([$this->controller, $this->method], false)
		)
		{
			throw PageNotFoundException::forMethodNotFound($this->method);
		}
	}

Now that everything has been setup, this method attempts to run the
controller method and make the script go. If it's not able to, will
show the appropriate Page Not Found error.

Now that everything has been setup this method attempts to run the controller method and make the script go . If it s not able to will show the appropriate Page Not Found error .


protected function createController()
	{
		$class = new $this->controller();
		$class->initController($this->request, $this->response, Services::logger());

		$this->benchmark->stop('controller_constructor');

		return $class;
	}

protected function createController ( ) { $ class = new $ this -> controller ( ) ; $ class -> initController ( $ this -> request , $ this -> response , Services :: logger ( ) ) ; $ this -> benchmark -> stop ( 'controller_constructor' ) ; return $ class ; }

Instantiates the controller class.

@return mixed


protected function runController($class)
	{
		if (method_exists($class, '_remap'))
		{
			$output = $class->_remap($this->method, ...$this->router->params());
		}
		else
		{
			$output = $class->{$this->method}(...$this->router->params());
		}

		$this->benchmark->stop('controller');

		return $output;
	}

protected function runController ( $ class ) { if ( method_exists ( $ class , '_remap' ) ) { $ output = $ class -> _remap ( $ this -> method , ... $ this -> router -> params ( ) ) ; } else { $ output = $ class -> { $ this -> method } ( ... $ this -> router -> params ( ) ) ; } $ this -> benchmark -> stop ( 'controller' ) ; return $ output ; }

Runs the controller, allowing for _remap methods to function.

@param mixed $class

@return mixed

Runs the controller allowing for _remap methods to function .


protected function gatherOutput($cacheConfig = null, $returned = null)
	{
		$this->output = ob_get_contents();
		// If buffering is not null.
		// Clean (erase) the output buffer and turn off output buffering
		if (ob_get_length())
		{
			ob_end_clean();
		}

		if ($returned instanceof DownloadResponse)
		{
			$this->response = $returned;
			return;
		}
		// If the controller returned a response object,
		// we need to grab the body from it so it can
		// be added to anything else that might have been
		// echoed already.
		// We also need to save the instance locally
		// so that any status code changes, etc, take place.
		if ($returned instanceof Response)
		{
			$this->response = $returned;
			$returned       = $returned->getBody();
		}

		if (is_string($returned))
		{
			$this->output .= $returned;
		}

		// Cache it without the performance metrics replaced
		// so that we can have live speed updates along the way.
		if (static::$cacheTTL > 0)
		{
			$this->cachePage($cacheConfig);
		}

		$this->output = $this->displayPerformanceMetrics($this->output);

		$this->response->setBody($this->output);
	}

Gathers the script output from the buffer, replaces some execution
time tag in the output and displays the debug toolbar, if required.

@param null $cacheConfig
@param null $returned

Gathers the script output from the buffer replaces some execution time tag in the output and displays the debug toolbar if required .


public function storePreviousURL($uri)
	{
		// This is mainly needed during testing...
		if (is_string($uri))
		{
			$uri = new URI($uri);
		}

		if (isset($_SESSION))
		{
			$_SESSION['_ci_previous_url'] = (string) $uri;
		}
	}

If we have a session object to use, store the current URI
as the previous URI. This is called just prior to sending the
response to the client, and will make it available next request.

This helps provider safer, more reliable previous_url() detection.

@param \CodeIgniter\HTTP\URI $uri

If we have a session object to use store the current URI as the previous URI . This is called just prior to sending the response to the client and will make it available next request .


public function spoofRequestMethod()
	{
		if (is_cli())
		{
			return;
		}

		// Only works with POSTED forms
		if ($this->request->getMethod() !== 'post')
		{
			return;
		}

		$method = $this->request->getPost('_method');

		if (empty($method))
		{
			return;
		}

		$this->request = $this->request->setMethod($method);
	}

public
function
spoofRequestMethod
(
)
{
if
(
is_cli
(
)
)
{
return
;
}
// Only works with POSTED forms
if
(
$
this
->
request
->
getMethod
(
)
!==
'post'
)
{
return
;
}
$
method
=
$
this
->
request
->
getPost
(
'_method'
)
;
if
(
empty
(
$
method
)
)
{
return
;
}
$
this
->
request
=
$
this
->
request
->
setMethod
(
$
method
)
;
}

Modifies the Request Object to use a different method if a POST
variable called _method is found.

Does not work on CLI commands.

Modifies the Request Object to use a different method if a POST variable called _method is found .


public static function getHandler($config, string $handler = null, string $backup = null)
	{
		if (! isset($config->validHandlers) || ! is_array($config->validHandlers))
		{
			throw CacheException::forInvalidHandlers();
		}

		if (! isset($config->handler) || ! isset($config->backupHandler))
		{
			throw CacheException::forNoBackup();
		}

		$handler = ! empty($handler) ? $handler : $config->handler;
		$backup  = ! empty($backup) ? $backup : $config->backupHandler;

		if (! array_key_exists($handler, $config->validHandlers) || ! array_key_exists($backup, $config->validHandlers))
		{
			throw CacheException::forHandlerNotFound();
		}

		// Get an instance of our handler.
		$adapter = new $config->validHandlers[$handler]($config);

		if (! $adapter->isSupported())
		{
			$adapter = new $config->validHandlers[$backup]($config);

			if (! $adapter->isSupported())
			{
				// Log stuff here, don't throw exception. No need to raise a fuss.
				// Fall back to the dummy adapter.
				$adapter = new $config->validHandlers['dummy']();
			}
		}

		$adapter->initialize();

		return $adapter;
	}

Attempts to create the desired cache handler, based upon the

@param $config
@param string $handler
@param string $backup

@return \CodeIgniter\Cache\CacheInterface

Attempts to create the desired cache handler based upon the


protected function createAliasFromTable(string $item): string
	{
		if (strpos($item, '.') !== false)
		{
			$item = explode('.', $item);

			return end($item);
		}

		return $item;
	}

protected function createAliasFromTable ( string $ item ) : string { if ( strpos ( $ item , '.' ) !== false ) { $ item = explode ( '.' , $ item ) ; return end ( $ item ) ; } return $ item ; }

Determines the alias name based on the table

@param string $item

@return string


public function whereNotIn(string $key = null, array $values = null, bool $escape = null)
	{
		return $this->_whereIn($key, $values, true, 'AND ', $escape);
	}

public
function
whereNotIn
(
string
$
key
=
,
array
$
values
=
,
bool
$
escape
=
)
{
return
$
this
->
_whereIn
(
$
key
,
$
values
,
true
,
'AND '
,
$
escape
)
;
}

WHERE NOT IN

Generates a WHERE field NOT IN('item', 'item') SQL query,
joined with 'AND' if appropriate.

@param string  $key    The field to search
@param array   $values The values searched on
@param boolean $escape

@return BaseBuilder


protected function _whereIn(string $key = null, array $values = null, bool $not = false, string $type = 'AND ', bool $escape = null)
	{
		if ($key === null || $values === null)
		{
			return $this;
		}

		is_bool($escape) || $escape = $this->db->protectIdentifiers;

		$ok = $key;

		if ($escape === true)
		{
			$key = $this->db->protectIdentifiers($key);
		}

		$not = ($not) ? ' NOT' : '';

		$where_in = array_values($values);
		$ok       = $this->setBind($ok, $where_in, $escape);

		$prefix = empty($this->QBWhere) ? $this->groupGetType('') : $this->groupGetType($type);

		$where_in = [
			'condition' => $prefix . $key . $not . " IN :{$ok}:",
			'escape'    => false,
		];

		$this->QBWhere[] = $where_in;

		return $this;
	}

protected
function
_whereIn
(
string
$
key
=
,
array
$
values
=
,
bool
$
not
=
false
,
string
$
type
=
'AND '
,
bool
$
escape
=
)
{
if
(
$
key
===
||
$
values
===
)
{
return
$
this
;
}
is_bool
(
$
escape
)
||
$
escape
=
$
this
->
db
->
protectIdentifiers
;
$
ok
=
$
key
;
if
(
$
escape
===
true
)
{
$
key
=
$
this
->
db
->
protectIdentifiers
(
$
key
)
;
}
$
not
=
(
$
not
)
' NOT'
:
''
;
$
where_in
=
array_values
(
$
values
)
;
$
ok
=
$
this
->
setBind
(
$
ok
,
$
where_in
,
$
escape
)
;
$
prefix
=
empty
(
$
this
->
QBWhere
)
$
this
->
groupGetType
(
''
)
:
$
this
->
groupGetType
(
$
type
)
;
$
where_in
=
[
'condition'
=>
$
prefix
.
$
key
.
$
not
.
" IN :{$ok}:"
,
'escape'
=>
false
,
]
;
$
this
->
QBWhere
[
]
=
$
where_in
;
return
$
this
;
}

Internal WHERE IN

@used-by WhereIn()
@used-by orWhereIn()
@used-by whereNotIn()
@used-by orWhereNotIn()

@param string  $key    The field to search
@param array   $values The values searched on
@param boolean $not    If the statement would be IN or NOT IN
@param string  $type
@param boolean $escape

@return BaseBuilder


protected function _like_statement(string $prefix = null, string $column, string $not = null, string $bind, bool $insensitiveSearch = false): string
	{
		$like_statement = "{$prefix} {$column} {$not} LIKE :{$bind}:";

		if ($insensitiveSearch === true)
		{
			$like_statement = "{$prefix} LOWER({$column}) {$not} LIKE :{$bind}:";
		}

		return $like_statement;
	}

Platform independent LIKE statement builder.

@param string    $prefix
@param string    $column
@param string    $not
@param string    $bind
@param boolean   $insensitiveSearch

@return string     $like_statement

Platform independent LIKE statement builder .


public function groupStart(string $not = '', string $type = 'AND ')
	{
		$type = $this->groupGetType($type);

		$this->QBWhereGroupStarted = true;
		$prefix                    = empty($this->QBWhere) ? '' : $type;
		$where                     = [
			'condition' => $prefix . $not . str_repeat(' ', ++ $this->QBWhereGroupCount) . ' (',
			'escape'    => false,
		];

		$this->QBWhere[] = $where;

		return $this;
	}

public
function
groupStart
(
string
$
not
=
''
,
string
$
type
=
'AND '
)
{
$
type
=
$
this
->
groupGetType
(
$
type
)
;
$
this
->
QBWhereGroupStarted
=
true
;
$
prefix
=
empty
(
$
this
->
QBWhere
)
''
:
$
type
;
$
where
=
[
'condition'
=>
$
prefix
.
$
not
.
str_repeat
(
' '
,
++
$
this
->
QBWhereGroupCount
)
.
' ('
,
'escape'
=>
false
,
]
;
$
this
->
QBWhere
[
]
=
$
where
;
return
$
this
;
}

Starts a query group.

@param string $not  (Internal use only)
@param string $type (Internal use only)

@return BaseBuilder


public function groupEnd()
	{
		$this->QBWhereGroupStarted = false;
		$where                     = [
			'condition' => str_repeat(' ', $this->QBWhereGroupCount -- ) . ')',
			'escape'    => false,
		];

		$this->QBWhere[] = $where;

		return $this;
	}

public
function
groupEnd
(
)
{
$
this
->
QBWhereGroupStarted
=
false
;
$
where
=
[
'condition'
=>
str_repeat
(
' '
,
$
this
->
QBWhereGroupCount
)
.
')'
,
'escape'
=>
false
,
]
;
$
this
->
QBWhere
[
]
=
$
where
;
return
$
this
;
}


public function offset(int $offset)
	{
		if (! empty($offset))
		{
			$this->QBOffset = (int) $offset;
		}

		return $this;
	}

public function offset ( int $ offset ) { if ( ! empty ( $ offset ) ) { $ this -> QBOffset = ( int ) $ offset ; } return $ this ; }

Sets the OFFSET value

@param integer $offset OFFSET value

@return BaseBuilder


public function set($key, string $value = '', bool $escape = null)
	{
		$key = $this->objectToArray($key);

		if (! is_array($key))
		{
			$key = [$key => $value];
		}

		$escape = is_bool($escape) ? $escape : $this->db->protectIdentifiers;

		foreach ($key as $k => $v)
		{
			if ($escape)
			{
				$bind = $this->setBind($k, $v, $escape);
				$this->QBSet[$this->db->protectIdentifiers($k, false, $escape)] = ":$bind:";
			}
			else
			{
				$this->QBSet[$this->db->protectIdentifiers($k, false, $escape)] = $v;
			}
		}

		return $this;
	}

public function set ( $ key , string $ value = '' , bool $ escape = null ) { $ key = $ this -> objectToArray ( $ key ) ; if ( ! is_array ( $ key ) ) { $ key = [ $ key => $ value ] ; } $ escape = is_bool ( $ escape ) ? $ escape : $ this -> db -> protectIdentifiers ; foreach ( $ key as $ k => $ v ) { if ( $ escape ) { $ bind = $ this -> setBind ( $ k , $ v , $ escape ) ; $ this -> QBSet [ $ this -> db -> protectIdentifiers ( $ k , false , $ escape ) ] = ":$bind:" ; } else { $ this -> QBSet [ $ this -> db -> protectIdentifiers ( $ k , false , $ escape ) ] = $ v ; } } return $ this ; }

The "set" function.

Allows key/value pairs to be set for insert(), update() or replace().

@param string|array|object $key    Field name, or an array of field/value pairs
@param string              $value  Field value, if $key is a single field
@param boolean             $escape Whether to escape values and identifiers

@return BaseBuilder


public function getCompiledSelect(bool $reset = true): string
	{
		$select = $this->compileSelect();

		if ($reset === true)
		{
			$this->resetSelect();
		}

		return $this->compileFinalQuery($select);
	}

public function getCompiledSelect ( bool $ reset = true ) : string { $ select = $ this -> compileSelect ( ) ; if ( $ reset === true ) { $ this -> resetSelect ( ) ; } return $ this -> compileFinalQuery ( $ select ) ; }

Get SELECT query string

Compiles a SELECT query string and returns the sql.

@param boolean $reset TRUE: resets QB values; FALSE: leave QB values alone

@return string


protected function compileFinalQuery(string $sql): string
	{
		$query = new Query($this->db);
		$query->setQuery($sql, $this->binds, false);

		if (! empty($this->db->swapPre) && ! empty($this->db->DBPrefix))
		{
			$query->swapPrefix($this->db->DBPrefix, $this->db->swapPre);
		}

		return $query->getQuery();
	}

protected function compileFinalQuery ( string $ sql ) : string { $ query = new Query ( $ this -> db ) ; $ query -> setQuery ( $ sql , $ this -> binds , false ) ; if ( ! empty ( $ this -> db -> swapPre ) && ! empty ( $ this -> db -> DBPrefix ) ) { $ query -> swapPrefix ( $ this -> db -> DBPrefix , $ this -> db -> swapPre ) ; } return $ query -> getQuery ( ) ; }

Returns a finalized, compiled query string with the bindings
inserted and prefixes swapped out.

@param string $sql

@return string

Returns a finalized compiled query string with the bindings inserted and prefixes swapped out .


public function countAll(bool $reset = true, bool $test = false)
	{
		$table = $this->QBFrom[0];

		$sql = $this->countString . $this->db->escapeIdentifiers('numrows') . ' FROM ' .
				$this->db->protectIdentifiers($table, true, null, false);

		if ($test)
		{
			return $sql;
		}

		$query = $this->db->query($sql, null, false);
		if (empty($query->getResult()))
		{
			return 0;
		}

		$query = $query->getRow();

		if ($reset === true)
		{
			$this->resetSelect();
		}

		return (int) $query->numrows;
	}

public
function
countAll
(
bool
$
reset
=
true
,
bool
$
test
=
false
)
{
$
table
=
$
this
->
QBFrom
[
0
]
;
$
sql
=
$
this
->
countString
.
$
this
->
db
->
escapeIdentifiers
(
'numrows'
)
.
' FROM '
.
$
this
->
db
->
protectIdentifiers
(
$
table
,
true
,
,
false
)
;
if
(
$
test
)
{
return
$
sql
;
}
$
query
=
$
this
->
db
->
query
(
$
sql
,
,
false
)
;
if
(
empty
(
$
query
->
getResult
(
)
)
)
{
return
0
;
}
$
query
=
$
query
->
getRow
(
)
;
if
(
$
reset
===
true
)
{
$
this
->
resetSelect
(
)
;
}
return
(
int
)
$
query
->
numrows
;
}

"Count All" query

Generates a platform-specific query string that counts all records in
the specified database

@param boolean $reset Are we want to clear query builder values?
@param boolean $test  Are we running automated tests?

@return integer|string when $test = true


public function countAllResults(bool $reset = true, bool $test = false)
	{
		// ORDER BY usage is often problematic here (most notably
		// on Microsoft SQL Server) and ultimately unnecessary
		// for selecting COUNT(*) ...
		$orderBy = [];
		if (! empty($this->QBOrderBy))
		{
			$orderBy         = $this->QBOrderBy;
			$this->QBOrderBy = null;
		}

		$sql = ($this->QBDistinct === true)
			?
			$this->countString . $this->db->protectIdentifiers('numrows') . "\nFROM (\n" . $this->compileSelect() . "\n) CI_count_all_results"
			:
			$this->compileSelect($this->countString . $this->db->protectIdentifiers('numrows'));

		if ($test)
		{
			return $sql;
		}

		$result = $this->db->query($sql, $this->binds, false);

		if ($reset === true)
		{
			$this->resetSelect();
		}
		// If we've previously reset the QBOrderBy values, get them back
		elseif (! isset($this->QBOrderBy))
		{
			$this->QBOrderBy = $orderBy ?? [];
		}

		$row = (! $result instanceof ResultInterface)
			? null
			: $result->getRow();

		if (empty($row))
		{
			return 0;
		}

		return (int) $row->numrows;
	}

"Count All Results" query

Generates a platform-specific query string that counts all records
returned by an Query Builder query.

@param boolean $reset
@param boolean $test  The reset clause

@return integer|string when $test = true


protected function _insertBatch(string $table, array $keys, array $values): string
	{
		return 'INSERT INTO ' . $table . ' (' . implode(', ', $keys) . ') VALUES ' . implode(', ', $values);
	}

protected
function
_insertBatch
(
string
$
table
,
array
$
keys
,
array
$
values
)
:
string
{
return
'INSERT INTO '
.
$
table
.
' ('
.
implode
(
', '
,
$
keys
)
.
') VALUES '
.
implode
(
', '
,
$
values
)
;
}

Insert batch statement

Generates a platform-specific insert string from the supplied data.

@param string $table  Table name
@param array  $keys   INSERT keys
@param array  $values INSERT values

@return string


public function getCompiledInsert(bool $reset = true): string
	{
		if ($this->validateInsert() === false)
		{
			return false;
		}

		$sql = $this->_insert(
				$this->db->protectIdentifiers(
						$this->QBFrom[0], true, null, false
				), array_keys($this->QBSet), array_values($this->QBSet)
		);

		if ($reset === true)
		{
			$this->resetWrite();
		}

		return $this->compileFinalQuery($sql);
	}

public function getCompiledInsert ( bool $ reset = true ) : string { if ( $ this -> validateInsert ( ) === false ) { return false ; } $ sql = $ this -> _insert ( $ this -> db -> protectIdentifiers ( $ this -> QBFrom [ 0 ] , true , null , false ) , array_keys ( $ this -> QBSet ) , array_values ( $ this -> QBSet ) ) ; if ( $ reset === true ) { $ this -> resetWrite ( ) ; } return $ this -> compileFinalQuery ( $ sql ) ; }

Get INSERT query string

Compiles an insert query and returns the sql

@param boolean $reset TRUE: reset QB values; FALSE: leave QB values alone

@return string


public function getCompiledUpdate(bool $reset = true): string
	{
		if ($this->validateUpdate() === false)
		{
			return false;
		}

		$sql = $this->_update($this->QBFrom[0], $this->QBSet);

		if ($reset === true)
		{
			$this->resetWrite();
		}

		return $this->compileFinalQuery($sql);
	}

public function getCompiledUpdate ( bool $ reset = true ) : string { if ( $ this -> validateUpdate ( ) === false ) { return false ; } $ sql = $ this -> _update ( $ this -> QBFrom [ 0 ] , $ this -> QBSet ) ; if ( $ reset === true ) { $ this -> resetWrite ( ) ; } return $ this -> compileFinalQuery ( $ sql ) ; }

Get UPDATE query string

Compiles an update query and returns the sql

@param boolean $reset TRUE: reset QB values; FALSE: leave QB values alone

@return string


public function getCompiledDelete(bool $reset = true): string
	{
		$table = $this->QBFrom[0];

		$sql = $this->delete($table, '', $reset, true);

		return $this->compileFinalQuery($sql);
	}

public function getCompiledDelete ( bool $ reset = true ) : string { $ table = $ this -> QBFrom [ 0 ] ; $ sql = $ this -> delete ( $ table , '' , $ reset , true ) ; return $ this -> compileFinalQuery ( $ sql ) ; }

Get DELETE query string

Compiles a delete query string and returns the sql

@param boolean $reset TRUE: reset QB values; FALSE: leave QB values alone

@return string


public function decrement(string $column, int $value = 1)
	{
		$column = $this->db->protectIdentifiers($column);

		$sql = $this->_update($this->QBFrom[0], [$column => "{$column}-{$value}"]);

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

public function decrement ( string $ column , int $ value = 1 ) { $ column = $ this -> db -> protectIdentifiers ( $ column ) ; $ sql = $ this -> _update ( $ this -> QBFrom [ 0 ] , [ $ column => "{$column}-{$value}" ] ) ; return $ this -> db -> query ( $ sql , $ this -> binds , false ) ; }

Decrements a numeric column by the specified value.

@param string  $column
@param integer $value

@return boolean

Decrements a numeric column by the specified value .


protected function compileSelect($select_override = false): string
	{
		// Write the "select" portion of the query
		if ($select_override !== false)
		{
			$sql = $select_override;
		}
		else
		{
			$sql = ( ! $this->QBDistinct) ? 'SELECT ' : 'SELECT DISTINCT ';

			if (empty($this->QBSelect))
			{
				$sql .= '*';
			}
			else
			{
				// Cycle through the "select" portion of the query and prep each column name.
				// The reason we protect identifiers here rather than in the select() function
				// is because until the user calls the from() function we don't know if there are aliases
				foreach ($this->QBSelect as $key => $val)
				{
					$no_escape            = $this->QBNoEscape[$key] ?? null;
					$this->QBSelect[$key] = $this->db->protectIdentifiers($val, false, $no_escape);
				}

				$sql .= implode(', ', $this->QBSelect);
			}
		}

		// Write the "FROM" portion of the query
		if (! empty($this->QBFrom))
		{
			$sql .= "\nFROM " . $this->_fromTables();
		}

		// Write the "JOIN" portion of the query
		if (! empty($this->QBJoin))
		{
			$sql .= "\n" . implode("\n", $this->QBJoin);
		}

		$sql .= $this->compileWhereHaving('QBWhere')
				. $this->compileGroupBy()
				. $this->compileWhereHaving('QBHaving')
				. $this->compileOrderBy(); // ORDER BY
		// LIMIT
		if ($this->QBLimit)
		{
			return $this->_limit($sql . "\n");
		}

		return $sql;
	}

Compile the SELECT statement

Generates a query string based on which functions were used.
Should not be called directly.

@param mixed $select_override

@return string


protected function compileWhereHaving(string $qb_key): string
	{
		if (! empty($this->$qb_key))
		{
			for ($i = 0, $c = count($this->$qb_key); $i < $c; $i ++)
			{
				// Is this condition already compiled?
				if (is_string($this->{$qb_key}[$i]))
				{
					continue;
				}
				elseif ($this->{$qb_key}[$i]['escape'] === false)
				{
					$this->{$qb_key}[$i] = $this->{$qb_key}[$i]['condition'];
					continue;
				}

				// Split multiple conditions
				$conditions = preg_split(
						'/((?:^|\s+)AND\s+|(?:^|\s+)OR\s+)/i', $this->{$qb_key}[$i]['condition'], -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY
				);

				for ($ci = 0, $cc = count($conditions); $ci < $cc; $ci ++)
				{
					if (($op = $this->getOperator($conditions[$ci])) === false
							|| ! preg_match('/^(\(?)(.*)(' . preg_quote($op, '/') . ')\s*(.*(?<!\)))?(\)?)$/i', $conditions[$ci], $matches)
					)
					{
						continue;
					}

					// $matches = array(
					//	0 => '(test <= foo)',	/* the whole thing */
					//	1 => '(',		/* optional */
					//	2 => 'test',		/* the field name */
					//	3 => ' <= ',		/* $op */
					//	4 => 'foo',		/* optional, if $op is e.g. 'IS NULL' */
					//	5 => ')'		/* optional */
					// );

					if (! empty($matches[4]))
					{
						$matches[4] = ' ' . $matches[4];
					}

					$conditions[$ci] = $matches[1] . $this->db->protectIdentifiers(trim($matches[2]))
							. ' ' . trim($matches[3]) . $matches[4] . $matches[5];
				}

				$this->{$qb_key}[$i] = implode('', $conditions);
			}

			return ($qb_key === 'QBHaving' ? "\nHAVING " : "\nWHERE ")
					. implode("\n", $this->$qb_key);
		}

		return '';
	}

Compile WHERE, HAVING statements

Escapes identifiers in WHERE and HAVING statements at execution time.

Required so that aliases are tracked properly, regardless of whether
where(), orWhere(), having(), orHaving are called prior to from(),
join() and prefixTable is added only if needed.

@param string $qb_key 'QBWhere' or 'QBHaving'

@return string    SQL statement


protected function compileGroupBy(): string
	{
		if (! empty($this->QBGroupBy))
		{
			for ($i = 0, $c = count($this->QBGroupBy); $i < $c; $i ++)
			{
				// Is it already compiled?
				if (is_string($this->QBGroupBy[$i]))
				{
					continue;
				}

				$this->QBGroupBy[$i] = ($this->QBGroupBy[$i]['escape'] === false ||
						$this->isLiteral($this->QBGroupBy[$i]['field'])) ? $this->QBGroupBy[$i]['field'] : $this->db->protectIdentifiers($this->QBGroupBy[$i]['field']);
			}

			return "\nGROUP BY " . implode(', ', $this->QBGroupBy);
		}

		return '';
	}

protected
function
compileGroupBy
(
)
:
string
{
if
(
!
empty
(
$
this
->
QBGroupBy
)
)
{
for
(
$
i
=
0
,
$
c
=
count
(
$
this
->
QBGroupBy
)
;
$
i
<
$
c
;
$
i
++
)
{
// Is it already compiled?
if
(
is_string
(
$
this
->
QBGroupBy
[
$
i
]
)
)
{
continue
;
}
$
this
->
QBGroupBy
[
$
i
]
=
(
$
this
->
QBGroupBy
[
$
i
]
[
'escape'
]
===
false
||
$
this
->
isLiteral
(
$
this
->
QBGroupBy
[
$
i
]
[
'field'
]
)
)
$
this
->
QBGroupBy
[
$
i
]
[
'field'
]
:
$
this
->
db
->
protectIdentifiers
(
$
this
->
QBGroupBy
[
$
i
]
[
'field'
]
)
;
}
return
"\nGROUP BY "
.
implode
(
', '
,
$
this
->
QBGroupBy
)
;
}
return
''
;
}

Compile GROUP BY

Escapes identifiers in GROUP BY statements at execution time.

Required so that aliases are tracked properly, regardless of whether
groupBy() is called prior to from(), join() and prefixTable is added
only if needed.

@return string    SQL statement


protected function compileOrderBy(): string
	{
		if (is_array($this->QBOrderBy) && ! empty($this->QBOrderBy))
		{
			for ($i = 0, $c = count($this->QBOrderBy); $i < $c; $i ++)
			{
				if ($this->QBOrderBy[$i]['escape'] !== false && ! $this->isLiteral($this->QBOrderBy[$i]['field']))
				{
					$this->QBOrderBy[$i]['field'] = $this->db->protectIdentifiers($this->QBOrderBy[$i]['field']);
				}

				$this->QBOrderBy[$i] = $this->QBOrderBy[$i]['field'] . $this->QBOrderBy[$i]['direction'];
			}

			return $this->QBOrderBy = "\nORDER BY " . implode(', ', $this->QBOrderBy);
		}
		elseif (is_string($this->QBOrderBy))
		{
			return $this->QBOrderBy;
		}

		return '';
	}

protected
function
compileOrderBy
(
)
:
string
{
if
(
is_array
(
$
this
->
QBOrderBy
)
&&
!
empty
(
$
this
->
QBOrderBy
)
)
{
for
(
$
i
=
0
,
$
c
=
count
(
$
this
->
QBOrderBy
)
;
$
i
<
$
c
;
$
i
++
)
{
if
(
$
this
->
QBOrderBy
[
$
i
]
[
'escape'
]
!==
false
&&
!
$
this
->
isLiteral
(
$
this
->
QBOrderBy
[
$
i
]
[
'field'
]
)
)
{
$
this
->
QBOrderBy
[
$
i
]
[
'field'
]
=
$
this
->
db
->
protectIdentifiers
(
$
this
->
QBOrderBy
[
$
i
]
[
'field'
]
)
;
}
$
this
->
QBOrderBy
[
$
i
]
=
$
this
->
QBOrderBy
[
$
i
]
[
'field'
]
.
$
this
->
QBOrderBy
[
$
i
]
[
'direction'
]
;
}
return
$
this
->
QBOrderBy
=
"\nORDER BY "
.
implode
(
', '
,
$
this
->
QBOrderBy
)
;
}
elseif
(
is_string
(
$
this
->
QBOrderBy
)
)
{
return
$
this
->
QBOrderBy
;
}
return
''
;
}

Compile ORDER BY

Escapes identifiers in ORDER BY statements at execution time.

Required so that aliases are tracked properly, regardless of whether
orderBy() is called prior to from(), join() and prefixTable is added
only if needed.

@return string    SQL statement


protected function getOperator(string $str, bool $list = false)
	{
		static $_operators;

		if (empty($_operators))
		{
			$_les       = ($this->db->likeEscapeStr !== '') ? '\s+' . preg_quote(trim(sprintf($this->db->likeEscapeStr, $this->db->likeEscapeChar)), '/') : '';
			$_operators = [
				'\s*(?:<|>|!)?=\s*', // =, <=, >=, !=
				'\s*<>?\s*', // <, <>
				'\s*>\s*', // >
				'\s+IS NULL', // IS NULL
				'\s+IS NOT NULL', // IS NOT NULL
				'\s+EXISTS\s*\(.*\)', // EXISTS(sql)
				'\s+NOT EXISTS\s*\(.*\)', // NOT EXISTS(sql)
				'\s+BETWEEN\s+', // BETWEEN value AND value
				'\s+IN\s*\(.*\)', // IN(list)
				'\s+NOT IN\s*\(.*\)', // NOT IN (list)
				'\s+LIKE\s+\S.*(' . $_les . ')?', // LIKE 'expr'[ ESCAPE '%s']
				'\s+NOT LIKE\s+\S.*(' . $_les . ')?', // NOT LIKE 'expr'[ ESCAPE '%s']
			];
		}

		return preg_match_all('/' . implode('|', $_operators) . '/i', $str, $match) ? ($list ? $match[0] : $match[0][count($match[0]) - 1]) : false;
	}

protected
function
getOperator
(
string
$
str
,
bool
$
list
=
false
)
{
static
$
_operators
;
if
(
empty
(
$
_operators
)
)
{
$
_les
=
(
$
this
->
db
->
likeEscapeStr
!==
''
)
'\s+'
.
preg_quote
(
trim
(
sprintf
(
$
this
->
db
->
likeEscapeStr
,
$
this
->
db
->
likeEscapeChar
)
)
,
'/'
)
:
''
;
$
_operators
=
[
'\s*(?:<|>|!)?=\s*'
,
// =, <=, >=, !=
'\s*<>?\s*'
,
// <, <>
'\s*>\s*'
,
// >
'\s+IS NULL'
,
// IS NULL
'\s+IS NOT NULL'
,
// IS NOT NULL
'\s+EXISTS\s*\(.*\)'
,
// EXISTS(sql)
'\s+NOT EXISTS\s*\(.*\)'
,
// NOT EXISTS(sql)
'\s+BETWEEN\s+'
,
// BETWEEN value AND value
'\s+IN\s*\(.*\)'
,
// IN(list)
'\s+NOT IN\s*\(.*\)'
,
// NOT IN (list)
'\s+LIKE\s+\S.*('
.
$
_les
.
')?'
,
// LIKE 'expr'[ ESCAPE '%s']
'\s+NOT LIKE\s+\S.*('
.
$
_les
.
')?'
,
// NOT LIKE 'expr'[ ESCAPE '%s']
]
;
}
return
preg_match_all
(
'/'
.
implode
(
'|'
,
$
_operators
)
.
'/i'
,
$
str
,
$
match
)
(
$
list
$
match
[
0
]
:
$
match
[
0
]
[
count
(
$
match
[
0
]
)
1
]
)
:
false
;
}

Returns the SQL string operator

@param string  $str
@param boolean $list

@return mixed


protected function renderTimeline(array $collectors, $startTime, int $segmentCount, int $segmentDuration, array &$styles): string
	{
		$displayTime = $segmentCount * $segmentDuration;
		$rows = $this->collectTimelineData($collectors);
		$output = '';
		$styleCount = 0;

		foreach ($rows as $row)
		{
			$output .= '
';
			$output .= "{$row['name']}	";
			$output .= "{$row['component']}	";
			$output .= "" . number_format($row['duration'] * 1000, 2) . ' ms	';
			$output .= "";

			$offset = ((($row['start'] - $startTime) * 1000) / $displayTime) * 100;
			$length = (($row['duration'] * 1000) / $displayTime) * 100;

			$styles['debug-bar-timeline-' . $styleCount] = "left: {$offset}%; width: {$length}%;";
			$output .= "";
			$output .= '	';
			$output .= '
';

			$styleCount++;
		}

		return $output;
	}

"<span class='timer debug-bar-timeline-{$styleCount}' title='"

Called within the view to display the timeline itself.

@param array   $collectors
@param float   $startTime
@param integer $segmentCount
@param integer $segmentDuration
@param array   $styles

@return string

Called within the view to display the timeline itself .


protected function collectTimelineData($collectors): array
	{
		$data = [];

		// Collect it
		foreach ($collectors as $collector)
		{
			if (! $collector['hasTimelineData'])
			{
				continue;
			}

			$data = array_merge($data, $collector['timelineData']);
		}

		// Sort it

		return $data;
	}

protected
function
collectTimelineData
(
$
collectors
)
:
array
{
$
data
=
[
]
;
// Collect it
foreach
(
$
collectors
as
$
collector
)
{
if
(
!
$
collector
[
'hasTimelineData'
]
)
{
continue
;
}
$
data
=
array_merge
(
$
data
,
$
collector
[
'timelineData'
]
)
;
}
// Sort it
return
$
data
;
}

Returns a sorted array of timeline data arrays from the collectors.

@param array $collectors

@return array

Returns a sorted array of timeline data arrays from the collectors .


protected function collectVarData(): array
	{
		$data = [];

		foreach ($this->collectors as $collector)
		{
			if (! $collector->hasVarData())
			{
				continue;
			}

			$data = array_merge($data, $collector->getVarData());
		}

		return $data;
	}

protected function collectVarData ( ) : array { $ data = [ ] ; foreach ( $ this -> collectors as $ collector ) { if ( ! $ collector -> hasVarData ( ) ) { continue ; } $ data = array_merge ( $ data , $ collector -> getVarData ( ) ) ; } return $ data ; }

Returns an array of data from all of the modules
that should be displayed in the 'Vars' tab.

@return array

Returns an array of data from all of the modules that should be displayed in the Vars tab .


protected function roundTo(float $number, int $increments = 5): float
	{
		$increments = 1 / $increments;

		return (ceil($number * $increments) / $increments);
	}

protected function roundTo ( float $ number , int $ increments = 5 ) : float { $ increments = 1 / $ increments ; return ( ceil ( $ number * $ increments ) / $ increments ) ; }

Rounds a number to the nearest incremental value.

@param float   $number
@param integer $increments

@return float

Rounds a number to the nearest incremental value .


public function copy(string $targetPath, string $targetName = null, int $perms = 0644): bool
	{
		$targetPath = rtrim($targetPath, '/ ') . '/';

		$targetName = is_null($targetName) ? $this->getFilename() : $targetName;

		if (empty($targetName))
		{
			throw ImageException::forInvalidFile($targetName);
		}

		if (! is_dir($targetPath))
		{
			mkdir($targetName, 0755, true);
		}

		if (! copy($this->getPathname(), "{$targetPath}{$targetName}"))
		{
			throw ImageException::forCopyError($targetPath);
		}

		chmod("{$targetPath}/{$targetName}", $perms);

		return true;
	}

public
function
copy
(
string
$
targetPath
,
string
$
targetName
=
,
int
$
perms
=
0644
)
:
bool
{
$
targetPath
=
rtrim
(
$
targetPath
,
'/ '
)
.
'/'
;
$
targetName
=
is_null
(
$
targetName
)
$
this
->
getFilename
(
)
:
$
targetName
;
if
(
empty
(
$
targetName
)
)
{
throw
ImageException
::
forInvalidFile
(
$
targetName
)
;
}
if
(
!
is_dir
(
$
targetPath
)
)
{
mkdir
(
$
targetName
,
0755
,
true
)
;
}
if
(
!
copy
(
$
this
->
getPathname
(
)
,
"{$targetPath}{$targetName}"
)
)
{
throw
ImageException
::
forCopyError
(
$
targetPath
)
;
}
chmod
(
"{$targetPath}/{$targetName}"
,
$
perms
)
;
return
true
;
}

Makes a copy of itself to the new location. If no filename is provided
it will use the existing filename.

@param string      $targetPath The directory to store the file in
@param string|null $targetName The new name of the copied file.
@param integer     $perms      File permissions to be applied after copy.

@return boolean

Makes a copy of itself to the new location . If no filename is provided it will use the existing filename .


public function getProperties(bool $return = false)
	{
		$path = $this->getPathname();

		$vals  = getimagesize($path);
		$types = [
			1 => 'gif',
			2 => 'jpeg',
			3 => 'png',
		];

		$mime = 'image/' . ($types[$vals[2]] ?? 'jpg');

		if ($return === true)
		{
			return [
				'width'      => $vals[0],
				'height'     => $vals[1],
				'image_type' => $vals[2],
				'size_str'   => $vals[3],
				'mime_type'  => $mime,
			];
		}

		$this->origWidth  = $vals[0];
		$this->origHeight = $vals[1];
		$this->imageType  = $vals[2];
		$this->sizeStr    = $vals[3];
		$this->mime       = $mime;

		return true;
	}

public function getProperties ( bool $ return = false ) { $ path = $ this -> getPathname ( ) ; $ vals = getimagesize ( $ path ) ; $ types = [ 1 => 'gif' , 2 => 'jpeg' , 3 => 'png' , ] ; $ mime = 'image/' . ( $ types [ $ vals [ 2 ] ] ?? 'jpg' ) ; if ( $ return === true ) { return [ 'width' => $ vals [ 0 ] , 'height' => $ vals [ 1 ] , 'image_type' => $ vals [ 2 ] , 'size_str' => $ vals [ 3 ] , 'mime_type' => $ mime , ] ; } $ this -> origWidth = $ vals [ 0 ] ; $ this -> origHeight = $ vals [ 1 ] ; $ this -> imageType = $ vals [ 2 ] ; $ this -> sizeStr = $ vals [ 3 ] ; $ this -> mime = $ mime ; return true ; }

Get image properties

A helper function that gets info about the file

@param boolean $return

@return mixed