129 lines
2.7 KiB
PHP
129 lines
2.7 KiB
PHP
<?php
|
|
require_once __DIR__ . '/db.php';
|
|
|
|
function getCurrentUser() {
|
|
if (!isset($_SESSION['user_id'])) {
|
|
return null;
|
|
}
|
|
|
|
return [
|
|
'id' => $_SESSION['user_id'],
|
|
'username' => $_SESSION['username'],
|
|
'role' => $_SESSION['role'],
|
|
];
|
|
}
|
|
|
|
function isAdmin() {
|
|
$user = getCurrentUser();
|
|
return $user && $user['role'] === 'admin';
|
|
}
|
|
|
|
function requireLogin($action) {
|
|
$publicActions = ['login'];
|
|
if (!in_array($action, $publicActions, true) && !isset($_SESSION['user_id'])) {
|
|
header('Location: ?action=login');
|
|
exit;
|
|
}
|
|
}
|
|
|
|
// ---------- Misc helpers ----------
|
|
|
|
function generatePassword($length = 16) {
|
|
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*';
|
|
$pass = '';
|
|
$max = strlen($chars) - 1;
|
|
for ($i = 0; $i < $length; $i++) {
|
|
$pass .= $chars[random_int(0, $max)];
|
|
}
|
|
return $pass;
|
|
}
|
|
|
|
// ---------- CLI Helpers ----------
|
|
|
|
function stripAnsi($str) {
|
|
// Remove ANSI escape sequences like \e[94m ... \e[0m
|
|
return preg_replace('/\x1B\[[0-9;]*[A-Za-z]/', '', $str);
|
|
}
|
|
|
|
function runCommand($cmd, &$output = null, &$status = null) {
|
|
$output = [];
|
|
exec($cmd . ' 2>&1', $output, $status);
|
|
|
|
// Strip ANSI codes from each line
|
|
foreach ($output as &$line) {
|
|
$line = stripAnsi($line);
|
|
}
|
|
|
|
return $status === 0;
|
|
}
|
|
|
|
function runCommandStreaming($cmd, callable $onLine) {
|
|
$descriptorspec = [
|
|
0 => ['pipe', 'r'], // stdin
|
|
1 => ['pipe', 'w'], // stdout
|
|
2 => ['pipe', 'w'], // stderr
|
|
];
|
|
|
|
$process = proc_open($cmd . ' 2>&1', $descriptorspec, $pipes);
|
|
|
|
if (!is_resource($process)) {
|
|
return [false, ['Failed to start process']];
|
|
}
|
|
|
|
// We don't need stdin
|
|
fclose($pipes[0]);
|
|
|
|
stream_set_blocking($pipes[1], false);
|
|
stream_set_blocking($pipes[2], false);
|
|
|
|
$allLines = [];
|
|
|
|
while (true) {
|
|
$status = proc_get_status($process);
|
|
|
|
$out = fgets($pipes[1]);
|
|
$err = fgets($pipes[2]);
|
|
|
|
foreach ([$out, $err] as $chunk) {
|
|
if ($chunk !== false && $chunk !== '') {
|
|
$chunk = stripAnsi($chunk);
|
|
$lines = preg_split("/\r\n|\n|\r/", $chunk);
|
|
foreach ($lines as $line) {
|
|
if ($line === '') {
|
|
continue;
|
|
}
|
|
$allLines[] = $line;
|
|
$onLine($line);
|
|
}
|
|
|
|
@ob_flush();
|
|
@flush();
|
|
}
|
|
}
|
|
|
|
if (!$status['running']) {
|
|
break;
|
|
}
|
|
|
|
usleep(50000); // 50ms
|
|
}
|
|
|
|
fclose($pipes[1]);
|
|
fclose($pipes[2]);
|
|
|
|
$exitCode = proc_close($process);
|
|
return [$exitCode === 0, $allLines];
|
|
}
|
|
|
|
function sanitizeDomain($domain) {
|
|
$domain = trim($domain);
|
|
if ($domain === '') {
|
|
return null;
|
|
}
|
|
// Allow letters, numbers, dots, and dashes
|
|
if (!preg_match('/^[a-zA-Z0-9.-]+$/', $domain)) {
|
|
return null;
|
|
}
|
|
return $domain;
|
|
}
|