116 lines
3.7 KiB
PHP
116 lines
3.7 KiB
PHP
|
<?php
|
||
|
|
||
|
// Security helper, to be used with all the forms in the app
|
||
|
|
||
|
class SecurityHelper {
|
||
|
private static $instance = null;
|
||
|
private $session;
|
||
|
|
||
|
private function __construct() {
|
||
|
// Don't start a new session, just reference the existing one
|
||
|
$this->session = &$_SESSION;
|
||
|
}
|
||
|
|
||
|
public static function getInstance() {
|
||
|
if (self::$instance === null) {
|
||
|
self::$instance = new SecurityHelper();
|
||
|
}
|
||
|
return self::$instance;
|
||
|
}
|
||
|
|
||
|
// Generate CSRF token
|
||
|
public function generateCsrfToken() {
|
||
|
if (empty($this->session['csrf_token'])) {
|
||
|
$this->session['csrf_token'] = bin2hex(random_bytes(32));
|
||
|
}
|
||
|
return $this->session['csrf_token'];
|
||
|
}
|
||
|
|
||
|
// Verify CSRF token
|
||
|
public function verifyCsrfToken($token) {
|
||
|
if (empty($this->session['csrf_token']) || empty($token)) {
|
||
|
return false;
|
||
|
}
|
||
|
return hash_equals($this->session['csrf_token'], $token);
|
||
|
}
|
||
|
|
||
|
// Sanitize string input
|
||
|
public function sanitizeString($input) {
|
||
|
if (is_string($input)) {
|
||
|
return htmlspecialchars(strip_tags(trim($input)), ENT_QUOTES, 'UTF-8');
|
||
|
}
|
||
|
return '';
|
||
|
}
|
||
|
|
||
|
// Validate email
|
||
|
public function validateEmail($email) {
|
||
|
return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
|
||
|
}
|
||
|
|
||
|
// Validate integer
|
||
|
public function validateInt($input) {
|
||
|
return filter_var($input, FILTER_VALIDATE_INT) !== false;
|
||
|
}
|
||
|
|
||
|
// Validate URL
|
||
|
public function validateUrl($url) {
|
||
|
return filter_var($url, FILTER_VALIDATE_URL) !== false;
|
||
|
}
|
||
|
|
||
|
// Sanitize array of inputs
|
||
|
public function sanitizeArray($array, $allowedKeys = []) {
|
||
|
$sanitized = [];
|
||
|
foreach ($array as $key => $value) {
|
||
|
if (empty($allowedKeys) || in_array($key, $allowedKeys)) {
|
||
|
if (is_array($value)) {
|
||
|
$sanitized[$key] = $this->sanitizeArray($value);
|
||
|
} else {
|
||
|
$sanitized[$key] = $this->sanitizeString($value);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return $sanitized;
|
||
|
}
|
||
|
|
||
|
// Validate form data based on rules
|
||
|
public function validateFormData($data, $rules) {
|
||
|
$errors = [];
|
||
|
foreach ($rules as $field => $rule) {
|
||
|
if (!isset($data[$field]) && $rule['required']) {
|
||
|
$errors[$field] = "Field is required";
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (isset($data[$field])) {
|
||
|
$value = $data[$field];
|
||
|
switch ($rule['type']) {
|
||
|
case 'email':
|
||
|
if (!$this->validateEmail($value)) {
|
||
|
$errors[$field] = "Invalid email format";
|
||
|
}
|
||
|
break;
|
||
|
case 'integer':
|
||
|
if (!$this->validateInt($value)) {
|
||
|
$errors[$field] = "Must be a valid integer";
|
||
|
}
|
||
|
break;
|
||
|
case 'url':
|
||
|
if (!$this->validateUrl($value)) {
|
||
|
$errors[$field] = "Invalid URL format";
|
||
|
}
|
||
|
break;
|
||
|
case 'string':
|
||
|
if (isset($rule['min']) && strlen($value) < $rule['min']) {
|
||
|
$errors[$field] = "Minimum length is {$rule['min']} characters";
|
||
|
}
|
||
|
if (isset($rule['max']) && strlen($value) > $rule['max']) {
|
||
|
$errors[$field] = "Maximum length is {$rule['max']} characters";
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return $errors;
|
||
|
}
|
||
|
}
|