Initial commit

This commit is contained in:
Porawit Dongwang
2026-09-16 23:20:08 +07:00
commit 0041668dbb
32577 changed files with 3687927 additions and 0 deletions
@@ -0,0 +1,44 @@
<?php
// core/ajax_dashboard_stats.php
require_once("../config/db.php");
require_once("../core/utils.php");
session_start();
if (empty($_SESSION['sess_userid'])) {
exit('Unauthorized');
}
$timezone = "Asia/Bangkok";
date_default_timezone_set($timezone);
$d_conv_search = date("Y-m-d");
function get_count($conn, $query, $date_param) {
$stmt = $conn->prepare($query);
if($stmt) {
$stmt->bind_param("s", $date_param);
$stmt->execute();
$result = $stmt->get_result();
$row = $result->fetch_assoc();
$stmt->close();
return $row['cc'] ?? 0;
}
return 0;
}
$cc_er = get_count($conn1, "SELECT count(*) as cc FROM er_regist WHERE vstdate=?", $d_conv_search);
$cc_pq = get_count($conn1, "SELECT count(*) as cc FROM pq_screen WHERE screen_date=?", $d_conv_search);
$cc_dt = get_count($conn1, "SELECT count(distinct hn) as cc FROM dtmain WHERE vstdate=?", $d_conv_search);
$cc_lab1 = get_count($conn1, "SELECT count(*) as cc FROM lab_head WHERE order_date=?", $d_conv_search);
$sub_y = substr((date("Y") + 543), 2, 2);
$d_rx = $sub_y . date("md") . "%";
$cc_rx = get_count($conn1, "SELECT count(*) as cc FROM rx_operator WHERE vn like ?", $d_rx);
header('Content-Type: application/json');
echo json_encode([
'er' => number_format($cc_er),
'pq' => number_format($cc_pq),
'dt' => number_format($cc_dt),
'rx' => number_format($cc_rx),
'lab' => number_format($cc_lab1)
]);
?>
+33
View File
@@ -0,0 +1,33 @@
<?php
// core/auth.php
require_once(dirname(__FILE__) . "/security.php");
configure_secure_session();
session_start();
send_security_headers();
if (empty($_SESSION['sess_userid']) || $_SESSION['sess_userid'] !== session_id()) {
header("Location: ../views/login.php");
exit();
}
$account = $_SESSION['account'] ?? '';
$login_id = $_SESSION['account'] ?? '';
$name = $_SESSION['name'] ?? '';
$position = $_SESSION['position'] ?? '';
$ip = $_SESSION['ip'] ?? '';
// Auto Logout Logic
require_once(dirname(__FILE__) . "/settings.php");
$app_settings = get_app_settings();
if (isset($app_settings['auto_logout_enable']) && $app_settings['auto_logout_enable'] === '1') {
$timeout_minutes = (int)($app_settings['auto_logout_minutes'] ?? 30);
if ($timeout_minutes < 1) $timeout_minutes = 30; // fallback
$timeout_seconds = $timeout_minutes * 60;
if (isset($_SESSION['last_activity']) && (time() - $_SESSION['last_activity'] > $timeout_seconds)) {
header("Location: ../views/login.php?action=timeout");
exit();
}
$_SESSION['last_activity'] = time(); // update last activity timestamp
}
?>
+119
View File
@@ -0,0 +1,119 @@
<?php
// core/search_action.php
require_once("../config/db.php");
require_once("../core/utils.php");
require_once("../core/security.php");
session_start();
// CSRF Validation
if (!verify_csrf_token($_POST['csrf_token'] ?? '')) {
echo "<tr><td colspan='5' class='py-16 text-center text-red-500'>การยืนยันตัวตนล้มเหลว (CSRF) กรุณาโหลดหน้าเว็บใหม่</td></tr>";
exit();
}
$type = $_POST['type'] ?? 'hn';
$query = $_POST['query'] ?? '';
$rows = [];
$current_user = $_SESSION['account'] ?? '';
if ($query !== "") {
if ($type === 'name') {
if (can_search_name($current_user)) {
// Split query by spaces to handle first and last name separately
$parts = preg_split('/\s+/', trim($query));
if (count($parts) >= 2) {
// First part is fname, second part is lname
$fname = "%" . $parts[0] . "%";
$lname = "%" . $parts[1] . "%";
$sql = "SELECT hn, pname, fname, lname, cid FROM patient WHERE fname LIKE ? AND lname LIKE ? LIMIT 50";
$stmt = $conn1->prepare($sql);
if ($stmt) {
$stmt->bind_param("ss", $fname, $lname);
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
$rows[] = $row;
}
$stmt->close();
}
} else {
// Just one word, search either fname or lname
$data = "%" . trim($query) . "%";
$sql = "SELECT hn, pname, fname, lname, cid FROM patient WHERE fname LIKE ? OR lname LIKE ? LIMIT 50";
$stmt = $conn1->prepare($sql);
if ($stmt) {
$stmt->bind_param("ss", $data, $data);
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
$rows[] = $row;
}
$stmt->close();
}
}
} else {
echo "<tr><td colspan='5' class='py-16 text-center text-red-500'>คุณไม่มีสิทธิ์ในการค้นหาด้วยชื่อ-สกุล</td></tr>";
exit();
}
} else {
require_once("../core/settings.php");
$app_settings = get_app_settings();
$is_strict = ($app_settings['strict_search_enable'] == '1');
$data = $is_strict ? $query : "%" . $query . "%";
$operator = $is_strict ? "=" : "LIKE";
if ($type === 'hn') {
$sql = "SELECT hn, pname, fname, lname, cid FROM patient WHERE hn $operator ? LIMIT 20";
} else if ($type === 'cid') {
$sql = "SELECT hn, pname, fname, lname, cid FROM patient WHERE cid $operator ? LIMIT 20";
} else if ($type === 'passport') {
$sql = "SELECT hn, pname, fname, lname, cid, passport_no FROM patient WHERE passport_no $operator ? LIMIT 20";
} else {
$sql = "SELECT hn, pname, fname, lname, cid FROM patient WHERE hn $operator ? LIMIT 20"; // default
}
$stmt = $conn1->prepare($sql);
if ($stmt) {
$stmt->bind_param("s", $data);
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
$rows[] = $row;
}
$stmt->close();
}
}
}
if (empty($rows)) {
echo "<tr><td colspan='5' class='py-16 text-center text-slate-500'>ไม่พบข้อมูลที่ตรงกับคำค้นหา</td></tr>";
} else {
$num = 1;
foreach ($rows as $row) {
$encoded_hn = encrypt_param($row['hn']); // No urlencode needed for hidden input
echo "<tr class='table-row-hover group'>";
echo "<td class='table-cell'>" . $num . "</td>";
echo "<td class='table-cell'><span class='inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-emerald-100 text-emerald-800'>" . htmlspecialchars($row['hn']) . "</span></td>";
$sort_name = htmlspecialchars($row['fname'] . " " . $row['lname']);
$display_name = htmlspecialchars($row['pname'] . $row['fname'] . " " . $row['lname']);
echo "<td class='table-cell font-medium text-slate-800' data-order='" . $sort_name . "'>" . $display_name . "</td>";
echo "<td class='table-cell text-slate-500'>" . htmlspecialchars($row['cid'] ?? '-') . "</td>";
echo "<td class='table-cell text-center'>
<form action='patient_detail.php' method='POST' class='m-0 inline'>
<input type='hidden' name='hn' value='" . htmlspecialchars($encoded_hn) . "'>
<button type='submit' class='inline-flex items-center justify-center w-8 h-8 rounded-full bg-emerald-50 text-emerald-600 hover:bg-emerald-500 hover:text-white transition-all shadow-sm ring-1 ring-emerald-500/20' title='เปิดดูข้อมูล'>
<svg class='w-4 h-4' fill='none' stroke='currentColor' viewBox='0 0 24 24'><path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z'></path></svg>
</button>
</form>
</td>";
echo "</tr>";
$num++;
}
}
?>
+210
View File
@@ -0,0 +1,210 @@
<?php
// core/security.php
// 1. Session Security Configuration
// Must be called BEFORE session_start()
function configure_secure_session() {
if (session_status() === PHP_SESSION_NONE) {
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_samesite', 'Lax');
ini_set('session.use_only_cookies', 1);
ini_set('session.cookie_secure', isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 1 : 0);
}
}
// 2. HTTP Security Headers
function send_security_headers() {
header("X-Frame-Options: SAMEORIGIN");
header("X-XSS-Protection: 1; mode=block");
header("X-Content-Type-Options: nosniff");
header("Strict-Transport-Security: max-age=31536000; includeSubDomains");
header("Referrer-Policy: strict-origin-when-cross-origin");
}
// 3. CSRF Protection
function generate_csrf_token() {
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
return $_SESSION['csrf_token'];
}
function verify_csrf_token($token) {
if (empty($_SESSION['csrf_token']) || empty($token)) {
return false;
}
return hash_equals($_SESSION['csrf_token'], $token);
}
// 4. Rate Limiting (Anti-Brute Force)
function check_rate_limit($conn, $ip) {
try {
// Create table if not exists (Auto-healing)
$sql_create = "CREATE TABLE IF NOT EXISTS sys_login_attempts (
id INT AUTO_INCREMENT PRIMARY KEY,
ip_address VARCHAR(45) NOT NULL,
username VARCHAR(255) NOT NULL,
attempt_time DATETIME NOT NULL
)";
$conn->query($sql_create);
// Clean up old attempts
$conn->query("DELETE FROM sys_login_attempts WHERE attempt_time <= (NOW() - INTERVAL 15 MINUTE)");
// Count recent failed attempts for this IP
$stmt = $conn->prepare("SELECT COUNT(*) as count FROM sys_login_attempts WHERE ip_address = ? AND attempt_time > (NOW() - INTERVAL 15 MINUTE)");
if ($stmt) {
$stmt->bind_param("s", $ip);
$stmt->execute();
$res = $stmt->get_result();
$row = $res->fetch_assoc();
$stmt->close();
if ($row && $row['count'] >= 5) {
return false; // Blocked
}
}
} catch (Throwable $e) {
error_log("check_rate_limit Error: " . $e->getMessage());
}
return true; // Allowed
}
function record_failed_login($conn, $ip, $username) {
try {
$stmt = $conn->prepare("INSERT INTO sys_login_attempts (ip_address, username, attempt_time) VALUES (?, ?, NOW())");
if ($stmt) {
$stmt->bind_param("ss", $ip, $username);
$stmt->execute();
$stmt->close();
// Check if exactly 5 to send notification
$stmt2 = $conn->prepare("SELECT COUNT(*) as count FROM sys_login_attempts WHERE ip_address = ? AND attempt_time > (NOW() - INTERVAL 15 MINUTE)");
if ($stmt2) {
$stmt2->bind_param("s", $ip);
$stmt2->execute();
$res = $stmt2->get_result();
$row = $res->fetch_assoc();
$stmt2->close();
if ($row && $row['count'] == 5) {
send_ban_notification($ip, $username);
}
}
}
} catch (Throwable $e) {
error_log("record_failed_login Error: " . $e->getMessage());
}
}
function clear_failed_logins($conn, $ip) {
try {
$stmt = $conn->prepare("DELETE FROM sys_login_attempts WHERE ip_address = ?");
if ($stmt) {
$stmt->bind_param("s", $ip);
$stmt->execute();
$stmt->close();
}
} catch (Throwable $e) {
error_log("clear_failed_logins Error: " . $e->getMessage());
}
}
function send_ban_notification($ip, $username) {
require_once(__DIR__."/settings.php");
$settings = get_app_settings();
$message = "⚠️ แจ้งเตือนความปลอดภัย\n";
$message .= "มีการระงับการใช้งาน IP Address (Ban IP)\n";
$message .= "IP: {$ip}\n";
$message .= "Username ที่พยายามเข้าสู่ระบบ: {$username}\n";
$message .= "เวลา: " . date("Y-m-d H:i:s");
// Line Notify
if (!empty($settings['line_notify_enable']) && $settings['line_notify_enable'] == '1' && !empty($settings['line_notify_token'])) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://notify-api.line.me/api/notify");
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, "message=" . urlencode($message));
$headers = array('Content-type: application/x-www-form-urlencoded', 'Authorization: Bearer ' . $settings['line_notify_token']);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_exec($ch);
curl_close($ch);
}
// Telegram Notify
if (!empty($settings['telegram_notify_enable']) && $settings['telegram_notify_enable'] == '1' && !empty($settings['telegram_bot_token']) && !empty($settings['telegram_chat_id'])) {
$bot_token = $settings['telegram_bot_token'];
$chat_id = $settings['telegram_chat_id'];
$url = "https://api.telegram.org/bot{$bot_token}/sendMessage";
$post_fields = array(
'chat_id' => $chat_id,
'text' => $message
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);
curl_close($ch);
}
}
function send_test_notification($target = 'all') {
require_once(__DIR__."/settings.php");
$settings = get_app_settings();
$message = "🔔 ทดสอบระบบแจ้งเตือน HOSxP Web Service\n";
$message .= "ระบบของคุณสามารถส่งการแจ้งเตือนได้ตามปกติ!\n";
$message .= "เวลา: " . date("Y-m-d H:i:s");
$results = [];
// Line Notify
if (($target === 'all' || $target === 'line') && !empty($settings['line_notify_enable']) && $settings['line_notify_enable'] == '1' && !empty($settings['line_notify_token'])) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://notify-api.line.me/api/notify");
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, "message=" . urlencode($message));
$headers = array('Content-type: application/x-www-form-urlencoded', 'Authorization: Bearer ' . $settings['line_notify_token']);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$res = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$results['line'] = ($http_code == 200);
}
// Telegram Notify
if (($target === 'all' || $target === 'telegram') && !empty($settings['telegram_notify_enable']) && $settings['telegram_notify_enable'] == '1' && !empty($settings['telegram_bot_token']) && !empty($settings['telegram_chat_id'])) {
$bot_token = $settings['telegram_bot_token'];
$chat_id = $settings['telegram_chat_id'];
$url = "https://api.telegram.org/bot{$bot_token}/sendMessage";
$post_fields = array(
'chat_id' => $chat_id,
'text' => $message
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$res = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$results['telegram'] = ($http_code == 200);
}
return $results;
}
?>
+218
View File
@@ -0,0 +1,218 @@
<?php
require_once(__DIR__."/../config/db.php");
function _init_settings_db($conn) {
$create_sql = "CREATE TABLE IF NOT EXISTS sys_settings (
setting_key VARCHAR(100) PRIMARY KEY,
setting_value TEXT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;";
try {
$conn->query($create_sql);
$create_changelog = "CREATE TABLE IF NOT EXISTS sys_changelog (
id INT AUTO_INCREMENT PRIMARY KEY,
release_date DATE NOT NULL,
version VARCHAR(50) NOT NULL,
description TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;";
$conn->query($create_changelog);
} catch (Exception $e) {
// Ignore table creation errors if it already exists
}
}
function get_changelogs() {
global $conn2;
if (!isset($conn2)) {
}
_init_settings_db($conn2);
$logs = [];
try {
$result = $conn2->query("SELECT * FROM sys_changelog ORDER BY release_date DESC, id DESC");
if ($result) {
while ($row = $result->fetch_assoc()) {
$logs[] = $row;
}
}
} catch (Exception $e) {}
return $logs;
}
function add_changelog($release_date, $version, $description) {
global $conn2;
if (!isset($conn2)) {
}
_init_settings_db($conn2);
try {
$stmt = $conn2->prepare("INSERT INTO sys_changelog (release_date, version, description) VALUES (?, ?, ?)");
if ($stmt) {
$stmt->bind_param("sss", $release_date, $version, $description);
$stmt->execute();
$stmt->close();
return true;
}
} catch (Exception $e) {}
return false;
}
function delete_changelog($id) {
global $conn2;
if (!isset($conn2)) {
}
try {
$stmt = $conn2->prepare("DELETE FROM sys_changelog WHERE id = ?");
if ($stmt) {
$stmt->bind_param("i", $id);
$stmt->execute();
$stmt->close();
return true;
}
} catch (Exception $e) {}
return false;
}
function get_app_settings() {
global $conn2;
if (!isset($conn2)) {
}
_init_settings_db($conn2);
$defaults = [
"login_header_main" => "ยินดีต้อนรับ",
"login_header_sub" => "HOSxP Web Service",
"sidebar_header_main" => "HOSxP Web",
"sidebar_header_sub" => "SMART MEDICAL SERVICE",
"footer_text" => "&copy; {YEAR} โรงพยาบาลเกาะสมุย",
"line_notify_enable" => "0",
"line_notify_token" => "",
"telegram_notify_enable" => "0",
"telegram_bot_token" => "",
"telegram_chat_id" => "",
"strict_search_enable" => "1",
"auto_logout_enable" => "1",
"auto_logout_minutes" => "30",
"vaccine_sql" => "SELECT
vax.source_type,
vax.hn,
vax.vaccine_date,
vax.vaccine_time,
vax.vaccine_code,
vax.vaccine_name,
vax.vaccine_group,
vax.vaccine_lot_no,
vax.vaccine_place_name
FROM (
-- 1. ประวัติจากงานผู้ป่วยนอก (OPD / ovst_vaccine)
SELECT
'OPD Service' AS source_type,
o.hn,
o.vstdate AS vaccine_date,
o.vsttime AS vaccine_time,
pv.vaccine_code,
pv.vaccine_name,
pv.vaccine_group,
ov.vaccine_lot_no,
'โรงพยาบาล (OPD)' AS vaccine_place_name
FROM ovst_vaccine ov
INNER JOIN ovst o ON ov.vn = o.vn
INNER JOIN person_vaccine pv ON ov.person_vaccine_id = pv.person_vaccine_id
WHERE o.hn = 'ระบุ_HN'
UNION ALL
-- 2. ประวัติจากงานส่งเสริมสุขภาพนักเรียน (village_student_vaccine + list)
SELECT
'School Health (Student)' AS source_type,
p.patient_hn AS hn,
vsv.vaccine_date,
vsv.vaccine_time,
sv.vaccine_code,
sv.student_vaccine_name AS vaccine_name,
'School/Student' AS vaccine_group,
vsvl.vaccine_lotno AS vaccine_lot_no,
svp.student_vaccine_place_name AS vaccine_place_name
FROM village_student_vaccine vsv
INNER JOIN village_student vs ON vsv.village_student_id = vs.village_student_id
INNER JOIN person p ON vs.person_id = p.person_id
INNER JOIN village_student_vaccine_list vsvl ON vsv.village_student_vaccine_id = vsvl.village_student_vaccine_id
INNER JOIN student_vaccine sv ON vsvl.student_vaccine_id = sv.student_vaccine_id
LEFT JOIN student_vaccine_place svp ON vsv.student_vaccine_place_id = svp.student_vaccine_place_id
WHERE p.patient_hn = 'ระบุ_HN'
) vax
ORDER BY vax.vaccine_date DESC, vax.vaccine_time DESC;",
"ncd_sql" => "SELECT pp.person_id, v.hn ,p.cid, p.mobile_phone_number,
concat(p.pname,p.fname,' ',p.lname) as pt_name, pp.house_regist_type_id, p.birthday,
s.name as sex_name, p.moopart, t3.name as tmb_name, cl.regdate, cl.clinicmember_id,
TIMESTAMPDIFF(YEAR, birthday, CURDATE()) AS age_y , pe.name as pttype_name,
h.name as hosp_name, p.addrpart, ci.icd10
FROM opdscreen os
LEFT OUTER JOIN vn_stat v on v.vn=os.vn
LEFT OUTER JOIN ovst o on v.vn=o.vn
LEFT OUTER JOIN patient p on p.hn=os.hn
LEFT OUTER JOIN person pp on p.hn=pp.patient_hn
LEFT OUTER JOIN sex s on p.sex=s.code
LEFT OUTER JOIN thaiaddress t1 on t1.chwpart=p.chwpart and t1.amppart='00' and t1.tmbpart='00'
LEFT OUTER JOIN thaiaddress t2 on t2.chwpart=p.chwpart and t2.amppart=p.amppart and t2.tmbpart='00'
LEFT OUTER JOIN thaiaddress t3 on t3.chwpart=p.chwpart and t3.amppart=p.amppart and t3.tmbpart=p.tmbpart
LEFT OUTER JOIN clinicmember cl on p.hn=cl.hn
LEFT OUTER JOIN pttype pe on v.pttype=pe.pttype
LEFT OUTER JOIN hospcode h on o.hospmain=h.hospcode
LEFT OUTER JOIN clinic_persist_icd ci on cl.hn=ci.hn
WHERE cl.hn in(select hn from ovst where vstdate between ? and ? )
AND cl.clinic_member_status_id='1' {clinic_cond}
GROUP BY v.hn ORDER BY v.hn ASC",
"ncd_clinic_dm_code" => "001",
"ncd_clinic_ht_code" => "002",
"ncd_clinic_dlp_code" => "039",
"ncd_clinic_ckd_code" => "051"
];
$db_settings = [];
try {
$result = $conn2->query("SELECT setting_key, setting_value FROM sys_settings");
if ($result) {
while ($row = $result->fetch_assoc()) {
$db_settings[$row['setting_key']] = $row['setting_value'];
}
}
} catch (Exception $e) {
// Ignore fetch errors
}
return array_merge($defaults, $db_settings);
}
function save_app_settings($settings) {
global $conn2;
if (!isset($conn2)) {
}
_init_settings_db($conn2);
try {
$stmt = $conn2->prepare("INSERT INTO sys_settings (setting_key, setting_value) VALUES (?, ?) ON DUPLICATE KEY UPDATE setting_value = VALUES(setting_value)");
if ($stmt) {
foreach ($settings as $key => $value) {
// Ensure value is a string
$val_str = (string)$value;
$stmt->bind_param("ss", $key, $val_str);
$stmt->execute();
}
$stmt->close();
return true;
}
} catch (Exception $e) {
error_log("Failed to save app settings: " . $e->getMessage());
}
return false;
}
?>
+778
View File
@@ -0,0 +1,778 @@
<?php
$user_agent = $_SERVER['HTTP_USER_AGENT'];
function getOS()
{
global $user_agent;
$os_platform = "Unknown OS Platform";
$os_array = array(
'/windows nt 10.0/i' => 'Windows 10/11',
'/windows nt 6.3/i' => 'Windows 8.1',
'/windows nt 6.2/i' => 'Windows 8',
'/windows nt 6.1/i' => 'Windows 7',
'/windows nt 6.0/i' => 'Windows Vista',
'/windows nt 5.2/i' => 'Windows Server 2003/XP x64',
'/windows nt 5.1/i' => 'Windows XP',
'/windows xp/i' => 'Windows XP',
'/windows nt 5.0/i' => 'Windows 2000',
'/windows me/i' => 'Windows ME',
'/win98/i' => 'Windows 98',
'/win95/i' => 'Windows 95',
'/win16/i' => 'Windows 3.11',
'/macintosh|mac os x/i' => 'Mac OS X',
'/mac_powerpc/i' => 'Mac OS 9',
'/linux/i' => 'Linux',
'/ubuntu/i' => 'Ubuntu',
'/iphone/i' => 'iPhone',
'/ipod/i' => 'iPod',
'/ipad/i' => 'iPad',
'/android/i' => 'Android',
'/blackberry/i' => 'BlackBerry',
'/webos/i' => 'Mobile'
);
foreach ($os_array as $regex => $value) {
if (preg_match($regex, $user_agent)) {
$os_platform = $value;
}
}
return $os_platform;
}
function getBrowser()
{
global $user_agent;
$browser = "Unknown Browser";
$browser_array = array(
'/edg/i' => 'Microsoft Edge',
'/msie/i' => 'Internet Explorer',
'/firefox/i' => 'Firefox',
'/safari/i' => 'Safari',
'/chrome/i' => 'Chrome',
'/opera/i' => 'Opera',
'/netscape/i' => 'Netscape',
'/maxthon/i' => 'Maxthon',
'/konqueror/i' => 'Konqueror',
'/mobile/i' => 'Handheld Browser'
);
foreach ($browser_array as $regex => $value) {
if (preg_match($regex, $user_agent)) {
$browser = $value;
}
}
return $browser;
}
$user_os = getOS();
$user_browser = getBrowser();
$show_ip = $_SERVER['REMOTE_ADDR'];
//$device_details = "<strong>Browser: </strong>".$user_browser."<br /><strong>Operating System: </strong>".$user_os."";
//print_r($device_details);
//echo("<br /><br /><br />".$_SERVER['HTTP_USER_AGENT']."");
//--------------------------------------ฟังก์ชันแปลงวันเป็นภาษาไทยแบบเต็ม------------------------------------------------//
function thai_date($date)
{
list($year, $month, $day) = explode('-', $date);
if ($day < 10) {
$day = substr($day, 1, 1);
}
$thMonth = array("ม.ค.", "ก.พ.", "มี.ค.", "เม.ย.", "พ.ค.", "มิ.ย.", "ก.ค.", "ส.ค.", "ก.ย.", "ต.ค.", "พ.ย.", "ธ.ค.");
if ($month < 10) {
$month = substr($month, 1, 1);
}
$year += 543;
return $day . "&nbsp;" . $thMonth[$month - 1] . "&nbsp;" . $year;
}
//---------------------------------ฟังก์ชันแปลงวันเป็นภาษาไทยแบบเต็ม-----------------------------------------------------//
//--------------------------------------ฟังก์ชันแปลงเดือนเป็นภาษาไทยแบบเต็ม------------------------------------------------//
function thai_month($date)
{
list($year, $month, $day) = explode('-', $date);
if ($day < 10) {
$day = substr($day, 1, 1);
}
$thMonth = array("มกราคม", "กุมภาพันธ์", "มีนาคม", "เมษายน", "พฤษภาคม", "มิถุนายน", "กรกฎาคม", "สิงหาคม", "กันยายน", "ตุลาคม", "พฤศจิกายน", "ธันวาคม");
if ($month < 10) {
$month = substr($month, 1, 1);
}
$year += 543;
return $thMonth[$month - 1] . "&nbsp;" . $year;
}
//---------------------------------ฟังก์ชันแปลงเดือนเป็นภาษาไทยแบบเต็ม-----------------------------------------------------//
//--------------------------------------ฟังก์ชันแปลงวันเป็นภาษาไทย2------------------------------------------------//
function thai_date2($date)
{
list($year, $month, $day) = explode('-', $date);
$year += 543;
return $day . "-" . $month . "-" . $year;
}
function thai_date3($date)
{
list($year, $month, $day) = explode('-', $date);
return $day . "-" . $month . "-" . $year;
}
function thai_date_full($date)
{
list($year, $month, $day) = explode('-', $date);
if ($day < 10) {
$day = substr($day, 1, 1);
}
$thMonth = array("มกราคม", "กุมภาพันธ์", "มีนาคม", "เมษายน", "พฤษภาคม", "มิถุนายน", "กรกฎาคม", "สิงหาคม", "กันยายน", "ตุลาคม", "พฤศจิกายน", "ธันวาคม");
if ($month < 10) {
$month = substr($month, 1, 1);
}
$year = $year + 543;
return $day . " " . $thMonth[$month - 1] . " พ.ศ. " . $year;
}
function thai_date5($date)
{
list($day, $month, $year) = explode('-', $date);
if ($day < 10) {
$day = substr($day, 1, 1);
}
$thMonth = array("มกราคม", "กุมภาพันธ์", "มีนาคม", "เมษายน", "พฤษภาคม", "มิถุนายน", "กรกฎาคม", "สิงหาคม", "กันยายน", "ตุลาคม", "พฤศจิกายน", "ธันวาคม");
if ($month < 10) {
$month = substr($month, 1, 1);
}
return $day . "&nbsp;" . $thMonth[$month - 1] . "&nbsp;พ.ศ.&nbsp;" . $year;
}
function thai_date6($date)
{
list($year, $month, $day) = explode('-', $date);
if ($day < 10) {
$day = substr($day, 1, 1);
}
$thMonth = array("ม.ค.", "ก.พ.", "มี.ค.", "เม.ย.", "พ.ค.", "มิ.ย.", "ก.ค.", "ส.ค.", "ก.ย.", "ต.ค.", "พ.ย.", "ธ.ค.");
if ($month < 10) {
$month = substr($month, 1, 1);
}
$year = $year + 543;
return $day . "&nbsp;" . $thMonth[$month - 1] . "&nbsp;" . $year;
}
function thai_date7($date)
{
list($year, $month, $day) = explode('-', $date);
if ($day < 10) {
$day = substr($day, 1, 1);
}
$thMonth = array("มกราคม", "กุมภาพันธ์", "มีนาคม", "เมษายน", "พฤษภาคม", "มิถุนายน", "กรกฎาคม", "สิงหาคม", "กันยายน", "ตุลาคม", "พฤศจิกายน", "ธันวาคม");
if ($month < 10) {
$month = substr($month, 1, 1);
}
$year = $year + 543;
return "วันที่ " . $day . "&nbsp;" . $thMonth[$month - 1] . "&nbsp;พ.ศ.&nbsp;" . $year;
}
function thai_date8($date)
{
list($day, $month, $year) = explode('-', $date);
if ($day < 10) {
$day = substr($day, 1, 1);
}
$thMonth = array("ม.ค.", "ก.พ.", "มี.ค.", "เม.ย.", "พ.ค.", "มิ.ย.", "ก.ค.", "ส.ค.", "ก.ย.", "ต.ค.", "พ.ย.", "ธ.ค.");
if ($month < 10) {
$month = substr($month, 1, 1);
}
return $day . "&nbsp;" . $thMonth[$month - 1] . "&nbsp;" . $year;
}
function novel_date1($date)
{
list($year, $month, $day) = explode('-', $date);
return $day . "/" . $month . "/" . $year;
}
function thai_date9($date)
{
list($year, $month, $day) = explode('-', $date);
$year += 543;
return $day . "/" . $month . "/" . $year;
}
//---------------------------------ฟังก์ชันแปลงวันเป็นภาษาไทย2-----------------------------------------------------//
//--------------------------------------ฟังก์ชันแปลงวันเป็นรูปแบบของ mysql------------------------------------------------//
function mysql_date1($date)
{
list($day, $month, $year) = explode('-', $date);
switch ($month) {
case "ม.ค.":
$thMonth = "01";
break;
case "ก.พ.":
$thMonth = "02";
break;
case "มี.ค.":
$thMonth = "03";
break;
case "เม.ย.":
$thMonth = "04";
break;
case "พ.ค.":
$thMonth = "05";
break;
case "มิ.ย.":
$thMonth = "06";
break;
case "ก.ค.":
$thMonth = "07";
break;
case "ส.ค.":
$thMonth = "08";
break;
case "ก.ย.":
$thMonth = "09";
break;
case "ต.ค.":
$thMonth = "10";
break;
case "พ.ย.":
$thMonth = "11";
break;
case "ธ.ค.":
$thMonth = "12";
break;
}
$year = $year - 543;
return $year . "-" . $thMonth . "-" . $day;
}
function mysql_date2($date)
{
list($null, $day, $month, $year) = explode('-', $date);
switch ($month) {
case "ม.ค.":
$thMonth = "01";
break;
case "ก.พ.":
$thMonth = "02";
break;
case "มี.ค.":
$thMonth = "03";
break;
case "เม.ย.":
$thMonth = "04";
break;
case "พ.ค.":
$thMonth = "05";
break;
case "มิ.ย.":
$thMonth = "06";
break;
case "ก.ค.":
$thMonth = "07";
break;
case "ส.ค.":
$thMonth = "08";
break;
case "ก.ย.":
$thMonth = "09";
break;
case "ต.ค.":
$thMonth = "10";
break;
case "พ.ย.":
$thMonth = "11";
break;
case "ธ.ค.":
$thMonth = "12";
break;
}
$year = $year - 543;
return $year . "-" . $thMonth . "-" . $day;
}
function mysql_date3($date)
{
@list($day, $month, $year) = @explode('-', $date);
return $year . "-" . $month . "-" . $day;
}
//--------------------------------ฟังก์ชันแปลงวันเป็นรูปแบบของ mysql------------------------------------------------------//
//--------------------------------------ฟังก์ชันแบ่งช่วงของวัน------------------------------------------------//
function explode_date1($date)
{
list($date1, $date2) = explode('-', $date);
return mysql_date1($date1);
}
function explode_date2($date)
{
list($date1, $date2) = explode('-', $date);
$new_date2 = mysql_date2($date2);
if ($new_date2 == "-543--") {
echo "";
} else {
return $new_date2;
}
}
//---------------------------------ฟังก์ชันแบ่งช่วงของวัน-----------------------------------------------------//
//--------------------------------------ฟังก์ชันแปลงวันเป็นรูปแบบเลขที่ใบสมัคร------------------------------------------------//
function code_date($date)
{
list($year, $month, $day) = explode('-', $date);
$Month = $month;
$year += 543;
$sYear = substr($year, 2, 2);
return $sYear . $day . $Month;
}
//---------------------------------ฟังก์ชันแปลงวันเป็นรูปแบบเลขที่ใบสมัคร-----------------------------------------------------//
//--------------------------------------ฟังก์ชันแยกชื่อ-นามสกุลไฟล์------------------------------------------------//
function explode_filename($filename)
{
list($name, $ext) = explode('.', $filename);
return $name;
}
function explode_extname($filename)
{
list($name, $ext) = explode('.', $filename);
return $ext;
}
//---------------------------------ฟังก์ชันแยกชื่อ-นามสกุลไฟล์-----------------------------------------------------//
//--------------------------------------ฟังก์ชันแบ่งชื่อ------------------------------------------------//
function split_fname($name)
{
list($fname, $lname) = explode(' ', $name);
return $fname;
}
function split_lname($name)
{
list($fname, $lname) = explode(' ', $name);
return $lname;
}
//---------------------------------ฟังก์ชันแบ่งชื่อ-----------------------------------------------------//
//--------------------------------------ฟังก์ชันแปลงวันเวลาเป็นวัน------------------------------------------------//
function datetime_to_date($date)
{
list($date1, $time) = explode(' ', $date);
list($year, $month, $day) = explode('-', $date1);
$year += 543;
return $day . "-" . $month . "-" . $year;
}
function datetime_to_date2($date)
{
list($date1, $time) = explode('-', $date);
return $date1;
}
//---------------------------------ฟังก์ชันแปลงวันเวลาเป็นวัน-----------------------------------------------------//
//--------------------------------------ฟังก์ชันแปลงวันเวลาเป็นเวลา------------------------------------------------//
function datetime_to_time($date)
{
list($date1, $time) = explode(' ', $date);
list($hh, $mm, $ss) = explode(':', $time);
return $hh . ":" . $mm;
}
//---------------------------------ฟังก์ชันแปลงวันเวลาเป็นเวลา-----------------------------------------------------//
//------------------------ตัดคำ----------------------------------------------------//
//------------------------------ฟังก์ชั่นตั้งชื่อไฟล์จากวันเวลา------------------------------------------------//
function gen_filename($date)
{
list($date1, $time) = explode(' ', $date);
list($year, $month, $day) = explode('-', $date1);
list($hh, $mm, $ss) = explode(':', $time);
$year += 543;
$year2 = substr($year, 2, 2);
return $year2 . "" . $month . "" . $day . "" . $hh . "" . $mm . "" . $ss;
}
//---------------------------------ฟังก์ชันแปลงวันเวลาเป็นเวลา-----------------------------------------------------//
//------------------------ตัดคำ----------------------------------------------------//
function cutStr($str, $maxChars = '', $holder = '')
{
if (strlen($str) > $maxChars) {
$str = iconv_substr($str, 0, $maxChars, "UTF-8") . $holder;
}
return $str;
}
//--------------------------------------ฟังก์ชันแยกเดือน-ปี------------------------------------------------//
function showDate($today)
{
list($year, $month, $date) = explode('-', $today);
return $date;
}
function showDate2($today)
{
list($year, $month, $date) = explode('-', $today);
return $date;
}
function showMonth($today)
{
list($year, $month, $date) = explode('-', $today);
return $month;
}
function showMonth2($today)
{
list($year, $month, $date) = explode('-', $today);
return $month;
}
function showYear($today, $date)
{
list($year, $month, $date) = explode('-', $today);
return $year;
}
function showYear2($today, $date)
{
list($year, $month, $date) = explode('-', $today);
return $year;
}
function showAll($today)
{
list($year, $month, $date) = explode('-', $today);
$thMonth = array("มกราคม", "กุมภาพันธ์", "มีนาคม", "เมษายน", "พฤษภาคม", "มิถุนายน", "กรกฎาคม", "สิงหาคม", "กันยายน", "ตุลาคม", "พฤศจิกายน", "ธันวาคม");
if ($month < 10) {
$month = substr($month, 1, 1);
}
$year += 543;
return $thMonth[$month - 1] . "&nbsp;พ.ศ.&nbsp;" . $year;
}
function showAll2($today)
{
list($year, $month, $date) = explode('-', $today);
$thMonth = array("มกราคม", "กุมภาพันธ์", "มีนาคม", "เมษายน", "พฤษภาคม", "มิถุนายน", "กรกฎาคม", "สิงหาคม", "กันยายน", "ตุลาคม", "พฤศจิกายน", "ธันวาคม");
if ($month < 10) {
$month = substr($month, 1, 1);
}
$year += 543;
return $date . " " . $thMonth[$month - 1] . "&nbsp;พ.ศ.&nbsp;" . $year;
}
function typeFile($name)
{
list($f, $l) = explode('.', $name);
return $l;
}
//--------------------------------------ฟังก์ชันแยกเดือน-ปี------------------------------------------------//
//--------------------------------------ฟังก์ชันแยกชื่อ-นามสกุล------------------------------------------------//
function explode_fname($data)
{
list($fname, $lname) = explode(' ', $data);
return $fname;
}
function explode_lname($data)
{
list($fname, $lname) = explode(' ', $data);
return $lname;
}
//---------------------------------ฟังก์ชันแยกชื่อ-นามสกุล-----------------------------------------------------//
//------------------ วันนี้ แยก วัน เดือน ปี -------------------------------------
function today_date($date)
{
list($year, $month, $day) = explode('-', $date);
if ($day < 10) {
$day = substr($day, 1, 1);
}
return $day;
}
function today_month($date)
{
list($year, $month, $day) = explode('-', $date);
$thMonth = array("มกราคม", "กุมภาพันธ์", "มีนาคม", "เมษายน", "พฤษภาคม", "มิถุนายน", "กรกฎาคม", "สิงหาคม", "กันยายน", "ตุลาคม", "พฤศจิกายน", "ธันวาคม");
if ($month < 10) {
$month = substr($month, 1, 1);
}
return $thMonth[$month - 1];
}
function today_year($date)
{
list($year, $month, $day) = explode('-', $date);
$year = $year + 543;
return $year;
}
//--------------------------------------ฟังก์ชันเข้ารหัสและถอดรหัส (URL Security)------------------------------------------------//
function encrypt_param($data) {
if (empty($data)) return '';
$method = 'AES-256-CBC';
$key = defined('APP_KEY') ? APP_KEY : 'default_fallback_key_2026';
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($method));
$encrypted = openssl_encrypt($data, $method, $key, 0, $iv);
// Combine IV (base64) and Encrypted payload (base64) to avoid binary concatenation issues
$payload = base64_encode($iv) . '::' . $encrypted;
// Use Base64URL to prevent +, /, and = from breaking in GET/POST requests
return rtrim(strtr(base64_encode($payload), '+/', '-_'), '=');
}
function decrypt_param($data) {
if (empty($data)) return '';
$method = 'AES-256-CBC';
$key = defined('APP_KEY') ? APP_KEY : 'default_fallback_key_2026';
// Decode Base64URL back to standard Base64
$b64 = str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT);
$decoded = base64_decode($b64);
if (strpos($decoded, '::') === false) {
// Fallback for legacy base64-only data to prevent breaking existing bookmarked links during transition
return base64_decode($data); // Fallback to raw base64 decode if it was an old link
}
list($iv_b64, $encrypted) = explode('::', $decoded, 2);
$iv = base64_decode($iv_b64);
return openssl_decrypt($encrypted, $method, $key, 0, $iv);
}
//--------------------------------------ฟังก์ชันตรวจสอบสิทธิ์แอดมิน------------------------------------------------//
function is_admin($username) {
global $conn2;
if (!$conn2 || empty($username)) return false;
// Auto-create sys_admins table
$create_sql = "CREATE TABLE IF NOT EXISTS sys_admins (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(255) NOT NULL UNIQUE,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
granted_by VARCHAR(255)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;";
$conn2->query($create_sql);
// Check total admins (Bootstrap logic)
$res_count = $conn2->query("SELECT COUNT(*) AS total FROM sys_admins");
if ($res_count) {
$row = $res_count->fetch_assoc();
if ($row['total'] == 0) {
// No admins exist yet, allow everyone so they can set themselves as admin
return true;
}
}
// Check if user is admin
$sql = "SELECT id FROM sys_admins WHERE username = ?";
$stmt = $conn2->prepare($sql);
if ($stmt) {
$stmt->bind_param("s", $username);
$stmt->execute();
$res = $stmt->get_result();
$is_admin = ($res->num_rows > 0);
$stmt->close();
$stmt->close();
return $is_admin;
}
return false;
}
//--------------------------------------ฟังก์ชันตรวจสอบสิทธิ์การค้นหาด้วยชื่อ------------------------------------------------//
function can_search_name($username) {
global $conn2;
if (!$conn2 || empty($username)) return false;
// Auto-create sys_user_permissions table
$create_sql = "CREATE TABLE IF NOT EXISTS sys_user_permissions (
username VARCHAR(255) PRIMARY KEY,
can_search_name TINYINT(1) DEFAULT 0,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
updated_by VARCHAR(255)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;";
$conn2->query($create_sql);
// If user is admin, they can do anything
if (is_admin($username)) return true;
// Check specific permission
$sql = "SELECT can_search_name FROM sys_user_permissions WHERE username = ? AND can_search_name = 1";
$stmt = $conn2->prepare($sql);
if ($stmt) {
$stmt->bind_param("s", $username);
$stmt->execute();
$res = $stmt->get_result();
$has_permission = ($res->num_rows > 0);
$stmt->close();
return $has_permission;
}
return false;
}
//--------------------------------------ฟังก์ชันเก็บประวัติการใช้งานระบบ (System Audit Logs)------------------------------------------------//
function system_log($conn, $username, $action, $details = null) {
if (!$conn) return false;
try {
// Auto-create table if not exists (safe to run, minimal overhead if table exists)
$create_sql = "CREATE TABLE IF NOT EXISTS sys_audit_logs (
id INT AUTO_INCREMENT PRIMARY KEY,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
username VARCHAR(255) NOT NULL,
action VARCHAR(50) NOT NULL,
details TEXT,
ip_address VARCHAR(45),
user_agent TEXT,
INDEX idx_action (action),
INDEX idx_username (username),
INDEX idx_created_at (created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;";
$conn->query($create_sql);
$ip_address = $_SERVER['REMOTE_ADDR'] ?? 'UNKNOWN';
$user_agent = $_SERVER['HTTP_USER_AGENT'] ?? 'UNKNOWN';
$details_json = is_array($details) ? json_encode($details, JSON_UNESCAPED_UNICODE) : $details;
$sql = "INSERT INTO sys_audit_logs (username, action, details, ip_address, user_agent) VALUES (?, ?, ?, ?, ?)";
$stmt = $conn->prepare($sql);
if ($stmt) {
$stmt->bind_param("sssss", $username, $action, $details_json, $ip_address, $user_agent);
$result = $stmt->execute();
$stmt->close();
return $result;
}
} catch (Throwable $e) {
error_log("system_log Error: " . $e->getMessage());
}
return false;
}
// Helper function to loosely determine abnormal labs
function isAbnormalLab($result, $normal) {
if (empty($result) || empty($normal) || $normal == '-') return false;
$resStr = strtolower(trim($result));
$normStr = strtolower(trim($normal));
// Keyword check
if (in_array($resStr, ['positive', 'reactive', 'detected'])) {
if (strpos($normStr, 'negative') !== false || strpos($normStr, 'non-reactive') !== false || strpos($normStr, 'undetected') !== false) {
return true;
}
}
// Numeric check
preg_match('/^[-+]?[0-9]*\.?[0-9]+/', $result, $resMatch);
if (!empty($resMatch)) {
$val = (float)$resMatch[0];
// Fix: Replace dashes between numbers with " to " so they aren't parsed as negative signs
$normal_parsed = preg_replace('/(\d)\s*-\s*(\d)/', '$1 to $2', $normal);
preg_match_all('/[-+]?[0-9]*\.?[0-9]+/', $normal_parsed, $normMatches);
if (!empty($normMatches[0])) {
$numbers = $normMatches[0];
// Since we replaced '-', check for "to" or '-' in original
if (count($numbers) == 2 && (strpos($normal, '-') !== false || strpos($normal_parsed, 'to') !== false) && !preg_match('/[ชญ]/u', $normal)) {
if ($val < (float)$numbers[0] || $val > (float)$numbers[1]) return true;
} else if (count($numbers) >= 4 && preg_match('/[ชญ]/u', $normal)) {
$min1 = min((float)$numbers[0], (float)$numbers[2]);
$max1 = max((float)$numbers[1], (float)$numbers[3]);
if ($val < $min1 || $val > $max1) return true;
} else if (strpos($normal, '<') !== false && count($numbers) >= 1) {
preg_match('/<\s*([0-9.]+)/', $normal, $ltMatch);
if (!empty($ltMatch) && $val >= (float)$ltMatch[1]) return true; // changed to >= if normal is < X, then X is abnormal
} else if (strpos($normal, '>') !== false && count($numbers) >= 1) {
preg_match('/>\s*([0-9.]+)/', $normal, $gtMatch);
if (!empty($gtMatch) && $val <= (float)$gtMatch[1]) return true; // changed to <= if normal is > X, then X is abnormal
}
}
}
return false;
}
?>