From e90569bab6453a35ba9e62b013664d5a6e7610f7 Mon Sep 17 00:00:00 2001 From: Basoro Date: Sun, 15 Sep 2024 17:33:49 +0800 Subject: [PATCH 1/9] Add backup and restore feature on mLite Settings --- .gitignore | 1 + plugins/settings/Admin.php | 92 +++- plugins/settings/inc/Backup_Database.php | 417 ++++++++++++++++++ plugins/settings/inc/Restore_Database.php | 266 +++++++++++ .../settings/view/admin/backup.restore.html | 93 ++++ 5 files changed, 862 insertions(+), 7 deletions(-) create mode 100644 plugins/settings/inc/Backup_Database.php create mode 100644 plugins/settings/inc/Restore_Database.php create mode 100644 plugins/settings/view/admin/backup.restore.html diff --git a/.gitignore b/.gitignore index 8cf6e0b48..61056beb2 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,4 @@ logs/ config.php workerman.php composer.lock +backups diff --git a/plugins/settings/Admin.php b/plugins/settings/Admin.php index 4d7a81ac9..02bbf6958 100644 --- a/plugins/settings/Admin.php +++ b/plugins/settings/Admin.php @@ -11,18 +11,13 @@ use RecursiveDirectoryIterator; use FilesystemIterator; use Plugins\Settings\Inc\RecursiveDotFilterIterator; +use Plugins\Settings\Inc\Backup_Database; +use Plugins\Settings\Inc\Restore_Database; class Admin extends AdminModule { private $assign = []; - public function init() - { - if (file_exists(BASE_DIR.'/inc/engine')) { - deleteDir(BASE_DIR.'/inc/engine'); - } - } - public function navigation() { return [ @@ -30,6 +25,7 @@ public function navigation() 'Umum' => 'general', 'Tema' => 'theme', 'Pembaruan' => 'updates', + 'Backup & Restore' => 'backuprestore', ]; } @@ -39,6 +35,7 @@ public function getManage() ['name' => 'Pengaturan Umum', 'url' => url([ADMIN, 'settings', 'general']), 'icon' => 'wrench', 'desc' => 'Pengaturan umum mLITE'], ['name' => 'Tema Publik', 'url' => url([ADMIN, 'settings', 'theme']), 'icon' => 'cubes', 'desc' => 'Pengaturan tema tampilan publik'], ['name' => 'Pembaruan Sistem', 'url' => url([ADMIN, 'settings', 'updates']), 'icon' => 'cubes', 'desc' => 'Pembaruan sistem'], + ['name' => 'Backup & Restore', 'url' => url([ADMIN, 'settings', 'backuprestore']), 'icon' => 'database', 'desc' => 'Backup dan restore database'], ]; return $this->draw('manage.html', ['sub_modules' => $sub_modules]); } @@ -583,6 +580,87 @@ public function anyCekDaftar() return $this->draw('cek.daftar.html'); } + public function getBackupRestore() + { + $database = DBNAME; + $get_table = $this->db()->pdo()->prepare("SELECT DISTINCT TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='$database'"); + $get_table->execute(); + $result = $get_table->fetchAll(); + + $backup_files = glob('../backups/*.sql.gz'); + // $backup_files = pathinfo($backup_files); + return $this->draw('backup.restore.html', ['databases' => $result, 'files' => $backup_files]); + } + + public function getBackupDatabase() + { + // Report all errors + error_reporting(E_ALL); + // Set script max execution time + set_time_limit(9000); // 15 minutes + + if (php_sapi_name() != "cli") { + echo '
'; + } + + $backupDatabase = new Backup_Database(DBHOST, DBUSER, DBPASS, DBNAME, CHARSET); + + // Option-1: Backup tables already defined above + $result = $backupDatabase->backupTables(TABLES) ? 'OK' : 'KO'; + + // Option-2: Backup changed tables only - uncomment block below + /* + $since = '1 day'; + $changed = $backupDatabase->getChangedTables($since); + if(!$changed){ + $backupDatabase->obfPrint('No tables modified since last ' . $since . '! Quitting..', 1); + die(); + } + $result = $backupDatabase->backupTables($changed) ? 'OK' : 'KO'; + */ + + $backupDatabase->obfPrint('Backup result: ' . $result, 1); + + // Use $output variable for further processing, for example to send it by email + $output = $backupDatabase->getOutput(); + + if (php_sapi_name() != "cli") { + echo '
'; + } + exit(); + } + + public function getRestoreDatabase() + { + $file_name = $_GET['filename']; + + define("BACKUP_FILE", $file_name); // Script will autodetect if backup file is gzipped based on .gz extension + // Report all errors + error_reporting(E_ALL); + // Set script max execution time + set_time_limit(900); // 15 minutes + + if (php_sapi_name() != "cli") { + echo '
'; + } + + $restoreDatabase = new Restore_Database(DBHOST, DBUSER, DBPASS, DBNAME); + $result = $restoreDatabase->restoreDb(BACKUP_DIR, BACKUP_FILE) ? 'OK' : 'KO'; + $restoreDatabase->obfPrint("Restoration result: ".$result, 1); + + if (php_sapi_name() != "cli") { + echo '
'; + } + exit(); + } + + public function getDeleteDatabase() + { + $file_name = $_GET['filename']; + unlink('../backups/' . $file_name); + exit(); + } + private function _addHeaderFiles() { $this->core->addCSS(url('assets/css/bootstrap-colorpicker.css')); diff --git a/plugins/settings/inc/Backup_Database.php b/plugins/settings/inc/Backup_Database.php new file mode 100644 index 000000000..bdf968417 --- /dev/null +++ b/plugins/settings/inc/Backup_Database.php @@ -0,0 +1,417 @@ +host = $host; + $this->username = $username; + $this->passwd = $passwd; + $this->dbName = $dbName; + $this->charset = $charset; + $this->conn = $this->initializeDatabase(); + $this->backupDir = BACKUP_DIR ? BACKUP_DIR : '.'; + $this->backupFile = 'backup-'.$this->dbName.'-'.date("Ymd_His", time()).'.sql'; + $this->gzipBackupFile = defined('GZIP_BACKUP_FILE') ? GZIP_BACKUP_FILE : true; + $this->disableForeignKeyChecks = defined('DISABLE_FOREIGN_KEY_CHECKS') ? DISABLE_FOREIGN_KEY_CHECKS : true; + $this->batchSize = defined('BATCH_SIZE') ? BATCH_SIZE : 1000; // default 1000 rows + $this->output = ''; + } + + protected function initializeDatabase() { + try { + $conn = mysqli_connect($this->host, $this->username, $this->passwd, $this->dbName); + if (mysqli_connect_errno()) { + throw new Exception('ERROR connecting database: ' . mysqli_connect_error()); + die(); + } + if (!mysqli_set_charset($conn, $this->charset)) { + mysqli_query($conn, 'SET NAMES '.$this->charset); + } + } catch (Exception $e) { + print_r($e->getMessage()); + die(); + } + + return $conn; + } + + /** + * Backup the whole database or just some tables + * Use '*' for whole database or 'table1 table2 table3...' + * @param string $tables + */ + public function backupTables($tables = '*') { + try { + /** + * Tables to export + */ + if($tables == '*') { + $tables = array(); + $result = mysqli_query($this->conn, 'SHOW TABLES'); + while($row = mysqli_fetch_row($result)) { + $tables[] = $row[0]; + } + } else { + $tables = is_array($tables) ? $tables : explode(',', str_replace(' ', '', $tables)); + } + + $sql = 'CREATE DATABASE IF NOT EXISTS `'.$this->dbName.'`'.";\n\n"; + $sql .= 'USE `'.$this->dbName."`;\n\n"; + + /** + * Disable foreign key checks + */ + if ($this->disableForeignKeyChecks === true) { + $sql .= "SET foreign_key_checks = 0;\n\n"; + } + + /** + * Iterate tables + */ + foreach($tables as $table) { + if( in_array($table, IGNORE_TABLES) ) + continue; + $this->obfPrint("Backing up `".$table."` table...".str_repeat('.', 50-strlen($table)), 0, 0); + + /** + * CREATE TABLE + */ + $sql .= 'DROP TABLE IF EXISTS `'.$table.'`;'; + $row = mysqli_fetch_row(mysqli_query($this->conn, 'SHOW CREATE TABLE `'.$table.'`')); + $sql .= "\n\n".$row[1].";\n\n"; + + /** + * INSERT INTO + */ + + $row = mysqli_fetch_row(mysqli_query($this->conn, 'SELECT COUNT(*) FROM `'.$table.'`')); + $numRows = $row[0]; + + // Split table in batches in order to not exhaust system memory + $numBatches = intval($numRows / $this->batchSize) + 1; // Number of while-loop calls to perform + + for ($b = 1; $b <= $numBatches; $b++) { + + $query = 'SELECT * FROM `' . $table . '` LIMIT ' . ($b * $this->batchSize - $this->batchSize) . ',' . $this->batchSize; + $result = mysqli_query($this->conn, $query); + $realBatchSize = mysqli_num_rows ($result); // Last batch size can be different from $this->batchSize + $numFields = mysqli_num_fields($result); + + if ($realBatchSize !== 0) { + $sql .= 'INSERT INTO `'.$table.'` VALUES '; + + for ($i = 0; $i < $numFields; $i++) { + $rowCount = 1; + while($row = mysqli_fetch_row($result)) { + $sql.='('; + for($j=0; $j<$numFields; $j++) { + if (isset($row[$j])) { + $row[$j] = addslashes($row[$j]); + $row[$j] = str_replace("\n","\\n",$row[$j]); + $row[$j] = str_replace("\r","\\r",$row[$j]); + $row[$j] = str_replace("\f","\\f",$row[$j]); + $row[$j] = str_replace("\t","\\t",$row[$j]); + $row[$j] = str_replace("\v","\\v",$row[$j]); + $row[$j] = str_replace("\a","\\a",$row[$j]); + $row[$j] = str_replace("\b","\\b",$row[$j]); + // if ($row[$j] == 'true' or $row[$j] == 'false' or preg_match('/^-?[1-9][0-9]*$/', $row[$j]) or $row[$j] == 'NULL' or $row[$j] == 'null') { + if ($row[$j] == 'true' or $row[$j] == 'false' or $row[$j] == 'NULL' or $row[$j] == 'null') { + $sql .= $row[$j]; + } else { + $sql .= '"'.$row[$j].'"' ; + } + } else { + $sql.= 'NULL'; + } + if ($j < ($numFields-1)) { + $sql .= ','; + } + } + + if ($rowCount == $realBatchSize) { + $rowCount = 0; + $sql.= ");\n"; //close the insert statement + } else { + $sql.= "),\n"; //close the row + } + + $rowCount++; + } + } + + $this->saveFile($sql); + $sql = ''; + } + } + + $sql.="\n\n"; + + $this->obfPrint('OK'); + } + + /** + * Re-enable foreign key checks + */ + if ($this->disableForeignKeyChecks === true) { + $sql .= "SET foreign_key_checks = 1;\n"; + } + + $this->saveFile($sql); + + if ($this->gzipBackupFile) { + $this->gzipBackupFile(); + } else { + $this->obfPrint('Backup file succesfully saved to ' . $this->backupDir.'/'.$this->backupFile, 1, 1); + } + } catch (Exception $e) { + print_r($e->getMessage()); + return false; + } + + return true; + } + + /** + * Save SQL to file + * @param string $sql + */ + protected function saveFile(&$sql) { + if (!$sql) return false; + + try { + + if (!file_exists($this->backupDir)) { + mkdir($this->backupDir, 0777, true); + } + + file_put_contents($this->backupDir.'/'.$this->backupFile, $sql, FILE_APPEND | LOCK_EX); + + } catch (Exception $e) { + print_r($e->getMessage()); + return false; + } + + return true; + } + + /* + * Gzip backup file + * + * @param integer $level GZIP compression level (default: 9) + * @return string New filename (with .gz appended) if success, or false if operation fails + */ + protected function gzipBackupFile($level = 9) { + if (!$this->gzipBackupFile) { + return true; + } + + $source = $this->backupDir . '/' . $this->backupFile; + $dest = $source . '.gz'; + + $this->obfPrint('Gzipping backup file to ' . $dest . '... ', 1, 0); + + $mode = 'wb' . $level; + if ($fpOut = gzopen($dest, $mode)) { + if ($fpIn = fopen($source,'rb')) { + while (!feof($fpIn)) { + gzwrite($fpOut, fread($fpIn, 1024 * 256)); + } + fclose($fpIn); + } else { + return false; + } + gzclose($fpOut); + if(!unlink($source)) { + return false; + } + } else { + return false; + } + + $this->obfPrint('OK'); + return $dest; + } + + /** + * Prints message forcing output buffer flush + * + */ + public function obfPrint ($msg = '', $lineBreaksBefore = 0, $lineBreaksAfter = 1) { + if (!$msg) { + return false; + } + + if ($msg != 'OK' and $msg != 'KO') { + $msg = date("Y-m-d H:i:s") . ' - ' . $msg; + } + $output = ''; + + if (php_sapi_name() != "cli") { + $lineBreak = "
"; + } else { + $lineBreak = "\n"; + } + + if ($lineBreaksBefore > 0) { + for ($i = 1; $i <= $lineBreaksBefore; $i++) { + $output .= $lineBreak; + } + } + + $output .= $msg; + + if ($lineBreaksAfter > 0) { + for ($i = 1; $i <= $lineBreaksAfter; $i++) { + $output .= $lineBreak; + } + } + + + // Save output for later use + $this->output .= str_replace('
', '\n', $output); + + echo $output; + + + if (php_sapi_name() != "cli") { + if( ob_get_level() > 0 ) { + ob_flush(); + } + } + + $this->output .= " "; + + flush(); + } + + /** + * Returns full execution output + * + */ + public function getOutput() { + return $this->output; + } + /** + * Returns name of backup file + * + */ + public function getBackupFile() { + if ($this->gzipBackupFile) { + return $this->backupDir.'/'.$this->backupFile.'.gz'; + } else + return $this->backupDir.'/'.$this->backupFile; + } + + /** + * Returns backup directory path + * + */ + public function getBackupDir() { + return $this->backupDir; + } + + /** + * Returns array of changed tables since duration + * + */ + public function getChangedTables($since = '1 day') { + $query = "SELECT TABLE_NAME,update_time FROM information_schema.tables WHERE table_schema='" . $this->dbName . "'"; + + $result = mysqli_query($this->conn, $query); + while($row=mysqli_fetch_assoc($result)) { + $resultset[] = $row; + } + if(empty($resultset)) + return false; + $tables = []; + for ($i=0; $i < count($resultset); $i++) { + if( in_array($resultset[$i]['TABLE_NAME'], IGNORE_TABLES) ) // ignore this table + continue; + if(strtotime('-' . $since) < strtotime($resultset[$i]['update_time'])) + $tables[] = $resultset[$i]['TABLE_NAME']; + } + return ($tables) ? $tables : false; + } +} diff --git a/plugins/settings/inc/Restore_Database.php b/plugins/settings/inc/Restore_Database.php new file mode 100644 index 000000000..d499addc0 --- /dev/null +++ b/plugins/settings/inc/Restore_Database.php @@ -0,0 +1,266 @@ +host = $host; + $this->username = $username; + $this->passwd = $passwd; + $this->dbName = $dbName; + $this->charset = $charset; + $this->disableForeignKeyChecks = defined('DISABLE_FOREIGN_KEY_CHECKS') ? DISABLE_FOREIGN_KEY_CHECKS : true; + $this->conn = $this->initializeDatabase(); + $this->backupDir = defined('BACKUP_DIR') ? BACKUP_DIR : '.'; + $this->backupFile = defined('BACKUP_FILE') ? BACKUP_FILE : null; + } + + /** + * Destructor re-enables foreign key checks + */ + function __destructor() { + /** + * Re-enable foreign key checks + */ + if ($this->disableForeignKeyChecks === true) { + mysqli_query($this->conn, 'SET foreign_key_checks = 1'); + } + } + + protected function initializeDatabase() { + try { + $conn = mysqli_connect($this->host, $this->username, $this->passwd, $this->dbName); + if (mysqli_connect_errno()) { + throw new Exception('ERROR connecting database: ' . mysqli_connect_error()); + die(); + } + if (!mysqli_set_charset($conn, $this->charset)) { + mysqli_query($conn, 'SET NAMES '.$this->charset); + } + + /** + * Disable foreign key checks + */ + if ($this->disableForeignKeyChecks === true) { + mysqli_query($conn, 'SET foreign_key_checks = 0'); + } + + } catch (Exception $e) { + print_r($e->getMessage()); + die(); + } + + return $conn; + } + + /** + * Backup the whole database or just some tables + * Use '*' for whole database or 'table1 table2 table3...' + * @param string $tables + */ + public function restoreDb() { + try { + $sql = ''; + $multiLineComment = false; + + $backupDir = $this->backupDir; + $backupFile = $this->backupFile; + + /** + * Gunzip file if gzipped + */ + $backupFileIsGzipped = substr($backupFile, -3, 3) == '.gz' ? true : false; + if ($backupFileIsGzipped) { + if (!$backupFile = $this->gunzipBackupFile()) { + throw new Exception("ERROR: couldn't gunzip backup file " . $backupDir . '/' . $backupFile); + } + } + + /** + * Read backup file line by line + */ + $handle = fopen($backupDir . '/' . $backupFile, "r"); + if ($handle) { + $result = mysqli_query($this->conn, 'DROP DATABASE '.$this->dbName); + while (($line = fgets($handle)) !== false) { + $line = ltrim(rtrim($line)); + if (strlen($line) > 1) { // avoid blank lines + $lineIsComment = false; + if (preg_match('/^\/\*/', $line)) { + $multiLineComment = true; + $lineIsComment = true; + } + if ($multiLineComment or preg_match('/^\/\//', $line)) { + $lineIsComment = true; + } + if (!$lineIsComment) { + $sql .= $line; + if (preg_match('/;$/', $line)) { + // execute query + if(mysqli_query($this->conn, $sql)) { + if (preg_match('/^CREATE TABLE `([^`]+)`/i', $sql, $tableName)) { + $this->obfPrint("Table succesfully created: `" . $tableName[1] . "`"); + } + $sql = ''; + } else { + throw new Exception("ERROR: SQL execution error: " . mysqli_error($this->conn)); + } + } + } else if (preg_match('/\*\/$/', $line)) { + $multiLineComment = false; + } + } + } + fclose($handle); + } else { + throw new Exception("ERROR: couldn't open backup file " . $backupDir . '/' . $backupFile); + } + } catch (Exception $e) { + print_r($e->getMessage()); + return false; + } + + if ($backupFileIsGzipped) { + unlink($backupDir . '/' . $backupFile); + } + + return true; + } + + /* + * Gunzip backup file + * + * @return string New filename (without .gz appended and without backup directory) if success, or false if operation fails + */ + protected function gunzipBackupFile() { + // Raising this value may increase performance + $bufferSize = 4096; // read 4kb at a time + $error = false; + + $source = $this->backupDir . '/' . $this->backupFile; + $dest = $this->backupDir . '/' . date("Ymd_His", time()) . '_' . substr($this->backupFile, 0, -3); + + $this->obfPrint('Gunzipping backup file ' . $source . '... ', 1, 1); + + // Remove $dest file if exists + if (file_exists($dest)) { + if (!unlink($dest)) { + return false; + } + } + + // Open gzipped and destination files in binary mode + if (!$srcFile = gzopen($this->backupDir . '/' . $this->backupFile, 'rb')) { + return false; + } + if (!$dstFile = fopen($dest, 'wb')) { + return false; + } + + while (!gzeof($srcFile)) { + // Read buffer-size bytes + // Both fwrite and gzread are binary-safe + if(!fwrite($dstFile, gzread($srcFile, $bufferSize))) { + return false; + } + } + + fclose($dstFile); + gzclose($srcFile); + + // Return backup filename excluding backup directory + return str_replace($this->backupDir . '/', '', $dest); + } + + /** + * Prints message forcing output buffer flush + * + */ + public function obfPrint ($msg = '', $lineBreaksBefore = 0, $lineBreaksAfter = 1) { + if (!$msg) { + return false; + } + + $msg = date("Y-m-d H:i:s") . ' - ' . $msg; + $output = ''; + + if (php_sapi_name() != "cli") { + $lineBreak = "
"; + } else { + $lineBreak = "\n"; + } + + if ($lineBreaksBefore > 0) { + for ($i = 1; $i <= $lineBreaksBefore; $i++) { + $output .= $lineBreak; + } + } + + $output .= $msg; + + if ($lineBreaksAfter > 0) { + for ($i = 1; $i <= $lineBreaksAfter; $i++) { + $output .= $lineBreak; + } + } + + if (php_sapi_name() == "cli") { + $output .= "\n"; + } + + echo $output; + + if (php_sapi_name() != "cli") { + ob_flush(); + } + + flush(); + } +} diff --git a/plugins/settings/view/admin/backup.restore.html b/plugins/settings/view/admin/backup.restore.html new file mode 100644 index 000000000..7453c86bf --- /dev/null +++ b/plugins/settings/view/admin/backup.restore.html @@ -0,0 +1,93 @@ +
+
+
+
+

Backup Database

+
+
+
+{loop: $databases}
+    {$value.TABLE_NAME}
+{/loop} + =============================== + Total : {?=count($databases)?} tabel +
+
+ +
+
+
+
+
+

Restore Database

+
+
+

+ Silahkan pilih file database yang mau dihapus. Tindakan ini bersifat permanen. +

+ + {loop: $files} + {?=pathinfo($value)['basename']?}
+ {/loop} +
+ +
+
+
+ + + \ No newline at end of file From dabee007fce2fad7ee050c211aa471c7fc99bef5 Mon Sep 17 00:00:00 2001 From: Basoro Date: Thu, 26 Sep 2024 19:41:36 +0800 Subject: [PATCH 2/9] Update celah keamanan di modul anjungan --- plugins/anjungan/Admin.php | 180 +++++++++++++- plugins/anjungan/Site.php | 211 ++--------------- plugins/anjungan/view/admin/pemanggil.html | 223 ++++++++++++++++++ .../anjungan/view/display.antrian.loket.html | 118 --------- plugins/laporan_bpjs/Info.php | 5 +- themes/admin/index.html | 6 + 6 files changed, 424 insertions(+), 319 deletions(-) create mode 100644 plugins/anjungan/view/admin/pemanggil.html diff --git a/plugins/anjungan/Admin.php b/plugins/anjungan/Admin.php index f54843b79..1907b5788 100644 --- a/plugins/anjungan/Admin.php +++ b/plugins/anjungan/Admin.php @@ -11,6 +11,7 @@ public function navigation() return [ 'Kelola' => 'manage', 'Display' => 'index', + 'Pemanggil' => 'pemanggil', 'Pengaturan' => 'settings', ]; } @@ -19,7 +20,8 @@ public function getManage() { $sub_modules = [ ['name' => 'Display', 'url' => url([ADMIN, 'anjungan', 'index']), 'icon' => 'desktop', 'desc' => 'Display-Display Informasi Anjungan'], - ['name' => 'Pengaturan', 'url' => url([ADMIN, 'anjungan', 'settings']), 'icon' => 'desktop', 'desc' => 'Pengaturan Anjungan'], + ['name' => 'Pemanggil', 'url' => url([ADMIN, 'anjungan', 'pemanggil']), 'icon' => 'bullhorn', 'desc' => 'Pemanggil Antrian'], + ['name' => 'Pengaturan', 'url' => url([ADMIN, 'anjungan', 'settings']), 'icon' => 'gear', 'desc' => 'Pengaturan Anjungan'], ]; return $this->draw('manage.html', ['sub_modules' => $sub_modules]); } @@ -29,6 +31,182 @@ public function getIndex() return $this->draw('index.html'); } + public function getPemanggil() + { + $title = 'Display Antrian Loket'; + $logo = $this->settings->get('settings.logo'); + $display = ''; + + $_username = ''; + $__username = 'Tamu'; + if(isset($_SESSION['mlite_user'])) { + $_username = $this->core->getUserInfo('fullname', null, true); + $__username = $this->core->getUserInfo('username'); + } + $tanggal = getDayIndonesia(date('Y-m-d')).', '.dateIndonesia(date('Y-m-d')); + $username = !empty($_username) ? $_username : $__username; + + $show = isset($_GET['show']) ? $_GET['show'] : ""; + switch($show){ + default: + break; + case "panggil_loket": + $display = 'Panggil Loket'; + + $_username = ''; + $__username = 'Tamu'; + if(isset($_SESSION['mlite_user'])) { + $_username = $this->core->getUserInfo('fullname', null, true); + $__username = $this->core->getUserInfo('username'); + } + $tanggal = getDayIndonesia(date('Y-m-d')).', '.dateIndonesia(date('Y-m-d')); + $username = !empty($_username) ? $_username : $__username; + + $setting_antrian_loket = str_replace(",","','", $this->settings->get('anjungan.antrian_loket')); + $loket = explode(",", $this->settings->get('anjungan.antrian_loket')); + $namaloket = 'a'; + $panggil_loket = 'panggil_loket'; + $get_antrian = $this->db('mlite_antrian_loket')->select('noantrian')->where('type', 'Loket')->where('postdate', date('Y-m-d'))->desc('start_time')->oneArray(); + $noantrian = 0; + if(!empty($get_antrian['noantrian'])) { + $noantrian = $get_antrian['noantrian']; + } + + $antriloket = $this->settings->get('anjungan.panggil_loket_nomor'); + $tcounter = $antriloket; + $_tcounter = 1; + if(!empty($tcounter)) { + $_tcounter = $tcounter + 1; + } + if(isset($_GET['loket'])) { + $this->db('mlite_antrian_loket') + ->where('type', 'Loket') + ->where('noantrian', $tcounter) + ->where('postdate', date('Y-m-d')) + ->save(['end_time' => date('H:i:s')]); + $this->db('mlite_settings')->where('module', 'anjungan')->where('field', 'panggil_loket')->save(['value' => $_GET['loket']]); + $this->db('mlite_settings')->where('module', 'anjungan')->where('field', 'panggil_loket_nomor')->save(['value' => $_tcounter]); + } + if(isset($_GET['antrian'])) { + $this->db('mlite_settings')->where('module', 'anjungan')->where('field', 'panggil_loket')->save(['value' => $_GET['reset']]); + $this->db('mlite_settings')->where('module', 'anjungan')->where('field', 'panggil_loket_nomor')->save(['value' => $_GET['antrian']]); + } + if(isset($_GET['no_rkm_medis'])) { + $this->db('mlite_antrian_loket')->where('noantrian', $_GET['noantrian'])->where('postdate', date('Y-m-d'))->save(['no_rkm_medis' => $_GET['no_rkm_medis']]); + } + $hitung_antrian = $this->db('mlite_antrian_loket') + ->where('type', 'Loket') + ->like('postdate', date('Y-m-d')) + ->toArray(); + $counter = strlen($tcounter); + $xcounter = []; + for($i=0;$i<$counter;$i++){ + $xcounter[] = ''; + }; + + break; + case "panggil_cs": + $display = 'Panggil CS'; + $loket = explode(",", $this->settings->get('anjungan.antrian_cs')); + $namaloket = 'b'; + $panggil_loket = 'panggil_cs'; + $get_antrian = $this->db('mlite_antrian_loket')->select('noantrian')->where('type', 'CS')->where('postdate', date('Y-m-d'))->desc('start_time')->oneArray(); + $noantrian = 0; + if(!empty($get_antrian['noantrian'])) { + $noantrian = $get_antrian['noantrian']; + } + + $antriloket = $this->settings->get('anjungan.panggil_cs_nomor'); + $tcounter = $antriloket; + $_tcounter = 1; + if(!empty($tcounter)) { + $_tcounter = $tcounter + 1; + } + if(isset($_GET['loket'])) { + $this->db('mlite_antrian_loket') + ->where('type', 'CS') + ->where('noantrian', $tcounter) + ->where('postdate', date('Y-m-d')) + ->save(['end_time' => date('H:i:s')]); + $this->db('mlite_settings')->where('module', 'anjungan')->where('field', 'panggil_cs')->save(['value' => $_GET['loket']]); + $this->db('mlite_settings')->where('module', 'anjungan')->where('field', 'panggil_cs_nomor')->save(['value' => $_tcounter]); + } + if(isset($_GET['antrian'])) { + $this->db('mlite_settings')->where('module', 'anjungan')->where('field', 'panggil_cs')->save(['value' => $_GET['reset']]); + $this->db('mlite_settings')->where('module', 'anjungan')->where('field', 'panggil_cs_nomor')->save(['value' => $_GET['antrian']]); + } + $hitung_antrian = $this->db('mlite_antrian_loket') + ->where('type', 'CS') + ->like('postdate', date('Y-m-d')) + ->toArray(); + $counter = strlen($tcounter); + $xcounter = []; + for($i=0;$i<$counter;$i++){ + $xcounter[] = ''; + }; + + break; + case "panggil_apotek": + $display = 'Panggil Apotek'; + $loket = explode(",", $this->settings->get('anjungan.antrian_apotek')); + $namaloket = 'f'; + $panggil_loket = 'panggil_apotek'; + $get_antrian = $this->db('mlite_antrian_loket')->select('noantrian')->where('type', 'Apotek')->where('postdate', date('Y-m-d'))->desc('start_time')->oneArray(); + $noantrian = 0; + if(!empty($get_antrian['noantrian'])) { + $noantrian = $get_antrian['noantrian']; + } + + $antriloket = $this->settings->get('anjungan.panggil_apotek_nomor'); + $tcounter = $antriloket; + $_tcounter = 1; + if(!empty($tcounter)) { + $_tcounter = $tcounter + 1; + } + if(isset($_GET['loket'])) { + $this->db('mlite_antrian_loket') + ->where('type', 'Apotek') + ->where('noantrian', $tcounter) + ->where('postdate', date('Y-m-d')) + ->save(['end_time' => date('H:i:s')]); + $this->db('mlite_settings')->where('module', 'anjungan')->where('field', 'panggil_apotek')->save(['value' => $_GET['loket']]); + $this->db('mlite_settings')->where('module', 'anjungan')->where('field', 'panggil_apotek_nomor')->save(['value' => $_tcounter]); + } + if(isset($_GET['antrian'])) { + $this->db('mlite_settings')->where('module', 'anjungan')->where('field', 'panggil_apotek')->save(['value' => $_GET['reset']]); + $this->db('mlite_settings')->where('module', 'anjungan')->where('field', 'panggil_apotek_nomor')->save(['value' => $_GET['antrian']]); + } + $hitung_antrian = $this->db('mlite_antrian_loket') + ->where('type', 'Apotek') + ->like('postdate', date('Y-m-d')) + ->toArray(); + $counter = strlen($tcounter); + $xcounter = []; + for($i=0;$i<$counter;$i++){ + $xcounter[] = ''; + }; + + break; + } + + return $this->draw('pemanggil.html', [ + 'title' => $title, + 'logo' => $logo, + 'powered' => 'Powered by mLITE', + 'username' => $username, + 'tanggal' => $tanggal, + 'show' => isset_or($show), + 'loket' => isset_or($loket), + 'namaloket' => isset_or($namaloket), + 'panggil_loket' => isset_or($panggil_loket), + 'antrian' => isset_or($tcounter), + 'hitung_antrian' => isset_or($hitung_antrian), + 'xcounter' => isset_or($xcounter), + 'noantrian' =>isset_or($noantrian), + 'display' => $display + ]); + } + public function getSettings() { $this->assign['title'] = 'Pengaturan Modul Anjungan'; diff --git a/plugins/anjungan/Site.php b/plugins/anjungan/Site.php index 72f721d5e..44b62d5e9 100644 --- a/plugins/anjungan/Site.php +++ b/plugins/anjungan/Site.php @@ -33,6 +33,9 @@ public function routes() $this->route('anjungan/loket2', 'getDisplayAntrianLoket2'); $this->route('anjungan/poli', 'getDisplayAntrianPoli'); + $this->route('anjungan/panggil_loket', 'getAntrianPanggilLoket'); + + /* Sumbangan Mbak Kiki Sagira RS Bhayangkara Makassar */ $this->route('anjungan/display/poli/(:str)', 'getDisplayAntrianPoliSatu'); $this->route('anjungan/display/poli/(:str)/(:str)', 'getDisplayAntrianPoliDua'); @@ -1146,202 +1149,17 @@ public function getDisplayAntrianLoket() $tanggal = getDayIndonesia(date('Y-m-d')).', '.dateIndonesia(date('Y-m-d')); $username = !empty($_username) ? $_username : $__username; - $show = isset($_GET['show']) ? $_GET['show'] : ""; - switch($show){ - default: - $display = 'Depan'; - $content = $this->draw('display.antrian.loket.html', [ - 'title' => $title, - 'logo' => $logo, - 'powered' => 'Powered by mLITE', - 'username' => $username, - 'tanggal' => $tanggal, - 'show' => $show, - 'vidio' => $this->settings->get('anjungan.vidio'), - 'running_text' => $this->settings->get('anjungan.text_loket'), - 'display' => $display - ]); - break; - case "panggil_loket": - $display = 'Panggil Loket'; - - $_username = ''; - $__username = 'Tamu'; - if(isset($_SESSION['mlite_user'])) { - $_username = $this->core->getUserInfo('fullname', null, true); - $__username = $this->core->getUserInfo('username'); - } - $tanggal = getDayIndonesia(date('Y-m-d')).', '.dateIndonesia(date('Y-m-d')); - $username = !empty($_username) ? $_username : $__username; - - $setting_antrian_loket = str_replace(",","','", $this->settings->get('anjungan.antrian_loket')); - $loket = explode(",", $this->settings->get('anjungan.antrian_loket')); - $get_antrian = $this->db('mlite_antrian_loket')->select('noantrian')->where('type', 'Loket')->where('postdate', date('Y-m-d'))->desc('start_time')->oneArray(); - $noantrian = 0; - if(!empty($get_antrian['noantrian'])) { - $noantrian = $get_antrian['noantrian']; - } - - $antriloket = $this->settings->get('anjungan.panggil_loket_nomor'); - $tcounter = $antriloket; - $_tcounter = 1; - if(!empty($tcounter)) { - $_tcounter = $tcounter + 1; - } - if(isset($_GET['loket'])) { - $this->db('mlite_antrian_loket') - ->where('type', 'Loket') - ->where('noantrian', $tcounter) - ->where('postdate', date('Y-m-d')) - ->save(['end_time' => date('H:i:s')]); - $this->db('mlite_settings')->where('module', 'anjungan')->where('field', 'panggil_loket')->save(['value' => $_GET['loket']]); - $this->db('mlite_settings')->where('module', 'anjungan')->where('field', 'panggil_loket_nomor')->save(['value' => $_tcounter]); - } - if(isset($_GET['antrian'])) { - $this->db('mlite_settings')->where('module', 'anjungan')->where('field', 'panggil_loket')->save(['value' => $_GET['reset']]); - $this->db('mlite_settings')->where('module', 'anjungan')->where('field', 'panggil_loket_nomor')->save(['value' => $_GET['antrian']]); - } - if(isset($_GET['no_rkm_medis'])) { - $this->db('mlite_antrian_loket')->where('noantrian', $_GET['noantrian'])->where('postdate', date('Y-m-d'))->save(['no_rkm_medis' => $_GET['no_rkm_medis']]); - } - $hitung_antrian = $this->db('mlite_antrian_loket') - ->where('type', 'Loket') - ->like('postdate', date('Y-m-d')) - ->toArray(); - $counter = strlen($tcounter); - $xcounter = []; - for($i=0;$i<$counter;$i++){ - $xcounter[] = ''; - }; - - $content = $this->draw('display.antrian.loket.html', [ - 'title' => $title, - 'logo' => $logo, - 'powered' => 'Powered by mLITE', - 'username' => $username, - 'tanggal' => $tanggal, - 'show' => $show, - 'loket' => $loket, - 'namaloket' => 'a', - 'panggil_loket' => 'panggil_loket', - 'antrian' => $tcounter, - 'hitung_antrian' => $hitung_antrian, - 'xcounter' => $xcounter, - 'noantrian' =>$noantrian, - 'display' => $display - ]); - break; - case "panggil_cs": - $display = 'Panggil CS'; - $loket = explode(",", $this->settings->get('anjungan.antrian_cs')); - $get_antrian = $this->db('mlite_antrian_loket')->select('noantrian')->where('type', 'CS')->where('postdate', date('Y-m-d'))->desc('start_time')->oneArray(); - $noantrian = 0; - if(!empty($get_antrian['noantrian'])) { - $noantrian = $get_antrian['noantrian']; - } - - $antriloket = $this->settings->get('anjungan.panggil_cs_nomor'); - $tcounter = $antriloket; - $_tcounter = 1; - if(!empty($tcounter)) { - $_tcounter = $tcounter + 1; - } - if(isset($_GET['loket'])) { - $this->db('mlite_antrian_loket') - ->where('type', 'CS') - ->where('noantrian', $tcounter) - ->where('postdate', date('Y-m-d')) - ->save(['end_time' => date('H:i:s')]); - $this->db('mlite_settings')->where('module', 'anjungan')->where('field', 'panggil_cs')->save(['value' => $_GET['loket']]); - $this->db('mlite_settings')->where('module', 'anjungan')->where('field', 'panggil_cs_nomor')->save(['value' => $_tcounter]); - } - if(isset($_GET['antrian'])) { - $this->db('mlite_settings')->where('module', 'anjungan')->where('field', 'panggil_cs')->save(['value' => $_GET['reset']]); - $this->db('mlite_settings')->where('module', 'anjungan')->where('field', 'panggil_cs_nomor')->save(['value' => $_GET['antrian']]); - } - $hitung_antrian = $this->db('mlite_antrian_loket') - ->where('type', 'CS') - ->like('postdate', date('Y-m-d')) - ->toArray(); - $counter = strlen($tcounter); - $xcounter = []; - for($i=0;$i<$counter;$i++){ - $xcounter[] = ''; - }; - - $content = $this->draw('display.antrian.loket.html', [ - 'title' => $title, - 'logo' => $logo, - 'powered' => 'Powered by mLITE', - 'username' => $username, - 'tanggal' => $tanggal, - 'show' => $show, - 'loket' => $loket, - 'namaloket' => 'b', - 'panggil_loket' => 'panggil_cs', - 'antrian' => $tcounter, - 'hitung_antrian' => $hitung_antrian, - 'xcounter' => $xcounter, - 'noantrian' =>$noantrian, - 'display' => $display - ]); - break; - case "panggil_apotek": - $display = 'Panggil Apotek'; - $loket = explode(",", $this->settings->get('anjungan.antrian_apotek')); - $get_antrian = $this->db('mlite_antrian_loket')->select('noantrian')->where('type', 'Apotek')->where('postdate', date('Y-m-d'))->desc('start_time')->oneArray(); - $noantrian = 0; - if(!empty($get_antrian['noantrian'])) { - $noantrian = $get_antrian['noantrian']; - } + $content = $this->draw('display.antrian.loket.html', [ + 'title' => $title, + 'logo' => $logo, + 'powered' => 'Powered by mLITE', + 'username' => $username, + 'tanggal' => $tanggal, + 'vidio' => $this->settings->get('anjungan.vidio'), + 'running_text' => $this->settings->get('anjungan.text_loket'), + 'display' => $display + ]); - $antriloket = $this->settings->get('anjungan.panggil_apotek_nomor'); - $tcounter = $antriloket; - $_tcounter = 1; - if(!empty($tcounter)) { - $_tcounter = $tcounter + 1; - } - if(isset($_GET['loket'])) { - $this->db('mlite_antrian_loket') - ->where('type', 'Apotek') - ->where('noantrian', $tcounter) - ->where('postdate', date('Y-m-d')) - ->save(['end_time' => date('H:i:s')]); - $this->db('mlite_settings')->where('module', 'anjungan')->where('field', 'panggil_apotek')->save(['value' => $_GET['loket']]); - $this->db('mlite_settings')->where('module', 'anjungan')->where('field', 'panggil_apotek_nomor')->save(['value' => $_tcounter]); - } - if(isset($_GET['antrian'])) { - $this->db('mlite_settings')->where('module', 'anjungan')->where('field', 'panggil_apotek')->save(['value' => $_GET['reset']]); - $this->db('mlite_settings')->where('module', 'anjungan')->where('field', 'panggil_apotek_nomor')->save(['value' => $_GET['antrian']]); - } - $hitung_antrian = $this->db('mlite_antrian_loket') - ->where('type', 'Apotek') - ->like('postdate', date('Y-m-d')) - ->toArray(); - $counter = strlen($tcounter); - $xcounter = []; - for($i=0;$i<$counter;$i++){ - $xcounter[] = ''; - }; - - $content = $this->draw('display.antrian.loket.html', [ - 'title' => $title, - 'logo' => $logo, - 'powered' => 'Powered by mLITE', - 'username' => $username, - 'tanggal' => $tanggal, - 'show' => $show, - 'loket' => $loket, - 'namaloket' => 'f', - 'panggil_loket' => 'panggil_apotek', - 'antrian' => $tcounter, - 'hitung_antrian' => $hitung_antrian, - 'xcounter' => $xcounter, - 'noantrian' =>$noantrian, - 'display' => $display - ]); - break; - } $assign = [ 'title' => $this->settings->get('settings.nama_instansi'), @@ -1353,7 +1171,6 @@ public function getDisplayAntrianLoket() $this->tpl->set('page', ['title' => $assign['title'], 'desc' => $assign['desc'], 'content' => $assign['content']]); - //exit(); } public function getDisplayAntrianLoket2() @@ -2326,7 +2143,7 @@ public function getAjax() $_POST['umurdaftar'] = $umur; $_POST['sttsumur'] = $sttsumur; $_POST['status_lanjut'] = 'Ralan'; - //$_POST['kd_pj'] = $this->settings->get('anjungan.carabayar_umum'); + $_POST['kd_pj'] = $this->settings->get('anjungan.carabayar_umum'); $_POST['status_bayar'] = 'Belum Bayar'; $_POST['no_rawat'] = $this->core->setNoRawat($date); $_POST['jam_reg'] = date('H:i:s'); diff --git a/plugins/anjungan/view/admin/pemanggil.html b/plugins/anjungan/view/admin/pemanggil.html new file mode 100644 index 000000000..6dd957557 --- /dev/null +++ b/plugins/anjungan/view/admin/pemanggil.html @@ -0,0 +1,223 @@ + + + +
+ + + + {if: $show} +
+
+
+ {loop: $loket} +
+
+
+
Loket {$value}
+
+
{?=strtoupper($namaloket)?}{$antrian}
+
+ +
+
+
+ {/loop} +
+
+
+
+
+ + + +
+
+
+ + + + +
+
+
+
+
+ {/if} + +
+
    +
  • Klik tombol 1x untuk memanggil antrian selanjutnya
  • +
  • Klik tombol 1x untuk memanggil ulang antrian
  • +
  • Untuk menyesuaikan urutan, masukkan nomor urut pada kolom lompat dan klik tombol panggil 1x
  • +
  • Angka di Sebelah Kiri Tombol Pemanggil Menunjukan Jumlah Nomor Antrian Yang Telah diambil Pasien
  • +
+
+
{$powered}
+ diff --git a/plugins/anjungan/view/display.antrian.loket.html b/plugins/anjungan/view/display.antrian.loket.html index dbc56830b..71b708294 100644 --- a/plugins/anjungan/view/display.antrian.loket.html +++ b/plugins/anjungan/view/display.antrian.loket.html @@ -92,7 +92,6 @@
- {if: !$show}

Antrian Loket {$settings.nama_instansi}

@@ -163,70 +162,6 @@

Pemanggil Antrian Loket

-
-
-
- {loop: $loket} -
-
-
-
Loket {$value}
-
-
{?=strtoupper($namaloket)?}{$antrian}
-
- -
-
-
- {/loop} -
-
-
-
-
- - -
-
-
- - - - -
-
-
-
-
- -
-
    -
  • Klik tombol 1x untuk memanggil antrian selanjutnya
  • -
  • Klik tombol 1x untuk memanggil ulang antrian
  • -
  • Untuk menyesuaikan urutan, masukkan nomor urut pada kolom lompat dan klik tombol panggil 1x
  • -
  • Angka di Sebelah Kiri Tombol Pemanggil Menunjukan Jumlah Nomor Antrian Yang Telah diambil Pasien
  • -
-
- {/if}