298 lines
9.6 KiB
PHP
298 lines
9.6 KiB
PHP
<?php
|
|
|
|
/**
|
|
* OPcache Preload Script for PHP 8.3-FPM
|
|
*
|
|
* Configure in php.ini:
|
|
* opcache.preload=/path/to/preload.php
|
|
* opcache.preload_user=www-data
|
|
*
|
|
* Run after deployment: php artisan optimize && php artisan filament:optimize
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
$basePath = __DIR__;
|
|
$preloadedCount = 0;
|
|
$skippedCount = 0;
|
|
|
|
/**
|
|
* Compile a file into OPcache without executing it
|
|
*/
|
|
function preloadFile(string $path): bool
|
|
{
|
|
global $preloadedCount, $skippedCount;
|
|
|
|
if (!is_file($path) || !is_readable($path)) {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
if (opcache_compile_file($path)) {
|
|
$preloadedCount++;
|
|
return true;
|
|
}
|
|
} catch (Throwable $e) {
|
|
// Silently skip files that can't be preloaded (syntax errors, etc.)
|
|
}
|
|
|
|
$skippedCount++;
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Recursively preload all PHP files in a directory
|
|
*/
|
|
function preloadDirectory(string $dir, array $excludePatterns = []): void
|
|
{
|
|
if (!is_dir($dir)) {
|
|
return;
|
|
}
|
|
|
|
$iterator = new RecursiveIteratorIterator(
|
|
new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS),
|
|
RecursiveIteratorIterator::LEAVES_ONLY
|
|
);
|
|
|
|
foreach ($iterator as $file) {
|
|
if (!$file->isFile() || $file->getExtension() !== 'php') {
|
|
continue;
|
|
}
|
|
|
|
$path = $file->getRealPath();
|
|
|
|
// Skip excluded patterns
|
|
foreach ($excludePatterns as $pattern) {
|
|
if (preg_match($pattern, $path)) {
|
|
continue 2;
|
|
}
|
|
}
|
|
|
|
preloadFile($path);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Preload specific files from a list
|
|
*/
|
|
function preloadFiles(array $files): void
|
|
{
|
|
foreach ($files as $file) {
|
|
if (is_file($file)) {
|
|
preloadFile($file);
|
|
}
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// 1. LARAVEL CACHED/COMPILED FILES (Most Critical)
|
|
// =============================================================================
|
|
|
|
$cachedFiles = [
|
|
$basePath . '/bootstrap/cache/packages.php',
|
|
$basePath . '/bootstrap/cache/services.php',
|
|
$basePath . '/bootstrap/cache/config.php',
|
|
$basePath . '/bootstrap/cache/routes-v7.php',
|
|
$basePath . '/bootstrap/cache/events.php',
|
|
$basePath . '/bootstrap/cache/filament.php',
|
|
$basePath . '/bootstrap/cache/livewire-components.php',
|
|
];
|
|
|
|
preloadFiles($cachedFiles);
|
|
|
|
// =============================================================================
|
|
// 2. COMPOSER AUTOLOADER (Essential for class resolution)
|
|
// =============================================================================
|
|
|
|
preloadFiles([
|
|
$basePath . '/vendor/autoload.php',
|
|
$basePath . '/vendor/composer/autoload_real.php',
|
|
$basePath . '/vendor/composer/ClassLoader.php',
|
|
$basePath . '/vendor/composer/autoload_static.php',
|
|
]);
|
|
|
|
// =============================================================================
|
|
// 3. LARAVEL CORE FRAMEWORK
|
|
// =============================================================================
|
|
|
|
$laravelCoreDirs = [
|
|
// Foundation & Core
|
|
$basePath . '/vendor/laravel/framework/src/Illuminate/Foundation',
|
|
$basePath . '/vendor/laravel/framework/src/Illuminate/Container',
|
|
$basePath . '/vendor/laravel/framework/src/Illuminate/Contracts',
|
|
|
|
// HTTP Layer
|
|
$basePath . '/vendor/laravel/framework/src/Illuminate/Http',
|
|
$basePath . '/vendor/laravel/framework/src/Illuminate/Routing',
|
|
$basePath . '/vendor/laravel/framework/src/Illuminate/Pipeline',
|
|
|
|
// Database & Eloquent
|
|
$basePath . '/vendor/laravel/framework/src/Illuminate/Database',
|
|
|
|
// Support utilities
|
|
$basePath . '/vendor/laravel/framework/src/Illuminate/Support',
|
|
$basePath . '/vendor/laravel/framework/src/Illuminate/Collections',
|
|
|
|
// Session & Auth
|
|
$basePath . '/vendor/laravel/framework/src/Illuminate/Auth',
|
|
$basePath . '/vendor/laravel/framework/src/Illuminate/Session',
|
|
$basePath . '/vendor/laravel/framework/src/Illuminate/Cookie',
|
|
|
|
// Views & Blade
|
|
$basePath . '/vendor/laravel/framework/src/Illuminate/View',
|
|
|
|
// Events & Queue
|
|
$basePath . '/vendor/laravel/framework/src/Illuminate/Events',
|
|
$basePath . '/vendor/laravel/framework/src/Illuminate/Queue',
|
|
|
|
// Validation & Cache
|
|
$basePath . '/vendor/laravel/framework/src/Illuminate/Validation',
|
|
$basePath . '/vendor/laravel/framework/src/Illuminate/Cache',
|
|
|
|
// Encryption & Hashing
|
|
$basePath . '/vendor/laravel/framework/src/Illuminate/Encryption',
|
|
$basePath . '/vendor/laravel/framework/src/Illuminate/Hashing',
|
|
];
|
|
|
|
// Exclude test files and stubs
|
|
$excludePatterns = [
|
|
'/[Tt]est[s]?\.php$/',
|
|
'/[Ss]tub[s]?\.php$/',
|
|
'/[Ff]ixture[s]?/',
|
|
];
|
|
|
|
foreach ($laravelCoreDirs as $dir) {
|
|
preloadDirectory($dir, $excludePatterns);
|
|
}
|
|
|
|
// =============================================================================
|
|
// 4. LIVEWIRE (Critical for your app)
|
|
// =============================================================================
|
|
|
|
preloadDirectory($basePath . '/vendor/livewire/livewire/src', $excludePatterns);
|
|
preloadDirectory($basePath . '/vendor/livewire/volt/src', $excludePatterns);
|
|
|
|
// =============================================================================
|
|
// 5. FILAMENT (Admin Panel - Critical for your app)
|
|
// =============================================================================
|
|
|
|
$filamentDirs = [
|
|
$basePath . '/vendor/filament/filament/src',
|
|
$basePath . '/vendor/filament/support/src',
|
|
$basePath . '/vendor/filament/forms/src',
|
|
$basePath . '/vendor/filament/tables/src',
|
|
$basePath . '/vendor/filament/actions/src',
|
|
$basePath . '/vendor/filament/infolists/src',
|
|
$basePath . '/vendor/filament/notifications/src',
|
|
$basePath . '/vendor/filament/widgets/src',
|
|
];
|
|
|
|
foreach ($filamentDirs as $dir) {
|
|
preloadDirectory($dir, $excludePatterns);
|
|
}
|
|
|
|
// =============================================================================
|
|
// 6. COMMON DEPENDENCIES
|
|
// =============================================================================
|
|
|
|
$commonDeps = [
|
|
// Symfony HTTP Foundation
|
|
$basePath . '/vendor/symfony/http-foundation/Request.php',
|
|
$basePath . '/vendor/symfony/http-foundation/Response.php',
|
|
$basePath . '/vendor/symfony/http-foundation/HeaderBag.php',
|
|
$basePath . '/vendor/symfony/http-foundation/ParameterBag.php',
|
|
$basePath . '/vendor/symfony/http-foundation/InputBag.php',
|
|
$basePath . '/vendor/symfony/http-foundation/FileBag.php',
|
|
$basePath . '/vendor/symfony/http-foundation/ServerBag.php',
|
|
$basePath . '/vendor/symfony/http-foundation/Cookie.php',
|
|
$basePath . '/vendor/symfony/http-foundation/Session/Session.php',
|
|
|
|
// Symfony HTTP Kernel
|
|
$basePath . '/vendor/symfony/http-kernel/HttpKernel.php',
|
|
|
|
// PSR Interfaces
|
|
$basePath . '/vendor/psr/container/src/ContainerInterface.php',
|
|
$basePath . '/vendor/psr/http-message/src/MessageInterface.php',
|
|
$basePath . '/vendor/psr/http-message/src/RequestInterface.php',
|
|
$basePath . '/vendor/psr/http-message/src/ResponseInterface.php',
|
|
$basePath . '/vendor/psr/log/src/LoggerInterface.php',
|
|
|
|
// Carbon (Date handling)
|
|
$basePath . '/vendor/nesbot/carbon/src/Carbon/Carbon.php',
|
|
$basePath . '/vendor/nesbot/carbon/src/Carbon/CarbonInterface.php',
|
|
$basePath . '/vendor/nesbot/carbon/src/Carbon/CarbonImmutable.php',
|
|
];
|
|
|
|
preloadFiles($commonDeps);
|
|
|
|
// =============================================================================
|
|
// 7. APPLICATION CODE (Your code)
|
|
// =============================================================================
|
|
|
|
$appDirs = [
|
|
// Models (Most frequently accessed)
|
|
$basePath . '/app/Models',
|
|
|
|
// HTTP Layer
|
|
$basePath . '/app/Http/Controllers',
|
|
$basePath . '/app/Http/Middleware',
|
|
$basePath . '/app/Http/Requests',
|
|
|
|
// Livewire Components
|
|
$basePath . '/app/Livewire',
|
|
|
|
// Filament Admin
|
|
$basePath . '/app/Admin/Resources',
|
|
$basePath . '/app/Admin/Pages',
|
|
$basePath . '/app/Admin/Widgets',
|
|
|
|
// Service Providers
|
|
$basePath . '/app/Providers',
|
|
|
|
// Jobs & Events
|
|
$basePath . '/app/Jobs',
|
|
$basePath . '/app/Events',
|
|
$basePath . '/app/Listeners',
|
|
|
|
// Helpers & Classes
|
|
$basePath . '/app/Classes',
|
|
$basePath . '/app/Helpers',
|
|
$basePath . '/app/Traits',
|
|
|
|
// Policies & Rules
|
|
$basePath . '/app/Policies',
|
|
$basePath . '/app/Rules',
|
|
];
|
|
|
|
foreach ($appDirs as $dir) {
|
|
preloadDirectory($dir);
|
|
}
|
|
|
|
// =============================================================================
|
|
// 8. BLADE COMPILED VIEWS (if using view caching)
|
|
// =============================================================================
|
|
|
|
// Only preload if compiled views exist and are recent
|
|
$compiledViewsPath = $basePath . '/storage/framework/views';
|
|
if (is_dir($compiledViewsPath)) {
|
|
// Limit to most recently modified compiled views (top 200)
|
|
$viewFiles = glob($compiledViewsPath . '/*.php');
|
|
if ($viewFiles) {
|
|
// Sort by modification time, newest first
|
|
usort($viewFiles, fn($a, $b) => filemtime($b) - filemtime($a));
|
|
$viewFiles = array_slice($viewFiles, 0, 200);
|
|
preloadFiles($viewFiles);
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// SUMMARY (logged to error_log for debugging)
|
|
// =============================================================================
|
|
|
|
if (php_sapi_name() === 'cli') {
|
|
echo "OPcache Preload Complete: {$preloadedCount} files preloaded, {$skippedCount} skipped\n";
|
|
echo "Memory usage: " . round(memory_get_usage(true) / 1024 / 1024, 2) . " MB\n";
|
|
} else {
|
|
error_log("OPcache Preload: {$preloadedCount} files preloaded, {$skippedCount} skipped");
|
|
}
|