Search by

taha20 / laravel-installer

khoshkhu95

A web-based step-by-step installer wizard for Laravel applications

Package info

github.com/khoshkhu95/laravel-installer

pkg:composer/taha20/laravel-installer

Statistics

Installs: 30

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

v1.0.7 2026-08-30 14:24 UTC

This package is auto-updated.

Last update: 2026-08-30 14:26:23 UTC


README

یک نصب‌کننده وب‌بیس (Web-based Installer) به شکل ویزارد چند مرحله‌ای برای پروژه‌های لاراول.

مراحل ویزارد

  1. خوش‌آمدگویی
  2. بررسی پیش‌نیازهای سرور (نسخه PHP و اکستنشن‌ها)
  3. بررسی پرمیشن پوشه‌ها و فایل‌ها
  4. دریافت و تست اتصال اطلاعات دیتابیس
  5. نوشتن .env، ساخت APP_KEY (در صورت نیاز) و اجرای مایگریشن
  6. ساخت حساب مدیر سیستم
  7. قفل شدن نصب‌کننده و اتمام نصب

دستور نصب پکیج

composer require taha20/laravel-installer

انتشار فایل‌های قابل سفارشی‌سازی

php artisan vendor:publish --tag=installer-config
php artisan vendor:publish --tag=installer-views
php artisan vendor:publish --tag=installer-lang

فعال‌سازی اجبار نصب در کل سایت (اختیاری)

اگر می‌خواهید تا وقتی نصب کامل نشده، هیچ صفحه‌ای از سایت باز نشود، میدلور را در bootstrap/app.php (لاراول ۱۱ به بعد) یا app/Http/Kernel.php (لاراول ۱۰) به گروه web اضافه کنید:

// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
    $middleware->web(append: [
        \Taha20\LaravelInstaller\Http\Middleware\RedirectIfNotInstalled::class,
    ]);
})

استفاده

بعد از نصب پکیج، آدرس زیر را در مرورگر باز کنید:

https://your-domain.com/installer

اجرای Seeder در پروژه‌های ماژولار

برخلاف مایگریشن‌ها که فایل‌محورند و مسیرشان با الگوهای glob قابل کشف خودکار است، Seeder ها کلاس PHP هستند و namespace هر ماژول از روی مسیر فایلش قابل‌اعتماد قابل حدس زدن نیست. به همین دلیل باید هر Seeder را صریحاً در config/installer.php معرفی کنی:

'seeder_classes' => [
    \Database\Seeders\DatabaseSeeder::class,
    \Modules\Blog\Database\Seeders\BlogDatabaseSeeder::class,
    \Modules\Shop\Database\Seeders\ShopDatabaseSeeder::class,
],

هر کلاس در این لیست، دقیقاً مثل مایگریشن‌ها، در یک درخواست AJAX جداگانه اجرا می‌شود (/installer/migrate/seed/prepare یک‌بار برای ساخت لیست، و /installer/migrate/seed/step به‌صورت حلقه‌ای برای اجرای هر کلاس) تا اگر Seeder یک ماژول داده‌ی زیادی وارد کند، تایم‌اوت رخ ندهد.

اگر کلاسی در لیست وجود نداشته باشد (class_exists() false برگرداند — مثلاً ماژول حذف شده)، آن کلاس نادیده گرفته می‌شود و نصب متوقف نمی‌شود.

برای غیرفعال‌کردن کامل اجرای seeder ها (مثلاً برای محیط‌هایی که فقط ساختار جدول لازم است، نه داده‌ی نمونه)، کافیست 'run_seeders' => false را در کانفیگ تنظیم کنی.

اجرای تکه‌تکه (Chunked) مایگریشن‌ها برای جلوگیری از Timeout

روی سرورهای اشتراکی معمولاً max_execution_time بین ۳۰ تا ۶۰ ثانیه است. اگه پروژه مایگریشن‌های زیادی داشته باشه، اجرای یکجای php artisan migrate ممکنه باعث خطای ۵۰۴ یا سفید شدن صفحه بشه.

برای حل این مشکل، مرحله مایگریشن به ۳ درخواست AJAX جدا تقسیم شده:

  1. /installer/migrate/prepare — یک بار صدا زده می‌شود: فایل .env را می‌نویسد، config:clear را اجرا می‌کند و لیست مایگریشن‌های اجرا‌نشده را در Session ذخیره کرده و تعداد کل را برمی‌گرداند.
  2. /installer/migrate/step — به صورت حلقه‌ای (یکی پس از دیگری) توسط جاوااسکریپت صدا زده می‌شود. هر بار فقط یک فایل مایگریشن را اجرا و از صف Session حذف می‌کند. چون هر درخواست HTTP فقط یک فایل را اجرا می‌کند، مدت زمان هر درخواست کوتاه می‌ماند و ریسک تایم‌اوت عملاً از بین می‌رود.
  3. /installer/migrate/seed — بعد از پایان همه مایگریشن‌ها یک بار صدا زده می‌شود و seeder ها را اجرا می‌کند.

نکته فنی: تابع Migrator::run($paths) در لاراول اگر مسیر داده‌شده به .php ختم شود (به‌جای مسیر یک پوشه)، فقط همان فایل را (در صورتی که قبلاً اجرا نشده باشد) اجرا می‌کند. از همین ویژگی برای اجرای تک‌فایلی استفاده شده.

محدودیت این روش

اگر داخل یک فایل مایگریشن عملیات بسیار سنگینی انجام شود (مثلاً میلیون‌ها رکورد insert در یک حلقه)، همان یک درخواست AJAX مربوط به آن فایل هنوز می‌تواند تایم‌اوت بدهد، چون تقسیم‌بندی در سطح «فایل» است نه داخل خود فایل. راه‌حل‌های تکمیلی برای این حالت:

  • مایگریشن سنگین را به چند فایل مایگریشن کوچک‌تر بشکنید.
  • منطق پرکردن داده‌های حجیم را به یک Seeder جدا منتقل کنید و آن Seeder را هم به همین روش (چند درخواست AJAX، هر بار یک بخش از داده) تقسیم کنید.
  • برای پروژه‌هایی که واقعاً حجم داده بالا دارند، به‌جای اجرای همزمان در درخواست HTTP، از یک صف (queue) با درایور database یا redis استفاده کنید و مرحله مایگریشن را به یک Job پس‌زمینه بسپارید؛ صفحه نصب‌کننده فقط وضعیت Job را هر چند ثانیه یک‌بار poll می‌کند. این حالت پیچیده‌تر است و در این نسخه پیاده‌سازی نشده.
  • در php.ini یا تنظیمات Nginx/PHP-FPM مقدار max_execution_time و fastcgi_read_timeout را برای مسیر /installer/* کمی بالاتر ببرید (مثلاً ۱۲۰ ثانیه) تا حاشیه امنیت بیشتری برای فایل‌های نسبتاً سنگین وجود داشته باشد. در کد کنترلر هم @set_time_limit(120) قبل از اجرای هر مایگریشن صدا زده می‌شود (در صورتی که هاست اجازه دهد).

پشتیبانی از ستون‌های سفارشی جدول users (پروژه‌های مختلف)

جدول users در پروژه‌های مختلف ممکن است ستون‌های سفارشی و NOT NULL داشته باشد که در فرم ساخت ادمین نصب‌کننده وجود ندارند (مثلاً role_id, company_id, status). اگر این ستون‌ها مقداردهی نشوند، insert با خطای دیتابیس (Integrity constraint violation) مواجه می‌شود.

راه‌حل: قبل از تحویل/نصب پروژه، مقدار پیش‌فرض این ستون‌ها را در config/installer.php داخل کلید admin_extra_fields مشخص کنید:

// config/installer.php
'admin_extra_fields' => [
    'role_id' => 1,
    'is_active' => true,
],

مقدار می‌تواند یک closure هم باشد، برای زمانی که مقدار باید در لحظه محاسبه شود (مثلاً بعد از اجرای seeder ها، از جدولی که تازه پر شده):

'admin_extra_fields' => fn () => [
    'company_id' => \App\Models\Company::first()?->id,
],

⚠️ این مرحله را برای هر پروژه‌ی جدید جداگانه چک کنید — چون ساختار جدول users معمولاً بین پروژه‌ها فرق می‌کند، فراموش‌کردن این تنظیم شایع‌ترین علت شکست مرحله‌ی ساخت ادمین است.

شبکه‌ی ایمنی: حتی اگر admin_extra_fields را تنظیم نکنید یا ستونی را جا بیندازید، نصب‌کننده به‌جای نمایش خطای خام SQL، پیام قابل‌فهمی نشان می‌دهد که دقیقاً نام ستون مشکل‌دار و راه رفعش را مشخص می‌کند (برای MySQL و PostgreSQL). با این حال بهتر است این خطا اصلاً رخ ندهد و از قبل کانفیگ را تنظیم کرده باشید.

نکات امنیتی مهم

  • بعد از اتمام نصب، حتماً دسترسی به مسیر /installer از طریق وب‌سرور (Nginx/Apache) هم مسدود شود؛ میدلور RedirectIfInstalled این کار را در سطح لاراول انجام می‌دهد اما یک لایه امنیتی اضافه در وب‌سرور توصیه می‌شود.

ساختار پوشه‌ها

laravel-installer/
├── composer.json
├── config/installer.php
├── routes/web.php
├── src/
│   ├── InstallerServiceProvider.php
│   ├── Console/InstallerResetCommand.php
│   └── Http/
│       ├── Controllers/InstallerController.php
│       └── Middleware/
│           ├── RedirectIfInstalled.php
│           └── RedirectIfNotInstalled.php
└── resources/
    ├── views/installer/*.blade.php
    └── lang/{fa,en}/installer.php