diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index 3df6d044..00000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1 +0,0 @@ -github: dunglas diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yaml similarity index 85% rename from .github/workflows/docker.yml rename to .github/workflows/docker.yaml index f5ad6185..1bbdc2ba 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yaml @@ -1,3 +1,4 @@ +--- name: Build Docker images on: pull_request: @@ -31,10 +32,12 @@ jobs: name: Create variants matrix id: matrix run: | - METADATA=$(docker buildx bake --print | jq -c) - echo "metadata=$METADATA" >> "$GITHUB_OUTPUT" - echo "variants=$(jq -c '.group.default.targets|map(sub("runner-|builder-"; ""))|unique' <<< $METADATA)" >> "$GITHUB_OUTPUT" - echo "platforms=$(jq -c 'first(.target[]) | .platforms' <<< $METADATA)" >> "$GITHUB_OUTPUT" + METADATA="$(docker buildx bake --print | jq -c)" + { + echo metadata="$METADATA" + echo variants="$(jq -c '.group.default.targets|map(sub("runner-|builder-"; ""))|unique' <<< "$METADATA")" + echo platforms="$(jq -c 'first(.target[]) | .platforms' <<< "$METADATA")" + } >> "$GITHUB_OUTPUT" env: LATEST: '1' # TODO: unset this variable when releasing the first stable version SHA: ${{github.sha}} @@ -107,10 +110,10 @@ jobs: run: | mkdir -p /tmp/metadata/builder /tmp/metadata/runner - builderDigest=$(jq -r '."builder-${{matrix.variant}}"."containerimage.digest"' <<< $METADATA) + builderDigest="$(jq -r '."builder-${{matrix.variant}}"."containerimage.digest"' <<< "$METADATA")" touch "/tmp/metadata/builder/${builderDigest#sha256:}" - runnerDigest=$(jq -r '."runner-${{matrix.variant}}"."containerimage.digest"' <<< $METADATA) + runnerDigest="$(jq -r '."runner-${{matrix.variant}}"."containerimage.digest"' <<< "$METADATA")" touch "/tmp/metadata/runner/${runnerDigest#sha256:}" env: METADATA: ${{steps.build.outputs.metadata}} @@ -138,7 +141,7 @@ jobs: continue-on-error: ${{fromJson(needs.prepare.outputs.push)}} run: | docker run --platform=${{matrix.platform}} --rm \ - $(jq -r '."builder-${{matrix.variant}}"."containerimage.config.digest"' <<< $METADATA) \ + "$(jq -r '."builder-${{matrix.variant}}"."containerimage.config.digest"' <<< "$METADATA")" \ sh -c 'go test ${{matrix.race}} -v ./... && cd caddy && go test ${{matrix.race}} -v ./...' env: METADATA: ${{steps.build.outputs.metadata}} @@ -176,13 +179,12 @@ jobs: name: Create manifest list and push working-directory: /tmp/metadata run: | - docker buildx imagetools create $(jq -cr '.target."${{matrix.target}}-${{matrix.variant}}".tags | map("-t " + .) | join(" ")' <<< $METADATA) \ - $(printf 'dunglas/frankenphp@sha256:%s ' *) + docker buildx imagetools create "$(jq -cr '.target."${{matrix.target}}-${{matrix.variant}}".tags | map("-t " + .) | join(" ")' <<< "$METADATA")" \ + "$(printf 'dunglas/frankenphp@sha256:%s ' *)" env: METADATA: ${{needs.prepare.outputs.metadata}} - name: Inspect image - run: | - docker buildx imagetools inspect $(jq -cr '.target."${{matrix.target}}-${{matrix.variant}}".tags | first' <<< $METADATA) + run: docker buildx imagetools inspect "$(jq -cr '.target."${{matrix.target}}-${{matrix.variant}}".tags | first' <<< "$METADATA")" env: METADATA: ${{needs.prepare.outputs.metadata}} diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml new file mode 100644 index 00000000..37cd22c8 --- /dev/null +++ b/.github/workflows/lint.yaml @@ -0,0 +1,43 @@ +--- +name: Lint Code Base +on: + pull_request: + branches: + - main + push: + branches: + - main + +jobs: + build: + name: Lint Code Base + runs-on: ubuntu-latest + + permissions: + contents: read + packages: read + statuses: write + + steps: + - + name: Checkout Code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - + name: Lint Code Base + uses: super-linter/super-linter@v5 + env: + VALIDATE_ALL_CODEBASE: true + DEFAULT_BRANCH: main + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + LINTER_RULES_PATH: / + FILTER_REGEX_EXCLUDE: '.*C-Thread-Pool/.*' + MARKDOWN_CONFIG_FILE: .markdown-lint.yaml + VALIDATE_CPP: false + VALIDATE_JSCPD: false + VALIDATE_GO: false + VALIDATE_PHP_PHPCS: false + VALIDATE_PHP_PHPSTAN: false + VALIDATE_PHP_PSALM: false + VALIDATE_TERRAGRUNT: false diff --git a/.github/workflows/static.yml b/.github/workflows/static.yaml similarity index 94% rename from .github/workflows/static.yml rename to .github/workflows/static.yaml index 2dd0da9e..ad115c79 100644 --- a/.github/workflows/static.yml +++ b/.github/workflows/static.yaml @@ -1,3 +1,4 @@ +--- name: Build binary releases on: pull_request: @@ -52,7 +53,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Copy binary - run: docker cp $(docker create --name static-builder dunglas/frankenphp:static-builder):/go/src/app/dist/frankenphp-linux-x86_64 frankenphp-linux-x86_64 ; docker rm static-builder + run: docker cp "$(docker create --name static-builder dunglas/frankenphp:static-builder):/go/src/app/dist/frankenphp-linux-x86_64" frankenphp-linux-x86_64 ; docker rm static-builder - name: Upload asset if: github.ref_type == 'tag' diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yaml similarity index 90% rename from .github/workflows/tests.yml rename to .github/workflows/tests.yaml index 7b517409..8570bbd1 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yaml @@ -1,3 +1,4 @@ +--- name: Tests on: pull_request: @@ -52,3 +53,8 @@ jobs: name: Run Caddy module tests working-directory: caddy/ run: go test -race -v ./... + - + name: Lint Go code + uses: golangci/golangci-lint-action@v3 + with: + version: latest diff --git a/.hadolint.yaml b/.hadolint.yaml new file mode 100644 index 00000000..a33477db --- /dev/null +++ b/.hadolint.yaml @@ -0,0 +1,6 @@ +--- +ignored: + - DL3006 + - DL3008 + - DL3018 + - DL3022 diff --git a/.markdown-lint.yaml b/.markdown-lint.yaml new file mode 100644 index 00000000..0fe7cd83 --- /dev/null +++ b/.markdown-lint.yaml @@ -0,0 +1,4 @@ +--- +no-hard-tabs: false +MD013: false +MD033: false diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a9851e78..c0c265e3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,15 +1,20 @@ # Contributing ## Compiling PHP + ### With Docker (Linux) Build the dev Docker image: - docker build -t frankenphp-dev -f dev.Dockerfile . - docker run --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -p 8080:8080 -p 443:443 -v $PWD:/go/src/app -it frankenphp-dev +```console +docker build -t frankenphp-dev -f dev.Dockerfile . +docker run --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -p 8080:8080 -p 443:443 -v $PWD:/go/src/app -it frankenphp-dev +``` The image contains the usual development tools (Go, GDB, Valgrind, Neovim...). + If docker version is lower than 23.0, build is failed by dockerignore [pattern issue](https://github.com/moby/moby/pull/42676). Add directories to `.dockerignore`. + ```patch !testdata/*.php !testdata/*.txt @@ -24,65 +29,79 @@ If docker version is lower than 23.0, build is failed by dockerignore [pattern i ## Running the test suite - go test -race -v ./... +```console +go test -race -v ./... +``` ## Caddy module Build Caddy with the FrankenPHP Caddy module: - cd caddy/frankenphp/ - go build - cd ../../ +```console +cd caddy/frankenphp/ +go build +cd ../../ +``` Run the Caddy with the FrankenPHP Caddy module: - cd testdata/ - ../caddy/frankenphp/frankenphp run +```console +cd testdata/ +../caddy/frankenphp/frankenphp run +``` The server is listening on `127.0.0.1:8080`: - curl -vk https://localhost/phpinfo.php +```console +curl -vk https://localhost/phpinfo.php +``` ## Minimal test server Build the minimal test server: - cd internal/testserver/ - go build - cd ../../ +```console +cd internal/testserver/ +go build +cd ../../ +``` Run the test server: - cd testdata/ - ../internal/testserver/testserver +```console +cd testdata/ +../internal/testserver/testserver +``` The server is listening on `127.0.0.1:8080`: - curl -v http://127.0.0.1:8080/phpinfo.php +```console +curl -v http://127.0.0.1:8080/phpinfo.php +``` -# Building Docker Images Locally +## Building Docker Images Locally Print bake plan: -``` +```console docker buildx bake -f docker-bake.hcl --print ``` Build FrankenPHP images for amd64 locally: -``` +```console docker buildx bake -f docker-bake.hcl --pull --load --set "*.platform=linux/amd64" ``` Build FrankenPHP images for arm64 locally: -``` +```console docker buildx bake -f docker-bake.hcl --pull --load --set "*.platform=linux/arm64" ``` Build FrankenPHP images from scratch for arm64 & amd64 and push to Docker Hub: -``` +```console docker buildx bake -f docker-bake.hcl --pull --no-cache --push ``` @@ -90,6 +109,7 @@ docker buildx bake -f docker-bake.hcl --pull --no-cache --push 1. Open `.github/workflows/tests.yml` 2. Enable PHP debug symbols + ```patch - uses: shivammathur/setup-php@v2 # ... @@ -97,7 +117,9 @@ docker buildx bake -f docker-bake.hcl --pull --no-cache --push phpts: ts + debug: true ``` + 3. Enable `tmate` to connect to the container + ```patch - name: Set CGO flags @@ -110,19 +132,24 @@ docker buildx bake -f docker-bake.hcl --pull --no-cache --push + - + uses: mxschmitt/action-tmate@v3 ``` + 4. Connect to the container 5. Open `frankenphp.go` 6. Enable `cgosymbolizer` + ```patch - //_ "github.com/ianlancetaylor/cgosymbolizer" + _ "github.com/ianlancetaylor/cgosymbolizer" ``` + 7. Download the module: `go get` 8. In the container, you can use GDB and the like: - ```sh + + ```console go test -c -ldflags=-w gdb --args ./frankenphp.test -test.run ^MyTest$ ``` + 9. When the bug is fixed, revert all these changes ## Misc Dev Resources @@ -142,10 +169,9 @@ docker buildx bake -f docker-bake.hcl --pull --no-cache --push * [Bake file definition](https://docs.docker.com/build/customize/bake/file-definition/) * [docker buildx build](https://docs.docker.com/engine/reference/commandline/buildx_build/) - ## Useful Command -``` +```console apk add strace util-linux gdb strace -e 'trace=!futex,epoll_ctl,epoll_pwait,tgkill,rt_sigreturn' -p 1 ``` diff --git a/Dockerfile b/Dockerfile index 67ecfec6..c931df72 100644 --- a/Dockerfile +++ b/Dockerfile @@ -46,6 +46,7 @@ LABEL org.opencontainers.image.vendor="Kévin Dunglas" FROM common AS builder ARG FRANKENPHP_VERSION='dev' +SHELL ["/bin/bash", "-o", "pipefail", "-c"] COPY --from=golang-base /usr/local/go /usr/local/go @@ -71,12 +72,11 @@ WORKDIR /go/src/app COPY --link go.mod go.sum ./ RUN go mod graph | awk '{if ($1 !~ "@") print $2}' | xargs go get -RUN mkdir caddy && cd caddy -COPY --link caddy/go.mod caddy/go.sum ./caddy/ - -RUN cd caddy && \ - go mod graph | awk '{if ($1 !~ "@") print $2}' | xargs go get +WORKDIR /go/src/app/caddy +COPY --link caddy/go.mod caddy/go.sum ./ +RUN go mod graph | awk '{if ($1 !~ "@") print $2}' | xargs go get +WORKDIR /go/src/app COPY --link *.* ./ COPY --link caddy caddy COPY --link C-Thread-Pool C-Thread-Pool @@ -87,12 +87,14 @@ COPY --link testdata testdata # see https://github.com/docker-library/php/blob/master/8.2/bookworm/zts/Dockerfile#L57-L59 for PHP values ENV CGO_LDFLAGS="-lssl -lcrypto -lreadline -largon2 -lcurl -lonig -lz $PHP_LDFLAGS" CGO_CFLAGS="-DFRANKENPHP_VERSION=$FRANKENPHP_VERSION $PHP_CFLAGS" CGO_CPPFLAGS=$PHP_CPPFLAGS -RUN cd caddy/frankenphp && \ - GOBIN=/usr/local/bin go install -ldflags "-X 'github.com/caddyserver/caddy/v2.CustomVersion=FrankenPHP $FRANKENPHP_VERSION PHP $PHP_VERSION Caddy'" && \ +WORKDIR /go/src/app/caddy/frankenphp +RUN GOBIN=/usr/local/bin go install -ldflags "-X 'github.com/caddyserver/caddy/v2.CustomVersion=FrankenPHP $FRANKENPHP_VERSION PHP $PHP_VERSION Caddy'" && \ setcap cap_net_bind_service=+ep /usr/local/bin/frankenphp && \ cp Caddyfile /etc/caddy/Caddyfile && \ frankenphp version +WORKDIR /go/src/app + FROM common AS runner diff --git a/README.md b/README.md index e697527c..24c221c6 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ FrankenPHP is a modern application server for PHP built on top of the [Caddy](ht FrankenPHP gives superpowers to your PHP apps thanks to its stunning features: [*Early Hints*](docs/early-hints.md), [worker mode](docs/worker.md), [real-time capabilities](docs/mercure.md), automatic HTTPS, HTTP/2, and HTTP/3 support... -FrankenPHP works with any PHP app and makes your Symfony projects faster than ever thanks to provided integration with the worker mode (Laravel Octane support coming). +FrankenPHP works with any PHP app and makes your Symfony projects faster than ever thanks to the provided integration with the worker mode (Laravel Octane support coming). FrankenPHP can also be used as a standalone Go library to embed PHP in any app using `net/http`. diff --git a/alpine.Dockerfile b/alpine.Dockerfile index 91cb9a14..9c77a2c0 100644 --- a/alpine.Dockerfile +++ b/alpine.Dockerfile @@ -43,11 +43,13 @@ LABEL org.opencontainers.image.vendor="Kévin Dunglas" FROM common AS builder ARG FRANKENPHP_VERSION='dev' +SHELL ["/bin/ash", "-eo", "pipefail", "-c"] COPY --link --from=golang-base /usr/local/go /usr/local/go ENV PATH /usr/local/go/bin:$PATH +# hadolint ignore=SC2086 RUN apk add --no-cache --virtual .build-deps \ $PHPIZE_DEPS \ argon2-dev \ @@ -67,11 +69,11 @@ WORKDIR /go/src/app COPY --link go.mod go.sum ./ RUN go mod graph | awk '{if ($1 !~ "@") print $2}' | xargs go get -RUN mkdir caddy && cd caddy -COPY caddy/go.mod caddy/go.sum ./caddy/ - -RUN cd caddy && go mod graph | awk '{if ($1 !~ "@") print $2}' | xargs go get +WORKDIR /go/src/app/caddy +COPY caddy/go.mod caddy/go.sum ./ +RUN go mod graph | awk '{if ($1 !~ "@") print $2}' | xargs go get +WORKDIR /go/src/app COPY --link *.* ./ COPY --link caddy caddy COPY --link C-Thread-Pool C-Thread-Pool @@ -82,11 +84,13 @@ COPY --link testdata testdata # see https://github.com/docker-library/php/blob/master/8.2/bookworm/zts/Dockerfile#L57-L59 for php values ENV CGO_LDFLAGS="-lssl -lcrypto -lreadline -largon2 -lcurl -lonig -lz $PHP_LDFLAGS" CGO_CFLAGS="-DFRANKENPHP_VERSION=$FRANKENPHP_VERSION $PHP_CFLAGS" CGO_CPPFLAGS=$PHP_CPPFLAGS -RUN cd caddy/frankenphp && \ - GOBIN=/usr/local/bin go install -ldflags "-extldflags '-Wl,-z,stack-size=0x80000' -X 'github.com/caddyserver/caddy/v2.CustomVersion=FrankenPHP $FRANKENPHP_VERSION PHP $PHP_VERSION Caddy'" && \ +WORKDIR /go/src/app/caddy/frankenphp +RUN GOBIN=/usr/local/bin go install -ldflags "-extldflags '-Wl,-z,stack-size=0x80000' -X 'github.com/caddyserver/caddy/v2.CustomVersion=FrankenPHP $FRANKENPHP_VERSION PHP $PHP_VERSION Caddy'" && \ setcap cap_net_bind_service=+ep /usr/local/bin/frankenphp && \ frankenphp version +WORKDIR /go/src/app + FROM common AS runner diff --git a/build-static.sh b/build-static.sh index e4c878c7..2d2c992f 100755 --- a/build-static.sh +++ b/build-static.sh @@ -1,7 +1,6 @@ #!/bin/sh set -o errexit -trap 'echo "Aborting due to errexit on line $LINENO. Exit code: $?" >&2' ERR set -o xtrace if ! type "git" > /dev/null; then @@ -38,7 +37,13 @@ if [ -z "$FRANKENPHP_VERSION" ]; then elif [ -d ".git/" ]; then CURRENT_REF="$(git rev-parse --abbrev-ref HEAD)" export CURRENT_REF - git checkout "v$FRANKENPHP_VERSION" + + if echo "$FRANKENPHP_VERSION" | grep -F -q "."; then + # Tag + git checkout "v$FRANKENPHP_VERSION" + else + git checkout "$FRANKENPHP_VERSION" + fi fi bin="frankenphp-$os-$arch" @@ -72,6 +77,7 @@ fi ./bin/spc doctor ./bin/spc fetch --with-php="$PHP_VERSION" --for-extensions="$PHP_EXTENSIONS" +# shellcheck disable=SC2086 ./bin/spc build --enable-zts --build-embed $extraOpts "$PHP_EXTENSIONS" --with-libs="$PHP_EXTENSION_LIBS" CGO_CFLAGS="-DFRANKENPHP_VERSION=$FRANKENPHP_VERSION $(./buildroot/bin/php-config --includes | sed s#-I/#-I"$PWD"/buildroot/#g)" export CGO_CFLAGS diff --git a/dev-alpine.Dockerfile b/dev-alpine.Dockerfile index b240ecf2..196d6755 100644 --- a/dev-alpine.Dockerfile +++ b/dev-alpine.Dockerfile @@ -37,8 +37,8 @@ RUN apk add --no-cache \ libtool && \ echo 'set auto-load safe-path /' > /root/.gdbinit -RUN git clone --branch=PHP-8.3 https://github.com/php/php-src.git && \ - cd php-src && \ +WORKDIR /usr/local/src/php +RUN git clone --branch=PHP-8.3 https://github.com/php/php-src.git . && \ # --enable-embed is only necessary to generate libphp.so, we don't use this SAPI directly ./buildconf --force && \ ./configure \ @@ -47,18 +47,19 @@ RUN git clone --branch=PHP-8.3 https://github.com/php/php-src.git && \ --disable-zend-signals \ --enable-zend-max-execution-timers \ --enable-debug && \ - make -j$(nproc) && \ + make -j"$(nproc)" && \ make install && \ ldconfig /etc/ld.so.conf.d && \ cp php.ini-development /usr/local/lib/php.ini && \ - echo -e "zend_extension=opcache.so\nopcache.enable=1" >> /usr/local/lib/php.ini &&\ + echo "zend_extension=opcache.so" >> /usr/local/lib/php.ini && \ + echo "opcache.enable=1" >> /usr/local/lib/php.ini && \ php --version WORKDIR /go/src/app - COPY . . -RUN cd caddy/frankenphp && \ - go build +WORKDIR /go/src/app/caddy/frankenphp +RUN go build +WORKDIR /go/src/app CMD [ "zsh" ] diff --git a/dev.Dockerfile b/dev.Dockerfile index 60015e2a..732224e5 100644 --- a/dev.Dockerfile +++ b/dev.Dockerfile @@ -13,6 +13,7 @@ ENV PHPIZE_DEPS \ pkg-config \ re2c +# hadolint ignore=DL3009 RUN apt-get update && \ apt-get -y --no-install-recommends install \ $PHPIZE_DEPS \ @@ -41,8 +42,8 @@ RUN apt-get update && \ && \ apt-get clean -RUN git clone --branch=PHP-8.3 https://github.com/php/php-src.git && \ - cd php-src && \ +WORKDIR /usr/local/src/php +RUN git clone --branch=PHP-8.3 https://github.com/php/php-src.git . && \ # --enable-embed is only necessary to generate libphp.so, we don't use this SAPI directly ./buildconf --force && \ ./configure \ @@ -51,18 +52,19 @@ RUN git clone --branch=PHP-8.3 https://github.com/php/php-src.git && \ --disable-zend-signals \ --enable-zend-max-execution-timers \ --enable-debug && \ - make -j$(nproc) && \ + make -j"$(nproc)" && \ make install && \ ldconfig && \ cp php.ini-development /usr/local/lib/php.ini && \ - echo "zend_extension=opcache.so\nopcache.enable=1" >> /usr/local/lib/php.ini &&\ + echo "zend_extension=opcache.so" >> /usr/local/lib/php.ini && \ + echo "opcache.enable=1" >> /usr/local/lib/php.ini && \ php --version WORKDIR /go/src/app - COPY . . -RUN cd caddy/frankenphp && \ - go build +WORKDIR /go/src/app/caddy/frankenphp +RUN go build +WORKDIR /go/src/app CMD [ "zsh" ] diff --git a/docs/compile.md b/docs/compile.md index b802cba2..53cf0227 100644 --- a/docs/compile.md +++ b/docs/compile.md @@ -89,4 +89,4 @@ CGO_ENABLED=1 xcaddy build \ --with github.com/dunglas/mercure/caddy \ --with github.com/dunglas/vulcain/caddy # Add extra Caddy modules here -``` \ No newline at end of file +``` diff --git a/docs/docker.md b/docs/docker.md index 3baa4c8d..f91d07d2 100644 --- a/docs/docker.md +++ b/docs/docker.md @@ -15,8 +15,8 @@ COPY . /app/public Then, run the commands to build and run the Docker image: ```console -$ docker build -t my-php-app . -$ docker run -it --rm --name my-running-app my-php-app +docker build -t my-php-app . +docker run -it --rm --name my-running-app my-php-app ``` ## How to Install More PHP Extensions @@ -70,7 +70,7 @@ COPY --from=builder /usr/local/bin/frankenphp /usr/local/bin/frankenphp The `builder` image provided by FrankenPHP contains a compiled version of libphp. [Builders images](https://hub.docker.com/r/dunglas/frankenphp/tags?name=builder) are provided for all versions of FrankenPHP and PHP, both for Alpine and Debian. -# Enabling the Worker Mode by Default +## Enabling the Worker Mode by Default Set the `FRANKENPHP_CONFIG` environment variable to start FrankenPHP with a worker script: @@ -82,7 +82,7 @@ FROM dunglas/frankenphp ENV FRANKENPHP_CONFIG="worker ./public/index.php" ``` -# Using a Volume in Development +## Using a Volume in Development To develop easily with FrankenPHP, mount the directory from your host containing the source code of the app as a volume in the Docker container: diff --git a/docs/known-issues.md b/docs/known-issues.md index 3f617865..ade7d69c 100644 --- a/docs/known-issues.md +++ b/docs/known-issues.md @@ -6,7 +6,6 @@ Calling PHP functions and language constructs that themselves call [cgo](https:/ This issue [is being worked on by the Go project](https://github.com/golang/go/issues/62130). - In the meantime, one solution is not to use constructs (like `echo`) and functions (like `header()`) that delegate to Go from inside Fibers. This code will likely crash because it uses `echo` in the Fiber: diff --git a/docs/laravel.md b/docs/laravel.md index b015ba9a..b1b31860 100644 --- a/docs/laravel.md +++ b/docs/laravel.md @@ -18,20 +18,22 @@ Alternatively, you can run your Laravel projects with FrankenPHP from your local 1. [Download the binary corresponding to your system](https://github.com/dunglas/frankenphp/releases) 2. Add the following configuration to a file named `Caddyfile` in the root directory of your Laravel project: -```caddyfile -{ - frankenphp - order php_server before file_server -} -# The domain name of your server -localhost { - # Enable compression (optional) - encode zstd gzip - # Execute PHP files in the current directory and serve assets - php_server -} -``` + ```caddyfile + { + frankenphp + order php_server before file_server + } + + # The domain name of your server + localhost { + # Enable compression (optional) + encode zstd gzip + # Execute PHP files in the current directory and serve assets + php_server + } + ``` + 3. Start FrankenPHP from the root directory of your Laravel project: `./frankenphp run` ## Laravel Octane diff --git a/docs/mercure.md b/docs/mercure.md index 0a2bf597..a3dd4e8d 100644 --- a/docs/mercure.md +++ b/docs/mercure.md @@ -7,6 +7,6 @@ No JS library or SDK required! ![Mercure](https://mercure.rocks/static/main.png) -To enable the Mercure hub, update the `Caddyfile` as described [on Mercure's website](https://mercure.rocks/docs/hub/config). +To enable the Mercure hub, update the `Caddyfile` as described [on Mercure's site](https://mercure.rocks/docs/hub/config). To push Mercure updates from your code, we recommend the [Symfony Mercure Component](https://symfony.com/components/Mercure) (you don't need the Symfony full stack framework to use it). diff --git a/docs/worker.md b/docs/worker.md index 65cd7113..18ab9754 100644 --- a/docs/worker.md +++ b/docs/worker.md @@ -64,7 +64,7 @@ do { $myApp->shutdown(); ``` -Then, start your app and use the `FRANKENPHP_CONFIG` environment variable to configure your worker: +Then, start your app and use the `FRANKENPHP_CONFIG` environment variable to configure your worker: ```console docker run \ diff --git a/frankenphp.c b/frankenphp.c index 324f6c23..80e418cd 100644 --- a/frankenphp.c +++ b/frankenphp.c @@ -1,741 +1,760 @@ +#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "C-Thread-Pool/thpool.h" #include "C-Thread-Pool/thpool.c" +#include "C-Thread-Pool/thpool.h" -#include "frankenphp_arginfo.h" #include "_cgo_export.h" +#include "frankenphp_arginfo.h" #if defined(PHP_WIN32) && defined(ZTS) ZEND_TSRMLS_CACHE_DEFINE() #endif -/* Timeouts are currently fundamentally broken with ZTS except on Linux: https://bugs.php.net/bug.php?id=79464 */ +/* Timeouts are currently fundamentally broken with ZTS except on Linux: + * https://bugs.php.net/bug.php?id=79464 */ #ifndef ZEND_MAX_EXECUTION_TIMERS -static const char HARDCODED_INI[] = - "max_execution_time=0\n" - "max_input_time=-1\n\0"; +static const char HARDCODED_INI[] = "max_execution_time=0\n" + "max_input_time=-1\n\0"; #endif -static const char *MODULES_TO_RELOAD[] = { - "filter", - "session", - NULL -}; +static const char *MODULES_TO_RELOAD[] = {"filter", "session", NULL}; frankenphp_version frankenphp_get_version() { - return (frankenphp_version){ - PHP_MAJOR_VERSION, - PHP_MINOR_VERSION, - PHP_RELEASE_VERSION, - PHP_EXTRA_VERSION, - PHP_VERSION, - PHP_VERSION_ID, - }; + return (frankenphp_version){ + PHP_MAJOR_VERSION, PHP_MINOR_VERSION, PHP_RELEASE_VERSION, + PHP_EXTRA_VERSION, PHP_VERSION, PHP_VERSION_ID, + }; } frankenphp_config frankenphp_get_config() { - return (frankenphp_config){ - frankenphp_get_version(), + return (frankenphp_config){ + frankenphp_get_version(), #ifdef ZTS - true, + true, #else - false, + false, #endif #ifdef ZEND_SIGNALS - true, + true, #else - false, + false, #endif #ifdef ZEND_MAX_EXECUTION_TIMERS - true, + true, #else - false, + false, #endif - }; + }; } typedef struct frankenphp_server_context { - uintptr_t current_request; - uintptr_t main_request; - bool worker_ready; - char *cookie_data; - bool finished; + uintptr_t current_request; + uintptr_t main_request; + bool worker_ready; + char *cookie_data; + bool finished; } frankenphp_server_context; static uintptr_t frankenphp_clean_server_context() { - frankenphp_server_context *ctx = SG(server_context); - if (ctx == NULL) { - return 0; - } + frankenphp_server_context *ctx = SG(server_context); + if (ctx == NULL) { + return 0; + } - free(SG(request_info).auth_password); - SG(request_info).auth_password = NULL; + free(SG(request_info).auth_password); + SG(request_info).auth_password = NULL; - free(SG(request_info).auth_user); - SG(request_info).auth_user = NULL; + free(SG(request_info).auth_user); + SG(request_info).auth_user = NULL; - free((char *) SG(request_info).request_method); - SG(request_info).request_method = NULL; + free((char *)SG(request_info).request_method); + SG(request_info).request_method = NULL; - free(SG(request_info).query_string); - SG(request_info).query_string = NULL; + free(SG(request_info).query_string); + SG(request_info).query_string = NULL; - free((char *) SG(request_info).content_type); - SG(request_info).content_type = NULL; + free((char *)SG(request_info).content_type); + SG(request_info).content_type = NULL; - free(SG(request_info).path_translated); - SG(request_info).path_translated = NULL; + free(SG(request_info).path_translated); + SG(request_info).path_translated = NULL; - free(SG(request_info).request_uri); - SG(request_info).request_uri = NULL; + free(SG(request_info).request_uri); + SG(request_info).request_uri = NULL; - return ctx->current_request; + return ctx->current_request; } static void frankenphp_request_reset() { - zend_try { - int i; + zend_try { + int i; - for (i=0; irequest_shutdown_func(module->type, module->module_number); - } - } + // TODO: store the list of modules to reload in a global module variable + const char **module_name; + zend_module_entry *module; + for (module_name = MODULES_TO_RELOAD; *module_name; module_name++) { + if ((module = zend_hash_str_find_ptr(&module_registry, *module_name, + strlen(*module_name)))) { + module->request_shutdown_func(module->type, module->module_number); + } + } - /* Shutdown output layer (send the set HTTP headers, cleanup output handlers, etc.) */ - zend_try { - php_output_deactivate(); - } zend_end_try(); + /* Shutdown output layer (send the set HTTP headers, cleanup output handlers, + * etc.) */ + zend_try { php_output_deactivate(); } + zend_end_try(); - /* Clean super globals */ - frankenphp_request_reset(); + /* Clean super globals */ + frankenphp_request_reset(); - /* SAPI related shutdown (free stuff) */ - frankenphp_clean_server_context(); - zend_try { - sapi_deactivate(); - } zend_end_try(); + /* SAPI related shutdown (free stuff) */ + frankenphp_clean_server_context(); + zend_try { sapi_deactivate(); } + zend_end_try(); - zend_set_memory_limit(PG(memory_limit)); + zend_set_memory_limit(PG(memory_limit)); } /* Adapted from php_request_startup() */ static int frankenphp_worker_request_startup() { - int retval = SUCCESS; + int retval = SUCCESS; - zend_try { - php_output_activate(); + zend_try { + php_output_activate(); - /* initialize global variables */ - PG(header_is_being_sent) = 0; - PG(connection_status) = PHP_CONNECTION_NORMAL; + /* initialize global variables */ + PG(header_is_being_sent) = 0; + PG(connection_status) = PHP_CONNECTION_NORMAL; - /* Keep the current execution context */ - sapi_activate(); + /* Keep the current execution context */ + sapi_activate(); - /* - * Timeouts are currently fundamentally broken with ZTS: https://bugs.php.net/bug.php?id=79464 - * - *if (PG(max_input_time) == -1) { - * zend_set_timeout(EG(timeout_seconds), 1); - *} else { - * zend_set_timeout(PG(max_input_time), 1); - *} - */ + /* + * Timeouts are currently fundamentally broken with ZTS: + *https://bugs.php.net/bug.php?id=79464 + * + *if (PG(max_input_time) == -1) { + * zend_set_timeout(EG(timeout_seconds), 1); + *} else { + * zend_set_timeout(PG(max_input_time), 1); + *} + */ - if (PG(expose_php)) { - sapi_add_header(SAPI_PHP_VERSION_HEADER, sizeof(SAPI_PHP_VERSION_HEADER)-1, 1); - } + if (PG(expose_php)) { + sapi_add_header(SAPI_PHP_VERSION_HEADER, + sizeof(SAPI_PHP_VERSION_HEADER) - 1, 1); + } - if (PG(output_handler) && PG(output_handler)[0]) { - zval oh; + if (PG(output_handler) && PG(output_handler)[0]) { + zval oh; - ZVAL_STRING(&oh, PG(output_handler)); - php_output_start_user(&oh, 0, PHP_OUTPUT_HANDLER_STDFLAGS); - zval_ptr_dtor(&oh); - } else if (PG(output_buffering)) { - php_output_start_user(NULL, PG(output_buffering) > 1 ? PG(output_buffering) : 0, PHP_OUTPUT_HANDLER_STDFLAGS); - } else if (PG(implicit_flush)) { - php_output_set_implicit_flush(1); - } + ZVAL_STRING(&oh, PG(output_handler)); + php_output_start_user(&oh, 0, PHP_OUTPUT_HANDLER_STDFLAGS); + zval_ptr_dtor(&oh); + } else if (PG(output_buffering)) { + php_output_start_user(NULL, + PG(output_buffering) > 1 ? PG(output_buffering) : 0, + PHP_OUTPUT_HANDLER_STDFLAGS); + } else if (PG(implicit_flush)) { + php_output_set_implicit_flush(1); + } - php_hash_environment(); + php_hash_environment(); - zend_is_auto_global(ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_SERVER)); + zend_is_auto_global(ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_SERVER)); - // unfinish the request - frankenphp_server_context *ctx = SG(server_context); - ctx->finished = false; + // unfinish the request + frankenphp_server_context *ctx = SG(server_context); + ctx->finished = false; - // TODO: store the list of modules to reload in a global module variable - const char **module_name; - zend_module_entry *module; - for (module_name = MODULES_TO_RELOAD; *module_name; module_name++) { - if ( - (module = zend_hash_str_find_ptr(&module_registry, *module_name, sizeof(*module_name)-1)) - && module->request_startup_func - ) { - module->request_startup_func(module->type, module->module_number); - } - } - } zend_catch { - retval = FAILURE; - } zend_end_try(); + // TODO: store the list of modules to reload in a global module variable + const char **module_name; + zend_module_entry *module; + for (module_name = MODULES_TO_RELOAD; *module_name; module_name++) { + if ((module = zend_hash_str_find_ptr(&module_registry, *module_name, + sizeof(*module_name) - 1)) && + module->request_startup_func) { + module->request_startup_func(module->type, module->module_number); + } + } + } + zend_catch { retval = FAILURE; } + zend_end_try(); - SG(sapi_started) = 1; + SG(sapi_started) = 1; - return retval; + return retval; } PHP_FUNCTION(frankenphp_finish_request) { /* {{{ */ - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + if (zend_parse_parameters_none() == FAILURE) { + RETURN_THROWS(); + } - frankenphp_server_context *ctx = SG(server_context); + frankenphp_server_context *ctx = SG(server_context); - if (ctx->finished) { - RETURN_FALSE; - } + if (ctx->finished) { + RETURN_FALSE; + } - php_output_end_all(); - php_header(); + php_output_end_all(); + php_header(); - if (ctx->current_request != 0) { - go_frankenphp_finish_request(ctx->main_request, ctx->current_request, false); - } + if (ctx->current_request != 0) { + go_frankenphp_finish_request(ctx->main_request, ctx->current_request, + false); + } - ctx->finished = true; + ctx->finished = true; - RETURN_TRUE; + RETURN_TRUE; } /* }}} */ PHP_FUNCTION(frankenphp_handle_request) { - zend_fcall_info fci; - zend_fcall_info_cache fcc; + zend_fcall_info fci; + zend_fcall_info_cache fcc; - ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_FUNC(fci, fcc) - ZEND_PARSE_PARAMETERS_END(); + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_FUNC(fci, fcc) + ZEND_PARSE_PARAMETERS_END(); - frankenphp_server_context *ctx = SG(server_context); + frankenphp_server_context *ctx = SG(server_context); - if (ctx->main_request == 0) { - // not a worker, throw an error - zend_throw_exception(spl_ce_RuntimeException, "frankenphp_handle_request() called while not in worker mode", 0); - RETURN_THROWS(); - } + if (ctx->main_request == 0) { + // not a worker, throw an error + zend_throw_exception( + spl_ce_RuntimeException, + "frankenphp_handle_request() called while not in worker mode", 0); + RETURN_THROWS(); + } - if (!ctx->worker_ready) { - /* Clean the first dummy request created to initialize the worker */ - frankenphp_worker_request_shutdown(); + if (!ctx->worker_ready) { + /* Clean the first dummy request created to initialize the worker */ + frankenphp_worker_request_shutdown(); - ctx->worker_ready = true; + ctx->worker_ready = true; - /* Mark the worker as ready to handle requests */ - go_frankenphp_worker_ready(); - } + /* Mark the worker as ready to handle requests */ + go_frankenphp_worker_ready(); + } #ifdef ZEND_MAX_EXECUTION_TIMERS - // Disable timeouts while waiting for a request to handle - zend_unset_timeout(); + // Disable timeouts while waiting for a request to handle + zend_unset_timeout(); #endif - uintptr_t request = go_frankenphp_worker_handle_request_start(ctx->main_request); - if ( - frankenphp_worker_request_startup() == FAILURE - /* Shutting down */ - || !request - ) { - RETURN_FALSE; - } + uintptr_t request = + go_frankenphp_worker_handle_request_start(ctx->main_request); + if (frankenphp_worker_request_startup() == FAILURE + /* Shutting down */ + || !request) { + RETURN_FALSE; + } #ifdef ZEND_MAX_EXECUTION_TIMERS - // Reset default timeout - // TODO: add support for max_input_time - zend_set_timeout(INI_INT("max_execution_time"), 0); + // Reset default timeout + // TODO: add support for max_input_time + zend_set_timeout(INI_INT("max_execution_time"), 0); #endif - /* Call the PHP func */ - zval retval = {0}; - fci.size = sizeof fci; - fci.retval = &retval; - if (zend_call_function(&fci, &fcc) == SUCCESS) { - zval_ptr_dtor(&retval); - } + /* Call the PHP func */ + zval retval = {0}; + fci.size = sizeof fci; + fci.retval = &retval; + if (zend_call_function(&fci, &fcc) == SUCCESS) { + zval_ptr_dtor(&retval); + } - /* If an exception occured, print the message to the client before closing the connection */ - if (EG(exception)) { - zend_exception_error(EG(exception), E_ERROR); - } + /* If an exception occured, print the message to the client before closing the + * connection */ + if (EG(exception)) { + zend_exception_error(EG(exception), E_ERROR); + } - frankenphp_worker_request_shutdown(); - ctx->current_request = 0; - go_frankenphp_finish_request(ctx->main_request, request, true); + frankenphp_worker_request_shutdown(); + ctx->current_request = 0; + go_frankenphp_finish_request(ctx->main_request, request, true); - RETURN_TRUE; + RETURN_TRUE; } PHP_FUNCTION(headers_send) { - zend_long response_code = 200; + zend_long response_code = 200; - ZEND_PARSE_PARAMETERS_START(0, 1) - Z_PARAM_OPTIONAL - Z_PARAM_LONG(response_code) - ZEND_PARSE_PARAMETERS_END(); + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(response_code) + ZEND_PARSE_PARAMETERS_END(); - int previous_status_code = SG(sapi_headers).http_response_code; - SG(sapi_headers).http_response_code = response_code; + int previous_status_code = SG(sapi_headers).http_response_code; + SG(sapi_headers).http_response_code = response_code; - if (response_code >= 100 && response_code < 200) { - int ret = sapi_module.send_headers(&SG(sapi_headers)); - SG(sapi_headers).http_response_code = previous_status_code; + if (response_code >= 100 && response_code < 200) { + int ret = sapi_module.send_headers(&SG(sapi_headers)); + SG(sapi_headers).http_response_code = previous_status_code; - RETURN_LONG(ret); - } - - RETURN_LONG(sapi_send_headers()); + RETURN_LONG(ret); + } + + RETURN_LONG(sapi_send_headers()); } static zend_module_entry frankenphp_module = { STANDARD_MODULE_HEADER, "frankenphp", - ext_functions, /* function table */ - NULL, /* initialization */ - NULL, /* shutdown */ - NULL, /* request initialization */ - NULL, /* request shutdown */ - NULL, /* information */ + ext_functions, /* function table */ + NULL, /* initialization */ + NULL, /* shutdown */ + NULL, /* request initialization */ + NULL, /* request shutdown */ + NULL, /* information */ TOSTRING(FRANKENPHP_VERSION), - STANDARD_MODULE_PROPERTIES -}; + STANDARD_MODULE_PROPERTIES}; -static uintptr_t frankenphp_request_shutdown() -{ - frankenphp_server_context *ctx = SG(server_context); +static uintptr_t frankenphp_request_shutdown() { + frankenphp_server_context *ctx = SG(server_context); - if (ctx->main_request && ctx->current_request) { - frankenphp_request_reset(); - } + if (ctx->main_request && ctx->current_request) { + frankenphp_request_reset(); + } - php_request_shutdown((void *) 0); + php_request_shutdown((void *)0); - free(ctx->cookie_data); - ((frankenphp_server_context*) SG(server_context))->cookie_data = NULL; - uintptr_t rh = frankenphp_clean_server_context(); + free(ctx->cookie_data); + ((frankenphp_server_context *)SG(server_context))->cookie_data = NULL; + uintptr_t rh = frankenphp_clean_server_context(); - free(ctx); - SG(server_context) = NULL; + free(ctx); + SG(server_context) = NULL; #if defined(ZTS) - ts_free_thread(); + ts_free_thread(); #endif - return rh; + return rh; } int frankenphp_update_server_context( - bool create, - uintptr_t current_request, - uintptr_t main_request, + bool create, uintptr_t current_request, uintptr_t main_request, - const char *request_method, - char *query_string, - zend_long content_length, - char *path_translated, - char *request_uri, - const char *content_type, - char *auth_user, - char *auth_password, - int proto_num -) { - frankenphp_server_context *ctx; + const char *request_method, char *query_string, zend_long content_length, + char *path_translated, char *request_uri, const char *content_type, + char *auth_user, char *auth_password, int proto_num) { + frankenphp_server_context *ctx; - if (create) { + if (create) { #ifdef ZTS - /* initial resource fetch */ - (void)ts_resource(0); -# ifdef PHP_WIN32 - ZEND_TSRMLS_CACHE_UPDATE(); -# endif + /* initial resource fetch */ + (void)ts_resource(0); +#ifdef PHP_WIN32 + ZEND_TSRMLS_CACHE_UPDATE(); +#endif #endif - /* todo: use a pool */ - ctx = (frankenphp_server_context *) calloc(1, sizeof(frankenphp_server_context)); - if (ctx == NULL) { - return FAILURE; - } + /* todo: use a pool */ + ctx = (frankenphp_server_context *)calloc( + 1, sizeof(frankenphp_server_context)); + if (ctx == NULL) { + return FAILURE; + } - ctx->cookie_data = NULL; - ctx->finished = false; + ctx->cookie_data = NULL; + ctx->finished = false; - SG(server_context) = ctx; - } else { - ctx = (frankenphp_server_context *) SG(server_context); - } + SG(server_context) = ctx; + } else { + ctx = (frankenphp_server_context *)SG(server_context); + } - ctx->main_request = main_request; - ctx->current_request = current_request; + ctx->main_request = main_request; + ctx->current_request = current_request; - SG(request_info).auth_password = auth_password; - SG(request_info).auth_user = auth_user; - SG(request_info).request_method = request_method; - SG(request_info).query_string = query_string; - SG(request_info).content_type = content_type; - SG(request_info).content_length = content_length; - SG(request_info).path_translated = path_translated; - SG(request_info).request_uri = request_uri; - SG(request_info).proto_num = proto_num; + SG(request_info).auth_password = auth_password; + SG(request_info).auth_user = auth_user; + SG(request_info).request_method = request_method; + SG(request_info).query_string = query_string; + SG(request_info).content_type = content_type; + SG(request_info).content_length = content_length; + SG(request_info).path_translated = path_translated; + SG(request_info).request_uri = request_uri; + SG(request_info).proto_num = proto_num; - return SUCCESS; + return SUCCESS; } -static int frankenphp_startup(sapi_module_struct *sapi_module) -{ - return php_module_startup(sapi_module, &frankenphp_module); +static int frankenphp_startup(sapi_module_struct *sapi_module) { + return php_module_startup(sapi_module, &frankenphp_module); } -static int frankenphp_deactivate(void) -{ - /* TODO: flush everything */ - return SUCCESS; +static int frankenphp_deactivate(void) { + /* TODO: flush everything */ + return SUCCESS; } -static size_t frankenphp_ub_write(const char *str, size_t str_length) -{ - frankenphp_server_context* ctx = SG(server_context); +static size_t frankenphp_ub_write(const char *str, size_t str_length) { + frankenphp_server_context *ctx = SG(server_context); - if(ctx->finished) { - // TODO: maybe log a warning that we tried to write to a finished request? - return 0; - } + if (ctx->finished) { + // TODO: maybe log a warning that we tried to write to a finished request? + return 0; + } - struct go_ub_write_return result = go_ub_write(ctx->current_request ? ctx->current_request : ctx->main_request, (char *) str, str_length); + struct go_ub_write_return result = go_ub_write( + ctx->current_request ? ctx->current_request : ctx->main_request, + (char *)str, str_length); - if (result.r1) { - php_handle_aborted_connection(); - } + if (result.r1) { + php_handle_aborted_connection(); + } - return result.r0; + return result.r0; } -static int frankenphp_send_headers(sapi_headers_struct *sapi_headers) -{ - if (SG(request_info).no_headers == 1) { - return SAPI_HEADER_SENT_SUCCESSFULLY; - } +static int frankenphp_send_headers(sapi_headers_struct *sapi_headers) { + if (SG(request_info).no_headers == 1) { + return SAPI_HEADER_SENT_SUCCESSFULLY; + } - int status; - frankenphp_server_context* ctx = SG(server_context); + int status; + frankenphp_server_context *ctx = SG(server_context); - if (ctx->current_request == 0) { - return SAPI_HEADER_SEND_FAILED; - } + if (ctx->current_request == 0) { + return SAPI_HEADER_SEND_FAILED; + } - if (SG(sapi_headers).http_status_line) { - status = atoi((SG(sapi_headers).http_status_line) + 9); - } else { - status = SG(sapi_headers).http_response_code; + if (SG(sapi_headers).http_status_line) { + status = atoi((SG(sapi_headers).http_status_line) + 9); + } else { + status = SG(sapi_headers).http_response_code; - if (!status) { - status = 200; - } - } + if (!status) { + status = 200; + } + } - go_write_headers(ctx->current_request, status, &sapi_headers->headers); + go_write_headers(ctx->current_request, status, &sapi_headers->headers); - return SAPI_HEADER_SENT_SUCCESSFULLY; + return SAPI_HEADER_SENT_SUCCESSFULLY; } -static void frankenphp_sapi_flush(void *server_context) -{ - frankenphp_server_context *ctx = (frankenphp_server_context *) server_context; +static void frankenphp_sapi_flush(void *server_context) { + frankenphp_server_context *ctx = (frankenphp_server_context *)server_context; - if (ctx && ctx->current_request != 0 && go_sapi_flush(ctx->current_request)) { - php_handle_aborted_connection(); - } + if (ctx && ctx->current_request != 0 && go_sapi_flush(ctx->current_request)) { + php_handle_aborted_connection(); + } } -static size_t frankenphp_read_post(char *buffer, size_t count_bytes) -{ - frankenphp_server_context* ctx = SG(server_context); +static size_t frankenphp_read_post(char *buffer, size_t count_bytes) { + frankenphp_server_context *ctx = SG(server_context); - return ctx->current_request ? go_read_post(ctx->current_request, buffer, count_bytes) : 0; + return ctx->current_request + ? go_read_post(ctx->current_request, buffer, count_bytes) + : 0; } -static char* frankenphp_read_cookies(void) -{ - frankenphp_server_context* ctx = SG(server_context); +static char *frankenphp_read_cookies(void) { + frankenphp_server_context *ctx = SG(server_context); - if (ctx->current_request == 0) { - return ""; - } + if (ctx->current_request == 0) { + return ""; + } - ctx->cookie_data = go_read_cookies(ctx->current_request); + ctx->cookie_data = go_read_cookies(ctx->current_request); - return ctx->cookie_data; + return ctx->cookie_data; } -static void frankenphp_register_known_variable(const char *key, char *value, zval *track_vars_array, bool f) -{ - if (value == NULL) { - return; - } +static void frankenphp_register_known_variable(const char *key, char *value, + zval *track_vars_array, bool f) { + if (value == NULL) { + return; + } - size_t new_val_len; - if (sapi_module.input_filter(PARSE_SERVER, key, &value, strlen(value), &new_val_len)) { - php_register_variable_safe(key, value, new_val_len, track_vars_array); - } + size_t new_val_len; + if (sapi_module.input_filter(PARSE_SERVER, key, &value, strlen(value), + &new_val_len)) { + php_register_variable_safe(key, value, new_val_len, track_vars_array); + } - if (f) { - free(value); - value = NULL; - } + if (f) { + free(value); + value = NULL; + } } -void frankenphp_register_bulk_variables(char *known_variables[27], char **dynamic_variables, size_t size, zval *track_vars_array) -{ - /* Not used, but must be present */ - frankenphp_register_known_variable("AUTH_TYPE", "", track_vars_array, false); - frankenphp_register_known_variable("REMOTE_IDENT", "", track_vars_array, false); +void frankenphp_register_bulk_variables(char *known_variables[27], + char **dynamic_variables, size_t size, + zval *track_vars_array) { + /* Not used, but must be present */ + frankenphp_register_known_variable("AUTH_TYPE", "", track_vars_array, false); + frankenphp_register_known_variable("REMOTE_IDENT", "", track_vars_array, + false); - /* Allocated in frankenphp_update_server_context() */ - frankenphp_register_known_variable("CONTENT_TYPE", (char *) SG(request_info).content_type, track_vars_array, false); - frankenphp_register_known_variable("PATH_TRANSLATED", (char *) SG(request_info).path_translated, track_vars_array, false); - frankenphp_register_known_variable("QUERY_STRING", SG(request_info).query_string, track_vars_array, false); - frankenphp_register_known_variable("REMOTE_USER", (char *) SG(request_info).auth_user, track_vars_array, false); - frankenphp_register_known_variable("REQUEST_METHOD", (char *) SG(request_info).request_method, track_vars_array, false); - frankenphp_register_known_variable("REQUEST_URI", SG(request_info).request_uri, track_vars_array,false); + /* Allocated in frankenphp_update_server_context() */ + frankenphp_register_known_variable("CONTENT_TYPE", + (char *)SG(request_info).content_type, + track_vars_array, false); + frankenphp_register_known_variable("PATH_TRANSLATED", + (char *)SG(request_info).path_translated, + track_vars_array, false); + frankenphp_register_known_variable( + "QUERY_STRING", SG(request_info).query_string, track_vars_array, false); + frankenphp_register_known_variable("REMOTE_USER", + (char *)SG(request_info).auth_user, + track_vars_array, false); + frankenphp_register_known_variable("REQUEST_METHOD", + (char *)SG(request_info).request_method, + track_vars_array, false); + frankenphp_register_known_variable( + "REQUEST_URI", SG(request_info).request_uri, track_vars_array, false); - /* Known variables */ - frankenphp_register_known_variable("CONTENT_LENGTH", known_variables[0], track_vars_array, true); - frankenphp_register_known_variable("DOCUMENT_ROOT", known_variables[1], track_vars_array, true); - frankenphp_register_known_variable("DOCUMENT_URI", known_variables[2], track_vars_array, true); - frankenphp_register_known_variable("GATEWAY_INTERFACE", known_variables[3], track_vars_array, true); - frankenphp_register_known_variable("HTTP_HOST", known_variables[4], track_vars_array, true); - frankenphp_register_known_variable("HTTPS", known_variables[5], track_vars_array, true); - frankenphp_register_known_variable("PATH_INFO", known_variables[6], track_vars_array, true); - frankenphp_register_known_variable("PHP_SELF", known_variables[7], track_vars_array, true); - frankenphp_register_known_variable("REMOTE_ADDR", known_variables[8], track_vars_array, known_variables[8] != known_variables[9]); - frankenphp_register_known_variable("REMOTE_HOST", known_variables[9], track_vars_array, true); - frankenphp_register_known_variable("REMOTE_PORT", known_variables[10], track_vars_array, true); - frankenphp_register_known_variable("REQUEST_SCHEME", known_variables[11], track_vars_array, true); - frankenphp_register_known_variable("SCRIPT_FILENAME", known_variables[12], track_vars_array, true); - frankenphp_register_known_variable("SCRIPT_NAME", known_variables[13], track_vars_array, true); - frankenphp_register_known_variable("SERVER_NAME", known_variables[14], track_vars_array, true); - frankenphp_register_known_variable("SERVER_PORT", known_variables[15], track_vars_array, true); - frankenphp_register_known_variable("SERVER_PROTOCOL", known_variables[16], track_vars_array, true); - frankenphp_register_known_variable("SERVER_SOFTWARE", known_variables[17], track_vars_array, true); - frankenphp_register_known_variable("SSL_PROTOCOL", known_variables[18], track_vars_array, true); + /* Known variables */ + frankenphp_register_known_variable("CONTENT_LENGTH", known_variables[0], + track_vars_array, true); + frankenphp_register_known_variable("DOCUMENT_ROOT", known_variables[1], + track_vars_array, true); + frankenphp_register_known_variable("DOCUMENT_URI", known_variables[2], + track_vars_array, true); + frankenphp_register_known_variable("GATEWAY_INTERFACE", known_variables[3], + track_vars_array, true); + frankenphp_register_known_variable("HTTP_HOST", known_variables[4], + track_vars_array, true); + frankenphp_register_known_variable("HTTPS", known_variables[5], + track_vars_array, true); + frankenphp_register_known_variable("PATH_INFO", known_variables[6], + track_vars_array, true); + frankenphp_register_known_variable("PHP_SELF", known_variables[7], + track_vars_array, true); + frankenphp_register_known_variable("REMOTE_ADDR", known_variables[8], + track_vars_array, + known_variables[8] != known_variables[9]); + frankenphp_register_known_variable("REMOTE_HOST", known_variables[9], + track_vars_array, true); + frankenphp_register_known_variable("REMOTE_PORT", known_variables[10], + track_vars_array, true); + frankenphp_register_known_variable("REQUEST_SCHEME", known_variables[11], + track_vars_array, true); + frankenphp_register_known_variable("SCRIPT_FILENAME", known_variables[12], + track_vars_array, true); + frankenphp_register_known_variable("SCRIPT_NAME", known_variables[13], + track_vars_array, true); + frankenphp_register_known_variable("SERVER_NAME", known_variables[14], + track_vars_array, true); + frankenphp_register_known_variable("SERVER_PORT", known_variables[15], + track_vars_array, true); + frankenphp_register_known_variable("SERVER_PROTOCOL", known_variables[16], + track_vars_array, true); + frankenphp_register_known_variable("SERVER_SOFTWARE", known_variables[17], + track_vars_array, true); + frankenphp_register_known_variable("SSL_PROTOCOL", known_variables[18], + track_vars_array, true); - size_t new_val_len; - for (size_t i = 0; i < size; i = i+2) - { - if (sapi_module.input_filter(PARSE_SERVER, dynamic_variables[i], &dynamic_variables[i+1], strlen(dynamic_variables[i+1]), &new_val_len)) { - php_register_variable_safe(dynamic_variables[i], dynamic_variables[i+1], new_val_len, track_vars_array); - } + size_t new_val_len; + for (size_t i = 0; i < size; i = i + 2) { + if (sapi_module.input_filter( + PARSE_SERVER, dynamic_variables[i], &dynamic_variables[i + 1], + strlen(dynamic_variables[i + 1]), &new_val_len)) { + php_register_variable_safe(dynamic_variables[i], dynamic_variables[i + 1], + new_val_len, track_vars_array); + } - free(dynamic_variables[i]); - free(dynamic_variables[i+1]); - } + free(dynamic_variables[i]); + free(dynamic_variables[i + 1]); + } - free(dynamic_variables); + free(dynamic_variables); } -static void frankenphp_register_variables(zval *track_vars_array) -{ - /* https://www.php.net/manual/en/reserved.variables.server.php */ - frankenphp_server_context* ctx = SG(server_context); +static void frankenphp_register_variables(zval *track_vars_array) { + /* https://www.php.net/manual/en/reserved.variables.server.php */ + frankenphp_server_context *ctx = SG(server_context); - go_register_variables(ctx->current_request ? ctx->current_request : ctx->main_request, track_vars_array); + go_register_variables(ctx->current_request ? ctx->current_request + : ctx->main_request, + track_vars_array); } -static void frankenphp_log_message(const char *message, int syslog_type_int) -{ - go_log((char *) message, syslog_type_int); +static void frankenphp_log_message(const char *message, int syslog_type_int) { + go_log((char *)message, syslog_type_int); } sapi_module_struct frankenphp_sapi_module = { - "frankenphp", /* name */ - "FrankenPHP", /* pretty name */ + "frankenphp", /* name */ + "FrankenPHP", /* pretty name */ - frankenphp_startup, /* startup */ - php_module_shutdown_wrapper, /* shutdown */ + frankenphp_startup, /* startup */ + php_module_shutdown_wrapper, /* shutdown */ - NULL, /* activate */ - frankenphp_deactivate, /* deactivate */ + NULL, /* activate */ + frankenphp_deactivate, /* deactivate */ - frankenphp_ub_write, /* unbuffered write */ - frankenphp_sapi_flush, /* flush */ - NULL, /* get uid */ - NULL, /* getenv */ + frankenphp_ub_write, /* unbuffered write */ + frankenphp_sapi_flush, /* flush */ + NULL, /* get uid */ + NULL, /* getenv */ - php_error, /* error handler */ + php_error, /* error handler */ - NULL, /* header handler */ - frankenphp_send_headers, /* send headers handler */ - NULL, /* send header handler */ + NULL, /* header handler */ + frankenphp_send_headers, /* send headers handler */ + NULL, /* send header handler */ - frankenphp_read_post, /* read POST data */ - frankenphp_read_cookies, /* read Cookies */ + frankenphp_read_post, /* read POST data */ + frankenphp_read_cookies, /* read Cookies */ - frankenphp_register_variables, /* register server variables */ - frankenphp_log_message, /* Log message */ - NULL, /* Get request time */ - NULL, /* Child terminate */ + frankenphp_register_variables, /* register server variables */ + frankenphp_log_message, /* Log message */ + NULL, /* Get request time */ + NULL, /* Child terminate */ - STANDARD_SAPI_MODULE_PROPERTIES -}; + STANDARD_SAPI_MODULE_PROPERTIES}; static void *manager_thread(void *arg) { #ifdef ZTS - // TODO: use tsrm_startup() directly as we know the number of expected threads - php_tsrm_startup(); - /*tsrm_error_set(TSRM_ERROR_LEVEL_INFO, NULL);*/ -# ifdef PHP_WIN32 - ZEND_TSRMLS_CACHE_UPDATE(); -# endif + // TODO: use tsrm_startup() directly as we know the number of expected threads + php_tsrm_startup(); + /*tsrm_error_set(TSRM_ERROR_LEVEL_INFO, NULL);*/ +#ifdef PHP_WIN32 + ZEND_TSRMLS_CACHE_UPDATE(); +#endif #endif - sapi_startup(&frankenphp_sapi_module); + sapi_startup(&frankenphp_sapi_module); #ifndef ZEND_MAX_EXECUTION_TIMERS -# if (PHP_VERSION_ID >= 80300) - frankenphp_sapi_module.ini_entries = HARDCODED_INI; -# else - frankenphp_sapi_module.ini_entries = malloc(sizeof(HARDCODED_INI)); - memcpy(frankenphp_sapi_module.ini_entries, HARDCODED_INI, sizeof(HARDCODED_INI)); -# endif +#if (PHP_VERSION_ID >= 80300) + frankenphp_sapi_module.ini_entries = HARDCODED_INI; +#else + frankenphp_sapi_module.ini_entries = malloc(sizeof(HARDCODED_INI)); + memcpy(frankenphp_sapi_module.ini_entries, HARDCODED_INI, + sizeof(HARDCODED_INI)); +#endif #endif - frankenphp_sapi_module.startup(&frankenphp_sapi_module); + frankenphp_sapi_module.startup(&frankenphp_sapi_module); - threadpool thpool = thpool_init(*((int *) arg)); - free(arg); + threadpool thpool = thpool_init(*((int *)arg)); + free(arg); - uintptr_t rh; - while ((rh = go_fetch_request())) { - thpool_add_work(thpool, go_execute_script, (void *) rh); - } + uintptr_t rh; + while ((rh = go_fetch_request())) { + thpool_add_work(thpool, go_execute_script, (void *)rh); + } - /* channel closed, shutdown gracefully */ - thpool_wait(thpool); - thpool_destroy(thpool); + /* channel closed, shutdown gracefully */ + thpool_wait(thpool); + thpool_destroy(thpool); - frankenphp_sapi_module.shutdown(&frankenphp_sapi_module); + frankenphp_sapi_module.shutdown(&frankenphp_sapi_module); - sapi_shutdown(); + sapi_shutdown(); #ifdef ZTS - tsrm_shutdown(); + tsrm_shutdown(); #endif #if (PHP_VERSION_ID < 80300) - if (frankenphp_sapi_module.ini_entries) { - free(frankenphp_sapi_module.ini_entries); - frankenphp_sapi_module.ini_entries = NULL; - } + if (frankenphp_sapi_module.ini_entries) { + free(frankenphp_sapi_module.ini_entries); + frankenphp_sapi_module.ini_entries = NULL; + } #endif - go_shutdown(); + go_shutdown(); - return NULL; + return NULL; } int frankenphp_init(int num_threads) { - pthread_t thread; + pthread_t thread; - int *num_threads_ptr = calloc(1, sizeof(int)); - *num_threads_ptr = num_threads; + int *num_threads_ptr = calloc(1, sizeof(int)); + *num_threads_ptr = num_threads; - if (pthread_create(&thread, NULL, *manager_thread, (void *) num_threads_ptr) != 0) { - go_shutdown(); + if (pthread_create(&thread, NULL, *manager_thread, (void *)num_threads_ptr) != + 0) { + go_shutdown(); - return -1; - } + return -1; + } - return pthread_detach(thread); + return pthread_detach(thread); } -int frankenphp_request_startup() -{ - if (php_request_startup() == SUCCESS) { - return SUCCESS; - } +int frankenphp_request_startup() { + if (php_request_startup() == SUCCESS) { + return SUCCESS; + } - frankenphp_server_context *ctx = SG(server_context); - SG(server_context) = NULL; - free(ctx); + frankenphp_server_context *ctx = SG(server_context); + SG(server_context) = NULL; + free(ctx); - php_request_shutdown((void *) 0); + php_request_shutdown((void *)0); - return FAILURE; + return FAILURE; } -int frankenphp_execute_script(char* file_name) -{ - if (frankenphp_request_startup() == FAILURE) { - free(file_name); +int frankenphp_execute_script(char *file_name) { + if (frankenphp_request_startup() == FAILURE) { + free(file_name); - return FAILURE; - } + return FAILURE; + } - int status = SUCCESS; + int status = SUCCESS; - zend_file_handle file_handle; - zend_stream_init_filename(&file_handle, file_name); - free(file_name); + zend_file_handle file_handle; + zend_stream_init_filename(&file_handle, file_name); + free(file_name); - file_handle.primary_script = 1; + file_handle.primary_script = 1; - zend_first_try { - EG(exit_status) = 0; - php_execute_script(&file_handle); - status = EG(exit_status); - } zend_catch { - status = EG(exit_status); - } zend_end_try(); + zend_first_try { + EG(exit_status) = 0; + php_execute_script(&file_handle); + status = EG(exit_status); + } + zend_catch { status = EG(exit_status); } + zend_end_try(); - zend_destroy_file_handle(&file_handle); + zend_destroy_file_handle(&file_handle); - frankenphp_clean_server_context(); - frankenphp_request_shutdown(); + frankenphp_clean_server_context(); + frankenphp_request_shutdown(); - return status; + return status; } // Use global variables to store CLI arguments to prevent useless allocations @@ -743,128 +762,141 @@ static char *cli_script; static int cli_argc; static char **cli_argv; -// Adapted from https://github.com/php/php-src/sapi/cli/php_cli.c (The PHP Group, The PHP License) +// Adapted from https://github.com/php/php-src/sapi/cli/php_cli.c (The PHP +// Group, The PHP License) static void cli_register_file_handles(bool no_close) /* {{{ */ { - php_stream *s_in, *s_out, *s_err; - php_stream_context *sc_in=NULL, *sc_out=NULL, *sc_err=NULL; - zend_constant ic, oc, ec; + php_stream *s_in, *s_out, *s_err; + php_stream_context *sc_in = NULL, *sc_out = NULL, *sc_err = NULL; + zend_constant ic, oc, ec; - s_in = php_stream_open_wrapper_ex("php://stdin", "rb", 0, NULL, sc_in); - s_out = php_stream_open_wrapper_ex("php://stdout", "wb", 0, NULL, sc_out); - s_err = php_stream_open_wrapper_ex("php://stderr", "wb", 0, NULL, sc_err); + s_in = php_stream_open_wrapper_ex("php://stdin", "rb", 0, NULL, sc_in); + s_out = php_stream_open_wrapper_ex("php://stdout", "wb", 0, NULL, sc_out); + s_err = php_stream_open_wrapper_ex("php://stderr", "wb", 0, NULL, sc_err); - if (s_in==NULL || s_out==NULL || s_err==NULL) { - if (s_in) php_stream_close(s_in); - if (s_out) php_stream_close(s_out); - if (s_err) php_stream_close(s_err); - return; - } + if (s_in == NULL || s_out == NULL || s_err == NULL) { + if (s_in) + php_stream_close(s_in); + if (s_out) + php_stream_close(s_out); + if (s_err) + php_stream_close(s_err); + return; + } - if (no_close) { - s_in->flags |= PHP_STREAM_FLAG_NO_CLOSE; - s_out->flags |= PHP_STREAM_FLAG_NO_CLOSE; - s_err->flags |= PHP_STREAM_FLAG_NO_CLOSE; - } + if (no_close) { + s_in->flags |= PHP_STREAM_FLAG_NO_CLOSE; + s_out->flags |= PHP_STREAM_FLAG_NO_CLOSE; + s_err->flags |= PHP_STREAM_FLAG_NO_CLOSE; + } - //s_in_process = s_in; + // s_in_process = s_in; - php_stream_to_zval(s_in, &ic.value); - php_stream_to_zval(s_out, &oc.value); - php_stream_to_zval(s_err, &ec.value); + php_stream_to_zval(s_in, &ic.value); + php_stream_to_zval(s_out, &oc.value); + php_stream_to_zval(s_err, &ec.value); - ZEND_CONSTANT_SET_FLAGS(&ic, CONST_CS, 0); - ic.name = zend_string_init_interned("STDIN", sizeof("STDIN")-1, 0); - zend_register_constant(&ic); + ZEND_CONSTANT_SET_FLAGS(&ic, CONST_CS, 0); + ic.name = zend_string_init_interned("STDIN", sizeof("STDIN") - 1, 0); + zend_register_constant(&ic); - ZEND_CONSTANT_SET_FLAGS(&oc, CONST_CS, 0); - oc.name = zend_string_init_interned("STDOUT", sizeof("STDOUT")-1, 0); - zend_register_constant(&oc); + ZEND_CONSTANT_SET_FLAGS(&oc, CONST_CS, 0); + oc.name = zend_string_init_interned("STDOUT", sizeof("STDOUT") - 1, 0); + zend_register_constant(&oc); - ZEND_CONSTANT_SET_FLAGS(&ec, CONST_CS, 0); - ec.name = zend_string_init_interned("STDERR", sizeof("STDERR")-1, 0); - zend_register_constant(&ec); + ZEND_CONSTANT_SET_FLAGS(&ec, CONST_CS, 0); + ec.name = zend_string_init_interned("STDERR", sizeof("STDERR") - 1, 0); + zend_register_constant(&ec); } /* }}} */ static void sapi_cli_register_variables(zval *track_vars_array) /* {{{ */ { - size_t len; - char *docroot = ""; + size_t len; + char *docroot = ""; - /* In CGI mode, we consider the environment to be a part of the server - * variables - */ - php_import_environment_variables(track_vars_array); + /* In CGI mode, we consider the environment to be a part of the server + * variables + */ + php_import_environment_variables(track_vars_array); - /* Build the special-case PHP_SELF variable for the CLI version */ - len = strlen(cli_script); - if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &cli_script, len, &len)) { - php_register_variable_safe("PHP_SELF", cli_script, len, track_vars_array); - } - if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_NAME", &cli_script, len, &len)) { - php_register_variable_safe("SCRIPT_NAME", cli_script, len, track_vars_array); - } - /* filenames are empty for stdin */ - if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_FILENAME", &cli_script, len, &len)) { - php_register_variable_safe("SCRIPT_FILENAME", cli_script, len, track_vars_array); - } - if (sapi_module.input_filter(PARSE_SERVER, "PATH_TRANSLATED", &cli_script, len, &len)) { - php_register_variable_safe("PATH_TRANSLATED", cli_script, len, track_vars_array); - } - /* just make it available */ - len = 0U; - if (sapi_module.input_filter(PARSE_SERVER, "DOCUMENT_ROOT", &docroot, len, &len)) { - php_register_variable_safe("DOCUMENT_ROOT", docroot, len, track_vars_array); - } + /* Build the special-case PHP_SELF variable for the CLI version */ + len = strlen(cli_script); + if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &cli_script, len, + &len)) { + php_register_variable_safe("PHP_SELF", cli_script, len, track_vars_array); + } + if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_NAME", &cli_script, len, + &len)) { + php_register_variable_safe("SCRIPT_NAME", cli_script, len, + track_vars_array); + } + /* filenames are empty for stdin */ + if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_FILENAME", &cli_script, + len, &len)) { + php_register_variable_safe("SCRIPT_FILENAME", cli_script, len, + track_vars_array); + } + if (sapi_module.input_filter(PARSE_SERVER, "PATH_TRANSLATED", &cli_script, + len, &len)) { + php_register_variable_safe("PATH_TRANSLATED", cli_script, len, + track_vars_array); + } + /* just make it available */ + len = 0U; + if (sapi_module.input_filter(PARSE_SERVER, "DOCUMENT_ROOT", &docroot, len, + &len)) { + php_register_variable_safe("DOCUMENT_ROOT", docroot, len, track_vars_array); + } } /* }}} */ -static void * execute_script_cli(void *arg) { - void *exit_status; +static void *execute_script_cli(void *arg) { + void *exit_status; - // The SAPI name "cli" is hardcoded into too many programs... let's usurp it. - php_embed_module.name = "cli"; - php_embed_module.pretty_name = "PHP CLI embedded in FrankenPHP"; - php_embed_module.register_server_variables = sapi_cli_register_variables; + // The SAPI name "cli" is hardcoded into too many programs... let's usurp it. + php_embed_module.name = "cli"; + php_embed_module.pretty_name = "PHP CLI embedded in FrankenPHP"; + php_embed_module.register_server_variables = sapi_cli_register_variables; - php_embed_init(cli_argc, cli_argv); + php_embed_init(cli_argc, cli_argv); - cli_register_file_handles(false); - zend_first_try { - zend_file_handle file_handle; - zend_stream_init_filename(&file_handle, cli_script); + cli_register_file_handles(false); + zend_first_try { + zend_file_handle file_handle; + zend_stream_init_filename(&file_handle, cli_script); - php_execute_script(&file_handle); - } zend_end_try(); + php_execute_script(&file_handle); + } + zend_end_try(); - exit_status = (void *) (intptr_t) EG(exit_status); + exit_status = (void *)(intptr_t)EG(exit_status); - php_embed_shutdown(); + php_embed_shutdown(); - return exit_status; + return exit_status; } int frankenphp_execute_script_cli(char *script, int argc, char **argv) { - pthread_t thread; - int err; - void *exit_status; + pthread_t thread; + int err; + void *exit_status; - cli_script = script; - cli_argc = argc; - cli_argv = argv; + cli_script = script; + cli_argc = argc; + cli_argv = argv; - // Start the script in a dedicated thread to prevent conflicts between Go and PHP signal handlers - err = pthread_create(&thread, NULL, execute_script_cli, NULL); - if (err != 0) { - return err; - } + // Start the script in a dedicated thread to prevent conflicts between Go and + // PHP signal handlers + err = pthread_create(&thread, NULL, execute_script_cli, NULL); + if (err != 0) { + return err; + } - err = pthread_join(thread, &exit_status); - if (err != 0) { - return err; - } + err = pthread_join(thread, &exit_status); + if (err != 0) { + return err; + } - return (intptr_t) exit_status; + return (intptr_t)exit_status; } - diff --git a/frankenphp.h b/frankenphp.h index 3c723cdd..5bbb2dfe 100644 --- a/frankenphp.h +++ b/frankenphp.h @@ -1,9 +1,9 @@ #ifndef _FRANKENPPHP_H #define _FRANKENPPHP_H -#include -#include #include +#include +#include #ifndef FRANKENPHP_VERSION #define FRANKENPHP_VERSION dev @@ -12,43 +12,36 @@ #define TOSTRING(x) STRINGIFY(x) typedef struct frankenphp_version { - unsigned char major_version; - unsigned char minor_version; - unsigned char release_version; - const char *extra_version; - const char *version; - unsigned long version_id; + unsigned char major_version; + unsigned char minor_version; + unsigned char release_version; + const char *extra_version; + const char *version; + unsigned long version_id; } frankenphp_version; frankenphp_version frankenphp_get_version(); typedef struct frankenphp_config { - frankenphp_version version; - bool zts; - bool zend_signals; - bool zend_max_execution_timers; + frankenphp_version version; + bool zts; + bool zend_signals; + bool zend_max_execution_timers; } frankenphp_config; frankenphp_config frankenphp_get_config(); int frankenphp_init(int num_threads); int frankenphp_update_server_context( - bool create, - uintptr_t current_request, - uintptr_t main_request, + bool create, uintptr_t current_request, uintptr_t main_request, - const char *request_method, - char *query_string, - zend_long content_length, - char *path_translated, - char *request_uri, - const char *content_type, - char *auth_user, - char *auth_password, - int proto_num -); + const char *request_method, char *query_string, zend_long content_length, + char *path_translated, char *request_uri, const char *content_type, + char *auth_user, char *auth_password, int proto_num); int frankenphp_request_startup(); int frankenphp_execute_script(char *file_name); -void frankenphp_register_bulk_variables(char *known_variables[27], char **dynamic_variables, size_t size, zval *track_vars_array); +void frankenphp_register_bulk_variables(char *known_variables[27], + char **dynamic_variables, size_t size, + zval *track_vars_array); int frankenphp_execute_script_cli(char *script, int argc, char **argv); diff --git a/frankenphp_arginfo.h b/frankenphp_arginfo.h index a9fcc7ab..df1e7f40 100644 --- a/frankenphp_arginfo.h +++ b/frankenphp_arginfo.h @@ -1,29 +1,28 @@ /* This is a generated file, edit the .stub.php file instead. * Stub hash: de4dc4063fafd8c933e3068c8349889a7ece5f03 */ -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_frankenphp_handle_request, 0, 1, _IS_BOOL, 0) - ZEND_ARG_TYPE_INFO(0, callback, IS_CALLABLE, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_frankenphp_handle_request, 0, 1, + _IS_BOOL, 0) +ZEND_ARG_TYPE_INFO(0, callback, IS_CALLABLE, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_headers_send, 0, 0, IS_LONG, 0) - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, status, IS_LONG, 0, "200") +ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, status, IS_LONG, 0, "200") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_frankenphp_finish_request, 0, 0, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_frankenphp_finish_request, 0, 0, + _IS_BOOL, 0) ZEND_END_ARG_INFO() #define arginfo_fastcgi_finish_request arginfo_frankenphp_finish_request - ZEND_FUNCTION(frankenphp_handle_request); ZEND_FUNCTION(headers_send); ZEND_FUNCTION(frankenphp_finish_request); - static const zend_function_entry ext_functions[] = { - ZEND_FE(frankenphp_handle_request, arginfo_frankenphp_handle_request) - ZEND_FE(headers_send, arginfo_headers_send) - ZEND_FE(frankenphp_finish_request, arginfo_frankenphp_finish_request) - ZEND_FALIAS(fastcgi_finish_request, frankenphp_finish_request, arginfo_fastcgi_finish_request) - ZEND_FE_END -}; + ZEND_FE(frankenphp_handle_request, arginfo_frankenphp_handle_request) + ZEND_FE(headers_send, arginfo_headers_send) ZEND_FE( + frankenphp_finish_request, arginfo_frankenphp_finish_request) + ZEND_FALIAS(fastcgi_finish_request, frankenphp_finish_request, + arginfo_fastcgi_finish_request) ZEND_FE_END}; diff --git a/static-builder.Dockerfile b/static-builder.Dockerfile index b68aed9b..3c17d458 100644 --- a/static-builder.Dockerfile +++ b/static-builder.Dockerfile @@ -5,6 +5,7 @@ ARG FRANKENPHP_VERSION='' ARG PHP_VERSION='' ARG PHP_EXTENSIONS='' ARG PHP_EXTENSION_LIBS='' +SHELL ["/bin/ash", "-eo", "pipefail", "-c"] RUN apk update; \ apk add --no-cache \ @@ -56,15 +57,14 @@ ENV PATH="${PATH}:/root/.composer/vendor/bin" COPY --from=composer/composer:2-bin --link /composer /usr/bin/composer WORKDIR /go/src/app - COPY go.mod go.sum ./ RUN go mod graph | awk '{if ($1 !~ "@") print $2}' | xargs go get -RUN mkdir caddy && cd caddy -COPY caddy/go.mod caddy/go.sum ./caddy/ - -RUN cd caddy && go mod graph | awk '{if ($1 !~ "@") print $2}' | xargs go get +WORKDIR /go/src/app/caddy +COPY caddy/go.mod caddy/go.sum ./ +RUN go mod graph | awk '{if ($1 !~ "@") print $2}' | xargs go get +WORKDIR /go/src/app COPY *.* ./ COPY caddy caddy COPY C-Thread-Pool C-Thread-Pool