Implemented many CodeIgniter classes.

Preparing for Factory Build
This commit is contained in:
Abel Hoogeveen 2016-05-24 12:05:29 +02:00
parent 02206f4bda
commit 3343c08594
19 changed files with 3940 additions and 125 deletions

View File

@ -5,10 +5,56 @@ return array(
'SITE_DOMAIN' => '',
'SERVER_NAME' => '',
'SITE_LOGO_URL' => '',
'administrator_mail' => '',
'default_controller' => 'standard',
'default_function' => 'index',
'application_prefix' => 'MY_',
'charset' => 'utf8',
'language' => 'english'
'charset' => 'utf-8',
'language' => 'english',
/*
|--------------------------------------------------------------------------
| Cookie Related Variables
|--------------------------------------------------------------------------
|
| 'cookie_prefix' = Set a cookie name prefix if you need to avoid collisions
| 'cookie_domain' = Set to .your-domain.com for site-wide cookies
| 'cookie_path' = Typically will be a forward slash
| 'cookie_secure' = Cookie will only be set if a secure HTTPS connection exists.
| 'cookie_httponly' = Cookie will only be accessible via HTTP(S) (no javascript)
|
| Note: These settings (with the exception of 'cookie_prefix' and
| 'cookie_httponly') will also affect sessions.
|
*/
'cookie_prefix' => '',
'cookie_domain' => '',
'cookie_path' => '/',
'cookie_secure' => FALSE,
'cookie_httponly' => FALSE,
/*
|--------------------------------------------------------------------------
| Output Compression
|--------------------------------------------------------------------------
|
| Enables Gzip output compression for faster page loads. When enabled,
| the output class will test whether your server supports Gzip.
| Even if it does, however, not all browsers support compression
| so enable only if you are reasonably sure your visitors can handle it.
|
| Only used if zlib.output_compression is turned off in your php.ini.
| Please do not use it together with httpd-level output compression.
|
| VERY IMPORTANT: If you are getting a blank page when compression is enabled it
| means you are prematurely outputting something to your browser. It could
| even be a line of whitespace at the end of one of your scripts. For
| compression to work, nothing can be sent before the output buffer is called
| by the output class. Do not 'echo' any values with compression enabled.
|
*/
'compress_output' => FALSE,
);

View File

@ -0,0 +1,87 @@
<?php
return array(
/*
|--------------------------------------------------------------------------
| Enable Query Strings
|--------------------------------------------------------------------------
|
| By default CodeIgniter uses search-engine friendly segment based URLs:
| example.com/who/what/where/
|
| By default CodeIgniter enables access to the $_GET array. If for some
| reason you would like to disable it, set 'allow_get_array' to FALSE.
|
| You can optionally enable standard query string based URLs:
| example.com?who=me&what=something&where=here
|
| Options are: TRUE or FALSE (boolean)
|
| The other items let you set the query string 'words' that will
| invoke your controllers and its functions:
| example.com/index.php?c=controller&m=function
|
| Please note that some of the helpers won't work as expected when
| this feature is enabled, since CodeIgniter is designed primarily to
| use segment based URLs.
|
*/
'allow_get_array' => TRUE,
'enable_query_strings' => FALSE,
'controller_trigger' => 'c',
'function_trigger' => 'm',
'directory_trigger' => 'd',
/*
|--------------------------------------------------------------------------
| Allowed URL Characters
|--------------------------------------------------------------------------
|
| This lets you specify which characters are permitted within your URLs.
| When someone tries to submit a URL with disallowed characters they will
| get a warning message.
|
| As a security measure you are STRONGLY encouraged to restrict URLs to
| as few characters as possible. By default only these are allowed: a-z 0-9~%.:_-
|
| Leave blank to allow all characters -- but only if you are insane.
|
| The configured value is actually a regular expression character group
| and it will be executed as: ! preg_match('/^[<permitted_uri_chars>]+$/i
|
| DO NOT CHANGE THIS UNLESS YOU FULLY UNDERSTAND THE REPERCUSSIONS!!
|
*/
'permitted_uri_chars' => 'a-z 0-9~%.:_\-',
/*
|--------------------------------------------------------------------------
| URI PROTOCOL
|--------------------------------------------------------------------------
|
| This item determines which server global should be used to retrieve the
| URI string. The default setting of 'REQUEST_URI' works for most servers.
| If your links do not seem to work, try one of the other delicious flavors:
|
| 'REQUEST_URI' Uses $_SERVER['REQUEST_URI']
| 'QUERY_STRING' Uses $_SERVER['QUERY_STRING']
| 'PATH_INFO' Uses $_SERVER['PATH_INFO']
|
| WARNING: If you set this to 'PATH_INFO', URIs will always be URL-decoded!
*/
'uri_protocol' => 'REQUEST_URI',
/*
|--------------------------------------------------------------------------
| URL suffix
|--------------------------------------------------------------------------
|
| This option allows you to add a suffix to all URLs generated by CodeIgniter.
| For more information please see the user guide:
|
| https://codeigniter.com/user_guide/general/urls.html
*/
'url_suffix' => '',
);

View File

@ -0,0 +1,72 @@
<?php
return array(
/*
|--------------------------------------------------------------------------
| Cross Site Request Forgery
|--------------------------------------------------------------------------
| Enables a CSRF cookie token to be set. When set to TRUE, token will be
| checked on a submitted form. If you are accepting user data, it is strongly
| recommended CSRF protection be enabled.
|
| 'csrf_token_name' = The token name
| 'csrf_cookie_name' = The cookie name
| 'csrf_expire' = The number in seconds the token should expire.
| 'csrf_regenerate' = Regenerate token on every submission
| 'csrf_exclude_uris' = Array of URIs which ignore CSRF checks
*/
'csrf_protection' => true,
'csrf_token_name' => 'csrf_test_name',
'csrf_cookie_name' => 'csrf_cookie_name',
'csrf_expire' => 7200,
'csrf_regenerate' => TRUE,
'csrf_exclude_uris' => array(),
/*
|--------------------------------------------------------------------------
| Standardize newlines
|--------------------------------------------------------------------------
|
| Determines whether to standardize newline characters in input data,
| meaning to replace \r\n, \r, \n occurrences with the PHP_EOL value.
|
| This is particularly useful for portability between UNIX-based OSes,
| (usually \n) and Windows (\r\n).
|
*/
'standardize_newlines' => FALSE,
/*
|--------------------------------------------------------------------------
| Global XSS Filtering
|--------------------------------------------------------------------------
|
| Determines whether the XSS filter is always active when GET, POST or
| COOKIE data is encountered
|
| WARNING: This feature is DEPRECATED and currently available only
| for backwards compatibility purposes!
|
*/
'global_xss_filtering' => FALSE,
/*
|--------------------------------------------------------------------------
| Reverse Proxy IPs
|--------------------------------------------------------------------------
|
| If your server is behind a reverse proxy, you must whitelist the proxy
| IP addresses from which CodeIgniter should trust headers such as
| HTTP_X_FORWARDED_FOR and HTTP_CLIENT_IP in order to properly identify
| the visitor's IP address.
|
| You can use both an array or a comma-separated list of proxy addresses,
| as well as specifying whole subnets. Here are a few examples:
|
| Comma-separated: '10.0.1.200,192.168.5.0/24'
| Array: array('10.0.1.200', '192.168.5.0/24')
*/
'proxy_ips' => ''
);

View File

@ -154,108 +154,6 @@ if ( ! function_exists('is_cli'))
// ------------------------------------------------------------------------
if ( ! function_exists('show_error'))
{
/**
* Error Handler
*
* This function lets us invoke the exception class and
* display errors using the standard error template located
* in application/views/errors/error_general.php
* This function will send the error page directly to the
* browser and exit.
*
* @param string
* @param int
* @param string
* @return void
*/
function show_error($message, $status_code = 500, $heading = 'An Error Was Encountered')
{
$status_code = abs($status_code);
if ($status_code < 100)
{
$exit_status = $status_code + 9; // 9 is EXIT__AUTO_MIN
if ($exit_status > 125) // 125 is EXIT__AUTO_MAX
{
$exit_status = 1; // EXIT_ERROR
}
$status_code = 500;
}
else
{
$exit_status = 1; // EXIT_ERROR
}
Logger::logError($heading . ' | ' . $message . ' | ' . $status_code);
Logger::http_error(500);
exit($exit_status);
}
}
// ------------------------------------------------------------------------
if ( ! function_exists('show_404'))
{
/**
* 404 Page Handler
*
* This function is similar to the show_error() function above
* However, instead of the standard error template it displays
* 404 errors.
*
* @param string
* @param bool
* @return void
*/
function show_404($page = '', $log_error = TRUE)
{
Logger::http_error(404);
exit(4); // EXIT_UNKNOWN_FILE
}
}
// ------------------------------------------------------------------------
if ( ! function_exists('log_message'))
{
/**
* Error Logging Interface
*
* We use this as a simple mechanism to access the logging
* class and send messages to be logged.
*
* @param string the error level: 'error', 'debug' or 'info'
* @param string the error message
* @return void
*/
function log_message($level, $message)
{
switch (strtoupper($level)) {
case 'INFO':
Logger::logInfo($message);
break;
case 'ERROR':
Logger::logError($message);
break;
case 'DEBUG':
Logger::logDebug($message);
break;
case 'ALL':
Logger::logInfo($message);
break;
default:
Logger::newLevel("Invalid logging message of type '".$level."'");
Logger::logWarning($message);
Logger::stopLevel();
break;
}
}
}
// ------------------------------------------------------------------------
if ( ! function_exists('set_status_header'))
{
/**
@ -274,7 +172,7 @@ if ( ! function_exists('set_status_header'))
if (empty($code) OR ! is_numeric($code))
{
show_error('Status codes must be numeric', 500);
throw new Exception('Status codes must be numeric', 1);
}
if (empty($text))

View File

@ -95,8 +95,7 @@ if ( ! function_exists('force_download'))
}
// Load the mime types
FuzeWorks\Helpers::load('common');
$mimes =& get_mimes();
$mimes = Config::get('mimes')->toArray();
// Only change the default MIME if we can find one
if (isset($mimes[$extension]))

View File

@ -86,12 +86,6 @@ class Core
// Load the config file of the FuzeWorks core
$config = Config::get('core');
// Load the logger
Logger::init();
// And initialize the router paths
Router::init();
// Disable events if requested to do so
if (!$config->enable_events)
{
@ -152,6 +146,11 @@ class Core
include_once 'Core/System/class.helpers.php';
include_once 'Core/System/class.database.php';
include_once 'Core/System/class.language.php';
include_once 'Core/System/class.utf8.php';
include_once 'Core/System/class.uri.php';
include_once 'Core/System/class.security.php';
include_once 'Core/System/class.input.php';
include_once 'Core/System/class.output.php';
// Load the core classes
new Config();
@ -159,12 +158,17 @@ class Core
new Events();
new Models();
new Layout();
new Router();
new Modules();
new Libraries();
new Helpers();
new Database();
new Language();
new Utf8();
new URI();
new Security();
new Input();
new Router();
new Output();
self::$loaded = true;
}

View File

@ -84,7 +84,7 @@ class Database
* @param string $parameters
* @param bool $newInstance
* @param bool $queryBuilder
* @return type FW_DB
* @return FW_DB
*/
public static function get($parameters = '', $newInstance = false, $queryBuilder = null)
{

View File

@ -160,4 +160,24 @@ class HelperException extends Exception
*/
class LanguageException extends Exception
{
}
/**
* Class UriException.
*
* @author Abel Hoogeveen <abel@techfuze.net>
* @copyright Copyright (c) 2013 - 2016, Techfuze. (http://techfuze.net)
*/
class UriException extends Exception
{
}
/**
* Class SecurityException.
*
* @author Abel Hoogeveen <abel@techfuze.net>
* @copyright Copyright (c) 2013 - 2016, Techfuze. (http://techfuze.net)
*/
class SecurityException extends Exception
{
}

View File

@ -0,0 +1,43 @@
<?php
/**
* FuzeWorks.
*
* The FuzeWorks MVC PHP FrameWork
*
* Copyright (C) 2015 TechFuze
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @author TechFuze
* @copyright Copyright (c) 2013 - 2016, Techfuze. (http://techfuze.net)
* @copyright Copyright (c) 1996 - 2015, Free Software Foundation, Inc. (http://www.fsf.org/)
* @license http://opensource.org/licenses/GPL-3.0 GPLv3 License
*
* @link http://fuzeworks.techfuze.net
* @since Version 0.0.1
*
* @version Version 0.0.1
*/
namespace FuzeWorks;
/**
*
* @author Abel Hoogeveen <abel@techfuze.net>
* @copyright Copyright (c) 2013 - 2016, Techfuze. (http://techfuze.net)
*/
class Factory
{
}

878
Core/System/class.input.php Normal file
View File

@ -0,0 +1,878 @@
<?php
/**
* FuzeWorks.
*
* The FuzeWorks MVC PHP FrameWork
*
* Copyright (C) 2015 TechFuze
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @author TechFuze
* @copyright Copyright (c) 2013 - 2016, Techfuze. (http://techfuze.net)
* @copyright Copyright (c) 1996 - 2015, Free Software Foundation, Inc. (http://www.fsf.org/)
* @license http://opensource.org/licenses/GPL-3.0 GPLv3 License
*
* @link http://fuzeworks.techfuze.net
* @since Version 0.0.1
*
* @version Version 0.0.1
*/
namespace FuzeWorks;
/**
* Input Class
*
* Pre-processes global input data for security
*
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2016, British Columbia Institute of Technology (http://bcit.ca/)
*/
class Input {
/**
* IP address of the current user
*
* @var string
*/
protected $ip_address = FALSE;
/**
* Allow GET array flag
*
* If set to FALSE, then $_GET will be set to an empty array.
*
* @var bool
*/
protected $_allow_get_array = TRUE;
/**
* Standardize new lines flag
*
* If set to TRUE, then newlines are standardized.
*
* @var bool
*/
protected $_standardize_newlines;
/**
* Enable XSS flag
*
* Determines whether the XSS filter is always active when
* GET, POST or COOKIE data is encountered.
* Set automatically based on config setting.
*
* @var bool
*/
protected $_enable_xss = FALSE;
/**
* Enable CSRF flag
*
* Enables a CSRF cookie token to be set.
* Set automatically based on config setting.
*
* @var bool
*/
protected $_enable_csrf = FALSE;
/**
* List of all HTTP request headers
*
* @var array
*/
protected $headers = array();
/**
* Raw input stream data
*
* Holds a cache of php://input contents
*
* @var string
*/
protected $_raw_input_stream;
/**
* Parsed input stream data
*
* Parsed from php://input at runtime
*
* @see CI_Input::input_stream()
* @var array
*/
protected $_input_stream;
// --------------------------------------------------------------------
/**
* Class constructor
*
* Determines whether to globally enable the XSS processing
* and whether to allow the $_GET array.
*
* @return void
*/
public function __construct()
{
$this->_allow_get_array = (Config::get('routing')->allow_get_array === TRUE);
$this->_enable_xss = (Config::get('security')->global_xss_filtering === TRUE);
$this->_enable_csrf = (Config::get('security')->csrf_protection === TRUE);
$this->_standardize_newlines = (bool) Config::get('security')->standardize_newlines;
// Sanitize global arrays
$this->_sanitize_globals();
// CSRF Protection check
if ($this->_enable_csrf === TRUE && ! $this->is_cli_request())
{
Security::csrf_verify();
}
}
// --------------------------------------------------------------------
/**
* Fetch from array
*
* Internal method used to retrieve values from global arrays.
*
* @param array &$array $_GET, $_POST, $_COOKIE, $_SERVER, etc.
* @param mixed $index Index for item to be fetched from $array
* @param bool $xss_clean Whether to apply XSS filtering
* @return mixed
*/
protected function _fetch_from_array(&$array, $index = NULL, $xss_clean = NULL)
{
is_bool($xss_clean) OR $xss_clean = $this->_enable_xss;
// If $index is NULL, it means that the whole $array is requested
isset($index) OR $index = array_keys($array);
// allow fetching multiple keys at once
if (is_array($index))
{
$output = array();
foreach ($index as $key)
{
$output[$key] = $this->_fetch_from_array($array, $key, $xss_clean);
}
return $output;
}
if (isset($array[$index]))
{
$value = $array[$index];
}
elseif (($count = preg_match_all('/(?:^[^\[]+)|\[[^]]*\]/', $index, $matches)) > 1) // Does the index contain array notation
{
$value = $array;
for ($i = 0; $i < $count; $i++)
{
$key = trim($matches[0][$i], '[]');
if ($key === '') // Empty notation will return the value as array
{
break;
}
if (isset($value[$key]))
{
$value = $value[$key];
}
else
{
return NULL;
}
}
}
else
{
return NULL;
}
return ($xss_clean === TRUE)
? Security::xss_clean($value)
: $value;
}
// --------------------------------------------------------------------
/**
* Fetch an item from the GET array
*
* @param mixed $index Index for item to be fetched from $_GET
* @param bool $xss_clean Whether to apply XSS filtering
* @return mixed
*/
public function get($index = NULL, $xss_clean = NULL)
{
return $this->_fetch_from_array($_GET, $index, $xss_clean);
}
// --------------------------------------------------------------------
/**
* Fetch an item from the POST array
*
* @param mixed $index Index for item to be fetched from $_POST
* @param bool $xss_clean Whether to apply XSS filtering
* @return mixed
*/
public function post($index = NULL, $xss_clean = NULL)
{
return $this->_fetch_from_array($_POST, $index, $xss_clean);
}
// --------------------------------------------------------------------
/**
* Fetch an item from POST data with fallback to GET
*
* @param string $index Index for item to be fetched from $_POST or $_GET
* @param bool $xss_clean Whether to apply XSS filtering
* @return mixed
*/
public function post_get($index, $xss_clean = NULL)
{
return isset($_POST[$index])
? $this->post($index, $xss_clean)
: $this->get($index, $xss_clean);
}
// --------------------------------------------------------------------
/**
* Fetch an item from GET data with fallback to POST
*
* @param string $index Index for item to be fetched from $_GET or $_POST
* @param bool $xss_clean Whether to apply XSS filtering
* @return mixed
*/
public function get_post($index, $xss_clean = NULL)
{
return isset($_GET[$index])
? $this->get($index, $xss_clean)
: $this->post($index, $xss_clean);
}
// --------------------------------------------------------------------
/**
* Fetch an item from the COOKIE array
*
* @param mixed $index Index for item to be fetched from $_COOKIE
* @param bool $xss_clean Whether to apply XSS filtering
* @return mixed
*/
public function cookie($index = NULL, $xss_clean = NULL)
{
return $this->_fetch_from_array($_COOKIE, $index, $xss_clean);
}
// --------------------------------------------------------------------
/**
* Fetch an item from the SERVER array
*
* @param mixed $index Index for item to be fetched from $_SERVER
* @param bool $xss_clean Whether to apply XSS filtering
* @return mixed
*/
public function server($index, $xss_clean = NULL)
{
return $this->_fetch_from_array($_SERVER, $index, $xss_clean);
}
// ------------------------------------------------------------------------
/**
* Fetch an item from the php://input stream
*
* Useful when you need to access PUT, DELETE or PATCH request data.
*
* @param string $index Index for item to be fetched
* @param bool $xss_clean Whether to apply XSS filtering
* @return mixed
*/
public function input_stream($index = NULL, $xss_clean = NULL)
{
// Prior to PHP 5.6, the input stream can only be read once,
// so we'll need to check if we have already done that first.
if ( ! is_array($this->_input_stream))
{
// $this->raw_input_stream will trigger __get().
parse_str($this->raw_input_stream, $this->_input_stream);
is_array($this->_input_stream) OR $this->_input_stream = array();
}
return $this->_fetch_from_array($this->_input_stream, $index, $xss_clean);
}
// ------------------------------------------------------------------------
/**
* Set cookie
*
* Accepts an arbitrary number of parameters (up to 7) or an associative
* array in the first parameter containing all the values.
*
* @param string|mixed[] $name Cookie name or an array containing parameters
* @param string $value Cookie value
* @param int $expire Cookie expiration time in seconds
* @param string $domain Cookie domain (e.g.: '.yourdomain.com')
* @param string $path Cookie path (default: '/')
* @param string $prefix Cookie name prefix
* @param bool $secure Whether to only transfer cookies via SSL
* @param bool $httponly Whether to only makes the cookie accessible via HTTP (no javascript)
* @return void
*/
public function set_cookie($name, $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = FALSE, $httponly = FALSE)
{
if (is_array($name))
{
// always leave 'name' in last place, as the loop will break otherwise, due to $$item
foreach (array('value', 'expire', 'domain', 'path', 'prefix', 'secure', 'httponly', 'name') as $item)
{
if (isset($name[$item]))
{
$$item = $name[$item];
}
}
}
// Get the variables
$cfg = Config::get('main');
if ($prefix === '' && $cfg->cookie_prefix !== '')
{
$prefix = $cfg->cookie_prefix;
}
if ($domain == '' && $cfg->cookie_domain != '')
{
$domain = $cfg->cookie_domain;
}
if ($path === '/' && $cfg->cookie_path !== '/')
{
$path = $cfg->cookie_path;
}
if ($secure === FALSE && $cfg->cookie_secure === TRUE)
{
$secure = $cfg->cookie_secure;
}
if ($httponly === FALSE && $cfg->cookie_httponly !== FALSE)
{
$httponly = $cfg->cookie_httponly;
}
if ( ! is_numeric($expire))
{
$expire = time() - 86500;
}
else
{
$expire = ($expire > 0) ? time() + $expire : 0;
}
setcookie($prefix.$name, $value, $expire, $path, $domain, $secure, $httponly);
}
// --------------------------------------------------------------------
/**
* Fetch the IP Address
*
* Determines and validates the visitor's IP address.
*
* @return string IP address
*/
public function ip_address()
{
if ($this->ip_address !== FALSE)
{
return $this->ip_address;
}
$proxy_ips = Config::get('security')->proxy_ips;
if ( ! empty($proxy_ips) && ! is_array($proxy_ips))
{
$proxy_ips = explode(',', str_replace(' ', '', $proxy_ips));
}
$this->ip_address = $this->server('REMOTE_ADDR');
if ($proxy_ips)
{
foreach (array('HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP', 'HTTP_X_CLIENT_IP', 'HTTP_X_CLUSTER_CLIENT_IP') as $header)
{
if (($spoof = $this->server($header)) !== NULL)
{
// Some proxies typically list the whole chain of IP
// addresses through which the client has reached us.
// e.g. client_ip, proxy_ip1, proxy_ip2, etc.
sscanf($spoof, '%[^,]', $spoof);
if ( ! $this->valid_ip($spoof))
{
$spoof = NULL;
}
else
{
break;
}
}
}
if ($spoof)
{
for ($i = 0, $c = count($proxy_ips); $i < $c; $i++)
{
// Check if we have an IP address or a subnet
if (strpos($proxy_ips[$i], '/') === FALSE)
{
// An IP address (and not a subnet) is specified.
// We can compare right away.
if ($proxy_ips[$i] === $this->ip_address)
{
$this->ip_address = $spoof;
break;
}
continue;
}
// We have a subnet ... now the heavy lifting begins
isset($separator) OR $separator = $this->valid_ip($this->ip_address, 'ipv6') ? ':' : '.';
// If the proxy entry doesn't match the IP protocol - skip it
if (strpos($proxy_ips[$i], $separator) === FALSE)
{
continue;
}
// Convert the REMOTE_ADDR IP address to binary, if needed
if ( ! isset($ip, $sprintf))
{
if ($separator === ':')
{
// Make sure we're have the "full" IPv6 format
$ip = explode(':',
str_replace('::',
str_repeat(':', 9 - substr_count($this->ip_address, ':')),
$this->ip_address
)
);
for ($j = 0; $j < 8; $j++)
{
$ip[$j] = intval($ip[$j], 16);
}
$sprintf = '%016b%016b%016b%016b%016b%016b%016b%016b';
}
else
{
$ip = explode('.', $this->ip_address);
$sprintf = '%08b%08b%08b%08b';
}
$ip = vsprintf($sprintf, $ip);
}
// Split the netmask length off the network address
sscanf($proxy_ips[$i], '%[^/]/%d', $netaddr, $masklen);
// Again, an IPv6 address is most likely in a compressed form
if ($separator === ':')
{
$netaddr = explode(':', str_replace('::', str_repeat(':', 9 - substr_count($netaddr, ':')), $netaddr));
for ($i = 0; $i < 8; $i++)
{
$netaddr[$i] = intval($netaddr[$i], 16);
}
}
else
{
$netaddr = explode('.', $netaddr);
}
// Convert to binary and finally compare
if (strncmp($ip, vsprintf($sprintf, $netaddr), $masklen) === 0)
{
$this->ip_address = $spoof;
break;
}
}
}
}
if ( ! $this->valid_ip($this->ip_address))
{
return $this->ip_address = '0.0.0.0';
}
return $this->ip_address;
}
// --------------------------------------------------------------------
/**
* Validate IP Address
*
* @param string $ip IP address
* @param string $which IP protocol: 'ipv4' or 'ipv6'
* @return bool
*/
public function valid_ip($ip, $which = '')
{
switch (strtolower($which))
{
case 'ipv4':
$which = FILTER_FLAG_IPV4;
break;
case 'ipv6':
$which = FILTER_FLAG_IPV6;
break;
default:
$which = NULL;
break;
}
return (bool) filter_var($ip, FILTER_VALIDATE_IP, $which);
}
// --------------------------------------------------------------------
/**
* Fetch User Agent string
*
* @return string|null User Agent string or NULL if it doesn't exist
*/
public function user_agent($xss_clean = NULL)
{
return $this->_fetch_from_array($_SERVER, 'HTTP_USER_AGENT', $xss_clean);
}
// --------------------------------------------------------------------
/**
* Sanitize Globals
*
* Internal method serving for the following purposes:
*
* - Unsets $_GET data, if query strings are not enabled
* - Cleans POST, COOKIE and SERVER data
* - Standardizes newline characters to PHP_EOL
*
* @return void
*/
protected function _sanitize_globals()
{
// Is $_GET data allowed? If not we'll set the $_GET to an empty array
if ($this->_allow_get_array === FALSE)
{
$_GET = array();
}
elseif (is_array($_GET))
{
foreach ($_GET as $key => $val)
{
$_GET[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);
}
}
// Clean $_POST Data
if (is_array($_POST))
{
foreach ($_POST as $key => $val)
{
$_POST[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);
}
}
// Clean $_COOKIE Data
if (is_array($_COOKIE))
{
// Also get rid of specially treated cookies that might be set by a server
// or silly application, that are of no use to a CI application anyway
// but that when present will trip our 'Disallowed Key Characters' alarm
// http://www.ietf.org/rfc/rfc2109.txt
// note that the key names below are single quoted strings, and are not PHP variables
unset(
$_COOKIE['$Version'],
$_COOKIE['$Path'],
$_COOKIE['$Domain']
);
foreach ($_COOKIE as $key => $val)
{
if (($cookie_key = $this->_clean_input_keys($key)) !== FALSE)
{
$_COOKIE[$cookie_key] = $this->_clean_input_data($val);
}
else
{
unset($_COOKIE[$key]);
}
}
}
// Sanitize PHP_SELF
$_SERVER['PHP_SELF'] = strip_tags($_SERVER['PHP_SELF']);
Logger::logDebug('Global POST, GET and COOKIE data sanitized');
}
// --------------------------------------------------------------------
/**
* Clean Input Data
*
* Internal method that aids in escaping data and
* standardizing newline characters to PHP_EOL.
*
* @param string|string[] $str Input string(s)
* @return string
*/
protected function _clean_input_data($str)
{
if (is_array($str))
{
$new_array = array();
foreach (array_keys($str) as $key)
{
$new_array[$this->_clean_input_keys($key)] = $this->_clean_input_data($str[$key]);
}
return $new_array;
}
/* We strip slashes if magic quotes is on to keep things consistent
NOTE: In PHP 5.4 get_magic_quotes_gpc() will always return 0 and
it will probably not exist in future versions at all.
*/
if ( ! Core::isPHP('5.4') && get_magic_quotes_gpc())
{
$str = stripslashes($str);
}
// Clean UTF-8 if supported
if (UTF8_ENABLED === TRUE)
{
$str = UTF8::clean_string($str);
}
// Remove control characters
$str = UTF8::remove_invisible_characters($str, FALSE);
// Standardize newlines if needed
if ($this->_standardize_newlines === TRUE)
{
return preg_replace('/(?:\r\n|[\r\n])/', PHP_EOL, $str);
}
return $str;
}
// --------------------------------------------------------------------
/**
* Clean Keys
*
* Internal method that helps to prevent malicious users
* from trying to exploit keys we make sure that keys are
* only named with alpha-numeric text and a few other items.
*
* @param string $str Input string
* @param bool $fatal Whether to terminate script exection
* or to return FALSE if an invalid
* key is encountered
* @return string|bool
*/
protected function _clean_input_keys($str, $fatal = TRUE)
{
if ( ! preg_match('/^[a-z0-9:_\/|-]+$/i', $str))
{
if ($fatal === TRUE)
{
return FALSE;
}
else
{
set_status_header(503);
echo 'Disallowed Key Characters.';
exit(7); // EXIT_USER_INPUT
}
}
// Clean UTF-8 if supported
if (UTF8_ENABLED === TRUE)
{
return UTF8::clean_string($str);
}
return $str;
}
// --------------------------------------------------------------------
/**
* Request Headers
*
* @param bool $xss_clean Whether to apply XSS filtering
* @return array
*/
public function request_headers($xss_clean = FALSE)
{
// If header is already defined, return it immediately
if ( ! empty($this->headers))
{
return $this->headers;
}
// In Apache, you can simply call apache_request_headers()
if (function_exists('apache_request_headers'))
{
return $this->headers = apache_request_headers();
}
$this->headers['Content-Type'] = isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : @getenv('CONTENT_TYPE');
foreach ($_SERVER as $key => $val)
{
if (sscanf($key, 'HTTP_%s', $header) === 1)
{
// take SOME_HEADER and turn it into Some-Header
$header = str_replace('_', ' ', strtolower($header));
$header = str_replace(' ', '-', ucwords($header));
$this->headers[$header] = $this->_fetch_from_array($_SERVER, $key, $xss_clean);
}
}
return $this->headers;
}
// --------------------------------------------------------------------
/**
* Get Request Header
*
* Returns the value of a single member of the headers class member
*
* @param string $index Header name
* @param bool $xss_clean Whether to apply XSS filtering
* @return string|null The requested header on success or NULL on failure
*/
public function get_request_header($index, $xss_clean = FALSE)
{
static $headers;
if ( ! isset($headers))
{
empty($this->headers) && $this->request_headers();
foreach ($this->headers as $key => $value)
{
$headers[strtolower($key)] = $value;
}
}
$index = strtolower($index);
if ( ! isset($headers[$index]))
{
return NULL;
}
return ($xss_clean === TRUE)
? Security::xss_clean($headers[$index])
: $headers[$index];
}
// --------------------------------------------------------------------
/**
* Is AJAX request?
*
* Test to see if a request contains the HTTP_X_REQUESTED_WITH header.
*
* @return bool
*/
public function is_ajax_request()
{
return ( ! empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest');
}
// --------------------------------------------------------------------
/**
* Is CLI request?
*
* Test to see if a request was made from the command line.
*
* @deprecated 3.0.0 Use is_cli() instead
* @return bool
*/
public function is_cli_request()
{
return (PHP_SAPI === 'cli' OR defined('STDIN'));
}
// --------------------------------------------------------------------
/**
* Get Request Method
*
* Return the request method
*
* @param bool $upper Whether to return in upper or lower case
* (default: FALSE)
* @return string
*/
public function method($upper = FALSE)
{
return ($upper)
? strtoupper($this->server('REQUEST_METHOD'))
: strtolower($this->server('REQUEST_METHOD'));
}
// ------------------------------------------------------------------------
/**
* Magic __get()
*
* Allows read access to protected properties
*
* @param string $name
* @return mixed
*/
public function __get($name)
{
if ($name === 'raw_input_stream')
{
isset($this->_raw_input_stream) OR $this->_raw_input_stream = file_get_contents('php://input');
return $this->_raw_input_stream;
}
elseif ($name === 'ip_address')
{
return $this->ip_address;
}
}
}

View File

@ -34,6 +34,7 @@ namespace FuzeWorks;
/**
* @todo add documentation
* @todo Add configuration load if no config parameter provided
*
* @author Abel Hoogeveen <abel@techfuze.net>
* @copyright Copyright (c) 2013 - 2016, Techfuze. (http://techfuze.net)

View File

@ -106,7 +106,7 @@ class Logger {
*
* Registers the error and exception handler, when required to do so by configuration
*/
public static function init() {
public function __construct() {
// Register the error handler
if (Config::get('error')->error_reporting == true) {
set_error_handler(array('\FuzeWorks\Logger', 'errorHandler'), E_ALL);
@ -138,7 +138,6 @@ class Logger {
// Log it!
self::errorHandler($errno, $errstr, $errfile, $errline);
self::logInfo(self::backtrace());
}
// And finally stop the Logging

View File

@ -383,16 +383,28 @@ class Modules
{
// First check if the caching engine can be used
if ($cache)
{
{
// Retrieve the cache if possible
$cache = Libraries::getDriver('cache');
$moduleRegister = $cache->$cachingMethod->get('moduleRegister');
$eventRegister = $cache->$cachingMethod->get('eventRegister');
$cacheData = $cache->$cachingMethod->get('moduleRegisters');
if ( ! is_bool($moduleRegister) && ! is_bool($eventRegister) )
if ( ! is_bool($cacheData) )
{
// Separate the data
$moduleRegister = $cacheData['moduleRegister'];
$eventRegister = $cacheData['eventRegister'];
$routeRegister = $cacheData['routeRegister'];
$advertiseRegister = $cacheData['advertiseRegister'];
// And register it all
Logger::newLevel("Loadig Module Headers from Cache");
self::$register = $moduleRegister;
Events::$register = $eventRegister;
self::$advertiseRegister = $advertiseRegister;
self::$module_routes = $routeRegister;
foreach ($routeRegister as $route => $name) {
Router::addRoute($route, array('\FuzeWorks\Modules', 'moduleCallable'), true);
}
Logger::stopLevel();
return true;
}
@ -534,8 +546,13 @@ class Modules
if ($cache)
{
Logger::log("Saving registry to cache");
$cache->$cachingMethod->save('moduleRegister', $register, $cachingTime);
$cache->$cachingMethod->save('eventRegister', $event_register, $cachingTime);
$cacheData = array(
'moduleRegister' => $register,
'eventRegister' => $event_register,
'routeRegister' => self::$module_routes,
'advertiseRegister' => self::$advertiseRegister
);
$cache->$cachingMethod->save('moduleRegisters', $cacheData, $cachingTime);
}
// And apply the registers to their dedicate location

View File

@ -0,0 +1,808 @@
<?php
/**
* FuzeWorks.
*
* The FuzeWorks MVC PHP FrameWork
*
* Copyright (C) 2015 TechFuze
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @author TechFuze
* @copyright Copyright (c) 2013 - 2016, Techfuze. (http://techfuze.net)
* @copyright Copyright (c) 1996 - 2015, Free Software Foundation, Inc. (http://www.fsf.org/)
* @license http://opensource.org/licenses/GPL-3.0 GPLv3 License
*
* @link http://fuzeworks.techfuze.net
* @since Version 0.0.1
*
* @version Version 0.0.1
*/
namespace FuzeWorks;
/**
* Output Class
*
* Responsible for sending final output to the browser.
*
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2016, British Columbia Institute of Technology (http://bcit.ca/)
*/
class Output {
/**
* Final output string
*
* @var string
*/
public $final_output;
/**
* Cache expiration time
*
* @var int
*/
public $cache_expiration = 0;
/**
* List of server headers
*
* @var array
*/
public $headers = array();
/**
* List of mime types
*
* @var array
*/
public $mimes = array();
/**
* Mime-type for the current page
*
* @var string
*/
protected $mime_type = 'text/html';
/**
* Enable Profiler flag
*
* @var bool
*/
public $enable_profiler = FALSE;
/**
* php.ini zlib.output_compression flag
*
* @var bool
*/
protected $_zlib_oc = FALSE;
/**
* CI output compression flag
*
* @var bool
*/
protected $_compress_output = FALSE;
/**
* List of profiler sections
*
* @var array
*/
protected $_profiler_sections = array();
/**
* Parse markers flag
*
* Whether or not to parse variables like {elapsed_time} and {memory_usage}.
*
* @var bool
*/
public $parse_exec_vars = TRUE;
/**
* Class constructor
*
* Determines whether zLib output compression will be used.
*
* @return void
*/
public function __construct()
{
$this->_zlib_oc = (bool) ini_get('zlib.output_compression');
$this->_compress_output = (
$this->_zlib_oc === FALSE
&& Config::get('main')->compress_output === TRUE
&& extension_loaded('zlib')
);
// Get mime types for later
$this->mimes = Config::get('mimes')->toArray();
}
// --------------------------------------------------------------------
/**
* Get Output
*
* Returns the current output string.
*
* @return string
*/
public function get_output()
{
return $this->final_output;
}
// --------------------------------------------------------------------
/**
* Set Output
*
* Sets the output string.
*
* @param string $output Output data
* @return CI_Output
*/
public function set_output($output)
{
$this->final_output = $output;
return $this;
}
// --------------------------------------------------------------------
/**
* Append Output
*
* Appends data onto the output string.
*
* @param string $output Data to append
* @return CI_Output
*/
public function append_output($output)
{
$this->final_output .= $output;
return $this;
}
// --------------------------------------------------------------------
/**
* Set Header
*
* Lets you set a server header which will be sent with the final output.
*
* Note: If a file is cached, headers will not be sent.
* @todo We need to figure out how to permit headers to be cached.
*
* @param string $header Header
* @param bool $replace Whether to replace the old header value, if already set
* @return CI_Output
*/
public function set_header($header, $replace = TRUE)
{
// If zlib.output_compression is enabled it will compress the output,
// but it will not modify the content-length header to compensate for
// the reduction, causing the browser to hang waiting for more data.
// We'll just skip content-length in those cases.
if ($this->_zlib_oc && strncasecmp($header, 'content-length', 14) === 0)
{
return $this;
}
$this->headers[] = array($header, $replace);
return $this;
}
// --------------------------------------------------------------------
/**
* Set Content-Type Header
*
* @param string $mime_type Extension of the file we're outputting
* @param string $charset Character set (default: NULL)
* @return CI_Output
*/
public function set_content_type($mime_type, $charset = NULL)
{
if (strpos($mime_type, '/') === FALSE)
{
$extension = ltrim($mime_type, '.');
// Is this extension supported?
if (isset($this->mimes[$extension]))
{
$mime_type =& $this->mimes[$extension];
if (is_array($mime_type))
{
$mime_type = current($mime_type);
}
}
}
$this->mime_type = $mime_type;
if (empty($charset))
{
$charset = Config::get('main')->charset;
}
$header = 'Content-Type: '.$mime_type
.(empty($charset) ? '' : '; charset='.$charset);
$this->headers[] = array($header, TRUE);
return $this;
}
// --------------------------------------------------------------------
/**
* Get Current Content-Type Header
*
* @return string 'text/html', if not already set
*/
public function get_content_type()
{
for ($i = 0, $c = count($this->headers); $i < $c; $i++)
{
if (sscanf($this->headers[$i][0], 'Content-Type: %[^;]', $content_type) === 1)
{
return $content_type;
}
}
return 'text/html';
}
// --------------------------------------------------------------------
/**
* Get Header
*
* @param string $header_name
* @return string
*/
public function get_header($header)
{
// Combine headers already sent with our batched headers
$headers = array_merge(
// We only need [x][0] from our multi-dimensional array
array_map('array_shift', $this->headers),
headers_list()
);
if (empty($headers) OR empty($header))
{
return NULL;
}
for ($i = 0, $c = count($headers); $i < $c; $i++)
{
if (strncasecmp($header, $headers[$i], $l = strlen($header)) === 0)
{
return trim(substr($headers[$i], $l+1));
}
}
return NULL;
}
// --------------------------------------------------------------------
/**
* Set HTTP Status Header
*
* As of version 1.7.2, this is an alias for common function
* set_status_header().
*
* @param int $code Status code (default: 200)
* @param string $text Optional message
* @todo Fix this
* @return CI_Output
*/
public function set_status_header($code = 200, $text = '')
{
return $this;
set_status_header($code, $text);
return $this;
}
// --------------------------------------------------------------------
/**
* Enable/disable Profiler
*
* @param bool $val TRUE to enable or FALSE to disable
* @return CI_Output
*/
public function enable_profiler($val = TRUE)
{
$this->enable_profiler = is_bool($val) ? $val : TRUE;
return $this;
}
// --------------------------------------------------------------------
/**
* Set Profiler Sections
*
* Allows override of default/config settings for
* Profiler section display.
*
* @param array $sections Profiler sections
* @return CI_Output
*/
public function set_profiler_sections($sections)
{
if (isset($sections['query_toggle_count']))
{
$this->_profiler_sections['query_toggle_count'] = (int) $sections['query_toggle_count'];
unset($sections['query_toggle_count']);
}
foreach ($sections as $section => $enable)
{
$this->_profiler_sections[$section] = ($enable !== FALSE);
}
return $this;
}
// --------------------------------------------------------------------
/**
* Set Cache
*
* @param int $time Cache expiration time in minutes
* @return CI_Output
*/
public function cache($time)
{
$this->cache_expiration = is_numeric($time) ? $time : 0;
return $this;
}
// --------------------------------------------------------------------
/**
* Display Output
*
* Processes and sends finalized output data to the browser along
* with any server headers and profile data. It also stops benchmark
* timers so the page rendering speed and memory usage can be shown.
*
* Note: All "view" data is automatically put into $this->final_output
* by controller class.
*
* @uses CI_Output::$final_output
* @param string $output Output data override
* @return void
* @todo Implement cache
*/
public function _display($output = '')
{
// Note: We use load_class() because we can't use $CI =& get_instance()
// since this function is sometimes called by the caching mechanism,
// which happens before the CI super object is available.
$BM =& load_class('Benchmark', 'core');
$CFG =& load_class('Config', 'core');
// Grab the super object if we can.
if (class_exists('CI_Controller', FALSE))
{
$CI =& get_instance();
}
// --------------------------------------------------------------------
// Set the output data
if ($output === '')
{
$output =& $this->final_output;
}
// --------------------------------------------------------------------
// Do we need to write a cache file? Only if the controller does not have its
// own _output() method and we are not dealing with a cache file, which we
// can determine by the existence of the $CI object above
//if ($this->cache_expiration > 0 && isset($CI) && ! method_exists($CI, '_output'))
//{
// $this->_write_cache($output);
//}
// --------------------------------------------------------------------
// Parse out the elapsed time and memory usage,
// then swap the pseudo-variables with the data
$elapsed = Logger::elapsedTime('total_execution_time_start', 'total_execution_time_end');
if ($this->parse_exec_vars === TRUE)
{
$memory = round(memory_get_usage() / 1024 / 1024, 2).'MB';
$output = str_replace(array('{elapsed_time}', '{memory_usage}'), array($elapsed, $memory), $output);
}
// --------------------------------------------------------------------
// Is compression requested?
//if (isset($CI) // This means that we're not serving a cache file, if we were, it would already be compressed
// && $this->_compress_output === TRUE
// && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE)
//{
// ob_start('ob_gzhandler');
//}
// --------------------------------------------------------------------
// Are there any server headers to send?
if (count($this->headers) > 0)
{
foreach ($this->headers as $header)
{
@header($header[0], $header[1]);
}
}
// --------------------------------------------------------------------
// Does the $CI object exist?
// If not we know we are dealing with a cache file so we'll
// simply echo out the data and exit.
if ( ! isset($CI))
{
if ($this->_compress_output === TRUE)
{
if (isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE)
{
header('Content-Encoding: gzip');
header('Content-Length: '.strlen($output));
}
else
{
// User agent doesn't support gzip compression,
// so we'll have to decompress our cache
$output = gzinflate(substr($output, 10, -8));
}
}
echo $output;
Logger::log('Final output sent to browser');
Logger::logDebug('Total execution time: '.$elapsed);
return;
}
// --------------------------------------------------------------------
// Do we need to generate profile data?
// If so, load the Profile class and run it.
/*if ($this->enable_profiler === TRUE)
{
$CI->load->library('profiler');
if ( ! empty($this->_profiler_sections))
{
$CI->profiler->set_sections($this->_profiler_sections);
}
// If the output data contains closing </body> and </html> tags
// we will remove them and add them back after we insert the profile data
$output = preg_replace('|</body>.*?</html>|is', '', $output, -1, $count).$CI->profiler->run();
if ($count > 0)
{
$output .= '</body></html>';
}
}
// Does the controller contain a function named _output()?
// If so send the output there. Otherwise, echo it.
if (method_exists($CI, '_output'))
{
$CI->_output($output);
}
else
{
echo $output; // Send it to the browser!
}*/
Logger::log('Final output sent to browser');
Logger::logDebug('Total execution time: '.$elapsed);
}
// --------------------------------------------------------------------
/**
* Write Cache
*
* @param string $output Output data to cache
* @todo Implement cache
* @return void
*/
public function _write_cache($output)
{
Logger::logWarning("Cache is not implemented as of yet");
return;
$CI =& get_instance();
$path = $CI->config->item('cache_path');
$cache_path = ($path === '') ? APPPATH.'cache/' : $path;
if ( ! is_dir($cache_path) OR ! is_really_writable($cache_path))
{
log_message('error', 'Unable to write cache file: '.$cache_path);
return;
}
$uri = $CI->config->item('base_url')
.$CI->config->item('index_page')
.$CI->uri->uri_string();
if (($cache_query_string = $CI->config->item('cache_query_string')) && ! empty($_SERVER['QUERY_STRING']))
{
if (is_array($cache_query_string))
{
$uri .= '?'.http_build_query(array_intersect_key($_GET, array_flip($cache_query_string)));
}
else
{
$uri .= '?'.$_SERVER['QUERY_STRING'];
}
}
$cache_path .= md5($uri);
if ( ! $fp = @fopen($cache_path, 'w+b'))
{
log_message('error', 'Unable to write cache file: '.$cache_path);
return;
}
if (flock($fp, LOCK_EX))
{
// If output compression is enabled, compress the cache
// itself, so that we don't have to do that each time
// we're serving it
if ($this->_compress_output === TRUE)
{
$output = gzencode($output);
if ($this->get_header('content-type') === NULL)
{
$this->set_content_type($this->mime_type);
}
}
$expire = time() + ($this->cache_expiration * 60);
// Put together our serialized info.
$cache_info = serialize(array(
'expire' => $expire,
'headers' => $this->headers
));
$output = $cache_info.'ENDCI--->'.$output;
for ($written = 0, $length = strlen($output); $written < $length; $written += $result)
{
if (($result = fwrite($fp, substr($output, $written))) === FALSE)
{
break;
}
}
flock($fp, LOCK_UN);
}
else
{
log_message('error', 'Unable to secure a file lock for file at: '.$cache_path);
return;
}
fclose($fp);
if (is_int($result))
{
chmod($cache_path, 0640);
log_message('debug', 'Cache file written: '.$cache_path);
// Send HTTP cache-control headers to browser to match file cache settings.
$this->set_cache_header($_SERVER['REQUEST_TIME'], $expire);
}
else
{
@unlink($cache_path);
log_message('error', 'Unable to write the complete cache content at: '.$cache_path);
}
}
// --------------------------------------------------------------------
/**
* Update/serve cached output
*
* @uses CI_Config
* @uses CI_URI
* @todo Implement
*
* @param object &$CFG CI_Config class instance
* @param object &$URI CI_URI class instance
* @return bool TRUE on success or FALSE on failure
*/
public function _display_cache(&$CFG, &$URI)
{
Logger::logWarning("Cache is not implemented as of yet");
return false;
$cache_path = ($CFG->item('cache_path') === '') ? APPPATH.'cache/' : $CFG->item('cache_path');
// Build the file path. The file name is an MD5 hash of the full URI
$uri = $CFG->item('base_url').$CFG->item('index_page').$URI->uri_string;
if (($cache_query_string = $CFG->item('cache_query_string')) && ! empty($_SERVER['QUERY_STRING']))
{
if (is_array($cache_query_string))
{
$uri .= '?'.http_build_query(array_intersect_key($_GET, array_flip($cache_query_string)));
}
else
{
$uri .= '?'.$_SERVER['QUERY_STRING'];
}
}
$filepath = $cache_path.md5($uri);
if ( ! file_exists($filepath) OR ! $fp = @fopen($filepath, 'rb'))
{
return FALSE;
}
flock($fp, LOCK_SH);
$cache = (filesize($filepath) > 0) ? fread($fp, filesize($filepath)) : '';
flock($fp, LOCK_UN);
fclose($fp);
// Look for embedded serialized file info.
if ( ! preg_match('/^(.*)ENDCI--->/', $cache, $match))
{
return FALSE;
}
$cache_info = unserialize($match[1]);
$expire = $cache_info['expire'];
$last_modified = filemtime($filepath);
// Has the file expired?
if ($_SERVER['REQUEST_TIME'] >= $expire && is_really_writable($cache_path))
{
// If so we'll delete it.
@unlink($filepath);
log_message('debug', 'Cache file has expired. File deleted.');
return FALSE;
}
else
{
// Or else send the HTTP cache control headers.
$this->set_cache_header($last_modified, $expire);
}
// Add headers from cache file.
foreach ($cache_info['headers'] as $header)
{
$this->set_header($header[0], $header[1]);
}
// Display the cache
$this->_display(substr($cache, strlen($match[0])));
log_message('debug', 'Cache file is current. Sending it to browser.');
return TRUE;
}
// --------------------------------------------------------------------
/**
* Delete cache
*
* @param string $uri URI string
* @return bool
* @todo Implement
*/
public function delete_cache($uri = '')
{
Logger::logWarning("Caching is not implemented as of yet");
return false;
$CI =& get_instance();
$cache_path = $CI->config->item('cache_path');
if ($cache_path === '')
{
$cache_path = APPPATH.'cache/';
}
if ( ! is_dir($cache_path))
{
log_message('error', 'Unable to find cache path: '.$cache_path);
return FALSE;
}
if (empty($uri))
{
$uri = $CI->uri->uri_string();
if (($cache_query_string = $CI->config->item('cache_query_string')) && ! empty($_SERVER['QUERY_STRING']))
{
if (is_array($cache_query_string))
{
$uri .= '?'.http_build_query(array_intersect_key($_GET, array_flip($cache_query_string)));
}
else
{
$uri .= '?'.$_SERVER['QUERY_STRING'];
}
}
}
$cache_path .= md5($CI->config->item('base_url').$CI->config->item('index_page').ltrim($uri, '/'));
if ( ! @unlink($cache_path))
{
log_message('error', 'Unable to delete cache file for '.$uri);
return FALSE;
}
return TRUE;
}
// --------------------------------------------------------------------
/**
* Set Cache Header
*
* Set the HTTP headers to match the server-side file cache settings
* in order to reduce bandwidth.
*
* @param int $last_modified Timestamp of when the page was last modified
* @param int $expiration Timestamp of when should the requested page expire from cache
* @return void
*/
public function set_cache_header($last_modified, $expiration)
{
$max_age = $expiration - $_SERVER['REQUEST_TIME'];
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $last_modified <= strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']))
{
$this->set_status_header(304);
exit;
}
else
{
header('Pragma: public');
header('Cache-Control: max-age='.$max_age.', public');
header('Expires: '.gmdate('D, d M Y H:i:s', $expiration).' GMT');
header('Last-modified: '.gmdate('D, d M Y H:i:s', $last_modified).' GMT');
}
}
}

View File

@ -106,7 +106,7 @@ class Router
/**
* The constructor adds the default route to the routing table.
*/
public static function init()
public function __construct()
{
foreach (Config::get('routes') as $route => $callable) {
if (is_int($route)) {

File diff suppressed because it is too large Load Diff

644
Core/System/class.uri.php Normal file
View File

@ -0,0 +1,644 @@
<?php
/**
* FuzeWorks.
*
* The FuzeWorks MVC PHP FrameWork
*
* Copyright (C) 2015 TechFuze
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @author TechFuze
* @copyright Copyright (c) 2013 - 2016, Techfuze. (http://techfuze.net)
* @copyright Copyright (c) 1996 - 2015, Free Software Foundation, Inc. (http://www.fsf.org/)
* @license http://opensource.org/licenses/GPL-3.0 GPLv3 License
*
* @link http://fuzeworks.techfuze.net
* @since Version 0.0.1
*
* @version Version 0.0.1
*/
namespace FuzeWorks;
/**
* URI Class
*
* Parses URIs and determines routing
*
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2016, British Columbia Institute of Technology (http://bcit.ca/)
*/
class URI {
/**
* List of cached URI segments
*
* @var array
*/
public static $keyval = array();
/**
* Current URI string
*
* @var string
*/
public static $uri_string = '';
/**
* List of URI segments
*
* Starts at 1 instead of 0.
*
* @var array
*/
public static $segments = array();
/**
* List of routed URI segments
*
* Starts at 1 instead of 0.
*
* @var array
*/
public static $rsegments = array();
/**
* Permitted URI chars
*
* PCRE character group allowed in URI segments
*
* @var string
*/
protected static $_permitted_uri_chars;
/**
* The configuration of this class
*
* @var ConfigORM
*/
private static $config;
/**
* Class constructor
*
* @return void
*/
public function __construct()
{
self::$config = Config::get('routing');
// If query strings are enabled, we don't need to parse any segments.
// However, they don't make sense under CLI.
if ((PHP_SAPI === 'cli' OR defined('STDIN')) OR self::$config->enable_query_strings !== TRUE)
{
self::$_permitted_uri_chars = self::$config->permitted_uri_chars;
// If it's a CLI request, ignore the configuration
if ( (PHP_SAPI === 'cli' OR defined('STDIN')) )
{
$uri = self::_parse_argv();
}
else
{
$protocol = self::$config->uri_protocol;
empty($protocol) && $protocol = 'REQUEST_URI';
switch ($protocol)
{
case 'AUTO': // For BC purposes only
case 'REQUEST_URI':
$uri = self::_parse_request_uri();
break;
case 'QUERY_STRING':
$uri = self::_parse_query_string();
break;
case 'PATH_INFO':
default:
$uri = isset($_SERVER[$protocol])
? $_SERVER[$protocol]
: self::_parse_request_uri();
break;
}
}
self::_set_uri_string($uri);
}
}
// --------------------------------------------------------------------
/**
* Set URI String
*
* @param string $str
* @return void
*/
protected static function _set_uri_string($str)
{
// Filter out control characters and trim slashes
self::$uri_string = trim(Utf8::remove_invisible_characters($str, FALSE), '/');
if (self::$uri_string !== '')
{
// Remove the URL suffix, if present
if (($suffix = (string) self::$config->url_suffix) !== '')
{
$slen = strlen($suffix);
if (substr(self::$uri_string, -$slen) === $suffix)
{
self::$uri_string = substr(self::$uri_string, 0, -$slen);
}
}
self::$segments[0] = NULL;
// Populate the segments array
foreach (explode('/', trim(self::$uri_string, '/')) as $val)
{
$val = trim($val);
// Filter segments for security
self::filter_uri($val);
if ($val !== '')
{
self::$segments[] = $val;
}
}
unset(self::$segments[0]);
}
}
// --------------------------------------------------------------------
/**
* Parse REQUEST_URI
*
* Will parse REQUEST_URI and automatically detect the URI from it,
* while fixing the query string if necessary.
*
* @return string
*/
protected static function _parse_request_uri()
{
if ( ! isset($_SERVER['REQUEST_URI'], $_SERVER['SCRIPT_NAME']))
{
return '';
}
// parse_url() returns false if no host is present, but the path or query string
// contains a colon followed by a number
$uri = parse_url('http://dummy'.$_SERVER['REQUEST_URI']);
$query = isset($uri['query']) ? $uri['query'] : '';
$uri = isset($uri['path']) ? $uri['path'] : '';
if (isset($_SERVER['SCRIPT_NAME'][0]))
{
if (strpos($uri, $_SERVER['SCRIPT_NAME']) === 0)
{
$uri = (string) substr($uri, strlen($_SERVER['SCRIPT_NAME']));
}
elseif (strpos($uri, dirname($_SERVER['SCRIPT_NAME'])) === 0)
{
$uri = (string) substr($uri, strlen(dirname($_SERVER['SCRIPT_NAME'])));
}
}
// This section ensures that even on servers that require the URI to be in the query string (Nginx) a correct
// URI is found, and also fixes the QUERY_STRING server var and $_GET array.
if (trim($uri, '/') === '' && strncmp($query, '/', 1) === 0)
{
$query = explode('?', $query, 2);
$uri = $query[0];
$_SERVER['QUERY_STRING'] = isset($query[1]) ? $query[1] : '';
}
else
{
$_SERVER['QUERY_STRING'] = $query;
}
parse_str($_SERVER['QUERY_STRING'], $_GET);
if ($uri === '/' OR $uri === '')
{
return '/';
}
// Do some final cleaning of the URI and return it
return self::_remove_relative_directory($uri);
}
// --------------------------------------------------------------------
/**
* Parse QUERY_STRING
*
* Will parse QUERY_STRING and automatically detect the URI from it.
*
* @return string
*/
protected static function _parse_query_string()
{
$uri = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');
if (trim($uri, '/') === '')
{
return '';
}
elseif (strncmp($uri, '/', 1) === 0)
{
$uri = explode('?', $uri, 2);
$_SERVER['QUERY_STRING'] = isset($uri[1]) ? $uri[1] : '';
$uri = $uri[0];
}
parse_str($_SERVER['QUERY_STRING'], $_GET);
return self::_remove_relative_directory($uri);
}
// --------------------------------------------------------------------
/**
* Parse CLI arguments
*
* Take each command line argument and assume it is a URI segment.
*
* @return string
*/
protected static function _parse_argv()
{
$args = array_slice($_SERVER['argv'], 1);
return $args ? implode('/', $args) : '';
}
// --------------------------------------------------------------------
/**
* Remove relative directory (../) and multi slashes (///)
*
* Do some final cleaning of the URI and return it, currently only used in self::_parse_request_uri()
*
* @param string $uri
* @return string
*/
protected static function _remove_relative_directory($uri)
{
$uris = array();
$tok = strtok($uri, '/');
while ($tok !== FALSE)
{
if (( ! empty($tok) OR $tok === '0') && $tok !== '..')
{
$uris[] = $tok;
}
$tok = strtok('/');
}
return implode('/', $uris);
}
// --------------------------------------------------------------------
/**
* Filter URI
*
* Filters segments for malicious characters.
*
* @param string $str
* @return void
*/
public static function filter_uri(&$str)
{
if ( ! empty($str) && ! empty(self::$_permitted_uri_chars) && ! preg_match('/^['.self::$_permitted_uri_chars.']+$/i'.(UTF8_ENABLED ? 'u' : ''), $str))
{
throw new UriException('The URI you submitted has disallowed characters.', 1);
}
}
// --------------------------------------------------------------------
/**
* Fetch URI Segment
*
* @see CI_URI::$segments
* @param int $n Index
* @param mixed $no_result What to return if the segment index is not found
* @return mixed
*/
public static function segment($n, $no_result = NULL)
{
return isset(self::$segments[$n]) ? self::$segments[$n] : $no_result;
}
// --------------------------------------------------------------------
/**
* Fetch URI "routed" Segment
*
* Returns the re-routed URI segment (assuming routing rules are used)
* based on the index provided. If there is no routing, will return
* the same result as CI_URI::segment().
*
* @see CI_URI::$rsegments
* @see CI_URI::segment()
* @param int $n Index
* @param mixed $no_result What to return if the segment index is not found
* @return mixed
*/
public static function rsegment($n, $no_result = NULL)
{
return isset(self::$rsegments[$n]) ? self::$rsegments[$n] : $no_result;
}
// --------------------------------------------------------------------
/**
* URI to assoc
*
* Generates an associative array of URI data starting at the supplied
* segment index. For example, if this is your URI:
*
* example.com/user/search/name/joe/location/UK/gender/male
*
* You can use this method to generate an array with this prototype:
*
* array (
* name => joe
* location => UK
* gender => male
* )
*
* @param int $n Index (default: 3)
* @param array $default Default values
* @return array
*/
public static function uri_to_assoc($n = 3, $default = array())
{
return self::_uri_to_assoc($n, $default, 'segment');
}
// --------------------------------------------------------------------
/**
* Routed URI to assoc
*
* Identical to CI_URI::uri_to_assoc(), only it uses the re-routed
* segment array.
*
* @see CI_URI::uri_to_assoc()
* @param int $n Index (default: 3)
* @param array $default Default values
* @return array
*/
public static function ruri_to_assoc($n = 3, $default = array())
{
return self::_uri_to_assoc($n, $default, 'rsegment');
}
// --------------------------------------------------------------------
/**
* Internal URI-to-assoc
*
* Generates a key/value pair from the URI string or re-routed URI string.
*
* @used-by CI_URI::uri_to_assoc()
* @used-by CI_URI::ruri_to_assoc()
* @param int $n Index (default: 3)
* @param array $default Default values
* @param string $which Array name ('segment' or 'rsegment')
* @return array
*/
protected static function _uri_to_assoc($n = 3, $default = array(), $which = 'segment')
{
if ( ! is_numeric($n))
{
return $default;
}
if (isset(self::$keyval[$which], self::$keyval[$which][$n]))
{
return self::$keyval[$which][$n];
}
$total_segments = "total_{$which}s";
$segment_array = "{$which}_array";
if (self::$total_segments() < $n)
{
return (count($default) === 0)
? array()
: array_fill_keys($default, NULL);
}
$segments = array_slice(self::$segment_array(), ($n - 1));
$i = 0;
$lastval = '';
$retval = array();
foreach ($segments as $seg)
{
if ($i % 2)
{
$retval[$lastval] = $seg;
}
else
{
$retval[$seg] = NULL;
$lastval = $seg;
}
$i++;
}
if (count($default) > 0)
{
foreach ($default as $val)
{
if ( ! array_key_exists($val, $retval))
{
$retval[$val] = NULL;
}
}
}
// Cache the array for reuse
isset(self::$keyval[$which]) OR self::$keyval[$which] = array();
self::$keyval[$which][$n] = $retval;
return $retval;
}
// --------------------------------------------------------------------
/**
* Assoc to URI
*
* Generates a URI string from an associative array.
*
* @param array $array Input array of key/value pairs
* @return string URI string
*/
public static function assoc_to_uri($array)
{
$temp = array();
foreach ((array) $array as $key => $val)
{
$temp[] = $key;
$temp[] = $val;
}
return implode('/', $temp);
}
// --------------------------------------------------------------------
/**
* Slash segment
*
* Fetches an URI segment with a slash.
*
* @param int $n Index
* @param string $where Where to add the slash ('trailing' or 'leading')
* @return string
*/
public static function slash_segment($n, $where = 'trailing')
{
return self::_slash_segment($n, $where, 'segment');
}
// --------------------------------------------------------------------
/**
* Slash routed segment
*
* Fetches an URI routed segment with a slash.
*
* @param int $n Index
* @param string $where Where to add the slash ('trailing' or 'leading')
* @return string
*/
public static function slash_rsegment($n, $where = 'trailing')
{
return self::_slash_segment($n, $where, 'rsegment');
}
// --------------------------------------------------------------------
/**
* Internal Slash segment
*
* Fetches an URI Segment and adds a slash to it.
*
* @used-by CI_URI::slash_segment()
* @used-by CI_URI::slash_rsegment()
*
* @param int $n Index
* @param string $where Where to add the slash ('trailing' or 'leading')
* @param string $which Array name ('segment' or 'rsegment')
* @return string
*/
protected static function _slash_segment($n, $where = 'trailing', $which = 'segment')
{
$leading = $trailing = '/';
if ($where === 'trailing')
{
$leading = '';
}
elseif ($where === 'leading')
{
$trailing = '';
}
return $leading.self::$which($n).$trailing;
}
// --------------------------------------------------------------------
/**
* Segment Array
*
* @return array CI_URI::$segments
*/
public static function segment_array()
{
return self::$segments;
}
// --------------------------------------------------------------------
/**
* Routed Segment Array
*
* @return array CI_URI::$rsegments
*/
public static function rsegment_array()
{
return self::$rsegments;
}
// --------------------------------------------------------------------
/**
* Total number of segments
*
* @return int
*/
public static function total_segments()
{
return count(self::$segments);
}
// --------------------------------------------------------------------
/**
* Total number of routed segments
*
* @return int
*/
public static function total_rsegments()
{
return count(self::$rsegments);
}
// --------------------------------------------------------------------
/**
* Fetch URI string
*
* @return string CI_URI::$uri_string
*/
public static function uri_string()
{
return self::$uri_string;
}
// --------------------------------------------------------------------
/**
* Fetch Re-routed URI string
*
* @return string
* @todo Implement router
*/
public static function ruri_string()
{
return ltrim(load_class('Router', 'core')->directory, '/').implode('/', self::$rsegments);
}
}

246
Core/System/class.utf8.php Normal file
View File

@ -0,0 +1,246 @@
<?php
/**
* FuzeWorks.
*
* The FuzeWorks MVC PHP FrameWork
*
* Copyright (C) 2015 TechFuze
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @author TechFuze
* @copyright Copyright (c) 2013 - 2016, Techfuze. (http://techfuze.net)
* @copyright Copyright (c) 1996 - 2015, Free Software Foundation, Inc. (http://www.fsf.org/)
* @license http://opensource.org/licenses/GPL-3.0 GPLv3 License
*
* @link http://fuzeworks.techfuze.net
* @since Version 0.0.1
*
* @version Version 0.0.1
*/
namespace FuzeWorks;
/**
* Utf8 Class
*
* Provides support for UTF-8 environments
*
* @author EllisLab Dev Team
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
* @copyright Copyright (c) 2014 - 2016, British Columbia Institute of Technology (http://bcit.ca/)
*/
class Utf8 {
/**
* Class constructor
*
* Determines if UTF-8 support is to be enabled.
*
* @return void
*/
public function __construct()
{
$charset = strtoupper(Config::get('main')->charset);
ini_set('default_charset', $charset);
/*
* Configure mbstring and/or iconv if they are enabled
* and set MB_ENABLED and ICONV_ENABLED constants, so
* that we don't repeatedly do extension_loaded() or
* function_exists() calls.
*/
if (extension_loaded('mbstring'))
{
define('MB_ENABLED', TRUE);
// mbstring.internal_encoding is deprecated starting with PHP 5.6
// and it's usage triggers E_DEPRECATED messages.
if (! Core::isPHP('5.6'))
{
@ini_set('mbstring.internal_encoding', $charset);
}
else
{
mb_internal_encoding($charset);
}
// This is required for mb_convert_encoding() to strip invalid characters.
// That's utilized by CI_Utf8, but it's also done for consistency with iconv.
mb_substitute_character('none');
}
else
{
define('MB_ENABLED', FALSE);
}
// There's an ICONV_IMPL constant, but the PHP manual says that using
// iconv's predefined constants is "strongly discouraged".
if (extension_loaded('iconv'))
{
define('ICONV_ENABLED', TRUE);
// iconv.internal_encoding is deprecated starting with PHP 5.6
// and it's usage triggers E_DEPRECATED messages.
if ( ! Core::isPHP(5.6) )
{
@ini_set('iconv.internal_encoding', $charset);
}
else
{
ini_set('default_encoding', $charset);
}
}
else
{
define('ICONV_ENABLED', FALSE);
}
if (Core::isPHP('5.6'))
{
ini_set('php.internal_encoding', $charset);
}
if (
defined('PREG_BAD_UTF8_ERROR') // PCRE must support UTF-8
&& (ICONV_ENABLED === TRUE OR MB_ENABLED === TRUE) // iconv or mbstring must be installed
&& strtoupper($charset) === 'UTF-8' // Application charset must be UTF-8
)
{
define('UTF8_ENABLED', TRUE);
Logger::log('UTF-8 Support Enabled');
}
else
{
define('UTF8_ENABLED', FALSE);
Logger::log('UTF-8 Support Disabled');
}
}
// --------------------------------------------------------------------
/**
* Clean UTF-8 strings
*
* Ensures strings contain only valid UTF-8 characters.
*
* @param string $str String to clean
* @return string
*/
public static function clean_string($str)
{
if (self::is_ascii($str) === FALSE)
{
if (MB_ENABLED)
{
$str = mb_convert_encoding($str, 'UTF-8', 'UTF-8');
}
elseif (ICONV_ENABLED)
{
$str = @iconv('UTF-8', 'UTF-8//IGNORE', $str);
}
}
return $str;
}
// --------------------------------------------------------------------
/**
* Remove ASCII control characters
*
* Removes all ASCII control characters except horizontal tabs,
* line feeds, and carriage returns, as all others can cause
* problems in XML.
*
* @param string $str String to clean
* @return string
*/
public static function safe_ascii_for_xml($str)
{
Helpers::load('common');
return remove_invisible_characters($str, FALSE);
}
// --------------------------------------------------------------------
/**
* Convert to UTF-8
*
* Attempts to convert a string to UTF-8.
*
* @param string $str Input string
* @param string $encoding Input encoding
* @return string $str encoded in UTF-8 or FALSE on failure
*/
public static function convert_to_utf8($str, $encoding)
{
if (MB_ENABLED)
{
return mb_convert_encoding($str, 'UTF-8', $encoding);
}
elseif (ICONV_ENABLED)
{
return @iconv($encoding, 'UTF-8', $str);
}
return FALSE;
}
// --------------------------------------------------------------------
/**
* Is ASCII?
*
* Tests if a string is standard 7-bit ASCII or not.
*
* @param string $str String to check
* @return bool
*/
public static function is_ascii($str)
{
return (preg_match('/[^\x00-\x7F]/S', $str) === 0);
}
/**
* Remove Invisible Characters
*
* This prevents sandwiching null characters
* between ascii characters, like Java\0script.
*
* @param string
* @param bool
* @return string
*/
public static function remove_invisible_characters($str, $url_encoded = TRUE)
{
$non_displayables = array();
// every control character except newline (dec 10),
// carriage return (dec 13) and horizontal tab (dec 09)
if ($url_encoded)
{
$non_displayables[] = '/%0[0-8bcef]/'; // url encoded 00-08, 11, 12, 14, 15
$non_displayables[] = '/%1[0-9a-f]/'; // url encoded 16-31
}
$non_displayables[] = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S'; // 00-08, 11, 12, 14-31, 127
do
{
$str = preg_replace($non_displayables, '', $str, -1, $count);
}
while ($count);
return $str;
}
}

View File

@ -1,6 +1,6 @@
{
"require": {
"php": ">=5.3.0",
"php": ">=5.4.0",
"ext-curl": "*",
"ext-json": "*",
"smarty/smarty": "~3.1"