Porting PHP to WebAssembly using WASI
We are really glad to announce that we have a first build of PHP for
wasm32-wasi target! It will work with any runtime supporting the
WebAssembly System Interface (WASI), which is
most of them. ✨
This first cut is definitely a bit rough and missing some functionality, but is enough to run WordPress on the server side using mod_wasm. We did so in the Open Source spirit of release early, release often and Reid Hoffman's philosophy of "If you're not embarrassed by the first version of your product, you've launched too late".
The rest of this article explores why we are doing this and how you can get it working in your environment.
WebAssembly (and WASI in particular) is gaining traction in scripting environments. We have two recent examples of popular language interpreters being ported to Wasm, CPython and Ruby. This is excellent news for all of us excited about WebAssembly! 🎉
PHP is another popular server side
language. We thought that it would be very interesting to have PHP
compiled to the
wasm32-wasi target, so that we allow the vast number
of projects written in this programming language to run on
WebAssembly. In other words, in order to run PHP in a Wasm runtime, we
will compile the mainstream PHP interpreter, which is written in C, to
WebAssembly and use it in turn to run the code for the PHP
A tale of two builds
As mentioned earlier, WasmLabs has done past work to run WordPress in
the browser. As part of this
work, we built the PHP interpreter to WebAssembly using the almighty
emscripten toolchain. You can find all the details in the blog post.
emscripten is very powerful and tackles a lot of complexity for
developers. For example, there are a number of syscalls implemented in
a different kind of build is necessary. Enter
wasi-sdk is a WASI-enabled
C/C++ toolchain. The code is compiled and linked by Clang from the
LLVM project, while the language runtime comes from the
project. This allows us to do builds for the
wasi-sdk's primary goal is to build C/C++ programs targeting the
server side, this is, run in a WebAssembly runtime such as
WasmEdge... instead of a browser — usually
Now that we have the toolchain that we'll use for the job, we need to decide what version of PHP we want to aim for.
We initially chose PHP 7.3.33, because we wanted the sqlite amalgamation to still be present in the PHP tree, which was removed in PHP 7.4.
This is the reason why the patch that we are publishing today is produced against PHP 7.3.33. We are currently working on patches for the latest release of PHP 7 as well as PHP 8.
Run PHP (wasm32-wasi) in Apache with mod_wasm
We have recently released the
mod_wasm Apache httpd
mod_wasm, you can run
WebAssembly modules within the Apache httpd server.
With the work presented here we can leverage
mod_wasm to run
php-cgi as a WebAssembly module within Apache's httpd.
The patch we are releasing today is just an early version — it truly requires a significant amount of yak-shaving -. Our intent is to share it with the broader PHP and WebAssembly communities so that we can get feedback and evolve it to contribute upstream.
wasi-sdk making the porting process relatively easy given
the early days of the overall ecosystem, there are issues that we had
to tackle. We describe some of those below.
These functions are commonly used for non-local jumps in programs
(control flow that deviates from the usual subroutine call and return
sequence). What this means in practice is that we have a
feature with the possibility to save the current stack, and come back
to this state somewhat later.
As an example, this is used to implement asynchronous features in synchronous programs, or alternative control flows, such as exception handling, fibers...
Due to WebAssembly's synchronous nature, it is not trivial to
implement such a feature.
emscripten has support for this feature
baked in. However, for a solution based in
wasi-sdk, a new approach
is required, such as the Asyncify
Luckily, the binaryen
project in their
tool has functionality to asyncify a WebAssembly
so that we could implement the missing bits in the PHP interpreter to
take advantage of it.
We have not implemented this yet, so that we have stripped away the calls to setjmp/longjmp for now.
WebAssembly does not have the concept of operating system
processes. Many of the syscalls that have to do with processes had to
either be hardcoded (such as
getpid), or be converted to
Given the nature of WASI's capability-oriented filesystem, there are subtle differences when it comes to accessing files. Particularly, because it's not WASI's aim to fulfill the everything-is-a-file Unix philosophy.
There is work in progress as well in this front.
Most of the filesystem syscalls that are not commonly used have been converted to no-operations for now.
WASI does not have full support for sockets yet. It allows us to accept incoming connections, receive and send messages, but at the moment it's not possible to open a socket; it has to be provided by the host. There is work in progress to improve their support, but it's still early to work on this for the PHP port.
As a result, we have stripped all networking capabilities from PHP for now.
Although we have not included it in our preliminary work, we believe
that WASIX by SingleStore
Labs might be worth adding as an extra dependency when building
projects in which
wasi-libc is not providing enough functionality.
We are still exploring this possibility, When it comes to contributing
to upstream projects there are trade-offs to measure such as including
similar changes for
wasm32-wasi support in multiple projects versus
adding an extra dependency such as WASIX.
In short, we are open to feedback from both communities!
Running a PHP script
We want to make it easier for users to test our work. We have created a container image that you can use to run a simple PHP script, or even your own custom PHP programs!
docker run -p8080:8080 projects.registry.vmware.com/wasmlabs/containers/php-mod-wasm:[email protected]:716518f5a264b63b3f00ce717b83af9a2c407df49b482dc36ce0d2882c731449
And now, we can perform a request to it:
❯ curl -vvv http://localhost:8080/
* Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.83.1
> Accept: */*
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Fri, 21 Oct 2022 06:13:03 GMT
< Server: Apache/2.4.54 (Unix)
< X-Powered-By: PHP/7.3.33
< Content-Length: 13
< Content-Type: text/html; charset=UTF-8
* Connection #0 to host localhost left intact
Running your own PHP programs in Apache
In order to run your own PHP application you only have to mount the PHP project directory in the expected location:
docker run -p8080:8080 -v /path/to/php/project:/usr/local/apache2/htdocs projects.registry.vmware.com/wasmlabs/containers/php-mod-wasm:[email protected]:716518f5a264b63b3f00ce717b83af9a2c407df49b482dc36ce0d2882c731449
Now you can visit your PHP project at
As an example, you can find how to run WordPress on Wasm with Apache
Feel free to experiment with your own applications, we are eager to learn about your findings. Your feedback will help us prioritize the remaining work.
This work is not finished yet, in fact we are just getting started! We would love your feedback and contributions to continue to improve language support for WebAssembly and move forward the current state of the art of WebAssembly tooling.