Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PHP: Use auto_prepend_file to preload mu-plugins (instead of creating them in wp-content/mu-plugins) #1366

Merged
merged 4 commits into from
May 9, 2024
Merged
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
3 changes: 3 additions & 0 deletions packages/php-wasm/compile/php/phpwasm-emscripten-library.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ const LibraryExample = {
// stdout, stderr, and headers information are written for the JavaScript
// code to read later on.
FS.mkdir("/internal");
// The files from the preload directory are preloaded using the
// auto_prepend_file php.ini directive.
FS.mkdir("/internal/preload");

PHPWASM.EventEmitter = ENVIRONMENT_IS_NODE
? require('events').EventEmitter
Expand Down
2 changes: 1 addition & 1 deletion packages/php-wasm/node/public/php_7_0.js
Original file line number Diff line number Diff line change
Expand Up @@ -5562,7 +5562,7 @@ var allocateUTF8OnStack = stringToUTF8OnStack;

var PHPWASM = {
init: function() {
FS.mkdir("/internal");
FS.mkdir("/internal");FS.mkdir("/internal/preload");
PHPWASM.EventEmitter = ENVIRONMENT_IS_NODE ? require("events").EventEmitter : class EventEmitter {
constructor() {
this.listeners = {};
Expand Down
2 changes: 1 addition & 1 deletion packages/php-wasm/node/public/php_7_1.js
Original file line number Diff line number Diff line change
Expand Up @@ -5562,7 +5562,7 @@ var allocateUTF8OnStack = stringToUTF8OnStack;

var PHPWASM = {
init: function() {
FS.mkdir("/internal");
FS.mkdir("/internal");FS.mkdir("/internal/preload");
PHPWASM.EventEmitter = ENVIRONMENT_IS_NODE ? require("events").EventEmitter : class EventEmitter {
constructor() {
this.listeners = {};
Expand Down
2 changes: 1 addition & 1 deletion packages/php-wasm/node/public/php_7_2.js
Original file line number Diff line number Diff line change
Expand Up @@ -5562,7 +5562,7 @@ var allocateUTF8OnStack = stringToUTF8OnStack;

var PHPWASM = {
init: function() {
FS.mkdir("/internal");
FS.mkdir("/internal");FS.mkdir("/internal/preload");
PHPWASM.EventEmitter = ENVIRONMENT_IS_NODE ? require("events").EventEmitter : class EventEmitter {
constructor() {
this.listeners = {};
Expand Down
2 changes: 1 addition & 1 deletion packages/php-wasm/node/public/php_7_3.js
Original file line number Diff line number Diff line change
Expand Up @@ -5562,7 +5562,7 @@ var allocateUTF8OnStack = stringToUTF8OnStack;

var PHPWASM = {
init: function() {
FS.mkdir("/internal");
FS.mkdir("/internal");FS.mkdir("/internal/preload");
PHPWASM.EventEmitter = ENVIRONMENT_IS_NODE ? require("events").EventEmitter : class EventEmitter {
constructor() {
this.listeners = {};
Expand Down
2 changes: 1 addition & 1 deletion packages/php-wasm/node/public/php_7_4.js
Original file line number Diff line number Diff line change
Expand Up @@ -5561,7 +5561,7 @@ var allocateUTF8OnStack = stringToUTF8OnStack;

var PHPWASM = {
init: function() {
FS.mkdir("/internal");
FS.mkdir("/internal");FS.mkdir("/internal/preload");
PHPWASM.EventEmitter = ENVIRONMENT_IS_NODE ? require("events").EventEmitter : class EventEmitter {
constructor() {
this.listeners = {};
Expand Down
2 changes: 1 addition & 1 deletion packages/php-wasm/node/public/php_8_0.js
Original file line number Diff line number Diff line change
Expand Up @@ -5561,7 +5561,7 @@ var allocateUTF8OnStack = stringToUTF8OnStack;

var PHPWASM = {
init: function() {
FS.mkdir("/internal");
FS.mkdir("/internal");FS.mkdir("/internal/preload");
PHPWASM.EventEmitter = ENVIRONMENT_IS_NODE ? require("events").EventEmitter : class EventEmitter {
constructor() {
this.listeners = {};
Expand Down
2 changes: 1 addition & 1 deletion packages/php-wasm/node/public/php_8_1.js
Original file line number Diff line number Diff line change
Expand Up @@ -5577,7 +5577,7 @@ var allocateUTF8OnStack = stringToUTF8OnStack;

var PHPWASM = {
init: function() {
FS.mkdir("/internal");
FS.mkdir("/internal");FS.mkdir("/internal/preload");
PHPWASM.EventEmitter = ENVIRONMENT_IS_NODE ? require("events").EventEmitter : class EventEmitter {
constructor() {
this.listeners = {};
Expand Down
2 changes: 1 addition & 1 deletion packages/php-wasm/node/public/php_8_2.js
Original file line number Diff line number Diff line change
Expand Up @@ -5582,7 +5582,7 @@ var allocateUTF8OnStack = stringToUTF8OnStack;

var PHPWASM = {
init: function() {
FS.mkdir("/internal");
FS.mkdir("/internal");FS.mkdir("/internal/preload");
PHPWASM.EventEmitter = ENVIRONMENT_IS_NODE ? require("events").EventEmitter : class EventEmitter {
constructor() {
this.listeners = {};
Expand Down
2 changes: 1 addition & 1 deletion packages/php-wasm/node/public/php_8_3.js
Original file line number Diff line number Diff line change
Expand Up @@ -5582,7 +5582,7 @@ var allocateUTF8OnStack = stringToUTF8OnStack;

var PHPWASM = {
init: function() {
FS.mkdir("/internal");
FS.mkdir("/internal");FS.mkdir("/internal/preload");
PHPWASM.EventEmitter = ENVIRONMENT_IS_NODE ? require("events").EventEmitter : class EventEmitter {
constructor() {
this.listeners = {};
Expand Down
40 changes: 24 additions & 16 deletions packages/php-wasm/universal/src/lib/base-php.ts
Original file line number Diff line number Diff line change
Expand Up @@ -358,32 +358,40 @@ export abstract class BasePHP implements IsomorphicLocalPHP, Disposable {
}

#initWebRuntime() {
this.writeFile(
'/internal/auto_prepend_file.php',
`<?php
foreach (glob('/internal/preload/*.php') as $file) {
require_once $file;
}
`
);
this.setPhpIniEntry(
'auto_prepend_file',
'/internal/auto_prepend_file.php'
);
adamziel marked this conversation as resolved.
Show resolved Hide resolved
/**
* This creates a consts.php file in an in-memory
* /internal directory and sets the auto_prepend_file PHP option
* /internal/preload directory and sets the auto_prepend_file PHP option
* to always load that file.
* @see https://www.php.net/manual/en/ini.core.php#ini.auto-prepend-file
*
* Technically, this is a workaround. In the future, let's implement a
* WASM SAPI method to pass consts directly.
* @see https://github.com/WordPress/wordpress-playground/issues/750
*/
this.setPhpIniEntry('auto_prepend_file', '/internal/consts.php');
if (!this.fileExists('/internal/consts.php')) {
this.writeFile(
'/internal/consts.php',
`<?php
if(file_exists('/internal/consts.json')) {
$consts = json_decode(file_get_contents('/internal/consts.json'), true);
foreach ($consts as $const => $value) {
if (!defined($const) && is_scalar($value)) {
define($const, $value);
}
this.writeFile(
'/internal/preload/consts.php',
`<?php
if(file_exists('/internal/consts.json')) {
$consts = json_decode(file_get_contents('/internal/consts.json'), true);
foreach ($consts as $const => $value) {
if (!defined($const) && is_scalar($value)) {
define($const, $value);
}
}`
);
}

}
}`
);
if (this.#phpIniOverrides.length > 0) {
const overridesAsIni =
this.#phpIniOverrides
Expand Down
1 change: 1 addition & 0 deletions packages/php-wasm/universal/src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,4 @@ export {
} from './urls';

export { isExitCodeZero } from './is-exit-code-zero';
export { proxyFileSystem } from './proxy-file-system';
7 changes: 6 additions & 1 deletion packages/php-wasm/universal/src/lib/php-request-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,12 @@ export class PHPRequestHandler<PHP extends BasePHP> {
filePath = '/index.php';
}

const resolvedFsPath = `${this.#DOCROOT}${filePath}`;
let resolvedFsPath = `${this.#DOCROOT}${filePath}`;
// If the requested PHP file doesn't exist, let's fall back to /index.php
// as the request may need to be rewritten.
if (!php.fileExists(resolvedFsPath)) {
resolvedFsPath = `${this.#DOCROOT}/index.php`;
}
if (php.fileExists(resolvedFsPath)) {
return resolvedFsPath;
}
Expand Down
36 changes: 36 additions & 0 deletions packages/php-wasm/universal/src/lib/proxy-file-system.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { BasePHP } from './base-php';

/**
* Proxy specific paths to the parent's MEMFS instance.
* This is useful for sharing the WordPress installation
* between the parent and child processes.
*/
export function proxyFileSystem(
sourceOfTruth: BasePHP,
replica: BasePHP,
paths: string[]
) {
// We can't just import the symbol from the library because
// Playground CLI is built as ESM and php-wasm-node is built as
// CJS and the imported symbols will different in the production build.
const __private__symbol = Object.getOwnPropertySymbols(sourceOfTruth)[0];
for (const path of paths) {
if (!replica.fileExists(path)) {
replica.mkdir(path);
}
if (!sourceOfTruth.fileExists(path)) {
sourceOfTruth.mkdir(path);
}
// @ts-ignore
replica[__private__symbol].FS.mount(
// @ts-ignore
replica[__private__symbol].PROXYFS,
{
root: path,
// @ts-ignore
fs: sourceOfTruth[__private__symbol].FS,
},
path
);
}
}
2 changes: 1 addition & 1 deletion packages/php-wasm/web/public/kitchen-sink/php_7_0.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/php-wasm/web/public/kitchen-sink/php_7_1.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/php-wasm/web/public/kitchen-sink/php_7_2.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/php-wasm/web/public/kitchen-sink/php_7_3.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/php-wasm/web/public/kitchen-sink/php_7_4.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/php-wasm/web/public/kitchen-sink/php_8_0.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/php-wasm/web/public/kitchen-sink/php_8_1.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/php-wasm/web/public/kitchen-sink/php_8_2.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/php-wasm/web/public/kitchen-sink/php_8_3.js
Original file line number Diff line number Diff line change
Expand Up @@ -5241,7 +5241,7 @@ var allocateUTF8OnStack = stringToUTF8OnStack;

var PHPWASM = {
init: function() {
FS.mkdir("/internal");
FS.mkdir("/internal");FS.mkdir("/internal/preload");
PHPWASM.EventEmitter = ENVIRONMENT_IS_NODE ? require("events").EventEmitter : class EventEmitter {
constructor() {
this.listeners = {};
Expand Down
2 changes: 1 addition & 1 deletion packages/php-wasm/web/public/light/php_7_0.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/php-wasm/web/public/light/php_7_1.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/php-wasm/web/public/light/php_7_2.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/php-wasm/web/public/light/php_7_3.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/php-wasm/web/public/light/php_7_4.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/php-wasm/web/public/light/php_8_0.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/php-wasm/web/public/light/php_8_1.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/php-wasm/web/public/light/php_8_2.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/php-wasm/web/public/light/php_8_3.js
Original file line number Diff line number Diff line change
Expand Up @@ -5241,7 +5241,7 @@ var allocateUTF8OnStack = stringToUTF8OnStack;

var PHPWASM = {
init: function() {
FS.mkdir("/internal");
FS.mkdir("/internal");FS.mkdir("/internal/preload");
PHPWASM.EventEmitter = ENVIRONMENT_IS_NODE ? require("events").EventEmitter : class EventEmitter {
constructor() {
this.listeners = {};
Expand Down
68 changes: 20 additions & 48 deletions packages/playground/cli/src/setup-php.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { NodePHP } from '@php-wasm/node';
import {
BasePHP,
PHPRequestHandler,
SupportedPHPVersion,
proxyFileSystem,
rotatePHPRuntime,
} from '@php-wasm/universal';
import { rootCertificates } from 'tls';
import { dirname } from '@php-wasm/util';
import { envPHP_to_loadMuPlugins } from '@wp-playground/wordpress';

export async function createPhp(
requestHandler: PHPRequestHandler<NodePHP>,
Expand Down Expand Up @@ -40,72 +41,43 @@ export async function createPhp(
php.setPhpIniEntry('openssl.cafile', '/tmp/ca-bundle.crt');
php.writeFile('/tmp/ca-bundle.crt', rootCertificates.join('\n'));

php.writeFile('/internal/preload/env.php', envPHP_to_loadMuPlugins);
php.writeFile(
'/internal/preload/phpinfo.php',
`<?php
// Render PHPInfo if the requested page is /phpinfo.php
if ( '/phpinfo.php' === $_SERVER['REQUEST_URI'] ) {
phpinfo();
exit;
}`
);
php.mkdir('/internal/mu-plugins');

if (!isPrimary) {
/**
* @TODO: Consider an API similar to
*
* php.mount('/wordpress', primaryPHP.getMountPoint('/wordpress'));
*/
proxyFileSystem(
await requestHandler.getPrimaryPhp(),
php,
'/wordpress'
);
proxyFileSystem(await requestHandler.getPrimaryPhp(), php, [
'/tmp',
requestHandler.documentRoot,
'/internal/mu-plugins',
]);
}

// php.setSpawnHandler(spawnHandlerFactory(processManager));
// Rotate the PHP runtime periodically to avoid memory leak-related crashes.
// @see https://github.com/WordPress/wordpress-playground/pull/990 for more context
rotatePHPRuntime({
php,
cwd: '/wordpress',
cwd: requestHandler.documentRoot,
recreateRuntime: createPhpRuntime,
maxRequests: 400,
});
return php;
}

/**
* Share the parent's MEMFS instance with the child process.
* Only mount the document root and the /tmp directory,
* the rest of the filesystem (like the devices) should be
* private to each PHP instance.
*
* @TODO: Ship this feature in the php-wasm library. It
* will be commonly used in multi-instance Playground
* applications. The website app does something similar,
* and so will wp-now, VSCode, etc.
*/
export function proxyFileSystem(
sourceOfTruth: BasePHP,
replica: BasePHP,
documentRoot: string
) {
// We can't just import the symbol from the library because
// Playground CLI is built as ESM and php-wasm-node is built as
// CJS and the imported symbols will different in the production build.
const __private__symbol = Object.getOwnPropertySymbols(sourceOfTruth)[0];
for (const path of [documentRoot, '/tmp']) {
if (!replica.fileExists(path)) {
replica.mkdir(path);
}
if (!sourceOfTruth.fileExists(path)) {
sourceOfTruth.mkdir(path);
}
// @ts-ignore
replica[__private__symbol].FS.mount(
// @ts-ignore
replica[__private__symbol].PROXYFS,
{
root: path,
// @ts-ignore
fs: sourceOfTruth[__private__symbol].FS,
},
path
);
}
}

/**
* @TODO: Ship this feature in the php-wasm library.
*
Expand Down
Loading
Loading