Your project uses dangerous command injection functions

More information: https://insight.symfony.com/what-we-analyse/php.use_command_injection_function

in scripts/init.php, line 150
  1. if ($overrides !== null) {
  2. $environment = array_merge((array) getenv(), $overrides);
  3. }
  4. $process = proc_open(
    proc_open() is vulnerable to command injection attacks. Use the Symfony Process component instead.
    Time to fix: about 4 hours
    Read doc Open Issue Permalink Copy Prompt
    Last edited by Fery Wardiyanto
  5. $command,
  6. [
  7. 0 => ['pipe', 'r'],
  8. 1 => ['pipe', 'w'],
  9. 2 => ['pipe', 'w'],

Your project uses discouraged functions to kill scripts

More information: https://insight.symfony.com/what-we-analyse/php.use_exit_function

in scripts/init.php, line 712
  1. return true;
  2. }
  3. if (realpath($_SERVER['SCRIPT_FILENAME'] ?? '') === __FILE__) {
  4. exit(main());
    This line stops the execution flow, without explanation. If this is for debug, you should remove it. If this is to deal with an error, use exceptions instead.
    Time to fix: about 4 hours
    Read doc Open Issue Permalink Copy Prompt
    Last edited by Fery Wardiyanto
  5. }

Your project should not use global variables or functions 18

More information: https://insight.symfony.com/what-we-analyse/php.use_global_variable_or_function

in scripts/init.php, line 27
  1. /**
  2. * Builds the default package name from host username and directory name.
  3. *
  4. * Falls back to the template name when no username can be determined.
  5. */
  6. function defaultPackageName(string $dirName, ?string $username): string
    defaultPackageName() adds to the global scope. Prefer class properties or methods to let other developers know what this relates to.
    Last edited by Fery Wardiyanto
  7. {
  8. if ($username === null || $username === '') {
  9. return 'projek-xyz/template';
  10. }
in scripts/init.php, line 45
  1. /**
  2. * Resolves the host username from the environment.
  3. *
  4. * Checks USER, LOGNAME, then USERNAME for cross-platform coverage.
  5. */
  6. function templateUsername(): ?string
    templateUsername() adds to the global scope. Prefer class properties or methods to let other developers know what this relates to.
    Last edited by Fery Wardiyanto
  7. {
  8. foreach (['USER', 'LOGNAME', 'USERNAME'] as $variable) {
  9. $value = getenv($variable);
  10. if ($value !== false && $value !== '') {
in scripts/init.php, line 66
  1. * Returns [package, warning]: null package means end of input (skip),
  2. * an invalid answer falls back to the default with a warning message.
  3. *
  4. * @return array{0: ?string, 1: ?string}
  5. */
  6. function resolvePackageInput(?string $line, string $default): array
    resolvePackageInput() adds to the global scope. Prefer class properties or methods to let other developers know what this relates to.
    Last edited by Fery Wardiyanto
  7. {
  8. if ($line === null) {
  9. return [null, null];
  10. }
in scripts/init.php, line 96
  1. * Returns null on end of input, otherwise the chosen or default name.
  2. *
  3. * @param resource $in
  4. * @param resource $out
  5. */
  6. function promptPackageName($in, $out, string $default): ?string
    promptPackageName() adds to the global scope. Prefer class properties or methods to let other developers know what this relates to.
    Last edited by Fery Wardiyanto
  7. {
  8. fwrite($out, 'Package name [' . $default . ']: ');
  9. $line = fgets($in);
  10. [$package, $warning] = resolvePackageInput($line === false ? null : $line, $default);
in scripts/init.php, line 119
  1. * Defaults to no on an empty answer or end of input.
  2. *
  3. * @param resource $in
  4. * @param resource $out
  5. */
  6. function promptGitInit($in, $out, string $package): bool
    promptGitInit() adds to the global scope. Prefer class properties or methods to let other developers know what this relates to.
    Last edited by Fery Wardiyanto
  7. {
  8. fwrite($out, 'Do you want to git init your ' . ANSI_YELLOW . $package . ANSI_RESET . ' repo? [y/N] ');
  9. $line = fgets($in);
in scripts/init.php, line 142
  1. * Overrides are merged over the current environment; null inherits it.
  2. *
  3. * @param ?array<string, string> $overrides
  4. * @return array{0: int, 1: string}
  5. */
  6. function runCommand(string $command, ?array $overrides = null): array
    runCommand() adds to the global scope. Prefer class properties or methods to let other developers know what this relates to.
    Last edited by Fery Wardiyanto
  7. {
  8. $environment = null;
  9. if ($overrides !== null) {
  10. $environment = array_merge((array) getenv(), $overrides);
in scripts/init.php, line 180
  1. /**
  2. * Checks whether a command can be executed.
  3. *
  4. * @param ?array<string, string> $overrides
  5. */
  6. function isCommandAvailable(string $command, ?array $overrides = null): bool
    isCommandAvailable() adds to the global scope. Prefer class properties or methods to let other developers know what this relates to.
    Last edited by Fery Wardiyanto
  7. {
  8. [$code] = runCommand($command . ' --version', $overrides);
  9. return $code === 0;
  10. }
in scripts/init.php, line 195
  1. * Returns a status word: git-not-found, already-git, no-identity,
  2. * committed, init-failed, or commit-failed.
  3. *
  4. * @param ?array<string, string> $overrides
  5. */
  6. function initializeGitRepository(string $root, string $message, ?array $overrides = null): string
    initializeGitRepository() adds to the global scope. Prefer class properties or methods to let other developers know what this relates to.
    Last edited by Fery Wardiyanto
  7. {
  8. if (! isCommandAvailable('git', $overrides)) {
  9. return 'git-not-found';
  10. }
in scripts/init.php, line 252
  1. * Interacts only when $interactive is true and github mode is off, then
  2. * transforms, verifies, strips the bootstrap itself, and finally
  3. * initializes git when requested — so the single initial commit contains
  4. * the bootstrapped state rather than the template state.
  5. */
  6. function bootstrapProject(string $root, $stdin, $stdout, bool $interactive, array $env): int
    bootstrapProject() adds to the global scope. Prefer class properties or methods to let other developers know what this relates to.
    Last edited by Fery Wardiyanto
  7. {
  8. $target = $env['GITHUB_REPOSITORY'] ?? null;
  9. $githubMode = is_string($target) && $target !== '';
  10. $initGit = false;
in scripts/init.php, line 329
  1. *
  2. * composer forks script hooks onto a real terminal only while it is
  3. * interactive (EventDispatcher::executeTty); with --no-interaction it
  4. * runs them on a pipe, so stream_isatty() mirrors composer's own mode.
  5. */
  6. function main(): int
    main() adds to the global scope. Prefer class properties or methods to let other developers know what this relates to.
    Last edited by Fery Wardiyanto
  7. {
  8. return bootstrapProject(
  9. dirname(__DIR__),
  10. STDIN,
  11. STDOUT,
in scripts/init.php, line 348
  1. * Skips dependency directories, binary files, and this script itself.
  2. * The visitor receives the relative path and the file content.
  3. *
  4. * @param callable(string, string): void $visitor
  5. */
  6. function walkTemplateFiles(string $root, callable $visitor): void
    walkTemplateFiles() adds to the global scope. Prefer class properties or methods to let other developers know what this relates to.
    Last edited by Fery Wardiyanto
  7. {
  8. $skipped = ['/vendor/', '/node_modules/', '/.git/'];
  9. $iterator = new RecursiveIteratorIterator(
  10. new RecursiveDirectoryIterator($root, FilesystemIterator::SKIP_DOTS),
in scripts/init.php, line 395
  1. *
  2. * Returns the sorted list of changed files relative to the root.
  3. *
  4. * @return string[]
  5. */
  6. function rewriteTemplateReferences(string $root, string $target): array
    rewriteTemplateReferences() adds to the global scope. Prefer class properties or methods to let other developers know what this relates to.
    Last edited by Fery Wardiyanto
  7. {
  8. $patterns = ['projek-xyz/php-lib-template', 'projek-xyz/template'];
  9. $changed = [];
  10. walkTemplateFiles($root, function (
in scripts/init.php, line 432
  1. * Resets root package versions to 0.0.0.
  2. *
  3. * Touches package.json and the two root entries of package-lock.json;
  4. * dependency versions and composer.lock stay untouched.
  5. */
  6. function resetPackageVersions(string $root): void
    resetPackageVersions() adds to the global scope. Prefer class properties or methods to let other developers know what this relates to.
    Last edited by Fery Wardiyanto
  7. {
  8. $targets = ['package.json', 'package-lock.json'];
  9. foreach ($targets as $file) {
  10. $path = $root . '/' . $file;
in scripts/init.php, line 467
  1. }
  2. /**
  3. * Removes a file or directory tree, tolerating missing paths.
  4. */
  5. function removePath(string $path): bool
    removePath() adds to the global scope. Prefer class properties or methods to let other developers know what this relates to.
    Last edited by Fery Wardiyanto
  6. {
  7. if (is_file($path)) {
  8. return unlink($path);
  9. }
in scripts/init.php, line 504
  1. * that regenerates them is available. Returns the sorted removed paths.
  2. *
  3. * @param array{composer?: bool, npm?: bool} $capabilities
  4. * @return string[]
  5. */
  6. function removeTemplateOnlyFiles(string $root, bool $githubMode, array $capabilities): array
    removeTemplateOnlyFiles() adds to the global scope. Prefer class properties or methods to let other developers know what this relates to.
    Last edited by Fery Wardiyanto
  7. {
  8. $targets = [
  9. '.github/README.md',
  10. '.github/workflows/init.yml',
  11. '.agents/rules',
in scripts/init.php, line 543
  1. /**
  2. * Activates the commented export-ignore list in .gitattributes.
  3. *
  4. * Returns the number of entries activated.
  5. */
  6. function uncommentExportIgnoreList(string $root): int
    uncommentExportIgnoreList() adds to the global scope. Prefer class properties or methods to let other developers know what this relates to.
    Last edited by Fery Wardiyanto
  7. {
  8. $path = $root . '/.gitattributes';
  9. if (! is_file($path)) {
  10. return 0;
in scripts/init.php, line 581
  1. * An empty array means the tree is clean. With no target (interactive
  2. * name prompt skipped) reference and name checks are omitted.
  3. *
  4. * @return string[]
  5. */
  6. function verifyTransformation(string $root, ?string $target, bool $githubMode): array
    verifyTransformation() adds to the global scope. Prefer class properties or methods to let other developers know what this relates to.
    Last edited by Fery Wardiyanto
  7. {
  8. $failures = [];
  9. $mustBeGone = [
  10. '.github/README.md',
in scripts/init.php, line 662
  1. /**
  2. * Removes the post-create-project-cmd hook from the project composer.json.
  3. *
  4. * Returns true when the hook was present and has been stripped.
  5. */
  6. function removeSelfFromComposerJson(string $root): bool
    removeSelfFromComposerJson() adds to the global scope. Prefer class properties or methods to let other developers know what this relates to.
    Last edited by Fery Wardiyanto
  7. {
  8. $path = $root . '/composer.json';
  9. if (! is_file($path)) {
  10. return false;

Your project should use dedicated PHP string functions 6

More information: https://insight.symfony.com/what-we-analyse/php.use_string_function

in scripts/init.php, line 368
  1. $path = $file->getPathname();
  2. $relative = str_replace('\\', '/', ltrim(substr($path, strlen($root)), '/'));
  3. $skip = $path === __FILE__;
  4. foreach ($skipped as $directory) {
  5. if (strpos('/' . $relative . '/', $directory) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by Fery Wardiyanto
  6. $skip = true;
  7. break;
  8. }
  9. }
in scripts/init.php, line 380
  1. continue;
  2. }
  3. $content = file_get_contents($path);
  4. if ($content === false || strpos(substr($content, 0, 8192), "\0") !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by Fery Wardiyanto
  5. continue;
  6. }
  7. $visitor($relative, $content);
  8. }
in scripts/init.php, line 409
  1. $root,
  2. $target,
  3. $patterns,
  4. &$changed
  5. ): void {
  6. if (strpos($content, 'projek-xyz/') === false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by Fery Wardiyanto
  7. return;
  8. }
  9. $replaced = str_replace($patterns, $target, $content);
in scripts/init.php, line 600
  1. }
  2. }
  3. $packageJson = file_get_contents($root . '/package.json');
  4. if ($packageJson === false || strpos($packageJson, '"version": "0.0.0"') === false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by Fery Wardiyanto
  5. $failures[] = 'package.json version is not 0.0.0';
  6. }
  7. $attributes = file_get_contents($root . '/.gitattributes');
  8. $totalEntries = $attributes === false ? 0 : preg_match_all('/^.*export-ignore$/m', $attributes);
in scripts/init.php, line 638
  1. string $content
  2. ) use (
  3. &$failures,
  4. $patterns
  5. ): void {
  6. if (strpos($content, $patterns[0]) !== false || strpos($content, $patterns[1]) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by Fery Wardiyanto
  7. $failures[] = 'residual template reference in ' . $relative;
  8. }
  9. });
  10. }
in scripts/init.php, line 638
  1. string $content
  2. ) use (
  3. &$failures,
  4. $patterns
  5. ): void {
  6. if (strpos($content, $patterns[0]) !== false || strpos($content, $patterns[1]) !== false) {
    Consider replacing strpos() with str_contains() for improved readability.
    Last edited by Fery Wardiyanto
  7. $failures[] = 'residual template reference in ' . $relative;
  8. }
  9. });
  10. }