feat: improve Dockerfile and add some docs (#15)

This commit is contained in:
Kévin Dunglas
2022-10-13 18:05:22 +02:00
committed by GitHub
parent b971c07d89
commit acc48830f7
15 changed files with 1139 additions and 107 deletions

2
.dockerignore Normal file
View File

@@ -0,0 +1,2 @@
Dockerfile
Dockerfile.dev

View File

@@ -57,3 +57,15 @@ Run the test app:
cd ../../testdata/
../internal/testserver/testserver
## Misc Dev Resources
* [PHP embedding in uWSGI](https://github.com/unbit/uwsgi/blob/master/plugins/php/php_plugin.c)
* [PHP embedding in NGINX Unit](https://github.com/nginx/unit/blob/master/src/nxt_php_sapi.c)
* [PHP embedding in Go (go-php)](https://github.com/deuill/go-php)
* [PHP embedding in Go (GoEmPHP)](https://github.com/mikespook/goemphp)
* [PHP embedding in C++](https://gist.github.com/paresy/3cbd4c6a469511ac7479aa0e7c42fea7)
* [Extending and Embedding PHP by Sara Golemon](https://books.google.fr/books?id=zMbGvK17_tYC&pg=PA254&lpg=PA254#v=onepage&q&f=false)
* [What the heck is TSRMLS_CC, anyway?](http://blog.golemon.com/2006/06/what-heck-is-tsrmlscc-anyway.html)
* [PHP embedding on Mac](https://gist.github.com/jonnywang/61427ffc0e8dde74fff40f479d147db4)
* [SDL bindings](https://pkg.go.dev/github.com/veandco/go-sdl2@v0.4.21/sdl#Main)

View File

@@ -25,26 +25,21 @@ RUN apt-get update && \
libxml2-dev \
zlib1g-dev \
bison \
# Dev tools \
git \
gdb \
valgrind \
neovim && \
zsh && \
echo 'set auto-load safe-path /' > /root/.gdbinit && \
echo '* soft core unlimited' >> /etc/security/limits.conf \
&& \
apt-get clean
RUN git clone https://github.com/dunglas/php-src.git && \
RUN git clone --depth=1 --single-branch --branch=frankenphp-8.2 https://github.com/dunglas/php-src.git && \
cd php-src && \
git checkout frankenphp-8.2 && \
#export CFLAGS="-DNO_SIGPROF" && \
# --enable-embed is only necessary to generate libphp.so, we don't use this SAPI directly
./buildconf && \
./configure --enable-embed=static --enable-zts --disable-zend-signals --enable-debug && \
./configure \
--enable-embed=static \
--enable-zts \
--disable-zend-signals && \
make -j6 && \
make install && \
#rm -Rf php-src/ && \
rm -Rf php-src/ && \
ldconfig && \
php --version
@@ -52,6 +47,26 @@ RUN echo "zend_extension=opcache.so\nopcache.enable=1" > /usr/local/lib/php.ini
WORKDIR /go/src/app
COPY go.mod go.sum ./
RUN go get -v ./...
RUN mkdir caddy && cd caddy
COPY go.mod go.sum ./
RUN go get -v ./... && \
cd ..
COPY . .
RUN go get -d -v ./...
RUN cd caddy/frankenphp && \
go build && \
cp frankenphp /usr/local/bin && \
cp /go/src/app/caddy/frankenphp/Caddyfile /etc/Caddyfile && \
rm -Rf /go
WORKDIR /app
RUN mkdir -p /app/public
RUN echo '<?php phpinfo();' > /app/public/index.php
CMD [ "frankenphp", "run", "--config", "/etc/Caddyfile" ]

61
Dockerfile.dev Normal file
View File

@@ -0,0 +1,61 @@
FROM golang
ARG LIBICONV_VERSION=1.17
ENV PHPIZE_DEPS \
autoconf \
dpkg-dev \
file \
g++ \
gcc \
libc-dev \
make \
pkg-config \
re2c
RUN apt-get update && \
apt-get -y --no-install-recommends install \
$PHPIZE_DEPS \
libargon2-dev \
libcurl4-openssl-dev \
libonig-dev \
libreadline-dev \
libsodium-dev \
libsqlite3-dev \
libssl-dev \
libxml2-dev \
zlib1g-dev \
bison \
# Dev tools \
git \
gdb \
valgrind \
neovim \
zsh && \
echo 'set auto-load safe-path /' > /root/.gdbinit && \
echo '* soft core unlimited' >> /etc/security/limits.conf \
&& \
apt-get clean
RUN git clone --depth=1 --single-branch --branch=frankenphp-8.2 https://github.com/dunglas/php-src.git && \
cd php-src && \
git checkout frankenphp-8.2 && \
export CFLAGS="-DNO_SIGPROF" && \
# --enable-embed is only necessary to generate libphp.so, we don't use this SAPI directly
./buildconf && \
./configure \
--enable-embed=static \
--enable-zts \
--disable-zend-signals \
--enable-debug && \
make -j6 && \
make install && \
ldconfig && \
php --version
RUN echo "zend_extension=opcache.so\nopcache.enable=1" > /usr/local/lib/php.ini
WORKDIR /go/src/app
COPY . .
RUN go get -d -v ./...

View File

@@ -1,93 +1,17 @@
# Caddy PHP
# FrankenPHP: Modern App Server for PHP
## Install
### Docker
The easiest way to get started is to use our Docker image:
## Getting Started
```
docker build -t frankenphp .
docker run -v $PWD:/app/public \
-p 80:80 -p 443:443 \
dunglas/frankenphp
```
### Compile From Sources
Your app is served at https://localhost!
#### Install PHP
## Docs
To use FrankenPHP, you currently need to compile a fork of PHP.
Patches have been contributed upstream, and some have already
been merged. It will be possible to use the vanilla version of PHP
starting with version 8.3.
First, get our PHP fork and prepare it:
```
git clone https://github.com/dunglas/php-src.git
cd php-src
git checkout frankenphp-8.2
./buildconf
```
Then, configure PHP for your platform:
**Linux**:
```
./configure \
--enable-embed \
--enable-zts \
--disable-zend-signals
```
**Mac**:
Use the [Homebrew](https://brew.sh/) package manager to install
`libiconv` and `bison`:
```
brew install libiconv bison
echo 'export PATH="/opt/homebrew/opt/bison/bin:$PATH"' >> ~/.zshrc
```
Then run the configure script:
```
./configure \
--enable-embed=static \
--enable-zts \
--disable-zend-signals \
--disable-opcache-jit \
--with-iconv=/opt/homebrew/opt/libiconv/
```
These flags are required, but you can add other flags (extra extensions...)
if needed.
Finally, compile PHP:
```
make -j6
make install
```
#### Compile the Go App
You can now use the Go lib and compile our Caddy build:
```
cd caddy/frankenphp
go build
```
## Misc Dev Resources
* [PHP embedding in uWSGI](https://github.com/unbit/uwsgi/blob/master/plugins/php/php_plugin.c)
* [PHP embedding in NGINX Unit](https://github.com/nginx/unit/blob/master/src/nxt_php_sapi.c)
* [PHP embedding in Go (go-php)](https://github.com/deuill/go-php)
* [PHP embedding in Go (GoEmPHP)](https://github.com/mikespook/goemphp)
* [PHP embedding in C++](https://gist.github.com/paresy/3cbd4c6a469511ac7479aa0e7c42fea7)
* [Extending and Embedding PHP by Sara Golemon](https://books.google.fr/books?id=zMbGvK17_tYC&pg=PA254&lpg=PA254#v=onepage&q&f=false)
* [What the heck is TSRMLS_CC, anyway?](http://blog.golemon.com/2006/06/what-heck-is-tsrmlscc-anyway.html)
* [PHP embedding on Mac](https://gist.github.com/jonnywang/61427ffc0e8dde74fff40f479d147db4)
* [SDL bindings](https://pkg.go.dev/github.com/veandco/go-sdl2@v0.4.21/sdl#Main)
* [worker mode](docs/worker.md)
* [Early Hints support (103 HTTP status code)](docs/early-hints.md)
* [compile from sources](docs/compile.md)

View File

@@ -0,0 +1,37 @@
{
# Debug
{$DEBUG}
frankenphp {
#worker /path/to/your/worker.php
{$FRANKENPHP_CONFIG}
}
}
{$SERVER_NAME:localhost}
log
route {
root * public/
# Add trailing slash for directory requests
@canonicalPath {
file {path}/index.php
not path */
}
redir @canonicalPath {path}/ 308
# If the requested file does not exist, try index files
@indexFiles file {
try_files {path} {path}/index.php index.php
split_path .php
}
rewrite @indexFiles {http.matchers.file.relative}
# FrankenPHP!
@phpFiles path *.php
php @phpFiles
encode zstd gzip
file_server
respond 404
}

View File

@@ -7,6 +7,8 @@ import (
// plug in Caddy modules here.
_ "github.com/caddyserver/caddy/v2/modules/standard"
_ "github.com/dunglas/frankenphp/caddy"
_ "github.com/dunglas/mercure/caddy"
_ "github.com/dunglas/vulcain/caddy"
)
func main() {

View File

@@ -7,6 +7,8 @@ replace github.com/dunglas/frankenphp => ../
require (
github.com/caddyserver/caddy/v2 v2.6.1
github.com/dunglas/frankenphp v0.0.0-00010101000000-000000000000
github.com/dunglas/mercure/caddy v0.14.1
github.com/dunglas/vulcain/caddy v0.0.0-20220906084821-705c1113298e
go.uber.org/zap v1.23.0
)
@@ -17,11 +19,14 @@ require (
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.1.1 // indirect
github.com/Masterminds/sprig/v3 v3.2.2 // indirect
github.com/MauriceGit/skiplist v0.0.0-20211105230623-77f5c8d3e145 // indirect
github.com/RoaringBitmap/roaring v1.2.1 // indirect
github.com/alecthomas/chroma v0.10.0 // indirect
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect
github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b // indirect
github.com/benesch/cgosymbolizer v0.0.0-20190515212042-bec6fe6e597b // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.3.0 // indirect
github.com/caddyserver/certmagic v0.17.1 // indirect
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
@@ -33,25 +38,38 @@ require (
github.com/dgraph-io/ristretto v0.1.0 // indirect
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
github.com/dlclark/regexp2 v1.7.0 // indirect
github.com/dunglas/httpsfv v0.1.1 // indirect
github.com/dunglas/mercure v0.14.1 // indirect
github.com/dunglas/vulcain v0.4.0 // indirect
github.com/dustin/go-humanize v1.0.1-0.20200219035652-afde56e7acac // indirect
github.com/felixge/httpsnoop v1.0.3 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/getkin/kin-openapi v0.55.0 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-chi/chi v4.1.2+incompatible // indirect
github.com/go-kit/kit v0.12.0 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.5.1 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/swag v0.19.15 // indirect
github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/gofrs/uuid v4.2.0+incompatible // indirect
github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
github.com/golang/glog v1.0.0 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/cel-go v0.12.5 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/handlers v1.5.1 // indirect
github.com/gorilla/mux v1.8.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/huandu/xstrings v1.3.2 // indirect
github.com/ianlancetaylor/cgosymbolizer v0.0.0-20220405231054-a1ae3e4bba26 // indirect
github.com/imdario/mergo v0.3.13 // indirect
@@ -64,10 +82,14 @@ require (
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
github.com/jackc/pgtype v1.12.0 // indirect
github.com/jackc/pgx/v4 v4.17.2 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/kevburnsjr/skipfilter v0.0.1 // indirect
github.com/klauspost/compress v1.15.11 // indirect
github.com/klauspost/cpuid/v2 v2.1.1 // indirect
github.com/libdns/libdns v0.2.1 // indirect
github.com/lucas-clemente/quic-go v0.29.1 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/manifoldco/promptui v0.9.0 // indirect
github.com/marten-seemann/qpack v0.2.1 // indirect
github.com/marten-seemann/qtls-go1-18 v0.1.2 // indirect
@@ -81,9 +103,13 @@ require (
github.com/miekg/dns v1.1.50 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-ps v1.0.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/mschoch/smat v0.2.0 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.13.0 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
@@ -99,12 +125,22 @@ require (
github.com/smallstep/cli v0.22.0 // indirect
github.com/smallstep/nosql v0.4.0 // indirect
github.com/smallstep/truststore v0.12.0 // indirect
github.com/spf13/afero v1.9.2 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/cobra v1.5.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.12.0 // indirect
github.com/stoewer/go-strcase v1.2.0 // indirect
github.com/subosito/gotenv v1.4.0 // indirect
github.com/tailscale/tscert v0.0.0-20220316030059-54bbcb9f74e2 // indirect
github.com/tidwall/gjson v1.7.5 // indirect
github.com/tidwall/match v1.0.3 // indirect
github.com/tidwall/pretty v1.1.0 // indirect
github.com/tidwall/sjson v1.1.6 // indirect
github.com/unrolled/secure v1.12.0 // indirect
github.com/urfave/cli v1.22.10 // indirect
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
github.com/yuin/goldmark v1.5.2 // indirect
github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
@@ -129,12 +165,13 @@ require (
golang.org/x/net v0.0.0-20221004154528-8021a29435af // indirect
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
golang.org/x/term v0.0.0-20220919170432-7a66f970e087 // indirect
golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b // indirect
golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2 // indirect
golang.org/x/tools v0.1.12 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/genproto v0.0.0-20220929141241-1ce7b20da813 // indirect
google.golang.org/grpc v1.49.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect

File diff suppressed because it is too large Load Diff

73
docs/compile.md Normal file
View File

@@ -0,0 +1,73 @@
# Compile From Sources
## Install PHP
To use FrankenPHP, you currently need to compile a fork of PHP.
Patches have been contributed upstream, and some have already
been merged. It will be possible to use the vanilla version of PHP
starting with version 8.3.
First, get our PHP fork and prepare it:
```
git clone https://github.com/dunglas/php-src.git
cd php-src
git checkout frankenphp-8.2
./buildconf
```
Then, configure PHP for your platform:
### Linux
```
./configure \
--enable-embed \
--enable-zts \
--disable-zend-signals
```
### Mac
Use the [Homebrew](https://brew.sh/) package manager to install
`libiconv` and `bison`:
```
brew install libiconv bison
echo 'export PATH="/opt/homebrew/opt/bison/bin:$PATH"' >> ~/.zshrc
```
Then run the configure script:
```
export CFLAGS="-DNO_SIGPROF"
./configure \
--enable-embed=static \
--enable-zts \
--disable-zend-signals \
--disable-opcache-jit \
--enable-static \
--enable-shared=no \
--with-iconv=/opt/homebrew/opt/libiconv/
```
These flags are required, but you can add other flags (extra extensions...)
if needed.
## Compile PHP
Finally, compile PHP:
```
make -j6
make install
```
#### Compile the Go App
You can now use the Go lib and compile our Caddy build:
```
cd caddy/frankenphp
go build
```

21
docs/early-hints.md Normal file
View File

@@ -0,0 +1,21 @@
# Early Hints
FrankenPHP natively supports the [103 Early Hints status code]().
Using Early Hints can improve the load of your web pages by 30%.
```php
<?php
header('Link: </style.css>; rel=preload; as=style');
headers_send(103);
// your slow algorithms and SQL queries 🤪
echo <<<'HTML'
<!DOCTYPE html>
<title>Hello FrankenPHP</title>
<link rel="stylesheet" href="style.css">
HTML;
```
Early Hints are supported by the normal and the [worker](worker.md) mode.

78
docs/worker.md Normal file
View File

@@ -0,0 +1,78 @@
# Using FrankenPHP Workers
## Custom Apps
```php
<?php
// public/index.php
// Boot your app
require __DIR__.'/vendor/autoload.php';
$myApp = new \App\Kernel();
$myApp->boot();
do {
$running = frankenphp_handle_request(function () use ($myApp) {
// Called when a request is received,
// superglobals, php://input and the like are reset
echo $myApp->handle($_GET, $_POST, $_COOKIE, $_FILES, $_SERVER);
});
// Do something after sending the HTTP response
$myApp->terminate();
} while ($running);
// Cleanup
$myApp->shutdown();
```
Then, start your app and use the `FRANKENPHP_CONFIG` environment variable to configure your worker:
```sh
docker run \
-e FRANKENPHP_CONFIG="worker ./public/index.php" \
-v $PWD:/app \
-p 80:80 -p 443:443 \
dunglas/frankenphp
```
By default, one worker per CPU is started.
You can also configure the number of workers to start:
```sh
docker run \
-e FRANKENPHP_CONFIG="worker ./public/index.php 42" \
-v $PWD:/app \
-p 80:80 -p 443:443 \
dunglas/frankenphp
```
## Symfony Runtime
The worker mode of FrankenPHP is supported by the [Symfony Runtime Component](https://symfony.com/doc/current/components/runtime.html).
To start any Symfony application in a worker, install the FrankenPHP package of [PHP Runtime](https://github.com/php-runtime/runtime):
```sh
composer require runtime/frankenphp-symfony
```
Then set the `APP_RUNTIME` environment variable to use the FrankenPHP Symfony Runtime:
```sh
# .env
APP_RUNTIME='Runtime\FrankenPhpSymfony\Runtime'
```
Finally, start your app server:
```sh
docker run \
-e FRANKENPHP_CONFIG="worker ./public/index.php" \
-v $PWD:/app \
-p 80:80 -p 443:443 \
dunglas/frankenphp
```
## Laravel Octane
Coming soon!

View File

@@ -43,7 +43,7 @@ typedef struct frankenphp_server_context {
} frankenphp_server_context;
/* Adapted from php_request_shutdown */
void frankenphp_worker_request_shutdown(uintptr_t current_request) {
static void frankenphp_worker_request_shutdown(uintptr_t current_request) {
/* Flush all output buffers */
zend_try {
php_output_end_all();
@@ -71,7 +71,7 @@ void frankenphp_worker_request_shutdown(uintptr_t current_request) {
}
/* Adapted from php_request_startup() */
int frankenphp_worker_request_startup() {
static int frankenphp_worker_request_startup() {
int retval = SUCCESS;
zend_try {
@@ -149,6 +149,9 @@ PHP_FUNCTION(frankenphp_handle_request) {
frankenphp_worker_request_startup();
ctx->current_request = 0;
// FIXME: definitely not a good idea!
//PG(report_memleaks) = 0;
RETURN_FALSE;
}
@@ -164,7 +167,7 @@ PHP_FUNCTION(frankenphp_handle_request) {
zval retval = {0};
fci.size = sizeof fci;
fci.retval = &retval;
if (zend_call_function(&fci, &fcc)) {
if (zend_call_function(&fci, &fcc) == SUCCESS) {
zval_ptr_dtor(&retval);
}
@@ -437,7 +440,7 @@ sapi_module_struct frankenphp_sapi_module = {
STANDARD_SAPI_MODULE_PROPERTIES
};
void *manager_thread(void *arg) {
static void *manager_thread(void *arg) {
#ifdef ZTS
php_tsrm_startup();
/*tsrm_error_set(TSRM_ERROR_LEVEL_INFO, NULL);*/

View File

@@ -1,6 +1,6 @@
package frankenphp
// #cgo CFLAGS: -Wall
// #cgo CFLAGS: -DNO_SIGPROF -Wall
// #cgo CFLAGS: -I/usr/local/include/php -I/usr/local/include/php/Zend -I/usr/local/include/php/TSRM -I/usr/local/include/php/main
// #cgo LDFLAGS: -L/usr/local/lib -L/opt/homebrew/opt/libiconv/lib -L/usr/lib -lphp -lxml2 -lresolv -lsqlite3 -ldl -lm -lutil
// #cgo darwin LDFLAGS: -liconv

4
testdata/Caddyfile vendored
View File

@@ -1,11 +1,11 @@
{
debug
frankenphp {
#worker ./error.php
worker ./index.php
}
}
localhost {
http:// {
log
route {
root * .