Created
September 11, 2025 14:52
-
-
Save ahsankhatri/4e13ec392c9b978283acbe9c3e933ec9 to your computer and use it in GitHub Desktop.
A utility to check server requirements for Laravel framework versions 10-12 (can be added). Supports both CLI and Web interfaces
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Laravel Requirements Checker | |
* | |
* A utility to check server requirements for Laravel framework versions 10-12 | |
* Supports both CLI and Web interfaces | |
* | |
* Usage (CLI): php laravel-requirements-checker.php [--version=10|11|12] [--format=text|json] | |
* Usage (Web): Access via browser | |
*/ | |
class LaravelRequirementsChecker | |
{ | |
public const DEFAULT_VERSION = 12; | |
private array $requirements = [ | |
'10' => [ | |
'name' => 'Laravel 10.x', | |
'php_version' => '8.1.0', | |
'required_extensions' => [ | |
'ctype', 'curl', 'dom', 'fileinfo', 'filter', 'hash', 'json', | |
'mbstring', 'openssl', 'pcre', 'pdo', 'session', 'tokenizer', 'xml' | |
], | |
'recommended_extensions' => [ | |
'bcmath', 'gd', 'imagick', 'intl', 'zip', 'redis', 'memcached', | |
'pcntl', 'pdo_mysql', 'xmlwriter', | |
] | |
], | |
'11' => [ | |
'name' => 'Laravel 11.x', | |
'php_version' => '8.2.0', | |
'required_extensions' => [ | |
'ctype', 'curl', 'dom', 'fileinfo', 'filter', 'hash', 'json', | |
'mbstring', 'openssl', 'pcre', 'pdo', 'session', 'tokenizer', 'xml' | |
], | |
'recommended_extensions' => [ | |
'bcmath', 'gd', 'imagick', 'intl', 'zip', 'redis', 'memcached', | |
'pcntl', 'pdo_mysql', 'xmlwriter', | |
] | |
], | |
'12' => [ | |
'name' => 'Laravel 12.x', | |
'php_version' => '8.2.0', | |
'required_extensions' => [ | |
'ctype', 'curl', 'dom', 'fileinfo', 'filter', 'hash', 'json', | |
'mbstring', 'openssl', 'pcre', 'pdo', 'session', 'tokenizer', 'xml' | |
], | |
'recommended_extensions' => [ | |
'bcmath', 'gd', 'imagick', 'intl', 'zip', 'redis', 'memcached', | |
'pcntl', 'pdo_mysql', 'xmlwriter', | |
] | |
] | |
]; | |
private string $laravelVersion; | |
private string $outputFormat; | |
private bool $isCliMode; | |
public function __construct() | |
{ | |
$this->isCliMode = php_sapi_name() === 'cli'; | |
$this->laravelVersion = $this->getRequestedVersion(); | |
$this->outputFormat = $this->getOutputFormat(); | |
} | |
private function getRequestedVersion(): string | |
{ | |
if ($this->isCliMode) { | |
$options = getopt('', ['version::', 'format::']); | |
return $options['version'] ?? self::DEFAULT_VERSION; | |
} else { | |
return $_GET['version'] ?? self::DEFAULT_VERSION; | |
} | |
} | |
private function getOutputFormat(): string | |
{ | |
if ($this->isCliMode) { | |
$options = getopt('', ['version::', 'format::']); | |
return $options['format'] ?? 'text'; | |
} else { | |
return $_GET['format'] ?? 'html'; | |
} | |
} | |
public function run(): void | |
{ | |
if (!isset($this->requirements[$this->laravelVersion])) { | |
$this->displayError("Unsupported Laravel version: {$this->laravelVersion}. Supported versions: " . implode(', ', array_keys($this->requirements))); | |
return; | |
} | |
$results = $this->checkRequirements(); | |
switch ($this->outputFormat) { | |
case 'json': | |
$this->displayJsonOutput($results); | |
break; | |
case 'html': | |
$this->displayHtmlOutput($results); | |
break; | |
default: | |
$this->displayTextOutput($results); | |
} | |
} | |
private function checkRequirements(): array | |
{ | |
$requirements = $this->requirements[$this->laravelVersion]; | |
$results = [ | |
'laravel_version' => $requirements['name'], | |
'server_info' => $this->getServerInfo(), | |
'php_check' => $this->checkPhpVersion($requirements['php_version']), | |
'required_extensions' => $this->checkExtensions($requirements['required_extensions'], true), | |
'recommended_extensions' => $this->checkExtensions($requirements['recommended_extensions'], false), | |
'additional_checks' => $this->performAdditionalChecks(), | |
'overall_status' => 'passed' | |
]; | |
// Determine overall status | |
if (!$results['php_check']['passed']) { | |
$results['overall_status'] = 'failed'; | |
} else { | |
foreach ($results['required_extensions'] as $ext) { | |
if (!$ext['installed']) { | |
$results['overall_status'] = 'failed'; | |
break; | |
} | |
} | |
} | |
return $results; | |
} | |
private function getServerInfo(): array | |
{ | |
return [ | |
'php_version' => PHP_VERSION, | |
'php_sapi' => php_sapi_name(), | |
'os' => php_uname('s') . ' ' . php_uname('r'), | |
'server_software' => $_SERVER['SERVER_SOFTWARE'] ?? 'CLI', | |
'memory_limit' => ini_get('memory_limit'), | |
'max_execution_time' => ini_get('max_execution_time'), | |
'upload_max_filesize' => ini_get('upload_max_filesize'), | |
'post_max_size' => ini_get('post_max_size') | |
]; | |
} | |
private function checkPhpVersion(string $requiredVersion): array | |
{ | |
$currentVersion = PHP_VERSION; | |
$passed = version_compare($currentVersion, $requiredVersion, '>='); | |
return [ | |
'required' => $requiredVersion, | |
'current' => $currentVersion, | |
'passed' => $passed, | |
'message' => $passed ? 'PHP version requirement met' : "PHP {$requiredVersion} or higher required, found {$currentVersion}" | |
]; | |
} | |
private function checkExtensions(array $extensions, bool $required): array | |
{ | |
$results = []; | |
foreach ($extensions as $extension) { | |
$installed = extension_loaded($extension); | |
$version = $installed ? phpversion($extension) : null; | |
$results[] = [ | |
'name' => $extension, | |
'installed' => $installed, | |
'version' => $version ?: 'N/A', | |
'required' => $required, | |
'status' => $installed ? 'OK' : ($required ? 'MISSING' : 'RECOMMENDED') | |
]; | |
} | |
return $results; | |
} | |
private function performAdditionalChecks(): array | |
{ | |
$checks = []; | |
// Composer check | |
$composerPath = $this->findComposer(); | |
$checks['composer'] = [ | |
'name' => 'Composer', | |
'status' => $composerPath ? 'OK' : 'NOT FOUND', | |
'path' => $composerPath, | |
'version' => $composerPath ? $this->getComposerVersion($composerPath) : null | |
]; | |
// Node.js check | |
$nodePath = $this->findExecutable('node'); | |
$checks['nodejs'] = [ | |
'name' => 'Node.js', | |
'status' => $nodePath ? 'OK' : 'NOT FOUND', | |
'path' => $nodePath, | |
'version' => $nodePath ? $this->getNodeVersion() : null | |
]; | |
// NPM check | |
$npmPath = $this->findExecutable('npm'); | |
$checks['npm'] = [ | |
'name' => 'NPM', | |
'status' => $npmPath ? 'OK' : 'NOT FOUND', | |
'path' => $npmPath, | |
'version' => $npmPath ? $this->getNpmVersion() : null | |
]; | |
// Directory permissions check (if in web context and Laravel directories exist) | |
if (!$this->isCliMode) { | |
$checks['permissions'] = $this->checkDirectoryPermissions(); | |
} | |
return $checks; | |
} | |
private function findComposer(): ?string | |
{ | |
$paths = ['composer', 'composer.phar', './composer.phar']; | |
foreach ($paths as $path) { | |
if ($this->commandExists($path)) { | |
return $path; | |
} | |
} | |
return null; | |
} | |
private function findExecutable(string $executable): ?string | |
{ | |
if ($this->commandExists($executable)) { | |
return $executable; | |
} | |
return null; | |
} | |
private function commandExists(string $command): bool | |
{ | |
$whereIsCommand = (PHP_OS == 'WINNT') ? 'where' : 'which'; | |
$process = proc_open( | |
"$whereIsCommand $command", | |
[ | |
0 => ['pipe', 'r'], | |
1 => ['pipe', 'w'], | |
2 => ['pipe', 'w'] | |
], | |
$pipes, | |
null, | |
null, | |
['suppress_errors' => true] | |
); | |
if (is_resource($process)) { | |
$result = stream_get_contents($pipes[1]); | |
fclose($pipes[0]); | |
fclose($pipes[1]); | |
fclose($pipes[2]); | |
$return_value = proc_close($process); | |
return $return_value === 0 && !empty(trim($result)); | |
} | |
return false; | |
} | |
private function getComposerVersion(?string $composerPath): ?string | |
{ | |
if (!$composerPath) return null; | |
$output = shell_exec("$composerPath --version 2>/dev/null"); | |
if (preg_match('/Composer version ([^\s]+)/', $output, $matches)) { | |
return $matches[1]; | |
} | |
return 'Unknown'; | |
} | |
private function getNodeVersion(): ?string | |
{ | |
$output = shell_exec('node --version 2>/dev/null'); | |
return $output ? trim($output) : null; | |
} | |
private function getNpmVersion(): ?string | |
{ | |
$output = shell_exec('npm --version 2>/dev/null'); | |
return $output ? trim($output) : null; | |
} | |
private function checkDirectoryPermissions(): array | |
{ | |
$directories = ['storage', 'bootstrap/cache']; | |
$results = []; | |
foreach ($directories as $dir) { | |
if (is_dir($dir)) { | |
$writable = is_writable($dir); | |
$results[$dir] = [ | |
'path' => $dir, | |
'exists' => true, | |
'writable' => $writable, | |
'permissions' => substr(sprintf('%o', fileperms($dir)), -4), | |
'status' => $writable ? 'OK' : 'NOT WRITABLE' | |
]; | |
} else { | |
$results[$dir] = [ | |
'path' => $dir, | |
'exists' => false, | |
'writable' => false, | |
'permissions' => 'N/A', | |
'status' => 'NOT FOUND' | |
]; | |
} | |
} | |
return $results; | |
} | |
private function displayError(string $message): void | |
{ | |
if ($this->isCliMode) { | |
echo "Error: $message\n"; | |
} else { | |
echo "<div style='color: red; padding: 20px; border: 1px solid red; margin: 20px;'>Error: $message</div>"; | |
} | |
} | |
private function displayJsonOutput(array $results): void | |
{ | |
if (!$this->isCliMode) { | |
header('Content-Type: application/json'); | |
} | |
echo json_encode($results, JSON_PRETTY_PRINT); | |
} | |
private function displayTextOutput(array $results): void | |
{ | |
$output = []; | |
$output[] = str_repeat('=', 60); | |
$output[] = "LARAVEL REQUIREMENTS CHECK - {$results['laravel_version']}"; | |
$output[] = str_repeat('=', 60); | |
// Server Info | |
$output[] = "\nπ SERVER INFORMATION:"; | |
$output[] = str_repeat('-', 30); | |
$output[] = "PHP Version: {$results['server_info']['php_version']}"; | |
$output[] = "PHP SAPI: {$results['server_info']['php_sapi']}"; | |
$output[] = "Operating System: {$results['server_info']['os']}"; | |
$output[] = "Memory Limit: {$results['server_info']['memory_limit']}"; | |
// PHP Version Check | |
$output[] = "\nπ PHP VERSION CHECK:"; | |
$output[] = str_repeat('-', 30); | |
$status = $results['php_check']['passed'] ? 'β PASS' : 'β FAIL'; | |
$output[] = "{$status} - {$results['php_check']['message']}"; | |
// Required Extensions | |
$output[] = "\nπ§ REQUIRED EXTENSIONS:"; | |
$output[] = str_repeat('-', 30); | |
foreach ($results['required_extensions'] as $ext) { | |
$status = $ext['installed'] ? 'β ' : 'β'; | |
$version = $ext['version'] !== 'N/A' ? " (v{$ext['version']})" : ''; | |
$output[] = "{$status} {$ext['name']}{$version} - {$ext['status']}"; | |
} | |
// Recommended Extensions | |
$output[] = "\nπ‘ RECOMMENDED EXTENSIONS:"; | |
$output[] = str_repeat('-', 30); | |
foreach ($results['recommended_extensions'] as $ext) { | |
$status = $ext['installed'] ? 'β ' : 'β οΈ'; | |
$version = $ext['version'] !== 'N/A' ? " (v{$ext['version']})" : ''; | |
$output[] = "{$status} {$ext['name']}{$version} - {$ext['status']}"; | |
} | |
// Additional Checks | |
$output[] = "\nπ οΈ ADDITIONAL TOOLS:"; | |
$output[] = str_repeat('-', 30); | |
foreach ($results['additional_checks'] as $key => $check) { | |
if ($key === 'permissions') continue; // Skip permissions in CLI | |
$status = $check['status'] === 'OK' ? 'β ' : 'β οΈ'; | |
$version = $check['version'] ? " (v{$check['version']})" : ''; | |
$output[] = "{$status} {$check['name']}{$version} - {$check['status']}"; | |
} | |
// Overall Status | |
$output[] = "\n" . str_repeat('=', 60); | |
$overallStatus = $results['overall_status'] === 'passed' ? 'β SYSTEM READY' : 'β SYSTEM NOT READY'; | |
$output[] = "OVERALL STATUS: {$overallStatus}"; | |
$output[] = str_repeat('=', 60); | |
echo implode("\n", $output) . "\n"; | |
} | |
private function displayHtmlOutput(array $results): void | |
{ | |
if (!headers_sent()) { | |
header('Content-Type: text/html; charset=UTF-8'); | |
} | |
$overallClass = $results['overall_status'] === 'passed' ? 'success' : 'danger'; | |
$overallText = $results['overall_status'] === 'passed' ? 'SYSTEM READY FOR LARAVEL' : 'SYSTEM NOT READY'; | |
$availableVersions = implode('', array_map(function ($x, $i) { | |
return sprintf('<a href="?version=%d" class="btn">%s</a>', $i, $x['name']); | |
}, $this->requirements, array_keys($this->requirements))); | |
echo <<<HTML | |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Laravel Requirements Checker</title> | |
<style> | |
* { margin: 0; padding: 0; box-sizing: border-box; } | |
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: #f8f9fa; padding: 20px; } | |
.container { max-width: 1200px; margin: 0 auto; } | |
.header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px; border-radius: 10px; margin-bottom: 30px; text-align: center; } | |
.version-selector { background: white; padding: 20px; border-radius: 10px; margin-bottom: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } | |
.card { background: white; border-radius: 10px; padding: 20px; margin-bottom: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } | |
.card h3 { margin-bottom: 15px; color: #333; border-bottom: 2px solid #eee; padding-bottom: 10px; } | |
.status-success { color: #28a745; font-weight: bold; } | |
.status-danger { color: #dc3545; font-weight: bold; } | |
.status-warning { color: #ffc107; font-weight: bold; } | |
.overall-status { padding: 20px; border-radius: 10px; text-align: center; font-size: 1.5em; font-weight: bold; margin-bottom: 30px; } | |
.overall-status.success { background: #d4edda; color: #155724; border: 1px solid #c3e6cb; } | |
.overall-status.danger { background: #f8d7da; color: #721c24; border: 1px solid #f1b0b7; } | |
.info-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 10px; } | |
.info-item { padding: 10px; background: #f8f9fa; border-radius: 5px; } | |
.extension-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 10px; } | |
.extension-item { padding: 10px; border-radius: 5px; border-left: 4px solid #eee; background: #f8f9fa; } | |
.extension-item.ok { border-left-color: #28a745; } | |
.extension-item.missing { border-left-color: #dc3545; } | |
.extension-item.recommended { border-left-color: #ffc107; } | |
.btn { display: inline-block; padding: 10px 20px; background: #007bff; color: white; text-decoration: none; border-radius: 5px; margin: 5px; } | |
.btn:hover { background: #0056b3; } | |
</style> | |
</head> | |
<body> | |
<div class="container"> | |
<div class="header"> | |
<h1>π Laravel Requirements Checker</h1> | |
<p>Checking requirements for {$results['laravel_version']}</p> | |
</div> | |
<div class="version-selector"> | |
<h3>Select Laravel Version:</h3> | |
{$availableVersions} | |
<a href="?format=json&version={$this->laravelVersion}" class="btn">JSON Output</a> | |
</div> | |
<div class="overall-status {$overallClass}"> | |
{$overallText} | |
</div> | |
<div class="card"> | |
<h3>π Server Information</h3> | |
<div class="info-grid"> | |
<div class="info-item"><strong>PHP Version:</strong> {$results['server_info']['php_version']}</div> | |
<div class="info-item"><strong>PHP SAPI:</strong> {$results['server_info']['php_sapi']}</div> | |
<div class="info-item"><strong>Operating System:</strong> {$results['server_info']['os']}</div> | |
<div class="info-item"><strong>Memory Limit:</strong> {$results['server_info']['memory_limit']}</div> | |
<div class="info-item"><strong>Max Execution Time:</strong> {$results['server_info']['max_execution_time']}s</div> | |
<div class="info-item"><strong>Upload Max Size:</strong> {$results['server_info']['upload_max_filesize']}</div> | |
</div> | |
</div> | |
<div class="card"> | |
<h3>π PHP Version Check</h3> | |
HTML; | |
$phpClass = $results['php_check']['passed'] ? 'ok' : 'missing'; | |
$phpStatusClass = $results['php_check']['passed'] ? 'status-success' : 'status-danger'; | |
$phpIcon = $results['php_check']['passed'] ? 'β PASS' : 'β FAIL'; | |
echo <<<HTML | |
<div class="extension-item {$phpClass}"> | |
<span class="{$phpStatusClass}"> | |
{$phpIcon} | |
</span> | |
- {$results['php_check']['message']} | |
</div> | |
</div> | |
<div class="card"> | |
<h3>π§ Required Extensions</h3> | |
<div class="extension-list"> | |
HTML; | |
foreach ($results['required_extensions'] as $ext) { | |
$class = $ext['installed'] ? 'ok' : 'missing'; | |
$statusClass = $ext['installed'] ? 'status-success' : 'status-danger'; | |
$icon = $ext['installed'] ? 'β ' : 'β'; | |
$version = $ext['version'] !== 'N/A' ? " (v{$ext['version']})" : ''; | |
echo <<<HTML | |
<div class="extension-item {$class}"> | |
<strong>{$ext['name']}</strong>{$version}<br> | |
<span class="{$statusClass}">{$icon} {$ext['status']}</span> | |
</div> | |
HTML; | |
} | |
echo <<<HTML | |
</div> | |
</div> | |
<div class="card"> | |
<h3>π‘ Recommended Extensions</h3> | |
<div class="extension-list"> | |
HTML; | |
foreach ($results['recommended_extensions'] as $ext) { | |
$class = $ext['installed'] ? 'ok' : 'recommended'; | |
$statusClass = $ext['installed'] ? 'status-success' : 'status-warning'; | |
$icon = $ext['installed'] ? 'β ' : 'β οΈ'; | |
$version = $ext['version'] !== 'N/A' ? " (v{$ext['version']})" : ''; | |
echo <<<HTML | |
<div class="extension-item {$class}"> | |
<strong>{$ext['name']}</strong>{$version}<br> | |
<span class="{$statusClass}">{$icon} {$ext['status']}</span> | |
</div> | |
HTML; | |
} | |
echo <<<HTML | |
</div> | |
</div> | |
<div class="card"> | |
<h3>π οΈ Additional Tools</h3> | |
<div class="extension-list"> | |
HTML; | |
foreach ($results['additional_checks'] as $key => $check) { | |
if ($key === 'permissions') { | |
// Handle permissions separately | |
echo '<div class="card"><h3>π Directory Permissions</h3><div class="extension-list">'; | |
foreach ($check as $dir => $perm) { | |
$class = $perm['status'] === 'OK' ? 'ok' : 'missing'; | |
$statusClass = $perm['status'] === 'OK' ? 'status-success' : 'status-danger'; | |
$icon = $perm['status'] === 'OK' ? 'β ' : 'β'; | |
$permissionLabel = $perm['exists'] ? " (Permissions: {$perm['permissions']})" : ''; | |
echo <<<HTML | |
<div class="extension-item {$class}"> | |
<strong>{$perm['path']}</strong><br> | |
<span class="{$statusClass}">{$icon} {$perm['status']}</span> | |
{$permissionLabel} | |
</div> | |
HTML; | |
} | |
echo '</div></div>'; | |
continue; | |
} | |
$class = $check['status'] === 'OK' ? 'ok' : 'recommended'; | |
$statusClass = $check['status'] === 'OK' ? 'status-success' : 'status-warning'; | |
$icon = $check['status'] === 'OK' ? 'β ' : 'β οΈ'; | |
$version = $check['version'] ? " (v{$check['version']})" : ''; | |
echo <<<HTML | |
<div class="extension-item {$class}"> | |
<strong>{$check['name']}</strong>{$version}<br> | |
<span class="{$statusClass}">{$icon} {$check['status']}</span> | |
</div> | |
HTML; | |
} | |
$timeGenerated = date('Y-m-d H:i:s'); | |
echo <<<HTML | |
</div> | |
</div> | |
<div style="text-align: center; margin-top: 30px; padding: 20px; background: white; border-radius: 10px;"> | |
<p>Generated on: {$timeGenerated}</p> | |
<p>Laravel Requirements Checker v1.0.0</p> | |
</div> | |
</div> | |
</body> | |
</html> | |
HTML; | |
} | |
} | |
// Main execution | |
try { | |
$checker = new LaravelRequirementsChecker(); | |
$checker->run(); | |
} catch (Exception $e) { | |
if (php_sapi_name() === 'cli') { | |
echo "Fatal Error: " . $e->getMessage() . "\n"; | |
exit(1); | |
} else { | |
echo "<div style='color: red; padding: 20px; margin: 20px; border: 1px solid red;'>Fatal Error: " . htmlspecialchars($e->getMessage()) . "</div>"; | |
} | |
} | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment