Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions docs/php.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,17 @@ Flock's PHP includes the extensions most Laravel apps need, all of them on, with

```text
apcu bcmath bz2 calendar ctype curl dom exif fileinfo filter ftp gd
gmp iconv igbinary imagick intl ldap mbstring memcached mongodb mysqli
opcache openssl pcntl pdo_mysql pdo_pgsql pdo_sqlite pgsql phar posix
readline redis session shmop simplexml soap sockets sodium sqlite3
gmp iconv igbinary imagick imap intl ldap mbstring memcached mongodb
mysqli opcache openssl pcntl pdo_mysql pdo_pgsql pdo_sqlite pgsql phar
posix readline redis session shmop simplexml soap sockets sodium sqlite3
tokenizer xml xmlreader xmlwriter xsl zip zlib
```

- On macOS and Linux, `sysvmsg`, `sysvsem` and `sysvshm` are included too, and on Windows `gettext`.
- **pcov** is on for the command line only (`php`, `composer`, `php artisan test`), so your tests can measure code coverage while web requests stay fast.
- **Xdebug** loads only for requests that ask for it. See [Xdebug](xdebug.md).
- On Windows, `memcached`, `pcntl` and `posix` aren't available, and `mongodb` needs PHP 8.1 or newer.
- **imap** left PHP's core in 8.4; Flock's PHP has it for every version. It isn't thread-safe, so sites on [FrankenPHP](#frankenphp) don't have it. It doesn't support Kerberos (GSSAPI) logins.

### Which extensions a project needs

Expand Down
5 changes: 3 additions & 2 deletions internal/frankenphp/frankenphp.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,13 +213,14 @@ func confDir(root, minor string) string { return filepath.Join(Dir(root, minor),

// EnsureIni (re)writes Flock's ini files for a build: the extensions in its ext/ load as for the
// regular PHP (on Windows the official build's plus Flock's extension pack; on macOS the larger
// ones the build doesn't compile in), and Flock's defaults apply as for it (see php.DefaultsIni).
// ones the build doesn't compile in) except php.ThreadUnsafeExtensions, and Flock's defaults
// apply as for it (see php.DefaultsIni).
func EnsureIni(root, minor string) error {
dir := confDir(root, minor)
if err := os.MkdirAll(dir, 0o755); err != nil {
return err
}
body := php.ExtensionsIni(filepath.Join(Dir(root, minor), "ext")) + php.DefaultsIni(root, minor)
body := php.ExtensionsIni(filepath.Join(Dir(root, minor), "ext"), php.ThreadUnsafeExtensions...) + php.DefaultsIni(root, minor)
return os.WriteFile(filepath.Join(dir, "00-flock.ini"), []byte(body), 0o644)
}

Expand Down
13 changes: 9 additions & 4 deletions internal/php/php.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"path/filepath"
"regexp"
"runtime"
"slices"
"sort"
"strconv"
"strings"
Expand Down Expand Up @@ -317,11 +318,15 @@ func ExtensionPath(root, minor, name string) string {
// compile most of these in and ship only the larger ones (imagick, mongodb, memcached) shared.
// Xdebug and pcov aren't here: Xdebug loads only for debugging, pcov only for the CLI.
var extensions = []string{
"bz2", "curl", "exif", "fileinfo", "ftp", "gd", "gettext", "gmp", "intl", "ldap", "mbstring", "mysqli",
"bz2", "curl", "exif", "fileinfo", "ftp", "gd", "gettext", "gmp", "imap", "intl", "ldap", "mbstring", "mysqli",
"openssl", "pdo_mysql", "pdo_pgsql", "pdo_sqlite", "pgsql", "shmop", "soap", "sockets", "sodium", "sqlite3", "xsl", "zip",
"apcu", "igbinary", "redis", "imagick", "mongodb", "memcached",
}

// ThreadUnsafeExtensions stay out of FrankenPHP, which runs PHP in many threads of one process.
// Its macOS and Linux builds don't ship them; on Windows it shares the official build's DLLs.
var ThreadUnsafeExtensions = []string{"imap"}

// ExtensionFile is a shared extension's file in extDir: imagick.so, or php_imagick.dll on Windows.
func ExtensionFile(extDir, name string) string {
if runtime.GOOS == "windows" {
Expand Down Expand Up @@ -387,16 +392,16 @@ func IniValue(ini, directive string) (value string, ok bool) {
}

// ExtensionsIni is the ini that points a build at its ext/ directory and loads the extensions
// present there (FrankenPHP's builds use the same).
func ExtensionsIni(extDir string) string {
// present there, except skip (FrankenPHP's builds use the same, skipping ThreadUnsafeExtensions).
func ExtensionsIni(extDir string, skip ...string) string {
var b strings.Builder
fmt.Fprintf(&b, "; Managed by Flock — regenerated on install, edit php.ini instead.\nextension_dir = \"%s\"\n", extDir)
// opcache is compiled in from PHP 8.5 on, and into the macOS builds from PHP 8.0 on.
if fileExists(ExtensionFile(extDir, "opcache")) {
b.WriteString("zend_extension = opcache\n")
}
for _, name := range extensions {
if fileExists(ExtensionFile(extDir, name)) {
if !slices.Contains(skip, name) && fileExists(ExtensionFile(extDir, name)) {
fmt.Fprintf(&b, "extension = %s\n", name)
}
}
Expand Down
16 changes: 16 additions & 0 deletions internal/php/php_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,22 @@ func TestDebugCGIPortsStayClearOfTheWorkers(t *testing.T) {
}
}

func TestExtensionsIniSkipsThreadUnsafeForFrankenPHP(t *testing.T) {
extDir := t.TempDir()
for _, name := range []string{"imap", "intl"} {
if err := os.WriteFile(ExtensionFile(extDir, name), nil, 0o644); err != nil {
t.Fatal(err)
}
}

if ini := ExtensionsIni(extDir); !strings.Contains(ini, "extension = imap\n") || !strings.Contains(ini, "extension = intl\n") {
t.Errorf("PHP doesn't load imap and intl:\n%s", ini)
}
if ini := ExtensionsIni(extDir, ThreadUnsafeExtensions...); strings.Contains(ini, "imap") || !strings.Contains(ini, "extension = intl\n") {
t.Errorf("FrankenPHP loads imap or misses intl:\n%s", ini)
}
}

func TestDefaultsYieldToPhpIni(t *testing.T) {
root := t.TempDir()
flockIni := func() string {
Expand Down
Loading