106 lines
5.5 KiB
PHP
106 lines
5.5 KiB
PHP
<?php
|
|
// Output buffering must be active before the first byte of HTML below, so that
|
|
// header() calls made later in the page still work — notably the
|
|
// not-logged-in redirect in include_topbar.php, which runs *after* this file
|
|
// has already emitted <!DOCTYPE html>. Without a buffer that redirect depends
|
|
// entirely on php.ini's output_buffering: it is on for the dev stack but off
|
|
// in production, where every protected page answered 200 with a half-rendered
|
|
// body instead of sending the browser to the login form. session.php starts a
|
|
// buffer for the same reason.
|
|
if (ob_get_level() === 0) {
|
|
ob_start();
|
|
}
|
|
|
|
// Never render PHP notices/warnings into the page: they leak absolute server
|
|
// paths to anonymous visitors and corrupt the markup. Errors still reach the
|
|
// server log. This mirrors the policy db_auth.php already applies to the JSON
|
|
// API routes, and keeps the app safe even where php.ini has display_errors on.
|
|
ini_set('display_errors', '0');
|
|
ini_set('log_errors', '1');
|
|
|
|
// Apply the configured application timezone. Pages that only require config.php
|
|
// (no dbconn.php) still call date() for default values such as "today", so they
|
|
// need this too or they render a UTC date.
|
|
require_once __DIR__ . '/assets/utils/timezone.php';
|
|
|
|
// Security headers (CSP, nosniff, framing, referrer) — emitted before any HTML output.
|
|
require_once __DIR__ . '/assets/utils/page_headers.php';
|
|
send_page_security_headers();
|
|
|
|
// Self-hosted libraries (assets/vendor/, exact versions in assets/vendor/VERSIONS.json):
|
|
// the app no longer depends on third-party CDNs being up or unchanged.
|
|
$vendor_url = $server_url . 'assets/vendor/';
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<title>BRN WMS</title>
|
|
<meta name="csrf-token" content="<?= htmlspecialchars($_SESSION['csrf_token'] ?? '') ?>">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<link rel="apple-touch-icon" sizes="180x180" href="<?php echo $server_url?>assets/images/favicon.png">
|
|
<link rel="icon" type="image/png" sizes="32x32" href="<?php echo $server_url?>assets/images/favicon32.png">
|
|
<link rel="icon" type="image/png" sizes="16x16" href="<?php echo $server_url?>assets/images/favicon32.png">
|
|
<link rel="manifest" href="<?php echo $server_url?>assets/site.webmanifest">
|
|
|
|
<!-- jquery -->
|
|
<script src="<?php echo $vendor_url?>jquery/3.7.1/jquery.min.js"></script>
|
|
|
|
<!-- popper (must be before bootstrap) -->
|
|
<script src="<?php echo $vendor_url?>popper/2.11.8/popper.min.js"></script>
|
|
|
|
<!-- bootstrap -->
|
|
<script src="<?php echo $vendor_url?>bootstrap/5.3.8/bootstrap.min.js"></script>
|
|
<!-- Disable the standalone Bootstrap's dropdown toggle — main.js bundles Bootstrap+Popper and
|
|
handles dropdown events. This copy stays for window.bootstrap (Modal API). -->
|
|
<script>bootstrap.Dropdown.prototype.toggle = function() {};</script>
|
|
|
|
<!-- bootbox -->
|
|
<script src="<?php echo $vendor_url?>bootbox/4.4.0/bootbox.min.js"></script>
|
|
|
|
<!-- overlay loader -->
|
|
<script src="<?php echo $vendor_url?>loadingoverlay/2.1.7/loadingoverlay.min.js"></script>
|
|
|
|
<!-- bootstrap css -->
|
|
<link href="<?php echo $vendor_url?>bootstrap/5.3.8/bootstrap.min.css" rel="stylesheet">
|
|
|
|
<!-- flatpickr date (custom.js initialises .flatpickr inputs on load, so not deferred) -->
|
|
<link rel="stylesheet" href="<?php echo $vendor_url?>flatpickr/4.6.13/flatpickr.min.css">
|
|
<script src="<?php echo $vendor_url?>flatpickr/4.6.13/flatpickr.min.js"></script>
|
|
|
|
<!-- flatpickr monthSelect plugin -->
|
|
<link rel="stylesheet" href="<?php echo $vendor_url?>flatpickr/4.6.13/plugins/monthSelect/style.css">
|
|
<script src="<?php echo $vendor_url?>flatpickr/4.6.13/plugins/monthSelect/index.js"></script>
|
|
|
|
<!-- autocomplete -->
|
|
<link rel="stylesheet" href="<?php echo $vendor_url?>jquery-ui/1.14.1/jquery-ui.css">
|
|
<script src="<?php echo $vendor_url?>jquery-ui/1.14.1/jquery-ui.min.js"></script>
|
|
|
|
<!-- alasql (only called from functions that run after load) -->
|
|
<script defer src="<?php echo $vendor_url?>alasql/4.6.6/alasql.min.js"></script>
|
|
|
|
<!-- dropzone -->
|
|
<script src="<?php echo $vendor_url?>dropzone/5.9.3/dropzone.min.js"></script>
|
|
<script>
|
|
// Turn off Dropzone's auto-scanner so it doesn't conflict with main.js
|
|
Dropzone.autoDiscover = false;
|
|
</script>
|
|
|
|
<!-- apexcharts (only called from functions that run after load) -->
|
|
<script defer src="<?php echo $vendor_url?>apexcharts/7.5.1/apexcharts.min.js"></script>
|
|
|
|
<!-- theme script -->
|
|
<link rel="stylesheet" href="<?php echo $server_url?>assets/css/main.css?v=<?php echo @filemtime(__DIR__ . '/assets/css/main.css'); ?>">
|
|
<script type="module" src="<?php echo $server_url?>assets/js/main.js?v=<?php echo @filemtime(__DIR__ . '/assets/js/main.js'); ?>"></script>
|
|
<link rel="stylesheet" href="<?php echo $server_url?>assets/css/custom.css?v=<?php echo @filemtime(__DIR__ . '/assets/css/custom.css'); ?>">
|
|
<script src="<?php echo $server_url?>assets/js/ajax_core.js?v=<?php echo @filemtime(__DIR__ . '/assets/js/ajax_core.js'); ?>"></script>
|
|
<script src="<?php echo $server_url?>assets/js/custom.js?v=<?php echo @filemtime(__DIR__ . '/assets/js/custom.js'); ?>"></script>
|
|
<script src="<?php echo $server_url?>assets/js/batch_overlay.js?v=<?php echo @filemtime(__DIR__ . '/assets/js/batch_overlay.js'); ?>"></script>
|
|
|
|
<!-- camera scanner library, loaded lazily by scanner.js when the camera opens -->
|
|
<script defer src="<?php echo $vendor_url?>html5-qrcode/2.3.8/html5-qrcode.min.js"></script>
|
|
<script src="<?php echo $server_url?>assets/js/scanner.js"></script>
|
|
|
|
</head>
|