Store: enforce configurable timezone for store timestamps
This commit is contained in:
@@ -19,6 +19,7 @@ class StoreController
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->applyStoreTimezone();
|
||||
$this->view = new View(__DIR__ . '/views');
|
||||
}
|
||||
|
||||
@@ -171,6 +172,8 @@ class StoreController
|
||||
$expiryDays = max(1, (int)$expiryDaysRaw);
|
||||
$orderPrefixRaw = array_key_exists('store_order_prefix', $_POST) ? (string)$_POST['store_order_prefix'] : (string)($current['store_order_prefix'] ?? 'AC-ORD');
|
||||
$orderPrefix = $this->sanitizeOrderPrefix($orderPrefixRaw);
|
||||
$timezoneRaw = array_key_exists('store_timezone', $_POST) ? (string)$_POST['store_timezone'] : (string)($current['store_timezone'] ?? 'UTC');
|
||||
$timezone = $this->normalizeTimezone($timezoneRaw);
|
||||
$testMode = array_key_exists('store_test_mode', $_POST) ? ((string)$_POST['store_test_mode'] === '1' ? '1' : '0') : (string)($current['store_test_mode'] ?? '1');
|
||||
$stripeEnabled = array_key_exists('store_stripe_enabled', $_POST) ? ((string)$_POST['store_stripe_enabled'] === '1' ? '1' : '0') : (string)($current['store_stripe_enabled'] ?? '0');
|
||||
$stripePublic = trim((string)(array_key_exists('store_stripe_public_key', $_POST) ? $_POST['store_stripe_public_key'] : ($current['store_stripe_public_key'] ?? '')));
|
||||
@@ -201,6 +204,7 @@ class StoreController
|
||||
Settings::set('store_download_limit', (string)$downloadLimit);
|
||||
Settings::set('store_download_expiry_days', (string)$expiryDays);
|
||||
Settings::set('store_order_prefix', $orderPrefix);
|
||||
Settings::set('store_timezone', $timezone);
|
||||
Settings::set('store_test_mode', $testMode);
|
||||
Settings::set('store_stripe_enabled', $stripeEnabled);
|
||||
Settings::set('store_stripe_public_key', $stripePublic);
|
||||
@@ -2257,6 +2261,7 @@ class StoreController
|
||||
'store_download_limit' => Settings::get('store_download_limit', '5'),
|
||||
'store_download_expiry_days' => Settings::get('store_download_expiry_days', '30'),
|
||||
'store_order_prefix' => Settings::get('store_order_prefix', 'AC-ORD'),
|
||||
'store_timezone' => Settings::get('store_timezone', 'UTC'),
|
||||
'store_test_mode' => Settings::get('store_test_mode', '1'),
|
||||
'store_stripe_enabled' => Settings::get('store_stripe_enabled', '0'),
|
||||
'store_stripe_public_key' => Settings::get('store_stripe_public_key', ''),
|
||||
@@ -2276,6 +2281,39 @@ class StoreController
|
||||
];
|
||||
}
|
||||
|
||||
private function normalizeTimezone(string $timezone): string
|
||||
{
|
||||
$timezone = trim($timezone);
|
||||
if ($timezone === '') {
|
||||
return 'UTC';
|
||||
}
|
||||
return in_array($timezone, \DateTimeZone::listIdentifiers(), true) ? $timezone : 'UTC';
|
||||
}
|
||||
|
||||
private function applyStoreTimezone(): void
|
||||
{
|
||||
$timezone = $this->normalizeTimezone((string)Settings::get('store_timezone', 'UTC'));
|
||||
@date_default_timezone_set($timezone);
|
||||
|
||||
$db = Database::get();
|
||||
if (!($db instanceof PDO)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$tz = new \DateTimeZone($timezone);
|
||||
$now = new \DateTimeImmutable('now', $tz);
|
||||
$offset = $tz->getOffset($now);
|
||||
$sign = $offset < 0 ? '-' : '+';
|
||||
$offset = abs($offset);
|
||||
$hours = str_pad((string)intdiv($offset, 3600), 2, '0', STR_PAD_LEFT);
|
||||
$mins = str_pad((string)intdiv($offset % 3600, 60), 2, '0', STR_PAD_LEFT);
|
||||
$dbTz = $sign . $hours . ':' . $mins;
|
||||
$db->exec("SET time_zone = '" . $dbTz . "'");
|
||||
} catch (Throwable $e) {
|
||||
}
|
||||
}
|
||||
|
||||
private function ensureSalesChartSchema(): void
|
||||
{
|
||||
$db = Database::get();
|
||||
|
||||
@@ -67,9 +67,25 @@ ob_start();
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="label" style="margin-top:12px;">Order Number Prefix</div>
|
||||
<input class="input" name="store_order_prefix" value="<?= htmlspecialchars((string)($settings['store_order_prefix'] ?? 'AC-ORD'), ENT_QUOTES, 'UTF-8') ?>" placeholder="AC-ORD">
|
||||
</div>
|
||||
<div class="label" style="margin-top:12px;">Order Number Prefix</div>
|
||||
<input class="input" name="store_order_prefix" value="<?= htmlspecialchars((string)($settings['store_order_prefix'] ?? 'AC-ORD'), ENT_QUOTES, 'UTF-8') ?>" placeholder="AC-ORD">
|
||||
|
||||
<div class="label" style="margin-top:12px;">Store Timezone</div>
|
||||
<input class="input" name="store_timezone" list="store-timezone-options" value="<?= htmlspecialchars((string)($settings['store_timezone'] ?? 'UTC'), ENT_QUOTES, 'UTF-8') ?>" placeholder="UTC">
|
||||
<datalist id="store-timezone-options">
|
||||
<option value="UTC"></option>
|
||||
<option value="Europe/London"></option>
|
||||
<option value="Europe/Berlin"></option>
|
||||
<option value="America/New_York"></option>
|
||||
<option value="America/Chicago"></option>
|
||||
<option value="America/Los_Angeles"></option>
|
||||
<option value="Australia/Sydney"></option>
|
||||
<option value="Asia/Tokyo"></option>
|
||||
</datalist>
|
||||
<div style="margin-top:8px; font-size:12px; color:var(--muted);">
|
||||
Used for order numbers, store timestamps, and expiry calculations. Invalid values fall back to UTC.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display:flex; justify-content:flex-end;">
|
||||
<button class="btn" type="submit">Save General Settings</button>
|
||||
|
||||
Reference in New Issue
Block a user