diff --git a/caddy/br.go b/caddy/br.go index 6522cb67a4..48d7741c3e 100644 --- a/caddy/br.go +++ b/caddy/br.go @@ -2,4 +2,21 @@ package caddy +import ( + "runtime/debug" + + "github.com/dunglas/frankenphp" +) + var brotli = true + +func init() { + if buildInfo, ok := debug.ReadBuildInfo(); ok { + for _, dep := range buildInfo.Deps { + if dep.Path == "github.com/dunglas/caddy-cbrotli" { + frankenphp.AddPhpinfoEntry("dunglas/caddy-cbrotli", dep.Version) + break + } + } + } +} diff --git a/caddy/caddy.go b/caddy/caddy.go index 9cbc219f3d..f203f8f659 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -9,6 +9,7 @@ import ( "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile" + "github.com/dunglas/frankenphp" ) const ( @@ -26,6 +27,14 @@ func init() { caddy.RegisterModule(FrankenPHPModule{}) caddy.RegisterModule(FrankenPHPAdmin{}) + // Report Caddy version in phpinfo() + simpleVersion, fullVersion := caddy.Version() + if fullVersion != "" { + frankenphp.AddPhpinfoEntry("caddy", fullVersion) + } else if simpleVersion != "" { + frankenphp.AddPhpinfoEntry("caddy", simpleVersion) + } + httpcaddyfile.RegisterGlobalOption("frankenphp", parseGlobalOption) httpcaddyfile.RegisterHandlerDirective("php", parseCaddyfile) diff --git a/cli.go b/cli.go index 96821a2392..a91a8c5df2 100644 --- a/cli.go +++ b/cli.go @@ -9,6 +9,7 @@ import "unsafe" func ExecuteScriptCLI(script string, args []string) int { // Ensure extensions are registered before CLI execution registerExtensions() + initPhpinfoEntries() cScript := C.CString(script) defer C.free(unsafe.Pointer(cScript)) @@ -22,6 +23,7 @@ func ExecuteScriptCLI(script string, args []string) int { func ExecutePHPCode(phpCode string) int { // Ensure extensions are registered before CLI execution registerExtensions() + initPhpinfoEntries() cCode := C.CString(phpCode) defer C.free(unsafe.Pointer(cCode)) diff --git a/frankenphp.c b/frankenphp.c index a47b6d80a7..acf625018e 100644 --- a/frankenphp.c +++ b/frankenphp.c @@ -6,6 +6,7 @@ #include #include #include +#include #ifdef HAVE_PHP_SESSION #include #endif @@ -107,6 +108,8 @@ frankenphp_config frankenphp_get_config() { }; } +const char **frankenphp_phpinfo_entries = NULL; + bool should_filter_var = 0; bool original_user_abort_setting = 0; frankenphp_interned_strings_t frankenphp_strings = {0}; @@ -1101,6 +1104,18 @@ PHP_MINIT_FUNCTION(frankenphp) { return SUCCESS; } +PHP_MINFO_FUNCTION(frankenphp) { + php_info_print_table_start(); + php_info_print_table_row(2, "frankenphp", TOSTRING(FRANKENPHP_VERSION)); + if (frankenphp_phpinfo_entries) { + for (int i = 0; frankenphp_phpinfo_entries[i] != NULL; i += 2) { + php_info_print_table_row(2, frankenphp_phpinfo_entries[i], + frankenphp_phpinfo_entries[i + 1]); + } + } + php_info_print_table_end(); +} + static zend_module_entry frankenphp_module = { STANDARD_MODULE_HEADER, "frankenphp", @@ -1109,7 +1124,7 @@ static zend_module_entry frankenphp_module = { NULL, /* shutdown */ NULL, /* request initialization */ NULL, /* request shutdown */ - NULL, /* information */ + PHP_MINFO(frankenphp), /* information */ TOSTRING(FRANKENPHP_VERSION), STANDARD_MODULE_PROPERTIES}; diff --git a/frankenphp.go b/frankenphp.go index ad2dedc42a..555ca0a688 100644 --- a/frankenphp.go +++ b/frankenphp.go @@ -30,6 +30,7 @@ import ( "os" "os/signal" "runtime" + "sort" "strings" "sync" "sync/atomic" @@ -37,7 +38,7 @@ import ( "time" "unsafe" // debug on Linux - //_ "github.com/ianlancetaylor/cgosymbolizer" + // _ "github.com/ianlancetaylor/cgosymbolizer" ) type contextKeyStruct struct{} @@ -156,6 +157,49 @@ func Config() PHPConfig { } } +type phpinfoEntry struct { + key, value string +} + +var ( + phpinfoEntries []phpinfoEntry + cPhpinfoArr []*C.char +) + +func AddPhpinfoEntry(key, value string) { + phpinfoEntries = append(phpinfoEntries, phpinfoEntry{key, value}) +} + +func initPhpinfoEntries() { + for _, cstr := range cPhpinfoArr { + if cstr != nil { + C.free(unsafe.Pointer(cstr)) + } + } + if cPhpinfoArr != nil { + C.free(unsafe.Pointer(&cPhpinfoArr[0])) + cPhpinfoArr = nil + C.frankenphp_phpinfo_entries = nil + } + + if len(phpinfoEntries) == 0 { + return + } + + sort.Slice(phpinfoEntries, func(i, j int) bool { + return phpinfoEntries[i].key < phpinfoEntries[j].key + }) + + n := 2*len(phpinfoEntries) + 1 + cPhpinfoArr = (*[1 << 28]*C.char)(C.malloc(C.size_t(n) * C.size_t(unsafe.Sizeof(uintptr(0)))))[:n:n] + for i, e := range phpinfoEntries { + cPhpinfoArr[2*i] = C.CString(e.key) + cPhpinfoArr[2*i+1] = C.CString(e.value) + } + cPhpinfoArr[n-1] = nil + C.frankenphp_phpinfo_entries = &cPhpinfoArr[0] +} + func calculateMaxThreads(opt *opt) (numWorkers int, _ error) { maxProcs := runtime.GOMAXPROCS(0) * 2 maxThreadsFromWorkers := 0 @@ -250,6 +294,7 @@ func Init(options ...Option) error { signal.Ignore(syscall.SIGPIPE) registerExtensions() + initPhpinfoEntries() opt := &opt{} for _, o := range options { diff --git a/frankenphp.h b/frankenphp.h index db32a82fe0..f23f81a385 100644 --- a/frankenphp.h +++ b/frankenphp.h @@ -74,6 +74,10 @@ typedef struct { #define STRINGIFY(x) #x #define TOSTRING(x) STRINGIFY(x) +/* phpinfo entries from Go - null-terminated array of key, value, key, value, + * ... */ +extern const char **frankenphp_phpinfo_entries; + typedef struct go_string { size_t len; char *data; diff --git a/mercure.go b/mercure.go index d7cf33609e..80c4370034 100644 --- a/mercure.go +++ b/mercure.go @@ -8,11 +8,23 @@ package frankenphp import "C" import ( "log/slog" + "runtime/debug" "unsafe" "github.com/dunglas/mercure" ) +func init() { + if buildInfo, ok := debug.ReadBuildInfo(); ok { + for _, dep := range buildInfo.Deps { + if dep.Path == "github.com/dunglas/mercure" { + AddPhpinfoEntry("dunglas/mercure", dep.Version) + break + } + } + } +} + type mercureContext struct { mercureHub *mercure.Hub } diff --git a/watcher.go b/watcher.go index cfe133e5ab..587178900b 100644 --- a/watcher.go +++ b/watcher.go @@ -3,12 +3,25 @@ package frankenphp import ( + "runtime/debug" "sync/atomic" "github.com/dunglas/frankenphp/internal/watcher" watcherGo "github.com/e-dant/watcher/watcher-go" ) +func init() { + // watcher doesn't expose the version, so get it from go.mod + if buildInfo, ok := debug.ReadBuildInfo(); ok { + for _, dep := range buildInfo.Deps { + if dep.Path == "github.com/e-dant/watcher" { + AddPhpinfoEntry("e-dant/watcher", dep.Version) + break + } + } + } +} + type hotReloadOpt struct { hotReload []*watcher.PatternGroup }