- Split single-page into 3 pages: - index.php: product catalog with VM size cards - create.php: order form (name, domain, description) - requests.php: request history with pagination - Rewrite NetBox integration to create Virtual Machines (/virtualization/virtual-machines/) instead of DCIM devices - Add netbox_integration/netbox_api.php: NetBoxClient with createVirtualMachine(), findCluster(), findTag(), getList() - Generate new sleek product-card images (420x280) with aligned spec boxes (vcpus/ram/disk) - Add webshop CSS: product cards, nav links, hero section, order layout, responsive grid - Update redirects: send.php -> requests.php, cancel.php -> requests.php - Update E2E test for new page structure - Add .gitignore, deploy-local.sh, setup_database.sql to repo
90 lines
2.0 KiB
PHP
Executable File
90 lines
2.0 KiB
PHP
Executable File
<?php
|
|
declare(strict_types=1);
|
|
|
|
$localConfig = __DIR__ . '/config.local.php';
|
|
$config = is_readable($localConfig) ? require $localConfig : [];
|
|
|
|
$dbConfig = [
|
|
'host' => $config['db_host'] ?? getenv('PHPSITE_DB_HOST') ?: '127.0.0.1',
|
|
'name' => $config['db_name'] ?? getenv('PHPSITE_DB_NAME') ?: 'phpsite',
|
|
'user' => $config['db_user'] ?? getenv('PHPSITE_DB_USER') ?: 'phpsite_app',
|
|
'pass' => $config['db_pass'] ?? getenv('PHPSITE_DB_PASS') ?: '',
|
|
];
|
|
|
|
// Include NetBox integration
|
|
require_once __DIR__ . '/netbox_integration/config.php';
|
|
|
|
function db(): PDO
|
|
{
|
|
static $pdo = null;
|
|
global $dbConfig;
|
|
|
|
if ($pdo instanceof PDO) {
|
|
return $pdo;
|
|
}
|
|
|
|
$dsn = sprintf(
|
|
'mysql:host=%s;dbname=%s;charset=utf8mb4',
|
|
$dbConfig['host'],
|
|
$dbConfig['name']
|
|
);
|
|
|
|
$pdo = new PDO($dsn, $dbConfig['user'], $dbConfig['pass'], [
|
|
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
|
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
|
PDO::ATTR_EMULATE_PREPARES => false,
|
|
]);
|
|
|
|
return $pdo;
|
|
}
|
|
|
|
function start_app_session(): void
|
|
{
|
|
if (session_status() === PHP_SESSION_ACTIVE) {
|
|
return;
|
|
}
|
|
|
|
session_set_cookie_params([
|
|
'lifetime' => 0,
|
|
'path' => '/',
|
|
'httponly' => true,
|
|
'samesite' => 'Lax',
|
|
]);
|
|
session_start();
|
|
}
|
|
|
|
function h(?string $value): string
|
|
{
|
|
return htmlspecialchars($value ?? '', ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
|
|
}
|
|
|
|
function require_login(): void
|
|
{
|
|
start_app_session();
|
|
|
|
if (empty($_SESSION['loggedin']) || $_SESSION['loggedin'] !== true) {
|
|
header('Location: /login.php');
|
|
exit;
|
|
}
|
|
}
|
|
|
|
function csrf_token(): string
|
|
{
|
|
start_app_session();
|
|
|
|
if (empty($_SESSION['csrf_token'])) {
|
|
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
|
}
|
|
|
|
return $_SESSION['csrf_token'];
|
|
}
|
|
|
|
function verify_csrf(?string $token): bool
|
|
{
|
|
start_app_session();
|
|
|
|
return is_string($token)
|
|
&& isset($_SESSION['csrf_token'])
|
|
&& hash_equals($_SESSION['csrf_token'], $token);
|
|
}
|