Compare commits

...

21 Commits

Author SHA1 Message Date
Kévin Dunglas
79e3a98a11 fix 2025-06-05 18:08:52 +02:00
Kévin Dunglas
afc4463ab3 feat: use frankenphp.dev as Go module path 2025-06-05 18:01:54 +02:00
Marc
6749ddbde5 ci: remove leading v from parsed version (#1626) 2025-06-03 15:01:24 +02:00
Kévin Dunglas
82ba882a4e chore: prepare release 1.7.0 2025-06-03 10:04:05 +02:00
Kévin Dunglas
4b1679e70f chore: bump deps 2025-06-02 17:36:51 +02:00
David Buchmann
75ce2e22c2 docs: clarify Mercure URLs (#916)
* clarify mercure URLs

* Update docs/mercure.md

Co-authored-by: David Buchmann <david@liip.ch>

* Update mercure.md

---------

Co-authored-by: Kévin Dunglas <kevin@dunglas.fr>
2025-06-02 16:04:56 +02:00
Marc
5a43e9f4de feat: make frankenphp directive optional in Caddyfile (#1601)
* make frankenphp directive optional, thanks @francislavoie

* get rid of global variable

* update workers when adding to app

* suggestions

* goto instead of continue outer?

* remove empty frankenphp directives

* update config to reflect the optional frankenphp directive

* AI translations

* restore eol newlines

* don't double check for duplicate worker name

* add short form for php_server worker too

* translations

* AI hates EOL newlines now?

* suggestion to check for nil

* suggestion to use else if block
2025-06-02 15:55:55 +02:00
Alexandre Daubois
5542044376 feat: allow omitting value with the --watch flag of php-server (#1595) 2025-06-02 15:54:01 +02:00
Marc
52b65311c2 ci: get package tag version from binary instead (#1606)
* get package tag version from binary instead

* capture output for better debugging instead
2025-06-01 23:55:50 +02:00
MaximAL
2dc8048ad2 docs: optimize PNG images losslessly: 2 → 1.3 MiB (−36%) (#1623) 2025-06-01 21:47:08 +02:00
Rob Landers
a59b649dac fix: headers before flushing (#1622)
* add tests

* fix test

* attempt to send headers when flushing

* Update testdata/only-headers.php

Co-authored-by: Kévin Dunglas <kevin@dunglas.fr>

---------

Co-authored-by: Kévin Dunglas <kevin@dunglas.fr>
2025-06-01 14:58:36 +02:00
Indra Gunawan
68a4548bf4 skip worker name default value assignment on unmarshal (#1607) 2025-05-31 10:25:47 +02:00
Kévin Dunglas
6f049f9a9c ci: minor cleanup (#1619)
* ci: minor cleanup

* add .golangci.yaml
2025-05-31 08:01:38 +02:00
Kévin Dunglas
340b1fd1c2 docs: improve compilation instructions 2025-05-30 14:05:08 +02:00
wu
c9329bd717 docs: fix typo in French laravel.md (#1617) 2025-05-30 14:04:29 +02:00
Kévin Dunglas
f54a1fa85e fix: prevent cert install warning in Docker images 2025-05-30 14:03:50 +02:00
Kévin Dunglas
b4115ca9a2 fix: linking on OpenBSD 2025-05-29 08:23:17 +02:00
Kévin Dunglas
14469d4a0a chore: fix typo in test comment 2025-05-27 10:10:39 +02:00
Kévin Dunglas
ee394756b1 chore: prepare release 1.6.2 2025-05-23 10:41:10 +02:00
Laury S.
5a260c430a chore: improve style of the default index.php file (#1598)
* feat: improve style of index.php file

* feat: remove assets folder

* Update index.php

* Update index.php

---------

Co-authored-by: Kévin Dunglas <kevin@dunglas.fr>
2025-05-23 10:24:57 +02:00
Kévin Dunglas
b6fcab5a95 ci: always login to Docker if not a Pull Request (#1599) 2025-05-23 00:53:03 +02:00
71 changed files with 1133 additions and 547 deletions

View File

@@ -6,6 +6,6 @@
.idea/
.vscode/
__debug_bin
frankenphp.test
frankenphp.dev.test
caddy/frankenphp/Build
*.log

View File

@@ -17,11 +17,6 @@ updates:
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:

View File

@@ -134,7 +134,7 @@ jobs:
platforms: ${{ matrix.platform }}
- name: Login to DockerHub
uses: docker/login-action@v3
if: github.event.pull_request.head.repo.full_name == github.repository
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,7 +223,7 @@ jobs:
uses: docker/setup-buildx-action@v3
- name: Login to DockerHub
uses: docker/login-action@v3
if: github.event.pull_request.head.repo.full_name == github.repository
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 }}

View File

@@ -23,8 +23,6 @@ jobs:
- name: Lint Code Base
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

View File

@@ -101,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

View File

@@ -101,7 +101,7 @@ jobs:
platforms: ${{ matrix.platform }}
- name: Login to DockerHub
uses: docker/login-action@v3
if: github.event.pull_request.head.repo.full_name == github.repository
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 }}
@@ -205,7 +205,7 @@ jobs:
platforms: ${{ matrix.platform }}
- name: Login to DockerHub
uses: docker/login-action@v3
if: github.event.pull_request.head.repo.full_name == github.repository
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 }}
@@ -315,7 +315,7 @@ jobs:
uses: docker/setup-buildx-action@v3
- name: Login to DockerHub
uses: docker/login-action@v3
if: github.event.pull_request.head.repo.full_name == github.repository
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 }}

View File

@@ -15,6 +15,7 @@ permissions:
contents: read
env:
GOTOOLCHAIN: local
GOEXPERIMENT: cgocheck2
jobs:
tests-linux:
name: Tests (Linux, PHP ${{ matrix.php-versions }})
@@ -24,7 +25,6 @@ jobs:
matrix:
php-versions: ["8.2", "8.3", "8.4"]
env:
GOEXPERIMENT: cgocheck2
GOMAXPROCS: 10
LIBRARY_PATH: ${{ github.workspace }}/watcher/target/lib
steps:
@@ -46,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
@@ -78,7 +78,6 @@ jobs:
name: Tests (macOS, PHP 8.4)
runs-on: macos-latest
env:
GOEXPERIMENT: cgocheck2
HOMEBREW_NO_AUTO_UPDATE: 1
steps:
- uses: actions/checkout@v4

2
.gitignore vendored
View File

@@ -6,7 +6,7 @@
.idea/
.vscode/
__debug_bin
frankenphp.test
frankenphp.dev.test
caddy/frankenphp/Build
package/etc/php.ini
*.log

7
.golangci.yaml Normal file
View File

@@ -0,0 +1,7 @@
---
version: "2"
run:
build-tags:
- nobadger
- nomysql
- nopgx

View File

@@ -176,7 +176,7 @@ 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. When the bug is fixed, revert all these changes
@@ -214,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

View File

@@ -43,12 +43,6 @@ You can also run command-line scripts with:
frankenphp php-cli /path/to/your/script.php
```
> [!WARNING]
>
> In production, prefer using [the Docker images](#docker), [the Brew package](#homebrew)
> or [compiling FrankenPHP from sources](https://frankenphp.dev/docs/compile/).
> The standalone binary is provided for development and testing purposes.
### Docker
Alternatively, [Docker images](https://frankenphp.dev/docs/docker/) are available:
@@ -100,7 +94,7 @@ frankenphp php-server
- [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)
- [Go library documentation](https://pkg.go.dev/frankenphp.dev)
- [Contributing and debugging](https://frankenphp.dev/docs/contributing/)
## Examples and Skeletons

View File

@@ -31,30 +31,14 @@ if [ ! -f "dist/$bin" ]; then
exit 1
fi
if [ -z "${FRANKENPHP_VERSION}" ]; then
FRANKENPHP_VERSION="$(git rev-parse --verify HEAD)"
export FRANKENPHP_VERSION
elif [ -d ".git/" ]; then
CURRENT_REF="$(git rev-parse --abbrev-ref HEAD)"
export CURRENT_REF
version_output="$(dist/"$bin" version)"
frankenphp_version=$(echo "$version_output" | grep -oP 'FrankenPHP\s+\K[^ ]+' || true)
frankenphp_version=${frankenphp_version#v}
if echo "${FRANKENPHP_VERSION}" | grep -F -q "."; then
# Tag
# Trim "v" prefix if any
FRANKENPHP_VERSION=${FRANKENPHP_VERSION#v}
export FRANKENPHP_VERSION
git checkout "v${FRANKENPHP_VERSION}"
else
git checkout "${FRANKENPHP_VERSION}"
fi
fi
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}'"
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
frankenphp_version=0.0.0
fi
group_preexists=0
@@ -87,7 +71,7 @@ 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}" \
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)" \
@@ -110,7 +94,7 @@ fpm -s dir -t rpm -n frankenphp -v "${FRANKENPHP_VERSION}" \
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}" \
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})" \

View File

@@ -330,8 +330,8 @@ CGO_ENABLED=1 \
${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

View File

@@ -4,7 +4,7 @@ import (
"encoding/json"
"fmt"
"github.com/caddyserver/caddy/v2"
"github.com/dunglas/frankenphp"
"frankenphp.dev"
"net/http"
)

View File

@@ -4,14 +4,14 @@ import (
"bytes"
"encoding/json"
"fmt"
"github.com/dunglas/frankenphp/internal/fastabs"
"io"
"net/http"
"sync"
"testing"
"frankenphp.dev"
"frankenphp.dev/internal/fastabs"
"github.com/caddyserver/caddy/v2/caddytest"
"github.com/dunglas/frankenphp"
"github.com/stretchr/testify/assert"
)
@@ -225,8 +225,6 @@ func TestAddModuleWorkerViaAdminApi(t *testing.T) {
skip_install_trust
admin localhost:2999
http_port `+testPort+`
frankenphp
}
localhost:`+testPort+` {
@@ -252,8 +250,6 @@ func TestAddModuleWorkerViaAdminApi(t *testing.T) {
skip_install_trust
admin localhost:2999
http_port ` + testPort + `
frankenphp
}
localhost:` + testPort + ` {

View File

@@ -14,7 +14,7 @@ import (
"strings"
"time"
"github.com/dunglas/frankenphp/internal/fastabs"
"frankenphp.dev/internal/fastabs"
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig"
@@ -23,7 +23,7 @@ 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"
"frankenphp.dev"
)
const (
@@ -33,10 +33,6 @@ const (
var iniError = errors.New("'php_ini' must be in the format: php_ini \"<key>\" \"<value>\"")
// FrankenPHPModule instances register their workers, and FrankenPHPApp reads them at Start() time.
// FrankenPHPApp.Workers may be set by JSON config, so keep them separate.
var moduleWorkerConfigs []workerConfig
func init() {
caddy.RegisterModule(FrankenPHPApp{})
caddy.RegisterModule(FrankenPHPModule{})
@@ -104,6 +100,40 @@ func (f *FrankenPHPApp) Provision(ctx caddy.Context) error {
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()
@@ -115,9 +145,7 @@ func (f *FrankenPHPApp) Start() error {
frankenphp.WithPhpIni(f.PhpIni),
frankenphp.WithMaxWaitTime(f.MaxWaitTime),
}
// Add workers from FrankenPHPApp and FrankenPHPModule configurations
// f.Workers may have been set by JSON config, so keep them separate
for _, w := range append(f.Workers, moduleWorkerConfigs...) {
for _, w := range append(f.Workers) {
opts = append(opts, frankenphp.WithWorkers(w.Name, repl.ReplaceKnown(w.FileName, ""), w.Num, w.Env, w.Watch))
}
@@ -143,7 +171,6 @@ func (f *FrankenPHPApp) Stop() error {
f.Workers = nil
f.NumThreads = 0
f.MaxWaitTime = 0
moduleWorkerConfigs = nil
return nil
}
@@ -316,14 +343,6 @@ func (f *FrankenPHPApp) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if frankenphp.EmbeddedAppPath != "" && filepath.IsLocal(wc.FileName) {
wc.FileName = filepath.Join(frankenphp.EmbeddedAppPath, wc.FileName)
}
if wc.Name == "" {
// let worker initialization validate if the FileName is valid or not
name, _ := fastabs.FastAbs(wc.FileName)
if name == "" {
name = wc.FileName
}
wc.Name = name
}
if strings.HasPrefix(wc.Name, "m#") {
return fmt.Errorf(`global worker names must not start with "m#": %q`, wc.Name)
}
@@ -391,6 +410,23 @@ func (FrankenPHPModule) CaddyModule() caddy.ModuleInfo {
// Provision sets up the module.
func (f *FrankenPHPModule) Provision(ctx caddy.Context) error {
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 == "" {
@@ -504,25 +540,6 @@ func (f *FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ c
return nil
}
func generateUniqueModuleWorkerName(filepath string) string {
var i uint
name := "m#" + filepath
outer:
for {
for _, wc := range moduleWorkerConfigs {
if wc.Name == name {
name = fmt.Sprintf("m#%s_%d", filepath, i)
i++
continue outer
}
}
return name
}
}
// UnmarshalCaddyfile implements caddyfile.Unmarshaler.
func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
// First pass: Parse all directives except "worker"
@@ -608,28 +625,14 @@ func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
}
}
if wc.Name == "" {
wc.Name = generateUniqueModuleWorkerName(wc.FileName)
}
if !strings.HasPrefix(wc.Name, "m#") {
wc.Name = "m#" + wc.Name
}
// 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)
}
}
// Check if a worker with this name and a different environment or filename already exists
for _, existingWorker := range moduleWorkerConfigs {
if existingWorker.Name == wc.Name {
return fmt.Errorf("workers must not have duplicate names: %q", wc.Name)
}
}
f.Workers = append(f.Workers, wc)
moduleWorkerConfigs = append(moduleWorkerConfigs, wc)
}
}
}

View File

@@ -14,8 +14,8 @@ import (
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddytest"
"github.com/dunglas/frankenphp"
"github.com/dunglas/frankenphp/internal/fastabs"
"frankenphp.dev"
"frankenphp.dev/internal/fastabs"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/stretchr/testify/require"
)
@@ -31,8 +31,6 @@ func TestPHP(t *testing.T) {
admin localhost:2999
http_port `+testPort+`
https_port 9443
frankenphp
}
localhost:`+testPort+` {
@@ -63,8 +61,6 @@ func TestLargeRequest(t *testing.T) {
admin localhost:2999
http_port `+testPort+`
https_port 9443
frankenphp
}
localhost:`+testPort+` {
@@ -182,8 +178,6 @@ func TestNamedModuleWorkers(t *testing.T) {
{
skip_install_trust
admin localhost:2999
frankenphp
}
http://localhost:`+testPort+` {
@@ -383,8 +377,6 @@ func TestPHPServerDirective(t *testing.T) {
admin localhost:2999
http_port `+testPort+`
https_port 9443
frankenphp
}
localhost:`+testPort+` {
@@ -406,8 +398,6 @@ func TestPHPServerDirectiveDisableFileServer(t *testing.T) {
admin localhost:2999
http_port `+testPort+`
https_port 9443
frankenphp
order php_server before respond
}
@@ -434,8 +424,6 @@ func TestMetrics(t *testing.T) {
http_port `+testPort+`
https_port 9443
metrics
frankenphp
}
localhost:`+testPort+` {
@@ -800,7 +788,6 @@ func TestAllDefinedServerVars(t *testing.T) {
skip_install_trust
admin localhost:2999
http_port `+testPort+`
frankenphp
}
localhost:`+testPort+` {
route {

View File

@@ -7,11 +7,6 @@ import (
"github.com/stretchr/testify/require"
)
// resetModuleWorkers resets the moduleWorkerConfigs slice for testing
func resetModuleWorkers() {
moduleWorkerConfigs = make([]workerConfig, 0)
}
func TestModuleWorkerDuplicateFilenamesFail(t *testing.T) {
// Create a test configuration with duplicate worker filenames
configWithDuplicateFilenames := `
@@ -38,53 +33,6 @@ func TestModuleWorkerDuplicateFilenamesFail(t *testing.T) {
// 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")
resetModuleWorkers()
}
func TestModuleWorkersDuplicateNameFail(t *testing.T) {
// Create a test configuration with a worker name
configWithWorkerName1 := `
{
php_server {
worker {
name test-worker
file ../testdata/worker-with-env.php
num 1
}
}
}`
// Parse the first configuration
d1 := caddyfile.NewTestDispenser(configWithWorkerName1)
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 the same worker name
configWithWorkerName2 := `
{
php_server {
worker {
name test-worker
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 an error was returned
require.Error(t, err, "Expected an error when two workers have the same name, but different environments")
require.Contains(t, err.Error(), "must not have duplicate names", "Error message should mention duplicate names")
resetModuleWorkers()
}
func TestModuleWorkersWithDifferentFilenames(t *testing.T) {
@@ -111,8 +59,6 @@ func TestModuleWorkersWithDifferentFilenames(t *testing.T) {
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")
resetModuleWorkers()
}
func TestModuleWorkersDifferentNamesSucceed(t *testing.T) {
@@ -130,6 +76,7 @@ func TestModuleWorkersDifferentNamesSucceed(t *testing.T) {
// Parse the first configuration
d1 := caddyfile.NewTestDispenser(configWithWorkerName1)
app := &FrankenPHPApp{}
module1 := &FrankenPHPModule{}
// Unmarshal the first configuration
@@ -158,12 +105,15 @@ func TestModuleWorkersDifferentNamesSucceed(t *testing.T) {
// Verify that no error was returned
require.NoError(t, err, "Expected no error when two workers have different names")
// Verify that both workers were added to moduleWorkerConfigs
require.Len(t, moduleWorkerConfigs, 2, "Expected two workers to be added to moduleWorkerConfigs")
require.Equal(t, "m#test-worker-1", moduleWorkerConfigs[0].Name, "First worker should have the correct name")
require.Equal(t, "m#test-worker-2", moduleWorkerConfigs[1].Name, "Second worker should have the correct name")
_, 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")
resetModuleWorkers()
// 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) {
@@ -198,8 +148,6 @@ func TestModuleWorkerWithEnvironmentVariables(t *testing.T) {
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")
resetModuleWorkers()
}
func TestModuleWorkerWithWatchConfiguration(t *testing.T) {
@@ -236,8 +184,6 @@ func TestModuleWorkerWithWatchConfiguration(t *testing.T) {
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")
resetModuleWorkers()
}
func TestModuleWorkerWithCustomName(t *testing.T) {
@@ -256,6 +202,7 @@ func TestModuleWorkerWithCustomName(t *testing.T) {
// Parse the configuration
d := caddyfile.NewTestDispenser(configWithCustomName)
module := &FrankenPHPModule{}
app := &FrankenPHPApp{}
// Unmarshal the configuration
err := module.UnmarshalCaddyfile(d)
@@ -267,8 +214,9 @@ func TestModuleWorkerWithCustomName(t *testing.T) {
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 moduleWorkerConfigs with the m# prefix
require.Equal(t, "m#custom-worker-name", module.Workers[0].Name, "Worker should have the custom name")
resetModuleWorkers()
// 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#")
}

View File

@@ -4,10 +4,11 @@
# https://caddyserver.com/docs/caddyfile
{
skip_install_trust
{$CADDY_GLOBAL_OPTIONS}
frankenphp {
{$FRANKENPHP_CONFIG}
{$FRANKENPHP_CONFIG}
}
}
@@ -46,7 +47,9 @@
{$CADDY_SERVER_EXTRA_DIRECTIVES}
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

View File

@@ -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"
)

View File

@@ -1,8 +1,8 @@
module github.com/dunglas/frankenphp/caddy
module frankenphp.dev/caddy
go 1.24.0
replace github.com/dunglas/frankenphp => ../
replace frankenphp.dev => ../
retract v1.0.0-rc.1 // Human error
@@ -10,7 +10,7 @@ require (
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.6.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
@@ -18,7 +18,7 @@ require (
github.com/stretchr/testify v1.10.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.24.0 // indirect
@@ -31,11 +31,11 @@ require (
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.9.5 // indirect
github.com/MicahParks/keyfunc/v3 v3.3.11 // 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.17.2 // 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
@@ -85,7 +85,7 @@ require (
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-20250501235452-c0086092b71a // 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
@@ -95,14 +95,14 @@ require (
github.com/inconshreveable/mousetrap v1.1.0 // 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.4 // 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.18.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/libdns/libdns v1.0.0 // 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
@@ -130,7 +130,7 @@ require (
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.51.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.9.0 // indirect
@@ -147,7 +147,7 @@ require (
github.com/smallstep/truststore v0.13.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.14.0 // indirect
github.com/spf13/cast v1.8.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
@@ -161,7 +161,7 @@ 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.11 // 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.4.0 // indirect
@@ -179,15 +179,15 @@ require (
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.63.0 // indirect
go.step.sm/crypto v0.66.0 // indirect
go.uber.org/automaxprocs v1.6.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.38.0 // indirect
golang.org/x/crypto/x509roots/fallback v0.0.0-20250512184618-9dbbcf002b5c // indirect
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // 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
@@ -197,9 +197,9 @@ require (
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-20250512202823-5a2f75b736a9 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250512202823-5a2f75b736a9 // indirect
google.golang.org/grpc v1.72.1 // 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

View File

@@ -6,18 +6,18 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
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.0 h1:Pd8P1s9WkcrBE2n/PhAwKsdrR35V3Sg2II9B+ndM3CU=
cloud.google.com/go/auth v0.16.0/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI=
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.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
cloud.google.com/go/iam v1.5.0 h1:QlLcVMhbLGOjRcGe6VTGGTyQib8dRLK2B/kYNV0+2xs=
cloud.google.com/go/iam v1.5.0/go.mod h1:U+DOtKQltF/LxPEtcDLoobcsZMilSRwR7mgNL7knOpo=
cloud.google.com/go/kms v1.21.2 h1:c/PRUSMNQ8zXrc1sdAUnsenWWaNXN+PzTXfXOcSFdoE=
cloud.google.com/go/kms v1.21.2/go.mod h1:8wkMtHV/9Z8mLXEXr1GK7xPSBdi6knuLXIhqjuWcI6w=
cloud.google.com/go/longrunning v0.6.6 h1:XJNDo5MUfMM05xK3ewpbSdmt7R2Zw+aQEMbdQR65Rbw=
cloud.google.com/go/longrunning v0.6.6/go.mod h1:hyeGJUrPHcx0u2Uu1UFSoYZLn4lkMrccJig0t4FI7yw=
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=
@@ -44,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.9.5 h1:/baA2n7RhO7nRIe1rx4ZX1Opeq+mwDuuWi2myDZwqnA=
github.com/MicahParks/jwkset v0.9.5/go.mod h1:U2oRhRaLgDCLjtpGL2GseNKGmZtLs/3O7p+OZaL5vo0=
github.com/MicahParks/keyfunc/v3 v3.3.11 h1:eA6wNltwdSRX2gtpTwZseBCC9nGeBkI9KxHtTyZbDbo=
github.com/MicahParks/keyfunc/v3 v3.3.11/go.mod h1:y6Ed3dMgNKTcpxbaQHD8mmrYDUZWJAxteddA6OQj+ag=
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=
@@ -59,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.17.2 h1:Rm81SCZ2mPoH+Q8ZCc/9YvzPUN/E7HgPiPJD8SLV6GI=
github.com/alecthomas/chroma/v2 v2.17.2/go.mod h1:RVX6AvYm4VfYe/zsk7mjHueLDZor3aWCNE14TFlepBk=
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=
@@ -167,6 +167,7 @@ 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/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=
@@ -263,8 +264,8 @@ 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-20250501235452-c0086092b71a h1:rDA3FfmxwXR+BVKKdz55WwMJ1pD2hJQNW31d+l3mPk4=
github.com/google/pprof v0.0.0-20250501235452-c0086092b71a/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
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=
@@ -274,8 +275,8 @@ github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7
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=
@@ -300,8 +301,8 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI
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.4 h1:9wKznZrhWa2QiHL+NjTSPP6yjl3451BX3imWDnokYlg=
github.com/jackc/pgx/v5 v5.7.4/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=
@@ -329,8 +330,8 @@ 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 v1.0.0 h1:IvYaz07JNz6jUQ4h/fv2R4sVnRnm77J/aOuC9B+TQTA=
github.com/libdns/libdns v1.0.0/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/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
@@ -412,8 +413,8 @@ github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzM
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.51.0 h1:K8exxe9zXxeRKxaXxi/GpUqYiTrtdiWP8bo1KFya6Wc=
github.com/quic-go/quic-go v0.51.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ=
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=
@@ -463,8 +464,8 @@ github.com/smallstep/certificates v0.28.3 h1:rcMh1TAs8m2emP3aDJxKLkE9jriAtcFtCuj
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.20240109183208-413678f90935 h1:kjYvkvS/Wdy0PVRDUAA0gGJIVSEZYhiAJtfwYgOYoGA=
github.com/smallstep/go-attestation v0.4.4-0.20240109183208-413678f90935/go.mod h1:vNAduivU014fubg6ewygkAvQC0IQVXqdc8vaGl/0er4=
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=
@@ -486,8 +487,8 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B
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.8.0 h1:gEN9K4b8Xws4EX0+a0reLmhq8moKn7ntRlQYgjPeCDk=
github.com/spf13/cast v1.8.0/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.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
@@ -546,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.11 h1:ZCxLyDMtz0nT2HFfsYG8WZ47Trip2+JyLysKcMYE5bo=
github.com/yuin/goldmark v1.7.11/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
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=
@@ -591,8 +592,8 @@ go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt
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.63.0 h1:U1QGELQqJ85oDfeNFE2V52cow1rvy0m3MekG3wFmyXY=
go.step.sm/crypto v0.63.0/go.mod h1:aj3LETmCZeSil1DMq3BlbhDBcN86+mmKrHZtXWyc0L4=
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=
@@ -618,11 +619,11 @@ golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v
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-20250512184618-9dbbcf002b5c h1:i8SXR9IEBPRl+jdkkgjldNlHiUFpO5pUejfO9igtrHs=
golang.org/x/crypto/x509roots/fallback v0.0.0-20250512184618-9dbbcf002b5c/go.mod h1:lxN5T34bK4Z/i6cMaU7frUU57VkDXFD4Kamfl/cp9oU=
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-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI=
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ=
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=
@@ -738,8 +739,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
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.230.0 h1:2u1hni3E+UXAXrONrrkfWpi/V6cyKVAbfGVeGtC3OxM=
google.golang.org/api v0.230.0/go.mod h1:aqvtoMk7YkiXx+6U12arQFExiRV9D/ekvMCwCd/TksQ=
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=
@@ -749,18 +750,18 @@ 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-20250303144028-a0af3efb3deb h1:ITgPrl429bc6+2ZraNSzMDk3I95nmQln2fuPstKwFDE=
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:sAo5UzpjUwgFBCzupwhcLcxHVDK7vG5IqI30YnwX2eE=
google.golang.org/genproto/googleapis/api v0.0.0-20250512202823-5a2f75b736a9 h1:WvBuA5rjZx9SNIzgcU53OohgZy6lKSus++uY4xLaWKc=
google.golang.org/genproto/googleapis/api v0.0.0-20250512202823-5a2f75b736a9/go.mod h1:W3S/3np0/dPWsWLi1h/UymYctGXaGBM2StwzD0y140U=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250512202823-5a2f75b736a9 h1:IkAfh6J/yllPtpYFU0zZN1hUPYdT0ogkBT/9hMxHjvg=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250512202823-5a2f75b736a9/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
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.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA=
google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
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=

View File

@@ -6,7 +6,7 @@ import (
"path/filepath"
caddycmd "github.com/caddyserver/caddy/v2/cmd"
"github.com/dunglas/frankenphp"
"frankenphp.dev"
"github.com/spf13/cobra"
)

View File

@@ -20,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,
@@ -47,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)
},
})

2
cgi.go
View File

@@ -18,7 +18,7 @@ import (
"strings"
"unsafe"
"github.com/dunglas/frankenphp/internal/phpheaders"
"frankenphp.dev/internal/phpheaders"
)
var knownServerKeys = []string{

View File

@@ -176,7 +176,7 @@ 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. 当错误修复后,恢复所有这些更改

View File

@@ -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

View File

@@ -1,4 +1,4 @@
# 配置
# 配置
FrankenPHPCaddy 以及 Mercure 和 Vulcain 模块可以使用 [Caddy 支持的格式](https://caddyserver.com/docs/getting-started#your-first-config) 进行配置。
@@ -39,16 +39,11 @@ FrankenPHP 安装 (.rpm 或 .deb):
## 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
@@ -57,7 +52,8 @@ localhost {
}
```
或者,可以在全局选项下指定要创建的线程数和要从服务器启动的 [worker 脚本](worker.md)。
您也可以使用全局选项显式配置 FrankenPHP
`frankenphp` [全局选项](https://caddyserver.com/docs/caddyfile/concepts#global-options) 可用于配置 FrankenPHP。
```caddyfile
{
@@ -89,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>
}
}
# ...
```
@@ -139,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 块中一样使用简短形式。
}
```

View File

@@ -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 \

View File

@@ -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:
@@ -67,23 +80,18 @@ Some FrankenPHP features depend on optional system dependencies that must be ins
Alternatively, these features can be disabled by passing build tags to the Go compiler.
| Feature | Dependency | Build tag to disable it |
| ------------------------------ | --------------------------------------------------------------------- | ----------------------- |
|--------------------------------|-----------------------------------------------------------------------|-------------------------|
| Brotli compression | [Brotli](https://github.com/google/brotli) | nobrotli |
| Restart workers on file change | [Watcher C](https://github.com/e-dant/watcher/tree/release/watcher-c) | nowatcher |
## 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
```

View File

@@ -42,16 +42,11 @@ RUN cp $PHP_INI_DIR/php.ini-development $PHP_INI_DIR/php.ini
## 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
@@ -60,7 +55,8 @@ 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
{
@@ -97,21 +93,18 @@ 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>
}
}
# ...
@@ -154,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.
}
```

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

View File

@@ -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 \

View File

@@ -177,7 +177,7 @@ 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. Quand le bug est corrigé, annulez tous les changements.

View File

@@ -42,12 +42,6 @@ Vous pouvez également exécuter des scripts en ligne de commande avec :
frankenphp php-cli /path/to/your/script.php
```
> [!WARNING]
>
> En production, préférez utiliser [les images Docker](#docker), [le paquet Brew](#homebrew)
> ou [compiler FrankenPHP à partir des sources](https://frankenphp.dev/docs/fr/compile/).
> Le binaire autonome est fourni à des fins de développement et de test.
### Docker
Des [images Docker](https://frankenphp.dev/docs/fr/docker/) sont également disponibles :

View File

@@ -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 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 +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 :
@@ -64,26 +79,19 @@ 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 balises de compilation au compilateur Go.
Ces fonctionnalités peuvent également être désactivées en passant des tags de compilation au compilateur Go.
| Fonctionnalité | Dépendance | Balise 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 |
| 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 compiler 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 -tags=nobadger,nomysql,nopgx
```
### 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 \
@@ -92,11 +100,11 @@ 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]
@@ -108,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
```

View File

@@ -1,4 +1,4 @@
# 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).
@@ -41,16 +41,11 @@ Binaire statique :
## 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
@@ -59,14 +54,15 @@ localhost {
}
```
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.
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é.
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.
@@ -96,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 {
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>
}
}
# ...
@@ -153,6 +146,14 @@ php_server [<matcher>] {
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.
}
```

View File

@@ -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 et Vulcain sont inclus dans la construction officielle, mais n'hésitez pas à les retirer
--with github.com/dunglas/mercure/caddy \

View File

@@ -74,7 +74,7 @@ La commande `octane:frankenphp` peut prendre les options suivantes :
- `--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).

View File

@@ -32,7 +32,7 @@ Il est également possible de [redémarrer le worker en cas de changement de fic
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"
frankenphp php-server --worker /path/to/your/worker/script.php --watch="/path/to/your/app/**/*.php"
```
## Runtime Symfony

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1009 KiB

View File

@@ -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!
![Mercure](mercure-hub.png)
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).

View File

@@ -176,7 +176,7 @@ 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. После исправления ошибки откатите все внесенные изменения.

View File

@@ -92,7 +92,7 @@ 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
# Добавьте дополнительные модули Caddy здесь

View File

@@ -1,4 +1,4 @@
# Конфигурация
# Конфигурация
FrankenPHP, Caddy, а также модули Mercure и Vulcain могут быть настроены с использованием [конфигурационных форматов, поддерживаемых Caddy](https://caddyserver.com/docs/getting-started#your-first-config).
@@ -41,16 +41,11 @@ RUN cp $PHP_INI_DIR/php.ini-development $PHP_INI_DIR/php.ini
## Конфигурация Caddyfile
Для настройки FrankenPHP установите [глобальную опцию](https://caddyserver.com/docs/caddyfile/concepts#global-options) frankenphp. После этого можно использовать [HTTP-директивы](https://caddyserver.com/docs/caddyfile/concepts#directives) `php_server` или `php` для обработки вашего PHP-приложения.
[HTTP-директивы](https://caddyserver.com/docs/caddyfile/concepts#directives) `php_server` или `php` могут быть использованы в блоках сайта для обработки вашего PHP-приложения.
Минимальный пример:
```caddyfile
{
# Включить FrankenPHP
frankenphp
}
localhost {
# Включить сжатие (опционально)
encode zstd br gzip
@@ -59,7 +54,8 @@ localhost {
}
```
Опционально можно указать количество потоков и [worker-скриптов](worker.md), которые запускаются вместе с сервером:
Вы также можете явно настроить FrankenPHP с помощью глобальной опции:
[Глобальная опция](https://caddyserver.com/docs/caddyfile/concepts#global-options) `frankenphp` может быть использована для настройки FrankenPHP.
```caddyfile
{
@@ -92,21 +88,18 @@ localhost {
Вы также можете определить несколько workers, если обслуживаете несколько приложений на одном сервере:
```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>
}
}
# ...
@@ -146,6 +139,14 @@ php_server [<matcher>] {
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.
}
```

View File

@@ -64,8 +64,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 \

View File

@@ -32,7 +32,7 @@ frankenphp php-server --worker /path/to/your/worker/script.php
Следующая команда выполнит перезапуск, если будет изменён любой файл с расширением `.php` в директории `/path/to/your/app/` или её поддиректориях:
```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

View File

@@ -176,7 +176,7 @@ 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. Hata düzeltildiğinde, tüm bu değişiklikleri geri alın

View File

@@ -82,7 +82,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

View File

@@ -1,4 +1,4 @@
# Konfigürasyon
# 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.
@@ -41,16 +41,11 @@ Statik ikili:
## 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.
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
@@ -59,7 +54,8 @@ localhost {
}
```
İ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.
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
{
@@ -91,21 +87,18 @@ Alternatif olarak, `worker` seçeneğinin tek satırlık kısa formunu kullanabi
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 {
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>
}
}
# ...
@@ -145,6 +138,15 @@ php_server [<matcher>] {
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.
}
```

View File

@@ -58,8 +58,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 ve Vulcain resmi yapıya dahil edilmiştir, ancak bunları kaldırmaktan çekinmeyin
--with github.com/dunglas/mercure/caddy \

View File

@@ -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

View File

@@ -588,6 +588,7 @@ static int frankenphp_send_headers(sapi_headers_struct *sapi_headers) {
}
static void frankenphp_sapi_flush(void *server_context) {
sapi_send_headers();
if (go_sapi_flush(thread_index)) {
php_handle_aborted_connection();
}

View File

@@ -19,9 +19,9 @@ package frankenphp
// #cgo CFLAGS: -I/usr/local/include -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib
// #cgo linux CFLAGS: -D_GNU_SOURCE
// #cgo darwin CFLAGS: -I/opt/homebrew/include
// #cgo LDFLAGS: -L/usr/local/lib -L/usr/lib -lphp -ldl -lm -lutil
// #cgo linux LDFLAGS: -lresolv
// #cgo darwin LDFLAGS: -Wl,-rpath,/usr/local/lib -L/opt/homebrew/lib -L/opt/homebrew/opt/libiconv/lib -liconv
// #cgo LDFLAGS: -L/usr/local/lib -L/usr/lib -lphp -lm -lutil
// #cgo linux LDFLAGS: -ldl -lresolv
// #cgo darwin LDFLAGS: -Wl,-rpath,/usr/local/lib -L/opt/homebrew/lib -L/opt/homebrew/opt/libiconv/lib -liconv -ldl
// #include <stdlib.h>
// #include <stdint.h>
// #include <php_variables.h>
@@ -492,6 +492,10 @@ func addHeader(fc *frankenPHPContext, cString *C.char, length C.int) {
func go_write_headers(threadIndex C.uintptr_t, status C.int, headers *C.zend_llist) C.bool {
fc := phpThreads[threadIndex].getRequestContext()
if fc == nil {
return C.bool(false)
}
if fc.isDone {
return C.bool(false)
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 KiB

After

Width:  |  Height:  |  Size: 116 KiB

View File

@@ -27,8 +27,8 @@ import (
"sync"
"testing"
"github.com/dunglas/frankenphp"
"github.com/dunglas/frankenphp/internal/fastabs"
"frankenphp.dev"
"frankenphp.dev/internal/fastabs"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap/exp/zapslog"
@@ -330,7 +330,7 @@ func TestMalformedCookie(t *testing.T) {
runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) {
req := httptest.NewRequest("GET", "http://example.com/cookies.php", nil)
req.Header.Add("Cookie", "foo =bar; ===;;==; .dot.=val ;\x00 ; PHPSESSID=1234")
// Muliple Cookie header should be joined https://www.rfc-editor.org/rfc/rfc7540#section-8.1.2.5
// Multiple Cookie header should be joined https://www.rfc-editor.org/rfc/rfc7540#section-8.1.2.5
req.Header.Add("Cookie", "secondCookie=test; secondCookie=overwritten")
w := httptest.NewRecorder()
handler(w, req)
@@ -1023,6 +1023,22 @@ func testRejectInvalidHeaders(t *testing.T, opts *testOptions) {
}
}
func TestFlushEmptyResponse_module(t *testing.T) { testFlushEmptyResponse(t, &testOptions{}) }
func TestFlushEmptyRespnse_worker(t *testing.T) {
testFlushEmptyResponse(t, &testOptions{workerScript: "only-headers.php"})
}
func testFlushEmptyResponse(t *testing.T, opts *testOptions) {
runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, _ int) {
req := httptest.NewRequest("GET", "http://example.com/only-headers.php", nil)
w := httptest.NewRecorder()
handler(w, req)
resp := w.Result()
assert.Equal(t, 204, resp.StatusCode)
}, opts)
}
// Worker mode will clean up unreferenced streams between requests
// Make sure referenced streams are not cleaned up
func TestFileStreamInWorkerMode(t *testing.T) {

2
go.mod
View File

@@ -1,4 +1,4 @@
module github.com/dunglas/frankenphp
module frankenphp.dev
go 1.24.0

View File

@@ -4,7 +4,7 @@ import (
"log"
"os"
"github.com/dunglas/frankenphp"
"frankenphp.dev"
)
func main() {

View File

@@ -6,7 +6,7 @@ import (
"net/http"
"os"
"github.com/dunglas/frankenphp"
"frankenphp.dev"
)
func main() {

View File

@@ -8,7 +8,7 @@ import (
"path/filepath"
"strings"
"github.com/dunglas/frankenphp/internal/fastabs"
"frankenphp.dev/internal/fastabs"
)
type watchPattern struct {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 6.2 KiB

View File

@@ -1,133 +1,731 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test Page for FrankenPHP</title>
<style>
* {
box-sizing: border-box;
}
html {
height: 100%;
}
body {
background-color: #FAF5F5;
background: #fff;
color: #000;
font-size: 0.9em;
font-family: sans-serif,helvetica;
font-family: sans-serif, helvetica;
margin: 0;
padding: 0;
height: 100%;
}
:link, :visited {
color: #0B2335;
}
a:hover {
color: #0069DA;
}
h1 {
text-align: center;
margin: 0;
padding: 0.6em 2em 0.4em;
background-color: #0B2335;
color: #fff;
font-weight: normal;
font-size: 1.75em;
border-bottom: 2px solid #000;
}
h1 strong {
a {
color: #390075;
font-weight: bold;
}
h2 {
font-size: 1.1em;
font-size: 1.5em;
font-weight: bold;
color: #390075;
}
hr {
display: none;
main {
display: flex;
margin-left: auto;
margin-right: auto;
height: 100%;
}
.content {
padding: 1em 5em;
}
.content-columns {
position: relative;
padding-top: 1em;
}
.content-column-left, .content-column-right {
width: 47%;
float: left;
padding-bottom: 2em;
}
.content-column-left {
padding-right: 3%;
}
.content-column-right {
padding-left: 3%;
}
.logos {
text-align: center;
margin-top: 2em;
}
img {
border: 2px solid #fff;
padding: 2px;
margin: 2px;
}
a:hover img {
border: 2px solid #f50;
}
.footer {
clear: both;
text-align: center;
font-size: xx-small;
flex: 1;
display: flex;
flex-direction: column;
gap: 10px;
padding: 1.5em 3em;
section {
max-width: 600px;
}
}
.runtime-info {
background: #efefef;
padding: 0.5em;
margin-top: 1em;
font-size: 0.85em;
border-left: 3px solid #0B2335;
border-left: 3px solid #390075;
}
.right {
overflow: auto;
flex: 1;
display: flex;
flex-direction: column;
}
.left {
width: 40%;
background: #230143;
color: #fff;
position: relative;
text-align: center;
padding-top: 1em;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 1em;
.logo {
width: 80%;
max-width: 400px;
margin-left: auto;
margin-right: auto;
}
.franky {
width: 80%;
max-width: 400px;
margin-bottom: 1em;
}
}
footer {
border-top: 1px solid #ccc;
font-size: 0.8em;
padding: 1em 3em;
display: flex;
flex-direction: column;
gap: 1em;
.logos {
display: flex;
gap: 12px;
align-items: center;
}
svg {
width: 120px;
}
p {
padding: 0;
margin: 0;
}
}
@media (max-width: 768px) {
main {
flex-direction: column;
}
.right {
overflow: visible;
}
.left {
width: 100%;
flex-direction: row;
padding: 1em;
.logo {
max-width: 250px;
}
.franky {
height: 100px;
width: auto;
}
.logo {
margin: 0;
}
}
.content {
padding: 1em 2em;
}
footer {
padding: 1em 2em;
text-align: center;
margin-top: 1em;
.logos {
justify-content: center;
}
}
}
</style>
</head>
<body>
<header>
<h1>FrankenPHP <strong>Test Page</strong></h1>
</header>
<main>
<div class="left">
<h1 class="logo">
<svg xmlns="http://www.w3.org/2000/svg" id="logo" viewBox="0 0 699.37 92.29">
<defs fill="#000000">
<style>
.logo_b {
fill: #fff;
}
<main class="content">
<div class="content-columns">
<section class="content-column-left">
<h2>If you are a member of the general public:</h2>
.c {
fill: #b3d133;
}
</style>
</defs>
<path class="c"
d="M22.65,38.71h20.32c3.02,0,5.65,1.1,7.89,3.3,2.24,2.2,3.36,4.85,3.36,7.96s-1.12,5.67-3.36,7.96c-2.24,2.29-4.96,3.43-8.15,3.43H22.65v19.8c0,3.45-1.12,6.17-3.37,8.15-2.24,1.99-4.88,2.98-7.89,2.98s-5.78-.99-8.02-2.98c-2.24-1.98-3.37-4.7-3.37-8.15V20.2c0-3.45,.86-6.64,2.59-9.58,1.72-2.93,4.03-5.26,6.92-6.99,2.89-1.72,6.06-2.59,9.51-2.59h28.86c3.19,0,5.89,1.1,8.09,3.3,2.2,2.2,3.3,4.81,3.3,7.83s-1.14,5.8-3.43,8.09c-2.29,2.29-4.94,3.43-7.96,3.43H22.65v15.01Z"
fill="#000000" />
<path class="c"
d="M118.29,54.76c3.88,2.42,6.66,5.18,8.35,8.28,1.68,3.11,2.52,6.77,2.52,11v6.6c0,3.11-1.08,5.76-3.24,7.96-2.16,2.2-4.75,3.3-7.77,3.3s-5.74-1.12-7.89-3.36c-2.16-2.24-3.24-4.87-3.24-7.89v-6.34l-22.13-26.92v33.26c0,3.11-1.08,5.76-3.24,7.96-2.16,2.2-4.79,3.3-7.89,3.3s-5.89-1.1-8.09-3.3c-2.2-2.2-3.3-4.85-3.3-7.96V12.44c0-3.19,1.1-5.89,3.3-8.09s4.9-3.3,8.09-3.3h25.24c5.09,0,9.62,1.86,13.59,5.57l11,10.61c4.05,4.06,6.08,8.72,6.08,13.98v5.05c0,8.54-3.8,14.71-11.39,18.51Zm-33.39-9.32h22.13V23.7h-22.13v21.74Z"
fill="#000000" />
<path class="c"
d="M270.74,88.54c-2.16,2.24-4.83,3.36-8.02,3.36s-6-1.12-8.15-3.36c-2.16-2.24-3.24-4.96-3.24-8.15V23.57h-20.84v57.07c0,3.19-1.12,5.87-3.37,8.02-2.24,2.16-4.96,3.24-8.15,3.24s-5.76-1.1-7.96-3.3c-2.2-2.2-3.3-4.85-3.3-7.96V12.05c0-3.19,1.12-5.89,3.37-8.09,2.24-2.2,4.87-3.3,7.89-3.3,3.19,0,5.91,1.1,8.15,3.3,2.24,2.2,3.37,4.9,3.37,8.09v3.75c0,.43,.08,.65,.26,.65s.26-.08,.26-.26c1.55-5,4.12-8.8,7.7-11.39,3.58-2.59,7.87-3.88,12.88-3.88,6.47,0,11.82,1.92,16.05,5.76,4.23,3.84,6.34,8.99,6.34,15.47v58.24c0,3.19-1.08,5.91-3.24,8.15Z"
fill="#000000" />
<path class="c"
d="M347.1,80.64c0,3.11-1.14,5.78-3.43,8.02-2.29,2.24-4.98,3.37-8.09,3.37s-5.8-1.12-8.09-3.37c-2.29-2.24-3.43-4.92-3.43-8.02v-24.72l-22.13-.26v24.98c0,3.19-1.1,5.89-3.3,8.09s-4.9,3.3-8.09,3.3-5.89-1.1-8.09-3.3-3.3-4.9-3.3-8.09V11.66c0-3.02,1.1-5.63,3.3-7.83,2.2-2.2,4.9-3.3,8.09-3.3s5.89,1.08,8.09,3.24c2.2,2.16,3.3,4.79,3.3,7.89V53.72l22.13-27.31V11.66c0-3.02,1.14-5.63,3.43-7.83,2.29-2.2,4.94-3.3,7.96-3.3s5.63,1.1,7.83,3.3c2.2,2.2,3.3,4.81,3.3,7.83v15.14c0,4.32-.84,8.05-2.52,11.19-1.68,3.15-4.51,5.98-8.48,8.48,7.68,3.62,11.52,9.79,11.52,18.51v15.66Z"
fill="#000000" />
<path class="c"
d="M374.66,35.6h25.24c3.11,0,5.76,1.1,7.96,3.3,2.2,2.2,3.3,4.9,3.3,8.09,0,3.02-1.12,5.65-3.37,7.89-2.24,2.24-4.88,3.36-7.89,3.36h-25.24v10.87h27.44c3.11,0,5.76,1.1,7.96,3.3,2.2,2.2,3.3,4.9,3.3,8.09,0,3.02-1.1,5.61-3.3,7.77-2.2,2.16-4.85,3.32-7.96,3.49h-31.19c-3.37,0-6.49-.86-9.38-2.59-2.89-1.73-5.2-4.05-6.92-6.99-1.73-2.93-2.59-6.12-2.59-9.58v-6.99c0-5.26,.73-9.55,2.2-12.88,1.47-3.32,4.49-5.76,9.06-7.31-4.32-1.47-7.27-3.77-8.87-6.92-1.6-3.15-2.39-7.23-2.39-12.23v-6.08c0-3.45,.86-6.64,2.59-9.58,1.73-2.93,4.03-5.26,6.92-6.99,2.89-1.72,6.02-2.59,9.38-2.59h31.19c3.11,0,5.76,1.1,7.96,3.3s3.3,4.81,3.3,7.83-1.12,5.8-3.37,8.09c-2.24,2.29-4.88,3.43-7.89,3.43h-27.44v11.91Z"
fill="#000000" />
<path class="c"
d="M480.4,88.54c-2.16,2.24-4.83,3.36-8.02,3.36s-6-1.12-8.15-3.36c-2.16-2.24-3.24-4.96-3.24-8.15V23.57h-20.84v57.07c0,3.19-1.12,5.87-3.37,8.02-2.24,2.16-4.96,3.24-8.15,3.24s-5.76-1.1-7.96-3.3c-2.2-2.2-3.3-4.85-3.3-7.96V12.05c0-3.19,1.12-5.89,3.37-8.09,2.24-2.2,4.87-3.3,7.89-3.3,3.19,0,5.91,1.1,8.15,3.3,2.24,2.2,3.37,4.9,3.37,8.09v3.75c0,.43,.08,.65,.26,.65s.26-.08,.26-.26c1.55-5,4.12-8.8,7.7-11.39,3.58-2.59,7.87-3.88,12.88-3.88,6.47,0,11.82,1.92,16.05,5.76,4.23,3.84,6.34,8.99,6.34,15.47v58.24c0,3.19-1.08,5.91-3.24,8.15Z"
fill="#000000" />
<path class="logo_b"
d="M511.07,80.25c0,3.19-1.06,5.91-3.17,8.15-2.12,2.24-4.72,3.37-7.83,3.37s-5.78-1.12-8.02-3.37c-2.24-2.24-3.37-4.96-3.37-8.15V20.07c0-3.45,.86-6.64,2.59-9.58,1.73-2.93,4.05-5.26,6.99-6.99,2.93-1.72,6.12-2.59,9.58-2.59h17.21c5.09,0,9.53,1.77,13.33,5.31l12.42,12.42c1.81,1.73,3.17,3.97,4.08,6.73,.91,2.76,1.36,5.74,1.36,8.93,0,3.71-.58,7.29-1.75,10.74-1.16,3.45-2.78,6.17-4.85,8.15l-11.26,10.74c-3.62,3.62-8.07,5.44-13.33,5.44h-13.98v10.87Zm21.74-56.69l-21.48-.26v23.42h21.48V23.57Z"
fill="#000000" />
<path class="logo_b"
d="M560.11,11.92c0-3.45,1.12-6.17,3.37-8.15,2.24-1.98,4.92-2.98,8.02-2.98s5.76,.97,7.96,2.91c2.2,1.94,3.3,4.64,3.3,8.09v28.47h21.35V11.92c0-3.45,1.14-6.17,3.43-8.15,2.29-1.98,4.98-2.98,8.09-2.98s5.76,.97,7.96,2.91,3.3,4.64,3.3,8.09V81.16c0,3.45-1.12,6.17-3.37,8.15-2.24,1.99-4.92,2.98-8.02,2.98s-5.78-.99-8.02-2.98c-2.24-1.98-3.37-4.7-3.37-8.15V43.5l-21.35,19.28v18.38c0,3.45-1.12,6.17-3.36,8.15-2.24,1.99-4.88,2.98-7.89,2.98s-5.78-.99-8.02-2.98c-2.24-1.98-3.37-4.7-3.37-8.15V11.92Z"
fill="#000000" />
<path class="logo_b"
d="M654.2,80.25c0,3.19-1.06,5.91-3.17,8.15-2.12,2.24-4.72,3.37-7.83,3.37s-5.78-1.12-8.02-3.37c-2.24-2.24-3.37-4.96-3.37-8.15V20.07c0-3.45,.86-6.64,2.59-9.58,1.73-2.93,4.05-5.26,6.99-6.99,2.93-1.72,6.12-2.59,9.58-2.59h17.21c5.09,0,9.53,1.77,13.33,5.31l12.42,12.42c1.81,1.73,3.17,3.97,4.08,6.73,.91,2.76,1.36,5.74,1.36,8.93,0,3.71-.58,7.29-1.75,10.74-1.16,3.45-2.78,6.17-4.85,8.15l-11.26,10.74c-3.62,3.62-8.07,5.44-13.33,5.44h-13.98v10.87Zm21.74-56.69l-21.48-.26v23.42h21.48V23.57Z"
fill="#000000" />
<g>
<path class="c"
d="M142.76,32.66v-3.51c0-1.32,1.04-2.4,2.32-2.4,1.29,0,2.33,1.07,2.33,2.39v3.51l7.92-.02v-3.51c0-1.32,1.04-2.4,2.32-2.4,1.29,0,2.33,1.07,2.33,2.39v3.51h6.64v-3.53c0-1.32,1.03-2.4,2.32-2.4s2.33,1.07,2.33,2.39v3.51h6.83v-3.53c0-1.32,1.03-2.4,2.32-2.4,1.29,0,2.33,1.07,2.33,2.39v3.51l7.69-.02v-3.51c0-1.32,1.03-2.4,2.32-2.4s2.33,1.07,2.33,2.39v3.51h6.89v-.85c-.17-3.02-.89-5.52-2.14-7.51-1.25-1.98-3.22-4.1-5.89-6.34l-16.95-13.85c-3.19-2.67-6.13-4.01-8.8-4.01s-5.61,1.34-9.06,4.01l-16.57,13.85c-2.68,2.33-4.66,4.49-5.95,6.47-1.29,1.99-2.07,4.44-2.33,7.38v.97l8.46-.02Z"
fill="#000000" />
<path class="c"
d="M195.11,37.2v3.5c0,1.32-1.03,2.4-2.32,2.4s-2.33-1.07-2.33-2.39v-3.5l-7.69,.02v3.5c0,1.32-1.03,2.4-2.32,2.4s-2.33-1.07-2.33-2.39v-3.5h-6.83v3.51c0,1.32-1.04,2.4-2.32,2.4-1.29,0-2.33-1.07-2.33-2.39v-3.5h-6.64v3.51c0,1.32-1.03,2.4-2.32,2.4-1.29,0-2.33-1.07-2.33-2.39v-3.5l-7.92,.02v3.5c0,1.32-1.03,2.4-2.32,2.4-1.29,0-2.33-1.07-2.33-2.39v-3.5l-8.47,.02v43.43c0,3.11,1.12,5.74,3.37,7.89,2.24,2.16,4.92,3.24,8.02,3.24s5.76-1.08,7.96-3.24c2.2-2.16,3.3-4.79,3.3-7.89v-31.84l22.52,20.84v11c0,3.11,1.1,5.74,3.3,7.89,2.2,2.16,4.9,3.24,8.09,3.24s5.74-1.08,7.9-3.24,3.24-4.79,3.24-7.89V37.19h-6.88Z"
fill="#000000" />
</g>
</svg>
<span>Test page</span>
</h1>
<svg class="franky" xmlns="http://www.w3.org/2000/svg" id="Calque_1" class="franky"
viewBox="0 0 668.77 742.85">
<defs>
<style>
.cls-1 {
fill: #010101
}
<p>The fact that you are seeing this page indicates that the website you just visited is either experiencing problems, or is undergoing routine maintenance.</p>
.cls-3 {
fill: #fff
}
<p>
If you would like to let the administrators of this website know that you've seen this page instead of the page you expected, you should send them e-mail.
In general, mail sent to the name "webmaster" and directed to the website's domain should reach the appropriate person.
</p>
.cls-4 {
fill: #feffff
}
<p>For example, try contacting <a href="mailto:webmaster@<?php echo $_SERVER['SERVER_NAME'] ?? 'example.com'; ?>">webmaster@<?php echo $_SERVER['SERVER_NAME'] ?? 'example.com'; ?></a>.</p>
.cls-7 {
fill: #b3cd38
}
<p>Learn more about FrankenPHP at the <a href="https://frankenphp.dev/">official website</a>.</p>
</section>
.cls-8 {
fill: #c3b2d3
}
<section class="content-column-right">
<h2>If you are the website administrator:</h2>
.cls-9 {
fill: #38276b
}
<p>Your server is running and serving requests using FrankenPHP, powered by Caddy</p>
.cls-10 {
fill: rgba(255, 255, 255, .6)
}
<p>To replace this page, deploy your application files to <code><?php echo getcwd(); ?></code>.</p>
.cls-11 {
fill: rgba(1, 1, 1, .19)
}
<p>Configuration is handled in your <code>Caddyfile</code>.</p>
.cls-12 {
opacity: .15
}
<div class="runtime-info">
<strong>Served by PHP SAPI: </strong> <?php echo php_sapi_name(); ?><br />
</div>
.cls-13 {
opacity: .19
}
.cls-14,
.cls-15 {
opacity: .3
}
.cls-20 {
opacity: .5
}
.cls-21 {
opacity: .7
}
</style>
</defs>
<path
d="m322.04 433.86-20.02 54.01s-102.75-3.02-160.97-43.78c9.22.24 20.68-2.07 26.69-13.28 10.15-18.96 34.85-56.38 66.66-61.26-1.05 2.76-1.54 5.53-1.32 8.35 2.52 30.64 88.97 55.96 88.97 55.96"
class="cls-7" />
<path
d="M566.16 490.35s-6.54-45.67 23.34-42.26c29.88 3.41 39.28-9.25 39.28-9.25s1.43 54.68-25.6 63.63c-19.28 6.39-31.15-8.29-31.15-8.29"
class="cls-9" />
<path
d="M628.74 443.89c-4.52 6.07-15.63 16.6-37.19 14.14-21.33-2.44-24.11 20.15-23.95 33.27l-1.44-.94s-6.55-45.67 23.33-42.26c29.89 3.4 39.28-9.25 39.28-9.25s.06 1.9-.04 5.05Z"
class="cls-3" style="opacity:.35" />
<g class="cls-12">
<path
d="M603.18 502.46c-19.29 6.39-31.15-8.29-31.15-8.29l-5.86-3.82s-1.31-9.19-.08-19.02c3.82 5.08 10.79 11.09 22.42 11.45 18.84.58 32.85-21.94 40.16-37.22-.62 14.88-4.34 49.89-25.49 56.9Z"
class="cls-9" />
</g>
<path
d="M593.47 508.95c-15.51 0-24.74-11.15-25.21-11.73-.53-.65-.86-1.39-1-2.16-.14.03-.28.06-.42.08-2.65.39-5.1-1.46-5.47-4.1-.17-1.16-3.91-28.48 8.59-41.34 5.05-5.2 11.83-7.36 20.09-6.41 26.23 2.99 34.81-7.3 34.89-7.4 1.23-1.66 3.35-2.32 5.32-1.7 1.97.62 3.3 2.46 3.35 4.53.06 2.38 1.18 58.39-28.92 68.36-4.03 1.34-7.78 1.88-11.23 1.88Zm-21.45-19.61c1.41 0 2.81.61 3.77 1.8.39.47 10.13 11.94 25.86 6.74 15.92-5.27 20.97-32.15 22.06-49.42-6.77 3.38-17.84 6.38-34.76 4.45-5.21-.6-9.15.56-12.04 3.53-7.55 7.76-6.9 26.26-5.98 33.03.36-.08.73-.13 1.1-.13Z"
class="cls-9" />
<path
d="M260.37 518.13s-82.72-10.58-105.81 55.88c-20.99 60.42 37.01 110.5 37.01 110.5s-26.58 3.88-29.71 22.63c-3.11 18.67 6.99 37.47 87.19 27.57 47.73-5.89 24.18-79.93 24.18-88.84s52.1-15.84 124.98-35.65c12.28-3.34-137.84-92.09-137.84-92.09"
class="cls-7" />
<path
d="M210.7 742.24c-23.85 0-39.54-4.17-47.6-12.58-5.59-5.84-7.62-13.68-6.01-23.32 2.41-14.45 15.73-21.33 24.91-24.4-5.51-5.75-13.69-15.26-20.97-27.58-16.28-27.52-20.1-55.86-11.04-81.95 10.01-28.81 32.48-48.16 65-55.97 24.15-5.8 45.11-3.22 45.99-3.11.65.08 1.28.3 1.84.63.35.21 35.39 20.93 69.83 42.47 72.21 45.16 71.62 49.53 71.05 53.76-.31 2.26-1.92 4.05-4.23 4.67-26.69 7.25-50.78 12.83-70.14 17.31-24.09 5.57-46.9 10.85-51.2 14.49.19 1.49.74 4.32 1.24 6.87 3.27 16.86 10.07 51.93-4.41 71.87-5.8 7.99-14.32 12.73-25.31 14.08-14.8 1.83-27.77 2.74-38.94 2.74Zm37.22-219.89c-7.96 0-19.13.68-30.95 3.55-29.42 7.14-48.89 23.86-57.86 49.68-19.65 56.55 35.05 104.78 35.6 105.26 1.43 1.24 2 3.19 1.47 5.01a4.827 4.827 0 0 1-3.94 3.42c-.22.03-23.14 3.63-25.64 18.65-1.11 6.66-.01 11.44 3.46 15.06 6.49 6.77 25.37 13.48 78.39 6.93 8.34-1.03 14.45-4.36 18.68-10.18 12.02-16.55 5.76-48.84 2.75-64.36-1-5.16-1.48-7.72-1.48-9.52 0-9.09 13.15-12.54 58.75-23.09 17.79-4.12 39.59-9.16 63.68-15.57-15.59-13.32-76.22-51.37-132.02-84.38-1.7-.16-5.58-.47-10.89-.47Z"
class="cls-9" />
<path
d="M194.35 680.56s-.11-.07-.1-.06l.03.03s.02.03.08.06l.25.18c.22.13.4.26.65.39.46.26.98.51 1.51.76 1.08.47 2.21.93 3.4 1.31 2.37.78 4.86 1.45 7.42 1.96 2.55.54 5.15.93 7.78 1.29l3.96.44 3.99.34h.07c1.33.12 2.32 1.29 2.21 2.62a2.414 2.414 0 0 1-2.25 2.21l-4.13.27-4.15.16c-2.77.04-5.57.04-8.39-.13a68.18 68.18 0 0 1-8.54-.94c-1.44-.24-2.9-.58-4.38-.98-.75-.22-1.49-.44-2.27-.73-.38-.13-.79-.31-1.19-.47l-.64-.3c-.1-.04-.24-.12-.36-.19l-.19-.1-.31-.2a4.826 4.826 0 0 1-1.16-6.73 4.826 4.826 0 0 1 6.73-1.16"
class="cls-9" />
<g class="cls-14">
<path
d="M394.99 611.86c-71.84 19.52-123.2 26.36-123.2 35.14 0 3.23 3.14 15.15 4.78 29.22 2.79 24.18 1.13 54.69-28.61 58.37-79.06 9.75-89.02-8.79-85.95-27.18.26-1.57.7-3.03 1.27-4.4 3.46 6.68 13.39 18.52 40.32 19.15 45.29 1.08 60.21-9.6 61.7-26.37 1.63-18.18-11.24-54.29-20.85-70.96-15.63-27.09-40.53-49.67-30.69-88.81 1.32-5.21 4.3-9.64 8.52-13.39 20.28-3.67 36.84-1.55 36.84-1.55s147.99 87.49 135.89 90.78"
class="cls-1" />
</g>
<path
d="M484.61 526.42s40.06 5.29 63.65-22.27c25.82-30.17 43.37-28.78 44.75-20.41 1.38 8.37-13.05 12.94-25.66 37.79-11.87 23.39-27.73 43.79-64.39 39.02"
class="cls-7" />
<g class="cls-12">
<path
d="M567.35 521.54c-11.88 23.4-27.74 43.8-64.4 39.02l-18.35-34.13s2.79.37 7.31.41l1.88 6.4c34.89 12.24 54.62-4.44 71.08-24.86 11.68-14.52 22.29-19.99 28.14-24.57 1.31 8.34-13.09 12.95-25.67 37.74"
class="cls-1" />
</g>
<path
d="M513.16 566.07c-3.42 0-7.01-.23-10.82-.73a4.816 4.816 0 0 1-4.16-5.41c.34-2.64 2.77-4.52 5.41-4.16 31.92 4.16 46.85-11.55 59.47-36.42 6.88-13.55 14.16-21.23 19.47-26.84 3.83-4.04 5.99-6.4 5.73-7.98-.04-.23-.11-.65-1.15-.94-4.15-1.16-16.84 2.3-35.16 23.7-25.01 29.22-66.21 24.15-67.95 23.92a4.83 4.83 0 0 1-4.15-5.42c.35-2.64 2.77-4.51 5.41-4.15.38.05 37.8 4.56 59.36-20.62 17.01-19.87 33.86-29.85 45.09-26.72 4.37 1.22 7.39 4.46 8.08 8.67 1.05 6.38-3.05 10.71-8.24 16.19-4.91 5.18-11.63 12.27-17.87 24.57-10.78 21.25-26.18 42.35-58.5 42.35Z"
class="cls-9" />
<path
d="M622.64 301.98c-52 39.58-118.56 71.02-150.03 84.84-11.26 4.95-18.03 7.64-18.03 7.64l-.58-2.45-6.82-28.71-17.11-72.15-1.42-5.99c9.26-2.27 21.56-7.18 35.67-13.53 57.2-25.73 143.96-74.98 176.39-66.94 8.28 2.05 21.03 13.36 22.97 30.74 1.94 17.25-6.76 40.47-41.03 66.55"
class="cls-7" />
<g class="cls-20">
<path
d="M663.69 244.42c-.01-.06-.01-.13-.02-.19-1.94-17.38-14.69-28.69-22.97-30.74-39.88-9.88-161.87 66.83-210.08 79.96l-1.97-8.29c46.78-11.49 171.62-90.49 212.05-80.47 8.28 2.05 21.03 13.36 22.97 30.74.33 2.84.35 5.84.02 8.99"
class="cls-3" />
</g>
<g class="cls-14">
<path
d="M622.64 301.98c-70.6 53.74-168.06 92.48-168.06 92.48l-.58-2.45 4.47-41.31s81.64-5.72 136.45-41.2c40.93-26.51 60.98-53.65 68.75-74.06 1.94 17.25-6.76 40.47-41.03 66.55"
class="cls-1" />
</g>
<path
d="M454.58 399.29c-1.92 0-3.74-1.15-4.49-3.05-.98-2.48.23-5.29 2.7-6.27.97-.38 97.69-39.14 166.93-91.83 29.07-22.12 42.79-45.34 38.65-65.36-2.79-13.48-12.88-21.93-18.83-23.41-23.32-5.78-82.61 23.06-130.24 46.22-31.46 15.3-61.17 29.75-79.5 34.25-2.6.64-5.2-.95-5.84-3.54-.64-2.59.95-5.2 3.54-5.84 17.34-4.26 46.6-18.49 77.58-33.56 54.11-26.31 110.07-53.52 136.79-46.91 10.01 2.48 22.51 14.12 25.97 30.82 3.49 16.88-1 43.6-42.26 75-70.31 53.51-168.23 92.73-169.21 93.12-.58.23-1.19.34-1.78.34Z"
class="cls-9" />
<path
d="M481.95 613.06c-33.16 17.95-86.73 25.72-142.28 25.71-26.32 0-84.93-4.73-112.44-65.49-20.27-44.75-.28-76.35 5.02-144.97.04-.48.07-.97.11-1.45 0 0 106.53-124.29 165.69-138.2 13.43-3.16 23.89-1.69 32.01 2.49 27.66 14.17 28.4 59.55 28.4 59.55.12.31.24.63.36.95 4.12 10.69 8.8 22.59 13.78 35.17 15.56 39.21 34.06 85.09 47.55 121.94 14.83 40.57-3.54 85.5-38.21 104.29"
class="cls-7" />
<path
d="M481.95 613.06c-33.16 17.95-86.73 25.72-142.28 25.71-21.85 0-65.95-3.26-96.03-39.12 29.18 21.18 63.4 23.45 82.12 23.45 58.5.01 114.93-8.17 149.84-27.08 29.37-15.9 47.62-49.59 45.54-84.38 12.97 39.79-5.35 83.08-39.2 101.42"
class="cls-11" />
<path
d="M460.72 349.83c13.01 27.24 24.39 55.13 35.49 83.17 5.58 14.01 11.13 28.03 16.59 42.11 2.73 7.04 5.43 14.09 8.09 21.16l3.96 10.62 1.81 5.7c.29.96.63 1.9.87 2.86l.63 2.93c1.9 7.76 2.42 15.82 2.13 23.77-.2 7.99-1.81 15.88-4.09 23.5-2.24 7.66-5.77 14.9-9.94 21.69-4.13 6.84-9.39 12.99-15.27 18.42l-2.24 2.02-1.12 1.01c-.38.33-.8.61-1.19.92l-4.83 3.61c-1.67 1.12-3.42 2.12-5.13 3.18-.86.5-1.71 1.1-2.59 1.51l-2.63 1.33c-3.48 1.86-7.09 3.32-10.66 4.91-3.64 1.36-7.24 2.86-10.93 4.01-14.68 4.94-29.72 8.22-44.83 10.56-15.11 2.35-30.31 3.82-45.51 4.58-7.6.37-15.21.64-22.81.7-7.54.12-15.38.07-23.11-.63-15.49-1.34-30.99-4.86-45.41-11.37-7.19-3.27-14.07-7.29-20.44-12.01-6.39-4.71-12.18-10.22-17.33-16.24-5.15-6.03-9.62-12.6-13.38-19.51-.94-1.73-1.89-3.45-2.7-5.24-.83-1.78-1.75-3.51-2.44-5.37l-2.21-5.5-.55-1.38c-.16-.47-.3-.95-.45-1.42l-.87-2.85-.87-2.85-.43-1.42-.32-1.46-1.24-5.84c-.24-.97-.35-1.96-.46-2.95l-.37-2.96-.36-2.96c-.13-.99-.11-1.98-.17-2.96l-.24-5.93.15-5.89c0-1.97.21-3.9.37-5.84.19-1.93.28-3.89.54-5.8 1.84-15.35 5.01-30.12 7.52-44.87 2.58-14.74 4.62-29.5 5.81-44.35a4.83 4.83 0 0 1 5.2-4.44c2.64.21 4.62 2.51 4.43 5.15-1.08 15.21-3.01 30.36-5.51 45.33-2.47 14.97-5.54 29.72-7.2 44.32-1.59 14.56-1.24 29.03 3.23 42.6l.79 2.55c.14.42.25.85.4 1.27l.51 1.24 2.03 4.98c.62 1.68 1.49 3.27 2.26 4.9.76 1.64 1.63 3.21 2.5 4.79 3.48 6.3 7.53 12.24 12.17 17.67 4.65 5.42 9.85 10.36 15.59 14.59a101.9 101.9 0 0 0 18.47 10.83c13.09 5.9 27.39 9.18 41.9 10.42 7.28.66 14.53.7 22.06.58 7.47-.07 14.92-.33 22.37-.7 14.89-.76 29.74-2.21 44.41-4.49l5.5-.88 5.47-1.01c3.66-.62 7.25-1.48 10.87-2.23 7.18-1.7 14.34-3.51 21.27-5.88 3.51-1.07 6.88-2.47 10.31-3.73 3.32-1.47 6.71-2.81 9.89-4.51l2.42-1.21c.83-.38 1.52-.89 2.29-1.33 1.49-.92 3.03-1.77 4.49-2.75l4.24-3.14c.35-.27.72-.51 1.05-.79l.98-.88 1.97-1.76c5.18-4.75 9.86-10.15 13.54-16.21 3.71-6.01 6.91-12.42 8.91-19.24 2.05-6.77 3.54-13.78 3.73-20.88.27-7.07-.14-14.21-1.81-21.1l-.55-2.6c-.21-.86-.51-1.69-.77-2.54l-1.58-5.08-3.89-10.57c-2.62-7.04-5.28-14.08-7.97-21.1-5.38-14.05-10.86-28.08-16.37-42.09-11.07-28.01-22.26-56.02-30.93-85.03-.38-1.28.35-2.63 1.62-3.01 1.16-.35 2.38.21 2.88 1.27Z"
class="cls-9" />
<path
d="M511.48 499.78c22.09 38.73 74.9 175.05 91.89 181.82 23.59 9.4 58.1 48.69-39.78 55.83-79.01 5.77-96.14-97-132.6-127.66"
class="cls-7" />
<path
d="M563.58 737.44c-79 5.77-96.12-96.99-132.6-127.66 0 0 21.51 4.44 50.19 51.58 18.31 30.09 51.97 58.16 86.66 55.63 32.63-2.39 50.54-8.34 59.06-15.56 7.36 14.45-2.02 31.53-63.32 36"
class="cls-1" style="opacity:.25" />
<path d="M511.41 491c-1.16-2.37 5.21-.45 6.52 1.83" class="cls-9" />
<path
d="M517.93 492.82c2.79 4.87 5.26 9.75 7.65 14.67 2.38 4.91 4.69 9.84 6.92 14.78 4.47 9.89 8.77 19.82 13.04 29.75 8.52 19.87 16.95 39.74 25.54 59.48 4.31 9.87 8.68 19.69 13.26 29.37 2.29 4.84 4.64 9.64 7.07 14.36 2.44 4.7 4.98 9.36 7.72 13.67 1.37 2.14 2.82 4.22 4.27 5.87.7.81 1.49 1.55 1.86 1.76l.07.06h.02l.11.06.26.11.52.22c.69.31 1.41.58 2.07.92 5.4 2.6 10.29 5.91 14.71 9.98 2.22 2.02 4.25 4.33 6.09 6.87 1.84 2.53 3.43 5.46 4.4 8.81.99 3.32 1.23 7.19.28 10.85-.28.89-.52 1.81-.88 2.66-.4.82-.81 1.64-1.23 2.45-.45.78-.99 1.46-1.5 2.19-.5.75-1.08 1.35-1.66 1.96-4.7 4.89-10.2 7.65-15.57 9.81-5.42 2.1-10.89 3.64-16.36 4.82-10.95 2.39-21.9 3.54-32.85 4.34-11.39.77-23.13-.69-34.01-4.72-5.38-2.12-10.62-4.64-15.38-7.85-2.46-1.5-4.69-3.28-6.97-5-1.16-.84-2.17-1.84-3.26-2.75-1.05-.95-2.18-1.82-3.16-2.84-8.18-7.82-15.15-16.62-21.27-25.79-6.15-9.16-11.62-18.64-16.87-28.12l-7.75-14.22c-2.53-4.73-5.09-9.44-7.71-14.05-2.64-4.6-5.3-9.18-8.27-13.49-2.92-4.34-6.09-8.47-9.67-12.2l-.04-.04c-.93-.96-.9-2.5.07-3.42.85-.82 2.15-.89 3.08-.23 4.65 3.28 8.59 7.36 12.23 11.58 1.82 2.13 3.48 4.33 5.15 6.55.83 1.11 1.59 2.25 2.38 3.38.8 1.13 1.57 2.27 2.32 3.42.75 1.15 1.52 2.28 2.25 3.44l2.15 3.49c1.44 2.32 2.82 4.66 4.21 7l8.03 14.07c5.27 9.37 10.66 18.58 16.6 27.32 5.9 8.76 12.5 16.92 19.98 23.99.9.93 1.92 1.7 2.87 2.55.99.81 1.91 1.72 2.94 2.45 2.04 1.51 4.03 3.11 6.21 4.4 4.21 2.82 8.78 4.95 13.44 6.77 9.42 3.4 19.55 4.64 29.7 3.91 10.57-.83 21.15-2.03 31.29-4.31 5.07-1.13 10.01-2.57 14.65-4.39 4.6-1.82 8.9-4.26 11.66-7.23 1.39-1.47 2.38-3.01 2.73-4.6.4-1.58.34-3.28-.19-5.12-.52-1.83-1.5-3.76-2.83-5.58-1.33-1.82-2.86-3.61-4.64-5.22-3.51-3.26-7.66-6.07-11.98-8.15-.54-.28-1.09-.48-1.63-.73l-.95-.42c-.3-.14-.6-.29-.89-.44l-.44-.24-.35-.23c-1.91-1.26-3.02-2.48-4.1-3.69-2.11-2.41-3.72-4.8-5.27-7.2-3.05-4.8-5.67-9.65-8.2-14.53-2.51-4.88-4.9-9.78-7.23-14.7-4.64-9.85-9.04-19.75-13.37-29.68-8.65-19.85-24.55-59.57-24.55-59.57l-25.24-56.42 6.45-6.96Z"
class="cls-9" />
<g style="opacity:.4">
<ellipse cx="304.82" cy="532.72" rx="66.87" ry="81.46" style="fill:#eeeff3"
transform="rotate(-10.12 304.677 532.525)" />
</g>
<path
d="M478.89 267.79s-66.49 20.77-66.64 21.09c-28.79 63.49 93.81 118.78 93.81 118.78s-63.19-90.07-27.18-139.87Z"
class="cls-3" />
<g class="cls-13">
<path
d="M415.22 287.79s.52-.21 1.42-.51c-3.71 39.9 46.24 74.77 76.22 91.96 8.48 16.38 16.17 27.34 16.17 27.34s-122.6-55.29-93.81-118.78Z"
class="cls-1" />
</g>
<path
d="m517.46 417.09-13-5.86c-.8-.36-19.88-9.02-41.42-23.53-12.7-8.55-23.58-17.36-32.34-26.18-11.12-11.19-18.87-22.46-23.03-33.51-5.26-13.94-4.92-27.65 1.02-40.75.71-1.57 1.96-2 3.07-2.37.51-.17 1.25-.42 2.19-.73 1.75-.57 4.3-1.39 7.6-2.44 5.54-1.76 13.25-4.2 22.91-7.24 16.45-5.17 33.1-10.37 33.27-10.43l11.23-3.51-6.9 9.54c-7.68 10.61-11.11 24.19-10.21 40.36.74 13.25 4.36 28.23 10.77 44.53 11 27.98 26.5 50.22 26.66 50.44l8.19 11.68Zm-102.29-125.1c-4.41 10.68-4.48 21.86-.18 33.25 8.62 22.85 33.21 43.01 52.32 55.9 10.43 7.03 20.42 12.72 27.84 16.68-5.65-9.44-13.41-23.67-19.82-39.98-6.71-17.08-10.51-32.88-11.29-46.96-.77-13.77 1.35-25.93 6.31-36.31-22.09 6.91-48.71 15.28-55.18 17.43Z"
class="cls-9" />
<path
d="M169.61 365.65s66.34-21.26 66.64-21.09c60.08 35.37-8.4 151.13-8.4 151.13s-.12-110.02-58.23-130.04Z"
class="cls-3" />
<g class="cls-13">
<path
d="M233.19 345.39s-.54.13-1.45.4c25.99 30.5 5.19 87.76-9.45 119.07 2.48 18.28 2.5 31.66 2.5 31.66s68.48-115.75 8.4-151.13Z"
class="cls-1" />
</g>
<path
d="m223.95 509.97-.02-14.27c0-.27-.12-27.51-7.25-56.73-4.14-16.99-9.8-31.3-16.81-42.54-8.56-13.71-19.16-22.82-31.53-27.08l-11.13-3.83 11.21-3.59c.17-.05 16.78-5.38 33.21-10.61 9.65-3.07 17.36-5.52 22.91-7.26 3.3-1.04 5.86-1.84 7.62-2.37.94-.29 1.69-.51 2.21-.66 1.12-.33 2.39-.69 3.87.18 12.39 7.3 20.56 18.31 24.28 32.74 2.95 11.43 3.09 25.11.44 40.66-2.09 12.25-5.93 25.71-11.39 40.02-9.27 24.25-19.9 42.31-20.34 43.07l-7.26 12.28ZM180.5 366.28c10.02 5.64 18.75 14.37 26.05 26.07 7.46 11.97 13.44 27.08 17.77 44.91 4.14 17.04 5.98 33.13 6.79 44.11 3.8-7.51 8.69-17.91 13.18-29.66 8.22-21.54 16.74-52.17 10.64-75.82-3.04-11.79-9.52-20.89-19.27-27.09-6.53 1.97-33.12 10.43-55.16 17.48Z"
class="cls-9" />
<path
d="M395.02 59.33s26.76-42.86 58.49-52.9 60.14 10.55 71.13 50.87c10.98 40.31 7.58 76.3 17.7 102.68 10.12 26.38 51.11 53.06 31.65 88.8-19.46 35.74-42.07 55.92-87.69 52.01-45.62-3.91-126.77-17.28-126.77-17.28l35.49-224.18Z"
class="cls-7" />
<path
d="M498.05 299.26c-19.14-3.32-45.16.19-67.14-5.21-.64-12.75-2.5-23.36.18-34.97 16.05-69.61 73.52 22.89 109.73-18.21 17.11-19.41-43.12-150.1-46.9-195.72-1.88-22.64 6.32-25.4 15.05-22.45 6.71 9.29 12.32 21.32 16.34 35.59 11.63 41.36 10.92 77.5 21 104.75s54.75 59.48 27.68 85.73c-25.09 24.32-37.4 57.16-75.94 50.48Z"
class="cls-11" />
<path
d="M454.82 28.32c-22.44 7.1-36.87 27.08-36.2 47.73a42.196 42.196 0 0 1-4.97-10.47c-7.67-24.25 7.66-50.74 34.24-59.15 26.59-8.41 54.36 4.43 62.04 28.68 1.2 3.78 1.83 7.61 1.96 11.42-11.33-17.27-34.62-25.32-57.06-18.22Z"
class="cls-10" />
<path
d="M497.01 305.18c-3.56 0-7.24-.16-11.05-.49-45.24-3.88-126.26-17.19-127.07-17.32l-3.84-.63 36.22-228.8.42-.67c.28-.45 6.99-11.14 17.74-23.22 14.62-16.42 29.05-26.97 42.89-31.35 14.35-4.54 28.55-3.33 41.07 3.49 16.18 8.83 28.62 26.61 35.01 50.08 5.46 20.06 7.44 39.22 9.18 56.14 1.83 17.81 3.42 33.2 8.4 46.17 2.98 7.75 8.95 15.74 15.26 24.2 7.22 9.66 14.69 19.65 18.76 30.68 4.8 13 3.96 25.17-2.59 37.2-11.2 20.58-22.1 33.62-35.33 42.28-12.54 8.21-27.37 12.25-45.08 12.25ZM364 280.27c16.63 2.68 83.32 13.25 122.63 16.62 10.89.93 20.4.48 29.05-1.38 8.19-1.76 15.42-4.75 22.12-9.13 12.09-7.91 22.19-20.08 32.74-39.47 5.48-10.07 6.16-19.84 2.13-30.75-3.68-9.96-10.8-19.49-17.69-28.7-6.65-8.9-12.94-17.31-16.3-26.08-5.35-13.94-7.06-30.57-8.88-48.18-1.71-16.61-3.65-35.44-8.95-54.88-5.83-21.39-16.91-37.47-31.21-45.26-10.6-5.78-22.69-6.78-34.96-2.9-27.9 8.83-52.46 45.26-55.94 50.6l-34.75 219.52Z"
class="cls-9" />
<path
d="M117.12 154.36s-46.54-19.67-78.28-9.63C7.11 154.77-4.29 187.96 9.92 227.25s37.7 66.77 44.59 94.17-11.28 72.8 25.2 90.85c36.48 18.04 66.58 21.54 101.64-7.9 35.06-29.44 93.75-87.06 93.75-87.06L117.12 154.36Z"
class="cls-7" />
<path
d="M164.51 417.58c13.75-13.72 43.42-33.51 58.28-50.57-6.82-10.8-11.39-20.55-20.26-28.5-53.17-47.71-46.97 61.02-100.23 48.23-25.16-6.04-51.07-147.58-74.22-187.07-11.49-19.6-19.78-17.15-25.22-9.7-.14 11.46 2.18 24.53 7.11 38.51 14.28 40.53 35.65 69.68 43.08 97.76s-9.68 73.92 26.59 84.24c22.61 6.43 67.59 24.35 84.88 7.1Z"
class="cls-11" />
<path
d="M50.37 163.4c22.44-7.1 45.73.94 57.06 18.22a42.04 42.04 0 0 0-1.96-11.42c-7.67-24.25-35.45-37.1-62.04-28.68-26.59 8.41-41.92 34.89-34.24 59.15 1.2 3.78 2.88 7.28 4.97 10.47-.67-20.65 13.75-40.63 36.2-47.73Z"
class="cls-10" />
<path
d="M128.66 430.09c-15.03 0-30.8-4.47-50.68-14.3-12.28-6.07-19.97-15.54-23.52-28.94-3.01-11.36-2.65-23.83-2.3-35.88.31-10.55.59-20.52-1.43-28.57-3.39-13.48-10.95-26.97-19.69-42.6-8.3-14.84-17.72-31.65-24.78-51.2-8.27-22.87-8.33-44.57-.17-61.1 6.31-12.78 17.23-21.94 31.59-26.48 13.84-4.38 31.71-4.05 53.11.97 15.74 3.7 27.38 8.58 27.87 8.78l.73.31.55.57 160.7 165.74-2.77 2.72c-.59.58-59.2 58.07-93.98 87.27-17.45 14.65-34.68 22.07-52.68 22.67-.84.03-1.69.04-2.53.04ZM59.48 145.8c-6.77 0-13.42.76-19.45 2.67-12.27 3.88-21.58 11.66-26.93 22.49-7.21 14.6-7.03 34.13.51 54.98 6.85 18.95 16.1 35.46 24.25 50.04 8.64 15.44 16.81 30.03 20.45 44.51 2.29 9.11 1.99 19.6 1.67 30.71-.33 11.5-.68 23.39 2.04 33.65 2.98 11.24 9.15 18.85 19.43 23.93 19.79 9.79 35.04 13.93 49.49 13.45 8-.27 15.64-1.99 23.35-5.26 8.15-3.46 16.18-8.55 24.56-15.59 30.22-25.37 78.69-72.38 90.75-84.14L114.88 157.68c-4.63-1.85-30.85-11.88-55.41-11.88Z"
class="cls-9" />
<path
d="M491.19 588.11c-159.82-46.08-241.51-209.96-241.51-209.98-152.04-83.46-144.45-179.68-83.33-243.45l205.24-64.94c63.52 19.38 101.89 88.17 52.99 232.85-41.18 146.84 82.52 225.46 82.52 225.46l-46.14 7.42 30.23 52.64Z"
class="cls-7" />
<path
d="M213.78 119.08c-84.76 61.25-101.14 132.02 72.53 227.35 0 .02 44 156.39 172.96 193.69 5.86 3.37 26.35 43.29 26.35 43.29-157.58-45.83-234.06-208.69-234.06-208.7C58.1 268.52 108.92 173.45 213.78 119.09Z"
class="cls-11" />
<path
d="m436.86 132.87 11.74 37.1 22.71-7.19 1.79 5.65c2.69 8.49 11.76 13.21 20.26 10.52l9.83-3.11c8.49-2.69 13.19-11.76 10.5-20.25l-15.05-47.56c-2.69-8.49-11.75-13.2-20.24-10.51l-9.83 3.11c-8.49 2.69-13.21 11.75-10.52 20.24l1.52 4.81-22.71 7.19Z"
class="cls-8" />
<g class="cls-21">
<path
d="m452.99 130.61 1.52 4.81-15.31 4.85-2.34-7.4 15.55-4.92c.12.89.3 1.78.58 2.66ZM508.63 165.33l-15.05-47.56c-2.69-8.49-11.75-13.2-20.24-10.51l-9.83 3.11a16.02 16.02 0 0 0-6.06 3.53c.8-6.01 4.96-11.32 11.12-13.27l9.83-3.11c8.49-2.69 17.55 2.02 20.24 10.51l15.05 47.56c1.95 6.16 0 12.62-4.46 16.73.3-2.28.14-4.66-.6-6.99Z"
class="cls-3" />
</g>
<g class="cls-15">
<path
d="m447.22 129.59 2.59 8.2c2.98 9.42 13.04 14.64 22.46 11.66 3.12-.99 6.45.74 7.44 3.86 2.69 8.5 11.76 13.21 20.26 10.52l9.82-3.11c1.66-.53 3.17-1.3 4.51-2.26.95 7.58-3.58 14.99-11.12 17.38l-9.82 3.11c-8.5 2.69-17.57-2.02-20.26-10.52l-1.79-5.65-22.71 7.19-11.74-37.1 10.36-3.28Z"
class="cls-9" />
</g>
<path
d="m467.92 170.07-.15-.47-17.53 5.55a5.44 5.44 0 0 1-6.82-3.54l-11.74-37.1c-.91-2.86.68-5.91 3.54-6.82l17.54-5.55c-3.33-11.23 2.96-23.14 14.18-26.69l9.83-3.11c11.33-3.59 23.47 2.72 27.06 14.05l15.05 47.56c3.59 11.34-2.71 23.48-14.04 27.07l-9.83 3.11c-11.34 3.59-23.49-2.72-27.07-14.06Zm2.29-64.26c-5.63 1.78-8.76 7.8-6.98 13.43l1.52 4.81c.91 2.86-.68 5.91-3.54 6.82l-17.53 5.55 8.46 26.74 17.53-5.55c2.86-.9 5.91.68 6.82 3.54l1.79 5.65c1.78 5.63 7.81 8.76 13.44 6.98l9.83-3.11c5.62-1.78 8.75-7.81 6.96-13.44l-15.05-47.56c-1.78-5.62-7.8-8.75-13.42-6.97l-9.83 3.11Z"
class="cls-9" />
<path
d="m129.88 256 315.53-99.84c2.14-.68 3.33-2.96 2.65-5.1s-2.96-3.33-5.1-2.65l-315.53 99.84a4.063 4.063 0 0 0-2.65 5.1 4.063 4.063 0 0 0 5.1 2.65Z"
class="cls-9" />
<path
d="M419.91 180.48a5.816 5.816 0 0 0 3.79-7.29l-8.53-26.94a5.816 5.816 0 0 0-7.29-3.79 5.816 5.816 0 0 0-3.79 7.29l8.53 26.94a5.816 5.816 0 0 0 7.29 3.79ZM372.24 195.56a5.816 5.816 0 0 0 3.79-7.29l-8.53-26.94a5.816 5.816 0 0 0-7.29-3.79 5.816 5.816 0 0 0-3.79 7.29l8.53 26.94a5.816 5.816 0 0 0 7.29 3.79ZM324.56 210.65a5.816 5.816 0 0 0 3.79-7.29l-8.53-26.94a5.816 5.816 0 0 0-7.29-3.79 5.816 5.816 0 0 0-3.79 7.29l8.53 26.94a5.816 5.816 0 0 0 7.29 3.79ZM164.72 261.23a5.816 5.816 0 0 0 3.79-7.29L159.98 227a5.816 5.816 0 0 0-7.29-3.79 5.816 5.816 0 0 0-3.79 7.29l8.53 26.94a5.816 5.816 0 0 0 7.29 3.79ZM212.4 246.14a5.816 5.816 0 0 0 3.79-7.29l-8.53-26.94a5.816 5.816 0 0 0-7.29-3.79 5.816 5.816 0 0 0-3.79 7.29l8.53 26.94a5.816 5.816 0 0 0 7.29 3.79ZM260.07 231.06a5.816 5.816 0 0 0 3.79-7.29l-8.53-26.94a5.816 5.816 0 0 0-7.29-3.79 5.816 5.816 0 0 0-3.79 7.29l8.53 26.94a5.816 5.816 0 0 0 7.29 3.79Z"
class="cls-9" />
<path
d="m125.35 236.76 11.74 37.1-22.71 7.19 1.79 5.65c2.69 8.49-2.03 17.57-10.52 20.26l-9.83 3.11c-8.49 2.69-17.56-2.03-20.24-10.52l-15.05-47.56c-2.69-8.49 2.02-17.55 10.51-20.24l9.83-3.11c8.49-2.69 17.57 2.01 20.25 10.5l1.52 4.81 22.71-7.19Z"
class="cls-8" />
<g class="cls-21">
<path
d="m110.86 244.2 1.52 4.81 15.31-4.85-2.34-7.4-15.55 4.92c.41.8.77 1.63 1.05 2.52ZM85.32 304.6l-15.05-47.56c-2.69-8.49 2.02-17.55 10.51-20.24l9.83-3.11c2.34-.74 4.71-.9 6.99-.6-4.11-4.46-10.57-6.41-16.73-4.46l-9.83 3.11c-8.49 2.69-13.2 11.75-10.51 20.24l15.05 47.56c1.95 6.16 7.26 10.32 13.27 11.12a16.096 16.096 0 0 1-3.53-6.06Z"
class="cls-3" />
</g>
<g class="cls-15">
<path
d="m115 240.04 2.59 8.2c2.98 9.42-2.24 19.48-11.66 22.46a5.927 5.927 0 0 0-3.86 7.44c2.69 8.5-2.02 17.57-10.52 20.26l-9.82 3.11c-1.66.53-3.34.76-4.99.75 3.58 6.74 11.56 10.2 19.09 7.81l9.82-3.11c8.5-2.69 13.21-11.76 10.52-20.26l-1.79-5.65 22.71-7.19-11.74-37.1-10.36 3.28Z"
class="cls-9" />
</g>
<path
d="m107.29 312.14-9.83 3.11c-11.33 3.59-23.47-2.72-27.06-14.06l-15.05-47.56c-3.59-11.33 2.72-23.47 14.05-27.06l9.83-3.11c11.22-3.55 23.22 2.58 26.95 13.68l17.54-5.55c2.86-.9 5.91.68 6.82 3.54l11.74 37.1c.91 2.86-.68 5.91-3.54 6.82l-17.53 5.55.15.47c3.59 11.34-2.72 23.49-14.06 27.08Zm-34.61-75.21c-5.62 1.78-8.75 7.8-6.97 13.42l15.05 47.56c1.78 5.63 7.8 8.76 13.43 6.98l9.83-3.11c5.63-1.78 8.76-7.81 6.98-13.44l-1.79-5.65c-.91-2.86.68-5.91 3.54-6.82l17.53-5.55-8.46-26.74-17.53 5.55a5.44 5.44 0 0 1-6.82-3.54l-1.52-4.81c-1.78-5.62-7.81-8.75-13.43-6.96l-9.83 3.11ZM345.59 396.05c-19.9 10.03-31.58 28.01-28.61 42.47-1.24-1.38-2.3-2.9-3.15-4.58-7.59-15.07 4.41-36.44 26.81-47.73s46.71-8.22 54.31 6.86a20.81 20.81 0 0 1 1.81 5.25c-9.85-10.99-31.26-12.31-51.16-2.28Z"
class="cls-9" />
<path
d="M361.94 425.47c-15.45 7.79-24.25 22.28-21.59 34.21-10.52-11.58-2.16-32.76 17.47-42.39 19.42-10.05 41.42-4.17 44.46 11.18-8-9.24-24.89-10.79-40.34-3ZM383.72 455.91c-11.87 5.98-18.66 17.04-16.66 26.12-8.03-8.82-1.53-24.93 13.54-32.33 14.91-7.7 31.73-3.34 34.03 8.36-6.1-7-19.04-8.13-30.9-2.15ZM172.17 213.6l-33.05-41.54c7.89-14.07 18.4-27.21 30.77-39.1l7.18-2.27 11.16-3.53 25.96-8.21 11.69-3.7 18.96-6 17.61-5.57 20.04-6.34 13.85-4.38 22.73-7.19 13.85-4.38 20.04-6.34 18.84-3.11c24.42 6 38.61 18.82 53.3 39.84l-3.35 22.87-33.9-42.61-3.22 54.35-33.41-41.99-3.17 53.56-30.95-38.9-2.94 49.63-33.41-41.99-3.17 53.56-34.39-43.23-3.26 55.14-28-35.2-2.66 44.9-33.9-42.61-3.22 54.35ZM138.7 172.85l-3.1 52.32-10.76-13.53c2.28-13.49 7.07-26.49 13.86-38.79Z"
class="cls-9" />
<path
d="m499.4 594.55-9.29-2.68c-36.89-10.64-72.68-28.41-106.37-52.84-26.9-19.5-52.54-43.26-76.19-70.62-21.03-24.33-36.57-47.06-45.91-61.85-5.3-8.39-9.2-15.17-11.55-19.38-1.72-3.09-2.76-4.99-3.38-6.21-38.19-21.09-68.15-44.05-89.04-68.28-19.39-22.48-31.11-46.14-34.82-70.31-3.03-19.77-.7-39.69 6.94-59.21 7.03-17.96 18.38-35.19 33.73-51.2l.69-.72.95-.3 206.4-65.31 1.16.35c13.75 4.2 25.99 10.54 36.39 18.84 11.05 8.84 20.06 19.94 26.76 33 10.51 20.46 15.45 45.82 14.71 75.39-.8 31.96-8.3 69.15-22.27 110.52-9.18 32.79-10.67 64.76-4.43 95.05 5 24.26 14.95 47.52 29.57 69.15 13.06 19.31 27.5 33.72 37.32 42.41 10.67 9.44 18.34 14.35 18.41 14.4l8.68 5.53-50.7 8.16 32.23 56.12ZM253.58 377.17c2.98 5.79 23.18 43.8 60.42 86.75 23.23 26.78 48.37 50.02 74.72 69.07 29.96 21.66 61.58 37.94 94.14 48.49l-28.12-48.96 42.35-6.81a215.74 215.74 0 0 1-11.27-9.29c-10.16-8.97-25.12-23.85-38.67-43.82-15.25-22.49-25.65-46.73-30.89-72.02-6.55-31.61-5.02-64.92 4.54-99.03l.06-.2c13.74-40.66 21.11-77.1 21.9-108.31.71-28.24-3.95-52.34-13.85-71.62-6.2-12.07-14.51-22.32-24.69-30.46-9.33-7.46-20.3-13.21-32.63-17.11l-203.11 64.27c-14.29 15.06-24.85 31.18-31.4 47.92-7.13 18.22-9.32 36.78-6.5 55.17 3.48 22.69 14.59 45.03 33.01 66.38 20.48 23.74 50.08 46.33 87.97 67.13l1.99 1.09.02 1.37Z"
class="cls-9" />
<path
d="M315.85 249.39c9.33 19.11 31.49 29.02 52.38 22.41 20.89-6.61 33.31-27.46 29.95-48.46l-82.33 26.05Z"
class="cls-3" />
<path
d="M369.65 276.3a48.368 48.368 0 0 1-33.82-1.73c-10.58-4.59-19.18-12.8-24.22-23.11l-2.4-4.92 92.77-29.35.86 5.41c1.81 11.33-.5 22.99-6.52 32.83a48.367 48.367 0 0 1-26.67 20.87Zm-46.77-24.18c4.12 6.04 9.9 10.84 16.71 13.79 8.6 3.73 18.27 4.22 27.22 1.39s16.57-8.8 21.46-16.8a38.94 38.94 0 0 0 5.73-20.89l-71.12 22.5Z"
class="cls-9" />
<circle cx="359.31" cy="245.38" r="10.66" class="cls-9" />
<path
d="M213.64 282.92c9.33 19.11 31.49 29.02 52.38 22.41 20.89-6.61 33.31-27.46 29.95-48.46l-82.33 26.05Z"
class="cls-3" />
<path
d="M267.44 309.83a48.368 48.368 0 0 1-33.82-1.73c-10.58-4.59-19.18-12.8-24.22-23.11l-2.4-4.92 92.77-29.35.86 5.41c1.81 11.33-.5 22.99-6.52 32.83a48.367 48.367 0 0 1-26.67 20.87Zm-46.77-24.18c4.12 6.04 9.9 10.84 16.71 13.79 8.6 3.73 18.27 4.22 27.22 1.39s16.57-8.8 21.46-16.8a38.94 38.94 0 0 0 5.73-20.89l-71.12 22.5Z"
class="cls-9" />
<circle cx="257.1" cy="278.91" r="10.66" class="cls-9" />
<path
d="M189.64 276.54c84.13-24.9 168.23-49.85 252.33-74.84 1.82-.54 2.28-.04 2.73 1.6 1.8 6.37 3.64 12.72 5.64 19.01.58 1.83.16 2.39-1.61 2.9-10.25 2.95-20.46 6.06-30.71 9.02-1.59.47-2 1.05-1.43 2.64.88 2.48 1.39 5.09 2.31 7.53.71 1.89.07 2.48-1.67 2.91-2.63.63-5.17 1.57-7.8 2.25-1.31.33-1.63.85-1.2 2.15.9 2.73 1.57 5.52 2.5 8.23.51 1.45.1 1.94-1.3 2.29-2.55.64-5.01 1.56-7.56 2.17-1.73.42-2.36 1.01-1.66 2.89.96 2.52 1.51 5.2 2.38 7.76.48 1.37.19 1.9-1.24 2.32a7385.42 7385.42 0 0 0-43.28 12.83c-1.29.39-1.82.21-2.17-1.14-.73-2.85-1.7-5.64-2.45-8.49-.35-1.34-.91-1.58-2.18-1.15-2.64.88-5.36 1.52-7.99 2.44-1.52.52-2.24.31-2.68-1.37-.86-3.23-1.95-6.39-2.95-9.57-3.35.99-6.72 1.94-10.04 3.01-1.08.35-1.56.18-1.87-.95-.92-3.38-1.93-6.73-2.9-10.09l.02.02s0-.01-.01-.02c-.14-.06-.32-.21-.42-.17-7.32 2.12-14.61 4.3-21.93 6.41-1.41.41-.71 1.31-.66 2.08.95 3.21 1.9 6.41 2.84 9.62-.03.96-.89.73-1.39.88-3.28 1.03-6.57 1.99-9.86 2.97h-.01c.91 3.22 1.75 6.45 2.75 9.63.45 1.41.34 2.12-1.3 2.5-2.78.67-5.49 1.66-8.26 2.38-1.35.34-1.57.93-1.15 2.2.89 2.72 1.58 5.51 2.49 8.23.46 1.34.28 1.92-1.19 2.35-14.44 4.23-28.87 8.5-43.27 12.84-1.54.46-1.93-.07-2.27-1.38-.73-2.77-1.68-5.49-2.39-8.26-.34-1.34-.92-1.57-2.17-1.16-2.5.82-5.07 1.4-7.54 2.31-1.8.65-2.67.44-3.11-1.6-.58-2.64-1.55-5.19-2.24-7.81-.31-1.21-.79-1.51-1.99-1.11-2.73.89-5.53 1.54-8.23 2.5-1.67.59-2.22.07-2.62-1.49-.68-2.7-1.61-5.34-2.32-8.03-.34-1.29-.84-1.65-2.16-1.21-2.72.91-5.52 1.58-8.23 2.52-1.44.49-1.89.1-2.29-1.29-1.85-6.51-3.75-13.01-5.77-19.47-.54-1.69-.24-2.28 1.49-2.79Z"
class="cls-9" />
<path
d="m251.02 298.65-3.51-12.06.08.05c-4 1.21-8 2.41-12 3.62l.04-.08c1.41 3.19 2.12 6.61 3.1 9.94.4 1.35.87 1.77 2.31 1.3 3.31-1.06 6.67-1.92 10.02-2.86l-.05.09Z"
style="fill:#fefffd" />
<path
d="M357.26 251.05c.38.7.84.95 1.7.67 3.44-1.12 6.91-2.15 10.37-3.21-.97-3.28-1.99-6.55-2.89-9.85-.32-1.18-.77-1.54-1.99-1.14-2.87.93-5.77 1.8-8.69 2.58-1.23.33-1.44.85-1.07 2.02.92 2.96 1.72 5.96 2.57 8.94M334.59 258.93c3.26-.97 6.51-2 9.79-2.88 1.33-.36 1.57-.89 1.15-2.17-1.05-3.24-1.98-6.52-2.95-9.78l-10.08 2.91c-.75.22-1.65.3-1.24 1.51 1.17 3.45 1.79 7.07 3.32 10.41"
class="cls-4" />
<path
d="M372.91 260.57c-3.49.98-6.96 2.03-10.48 2.9-1.38.34-.82 1.25-.9 2.01.37.85.74 1.7.71 2.66-.16 1.38-.08 2.68 1.12 3.64 1.43 3.62 1.45 3.68 5.32 2.44 2.46-.79 6.11-.61 7.05-2.62.81-1.75-1-4.73-1.67-7.16-.36-1.3-.77-2.59-1.15-3.88"
style="fill:#fbfbfb" />
<path
d="M247.5 286.59c3.43-.98 6.87-1.97 10.31-2.93.9-.25 1.35-.55 1-1.63-.97-3.03-1.88-6.07-2.71-9.14-.3-1.1-.81-1.1-1.71-.82-2.96.92-5.92 1.82-8.91 2.63-1.17.32-1.26.88-.94 1.9 1.05 3.33 2.03 6.69 3.04 10.04l-.08-.05Z"
class="cls-3" />
<path
d="M235.59 290.25c-.46-3.65-1.97-7.01-2.85-10.55-.24-.96-.77-1-1.58-.75-2.97.91-5.94 1.82-8.93 2.64-1.09.3-1.4.74-1.04 1.85.92 2.88 1.8 5.78 2.57 8.7.34 1.29.95 1.36 2.06 1.01 3.26-1.04 6.54-1.99 9.82-2.98l-.04.08M251.07 298.56c.97 3.27 1.99 6.52 2.88 9.81.35 1.28.84 1.64 2.15 1.2 2.78-.93 5.6-1.73 8.43-2.51 1.09-.3 1.58-.64 1.15-1.93-.98-2.92-1.79-5.9-2.66-8.85-.2-.7-.3-1.4-1.37-1.03-3.51 1.21-7.2 1.85-10.61 3.39l.05-.09"
class="cls-4" />
<path
d="M167.27 433.19c9.62-29.21 55.01-60.77 82.24-107.29 11.54-19.71 2.97-51.8-22.95-56.38-56.15-9.91-96.62 37.51-96.62 37.51s-37.46 35.45-25.85 86.54c0 0 7.93 30.62 36.95 50.52l23.64.81 2.6-11.71Z"
class="cls-7" />
<path
d="M254.51 307.83c-3.13-13.15-12.37-24.66-27.22-27.28-57-10.05-98.1 38.09-98.1 38.09s-21.89 20.72-27.31 53.37c.84-39.23 28.05-64.98 28.05-64.98s40.47-47.42 96.63-37.51c18.87 3.33 28.53 21.22 27.95 38.31"
class="cls-3" style="opacity:.4" />
<path
d="M164.98 432.44c1.35-6.88 4.47-13.2 8.05-18.95 3.61-5.76 7.73-11.08 12.05-16.12 8.69-10.05 17.73-19.53 26.34-29.27 8.63-9.73 16.9-19.67 24.26-30.18.93-1.31 1.84-2.63 2.72-3.97.89-1.33 1.78-2.66 2.62-4.02.86-1.35 1.72-2.7 2.52-4.07l1.23-2.05.31-.51.25-.46.49-.92c2.53-4.97 3.65-10.77 3.49-16.53-.17-5.76-1.68-11.5-4.38-16.45-2.69-4.97-6.7-9.02-11.51-11.52-2.41-1.26-5.01-2.12-7.74-2.6l-4.57-.66c-1.53-.18-3.07-.27-4.6-.41-6.14-.37-12.32-.08-18.42.85-12.21 1.84-24.01 6.43-34.88 12.65-5.41 3.16-10.64 6.7-15.56 10.63-2.46 1.96-4.86 4-7.16 6.13-1.15 1.07-2.29 2.15-3.38 3.25a74.216 74.216 0 0 0-3.09 3.27l-.21.23-.19.18c-.4.38-.99 1-1.48 1.53l-1.54 1.7a97.533 97.533 0 0 0-8.39 11.21 99.179 99.179 0 0 0-8.63 16.57c-2.31 5.77-4.09 11.75-5.18 17.83a83.369 83.369 0 0 0-1.18 18.46c.03 1.55.24 3.08.35 4.63.14 1.54.42 3.07.61 4.6.25 1.52.57 3 .85 4.5.04.18.08.41.1.46l.14.46c.1.34.21.69.33 1.06.22.71.48 1.44.74 2.16a93.879 93.879 0 0 0 8.13 16.8c3.27 5.33 7.02 10.36 11.27 14.92 4.25 4.56 7.25 8.48 12.31 12.1 0 0-1.68 8.9-3.84 7.41-11.42-7.86-21.15-17.32-28.38-29.1-3.66-5.86-6.72-12.06-9.18-18.6-.3-.82-.6-1.65-.88-2.5-.14-.42-.28-.85-.41-1.3l-.21-.72c-.1-.35-.13-.53-.17-.75-.35-1.73-.74-3.46-1.03-5.18-.24-1.72-.55-3.44-.73-5.17-.14-1.74-.39-3.46-.44-5.21-.39-6.96 0-13.97 1.16-20.85 1.17-6.87 3.11-13.59 5.7-20.03 2.6-6.43 5.81-12.59 9.55-18.39 1.87-2.91 3.87-5.72 6.01-8.45 1.06-1.37 2.18-2.7 3.32-4.02.58-.66 1.16-1.31 1.77-1.96.63-.67 1.17-1.25 1.96-2.01l-.4.42c1.29-1.47 2.41-2.63 3.65-3.88 1.21-1.22 2.45-2.4 3.7-3.57 2.51-2.32 5.1-4.53 7.76-6.66 5.31-4.26 10.97-8.1 16.87-11.55 11.84-6.8 24.89-11.92 38.63-14.01a92.636 92.636 0 0 1 20.78-.89c1.73.17 3.47.29 5.19.5l5.16.78c3.73.67 7.4 1.91 10.8 3.71 6.82 3.58 12.32 9.36 15.82 15.93 3.53 6.58 5.35 13.89 5.53 21.22.15 7.32-1.29 14.79-4.75 21.5l-.68 1.24-.34.62-.33.54-1.31 2.16c-.86 1.45-1.77 2.86-2.68 4.27-.9 1.42-1.83 2.81-2.78 4.2-.93 1.4-1.89 2.77-2.87 4.13-7.75 10.92-16.35 21.1-25.17 30.92-8.82 9.83-17.92 19.29-26.46 29-8.52 9.71-17.05 19.18-22.79 30.26l-.04.08a2.436 2.436 0 0 1-3.28 1.04 2.441 2.441 0 0 1-1.27-2.63"
class="cls-9" />
<g class="cls-20">
<path
d="M211.98 349.04c-8.63 8.62-21.18 10.05-28.04 3.19-6.86-6.86-5.43-19.41 3.2-28.03 8.62-8.62 21.18-10.05 28.03-3.2 6.86 6.86 5.43 19.41-3.2 28.04"
class="cls-3" />
</g>
<g class="cls-20">
<path
d="M214.43 309.1c-3.66 3.66-9 4.27-11.91 1.36-2.91-2.91-2.31-8.25 1.36-11.91 3.66-3.66 9-4.27 11.91-1.36 2.91 2.91 2.31 8.25-1.36 11.91"
class="cls-3" />
</g>
<g class="cls-20">
<path
d="M230.61 315.92c-3.74 3.75-9.19 4.37-12.17 1.39-2.98-2.98-2.36-8.43 1.39-12.17 3.74-3.74 9.19-4.37 12.17-1.39 2.98 2.98 2.36 8.43-1.39 12.17"
class="cls-3" />
</g>
<g class="cls-20">
<path
d="M234.52 329.19c-3.03 3.03-7.45 3.54-9.86 1.12-2.41-2.41-1.91-6.83 1.12-9.86 3.03-3.03 7.45-3.54 9.86-1.12 2.41 2.41 1.91 6.83-1.12 9.86"
class="cls-3" />
</g>
<path
d="M232.2 483.14c-10.58-.05-29.68-6.12-56.76-18.06-19.9-8.77-37.07-17.65-37.24-17.74l3.84-7.41c.17.09 17.14 8.86 36.8 17.53 32.39 14.27 42.22 15.99 48.7 16.01l4.65 9.66Z"
class="cls-9" />
</svg>
</div>
<div class="right">
<div class="content">
<section class="general">
<h2>If you are a member of the general public:</h2>
<p>The fact that you are seeing this page indicates that the website you just visited is either
experiencing problems, or is undergoing routine maintenance.</p>
<p>
If you would like to let the administrators of this website know that you've seen this page
instead of the page you expected, you should send them e-mail.
In general, mail sent to the name "webmaster" and directed to the website's domain should reach
the appropriate person.
</p>
<p>For example, try contacting <a
href="mailto:webmaster@<?php echo $_SERVER['SERVER_NAME'] ?? 'example.com'; ?>">webmaster@<?php echo $_SERVER['SERVER_NAME'] ?? 'example.com'; ?></a>.
</p>
<p>Learn more about FrankenPHP at the <a href="https://frankenphp.dev/">official website</a>.</p>
</section>
<section class="administrator">
<h2>If you are the website administrator:</h2>
<p>Your server is running and serving requests using FrankenPHP</p>
<p>To replace this page, deploy your application files to <code><?php echo getcwd(); ?></code>.</p>
<p>Configuration is handled in your <code>Caddyfile</code>.</p>
<div class="runtime-info">
<strong>Served by PHP SAPI: </strong> <?php echo php_sapi_name(); ?><br />
</div>
</section>
</div>
<footer class="footer">
<p><a href="https://frankenphp.dev">FrankenPHP</a> is a free and open-source web server for PHP built on top
of <a href="https://caddyserver.com">Caddy</a>.</p>
<div class="logos">
<a href="https://frankenphp.dev/"><img src="assets/frankenphp.svg" height="50" width="166" alt="Powered by FrankenPHP" /></a>
<a href="https://caddyserver.com/"><img src="assets/caddy.png" height="50" width="166" alt="Powered by Caddy" /></a>
<a href="https://frankenphp.dev/"><svg xmlns="http://www.w3.org/2000/svg" id="a"
viewBox="0 0 699.37 92.29">
<defs fill="#000000">
<style>
.b {
fill: #390075;
}
.c {
fill: #b3d133;
}
</style>
</defs>
<path class="c"
d="M22.65,38.71h20.32c3.02,0,5.65,1.1,7.89,3.3,2.24,2.2,3.36,4.85,3.36,7.96s-1.12,5.67-3.36,7.96c-2.24,2.29-4.96,3.43-8.15,3.43H22.65v19.8c0,3.45-1.12,6.17-3.37,8.15-2.24,1.99-4.88,2.98-7.89,2.98s-5.78-.99-8.02-2.98c-2.24-1.98-3.37-4.7-3.37-8.15V20.2c0-3.45,.86-6.64,2.59-9.58,1.72-2.93,4.03-5.26,6.92-6.99,2.89-1.72,6.06-2.59,9.51-2.59h28.86c3.19,0,5.89,1.1,8.09,3.3,2.2,2.2,3.3,4.81,3.3,7.83s-1.14,5.8-3.43,8.09c-2.29,2.29-4.94,3.43-7.96,3.43H22.65v15.01Z"
fill="#000000" />
<path class="c"
d="M118.29,54.76c3.88,2.42,6.66,5.18,8.35,8.28,1.68,3.11,2.52,6.77,2.52,11v6.6c0,3.11-1.08,5.76-3.24,7.96-2.16,2.2-4.75,3.3-7.77,3.3s-5.74-1.12-7.89-3.36c-2.16-2.24-3.24-4.87-3.24-7.89v-6.34l-22.13-26.92v33.26c0,3.11-1.08,5.76-3.24,7.96-2.16,2.2-4.79,3.3-7.89,3.3s-5.89-1.1-8.09-3.3c-2.2-2.2-3.3-4.85-3.3-7.96V12.44c0-3.19,1.1-5.89,3.3-8.09s4.9-3.3,8.09-3.3h25.24c5.09,0,9.62,1.86,13.59,5.57l11,10.61c4.05,4.06,6.08,8.72,6.08,13.98v5.05c0,8.54-3.8,14.71-11.39,18.51Zm-33.39-9.32h22.13V23.7h-22.13v21.74Z"
fill="#000000" />
<path class="c"
d="M270.74,88.54c-2.16,2.24-4.83,3.36-8.02,3.36s-6-1.12-8.15-3.36c-2.16-2.24-3.24-4.96-3.24-8.15V23.57h-20.84v57.07c0,3.19-1.12,5.87-3.37,8.02-2.24,2.16-4.96,3.24-8.15,3.24s-5.76-1.1-7.96-3.3c-2.2-2.2-3.3-4.85-3.3-7.96V12.05c0-3.19,1.12-5.89,3.37-8.09,2.24-2.2,4.87-3.3,7.89-3.3,3.19,0,5.91,1.1,8.15,3.3,2.24,2.2,3.37,4.9,3.37,8.09v3.75c0,.43,.08,.65,.26,.65s.26-.08,.26-.26c1.55-5,4.12-8.8,7.7-11.39,3.58-2.59,7.87-3.88,12.88-3.88,6.47,0,11.82,1.92,16.05,5.76,4.23,3.84,6.34,8.99,6.34,15.47v58.24c0,3.19-1.08,5.91-3.24,8.15Z"
fill="#000000" />
<path class="c"
d="M347.1,80.64c0,3.11-1.14,5.78-3.43,8.02-2.29,2.24-4.98,3.37-8.09,3.37s-5.8-1.12-8.09-3.37c-2.29-2.24-3.43-4.92-3.43-8.02v-24.72l-22.13-.26v24.98c0,3.19-1.1,5.89-3.3,8.09s-4.9,3.3-8.09,3.3-5.89-1.1-8.09-3.3-3.3-4.9-3.3-8.09V11.66c0-3.02,1.1-5.63,3.3-7.83,2.2-2.2,4.9-3.3,8.09-3.3s5.89,1.08,8.09,3.24c2.2,2.16,3.3,4.79,3.3,7.89V53.72l22.13-27.31V11.66c0-3.02,1.14-5.63,3.43-7.83,2.29-2.2,4.94-3.3,7.96-3.3s5.63,1.1,7.83,3.3c2.2,2.2,3.3,4.81,3.3,7.83v15.14c0,4.32-.84,8.05-2.52,11.19-1.68,3.15-4.51,5.98-8.48,8.48,7.68,3.62,11.52,9.79,11.52,18.51v15.66Z"
fill="#000000" />
<path class="c"
d="M374.66,35.6h25.24c3.11,0,5.76,1.1,7.96,3.3,2.2,2.2,3.3,4.9,3.3,8.09,0,3.02-1.12,5.65-3.37,7.89-2.24,2.24-4.88,3.36-7.89,3.36h-25.24v10.87h27.44c3.11,0,5.76,1.1,7.96,3.3,2.2,2.2,3.3,4.9,3.3,8.09,0,3.02-1.1,5.61-3.3,7.77-2.2,2.16-4.85,3.32-7.96,3.49h-31.19c-3.37,0-6.49-.86-9.38-2.59-2.89-1.73-5.2-4.05-6.92-6.99-1.73-2.93-2.59-6.12-2.59-9.58v-6.99c0-5.26,.73-9.55,2.2-12.88,1.47-3.32,4.49-5.76,9.06-7.31-4.32-1.47-7.27-3.77-8.87-6.92-1.6-3.15-2.39-7.23-2.39-12.23v-6.08c0-3.45,.86-6.64,2.59-9.58,1.73-2.93,4.03-5.26,6.92-6.99,2.89-1.72,6.02-2.59,9.38-2.59h31.19c3.11,0,5.76,1.1,7.96,3.3s3.3,4.81,3.3,7.83-1.12,5.8-3.37,8.09c-2.24,2.29-4.88,3.43-7.89,3.43h-27.44v11.91Z"
fill="#000000" />
<path class="c"
d="M480.4,88.54c-2.16,2.24-4.83,3.36-8.02,3.36s-6-1.12-8.15-3.36c-2.16-2.24-3.24-4.96-3.24-8.15V23.57h-20.84v57.07c0,3.19-1.12,5.87-3.37,8.02-2.24,2.16-4.96,3.24-8.15,3.24s-5.76-1.1-7.96-3.3c-2.2-2.2-3.3-4.85-3.3-7.96V12.05c0-3.19,1.12-5.89,3.37-8.09,2.24-2.2,4.87-3.3,7.89-3.3,3.19,0,5.91,1.1,8.15,3.3,2.24,2.2,3.37,4.9,3.37,8.09v3.75c0,.43,.08,.65,.26,.65s.26-.08,.26-.26c1.55-5,4.12-8.8,7.7-11.39,3.58-2.59,7.87-3.88,12.88-3.88,6.47,0,11.82,1.92,16.05,5.76,4.23,3.84,6.34,8.99,6.34,15.47v58.24c0,3.19-1.08,5.91-3.24,8.15Z"
fill="#000000" />
<path class="b"
d="M511.07,80.25c0,3.19-1.06,5.91-3.17,8.15-2.12,2.24-4.72,3.37-7.83,3.37s-5.78-1.12-8.02-3.37c-2.24-2.24-3.37-4.96-3.37-8.15V20.07c0-3.45,.86-6.64,2.59-9.58,1.73-2.93,4.05-5.26,6.99-6.99,2.93-1.72,6.12-2.59,9.58-2.59h17.21c5.09,0,9.53,1.77,13.33,5.31l12.42,12.42c1.81,1.73,3.17,3.97,4.08,6.73,.91,2.76,1.36,5.74,1.36,8.93,0,3.71-.58,7.29-1.75,10.74-1.16,3.45-2.78,6.17-4.85,8.15l-11.26,10.74c-3.62,3.62-8.07,5.44-13.33,5.44h-13.98v10.87Zm21.74-56.69l-21.48-.26v23.42h21.48V23.57Z"
fill="#000000" />
<path class="b"
d="M560.11,11.92c0-3.45,1.12-6.17,3.37-8.15,2.24-1.98,4.92-2.98,8.02-2.98s5.76,.97,7.96,2.91c2.2,1.94,3.3,4.64,3.3,8.09v28.47h21.35V11.92c0-3.45,1.14-6.17,3.43-8.15,2.29-1.98,4.98-2.98,8.09-2.98s5.76,.97,7.96,2.91,3.3,4.64,3.3,8.09V81.16c0,3.45-1.12,6.17-3.37,8.15-2.24,1.99-4.92,2.98-8.02,2.98s-5.78-.99-8.02-2.98c-2.24-1.98-3.37-4.7-3.37-8.15V43.5l-21.35,19.28v18.38c0,3.45-1.12,6.17-3.36,8.15-2.24,1.99-4.88,2.98-7.89,2.98s-5.78-.99-8.02-2.98c-2.24-1.98-3.37-4.7-3.37-8.15V11.92Z"
fill="#000000" />
<path class="b"
d="M654.2,80.25c0,3.19-1.06,5.91-3.17,8.15-2.12,2.24-4.72,3.37-7.83,3.37s-5.78-1.12-8.02-3.37c-2.24-2.24-3.37-4.96-3.37-8.15V20.07c0-3.45,.86-6.64,2.59-9.58,1.73-2.93,4.05-5.26,6.99-6.99,2.93-1.72,6.12-2.59,9.58-2.59h17.21c5.09,0,9.53,1.77,13.33,5.31l12.42,12.42c1.81,1.73,3.17,3.97,4.08,6.73,.91,2.76,1.36,5.74,1.36,8.93,0,3.71-.58,7.29-1.75,10.74-1.16,3.45-2.78,6.17-4.85,8.15l-11.26,10.74c-3.62,3.62-8.07,5.44-13.33,5.44h-13.98v10.87Zm21.74-56.69l-21.48-.26v23.42h21.48V23.57Z"
fill="#000000" />
<g>
<path class="c"
d="M142.76,32.66v-3.51c0-1.32,1.04-2.4,2.32-2.4,1.29,0,2.33,1.07,2.33,2.39v3.51l7.92-.02v-3.51c0-1.32,1.04-2.4,2.32-2.4,1.29,0,2.33,1.07,2.33,2.39v3.51h6.64v-3.53c0-1.32,1.03-2.4,2.32-2.4s2.33,1.07,2.33,2.39v3.51h6.83v-3.53c0-1.32,1.03-2.4,2.32-2.4,1.29,0,2.33,1.07,2.33,2.39v3.51l7.69-.02v-3.51c0-1.32,1.03-2.4,2.32-2.4s2.33,1.07,2.33,2.39v3.51h6.89v-.85c-.17-3.02-.89-5.52-2.14-7.51-1.25-1.98-3.22-4.1-5.89-6.34l-16.95-13.85c-3.19-2.67-6.13-4.01-8.8-4.01s-5.61,1.34-9.06,4.01l-16.57,13.85c-2.68,2.33-4.66,4.49-5.95,6.47-1.29,1.99-2.07,4.44-2.33,7.38v.97l8.46-.02Z"
fill="#000000" />
<path class="c"
d="M195.11,37.2v3.5c0,1.32-1.03,2.4-2.32,2.4s-2.33-1.07-2.33-2.39v-3.5l-7.69,.02v3.5c0,1.32-1.03,2.4-2.32,2.4s-2.33-1.07-2.33-2.39v-3.5h-6.83v3.51c0,1.32-1.04,2.4-2.32,2.4-1.29,0-2.33-1.07-2.33-2.39v-3.5h-6.64v3.51c0,1.32-1.03,2.4-2.32,2.4-1.29,0-2.33-1.07-2.33-2.39v-3.5l-7.92,.02v3.5c0,1.32-1.03,2.4-2.32,2.4-1.29,0-2.33-1.07-2.33-2.39v-3.5l-8.47,.02v43.43c0,3.11,1.12,5.74,3.37,7.89,2.24,2.16,4.92,3.24,8.02,3.24s5.76-1.08,7.96-3.24c2.2-2.16,3.3-4.79,3.3-7.89v-31.84l22.52,20.84v11c0,3.11,1.1,5.74,3.3,7.89,2.2,2.16,4.9,3.24,8.09,3.24s5.74-1.08,7.9-3.24,3.24-4.79,3.24-7.89V37.19h-6.88Z"
fill="#000000" />
</g>
</svg></a>
<a href="https://caddyserver.com/"><svg width="100%" height="100%" viewBox="0 0 379 114"
version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
xml:space="preserve" xmlns:serif="http://www.serif.com/"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;">
<g transform="matrix(1,0,0,1,-35.5985,-67.948)">
<g transform="matrix(1.16548,0,0,1.10195,-124,-68.27)">
<g id="Light-Logo" serif:id="Light Logo"
transform="matrix(0.858013,0,0,0.907485,-3243.42,-1469.17)">
<g id="Logo" transform="matrix(1,0,0,1,21.4759,36.7359)">
<g id="Icon">
<g>
<g
transform="matrix(-0.191794,-0.715786,0.715786,-0.191794,4329.14,4673.64)">
<path
d="M3901.56,610.734C3893.53,610.261 3886.06,608.1 3879.2,604.877C3872.24,601.608 3866.04,597.093 3860.8,591.633C3858.71,589.457 3856.76,587.149 3854.97,584.709C3853.2,582.281 3851.57,579.733 3850.13,577.066C3845.89,569.224 3843.21,560.381 3842.89,550.868C3842.57,543.321 3843.64,536.055 3845.94,529.307C3848.37,522.203 3852.08,515.696 3856.83,510.049L3855.79,509.095C3850.39,514.54 3846.02,520.981 3842.9,528.125C3839.84,535.125 3838.03,542.781 3837.68,550.868C3837.34,561.391 3839.51,571.425 3843.79,580.306C3845.27,583.38 3847.03,586.304 3849.01,589.049C3851.01,591.806 3853.24,594.39 3855.69,596.742C3861.75,602.568 3869,607.19 3877.03,610.1C3884.66,612.867 3892.96,614.059 3901.56,613.552L3901.56,610.734Z"
style="fill:rgb(0,144,221);" />
</g>
<g
transform="matrix(-0.191794,-0.715786,0.715786,-0.191794,4329.14,4673.64)">
<path
d="M3875.69,496.573C3879.62,494.538 3883.8,492.897 3888.2,491.786C3892.49,490.704 3896.96,490.124 3901.56,490.032C3903.82,490.13 3906.03,490.332 3908.21,490.688C3917.13,492.147 3925.19,495.814 3932.31,500.683C3936.13,503.294 3939.59,506.335 3942.81,509.619C3947.09,513.98 3950.89,518.816 3953.85,524.232C3958.2,532.197 3960.96,541.186 3961.32,550.868C3961.61,558.748 3960.46,566.345 3957.88,573.322C3956.09,578.169 3953.7,582.753 3950.66,586.838C3947.22,591.461 3942.96,595.427 3938.27,598.769C3933.66,602.055 3928.53,604.619 3923.09,606.478C3922.37,606.721 3921.6,606.805 3920.93,607.167C3920.42,607.448 3920.14,607.854 3919.69,608.224L3920.37,610.389C3920.98,610.432 3921.47,610.573 3922.07,610.474C3922.86,610.344 3923.55,609.883 3924.28,609.566C3931.99,606.216 3938.82,601.355 3944.57,595.428C3947.02,592.903 3949.25,590.174 3951.31,587.319C3953.59,584.168 3955.66,580.853 3957.43,577.348C3961.47,569.34 3964.01,560.422 3964.36,550.868C3964.74,540.511 3962.66,530.628 3958.48,521.868C3955.57,515.775 3951.72,510.163 3946.95,505.478C3943.37,501.962 3939.26,498.99 3934.84,496.562C3926.88,492.192 3917.87,489.76 3908.37,489.229C3906.12,489.104 3903.86,489.054 3901.56,489.154C3896.87,489.06 3892.3,489.519 3887.89,490.397C3883.3,491.309 3878.89,492.683 3874.71,494.525L3875.69,496.573Z"
style="fill:rgb(0,144,221);" />
</g>
</g>
<g>
<g
transform="matrix(-3.37109,-0.514565,0.514565,-3.37109,4078.07,1806.88)">
<path
d="M22,12C22,10.903 21.097,10 20,10C19.421,10 18.897,10.251 18.53,10.649C18.202,11.006 18,11.481 18,12C18,13.097 18.903,14 20,14C21.097,14 22,13.097 22,12Z"
style="fill:none;fill-rule:nonzero;stroke:rgb(0,144,221);stroke-width:1.05px;" />
</g>
<g
transform="matrix(-5.33921,-5.26159,-3.12106,-6.96393,4073.87,1861.55)">
<path
d="M10.315,5.333C10.315,5.333 9.748,5.921 9.03,6.673C7.768,7.995 6.054,9.805 6.054,9.805L6.237,9.86C6.237,9.86 8.045,8.077 9.36,6.771C10.107,6.028 10.689,5.444 10.689,5.444L10.315,5.333Z"
style="fill:rgb(0,144,221);" />
</g>
</g>
<g id="Padlock" transform="matrix(3.11426,0,0,3.11426,3938.31,1737.25)">
<g>
<path
d="M9.876,21L18.162,21C18.625,21 19,20.625 19,20.162L19,11.838C19,11.375 18.625,11 18.162,11L5.838,11C5.375,11 5,11.375 5,11.838L5,16.758"
style="fill:none;stroke:rgb(34,182,56);stroke-width:1.89px;stroke-linecap:butt;stroke-linejoin:miter;" />
<path
d="M8,11L8,7C8,4.806 9.806,3 12,3C14.194,3 16,4.806 16,7L16,11"
style="fill:none;fill-rule:nonzero;stroke:rgb(34,182,56);stroke-width:1.89px;" />
</g>
</g>
<g>
<g
transform="matrix(5.30977,0.697415,-0.697415,5.30977,3852.72,1727.97)">
<path
d="M22,12C22,11.659 21.913,11.337 21.76,11.055C21.421,10.429 20.756,10 20,10C18.903,10 18,10.903 18,12C18,13.097 18.903,14 20,14C21.097,14 22,13.097 22,12Z"
style="fill:none;fill-rule:nonzero;stroke:rgb(0,144,221);stroke-width:0.98px;" />
</g>
<g
transform="matrix(4.93114,2.49604,1.11018,5.44847,3921.41,1726.72)">
<path
d="M8.902,6.77C8.902,6.77 7.235,8.253 6.027,9.366C5.343,9.996 4.819,10.502 4.819,10.502L5.52,11.164C5.52,11.164 6.021,10.637 6.646,9.951C7.749,8.739 9.219,7.068 9.219,7.068L8.902,6.77Z"
style="fill:rgb(0,144,221);" />
</g>
</g>
</g>
<g id="Wordmark" transform="matrix(1.54159,0,0,2.8744,2710.6,709.804)">
<g id="y" transform="matrix(0.50291,0,0,0.281607,905.533,304.987)">
<path
d="M192.152,286.875L202.629,268.64C187.804,270.106 183.397,265.779 180.143,263.391C176.888,261.004 174.362,257.99 172.563,254.347C170.765,250.705 169.866,246.691 169.866,242.305L169.866,208.107L183.21,208.107L183.21,242.213C183.21,245.188 183.896,247.822 185.268,250.116C186.64,252.41 188.465,254.197 190.743,255.475C193.022,256.754 195.501,257.393 198.182,257.393C200.894,257.393 203.393,256.75 205.68,255.463C207.966,254.177 209.799,252.391 211.178,250.105C212.558,247.818 213.248,245.188 213.248,242.213L213.248,208.107L226.545,208.107L226.545,242.305C226.545,246.707 225.378,258.46 218.079,268.64C215.735,271.909 207.835,286.875 207.835,286.875L192.152,286.875Z"
style="fill:#2e2e2e;fill-rule:nonzero;" />
</g>
<g id="add" transform="matrix(0.525075,0,0,0.281607,801.871,304.987)">
<g transform="matrix(116.242,0,0,116.242,161.846,267.39)">
<path
d="M0.276,0.012C0.227,0.012 0.186,0 0.15,-0.024C0.115,-0.048 0.088,-0.08 0.069,-0.12C0.05,-0.161 0.04,-0.205 0.04,-0.254C0.04,-0.305 0.051,-0.35 0.072,-0.39C0.094,-0.431 0.125,-0.463 0.165,-0.487C0.205,-0.51 0.254,-0.522 0.31,-0.522C0.366,-0.522 0.413,-0.51 0.452,-0.486C0.491,-0.463 0.521,-0.431 0.542,-0.39C0.562,-0.35 0.573,-0.305 0.573,-0.256L0.573,-0L0.458,-0L0.458,-0.095L0.456,-0.095C0.446,-0.076 0.433,-0.058 0.417,-0.042C0.401,-0.026 0.381,-0.013 0.358,-0.003C0.335,0.007 0.307,0.012 0.276,0.012ZM0.307,-0.086C0.337,-0.086 0.363,-0.093 0.386,-0.108C0.408,-0.123 0.426,-0.144 0.438,-0.17C0.45,-0.195 0.456,-0.224 0.456,-0.256C0.456,-0.288 0.45,-0.317 0.438,-0.342C0.426,-0.367 0.409,-0.387 0.387,-0.402C0.365,-0.417 0.338,-0.424 0.308,-0.424C0.276,-0.424 0.249,-0.417 0.226,-0.402C0.204,-0.387 0.186,-0.366 0.174,-0.341C0.162,-0.315 0.156,-0.287 0.156,-0.255C0.156,-0.224 0.162,-0.195 0.174,-0.169C0.186,-0.144 0.203,-0.123 0.226,-0.108C0.248,-0.093 0.275,-0.086 0.307,-0.086Z"
style="fill:#2e2e2e;fill-rule:nonzero;" />
</g>
<g transform="matrix(116.242,0,0,116.242,226.592,267.39)">
<path
d="M0.306,0.012C0.265,0.012 0.229,0.006 0.196,-0.008C0.163,-0.021 0.135,-0.039 0.112,-0.064C0.089,-0.088 0.071,-0.117 0.059,-0.151C0.046,-0.185 0.04,-0.222 0.04,-0.263C0.04,-0.315 0.051,-0.36 0.072,-0.399C0.093,-0.437 0.122,-0.468 0.159,-0.489C0.196,-0.511 0.239,-0.522 0.287,-0.522C0.311,-0.522 0.333,-0.518 0.355,-0.511C0.377,-0.504 0.396,-0.493 0.413,-0.48C0.431,-0.466 0.445,-0.451 0.455,-0.433L0.456,-0.433L0.456,-0.73L0.571,-0.73L0.571,-0.261C0.571,-0.205 0.56,-0.156 0.537,-0.115C0.515,-0.074 0.484,-0.043 0.444,-0.021C0.405,0.001 0.358,0.012 0.306,0.012ZM0.306,-0.086C0.335,-0.086 0.361,-0.093 0.384,-0.107C0.406,-0.122 0.423,-0.141 0.436,-0.167C0.448,-0.192 0.455,-0.221 0.455,-0.255C0.455,-0.288 0.448,-0.317 0.436,-0.343C0.423,-0.368 0.406,-0.388 0.383,-0.402C0.361,-0.417 0.335,-0.424 0.305,-0.424C0.276,-0.424 0.251,-0.417 0.228,-0.402C0.206,-0.387 0.188,-0.368 0.175,-0.342C0.163,-0.317 0.156,-0.288 0.156,-0.255C0.156,-0.222 0.163,-0.193 0.175,-0.167C0.188,-0.142 0.206,-0.122 0.229,-0.108C0.251,-0.093 0.277,-0.086 0.306,-0.086Z"
style="fill:#2e2e2e;fill-rule:nonzero;" />
</g>
<g transform="matrix(116.242,0,0,116.242,290.293,267.39)">
<path
d="M0.306,0.012C0.265,0.012 0.229,0.006 0.196,-0.008C0.163,-0.021 0.135,-0.039 0.112,-0.064C0.089,-0.088 0.071,-0.117 0.059,-0.151C0.046,-0.185 0.04,-0.222 0.04,-0.263C0.04,-0.315 0.051,-0.36 0.072,-0.399C0.093,-0.437 0.122,-0.468 0.159,-0.489C0.196,-0.511 0.239,-0.522 0.287,-0.522C0.311,-0.522 0.333,-0.518 0.355,-0.511C0.377,-0.504 0.396,-0.493 0.413,-0.48C0.431,-0.466 0.445,-0.451 0.455,-0.433L0.456,-0.433L0.456,-0.73L0.571,-0.73L0.571,-0.261C0.571,-0.205 0.56,-0.156 0.537,-0.115C0.515,-0.074 0.484,-0.043 0.444,-0.021C0.405,0.001 0.358,0.012 0.306,0.012ZM0.306,-0.086C0.335,-0.086 0.361,-0.093 0.384,-0.107C0.406,-0.122 0.423,-0.141 0.436,-0.167C0.448,-0.192 0.455,-0.221 0.455,-0.255C0.455,-0.288 0.448,-0.317 0.436,-0.343C0.423,-0.368 0.406,-0.388 0.383,-0.402C0.361,-0.417 0.335,-0.424 0.305,-0.424C0.276,-0.424 0.251,-0.417 0.228,-0.402C0.206,-0.387 0.188,-0.368 0.175,-0.342C0.163,-0.317 0.156,-0.288 0.156,-0.255C0.156,-0.222 0.163,-0.193 0.175,-0.167C0.188,-0.142 0.206,-0.122 0.229,-0.108C0.251,-0.093 0.277,-0.086 0.306,-0.086Z"
style="fill:#2e2e2e;fill-rule:nonzero;" />
</g>
</g>
<g id="c"
transform="matrix(-0.0716462,0.31304,-0.583685,-0.0384251,1489.76,-444.051)">
<path
d="M2668.11,700.4C2666.79,703.699 2666.12,707.216 2666.12,710.766C2666.12,726.268 2678.71,738.854 2694.21,738.854C2709.71,738.854 2722.3,726.268 2722.3,710.766C2722.3,704.111 2719.93,697.672 2715.63,692.597L2707.63,699.378C2710.33,702.559 2711.57,706.602 2711.81,710.766C2712.2,717.38 2706.61,724.52 2697.27,726.637C2683.9,728.581 2676.61,720.482 2676.61,710.766C2676.61,708.541 2677.03,706.336 2677.85,704.269L2668.11,700.4Z"
style="fill:#2e2e2e;" />
</g>
</g>
</g>
<g id="R" transform="matrix(0.497016,0,0,0.497016,2390.38,823.152)">
<g transform="matrix(1,0,0,1,-0.10786,0.450801)">
<g transform="matrix(12.1247,0,0,12.1247,3862.61,1929.9)">
<path
d="M0.073,-0L0.073,-0.7L0.383,-0.7C0.428,-0.7 0.469,-0.69 0.506,-0.67C0.543,-0.651 0.572,-0.623 0.594,-0.588C0.616,-0.553 0.627,-0.512 0.627,-0.465C0.627,-0.418 0.615,-0.377 0.592,-0.342C0.569,-0.306 0.539,-0.279 0.501,-0.259L0.57,-0.128C0.574,-0.12 0.579,-0.115 0.584,-0.111C0.59,-0.107 0.596,-0.106 0.605,-0.106L0.664,-0.106L0.664,-0L0.587,-0C0.56,-0 0.535,-0.007 0.514,-0.02C0.493,-0.034 0.476,-0.052 0.463,-0.075L0.381,-0.232C0.375,-0.231 0.368,-0.231 0.361,-0.231C0.354,-0.231 0.347,-0.231 0.34,-0.231L0.192,-0.231L0.192,-0L0.073,-0ZM0.192,-0.336L0.368,-0.336C0.394,-0.336 0.417,-0.341 0.438,-0.351C0.459,-0.361 0.476,-0.376 0.489,-0.396C0.501,-0.415 0.507,-0.438 0.507,-0.465C0.507,-0.492 0.501,-0.516 0.488,-0.535C0.475,-0.554 0.459,-0.569 0.438,-0.579C0.417,-0.59 0.394,-0.595 0.369,-0.595L0.192,-0.595L0.192,-0.336Z"
style="fill:#2e2e2e;fill-rule:nonzero;" />
</g>
</g>
<g transform="matrix(1,0,0,1,0.278569,0.101881)">
<circle cx="3866.43" cy="1926.14" r="8.923"
style="fill:none;stroke:#2e2e2e;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;" />
</g>
</g>
</g>
</g>
</g>
</svg>
</a>
</div>
</section>
</footer>
</div>
</main>
<footer class="footer">
<p><a href="https://frankenphp.dev">FrankenPHP</a> is an open-source web server for PHP built on top of <a href="https://caddyserver.com">Caddy</a>.</p>
</footer>
</body>
</html>
</html>

View File

@@ -13,8 +13,8 @@ import (
"strings"
"sync"
"github.com/dunglas/frankenphp/internal/memory"
"github.com/dunglas/frankenphp/internal/phpheaders"
"frankenphp.dev/internal/memory"
"frankenphp.dev/internal/phpheaders"
)
// represents the main PHP thread

View File

@@ -12,7 +12,7 @@ import (
"testing"
"time"
"github.com/dunglas/frankenphp/internal/phpheaders"
"frankenphp.dev/internal/phpheaders"
"github.com/stretchr/testify/assert"
)

View File

@@ -7,7 +7,7 @@ import (
"sync"
"sync/atomic"
"github.com/dunglas/frankenphp/internal/fastabs"
"frankenphp.dev/internal/fastabs"
)
// RequestOption instances allow to configure a FrankenPHP Request.

View File

@@ -10,7 +10,7 @@ import (
"sync"
"time"
"github.com/dunglas/frankenphp/internal/cpu"
"frankenphp.dev/internal/cpu"
)
const (

11
testdata/only-headers.php vendored Normal file
View File

@@ -0,0 +1,11 @@
<?php
require_once __DIR__.'/_executor.php';
return function () {
header('Content-Type: application/json');
header('HTTP/1.1 204 No Content', true, 204);
echo '{"status": "test"}';
flush();
};

View File

@@ -8,8 +8,8 @@ import (
"sync"
"time"
"github.com/dunglas/frankenphp/internal/fastabs"
"github.com/dunglas/frankenphp/internal/watcher"
"frankenphp.dev/internal/fastabs"
"frankenphp.dev/internal/watcher"
)
// represents a worker script and can have many threads assigned to it

View File

@@ -15,7 +15,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/dunglas/frankenphp"
"frankenphp.dev"
"github.com/stretchr/testify/assert"
"go.uber.org/zap/exp/zapslog"
"go.uber.org/zap/zapcore"