Skip to content

Commit 6bd99fb

Browse files
author
mirkobrombin
committed
feat: add PHP plugin with PHP-FPM support
- Implemented PHPPlugin to handle PHP scripts using php-fpm - Added middleware to dynamically route `.php` requests to the configured php-fpm backend - Registered PHPPlugin in the main plugin manager - Added a sample `test.php` file for testing PHP support
1 parent 18cd39c commit 6bd99fb

File tree

3 files changed

+124
-0
lines changed

3 files changed

+124
-0
lines changed

cmd/goup/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ func main() {
1111

1212
// Register your plugins here:
1313
pluginManager.Register(&plugins.CustomHeaderPlugin{})
14+
pluginManager.Register(&plugins.PHPPlugin{})
1415

1516
cli.Execute()
1617
}

plugins/php.go

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package plugins
2+
3+
import (
4+
"net/http"
5+
"os"
6+
"path/filepath"
7+
"strings"
8+
9+
"github.com/mirkobrombin/goup/internal/config"
10+
"github.com/mirkobrombin/goup/internal/server/middleware"
11+
log "github.com/sirupsen/logrus"
12+
"github.com/yookoala/gofast"
13+
)
14+
15+
// PHPPlugin handles the execution of PHP scripts via PHP-FPM.
16+
type PHPPlugin struct{}
17+
18+
// Name returns the name of the plugin.
19+
func (p *PHPPlugin) Name() string {
20+
return "PHPPlugin"
21+
}
22+
23+
// Init registers any global middleware (none for PHPPlugin).
24+
func (p *PHPPlugin) Init(mwManager *middleware.MiddlewareManager) error {
25+
return nil
26+
}
27+
28+
// InitForSite initializes the plugin for a specific site.
29+
func (p *PHPPlugin) InitForSite(mwManager *middleware.MiddlewareManager, logger *log.Logger, conf config.SiteConfig) error {
30+
mwManager.Use(p.phpMiddleware(logger, conf))
31+
return nil
32+
}
33+
34+
// PHPPluginConfig represents the configuration for the PHPPlugin.
35+
type PHPPluginConfig struct {
36+
Enable bool `json:"enable"`
37+
FPMAddr string `json:"fpm_addr"`
38+
}
39+
40+
// phpMiddleware is the middleware that handles PHP requests.
41+
func (p *PHPPlugin) phpMiddleware(logger *log.Logger, conf config.SiteConfig) middleware.MiddlewareFunc {
42+
return func(next http.Handler) http.Handler {
43+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
44+
45+
// Retrieve site-specific plugin configuration.
46+
pluginConfigRaw, ok := conf.PluginConfigs[p.Name()]
47+
if !ok {
48+
logger.Warnf("Plugin config not found for host: %s", r.Host)
49+
next.ServeHTTP(w, r)
50+
return
51+
}
52+
53+
// FIXME: find a better way to map the configuration, currently
54+
// it is like this due to fpm_addr not being unmarshalled correctly.
55+
pluginConfig := PHPPluginConfig{}
56+
if rawMap, ok := pluginConfigRaw.(map[string]interface{}); ok {
57+
if enable, ok := rawMap["enable"].(bool); ok {
58+
pluginConfig.Enable = enable
59+
}
60+
if fpmAddr, ok := rawMap["fpm_addr"].(string); ok {
61+
pluginConfig.FPMAddr = fpmAddr
62+
}
63+
}
64+
65+
if !pluginConfig.Enable {
66+
logger.Infof("PHP Plugin is disabled for host: %s", r.Host)
67+
next.ServeHTTP(w, r)
68+
return
69+
}
70+
71+
// We only handle PHP requests here.
72+
if strings.HasSuffix(r.URL.Path, ".php") {
73+
logger.Infof("Handling PHP request: %s", r.URL.Path)
74+
75+
phpFPMAddr := pluginConfig.FPMAddr
76+
if phpFPMAddr == "" {
77+
phpFPMAddr = "127.0.0.1:9000"
78+
}
79+
80+
var connFactory gofast.ConnFactory
81+
if strings.HasPrefix(phpFPMAddr, "/") {
82+
connFactory = gofast.SimpleConnFactory("unix", phpFPMAddr)
83+
} else {
84+
connFactory = gofast.SimpleConnFactory("tcp", phpFPMAddr)
85+
}
86+
87+
clientFactory := gofast.SimpleClientFactory(connFactory)
88+
89+
// Build the full path to the script
90+
root := conf.RootDirectory
91+
scriptFilename := filepath.Join(root, r.URL.Path)
92+
if _, err := os.Stat(scriptFilename); os.IsNotExist(err) {
93+
http.NotFound(w, r)
94+
return
95+
}
96+
97+
// Create a new FastCGI handler
98+
fcgiHandler := gofast.NewHandler(
99+
func(client gofast.Client, req *gofast.Request) (*gofast.ResponsePipe, error) {
100+
req.Params["SCRIPT_FILENAME"] = scriptFilename
101+
req.Params["DOCUMENT_ROOT"] = root
102+
req.Params["REQUEST_METHOD"] = r.Method
103+
req.Params["SERVER_PROTOCOL"] = r.Proto
104+
req.Params["REQUEST_URI"] = r.URL.RequestURI()
105+
req.Params["QUERY_STRING"] = r.URL.RawQuery
106+
req.Params["REMOTE_ADDR"] = r.RemoteAddr
107+
108+
return gofast.BasicSession(client, req)
109+
},
110+
clientFactory,
111+
)
112+
113+
// Serve the request
114+
fcgiHandler.ServeHTTP(w, r)
115+
} else {
116+
next.ServeHTTP(w, r)
117+
}
118+
})
119+
}
120+
}

public/test.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<?php
2+
phpinfo();
3+
?>

0 commit comments

Comments
 (0)