529 lines
20 KiB
PHP
529 lines
20 KiB
PHP
<?php
|
|
|
|
require_once __DIR__ . '/database.php';
|
|
|
|
define('VERSION', '1.2.3');
|
|
define('BUILD', 'Reawaken');
|
|
define('START', microtime(true));
|
|
|
|
/**
|
|
* Open or get SQLite database connection.
|
|
*/
|
|
function db(): Database
|
|
{
|
|
return $GLOBALS['database'] ??= new Database(__DIR__ . '/../database.db');
|
|
}
|
|
|
|
/**
|
|
* Redirect to a different URL, exit.
|
|
*/
|
|
function redirect(string $location): void
|
|
{
|
|
header("Location: $location");
|
|
exit;
|
|
}
|
|
|
|
function gettemplate($templatename) { // SQL query for the template.
|
|
|
|
$filename = __DIR__ . "/../templates/" . $templatename . ".php";
|
|
include("$filename");
|
|
return $template;
|
|
|
|
}
|
|
|
|
function parsetemplate($template, $array) { // Replace template with proper content.
|
|
|
|
foreach($array as $a => $b) {
|
|
$template = str_replace("{{{$a}}}", $b, $template);
|
|
}
|
|
return $template;
|
|
|
|
}
|
|
|
|
function getmicrotime() { // Used for timing script operations.
|
|
|
|
list($usec, $sec) = explode(" ",microtime());
|
|
return ((float)$usec + (float)$sec);
|
|
|
|
}
|
|
|
|
function prettydate($uglydate) { // Change the MySQL date format (YYYY-MM-DD) into something friendlier.
|
|
|
|
return date("F j, Y", mktime(0,0,0,substr($uglydate, 5, 2),substr($uglydate, 8, 2),substr($uglydate, 0, 4)));
|
|
|
|
}
|
|
|
|
function prettyforumdate($uglydate) { // Change the MySQL date format (YYYY-MM-DD) into something friendlier.
|
|
|
|
return date("F j, Y", mktime(0,0,0,substr($uglydate, 5, 2),substr($uglydate, 8, 2),substr($uglydate, 0, 4)));
|
|
|
|
}
|
|
|
|
function is_email($email) { // Thanks to "mail(at)philipp-louis.de" from php.net!
|
|
|
|
return(preg_match("/^[-_.[:alnum:]]+@((([[:alnum:]]|[[:alnum:]][[:alnum:]-]*[[:alnum:]])\.)+(ad|ae|aero|af|ag|ai|al|am|an|ao|aq|ar|arpa|as|at|au|aw|az|ba|bb|bd|be|bf|bg|bh|bi|biz|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|com|coop|cr|cs|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|ec|edu|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gh|gi|gl|gm|gn|gov|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|in|info|int|io|iq|ir|is|it|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|mg|mh|mil|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|museum|mv|mw|mx|my|mz|na|name|nc|ne|net|nf|ng|ni|nl|no|np|nr|nt|nu|nz|om|org|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|pro|ps|pt|pw|py|qa|re|ro|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|su|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|um|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw)$|(([0-9][0-9]?|[0-1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5])\.){3}([0-9][0-9]?|[0-1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5]))$/i",$email));
|
|
|
|
}
|
|
|
|
function makesafe($d) {
|
|
return htmlentities($d);
|
|
}
|
|
|
|
/**
|
|
* Finalize page and output to browser.
|
|
*/
|
|
function admindisplay($content, $title)
|
|
{
|
|
global $userrow, $controlrow;
|
|
if (!isset($controlrow)) {
|
|
$query = db()->query('SELECT * FROM control WHERE id=1 LIMIT 1;');
|
|
$controlrow = $query->fetchArray(SQLITE3_ASSOC);
|
|
}
|
|
|
|
$page = parsetemplate(gettemplate("admin"), [
|
|
"title" => $title,
|
|
"content" => $content,
|
|
"totaltime" => round(getmicrotime() - START, 4),
|
|
"numqueries" => db()->count,
|
|
"version" => VERSION,
|
|
"build" => BUILD
|
|
]);
|
|
|
|
echo "<html>\n" . $page;
|
|
|
|
exit;
|
|
}
|
|
|
|
function display($content, $title, $topnav=true, $leftnav=true, $rightnav=true, $badstart=false) { // Finalize page and output to browser.
|
|
|
|
global $numqueries, $userrow, $controlrow, $version, $build;
|
|
if (!isset($controlrow)) {
|
|
$query = db()->query('SELECT * FROM control WHERE id=1 LIMIT 1;');
|
|
$controlrow = $query->fetchArray(SQLITE3_ASSOC);
|
|
}
|
|
if ($badstart == false) { global $starttime; } else { $starttime = $badstart; }
|
|
|
|
if ($rightnav == true) { $rightnav = gettemplate("rightnav"); } else { $rightnav = ""; }
|
|
if ($leftnav == true) { $leftnav = gettemplate("leftnav"); } else { $leftnav = ""; }
|
|
if ($topnav == true) {
|
|
$topnav = "<a href=\"login.php?do=logout\"><img src=\"/img/button_logout.gif\" alt=\"Log Out\" title=\"Log Out\" border=\"0\" /></a> <a href=\"help.php\"><img src=\"/img/button_help.gif\" alt=\"Help\" title=\"Help\" border=\"0\" /></a>";
|
|
} else {
|
|
$topnav = "<a href=\"login.php?do=login\"><img src=\"/img/button_login.gif\" alt=\"Log In\" title=\"Log In\" border=\"0\" /></a> <a href=\"users.php?do=register\"><img src=\"/img/button_register.gif\" alt=\"Register\" title=\"Register\" border=\"0\" /></a> <a href=\"help.php\"><img src=\"/img/button_help.gif\" alt=\"Help\" title=\"Help\" border=\"0\" /></a>";
|
|
}
|
|
|
|
if (isset($userrow)) {
|
|
|
|
// Get userrow again, in case something has been updated.
|
|
$userquery = db()->query('SELECT * FROM users WHERE id = ? LIMIT 1;', [$userrow['id']]);
|
|
unset($userrow);
|
|
$userrow = $userquery->fetchArray(SQLITE3_ASSOC);
|
|
|
|
// Current town name.
|
|
if ($userrow["currentaction"] == "In Town") {
|
|
$townquery = db()->query('SELECT * FROM towns WHERE latitude = ? AND longitude = ? LIMIT 1;', [$userrow["latitude"], $userrow["longitude"]]);
|
|
$townrow = $townquery->fetchArray(SQLITE3_ASSOC);
|
|
$userrow["currenttown"] = "Welcome to <b>".$townrow["name"]."</b>.<br><br>";
|
|
} else {
|
|
$userrow["currenttown"] = "";
|
|
}
|
|
|
|
$userrow["forumslink"] = "<a href=\"forum.php\">Forum</a><br>";
|
|
|
|
// Format various userrow stuffs...
|
|
if ($userrow["latitude"] < 0) { $userrow["latitude"] = $userrow["latitude"] * -1 . "S"; } else { $userrow["latitude"] .= "N"; }
|
|
if ($userrow["longitude"] < 0) { $userrow["longitude"] = $userrow["longitude"] * -1 . "W"; } else { $userrow["longitude"] .= "E"; }
|
|
$userrow["experience"] = number_format($userrow["experience"]);
|
|
$userrow["gold"] = number_format($userrow["gold"]);
|
|
if ($userrow["authlevel"] == 1) { $userrow["adminlink"] = "<a href=\"admin.php\">Admin</a><br>"; } else { $userrow["adminlink"] = ""; }
|
|
|
|
// HP/MP/TP bars.
|
|
$stathp = ceil($userrow["currenthp"] / $userrow["maxhp"] * 100);
|
|
if ($userrow["maxmp"] != 0) { $statmp = ceil($userrow["currentmp"] / $userrow["maxmp"] * 100); } else { $statmp = 0; }
|
|
$stattp = ceil($userrow["currenttp"] / $userrow["maxtp"] * 100);
|
|
$stattable = "<table width=\"100\"><tr><td width=\"33%\">\n";
|
|
$stattable .= "<table cellspacing=\"0\" cellpadding=\"0\"><tr><td style=\"padding:0px; width:15px; height:100px; border:solid 1px black; vertical-align:bottom;\">\n";
|
|
if ($stathp >= 66) { $stattable .= "<div style=\"padding:0px; height:".$stathp."px; border-top:solid 1px black; background-image:url(/img/bars_green.gif);\"><img src=\"/img/bars_green.gif\" alt=\"\" /></div>"; }
|
|
if ($stathp < 66 && $stathp >= 33) { $stattable .= "<div style=\"padding:0px; height:".$stathp."px; border-top:solid 1px black; background-image:url(/img/bars_yellow.gif);\"><img src=\"/img/bars_yellow.gif\" alt=\"\" /></div>"; }
|
|
if ($stathp < 33) { $stattable .= "<div style=\"padding:0px; height:".$stathp."px; border-top:solid 1px black; background-image:url(/img/bars_red.gif);\"><img src=\"/img/bars_red.gif\" alt=\"\" /></div>"; }
|
|
$stattable .= "</td></tr></table></td><td width=\"33%\">\n";
|
|
$stattable .= "<table cellspacing=\"0\" cellpadding=\"0\"><tr><td style=\"padding:0px; width:15px; height:100px; border:solid 1px black; vertical-align:bottom;\">\n";
|
|
if ($statmp >= 66) { $stattable .= "<div style=\"padding:0px; height:".$statmp."px; border-top:solid 1px black; background-image:url(/img/bars_green.gif);\"><img src=\"/img/bars_green.gif\" alt=\"\" /></div>"; }
|
|
if ($statmp < 66 && $statmp >= 33) { $stattable .= "<div style=\"padding:0px; height:".$statmp."px; border-top:solid 1px black; background-image:url(/img/bars_yellow.gif);\"><img src=\"/img/bars_yellow.gif\" alt=\"\" /></div>"; }
|
|
if ($statmp < 33) { $stattable .= "<div style=\"padding:0px; height:".$statmp."px; border-top:solid 1px black; background-image:url(/img/bars_red.gif);\"><img src=\"/img/bars_red.gif\" alt=\"\" /></div>"; }
|
|
$stattable .= "</td></tr></table></td><td width=\"33%\">\n";
|
|
$stattable .= "<table cellspacing=\"0\" cellpadding=\"0\"><tr><td style=\"padding:0px; width:15px; height:100px; border:solid 1px black; vertical-align:bottom;\">\n";
|
|
if ($stattp >= 66) { $stattable .= "<div style=\"padding:0px; height:".$stattp."px; border-top:solid 1px black; background-image:url(/img/bars_green.gif);\"><img src=\"/img/bars_green.gif\" alt=\"\" /></div>"; }
|
|
if ($stattp < 66 && $stattp >= 33) { $stattable .= "<div style=\"padding:0px; height:".$stattp."px; border-top:solid 1px black; background-image:url(/img/bars_yellow.gif);\"><img src=\"/img/bars_yellow.gif\" alt=\"\" /></div>"; }
|
|
if ($stattp < 33) { $stattable .= "<div style=\"padding:0px; height:".$stattp."px; border-top:solid 1px black; background-image:url(/img/bars_red.gif);\"><img src=\"/img/bars_red.gif\" alt=\"\" /></div>"; }
|
|
$stattable .= "</td></tr></table></td>\n";
|
|
$stattable .= "</tr><tr><td>HP</td><td>MP</td><td>TP</td></tr></table>\n";
|
|
$userrow["statbars"] = $stattable;
|
|
|
|
// Now make numbers stand out if they're low.
|
|
if ($userrow["currenthp"] <= ($userrow["maxhp"]/5)) { $userrow["currenthp"] = "<blink><span class=\"highlight\"><b>*".$userrow["currenthp"]."*</b></span></blink>"; }
|
|
if ($userrow["currentmp"] <= ($userrow["maxmp"]/5)) { $userrow["currentmp"] = "<blink><span class=\"highlight\"><b>*".$userrow["currentmp"]."*</b></span></blink>"; }
|
|
|
|
$spellquery = db()->query('SELECT id, name, type FROM spells;');
|
|
$userspells = explode(",",$userrow["spells"]);
|
|
$userrow["magiclist"] = "";
|
|
while ($spellrow = $spellquery->fetchArray(SQLITE3_ASSOC)) {
|
|
$spell = false;
|
|
foreach($userspells as $a => $b) {
|
|
if ($b == $spellrow["id"] && $spellrow["type"] == 1) { $spell = true; }
|
|
}
|
|
if ($spell == true) {
|
|
$userrow["magiclist"] .= "<a href=\"/spell/{$spellrow["id"]}\">".$spellrow["name"]."</a><br>";
|
|
}
|
|
}
|
|
if ($userrow["magiclist"] == "") { $userrow["magiclist"] = "None"; }
|
|
|
|
// Travel To list.
|
|
$townslist = explode(",",$userrow["towns"]);
|
|
$townquery2 = db()->query('SELECT * FROM towns ORDER BY id;');
|
|
$userrow["townslist"] = "";
|
|
while ($townrow2 = $townquery2->fetchArray(SQLITE3_ASSOC)) {
|
|
$town = false;
|
|
foreach($townslist as $a => $b) {
|
|
if ($b == $townrow2["id"]) { $town = true; }
|
|
}
|
|
if ($town == true) {
|
|
$userrow["townslist"] .= "<a href=\"/gotown/{$townrow2["id"]}\">".$townrow2["name"]."</a><br>\n";
|
|
}
|
|
}
|
|
} else {
|
|
$userrow = [];
|
|
}
|
|
|
|
$page = parsetemplate(gettemplate("primary"), [
|
|
"dkgamename" => $controlrow["gamename"],
|
|
"title" => $title,
|
|
"content" => $content,
|
|
"rightnav" => parsetemplate($rightnav, $userrow),
|
|
"leftnav" => parsetemplate($leftnav, $userrow),
|
|
"topnav" => $topnav,
|
|
"totaltime" => round(getmicrotime() - START, 4),
|
|
"numqueries" => db()->count,
|
|
"version" => VERSION,
|
|
"build" => BUILD
|
|
]);
|
|
|
|
echo "<html>\n" . $page;
|
|
exit;
|
|
}
|
|
|
|
function checkcookies()
|
|
{
|
|
$row = false;
|
|
|
|
if (isset($_COOKIE["dkgame"])) {
|
|
// COOKIE FORMAT:
|
|
// {ID} {USERNAME} {PASSWORDHASH} {REMEMBERME}
|
|
$theuser = explode(" ",$_COOKIE["dkgame"]);
|
|
$query = db()->query('SELECT * FROM users WHERE id = ? AND username = ? AND password = ? LIMIT 1;', [$theuser[0], $theuser[1], $theuser[2]]);
|
|
if ($query === false) {
|
|
set_cookie('dkgame', '', -3600);
|
|
die("Invalid cookie data. Please log in again.");
|
|
}
|
|
$row = $query->fetchArray(SQLITE3_ASSOC);
|
|
set_cookie('dkgame', implode(" ", $theuser), (int) $theuser[3] === 1 ? time() + 31536000 : 0);
|
|
db()->exec('UPDATE users SET onlinetime = CURRENT_TIMESTAMP WHERE id = ?;', [$theuser[0]]);
|
|
}
|
|
|
|
return $row;
|
|
}
|
|
|
|
/**
|
|
* Set a cookie with secure and HTTP-only flags.
|
|
*/
|
|
function set_cookie($name, $value, $expires)
|
|
{
|
|
setcookie($name, $value, [
|
|
'expires' => $expires,
|
|
'path' => '/',
|
|
'domain' => '', // Defaults to the current domain
|
|
'secure' => true, // Ensure the cookie is only sent over HTTPS
|
|
'httponly' => true, // Prevent access to cookie via JavaScript
|
|
'samesite' => 'Strict' // Enforce SameSite=Strict
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Get the current control row from the database.
|
|
*/
|
|
function get_control_row(): array|false
|
|
{
|
|
$query = db()->query('SELECT * FROM control WHERE id = 1 LIMIT 1;');
|
|
if ($query === false) return false;
|
|
return $query->fetchArray(SQLITE3_ASSOC);
|
|
}
|
|
|
|
/**
|
|
* Get a town's data by it's coordinates.
|
|
*/
|
|
function get_town_by_xy(int $x, int $y): array|false
|
|
{
|
|
$query = db()->query('SELECT * FROM towns WHERE longitude = ? AND latitude = ? LIMIT 1;', [$x, $y]);
|
|
if ($query === false) return false;
|
|
return $query->fetchArray(SQLITE3_ASSOC);
|
|
}
|
|
|
|
/**
|
|
* Get a town's data by it's ID.
|
|
*/
|
|
function get_town_by_id(int $id): array|false
|
|
{
|
|
$query = db()->query('SELECT * FROM towns WHERE id = ? LIMIT 1;', [$id]);
|
|
if ($query === false) return false;
|
|
return $query->fetchArray(SQLITE3_ASSOC);
|
|
}
|
|
|
|
/**
|
|
* Get an item by it's ID.
|
|
*/
|
|
function get_item(int $id): array|false
|
|
{
|
|
$query = db()->query('SELECT * FROM items WHERE id=? LIMIT 1;', [$id]);
|
|
if ($query === false) return false;
|
|
return $query->fetchArray(SQLITE3_ASSOC);
|
|
}
|
|
|
|
/**
|
|
* Get a drop by it's ID.
|
|
*/
|
|
function get_drop(int $id): array|false
|
|
{
|
|
$query = db()->query('SELECT * FROM drops WHERE id=? LIMIT 1;', [$id]);
|
|
if ($query === false) return false;
|
|
return $query->fetchArray(SQLITE3_ASSOC);
|
|
}
|
|
|
|
/**
|
|
* Get a spell by it's ID.
|
|
*/
|
|
function get_spell(int $id): array|false
|
|
{
|
|
$query = db()->query('SELECT * FROM spells WHERE id=? LIMIT 1;', [$id]);
|
|
if ($query === false) return false;
|
|
return $query->fetchArray(SQLITE3_ASSOC);
|
|
}
|
|
|
|
/**
|
|
* Get a monster by it's ID.
|
|
*/
|
|
function get_monster(int $id): array|false
|
|
{
|
|
$query = db()->query('SELECT * FROM monsters WHERE id=? LIMIT 1;', [$id]);
|
|
if ($query === false) return false;
|
|
return $query->fetchArray(SQLITE3_ASSOC);
|
|
}
|
|
|
|
/**
|
|
* Translate a Specials keyword to it's string.
|
|
*/
|
|
function special_to_string(string $special): string
|
|
{
|
|
return match ($special) {
|
|
'maxhp' => 'Max HP',
|
|
'maxmp' => 'Max MP',
|
|
'maxtp' => 'Max TP',
|
|
'goldbonus' => 'Gold Bonus (%)',
|
|
'expbonus' => 'Experience Bonus (%)',
|
|
'strength' => 'Strength',
|
|
'dexterity' => 'Dexterity',
|
|
'attackpower' => 'Attack Power',
|
|
'defensepower' => 'Defense Power',
|
|
default => $special
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Generate a pretty dope token.
|
|
*/
|
|
function token($length = 32): string
|
|
{
|
|
return bin2hex(random_bytes($length));
|
|
}
|
|
|
|
/**
|
|
* Validate any given array of data against rules. Returns [valid, data, error]. Data contains the trimmed
|
|
* values from the input array. Note: all fields with rules are assumed to be required, unless the optional
|
|
* rule is used.
|
|
*
|
|
* Example: ['required', 'no-trim', 'length:5-20', 'alphanum-spaces']
|
|
*/
|
|
function validate(array $input_data, array $rules): array
|
|
{
|
|
$data = [];
|
|
$errors = [];
|
|
|
|
foreach ($rules as $field => $field_rules) {
|
|
$value = $input_data[$field] ?? null;
|
|
$field_name = ucfirst(str_replace('_', ' ', $field));
|
|
$is_required = true;
|
|
$default_value = null;
|
|
|
|
if (in_array('optional', $field_rules)) {
|
|
$is_required = false;
|
|
}
|
|
|
|
foreach ($field_rules as $rule) {
|
|
if (strpos($rule, 'default:') === 0) {
|
|
$default_value = substr($rule, 8);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (($value === null || $value === '') && $default_value !== null) {
|
|
$value = $default_value;
|
|
}
|
|
|
|
if (($value === null || $value === '') && !$is_required) continue;
|
|
|
|
if ($is_required && ($value === null || $value === '')) {
|
|
$errors[$field][] = "{$field_name} is required.";
|
|
continue;
|
|
}
|
|
|
|
if (!in_array('no-trim', $field_rules)) {
|
|
$value = trim($value);
|
|
}
|
|
|
|
$data[$field] = $value;
|
|
|
|
foreach ($field_rules as $rule) {
|
|
// Parse rule and arguments
|
|
if (strpos($rule, ':') !== false) {
|
|
list($rule_name, $rule_args) = explode(':', $rule, 2);
|
|
} else {
|
|
$rule_name = $rule;
|
|
$rule_args = null;
|
|
}
|
|
|
|
if ($rule_name === 'optional') continue;
|
|
|
|
switch ($rule_name) {
|
|
case 'bool':
|
|
if (!isset($input_data[$field]) || empty($value)) {
|
|
$value = false;
|
|
} else {
|
|
$value = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
|
|
|
|
if ($value === null) {
|
|
$errors[$field][] = "{$field_name} must be a valid boolean value.";
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'length':
|
|
list($min, $max) = explode('-', $rule_args);
|
|
$len = strlen((string)$value);
|
|
if ($len < $min || $len > $max) {
|
|
$errors[$field][] = "{$field_name} must be between {$min} and {$max} characters.";
|
|
}
|
|
break;
|
|
|
|
case 'alphanum':
|
|
if (!preg_match('/^[a-zA-Z0-9]+$/', $value)) {
|
|
$errors[$field][] = "{$field_name} must contain only letters and numbers.";
|
|
}
|
|
break;
|
|
|
|
case 'alpha':
|
|
if (!preg_match('/^[a-zA-Z]+$/', $value)) {
|
|
$errors[$field][] = "{$field_name} must contain only letters and numbers.";
|
|
}
|
|
break;
|
|
|
|
case 'alphanum-spaces':
|
|
if (!preg_match('/^[a-zA-Z0-9\s_]+$/', $value)) {
|
|
$errors[$field][] = "{$field_name} must contain only letters, numbers, spaces, and underscores.";
|
|
}
|
|
break;
|
|
|
|
case 'alpha-spaces':
|
|
if (!preg_match('/^[a-zA-Z\s_]+$/', $value)) {
|
|
$errors[$field][] = "{$field_name} must contain only letters, numbers, spaces, and underscores.";
|
|
}
|
|
break;
|
|
|
|
case 'email':
|
|
if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
|
|
$errors[$field][] = "{$field_name} must be a valid email address.";
|
|
}
|
|
break;
|
|
|
|
case 'int':
|
|
if (!filter_var($value, FILTER_VALIDATE_INT)) {
|
|
$errors[$field][] = "{$field_name} must be an integer.";
|
|
}
|
|
break;
|
|
|
|
case 'min':
|
|
if ($value < $rule_args) {
|
|
$errors[$field][] = "{$field_name} must be at least {$rule_args}.";
|
|
}
|
|
break;
|
|
|
|
case 'max':
|
|
if ($value > $rule_args) {
|
|
$errors[$field][] = "{$field_name} must be no more than {$rule_args}.";
|
|
}
|
|
break;
|
|
|
|
case 'regex':
|
|
if (!preg_match($rule_args, $value)) {
|
|
$errors[$field][] = "{$field_name} does not match the required pattern.";
|
|
}
|
|
break;
|
|
|
|
case 'in':
|
|
$options = explode(',', $rule_args);
|
|
if (!in_array($value, $options)) {
|
|
$errors[$field][] = "{$field_name} must be one of: " . implode(', ', $options);
|
|
}
|
|
break;
|
|
|
|
case 'confirm':
|
|
$field_to_confirm = substr($field, 8);
|
|
$confirm_value = $data[$field_to_confirm] ?? '';
|
|
$confirm_field_name = ucfirst(str_replace('_', ' ', $field_to_confirm));
|
|
if ($value !== $confirm_value) {
|
|
$errors[$field][] = "{$field_name} must match {$confirm_field_name}.";
|
|
}
|
|
break;
|
|
|
|
case 'unique':
|
|
list($table, $column) = explode(',', $rule_args, 2);
|
|
if (db()->exists($table, $column, $value)) {
|
|
$errors[$field][] = "{$field_name} must be unique.";
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach ($input_data as $field => $value) {
|
|
if (!isset($data[$field])) $data[$field] = trim($value);
|
|
}
|
|
|
|
return [
|
|
'valid' => empty($errors),
|
|
'data' => $data,
|
|
'errors' => $errors
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Generates a ul list from `validate()`'s errors.
|
|
*/
|
|
function ul_from_validate_errors(array $errors): string
|
|
{
|
|
$string = '<ul>';
|
|
foreach ($errors as $field => $errors) {
|
|
$string .= '<li>';
|
|
foreach ($errors as $error) $string .= $error;
|
|
$string .= '</li>';
|
|
}
|
|
return $string . '</ul>';
|
|
}
|