frankenphp package - github.com/dunglas/frankenphp - Go Packages
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.
- Constants
- Variables
- func CallPHPCallable(cb unsafe.Pointer, params []interface{}) interface{}
- func DrainWorkers()
- func ExecutePHPCode(phpCode string) int
- func ExecuteScriptCLI(script string, args []string) int
- func GoMap[T any](arr unsafe.Pointer) (map[string]T, error)
- func GoPackedArray[T any](arr unsafe.Pointer) ([]T, error)
- func GoString(s unsafe.Pointer) string
- func GoValue[T any](zval unsafe.Pointer) (T, error)
- func Init(options ...Option) error
- func IsPacked(arr unsafe.Pointer) bool
- func NewRequestWithContext(r *http.Request, opts ...RequestOption) (*http.Request, error)
- func PHPAssociativeArray[T any](arr AssociativeArray[T]) unsafe.Pointer
- func PHPMap[T any](arr map[string]T) unsafe.Pointer
- func PHPPackedArray[T any](slice []T) unsafe.Pointer
- func PHPString(s string, persistent bool) unsafe.Pointer
- func PHPValue(value any) unsafe.Pointer
- func RegisterExtension(me unsafe.Pointer)
- func RestartWorkers()
- func ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) error
- func Shutdown()
- func WithExtensionWorkers(name, fileName string, numThreads int, options ...WorkerOption) (Workers, Option)
- type AssociativeArray
- type ErrRejected
- type FrankenPHPDebugState
- type Metrics
- type Option
- func WithContext(ctx context.Context) Option
- func WithHotReload(topic string, hub *mercure.Hub, patterns []string) Option
- func WithLogger(l *slog.Logger) Option
- func WithMaxIdleTime(maxIdleTime time.Duration) Option
- func WithMaxThreads(maxThreads int) Option
- func WithMaxWaitTime(maxWaitTime time.Duration) Option
- func WithMetrics(m Metrics) Option
- func WithNumThreads(numThreads int) Option
- func WithPhpIni(overrides map[string]string) Option
- func WithWorkers(name, fileName string, num int, options ...WorkerOption) Option
- type PHPConfig
- type PHPVersion
- type PreparedEnv
- type PrometheusMetrics
- func (m *PrometheusMetrics) DequeuedRequest()
- func (m *PrometheusMetrics) DequeuedWorkerRequest(name string)
- func (m *PrometheusMetrics) QueuedRequest()
- func (m *PrometheusMetrics) QueuedWorkerRequest(name string)
- func (m *PrometheusMetrics) ReadyWorker(name string)
- func (m *PrometheusMetrics) Shutdown()
- func (m *PrometheusMetrics) StartRequest()
- func (m *PrometheusMetrics) StartWorker(name string)
- func (m *PrometheusMetrics) StartWorkerRequest(name string)
- func (m *PrometheusMetrics) StopRequest()
- func (m *PrometheusMetrics) StopWorker(name string, reason StopReason)
- func (m *PrometheusMetrics) StopWorkerRequest(name string, duration time.Duration)
- func (m *PrometheusMetrics) TotalThreads(num int)
- func (m *PrometheusMetrics) TotalWorkers(string, int)
- type RequestOption
- func WithMercureHub(hub *mercure.Hub) RequestOption
- func WithOriginalRequest(r *http.Request) RequestOption
- func WithRequestDocumentRoot(documentRoot string, resolveSymlink bool) RequestOption
- func WithRequestEnv(env map[string]string) RequestOption
- func WithRequestLogger(logger *slog.Logger) RequestOption
- func WithRequestPreparedEnv(env PreparedEnv) RequestOption
- func WithRequestResolvedDocumentRoot(documentRoot string) RequestOption
- func WithRequestSplitPath(splitPath []string) (RequestOption, error)
- func WithWorkerName(name string) RequestOption
- type StopReason
- type ThreadDebugState
- type WorkerOption
- func WithWorkerEnv(env map[string]string) WorkerOption
- func WithWorkerMaxFailures(maxFailures int) WorkerOption
- func WithWorkerMaxThreads(num int) WorkerOption
- func WithWorkerMercureHub(hub *mercure.Hub) WorkerOption
- func WithWorkerOnReady(f func(int)) WorkerOption
- func WithWorkerOnServerShutdown(f func()) WorkerOption
- func WithWorkerOnServerStartup(f func()) WorkerOption
- func WithWorkerOnShutdown(f func(int)) WorkerOption
- func WithWorkerRequestOptions(options ...RequestOption) WorkerOption
- func WithWorkerWatchMode(watch []string) WorkerOption
- type Workers
const ( StopReasonCrash = iota StopReasonRestart StopReasonBootFailure )
var ( ErrInvalidRequest = errors.New("not a FrankenPHP request") ErrAlreadyStarted = errors.New("FrankenPHP is already started") ErrInvalidPHPVersion = errors.New("FrankenPHP is only compatible with PHP 8.2+") ErrMainThreadCreation = errors.New("error creating the main thread") ErrScriptExecution = errors.New("error during PHP script execution") ErrNotRunning = errors.New("FrankenPHP is not running. For proper configuration visit: https://frankenphp.dev/docs/config/#caddyfile-config") ErrInvalidRequestPath = ErrRejected{"invalid request path", http.StatusBadRequest} ErrInvalidContentLengthHeader = ErrRejected{"invalid Content-Length header", http.StatusBadRequest} ErrMaxWaitTimeExceeded = ErrRejected{"maximum request handling time exceeded", http.StatusServiceUnavailable} )
EmbeddedAppPath contains the path of the embedded PHP application (empty if none). It can be set at build time using -ldflags to override the default extraction path:
go build -ldflags "-X github.com/dunglas/frankenphp.EmbeddedAppPath=/app" ...
When set, the embedded app is extracted to this fixed path instead of a temp directory with a checksum suffix. This is useful when the app contains pre-compiled artifacts (e.g. OPcache file cache) that reference absolute paths and need a predictable extraction location.
EXPERIMENTAL: CallPHPCallable executes a PHP callable with the given parameters. Returns the result of the callable as a Go interface{}, or nil if the call failed.
EXPERIMENTAL: DrainWorkers finishes all worker scripts before a graceful shutdown
ExecuteScriptCLI executes the PHP script passed as parameter. It returns the exit status code of the script.
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))
}
EXPERIMENTAL: GoMap converts a zend_array to an unordered Go map
EXPERIMENTAL: GoPackedArray converts a zend_array to a Go slice
EXPERIMENTAL: GoString copies a zend_string to a Go string.
EXPERIMENTAL: GoValue converts a PHP zval to a Go value
Zval having the null, bool, long, double, string and array types are currently supported. Arrays can currently only be converted to any[] and AssociativeArray[any]. Any other type will cause an error. More types may be supported in the future.
IsPacked determines if the given zend_array is a packed array (list). Returns false if the array is nil or not packed.
NewRequestWithContext creates a new FrankenPHP request context.
EXPERIMENTAL: PHPAssociativeArray converts a Go AssociativeArray to a zend_array
EXPERIMENTAL: PHPMap converts an unordered Go map to a zend_array
EXPERIMENTAL: PHPPackedArray converts a Go slice to a PHP zval with a zend_array value.
EXPERIMENTAL: PHPString converts a Go string to a zend_string with copy. The string can be non-persistent (automatically freed after the request by the ZMM) or persistent. If you choose the second mode, it is your repsonsability to free the allocated memory.
EXPERIMENTAL: PHPValue converts a Go any to a PHP zval
nil, bool, int, int64, float64, string, []any, and map[string]any are currently supported. Any other type will cause a panic. More types may be supported in the future.
RegisterExtension registers a new PHP extension.
RestartWorkers attempts to restart all workers gracefully All workers must be restarted at the same time to prevent issues with opcache resetting.
ServeHTTP executes a PHP script according to the given context.
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))
}
package main
import (
"log"
"net/http"
"github.com/dunglas/frankenphp"
)
func main() {
if err := frankenphp.Init(
frankenphp.WithWorkers("worker1", "worker1.php", 4,
frankenphp.WithWorkerEnv(map[string]string{"ENV1": "foo"}),
frankenphp.WithWorkerWatchMode([]string{}),
frankenphp.WithWorkerMaxFailures(0),
),
frankenphp.WithWorkers("worker2", "worker2.php", 2,
frankenphp.WithWorkerEnv(map[string]string{"ENV2": "bar"}),
frankenphp.WithWorkerWatchMode([]string{}),
frankenphp.WithWorkerMaxFailures(0),
),
); 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))
}
Shutdown stops the workers and the PHP runtime.
func WithExtensionWorkers(name, fileName string, numThreads int, options ...WorkerOption) (Workers, Option)
EXPERIMENTAL: WithExtensionWorkers allow extensions to create workers.
A worker script with the provided name, fileName and thread count will be registered, along with additional configuration through WorkerOptions.
Workers are designed to run indefinitely and will be gracefully shut down when FrankenPHP shuts down.
Extension workers receive the lowest priority when determining thread allocations. If the requested number of threads cannot be allocated, then FrankenPHP will panic and provide this information to the user (who will need to allocate more total threads). Don't be greedy.
AssociativeArray represents a PHP array with ordered key-value pairs
EXPERIMENTAL: GoAssociativeArray converts a zend_array to a Go AssociativeArray
type ErrRejected struct {
}
type FrankenPHPDebugState struct {
ThreadDebugStates []ThreadDebugState
ReservedThreadCount int
}
EXPERIMENTAL: FrankenPHPDebugState prints the state of all PHP threads - debugging purposes only
func DebugState() FrankenPHPDebugState
EXPERIMENTAL: DebugState prints the state of all PHP threads - debugging purposes only
type Metrics interface {
StartWorker(name string)
ReadyWorker(name string)
StopWorker(name string, reason StopReason)
TotalWorkers(name string, num int)
TotalThreads(num int)
StartRequest()
StopRequest()
StopWorkerRequest(name string, duration time.Duration)
StartWorkerRequest(name string)
Shutdown()
QueuedWorkerRequest(name string)
DequeuedWorkerRequest(name string)
QueuedRequest()
DequeuedRequest()
}
type Option func(h *opt) error
Option instances allow to configure FrankenPHP.
WithContext sets the main context to use.
WithHotReload sets files to watch for file changes to trigger a hot reload update.
WithLogger configures the global logger to use.
WithMaxIdleTime configures the max time an autoscaled thread may be idle before being deactivated.
WithMaxWaitTime configures the max time a request may be stalled waiting for a thread.
WithNumThreads configures the number of PHP threads to start.
WithPhpIni configures user defined PHP ini settings.
func WithWorkers(name, fileName string, num int, options ...WorkerOption) Option
WithWorkers configures the PHP workers to start
type PHPConfig struct {
Version PHPVersion
ZTS bool
ZendSignals bool
ZendMaxExecutionTimers bool
}
type PHPVersion struct {
MajorVersion int
MinorVersion int
ReleaseVersion int
Version string
VersionID int
}
func Version() PHPVersion
Version returns infos about the PHP version.
type PrometheusMetrics struct {
}
func (m *PrometheusMetrics) DequeuedRequest()
func (m *PrometheusMetrics) DequeuedWorkerRequest(name string)
func (m *PrometheusMetrics) QueuedRequest()
func (m *PrometheusMetrics) QueuedWorkerRequest(name string)
func (m *PrometheusMetrics) Shutdown()
func (m *PrometheusMetrics) StartRequest()
func (m *PrometheusMetrics) StartWorkerRequest(name string)
func (m *PrometheusMetrics) StopRequest()
func (m *PrometheusMetrics) TotalThreads(num int)
type RequestOption func(h *frankenPHPContext) error
RequestOption instances allow to configure a FrankenPHP Request.
WithMercureHub sets the mercure.Hub to use to publish updates
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.
WithRequestEnv set CGI-like environment variables that will be available in $_SERVER. Values set with WithEnv always have priority over automatically populated values.
WithRequestLogger sets the logger associated with the current request
func WithRequestPreparedEnv(env PreparedEnv) RequestOption
func WithRequestResolvedDocumentRoot(documentRoot string) RequestOption
WithRequestResolvedDocumentRoot is similar to WithRequestDocumentRoot but doesn't do any checks or resolving on the path to improve performance.
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.
Split paths can only contain ASCII characters. Comparison is case-insensitive.
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.
WithWorkerName sets the worker that should handle the request
EXPERIMENTAL: ThreadDebugState prints the state of a single PHP thread - debugging purposes only
type WorkerOption func(*workerOpt) error
WorkerOption instances allow configuring FrankenPHP worker.
WithWorkerEnv sets environment variables for the worker
func WithWorkerMaxFailures(maxFailures int) WorkerOption
WithWorkerMaxFailures sets the maximum number of consecutive failures before panicking
func WithWorkerMaxThreads(num int) WorkerOption
WithWorkerMaxThreads sets the max number of threads for this specific worker
WithWorkerMercureHub sets the mercure.Hub in the worker script and used to dispatch hot reloading-related mercure.Update.
func WithWorkerOnReady(f func(int)) WorkerOption
func WithWorkerOnServerShutdown(f func()) WorkerOption
WithWorkerOnServerShutdown adds a function to be called right before server shutdown. Useful for extensions.
func WithWorkerOnServerStartup(f func()) WorkerOption
WithWorkerOnServerStartup adds a function to be called right after server startup. Useful for extensions.
func WithWorkerOnShutdown(f func(int)) WorkerOption
func WithWorkerRequestOptions(options ...RequestOption) WorkerOption
WithWorkerRequestOptions sets options for the main dummy request created for the worker
func WithWorkerWatchMode(watch []string) WorkerOption
WithWorkerWatchMode sets directories to watch for file changes
EXPERIMENTAL: Workers allows you to register a worker.