dbXapp 2.0
RAD, CMS, Module und Runtime-IDE fuer dbXapp
Loading...
Searching...
No Matches
dbxValidator.class.php
Go to the documentation of this file.
1<?php
2
4
5 private array $errorMessages = [];
6
7 private static array $ruleCache = [];
8
9
10 /* =====================================================
11 DB TYPE LIMITS
12 ===================================================== */
13
14 private const INT_RANGE = [
15
16 'tinyint' => [-128,127],
17 'smallint' => [-32768,32767],
18 'mediumint' => [-8388608,8388607],
19 'int' => [-2147483648,2147483647]
20
21 // 🔥 bigint entfernt → wird separat geprüft
22
23 ];
24
25 private const TEXT_LIMIT = [
26
27 'tinytext' => 255,
28 'text' => 65535,
29 'mediumtext' => 16777215,
30 'longtext' => 4294967295
31
32 ];
33
34 private const BLOB_PASS = [
35
36 'blob'=>true,
37 'tinyblob'=>true,
38 'mediumblob'=>true,
39 'longblob'=>true
40
41 ];
42
43
44 /* =====================================================
45 TYPE ALIAS
46 ===================================================== */
47
48 private const TYPE_ALIAS = [
49
50 'integer'=>'int',
51 'numeric'=>'decimal',
52 'double'=>'float',
53 'real'=>'float',
54
55 'varchar2'=>'varchar',
56 'bool'=>'boolean'
57
58 ];
59
60
61 /* =====================================================
62 REGEX
63 ===================================================== */
64
65 private const REGEX = [
66
67 'parameter' => '/^[a-zA-Z0-9._\-|]+$/',
68 'parameters' => '/^[a-zA-Z0-9._\/&=\-|]+$/',
69 'datetime' => '/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(\.\d{1,6})?$/',
70
71 'word' => '/^[\p{L}\p{M}\p{N}@._,:;-]+$/u',
72 'words' => '/^[\p{L}\p{M}\p{N}\s@._,:;-]+$/u',
73 'sqlsearch' => '/^[\p{L}\p{M}\p{N}\s@._,:;\/\-]+$/u',
74
75 'alphanum' => '/^[\p{L}\p{M}0-9@_ .,:-]+$/u',
76
77 'email' => '/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/',
78 'phone' => '/^\+?[0-9\/\- ]+$/'
79
80 ];
81
82
83 /* =====================================================
84 RULE PARSER
85 ===================================================== */
86
87 private function parseRule(string $rules): array {
88
89 if (isset(self::$ruleCache[$rules])) {
90 return self::$ruleCache[$rules];
91 }
92
93 $r=[
94
95 'base'=>'',
96 'extra'=>'',
97 'min'=>null,
98 'max'=>null
99
100 ];
101
102 foreach(explode('|',$rules) as $p){
103
104 if (strpos($p,'=')!==false){
105
106 [$k,$v]=explode('=',$p,2);
107
108 if ($k==='min') $r['min']=(int)$v;
109 elseif ($k==='max') $r['max']=(int)$v;
110
111 continue;
112 }
113
114 if (($pos=strpos($p,'+'))!==false){
115
116 $r['base']=substr($p,0,$pos);
117 $r['extra']=substr($p,$pos+1);
118
119 } else {
120
121 $r['base']=$p;
122 }
123 }
124
125 $r['base']=strtolower($r['base']);
126
127 if (isset(self::TYPE_ALIAS[$r['base']])) {
128 $r['base']=self::TYPE_ALIAS[$r['base']];
129 }
130
131 self::$ruleCache[$rules]=$r;
132
133 return $r;
134 }
135
136
137 /* =====================================================
138 LENGTH
139 ===================================================== */
140
141 private function lengthOK(string $v,$min,$max): bool {
142
143 $l=strlen($v);
144
145 if ($min!==null && $l<$min) return false;
146 if ($max!==null && $l>$max) return false;
147
148 return true;
149 }
150
151
152 /* =====================================================
153 EXTRA STRIP
154 ===================================================== */
155
156 private function stripExtra(string $v,string $extra): string {
157
158 if ($extra==='') return $v;
159
160 return str_replace(str_split($extra),'',$v);
161 }
162
163
164 /* =====================================================
165 DATE / TIME
166 ===================================================== */
167
168 private function validateDate(string $v): bool {
169
170 if (!preg_match('/^\d{4}-\d{2}-\d{2}$/',$v)) return false;
171
172 [$y,$m,$d]=explode('-',$v);
173
174 return checkdate((int)$m,(int)$d,(int)$y);
175 }
176
177 private function validateTime(string $v): bool {
178
179 return (bool)preg_match('/^([01]\d|2[0-3]):[0-5]\d(:[0-5]\d)?$/',$v);
180 }
181
182 private function validateTimestamp(string $v): bool {
183
184 if (!preg_match('/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/',$v,$m))
185 return false;
186
187 return checkdate((int)$m[2],(int)$m[3],(int)$m[1]);
188 }
189
190
191 /* =====================================================
192 INT VALIDATION
193 ===================================================== */
194
195 private function validateInt(string $v,string $type): bool {
196
197 if (!preg_match('/^-?\d+$/',$v)) return false;
198
199 // 🔥 SIMPLE BIGINT (max 19 digits)
200 if ($type === 'bigint') {
201
202 $digits = ltrim($v, '-');
203
204 return strlen($digits) <= 19;
205 }
206
207 if (!isset(self::INT_RANGE[$type])) return true;
208
209 [$min,$max]=self::INT_RANGE[$type];
210
211 $i=(int)$v;
212
213 return ($i>=$min && $i<=$max);
214 }
215
216
217 /* =====================================================
218 SCALAR VALIDATION
219 ===================================================== */
220
221 private function validateScalar($value,array $rule,string $rulestr): bool {
222
223 $base=$rule['base'];
224 $extra=$rule['extra'];
225 $min=$rule['min'];
226 $max=$rule['max'];
227
228 if ($value===null) $value='';
229
230 $orig=$value;
231
232 $value=(string)$value;
233
234 if (!$this->lengthOK($value,$min,$max)){
235 return false;
236 }
237
238 if ($orig===null || $orig==='' || $orig==='0' || $orig==='1' || $orig===0 || $orig===1){
239 return true;
240 }
241
242 $value=$this->stripExtra($value,$extra);
243
244 if ($value === '') {
245 return true;
246 }
247
248 switch($base){
249
250 case '*':
251 $ok=true;
252 break;
253
254 case 'int':
255 case 'tinyint':
256 case 'smallint':
257 case 'mediumint':
258 case 'bigint':
259 $ok=$this->validateInt($value,$base);
260 break;
261
262 case 'decimal':
263 case 'float':
264 $ok=is_numeric($value);
265 break;
266
267 case 'date':
268 $ok=$this->validateDate($value);
269 break;
270
271 case 'time':
272 $ok=$this->validateTime($value);
273 break;
274
275 case 'datetime':
276 case 'timestamp':
277 $ok=$this->validateTimestamp($value);
278 break;
279
280 case 'varchar':
281 case 'char':
282 $ok=true;
283 break;
284
285 case 'boolean':
286 $ok=($value==='0'||$value==='1'||$value==='true'||$value==='false');
287 break;
288
289 case 'json':
290 json_decode($value);
291 $ok=(json_last_error()===JSON_ERROR_NONE);
292 break;
293
294 case 'year':
295 $ok=preg_match('/^\d{4}$/',$value);
296 break;
297
298 default:
299
300 if (isset(self::TEXT_LIMIT[$base])){
301 $ok=strlen($value)<=self::TEXT_LIMIT[$base];
302 break;
303 }
304
305 if (isset(self::BLOB_PASS[$base])){
306 $ok=true;
307 break;
308 }
309
310 if (isset(self::REGEX[$base])){
311 $ok=preg_match(self::REGEX[$base],$value);
312 break;
313 }
314
315 return false;
316 }
317
318 return (bool)$ok;
319 }
320
321
322 /* =====================================================
323 PUBLIC VALIDATE (STRICT)
324 ===================================================== */
325
326 public function validate($value,$rules='parameter',$name='-undef-'): bool {
327
328 $this->errorMessages=[];
329
330 if ($rules== '*' ) return true;
331
332 $parts = explode('|', (string)$rules);
333 $arrayRule = in_array('array', $parts, true);
334
335 if ($arrayRule) {
336 if ($value === null || $value === '') {
337 return true;
338 }
339
340 if (!is_array($value)) {
341 return false;
342 }
343
344 $itemRules = implode('|', array_values(array_filter($parts, static function ($part) {
345 return $part !== 'array';
346 })));
347
348 if ($itemRules === '') {
349 $itemRules = '*';
350 }
351
352 if ($itemRules === '*') {
353 return true;
354 }
355
356 $rule = $this->parseRule($itemRules);
357
358 foreach ($value as $item) {
359 if (is_array($item) || is_object($item) || is_resource($item) || (!is_scalar($item) && $item !== null)) {
360 return false;
361 }
362
363 if (!$this->validateScalar($item, $rule, $itemRules)) {
364 return false;
365 }
366 }
367
368 return true;
369 }
370
371 $rule=$this->parseRule($rules);
372
373 if (is_array($value)) return false;
374 if (is_object($value)) return false;
375 if (is_resource($value)) return false;
376 if (!is_scalar($value) && $value !== null) return false;
377
378 return $this->validateScalar($value,$rule,$rules);
379 }
380
381
382 /* =====================================================
383 CLEAN
384 ===================================================== */
385
386 public function clean($value,$rules,$length=-1,$name='-undef-'){
387
388 if (!is_scalar($value) && $value !== null) return '';
389
390 if ($value===null) $value='';
391 $value = (string)$value;
392 $length = (int)$length;
393
394 if ($length>0 && strlen($value)>$length)
395 $value=substr($value,0,$length);
396
397 return $value;
398 }
399
400
401 /* =====================================================
402 UTIL
403 ===================================================== */
404
405 public function getErrorMessages(): array {
406 return $this->errorMessages;
407 }
408
409 public function clearErrors(): void {
410 $this->errorMessages=[];
411 }
412
413 public function get_rule_val($rules,$rule=''){
414
415 if (is_string($rules)) $rules=explode('|',$rules);
416
417 if (!is_array($rules)) return '';
418
419 foreach ($rules as $r){
420
421 if ($rule==='rule' && strpos($r,'=')===false)
422 return $r;
423
424 if (strpos($r,'=')!==false){
425
426 [$k,$v]=explode('=',$r,2);
427
428 if ($k===$rule)
429 return $v;
430 }
431 }
432
433 return '';
434 }
435
436}
validate($value, $rules='parameter', $name='-undef-')
clean($value, $rules, $length=-1, $name='-undef-')
get_rule_val($rules, $rule='')