diff --git a/packages/php-wasm/compile/php/php_wasm.c b/packages/php-wasm/compile/php/php_wasm.c index d360fe307e..fc6a0b4656 100644 --- a/packages/php-wasm/compile/php/php_wasm.c +++ b/packages/php-wasm/compile/php/php_wasm.c @@ -1450,12 +1450,14 @@ int EMSCRIPTEN_KEEPALIVE wasm_sapi_handle_request() goto wasm_request_done; } - result = php_execute_script(&file_handle TSRMLS_CC); + php_execute_script(&file_handle TSRMLS_CC); } else { - result = run_php(wasm_server_context->php_code); + run_php(wasm_server_context->php_code); } + result = EG(exit_status); + wasm_request_done: wasm_sapi_request_shutdown(); return result; @@ -1700,26 +1702,21 @@ int php_wasm_init() */ static int EMSCRIPTEN_KEEPALIVE run_php(char *code) { - int retVal = 255; // Unknown error. - zend_try { - retVal = zend_eval_string(code, NULL, "php-wasm run script"); + zend_eval_string(code, NULL, "php-wasm run script"); if (EG(exception)) { zend_exception_error(EG(exception), E_ERROR); - retVal = 2; } } zend_catch { - retVal = 1; // Code died. } - zend_end_try(); - return retVal; + return EG(exit_status); } #ifdef WITH_VRZNO diff --git a/packages/php-wasm/node/public/7_0_33/php_7_0.wasm b/packages/php-wasm/node/public/7_0_33/php_7_0.wasm index 46d55da223..1ee4857754 100755 Binary files a/packages/php-wasm/node/public/7_0_33/php_7_0.wasm and b/packages/php-wasm/node/public/7_0_33/php_7_0.wasm differ diff --git a/packages/php-wasm/node/public/7_1_30/php_7_1.wasm b/packages/php-wasm/node/public/7_1_30/php_7_1.wasm index 2de4e6d328..ce7c31c549 100755 Binary files a/packages/php-wasm/node/public/7_1_30/php_7_1.wasm and b/packages/php-wasm/node/public/7_1_30/php_7_1.wasm differ diff --git a/packages/php-wasm/node/public/7_2_34/php_7_2.wasm b/packages/php-wasm/node/public/7_2_34/php_7_2.wasm index 61a985ff68..e95e3b2b1b 100755 Binary files a/packages/php-wasm/node/public/7_2_34/php_7_2.wasm and b/packages/php-wasm/node/public/7_2_34/php_7_2.wasm differ diff --git a/packages/php-wasm/node/public/7_3_33/php_7_3.wasm b/packages/php-wasm/node/public/7_3_33/php_7_3.wasm index 0aa243d09d..bcd0775427 100755 Binary files a/packages/php-wasm/node/public/7_3_33/php_7_3.wasm and b/packages/php-wasm/node/public/7_3_33/php_7_3.wasm differ diff --git a/packages/php-wasm/node/public/7_4_33/php_7_4.wasm b/packages/php-wasm/node/public/7_4_33/php_7_4.wasm index c0c70c2bdc..b8b55e04d7 100755 Binary files a/packages/php-wasm/node/public/7_4_33/php_7_4.wasm and b/packages/php-wasm/node/public/7_4_33/php_7_4.wasm differ diff --git a/packages/php-wasm/node/public/8_0_30/php_8_0.wasm b/packages/php-wasm/node/public/8_0_30/php_8_0.wasm index b83ecbd9cf..5ddfa5b431 100755 Binary files a/packages/php-wasm/node/public/8_0_30/php_8_0.wasm and b/packages/php-wasm/node/public/8_0_30/php_8_0.wasm differ diff --git a/packages/php-wasm/node/public/8_1_23/php_8_1.wasm b/packages/php-wasm/node/public/8_1_23/php_8_1.wasm index 68ad3a213d..4bbe122b7c 100755 Binary files a/packages/php-wasm/node/public/8_1_23/php_8_1.wasm and b/packages/php-wasm/node/public/8_1_23/php_8_1.wasm differ diff --git a/packages/php-wasm/node/public/8_2_10/php_8_2.wasm b/packages/php-wasm/node/public/8_2_10/php_8_2.wasm index 8354498469..588343c5bf 100755 Binary files a/packages/php-wasm/node/public/8_2_10/php_8_2.wasm and b/packages/php-wasm/node/public/8_2_10/php_8_2.wasm differ diff --git a/packages/php-wasm/node/public/8_3_0/php_8_3.wasm b/packages/php-wasm/node/public/8_3_0/php_8_3.wasm index a46f2ee284..8c94255c25 100755 Binary files a/packages/php-wasm/node/public/8_3_0/php_8_3.wasm and b/packages/php-wasm/node/public/8_3_0/php_8_3.wasm differ diff --git a/packages/php-wasm/node/public/php_7_0.js b/packages/php-wasm/node/public/php_7_0.js index 081eed149e..18453c1c4d 100644 --- a/packages/php-wasm/node/public/php_7_0.js +++ b/packages/php-wasm/node/public/php_7_0.js @@ -1,6 +1,6 @@ const dependencyFilename = __dirname + '/7_0_33/php_7_0.wasm'; export { dependencyFilename }; -export const dependenciesTotalSize = 11391671; +export const dependenciesTotalSize = 11391850; export function init(RuntimeName, PHPLoader) { /** * Overrides Emscripten's default ExitStatus object which gets diff --git a/packages/php-wasm/node/public/php_7_1.js b/packages/php-wasm/node/public/php_7_1.js index 7154a1f1fd..a36f572813 100644 --- a/packages/php-wasm/node/public/php_7_1.js +++ b/packages/php-wasm/node/public/php_7_1.js @@ -1,6 +1,6 @@ const dependencyFilename = __dirname + '/7_1_30/php_7_1.wasm'; export { dependencyFilename }; -export const dependenciesTotalSize = 11592868; +export const dependenciesTotalSize = 11592769; export function init(RuntimeName, PHPLoader) { /** * Overrides Emscripten's default ExitStatus object which gets diff --git a/packages/php-wasm/node/public/php_7_2.js b/packages/php-wasm/node/public/php_7_2.js index 6730a2ab4c..ab38de4101 100644 --- a/packages/php-wasm/node/public/php_7_2.js +++ b/packages/php-wasm/node/public/php_7_2.js @@ -1,6 +1,6 @@ const dependencyFilename = __dirname + '/7_2_34/php_7_2.wasm'; export { dependencyFilename }; -export const dependenciesTotalSize = 11976523; +export const dependenciesTotalSize = 11976484; export function init(RuntimeName, PHPLoader) { /** * Overrides Emscripten's default ExitStatus object which gets diff --git a/packages/php-wasm/node/public/php_7_3.js b/packages/php-wasm/node/public/php_7_3.js index 85070cfda7..f020a1ccf1 100644 --- a/packages/php-wasm/node/public/php_7_3.js +++ b/packages/php-wasm/node/public/php_7_3.js @@ -1,6 +1,6 @@ const dependencyFilename = __dirname + '/7_3_33/php_7_3.wasm'; export { dependencyFilename }; -export const dependenciesTotalSize = 11900322; +export const dependenciesTotalSize = 11900277; export function init(RuntimeName, PHPLoader) { /** * Overrides Emscripten's default ExitStatus object which gets diff --git a/packages/php-wasm/node/public/php_7_4.js b/packages/php-wasm/node/public/php_7_4.js index b3b8e5343c..affb28ba95 100644 --- a/packages/php-wasm/node/public/php_7_4.js +++ b/packages/php-wasm/node/public/php_7_4.js @@ -1,6 +1,6 @@ const dependencyFilename = __dirname + '/7_4_33/php_7_4.wasm'; export { dependencyFilename }; -export const dependenciesTotalSize = 11983492; +export const dependenciesTotalSize = 11983453; export function init(RuntimeName, PHPLoader) { /** * Overrides Emscripten's default ExitStatus object which gets diff --git a/packages/php-wasm/node/public/php_8_0.js b/packages/php-wasm/node/public/php_8_0.js index 07d28799be..9cac854b93 100644 --- a/packages/php-wasm/node/public/php_8_0.js +++ b/packages/php-wasm/node/public/php_8_0.js @@ -1,6 +1,6 @@ const dependencyFilename = __dirname + '/8_0_30/php_8_0.wasm'; export { dependencyFilename }; -export const dependenciesTotalSize = 11122298; +export const dependenciesTotalSize = 11122221; export function init(RuntimeName, PHPLoader) { /** * Overrides Emscripten's default ExitStatus object which gets diff --git a/packages/php-wasm/node/public/php_8_1.js b/packages/php-wasm/node/public/php_8_1.js index 7e30667082..692dede9ab 100644 --- a/packages/php-wasm/node/public/php_8_1.js +++ b/packages/php-wasm/node/public/php_8_1.js @@ -1,6 +1,6 @@ const dependencyFilename = __dirname + '/8_1_23/php_8_1.wasm'; export { dependencyFilename }; -export const dependenciesTotalSize = 10994236; +export const dependenciesTotalSize = 10994178; export function init(RuntimeName, PHPLoader) { /** * Overrides Emscripten's default ExitStatus object which gets diff --git a/packages/php-wasm/node/public/php_8_2.js b/packages/php-wasm/node/public/php_8_2.js index 76d7c97c5c..80d693bb9a 100644 --- a/packages/php-wasm/node/public/php_8_2.js +++ b/packages/php-wasm/node/public/php_8_2.js @@ -1,6 +1,6 @@ const dependencyFilename = __dirname + '/8_2_10/php_8_2.wasm'; export { dependencyFilename }; -export const dependenciesTotalSize = 11251697; +export const dependenciesTotalSize = 11251680; export function init(RuntimeName, PHPLoader) { /** * Overrides Emscripten's default ExitStatus object which gets diff --git a/packages/php-wasm/node/public/php_8_3.js b/packages/php-wasm/node/public/php_8_3.js index b87b005d9b..26ea4d3f57 100644 --- a/packages/php-wasm/node/public/php_8_3.js +++ b/packages/php-wasm/node/public/php_8_3.js @@ -1,6 +1,6 @@ const dependencyFilename = __dirname + '/8_3_0/php_8_3.wasm'; export { dependencyFilename }; -export const dependenciesTotalSize = 11370244; +export const dependenciesTotalSize = 11370191; export function init(RuntimeName, PHPLoader) { /** * Overrides Emscripten's default ExitStatus object which gets diff --git a/packages/php-wasm/node/src/test/php-request-handler.spec.ts b/packages/php-wasm/node/src/test/php-request-handler.spec.ts index 2d1a0a2699..38d51a486b 100644 --- a/packages/php-wasm/node/src/test/php-request-handler.spec.ts +++ b/packages/php-wasm/node/src/test/php-request-handler.spec.ts @@ -32,7 +32,7 @@ describe.each(SupportedPHPVersions)( }, bytes: new TextEncoder().encode('Hello World'), errors: '', - exitCode: 1, // @TODO This should be 0 + exitCode: 0, }); }); @@ -120,7 +120,7 @@ describe.each(SupportedPHPVersions)( }, bytes: new TextEncoder().encode('Hello World'), errors: '', - exitCode: 1, // @TODO This should be 0 + exitCode: 0, }); expect(response2Result).toEqual({ httpStatusCode: 200, @@ -130,7 +130,7 @@ describe.each(SupportedPHPVersions)( }, bytes: new TextEncoder().encode('Hello World'), errors: '', - exitCode: 1, // @TODO This should be 0 + exitCode: 0, }); }); diff --git a/packages/php-wasm/node/src/test/php.spec.ts b/packages/php-wasm/node/src/test/php.spec.ts index 68bdcc26be..22fba76718 100644 --- a/packages/php-wasm/node/src/test/php.spec.ts +++ b/packages/php-wasm/node/src/test/php.spec.ts @@ -70,7 +70,12 @@ would not suffer fools gladly.`; describe.each(SupportedPHPVersions)('PHP %s', (phpVersion) => { let php: NodePHP; beforeEach(async () => { - php = await NodePHP.load(phpVersion as any); + php = await NodePHP.load(phpVersion as any, { + requestHandler: { + documentRoot: '/php', + }, + }); + php.mkdir('/php'); php.setPhpIniEntry('disable_functions', ''); }); @@ -634,6 +639,93 @@ describe.each(SupportedPHPVersions)('PHP %s', (phpVersion) => { }); }); + describe('Exit codes', () => { + describe('Returns exit code 0', () => { + const testsSnippets = { + 'on empty code': '', + 'on successful run': ' { + const result = await php.run({ + code: testSnippet, + }); + expect(result.exitCode).toEqual(0); + }); + + // Run via request handler + it(testName, async () => { + php.writeFile('/test.php', testSnippet); + const result = await php.run({ + scriptPath: '/test.php', + }); + expect(result.exitCode).toEqual(0); + }); + } + }); + describe('Returns exit code > 0', () => { + const testsSnippets = { + 'syntax error': ' { + const result = await php.run({ + code: testSnippet, + }); + expect(result.exitCode).toBeGreaterThan(0); + }); + + // Run via the request handler + it(testName, async () => { + php.writeFile('/test.php', testSnippet); + const result = await php.run({ + scriptPath: '/test.php', + }); + expect(result.exitCode).toBeGreaterThan(0); + }); + } + }); + it('Returns the correct exit code on subsequent runs', async () => { + const result1 = await php.run({ + code: ' { it('should output strings (1)', async () => { expect( diff --git a/packages/php-wasm/universal/src/lib/base-php.ts b/packages/php-wasm/universal/src/lib/base-php.ts index 1d2ed66e15..4cbce8c855 100644 --- a/packages/php-wasm/universal/src/lib/base-php.ts +++ b/packages/php-wasm/universal/src/lib/base-php.ts @@ -253,11 +253,25 @@ export abstract class BasePHP implements IsomorphicLocalPHP { this.#addUploadedFile(file); } } - if (request.code) { + if (typeof request.code === 'string') { this.#setPHPCode(' ?>' + request.code); } this.#addServerGlobalEntriesInWasm(); - return await this.#handleRequest(); + const response = await this.#handleRequest(); + if (request.throwOnError && response.exitCode !== 0) { + const output = { + stdout: response.text, + stderr: response.errors, + }; + console.warn(`PHP.run() output was:`, output); + const error = new Error( + `PHP.run() failed with exit code ${response.exitCode} and the following output` + ); + // @ts-ignore + error.output = output; + throw error; + } + return response; } finally { release(); this.dispatchEvent({ diff --git a/packages/php-wasm/universal/src/lib/universal-php.ts b/packages/php-wasm/universal/src/lib/universal-php.ts index 9b7184a43f..0b3e84d22a 100644 --- a/packages/php-wasm/universal/src/lib/universal-php.ts +++ b/packages/php-wasm/universal/src/lib/universal-php.ts @@ -525,6 +525,12 @@ export interface PHPRunOptions { * The code snippet to eval instead of a php file. */ code?: string; + + /** + * Whether to throw an error if the PHP process exits with a non-zero code + * or outputs to stderr. + */ + throwOnError?: boolean; } /** diff --git a/packages/php-wasm/web/public/kitchen-sink/7_0_33/php_7_0.wasm b/packages/php-wasm/web/public/kitchen-sink/7_0_33/php_7_0.wasm index bb7dec7e39..7d720b00bf 100755 Binary files a/packages/php-wasm/web/public/kitchen-sink/7_0_33/php_7_0.wasm and b/packages/php-wasm/web/public/kitchen-sink/7_0_33/php_7_0.wasm differ diff --git a/packages/php-wasm/web/public/kitchen-sink/7_1_30/php_7_1.wasm b/packages/php-wasm/web/public/kitchen-sink/7_1_30/php_7_1.wasm index 0195f4427d..4c26f91de5 100755 Binary files a/packages/php-wasm/web/public/kitchen-sink/7_1_30/php_7_1.wasm and b/packages/php-wasm/web/public/kitchen-sink/7_1_30/php_7_1.wasm differ diff --git a/packages/php-wasm/web/public/kitchen-sink/7_2_34/php_7_2.wasm b/packages/php-wasm/web/public/kitchen-sink/7_2_34/php_7_2.wasm index b765853dfc..7674b04cd3 100755 Binary files a/packages/php-wasm/web/public/kitchen-sink/7_2_34/php_7_2.wasm and b/packages/php-wasm/web/public/kitchen-sink/7_2_34/php_7_2.wasm differ diff --git a/packages/php-wasm/web/public/kitchen-sink/7_3_33/php_7_3.wasm b/packages/php-wasm/web/public/kitchen-sink/7_3_33/php_7_3.wasm index 0319b5ea1a..9f56bec59c 100755 Binary files a/packages/php-wasm/web/public/kitchen-sink/7_3_33/php_7_3.wasm and b/packages/php-wasm/web/public/kitchen-sink/7_3_33/php_7_3.wasm differ diff --git a/packages/php-wasm/web/public/kitchen-sink/7_4_33/php_7_4.wasm b/packages/php-wasm/web/public/kitchen-sink/7_4_33/php_7_4.wasm index 7645c13c24..b98b6d4d43 100755 Binary files a/packages/php-wasm/web/public/kitchen-sink/7_4_33/php_7_4.wasm and b/packages/php-wasm/web/public/kitchen-sink/7_4_33/php_7_4.wasm differ diff --git a/packages/php-wasm/web/public/kitchen-sink/8_0_30/php_8_0.wasm b/packages/php-wasm/web/public/kitchen-sink/8_0_30/php_8_0.wasm index 349900be01..6c28cc5758 100755 Binary files a/packages/php-wasm/web/public/kitchen-sink/8_0_30/php_8_0.wasm and b/packages/php-wasm/web/public/kitchen-sink/8_0_30/php_8_0.wasm differ diff --git a/packages/php-wasm/web/public/kitchen-sink/8_1_23/php_8_1.wasm b/packages/php-wasm/web/public/kitchen-sink/8_1_23/php_8_1.wasm index 8c4fbdd484..6198e17be7 100755 Binary files a/packages/php-wasm/web/public/kitchen-sink/8_1_23/php_8_1.wasm and b/packages/php-wasm/web/public/kitchen-sink/8_1_23/php_8_1.wasm differ diff --git a/packages/php-wasm/web/public/kitchen-sink/8_2_10/php_8_2.wasm b/packages/php-wasm/web/public/kitchen-sink/8_2_10/php_8_2.wasm index 70c7b70919..3c115a19c9 100755 Binary files a/packages/php-wasm/web/public/kitchen-sink/8_2_10/php_8_2.wasm and b/packages/php-wasm/web/public/kitchen-sink/8_2_10/php_8_2.wasm differ diff --git a/packages/php-wasm/web/public/kitchen-sink/8_3_0/php_8_3.wasm b/packages/php-wasm/web/public/kitchen-sink/8_3_0/php_8_3.wasm index 9e8d39bc10..fc808d38fd 100755 Binary files a/packages/php-wasm/web/public/kitchen-sink/8_3_0/php_8_3.wasm and b/packages/php-wasm/web/public/kitchen-sink/8_3_0/php_8_3.wasm differ diff --git a/packages/php-wasm/web/public/kitchen-sink/php_7_0.js b/packages/php-wasm/web/public/kitchen-sink/php_7_0.js index 72e49aa4ae..bf140a4501 100644 --- a/packages/php-wasm/web/public/kitchen-sink/php_7_0.js +++ b/packages/php-wasm/web/public/kitchen-sink/php_7_0.js @@ -1,6 +1,6 @@ import dependencyFilename from './7_0_33/php_7_0.wasm'; export { dependencyFilename }; -export const dependenciesTotalSize = 9833696; +export const dependenciesTotalSize = 9833750; export function init(RuntimeName, PHPLoader) { /** * Overrides Emscripten's default ExitStatus object which gets diff --git a/packages/php-wasm/web/public/kitchen-sink/php_7_1.js b/packages/php-wasm/web/public/kitchen-sink/php_7_1.js index 3752b5c486..1b742a3fa1 100644 --- a/packages/php-wasm/web/public/kitchen-sink/php_7_1.js +++ b/packages/php-wasm/web/public/kitchen-sink/php_7_1.js @@ -1,6 +1,6 @@ import dependencyFilename from './7_1_30/php_7_1.wasm'; export { dependencyFilename }; -export const dependenciesTotalSize = 9998422; +export const dependenciesTotalSize = 9998308; export function init(RuntimeName, PHPLoader) { /** * Overrides Emscripten's default ExitStatus object which gets diff --git a/packages/php-wasm/web/public/kitchen-sink/php_7_2.js b/packages/php-wasm/web/public/kitchen-sink/php_7_2.js index 7141f40512..236acb339d 100644 --- a/packages/php-wasm/web/public/kitchen-sink/php_7_2.js +++ b/packages/php-wasm/web/public/kitchen-sink/php_7_2.js @@ -1,6 +1,6 @@ import dependencyFilename from './7_2_34/php_7_2.wasm'; export { dependencyFilename }; -export const dependenciesTotalSize = 10366240; +export const dependenciesTotalSize = 10366209; export function init(RuntimeName, PHPLoader) { /** * Overrides Emscripten's default ExitStatus object which gets diff --git a/packages/php-wasm/web/public/kitchen-sink/php_7_3.js b/packages/php-wasm/web/public/kitchen-sink/php_7_3.js index d420f81aa4..d11a84a1e7 100644 --- a/packages/php-wasm/web/public/kitchen-sink/php_7_3.js +++ b/packages/php-wasm/web/public/kitchen-sink/php_7_3.js @@ -1,6 +1,6 @@ import dependencyFilename from './7_3_33/php_7_3.wasm'; export { dependencyFilename }; -export const dependenciesTotalSize = 10302048; +export const dependenciesTotalSize = 10302008; export function init(RuntimeName, PHPLoader) { /** * Overrides Emscripten's default ExitStatus object which gets diff --git a/packages/php-wasm/web/public/kitchen-sink/php_7_4.js b/packages/php-wasm/web/public/kitchen-sink/php_7_4.js index a41bda5670..03140c73e6 100644 --- a/packages/php-wasm/web/public/kitchen-sink/php_7_4.js +++ b/packages/php-wasm/web/public/kitchen-sink/php_7_4.js @@ -1,6 +1,6 @@ import dependencyFilename from './7_4_33/php_7_4.wasm'; export { dependencyFilename }; -export const dependenciesTotalSize = 10388320; +export const dependenciesTotalSize = 10388281; export function init(RuntimeName, PHPLoader) { /** * Overrides Emscripten's default ExitStatus object which gets diff --git a/packages/php-wasm/web/public/kitchen-sink/php_8_0.js b/packages/php-wasm/web/public/kitchen-sink/php_8_0.js index 623fee7ca8..9885a98767 100644 --- a/packages/php-wasm/web/public/kitchen-sink/php_8_0.js +++ b/packages/php-wasm/web/public/kitchen-sink/php_8_0.js @@ -1,6 +1,6 @@ import dependencyFilename from './8_0_30/php_8_0.wasm'; export { dependencyFilename }; -export const dependenciesTotalSize = 9985380; +export const dependenciesTotalSize = 9985321; export function init(RuntimeName, PHPLoader) { /** * Overrides Emscripten's default ExitStatus object which gets diff --git a/packages/php-wasm/web/public/kitchen-sink/php_8_1.js b/packages/php-wasm/web/public/kitchen-sink/php_8_1.js index cc504a8eaa..83214c7e00 100644 --- a/packages/php-wasm/web/public/kitchen-sink/php_8_1.js +++ b/packages/php-wasm/web/public/kitchen-sink/php_8_1.js @@ -1,6 +1,6 @@ import dependencyFilename from './8_1_23/php_8_1.wasm'; export { dependencyFilename }; -export const dependenciesTotalSize = 9856255; +export const dependenciesTotalSize = 9856210; export function init(RuntimeName, PHPLoader) { /** * Overrides Emscripten's default ExitStatus object which gets diff --git a/packages/php-wasm/web/public/kitchen-sink/php_8_2.js b/packages/php-wasm/web/public/kitchen-sink/php_8_2.js index e5ddcf0a3f..48eb0ddf09 100644 --- a/packages/php-wasm/web/public/kitchen-sink/php_8_2.js +++ b/packages/php-wasm/web/public/kitchen-sink/php_8_2.js @@ -1,6 +1,6 @@ import dependencyFilename from './8_2_10/php_8_2.wasm'; export { dependencyFilename }; -export const dependenciesTotalSize = 10102016; +export const dependenciesTotalSize = 10101963; export function init(RuntimeName, PHPLoader) { /** * Overrides Emscripten's default ExitStatus object which gets diff --git a/packages/php-wasm/web/public/kitchen-sink/php_8_3.js b/packages/php-wasm/web/public/kitchen-sink/php_8_3.js index 7d96b99647..bc7194a8be 100644 --- a/packages/php-wasm/web/public/kitchen-sink/php_8_3.js +++ b/packages/php-wasm/web/public/kitchen-sink/php_8_3.js @@ -1,6 +1,6 @@ import dependencyFilename from './8_3_0/php_8_3.wasm'; export { dependencyFilename }; -export const dependenciesTotalSize = 10218052; +export const dependenciesTotalSize = 10217997; export function init(RuntimeName, PHPLoader) { /** * Overrides Emscripten's default ExitStatus object which gets diff --git a/packages/php-wasm/web/public/light/7_0_33/php_7_0.wasm b/packages/php-wasm/web/public/light/7_0_33/php_7_0.wasm index 7978a6b393..becf264210 100755 Binary files a/packages/php-wasm/web/public/light/7_0_33/php_7_0.wasm and b/packages/php-wasm/web/public/light/7_0_33/php_7_0.wasm differ diff --git a/packages/php-wasm/web/public/light/7_1_30/php_7_1.wasm b/packages/php-wasm/web/public/light/7_1_30/php_7_1.wasm index 3e09371561..e3c2cc70ef 100755 Binary files a/packages/php-wasm/web/public/light/7_1_30/php_7_1.wasm and b/packages/php-wasm/web/public/light/7_1_30/php_7_1.wasm differ diff --git a/packages/php-wasm/web/public/light/7_2_34/php_7_2.wasm b/packages/php-wasm/web/public/light/7_2_34/php_7_2.wasm index 12bb4b6074..6880955d85 100755 Binary files a/packages/php-wasm/web/public/light/7_2_34/php_7_2.wasm and b/packages/php-wasm/web/public/light/7_2_34/php_7_2.wasm differ diff --git a/packages/php-wasm/web/public/light/7_3_33/php_7_3.wasm b/packages/php-wasm/web/public/light/7_3_33/php_7_3.wasm index 7da33123ac..7cdb828421 100755 Binary files a/packages/php-wasm/web/public/light/7_3_33/php_7_3.wasm and b/packages/php-wasm/web/public/light/7_3_33/php_7_3.wasm differ diff --git a/packages/php-wasm/web/public/light/7_4_33/php_7_4.wasm b/packages/php-wasm/web/public/light/7_4_33/php_7_4.wasm index 3c3728a492..ced63cc533 100755 Binary files a/packages/php-wasm/web/public/light/7_4_33/php_7_4.wasm and b/packages/php-wasm/web/public/light/7_4_33/php_7_4.wasm differ diff --git a/packages/php-wasm/web/public/light/8_0_30/php_8_0.wasm b/packages/php-wasm/web/public/light/8_0_30/php_8_0.wasm index 4c9630a148..5454c82f40 100755 Binary files a/packages/php-wasm/web/public/light/8_0_30/php_8_0.wasm and b/packages/php-wasm/web/public/light/8_0_30/php_8_0.wasm differ diff --git a/packages/php-wasm/web/public/light/8_1_23/php_8_1.wasm b/packages/php-wasm/web/public/light/8_1_23/php_8_1.wasm index a1e9ef22b9..1d9f0c7e1b 100755 Binary files a/packages/php-wasm/web/public/light/8_1_23/php_8_1.wasm and b/packages/php-wasm/web/public/light/8_1_23/php_8_1.wasm differ diff --git a/packages/php-wasm/web/public/light/8_2_10/php_8_2.wasm b/packages/php-wasm/web/public/light/8_2_10/php_8_2.wasm index f5fb8142b0..b3e2c09e19 100755 Binary files a/packages/php-wasm/web/public/light/8_2_10/php_8_2.wasm and b/packages/php-wasm/web/public/light/8_2_10/php_8_2.wasm differ diff --git a/packages/php-wasm/web/public/light/8_3_0/php_8_3.wasm b/packages/php-wasm/web/public/light/8_3_0/php_8_3.wasm index e5d5ee186e..a8d5a73118 100755 Binary files a/packages/php-wasm/web/public/light/8_3_0/php_8_3.wasm and b/packages/php-wasm/web/public/light/8_3_0/php_8_3.wasm differ diff --git a/packages/php-wasm/web/public/light/php_7_0.js b/packages/php-wasm/web/public/light/php_7_0.js index 0927a9d599..719e256d12 100644 --- a/packages/php-wasm/web/public/light/php_7_0.js +++ b/packages/php-wasm/web/public/light/php_7_0.js @@ -1,6 +1,6 @@ import dependencyFilename from './7_0_33/php_7_0.wasm'; export { dependencyFilename }; -export const dependenciesTotalSize = 5279438; +export const dependenciesTotalSize = 5279493; export function init(RuntimeName, PHPLoader) { /** * Overrides Emscripten's default ExitStatus object which gets diff --git a/packages/php-wasm/web/public/light/php_7_1.js b/packages/php-wasm/web/public/light/php_7_1.js index cc4e5e7008..f57446b485 100644 --- a/packages/php-wasm/web/public/light/php_7_1.js +++ b/packages/php-wasm/web/public/light/php_7_1.js @@ -1,6 +1,6 @@ import dependencyFilename from './7_1_30/php_7_1.wasm'; export { dependencyFilename }; -export const dependenciesTotalSize = 5423636; +export const dependenciesTotalSize = 5423519; export function init(RuntimeName, PHPLoader) { /** * Overrides Emscripten's default ExitStatus object which gets diff --git a/packages/php-wasm/web/public/light/php_7_2.js b/packages/php-wasm/web/public/light/php_7_2.js index ff81355e26..cbc752b449 100644 --- a/packages/php-wasm/web/public/light/php_7_2.js +++ b/packages/php-wasm/web/public/light/php_7_2.js @@ -1,6 +1,6 @@ import dependencyFilename from './7_2_34/php_7_2.wasm'; export { dependencyFilename }; -export const dependenciesTotalSize = 5766614; +export const dependenciesTotalSize = 5766573; export function init(RuntimeName, PHPLoader) { /** * Overrides Emscripten's default ExitStatus object which gets diff --git a/packages/php-wasm/web/public/light/php_7_3.js b/packages/php-wasm/web/public/light/php_7_3.js index 8c262f2638..a75ff880b7 100644 --- a/packages/php-wasm/web/public/light/php_7_3.js +++ b/packages/php-wasm/web/public/light/php_7_3.js @@ -1,6 +1,6 @@ import dependencyFilename from './7_3_33/php_7_3.wasm'; export { dependencyFilename }; -export const dependenciesTotalSize = 5694825; +export const dependenciesTotalSize = 5694789; export function init(RuntimeName, PHPLoader) { /** * Overrides Emscripten's default ExitStatus object which gets diff --git a/packages/php-wasm/web/public/light/php_7_4.js b/packages/php-wasm/web/public/light/php_7_4.js index f1c6921ddd..9abac35be4 100644 --- a/packages/php-wasm/web/public/light/php_7_4.js +++ b/packages/php-wasm/web/public/light/php_7_4.js @@ -1,6 +1,6 @@ import dependencyFilename from './7_4_33/php_7_4.wasm'; export { dependencyFilename }; -export const dependenciesTotalSize = 5776078; +export const dependenciesTotalSize = 5776044; export function init(RuntimeName, PHPLoader) { /** * Overrides Emscripten's default ExitStatus object which gets diff --git a/packages/php-wasm/web/public/light/php_8_0.js b/packages/php-wasm/web/public/light/php_8_0.js index 13619fd3ad..325a4609d9 100644 --- a/packages/php-wasm/web/public/light/php_8_0.js +++ b/packages/php-wasm/web/public/light/php_8_0.js @@ -1,6 +1,6 @@ import dependencyFilename from './8_0_30/php_8_0.wasm'; export { dependencyFilename }; -export const dependenciesTotalSize = 5573686; +export const dependenciesTotalSize = 5573621; export function init(RuntimeName, PHPLoader) { /** * Overrides Emscripten's default ExitStatus object which gets diff --git a/packages/php-wasm/web/public/light/php_8_1.js b/packages/php-wasm/web/public/light/php_8_1.js index 51a8106b22..f391998315 100644 --- a/packages/php-wasm/web/public/light/php_8_1.js +++ b/packages/php-wasm/web/public/light/php_8_1.js @@ -1,6 +1,6 @@ import dependencyFilename from './8_1_23/php_8_1.wasm'; export { dependencyFilename }; -export const dependenciesTotalSize = 5376968; +export const dependenciesTotalSize = 5376908; export function init(RuntimeName, PHPLoader) { /** * Overrides Emscripten's default ExitStatus object which gets diff --git a/packages/php-wasm/web/public/light/php_8_2.js b/packages/php-wasm/web/public/light/php_8_2.js index 560c5af6d0..a1508852da 100644 --- a/packages/php-wasm/web/public/light/php_8_2.js +++ b/packages/php-wasm/web/public/light/php_8_2.js @@ -1,6 +1,6 @@ import dependencyFilename from './8_2_10/php_8_2.wasm'; export { dependencyFilename }; -export const dependenciesTotalSize = 5490797; +export const dependenciesTotalSize = 5490746; export function init(RuntimeName, PHPLoader) { /** * Overrides Emscripten's default ExitStatus object which gets diff --git a/packages/php-wasm/web/public/light/php_8_3.js b/packages/php-wasm/web/public/light/php_8_3.js index 0ba87a52da..3d97d28938 100644 --- a/packages/php-wasm/web/public/light/php_8_3.js +++ b/packages/php-wasm/web/public/light/php_8_3.js @@ -1,6 +1,6 @@ import dependencyFilename from './8_3_0/php_8_3.wasm'; export { dependencyFilename }; -export const dependenciesTotalSize = 5582003; +export const dependenciesTotalSize = 5581960; export function init(RuntimeName, PHPLoader) { /** * Overrides Emscripten's default ExitStatus object which gets diff --git a/packages/playground/blueprints/src/lib/compile.ts b/packages/playground/blueprints/src/lib/compile.ts index 1feef66572..8d825c843a 100644 --- a/packages/playground/blueprints/src/lib/compile.ts +++ b/packages/playground/blueprints/src/lib/compile.ts @@ -182,9 +182,21 @@ export function compileBlueprint( } } - for (const { run, step } of compiled) { - const result = await run(playground); - onStepCompleted(result, step); + for (const [i, { run, step }] of Object.entries(compiled)) { + try { + const result = await run(playground); + onStepCompleted(result, step); + } catch (e) { + throw new Error( + `Error when executing the blueprint step #${i} (${JSON.stringify( + step + )}). ` + + `Inspect the cause of this error for more details`, + { + cause: e, + } + ); + } } } finally { try { diff --git a/packages/playground/blueprints/src/lib/steps/activate-plugin.ts b/packages/playground/blueprints/src/lib/steps/activate-plugin.ts index 16cc64d999..5a24bfdfb8 100644 --- a/packages/playground/blueprints/src/lib/steps/activate-plugin.ts +++ b/packages/playground/blueprints/src/lib/steps/activate-plugin.ts @@ -35,6 +35,7 @@ export const activatePlugin: StepHandler = async ( const docroot = await playground.documentRoot; await playground.run({ + throwOnError: true, code: ` = async ( progress?.tracker.setCaption(`Activating ${themeFolderName}`); const docroot = await playground.documentRoot; await playground.run({ + throwOnError: true, code: ` contents.replace( /add_filter[^;]+wp_maybe_grant_site_health_caps[^;]+;/i, @@ -118,7 +119,7 @@ class WordPressPatcher { async disableWpNewBlogNotification() { await updateFile( this.php, - `${this.wordpressPath}/wp-config.php`, + joinPaths(this.wordpressPath, 'wp-config.php'), // The original version of this function crashes WASM PHP, let's define an empty one instead. (contents) => `${contents} function wp_new_blog_notification(...$args){} ` @@ -127,16 +128,27 @@ class WordPressPatcher { async prepareForRunningInsideWebBrowser() { // Various tweaks - await this.php.mkdir(`${this.wordpressPath}/wp-content/mu-plugins`); + await this.php.mkdir( + joinPaths(this.wordpressPath, 'wp-content/mu-plugins') + ); await this.php.writeFile( - `${this.wordpressPath}/wp-content/mu-plugins/0-playground.php`, + joinPaths( + this.wordpressPath, + '/wp-content/mu-plugins/0-playground.php' + ), playgroundMuPlugin ); await this.php.mkdir( - `${this.wordpressPath}/wp-content/mu-plugins/playground-includes` + joinPaths( + this.wordpressPath, + `/wp-content/mu-plugins/playground-includes` + ) ); await this.php.writeFile( - `${this.wordpressPath}/wp-content/mu-plugins/playground-includes/requests_transport_dummy.php`, + joinPaths( + this.wordpressPath, + `/wp-content/mu-plugins/playground-includes/requests_transport_dummy.php` + ), transportDummy ); } @@ -150,10 +162,22 @@ class WordPressPatcher { // Force the fsockopen and cUrl transports to report they don't work: const transports = [ - `${this.wordpressPath}/wp-includes/Requests/Transport/fsockopen.php`, - `${this.wordpressPath}/wp-includes/Requests/Transport/cURL.php`, - `${this.wordpressPath}/wp-includes/Requests/src/Transport/Fsockopen.php`, - `${this.wordpressPath}/wp-includes/Requests/src/Transport/Curl.php`, + joinPaths( + this.wordpressPath, + `/wp-includes/Requests/Transport/fsockopen.php` + ), + joinPaths( + this.wordpressPath, + `/wp-includes/Requests/Transport/cURL.php` + ), + joinPaths( + this.wordpressPath, + `/wp-includes/Requests/src/Transport/Fsockopen.php` + ), + joinPaths( + this.wordpressPath, + `/wp-includes/Requests/src/Transport/Curl.php` + ), ]; for (const transport of transports) { // One of the transports might not exist in the latest WordPress version. @@ -174,7 +198,10 @@ class WordPressPatcher { // Add fetch and dummy transports for HTTP requests await this.php.writeFile( - `${this.wordpressPath}/wp-content/mu-plugins/playground-includes/wp_http_fetch.php`, + joinPaths( + this.wordpressPath, + 'wp-content/mu-plugins/playground-includes/wp_http_fetch.php' + ), transportFetch ); await this.php.mkdir(`${this.wordpressPath}/wp-content/fonts`); diff --git a/packages/playground/blueprints/src/lib/steps/cp.spec.ts b/packages/playground/blueprints/src/lib/steps/cp.spec.ts new file mode 100644 index 0000000000..00c17c95b8 --- /dev/null +++ b/packages/playground/blueprints/src/lib/steps/cp.spec.ts @@ -0,0 +1,55 @@ +import { NodePHP } from '@php-wasm/node'; +import { RecommendedPHPVersion } from '@wp-playground/wordpress'; +import { cp } from './cp'; + +const docroot = '/php'; +describe('Blueprint step cp()', () => { + let php: NodePHP; + beforeEach(async () => { + php = await NodePHP.load(RecommendedPHPVersion); + php.mkdir(docroot); + }); + + it('should copy a file', async () => { + php.writeFile(`/${docroot}/index.php`, ` { + await expect( + cp(php, { + fromPath: `/${docroot}/index.php`, + toPath: `/${docroot}/index2.php`, + }) + ).rejects.toThrow(/There is no such file or directory/); + }); + + it('should fail when the source file is a directory', async () => { + php.mkdir(`/${docroot}/dir`); + await expect( + cp(php, { + fromPath: `/${docroot}/dir`, + toPath: `/${docroot}/index2.php`, + }) + ).rejects.toThrow(/There is a directory under that path/); + }); + + it('should overwrite the target file', async () => { + php.writeFile(`/${docroot}/index.php`, ` { + async function bootWordPress(options: { absoluteUrl: string }) { + const php = await NodePHP.load(RecommendedPHPVersion, { + requestHandler: { + documentRoot: DOCROOT, + ...options, + }, + }); + await unzip(php, { + zipFile: await getWordPressModule(), + extractToPath: DOCROOT, + }); + return php; + } + + it('should enable a multisite on a scoped URL', async () => { + const php = await bootWordPress({ + absoluteUrl: 'http://playground-domain/scope:987987/', + }); + await enableMultisite(php, {}); + + const response = await php.request({ + url: '/wp-admin/network/', + }); + expect(response.text).toContain('My Sites'); + }, 30_000); + + it('should enable a multisite on a scopeless URL', async () => { + const php = await bootWordPress({ + absoluteUrl: 'http://playground-domain/', + }); + await enableMultisite(php, {}); + + const response = await php.request({ + url: '/wp-admin/network/', + }); + expect(response.text).toContain('My Sites'); + }, 30_000); +}); diff --git a/packages/playground/blueprints/src/lib/steps/enable-multisite.ts b/packages/playground/blueprints/src/lib/steps/enable-multisite.ts index b6c8d7ef5c..484ee9ce5f 100644 --- a/packages/playground/blueprints/src/lib/steps/enable-multisite.ts +++ b/packages/playground/blueprints/src/lib/steps/enable-multisite.ts @@ -1,11 +1,11 @@ -import { phpVar } from '@php-wasm/util'; +import { joinPaths, phpVar } from '@php-wasm/util'; import { StepHandler } from '.'; import { defineWpConfigConsts } from './define-wp-config-consts'; import { login } from './login'; import { request } from './request'; import { setSiteOptions } from './site-data'; import { activatePlugin } from './activate-plugin'; -import { getURLScope } from '@php-wasm/scopes'; +import { getURLScope, isURLScoped } from '@php-wasm/scopes'; /** * @inheritDoc enableMultisite @@ -33,9 +33,6 @@ export interface EnableMultisiteStep { export const enableMultisite: StepHandler = async ( playground ) => { - // Ensure we're logged in - await login(playground, {}); - await defineWpConfigConsts(playground, { consts: { WP_ALLOW_MULTISITE: 1, @@ -59,13 +56,21 @@ export const enableMultisite: StepHandler = async ( }, }); + // Ensure we're logged in + await login(playground, {}); + const docroot = await playground.documentRoot; // Deactivate all the plugins as required by the multisite installation. const result = await playground.run({ + throwOnError: true, code: ` 'Administrator') )[0] ); + require_once(${phpVar(docroot)} . "/wp-admin/includes/plugin.php"); $plugins_root = ${phpVar(docroot)} . "/wp-content/plugins"; $plugins = glob($plugins_root . "/*"); @@ -115,7 +120,7 @@ echo json_encode($deactivated_plugins); })).text; */ - await request(playground, { + const response = await request(playground, { request: { url: '/wp-admin/network.php', method: 'POST', @@ -123,7 +128,7 @@ echo json_encode($deactivated_plugins); 'Content-Type': 'application/x-www-form-urlencoded', }, body: jsonToUrlEncoded({ - _wpnonce: nonce, + _wpnonce: nonce!, _wp_http_referer: sitePath + 'wp-admin/network.php', sitename: 'My WordPress Website Sites', email: 'admin@localhost.com', @@ -131,6 +136,16 @@ echo json_encode($deactivated_plugins); }), }, }); + if (response.httpStatusCode !== 200) { + console.warn('WordPress response was', { + response, + text: response.text, + headers: response.headers, + }); + throw new Error( + `Failed to enable multisite. Response code was ${response.httpStatusCode}` + ); + } await defineWpConfigConsts(playground, { consts: { @@ -148,15 +163,17 @@ echo json_encode($deactivated_plugins); // by default. Without this, requiring `wp-load.php` will result in // a redirect to the main site. const playgroundUrl = new URL(await playground.absoluteUrl); - const wpInstallationFolder = 'scope:' + getURLScope(playgroundUrl); + const wpInstallationFolder = isURLScoped(playgroundUrl) + ? 'scope:' + getURLScope(playgroundUrl) + : null; await playground.writeFile( - `${await playground.documentRoot}/wp-content/sunrise.php`, + joinPaths(docroot, '/wp-content/sunrise.php'), `> = ( +export type StepHandler, Return = any> = ( /** * A PHP instance or Playground client. */ php: UniversalPHP, args: Omit, progressArgs?: StepProgress -) => any; +) => Return; diff --git a/packages/playground/blueprints/src/lib/steps/install-plugin.ts b/packages/playground/blueprints/src/lib/steps/install-plugin.ts index 87bebdb385..70dbee13a5 100644 --- a/packages/playground/blueprints/src/lib/steps/install-plugin.ts +++ b/packages/playground/blueprints/src/lib/steps/install-plugin.ts @@ -61,31 +61,22 @@ export const installPlugin: StepHandler> = async ( const zipNiceName = zipNameToHumanName(zipFileName); progress?.tracker.setCaption(`Installing the ${zipNiceName} plugin`); - try { - const { assetFolderPath } = await installAsset(playground, { - zipFile: pluginZipFile, - targetPath: `${await playground.documentRoot}/wp-content/plugins`, - }); + const { assetFolderPath } = await installAsset(playground, { + zipFile: pluginZipFile, + targetPath: `${await playground.documentRoot}/wp-content/plugins`, + }); - // Activate + // Activate + const activate = 'activate' in options ? options.activate : true; - const activate = 'activate' in options ? options.activate : true; - - if (activate) { - await activatePlugin( - playground, - { - pluginPath: assetFolderPath, - pluginName: zipNiceName, - }, - progress - ); - } - } catch (error) { - console.error( - `Proceeding without the ${zipNiceName} plugin. Could not install it in wp-admin. ` + - `The original error was: ${error}` + if (activate) { + await activatePlugin( + playground, + { + pluginPath: assetFolderPath, + pluginName: zipNiceName, + }, + progress ); - console.error(error); } }; diff --git a/packages/playground/blueprints/src/lib/steps/install-theme.ts b/packages/playground/blueprints/src/lib/steps/install-theme.ts index d6d8995d05..6e319affa0 100644 --- a/packages/playground/blueprints/src/lib/steps/install-theme.ts +++ b/packages/playground/blueprints/src/lib/steps/install-theme.ts @@ -64,31 +64,19 @@ export const installTheme: StepHandler> = async ( const zipNiceName = zipNameToHumanName(themeZipFile.name); progress?.tracker.setCaption(`Installing the ${zipNiceName} theme`); + const { assetFolderName } = await installAsset(playground, { + zipFile: themeZipFile, + targetPath: `${await playground.documentRoot}/wp-content/themes`, + }); - try { - const { assetFolderName } = await installAsset(playground, { - zipFile: themeZipFile, - targetPath: `${await playground.documentRoot}/wp-content/themes`, - }); - - // Activate - - const activate = 'activate' in options ? options.activate : true; - - if (activate) { - await activateTheme( - playground, - { - themeFolderName: assetFolderName, - }, - progress - ); - } - } catch (error) { - console.error( - `Proceeding without the ${zipNiceName} theme. Could not install it in wp-admin. ` + - `The original error was: ${error}` + const activate = 'activate' in options ? options.activate : true; + if (activate) { + await activateTheme( + playground, + { + themeFolderName: assetFolderName, + }, + progress ); - console.error(error); } }; diff --git a/packages/playground/blueprints/src/lib/steps/login.spec.ts b/packages/playground/blueprints/src/lib/steps/login.spec.ts new file mode 100644 index 0000000000..2335b7bd5a --- /dev/null +++ b/packages/playground/blueprints/src/lib/steps/login.spec.ts @@ -0,0 +1,30 @@ +import { NodePHP } from '@php-wasm/node'; +import { + RecommendedPHPVersion, + getWordPressModule, +} from '@wp-playground/wordpress'; +import { login } from './login'; +import { unzip } from './unzip'; + +describe('Blueprint step installPlugin', () => { + let php: NodePHP; + beforeEach(async () => { + php = await NodePHP.load(RecommendedPHPVersion, { + requestHandler: { + documentRoot: '/wordpress', + }, + }); + await unzip(php, { + zipFile: await getWordPressModule(), + extractToPath: '/wordpress', + }); + }); + + it('should log the user in', async () => { + await login(php, {}); + const response = await php.request({ + url: '/wp-admin', + }); + expect(response.text).toContain('Dashboard'); + }); +}); diff --git a/packages/playground/blueprints/src/lib/steps/login.ts b/packages/playground/blueprints/src/lib/steps/login.ts index d8fb2a984f..07cad2d773 100644 --- a/packages/playground/blueprints/src/lib/steps/login.ts +++ b/packages/playground/blueprints/src/lib/steps/login.ts @@ -36,11 +36,12 @@ export const login: StepHandler = async ( progress ) => { progress?.tracker.setCaption(progress?.initialCaption || 'Logging in'); + // Allow WordPress to set the cookies. await playground.request({ url: '/wp-login.php', }); - await playground.request({ + const response = await playground.request({ url: '/wp-login.php', method: 'POST', formData: { @@ -49,4 +50,14 @@ export const login: StepHandler = async ( rememberme: 'forever', }, }); + + if (!response.headers?.['location']?.[0]?.includes('/wp-admin/')) { + console.warn('WordPress response was', { + response, + text: response.text, + }); + throw new Error( + `Failed to log in as ${username} with password ${password}` + ); + } }; diff --git a/packages/playground/blueprints/src/lib/steps/mv.spec.ts b/packages/playground/blueprints/src/lib/steps/mv.spec.ts new file mode 100644 index 0000000000..277a149f00 --- /dev/null +++ b/packages/playground/blueprints/src/lib/steps/mv.spec.ts @@ -0,0 +1,55 @@ +import { NodePHP } from '@php-wasm/node'; +import { RecommendedPHPVersion } from '@wp-playground/wordpress'; +import { mv } from './mv'; + +const docroot = '/php'; +describe('Blueprint step mv()', () => { + let php: NodePHP; + beforeEach(async () => { + php = await NodePHP.load(RecommendedPHPVersion); + php.mkdir(docroot); + }); + + it('should move a file', async () => { + php.writeFile(`/${docroot}/index.php`, ` { + await expect( + mv(php, { + fromPath: `/${docroot}/index.php`, + toPath: `/${docroot}/index2.php`, + }) + ).rejects.toThrow(/There is no such file or directory/); + }); + + it('should move a directory', async () => { + php.mkdir(`/${docroot}/dir`); + mv(php, { + fromPath: `/${docroot}/dir`, + toPath: `/${docroot}/dir2`, + }); + expect(php.fileExists(`/${docroot}/dir`)).toBe(false); + expect(php.fileExists(`/${docroot}/dir2`)).toBe(true); + }); + + it('should overwrite the target file', async () => { + php.writeFile(`/${docroot}/index.php`, ` = async ( +export const request: StepHandler> = async ( playground, { request } ) => { - return await playground.request(request); + const response = await playground.request(request); + if (response.httpStatusCode > 399 || response.httpStatusCode < 200) { + console.warn('WordPress response was', { response }); + throw new Error( + `Request failed with status ${response.httpStatusCode}` + ); + } + return response; }; diff --git a/packages/playground/blueprints/src/lib/steps/rewrite-wp-config-to-define-constants.php b/packages/playground/blueprints/src/lib/steps/rewrite-wp-config-to-define-constants.php index 752a8c700e..1d1d977648 100644 --- a/packages/playground/blueprints/src/lib/steps/rewrite-wp-config-to-define-constants.php +++ b/packages/playground/blueprints/src/lib/steps/rewrite-wp-config-to-define-constants.php @@ -271,7 +271,7 @@ function rewrite_wp_config_to_define_constants($content, $constants = []) [','], [var_export($constants[$name], true)], $third_arg_buffer, - [");"], + [");"] ); // Remove the constant from the list so we can process any remaining @@ -292,14 +292,14 @@ function rewrite_wp_config_to_define_constants($content, $constants = []) var_export($name, true), ',', var_export($value, true), - ");\n", - ], + ");\n" + ] ); } $prepend[] = "?>"; $output = array_merge( $prepend, - $output, + $output ); } diff --git a/packages/playground/blueprints/src/lib/steps/rm.spec.ts b/packages/playground/blueprints/src/lib/steps/rm.spec.ts new file mode 100644 index 0000000000..f128ffbc0c --- /dev/null +++ b/packages/playground/blueprints/src/lib/steps/rm.spec.ts @@ -0,0 +1,37 @@ +import { NodePHP } from '@php-wasm/node'; +import { RecommendedPHPVersion } from '@wp-playground/wordpress'; +import { rm } from './rm'; + +const docroot = '/php'; +describe('Blueprint step rm()', () => { + let php: NodePHP; + beforeEach(async () => { + php = await NodePHP.load(RecommendedPHPVersion); + php.mkdir(docroot); + }); + + it('should remove a file', async () => { + php.writeFile(`/${docroot}/index.php`, ` { + await expect( + rm(php, { + path: `/${docroot}/index.php`, + }) + ).rejects.toThrow(/There is no such file or directory/); + }); + + it('should fail when the file is a directory', async () => { + php.mkdir(`/${docroot}/dir`); + await expect( + rm(php, { + path: `/${docroot}/dir`, + }) + ).rejects.toThrow(/There is a directory under that path./); + }); +}); diff --git a/packages/playground/blueprints/src/lib/steps/run-php.spec.ts b/packages/playground/blueprints/src/lib/steps/run-php.spec.ts new file mode 100644 index 0000000000..de342fd73b --- /dev/null +++ b/packages/playground/blueprints/src/lib/steps/run-php.spec.ts @@ -0,0 +1,24 @@ +import { NodePHP } from '@php-wasm/node'; +import { runPHP } from './run-php'; + +const phpVersion = '8.0'; +describe('Blueprint step runPHP', () => { + let php: NodePHP; + + beforeEach(async () => { + php = await NodePHP.load(phpVersion, { + requestHandler: { + documentRoot: '/wordpress', + }, + }); + }); + + it('should run PHP code', async () => { + const result = await runPHP(php, { code: ' { + expect(runPHP(php, { code: ' = async (playground, { code }) => { - return await playground.run({ code }); +export const runPHP: StepHandler> = async ( + playground, + { code } +) => { + return await playground.run({ code, throwOnError: true }); }; diff --git a/packages/playground/blueprints/src/lib/steps/site-data.ts b/packages/playground/blueprints/src/lib/steps/site-data.ts index f69048a522..8ba534d126 100644 --- a/packages/playground/blueprints/src/lib/steps/site-data.ts +++ b/packages/playground/blueprints/src/lib/steps/site-data.ts @@ -1,4 +1,3 @@ -import { PHPResponse } from '@php-wasm/universal'; import { phpVar } from '@php-wasm/util'; import { StepHandler } from '.'; @@ -30,22 +29,21 @@ export type SetSiteOptionsStep = { * option in the `options` object. */ export const setSiteOptions: StepHandler = async ( - client, + php, { options } ) => { - const code = ` $value) { - update_option($name, $value); - } - echo "Success"; - `; - const result = await client.run({ - code, + const docroot = await php.documentRoot; + await php.run({ + throwOnError: true, + code: ` $value) { + update_option($name, $value); + } + echo "Success"; + `, }); - assertSuccess(result); - return { code, result }; }; /** @@ -78,27 +76,18 @@ export interface UpdateUserMetaStep { * meta value in the `meta` object. */ export const updateUserMeta: StepHandler = async ( - client, + php, { meta, userId } ) => { - const code = ` $value) { - update_user_meta(${phpVar(userId)}, $name, $value); - } - echo "Success"; - `; - const result = await client.run({ - code, + const docroot = await php.documentRoot; + await php.run({ + throwOnError: true, + code: ` $value) { + update_user_meta(${phpVar(userId)}, $name, $value); + } + `, }); - assertSuccess(result); - return { code, result }; }; - -async function assertSuccess(result: PHPResponse) { - if (result.text !== 'Success') { - console.log(result); - throw new Error(`Failed to run code: ${result.text} ${result.errors}`); - } -} diff --git a/packages/playground/blueprints/src/lib/utils/run-php-with-zip-functions.ts b/packages/playground/blueprints/src/lib/utils/run-php-with-zip-functions.ts index 4568523dbd..8323a2519f 100644 --- a/packages/playground/blueprints/src/lib/utils/run-php-with-zip-functions.ts +++ b/packages/playground/blueprints/src/lib/utils/run-php-with-zip-functions.ts @@ -5,14 +5,8 @@ export async function runPhpWithZipFunctions( playground: UniversalPHP, code: string ) { - const result = await playground.run({ + return await playground.run({ + throwOnError: true, code: zipFunctions + code, }); - if (result.exitCode !== 0) { - console.log(zipFunctions + code); - console.log(code + ''); - console.log(result.errors); - throw result.errors; - } - return result; } diff --git a/packages/playground/remote/src/lib/worker-thread.ts b/packages/playground/remote/src/lib/worker-thread.ts index 9844a9cbd0..61275f9b7f 100644 --- a/packages/playground/remote/src/lib/worker-thread.ts +++ b/packages/playground/remote/src/lib/worker-thread.ts @@ -224,7 +224,6 @@ try { * The stored version, presumably, has all the patches * already applied. */ - // await wordPressModule; await applyWordPressPatches(php, { wordpressPath: DOCROOT, patchSecrets: true, diff --git a/packages/playground/website/cypress/e2e/website-ui.cy.ts b/packages/playground/website/cypress/e2e/website-ui.cy.ts index ca20cd444b..eb9f010163 100644 --- a/packages/playground/website/cypress/e2e/website-ui.cy.ts +++ b/packages/playground/website/cypress/e2e/website-ui.cy.ts @@ -21,6 +21,11 @@ describe('Playground website UI', () => { // Test all PHP versions for completeness describe('PHP version switcher', () => { SupportedPHPVersions.forEach((version) => { + if (version === '7.0') { + // The SQLite integration plugin uses `private const` which is not supported in PHP 7.0 + // @TODO: Adjust the plugin and remove this condition. + return; + } it('should switch PHP version to ' + version, () => { // Update settings in Playground configurator cy.get('button#configurator').click();