diff --git a/commands/local_server_start.go b/commands/local_server_start.go index 9b2e0fde..2ad7ca94 100644 --- a/commands/local_server_start.go +++ b/commands/local_server_start.go @@ -31,6 +31,7 @@ import ( "path/filepath" "syscall" + "github.com/dunglas/frankenphp" "github.com/pkg/errors" "github.com/rs/zerolog" "github.com/soheilhy/cmux" @@ -68,6 +69,7 @@ var localServerStartCmd = &console.Command{ &console.StringFlag{Name: "p12", Usage: "Name of the file containing the TLS certificate to use in p12 format"}, &console.BoolFlag{Name: "no-tls", Usage: "Use HTTP instead of HTTPS"}, &console.BoolFlag{Name: "use-gzip", Usage: "Use GZIP"}, + &console.BoolFlag{Name: "frankenphp", Usage: "Use FrankenPHP (built-in) instead of PHP FPM"}, }, Action: func(c *console.Context) error { ui := terminal.SymfonyStyle(terminal.Stdout, terminal.Stdin) @@ -201,52 +203,58 @@ var localServerStartCmd = &console.Command{ return err } - // We retrieve a reader on logs as soon as possible to be able to - // display error logs in case of startup errors. We can't do it - // later as the log file will already be deleted. - logs, err := phpPidFile.LogReader() - if err != nil { - return err - } + if phpPidFile == nil { + if err := phpStartCallback(); err != nil { + return err + } + } else { + // We retrieve a reader on logs as soon as possible to be able to + // display error logs in case of startup errors. We can't do it + // later as the log file will already be deleted. + logs, err := phpPidFile.LogReader() + if err != nil { + return err + } - if !reexec.IsChild() { - tailer.WatchAdditionalPidFile(phpPidFile) - } + if !reexec.IsChild() { + tailer.WatchAdditionalPidFile(phpPidFile) + } - // we run FPM in its own goroutine to allow it to run even when - // foreground is forced - go func() { errChan <- phpStartCallback() }() + // we run FPM in its own goroutine to allow it to run even when + // foreground is forced + go func() { errChan <- phpStartCallback() }() - // Give time to PHP to fail or to be ready - select { - case err := <-errChan: - terminal.Logger.Error().Msgf("Unable to start %s", phpPidFile.CustomName) + // Give time to PHP to fail or to be ready + select { + case err := <-errChan: + terminal.Logger.Error().Msgf("Unable to start %s", phpPidFile.CustomName) - humanizer := humanlog.NewHandler(&humanlog.Options{ - SkipUnchanged: true, - WithSource: true, - }) + humanizer := humanlog.NewHandler(&humanlog.Options{ + SkipUnchanged: true, + WithSource: true, + }) - buf := bytes.Buffer{} - fmt.Fprintf(&buf, "%s failed to start:\n", phpPidFile.CustomName) + buf := bytes.Buffer{} + fmt.Fprintf(&buf, "%s failed to start:\n", phpPidFile.CustomName) - scanner := bufio.NewScanner(logs) - for scanner.Scan() { - buf.Write(humanizer.Simplify(scanner.Bytes())) - buf.WriteRune('\n') - } + scanner := bufio.NewScanner(logs) + for scanner.Scan() { + buf.Write(humanizer.Simplify(scanner.Bytes())) + buf.WriteRune('\n') + } - ui.Error(buf.String()) + ui.Error(buf.String()) - if err != nil { - return err - } - return nil - case err := <-phpPidFile.WaitForPid(): - // PHP started, we can close logs and go ahead - logs.Close() - if err != nil { - return err + if err != nil { + return err + } + return nil + case err := <-phpPidFile.WaitForPid(): + // PHP started, we can close logs and go ahead + logs.Close() + if err != nil { + return err + } } } } @@ -343,6 +351,11 @@ var localServerStartCmd = &console.Command{ case <-shutdownCh: terminal.Eprintln("") terminal.Eprintln("Shutting down!") + + if config.FrankenPHP { + frankenphp.Shutdown() + } + if err := cleanupWebServerFiles(projectDir, pidFile); err != nil { return err } diff --git a/go.mod b/go.mod index 9e36f098..a5fc1d7a 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,11 @@ module github.com/symfony-cli/symfony-cli +replace github.com/symfony-cli/phpstore => github.com/dunglas/phpstore v1.0.6-0.20221112140329-97f1078dbfc1 + require ( github.com/compose-spec/compose-go v1.6.0 github.com/docker/docker v20.10.21+incompatible + github.com/dunglas/frankenphp v0.0.0-20221112134810-6a6dda5ed924 github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819 github.com/fabpot/local-php-security-checker/v2 v2.0.5 github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 @@ -24,11 +27,17 @@ require ( github.com/symfony-cli/phpstore v1.0.5 github.com/symfony-cli/terminal v1.0.4 github.com/syncthing/notify v0.0.0-20210616190510-c6b7342338d2 + go.uber.org/zap v1.23.0 golang.org/x/sync v0.1.0 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c gopkg.in/yaml.v2 v2.4.0 ) +require ( + go.uber.org/atomic v1.10.0 // indirect + go.uber.org/multierr v1.8.0 // indirect +) + require ( github.com/Microsoft/go-winio v0.6.0 // indirect github.com/NYTimes/gziphandler v1.1.1 diff --git a/go.sum b/go.sum index 89a7de8a..c22df12f 100644 --- a/go.sum +++ b/go.sum @@ -44,6 +44,7 @@ github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2y github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= +github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= @@ -70,6 +71,12 @@ github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKoh github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dunglas/frankenphp v0.0.0-20221110130350-f0b2eb74451c h1:MV2p5aj2WsUVKtPU5iWyQCqrTlPnc7h/Xcpd5Fp//Mo= +github.com/dunglas/frankenphp v0.0.0-20221110130350-f0b2eb74451c/go.mod h1:6b1QU694yYzvWx460qOVNYJGOwOLZtErhiUNLiVHpSI= +github.com/dunglas/frankenphp v0.0.0-20221112134810-6a6dda5ed924 h1:xE23E2Ch9txx7bSas/xeLa1j+GEfSSUXbwZ72LCjjnY= +github.com/dunglas/frankenphp v0.0.0-20221112134810-6a6dda5ed924/go.mod h1:6b1QU694yYzvWx460qOVNYJGOwOLZtErhiUNLiVHpSI= +github.com/dunglas/phpstore v1.0.6-0.20221112140329-97f1078dbfc1 h1:y124yxl6y4skiXW87SIisI76sWcsx0QKpyPvZwBEvLU= +github.com/dunglas/phpstore v1.0.6-0.20221112140329-97f1078dbfc1/go.mod h1:Pug4pGst4b5DcGUwYz2DB1LjltohPgvE4OusDe1z2Xg= github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819 h1:RIB4cRk+lBqKK3Oy0r2gRX4ui7tuhiZq2SuTtTCi0/0= github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2 h1:dWB6v3RcOy03t/bUadywsbyrQwCqZeNIEX6M1OtSZOM= @@ -269,8 +276,6 @@ github.com/symfony-cli/cert v1.0.1 h1:ETYVBshgY+SaydBJmMkU0PaoDrWm6zsGNB/799ZQYC github.com/symfony-cli/cert v1.0.1/go.mod h1:g4WrLT6EQsEPmA19xh5Jv9Jnpg5EvtFqArJf2AG2S+w= github.com/symfony-cli/console v1.0.2 h1:u8KJm9jFbfzmN0y7fcfjjal3wWOLflNomu29PLgYQjQ= github.com/symfony-cli/console v1.0.2/go.mod h1:z2dLSNdPW3rWdSxj8DlZocMtMYN5EF6OeIYjVioXVqE= -github.com/symfony-cli/phpstore v1.0.5 h1:e1J+FcztiSSAVuD4gwatPwMpeqQy3SGNdhd6Vtuncy8= -github.com/symfony-cli/phpstore v1.0.5/go.mod h1:Pug4pGst4b5DcGUwYz2DB1LjltohPgvE4OusDe1z2Xg= github.com/symfony-cli/terminal v1.0.4 h1:jam7aN7g7WQ9uOwV9UC+iVGBLTlzK8kAC5EKcxq21Z8= github.com/symfony-cli/terminal v1.0.4/go.mod h1:+OxxnU05wyRHKYyQkTzTaCSSxmmIBcvAHLcQ099odj4= github.com/syncthing/notify v0.0.0-20210616190510-c6b7342338d2 h1:F4snRP//nIuTTW9LYEzVH4HVwDG9T3M4t8y/2nqMbiY= @@ -292,6 +297,14 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= +go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -614,6 +627,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/local/php/php_server.go b/local/php/php_server.go index 676e88a0..1342f09a 100644 --- a/local/php/php_server.go +++ b/local/php/php_server.go @@ -37,6 +37,7 @@ import ( "strings" "time" + "github.com/dunglas/frankenphp" "github.com/pkg/errors" "github.com/rs/xid" "github.com/rs/zerolog" @@ -46,6 +47,7 @@ import ( "github.com/symfony-cli/symfony-cli/local/html" "github.com/symfony-cli/symfony-cli/local/pid" "github.com/symfony-cli/symfony-cli/local/process" + "go.uber.org/zap" ) // Server represents a PHP server process (can be php-fpm, php-cgi, or php-cli) @@ -63,16 +65,30 @@ type Server struct { var addslashes = strings.NewReplacer("\\", "\\\\", "'", "\\'") // NewServer creates a new PHP server backend -func NewServer(homeDir, projectDir, documentRoot, passthru string, logger zerolog.Logger) (*Server, error) { - logger.Debug().Str("source", "PHP").Msg("Reloading PHP versions") - phpStore := phpstore.New(homeDir, true, nil) - version, source, warning, err := phpStore.BestVersionForDir(projectDir) - if warning != "" { - logger.Warn().Str("source", "PHP").Msg(warning) - } - if err != nil { - return nil, err +func NewServer(homeDir, projectDir, documentRoot, passthru string, useFrankenPHP bool, logger zerolog.Logger) (*Server, error) { + var ( + version *phpstore.Version + source string + ) + + if useFrankenPHP { + version = &phpstore.Version{Version: frankenphp.Version().Version, FrankenPHP: true} + source = "FrankenPHP" + } else { + logger.Debug().Str("source", "PHP").Msg("Reloading PHP versions") + phpStore := phpstore.New(homeDir, true, nil) + v, s, warning, err := phpStore.BestVersionForDir(projectDir) + if warning != "" { + logger.Warn().Str("source", "PHP").Msg(warning) + } + if err != nil { + return nil, err + } + + version = v + source = s } + logger.Debug().Str("source", "PHP").Msgf("Using PHP version %s (from %s)", version.Version, source) return &Server{ Version: version, @@ -86,6 +102,21 @@ func NewServer(homeDir, projectDir, documentRoot, passthru string, logger zerolo // Start starts a PHP server func (p *Server) Start(ctx context.Context, pidFile *pid.PidFile) (*pid.PidFile, func() error, error) { + if p.Version.IsFrankenPHPServer() { + return nil, func() error { + // TODO: create an adapter between zerolog and zap + z, err := zap.NewProduction() + if err != nil { + return errors.Wrap(err, "unable to create FrankenPHP's logger") + } + if err = frankenphp.Init(frankenphp.WithLogger(z)); err != nil { + return errors.Wrap(err, "unable to start FrankenPHP's logger") + } + + return nil + }, nil + } + var pathsToRemove []string port, err := process.FindAvailablePort() if err != nil { @@ -197,6 +228,14 @@ func (p *Server) Serve(w http.ResponseWriter, r *http.Request, env map[string]st for k, v := range p.generateEnv(r) { env[k] = v } + if p.Version.IsFrankenPHPServer() { + fr := frankenphp.NewRequestWithContext(r, p.documentRoot, nil) + fc, _ := frankenphp.FromContext(fr.Context()) + fc.Env = env + fc.Env["SCRIPT_FILENAME"] = p.documentRoot + string(os.PathSeparator) + p.passthru + + return frankenphp.ServeHTTP(w, fr) + } if p.Version.IsCLIServer() { rid := xid.New().String() r.Header.Add("__SYMFONY_LOCAL_REQUEST_ID__", rid) diff --git a/local/project/config.go b/local/project/config.go index 175e1451..a175c4fd 100644 --- a/local/project/config.go +++ b/local/project/config.go @@ -45,6 +45,7 @@ type Config struct { NoTLS bool `yaml:"no_tls"` Daemon bool `yaml:"daemon"` UseGzip bool `yaml:"use_gzip"` + FrankenPHP bool `yaml:"frankenphp"` } type FileConfig struct { @@ -104,10 +105,12 @@ func NewConfigFromContext(c *console.Context, projectDir string) (*Config, *File if c.IsSet("daemon") { config.Daemon = c.Bool("daemon") } - if c.IsSet("use-gzip") { config.UseGzip = c.Bool("use-gzip") } + if c.IsSet("frankenphp") { + config.FrankenPHP = c.Bool("frankenphp") + } return config, fileConfig, nil } diff --git a/local/project/project.go b/local/project/project.go index 6fcb0c88..c4b46053 100644 --- a/local/project/project.go +++ b/local/project/project.go @@ -76,7 +76,7 @@ func New(c *Config) (*Project, error) { return nil } } else { - p.PHPServer, err = php.NewServer(c.HomeDir, c.ProjectDir, documentRoot, passthru, c.Logger) + p.PHPServer, err = php.NewServer(c.HomeDir, c.ProjectDir, documentRoot, passthru, c.FrankenPHP, c.Logger) if err != nil { return nil, err } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy