🌐 AI搜索 & 代理 主页
Skip to content
Open
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
30 changes: 24 additions & 6 deletions local/php/composer.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,34 @@ func Composer(dir string, args, env []string, stdout, stderr, logger io.Writer,
if composerPath := os.Getenv("SYMFONY_COMPOSER_PATH"); composerPath != "" {
debugLogger.Debug().Str("SYMFONY_COMPOSER_PATH", composerPath).Msg("SYMFONY_COMPOSER_PATH has been defined. User is taking control over Composer detection and execution.")
e.Args = append([]string{composerPath}, args...)
} else if path, err := e.findComposer(composerBin); err == nil && isPHPScript(path) {
e.Args = append([]string{"php", path}, args...)
} else if path, err := e.findComposer(composerBin); err == nil {
if isNixWrapper(path) {
// Nix wrappers are executable binaries that wrap the PHP script
// Execute them directly, not with php
e.Args = append([]string{path}, args...)
} else if isPHPScriptDirect(path) {
// Regular PHP script or PHAR file
e.Args = append([]string{"php", path}, args...)
} else {
// Found a file but it's not a valid composer
reason := fmt.Sprintf("Detected Composer file (%s) is not a valid PHAR or PHP script.", path)
fmt.Fprintln(logger, " WARNING:", reason)
fmt.Fprintln(logger, " Downloading Composer for you, but it is recommended to install Composer yourself, instructions available at https://getcomposer.org/download/")
binDir := filepath.Join(util.GetHomeDir(), "composer")
if path, err = downloadComposer(binDir, debugLogger); err != nil {
return ComposerResult{
code: 1,
error: errors.Wrap(err, "unable to find composer, get it at https://getcomposer.org/download/"),
}
}
e.Args = append([]string{"php", path}, args...)
fmt.Fprintf(logger, " (running %s)\n\n", e.CommandLine())
}
} else {
// No composer found at all
reason := "No Composer installation found."
if path != "" {
reason = fmt.Sprintf("Detected Composer file (%s) is not a valid PHAR or PHP script.", path)
}
fmt.Fprintln(logger, " WARNING:", reason)
fmt.Fprintln(logger, " Downloading Composer for you, but it is recommended to install Composer yourself, instructions available at https://getcomposer.org/download/")
// we don't store it under bin/ to avoid it being found by findComposer as we want to only use it as a fallback
binDir := filepath.Join(util.GetHomeDir(), "composer")
if path, err = downloadComposer(binDir, debugLogger); err != nil {
return ComposerResult{
Expand Down
3 changes: 3 additions & 0 deletions local/php/testdata/php_scripts/.nix-wrapper-invalid-wrapped
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env bash

echo 'Not a PHP script'
4 changes: 4 additions & 0 deletions local/php/testdata/php_scripts/.nix-wrapper-wrapped
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/nix/store/ka93claiq3y8ydzj6ln0kan2skq9zyp2-php-with-extensions-8.4.13/bin/php
<?php

echo 'Nix wrapped Composer';
2 changes: 2 additions & 0 deletions local/php/testdata/php_scripts/nix-wrapper
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ELF binary wrapper - not a PHP script
This simulates a Nix C wrapper binary
2 changes: 2 additions & 0 deletions local/php/testdata/php_scripts/nix-wrapper-invalid
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ELF binary wrapper - not a PHP script
This simulates a Nix C wrapper binary but has no valid wrapped file
30 changes: 30 additions & 0 deletions local/php/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,43 @@ import (
"bufio"
"bytes"
"os"
"path/filepath"
)

// isPHPScript checks that the provided file is indeed a phar/PHP script (not a .bat file)
// It also handles Nix wrappers that wrap the actual PHP script
func isPHPScript(path string) bool {
if path == "" {
return false
}

if isPHPScriptDirect(path) {
return true
}

// Check for Nix-style wrappers (e.g., composer -> .composer-wrapped)
return isNixWrapper(path)
}

// isNixWrapper checks if the file is a Nix wrapper binary with a valid wrapped PHP script
func isNixWrapper(path string) bool {
if path == "" {
return false
}

dir := filepath.Dir(path)
base := filepath.Base(path)
wrappedPath := filepath.Join(dir, "."+base+"-wrapped")

if _, err := os.Stat(wrappedPath); err == nil {
return isPHPScriptDirect(wrappedPath)
}

return false
}

// isPHPScriptDirect checks if the file itself is a PHP script
func isPHPScriptDirect(path string) bool {
file, err := os.Open(path)
if err != nil {
return false
Expand Down
13 changes: 13 additions & 0 deletions local/php/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,16 @@ func (s *UtilsSuite) TestIsPHPScript(c *C) {
c.Assert(isPHPScript(filepath.Join(dir, validScripts)), Equals, true)
}
}

func (s *UtilsSuite) TestIsPHPScriptNixWrapper(c *C) {
dir, err := filepath.Abs("testdata/php_scripts")
c.Assert(err, IsNil)

// Test Nix wrapper with valid PHP script
c.Assert(isPHPScript(filepath.Join(dir, "nix-wrapper")), Equals, true,
Commentf("Nix wrapper with valid PHP wrapped file should be detected as PHP script"))

// Test Nix wrapper with invalid wrapped file
c.Assert(isPHPScript(filepath.Join(dir, "nix-wrapper-invalid")), Equals, false,
Commentf("Nix wrapper with invalid wrapped file should not be detected as PHP script"))
}