first commit

This commit is contained in:
2024-07-15 11:28:08 +02:00
commit f52d538ea5
21891 changed files with 6161164 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
{
"name": "flycartinc/inputhelper",
"description": "Data Sanitization and Validation With WordPress",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "Ashlin Rejo"
}
],
"require": {
"php": ">=5.3.0"
},
"require-dev": {
},
"autoload": {
"psr-4": {
"FlycartInput\\": "src/"
}
}
}

View File

@@ -0,0 +1,429 @@
<?php
namespace FlycartInput;
if (!defined('ABSPATH')) exit; // Exit if accessed directly
use Serializable;
use Countable;
use FlycartInput\FFilterInput;
require_once 'FFilterInput.php';
/**
* This is an abstracted input class used to manage retrieving data from the application environment.
*
* @since 11.1
*
* @property-read JInput $get
* @property-read JInput $post
* @property-read JInput $request
* @property-read JInput $server
* @property-read JInputFiles $files
* @property-read JInputCookie $cookie
*
* @method integer getInt() getInt($name, $default = null) Get a signed integer.
* @method integer getUint() getUint($name, $default = null) Get an unsigned integer.
* @method float getFloat() getFloat($name, $default = null) Get a floating-point number.
* @method boolean getBool() getBool($name, $default = null) Get a boolean.
* @method string getWord() getWord($name, $default = null)
* @method string getAlnum() getAlnum($name, $default = null)
* @method string getCmd() getCmd($name, $default = null)
* @method string getBase64() getBase64($name, $default = null)
* @method string getString() getString($name, $default = null)
* @method string getHtml() getHtml($name, $default = null)
* @method string getPath() getPath($name, $default = null)
* @method string getUsername() getUsername($name, $default = null)
*/
class FInput implements Serializable, Countable
{
/**
* Options array for the FInput instance.
*
* @var array
* @since 11.1
*/
protected $options = array();
/**
* Filter object to use.
*
* @var FFilterInput
*/
protected $filter = null;
/**
* Input data.
*
* @var array
* @since 11.1
*/
protected $data = array();
/**
* Input objects
*
* @var array
* @since 11.1
*/
protected $inputs = array();
public static $instance;
/**
* Constructor.
*
* @param array $source Source data (Optional, default is $_REQUEST)
* @param array $options Array of configuration parameters (Optional)
*
* @since 11.1
*/
public function __construct($source = null, array $options = array())
{
if (isset($options['filter']))
{
$this->filter = $options['filter'];
}
else
{
$this->filter = FFilterInput::getInstance();
}
if (is_null($source))
{
$this->data = &$_REQUEST;
}
else
{
$this->data = $source;
}
// Set the options for the class.
$this->options = $options;
}
/**
* To create instance
* */
public static function getInstance($config = array())
{
if (!self::$instance)
{
self::$instance = new self();
}
return self::$instance;
}
/**
* Magic method to get an input object
*
* @param mixed $name Name of the input object to retrieve.
*
* @return FInput The request input object
*
* @since 11.1
*/
public function __get($name)
{
if (isset($this->inputs[$name]))
{
return $this->inputs[$name];
}
$className = 'FInput' . ucfirst($name);
if (class_exists($className))
{
$this->inputs[$name] = new $className(null, $this->options);
return $this->inputs[$name];
}
$superGlobal = '_' . strtoupper($name);
if (isset($GLOBALS[$superGlobal]))
{
$this->inputs[$name] = new FInput($GLOBALS[$superGlobal], $this->options);
return $this->inputs[$name];
}
// TODO throw an exception
}
/**
* Get the number of variables.
*
* @return integer The number of variables in the input.
*
* @since 12.2
* @see Countable::count()
*/
public function count()
{
return count($this->data);
}
/**
* Gets a value from the input data.
*
* @param string $name Name of the value to get.
* @param mixed $default Default value to return if variable does not exist.
* @param string $filter Filter to apply to the value.
*
* @return mixed The filtered input value.
*
* @since 11.1
*/
public function get($name, $default = null, $filter = 'cmd')
{
if (isset($this->data[$name]))
{
return $this->filter->clean($this->data[$name], $filter);
}
return $default;
}
/**
* Gets an array of values from the request.
*
* @param array $vars Associative array of keys and filter types to apply.
* If empty and datasource is null, all the input data will be returned
* but filtered using the filter given by the parameter defaultFilter in
* JFilterInput::clean.
* @param mixed $datasource Array to retrieve data from, or null.
* @param string $defaultFilter Default filter used in JFilterInput::clean if vars is empty and
* datasource is null. If 'unknown', the default case is used in
* FFilterInput::clean.
*
* @return mixed The filtered input data.
*
* @since 11.1
*/
public function getArray(array $vars = array(), $datasource = null, $defaultFilter = 'unknown')
{
return $this->getArrayRecursive($vars, $datasource, $defaultFilter, false);
}
/**
* Gets an array of values from the request.
*
* @param array $vars Associative array of keys and filter types to apply.
* If empty and datasource is null, all the input data will be returned
* but filtered using the filter given by the parameter defaultFilter in
* JFilterInput::clean.
* @param mixed $datasource Array to retrieve data from, or null.
* @param string $defaultFilter Default filter used in JFilterInput::clean if vars is empty and
* datasource is null. If 'unknown', the default case is used in
* FFilterInput::clean.
* @param bool $recursion Flag to indicate a recursive function call.
*
* @return mixed The filtered input data.
*
* @since 3.4.2
*/
protected function getArrayRecursive(array $vars = array(), $datasource = null, $defaultFilter = 'unknown', $recursion = false)
{
if (empty($vars) && is_null($datasource))
{
$vars = $this->data;
}
else
{
if (!$recursion)
{
$defaultFilter = null;
}
}
$results = array();
foreach ($vars as $k => $v)
{
if (is_array($v))
{
if (is_null($datasource))
{
$results[$k] = $this->getArrayRecursive($v, $this->get($k, null, 'array'), $defaultFilter, true);
}
else
{
$results[$k] = $this->getArrayRecursive($v, $datasource[$k], $defaultFilter, true);
}
}
else
{
$filter = isset($defaultFilter) ? $defaultFilter : $v;
if (is_null($datasource))
{
$results[$k] = $this->get($k, null, $filter);
}
elseif (isset($datasource[$k]))
{
$results[$k] = $this->filter->clean($datasource[$k], $filter);
}
else
{
$results[$k] = $this->filter->clean(null, $filter);
}
}
}
return $results;
}
/**
* Sets a value
*
* @param string $name Name of the value to set.
* @param mixed $value Value to assign to the input.
*
* @return void
*
* @since 11.1
*/
public function set($name, $value)
{
$this->data[$name] = $value;
}
/**
* Define a value. The value will only be set if there's no value for the name or if it is null.
*
* @param string $name Name of the value to define.
* @param mixed $value Value to assign to the input.
*
* @return void
*
* @since 12.1
*/
public function def($name, $value)
{
if (isset($this->data[$name]))
{
return;
}
$this->data[$name] = $value;
}
/**
* Magic method to get filtered input data.
*
* @param string $name Name of the filter type prefixed with 'get'.
* @param array $arguments [0] The name of the variable [1] The default value.
*
* @return mixed The filtered input value.
*
* @since 11.1
*/
public function __call($name, $arguments)
{
if (substr($name, 0, 3) == 'get')
{
$filter = substr($name, 3);
$default = null;
if (isset($arguments[1]))
{
$default = $arguments[1];
}
return $this->get($arguments[0], $default, $filter);
}
}
/**
* Gets the request method.
*
* @return string The request method.
*
* @since 11.1
*/
public function getMethod()
{
// Get method if exist
$method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : '';
$method = strtoupper($method);
return $method;
}
/**
* Method to serialize the input.
*
* @return string The serialized input.
*
* @since 12.1
*/
public function serialize()
{
// Load all of the inputs.
$this->loadAllInputs();
// Remove $_ENV and $_SERVER from the inputs.
$inputs = $this->inputs;
unset($inputs['env']);
unset($inputs['server']);
// Serialize the options, data, and inputs.
return serialize(array($this->options, $this->data, $inputs));
}
/**
* Method to unserialize the input.
*
* @param string $input The serialized input.
*
* @return FInput The input object.
*
* @since 12.1
*/
public function unserialize($input)
{
// Unserialize the options, data, and inputs.
list($this->options, $this->data, $this->inputs) = unserialize($input);
// Load the filter.
if (isset($this->options['filter']))
{
$this->filter = $this->options['filter'];
}
else
{
$this->filter = FFilterInput::getInstance();
}
}
/**
* Method to load all of the global inputs.
*
* @return void
*
* @since 12.1
*/
protected function loadAllInputs()
{
static $loaded = false;
if (!$loaded)
{
// Load up all the globals.
foreach ($GLOBALS as $global => $data)
{
// Check if the global starts with an underscore.
if (strpos($global, '_') === 0)
{
// Convert global name to input name.
$global = strtolower($global);
$global = substr($global, 1);
// Get the input.
$this->$global;
}
}
$loaded = true;
}
}
}

View File

@@ -0,0 +1,944 @@
<?php
namespace FlycartInput;
if (!defined('ABSPATH')) exit; // Exit if accessed directly
use FlycartInput\StringHelper;
require_once 'StringHelper.php';
/**
* InputFilter is a class for filtering input from any data source
*/
class InputFilter
{
/**
* A container for InputFilter instances.
*
* @var InputFilter[]
* @since 1.0
* @deprecated 2.0
*/
protected static $instances = array();
/**
* The array of permitted tags (white list).
*
* @var array
* @since 1.0
*/
public $tagsArray;
/**
* The array of permitted tag attributes (white list).
*
* @var array
* @since 1.0
*/
public $attrArray;
/**
* The method for sanitising tags: WhiteList method = 0 (default), BlackList method = 1
*
* @var integer
* @since 1.0
*/
public $tagsMethod;
/**
* The method for sanitising attributes: WhiteList method = 0 (default), BlackList method = 1
*
* @var integer
* @since 1.0
*/
public $attrMethod;
/**
* A flag for XSS checks. Only auto clean essentials = 0, Allow clean blacklisted tags/attr = 1
*
* @var integer
* @since 1.0
*/
public $xssAuto;
/**
* The list of the default blacklisted tags.
*
* @var array
* @since 1.0
*/
public $tagBlacklist = array(
'applet',
'body',
'bgsound',
'base',
'basefont',
'embed',
'frame',
'frameset',
'head',
'html',
'id',
'iframe',
'ilayer',
'layer',
'link',
'meta',
'name',
'object',
'script',
'style',
'title',
'xml',
);
/**
* The list of the default blacklisted tag attributes. All event handlers implicit.
*
* @var array
* @since 1.0
*/
public $attrBlacklist = array(
'action',
'background',
'codebase',
'dynsrc',
'lowsrc',
);
/**
* Constructor for InputFilter class.
*
* @param array $tagsArray List of user-defined tags
* @param array $attrArray List of user-defined attributes
* @param integer $tagsMethod WhiteList method = 0, BlackList method = 1
* @param integer $attrMethod WhiteList method = 0, BlackList method = 1
* @param integer $xssAuto Only auto clean essentials = 0, Allow clean blacklisted tags/attr = 1
*
* @since 1.0
*/
public function __construct($tagsArray = array(), $attrArray = array(), $tagsMethod = 0, $attrMethod = 0, $xssAuto = 1)
{
// Make sure user defined arrays are in lowercase
$tagsArray = array_map('strtolower', (array) $tagsArray);
$attrArray = array_map('strtolower', (array) $attrArray);
// Assign member variables
$this->tagsArray = $tagsArray;
$this->attrArray = $attrArray;
$this->tagsMethod = $tagsMethod;
$this->attrMethod = $attrMethod;
$this->xssAuto = $xssAuto;
}
/**
* Method to be called by another php script. Processes for XSS and
* specified bad code.
*
* @param mixed $source Input string/array-of-string to be 'cleaned'
* @param string $type The return type for the variable:
* INT: An integer, or an array of integers,
* UINT: An unsigned integer, or an array of unsigned integers,
* FLOAT: A floating point number, or an array of floating point numbers,
* BOOLEAN: A boolean value,
* WORD: A string containing A-Z or underscores only (not case sensitive),
* ALNUM: A string containing A-Z or 0-9 only (not case sensitive),
* CMD: A string containing A-Z, 0-9, underscores, periods or hyphens (not case sensitive),
* BASE64: A string containing A-Z, 0-9, forward slashes, plus or equals (not case sensitive),
* STRING: A fully decoded and sanitised string (default),
* HTML: A sanitised string,
* ARRAY: An array,
* PATH: A sanitised file path, or an array of sanitised file paths,
* TRIM: A string trimmed from normal, non-breaking and multibyte spaces
* USERNAME: Do not use (use an application specific filter),
* RAW: The raw string is returned with no filtering,
* unknown: An unknown filter will act like STRING. If the input is an array it will return an
* array of fully decoded and sanitised strings.
*
* @return mixed 'Cleaned' version of input parameter
*
* @since 1.0
*/
public function clean($source, $type = 'string')
{
// Handle the type constraint cases
switch (strtoupper($type))
{
case 'INT':
case 'INTEGER':
$pattern = '/[-+]?[0-9]+/';
if (is_array($source))
{
$result = array();
// Iterate through the array
foreach ($source as $eachString)
{
preg_match($pattern, (string) $eachString, $matches);
$result[] = isset($matches[0]) ? (int) $matches[0] : 0;
}
}
else
{
preg_match($pattern, (string) $source, $matches);
$result = isset($matches[0]) ? (int) $matches[0] : 0;
}
break;
case 'UINT':
$pattern = '/[-+]?[0-9]+/';
if (is_array($source))
{
$result = array();
// Iterate through the array
foreach ($source as $eachString)
{
preg_match($pattern, (string) $eachString, $matches);
$result[] = isset($matches[0]) ? abs((int) $matches[0]) : 0;
}
}
else
{
preg_match($pattern, (string) $source, $matches);
$result = isset($matches[0]) ? abs((int) $matches[0]) : 0;
}
break;
case 'FLOAT':
case 'DOUBLE':
$pattern = '/[-+]?[0-9]+(\.[0-9]+)?([eE][-+]?[0-9]+)?/';
if (is_array($source))
{
$result = array();
// Iterate through the array
foreach ($source as $eachString)
{
preg_match($pattern, (string) $eachString, $matches);
$result[] = isset($matches[0]) ? (float) $matches[0] : 0;
}
}
else
{
preg_match($pattern, (string) $source, $matches);
$result = isset($matches[0]) ? (float) $matches[0] : 0;
}
break;
case 'BOOL':
case 'BOOLEAN':
$result = (bool) $source;
break;
case 'WORD':
$pattern = '/[^A-Z_]/i';
if (is_array($source))
{
$result = array();
// Iterate through the array
foreach ($source as $eachString)
{
$result[] = (string) preg_replace($pattern, '', $eachString);
}
}
else
{
$result = (string) preg_replace($pattern, '', $source);
}
break;
case 'ALNUM':
$pattern = '/[^A-Z0-9]/i';
if (is_array($source))
{
$result = array();
// Iterate through the array
foreach ($source as $eachString)
{
$result[] = (string) preg_replace($pattern, '', $eachString);
}
}
else
{
$result = (string) preg_replace($pattern, '', $source);
}
break;
case 'CMD':
$pattern = '/[^A-Z0-9_\.-]/i';
if (is_array($source))
{
$result = array();
// Iterate through the array
foreach ($source as $eachString)
{
$cleaned = (string) preg_replace($pattern, '', $eachString);
$result[] = ltrim($cleaned, '.');
}
}
else
{
$result = (string) preg_replace($pattern, '', $source);
$result = ltrim($result, '.');
}
break;
case 'BASE64':
$pattern = '/[^A-Z0-9\/+=]/i';
if (is_array($source))
{
$result = array();
// Iterate through the array
foreach ($source as $eachString)
{
$result[] = (string) preg_replace($pattern, '', $eachString);
}
}
else
{
$result = (string) preg_replace($pattern, '', $source);
}
break;
case 'STRING':
if (is_array($source))
{
$result = array();
// Iterate through the array
foreach ($source as $eachString)
{
$result[] = (string) $this->remove($this->decode((string) $eachString));
}
}
else
{
$result = (string) $this->remove($this->decode((string) $source));
}
break;
case 'HTML':
if (is_array($source))
{
$result = array();
// Iterate through the array
foreach ($source as $eachString)
{
$result[] = (string) $this->remove((string) $eachString);
}
}
else
{
$result = (string) $this->remove((string) $source);
}
break;
case 'ARRAY':
$result = (array) $source;
break;
case 'PATH':
$pattern = '/^[A-Za-z0-9_\/-]+[A-Za-z0-9_\.-]*([\\\\\/][A-Za-z0-9_-]+[A-Za-z0-9_\.-]*)*$/';
if (is_array($source))
{
$result = array();
// Iterate through the array
foreach ($source as $eachString)
{
preg_match($pattern, (string) $eachString, $matches);
$result[] = isset($matches[0]) ? (string) $matches[0] : '';
}
}
else
{
preg_match($pattern, $source, $matches);
$result = isset($matches[0]) ? (string) $matches[0] : '';
}
break;
case 'TRIM':
if (is_array($source))
{
$result = array();
// Iterate through the array
foreach ($source as $eachString)
{
$cleaned = (string) trim($eachString);
$cleaned = StringHelper::trim($cleaned, chr(0xE3) . chr(0x80) . chr(0x80));
$result[] = StringHelper::trim($cleaned, chr(0xC2) . chr(0xA0));
}
}
else
{
$result = (string) trim($source);
$result = StringHelper::trim($result, chr(0xE3) . chr(0x80) . chr(0x80));
$result = StringHelper::trim($result, chr(0xC2) . chr(0xA0));
}
break;
case 'USERNAME':
$pattern = '/[\x00-\x1F\x7F<>"\'%&]/';
if (is_array($source))
{
$result = array();
// Iterate through the array
foreach ($source as $eachString)
{
$result[] = (string) preg_replace($pattern, '', $eachString);
}
}
else
{
$result = (string) preg_replace($pattern, '', $source);
}
break;
case 'RAW':
$result = $source;
break;
default:
// Are we dealing with an array?
if (is_array($source))
{
foreach ($source as $key => $value)
{
// Filter element for XSS and other 'bad' code etc.
if (is_string($value))
{
$source[$key] = $this->remove($this->decode($value));
}
}
$result = $source;
}
else
{
// Or a string?
if (is_string($source) && !empty($source))
{
// Filter source for XSS and other 'bad' code etc.
$result = $this->remove($this->decode($source));
}
else
{
// Not an array or string... return the passed parameter
$result = $source;
}
}
break;
}
return $result;
}
/**
* Function to determine if contents of an attribute are safe
*
* @param array $attrSubSet A 2 element array for attribute's name, value
*
* @return boolean True if bad code is detected
*
* @since 1.0
*/
public static function checkAttribute($attrSubSet)
{
$attrSubSet[0] = strtolower($attrSubSet[0]);
$attrSubSet[1] = strtolower($attrSubSet[1]);
return (((strpos($attrSubSet[1], 'expression') !== false) && ($attrSubSet[0]) == 'style') || (strpos($attrSubSet[1], 'javascript:') !== false) ||
(strpos($attrSubSet[1], 'behaviour:') !== false) || (strpos($attrSubSet[1], 'vbscript:') !== false) ||
(strpos($attrSubSet[1], 'mocha:') !== false) || (strpos($attrSubSet[1], 'livescript:') !== false));
}
/**
* Internal method to iteratively remove all unwanted tags and attributes
*
* @param string $source Input string to be 'cleaned'
*
* @return string 'Cleaned' version of input parameter
*
* @since 1.0
*/
protected function remove($source)
{
$loopCounter = 0;
// Iteration provides nested tag protection
while ($source != $this->cleanTags($source))
{
$source = $this->cleanTags($source);
$loopCounter++;
}
return $source;
}
/**
* Internal method to strip a string of certain tags
*
* @param string $source Input string to be 'cleaned'
*
* @return string 'Cleaned' version of input parameter
*
* @since 1.0
*/
protected function cleanTags($source)
{
// First, pre-process this for illegal characters inside attribute values
$source = $this->escapeAttributeValues($source);
// In the beginning we don't really have a tag, so everything is postTag
$preTag = null;
$postTag = $source;
$currentSpace = false;
// Setting to null to deal with undefined variables
$attr = '';
// Is there a tag? If so it will certainly start with a '<'.
$tagOpen_start = strpos($source, '<');
while ($tagOpen_start !== false)
{
// Get some information about the tag we are processing
$preTag .= substr($postTag, 0, $tagOpen_start);
$postTag = substr($postTag, $tagOpen_start);
$fromTagOpen = substr($postTag, 1);
$tagOpen_end = strpos($fromTagOpen, '>');
// Check for mal-formed tag where we have a second '<' before the first '>'
$nextOpenTag = (strlen($postTag) > $tagOpen_start) ? strpos($postTag, '<', $tagOpen_start + 1) : false;
if (($nextOpenTag !== false) && ($nextOpenTag < $tagOpen_end))
{
// At this point we have a mal-formed tag -- remove the offending open
$postTag = substr($postTag, 0, $tagOpen_start) . substr($postTag, $tagOpen_start + 1);
$tagOpen_start = strpos($postTag, '<');
continue;
}
// Let's catch any non-terminated tags and skip over them
if ($tagOpen_end === false)
{
$postTag = substr($postTag, $tagOpen_start + 1);
$tagOpen_start = strpos($postTag, '<');
continue;
}
// Do we have a nested tag?
$tagOpen_nested = strpos($fromTagOpen, '<');
if (($tagOpen_nested !== false) && ($tagOpen_nested < $tagOpen_end))
{
$preTag .= substr($postTag, 0, ($tagOpen_nested + 1));
$postTag = substr($postTag, ($tagOpen_nested + 1));
$tagOpen_start = strpos($postTag, '<');
continue;
}
// Let's get some information about our tag and setup attribute pairs
$tagOpen_nested = (strpos($fromTagOpen, '<') + $tagOpen_start + 1);
$currentTag = substr($fromTagOpen, 0, $tagOpen_end);
$tagLength = strlen($currentTag);
$tagLeft = $currentTag;
$attrSet = array();
$currentSpace = strpos($tagLeft, ' ');
// Are we an open tag or a close tag?
if (substr($currentTag, 0, 1) == '/')
{
// Close Tag
$isCloseTag = true;
list ($tagName) = explode(' ', $currentTag);
$tagName = substr($tagName, 1);
}
else
{
// Open Tag
$isCloseTag = false;
list ($tagName) = explode(' ', $currentTag);
}
/*
* Exclude all "non-regular" tagnames
* OR no tagname
* OR remove if xssauto is on and tag is blacklisted
*/
if ((!preg_match("/^[a-z][a-z0-9]*$/i", $tagName)) || (!$tagName) || ((in_array(strtolower($tagName), $this->tagBlacklist)) && ($this->xssAuto)))
{
$postTag = substr($postTag, ($tagLength + 2));
$tagOpen_start = strpos($postTag, '<');
// Strip tag
continue;
}
/*
* Time to grab any attributes from the tag... need this section in
* case attributes have spaces in the values.
*/
while ($currentSpace !== false)
{
$attr = '';
$fromSpace = substr($tagLeft, ($currentSpace + 1));
$nextEqual = strpos($fromSpace, '=');
$nextSpace = strpos($fromSpace, ' ');
$openQuotes = strpos($fromSpace, '"');
$closeQuotes = strpos(substr($fromSpace, ($openQuotes + 1)), '"') + $openQuotes + 1;
$startAtt = '';
$startAttPosition = 0;
// Find position of equal and open quotes ignoring
if (preg_match('#\s*=\s*\"#', $fromSpace, $matches, PREG_OFFSET_CAPTURE))
{
$startAtt = $matches[0][0];
$startAttPosition = $matches[0][1];
$closeQuotes = strpos(substr($fromSpace, ($startAttPosition + strlen($startAtt))), '"') + $startAttPosition + strlen($startAtt);
$nextEqual = $startAttPosition + strpos($startAtt, '=');
$openQuotes = $startAttPosition + strpos($startAtt, '"');
$nextSpace = strpos(substr($fromSpace, $closeQuotes), ' ') + $closeQuotes;
}
// Do we have an attribute to process? [check for equal sign]
if ($fromSpace != '/' && (($nextEqual && $nextSpace && $nextSpace < $nextEqual) || !$nextEqual))
{
if (!$nextEqual)
{
$attribEnd = strpos($fromSpace, '/') - 1;
}
else
{
$attribEnd = $nextSpace - 1;
}
// If there is an ending, use this, if not, do not worry.
if ($attribEnd > 0)
{
$fromSpace = substr($fromSpace, $attribEnd + 1);
}
}
if (strpos($fromSpace, '=') !== false)
{
// If the attribute value is wrapped in quotes we need to grab the substring from
// the closing quote, otherwise grab until the next space.
if (($openQuotes !== false) && (strpos(substr($fromSpace, ($openQuotes + 1)), '"') !== false))
{
$attr = substr($fromSpace, 0, ($closeQuotes + 1));
}
else
{
$attr = substr($fromSpace, 0, $nextSpace);
}
}
else
// No more equal signs so add any extra text in the tag into the attribute array [eg. checked]
{
if ($fromSpace != '/')
{
$attr = substr($fromSpace, 0, $nextSpace);
}
}
// Last Attribute Pair
if (!$attr && $fromSpace != '/')
{
$attr = $fromSpace;
}
// Add attribute pair to the attribute array
$attrSet[] = $attr;
// Move search point and continue iteration
$tagLeft = substr($fromSpace, strlen($attr));
$currentSpace = strpos($tagLeft, ' ');
}
// Is our tag in the user input array?
$tagFound = in_array(strtolower($tagName), $this->tagsArray);
// If the tag is allowed let's append it to the output string.
if ((!$tagFound && $this->tagsMethod) || ($tagFound && !$this->tagsMethod))
{
// Reconstruct tag with allowed attributes
if (!$isCloseTag)
{
// Open or single tag
$attrSet = $this->cleanAttributes($attrSet);
$preTag .= '<' . $tagName;
for ($i = 0, $count = count($attrSet); $i < $count; $i++)
{
$preTag .= ' ' . $attrSet[$i];
}
// Reformat single tags to XHTML
if (strpos($fromTagOpen, '</' . $tagName))
{
$preTag .= '>';
}
else
{
$preTag .= ' />';
}
}
else
// Closing tag
{
$preTag .= '</' . $tagName . '>';
}
}
// Find next tag's start and continue iteration
$postTag = substr($postTag, ($tagLength + 2));
$tagOpen_start = strpos($postTag, '<');
}
// Append any code after the end of tags and return
if ($postTag != '<')
{
$preTag .= $postTag;
}
return $preTag;
}
/**
* Internal method to strip a tag of certain attributes
*
* @param array $attrSet Array of attribute pairs to filter
*
* @return array Filtered array of attribute pairs
*
* @since 1.0
*/
protected function cleanAttributes($attrSet)
{
$newSet = array();
$count = count($attrSet);
// Iterate through attribute pairs
for ($i = 0; $i < $count; $i++)
{
// Skip blank spaces
if (!$attrSet[$i])
{
continue;
}
// Split into name/value pairs
$attrSubSet = explode('=', trim($attrSet[$i]), 2);
// Take the last attribute in case there is an attribute with no value
$attrSubSet_0 = explode(' ', trim($attrSubSet[0]));
$attrSubSet[0] = array_pop($attrSubSet_0);
// Remove all "non-regular" attribute names
// AND blacklisted attributes
if ((!preg_match('/[a-z]*$/i', $attrSubSet[0]))
|| (($this->xssAuto) && ((in_array(strtolower($attrSubSet[0]), $this->attrBlacklist))
|| (substr($attrSubSet[0], 0, 2) == 'on'))))
{
continue;
}
// XSS attribute value filtering
if (isset($attrSubSet[1]))
{
// Trim leading and trailing spaces
$attrSubSet[1] = trim($attrSubSet[1]);
// Strips unicode, hex, etc
$attrSubSet[1] = str_replace('&#', '', $attrSubSet[1]);
// Strip normal newline within attr value
$attrSubSet[1] = preg_replace('/[\n\r]/', '', $attrSubSet[1]);
// Strip double quotes
$attrSubSet[1] = str_replace('"', '', $attrSubSet[1]);
// Convert single quotes from either side to doubles (Single quotes shouldn't be used to pad attr values)
if ((substr($attrSubSet[1], 0, 1) == "'") && (substr($attrSubSet[1], (strlen($attrSubSet[1]) - 1), 1) == "'"))
{
$attrSubSet[1] = substr($attrSubSet[1], 1, (strlen($attrSubSet[1]) - 2));
}
// Strip slashes
$attrSubSet[1] = stripslashes($attrSubSet[1]);
}
else
{
continue;
}
// Autostrip script tags
if (self::checkAttribute($attrSubSet))
{
continue;
}
// Is our attribute in the user input array?
$attrFound = in_array(strtolower($attrSubSet[0]), $this->attrArray);
// If the tag is allowed lets keep it
if ((!$attrFound && $this->attrMethod) || ($attrFound && !$this->attrMethod))
{
// Does the attribute have a value?
if (empty($attrSubSet[1]) === false)
{
$newSet[] = $attrSubSet[0] . '="' . $attrSubSet[1] . '"';
}
elseif ($attrSubSet[1] === "0")
{
// Special Case
// Is the value 0?
$newSet[] = $attrSubSet[0] . '="0"';
}
else
{
// Leave empty attributes alone
$newSet[] = $attrSubSet[0] . '=""';
}
}
}
return $newSet;
}
/**
* Try to convert to plaintext
*
* @param string $source The source string.
*
* @return string Plaintext string
*
* @since 1.0
* @deprecated This method will be removed once support for PHP 5.3 is discontinued.
*/
protected function decode($source)
{
return html_entity_decode($source, ENT_QUOTES, 'UTF-8');
}
/**
* Escape < > and " inside attribute values
*
* @param string $source The source string.
*
* @return string Filtered string
*
* @since 1.0
*/
protected function escapeAttributeValues($source)
{
$alreadyFiltered = '';
$remainder = $source;
$badChars = array('<', '"', '>');
$escapedChars = array('&lt;', '&quot;', '&gt;');
// Process each portion based on presence of =" and "<space>, "/>, or ">
// See if there are any more attributes to process
while (preg_match('#<[^>]*?=\s*?(\"|\')#s', $remainder, $matches, PREG_OFFSET_CAPTURE))
{
// Get the portion before the attribute value
$quotePosition = $matches[0][1];
$nextBefore = $quotePosition + strlen($matches[0][0]);
// Figure out if we have a single or double quote and look for the matching closing quote
// Closing quote should be "/>, ">, "<space>, or " at the end of the string
$quote = substr($matches[0][0], -1);
$pregMatch = ($quote == '"') ? '#(\"\s*/\s*>|\"\s*>|\"\s+|\"$)#' : "#(\'\s*/\s*>|\'\s*>|\'\s+|\'$)#";
// Get the portion after attribute value
if (preg_match($pregMatch, substr($remainder, $nextBefore), $matches, PREG_OFFSET_CAPTURE))
{
// We have a closing quote
$nextAfter = $nextBefore + $matches[0][1];
}
else
{
// No closing quote
$nextAfter = strlen($remainder);
}
// Get the actual attribute value
$attributeValue = substr($remainder, $nextBefore, $nextAfter - $nextBefore);
// Escape bad chars
$attributeValue = str_replace($badChars, $escapedChars, $attributeValue);
$attributeValue = $this->stripCssExpressions($attributeValue);
$alreadyFiltered .= substr($remainder, 0, $nextBefore) . $attributeValue . $quote;
$remainder = substr($remainder, $nextAfter + 1);
}
// At this point, we just have to return the $alreadyFiltered and the $remainder
return $alreadyFiltered . $remainder;
}
/**
* Remove CSS Expressions in the form of <property>:expression(...)
*
* @param string $source The source string.
*
* @return string Filtered string
*
* @since 1.0
*/
protected function stripCssExpressions($source)
{
// Strip any comments out (in the form of /*...*/)
$test = preg_replace('#\/\*.*\*\/#U', '', $source);
// Test for :expression
if (!stripos($test, ':expression'))
{
// Not found, so we are done
$return = $source;
}
else
{
// At this point, we have stripped out the comments and have found :expression
// Test stripped string for :expression followed by a '('
if (preg_match_all('#:expression\s*\(#', $test, $matches))
{
// If found, remove :expression
$test = str_ireplace(':expression', '', $test);
$return = $test;
}
}
return $return;
}
}

View File

@@ -0,0 +1,11 @@
**How to use?**
Add the code as required
use FlycartInput\FInput;
or
require_once 'FlycartInput/FInput.php';
**To get an input value:**
$postData = FInput::getInstance();
$page_id = $postData->get('page_id'));

View File

@@ -0,0 +1,834 @@
<?php
namespace FlycartInput;
if (!defined('ABSPATH')) exit; // Exit if accessed directly
// PHP mbstring and iconv local configuration
if (version_compare(PHP_VERSION, '5.6', '>='))
{
@ini_set('default_charset', 'UTF-8');
}
else
{
// Check if mbstring extension is loaded and attempt to load it if not present except for windows
if (extension_loaded('mbstring'))
{
@ini_set('mbstring.internal_encoding', 'UTF-8');
@ini_set('mbstring.http_input', 'UTF-8');
@ini_set('mbstring.http_output', 'UTF-8');
}
// Same for iconv
if (function_exists('iconv'))
{
iconv_set_encoding('internal_encoding', 'UTF-8');
iconv_set_encoding('input_encoding', 'UTF-8');
iconv_set_encoding('output_encoding', 'UTF-8');
}
}
/**
* String handling class for UTF-8 data wrapping the phputf8 library. All functions assume the validity of UTF-8 strings.
*
* @since 1.3.0
*/
abstract class StringHelper
{
/**
* Increment styles.
*
* @var array
* @since 1.3.0
*/
protected static $incrementStyles = array(
'dash' => array(
'#-(\d+)$#',
'-%d'
),
'default' => array(
array('#\((\d+)\)$#', '#\(\d+\)$#'),
array(' (%d)', '(%d)'),
),
);
/**
* Increments a trailing number in a string.
*
* Used to easily create distinct labels when copying objects. The method has the following styles:
*
* default: "Label" becomes "Label (2)"
* dash: "Label" becomes "Label-2"
*
* @param string $string The source string.
* @param string $style The the style (default|dash).
* @param integer $n If supplied, this number is used for the copy, otherwise it is the 'next' number.
*
* @return string The incremented string.
*
* @since 1.3.0
*/
public static function increment($string, $style = 'default', $n = 0)
{
$styleSpec = isset(static::$incrementStyles[$style]) ? static::$incrementStyles[$style] : static::$incrementStyles['default'];
// Regular expression search and replace patterns.
if (is_array($styleSpec[0]))
{
$rxSearch = $styleSpec[0][0];
$rxReplace = $styleSpec[0][1];
}
else
{
$rxSearch = $rxReplace = $styleSpec[0];
}
// New and old (existing) sprintf formats.
if (is_array($styleSpec[1]))
{
$newFormat = $styleSpec[1][0];
$oldFormat = $styleSpec[1][1];
}
else
{
$newFormat = $oldFormat = $styleSpec[1];
}
// Check if we are incrementing an existing pattern, or appending a new one.
if (preg_match($rxSearch, $string, $matches))
{
$n = empty($n) ? ($matches[1] + 1) : $n;
$string = preg_replace($rxReplace, sprintf($oldFormat, $n), $string);
}
else
{
$n = empty($n) ? 2 : $n;
$string .= sprintf($newFormat, $n);
}
return $string;
}
/**
* Tests whether a string contains only 7bit ASCII bytes.
*
* You might use this to conditionally check whether a string needs handling as UTF-8 or not, potentially offering performance
* benefits by using the native PHP equivalent if it's just ASCII e.g.;
*
* <code>
* if (StringHelper::is_ascii($someString))
* {
* // It's just ASCII - use the native PHP version
* $someString = strtolower($someString);
* }
* else
* {
* $someString = StringHelper::strtolower($someString);
* }
* </code>
*
* @param string $str The string to test.
*
* @return boolean True if the string is all ASCII
*
* @since 1.3.0
*/
public static function is_ascii($str)
{
return utf8_is_ascii($str);
}
/**
* UTF-8 aware alternative to ord()
*
* Returns the unicode ordinal for a character.
*
* @param string $chr UTF-8 encoded character
*
* @return integer Unicode ordinal for the character
*
* @see http://www.php.net/ord
* @since 1.4.0
*/
public static function ord($chr)
{
return utf8_ord($chr);
}
/**
* UTF-8 aware alternative to strpos()
*
* Find position of first occurrence of a string.
*
* @param string $str String being examined
* @param string $search String being searched for
* @param integer $offset Optional, specifies the position from which the search should be performed
*
* @return mixed Number of characters before the first match or FALSE on failure
*
* @see http://www.php.net/strpos
* @since 1.3.0
*/
public static function strpos($str, $search, $offset = false)
{
if ($offset === false)
{
return utf8_strpos($str, $search);
}
return utf8_strpos($str, $search, $offset);
}
/**
* UTF-8 aware alternative to strrpos()
*
* Finds position of last occurrence of a string.
*
* @param string $str String being examined.
* @param string $search String being searched for.
* @param integer $offset Offset from the left of the string.
*
* @return mixed Number of characters before the last match or false on failure
*
* @see http://www.php.net/strrpos
* @since 1.3.0
*/
public static function strrpos($str, $search, $offset = 0)
{
return utf8_strrpos($str, $search, $offset);
}
/**
* UTF-8 aware alternative to substr()
*
* Return part of a string given character offset (and optionally length).
*
* @param string $str String being processed
* @param integer $offset Number of UTF-8 characters offset (from left)
* @param integer $length Optional length in UTF-8 characters from offset
*
* @return mixed string or FALSE if failure
*
* @see http://www.php.net/substr
* @since 1.3.0
*/
public static function substr($str, $offset, $length = false)
{
if ($length === false)
{
return utf8_substr($str, $offset);
}
return utf8_substr($str, $offset, $length);
}
/**
* UTF-8 aware alternative to strtolower()
*
* Make a string lowercase
*
* Note: The concept of a characters "case" only exists is some alphabets such as Latin, Greek, Cyrillic, Armenian and archaic Georgian - it does
* not exist in the Chinese alphabet, for example. See Unicode Standard Annex #21: Case Mappings
*
* @param string $str String being processed
*
* @return mixed Either string in lowercase or FALSE is UTF-8 invalid
*
* @see http://www.php.net/strtolower
* @since 1.3.0
*/
public static function strtolower($str)
{
return utf8_strtolower($str);
}
/**
* UTF-8 aware alternative to strtoupper()
*
* Make a string uppercase
*
* Note: The concept of a characters "case" only exists is some alphabets such as Latin, Greek, Cyrillic, Armenian and archaic Georgian - it does
* not exist in the Chinese alphabet, for example. See Unicode Standard Annex #21: Case Mappings
*
* @param string $str String being processed
*
* @return mixed Either string in uppercase or FALSE is UTF-8 invalid
*
* @see http://www.php.net/strtoupper
* @since 1.3.0
*/
public static function strtoupper($str)
{
return utf8_strtoupper($str);
}
/**
* UTF-8 aware alternative to strlen()
*
* Returns the number of characters in the string (NOT THE NUMBER OF BYTES).
*
* @param string $str UTF-8 string.
*
* @return integer Number of UTF-8 characters in string.
*
* @see http://www.php.net/strlen
* @since 1.3.0
*/
public static function strlen($str)
{
return utf8_strlen($str);
}
/**
* UTF-8 aware alternative to str_ireplace()
*
* Case-insensitive version of str_replace()
*
* @param string $search String to search
* @param string $replace Existing string to replace
* @param string $str New string to replace with
* @param integer $count Optional count value to be passed by referene
*
* @return string UTF-8 String
*
* @see http://www.php.net/str_ireplace
* @since 1.3.0
*/
public static function str_ireplace($search, $replace, $str, $count = null)
{
if ($count === false)
{
return utf8_ireplace($search, $replace, $str);
}
return utf8_ireplace($search, $replace, $str, $count);
}
/**
* UTF-8 aware alternative to str_pad()
*
* Pad a string to a certain length with another string.
* $padStr may contain multi-byte characters.
*
* @param string $input The input string.
* @param integer $length If the value is negative, less than, or equal to the length of the input string, no padding takes place.
* @param string $padStr The string may be truncated if the number of padding characters can't be evenly divided by the string's length.
* @param integer $type The type of padding to apply
*
* @return string
*
* @see http://www.php.net/str_pad
* @since 1.4.0
*/
public static function str_pad($input, $length, $padStr = ' ', $type = STR_PAD_RIGHT)
{
return utf8_str_pad($input, $length, $padStr, $type);
}
/**
* UTF-8 aware alternative to str_split()
*
* Convert a string to an array.
*
* @param string $str UTF-8 encoded string to process
* @param integer $split_len Number to characters to split string by
*
* @return array
*
* @see http://www.php.net/str_split
* @since 1.3.0
*/
public static function str_split($str, $split_len = 1)
{
return utf8_str_split($str, $split_len);
}
/**
* UTF-8/LOCALE aware alternative to strcasecmp()
*
* A case insensitive string comparison.
*
* @param string $str1 string 1 to compare
* @param string $str2 string 2 to compare
* @param mixed $locale The locale used by strcoll or false to use classical comparison
*
* @return integer < 0 if str1 is less than str2; > 0 if str1 is greater than str2, and 0 if they are equal.
*
* @see http://www.php.net/strcasecmp
* @see http://www.php.net/strcoll
* @see http://www.php.net/setlocale
* @since 1.3.0
*/
public static function strcasecmp($str1, $str2, $locale = false)
{
if ($locale)
{
// Get current locale
$locale0 = setlocale(LC_COLLATE, 0);
if (!$locale = setlocale(LC_COLLATE, $locale))
{
$locale = $locale0;
}
// See if we have successfully set locale to UTF-8
if (!stristr($locale, 'UTF-8') && stristr($locale, '_') && preg_match('~\.(\d+)$~', $locale, $m))
{
$encoding = 'CP' . $m[1];
}
elseif (stristr($locale, 'UTF-8') || stristr($locale, 'utf8'))
{
$encoding = 'UTF-8';
}
else
{
$encoding = 'nonrecodable';
}
// If we successfully set encoding it to utf-8 or encoding is sth weird don't recode
if ($encoding == 'UTF-8' || $encoding == 'nonrecodable')
{
return strcoll(utf8_strtolower($str1), utf8_strtolower($str2));
}
return strcoll(
static::transcode(utf8_strtolower($str1), 'UTF-8', $encoding),
static::transcode(utf8_strtolower($str2), 'UTF-8', $encoding)
);
}
return utf8_strcasecmp($str1, $str2);
}
/**
* UTF-8/LOCALE aware alternative to strcmp()
*
* A case sensitive string comparison.
*
* @param string $str1 string 1 to compare
* @param string $str2 string 2 to compare
* @param mixed $locale The locale used by strcoll or false to use classical comparison
*
* @return integer < 0 if str1 is less than str2; > 0 if str1 is greater than str2, and 0 if they are equal.
*
* @see http://www.php.net/strcmp
* @see http://www.php.net/strcoll
* @see http://www.php.net/setlocale
* @since 1.3.0
*/
public static function strcmp($str1, $str2, $locale = false)
{
if ($locale)
{
// Get current locale
$locale0 = setlocale(LC_COLLATE, 0);
if (!$locale = setlocale(LC_COLLATE, $locale))
{
$locale = $locale0;
}
// See if we have successfully set locale to UTF-8
if (!stristr($locale, 'UTF-8') && stristr($locale, '_') && preg_match('~\.(\d+)$~', $locale, $m))
{
$encoding = 'CP' . $m[1];
}
elseif (stristr($locale, 'UTF-8') || stristr($locale, 'utf8'))
{
$encoding = 'UTF-8';
}
else
{
$encoding = 'nonrecodable';
}
// If we successfully set encoding it to utf-8 or encoding is sth weird don't recode
if ($encoding == 'UTF-8' || $encoding == 'nonrecodable')
{
return strcoll($str1, $str2);
}
return strcoll(static::transcode($str1, 'UTF-8', $encoding), static::transcode($str2, 'UTF-8', $encoding));
}
return strcmp($str1, $str2);
}
/**
* UTF-8 aware alternative to strcspn()
*
* Find length of initial segment not matching mask.
*
* @param string $str The string to process
* @param string $mask The mask
* @param integer $start Optional starting character position (in characters)
* @param integer $length Optional length
*
* @return integer The length of the initial segment of str1 which does not contain any of the characters in str2
*
* @see http://www.php.net/strcspn
* @since 1.3.0
*/
public static function strcspn($str, $mask, $start = null, $length = null)
{
if ($start === false && $length === false)
{
return utf8_strcspn($str, $mask);
}
if ($length === false)
{
return utf8_strcspn($str, $mask, $start);
}
return utf8_strcspn($str, $mask, $start, $length);
}
/**
* UTF-8 aware alternative to stristr()
*
* Returns all of haystack from the first occurrence of needle to the end. Needle and haystack are examined in a case-insensitive manner to
* find the first occurrence of a string using case insensitive comparison.
*
* @param string $str The haystack
* @param string $search The needle
*
* @return string the sub string
*
* @see http://www.php.net/stristr
* @since 1.3.0
*/
public static function stristr($str, $search)
{
return utf8_stristr($str, $search);
}
/**
* UTF-8 aware alternative to strrev()
*
* Reverse a string.
*
* @param string $str String to be reversed
*
* @return string The string in reverse character order
*
* @see http://www.php.net/strrev
* @since 1.3.0
*/
public static function strrev($str)
{
return utf8_strrev($str);
}
/**
* UTF-8 aware alternative to strspn()
*
* Find length of initial segment matching mask.
*
* @param string $str The haystack
* @param string $mask The mask
* @param integer $start Start optional
* @param integer $length Length optional
*
* @return integer
*
* @see http://www.php.net/strspn
* @since 1.3.0
*/
public static function strspn($str, $mask, $start = null, $length = null)
{
if ($start === null && $length === null)
{
return utf8_strspn($str, $mask);
}
if ($length === null)
{
return utf8_strspn($str, $mask, $start);
}
return utf8_strspn($str, $mask, $start, $length);
}
/**
* UTF-8 aware alternative to substr_replace()
*
* Replace text within a portion of a string.
*
* @param string $str The haystack
* @param string $repl The replacement string
* @param integer $start Start
* @param integer $length Length (optional)
*
* @return string
*
* @see http://www.php.net/substr_replace
* @since 1.3.0
*/
public static function substr_replace($str, $repl, $start, $length = null)
{
// Loaded by library loader
if ($length === false)
{
return utf8_substr_replace($str, $repl, $start);
}
return utf8_substr_replace($str, $repl, $start, $length);
}
/**
* UTF-8 aware replacement for ltrim()
*
* Strip whitespace (or other characters) from the beginning of a string. You only need to use this if you are supplying the charlist
* optional arg and it contains UTF-8 characters. Otherwise ltrim will work normally on a UTF-8 string.
*
* @param string $str The string to be trimmed
* @param string $charlist The optional charlist of additional characters to trim
*
* @return string The trimmed string
*
* @see http://www.php.net/ltrim
* @since 1.3.0
*/
public static function ltrim($str, $charlist = false)
{
if (empty($charlist) && $charlist !== false)
{
return $str;
}
if ($charlist === false)
{
return utf8_ltrim($str);
}
return utf8_ltrim($str, $charlist);
}
/**
* UTF-8 aware replacement for rtrim()
*
* Strip whitespace (or other characters) from the end of a string. You only need to use this if you are supplying the charlist
* optional arg and it contains UTF-8 characters. Otherwise rtrim will work normally on a UTF-8 string.
*
* @param string $str The string to be trimmed
* @param string $charlist The optional charlist of additional characters to trim
*
* @return string The trimmed string
*
* @see http://www.php.net/rtrim
* @since 1.3.0
*/
public static function rtrim($str, $charlist = false)
{
if (empty($charlist) && $charlist !== false)
{
return $str;
}
if ($charlist === false)
{
return utf8_rtrim($str);
}
return utf8_rtrim($str, $charlist);
}
/**
* UTF-8 aware replacement for trim()
*
* Strip whitespace (or other characters) from the beginning and end of a string. You only need to use this if you are supplying the charlist
* optional arg and it contains UTF-8 characters. Otherwise trim will work normally on a UTF-8 string
*
* @param string $str The string to be trimmed
* @param string $charlist The optional charlist of additional characters to trim
*
* @return string The trimmed string
*
* @see http://www.php.net/trim
* @since 1.3.0
*/
public static function trim($str, $charlist = false)
{
if (empty($charlist) && $charlist !== false)
{
return $str;
}
if ($charlist === false)
{
return utf8_trim($str);
}
return utf8_trim($str, $charlist);
}
/**
* UTF-8 aware alternative to ucfirst()
*
* Make a string's first character uppercase or all words' first character uppercase.
*
* @param string $str String to be processed
* @param string $delimiter The words delimiter (null means do not split the string)
* @param string $newDelimiter The new words delimiter (null means equal to $delimiter)
*
* @return string If $delimiter is null, return the string with first character as upper case (if applicable)
* else consider the string of words separated by the delimiter, apply the ucfirst to each words
* and return the string with the new delimiter
*
* @see http://www.php.net/ucfirst
* @since 1.3.0
*/
public static function ucfirst($str, $delimiter = null, $newDelimiter = null)
{
if ($delimiter === null)
{
return utf8_ucfirst($str);
}
if ($newDelimiter === null)
{
$newDelimiter = $delimiter;
}
return implode($newDelimiter, array_map('utf8_ucfirst', explode($delimiter, $str)));
}
/**
* UTF-8 aware alternative to ucwords()
*
* Uppercase the first character of each word in a string.
*
* @param string $str String to be processed
*
* @return string String with first char of each word uppercase
*
* @see http://www.php.net/ucwords
* @since 1.3.0
*/
public static function ucwords($str)
{
return utf8_ucwords($str);
}
/**
* Transcode a string.
*
* @param string $source The string to transcode.
* @param string $from_encoding The source encoding.
* @param string $to_encoding The target encoding.
*
* @return mixed The transcoded string, or null if the source was not a string.
*
* @link https://bugs.php.net/bug.php?id=48147
*
* @since 1.3.0
*/
public static function transcode($source, $from_encoding, $to_encoding)
{
if (is_string($source))
{
switch (ICONV_IMPL)
{
case 'glibc':
return @iconv($from_encoding, $to_encoding . '//TRANSLIT,IGNORE', $source);
case 'libiconv':
default:
return iconv($from_encoding, $to_encoding . '//IGNORE//TRANSLIT', $source);
}
}
return null;
}
/**
* Tests a string as to whether it's valid UTF-8 and supported by the Unicode standard.
*
* Note: this function has been modified to simple return true or false.
*
* @param string $str UTF-8 encoded string.
*
* @return boolean true if valid
*
* @author <hsivonen@iki.fi>
* @see http://hsivonen.iki.fi/php-utf8/
* @see compliant
* @since 1.3.0
*/
public static function valid($str)
{
return utf8_is_valid($str);
}
/**
* Tests whether a string complies as UTF-8.
*
* This will be much faster than StringHelper::valid() but will pass five and six octet UTF-8 sequences, which are not supported by Unicode and
* so cannot be displayed correctly in a browser. In other words it is not as strict as StringHelper::valid() but it's faster. If you use it to
* validate user input, you place yourself at the risk that attackers will be able to inject 5 and 6 byte sequences (which may or may not be a
* significant risk, depending on what you are are doing).
*
* @param string $str UTF-8 string to check
*
* @return boolean TRUE if string is valid UTF-8
*
* @see StringHelper::valid
* @see http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php#54805
* @since 1.3.0
*/
public static function compliant($str)
{
return utf8_compliant($str);
}
/**
* Converts Unicode sequences to UTF-8 string.
*
* @param string $str Unicode string to convert
*
* @return string UTF-8 string
*
* @since 1.3.0
*/
public static function unicode_to_utf8($str)
{
if (extension_loaded('mbstring'))
{
return preg_replace_callback(
'/\\\\u([0-9a-fA-F]{4})/',
function ($match)
{
return mb_convert_encoding(pack('H*', $match[1]), 'UTF-8', 'UCS-2BE');
},
$str
);
}
return $str;
}
/**
* Converts Unicode sequences to UTF-16 string.
*
* @param string $str Unicode string to convert
*
* @return string UTF-16 string
*
* @since 1.3.0
*/
public static function unicode_to_utf16($str)
{
if (extension_loaded('mbstring'))
{
return preg_replace_callback(
'/\\\\u([0-9a-fA-F]{4})/',
function ($match)
{
return mb_convert_encoding(pack('H*', $match[1]), 'UTF-8', 'UTF-16BE');
},
$str
);
}
return $str;
}
}