diff --git a/.gitignore b/.gitignore index 993527f..84dee80 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,6 @@ Thumbs.db # Logs *.log + +# Portable XAMPP Lite deployment stack (third-party; not versioned here) +xampp_lite_8_5/ diff --git a/install/README.md b/install/README.md new file mode 100644 index 0000000..b3c3b29 --- /dev/null +++ b/install/README.md @@ -0,0 +1,59 @@ +# Deploying PQS on XAMPP Lite 8.5 (on-demand) + +PQS is designed to run from a **portable XAMPP Lite 8.5** stack (PHP 8.5 + +MariaDB + Apache) so the whole system can be stood up on demand at a venue with +no internet. This folder holds the one-shot database installer. + +## Steps + +1. **Drop the app into htdocs.** Copy the PQS folder to: + ``` + xampp\htdocs\pqs + ``` + (The app uses `/pqs/...` URLs, so the folder must be named `pqs`.) + +2. **Start Apache and MySQL** from the XAMPP control panel. + +3. **Create the database.** From `xampp\mysql\bin` (XAMPP's MariaDB root has no + password by default): + ``` + mysql -u root < ..\..\htdocs\pqs\install\pqs_install.sql + ``` + Or in phpMyAdmin (http://localhost/phpmyadmin) → Import → choose + `install\pqs_install.sql`. + + This creates the `pqs` database, the `pqs`/`pqs` application user, every + table (all InnoDB), and the static seed data (mechs, maps, game types, + default game config, pod layout). Queue/mission/history start empty. It is + safe to re-run; to wipe clean, `DROP DATABASE pqs` first. + +4. **Open the app:** + | Screen | URL | + |--------|-----| + | Registration kiosk | http://localhost/pqs/callsign.php | + | Registration console | http://localhost/pqs/registration.php | + | Game/ops console | http://localhost/pqs/console.php | + | Queue wall | http://localhost/pqs/combinedqueue.php | + +That's it — no build step, no internet. + +## Notes + +- **Credentials.** The app connects as `pqs`/`pqs` on `localhost` (see + `includes/db.php`). These are a formality on an air-gapped LAN. +- **Timezone.** Set once in `includes/db.php` (`PQS_TIMEZONE`, default + `America/Chicago`). Change it there. +- **PHP target.** Code targets PHP 7.4+; XAMPP Lite 8.5 ships PHP 8.5. Tested on + PHP 8.3 / MariaDB (see `dev/`). +- **`time.php` (optional clock sync).** Sets the machine clock from the browser + for the air-gapped box. On Windows it uses PowerShell `Set-Date`, which only + works if Apache is **running as administrator**. If the host clock is already + correct you don't need this. + +## Fresh install vs. upgrading an existing DB + +- **Fresh XAMPP deploy →** use `install/pqs_install.sql` (this folder). It + already creates every table as InnoDB, so no migrations are needed. +- **Upgrading a pre-existing (older MyISAM) database →** run the incremental + `dev/migrations/001-*.sql` and `002-*.sql` instead, which convert the affected + tables to InnoDB in place. diff --git a/install/pqs_install.sql b/install/pqs_install.sql new file mode 100644 index 0000000..013797b --- /dev/null +++ b/install/pqs_install.sql @@ -0,0 +1,377 @@ +-- ===================================================================== +-- PQS on-demand installer (XAMPP Lite 8.5 / MariaDB) +-- ===================================================================== +-- Fresh install: run once as a privileged user. XAMPP's MariaDB root has +-- no password by default, so from xampp\mysql\bin: +-- +-- mysql -u root < install\pqs_install.sql +-- +-- Creates the `pqs` database, the pqs/pqs application user, every table +-- (all InnoDB) and the static seed data (mechs, maps, game types, default +-- game config and pod layout). The queue/mission/history tables start empty. +-- +-- Re-running is safe: it uses IF NOT EXISTS and will not clobber existing +-- data. To wipe and start clean, DROP DATABASE pqs first. +-- ===================================================================== + +CREATE DATABASE IF NOT EXISTS `pqs` CHARACTER SET latin1; +CREATE USER IF NOT EXISTS 'pqs'@'localhost' IDENTIFIED BY 'pqs'; +GRANT ALL PRIVILEGES ON `pqs`.* TO 'pqs'@'localhost'; +FLUSH PRIVILEGES; +USE `pqs`; + +-- phpMyAdmin SQL Dump +-- version 3.4.11.1deb2+deb7u5 +-- http://www.phpmyadmin.net +-- +-- Host: localhost +-- Generation Time: Feb 19, 2017 at 12:21 AM +-- Server version: 5.5.50 +-- PHP Version: 5.4.45-0+deb7u4 + +SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; +SET time_zone = "+00:00"; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; + +-- +-- Database: `pqs` +-- + +-- -------------------------------------------------------- + +-- +-- Table structure for table `pqs_currentmission` +-- + +CREATE TABLE IF NOT EXISTS `pqs_currentmission` ( + `Callsign` varchar(25) DEFAULT NULL, + `MissionID` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `pqs_gameconfig` +-- + +CREATE TABLE IF NOT EXISTS `pqs_gameconfig` ( + `gamechoiceid` int(11) DEFAULT NULL, + `numpods` int(11) DEFAULT NULL, + `timepergame` int(11) DEFAULT NULL, + `timetoreset` int(11) DEFAULT NULL, + `mapid` int(11) NOT NULL, + `typeid` int(11) NOT NULL, + `launchdelay` int(11) NOT NULL, + `visibility` int(11) NOT NULL, + `weather` int(11) NOT NULL, + `timeofday` int(11) NOT NULL, + `timelimit` int(11) NOT NULL, + `radar` int(11) NOT NULL, + `heat` tinyint(1) NOT NULL, + `friendlyfire` tinyint(1) NOT NULL, + `splashdamage` tinyint(1) NOT NULL, + `limitedammo` tinyint(1) NOT NULL, + `noreturn` tinyint(1) NOT NULL, + `printdebriefing` tinyint(1) NOT NULL, + `missionreview` tinyint(1) NOT NULL, + `weaponjam` tinyint(1) NOT NULL, + `advancemode` tinyint(1) NOT NULL, + `armormode` tinyint(1) NOT NULL, + `cameraship` int(2) NOT NULL, + `GroupAvalible` tinyint(1) NOT NULL, + UNIQUE KEY `gamechoiceid` (`gamechoiceid`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `pqs_gameconfig` +-- + +INSERT INTO `pqs_gameconfig` (`gamechoiceid`, `numpods`, `timepergame`, `timetoreset`, `mapid`, `typeid`, `launchdelay`, `visibility`, `weather`, `timeofday`, `timelimit`, `radar`, `heat`, `friendlyfire`, `splashdamage`, `limitedammo`, `noreturn`, `printdebriefing`, `missionreview`, `weaponjam`, `advancemode`, `armormode`, `cameraship`, `GroupAvalible`) VALUES +(1, 6, 10, 5, -1, 3, 5, 1, 1, 1, 10, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 2, 0); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `pqs_gametype` +-- + +CREATE TABLE IF NOT EXISTS `pqs_gametype` ( + `TypeID` int(11) NOT NULL AUTO_INCREMENT, + `TypeName` varchar(22) NOT NULL, + `roster` int(11) NOT NULL, + PRIMARY KEY (`TypeID`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=11 ; + +-- +-- Dumping data for table `pqs_gametype` +-- + +INSERT INTO `pqs_gametype` (`TypeID`, `TypeName`, `roster`) VALUES +(1, 'Destruction', -2), +(2, 'Team Destruction', -1), +(3, 'Attrition', 0), +(4, 'Team Attrition', 1), +(5, 'Capture the Flag', 2), +(6, 'King of the Hill', 3), +(7, 'Team King of the Hill', 4), +(8, 'Steal the Beacon', 5), +(9, 'Master Trial', 6), +(10, 'Siege Assault', 7); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `pqs_infopanel` +-- + +CREATE TABLE IF NOT EXISTS `pqs_infopanel` ( + `Updated` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `pqs_infopanel` +-- + +INSERT INTO `pqs_infopanel` (`Updated`) VALUES +(0); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `pqs_mapinfo` +-- + +CREATE TABLE IF NOT EXISTS `pqs_mapinfo` ( + `MapID` int(11) NOT NULL, + `MapName` varchar(25) NOT NULL, + `D` tinyint(1) NOT NULL, + `TD` tinyint(1) NOT NULL, + `A` tinyint(1) NOT NULL, + `TA` tinyint(1) NOT NULL, + `CTF` tinyint(1) NOT NULL, + `KOTH` tinyint(1) NOT NULL, + `TKOTH` tinyint(1) NOT NULL, + `STB` tinyint(1) NOT NULL, + `MT` tinyint(1) NOT NULL, + `SA` tinyint(1) NOT NULL, + `size` int(11) NOT NULL, + `DZ` int(11) NOT NULL, + `HE` int(11) NOT NULL, + `MRB` int(11) NOT NULL, + UNIQUE KEY `MapID` (`MapID`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `pqs_mapinfo` +-- + +INSERT INTO `pqs_mapinfo` (`MapID`, `MapName`, `D`, `TD`, `A`, `TA`, `CTF`, `KOTH`, `TKOTH`, `STB`, `MT`, `SA`, `size`, `DZ`, `HE`, `MRB`) VALUES +(-1, 'Random', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +(1, 'BigCity', 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 4, 4, 0, 0), +(2, 'Cantina', 2, 2, 2, 2, 2, 0, 0, 0, 0, 1, 3, 4, 0, 1), +(3, 'CentralPark', 3, 3, 3, 3, 0, 1, 1, 1, 1, 0, 4, 4, 0, 0), +(4, 'Coliseum', 4, 4, 4, 4, 3, 0, 0, 0, 0, 0, 2, 4, 0, 1), +(5, 'DustBowl', 5, 5, 5, 5, 0, 2, 2, 0, 0, 0, 4, 4, 0, 0), +(6, 'Factory', 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0), +(7, 'Frostbite', 7, 7, 7, 7, 4, 3, 3, 2, 0, 0, 4, 4, 0, 0), +(8, 'Freezer', 8, 8, 8, 8, 0, 4, 4, 0, 2, 0, 4, 4, 0, 0), +(9, 'GatorBait', 9, 9, 9, 9, 0, 5, 5, 3, 3, 0, 4, 4, 0, 0), +(10, 'GhostHighway', 10, 10, 10, 10, 0, 6, 6, 4, 4, 0, 4, 4, 0, 0), +(11, 'Grassland', 11, 11, 11, 11, 5, 7, 0, 0, 5, 0, 4, 4, 0, 0), +(12, 'Hidaway', 12, 12, 12, 12, 6, 8, 7, 5, 0, 0, 4, 2, 0, 1), +(13, 'Hotplate', 13, 13, 13, 13, 7, 0, 0, 0, 6, 0, 4, 4, 0, 0), +(14, 'InnerCity', 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0), +(15, 'Jungle', 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0), +(16, 'Lunacy', 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0), +(17, 'Nazca', 17, 17, 17, 17, 8, 9, 8, 0, 7, 0, 4, 4, 0, 0), +(18, 'PalaceGates', 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 3, 2, 0, 0), +(19, 'Peaks', 19, 19, 19, 19, 9, 0, 0, 0, 8, 0, 4, 4, 0, 0), +(20, 'Reduex', 20, 20, 20, 20, 10, 0, 0, 0, 0, 2, 3, 4, 0, 1), +(21, 'ScarabStronghold', 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0), +(22, 'SnowJob', 22, 22, 22, 22, 0, 0, 0, 0, 0, 0, 4, 2, 0, 0), +(23, 'StormCanyon', 23, 23, 23, 23, 11, 0, 0, 0, 0, 3, 3, 4, 0, 1), +(24, 'Timberline', 24, 24, 24, 24, 12, 0, 0, 0, 0, 0, 4, 4, 0, 0), +(25, 'TribelIncursion', 25, 25, 25, 25, 0, 0, 0, 0, 0, 0, 3, 3, 0, 1); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `pqs_mechinfo` +-- + +CREATE TABLE IF NOT EXISTS `pqs_mechinfo` ( + `MechID` int(11) NOT NULL AUTO_INCREMENT, + `MechName` varchar(25) NOT NULL, + `Firepower` int(11) NOT NULL, + `Armor` int(11) NOT NULL, + `Speed` int(11) NOT NULL, + `Heat` int(11) NOT NULL, + `Class` varchar(25) NOT NULL, + `img_name` varchar(25) NOT NULL, + `Tons` int(11) NOT NULL, + `roster` int(11) NOT NULL, + PRIMARY KEY (`MechID`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=64 ; + +-- +-- Dumping data for table `pqs_mechinfo` +-- + +INSERT INTO `pqs_mechinfo` (`MechID`, `MechName`, `Firepower`, `Armor`, `Speed`, `Heat`, `Class`, `img_name`, `Tons`, `roster`) VALUES +(1, 'Brigand', 25, 28, 85, 74, 'Light', 'brigand.jpg', 25, 17), +(2, 'Commando', 27, 34, 85, 100, 'Light', 'commando.jpg', 25, 22), +(3, 'Osiris', 22, 34, 83, 93, 'Light', 'osiris.jpg', 30, 46), +(4, 'Uller', 35, 31, 89, 89, 'Light', 'uller.jpg', 30, 58), +(5, 'Cougar', 37, 40, 81, 83, 'Light', 'cougar.jpg', 35, 23), +(6, 'Owens', 43, 39, 80, 71, 'Light', 'owens.jpg', 35, 47), +(7, 'Puma', 57, 38, 82, 89, 'Light', 'puma.jpg', 35, 48), +(8, 'Raven', 35, 35, 77, 76, 'Light', 'raven.jpg', 35, 49), +(9, 'Wolfhound IIC', 28, 39, 72, 80, 'Light', 'wolfhound.jpg', 35, 64), +(10, 'Arctic Wolf', 47, 45, 73, 80, 'Medium', 'arcticwolf.jpg', 40, 3), +(11, 'Chimera', 47, 46, 73, 59, 'Medium', 'chimera.jpg', 40, 21), +(12, 'Hollander II', 45, 48, 75, 61, 'Medium', 'hollanderii.jpg', 45, 36), +(13, 'Shadowcat', 51, 48, 73, 74, 'Medium', 'shadowcat.jpg', 45, 52), +(14, 'Hellhound', 47, 54, 67, 59, 'Medium', 'hellhound.jpg', 50, 33), +(15, 'Hunchback', 38, 52, 64, 63, 'Medium', 'hunchback.jpg', 50, 37), +(16, 'Uziel', 43, 50, 69, 60, 'Medium', 'uziel.jpg', 50, 60), +(17, 'Black Lanner', 50, 56, 67, 56, 'Medium', 'blacklanner.jpg', 55, 16), +(18, 'Bushwacker', 45, 58, 70, 56, 'Medium', 'bushwacker.jpg', 55, 18), +(19, 'Ryoken', 55, 58, 70, 56, 'Medium', 'ryoken.jpg', 55, 51), +(20, 'Dragon', 43, 60, 63, 55, 'Heavy', 'dragon.jpg', 60, 27), +(21, 'Vulture', 59, 63, 63, 52, 'Heavy', 'vulture.jpg', 60, 62), +(22, 'Catapult', 70, 60, 65, 42, 'Heavy', 'catapult.jpg', 65, 19), +(23, 'Cauldronborn', 65, 60, 61, 70, 'Heavy', 'cauldronborn.jpg', 65, 20), +(24, 'Loki', 48, 64, 57, 77, 'Heavy', 'loki.jpg', 65, 39), +(25, 'Grizzly', 55, 67, 54, 61, 'Heavy', 'grizzly.jpg', 70, 31), +(26, 'Novacat', 51, 65, 59, 50, 'Heavy', 'novacat.jpg', 70, 45), +(27, 'Thor', 58, 67, 50, 71, 'Heavy', 'thor.jpg', 70, 57), +(28, 'Black Knight', 61, 65, 55, 50, 'Heavy', 'blackknight.jpg', 75, 15), +(29, 'Mad Cat', 58, 70, 58, 56, 'Heavy', 'madcat.jpg', 75, 41), +(30, 'Thanatos', 63, 66, 48, 51, 'Heavy', 'thanatos.jpg', 75, 56), +(31, 'Awesome', 57, 74, 47, 58, 'Assault', 'awesome.jpg', 80, 9), +(32, 'Zeus', 80, 71, 49, 60, 'Assault', 'zeus.jpg', 80, 65), +(33, 'Deimos', 80, 71, 49, 60, 'Assault', 'deimos.jpg', 85, 26), +(34, 'Masakari', 66, 78, 49, 69, 'Assault', 'masakari.jpg', 85, 43), +(35, 'Templar', 68, 77, 49, 60, 'Assault', 'templar.jpg', 85, 55), +(36, 'Cyclops', 72, 78, 46, 50, 'Assault', 'cyclops.jpg', 90, 24), +(37, 'Highlander', 73, 79, 42, 55, 'Assault', 'highlander.jpg', 90, 35), +(38, 'Madcat Mk II', 93, 78, 46, 56, 'Assault', 'madcatii.jpg', 90, 42), +(39, 'Mauler', 95, 78, 41, 50, 'Assault', 'mauler.jpg', 90, 44), +(40, 'Hauptmann IIC', 86, 84, 35, 51, 'Assault', 'hauptmann.jpg', 95, 32), +(41, 'Atlas', 95, 99, 38, 50, 'Assault', 'atlas.jpg', 100, 7), +(42, 'Daishi', 78, 91, 36, 57, 'Assault', 'daishi.jpg', 100, 25), +(43, 'Flea', 0, 0, 0, 0, 'Light', 'bdicon.jpg', 20, 29), +(44, 'Solitare', 0, 0, 0, 0, 'Light', 'bdicon.jpg', 25, 53), +(45, 'Assassin II', 0, 0, 0, 0, 'Medium', 'bdicon.jpg', 45, 6), +(46, 'Hellspawn', 0, 0, 0, 0, 'Medium', 'bdicon.jpg', 45, 34), +(47, 'Black Hawk', 0, 0, 0, 0, 'Medium', 'bdicon.jpg', 50, 14), +(48, 'Ares', 0, 0, 0, 0, 'Heavy', 'bdicon.jpg', 60, 4), +(49, 'Argus', 0, 0, 0, 0, 'Heavy', 'bdicon.jpg', 60, 5), +(50, 'Avatar', 0, 0, 0, 0, 'Heavy', 'bdicon.jpg', 70, 8), +(51, 'Longbow', 0, 0, 0, 0, 'Assault', 'bdicon.jpg', 85, 40), +(52, 'Victor', 0, 0, 0, 0, 'Assault', 'bdicon.jpg', 85, 61), +(53, 'Sunder', 0, 0, 0, 0, 'Assault', 'bdicon.jpg', 90, 54), +(54, 'Gladiator', 0, 0, 0, 0, 'Assault', 'bdicon.jpg', 95, 30), +(55, 'Annihilator', 0, 0, 0, 0, 'Assault', 'bdicon.jpg', 100, 1), +(56, 'Behemoth', 0, 0, 0, 0, 'Assault', 'bdicon.jpg', 100, 12), +(57, 'Fafnir', 0, 0, 0, 0, 'Assault', 'bdicon.jpg', 100, 28), +(58, 'Kodiak', 0, 0, 0, 0, 'Assault', 'bdicon.jpg', 100, 38), +(59, 'Random Any', 0, 0, 0, 0, 'Random', 'bdicon.jpg', 0, 0), +(60, 'Random Light', 0, 0, 0, 0, 'Random', 'bdicon.jpg', 20, -1), +(61, 'Random Medium', 0, 0, 0, 0, 'Random', 'bdicon.jpg', 40, -2), +(62, 'Random Heavy', 0, 0, 0, 0, 'Random', 'bdicon.jpg', 60, -3), +(63, 'Random Assault', 0, 0, 0, 0, 'Random', 'bdicon.jpg', 80, -4); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `pqs_mission` +-- + +CREATE TABLE IF NOT EXISTS `pqs_mission` ( + `MissionID` int(11) NOT NULL AUTO_INCREMENT, + `MissionDate` int(11) NOT NULL, + `MissionSize` int(11) NOT NULL, + `numplayers` int(11) DEFAULT NULL, + `Completed` tinyint(1) NOT NULL DEFAULT '0', + `nummercs` int(11) NOT NULL, + `locked` tinyint(1) NOT NULL DEFAULT '0', + `MissionTime` int(11) NOT NULL, + `GameType` int(11) NOT NULL DEFAULT '3', + `map` int(11) NOT NULL DEFAULT '21', + UNIQUE KEY `MatchID` (`MissionID`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `pqs_pastmissions` +-- + +CREATE TABLE IF NOT EXISTS `pqs_pastmissions` ( + `Callsign` varchar(25) DEFAULT NULL, + `Mech` varchar(25) DEFAULT NULL, + `Missionid` int(11) DEFAULT NULL, + `ctime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `pqs_pods` +-- + +CREATE TABLE IF NOT EXISTS `pqs_pods` ( + `pod01` tinyint(1) NOT NULL, + `pod02` tinyint(1) NOT NULL, + `pod03` tinyint(1) NOT NULL, + `pod04` tinyint(1) NOT NULL, + `pod05` tinyint(1) NOT NULL, + `pod06` tinyint(1) NOT NULL, + `pod07` tinyint(1) NOT NULL, + `pod08` tinyint(1) NOT NULL, + `pod09` tinyint(1) NOT NULL, + `pod10` tinyint(1) NOT NULL, + `pod11` tinyint(1) NOT NULL, + `pod12` tinyint(1) NOT NULL, + `pod13` tinyint(1) NOT NULL, + `pod14` tinyint(1) NOT NULL, + `pod15` tinyint(1) NOT NULL, + `pod16` tinyint(1) NOT NULL, + `ID` tinyint(1) NOT NULL, + UNIQUE KEY `ID` (`ID`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `pqs_pods` +-- + +INSERT INTO `pqs_pods` (`pod01`, `pod02`, `pod03`, `pod04`, `pod05`, `pod06`, `pod07`, `pod08`, `pod09`, `pod10`, `pod11`, `pod12`, `pod13`, `pod14`, `pod15`, `pod16`, `ID`) VALUES +(1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `pqs_queue` +-- + +CREATE TABLE IF NOT EXISTS `pqs_queue` ( + `CallSign` varchar(25) NOT NULL, + `Mech` varchar(25) NOT NULL, + `ID` int(11) NOT NULL AUTO_INCREMENT, + `MissionID` int(11) DEFAULT NULL, + `Merc` tinyint(1) NOT NULL DEFAULT '0', + `Updated` tinyint(1) NOT NULL DEFAULT '0', + `team` int(2) NOT NULL DEFAULT '0', + `unit` int(2) NOT NULL DEFAULT '0', + UNIQUE KEY `ID` (`ID`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; + +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/time.php b/time.php index 151ccbb..5a35a46 100644 --- a/time.php +++ b/time.php @@ -6,13 +6,19 @@ if (isset($_GET['submit'])) {$submit=$_GET['submit'];}else{$submit='';} if ($submit=='update'){ + // Set the machine clock from the browser's time (air-gapped box has no NTP). + // $epoch is round(intval(...)) so it is a pure integer -- no shell injection. + $epoch = (int) round(((int)($_GET['lct'] ?? 0)) / 1000); - $settime = $_GET['lct']; - $settime2 = round($settime/1000); - $settime3 = "@".$settime2; - -echo exec("sudo date -s $settime3 > /dev/null &"); -}; + if (stripos(PHP_OS, 'WIN') === 0) { + // Windows / XAMPP: requires Apache (httpd) to be running as administrator. + $ps = 'Set-Date -Date ([DateTimeOffset]::FromUnixTimeSeconds(' . $epoch . ').LocalDateTime)'; + exec('powershell -NoProfile -Command "' . $ps . '"'); + } else { + // Linux: requires the web user to have passwordless sudo for date. + exec('sudo date -s @' . $epoch . ' > /dev/null &'); + } +} ?>