146 lines
5.4 KiB
PHP
146 lines
5.4 KiB
PHP
<?php
|
|
namespace App\Helpers;
|
|
|
|
/**
|
|
* Class Validator
|
|
* Enterprise Data Validation Engine (Input & API Request Guard)
|
|
*
|
|
* @package App\Helpers
|
|
*/
|
|
class Validator
|
|
{
|
|
private array $errors = [];
|
|
private array $data;
|
|
|
|
public function __construct(array $data)
|
|
{
|
|
$this->data = $data;
|
|
}
|
|
|
|
/**
|
|
* Create and run validation rules
|
|
*
|
|
* @param array $data
|
|
* @param array $rules Rule definitions e.g. ['national_id' => 'required|cid_13']
|
|
* @return self
|
|
*/
|
|
public static function make(array $data, array $rules): self
|
|
{
|
|
$validator = new self($data);
|
|
foreach ($rules as $field => $ruleStr) {
|
|
$ruleList = explode('|', $ruleStr);
|
|
foreach ($ruleList as $rule) {
|
|
if (strpos((string)$rule, ':') !== false) {
|
|
[$ruleName, $param] = explode(':', $rule, 2);
|
|
$validator->applyRule($field, $ruleName, $param);
|
|
} else {
|
|
$validator->applyRule($field, $rule, null);
|
|
}
|
|
}
|
|
}
|
|
return $validator;
|
|
}
|
|
|
|
private function applyRule(string $field, string $rule, ?string $param): void
|
|
{
|
|
$val = $this->data[$field] ?? null;
|
|
|
|
if ($rule === 'required' && ($val === null || trim((string)$val) === '')) {
|
|
$this->addError($field, "ฟิลด์ {$field} เป็นข้อมูลที่ต้องระบุ (Required)");
|
|
return;
|
|
}
|
|
|
|
if ($val === null || trim((string)$val) === '') {
|
|
return; // ข้ามการตรวจสอบอื่นถ้าค่าเป็นว่างและไม่ได้เป็น required
|
|
}
|
|
|
|
switch ($rule) {
|
|
case 'cid_13':
|
|
if (!preg_match('/^[0-9]{13}$/', (string)$val)) {
|
|
$this->addError($field, "เลขบัตรประชาชนต้องเป็นตัวเลข 13 หลักเท่านั้น");
|
|
} elseif (!$this->verifyThaiIDChecksum((string)$val)) {
|
|
$this->addError($field, "เลขบัตรประชาชน 13 หลักไม่ถูกต้องตามสูตรคำนวณ Checksum");
|
|
}
|
|
break;
|
|
|
|
case 'numeric':
|
|
if (!is_numeric($val)) {
|
|
$this->addError($field, "ฟิลด์ {$field} ต้องเป็นตัวเลขเท่านั้น");
|
|
}
|
|
break;
|
|
|
|
case 'email':
|
|
if (!filter_var($val, FILTER_VALIDATE_EMAIL)) {
|
|
$this->addError($field, "รูปแบบอีเมลไม่ถูกต้อง");
|
|
}
|
|
break;
|
|
|
|
case 'min':
|
|
if (strlen((string)$val) < (int)$param) {
|
|
$this->addError($field, "ฟิลด์ {$field} ต้องมีความยาวอย่างน้อย {$param} ตัวอักษร");
|
|
}
|
|
break;
|
|
|
|
case 'max':
|
|
if (strlen((string)$val) > (int)$param) {
|
|
$this->addError($field, "ฟิลด์ {$field} ต้องมีความยาวไม่เกิน {$param} ตัวอักษร");
|
|
}
|
|
break;
|
|
|
|
case 'in':
|
|
$allowed = explode(',', (string)$param);
|
|
if (!in_array($val, $allowed, true)) {
|
|
$this->addError($field, "ค่าในฟิลด์ {$field} ไม่ถูกต้อง (ต้องเป็น: " . implode(', ', $allowed) . ")");
|
|
}
|
|
break;
|
|
|
|
case 'date':
|
|
if (!strtotime((string)$val)) {
|
|
$this->addError($field, "ฟิลด์ {$field} ต้องเป็นวันที่ที่ถูกต้อง (YYYY-MM-DD)");
|
|
}
|
|
break;
|
|
|
|
case 'time':
|
|
if (!preg_match('/^(0[0-9]|1[0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?$/', (string)$val)) {
|
|
$this->addError($field, "ฟิลด์ {$field} ต้องเป็นเวลาที่ถูกต้อง (HH:MM หรือ HH:MM:SS)");
|
|
}
|
|
break;
|
|
|
|
case 'vas_score':
|
|
if (!is_numeric($val) || (int)$val < 0 || (int)$val > 10) {
|
|
$this->addError($field, "ระดับความปวด VAS Score ต้องเป็นตัวเลขระหว่าง 0 ถึง 10");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* ตรวจสอบ Checksum เลขบัตรประชาชนไทย 13 หลัก ตามหลักโมดูโล 11
|
|
*/
|
|
private function verifyThaiIDChecksum(string $cid): bool
|
|
{
|
|
if (strlen($cid) !== 13) return false;
|
|
$sum = 0;
|
|
for ($i = 0; $i < 12; $i++) {
|
|
$sum += (int)$cid[$i] * (13 - $i);
|
|
}
|
|
$checkDigit = (11 - ($sum % 11)) % 10;
|
|
return (int)$cid[12] === $checkDigit;
|
|
}
|
|
|
|
private function addError(string $field, string $msg): void
|
|
{
|
|
$this->errors[$field][] = $msg;
|
|
}
|
|
|
|
public function fails(): bool
|
|
{
|
|
return !empty($this->errors);
|
|
}
|
|
|
|
public function getErrors(): array
|
|
{
|
|
return $this->errors;
|
|
}
|
|
}
|