Skip to content

Commit dc6470a

Browse files
committed
Initial (cleaned up) method for building the PHP WASM files
This is based on soyuka/php-wasm#7 Support for mbstring and the XML extensions will be in the next commit.
0 parents  commit dc6470a

File tree

5 files changed

+232
-0
lines changed

5 files changed

+232
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
build/*.wasm
2+
build/*.js

Dockerfile

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
FROM debian:bookworm as bookworm
2+
ARG PHP_VERSION=8.4.3
3+
WORKDIR /local/src
4+
5+
# Copy SHIM source to /local/src
6+
COPY phpw.c /local/src/phpw.c
7+
8+
# Apt-Install
9+
RUN apt-get update && \
10+
apt-get --no-install-recommends -y install \
11+
build-essential \
12+
automake \
13+
autoconf \
14+
libtool \
15+
pkg-config \
16+
bison \
17+
flex \
18+
make \
19+
re2c \
20+
git \
21+
pv \
22+
ca-certificates \
23+
python3
24+
25+
# Install emscripten sdk
26+
RUN \
27+
git clone https://github.com/emscripten-core/emsdk.git && \
28+
cd emsdk && \
29+
./emsdk install latest && \
30+
./emsdk activate latest
31+
32+
# Download PHP and Set-Up Configure
33+
RUN \
34+
git clone https://github.com/php/php-src.git php-src --branch PHP-$PHP_VERSION --single-branch --depth 1 && \
35+
cd php-src && \
36+
./buildconf --force
37+
38+
# Setting ENV vars
39+
ENV PATH=/local/src/emsdk:/local/src/emsdk/upstream/emscripten:/usr/local/bin:/usr/bin
40+
ENV EMSDK=/local/src/emsdk
41+
ENV EMSDK_NODE=/local/src/emsdk/node/20.18.0_64bit/bin/node
42+
43+
# Configure PHP
44+
RUN cd php-src && \
45+
emconfigure ./configure --enable-embed=static \
46+
--disable-all --without-pcre-jit --disable-fiber-asm --disable-cgi --disable-cli --disable-phpdbg \
47+
# --with-libxml --enable-simplexml --enable-xml --enable-xmlreader --enable-dom \
48+
# --enable-mbstring \
49+
--enable-calendar --enable-ctype
50+
51+
# Compile WASM shim
52+
RUN \
53+
emcc -O2 -I php-src/. -I php-src/Zend -I php-src/main -I php-src/TSRM -c phpw.c -o phpw.o
54+
55+
# Compile PHP
56+
RUN \
57+
cd php-src && \
58+
emmake make -j`nproc`
59+
60+
# Create PHP-WASM
61+
RUN mkdir /build && \
62+
emcc -o /build/php-$PHP_VERSION-web.mjs \
63+
-O2 --llvm-lto 2 \
64+
-s EXPORTED_FUNCTIONS='["_phpw", "_phpw_flush", "_phpw_exec", "_phpw_run", "_chdir", "_setenv", "_php_embed_init", "_php_embed_shutdown", "_zend_eval_string"]' \
65+
-s EXPORTED_RUNTIME_METHODS='["ccall", "UTF8ToString", "lengthBytesUTF8", "FS"]' \
66+
-s ENVIRONMENT=web \
67+
-s MAXIMUM_MEMORY=128mb -s INITIAL_MEMORY=128mb -s ALLOW_MEMORY_GROWTH=0 \
68+
-s ASSERTIONS=0 -s ERROR_ON_UNDEFINED_SYMBOLS=0 -s MODULARIZE=1 -s INVOKE_RUN=0 -s LZ4=1 -s EXPORT_ES6=1 \
69+
-s EXPORT_NAME=createPhpModule \
70+
phpw.o php-src/.libs/libphp.a \
71+
# ../install/lib/libxml2.a ../install/lib/libonig.a \
72+
php-src/.libs/libphp.a
73+
74+
# Save file
75+
FROM scratch
76+
COPY --from=bookworm /build/ .

README.rst

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
PHP WASM Builder
2+
================
3+
4+
The Dockerfile in this repository builds the PHP WASM files for use in the
5+
documentation, and the PHP Tour.
6+
7+
You can build them, by running the following command::
8+
9+
docker buildx bake
10+
11+
The builds will then up in the ``build/`` directory. These two files then need
12+
to be copied to https://github.com/php/web-php.git/js (as ``php-web.wasm`` and
13+
``php-web.mjs``)
14+
15+
By default, this will build PHP 8.4.3, but you can override this by setting an
16+
argument::
17+
18+
docker buildx bake --set default.args.PHP_VERSION=8.3.16
19+
20+
Supported Extensions
21+
--------------------
22+
23+
- Core
24+
- calendar
25+
- ctype
26+
- date
27+
- dom
28+
- hash
29+
- json
30+
- libxml
31+
- mbstring
32+
- pcre
33+
- random
34+
- Reflection
35+
- SimpleXML
36+
- SPL
37+
- standard
38+
- xml
39+
- xmlreader

docker-bake.hcl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
target "default" {
2+
output = ["type=local,dest=./build"]
3+
tags = ["php-wasm"]
4+
}

phpw.c

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/**
2+
* Copyright (c) 2025 The PHP Foundation
3+
* Copyright (c) 2023-2024 Antoine Bluchet
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a
6+
* copy of this software and associated documentation files (the "Software"),
7+
* to deal in the Software without restriction, including without limitation
8+
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
9+
* and/or sell copies of the Software, and to permit persons to whom the
10+
* Software is furnished to do so, subject to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be included in
13+
* all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21+
* DEALINGS IN THE SOFTWARE.
22+
*/
23+
#include "sapi/embed/php_embed.h"
24+
#include <emscripten.h>
25+
#include <stdlib.h>
26+
27+
#include "zend_globals_macros.h"
28+
#include "zend_exceptions.h"
29+
#include "zend_closures.h"
30+
31+
int main() {
32+
return 0;
33+
}
34+
35+
void phpw_flush()
36+
{
37+
fprintf(stdout, "\n");
38+
fprintf(stderr, "\n");
39+
}
40+
41+
char *EMSCRIPTEN_KEEPALIVE phpw_exec(char *code)
42+
{
43+
setenv("USE_ZEND_ALLOC", "0", 1);
44+
php_embed_init(0, NULL);
45+
char *retVal = NULL;
46+
47+
zend_try
48+
{
49+
zval ret_zv;
50+
51+
zend_eval_string(code, &ret_zv, "expression");
52+
convert_to_string(&ret_zv);
53+
54+
retVal = Z_STRVAL(ret_zv);
55+
} zend_catch {
56+
} zend_end_try();
57+
58+
phpw_flush();
59+
php_embed_shutdown();
60+
61+
return retVal;
62+
}
63+
64+
void EMSCRIPTEN_KEEPALIVE phpw_run(char *code)
65+
{
66+
setenv("USE_ZEND_ALLOC", "0", 1);
67+
php_embed_init(0, NULL);
68+
69+
zend_try
70+
{
71+
zend_eval_string(code, NULL, "script");
72+
if (EG(exception)) {
73+
zend_exception_error(EG(exception), E_ERROR);
74+
}
75+
} zend_catch {
76+
/* int exit_status = EG(exit_status); */
77+
} zend_end_try();
78+
79+
phpw_flush();
80+
php_embed_shutdown();
81+
}
82+
83+
int EMBED_SHUTDOWN = 1;
84+
85+
void phpw(char *file)
86+
{
87+
setenv("USE_ZEND_ALLOC", "0", 1);
88+
if (EMBED_SHUTDOWN == 0) {
89+
php_embed_shutdown();
90+
}
91+
92+
php_embed_init(0, NULL);
93+
EMBED_SHUTDOWN = 0;
94+
zend_first_try {
95+
zend_file_handle file_handle;
96+
zend_stream_init_filename(&file_handle, file);
97+
// file_handle.primary_script = 1;
98+
99+
if (!php_execute_script(&file_handle)) {
100+
php_printf("Failed to execute PHP script.\n");
101+
}
102+
103+
zend_destroy_file_handle(&file_handle);
104+
} zend_catch {
105+
/* int exit_status = EG(exit_status); */
106+
} zend_end_try();
107+
108+
phpw_flush();
109+
php_embed_shutdown();
110+
EMBED_SHUTDOWN = 1;
111+
}

0 commit comments

Comments
 (0)