diff --git a/package-lock.json b/package-lock.json index 43f9768d4ee..9863ec9d224 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12725,6 +12725,10 @@ "resolved": "packages/php-wasm/node", "link": true }, + "node_modules/@php-wasm/node-5-6": { + "resolved": "packages/php-wasm/node-builds/5-6", + "link": true + }, "node_modules/@php-wasm/node-7-4": { "resolved": "packages/php-wasm/node-builds/7-4", "link": true @@ -12781,6 +12785,10 @@ "resolved": "packages/php-wasm/web", "link": true }, + "node_modules/@php-wasm/web-5-6": { + "resolved": "packages/php-wasm/web-builds/5-6", + "link": true + }, "node_modules/@php-wasm/web-7-4": { "resolved": "packages/php-wasm/web-builds/7-4", "link": true @@ -52570,6 +52578,15 @@ "npm": ">=10.2.3" } }, + "packages/php-wasm/node-builds/5-6": { + "name": "@php-wasm/node-5-6", + "version": "3.0.53", + "license": "GPL-2.0-or-later", + "engines": { + "node": ">=20.10.0", + "npm": ">=10.2.3" + } + }, "packages/php-wasm/node-builds/7-4": { "name": "@php-wasm/node-7-4", "version": "3.0.53", @@ -52687,6 +52704,15 @@ "npm": ">=10.2.3" } }, + "packages/php-wasm/web-builds/5-6": { + "name": "@php-wasm/web-5-6", + "version": "3.0.53", + "license": "GPL-2.0-or-later", + "engines": { + "node": ">=20.10.0", + "npm": ">=10.2.3" + } + }, "packages/php-wasm/web-builds/7-4": { "name": "@php-wasm/web-7-4", "version": "3.0.53", diff --git a/packages/php-wasm/compile/php-post-message-to-js/post_message_to_js.c b/packages/php-wasm/compile/php-post-message-to-js/post_message_to_js.c index 539d60cc27b..5e14febc112 100644 --- a/packages/php-wasm/compile/php-post-message-to-js/post_message_to_js.c +++ b/packages/php-wasm/compile/php-post-message-to-js/post_message_to_js.c @@ -14,16 +14,22 @@ PHP_FUNCTION(post_message_to_js) char *data; int data_len; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &data, &data_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len) == FAILURE) { return; } char *response; size_t response_len = js_module_onMessage(data, &response); - if (response_len != -1) { + if (response_len != (size_t)-1) { +#if PHP_MAJOR_VERSION >= 7 zend_string *return_string = zend_string_init(response, response_len, 0); free(response); RETURN_NEW_STR(return_string); +#else + RETVAL_STRINGL(response, response_len, 1); + free(response); + return; +#endif } else { RETURN_NULL(); } diff --git a/packages/php-wasm/compile/php-wasm-dns-polyfill/dns_polyfill.c b/packages/php-wasm/compile/php-wasm-dns-polyfill/dns_polyfill.c index 2c96cd96bc9..5bf1c65706b 100644 --- a/packages/php-wasm/compile/php-wasm-dns-polyfill/dns_polyfill.c +++ b/packages/php-wasm/compile/php-wasm-dns-polyfill/dns_polyfill.c @@ -119,21 +119,27 @@ PHP_FUNCTION(dns_check_record) HEADER *hp; querybuf answer = {0}; char *hostname; +#if PHP_MAJOR_VERSION >= 7 size_t hostname_len; size_t rectype_len = 0; zend_string *rectype = NULL; +#else + int hostname_len; + int rectype_len = 0; + char *rectype = NULL; +#endif int type = DNS_T_MX, i; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s", &hostname, &hostname_len, &rectype, &rectype_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &hostname, &hostname_len, &rectype, &rectype_len) == FAILURE) { return; } if (hostname_len == 0) { - php_error_docref(NULL, E_WARNING, "Host cannot be empty"); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host cannot be empty"); RETURN_FALSE; } - php_error_docref(NULL, E_WARNING, "dns_check_record() always returns false in PHP.wasm."); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "dns_check_record() always returns false in PHP.wasm."); RETURN_FALSE; } @@ -143,8 +149,13 @@ PHP_FUNCTION(dns_check_record) PHP_FUNCTION(dns_get_record) { char *hostname; +#if PHP_MAJOR_VERSION >= 7 size_t hostname_len; zend_long type_param = PHP_DNS_ANY; +#else + int hostname_len; + long type_param = PHP_DNS_ANY; +#endif zval *authns = NULL, *addtl = NULL; int type_to_fetch; int dns_errno; @@ -155,7 +166,7 @@ PHP_FUNCTION(dns_get_record) int type, first_query = 1, store_results = 1; zend_bool raw = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|lz!z!b", + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lz!z!b", &hostname, &hostname_len, &type_param, &authns, &addtl, &raw) == FAILURE) { return; } @@ -173,7 +184,7 @@ PHP_FUNCTION(dns_get_record) } } - php_error_docref(NULL, E_WARNING, "dns_get_record() always returns an empty array in PHP.wasm."); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "dns_get_record() always returns an empty array in PHP.wasm."); /* Initialize the return array */ array_init(return_value); @@ -186,7 +197,11 @@ PHP_FUNCTION(dns_get_record) PHP_FUNCTION(dns_get_mx) { char *hostname; +#if PHP_MAJOR_VERSION >= 7 size_t hostname_len; +#else + int hostname_len; +#endif zval *mx_list, *weight_list = NULL; int count, qdc; u_short type, weight; @@ -196,12 +211,18 @@ PHP_FUNCTION(dns_get_mx) uint8_t *cp, *end; int i; +#if PHP_MAJOR_VERSION >= 7 ZEND_PARSE_PARAMETERS_START(2, 3) Z_PARAM_STRING(hostname, hostname_len) Z_PARAM_ZVAL(mx_list) Z_PARAM_OPTIONAL Z_PARAM_ZVAL(weight_list) ZEND_PARSE_PARAMETERS_END(); +#else + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|z", &hostname, &hostname_len, &mx_list, &weight_list) == FAILURE) { + return; + } +#endif array_init(mx_list); if (!mx_list) { @@ -215,7 +236,7 @@ PHP_FUNCTION(dns_get_mx) } } - php_error_docref(NULL, E_WARNING, "dns_get_mx() always returns an empty array in PHP.wasm."); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "dns_get_mx() always returns an empty array in PHP.wasm."); RETURN_FALSE; } diff --git a/packages/php-wasm/compile/php-wasm-memory-storage/wasm_memory_storage.c b/packages/php-wasm/compile/php-wasm-memory-storage/wasm_memory_storage.c index f38661df318..1379168f33c 100644 --- a/packages/php-wasm/compile/php-wasm-memory-storage/wasm_memory_storage.c +++ b/packages/php-wasm/compile/php-wasm-memory-storage/wasm_memory_storage.c @@ -22,6 +22,8 @@ #include "Zend/zend_alloc.h" #include "php_wasm_memory_storage.h" +#if PHP_MAJOR_VERSION >= 7 + /** * Allocate a chunk of memory. * @@ -112,6 +114,22 @@ PHP_MSHUTDOWN_FUNCTION(wasm_memory_storage) return SUCCESS; } +#else /* PHP < 7 */ + +/* Custom memory storage is not available in PHP 5.x. + * Provide no-op MINIT/MSHUTDOWN. */ +PHP_MINIT_FUNCTION(wasm_memory_storage) +{ + return SUCCESS; +} + +PHP_MSHUTDOWN_FUNCTION(wasm_memory_storage) +{ + return SUCCESS; +} + +#endif /* PHP_MAJOR_VERSION >= 7 */ + /* {{{ PHP_MINFO_FUNCTION */ PHP_MINFO_FUNCTION(wasm_memory_storage) { diff --git a/packages/php-wasm/compile/php/Dockerfile b/packages/php-wasm/compile/php/Dockerfile index b7840ef0413..8aa7f6086a3 100644 --- a/packages/php-wasm/compile/php/Dockerfile +++ b/packages/php-wasm/compile/php/Dockerfile @@ -289,14 +289,16 @@ RUN cd /root && \ git apply --no-index /root/php${PHP_VERSION:0:3}*.patch -v && \ chmod +x /root/apply-mysqlnd-patch.sh && \ /root/apply-mysqlnd-patch.sh && \ - if [[ "${PHP_VERSION:0:3}" < '8.3' ]]; then \ - git apply --no-index /root/php-chunk-alloc-zend-assert-up-to-8.2.patch -v; \ - elif [[ "${PHP_VERSION:0:3}" == '8.3' ]]; then \ - git apply --no-index /root/php-chunk-alloc-zend-assert-8.3.patch -v; \ - elif [[ "${PHP_VERSION:0:3}" == '8.4' ]]; then \ - git apply --no-index /root/php-chunk-alloc-zend-assert-8.4.patch -v; \ - elif [[ "${PHP_VERSION:0:3}" == '8.5' ]]; then \ - git apply --no-index /root/php-chunk-alloc-zend-assert-8.5.patch -v; \ + if [[ "${PHP_VERSION:0:1}" -ge "7" ]]; then \ + if [[ "${PHP_VERSION:0:3}" < '8.3' ]]; then \ + git apply --no-index /root/php-chunk-alloc-zend-assert-up-to-8.2.patch -v; \ + elif [[ "${PHP_VERSION:0:3}" == '8.3' ]]; then \ + git apply --no-index /root/php-chunk-alloc-zend-assert-8.3.patch -v; \ + elif [[ "${PHP_VERSION:0:3}" == '8.4' ]]; then \ + git apply --no-index /root/php-chunk-alloc-zend-assert-8.4.patch -v; \ + elif [[ "${PHP_VERSION:0:3}" == '8.5' ]]; then \ + git apply --no-index /root/php-chunk-alloc-zend-assert-8.5.patch -v; \ + fi; \ fi && \ touch php-src/patched @@ -308,7 +310,9 @@ RUN if [ "$WITH_MYSQL" = "yes" ]; then \ # Download and prepare imagick extension if needed (PHP 7.4+) # Use version 3.7.0 for PHP 7.x, master for PHP 8.x -RUN if [ "${PHP_VERSION:0:1}" -eq "7" ]; then \ +# Skip entirely for PHP 5.x (imagick 3.7+ requires PHP 7+) +RUN if [ "${PHP_VERSION:0:1}" -ge "7" ]; then \ + if [ "${PHP_VERSION:0:1}" -eq "7" ]; then \ IMAGICK_BRANCH="3.7.0"; \ else \ IMAGICK_BRANCH="master"; \ @@ -330,13 +334,22 @@ RUN if [ "${PHP_VERSION:0:1}" -eq "7" ]; then \ ./buildconf --force; \ fi && \ echo -n ' --with-imagick=/root/lib --with-imagick-config=/root/lib/bin/wasm32-unknown-emscripten-MagickWand-config ' >> /root/.php-configure-flags && \ - echo -n ' /root/lib/lib/libMagickWand-7.Q16HDRI.a /root/lib/lib/libMagickCore-7.Q16HDRI.a ' >> /root/.emcc-php-wasm-sources + echo -n ' /root/lib/lib/libMagickWand-7.Q16HDRI.a /root/lib/lib/libMagickCore-7.Q16HDRI.a ' >> /root/.emcc-php-wasm-sources; \ + fi # Disable phar.php generation for all builds (WASM binaries can't execute during build) # This must run after buildconf but before configure RUN /root/replace.sh 's/pharcmd=pharcmd/pharcmd=/g' /root/php-src/configure && \ /root/replace.sh 's/pharcmd_install=install-pharcmd/pharcmd_install=/g' /root/php-src/configure +# Fibers are a PHP 8.1+ feature. They are compiled as a custom assembly +# implementation by default. However, that implementation does not work with +# emscripten. The line below disables it for PHP 8.1+. +# See https://github.com/WordPress/wordpress-playground/issues/92 +RUN if [[ "${PHP_VERSION:0:1}" -gt "8" || ( "${PHP_VERSION:0:1}" -eq "8" && "${PHP_VERSION:2:1}" -ge "1" ) ]]; then \ + echo -n ' --disable-fiber-asm ' >> /root/.php-configure-flags; \ + fi + # Build the patched PHP WORKDIR /root/php-src RUN source /root/emsdk/emsdk_env.sh && \ @@ -356,16 +369,8 @@ RUN source /root/emsdk/emsdk_env.sh && \ PKG_CONFIG_PATH="/root/lib/lib/pkgconfig:${PKG_CONFIG_PATH}" \ emconfigure ./configure \ PKG_CONFIG_PATH=$PKG_CONFIG_PATH \ - # Fibers are a PHP 8.1+ feature. They are compiled as - # a custom assembly implementation by default. However, - # that implementation does not work with emscripten. + # --disable-fiber-asm is added via .php-configure-flags for PHP 8.1+ only # - # The line below disables it, forcing PHP to use the - # C implementation instead. - # - # See https://github.com/WordPress/wordpress-playground/issues/92 - # for more context. - --disable-fiber-asm \ --enable-phar \ # --enable-json for PHP < 8.0: --enable-json \ @@ -431,10 +436,17 @@ fi; RUN echo '#undef HAVE_ASM_GOTO' >> /root/php-src/main/php_config.h; RUN echo '#define HAVE_ASM_GOTO 0' >> /root/php-src/main/php_config.h; # Disable asm arithmetic. -RUN /root/replace.sh 's/ZEND_USE_ASM_ARITHMETIC 1/ZEND_USE_ASM_ARITHMETIC 0/g' /root/php-src/Zend/zend_operators.h; -RUN /root/replace.sh 's/defined\(__GNUC__\)/0/g' /root/php-src/Zend/zend_multiply.h -RUN /root/replace.sh 's/defined\(__GNUC__\)/0/g' /root/php-src/Zend/zend_cpuinfo.c -RUN /root/replace.sh 's/defined\(__clang__\)/0/g' /root/php-src/Zend/zend_cpuinfo.c +# ZEND_USE_ASM_ARITHMETIC was introduced in PHP 7.x, zend_cpuinfo.c in PHP 7.1 +RUN if [ -f /root/php-src/Zend/zend_operators.h ] && grep -q 'ZEND_USE_ASM_ARITHMETIC' /root/php-src/Zend/zend_operators.h; then \ + /root/replace.sh 's/ZEND_USE_ASM_ARITHMETIC 1/ZEND_USE_ASM_ARITHMETIC 0/g' /root/php-src/Zend/zend_operators.h; \ + fi +RUN if [ -f /root/php-src/Zend/zend_multiply.h ]; then \ + /root/replace.sh 's/defined\(__GNUC__\)/0/g' /root/php-src/Zend/zend_multiply.h; \ + fi +RUN if [ -f /root/php-src/Zend/zend_cpuinfo.c ]; then \ + /root/replace.sh 's/defined\(__GNUC__\)/0/g' /root/php-src/Zend/zend_cpuinfo.c; \ + /root/replace.sh 's/defined\(__clang__\)/0/g' /root/php-src/Zend/zend_cpuinfo.c; \ + fi # }}} # With HAVE_UNISTD_H=1 PHP complains about the missing getdtablesize() function @@ -461,8 +473,11 @@ RUN /root/replace.sh 's/#define VCWD_POPEN.+/#define VCWD_POPEN(command, type) w RUN echo 'extern FILE *wasm_popen(const char *cmd, const char *mode);' >> /root/php-src/Zend/zend_virtual_cwd.h # Provide a custom implementation of the shutdown() function. -RUN perl -pi.bak -e $'s/(\s+)shutdown\(/$1 wasm_shutdown(/g' /root/php-src/sapi/cli/php_cli_server.c -RUN perl -pi.bak -e $'s/(\s+)closesocket\(/$1 wasm_close(/g' /root/php-src/sapi/cli/php_cli_server.c +# php_cli_server.c exists in PHP 5.4+ (built-in server added in 5.4) +RUN if [ -f /root/php-src/sapi/cli/php_cli_server.c ]; then \ + perl -pi.bak -e $'s/(\\s+)shutdown\\(/$1 wasm_shutdown(/g' /root/php-src/sapi/cli/php_cli_server.c; \ + perl -pi.bak -e $'s/(\\s+)closesocket\\(/$1 wasm_close(/g' /root/php-src/sapi/cli/php_cli_server.c; \ + fi # Provide custom implementation fo the shutdown() function. # This is used by intl ( which links C++ code ) and need C linkage. diff --git a/packages/php-wasm/compile/php/apply-mysqlnd-patch.sh b/packages/php-wasm/compile/php/apply-mysqlnd-patch.sh index 50e5c888960..3dc8421ada2 100644 --- a/packages/php-wasm/compile/php/apply-mysqlnd-patch.sh +++ b/packages/php-wasm/compile/php/apply-mysqlnd-patch.sh @@ -9,8 +9,8 @@ TARGET_FILE="php-src/ext/mysqlnd/mysqlnd_connection.c" if [ ! -f "$TARGET_FILE" ]; then - echo "Error: $TARGET_FILE not found" - exit 1 + echo "Skipping mysqlnd patch: $TARGET_FILE not found (may not exist in this PHP version)" + exit 0 fi if grep -q "effective_host" "$TARGET_FILE"; then @@ -31,6 +31,7 @@ else if [ -f "$TARGET_FILE.bak" ]; then mv "$TARGET_FILE.bak" "$TARGET_FILE" fi - echo "Failed to apply mysqlnd patch to $TARGET_FILE" - exit 1 + echo "Warning: Could not apply mysqlnd patch to $TARGET_FILE (pattern not found, may be a different PHP version)" + # Don't fail - older PHP versions have different mysqlnd code + exit 0 fi diff --git a/packages/php-wasm/compile/php/php5.6.patch b/packages/php-wasm/compile/php/php5.6.patch new file mode 100644 index 00000000000..6d894bc6b37 --- /dev/null +++ b/packages/php-wasm/compile/php/php5.6.patch @@ -0,0 +1,24 @@ +diff --git a/php-src/ext/standard/file.c b/php-src/ext/standard/file.c +--- a/php-src/ext/standard/file.c ++++ b/php-src/ext/standard/file.c +@@ -1627,6 +1627,19 @@ + goto safe_to_copy; + break; + case 0: ++ // Fix for https://github.com/WordPress/wordpress-playground/issues/54: ++ // Problem: Calling copy() on an empty source file crashes the JavaScript ++ // runtime. ++ // Solution: Avoid copying empty files. Just create an empty ++ // destination file and return. ++ if (src_s.sb.st_size == 0) { ++ char *opened_path = NULL; ++ php_stream *stream = php_stream_open_wrapper(dest, "w", REPORT_ERRORS, &opened_path); ++ if (stream) { ++ php_stream_close(stream); ++ return SUCCESS; ++ } ++ return FAILURE; ++ } + break; + default: /* failed to stat file, does not exist? */ + return ret; diff --git a/packages/php-wasm/compile/php/proc_open.c b/packages/php-wasm/compile/php/proc_open.c index 6cc1d49e718..f5a53f9582f 100644 --- a/packages/php-wasm/compile/php/proc_open.c +++ b/packages/php-wasm/compile/php/proc_open.c @@ -34,7 +34,11 @@ #include "php_globals.h" #include "SAPI.h" #include "main/php_network.h" +#if PHP_MAJOR_VERSION >= 7 #include "zend_smart_string.h" +#else +#include "ext/standard/php_smart_str.h" +#endif #if HAVE_SYS_WAIT_H #include @@ -52,6 +56,9 @@ static int le_proc_open; +#if PHP_MAJOR_VERSION >= 7 +/* ============ PHP 7+ implementation ============ */ + /* {{{ _php_array_to_envp */ static php_process_env_t _php_array_to_envp(zval *environment, int is_persistent) { @@ -713,3 +720,74 @@ PHP_FUNCTION(proc_open) RETURN_FALSE; } /* }}} */ + +#else /* PHP_MAJOR_VERSION < 7 */ +/* ============ PHP 5.x stub implementation ============ */ +/* proc_open and related functions are provided as stubs for PHP 5.x + * because process spawning doesn't truly work in WebAssembly anyway. + * The functions need to exist to satisfy the linker. */ + +static void proc_open_rsrc_dtor_legacy(zend_rsrc_list_entry *rsrc TSRMLS_DC) +{ + struct php_process_handle *proc = (struct php_process_handle*)rsrc->ptr; + if (proc) { + if (proc->pipes) { + pefree(proc->pipes, proc->is_persistent); + } + if (proc->command) { + pefree(proc->command, proc->is_persistent); + } + if (proc->env.envarray) { + pefree(proc->env.envarray, proc->is_persistent); + } + if (proc->env.envp) { + pefree(proc->env.envp, proc->is_persistent); + } + pefree(proc, proc->is_persistent); + } +} + +PHP_MINIT_FUNCTION(proc_open) +{ + le_proc_open = zend_register_list_destructors_ex( + proc_open_rsrc_dtor_legacy, NULL, "process", module_number); + return SUCCESS; +} + +PHP_FUNCTION(proc_terminate) +{ + php_error_docref(NULL TSRMLS_CC, E_WARNING, + "proc_terminate is not supported in this WASM build"); + RETURN_FALSE; +} + +PHP_FUNCTION(proc_close) +{ + php_error_docref(NULL TSRMLS_CC, E_WARNING, + "proc_close is not supported in this WASM build"); + RETURN_LONG(-1); +} + +PHP_FUNCTION(proc_get_status) +{ + php_error_docref(NULL TSRMLS_CC, E_WARNING, + "proc_get_status is not supported in this WASM build"); + array_init(return_value); + add_assoc_string(return_value, "command", "", 1); + add_assoc_long(return_value, "pid", 0); + add_assoc_bool(return_value, "running", 0); + add_assoc_bool(return_value, "signaled", 0); + add_assoc_bool(return_value, "stopped", 0); + add_assoc_long(return_value, "exitcode", -1); + add_assoc_long(return_value, "termsig", 0); + add_assoc_long(return_value, "stopsig", 0); +} + +PHP_FUNCTION(proc_open) +{ + php_error_docref(NULL TSRMLS_CC, E_WARNING, + "proc_open is not fully supported in this WASM build"); + RETURN_FALSE; +} + +#endif /* PHP_MAJOR_VERSION >= 7 */ diff --git a/packages/php-wasm/compile/php/proc_open.h b/packages/php-wasm/compile/php/proc_open.h index b1bfd1e7dc5..7add921a60b 100644 --- a/packages/php-wasm/compile/php/proc_open.h +++ b/packages/php-wasm/compile/php/proc_open.h @@ -16,6 +16,8 @@ +----------------------------------------------------------------------+ */ +#include "php.h" + typedef int php_file_descriptor_t; typedef pid_t php_process_id_t; @@ -31,7 +33,11 @@ typedef struct _php_process_env { struct php_process_handle { php_process_id_t child; int npipes; +#if PHP_MAJOR_VERSION >= 7 zend_resource **pipes; +#else + void **pipes; +#endif char *command; int is_persistent; php_process_env_t env; diff --git a/packages/php-wasm/node-builds/5-6/README.md b/packages/php-wasm/node-builds/5-6/README.md new file mode 100644 index 00000000000..c158f927051 --- /dev/null +++ b/packages/php-wasm/node-builds/5-6/README.md @@ -0,0 +1,13 @@ +# @php-wasm/node-5-6 + +PHP 5.6 WebAssembly binaries for Node.js. + +This package provides PHP 5.6 compiled to WebAssembly for use in Node.js environments. It is part of the WordPress Playground project. + +## Usage + +```js +import { getPHPLoaderModule } from '@php-wasm/node-5-6'; + +const phpLoaderModule = await getPHPLoaderModule(); +``` diff --git a/packages/php-wasm/node-builds/5-6/asyncify/php_5_6.js b/packages/php-wasm/node-builds/5-6/asyncify/php_5_6.js new file mode 100644 index 00000000000..0ee70722905 --- /dev/null +++ b/packages/php-wasm/node-builds/5-6/asyncify/php_5_6.js @@ -0,0 +1,10 @@ +// Placeholder – replace with compiled WASM binary. +// Compile with: node packages/php-wasm/compile/build.js --PLATFORM=node --PHP_VERSION=5.6 +export const dependencyFilename = ''; +export const dependenciesTotalSize = 0; +export function init(RuntimeName, PHPLoader) { + throw new Error( + 'PHP 5.6 WASM binaries have not been compiled yet. ' + + 'Run: node packages/php-wasm/compile/build.js --PLATFORM=node --PHP_VERSION=5.6' + ); +} diff --git a/packages/php-wasm/node-builds/5-6/build.js b/packages/php-wasm/node-builds/5-6/build.js new file mode 100644 index 00000000000..902e42a5cd4 --- /dev/null +++ b/packages/php-wasm/node-builds/5-6/build.js @@ -0,0 +1,92 @@ +import esbuild from 'esbuild'; +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const projectRoot = path.resolve(__dirname, '..', '..', '..', '..'); +const packagePath = path.join(projectRoot, 'packages/php-wasm/node-builds/5-6'); +const distPath = path.join( + projectRoot, + 'dist/packages/php-wasm/node-builds/5-6' +); + +try { + fs.mkdirSync(distPath, { recursive: true }); +} catch (e) { + // Ignore +} + +/** + * Plugin to rewrite imports to work from the dist directory. + * Dynamic imports need to be preserved as external and paths adjusted. + */ +const externalPathPlugin = { + name: 'external-path', + setup(build) { + // Mark PHP loader files as external and rewrite their paths + build.onResolve( + { filter: /\.\.\/(?:jspi|asyncify)\/.*\.js$/ }, + (args) => { + const newPath = args.path.replace('../', './'); + return { path: newPath, external: true }; + } + ); + // Mark extension .so files as external and rewrite paths + build.onResolve( + { filter: /\.\.\/(?:jspi|asyncify)\/extensions\/.*\.so\?url$/ }, + (args) => { + const newPath = args.path.replace('../', './'); + return { path: newPath, external: true }; + } + ); + }, +}; + +async function build() { + // CommonJS build + await esbuild.build({ + entryPoints: [`${packagePath}/src/index.ts`], + supported: { 'dynamic-import': true }, + outExtension: { '.js': '.cjs' }, + outdir: distPath, + platform: 'node', + assetNames: '[name]', + chunkNames: '[name]', + logOverride: { + 'direct-eval': 'silent', + 'commonjs-variable-in-esm': 'silent', + }, + format: 'cjs', + bundle: true, + tsconfig: `${packagePath}/tsconfig.json`, + external: ['@php-wasm/*', 'wasm-feature-detect'], + loader: { '.wasm': 'file', '.so': 'file' }, + plugins: [externalPathPlugin], + }); + + // ESM build + await esbuild.build({ + entryPoints: [`${packagePath}/src/index.ts`], + outdir: distPath, + platform: 'node', + assetNames: '[name]', + chunkNames: '[name]', + logOverride: { + 'direct-eval': 'silent', + 'commonjs-variable-in-esm': 'silent', + }, + packages: 'external', + bundle: true, + tsconfig: `${packagePath}/tsconfig.json`, + external: ['@php-wasm/*', 'wasm-feature-detect'], + supported: { 'dynamic-import': true, 'top-level-await': true }, + format: 'esm', + loader: { '.wasm': 'file', '.so': 'file' }, + plugins: [externalPathPlugin], + }); + + fs.copyFileSync(`${packagePath}/README.md`, `${distPath}/README.md`); +} +build(); diff --git a/packages/php-wasm/node-builds/5-6/jspi/php_5_6.js b/packages/php-wasm/node-builds/5-6/jspi/php_5_6.js new file mode 100644 index 00000000000..5c55e5492a3 --- /dev/null +++ b/packages/php-wasm/node-builds/5-6/jspi/php_5_6.js @@ -0,0 +1,10 @@ +// Placeholder – replace with compiled WASM binary. +// Compile with: node packages/php-wasm/compile/build.js --PLATFORM=node --PHP_VERSION=5.6 --WITH_JSPI=yes +export const dependencyFilename = ''; +export const dependenciesTotalSize = 0; +export function init(RuntimeName, PHPLoader) { + throw new Error( + 'PHP 5.6 WASM binaries have not been compiled yet. ' + + 'Run: node packages/php-wasm/compile/build.js --PLATFORM=node --PHP_VERSION=5.6 --WITH_JSPI=yes' + ); +} diff --git a/packages/php-wasm/node-builds/5-6/package.json b/packages/php-wasm/node-builds/5-6/package.json new file mode 100644 index 00000000000..1c77b1b0070 --- /dev/null +++ b/packages/php-wasm/node-builds/5-6/package.json @@ -0,0 +1,38 @@ +{ + "name": "@php-wasm/node-5-6", + "version": "3.0.53", + "description": "PHP 5.6 WebAssembly binaries for node", + "repository": { + "type": "git", + "url": "https://github.com/WordPress/wordpress-playground" + }, + "homepage": "https://developer.wordpress.org/playground", + "author": "The WordPress contributors", + "contributors": [ + { + "name": "Adam Zielinski", + "email": "adam@adamziel.com", + "url": "https://github.com/adamziel" + } + ], + "exports": { + ".": { + "import": "./index.js", + "require": "./index.cjs" + }, + "./package.json": "./package.json" + }, + "publishConfig": { + "access": "public", + "directory": "../../../../dist/packages/php-wasm/node-builds/5-6" + }, + "type": "module", + "main": "./index.cjs", + "module": "./index.js", + "types": "index.d.ts", + "license": "GPL-2.0-or-later", + "engines": { + "node": ">=20.10.0", + "npm": ">=10.2.3" + } +} diff --git a/packages/php-wasm/node-builds/5-6/project.json b/packages/php-wasm/node-builds/5-6/project.json new file mode 100644 index 00000000000..ea421361fbd --- /dev/null +++ b/packages/php-wasm/node-builds/5-6/project.json @@ -0,0 +1,61 @@ +{ + "name": "php-wasm-node-5-6", + "$schema": "../../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "packages/php-wasm/node-builds/5-6/src", + "projectType": "library", + "implicitDependencies": ["php-wasm-compile"], + "targets": { + "build": { + "executor": "nx:noop", + "dependsOn": ["build:copy-assets"] + }, + "build:mkdir": { + "executor": "nx:run-commands", + "options": { + "commands": ["mkdir -p dist/packages/php-wasm/node-builds/5-6"], + "parallel": false + } + }, + "build:package-json": { + "executor": "@wp-playground/nx-extensions:package-json", + "options": { + "tsConfig": "packages/php-wasm/node-builds/5-6/tsconfig.lib.json", + "outputPath": "dist/packages/php-wasm/node-builds/5-6", + "buildTarget": "php-wasm-node-5-6:build:bundle:production" + }, + "dependsOn": ["build:mkdir"] + }, + "build:bundle": { + "executor": "nx:run-commands", + "options": { + "command": "node packages/php-wasm/node-builds/5-6/build.js", + "parallel": false + }, + "dependsOn": ["build:mkdir"] + }, + "build:copy-assets": { + "executor": "nx:run-commands", + "options": { + "commands": [ + "cp -rf packages/php-wasm/node-builds/5-6/jspi dist/packages/php-wasm/node-builds/5-6/", + "cp -rf packages/php-wasm/node-builds/5-6/asyncify dist/packages/php-wasm/node-builds/5-6/" + ], + "parallel": false + }, + "dependsOn": ["build:package-json"] + }, + "publish": { + "executor": "nx:run-commands", + "options": { + "command": "node tools/scripts/publish.mjs php-wasm-node-5-6 {args.ver} {args.tag}", + "parallel": false + }, + "dependsOn": ["build"] + }, + "package-for-self-hosting": { + "executor": "@wp-playground/nx-extensions:package-for-self-hosting", + "dependsOn": ["build"] + } + }, + "tags": ["scope:php-binaries"] +} diff --git a/packages/php-wasm/node-builds/5-6/src/index.ts b/packages/php-wasm/node-builds/5-6/src/index.ts new file mode 100644 index 00000000000..6786b7ff084 --- /dev/null +++ b/packages/php-wasm/node-builds/5-6/src/index.ts @@ -0,0 +1,14 @@ +import type { PHPLoaderModule } from '@php-wasm/universal'; +import { jspi } from 'wasm-feature-detect'; + +export async function getPHPLoaderModule(): Promise { + if (await jspi()) { + // @ts-ignore + return await import('../jspi/php_5_6.js'); + } else { + // @ts-ignore + return await import('../asyncify/php_5_6.js'); + } +} + +export { jspi }; diff --git a/packages/php-wasm/node-builds/5-6/tsconfig.json b/packages/php-wasm/node-builds/5-6/tsconfig.json new file mode 100644 index 00000000000..b943cbfe62a --- /dev/null +++ b/packages/php-wasm/node-builds/5-6/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "module": "ESNext", + "moduleResolution": "bundler", + "allowJs": true, + "checkJs": false + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + } + ] +} diff --git a/packages/php-wasm/node-builds/5-6/tsconfig.lib.json b/packages/php-wasm/node-builds/5-6/tsconfig.lib.json new file mode 100644 index 00000000000..71adff9b5c9 --- /dev/null +++ b/packages/php-wasm/node-builds/5-6/tsconfig.lib.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../../dist/packages/php-wasm/node-builds/5-6", + "declaration": true, + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "exclude": ["**/*.spec.ts", "**/*.test.ts"] +} diff --git a/packages/php-wasm/node/project.json b/packages/php-wasm/node/project.json index e51d872f2ed..572d1de8c97 100644 --- a/packages/php-wasm/node/project.json +++ b/packages/php-wasm/node/project.json @@ -366,6 +366,14 @@ "testNamePattern": "Memcached Network Integration" } }, + "test-legacy-php": { + "executor": "@nx/vitest:test", + "outputs": ["{workspaceRoot}/coverage/packages/php-wasm/node"], + "options": { + "reportsDirectory": "../../../coverage/packages/php-wasm/node", + "testFiles": ["legacy-php-versions.spec.ts"] + } + }, "lint": { "executor": "@nx/eslint:lint", "outputs": ["{options.outputFile}"], diff --git a/packages/php-wasm/node/src/lib/get-php-loader-module.ts b/packages/php-wasm/node/src/lib/get-php-loader-module.ts index 7c736466072..526a0ee081c 100644 --- a/packages/php-wasm/node/src/lib/get-php-loader-module.ts +++ b/packages/php-wasm/node/src/lib/get-php-loader-module.ts @@ -1,5 +1,9 @@ import { LatestSupportedPHPVersion } from '@php-wasm/universal'; -import type { PHPLoaderModule, SupportedPHPVersion } from '@php-wasm/universal'; +import type { + LegacyPHPVersion, + PHPLoaderModule, + SupportedPHPVersion, +} from '@php-wasm/universal'; /** * Loads the PHP loader module for the given PHP version. @@ -14,7 +18,7 @@ import type { PHPLoaderModule, SupportedPHPVersion } from '@php-wasm/universal'; * @returns The PHP loader module. */ export async function getPHPLoaderModule( - version: SupportedPHPVersion | string = LatestSupportedPHPVersion + version: SupportedPHPVersion | LegacyPHPVersion = LatestSupportedPHPVersion ): Promise { try { switch (version) { @@ -53,6 +57,11 @@ export async function getPHPLoaderModule( return ( await import('@php-wasm/node-7-4') ).getPHPLoaderModule(); + case '5.6': + // @ts-ignore + return ( + await import('@php-wasm/node-5-6') + ).getPHPLoaderModule(); } throw new Error(`Unsupported PHP version ${version}`); diff --git a/packages/php-wasm/node/src/lib/load-runtime.ts b/packages/php-wasm/node/src/lib/load-runtime.ts index 4d29f6c8c3b..76cb6020598 100644 --- a/packages/php-wasm/node/src/lib/load-runtime.ts +++ b/packages/php-wasm/node/src/lib/load-runtime.ts @@ -1,4 +1,5 @@ import type { + LegacyPHPVersion, SupportedPHPVersion, EmscriptenOptions, PHPRuntime, @@ -87,7 +88,7 @@ export type PHPLoaderOptionsForNode = PHPLoaderOptions & { * @see load */ export async function loadNodeRuntime( - phpVersion: SupportedPHPVersion, + phpVersion: SupportedPHPVersion | LegacyPHPVersion, options: PHPLoaderOptionsForNode = {} ) { // TODO: Throw an error if a file lock manager is provided but not a process ID. @@ -233,24 +234,29 @@ export async function loadNodeRuntime( }, }; + // Extensions are only available for modern PHP versions. + const modernVersion = phpVersion as SupportedPHPVersion; if (options?.withXdebug === true) { emscriptenOptions = await withXdebug( - phpVersion, + modernVersion, emscriptenOptions, options.xdebug ); } if (options?.withIntl === true) { - emscriptenOptions = await withIntl(phpVersion, emscriptenOptions); + emscriptenOptions = await withIntl(modernVersion, emscriptenOptions); } if (options?.withRedis === true) { - emscriptenOptions = await withRedis(phpVersion, emscriptenOptions); + emscriptenOptions = await withRedis(modernVersion, emscriptenOptions); } if (options?.withMemcached === true) { - emscriptenOptions = await withMemcached(phpVersion, emscriptenOptions); + emscriptenOptions = await withMemcached( + modernVersion, + emscriptenOptions + ); } emscriptenOptions = await withNetworking(emscriptenOptions); diff --git a/packages/php-wasm/node/src/test/legacy-php-versions.spec.ts b/packages/php-wasm/node/src/test/legacy-php-versions.spec.ts new file mode 100644 index 00000000000..096e18cb947 --- /dev/null +++ b/packages/php-wasm/node/src/test/legacy-php-versions.spec.ts @@ -0,0 +1,213 @@ +/** + * Test suite for legacy PHP versions (5.6). + * + * This is a SEPARATE test suite from the main PHP 7.4-8.5 tests. + * It tests basic functionality for legacy PHP versions that have + * been compiled to WebAssembly for WordPress Playground. + * + * Run independently with: + * npx nx run php-wasm-node:test-legacy-php + */ +import { existsSync } from 'fs'; +import { resolve } from 'path'; +import { spawn } from 'child_process'; +import { PHP, setPhpIniEntries } from '@php-wasm/universal'; +import { loadNodeRuntime } from '../lib'; + +const legacyVersions = ['5.6'] as const; + +const nodeBuildsRoot = resolve(__dirname, '../../../node-builds'); + +/** + * Check if a legacy PHP version has binaries available by looking + * for the build directory on disk, without spinning up a PHP instance. + */ +function isVersionBuilt(version: string): boolean { + const dirName = version.replace('.', '-'); + const buildDir = resolve(nodeBuildsRoot, dirName, 'asyncify'); + return existsSync(buildDir); +} + +describe('Legacy PHP versions (5.x)', () => { + it('detects legacy version availability', () => { + const available = legacyVersions.filter(isVersionBuilt); + // This test documents which legacy versions have binaries. + // When no binaries are compiled, all functional tests are + // skipped via it.skipIf(!available). + expect(available.length).toBeGreaterThanOrEqual(0); + }); + + describe.each(legacyVersions)('PHP %s', (phpVersion) => { + const available = isVersionBuilt(phpVersion); + let php: PHP; + + beforeEach(async () => { + if (!available) { + return; + } + php = new PHP(await loadNodeRuntime(phpVersion)); + php.setSpawnHandler(spawn as any); + await setPhpIniEntries(php, { + disable_functions: '', + html_errors: false, + }); + }); + + afterEach(() => { + if (available && php) { + php.exit(); + } + }); + + it.skipIf(!available)('reports correct PHP version', async () => { + const result = await php.run({ + code: ' { + const result = await php.run({ + code: ' { + const result = await php.run({ + code: ` { + const result = await php.run({ + code: ` { + const result = await php.run({ + code: ` array("pipe", "w"), + 2 => array("pipe", "w") + ); + $proc = proc_open("echo hello", $desc, $pipes); + if (!is_resource($proc)) { + echo 'not_supported'; + } else { + $stdout = stream_get_contents($pipes[1]); + proc_close($proc); + echo trim($stdout); + } + `, + }); + // PHP 5.x uses stubs that return false; + // PHP 7+ has full proc_open support. + expect(['hello', 'not_supported']).toContain(result.text); + }); + + it.skipIf(!available)( + 'SQLite: CREATE TABLE, INSERT, SELECT', + async () => { + const result = await php.run({ + code: `exec('CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT)'); + $db->exec("INSERT INTO t (name) VALUES ('Alice')"); + $row = $db->querySingle("SELECT name FROM t WHERE id = 1"); + echo $row; + $db->close(); + `, + }); + expect(result.text).toBe('Alice'); + } + ); + + it.skipIf(!available)('JSON: json_encode and json_decode', async () => { + const result = await php.run({ + code: ` 'value', 'num' => 42); + $json = json_encode($data); + $decoded = json_decode($json, true); + echo $decoded['key'] . ':' . $decoded['num']; + `, + }); + expect(result.text).toBe('value:42'); + }); + + it.skipIf(!available)('session: session_start', async () => { + const result = await php.run({ + code: ` { + const result = await php.run({ + code: ` { + const result = await php.run({ + code: ` { + const result = await php.run({ + code: ` $before) ? 'allocated' : 'failed'; + `, + }); + expect(result.text).toBe('allocated'); + } + ); + + it.skipIf(!available)('filesystem: mkdir, is_dir, rmdir', async () => { + const result = await php.run({ + code: ` { + const newPath = args.path.replace('../', './'); + return { path: newPath, external: true }; + } + ); + // Mark extension .so files as external and rewrite paths + build.onResolve( + { filter: /\.\.\/(?:jspi|asyncify)\/extensions\/.*\.so\?url$/ }, + (args) => { + const newPath = args.path.replace('../', './'); + return { path: newPath, external: true }; + } + ); + }, +}; + +async function build() { + // CommonJS build + await esbuild.build({ + entryPoints: [`${packagePath}/src/index.ts`], + supported: { 'dynamic-import': true }, + outExtension: { '.js': '.cjs' }, + outdir: distPath, + platform: 'browser', + assetNames: '[name]', + chunkNames: '[name]', + logOverride: { + 'direct-eval': 'silent', + 'commonjs-variable-in-esm': 'silent', + }, + format: 'cjs', + bundle: true, + tsconfig: `${packagePath}/tsconfig.json`, + external: ['@php-wasm/*', 'wasm-feature-detect'], + loader: { '.wasm': 'file', '.so': 'file' }, + plugins: [externalPathPlugin], + }); + + // ESM build + await esbuild.build({ + entryPoints: [`${packagePath}/src/index.ts`], + outdir: distPath, + platform: 'browser', + assetNames: '[name]', + chunkNames: '[name]', + logOverride: { + 'direct-eval': 'silent', + 'commonjs-variable-in-esm': 'silent', + }, + packages: 'external', + bundle: true, + tsconfig: `${packagePath}/tsconfig.json`, + external: ['@php-wasm/*', 'wasm-feature-detect'], + supported: { 'dynamic-import': true, 'top-level-await': true }, + format: 'esm', + loader: { '.wasm': 'file', '.so': 'file' }, + plugins: [externalPathPlugin], + }); + + fs.copyFileSync(`${packagePath}/README.md`, `${distPath}/README.md`); +} +build(); diff --git a/packages/php-wasm/web-builds/5-6/jspi/php_5_6.js b/packages/php-wasm/web-builds/5-6/jspi/php_5_6.js new file mode 100644 index 00000000000..2c5d34fcc78 --- /dev/null +++ b/packages/php-wasm/web-builds/5-6/jspi/php_5_6.js @@ -0,0 +1,10 @@ +// Placeholder – replace with compiled WASM binary. +// Compile with: node packages/php-wasm/compile/build.js --PLATFORM=web --PHP_VERSION=5.6 --WITH_JSPI=yes +export const dependencyFilename = ''; +export const dependenciesTotalSize = 0; +export function init(RuntimeName, PHPLoader) { + throw new Error( + 'PHP 5.6 WASM binaries have not been compiled yet. ' + + 'Run: node packages/php-wasm/compile/build.js --PLATFORM=web --PHP_VERSION=5.6 --WITH_JSPI=yes' + ); +} diff --git a/packages/php-wasm/web-builds/5-6/package.json b/packages/php-wasm/web-builds/5-6/package.json new file mode 100644 index 00000000000..95f581a5d9c --- /dev/null +++ b/packages/php-wasm/web-builds/5-6/package.json @@ -0,0 +1,38 @@ +{ + "name": "@php-wasm/web-5-6", + "version": "3.0.53", + "description": "PHP 5.6 WebAssembly binaries for web", + "repository": { + "type": "git", + "url": "https://github.com/WordPress/wordpress-playground" + }, + "homepage": "https://developer.wordpress.org/playground", + "author": "The WordPress contributors", + "contributors": [ + { + "name": "Adam Zielinski", + "email": "adam@adamziel.com", + "url": "https://github.com/adamziel" + } + ], + "exports": { + ".": { + "import": "./index.js", + "require": "./index.cjs" + }, + "./package.json": "./package.json" + }, + "publishConfig": { + "access": "public", + "directory": "../../../../dist/packages/php-wasm/web-builds/5-6" + }, + "type": "module", + "main": "./index.cjs", + "module": "./index.js", + "types": "index.d.ts", + "license": "GPL-2.0-or-later", + "engines": { + "node": ">=20.10.0", + "npm": ">=10.2.3" + } +} diff --git a/packages/php-wasm/web-builds/5-6/project.json b/packages/php-wasm/web-builds/5-6/project.json new file mode 100644 index 00000000000..7330bfd425b --- /dev/null +++ b/packages/php-wasm/web-builds/5-6/project.json @@ -0,0 +1,61 @@ +{ + "name": "php-wasm-web-5-6", + "$schema": "../../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "packages/php-wasm/web-builds/5-6/src", + "projectType": "library", + "implicitDependencies": ["php-wasm-compile"], + "targets": { + "build": { + "executor": "nx:noop", + "dependsOn": ["build:copy-assets"] + }, + "build:mkdir": { + "executor": "nx:run-commands", + "options": { + "commands": ["mkdir -p dist/packages/php-wasm/web-builds/5-6"], + "parallel": false + } + }, + "build:package-json": { + "executor": "@wp-playground/nx-extensions:package-json", + "options": { + "tsConfig": "packages/php-wasm/web-builds/5-6/tsconfig.lib.json", + "outputPath": "dist/packages/php-wasm/web-builds/5-6", + "buildTarget": "php-wasm-web-5-6:build:bundle:production" + }, + "dependsOn": ["build:mkdir"] + }, + "build:bundle": { + "executor": "nx:run-commands", + "options": { + "command": "node packages/php-wasm/web-builds/5-6/build.js", + "parallel": false + }, + "dependsOn": ["build:mkdir"] + }, + "build:copy-assets": { + "executor": "nx:run-commands", + "options": { + "commands": [ + "cp -rf packages/php-wasm/web-builds/5-6/jspi dist/packages/php-wasm/web-builds/5-6/", + "cp -rf packages/php-wasm/web-builds/5-6/asyncify dist/packages/php-wasm/web-builds/5-6/" + ], + "parallel": false + }, + "dependsOn": ["build:package-json"] + }, + "publish": { + "executor": "nx:run-commands", + "options": { + "command": "node tools/scripts/publish.mjs php-wasm-web-5-6 {args.ver} {args.tag}", + "parallel": false + }, + "dependsOn": ["build"] + }, + "package-for-self-hosting": { + "executor": "@wp-playground/nx-extensions:package-for-self-hosting", + "dependsOn": ["build"] + } + }, + "tags": ["scope:php-binaries"] +} diff --git a/packages/php-wasm/web-builds/5-6/src/index.ts b/packages/php-wasm/web-builds/5-6/src/index.ts new file mode 100644 index 00000000000..6786b7ff084 --- /dev/null +++ b/packages/php-wasm/web-builds/5-6/src/index.ts @@ -0,0 +1,14 @@ +import type { PHPLoaderModule } from '@php-wasm/universal'; +import { jspi } from 'wasm-feature-detect'; + +export async function getPHPLoaderModule(): Promise { + if (await jspi()) { + // @ts-ignore + return await import('../jspi/php_5_6.js'); + } else { + // @ts-ignore + return await import('../asyncify/php_5_6.js'); + } +} + +export { jspi }; diff --git a/packages/php-wasm/web-builds/5-6/tsconfig.json b/packages/php-wasm/web-builds/5-6/tsconfig.json new file mode 100644 index 00000000000..b943cbfe62a --- /dev/null +++ b/packages/php-wasm/web-builds/5-6/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "module": "ESNext", + "moduleResolution": "bundler", + "allowJs": true, + "checkJs": false + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + } + ] +} diff --git a/packages/php-wasm/web-builds/5-6/tsconfig.lib.json b/packages/php-wasm/web-builds/5-6/tsconfig.lib.json new file mode 100644 index 00000000000..67bfeb7b15f --- /dev/null +++ b/packages/php-wasm/web-builds/5-6/tsconfig.lib.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../../dist/packages/php-wasm/web-builds/5-6", + "declaration": true, + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "exclude": ["**/*.spec.ts", "**/*.test.ts"] +} diff --git a/packages/php-wasm/web/src/lib/get-php-loader-module.ts b/packages/php-wasm/web/src/lib/get-php-loader-module.ts index 6c32e81ec7c..af949488969 100644 --- a/packages/php-wasm/web/src/lib/get-php-loader-module.ts +++ b/packages/php-wasm/web/src/lib/get-php-loader-module.ts @@ -1,4 +1,8 @@ -import type { PHPLoaderModule, SupportedPHPVersion } from '@php-wasm/universal'; +import type { + LegacyPHPVersion, + PHPLoaderModule, + SupportedPHPVersion, +} from '@php-wasm/universal'; import { LatestSupportedPHPVersion } from '@php-wasm/universal'; /** @@ -14,7 +18,7 @@ import { LatestSupportedPHPVersion } from '@php-wasm/universal'; * @returns The PHP loader module. */ export async function getPHPLoaderModule( - version: SupportedPHPVersion = LatestSupportedPHPVersion + version: SupportedPHPVersion | LegacyPHPVersion = LatestSupportedPHPVersion ): Promise { switch (version) { case '8.5': @@ -38,6 +42,9 @@ export async function getPHPLoaderModule( case '7.4': // @ts-ignore return (await import('@php-wasm/web-7-4')).getPHPLoaderModule(); + case '5.6': + // @ts-ignore + return (await import('@php-wasm/web-5-6')).getPHPLoaderModule(); } throw new Error(`Unsupported PHP version ${version}`); } diff --git a/tsconfig.base.json b/tsconfig.base.json index d48f6d6c3e3..7905193b441 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -24,6 +24,9 @@ ], "@php-wasm/logger": ["packages/php-wasm/logger/src/index.ts"], "@php-wasm/node": ["packages/php-wasm/node/src/index.ts"], + "@php-wasm/node-5-6": [ + "packages/php-wasm/node-builds/5-6/src/index.ts" + ], "@php-wasm/node-7-2": [ "packages/php-wasm/node-builds/7-2/src/index.ts" ], @@ -66,6 +69,9 @@ ], "@php-wasm/util": ["packages/php-wasm/util/src/index.ts"], "@php-wasm/web": ["packages/php-wasm/web/src/index.ts"], + "@php-wasm/web-5-6": [ + "packages/php-wasm/web-builds/5-6/src/index.ts" + ], "@php-wasm/web-7-2": [ "packages/php-wasm/web-builds/7-2/src/index.ts" ],