'',
'value' => '',
//'default' => '',
'name' => '',
//'id' => '',
'safemode' => '',
'path' => '',
'thumbnail_1' => '',
'thumbnail_2' => '',
];
private static $input_error_text = [];
public function __construct() {
}
/**
* Generates and return class instance
* Eliminates global usage in functions
* Instead of using - `global $defender`, try `\defender->getInstance()`
*
* @return null|static
*/
public static function getInstance() {
if (self::$defender_instance === NULL) {
self::$defender_instance = new static();
}
return self::$defender_instance;
}
public static function set_remoteFile($file) {
self::$remote_file = $file;
}
/**
* Request whether safe to proceed at all times
*
* @return bool
*/
public static function safe() {
if (!defined("FUSION_NULL")) {
return TRUE;
}
return FALSE;
}
/**
* Serialize an array securely
*
* @param array $array
*
* @return string
*/
public static function serialize(array $array = []) {
$return_default = "";
if (is_array($array)) {
return base64_encode(serialize($array));
}
return $return_default;
}
public static function encode($value) {
return base64_encode(json_encode($value));
}
public static function decode($value) {
return json_decode(base64_decode($value), TRUE);
}
/**
* Read serialized array
*
* @param $string - serialized string
*
* @return array|mixed
*/
public static function unserialize($string) {
$return_default = [];
if (!empty($string)) {
$array = unserialize(base64_decode($string));
if (!empty($array)) {
return $array;
}
}
return $return_default;
}
public static function add_field_session(array $array) {
$_SESSION['form_fields'][self::pageHash()][$array['input_name']] = $array;
}
/**
* @param array $array
*/
public function addHoneypot(array $array) {
$_SESSION['honeypots'][self::pageHash()][$array['honeypot']] = $array;
}
/**
* @param string $honeypot
*
* @return string
*/
public function getHoneypot($honeypot = '') {
if ($honeypot && isset($_SESSION['honeypots'][self::pageHash()][$honeypot])) {
return $_SESSION['honeypots'][self::pageHash()][$honeypot];
} else {
if ($honeypot) {
return "This form contains no honeypots";
} else {
return $_SESSION['honeypots'][self::pageHash()];
}
}
}
private static $page_hash = '';
/**
* Hash a token to prevent unauthorized access
*
* @return string
*/
public static function pageHash() {
if (!defined('SECRET_KEY')) {
$chars = ["abcdefghijklmnpqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ", "123456789"];
$count = [(strlen($chars[0]) - 1), (strlen($chars[1]) - 1)];
$key = "";
for ($i = 0; $i < 32; $i++) {
$type = mt_rand(0, 1);
$key .= substr($chars[$type], mt_rand(0, $count[$type]), 1);
}
define('SECRET_KEY', $key);
}
if (empty(self::$page_hash)) {
self::$page_hash = md5(SECRET_KEY);
}
return (string)self::$page_hash;
}
// Checks whether an input was marked as invalid
/**
* Return the current document field session or sessions
* Use for debug purposes
*
* @param string $input_name
*
* @return string
*/
public static function get_current_field_session($input_name = '') {
if ($input_name && isset($_SESSION['form_fields'][self::pageHash()][$input_name])) {
return $_SESSION['form_fields'][self::pageHash()][$input_name];
} else {
if ($input_name) {
return "The session for this field is not found";
} else {
//return $_SESSION['form_fields'];
return $_SESSION['form_fields'][self::pageHash()];
}
}
}
public static function unset_field_session() {
unset($_SESSION['form_fields']);
}
static function sanitize_array($array) {
foreach ($array as $name => $value) {
$array[stripinput($name)] = trim(censorwords(stripinput($value)));
}
return (array)$array;
}
/**
* ID for Session
* No $userName because it can be changed and tampered via Edit Profile.
* Using IP address extends for guest
*
* @return mixed
*/
public static function set_sessionUserID() {
$userdata = fusion_get_userdata();
return !empty($userdata['user_id']) && !isset($_POST['login']) ? (int)fusion_get_userdata('user_id') : str_replace('.', '-', USER_IP);
}
/**
* @param bool|FALSE $value
*/
public function debug($value = FALSE) {
self::$debug = $value;
}
/**
* @return array
*/
public static function getInputErrors() {
return self::$input_errors;
}
/**
* Set and override default field error text
*
* @param $input_name
* @param $text
*/
public static function setErrorText($input_name, $text) {
self::$input_error_text[$input_name] = $text;
}
/**
* Fetches the latest error text of this input
* Important! Ensure your applications do not refresh screen for this error to show.
* Usage \defender::safe(); for conditional redirect.
*
* @param $input_name
*
* @return null
*/
public static function getErrorText($input_name) {
if (self::inputHasError($input_name)) {
return isset(self::$input_error_text[$input_name]) ? self::$input_error_text[$input_name] : NULL;
}
return NULL;
}
public static function inputHasError($input_name) {
if (isset(self::$input_errors[$input_name])) {
return TRUE;
}
return FALSE;
}
public static function get_inputError() {
return self::$input_errors;
}
/**
* @param $key
*
* @return string
*/
public function filterPostArray($key) {
$flag = '';
$input_key = $key;
if (is_array($key)) {
// always use key 0 for filter var
$input_key = $key[0];
$flag = FILTER_REQUIRE_ARRAY;
}
$filtered = post($input_key, FILTER_DEFAULT, $flag);
if (is_array($key)) {
$input_ref = $key;
unset($input_ref[0]);
// Get the value of the filtered post value using the $key array as map
return array_reduce($input_ref, function ($value, $key) {
return (!empty($value[$key]) ? $value[$key] : '');
}, $filtered);
}
return (string)$filtered;
}
/**
* Sanitize
*
* @param $value
* @param string $default
* @param bool|FALSE $input_name
* @param bool|FALSE $is_multiLang
*
* @return string|mixed
* @throws Exception
*/
public function form_sanitizer($value, $default = "", $input_name = FALSE, $is_multiLang = FALSE) {
$val = [];
if ($input_name) {
if ($is_multiLang) {
foreach (fusion_get_enabled_languages() as $lang => $language) {
$iname = $input_name."[".$lang."]";
if (isset($_SESSION['form_fields'][self::pageHash()][$iname])) {
$this->field_config = $_SESSION['form_fields'][self::pageHash()][$iname];
$this->field_name = $iname;
$this->field_value = $value[$lang];
$this->field_default = $default;
$val[$lang] = $this->validate();
}
}
if ($this->field_config['required'] && (!$value[LANGUAGE])) {
self::stop();
$iname = $input_name."[".LANGUAGE."]";
self::setInputError($iname);
return $default;
} else {
$val_ = [];
foreach ($val as $lang => $value) {
$val_[$lang] = $val[$lang];
}
return serialize($val_);
}
} else {
// Make sure that the input was actually defined in code.. AND there must be a value to worth the processing power expense!
if (isset($_SESSION['form_fields'][self::pageHash()][$input_name])) {
$this->field_config = $_SESSION['form_fields'][self::pageHash()][$input_name];
$this->field_name = $input_name;
$this->field_value = $value;
$this->field_default = $default;
/*
* These two checks won't be neccesary after we add the options in all inputs
* NOTE: Please don't pass 'stripinput' as callback, before we reach a callback
* everything is checked and sanitized already. The callback should only check
* if certain conditions are met then return TRUE|FALSE and not do any alterations
* the the value itself
*/
$callback = isset($this->field_config['callback_check']) ? $this->field_config['callback_check'] : FALSE;
$regex = isset($this->field_config['regex']) ? $this->field_config['regex'] : FALSE;
$secured = $this->validate();
// If truly FALSE the check failed
if ($secured === FALSE || ($this->field_config['required'] == 1 && ($secured === FALSE || $secured == '')) ||
($secured != '' && $regex && !preg_match('@^'.$regex.'$@i', $secured)) || // regex will fail for an imploded array, maybe move this check
(is_callable($callback) && !$callback($secured))
) {
self::stop();
self::setInputError($input_name);
// Add regex error message.
if ($secured != '' && $regex && !preg_match('@^'.$regex.'$@i', $secured)) {
addNotice("danger", sprintf(fusion_get_locale('regex_error'), $this->field_config['title']));
unset($locale);
}
// Add a notice
if (self::$debug) {
addNotice('warning', ''.$input_name.':'.($this->field_config['safemode'] ? ' is in SAFEMODE and the' : '').' check failed');
}
// Return user's input for correction
return $this->field_value;
} else {
if (self::$debug) {
addNotice('info', $input_name.' = '.(is_array($secured) ? 'array' : $secured));
}
return $secured;
}
} else {
return $default;
}
}
} else {
if ($value) {
if (!is_array($value)) {
if (intval($value)) {
return stripinput($value); // numbers
} else {
return censorwords(stripinput(trim(preg_replace("/ +/i", " ", $value))));
}
} else {
$secured = [];
foreach ($value as $arr => $unsecured) {
if (intval($unsecured)) {
$secured[] = stripinput($unsecured); // numbers
} else {
$secured[] = censorwords(stripinput(trim(preg_replace("/ +/i", " ", $unsecured))));
}
}
return implode($this->field_config['delimiter'], $secured);
}
} else {
return $default;
}
}
throw new \Exception('The form sanitizer could not handle the request! (input: '.$input_name.')');
}
/**
* Sanitize with input name
*
* @param $key
* @param string $default
* @param bool $input_name
* @param bool $is_multiLang
*
* @return string
* @throws Exception
*/
public function sanitizer($key, $default = '', $input_name = FALSE, $is_multiLang = FALSE) {
$value = $this->filterPostArray($key);
return $this->form_sanitizer($value, $default, $input_name, $is_multiLang);
}
public function fileSanitizer($key, $default = '', $input_name = FALSE) {
$upload = $this->form_sanitizer($_FILES[$key], $default, $input_name);
if (isset($upload['error']) && $upload['error'] == 0) {
return $upload;
}
return [];
}
/** @noinspection PhpInconsistentReturnPointsInspection */
public function validate() {
\defender\Validation::inputName($this->field_name);
\defender\Validation::inputDefault($this->field_default);
\defender\Validation::inputValue($this->field_value);
\defender\Validation::inputConfig($this->field_config);
$locale = fusion_get_locale(LOCALE.LOCALESET.'defender.php');
// Are there situations were inputs could have leading
// or trailing spaces? If not then uncomment line below
//$this->field_value = trim($this->field_value);
// Don't bother processing and validating empty inputs
//if ($this->field_value == '') return $this->field_value;
/**
* Keep this include in the constructor
* This solution was needed to load the defender.inc.php before
* defining LOCALESET
*/
// declare the validation rules and assign them
// type of fields vs type of validator
// execute sanitisation rules at point blank precision using switch
try {
if (!empty($this->field_config['type'])) {
if (empty($this->field_value) && ($this->field_config['type'] !== "number")) {
return $this->field_default;
}
return \defender\Validation::getValidated();
} else {
self::stop();
$locale['type_unknown'] = '%s: has an unknown type set'; // to be moved
addNotice('danger', sprintf($locale['type_unknown'], self::$inputName));
}
} catch (Exception $e) {
self::stop();
addNotice('danger', $e->getMessage());
}
return NULL;
}
/**
* Send an Unsafe Signal acorss all PHP-Fusion Components
* This will automatically halt on all important execution without exiting.
*
* @param $notice - Show custom notice message on validation errors
*/
public static function stop($notice = '') {
if (!defined('FUSION_NULL')) {
define('FUSION_NULL', TRUE);
if ($notice) {
if (function_exists('alert')) {
echo alert($notice);
} else {
addNotice("danger", $notice);
}
}
//addNotice('danger', ''.fusion_get_locale('error_request', LOCALE.LOCALESET.'defender.php').'');
if (self::$debug) {
debug_print_backtrace();
define("STOP_REDIRECT", TRUE);
}
}
}
/*
* Highlight the form field as error
*/
public static function setInputError($input_name) {
self::$input_errors[$input_name] = TRUE;
}
/**
* Generate a key
*
* @param $private_key
*
* @return string
*/
public static function get_encrypt_key($private_key) {
return $encryption_key = openssl_random_pseudo_bytes(32, $private_key); // 256 bits
}
private static function pkcs7_pad($data, $size) {
$length = $size - strlen($data) % $size;
return $data.str_repeat(chr($length), $length);
}
private static function pkcs7_unpad($data) {
return substr($data, 0, -ord($data[strlen($data) - 1]));
}
/**
* Encrypts a string securely with a private key
*
* @param string $string The text to encrypt
* @param string $private_key For better security use \defender::get_encrypt_key to generate your private key
*
* Does not support array encrypt.
*
* @return string
*/
public static function encrypt_string($string, $private_key = 'php-fusion') {
$ivlen = openssl_cipher_iv_length($cipher = "AES-128-CBC");
$iv = openssl_random_pseudo_bytes(16, $ivlen); // 128 bits
$string = self::pkcs7_pad($string, 16);
$ciphertext_raw = openssl_encrypt($string, $cipher, $private_key, $options = OPENSSL_RAW_DATA, $iv);
$hmac = hash_hmac('sha256', $ciphertext_raw, $private_key, $as_binary = TRUE);
return base64_encode($iv.$hmac.$ciphertext_raw);
}
/**
* Decrypts a string securely with a private key
*
* @param $string - The string to decrypt
* @param $private_key - For better security use \defender::get_encrypt_key to generate your private key
*
* @return null|string
*/
public static function decrypt_string($string, $private_key = 'php-fusion') {
$c = base64_decode($string);
$ivlen = openssl_cipher_iv_length($cipher = "AES-128-CBC");
$iv = substr($c, 0, $ivlen);
$hmac = substr($c, $ivlen, $sha2len = 32);
$ciphertext_raw = substr($c, $ivlen + $sha2len);
$string = openssl_decrypt($ciphertext_raw, $cipher, $private_key, $options = OPENSSL_RAW_DATA, $iv);
$string = self::pkcs7_unpad($string);
$calcmac = hash_hmac('sha256', $ciphertext_raw, $private_key, $as_binary = TRUE);
if (!function_exists('hash_equals')) {
function hash_equals($str1, $str2) {
if (strlen($str1) != strlen($str2)) {
return FALSE;
} else {
$res = $str1 ^ $str2;
$ret = 0;
for ($i = strlen($res) - 1; $i >= 0; $i--) {
$ret |= ord($res[$i]);
}
return !$ret;
}
}
}
if (hash_equals($hmac, $calcmac))//PHP 5.6+ timing attack safe comparison
{
return $string;
}
return NULL;
}
}
/**
* Verify and Sanitize Inputs
*
* @param $value
* @param string $default
* @param bool|FALSE $input_name
* @param bool|FALSE $is_multiLang
*
* @return mixed
* @throws Exception
*/
function form_sanitizer($value, $default = "", $input_name = FALSE, $is_multiLang = FALSE) {
return defender::getInstance()->form_sanitizer($value, $default, $input_name, $is_multiLang);
}
/**
* Verify and Sanitize Inputs with input_name
* A more secured method
*
* @param $value
* @param string $default
* @param bool $input_name
* @param bool $is_multiLang
*
* @return string
* @throws Exception
*/
function sanitizer($value, $default = '', $input_name = FALSE, $is_multiLang = FALSE) {
return defender::getInstance()->sanitizer($value, $default, $input_name, $is_multiLang);
}
function file_sanitizer($value, $default = '', $input_name = FALSE) {
return defender::getInstance()->fileSanitizer($value, $default, $input_name);
}
/**
* @param null $key
* @param int $type
* @param string $flags
*
* @return mixed
*/
function get($key = NULL, $type = FILTER_DEFAULT, $flags = '') {
if ($flags == FILTER_VALIDATE_INT) {
if (isset($_GET[$key]) && isnum($_GET[$key]) && $_GET[$key] > PHP_INT_MAX) {
return intval($_GET[$key]);
}
return intval(0);
}
return stripinput(filter_input(INPUT_GET, $key, $type, $flags));
}
/**
* @param $key
* @param int $type
* @param $flags
*
* @return mixed
*/
function post($key, $type = FILTER_DEFAULT, $flags = '') {
if (is_array($key)) {
$flag = '';
$input_key = $key;
if (is_array($key)) {
// always use key 0 for filter var
$input_key = $key[0];
$flag = FILTER_REQUIRE_ARRAY;
}
$filtered = post($input_key, FILTER_DEFAULT, $flag);
if (is_array($key)) {
$input_ref = $key;
unset($input_ref[0]);
// Get the value of the filtered post value using the $key array as map
return array_reduce($input_ref, function ($value, $key) {
return (!empty($value[$key]) ? $value[$key] : '');
}, $filtered);
}
return (string)$filtered;
}
if ($flags == FILTER_VALIDATE_INT) {
if (isset($_POST[$key]) && isnum($_POST[$key]) && $_POST[$key] > PHP_INT_MAX) {
return intval($_GET[$key]);
}
}
return filter_input(INPUT_POST, $key, $type, $flags);
}
/**
* @param $key
*
* @return array
*/
function post_array($key) {
return (array)\defender::getInstance()->filterPostArray($key);
}
/**
* @param $key
* @param int $type
*
* @return mixed
*/
function server($key, $type = FILTER_DEFAULT) {
return filter_input(INPUT_SERVER, $key, $type);
}
/**
* @param $key
*
* @return bool
*/
function file_uploaded($key) {
if (!empty($_FILES)) {
if (is_array($key)) {
$files =& $_FILES;
foreach ($key as $pkey) {
$files =& $files[$pkey];
}
return is_uploaded_file($files['tmp_name']);
}
return is_uploaded_file($_FILES[$key]['tmp_name']);
}
return FALSE;
}
/**
* @param $key
* @param int $type
*
* @return mixed
*/
function environment($key, $type = FILTER_DEFAULT) {
return filter_input(INPUT_ENV, $key, $type);
}
/**
* @param $key
* @param int $type
*
* @return mixed
*/
function cookie($key, $type = FILTER_DEFAULT) {
return stripinput(filter_input(INPUT_COOKIE, $key, $type));
}
function fusion_safe() {
return defender::safe();
}
require_once __DIR__.'/defender/validation.php';
require_once __DIR__.'/defender/token.php';
require_once __DIR__.'/defender/mimecheck.php';