151 lines
5.0 KiB
PHP
151 lines
5.0 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Symfony\Component\Process\Process;
|
|
|
|
class SystemStatusController extends Controller
|
|
{
|
|
public function __invoke(Request $request): JsonResponse
|
|
{
|
|
$user = $request->user();
|
|
if (!$user || !$user->roles()->where('name', 'ROLE_ADMIN')->exists()) {
|
|
return response()->json(['message' => 'Forbidden'], 403);
|
|
}
|
|
|
|
$phpDefaultPath = $this->resolveBinary('php');
|
|
$phpSelectedPath = PHP_BINARY ?: $phpDefaultPath;
|
|
$phpSelectedOk = (bool) $phpSelectedPath;
|
|
$phpSelectedVersion = PHP_VERSION;
|
|
$minVersions = $this->resolveMinVersions();
|
|
$composerPath = $this->resolveBinary('composer');
|
|
$nodePath = $this->resolveBinary('node');
|
|
$npmPath = $this->resolveBinary('npm');
|
|
$tarPath = $this->resolveBinary('tar');
|
|
$rsyncPath = $this->resolveBinary('rsync');
|
|
$procFunctions = [
|
|
'proc_open',
|
|
'proc_get_status',
|
|
'proc_close',
|
|
];
|
|
$disabledFunctions = array_filter(array_map('trim', explode(',', (string) ini_get('disable_functions'))));
|
|
$disabledLookup = array_fill_keys($disabledFunctions, true);
|
|
$procFunctionStatus = [];
|
|
foreach ($procFunctions as $function) {
|
|
$procFunctionStatus[$function] = function_exists($function) && !isset($disabledLookup[$function]);
|
|
}
|
|
|
|
return response()->json([
|
|
'php' => PHP_VERSION,
|
|
'php_default' => $phpDefaultPath,
|
|
'php_selected_path' => $phpSelectedPath,
|
|
'php_selected_ok' => $phpSelectedOk,
|
|
'php_selected_version' => $phpSelectedVersion,
|
|
'min_versions' => $minVersions,
|
|
'composer' => $composerPath,
|
|
'composer_version' => $this->resolveBinaryVersion($composerPath, ['--version']),
|
|
'node' => $nodePath,
|
|
'node_version' => $this->resolveBinaryVersion($nodePath, ['--version']),
|
|
'npm' => $npmPath,
|
|
'npm_version' => $this->resolveBinaryVersion($npmPath, ['--version']),
|
|
'tar' => $tarPath,
|
|
'tar_version' => $this->resolveBinaryVersion($tarPath, ['--version']),
|
|
'rsync' => $rsyncPath,
|
|
'rsync_version' => $this->resolveBinaryVersion($rsyncPath, ['--version']),
|
|
'proc_functions' => $procFunctionStatus,
|
|
'storage_writable' => is_writable(storage_path()),
|
|
'updates_writable' => is_writable(storage_path('app/updates')) || @mkdir(storage_path('app/updates'), 0755, true),
|
|
]);
|
|
}
|
|
|
|
private function resolveBinary(string $name): ?string
|
|
{
|
|
$process = new Process(['sh', '-lc', "command -v {$name}"]);
|
|
$process->setTimeout(5);
|
|
$process->run();
|
|
|
|
if (!$process->isSuccessful()) {
|
|
return null;
|
|
}
|
|
|
|
$output = trim($process->getOutput());
|
|
return $output !== '' ? $output : null;
|
|
}
|
|
|
|
private function resolvePhpVersion(string $path): ?string
|
|
{
|
|
$process = new Process([$path, '-r', 'echo PHP_VERSION;']);
|
|
$process->setTimeout(5);
|
|
$process->run();
|
|
|
|
if (!$process->isSuccessful()) {
|
|
return null;
|
|
}
|
|
|
|
$output = trim($process->getOutput());
|
|
return $output !== '' ? $output : null;
|
|
}
|
|
|
|
private function resolveBinaryVersion(?string $path, array $args): ?string
|
|
{
|
|
if (!$path) {
|
|
return null;
|
|
}
|
|
|
|
$process = new Process(array_merge([$path], $args));
|
|
$process->setTimeout(5);
|
|
$process->run();
|
|
|
|
if (!$process->isSuccessful()) {
|
|
return null;
|
|
}
|
|
|
|
$output = trim($process->getOutput());
|
|
if ($output === '') {
|
|
return null;
|
|
}
|
|
|
|
$line = strtok($output, "\n") ?: $output;
|
|
if (preg_match('/(\\d+\\.\\d+(?:\\.\\d+)?)/', $line, $matches)) {
|
|
return $matches[1];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private function resolveMinVersions(): array
|
|
{
|
|
$composerJson = $this->readJson(base_path('composer.json'));
|
|
$packageJson = $this->readJson(base_path('package.json'));
|
|
|
|
$php = $composerJson['require']['php'] ?? null;
|
|
$node = $packageJson['engines']['node'] ?? null;
|
|
$npm = $packageJson['engines']['npm'] ?? null;
|
|
$composer = $composerJson['require']['composer-runtime-api'] ?? null;
|
|
|
|
return [
|
|
'php' => is_string($php) ? $php : null,
|
|
'node' => is_string($node) ? $node : null,
|
|
'npm' => is_string($npm) ? $npm : null,
|
|
'composer' => is_string($composer) ? $composer : null,
|
|
];
|
|
}
|
|
|
|
private function readJson(string $path): array
|
|
{
|
|
if (!is_file($path)) {
|
|
return [];
|
|
}
|
|
|
|
$contents = file_get_contents($path);
|
|
if ($contents === false) {
|
|
return [];
|
|
}
|
|
|
|
$data = json_decode($contents, true);
|
|
return is_array($data) ? $data : [];
|
|
}
|
|
}
|