sbamtr/laravel-source-encrypter
Encrypt PHP source files in your Laravel app to protect code before distribution. Artisan commands encrypt files using a secret key, and a runtime loader decrypts them transparently so they execute normally without exposing your source.
composer require sbamtr/laravel-source-encrypter gets you the Artisan tooling, but encryption is only half the story — the encrypted files are decrypted at runtime by the phpBolt PHP extension (bolt.so). Nothing will execute until that extension is compiled for the exact PHP version/ABI of the target machine and enabled in php.ini. Install it on your build box and every box that will run the app.^1.6.0 if you are on Laravel 11 or 12. 1.6.0 is the release that adds Laravel 11 & 12 support (PR #43, first contribution from @ionikdev). Anything below 1.6.0 will fail Composer resolution against an L11/L12 skeleton, so check composer show sbamtr/laravel-source-encrypter against your framework constraint before you start debugging anything else. On L10 and below, 1.5.0 still works.php artisan vendor:publish for the SiavashBamshadnia\LaravelSourceEncrypter provider and open config/source-encrypter.php. This is the whole API surface: an encryption key and the list of files/paths to encrypt. Look at the service provider and the phpBolt README next — the package is a thin wrapper, so every real limitation you hit is a phpBolt limitation. Provider auto-discovery is unchanged in L11/L12 (no config/app.php entry to add).php artisan list | grep -i encrypt. The package exposes an encrypt command that reads your configured paths, encrypts each .php file in place (or into the configured destination, depending on version), and preserves directory structure. Because the project has very few dependents, confirm behaviour against the installed tag rather than trusting a blog post.app/. Start by encrypting only app/, run the resulting artifact on a staging box that has phpBolt enabled, and confirm the app boots (php artisan about) and a route responds before you widen the path list.Treat encryption as a build step, never a dev step. Keep the repository plaintext. Local php artisan serve, tests, PHPStan, and Xdebug all need readable source. Add a composer script or Makefile target (build:encrypted) that: installs production deps → config:cache/route:cache → runs the encrypter → tars the artifact. CI produces the encrypted bundle; developers never run the encrypter against their working tree (it mutates files).
Scope the path list deliberately, and mind the L11/L12 skeleton. Typical config: encrypt app/, routes/, database/migrations (if the customer runs migrations), and custom packages/ you own. In Laravel 11/12 the bootstrap surface moved — bootstrap/app.php and bootstrap/providers.php are now the wiring points rather than app/Http/Kernel.php and config/app.php. Encrypting bootstrap/providers.php is fine (it's plain PHP loaded through phpBolt), but keep config/, public/, resources/views/*.blade.php, bootstrap/cache/, storage/, and vendor/ plaintext. Encrypting vendor breaks third-party licences and gets clobbered by composer install.
Pair it with composer install --no-dev --classmap-authoritative. Encrypting app/ while leaving a chatty vendor/ and debug tooling installed gives a false sense of protection — most business logic leaks through logs, stack traces, and .env files anyway. Ship APP_DEBUG=false, no dev dependencies, and a locked-down .env.
Per-customer keys. If you sell licences, generate a key per deployment (SOURCE_ENCRYPTER_KEY injected from your secret manager) so a leaked artifact can't be trivially reused. Keep a build matrix entry per customer rather than re-encrypting by hand.
Smoke-test the encrypted artifact in a container that mirrors production. Build a Docker image with phpBolt compiled in, drop the encrypted app in, then run php artisan about, php artisan route:list, php artisan config:show app, a queue job, and one HTTP request. On L11/L12 also hit a health-check route and a queued listener — the slim skeleton defers more wiring to bootstrap/app.php, so a bad artifact often fails later than it used to. That single test catches ~90% of the failures below.
Keep version control of the plaintext. Encryption is not a backup and not reversible without your key. Tag the exact commit that produced each shipped artifact so production stack traces can be mapped back to readable source.
^1.6.0 and audit the diff — this release is one community PR from a new contributor, so review what changed before trusting it in a paid artifact pipeline..blade.php as text. Either leave views plaintext or run php artisan view:cache on the unencrypted build and ship the compiled views, never running view:clear on the target.opcache.preload pointing at encrypted files requires the extension loaded before preload runs. Test it explicitly if you preload.composer dump-autoload -o scans files. Generate the optimised autoloader before encrypting, and don't re-run Composer on the customer's box.php -l all break on encrypted files. Run them in the plaintext pipeline only. L11/L12's default Pint/PHPStan setup should never see an encrypted tree.APP_BUILD env var — in L11/L12, bootstrap/app.php is loaded very early, so prefer env/metadata over editing it if you also encrypt it).artisan migrate. Either run migrations at build time or leave database/ plaintext.storage/, bootstrap/cache/, and config/ writable and unencrypted — Laravel writes to them at runtime, and cached config is already plain PHP you'll want to inspect during incidents. php artisan config:cache on L11/L12 still emits plain PHP, so it is not a substitute for encryption.How can I help you explore Laravel packages today?