frankenphp package - github.com/dunglas/frankenphp - Go Packages (original) (raw)

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.

View Source

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](#ErrRejected){"invalid request path", [http](/net/http).[StatusBadRequest](/net/http#StatusBadRequest)}
ErrInvalidContentLengthHeader = [ErrRejected](#ErrRejected){"invalid Content-Length header", [http](/net/http).[StatusBadRequest](/net/http#StatusBadRequest)}
ErrMaxWaitTimeExceeded        = [ErrRejected](#ErrRejected){"maximum request handling time exceeded", [http](/net/http).[StatusServiceUnavailable](/net/http#StatusServiceUnavailable)}

)

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

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 zval having a zend_array value to an unordered Go map

EXPERIMENTAL: GoPackedArray converts a zval with a zend_array value 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 curently only be converted to any[] and AssociativeArray[any]. Any other type will cause an error. More types may be supported in the future.

func Init(options ...Option) error

Init starts the PHP runtime and the configured workers.

NewRequestWithContext creates a new FrankenPHP request context.

EXPERIMENTAL: PHPAssociativeArray converts a Go AssociativeArray to a PHP zval with a zend_array value

EXPERIMENTAL: PHPMap converts an unordered Go map to a PHP 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

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](/builtin#string))

ReadyWorker(name [string](/builtin#string))

StopWorker(name [string](/builtin#string), reason [StopReason](#StopReason))

TotalWorkers(name [string](/builtin#string), num [int](/builtin#int))

TotalThreads(num [int](/builtin#int))

StartRequest()

StopRequest()

StopWorkerRequest(name [string](/builtin#string), duration [time](/time).[Duration](/time#Duration))

StartWorkerRequest(name [string](/builtin#string))
Shutdown()
QueuedWorkerRequest(name [string](/builtin#string))
DequeuedWorkerRequest(name [string](/builtin#string))
QueuedRequest()
DequeuedRequest()

}

type Option func(h *opt) error

Option instances allow to configure FrankenPHP.

WithContext sets the main context to use.

WithLogger configures the global logger to use.

func WithMaxThreads(maxThreads int) Option

WithMaxWaitTime configures the max time a request may be stalled waiting for a thread.

func WithMetrics(m Metrics) Option

func WithNumThreads(numThreads int) Option

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.

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.

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

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.