symfony/process
Symfony Process component runs external commands in separate processes with robust control over arguments, environment, timeouts, and working directory. Capture stdout/stderr, stream live output, manage input, and handle exit codes reliably across platforms.
Artisan commands, queues (via RunProcessMessage), and service containers. The Process facade (if added via Laravel extensions) aligns with Laravel’s service provider pattern.Process facade (if using symfony/process as a drop-in). Composer dependency (symfony/process:^8.0) is trivial.spatie/laravel-process (if available) can abstract the API further (e.g., Process::run('command')).RunProcessMessage (Symfony Messenger), enabling async subprocess execution (e.g., background image processing).shell_exec() in custom commands with Process::fromShellCommandline() for safer CLI tool invocation.| Risk Area | Mitigation |
|---|---|
| Windows Compatibility | Test environment variable limits (32KB) and MSYS escaping fixes (CVE-2026-24739). Use Process::isOutputReadable() to handle platform quirks. |
| Resource Leaks | Always call ->stop() or use try-finally for long-running processes. Symfony Process auto-closes pipes, but Laravel wrappers may need cleanup logic. |
| Output Corruption | Use ->setTimeout() and ->getOutput() to avoid mixed STDOUT/STDERR in PTY mode (fixed in v7.2.5+). For real-time streaming, use ->run(function($type, $buffer) { ... }). |
| Security Misconfigurations | Validate all commands/args (e.g., Process::fromShellCommandline() escapes args by default). Avoid dynamic command concatenation. |
| PHP Version Lock-in | Laravel 10+ uses PHP 8.1+ (compatible with symfony/process:^8.0). For older Laravel, use ^7.4 or ^6.4 branches. |
| Dependency Bloat | Minimal footprint (~10KB). No risk of pulling in Symfony’s full framework. |
git status) or long-running processes (e.g., ffmpeg encoding)? The latter may need custom signal handling.SIGINT handling)?HttpClient, Messenger), integration is seamless. Otherwise, minimal learning curve.RunProcessMessage in Laravel Queues (via Symfony Messenger bridge).shell_exec() in custom commands.ProcessTestCase from Symfony).| Phase | Action Items |
|---|---|
| Assessment | Audit all subprocess calls (shell_exec, exec, popen, proc_open). Categorize by use case (CLI tools, background jobs, real-time output). |
| Pilot Implementation | Replace 1–2 high-risk subprocess calls (e.g., a security-sensitive git command or a long-running ffmpeg job) with symfony/process. |
| Facade/Wrapper | Create a Laravel service provider to register a Process facade (optional but recommended for consistency). Example: |
| ```php | |
| // app/Providers/ProcessServiceProvider.php | |
| namespace App\Providers; | |
| use Symfony\Component\Process\Process; | |
| class ProcessServiceProvider extends ServiceProvider { | |
| public function register() { | |
| $this->app->singleton('process', fn() => new Process([])); | |
| } | |
| } | |
| Queue Integration | For async processes, use RunProcessMessage with Laravel Queues: |
| ```php | |
| // app/Console/Commands/RunAsyncProcess.php | |
| use Symfony\Component\Process\Exception\ProcessFailedException; | |
| use Symfony\Component\Process\Process; | |
| class RunAsyncProcess extends Command { | |
| protected function handle() { | |
| $process = new Process(['ls', '-la']); | |
| $process->run(); | |
| if (!$process->isSuccessful()) { | |
| throw new ProcessFailedException($process); | |
| } | |
| } | |
| } | |
| Testing | Write integration tests for subprocess calls. Use ProcessTestCase or mock Process in unit tests. Example: |
| ```php | |
| // tests/Feature/ProcessTest.php | |
| public function test_process_execution() { | |
| $process = new Process(['echo', 'test']); | |
| $process->run(); | |
| $this->assertEquals('test', trim($process->getOutput())); | |
| } | |
| Rollout | Gradually replace remaining subprocess calls. Monitor for: |
| - Performance regressions (e.g., slower CLI tool execution). | |
| - Windows-specific issues (e.g., path escaping). | |
- Output formatting differences (e.g., STDERR mixing with STDOUT). |
symfony/process:^8.0.symfony/process:^7.4.symfony/process:^6.4 (but note fewer security updates).proc_open (enabled by default on most PHP installations). For Windows, ensure pipes are supported.C:\path with spaces).proc_open is not disabledHow can I help you explore Laravel packages today?