Skip to content

Commit e8f9bb0

Browse files
using HTMLPurifier against XSS, Injection, Output Safety
1 parent 159a820 commit e8f9bb0

9 files changed

Lines changed: 225 additions & 161 deletions

File tree

src/Methods/CsrfToken.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77

88
use Tamedevelopers\Support\Str;
9+
use Tamedevelopers\Support\Process\Http;
910

1011
class CsrfToken{
1112

@@ -126,7 +127,7 @@ static public function generateCSRFInputToken()
126127
static private function generateTokenOnPageLoad()
127128
{
128129
// if csrf is allowed to be use
129-
if(self::$csrf && Str::upper($_SERVER['REQUEST_METHOD']) == 'GET' && empty($_REQUEST[self::$session])){
130+
if(self::$csrf && Str::upper(Http::method()) == 'GET' && empty($_REQUEST[self::$session])){
130131
unset($_SESSION[self::$session]);
131132
$_SESSION[self::$session] = self::generateOrIgnore();
132133
}

src/Methods/Datatype.php

Lines changed: 119 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,29 @@
55
namespace Tamedevelopers\Validator\Methods;
66

77
use Tamedevelopers\Support\Str;
8-
use Tamedevelopers\Support\Tame;
8+
use Tamedevelopers\Support\Purify;
9+
use Tamedevelopers\Support\Utility;
910

1011
class Datatype {
1112

13+
// Rule name groups (constants instead of magic strings)
14+
private const RULE_EMAIL = ['email', 'e'];
15+
private const RULE_INT = ['int', 'integer', 'i'];
16+
private const RULE_FLOAT = ['float', 'f'];
17+
private const RULE_URL = ['url', 'link', 'u', 'anchor'];
18+
private const RULE_ARRAY = ['array', 'a'];
19+
private const RULE_BOOL = ['bool', 'b'];
20+
private const RULE_ENUM = ['enum', 'en', 'enm'];
21+
private const RULE_HTML = ['html'];
22+
private const RULE_DEV = ['dev'];
23+
1224
/**
1325
* Private instance of parent validator
1426
*
1527
* @var mixed
1628
*/
1729
private static $validator;
1830

19-
2031
/**
2132
* Validate if form data is set
2233
* And if data type is correct
@@ -39,7 +50,7 @@ public static function validate($rulesData)
3950
$type = true;
4051

4152
// check for ENUM types
42-
if(self::checkEmun($rulesData)){
53+
if(self::checkEnum($rulesData)){
4354
$type = self::validateForminput($rulesData);
4455
}
4556

@@ -65,127 +76,135 @@ public static function validate($rulesData)
6576
}
6677

6778
/**
68-
* Majorly for Form's Radio/Checkbox
69-
* If either of those input type is not checked yet, input not send along form
70-
* So we need determine if it should be set by the system, or not.
79+
* Get form input safely
7180
*
72-
* @param array $rulesData
73-
* - [data_type|input_name|operator|value]
81+
* @param string $inputName Name of the input
82+
* @param string|null $dataType Optional type for validation/purification
83+
* @param mixed $default Default value if input not set
7484
*
75-
* @return bool
85+
* @return mixed
7686
*/
77-
protected static function checkEmun($rulesData)
87+
public static function getFormInput(string $inputName, ?string $dataType = null, $default = null)
7888
{
79-
if(in_array(strtolower($rulesData['data_type']), ['enum', 'en', 'enm'])){
80-
return true;
89+
// Check if input exists in validator param
90+
$value = self::$validator->param[$inputName] ?? $default;
91+
92+
// If no data type specified, return raw value
93+
if (!$dataType) {
94+
return $value;
8195
}
8296

83-
return false;
97+
// Apply validation/purification based on type
98+
$rulesData = [
99+
'data_type' => $dataType,
100+
'input_name' => $inputName,
101+
];
102+
103+
$validated = self::validateForminput($rulesData);
104+
105+
// If validation fails, return default value
106+
if ($validated === false) {
107+
return $default;
108+
}
109+
110+
return $validated;
84111
}
85112

86113
/**
87114
* Validate form input
88-
* If either of those input type is not checked yet, input not send along form
89-
* So we need determine if it should be set by the system, or not.
90-
*
91-
* @param array $rulesData
115+
*
116+
* @param array $rulesData
92117
* - [data_type|input_name|operator|value]
93-
*
94-
* @return bool|string
118+
*
119+
* @return string|int|float|bool|array
95120
*/
96-
protected static function validateForminput($rulesData)
121+
protected static function validateFormInput(array $rulesData)
97122
{
98-
// lowercase
99-
$rulesData['data_type'] = Str::lower($rulesData['data_type']);
100-
$request = self::requestType(self::$validator->config['request']);
101-
$param = self::$validator->param[$rulesData['input_name']];
102-
103-
switch($rulesData['data_type']){
104-
105-
// email validation
106-
case (in_array($rulesData['data_type'], ['email', 'e'])):
107-
$type = filter_input($request, $rulesData['input_name'], FILTER_VALIDATE_EMAIL);
108-
break;
109-
110-
// integer validation
111-
case (in_array($rulesData['data_type'], ['int', 'integer', 'i'])):
112-
$type = filter_input($request, $rulesData['input_name'], FILTER_VALIDATE_INT);
113-
break;
114-
115-
// float validation
116-
case (in_array($rulesData['data_type'], ['float', 'f'])):
117-
$type = filter_input($request, $rulesData['input_name'], FILTER_VALIDATE_FLOAT);
118-
break;
119-
120-
// url validation
121-
case (in_array($rulesData['data_type'], ['url', 'link', 'u'])):
122-
$type = filter_input($request, $rulesData['input_name'], FILTER_VALIDATE_URL);
123-
break;
124-
125-
// array validation
126-
case (in_array($rulesData['data_type'], ['array', 'a'])):
127-
if(is_string($param)){
128-
$array = json_decode($param, true);
129-
} else{
130-
$array = $param;
123+
$ruleFlag = Str::lower($rulesData['data_type']);
124+
$ruleInput = $rulesData['input_name'];
125+
$value = self::$validator->param[$ruleInput] ?? null;
126+
127+
switch (true) {
128+
129+
// ---------------- EMAIL ----------------
130+
case in_array($ruleFlag, self::RULE_EMAIL, true):
131+
$valid = Utility::validateEmail($value);
132+
return $valid ? Purify::string((string) $value) : false;
133+
134+
// ---------------- INTEGER ----------------
135+
case in_array($ruleFlag, self::RULE_INT, true):
136+
$valid = filter_var($value, FILTER_VALIDATE_INT);
137+
return $valid !== false ? intval($valid) : false;
138+
139+
// ---------------- FLOAT ----------------
140+
case in_array($ruleFlag, self::RULE_FLOAT, true):
141+
$valid = filter_var($value, FILTER_VALIDATE_FLOAT);
142+
return $valid !== false ? floatval($valid) : false;
143+
144+
// ---------------- URL ----------------
145+
case in_array($ruleFlag, self::RULE_URL, true):
146+
if ($value && !preg_match('/^https?:\/\//i', $value)) {
147+
$value = 'http://' . $value;
131148
}
132-
$type = isset($param) && is_array($array) && count($array) > 0;
133-
break;
134-
135-
// bool|bool validation
136-
case (in_array($rulesData['data_type'], ['bool', 'b'])):
137-
$type = filter_input($request, $rulesData['input_name'], FILTER_VALIDATE_BOOL);
138-
break;
139-
140-
// enum validation
141-
case (in_array($rulesData['data_type'], ['enum', 'en', 'enm'])):
142-
// if value is not set -- it will return null
143-
if(is_null(filter_input($request, $rulesData['input_name']))){
144-
$type = '';
145-
} else{
146-
$type = filter_input($request, $rulesData['input_name']);
149+
$valid = filter_var($value, FILTER_VALIDATE_URL);
150+
return $valid ? Purify::string((string) $valid) : false;
151+
152+
// ---------------- ARRAY ----------------
153+
case in_array($ruleFlag, self::RULE_ARRAY, true):
154+
$array = is_string($value) ? json_decode($value, true) : $value;
155+
156+
$sanitizeArray = function ($arr) use (&$sanitizeArray) {
157+
return array_map(fn($v) =>
158+
is_array($v) ? $sanitizeArray($v) :
159+
(is_string($v) ? Purify::string($v) : $v), $arr);
160+
};
161+
162+
return (is_array($array) && count($array) > 0)
163+
? $sanitizeArray($array)
164+
: false;
165+
166+
// ---------------- BOOLEAN ----------------
167+
case in_array($ruleFlag, self::RULE_BOOL, true):
168+
$valid = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
169+
return $valid === null ? false : $valid;
170+
171+
// ---------------- ENUM ----------------
172+
case in_array($ruleFlag, self::RULE_ENUM, true):
173+
if ($value === null || ($value === '' && $value !== '0')) {
174+
return false;
147175
}
176+
return Purify::string((string) $value);
148177

149-
// mostly for value of 0
150-
if(empty($type) && $type != '0') {
151-
$type = false;
152-
}
153-
break;
178+
// ---------------- HTML ----------------
179+
case in_array($ruleFlag, self::RULE_HTML, true):
180+
$sanitized = Purify::html($value);
181+
return (empty($sanitized) && $sanitized !== '0') ? false : $sanitized;
154182

155-
// string validation
156-
default:
157-
$type = Tame::filter_input(
158-
filter_input($request, $rulesData['input_name'])
159-
);
183+
// ---------------- DEV ----------------
184+
case in_array($ruleFlag, self::RULE_DEV, true):
185+
$sanitized = Purify::dev($value);
186+
return (empty($sanitized) && $sanitized !== '0') ? false : $sanitized;
160187

161-
// mostly for value of 0
162-
if(empty($type) && $type != '0') {
163-
$type = false;
164-
}
165-
break;
188+
// ---------------- DEFAULT STRING ----------------
189+
default:
190+
$sanitized = Purify::string($value);
191+
return (empty($sanitized) && $sanitized !== '0') ? false : $sanitized;
166192
}
167-
168-
return $type;
169193
}
170194

171-
172195
/**
173-
* Get Request Type
174-
*
175-
* @param mixed $request
176-
* @return int
196+
* Majorly for Form's Radio/Checkbox
197+
* If either of those input type is not checked yet, input not send along form
198+
* So we need determine if it should be set by the system, or not.
199+
*
200+
* @param array $rulesData
201+
* - [data_type|input_name|operator|value]
202+
*
203+
* @return bool
177204
*/
178-
static private function requestType($request = null)
205+
protected static function checkEnum($rulesData)
179206
{
180-
if(empty($request) || $request == 2){
181-
$request = $_SERVER['REQUEST_METHOD'];
182-
}
183-
184-
if(Str::lower($request) == 'post' || $request == 0){
185-
return INPUT_POST;
186-
}
187-
188-
return INPUT_GET;
207+
return in_array(strtolower($rulesData['data_type']), ['enum', 'en', 'enm']);
189208
}
190209

191210
}

src/Methods/GetRequestType.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Tamedevelopers\Validator\Methods;
66

7+
use Tamedevelopers\Support\Process\Http;
78
use Tamedevelopers\Support\Str;
89

910
class GetRequestType {
@@ -25,7 +26,7 @@ public static function request($request = null)
2526
if(!empty($request)){
2627
// convert any and get needed request
2728
if($request === 'all'){
28-
$requestStatus = self::fetchRequest($_SERVER['REQUEST_METHOD']);
29+
$requestStatus = self::fetchRequest(Http::method());
2930
} else{
3031
$requestStatus = self::fetchRequest($request);
3132
}
@@ -34,7 +35,6 @@ public static function request($request = null)
3435
return $requestStatus;
3536
}
3637

37-
3838
/**
3939
* Fetch Requerst
4040
*

src/Methods/Operator.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,6 @@ public static function validate($validator, $dataType = [])
168168
}
169169
}
170170
}
171-
172171
}
173172

174173
return $operatorError;

0 commit comments

Comments
 (0)