frankenphp

package module
v1.3.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 22, 2024 License: MIT Imports: 33 Imported by: 3

README

FrankenPHP: Modern App Server for PHP

FrankenPHP

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

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

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

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

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

Slides

Getting Started

Docker
docker run -v .:/app/public \
    -p 80:80 -p 443:443 -p 443:443/udp \
    dunglas/frankenphp

Go to https://localhost, and enjoy!

[!TIP]

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

Standalone Binary

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

On Windows, use WSL to run FrankenPHP.

Download FrankenPHP or copy this line into your terminal to automatically install the version appropriate for your platform:

curl https://frankenphp.dev/install.sh | sh
mv frankenphp /usr/local/bin/

To serve the content of the current directory, run:

frankenphp php-server

You can also run command-line scripts with:

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

Docs

Examples and Skeletons

Documentation

Overview

Package frankenphp embeds PHP in Go projects and provides a SAPI for net/http.

This is the core of the FrankenPHP app server, and can be used in any Go program.

Index

Examples

Constants

View Source
const (
	StopReasonCrash = iota
	StopReasonRestart
	StopReasonShutdown
)

Variables

View Source
var (
	InvalidRequestError         = errors.New("not a FrankenPHP request")
	AlreadyStartedError         = errors.New("FrankenPHP is already started")
	InvalidPHPVersionError      = errors.New("FrankenPHP is only compatible with PHP 8.2+")
	NotEnoughThreads            = errors.New("the number of threads must be superior to the number of workers")
	MainThreadCreationError     = errors.New("error creating the main thread")
	RequestContextCreationError = errors.New("error during request context creation")
	ScriptExecutionError        = errors.New("error during PHP script execution")
)
View Source
var EmbeddedAppPath string

EmbeddedAppPath contains the path of the embedded PHP application (empty if none)

View Source
var MaxThreads int

MaxThreads is internally used during tests. It is written to, but never read and may go away in the future.

Functions

func ExecuteScriptCLI

func ExecuteScriptCLI(script string, args []string) int

ExecuteScriptCLI executes the PHP script passed as parameter. It returns the exit status code of the script.

Example
package main

import (
	"log"
	"os"

	"github.com/dunglas/frankenphp"
)

func main() {
	if len(os.Args) <= 1 {
		log.Println("Usage: my-program script.php")
		os.Exit(1)
	}

	os.Exit(frankenphp.ExecuteScriptCLI(os.Args[1], os.Args))
}
Output:

func Init

func Init(options ...Option) error

Init starts the PHP runtime and the configured workers.

func NewRequestWithContext

func NewRequestWithContext(r *http.Request, opts ...RequestOption) (*http.Request, error)

NewRequestWithContext creates a new FrankenPHP request context.

func ServeHTTP

func ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) error

ServeHTTP executes a PHP script according to the given context.

Example
package main

import (
	"log"
	"net/http"

	"github.com/dunglas/frankenphp"
)

func main() {
	if err := frankenphp.Init(); err != nil {
		panic(err)
	}
	defer frankenphp.Shutdown()

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		req, err := frankenphp.NewRequestWithContext(r, frankenphp.WithRequestDocumentRoot("/path/to/document/root", false))
		if err != nil {
			panic(err)
		}

		if err := frankenphp.ServeHTTP(w, req); err != nil {
			panic(err)
		}
	})
	log.Fatal(http.ListenAndServe(":8080", nil))
}
Output:

Example (Workers)
package main

import (
	"log"
	"net/http"

	"github.com/dunglas/frankenphp"
)

func main() {
	if err := frankenphp.Init(
		frankenphp.WithWorkers("worker1.php", 4, map[string]string{"ENV1": "foo"}, []string{}),
		frankenphp.WithWorkers("worker2.php", 2, map[string]string{"ENV2": "bar"}, []string{}),
	); err != nil {
		panic(err)
	}
	defer frankenphp.Shutdown()

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		req, err := frankenphp.NewRequestWithContext(r, frankenphp.WithRequestDocumentRoot("/path/to/document/root", false))
		if err != nil {
			panic(err)
		}

		if err := frankenphp.ServeHTTP(w, req); err != nil {
			panic(err)
		}
	})
	log.Fatal(http.ListenAndServe(":8080", nil))
}
Output:

func Shutdown

func Shutdown()

Shutdown stops the workers and the PHP runtime.

Types

type FrankenPHPContext

type FrankenPHPContext struct {
	// contains filtered or unexported fields
}

FrankenPHPContext provides contextual information about the Request to handle.

func FromContext

func FromContext(ctx context.Context) (fctx *FrankenPHPContext, ok bool)

FromContext extracts the FrankenPHPContext from a context.

type Metrics added in v1.3.0

type Metrics interface {
	// StartWorker collects started workers
	StartWorker(name string)
	// ReadyWorker collects ready workers
	ReadyWorker(name string)
	// StopWorker collects stopped workers
	StopWorker(name string, reason StopReason)
	// TotalWorkers collects expected workers
	TotalWorkers(name string, num int)
	// TotalThreads collects total threads
	TotalThreads(num int)
	// StartRequest collects started requests
	StartRequest()
	// StopRequest collects stopped requests
	StopRequest()
	// StopWorkerRequest collects stopped worker requests
	StopWorkerRequest(name string, duration time.Duration)
	// StartWorkerRequest collects started worker requests
	StartWorkerRequest(name string)
	Shutdown()
}

type Option

type Option func(h *opt) error

Option instances allow to configure FrankenPHP.

func WithLogger

func WithLogger(l *zap.Logger) Option

WithLogger configures the global logger to use.

func WithMetrics added in v1.3.0

func WithMetrics(m Metrics) Option

func WithNumThreads

func WithNumThreads(numThreads int) Option

WithNumThreads configures the number of PHP threads to start.

func WithWorkers

func WithWorkers(fileName string, num int, env map[string]string, watch []string) Option

WithWorkers configures the PHP workers to start.

type PHPConfig

type PHPConfig struct {
	Version                PHPVersion
	ZTS                    bool
	ZendSignals            bool
	ZendMaxExecutionTimers bool
}

func Config

func Config() PHPConfig

type PHPVersion

type PHPVersion struct {
	MajorVersion   int
	MinorVersion   int
	ReleaseVersion int
	ExtraVersion   string
	Version        string
	VersionID      int
}

func Version

func Version() PHPVersion

Version returns infos about the PHP version.

type PreparedEnv added in v1.1.1

type PreparedEnv = map[string]string

func PrepareEnv added in v1.1.1

func PrepareEnv(env map[string]string) PreparedEnv

type PrometheusMetrics added in v1.3.0

type PrometheusMetrics struct {
	// contains filtered or unexported fields
}

func NewPrometheusMetrics added in v1.3.0

func NewPrometheusMetrics(registry prometheus.Registerer) *PrometheusMetrics

func (*PrometheusMetrics) ReadyWorker added in v1.3.0

func (m *PrometheusMetrics) ReadyWorker(name string)

func (*PrometheusMetrics) Shutdown added in v1.3.0

func (m *PrometheusMetrics) Shutdown()

func (*PrometheusMetrics) StartRequest added in v1.3.0

func (m *PrometheusMetrics) StartRequest()

func (*PrometheusMetrics) StartWorker added in v1.3.0

func (m *PrometheusMetrics) StartWorker(name string)

func (*PrometheusMetrics) StartWorkerRequest added in v1.3.0

func (m *PrometheusMetrics) StartWorkerRequest(name string)

func (*PrometheusMetrics) StopRequest added in v1.3.0

func (m *PrometheusMetrics) StopRequest()

func (*PrometheusMetrics) StopWorker added in v1.3.0

func (m *PrometheusMetrics) StopWorker(name string, reason StopReason)

func (*PrometheusMetrics) StopWorkerRequest added in v1.3.0

func (m *PrometheusMetrics) StopWorkerRequest(name string, duration time.Duration)

func (*PrometheusMetrics) TotalThreads added in v1.3.0

func (m *PrometheusMetrics) TotalThreads(num int)

func (*PrometheusMetrics) TotalWorkers added in v1.3.0

func (m *PrometheusMetrics) TotalWorkers(name string, _ int)

type RequestOption

type RequestOption func(h *FrankenPHPContext) error

RequestOption instances allow to configure a FrankenPHP Request.

func WithRequestDocumentRoot

func WithRequestDocumentRoot(documentRoot string, resolveSymlink bool) RequestOption

WithRequestDocumentRoot sets the root directory of the PHP application. if resolveSymlink is true, oath declared as root directory will be resolved to its absolute value after the evaluation of any symbolic links. Due to the nature of PHP opcache, root directory path is cached: when using a symlinked directory as root this could generate errors when symlink is changed without PHP being restarted; enabling this directive will set $_SERVER['DOCUMENT_ROOT'] to the real directory path.

func WithRequestEnv

func WithRequestEnv(env map[string]string) RequestOption

WithRequestEnv set CGI-like environment variables that will be available in $_SERVER. Values set with WithEnv always have priority over automatically populated values.

func WithRequestLogger

func WithRequestLogger(logger *zap.Logger) RequestOption

WithRequestLogger sets the logger associated with the current request

func WithRequestPreparedEnv added in v1.1.1

func WithRequestPreparedEnv(env PreparedEnv) RequestOption

func WithRequestResolvedDocumentRoot added in v1.2.5

func WithRequestResolvedDocumentRoot(documentRoot string) RequestOption

WithRequestResolvedDocumentRoot is similar to WithRequestDocumentRoot but doesn't do any checks or resolving on the path to improve performance.

func WithRequestSplitPath

func WithRequestSplitPath(splitPath []string) RequestOption

WithRequestSplitPath contains a list of split path strings.

The path in the URL will be split into two, with the first piece ending with the value of splitPath. The first piece will be assumed as the actual resource (CGI script) name, and the second piece will be set to PATH_INFO for the CGI script to use.

Future enhancements should be careful to avoid CVE-2019-11043, which can be mitigated with use of a try_files-like behavior that 404s if the FastCGI path info is not found.

type StopReason added in v1.3.0

type StopReason int

Directories

Path Synopsis
caddy module
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL