Giter VIP home page Giter VIP logo

frankenphp's Introduction

FrankenPHP: Modern App Server for PHP

FrankenPHP

FrankenPHP is a modern application server for PHP built on top of the Caddy web server.

FrankenPHP gives superpowers to your PHP apps thanks to its stunning features: Early Hints, worker mode, real-time capabilities, automatic HTTPS, HTTP/2, and HTTP/3 support...

FrankenPHP works with any PHP app and makes your Laravel and Symfony projects faster than ever thanks to their official integrations with the worker mode.

FrankenPHP can also be used as a standalone Go library to embed PHP in any app using net/http.

Learn more on frankenphp.dev and in this slide deck:

Slides

Getting Started

Docker

docker run -v $PWD:/app/public \
    -p 80:80 -p 443:443 -p 443:443/udp \
    dunglas/frankenphp

Go to https://localhost, and enjoy!

Tip

Do not attempt to use https://127.0.0.1. Use https://localhost and accept the self-signed certificate. Use the SERVER_NAME environment variable to change the domain to use.

Standalone Binary

If you prefer not to use Docker, we provide standalone FrankenPHP binaries for Linux and macOS containing PHP 8.3 and most popular PHP extensions: Download FrankenPHP

To serve the content of the current directory, run:

./frankenphp php-server

You can also run command-line scripts with:

./frankenphp php-cli /path/to/your/script.php

Docs

Examples and Skeletons

frankenphp's People

Contributors

alamirault avatar alexandreelise avatar back-2-95 avatar chalasr avatar crazywhalecc avatar dependabot[bot] avatar dracoblue avatar dubbleclick avatar dunglas avatar flexponsive avatar jdreesen avatar kassner avatar krakjoe avatar leocavalcante avatar nitneuk avatar peterfox avatar pierredup avatar pierresh avatar pierstoval avatar rokiszb avatar rubenkruiswijk avatar ruudk avatar shinsenter avatar shyim avatar sneycampos avatar stephenmiracle avatar steveoliver avatar virp avatar withinboredom avatar yoann-tyt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

frankenphp's Issues

Death of worker causes panic

I attempted a very simple implementation of restarting a worker on a file change:

<?php

$startup = hash_file('crc32', __FILE__);

do {
    $running = frankenphp_handle_request(function (): void {
        echo "hi!!";
        var_dump(hash_file('crc32', __FILE__));
    });
    if (hash_file('crc32', __FILE__) !== $startup) {
        error_log('rebooting');
        die();
    }
} while ($running);

This causes a panic in frankenphp:

{"level":"info","ts":1666099933.9751377,"msg":"rebooting","syslog_level":"notice"}
{"level":"info","ts":1666099933.9752717,"logger":"http.log.access","msg":"handled request","request":{"remote_ip":"172.17.0.1","remote_port":"47406","proto":"HTTP/2.0","method":"GET","host":"localhost","uri":"/","headers":{"User-Agent":["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36 Edg/106.0.1370.47"],"Sec-Fetch-Dest":["document"],"Cache-Control":["max-age=0"],"Sec-Ch-Ua-Mobile":["?0"],"Upgrade-Insecure-Requests":["1"],"Accept-Encoding":["gzip, deflate, br"],"Accept-Language":["en-US,en;q=0.9"],"Sec-Ch-Ua-Platform":["\"Windows\""],"Dnt":["1"],"Sec-Fetch-Mode":["navigate"],"Sec-Fetch-User":["?1"],"Sec-Ch-Ua":["\"Chromium\";v=\"106\", \"Microsoft Edge\";v=\"106\", \"Not;A=Brand\";v=\"99\""],"Accept":["text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"],"Sec-Fetch-Site":["none"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h2","server_name":"localhost"}},"user_id":"","duration":0.000535418,"size":24,"status":200,"resp_headers":{"Content-Type":["text/html; charset=UTF-8"],"Server":["Caddy"],"Alt-Svc":["h3=\":443\"; ma=2592000"],"X-Powered-By":["PHP/8.2.0-dev"]}}
{"level":"error","ts":1666099933.975745,"msg":"unexpected termination, restarting","worker":"/app/public/index.php"}
{"level":"error","ts":1666099933.9771106,"msg":"unexpected termination, restarting","worker":"/app/public/index.php"}
panic: sync: negative WaitGroup counter

goroutine 117 [running, locked to thread]:
sync.(*WaitGroup).Add(0x48cf46?, 0x1e3ad80?)
        /usr/local/go/src/sync/waitgroup.go:83 +0xda
sync.(*WaitGroup).Done(...)
        /usr/local/go/src/sync/waitgroup.go:108
github.com/dunglas/frankenphp.go_frankenphp_worker_ready(...)
        /go/src/app/worker.go:111
github.com/dunglas/frankenphp._Cfunc_frankenphp_execute_script(0x76b43c08dec0)
        _cgo_gotypes.go:769 +0x48
github.com/dunglas/frankenphp.go_execute_script(0xc0000e8301?)
        /go/src/app/frankenphp.go:385 +0x237

(worker): unexpected termination

Hi Dunglas ๐Ÿ‘‹๐Ÿป

First, thanks for this new SAPI, amazing to see how PHP can be improved for future applications.

Small issue that I'm facing while using the worker mode, I followed the documentation for the Symfony application then launched it using Docker:

docker run \
    -e FRANKENPHP_CONFIG="worker ./public/index.php" \
    -v $PWD:/app \       
    -p 80:80 -p 443:443 \
    dunglas/frankenphp
WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested

# ...

First, it seems that the v8 version is not automatically pulled, is there any issue using an arm64 image (I'm on M1 chip)?

Second, when launched (it launched even with the warning message, it seems that it cannot be started correctly:

{"level":"info","ts":1665988244.9370515,"msg":"using provided configuration","config_file":"/etc/Caddyfile","config_adapter":""}
{"level":"warn","ts":1665988244.965832,"msg":"Caddyfile input is not formatted; run the 'caddy fmt' command to fix inconsistencies","adapter":"caddyfile","file":"/etc/Caddyfile","line":3}
{"level":"info","ts":1665988244.9821901,"logger":"admin","msg":"admin endpoint started","address":"localhost:2019","enforce_origin":false,"origins":["//localhost:2019","//[::1]:2019","//127.0.0.1:2019"]}
{"level":"info","ts":1665988244.9869301,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc000518540"}
{"level":"info","ts":1665988244.9886699,"logger":"http","msg":"server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS","server_name":"srv0","https_port":443}
{"level":"info","ts":1665988244.989175,"logger":"http","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
{"level":"error","ts":1665988250.9599025,"msg":"unexpected termination, restarting","worker":"/app/public/index.php"}
{"level":"error","ts":1665988250.9616716,"msg":"unexpected termination, restarting","worker":"/app/public/index.php"}
{"level":"error","ts":1665988250.9628036,"msg":"unexpected termination, restarting","worker":"/app/public/index.php"}
{"level":"error","ts":1665988250.9642198,"msg":"unexpected termination, restarting","worker":"/app/public/index.php"}
{"level":"error","ts":1665988250.9654243,"msg":"unexpected termination, restarting","worker":"/app/public/index.php"}
{"level":"error","ts":1665988250.9677563,"msg":"unexpected termination, restarting","worker":"/app/public/index.php"}

I'm not sure why it tries to restart the worker (maybe it's due to the arm64 architecture?) but the application does not respond ๐Ÿ™

Thanks for the help and sorry for this issue ๐Ÿ˜„

per project Caddyfile SERVER_NAME override?

I am able to change {$SERVER_NAME:localhost} to {$SERVER_NAME:demo.localhost} in caddy/frankenphp/Cadyfile and it works. This way my url matches my Laravel .env APP_URL setting.

Is is possible to have that setting pulled from a project level Caddyfile or preferably from a .env file instead of hard coded into the image?

Rebuild for 8.2.3

I kicked off a new build in GitHub Actions to pick up 8.2.3 which contains security fixes.

Support for mysql database : Error when i build Dockerfile

Hi everyone, I have an error when building the dockerfile.

=> ERROR [12/15] RUN cd caddy/frankenphp &&     go build &&     cp frankenphp /usr/local/bin &&     cp /go/src/app/caddy/frankenphp/Caddyfile /etc/Caddyfile &&     rm -Rf /go                                 49.1s
------                                                                                                                                                                                                                
 > [12/15] RUN cd caddy/frankenphp &&     go build &&     cp frankenphp /usr/local/bin &&     cp /go/src/app/caddy/frankenphp/Caddyfile /etc/Caddyfile &&     rm -Rf /go:                                             
#16 0.212 go: downloading github.com/dunglas/mercure/caddy v0.14.1                                                                                                                                                    
#16 0.213 go: downloading github.com/caddyserver/caddy/v2 v2.6.1                                                                                                                                                      
#16 0.213 go: downloading github.com/dunglas/vulcain/caddy v0.0.0-20220906084821-705c1113298e                                                                                                                         
#16 0.327 go: downloading github.com/dunglas/mercure v0.14.1                                                                                                                                                          
#16 0.348 go: downloading github.com/dunglas/vulcain v0.4.0
#16 0.489 go: downloading go.uber.org/zap v1.23.0
#16 0.520 go: downloading github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b
#16 0.611 go: downloading github.com/caddyserver/certmagic v0.17.1
#16 0.645 go: downloading github.com/spf13/cobra v1.5.0
#16 0.673 go: downloading github.com/spf13/pflag v1.0.5
#16 0.724 go: downloading github.com/google/uuid v1.3.0
#16 0.724 go: downloading github.com/lucas-clemente/quic-go v0.29.1
#16 0.747 go: downloading github.com/prometheus/client_golang v1.13.0
#16 0.862 go: downloading golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec
#16 0.862 go: downloading golang.org/x/term v0.0.0-20220919170432-7a66f970e087
#16 0.891 go: downloading github.com/dustin/go-humanize v1.0.1-0.20200219035652-afde56e7acac
#16 0.892 go: downloading github.com/mholt/acmez v1.0.4
#16 0.951 go: downloading github.com/google/cel-go v0.12.5
#16 1.136 go: downloading golang.org/x/net v0.0.0-20221004154528-8021a29435af
#16 1.137 go: downloading google.golang.org/genproto v0.0.0-20220929141241-1ce7b20da813
#16 1.287 go: downloading github.com/klauspost/cpuid/v2 v2.1.1
#16 1.358 go: downloading github.com/libdns/libdns v0.2.1
#16 1.376 go: downloading github.com/miekg/dns v1.1.50
#16 1.430 go: downloading golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be
#16 1.430 go: downloading go.uber.org/atomic v1.10.0
#16 1.436 go: downloading go.uber.org/multierr v1.8.0
#16 1.462 go: downloading github.com/cpuguy83/go-md2man/v2 v2.0.2
#16 1.539 go: downloading gopkg.in/yaml.v2 v2.4.0
#16 1.670 go: downloading github.com/beorn7/perks v1.0.1
#16 1.672 go: downloading github.com/cespare/xxhash/v2 v2.1.2
#16 1.692 go: downloading github.com/golang/protobuf v1.5.2
#16 1.694 go: downloading github.com/cespare/xxhash v1.1.0
#16 1.723 go: downloading github.com/prometheus/client_model v0.2.0
#16 1.739 go: downloading github.com/prometheus/common v0.37.0
#16 1.753 go: downloading github.com/prometheus/procfs v0.8.0
#16 1.875 go: downloading google.golang.org/protobuf v1.28.1
#16 1.878 go: downloading github.com/marten-seemann/qpack v0.2.1
#16 1.910 go: downloading github.com/smallstep/certificates v0.22.1
#16 2.325 go: downloading github.com/smallstep/cli v0.22.0
#16 2.879 go: downloading github.com/smallstep/truststore v0.12.0
#16 5.272 go: downloading github.com/tailscale/tscert v0.0.0-20220316030059-54bbcb9f74e2
#16 5.308 go: downloading golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2
#16 5.526 go: downloading github.com/stoewer/go-strcase v1.2.0
#16 5.527 go: downloading github.com/antlr/antlr4/runtime/Go/antlr v1.4.10
#16 5.529 go: downloading github.com/go-chi/chi v4.1.2+incompatible
#16 5.808 go: downloading github.com/smallstep/nosql v0.4.0
#16 5.969 go: downloading gopkg.in/natefinch/lumberjack.v2 v2.0.0
#16 5.980 go: downloading github.com/dgraph-io/ristretto v0.1.0
#16 6.332 go: downloading github.com/gofrs/uuid v4.2.0+incompatible
#16 6.351 go: downloading github.com/golang-jwt/jwt/v4 v4.4.2
#16 6.516 go: downloading github.com/gorilla/handlers v1.5.1
#16 6.549 go: downloading github.com/gorilla/mux v1.8.0
#16 6.581 go: downloading github.com/hashicorp/golang-lru v0.5.4
#16 6.646 go: downloading github.com/kevburnsjr/skipfilter v0.0.1
#16 6.649 go: downloading github.com/spf13/viper v1.12.0
#16 6.650 go: downloading github.com/unrolled/secure v1.12.0
#16 6.663 go: downloading github.com/yosida95/uritemplate/v3 v3.0.2
#16 6.687 go: downloading go.etcd.io/bbolt v1.3.6
#16 6.689 go: downloading github.com/dunglas/httpsfv v0.1.1
#16 6.697 go: downloading github.com/getkin/kin-openapi v0.55.0
#16 6.747 go: downloading github.com/tidwall/gjson v1.7.5
#16 6.747 go: downloading github.com/tidwall/sjson v1.1.6
#16 7.006 go: downloading github.com/russross/blackfriday/v2 v2.1.0
#16 7.008 go: downloading github.com/matttproud/golang_protobuf_extensions v1.0.2
#16 7.010 go: downloading golang.org/x/exp v0.0.0-20220929160808-de9c53c655b9
#16 7.010 go: downloading github.com/marten-seemann/qtls-go1-19 v0.1.0
#16 7.048 go: downloading github.com/pkg/errors v0.9.1
#16 7.048 go: downloading go.step.sm/cli-utils v0.7.5
#16 7.161 go: downloading go.step.sm/crypto v0.19.0
#16 7.243 go: downloading go.step.sm/linkedca v0.18.0
#16 7.243 go: downloading google.golang.org/grpc v1.49.0
#16 7.244 go: downloading gopkg.in/square/go-jose.v2 v2.6.0
#16 7.273 go: downloading github.com/slackhq/nebula v1.6.1
#16 7.356 go: downloading github.com/klauspost/compress v1.15.11
#16 7.596 go: downloading github.com/BurntSushi/toml v1.2.0
#16 7.598 go: downloading github.com/Masterminds/sprig/v3 v3.2.2
#16 7.648 go: downloading github.com/alecthomas/chroma v0.10.0
#16 7.667 go: downloading github.com/yuin/goldmark v1.5.2
#16 7.948 go: downloading github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594
#16 7.971 go: downloading gopkg.in/yaml.v3 v3.0.1
#16 8.005 go: downloading go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.1
#16 8.020 go: downloading go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.10.0
#16 8.034 go: downloading go.opentelemetry.io/otel v1.10.0
#16 8.047 go: downloading go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.10.0
#16 8.203 go: downloading go.opentelemetry.io/otel/sdk v1.10.0
#16 8.261 go: downloading github.com/felixge/httpsnoop v1.0.3
#16 8.261 go: downloading github.com/MauriceGit/skiplist v0.0.0-20211105230623-77f5c8d3e145
#16 8.285 go: downloading github.com/RoaringBitmap/roaring v1.2.1
#16 8.381 go: downloading github.com/fsnotify/fsnotify v1.5.4
#16 8.413 go: downloading github.com/mitchellh/mapstructure v1.5.0
#16 8.442 go: downloading github.com/spf13/afero v1.9.2
#16 8.501 go: downloading github.com/spf13/cast v1.5.0
#16 8.525 go: downloading github.com/spf13/jwalterweatherman v1.1.0
#16 8.546 go: downloading github.com/ghodss/yaml v1.0.0
#16 8.568 go: downloading github.com/go-openapi/jsonpointer v0.19.5
#16 8.592 go: downloading github.com/tidwall/match v1.0.3
#16 8.612 go: downloading github.com/tidwall/pretty v1.1.0
#16 8.634 go: downloading github.com/urfave/cli v1.22.10
#16 8.690 go: downloading github.com/mitchellh/go-ps v1.0.0
#16 8.717 go: downloading github.com/micromdm/scep/v2 v2.1.0
#16 8.769 go: downloading go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352
#16 8.809 go: downloading github.com/chzyer/readline v1.5.1
#16 8.845 go: downloading github.com/manifoldco/promptui v0.9.0
#16 8.881 go: downloading filippo.io/edwards25519 v1.0.0
#16 8.918 go: downloading github.com/Masterminds/goutils v1.1.1
#16 8.943 go: downloading github.com/Masterminds/semver/v3 v3.1.1
#16 8.973 go: downloading github.com/huandu/xstrings v1.3.2
#16 9.001 go: downloading github.com/imdario/mergo v0.3.13
#16 9.038 go: downloading github.com/mitchellh/copystructure v1.2.0
#16 9.089 go: downloading github.com/shopspring/decimal v1.3.1
#16 9.138 go: downloading go.opentelemetry.io/otel/metric v0.32.1
#16 9.173 go: downloading go.opentelemetry.io/otel/trace v1.10.0
#16 9.300 go: downloading go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.10.0
#16 9.359 go: downloading go.opentelemetry.io/proto/otlp v0.19.0
#16 9.709 go: downloading github.com/rs/xid v1.4.0
#16 10.06 go: downloading github.com/sirupsen/logrus v1.9.0
#16 10.20 go: downloading github.com/dgraph-io/badger v1.6.2
#16 10.48 go: downloading github.com/dgraph-io/badger/v2 v2.2007.4
#16 10.86 go: downloading github.com/go-sql-driver/mysql v1.6.0
#16 10.98 go: downloading github.com/jackc/pgx/v4 v4.17.2
#16 11.16 go: downloading github.com/golang/glog v1.0.0
#16 11.25 go: downloading github.com/subosito/gotenv v1.4.0
#16 11.29 go: downloading github.com/hashicorp/hcl v1.0.0
#16 11.50 go: downloading gopkg.in/ini.v1 v1.67.0
#16 11.62 go: downloading github.com/magiconair/properties v1.8.6
#16 11.69 go: downloading github.com/pelletier/go-toml/v2 v2.0.2
#16 12.53 go: downloading github.com/pelletier/go-toml v1.9.5
#16 12.66 go: downloading github.com/go-openapi/swag v0.19.15
#16 12.73 go: downloading github.com/go-kit/kit v0.12.0
#16 13.11 go: downloading github.com/mitchellh/reflectwalk v1.0.2
#16 13.14 go: downloading github.com/dlclark/regexp2 v1.7.0
#16 13.73 go: downloading github.com/go-logr/logr v1.2.3
#16 13.79 go: downloading github.com/cenkalti/backoff/v4 v4.1.3
#16 13.85 go: downloading github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3
#16 14.74 go: downloading github.com/grpc-ecosystem/grpc-gateway v1.16.0
#16 14.84 go: downloading github.com/go-logr/stdr v1.2.2
#16 15.37 go: downloading github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13
#16 15.42 go: downloading github.com/jackc/pgconn v1.13.0
#16 15.43 go: downloading github.com/jackc/pgio v1.0.0
#16 15.52 go: downloading github.com/jackc/pgproto3/v2 v2.3.1
#16 15.53 go: downloading github.com/jackc/pgtype v1.12.0
#16 15.53 go: downloading github.com/mailru/easyjson v0.7.7
#16 15.94 go: downloading github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d
#16 15.94 go: downloading github.com/go-kit/log v0.2.1
#16 15.99 go: downloading github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96
#16 16.01 go: downloading github.com/golang/snappy v0.0.4
#16 16.01 go: downloading github.com/jackc/chunkreader/v2 v2.0.1
#16 16.02 go: downloading github.com/jackc/pgpassfile v1.0.0
#16 16.03 go: downloading github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b
#16 16.10 go: downloading github.com/josharian/intern v1.0.0
#16 16.10 go: downloading github.com/shurcooL/sanitized_anchor_name v1.0.0
#16 16.11 go: downloading github.com/mattn/go-colorable v0.1.13
#16 16.13 go: downloading github.com/go-logfmt/logfmt v0.5.1
#16 16.18 go: downloading github.com/mattn/go-isatty v0.0.16
#16 47.73 # github.com/dunglas/frankenphp
#16 47.73 In file included from /usr/local/include/php/Zend/zend.h:409,
#16 47.73                  from /usr/local/include/php/main/php.h:31,
#16 47.73                  from /usr/local/include/php/main/php_variables.h:21,
#16 47.73                  from frankenphp.go:14,
#16 47.73                  from _cgo_export.c:4:
#16 47.73 /usr/local/include/php/Zend/zend_operators.h: In function 'zend_memrchr':
#16 47.73 /usr/local/include/php/Zend/zend_operators.h:205:22: warning: implicit declaration of function 'memrchr'; did you mean 'memchr'? [-Wimplicit-function-declaration]
#16 47.73   205 |  return (const void*)memrchr(s, c, n);
#16 47.73       |                      ^~~~~~~
#16 47.73       |                      memchr
#16 47.73 /usr/local/include/php/Zend/zend_operators.h:205:9: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
#16 47.73   205 |  return (const void*)memrchr(s, c, n);
#16 47.73       |         ^
#16 47.73 # github.com/dunglas/frankenphp
#16 47.73 In file included from /usr/local/include/php/Zend/zend.h:409,
#16 47.73                  from /usr/local/include/php/main/php.h:31,
#16 47.73                  from /usr/local/include/php/main/php_variables.h:21,
#16 47.73                  from ../../frankenphp.go:14:
#16 47.73 /usr/local/include/php/Zend/zend_operators.h: In function 'zend_memrchr':
#16 47.73 /usr/local/include/php/Zend/zend_operators.h:205:22: warning: implicit declaration of function 'memrchr'; did you mean 'memchr'? [-Wimplicit-function-declaration]
#16 47.73   205 |  return (const void*)memrchr(s, c, n);
#16 47.73       |                      ^~~~~~~
#16 47.73       |                      memchr
#16 47.73 /usr/local/include/php/Zend/zend_operators.h:205:9: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
#16 47.73   205 |  return (const void*)memrchr(s, c, n);
#16 47.73       |         ^
#16 47.73 # github.com/dunglas/frankenphp
#16 47.73 In file included from /usr/local/include/php/Zend/zend.h:409,
#16 47.73                  from /usr/local/include/php/main/php.h:31,
#16 47.73                  from frankenphp.c:5:
#16 47.73 /usr/local/include/php/Zend/zend_operators.h: In function 'zend_memrchr':
#16 47.73 /usr/local/include/php/Zend/zend_operators.h:205:22: warning: implicit declaration of function 'memrchr'; did you mean 'memchr'? [-Wimplicit-function-declaration]
#16 47.73   205 |  return (const void*)memrchr(s, c, n);
#16 47.73       |                      ^~~~~~~
#16 47.73       |                      memchr
#16 47.73 /usr/local/include/php/Zend/zend_operators.h:205:9: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
#16 47.73   205 |  return (const void*)memrchr(s, c, n);
#16 47.73       |         ^
#16 47.73 frankenphp.c: At top level:
#16 47.73 frankenphp.c:16:10: fatal error: C-Thread-Pool/thpool.h: No such file or directory
#16 47.73    16 | #include "C-Thread-Pool/thpool.h"
#16 47.73       |          ^~~~~~~~~~~~~~~~~~~~~~~~
#16 47.73 compilation terminated.
------
executor failed running [/bin/sh -c cd caddy/frankenphp &&     go build &&     cp frankenphp /usr/local/bin &&     cp /go/src/app/caddy/frankenphp/Caddyfile /etc/Caddyfile &&     rm -Rf /go]: exit code: 2

Consider renaming DEBUG env var

In the built-in Caddyfile, there is a built-in DEBUG env var injected. This is quite generic and may conflict with other frameworks or applications. Perhaps we should call it FRANKENPHP_DEBUG?

Windows compatibility

Currently this project is compatible with Linux and macOS (and likely with other UNIXes such as FreeBSD), but it hasn't been tested on Windows.

It would be nice to make it compatible for Windows and provide some binaries for this platform.

Starting with a basic file cannot execute

Create an index.php file with the following

<php
echo "Hey!";
?>

Start the docker and open the webrowser at https://localhost, accept "the risk".

The following message occurs:

Warning: Unknown: Failed to open stream: No such file or directory in Unknown on line 0
Fatal error: Failed opening required '/app/public/index.php' (include_path='.:/usr/local/lib/php') in Unknown on line 0

runtime missed error

When I try to launch a Symfony project in worker mode without installing the runtime/frankenphp-symfony library, I have this line in a loop into the log
{"level":"error","ts":1668116008.9931438,"msg":"unexpected termination, restarting","worker":"/app/public/index.php"}

To reproduce:

symfony new --full test
cd test
docker run --rm -e FRANKENPHP_CONFIG="worker ./public/index.php" -e APP_RUNTIME=Runtime\\FrankenPhpSymfony\\Runtime -p 80:80 -p 443:443 -v $(pwd):/app dunglas/frankenphp

To solve:

symfony composer req runtime/frankenphp-symfony

Is worker mode broken???

PHP file

// public/worker.php
<?php

do {
	$running = frankenphp_handle_request(
		function () {
			echo "hello world";
		}
	);
} while ($running);

Then:

docker run --rm -e FRANKENPHP_CONFIG="worker ./public/worker.php" -p 80:80 -p 443:443 -v $(pwd):/app -w /app dunglas/frankenphp

When I curl localhost, it just hangs forever. @dunglas, can you reproduce this or am I doing something wrong?

Consider implementing fastcgi_finish_request()?

fastcgi_finish_request is often used to perform operations after a request is completed (such as sending an email). Should FrankenPHP implement this and/or create a similar function? There are pro/cons to implementing it with the same name (it will "just work" with existing code), and a con would be that if there are any differences in behavior, then things may not work as expected or code may use the existence of that function as a sentinel that it is running in a fastcgi context and do unexpected things.

I'd be happy to tackle implementing this, whatever is decided.

Proposal: remove automatic exceptions handling

Currently, in worker mode, FrankenPHP automatically catches exceptions: https://github.com/dunglas/frankenphp/blob/main/frankenphp.c#L187-L196

Exceptions would be better handled in userland. This would simplify Franken's PHP code and make its behavior more predictable. AFAIK, other runtimes with a worker mode (RoadRunner) don't automatically handle exceptions as well.

Symfony never throws in worker mode: symfony/symfony#45997

WDYT @Nyholm, as you have a good experience of what is expected in these cases?

How are shutdown functions called?

Consider the following code:

register_shutdown_function(function() { error_log('outside'); });

do {
    $running = frankenphp_handle_request(function (): void {
        register_shutdown_function(function() { error_log('in request'); });
    });
} while ($running);

Nothing is output in the logs that I can see (tested SIGTERM, SIGINT to stop the server):

  1. Are shutdown functions called per request/worker/ever? (I could probably do a db insert or something to see for sure.)
  2. Should shutdown functions be contextual on workers (such as in the example)?

A number of frameworks/libraries use shutdown functions to trigger things after a request (I've abused them to process queues, I think WordPress uses them to process cron jobs, error reporting, etc). It'd also be useful to do things when the worker itself dies (outside the loop) though, but in most cases shut down functions are registered with an expectation of request ending.

How to install php extensions?

Installing a php8.2-{extension} and moving the .so into /usr/local/lib/php/extensions/no-debug-zts-20220829 will end up with a core_symbols error.

Running on a different port redirects to :80

Run a different port is very convenient for development as it does not require to run with sudo and does not conflict with existing server.

However running the following does not up so well:

docker run -v $PWD:/app/public \
    -p 8080:80 -p 443:443 \
    dunglas/frankenphp

shoud allow to open a browser and read the app from http://localhost:8080.
However we get redirected to https://localhost.

Create integration tests

We currently build docker images in each PR but don't use them. We can, however, use those images and example repos like dunglas/frankenphp-drupal, dunglas/frankenphp-wordpress, etc. to spin up integration tests with "real world" code and verify (at least) a lack of seg-fault. The idea is to run it manually before merging (I imagine these tests will take a while to run).

Perhaps we can use something like dapr/mechanical-markdown to script it?

Globals leak out of request in worker mode

Probably related to #85.

Take the following code:

<?php

do {
	$running = frankenphp_handle_request(
		function () {
			global $global;
			echo $global ?? 'no global';
			$global = 'global';
		}
	);
} while ($running);

After a worker does the first request, "global" will be output instead of "no global" which I (personally) wasn't expecting. Is this expected? I was under the expectation that super-globals are always reset (at least that is what it looks like is going on in the docs).

License

Hi,

looks like there is currently no license. Could you please add one?

Thanks

ARM64 container image

Running this on an Apple M1 chip give the following warning:

WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested

Would be useful to have ARM variants of the container image.

Idea: Memcached client in golang with request pipelining

For https://memcached.org/ servers or proxies

This may be out of scope.

Motivation

  • Memcached is heavily used in some web applications for caching state or the results of expensive operations (db queries, results of reading data from web services, etc)

  • If there are hundreds of workers, it'd reduce cpu and memory resource usage and syscalls if they shared a small finite number of memcache connections (pool)

    (unless there are ~32+ cpu cores, 1 connection may suffice)

  • Both golang and php could use the same client, allowing moving method implementations to/from golang (e.g. check a json array for a value, add a value)

    • (or read/write with serializers such as PECL msgpack, etc. https://msgpack.org/ has many implementations. )
    • Though this could go in its own PECL, the ability to share the same client is useful

Benchmarking notes

  • Request pipelining does better when there is actual network latency (https://github.com/twitter/twemproxy/#pipelining) (e.g. non-pipelined golang clients would be limited to 1000 requests per second with 0.001 second network latency)
  • https://github.com/twitter/twemproxy/ has performance issues when clients pipeline requests. Reduce mbuf size with -m $MBUF_SIZE if this is configured to connect to a twemproxy proxy
  • I haven't benchmarked this yet.

Background

It would be extremely useful to have compatibility with the memcached flags int used to indicate the chosen serializer https://github.com/php-memcached-dev/php-memcached/ (source of http://pecl.php.net/memcached )

The memcached client this uses is based on https://github.com/bradfitz/gomemcache

  • This rewrites parts of it and adds pipelining support to that library.

Alternatives

Use existing memcached or memcache PECL normally

Cache (Twig) is not regenerated in dev mode

Hi, I use the FrankenPHP demo with the worker mode. If we modify a Twig template (with the dev env), docker has to be restarted, so the changes are taken in account. Is it a limitation of the worker mode?

And even if we clear the cache manually, we still have to restart FrankenPHP so see the new changes.

WordPress?

Can this run WordPress also or is it targeting custom symphony applications only?

Go's garbage collector and load (benchmarks)

While doing some load testing and comparing frankenphp to apache and fpm, I noticed that a single gc cycle from golang can screw up everything.

Here's apache:

Apache 200rps

Here's fpm:

Screenshot_20221117_212927

And here's frankenphp:

image

and the average graph to show the gc:

image

This is mostly to document this behavior and if benchmarking is desired, take note to tune two environment variables:

  • GOGC: "a parameter that picks a point in the GC CPU and memory trade-off. The key takeaway is that doubling GOGC will double heap memory overheads and roughly halve GC CPU cost, and vice versa." A value of 512 will get you approx 2-3 minutes @ 200 rps before running into 2-3s stop-the-world gc pauses. If you're doing benchmarks, and not considering memory usage, setting it "off" might be worth considering, with a noted caveat that "memory/gc tuning will be required to achieve these values long-term."
  • GOMEMLIMIT: the maximum amount of memory to use. Due to the overhead of caddy, Go VM, and frankenphp, it should be larger than the PHP memory limit.

Setting GOGC=off GOMEMLIMIT=4096 gives me nearly 8 minutes at full load before a GC pause. Take note that this is mostly an issue when load testing specifically. During normal usage, it is unlikely for every single thread to be in use and Go will coordinate these threads to perform a GC. When under load, there is no choice but to affect every request. In the "real world" if every server is running at 100%, there are bigger problems to worry about, so please ensure to remove these pauses from your benchmark to reflect real-world maximums in a perfectly tuned or bursty environment.

See this guide for more information about how these parameters work.

flush() doesn't appear to work

Example code:

<?php

echo "hello";
flush();
sleep(2);
echo "world";

Frankenphp should send hello, then 2 seconds later send world. However, we end up with no response sent for 2 seconds, then helloworld sent all in one go.

Consider increasing # of default workers?

Currently, there is one worker spawned per core (if I'm understanding correctly).

This severely limits concurrent connections as it appears only one request per worker can be handled at a time.

Changing this to 2x dramatically affects the techempower benchmarks:

from:

        {
          "latencyAvg": "421.56ms", 
          "latencyMax": "3.65s", 
          "latencyStdev": "766.41ms", 
          "totalRequests": 74185, 
          "startTime": 1671386842, 
          "endTime": 1671386858
        }

to

        {
          "latencyAvg": "100.05ms", 
          "latencyMax": "1.01s", 
          "latencyStdev": "137.47ms", 
          "totalRequests": 112578, 
          "startTime": 1671387704, 
          "endTime": 1671387719
        }

Anything beyond 2x has diminishing returns in my testing. FWIW, 2x on my hardware is 32 workers.

Session handling not working in worker mode

I'm trying to use a bigger Symfony application in worker mode. If the caches are warm, it generally works as long as no session is used.
If I visit actions containing e.g. flash message

<div class="flashbags container">
    {% for type, messages in app.flashes %}
        ...
    {% endfor %}
</div>

I get this:

<b>Fatal error</b>:  Uncaught RuntimeException: Failed to start the session. in /app/vendor/symfony/http-foundation/Session/Storage/NativeSessionStorage.php:186
Stack trace:
#0 /app/vendor/symfony/http-foundation/Session/Storage/NativeSessionStorage.php(352): Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage-&gt;start()
#1 /app/vendor/symfony/http-foundation/Session/Session.php(261): Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage-&gt;getBag('flashes')
#2 /app/vendor/symfony/http-foundation/Session/Session.php(273): Symfony\Component\HttpFoundation\Session\Session-&gt;getBag('flashes')
#3 /app/vendor/symfony/twig-bridge/AppVariable.php(177): Symfony\Component\HttpFoundation\Session\Session-&gt;getFlashBag()

How to use this outside of docker?

Hi,

Thank you very much for the amazing work done. I really wanted to use Nginx Unit but lack of gzip compression prevents me from using it. I have no complaint with Caddy as it supports all the features I need. Now I can use FrankenPHP to enjoy faster performance like Nginx unit because of vertical integration with PHP without missing the features and ease of Caddy.

I am using Caddy compiled with Cloudflare DNS Module right now with PHP-FPM. I am not using Docker. How do I use this without docker? Will there be any performance improvement for wordpress websites? I understand they won't run in worker mode and only benefit I'll get is easy integration here. Please let me know. Thanks again!

ssl

im getting ERR_SSL_PROTOCOL_ERROR
is there a way to server files with working ssl?
i want to use public ip or able to link it behind cloudflare with domain
is there env for custom crt?

Cannot install gd extension

Hello @dunglas,

Tried to install gd extension on FrankenPHP:

FROM dunglas/frankenphp:latest
# FROM dunglas/frankenphp:latest-alpine
# FROM php:8.2-apache
ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/
RUN chmod +x /usr/local/bin/install-php-extensions && \
  install-php-extensions gd
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
COPY . /app
RUN composer install

It fails:

#0 277.0 /tmp/pear/temp/pecl_http/src/php_http_curl.c:28:13: fatal error: gcrypt.h: No such file or directory 

It fails also with frankenphp:latest-alpine:

php_http_client_response.lo  -fPIC -DPIC -o src/.libs/php_http_client_response.o
#0 277.0 /tmp/pear/temp/pecl_http/src/php_http_curl.c:28:13: fatal error: gcrypt.h: No such file or directory
#0 277.0    28 | #   include <gcrypt.h>
#0 277.0       |             ^~~~~~~~~~
#0 277.0 compilation terminated.
#0 277.0 make: *** [Makefile:257: src/php_http_curl.lo] Error 1
#0 277.0 make: *** Waiting for unfinished jobs....
#0 278.5 ERROR: `make -j16' failed

I thought it was related to install-php-extensions script but as it's working properly with php:8.2-apache, I guess it's somewhat related to FrankenPHP specificity. My guess is that the script is not FrankenPHP ready and there are some differences to investigate?

Thank you

Congrats on FrankenPHP

It REALLY sounds and looks like a very promising PHP Framework!

Thumbs Up!

Hugo Barbosa

Worker mode uses wrong path

Hi, thanks for the quick fix for #104!

I am now one step further, as in: the server now redirects and responds correctly, but it doesn't serve the file I gave it in the command line.

Running this command with the latest (sha-878a30d) image:

docker run --rm -e FRANKENPHP_CONFIG="worker ./example/worker.php" -p 80:80 -p 443:443 -v $pwd:/app -w /app dunglas/frankenphp

and this worker.php file:

<?php
// ./example/worker.php

do {
    $running = frankenphp_handle_request(
        function () {
            echo "hello world";
        }
    );
} while ($running);

Results in this output:


Warning: Unknown: Failed to open stream: No such file or directory in Unknown on line 0

Fatal error: Failed opening required '/app/public/worker.php' (include_path='.:/usr/local/lib/php') in Unknown on line 0

So I assume the public path is hardcoded somehow? Which path do I need to give it in the FRANKENPHP_CONFIG value for the worker mode?

Random PHP errors when in worker mode (extremely rare)

I'm seeing random (but extremely rare: <0.5% of requests) fatal PHP errors in worker mode:

  • Cannot instantiate interface from
  • Cannot instantiate trait from
  • Cannot instantiate enum
  • Cannot instantiate abstract class

There's no interface or trait specified in the error, just to be clear, those errors are the literal messages given. The error occurs on random lines/files.

This never happens outside of worker mode and I cannot reproduce it in a smaller sample.

The relevant error messages are coming from these lines in php-src. It smells like some memory shenanigans but it isn't clear if it is a frankenphp bug or a PHP/extension bug.

Specific PHP version tagging

It's unclear from the docker tags which PHP version I would be getting.

I think for adoption it'd be good to be specific about this, even if you only want to be building 8.2, make an :php-8.2 tag so that when you update to 8.3 people can stick on the older version

cURL error 28: Operation timed out after 10000 milliseconds with 0 bytes received

Wordpress REST API seems to fail because cURL times out after 10 seconds.
I noticed some comments that timeouts are broken because FrankenPHP uses ZTS? (probably for performance reasons?
)
I tried editing the Caddyfile main block and adding a timeouts directive in the frankenphp block but it doesn't seem to affect the error.

Can someone point me in a solvable direction?

Pontential memory leak in worker mode

When PHP is compiled with the --enable-debug flag, a potential memory leak is reported in worker mode when running the tests:

go test -v

[Fri Oct 21 08:21:09 2022]  Script:  '-'
/Users/dunglas/workspace/php-src/Zend/zend_hash.c(279) :  Freeing 0x000000012aa5e000 (56 bytes), script=-
Last leak repeated 3 times
=== Total 4 memory leaks detected ===

I tried to track the potential leak with Valgrind but didn't find anything obvious yet.

Alpine image

I just re-did Dockerfile with alpine images:

CleanShot 2022-10-19 at 23 25 27@2x

From 2.51 Gb (Bullseye) to 256 Mb (Alpine)

I need to cleanup my work and create PR.

Error while trying to start the local server

Posted from SymfonyCon ๐Ÿ˜‰

I was trying to make a local run for my project https://github.com/florentdestremau/symfonycon-turbo and by following the docs, it doesn't work ๐Ÿ˜ฌ It goes into an infinite log as seen below. I ended up cancelling the command with ctrl + C, and even then I had to cancel twice.

โžœ  symfonycon git:(main) docker run \
    -e FRANKENPHP_CONFIG="worker ./public/index.php" \
    -v $PWD:/app \
    -p 80:80 -p 443:443 \
    dunglas/frankenphp

{"level":"info","ts":1668702639.1660728,"msg":"using provided configuration","config_file":"/etc/Caddyfile","config_adapter":""}
{"level":"warn","ts":1668702639.1691551,"msg":"Caddyfile input is not formatted; run the 'caddy fmt' command to fix inconsistencies","adapter":"caddyfile","file":"/etc/Caddyfile","line":3}
{"level":"info","ts":1668702639.1704738,"logger":"admin","msg":"admin endpoint started","address":"localhost:2019","enforce_origin":false,"origins":["//localhost:2019","//[::1]:2019","//127.0.0.1:2019"]}
{"level":"info","ts":1668702639.1707454,"logger":"http","msg":"server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS","server_name":"srv0","https_port":443}
{"level":"info","ts":1668702639.1707623,"logger":"http","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
{"level":"info","ts":1668702639.1708112,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc000710cb0"}
{"level":"error","ts":1668702639.4052052,"msg":"unexpected termination, restarting","worker":"/app/public/index.php"}
{"level":"error","ts":1668702639.4088736,"msg":"unexpected termination, restarting","worker":"/app/public/index.php"}
{"level":"error","ts":1668702639.409998,"msg":"unexpected termination, restarting","worker":"/app/public/index.php"}
{"level":"error","ts":1668702639.411147,"msg":"unexpected termination, restarting","worker":"/app/public/index.php"}
{"level":"error","ts":1668702639.6226852,"msg":"unexpected termination, restarting","worker":"/app/public/index.php"}
{"level":"error","ts":1668702639.6318924,"msg":"unexpected termination, restarting","worker":"/app/public/index.php"}
{"level":"error","ts":1668702639.63311,"msg":"unexpected termination, restarting","worker":"/app/public/index.php"}
{"level":"error","ts":1668702639.6401458,"msg":"unexpected termination, restarting","worker":"/app/public/index.php"}
{"level":"error","ts":1668702639.8418236,"msg":"unexpected termination, restarting","worker":"/app/public/index.php"}
{"level":"error","ts":1668702639.854498,"msg":"unexpected termination, restarting","worker":"/app/public/index.php"}
{"level":"error","ts":1668702639.8559601,"msg":"unexpected termination, restarting","worker":"/app/public/index.php"}
{"level":"error","ts":1668702639.8625023,"msg":"unexpected termination, restarting","worker":"/app/public/index.php"}
^C{"level":"info","ts":1668702640.0067117,"msg":"shutting down","signal":"SIGINT"}
{"level":"warn","ts":1668702640.007078,"msg":"exiting; byeee!! ๐Ÿ‘‹","signal":"SIGINT"}
{"level":"error","ts":1668702640.0708613,"msg":"unexpected termination, restarting","worker":"/app/public/index.php"}
{"level":"error","ts":1668702640.0882797,"msg":"unexpected termination, restarting","worker":"/app/public/index.php"}
{"level":"error","ts":1668702640.0896192,"msg":"unexpected termination, restarting","worker":"/app/public/index.php"}
{"level":"error","ts":1668702640.094384,"msg":"unexpected termination, restarting","worker":"/app/public/index.php"}
^C{"level":"warn","ts":1668702640.2882946,"msg":"force quit","signal":"SIGINT"}

Using Fibers causes epic crash

Minimal code to reproduce:

<?php

do {
    $running = false;
    //$running = frankenphp_handle_request(function (): void {
        $fiber = new Fiber(function() {
            echo "Starting Fiber\n";
        });
        $fiber->start();
    //});
} while ($running);

With some slight modifications, it can also be reproduced in worker mode.

Server hangs forever

I am using the same setup as described in #100 and the request just hangs indefinitely. Any idea what I can do?

Also, but unrelated to this issue: is it possible to stop the server using ctrl+c? I always have to delete the container through Docker Desktop...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.