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; } }