feat: implement Nginx configuration management, PHP environment initialization, and extension management UI
This commit is contained in:
@@ -14,8 +14,8 @@ expose_php = On
|
|||||||
max_execution_time = 300
|
max_execution_time = 300
|
||||||
max_input_time = 120
|
max_input_time = 120
|
||||||
memory_limit = 512M
|
memory_limit = 512M
|
||||||
error_reporting = E_ALL
|
error_reporting = {{ERROR_REPORTING}}
|
||||||
display_errors = On
|
display_errors = {{DISPLAY_ERRORS}}
|
||||||
display_startup_errors = On
|
display_startup_errors = On
|
||||||
log_errors = On
|
log_errors = On
|
||||||
log_errors_max_len = 1024
|
log_errors_max_len = 1024
|
||||||
|
|||||||
+19
-19
@@ -194,15 +194,27 @@ export function registerIpcHandlers(): void {
|
|||||||
|
|
||||||
// --- 1. Get extensions from local php.ini ---
|
// --- 1. Get extensions from local php.ini ---
|
||||||
let extensionsList = ''
|
let extensionsList = ''
|
||||||
|
let errorReporting = 'E_ALL'
|
||||||
|
let displayErrors = 'On'
|
||||||
|
|
||||||
const localIniPath = path.join(phpDir, 'php.ini')
|
const localIniPath = path.join(phpDir, 'php.ini')
|
||||||
const mustHaves = ['curl', 'mbstring', 'openssl', 'mysqli', 'pdo_mysql', 'gd', 'fileinfo', 'exif', 'intl', 'bz2', 'gettext', 'soap', 'xsl']
|
const mustHaves = ['curl', 'mbstring', 'openssl', 'mysqli', 'pdo_mysql', 'gd', 'fileinfo', 'exif', 'intl', 'bz2', 'gettext', 'soap', 'xsl']
|
||||||
|
|
||||||
if (fs.existsSync(localIniPath)) {
|
if (fs.existsSync(localIniPath)) {
|
||||||
const localIniContent = fs.readFileSync(localIniPath, 'utf8')
|
const localIniContent = fs.readFileSync(localIniPath, 'utf8')
|
||||||
|
|
||||||
|
// 1. Get extensions
|
||||||
const extMatches = localIniContent.match(/^\s*extension\s*=.*$/gm)
|
const extMatches = localIniContent.match(/^\s*extension\s*=.*$/gm)
|
||||||
if (extMatches) {
|
if (extMatches) {
|
||||||
extensionsList = extMatches.join('\n')
|
extensionsList = extMatches.join('\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2. Get error settings
|
||||||
|
const erMatch = localIniContent.match(/^\s*error_reporting\s*=\s*(.+)$/m)
|
||||||
|
if (erMatch) errorReporting = erMatch[1].trim()
|
||||||
|
|
||||||
|
const deMatch = localIniContent.match(/^\s*display_errors\s*=\s*(.+)$/m)
|
||||||
|
if (deMatch) displayErrors = deMatch[1].trim()
|
||||||
} else {
|
} else {
|
||||||
// Fallback formatting based on version
|
// Fallback formatting based on version
|
||||||
const prefix = (phpVersion?.startsWith('5.') || phpVersion?.startsWith('7.')) ? 'php_' : ''
|
const prefix = (phpVersion?.startsWith('5.') || phpVersion?.startsWith('7.')) ? 'php_' : ''
|
||||||
@@ -215,7 +227,9 @@ export function registerIpcHandlers(): void {
|
|||||||
GD_EXT: gdExtName,
|
GD_EXT: gdExtName,
|
||||||
SESSION_DIR: sessionDir,
|
SESSION_DIR: sessionDir,
|
||||||
TEMP_DIR: tempDir,
|
TEMP_DIR: tempDir,
|
||||||
EXTENSIONS: extensionsList
|
EXTENSIONS: extensionsList,
|
||||||
|
ERROR_REPORTING: errorReporting,
|
||||||
|
DISPLAY_ERRORS: displayErrors
|
||||||
})
|
})
|
||||||
|
|
||||||
// Add a small delay to ensure previous instance (if any) is fully killed
|
// Add a small delay to ensure previous instance (if any) is fully killed
|
||||||
@@ -374,23 +388,10 @@ export function registerIpcHandlers(): void {
|
|||||||
ipcMain.handle('php:extensions:toggle', async (_event, { version, extName, enabled }) => {
|
ipcMain.handle('php:extensions:toggle', async (_event, { version, extName, enabled }) => {
|
||||||
const result = await phpManagerService.toggleExtension(version, extName, enabled)
|
const result = await phpManagerService.toggleExtension(version, extName, enabled)
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
// Automatically restart the PHP service if it's running
|
|
||||||
const serviceName = `php:${version}`
|
const serviceName = `php:${version}`
|
||||||
if (processManager.isServiceRunning(serviceName)) {
|
if (processManager.isServiceRunning(serviceName)) {
|
||||||
console.log(`Restarting ${serviceName} due to extension change...`)
|
|
||||||
await processManager.stopService(serviceName)
|
await processManager.stopService(serviceName)
|
||||||
// We need to re-run the start logic or just let the user do it?
|
result.message += " (Service stopped for restart)"
|
||||||
// The user said "Proceed with the decision that you think is the most optimal"
|
|
||||||
// Optimal is to restart it exactly as it was.
|
|
||||||
// However, the start logic in 'services:start' has many parameters (ports, ini templates).
|
|
||||||
// It's better to just stop it and tell the user it needs to be started again,
|
|
||||||
// OR I can try to trigger the same start logic.
|
|
||||||
// Given the current architecture, I'll just stop it and return a message.
|
|
||||||
// Wait, I can't easily call 'services:start' from here without the event object.
|
|
||||||
// Actually, I can just not restart it here and let the renderer handle it if they want.
|
|
||||||
// NO, I'll just return that it's updated. PHP usually needs a restart anyway.
|
|
||||||
// I'll update the message to reflect that.
|
|
||||||
result.message += ". Please restart the PHP service to apply changes."
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
@@ -413,13 +414,12 @@ export function registerIpcHandlers(): void {
|
|||||||
const iniPath = path.join(phpDir, 'php.ini')
|
const iniPath = path.join(phpDir, 'php.ini')
|
||||||
fs.writeFileSync(iniPath, content)
|
fs.writeFileSync(iniPath, content)
|
||||||
|
|
||||||
// Return a result that indicates a restart is needed
|
|
||||||
const serviceName = `php:${version}`
|
const serviceName = `php:${version}`
|
||||||
const isRunning = processManager.isServiceRunning(serviceName)
|
if (processManager.isServiceRunning(serviceName)) {
|
||||||
if (isRunning) {
|
|
||||||
await processManager.stopService(serviceName)
|
await processManager.stopService(serviceName)
|
||||||
}
|
}
|
||||||
return { success: true, message: `php.ini saved.${isRunning ? ' Current PHP service stopped. Please restart to apply.' : ''}` }
|
|
||||||
|
return { success: true, message: 'Configuration saved.' }
|
||||||
})
|
})
|
||||||
|
|
||||||
// MariaDB Versions
|
// MariaDB Versions
|
||||||
|
|||||||
@@ -71,18 +71,34 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
|||||||
|
|
||||||
const handleSaveRaw = async () => {
|
const handleSaveRaw = async () => {
|
||||||
setIsSavingRaw(true)
|
setIsSavingRaw(true)
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Yapılandırma Kaydediliyor',
|
||||||
|
text: 'PHP servisi yeniden başlatılıyor...',
|
||||||
|
allowOutsideClick: false,
|
||||||
|
didOpen: () => {
|
||||||
|
Swal.showLoading()
|
||||||
|
},
|
||||||
|
background: '#1e1e1e',
|
||||||
|
color: '#fff'
|
||||||
|
})
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await window.api.invoke('php:config:save', { version: phpVersion, content: rawConfig })
|
const result = await window.api.invoke('php:config:save', { version: phpVersion, content: rawConfig })
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
|
// Trigger restart
|
||||||
|
await window.api.invoke('services:start', `php:${phpVersion}`)
|
||||||
|
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: 'Başarılı',
|
title: 'Başarılı',
|
||||||
text: result.message,
|
text: 'Yapılandırma kaydedildi ve servis yeniden başlatıldı.',
|
||||||
icon: 'success',
|
icon: 'success',
|
||||||
|
timer: 2000,
|
||||||
|
showConfirmButton: false,
|
||||||
background: '#1e1e1e',
|
background: '#1e1e1e',
|
||||||
color: '#fff'
|
color: '#fff'
|
||||||
})
|
})
|
||||||
setIsRawEditorOpen(false)
|
setIsRawEditorOpen(false)
|
||||||
fetchExtensions() // Refresh extension list too
|
fetchExtensions()
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
Swal.fire({ title: 'Hata', text: error.message, icon: 'error', background: '#1e1e1e', color: '#fff' })
|
Swal.fire({ title: 'Hata', text: error.message, icon: 'error', background: '#1e1e1e', color: '#fff' })
|
||||||
@@ -99,36 +115,37 @@ const PhpExtensionManager: React.FC<PhpExtensionManagerProps> = ({ open, onClose
|
|||||||
|
|
||||||
const handleToggle = async (extName: string, enabled: boolean) => {
|
const handleToggle = async (extName: string, enabled: boolean) => {
|
||||||
setSaving(extName)
|
setSaving(extName)
|
||||||
|
|
||||||
|
// Show a non-blocking toast or a small overlay if we want, but for "Restart" let's be more explicit if it was running
|
||||||
|
const wasRunning = await window.api.invoke('service:status', `php:${phpVersion}`) === 'running'
|
||||||
|
|
||||||
|
if (wasRunning) {
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Eklenti Ayarlanıyor',
|
||||||
|
text: `${extName} ${enabled ? 'aktif ediliyor' : 'devre dışı bırakılıyor'} ve PHP yeniden başlatılıyor...`,
|
||||||
|
allowOutsideClick: false,
|
||||||
|
didOpen: () => {
|
||||||
|
Swal.showLoading()
|
||||||
|
},
|
||||||
|
background: '#1e1e1e',
|
||||||
|
color: '#fff'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await window.api.invoke('php:extensions:toggle', { version: phpVersion, extName, enabled })
|
const result = await window.api.invoke('php:extensions:toggle', { version: phpVersion, extName, enabled })
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
setExtensions(prev => prev.map(ext => ext.name === extName ? { ...ext, enabled } : ext))
|
setExtensions(prev => prev.map(ext => ext.name === extName ? { ...ext, enabled } : ext))
|
||||||
if (result.message.includes('restart')) {
|
|
||||||
Swal.fire({
|
if (wasRunning) {
|
||||||
title: 'Bilgi',
|
await window.api.invoke('services:start', `php:${phpVersion}`)
|
||||||
text: result.message,
|
Swal.close()
|
||||||
icon: 'info',
|
|
||||||
background: '#1e1e1e',
|
|
||||||
color: '#fff'
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Swal.fire({
|
Swal.fire({ title: 'Hata', text: result.message, icon: 'error', background: '#1e1e1e', color: '#fff' })
|
||||||
title: 'Hata',
|
|
||||||
text: result.message,
|
|
||||||
icon: 'error',
|
|
||||||
background: '#1e1e1e',
|
|
||||||
color: '#fff'
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
Swal.fire({
|
Swal.fire({ title: 'Hata', text: error.message, icon: 'error', background: '#1e1e1e', color: '#fff' })
|
||||||
title: 'Hata',
|
|
||||||
text: error.message,
|
|
||||||
icon: 'error',
|
|
||||||
background: '#1e1e1e',
|
|
||||||
color: '#fff'
|
|
||||||
})
|
|
||||||
} finally {
|
} finally {
|
||||||
setSaving(null)
|
setSaving(null)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user