Skip to content

Repository files navigation

phasm

PHP 8.5 compiled to WebAssembly. Run PHP in the browser or in Node.js.

npm install @alganet/phasm

Included Extensions

calendar, ctype, fileinfo, filter, iconv, mbstring, opcache, pcntl, pdo, pdo_sqlite, sqlite3, tokenizer, zip.

Plus PHP's always-on core: Core, date, hash, json, lexbor, pcre, random, Reflection, SPL, standard, uri.

get_loaded_extensions() is the authority; npm test asserts this list matches what the binary actually links, so it cannot drift again.

Node.js

import Phasm from "@alganet/phasm";

const php = await Phasm({
  noInitialRun: true,
  print: (text) => process.stdout.write(text + "\n"),
  printErr: (text) => process.stderr.write(text + "\n"),
});

php.FS.writeFile("/hello.php", `<?php echo "Hello from PHP!\\n"; ?>`);
php.callMain(["hello.php"]);

Browser

<script src="https://unpkg.com/@alganet/phasm/dist/php.js"></script>
<pre id="output"></pre>
<script>
  Phasm({
    noInitialRun: true,
    print: (text) => document.getElementById("output").textContent += text + "\n",
    printErr: (text) => console.error(text),
  }).then((php) => {
    php.FS.writeFile("/hello.php", '<?php echo "Hello from PHP!\\n"; ?>');
    php.callMain(["hello.php"]);
  });
</script>

TypeScript

Types ship with the package — Phasm, PhasmOptions, PhasmModule and PhasmFS are all declared, no @types package needed.

import Phasm, { type PhasmModule } from "@alganet/phasm";

const php: PhasmModule = await Phasm({ noInitialRun: true });

Configuration

Phasm() is a factory function that accepts standard Emscripten Module options and returns a promise that resolves to the initialized module:

Option Description
noInitialRun Set true to prevent automatic execution on load.
arguments Array of CLI arguments (e.g. ["script.php"]).
print(text) Callback for stdout output.
printErr(text) Callback for stderr output.
stdin() Callback to provide stdin input. Return null for EOF.

The resolved module exposes callMain() to run PHP scripts and FS for filesystem access.

One run per module. The CLI SAPI's main() does full init and shutdown, so state leaks across repeated callMain() calls on a single instance and it will eventually crash. Create a fresh module per run.

Virtual Filesystem

Phasm uses Emscripten's virtual filesystem. Write PHP files before calling callMain():

php.FS.writeFile("/app.php", '<?php echo "works"; ?>');
php.FS.writeFile("/data.json", JSON.stringify({ key: "value" }));
php.callMain(["app.php"]);

See the Emscripten File System API for the full reference.

Live Demo

A live demo is available at alganet.github.io/phasm.

Contributing

See CONTRIBUTING.md for build instructions and development guidelines.

License

ISC

About

Minimalistic PHP WebAssembly builds

Resources

Contributing

Stars

4 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages