Files
jabali-panel/app/Filament/Jabali/Pages/PhpSettings.php
2026-02-02 03:11:45 +02:00

323 lines
12 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Filament\Jabali\Pages;
use App\Services\Agent\AgentClient;
use BackedEnum;
use Filament\Actions\Action;
use Filament\Actions\Concerns\InteractsWithActions;
use Filament\Actions\Contracts\HasActions;
use Filament\Forms\Components\Select;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Filament\Schemas\Components\Grid;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Schema;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Support\Facades\Auth;
class PhpSettings extends Page implements HasActions, HasForms
{
use InteractsWithActions;
use InteractsWithForms;
protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-cog-6-tooth';
protected static ?int $navigationSort = 5;
public static function getNavigationLabel(): string
{
return __('PHP Settings');
}
public function getTitle(): string|Htmlable
{
return __('PHP Settings');
}
protected static ?string $slug = 'php-settings';
protected string $view = 'filament.jabali.pages.php-settings';
public array $domains = [];
public ?string $selectedDomain = null;
public array $phpVersions = [];
// PHP Settings form data
public ?array $data = [];
protected ?AgentClient $agent = null;
protected function getAgent(): AgentClient
{
if ($this->agent === null) {
$this->agent = new AgentClient;
}
return $this->agent;
}
protected function getUsername(): string
{
return Auth::user()->username ?? Auth::user()->name ?? 'unknown';
}
public function mount(): void
{
$this->loadDomains();
$this->loadPhpVersions();
if (! empty($this->domains)) {
$this->selectedDomain = $this->domains[0]['domain'] ?? null;
$this->loadSettings();
}
$this->form->fill($this->data);
}
protected function loadDomains(): void
{
$result = $this->getAgent()->send('domain.list', [
'username' => $this->getUsername(),
]);
$this->domains = ($result['success'] ?? false) ? ($result['domains'] ?? []) : [];
}
protected function loadPhpVersions(): void
{
$result = $this->getAgent()->send('php.list_versions', []);
$this->phpVersions = [];
if ($result['success'] ?? false) {
foreach ($result['versions'] ?? [] as $v) {
$version = $v['version'] ?? $v;
$this->phpVersions[$version] = "PHP $version";
}
}
if (empty($this->phpVersions)) {
$this->phpVersions = ['8.4' => 'PHP 8.4'];
}
}
public function selectDomain(string $domain): void
{
$this->selectedDomain = $domain;
$this->loadSettings();
$this->form->fill($this->data);
}
public function loadSettings(): void
{
if (! $this->selectedDomain) {
return;
}
$result = $this->getAgent()->send('php.getSettings', [
'domain' => $this->selectedDomain,
'username' => $this->getUsername(),
]);
if ($result['success'] ?? false) {
$settings = $result['settings'] ?? [];
$this->data = [
'php_version' => $settings['php_version'] ?? array_key_first($this->phpVersions),
'memory_limit' => $settings['memory_limit'] ?? '256M',
'upload_max_filesize' => $settings['upload_max_filesize'] ?? '64M',
'post_max_size' => $settings['post_max_size'] ?? '64M',
'max_input_vars' => $settings['max_input_vars'] ?? '3000',
'max_execution_time' => $settings['max_execution_time'] ?? '300',
'max_input_time' => $settings['max_input_time'] ?? '300',
];
} else {
$this->data = [
'php_version' => array_key_first($this->phpVersions),
'memory_limit' => '256M',
'upload_max_filesize' => '64M',
'post_max_size' => '64M',
'max_input_vars' => '3000',
'max_execution_time' => '300',
'max_input_time' => '300',
];
}
}
public function form(Schema $form): Schema
{
return $form
->schema([
Section::make(__('PHP Version'))
->description(__('Choose which PHP version to use for this domain.'))
->icon('heroicon-o-code-bracket')
->schema([
Select::make('php_version')
->label(__('PHP Version'))
->options($this->phpVersions)
->required()
->helperText(__('Recommended: Use the latest stable PHP version for best security and performance.')),
]),
Section::make(__('Resource Limits'))
->description(__('Configure memory and upload limits for your PHP applications.'))
->icon('heroicon-o-cpu-chip')
->schema([
Grid::make(2)
->schema([
Select::make('memory_limit')
->label(__('Memory Limit'))
->options([
'64M' => '64 MB',
'128M' => '128 MB',
'256M' => '256 MB',
'512M' => '512 MB',
'1024M' => '1024 MB',
'2048M' => '2048 MB',
])
->required()
->helperText(__('Maximum memory a script can allocate.')),
Select::make('upload_max_filesize')
->label(__('Upload Max Filesize'))
->options([
'2M' => '2 MB',
'8M' => '8 MB',
'16M' => '16 MB',
'32M' => '32 MB',
'64M' => '64 MB',
'128M' => '128 MB',
'256M' => '256 MB',
'512M' => '512 MB',
])
->required()
->helperText(__('Maximum size of uploaded files.')),
Select::make('post_max_size')
->label(__('Post Max Size'))
->options([
'8M' => '8 MB',
'16M' => '16 MB',
'32M' => '32 MB',
'64M' => '64 MB',
'128M' => '128 MB',
'256M' => '256 MB',
'512M' => '512 MB',
])
->required()
->helperText(__('Maximum size of POST data.')),
Select::make('max_input_vars')
->label(__('Max Input Vars'))
->options([
'1000' => '1,000',
'2000' => '2,000',
'3000' => '3,000',
'5000' => '5,000',
'10000' => '10,000',
])
->required()
->helperText(__('Maximum number of input variables.')),
]),
]),
Section::make(__('Execution Limits'))
->description(__('Set maximum execution and input processing time for PHP scripts.'))
->icon('heroicon-o-clock')
->schema([
Grid::make(2)
->schema([
Select::make('max_execution_time')
->label(__('Max Execution Time'))
->options([
'30' => '30 '.__('seconds'),
'60' => '60 '.__('seconds'),
'120' => '120 '.__('seconds'),
'300' => '300 '.__('seconds'),
'600' => '600 '.__('seconds'),
'900' => '900 '.__('seconds'),
])
->required()
->helperText(__('Maximum time a script can run.')),
Select::make('max_input_time')
->label(__('Max Input Time'))
->options([
'60' => '60 '.__('seconds'),
'120' => '120 '.__('seconds'),
'300' => '300 '.__('seconds'),
'600' => '600 '.__('seconds'),
'900' => '900 '.__('seconds'),
])
->required()
->helperText(__('Maximum time for parsing input data.')),
]),
]),
])
->statePath('data');
}
protected function getHeaderActions(): array
{
return [
$this->saveSettingsAction(),
];
}
protected function saveSettingsAction(): Action
{
return Action::make('saveSettings')
->label(__('Save Changes'))
->icon('heroicon-o-check')
->color('success')
->requiresConfirmation()
->modalHeading(__('Save PHP Settings'))
->modalDescription(__('This will update PHP settings for :domain. PHP-FPM will be reloaded to apply changes.', ['domain' => $this->selectedDomain ?? '']))
->modalIcon('heroicon-o-cog-6-tooth')
->modalIconColor('warning')
->modalSubmitActionLabel(__('Save & Reload PHP'))
->visible(fn () => $this->selectedDomain !== null)
->action(function (): void {
$this->save();
});
}
public function save(): void
{
$formData = $this->form->getState();
$result = $this->getAgent()->send('php.setSettings', [
'domain' => $this->selectedDomain,
'username' => $this->getUsername(),
'settings' => [
'php_version' => $formData['php_version'],
'memory_limit' => $formData['memory_limit'],
'upload_max_filesize' => $formData['upload_max_filesize'],
'post_max_size' => $formData['post_max_size'],
'max_input_vars' => $formData['max_input_vars'],
'max_execution_time' => $formData['max_execution_time'],
'max_input_time' => $formData['max_input_time'],
],
]);
if ($result['success'] ?? false) {
Notification::make()
->title(__('PHP settings saved'))
->body(__('PHP-FPM has been reloaded to apply your changes.'))
->success()
->send();
} else {
Notification::make()
->title(__('Failed to save settings'))
->body($result['error'] ?? __('Unknown error'))
->danger()
->send();
}
}
}