Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions evals/evals.json
Original file line number Diff line number Diff line change
Expand Up @@ -455,5 +455,26 @@
"description": "Recommends matching CI via the project's runner / Docker (e.g. make code-style or docker run php:8.2-cli)"
}
]
},
{
"name": "php-subprocess-from-web-sapi",
"prompt": "This PHP service spawns a subprocess to run a CLI script. It works from our console command and cron, but crashes with \"ValueError: First element must contain a non-empty program name\" when the same code runs behind Apache mod_php. Fix it:\n\n```php\n<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Service;\n\nuse Symfony\\Component\\Process\\Process;\n\nfinal class IndexBuilder\n{\n public function build(string $script): void\n {\n $process = new Process([\\PHP_BINARY, $script]);\n $process->mustRun();\n }\n}\n```",
"assertions": [
{
"type": "content_contains",
"value": "PhpExecutableFinder",
"description": "Resolves the PHP binary via PhpExecutableFinder instead of \\PHP_BINARY"
},
{
"type": "content_contains",
"value": "find(false)",
"description": "Uses find(false) so console/cron behaviour is unchanged"
},
{
"type": "content_regex",
"value": "SAPI|mod_php|web|empty",
"description": "Explains that \\PHP_BINARY is empty under a non-CLI SAPI"
}
]
}
]
43 changes: 43 additions & 0 deletions skills/php-modernization/references/symfony-patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,49 @@ final class NotificationService
}
```

## Spawning a PHP subprocess (`Process` component)

`\PHP_BINARY` is an **empty string under a non-CLI SAPI** (Apache `mod_php`,
PHP-FPM). It only resolves to the interpreter path under the CLI SAPI. So
`new Process([\PHP_BINARY, $script, ...])` works from a console command, a
cron job, or CI, but throws from any web entry point:

```
ValueError: First element must contain a non-empty program name
at Symfony\Component\Process\Process::__construct()
```

The trap is that the CLI paths — the ones you test — pass, while the web path
fails only in production. Resolve the executable with `PhpExecutableFinder`
instead of reading the constant directly:

```php
<?php

declare(strict_types=1);

use Symfony\Component\Process\PhpExecutableFinder;
use Symfony\Component\Process\Process;

// find(false): do NOT append server-API arguments — we want the bare binary.
// Under CLI this returns \PHP_BINARY; under a web SAPI it falls through to
// PHP_BINDIR/php (e.g. /usr/local/bin/php in the php:*-apache image).
$php = (new PhpExecutableFinder())->find(false);

if (false === $php) {
throw new \RuntimeException('Could not locate the PHP CLI binary.');
}

$args = [$script, '--shard', '1/4']; // whatever the script needs
$process = new Process([$php, ...$args]);
$process->mustRun();
```

`find(false)` returns `\PHP_BINARY` under CLI, so console/cron/CI behaviour is
unchanged; it only differs where the constant would have been empty. Handle the
`false` return — a container without a CLI binary on `PATH` is a real
possibility. Never hardcode `/usr/bin/php`: the path varies across base images.

## Security Configuration

```php
Expand Down
Loading