mirror of
https://github.com/dunglas/frankenphp.git
synced 2025-12-24 13:38:11 +08:00
Compare commits
130 Commits
v1.4.2
...
feat/frank
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79e3a98a11 | ||
|
|
afc4463ab3 | ||
|
|
6749ddbde5 | ||
|
|
82ba882a4e | ||
|
|
4b1679e70f | ||
|
|
75ce2e22c2 | ||
|
|
5a43e9f4de | ||
|
|
5542044376 | ||
|
|
52b65311c2 | ||
|
|
2dc8048ad2 | ||
|
|
a59b649dac | ||
|
|
68a4548bf4 | ||
|
|
6f049f9a9c | ||
|
|
340b1fd1c2 | ||
|
|
c9329bd717 | ||
|
|
f54a1fa85e | ||
|
|
b4115ca9a2 | ||
|
|
14469d4a0a | ||
|
|
ee394756b1 | ||
|
|
5a260c430a | ||
|
|
b6fcab5a95 | ||
|
|
1e49586b0e | ||
|
|
b27cd1c986 | ||
|
|
c6483088c5 | ||
|
|
5a9785d0d9 | ||
|
|
c522b52804 | ||
|
|
9a8ad979e0 | ||
|
|
663aff7cc4 | ||
|
|
79f2b2347b | ||
|
|
bf5c98410b | ||
|
|
cf7541fde6 | ||
|
|
25491068df | ||
|
|
d72751b9fd | ||
|
|
8820e53819 | ||
|
|
d2b6f9e723 | ||
|
|
13fbe126ea | ||
|
|
afa7dafe1c | ||
|
|
39e22bd5e0 | ||
|
|
bbbfdb31b5 | ||
|
|
0b83602575 | ||
|
|
ecca9dc01d | ||
|
|
eb40c03a21 | ||
|
|
c2390e7c3b | ||
|
|
0d12a5162d | ||
|
|
a48db9422d | ||
|
|
ab0fcd80de | ||
|
|
2f7b987198 | ||
|
|
1d74b2caa8 | ||
|
|
92e92335e3 | ||
|
|
8f5f9e4c8b | ||
|
|
5b7fc5ec52 | ||
|
|
05220de0e3 | ||
|
|
3741782330 | ||
|
|
a6e1d3554d | ||
|
|
6f1b4f3bae | ||
|
|
cd540bda11 | ||
|
|
8125993001 | ||
|
|
8583afd83e | ||
|
|
d10a243f86 | ||
|
|
1ec37f6cc9 | ||
|
|
4ad5e870ec | ||
|
|
49d2e62996 | ||
|
|
8febee71af | ||
|
|
16814581f9 | ||
|
|
ffa52f7c8d | ||
|
|
4550027de4 | ||
|
|
7f8e43fd62 | ||
|
|
254c0a8a55 | ||
|
|
22cf94d556 | ||
|
|
a4dc93f831 | ||
|
|
c276a3f434 | ||
|
|
02a1c92b88 | ||
|
|
8092f4a35c | ||
|
|
b250bd9a07 | ||
|
|
99064ee3e1 | ||
|
|
58a728b790 | ||
|
|
66aa975d47 | ||
|
|
5e1ad5d797 | ||
|
|
96dd739064 | ||
|
|
729cf9bba1 | ||
|
|
c5752f9e3b | ||
|
|
ba36f92a35 | ||
|
|
d3589f9770 | ||
|
|
8e6a183bda | ||
|
|
855b3f93b1 | ||
|
|
f85ca1c2d2 | ||
|
|
a30ed2e9d3 | ||
|
|
565b3a9629 | ||
|
|
3701516e5e | ||
|
|
f36bd51163 | ||
|
|
45bba2101f | ||
|
|
87315a19ae | ||
|
|
3bc426482a | ||
|
|
341b0240c9 | ||
|
|
432824edf1 | ||
|
|
9cca12858b | ||
|
|
cc473ee03e | ||
|
|
93266dfcad | ||
|
|
6203d207fa | ||
|
|
424ca426cb | ||
|
|
a9cf944b62 | ||
|
|
8d9ce15849 | ||
|
|
409c0fdf5f | ||
|
|
f50248a7d2 | ||
|
|
09b8219ad4 | ||
|
|
f2bae25a78 | ||
|
|
3dd90a3071 | ||
|
|
c57f741d83 | ||
|
|
3ba4e257a1 | ||
|
|
619c903386 | ||
|
|
78824107f0 | ||
|
|
f64c0f948e | ||
|
|
db3e1a047c | ||
|
|
80f13f07ea | ||
|
|
072151dfee | ||
|
|
965fa6570c | ||
|
|
251567a617 | ||
|
|
57e7747b9b | ||
|
|
f109f0403b | ||
|
|
d407dbd498 | ||
|
|
d970309544 | ||
|
|
30bf69cbe5 | ||
|
|
f61bc180c4 | ||
|
|
9f5e7a9eaa | ||
|
|
a5ca60da44 | ||
|
|
1c097a6fdf | ||
|
|
233753ca6b | ||
|
|
9dd05b0b1b | ||
|
|
4c92633396 | ||
|
|
be2e4714f5 |
@@ -1,14 +1,11 @@
|
||||
# ignored
|
||||
**/*
|
||||
|
||||
# authorized
|
||||
!**/Caddyfile
|
||||
!**/*.go
|
||||
!**/go.*
|
||||
!**/*.c
|
||||
!**/*.h
|
||||
!testdata/*.php
|
||||
!testdata/*.txt
|
||||
!build-static.sh
|
||||
!app.tar
|
||||
!app_checksum.txt
|
||||
/caddy/frankenphp/frankenphp
|
||||
/internal/testserver/testserver
|
||||
/internal/testcli/testcli
|
||||
/dist
|
||||
.DS_Store
|
||||
.idea/
|
||||
.vscode/
|
||||
__debug_bin
|
||||
frankenphp.dev.test
|
||||
caddy/frankenphp/Build
|
||||
*.log
|
||||
|
||||
17
.github/dependabot.yaml
vendored
17
.github/dependabot.yaml
vendored
@@ -7,20 +7,27 @@ updates:
|
||||
interval: weekly
|
||||
commit-message:
|
||||
prefix: chore
|
||||
groups:
|
||||
go-modules:
|
||||
patterns:
|
||||
- "*"
|
||||
- package-ecosystem: gomod
|
||||
directory: /caddy
|
||||
schedule:
|
||||
interval: weekly
|
||||
commit-message:
|
||||
prefix: chore(caddy)
|
||||
# These packages must be in sync with versions
|
||||
# used by github.com/caddyserver/caddy/v2
|
||||
ignore:
|
||||
- dependency-name: github.com/google/cel-go
|
||||
- dependency-name: github.com/quic-go/*
|
||||
groups:
|
||||
go-modules:
|
||||
patterns:
|
||||
- "*"
|
||||
- package-ecosystem: github-actions
|
||||
directory: /
|
||||
schedule:
|
||||
interval: weekly
|
||||
commit-message:
|
||||
prefix: ci
|
||||
groups:
|
||||
github-actions:
|
||||
patterns:
|
||||
- "*"
|
||||
|
||||
3
.github/workflows/docker.yaml
vendored
3
.github/workflows/docker.yaml
vendored
@@ -133,8 +133,8 @@ jobs:
|
||||
with:
|
||||
platforms: ${{ matrix.platform }}
|
||||
- name: Login to DockerHub
|
||||
if: fromJson(needs.prepare.outputs.push)
|
||||
uses: docker/login-action@v3
|
||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
|
||||
with:
|
||||
username: ${{ secrets.REGISTRY_USERNAME }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
@@ -223,6 +223,7 @@ jobs:
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
|
||||
with:
|
||||
username: ${{ secrets.REGISTRY_USERNAME }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
|
||||
4
.github/workflows/lint.yaml
vendored
4
.github/workflows/lint.yaml
vendored
@@ -21,10 +21,8 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Lint Code Base
|
||||
uses: super-linter/super-linter/slim@v7.2.1
|
||||
uses: super-linter/super-linter/slim@v7.4.0
|
||||
env:
|
||||
VALIDATE_ALL_CODEBASE: true
|
||||
DEFAULT_BRANCH: main
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
LINTER_RULES_PATH: /
|
||||
MARKDOWN_CONFIG_FILE: .markdown-lint.yaml
|
||||
|
||||
6
.github/workflows/sanitizers.yaml
vendored
6
.github/workflows/sanitizers.yaml
vendored
@@ -13,6 +13,8 @@ on:
|
||||
- "docs/**"
|
||||
permissions:
|
||||
contents: read
|
||||
env:
|
||||
GOTOOLCHAIN: local
|
||||
jobs:
|
||||
# Adapted from https://github.com/beberlei/hdrhistogram-php
|
||||
sanitizers:
|
||||
@@ -36,7 +38,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: "1.22"
|
||||
go-version: "1.24"
|
||||
cache-dependency-path: |
|
||||
go.sum
|
||||
caddy/go.sum
|
||||
@@ -99,4 +101,4 @@ jobs:
|
||||
- name: Compile tests
|
||||
run: go test ${{ matrix.sanitizer == 'msan' && '-tags=nowatcher' || '' }} -${{ matrix.sanitizer }} -v -x -c
|
||||
- name: Run tests
|
||||
run: ./frankenphp.test -test.v
|
||||
run: ./frankenphp.dev.test -test.v
|
||||
|
||||
182
.github/workflows/static.yaml
vendored
182
.github/workflows/static.yaml
vendored
@@ -29,6 +29,7 @@ permissions:
|
||||
attestations: write
|
||||
env:
|
||||
IMAGE_NAME: ${{ (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.version) || startsWith(github.ref, 'refs/tags/')) && 'dunglas/frankenphp' || 'dunglas/frankenphp-dev' }}
|
||||
GOTOOLCHAIN: local
|
||||
jobs:
|
||||
prepare:
|
||||
runs-on: ubuntu-24.04
|
||||
@@ -36,6 +37,7 @@ jobs:
|
||||
push: ${{ toJson((steps.check.outputs.ref || (github.event_name == 'workflow_dispatch' && inputs.version) || startsWith(github.ref, 'refs/tags/') || (github.ref == 'refs/heads/main' && github.event_name != 'pull_request')) && true || false) }}
|
||||
platforms: ${{ steps.matrix.outputs.platforms }}
|
||||
metadata: ${{ steps.matrix.outputs.metadata }}
|
||||
gnu_metadata: ${{ steps.matrix.outputs.gnu_metadata }}
|
||||
ref: ${{ steps.check.outputs.ref }}
|
||||
steps:
|
||||
- name: Get version
|
||||
@@ -58,15 +60,17 @@ jobs:
|
||||
- name: Create platforms matrix
|
||||
id: matrix
|
||||
run: |
|
||||
METADATA="$(docker buildx bake --print static-builder | jq -c)"
|
||||
METADATA="$(docker buildx bake --print static-builder-musl | jq -c)"
|
||||
GNU_METADATA="$(docker buildx bake --print static-builder-gnu | jq -c)"
|
||||
{
|
||||
echo metadata="${METADATA}"
|
||||
echo platforms="$(jq -c 'first(.target[]) | .platforms' <<< "${METADATA}")"
|
||||
echo gnu_metadata="${GNU_METADATA}"
|
||||
} >> "${GITHUB_OUTPUT}"
|
||||
env:
|
||||
SHA: ${{ github.sha }}
|
||||
VERSION: ${{ steps.check.outputs.ref || 'dev' }}
|
||||
build-linux:
|
||||
build-linux-musl:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -79,7 +83,7 @@ jobs:
|
||||
debug: true
|
||||
- platform: linux/amd64
|
||||
mimalloc: true
|
||||
name: Build ${{ matrix.platform }} static binary${{ matrix.debug && ' (debug)' || '' }}${{ matrix.mimalloc && ' (mimalloc)' || '' }}
|
||||
name: Build ${{ matrix.platform }} static musl binary${{ matrix.debug && ' (debug)' || '' }}${{ matrix.mimalloc && ' (mimalloc)' || '' }}
|
||||
runs-on: ${{ startsWith(matrix.platform, 'linux/arm') && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
|
||||
needs: [prepare]
|
||||
steps:
|
||||
@@ -96,8 +100,8 @@ jobs:
|
||||
with:
|
||||
platforms: ${{ matrix.platform }}
|
||||
- name: Login to DockerHub
|
||||
if: ${{ fromJson(needs.prepare.outputs.push) && !matrix.debug && !matrix.mimalloc }}
|
||||
uses: docker/login-action@v3
|
||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
|
||||
with:
|
||||
username: ${{ secrets.REGISTRY_USERNAME }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
@@ -107,16 +111,16 @@ jobs:
|
||||
with:
|
||||
pull: true
|
||||
load: ${{ !fromJson(needs.prepare.outputs.push) || matrix.debug || matrix.mimalloc }}
|
||||
targets: static-builder
|
||||
targets: static-builder-musl
|
||||
set: |
|
||||
${{ matrix.debug && 'static-builder.args.DEBUG_SYMBOLS=1' || '' }}
|
||||
${{ matrix.mimalloc && 'static-builder.args.MIMALLOC=1' || '' }}
|
||||
${{ (github.event_name == 'pull_request' || matrix.platform == 'linux/arm64') && 'static-builder.args.NO_COMPRESS=1' || '' }}
|
||||
${{ matrix.debug && 'static-builder-musl.args.DEBUG_SYMBOLS=1' || '' }}
|
||||
${{ matrix.mimalloc && 'static-builder-musl.args.MIMALLOC=1' || '' }}
|
||||
${{ (github.event_name == 'pull_request' || matrix.platform == 'linux/arm64') && 'static-builder-musl.args.NO_COMPRESS=1' || '' }}
|
||||
*.tags=
|
||||
*.platform=${{ matrix.platform }}
|
||||
*.cache-from=type=gha,scope=${{ needs.prepare.outputs.ref || github.ref }}-static-builder${{ matrix.debug && '-debug' || '' }}${{ matrix.mimalloc && '-mimalloc' || '' }}
|
||||
*.cache-from=type=gha,scope=refs/heads/main-static-builder${{ matrix.debug && '-debug' || '' }}${{ matrix.mimalloc && '-mimalloc' || '' }}
|
||||
*.cache-to=type=gha,scope=${{ needs.prepare.outputs.ref || github.ref }}-static-builder${{ matrix.debug && '-debug' || '' }}${{ matrix.mimalloc && '-mimalloc' || '' }},ignore-error=true
|
||||
*.cache-from=type=gha,scope=${{ needs.prepare.outputs.ref || github.ref }}-static-builder-musl${{ matrix.debug && '-debug' || '' }}${{ matrix.mimalloc && '-mimalloc' || '' }}
|
||||
*.cache-from=type=gha,scope=refs/heads/main-static-builder-musl${{ matrix.debug && '-debug' || '' }}${{ matrix.mimalloc && '-mimalloc' || '' }}
|
||||
*.cache-to=type=gha,scope=${{ needs.prepare.outputs.ref || github.ref }}-static-builder-musl${{ matrix.debug && '-debug' || '' }}${{ matrix.mimalloc && '-mimalloc' || '' }},ignore-error=true
|
||||
${{ (fromJson(needs.prepare.outputs.push) && !matrix.debug && !matrix.mimalloc) && format('*.output=type=image,name={0},push-by-digest=true,name-canonical=true,push=true', env.IMAGE_NAME) || '' }}
|
||||
env:
|
||||
SHA: ${{ github.sha }}
|
||||
@@ -129,7 +133,7 @@ jobs:
|
||||
mkdir -p /tmp/metadata
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
digest=$(jq -r '."static-builder"."containerimage.digest"' <<< ${METADATA})
|
||||
digest=$(jq -r '."static-builder-musl"."containerimage.digest"' <<< ${METADATA})
|
||||
touch "/tmp/metadata/${digest#sha256:}"
|
||||
env:
|
||||
METADATA: ${{ steps.build.outputs.metadata }}
|
||||
@@ -137,16 +141,16 @@ jobs:
|
||||
if: fromJson(needs.prepare.outputs.push) && !matrix.debug && !matrix.mimalloc
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: metadata-static-builder-${{ steps.prepare.outputs.sanitized_platform }}
|
||||
name: metadata-static-builder-musl-${{ steps.prepare.outputs.sanitized_platform }}
|
||||
path: /tmp/metadata/*
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
- name: Copy binary
|
||||
run: |
|
||||
# shellcheck disable=SC2034
|
||||
digest=$(jq -r '."static-builder"."${{ (fromJson(needs.prepare.outputs.push) && !matrix.debug && !matrix.mimalloc) && 'containerimage.digest' || 'containerimage.config.digest' }}"' <<< "${METADATA}")
|
||||
docker create --platform=${{ matrix.platform }} --name static-builder "${{ (fromJson(needs.prepare.outputs.push) && !matrix.debug && !matrix.mimalloc) && '${IMAGE_NAME}@${digest}' || '${digest}' }}"
|
||||
docker cp "static-builder:/go/src/app/dist/${BINARY}" "${BINARY}${{ matrix.debug && '-debug' || '' }}${{ matrix.mimalloc && '-mimalloc' || '' }}"
|
||||
digest=$(jq -r '."static-builder-musl"."${{ (fromJson(needs.prepare.outputs.push) && !matrix.debug && !matrix.mimalloc) && 'containerimage.digest' || 'containerimage.config.digest' }}"' <<< "${METADATA}")
|
||||
docker create --platform=${{ matrix.platform }} --name static-builder-musl "${{ (fromJson(needs.prepare.outputs.push) && !matrix.debug && !matrix.mimalloc) && '${IMAGE_NAME}@${digest}' || '${digest}' }}"
|
||||
docker cp "static-builder-musl:/go/src/app/dist/${BINARY}" "${BINARY}${{ matrix.debug && '-debug' || '' }}${{ matrix.mimalloc && '-mimalloc' || '' }}"
|
||||
env:
|
||||
METADATA: ${{ steps.build.outputs.metadata }}
|
||||
BINARY: frankenphp-linux-${{ matrix.platform == 'linux/amd64' && 'x86_64' || 'aarch64' }}
|
||||
@@ -168,32 +172,150 @@ jobs:
|
||||
- name: Run sanity checks
|
||||
run: |
|
||||
"${BINARY}" version
|
||||
"${BINARY}" build-info
|
||||
"${BINARY}" list-modules | grep frankenphp
|
||||
"${BINARY}" list-modules | grep http.encoders.br
|
||||
"${BINARY}" list-modules | grep http.handlers.mercure
|
||||
"${BINARY}" list-modules | grep http.handlers.mercure
|
||||
"${BINARY}" list-modules | grep http.handlers.vulcain
|
||||
"${BINARY}" php-cli -r "echo 'Sanity check passed';"
|
||||
env:
|
||||
BINARY: ./frankenphp-linux-${{ matrix.platform == 'linux/amd64' && 'x86_64' || 'aarch64' }}${{ matrix.debug && '-debug' || '' }}${{ matrix.mimalloc && '-mimalloc' || '' }}
|
||||
|
||||
build-linux-gnu:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: ${{ fromJson(needs.prepare.outputs.platforms) }}
|
||||
name: Build ${{ matrix.platform }} static GNU binary
|
||||
runs-on: ${{ startsWith(matrix.platform, 'linux/arm') && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
|
||||
needs: [prepare]
|
||||
steps:
|
||||
- name: Prepare
|
||||
id: prepare
|
||||
run: |
|
||||
platform=${{ matrix.platform }}
|
||||
echo "sanitized_platform=${platform//\//-}" >> "${GITHUB_OUTPUT}"
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ needs.prepare.outputs.ref }}
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
platforms: ${{ matrix.platform }}
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
|
||||
with:
|
||||
username: ${{ secrets.REGISTRY_USERNAME }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
- name: Build
|
||||
id: build
|
||||
uses: docker/bake-action@v6
|
||||
with:
|
||||
pull: true
|
||||
load: ${{ !fromJson(needs.prepare.outputs.push) }}
|
||||
targets: static-builder-gnu
|
||||
set: |
|
||||
${{ (github.event_name == 'pull_request' || matrix.platform == 'linux/arm64') && 'static-builder-gnu.args.NO_COMPRESS=1' || '' }}
|
||||
static-builder-gnu.args.BUILD_PACKAGES=1
|
||||
*.tags=
|
||||
*.platform=${{ matrix.platform }}
|
||||
*.cache-from=type=gha,scope=${{ needs.prepare.outputs.ref || github.ref }}-static-builder-gnu
|
||||
*.cache-from=type=gha,scope=refs/heads/main-static-builder-gnu
|
||||
*.cache-to=type=gha,scope=${{ needs.prepare.outputs.ref || github.ref }}-static-builder-gnu,ignore-error=true
|
||||
${{ fromJson(needs.prepare.outputs.push) && format('*.output=type=image,name={0},push-by-digest=true,name-canonical=true,push=true', env.IMAGE_NAME) || '' }}
|
||||
env:
|
||||
SHA: ${{ github.sha }}
|
||||
VERSION: ${{ (github.ref_type == 'tag' && github.ref_name) || needs.prepare.outputs.ref || 'dev' }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- # Workaround for https://github.com/actions/runner/pull/2477#issuecomment-1501003600
|
||||
name: Export metadata
|
||||
if: fromJson(needs.prepare.outputs.push)
|
||||
run: |
|
||||
mkdir -p /tmp/metadata-gnu
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
digest=$(jq -r '."static-builder-gnu"."containerimage.digest"' <<< ${METADATA})
|
||||
touch "/tmp/metadata-gnu/${digest#sha256:}"
|
||||
env:
|
||||
METADATA: ${{ steps.build.outputs.metadata }}
|
||||
- name: Upload metadata
|
||||
if: fromJson(needs.prepare.outputs.push)
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: metadata-static-builder-gnu-${{ steps.prepare.outputs.sanitized_platform }}
|
||||
path: /tmp/metadata-gnu/*
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
- name: Copy all frankenphp* files
|
||||
run: |
|
||||
# shellcheck disable=SC2034
|
||||
digest=$(jq -r '."static-builder-gnu"."${{ fromJson(needs.prepare.outputs.push) && 'containerimage.digest' || 'containerimage.config.digest' }}"' <<< "${METADATA}")
|
||||
container_id=$(docker create --platform=${{ matrix.platform }} "${{ fromJson(needs.prepare.outputs.push) && '${IMAGE_NAME}@${digest}' || '${digest}' }}")
|
||||
mkdir -p gh-output
|
||||
cd gh-output
|
||||
for file in $(docker run --rm "${{ fromJson(needs.prepare.outputs.push) && '${IMAGE_NAME}@${digest}' || '${digest}' }}" sh -c "ls /go/src/app/dist | grep '^frankenphp'"); do
|
||||
docker cp "${container_id}:/go/src/app/dist/${file}" "./${file}"
|
||||
done
|
||||
docker rm "${container_id}"
|
||||
mv "${BINARY}" "${BINARY}-gnu"
|
||||
env:
|
||||
METADATA: ${{ steps.build.outputs.metadata }}
|
||||
BINARY: frankenphp-linux-${{ matrix.platform == 'linux/amd64' && 'x86_64' || 'aarch64' }}
|
||||
- name: Upload artifact
|
||||
if: ${{ !fromJson(needs.prepare.outputs.push) }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: frankenphp-linux-${{ matrix.platform == 'linux/amd64' && 'x86_64' || 'aarch64' }}-gnu-files
|
||||
path: gh-output/*
|
||||
- name: Upload assets
|
||||
if: fromJson(needs.prepare.outputs.push) && (needs.prepare.outputs.ref || github.ref_type == 'tag')
|
||||
run: gh release upload "${{ (github.ref_type == 'tag' && github.ref_name) || needs.prepare.outputs.ref }}" gh-output/* --repo dunglas/frankenphp --clobber
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- if: fromJson(needs.prepare.outputs.push) && (needs.prepare.outputs.ref || github.ref_type == 'tag')
|
||||
uses: actions/attest-build-provenance@v2
|
||||
with:
|
||||
subject-path: ${{ github.workspace }}/gh-output/frankenphp-linux-*-gnu
|
||||
- name: Run sanity checks
|
||||
run: |
|
||||
"${BINARY}" version
|
||||
"${BINARY}" list-modules | grep frankenphp
|
||||
"${BINARY}" list-modules | grep http.encoders.br
|
||||
"${BINARY}" list-modules | grep http.handlers.mercure
|
||||
"${BINARY}" list-modules | grep http.handlers.mercure
|
||||
"${BINARY}" list-modules | grep http.handlers.vulcain
|
||||
"${BINARY}" php-cli -r "echo 'Sanity check passed';"
|
||||
env:
|
||||
BINARY: ./gh-output/frankenphp-linux-${{ matrix.platform == 'linux/amd64' && 'x86_64' || 'aarch64' }}-gnu
|
||||
|
||||
# Adapted from https://docs.docker.com/build/ci/github-actions/multi-platform/
|
||||
push:
|
||||
runs-on: ubuntu-24.04
|
||||
needs:
|
||||
- prepare
|
||||
- build-linux
|
||||
- build-linux-musl
|
||||
- build-linux-gnu
|
||||
if: fromJson(needs.prepare.outputs.push)
|
||||
steps:
|
||||
- name: Download metadata
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: metadata-static-builder-*
|
||||
pattern: metadata-static-builder-musl-*
|
||||
path: /tmp/metadata
|
||||
merge-multiple: true
|
||||
- name: Download GNU metadata
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: metadata-static-builder-gnu-*
|
||||
path: /tmp/metadata-gnu
|
||||
merge-multiple: true
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
|
||||
with:
|
||||
username: ${{ secrets.REGISTRY_USERNAME }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
@@ -201,16 +323,30 @@ jobs:
|
||||
working-directory: /tmp/metadata
|
||||
run: |
|
||||
# shellcheck disable=SC2046,SC2086
|
||||
docker buildx imagetools create $(jq -cr '.target."static-builder".tags | map("-t " + .) | join(" ")' <<< "${METADATA}") \
|
||||
docker buildx imagetools create $(jq -cr '.target."static-builder-musl".tags | map("-t " + .) | join(" ")' <<< "${METADATA}") \
|
||||
$(printf "${IMAGE_NAME}@sha256:%s " *)
|
||||
env:
|
||||
METADATA: ${{ needs.prepare.outputs.metadata }}
|
||||
- name: Create GNU manifest list and push
|
||||
working-directory: /tmp/metadata-gnu
|
||||
run: |
|
||||
# shellcheck disable=SC2046,SC2086
|
||||
docker buildx imagetools create $(jq -cr '.target."static-builder-gnu".tags | map("-t " + .) | join(" ")' <<< "${GNU_METADATA}") \
|
||||
$(printf "${IMAGE_NAME}@sha256:%s " *)
|
||||
env:
|
||||
GNU_METADATA: ${{ needs.prepare.outputs.gnu_metadata }}
|
||||
- name: Inspect image
|
||||
run: |
|
||||
# shellcheck disable=SC2046,SC2086
|
||||
docker buildx imagetools inspect "$(jq -cr '.target."static-builder".tags | first' <<< "${METADATA}")"
|
||||
docker buildx imagetools inspect "$(jq -cr '.target."static-builder-musl".tags | first' <<< "${METADATA}")"
|
||||
env:
|
||||
METADATA: ${{ needs.prepare.outputs.metadata }}
|
||||
- name: Inspect GNU image
|
||||
run: |
|
||||
# shellcheck disable=SC2046,SC2086
|
||||
docker buildx imagetools inspect "$(jq -cr '.target."static-builder-gnu".tags | first' <<< "${GNU_METADATA}")-gnu"
|
||||
env:
|
||||
GNU_METADATA: ${{ needs.prepare.outputs.gnu_metadata }}
|
||||
|
||||
build-mac:
|
||||
strategy:
|
||||
@@ -228,9 +364,9 @@ jobs:
|
||||
ref: ${{ needs.prepare.outputs.ref }}
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: "1.22"
|
||||
go-version: "1.24"
|
||||
cache-dependency-path: |
|
||||
go.sum
|
||||
go.sum
|
||||
caddy/go.sum
|
||||
- name: Set FRANKENPHP_VERSION
|
||||
run: |
|
||||
@@ -262,10 +398,12 @@ jobs:
|
||||
- name: Run sanity checks
|
||||
run: |
|
||||
"${BINARY}" version
|
||||
"${BINARY}" build-info
|
||||
"${BINARY}" list-modules | grep frankenphp
|
||||
"${BINARY}" list-modules | grep http.encoders.br
|
||||
"${BINARY}" list-modules | grep http.handlers.mercure
|
||||
"${BINARY}" list-modules | grep http.handlers.mercure
|
||||
"${BINARY}" list-modules | grep http.handlers.vulcain
|
||||
"${BINARY}" php-cli -r "echo 'Sanity check passed';"
|
||||
env:
|
||||
BINARY: dist/frankenphp-mac-${{ matrix.platform }}
|
||||
|
||||
48
.github/workflows/tests.yaml
vendored
48
.github/workflows/tests.yaml
vendored
@@ -13,22 +13,25 @@ on:
|
||||
- "docs/**"
|
||||
permissions:
|
||||
contents: read
|
||||
env:
|
||||
GOTOOLCHAIN: local
|
||||
GOEXPERIMENT: cgocheck2
|
||||
jobs:
|
||||
tests:
|
||||
tests-linux:
|
||||
name: Tests (Linux, PHP ${{ matrix.php-versions }})
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-versions: ["8.2", "8.3", "8.4"]
|
||||
env:
|
||||
GOEXPERIMENT: cgocheck2
|
||||
GOMAXPROCS: 10
|
||||
LIBRARY_PATH: ${{ github.workspace }}/watcher/target/lib
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: "1.22"
|
||||
go-version: "1.24"
|
||||
cache-dependency-path: |
|
||||
go.sum
|
||||
caddy/go.sum
|
||||
@@ -43,7 +46,7 @@ jobs:
|
||||
debug: true
|
||||
- name: Install e-dant/watcher
|
||||
uses: ./.github/actions/watcher
|
||||
- name: Set Set CGO flags
|
||||
- name: Set CGO flags
|
||||
run: echo "CGO_CFLAGS=-I${PWD}/watcher/target/include $(php-config --includes)" >> "${GITHUB_ENV}"
|
||||
- name: Build
|
||||
run: go build
|
||||
@@ -67,7 +70,42 @@ jobs:
|
||||
- name: Run integrations tests
|
||||
run: ./reload_test.sh
|
||||
- name: Lint Go code
|
||||
uses: golangci/golangci-lint-action@v6
|
||||
uses: golangci/golangci-lint-action@v8
|
||||
if: matrix.php-versions == '8.4'
|
||||
with:
|
||||
version: latest
|
||||
tests-mac:
|
||||
name: Tests (macOS, PHP 8.4)
|
||||
runs-on: macos-latest
|
||||
env:
|
||||
HOMEBREW_NO_AUTO_UPDATE: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: "1.24"
|
||||
cache-dependency-path: |
|
||||
go.sum
|
||||
caddy/go.sum
|
||||
- uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: 8.4
|
||||
ini-file: development
|
||||
coverage: none
|
||||
tools: none
|
||||
env:
|
||||
phpts: ts
|
||||
debug: true
|
||||
- name: Set Set CGO flags
|
||||
run: |
|
||||
{
|
||||
echo "CGO_CFLAGS=-I/opt/homebrew/include/ $(php-config --includes)"
|
||||
echo "CGO_LDFLAGS=-L/opt/homebrew/lib/ $(php-config --ldflags) $(php-config --libs)"
|
||||
} >> "${GITHUB_ENV}"
|
||||
- name: Build
|
||||
run: go build -tags nowatcher
|
||||
- name: Run library tests
|
||||
run: go test -tags nowatcher -race -v ./...
|
||||
- name: Run Caddy module tests
|
||||
working-directory: caddy/
|
||||
run: go test -tags nowatcher,nobadger,nomysql,nopgx -race -v ./...
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -2,7 +2,11 @@
|
||||
/internal/testserver/testserver
|
||||
/internal/testcli/testcli
|
||||
/dist
|
||||
.DS_Store
|
||||
.idea/
|
||||
.vscode/
|
||||
__debug_bin
|
||||
frankenphp.test
|
||||
frankenphp.dev.test
|
||||
caddy/frankenphp/Build
|
||||
package/etc/php.ini
|
||||
*.log
|
||||
|
||||
7
.golangci.yaml
Normal file
7
.golangci.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
version: "2"
|
||||
run:
|
||||
build-tags:
|
||||
- nobadger
|
||||
- nomysql
|
||||
- nopgx
|
||||
110
CONTRIBUTING.md
110
CONTRIBUTING.md
@@ -11,9 +11,13 @@ docker build -t frankenphp-dev -f dev.Dockerfile .
|
||||
docker run --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -p 8080:8080 -p 443:443 -p 443:443/udp -v $PWD:/go/src/app -it frankenphp-dev
|
||||
```
|
||||
|
||||
The image contains the usual development tools (Go, GDB, Valgrind, Neovim...).
|
||||
The image contains the usual development tools (Go, GDB, Valgrind, Neovim...) and uses the following php setting locations
|
||||
|
||||
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`.
|
||||
- php.ini: `/etc/frankenphp/php.ini` A php.ini file with development presets is provided by default.
|
||||
- additional configuration files: `/etc/frankenphp/php.d/*.ini`
|
||||
- php extensions: `/usr/lib/frankenphp/modules/`
|
||||
|
||||
If your docker version is lower than 23.0, the build will fail due to dockerignore [pattern issue](https://github.com/moby/moby/pull/42676). Add directories to `.dockerignore`.
|
||||
|
||||
```patch
|
||||
!testdata/*.php
|
||||
@@ -49,10 +53,13 @@ cd testdata/
|
||||
../caddy/frankenphp/frankenphp run
|
||||
```
|
||||
|
||||
The server is listening on `127.0.0.1:8080`:
|
||||
The server is listening on `127.0.0.1:80`:
|
||||
|
||||
> [!NOTE]
|
||||
> if you are using Docker, you will have to either bind container port 80 or execute from inside the container
|
||||
|
||||
```console
|
||||
curl -vk https://localhost/phpinfo.php
|
||||
curl -vk http://127.0.0.1/phpinfo.php
|
||||
```
|
||||
|
||||
## Minimal test server
|
||||
@@ -108,22 +115,22 @@ docker buildx bake -f docker-bake.hcl --pull --no-cache --push
|
||||
|
||||
1. Download the debug version of the FrankenPHP binary from GitHub or create your custom static build including debug symbols:
|
||||
|
||||
```console
|
||||
docker buildx bake \
|
||||
--load \
|
||||
--set static-builder.args.DEBUG_SYMBOLS=1 \
|
||||
--set "static-builder.platform=linux/amd64" \
|
||||
static-builder
|
||||
docker cp $(docker create --name static-builder dunglas/frankenphp:static-builder):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp
|
||||
```
|
||||
```console
|
||||
docker buildx bake \
|
||||
--load \
|
||||
--set static-builder.args.DEBUG_SYMBOLS=1 \
|
||||
--set "static-builder.platform=linux/amd64" \
|
||||
static-builder
|
||||
docker cp $(docker create --name static-builder-musl dunglas/frankenphp:static-builder-musl):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp
|
||||
```
|
||||
|
||||
2. Replace your current version of `frankenphp` by the debug FrankenPHP executable
|
||||
3. Start FrankenPHP as usual (alternatively, you can directly start FrankenPHP with GDB: `gdb --args frankenphp run`)
|
||||
4. Attach to the process with GDB:
|
||||
|
||||
```console
|
||||
gdb -p `pidof frankenphp`
|
||||
```
|
||||
```console
|
||||
gdb -p `pidof frankenphp`
|
||||
```
|
||||
|
||||
5. If necessary, type `continue` in the GDB shell
|
||||
6. Make FrankenPHP crash
|
||||
@@ -135,63 +142,60 @@ 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
|
||||
# ...
|
||||
env:
|
||||
phpts: ts
|
||||
+ debug: true
|
||||
```
|
||||
```patch
|
||||
- uses: shivammathur/setup-php@v2
|
||||
# ...
|
||||
env:
|
||||
phpts: ts
|
||||
+ debug: true
|
||||
```
|
||||
|
||||
3. Enable `tmate` to connect to the container
|
||||
|
||||
```patch
|
||||
-
|
||||
name: Set CGO flags
|
||||
run: echo "CGO_CFLAGS=$(php-config --includes)" >> "$GITHUB_ENV"
|
||||
+ -
|
||||
+ run: |
|
||||
+ sudo apt install gdb
|
||||
+ mkdir -p /home/runner/.config/gdb/
|
||||
+ printf "set auto-load safe-path /\nhandle SIG34 nostop noprint pass" > /home/runner/.config/gdb/gdbinit
|
||||
+ -
|
||||
+ uses: mxschmitt/action-tmate@v3
|
||||
```
|
||||
```patch
|
||||
- name: Set CGO flags
|
||||
run: echo "CGO_CFLAGS=$(php-config --includes)" >> "$GITHUB_ENV"
|
||||
+ - run: |
|
||||
+ sudo apt install gdb
|
||||
+ mkdir -p /home/runner/.config/gdb/
|
||||
+ printf "set auto-load safe-path /\nhandle SIG34 nostop noprint pass" > /home/runner/.config/gdb/gdbinit
|
||||
+ - 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"
|
||||
```
|
||||
```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:
|
||||
|
||||
```console
|
||||
go test -tags watcher -c -ldflags=-w
|
||||
gdb --args frankenphp.test -test.run ^MyTest$
|
||||
```
|
||||
```console
|
||||
go test -tags watcher -c -ldflags=-w
|
||||
gdb --args frankenphp.dev.test -test.run ^MyTest$
|
||||
```
|
||||
|
||||
9. When the bug is fixed, revert all these changes
|
||||
|
||||
## 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)
|
||||
* [SDL bindings](https://pkg.go.dev/github.com/veandco/go-sdl2@v0.4.21/sdl#Main)
|
||||
- [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)
|
||||
- [SDL bindings](https://pkg.go.dev/github.com/veandco/go-sdl2@v0.4.21/sdl#Main)
|
||||
|
||||
## Docker-Related Resources
|
||||
|
||||
* [Bake file definition](https://docs.docker.com/build/customize/bake/file-definition/)
|
||||
* [docker buildx build](https://docs.docker.com/engine/reference/commandline/buildx_build/)
|
||||
- [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
|
||||
|
||||
@@ -210,6 +214,6 @@ follow these steps:
|
||||
3. Copy the `README.md` and `CONTRIBUTING.md` files from the root directory to the new directory
|
||||
4. Translate the content of the files, but don't change the filenames, also don't translate strings starting with `> [!` (it's special markup for GitHub)
|
||||
5. Create a Pull Request with the translations
|
||||
6. In the [site repository](https://github.com/dunglas/frankenphp-website/tree/main), copy and translate the translation files in the `content/`, `data/` and `i18n/` directories
|
||||
6. In the [site repository](https://github.com/dunglas/frankenphp-website), copy and translate the translation files in the `content/`, `data/` and `i18n/` directories
|
||||
7. Translate the values in the created YAML file
|
||||
8. Open a Pull Request on the site repository
|
||||
|
||||
49
Dockerfile
49
Dockerfile
@@ -19,17 +19,19 @@ RUN set -eux; \
|
||||
/app/public \
|
||||
/config/caddy \
|
||||
/data/caddy \
|
||||
/etc/caddy; \
|
||||
/etc/caddy \
|
||||
/etc/frankenphp; \
|
||||
sed -i 's/php/frankenphp run/g' /usr/local/bin/docker-php-entrypoint; \
|
||||
echo '<?php phpinfo();' > /app/public/index.php
|
||||
|
||||
COPY --link caddy/frankenphp/Caddyfile /etc/caddy/Caddyfile
|
||||
RUN curl -sSLf \
|
||||
RUN ln /etc/caddy/Caddyfile /etc/frankenphp/Caddyfile && \
|
||||
curl -sSLf \
|
||||
-o /usr/local/bin/install-php-extensions \
|
||||
https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions && \
|
||||
chmod +x /usr/local/bin/install-php-extensions
|
||||
|
||||
CMD ["--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"]
|
||||
CMD ["--config", "/etc/frankenphp/Caddyfile", "--adapter", "caddyfile"]
|
||||
HEALTHCHECK CMD curl -f http://localhost:2019/metrics || exit 1
|
||||
|
||||
# See https://caddyserver.com/docs/conventions#file-locations for details
|
||||
@@ -57,11 +59,13 @@ SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
COPY --from=golang-base /usr/local/go /usr/local/go
|
||||
|
||||
ENV PATH=/usr/local/go/bin:$PATH
|
||||
ENV GOTOOLCHAIN=local
|
||||
|
||||
# This is required to link the FrankenPHP binary to the PHP binary
|
||||
RUN apt-get update && \
|
||||
apt-get -y --no-install-recommends install \
|
||||
cmake \
|
||||
cmake \
|
||||
git \
|
||||
libargon2-dev \
|
||||
libbrotli-dev \
|
||||
libcurl4-openssl-dev \
|
||||
@@ -75,21 +79,6 @@ RUN apt-get update && \
|
||||
&& \
|
||||
apt-get clean
|
||||
|
||||
WORKDIR /go/src/app
|
||||
|
||||
COPY --link go.mod go.sum ./
|
||||
RUN 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 internal internal
|
||||
COPY --link testdata testdata
|
||||
|
||||
# Install e-dant/watcher (necessary for file watching)
|
||||
WORKDIR /usr/local/src/watcher
|
||||
RUN curl -s https://api.github.com/repos/e-dant/watcher/releases/latest | \
|
||||
@@ -104,6 +93,18 @@ RUN curl -s https://api.github.com/repos/e-dant/watcher/releases/latest | \
|
||||
cmake --install build && \
|
||||
ldconfig
|
||||
|
||||
WORKDIR /go/src/app
|
||||
|
||||
COPY --link go.mod go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
WORKDIR /go/src/app/caddy
|
||||
COPY --link caddy/go.mod caddy/go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
WORKDIR /go/src/app
|
||||
COPY --link . ./
|
||||
|
||||
# See https://github.com/docker-library/php/blob/master/8.3/bookworm/zts/Dockerfile#L57-L59 for PHP values
|
||||
ENV CGO_CFLAGS="-DFRANKENPHP_VERSION=$FRANKENPHP_VERSION $PHP_CFLAGS"
|
||||
ENV CGO_CPPFLAGS=$PHP_CPPFLAGS
|
||||
@@ -112,10 +113,11 @@ ENV CGO_LDFLAGS="-L/usr/local/lib -lssl -lcrypto -lreadline -largon2 -lcurl -lon
|
||||
RUN echo $CGO_LDFLAGS
|
||||
|
||||
WORKDIR /go/src/app/caddy/frankenphp
|
||||
RUN GOBIN=/usr/local/bin go install -tags 'nobadger,nomysql,nopgx' -ldflags "-w -s -X 'github.com/caddyserver/caddy/v2.CustomVersion=FrankenPHP $FRANKENPHP_VERSION PHP $PHP_VERSION Caddy'" && \
|
||||
RUN GOBIN=/usr/local/bin go install -tags 'nobadger,nomysql,nopgx' -ldflags "-w -s -X 'github.com/caddyserver/caddy/v2.CustomVersion=FrankenPHP $FRANKENPHP_VERSION PHP $PHP_VERSION Caddy'" -buildvcs=true && \
|
||||
setcap cap_net_bind_service=+ep /usr/local/bin/frankenphp && \
|
||||
cp Caddyfile /etc/caddy/Caddyfile && \
|
||||
frankenphp version
|
||||
cp Caddyfile /etc/frankenphp/Caddyfile && \
|
||||
frankenphp version && \
|
||||
frankenphp build-info
|
||||
|
||||
WORKDIR /go/src/app
|
||||
|
||||
@@ -133,4 +135,5 @@ RUN apt-get install -y --no-install-recommends libstdc++6 && \
|
||||
|
||||
COPY --from=builder /usr/local/bin/frankenphp /usr/local/bin/frankenphp
|
||||
RUN setcap cap_net_bind_service=+ep /usr/local/bin/frankenphp && \
|
||||
frankenphp version
|
||||
frankenphp version && \
|
||||
frankenphp build-info
|
||||
|
||||
106
README.md
106
README.md
@@ -4,36 +4,21 @@
|
||||
|
||||
FrankenPHP is a modern application server for PHP built on top of the [Caddy](https://caddyserver.com/) web server.
|
||||
|
||||
FrankenPHP gives superpowers to your PHP apps thanks to its stunning features: [*Early Hints*](https://frankenphp.dev/docs/early-hints/), [worker mode](https://frankenphp.dev/docs/worker/), [real-time capabilities](https://frankenphp.dev/docs/mercure/), automatic HTTPS, HTTP/2, and HTTP/3 support...
|
||||
FrankenPHP gives superpowers to your PHP apps thanks to its stunning features: [_Early Hints_](https://frankenphp.dev/docs/early-hints/), [worker mode](https://frankenphp.dev/docs/worker/), [real-time capabilities](https://frankenphp.dev/docs/mercure/), 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*](https://frankenphp.dev) and in this slide deck:
|
||||
[**Learn more** on _frankenphp.dev_](https://frankenphp.dev) and in this slide deck:
|
||||
|
||||
<a href="https://dunglas.dev/2022/10/frankenphp-the-modern-php-app-server-written-in-go/"><img src="https://dunglas.dev/wp-content/uploads/2022/10/frankenphp.png" alt="Slides" width="600"></a>
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Docker
|
||||
|
||||
```console
|
||||
docker run -v .:/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](docs/config.md#environment-variables) to change the domain to use.
|
||||
|
||||
### Standalone Binary
|
||||
|
||||
If you prefer not to use Docker, we provide standalone FrankenPHP binaries for Linux and macOS
|
||||
We provide static FrankenPHP binaries for Linux and macOS
|
||||
containing [PHP 8.4](https://www.php.net/releases/8.4/en.php) and most popular PHP extensions.
|
||||
|
||||
On Windows, use [WSL](https://learn.microsoft.com/windows/wsl/) to run FrankenPHP.
|
||||
@@ -58,33 +43,68 @@ You can also run command-line scripts with:
|
||||
frankenphp php-cli /path/to/your/script.php
|
||||
```
|
||||
|
||||
### Docker
|
||||
|
||||
Alternatively, [Docker images](https://frankenphp.dev/docs/docker/) are available:
|
||||
|
||||
```console
|
||||
docker run -v .:/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](docs/config.md#environment-variables) to change the domain to use.
|
||||
|
||||
### Homebrew
|
||||
|
||||
FrankenPHP is also available as a [Homebrew](https://brew.sh) package for macOS and Linux.
|
||||
|
||||
To install it:
|
||||
|
||||
```console
|
||||
brew install dunglas/frankenphp/frankenphp
|
||||
```
|
||||
|
||||
To serve the content of the current directory, run:
|
||||
|
||||
```console
|
||||
frankenphp php-server
|
||||
```
|
||||
|
||||
## Docs
|
||||
|
||||
* [Classic mode](https://frankenphp.dev/docs/classic/)
|
||||
* [Worker mode](https://frankenphp.dev/docs/worker/)
|
||||
* [Early Hints support (103 HTTP status code)](https://frankenphp.dev/docs/early-hints/)
|
||||
* [Real-time](https://frankenphp.dev/docs/mercure/)
|
||||
* [Configuration](https://frankenphp.dev/docs/config/)
|
||||
* [Docker images](https://frankenphp.dev/docs/docker/)
|
||||
* [Deploy in production](https://frankenphp.dev/docs/production/)
|
||||
* [Performance optimization](https://frankenphp.dev/docs/performance/)
|
||||
* [Create **standalone**, self-executable PHP apps](https://frankenphp.dev/docs/embed/)
|
||||
* [Create static binaries](https://frankenphp.dev/docs/static/)
|
||||
* [Compile from sources](https://frankenphp.dev/docs/compile/)
|
||||
* [Laravel integration](https://frankenphp.dev/docs/laravel/)
|
||||
* [Known issues](https://frankenphp.dev/docs/known-issues/)
|
||||
* [Demo app (Symfony) and benchmarks](https://github.com/dunglas/frankenphp-demo)
|
||||
* [Go library documentation](https://pkg.go.dev/github.com/dunglas/frankenphp)
|
||||
* [Contributing and debugging](https://frankenphp.dev/docs/contributing/)
|
||||
- [Classic mode](https://frankenphp.dev/docs/classic/)
|
||||
- [Worker mode](https://frankenphp.dev/docs/worker/)
|
||||
- [Early Hints support (103 HTTP status code)](https://frankenphp.dev/docs/early-hints/)
|
||||
- [Real-time](https://frankenphp.dev/docs/mercure/)
|
||||
- [Efficiently Serving Large Static Files](https://frankenphp.dev/docs/x-sendfile/)
|
||||
- [Configuration](https://frankenphp.dev/docs/config/)
|
||||
- [Docker images](https://frankenphp.dev/docs/docker/)
|
||||
- [Deploy in production](https://frankenphp.dev/docs/production/)
|
||||
- [Performance optimization](https://frankenphp.dev/docs/performance/)
|
||||
- [Create **standalone**, self-executable PHP apps](https://frankenphp.dev/docs/embed/)
|
||||
- [Create static binaries](https://frankenphp.dev/docs/static/)
|
||||
- [Compile from sources](https://frankenphp.dev/docs/compile/)
|
||||
- [Monitoring FrankenPHP](https://frankenphp.dev/docs/metrics/)
|
||||
- [Laravel integration](https://frankenphp.dev/docs/laravel/)
|
||||
- [Known issues](https://frankenphp.dev/docs/known-issues/)
|
||||
- [Demo app (Symfony) and benchmarks](https://github.com/dunglas/frankenphp-demo)
|
||||
- [Go library documentation](https://pkg.go.dev/frankenphp.dev)
|
||||
- [Contributing and debugging](https://frankenphp.dev/docs/contributing/)
|
||||
|
||||
## Examples and Skeletons
|
||||
|
||||
* [Symfony](https://github.com/dunglas/symfony-docker)
|
||||
* [API Platform](https://api-platform.com/docs/symfony)
|
||||
* [Laravel](https://frankenphp.dev/docs/laravel/)
|
||||
* [Sulu](https://sulu.io/blog/running-sulu-with-frankenphp)
|
||||
* [WordPress](https://github.com/StephenMiracle/frankenwp)
|
||||
* [Drupal](https://github.com/dunglas/frankenphp-drupal)
|
||||
* [Joomla](https://github.com/alexandreelise/frankenphp-joomla)
|
||||
* [TYPO3](https://github.com/ochorocho/franken-typo3)
|
||||
* [Magento2](https://github.com/ekino/frankenphp-magento2)
|
||||
- [Symfony](https://github.com/dunglas/symfony-docker)
|
||||
- [API Platform](https://api-platform.com/docs/symfony)
|
||||
- [Laravel](https://frankenphp.dev/docs/laravel/)
|
||||
- [Sulu](https://sulu.io/blog/running-sulu-with-frankenphp)
|
||||
- [WordPress](https://github.com/StephenMiracle/frankenwp)
|
||||
- [Drupal](https://github.com/dunglas/frankenphp-drupal)
|
||||
- [Joomla](https://github.com/alexandreelise/frankenphp-joomla)
|
||||
- [TYPO3](https://github.com/ochorocho/franken-typo3)
|
||||
- [Magento2](https://github.com/ekino/frankenphp-magento2)
|
||||
|
||||
@@ -18,17 +18,20 @@ RUN set -eux; \
|
||||
/app/public \
|
||||
/config/caddy \
|
||||
/data/caddy \
|
||||
/etc/caddy; \
|
||||
/etc/caddy \
|
||||
/etc/frankenphp; \
|
||||
sed -i 's/php/frankenphp run/g' /usr/local/bin/docker-php-entrypoint; \
|
||||
echo '<?php phpinfo();' > /app/public/index.php
|
||||
|
||||
COPY --link caddy/frankenphp/Caddyfile /etc/caddy/Caddyfile
|
||||
RUN curl -sSLf \
|
||||
|
||||
RUN ln /etc/caddy/Caddyfile /etc/frankenphp/Caddyfile && \
|
||||
curl -sSLf \
|
||||
-o /usr/local/bin/install-php-extensions \
|
||||
https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions && \
|
||||
chmod +x /usr/local/bin/install-php-extensions
|
||||
|
||||
CMD ["--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"]
|
||||
CMD ["--config", "/etc/frankenphp/Caddyfile", "--adapter", "caddyfile"]
|
||||
HEALTHCHECK CMD curl -f http://localhost:2019/metrics || exit 1
|
||||
|
||||
# See https://caddyserver.com/docs/conventions#file-locations for details
|
||||
@@ -57,6 +60,7 @@ SHELL ["/bin/ash", "-eo", "pipefail", "-c"]
|
||||
COPY --link --from=golang-base /usr/local/go /usr/local/go
|
||||
|
||||
ENV PATH=/usr/local/go/bin:$PATH
|
||||
ENV GOTOOLCHAIN=local
|
||||
|
||||
# hadolint ignore=SC2086
|
||||
RUN apk add --no-cache --virtual .build-deps \
|
||||
@@ -82,21 +86,6 @@ RUN apk add --no-cache --virtual .build-deps \
|
||||
sqlite-dev \
|
||||
upx
|
||||
|
||||
WORKDIR /go/src/app
|
||||
|
||||
COPY --link go.mod go.sum ./
|
||||
RUN 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 internal internal
|
||||
COPY --link testdata testdata
|
||||
|
||||
# Install e-dant/watcher (necessary for file watching)
|
||||
WORKDIR /usr/local/src/watcher
|
||||
RUN curl -s https://api.github.com/repos/e-dant/watcher/releases/latest | \
|
||||
@@ -110,16 +99,29 @@ RUN curl -s https://api.github.com/repos/e-dant/watcher/releases/latest | \
|
||||
cmake --build build && \
|
||||
cmake --install build
|
||||
|
||||
WORKDIR /go/src/app
|
||||
|
||||
COPY --link go.mod go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
WORKDIR /go/src/app/caddy
|
||||
COPY caddy/go.mod caddy/go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
WORKDIR /go/src/app
|
||||
COPY --link . ./
|
||||
|
||||
# See https://github.com/docker-library/php/blob/master/8.3/alpine3.20/zts/Dockerfile#L53-L55
|
||||
ENV CGO_CFLAGS="-DFRANKENPHP_VERSION=$FRANKENPHP_VERSION $PHP_CFLAGS"
|
||||
ENV CGO_CPPFLAGS=$PHP_CPPFLAGS
|
||||
ENV CGO_LDFLAGS="-lssl -lcrypto -lreadline -largon2 -lcurl -lonig -lz $PHP_LDFLAGS"
|
||||
|
||||
WORKDIR /go/src/app/caddy/frankenphp
|
||||
RUN GOBIN=/usr/local/bin go install -tags 'nobadger,nomysql,nopgx' -ldflags "-w -s -extldflags '-Wl,-z,stack-size=0x80000' -X 'github.com/caddyserver/caddy/v2.CustomVersion=FrankenPHP $FRANKENPHP_VERSION PHP $PHP_VERSION Caddy'" && \
|
||||
RUN GOBIN=/usr/local/bin go install -tags 'nobadger,nomysql,nopgx' -ldflags "-w -s -extldflags '-Wl,-z,stack-size=0x80000' -X 'github.com/caddyserver/caddy/v2.CustomVersion=FrankenPHP $FRANKENPHP_VERSION PHP $PHP_VERSION Caddy'" -buildvcs=true && \
|
||||
setcap cap_net_bind_service=+ep /usr/local/bin/frankenphp && \
|
||||
([ -z "${NO_COMPRESS}" ] && upx --best /usr/local/bin/frankenphp || true) && \
|
||||
frankenphp version
|
||||
frankenphp version && \
|
||||
frankenphp build-info
|
||||
|
||||
WORKDIR /go/src/app
|
||||
|
||||
@@ -135,4 +137,5 @@ RUN apk add --no-cache libstdc++ && \
|
||||
|
||||
COPY --from=builder /usr/local/bin/frankenphp /usr/local/bin/frankenphp
|
||||
RUN setcap cap_net_bind_service=+ep /usr/local/bin/frankenphp && \
|
||||
frankenphp version
|
||||
frankenphp version && \
|
||||
frankenphp build-info
|
||||
|
||||
119
build-packages.sh
Executable file
119
build-packages.sh
Executable file
@@ -0,0 +1,119 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -o errexit
|
||||
set -x
|
||||
|
||||
# Ensure required tools are installed
|
||||
if ! command -v rpmbuild &>/dev/null; then
|
||||
echo "Error: rpm-build is required to create RPM packages."
|
||||
echo "Install it with: sudo dnf install rpm-build"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v ruby &>/dev/null; then
|
||||
echo "Error: Ruby is required by FPM."
|
||||
echo "Install it with: sudo dnf install ruby"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v fpm &>/dev/null; then
|
||||
echo "Error: FPM (rubygem-fpm) is required to create RPM packages."
|
||||
echo "Install it with: sudo gem install fpm"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
arch="$(uname -m)"
|
||||
os="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
||||
bin="frankenphp-${os}-${arch}"
|
||||
|
||||
if [ ! -f "dist/$bin" ]; then
|
||||
echo "Error: dist/$bin not found. Run './build-static.sh' first"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
version_output="$(dist/"$bin" version)"
|
||||
frankenphp_version=$(echo "$version_output" | grep -oP 'FrankenPHP\s+\K[^ ]+' || true)
|
||||
frankenphp_version=${frankenphp_version#v}
|
||||
|
||||
if [[ ! "${frankenphp_version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "Warning: frankenphp_version must be set to X.Y.Z (e.g. 1.5.1), got '${frankenphp_version}'"
|
||||
echo "Falling back to non-release version 0.0.0"
|
||||
frankenphp_version=0.0.0
|
||||
fi
|
||||
|
||||
group_preexists=0
|
||||
user_preexists=0
|
||||
|
||||
if getent group frankenphp >/dev/null; then
|
||||
group_preexists=1
|
||||
else
|
||||
sudo groupadd --system frankenphp
|
||||
fi
|
||||
|
||||
if getent passwd frankenphp >/dev/null; then
|
||||
user_preexists=1
|
||||
else
|
||||
sudo useradd --system \
|
||||
--gid frankenphp \
|
||||
--create-home \
|
||||
--home-dir /var/lib/frankenphp \
|
||||
--shell /usr/sbin/nologin \
|
||||
--comment "FrankenPHP web server" \
|
||||
frankenphp
|
||||
fi
|
||||
|
||||
mkdir -p package/empty
|
||||
mkdir -p package/etc
|
||||
[ -f ./dist/static-php-cli/source/php-src/php.ini-production ] && cp -f ./dist/static-php-cli/source/php-src/php.ini-production ./package/etc/php.ini
|
||||
|
||||
cd dist
|
||||
iteration=1
|
||||
glibc_version=$(ldd -v "$bin" | awk '/GLIBC_/ {gsub(/[()]/, "", $2); print $2}' | grep -v GLIBC_PRIVATE | sort -V | tail -n1)
|
||||
cxxabi_version=$(strings "$bin" | grep -oP 'CXXABI_\d+\.\d+(\.\d+)?' | sort -V | tail -n1)
|
||||
|
||||
fpm -s dir -t rpm -n frankenphp -v "${frankenphp_version}" \
|
||||
--config-files /etc/frankenphp/Caddyfile \
|
||||
--config-files /etc/frankenphp/php.ini \
|
||||
--depends "libc.so.6(${glibc_version})(64bit)" \
|
||||
--depends "libstdc++.so.6(${cxxabi_version})(64bit)" \
|
||||
--before-install ../package/rhel/preinstall.sh \
|
||||
--after-install ../package/rhel/postinstall.sh \
|
||||
--before-remove ../package/rhel/preuninstall.sh \
|
||||
--after-remove ../package/rhel/postuninstall.sh \
|
||||
--iteration "${iteration}" \
|
||||
--rpm-user frankenphp --rpm-group frankenphp \
|
||||
"${bin}=/usr/bin/frankenphp" \
|
||||
"../package/rhel/frankenphp.service=/usr/lib/systemd/system/frankenphp.service" \
|
||||
"../package/Caddyfile=/etc/frankenphp/Caddyfile" \
|
||||
"../package/content/=/usr/share/frankenphp" \
|
||||
"../package/etc/php.ini=/etc/frankenphp/php.ini" \
|
||||
"../package/empty/=/etc/frankenphp/php.d" \
|
||||
"../package/empty/=/usr/lib/frankenphp/modules" \
|
||||
"../package/empty/=/var/lib/frankenphp"
|
||||
|
||||
glibc_version=$(ldd -v "$bin" | awk '/GLIBC_/ {gsub(/[()]/, "", $2); print $2}' | grep -v GLIBC_PRIVATE | sed 's/GLIBC_//' | sort -V | tail -n1)
|
||||
cxxabi_version=$(strings "$bin" | grep -oP 'CXXABI_\d+\.\d+(\.\d+)?' | sed 's/CXXABI_//' | sort -V | tail -n1)
|
||||
|
||||
fpm -s dir -t deb -n frankenphp -v "${frankenphp_version}" \
|
||||
--config-files /etc/frankenphp/Caddyfile \
|
||||
--config-files /etc/frankenphp/php.ini \
|
||||
--depends "libc6 (>= ${glibc_version})" \
|
||||
--depends "libstdc++6 (>= ${cxxabi_version})" \
|
||||
--after-install ../package/debian/postinst.sh \
|
||||
--before-remove ../package/debian/prerm.sh \
|
||||
--after-remove ../package/debian/postrm.sh \
|
||||
--iteration "${iteration}" \
|
||||
--deb-user frankenphp --deb-group frankenphp \
|
||||
"${bin}=/usr/bin/frankenphp" \
|
||||
"../package/debian/frankenphp.service=/usr/lib/systemd/system/frankenphp.service" \
|
||||
"../package/Caddyfile=/etc/frankenphp/Caddyfile" \
|
||||
"../package/content/=/usr/share/frankenphp" \
|
||||
"../package/etc/php.ini=/etc/frankenphp/php.ini" \
|
||||
"../package/empty/=/etc/frankenphp/php.d" \
|
||||
"../package/empty/=/usr/lib/frankenphp/modules" \
|
||||
"../package/empty/=/var/lib/frankenphp"
|
||||
|
||||
[ "$user_preexists" -eq 0 ] && sudo userdel frankenphp
|
||||
[ "$group_preexists" -eq 0 ] && (sudo groupdel frankenphp || true)
|
||||
|
||||
cd ..
|
||||
335
build-static.sh
335
build-static.sh
@@ -10,8 +10,75 @@ fi
|
||||
|
||||
arch="$(uname -m)"
|
||||
os="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
||||
# FIXME: re-enable PHP errors when SPC will be compatible with PHP 8.4
|
||||
spcCommand="php -ddisplay_errors=Off ./bin/spc"
|
||||
|
||||
# Supported variables:
|
||||
# - PHP_VERSION: PHP version to build (default: "8.4")
|
||||
# - PHP_EXTENSIONS: PHP extensions to build (default: ${defaultExtensions} set below)
|
||||
# - PHP_EXTENSION_LIBS: PHP extension libraries to build (default: ${defaultExtensionLibs} set below)
|
||||
# - FRANKENPHP_VERSION: FrankenPHP version (default: current Git commit)
|
||||
# - EMBED: Path to the PHP app to embed (default: none)
|
||||
# - DEBUG_SYMBOLS: Enable debug symbols if set to 1 (default: none)
|
||||
# - MIMALLOC: Use mimalloc as the allocator if set to 1 (default: none)
|
||||
# - XCADDY_ARGS: Additional arguments to pass to xcaddy
|
||||
# - RELEASE: [maintainer only] Create a GitHub release if set to 1 (default: none)
|
||||
|
||||
# - SPC_REL_TYPE: Release type to download (accept "source" and "binary", default: "source")
|
||||
# - SPC_OPT_BUILD_ARGS: Additional arguments to pass to spc build
|
||||
# - SPC_OPT_DOWNLOAD_ARGS: Additional arguments to pass to spc download
|
||||
# - SPC_LIBC: Set to glibc to build with GNU toolchain (default: musl)
|
||||
|
||||
# init spc command, if we use spc binary, just use it instead of fetching source
|
||||
if [ -z "${SPC_REL_TYPE}" ]; then
|
||||
SPC_REL_TYPE="source"
|
||||
fi
|
||||
# init spc libc
|
||||
if [ -z "${SPC_LIBC}" ]; then
|
||||
if [ "${os}" = "linux" ]; then
|
||||
SPC_LIBC="musl"
|
||||
fi
|
||||
fi
|
||||
# init spc build additional args
|
||||
if [ -z "${SPC_OPT_BUILD_ARGS}" ]; then
|
||||
SPC_OPT_BUILD_ARGS=""
|
||||
fi
|
||||
if [ "${SPC_LIBC}" = "musl" ] && [[ "${SPC_OPT_BUILD_ARGS}" != *"--disable-opcache-jit"* ]]; then
|
||||
SPC_OPT_BUILD_ARGS="${SPC_OPT_BUILD_ARGS} --disable-opcache-jit"
|
||||
fi
|
||||
# init spc download additional args
|
||||
if [ -z "${SPC_OPT_DOWNLOAD_ARGS}" ]; then
|
||||
SPC_OPT_DOWNLOAD_ARGS="--ignore-cache-sources=php-src --retry 5"
|
||||
if [ "${SPC_LIBC}" = "musl" ]; then
|
||||
SPC_OPT_DOWNLOAD_ARGS="${SPC_OPT_DOWNLOAD_ARGS} --prefer-pre-built"
|
||||
fi
|
||||
fi
|
||||
# if we need debug symbols, disable strip
|
||||
if [ -n "${DEBUG_SYMBOLS}" ]; then
|
||||
SPC_OPT_BUILD_ARGS="${SPC_OPT_BUILD_ARGS} --no-strip"
|
||||
fi
|
||||
# php version to build
|
||||
if [ -z "${PHP_VERSION}" ]; then
|
||||
get_latest_php_version() {
|
||||
input="$1"
|
||||
json=$(curl -s "https://www.php.net/releases/index.php?json&version=$input")
|
||||
latest=$(echo "$json" | jq -r '.version')
|
||||
|
||||
if [[ "$latest" == "$input"* ]]; then
|
||||
echo "$latest"
|
||||
else
|
||||
echo "$input"
|
||||
fi
|
||||
}
|
||||
|
||||
PHP_VERSION="$(get_latest_php_version "8.4")"
|
||||
export PHP_VERSION
|
||||
fi
|
||||
# default extension set
|
||||
defaultExtensions="apcu,bcmath,bz2,calendar,ctype,curl,dba,dom,exif,fileinfo,filter,ftp,gd,gmp,gettext,iconv,igbinary,imagick,intl,ldap,mbregex,mbstring,mysqli,mysqlnd,opcache,openssl,parallel,pcntl,pdo,pdo_mysql,pdo_pgsql,pdo_sqlite,pgsql,phar,posix,protobuf,readline,redis,session,shmop,simplexml,soap,sockets,sodium,sqlite3,ssh2,sysvmsg,sysvsem,sysvshm,tidy,tokenizer,xlswriter,xml,xmlreader,xmlwriter,zip,zlib,yaml,zstd"
|
||||
# if [ "${os}" != "linux" ] || [ "${SPC_LIBC}" = "glibc" ]; then
|
||||
# defaultExtensions="${defaultExtensions},ffi"
|
||||
# fi
|
||||
defaultExtensionLibs="bzip2,freetype,libavif,libjpeg,liblz4,libwebp,libzip,nghttp2"
|
||||
|
||||
md5binary="md5sum"
|
||||
if [ "${os}" = "darwin" ]; then
|
||||
os="mac"
|
||||
@@ -35,32 +102,6 @@ else
|
||||
fpie="-fpie"
|
||||
fi
|
||||
|
||||
if [ -z "${PHP_EXTENSIONS}" ]; then
|
||||
if [ -n "${EMBED}" ] && [ -f "${EMBED}/composer.json" ]; then
|
||||
cd "${EMBED}"
|
||||
# read the composer.json file and extract the required PHP extensions
|
||||
# remove internal extensions from the list: https://github.com/crazywhalecc/static-php-cli/blob/4b16631d45a57370b4747df15c8f105130e96d03/src/globals/defines.php#L26-L34
|
||||
PHP_EXTENSIONS="$(composer check-platform-reqs --no-dev 2>/dev/null | grep ^ext | sed -e 's/^ext-core//' -e 's/^ext-hash//' -e 's/^ext-json//' -e 's/^ext-pcre//' -e 's/^ext-reflection//' -e 's/^ext-spl//' -e 's/^ext-standard//' -e 's/^ext-//' -e 's/ .*//' | xargs | tr ' ' ',')"
|
||||
export PHP_EXTENSIONS
|
||||
cd -
|
||||
else
|
||||
export PHP_EXTENSIONS="apcu,bcmath,bz2,calendar,ctype,curl,dba,dom,exif,fileinfo,filter,ftp,gd,gmp,gettext,iconv,igbinary,imagick,intl,ldap,mbregex,mbstring,mysqli,mysqlnd,opcache,openssl,parallel,pcntl,pdo,pdo_mysql,pdo_pgsql,pdo_sqlite,pgsql,phar,posix,protobuf,readline,redis,session,shmop,simplexml,soap,sockets,sodium,sqlite3,ssh2,sysvmsg,sysvsem,sysvshm,tidy,tokenizer,xlswriter,xml,xmlreader,xmlwriter,zip,zlib,yaml,zstd"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "${PHP_EXTENSION_LIBS}" ]; then
|
||||
export PHP_EXTENSION_LIBS="bzip2,freetype,libavif,libjpeg,liblz4,libwebp,libzip,nghttp2"
|
||||
fi
|
||||
|
||||
# The Brotli library must always be built as it is required by http://github.com/dunglas/caddy-cbrotli
|
||||
if ! echo "${PHP_EXTENSION_LIBS}" | grep -q "\bbrotli\b"; then
|
||||
export PHP_EXTENSION_LIBS="${PHP_EXTENSION_LIBS},brotli"
|
||||
fi
|
||||
|
||||
if [ -z "${PHP_VERSION}" ]; then
|
||||
export PHP_VERSION="8.4"
|
||||
fi
|
||||
|
||||
if [ -z "${FRANKENPHP_VERSION}" ]; then
|
||||
FRANKENPHP_VERSION="$(git rev-parse --verify HEAD)"
|
||||
export FRANKENPHP_VERSION
|
||||
@@ -88,55 +129,90 @@ if [ -n "${CLEAN}" ]; then
|
||||
go clean -cache
|
||||
fi
|
||||
|
||||
cache_key="${PHP_VERSION}-${PHP_EXTENSIONS}-${PHP_EXTENSION_LIBS}"
|
||||
mkdir -p dist/
|
||||
cd dist/
|
||||
|
||||
if type "brew" >/dev/null 2>&1; then
|
||||
if ! type "composer" >/dev/null; then
|
||||
packages="composer"
|
||||
fi
|
||||
if ! type "go" >/dev/null 2>&1; then
|
||||
packages="${packages} go"
|
||||
fi
|
||||
if [ -n "${RELEASE}" ] && ! type "gh" >/dev/null 2>&1; then
|
||||
packages="${packages} gh"
|
||||
fi
|
||||
|
||||
if [ -n "${packages}" ]; then
|
||||
# shellcheck disable=SC2086
|
||||
brew install --formula --quiet ${packages}
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "${SPC_REL_TYPE}" = "binary" ]; then
|
||||
mkdir -p static-php-cli/
|
||||
cd static-php-cli/
|
||||
if [[ "${arch}" =~ "arm" ]]; then
|
||||
dl_arch="aarch64"
|
||||
else
|
||||
dl_arch="${arch}"
|
||||
fi
|
||||
curl -o spc -fsSL "https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-linux-${dl_arch}"
|
||||
chmod +x spc
|
||||
spcCommand="./spc"
|
||||
elif [ -d "static-php-cli/src" ]; then
|
||||
cd static-php-cli/
|
||||
git pull
|
||||
composer install --no-dev -a --no-interaction
|
||||
spcCommand="./bin/spc"
|
||||
else
|
||||
git clone --depth 1 https://github.com/crazywhalecc/static-php-cli --branch main
|
||||
cd static-php-cli/
|
||||
composer install --no-dev -a --no-interaction
|
||||
spcCommand="./bin/spc"
|
||||
fi
|
||||
|
||||
# Extensions to build
|
||||
if [ -z "${PHP_EXTENSIONS}" ]; then
|
||||
# enable EMBED mode, first check if project has dumped extensions
|
||||
if [ -n "${EMBED}" ] && [ -f "${EMBED}/composer.json" ] && [ -f "${EMBED}/composer.lock" ] && [ -f "${EMBED}/vendor/installed.json" ]; then
|
||||
cd "${EMBED}"
|
||||
# read the extensions using spc dump-extensions
|
||||
PHP_EXTENSIONS=$(${spcCommand} dump-extensions "${EMBED}" --format=text --no-dev --no-ext-output="${defaultExtensions}")
|
||||
else
|
||||
PHP_EXTENSIONS="${defaultExtensions}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Additional libraries to build
|
||||
if [ -z "${PHP_EXTENSION_LIBS}" ]; then
|
||||
PHP_EXTENSION_LIBS="${defaultExtensionLibs}"
|
||||
fi
|
||||
|
||||
# The Brotli library must always be built as it is required by http://github.com/dunglas/caddy-cbrotli
|
||||
if ! echo "${PHP_EXTENSION_LIBS}" | grep -q "\bbrotli\b"; then
|
||||
PHP_EXTENSION_LIBS="${PHP_EXTENSION_LIBS},brotli"
|
||||
fi
|
||||
|
||||
# The mimalloc library must be built if MIMALLOC is true
|
||||
if [ -n "${MIMALLOC}" ]; then
|
||||
if ! echo "${PHP_EXTENSION_LIBS}" | grep -q "\bmimalloc\b"; then
|
||||
PHP_EXTENSION_LIBS="${PHP_EXTENSION_LIBS},mimalloc"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Build libphp if necessary
|
||||
if [ -f dist/cache_key ] && [ "$(cat dist/cache_key)" = "${cache_key}" ] && [ -f "dist/static-php-cli/buildroot/lib/libphp.a" ]; then
|
||||
cd dist/static-php-cli
|
||||
cache_key="${PHP_VERSION}-${PHP_EXTENSIONS}-${PHP_EXTENSION_LIBS}"
|
||||
if [ -f ../cache_key ] && [ "$(cat ../cache_key)" = "${cache_key}" ] && [ -f "buildroot/lib/libphp.a" ]; then
|
||||
echo "Hit cache, skipping libphp build."
|
||||
else
|
||||
mkdir -p dist/
|
||||
cd dist/
|
||||
echo -n "${cache_key}" >cache_key
|
||||
|
||||
if [ -d "static-php-cli/" ]; then
|
||||
cd static-php-cli/
|
||||
git pull
|
||||
else
|
||||
git clone --depth 1 https://github.com/crazywhalecc/static-php-cli
|
||||
cd static-php-cli/
|
||||
fi
|
||||
|
||||
if type "brew" >/dev/null 2>&1; then
|
||||
if ! type "composer" >/dev/null; then
|
||||
packages="composer"
|
||||
fi
|
||||
if ! type "go" >/dev/null 2>&1; then
|
||||
packages="${packages} go"
|
||||
fi
|
||||
if [ -n "${RELEASE}" ] && ! type "gh" >/dev/null 2>&1; then
|
||||
packages="${packages} gh"
|
||||
fi
|
||||
|
||||
if [ -n "${packages}" ]; then
|
||||
# shellcheck disable=SC2086
|
||||
brew install --formula --quiet ${packages}
|
||||
fi
|
||||
fi
|
||||
|
||||
composer install --no-dev -a
|
||||
|
||||
if [ "${os}" = "linux" ]; then
|
||||
extraOpts="--disable-opcache-jit"
|
||||
fi
|
||||
|
||||
if [ -n "${DEBUG_SYMBOLS}" ]; then
|
||||
extraOpts="${extraOpts} --no-strip"
|
||||
fi
|
||||
|
||||
${spcCommand} doctor --auto-fix
|
||||
${spcCommand} download --with-php="${PHP_VERSION}" --for-extensions="${PHP_EXTENSIONS}" --for-libs="${PHP_EXTENSION_LIBS}" --ignore-cache-sources=php-src --prefer-pre-built
|
||||
# shellcheck disable=SC2086
|
||||
${spcCommand} build --debug --enable-zts --build-embed ${extraOpts} "${PHP_EXTENSIONS}" --with-libs="${PHP_EXTENSION_LIBS}"
|
||||
${spcCommand} download --with-php="${PHP_VERSION}" --for-extensions="${PHP_EXTENSIONS}" --for-libs="${PHP_EXTENSION_LIBS}" ${SPC_OPT_DOWNLOAD_ARGS}
|
||||
# shellcheck disable=SC2086
|
||||
${spcCommand} build --enable-zts --build-embed ${SPC_OPT_BUILD_ARGS} "${PHP_EXTENSIONS}" --with-libs="${PHP_EXTENSION_LIBS}"
|
||||
|
||||
echo -n "${cache_key}" >../cache_key
|
||||
fi
|
||||
|
||||
if ! type "go" >/dev/null 2>&1; then
|
||||
@@ -166,7 +242,12 @@ curl -f --retry 5 "${curlGitHubHeaders[@]}" https://api.github.com/repos/e-dant/
|
||||
xargs curl -fL --retry 5 "${curlGitHubHeaders[@]}" |
|
||||
tar xz --strip-components 1
|
||||
cd watcher-c
|
||||
cc -c -o libwatcher-c.o ./src/watcher-c.cpp -I ./include -I ../include -std=c++17 -Wall -Wextra "${fpic}"
|
||||
if [ -z "${CC}" ]; then
|
||||
watcherCC=cc
|
||||
else
|
||||
watcherCC="${CC}"
|
||||
fi
|
||||
${watcherCC} -c -o libwatcher-c.o ./src/watcher-c.cpp -I ./include -I ../include -std=c++17 -Wall -Wextra "${fpic}"
|
||||
ar rcs libwatcher-c.a libwatcher-c.o
|
||||
cp libwatcher-c.a ../../buildroot/lib/libwatcher-c.a
|
||||
mkdir -p ../../buildroot/include/wtr
|
||||
@@ -188,12 +269,19 @@ if [ "${os}" = "mac" ]; then
|
||||
elif [ "${os}" = "linux" ] && [ -z "${DEBUG_SYMBOLS}" ]; then
|
||||
CGO_LDFLAGS="-Wl,-O1 -pie"
|
||||
fi
|
||||
if [ "${os}" = "linux" ] && [ "${SPC_LIBC}" = "glibc" ]; then
|
||||
CGO_LDFLAGS="${CGO_LDFLAGS} -Wl,--allow-multiple-definition -Wl,--export-dynamic"
|
||||
fi
|
||||
|
||||
CGO_LDFLAGS="${CGO_LDFLAGS} ${PWD}/buildroot/lib/libbrotlicommon.a ${PWD}/buildroot/lib/libbrotlienc.a ${PWD}/buildroot/lib/libbrotlidec.a ${PWD}/buildroot/lib/libwatcher-c.a $(${spcCommand} spc-config "${PHP_EXTENSIONS}" --with-libs="${PHP_EXTENSION_LIBS}" --libs)"
|
||||
if [ "${os}" = "linux" ]; then
|
||||
if echo "${PHP_EXTENSIONS}" | grep -qE "\b(intl|imagick|grpc|v8js|protobuf|mongodb|tbb)\b"; then
|
||||
CGO_LDFLAGS="${CGO_LDFLAGS} -lstdc++"
|
||||
fi
|
||||
if [[ "$CGO_LDFLAGS" == *"${PWD}/buildroot/lib/mimalloc.o"* ]]; then
|
||||
CGO_LDFLAGS=${CGO_LDFLAGS//${PWD}\/buildroot\/lib\/mimalloc.o/}
|
||||
CGO_LDFLAGS="${PWD}/buildroot/lib/libmimalloc.a $CGO_LDFLAGS"
|
||||
fi
|
||||
if [ "${os}" = "linux" ] && [ "${SPC_LIBC}" = "glibc" ]; then
|
||||
CGO_LDFLAGS="${CGO_LDFLAGS//-lphp/-Wl,--whole-archive -lphp -Wl,--no-whole-archive}"
|
||||
# shellcheck disable=SC2046
|
||||
ar d "${PWD}/buildroot/lib/libphp.a" $(ar t "${PWD}/buildroot/lib/libphp.a" | grep '\.a$')
|
||||
fi
|
||||
|
||||
export CGO_LDFLAGS
|
||||
@@ -202,82 +290,6 @@ LIBPHP_VERSION="$(./buildroot/bin/php-config --version)"
|
||||
|
||||
cd ../
|
||||
|
||||
if [ "${os}" = "linux" ]; then
|
||||
if [ -n "${MIMALLOC}" ]; then
|
||||
# Replace musl's mallocng by mimalloc
|
||||
# The default musl allocator is slow, especially when used by multi-threaded apps,
|
||||
# and triggers weird bugs
|
||||
# Adapted from https://www.tweag.io/blog/2023-08-10-rust-static-link-with-mimalloc/
|
||||
|
||||
echo 'The USE_MIMALLOC environment variable is EXPERIMENTAL.'
|
||||
echo 'This option can be removed or its behavior modified at any time.'
|
||||
|
||||
if [ ! -f "mimalloc/out/libmimalloc.a" ]; then
|
||||
if [ -d "mimalloc" ]; then
|
||||
cd mimalloc/
|
||||
git reset --hard
|
||||
git clean -xdf
|
||||
git fetch --tags
|
||||
else
|
||||
git clone https://github.com/microsoft/mimalloc.git
|
||||
cd mimalloc/
|
||||
fi
|
||||
|
||||
git checkout "$(git describe --tags "$(git rev-list --tags --max-count=1 || true)" || true)"
|
||||
|
||||
curl -fL --retry 5 https://raw.githubusercontent.com/tweag/rust-alpine-mimalloc/1a756444a5c1484d26af9cd39187752728416ba8/mimalloc.diff -o mimalloc.diff
|
||||
patch -p1 <mimalloc.diff
|
||||
|
||||
mkdir -p out/
|
||||
cd out/
|
||||
if [ -n "${DEBUG_SYMBOLS}" ]; then
|
||||
cmake \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DMI_BUILD_SHARED=OFF \
|
||||
-DMI_BUILD_OBJECT=OFF \
|
||||
-DMI_BUILD_TESTS=OFF \
|
||||
../
|
||||
else
|
||||
cmake \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DMI_BUILD_SHARED=OFF \
|
||||
-DMI_BUILD_OBJECT=OFF \
|
||||
-DMI_BUILD_TESTS=OFF \
|
||||
../
|
||||
fi
|
||||
make -j"$(nproc || true)"
|
||||
|
||||
cd ../../
|
||||
fi
|
||||
|
||||
if [ -n "${DEBUG_SYMBOLS}" ]; then
|
||||
libmimalloc_path=mimalloc/out/libmimalloc-debug.a
|
||||
else
|
||||
libmimalloc_path=mimalloc/out/libmimalloc.a
|
||||
fi
|
||||
|
||||
# Patch musl library to use mimalloc
|
||||
for libc_path in "/usr/local/musl/lib/libc.a" "/usr/local/musl/$(uname -m)-linux-musl/lib/libc.a" "/usr/lib/libc.a"; do
|
||||
if [ ! -f "${libc_path}" ] || [ -f "${libc_path}.unpatched" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
{
|
||||
echo "CREATE libc.a"
|
||||
echo "ADDLIB ${libc_path}"
|
||||
echo "DELETE aligned_alloc.lo calloc.lo donate.lo free.lo libc_calloc.lo lite_malloc.lo malloc.lo malloc_usable_size.lo memalign.lo posix_memalign.lo realloc.lo reallocarray.lo valloc.lo"
|
||||
echo "ADDLIB ${libmimalloc_path}"
|
||||
echo "SAVE"
|
||||
} | ar -M
|
||||
mv "${libc_path}" "${libc_path}.unpatched"
|
||||
mv libc.a "${libc_path}"
|
||||
done
|
||||
fi
|
||||
|
||||
# Increase the default stack size to prevents issues with code including many files such as Symfony containers
|
||||
extraExtldflags="-Wl,-z,stack-size=0x80000"
|
||||
fi
|
||||
|
||||
if [ -z "${DEBUG_SYMBOLS}" ]; then
|
||||
extraLdflags="-w -s"
|
||||
fi
|
||||
@@ -299,17 +311,27 @@ if [ -n "${DEBUG_SYMBOLS}" ]; then
|
||||
XCADDY_DEBUG=1
|
||||
fi
|
||||
|
||||
if [ "${SPC_LIBC}" = "musl" ]; then
|
||||
muslStackSizeFix="-Wl,-z,stack-size=0x80000"
|
||||
fi
|
||||
|
||||
go env
|
||||
cd caddy/
|
||||
if [ -z "${SPC_LIBC}" ] || [ "${SPC_LIBC}" = "musl" ]; then
|
||||
xcaddyGoBuildFlags="-buildmode=pie -tags cgo,netgo,osusergo,static_build,nobadger,nomysql,nopgx -ldflags \"-linkmode=external -extldflags '-static-pie ${muslStackSizeFix}' ${extraLdflags} -X 'github.com/caddyserver/caddy/v2.CustomVersion=FrankenPHP ${FRANKENPHP_VERSION} PHP ${LIBPHP_VERSION} Caddy'\""
|
||||
elif [ "${SPC_LIBC}" = "glibc" ]; then
|
||||
xcaddyGoBuildFlags="-buildmode=pie -tags cgo,netgo,osusergo,nobadger,nomysql,nopgx -ldflags \"-linkmode=external -extldflags '-pie' ${extraLdflags} -X 'github.com/caddyserver/caddy/v2.CustomVersion=FrankenPHP ${FRANKENPHP_VERSION} PHP ${LIBPHP_VERSION} Caddy'\""
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
CGO_ENABLED=1 \
|
||||
XCADDY_GO_BUILD_FLAGS="-buildmode=pie -tags cgo,netgo,osusergo,static_build,nobadger,nomysql,nopgx -ldflags \"-linkmode=external -extldflags '-static-pie ${extraExtldflags}' ${extraLdflags} -X 'github.com/caddyserver/caddy/v2.CustomVersion=FrankenPHP ${FRANKENPHP_VERSION} PHP ${LIBPHP_VERSION} Caddy'\"" \
|
||||
XCADDY_GO_BUILD_FLAGS=${xcaddyGoBuildFlags} \
|
||||
XCADDY_DEBUG="${XCADDY_DEBUG}" \
|
||||
${XCADDY_COMMAND} build \
|
||||
--output "../dist/${bin}" \
|
||||
${XCADDY_ARGS} \
|
||||
--with github.com/dunglas/frankenphp=.. \
|
||||
--with github.com/dunglas/frankenphp/caddy=.
|
||||
--with frankenphp.dev=.. \
|
||||
--with frankenphp.dev/caddy=.
|
||||
cd ..
|
||||
|
||||
if [ -d "${EMBED}" ]; then
|
||||
@@ -322,6 +344,7 @@ if type "upx" >/dev/null 2>&1 && [ -z "${DEBUG_SYMBOLS}" ] && [ -z "${NO_COMPRES
|
||||
fi
|
||||
|
||||
"dist/${bin}" version
|
||||
"dist/${bin}" build-info
|
||||
|
||||
if [ -n "${RELEASE}" ]; then
|
||||
gh release upload "v${FRANKENPHP_VERSION}" "dist/${bin}" --repo dunglas/frankenphp --clobber
|
||||
|
||||
65
caddy/admin.go
Normal file
65
caddy/admin.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package caddy
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/caddyserver/caddy/v2"
|
||||
"frankenphp.dev"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type FrankenPHPAdmin struct{}
|
||||
|
||||
// if the id starts with "admin.api" the module will register AdminRoutes via module.Routes()
|
||||
func (FrankenPHPAdmin) CaddyModule() caddy.ModuleInfo {
|
||||
return caddy.ModuleInfo{
|
||||
ID: "admin.api.frankenphp",
|
||||
New: func() caddy.Module { return new(FrankenPHPAdmin) },
|
||||
}
|
||||
}
|
||||
|
||||
// EXPERIMENTAL: These routes are not yet stable and may change in the future.
|
||||
func (admin FrankenPHPAdmin) Routes() []caddy.AdminRoute {
|
||||
return []caddy.AdminRoute{
|
||||
{
|
||||
Pattern: "/frankenphp/workers/restart",
|
||||
Handler: caddy.AdminHandlerFunc(admin.restartWorkers),
|
||||
},
|
||||
{
|
||||
Pattern: "/frankenphp/threads",
|
||||
Handler: caddy.AdminHandlerFunc(admin.threads),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (admin *FrankenPHPAdmin) restartWorkers(w http.ResponseWriter, r *http.Request) error {
|
||||
if r.Method != http.MethodPost {
|
||||
return admin.error(http.StatusMethodNotAllowed, fmt.Errorf("method not allowed"))
|
||||
}
|
||||
|
||||
frankenphp.RestartWorkers()
|
||||
caddy.Log().Info("workers restarted from admin api")
|
||||
admin.success(w, "workers restarted successfully\n")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (admin *FrankenPHPAdmin) threads(w http.ResponseWriter, _ *http.Request) error {
|
||||
debugState := frankenphp.DebugState()
|
||||
prettyJson, err := json.MarshalIndent(debugState, "", " ")
|
||||
if err != nil {
|
||||
return admin.error(http.StatusInternalServerError, err)
|
||||
}
|
||||
|
||||
return admin.success(w, string(prettyJson))
|
||||
}
|
||||
|
||||
func (admin *FrankenPHPAdmin) success(w http.ResponseWriter, message string) error {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, err := w.Write([]byte(message))
|
||||
return err
|
||||
}
|
||||
|
||||
func (admin *FrankenPHPAdmin) error(statusCode int, err error) error {
|
||||
return caddy.APIError{HTTPStatus: statusCode, Err: err}
|
||||
}
|
||||
293
caddy/admin_test.go
Normal file
293
caddy/admin_test.go
Normal file
@@ -0,0 +1,293 @@
|
||||
package caddy_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"frankenphp.dev"
|
||||
"frankenphp.dev/internal/fastabs"
|
||||
"github.com/caddyserver/caddy/v2/caddytest"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRestartWorkerViaAdminApi(t *testing.T) {
|
||||
tester := caddytest.NewTester(t)
|
||||
tester.InitServer(`
|
||||
{
|
||||
skip_install_trust
|
||||
admin localhost:2999
|
||||
http_port `+testPort+`
|
||||
|
||||
frankenphp {
|
||||
worker ../testdata/worker-with-counter.php 1
|
||||
}
|
||||
}
|
||||
|
||||
localhost:`+testPort+` {
|
||||
route {
|
||||
root ../testdata
|
||||
rewrite worker-with-counter.php
|
||||
php
|
||||
}
|
||||
}
|
||||
`, "caddyfile")
|
||||
|
||||
tester.AssertGetResponse("http://localhost:"+testPort+"/", http.StatusOK, "requests:1")
|
||||
tester.AssertGetResponse("http://localhost:"+testPort+"/", http.StatusOK, "requests:2")
|
||||
|
||||
assertAdminResponse(t, tester, "POST", "workers/restart", http.StatusOK, "workers restarted successfully\n")
|
||||
|
||||
tester.AssertGetResponse("http://localhost:"+testPort+"/", http.StatusOK, "requests:1")
|
||||
}
|
||||
|
||||
func TestShowTheCorrectThreadDebugStatus(t *testing.T) {
|
||||
tester := caddytest.NewTester(t)
|
||||
tester.InitServer(`
|
||||
{
|
||||
skip_install_trust
|
||||
admin localhost:2999
|
||||
http_port `+testPort+`
|
||||
|
||||
frankenphp {
|
||||
num_threads 3
|
||||
max_threads 6
|
||||
worker ../testdata/worker-with-counter.php 1
|
||||
worker ../testdata/index.php 1
|
||||
}
|
||||
}
|
||||
|
||||
localhost:`+testPort+` {
|
||||
route {
|
||||
root ../testdata
|
||||
rewrite worker-with-counter.php
|
||||
php
|
||||
}
|
||||
}
|
||||
`, "caddyfile")
|
||||
|
||||
debugState := getDebugState(t, tester)
|
||||
|
||||
// assert that the correct threads are present in the thread info
|
||||
assert.Equal(t, debugState.ThreadDebugStates[0].State, "ready")
|
||||
assert.Contains(t, debugState.ThreadDebugStates[1].Name, "worker-with-counter.php")
|
||||
assert.Contains(t, debugState.ThreadDebugStates[2].Name, "index.php")
|
||||
assert.Equal(t, debugState.ReservedThreadCount, 3)
|
||||
assert.Len(t, debugState.ThreadDebugStates, 3)
|
||||
}
|
||||
|
||||
func TestAutoScaleWorkerThreads(t *testing.T) {
|
||||
wg := sync.WaitGroup{}
|
||||
maxTries := 10
|
||||
requestsPerTry := 200
|
||||
tester := caddytest.NewTester(t)
|
||||
tester.InitServer(`
|
||||
{
|
||||
skip_install_trust
|
||||
admin localhost:2999
|
||||
http_port `+testPort+`
|
||||
|
||||
frankenphp {
|
||||
max_threads 10
|
||||
num_threads 2
|
||||
worker ../testdata/sleep.php 1
|
||||
}
|
||||
}
|
||||
|
||||
localhost:`+testPort+` {
|
||||
route {
|
||||
root ../testdata
|
||||
rewrite sleep.php
|
||||
php
|
||||
}
|
||||
}
|
||||
`, "caddyfile")
|
||||
|
||||
// spam an endpoint that simulates IO
|
||||
endpoint := "http://localhost:" + testPort + "/?sleep=2&work=1000"
|
||||
amountOfThreads := len(getDebugState(t, tester).ThreadDebugStates)
|
||||
|
||||
// try to spawn the additional threads by spamming the server
|
||||
for tries := 0; tries < maxTries; tries++ {
|
||||
wg.Add(requestsPerTry)
|
||||
for i := 0; i < requestsPerTry; i++ {
|
||||
go func() {
|
||||
tester.AssertGetResponse(endpoint, http.StatusOK, "slept for 2 ms and worked for 1000 iterations")
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
amountOfThreads = len(getDebugState(t, tester).ThreadDebugStates)
|
||||
if amountOfThreads > 2 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// assert that there are now more threads than before
|
||||
assert.NotEqual(t, amountOfThreads, 2)
|
||||
}
|
||||
|
||||
// Note this test requires at least 2x40MB available memory for the process
|
||||
func TestAutoScaleRegularThreadsOnAutomaticThreadLimit(t *testing.T) {
|
||||
wg := sync.WaitGroup{}
|
||||
maxTries := 10
|
||||
requestsPerTry := 200
|
||||
tester := caddytest.NewTester(t)
|
||||
tester.InitServer(`
|
||||
{
|
||||
skip_install_trust
|
||||
admin localhost:2999
|
||||
http_port `+testPort+`
|
||||
|
||||
frankenphp {
|
||||
max_threads auto
|
||||
num_threads 1
|
||||
php_ini memory_limit 40M # a reasonable limit for the test
|
||||
}
|
||||
}
|
||||
|
||||
localhost:`+testPort+` {
|
||||
route {
|
||||
root ../testdata
|
||||
php
|
||||
}
|
||||
}
|
||||
`, "caddyfile")
|
||||
|
||||
// spam an endpoint that simulates IO
|
||||
endpoint := "http://localhost:" + testPort + "/sleep.php?sleep=2&work=1000"
|
||||
amountOfThreads := len(getDebugState(t, tester).ThreadDebugStates)
|
||||
|
||||
// try to spawn the additional threads by spamming the server
|
||||
for tries := 0; tries < maxTries; tries++ {
|
||||
wg.Add(requestsPerTry)
|
||||
for i := 0; i < requestsPerTry; i++ {
|
||||
go func() {
|
||||
tester.AssertGetResponse(endpoint, http.StatusOK, "slept for 2 ms and worked for 1000 iterations")
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
amountOfThreads = len(getDebugState(t, tester).ThreadDebugStates)
|
||||
if amountOfThreads > 1 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// assert that there are now more threads present
|
||||
assert.NotEqual(t, amountOfThreads, 1)
|
||||
}
|
||||
|
||||
func assertAdminResponse(t *testing.T, tester *caddytest.Tester, method string, path string, expectedStatus int, expectedBody string) {
|
||||
adminUrl := "http://localhost:2999/frankenphp/"
|
||||
r, err := http.NewRequest(method, adminUrl+path, nil)
|
||||
assert.NoError(t, err)
|
||||
if expectedBody == "" {
|
||||
_ = tester.AssertResponseCode(r, expectedStatus)
|
||||
return
|
||||
}
|
||||
_, _ = tester.AssertResponse(r, expectedStatus, expectedBody)
|
||||
}
|
||||
|
||||
func getAdminResponseBody(t *testing.T, tester *caddytest.Tester, method string, path string) string {
|
||||
adminUrl := "http://localhost:2999/frankenphp/"
|
||||
r, err := http.NewRequest(method, adminUrl+path, nil)
|
||||
assert.NoError(t, err)
|
||||
resp := tester.AssertResponseCode(r, http.StatusOK)
|
||||
defer resp.Body.Close()
|
||||
bytes, err := io.ReadAll(resp.Body)
|
||||
assert.NoError(t, err)
|
||||
|
||||
return string(bytes)
|
||||
}
|
||||
|
||||
func getDebugState(t *testing.T, tester *caddytest.Tester) frankenphp.FrankenPHPDebugState {
|
||||
threadStates := getAdminResponseBody(t, tester, "GET", "threads")
|
||||
|
||||
var debugStates frankenphp.FrankenPHPDebugState
|
||||
err := json.Unmarshal([]byte(threadStates), &debugStates)
|
||||
assert.NoError(t, err)
|
||||
|
||||
return debugStates
|
||||
}
|
||||
|
||||
func TestAddModuleWorkerViaAdminApi(t *testing.T) {
|
||||
// Initialize a server with admin API enabled
|
||||
tester := caddytest.NewTester(t)
|
||||
tester.InitServer(`
|
||||
{
|
||||
skip_install_trust
|
||||
admin localhost:2999
|
||||
http_port `+testPort+`
|
||||
}
|
||||
|
||||
localhost:`+testPort+` {
|
||||
route {
|
||||
root ../testdata
|
||||
php
|
||||
}
|
||||
}
|
||||
`, "caddyfile")
|
||||
|
||||
// Get initial debug state to check number of workers
|
||||
initialDebugState := getDebugState(t, tester)
|
||||
initialWorkerCount := 0
|
||||
for _, thread := range initialDebugState.ThreadDebugStates {
|
||||
if thread.Name != "" && thread.Name != "ready" {
|
||||
initialWorkerCount++
|
||||
}
|
||||
}
|
||||
|
||||
// Create a Caddyfile configuration with a module worker
|
||||
workerConfig := `
|
||||
{
|
||||
skip_install_trust
|
||||
admin localhost:2999
|
||||
http_port ` + testPort + `
|
||||
}
|
||||
|
||||
localhost:` + testPort + ` {
|
||||
route {
|
||||
root ../testdata
|
||||
php {
|
||||
worker ../testdata/worker-with-counter.php 1
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
// Send the configuration to the admin API
|
||||
adminUrl := "http://localhost:2999/load"
|
||||
r, err := http.NewRequest("POST", adminUrl, bytes.NewBufferString(workerConfig))
|
||||
assert.NoError(t, err)
|
||||
r.Header.Set("Content-Type", "text/caddyfile")
|
||||
resp := tester.AssertResponseCode(r, http.StatusOK)
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Get the updated debug state to check if the worker was added
|
||||
updatedDebugState := getDebugState(t, tester)
|
||||
updatedWorkerCount := 0
|
||||
workerFound := false
|
||||
filename, _ := fastabs.FastAbs("../testdata/worker-with-counter.php")
|
||||
for _, thread := range updatedDebugState.ThreadDebugStates {
|
||||
if thread.Name != "" && thread.Name != "ready" {
|
||||
updatedWorkerCount++
|
||||
if thread.Name == "Worker PHP Thread - "+filename {
|
||||
workerFound = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Assert that the worker was added
|
||||
assert.Greater(t, updatedWorkerCount, initialWorkerCount, "Worker count should have increased")
|
||||
assert.True(t, workerFound, fmt.Sprintf("Worker with name %q should be found", "Worker PHP Thread - "+filename))
|
||||
|
||||
// Make a request to the worker to verify it's working
|
||||
tester.AssertGetResponse("http://localhost:"+testPort+"/worker-with-counter.php", http.StatusOK, "requests:1")
|
||||
}
|
||||
423
caddy/caddy.go
423
caddy/caddy.go
@@ -7,12 +7,14 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/dunglas/frankenphp/internal/fastabs"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"frankenphp.dev/internal/fastabs"
|
||||
|
||||
"github.com/caddyserver/caddy/v2"
|
||||
"github.com/caddyserver/caddy/v2/caddyconfig"
|
||||
@@ -21,15 +23,20 @@ import (
|
||||
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
|
||||
"github.com/caddyserver/caddy/v2/modules/caddyhttp/fileserver"
|
||||
"github.com/caddyserver/caddy/v2/modules/caddyhttp/rewrite"
|
||||
"github.com/dunglas/frankenphp"
|
||||
"go.uber.org/zap"
|
||||
"frankenphp.dev"
|
||||
)
|
||||
|
||||
const defaultDocumentRoot = "public"
|
||||
const (
|
||||
defaultDocumentRoot = "public"
|
||||
defaultWatchPattern = "./**/*.{php,yaml,yml,twig,env}"
|
||||
)
|
||||
|
||||
var iniError = errors.New("'php_ini' must be in the format: php_ini \"<key>\" \"<value>\"")
|
||||
|
||||
func init() {
|
||||
caddy.RegisterModule(FrankenPHPApp{})
|
||||
caddy.RegisterModule(FrankenPHPModule{})
|
||||
caddy.RegisterModule(FrankenPHPAdmin{})
|
||||
|
||||
httpcaddyfile.RegisterGlobalOption("frankenphp", parseGlobalOption)
|
||||
|
||||
@@ -40,9 +47,9 @@ func init() {
|
||||
httpcaddyfile.RegisterDirectiveOrder("php_server", "before", "file_server")
|
||||
}
|
||||
|
||||
var metrics = frankenphp.NewPrometheusMetrics(prometheus.DefaultRegisterer)
|
||||
|
||||
type workerConfig struct {
|
||||
// Name for the worker. Default: the filename for FrankenPHPApp workers, always prefixed with "m#" for FrankenPHPModule workers.
|
||||
Name string `json:"name,omitempty"`
|
||||
// FileName sets the path to the worker script.
|
||||
FileName string `json:"file_name,omitempty"`
|
||||
// Num sets the number of workers to start.
|
||||
@@ -56,8 +63,17 @@ type workerConfig struct {
|
||||
type FrankenPHPApp struct {
|
||||
// NumThreads sets the number of PHP threads to start. Default: 2x the number of available CPUs.
|
||||
NumThreads int `json:"num_threads,omitempty"`
|
||||
// MaxThreads limits how many threads can be started at runtime. Default 2x NumThreads
|
||||
MaxThreads int `json:"max_threads,omitempty"`
|
||||
// Workers configures the worker scripts to start.
|
||||
Workers []workerConfig `json:"workers,omitempty"`
|
||||
// Overwrites the default php ini configuration
|
||||
PhpIni map[string]string `json:"php_ini,omitempty"`
|
||||
// The maximum amount of time a request may be stalled waiting for a thread
|
||||
MaxWaitTime time.Duration `json:"max_wait_time,omitempty"`
|
||||
|
||||
metrics frankenphp.Metrics
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
// CaddyModule returns the Caddy module information.
|
||||
@@ -68,13 +84,69 @@ func (f FrankenPHPApp) CaddyModule() caddy.ModuleInfo {
|
||||
}
|
||||
}
|
||||
|
||||
// Provision sets up the module.
|
||||
func (f *FrankenPHPApp) Provision(ctx caddy.Context) error {
|
||||
f.logger = ctx.Slogger()
|
||||
|
||||
if httpApp, err := ctx.AppIfConfigured("http"); err == nil {
|
||||
if httpApp.(*caddyhttp.App).Metrics != nil {
|
||||
f.metrics = frankenphp.NewPrometheusMetrics(ctx.GetMetricsRegistry())
|
||||
}
|
||||
} else {
|
||||
// if the http module is not configured (this should never happen) then collect the metrics by default
|
||||
f.metrics = frankenphp.NewPrometheusMetrics(ctx.GetMetricsRegistry())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *FrankenPHPApp) generateUniqueModuleWorkerName(filepath string) string {
|
||||
var i uint
|
||||
filepath, _ = fastabs.FastAbs(filepath)
|
||||
name := "m#" + filepath
|
||||
|
||||
retry:
|
||||
for _, wc := range f.Workers {
|
||||
if wc.Name == name {
|
||||
name = fmt.Sprintf("m#%s_%d", filepath, i)
|
||||
i++
|
||||
|
||||
goto retry
|
||||
}
|
||||
}
|
||||
|
||||
return name
|
||||
}
|
||||
|
||||
func (f *FrankenPHPApp) addModuleWorkers(workers ...workerConfig) ([]workerConfig, error) {
|
||||
for i := range workers {
|
||||
w := &workers[i]
|
||||
if frankenphp.EmbeddedAppPath != "" && filepath.IsLocal(w.FileName) {
|
||||
w.FileName = filepath.Join(frankenphp.EmbeddedAppPath, w.FileName)
|
||||
}
|
||||
if w.Name == "" {
|
||||
w.Name = f.generateUniqueModuleWorkerName(w.FileName)
|
||||
} else if !strings.HasPrefix(w.Name, "m#") {
|
||||
w.Name = "m#" + w.Name
|
||||
}
|
||||
f.Workers = append(f.Workers, *w)
|
||||
}
|
||||
return workers, nil
|
||||
}
|
||||
|
||||
func (f *FrankenPHPApp) Start() error {
|
||||
repl := caddy.NewReplacer()
|
||||
logger := caddy.Log()
|
||||
|
||||
opts := []frankenphp.Option{frankenphp.WithNumThreads(f.NumThreads), frankenphp.WithLogger(logger), frankenphp.WithMetrics(metrics)}
|
||||
for _, w := range f.Workers {
|
||||
opts = append(opts, frankenphp.WithWorkers(repl.ReplaceKnown(w.FileName, ""), w.Num, w.Env, w.Watch))
|
||||
opts := []frankenphp.Option{
|
||||
frankenphp.WithNumThreads(f.NumThreads),
|
||||
frankenphp.WithMaxThreads(f.MaxThreads),
|
||||
frankenphp.WithLogger(f.logger),
|
||||
frankenphp.WithMetrics(f.metrics),
|
||||
frankenphp.WithPhpIni(f.PhpIni),
|
||||
frankenphp.WithMaxWaitTime(f.MaxWaitTime),
|
||||
}
|
||||
for _, w := range append(f.Workers) {
|
||||
opts = append(opts, frankenphp.WithWorkers(w.Name, repl.ReplaceKnown(w.FileName, ""), w.Num, w.Env, w.Watch))
|
||||
}
|
||||
|
||||
frankenphp.Shutdown()
|
||||
@@ -86,104 +158,213 @@ func (f *FrankenPHPApp) Start() error {
|
||||
}
|
||||
|
||||
func (f *FrankenPHPApp) Stop() error {
|
||||
caddy.Log().Info("FrankenPHP stopped 🐘")
|
||||
f.logger.Info("FrankenPHP stopped 🐘")
|
||||
|
||||
// attempt a graceful shutdown if caddy is exiting
|
||||
// note: Exiting() is currently marked as 'experimental'
|
||||
// https://github.com/caddyserver/caddy/blob/e76405d55058b0a3e5ba222b44b5ef00516116aa/caddy.go#L810
|
||||
if caddy.Exiting() {
|
||||
frankenphp.Shutdown()
|
||||
frankenphp.DrainWorkers()
|
||||
}
|
||||
|
||||
// reset configuration so it doesn't bleed into later tests
|
||||
// reset the configuration so it doesn't bleed into later tests
|
||||
f.Workers = nil
|
||||
f.NumThreads = 0
|
||||
f.MaxWaitTime = 0
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseWorkerConfig(d *caddyfile.Dispenser) (workerConfig, error) {
|
||||
wc := workerConfig{}
|
||||
if d.NextArg() {
|
||||
wc.FileName = d.Val()
|
||||
}
|
||||
|
||||
if d.NextArg() {
|
||||
if d.Val() == "watch" {
|
||||
wc.Watch = append(wc.Watch, defaultWatchPattern)
|
||||
} else {
|
||||
v, err := strconv.ParseUint(d.Val(), 10, 32)
|
||||
if err != nil {
|
||||
return wc, err
|
||||
}
|
||||
|
||||
wc.Num = int(v)
|
||||
}
|
||||
}
|
||||
|
||||
if d.NextArg() {
|
||||
return wc, errors.New(`FrankenPHP: too many "worker" arguments: ` + d.Val())
|
||||
}
|
||||
|
||||
for d.NextBlock(1) {
|
||||
v := d.Val()
|
||||
switch v {
|
||||
case "name":
|
||||
if !d.NextArg() {
|
||||
return wc, d.ArgErr()
|
||||
}
|
||||
wc.Name = d.Val()
|
||||
case "file":
|
||||
if !d.NextArg() {
|
||||
return wc, d.ArgErr()
|
||||
}
|
||||
wc.FileName = d.Val()
|
||||
case "num":
|
||||
if !d.NextArg() {
|
||||
return wc, d.ArgErr()
|
||||
}
|
||||
|
||||
v, err := strconv.ParseUint(d.Val(), 10, 32)
|
||||
if err != nil {
|
||||
return wc, err
|
||||
}
|
||||
|
||||
wc.Num = int(v)
|
||||
case "env":
|
||||
args := d.RemainingArgs()
|
||||
if len(args) != 2 {
|
||||
return wc, d.ArgErr()
|
||||
}
|
||||
if wc.Env == nil {
|
||||
wc.Env = make(map[string]string)
|
||||
}
|
||||
wc.Env[args[0]] = args[1]
|
||||
case "watch":
|
||||
if !d.NextArg() {
|
||||
// the default if the watch directory is left empty:
|
||||
wc.Watch = append(wc.Watch, defaultWatchPattern)
|
||||
} else {
|
||||
wc.Watch = append(wc.Watch, d.Val())
|
||||
}
|
||||
default:
|
||||
allowedDirectives := "name, file, num, env, watch"
|
||||
return wc, wrongSubDirectiveError("worker", allowedDirectives, v)
|
||||
}
|
||||
}
|
||||
|
||||
if wc.FileName == "" {
|
||||
return wc, errors.New(`the "file" argument must be specified`)
|
||||
}
|
||||
|
||||
if frankenphp.EmbeddedAppPath != "" && filepath.IsLocal(wc.FileName) {
|
||||
wc.FileName = filepath.Join(frankenphp.EmbeddedAppPath, wc.FileName)
|
||||
}
|
||||
|
||||
return wc, nil
|
||||
}
|
||||
|
||||
// UnmarshalCaddyfile implements caddyfile.Unmarshaler.
|
||||
func (f *FrankenPHPApp) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
|
||||
for d.Next() {
|
||||
for d.NextBlock(0) {
|
||||
// when adding a new directive, also update the allowedDirectives error message
|
||||
switch d.Val() {
|
||||
case "num_threads":
|
||||
if !d.NextArg() {
|
||||
return d.ArgErr()
|
||||
}
|
||||
|
||||
v, err := strconv.Atoi(d.Val())
|
||||
v, err := strconv.ParseUint(d.Val(), 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.NumThreads = v
|
||||
case "worker":
|
||||
wc := workerConfig{}
|
||||
if d.NextArg() {
|
||||
wc.FileName = d.Val()
|
||||
f.NumThreads = int(v)
|
||||
case "max_threads":
|
||||
if !d.NextArg() {
|
||||
return d.ArgErr()
|
||||
}
|
||||
|
||||
if d.NextArg() {
|
||||
v, err := strconv.Atoi(d.Val())
|
||||
if d.Val() == "auto" {
|
||||
f.MaxThreads = -1
|
||||
continue
|
||||
}
|
||||
|
||||
v, err := strconv.ParseUint(d.Val(), 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.MaxThreads = int(v)
|
||||
case "max_wait_time":
|
||||
if !d.NextArg() {
|
||||
return d.ArgErr()
|
||||
}
|
||||
|
||||
v, err := time.ParseDuration(d.Val())
|
||||
if err != nil {
|
||||
return errors.New("max_wait_time must be a valid duration (example: 10s)")
|
||||
}
|
||||
|
||||
f.MaxWaitTime = v
|
||||
case "php_ini":
|
||||
parseIniLine := func(d *caddyfile.Dispenser) error {
|
||||
key := d.Val()
|
||||
if !d.NextArg() {
|
||||
return iniError
|
||||
}
|
||||
if f.PhpIni == nil {
|
||||
f.PhpIni = make(map[string]string)
|
||||
}
|
||||
f.PhpIni[key] = d.Val()
|
||||
if d.NextArg() {
|
||||
return iniError
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
isBlock := false
|
||||
for d.NextBlock(1) {
|
||||
isBlock = true
|
||||
err := parseIniLine(d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
wc.Num = v
|
||||
}
|
||||
|
||||
for d.NextBlock(1) {
|
||||
v := d.Val()
|
||||
switch v {
|
||||
case "file":
|
||||
if !d.NextArg() {
|
||||
return d.ArgErr()
|
||||
}
|
||||
wc.FileName = d.Val()
|
||||
case "num":
|
||||
if !d.NextArg() {
|
||||
return d.ArgErr()
|
||||
}
|
||||
|
||||
v, err := strconv.Atoi(d.Val())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
wc.Num = v
|
||||
case "env":
|
||||
args := d.RemainingArgs()
|
||||
if len(args) != 2 {
|
||||
return d.ArgErr()
|
||||
}
|
||||
if wc.Env == nil {
|
||||
wc.Env = make(map[string]string)
|
||||
}
|
||||
wc.Env[args[0]] = args[1]
|
||||
case "watch":
|
||||
if !d.NextArg() {
|
||||
// the default if the watch directory is left empty:
|
||||
wc.Watch = append(wc.Watch, "./**/*.{php,yaml,yml,twig,env}")
|
||||
} else {
|
||||
wc.Watch = append(wc.Watch, d.Val())
|
||||
}
|
||||
if !isBlock {
|
||||
if !d.NextArg() {
|
||||
return iniError
|
||||
}
|
||||
|
||||
if wc.FileName == "" {
|
||||
return errors.New(`the "file" argument must be specified`)
|
||||
err := parseIniLine(d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if frankenphp.EmbeddedAppPath != "" && filepath.IsLocal(wc.FileName) {
|
||||
wc.FileName = filepath.Join(frankenphp.EmbeddedAppPath, wc.FileName)
|
||||
case "worker":
|
||||
wc, err := parseWorkerConfig(d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if frankenphp.EmbeddedAppPath != "" && filepath.IsLocal(wc.FileName) {
|
||||
wc.FileName = filepath.Join(frankenphp.EmbeddedAppPath, wc.FileName)
|
||||
}
|
||||
if strings.HasPrefix(wc.Name, "m#") {
|
||||
return fmt.Errorf(`global worker names must not start with "m#": %q`, wc.Name)
|
||||
}
|
||||
// check for duplicate workers
|
||||
for _, existingWorker := range f.Workers {
|
||||
if existingWorker.FileName == wc.FileName {
|
||||
return fmt.Errorf("global workers must not have duplicate filenames: %q", wc.FileName)
|
||||
}
|
||||
}
|
||||
|
||||
f.Workers = append(f.Workers, wc)
|
||||
default:
|
||||
allowedDirectives := "num_threads, max_threads, php_ini, worker, max_wait_time"
|
||||
return wrongSubDirectiveError("frankenphp", allowedDirectives, d.Val())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if f.MaxThreads > 0 && f.NumThreads > 0 && f.MaxThreads < f.NumThreads {
|
||||
return errors.New(`"max_threads"" must be greater than or equal to "num_threads"`)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -209,11 +390,13 @@ type FrankenPHPModule struct {
|
||||
ResolveRootSymlink *bool `json:"resolve_root_symlink,omitempty"`
|
||||
// Env sets an extra environment variable to the given value. Can be specified more than once for multiple environment variables.
|
||||
Env map[string]string `json:"env,omitempty"`
|
||||
// Workers configures the worker scripts to start.
|
||||
Workers []workerConfig `json:"workers,omitempty"`
|
||||
|
||||
resolvedDocumentRoot string
|
||||
preparedEnv frankenphp.PreparedEnv
|
||||
preparedEnvNeedsReplacement bool
|
||||
logger *zap.Logger
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
// CaddyModule returns the Caddy module information.
|
||||
@@ -226,7 +409,24 @@ func (FrankenPHPModule) CaddyModule() caddy.ModuleInfo {
|
||||
|
||||
// Provision sets up the module.
|
||||
func (f *FrankenPHPModule) Provision(ctx caddy.Context) error {
|
||||
f.logger = ctx.Logger(f)
|
||||
f.logger = ctx.Slogger()
|
||||
app, err := ctx.App("frankenphp")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fapp, ok := app.(*FrankenPHPApp)
|
||||
if !ok {
|
||||
return fmt.Errorf(`expected ctx.App("frankenphp") to return *FrankenPHPApp, got %T`, app)
|
||||
}
|
||||
if fapp == nil {
|
||||
return fmt.Errorf(`expected ctx.App("frankenphp") to return *FrankenPHPApp, got nil`)
|
||||
}
|
||||
|
||||
workers, err := fapp.addModuleWorkers(f.Workers...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.Workers = workers
|
||||
|
||||
if f.Root == "" {
|
||||
if frankenphp.EmbeddedAppPath == "" {
|
||||
@@ -285,20 +485,26 @@ func (f *FrankenPHPModule) Provision(ctx caddy.Context) error {
|
||||
|
||||
// needReplacement checks if a string contains placeholders.
|
||||
func needReplacement(s string) bool {
|
||||
return strings.Contains(s, "{") || strings.Contains(s, "}")
|
||||
return strings.ContainsAny(s, "{}")
|
||||
}
|
||||
|
||||
// ServeHTTP implements caddyhttp.MiddlewareHandler.
|
||||
// TODO: Expose TLS versions as env vars, as Apache's mod_ssl: https://github.com/caddyserver/caddy/blob/master/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go#L298
|
||||
func (f FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ caddyhttp.Handler) error {
|
||||
func (f *FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ caddyhttp.Handler) error {
|
||||
origReq := r.Context().Value(caddyhttp.OriginalRequestCtxKey).(http.Request)
|
||||
repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
|
||||
|
||||
var documentRootOption frankenphp.RequestOption
|
||||
var documentRoot string
|
||||
if f.resolvedDocumentRoot == "" {
|
||||
documentRootOption = frankenphp.WithRequestDocumentRoot(repl.ReplaceKnown(f.Root, ""), *f.ResolveRootSymlink)
|
||||
documentRoot = repl.ReplaceKnown(f.Root, "")
|
||||
if documentRoot == "" && frankenphp.EmbeddedAppPath != "" {
|
||||
documentRoot = frankenphp.EmbeddedAppPath
|
||||
}
|
||||
documentRootOption = frankenphp.WithRequestDocumentRoot(documentRoot, *f.ResolveRootSymlink)
|
||||
} else {
|
||||
documentRootOption = frankenphp.WithRequestResolvedDocumentRoot(f.resolvedDocumentRoot)
|
||||
documentRoot = f.resolvedDocumentRoot
|
||||
documentRootOption = frankenphp.WithRequestResolvedDocumentRoot(documentRoot)
|
||||
}
|
||||
|
||||
env := f.preparedEnv
|
||||
@@ -309,18 +515,24 @@ func (f FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ ca
|
||||
}
|
||||
}
|
||||
|
||||
fullScriptPath, _ := fastabs.FastAbs(documentRoot + "/" + r.URL.Path)
|
||||
|
||||
workerName := ""
|
||||
for _, w := range f.Workers {
|
||||
if p, _ := fastabs.FastAbs(w.FileName); p == fullScriptPath {
|
||||
workerName = w.Name
|
||||
}
|
||||
}
|
||||
|
||||
fr, err := frankenphp.NewRequestWithContext(
|
||||
r,
|
||||
documentRootOption,
|
||||
frankenphp.WithRequestSplitPath(f.SplitPath),
|
||||
frankenphp.WithRequestPreparedEnv(env),
|
||||
frankenphp.WithOriginalRequest(&origReq),
|
||||
frankenphp.WithWorkerName(workerName),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return caddyhttp.Error(http.StatusInternalServerError, err)
|
||||
}
|
||||
|
||||
if err = frankenphp.ServeHTTP(w, fr); err != nil {
|
||||
return caddyhttp.Error(http.StatusInternalServerError, err)
|
||||
}
|
||||
@@ -330,6 +542,7 @@ func (f FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ ca
|
||||
|
||||
// UnmarshalCaddyfile implements caddyfile.Unmarshaler.
|
||||
func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
|
||||
// First pass: Parse all directives except "worker"
|
||||
for d.Next() {
|
||||
for d.NextBlock(0) {
|
||||
switch d.Val() {
|
||||
@@ -361,7 +574,6 @@ func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
|
||||
if !d.NextArg() {
|
||||
continue
|
||||
}
|
||||
|
||||
v, err := strconv.ParseBool(d.Val())
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -369,8 +581,58 @@ func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
|
||||
if d.NextArg() {
|
||||
return d.ArgErr()
|
||||
}
|
||||
|
||||
f.ResolveRootSymlink = &v
|
||||
|
||||
case "worker":
|
||||
for d.NextBlock(1) {
|
||||
}
|
||||
for d.NextArg() {
|
||||
}
|
||||
// Skip "worker" blocks in the first pass
|
||||
continue
|
||||
|
||||
default:
|
||||
allowedDirectives := "root, split, env, resolve_root_symlink, worker"
|
||||
return wrongSubDirectiveError("php or php_server", allowedDirectives, d.Val())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Second pass: Parse only "worker" blocks
|
||||
d.Reset()
|
||||
for d.Next() {
|
||||
for d.NextBlock(0) {
|
||||
if d.Val() == "worker" {
|
||||
wc, err := parseWorkerConfig(d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Inherit environment variables from the parent php_server directive
|
||||
if !filepath.IsAbs(wc.FileName) && f.Root != "" {
|
||||
wc.FileName = filepath.Join(f.Root, wc.FileName)
|
||||
}
|
||||
|
||||
if f.Env != nil {
|
||||
if wc.Env == nil {
|
||||
wc.Env = make(map[string]string)
|
||||
}
|
||||
for k, v := range f.Env {
|
||||
// Only set if not already defined in the worker
|
||||
if _, exists := wc.Env[k]; !exists {
|
||||
wc.Env[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if a worker with this filename already exists in this module
|
||||
for _, existingWorker := range f.Workers {
|
||||
if existingWorker.FileName == wc.FileName {
|
||||
return fmt.Errorf(`workers in a single "php_server" block must not have duplicate filenames: %q`, wc.FileName)
|
||||
}
|
||||
}
|
||||
|
||||
f.Workers = append(f.Workers, wc)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -380,7 +642,7 @@ func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
|
||||
|
||||
// parseCaddyfile unmarshals tokens from h into a new Middleware.
|
||||
func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
|
||||
m := FrankenPHPModule{}
|
||||
m := &FrankenPHPModule{}
|
||||
err := m.UnmarshalCaddyfile(h.Dispenser)
|
||||
|
||||
return m, err
|
||||
@@ -617,6 +879,7 @@ func parsePhpServer(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error)
|
||||
// using the php directive syntax
|
||||
dispenser.Next() // consume the directive name
|
||||
err = phpsrv.UnmarshalCaddyfile(dispenser)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -668,9 +931,15 @@ func parsePhpServer(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error)
|
||||
}, nil
|
||||
}
|
||||
|
||||
// return a nice error message
|
||||
func wrongSubDirectiveError(module string, allowedDriectives string, wrongValue string) error {
|
||||
return fmt.Errorf("unknown '%s' subdirective: '%s' (allowed directives are: %s)", module, wrongValue, allowedDriectives)
|
||||
}
|
||||
|
||||
// Interface guards
|
||||
var (
|
||||
_ caddy.App = (*FrankenPHPApp)(nil)
|
||||
_ caddy.Provisioner = (*FrankenPHPApp)(nil)
|
||||
_ caddy.Provisioner = (*FrankenPHPModule)(nil)
|
||||
_ caddyhttp.MiddlewareHandler = (*FrankenPHPModule)(nil)
|
||||
_ caddyfile.Unmarshaler = (*FrankenPHPModule)(nil)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
222
caddy/config_test.go
Normal file
222
caddy/config_test.go
Normal file
@@ -0,0 +1,222 @@
|
||||
package caddy
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestModuleWorkerDuplicateFilenamesFail(t *testing.T) {
|
||||
// Create a test configuration with duplicate worker filenames
|
||||
configWithDuplicateFilenames := `
|
||||
{
|
||||
php {
|
||||
worker {
|
||||
file worker-with-env.php
|
||||
num 1
|
||||
}
|
||||
worker {
|
||||
file worker-with-env.php
|
||||
num 2
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
// Parse the configuration
|
||||
d := caddyfile.NewTestDispenser(configWithDuplicateFilenames)
|
||||
module := &FrankenPHPModule{}
|
||||
|
||||
// Unmarshal the configuration
|
||||
err := module.UnmarshalCaddyfile(d)
|
||||
|
||||
// Verify that an error was returned
|
||||
require.Error(t, err, "Expected an error when two workers in the same module have the same filename")
|
||||
require.Contains(t, err.Error(), "must not have duplicate filenames", "Error message should mention duplicate filenames")
|
||||
}
|
||||
|
||||
func TestModuleWorkersWithDifferentFilenames(t *testing.T) {
|
||||
// Create a test configuration with different worker filenames
|
||||
configWithDifferentFilenames := `
|
||||
{
|
||||
php {
|
||||
worker ../testdata/worker-with-env.php
|
||||
worker ../testdata/worker-with-counter.php
|
||||
}
|
||||
}`
|
||||
|
||||
// Parse the configuration
|
||||
d := caddyfile.NewTestDispenser(configWithDifferentFilenames)
|
||||
module := &FrankenPHPModule{}
|
||||
|
||||
// Unmarshal the configuration
|
||||
err := module.UnmarshalCaddyfile(d)
|
||||
|
||||
// Verify that no error was returned
|
||||
require.NoError(t, err, "Expected no error when two workers in the same module have different filenames")
|
||||
|
||||
// Verify that both workers were added to the module
|
||||
require.Len(t, module.Workers, 2, "Expected two workers to be added to the module")
|
||||
require.Equal(t, "../testdata/worker-with-env.php", module.Workers[0].FileName, "First worker should have the correct filename")
|
||||
require.Equal(t, "../testdata/worker-with-counter.php", module.Workers[1].FileName, "Second worker should have the correct filename")
|
||||
}
|
||||
|
||||
func TestModuleWorkersDifferentNamesSucceed(t *testing.T) {
|
||||
// Create a test configuration with a worker name
|
||||
configWithWorkerName1 := `
|
||||
{
|
||||
php_server {
|
||||
worker {
|
||||
name test-worker-1
|
||||
file ../testdata/worker-with-env.php
|
||||
num 1
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
// Parse the first configuration
|
||||
d1 := caddyfile.NewTestDispenser(configWithWorkerName1)
|
||||
app := &FrankenPHPApp{}
|
||||
module1 := &FrankenPHPModule{}
|
||||
|
||||
// Unmarshal the first configuration
|
||||
err := module1.UnmarshalCaddyfile(d1)
|
||||
require.NoError(t, err, "First module should be configured without errors")
|
||||
|
||||
// Create a second test configuration with a different worker name
|
||||
configWithWorkerName2 := `
|
||||
{
|
||||
php_server {
|
||||
worker {
|
||||
name test-worker-2
|
||||
file ../testdata/worker-with-env.php
|
||||
num 1
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
// Parse the second configuration
|
||||
d2 := caddyfile.NewTestDispenser(configWithWorkerName2)
|
||||
module2 := &FrankenPHPModule{}
|
||||
|
||||
// Unmarshal the second configuration
|
||||
err = module2.UnmarshalCaddyfile(d2)
|
||||
|
||||
// Verify that no error was returned
|
||||
require.NoError(t, err, "Expected no error when two workers have different names")
|
||||
|
||||
_, err = app.addModuleWorkers(module1.Workers...)
|
||||
require.NoError(t, err, "Expected no error when adding the first module workers")
|
||||
_, err = app.addModuleWorkers(module2.Workers...)
|
||||
require.NoError(t, err, "Expected no error when adding the second module workers")
|
||||
|
||||
// Verify that both workers were added
|
||||
require.Len(t, app.Workers, 2, "Expected two workers in the app")
|
||||
require.Equal(t, "m#test-worker-1", app.Workers[0].Name, "First worker should have the correct name")
|
||||
require.Equal(t, "m#test-worker-2", app.Workers[1].Name, "Second worker should have the correct name")
|
||||
}
|
||||
|
||||
func TestModuleWorkerWithEnvironmentVariables(t *testing.T) {
|
||||
// Create a test configuration with environment variables
|
||||
configWithEnv := `
|
||||
{
|
||||
php {
|
||||
worker {
|
||||
file ../testdata/worker-with-env.php
|
||||
num 1
|
||||
env APP_ENV production
|
||||
env DEBUG true
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
// Parse the configuration
|
||||
d := caddyfile.NewTestDispenser(configWithEnv)
|
||||
module := &FrankenPHPModule{}
|
||||
|
||||
// Unmarshal the configuration
|
||||
err := module.UnmarshalCaddyfile(d)
|
||||
|
||||
// Verify that no error was returned
|
||||
require.NoError(t, err, "Expected no error when configuring a worker with environment variables")
|
||||
|
||||
// Verify that the worker was added to the module
|
||||
require.Len(t, module.Workers, 1, "Expected one worker to be added to the module")
|
||||
require.Equal(t, "../testdata/worker-with-env.php", module.Workers[0].FileName, "Worker should have the correct filename")
|
||||
|
||||
// Verify that the environment variables were set correctly
|
||||
require.Len(t, module.Workers[0].Env, 2, "Expected two environment variables")
|
||||
require.Equal(t, "production", module.Workers[0].Env["APP_ENV"], "APP_ENV should be set to production")
|
||||
require.Equal(t, "true", module.Workers[0].Env["DEBUG"], "DEBUG should be set to true")
|
||||
}
|
||||
|
||||
func TestModuleWorkerWithWatchConfiguration(t *testing.T) {
|
||||
// Create a test configuration with watch directories
|
||||
configWithWatch := `
|
||||
{
|
||||
php {
|
||||
worker {
|
||||
file ../testdata/worker-with-env.php
|
||||
num 1
|
||||
watch
|
||||
watch ./src/**/*.php
|
||||
watch ./config/**/*.yaml
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
// Parse the configuration
|
||||
d := caddyfile.NewTestDispenser(configWithWatch)
|
||||
module := &FrankenPHPModule{}
|
||||
|
||||
// Unmarshal the configuration
|
||||
err := module.UnmarshalCaddyfile(d)
|
||||
|
||||
// Verify that no error was returned
|
||||
require.NoError(t, err, "Expected no error when configuring a worker with watch directories")
|
||||
|
||||
// Verify that the worker was added to the module
|
||||
require.Len(t, module.Workers, 1, "Expected one worker to be added to the module")
|
||||
require.Equal(t, "../testdata/worker-with-env.php", module.Workers[0].FileName, "Worker should have the correct filename")
|
||||
|
||||
// Verify that the watch directories were set correctly
|
||||
require.Len(t, module.Workers[0].Watch, 3, "Expected three watch patterns")
|
||||
require.Equal(t, "./**/*.{php,yaml,yml,twig,env}", module.Workers[0].Watch[0], "First watch pattern should be the default")
|
||||
require.Equal(t, "./src/**/*.php", module.Workers[0].Watch[1], "Second watch pattern should match the configuration")
|
||||
require.Equal(t, "./config/**/*.yaml", module.Workers[0].Watch[2], "Third watch pattern should match the configuration")
|
||||
}
|
||||
|
||||
func TestModuleWorkerWithCustomName(t *testing.T) {
|
||||
// Create a test configuration with a custom worker name
|
||||
configWithCustomName := `
|
||||
{
|
||||
php {
|
||||
worker {
|
||||
file ../testdata/worker-with-env.php
|
||||
num 1
|
||||
name custom-worker-name
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
// Parse the configuration
|
||||
d := caddyfile.NewTestDispenser(configWithCustomName)
|
||||
module := &FrankenPHPModule{}
|
||||
app := &FrankenPHPApp{}
|
||||
|
||||
// Unmarshal the configuration
|
||||
err := module.UnmarshalCaddyfile(d)
|
||||
|
||||
// Verify that no error was returned
|
||||
require.NoError(t, err, "Expected no error when configuring a worker with a custom name")
|
||||
|
||||
// Verify that the worker was added to the module
|
||||
require.Len(t, module.Workers, 1, "Expected one worker to be added to the module")
|
||||
require.Equal(t, "../testdata/worker-with-env.php", module.Workers[0].FileName, "Worker should have the correct filename")
|
||||
|
||||
// Verify that the worker was added to app.Workers with the m# prefix
|
||||
module.Workers, err = app.addModuleWorkers(module.Workers...)
|
||||
require.NoError(t, err, "Expected no error when adding the worker to the app")
|
||||
require.Equal(t, "m#custom-worker-name", module.Workers[0].Name, "Worker should have the custom name, prefixed with m#")
|
||||
require.Equal(t, "m#custom-worker-name", app.Workers[0].Name, "Worker should have the custom name, prefixed with m#")
|
||||
}
|
||||
@@ -1,8 +1,14 @@
|
||||
# The Caddyfile is an easy way to configure FrankenPHP and the Caddy web server.
|
||||
#
|
||||
# https://frankenphp.dev/docs/config
|
||||
# https://caddyserver.com/docs/caddyfile
|
||||
{
|
||||
skip_install_trust
|
||||
|
||||
{$CADDY_GLOBAL_OPTIONS}
|
||||
|
||||
frankenphp {
|
||||
{$FRANKENPHP_CONFIG}
|
||||
#worker /path/to/your/worker.php
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +25,7 @@
|
||||
#}
|
||||
|
||||
root public/
|
||||
root * public/
|
||||
encode zstd br gzip
|
||||
|
||||
# Uncomment the following lines to enable Mercure and Vulcain modules
|
||||
#mercure {
|
||||
@@ -41,5 +47,13 @@
|
||||
{$CADDY_SERVER_EXTRA_DIRECTIVES}
|
||||
|
||||
php_server {
|
||||
php_server
|
||||
#worker /path/to/your/worker.php
|
||||
}
|
||||
}
|
||||
|
||||
# As an alternative to editing the above site block, you can add your own site
|
||||
# block files in the Caddyfile.d directory, and they will be included as long
|
||||
# as they use the .caddyfile extension.
|
||||
|
||||
import Caddyfile.d/*.caddyfile
|
||||
import Caddyfile.d/*.caddyfile
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
// plug in Caddy modules here.
|
||||
_ "github.com/caddyserver/caddy/v2/modules/standard"
|
||||
_ "github.com/dunglas/caddy-cbrotli"
|
||||
_ "github.com/dunglas/frankenphp/caddy"
|
||||
_ "frankenphp.dev/caddy"
|
||||
_ "github.com/dunglas/mercure/caddy"
|
||||
_ "github.com/dunglas/vulcain/caddy"
|
||||
)
|
||||
|
||||
210
caddy/go.mod
210
caddy/go.mod
@@ -1,153 +1,155 @@
|
||||
module github.com/dunglas/frankenphp/caddy
|
||||
module frankenphp.dev/caddy
|
||||
|
||||
go 1.22.7
|
||||
go 1.24.0
|
||||
|
||||
replace github.com/dunglas/frankenphp => ../
|
||||
replace frankenphp.dev => ../
|
||||
|
||||
retract v1.0.0-rc.1 // Human error
|
||||
|
||||
require (
|
||||
github.com/caddyserver/caddy/v2 v2.9.1
|
||||
github.com/caddyserver/certmagic v0.21.7
|
||||
github.com/caddyserver/caddy/v2 v2.10.0
|
||||
github.com/caddyserver/certmagic v0.23.0
|
||||
github.com/dunglas/caddy-cbrotli v1.0.0
|
||||
github.com/dunglas/frankenphp v1.4.2
|
||||
github.com/dunglas/mercure/caddy v0.18.2
|
||||
github.com/dunglas/vulcain/caddy v1.1.1
|
||||
github.com/prometheus/client_golang v1.20.5
|
||||
github.com/spf13/cobra v1.8.1
|
||||
frankenphp.dev v1.7.0
|
||||
github.com/dunglas/mercure/caddy v0.19.2
|
||||
github.com/dunglas/vulcain/caddy v1.2.0
|
||||
github.com/prometheus/client_golang v1.22.0
|
||||
github.com/spf13/cobra v1.9.1
|
||||
github.com/stretchr/testify v1.10.0
|
||||
go.uber.org/zap v1.27.0
|
||||
)
|
||||
|
||||
require github.com/smallstep/go-attestation v0.4.4-0.20240109183208-413678f90935 // indirect
|
||||
require github.com/smallstep/go-attestation v0.4.4-0.20241119153605-2306d5b464ca // indirect
|
||||
|
||||
require (
|
||||
cel.dev/expr v0.19.2 // indirect
|
||||
dario.cat/mergo v1.0.1 // indirect
|
||||
cel.dev/expr v0.24.0 // indirect
|
||||
dario.cat/mergo v1.0.2 // indirect
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect
|
||||
github.com/BurntSushi/toml v1.4.0 // indirect
|
||||
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||
github.com/KimMachineGun/automemlimit v0.7.2 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.3.1 // indirect
|
||||
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
|
||||
github.com/MauriceGit/skiplist v0.0.0-20211105230623-77f5c8d3e145 // indirect
|
||||
github.com/MicahParks/jwkset v0.8.0 // indirect
|
||||
github.com/MicahParks/keyfunc/v3 v3.3.10 // indirect
|
||||
github.com/MicahParks/jwkset v0.9.6 // indirect
|
||||
github.com/MicahParks/keyfunc/v3 v3.4.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/RoaringBitmap/roaring v1.9.4 // indirect
|
||||
github.com/alecthomas/chroma/v2 v2.15.0 // indirect
|
||||
github.com/alecthomas/chroma/v2 v2.18.0 // indirect
|
||||
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
|
||||
github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.20.0 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.22.0 // indirect
|
||||
github.com/caddyserver/zerossl v0.1.3 // indirect
|
||||
github.com/ccoveille/go-safecast v1.6.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cespare/xxhash v1.1.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/chzyer/readline v1.5.1 // indirect
|
||||
github.com/coreos/go-oidc/v3 v3.12.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
|
||||
github.com/cloudflare/circl v1.6.1 // indirect
|
||||
github.com/coreos/go-oidc/v3 v3.14.1 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/dgraph-io/badger v1.6.2 // indirect
|
||||
github.com/dgraph-io/badger/v2 v2.2007.4 // indirect
|
||||
github.com/dgraph-io/ristretto v0.2.0 // indirect
|
||||
github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da // indirect
|
||||
github.com/dlclark/regexp2 v1.11.4 // indirect
|
||||
github.com/dlclark/regexp2 v1.11.5 // indirect
|
||||
github.com/dolthub/maphash v0.1.0 // indirect
|
||||
github.com/dunglas/httpsfv v1.0.2 // indirect
|
||||
github.com/dunglas/mercure v0.18.2 // indirect
|
||||
github.com/dunglas/vulcain v1.1.1 // indirect
|
||||
github.com/dunglas/httpsfv v1.1.0 // indirect
|
||||
github.com/dunglas/mercure v0.19.2 // indirect
|
||||
github.com/dunglas/vulcain v1.2.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/francoispqt/gojay v1.2.13 // indirect
|
||||
github.com/fsnotify/fsnotify v1.8.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.8.0 // indirect
|
||||
github.com/gammazero/deque v1.0.0 // indirect
|
||||
github.com/getkin/kin-openapi v0.128.0 // indirect
|
||||
github.com/go-chi/chi/v5 v5.2.0 // indirect
|
||||
github.com/go-jose/go-jose/v3 v3.0.3 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.4 // indirect
|
||||
github.com/getkin/kin-openapi v0.132.0 // indirect
|
||||
github.com/go-chi/chi/v5 v5.2.1 // indirect
|
||||
github.com/go-jose/go-jose/v3 v3.0.4 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.1.0 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/go-sql-driver/mysql v1.8.1 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.1 // indirect
|
||||
github.com/go-openapi/swag v0.23.1 // indirect
|
||||
github.com/go-sql-driver/mysql v1.9.2 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
|
||||
github.com/gofrs/uuid v4.4.0+incompatible // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/golang/snappy v1.0.0 // indirect
|
||||
github.com/google/brotli/go/cbrotli v0.0.0-20241111155135-4303850b01d6 // indirect
|
||||
github.com/google/cel-go v0.23.0 // indirect
|
||||
github.com/google/certificate-transparency-go v1.3.0 // indirect
|
||||
github.com/google/go-tpm v0.9.3 // indirect
|
||||
github.com/google/cel-go v0.25.0 // indirect
|
||||
github.com/google/certificate-transparency-go v1.3.1 // indirect
|
||||
github.com/google/go-tpm v0.9.5 // indirect
|
||||
github.com/google/go-tspi v0.3.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20250125003558-7fdb3d7e6fa0 // indirect
|
||||
github.com/google/pprof v0.0.0-20250602020802-c6617b811d0e // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/handlers v1.5.2 // indirect
|
||||
github.com/gorilla/mux v1.8.1 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
|
||||
github.com/hashicorp/golang-lru v1.0.2 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/huandu/xstrings v1.5.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/invopop/yaml v0.3.1 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/pgx/v5 v5.7.2 // indirect
|
||||
github.com/jackc/pgx/v5 v5.7.5 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/kevburnsjr/skipfilter v0.0.1 // indirect
|
||||
github.com/klauspost/compress v1.17.11 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/libdns/libdns v0.2.2 // indirect
|
||||
github.com/magiconair/properties v1.8.9 // indirect
|
||||
github.com/libdns/libdns v1.1.0 // indirect
|
||||
github.com/mailru/easyjson v0.9.0 // indirect
|
||||
github.com/manifoldco/promptui v0.9.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/maypok86/otter v1.2.4 // indirect
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
||||
github.com/mholt/acmez/v3 v3.0.1 // indirect
|
||||
github.com/miekg/dns v1.1.63 // indirect
|
||||
github.com/mholt/acmez/v3 v3.1.2 // indirect
|
||||
github.com/miekg/dns v1.1.66 // 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/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
|
||||
github.com/mschoch/smat v0.2.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.22.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect
|
||||
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.23.4 // indirect
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/perimeterx/marshmallow v1.1.5 // indirect
|
||||
github.com/pires/go-proxyproto v0.8.0 // indirect
|
||||
github.com/pires/go-proxyproto v0.8.1 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.62.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.64.0 // indirect
|
||||
github.com/prometheus/procfs v0.16.1 // indirect
|
||||
github.com/quic-go/qpack v0.5.1 // indirect
|
||||
github.com/quic-go/quic-go v0.49.0 // indirect
|
||||
github.com/quic-go/quic-go v0.52.0 // indirect
|
||||
github.com/rs/xid v1.6.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sagikazarmark/locafero v0.7.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/sagikazarmark/locafero v0.9.0 // indirect
|
||||
github.com/shopspring/decimal v1.4.0 // indirect
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/slackhq/nebula v1.9.4 // indirect
|
||||
github.com/smallstep/certificates v0.28.1 // indirect
|
||||
github.com/smallstep/cli-utils v0.10.0 // indirect
|
||||
github.com/slackhq/nebula v1.9.5 // indirect
|
||||
github.com/smallstep/certificates v0.28.3 // indirect
|
||||
github.com/smallstep/cli-utils v0.12.1 // indirect
|
||||
github.com/smallstep/linkedca v0.23.0 // indirect
|
||||
github.com/smallstep/nosql v0.7.0 // indirect
|
||||
github.com/smallstep/pkcs7 v0.1.1 // indirect
|
||||
github.com/smallstep/scep v0.0.0-20241223071629-a37a330173bc // indirect
|
||||
github.com/smallstep/pkcs7 v0.2.1 // indirect
|
||||
github.com/smallstep/scep v0.0.0-20250318231241-a25cabb69492 // indirect
|
||||
github.com/smallstep/truststore v0.13.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.12.0 // indirect
|
||||
github.com/spf13/cast v1.7.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/viper v1.19.0 // indirect
|
||||
github.com/spf13/afero v1.14.0 // indirect
|
||||
github.com/spf13/cast v1.9.2 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/spf13/viper v1.20.1 // indirect
|
||||
github.com/stoewer/go-strcase v1.3.0 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/tailscale/tscert v0.0.0-20240608151842-d3f834017e53 // indirect
|
||||
@@ -159,47 +161,47 @@ require (
|
||||
github.com/urfave/cli v1.22.16 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
|
||||
github.com/yuin/goldmark v1.7.8 // indirect
|
||||
github.com/yuin/goldmark v1.7.12 // indirect
|
||||
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc // indirect
|
||||
github.com/zeebo/blake3 v0.2.4 // indirect
|
||||
go.etcd.io/bbolt v1.3.11 // indirect
|
||||
go.etcd.io/bbolt v1.4.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect
|
||||
go.opentelemetry.io/contrib/propagators/autoprop v0.58.0 // indirect
|
||||
go.opentelemetry.io/contrib/propagators/aws v1.33.0 // indirect
|
||||
go.opentelemetry.io/contrib/propagators/b3 v1.33.0 // indirect
|
||||
go.opentelemetry.io/contrib/propagators/jaeger v1.33.0 // indirect
|
||||
go.opentelemetry.io/contrib/propagators/ot v1.33.0 // indirect
|
||||
go.opentelemetry.io/otel v1.33.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.33.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.33.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.33.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.4.0 // indirect
|
||||
go.step.sm/crypto v0.57.0 // indirect
|
||||
go.step.sm/linkedca v0.22.2 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
|
||||
go.opentelemetry.io/contrib/propagators/autoprop v0.60.0 // indirect
|
||||
go.opentelemetry.io/contrib/propagators/aws v1.35.0 // indirect
|
||||
go.opentelemetry.io/contrib/propagators/b3 v1.35.0 // indirect
|
||||
go.opentelemetry.io/contrib/propagators/jaeger v1.35.0 // indirect
|
||||
go.opentelemetry.io/contrib/propagators/ot v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.35.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.6.0 // indirect
|
||||
go.step.sm/crypto v0.66.0 // indirect
|
||||
go.uber.org/automaxprocs v1.6.0 // indirect
|
||||
go.uber.org/mock v0.5.0 // indirect
|
||||
go.uber.org/mock v0.5.2 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
go.uber.org/zap/exp v0.3.0 // indirect
|
||||
golang.org/x/crypto v0.32.0 // indirect
|
||||
golang.org/x/crypto/x509roots/fallback v0.0.0-20250118192723-a8ea4be81f07 // indirect
|
||||
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect
|
||||
golang.org/x/mod v0.22.0 // indirect
|
||||
golang.org/x/net v0.34.0 // indirect
|
||||
golang.org/x/oauth2 v0.25.0 // indirect
|
||||
golang.org/x/sync v0.10.0 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
golang.org/x/term v0.28.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/time v0.9.0 // indirect
|
||||
golang.org/x/tools v0.29.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250127172529-29210b9bc287 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250127172529-29210b9bc287 // indirect
|
||||
google.golang.org/grpc v1.70.0 // indirect
|
||||
google.golang.org/protobuf v1.36.4 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
golang.org/x/crypto v0.38.0 // indirect
|
||||
golang.org/x/crypto/x509roots/fallback v0.0.0-20250531095911-4f9f0ca9fcfb // indirect
|
||||
golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b // indirect
|
||||
golang.org/x/mod v0.24.0 // indirect
|
||||
golang.org/x/net v0.40.0 // indirect
|
||||
golang.org/x/oauth2 v0.30.0 // indirect
|
||||
golang.org/x/sync v0.14.0 // indirect
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
golang.org/x/term v0.32.0 // indirect
|
||||
golang.org/x/text v0.25.0 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
golang.org/x/tools v0.33.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect
|
||||
google.golang.org/grpc v1.72.2 // indirect
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
howett.net/plist v1.0.1 // indirect
|
||||
|
||||
531
caddy/go.sum
531
caddy/go.sum
@@ -1,26 +1,25 @@
|
||||
cel.dev/expr v0.19.2 h1:V354PbqIXr9IQdwy4SYA4xa0HXaWq1BUPAGzugBY5V4=
|
||||
cel.dev/expr v0.19.2/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
|
||||
cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY=
|
||||
cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
|
||||
cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE=
|
||||
cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U=
|
||||
cloud.google.com/go/auth v0.13.0 h1:8Fu8TZy167JkW8Tj3q7dIkr2v4cndv41ouecJx0PAHs=
|
||||
cloud.google.com/go/auth v0.13.0/go.mod h1:COOjD9gwfKNKz+IIduatIhYJQIc0mG3H102r/EMxX6Q=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.6 h1:V6a6XDu2lTwPZWOawrAa9HUK+DB2zfJyTuciBG5hFkU=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.6/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8=
|
||||
cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg=
|
||||
cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
|
||||
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
|
||||
cloud.google.com/go/iam v1.2.2 h1:ozUSofHUGf/F4tCNy/mu9tHLTaxZFLOUiKzjcgWHGIA=
|
||||
cloud.google.com/go/iam v1.2.2/go.mod h1:0Ys8ccaZHdI1dEUilwzqng/6ps2YB6vRsjIe00/+6JY=
|
||||
cloud.google.com/go/kms v1.20.4 h1:CJ0hMpOg1ANN9tx/a/GPJ+Uxudy8k6f3fvGFuTHiE5A=
|
||||
cloud.google.com/go/kms v1.20.4/go.mod h1:gPLsp1r4FblUgBYPOcvI/bUPpdMg2Jm1ZVKU4tQUfcc=
|
||||
cloud.google.com/go/longrunning v0.6.2 h1:xjDfh1pQcWPEvnfjZmwjKQEcHnpz6lHjfy7Fo0MK+hc=
|
||||
cloud.google.com/go/longrunning v0.6.2/go.mod h1:k/vIs83RN4bE3YCswdXC5PFfWVILjm3hpEUlSko4PiI=
|
||||
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
||||
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
cloud.google.com/go v0.120.0 h1:wc6bgG9DHyKqF5/vQvX1CiZrtHnxJjBlKUyF9nP6meA=
|
||||
cloud.google.com/go v0.120.0/go.mod h1:/beW32s8/pGRuj4IILWQNd4uuebeT4dkOhKmkfit64Q=
|
||||
cloud.google.com/go/auth v0.16.1 h1:XrXauHMd30LhQYVRHLGvJiYeczweKQXZxsTbV9TiguU=
|
||||
cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
|
||||
cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU=
|
||||
cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo=
|
||||
cloud.google.com/go/iam v1.5.2 h1:qgFRAGEmd8z6dJ/qyEchAuL9jpswyODjA2lS+w234g8=
|
||||
cloud.google.com/go/iam v1.5.2/go.mod h1:SE1vg0N81zQqLzQEwxL2WI6yhetBdbNQuTvIKCSkUHE=
|
||||
cloud.google.com/go/kms v1.22.0 h1:dBRIj7+GDeeEvatJeTB19oYZNV0aj6wEqSIT/7gLqtk=
|
||||
cloud.google.com/go/kms v1.22.0/go.mod h1:U7mf8Sva5jpOb4bxYZdtw/9zsbIjrklYwPcvMk34AL8=
|
||||
cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE=
|
||||
cloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY=
|
||||
dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
|
||||
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
|
||||
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
|
||||
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
|
||||
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
|
||||
@@ -31,8 +30,11 @@ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGy
|
||||
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M=
|
||||
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
||||
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/KimMachineGun/automemlimit v0.7.2 h1:DyfHI7zLWmZPn2Wqdy2AgTiUvrGPmnYWgwhHXtAegX4=
|
||||
github.com/KimMachineGun/automemlimit v0.7.2/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM=
|
||||
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4=
|
||||
@@ -42,10 +44,10 @@ github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSC
|
||||
github.com/MauriceGit/skiplist v0.0.0-20191117202105-643e379adb62/go.mod h1:877WBceefKn14QwVVn4xRFUsHsZb9clICgdeTj4XsUg=
|
||||
github.com/MauriceGit/skiplist v0.0.0-20211105230623-77f5c8d3e145 h1:1yw6O62BReQ+uA1oyk9XaQTvLhcoHWmoQAgXmDFXpIY=
|
||||
github.com/MauriceGit/skiplist v0.0.0-20211105230623-77f5c8d3e145/go.mod h1:877WBceefKn14QwVVn4xRFUsHsZb9clICgdeTj4XsUg=
|
||||
github.com/MicahParks/jwkset v0.8.0 h1:jHtclI38Gibmu17XMI6+6/UB59srp58pQVxePHRK5o8=
|
||||
github.com/MicahParks/jwkset v0.8.0/go.mod h1:fVrj6TmG1aKlJEeceAz7JsXGTXEn72zP1px3us53JrA=
|
||||
github.com/MicahParks/keyfunc/v3 v3.3.10 h1:JtEGE8OcNeI297AMrR4gVXivV8fyAawFUMkbwNreJRk=
|
||||
github.com/MicahParks/keyfunc/v3 v3.3.10/go.mod h1:1TEt+Q3FO7Yz2zWeYO//fMxZMOiar808NqjWQQpBPtU=
|
||||
github.com/MicahParks/jwkset v0.9.6 h1:Tf8l2/MOby5Kh3IkrqzThPQKfLytMERoAsGZKlyYZxg=
|
||||
github.com/MicahParks/jwkset v0.9.6/go.mod h1:U2oRhRaLgDCLjtpGL2GseNKGmZtLs/3O7p+OZaL5vo0=
|
||||
github.com/MicahParks/keyfunc/v3 v3.4.0 h1:g03TXq6NjhZyO/UkODl//abm4KiLLNRi0VhW7vGOHyg=
|
||||
github.com/MicahParks/keyfunc/v3 v3.4.0/go.mod h1:y6Ed3dMgNKTcpxbaQHD8mmrYDUZWJAxteddA6OQj+ag=
|
||||
github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
@@ -57,8 +59,8 @@ github.com/RoaringBitmap/roaring v1.9.4/go.mod h1:6AXUsoIEzDTFFQCe1RbGA6uFONMhve
|
||||
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
|
||||
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
||||
github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs=
|
||||
github.com/alecthomas/chroma/v2 v2.15.0 h1:LxXTQHFoYrstG2nnV9y2X5O94sOBzf0CIUpSTbpxvMc=
|
||||
github.com/alecthomas/chroma/v2 v2.15.0/go.mod h1:gUhVLrPDXPtp/f+L1jo9xepo9gL4eLwRuGAunSZMkio=
|
||||
github.com/alecthomas/chroma/v2 v2.18.0 h1:6h53Q4hW83SuF+jcsp7CVhLsMozzvQvO8HBbKQW+gn4=
|
||||
github.com/alecthomas/chroma/v2 v2.18.0/go.mod h1:RVX6AvYm4VfYe/zsk7mjHueLDZor3aWCNE14TFlepBk=
|
||||
github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
|
||||
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
|
||||
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||
@@ -68,49 +70,51 @@ github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmO
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b h1:uUXgbcPDK3KpW29o4iy7GtuappbWT0l5NaMo9H9pJDw=
|
||||
github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
|
||||
github.com/aws/aws-sdk-go-v2 v1.32.8 h1:cZV+NUS/eGxKXMtmyhtYPJ7Z4YLoI/V8bkTdRZfYhGo=
|
||||
github.com/aws/aws-sdk-go-v2 v1.32.8/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.28.10 h1:fKODZHfqQu06pCzR69KJ3GuttraRJkhlC8g80RZ0Dfg=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.28.10/go.mod h1:PvdxRYZ5Um9QMq9PQ0zHHNdtKK+he2NHtFCUFMXWXeg=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.51 h1:F/9Sm6Y6k4LqDesZDPJCLxQGXNNHd/ZtJiWd0lCZKRk=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.51/go.mod h1:TKbzCHm43AoPyA+iLGGcruXd4AFhF8tOmLex2R9jWNQ=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.23 h1:IBAoD/1d8A8/1aA8g4MBVtTRHhXRiNAgwdbo/xRM2DI=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.23/go.mod h1:vfENuCM7dofkgKpYzuzf1VT1UKkA/YL3qanfBn7HCaA=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.27 h1:jSJjSBzw8VDIbWv+mmvBSP8ezsztMYJGH+eKqi9AmNs=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.27/go.mod h1:/DAhLbFRgwhmvJdOfSm+WwikZrCuUJiA4WgJG0fTNSw=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.27 h1:l+X4K77Dui85pIj5foXDhPlnqcNRG2QUyvca300lXh8=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.27/go.mod h1:KvZXSFEXm6x84yE8qffKvT3x8J5clWnVFXphpohhzJ8=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 h1:iXtILhvDxB6kPvEXgsDhGaZCSC6LQET5ZHSdJozeI0Y=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1/go.mod h1:9nu0fVANtYiAePIBh2/pFUSwtJ402hLnp854CNoDOeE=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.8 h1:cWno7lefSH6Pp+mSznagKCgfDGeZRin66UvYUqAkyeA=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.8/go.mod h1:tPD+VjU3ABTBoEJ3nctu5Nyg4P4yjqSH5bJGGkY4+XE=
|
||||
github.com/aws/aws-sdk-go-v2/service/kms v1.37.8 h1:KbLZjYqhQ9hyB4HwXiheiflTlYQa0+Fz0Ms/rh5f3mk=
|
||||
github.com/aws/aws-sdk-go-v2/service/kms v1.37.8/go.mod h1:ANs9kBhK4Ghj9z1W+bsr3WsNaPF71qkgd6eE6Ekol/Y=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.24.9 h1:YqtxripbjWb2QLyzRK9pByfEDvgg95gpC2AyDq4hFE8=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.24.9/go.mod h1:lV8iQpg6OLOfBnqbGMBKYjilBlf633qwHnBEiMSPoHY=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.8 h1:6dBT1Lz8fK11m22R+AqfRsFn8320K0T5DTGxxOQBSMw=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.8/go.mod h1:/kiBvRQXBc6xeJTYzhSdGvJ5vm1tjaDEjH+MSeRJnlY=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.6 h1:VwhTrsTuVn52an4mXx29PqRzs2Dvu921NpGk7y43tAM=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.6/go.mod h1:+8h7PZb3yY5ftmVLD7ocEoE98hdc8PoKS0H3wfx1dlc=
|
||||
github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro=
|
||||
github.com/aws/smithy-go v1.22.1/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM=
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.14 h1:f+eEi/2cKCg9pqKBoAIwRGzVb70MRKqWX4dg1BDcSJM=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.14/go.mod h1:wVPHWcIFv3WO89w0rE10gzf17ZYy+UVS1Geq8Iei34g=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.67 h1:9KxtdcIA/5xPNQyZRgUSpYOE6j9Bc4+D7nZua0KGYOM=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.67/go.mod h1:p3C44m+cfnbv763s52gCqrjaqyPikj9Sg47kUVaNZQQ=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 h1:x793wxmUWVDhshP8WW2mlnXuFrO4cOd3HLBroh1paFw=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30/go.mod h1:Jpne2tDnYiFascUEs2AWHJL9Yp7A5ZVy3TNyxaAjD6M=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34/go.mod h1:p4VfIceZokChbA9FzMbRGz5OV+lekcVtHlPKEO0gSZY=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0ioo/gq8Mn6u9w19Mri8DnJ15Jf0=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 h1:dM9/92u2F1JbDaGooxTq18wmmFzbJRfXfVfy96/1CXM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15/go.mod h1:SwFBy2vjtA0vZbjjaFtfN045boopadnoVPhu4Fv66vY=
|
||||
github.com/aws/aws-sdk-go-v2/service/kms v1.38.3 h1:RivOtUH3eEu6SWnUMFHKAW4MqDOzWn1vGQ3S38Y5QMg=
|
||||
github.com/aws/aws-sdk-go-v2/service/kms v1.38.3/go.mod h1:cQn6tAF77Di6m4huxovNM7NVAozWTZLsDRp9t8Z/WYk=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 h1:1Gw+9ajCV1jogloEv1RRnvfRFia2cL6c9cuKV2Ps+G8=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.3/go.mod h1:qs4a9T5EMLl/Cajiw2TcbNt2UNo/Hqlyp+GiuG4CFDI=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 h1:hXmVKytPfTy5axZ+fYbR5d0cFmC3JvwLm5kM83luako=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1/go.mod h1:MlYRNmYu/fGPoxBQVvBYr9nyr948aY/WLUvwBMBJubs=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.19 h1:1XuUZ8mYJw9B6lzAkXhqHlJd/XvaX32evhproijJEZY=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.19/go.mod h1:cQnB8CUnxbMU82JvlqjKR2HBOm3fe9pWorWBza6MBJ4=
|
||||
github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ=
|
||||
github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
|
||||
github.com/bits-and-blooms/bitset v1.12.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/bits-and-blooms/bitset v1.20.0 h1:2F+rfL86jE2d/bmw7OhqUg2Sj/1rURkBn3MdfoPyRVU=
|
||||
github.com/bits-and-blooms/bitset v1.20.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/bits-and-blooms/bitset v1.22.0 h1:Tquv9S8+SGaS3EhyA+up3FXzmkhxPGjQQCkcs2uw7w4=
|
||||
github.com/bits-and-blooms/bitset v1.22.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
||||
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
||||
github.com/caddyserver/caddy/v2 v2.9.1 h1:OEYiZ7DbCzAWVb6TNEkjRcSCRGHVoZsJinoDR/n9oaY=
|
||||
github.com/caddyserver/caddy/v2 v2.9.1/go.mod h1:ImUELya2el1FDVp3ahnSO2iH1or1aHxlQEQxd/spP68=
|
||||
github.com/caddyserver/certmagic v0.21.7 h1:66KJioPFJwttL43KYSWk7ErSmE6LfaJgCQuhm8Sg6fg=
|
||||
github.com/caddyserver/certmagic v0.21.7/go.mod h1:LCPG3WLxcnjVKl/xpjzM0gqh0knrKKKiO5WVttX2eEI=
|
||||
github.com/caddyserver/caddy/v2 v2.10.0 h1:fonubSaQKF1YANl8TXqGcn4IbIRUDdfAkpcsfI/vX5U=
|
||||
github.com/caddyserver/caddy/v2 v2.10.0/go.mod h1:q+dgBS3xtIJJGYI2H5Nyh9+4BvhQQ9yCGmECv4Ubdjo=
|
||||
github.com/caddyserver/certmagic v0.23.0 h1:CfpZ/50jMfG4+1J/u2LV6piJq4HOfO6ppOnOf7DkFEU=
|
||||
github.com/caddyserver/certmagic v0.23.0/go.mod h1:9mEZIWqqWoI+Gf+4Trh04MOVPD0tGSxtqsxg87hAIH4=
|
||||
github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA=
|
||||
github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4=
|
||||
github.com/ccoveille/go-safecast v1.6.1 h1:Nb9WMDR8PqhnKCVs2sCB+OqhohwO5qaXtCviZkIff5Q=
|
||||
github.com/ccoveille/go-safecast v1.6.1/go.mod h1:QqwNjxQ7DAqY0C721OIO9InMk9zCwcsO7tnRuHytad8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
@@ -127,17 +131,19 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
|
||||
github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04=
|
||||
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
||||
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||
github.com/coreos/go-oidc/v3 v3.12.0 h1:sJk+8G2qq94rDI6ehZ71Bol3oUHy63qNYmkiSjrc/Jo=
|
||||
github.com/coreos/go-oidc/v3 v3.12.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0=
|
||||
github.com/coreos/go-oidc/v3 v3.14.1 h1:9ePWwfdwC4QKRlCXsJGou56adA/owXczOzwKdOumLqk=
|
||||
github.com/coreos/go-oidc/v3 v3.14.1/go.mod h1:HaZ3szPaZ0e4r6ebqvsLWlk2Tn+aejfmrfah6hnSYEU=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
@@ -155,22 +161,23 @@ github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da h1:aIftn67I1fkbMa5
|
||||
github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||
github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
|
||||
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
|
||||
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/dolthub/maphash v0.1.0 h1:bsQ7JsF4FkkWyrP3oCnFJgrCUAFbFf3kOl4L/QxPDyQ=
|
||||
github.com/dolthub/maphash v0.1.0/go.mod h1:gkg4Ch4CdCDu5h6PMriVLawB7koZ+5ijb9puGMV50a4=
|
||||
github.com/dunglas/caddy-cbrotli v1.0.0 h1:+WNqXBkWyMcIpXB2rVZ3nwcElUbuAzf0kPxNXU4D+u0=
|
||||
github.com/dunglas/caddy-cbrotli v1.0.0/go.mod h1:KZsUu3fnQBgO0o3YDoQuO3Z61dFgUncr1F8rg8acwQw=
|
||||
github.com/dunglas/httpsfv v1.0.2 h1:iERDp/YAfnojSDJ7PW3dj1AReJz4MrwbECSSE59JWL0=
|
||||
github.com/dunglas/httpsfv v1.0.2/go.mod h1:zID2mqw9mFsnt7YC3vYQ9/cjq30q41W+1AnDwH8TiMg=
|
||||
github.com/dunglas/mercure v0.18.2 h1:WknM1Ags4wwcD6t6D2hjAQhdKte43SLQAKCVX8Cxc3w=
|
||||
github.com/dunglas/mercure v0.18.2/go.mod h1:4f0YfFbnggYNEoJmCpjzxx6LeybiZlf8smBYOBOCsH4=
|
||||
github.com/dunglas/mercure/caddy v0.18.2 h1:k7IqRL/kAkOveBBcwC6OC35dmwuOMDk4pNkcKz8gXdc=
|
||||
github.com/dunglas/mercure/caddy v0.18.2/go.mod h1:vLAxBRWSxlPgvrEK3Q7rswvHQFvlxbKEsVOoedAymSs=
|
||||
github.com/dunglas/vulcain v1.1.1 h1:nWh6sEhaeSla3IVXpzxQ8tK1nEr4lM1Q/HW8EVdpIgU=
|
||||
github.com/dunglas/vulcain v1.1.1/go.mod h1:5YslB+KQI6SbghCDB3zrDyGtS2WCLvu+oFBkHi6mo+w=
|
||||
github.com/dunglas/vulcain/caddy v1.1.1 h1:TT90lkiqnF1rGEyWXwZwhnuTRInNmYgJsFzR9ZH8pbQ=
|
||||
github.com/dunglas/vulcain/caddy v1.1.1/go.mod h1:6aXBrXh46qlJv9rIBlX5DlxzmRPJyVWpnFp8JMkpBNI=
|
||||
github.com/dunglas/frankenphp v1.7.0/go.mod h1:BaPr7WO5PmAkMtJvRUhRcmdWNAuEIK1zWLC++c8GhE0=
|
||||
github.com/dunglas/httpsfv v1.1.0 h1:Jw76nAyKWKZKFrpMMcL76y35tOpYHqQPzHQiwDvpe54=
|
||||
github.com/dunglas/httpsfv v1.1.0/go.mod h1:zID2mqw9mFsnt7YC3vYQ9/cjq30q41W+1AnDwH8TiMg=
|
||||
github.com/dunglas/mercure v0.19.2 h1:eBMQhxvzJTenIffL+jlqtWO+TPevCjOQ+DQJb8iB6+s=
|
||||
github.com/dunglas/mercure v0.19.2/go.mod h1:/8edy/qugBTM4CbEzX4DwykEIh1VWHWlo1e/pHos120=
|
||||
github.com/dunglas/mercure/caddy v0.19.2 h1:Ug/nALeSn7DH4qMy7I2pImCf1D0H+0vr6K4AWjgmOKg=
|
||||
github.com/dunglas/mercure/caddy v0.19.2/go.mod h1:Kq+qvO79l8odqokiNcdKbH53aOLurarse8xZ42ALzJQ=
|
||||
github.com/dunglas/vulcain v1.2.0 h1:RPNYuTe0woh4bGfIMAJ3dCgJDN8VJwhDjucQiCOoUsE=
|
||||
github.com/dunglas/vulcain v1.2.0/go.mod h1:LhyYeqSAEw9P65l25CIzS1sRwJxkP75Qa7p8lIHZPsc=
|
||||
github.com/dunglas/vulcain/caddy v1.2.0 h1:2O2R7Hn+kkInv6mrmOk5LLDtgRdPKGlXzdFJUKrb/jE=
|
||||
github.com/dunglas/vulcain/caddy v1.2.0/go.mod h1:RAbiewGNIyWCmT37C2k4O1hs4IF+QIGVVgSNQuW2FH4=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
@@ -182,43 +189,45 @@ github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiD
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
||||
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU=
|
||||
github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
||||
github.com/gammazero/deque v1.0.0 h1:LTmimT8H7bXkkCy6gZX7zNLtkbz4NdS2z8LZuor3j34=
|
||||
github.com/gammazero/deque v1.0.0/go.mod h1:iflpYvtGfM3U8S8j+sZEKIak3SAKYpA5/SQewgfXDKo=
|
||||
github.com/getkin/kin-openapi v0.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4=
|
||||
github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM=
|
||||
github.com/getkin/kin-openapi v0.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk=
|
||||
github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/go-chi/chi/v5 v5.2.0 h1:Aj1EtB0qR2Rdo2dG4O94RIU35w2lvQSj6BRA4+qwFL0=
|
||||
github.com/go-chi/chi/v5 v5.2.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8=
|
||||
github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k=
|
||||
github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ=
|
||||
github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E=
|
||||
github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc=
|
||||
github.com/go-jose/go-jose/v3 v3.0.4 h1:Wp5HA7bLQcKnf6YYao/4kpRpVMp/yf6+pJKV8WFSaNY=
|
||||
github.com/go-jose/go-jose/v3 v3.0.4/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ=
|
||||
github.com/go-jose/go-jose/v4 v4.1.0 h1:cYSYxd3pw5zd2FSXk2vGdn9igQU2PS8MuxrCOCl0FdY=
|
||||
github.com/go-jose/go-jose/v4 v4.1.0/go.mod h1:GG/vqmYm3Von2nYiB2vGTXzdoNKE5tix5tuc6iAd+sw=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
||||
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
||||
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
||||
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
||||
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||
github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic=
|
||||
github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk=
|
||||
github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU=
|
||||
github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0=
|
||||
github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRjiHuU=
|
||||
github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
|
||||
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
|
||||
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
@@ -228,45 +237,46 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
|
||||
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/brotli/go/cbrotli v0.0.0-20241111155135-4303850b01d6 h1:ygfAzuHUP3wed0um8AamwtZIh022Ie5lnsWHhItj/sY=
|
||||
github.com/google/brotli/go/cbrotli v0.0.0-20241111155135-4303850b01d6/go.mod h1:nOPhAkwVliJdNTkj3gXpljmWhjc4wCaVqbMJcPKWP4s=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
github.com/google/cel-go v0.23.0 h1:knsnzeUOcREUFo0ZFJqZI8Rk6uEVyobAlir7GEbf5v0=
|
||||
github.com/google/cel-go v0.23.0/go.mod h1:52Pb6QsDbC5kvgxvZhiL9QX1oZEkcUF/ZqaPx1J5Wwo=
|
||||
github.com/google/cel-go v0.25.0 h1:jsFw9Fhn+3y2kBbltZR4VEz5xKkcIFRPDnuEzAGv5GY=
|
||||
github.com/google/cel-go v0.25.0/go.mod h1:hjEb6r5SuOSlhCHmFoLzu8HGCERvIsDAbxDAyNU/MmI=
|
||||
github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
|
||||
github.com/google/certificate-transparency-go v1.3.0 h1:+UhSNQAyA38Ed4CGfwOZeG4sJ030ELQZE4xtMFOxA7U=
|
||||
github.com/google/certificate-transparency-go v1.3.0/go.mod h1:/xVlT13jyrOuJOXTW5PjCBCrHBtXUq/jT5UeW40xliQ=
|
||||
github.com/google/certificate-transparency-go v1.3.1 h1:akbcTfQg0iZlANZLn0L9xOeWtyCIdeoYhKrqi5iH3Go=
|
||||
github.com/google/certificate-transparency-go v1.3.1/go.mod h1:gg+UQlx6caKEDQ9EElFOujyxEQEfOiQzAt6782Bvi8k=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/go-tpm v0.9.3 h1:+yx0/anQuGzi+ssRqeD6WpXjW2L/V0dItUayO0i9sRc=
|
||||
github.com/google/go-tpm v0.9.3/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
|
||||
github.com/google/go-tpm-tools v0.4.4 h1:oiQfAIkc6xTy9Fl5NKTeTJkBTlXdHsxAofmQyxBKY98=
|
||||
github.com/google/go-tpm-tools v0.4.4/go.mod h1:T8jXkp2s+eltnCDIsXR84/MTcVU9Ja7bh3Mit0pa4AY=
|
||||
github.com/google/go-tpm v0.9.5 h1:ocUmnDebX54dnW+MQWGQRbdaAcJELsa6PqZhJ48KwVU=
|
||||
github.com/google/go-tpm v0.9.5/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
|
||||
github.com/google/go-tpm-tools v0.4.5 h1:3fhthtyMDbIZFR5/0y1hvUoZ1Kf4i1eZ7C73R4Pvd+k=
|
||||
github.com/google/go-tpm-tools v0.4.5/go.mod h1:ktjTNq8yZFD6TzdBFefUfen96rF3NpYwpSb2d8bc+Y8=
|
||||
github.com/google/go-tspi v0.3.0 h1:ADtq8RKfP+jrTyIWIZDIYcKOMecRqNJFOew2IT0Inus=
|
||||
github.com/google/go-tspi v0.3.0/go.mod h1:xfMGI3G0PhxCdNVcYr1C4C+EizojDg/TXuX5by8CiHI=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20250125003558-7fdb3d7e6fa0 h1:my2ucqBZmv+cWHIhZNSIYKzgN8EBGyHdC7zD5sASRAg=
|
||||
github.com/google/pprof v0.0.0-20250125003558-7fdb3d7e6fa0/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM=
|
||||
github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA=
|
||||
github.com/google/pprof v0.0.0-20250602020802-c6617b811d0e h1:FJta/0WsADCe1r9vQjdHbd3KuiLPu7Y9WlyLGwMUNyE=
|
||||
github.com/google/pprof v0.0.0-20250602020802-c6617b811d0e/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
|
||||
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
|
||||
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
|
||||
github.com/googleapis/gax-go v2.0.0+incompatible h1:j0GKcs05QVmm7yesiZq2+9cxHkNK9YM6zKx4D2qucQU=
|
||||
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
|
||||
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
|
||||
github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q=
|
||||
github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA=
|
||||
github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0=
|
||||
github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE=
|
||||
github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w=
|
||||
@@ -274,12 +284,11 @@ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
|
||||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
|
||||
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
|
||||
@@ -288,14 +297,12 @@ github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso=
|
||||
github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI=
|
||||
github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ=
|
||||
github.com/jackc/pgx/v5 v5.7.5 h1:JHGfMnQY+IEtGM63d+NGMjoRpysB2JBwDr5fsngwmJs=
|
||||
github.com/jackc/pgx/v5 v5.7.5/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
|
||||
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
||||
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
|
||||
@@ -308,10 +315,10 @@ github.com/kevburnsjr/skipfilter v0.0.1 h1:EWl1lWUJfIehrKYIEkps0Cl67lCfS2pUM9iZF
|
||||
github.com/kevburnsjr/skipfilter v0.0.1/go.mod h1:jfaRyFOYVUtIa6IIC+0mB1qiZqhHw+DKvFowCBuijSk=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
|
||||
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
@@ -323,12 +330,10 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s=
|
||||
github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
|
||||
github.com/libdns/libdns v1.1.0 h1:9ze/tWvt7Df6sbhOJRB8jT33GHEHpEQXdtkE3hPthbU=
|
||||
github.com/libdns/libdns v1.1.0/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
|
||||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM=
|
||||
github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
|
||||
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
|
||||
@@ -343,19 +348,17 @@ github.com/maypok86/otter v1.2.4 h1:HhW1Pq6VdJkmWwcZZq19BlEQkHtI8xgsQzBVXJU0nfc=
|
||||
github.com/maypok86/otter v1.2.4/go.mod h1:mKLfoI7v1HOmQMwFgX4QkRk23mX6ge3RDvjdHOWG4R4=
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/mholt/acmez/v3 v3.0.1 h1:4PcjKjaySlgXK857aTfDuRbmnM5gb3Ruz3tvoSJAUp8=
|
||||
github.com/mholt/acmez/v3 v3.0.1/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ=
|
||||
github.com/mholt/acmez/v3 v3.1.2 h1:auob8J/0FhmdClQicvJvuDavgd5ezwLBfKuYmynhYzc=
|
||||
github.com/mholt/acmez/v3 v3.1.2/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ=
|
||||
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
||||
github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY=
|
||||
github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs=
|
||||
github.com/miekg/dns v1.1.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE=
|
||||
github.com/miekg/dns v1.1.66/go.mod h1:jGFzBsSNbJw6z1HYut1RKBKHA9PBdxeHrZG8J+gC2WE=
|
||||
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
||||
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
|
||||
github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
||||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
@@ -368,20 +371,26 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
||||
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
|
||||
github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU=
|
||||
github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk=
|
||||
github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
|
||||
github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
|
||||
github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY=
|
||||
github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw=
|
||||
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c=
|
||||
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o=
|
||||
github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus=
|
||||
github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8=
|
||||
github.com/onsi/gomega v1.36.3 h1:hID7cr8t3Wp26+cYnfcjR6HpJ00fdogN6dqZ1t6IylU=
|
||||
github.com/onsi/gomega v1.36.3/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
|
||||
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||
github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s=
|
||||
github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
|
||||
github.com/peterbourgon/diskv/v3 v3.0.1 h1:x06SQA46+PKIUftmEujdwSEpIx8kR+M9eLYsUxeYveU=
|
||||
github.com/peterbourgon/diskv/v3 v3.0.1/go.mod h1:kJ5Ny7vLdARGU3WUuy6uzO6T0nb/2gWcT1JiBvRmb5o=
|
||||
github.com/pires/go-proxyproto v0.8.0 h1:5unRmEAPbHXHuLjDg01CxJWf91cw3lKHc/0xzKpXEe0=
|
||||
github.com/pires/go-proxyproto v0.8.0/go.mod h1:iknsfgnH8EkjrMeMyvfKByp9TiBZCKZM0jx2xmKqnVY=
|
||||
github.com/pires/go-proxyproto v0.8.1 h1:9KEixbdJfhrbtjpz/ZwCdWDD2Xem0NZ38qMYaASJgp0=
|
||||
github.com/pires/go-proxyproto v0.8.1/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
@@ -391,21 +400,21 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH
|
||||
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
|
||||
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
|
||||
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
|
||||
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
|
||||
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
|
||||
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
||||
github.com/prometheus/common v0.64.0 h1:pdZeA+g617P7oGv1CzdTzyeShxAGrTBsolKNOLQPGO4=
|
||||
github.com/prometheus/common v0.64.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
|
||||
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
|
||||
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
|
||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||
github.com/quic-go/quic-go v0.49.0 h1:w5iJHXwHxs1QxyBv1EHKuC50GX5to8mJAxvtnttJp94=
|
||||
github.com/quic-go/quic-go v0.49.0/go.mod h1:s2wDnmCdooUQBmQfpUSTCYBl1/D4FcqbULMMkASvR6s=
|
||||
github.com/quic-go/quic-go v0.52.0 h1:/SlHrCRElyaU6MaEPKqKr9z83sBg2v4FLLvWM+Z47pA=
|
||||
github.com/quic-go/quic-go v0.52.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
|
||||
@@ -413,10 +422,8 @@ github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo=
|
||||
github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||
github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFTqyMTC9k=
|
||||
github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk=
|
||||
github.com/schollz/jsonstore v1.1.0 h1:WZBDjgezFS34CHI+myb4s8GGpir3UMpy7vWoCeO0n6E=
|
||||
github.com/schollz/jsonstore v1.1.0/go.mod h1:15c6+9guw8vDRyozGjN3FoILt0wpruJk9Pi66vjaZfg=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
@@ -449,22 +456,24 @@ github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5k
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/slackhq/nebula v1.9.4 h1:p06JxtXT/OBMWt2OQkY7F0phOBb42X93YWNsS1yqC9o=
|
||||
github.com/slackhq/nebula v1.9.4/go.mod h1:1+4q4wd3dDAjO8rKCttSb9JIVbklQhuJiBp5I0lbIsQ=
|
||||
github.com/slackhq/nebula v1.9.5 h1:ZrxcvP/lxwFglaijmiwXLuCSkybZMJnqSYI1S8DtGnY=
|
||||
github.com/slackhq/nebula v1.9.5/go.mod h1:1+4q4wd3dDAjO8rKCttSb9JIVbklQhuJiBp5I0lbIsQ=
|
||||
github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY=
|
||||
github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc=
|
||||
github.com/smallstep/certificates v0.28.1 h1:hLYz1It9mecJD0DqQ+qLldQnTUkanFIztuyqmxKRZkY=
|
||||
github.com/smallstep/certificates v0.28.1/go.mod h1:/xlSParPTewKBdhyp/vHcoOmtwK8AbPiXdmbu6c4J3A=
|
||||
github.com/smallstep/cli-utils v0.10.0 h1:CfXNvHtIN5pAzGvGP0NEUZoGFcj5epNEB6RSpSfduek=
|
||||
github.com/smallstep/cli-utils v0.10.0/go.mod h1:jIeNa5ctrVg89lU5TaQKYd6o1eFxi9mtZu1sXSxpEBg=
|
||||
github.com/smallstep/go-attestation v0.4.4-0.20240109183208-413678f90935 h1:kjYvkvS/Wdy0PVRDUAA0gGJIVSEZYhiAJtfwYgOYoGA=
|
||||
github.com/smallstep/go-attestation v0.4.4-0.20240109183208-413678f90935/go.mod h1:vNAduivU014fubg6ewygkAvQC0IQVXqdc8vaGl/0er4=
|
||||
github.com/smallstep/certificates v0.28.3 h1:rcMh1TAs8m2emP3aDJxKLkE9jriAtcFtCuj2gttnpmI=
|
||||
github.com/smallstep/certificates v0.28.3/go.mod h1:P/IjGTvRCem3YZ7d1XtUxpvK/8dfFsJn7gaVLpMXbJw=
|
||||
github.com/smallstep/cli-utils v0.12.1 h1:D9QvfbFqiKq3snGZ2xDcXEFrdFJ1mQfPHZMq/leerpE=
|
||||
github.com/smallstep/cli-utils v0.12.1/go.mod h1:skV2Neg8qjiKPu2fphM89H9bIxNpKiiRTnX9Q6Lc+20=
|
||||
github.com/smallstep/go-attestation v0.4.4-0.20241119153605-2306d5b464ca h1:VX8L0r8vybH0bPeaIxh4NQzafKQiqvlOn8pmOXbFLO4=
|
||||
github.com/smallstep/go-attestation v0.4.4-0.20241119153605-2306d5b464ca/go.mod h1:vNAduivU014fubg6ewygkAvQC0IQVXqdc8vaGl/0er4=
|
||||
github.com/smallstep/linkedca v0.23.0 h1:5W/7EudlK1HcCIdZM68dJlZ7orqCCCyv6bm2l/0JmLU=
|
||||
github.com/smallstep/linkedca v0.23.0/go.mod h1:7cyRM9soAYySg9ag65QwytcgGOM+4gOlkJ/YA58A9E8=
|
||||
github.com/smallstep/nosql v0.7.0 h1:YiWC9ZAHcrLCrayfaF+QJUv16I2bZ7KdLC3RpJcnAnE=
|
||||
github.com/smallstep/nosql v0.7.0/go.mod h1:H5VnKMCbeq9QA6SRY5iqPylfxLfYcLwvUff3onQ8+HU=
|
||||
github.com/smallstep/pkcs7 v0.1.1 h1:x+rPdt2W088V9Vkjho4KtoggyktZJlMduZAtRHm68LU=
|
||||
github.com/smallstep/pkcs7 v0.1.1/go.mod h1:dL6j5AIz9GHjVEBTXtW+QliALcgM19RtXaTeyxI+AfA=
|
||||
github.com/smallstep/scep v0.0.0-20241223071629-a37a330173bc h1:gJ1mkz/iJhKnKUJit5DCFxNRWo9mxIkVm9SI8DiUugI=
|
||||
github.com/smallstep/scep v0.0.0-20241223071629-a37a330173bc/go.mod h1:bENyEPpujhqigQx115AitJTc11LZmGUNk0ftgyhcNus=
|
||||
github.com/smallstep/pkcs7 v0.2.1 h1:6Kfzr/QizdIuB6LSv8y1LJdZ3aPSfTNhTLqAx9CTLfA=
|
||||
github.com/smallstep/pkcs7 v0.2.1/go.mod h1:RcXHsMfL+BzH8tRhmrF1NkkpebKpq3JEM66cOFxanf0=
|
||||
github.com/smallstep/scep v0.0.0-20250318231241-a25cabb69492 h1:k23+s51sgYix4Zgbvpmy+1ZgXLjr4ZTkBTqXmpnImwA=
|
||||
github.com/smallstep/scep v0.0.0-20250318231241-a25cabb69492/go.mod h1:QQhwLqCS13nhv8L5ov7NgusowENUtXdEzdytjmJHdZQ=
|
||||
github.com/smallstep/truststore v0.13.0 h1:90if9htAOblavbMeWlqNLnO9bsjjgVv2hQeQJCi/py4=
|
||||
github.com/smallstep/truststore v0.13.0/go.mod h1:3tmMp2aLKZ/OA/jnFUB0cYPcho402UG2knuJoPh4j7A=
|
||||
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
|
||||
@@ -475,21 +484,21 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO
|
||||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs=
|
||||
github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4=
|
||||
github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA=
|
||||
github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
|
||||
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/cast v1.9.2 h1:SsGfm7M8QOFtEzumm7UZrZdLLquNdzFYfIbEXntcFbE=
|
||||
github.com/spf13/cast v1.9.2/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
||||
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
|
||||
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
|
||||
github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4=
|
||||
github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4=
|
||||
github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs=
|
||||
github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
@@ -538,8 +547,8 @@ github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zI
|
||||
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yuin/goldmark v1.4.15/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic=
|
||||
github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||
github.com/yuin/goldmark v1.7.12 h1:YwGP/rrea2/CnCtUHgjuolG/PnMxdQtPMO5PvaE2/nY=
|
||||
github.com/yuin/goldmark v1.7.12/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
|
||||
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ=
|
||||
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I=
|
||||
github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=
|
||||
@@ -548,51 +557,49 @@ github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI=
|
||||
github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE=
|
||||
github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
|
||||
github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
|
||||
go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0=
|
||||
go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I=
|
||||
go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk=
|
||||
go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk=
|
||||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 h1:yd02MEjBdJkG3uabWP9apV+OuWRIXGDuJEUJbOHmCFU=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q=
|
||||
go.opentelemetry.io/contrib/propagators/autoprop v0.58.0 h1:pL1MMoBcG/ol6fVsjE1bbOO9A8GMQiN+T73hnmaXDoU=
|
||||
go.opentelemetry.io/contrib/propagators/autoprop v0.58.0/go.mod h1:EU5uMoCqafsagp4hzFqzu1Eyg/8L23JS5Y1hChoHf7s=
|
||||
go.opentelemetry.io/contrib/propagators/aws v1.33.0 h1:MefPfPIut0IxEiQRK1qVv5AFADBOwizl189+m7QhpFg=
|
||||
go.opentelemetry.io/contrib/propagators/aws v1.33.0/go.mod h1:VB6xPo12uW/PezOqtA/cY2/DiAGYshnhID606wC9NEY=
|
||||
go.opentelemetry.io/contrib/propagators/b3 v1.33.0 h1:ig/IsHyyoQ1F1d6FUDIIW5oYpsuTVtN16AyGOgdjAHQ=
|
||||
go.opentelemetry.io/contrib/propagators/b3 v1.33.0/go.mod h1:EsVYoNy+Eol5znb6wwN3XQTILyjl040gUpEnUSNZfsk=
|
||||
go.opentelemetry.io/contrib/propagators/jaeger v1.33.0 h1:Jok/dG8kfp+yod29XKYV/blWgYPlMuRUoRHljrXMF5E=
|
||||
go.opentelemetry.io/contrib/propagators/jaeger v1.33.0/go.mod h1:ku/EpGk44S5lyVMbtJRK2KFOnXEehxf6SDnhu1eZmjA=
|
||||
go.opentelemetry.io/contrib/propagators/ot v1.33.0 h1:xj/pQFKo4ROsx0v129KpLgFwaYMgFTu3dAMEEih97cY=
|
||||
go.opentelemetry.io/contrib/propagators/ot v1.33.0/go.mod h1:/xxHCLhTmaypEFwMViRGROj2qgrGiFrkxIlATt0rddc=
|
||||
go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw=
|
||||
go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0 h1:Vh5HayB/0HHfOQA7Ctx69E/Y/DcQSMPpKANYVMQ7fBA=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0/go.mod h1:cpgtDBaqD/6ok/UG0jT15/uKjAY8mRA53diogHBg3UI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 h1:5pojmb1U1AogINhN3SurB+zm/nIcusopeBNp42f45QM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0/go.mod h1:57gTHJSE5S1tqg+EKsLPlTWhpHMsWlVmer+LA926XiA=
|
||||
go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ=
|
||||
go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M=
|
||||
go.opentelemetry.io/otel/sdk v1.33.0 h1:iax7M131HuAm9QkZotNHEfstof92xM+N8sr3uHXc2IM=
|
||||
go.opentelemetry.io/otel/sdk v1.33.0/go.mod h1:A1Q5oi7/9XaMlIWzPSxLRWOI8nG3FnzHJNbiENQuihM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ=
|
||||
go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s=
|
||||
go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck=
|
||||
go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg=
|
||||
go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY=
|
||||
go.step.sm/crypto v0.57.0 h1:YjoRQDaJYAxHLVwjst0Bl0xcnoKzVwuHCJtEo2VSHYU=
|
||||
go.step.sm/crypto v0.57.0/go.mod h1:+Lwp5gOVPaTa3H/Ul/TzGbxQPXZZcKIUGMS0lG6n9Go=
|
||||
go.step.sm/linkedca v0.22.2 h1:zmFIyDC77gFHo6FLQJ8OIXYpLYDIsgDWaYqtYs6A9/Q=
|
||||
go.step.sm/linkedca v0.22.2/go.mod h1:ESY8r5VfhJA8ZVzI6hXIQcEX9LwaY3aoPnT+Hb9jpbw=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
|
||||
go.opentelemetry.io/contrib/propagators/autoprop v0.60.0 h1:sevByeAWTtfBdJQT7nkJfK5wOCjNpmDMZGPEBx3l1RA=
|
||||
go.opentelemetry.io/contrib/propagators/autoprop v0.60.0/go.mod h1:uEhyRPnUTSeUwMjDdrMQnsJ0sQ2mf/fA94hfchemm4A=
|
||||
go.opentelemetry.io/contrib/propagators/aws v1.35.0 h1:xoXA+5dVwsf5uE5GvSJ3lKiapyMFuIzbEmJwQ0JP+QU=
|
||||
go.opentelemetry.io/contrib/propagators/aws v1.35.0/go.mod h1:s11Orts/IzEgw9Srw5iRXtk2kM2j3jt/45noUWyf60E=
|
||||
go.opentelemetry.io/contrib/propagators/b3 v1.35.0 h1:DpwKW04LkdFRFCIgM3sqwTJA/QREHMeMHYPWP1WeaPQ=
|
||||
go.opentelemetry.io/contrib/propagators/b3 v1.35.0/go.mod h1:9+SNxwqvCWo1qQwUpACBY5YKNVxFJn5mlbXg/4+uKBg=
|
||||
go.opentelemetry.io/contrib/propagators/jaeger v1.35.0 h1:UIrZgRBHUrYRlJ4V419lVb4rs2ar0wFzKNAebaP05XU=
|
||||
go.opentelemetry.io/contrib/propagators/jaeger v1.35.0/go.mod h1:0ciyFyYZxE6JqRAQvIgGRabKWDUmNdW3GAQb6y/RlFU=
|
||||
go.opentelemetry.io/contrib/propagators/ot v1.35.0 h1:ZsgYijVvOpju4mq3g4QyqCwLKs2vKenlCpZHbKu50OA=
|
||||
go.opentelemetry.io/contrib/propagators/ot v1.35.0/go.mod h1:t1ZwtgjEtDH9uW6OlCRVLL2wOgsTJmp0pJwNouUq+HE=
|
||||
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
|
||||
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 h1:m639+BofXTvcY1q8CGs4ItwQarYtJPOWmVobfM1HpVI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0/go.mod h1:LjReUci/F4BUyv+y4dwnq3h/26iNOeC3wAIqgvTIZVo=
|
||||
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
|
||||
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
|
||||
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
|
||||
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
|
||||
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
|
||||
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
|
||||
go.opentelemetry.io/proto/otlp v1.6.0 h1:jQjP+AQyTf+Fe7OKj/MfkDrmK4MNVtw2NpXsf9fefDI=
|
||||
go.opentelemetry.io/proto/otlp v1.6.0/go.mod h1:cicgGehlFuNdgZkcALOCh3VE6K/u2tAjzlRhDwmVpZc=
|
||||
go.step.sm/crypto v0.66.0 h1:9TW6BEguOtcS9NIjja9bDQ+j8OjhenU/F6lJfHjbXNU=
|
||||
go.step.sm/crypto v0.66.0/go.mod h1:anqGyvO/Px05D1mznHq4/a9wwP1I1DmMZvk+TWX5Dzo=
|
||||
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
|
||||
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
|
||||
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
||||
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
||||
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
@@ -609,14 +616,14 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/crypto/x509roots/fallback v0.0.0-20250118192723-a8ea4be81f07 h1:Tuk3hxOkRoX4Xwph6/tRU1wGumEsVYM2TZfvAC6MllM=
|
||||
golang.org/x/crypto/x509roots/fallback v0.0.0-20250118192723-a8ea4be81f07/go.mod h1:kNa9WdvYnzFwC79zRpLRMJbdEFlhyM5RPFBBZp/wWH8=
|
||||
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
|
||||
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
|
||||
golang.org/x/crypto/x509roots/fallback v0.0.0-20250531095911-4f9f0ca9fcfb h1:Qr7HsIdEUI8QBvEohd2cTYzTErkEkUXafR9qx9D6QEo=
|
||||
golang.org/x/crypto/x509roots/fallback v0.0.0-20250531095911-4f9f0ca9fcfb/go.mod h1:lxN5T34bK4Z/i6cMaU7frUU57VkDXFD4Kamfl/cp9oU=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA=
|
||||
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
|
||||
golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b h1:QoALfVG9rhQ/M7vYDScfPdWjGL9dlsVVM5VGh7aKoAA=
|
||||
golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ=
|
||||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
@@ -625,8 +632,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
|
||||
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -643,14 +650,14 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
||||
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70=
|
||||
golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -662,8 +669,9 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
||||
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -685,9 +693,9 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -696,9 +704,9 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
|
||||
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
|
||||
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
@@ -708,12 +716,13 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
||||
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
|
||||
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
||||
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@@ -724,14 +733,14 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE=
|
||||
golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588=
|
||||
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
|
||||
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
|
||||
google.golang.org/api v0.216.0 h1:xnEHy+xWFrtYInWPy8OdGFsyIfWJjtVnO39g7pz2BFY=
|
||||
google.golang.org/api v0.216.0/go.mod h1:K9wzQMvWi47Z9IU7OgdOofvZuw75Ge3PPITImZR/UyI=
|
||||
google.golang.org/api v0.234.0 h1:d3sAmYq3E9gdr2mpmiWGbm9pHsA/KJmyiLkwKfHBqU4=
|
||||
google.golang.org/api v0.234.0/go.mod h1:QpeJkemzkFKe5VCE/PMv7GsUfn9ZF+u+q1Q7w6ckxTg=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
@@ -741,27 +750,27 @@ google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoA
|
||||
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
|
||||
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 h1:ToEetK57OidYuqD4Q5w+vfEnPvPpuTwedCNVohYJfNk=
|
||||
google.golang.org/genproto v0.0.0-20241118233622-e639e219e697/go.mod h1:JJrvXBWRZaFMxBufik1a4RpFw4HhgVtBBWQeQgUj2cc=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250127172529-29210b9bc287 h1:A2ni10G3UlplFrWdCDJTl7D7mJ7GSRm37S+PDimaKRw=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250127172529-29210b9bc287/go.mod h1:iYONQfRdizDB8JJBybql13nArx91jcUk7zCXEsOofM4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250127172529-29210b9bc287 h1:J1H9f+LEdWAfHcez/4cvaVBox7cOYT+IU6rgqj5x++8=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250127172529-29210b9bc287/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk=
|
||||
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 h1:1tXaIXCracvtsRxSBsYDiSBN0cuJvM7QYW+MrpIRY78=
|
||||
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a h1:SGktgSolFCo75dnHJF2yMvnns6jCmHFJ0vE4Vn2JKvQ=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a/go.mod h1:a77HrdMjoeKbnd2jmgcWdaS++ZLZAEq3orIOAEIKiVw=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ=
|
||||
google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw=
|
||||
google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM=
|
||||
google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/grpc v1.72.2 h1:TdbGzwb82ty4OusHWepvFWGLgIbNo1/SUynEN0ssqv8=
|
||||
google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 h1:F29+wU6Ee6qgu9TddPgooOdaqsxTMunOoj8KA5yuS5A=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1/go.mod h1:5KF+wpkbTSbGcR9zteSqZV6fqFOWBl4Yde8En8MryZA=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
caddycmd "github.com/caddyserver/caddy/v2/cmd"
|
||||
"github.com/dunglas/frankenphp"
|
||||
"frankenphp.dev"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -25,7 +25,7 @@ Executes a PHP script similarly to the CLI SAPI.`,
|
||||
})
|
||||
}
|
||||
|
||||
func cmdPHPCLI(caddycmd.Flags) (int, error) {
|
||||
func cmdPHPCLI(fs caddycmd.Flags) (int, error) {
|
||||
args := os.Args[2:]
|
||||
if len(args) < 1 {
|
||||
return 1, errors.New("the path to the PHP script is required")
|
||||
@@ -37,7 +37,13 @@ func cmdPHPCLI(caddycmd.Flags) (int, error) {
|
||||
}
|
||||
}
|
||||
|
||||
status := frankenphp.ExecuteScriptCLI(args[0], args)
|
||||
var status int
|
||||
if len(args) >= 2 && args[0] == "-r" {
|
||||
status = frankenphp.ExecutePHPCode(args[1])
|
||||
} else {
|
||||
status = frankenphp.ExecuteScriptCLI(args[0], args)
|
||||
}
|
||||
|
||||
os.Exit(status)
|
||||
|
||||
return status, nil
|
||||
|
||||
@@ -3,15 +3,14 @@ package caddy
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
mercureModule "github.com/dunglas/mercure/caddy"
|
||||
"go.uber.org/zap/zapcore"
|
||||
|
||||
"github.com/caddyserver/caddy/v2"
|
||||
"github.com/caddyserver/caddy/v2/caddyconfig"
|
||||
@@ -21,15 +20,14 @@ import (
|
||||
"github.com/caddyserver/caddy/v2/modules/caddyhttp/fileserver"
|
||||
"github.com/caddyserver/caddy/v2/modules/caddyhttp/rewrite"
|
||||
"github.com/caddyserver/certmagic"
|
||||
"github.com/dunglas/frankenphp"
|
||||
|
||||
"frankenphp.dev"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
caddycmd.RegisterCommand(caddycmd.Command{
|
||||
Name: "php-server",
|
||||
Usage: "[--domain <example.com>] [--root <path>] [--listen <addr>] [--worker /path/to/worker.php<,nb-workers>] [--watch <paths...>] [--access-log] [--debug] [--no-compress] [--mercure]",
|
||||
Usage: "[--domain=<example.com>] [--root=<path>] [--listen=<addr>] [--worker=/path/to/worker.php<,nb-workers>] [--watch[=<glob-pattern>]]... [--access-log] [--debug] [--no-compress] [--mercure]",
|
||||
Short: "Spins up a production-ready PHP server",
|
||||
Long: `
|
||||
A simple but production-ready PHP server. Useful for quick deployments,
|
||||
@@ -48,11 +46,14 @@ For more advanced use cases, see https://github.com/dunglas/frankenphp/blob/main
|
||||
cmd.Flags().StringP("root", "r", "", "The path to the root of the site")
|
||||
cmd.Flags().StringP("listen", "l", "", "The address to which to bind the listener")
|
||||
cmd.Flags().StringArrayP("worker", "w", []string{}, "Worker script")
|
||||
cmd.Flags().StringArrayP("watch", "", []string{}, "Directory to watch for file changes")
|
||||
cmd.Flags().StringArray("watch", []string{}, "Glob pattern of directories and files to watch for changes")
|
||||
cmd.Flags().BoolP("access-log", "a", false, "Enable the access log")
|
||||
cmd.Flags().BoolP("debug", "v", false, "Enable verbose debug logs")
|
||||
cmd.Flags().BoolP("mercure", "m", false, "Enable the built-in Mercure.rocks hub")
|
||||
cmd.Flags().BoolP("no-compress", "", false, "Disable Zstandard, Brotli and Gzip compression")
|
||||
cmd.Flags().Bool("no-compress", false, "Disable Zstandard, Brotli and Gzip compression")
|
||||
|
||||
cmd.Flags().Lookup("watch").NoOptDefVal = defaultWatchPattern
|
||||
|
||||
cmd.RunE = caddycmd.WrapCommandFuncForCobra(cmdPHPServer)
|
||||
},
|
||||
})
|
||||
@@ -79,27 +80,30 @@ func cmdPHPServer(fs caddycmd.Flags) (int, error) {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if frankenphp.EmbeddedAppPath != "" {
|
||||
if err := os.Chdir(frankenphp.EmbeddedAppPath); err != nil {
|
||||
return caddy.ExitCodeFailedStartup, err
|
||||
}
|
||||
}
|
||||
|
||||
var workersOption []workerConfig
|
||||
if len(workers) != 0 {
|
||||
workersOption = make([]workerConfig, 0, len(workers))
|
||||
for _, worker := range workers {
|
||||
parts := strings.SplitN(worker, ",", 2)
|
||||
if frankenphp.EmbeddedAppPath != "" && filepath.IsLocal(parts[0]) {
|
||||
parts[0] = filepath.Join(frankenphp.EmbeddedAppPath, parts[0])
|
||||
}
|
||||
|
||||
var num int
|
||||
var num uint64
|
||||
if len(parts) > 1 {
|
||||
num, _ = strconv.Atoi(parts[1])
|
||||
num, _ = strconv.ParseUint(parts[1], 10, 32)
|
||||
}
|
||||
|
||||
workersOption = append(workersOption, workerConfig{FileName: parts[0], Num: num})
|
||||
workersOption = append(workersOption, workerConfig{FileName: parts[0], Num: int(num)})
|
||||
}
|
||||
workersOption[0].Watch = watch
|
||||
}
|
||||
|
||||
if frankenphp.EmbeddedAppPath != "" {
|
||||
if _, err := os.Stat(filepath.Join(frankenphp.EmbeddedAppPath, "php.ini")); err == nil {
|
||||
if _, err := os.Stat("php.ini"); err == nil {
|
||||
iniScanDir := os.Getenv("PHP_INI_SCAN_DIR")
|
||||
|
||||
if err := os.Setenv("PHP_INI_SCAN_DIR", iniScanDir+":"+frankenphp.EmbeddedAppPath); err != nil {
|
||||
@@ -107,8 +111,8 @@ func cmdPHPServer(fs caddycmd.Flags) (int, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := os.Stat(filepath.Join(frankenphp.EmbeddedAppPath, "Caddyfile")); err == nil {
|
||||
config, _, err := caddycmd.LoadConfig(filepath.Join(frankenphp.EmbeddedAppPath, "Caddyfile"), "")
|
||||
if _, err := os.Stat("Caddyfile"); err == nil {
|
||||
config, _, err := caddycmd.LoadConfig("Caddyfile", "caddyfile")
|
||||
if err != nil {
|
||||
return caddy.ExitCodeFailedStartup, err
|
||||
}
|
||||
@@ -121,9 +125,7 @@ func cmdPHPServer(fs caddycmd.Flags) (int, error) {
|
||||
}
|
||||
|
||||
if root == "" {
|
||||
root = filepath.Join(frankenphp.EmbeddedAppPath, defaultDocumentRoot)
|
||||
} else if filepath.IsLocal(root) {
|
||||
root = filepath.Join(frankenphp.EmbeddedAppPath, root)
|
||||
root = defaultDocumentRoot
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,7 +336,7 @@ func cmdPHPServer(fs caddycmd.Flags) (int, error) {
|
||||
cfg.Logging = &caddy.Logging{
|
||||
Logs: map[string]*caddy.CustomLog{
|
||||
"default": {
|
||||
BaseLog: caddy.BaseLog{Level: zapcore.DebugLevel.CapitalString()},
|
||||
BaseLog: caddy.BaseLog{Level: slog.LevelDebug.String()},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ func TestWorkerWithInactiveWatcher(t *testing.T) {
|
||||
|
||||
frankenphp {
|
||||
worker {
|
||||
file ../testdata/worker-with-watcher.php
|
||||
file ../testdata/worker-with-counter.php
|
||||
num 1
|
||||
watch ./**/*.php
|
||||
}
|
||||
@@ -28,7 +28,7 @@ func TestWorkerWithInactiveWatcher(t *testing.T) {
|
||||
|
||||
localhost:`+testPort+` {
|
||||
root ../testdata
|
||||
rewrite worker-with-watcher.php
|
||||
rewrite worker-with-counter.php
|
||||
php
|
||||
}
|
||||
`, "caddyfile")
|
||||
|
||||
29
cgi.go
29
cgi.go
@@ -1,17 +1,24 @@
|
||||
package frankenphp
|
||||
|
||||
// #cgo nocallback frankenphp_register_bulk
|
||||
// #cgo nocallback frankenphp_register_variables_from_request_info
|
||||
// #cgo nocallback frankenphp_register_variable_safe
|
||||
// #cgo nocallback frankenphp_register_single
|
||||
// #cgo noescape frankenphp_register_bulk
|
||||
// #cgo noescape frankenphp_register_variables_from_request_info
|
||||
// #cgo noescape frankenphp_register_variable_safe
|
||||
// #cgo noescape frankenphp_register_single
|
||||
// #include <php_variables.h>
|
||||
// #include "frankenphp.h"
|
||||
import "C"
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"github.com/dunglas/frankenphp/internal/phpheaders"
|
||||
"frankenphp.dev/internal/phpheaders"
|
||||
)
|
||||
|
||||
var knownServerKeys = []string{
|
||||
@@ -48,7 +55,8 @@ var knownServerKeys = []string{
|
||||
//
|
||||
// TODO: handle this case https://github.com/caddyserver/caddy/issues/3718
|
||||
// Inspired by https://github.com/caddyserver/caddy/blob/master/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go
|
||||
func addKnownVariablesToServer(thread *phpThread, request *http.Request, fc *FrankenPHPContext, trackVarsArray *C.zval) {
|
||||
func addKnownVariablesToServer(thread *phpThread, fc *frankenPHPContext, trackVarsArray *C.zval) {
|
||||
request := fc.request
|
||||
keys := mainThread.knownServerKeys
|
||||
// Separate remote IP and port; more lenient than net.SplitHostPort
|
||||
var ip, port string
|
||||
@@ -160,8 +168,8 @@ func packCgiVariable(key *C.zend_string, value string) C.ht_key_value_pair {
|
||||
return C.ht_key_value_pair{key, toUnsafeChar(value), C.size_t(len(value))}
|
||||
}
|
||||
|
||||
func addHeadersToServer(request *http.Request, thread *phpThread, fc *FrankenPHPContext, trackVarsArray *C.zval) {
|
||||
for field, val := range request.Header {
|
||||
func addHeadersToServer(fc *frankenPHPContext, trackVarsArray *C.zval) {
|
||||
for field, val := range fc.request.Header {
|
||||
if k := mainThread.commonHeaders[field]; k != nil {
|
||||
v := strings.Join(val, ", ")
|
||||
C.frankenphp_register_single(k, toUnsafeChar(v), C.size_t(len(v)), trackVarsArray)
|
||||
@@ -176,7 +184,7 @@ func addHeadersToServer(request *http.Request, thread *phpThread, fc *FrankenPHP
|
||||
}
|
||||
}
|
||||
|
||||
func addPreparedEnvToServer(fc *FrankenPHPContext, trackVarsArray *C.zval) {
|
||||
func addPreparedEnvToServer(fc *frankenPHPContext, trackVarsArray *C.zval) {
|
||||
for k, v := range fc.env {
|
||||
C.frankenphp_register_variable_safe(toUnsafeChar(k), toUnsafeChar(v), C.size_t(len(v)), trackVarsArray)
|
||||
}
|
||||
@@ -186,11 +194,10 @@ func addPreparedEnvToServer(fc *FrankenPHPContext, trackVarsArray *C.zval) {
|
||||
//export go_register_variables
|
||||
func go_register_variables(threadIndex C.uintptr_t, trackVarsArray *C.zval) {
|
||||
thread := phpThreads[threadIndex]
|
||||
r := thread.getActiveRequest()
|
||||
fc := r.Context().Value(contextKey).(*FrankenPHPContext)
|
||||
fc := thread.getRequestContext()
|
||||
|
||||
addKnownVariablesToServer(thread, r, fc, trackVarsArray)
|
||||
addHeadersToServer(r, thread, fc, trackVarsArray)
|
||||
addKnownVariablesToServer(thread, fc, trackVarsArray)
|
||||
addHeadersToServer(fc, trackVarsArray)
|
||||
|
||||
// The Prepared Environment is registered last and can overwrite any previous values
|
||||
addPreparedEnvToServer(fc, trackVarsArray)
|
||||
@@ -201,7 +208,7 @@ func go_register_variables(threadIndex C.uintptr_t, trackVarsArray *C.zval) {
|
||||
//
|
||||
// Adapted from https://github.com/caddyserver/caddy/blob/master/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go
|
||||
// Copyright 2015 Matthew Holt and The Caddy Authors
|
||||
func splitPos(fc *FrankenPHPContext, path string) int {
|
||||
func splitPos(fc *frankenPHPContext, path string) int {
|
||||
if len(fc.splitPath) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
166
context.go
Normal file
166
context.go
Normal file
@@ -0,0 +1,166 @@
|
||||
package frankenphp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// frankenPHPContext provides contextual information about the Request to handle.
|
||||
type frankenPHPContext struct {
|
||||
documentRoot string
|
||||
splitPath []string
|
||||
env PreparedEnv
|
||||
logger *slog.Logger
|
||||
request *http.Request
|
||||
originalRequest *http.Request
|
||||
|
||||
docURI string
|
||||
pathInfo string
|
||||
scriptName string
|
||||
scriptFilename string
|
||||
workerName string
|
||||
|
||||
// Whether the request is already closed by us
|
||||
isDone bool
|
||||
|
||||
responseWriter http.ResponseWriter
|
||||
|
||||
done chan interface{}
|
||||
startedAt time.Time
|
||||
}
|
||||
|
||||
// fromContext extracts the frankenPHPContext from a context.
|
||||
func fromContext(ctx context.Context) (fctx *frankenPHPContext, ok bool) {
|
||||
fctx, ok = ctx.Value(contextKey).(*frankenPHPContext)
|
||||
return
|
||||
}
|
||||
|
||||
// NewRequestWithContext creates a new FrankenPHP request context.
|
||||
func NewRequestWithContext(r *http.Request, opts ...RequestOption) (*http.Request, error) {
|
||||
fc := &frankenPHPContext{
|
||||
done: make(chan interface{}),
|
||||
startedAt: time.Now(),
|
||||
request: r,
|
||||
}
|
||||
for _, o := range opts {
|
||||
if err := o(fc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if fc.logger == nil {
|
||||
fc.logger = logger
|
||||
}
|
||||
|
||||
if fc.documentRoot == "" {
|
||||
if EmbeddedAppPath != "" {
|
||||
fc.documentRoot = EmbeddedAppPath
|
||||
} else {
|
||||
var err error
|
||||
if fc.documentRoot, err = os.Getwd(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if fc.splitPath == nil {
|
||||
fc.splitPath = []string{".php"}
|
||||
}
|
||||
|
||||
if fc.env == nil {
|
||||
fc.env = make(map[string]string)
|
||||
}
|
||||
|
||||
if splitPos := splitPos(fc, r.URL.Path); splitPos > -1 {
|
||||
fc.docURI = r.URL.Path[:splitPos]
|
||||
fc.pathInfo = r.URL.Path[splitPos:]
|
||||
|
||||
// Strip PATH_INFO from SCRIPT_NAME
|
||||
fc.scriptName = strings.TrimSuffix(r.URL.Path, fc.pathInfo)
|
||||
|
||||
// Ensure the SCRIPT_NAME has a leading slash for compliance with RFC3875
|
||||
// Info: https://tools.ietf.org/html/rfc3875#section-4.1.13
|
||||
if fc.scriptName != "" && !strings.HasPrefix(fc.scriptName, "/") {
|
||||
fc.scriptName = "/" + fc.scriptName
|
||||
}
|
||||
}
|
||||
|
||||
// SCRIPT_FILENAME is the absolute path of SCRIPT_NAME
|
||||
fc.scriptFilename = sanitizedPathJoin(fc.documentRoot, fc.scriptName)
|
||||
c := context.WithValue(r.Context(), contextKey, fc)
|
||||
|
||||
return r.WithContext(c), nil
|
||||
}
|
||||
|
||||
func newDummyContext(requestPath string, opts ...RequestOption) (*frankenPHPContext, error) {
|
||||
r, err := http.NewRequest(http.MethodGet, requestPath, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fr, err := NewRequestWithContext(r, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fc, _ := fromContext(fr.Context())
|
||||
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
// closeContext sends the response to the client
|
||||
func (fc *frankenPHPContext) closeContext() {
|
||||
if fc.isDone {
|
||||
return
|
||||
}
|
||||
|
||||
close(fc.done)
|
||||
fc.isDone = true
|
||||
}
|
||||
|
||||
// validate checks if the request should be outright rejected
|
||||
func (fc *frankenPHPContext) validate() bool {
|
||||
if !strings.Contains(fc.request.URL.Path, "\x00") {
|
||||
return true
|
||||
}
|
||||
|
||||
fc.rejectBadRequest("Invalid request path")
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (fc *frankenPHPContext) clientHasClosed() bool {
|
||||
select {
|
||||
case <-fc.request.Context().Done():
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// reject sends a response with the given status code and message
|
||||
func (fc *frankenPHPContext) reject(statusCode int, message string) {
|
||||
if fc.isDone {
|
||||
return
|
||||
}
|
||||
|
||||
rw := fc.responseWriter
|
||||
if rw != nil {
|
||||
rw.WriteHeader(statusCode)
|
||||
_, _ = rw.Write([]byte(message))
|
||||
|
||||
if f, ok := rw.(http.Flusher); ok {
|
||||
f.Flush()
|
||||
}
|
||||
}
|
||||
|
||||
fc.closeContext()
|
||||
}
|
||||
|
||||
func (fc *frankenPHPContext) rejectBadRequest(message string) {
|
||||
fc.reject(http.StatusBadRequest, message)
|
||||
}
|
||||
46
debugstate.go
Normal file
46
debugstate.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package frankenphp
|
||||
|
||||
// EXPERIMENTAL: ThreadDebugState prints the state of a single PHP thread - debugging purposes only
|
||||
type ThreadDebugState struct {
|
||||
Index int
|
||||
Name string
|
||||
State string
|
||||
IsWaiting bool
|
||||
IsBusy bool
|
||||
WaitingSinceMilliseconds int64
|
||||
}
|
||||
|
||||
// EXPERIMENTAL: FrankenPHPDebugState prints the state of all PHP threads - debugging purposes only
|
||||
type FrankenPHPDebugState struct {
|
||||
ThreadDebugStates []ThreadDebugState
|
||||
ReservedThreadCount int
|
||||
}
|
||||
|
||||
// EXPERIMENTAL: DebugState prints the state of all PHP threads - debugging purposes only
|
||||
func DebugState() FrankenPHPDebugState {
|
||||
fullState := FrankenPHPDebugState{
|
||||
ThreadDebugStates: make([]ThreadDebugState, 0, len(phpThreads)),
|
||||
ReservedThreadCount: 0,
|
||||
}
|
||||
for _, thread := range phpThreads {
|
||||
if thread.state.is(stateReserved) {
|
||||
fullState.ReservedThreadCount++
|
||||
continue
|
||||
}
|
||||
fullState.ThreadDebugStates = append(fullState.ThreadDebugStates, threadDebugState(thread))
|
||||
}
|
||||
|
||||
return fullState
|
||||
}
|
||||
|
||||
// threadDebugState creates a small jsonable status message for debugging purposes
|
||||
func threadDebugState(thread *phpThread) ThreadDebugState {
|
||||
return ThreadDebugState{
|
||||
Index: thread.threadIndex,
|
||||
Name: thread.name(),
|
||||
State: thread.state.name(),
|
||||
IsWaiting: thread.state.isInWaitingState(),
|
||||
IsBusy: !thread.state.isInWaitingState(),
|
||||
WaitingSinceMilliseconds: thread.state.waitTime(),
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
#checkov:skip=CKV_DOCKER_2
|
||||
#checkov:skip=CKV_DOCKER_3
|
||||
FROM golang:1.22-alpine
|
||||
FROM golang:1.24-alpine
|
||||
|
||||
ENV GOTOOLCHAIN=local
|
||||
ENV CFLAGS="-ggdb3"
|
||||
ENV PHPIZE_DEPS="\
|
||||
autoconf \
|
||||
@@ -50,18 +51,21 @@ WORKDIR /usr/local/src/php
|
||||
RUN git clone --branch=PHP-8.4 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 \
|
||||
EXTENSION_DIR=/usr/lib/frankenphp/modules ./configure \
|
||||
--enable-embed \
|
||||
--enable-zts \
|
||||
--disable-zend-signals \
|
||||
--enable-zend-max-execution-timers \
|
||||
--with-config-file-path=/etc/frankenphp/php.ini \
|
||||
--with-config-file-scan-dir=/etc/frankenphp/php.d \
|
||||
--enable-debug && \
|
||||
make -j"$(nproc)" && \
|
||||
make install && \
|
||||
ldconfig /etc/ld.so.conf.d && \
|
||||
cp php.ini-development /usr/local/lib/php.ini && \
|
||||
echo "zend_extension=opcache.so" >> /usr/local/lib/php.ini && \
|
||||
echo "opcache.enable=1" >> /usr/local/lib/php.ini && \
|
||||
mkdir -p /etc/frankenphp/php.d && \
|
||||
cp php.ini-development /etc/frankenphp/php.ini && \
|
||||
echo "zend_extension=opcache.so" >> /etc/frankenphp/php.ini && \
|
||||
echo "opcache.enable=1" >> /etc/frankenphp/php.ini && \
|
||||
php --version
|
||||
|
||||
# Install e-dant/watcher (necessary for file watching)
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
#checkov:skip=CKV_DOCKER_2
|
||||
#checkov:skip=CKV_DOCKER_3
|
||||
FROM golang:1.22
|
||||
FROM golang:1.24
|
||||
|
||||
ENV GOTOOLCHAIN=local
|
||||
ENV CFLAGS="-ggdb3"
|
||||
ENV PHPIZE_DEPS="\
|
||||
autoconf \
|
||||
@@ -46,24 +47,27 @@ RUN apt-get update && \
|
||||
echo 'set auto-load safe-path /' > /root/.gdbinit && \
|
||||
echo '* soft core unlimited' >> /etc/security/limits.conf \
|
||||
&& \
|
||||
apt-get clean
|
||||
apt-get clean
|
||||
|
||||
WORKDIR /usr/local/src/php
|
||||
RUN git clone --branch=PHP-8.4 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 \
|
||||
EXTENSION_DIR=/usr/lib/frankenphp/modules ./configure \
|
||||
--enable-embed \
|
||||
--enable-zts \
|
||||
--disable-zend-signals \
|
||||
--enable-zend-max-execution-timers \
|
||||
--with-config-file-path=/etc/frankenphp/php.ini \
|
||||
--with-config-file-scan-dir=/etc/frankenphp/php.d \
|
||||
--enable-debug && \
|
||||
make -j"$(nproc)" && \
|
||||
make install && \
|
||||
ldconfig && \
|
||||
cp php.ini-development /usr/local/lib/php.ini && \
|
||||
echo "zend_extension=opcache.so" >> /usr/local/lib/php.ini && \
|
||||
echo "opcache.enable=1" >> /usr/local/lib/php.ini && \
|
||||
mkdir -p /etc/frankenphp/php.d && \
|
||||
cp php.ini-development /etc/frankenphp/php.ini && \
|
||||
echo "zend_extension=opcache.so" >> /etc/frankenphp/php.ini && \
|
||||
echo "opcache.enable=1" >> /etc/frankenphp/php.ini && \
|
||||
php --version
|
||||
|
||||
# Install e-dant/watcher (necessary for file watching)
|
||||
@@ -71,7 +75,9 @@ WORKDIR /usr/local/src/watcher
|
||||
RUN git clone https://github.com/e-dant/watcher . && \
|
||||
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release && \
|
||||
cmake --build build/ && \
|
||||
cmake --install build
|
||||
cmake --install build && \
|
||||
cp build/libwatcher-c.so /usr/local/lib/libwatcher-c.so && \
|
||||
ldconfig
|
||||
|
||||
WORKDIR /go/src/app
|
||||
COPY . .
|
||||
|
||||
@@ -11,7 +11,7 @@ variable "PHP_VERSION" {
|
||||
}
|
||||
|
||||
variable "GO_VERSION" {
|
||||
default = "1.23"
|
||||
default = "1.24"
|
||||
}
|
||||
|
||||
variable "SHA" {}
|
||||
@@ -118,20 +118,20 @@ target "default" {
|
||||
}
|
||||
}
|
||||
|
||||
target "static-builder" {
|
||||
target "static-builder-musl" {
|
||||
contexts = {
|
||||
golang-base = "docker-image://golang:${GO_VERSION}-alpine"
|
||||
}
|
||||
dockerfile = "static-builder.Dockerfile"
|
||||
dockerfile = "static-builder-musl.Dockerfile"
|
||||
context = "./"
|
||||
platforms = [
|
||||
"linux/amd64",
|
||||
"linux/arm64",
|
||||
]
|
||||
tags = distinct(flatten([
|
||||
LATEST ? "${IMAGE_NAME}:static-builder" : "",
|
||||
SHA == "" || VERSION != "dev" ? "" : "${IMAGE_NAME}:static-builder-sha-${substr(SHA, 0, 7)}",
|
||||
VERSION == "dev" ? [] : [for v in semver(VERSION) : "${IMAGE_NAME}:static-builder-${v}"]
|
||||
LATEST ? "${IMAGE_NAME}:static-builder-musl" : "",
|
||||
SHA == "" || VERSION != "dev" ? "" : "${IMAGE_NAME}:static-builder-musl-sha-${substr(SHA, 0, 7)}",
|
||||
VERSION == "dev" ? [] : [for v in semver(VERSION) : "${IMAGE_NAME}:static-builder-musl-${v}"]
|
||||
]))
|
||||
labels = {
|
||||
"org.opencontainers.image.created" = "${timestamp()}"
|
||||
@@ -143,3 +143,27 @@ target "static-builder" {
|
||||
}
|
||||
secret = ["id=github-token,env=GITHUB_TOKEN"]
|
||||
}
|
||||
|
||||
target "static-builder-gnu" {
|
||||
dockerfile = "static-builder-gnu.Dockerfile"
|
||||
context = "./"
|
||||
platforms = [
|
||||
"linux/amd64",
|
||||
"linux/arm64"
|
||||
]
|
||||
tags = distinct(flatten([
|
||||
LATEST ? "${IMAGE_NAME}:static-builder-gnu" : "",
|
||||
SHA == "" || VERSION != "dev" ? "" : "${IMAGE_NAME}:static-builder-gnu-sha-${substr(SHA, 0, 7)}",
|
||||
VERSION == "dev" ? [] : [for v in semver(VERSION) : "${IMAGE_NAME}:static-builder-gnu-${v}"]
|
||||
]))
|
||||
labels = {
|
||||
"org.opencontainers.image.created" = "${timestamp()}"
|
||||
"org.opencontainers.image.version" = VERSION
|
||||
"org.opencontainers.image.revision" = SHA
|
||||
}
|
||||
args = {
|
||||
FRANKENPHP_VERSION = VERSION
|
||||
GO_VERSION = GO_VERSION
|
||||
}
|
||||
secret = ["id=github-token,env=GITHUB_TOKEN"]
|
||||
}
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
Without any additional configuration, FrankenPHP operates in classic mode. In this mode, FrankenPHP functions like a traditional PHP server, directly serving PHP files. This makes it a seamless drop-in replacement for PHP-FPM or Apache with mod_php.
|
||||
|
||||
Similar to Caddy, FrankenPHP accepts an unlimited number of connections and uses a [fixed number of threads](config.md#caddyfile-config) to serve them. The number of accepted and queued connections is limited only by the available system resources. The PHP thread pool operates with a fixed number of threads initialized at startup, comparable to the static mode of PHP-FPM.
|
||||
Similar to Caddy, FrankenPHP accepts an unlimited number of connections and uses a [fixed number of threads](config.md#caddyfile-config) to serve them. The number of accepted and queued connections is limited only by the available system resources.
|
||||
The PHP thread pool operates with a fixed number of threads initialized at startup, comparable to the static mode of PHP-FPM. It's also possible to let threads [scale automatically at runtime](performance.md#max_threads), similar to the dynamic mode of PHP-FPM.
|
||||
|
||||
Queued connections will wait indefinitely until a PHP thread is available to serve them. To prevent that, set a reasonable [write timeout in Caddy](https://caddyserver.com/docs/caddyfile/options#timeouts).
|
||||
Queued connections will wait indefinitely until a PHP thread is available to serve them. To prevent that, you can use the `max_wait_time` [configuration](config.md#caddyfile-config) to limit how long a request may wait for a free PHP thread before being rejected.
|
||||
Additionally, you can set a reasonable [write timeout in Caddy](https://caddyserver.com/docs/caddyfile/options#timeouts).
|
||||
|
||||
Each Caddy instance will only spin up one FrankenPHP thread pool, which will be shared across all `php_server` blocks.
|
||||
|
||||
@@ -11,9 +11,13 @@ docker build -t frankenphp-dev -f dev.Dockerfile .
|
||||
docker run --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -p 8080:8080 -p 443:443 -p 443:443/udp -v $PWD:/go/src/app -it frankenphp-dev
|
||||
```
|
||||
|
||||
该镜像包含常用的开发工具(Go、GDB、Valgrind、Neovim等)。
|
||||
该镜像包含常用的开发工具(Go、GDB、Valgrind、Neovim等)并使用以下 php 设置位置
|
||||
|
||||
如果 docker 版本低于 23.0,则会因为 dockerignore [pattern issue](https://github.com/moby/moby/pull/42676) 而导致构建失败。将目录添加到 `.dockerignore`。
|
||||
- php.ini: `/etc/frankenphp/php.ini` 默认提供了一个带有开发预设的 php.ini 文件。
|
||||
- 附加配置文件: `/etc/frankenphp/php.d/*.ini`
|
||||
- php 扩展: `/usr/lib/frankenphp/modules/`
|
||||
|
||||
如果您的 docker 版本低于 23.0,则会因为 dockerignore [pattern issue](https://github.com/moby/moby/pull/42676) 而导致构建失败。将目录添加到 `.dockerignore`。
|
||||
|
||||
```patch
|
||||
!testdata/*.php
|
||||
@@ -114,7 +118,7 @@ docker buildx bake -f docker-bake.hcl --pull --no-cache --push
|
||||
--set static-builder.args.DEBUG_SYMBOLS=1 \
|
||||
--set "static-builder.platform=linux/amd64" \
|
||||
static-builder
|
||||
docker cp $(docker create --name static-builder dunglas/frankenphp:static-builder):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp
|
||||
docker cp $(docker create --name static-builder-musl dunglas/frankenphp:static-builder-musl):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp
|
||||
```
|
||||
|
||||
2. 将当前版本的 `frankenphp` 替换为 debug FrankenPHP 可执行文件
|
||||
@@ -172,27 +176,27 @@ docker buildx bake -f docker-bake.hcl --pull --no-cache --push
|
||||
|
||||
```console
|
||||
go test -tags watcher -c -ldflags=-w
|
||||
gdb --args frankenphp.test -test.run ^MyTest$
|
||||
gdb --args frankenphp.dev.test -test.run ^MyTest$
|
||||
```
|
||||
|
||||
9. 当错误修复后,恢复所有这些更改
|
||||
|
||||
## 其他开发资源
|
||||
|
||||
* [PHP 嵌入 uWSGI](https://github.com/unbit/uwsgi/blob/master/plugins/php/php_plugin.c)
|
||||
* [PHP 嵌入 NGINX Unit](https://github.com/nginx/unit/blob/master/src/nxt_php_sapi.c)
|
||||
* [PHP 嵌入 Go (go-php)](https://github.com/deuill/go-php)
|
||||
* [PHP 嵌入 Go (GoEmPHP)](https://github.com/mikespook/goemphp)
|
||||
* [PHP 嵌入 C++](https://gist.github.com/paresy/3cbd4c6a469511ac7479aa0e7c42fea7)
|
||||
* [扩展和嵌入 PHP 作者:Sara Golemon](https://books.google.fr/books?id=zMbGvK17_tYC&pg=PA254&lpg=PA254#v=onepage&q&f=false)
|
||||
* [TSRMLS_CC到底是什么?](http://blog.golemon.com/2006/06/what-heck-is-tsrmlscc-anyway.html)
|
||||
* [Mac 上的 PHP 嵌入](https://gist.github.com/jonnywang/61427ffc0e8dde74fff40f479d147db4)
|
||||
* [SDL 绑定](https://pkg.go.dev/github.com/veandco/go-sdl2@v0.4.21/sdl#Main)
|
||||
- [PHP 嵌入 uWSGI](https://github.com/unbit/uwsgi/blob/master/plugins/php/php_plugin.c)
|
||||
- [PHP 嵌入 NGINX Unit](https://github.com/nginx/unit/blob/master/src/nxt_php_sapi.c)
|
||||
- [PHP 嵌入 Go (go-php)](https://github.com/deuill/go-php)
|
||||
- [PHP 嵌入 Go (GoEmPHP)](https://github.com/mikespook/goemphp)
|
||||
- [PHP 嵌入 C++](https://gist.github.com/paresy/3cbd4c6a469511ac7479aa0e7c42fea7)
|
||||
- [扩展和嵌入 PHP 作者:Sara Golemon](https://books.google.fr/books?id=zMbGvK17_tYC&pg=PA254&lpg=PA254#v=onepage&q&f=false)
|
||||
- [TSRMLS_CC到底是什么?](http://blog.golemon.com/2006/06/what-heck-is-tsrmlscc-anyway.html)
|
||||
- [Mac 上的 PHP 嵌入](https://gist.github.com/jonnywang/61427ffc0e8dde74fff40f479d147db4)
|
||||
- [SDL 绑定](https://pkg.go.dev/github.com/veandco/go-sdl2@v0.4.21/sdl#Main)
|
||||
|
||||
## Docker 相关资源
|
||||
|
||||
* [Bake 文件定义](https://docs.docker.com/build/customize/bake/file-definition/)
|
||||
* [docker buildx 构建](https://docs.docker.com/engine/reference/commandline/buildx_build/)
|
||||
- [Bake 文件定义](https://docs.docker.com/build/customize/bake/file-definition/)
|
||||
- [docker buildx 构建](https://docs.docker.com/engine/reference/commandline/buildx_build/)
|
||||
|
||||
## 有用的命令
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ CGO_ENABLED=1 \
|
||||
XCADDY_GO_BUILD_FLAGS="-ldflags '-w -s'" \
|
||||
xcaddy build \
|
||||
--output frankenphp \
|
||||
--with github.com/dunglas/frankenphp/caddy \
|
||||
--with frankenphp.dev/caddy \
|
||||
--with github.com/dunglas/caddy-cbrotli \
|
||||
--with github.com/dunglas/mercure/caddy \
|
||||
--with github.com/dunglas/vulcain/caddy
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
# 配置
|
||||
# 配置
|
||||
|
||||
FrankenPHP,Caddy 以及 Mercure 和 Vulcain 模块可以使用 [Caddy 支持的格式](https://caddyserver.com/docs/getting-started#your-first-config) 进行配置。
|
||||
|
||||
在[Docker 映像](docker.md) 中,`Caddyfile` 位于 `/etc/caddy/Caddyfile`。
|
||||
在[Docker 映像](docker.md) 中,`Caddyfile` 位于 `/etc/frankenphp/Caddyfile`。
|
||||
静态二进制文件会在启动时所在的目录中查找 `Caddyfile`。
|
||||
PHP 本身可以[使用 `php.ini` 文件](https://www.php.net/manual/zh/configuration.file.php)进行配置。
|
||||
默认情况下,随 Docker 映像提供的 PHP 和静态二进制文件中包含的 PHP 将在启动 FrankenPHP 的目录和 `/usr/local/etc/php/` 中查找`php.ini` 文件。它们还会从 `/usr/local/etc/php/conf.d/` 中加载所有以 `.ini` 结尾的文件。
|
||||
默认情况下没有 `php.ini` 文件,因此应复制 PHP 项目提供的官方模板。
|
||||
在 Docker 上,模板在镜像中提供:
|
||||
PHP 解释器将在以下位置查找:
|
||||
|
||||
Docker:
|
||||
|
||||
- php.ini: `/usr/local/etc/php/php.ini` 默认情况下不提供 php.ini。
|
||||
- 附加配置文件: `/usr/local/etc/php/conf.d/*.ini`
|
||||
- php 扩展: `/usr/local/lib/php/extensions/no-debug-zts-<YYYYMMDD>/`
|
||||
- 您应该复制 PHP 项目提供的官方模板:
|
||||
|
||||
```dockerfile
|
||||
FROM dunglas/frankenphp
|
||||
@@ -19,20 +24,26 @@ RUN cp $PHP_INI_DIR/php.ini-production $PHP_INI_DIR/php.ini
|
||||
RUN cp $PHP_INI_DIR/php.ini-development $PHP_INI_DIR/php.ini
|
||||
```
|
||||
|
||||
如果不使用 Docker,请复制[PHP 源代码](https://github.com/php/php-src/)中提供的`php.ini-production`或`php.ini-development`中的一个。
|
||||
FrankenPHP 安装 (.rpm 或 .deb):
|
||||
|
||||
- php.ini: `/etc/frankenphp/php.ini` 默认情况下提供带有生产预设的 php.ini 文件。
|
||||
- 附加配置文件: `/etc/frankenphp/php.d/*.ini`
|
||||
- php 扩展: `/usr/lib/frankenphp/modules/`
|
||||
|
||||
静态二进制:
|
||||
|
||||
- php.ini: 执行 `frankenphp run` 或 `frankenphp php-server` 的目录,然后是 `/etc/frankenphp/php.ini`
|
||||
- 附加配置文件: `/etc/frankenphp/php.d/*.ini`
|
||||
- php 扩展: 无法加载
|
||||
- 复制[PHP 源代码](https://github.com/php/php-src/)中提供的`php.ini-production`或`php.ini-development`中的一个。
|
||||
|
||||
## Caddyfile 配置
|
||||
|
||||
要注册 FrankenPHP 执行器,必须设置 `frankenphp` [全局选项](https://caddyserver.com/docs/caddyfile/concepts#global-options),然后可以在站点块中使用 `php_server` 或 `php` [HTTP 指令](https://caddyserver.com/docs/caddyfile/concepts#directives) 来为您的 PHP 应用程序提供服务。
|
||||
可以在站点块中使用 `php_server` 或 `php` [HTTP 指令](https://caddyserver.com/docs/caddyfile/concepts#directives) 来为您的 PHP 应用程序提供服务。
|
||||
|
||||
最小示例:
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
# 启用 FrankenPHP
|
||||
frankenphp
|
||||
}
|
||||
|
||||
localhost {
|
||||
# 启用压缩(可选)
|
||||
encode zstd br gzip
|
||||
@@ -41,7 +52,8 @@ localhost {
|
||||
}
|
||||
```
|
||||
|
||||
或者,可以在全局选项下指定要创建的线程数和要从服务器启动的 [worker 脚本](worker.md)。
|
||||
您也可以使用全局选项显式配置 FrankenPHP:
|
||||
`frankenphp` [全局选项](https://caddyserver.com/docs/caddyfile/concepts#global-options) 可用于配置 FrankenPHP。
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
@@ -73,21 +85,18 @@ localhost {
|
||||
如果在同一服务器上运行多个应用,还可以定义多个 worker:
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
frankenphp {
|
||||
worker /path/to/app/public/index.php <num>
|
||||
worker /path/to/other/public/index.php <num>
|
||||
app.example.com {
|
||||
php_server {
|
||||
root /path/to/app/public
|
||||
worker index.php <num>
|
||||
}
|
||||
}
|
||||
|
||||
app.example.com {
|
||||
root * /path/to/app/public
|
||||
php_server
|
||||
}
|
||||
|
||||
other.example.com {
|
||||
root * /path/to/other/public
|
||||
php_server
|
||||
php_server {
|
||||
root /path/to/other/public
|
||||
worker index.php <num>
|
||||
}
|
||||
}
|
||||
# ...
|
||||
```
|
||||
@@ -123,9 +132,18 @@ route {
|
||||
```caddyfile
|
||||
php_server [<matcher>] {
|
||||
root <directory> # 设置站点的根目录。默认值:`root` 指令。
|
||||
split_path <delim...> # 设置用于将 URI 拆分为两部分的子字符串。第一个匹配的子字符串将用于从路径中拆分“路径信息”。第一个部分以匹配的子字符串为后缀,并将假定为实际资源(CGI 脚本)名称。第二部分将设置为PATH_INFO,供脚本使用。默认值:`.php`
|
||||
split_path <delim...> # 设置用于将 URI 拆分为两部分的子字符串。第一个匹配的子字符串将用于从路径中拆分"路径信息"。第一个部分以匹配的子字符串为后缀,并将假定为实际资源(CGI 脚本)名称。第二部分将设置为PATH_INFO,供脚本使用。默认值:`.php`
|
||||
resolve_root_symlink false # 禁用将 `root` 目录在符号链接时将其解析为实际值(默认启用)。
|
||||
env <key> <value> # 设置额外的环境变量,可以设置多个环境变量。
|
||||
file_server off # 禁用内置的 file_server 指令。
|
||||
worker { # 创建特定于此服务器的 worker。可以为多个 worker 多次指定。
|
||||
file <path> # 设置 worker 脚本的路径,可以相对于 php_server 根目录
|
||||
num <num> # 设置要启动的 PHP 线程数,默认为可用 CPU 数的 2 倍
|
||||
name <name> # 为 worker 设置名称,用于日志和指标。默认值:worker 文件的绝对路径。在 php_server 块中定义时始终以 m# 开头。
|
||||
watch <path> # 设置要监视文件更改的路径。可以为多个路径多次指定。
|
||||
env <key> <value> # 将额外的环境变量设置为给定值。可以为多个环境变量多次指定。此 worker 的环境变量也从 php_server 父级继承,但可以在此处覆盖。
|
||||
}
|
||||
worker <other_file> <num> # 也可以像在全局 frankenphp 块中一样使用简短形式。
|
||||
}
|
||||
```
|
||||
|
||||
@@ -133,9 +151,9 @@ php_server [<matcher>] {
|
||||
|
||||
以下环境变量可用于在 `Caddyfile` 中注入 Caddy 指令,而无需对其进行修改:
|
||||
|
||||
* `SERVER_NAME`: 更改 [要监听的地址](https://caddyserver.com/docs/caddyfile/concepts#addresses),提供的主机名也将用于生成的 TLS 证书
|
||||
* `CADDY_GLOBAL_OPTIONS`: 注入 [全局选项](https://caddyserver.com/docs/caddyfile/options)
|
||||
* `FRANKENPHP_CONFIG`: 在 `frankenphp` 指令下注入配置
|
||||
- `SERVER_NAME`: 更改 [要监听的地址](https://caddyserver.com/docs/caddyfile/concepts#addresses),提供的主机名也将用于生成的 TLS 证书
|
||||
- `CADDY_GLOBAL_OPTIONS`: 注入 [全局选项](https://caddyserver.com/docs/caddyfile/options)
|
||||
- `FRANKENPHP_CONFIG`: 在 `frankenphp` 指令下注入配置
|
||||
|
||||
## PHP 配置
|
||||
|
||||
|
||||
@@ -57,8 +57,8 @@ RUN CGO_ENABLED=1 \
|
||||
CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" \
|
||||
xcaddy build \
|
||||
--output /usr/local/bin/frankenphp \
|
||||
--with github.com/dunglas/frankenphp=./ \
|
||||
--with github.com/dunglas/frankenphp/caddy=./caddy/ \
|
||||
--with frankenphp.dev=./ \
|
||||
--with frankenphp.dev/caddy=./caddy/ \
|
||||
--with github.com/dunglas/caddy-cbrotli \
|
||||
# Mercure 和 Vulcain 包含在官方版本中,如果不需要你可以删除它们
|
||||
--with github.com/dunglas/mercure/caddy \
|
||||
|
||||
@@ -27,7 +27,7 @@ docker run -p 80:80 -p 443:443 -p 443:443/udp -v $PWD:/app dunglas/frankenphp
|
||||
# 服务器的域名
|
||||
localhost {
|
||||
# 将 webroot 设置为 public/ 目录
|
||||
root * public/
|
||||
root public/
|
||||
# 启用压缩(可选)
|
||||
encode zstd br gzip
|
||||
# 执行当前目录中的 PHP 文件并提供资产
|
||||
|
||||
@@ -13,7 +13,7 @@ FrankenPHP 还支持 [将 PHP 应用程序嵌入到静态二进制文件中](emb
|
||||
|
||||
```console
|
||||
docker buildx bake --load static-builder
|
||||
docker cp $(docker create --name static-builder dunglas/frankenphp:static-builder):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp ; docker rm static-builder
|
||||
docker cp $(docker create --name static-builder-musl dunglas/frankenphp:static-builder-musl):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp ; docker rm static-builder
|
||||
```
|
||||
|
||||
生成的静态二进制文件名为 `frankenphp`,可在当前目录中找到。
|
||||
|
||||
@@ -3,13 +3,30 @@
|
||||
This document explains how to create a FrankenPHP binary that will load PHP as a dynamic library.
|
||||
This is the recommended method.
|
||||
|
||||
Alternatively, [static builds](static.md) can also be created.
|
||||
Alternatively, [fully and mostly static builds](static.md) can also be created.
|
||||
|
||||
## Install PHP
|
||||
|
||||
FrankenPHP is compatible with PHP 8.2 and superior.
|
||||
|
||||
First, [get the PHP sources](https://www.php.net/downloads.php) and extract them:
|
||||
### With Homebrew (Linux and Mac)
|
||||
|
||||
The easiest way to install a version of libphp compatible with FrankenPHP is to use the ZTS packages provided by [Homebrew PHP](https://github.com/shivammathur/homebrew-php).
|
||||
|
||||
First, if not already done, install [Homebrew](https://brew.sh).
|
||||
|
||||
Then, install the ZTS variant of PHP, Brotli (optional, for compression support) and watcher (optional, for file change detection):
|
||||
|
||||
```console
|
||||
brew install shivammathur/php/php-zts brotli watcher
|
||||
brew link --overwrite --force shivammathur/php/php-zts
|
||||
```
|
||||
|
||||
### By Compiling PHP
|
||||
|
||||
Alternatively, you can compile PHP from sources with the options needed by FrankenPHP by following these steps.
|
||||
~~
|
||||
~~First, [get the PHP sources](https://www.php.net/downloads.php) and extract them:
|
||||
|
||||
```console
|
||||
tar xf php-*
|
||||
@@ -19,7 +36,7 @@ cd php-*/
|
||||
Then, run the `configure` script with the options needed for your platform.
|
||||
The following `./configure` flags are mandatory, but you can add others, for example, to compile extensions or additional features.
|
||||
|
||||
### Linux
|
||||
#### Linux
|
||||
|
||||
```console
|
||||
./configure \
|
||||
@@ -29,13 +46,12 @@ The following `./configure` flags are mandatory, but you can add others, for exa
|
||||
--enable-zend-max-execution-timers
|
||||
```
|
||||
|
||||
### Mac
|
||||
#### Mac
|
||||
|
||||
Use the [Homebrew](https://brew.sh/) package manager to install
|
||||
`libiconv`, `bison`, `re2c` and `pkg-config`:
|
||||
Use the [Homebrew](https://brew.sh/) package manager to install the required and optional dependencies:
|
||||
|
||||
```console
|
||||
brew install libiconv bison brotli re2c pkg-config
|
||||
brew install libiconv bison brotli re2c pkg-config watcher
|
||||
echo 'export PATH="/opt/homebrew/opt/bison/bin:$PATH"' >> ~/.zshrc
|
||||
```
|
||||
|
||||
@@ -43,16 +59,13 @@ Then run the configure script:
|
||||
|
||||
```console
|
||||
./configure \
|
||||
--enable-embed=static \
|
||||
--enable-embed \
|
||||
--enable-zts \
|
||||
--disable-zend-signals \
|
||||
--disable-opcache-jit \
|
||||
--enable-static \
|
||||
--enable-shared=no \
|
||||
--with-iconv=/opt/homebrew/opt/libiconv/
|
||||
```
|
||||
|
||||
## Compile PHP
|
||||
#### Compile PHP
|
||||
|
||||
Finally, compile and install PHP:
|
||||
|
||||
@@ -73,17 +86,12 @@ Alternatively, these features can be disabled by passing build tags to the Go co
|
||||
|
||||
## Compile the Go App
|
||||
|
||||
You can now build the final binary:
|
||||
|
||||
```console
|
||||
curl -L https://github.com/dunglas/frankenphp/archive/refs/heads/main.tar.gz | tar xz
|
||||
cd frankenphp-main/caddy/frankenphp
|
||||
CGO_CFLAGS=$(php-config --includes) CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" go build -tags=nobadger,nomysql,nopgx
|
||||
```
|
||||
You can now build the final binary.
|
||||
|
||||
### Using xcaddy
|
||||
|
||||
Alternatively, use [xcaddy](https://github.com/caddyserver/xcaddy) to compile FrankenPHP with [custom Caddy modules](https://caddyserver.com/docs/modules/):
|
||||
The recommended way is to use [xcaddy](https://github.com/caddyserver/xcaddy) to compile FrankenPHP.
|
||||
`xcaddy` also allows to easily add [custom Caddy modules](https://caddyserver.com/docs/modules/) and FrankenPHP extensions:
|
||||
|
||||
```console
|
||||
CGO_ENABLED=1 \
|
||||
@@ -92,10 +100,10 @@ CGO_CFLAGS=$(php-config --includes) \
|
||||
CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" \
|
||||
xcaddy build \
|
||||
--output frankenphp \
|
||||
--with github.com/dunglas/frankenphp/caddy \
|
||||
--with frankenphp.dev/caddy \
|
||||
--with github.com/dunglas/mercure/caddy \
|
||||
--with github.com/dunglas/vulcain/caddy
|
||||
# Add extra Caddy modules here
|
||||
# Add extra Caddy modules and FrankenPHP extensions here
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
@@ -107,3 +115,13 @@ xcaddy build \
|
||||
> To do so, change the `XCADDY_GO_BUILD_FLAGS` environment variable to something like
|
||||
> `XCADDY_GO_BUILD_FLAGS=$'-ldflags "-w -s -extldflags \'-Wl,-z,stack-size=0x80000\'"'`
|
||||
> (change the stack size value according to your app needs).
|
||||
|
||||
### Without xcaddy
|
||||
|
||||
Alternatively, it's possible to compile FrankenPHP without `xcaddy` by using the `go` command directly:
|
||||
|
||||
```console
|
||||
curl -L https://github.com/dunglas/frankenphp/archive/refs/heads/main.tar.gz | tar xz
|
||||
cd frankenphp-main/caddy/frankenphp
|
||||
CGO_CFLAGS=$(php-config --includes) CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" go build -tags=nobadger,nomysql,nopgx
|
||||
```
|
||||
|
||||
103
docs/config.md
103
docs/config.md
@@ -2,16 +2,20 @@
|
||||
|
||||
FrankenPHP, Caddy as well as the Mercure and Vulcain modules can be configured using [the formats supported by Caddy](https://caddyserver.com/docs/getting-started#your-first-config).
|
||||
|
||||
In [the Docker images](docker.md), the `Caddyfile` is located at `/etc/caddy/Caddyfile`.
|
||||
The static binary will look for the `Caddyfile` in the directory in which it is started.
|
||||
In [the Docker images](docker.md), the `Caddyfile` is located at `/etc/frankenphp/Caddyfile`.
|
||||
The static binary will also look for the `Caddyfile` in the directory where the `frankenphp run` command is executed.
|
||||
You can specify a custom path with the `-c` or `--config` option.
|
||||
|
||||
PHP itself can be configured [using a `php.ini` file](https://www.php.net/manual/en/configuration.file.php).
|
||||
|
||||
By default, PHP supplied with Docker images and the one included in the static binary will look for a `php.ini` file in the directory where FrankenPHP is started and in `/usr/local/etc/php/`. They will also load all files ending in `.ini` from `/usr/local/etc/php/conf.d/`.
|
||||
Depending on your installation method, the PHP interpreter will look for configuration files in locations described above.
|
||||
|
||||
No `php.ini` file is present by default, you should copy an official template provided by the PHP project.
|
||||
## Docker
|
||||
|
||||
On Docker, the templates are provided in the images:
|
||||
- `php.ini`: `/usr/local/etc/php/php.ini` (no `php.ini` is provided by default)
|
||||
- additional configuration files: `/usr/local/etc/php/conf.d/*.ini`
|
||||
- PHP extensions: `/usr/local/lib/php/extensions/no-debug-zts-<YYYYMMDD>/`
|
||||
- You should copy an official template provided by the PHP project:
|
||||
|
||||
```dockerfile
|
||||
FROM dunglas/frankenphp
|
||||
@@ -23,20 +27,26 @@ RUN cp $PHP_INI_DIR/php.ini-production $PHP_INI_DIR/php.ini
|
||||
RUN cp $PHP_INI_DIR/php.ini-development $PHP_INI_DIR/php.ini
|
||||
```
|
||||
|
||||
If you don't use Docker, copy one of `php.ini-production` or `php.ini-development` provided [in the PHP sources](https://github.com/php/php-src/).
|
||||
## RPM and Debian packages
|
||||
|
||||
- `php.ini`: `/etc/frankenphp/php.ini` (a `php.ini` file with production presets is provided by default)
|
||||
- additional configuration files: `/etc/frankenphp/php.d/*.ini`
|
||||
- PHP extensions: `/usr/lib/frankenphp/modules/`
|
||||
|
||||
## Static binary
|
||||
|
||||
- `php.ini`: The directory in which `frankenphp run` or `frankenphp php-server` is executed, then `/etc/frankenphp/php.ini`
|
||||
- additional configuration files: `/etc/frankenphp/php.d/*.ini`
|
||||
- PHP extensions: cannot be loaded, bundle them in the binary itself
|
||||
- copy one of `php.ini-production` or `php.ini-development` provided [in the PHP sources](https://github.com/php/php-src/).
|
||||
|
||||
## Caddyfile Config
|
||||
|
||||
To register the FrankenPHP executor, the `frankenphp` [global option](https://caddyserver.com/docs/caddyfile/concepts#global-options) must be set, then the `php_server` or the `php` [HTTP directives](https://caddyserver.com/docs/caddyfile/concepts#directives) may be used within the site blocks to serve your PHP app.
|
||||
The `php_server` or the `php` [HTTP directives](https://caddyserver.com/docs/caddyfile/concepts#directives) may be used within the site blocks to serve your PHP app.
|
||||
|
||||
Minimal example:
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
# Enable FrankenPHP
|
||||
frankenphp
|
||||
}
|
||||
|
||||
localhost {
|
||||
# Enable compression (optional)
|
||||
encode zstd br gzip
|
||||
@@ -45,17 +55,22 @@ localhost {
|
||||
}
|
||||
```
|
||||
|
||||
Optionally, the number of threads to create and [worker scripts](worker.md) to start with the server can be specified under the global option.
|
||||
You can also explicitly configure FrankenPHP using the global option:
|
||||
The `frankenphp` [global option](https://caddyserver.com/docs/caddyfile/concepts#global-options) can be used to configure FrankenPHP.
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
frankenphp {
|
||||
num_threads <num_threads> # Sets the number of PHP threads to start. Default: 2x the number of available CPUs.
|
||||
max_threads <num_threads> # Limits the number of additional PHP threads that can be started at runtime. Default: num_threads. Can be set to 'auto'.
|
||||
max_wait_time <duration> # Sets the maximum time a request may wait for a free PHP thread before timing out. Default: disabled.
|
||||
php_ini <key> <value> # Set a php.ini directive. Can be used several times to set multiple directives.
|
||||
worker {
|
||||
file <path> # Sets the path to the worker script.
|
||||
num <num> # Sets the number of PHP threads to start, defaults to 2x the number of available CPUs.
|
||||
env <key> <value> # Sets an extra environment variable to the given value. Can be specified more than once for multiple environment variables.
|
||||
watch <path> # Sets the path to watch for file changes. Can be specified more than once for multiple paths.
|
||||
name <name> # Sets the name of the worker, used in logs and metrics. Default: absolute path of worker file
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,28 +93,27 @@ Alternatively, you may use the one-line short form of the `worker` option:
|
||||
You can also define multiple workers if you serve multiple apps on the same server:
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
frankenphp {
|
||||
worker /path/to/app/public/index.php <num>
|
||||
worker /path/to/other/public/index.php <num>
|
||||
app.example.com {
|
||||
php_server {
|
||||
root /path/to/app/public
|
||||
worker index.php <num>
|
||||
}
|
||||
}
|
||||
|
||||
app.example.com {
|
||||
root * /path/to/app/public
|
||||
php_server
|
||||
}
|
||||
|
||||
other.example.com {
|
||||
root * /path/to/other/public
|
||||
php_server
|
||||
php_server {
|
||||
root /path/to/other/public
|
||||
worker index.php <num>
|
||||
}
|
||||
}
|
||||
|
||||
# ...
|
||||
```
|
||||
|
||||
Using the `php_server` directive is generally what you need,
|
||||
but if you need full control, you can use the lower level `php` directive:
|
||||
but if you need full control, you can use the lower-level `php` directive.
|
||||
The `php` directive passes all input to PHP, instead of first checking whether
|
||||
it's a PHP file or not. Read more about it in the [performance page](performance.md).
|
||||
|
||||
Using the `php_server` directive is equivalent to this configuration:
|
||||
|
||||
@@ -133,6 +147,14 @@ php_server [<matcher>] {
|
||||
resolve_root_symlink false # Disables resolving the `root` directory to its actual value by evaluating a symbolic link, if one exists (enabled by default).
|
||||
env <key> <value> # Sets an extra environment variable to the given value. Can be specified more than once for multiple environment variables.
|
||||
file_server off # Disables the built-in file_server directive.
|
||||
worker { # Creates a worker specific to this server. Can be specified more than once for multiple workers.
|
||||
file <path> # Sets the path to the worker script, can be relative to the php_server root
|
||||
num <num> # Sets the number of PHP threads to start, defaults to 2x the number of available
|
||||
name <name> # Sets the name for the worker, used in logs and metrics. Default: absolute path of worker file. Always starts with m# when defined in a php_server block.
|
||||
watch <path> # Sets the path to watch for file changes. Can be specified more than once for multiple paths.
|
||||
env <key> <value> # Sets an extra environment variable to the given value. Can be specified more than once for multiple environment variables. Environment variables for this worker are also inherited from the php_server parent, but can be overwritten here.
|
||||
}
|
||||
worker <other_file> <num> # Can also use the short form like in the global frankenphp block.
|
||||
}
|
||||
```
|
||||
|
||||
@@ -174,10 +196,10 @@ where the FrankenPHP process was started. You can instead also specify one or mo
|
||||
}
|
||||
```
|
||||
|
||||
* The `**` pattern signifies recursive watching
|
||||
* Directories can also be relative (to where the FrankenPHP process is started from)
|
||||
* If you have multiple workers defined, all of them will be restarted when a file changes
|
||||
* Be wary about watching files that are created at runtime (like logs) since they might cause unwanted worker restarts.
|
||||
- The `**` pattern signifies recursive watching
|
||||
- Directories can also be relative (to where the FrankenPHP process is started from)
|
||||
- If you have multiple workers defined, all of them will be restarted when a file changes
|
||||
- Be wary about watching files that are created at runtime (like logs) since they might cause unwanted worker restarts.
|
||||
|
||||
The file watcher is based on [e-dant/watcher](https://github.com/e-dant/watcher).
|
||||
|
||||
@@ -213,9 +235,9 @@ You can find more information about this setting in the [Caddy documentation](ht
|
||||
|
||||
The following environment variables can be used to inject Caddy directives in the `Caddyfile` without modifying it:
|
||||
|
||||
* `SERVER_NAME`: change [the addresses on which to listen](https://caddyserver.com/docs/caddyfile/concepts#addresses), the provided hostnames will also be used for the generated TLS certificate
|
||||
* `CADDY_GLOBAL_OPTIONS`: inject [global options](https://caddyserver.com/docs/caddyfile/options)
|
||||
* `FRANKENPHP_CONFIG`: inject config under the `frankenphp` directive
|
||||
- `SERVER_NAME`: change [the addresses on which to listen](https://caddyserver.com/docs/caddyfile/concepts#addresses), the provided hostnames will also be used for the generated TLS certificate
|
||||
- `CADDY_GLOBAL_OPTIONS`: inject [global options](https://caddyserver.com/docs/caddyfile/options)
|
||||
- `FRANKENPHP_CONFIG`: inject config under the `frankenphp` directive
|
||||
|
||||
As for FPM and CLI SAPIs, environment variables are exposed by default in the `$_SERVER` superglobal.
|
||||
|
||||
@@ -227,6 +249,23 @@ To load [additional PHP configuration files](https://www.php.net/manual/en/confi
|
||||
the `PHP_INI_SCAN_DIR` environment variable can be used.
|
||||
When set, PHP will load all the file with the `.ini` extension present in the given directories.
|
||||
|
||||
You can also change the PHP configuration using the `php_ini` directive in the `Caddyfile`:
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
frankenphp {
|
||||
php_ini memory_limit 256M
|
||||
|
||||
# or
|
||||
|
||||
php_ini {
|
||||
memory_limit 256M
|
||||
max_execution_time 15
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Enable the Debug Mode
|
||||
|
||||
When using the Docker image, set the `CADDY_GLOBAL_OPTIONS` environment variable to `debug` to enable the debug mode:
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 126 KiB After Width: | Height: | Size: 73 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 159 KiB After Width: | Height: | Size: 87 KiB |
@@ -6,8 +6,8 @@ Variants for PHP 8.2, 8.3 and 8.4 are provided.
|
||||
|
||||
The tags follow this pattern: `dunglas/frankenphp:<frankenphp-version>-php<php-version>-<os>`
|
||||
|
||||
* `<frankenphp-version>` and `<php-version>` are version numbers of FrankenPHP and PHP respectively, ranging from major (e.g. `1`), minor (e.g. `1.2`) to patch versions (e.g. `1.2.3`).
|
||||
* `<os>` is either `bookworm` (for Debian Bookworm) or `alpine` (for the latest stable version of Alpine).
|
||||
- `<frankenphp-version>` and `<php-version>` are version numbers of FrankenPHP and PHP respectively, ranging from major (e.g. `1`), minor (e.g. `1.2`) to patch versions (e.g. `1.2.3`).
|
||||
- `<os>` is either `bookworm` (for Debian Bookworm) or `alpine` (for the latest stable version of Alpine).
|
||||
|
||||
[Browse tags](https://hub.docker.com/r/dunglas/frankenphp/tags).
|
||||
|
||||
@@ -65,8 +65,8 @@ RUN CGO_ENABLED=1 \
|
||||
CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" \
|
||||
xcaddy build \
|
||||
--output /usr/local/bin/frankenphp \
|
||||
--with github.com/dunglas/frankenphp=./ \
|
||||
--with github.com/dunglas/frankenphp/caddy=./caddy/ \
|
||||
--with frankenphp.dev=./ \
|
||||
--with frankenphp.dev/caddy=./caddy/ \
|
||||
--with github.com/dunglas/caddy-cbrotli \
|
||||
# Mercure and Vulcain are included in the official build, but feel free to remove them
|
||||
--with github.com/dunglas/mercure/caddy \
|
||||
@@ -193,8 +193,8 @@ Example: `:8000`
|
||||
|
||||
The Docker images are built:
|
||||
|
||||
* when a new release is tagged
|
||||
* daily at 4 am UTC, if new versions of the official PHP images are available
|
||||
- when a new release is tagged
|
||||
- daily at 4 am UTC, if new versions of the official PHP images are available
|
||||
|
||||
## Development Versions
|
||||
|
||||
|
||||
@@ -14,10 +14,10 @@ Before creating the self-contained binary be sure that your app is ready for emb
|
||||
|
||||
For instance, you likely want to:
|
||||
|
||||
* Install the production dependencies of the app
|
||||
* Dump the autoloader
|
||||
* Enable the production mode of your application (if any)
|
||||
* Strip unneeded files such as `.git` or tests to reduce the size of your final binary
|
||||
- Install the production dependencies of the app
|
||||
- Dump the autoloader
|
||||
- Enable the production mode of your application (if any)
|
||||
- Strip unneeded files such as `.git` or tests to reduce the size of your final binary
|
||||
|
||||
For instance, for a Symfony app, you can use the following commands:
|
||||
|
||||
@@ -53,34 +53,34 @@ The easiest way to create a Linux binary is to use the Docker-based builder we p
|
||||
|
||||
1. Create a file named `static-build.Dockerfile` in the repository of your app:
|
||||
|
||||
```dockerfile
|
||||
FROM --platform=linux/amd64 dunglas/frankenphp:static-builder
|
||||
```dockerfile
|
||||
FROM --platform=linux/amd64 dunglas/frankenphp:static-builder
|
||||
|
||||
# Copy your app
|
||||
WORKDIR /go/src/app/dist/app
|
||||
COPY . .
|
||||
# Copy your app
|
||||
WORKDIR /go/src/app/dist/app
|
||||
COPY . .
|
||||
|
||||
# Build the static binary
|
||||
WORKDIR /go/src/app/
|
||||
RUN EMBED=dist/app/ ./build-static.sh
|
||||
```
|
||||
# Build the static binary
|
||||
WORKDIR /go/src/app/
|
||||
RUN EMBED=dist/app/ ./build-static.sh
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
>
|
||||
> Some `.dockerignore` files (e.g. default [Symfony Docker `.dockerignore`](https://github.com/dunglas/symfony-docker/blob/main/.dockerignore))
|
||||
> will ignore the `vendor/` directory and `.env` files. Be sure to adjust or remove the `.dockerignore` file before the build.
|
||||
> [!CAUTION]
|
||||
>
|
||||
> Some `.dockerignore` files (e.g. default [Symfony Docker `.dockerignore`](https://github.com/dunglas/symfony-docker/blob/main/.dockerignore))
|
||||
> will ignore the `vendor/` directory and `.env` files. Be sure to adjust or remove the `.dockerignore` file before the build.
|
||||
|
||||
2. Build:
|
||||
|
||||
```console
|
||||
docker build -t static-app -f static-build.Dockerfile .
|
||||
```
|
||||
```console
|
||||
docker build -t static-app -f static-build.Dockerfile .
|
||||
```
|
||||
|
||||
3. Extract the binary:
|
||||
|
||||
```console
|
||||
docker cp $(docker create --name static-app-tmp static-app):/go/src/app/dist/frankenphp-linux-x86_64 my-app ; docker rm static-app-tmp
|
||||
```
|
||||
```console
|
||||
docker cp $(docker create --name static-app-tmp static-app):/go/src/app/dist/frankenphp-linux-x86_64 my-app ; docker rm static-app-tmp
|
||||
```
|
||||
|
||||
The resulting binary is the file named `my-app` in the current directory.
|
||||
|
||||
|
||||
@@ -11,9 +11,13 @@ docker build -t frankenphp-dev -f dev.Dockerfile .
|
||||
docker run --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -p 8080:8080 -p 443:443 -p 443:443/udp -v $PWD:/go/src/app -it frankenphp-dev
|
||||
```
|
||||
|
||||
L'image contient les outils de développement habituels (Go, GDB, Valgrind, Neovim...).
|
||||
L'image contient les outils de développement habituels (Go, GDB, Valgrind, Neovim...) et utilise les emplacements de configuration PHP suivants
|
||||
|
||||
Si la version de Docker est inférieure à 23.0, la construction échoue à cause d'un [problème de pattern](https://github.com/moby/moby/pull/42676) dans `.dockerignore`. Ajoutez les répertoires à `.dockerignore`.
|
||||
- php.ini: `/etc/frankenphp/php.ini` Un fichier php.ini avec des préréglages de développement est fourni par défaut.
|
||||
- fichiers de configuration supplémentaires: `/etc/frankenphp/php.d/*.ini`
|
||||
- extensions php: `/usr/lib/frankenphp/modules/`
|
||||
|
||||
Si votre version de Docker est inférieure à 23.0, la construction échouera à cause d'un [problème de pattern](https://github.com/moby/moby/pull/42676) dans `.dockerignore`. Ajoutez les répertoires à `.dockerignore`.
|
||||
|
||||
```patch
|
||||
!testdata/*.php
|
||||
@@ -38,7 +42,7 @@ Construire Caddy avec le module FrankenPHP :
|
||||
|
||||
```console
|
||||
cd caddy/frankenphp/
|
||||
go build
|
||||
go build -tags watcher,brotli,nobadger,nomysql,nopgx
|
||||
cd ../../
|
||||
```
|
||||
|
||||
@@ -49,10 +53,14 @@ cd testdata/
|
||||
../caddy/frankenphp/frankenphp run
|
||||
```
|
||||
|
||||
Le serveur est configuré pour écouter à l'adresse `127.0.0.1:8080`:
|
||||
Le serveur est configuré pour écouter à l'adresse `127.0.0.1:80`:
|
||||
|
||||
> [!NOTE]
|
||||
>
|
||||
> Si vous utilisez Docker, vous devrez soit lier le port 80 du conteneur, soit exécuter depuis l'intérieur du conteneur.
|
||||
|
||||
```console
|
||||
curl -vk https://localhost/phpinfo.php
|
||||
curl -vk http://127.0.0.1/phpinfo.php
|
||||
```
|
||||
|
||||
## Serveur de test minimal
|
||||
@@ -104,69 +112,92 @@ Construire à partir de zéro les images FrankenPHP pour arm64 & amd64 et les po
|
||||
docker buildx bake -f docker-bake.hcl --pull --no-cache --push
|
||||
```
|
||||
|
||||
## Déboguer les erreurs de segmentation avec les builds statiques
|
||||
|
||||
1. Téléchargez la version de débogage du binaire FrankenPHP depuis GitHub ou créez votre propre build statique incluant des symboles de débogage :
|
||||
|
||||
```console
|
||||
docker buildx bake \
|
||||
--load \
|
||||
--set static-builder.args.DEBUG_SYMBOLS=1 \
|
||||
--set "static-builder.platform=linux/amd64" \
|
||||
static-builder
|
||||
docker cp $(docker create --name static-builder-musl dunglas/frankenphp:static-builder-musl):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp
|
||||
```
|
||||
|
||||
2. Remplacez votre version actuelle de `frankenphp` par l'exécutable de débogage de FrankenPHP.
|
||||
3. Démarrez FrankenPHP comme d'habitude (alternativement, vous pouvez directement démarrer FrankenPHP avec GDB : `gdb --args frankenphp run`).
|
||||
4. Attachez-vous au processus avec GDB :
|
||||
|
||||
```console
|
||||
gdb -p `pidof frankenphp`
|
||||
```
|
||||
|
||||
5. Si nécessaire, tapez `continue` dans le shell GDB
|
||||
6. Faites planter FrankenPHP.
|
||||
7. Tapez `bt` dans le shell GDB
|
||||
8. Copiez la sortie
|
||||
|
||||
## Déboguer les erreurs de segmentation dans GitHub Actions
|
||||
|
||||
1. Ouvrir `.github/workflows/tests.yml`
|
||||
2. Activer les symboles de débogage de la bibliothèque PHP
|
||||
|
||||
```patch
|
||||
- uses: shivammathur/setup-php@v2
|
||||
# ...
|
||||
env:
|
||||
phpts: ts
|
||||
+ debug: true
|
||||
```
|
||||
```patch
|
||||
- uses: shivammathur/setup-php@v2
|
||||
# ...
|
||||
env:
|
||||
phpts: ts
|
||||
+ debug: true
|
||||
```
|
||||
|
||||
3. Activer `tmate` pour se connecter au conteneur
|
||||
|
||||
```patch
|
||||
-
|
||||
name: Set CGO flags
|
||||
run: echo "CGO_CFLAGS=$(php-config --includes)" >> "$GITHUB_ENV"
|
||||
+ -
|
||||
+ run: |
|
||||
+ sudo apt install gdb
|
||||
+ mkdir -p /home/runner/.config/gdb/
|
||||
+ printf "set auto-load safe-path /\nhandle SIG34 nostop noprint pass" > /home/runner/.config/gdb/gdbinit
|
||||
+ -
|
||||
+ uses: mxschmitt/action-tmate@v3
|
||||
```
|
||||
```patch
|
||||
- name: Set CGO flags
|
||||
run: echo "CGO_CFLAGS=$(php-config --includes)" >> "$GITHUB_ENV"
|
||||
+ - run: |
|
||||
+ sudo apt install gdb
|
||||
+ mkdir -p /home/runner/.config/gdb/
|
||||
+ printf "set auto-load safe-path /\nhandle SIG34 nostop noprint pass" > /home/runner/.config/gdb/gdbinit
|
||||
+ - uses: mxschmitt/action-tmate@v3
|
||||
```
|
||||
|
||||
4. Se connecter au conteneur
|
||||
5. Ouvrir `frankenphp.go`
|
||||
6. Activer `cgosymbolizer`
|
||||
|
||||
```patch
|
||||
- //_ "github.com/ianlancetaylor/cgosymbolizer"
|
||||
+ _ "github.com/ianlancetaylor/cgosymbolizer"
|
||||
```
|
||||
```patch
|
||||
- //_ "github.com/ianlancetaylor/cgosymbolizer"
|
||||
+ _ "github.com/ianlancetaylor/cgosymbolizer"
|
||||
```
|
||||
|
||||
7. Télécharger le module : `go get`
|
||||
8. Dans le conteneur, vous pouvez utiliser GDB et similaires :
|
||||
|
||||
```console
|
||||
go test -tags watcher -c -ldflags=-w
|
||||
gdb --args frankenphp.test -test.run ^MyTest$
|
||||
```
|
||||
```console
|
||||
go test -tags watcher -c -ldflags=-w
|
||||
gdb --args frankenphp.dev.test -test.run ^MyTest$
|
||||
```
|
||||
|
||||
9. Quand le bug est corrigé, annulez tous les changements
|
||||
9. Quand le bug est corrigé, annulez tous les changements.
|
||||
|
||||
## Ressources Diverses pour le Développement
|
||||
|
||||
* [Intégration de PHP dans uWSGI](https://github.com/unbit/uwsgi/blob/master/plugins/php/php_plugin.c)
|
||||
* [Intégration de PHP dans NGINX Unit](https://github.com/nginx/unit/blob/master/src/nxt_php_sapi.c)
|
||||
* [Intégration de PHP dans Go (go-php)](https://github.com/deuill/go-php)
|
||||
* [Intégration de PHP dans Go (GoEmPHP)](https://github.com/mikespook/goemphp)
|
||||
* [Intégration de PHP dans C++](https://gist.github.com/paresy/3cbd4c6a469511ac7479aa0e7c42fea7)
|
||||
* [Extending and Embedding PHP par Sara Golemon](https://books.google.fr/books?id=zMbGvK17_tYC&pg=PA254&lpg=PA254#v=onepage&q&f=false)
|
||||
* [Qu'est-ce que TSRMLS_CC, au juste ?](http://blog.golemon.com/2006/06/what-heck-is-tsrmlscc-anyway.html)
|
||||
* [Intégration de PHP sur Mac](https://gist.github.com/jonnywang/61427ffc0e8dde74fff40f479d147db4)
|
||||
* [Bindings SDL](https://pkg.go.dev/github.com/veandco/go-sdl2@v0.4.21/sdl#Main)
|
||||
- [Intégration de PHP dans uWSGI](https://github.com/unbit/uwsgi/blob/master/plugins/php/php_plugin.c)
|
||||
- [Intégration de PHP dans NGINX Unit](https://github.com/nginx/unit/blob/master/src/nxt_php_sapi.c)
|
||||
- [Intégration de PHP dans Go (go-php)](https://github.com/deuill/go-php)
|
||||
- [Intégration de PHP dans Go (GoEmPHP)](https://github.com/mikespook/goemphp)
|
||||
- [Intégration de PHP dans C++](https://gist.github.com/paresy/3cbd4c6a469511ac7479aa0e7c42fea7)
|
||||
- [Extending and Embedding PHP par Sara Golemon](https://books.google.fr/books?id=zMbGvK17_tYC&pg=PA254&lpg=PA254#v=onepage&q&f=false)
|
||||
- [Qu'est-ce que TSRMLS_CC, au juste ?](http://blog.golemon.com/2006/06/what-heck-is-tsrmlscc-anyway.html)
|
||||
- [Intégration de PHP sur Mac](https://gist.github.com/jonnywang/61427ffc0e8dde74fff40f479d147db4)
|
||||
- [Bindings SDL](https://pkg.go.dev/github.com/veandco/go-sdl2@v0.4.21/sdl#Main)
|
||||
|
||||
## Ressources Liées à Docker
|
||||
|
||||
* [Définition du fichier Bake](https://docs.docker.com/build/customize/bake/file-definition/)
|
||||
* [docker buildx build](https://docs.docker.com/engine/reference/commandline/buildx_build/)
|
||||
- [Définition du fichier Bake](https://docs.docker.com/build/customize/bake/file-definition/)
|
||||
- [docker buildx build](https://docs.docker.com/engine/reference/commandline/buildx_build/)
|
||||
|
||||
## Commande utile
|
||||
|
||||
@@ -174,3 +205,16 @@ docker buildx bake -f docker-bake.hcl --pull --no-cache --push
|
||||
apk add strace util-linux gdb
|
||||
strace -e 'trace=!futex,epoll_ctl,epoll_pwait,tgkill,rt_sigreturn' -p 1
|
||||
```
|
||||
|
||||
## Traduire la documentation
|
||||
|
||||
Pour traduire la documentation et le site dans une nouvelle langue, procédez comme suit :
|
||||
|
||||
1. Créez un nouveau répertoire nommé avec le code ISO à 2 caractères de la langue dans le répertoire `docs/` de ce dépôt
|
||||
2. Copiez tous les fichiers `.md` à la racine du répertoire `docs/` dans le nouveau répertoire (utilisez toujours la version anglaise comme source de traduction, car elle est toujours à jour).
|
||||
3. Copiez les fichiers `README.md` et `CONTRIBUTING.md` du répertoire racine vers le nouveau répertoire.
|
||||
4. Traduisez le contenu des fichiers, mais ne changez pas les noms de fichiers, ne traduisez pas non plus les chaînes commençant par `> [!` (c'est un balisage spécial pour GitHub).
|
||||
5. Créez une Pull Request avec les traductions
|
||||
6. Dans le [référentiel du site](https://github.com/dunglas/frankenphp-website/tree/main), copiez et traduisez les fichiers de traduction dans les répertoires `content/`, `data/` et `i18n/`.
|
||||
7. Traduire les valeurs dans le fichier YAML créé.
|
||||
8. Ouvrir une Pull Request sur le dépôt du site.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
FrankenPHP est un serveur d'applications moderne pour PHP construit à partir du serveur web [Caddy](https://caddyserver.com/).
|
||||
|
||||
FrankenPHP donne des super-pouvoirs à vos applications PHP grâce à ses fonctionnalités à la pointe : [*Early Hints*](early-hints.md), [mode worker](worker.md), [fonctionnalités en temps réel](mercure.md), HTTPS automatique, prise en charge de HTTP/2 et HTTP/3...
|
||||
FrankenPHP donne des super-pouvoirs à vos applications PHP grâce à ses fonctionnalités à la pointe : [_Early Hints_](early-hints.md), [mode worker](worker.md), [fonctionnalités en temps réel](mercure.md), HTTPS automatique, prise en charge de HTTP/2 et HTTP/3...
|
||||
|
||||
FrankenPHP fonctionne avec n'importe quelle application PHP et rend vos projets Laravel et Symfony plus rapides que jamais grâce à leurs intégrations officielles avec le mode worker.
|
||||
|
||||
@@ -16,21 +16,6 @@ Découvrez plus de détails sur ce serveur d’application dans le replay de cet
|
||||
|
||||
## Pour Commencer
|
||||
|
||||
### Docker
|
||||
|
||||
```console
|
||||
docker run -v $PWD:/app/public \
|
||||
-p 80:80 -p 443:443 -p 443:443/udp \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
|
||||
Rendez-vous sur `https://localhost`, c'est parti !
|
||||
|
||||
> [!TIP]
|
||||
>
|
||||
> Ne tentez pas d'utiliser `https://127.0.0.1`. Utilisez `https://localhost` et acceptez le certificat auto-signé.
|
||||
> Utilisez [la variable d'environnement `SERVER_NAME`](config.md#variables-denvironnement) pour changer le domaine à utiliser.
|
||||
|
||||
### Binaire autonome
|
||||
|
||||
Si vous préférez ne pas utiliser Docker, nous fournissons des binaires autonomes de FrankenPHP pour Linux et macOS
|
||||
@@ -57,32 +42,68 @@ Vous pouvez également exécuter des scripts en ligne de commande avec :
|
||||
frankenphp php-cli /path/to/your/script.php
|
||||
```
|
||||
|
||||
### Docker
|
||||
|
||||
Des [images Docker](https://frankenphp.dev/docs/fr/docker/) sont également disponibles :
|
||||
|
||||
```console
|
||||
docker run -v .:/app/public \
|
||||
-p 80:80 -p 443:443 -p 443:443/udp \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
|
||||
Rendez-vous sur `https://localhost`, c'est parti !
|
||||
|
||||
> [!TIP]
|
||||
>
|
||||
> Ne tentez pas d'utiliser `https://127.0.0.1`. Utilisez `https://localhost` et acceptez le certificat auto-signé.
|
||||
> Utilisez [la variable d'environnement `SERVER_NAME`](config.md#variables-denvironnement) pour changer le domaine à utiliser.
|
||||
|
||||
### Homebrew
|
||||
|
||||
FrankenPHP est également disponible sous forme de paquet [Homebrew](https://brew.sh) pour macOS et Linux.
|
||||
|
||||
Pour l'installer :
|
||||
|
||||
```console
|
||||
brew install dunglas/frankenphp/frankenphp
|
||||
```
|
||||
|
||||
Pour servir le contenu du répertoire courant, exécutez :
|
||||
|
||||
```console
|
||||
frankenphp php-server
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
* [Le mode worker](worker.md)
|
||||
* [Le support des Early Hints (code de statut HTTP 103)](early-hints.md)
|
||||
* [Temps réel](mercure.md)
|
||||
* [Configuration](config.md)
|
||||
* [Images Docker](docker.md)
|
||||
* [Déploiement en production](production.md)
|
||||
* [Optimisation des performances](performance.md)
|
||||
* [Créer des applications PHP **standalone**, auto-exécutables](embed.md)
|
||||
* [Créer un build statique](static.md)
|
||||
* [Compiler depuis les sources](compile.md)
|
||||
* [Intégration Laravel](laravel.md)
|
||||
* [Problèmes connus](known-issues.md)
|
||||
* [Application de démo (Symfony) et benchmarks](https://github.com/dunglas/frankenphp-demo)
|
||||
* [Documentation de la bibliothèque Go](https://pkg.go.dev/github.com/dunglas/frankenphp)
|
||||
* [Contribuer et débugger](CONTRIBUTING.md)
|
||||
- [Le mode classique](classic.md)
|
||||
- [Le mode worker](worker.md)
|
||||
- [Le support des Early Hints (code de statut HTTP 103)](early-hints.md)
|
||||
- [Temps réel](mercure.md)
|
||||
- [Servir efficacement les fichiers statiques volumineux](x-sendfile.md)
|
||||
- [Configuration](config.md)
|
||||
- [Images Docker](docker.md)
|
||||
- [Déploiement en production](production.md)
|
||||
- [Optimisation des performances](performance.md)
|
||||
- [Créer des applications PHP **standalone**, auto-exécutables](embed.md)
|
||||
- [Créer un build statique](static.md)
|
||||
- [Compiler depuis les sources](compile.md)
|
||||
- [Surveillance de FrankenPHP](metrics.md)
|
||||
- [Intégration Laravel](laravel.md)
|
||||
- [Problèmes connus](known-issues.md)
|
||||
- [Application de démo (Symfony) et benchmarks](https://github.com/dunglas/frankenphp-demo)
|
||||
- [Documentation de la bibliothèque Go](https://pkg.go.dev/github.com/dunglas/frankenphp)
|
||||
- [Contribuer et débugger](CONTRIBUTING.md)
|
||||
|
||||
## Exemples et squelettes
|
||||
|
||||
* [Symfony](https://github.com/dunglas/symfony-docker)
|
||||
* [API Platform](https://api-platform.com/docs/distribution/)
|
||||
* [Laravel](laravel.md)
|
||||
* [Sulu](https://sulu.io/blog/running-sulu-with-frankenphp)
|
||||
* [WordPress](https://github.com/StephenMiracle/frankenwp)
|
||||
* [Drupal](https://github.com/dunglas/frankenphp-drupal)
|
||||
* [Joomla](https://github.com/alexandreelise/frankenphp-joomla)
|
||||
* [TYPO3](https://github.com/ochorocho/franken-typo3)
|
||||
* [Magento2](https://github.com/ekino/frankenphp-magento2)
|
||||
- [Symfony](https://github.com/dunglas/symfony-docker)
|
||||
- [API Platform](https://api-platform.com/docs/distribution/)
|
||||
- [Laravel](laravel.md)
|
||||
- [Sulu](https://sulu.io/blog/running-sulu-with-frankenphp)
|
||||
- [WordPress](https://github.com/StephenMiracle/frankenwp)
|
||||
- [Drupal](https://github.com/dunglas/frankenphp-drupal)
|
||||
- [Joomla](https://github.com/alexandreelise/frankenphp-joomla)
|
||||
- [TYPO3](https://github.com/ochorocho/franken-typo3)
|
||||
- [Magento2](https://github.com/ekino/frankenphp-magento2)
|
||||
|
||||
11
docs/fr/classic.md
Normal file
11
docs/fr/classic.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Utilisation du mode classique
|
||||
|
||||
Sans aucune configuration additionnelle, FrankenPHP fonctionne en mode classique. Dans ce mode, FrankenPHP fonctionne comme un serveur PHP traditionnel, en servant directement les fichiers PHP. Cela en fait un remplaçant parfait à PHP-FPM ou Apache avec mod_php.
|
||||
|
||||
Comme Caddy, FrankenPHP accepte un nombre illimité de connexions et utilise un [nombre fixe de threads](config.md#configuration-du-caddyfile) pour les servir. Le nombre de connexions acceptées et en attente n'est limité que par les ressources système disponibles.
|
||||
Le pool de threads PHP fonctionne avec un nombre fixe de threads initialisés au démarrage, comparable au mode statique de PHP-FPM. Il est également possible de laisser les threads [s'adapter automatiquement à l'exécution](performance.md#max_threads), comme dans le mode dynamique de PHP-FPM.
|
||||
|
||||
Les connexions en file d'attente attendront indéfiniment jusqu'à ce qu'un thread PHP soit disponible pour les servir. Pour éviter cela, vous pouvez utiliser la [configuration](config.md#configuration-du-caddyfile) `max_wait_time` pour limiter la durée pendant laquelle une requête peut attendre un thread PHP libre avant d'être rejetée.
|
||||
En outre, vous pouvez définir un [délai d'écriture dans Caddy](https://caddyserver.com/docs/caddyfile/options#timeouts) raisonnable.
|
||||
|
||||
Chaque instance de Caddy n'utilisera qu'un seul pool de threads FrankenPHP, qui sera partagé par tous les blocs `php_server`.
|
||||
@@ -9,6 +9,23 @@ Alternativement, il est aussi possible de [créer des builds statiques](static.m
|
||||
|
||||
FrankenPHP est compatible avec PHP 8.2 et versions ultérieures.
|
||||
|
||||
### Avec Homebrew (Linux et Mac)
|
||||
|
||||
La manière la plus simple d'installer une version de libphp compatible avec FrankenPHP est d'utiliser les paquets ZTS fournis par [Homebrew PHP](https://github.com/shivammathur/homebrew-php).
|
||||
|
||||
Tout d'abord, si ce n'est déjà fait, installez [Homebrew](https://brew.sh).
|
||||
|
||||
Ensuite, installez la variante ZTS de PHP, Brotli (facultatif, pour la prise en charge de la compression) et watcher (facultatif, pour la détection des modifications de fichiers) :
|
||||
|
||||
```console
|
||||
brew install shivammathur/php/php-zts brotli watcher
|
||||
brew link --overwrite --force shivammathur/php/php-zts
|
||||
```
|
||||
|
||||
### En compilant PHP
|
||||
|
||||
Vous pouvez également compiler PHP à partir des sources avec les options requises par FrankenPHP en suivant ces étapes.
|
||||
|
||||
Tout d'abord, [téléchargez les sources de PHP](https://www.php.net/downloads.php) et extrayez-les :
|
||||
|
||||
```console
|
||||
@@ -32,10 +49,10 @@ Les options de configuration suivantes sont nécessaires pour la compilation, ma
|
||||
|
||||
### Mac
|
||||
|
||||
Utilisez le gestionnaire de paquets [Homebrew](https://brew.sh/) pour installer `libiconv`, `bison`, `re2c` et `pkg-config` :
|
||||
Utilisez le gestionnaire de paquets [Homebrew](https://brew.sh/) pour installer les dépendances obligatoires et optionnelles :
|
||||
|
||||
```console
|
||||
brew install libiconv bison re2c pkg-config
|
||||
brew install libiconv bison brotli re2c pkg-config watcher
|
||||
echo 'export PATH="/opt/homebrew/opt/bison/bin:$PATH"' >> ~/.zshrc
|
||||
```
|
||||
|
||||
@@ -43,16 +60,14 @@ Puis exécutez le script de configuration :
|
||||
|
||||
```console
|
||||
./configure \
|
||||
--enable-embed=static \
|
||||
--enable-embed \
|
||||
--enable-zts \
|
||||
--disable-zend-signals \
|
||||
--disable-opcache-jit \
|
||||
--enable-static \
|
||||
--enable-shared=no \
|
||||
--with-iconv=/opt/homebrew/opt/libiconv/
|
||||
```
|
||||
|
||||
## Compilez PHP
|
||||
### Compilez PHP
|
||||
|
||||
Finalement, compilez et installez PHP :
|
||||
|
||||
@@ -61,30 +76,35 @@ make -j"$(getconf _NPROCESSORS_ONLN)"
|
||||
sudo make install
|
||||
```
|
||||
|
||||
## Installez les dépendances optionnelles
|
||||
|
||||
Certaines fonctionnalités de FrankenPHP nécessitent des dépendances optionnelles qui doivent être installées.
|
||||
Ces fonctionnalités peuvent également être désactivées en passant des tags de compilation au compilateur Go.
|
||||
|
||||
| Fonctionnalité | Dépendance | Tag de compilation pour la désactiver |
|
||||
|---------------------------------------------------------|-----------------------------------------------------------------------|---------------------------------------|
|
||||
| Compression Brotli | [Brotli](https://github.com/google/brotli) | nobrotli |
|
||||
| Redémarrage des workers en cas de changement de fichier | [Watcher C](https://github.com/e-dant/watcher/tree/release/watcher-c) | nowatcher |
|
||||
|
||||
## Compiler l'application Go
|
||||
|
||||
Vous pouvez maintenant compilez FrankenPHP :
|
||||
|
||||
```console
|
||||
curl -L https://github.com/dunglas/frankenphp/archive/refs/heads/main.tar.gz | tar xz
|
||||
cd frankenphp-main/caddy/frankenphp
|
||||
CGO_CFLAGS=$(php-config --includes) CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" go build
|
||||
```
|
||||
|
||||
### Utiliser xcaddy
|
||||
|
||||
Alternativement, Vous pouvez utiliser [xcaddy](https://github.com/caddyserver/xcaddy) pour compiler FrankenPHP avec [des modules Caddy additionnels](https://caddyserver.com/docs/modules/):
|
||||
La méthode recommandée consiste à utiliser [xcaddy](https://github.com/caddyserver/xcaddy) pour compiler FrankenPHP.
|
||||
`xcaddy` permet également d'ajouter facilement des [modules Caddy personnalisés](https://caddyserver.com/docs/modules/) et des extensions FrankenPHP :
|
||||
|
||||
```console
|
||||
CGO_ENABLED=1 \
|
||||
XCADDY_GO_BUILD_FLAGS="-ldflags '-w -s'" \
|
||||
XCADDY_GO_BUILD_FLAGS="-ldflags='-w -s' -tags=nobadger,nomysql,nopgx" \
|
||||
CGO_CFLAGS=$(php-config --includes) \
|
||||
CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" \
|
||||
xcaddy build \
|
||||
--output frankenphp \
|
||||
--with github.com/dunglas/frankenphp/caddy \
|
||||
--with frankenphp.dev/caddy \
|
||||
--with github.com/dunglas/caddy-cbrotli \
|
||||
--with github.com/dunglas/mercure/caddy \
|
||||
--with github.com/dunglas/vulcain/caddy
|
||||
# Add extra Caddy modules here
|
||||
# Ajoutez les modules Caddy supplémentaires et les extensions FrankenPHP ici
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
@@ -96,3 +116,13 @@ xcaddy build \
|
||||
> Pour ce faire, modifiez la variable d'environnement `XCADDY_GO_BUILD_FLAGS` en quelque chose comme
|
||||
> `XCADDY_GO_BUILD_FLAGS=$'-ldflags "-w -s -extldflags \'-Wl,-z,stack-size=0x80000\'"'`
|
||||
> (modifiez la valeur de la taille de la pile selon les besoins de votre application).
|
||||
|
||||
### Sans xcaddy
|
||||
|
||||
Il est également possible de compiler FrankenPHP sans `xcaddy` en utilisant directement la commande `go` :
|
||||
|
||||
```console
|
||||
curl -L https://github.com/dunglas/frankenphp/archive/refs/heads/main.tar.gz | tar xz
|
||||
cd frankenphp-main/caddy/frankenphp
|
||||
CGO_CFLAGS=$(php-config --includes) CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" go build -tags=nobadger,nomysql,nopgx
|
||||
```
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
# Configuration
|
||||
# Configuration
|
||||
|
||||
FrankenPHP, Caddy ainsi que les modules Mercure et Vulcain peuvent être configurés en utilisant [les formats pris en charge par Caddy](https://caddyserver.com/docs/getting-started#your-first-config).
|
||||
|
||||
Dans [les images Docker](docker.md), le `Caddyfile` est situé dans `/etc/caddy/Caddyfile`.
|
||||
Dans [les images Docker](docker.md), le `Caddyfile` est situé dans `/etc/frankenphp/Caddyfile`.
|
||||
Le binaire statique cherchera le `Caddyfile` dans le répertoire dans lequel il est démarré.
|
||||
|
||||
PHP lui-même peut être configuré [en utilisant un fichier `php.ini`](https://www.php.net/manual/fr/configuration.file.php).
|
||||
|
||||
Par défaut, le PHP fourni avec les images Docker et celui inclus dans le binaire statique cherchera un fichier `php.ini` dans le répertoire où FrankenPHP est démarré et dans `/usr/local/etc/php/`. Ils chargeront également tous les fichiers se terminant par `.ini` dans `/usr/local/etc/php/conf.d/`.
|
||||
L'interpréteur PHP cherchera dans les emplacements suivants :
|
||||
|
||||
Aucun fichier `php.ini` n'est présent par défaut, vous devriez copier un modèle officiel fourni par le projet PHP.
|
||||
Sur Docker, les modèles sont fournis dans les images :
|
||||
Docker :
|
||||
|
||||
- php.ini : `/usr/local/etc/php/php.ini` Aucun php.ini n'est fourni par défaut.
|
||||
- fichiers de configuration supplémentaires : `/usr/local/etc/php/conf.d/*.ini`
|
||||
- extensions php : `/usr/local/lib/php/extensions/no-debug-zts-<YYYYMMDD>/`
|
||||
- Vous devriez copier un modèle officiel fourni par le projet PHP :
|
||||
|
||||
```dockerfile
|
||||
FROM dunglas/frankenphp
|
||||
@@ -21,40 +26,52 @@ RUN cp $PHP_INI_DIR/php.ini-production $PHP_INI_DIR/php.ini
|
||||
RUN cp $PHP_INI_DIR/php.ini-development $PHP_INI_DIR/php.ini
|
||||
```
|
||||
|
||||
Si vous n'utilisez pas Docker, copiez l'un des fichiers `php.ini-production` ou `php.ini-development` fournis [dans les sources de PHP](https://github.com/php/php-src/).
|
||||
Installation de FrankenPHP (.rpm ou .deb) :
|
||||
|
||||
- php.ini : `/etc/frankenphp/php.ini` Un fichier php.ini avec des préréglages de production est fourni par défaut.
|
||||
- fichiers de configuration supplémentaires : `/etc/frankenphp/php.d/*.ini`
|
||||
- extensions php : `/usr/lib/frankenphp/modules/`
|
||||
|
||||
Binaire statique :
|
||||
|
||||
- php.ini : Le répertoire dans lequel `frankenphp run` ou `frankenphp php-server` est exécuté, puis `/etc/frankenphp/php.ini`
|
||||
- fichiers de configuration supplémentaires : `/etc/frankenphp/php.d/*.ini`
|
||||
- extensions php : ne peuvent pas être chargées
|
||||
- copiez l'un des fichiers `php.ini-production` ou `php.ini-development` fournis [dans les sources de PHP](https://github.com/php/php-src/).
|
||||
|
||||
## Configuration du Caddyfile
|
||||
|
||||
Pour enregistrer l'exécutable de FrankenPHP, l'[option globale](https://caddyserver.com/docs/caddyfile/concepts#global-options) `frankenphp` doit être définie, puis les [directives HTTP](https://caddyserver.com/docs/caddyfile/concepts#directives) `php_server` ou `php` peuvent être utilisées dans les blocs de site pour servir votre application PHP.
|
||||
Les [directives HTTP](https://caddyserver.com/docs/caddyfile/concepts#directives) `php_server` ou `php` peuvent être utilisées dans les blocs de site pour servir votre application PHP.
|
||||
|
||||
Exemple minimal :
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
# Activer FrankenPHP
|
||||
frankenphp
|
||||
}
|
||||
|
||||
localhost {
|
||||
# Activer la compression (optionnel)
|
||||
encode zstd br gzip
|
||||
# Exécuter les fichiers PHP dans le répertoire courant et servir les assets
|
||||
php_server
|
||||
# Activer la compression (optionnel)
|
||||
encode zstd br gzip
|
||||
# Exécuter les fichiers PHP dans le répertoire courant et servir les assets
|
||||
php_server
|
||||
}
|
||||
```
|
||||
|
||||
En option, le nombre de threads à créer et les [workers](worker.md) à démarrer avec le serveur peuvent être spécifiés sous l'option globale.
|
||||
Vous pouvez également configurer explicitement FrankenPHP en utilisant l'option globale :
|
||||
L'[option globale](https://caddyserver.com/docs/caddyfile/concepts#global-options) `frankenphp` peut être utilisée pour configurer FrankenPHP.
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
frankenphp {
|
||||
num_threads <num_threads> # Définit le nombre de threads PHP à démarrer. Par défaut : 2x le nombre de CPUs disponibles.
|
||||
worker {
|
||||
file <path> # Définit le chemin vers le script worker.
|
||||
num <num> # Définit le nombre de threads PHP à démarrer, par défaut 2x le nombre de CPUs disponibles.
|
||||
env <key> <value> # Définit une variable d'environnement supplémentaire avec la valeur donnée. Peut être spécifié plusieurs fois pour régler plusieurs variables d'environnement.
|
||||
}
|
||||
}
|
||||
frankenphp {
|
||||
num_threads <num_threads> # Définit le nombre de threads PHP à démarrer. Par défaut : 2x le nombre de CPUs disponibles.
|
||||
max_threads <num_threads> # Limite le nombre de threads PHP supplémentaires qui peuvent être démarrés au moment de l'exécution. Valeur par défaut : num_threads. Peut être mis à 'auto'.
|
||||
max_wait_time <duration> # Définit le temps maximum pendant lequel une requête peut attendre un thread PHP libre avant d'être interrompue. Valeur par défaut : désactivé.
|
||||
php_ini <key> <value> Définit une directive php.ini. Peut être utilisé plusieurs fois pour définir plusieurs directives.
|
||||
worker {
|
||||
file <path> # Définit le chemin vers le script worker.
|
||||
num <num> # Définit le nombre de threads PHP à démarrer, par défaut 2x le nombre de CPUs disponibles.
|
||||
env <key> <value> # Définit une variable d'environnement supplémentaire avec la valeur donnée. Peut être spécifié plusieurs fois pour régler plusieurs variables d'environnement.
|
||||
watch <path> # Définit le chemin d'accès à surveiller pour les modifications de fichiers. Peut être spécifié plusieurs fois pour plusieurs chemins.
|
||||
name <name> # Définit le nom du worker, utilisé dans les journaux et les métriques. Défaut : chemin absolu du fichier du worker
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ...
|
||||
@@ -64,9 +81,9 @@ Vous pouvez également utiliser la forme courte de l'option worker en une seule
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
frankenphp {
|
||||
worker <file> <num>
|
||||
}
|
||||
frankenphp {
|
||||
worker <file> <num>
|
||||
}
|
||||
}
|
||||
|
||||
# ...
|
||||
@@ -75,21 +92,18 @@ Vous pouvez également utiliser la forme courte de l'option worker en une seule
|
||||
Vous pouvez aussi définir plusieurs workers si vous servez plusieurs applications sur le même serveur :
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
frankenphp {
|
||||
worker /path/to/app/public/index.php <num>
|
||||
worker /path/to/other/public/index.php <num>
|
||||
}
|
||||
}
|
||||
|
||||
app.example.com {
|
||||
root * /path/to/app/public
|
||||
php_server
|
||||
php_server {
|
||||
root /path/to/app/public
|
||||
worker index.php <num>
|
||||
}
|
||||
}
|
||||
|
||||
other.example.com {
|
||||
root * /path/to/other/public
|
||||
php_server
|
||||
php_server {
|
||||
root /path/to/other/public
|
||||
worker index.php <num>
|
||||
}
|
||||
}
|
||||
|
||||
# ...
|
||||
@@ -97,27 +111,29 @@ other.example.com {
|
||||
|
||||
L'utilisation de la directive `php_server` est généralement suffisante,
|
||||
mais si vous avez besoin d'un contrôle total, vous pouvez utiliser la directive `php`, qui permet un plus grand niveau de finesse dans la configuration.
|
||||
La directive `php` transmet toutes les entrées à PHP, au lieu de vérifier d'abord si
|
||||
c'est un fichier PHP ou pas. En savoir plus à ce sujet dans la [page performances](performance.md).
|
||||
|
||||
Utiliser la directive `php_server` est équivalent à cette configuration :
|
||||
|
||||
```caddyfile
|
||||
route {
|
||||
# Ajoute un slash final pour les requêtes de répertoire
|
||||
@canonicalPath {
|
||||
file {path}/index.php
|
||||
not path */
|
||||
}
|
||||
redir @canonicalPath {path}/ 308
|
||||
# Si le fichier demandé n'existe pas, essayer les fichiers index
|
||||
@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
|
||||
file_server
|
||||
# Ajoute un slash final pour les requêtes de répertoire
|
||||
@canonicalPath {
|
||||
file {path}/index.php
|
||||
not path */
|
||||
}
|
||||
redir @canonicalPath {path}/ 308
|
||||
# Si le fichier demandé n'existe pas, essayer les fichiers index
|
||||
@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
|
||||
file_server
|
||||
}
|
||||
```
|
||||
|
||||
@@ -125,20 +141,102 @@ Les directives `php_server` et `php` disposent des options suivantes :
|
||||
|
||||
```caddyfile
|
||||
php_server [<matcher>] {
|
||||
root <directory> # Définit le dossier racine du le site. Par défaut : valeur de la directive `root` parente.
|
||||
split_path <delim...> # Définit les sous-chaînes pour diviser l'URI en deux parties. La première sous-chaîne correspondante sera utilisée pour séparer le "path info" du chemin. La première partie est suffixée avec la sous-chaîne correspondante et sera considérée comme le nom réel de la ressource (script CGI). La seconde partie sera définie comme PATH_INFO pour utilisation par le script. Par défaut : `.php`
|
||||
resolve_root_symlink false # Désactive la résolution du répertoire `root` vers sa valeur réelle en évaluant un lien symbolique, s'il existe (activé par défaut).
|
||||
env <key> <value> # Définit une variable d'environnement supplémentaire avec la valeur donnée. Peut être spécifié plusieurs fois pour plusieurs variables d'environnement.
|
||||
root <directory> # Définit le dossier racine du le site. Par défaut : valeur de la directive `root` parente.
|
||||
split_path <delim...> # Définit les sous-chaînes pour diviser l'URI en deux parties. La première sous-chaîne correspondante sera utilisée pour séparer le "path info" du chemin. La première partie est suffixée avec la sous-chaîne correspondante et sera considérée comme le nom réel de la ressource (script CGI). La seconde partie sera définie comme PATH_INFO pour utilisation par le script. Par défaut : `.php`
|
||||
resolve_root_symlink false # Désactive la résolution du répertoire `root` vers sa valeur réelle en évaluant un lien symbolique, s'il existe (activé par défaut).
|
||||
env <key> <value> # Définit une variable d'environnement supplémentaire avec la valeur donnée. Peut être spécifié plusieurs fois pour plusieurs variables d'environnement.
|
||||
file_server off # Désactive la directive file_server intégrée.
|
||||
worker { # Crée un worker spécifique à ce serveur. Peut être spécifié plusieurs fois pour plusieurs workers.
|
||||
file <path> # Définit le chemin vers le script worker, peut être relatif à la racine du php_server
|
||||
num <num> # Définit le nombre de threads PHP à démarrer, par défaut 2x le nombre de CPUs disponibles
|
||||
name <name> # Définit le nom du worker, utilisé dans les journaux et les métriques. Défaut : chemin absolu du fichier du worker. Commence toujours par m# lorsqu'il est défini dans un bloc php_server.
|
||||
watch <path> # Définit le chemin d'accès à surveiller pour les modifications de fichiers. Peut être spécifié plusieurs fois pour plusieurs chemins.
|
||||
env <key> <value> # Définit une variable d'environnement supplémentaire avec la valeur donnée. Peut être spécifié plusieurs fois pour plusieurs variables d'environnement. Les variables d'environnement pour ce worker sont également héritées du parent php_server, mais peuvent être écrasées ici.
|
||||
}
|
||||
worker <other_file> <num> # Peut également utiliser la forme courte comme dans le bloc frankenphp global.
|
||||
}
|
||||
```
|
||||
|
||||
### Surveillance des modifications de fichier
|
||||
|
||||
Vu que les workers ne démarrent votre application qu'une seule fois et la gardent en mémoire, toute modification
|
||||
apportée à vos fichiers PHP ne sera pas répercutée immédiatement.
|
||||
|
||||
Les workers peuvent être redémarrés en cas de changement de fichier via la directive `watch`.
|
||||
Ceci est utile pour les environnements de développement.
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
frankenphp {
|
||||
worker {
|
||||
file /path/to/app/public/worker.php
|
||||
watch
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Si le répertoire `watch` n'est pas précisé, il se rabattra sur `./**/*.{php,yaml,yml,twig,env}`,
|
||||
qui surveille tous les fichiers `.php`, `.yaml`, `.yml`, `.twig` et `.env` dans le répertoire et les sous-répertoires
|
||||
où le processus FrankenPHP a été lancé. Vous pouvez également spécifier un ou plusieurs répertoires via une commande
|
||||
[motif de nom de fichier shell](https://pkg.go.dev/path/filepath#Match) :
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
frankenphp {
|
||||
worker {
|
||||
file /path/to/app/public/worker.php
|
||||
watch /path/to/app # surveille tous les fichiers dans tous les sous-répertoires de /path/to/app
|
||||
watch /path/to/app/*.php # surveille les fichiers se terminant par .php dans /path/to/app
|
||||
watch /path/to/app/**/*.php # surveille les fichiers PHP dans /path/to/app et les sous-répertoires
|
||||
watch /path/to/app/**/*.{php,twig} # surveille les fichiers PHP et Twig dans /path/to/app et les sous-répertoires
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- Le motif `**` signifie une surveillance récursive.
|
||||
- Les répertoires peuvent également être relatifs (depuis l'endroit où le processus FrankenPHP est démarré).
|
||||
- Si vous avez défini plusieurs workers, ils seront tous redémarrés lorsqu'un fichier est modifié.
|
||||
- Méfiez-vous des fichiers créés au moment de l'exécution (comme les logs) car ils peuvent provoquer des redémarrages intempestifs du worker.
|
||||
|
||||
La surveillance des fichiers est basé sur [e-dant/watcher](https://github.com/e-dant/watcher).
|
||||
|
||||
### Full Duplex (HTTP/1)
|
||||
|
||||
Lors de l'utilisation de HTTP/1.x, il peut être souhaitable d'activer le mode full-duplex pour permettre l'écriture d'une réponse avant que le corps entier
|
||||
n'ait été lu. (par exemple : WebSocket, événements envoyés par le serveur, etc.)
|
||||
|
||||
Il s'agit d'une configuration optionnelle qui doit être ajoutée aux options globales dans le fichier `Caddyfile` :
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
servers {
|
||||
enable_full_duplex
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
>
|
||||
> L'activation de cette option peut entraîner un blocage (deadlock) des anciens clients HTTP/1.x qui ne supportent pas le full-duplex.
|
||||
> Cela peut aussi être configuré en utilisant la variable d'environnement `CADDY_GLOBAL_OPTIONS` :
|
||||
|
||||
```sh
|
||||
CADDY_GLOBAL_OPTIONS="servers {
|
||||
enable_full_duplex
|
||||
}"
|
||||
```
|
||||
|
||||
Vous trouverez plus d'informations sur ce paramètre dans la [documentation Caddy](https://caddyserver.com/docs/caddyfile/options#enable-full-duplex).
|
||||
|
||||
## Variables d'environnement
|
||||
|
||||
Les variables d'environnement suivantes peuvent être utilisées pour insérer des directives Caddy dans le `Caddyfile` sans le modifier :
|
||||
|
||||
* `SERVER_NAME` : change [les adresses sur lesquelles écouter](https://caddyserver.com/docs/caddyfile/concepts#addresses), les noms d'hôte fournis seront également utilisés pour le certificat TLS généré
|
||||
* `CADDY_GLOBAL_OPTIONS` : injecte [des options globales](https://caddyserver.com/docs/caddyfile/options)
|
||||
* `FRANKENPHP_CONFIG` : insère la configuration sous la directive `frankenphp`
|
||||
- `SERVER_NAME` : change [les adresses sur lesquelles écouter](https://caddyserver.com/docs/caddyfile/concepts#addresses), les noms d'hôte fournis seront également utilisés pour le certificat TLS généré
|
||||
- `CADDY_GLOBAL_OPTIONS` : injecte [des options globales](https://caddyserver.com/docs/caddyfile/options)
|
||||
- `FRANKENPHP_CONFIG` : insère la configuration sous la directive `frankenphp`
|
||||
|
||||
Comme pour les SAPI FPM et CLI, les variables d'environnement ne sont exposées par défaut dans la superglobale `$_SERVER`.
|
||||
|
||||
@@ -146,9 +244,27 @@ La valeur `S` de [la directive `variables_order` de PHP](https://www.php.net/man
|
||||
|
||||
## Configuration PHP
|
||||
|
||||
Pour charger [des fichiers de configuration PHP supplémentaires](https://www.php.net/manual/fr/configuration.file.php#configuration.file.scan), la variable d'environnement `PHP_INI_SCAN_DIR` peut être utilisée.
|
||||
Pour charger [des fichiers de configuration PHP supplémentaires](https://www.php.net/manual/fr/configuration.file.php#configuration.file.scan),
|
||||
la variable d'environnement `PHP_INI_SCAN_DIR` peut être utilisée.
|
||||
Lorsqu'elle est définie, PHP chargera tous les fichiers avec l'extension `.ini` présents dans les répertoires donnés.
|
||||
|
||||
Vous pouvez également modifier la configuration de PHP en utilisant la directive `php_ini` dans le fichier `Caddyfile` :
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
frankenphp {
|
||||
php_ini memory_limit 256M
|
||||
|
||||
# or
|
||||
|
||||
php_ini {
|
||||
memory_limit 256M
|
||||
max_execution_time 15
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Activer le mode debug
|
||||
|
||||
Lors de l'utilisation de l'image Docker, définissez la variable d'environnement `CADDY_GLOBAL_OPTIONS` sur `debug` pour activer le mode debug :
|
||||
|
||||
@@ -4,6 +4,13 @@ Les images Docker de [FrankenPHP](https://hub.docker.com/r/dunglas/frankenphp) s
|
||||
|
||||
Des variantes pour PHP 8.2, 8.3 et 8.4 sont disponibles. [Parcourir les tags](https://hub.docker.com/r/dunglas/frankenphp/tags).
|
||||
|
||||
Les tags suivent le pattern suivant: `dunglas/frankenphp:<frankenphp-version>-php<php-version>-<os>`
|
||||
|
||||
- `<frankenphp-version>` et `<php-version>` sont repsectivement les numéros de version de FrankenPHP et PHP, allant de majeur (e.g. `1`), mineur (e.g. `1.2`) à des versions correctives (e.g. `1.2.3`).
|
||||
- `<os>` est soit `bookworm` (pour Debian Bookworm) ou `alpine` (pour la dernière version stable d'Alpine).
|
||||
|
||||
[Parcourir les tags](https://hub.docker.com/r/dunglas/frankenphp/tags).
|
||||
|
||||
## Comment utiliser les images
|
||||
|
||||
Créez un `Dockerfile` dans votre projet :
|
||||
@@ -42,7 +49,7 @@ RUN install-php-extensions \
|
||||
|
||||
FrankenPHP est construit sur Caddy, et tous les [modules Caddy](https://caddyserver.com/docs/modules/) peuvent être utilisés avec FrankenPHP.
|
||||
|
||||
La manière la plus simple d'installer des modules Caddy personnalisés est d'utiliser [xcaddy](https://github.com/caddyserver/xcaddy):
|
||||
La manière la plus simple d'installer des modules Caddy personnalisés est d'utiliser [xcaddy](https://github.com/caddyserver/xcaddy) :
|
||||
|
||||
```dockerfile
|
||||
FROM dunglas/frankenphp:builder AS builder
|
||||
@@ -58,8 +65,8 @@ RUN CGO_ENABLED=1 \
|
||||
CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" \
|
||||
xcaddy build \
|
||||
--output /usr/local/bin/frankenphp \
|
||||
--with github.com/dunglas/frankenphp=./ \
|
||||
--with github.com/dunglas/frankenphp/caddy=./caddy/ \
|
||||
--with frankenphp.dev=./ \
|
||||
--with frankenphp.dev/caddy=./caddy/ \
|
||||
--with github.com/dunglas/caddy-cbrotli \
|
||||
# Mercure et Vulcain sont inclus dans la construction officielle, mais n'hésitez pas à les retirer
|
||||
--with github.com/dunglas/mercure/caddy \
|
||||
@@ -167,12 +174,12 @@ FROM dunglas/frankenphp
|
||||
|
||||
ARG USER=appuser
|
||||
|
||||
RUN
|
||||
RUN \
|
||||
# Utiliser "adduser -D ${USER}" pour les distros basées sur Alpine
|
||||
useradd ${USER};
|
||||
# Supprimer la capacité par défaut
|
||||
useradd ${USER}; \
|
||||
# Supprimer la capacité par défaut \
|
||||
setcap -r /usr/local/bin/frankenphp; \
|
||||
# Donner un accès en écriture à /data/caddy et /config/caddy
|
||||
# Donner un accès en écriture à /data/caddy et /config/caddy \
|
||||
chown -R ${USER}:${USER} /data/caddy && chown -R ${USER}:${USER} /config/caddy
|
||||
|
||||
USER ${USER}
|
||||
@@ -185,8 +192,8 @@ Exemple `:8000`
|
||||
|
||||
Les images Docker sont construites :
|
||||
|
||||
* lorsqu'une nouvelle version est taguée
|
||||
* tous les jours à 4h UTC, si de nouvelles versions des images officielles PHP sont disponibles
|
||||
- lorsqu'une nouvelle version est taguée
|
||||
- tous les jours à 4h UTC, si de nouvelles versions des images officielles PHP sont disponibles
|
||||
|
||||
## Versions de développement
|
||||
|
||||
|
||||
@@ -6,16 +6,18 @@ Grâce à cette fonctionnalité, les applications PHP peuvent être distribuées
|
||||
|
||||
Pour en savoir plus sur cette fonctionnalité, consultez [la présentation faite par Kévin à la SymfonyCon 2023](https://dunglas.dev/2023/12/php-and-symfony-apps-as-standalone-binaries/).
|
||||
|
||||
Pour embarquer des applications Laravel, [lisez ce point spécifique de la documentation](laravel.md#les-applications-laravel-en-tant-que-binaires-autonomes).
|
||||
|
||||
## Préparer votre application
|
||||
|
||||
Avant de créer le binaire autonome, assurez-vous que votre application est prête à être intégrée.
|
||||
|
||||
Vous devrez probablement :
|
||||
|
||||
* Installer les dépendances de production de l'application
|
||||
* Dumper l'autoloader
|
||||
* Activer le mode production de votre application (si disponible)
|
||||
* Supprimer les fichiers inutiles tels que `.git` ou les tests pour réduire la taille de votre binaire final
|
||||
- Installer les dépendances de production de l'application
|
||||
- Dumper l'autoloader
|
||||
- Activer le mode production de votre application (si disponible)
|
||||
- Supprimer les fichiers inutiles tels que `.git` ou les tests pour réduire la taille de votre binaire final
|
||||
|
||||
Par exemple, pour une application Symfony, lancez les commandes suivantes :
|
||||
|
||||
@@ -29,7 +31,8 @@ cd $TMPDIR/my-prepared-app
|
||||
echo APP_ENV=prod > .env.local
|
||||
echo APP_DEBUG=0 >> .env.local
|
||||
|
||||
# Supprimer les tests
|
||||
# Supprimer les tests et autres fichiers inutiles pour économiser de l'espace
|
||||
# Alternativement, ajoutez ces fichiers avec l'attribut export-ignore dans votre fichier .gitattributes
|
||||
rm -Rf tests/
|
||||
|
||||
# Installer les dépendances
|
||||
@@ -52,36 +55,34 @@ La manière la plus simple de créer un binaire Linux est d'utiliser le builder
|
||||
|
||||
1. Créez un fichier nommé `static-build.Dockerfile` dans le répertoire de votre application préparée :
|
||||
|
||||
```dockerfile
|
||||
FROM --platform=linux/amd64 dunglas/frankenphp:static-builder
|
||||
```dockerfile
|
||||
FROM --platform=linux/amd64 dunglas/frankenphp:static-builder
|
||||
|
||||
# Copy your app
|
||||
WORKDIR /go/src/app/dist/app
|
||||
COPY . .
|
||||
# Copy your app
|
||||
WORKDIR /go/src/app/dist/app
|
||||
COPY . .
|
||||
|
||||
# Build the static binary, be sure to select only the PHP extensions you want
|
||||
WORKDIR /go/src/app/
|
||||
RUN EMBED=dist/app/ \
|
||||
PHP_EXTENSIONS=ctype,iconv,pdo_sqlite \
|
||||
./build-static.sh
|
||||
```
|
||||
# Build the static binary, be sure to select only the PHP extensions you want
|
||||
WORKDIR /go/src/app/
|
||||
RUN EMBED=dist/app/ ./build-static.sh
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
>
|
||||
> Certains fichiers `.dockerignore` (par exemple celui fourni par défaut par [Symfony Docker](https://github.com/dunglas/symfony-docker/blob/main/.dockerignore))
|
||||
> empêchent la copie du dossier `vendor/` et des fichiers `.env`. Assurez-vous d'ajuster ou de supprimer le fichier `.dockerignore` avant le build.
|
||||
> [!CAUTION]
|
||||
>
|
||||
> Certains fichiers `.dockerignore` (par exemple celui fourni par défaut par [Symfony Docker](https://github.com/dunglas/symfony-docker/blob/main/.dockerignore))
|
||||
> empêchent la copie du dossier `vendor/` et des fichiers `.env`. Assurez-vous d'ajuster ou de supprimer le fichier `.dockerignore` avant le build.
|
||||
|
||||
2. Construisez:
|
||||
|
||||
```console
|
||||
docker build -t static-app -f static-build.Dockerfile .
|
||||
```
|
||||
```console
|
||||
docker build -t static-app -f static-build.Dockerfile .
|
||||
```
|
||||
|
||||
3. Extrayez le binaire :
|
||||
|
||||
```console
|
||||
docker cp $(docker create --name static-app-tmp static-app):/go/src/app/dist/frankenphp-linux-x86_64 my-app ; docker rm static-app-tmp
|
||||
```
|
||||
```console
|
||||
docker cp $(docker create --name static-app-tmp static-app):/go/src/app/dist/frankenphp-linux-x86_64 my-app ; docker rm static-app-tmp
|
||||
```
|
||||
|
||||
Le binaire généré sera nommé `my-app` dans le répertoire courant.
|
||||
|
||||
@@ -92,9 +93,7 @@ Si vous ne souhaitez pas utiliser Docker, ou souhaitez construire un binaire mac
|
||||
```console
|
||||
git clone https://github.com/dunglas/frankenphp
|
||||
cd frankenphp
|
||||
EMBED=/path/to/your/app \
|
||||
PHP_EXTENSIONS=ctype,iconv,pdo_sqlite \
|
||||
./build-static.sh
|
||||
EMBED=/path/to/your/app ./build-static.sh
|
||||
```
|
||||
|
||||
Le binaire obtenu est le fichier nommé `frankenphp-<os>-<arch>` dans le répertoire `dist/`.
|
||||
@@ -127,6 +126,19 @@ Vous pouvez également exécuter les scripts CLI PHP incorporés dans votre bina
|
||||
./my-app php-cli bin/console
|
||||
```
|
||||
|
||||
## Extensions PHP
|
||||
|
||||
Par défaut, le script construira les extensions requises par le fichier `composer.json` de votre projet, s'il y en a.
|
||||
Si le fichier `composer.json` n'existe pas, les extensions par défaut sont construites, comme documenté dans [Créer un binaire statique](static.md).
|
||||
|
||||
Pour personnaliser les extensions, utilisez la variable d'environnement `PHP_EXTENSIONS`.
|
||||
|
||||
```console
|
||||
EMBED=/path/to/your/app \
|
||||
PHP_EXTENSIONS=ctype,iconv,pdo_sqlite \
|
||||
./build-static.sh
|
||||
```
|
||||
|
||||
## Personnaliser la compilation
|
||||
|
||||
[Consultez la documentation sur la compilation statique](static.md) pour voir comment personnaliser le binaire (extensions, version PHP...).
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
Les extensions suivantes sont connues pour ne pas être compatibles avec FrankenPHP :
|
||||
|
||||
| Nom | Raison | Alternatives |
|
||||
|-------------------------------------------------------------------------------------------------------------|-----------------|----------------------------------------------------------------------------------------------------------------------|
|
||||
| ----------------------------------------------------------------------------------------------------------- | --------------- | -------------------------------------------------------------------------------------------------------------------- |
|
||||
| [imap](https://www.php.net/manual/en/imap.installation.php) | Non thread-safe | [javanile/php-imap2](https://github.com/javanile/php-imap2), [webklex/php-imap](https://github.com/Webklex/php-imap) |
|
||||
| [newrelic](https://docs.newrelic.com/docs/apm/agents/php-agent/getting-started/introduction-new-relic-php/) | Non thread-safe | - |
|
||||
|
||||
@@ -14,7 +14,7 @@ Les extensions suivantes sont connues pour ne pas être compatibles avec Franken
|
||||
Les extensions suivantes ont des bugs connus ou des comportements inattendus lorsqu'elles sont utilisées avec FrankenPHP :
|
||||
|
||||
| Nom | Problème |
|
||||
|---------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| ------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [ext-openssl](https://www.php.net/manual/fr/book.openssl.php) | Lors de l'utilisation d'une version statique de FrankenPHP (construite avec la libc musl), l'extension OpenSSL peut planter sous de fortes charges. Une solution consiste à utiliser une version liée dynamiquement (comme celle utilisée dans les images Docker). Ce bogue est [suivi par PHP](https://github.com/php/php-src/issues/13648). |
|
||||
|
||||
## get_browser
|
||||
@@ -30,7 +30,7 @@ Le binaire autonome et les images docker basées sur Alpine (`dunglas/frankenphp
|
||||
Par défaut, FrankenPHP génère un certificat TLS pour `localhost`.
|
||||
C'est l'option la plus simple et recommandée pour le développement local.
|
||||
|
||||
Si vous voulez vraiment utiliser `127.0.0.1` comme hôte, il est possible de configure FrankenPHP pour générer un certificat pour cela en définissant le nom du serveur à `127.0.0.1`.
|
||||
Si vous voulez vraiment utiliser `127.0.0.1` comme hôte, il est possible de configurer FrankenPHP pour générer un certificat pour cela en définissant le nom du serveur à `127.0.0.1`.
|
||||
|
||||
Malheureusement, cela ne suffit pas lors de l'utilisation de Docker à cause de [son système de gestion des réseaux](https://docs.docker.com/network/).
|
||||
Vous obtiendrez une erreur TLS similaire à `curl: (35) LibreSSL/3.3.6: error:1404B438:SSL routines:ST_CONNECT:tlsv1 alert internal error`.
|
||||
@@ -47,7 +47,7 @@ docker run \
|
||||
|
||||
Le pilote de réseau "hôte" n'est pas pris en charge sur Mac et Windows. Sur ces plateformes, vous devrez deviner l'adresse IP du conteneur et l'inclure dans les noms de serveur.
|
||||
|
||||
Exécutez la commande `docker network inspect bridge` et inpectez la clef `Containers` pour identifier la dernière adresse IP attribuée sous la clef `IPv4Address`, puis incrémentez-la de un. Si aucun conteneur n'est en cours d'exécution, la première adresse IP attribuée est généralement `172.17.0.2`.
|
||||
Exécutez la commande `docker network inspect bridge` et inpectez la clef `Containers` pour identifier la dernière adresse IP attribuée sous la clef `IPv4Address`, puis incrémentez-la d'un. Si aucun conteneur n'est en cours d'exécution, la première adresse IP attribuée est généralement `172.17.0.2`.
|
||||
|
||||
Ensuite, incluez ceci dans la variable d'environnement `SERVER_NAME` :
|
||||
|
||||
@@ -75,3 +75,69 @@ docker run \
|
||||
-p 80:80 -p 443:443 -p 443:443/udp \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
|
||||
## Scripts Composer Faisant Références à `@php`
|
||||
|
||||
Les [scripts Composer](https://getcomposer.org/doc/articles/scripts.md) peuvent vouloir exécuter un binaire PHP pour certaines tâches, par exemple dans [un projet Laravel](laravel.md) pour exécuter `@php artisan package:discover --ansi`. Cela [echoue actuellement](https://github.com/dunglas/frankenphp/issues/483#issuecomment-1899890915) pour deux raisons :
|
||||
|
||||
- Composer ne sait pas comment appeler le binaire FrankenPHP ;
|
||||
- Composer peut ajouter des paramètres PHP en utilisant le paramètre `-d` dans la commande, ce que FrankenPHP ne supporte pas encore.
|
||||
|
||||
Comme solution de contournement, nous pouvons créer un script shell dans `/usr/local/bin/php` qui supprime les paramètres non supportés et appelle ensuite FrankenPHP :
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
args=("$@")
|
||||
index=0
|
||||
for i in "$@"
|
||||
do
|
||||
if [ "$i" == "-d" ]; then
|
||||
unset 'args[$index]'
|
||||
unset 'args[$index+1]'
|
||||
fi
|
||||
index=$((index+1))
|
||||
done
|
||||
|
||||
/usr/local/bin/frankenphp php-cli ${args[@]}
|
||||
```
|
||||
|
||||
Ensuite, mettez la variable d'environnement `PHP_BINARY` au chemin de notre script `php` et lancez Composer :
|
||||
|
||||
```console
|
||||
export PHP_BINARY=/usr/local/bin/php
|
||||
composer install
|
||||
```
|
||||
|
||||
## Résolution des problèmes TLS/SSL avec les binaires statiques
|
||||
|
||||
Lorsque vous utilisez les binaires statiques, vous pouvez rencontrer les erreurs suivantes liées à TLS, par exemple lors de l'envoi de courriels utilisant STARTTLS :
|
||||
|
||||
```text
|
||||
Unable to connect with STARTTLS: stream_socket_enable_crypto(): SSL operation failed with code 5. OpenSSL Error messages:
|
||||
error:80000002:system library::No such file or directory
|
||||
error:80000002:system library::No such file or directory
|
||||
error:80000002:system library::No such file or directory
|
||||
error:0A000086:SSL routines::certificate verify failed
|
||||
```
|
||||
|
||||
Comme le binaire statique ne contient pas de certificats TLS, vous devez indiquer à OpenSSL l'installation de vos certificats CA locaux.
|
||||
|
||||
Inspectez la sortie de [`openssl_get_cert_locations()`](https://www.php.net/manual/en/function.openssl-get-cert-locations.php),
|
||||
pour trouver l'endroit où les certificats CA doivent être installés et stockez-les à cet endroit.
|
||||
|
||||
> [!WARNING]
|
||||
>
|
||||
> Les contextes Web et CLI peuvent avoir des paramètres différents.
|
||||
> Assurez-vous d'exécuter `openssl_get_cert_locations()` dans le bon contexte.
|
||||
|
||||
[Les certificats CA extraits de Mozilla peuvent être téléchargés sur le site curl](https://curl.se/docs/caextract.html).
|
||||
|
||||
Alternativement, de nombreuses distributions, y compris Debian, Ubuntu, et Alpine fournissent des paquets nommés `ca-certificates` qui contiennent ces certificats.
|
||||
|
||||
Il est également possible d'utiliser `SSL_CERT_FILE` et `SSL_CERT_DIR` pour indiquer à OpenSSL où chercher les certificats CA :
|
||||
|
||||
```console
|
||||
# Définir les variables d'environnement des certificats TLS
|
||||
export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
|
||||
export SSL_CERT_DIR=/etc/ssl/certs
|
||||
```
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
## Docker
|
||||
|
||||
Déployer une application web [Laravel](https://laravel.com) avec FrankenPHP est très facile.
|
||||
Il suffit de monter le projet dans le répertoire `/app` de l'image Docker officielle.
|
||||
Déployer une application web [Laravel](https://laravel.com) avec FrankenPHP est très facile. Il suffit de monter le projet dans le répertoire `/app` de l'image Docker officielle.
|
||||
|
||||
Exécutez cette commande depuis le répertoire principal de votre application Laravel :
|
||||
|
||||
@@ -20,21 +19,23 @@ Vous pouvez également exécuter vos projets Laravel avec FrankenPHP depuis votr
|
||||
1. [Téléchargez le binaire correspondant à votre système](README.md#binaire-autonome)
|
||||
2. Ajoutez la configuration suivante dans un fichier nommé `Caddyfile` placé dans le répertoire racine de votre projet Laravel :
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
frankenphp
|
||||
}
|
||||
```caddyfile
|
||||
{
|
||||
frankenphp
|
||||
}
|
||||
|
||||
# Le nom de domaine de votre serveur
|
||||
localhost {
|
||||
# Définir le répertoire racine sur le dossier public/
|
||||
root * public/
|
||||
# Autoriser la compression (optionnel)
|
||||
encode zstd br gzip
|
||||
# Exécuter les scripts PHP du dossier public/ et servir les assets
|
||||
php_server
|
||||
}
|
||||
```
|
||||
# Le nom de domaine de votre serveur
|
||||
localhost {
|
||||
# Définir le répertoire racine sur le dossier public/
|
||||
root public/
|
||||
# Autoriser la compression (optionnel)
|
||||
encode zstd br gzip
|
||||
# Exécuter les scripts PHP du dossier public/ et servir les assets
|
||||
php_server {
|
||||
try_files {path} index.php
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. Démarrez FrankenPHP depuis le répertoire racine de votre projet Laravel : `frankenphp run`
|
||||
|
||||
@@ -60,19 +61,124 @@ php artisan octane:frankenphp
|
||||
|
||||
La commande `octane:frankenphp` peut prendre les options suivantes :
|
||||
|
||||
* `--host` : L'adresse IP à laquelle le serveur doit se lier (par défaut : `127.0.0.1`)
|
||||
* `--port` : Le port sur lequel le serveur doit être disponible (par défaut : `8000`)
|
||||
* `--admin-port` : Le port sur lequel le serveur administratif doit être disponible (par défaut : `2019`)
|
||||
* `--workers` : Le nombre de workers qui doivent être disponibles pour traiter les requêtes (par défaut : `auto`)
|
||||
* `--max-requests` : Le nombre de requêtes à traiter avant de recharger le serveur (par défaut : `500`)
|
||||
* `--caddyfile` : Le chemin vers le fichier `Caddyfile` de FrankenPHP
|
||||
* `--https` : Activer HTTPS, HTTP/2, et HTTP/3, et générer automatiquement et renouveler les certificats
|
||||
* `--http-redirect` : Activer la redirection HTTP vers HTTPS (uniquement activé si --https est passé)
|
||||
* `--watch` : Recharger automatiquement le serveur lorsque l'application est modifiée
|
||||
* `--poll` : Utiliser le sondage du système de fichiers pendant la surveillance pour surveiller les fichiers sur un réseau
|
||||
* `--log-level` : Enregistrer les messages au niveau de journalisation spécifié ou au-dessus, en utilisant le logger natif de Caddy
|
||||
- `--host` : L'adresse IP à laquelle le serveur doit se lier (par défaut : `127.0.0.1`)
|
||||
- `--port` : Le port sur lequel le serveur doit être disponible (par défaut : `8000`)
|
||||
- `--admin-port` : Le port sur lequel le serveur administratif doit être disponible (par défaut : `2019`)
|
||||
- `--workers` : Le nombre de workers qui doivent être disponibles pour traiter les requêtes (par défaut : `auto`)
|
||||
- `--max-requests` : Le nombre de requêtes à traiter avant de recharger le serveur (par défaut : `500`)
|
||||
- `--caddyfile` : Le chemin vers le fichier `Caddyfile` de FrankenPHP
|
||||
- `--https` : Activer HTTPS, HTTP/2, et HTTP/3, et générer automatiquement et renouveler les certificats
|
||||
- `--http-redirect` : Activer la redirection HTTP vers HTTPS (uniquement activé si --https est passé)
|
||||
- `--watch` : Recharger automatiquement le serveur lorsque l'application est modifiée
|
||||
- `--poll` : Utiliser le sondage du système de fichiers pendant la surveillance pour surveiller les fichiers sur un réseau
|
||||
- `--log-level` : Enregistrer les messages au niveau de journalisation spécifié ou au-dessus, en utilisant le logger natif de Caddy
|
||||
|
||||
> [!TIP]
|
||||
> Pour obtenir des logs structurés en JSON logs (utile quand vous utilisez des solutions d'analyse de logs), passez explicitement l'otpion `--log-level`.
|
||||
> Pour obtenir des logs structurés en JSON logs (utile quand vous utilisez des solutions d'analyse de logs), passez explicitement l'option `--log-level`.
|
||||
|
||||
En savoir plus sur Laravel Octane [dans sa documentation officielle](https://laravel.com/docs/octane).
|
||||
|
||||
## Les Applications Laravel En Tant Que Binaires Autonomes
|
||||
|
||||
En utilisant la [fonctionnalité d'intégration d'applications de FrankenPHP](embed.md), il est possible de distribuer
|
||||
les applications Laravel sous forme de binaires autonomes.
|
||||
|
||||
Suivez ces étapes pour empaqueter votre application Laravel en tant que binaire autonome pour Linux :
|
||||
|
||||
1. Créez un fichier nommé `static-build.Dockerfile` dans le dépôt de votre application :
|
||||
|
||||
```dockerfile
|
||||
FROM --platform=linux/amd64 dunglas/frankenphp:static-builder
|
||||
|
||||
# Copiez votre application
|
||||
WORKDIR /go/src/app/dist/app
|
||||
COPY . .
|
||||
|
||||
# Supprimez les tests et autres fichiers inutiles pour gagner de la place
|
||||
# Alternativement, ajoutez ces fichiers à un fichier .dockerignore
|
||||
RUN rm -Rf tests/
|
||||
|
||||
# Copiez le fichier .env
|
||||
RUN cp .env.example .env
|
||||
# Modifier APP_ENV et APP_DEBUG pour qu'ils soient prêts pour la production
|
||||
RUN sed -i'' -e 's/^APP_ENV=.*/APP_ENV=production/' -e 's/^APP_DEBUG=.*/APP_DEBUG=false/' .env
|
||||
|
||||
# Apportez d'autres modifications à votre fichier .env si nécessaire
|
||||
|
||||
# Installez les dépendances
|
||||
RUN composer install --ignore-platform-reqs --no-dev -a
|
||||
|
||||
# Construire le binaire statique
|
||||
WORKDIR /go/src/app/
|
||||
RUN EMBED=dist/app/ ./build-static.sh
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
>
|
||||
> Certains fichiers `.dockerignore` ignoreront le répertoire `vendor/`
|
||||
> et les fichiers `.env`. Assurez-vous d'ajuster ou de supprimer le fichier `.dockerignore` avant la construction.
|
||||
|
||||
2. Build:
|
||||
|
||||
```console
|
||||
docker build -t static-laravel-app -f static-build.Dockerfile .
|
||||
```
|
||||
|
||||
3. Extraire le binaire
|
||||
|
||||
```console
|
||||
docker cp $(docker create --name static-laravel-app-tmp static-laravel-app):/go/src/app/dist/frankenphp-linux-x86_64 frankenphp ; docker rm static-laravel-app-tmp
|
||||
```
|
||||
|
||||
4. Remplir les caches :
|
||||
|
||||
```console
|
||||
frankenphp php-cli artisan optimize
|
||||
```
|
||||
|
||||
5. Exécutez les migrations de base de données (s'il y en a) :
|
||||
|
||||
```console
|
||||
frankenphp php-cli artisan migrate
|
||||
```
|
||||
|
||||
6. Générer la clé secrète de l'application :
|
||||
|
||||
```console
|
||||
frankenphp php-cli artisan key:generate
|
||||
```
|
||||
|
||||
7. Démarrez le serveur:
|
||||
|
||||
```console
|
||||
frankenphp php-server
|
||||
```
|
||||
|
||||
Votre application est maintenant prête !
|
||||
|
||||
Pour en savoir plus sur les options disponibles et sur la construction de binaires pour d'autres systèmes d'exploitation,
|
||||
consultez la documentation [Applications PHP en tant que binaires autonomes](embed.md).
|
||||
|
||||
### Changer le chemin de stockage
|
||||
|
||||
Par défaut, Laravel stocke les fichiers téléchargés, les caches, les logs, etc. dans le répertoire `storage/` de l'application.
|
||||
Ceci n'est pas adapté aux applications embarquées, car chaque nouvelle version sera extraite dans un répertoire temporaire différent.
|
||||
|
||||
Définissez la variable d'environnement `LARAVEL_STORAGE_PATH` (par exemple, dans votre fichier `.env`) ou appelez la méthode `Illuminate\Foundation\Application::useStoragePath()` pour utiliser un répertoire en dehors du répertoire temporaire.
|
||||
|
||||
### Exécuter Octane avec des binaires autonomes
|
||||
|
||||
Il est même possible d'empaqueter les applications Laravel Octane en tant que binaires autonomes !
|
||||
|
||||
Pour ce faire, [installez Octane correctement](#laravel-octane) et suivez les étapes décrites dans [la section précédente](#les-applications-laravel-en-tant-que-binaires-autonomes).
|
||||
|
||||
Ensuite, pour démarrer FrankenPHP en mode worker via Octane, exécutez :
|
||||
|
||||
```console
|
||||
PATH="$PWD:$PATH" frankenphp php-cli artisan octane:frankenphp
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
>
|
||||
> Pour que la commande fonctionne, le binaire autonome **doit** être nommé `frankenphp`
|
||||
> car Octane a besoin d'un programme nommé `frankenphp` disponible dans le chemin
|
||||
|
||||
17
docs/fr/metrics.md
Normal file
17
docs/fr/metrics.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Métriques
|
||||
|
||||
Lorsque les [métriques Caddy](https://caddyserver.com/docs/metrics) sont activées, FrankenPHP expose les métriques suivantes :
|
||||
|
||||
- `frankenphp_total_threads` : Le nombre total de threads PHP.
|
||||
- `frankenphp_busy_threads` : Le nombre de threads PHP en cours de traitement d'une requête (les workers en cours d'exécution consomment toujours un thread).
|
||||
- `frankenphp_queue_depth` : Le nombre de requêtes régulières en file d'attente
|
||||
- `frankenphp_total_workers{worker=« [nom_du_worker] »}` : Le nombre total de workers.
|
||||
- `frankenphp_busy_workers{worker=« [nom_du_worker] »}` : Le nombre de workers qui traitent actuellement une requête.
|
||||
- `frankenphp_worker_request_time{worker=« [nom_du_worker] »}` : Le temps passé à traiter les requêtes par tous les workers.
|
||||
- `frankenphp_worker_request_count{worker=« [nom_du_worker] »}` : Le nombre de requêtes traitées par tous les workers.
|
||||
- `frankenphp_ready_workers{worker=« [nom_du_worker] »}` : Le nombre de workers qui ont appelé `frankenphp_handle_request` au moins une fois.
|
||||
- `frankenphp_worker_crashes{worker=« [nom_du_worker] »}` : Le nombre de fois où un worker s'est arrêté de manière inattendue.
|
||||
- `frankenphp_worker_restarts{worker=« [nom_du_worker] »}` : Le nombre de fois où un worker a été délibérément redémarré.
|
||||
- `frankenphp_worker_queue_depth{worker=« [nom_du_worker] »}` : Le nombre de requêtes en file d'attente.
|
||||
|
||||
Pour les métriques de worker, le placeholder `[nom_du_worker]` est remplacé par le nom du worker dans le Caddyfile, sinon le chemin absolu du fichier du worker sera utilisé.
|
||||
@@ -5,7 +5,7 @@ Cependant, il est possible d'améliorer considérablement les performances en ut
|
||||
|
||||
## Nombre de threads et de workers
|
||||
|
||||
Par défaut, FrankenPHP démarre 2 fois plus de threads et de workers (en mode worker) que le nombre de CPU disponibles.
|
||||
Par défaut, FrankenPHP démarre deux fois plus de threads et de workers (en mode worker) que le nombre de CPU disponibles.
|
||||
|
||||
Les valeurs appropriées dépendent fortement de la manière dont votre application est écrite, de ce qu'elle fait et de votre matériel.
|
||||
Nous recommandons vivement de modifier ces valeurs.
|
||||
@@ -16,6 +16,16 @@ Pour trouver les bonnes valeurs, il est souhaitable d'effectuer des tests de cha
|
||||
Pour configurer le nombre de threads, utilisez l'option `num_threads` des directives `php_server` et `php`.
|
||||
Pour changer le nombre de travailleurs, utilisez l'option `num` de la section `worker` de la directive `frankenphp`.
|
||||
|
||||
### `max_threads`
|
||||
|
||||
Bien qu'il soit toujours préférable de savoir exactement à quoi ressemblera votre trafic, les applications réelles
|
||||
ont tendance à être plus imprévisibles. Le paramètre `max_threads` permet à FrankenPHP de créer automatiquement des threads supplémentaires au moment de l'exécution, jusqu'à la limite spécifiée.
|
||||
`max_threads` peut vous aider à déterminer le nombre de threads dont vous avez besoin pour gérer votre trafic et peut rendre le serveur plus résistant aux pics de latence.
|
||||
Si elle est fixée à `auto`, la limite sera estimée en fonction de la valeur de `memory_limit` dans votre `php.ini`. Si ce n'est pas possible,
|
||||
`auto` prendra par défaut 2x `num_threads`. Gardez à l'esprit que `auto` peut fortement sous-estimer le nombre de threads nécessaires.
|
||||
`max_threads` est similaire à [pm.max_children](https://www.php.net/manual/en/install.fpm.configuration.php#pm.max-children) de PHP FPM. La principale différence est que FrankenPHP utilise des threads au lieu de
|
||||
processus et les délègue automatiquement à différents scripts de travail et au `mode classique` selon les besoins.
|
||||
|
||||
## Mode worker
|
||||
|
||||
Activer [le mode worker](worker.md) améliore considérablement les performances,
|
||||
@@ -27,7 +37,7 @@ vous devez créer un script worker et vous assurer que l'application n'a pas de
|
||||
Les binaires statiques que nous fournissons, ainsi que la variante Alpine Linux des images Docker officielles, utilisent [la bibliothèque musl](https://musl.libc.org).
|
||||
|
||||
PHP est connu pour être [significativement plus lent](https://gitlab.alpinelinux.org/alpine/aports/-/issues/14381) lorsqu'il utilise cette bibliothèque C alternative au lieu de la bibliothèque GNU traditionnelle,
|
||||
surtout lorsqu'il est compilé en mode ZTS (*thread-safe*), ce qui est nécessaire pour FrankenPHP.
|
||||
surtout lorsqu'il est compilé en mode ZTS (_thread-safe_), ce qui est nécessaire pour FrankenPHP.
|
||||
|
||||
En outre, [certains bogues ne se produisent que lors de l'utilisation de musl](https://github.com/php/php-src/issues?q=sort%3Aupdated-desc+is%3Aissue+is%3Aopen+label%3ABug+musl).
|
||||
|
||||
@@ -53,7 +63,7 @@ Pour plus de détails, [la page de documentation Go dédiée à ce sujet](https:
|
||||
|
||||
## `file_server`
|
||||
|
||||
Par défaut, la directive `php_server` met automatiquement en place un serveur de fichiers pour
|
||||
Par défaut, la directive `php_server` met automatiquement en place un serveur de fichiers
|
||||
pour servir les fichiers statiques (assets) stockés dans le répertoire racine.
|
||||
|
||||
Cette fonctionnalité est pratique, mais a un coût.
|
||||
@@ -65,16 +75,54 @@ php_server {
|
||||
}
|
||||
```
|
||||
|
||||
## *Placeholders*
|
||||
## `try_files`
|
||||
|
||||
Vous pouvez utiliser des [*placeholders*](https://caddyserver.com/docs/conventions#placeholders) dans les directives `root` et `env`.
|
||||
En plus des fichiers statiques et des fichiers PHP, `php_server` essaiera aussi de servir les fichiers d'index
|
||||
et d'index de répertoire de votre application (`/path/` -> `/path/index.php`). Si vous n'avez pas besoin des index de répertoires,
|
||||
vous pouvez les désactiver en définissant explicitement `try_files` comme ceci :
|
||||
|
||||
```caddyfile
|
||||
php_server {
|
||||
try_files {path} index.php
|
||||
root /root/to/your/app # l'ajout explicite de la racine ici permet une meilleure mise en cache
|
||||
}
|
||||
```
|
||||
|
||||
Cela permet de réduire considérablement le nombre d'opérations inutiles sur les fichiers.
|
||||
|
||||
Une approche alternative avec 0 opérations inutiles sur le système de fichiers serait d'utiliser la directive `php`
|
||||
et de diviser les fichiers de PHP par chemin. Cette approche fonctionne bien si votre application entière est servie par un seul fichier d'entrée.
|
||||
Un exemple de [configuration](config.md#configuration-du-caddyfile) qui sert des fichiers statiques derrière un dossier `/assets` pourrait ressembler à ceci :
|
||||
|
||||
```caddyfile
|
||||
route {
|
||||
@assets {
|
||||
path /assets/*
|
||||
}
|
||||
|
||||
# tout ce qui se trouve derrière /assets est géré par le serveur de fichiers
|
||||
file_server @assets {
|
||||
root /root/to/your/app
|
||||
}
|
||||
|
||||
# tout ce qui n'est pas dans /assets est géré par votre index ou votre fichier PHP worker
|
||||
rewrite index.php
|
||||
php {
|
||||
root /root/to/your/app # l'ajout explicite de la racine ici permet une meilleure mise en cache
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## _Placeholders_
|
||||
|
||||
Vous pouvez utiliser des [_placeholders_](https://caddyserver.com/docs/conventions#placeholders) dans les directives `root` et `env`.
|
||||
Cependant, cela empêche la mise en cache de ces valeurs et a un coût important en termes de performances.
|
||||
|
||||
Si possible, évitez les *placeholders* dans ces directives.
|
||||
Si possible, évitez les _placeholders_ dans ces directives.
|
||||
|
||||
## `resolve_root_symlink`
|
||||
|
||||
Par défaut, si le *document root* est un lien symbolique, il est automatiquement résolu par FrankenPHP (c'est nécessaire pour le bon fonctionnement de PHP).
|
||||
Par défaut, si le _document root_ est un lien symbolique, il est automatiquement résolu par FrankenPHP (c'est nécessaire pour le bon fonctionnement de PHP).
|
||||
Si la racine du document n'est pas un lien symbolique, vous pouvez désactiver cette fonctionnalité.
|
||||
|
||||
```caddyfile
|
||||
@@ -83,12 +131,12 @@ php_server {
|
||||
}
|
||||
```
|
||||
|
||||
Cela améliorera les performances si la directive `root` contient des [*placeholders*](https://caddyserver.com/docs/conventions#placeholders).
|
||||
Cela améliorera les performances si la directive `root` contient des [_placeholders_](https://caddyserver.com/docs/conventions#placeholders).
|
||||
Le gain sera négligeable dans les autres cas.
|
||||
|
||||
## Journaux
|
||||
|
||||
La journalisation est évidemment très utile, mais, par définition, elle nécessite des opérations d'*I/O* et des allocations de mémoire,
|
||||
La journalisation est évidemment très utile, mais, par définition, elle nécessite des opérations d'_I/O_ et des allocations de mémoire,
|
||||
ce qui réduit considérablement les performances.
|
||||
Assurez-vous de [définir le niveau de journalisation](https://caddyserver.com/docs/caddyfile/options#log) correctement,
|
||||
et de ne journaliser que ce qui est nécessaire.
|
||||
@@ -100,10 +148,10 @@ Toutes les optimisations de performances habituelles liées à PHP s'appliquent
|
||||
|
||||
En particulier :
|
||||
|
||||
* vérifiez que [OPcache](https://www.php.net/manual/en/book.opcache.php) est installé, activé et correctement configuré
|
||||
* activez [les optimisations de l'autoloader de Composer](https://getcomposer.org/doc/articles/autoloader-optimization.md)
|
||||
* assurez-vous que le cache `realpath` est suffisamment grand pour les besoins de votre application
|
||||
* utilisez le [pré-chargement](https://www.php.net/manual/en/opcache.preloading.php)
|
||||
- vérifiez que [OPcache](https://www.php.net/manual/en/book.opcache.php) est installé, activé et correctement configuré
|
||||
- activez [les optimisations de l'autoloader de Composer](https://getcomposer.org/doc/articles/autoloader-optimization.md)
|
||||
- assurez-vous que le cache `realpath` est suffisamment grand pour les besoins de votre application
|
||||
- utilisez le [pré-chargement](https://www.php.net/manual/en/opcache.preloading.php)
|
||||
|
||||
Pour plus de détails, lisez [l'entrée de la documentation dédiée de Symfony](https://symfony.com/doc/current/performance.html)
|
||||
(la plupart des conseils sont utiles même si vous n'utilisez pas Symfony).
|
||||
|
||||
@@ -4,20 +4,49 @@ Au lieu d'utiliser une installation locale de la bibliothèque PHP, il est possi
|
||||
|
||||
Avec cette méthode, un binaire portable unique contiendra l'interpréteur PHP, le serveur web Caddy et FrankenPHP !
|
||||
|
||||
Les exécutables natifs entièrement statiques ne nécessitent aucune dépendance et peuvent même être exécutés sur une [image Docker `scratch`](https://docs.docker.com/build/building/base-images/#create-a-minimal-base-image-using-scratch).
|
||||
Cependant, ils ne peuvent pas charger les extensions dynamiques de PHP (comme Xdebug) et ont quelques limitations parce qu'ils utilisent la librairie musl.
|
||||
|
||||
La plupart des binaires statiques ne nécessitent que la `glibc` et peuvent charger des extensions dynamiques.
|
||||
|
||||
Lorsque c'est possible, nous recommandons d'utiliser des binaires statiques basés sur la glibc.
|
||||
|
||||
FrankenPHP permet également [d'embarquer l'application PHP dans le binaire statique](embed.md).
|
||||
|
||||
## Linux
|
||||
|
||||
Nous fournissons une image Docker pour créer un binaire statique pour Linux :
|
||||
Nous fournissons des images Docker pour créer des binaires statiques pour Linux :
|
||||
|
||||
### Build entièrement statique, basé sur musl
|
||||
|
||||
Pour un binaire entièrement statique qui fonctionne sur n'importe quelle distribution Linux sans dépendances,
|
||||
mais qui ne prend pas en charge le chargement dynamique des extensions :
|
||||
|
||||
```console
|
||||
docker buildx bake --load static-builder
|
||||
docker cp $(docker create --name static-builder dunglas/frankenphp:static-builder):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp ; docker rm static-builder
|
||||
docker buildx bake --load static-builder-musl
|
||||
docker cp $(docker create --name static-builder-musl dunglas/frankenphp:static-builder-musl):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp ; docker rm static-builder-musl
|
||||
```
|
||||
|
||||
Le binaire statique résultant est nommé `frankenphp`, et il est disponible dans le répertoire courant.
|
||||
Pour améliorer les performances dans les scénarios fortement concurrents, envisagez d'utiliser l'allocateur [mimalloc](https://github.com/microsoft/mimalloc).
|
||||
|
||||
Si vous souhaitez construire le binaire statique sans Docker, regardez les instructions pour macOS, qui fonctionnent également pour Linux.
|
||||
```console
|
||||
docker buildx bake --load --set static-builder-musl.args.MIMALLOC=1 static-builder-musl
|
||||
```
|
||||
|
||||
### Construction principalement statique (avec prise en charge des extensions dynamiques), basé sur la glibc
|
||||
|
||||
Pour un binaire qui supporte le chargement dynamique des extensions PHP tout en ayant les extensions sélectionnées compilées statiquement :
|
||||
|
||||
```console
|
||||
docker buildx bake --load static-builder-gnu
|
||||
docker cp $(docker create --name static-builder-gnu dunglas/frankenphp:static-builder-gnu):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp ; docker rm static-builder-gnu
|
||||
```
|
||||
|
||||
Ce binaire supporte toutes les versions 2.17 et supérieures de la glibc mais ne fonctionne pas sur les systèmes basés sur musl (comme Alpine Linux).
|
||||
|
||||
Le binaire résultant, principalement statique (à l'exception de `glibc`), est nommé `frankenphp` et est disponible dans le répertoire courant.
|
||||
|
||||
Si vous voulez construire le binaire statique sans Docker, jetez un coup d'œil aux instructions pour macOS, qui fonctionnent aussi pour Linux.
|
||||
|
||||
### Extensions personnalisées
|
||||
|
||||
@@ -28,7 +57,7 @@ Pour réduire la taille du binaire et diminuer la surface d'attaque, vous pouvez
|
||||
Par exemple, exécutez la commande suivante pour ne construire que l'extension `opcache` :
|
||||
|
||||
```console
|
||||
docker buildx bake --load --set static-builder.args.PHP_EXTENSIONS=opcache,pdo_sqlite static-builder
|
||||
docker buildx bake --load --set static-builder-musl.args.PHP_EXTENSIONS=opcache,pdo_sqlite static-builder-musl
|
||||
# ...
|
||||
```
|
||||
|
||||
@@ -37,9 +66,9 @@ Pour ajouter des bibliothèques permettant des fonctionnalités supplémentaires
|
||||
```console
|
||||
docker buildx bake \
|
||||
--load \
|
||||
--set static-builder.args.PHP_EXTENSIONS=gd \
|
||||
--set static-builder.args.PHP_EXTENSION_LIBS=libjpeg,libwebp \
|
||||
static-builder
|
||||
--set static-builder-musl.args.PHP_EXTENSIONS=gd \
|
||||
--set static-builder-musl.args.PHP_EXTENSION_LIBS=libjpeg,libwebp \
|
||||
static-builder-musl
|
||||
```
|
||||
|
||||
### Modules supplémentaires de Caddy
|
||||
@@ -49,8 +78,8 @@ Pour ajouter des modules Caddy supplémentaires ou passer d'autres arguments à
|
||||
```console
|
||||
docker buildx bake \
|
||||
--load \
|
||||
--set static-builder.args.XCADDY_ARGS="--with github.com/darkweak/souin/plugins/caddy --with github.com/dunglas/caddy-cbrotli --with github.com/dunglas/mercure/caddy --with github.com/dunglas/vulcain/caddy" \
|
||||
static-builder
|
||||
--set static-builder-musl.args.XCADDY_ARGS="--with github.com/darkweak/souin/plugins/caddy --with github.com/dunglas/caddy-cbrotli --with github.com/dunglas/mercure/caddy --with github.com/dunglas/vulcain/caddy" \
|
||||
static-builder-musl
|
||||
```
|
||||
|
||||
Dans cet exemple, nous ajoutons le module de cache HTTP [Souin](https://souin.io) pour Caddy ainsi que les modules [cbrotli](https://github.com/dunglas/caddy-cbrotli), [Mercure](https://mercure.rocks) et [Vulcain](https://vulcain.rocks).
|
||||
@@ -67,7 +96,7 @@ Voir aussi comment [personnaliser la construction](#personnalisation-de-la-const
|
||||
Si vous atteignez la limite de taux d'appels de l'API GitHub, définissez un jeton d'accès personnel GitHub dans une variable d'environnement nommée `GITHUB_TOKEN` :
|
||||
|
||||
```console
|
||||
GITHUB_TOKEN="xxx" docker --load buildx bake static-builder
|
||||
GITHUB_TOKEN="xxx" docker --load buildx bake static-builder-musl
|
||||
# ...
|
||||
```
|
||||
|
||||
@@ -87,14 +116,46 @@ Note : ce script fonctionne également sur Linux (et probablement sur d'autres U
|
||||
|
||||
Les variables d'environnement suivantes peuvent être transmises à `docker build` et au script `build-static.sh` pour personnaliser la construction statique :
|
||||
|
||||
* `FRANKENPHP_VERSION` : la version de FrankenPHP à utiliser
|
||||
* `PHP_VERSION` : la version de PHP à utiliser
|
||||
* `PHP_EXTENSIONS` : les extensions PHP à construire ([liste des extensions prises en charge](https://static-php.dev/en/guide/extensions.html))
|
||||
* `PHP_EXTENSION_LIBS` : bibliothèques supplémentaires à construire qui ajoutent des fonctionnalités aux extensions
|
||||
* `XCADDY_ARGS` : arguments à passer à [xcaddy](https://github.com/caddyserver/xcaddy), par exemple pour ajouter des modules Caddy supplémentaires
|
||||
* `EMBED` : chemin de l'application PHP à intégrer dans le binaire
|
||||
* `CLEAN` : lorsque défini, `libphp` et toutes ses dépendances sont construites à partir de zéro (pas de cache)
|
||||
* `DEBUG_SYMBOLS` : lorsque défini, les symboles de débogage ne seront pas supprimés et seront ajoutés dans le binaire
|
||||
* `NO_COMPRESS`: ne pas compresser le binaire avec UPX
|
||||
* `MIMALLOC`: (expérimental, Linux seulement) remplace l'allocateur mallocng de musl par [mimalloc](https://github.com/microsoft/mimalloc) pour des performances améliorées
|
||||
* `RELEASE` : (uniquement pour les mainteneurs) lorsque défini, le binaire résultant sera uploadé sur GitHub
|
||||
- `FRANKENPHP_VERSION` : la version de FrankenPHP à utiliser
|
||||
- `PHP_VERSION` : la version de PHP à utiliser
|
||||
- `PHP_EXTENSIONS` : les extensions PHP à construire ([liste des extensions prises en charge](https://static-php.dev/en/guide/extensions.html))
|
||||
- `PHP_EXTENSION_LIBS` : bibliothèques supplémentaires à construire qui ajoutent des fonctionnalités aux extensions
|
||||
- `XCADDY_ARGS` : arguments à passer à [xcaddy](https://github.com/caddyserver/xcaddy), par exemple pour ajouter des modules Caddy supplémentaires
|
||||
- `EMBED` : chemin de l'application PHP à intégrer dans le binaire
|
||||
- `CLEAN` : lorsque défini, `libphp` et toutes ses dépendances sont construites à partir de zéro (pas de cache)
|
||||
- `DEBUG_SYMBOLS` : lorsque défini, les symboles de débogage ne seront pas supprimés et seront ajoutés dans le binaire
|
||||
- `NO_COMPRESS`: ne pas compresser le binaire avec UPX
|
||||
- `MIMALLOC`: (expérimental, Linux seulement) remplace l'allocateur mallocng de musl par [mimalloc](https://github.com/microsoft/mimalloc) pour des performances améliorées
|
||||
- `RELEASE` : (uniquement pour les mainteneurs) lorsque défini, le binaire résultant sera uploadé sur GitHub
|
||||
|
||||
## Extensions
|
||||
|
||||
Avec la glibc ou les binaires basés sur macOS, vous pouvez charger des extensions PHP dynamiquement. Cependant, ces extensions devront être compilées avec le support ZTS.
|
||||
Comme la plupart des gestionnaires de paquets ne proposent pas de versions ZTS de leurs extensions, vous devrez les compiler vous-même.
|
||||
|
||||
Pour cela, vous pouvez construire et exécuter le conteneur Docker `static-builder-gnu`, vous y connecter à distance et compiler les extensions avec `./configure --with-php-config=/go/src/app/dist/static-php-cli/buildroot/bin/php-config`.
|
||||
|
||||
Exemple d'étapes pour [l'extension Xdebug](https://xdebug.org) :
|
||||
|
||||
```console
|
||||
docker build -t gnu-ext -f static-builder-gnu.Dockerfile --build-arg FRANKENPHP_VERSION=1.0 .
|
||||
docker create --name static-builder-gnu -it gnu-ext /bin/sh
|
||||
docker start static-builder-gnu
|
||||
docker exec -it static-builder-gnu /bin/sh
|
||||
cd /go/src/app/dist/static-php-cli/buildroot/bin
|
||||
git clone https://github.com/xdebug/xdebug.git && cd xdebug
|
||||
source scl_source enable devtoolset-10
|
||||
../phpize
|
||||
./configure --with-php-config=/go/src/app/dist/static-php-cli/buildroot/bin/php-config
|
||||
make
|
||||
exit
|
||||
docker cp static-builder-gnu:/go/src/app/dist/static-php-cli/buildroot/bin/xdebug/modules/xdebug.so xdebug-zts.so
|
||||
docker cp static-builder-gnu:/go/src/app/dist/frankenphp-linux-$(uname -m) ./frankenphp
|
||||
docker stop static-builder-gnu
|
||||
docker rm static-builder-gnu
|
||||
docker rmi gnu-ext
|
||||
```
|
||||
|
||||
Cela aura créé `frankenphp` et `xdebug-zts.so` dans le répertoire courant.
|
||||
Si vous déplacez `xdebug-zts.so` dans votre répertoire d'extension, ajoutez `zend_extension=xdebug-zts.so` à votre php.ini
|
||||
et lancez FrankenPHP, il chargera Xdebug.
|
||||
|
||||
@@ -28,6 +28,13 @@ frankenphp php-server --worker /path/to/your/worker/script.php
|
||||
Si votre application PHP est [intégrée dans le binaire](embed.md), vous pouvez également ajouter un `Caddyfile` personnalisé dans le répertoire racine de l'application.
|
||||
Il sera utilisé automatiquement.
|
||||
|
||||
Il est également possible de [redémarrer le worker en cas de changement de fichier](config.md#surveillance-des-modifications-de-fichier) avec l'option `--watch`.
|
||||
La commande suivante déclenchera un redémarrage si un fichier se terminant par `.php` dans le répertoire `/path/to/your/app/` ou ses sous-répertoires est modifié :
|
||||
|
||||
```console
|
||||
frankenphp php-server --worker /path/to/your/worker/script.php --watch="/path/to/your/app/**/*.php"
|
||||
```
|
||||
|
||||
## Runtime Symfony
|
||||
|
||||
Le mode worker de FrankenPHP est pris en charge par le [Composant Runtime de Symfony](https://symfony.com/doc/current/components/runtime.html).
|
||||
@@ -76,14 +83,17 @@ $handler = static function () use ($myApp) {
|
||||
echo $myApp->handle($_GET, $_POST, $_COOKIE, $_FILES, $_SERVER);
|
||||
};
|
||||
|
||||
for ($nbRequests = 0, $running = true; isset($_SERVER['MAX_REQUESTS']) && ($nbRequests < ((int)$_SERVER['MAX_REQUESTS'])) && $running; ++$nbRequests) {
|
||||
$running = \frankenphp_handle_request($handler);
|
||||
$maxRequests = (int)($_SERVER['MAX_REQUESTS'] ?? 0);
|
||||
for ($nbRequests = 0; !$maxRequests || $nbRequests < $maxRequests; ++$nbRequests) {
|
||||
$keepRunning = \frankenphp_handle_request($handler);
|
||||
|
||||
// Faire quelque chose après l'envoi de la réponse HTTP
|
||||
$myApp->terminate();
|
||||
|
||||
// Exécuter le ramasse-miettes pour réduire les chances qu'il soit déclenché au milieu de la génération d'une page
|
||||
gc_collect_cycles();
|
||||
|
||||
if (!$keepRunning) break;
|
||||
}
|
||||
|
||||
// Nettoyage
|
||||
@@ -118,13 +128,35 @@ Une solution pour utiliser ce type de code en mode worker est de redémarrer le
|
||||
|
||||
Le code du worker précédent permet de configurer un nombre maximal de requêtes à traiter en définissant une variable d'environnement nommée `MAX_REQUESTS`.
|
||||
|
||||
### Redémarrer les workers manuellement
|
||||
|
||||
Bien qu'il soit possible de redémarrer les workers [en cas de changement de fichier](config.md#surveillance-des-modifications-de-fichier),
|
||||
il est également possible de redémarrer tous les workers de manière élégante via l'[API Admin de Caddy](https://caddyserver.com/docs/api).
|
||||
Si l'administration est activée dans votre [Caddyfile](config.md#configuration-du-caddyfile), vous pouvez envoyer un ping
|
||||
à l'endpoint de redémarrage avec une simple requête POST comme celle-ci :
|
||||
|
||||
```console
|
||||
curl -X POST http://localhost:2019/frankenphp/workers/restart
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
>
|
||||
> C'est une fonctionnalité expérimentale et peut être modifiée ou supprimée dans le futur.
|
||||
|
||||
### Worker Failures
|
||||
|
||||
Si un script de worker se plante avec un code de sortie non nul, FrankenPHP le redémarre avec une stratégie de backoff exponentielle.
|
||||
Si le script worker reste en place plus longtemps que le dernier backoff \* 2, FrankenPHP ne pénalisera pas le script et le redémarrera à nouveau.
|
||||
Toutefois, si le script de worker continue d'échouer avec un code de sortie non nul dans un court laps de temps
|
||||
(par exemple, une faute de frappe dans un script), FrankenPHP plantera avec l'erreur : `too many consecutive failures` (trop d'échecs consécutifs).
|
||||
|
||||
## Comportement des superglobales
|
||||
|
||||
[Les superglobales PHP](https://www.php.net/manual/fr/language.variables.superglobals.php) (`$_SERVER`, `$_ENV`, `$_GET`...)
|
||||
se comportent comme suit :
|
||||
|
||||
* avant le premier appel à `frankenphp_handle_request()`, les superglobales contiennent des valeurs liées au script worker lui-même
|
||||
* pendant et après l'appel à `frankenphp_handle_request()`, les superglobales contiennent des valeurs générées à partir de la requête HTTP traitée, chaque appel à `frankenphp_handle_request()` change les valeurs des superglobales
|
||||
- avant le premier appel à `frankenphp_handle_request()`, les superglobales contiennent des valeurs liées au script worker lui-même
|
||||
- pendant et après l'appel à `frankenphp_handle_request()`, les superglobales contiennent des valeurs générées à partir de la requête HTTP traitée, chaque appel à `frankenphp_handle_request()` change les valeurs des superglobales
|
||||
|
||||
Pour accéder aux superglobales du script worker à l'intérieur de la fonction de rappel, vous devez les copier et importer la copie dans le scope de la fonction :
|
||||
|
||||
|
||||
71
docs/fr/x-sendfile.md
Normal file
71
docs/fr/x-sendfile.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Servir efficacement les gros fichiers statiques (`X-Sendfile`/`X-Accel-Redirect`)
|
||||
|
||||
Habituellement, les fichiers statiques peuvent être servis directement par le serveur web,
|
||||
mais parfois, il est nécessaire d'exécuter du code PHP avant de les envoyer :
|
||||
contrôle d'accès, statistiques, en-têtes HTTP personnalisés...
|
||||
|
||||
Malheureusement, utiliser PHP pour servir de gros fichiers statiques est inefficace comparé à
|
||||
à l'utilisation directe du serveur web (surcharge mémoire, diminution des performances...).
|
||||
|
||||
FrankenPHP permet de déléguer l'envoi des fichiers statiques au serveur web
|
||||
**après** avoir exécuté du code PHP personnalisé.
|
||||
|
||||
Pour ce faire, votre application PHP n'a qu'à définir un en-tête HTTP personnalisé
|
||||
contenant le chemin du fichier à servir. FrankenPHP se chargera du reste.
|
||||
|
||||
Cette fonctionnalité est connue sous le nom de **`X-Sendfile`** pour Apache, et **`X-Accel-Redirect`** pour NGINX.
|
||||
|
||||
Dans les exemples suivants, nous supposons que le "document root" du projet est le répertoire `public/`
|
||||
et que nous voulons utiliser PHP pour servir des fichiers stockés en dehors du dossier `public/`,
|
||||
depuis un répertoire nommé `private-files/`.
|
||||
|
||||
## Configuration
|
||||
|
||||
Tout d'abord, ajoutez la configuration suivante à votre `Caddyfile` pour activer cette fonctionnalité :
|
||||
|
||||
```patch
|
||||
root public/
|
||||
# ...
|
||||
|
||||
+ # Needed for Symfony, Laravel and other projects using the Symfony HttpFoundation component
|
||||
+ request_header X-Sendfile-Type x-accel-redirect
|
||||
+ request_header X-Accel-Mapping ../private-files=/private-files
|
||||
+
|
||||
+ intercept {
|
||||
+ @accel header X-Accel-Redirect *
|
||||
+ handle_response @accel {
|
||||
+ root private-files/
|
||||
+ rewrite * {resp.header.X-Accel-Redirect}
|
||||
+ method * GET
|
||||
+
|
||||
+ # Remove the X-Accel-Redirect header set by PHP for increased security
|
||||
+ header -X-Accel-Redirect
|
||||
+
|
||||
+ file_server
|
||||
+ }
|
||||
+ }
|
||||
|
||||
php_server
|
||||
```
|
||||
|
||||
## PHP simple
|
||||
|
||||
Définissez le chemin relatif du fichier (à partir de `private-files/`) comme valeur de l'en-tête `X-Accel-Redirect` :
|
||||
|
||||
```php
|
||||
header('X-Accel-Redirect: file.txt') ;
|
||||
```
|
||||
|
||||
## Projets utilisant le composant Symfony HttpFoundation (Symfony, Laravel, Drupal...)
|
||||
|
||||
Symfony HttpFoundation [supporte nativement cette fonctionnalité](https://symfony.com/doc/current/components/http_foundation.html#serving-files).
|
||||
Il va automatiquement déterminer la bonne valeur pour l'en-tête `X-Accel-Redirect` et l'ajoutera à la réponse.
|
||||
|
||||
```php
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
|
||||
BinaryFileResponse::trustXSendfileTypeHeader();
|
||||
$response = new BinaryFileResponse(__DIR__.'/../private-files/file.txt');
|
||||
|
||||
// ...
|
||||
```
|
||||
@@ -5,7 +5,7 @@
|
||||
The following extensions are known not to be compatible with FrankenPHP:
|
||||
|
||||
| Name | Reason | Alternatives |
|
||||
|-------------------------------------------------------------------------------------------------------------|-----------------|----------------------------------------------------------------------------------------------------------------------|
|
||||
| ----------------------------------------------------------------------------------------------------------- | --------------- | -------------------------------------------------------------------------------------------------------------------- |
|
||||
| [imap](https://www.php.net/manual/en/imap.installation.php) | Not thread-safe | [javanile/php-imap2](https://github.com/javanile/php-imap2), [webklex/php-imap](https://github.com/Webklex/php-imap) |
|
||||
| [newrelic](https://docs.newrelic.com/docs/apm/agents/php-agent/getting-started/introduction-new-relic-php/) | Not thread-safe | - |
|
||||
|
||||
@@ -14,7 +14,7 @@ The following extensions are known not to be compatible with FrankenPHP:
|
||||
The following extensions have known bugs and unexpected behaviors when used with FrankenPHP:
|
||||
|
||||
| Name | Problem |
|
||||
|---------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [ext-openssl](https://www.php.net/manual/en/book.openssl.php) | When using a static build of FrankenPHP (built with the musl libc), the OpenSSL extension may crash under heavy loads. A workaround is to use a dynamically linked build (like the one used in Docker images). This bug is [being tracked by PHP](https://github.com/php/php-src/issues/13648). |
|
||||
|
||||
## get_browser
|
||||
@@ -80,8 +80,8 @@ docker run \
|
||||
|
||||
[Composer scripts](https://getcomposer.org/doc/articles/scripts.md) may want to execute a PHP binary for some tasks, e.g. in [a Laravel project](laravel.md) to run `@php artisan package:discover --ansi`. This [currently fails](https://github.com/dunglas/frankenphp/issues/483#issuecomment-1899890915) for two reasons:
|
||||
|
||||
* Composer does not know how to call the FrankenPHP binary;
|
||||
* Composer may add PHP settings using the `-d` flag in the command, which FrankenPHP does not yet support.
|
||||
- Composer does not know how to call the FrankenPHP binary;
|
||||
- Composer may add PHP settings using the `-d` flag in the command, which FrankenPHP does not yet support.
|
||||
|
||||
As a workaround, we can create a shell script in `/usr/local/bin/php` which strips the unsupported parameters and then calls FrankenPHP:
|
||||
|
||||
|
||||
138
docs/laravel.md
138
docs/laravel.md
@@ -16,26 +16,26 @@ And enjoy!
|
||||
|
||||
Alternatively, you can run your Laravel projects with FrankenPHP from your local machine:
|
||||
|
||||
1. [Download the binary corresponding to your system](../README.md#standalone-binary)
|
||||
1. [Download the binary corresponding to your system](../#standalone-binary)
|
||||
2. Add the following configuration to a file named `Caddyfile` in the root directory of your Laravel project:
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
frankenphp
|
||||
}
|
||||
```caddyfile
|
||||
{
|
||||
frankenphp
|
||||
}
|
||||
|
||||
# The domain name of your server
|
||||
localhost {
|
||||
# Set the webroot to the public/ directory
|
||||
root * public/
|
||||
# Enable compression (optional)
|
||||
encode zstd br gzip
|
||||
# Execute PHP files from the public/ directory and serve assets
|
||||
php_server {
|
||||
try_files {path} index.php
|
||||
}
|
||||
}
|
||||
```
|
||||
# The domain name of your server
|
||||
localhost {
|
||||
# Set the webroot to the public/ directory
|
||||
root public/
|
||||
# Enable compression (optional)
|
||||
encode zstd br gzip
|
||||
# Execute PHP files from the public/ directory and serve assets
|
||||
php_server {
|
||||
try_files {path} index.php
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. Start FrankenPHP from the root directory of your Laravel project: `frankenphp run`
|
||||
|
||||
@@ -61,17 +61,17 @@ php artisan octane:frankenphp
|
||||
|
||||
The `octane:frankenphp` command can take the following options:
|
||||
|
||||
* `--host`: The IP address the server should bind to (default: `127.0.0.1`)
|
||||
* `--port`: The port the server should be available on (default: `8000`)
|
||||
* `--admin-port`: The port the admin server should be available on (default: `2019`)
|
||||
* `--workers`: The number of workers that should be available to handle requests (default: `auto`)
|
||||
* `--max-requests`: The number of requests to process before reloading the server (default: `500`)
|
||||
* `--caddyfile`: The path to the FrankenPHP `Caddyfile` file (default: [stubbed `Caddyfile` in Laravel Octane](https://github.com/laravel/octane/blob/2.x/src/Commands/stubs/Caddyfile))
|
||||
* `--https`: Enable HTTPS, HTTP/2, and HTTP/3, and automatically generate and renew certificates
|
||||
* `--http-redirect`: Enable HTTP to HTTPS redirection (only enabled if --https is passed)
|
||||
* `--watch`: Automatically reload the server when the application is modified
|
||||
* `--poll`: Use file system polling while watching in order to watch files over a network
|
||||
* `--log-level`: Log messages at or above the specified log level, using the native Caddy logger
|
||||
- `--host`: The IP address the server should bind to (default: `127.0.0.1`)
|
||||
- `--port`: The port the server should be available on (default: `8000`)
|
||||
- `--admin-port`: The port the admin server should be available on (default: `2019`)
|
||||
- `--workers`: The number of workers that should be available to handle requests (default: `auto`)
|
||||
- `--max-requests`: The number of requests to process before reloading the server (default: `500`)
|
||||
- `--caddyfile`: The path to the FrankenPHP `Caddyfile` file (default: [stubbed `Caddyfile` in Laravel Octane](https://github.com/laravel/octane/blob/2.x/src/Commands/stubs/Caddyfile))
|
||||
- `--https`: Enable HTTPS, HTTP/2, and HTTP/3, and automatically generate and renew certificates
|
||||
- `--http-redirect`: Enable HTTP to HTTPS redirection (only enabled if --https is passed)
|
||||
- `--watch`: Automatically reload the server when the application is modified
|
||||
- `--poll`: Use file system polling while watching in order to watch files over a network
|
||||
- `--log-level`: Log messages at or above the specified log level, using the native Caddy logger
|
||||
|
||||
> [!TIP]
|
||||
> To get structured JSON logs (useful when using log analytics solutions), explicitly the pass `--log-level` option.
|
||||
@@ -87,72 +87,72 @@ Follow these steps to package your Laravel app as a standalone binary for Linux:
|
||||
|
||||
1. Create a file named `static-build.Dockerfile` in the repository of your app:
|
||||
|
||||
```dockerfile
|
||||
FROM --platform=linux/amd64 dunglas/frankenphp:static-builder
|
||||
```dockerfile
|
||||
FROM --platform=linux/amd64 dunglas/frankenphp:static-builder
|
||||
|
||||
# Copy your app
|
||||
WORKDIR /go/src/app/dist/app
|
||||
COPY . .
|
||||
# Copy your app
|
||||
WORKDIR /go/src/app/dist/app
|
||||
COPY . .
|
||||
|
||||
# Remove the tests and other unneeded files to save space
|
||||
# Alternatively, add these files to a .dockerignore file
|
||||
RUN rm -Rf tests/
|
||||
# Remove the tests and other unneeded files to save space
|
||||
# Alternatively, add these files to a .dockerignore file
|
||||
RUN rm -Rf tests/
|
||||
|
||||
# Copy .env file
|
||||
RUN cp .env.example .env
|
||||
# Change APP_ENV and APP_DEBUG to be production ready
|
||||
RUN sed -i'' -e 's/^APP_ENV=.*/APP_ENV=production/' -e 's/^APP_DEBUG=.*/APP_DEBUG=false/' .env
|
||||
# Copy .env file
|
||||
RUN cp .env.example .env
|
||||
# Change APP_ENV and APP_DEBUG to be production ready
|
||||
RUN sed -i'' -e 's/^APP_ENV=.*/APP_ENV=production/' -e 's/^APP_DEBUG=.*/APP_DEBUG=false/' .env
|
||||
|
||||
# Make other changes to your .env file if needed
|
||||
# Make other changes to your .env file if needed
|
||||
|
||||
# Install the dependencies
|
||||
RUN composer install --ignore-platform-reqs --no-dev -a
|
||||
# Install the dependencies
|
||||
RUN composer install --ignore-platform-reqs --no-dev -a
|
||||
|
||||
# Build the static binary
|
||||
WORKDIR /go/src/app/
|
||||
RUN EMBED=dist/app/ ./build-static.sh
|
||||
```
|
||||
# Build the static binary
|
||||
WORKDIR /go/src/app/
|
||||
RUN EMBED=dist/app/ ./build-static.sh
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
>
|
||||
> Some `.dockerignore` files
|
||||
> will ignore the `vendor/` directory and `.env` files. Be sure to adjust or remove the `.dockerignore` file before the build.
|
||||
> [!CAUTION]
|
||||
>
|
||||
> Some `.dockerignore` files
|
||||
> will ignore the `vendor/` directory and `.env` files. Be sure to adjust or remove the `.dockerignore` file before the build.
|
||||
|
||||
2. Build:
|
||||
|
||||
```console
|
||||
docker build -t static-laravel-app -f static-build.Dockerfile .
|
||||
```
|
||||
```console
|
||||
docker build -t static-laravel-app -f static-build.Dockerfile .
|
||||
```
|
||||
|
||||
3. Extract the binary:
|
||||
|
||||
```console
|
||||
docker cp $(docker create --name static-laravel-app-tmp static-laravel-app):/go/src/app/dist/frankenphp-linux-x86_64 frankenphp ; docker rm static-laravel-app-tmp
|
||||
```
|
||||
```console
|
||||
docker cp $(docker create --name static-laravel-app-tmp static-laravel-app):/go/src/app/dist/frankenphp-linux-x86_64 frankenphp ; docker rm static-laravel-app-tmp
|
||||
```
|
||||
|
||||
4. Populate caches:
|
||||
|
||||
```console
|
||||
frankenphp php-cli artisan optimize
|
||||
```
|
||||
```console
|
||||
frankenphp php-cli artisan optimize
|
||||
```
|
||||
|
||||
5. Run database migrations (if any):
|
||||
|
||||
```console
|
||||
frankenphp php-cli artisan migrate
|
||||
````
|
||||
```console
|
||||
frankenphp php-cli artisan migrate
|
||||
```
|
||||
|
||||
6. Generate app's secret key:
|
||||
|
||||
```console
|
||||
frankenphp php-cli artisan key:generate
|
||||
```
|
||||
```console
|
||||
frankenphp php-cli artisan key:generate
|
||||
```
|
||||
|
||||
7. Start the server:
|
||||
|
||||
```console
|
||||
frankenphp php-server
|
||||
```
|
||||
```console
|
||||
frankenphp php-server
|
||||
```
|
||||
|
||||
Your app is now ready!
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.5 MiB After Width: | Height: | Size: 1009 KiB |
@@ -1,12 +1,15 @@
|
||||
# Real-time
|
||||
|
||||
FrankenPHP comes with a built-in [Mercure](https://mercure.rocks) hub!
|
||||
Mercure allows to push events in real-time to all the connected devices: they will receive a JavaScript event instantly.
|
||||
Mercure allows you to push real-time events to all the connected devices: they will receive a JavaScript event instantly.
|
||||
|
||||
No JS library or SDK required!
|
||||
No JS library or SDK is required!
|
||||
|
||||

|
||||
|
||||
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).
|
||||
The path of the Mercure hub is `/.well-known/mercure`.
|
||||
When running FrankenPHP inside Docker, the full send URL would look like `http://php/.well-known/mercure` (with `php` being the container's name running FrankenPHP).
|
||||
|
||||
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).
|
||||
|
||||
@@ -2,14 +2,16 @@
|
||||
|
||||
When [Caddy metrics](https://caddyserver.com/docs/metrics) are enabled, FrankenPHP exposes the following metrics:
|
||||
|
||||
* `frankenphp_[worker]_total_workers`: The total number of workers.
|
||||
* `frankenphp_[worker]_busy_workers`: The number of workers currently processing a request.
|
||||
* `frankenphp_[worker]_worker_request_time`: The time spent processing requests by all workers.
|
||||
* `frankenphp_[worker]_worker_request_count`: The number of requests processed by all workers.
|
||||
* `frankenphp_[worker]_ready_workers`: The number of workers that have called `frankenphp_handle_request` at least once.
|
||||
* `frankenphp_[worker]_worker_crashes`: The number of times a worker has unexpectedly terminated.
|
||||
* `frankenphp_[worker]_worker_restarts`: The number of times a worker has been deliberately restarted.
|
||||
* `frankenphp_total_threads`: The total number of PHP threads.
|
||||
* `frankenphp_busy_threads`: The number of PHP threads currently processing a request (running workers always consume a thread).
|
||||
- `frankenphp_total_threads`: The total number of PHP threads.
|
||||
- `frankenphp_busy_threads`: The number of PHP threads currently processing a request (running workers always consume a thread).
|
||||
- `frankenphp_queue_depth`: The number of regular queued requests
|
||||
- `frankenphp_total_workers{worker="[worker_name]"}`: The total number of workers.
|
||||
- `frankenphp_busy_workers{worker="[worker_name]"}`: The number of workers currently processing a request.
|
||||
- `frankenphp_worker_request_time{worker="[worker_name]"}`: The time spent processing requests by all workers.
|
||||
- `frankenphp_worker_request_count{worker="[worker_name]"}`: The number of requests processed by all workers.
|
||||
- `frankenphp_ready_workers{worker="[worker_name]"}`: The number of workers that have called `frankenphp_handle_request` at least once.
|
||||
- `frankenphp_worker_crashes{worker="[worker_name]"}`: The number of times a worker has unexpectedly terminated.
|
||||
- `frankenphp_worker_restarts{worker="[worker_name]"}`: The number of times a worker has been deliberately restarted.
|
||||
- `frankenphp_worker_queue_depth{worker="[worker_name]"}`: The number of queued requests.
|
||||
|
||||
For worker metrics, the `[worker]` placeholder is replaced by the worker script path in the Caddyfile.
|
||||
For worker metrics, the `[worker_name]` placeholder is replaced by the worker name in the Caddyfile, otherwise absolute path of worker file will be used.
|
||||
|
||||
@@ -16,6 +16,16 @@ To find the right values, it's best to run load tests simulating real traffic.
|
||||
To configure the number of threads, use the `num_threads` option of the `php_server` and `php` directives.
|
||||
To change the number of workers, use the `num` option of the `worker` section of the `frankenphp` directive.
|
||||
|
||||
### `max_threads`
|
||||
|
||||
While it's always better to know exactly what your traffic will look like, real-life applications tend to be more
|
||||
unpredictable. The `max_threads` [configuration](config.md#caddyfile-config) allows FrankenPHP to automatically spawn additional threads at runtime up to the specified limit.
|
||||
`max_threads` can help you figure out how many threads you need to handle your traffic and can make the server more resilient to latency spikes.
|
||||
If set to `auto`, the limit will be estimated based on the `memory_limit` in your `php.ini`. If not able to do so,
|
||||
`auto` will instead default to 2x `num_threads`. Keep in mind that `auto` might strongly underestimate the number of threads needed.
|
||||
`max_threads` is similar to PHP FPM's [pm.max_children](https://www.php.net/manual/en/install.fpm.configuration.php#pm.max-children). The main difference is that FrankenPHP uses threads instead of
|
||||
processes and automatically delegates them across different worker scripts and 'classic mode' as needed.
|
||||
|
||||
## Worker Mode
|
||||
|
||||
Enabling [the worker mode](worker.md) dramatically improves performance,
|
||||
@@ -24,19 +34,18 @@ you need to create a worker script and to be sure that the app is not leaking me
|
||||
|
||||
## Don't Use musl
|
||||
|
||||
The static binaries we provide and the Alpine Linux variant of the official Docker images
|
||||
are using [the musl libc](https://musl.libc.org).
|
||||
The Alpine Linux variant of the official Docker images and the default binaries we provide are using [the musl libc](https://musl.libc.org).
|
||||
|
||||
PHP is known to be [significantly slower](https://gitlab.alpinelinux.org/alpine/aports/-/issues/14381) when using this alternative C library instead of the traditional GNU library,
|
||||
especially when compiled in ZTS mode (thread-safe), which is required for FrankenPHP.
|
||||
PHP is known to be [slower](https://gitlab.alpinelinux.org/alpine/aports/-/issues/14381) when using this alternative C library instead of the traditional GNU library,
|
||||
especially when compiled in ZTS mode (thread-safe), which is required for FrankenPHP. The difference can be significant in a heavily threaded environment.
|
||||
|
||||
Also, [some bugs only happen when using musl](https://github.com/php/php-src/issues?q=sort%3Aupdated-desc+is%3Aissue+is%3Aopen+label%3ABug+musl).
|
||||
|
||||
In production environments, we strongly recommend to use the glibc.
|
||||
In production environments, we recommend using FrankenPHP linked against glibc.
|
||||
|
||||
This can be achieved by using the Debian Docker images (the default) and [by compiling FrankenPHP from sources](compile.md).
|
||||
This can be achieved by using the Debian Docker images (the default), downloading the -gnu suffix binary from our [Releases](https://github.com/dunglas/frankenphp/releases), or by [compiling FrankenPHP from sources](compile.md).
|
||||
|
||||
Alternatively, we provide static binaries compiled with [the mimalloc allocator](https://github.com/microsoft/mimalloc), which makes FrankenPHP+musl faster (but still slower than FrankenPHP+glibc).
|
||||
Alternatively, we provide static musl binaries compiled with [the mimalloc allocator](https://github.com/microsoft/mimalloc), which alleviates the problems in threaded scenarios.
|
||||
|
||||
## Go Runtime Configuration
|
||||
|
||||
@@ -139,10 +148,10 @@ All usual PHP-related performance optimizations apply with FrankenPHP.
|
||||
|
||||
In particular:
|
||||
|
||||
* check that [OPcache](https://www.php.net/manual/en/book.opcache.php) is installed, enabled and properly configured
|
||||
* enable [Composer autoloader optimizations](https://getcomposer.org/doc/articles/autoloader-optimization.md)
|
||||
* ensure that the `realpath` cache is big enough for the needs of your application
|
||||
* use [preloading](https://www.php.net/manual/en/opcache.preloading.php)
|
||||
- check that [OPcache](https://www.php.net/manual/en/book.opcache.php) is installed, enabled and properly configured
|
||||
- enable [Composer autoloader optimizations](https://getcomposer.org/doc/articles/autoloader-optimization.md)
|
||||
- ensure that the `realpath` cache is big enough for the needs of your application
|
||||
- use [preloading](https://www.php.net/manual/en/opcache.preloading.php)
|
||||
|
||||
For more details, read [the dedicated Symfony documentation entry](https://symfony.com/doc/current/performance.html)
|
||||
(most tips are useful even if you don't use Symfony).
|
||||
|
||||
@@ -124,7 +124,7 @@ git clone git@github.com:<username>/<project-name>.git
|
||||
Go into the directory containing your project (`<project-name>`), and start the app in production mode:
|
||||
|
||||
```console
|
||||
docker compose up -d --wait
|
||||
docker compose up --wait
|
||||
```
|
||||
|
||||
Your server is up and running, and an HTTPS certificate has been automatically generated for you.
|
||||
|
||||
218
docs/ru/CONTRIBUTING.md
Normal file
218
docs/ru/CONTRIBUTING.md
Normal file
@@ -0,0 +1,218 @@
|
||||
# Участие в проекте
|
||||
|
||||
## Компиляция PHP
|
||||
|
||||
### С помощью Docker (Linux)
|
||||
|
||||
Создайте образ Docker для разработки:
|
||||
|
||||
```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 -p 443:443/udp -v $PWD:/go/src/app -it frankenphp-dev
|
||||
```
|
||||
|
||||
Образ содержит стандартные инструменты для разработки (Go, GDB, Valgrind, Neovim и др.) и использует следующие пути для настроек PHP
|
||||
|
||||
- php.ini: `/etc/frankenphp/php.ini` По умолчанию предоставляется файл php.ini с настройками для разработки.
|
||||
- дополнительные файлы конфигурации: `/etc/frankenphp/php.d/*.ini`
|
||||
- расширения php: `/usr/lib/frankenphp/modules/`
|
||||
|
||||
Если ваша версия Docker ниже 23.0, сборка может завершиться ошибкой из-за [проблемы с шаблонами dockerignore](https://github.com/moby/moby/pull/42676). Добавьте в `.dockerignore` следующие директории:
|
||||
|
||||
```patch
|
||||
!testdata/*.php
|
||||
!testdata/*.txt
|
||||
+!caddy
|
||||
+!internal
|
||||
```
|
||||
|
||||
### Без Docker (Linux и macOS)
|
||||
|
||||
[Следуйте инструкциям по компиляции из исходников](https://frankenphp.dev/docs/compile/) и укажите флаг конфигурации `--debug`.
|
||||
|
||||
## Запуск тестов
|
||||
|
||||
```console
|
||||
go test -tags watcher -race -v ./...
|
||||
```
|
||||
|
||||
## Модуль Caddy
|
||||
|
||||
Соберите Caddy с модулем FrankenPHP:
|
||||
|
||||
```console
|
||||
cd caddy/frankenphp/
|
||||
go build -tags watcher,brotli,nobadger,nomysql,nopgx
|
||||
cd ../../
|
||||
```
|
||||
|
||||
Запустите Caddy с модулем FrankenPHP:
|
||||
|
||||
```console
|
||||
cd testdata/
|
||||
../caddy/frankenphp/frankenphp run
|
||||
```
|
||||
|
||||
Сервер будет доступен по адресу `127.0.0.1:8080`:
|
||||
|
||||
```console
|
||||
curl -vk https://localhost/phpinfo.php
|
||||
```
|
||||
|
||||
## Минимальный тестовый сервер
|
||||
|
||||
Соберите минимальный тестовый сервер:
|
||||
|
||||
```console
|
||||
cd internal/testserver/
|
||||
go build
|
||||
cd ../../
|
||||
```
|
||||
|
||||
Запустите тестовый сервер:
|
||||
|
||||
```console
|
||||
cd testdata/
|
||||
../internal/testserver/testserver
|
||||
```
|
||||
|
||||
Сервер будет доступен по адресу `127.0.0.1:8080`:
|
||||
|
||||
```console
|
||||
curl -v http://127.0.0.1:8080/phpinfo.php
|
||||
```
|
||||
|
||||
## Локальная сборка Docker-образов
|
||||
|
||||
Выведите план bake:
|
||||
|
||||
```console
|
||||
docker buildx bake -f docker-bake.hcl --print
|
||||
```
|
||||
|
||||
Соберите образы FrankenPHP для amd64 локально:
|
||||
|
||||
```console
|
||||
docker buildx bake -f docker-bake.hcl --pull --load --set "*.platform=linux/amd64"
|
||||
```
|
||||
|
||||
Соберите образы FrankenPHP для arm64 локально:
|
||||
|
||||
```console
|
||||
docker buildx bake -f docker-bake.hcl --pull --load --set "*.platform=linux/arm64"
|
||||
```
|
||||
|
||||
Соберите образы FrankenPHP с нуля для arm64 и amd64 и отправьте их в Docker Hub:
|
||||
|
||||
```console
|
||||
docker buildx bake -f docker-bake.hcl --pull --no-cache --push
|
||||
```
|
||||
|
||||
## Отладка ошибок сегментации с использованием статических сборок
|
||||
|
||||
1. Скачайте отладочную версию бинарного файла FrankenPHP с GitHub или создайте собственную статическую сборку с включённым отладочным режимом:
|
||||
|
||||
```console
|
||||
docker buildx bake \
|
||||
--load \
|
||||
--set static-builder.args.DEBUG_SYMBOLS=1 \
|
||||
--set "static-builder.platform=linux/amd64" \
|
||||
static-builder
|
||||
docker cp $(docker create --name static-builder-musl dunglas/frankenphp:static-builder-musl):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp
|
||||
```
|
||||
|
||||
2. Замените текущую версию `frankenphp` на бинарный файл с включенным отладочным режимом.
|
||||
3. Запустите FrankenPHP как обычно (или сразу запустите FrankenPHP с GDB: `gdb --args frankenphp run`).
|
||||
4. Подключитесь к процессу через GDB:
|
||||
|
||||
```console
|
||||
gdb -p `pidof frankenphp`
|
||||
```
|
||||
|
||||
5. При необходимости введите `continue` в консоли GDB.
|
||||
6. Вызовите сбой FrankenPHP.
|
||||
7. Введите `bt` в консоли GDB.
|
||||
8. Скопируйте вывод.
|
||||
|
||||
## Отладка ошибок сегментации в GitHub Actions
|
||||
|
||||
1. Откройте файл `.github/workflows/tests.yml`.
|
||||
2. Включите режим отладки PHP:
|
||||
|
||||
```patch
|
||||
- uses: shivammathur/setup-php@v2
|
||||
# ...
|
||||
env:
|
||||
phpts: ts
|
||||
+ debug: true
|
||||
```
|
||||
|
||||
3. Настройте `tmate` для удалённого подключения к контейнеру:
|
||||
|
||||
```patch
|
||||
-
|
||||
name: Set CGO flags
|
||||
run: echo "CGO_CFLAGS=$(php-config --includes)" >> "$GITHUB_ENV"
|
||||
+ -
|
||||
+ run: |
|
||||
+ sudo apt install gdb
|
||||
+ mkdir -p /home/runner/.config/gdb/
|
||||
+ printf "set auto-load safe-path /\nhandle SIG34 nostop noprint pass" > /home/runner/.config/gdb/gdbinit
|
||||
+ -
|
||||
+ uses: mxschmitt/action-tmate@v3
|
||||
```
|
||||
|
||||
4. Подключитесь к контейнеру.
|
||||
5. Откройте файл `frankenphp.go`.
|
||||
6. Включите `cgosymbolizer`:
|
||||
|
||||
```patch
|
||||
- //_ "github.com/ianlancetaylor/cgosymbolizer"
|
||||
+ _ "github.com/ianlancetaylor/cgosymbolizer"
|
||||
```
|
||||
|
||||
7. Загрузите модуль: `go get`.
|
||||
8. В контейнере используйте GDB и другие инструменты:
|
||||
|
||||
```console
|
||||
go test -tags watcher -c -ldflags=-w
|
||||
gdb --args frankenphp.dev.test -test.run ^MyTest$
|
||||
```
|
||||
|
||||
9. После исправления ошибки откатите все внесенные изменения.
|
||||
|
||||
## Дополнительные ресурсы для разработки
|
||||
|
||||
- [Встраивание PHP в uWSGI](https://github.com/unbit/uwsgi/blob/master/plugins/php/php_plugin.c)
|
||||
- [Встраивание PHP в NGINX Unit](https://github.com/nginx/unit/blob/master/src/nxt_php_sapi.c)
|
||||
- [Встраивание PHP в Go (go-php)](https://github.com/deuill/go-php)
|
||||
- [Встраивание PHP в Go (GoEmPHP)](https://github.com/mikespook/goemphp)
|
||||
- [Встраивание PHP в C++](https://gist.github.com/paresy/3cbd4c6a469511ac7479aa0e7c42fea7)
|
||||
- [Книга "Extending and Embedding PHP" Сары Големан](https://books.google.fr/books?id=zMbGvK17_tYC&pg=PA254&lpg=PA254#v=onepage&q&f=false)
|
||||
- [Статья: Что такое TSRMLS_CC?](http://blog.golemon.com/2006/06/what-heck-is-tsrmlscc-anyway.html)
|
||||
- [SDL bindings](https://pkg.go.dev/github.com/veandco/go-sdl2@v0.4.21/sdl#Main)
|
||||
|
||||
## Docker-ресурсы
|
||||
|
||||
- [Определение файлов bake](https://docs.docker.com/build/customize/bake/file-definition/)
|
||||
- [Документация по команде `docker buildx build`](https://docs.docker.com/engine/reference/commandline/buildx_build/)
|
||||
|
||||
## Полезные команды
|
||||
|
||||
```console
|
||||
apk add strace util-linux gdb
|
||||
strace -e 'trace=!futex,epoll_ctl,epoll_pwait,tgkill,rt_sigreturn' -p 1
|
||||
```
|
||||
|
||||
## Перевод документации
|
||||
|
||||
Чтобы перевести документацию и сайт на новый язык, выполните следующие шаги:
|
||||
|
||||
1. Создайте новую директорию с 2-буквенным ISO-кодом языка в папке `docs/`.
|
||||
2. Скопируйте все `.md` файлы из корня папки `docs/` в новую директорию (используйте английскую версию как основу для перевода).
|
||||
3. Скопируйте файлы `README.md` и `CONTRIBUTING.md` из корневой директории в новую папку.
|
||||
4. Переведите содержимое файлов, но не изменяйте имена файлов. Не переводите строки, начинающиеся с `> [!`, это специальная разметка GitHub.
|
||||
5. Создайте Pull Request с переводом.
|
||||
6. В [репозитории сайта](https://github.com/dunglas/frankenphp-website/tree/main) скопируйте и переведите файлы в папках `content/`, `data/` и `i18n/`.
|
||||
7. Переведите значения в созданных YAML-файлах.
|
||||
8. Откройте Pull Request в репозитории сайта.
|
||||
86
docs/ru/README.md
Normal file
86
docs/ru/README.md
Normal file
@@ -0,0 +1,86 @@
|
||||
# FrankenPHP: Современный сервер приложений для PHP
|
||||
|
||||
<h1 align="center"><a href="https://frankenphp.dev"><img src="../../frankenphp.png" alt="FrankenPHP" width="600"></a></h1>
|
||||
|
||||
**FrankenPHP** — это современный сервер приложений для PHP, построенный на базе веб-сервера [Caddy](https://caddyserver.com/).
|
||||
|
||||
FrankenPHP добавляет новые возможности вашим PHP-приложениям благодаря следующим функциям: [_Early Hints_](https://frankenphp.dev/docs/early-hints/), [Worker режим](https://frankenphp.dev/docs/worker/), [Real-time режим](https://frankenphp.dev/docs/mercure/), автоматическая поддержка HTTPS, HTTP/2 и HTTP/3.
|
||||
|
||||
FrankenPHP совместим с любыми PHP-приложениями и значительно ускоряет ваши проекты на Laravel и Symfony благодаря их официальной поддержке в worker режиме.
|
||||
|
||||
FrankenPHP также может использоваться как автономная Go-библиотека для встраивания PHP в любое приложение с использованием `net/http`.
|
||||
|
||||
[**Узнайте больше** на сайте _frankenphp.dev_](https://frankenphp.dev) или из этой презентации:
|
||||
|
||||
<a href="https://dunglas.dev/2022/10/frankenphp-the-modern-php-app-server-written-in-go/"><img src="https://dunglas.dev/wp-content/uploads/2022/10/frankenphp.png" alt="Slides" width="600"></a>
|
||||
|
||||
## Начало работы
|
||||
|
||||
### Docker
|
||||
|
||||
```console
|
||||
docker run -v .:/app/public \
|
||||
-p 80:80 -p 443:443 -p 443:443/udp \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
|
||||
Перейдите по адресу `https://localhost` и наслаждайтесь!
|
||||
|
||||
> [!TIP]
|
||||
>
|
||||
> Не используйте `https://127.0.0.1`. Используйте `https://localhost` и настройте самоподписанный сертификат.
|
||||
> Чтобы изменить используемый домен, настройте переменную окружения [`SERVER_NAME`](config.md#переменные-окружения).
|
||||
|
||||
### Автономный бинарный файл
|
||||
|
||||
Если вы предпочитаете не использовать Docker, мы предоставляем автономный бинарный файл FrankenPHP для Linux и macOS, включающий [PHP 8.4](https://www.php.net/releases/8.4/en.php) и большинство популярных PHP-расширений.
|
||||
|
||||
Для Windows используйте [WSL](https://learn.microsoft.com/windows/wsl/) для запуска FrankenPHP.
|
||||
|
||||
[Скачать FrankenPHP](https://github.com/dunglas/frankenphp/releases) или выполните следующую команду для автоматической установки подходящей версии:
|
||||
|
||||
```console
|
||||
curl https://frankenphp.dev/install.sh | sh
|
||||
mv frankenphp /usr/local/bin/
|
||||
```
|
||||
|
||||
Для запуска содержимого текущей директории выполните:
|
||||
|
||||
```console
|
||||
frankenphp php-server
|
||||
```
|
||||
|
||||
Вы также можете запускать CLI-скрипты:
|
||||
|
||||
```console
|
||||
frankenphp php-cli /path/to/your/script.php
|
||||
```
|
||||
|
||||
## Документация
|
||||
|
||||
- [Worker режим](https://frankenphp.dev/docs/worker/)
|
||||
- [Поддержка Early Hints (103 HTTP статус код)](https://frankenphp.dev/docs/early-hints/)
|
||||
- [Real-time режим](https://frankenphp.dev/docs/mercure/)
|
||||
- [Конфигурация](https://frankenphp.dev/docs/config/)
|
||||
- [Docker-образы](https://frankenphp.dev/docs/docker/)
|
||||
- [Деплой в продакшен](https://frankenphp.dev/docs/production/)
|
||||
- [Оптимизация производительности](https://frankenphp.dev/docs/performance/)
|
||||
- [Создание автономного PHP-приложений](https://frankenphp.dev/docs/embed/)
|
||||
- [Создание статических бинарных файлов](https://frankenphp.dev/docs/static/)
|
||||
- [Компиляция из исходников](https://frankenphp.dev/docs/compile/)
|
||||
- [Интеграция с Laravel](https://frankenphp.dev/docs/laravel/)
|
||||
- [Известные проблемы](https://frankenphp.dev/docs/known-issues/)
|
||||
- [Демо-приложение (Symfony) и бенчмарки](https://github.com/dunglas/frankenphp-demo)
|
||||
- [Документация Go-библиотеки](https://pkg.go.dev/github.com/dunglas/frankenphp)
|
||||
- [Участие в проекте и отладка](https://frankenphp.dev/docs/contributing/)
|
||||
|
||||
## Примеры и шаблоны
|
||||
|
||||
- [Symfony](https://github.com/dunglas/symfony-docker)
|
||||
- [API Platform](https://api-platform.com/docs/symfony)
|
||||
- [Laravel](https://frankenphp.dev/docs/laravel/)
|
||||
- [Sulu](https://sulu.io/blog/running-sulu-with-frankenphp)
|
||||
- [WordPress](https://github.com/StephenMiracle/frankenwp)
|
||||
- [Drupal](https://github.com/dunglas/frankenphp-drupal)
|
||||
- [Joomla](https://github.com/alexandreelise/frankenphp-joomla)
|
||||
- [TYPO3](https://github.com/ochorocho/franken-typo3)
|
||||
110
docs/ru/compile.md
Normal file
110
docs/ru/compile.md
Normal file
@@ -0,0 +1,110 @@
|
||||
# Компиляция из исходников
|
||||
|
||||
Этот документ объясняет, как создать бинарный файл FrankenPHP, который будет загружать PHP как динамическую библиотеку.
|
||||
Это рекомендуемый способ.
|
||||
|
||||
Альтернативно можно создать [статическую сборку](static.md).
|
||||
|
||||
## Установка PHP
|
||||
|
||||
FrankenPHP совместим с PHP версии 8.2 и выше.
|
||||
|
||||
Сначала [загрузите исходники PHP](https://www.php.net/downloads.php) и распакуйте их:
|
||||
|
||||
```console
|
||||
tar xf php-*
|
||||
cd php-*/
|
||||
```
|
||||
|
||||
Далее выполните скрипт `configure` с параметрами, необходимыми для вашей платформы.
|
||||
Следующие флаги `./configure` обязательны, но вы можете добавить и другие, например, для компиляции расширений или дополнительных функций.
|
||||
|
||||
### Linux
|
||||
|
||||
```console
|
||||
./configure \
|
||||
--enable-embed \
|
||||
--enable-zts \
|
||||
--disable-zend-signals \
|
||||
--enable-zend-max-execution-timers
|
||||
```
|
||||
|
||||
### Mac
|
||||
|
||||
Используйте пакетный менеджер [Homebrew](https://brew.sh/) для установки
|
||||
`libiconv`, `bison`, `re2c` и `pkg-config`:
|
||||
|
||||
```console
|
||||
brew install libiconv bison brotli re2c pkg-config
|
||||
echo 'export PATH="/opt/homebrew/opt/bison/bin:$PATH"' >> ~/.zshrc
|
||||
```
|
||||
|
||||
Затем выполните скрипт configure:
|
||||
|
||||
```console
|
||||
./configure \
|
||||
--enable-embed=static \
|
||||
--enable-zts \
|
||||
--disable-zend-signals \
|
||||
--disable-opcache-jit \
|
||||
--enable-static \
|
||||
--enable-shared=no \
|
||||
--with-iconv=/opt/homebrew/opt/libiconv/
|
||||
```
|
||||
|
||||
## Компиляция PHP
|
||||
|
||||
Наконец, скомпилируйте и установите PHP:
|
||||
|
||||
```console
|
||||
make -j"$(getconf _NPROCESSORS_ONLN)"
|
||||
sudo make install
|
||||
```
|
||||
|
||||
## Установка дополнительных зависимостей
|
||||
|
||||
Некоторые функции FrankenPHP зависят от опциональных системных зависимостей.
|
||||
Альтернативно, эти функции можно отключить, передав соответствующие теги сборки компилятору Go.
|
||||
|
||||
| Функция | Зависимость | Тег сборки для отключения |
|
||||
| ----------------------------------------------- | --------------------------------------------------------------------- | ------------------------- |
|
||||
| Сжатие Brotli | [Brotli](https://github.com/google/brotli) | nobrotli |
|
||||
| Перезапуск worker-скриптов при изменении файлов | [Watcher C](https://github.com/e-dant/watcher/tree/release/watcher-c) | nowatcher |
|
||||
|
||||
## Компиляция Go-приложения
|
||||
|
||||
Теперь можно собрать итоговый бинарный файл:
|
||||
|
||||
```console
|
||||
curl -L https://github.com/dunglas/frankenphp/archive/refs/heads/main.tar.gz | tar xz
|
||||
cd frankenphp-main/caddy/frankenphp
|
||||
CGO_CFLAGS=$(php-config --includes) CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" go build -tags=nobadger,nomysql,nopgx
|
||||
```
|
||||
|
||||
### Использование xcaddy
|
||||
|
||||
Альтернативно, используйте [xcaddy](https://github.com/caddyserver/xcaddy) для компиляции FrankenPHP с [пользовательскими модулями Caddy](https://caddyserver.com/docs/modules/):
|
||||
|
||||
```console
|
||||
CGO_ENABLED=1 \
|
||||
XCADDY_GO_BUILD_FLAGS="-ldflags='-w -s' -tags=nobadger,nomysql,nopgx" \
|
||||
CGO_CFLAGS=$(php-config --includes) \
|
||||
CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" \
|
||||
xcaddy build \
|
||||
--output frankenphp \
|
||||
--with frankenphp.dev/caddy \
|
||||
--with github.com/dunglas/mercure/caddy \
|
||||
--with github.com/dunglas/vulcain/caddy
|
||||
# Добавьте дополнительные модули Caddy здесь
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
>
|
||||
> Если вы используете musl libc (по умолчанию в Alpine Linux) и Symfony,
|
||||
> возможно, потребуется увеличить размер стека.
|
||||
> В противном случае вы можете столкнуться с ошибками вроде
|
||||
> `PHP Fatal error: Maximum call stack size of 83360 bytes reached during compilation. Try splitting expression`.
|
||||
>
|
||||
> Для этого измените значение переменной окружения `XCADDY_GO_BUILD_FLAGS`, например:
|
||||
> `XCADDY_GO_BUILD_FLAGS=$'-ldflags "-w -s -extldflags \'-Wl,-z,stack-size=0x80000\'"'`
|
||||
> (измените значение размера стека в зависимости от требований вашего приложения).
|
||||
247
docs/ru/config.md
Normal file
247
docs/ru/config.md
Normal file
@@ -0,0 +1,247 @@
|
||||
# Конфигурация
|
||||
|
||||
FrankenPHP, Caddy, а также модули Mercure и Vulcain могут быть настроены с использованием [конфигурационных форматов, поддерживаемых Caddy](https://caddyserver.com/docs/getting-started#your-first-config).
|
||||
|
||||
В [Docker-образах](docker.md) файл `Caddyfile` находится по пути `/etc/frankenphp/Caddyfile`.
|
||||
Статический бинарный файл будет искать `Caddyfile` в директории запуска.
|
||||
|
||||
PHP можно настроить [с помощью файла `php.ini`](https://www.php.net/manual/en/configuration.file.php).
|
||||
|
||||
PHP-интерпретатор будет искать в следующих местах:
|
||||
|
||||
Docker:
|
||||
|
||||
- php.ini: `/usr/local/etc/php/php.ini` По умолчанию php.ini не предоставляется.
|
||||
- дополнительные файлы конфигурации: `/usr/local/etc/php/conf.d/*.ini`
|
||||
- расширения php: `/usr/local/lib/php/extensions/no-debug-zts-<YYYYMMDD>/`
|
||||
- Вы должны скопировать официальный шаблон, предоставляемый проектом PHP:
|
||||
|
||||
```dockerfile
|
||||
FROM dunglas/frankenphp
|
||||
|
||||
# Для production:
|
||||
RUN cp $PHP_INI_DIR/php.ini-production $PHP_INI_DIR/php.ini
|
||||
|
||||
# Или для development:
|
||||
RUN cp $PHP_INI_DIR/php.ini-development $PHP_INI_DIR/php.ini
|
||||
```
|
||||
|
||||
Установка FrankenPHP (.rpm или .deb):
|
||||
|
||||
- php.ini: `/etc/frankenphp/php.ini` По умолчанию предоставляется файл php.ini с производственными настройками.
|
||||
- дополнительные файлы конфигурации: `/etc/frankenphp/php.d/*.ini`
|
||||
- расширения php: `/usr/lib/frankenphp/modules/`
|
||||
|
||||
Статический бинарный файл:
|
||||
|
||||
- php.ini: Директория, в которой выполняется `frankenphp run` или `frankenphp php-server`, затем `/etc/frankenphp/php.ini`
|
||||
- дополнительные файлы конфигурации: `/etc/frankenphp/php.d/*.ini`
|
||||
- расширения php: не могут быть загружены
|
||||
- скопируйте один из шаблонов `php.ini-production` или `php.ini-development`, предоставленных [в исходниках PHP](https://github.com/php/php-src/).
|
||||
|
||||
## Конфигурация Caddyfile
|
||||
|
||||
[HTTP-директивы](https://caddyserver.com/docs/caddyfile/concepts#directives) `php_server` или `php` могут быть использованы в блоках сайта для обработки вашего PHP-приложения.
|
||||
|
||||
Минимальный пример:
|
||||
|
||||
```caddyfile
|
||||
localhost {
|
||||
# Включить сжатие (опционально)
|
||||
encode zstd br gzip
|
||||
# Выполнять PHP-файлы в текущей директории и обслуживать ресурсы
|
||||
php_server
|
||||
}
|
||||
```
|
||||
|
||||
Вы также можете явно настроить FrankenPHP с помощью глобальной опции:
|
||||
[Глобальная опция](https://caddyserver.com/docs/caddyfile/concepts#global-options) `frankenphp` может быть использована для настройки FrankenPHP.
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
frankenphp {
|
||||
num_threads <num_threads> # Указывает количество потоков PHP. По умолчанию: 2x от числа доступных CPU.
|
||||
worker {
|
||||
file <path> # Указывает путь к worker-скрипту.
|
||||
num <num> # Указывает количество потоков PHP. По умолчанию: 2x от числа доступных CPU.
|
||||
env <key> <value> # Устанавливает дополнительную переменную окружения. Можно указать несколько раз для разных переменных.
|
||||
watch <path> # Указывает путь для отслеживания изменений файлов.Можно указать несколько раз для разных путей.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ...
|
||||
```
|
||||
|
||||
В качестве альтернативы можно использовать однострочную краткую форму для опции `worker`:
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
frankenphp {
|
||||
worker <file> <num>
|
||||
}
|
||||
}
|
||||
|
||||
# ...
|
||||
```
|
||||
|
||||
Вы также можете определить несколько workers, если обслуживаете несколько приложений на одном сервере:
|
||||
|
||||
```caddyfile
|
||||
app.example.com {
|
||||
php_server {
|
||||
root /path/to/app/public
|
||||
worker index.php <num>
|
||||
}
|
||||
}
|
||||
|
||||
other.example.com {
|
||||
php_server {
|
||||
root /path/to/other/public
|
||||
worker index.php <num>
|
||||
}
|
||||
}
|
||||
|
||||
# ...
|
||||
```
|
||||
|
||||
Использование директивы `php_server` — это то, что нужно в большинстве случаев. Однако если требуется полный контроль, вы можете использовать более низкоуровневую директиву `php`:
|
||||
|
||||
Использование директивы `php_server` эквивалентно следующей конфигурации:
|
||||
|
||||
```caddyfile
|
||||
route {
|
||||
# Добавить слэш в конец запросов к директориям
|
||||
@canonicalPath {
|
||||
file {path}/index.php
|
||||
not path */
|
||||
}
|
||||
redir @canonicalPath {path}/ 308
|
||||
# Если запрошенный файл не существует, попытаться использовать файлы index
|
||||
@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
|
||||
file_server
|
||||
}
|
||||
```
|
||||
|
||||
Директивы `php_server` и `php` имеют следующие опции:
|
||||
|
||||
```caddyfile
|
||||
php_server [<matcher>] {
|
||||
root <directory> # Указывает корневую директорию сайта. По умолчанию: директива `root`.
|
||||
split_path <delim...> # Устанавливает подстроки для разделения URI на две части. Первая часть будет использована как имя ресурса (CGI-скрипта), вторая часть — как PATH_INFO. По умолчанию: `.php`.
|
||||
resolve_root_symlink false # Отключает разрешение символьных ссылок для `root` (включено по умолчанию).
|
||||
env <key> <value> # Устанавливает дополнительные переменные окружения. Можно указать несколько раз для разных переменных.
|
||||
file_server off # Отключает встроенную директиву file_server.
|
||||
worker { # Создает worker, специфичный для этого сервера. Можно указать несколько раз для разных workers.
|
||||
file <path> # Указывает путь к worker-скрипту, может быть относительным к корню php_server
|
||||
num <num> # Указывает количество потоков PHP. По умолчанию: 2x от числа доступных CPU.
|
||||
name <name> # Устанавливает имя для worker, используемое в логах и метриках. По умолчанию: абсолютный путь к файлу worker. Всегда начинается с m# при определении в блоке php_server.
|
||||
watch <path> # Указывает путь для отслеживания изменений файлов. Можно указать несколько раз для разных путей.
|
||||
env <key> <value> # Устанавливает дополнительную переменную окружения. Можно указать несколько раз для разных переменных. Переменные окружения для этого worker также наследуются от родительского php_server, но могут быть переопределены здесь.
|
||||
}
|
||||
worker <other_file> <num> # Также можно использовать краткую форму как в глобальном блоке frankenphp.
|
||||
}
|
||||
```
|
||||
|
||||
### Отслеживание изменений файлов
|
||||
|
||||
Поскольку workers запускают ваше приложение только один раз и держат его в памяти, изменения в PHP-файлах не будут применяться сразу.
|
||||
|
||||
Для разработки можно настроить перезапуск workers при изменении файлов с помощью директивы `watch`:
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
frankenphp {
|
||||
worker {
|
||||
file /path/to/app/public/worker.php
|
||||
watch
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Если директория для `watch` не указана, по умолчанию будет использоваться путь `./**/*.{php,yaml,yml,twig,env}`,
|
||||
который отслеживает все файлы с расширениями `.php`, `.yaml`, `.yml`, `.twig` и `.env` в директории, где был запущен процесс FrankenPHP, и во всех её поддиректориях. Вы также можете указать одну или несколько директорий с использованием [шаблона имён файлов](https://pkg.go.dev/path/filepath#Match):
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
frankenphp {
|
||||
worker {
|
||||
file /path/to/app/public/worker.php
|
||||
watch /path/to/app # отслеживает все файлы во всех поддиректориях /path/to/app
|
||||
watch /path/to/app/*.php # отслеживает файлы с расширением .php в /path/to/app
|
||||
watch /path/to/app/**/*.php # отслеживает PHP-файлы в /path/to/app и поддиректориях
|
||||
watch /path/to/app/**/*.{php,twig} # отслеживает PHP и Twig-файлы в /path/to/app и поддиректориях
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- Шаблон `**` указывает на рекурсивное отслеживание.
|
||||
- Директории могут быть указаны относительно директории запуска FrankenPHP.
|
||||
- Если у вас определено несколько workers, все они будут перезапущены при изменении файлов.
|
||||
- Избегайте отслеживания файлов, создаваемых во время выполнения (например, логов), так как это может вызвать нежелательные перезапуски.
|
||||
|
||||
Механизм отслеживания файлов основан на [e-dant/watcher](https://github.com/e-dant/watcher).
|
||||
|
||||
### Полный дуплекс (HTTP/1)
|
||||
|
||||
При использовании HTTP/1.x можно включить режим полного дуплекса, чтобы разрешить запись ответа до завершения чтения тела запроса (например, для WebSocket, Server-Sent Events и т.д.).
|
||||
|
||||
Эта опция включается вручную и должна быть добавлена в глобальные настройки `Caddyfile`:
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
servers {
|
||||
enable_full_duplex
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
>
|
||||
> Включение этой опции может привести к зависанию устаревших HTTP/1.x клиентов, которые не поддерживают полный дуплекс.
|
||||
> Настройка также доступна через переменную окружения `CADDY_GLOBAL_OPTIONS`:
|
||||
|
||||
```sh
|
||||
CADDY_GLOBAL_OPTIONS="servers {
|
||||
enable_full_duplex
|
||||
}"
|
||||
```
|
||||
|
||||
Дополнительную информацию об этой настройке можно найти в [документации Caddy](https://caddyserver.com/docs/caddyfile/options#enable-full-duplex).
|
||||
|
||||
## Переменные окружения
|
||||
|
||||
Следующие переменные окружения могут быть использованы для добавления директив в `Caddyfile` без его изменения:
|
||||
|
||||
- `SERVER_NAME`: изменение [адресов для прослушивания](https://caddyserver.com/docs/caddyfile/concepts#addresses); предоставленные хостнеймы также будут использованы для генерации TLS-сертификата.
|
||||
- `CADDY_GLOBAL_OPTIONS`: добавление [глобальных опций](https://caddyserver.com/docs/caddyfile/options).
|
||||
- `FRANKENPHP_CONFIG`: добавление конфигурации в директиву `frankenphp`.
|
||||
|
||||
Как и для FPM и CLI SAPIs, переменные окружения по умолчанию доступны в суперглобальной переменной `$_SERVER`.
|
||||
|
||||
Значение `S` в [директиве PHP `variables_order`](https://www.php.net/manual/en/ini.core.php#ini.variables-order) всегда эквивалентно `ES`, независимо от того, где расположена `E` в этой директиве.
|
||||
|
||||
## Конфигурация PHP
|
||||
|
||||
Для загрузки [дополнительных конфигурационных файлов PHP](https://www.php.net/manual/en/configuration.file.php#configuration.file.scan) можно использовать переменную окружения `PHP_INI_SCAN_DIR`.
|
||||
Если она установлена, PHP загрузит все файлы с расширением `.ini`, находящиеся в указанных директориях.
|
||||
|
||||
## Включение режима отладки
|
||||
|
||||
При использовании Docker-образа установите переменную окружения `CADDY_GLOBAL_OPTIONS` в `debug`, чтобы включить режим отладки:
|
||||
|
||||
```console
|
||||
docker run -v $PWD:/app/public \
|
||||
-e CADDY_GLOBAL_OPTIONS=debug \
|
||||
-p 80:80 -p 443:443 -p 443:443/udp \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
201
docs/ru/docker.md
Normal file
201
docs/ru/docker.md
Normal file
@@ -0,0 +1,201 @@
|
||||
# Создание кастомных Docker-образов
|
||||
|
||||
[Docker-образы FrankenPHP](https://hub.docker.com/r/dunglas/frankenphp) основаны на [официальных PHP-образах](https://hub.docker.com/_/php/). Доступны варианты для Debian и Alpine Linux для популярных архитектур. Рекомендуется использовать Debian-варианты.
|
||||
|
||||
Доступны версии для PHP 8.2, 8.3 и 8.4.
|
||||
|
||||
Теги следуют следующему шаблону: `dunglas/frankenphp:<frankenphp-version>-php<php-version>-<os>`.
|
||||
|
||||
- `<frankenphp-version>` и `<php-version>` — версии FrankenPHP и PHP соответственно: от основных (например, `1`) до минорных (например, `1.2`) и патч-версий (например, `1.2.3`).
|
||||
- `<os>` может быть `bookworm` (для Debian Bookworm) или `alpine` (для последней стабильной версии Alpine).
|
||||
|
||||
[Просмотреть доступные теги](https://hub.docker.com/r/dunglas/frankenphp/tags).
|
||||
|
||||
## Как использовать образы
|
||||
|
||||
Создайте `Dockerfile` в вашем проекте:
|
||||
|
||||
```dockerfile
|
||||
FROM dunglas/frankenphp
|
||||
|
||||
COPY . /app/public
|
||||
```
|
||||
|
||||
Затем выполните следующие команды для сборки и запуска Docker-образа:
|
||||
|
||||
```console
|
||||
docker build -t my-php-app .
|
||||
docker run -it --rm --name my-running-app my-php-app
|
||||
```
|
||||
|
||||
## Как установить дополнительные PHP-расширения
|
||||
|
||||
Скрипт [`docker-php-extension-installer`](https://github.com/mlocati/docker-php-extension-installer) включён в базовый образ. Установка дополнительных PHP-расширений осуществляется просто:
|
||||
|
||||
```dockerfile
|
||||
FROM dunglas/frankenphp
|
||||
|
||||
# Добавьте дополнительные расширения здесь:
|
||||
RUN install-php-extensions \
|
||||
pdo_mysql \
|
||||
gd \
|
||||
intl \
|
||||
zip \
|
||||
opcache
|
||||
```
|
||||
|
||||
## Как установить дополнительные модули Caddy
|
||||
|
||||
FrankenPHP построен на базе Caddy, и все [модули Caddy](https://caddyserver.com/docs/modules/) можно использовать с FrankenPHP.
|
||||
|
||||
Самый простой способ установить пользовательские модули Caddy — использовать [xcaddy](https://github.com/caddyserver/xcaddy):
|
||||
|
||||
```dockerfile
|
||||
FROM dunglas/frankenphp:builder AS builder
|
||||
|
||||
# Копируем xcaddy в образ сборки
|
||||
COPY --from=caddy:builder /usr/bin/xcaddy /usr/bin/xcaddy
|
||||
|
||||
# Для сборки FrankenPHP необходимо включить CGO
|
||||
RUN CGO_ENABLED=1 \
|
||||
XCADDY_SETCAP=1 \
|
||||
XCADDY_GO_BUILD_FLAGS="-ldflags='-w -s' -tags=nobadger,nomysql,nopgx" \
|
||||
CGO_CFLAGS=$(php-config --includes) \
|
||||
CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" \
|
||||
xcaddy build \
|
||||
--output /usr/local/bin/frankenphp \
|
||||
--with frankenphp.dev=./ \
|
||||
--with frankenphp.dev/caddy=./caddy/ \
|
||||
--with github.com/dunglas/caddy-cbrotli \
|
||||
# Mercure и Vulcain включены в официальный билд, но вы можете их удалить
|
||||
--with github.com/dunglas/mercure/caddy \
|
||||
--with github.com/dunglas/vulcain/caddy
|
||||
# Добавьте дополнительные модули Caddy здесь
|
||||
|
||||
FROM dunglas/frankenphp AS runner
|
||||
|
||||
# Заменяем официальный бинарный файл на пользовательский с добавленными модулями
|
||||
COPY --from=builder /usr/local/bin/frankenphp /usr/local/bin/frankenphp
|
||||
```
|
||||
|
||||
Образ `builder`, предоставляемый FrankenPHP, содержит скомпилированную версию `libphp`.
|
||||
[Образы builder](https://hub.docker.com/r/dunglas/frankenphp/tags?name=builder) доступны для всех версий FrankenPHP и PHP, как для Debian, так и для Alpine.
|
||||
|
||||
> [!TIP]
|
||||
>
|
||||
> Если вы используете Alpine Linux и Symfony, возможно, потребуется [увеличить размер стека](compile.md#использование-xcaddy).
|
||||
|
||||
## Активировать worker режим по умолчанию
|
||||
|
||||
Установите переменную окружения `FRANKENPHP_CONFIG`, чтобы запускать FrankenPHP с Worker-скриптом:
|
||||
|
||||
```dockerfile
|
||||
FROM dunglas/frankenphp
|
||||
|
||||
# ...
|
||||
|
||||
ENV FRANKENPHP_CONFIG="worker ./public/index.php"
|
||||
```
|
||||
|
||||
## Использование тома в разработке
|
||||
|
||||
Для удобной разработки с FrankenPHP смонтируйте директорию с исходным кодом приложения на хосте как том в Docker-контейнере:
|
||||
|
||||
```console
|
||||
docker run -v $PWD:/app/public -p 80:80 -p 443:443 -p 443:443/udp --tty my-php-app
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
>
|
||||
> Опция `--tty` позволяет видеть удобочитаемые логи вместо JSON-формата.
|
||||
|
||||
С использованием Docker Compose:
|
||||
|
||||
```yaml
|
||||
# compose.yaml
|
||||
|
||||
services:
|
||||
php:
|
||||
image: dunglas/frankenphp
|
||||
# раскомментируйте следующую строку, если хотите использовать собственный Dockerfile
|
||||
#build: .
|
||||
# раскомментируйте следующую строку, если вы запускаете это в продакшн среде
|
||||
# restart: always
|
||||
ports:
|
||||
- "80:80" # HTTP
|
||||
- "443:443" # HTTPS
|
||||
- "443:443/udp" # HTTP/3
|
||||
volumes:
|
||||
- ./:/app/public
|
||||
- caddy_data:/data
|
||||
- caddy_config:/config
|
||||
# закомментируйте следующую строку в продакшн среде, она позволяет получать удобочитаемые логи в режиме разработки
|
||||
tty: true
|
||||
|
||||
# Томы, необходимые для сертификатов и конфигурации Caddy
|
||||
volumes:
|
||||
caddy_data:
|
||||
caddy_config:
|
||||
```
|
||||
|
||||
## Запуск под обычным пользователем
|
||||
|
||||
FrankenPHP поддерживает запуск под обычным пользователем в Docker.
|
||||
|
||||
Пример `Dockerfile` для этого:
|
||||
|
||||
```dockerfile
|
||||
FROM dunglas/frankenphp
|
||||
|
||||
ARG USER=appuser
|
||||
|
||||
RUN \
|
||||
# Для дистрибутивов на основе Alpine используйте "adduser -D ${USER}"
|
||||
useradd ${USER}; \
|
||||
# Добавьте возможность привязываться к портам 80 и 443
|
||||
setcap CAP_NET_BIND_SERVICE=+eip /usr/local/bin/frankenphp; \
|
||||
# Дайте права на запись для /data/caddy и /config/caddy
|
||||
chown -R ${USER}:${USER} /data/caddy && chown -R ${USER}:${USER} /config/caddy
|
||||
|
||||
USER ${USER}
|
||||
```
|
||||
|
||||
### Запуск без дополнительных прав
|
||||
|
||||
Даже при запуске без root-прав, FrankenPHP требуется возможность `CAP_NET_BIND_SERVICE` для привязки веб-сервера к зарезервированным портам (80 и 443).
|
||||
|
||||
Если вы открываете доступ к FrankenPHP на непривилегированном порту (1024 и выше), можно запустить веб-сервер от имени обычного пользователя без необходимости предоставления дополнительных возможностей:
|
||||
|
||||
```dockerfile
|
||||
FROM dunglas/frankenphp
|
||||
|
||||
ARG USER=appuser
|
||||
|
||||
RUN \
|
||||
# Для Alpine-дистрибутивов используйте команду "adduser -D ${USER}"
|
||||
useradd ${USER}; \
|
||||
# Удалите стандартные возможности
|
||||
setcap -r /usr/local/bin/frankenphp; \
|
||||
# Дайте права на запись для /data/caddy и /config/caddy
|
||||
chown -R ${USER}:${USER} /data/caddy && chown -R ${USER}:${USER} /config/caddy
|
||||
|
||||
USER ${USER}
|
||||
```
|
||||
|
||||
Затем установите переменную окружения `SERVER_NAME`, чтобы использовать непривилегированный порт.
|
||||
Пример: `:8000`.
|
||||
|
||||
## Обновления
|
||||
|
||||
Docker-образы обновляются:
|
||||
|
||||
- при выпуске новой версии;
|
||||
- ежедневно в 4 утра UTC, если доступны новые версии официальных PHP-образов.
|
||||
|
||||
## Версии для разработки
|
||||
|
||||
Версии для разработки доступны в Docker-репозитории [`dunglas/frankenphp-dev`](https://hub.docker.com/repository/docker/dunglas/frankenphp-dev).
|
||||
Сборка запускается автоматически при каждом коммите в основную ветку GitHub-репозитория
|
||||
|
||||
Теги с префиксом `latest*` указывают на актуальное состояние ветки `main`.
|
||||
Также доступны теги в формате `sha-<git-commit-hash>`.
|
||||
21
docs/ru/early-hints.md
Normal file
21
docs/ru/early-hints.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Early Hints
|
||||
|
||||
FrankenPHP изначально поддерживает [Early Hints (103 HTTP статус код)](https://developer.chrome.com/blog/early-hints/).
|
||||
Использование Early Hints может улучшить время загрузки ваших веб-страниц на 30%.
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
header('Link: </style.css>; rel=preload; as=style');
|
||||
headers_send(103);
|
||||
|
||||
// ваши медленные алгоритмы и SQL-запросы 🤪
|
||||
|
||||
echo <<<'HTML'
|
||||
<!DOCTYPE html>
|
||||
<title>Hello FrankenPHP</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
HTML;
|
||||
```
|
||||
|
||||
Early Hints поддерживается как в обычном, так и в [worker режиме](worker.md).
|
||||
140
docs/ru/embed.md
Normal file
140
docs/ru/embed.md
Normal file
@@ -0,0 +1,140 @@
|
||||
# PHP-приложения как автономные бинарные файлы
|
||||
|
||||
FrankenPHP позволяет встраивать исходный код и ресурсы PHP-приложений в статический автономный бинарный файл.
|
||||
|
||||
Благодаря этой функции PHP-приложения могут распространяться как автономные бинарные файлы, которые содержат само приложение, интерпретатор PHP и Caddy — веб-сервер уровня продакшн.
|
||||
|
||||
Подробнее об этой функции [в презентации Кевина на SymfonyCon 2023](https://dunglas.dev/2023/12/php-and-symfony-apps-as-standalone-binaries/).
|
||||
|
||||
Для встраивания Laravel-приложений ознакомьтесь с [документацией](laravel.md#laravel-приложения-как-автономные-бинарные-файлы).
|
||||
|
||||
## Подготовка приложения
|
||||
|
||||
Перед созданием автономного бинарного файла убедитесь, что ваше приложение готово для встраивания.
|
||||
|
||||
Например, вам может понадобиться:
|
||||
|
||||
- Установить продакшн-зависимости приложения.
|
||||
- Сгенерировать автозагрузчик.
|
||||
- Включить продакшн-режим приложения (если он есть).
|
||||
- Удалить ненужные файлы, такие как `.git` или тесты, чтобы уменьшить размер итогового бинарного файла.
|
||||
|
||||
Для приложения на Symfony это может выглядеть так:
|
||||
|
||||
```console
|
||||
# Экспорт проекта, чтобы избавиться от .git/ и других ненужных файлов
|
||||
mkdir $TMPDIR/my-prepared-app
|
||||
git archive HEAD | tar -x -C $TMPDIR/my-prepared-app
|
||||
cd $TMPDIR/my-prepared-app
|
||||
|
||||
# Установить соответствующие переменные окружения
|
||||
echo APP_ENV=prod > .env.local
|
||||
echo APP_DEBUG=0 >> .env.local
|
||||
|
||||
# Удалить тесты и другие ненужные файлы
|
||||
rm -Rf tests/
|
||||
|
||||
# Установить зависимости
|
||||
composer install --ignore-platform-reqs --no-dev -a
|
||||
|
||||
# Оптимизировать .env
|
||||
composer dump-env prod
|
||||
```
|
||||
|
||||
### Настройка конфигурации
|
||||
|
||||
Чтобы настроить [конфигурацию](config.md), вы можете разместить файлы `Caddyfile` и `php.ini` в основной директории приложения (`$TMPDIR/my-prepared-app` в примере выше).
|
||||
|
||||
## Создание бинарного файла для Linux
|
||||
|
||||
Самый простой способ создать бинарный файл для Linux — использовать предоставленный Docker-билдер.
|
||||
|
||||
1. Создайте файл `static-build.Dockerfile` в репозитории вашего приложения:
|
||||
|
||||
```dockerfile
|
||||
FROM --platform=linux/amd64 dunglas/frankenphp:static-builder
|
||||
|
||||
# Скопировать приложение
|
||||
WORKDIR /go/src/app/dist/app
|
||||
COPY . .
|
||||
|
||||
# Сборка статического бинарного файла
|
||||
WORKDIR /go/src/app/
|
||||
RUN EMBED=dist/app/ ./build-static.sh
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
>
|
||||
> Некоторые `.dockerignore` файлы (например, [Symfony Docker `.dockerignore`](https://github.com/dunglas/symfony-docker/blob/main/.dockerignore))
|
||||
> игнорируют директорию `vendor/` и файлы `.env`. Перед сборкой убедитесь, что `.dockerignore` файл настроен корректно или удалён.
|
||||
|
||||
2. Соберите образ:
|
||||
|
||||
```console
|
||||
docker build -t static-app -f static-build.Dockerfile .
|
||||
```
|
||||
|
||||
3. Извлеките бинарный файл:
|
||||
|
||||
```console
|
||||
docker cp $(docker create --name static-app-tmp static-app):/go/src/app/dist/frankenphp-linux-x86_64 my-app ; docker rm static-app-tmp
|
||||
```
|
||||
|
||||
Созданный бинарный файл сохранится в текущей директории под именем `my-app`.
|
||||
|
||||
## Создание бинарного файла для других ОС
|
||||
|
||||
Если вы не хотите использовать Docker или хотите собрать бинарный файл для macOS, используйте предоставленный скрипт:
|
||||
|
||||
```console
|
||||
git clone https://github.com/dunglas/frankenphp
|
||||
cd frankenphp
|
||||
EMBED=/path/to/your/app ./build-static.sh
|
||||
```
|
||||
|
||||
Итоговый бинарный файл будет находиться в директории `dist/` под именем `frankenphp-<os>-<arch>`.
|
||||
|
||||
## Использование бинарного файла
|
||||
|
||||
Готово! Файл `my-app` (или `dist/frankenphp-<os>-<arch>` для других ОС) содержит ваше автономное приложение.
|
||||
|
||||
Для запуска веб-приложения выполните:
|
||||
|
||||
```console
|
||||
./my-app php-server
|
||||
```
|
||||
|
||||
Если ваше приложение содержит [worker-скрипт](worker.md), запустите его следующим образом:
|
||||
|
||||
```console
|
||||
./my-app php-server --worker public/index.php
|
||||
```
|
||||
|
||||
Чтобы включить HTTPS (Let's Encrypt автоматически создаст сертификат), HTTP/2 и HTTP/3, укажите доменное имя:
|
||||
|
||||
```console
|
||||
./my-app php-server --domain localhost
|
||||
```
|
||||
|
||||
Вы также можете запускать PHP-скрипты CLI, встроенные в бинарный файл:
|
||||
|
||||
```console
|
||||
./my-app php-cli bin/console
|
||||
```
|
||||
|
||||
## PHP-расширения
|
||||
|
||||
По умолчанию скрипт собирает расширения, указанные в `composer.json` вашего проекта.
|
||||
Если файла `composer.json` нет, собираются стандартные расширения, как указано в [документации по статической сборке](static.md).
|
||||
|
||||
Чтобы настроить список расширений, используйте переменную окружения `PHP_EXTENSIONS`.
|
||||
|
||||
## Настройка сборки
|
||||
|
||||
[Ознакомьтесь с документацией по статической сборке](static.md), чтобы узнать, как настроить бинарный файл (расширения, версию PHP и т.д.).
|
||||
|
||||
## Распространение бинарного файла
|
||||
|
||||
На Linux созданный бинарный файл сжимается с помощью [UPX](https://upx.github.io).
|
||||
|
||||
На Mac для уменьшения размера файла перед отправкой его можно сжать. Рекомендуется использовать `xz`.
|
||||
30
docs/ru/github-actions.md
Normal file
30
docs/ru/github-actions.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# Использование GitHub Actions
|
||||
|
||||
Этот репозиторий автоматически собирает и публикует Docker-образы в [Docker Hub](https://hub.docker.com/r/dunglas/frankenphp) для каждого одобренного pull request или вашего собственного форка после настройки.
|
||||
|
||||
## Настройка GitHub Actions
|
||||
|
||||
В настройках репозитория, в разделе "Secrets", добавьте следующие секреты:
|
||||
|
||||
- `REGISTRY_LOGIN_SERVER`: Docker-реестр, который будет использоваться (например, `docker.io`).
|
||||
- `REGISTRY_USERNAME`: Имя пользователя для входа в реестр (например, `dunglas`).
|
||||
- `REGISTRY_PASSWORD`: Пароль для входа в реестр (например, токен доступа).
|
||||
- `IMAGE_NAME`: Имя образа (например, `dunglas/frankenphp`).
|
||||
|
||||
## Сборка и загрузка образа
|
||||
|
||||
1. Создайте Pull Request или выполните push в ваш форк.
|
||||
2. GitHub Actions соберёт образ и выполнит тесты.
|
||||
3. Если сборка пройдёт успешно, образ будет отправлен в реестр с тегом `pr-x`, где `x` — номер PR.
|
||||
|
||||
## Развёртывание образа
|
||||
|
||||
1. После слияния Pull Request GitHub Actions выполнит повторные тесты и соберёт новый образ.
|
||||
2. Если сборка пройдёт успешно, тег `main` будет обновлён в Docker-реестре.
|
||||
|
||||
## Релизы
|
||||
|
||||
1. Создайте новый тег в репозитории.
|
||||
2. GitHub Actions соберёт образ и выполнит тесты.
|
||||
3. Если сборка пройдёт успешно, образ будет отправлен в реестр с именем тега (например, `v1.2.3` и `v1.2` будут созданы).
|
||||
4. Также будет обновлён тег `latest`.
|
||||
140
docs/ru/known-issues.md
Normal file
140
docs/ru/known-issues.md
Normal file
@@ -0,0 +1,140 @@
|
||||
# Известные проблемы
|
||||
|
||||
## Неподдерживаемые расширения PHP
|
||||
|
||||
Следующие расширения не совместимы с FrankenPHP:
|
||||
|
||||
| Название | Причина | Альтернативы |
|
||||
| ----------------------------------------------------------------------------------------------------------- | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
||||
| [imap](https://www.php.net/manual/en/imap.installation.php) | Не поддерживает потокобезопасность | [javanile/php-imap2](https://github.com/javanile/php-imap2), [webklex/php-imap](https://github.com/Webklex/php-imap) |
|
||||
| [newrelic](https://docs.newrelic.com/docs/apm/agents/php-agent/getting-started/introduction-new-relic-php/) | Не поддерживает потокобезопасность | - |
|
||||
|
||||
## Проблемные расширения PHP
|
||||
|
||||
Следующие расширения имеют известные ошибки или могут вести себя непредсказуемо при использовании с FrankenPHP:
|
||||
|
||||
| Название | Проблема |
|
||||
| ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [ext-openssl](https://www.php.net/manual/en/book.openssl.php) | При использовании статической сборки FrankenPHP (на базе musl libc) расширение OpenSSL может аварийно завершаться при высокой нагрузке. Решение — использовать динамически связанную сборку (например, ту, что используется в Docker-образах). Ошибка [отслеживается сообществом PHP](https://github.com/php/php-src/issues/13648). |
|
||||
|
||||
## `get_browser`
|
||||
|
||||
Функция [get_browser()](https://www.php.net/manual/en/function.get-browser.php) начинает работать медленно через некоторое время. Решение — кэшировать результаты для каждого User-Agent, например, с помощью [APCu](https://www.php.net/manual/en/book.apcu.php), так как они статичны.
|
||||
|
||||
## Автономные бинарные файлы и образы на базе Alpine
|
||||
|
||||
Автономные бинарные файлы и образы на базе Alpine (`dunglas/frankenphp:*-alpine`) используют [musl libc](https://musl.libc.org/) вместо [glibc](https://www.etalabs.net/compare_libcs.html) для уменьшения размера бинарных файлов. Это может вызвать проблемы совместимости. В частности, флаг `GLOB_BRACE` в функции glob [не поддерживается](https://www.php.net/manual/en/function.glob.php).
|
||||
|
||||
## Использование `https://127.0.0.1` с Docker
|
||||
|
||||
По умолчанию FrankenPHP генерирует TLS-сертификат для `localhost`, что является самым простым и рекомендуемым вариантом для локальной разработки.
|
||||
|
||||
Если вы всё же хотите использовать `127.0.0.1`, настройте генерацию сертификата, указав в переменной окружения `SERVER_NAME` значение `127.0.0.1`.
|
||||
|
||||
Однако этого может не хватить при использовании Docker из-за [особенностей его сетевой системы](https://docs.docker.com/network/). Возможна ошибка TLS вида:
|
||||
`curl: (35) LibreSSL/3.3.6: error:1404B438:SSL routines:ST_CONNECT:tlsv1 alert internal error`.
|
||||
|
||||
Если вы используете Linux, можно воспользоваться [host-драйвером](https://docs.docker.com/network/network-tutorial-host/):
|
||||
|
||||
```console
|
||||
docker run \
|
||||
-e SERVER_NAME="127.0.0.1" \
|
||||
-v $PWD:/app/public \
|
||||
--network host \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
|
||||
Host-драйвер не поддерживается на Mac и Windows. На этих платформах нужно определить IP-адрес контейнера и включить его в `SERVER_NAME`.
|
||||
|
||||
Выполните команду `docker network inspect bridge`, найдите ключ `Containers` и определите последний присвоенный IP из `IPv4Address`. Увеличьте его на единицу. Если контейнеров нет, первый IP обычно `172.17.0.2`.
|
||||
|
||||
Включите этот IP в переменную окружения `SERVER_NAME`:
|
||||
|
||||
```console
|
||||
docker run \
|
||||
-e SERVER_NAME="127.0.0.1, 172.17.0.3" \
|
||||
-v $PWD:/app/public \
|
||||
-p 80:80 -p 443:443 -p 443:443/udp \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
> Обязательно замените `172.17.0.3` на IP, который будет присвоен вашему контейнеру.
|
||||
|
||||
Теперь вы должны иметь доступ к `https://127.0.0.1`.
|
||||
|
||||
Если это не так, запустите FrankenPHP в режиме отладки:
|
||||
|
||||
```console
|
||||
docker run \
|
||||
-e CADDY_GLOBAL_OPTIONS="debug" \
|
||||
-e SERVER_NAME="127.0.0.1" \
|
||||
-v $PWD:/app/public \
|
||||
-p 80:80 -p 443:443 -p 443:443/udp \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
|
||||
## Скрипты Composer с использованием `@php`
|
||||
|
||||
[Скрипты Composer](https://getcomposer.org/doc/articles/scripts.md) могут вызывать PHP для выполнения задач, например, в [проекте Laravel](laravel.md) для команды `@php artisan package:discover --ansi`.
|
||||
Это [на данный момент не поддерживается](https://github.com/dunglas/frankenphp/issues/483#issuecomment-1899890915) по двум причинам:
|
||||
|
||||
- Composer не знает, как вызывать бинарный файл FrankenPHP;
|
||||
- Composer может добавлять настройки PHP через флаг `-d`, который FrankenPHP пока не поддерживает.
|
||||
|
||||
Решение — создать shell-скрипт в `/usr/local/bin/php`, который удаляет неподдерживаемые параметры и вызывает FrankenPHP:
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
args=("$@")
|
||||
index=0
|
||||
for i in "$@"
|
||||
do
|
||||
if [ "$i" == "-d" ]; then
|
||||
unset 'args[$index]'
|
||||
unset 'args[$index+1]'
|
||||
fi
|
||||
index=$((index+1))
|
||||
done
|
||||
|
||||
/usr/local/bin/frankenphp php-cli ${args[@]}
|
||||
```
|
||||
|
||||
Затем установите переменную окружения `PHP_BINARY` на путь к нашему скрипту `php` и запустите Composer:
|
||||
|
||||
```console
|
||||
export PHP_BINARY=/usr/local/bin/php
|
||||
composer install
|
||||
```
|
||||
|
||||
## TLS/SSL: проблемы со статическими бинарными файлами
|
||||
|
||||
При использовании статических бинарных файлов могут возникать следующие ошибки TLS, например, при отправке писем через STARTTLS:
|
||||
|
||||
```text
|
||||
Unable to connect with STARTTLS: stream_socket_enable_crypto(): SSL operation failed with code 5. OpenSSL Error messages:
|
||||
error:80000002:system library::No such file or directory
|
||||
error:80000002:system library::No such file or directory
|
||||
error:80000002:system library::No such file or directory
|
||||
error:0A000086:SSL routines::certificate verify failed
|
||||
```
|
||||
|
||||
Статический бинарный файл не включает TLS-сертификаты, поэтому необходимо указать OpenSSL местоположение локальных сертификатов CA.
|
||||
|
||||
Выполните [`openssl_get_cert_locations()`](https://www.php.net/manual/en/function.openssl-get-cert-locations.php), чтобы определить, где должны находиться сертификаты CA, и поместите их туда.
|
||||
|
||||
> [!WARNING]
|
||||
> Веб и CLI контексты могут иметь разные настройки.
|
||||
> Запустите `openssl_get_cert_locations()` в нужном контексте.
|
||||
|
||||
[Сертификаты CA, извлечённые из Mozilla, можно скачать с сайта curl](https://curl.se/docs/caextract.html).
|
||||
|
||||
Кроме того, многие дистрибутивы, такие как Debian, Ubuntu и Alpine, предоставляют пакеты `ca-certificates`, содержащие эти сертификаты.
|
||||
|
||||
Также можно использовать переменные `SSL_CERT_FILE` и `SSL_CERT_DIR`, чтобы указать OpenSSL, где искать сертификаты CA:
|
||||
|
||||
```console
|
||||
# Установите переменные окружения для TLS-сертификатов
|
||||
export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
|
||||
export SSL_CERT_DIR=/etc/ssl/certs
|
||||
```
|
||||
176
docs/ru/laravel.md
Normal file
176
docs/ru/laravel.md
Normal file
@@ -0,0 +1,176 @@
|
||||
# Laravel
|
||||
|
||||
## Docker
|
||||
|
||||
Запустить [Laravel](https://laravel.com) веб-приложение с FrankenPHP очень просто: достаточно смонтировать проект в директорию `/app` официального Docker-образа.
|
||||
|
||||
Выполните эту команду из корневой директории вашего Laravel-приложения:
|
||||
|
||||
```console
|
||||
docker run -p 80:80 -p 443:443 -p 443:443/udp -v $PWD:/app dunglas/frankenphp
|
||||
```
|
||||
|
||||
И наслаждайтесь!
|
||||
|
||||
## Локальная установка
|
||||
|
||||
Вы также можете запустить ваши Laravel-проекты с FrankenPHP на локальной машине:
|
||||
|
||||
1. [Скачайте бинарный файл для вашей системы](README.md#автономный-бинарный-файл)
|
||||
2. Добавьте следующую конфигурацию в файл с именем `Caddyfile` в корневой директории вашего Laravel-проекта:
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
frankenphp
|
||||
}
|
||||
|
||||
# Доменное имя вашего сервера
|
||||
localhost {
|
||||
# Укажите веб-корень как директорию public/
|
||||
root public/
|
||||
# Включите сжатие (опционально)
|
||||
encode zstd br gzip
|
||||
# Выполняйте PHP-файлы из директории public/ и обслуживайте статические файлы
|
||||
php_server
|
||||
}
|
||||
```
|
||||
|
||||
3. Запустите FrankenPHP из корневой директории вашего Laravel-проекта: `frankenphp run`
|
||||
|
||||
## Laravel Octane
|
||||
|
||||
Octane можно установить с помощью менеджера пакетов Composer:
|
||||
|
||||
```console
|
||||
composer require laravel/octane
|
||||
```
|
||||
|
||||
После установки Octane выполните Artisan-команду `octane:install`, которая создаст конфигурационный файл Octane в вашем приложении:
|
||||
|
||||
```console
|
||||
php artisan octane:install --server=frankenphp
|
||||
```
|
||||
|
||||
Сервер Octane можно запустить с помощью Artisan-команды `octane:frankenphp`:
|
||||
|
||||
```console
|
||||
php artisan octane:frankenphp
|
||||
```
|
||||
|
||||
Команда `octane:frankenphp` поддерживает следующие опции:
|
||||
|
||||
- `--host`: IP-адрес, к которому должен привязаться сервер (по умолчанию: `127.0.0.1`)
|
||||
- `--port`: Порт, на котором сервер будет доступен (по умолчанию: `8000`)
|
||||
- `--admin-port`: Порт, на котором будет доступен административный сервер (по умолчанию: `2019`)
|
||||
- `--workers`: Количество worker-скриптов для обработки запросов (по умолчанию: `auto`)
|
||||
- `--max-requests`: Количество запросов, обрабатываемых перед перезагрузкой сервера (по умолчанию: `500`)
|
||||
- `--caddyfile`: Путь к файлу `Caddyfile` FrankenPHP (по умолчанию: [stubbed `Caddyfile` в Laravel Octane](https://github.com/laravel/octane/blob/2.x/src/Commands/stubs/Caddyfile))
|
||||
- `--https`: Включить HTTPS, HTTP/2 и HTTP/3, а также автоматически генерировать и обновлять сертификаты
|
||||
- `--http-redirect`: Включить редирект с HTTP на HTTPS (включается только при передаче --https)
|
||||
- `--watch`: Автоматически перезагружать сервер при изменении приложения
|
||||
- `--poll`: Использовать опрос файловой системы для отслеживания изменений в файлах через сеть
|
||||
- `--log-level`: Установить уровень логирования, используя встроенный логгер Caddy
|
||||
|
||||
> [!TIP]
|
||||
> Чтобы получить структурированные JSON-логи (полезно при использовании решений для анализа логов), явно укажите опцию `--log-level`.
|
||||
|
||||
Подробнее о [Laravel Octane читайте в официальной документации](https://laravel.com/docs/octane).
|
||||
|
||||
## Laravel-приложения как автономные бинарные файлы
|
||||
|
||||
Используя [возможность встраивания приложений в FrankenPHP](embed.md), можно распространять Laravel-приложения как автономные бинарные файлы.
|
||||
|
||||
Следуйте этим шагам, чтобы упаковать ваше Laravel-приложение в автономный бинарный файл для Linux:
|
||||
|
||||
1. Создайте файл с именем `static-build.Dockerfile` в репозитории вашего приложения:
|
||||
|
||||
```dockerfile
|
||||
FROM --platform=linux/amd64 dunglas/frankenphp:static-builder
|
||||
|
||||
# Скопируйте ваше приложение
|
||||
WORKDIR /go/src/app/dist/app
|
||||
COPY . .
|
||||
|
||||
# Удалите тесты и другие ненужные файлы, чтобы сэкономить место
|
||||
# В качестве альтернативы добавьте эти файлы в .dockerignore
|
||||
RUN rm -Rf tests/
|
||||
|
||||
# Скопируйте файл .env
|
||||
RUN cp .env.example .env
|
||||
# Измените APP_ENV и APP_DEBUG для продакшна
|
||||
RUN sed -i'' -e 's/^APP_ENV=.*/APP_ENV=production/' -e 's/^APP_DEBUG=.*/APP_DEBUG=false/' .env
|
||||
|
||||
# Внесите другие изменения в файл .env, если необходимо
|
||||
|
||||
# Установите зависимости
|
||||
RUN composer install --ignore-platform-reqs --no-dev -a
|
||||
|
||||
# Соберите статический бинарный файл
|
||||
WORKDIR /go/src/app/
|
||||
RUN EMBED=dist/app/ ./build-static.sh
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
>
|
||||
> Некоторые `.dockerignore` файлы могут игнорировать директорию `vendor/` и файлы `.env`. Убедитесь, что вы скорректировали или удалили `.dockerignore` перед сборкой.
|
||||
|
||||
2. Соберите:
|
||||
|
||||
```console
|
||||
docker build -t static-laravel-app -f static-build.Dockerfile .
|
||||
```
|
||||
|
||||
3. Извлеките бинарный файл:
|
||||
|
||||
```console
|
||||
docker cp $(docker create --name static-laravel-app-tmp static-laravel-app):/go/src/app/dist/frankenphp-linux-x86_64 frankenphp ; docker rm static-laravel-app-tmp
|
||||
```
|
||||
|
||||
4. Заполните кеши:
|
||||
|
||||
```console
|
||||
frankenphp php-cli artisan optimize
|
||||
```
|
||||
|
||||
5. Запустите миграции базы данных (если есть):
|
||||
|
||||
```console
|
||||
frankenphp php-cli artisan migrate
|
||||
```
|
||||
|
||||
6. Сгенерируйте секретный ключ приложения:
|
||||
|
||||
```console
|
||||
frankenphp php-cli artisan key:generate
|
||||
```
|
||||
|
||||
7. Запустите сервер:
|
||||
|
||||
```console
|
||||
frankenphp php-server
|
||||
```
|
||||
|
||||
Ваше приложение готово!
|
||||
|
||||
Узнайте больше о доступных опциях и о том, как собирать бинарные файлы для других ОС в [документации по встраиванию приложений](embed.md).
|
||||
|
||||
### Изменение пути хранения
|
||||
|
||||
По умолчанию Laravel сохраняет загруженные файлы, кеши, логи и другие данные в директории `storage/` приложения. Это неудобно для встроенных приложений, так как каждая новая версия будет извлекаться в другую временную директорию.
|
||||
|
||||
Установите переменную окружения `LARAVEL_STORAGE_PATH` (например, в вашем `.env` файле) или вызовите метод `Illuminate\Foundation\Application::useStoragePath()`, чтобы использовать директорию за пределами временной директории.
|
||||
|
||||
### Запуск Octane как автономный бинарный файл
|
||||
|
||||
Можно даже упаковать приложения Laravel Octane как автономный бинарный файл!
|
||||
|
||||
Для этого [установите Octane правильно](#laravel-octane) и следуйте шагам, описанным в [предыдущем разделе](#laravel-приложения-как-автономные-бинарные-файлы).
|
||||
|
||||
Затем, чтобы запустить FrankenPHP в worker-режиме через Octane, выполните:
|
||||
|
||||
```console
|
||||
PATH="$PWD:$PATH" frankenphp php-cli artisan octane:frankenphp
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
> Для работы команды автономный бинарник **обязательно** должен быть назван `frankenphp`, так как Octane требует наличия программы с именем `frankenphp` в PATH.
|
||||
12
docs/ru/mercure.md
Normal file
12
docs/ru/mercure.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# Real-time режим
|
||||
|
||||
FrankenPHP поставляется с встроенным хабом [Mercure](https://mercure.rocks)!
|
||||
Mercure позволяет отправлять события в режиме реального времени на все подключённые устройства: они мгновенно получат JavaScript-событие.
|
||||
|
||||
Не требуются JS-библиотеки или SDK!
|
||||
|
||||

|
||||
|
||||
Чтобы включить хаб Mercure, обновите `Caddyfile` в соответствии с инструкциями [на сайте Mercure](https://mercure.rocks/docs/hub/config).
|
||||
|
||||
Для отправки обновлений Mercure из вашего кода мы рекомендуем использовать [Symfony Mercure Component](https://symfony.com/components/Mercure) (для его использования не требуется полный стек Symfony).
|
||||
15
docs/ru/metrics.md
Normal file
15
docs/ru/metrics.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Метрики
|
||||
|
||||
При включении [метрик Caddy](https://caddyserver.com/docs/metrics) FrankenPHP предоставляет следующие метрики:
|
||||
|
||||
- `frankenphp_[worker]_total_workers`: Общее количество worker-скриптов.
|
||||
- `frankenphp_[worker]_busy_workers`: Количество worker-скриптов, которые в данный момент обрабатывают запрос.
|
||||
- `frankenphp_[worker]_worker_request_time`: Время, затраченное всеми worker-скриптами на обработку запросов.
|
||||
- `frankenphp_[worker]_worker_request_count`: Количество запросов, обработанных всеми worker-скриптами.
|
||||
- `frankenphp_[worker]_ready_workers`: Количество worker-скриптов, которые вызвали `frankenphp_handle_request` хотя бы один раз.
|
||||
- `frankenphp_[worker]_worker_crashes`: Количество случаев неожиданного завершения worker-скриптов.
|
||||
- `frankenphp_[worker]_worker_restarts`: Количество случаев, когда worker-скрипт был перезапущен целенаправленно.
|
||||
- `frankenphp_total_threads`: Общее количество потоков PHP.
|
||||
- `frankenphp_busy_threads`: Количество потоков PHP, которые в данный момент обрабатывают запрос (работающие worker-скрипты всегда используют поток).
|
||||
|
||||
Для метрик worker-скриптов плейсхолдер `[worker]` заменяется на путь к Worker-скрипту, указанному в Caddyfile.
|
||||
101
docs/ru/performance.md
Normal file
101
docs/ru/performance.md
Normal file
@@ -0,0 +1,101 @@
|
||||
# Производительность
|
||||
|
||||
По умолчанию FrankenPHP предлагает хороший баланс между производительностью и удобством использования.
|
||||
Однако, используя подходящую конфигурацию, можно существенно улучшить производительность.
|
||||
|
||||
## Количество потоков и worker-скриптов
|
||||
|
||||
По умолчанию FrankenPHP запускает потоков и worker-скриптов (в worker режиме) вдвое больше, чем количество доступных процессорных ядер.
|
||||
|
||||
Оптимальные значения зависят от структуры вашего приложения, его функциональности и аппаратного обеспечения.
|
||||
Мы настоятельно рекомендуем изменить эти значения.
|
||||
|
||||
Чтобы найти подходящие параметры, лучше всего провести нагрузочные тесты, имитирующие реальный трафик.
|
||||
Хорошими инструментами для этого являются [k6](https://k6.io) и [Gatling](https://gatling.io).
|
||||
|
||||
Чтобы настроить количество потоков, используйте опцию `num_threads` в директивах `php_server` и `php`.
|
||||
Для изменения количества worker-скриптов используйте опцию `num` в секции `worker` директивы `frankenphp`.
|
||||
|
||||
## Worker режим
|
||||
|
||||
Включение [Worker режима](worker.md) значительно улучшает производительность,
|
||||
но ваше приложение должно быть адаптировано для совместимости с этим режимом:
|
||||
необходимо создать worker-скрипт и убедиться, что приложение не имеет утечек памяти.
|
||||
|
||||
## Избегайте использования musl
|
||||
|
||||
Статические бинарники, которые мы предоставляем, а также Alpine Linux-вариант официальных Docker-образов используют [библиотеку musl libc](https://musl.libc.org).
|
||||
|
||||
Известно, что PHP [значительно медленнее работает](https://gitlab.alpinelinux.org/alpine/aports/-/issues/14381) с этой библиотекой по сравнению с традиционной GNU libc, особенно при компиляции в ZTS режиме (потокобезопасный режим), который требуется для FrankenPHP.
|
||||
|
||||
Кроме того, [некоторые ошибки проявляются исключительно при использовании musl](https://github.com/php/php-src/issues?q=sort%3Aupdated-desc+is%3Aissue+is%3Aopen+label%3ABug+musl).
|
||||
|
||||
В производственной среде настоятельно рекомендуется использовать glibc.
|
||||
|
||||
Это можно сделать, используя Debian Docker-образы (по умолчанию) и [компилируя FrankenPHP из исходников](compile.md).
|
||||
|
||||
В качестве альтернативы мы предоставляем статические бинарники, скомпилированные с [аллокатором mimalloc](https://github.com/microsoft/mimalloc), что делает FrankenPHP+musl быстрее (но всё же медленнее, чем FrankenPHP+glibc).
|
||||
|
||||
## Настройка среды выполнения Go
|
||||
|
||||
FrankenPHP написан на языке Go.
|
||||
|
||||
В большинстве случаев среда выполнения Go не требует особой настройки, но в некоторых ситуациях специфическая конфигурация может улучшить производительность.
|
||||
|
||||
Рекомендуется установить переменную окружения `GODEBUG` в значение `cgocheck=0` (по умолчанию в Docker-образах FrankenPHP).
|
||||
|
||||
Если вы запускаете FrankenPHP в контейнерах (Docker, Kubernetes, LXC и т.д.) и ограничиваете доступную память, установите переменную окружения `GOMEMLIMIT` в значение доступного объёма памяти.
|
||||
|
||||
Для более детальной информации ознакомьтесь с [документацией Go по этой теме](https://pkg.go.dev/runtime#hdr-Environment_Variables).
|
||||
|
||||
## `file_server`
|
||||
|
||||
По умолчанию директива `php_server` автоматически настраивает файловый сервер для обслуживания статических файлов (ресурсов), хранящихся в корневой директории.
|
||||
|
||||
Эта функция удобна, но имеет издержки. Чтобы отключить её, используйте следующую конфигурацию:
|
||||
|
||||
```caddyfile
|
||||
php_server {
|
||||
file_server off
|
||||
}
|
||||
```
|
||||
|
||||
## Плейсхолдеры
|
||||
|
||||
Вы можете использовать [плейсхолдеры](https://caddyserver.com/docs/conventions#placeholders) в директивах `root` и `env`.
|
||||
Однако это предотвращает кеширование значений и существенно снижает производительность.
|
||||
|
||||
По возможности избегайте использования плейсхолдеров в этих директивах.
|
||||
|
||||
## `resolve_root_symlink`
|
||||
|
||||
По умолчанию, если корневая директория документа является символьной ссылкой, она автоматически разрешается FrankenPHP (это необходимо для корректной работы PHP).
|
||||
Если корневая директория документа не является символьной ссылкой, вы можете отключить эту функцию.
|
||||
|
||||
```caddyfile
|
||||
php_server {
|
||||
resolve_root_symlink false
|
||||
}
|
||||
```
|
||||
|
||||
Это улучшит производительность, если директива `root` содержит [плейсхолдеры](https://caddyserver.com/docs/conventions#placeholders).
|
||||
В остальных случаях прирост производительности будет минимальным.
|
||||
|
||||
## Логи
|
||||
|
||||
Логирование, безусловно, полезно, но требует операций ввода-вывода и выделения памяти, что значительно снижает производительность.
|
||||
Убедитесь, что вы [правильно настроили уровень логирования](https://caddyserver.com/docs/caddyfile/options#log) и логируете только необходимое.
|
||||
|
||||
## Производительность PHP
|
||||
|
||||
FrankenPHP использует официальный интерпретатор PHP.
|
||||
Все стандартные оптимизации производительности PHP применимы к FrankenPHP.
|
||||
|
||||
В частности:
|
||||
|
||||
- убедитесь, что [OPcache](https://www.php.net/manual/en/book.opcache.php) установлен, включён и настроен должным образом;
|
||||
- включите [оптимизацию автозагрузки Composer](https://getcomposer.org/doc/articles/autoloader-optimization.md);
|
||||
- убедитесь, что кеш `realpath` достаточно велик для нужд вашего приложения;
|
||||
- используйте [предварительную загрузку](https://www.php.net/manual/en/opcache.preloading.php).
|
||||
|
||||
Для более детальной информации ознакомьтесь с [документацией Symfony о производительности](https://symfony.com/doc/current/performance.html) (большинство советов полезны даже если вы не используете Symfony).
|
||||
125
docs/ru/production.md
Normal file
125
docs/ru/production.md
Normal file
@@ -0,0 +1,125 @@
|
||||
# Деплой в продакшен
|
||||
|
||||
В этом руководстве мы рассмотрим, как развернуть PHP-приложение на одном сервере с использованием Docker Compose.
|
||||
|
||||
Если вы используете Symfony, рекомендуется прочитать раздел "[Deploy in production](https://github.com/dunglas/symfony-docker/blob/main/docs/production.md)" документации проекта Symfony Docker (в котором используется FrankenPHP).
|
||||
|
||||
Если вы используете API Platform (который также работает с FrankenPHP), ознакомьтесь с [документацией по деплою этого фреймворка](https://api-platform.com/docs/deployment/).
|
||||
|
||||
## Подготовка приложения
|
||||
|
||||
Сначала создайте файл `Dockerfile` в корневой директории вашего PHP-проекта:
|
||||
|
||||
```dockerfile
|
||||
FROM dunglas/frankenphp
|
||||
|
||||
# Замените "your-domain-name.example.com" на ваш домен
|
||||
ENV SERVER_NAME=your-domain-name.example.com
|
||||
# Если вы хотите отключить HTTPS, используйте вместо этого:
|
||||
#ENV SERVER_NAME=:80
|
||||
|
||||
# Включите настройки PHP для продакшн
|
||||
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
|
||||
|
||||
# Скопируйте файлы PHP вашего проекта в публичную директорию
|
||||
COPY . /app/public
|
||||
# Если вы используете Symfony или Laravel, необходимо скопировать весь проект:
|
||||
#COPY . /app
|
||||
```
|
||||
|
||||
Ознакомьтесь с разделом "[Создание кастомных Docker-образов](docker.md)" для получения дополнительных подробностей и настроек, а также для установки PHP-расширений и модулей Caddy.
|
||||
|
||||
Если ваш проект использует Composer, убедитесь, что он включён в Docker-образ, и установите все зависимости.
|
||||
|
||||
Затем добавьте файл `compose.yaml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
php:
|
||||
image: dunglas/frankenphp
|
||||
restart: always
|
||||
ports:
|
||||
- "80:80" # HTTP
|
||||
- "443:443" # HTTPS
|
||||
- "443:443/udp" # HTTP/3
|
||||
volumes:
|
||||
- caddy_data:/data
|
||||
- caddy_config:/config
|
||||
|
||||
# Томы, необходимые для сертификатов и конфигурации Caddy
|
||||
volumes:
|
||||
caddy_data:
|
||||
caddy_config:
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
>
|
||||
> Примеры выше предназначены для использования в продакшне.
|
||||
> В процессе разработки вы можете использовать том для монтирования, другую конфигурацию PHP и другое значение для переменной окружения `SERVER_NAME`.
|
||||
>
|
||||
> Посмотрите проект [Symfony Docker](https://github.com/dunglas/symfony-docker) (который использует FrankenPHP) для более сложного примера с использованием мультистейдж-образов, Composer, дополнительных PHP-расширений и т.д.
|
||||
|
||||
Наконец, если вы используете Git, закоммитьте эти файлы и отправьте их в репозиторий.
|
||||
|
||||
## Подготовка сервера
|
||||
|
||||
Для деплоя приложения в продакшн требуется сервер. В этом руководстве мы будем использовать виртуальную машину, предоставляемую DigitalOcean, но подойдёт любой Linux-сервер.
|
||||
Если у вас уже есть Linux-сервер с установленным Docker, вы можете сразу перейти к [следующему разделу](#настройка-доменного-имени).
|
||||
|
||||
В противном случае, используйте [эту ссылку](https://m.do.co/c/5d8aabe3ab80), чтобы получить $200 на баланс, создайте аккаунт, затем нажмите "Create a Droplet".
|
||||
Перейдите во вкладку "Marketplace" в разделе "Choose an image" и найдите приложение "Docker". Это создаст сервер на Ubuntu с установленными Docker и Docker Compose.
|
||||
|
||||
Для тестов подойдут самые дешёвые тарифы. Для реального продакшна выберите тариф из раздела "general purpose" в зависимости от ваших потребностей.
|
||||
|
||||

|
||||
|
||||
После этого подключитесь к серверу через SSH:
|
||||
|
||||
```console
|
||||
ssh root@<droplet-ip>
|
||||
```
|
||||
|
||||
## Настройка доменного имени
|
||||
|
||||
В большинстве случаев вам потребуется связать доменное имя с вашим сайтом.
|
||||
Создайте запись DNS типа `A`, указывающую на IP вашего сервера:
|
||||
|
||||
```dns
|
||||
your-domain-name.example.com. IN A 207.154.233.113
|
||||
```
|
||||
|
||||
Пример настройки через DigitalOcean ("Networking" > "Domains"):
|
||||
|
||||

|
||||
|
||||
> [!NOTE]
|
||||
>
|
||||
> Let's Encrypt, сервис, используемый FrankenPHP для автоматической генерации TLS-сертификатов, не поддерживает использование IP-адресов. Для работы необходим домен.
|
||||
|
||||
## Деплой
|
||||
|
||||
Скопируйте ваш проект на сервер с помощью `git clone`, `scp` или любого другого инструмента.
|
||||
Если вы используете GitHub, настройте [ключи развёртывания](https://docs.github.com/en/free-pro-team@latest/developers/overview/managing-deploy-keys#deploy-keys).
|
||||
|
||||
Пример с использованием Git:
|
||||
|
||||
```console
|
||||
git clone git@github.com:<username>/<project-name>.git
|
||||
```
|
||||
|
||||
Перейдите в директорию проекта и запустите приложение в режиме продакшн:
|
||||
|
||||
```console
|
||||
docker compose up -d --wait
|
||||
```
|
||||
|
||||
Сервер готов, а HTTPS-сертификат был автоматически сгенерирован. Перейдите на `https://your-domain-name.example.com` и наслаждайтесь!
|
||||
|
||||
> [!CAUTION]
|
||||
>
|
||||
> Docker может кэшировать слои. Убедитесь, что вы используете актуальную сборку, или используйте опцию `--no-cache` для предотвращения проблем с кэшем.
|
||||
|
||||
## Деплой на несколько узлов
|
||||
|
||||
Если вам нужно развернуть приложение на кластер машин, используйте [Docker Swarm](https://docs.docker.com/engine/swarm/stack-deploy/), который совместим с предоставленными файлами Compose.
|
||||
Для деплоя на Kubernetes ознакомьтесь с [Helm-чартом API Platform](https://api-platform.com/docs/deployment/kubernetes/), который использует FrankenPHP.
|
||||
100
docs/ru/static.md
Normal file
100
docs/ru/static.md
Normal file
@@ -0,0 +1,100 @@
|
||||
# Создание статических бинарных файлов
|
||||
|
||||
Вместо использования локальной установки библиотеки PHP, можно создать статическую сборку FrankenPHP благодаря проекту [static-php-cli](https://github.com/crazywhalecc/static-php-cli) (несмотря на название, проект поддерживает все SAPI, а не только CLI).
|
||||
|
||||
С помощью этого метода создаётся единый переносимый бинарник, который включает PHP-интерпретатор, веб-сервер Caddy и FrankenPHP!
|
||||
|
||||
FrankenPHP также поддерживает [встраивание PHP-приложений в статический бинарный файл](embed.md).
|
||||
|
||||
## Linux
|
||||
|
||||
Мы предоставляем Docker-образ для сборки статического бинарника для Linux:
|
||||
|
||||
```console
|
||||
docker buildx bake --load static-builder
|
||||
docker cp $(docker create --name static-builder-musl dunglas/frankenphp:static-builder-musl):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp ; docker rm static-builder
|
||||
```
|
||||
|
||||
Созданный статический бинарный файл называется `frankenphp` и будет доступен в текущей директории.
|
||||
|
||||
Чтобы собрать статический бинарный файл без Docker, используйте инструкции для macOS — они подходят и для Linux.
|
||||
|
||||
### Дополнительные расширения
|
||||
|
||||
По умолчанию компилируются самые популярные PHP-расширения.
|
||||
|
||||
Чтобы уменьшить размер бинарного файла и сократить возможные векторы атак, можно указать список расширений, которые следует включить в сборку, используя Docker-аргумент `PHP_EXTENSIONS`.
|
||||
|
||||
Например, выполните следующую команду, чтобы собрать только расширение `opcache`:
|
||||
|
||||
```console
|
||||
docker buildx bake --load --set static-builder.args.PHP_EXTENSIONS=opcache,pdo_sqlite static-builder
|
||||
# ...
|
||||
```
|
||||
|
||||
Чтобы добавить библиотеки, расширяющие функциональность включённых расширений, используйте Docker-аргумент `PHP_EXTENSION_LIBS`:
|
||||
|
||||
```console
|
||||
docker buildx bake \
|
||||
--load \
|
||||
--set static-builder.args.PHP_EXTENSIONS=gd \
|
||||
--set static-builder.args.PHP_EXTENSION_LIBS=libjpeg,libwebp \
|
||||
static-builder
|
||||
```
|
||||
|
||||
### Дополнительные модули Caddy
|
||||
|
||||
Чтобы добавить дополнительные модули Caddy или передать аргументы в [xcaddy](https://github.com/caddyserver/xcaddy), используйте Docker-аргумент `XCADDY_ARGS`:
|
||||
|
||||
```console
|
||||
docker buildx bake \
|
||||
--load \
|
||||
--set static-builder.args.XCADDY_ARGS="--with github.com/darkweak/souin/plugins/caddy --with github.com/dunglas/caddy-cbrotli --with github.com/dunglas/mercure/caddy --with github.com/dunglas/vulcain/caddy" \
|
||||
static-builder
|
||||
```
|
||||
|
||||
В этом примере добавляются модуль HTTP-кэширования [Souin](https://souin.io) для Caddy, а также модули [cbrotli](https://github.com/dunglas/caddy-cbrotli), [Mercure](https://mercure.rocks) и [Vulcain](https://vulcain.rocks).
|
||||
|
||||
> [!TIP]
|
||||
>
|
||||
> Модули cbrotli, Mercure и Vulcain включены по умолчанию, если `XCADDY_ARGS` пуст или не установлен.
|
||||
> Если вы изменяете значение `XCADDY_ARGS`, добавьте их явно, если хотите включить их в сборку.
|
||||
|
||||
См. также, как [настроить сборку](#настройка-сборки).
|
||||
|
||||
### Токен GitHub
|
||||
|
||||
Если вы достигли лимита запросов к API GitHub, задайте личный токен доступа GitHub в переменной окружения `GITHUB_TOKEN`:
|
||||
|
||||
```console
|
||||
GITHUB_TOKEN="xxx" docker --load buildx bake static-builder
|
||||
# ...
|
||||
```
|
||||
|
||||
## macOS
|
||||
|
||||
Запустите следующий скрипт, чтобы создать статический бинарный файл для macOS (должен быть установлен [Homebrew](https://brew.sh/)):
|
||||
|
||||
```console
|
||||
git clone https://github.com/dunglas/frankenphp
|
||||
cd frankenphp
|
||||
./build-static.sh
|
||||
```
|
||||
|
||||
Примечание: этот скрипт также работает на Linux (и, вероятно, на других Unix-системах) и используется внутри предоставленного Docker-образа для статической сборки.
|
||||
|
||||
## Настройка сборки
|
||||
|
||||
Следующие переменные окружения можно передать в `docker build` и скрипт `build-static.sh`, чтобы настроить статическую сборку:
|
||||
|
||||
- `FRANKENPHP_VERSION`: версия FrankenPHP
|
||||
- `PHP_VERSION`: версия PHP
|
||||
- `PHP_EXTENSIONS`: PHP-расширения для сборки ([список поддерживаемых расширений](https://static-php.dev/en/guide/extensions.html))
|
||||
- `PHP_EXTENSION_LIBS`: дополнительные библиотеки, добавляющие функциональность расширениям
|
||||
- `XCADDY_ARGS`: аргументы для [xcaddy](https://github.com/caddyserver/xcaddy), например, для добавления модулей Caddy
|
||||
- `EMBED`: путь к PHP-приложению для встраивания в бинарник
|
||||
- `CLEAN`: если задано, libphp и все его зависимости будут пересобраны с нуля (без кэша)
|
||||
- `NO_COMPRESS`: отключает сжатие результирующего бинарника с помощью UPX
|
||||
- `DEBUG_SYMBOLS`: если задано, отладочные символы не будут удалены и будут добавлены в бинарник
|
||||
- `MIMALLOC`: (экспериментально, только для Linux) заменяет musl's mallocng на [mimalloc](https://github.com/microsoft/mimalloc) для повышения производительности
|
||||
- `RELEASE`: (только для мейнтейнеров) если задано, бинарник будет загружен на GitHub
|
||||
159
docs/ru/worker.md
Normal file
159
docs/ru/worker.md
Normal file
@@ -0,0 +1,159 @@
|
||||
# Worker режим в FrankenPHP
|
||||
|
||||
Загрузите приложение один раз и держите его в памяти.
|
||||
FrankenPHP обрабатывает входящие запросы за несколько миллисекунд.
|
||||
|
||||
## Запуск worker-скриптов
|
||||
|
||||
### Docker
|
||||
|
||||
Установите значение переменной окружения `FRANKENPHP_CONFIG` на `worker /path/to/your/worker/script.php`:
|
||||
|
||||
```console
|
||||
docker run \
|
||||
-e FRANKENPHP_CONFIG="worker /app/path/to/your/worker/script.php" \
|
||||
-v $PWD:/app \
|
||||
-p 80:80 -p 443:443 -p 443:443/udp \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
|
||||
### Автономный бинарный файл
|
||||
|
||||
Используйте опцию `--worker` команды `php-server`, чтобы обслуживать содержимое текущей директории через worker-скрипт:
|
||||
|
||||
```console
|
||||
frankenphp php-server --worker /path/to/your/worker/script.php
|
||||
```
|
||||
|
||||
Если ваше PHP-приложение [встроено в бинарник](embed.md), вы можете добавить пользовательский `Caddyfile` в корневую директорию приложения.
|
||||
Он будет использоваться автоматически.
|
||||
|
||||
Также можно настроить [автоматический перезапуск worker-скрипта при изменении файлов](config.md#отслеживание-изменений-файлов) с помощью опции `--watch`.
|
||||
Следующая команда выполнит перезапуск, если будет изменён любой файл с расширением `.php` в директории `/path/to/your/app/` или её поддиректориях:
|
||||
|
||||
```console
|
||||
frankenphp php-server --worker /path/to/your/worker/script.php --watch="/path/to/your/app/**/*.php"
|
||||
```
|
||||
|
||||
## Symfony Runtime
|
||||
|
||||
Worker режим FrankenPHP поддерживается компонентом [Symfony Runtime](https://symfony.com/doc/current/components/runtime.html).
|
||||
Чтобы запустить любое Symfony-приложение в worker режиме, установите пакет FrankenPHP для [PHP Runtime](https://github.com/php-runtime/runtime):
|
||||
|
||||
```console
|
||||
composer require runtime/frankenphp-symfony
|
||||
```
|
||||
|
||||
Запустите сервер приложения, задав переменную окружения `APP_RUNTIME` для использования FrankenPHP Symfony Runtime:
|
||||
|
||||
```console
|
||||
docker run \
|
||||
-e FRANKENPHP_CONFIG="worker ./public/index.php" \
|
||||
-e APP_RUNTIME=Runtime\\FrankenPhpSymfony\\Runtime \
|
||||
-v $PWD:/app \
|
||||
-p 80:80 -p 443:443 -p 443:443/udp \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
|
||||
## Laravel Octane
|
||||
|
||||
Подробнее см. в [документации](laravel.md#laravel-octane).
|
||||
|
||||
## Пользовательские приложения
|
||||
|
||||
Следующий пример показывает, как создать собственный worker-скрипт без использования сторонних библиотек:
|
||||
|
||||
```php
|
||||
<?php
|
||||
// public/index.php
|
||||
|
||||
// Предотвращает завершение worker-скрипта при разрыве соединения клиента
|
||||
ignore_user_abort(true);
|
||||
|
||||
// Инициализация приложения
|
||||
require __DIR__.'/vendor/autoload.php';
|
||||
|
||||
$myApp = new \App\Kernel();
|
||||
$myApp->boot();
|
||||
|
||||
// Обработчик запросов за пределами цикла для повышения производительности
|
||||
$handler = static function () use ($myApp) {
|
||||
// Выполняется при обработке запроса.
|
||||
// Суперглобальные переменные, php://input и другие данные обновляются для каждого запроса.
|
||||
echo $myApp->handle($_GET, $_POST, $_COOKIE, $_FILES, $_SERVER);
|
||||
};
|
||||
|
||||
$maxRequests = (int)($_SERVER['MAX_REQUESTS'] ?? 0);
|
||||
for ($nbRequests = 0; !$maxRequests || $nbRequests < $maxRequests; ++$nbRequests) {
|
||||
$keepRunning = \frankenphp_handle_request($handler);
|
||||
|
||||
// Действия после отправки HTTP-ответа
|
||||
$myApp->terminate();
|
||||
|
||||
// Вызов сборщика мусора, чтобы снизить вероятность его запуска в процессе генерации страницы
|
||||
gc_collect_cycles();
|
||||
|
||||
if (!$keepRunning) break;
|
||||
}
|
||||
|
||||
// Завершение
|
||||
$myApp->shutdown();
|
||||
```
|
||||
|
||||
Запустите приложение, настроив worker-скрипт с помощью переменной окружения `FRANKENPHP_CONFIG`:
|
||||
|
||||
```console
|
||||
docker run \
|
||||
-e FRANKENPHP_CONFIG="worker ./public/index.php" \
|
||||
-v $PWD:/app \
|
||||
-p 80:80 -p 443:443 -p 443:443/udp \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
|
||||
## Настройка количества worker-скриптов
|
||||
|
||||
По умолчанию запускается по 2 worker-скрипта на каждый CPU.
|
||||
Вы можете задать своё значение:
|
||||
|
||||
```console
|
||||
docker run \
|
||||
-e FRANKENPHP_CONFIG="worker ./public/index.php 42" \
|
||||
-v $PWD:/app \
|
||||
-p 80:80 -p 443:443 -p 443:443/udp \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
|
||||
### Перезапуск worker-скрипта после определённого количества запросов
|
||||
|
||||
PHP изначально не предназначался для долгоживущих процессов, поэтому некоторые библиотеки и устаревший код могут приводить к утечкам памяти.
|
||||
Для этого можно настроить автоматический перезапуск worker-скрипта после обработки определённого количества запросов.
|
||||
|
||||
В предыдущем примере максимальное количество запросов задаётся с помощью переменной окружения `MAX_REQUESTS`.
|
||||
|
||||
### Сбои worker-скрипта
|
||||
|
||||
Если worker-скрипт завершится с ненулевым кодом выхода, FrankenPHP перезапустит его с использованием экспоненциальной задержки.
|
||||
Если worker-скрипт проработает дольше, чем время последней задержки \* 2, он будет считаться стабильным, и задержка сбросится.
|
||||
Однако, если worker-скрипт продолжает завершаться с ненулевым кодом выхода в течение короткого промежутка времени (например, из-за опечатки в коде), FrankenPHP завершит работу с ошибкой: `too many consecutive failures`.
|
||||
|
||||
## Поведение суперглобальных переменных
|
||||
|
||||
[PHP суперглобальные переменные](https://www.php.net/manual/en/language.variables.superglobals.php) (`$_SERVER`, `$_ENV`, `$_GET` и т.д.) ведут себя следующим образом:
|
||||
|
||||
- до первого вызова `frankenphp_handle_request()` суперглобальные переменные содержат значения, связанные с самим worker-скриптом
|
||||
- во время и после вызова `frankenphp_handle_request()` суперглобальные переменные содержат значения, сгенерированные на основе обработанного HTTP-запроса, каждый вызов изменяет значения суперглобальных переменных
|
||||
|
||||
Чтобы получить доступ к суперглобальным переменным worker-скрипта внутри колбэка, необходимо скопировать их и импортировать копию в область видимости колбэка:
|
||||
|
||||
```php
|
||||
<?php
|
||||
// Копирование $_SERVER worker-скрипта перед первым вызовом frankenphp_handle_request()
|
||||
$workerServer = $_SERVER;
|
||||
|
||||
$handler = static function () use ($workerServer) {
|
||||
var_dump($_SERVER); // $_SERVER для запроса
|
||||
var_dump($workerServer); // $_SERVER worker-скрипта
|
||||
};
|
||||
|
||||
// ...
|
||||
```
|
||||
117
docs/static.md
117
docs/static.md
@@ -1,46 +1,74 @@
|
||||
# Create a Static Build
|
||||
|
||||
Instead of using a local installation of the PHP library,
|
||||
it's possible to create a static build of FrankenPHP thanks to the great [static-php-cli project](https://github.com/crazywhalecc/static-php-cli) (despite its name, this project support all SAPIs, not only CLI).
|
||||
it's possible to create a static or mostly static build of FrankenPHP thanks to the great [static-php-cli project](https://github.com/crazywhalecc/static-php-cli) (despite its name, this project supports all SAPIs, not only CLI).
|
||||
|
||||
With this method, a single, portable, binary will contain the PHP interpreter, the Caddy web server and FrankenPHP!
|
||||
With this method, a single, portable, binary will contain the PHP interpreter, the Caddy web server, and FrankenPHP!
|
||||
|
||||
Fully static native executables require no dependencies at all and can even be run on [`scratch` Docker image](https://docs.docker.com/build/building/base-images/#create-a-minimal-base-image-using-scratch).
|
||||
However, they can't load dynamic PHP extensions (such as Xdebug) and have some limitations because they are using the musl libc.
|
||||
|
||||
Mostly static binaries only require `glibc` and can load dynamic extensions.
|
||||
|
||||
When possible, we recommend using glibc-based, mostly static builds.
|
||||
|
||||
FrankenPHP also supports [embedding the PHP app in the static binary](embed.md).
|
||||
|
||||
## Linux
|
||||
|
||||
We provide a Docker image to build a Linux static binary:
|
||||
We provide Docker images to build static Linux binaries:
|
||||
|
||||
### musl-Based, Fully Static Build
|
||||
|
||||
For a fully-static binary that runs on any Linux distribution without dependencies but doesn't support dynamic loading of extensions:
|
||||
|
||||
```console
|
||||
docker buildx bake --load static-builder
|
||||
docker cp $(docker create --name static-builder dunglas/frankenphp:static-builder):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp ; docker rm static-builder
|
||||
docker buildx bake --load static-builder-musl
|
||||
docker cp $(docker create --name static-builder-musl dunglas/frankenphp:static-builder-musl):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp ; docker rm static-builder-musl
|
||||
```
|
||||
|
||||
The resulting static binary is named `frankenphp` and is available in the current directory.
|
||||
For better performance in heavily concurrent scenarios, consider using the [mimalloc](https://github.com/microsoft/mimalloc) allocator.
|
||||
|
||||
If you want to build the static binary without Docker, take a look at the macOS instructions, which also works for Linux.
|
||||
```console
|
||||
docker buildx bake --load --set static-builder-musl.args.MIMALLOC=1 static-builder-musl
|
||||
```
|
||||
|
||||
### glibc-Based, Mostly Static Build (With Dynamic Extension Support)
|
||||
|
||||
For a binary that supports loading PHP extensions dynamically while still having the selected extensions compiled statically:
|
||||
|
||||
```console
|
||||
docker buildx bake --load static-builder-gnu
|
||||
docker cp $(docker create --name static-builder-gnu dunglas/frankenphp:static-builder-gnu):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp ; docker rm static-builder-gnu
|
||||
```
|
||||
|
||||
This binary supports all glibc versions 2.17 and superior but does not run on musl-based systems (like Alpine Linux).
|
||||
|
||||
The resulting mostly static (except `glibc`) binary is named `frankenphp` and is available in the current directory.
|
||||
|
||||
If you want to build the static binary without Docker, take a look at the macOS instructions, which also work for Linux.
|
||||
|
||||
### Custom Extensions
|
||||
|
||||
By default, most popular PHP extensions are compiled.
|
||||
By default, the most popular PHP extensions are compiled.
|
||||
|
||||
To reduce the size of the binary and to reduce the attack surface, you can choose the list of extensions to build using the `PHP_EXTENSIONS` Docker ARG.
|
||||
|
||||
For instance, run the following command to only build the `opcache` extension:
|
||||
|
||||
```console
|
||||
docker buildx bake --load --set static-builder.args.PHP_EXTENSIONS=opcache,pdo_sqlite static-builder
|
||||
docker buildx bake --load --set static-builder-musl.args.PHP_EXTENSIONS=opcache,pdo_sqlite static-builder-musl
|
||||
# ...
|
||||
```
|
||||
|
||||
To add libraries enabling additional functionality to the extensions you've enabled, you can pass use the `PHP_EXTENSION_LIBS` Docker ARG:
|
||||
To add libraries enabling additional functionality to the extensions you've enabled, you can pass the `PHP_EXTENSION_LIBS` Docker ARG:
|
||||
|
||||
```console
|
||||
docker buildx bake \
|
||||
--load \
|
||||
--set static-builder.args.PHP_EXTENSIONS=gd \
|
||||
--set static-builder.args.PHP_EXTENSION_LIBS=libjpeg,libwebp \
|
||||
static-builder
|
||||
--set static-builder-musl.args.PHP_EXTENSIONS=gd \
|
||||
--set static-builder-musl.args.PHP_EXTENSION_LIBS=libjpeg,libwebp \
|
||||
static-builder-musl
|
||||
```
|
||||
|
||||
### Extra Caddy Modules
|
||||
@@ -50,15 +78,15 @@ To add extra Caddy modules or pass other arguments to [xcaddy](https://github.co
|
||||
```console
|
||||
docker buildx bake \
|
||||
--load \
|
||||
--set static-builder.args.XCADDY_ARGS="--with github.com/darkweak/souin/plugins/caddy --with github.com/dunglas/caddy-cbrotli --with github.com/dunglas/mercure/caddy --with github.com/dunglas/vulcain/caddy" \
|
||||
static-builder
|
||||
--set static-builder-musl.args.XCADDY_ARGS="--with github.com/darkweak/souin/plugins/caddy --with github.com/dunglas/caddy-cbrotli --with github.com/dunglas/mercure/caddy --with github.com/dunglas/vulcain/caddy" \
|
||||
static-builder-musl
|
||||
```
|
||||
|
||||
In this example, we add the [Souin](https://souin.io) HTTP cache module for Caddy as well as the [cbrotli](https://github.com/dunglas/caddy-cbrotli), [Mercure](https://mercure.rocks) and [Vulcain](https://vulcain.rocks) modules.
|
||||
|
||||
> [!TIP]
|
||||
>
|
||||
> The cbrotli, Mercure and Vulcain modules are included by default if `XCADDY_ARGS` is empty or not set.
|
||||
> The cbrotli, Mercure, and Vulcain modules are included by default if `XCADDY_ARGS` is empty or not set.
|
||||
> If you customize the value of `XCADDY_ARGS`, you must include them explicitly if you want them to be included.
|
||||
|
||||
See also how to [customize the build](#customizing-the-build)
|
||||
@@ -68,7 +96,7 @@ See also how to [customize the build](#customizing-the-build)
|
||||
If you hit the GitHub API rate limit, set a GitHub Personal Access Token in an environment variable named `GITHUB_TOKEN`:
|
||||
|
||||
```console
|
||||
GITHUB_TOKEN="xxx" docker --load buildx bake static-builder
|
||||
GITHUB_TOKEN="xxx" docker --load buildx bake static-builder-musl
|
||||
# ...
|
||||
```
|
||||
|
||||
@@ -82,21 +110,52 @@ cd frankenphp
|
||||
./build-static.sh
|
||||
```
|
||||
|
||||
Note: this script also works on Linux (and probably on other Unixes), and is used internally by the Docker based static builder we provide.
|
||||
Note: this script also works on Linux (and probably on other Unixes), and is used internally by the Docker images we provide.
|
||||
|
||||
## Customizing The Build
|
||||
|
||||
The following environment variables can be passed to `docker build` and to the `build-static.sh`
|
||||
script to customize the static build:
|
||||
|
||||
* `FRANKENPHP_VERSION`: the version of FrankenPHP to use
|
||||
* `PHP_VERSION`: the version of PHP to use
|
||||
* `PHP_EXTENSIONS`: the PHP extensions to build ([list of supported extensions](https://static-php.dev/en/guide/extensions.html))
|
||||
* `PHP_EXTENSION_LIBS`: extra libraries to build that add features to the extensions
|
||||
* `XCADDY_ARGS`: arguments to pass to [xcaddy](https://github.com/caddyserver/xcaddy), for instance to add extra Caddy modules
|
||||
* `EMBED`: path of the PHP application to embed in the binary
|
||||
* `CLEAN`: when set, libphp and all its dependencies are built from scratch (no cache)
|
||||
* `NO_COMPRESS`: don't compress the resulting binary using UPX
|
||||
* `DEBUG_SYMBOLS`: when set, debug-symbols will not be stripped and will be added within the binary
|
||||
* `MIMALLOC`: (experimental, Linux-only) replace musl's mallocng by [mimalloc](https://github.com/microsoft/mimalloc) for improved performance
|
||||
* `RELEASE`: (maintainers only) when set, the resulting binary will be uploaded on GitHub
|
||||
- `FRANKENPHP_VERSION`: the version of FrankenPHP to use
|
||||
- `PHP_VERSION`: the version of PHP to use
|
||||
- `PHP_EXTENSIONS`: the PHP extensions to build ([list of supported extensions](https://static-php.dev/en/guide/extensions.html))
|
||||
- `PHP_EXTENSION_LIBS`: extra libraries to build that add features to the extensions
|
||||
- `XCADDY_ARGS`: arguments to pass to [xcaddy](https://github.com/caddyserver/xcaddy), for instance to add extra Caddy modules
|
||||
- `EMBED`: path of the PHP application to embed in the binary
|
||||
- `CLEAN`: when set, libphp and all its dependencies are built from scratch (no cache)
|
||||
- `NO_COMPRESS`: don't compress the resulting binary using UPX
|
||||
- `DEBUG_SYMBOLS`: when set, debug-symbols will not be stripped and will be added to the binary
|
||||
- `MIMALLOC`: (experimental, Linux-only) replace musl's mallocng by [mimalloc](https://github.com/microsoft/mimalloc) for improved performance. We only recommend using this for musl targeting builds, for glibc prefer disabling this option and using [`LD_PRELOAD`](https://microsoft.github.io/mimalloc/overrides.html) when you run your binary instead.
|
||||
- `RELEASE`: (maintainers only) when set, the resulting binary will be uploaded on GitHub
|
||||
|
||||
## Extensions
|
||||
|
||||
With the glibc or macOS-based binaries, you can load PHP extensions dynamically. However, these extensions will have to be compiled with ZTS support.
|
||||
Since most package managers do not currently offer ZTS versions of their extensions, you will have to compile them yourself.
|
||||
|
||||
For this, you can build and run the `static-builder-gnu` Docker container, remote into it, and compile the extensions with `./configure --with-php-config=/go/src/app/dist/static-php-cli/buildroot/bin/php-config`.
|
||||
|
||||
Example steps for [the Xdebug extension](https://xdebug.org):
|
||||
|
||||
```console
|
||||
docker build -t gnu-ext -f static-builder-gnu.Dockerfile --build-arg FRANKENPHP_VERSION=1.0 .
|
||||
docker create --name static-builder-gnu -it gnu-ext /bin/sh
|
||||
docker start static-builder-gnu
|
||||
docker exec -it static-builder-gnu /bin/sh
|
||||
cd /go/src/app/dist/static-php-cli/buildroot/bin
|
||||
git clone https://github.com/xdebug/xdebug.git && cd xdebug
|
||||
source scl_source enable devtoolset-10
|
||||
../phpize
|
||||
./configure --with-php-config=/go/src/app/dist/static-php-cli/buildroot/bin/php-config
|
||||
make
|
||||
exit
|
||||
docker cp static-builder-gnu:/go/src/app/dist/static-php-cli/buildroot/bin/xdebug/modules/xdebug.so xdebug-zts.so
|
||||
docker cp static-builder-gnu:/go/src/app/dist/frankenphp-linux-$(uname -m) ./frankenphp
|
||||
docker stop static-builder-gnu
|
||||
docker rm static-builder-gnu
|
||||
docker rmi gnu-ext
|
||||
```
|
||||
|
||||
This will have created `frankenphp` and `xdebug-zts.so` in the current directory.
|
||||
If you move the `xdebug-zts.so` into your extension directory, add `zend_extension=xdebug-zts.so` to your php.ini and run FrankenPHP, it will load Xdebug.
|
||||
|
||||
@@ -1,202 +1,206 @@
|
||||
# Katkıda Bulunmak
|
||||
|
||||
## PHP Derleme
|
||||
|
||||
### Docker ile (Linux)
|
||||
|
||||
Geliştirme Ortamı için Docker İmajını Oluşturun:
|
||||
|
||||
```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 -p 443:443/udp -v $PWD:/go/src/app -it frankenphp-dev
|
||||
```
|
||||
|
||||
İmaj genel geliştirme araçlarını (Go, GDB, Valgrind, Neovim...) içerir.
|
||||
|
||||
Docker sürümü 23.0'dan düşükse, derleme dockerignore [pattern issue](https://github.com/moby/moby/pull/42676) tarafından başarısız olur. Dizinleri `.dockerignore` dosyasına ekleyin.
|
||||
|
||||
```patch
|
||||
!testdata/*.php
|
||||
!testdata/*.txt
|
||||
+!caddy
|
||||
+!internal
|
||||
```
|
||||
|
||||
### Docker olmadan (Linux ve macOS)
|
||||
|
||||
[Kaynaklardan derlemek için talimatları izleyin](https://frankenphp.dev/docs/compile/) ve `--debug` yapılandırma seçeneğini geçirin.
|
||||
|
||||
## Test senaryolarını çalıştırma
|
||||
|
||||
```console
|
||||
go test -tags watcher -race -v ./...
|
||||
```
|
||||
|
||||
## Caddy modülü
|
||||
|
||||
FrankenPHP Caddy modülü ile Caddy'yi oluşturun:
|
||||
|
||||
```console
|
||||
cd caddy/frankenphp/
|
||||
go build
|
||||
cd ../../
|
||||
```
|
||||
|
||||
Caddy'yi FrankenPHP Caddy modülü ile çalıştırın:
|
||||
|
||||
```console
|
||||
cd testdata/
|
||||
../caddy/frankenphp/frankenphp run
|
||||
```
|
||||
|
||||
Sunucu `127.0.0.1:8080` adresini dinliyor:
|
||||
|
||||
```console
|
||||
curl -vk https://localhost/phpinfo.php
|
||||
```
|
||||
|
||||
## Minimal test sunucusu
|
||||
|
||||
Minimal test sunucusunu oluşturun:
|
||||
|
||||
```console
|
||||
cd internal/testserver/
|
||||
go build
|
||||
cd ../../
|
||||
```
|
||||
|
||||
Test sunucusunu çalıştırın:
|
||||
|
||||
```console
|
||||
cd testdata/
|
||||
../internal/testserver/testserver
|
||||
```
|
||||
|
||||
Sunucu `127.0.0.1:8080` adresini dinliyor:
|
||||
|
||||
```console
|
||||
curl -v http://127.0.0.1:8080/phpinfo.php
|
||||
```
|
||||
|
||||
## Docker İmajlarını Yerel Olarak Oluşturma
|
||||
|
||||
Bake (pişirme) planını yazdırın:
|
||||
|
||||
```console
|
||||
docker buildx bake -f docker-bake.hcl --print
|
||||
```
|
||||
|
||||
Yerel olarak amd64 için FrankenPHP görüntüleri oluşturun:
|
||||
|
||||
```console
|
||||
docker buildx bake -f docker-bake.hcl --pull --load --set "*.platform=linux/amd64"
|
||||
```
|
||||
|
||||
Yerel olarak arm64 için FrankenPHP görüntüleri oluşturun:
|
||||
|
||||
```console
|
||||
docker buildx bake -f docker-bake.hcl --pull --load --set "*.platform=linux/arm64"
|
||||
```
|
||||
|
||||
FrankenPHP imajlarını arm64 ve amd64 için sıfırdan oluşturun ve Docker Hub'a gönderin:
|
||||
|
||||
```console
|
||||
docker buildx bake -f docker-bake.hcl --pull --no-cache --push
|
||||
```
|
||||
|
||||
## Statik Derlemelerle Segmentasyon Hatalarında Hata Ayıklama
|
||||
|
||||
1. FrankenPHP binary dosyasının hata ayıklama sürümünü GitHub'dan indirin veya hata ayıklama seçeneklerini kullanarak özel statik derlemenizi oluşturun:
|
||||
|
||||
```console
|
||||
docker buildx bake \
|
||||
--load \
|
||||
--set static-builder.args.DEBUG_SYMBOLS=1 \
|
||||
--set "static-builder.platform=linux/amd64" \
|
||||
static-builder
|
||||
docker cp $(docker create --name static-builder dunglas/frankenphp:static-builder):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp
|
||||
```
|
||||
|
||||
2. Mevcut `frankenphp` sürümünüzü hata ayıklama FrankenPHP çalıştırılabilir dosyasıyla değiştirin
|
||||
3. FrankenPHP'yi her zamanki gibi başlatın (alternatif olarak FrankenPHP'yi doğrudan GDB ile başlatabilirsiniz: `gdb --args frankenphp run`)
|
||||
4. GDB ile sürece bağlanın:
|
||||
|
||||
```console
|
||||
gdb -p `pidof frankenphp`
|
||||
```
|
||||
|
||||
5. Gerekirse, GDB kabuğuna `continue` yazın
|
||||
6. FrankenPHP'nin çökmesini sağlayın
|
||||
7. GDB kabuğuna `bt` yazın
|
||||
8. Çıktıyı kopyalayın
|
||||
|
||||
## GitHub Eylemlerinde Segmentasyon Hatalarında Hata Ayıklama
|
||||
|
||||
1. `.github/workflows/tests.yml` dosyasını açın
|
||||
2. PHP hata ayıklama seçeneklerini etkinleştirin
|
||||
|
||||
```patch
|
||||
- uses: shivammathur/setup-php@v2
|
||||
# ...
|
||||
env:
|
||||
phpts: ts
|
||||
+ debug: true
|
||||
```
|
||||
|
||||
3. Konteynere bağlanmak için `tmate`i etkinleştirin
|
||||
|
||||
```patch
|
||||
-
|
||||
name: Set CGO flags
|
||||
run: echo "CGO_CFLAGS=$(php-config --includes)" >> "$GITHUB_ENV"
|
||||
+ -
|
||||
+ run: |
|
||||
+ sudo apt install gdb
|
||||
+ mkdir -p /home/runner/.config/gdb/
|
||||
+ printf "set auto-load safe-path /\nhandle SIG34 nostop noprint pass" > /home/runner/.config/gdb/gdbinit
|
||||
+ -
|
||||
+ uses: mxschmitt/action-tmate@v3
|
||||
```
|
||||
|
||||
4. Konteynere bağlanın
|
||||
5. `frankenphp.go` dosyasını açın
|
||||
6. `cgosymbolizer`'ı etkinleştirin
|
||||
|
||||
```patch
|
||||
- //_ "github.com/ianlancetaylor/cgosymbolizer"
|
||||
+ _ "github.com/ianlancetaylor/cgosymbolizer"
|
||||
```
|
||||
|
||||
7. Modülü indirin: `go get`
|
||||
8. Konteynerde GDB ve benzerlerini kullanabilirsiniz:
|
||||
|
||||
```console
|
||||
go test -tags watcher -c -ldflags=-w
|
||||
gdb --args frankenphp.test -test.run ^MyTest$
|
||||
```
|
||||
|
||||
9. Hata düzeltildiğinde, tüm bu değişiklikleri geri alın
|
||||
|
||||
## Misc Dev Resources
|
||||
|
||||
* [uWSGI içine PHP gömme](https://github.com/unbit/uwsgi/blob/master/plugins/php/php_plugin.c)
|
||||
* [NGINX Unit'te PHP gömme](https://github.com/nginx/unit/blob/master/src/nxt_php_sapi.c)
|
||||
* [Go (go-php) içinde PHP gömme](https://github.com/deuill/go-php)
|
||||
* [Go'da PHP gömme (GoEmPHP)](https://github.com/mikespook/goemphp)
|
||||
* [C++'da PHP gömme](https://gist.github.com/paresy/3cbd4c6a469511ac7479aa0e7c42fea7)
|
||||
* [Sara Golemon tarafından PHP'yi Genişletme ve Yerleştirme](https://books.google.fr/books?id=zMbGvK17_tYC&pg=PA254&lpg=PA254#v=onepage&q&f=false)
|
||||
* [TSRMLS_CC de neyin nesi?](http://blog.golemon.com/2006/06/what-heck-is-tsrmlscc-anyway.html)
|
||||
* [Mac'te PHP gömme](https://gist.github.com/jonnywang/61427ffc0e8dde74fff40f479d147db4)
|
||||
* [SDL bağları](https://pkg.go.dev/github.com/veandco/go-sdl2@v0.4.21/sdl#Main)
|
||||
|
||||
## Docker ile İlgili Kaynaklar
|
||||
|
||||
* [Pişirme (bake) dosya tanımı](https://docs.docker.com/build/customize/bake/file-definition/)
|
||||
* [docker buildx build](https://docs.docker.com/engine/reference/commandline/buildx_build/)
|
||||
|
||||
## Faydalı Komut
|
||||
|
||||
```console
|
||||
apk add strace util-linux gdb
|
||||
strace -e 'trace=!futex,epoll_ctl,epoll_pwait,tgkill,rt_sigreturn' -p 1
|
||||
```
|
||||
# Katkıda Bulunmak
|
||||
|
||||
## PHP Derleme
|
||||
|
||||
### Docker ile (Linux)
|
||||
|
||||
Geliştirme Ortamı için Docker İmajını Oluşturun:
|
||||
|
||||
```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 -p 443:443/udp -v $PWD:/go/src/app -it frankenphp-dev
|
||||
```
|
||||
|
||||
İmaj genel geliştirme araçlarını (Go, GDB, Valgrind, Neovim...) içerir ve aşağıdaki php ayar konumlarını kullanır
|
||||
|
||||
- php.ini: `/etc/frankenphp/php.ini` Varsayılan olarak geliştirme ön ayarlarına sahip bir php.ini dosyası sağlanır.
|
||||
- ek yapılandırma dosyaları: `/etc/frankenphp/php.d/*.ini`
|
||||
- php uzantıları: `/usr/lib/frankenphp/modules/`
|
||||
|
||||
Docker sürümünüz 23.0'dan düşükse, derleme dockerignore [pattern issue](https://github.com/moby/moby/pull/42676) nedeniyle başarısız olacaktır. Dizinleri `.dockerignore` dosyasına ekleyin.
|
||||
|
||||
```patch
|
||||
!testdata/*.php
|
||||
!testdata/*.txt
|
||||
+!caddy
|
||||
+!internal
|
||||
```
|
||||
|
||||
### Docker olmadan (Linux ve macOS)
|
||||
|
||||
[Kaynaklardan derlemek için talimatları izleyin](https://frankenphp.dev/docs/compile/) ve `--debug` yapılandırma seçeneğini geçirin.
|
||||
|
||||
## Test senaryolarını çalıştırma
|
||||
|
||||
```console
|
||||
go test -tags watcher -race -v ./...
|
||||
```
|
||||
|
||||
## Caddy modülü
|
||||
|
||||
FrankenPHP Caddy modülü ile Caddy'yi oluşturun:
|
||||
|
||||
```console
|
||||
cd caddy/frankenphp/
|
||||
go build
|
||||
cd ../../
|
||||
```
|
||||
|
||||
Caddy'yi FrankenPHP Caddy modülü ile çalıştırın:
|
||||
|
||||
```console
|
||||
cd testdata/
|
||||
../caddy/frankenphp/frankenphp run
|
||||
```
|
||||
|
||||
Sunucu `127.0.0.1:8080` adresini dinliyor:
|
||||
|
||||
```console
|
||||
curl -vk https://localhost/phpinfo.php
|
||||
```
|
||||
|
||||
## Minimal test sunucusu
|
||||
|
||||
Minimal test sunucusunu oluşturun:
|
||||
|
||||
```console
|
||||
cd internal/testserver/
|
||||
go build
|
||||
cd ../../
|
||||
```
|
||||
|
||||
Test sunucusunu çalıştırın:
|
||||
|
||||
```console
|
||||
cd testdata/
|
||||
../internal/testserver/testserver
|
||||
```
|
||||
|
||||
Sunucu `127.0.0.1:8080` adresini dinliyor:
|
||||
|
||||
```console
|
||||
curl -v http://127.0.0.1:8080/phpinfo.php
|
||||
```
|
||||
|
||||
## Docker İmajlarını Yerel Olarak Oluşturma
|
||||
|
||||
Bake (pişirme) planını yazdırın:
|
||||
|
||||
```console
|
||||
docker buildx bake -f docker-bake.hcl --print
|
||||
```
|
||||
|
||||
Yerel olarak amd64 için FrankenPHP görüntüleri oluşturun:
|
||||
|
||||
```console
|
||||
docker buildx bake -f docker-bake.hcl --pull --load --set "*.platform=linux/amd64"
|
||||
```
|
||||
|
||||
Yerel olarak arm64 için FrankenPHP görüntüleri oluşturun:
|
||||
|
||||
```console
|
||||
docker buildx bake -f docker-bake.hcl --pull --load --set "*.platform=linux/arm64"
|
||||
```
|
||||
|
||||
FrankenPHP imajlarını arm64 ve amd64 için sıfırdan oluşturun ve Docker Hub'a gönderin:
|
||||
|
||||
```console
|
||||
docker buildx bake -f docker-bake.hcl --pull --no-cache --push
|
||||
```
|
||||
|
||||
## Statik Derlemelerle Segmentasyon Hatalarında Hata Ayıklama
|
||||
|
||||
1. FrankenPHP binary dosyasının hata ayıklama sürümünü GitHub'dan indirin veya hata ayıklama seçeneklerini kullanarak özel statik derlemenizi oluşturun:
|
||||
|
||||
```console
|
||||
docker buildx bake \
|
||||
--load \
|
||||
--set static-builder.args.DEBUG_SYMBOLS=1 \
|
||||
--set "static-builder.platform=linux/amd64" \
|
||||
static-builder
|
||||
docker cp $(docker create --name static-builder-musl dunglas/frankenphp:static-builder-musl):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp
|
||||
```
|
||||
|
||||
2. Mevcut `frankenphp` sürümünüzü hata ayıklama FrankenPHP çalıştırılabilir dosyasıyla değiştirin
|
||||
3. FrankenPHP'yi her zamanki gibi başlatın (alternatif olarak FrankenPHP'yi doğrudan GDB ile başlatabilirsiniz: `gdb --args frankenphp run`)
|
||||
4. GDB ile sürece bağlanın:
|
||||
|
||||
```console
|
||||
gdb -p `pidof frankenphp`
|
||||
```
|
||||
|
||||
5. Gerekirse, GDB kabuğuna `continue` yazın
|
||||
6. FrankenPHP'nin çökmesini sağlayın
|
||||
7. GDB kabuğuna `bt` yazın
|
||||
8. Çıktıyı kopyalayın
|
||||
|
||||
## GitHub Eylemlerinde Segmentasyon Hatalarında Hata Ayıklama
|
||||
|
||||
1. `.github/workflows/tests.yml` dosyasını açın
|
||||
2. PHP hata ayıklama seçeneklerini etkinleştirin
|
||||
|
||||
```patch
|
||||
- uses: shivammathur/setup-php@v2
|
||||
# ...
|
||||
env:
|
||||
phpts: ts
|
||||
+ debug: true
|
||||
```
|
||||
|
||||
3. Konteynere bağlanmak için `tmate`i etkinleştirin
|
||||
|
||||
```patch
|
||||
-
|
||||
name: Set CGO flags
|
||||
run: echo "CGO_CFLAGS=$(php-config --includes)" >> "$GITHUB_ENV"
|
||||
+ -
|
||||
+ run: |
|
||||
+ sudo apt install gdb
|
||||
+ mkdir -p /home/runner/.config/gdb/
|
||||
+ printf "set auto-load safe-path /\nhandle SIG34 nostop noprint pass" > /home/runner/.config/gdb/gdbinit
|
||||
+ -
|
||||
+ uses: mxschmitt/action-tmate@v3
|
||||
```
|
||||
|
||||
4. Konteynere bağlanın
|
||||
5. `frankenphp.go` dosyasını açın
|
||||
6. `cgosymbolizer`'ı etkinleştirin
|
||||
|
||||
```patch
|
||||
- //_ "github.com/ianlancetaylor/cgosymbolizer"
|
||||
+ _ "github.com/ianlancetaylor/cgosymbolizer"
|
||||
```
|
||||
|
||||
7. Modülü indirin: `go get`
|
||||
8. Konteynerde GDB ve benzerlerini kullanabilirsiniz:
|
||||
|
||||
```console
|
||||
go test -tags watcher -c -ldflags=-w
|
||||
gdb --args frankenphp.dev.test -test.run ^MyTest$
|
||||
```
|
||||
|
||||
9. Hata düzeltildiğinde, tüm bu değişiklikleri geri alın
|
||||
|
||||
## Misc Dev Resources
|
||||
|
||||
- [uWSGI içine PHP gömme](https://github.com/unbit/uwsgi/blob/master/plugins/php/php_plugin.c)
|
||||
- [NGINX Unit'te PHP gömme](https://github.com/nginx/unit/blob/master/src/nxt_php_sapi.c)
|
||||
- [Go (go-php) içinde PHP gömme](https://github.com/deuill/go-php)
|
||||
- [Go'da PHP gömme (GoEmPHP)](https://github.com/mikespook/goemphp)
|
||||
- [C++'da PHP gömme](https://gist.github.com/paresy/3cbd4c6a469511ac7479aa0e7c42fea7)
|
||||
- [Sara Golemon tarafından PHP'yi Genişletme ve Yerleştirme](https://books.google.fr/books?id=zMbGvK17_tYC&pg=PA254&lpg=PA254#v=onepage&q&f=false)
|
||||
- [TSRMLS_CC de neyin nesi?](http://blog.golemon.com/2006/06/what-heck-is-tsrmlscc-anyway.html)
|
||||
- [Mac'te PHP gömme](https://gist.github.com/jonnywang/61427ffc0e8dde74fff40f479d147db4)
|
||||
- [SDL bağları](https://pkg.go.dev/github.com/veandco/go-sdl2@v0.4.21/sdl#Main)
|
||||
|
||||
## Docker ile İlgili Kaynaklar
|
||||
|
||||
- [Pişirme (bake) dosya tanımı](https://docs.docker.com/build/customize/bake/file-definition/)
|
||||
- [docker buildx build](https://docs.docker.com/engine/reference/commandline/buildx_build/)
|
||||
|
||||
## Faydalı Komut
|
||||
|
||||
```console
|
||||
apk add strace util-linux gdb
|
||||
strace -e 'trace=!futex,epoll_ctl,epoll_pwait,tgkill,rt_sigreturn' -p 1
|
||||
```
|
||||
|
||||
@@ -1,78 +1,78 @@
|
||||
# FrankenPHP: PHP için Modern Uygulama Sunucusu
|
||||
|
||||
<h1 align="center"><a href="https://frankenphp.dev"><img src="../../frankenphp.png" alt="FrankenPHP" width="600"></a></h1>
|
||||
|
||||
FrankenPHP, [Caddy](https://caddyserver.com/) web sunucusunun üzerine inşa edilmiş PHP için modern bir uygulama sunucusudur.
|
||||
|
||||
FrankenPHP, çarpıcı özellikleri sayesinde PHP uygulamalarınıza süper güçler kazandırır: [Early Hints*](https://frankenphp.dev/docs/early-hints/), [worker modu](https://frankenphp.dev/docs/worker/), [real-time yetenekleri](https://frankenphp.dev/docs/mercure/), otomatik HTTPS, HTTP/2 ve HTTP/3 desteği...
|
||||
|
||||
FrankenPHP herhangi bir PHP uygulaması ile çalışır ve worker modu ile resmi entegrasyonları sayesinde Laravel ve Symfony projelerinizi her zamankinden daha performanslı hale getirir.
|
||||
|
||||
FrankenPHP, PHP'yi `net/http` kullanarak herhangi bir uygulamaya yerleştirmek için bağımsız bir Go kütüphanesi olarak da kullanılabilir.
|
||||
|
||||
[*Frankenphp.dev*](https://frankenphp.dev) adresinden ve bu slayt üzerinden daha fazlasını öğrenin:
|
||||
|
||||
<a href="https://dunglas.dev/2022/10/frankenphp-the-modern-php-app-server-written-in-go/"><img src="https://dunglas.dev/wp-content/uploads/2022/10/frankenphp.png" alt="Slides" width="600"></a>
|
||||
|
||||
## Başlarken
|
||||
|
||||
### Docker
|
||||
|
||||
```console
|
||||
docker run -v $PWD:/app/public \
|
||||
-p 80:80 -p 443:443 -p 443:443/udp \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
|
||||
`https://localhost` adresine gidin ve keyfini çıkarın!
|
||||
|
||||
> [!TIP]
|
||||
>
|
||||
> `https://127.0.0.1` kullanmaya çalışmayın. `https://localhost` kullanın ve kendinden imzalı sertifikayı kabul edin.
|
||||
> Kullanılacak alan adını değiştirmek için [`SERVER_NAME` ortam değişkenini](https://frankenphp.dev/tr/docs/config#ortam-değişkenleri) kullanın.
|
||||
|
||||
### Binary Çıktısı
|
||||
|
||||
Docker kullanmayı tercih etmiyorsanız, Linux ve macOS için bağımsız FrankenPHP binary dosyası sağlıyoruz
|
||||
[PHP 8.4](https://www.php.net/releases/8.4/en.php) ve en popüler PHP eklentilerini de içermekte: [FrankenPHP](https://github.com/dunglas/frankenphp/releases) indirin
|
||||
|
||||
Geçerli dizinin içeriğini başlatmak için çalıştırın:
|
||||
|
||||
```console
|
||||
./frankenphp php-server
|
||||
```
|
||||
|
||||
Ayrıca aşağıdaki tek komut satırı ile de çalıştırabilirsiniz:
|
||||
|
||||
```console
|
||||
./frankenphp php-cli /path/to/your/script.php
|
||||
```
|
||||
|
||||
## Docs
|
||||
|
||||
* [Worker modu](worker.md)
|
||||
* [Early Hints desteği (103 HTTP durum kodu)](early-hints.md)
|
||||
* [Real-time](mercure.md)
|
||||
* [Konfigürasyon](config.md)
|
||||
* [Docker imajları](docker.md)
|
||||
* [Production'a dağıtım](production.md)
|
||||
* [**Bağımsız** kendiliğinden çalıştırılabilir PHP uygulamaları oluşturma](embed.md)
|
||||
* [Statik binary'leri oluşturma](static.md)
|
||||
* [Kaynak dosyalarından derleme](config.md)
|
||||
* [Laravel entegrasyonu](laravel.md)
|
||||
* [Bilinen sorunlar](known-issues.md)
|
||||
* [Demo uygulama (Symfony) ve kıyaslamalar](https://github.com/dunglas/frankenphp-demo)
|
||||
* [Go kütüphane dokümantasonu](https://pkg.go.dev/github.com/dunglas/frankenphp)
|
||||
* [Katkıda bulunma ve hata ayıklama](CONTRIBUTING.md)
|
||||
|
||||
## Örnekler ve İskeletler
|
||||
|
||||
* [Symfony](https://github.com/dunglas/symfony-docker)
|
||||
* [API Platform](https://api-platform.com/docs/distribution/)
|
||||
* [Laravel](https://frankenphp.dev/docs/laravel/)
|
||||
* [Sulu](https://sulu.io/blog/running-sulu-with-frankenphp)
|
||||
* [WordPress](https://github.com/StephenMiracle/frankenwp)
|
||||
* [Drupal](https://github.com/dunglas/frankenphp-drupal)
|
||||
* [Joomla](https://github.com/alexandreelise/frankenphp-joomla)
|
||||
* [TYPO3](https://github.com/ochorocho/franken-typo3)
|
||||
* [Magento2](https://github.com/ekino/frankenphp-magento2)
|
||||
# FrankenPHP: PHP için Modern Uygulama Sunucusu
|
||||
|
||||
<h1 align="center"><a href="https://frankenphp.dev"><img src="../../frankenphp.png" alt="FrankenPHP" width="600"></a></h1>
|
||||
|
||||
FrankenPHP, [Caddy](https://caddyserver.com/) web sunucusunun üzerine inşa edilmiş PHP için modern bir uygulama sunucusudur.
|
||||
|
||||
FrankenPHP, çarpıcı özellikleri sayesinde PHP uygulamalarınıza süper güçler kazandırır: [Early Hints\*](https://frankenphp.dev/docs/early-hints/), [worker modu](https://frankenphp.dev/docs/worker/), [real-time yetenekleri](https://frankenphp.dev/docs/mercure/), otomatik HTTPS, HTTP/2 ve HTTP/3 desteği...
|
||||
|
||||
FrankenPHP herhangi bir PHP uygulaması ile çalışır ve worker modu ile resmi entegrasyonları sayesinde Laravel ve Symfony projelerinizi her zamankinden daha performanslı hale getirir.
|
||||
|
||||
FrankenPHP, PHP'yi `net/http` kullanarak herhangi bir uygulamaya yerleştirmek için bağımsız bir Go kütüphanesi olarak da kullanılabilir.
|
||||
|
||||
[_Frankenphp.dev_](https://frankenphp.dev) adresinden ve bu slayt üzerinden daha fazlasını öğrenin:
|
||||
|
||||
<a href="https://dunglas.dev/2022/10/frankenphp-the-modern-php-app-server-written-in-go/"><img src="https://dunglas.dev/wp-content/uploads/2022/10/frankenphp.png" alt="Slides" width="600"></a>
|
||||
|
||||
## Başlarken
|
||||
|
||||
### Docker
|
||||
|
||||
```console
|
||||
docker run -v $PWD:/app/public \
|
||||
-p 80:80 -p 443:443 -p 443:443/udp \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
|
||||
`https://localhost` adresine gidin ve keyfini çıkarın!
|
||||
|
||||
> [!TIP]
|
||||
>
|
||||
> `https://127.0.0.1` kullanmaya çalışmayın. `https://localhost` kullanın ve kendinden imzalı sertifikayı kabul edin.
|
||||
> Kullanılacak alan adını değiştirmek için [`SERVER_NAME` ortam değişkenini](https://frankenphp.dev/tr/docs/config#ortam-değişkenleri) kullanın.
|
||||
|
||||
### Binary Çıktısı
|
||||
|
||||
Docker kullanmayı tercih etmiyorsanız, Linux ve macOS için bağımsız FrankenPHP binary dosyası sağlıyoruz
|
||||
[PHP 8.4](https://www.php.net/releases/8.4/en.php) ve en popüler PHP eklentilerini de içermekte: [FrankenPHP](https://github.com/dunglas/frankenphp/releases) indirin
|
||||
|
||||
Geçerli dizinin içeriğini başlatmak için çalıştırın:
|
||||
|
||||
```console
|
||||
./frankenphp php-server
|
||||
```
|
||||
|
||||
Ayrıca aşağıdaki tek komut satırı ile de çalıştırabilirsiniz:
|
||||
|
||||
```console
|
||||
./frankenphp php-cli /path/to/your/script.php
|
||||
```
|
||||
|
||||
## Docs
|
||||
|
||||
- [Worker modu](worker.md)
|
||||
- [Early Hints desteği (103 HTTP durum kodu)](early-hints.md)
|
||||
- [Real-time](mercure.md)
|
||||
- [Konfigürasyon](config.md)
|
||||
- [Docker imajları](docker.md)
|
||||
- [Production'a dağıtım](production.md)
|
||||
- [**Bağımsız** kendiliğinden çalıştırılabilir PHP uygulamaları oluşturma](embed.md)
|
||||
- [Statik binary'leri oluşturma](static.md)
|
||||
- [Kaynak dosyalarından derleme](config.md)
|
||||
- [Laravel entegrasyonu](laravel.md)
|
||||
- [Bilinen sorunlar](known-issues.md)
|
||||
- [Demo uygulama (Symfony) ve kıyaslamalar](https://github.com/dunglas/frankenphp-demo)
|
||||
- [Go kütüphane dokümantasonu](https://pkg.go.dev/github.com/dunglas/frankenphp)
|
||||
- [Katkıda bulunma ve hata ayıklama](CONTRIBUTING.md)
|
||||
|
||||
## Örnekler ve İskeletler
|
||||
|
||||
- [Symfony](https://github.com/dunglas/symfony-docker)
|
||||
- [API Platform](https://api-platform.com/docs/distribution/)
|
||||
- [Laravel](https://frankenphp.dev/docs/laravel/)
|
||||
- [Sulu](https://sulu.io/blog/running-sulu-with-frankenphp)
|
||||
- [WordPress](https://github.com/StephenMiracle/frankenwp)
|
||||
- [Drupal](https://github.com/dunglas/frankenphp-drupal)
|
||||
- [Joomla](https://github.com/alexandreelise/frankenphp-joomla)
|
||||
- [TYPO3](https://github.com/ochorocho/franken-typo3)
|
||||
- [Magento2](https://github.com/ekino/frankenphp-magento2)
|
||||
|
||||
@@ -1,100 +1,100 @@
|
||||
# Kaynak Kodlardan Derleme
|
||||
|
||||
Bu doküman, PHP'yi dinamik bir kütüphane olarak yükleyecek bir FrankenPHP yapısının nasıl oluşturulacağını açıklamaktadır.
|
||||
Önerilen yöntem bu şekildedir.
|
||||
|
||||
Alternatif olarak, [statik yapılar oluşturma](static.md) da mümkündür.
|
||||
|
||||
## PHP'yi yükleyin
|
||||
|
||||
FrankenPHP, PHP 8.2 ve üstü ile uyumludur.
|
||||
|
||||
İlk olarak, [PHP'nin kaynaklarını edinin](https://www.php.net/downloads.php) ve bunları çıkarın:
|
||||
|
||||
```console
|
||||
tar xf php-*
|
||||
cd php-*/
|
||||
```
|
||||
|
||||
Ardından, PHP'yi platformunuz için yapılandırın.
|
||||
|
||||
Bu şekilde yapılandırma gereklidir, ancak başka opsiyonlar da ekleyebilirsiniz (örn. ekstra uzantılar)
|
||||
İhtiyaç halinde.
|
||||
|
||||
### Linux
|
||||
|
||||
```console
|
||||
./configure \
|
||||
--enable-embed \
|
||||
--enable-zts \
|
||||
--disable-zend-signals \
|
||||
--enable-zend-max-execution-timers
|
||||
```
|
||||
|
||||
### Mac
|
||||
|
||||
Yüklemek için [Homebrew](https://brew.sh/) paket yöneticisini kullanın
|
||||
`libiconv`, `bison`, `re2c` ve `pkg-config`:
|
||||
|
||||
```console
|
||||
brew install libiconv bison re2c pkg-config
|
||||
echo 'export PATH="/opt/homebrew/opt/bison/bin:$PATH"' >> ~/.zshrc
|
||||
```
|
||||
|
||||
Ardından yapılandırma betiğini çalıştırın:
|
||||
|
||||
```console
|
||||
./configure \
|
||||
--enable-embed=static \
|
||||
--enable-zts \
|
||||
--disable-zend-signals \
|
||||
--disable-opcache-jit \
|
||||
--enable-static \
|
||||
--enable-shared=no \
|
||||
--with-iconv=/opt/homebrew/opt/libiconv/
|
||||
```
|
||||
|
||||
## PHP Derleyin
|
||||
|
||||
Son olarak, PHP'yi derleyin ve kurun:
|
||||
|
||||
```console
|
||||
make -j"$(getconf _NPROCESSORS_ONLN)"
|
||||
sudo make install
|
||||
```
|
||||
|
||||
## Go Uygulamasını Derleyin
|
||||
|
||||
Artık Go kütüphanesini kullanabilir ve Caddy yapımızı derleyebilirsiniz:
|
||||
|
||||
```console
|
||||
curl -L https://github.com/dunglas/frankenphp/archive/refs/heads/main.tar.gz | tar xz
|
||||
cd frankenphp-main/caddy/frankenphp
|
||||
CGO_CFLAGS=$(php-config --includes) CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" go build
|
||||
```
|
||||
|
||||
### Xcaddy kullanımı
|
||||
|
||||
Alternatif olarak, FrankenPHP'yi [özel Caddy modülleri](https://caddyserver.com/docs/modules/) ile derlemek için [xcaddy](https://github.com/caddyserver/xcaddy) kullanın:
|
||||
|
||||
```console
|
||||
CGO_ENABLED=1 \
|
||||
XCADDY_GO_BUILD_FLAGS="-ldflags '-w -s'" \
|
||||
xcaddy build \
|
||||
--output frankenphp \
|
||||
--with github.com/dunglas/frankenphp/caddy \
|
||||
--with github.com/dunglas/caddy-cbrotli \
|
||||
--with github.com/dunglas/mercure/caddy \
|
||||
--with github.com/dunglas/vulcain/caddy
|
||||
# Add extra Caddy modules here
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
>
|
||||
> Eğer musl libc (Alpine Linux'ta varsayılan) ve Symfony kullanıyorsanız,
|
||||
> varsayılan yığın boyutunu artırmanız gerekebilir.
|
||||
> Aksi takdirde, şu tarz hatalar alabilirsiniz `PHP Fatal error: Maximum call stack size of 83360 bytes reached during compilation. Try splitting expression`
|
||||
>
|
||||
> Bunu yapmak için, `XCADDY_GO_BUILD_FLAGS` ortam değişkenini bu şekilde değiştirin
|
||||
> `XCADDY_GO_BUILD_FLAGS=$'-ldflags "-w -s -extldflags \'-Wl,-z,stack-size=0x80000\'"'`
|
||||
> (yığın boyutunun değerini uygulamanızın ihtiyaçlarına göre değiştirin).
|
||||
# Kaynak Kodlardan Derleme
|
||||
|
||||
Bu doküman, PHP'yi dinamik bir kütüphane olarak yükleyecek bir FrankenPHP yapısının nasıl oluşturulacağını açıklamaktadır.
|
||||
Önerilen yöntem bu şekildedir.
|
||||
|
||||
Alternatif olarak, [statik yapılar oluşturma](static.md) da mümkündür.
|
||||
|
||||
## PHP'yi yükleyin
|
||||
|
||||
FrankenPHP, PHP 8.2 ve üstü ile uyumludur.
|
||||
|
||||
İlk olarak, [PHP'nin kaynaklarını edinin](https://www.php.net/downloads.php) ve bunları çıkarın:
|
||||
|
||||
```console
|
||||
tar xf php-*
|
||||
cd php-*/
|
||||
```
|
||||
|
||||
Ardından, PHP'yi platformunuz için yapılandırın.
|
||||
|
||||
Bu şekilde yapılandırma gereklidir, ancak başka opsiyonlar da ekleyebilirsiniz (örn. ekstra uzantılar)
|
||||
İhtiyaç halinde.
|
||||
|
||||
### Linux
|
||||
|
||||
```console
|
||||
./configure \
|
||||
--enable-embed \
|
||||
--enable-zts \
|
||||
--disable-zend-signals \
|
||||
--enable-zend-max-execution-timers
|
||||
```
|
||||
|
||||
### Mac
|
||||
|
||||
Yüklemek için [Homebrew](https://brew.sh/) paket yöneticisini kullanın
|
||||
`libiconv`, `bison`, `re2c` ve `pkg-config`:
|
||||
|
||||
```console
|
||||
brew install libiconv bison re2c pkg-config
|
||||
echo 'export PATH="/opt/homebrew/opt/bison/bin:$PATH"' >> ~/.zshrc
|
||||
```
|
||||
|
||||
Ardından yapılandırma betiğini çalıştırın:
|
||||
|
||||
```console
|
||||
./configure \
|
||||
--enable-embed=static \
|
||||
--enable-zts \
|
||||
--disable-zend-signals \
|
||||
--disable-opcache-jit \
|
||||
--enable-static \
|
||||
--enable-shared=no \
|
||||
--with-iconv=/opt/homebrew/opt/libiconv/
|
||||
```
|
||||
|
||||
## PHP Derleyin
|
||||
|
||||
Son olarak, PHP'yi derleyin ve kurun:
|
||||
|
||||
```console
|
||||
make -j"$(getconf _NPROCESSORS_ONLN)"
|
||||
sudo make install
|
||||
```
|
||||
|
||||
## Go Uygulamasını Derleyin
|
||||
|
||||
Artık Go kütüphanesini kullanabilir ve Caddy yapımızı derleyebilirsiniz:
|
||||
|
||||
```console
|
||||
curl -L https://github.com/dunglas/frankenphp/archive/refs/heads/main.tar.gz | tar xz
|
||||
cd frankenphp-main/caddy/frankenphp
|
||||
CGO_CFLAGS=$(php-config --includes) CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" go build
|
||||
```
|
||||
|
||||
### Xcaddy kullanımı
|
||||
|
||||
Alternatif olarak, FrankenPHP'yi [özel Caddy modülleri](https://caddyserver.com/docs/modules/) ile derlemek için [xcaddy](https://github.com/caddyserver/xcaddy) kullanın:
|
||||
|
||||
```console
|
||||
CGO_ENABLED=1 \
|
||||
XCADDY_GO_BUILD_FLAGS="-ldflags '-w -s'" \
|
||||
xcaddy build \
|
||||
--output frankenphp \
|
||||
--with frankenphp.dev/caddy \
|
||||
--with github.com/dunglas/caddy-cbrotli \
|
||||
--with github.com/dunglas/mercure/caddy \
|
||||
--with github.com/dunglas/vulcain/caddy
|
||||
# Add extra Caddy modules here
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
>
|
||||
> Eğer musl libc (Alpine Linux'ta varsayılan) ve Symfony kullanıyorsanız,
|
||||
> varsayılan yığın boyutunu artırmanız gerekebilir.
|
||||
> Aksi takdirde, şu tarz hatalar alabilirsiniz `PHP Fatal error: Maximum call stack size of 83360 bytes reached during compilation. Try splitting expression`
|
||||
>
|
||||
> Bunu yapmak için, `XCADDY_GO_BUILD_FLAGS` ortam değişkenini bu şekilde değiştirin
|
||||
> `XCADDY_GO_BUILD_FLAGS=$'-ldflags "-w -s -extldflags \'-Wl,-z,stack-size=0x80000\'"'`
|
||||
> (yığın boyutunun değerini uygulamanızın ihtiyaçlarına göre değiştirin).
|
||||
|
||||
@@ -1,163 +1,180 @@
|
||||
# Konfigürasyon
|
||||
|
||||
FrankenPHP, Caddy'nin yanı sıra Mercure ve Vulcain modülleri [Caddy tarafından desteklenen formatlar](https://caddyserver.com/docs/getting-started#your-first-config) kullanılarak yapılandırılabilir.
|
||||
|
||||
Docker imajlarında] (docker.md), `Caddyfile` `/etc/caddy/Caddyfile` adresinde bulunur.
|
||||
Statik ikili, başlatıldığı dizinde `Caddyfile` dosyasını arayacaktır.
|
||||
|
||||
PHP'nin kendisi [bir `php.ini` dosyası kullanılarak yapılandırılabilir](https://www.php.net/manual/tr/configuration.file.php).
|
||||
|
||||
Varsayılan olarak, Docker imajlarıyla birlikte verilen PHP ve statik ikili dosyada bulunan PHP, FrankenPHP'nin başlatıldığı dizinde ve `/usr/local/etc/php/` içinde bir `php.ini` dosyası arayacaktır. Ayrıca `.ini` ile biten tüm dosyaları `/usr/local/etc/php/conf.d/` dizininden yükleyecektir.
|
||||
|
||||
Öntanımlı olarak `php.ini` dosyası yoktur, PHP projesi tarafından sağlanan resmi bir şablonu kopyalamanız gerekir.
|
||||
Docker'da şablonlar imajlar içinde sağlanır:
|
||||
|
||||
```dockerfile
|
||||
FROM dunglas/frankenphp
|
||||
|
||||
# Developement:
|
||||
RUN cp $PHP_INI_DIR/php.ini-development $PHP_INI_DIR/php.ini
|
||||
|
||||
# Veya production:
|
||||
RUN cp $PHP_INI_DIR/php.ini-production $PHP_INI_DIR/php.ini
|
||||
```
|
||||
|
||||
Docker kullanmıyorsanız, [PHP kaynak kodu](https://github.com/php/php-src/) ile birlikte verilen `php.ini-production` veya `php.ini-development` dosyalarından birini kopyalayın.
|
||||
|
||||
## Caddyfile Konfigürasyonu
|
||||
|
||||
FrankenPHP yürütücüsünü kaydetmek için `frankenphp` [global seçenek](https://caddyserver.com/docs/caddyfile/concepts#global-options) ayarlanmalıdır, ardından PHP uygulamanızı sunmak için site blokları içinde `php_server` veya `php` [HTTP yönergeleri](https://caddyserver.com/docs/caddyfile/concepts#directives) kullanılabilir.
|
||||
|
||||
Minimal örnek:
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
# FrankenPHP'yi aktif et
|
||||
frankenphp
|
||||
}
|
||||
|
||||
localhost {
|
||||
# Sıkıştırmayı etkinleştir (isteğe bağlı)
|
||||
encode zstd br gzip
|
||||
# Geçerli dizindeki PHP dosyalarını çalıştırın ve varlıkları sunun
|
||||
php_server
|
||||
}
|
||||
```
|
||||
|
||||
İsteğe bağlı olarak, oluşturulacak iş parçacığı sayısı ve sunucuyla birlikte başlatılacak [işçi betikleri] (worker.md) global seçenek altında belirtilebilir.
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
frankenphp {
|
||||
num_threads <num_threads> # Başlatılacak PHP iş parçacığı sayısını ayarlar. Varsayılan: Mevcut CPU çekirdek sayısının 2 katı.
|
||||
worker {
|
||||
file <path> # Çalışan komut dosyasının yolunu ayarlar.
|
||||
num <num> # Başlatılacak PHP iş parçacığı sayısını ayarlar, varsayılan değer mevcut CPU çekirdek sayısının 2 katıdır.
|
||||
env <key> <value> # Ek bir ortam değişkenini verilen değere ayarlar. Birden fazla ortam değişkeni için birden fazla kez belirtilebilir.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ...
|
||||
```
|
||||
|
||||
Alternatif olarak, `worker` seçeneğinin tek satırlık kısa formunu kullanabilirsiniz:
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
frankenphp {
|
||||
worker <file> <num>
|
||||
}
|
||||
}
|
||||
|
||||
# ...
|
||||
```
|
||||
|
||||
Aynı sunucuda birden fazla uygulamaya hizmet veriyorsanız birden fazla işçi de tanımlayabilirsiniz:
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
frankenphp {
|
||||
worker /path/to/app/public/index.php <num>
|
||||
worker /path/to/other/public/index.php <num>
|
||||
}
|
||||
}
|
||||
|
||||
app.example.com {
|
||||
root * /path/to/app/public
|
||||
php_server
|
||||
}
|
||||
|
||||
other.example.com {
|
||||
root * /path/to/other/public
|
||||
php_server
|
||||
}
|
||||
|
||||
# ...
|
||||
```
|
||||
|
||||
Genellikle ihtiyacınız olan şey `php_server` yönergesini kullanmaktır,
|
||||
ancak tam kontrole ihtiyacınız varsa, daha düşük seviyeli `php` yönergesini kullanabilirsiniz:
|
||||
|
||||
php_server` yönergesini kullanmak bu yapılandırmay ile aynıdır:
|
||||
|
||||
```caddyfile
|
||||
route {
|
||||
# Dizin istekleri için sondaki eğik çizgiyi, diğer adıyla taksim işaretini ekleyin
|
||||
@canonicalPath {
|
||||
file {path}/index.php
|
||||
not path */
|
||||
}
|
||||
redir @canonicalPath {path}/ 308
|
||||
# İstenen dosya mevcut değilse, dizin dosyalarını deneyin
|
||||
@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
|
||||
file_server
|
||||
}
|
||||
```
|
||||
|
||||
php_server` ve `php` yönergeleri aşağıdaki seçeneklere sahiptir:
|
||||
|
||||
```caddyfile
|
||||
php_server [<matcher>] {
|
||||
root <directory> # Sitenin kök klasörünü ayarlar. Öntanımlı: `root` yönergesi.
|
||||
split_path <delim...> # URI'yi iki parçaya bölmek için alt dizgeleri ayarlar. İlk eşleşen alt dizge "yol bilgisini" yoldan ayırmak için kullanılır. İlk parça eşleşen alt dizeyle sonlandırılır ve gerçek kaynak (CGI betiği) adı olarak kabul edilir. İkinci parça betiğin kullanması için PATH_INFO olarak ayarlanacaktır. Varsayılan: `.php`
|
||||
resolve_root_symlink false # Varsa, sembolik bir bağlantıyı değerlendirerek `root` dizininin gerçek değerine çözümlenmesini devre dışı bırakır (varsayılan olarak etkindir).
|
||||
env <key> <value> # Ek bir ortam değişkenini verilen değere ayarlar. Birden fazla ortam değişkeni için birden fazla kez belirtilebilir.
|
||||
}
|
||||
```
|
||||
|
||||
## Ortam Değişkenleri
|
||||
|
||||
Aşağıdaki ortam değişkenleri `Caddyfile` içinde değişiklik yapmadan Caddy yönergelerini entegre etmek için kullanılabilir:
|
||||
|
||||
* `SERVER_NAME`: değiştirin [dinlenecek adresleri](https://caddyserver.com/docs/caddyfile/concepts#addresses), sağlanan ana bilgisayar adları oluşturulan TLS sertifikası için de kullanılacaktır
|
||||
* `CADDY_GLOBAL_OPTIONS`: entegre edin [global seçenekler](https://caddyserver.com/docs/caddyfile/options)
|
||||
* `FRANKENPHP_CONFIG`: `frankenphp` yönergesi altına yapılandırma entegre edin
|
||||
|
||||
FPM ve CLI SAPI'lerinde olduğu gibi, ortam değişkenleri varsayılan olarak `$_SERVER` süper globalinde gösterilir.
|
||||
|
||||
[`variables_order`'a ait PHP yönergesinin](https://www.php.net/manual/en/ini.core.php#ini.variables-order) `S` değeri bu yönergede `E`'nin başka bir yere yerleştirilmesinden bağımsız olarak her zaman `ES` ile eş değerdir.
|
||||
|
||||
## PHP konfigürasyonu
|
||||
|
||||
Ek olarak [PHP yapılandırma dosyalarını](https://www.php.net/manual/en/configuration.file.php#configuration.file.scan) yüklemek için
|
||||
`PHP_INI_SCAN_DIR` ortam değişkeni kullanılabilir.
|
||||
Ayarlandığında, PHP verilen dizinlerde bulunan `.ini` uzantılı tüm dosyaları yükleyecektir.
|
||||
|
||||
## Hata Ayıklama Modunu Etkinleştirin
|
||||
|
||||
Docker imajını kullanırken, hata ayıklama modunu etkinleştirmek için `CADDY_GLOBAL_OPTIONS` ortam değişkenini `debug` olarak ayarlayın:
|
||||
|
||||
```console
|
||||
docker run -v $PWD:/app/public \
|
||||
-e CADDY_GLOBAL_OPTIONS=debug \
|
||||
-p 80:80 -p 443:443 -p 443:443/udp \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
# Konfigürasyon
|
||||
|
||||
FrankenPHP, Caddy'nin yanı sıra Mercure ve Vulcain modülleri [Caddy tarafından desteklenen formatlar](https://caddyserver.com/docs/getting-started#your-first-config) kullanılarak yapılandırılabilir.
|
||||
|
||||
Docker imajlarında] (docker.md), `Caddyfile` `/etc/frankenphp/Caddyfile` adresinde bulunur.
|
||||
Statik ikili, başlatıldığı dizinde `Caddyfile` dosyasını arayacaktır.
|
||||
|
||||
PHP'nin kendisi [bir `php.ini` dosyası kullanılarak yapılandırılabilir](https://www.php.net/manual/tr/configuration.file.php).
|
||||
|
||||
PHP yorumlayıcısı aşağıdaki konumlarda arama yapacaktır:
|
||||
|
||||
Docker:
|
||||
|
||||
- php.ini: `/usr/local/etc/php/php.ini` Varsayılan olarak php.ini sağlanmaz.
|
||||
- ek yapılandırma dosyaları: `/usr/local/etc/php/conf.d/*.ini`
|
||||
- php uzantıları: `/usr/local/lib/php/extensions/no-debug-zts-<YYYYMMDD>/`
|
||||
- PHP projesi tarafından sağlanan resmi bir şablonu kopyalamalısınız:
|
||||
|
||||
```dockerfile
|
||||
FROM dunglas/frankenphp
|
||||
|
||||
# Developement:
|
||||
RUN cp $PHP_INI_DIR/php.ini-development $PHP_INI_DIR/php.ini
|
||||
|
||||
# Veya production:
|
||||
RUN cp $PHP_INI_DIR/php.ini-production $PHP_INI_DIR/php.ini
|
||||
```
|
||||
|
||||
FrankenPHP kurulumu (.rpm veya .deb):
|
||||
|
||||
- php.ini: `/etc/frankenphp/php.ini` Varsayılan olarak üretim ön ayarlarına sahip bir php.ini dosyası sağlanır.
|
||||
- ek yapılandırma dosyaları: `/etc/frankenphp/php.d/*.ini`
|
||||
- php uzantıları: `/usr/lib/frankenphp/modules/`
|
||||
|
||||
Statik ikili:
|
||||
|
||||
- php.ini: `frankenphp run` veya `frankenphp php-server` komutunun çalıştırıldığı dizin, ardından `/etc/frankenphp/php.ini`
|
||||
- ek yapılandırma dosyaları: `/etc/frankenphp/php.d/*.ini`
|
||||
- php uzantıları: yüklenemez
|
||||
- [PHP kaynak kodu](https://github.com/php/php-src/) ile birlikte verilen `php.ini-production` veya `php.ini-development` dosyalarından birini kopyalayın.
|
||||
|
||||
## Caddyfile Konfigürasyonu
|
||||
|
||||
PHP uygulamanızı sunmak için site blokları içinde `php_server` veya `php` [HTTP yönergeleri](https://caddyserver.com/docs/caddyfile/concepts#directives) kullanılabilir.
|
||||
|
||||
Minimal örnek:
|
||||
|
||||
```caddyfile
|
||||
localhost {
|
||||
# Sıkıştırmayı etkinleştir (isteğe bağlı)
|
||||
encode zstd br gzip
|
||||
# Geçerli dizindeki PHP dosyalarını çalıştırın ve varlıkları sunun
|
||||
php_server
|
||||
}
|
||||
```
|
||||
|
||||
FrankenPHP'yi global seçenek kullanarak açıkça yapılandırabilirsiniz:
|
||||
`frankenphp` [global seçenek](https://caddyserver.com/docs/caddyfile/concepts#global-options) FrankenPHP'yi yapılandırmak için kullanılabilir.
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
frankenphp {
|
||||
num_threads <num_threads> # Başlatılacak PHP iş parçacığı sayısını ayarlar. Varsayılan: Mevcut CPU çekirdek sayısının 2 katı.
|
||||
worker {
|
||||
file <path> # Çalışan komut dosyasının yolunu ayarlar.
|
||||
num <num> # Başlatılacak PHP iş parçacığı sayısını ayarlar, varsayılan değer mevcut CPU çekirdek sayısının 2 katıdır.
|
||||
env <key> <value> # Ek bir ortam değişkenini verilen değere ayarlar. Birden fazla ortam değişkeni için birden fazla kez belirtilebilir.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ...
|
||||
```
|
||||
|
||||
Alternatif olarak, `worker` seçeneğinin tek satırlık kısa formunu kullanabilirsiniz:
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
frankenphp {
|
||||
worker <file> <num>
|
||||
}
|
||||
}
|
||||
|
||||
# ...
|
||||
```
|
||||
|
||||
Aynı sunucuda birden fazla uygulamaya hizmet veriyorsanız birden fazla işçi de tanımlayabilirsiniz:
|
||||
|
||||
```caddyfile
|
||||
app.example.com {
|
||||
php_server {
|
||||
root /path/to/app/public
|
||||
worker index.php <num>
|
||||
}
|
||||
}
|
||||
|
||||
other.example.com {
|
||||
php_server {
|
||||
root /path/to/other/public
|
||||
worker index.php <num>
|
||||
}
|
||||
}
|
||||
|
||||
# ...
|
||||
```
|
||||
|
||||
Genellikle ihtiyacınız olan şey `php_server` yönergesini kullanmaktır,
|
||||
ancak tam kontrole ihtiyacınız varsa, daha düşük seviyeli `php` yönergesini kullanabilirsiniz:
|
||||
|
||||
php_server` yönergesini kullanmak bu yapılandırmay ile aynıdır:
|
||||
|
||||
```caddyfile
|
||||
route {
|
||||
# Dizin istekleri için sondaki eğik çizgiyi, diğer adıyla taksim işaretini ekleyin
|
||||
@canonicalPath {
|
||||
file {path}/index.php
|
||||
not path */
|
||||
}
|
||||
redir @canonicalPath {path}/ 308
|
||||
# İstenen dosya mevcut değilse, dizin dosyalarını deneyin
|
||||
@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
|
||||
file_server
|
||||
}
|
||||
```
|
||||
|
||||
php_server`ve`php` yönergeleri aşağıdaki seçeneklere sahiptir:
|
||||
|
||||
```caddyfile
|
||||
php_server [<matcher>] {
|
||||
root <directory> # Sitenin kök klasörünü ayarlar. Öntanımlı: `root` yönergesi.
|
||||
split_path <delim...> # URI'yi iki parçaya bölmek için alt dizgeleri ayarlar. İlk eşleşen alt dizge "yol bilgisini" yoldan ayırmak için kullanılır. İlk parça eşleşen alt dizeyle sonlandırılır ve gerçek kaynak (CGI betiği) adı olarak kabul edilir. İkinci parça betiğin kullanması için PATH_INFO olarak ayarlanacaktır. Varsayılan: `.php`
|
||||
resolve_root_symlink false # Varsa, sembolik bir bağlantıyı değerlendirerek `root` dizininin gerçek değerine çözümlenmesini devre dışı bırakır (varsayılan olarak etkindir).
|
||||
env <key> <value> # Ek bir ortam değişkenini verilen değere ayarlar. Birden fazla ortam değişkeni için birden fazla kez belirtilebilir.
|
||||
file_server off # Yerleşik file_server yönergesini devre dışı bırakır.
|
||||
worker { # Bu sunucuya özgü bir worker oluşturur. Birden fazla worker için birden fazla kez belirtilebilir.
|
||||
file <path> # Worker betiğinin yolunu ayarlar, php_server köküne göre göreceli olabilir
|
||||
num <num> # Başlatılacak PHP iş parçacığı sayısını ayarlar, varsayılan değer mevcut CPU çekirdek sayısının 2 katıdır
|
||||
name <name> # Worker için günlüklerde ve metriklerde kullanılan bir ad ayarlar. Varsayılan: worker dosyasının mutlak yolu. Bir php_server bloğunda tanımlandığında her zaman m# ile başlar.
|
||||
watch <path> # Dosya değişikliklerini izlemek için yolu ayarlar. Birden fazla yol için birden fazla kez belirtilebilir.
|
||||
env <key> <value> # Ek bir ortam değişkenini verilen değere ayarlar. Birden fazla ortam değişkeni için birden fazla kez belirtilebilir. Bu worker için ortam değişkenleri ayrıca php_server üst öğesinden devralınır, ancak burada geçersiz kılınabilir.
|
||||
}
|
||||
worker <other_file> <num> # Global frankenphp bloğundaki gibi kısa formu da kullanabilirsiniz.
|
||||
}
|
||||
```
|
||||
|
||||
## Ortam Değişkenleri
|
||||
|
||||
Aşağıdaki ortam değişkenleri `Caddyfile` içinde değişiklik yapmadan Caddy yönergelerini entegre etmek için kullanılabilir:
|
||||
|
||||
- `SERVER_NAME`: değiştirin [dinlenecek adresleri](https://caddyserver.com/docs/caddyfile/concepts#addresses), sağlanan ana bilgisayar adları oluşturulan TLS sertifikası için de kullanılacaktır
|
||||
- `CADDY_GLOBAL_OPTIONS`: entegre edin [global seçenekler](https://caddyserver.com/docs/caddyfile/options)
|
||||
- `FRANKENPHP_CONFIG`: `frankenphp` yönergesi altına yapılandırma entegre edin
|
||||
|
||||
FPM ve CLI SAPI'lerinde olduğu gibi, ortam değişkenleri varsayılan olarak `$_SERVER` süper globalinde gösterilir.
|
||||
|
||||
[`variables_order`'a ait PHP yönergesinin](https://www.php.net/manual/en/ini.core.php#ini.variables-order) `S` değeri bu yönergede `E`'nin başka bir yere yerleştirilmesinden bağımsız olarak her zaman `ES` ile eş değerdir.
|
||||
|
||||
## PHP konfigürasyonu
|
||||
|
||||
Ek olarak [PHP yapılandırma dosyalarını](https://www.php.net/manual/en/configuration.file.php#configuration.file.scan) yüklemek için
|
||||
`PHP_INI_SCAN_DIR` ortam değişkeni kullanılabilir.
|
||||
Ayarlandığında, PHP verilen dizinlerde bulunan `.ini` uzantılı tüm dosyaları yükleyecektir.
|
||||
|
||||
## Hata Ayıklama Modunu Etkinleştirin
|
||||
|
||||
Docker imajını kullanırken, hata ayıklama modunu etkinleştirmek için `CADDY_GLOBAL_OPTIONS` ortam değişkenini `debug` olarak ayarlayın:
|
||||
|
||||
```console
|
||||
docker run -v $PWD:/app/public \
|
||||
-e CADDY_GLOBAL_OPTIONS=debug \
|
||||
-p 80:80 -p 443:443 -p 443:443/udp \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
|
||||
@@ -1,171 +1,171 @@
|
||||
# Özel Docker İmajı Oluşturma
|
||||
|
||||
[Resmi PHP imajları](https://hub.docker.com/_/php/) temel alınarak [FrankenPHP Docker imajları](https://hub.docker.com/r/dunglas/frankenphp) hazırlanmıştır. Popüler mimariler için Debian ve Alpine Linux varyantları sağlanmıştır. Debian dağıtımı tavsiye edilir.
|
||||
|
||||
PHP 8.2, 8.3 ve 8.4 için varyantlar sağlanmıştır. [Etiketlere göz atın](https://hub.docker.com/r/dunglas/frankenphp/tags).
|
||||
|
||||
## İmajlar Nasıl Kullanılır
|
||||
|
||||
Projenizde bir `Dockerfile` oluşturun:
|
||||
|
||||
```dockerfile
|
||||
FROM dunglas/frankenphp
|
||||
|
||||
COPY . /app/public
|
||||
```
|
||||
|
||||
Ardından, Docker imajını oluşturmak ve çalıştırmak için bu komutları çalıştırın:
|
||||
|
||||
```console
|
||||
docker build -t my-php-app .
|
||||
docker run -it --rm --name my-running-app my-php-app
|
||||
```
|
||||
|
||||
## Daha Fazla PHP Eklentisi Nasıl Kurulur
|
||||
|
||||
[Docker-php-extension-installer`](https://github.com/mlocati/docker-php-extension-installer) betiği temel imajda sağlanmıştır.
|
||||
Ek PHP eklentileri eklemek ise gerçekten kolaydır:
|
||||
|
||||
```dockerfile
|
||||
FROM dunglas/frankenphp
|
||||
|
||||
# buraya istenilen eklentileri ekleyin:
|
||||
RUN install-php-extensions \
|
||||
pdo_mysql \
|
||||
gd \
|
||||
intl \
|
||||
zip \
|
||||
opcache
|
||||
```
|
||||
|
||||
## Daha Fazla Caddy Modülü Nasıl Kurulur
|
||||
|
||||
FrankenPHP, Caddy'nin üzerine inşa edilmiştir ve tüm [Caddy modülleri](https://caddyserver.com/docs/modules/) FrankenPHP ile kullanılabilir.
|
||||
|
||||
Özel Caddy modüllerini kurmanın en kolay yolu [xcaddy](https://github.com/caddyserver/xcaddy) kullanmaktır:
|
||||
|
||||
```dockerfile
|
||||
FROM dunglas/frankenphp:builder AS builder
|
||||
|
||||
# xcaddy'yi derleyen imaja kopyalayın
|
||||
COPY --from=caddy:builder /usr/bin/xcaddy /usr/bin/xcaddy
|
||||
|
||||
# FrankenPHP oluşturmak için CGO etkinleştirilmelidir
|
||||
RUN CGO_ENABLED=1 \
|
||||
XCADDY_SETCAP=1 \
|
||||
XCADDY_GO_BUILD_FLAGS="-ldflags='-w -s' -tags=nobadger,nomysql,nopgx" \
|
||||
CGO_CFLAGS=$(php-config --includes) \
|
||||
CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" \
|
||||
xcaddy build \
|
||||
--output /usr/local/bin/frankenphp \
|
||||
--with github.com/dunglas/frankenphp=./ \
|
||||
--with github.com/dunglas/frankenphp/caddy=./caddy/ \
|
||||
--with github.com/dunglas/caddy-cbrotli \
|
||||
# Mercure ve Vulcain resmi yapıya dahil edilmiştir, ancak bunları kaldırmaktan çekinmeyin
|
||||
--with github.com/dunglas/mercure/caddy \
|
||||
--with github.com/dunglas/vulcain/caddy
|
||||
# Buraya ekstra Caddy modülleri ekleyin
|
||||
|
||||
FROM dunglas/frankenphp AS runner
|
||||
|
||||
# Resmi binary dosyayı özel modüllerinizi içeren binary dosyayla değiştirin
|
||||
COPY --from=builder /usr/local/bin/frankenphp /usr/local/bin/frankenphp
|
||||
```
|
||||
|
||||
FrankenPHP tarafından sağlanan `builder` imajı `libphp`'nin derlenmiş bir sürümünü içerir.
|
||||
[Derleyici imajları](https://hub.docker.com/r/dunglas/frankenphp/tags?name=builder) hem Debian hem de Alpine için FrankenPHP ve PHP'nin tüm sürümleri için sağlanmıştır.
|
||||
|
||||
> [!TIP]
|
||||
>
|
||||
> Eğer Alpine Linux ve Symfony kullanıyorsanız,
|
||||
> [varsayılan yığın boyutunu artırmanız](compile.md#xcaddy-kullanımı) gerekebilir.
|
||||
|
||||
## Varsayılan Olarak Worker Modunun Etkinleştirilmesi
|
||||
|
||||
FrankenPHP'yi bir worker betiği ile başlatmak için `FRANKENPHP_CONFIG` ortam değişkenini ayarlayın:
|
||||
|
||||
```dockerfile
|
||||
FROM dunglas/frankenphp
|
||||
|
||||
# ...
|
||||
|
||||
ENV FRANKENPHP_CONFIG="worker ./public/index.php"
|
||||
```
|
||||
|
||||
## Geliştirme Sürecinde Yığın (Volume) Kullanma
|
||||
|
||||
FrankenPHP ile kolayca geliştirme yapmak için, uygulamanın kaynak kodunu içeren dizini ana bilgisayarınızdan Docker konteynerine bir yığın (volume) olarak bağlayın:
|
||||
|
||||
```console
|
||||
docker run -v $PWD:/app/public -p 80:80 -p 443:443 -p 443:443/udp --tty my-php-app
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
>
|
||||
> `--tty` seçeneği JSON günlükleri yerine insan tarafından okunabilir güzel günlüklere sahip olmayı sağlar.
|
||||
|
||||
Docker Compose ile:
|
||||
|
||||
```yaml
|
||||
# compose.yaml
|
||||
|
||||
services:
|
||||
php:
|
||||
image: dunglas/frankenphp
|
||||
# özel bir Dockerfile kullanmak istiyorsanız aşağıdaki yorum satırını kaldırın
|
||||
#build: .
|
||||
# bunu bir production ortamında çalıştırmak istiyorsanız aşağıdaki yorum satırını kaldırın
|
||||
# restart: always
|
||||
ports:
|
||||
- "80:80" # HTTP
|
||||
- "443:443" # HTTPS
|
||||
- "443:443/udp" # HTTP/3
|
||||
volumes:
|
||||
- ./:/app/public
|
||||
- caddy_data:/data
|
||||
- caddy_config:/config
|
||||
# production ortamda aşağıdaki satırı yorum satırı yapın, geliştirme ortamında insan tarafından okunabilir güzel günlüklere sahip olmanızı sağlar
|
||||
tty: true
|
||||
|
||||
# Caddy sertifikaları ve yapılandırması için gereken yığınlar (volumes)
|
||||
volumes:
|
||||
caddy_data:
|
||||
caddy_config:
|
||||
```
|
||||
|
||||
## Root Olmayan Kullanıcı Olarak Çalıştırma
|
||||
|
||||
FrankenPHP, Docker'da root olmayan kullanıcı olarak çalışabilir.
|
||||
|
||||
İşte bunu yapan örnek bir `Dockerfile`:
|
||||
|
||||
```dockerfile
|
||||
FROM dunglas/frankenphp
|
||||
|
||||
ARG USER=appuser
|
||||
|
||||
RUN \
|
||||
# Alpine tabanlı dağıtımlar için "adduser -D ${USER}" kullanın
|
||||
useradd ${USER}; \
|
||||
# 80 ve 443 numaralı bağlantı noktalarına bağlanmak için ek özellik ekleyin
|
||||
setcap CAP_NET_BIND_SERVICE=+eip /usr/local/bin/frankenphp; \
|
||||
# /data/caddy ve /config/caddy dosyalarına yazma erişimi verin
|
||||
chown -R ${USER}:${USER} /data/caddy && chown -R ${USER}:${USER} /config/caddy;
|
||||
|
||||
USER ${USER}
|
||||
```
|
||||
|
||||
## Güncellemeler
|
||||
|
||||
Docker imajları oluşturulur:
|
||||
|
||||
* Yeni bir sürüm etiketlendiğinde
|
||||
* Her gün UTC ile saat 4'te Resmi PHP imajlarının yeni sürümleri mevcutsa
|
||||
|
||||
## Geliştirme Sürümleri
|
||||
|
||||
Geliştirme sürümleri [`dunglas/frankenphp-dev`](https://hub.docker.com/repository/docker/dunglas/frankenphp-dev) Docker deposunda mevcuttur.
|
||||
GitHub deposunun ana dalına her commit yapıldığında yeni bir derleme tetiklenir.
|
||||
|
||||
`latest*` etiketleri `main` dalının başına işaret eder.
|
||||
`sha-<hash-du-commit-git>` biçimindeki etiketler de kullanılabilir.
|
||||
# Özel Docker İmajı Oluşturma
|
||||
|
||||
[Resmi PHP imajları](https://hub.docker.com/_/php/) temel alınarak [FrankenPHP Docker imajları](https://hub.docker.com/r/dunglas/frankenphp) hazırlanmıştır. Popüler mimariler için Debian ve Alpine Linux varyantları sağlanmıştır. Debian dağıtımı tavsiye edilir.
|
||||
|
||||
PHP 8.2, 8.3 ve 8.4 için varyantlar sağlanmıştır. [Etiketlere göz atın](https://hub.docker.com/r/dunglas/frankenphp/tags).
|
||||
|
||||
## İmajlar Nasıl Kullanılır
|
||||
|
||||
Projenizde bir `Dockerfile` oluşturun:
|
||||
|
||||
```dockerfile
|
||||
FROM dunglas/frankenphp
|
||||
|
||||
COPY . /app/public
|
||||
```
|
||||
|
||||
Ardından, Docker imajını oluşturmak ve çalıştırmak için bu komutları çalıştırın:
|
||||
|
||||
```console
|
||||
docker build -t my-php-app .
|
||||
docker run -it --rm --name my-running-app my-php-app
|
||||
```
|
||||
|
||||
## Daha Fazla PHP Eklentisi Nasıl Kurulur
|
||||
|
||||
[Docker-php-extension-installer`](https://github.com/mlocati/docker-php-extension-installer) betiği temel imajda sağlanmıştır.
|
||||
Ek PHP eklentileri eklemek ise gerçekten kolaydır:
|
||||
|
||||
```dockerfile
|
||||
FROM dunglas/frankenphp
|
||||
|
||||
# buraya istenilen eklentileri ekleyin:
|
||||
RUN install-php-extensions \
|
||||
pdo_mysql \
|
||||
gd \
|
||||
intl \
|
||||
zip \
|
||||
opcache
|
||||
```
|
||||
|
||||
## Daha Fazla Caddy Modülü Nasıl Kurulur
|
||||
|
||||
FrankenPHP, Caddy'nin üzerine inşa edilmiştir ve tüm [Caddy modülleri](https://caddyserver.com/docs/modules/) FrankenPHP ile kullanılabilir.
|
||||
|
||||
Özel Caddy modüllerini kurmanın en kolay yolu [xcaddy](https://github.com/caddyserver/xcaddy) kullanmaktır:
|
||||
|
||||
```dockerfile
|
||||
FROM dunglas/frankenphp:builder AS builder
|
||||
|
||||
# xcaddy'yi derleyen imaja kopyalayın
|
||||
COPY --from=caddy:builder /usr/bin/xcaddy /usr/bin/xcaddy
|
||||
|
||||
# FrankenPHP oluşturmak için CGO etkinleştirilmelidir
|
||||
RUN CGO_ENABLED=1 \
|
||||
XCADDY_SETCAP=1 \
|
||||
XCADDY_GO_BUILD_FLAGS="-ldflags='-w -s' -tags=nobadger,nomysql,nopgx" \
|
||||
CGO_CFLAGS=$(php-config --includes) \
|
||||
CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" \
|
||||
xcaddy build \
|
||||
--output /usr/local/bin/frankenphp \
|
||||
--with frankenphp.dev=./ \
|
||||
--with frankenphp.dev/caddy=./caddy/ \
|
||||
--with github.com/dunglas/caddy-cbrotli \
|
||||
# Mercure ve Vulcain resmi yapıya dahil edilmiştir, ancak bunları kaldırmaktan çekinmeyin
|
||||
--with github.com/dunglas/mercure/caddy \
|
||||
--with github.com/dunglas/vulcain/caddy
|
||||
# Buraya ekstra Caddy modülleri ekleyin
|
||||
|
||||
FROM dunglas/frankenphp AS runner
|
||||
|
||||
# Resmi binary dosyayı özel modüllerinizi içeren binary dosyayla değiştirin
|
||||
COPY --from=builder /usr/local/bin/frankenphp /usr/local/bin/frankenphp
|
||||
```
|
||||
|
||||
FrankenPHP tarafından sağlanan `builder` imajı `libphp`'nin derlenmiş bir sürümünü içerir.
|
||||
[Derleyici imajları](https://hub.docker.com/r/dunglas/frankenphp/tags?name=builder) hem Debian hem de Alpine için FrankenPHP ve PHP'nin tüm sürümleri için sağlanmıştır.
|
||||
|
||||
> [!TIP]
|
||||
>
|
||||
> Eğer Alpine Linux ve Symfony kullanıyorsanız,
|
||||
> [varsayılan yığın boyutunu artırmanız](compile.md#xcaddy-kullanımı) gerekebilir.
|
||||
|
||||
## Varsayılan Olarak Worker Modunun Etkinleştirilmesi
|
||||
|
||||
FrankenPHP'yi bir worker betiği ile başlatmak için `FRANKENPHP_CONFIG` ortam değişkenini ayarlayın:
|
||||
|
||||
```dockerfile
|
||||
FROM dunglas/frankenphp
|
||||
|
||||
# ...
|
||||
|
||||
ENV FRANKENPHP_CONFIG="worker ./public/index.php"
|
||||
```
|
||||
|
||||
## Geliştirme Sürecinde Yığın (Volume) Kullanma
|
||||
|
||||
FrankenPHP ile kolayca geliştirme yapmak için, uygulamanın kaynak kodunu içeren dizini ana bilgisayarınızdan Docker konteynerine bir yığın (volume) olarak bağlayın:
|
||||
|
||||
```console
|
||||
docker run -v $PWD:/app/public -p 80:80 -p 443:443 -p 443:443/udp --tty my-php-app
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
>
|
||||
> `--tty` seçeneği JSON günlükleri yerine insan tarafından okunabilir güzel günlüklere sahip olmayı sağlar.
|
||||
|
||||
Docker Compose ile:
|
||||
|
||||
```yaml
|
||||
# compose.yaml
|
||||
|
||||
services:
|
||||
php:
|
||||
image: dunglas/frankenphp
|
||||
# özel bir Dockerfile kullanmak istiyorsanız aşağıdaki yorum satırını kaldırın
|
||||
#build: .
|
||||
# bunu bir production ortamında çalıştırmak istiyorsanız aşağıdaki yorum satırını kaldırın
|
||||
# restart: always
|
||||
ports:
|
||||
- "80:80" # HTTP
|
||||
- "443:443" # HTTPS
|
||||
- "443:443/udp" # HTTP/3
|
||||
volumes:
|
||||
- ./:/app/public
|
||||
- caddy_data:/data
|
||||
- caddy_config:/config
|
||||
# production ortamda aşağıdaki satırı yorum satırı yapın, geliştirme ortamında insan tarafından okunabilir güzel günlüklere sahip olmanızı sağlar
|
||||
tty: true
|
||||
|
||||
# Caddy sertifikaları ve yapılandırması için gereken yığınlar (volumes)
|
||||
volumes:
|
||||
caddy_data:
|
||||
caddy_config:
|
||||
```
|
||||
|
||||
## Root Olmayan Kullanıcı Olarak Çalıştırma
|
||||
|
||||
FrankenPHP, Docker'da root olmayan kullanıcı olarak çalışabilir.
|
||||
|
||||
İşte bunu yapan örnek bir `Dockerfile`:
|
||||
|
||||
```dockerfile
|
||||
FROM dunglas/frankenphp
|
||||
|
||||
ARG USER=appuser
|
||||
|
||||
RUN \
|
||||
# Alpine tabanlı dağıtımlar için "adduser -D ${USER}" kullanın
|
||||
useradd ${USER}; \
|
||||
# 80 ve 443 numaralı bağlantı noktalarına bağlanmak için ek özellik ekleyin
|
||||
setcap CAP_NET_BIND_SERVICE=+eip /usr/local/bin/frankenphp; \
|
||||
# /data/caddy ve /config/caddy dosyalarına yazma erişimi verin
|
||||
chown -R ${USER}:${USER} /data/caddy && chown -R ${USER}:${USER} /config/caddy;
|
||||
|
||||
USER ${USER}
|
||||
```
|
||||
|
||||
## Güncellemeler
|
||||
|
||||
Docker imajları oluşturulur:
|
||||
|
||||
- Yeni bir sürüm etiketlendiğinde
|
||||
- Her gün UTC ile saat 4'te Resmi PHP imajlarının yeni sürümleri mevcutsa
|
||||
|
||||
## Geliştirme Sürümleri
|
||||
|
||||
Geliştirme sürümleri [`dunglas/frankenphp-dev`](https://hub.docker.com/repository/docker/dunglas/frankenphp-dev) Docker deposunda mevcuttur.
|
||||
GitHub deposunun ana dalına her commit yapıldığında yeni bir derleme tetiklenir.
|
||||
|
||||
`latest*` etiketleri `main` dalının başına işaret eder.
|
||||
`sha-<hash-du-commit-git>` biçimindeki etiketler de kullanılabilir.
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
# Early Hints
|
||||
|
||||
FrankenPHP [103 Early Hints durum kodunu](https://developer.chrome.com/blog/early-hints/) yerel olarak destekler.
|
||||
Early Hints kullanmak web sayfalarınızın yüklenme süresini %30 oranında artırabilir.
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
header('Link: </style.css>; rel=preload; as=style');
|
||||
headers_send(103);
|
||||
|
||||
// yavaş algoritmalarınız ve SQL sorgularınız 🤪
|
||||
|
||||
echo <<<'HTML'
|
||||
<!DOCTYPE html>
|
||||
<title>Hello FrankenPHP</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
HTML;
|
||||
```
|
||||
|
||||
Early Hints hem normal hem de [worker](worker.md) modları tarafından desteklenir.
|
||||
# Early Hints
|
||||
|
||||
FrankenPHP [103 Early Hints durum kodunu](https://developer.chrome.com/blog/early-hints/) yerel olarak destekler.
|
||||
Early Hints kullanmak web sayfalarınızın yüklenme süresini %30 oranında artırabilir.
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
header('Link: </style.css>; rel=preload; as=style');
|
||||
headers_send(103);
|
||||
|
||||
// yavaş algoritmalarınız ve SQL sorgularınız 🤪
|
||||
|
||||
echo <<<'HTML'
|
||||
<!DOCTYPE html>
|
||||
<title>Hello FrankenPHP</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
HTML;
|
||||
```
|
||||
|
||||
Early Hints hem normal hem de [worker](worker.md) modları tarafından desteklenir.
|
||||
|
||||
264
docs/tr/embed.md
264
docs/tr/embed.md
@@ -1,132 +1,132 @@
|
||||
# Binary Dosyası Olarak PHP Uygulamaları
|
||||
|
||||
FrankenPHP, PHP uygulamalarının kaynak kodunu ve varlıklarını statik, kendi kendine yeten bir binary dosyaya yerleştirme yeteneğine sahiptir.
|
||||
|
||||
Bu özellik sayesinde PHP uygulamaları, uygulamanın kendisini, PHP yorumlayıcısını ve üretim düzeyinde bir web sunucusu olan Caddy'yi içeren bağımsız bir binary dosyalar olarak çıktısı alınabilir ve dağıtılabilir.
|
||||
|
||||
Bu özellik hakkında daha fazla bilgi almak için [Kévin tarafından SymfonyCon 2023'te yapılan sunuma](https://dunglas.dev/2023/12/php-and-symfony-apps-as-standalone-binaries/) göz atabilirsiniz.
|
||||
|
||||
## Preparing Your App
|
||||
|
||||
Bağımsız binary dosyayı oluşturmadan önce uygulamanızın gömülmeye hazır olduğundan emin olun.
|
||||
|
||||
Örneğin muhtemelen şunları yapmak istersiniz:
|
||||
|
||||
* Uygulamanın üretim bağımlılıklarını yükleyin
|
||||
* Otomatik yükleyiciyi boşaltın
|
||||
* Uygulamanızın üretim modunu etkinleştirin (varsa)
|
||||
* Nihai binary dosyanızın boyutunu küçültmek için `.git` veya testler gibi gerekli olmayan dosyaları çıkarın
|
||||
|
||||
Örneğin, bir Symfony uygulaması için aşağıdaki komutları kullanabilirsiniz:
|
||||
|
||||
```console
|
||||
# .git/, vb. dosyalarından kurtulmak için projeyi dışa aktarın
|
||||
mkdir $TMPDIR/my-prepared-app
|
||||
git archive HEAD | tar -x -C $TMPDIR/my-prepared-app
|
||||
cd $TMPDIR/my-prepared-app
|
||||
|
||||
# Uygun ortam değişkenlerini ayarlayın
|
||||
echo APP_ENV=prod > .env.local
|
||||
echo APP_DEBUG=0 >> .env.local
|
||||
|
||||
# Testleri kaldırın
|
||||
rm -Rf tests/
|
||||
|
||||
# Bağımlılıkları yükleyin
|
||||
composer install --ignore-platform-reqs --no-dev -a
|
||||
|
||||
# .env'yi optimize edin
|
||||
composer dump-env prod
|
||||
```
|
||||
|
||||
## Linux Binary'si Oluşturma
|
||||
|
||||
Bir Linux binary çıktısı almanın en kolay yolu, sağladığımız Docker tabanlı derleyiciyi kullanmaktır.
|
||||
|
||||
1. Hazırladığınız uygulamanın deposunda `static-build.Dockerfile` adlı bir dosya oluşturun:
|
||||
|
||||
```dockerfile
|
||||
FROM --platform=linux/amd64 dunglas/frankenphp:static-builder
|
||||
|
||||
# Uygulamanızı kopyalayın
|
||||
WORKDIR /go/src/app/dist/app
|
||||
COPY . .
|
||||
|
||||
# Statik binary dosyasını oluşturun, yalnızca istediğiniz PHP eklentilerini seçtiğinizden emin olun
|
||||
WORKDIR /go/src/app/
|
||||
RUN EMBED=dist/app/ \
|
||||
PHP_EXTENSIONS=ctype,iconv,pdo_sqlite \
|
||||
./build-static.sh
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
>
|
||||
> Bazı `.dockerignore` dosyaları (örneğin varsayılan [Symfony Docker `.dockerignore`](https://github.com/dunglas/symfony-docker/blob/main/.dockerignore))
|
||||
> `vendor/` dizinini ve `.env` dosyalarını yok sayacaktır. Derlemeden önce `.dockerignore` dosyasını ayarladığınızdan veya kaldırdığınızdan emin olun.
|
||||
|
||||
2. Derleyin:
|
||||
|
||||
```console
|
||||
docker build -t static-app -f static-build.Dockerfile .
|
||||
```
|
||||
|
||||
3. Binary dosyasını çıkarın:
|
||||
|
||||
```console
|
||||
docker cp $(docker create --name static-app-tmp static-app):/go/src/app/dist/frankenphp-linux-x86_64 my-app ; docker rm static-app-tmp
|
||||
```
|
||||
|
||||
Elde edilen binary dosyası, geçerli dizindeki `my-app` adlı dosyadır.
|
||||
|
||||
## Diğer İşletim Sistemleri için Binary Çıktısı Alma
|
||||
|
||||
Docker kullanmak istemiyorsanız veya bir macOS binary dosyası oluşturmak istiyorsanız, sağladığımız kabuk betiğini kullanın:
|
||||
|
||||
```console
|
||||
git clone https://github.com/dunglas/frankenphp
|
||||
cd frankenphp
|
||||
EMBED=/path/to/your/app \
|
||||
PHP_EXTENSIONS=ctype,iconv,pdo_sqlite \
|
||||
./build-static.sh
|
||||
```
|
||||
|
||||
Elde edilen binary dosyası `dist/` dizinindeki `frankenphp-<os>-<arch>` adlı dosyadır.
|
||||
|
||||
## Binary Dosyasını Kullanma
|
||||
|
||||
İşte bu kadar! `my-app` dosyası (veya diğer işletim sistemlerinde `dist/frankenphp-<os>-<arch>`) bağımsız uygulamanızı içerir!
|
||||
|
||||
Web uygulamasını başlatmak için çalıştırın:
|
||||
|
||||
```console
|
||||
./my-app php-server
|
||||
```
|
||||
|
||||
Uygulamanız bir [worker betiği](worker.md) içeriyorsa, worker'ı aşağıdaki gibi bir şeyle başlatın:
|
||||
|
||||
```console
|
||||
./my-app php-server --worker public/index.php
|
||||
```
|
||||
|
||||
HTTPS (Let's Encrypt sertifikası otomatik olarak oluşturulur), HTTP/2 ve HTTP/3'ü etkinleştirmek için kullanılacak alan adını belirtin:
|
||||
|
||||
```console
|
||||
./my-app php-server --domain localhost
|
||||
```
|
||||
|
||||
Ayrıca binary dosyanıza gömülü PHP CLI betiklerini de çalıştırabilirsiniz:
|
||||
|
||||
```console
|
||||
./my-app php-cli bin/console
|
||||
```
|
||||
|
||||
## Yapıyı Özelleştirme
|
||||
|
||||
Binary dosyasının nasıl özelleştirileceğini (uzantılar, PHP sürümü...) görmek için [Statik derleme dokümanını okuyun](static.md).
|
||||
|
||||
## Binary Dosyasının Dağıtılması
|
||||
|
||||
Linux'ta, oluşturulan ikili dosya [UPX](https://upx.github.io) kullanılarak sıkıştırılır.
|
||||
|
||||
Mac'te, göndermeden önce dosyanın boyutunu küçültmek için sıkıştırabilirsiniz.
|
||||
Biz `xz` öneririz.
|
||||
# Binary Dosyası Olarak PHP Uygulamaları
|
||||
|
||||
FrankenPHP, PHP uygulamalarının kaynak kodunu ve varlıklarını statik, kendi kendine yeten bir binary dosyaya yerleştirme yeteneğine sahiptir.
|
||||
|
||||
Bu özellik sayesinde PHP uygulamaları, uygulamanın kendisini, PHP yorumlayıcısını ve üretim düzeyinde bir web sunucusu olan Caddy'yi içeren bağımsız bir binary dosyalar olarak çıktısı alınabilir ve dağıtılabilir.
|
||||
|
||||
Bu özellik hakkında daha fazla bilgi almak için [Kévin tarafından SymfonyCon 2023'te yapılan sunuma](https://dunglas.dev/2023/12/php-and-symfony-apps-as-standalone-binaries/) göz atabilirsiniz.
|
||||
|
||||
## Preparing Your App
|
||||
|
||||
Bağımsız binary dosyayı oluşturmadan önce uygulamanızın gömülmeye hazır olduğundan emin olun.
|
||||
|
||||
Örneğin muhtemelen şunları yapmak istersiniz:
|
||||
|
||||
- Uygulamanın üretim bağımlılıklarını yükleyin
|
||||
- Otomatik yükleyiciyi boşaltın
|
||||
- Uygulamanızın üretim modunu etkinleştirin (varsa)
|
||||
- Nihai binary dosyanızın boyutunu küçültmek için `.git` veya testler gibi gerekli olmayan dosyaları çıkarın
|
||||
|
||||
Örneğin, bir Symfony uygulaması için aşağıdaki komutları kullanabilirsiniz:
|
||||
|
||||
```console
|
||||
# .git/, vb. dosyalarından kurtulmak için projeyi dışa aktarın
|
||||
mkdir $TMPDIR/my-prepared-app
|
||||
git archive HEAD | tar -x -C $TMPDIR/my-prepared-app
|
||||
cd $TMPDIR/my-prepared-app
|
||||
|
||||
# Uygun ortam değişkenlerini ayarlayın
|
||||
echo APP_ENV=prod > .env.local
|
||||
echo APP_DEBUG=0 >> .env.local
|
||||
|
||||
# Testleri kaldırın
|
||||
rm -Rf tests/
|
||||
|
||||
# Bağımlılıkları yükleyin
|
||||
composer install --ignore-platform-reqs --no-dev -a
|
||||
|
||||
# .env'yi optimize edin
|
||||
composer dump-env prod
|
||||
```
|
||||
|
||||
## Linux Binary'si Oluşturma
|
||||
|
||||
Bir Linux binary çıktısı almanın en kolay yolu, sağladığımız Docker tabanlı derleyiciyi kullanmaktır.
|
||||
|
||||
1. Hazırladığınız uygulamanın deposunda `static-build.Dockerfile` adlı bir dosya oluşturun:
|
||||
|
||||
```dockerfile
|
||||
FROM --platform=linux/amd64 dunglas/frankenphp:static-builder
|
||||
|
||||
# Uygulamanızı kopyalayın
|
||||
WORKDIR /go/src/app/dist/app
|
||||
COPY . .
|
||||
|
||||
# Statik binary dosyasını oluşturun, yalnızca istediğiniz PHP eklentilerini seçtiğinizden emin olun
|
||||
WORKDIR /go/src/app/
|
||||
RUN EMBED=dist/app/ \
|
||||
PHP_EXTENSIONS=ctype,iconv,pdo_sqlite \
|
||||
./build-static.sh
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
>
|
||||
> Bazı `.dockerignore` dosyaları (örneğin varsayılan [Symfony Docker `.dockerignore`](https://github.com/dunglas/symfony-docker/blob/main/.dockerignore))
|
||||
> `vendor/` dizinini ve `.env` dosyalarını yok sayacaktır. Derlemeden önce `.dockerignore` dosyasını ayarladığınızdan veya kaldırdığınızdan emin olun.
|
||||
|
||||
2. Derleyin:
|
||||
|
||||
```console
|
||||
docker build -t static-app -f static-build.Dockerfile .
|
||||
```
|
||||
|
||||
3. Binary dosyasını çıkarın:
|
||||
|
||||
```console
|
||||
docker cp $(docker create --name static-app-tmp static-app):/go/src/app/dist/frankenphp-linux-x86_64 my-app ; docker rm static-app-tmp
|
||||
```
|
||||
|
||||
Elde edilen binary dosyası, geçerli dizindeki `my-app` adlı dosyadır.
|
||||
|
||||
## Diğer İşletim Sistemleri için Binary Çıktısı Alma
|
||||
|
||||
Docker kullanmak istemiyorsanız veya bir macOS binary dosyası oluşturmak istiyorsanız, sağladığımız kabuk betiğini kullanın:
|
||||
|
||||
```console
|
||||
git clone https://github.com/dunglas/frankenphp
|
||||
cd frankenphp
|
||||
EMBED=/path/to/your/app \
|
||||
PHP_EXTENSIONS=ctype,iconv,pdo_sqlite \
|
||||
./build-static.sh
|
||||
```
|
||||
|
||||
Elde edilen binary dosyası `dist/` dizinindeki `frankenphp-<os>-<arch>` adlı dosyadır.
|
||||
|
||||
## Binary Dosyasını Kullanma
|
||||
|
||||
İşte bu kadar! `my-app` dosyası (veya diğer işletim sistemlerinde `dist/frankenphp-<os>-<arch>`) bağımsız uygulamanızı içerir!
|
||||
|
||||
Web uygulamasını başlatmak için çalıştırın:
|
||||
|
||||
```console
|
||||
./my-app php-server
|
||||
```
|
||||
|
||||
Uygulamanız bir [worker betiği](worker.md) içeriyorsa, worker'ı aşağıdaki gibi bir şeyle başlatın:
|
||||
|
||||
```console
|
||||
./my-app php-server --worker public/index.php
|
||||
```
|
||||
|
||||
HTTPS (Let's Encrypt sertifikası otomatik olarak oluşturulur), HTTP/2 ve HTTP/3'ü etkinleştirmek için kullanılacak alan adını belirtin:
|
||||
|
||||
```console
|
||||
./my-app php-server --domain localhost
|
||||
```
|
||||
|
||||
Ayrıca binary dosyanıza gömülü PHP CLI betiklerini de çalıştırabilirsiniz:
|
||||
|
||||
```console
|
||||
./my-app php-cli bin/console
|
||||
```
|
||||
|
||||
## Yapıyı Özelleştirme
|
||||
|
||||
Binary dosyasının nasıl özelleştirileceğini (uzantılar, PHP sürümü...) görmek için [Statik derleme dokümanını okuyun](static.md).
|
||||
|
||||
## Binary Dosyasının Dağıtılması
|
||||
|
||||
Linux'ta, oluşturulan ikili dosya [UPX](https://upx.github.io) kullanılarak sıkıştırılır.
|
||||
|
||||
Mac'te, göndermeden önce dosyanın boyutunu küçültmek için sıkıştırabilirsiniz.
|
||||
Biz `xz` öneririz.
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
# GitHub Actions Kullanma
|
||||
|
||||
Bu depo Docker imajını [Docker Hub](https://hub.docker.com/r/dunglas/frankenphp) üzerinde derler ve dağıtır.
|
||||
Bu durum onaylanan her çekme (pull) isteğinde veya çatallandıktan (fork) sonra gerçekleşir.
|
||||
|
||||
## GitHub Eylemlerini Ayarlama
|
||||
|
||||
Depo ayarlarında, gizli değerler altında aşağıdaki gizli değerleri ekleyin:
|
||||
|
||||
- `REGISTRY_LOGIN_SERVER`: Kullanılacak Docker Registry bilgisi (örneğin `docker.io`).
|
||||
- `REGISTRY_USERNAME`: Giriş yapmak için kullanılacak kullanıcı adı (örn. `dunglas`).
|
||||
- `REGISTRY_PASSWORD`: Oturum açmak için kullanılacak parola (örn. bir erişim anahtarı).
|
||||
- `IMAGE_NAME`: İmajın adı (örn. `dunglas/frankenphp`).
|
||||
|
||||
## İmajı Oluşturma ve Dağıtma
|
||||
|
||||
1. Bir Çekme (pull) İsteği oluşturun veya çatala (forka) dağıtın.
|
||||
2. GitHub Actions imajı oluşturacak ve tüm testleri çalıştıracaktır.
|
||||
3. Derleme başarılı olursa, görüntü `pr-x` (burada `x` PR numarasıdır) etiketi kullanılarak ilgili saklanan yere (registry'e) gönderilir.
|
||||
|
||||
## İmajı Dağıtma
|
||||
|
||||
1. Çekme (pull) isteği birleştirildikten sonra, GitHub Actions testleri tekrar çalıştıracak ve yeni bir imaj oluşturacaktır.
|
||||
2. Derleme başarılı olursa, `main` etiketi Docker Registry'de güncellenecektir.
|
||||
|
||||
## Bültenler
|
||||
|
||||
1. Depoda yeni bir etiket oluşturun.
|
||||
2. GitHub Actions imajı oluşturacak ve tüm testleri çalıştıracaktır.
|
||||
3. Derleme başarılı olursa, etiket adı etiket olarak kullanılarak imaj saklanan yere (registry'e) gönderilir (örneğin `v1.2.3` ve `v1.2` oluşturulur).
|
||||
4. `latest` etiketi de güncellenecektir.
|
||||
# GitHub Actions Kullanma
|
||||
|
||||
Bu depo Docker imajını [Docker Hub](https://hub.docker.com/r/dunglas/frankenphp) üzerinde derler ve dağıtır.
|
||||
Bu durum onaylanan her çekme (pull) isteğinde veya çatallandıktan (fork) sonra gerçekleşir.
|
||||
|
||||
## GitHub Eylemlerini Ayarlama
|
||||
|
||||
Depo ayarlarında, gizli değerler altında aşağıdaki gizli değerleri ekleyin:
|
||||
|
||||
- `REGISTRY_LOGIN_SERVER`: Kullanılacak Docker Registry bilgisi (örneğin `docker.io`).
|
||||
- `REGISTRY_USERNAME`: Giriş yapmak için kullanılacak kullanıcı adı (örn. `dunglas`).
|
||||
- `REGISTRY_PASSWORD`: Oturum açmak için kullanılacak parola (örn. bir erişim anahtarı).
|
||||
- `IMAGE_NAME`: İmajın adı (örn. `dunglas/frankenphp`).
|
||||
|
||||
## İmajı Oluşturma ve Dağıtma
|
||||
|
||||
1. Bir Çekme (pull) İsteği oluşturun veya çatala (forka) dağıtın.
|
||||
2. GitHub Actions imajı oluşturacak ve tüm testleri çalıştıracaktır.
|
||||
3. Derleme başarılı olursa, görüntü `pr-x` (burada `x` PR numarasıdır) etiketi kullanılarak ilgili saklanan yere (registry'e) gönderilir.
|
||||
|
||||
## İmajı Dağıtma
|
||||
|
||||
1. Çekme (pull) isteği birleştirildikten sonra, GitHub Actions testleri tekrar çalıştıracak ve yeni bir imaj oluşturacaktır.
|
||||
2. Derleme başarılı olursa, `main` etiketi Docker Registry'de güncellenecektir.
|
||||
|
||||
## Bültenler
|
||||
|
||||
1. Depoda yeni bir etiket oluşturun.
|
||||
2. GitHub Actions imajı oluşturacak ve tüm testleri çalıştıracaktır.
|
||||
3. Derleme başarılı olursa, etiket adı etiket olarak kullanılarak imaj saklanan yere (registry'e) gönderilir (örneğin `v1.2.3` ve `v1.2` oluşturulur).
|
||||
4. `latest` etiketi de güncellenecektir.
|
||||
|
||||
@@ -1,107 +1,107 @@
|
||||
# Bilinen Sorunlar
|
||||
|
||||
## Desteklenmeyen PHP Eklentileri
|
||||
|
||||
Aşağıdaki eklentilerin FrankenPHP ile uyumlu olmadığı bilinmektedir:
|
||||
|
||||
| Adı | Nedeni | Alternatifleri |
|
||||
|-------------------------------------------------------------|----------------------------|----------------------------------------------------------------------------------------------------------------------|
|
||||
| [imap](https://www.php.net/manual/en/imap.installation.php) | İş parçacığı güvenli değil | [javanile/php-imap2](https://github.com/javanile/php-imap2), [webklex/php-imap](https://github.com/Webklex/php-imap) |
|
||||
|
||||
## Sorunlu PHP Eklentileri
|
||||
|
||||
Aşağıdaki eklentiler FrankenPHP ile kullanıldığında bilinen hatalara ve beklenmeyen davranışlara sahiptir:
|
||||
|
||||
| Adı | Problem |
|
||||
|-----------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
|
||||
## get_browser
|
||||
|
||||
[get_browser()](https://www.php.net/manual/en/function.get-browser.php) fonksiyonu bir süre sonra kötü performans gösteriyor gibi görünüyor. Geçici bir çözüm, statik oldukları için User-Agent başına sonuçları önbelleğe almaktır (örneğin [APCu](https://www.php.net/manual/en/book.apcu.php) ile).
|
||||
|
||||
## Binary Çıktısı ve Alpine Tabanlı Docker İmajları
|
||||
|
||||
Binary çıktısı ve Alpine tabanlı Docker imajları (dunglas/frankenphp:*-alpine), daha küçük bir binary boyutu korumak için glibc ve arkadaşları yerine musl libc kullanır. Bu durum bazı uyumluluk sorunlarına yol açabilir. Özellikle, glob seçeneği GLOB_BRACE mevcut değildir.
|
||||
|
||||
## Docker ile `https://127.0.0.1` Kullanımı
|
||||
|
||||
FrankenPHP varsayılan olarak `localhost` için bir TLS sertifikası oluşturur.
|
||||
Bu, yerel geliştirme için en kolay ve önerilen seçenektir.
|
||||
|
||||
Bunun yerine ana bilgisayar olarak `127.0.0.1` kullanmak istiyorsanız, sunucu adını `127.0.0.1` şeklinde ayarlayarak bunun için bir sertifika oluşturacak yapılandırma yapmak mümkündür.
|
||||
|
||||
Ne yazık ki, [ağ sistemi](https://docs.docker.com/network/) nedeniyle Docker kullanırken bu yeterli değildir.
|
||||
`Curl: (35) LibreSSL/3.3.6: error:1404B438:SSL routines:ST_CONNECT:tlsv1 alert internal error`'a benzer bir TLS hatası alırsınız.
|
||||
|
||||
Linux kullanıyorsanız, [ana bilgisayar ağ sürücüsünü](https://docs.docker.com/network/network-tutorial-host/) kullanmak bir çözümdür:
|
||||
|
||||
```console
|
||||
docker run \
|
||||
-e SERVER_NAME="127.0.0.1" \
|
||||
-v $PWD:/app/public \
|
||||
--network host \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
|
||||
Ana bilgisayar ağ sürücüsü Mac ve Windows'ta desteklenmez. Bu platformlarda, konteynerin IP adresini tahmin etmeniz ve bunu sunucu adlarına dahil etmeniz gerekecektir.
|
||||
|
||||
`docker network inspect bridge`'i çalıştırın ve `IPv4Address` anahtarının altındaki son atanmış IP adresini belirlemek için `Containers` anahtarına bakın ve bir artırın. Eğer hiçbir konteyner çalışmıyorsa, ilk atanan IP adresi genellikle `172.17.0.2`dir.
|
||||
|
||||
Ardından, bunu `SERVER_NAME` ortam değişkenine ekleyin:
|
||||
|
||||
```console
|
||||
docker run \
|
||||
-e SERVER_NAME="127.0.0.1, 172.17.0.3" \
|
||||
-v $PWD:/app/public \
|
||||
-p 80:80 -p 443:443 -p 443:443/udp \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
>
|
||||
> 172.17.0.3`ü konteynerinize atanacak IP ile değiştirdiğinizden emin olun.
|
||||
|
||||
Artık ana makineden `https://127.0.0.1` adresine erişebilmeniz gerekir.
|
||||
|
||||
Eğer durum böyle değilse, sorunu anlamaya çalışmak için FrankenPHP'yi hata ayıklama modunda başlatın:
|
||||
|
||||
```console
|
||||
docker run \
|
||||
-e CADDY_GLOBAL_OPTIONS="debug" \
|
||||
-e SERVER_NAME="127.0.0.1" \
|
||||
-v $PWD:/app/public \
|
||||
-p 80:80 -p 443:443 -p 443:443/udp \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
|
||||
## `@php` Referanslı Composer Betikler
|
||||
|
||||
[Composer betikleri](https://getcomposer.org/doc/articles/scripts.md) bazı görevler için bir PHP binary çalıştırmak isteyebilir, örneğin [bir Laravel projesinde](laravel.md) `@php artisan package:discover --ansi` çalıştırmak. Bu [şu anda mümkün değil](https://github.com/dunglas/frankenphp/issues/483#issuecomment-1899890915) ve 2 nedeni var:
|
||||
|
||||
* Composer FrankenPHP binary dosyasını nasıl çağıracağını bilmiyor;
|
||||
* Composer, FrankenPHP'nin henüz desteklemediği `-d` bayrağını kullanarak PHP ayarlarını komuta ekleyebilir.
|
||||
|
||||
Geçici bir çözüm olarak, `/usr/local/bin/php` içinde desteklenmeyen parametreleri silen ve ardından FrankenPHP'yi çağıran bir kabuk betiği oluşturabiliriz:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
args=("$@")
|
||||
index=0
|
||||
for i in "$@"
|
||||
do
|
||||
if [ "$i" == "-d" ]; then
|
||||
unset 'args[$index]'
|
||||
unset 'args[$index+1]'
|
||||
fi
|
||||
index=$((index+1))
|
||||
done
|
||||
|
||||
/usr/local/bin/frankenphp php-cli ${args[@]}
|
||||
```
|
||||
|
||||
Ardından `PHP_BINARY` ortam değişkenini PHP betiğimizin yoluna ayarlayın ve Composer bu yolla çalışacaktır:
|
||||
|
||||
```bash
|
||||
export PHP_BINARY=/usr/local/bin/php
|
||||
composer install
|
||||
```
|
||||
# Bilinen Sorunlar
|
||||
|
||||
## Desteklenmeyen PHP Eklentileri
|
||||
|
||||
Aşağıdaki eklentilerin FrankenPHP ile uyumlu olmadığı bilinmektedir:
|
||||
|
||||
| Adı | Nedeni | Alternatifleri |
|
||||
| ----------------------------------------------------------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
||||
| [imap](https://www.php.net/manual/en/imap.installation.php) | İş parçacığı güvenli değil | [javanile/php-imap2](https://github.com/javanile/php-imap2), [webklex/php-imap](https://github.com/Webklex/php-imap) |
|
||||
|
||||
## Sorunlu PHP Eklentileri
|
||||
|
||||
Aşağıdaki eklentiler FrankenPHP ile kullanıldığında bilinen hatalara ve beklenmeyen davranışlara sahiptir:
|
||||
|
||||
| Adı | Problem |
|
||||
| --- | ------- |
|
||||
|
||||
## get_browser
|
||||
|
||||
[get_browser()](https://www.php.net/manual/en/function.get-browser.php) fonksiyonu bir süre sonra kötü performans gösteriyor gibi görünüyor. Geçici bir çözüm, statik oldukları için User-Agent başına sonuçları önbelleğe almaktır (örneğin [APCu](https://www.php.net/manual/en/book.apcu.php) ile).
|
||||
|
||||
## Binary Çıktısı ve Alpine Tabanlı Docker İmajları
|
||||
|
||||
Binary çıktısı ve Alpine tabanlı Docker imajları (dunglas/frankenphp:\*-alpine), daha küçük bir binary boyutu korumak için glibc ve arkadaşları yerine musl libc kullanır. Bu durum bazı uyumluluk sorunlarına yol açabilir. Özellikle, glob seçeneği GLOB_BRACE mevcut değildir.
|
||||
|
||||
## Docker ile `https://127.0.0.1` Kullanımı
|
||||
|
||||
FrankenPHP varsayılan olarak `localhost` için bir TLS sertifikası oluşturur.
|
||||
Bu, yerel geliştirme için en kolay ve önerilen seçenektir.
|
||||
|
||||
Bunun yerine ana bilgisayar olarak `127.0.0.1` kullanmak istiyorsanız, sunucu adını `127.0.0.1` şeklinde ayarlayarak bunun için bir sertifika oluşturacak yapılandırma yapmak mümkündür.
|
||||
|
||||
Ne yazık ki, [ağ sistemi](https://docs.docker.com/network/) nedeniyle Docker kullanırken bu yeterli değildir.
|
||||
`Curl: (35) LibreSSL/3.3.6: error:1404B438:SSL routines:ST_CONNECT:tlsv1 alert internal error`'a benzer bir TLS hatası alırsınız.
|
||||
|
||||
Linux kullanıyorsanız, [ana bilgisayar ağ sürücüsünü](https://docs.docker.com/network/network-tutorial-host/) kullanmak bir çözümdür:
|
||||
|
||||
```console
|
||||
docker run \
|
||||
-e SERVER_NAME="127.0.0.1" \
|
||||
-v $PWD:/app/public \
|
||||
--network host \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
|
||||
Ana bilgisayar ağ sürücüsü Mac ve Windows'ta desteklenmez. Bu platformlarda, konteynerin IP adresini tahmin etmeniz ve bunu sunucu adlarına dahil etmeniz gerekecektir.
|
||||
|
||||
`docker network inspect bridge`'i çalıştırın ve `IPv4Address` anahtarının altındaki son atanmış IP adresini belirlemek için `Containers` anahtarına bakın ve bir artırın. Eğer hiçbir konteyner çalışmıyorsa, ilk atanan IP adresi genellikle `172.17.0.2`dir.
|
||||
|
||||
Ardından, bunu `SERVER_NAME` ortam değişkenine ekleyin:
|
||||
|
||||
```console
|
||||
docker run \
|
||||
-e SERVER_NAME="127.0.0.1, 172.17.0.3" \
|
||||
-v $PWD:/app/public \
|
||||
-p 80:80 -p 443:443 -p 443:443/udp \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
>
|
||||
> 172.17.0.3`ü konteynerinize atanacak IP ile değiştirdiğinizden emin olun.
|
||||
|
||||
Artık ana makineden `https://127.0.0.1` adresine erişebilmeniz gerekir.
|
||||
|
||||
Eğer durum böyle değilse, sorunu anlamaya çalışmak için FrankenPHP'yi hata ayıklama modunda başlatın:
|
||||
|
||||
```console
|
||||
docker run \
|
||||
-e CADDY_GLOBAL_OPTIONS="debug" \
|
||||
-e SERVER_NAME="127.0.0.1" \
|
||||
-v $PWD:/app/public \
|
||||
-p 80:80 -p 443:443 -p 443:443/udp \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
|
||||
## `@php` Referanslı Composer Betikler
|
||||
|
||||
[Composer betikleri](https://getcomposer.org/doc/articles/scripts.md) bazı görevler için bir PHP binary çalıştırmak isteyebilir, örneğin [bir Laravel projesinde](laravel.md) `@php artisan package:discover --ansi` çalıştırmak. Bu [şu anda mümkün değil](https://github.com/dunglas/frankenphp/issues/483#issuecomment-1899890915) ve 2 nedeni var:
|
||||
|
||||
- Composer FrankenPHP binary dosyasını nasıl çağıracağını bilmiyor;
|
||||
- Composer, FrankenPHP'nin henüz desteklemediği `-d` bayrağını kullanarak PHP ayarlarını komuta ekleyebilir.
|
||||
|
||||
Geçici bir çözüm olarak, `/usr/local/bin/php` içinde desteklenmeyen parametreleri silen ve ardından FrankenPHP'yi çağıran bir kabuk betiği oluşturabiliriz:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
args=("$@")
|
||||
index=0
|
||||
for i in "$@"
|
||||
do
|
||||
if [ "$i" == "-d" ]; then
|
||||
unset 'args[$index]'
|
||||
unset 'args[$index+1]'
|
||||
fi
|
||||
index=$((index+1))
|
||||
done
|
||||
|
||||
/usr/local/bin/frankenphp php-cli ${args[@]}
|
||||
```
|
||||
|
||||
Ardından `PHP_BINARY` ortam değişkenini PHP betiğimizin yoluna ayarlayın ve Composer bu yolla çalışacaktır:
|
||||
|
||||
```bash
|
||||
export PHP_BINARY=/usr/local/bin/php
|
||||
composer install
|
||||
```
|
||||
|
||||
@@ -1,74 +1,74 @@
|
||||
# Laravel
|
||||
|
||||
## Docker
|
||||
|
||||
Bir [Laravel](https://laravel.com) web uygulamasını FrankenPHP ile çalıştırmak, projeyi resmi Docker imajının `/app` dizinine monte etmek kadar kolaydır.
|
||||
|
||||
Bu komutu Laravel uygulamanızın ana dizininden çalıştırın:
|
||||
|
||||
```console
|
||||
docker run -p 80:80 -p 443:443 -p 443:443/udp -v $PWD:/app dunglas/frankenphp
|
||||
```
|
||||
|
||||
And tadını çıkarın!
|
||||
|
||||
## Yerel Kurulum
|
||||
|
||||
Alternatif olarak, Laravel projelerinizi FrankenPHP ile yerel makinenizden çalıştırabilirsiniz:
|
||||
|
||||
1. [Sisteminize karşılık gelen binary dosyayı indirin](https://github.com/dunglas/frankenphp/releases)
|
||||
2. Aşağıdaki yapılandırmayı Laravel projenizin kök dizinindeki `Caddyfile` adlı bir dosyaya ekleyin:
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
frankenphp
|
||||
}
|
||||
|
||||
# Sunucunuzun alan adı
|
||||
localhost {
|
||||
# Webroot'u public/ dizinine ayarlayın
|
||||
root * public/
|
||||
# Sıkıştırmayı etkinleştir (isteğe bağlı)
|
||||
encode zstd br gzip
|
||||
# PHP dosyalarını public/ dizininden çalıştırın ve varlıkları sunun
|
||||
php_server
|
||||
}
|
||||
```
|
||||
|
||||
3. FrankenPHP'yi Laravel projenizin kök dizininden başlatın: `frankenphp run`
|
||||
|
||||
## Laravel Octane
|
||||
|
||||
Octane, Composer paket yöneticisi aracılığıyla kurulabilir:
|
||||
|
||||
```console
|
||||
composer require laravel/octane
|
||||
```
|
||||
|
||||
Octane'ı kurduktan sonra, Octane'ın yapılandırma dosyasını uygulamanıza yükleyecek olan `octane:install` Artisan komutunu çalıştırabilirsiniz:
|
||||
|
||||
```console
|
||||
php artisan octane:install --server=frankenphp
|
||||
```
|
||||
|
||||
Octane sunucusu `octane:frankenphp` Artisan komutu aracılığıyla başlatılabilir.
|
||||
|
||||
```console
|
||||
php artisan octane:frankenphp
|
||||
```
|
||||
|
||||
`octane:frankenphp` komutu aşağıdaki seçenekleri alabilir:
|
||||
|
||||
* `--host`: Sunucunun bağlanması gereken IP adresi (varsayılan: `127.0.0.1`)
|
||||
* `--port`: Sunucunun erişilebilir olması gereken port (varsayılan: `8000`)
|
||||
* `--admin-port`: Yönetici sunucusunun erişilebilir olması gereken port (varsayılan: `2019`)
|
||||
* `--workers`: İstekleri işlemek için hazır olması gereken worker sayısı (varsayılan: `auto`)
|
||||
* `--max-requests`: Sunucu yeniden yüklenmeden önce işlenecek istek sayısı (varsayılan: `500`)
|
||||
* `--caddyfile`: FrankenPHP `Caddyfile` dosyasının yolu
|
||||
* `--https`: HTTPS, HTTP/2 ve HTTP/3'ü etkinleştirin ve sertifikaları otomatik olarak oluşturup yenileyin
|
||||
* `--http-redirect`: HTTP'den HTTPS'ye yeniden yönlendirmeyi etkinleştir (yalnızca --https geçilirse etkinleştirilir)
|
||||
* `--watch`: Uygulamada kod değişikliği olduğunda sunucuyu otomatik olarak yeniden yükle
|
||||
* `--poll`: Dosyaları bir ağ üzerinden izlemek için izleme sırasında dosya sistemi yoklamasını kullanın
|
||||
* `--log-level`: Belirtilen günlük seviyesinde veya üzerinde günlük mesajları
|
||||
|
||||
Laravel Octane hakkında daha fazla bilgi edinmek için [Laravel Octane resmi belgelerine](https://laravel.com/docs/octane) göz atın.
|
||||
# Laravel
|
||||
|
||||
## Docker
|
||||
|
||||
Bir [Laravel](https://laravel.com) web uygulamasını FrankenPHP ile çalıştırmak, projeyi resmi Docker imajının `/app` dizinine monte etmek kadar kolaydır.
|
||||
|
||||
Bu komutu Laravel uygulamanızın ana dizininden çalıştırın:
|
||||
|
||||
```console
|
||||
docker run -p 80:80 -p 443:443 -p 443:443/udp -v $PWD:/app dunglas/frankenphp
|
||||
```
|
||||
|
||||
And tadını çıkarın!
|
||||
|
||||
## Yerel Kurulum
|
||||
|
||||
Alternatif olarak, Laravel projelerinizi FrankenPHP ile yerel makinenizden çalıştırabilirsiniz:
|
||||
|
||||
1. [Sisteminize karşılık gelen binary dosyayı indirin](https://github.com/dunglas/frankenphp/releases)
|
||||
2. Aşağıdaki yapılandırmayı Laravel projenizin kök dizinindeki `Caddyfile` adlı bir dosyaya ekleyin:
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
frankenphp
|
||||
}
|
||||
|
||||
# Sunucunuzun alan adı
|
||||
localhost {
|
||||
# Webroot'u public/ dizinine ayarlayın
|
||||
root public/
|
||||
# Sıkıştırmayı etkinleştir (isteğe bağlı)
|
||||
encode zstd br gzip
|
||||
# PHP dosyalarını public/ dizininden çalıştırın ve varlıkları sunun
|
||||
php_server
|
||||
}
|
||||
```
|
||||
|
||||
3. FrankenPHP'yi Laravel projenizin kök dizininden başlatın: `frankenphp run`
|
||||
|
||||
## Laravel Octane
|
||||
|
||||
Octane, Composer paket yöneticisi aracılığıyla kurulabilir:
|
||||
|
||||
```console
|
||||
composer require laravel/octane
|
||||
```
|
||||
|
||||
Octane'ı kurduktan sonra, Octane'ın yapılandırma dosyasını uygulamanıza yükleyecek olan `octane:install` Artisan komutunu çalıştırabilirsiniz:
|
||||
|
||||
```console
|
||||
php artisan octane:install --server=frankenphp
|
||||
```
|
||||
|
||||
Octane sunucusu `octane:frankenphp` Artisan komutu aracılığıyla başlatılabilir.
|
||||
|
||||
```console
|
||||
php artisan octane:frankenphp
|
||||
```
|
||||
|
||||
`octane:frankenphp` komutu aşağıdaki seçenekleri alabilir:
|
||||
|
||||
- `--host`: Sunucunun bağlanması gereken IP adresi (varsayılan: `127.0.0.1`)
|
||||
- `--port`: Sunucunun erişilebilir olması gereken port (varsayılan: `8000`)
|
||||
- `--admin-port`: Yönetici sunucusunun erişilebilir olması gereken port (varsayılan: `2019`)
|
||||
- `--workers`: İstekleri işlemek için hazır olması gereken worker sayısı (varsayılan: `auto`)
|
||||
- `--max-requests`: Sunucu yeniden yüklenmeden önce işlenecek istek sayısı (varsayılan: `500`)
|
||||
- `--caddyfile`: FrankenPHP `Caddyfile` dosyasının yolu
|
||||
- `--https`: HTTPS, HTTP/2 ve HTTP/3'ü etkinleştirin ve sertifikaları otomatik olarak oluşturup yenileyin
|
||||
- `--http-redirect`: HTTP'den HTTPS'ye yeniden yönlendirmeyi etkinleştir (yalnızca --https geçilirse etkinleştirilir)
|
||||
- `--watch`: Uygulamada kod değişikliği olduğunda sunucuyu otomatik olarak yeniden yükle
|
||||
- `--poll`: Dosyaları bir ağ üzerinden izlemek için izleme sırasında dosya sistemi yoklamasını kullanın
|
||||
- `--log-level`: Belirtilen günlük seviyesinde veya üzerinde günlük mesajları
|
||||
|
||||
Laravel Octane hakkında daha fazla bilgi edinmek için [Laravel Octane resmi belgelerine](https://laravel.com/docs/octane) göz atın.
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Gerçek Zamanlı
|
||||
|
||||
FrankenPHP yerleşik bir [Mercure](https://mercure.rocks) hub ile birlikte gelir!
|
||||
Mercure, olayları tüm bağlı cihazlara gerçek zamanlı olarak göndermeye olanak tanır: anında bir JavaScript olayı alırlar.
|
||||
|
||||
JS kütüphanesi veya SDK gerekmez!
|
||||
|
||||

|
||||
|
||||
Mercure hub'ını etkinleştirmek için [Mercure'ün sitesinde](https://mercure.rocks/docs/hub/config) açıklandığı gibi `Caddyfile`'ı güncelleyin.
|
||||
|
||||
Mercure güncellemelerini kodunuzdan göndermek için [Symfony Mercure Bileşenini](https://symfony.com/components/Mercure) öneririz (kullanmak için Symfony tam yığın çerçevesine ihtiyacınız yoktur).
|
||||
# Gerçek Zamanlı
|
||||
|
||||
FrankenPHP yerleşik bir [Mercure](https://mercure.rocks) hub ile birlikte gelir!
|
||||
Mercure, olayları tüm bağlı cihazlara gerçek zamanlı olarak göndermeye olanak tanır: anında bir JavaScript olayı alırlar.
|
||||
|
||||
JS kütüphanesi veya SDK gerekmez!
|
||||
|
||||

|
||||
|
||||
Mercure hub'ını etkinleştirmek için [Mercure'ün sitesinde](https://mercure.rocks/docs/hub/config) açıklandığı gibi `Caddyfile`'ı güncelleyin.
|
||||
|
||||
Mercure güncellemelerini kodunuzdan göndermek için [Symfony Mercure Bileşenini](https://symfony.com/components/Mercure) öneririz (kullanmak için Symfony tam yığın çerçevesine ihtiyacınız yoktur).
|
||||
|
||||
@@ -1,139 +1,139 @@
|
||||
# Production Ortamına Dağıtım
|
||||
|
||||
Bu dokümanda, Docker Compose kullanarak bir PHP uygulamasını tek bir sunucuya nasıl dağıtacağımızı öğreneceğiz.
|
||||
|
||||
Symfony kullanıyorsanız, Symfony Docker projesinin (FrankenPHP kullanan) "[Production ortamına dağıtım](https://github.com/dunglas/symfony-docker/blob/main/docs/production.md)" dokümanını okumayı tercih edebilirsiniz.
|
||||
|
||||
API Platform (FrankenPHP de kullanır) tercih ediyorsanız, [çerçevenin dağıtım dokümanına](https://api-platform.com/docs/deployment/) bakabilirsiniz.
|
||||
|
||||
## Uygulamanızı Hazırlama
|
||||
|
||||
İlk olarak, PHP projenizin kök dizininde bir `Dockerfile` oluşturun:
|
||||
|
||||
```dockerfile
|
||||
FROM dunglas/frankenphp
|
||||
|
||||
# "your-domain-name.example.com" yerine kendi alan adınızı yazdığınızdan emin olun
|
||||
ENV SERVER_NAME=your-domain-name.example.com
|
||||
# HTTPS'yi devre dışı bırakmak istiyorsanız, bunun yerine bu değeri kullanın:
|
||||
#ENV SERVER_NAME=:80
|
||||
|
||||
# PHP production ayarlarını etkinleştirin
|
||||
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
|
||||
|
||||
# Projenizin PHP dosyalarını genel dizine kopyalayın
|
||||
COPY . /app/public
|
||||
# Symfony veya Laravel kullanıyorsanız, bunun yerine tüm projeyi kopyalamanız gerekir:
|
||||
#COPY . /app
|
||||
```
|
||||
|
||||
Daha fazla ayrıntı ve seçenek için "[Özel Docker İmajı Oluşturma](docker.md)" bölümüne bakın,
|
||||
ve yapılandırmayı nasıl özelleştireceğinizi öğrenmek için PHP eklentilerini ve Caddy modüllerini yükleyin.
|
||||
|
||||
Projeniz Composer kullanıyorsa,
|
||||
Docker imajına dahil ettiğinizden ve bağımlılıklarınızı yüklediğinizden emin olun.
|
||||
|
||||
Ardından, bir `compose.yaml` dosyası ekleyin:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
php:
|
||||
image: dunglas/frankenphp
|
||||
restart: always
|
||||
ports:
|
||||
- "80:80" # HTTP
|
||||
- "443:443" # HTTPS
|
||||
- "443:443/udp" # HTTP/3
|
||||
volumes:
|
||||
- caddy_data:/data
|
||||
- caddy_config:/config
|
||||
|
||||
# Caddy sertifikaları ve yapılandırması için gereken yığınlar (volumes)
|
||||
volumes:
|
||||
caddy_data:
|
||||
caddy_config:
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
>
|
||||
> Önceki örnekler production kullanımı için tasarlanmıştır.
|
||||
> Geliştirme aşamasında, bir yığın (volume), farklı bir PHP yapılandırması ve `SERVER_NAME` ortam değişkeni için farklı bir değer kullanmak isteyebilirsiniz.
|
||||
>
|
||||
> (FrankenPHP kullanan) çok aşamalı Composer, ekstra PHP eklentileri vb. içeren imajlara başvuran daha gelişmiş bir örnek için [Symfony Docker](https://github.com/dunglas/symfony-docker) projesine bir göz atın.
|
||||
|
||||
Son olarak, eğer Git kullanıyorsanız, bu dosyaları commit edin ve push edin.
|
||||
|
||||
## Sunucu Hazırlama
|
||||
|
||||
Uygulamanızı production ortamına dağıtmak için bir sunucuya ihtiyacınız vardır.
|
||||
Bu dokümanda, DigitalOcean tarafından sağlanan bir sanal makine kullanacağız, ancak herhangi bir Linux sunucusu çalışabilir.
|
||||
Docker yüklü bir Linux sunucunuz varsa, doğrudan [bir sonraki bölüme](#alan-adı-yapılandırma) geçebilirsiniz.
|
||||
|
||||
Aksi takdirde, 200 $ ücretsiz kredi almak için [bu ortaklık bağlantısını](https://m.do.co/c/5d8aabe3ab80) kullanın, bir hesap oluşturun ve ardından "Create a Droplet" seçeneğine tıklayın.
|
||||
Ardından, "Bir imaj seçin" bölümünün altındaki "Marketplace" sekmesine tıklayın ve "Docker" adlı uygulamayı bulun.
|
||||
Bu, Docker ve Docker Compose'un en son sürümlerinin zaten yüklü olduğu bir Ubuntu sunucusu sağlayacaktır!
|
||||
|
||||
Test amaçlı kullanım için en ucuz planlar yeterli olacaktır.
|
||||
Gerçek production kullanımı için, muhtemelen ihtiyaçlarınıza uyacak şekilde "genel amaçlı" bölümünden bir plan seçmek isteyeceksiniz.
|
||||
|
||||

|
||||
|
||||
Diğer ayarlar için varsayılanları koruyabilir veya ihtiyaçlarınıza göre değiştirebilirsiniz.
|
||||
SSH anahtarınızı eklemeyi veya bir parola oluşturmayı unutmayın, ardından "Sonlandır ve oluştur" düğmesine basın.
|
||||
|
||||
Ardından, Droplet'iniz hazırlanırken birkaç saniye bekleyin.
|
||||
Droplet'iniz hazır olduğunda, bağlanmak için SSH kullanın:
|
||||
|
||||
```console
|
||||
ssh root@<droplet-ip>
|
||||
```
|
||||
|
||||
## Alan Adı Yapılandırma
|
||||
|
||||
Çoğu durumda sitenizle bir alan adını ilişkilendirmek isteyeceksiniz.
|
||||
Henüz bir alan adınız yoksa, bir kayıt şirketi aracılığıyla bir alan adı satın almanız gerekir.
|
||||
|
||||
Daha sonra alan adınız için sunucunuzun IP adresini işaret eden `A` türünde bir DNS kaydı oluşturun:
|
||||
|
||||
```dns
|
||||
your-domain-name.example.com. IN A 207.154.233.113
|
||||
```
|
||||
|
||||
DigitalOcean Alan Adları hizmetiyle ilgili örnek ("Networking" > "Domains"):
|
||||
|
||||

|
||||
|
||||
> [!NOTE]
|
||||
>
|
||||
> FrankenPHP tarafından varsayılan olarak otomatik olarak TLS sertifikası oluşturmak için kullanılan hizmet olan Let's Encrypt, direkt IP adreslerinin kullanılmasını desteklemez. Let's Encrypt'i kullanmak için alan adı kullanmak zorunludur.
|
||||
|
||||
## Dağıtım
|
||||
|
||||
Projenizi `git clone`, `scp` veya ihtiyacınıza uygun başka bir araç kullanarak sunucuya kopyalayın.
|
||||
GitHub kullanıyorsanız [bir dağıtım anahtarı](https://docs.github.com/en/free-pro-team@latest/developers/overview/managing-deploy-keys#deploy-keys) kullanmak isteyebilirsiniz.
|
||||
Dağıtım anahtarları ayrıca [GitLab tarafından desteklenir](https://docs.gitlab.com/ee/user/project/deploy_keys/).
|
||||
|
||||
Git ile örnek:
|
||||
|
||||
```console
|
||||
git clone git@github.com:<username>/<project-name>.git
|
||||
```
|
||||
|
||||
Projenizi içeren dizine gidin (`<proje-adı>`) ve uygulamayı production modunda başlatın:
|
||||
|
||||
```console
|
||||
docker compose up -d --wait
|
||||
```
|
||||
|
||||
Sunucunuz hazır ve çalışıyor. Sizin için otomatik olarak bir HTTPS sertifikası oluşturuldu.
|
||||
`https://your-domain-name.example.com` adresine gidin ve keyfini çıkarın!
|
||||
|
||||
> [!CAUTION]
|
||||
>
|
||||
> Docker bir önbellek katmanına sahip olabilir, her dağıtım için doğru derlemeye sahip olduğunuzdan emin olun veya önbellek sorununu önlemek için projenizi `--no-cache` seçeneği ile yeniden oluşturun.
|
||||
|
||||
## Birden Fazla Düğümde Dağıtım
|
||||
|
||||
Uygulamanızı bir makine kümesine dağıtmak istiyorsanız, [Docker Swarm](https://docs.docker.com/engine/swarm/stack-deploy/) kullanabilirsiniz,
|
||||
sağlanan Compose dosyaları ile uyumludur.
|
||||
Kubernetes üzerinde dağıtım yapmak için FrankenPHP kullanan [API Platformu ile sağlanan Helm grafiğine](https://api-platform.com/docs/deployment/kubernetes/) göz atın.
|
||||
# Production Ortamına Dağıtım
|
||||
|
||||
Bu dokümanda, Docker Compose kullanarak bir PHP uygulamasını tek bir sunucuya nasıl dağıtacağımızı öğreneceğiz.
|
||||
|
||||
Symfony kullanıyorsanız, Symfony Docker projesinin (FrankenPHP kullanan) "[Production ortamına dağıtım](https://github.com/dunglas/symfony-docker/blob/main/docs/production.md)" dokümanını okumayı tercih edebilirsiniz.
|
||||
|
||||
API Platform (FrankenPHP de kullanır) tercih ediyorsanız, [çerçevenin dağıtım dokümanına](https://api-platform.com/docs/deployment/) bakabilirsiniz.
|
||||
|
||||
## Uygulamanızı Hazırlama
|
||||
|
||||
İlk olarak, PHP projenizin kök dizininde bir `Dockerfile` oluşturun:
|
||||
|
||||
```dockerfile
|
||||
FROM dunglas/frankenphp
|
||||
|
||||
# "your-domain-name.example.com" yerine kendi alan adınızı yazdığınızdan emin olun
|
||||
ENV SERVER_NAME=your-domain-name.example.com
|
||||
# HTTPS'yi devre dışı bırakmak istiyorsanız, bunun yerine bu değeri kullanın:
|
||||
#ENV SERVER_NAME=:80
|
||||
|
||||
# PHP production ayarlarını etkinleştirin
|
||||
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
|
||||
|
||||
# Projenizin PHP dosyalarını genel dizine kopyalayın
|
||||
COPY . /app/public
|
||||
# Symfony veya Laravel kullanıyorsanız, bunun yerine tüm projeyi kopyalamanız gerekir:
|
||||
#COPY . /app
|
||||
```
|
||||
|
||||
Daha fazla ayrıntı ve seçenek için "[Özel Docker İmajı Oluşturma](docker.md)" bölümüne bakın,
|
||||
ve yapılandırmayı nasıl özelleştireceğinizi öğrenmek için PHP eklentilerini ve Caddy modüllerini yükleyin.
|
||||
|
||||
Projeniz Composer kullanıyorsa,
|
||||
Docker imajına dahil ettiğinizden ve bağımlılıklarınızı yüklediğinizden emin olun.
|
||||
|
||||
Ardından, bir `compose.yaml` dosyası ekleyin:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
php:
|
||||
image: dunglas/frankenphp
|
||||
restart: always
|
||||
ports:
|
||||
- "80:80" # HTTP
|
||||
- "443:443" # HTTPS
|
||||
- "443:443/udp" # HTTP/3
|
||||
volumes:
|
||||
- caddy_data:/data
|
||||
- caddy_config:/config
|
||||
|
||||
# Caddy sertifikaları ve yapılandırması için gereken yığınlar (volumes)
|
||||
volumes:
|
||||
caddy_data:
|
||||
caddy_config:
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
>
|
||||
> Önceki örnekler production kullanımı için tasarlanmıştır.
|
||||
> Geliştirme aşamasında, bir yığın (volume), farklı bir PHP yapılandırması ve `SERVER_NAME` ortam değişkeni için farklı bir değer kullanmak isteyebilirsiniz.
|
||||
>
|
||||
> (FrankenPHP kullanan) çok aşamalı Composer, ekstra PHP eklentileri vb. içeren imajlara başvuran daha gelişmiş bir örnek için [Symfony Docker](https://github.com/dunglas/symfony-docker) projesine bir göz atın.
|
||||
|
||||
Son olarak, eğer Git kullanıyorsanız, bu dosyaları commit edin ve push edin.
|
||||
|
||||
## Sunucu Hazırlama
|
||||
|
||||
Uygulamanızı production ortamına dağıtmak için bir sunucuya ihtiyacınız vardır.
|
||||
Bu dokümanda, DigitalOcean tarafından sağlanan bir sanal makine kullanacağız, ancak herhangi bir Linux sunucusu çalışabilir.
|
||||
Docker yüklü bir Linux sunucunuz varsa, doğrudan [bir sonraki bölüme](#alan-adı-yapılandırma) geçebilirsiniz.
|
||||
|
||||
Aksi takdirde, 200 $ ücretsiz kredi almak için [bu ortaklık bağlantısını](https://m.do.co/c/5d8aabe3ab80) kullanın, bir hesap oluşturun ve ardından "Create a Droplet" seçeneğine tıklayın.
|
||||
Ardından, "Bir imaj seçin" bölümünün altındaki "Marketplace" sekmesine tıklayın ve "Docker" adlı uygulamayı bulun.
|
||||
Bu, Docker ve Docker Compose'un en son sürümlerinin zaten yüklü olduğu bir Ubuntu sunucusu sağlayacaktır!
|
||||
|
||||
Test amaçlı kullanım için en ucuz planlar yeterli olacaktır.
|
||||
Gerçek production kullanımı için, muhtemelen ihtiyaçlarınıza uyacak şekilde "genel amaçlı" bölümünden bir plan seçmek isteyeceksiniz.
|
||||
|
||||

|
||||
|
||||
Diğer ayarlar için varsayılanları koruyabilir veya ihtiyaçlarınıza göre değiştirebilirsiniz.
|
||||
SSH anahtarınızı eklemeyi veya bir parola oluşturmayı unutmayın, ardından "Sonlandır ve oluştur" düğmesine basın.
|
||||
|
||||
Ardından, Droplet'iniz hazırlanırken birkaç saniye bekleyin.
|
||||
Droplet'iniz hazır olduğunda, bağlanmak için SSH kullanın:
|
||||
|
||||
```console
|
||||
ssh root@<droplet-ip>
|
||||
```
|
||||
|
||||
## Alan Adı Yapılandırma
|
||||
|
||||
Çoğu durumda sitenizle bir alan adını ilişkilendirmek isteyeceksiniz.
|
||||
Henüz bir alan adınız yoksa, bir kayıt şirketi aracılığıyla bir alan adı satın almanız gerekir.
|
||||
|
||||
Daha sonra alan adınız için sunucunuzun IP adresini işaret eden `A` türünde bir DNS kaydı oluşturun:
|
||||
|
||||
```dns
|
||||
your-domain-name.example.com. IN A 207.154.233.113
|
||||
```
|
||||
|
||||
DigitalOcean Alan Adları hizmetiyle ilgili örnek ("Networking" > "Domains"):
|
||||
|
||||

|
||||
|
||||
> [!NOTE]
|
||||
>
|
||||
> FrankenPHP tarafından varsayılan olarak otomatik olarak TLS sertifikası oluşturmak için kullanılan hizmet olan Let's Encrypt, direkt IP adreslerinin kullanılmasını desteklemez. Let's Encrypt'i kullanmak için alan adı kullanmak zorunludur.
|
||||
|
||||
## Dağıtım
|
||||
|
||||
Projenizi `git clone`, `scp` veya ihtiyacınıza uygun başka bir araç kullanarak sunucuya kopyalayın.
|
||||
GitHub kullanıyorsanız [bir dağıtım anahtarı](https://docs.github.com/en/free-pro-team@latest/developers/overview/managing-deploy-keys#deploy-keys) kullanmak isteyebilirsiniz.
|
||||
Dağıtım anahtarları ayrıca [GitLab tarafından desteklenir](https://docs.gitlab.com/ee/user/project/deploy_keys/).
|
||||
|
||||
Git ile örnek:
|
||||
|
||||
```console
|
||||
git clone git@github.com:<username>/<project-name>.git
|
||||
```
|
||||
|
||||
Projenizi içeren dizine gidin (`<proje-adı>`) ve uygulamayı production modunda başlatın:
|
||||
|
||||
```console
|
||||
docker compose up -d --wait
|
||||
```
|
||||
|
||||
Sunucunuz hazır ve çalışıyor. Sizin için otomatik olarak bir HTTPS sertifikası oluşturuldu.
|
||||
`https://your-domain-name.example.com` adresine gidin ve keyfini çıkarın!
|
||||
|
||||
> [!CAUTION]
|
||||
>
|
||||
> Docker bir önbellek katmanına sahip olabilir, her dağıtım için doğru derlemeye sahip olduğunuzdan emin olun veya önbellek sorununu önlemek için projenizi `--no-cache` seçeneği ile yeniden oluşturun.
|
||||
|
||||
## Birden Fazla Düğümde Dağıtım
|
||||
|
||||
Uygulamanızı bir makine kümesine dağıtmak istiyorsanız, [Docker Swarm](https://docs.docker.com/engine/swarm/stack-deploy/) kullanabilirsiniz,
|
||||
sağlanan Compose dosyaları ile uyumludur.
|
||||
Kubernetes üzerinde dağıtım yapmak için FrankenPHP kullanan [API Platformu ile sağlanan Helm grafiğine](https://api-platform.com/docs/deployment/kubernetes/) göz atın.
|
||||
|
||||
@@ -1,100 +1,100 @@
|
||||
# Statik Yapı Oluşturun
|
||||
|
||||
PHP kütüphanesinin yerel kurulumunu kullanmak yerine,
|
||||
harika [static-php-cli projesi](https://github.com/crazywhalecc/static-php-cli) sayesinde FrankenPHP'nin statik bir yapısını oluşturmak mümkündür (adına rağmen, bu proje sadece CLI'yi değil, tüm SAPI'leri destekler).
|
||||
|
||||
Bu yöntemle, tek, taşınabilir bir ikili PHP yorumlayıcısını, Caddy web sunucusunu ve FrankenPHP'yi içerecektir!
|
||||
|
||||
FrankenPHP ayrıca [PHP uygulamasının statik binary gömülmesini](embed.md) destekler.
|
||||
|
||||
## Linux
|
||||
|
||||
Linux statik binary dosyası oluşturmak için bir Docker imajı sağlıyoruz:
|
||||
|
||||
```console
|
||||
docker buildx bake --load static-builder
|
||||
docker cp $(docker create --name static-builder dunglas/frankenphp:static-builder):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp ; docker rm static-builder
|
||||
```
|
||||
|
||||
Elde edilen statik binary `frankenphp` olarak adlandırılır ve geçerli dizinde kullanılabilir.
|
||||
|
||||
Statik binary dosyasını Docker olmadan oluşturmak istiyorsanız, Linux için de çalışan macOS talimatlarına bir göz atın.
|
||||
|
||||
### Özel Eklentiler
|
||||
|
||||
Varsayılan olarak, en popüler PHP eklentileri zaten derlenir.
|
||||
|
||||
Binary dosyanın boyutunu küçültmek ve saldırı yüzeyini azaltmak için `PHP_EXTENSIONS` Docker ARG'sini kullanarak derlenecek eklentilerin listesini seçebilirsiniz.
|
||||
|
||||
Örneğin, yalnızca `opcache` eklentisini derlemek için aşağıdaki komutu çalıştırın:
|
||||
|
||||
```console
|
||||
docker buildx bake --load --set static-builder.args.PHP_EXTENSIONS=opcache,pdo_sqlite static-builder
|
||||
# ...
|
||||
```
|
||||
|
||||
Etkinleştirdiğiniz eklentilere ek işlevler sağlayan kütüphaneler eklemek için `PHP_EXTENSION_LIBS` Docker ARG'sini kullanabilirsiniz:
|
||||
|
||||
```console
|
||||
docker buildx bake \
|
||||
--load \
|
||||
--set static-builder.args.PHP_EXTENSIONS=gd \
|
||||
--set static-builder.args.PHP_EXTENSION_LIBS=libjpeg,libwebp \
|
||||
static-builder
|
||||
```
|
||||
|
||||
### Ekstra Caddy Modülleri
|
||||
|
||||
Ekstra Caddy modülleri eklemek veya [xcaddy](https://github.com/caddyserver/xcaddy) adresine başka argümanlar iletmek için `XCADDY_ARGS` Docker ARG'sini kullanın:
|
||||
|
||||
```console
|
||||
docker buildx bake \
|
||||
--load \
|
||||
--set static-builder.args.XCADDY_ARGS="--with github.com/darkweak/souin/plugins/caddy --with github.com/dunglas/caddy-cbrotli --with github.com/dunglas/mercure/caddy --with github.com/dunglas/vulcain/caddy" \
|
||||
static-builder
|
||||
```
|
||||
|
||||
Bu örnekte, Caddy için [Souin](https://souin.io) HTTP önbellek modülünün yanı sıra [cbrotli](https://github.com/dunglas/caddy-cbrotli), [Mercure](https://mercure.rocks) ve [Vulcain](https://vulcain.rocks) modüllerini ekliyoruz.
|
||||
|
||||
> [!TIP]
|
||||
>
|
||||
> cbrotli, Mercure ve Vulcain modülleri, `XCADDY_ARGS` boşsa veya ayarlanmamışsa varsayılan olarak dahil edilir.
|
||||
> Eğer `XCADDY_ARGS` değerini özelleştirirseniz, dahil edilmelerini istiyorsanız bunları açıkça dahil etmelisiniz.
|
||||
|
||||
Derlemeyi nasıl [özelleştireceğinize](#yapıyı-özelleştirme) de bakın.
|
||||
|
||||
### GitHub Token
|
||||
|
||||
GitHub API kullanım limitine ulaşırsanız, `GITHUB_TOKEN` adlı bir ortam değişkeninde bir GitHub Personal Access Token ayarlayın:
|
||||
|
||||
```console
|
||||
GITHUB_TOKEN="xxx" docker --load buildx bake static-builder
|
||||
# ...
|
||||
```
|
||||
|
||||
## macOS
|
||||
|
||||
macOS için statik bir binary oluşturmak için aşağıdaki betiği çalıştırın ([Homebrew](https://brew.sh/) yüklü olmalıdır):
|
||||
|
||||
```console
|
||||
git clone https://github.com/dunglas/frankenphp
|
||||
cd frankenphp
|
||||
./build-static.sh
|
||||
```
|
||||
|
||||
Not: Bu betik Linux'ta (ve muhtemelen diğer Unix'lerde) da çalışır ve sağladığımız Docker tabanlı statik derleyici tarafından dahili olarak kullanılır.
|
||||
|
||||
## Yapıyı Özelleştirme
|
||||
|
||||
Aşağıdaki ortam değişkenleri `docker build` ve `build-static.sh` dosyalarına aktarılabilir
|
||||
statik derlemeyi özelleştirmek için betik:
|
||||
|
||||
* `FRANKENPHP_VERSION`: kullanılacak FrankenPHP sürümü
|
||||
* `PHP_VERSION`: kullanılacak PHP sürümü
|
||||
* `PHP_EXTENSIONS`: oluşturulacak PHP eklentileri ([desteklenen eklentiler listesi](https://static-php.dev/en/guide/extensions.html))
|
||||
* `PHP_EXTENSION_LIBS`: eklentilere özellikler ekleyen oluşturulacak ekstra kütüphaneler
|
||||
* `XCADDY_ARGS`: [xcaddy](https://github.com/caddyserver/xcaddy) adresine iletilecek argümanlar, örneğin ekstra Caddy modülleri eklemek için
|
||||
* `EMBED`: binary dosyaya gömülecek PHP uygulamasının yolu
|
||||
* `CLEAN`: ayarlandığında, libphp ve tüm bağımlılıkları sıfırdan oluşturulur (önbellek yok)
|
||||
* `DEBUG_SYMBOLS`: ayarlandığında, hata ayıklama sembolleri ayıklanmayacak ve binary dosyaya eklenecektir
|
||||
* `RELEASE`: (yalnızca bakımcılar) ayarlandığında, ortaya çıkan binary dosya GitHub'a yüklenecektir
|
||||
# Statik Yapı Oluşturun
|
||||
|
||||
PHP kütüphanesinin yerel kurulumunu kullanmak yerine,
|
||||
harika [static-php-cli projesi](https://github.com/crazywhalecc/static-php-cli) sayesinde FrankenPHP'nin statik bir yapısını oluşturmak mümkündür (adına rağmen, bu proje sadece CLI'yi değil, tüm SAPI'leri destekler).
|
||||
|
||||
Bu yöntemle, tek, taşınabilir bir ikili PHP yorumlayıcısını, Caddy web sunucusunu ve FrankenPHP'yi içerecektir!
|
||||
|
||||
FrankenPHP ayrıca [PHP uygulamasının statik binary gömülmesini](embed.md) destekler.
|
||||
|
||||
## Linux
|
||||
|
||||
Linux statik binary dosyası oluşturmak için bir Docker imajı sağlıyoruz:
|
||||
|
||||
```console
|
||||
docker buildx bake --load static-builder
|
||||
docker cp $(docker create --name static-builder-musl dunglas/frankenphp:static-builder-musl):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp ; docker rm static-builder
|
||||
```
|
||||
|
||||
Elde edilen statik binary `frankenphp` olarak adlandırılır ve geçerli dizinde kullanılabilir.
|
||||
|
||||
Statik binary dosyasını Docker olmadan oluşturmak istiyorsanız, Linux için de çalışan macOS talimatlarına bir göz atın.
|
||||
|
||||
### Özel Eklentiler
|
||||
|
||||
Varsayılan olarak, en popüler PHP eklentileri zaten derlenir.
|
||||
|
||||
Binary dosyanın boyutunu küçültmek ve saldırı yüzeyini azaltmak için `PHP_EXTENSIONS` Docker ARG'sini kullanarak derlenecek eklentilerin listesini seçebilirsiniz.
|
||||
|
||||
Örneğin, yalnızca `opcache` eklentisini derlemek için aşağıdaki komutu çalıştırın:
|
||||
|
||||
```console
|
||||
docker buildx bake --load --set static-builder.args.PHP_EXTENSIONS=opcache,pdo_sqlite static-builder
|
||||
# ...
|
||||
```
|
||||
|
||||
Etkinleştirdiğiniz eklentilere ek işlevler sağlayan kütüphaneler eklemek için `PHP_EXTENSION_LIBS` Docker ARG'sini kullanabilirsiniz:
|
||||
|
||||
```console
|
||||
docker buildx bake \
|
||||
--load \
|
||||
--set static-builder.args.PHP_EXTENSIONS=gd \
|
||||
--set static-builder.args.PHP_EXTENSION_LIBS=libjpeg,libwebp \
|
||||
static-builder
|
||||
```
|
||||
|
||||
### Ekstra Caddy Modülleri
|
||||
|
||||
Ekstra Caddy modülleri eklemek veya [xcaddy](https://github.com/caddyserver/xcaddy) adresine başka argümanlar iletmek için `XCADDY_ARGS` Docker ARG'sini kullanın:
|
||||
|
||||
```console
|
||||
docker buildx bake \
|
||||
--load \
|
||||
--set static-builder.args.XCADDY_ARGS="--with github.com/darkweak/souin/plugins/caddy --with github.com/dunglas/caddy-cbrotli --with github.com/dunglas/mercure/caddy --with github.com/dunglas/vulcain/caddy" \
|
||||
static-builder
|
||||
```
|
||||
|
||||
Bu örnekte, Caddy için [Souin](https://souin.io) HTTP önbellek modülünün yanı sıra [cbrotli](https://github.com/dunglas/caddy-cbrotli), [Mercure](https://mercure.rocks) ve [Vulcain](https://vulcain.rocks) modüllerini ekliyoruz.
|
||||
|
||||
> [!TIP]
|
||||
>
|
||||
> cbrotli, Mercure ve Vulcain modülleri, `XCADDY_ARGS` boşsa veya ayarlanmamışsa varsayılan olarak dahil edilir.
|
||||
> Eğer `XCADDY_ARGS` değerini özelleştirirseniz, dahil edilmelerini istiyorsanız bunları açıkça dahil etmelisiniz.
|
||||
|
||||
Derlemeyi nasıl [özelleştireceğinize](#yapıyı-özelleştirme) de bakın.
|
||||
|
||||
### GitHub Token
|
||||
|
||||
GitHub API kullanım limitine ulaşırsanız, `GITHUB_TOKEN` adlı bir ortam değişkeninde bir GitHub Personal Access Token ayarlayın:
|
||||
|
||||
```console
|
||||
GITHUB_TOKEN="xxx" docker --load buildx bake static-builder
|
||||
# ...
|
||||
```
|
||||
|
||||
## macOS
|
||||
|
||||
macOS için statik bir binary oluşturmak için aşağıdaki betiği çalıştırın ([Homebrew](https://brew.sh/) yüklü olmalıdır):
|
||||
|
||||
```console
|
||||
git clone https://github.com/dunglas/frankenphp
|
||||
cd frankenphp
|
||||
./build-static.sh
|
||||
```
|
||||
|
||||
Not: Bu betik Linux'ta (ve muhtemelen diğer Unix'lerde) da çalışır ve sağladığımız Docker tabanlı statik derleyici tarafından dahili olarak kullanılır.
|
||||
|
||||
## Yapıyı Özelleştirme
|
||||
|
||||
Aşağıdaki ortam değişkenleri `docker build` ve `build-static.sh` dosyalarına aktarılabilir
|
||||
statik derlemeyi özelleştirmek için betik:
|
||||
|
||||
- `FRANKENPHP_VERSION`: kullanılacak FrankenPHP sürümü
|
||||
- `PHP_VERSION`: kullanılacak PHP sürümü
|
||||
- `PHP_EXTENSIONS`: oluşturulacak PHP eklentileri ([desteklenen eklentiler listesi](https://static-php.dev/en/guide/extensions.html))
|
||||
- `PHP_EXTENSION_LIBS`: eklentilere özellikler ekleyen oluşturulacak ekstra kütüphaneler
|
||||
- `XCADDY_ARGS`: [xcaddy](https://github.com/caddyserver/xcaddy) adresine iletilecek argümanlar, örneğin ekstra Caddy modülleri eklemek için
|
||||
- `EMBED`: binary dosyaya gömülecek PHP uygulamasının yolu
|
||||
- `CLEAN`: ayarlandığında, libphp ve tüm bağımlılıkları sıfırdan oluşturulur (önbellek yok)
|
||||
- `DEBUG_SYMBOLS`: ayarlandığında, hata ayıklama sembolleri ayıklanmayacak ve binary dosyaya eklenecektir
|
||||
- `RELEASE`: (yalnızca bakımcılar) ayarlandığında, ortaya çıkan binary dosya GitHub'a yüklenecektir
|
||||
|
||||
@@ -1,121 +1,124 @@
|
||||
# FrankenPHP Worker'ları Kullanma
|
||||
|
||||
Uygulamanızı bir kez önyükleyin ve bellekte tutun.
|
||||
FrankenPHP gelen istekleri birkaç milisaniye içinde halledecektir.
|
||||
|
||||
## Çalışan Komut Dosyalarının Başlatılması
|
||||
|
||||
### Docker
|
||||
|
||||
`FRANKENPHP_CONFIG` ortam değişkeninin değerini `worker /path/to/your/worker/script.php` olarak ayarlayın:
|
||||
|
||||
```console
|
||||
docker run \
|
||||
-e FRANKENPHP_CONFIG="worker /app/path/to/your/worker/script.php" \
|
||||
-v $PWD:/app \
|
||||
-p 80:80 -p 443:443 -p 443:443/udp \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
|
||||
### Binary Çıktısı
|
||||
|
||||
Geçerli dizinin içeriğini bir worker kullanarak sunmak için `php-server` komutunun `--worker` seçeneğini kullanın:
|
||||
|
||||
```console
|
||||
frankenphp php-server --worker /path/to/your/worker/script.php
|
||||
```
|
||||
|
||||
PHP uygulamanız [binary dosyaya gömülü](embed.md) ise, uygulamanın kök dizinine özel bir `Caddyfile` ekleyebilirsiniz.
|
||||
Otomatik olarak kullanılacaktır.
|
||||
|
||||
## Symfony Çalışma Zamanı
|
||||
|
||||
FrankenPHP'nin worker modu [Symfony Runtime Component](https://symfony.com/doc/current/components/runtime.html) tarafından desteklenmektedir.
|
||||
Herhangi bir Symfony uygulamasını bir worker'da başlatmak için [PHP Runtime](https://github.com/php-runtime/runtime)'ın FrankenPHP paketini yükleyin:
|
||||
|
||||
```console
|
||||
composer require runtime/frankenphp-symfony
|
||||
```
|
||||
|
||||
FrankenPHP Symfony Runtime'ı kullanmak için `APP_RUNTIME` ortam değişkenini tanımlayarak uygulama sunucunuzu başlatın:
|
||||
|
||||
```console
|
||||
docker run \
|
||||
-e FRANKENPHP_CONFIG="worker ./public/index.php" \
|
||||
-e APP_RUNTIME=Runtime\\FrankenPhpSymfony\\Runtime \
|
||||
-v $PWD:/app \
|
||||
-p 80:80 -p 443:443 -p 443:443/udp \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
|
||||
## Laravel Octane
|
||||
|
||||
Bkz. [ilgili doküman](laravel.md#laravel-octane).
|
||||
|
||||
## Özel Uygulamalar
|
||||
|
||||
Aşağıdaki örnek, üçüncü taraf bir kütüphaneye güvenmeden kendi çalışan kodunuzu nasıl oluşturacağınızı göstermektedir:
|
||||
|
||||
```php
|
||||
<?php
|
||||
// public/index.php
|
||||
|
||||
// Bir istemci bağlantısı kesildiğinde alt komut dosyasının sonlandırılmasını önleyin
|
||||
ignore_user_abort(true);
|
||||
|
||||
// Uygulamanızı önyükleyin
|
||||
require __DIR__.'/vendor/autoload.php';
|
||||
|
||||
$myApp = new \App\Kernel();
|
||||
$myApp->boot();
|
||||
|
||||
// Daha iyi performans için döngü dışında işleyici (daha az iş yapıyor)
|
||||
$handler = static function () use ($myApp) {
|
||||
// Bir istek alındığında çağrılır,
|
||||
// superglobals, php://input ve benzerleri sıfırlanır
|
||||
echo $myApp->handle($_GET, $_POST, $_COOKIE, $_FILES, $_SERVER);
|
||||
};
|
||||
|
||||
for ($nbRequests = 0, $running = true; isset($_SERVER['MAX_REQUESTS']) && ($nbRequests < ((int)$_SERVER['MAX_REQUESTS'])) && $running; ++$nbRequests) {
|
||||
$running = \frankenphp_handle_request($handler);
|
||||
|
||||
// HTTP yanıtını gönderdikten sonra bir şey yapın
|
||||
$myApp->terminate();
|
||||
|
||||
// Bir sayfa oluşturmanın ortasında tetiklenme olasılığını azaltmak için çöp toplayıcıyı çağırın
|
||||
gc_collect_cycles();
|
||||
}
|
||||
|
||||
// Temizleme
|
||||
$myApp->shutdown();
|
||||
```
|
||||
|
||||
Ardından, uygulamanızı başlatın ve çalışanınızı yapılandırmak için `FRANKENPHP_CONFIG` ortam değişkenini kullanın:
|
||||
|
||||
```console
|
||||
docker run \
|
||||
-e FRANKENPHP_CONFIG="worker ./public/index.php" \
|
||||
-v $PWD:/app \
|
||||
-p 80:80 -p 443:443 -p 443:443/udp \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
|
||||
Varsayılan olarak, CPU başına 2 worker başlatılır.
|
||||
Başlatılacak worker sayısını da yapılandırabilirsiniz:
|
||||
|
||||
```console
|
||||
docker run \
|
||||
-e FRANKENPHP_CONFIG="worker ./public/index.php 42" \
|
||||
-v $PWD:/app \
|
||||
-p 80:80 -p 443:443 -p 443:443/udp \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
|
||||
### Belirli Sayıda İstekten Sonra Worker'ı Yeniden Başlatın
|
||||
|
||||
<!-- textlint-disable -->
|
||||
PHP başlangıçta uzun süreli işlemler için tasarlanmadığından, hala bellek sızdıran birçok kütüphane ve eski kod vardır.
|
||||
<!-- textlint-enable -->
|
||||
Bu tür kodları worker modunda kullanmak için geçici bir çözüm, belirli sayıda isteği işledikten sonra worker betiğini yeniden başlatmaktır:
|
||||
|
||||
Önceki worker kod parçacığı, `MAX_REQUESTS` adlı bir ortam değişkeni ayarlayarak işlenecek maksimum istek sayısını yapılandırmaya izin verir.
|
||||
# FrankenPHP Worker'ları Kullanma
|
||||
|
||||
Uygulamanızı bir kez önyükleyin ve bellekte tutun.
|
||||
FrankenPHP gelen istekleri birkaç milisaniye içinde halledecektir.
|
||||
|
||||
## Çalışan Komut Dosyalarının Başlatılması
|
||||
|
||||
### Docker
|
||||
|
||||
`FRANKENPHP_CONFIG` ortam değişkeninin değerini `worker /path/to/your/worker/script.php` olarak ayarlayın:
|
||||
|
||||
```console
|
||||
docker run \
|
||||
-e FRANKENPHP_CONFIG="worker /app/path/to/your/worker/script.php" \
|
||||
-v $PWD:/app \
|
||||
-p 80:80 -p 443:443 -p 443:443/udp \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
|
||||
### Binary Çıktısı
|
||||
|
||||
Geçerli dizinin içeriğini bir worker kullanarak sunmak için `php-server` komutunun `--worker` seçeneğini kullanın:
|
||||
|
||||
```console
|
||||
frankenphp php-server --worker /path/to/your/worker/script.php
|
||||
```
|
||||
|
||||
PHP uygulamanız [binary dosyaya gömülü](embed.md) ise, uygulamanın kök dizinine özel bir `Caddyfile` ekleyebilirsiniz.
|
||||
Otomatik olarak kullanılacaktır.
|
||||
|
||||
## Symfony Çalışma Zamanı
|
||||
|
||||
FrankenPHP'nin worker modu [Symfony Runtime Component](https://symfony.com/doc/current/components/runtime.html) tarafından desteklenmektedir.
|
||||
Herhangi bir Symfony uygulamasını bir worker'da başlatmak için [PHP Runtime](https://github.com/php-runtime/runtime)'ın FrankenPHP paketini yükleyin:
|
||||
|
||||
```console
|
||||
composer require runtime/frankenphp-symfony
|
||||
```
|
||||
|
||||
FrankenPHP Symfony Runtime'ı kullanmak için `APP_RUNTIME` ortam değişkenini tanımlayarak uygulama sunucunuzu başlatın:
|
||||
|
||||
```console
|
||||
docker run \
|
||||
-e FRANKENPHP_CONFIG="worker ./public/index.php" \
|
||||
-e APP_RUNTIME=Runtime\\FrankenPhpSymfony\\Runtime \
|
||||
-v $PWD:/app \
|
||||
-p 80:80 -p 443:443 -p 443:443/udp \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
|
||||
## Laravel Octane
|
||||
|
||||
Bkz. [ilgili doküman](laravel.md#laravel-octane).
|
||||
|
||||
## Özel Uygulamalar
|
||||
|
||||
Aşağıdaki örnek, üçüncü taraf bir kütüphaneye güvenmeden kendi çalışan kodunuzu nasıl oluşturacağınızı göstermektedir:
|
||||
|
||||
```php
|
||||
<?php
|
||||
// public/index.php
|
||||
|
||||
// Bir istemci bağlantısı kesildiğinde alt komut dosyasının sonlandırılmasını önleyin
|
||||
ignore_user_abort(true);
|
||||
|
||||
// Uygulamanızı önyükleyin
|
||||
require __DIR__.'/vendor/autoload.php';
|
||||
|
||||
$myApp = new \App\Kernel();
|
||||
$myApp->boot();
|
||||
|
||||
// Daha iyi performans için döngü dışında işleyici (daha az iş yapıyor)
|
||||
$handler = static function () use ($myApp) {
|
||||
// Bir istek alındığında çağrılır,
|
||||
// superglobals, php://input ve benzerleri sıfırlanır
|
||||
echo $myApp->handle($_GET, $_POST, $_COOKIE, $_FILES, $_SERVER);
|
||||
};
|
||||
|
||||
for ($nbRequests = 0, $running = true; isset($_SERVER['MAX_REQUESTS']) && ($nbRequests < ((int)$_SERVER['MAX_REQUESTS'])) && $running; ++$nbRequests) {
|
||||
$running = \frankenphp_handle_request($handler);
|
||||
|
||||
// HTTP yanıtını gönderdikten sonra bir şey yapın
|
||||
$myApp->terminate();
|
||||
|
||||
// Bir sayfa oluşturmanın ortasında tetiklenme olasılığını azaltmak için çöp toplayıcıyı çağırın
|
||||
gc_collect_cycles();
|
||||
}
|
||||
|
||||
// Temizleme
|
||||
$myApp->shutdown();
|
||||
```
|
||||
|
||||
Ardından, uygulamanızı başlatın ve çalışanınızı yapılandırmak için `FRANKENPHP_CONFIG` ortam değişkenini kullanın:
|
||||
|
||||
```console
|
||||
docker run \
|
||||
-e FRANKENPHP_CONFIG="worker ./public/index.php" \
|
||||
-v $PWD:/app \
|
||||
-p 80:80 -p 443:443 -p 443:443/udp \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
|
||||
Varsayılan olarak, CPU başına 2 worker başlatılır.
|
||||
Başlatılacak worker sayısını da yapılandırabilirsiniz:
|
||||
|
||||
```console
|
||||
docker run \
|
||||
-e FRANKENPHP_CONFIG="worker ./public/index.php 42" \
|
||||
-v $PWD:/app \
|
||||
-p 80:80 -p 443:443 -p 443:443/udp \
|
||||
dunglas/frankenphp
|
||||
```
|
||||
|
||||
### Belirli Sayıda İstekten Sonra Worker'ı Yeniden Başlatın
|
||||
|
||||
<!-- textlint-disable -->
|
||||
|
||||
PHP başlangıçta uzun süreli işlemler için tasarlanmadığından, hala bellek sızdıran birçok kütüphane ve eski kod vardır.
|
||||
|
||||
<!-- textlint-enable -->
|
||||
|
||||
Bu tür kodları worker modunda kullanmak için geçici bir çözüm, belirli sayıda isteği işledikten sonra worker betiğini yeniden başlatmaktır:
|
||||
|
||||
Önceki worker kod parçacığı, `MAX_REQUESTS` adlı bir ortam değişkeni ayarlayarak işlenecek maksimum istek sayısını yapılandırmaya izin verir.
|
||||
|
||||
@@ -32,7 +32,7 @@ It's also possible to [restart the worker on file changes](config.md#watching-fo
|
||||
The following command will trigger a restart if any file ending in `.php` in the `/path/to/your/app/` directory or subdirectories is modified:
|
||||
|
||||
```console
|
||||
frankenphp php-server --worker /path/to/your/worker/script.php --watch "/path/to/your/app/**/*.php"
|
||||
frankenphp php-server --worker /path/to/your/worker/script.php --watch="/path/to/your/app/**/*.php"
|
||||
```
|
||||
|
||||
## Symfony Runtime
|
||||
@@ -128,10 +128,20 @@ A workaround to using this type of code in worker mode is to restart the worker
|
||||
|
||||
The previous worker snippet allows configuring a maximum number of request to handle by setting an environment variable named `MAX_REQUESTS`.
|
||||
|
||||
### Restart Workers Manually
|
||||
|
||||
While it's possible to restart workers [on file changes](config.md#watching-for-file-changes), it's also possible to restart all workers
|
||||
gracefully via the [Caddy admin API](https://caddyserver.com/docs/api). If the admin is enabled in your
|
||||
[Caddyfile](config.md#caddyfile-config), you can ping the restart endpoint with a simple POST request like this:
|
||||
|
||||
```console
|
||||
curl -X POST http://localhost:2019/frankenphp/workers/restart
|
||||
```
|
||||
|
||||
### Worker Failures
|
||||
|
||||
If a worker script crashes with a non-zero exit code, FrankenPHP will restart it with an exponential backoff strategy.
|
||||
If the worker script stays up longer than the last backoff * 2,
|
||||
If the worker script stays up longer than the last backoff \* 2,
|
||||
it will not penalize the worker script and restart it again.
|
||||
However, if the worker script continues to fail with a non-zero exit code in a short period of time
|
||||
(for example, having a typo in a script), FrankenPHP will crash with the error: `too many consecutive failures`.
|
||||
@@ -141,8 +151,8 @@ However, if the worker script continues to fail with a non-zero exit code in a s
|
||||
[PHP superglobals](https://www.php.net/manual/en/language.variables.superglobals.php) (`$_SERVER`, `$_ENV`, `$_GET`...)
|
||||
behave as follows:
|
||||
|
||||
* before the first call to `frankenphp_handle_request()`, superglobals contain values bound to the worker script itself
|
||||
* during and after the call to `frankenphp_handle_request()`, superglobals contain values generated from the processed HTTP request, each call to `frankenphp_handle_request()` changes the superglobals values
|
||||
- before the first call to `frankenphp_handle_request()`, superglobals contain values bound to the worker script itself
|
||||
- during and after the call to `frankenphp_handle_request()`, superglobals contain values generated from the processed HTTP request, each call to `frankenphp_handle_request()` changes the superglobals values
|
||||
|
||||
To access the superglobals of the worker script inside the callback, you must copy them and import the copy in the scope of the callback:
|
||||
|
||||
|
||||
71
docs/x-sendfile.md
Normal file
71
docs/x-sendfile.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Efficiently Serving Large Static Files (`X-Sendfile`/`X-Accel-Redirect`)
|
||||
|
||||
Usually, static files can be served directly by the web server,
|
||||
but sometimes it's necessary to execute some PHP code before sending them:
|
||||
access control, statistics, custom HTTP headers...
|
||||
|
||||
Unfortunately, using PHP to serve large static files is inefficient compared to
|
||||
direct use of the web server (memory overload, reduced performance...).
|
||||
|
||||
FrankenPHP lets you delegate the sending of static files to the web server
|
||||
**after** executing customized PHP code.
|
||||
|
||||
To do this, your PHP application simply needs to define a custom HTTP header
|
||||
containing the path of the file to be served. FrankenPHP takes care of the rest.
|
||||
|
||||
This feature is known as **`X-Sendfile`** for Apache, and **`X-Accel-Redirect`** for NGINX.
|
||||
|
||||
In the following examples, we assume that the document root of the project is the `public/` directory.
|
||||
and that we want to use PHP to serve files stored outside the `public/` directory,
|
||||
from a directory named `private-files/`.
|
||||
|
||||
## Configuration
|
||||
|
||||
First, add the following configuration to your `Caddyfile` to enable this feature:
|
||||
|
||||
```patch
|
||||
root public/
|
||||
# ...
|
||||
|
||||
+ # Needed for Symfony, Laravel and other projects using the Symfony HttpFoundation component
|
||||
+ request_header X-Sendfile-Type x-accel-redirect
|
||||
+ request_header X-Accel-Mapping ../private-files=/private-files
|
||||
+
|
||||
+ intercept {
|
||||
+ @accel header X-Accel-Redirect *
|
||||
+ handle_response @accel {
|
||||
+ root private-files/
|
||||
+ rewrite * {resp.header.X-Accel-Redirect}
|
||||
+ method * GET
|
||||
+
|
||||
+ # Remove the X-Accel-Redirect header set by PHP for increased security
|
||||
+ header -X-Accel-Redirect
|
||||
+
|
||||
+ file_server
|
||||
+ }
|
||||
+ }
|
||||
|
||||
php_server
|
||||
```
|
||||
|
||||
## Plain PHP
|
||||
|
||||
Set the relative file path (from `private-files/`) as the value of the `X-Accel-Redirect` header:
|
||||
|
||||
```php
|
||||
header('X-Accel-Redirect: file.txt');
|
||||
```
|
||||
|
||||
## Projects using the Symfony HttpFoundation component (Symfony, Laravel, Drupal...)
|
||||
|
||||
Symfony HttpFoundation [natively supports this feature](https://symfony.com/doc/current/components/http_foundation.html#serving-files).
|
||||
It will automatically determine the correct value for the `X-Accel-Redirect` header and add it to the response.
|
||||
|
||||
```php
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
|
||||
BinaryFileResponse::trustXSendfileTypeHeader();
|
||||
$response = new BinaryFileResponse(__DIR__.'/../private-files/file.txt');
|
||||
|
||||
// ...
|
||||
```
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user