Skip to content

Commit 7c2a752

Browse files
committed
PHP Boot: Align the boot process between remote and CLI
§
1 parent 32c7d6f commit 7c2a752

File tree

6 files changed

+314
-216
lines changed

6 files changed

+314
-216
lines changed

packages/php-wasm/universal/src/lib/base-php.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,10 @@ export abstract class BasePHP implements IsomorphicLocalPHP, Disposable {
358358
}
359359

360360
#initWebRuntime() {
361+
this.setPhpIniEntry(
362+
'auto_prepend_file',
363+
'/internal/shared/auto_prepend_file.php'
364+
);
361365
if (!this.fileExists('/internal/shared/auto_prepend_file.php')) {
362366
this.writeFile(
363367
'/internal/shared/auto_prepend_file.php',
@@ -367,10 +371,6 @@ export abstract class BasePHP implements IsomorphicLocalPHP, Disposable {
367371
}
368372
`
369373
);
370-
this.setPhpIniEntry(
371-
'auto_prepend_file',
372-
'/internal/shared/auto_prepend_file.php'
373-
);
374374
/**
375375
* This creates a consts.php file in an in-memory
376376
* /internal/preload directory and sets the auto_prepend_file PHP option

packages/playground/cli/src/setup-php.ts

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ import {
77
} from '@php-wasm/universal';
88
import { rootCertificates } from 'tls';
99
import { dirname } from '@php-wasm/util';
10-
import { envPHP_to_loadMuPlugins } from '@wp-playground/wordpress';
10+
import {
11+
preloadPhpInfoRoute,
12+
enablePlatformMuPlugins,
13+
preloadRequiredMuPlugin,
14+
} from '@wp-playground/wordpress';
1115

1216
export async function createPhp(
1317
requestHandler: PHPRequestHandler<NodePHP>,
@@ -44,20 +48,9 @@ export async function createPhp(
4448
'/internal/shared/ca-bundle.crt',
4549
rootCertificates.join('\n')
4650
);
47-
php.writeFile(
48-
'/internal/shared/preload/env.php',
49-
envPHP_to_loadMuPlugins
50-
);
51-
php.writeFile(
52-
'/internal/shared/preload/phpinfo.php',
53-
`<?php
54-
// Render PHPInfo if the requested page is /phpinfo.php
55-
if ( '/phpinfo.php' === $_SERVER['REQUEST_URI'] ) {
56-
phpinfo();
57-
exit;
58-
}`
59-
);
60-
php.mkdir('/internal/shared/mu-plugins');
51+
await preloadPhpInfoRoute(php);
52+
await enablePlatformMuPlugins(php);
53+
await preloadRequiredMuPlugin(php);
6154
} else {
6255
/**
6356
* @TODO: Consider an API similar to

packages/playground/cli/src/setup-wp.ts

Lines changed: 8 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
readAsFile,
1717
} from './download';
1818
import { withPHPIniValues } from './setup-php';
19-
import { playgroundMuPlugin } from '@wp-playground/wordpress';
19+
import { preloadSqliteIntegration } from '@wp-playground/wordpress';
2020

2121
/**
2222
* Ensures a functional WordPress installation in php document root.
@@ -49,7 +49,11 @@ export async function setupWordPress(
4949
monitor
5050
),
5151
]);
52-
await prepareWordPress(php, wpZip, sqliteZip);
52+
await prepareWordPress(php, wpZip);
53+
// Setup the SQLite integration if no custom database drop-in is present
54+
if (!php.fileExists('/wordpress/wp-content/db.php')) {
55+
await preloadSqliteIntegration(php, sqliteZip);
56+
}
5357

5458
const preinstalledWpContentPath = path.join(
5559
CACHE_FOLDER,
@@ -96,7 +100,7 @@ export async function setupWordPress(
96100
* the sqlite-database-integration zip file.
97101
*
98102
* This is a TypeScript function for now, just to get something off the
99-
* ground, but it will be superseded by the PHP Blueprints library developed
103+
* ground, but it may be superseded by the PHP Blueprints library developed
100104
* at https://github.com/WordPress/blueprints-library/
101105
*
102106
* That PHP library will come with a set of functions and a CLI tool to
@@ -105,14 +109,7 @@ export async function setupWordPress(
105109
* accept the limitation, and switch to the PHP implementation as soon
106110
* as that's viable.
107111
*/
108-
async function prepareWordPress(php: NodePHP, wpZip: File, sqliteZip: File) {
109-
php.mkdir('/internal/shared/mu-plugins');
110-
php.writeFile(
111-
'/internal/shared/mu-plugins/0-playground.php',
112-
playgroundMuPlugin
113-
);
114-
115-
// Extract WordPress {{{
112+
async function prepareWordPress(php: NodePHP, wpZip: File) {
116113
php.mkdir('/tmp/unzipped-wordpress');
117114
await unzip(php, {
118115
zipFile: wpZip,
@@ -128,33 +125,4 @@ async function prepareWordPress(php: NodePHP, wpZip: File, sqliteZip: File) {
128125
'/wordpress/wp-config.php',
129126
php.readFileAsText('/wordpress/wp-config-sample.php')
130127
);
131-
// }}}
132-
133-
// Setup the SQLite integration {{{
134-
php.mkdir('/tmp/sqlite-database-integration');
135-
await unzip(php, {
136-
zipFile: sqliteZip,
137-
extractToPath: '/tmp/sqlite-database-integration',
138-
});
139-
php.mv(
140-
'/tmp/sqlite-database-integration/sqlite-database-integration-main',
141-
'/internal/shared/mu-plugins/sqlite-database-integration'
142-
);
143-
144-
const dbPhp = php
145-
.readFileAsText(
146-
'/internal/shared/mu-plugins/sqlite-database-integration/db.copy'
147-
)
148-
.replace(
149-
"'{SQLITE_IMPLEMENTATION_FOLDER_PATH}'",
150-
"'/internal/shared/mu-plugins/sqlite-database-integration/'"
151-
)
152-
.replace(
153-
"'{SQLITE_PLUGIN}'",
154-
"'/internal/shared/mu-plugins/sqlite-database-integration/load.php'"
155-
);
156-
// @TODO do not create the db.php file. Either find a way to mount it, or
157-
// load the custom $wpdb object in a different way.
158-
php.writeFile('/wordpress/wp-content/db.php', dbPhp);
159-
// }}}
160128
}

packages/playground/remote/src/lib/worker-thread.ts

Lines changed: 6 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,8 @@ import {
77
LatestSupportedWordPressVersion,
88
SupportedWordPressVersions,
99
} from '@wp-playground/wordpress-builds';
10-
import {
11-
envPHP_to_loadMuPlugins,
12-
playgroundMuPlugin,
13-
wordPressRewriteRules,
14-
} from '@wp-playground/wordpress';
15-
import {
16-
PHPRequestHandler,
17-
proxyFileSystem,
18-
writeFiles,
19-
} from '@php-wasm/universal';
10+
import { wordPressRewriteRules } from '@wp-playground/wordpress';
11+
import { PHPRequestHandler } from '@php-wasm/universal';
2012
import {
2113
SyncProgressCallback,
2214
bindOpfs,
@@ -28,13 +20,7 @@ import {
2820
unzip,
2921
} from '@wp-playground/blueprints';
3022

31-
/** @ts-ignore */
32-
import transportFetch from './playground-mu-plugin/playground-includes/wp_http_fetch.php?raw';
33-
/** @ts-ignore */
34-
import transportDummy from './playground-mu-plugin/playground-includes/wp_http_dummy.php?raw';
35-
/** @ts-ignore */
36-
import playgroundWebMuPlugin from './playground-mu-plugin/0-playground.php?raw';
37-
import { joinPaths, randomString } from '@php-wasm/util';
23+
import { randomString } from '@php-wasm/util';
3824
import {
3925
requestedWPVersion,
4026
createPhp,
@@ -169,37 +155,12 @@ export class PlaygroundWorkerEndpoint extends WebPHPEndpoint {
169155

170156
const scopedSiteUrl = setURLScope(wordPressSiteUrl, scope).toString();
171157
const requestHandler = new PHPRequestHandler({
172-
phpFactory: async ({ isPrimary }) => {
173-
const php = await createPhp(requestHandler);
174-
php.defineConstant('SCOPED_SITE_PATH', new URL(scopedSiteUrl).pathname);
175-
if (isPrimary) {
176-
php.writeFile(
177-
'/internal/shared/preload/env.php',
178-
envPHP_to_loadMuPlugins
179-
);
180-
php.writeFile(
181-
'/internal/shared/preload/phpinfo.php',
182-
`<?php
183-
// Render PHPInfo if the requested page is /phpinfo.php
184-
if ( SCOPED_SITE_PATH . '/phpinfo.php' === $_SERVER['REQUEST_URI'] ) {
185-
phpinfo();
186-
exit;
187-
}
188-
`
189-
);
190-
} else {
191-
proxyFileSystem(await requestHandler.getPrimaryPhp(), php, [
192-
'/tmp',
193-
requestHandler.documentRoot,
194-
'/internal/shared',
195-
]);
196-
}
197-
return php;
198-
},
158+
phpFactory: async ({ isPrimary }) =>
159+
await createPhp(requestHandler, scopedSiteUrl, isPrimary),
199160
documentRoot: DOCROOT,
200161
absoluteUrl: scopedSiteUrl,
201162
rewriteRules: wordPressRewriteRules,
202-
});
163+
}) as PHPRequestHandler<WebPHP>;
203164
const apiEndpoint = new PlaygroundWorkerEndpoint(
204165
requestHandler,
205166
downloadMonitor,
@@ -241,18 +202,6 @@ try {
241202
});
242203
}
243204

244-
// Always install the playground mu-plugin, even if WordPress is loaded
245-
// from the OPFS. This ensures:
246-
// * The mu-plugin is always there, even when a custom WordPress directory
247-
// is mounted.
248-
// * The mu-plugin is always up to date.
249-
await writeFiles(primaryPhp, joinPaths('/internal/shared/mu-plugins'), {
250-
'0-playground.php': playgroundMuPlugin,
251-
'1-playground-web.php': playgroundWebMuPlugin,
252-
'playground-includes/wp_http_dummy.php': transportDummy,
253-
'playground-includes/wp_http_fetch.php': transportFetch,
254-
});
255-
256205
if (virtualOpfsDir) {
257206
await bindOpfs({
258207
php: primaryPhp,

packages/playground/remote/src/lib/worker-utils.ts

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,24 @@ import {
1010
SupportedPHPVersionsList,
1111
rotatePHPRuntime,
1212
PHPRequestHandler,
13+
proxyFileSystem,
14+
writeFiles,
1315
} from '@php-wasm/universal';
1416
import { EmscriptenDownloadMonitor } from '@php-wasm/progress';
15-
import { createSpawnHandler, phpVar } from '@php-wasm/util';
17+
import { createSpawnHandler, joinPaths, phpVar } from '@php-wasm/util';
1618
import { createMemoizedFetch } from './create-memoized-fetch';
1719
import { logger } from '@php-wasm/logger';
20+
/** @ts-ignore */
21+
import transportFetch from './playground-mu-plugin/playground-includes/wp_http_fetch.php?raw';
22+
/** @ts-ignore */
23+
import transportDummy from './playground-mu-plugin/playground-includes/wp_http_dummy.php?raw';
24+
/** @ts-ignore */
25+
import playgroundWebMuPlugin from './playground-mu-plugin/0-playground.php?raw';
26+
import {
27+
enablePlatformMuPlugins,
28+
preloadPhpInfoRoute,
29+
preloadRequiredMuPlugin,
30+
} from '@wp-playground/wordpress';
1831

1932
export type ReceivedStartupOptions = {
2033
wpVersion?: string;
@@ -59,15 +72,42 @@ export const startupOptions = {
5972
phpExtensions: receivedParams.phpExtensions || [],
6073
} as ParsedStartupOptions;
6174

62-
export async function createPhp(requestHandler: PHPRequestHandler<WebPHP>) {
75+
export async function createPhp(
76+
requestHandler: PHPRequestHandler<WebPHP>,
77+
siteUrl: string,
78+
isPrimary: boolean
79+
) {
6380
const php = new WebPHP();
6481
php.requestHandler = requestHandler as any;
82+
6583
php.initializeRuntime(await createPhpRuntime());
66-
php.setPhpIniEntry('memory_limit', '256M');
6784
if (startupOptions.sapiName) {
6885
await php.setSapiName(startupOptions.sapiName);
6986
}
87+
php.setPhpIniEntry('memory_limit', '256M');
7088
php.setSpawnHandler(spawnHandlerFactory(requestHandler.processManager));
89+
90+
if (isPrimary) {
91+
const scopedSitePath = new URL(siteUrl).pathname;
92+
await preloadPhpInfoRoute(
93+
php,
94+
joinPaths(scopedSitePath, 'phpinfo.php')
95+
);
96+
await enablePlatformMuPlugins(php);
97+
await preloadRequiredMuPlugin(php);
98+
await writeFiles(php, joinPaths('/internal/shared/mu-plugins'), {
99+
'1-playground-web.php': playgroundWebMuPlugin,
100+
'playground-includes/wp_http_dummy.php': transportDummy,
101+
'playground-includes/wp_http_fetch.php': transportFetch,
102+
});
103+
} else {
104+
proxyFileSystem(await requestHandler.getPrimaryPhp(), php, [
105+
'/tmp',
106+
requestHandler.documentRoot,
107+
'/internal/shared',
108+
]);
109+
}
110+
71111
// Rotate the PHP runtime periodically to avoid memory leak-related crashes.
72112
// @see https://github.com/WordPress/wordpress-playground/pull/990 for more context
73113
rotatePHPRuntime({

0 commit comments

Comments
 (0)