aboutsummaryrefslogtreecommitdiffhomepage
path: root/worker/php
diff options
context:
space:
mode:
Diffstat (limited to 'worker/php')
-rw-r--r--worker/php/biome.json64
-rw-r--r--worker/php/exec.mjs30
-rw-r--r--worker/php/index.mjs44
-rw-r--r--worker/php/lib.mjs118
-rw-r--r--worker/php/lib.test.mjs276
-rw-r--r--worker/php/package.json34
-rw-r--r--worker/php/vitest.config.mjs2
7 files changed, 284 insertions, 284 deletions
diff --git a/worker/php/biome.json b/worker/php/biome.json
index 7f791c6..f0aaa73 100644
--- a/worker/php/biome.json
+++ b/worker/php/biome.json
@@ -1,34 +1,34 @@
{
- "$schema": "https://biomejs.dev/schemas/2.3.15/schema.json",
- "vcs": {
- "enabled": false,
- "clientKind": "git",
- "useIgnoreFile": false
- },
- "files": {
- "ignoreUnknown": false,
- "includes": ["**"]
- },
- "formatter": {
- "enabled": true,
- "indentStyle": "tab"
- },
- "assist": {
- "actions": {
- "source": {
- "organizeImports": "on"
- }
- }
- },
- "linter": {
- "enabled": true,
- "rules": {
- "recommended": true
- }
- },
- "javascript": {
- "formatter": {
- "quoteStyle": "double"
- }
- }
+ "$schema": "https://biomejs.dev/schemas/2.3.15/schema.json",
+ "vcs": {
+ "enabled": false,
+ "clientKind": "git",
+ "useIgnoreFile": false
+ },
+ "files": {
+ "ignoreUnknown": false,
+ "includes": ["**"]
+ },
+ "formatter": {
+ "enabled": true,
+ "indentStyle": "space"
+ },
+ "assist": {
+ "actions": {
+ "source": {
+ "organizeImports": "on"
+ }
+ }
+ },
+ "linter": {
+ "enabled": true,
+ "rules": {
+ "recommended": true
+ }
+ },
+ "javascript": {
+ "formatter": {
+ "quoteStyle": "double"
+ }
+ }
}
diff --git a/worker/php/exec.mjs b/worker/php/exec.mjs
index 7403dfc..f1cb361 100644
--- a/worker/php/exec.mjs
+++ b/worker/php/exec.mjs
@@ -2,22 +2,22 @@ import { buildResult, createIOCallbacks, preprocessCode } from "./lib.mjs";
import PHPWasm from "./php-wasm.js";
process.once("message", async ({ code: originalCode, input }) => {
- const code = preprocessCode(originalCode);
- const io = createIOCallbacks(input);
+ const code = preprocessCode(originalCode);
+ const io = createIOCallbacks(input);
- const { ccall } = await PHPWasm({
- stdin: io.stdin,
- stdout: io.stdout,
- stderr: io.stderr,
- });
+ const { ccall } = await PHPWasm({
+ stdin: io.stdin,
+ stdout: io.stdout,
+ stderr: io.stderr,
+ });
- let err;
- let result;
- try {
- result = ccall("php_wasm_run", "number", ["string"], [code]);
- } catch (e) {
- err = e;
- }
+ let err;
+ let result;
+ try {
+ result = ccall("php_wasm_run", "number", ["string"], [code]);
+ } catch (e) {
+ err = e;
+ }
- process.send(buildResult(err, result, io.getStdout, io.getStderr));
+ process.send(buildResult(err, result, io.getStdout, io.getStderr));
});
diff --git a/worker/php/index.mjs b/worker/php/index.mjs
index 9950ffa..c2bd818 100644
--- a/worker/php/index.mjs
+++ b/worker/php/index.mjs
@@ -3,37 +3,37 @@ import { serve } from "@hono/node-server";
import { Hono } from "hono";
const execPhp = (code, input, timeoutMsec) => {
- return new Promise((resolve, _reject) => {
- const proc = fork("./exec.mjs");
+ return new Promise((resolve, _reject) => {
+ const proc = fork("./exec.mjs");
- proc.send({ code, input });
+ proc.send({ code, input });
- proc.on("message", (result) => {
- resolve(result);
- proc.kill();
- });
+ proc.on("message", (result) => {
+ resolve(result);
+ proc.kill();
+ });
- setTimeout(() => {
- resolve({
- status: "timeout",
- stdout: "",
- stderr: `Time Limit Exceeded: ${timeoutMsec} msec`,
- });
- proc.kill();
- }, timeoutMsec);
- });
+ setTimeout(() => {
+ resolve({
+ status: "timeout",
+ stdout: "",
+ stderr: `Time Limit Exceeded: ${timeoutMsec} msec`,
+ });
+ proc.kill();
+ }, timeoutMsec);
+ });
};
const app = new Hono();
app.post("/exec", async (c) => {
- console.log("worker/exec");
- const { code, stdin, max_duration_ms } = await c.req.json();
- const result = await execPhp(code, stdin, max_duration_ms);
- return c.json(result);
+ console.log("worker/exec");
+ const { code, stdin, max_duration_ms } = await c.req.json();
+ const result = await execPhp(code, stdin, max_duration_ms);
+ return c.json(result);
});
serve({
- fetch: app.fetch,
- port: 80,
+ fetch: app.fetch,
+ port: 80,
});
diff --git a/worker/php/lib.mjs b/worker/php/lib.mjs
index 4a34733..d877856 100644
--- a/worker/php/lib.mjs
+++ b/worker/php/lib.mjs
@@ -10,70 +10,70 @@ const PRELUDE = `
const BUFFER_MAX = 10 * 1024;
export function preprocessCode(originalCode) {
- if (originalCode.startsWith("<?php")) {
- return PRELUDE + originalCode.slice(5);
- }
- if (originalCode.startsWith("<?")) {
- return PRELUDE + originalCode.slice(2);
- }
- return PRELUDE + originalCode;
+ if (originalCode.startsWith("<?php")) {
+ return PRELUDE + originalCode.slice(5);
+ }
+ if (originalCode.startsWith("<?")) {
+ return PRELUDE + originalCode.slice(2);
+ }
+ return PRELUDE + originalCode;
}
export function createIOCallbacks(input) {
- let stdinPos = 0;
- const stdinBuf = Buffer.from(input);
- let stdoutPos = 0;
- const stdoutBuf = Buffer.alloc(BUFFER_MAX);
- let stderrPos = 0;
- const stderrBuf = Buffer.alloc(BUFFER_MAX);
+ let stdinPos = 0;
+ const stdinBuf = Buffer.from(input);
+ let stdoutPos = 0;
+ const stdoutBuf = Buffer.alloc(BUFFER_MAX);
+ let stderrPos = 0;
+ const stderrBuf = Buffer.alloc(BUFFER_MAX);
- return {
- stdin: () => {
- if (stdinBuf.length <= stdinPos) {
- return null;
- }
- return stdinBuf.readUInt8(stdinPos++);
- },
- stdout: (asciiCode) => {
- if (asciiCode === null) {
- return;
- }
- if (BUFFER_MAX <= stdoutPos) {
- return;
- }
- stdoutBuf.writeUInt8(
- asciiCode < 0 ? asciiCode + 256 : asciiCode,
- stdoutPos++,
- );
- },
- stderr: (asciiCode) => {
- if (asciiCode === null) {
- return;
- }
- if (BUFFER_MAX <= stderrPos) {
- return;
- }
- stderrBuf.writeUInt8(
- asciiCode < 0 ? asciiCode + 256 : asciiCode,
- stderrPos++,
- );
- },
- getStdout: () => stdoutBuf.subarray(0, stdoutPos).toString(),
- getStderr: () => stderrBuf.subarray(0, stderrPos).toString(),
- };
+ return {
+ stdin: () => {
+ if (stdinBuf.length <= stdinPos) {
+ return null;
+ }
+ return stdinBuf.readUInt8(stdinPos++);
+ },
+ stdout: (asciiCode) => {
+ if (asciiCode === null) {
+ return;
+ }
+ if (BUFFER_MAX <= stdoutPos) {
+ return;
+ }
+ stdoutBuf.writeUInt8(
+ asciiCode < 0 ? asciiCode + 256 : asciiCode,
+ stdoutPos++,
+ );
+ },
+ stderr: (asciiCode) => {
+ if (asciiCode === null) {
+ return;
+ }
+ if (BUFFER_MAX <= stderrPos) {
+ return;
+ }
+ stderrBuf.writeUInt8(
+ asciiCode < 0 ? asciiCode + 256 : asciiCode,
+ stderrPos++,
+ );
+ },
+ getStdout: () => stdoutBuf.subarray(0, stdoutPos).toString(),
+ getStderr: () => stderrBuf.subarray(0, stderrPos).toString(),
+ };
}
export function buildResult(err, ccallResult, getStdout, getStderr) {
- if (err) {
- return {
- status: "runtime_error",
- stdout: getStdout(),
- stderr: `${getStderr()}\n${err.toString()}`,
- };
- }
- return {
- status: ccallResult === 0 ? "success" : "runtime_error",
- stdout: getStdout(),
- stderr: getStderr(),
- };
+ if (err) {
+ return {
+ status: "runtime_error",
+ stdout: getStdout(),
+ stderr: `${getStderr()}\n${err.toString()}`,
+ };
+ }
+ return {
+ status: ccallResult === 0 ? "success" : "runtime_error",
+ stdout: getStdout(),
+ stderr: getStderr(),
+ };
}
diff --git a/worker/php/lib.test.mjs b/worker/php/lib.test.mjs
index d4f420f..ef01852 100644
--- a/worker/php/lib.test.mjs
+++ b/worker/php/lib.test.mjs
@@ -2,164 +2,164 @@ import { describe, expect, it } from "vitest";
import { buildResult, createIOCallbacks, preprocessCode } from "./lib.mjs";
describe("preprocessCode", () => {
- it("removes <?php tag and prepends PRELUDE", () => {
- const result = preprocessCode('<?php echo "hello";');
- expect(result).toContain('echo "hello";');
- expect(result).toContain("error_reporting");
- expect(result).not.toContain("<?php");
- });
+ it("removes <?php tag and prepends PRELUDE", () => {
+ const result = preprocessCode('<?php echo "hello";');
+ expect(result).toContain('echo "hello";');
+ expect(result).toContain("error_reporting");
+ expect(result).not.toContain("<?php");
+ });
- it("removes <? short tag and prepends PRELUDE", () => {
- const result = preprocessCode('<? echo "hello";');
- expect(result).toContain('echo "hello";');
- expect(result).toContain("error_reporting");
- expect(result).not.toContain("<?");
- });
+ it("removes <? short tag and prepends PRELUDE", () => {
+ const result = preprocessCode('<? echo "hello";');
+ expect(result).toContain('echo "hello";');
+ expect(result).toContain("error_reporting");
+ expect(result).not.toContain("<?");
+ });
- it("prepends PRELUDE when no php tag present", () => {
- const result = preprocessCode('echo "hello";');
- expect(result).toContain('echo "hello";');
- expect(result).toContain("error_reporting");
- });
+ it("prepends PRELUDE when no php tag present", () => {
+ const result = preprocessCode('echo "hello";');
+ expect(result).toContain('echo "hello";');
+ expect(result).toContain("error_reporting");
+ });
- it("handles empty string", () => {
- const result = preprocessCode("");
- expect(result).toContain("error_reporting");
- });
+ it("handles empty string", () => {
+ const result = preprocessCode("");
+ expect(result).toContain("error_reporting");
+ });
- it("does not remove <?php when not at the start", () => {
- const result = preprocessCode('echo "x"; <?php echo "y";');
- expect(result).toContain("<?php");
- });
+ it("does not remove <?php when not at the start", () => {
+ const result = preprocessCode('echo "x"; <?php echo "y";');
+ expect(result).toContain("<?php");
+ });
});
describe("createIOCallbacks", () => {
- describe("stdin", () => {
- it("reads input byte by byte", () => {
- const io = createIOCallbacks("AB");
- expect(io.stdin()).toBe(65); // 'A'
- expect(io.stdin()).toBe(66); // 'B'
- });
+ describe("stdin", () => {
+ it("reads input byte by byte", () => {
+ const io = createIOCallbacks("AB");
+ expect(io.stdin()).toBe(65); // 'A'
+ expect(io.stdin()).toBe(66); // 'B'
+ });
- it("returns null at EOF", () => {
- const io = createIOCallbacks("A");
- io.stdin(); // consume 'A'
- expect(io.stdin()).toBeNull();
- expect(io.stdin()).toBeNull();
- });
+ it("returns null at EOF", () => {
+ const io = createIOCallbacks("A");
+ io.stdin(); // consume 'A'
+ expect(io.stdin()).toBeNull();
+ expect(io.stdin()).toBeNull();
+ });
- it("returns null immediately for empty input", () => {
- const io = createIOCallbacks("");
- expect(io.stdin()).toBeNull();
- });
- });
+ it("returns null immediately for empty input", () => {
+ const io = createIOCallbacks("");
+ expect(io.stdin()).toBeNull();
+ });
+ });
- describe("stdout", () => {
- it("captures ASCII writes", () => {
- const io = createIOCallbacks("");
- io.stdout(72); // 'H'
- io.stdout(105); // 'i'
- expect(io.getStdout()).toBe("Hi");
- });
+ describe("stdout", () => {
+ it("captures ASCII writes", () => {
+ const io = createIOCallbacks("");
+ io.stdout(72); // 'H'
+ io.stdout(105); // 'i'
+ expect(io.getStdout()).toBe("Hi");
+ });
- it("ignores null (flush)", () => {
- const io = createIOCallbacks("");
- io.stdout(65);
- io.stdout(null);
- io.stdout(66);
- expect(io.getStdout()).toBe("AB");
- });
+ it("ignores null (flush)", () => {
+ const io = createIOCallbacks("");
+ io.stdout(65);
+ io.stdout(null);
+ io.stdout(66);
+ expect(io.getStdout()).toBe("AB");
+ });
- it("corrects negative asciiCode by adding 256", () => {
- const io = createIOCallbacks("");
- // -191 + 256 = 65 = 'A'
- io.stdout(-191);
- expect(io.getStdout()).toBe("A");
- });
+ it("corrects negative asciiCode by adding 256", () => {
+ const io = createIOCallbacks("");
+ // -191 + 256 = 65 = 'A'
+ io.stdout(-191);
+ expect(io.getStdout()).toBe("A");
+ });
- it("truncates output at 10KB buffer limit", () => {
- const io = createIOCallbacks("");
- const limit = 10 * 1024;
- for (let i = 0; i < limit + 100; i++) {
- io.stdout(65);
- }
- expect(io.getStdout().length).toBe(limit);
- });
- });
+ it("truncates output at 10KB buffer limit", () => {
+ const io = createIOCallbacks("");
+ const limit = 10 * 1024;
+ for (let i = 0; i < limit + 100; i++) {
+ io.stdout(65);
+ }
+ expect(io.getStdout().length).toBe(limit);
+ });
+ });
- describe("stderr", () => {
- it("captures ASCII writes", () => {
- const io = createIOCallbacks("");
- io.stderr(69); // 'E'
- io.stderr(114); // 'r'
- expect(io.getStderr()).toBe("Er");
- });
+ describe("stderr", () => {
+ it("captures ASCII writes", () => {
+ const io = createIOCallbacks("");
+ io.stderr(69); // 'E'
+ io.stderr(114); // 'r'
+ expect(io.getStderr()).toBe("Er");
+ });
- it("ignores null (flush)", () => {
- const io = createIOCallbacks("");
- io.stderr(65);
- io.stderr(null);
- expect(io.getStderr()).toBe("A");
- });
+ it("ignores null (flush)", () => {
+ const io = createIOCallbacks("");
+ io.stderr(65);
+ io.stderr(null);
+ expect(io.getStderr()).toBe("A");
+ });
- it("corrects negative asciiCode by adding 256", () => {
- const io = createIOCallbacks("");
- // -156 + 256 = 100 = 'd'
- io.stderr(-156);
- expect(io.getStderr()).toBe("d");
- });
+ it("corrects negative asciiCode by adding 256", () => {
+ const io = createIOCallbacks("");
+ // -156 + 256 = 100 = 'd'
+ io.stderr(-156);
+ expect(io.getStderr()).toBe("d");
+ });
- it("truncates output at 10KB buffer limit", () => {
- const io = createIOCallbacks("");
- const limit = 10 * 1024;
- for (let i = 0; i < limit + 100; i++) {
- io.stderr(65);
- }
- expect(io.getStderr().length).toBe(limit);
- });
- });
+ it("truncates output at 10KB buffer limit", () => {
+ const io = createIOCallbacks("");
+ const limit = 10 * 1024;
+ for (let i = 0; i < limit + 100; i++) {
+ io.stderr(65);
+ }
+ expect(io.getStderr().length).toBe(limit);
+ });
+ });
});
describe("buildResult", () => {
- it("returns success when err is null and result is 0", () => {
- const result = buildResult(
- null,
- 0,
- () => "out",
- () => "",
- );
- expect(result).toEqual({
- status: "success",
- stdout: "out",
- stderr: "",
- });
- });
+ it("returns success when err is null and result is 0", () => {
+ const result = buildResult(
+ null,
+ 0,
+ () => "out",
+ () => "",
+ );
+ expect(result).toEqual({
+ status: "success",
+ stdout: "out",
+ stderr: "",
+ });
+ });
- it("returns runtime_error when result is non-zero", () => {
- const result = buildResult(
- null,
- 1,
- () => "out",
- () => "err",
- );
- expect(result).toEqual({
- status: "runtime_error",
- stdout: "out",
- stderr: "err",
- });
- });
+ it("returns runtime_error when result is non-zero", () => {
+ const result = buildResult(
+ null,
+ 1,
+ () => "out",
+ () => "err",
+ );
+ expect(result).toEqual({
+ status: "runtime_error",
+ stdout: "out",
+ stderr: "err",
+ });
+ });
- it("returns runtime_error with concatenated stderr when err is thrown", () => {
- const err = new Error("fatal");
- const result = buildResult(
- err,
- undefined,
- () => "out",
- () => "err",
- );
- expect(result.status).toBe("runtime_error");
- expect(result.stdout).toBe("out");
- expect(result.stderr).toContain("err");
- expect(result.stderr).toContain("Error: fatal");
- });
+ it("returns runtime_error with concatenated stderr when err is thrown", () => {
+ const err = new Error("fatal");
+ const result = buildResult(
+ err,
+ undefined,
+ () => "out",
+ () => "err",
+ );
+ expect(result.status).toBe("runtime_error");
+ expect(result.stdout).toBe("out");
+ expect(result.stderr).toContain("err");
+ expect(result.stderr).toContain("Error: fatal");
+ });
});
diff --git a/worker/php/package.json b/worker/php/package.json
index 12127bd..2430199 100644
--- a/worker/php/package.json
+++ b/worker/php/package.json
@@ -1,19 +1,19 @@
{
- "name": "albatross-2026-worker-php",
- "private": true,
- "type": "module",
- "main": "index.mjs",
- "scripts": {
- "check": "npm run check:biome",
- "check:biome": "biome check --write",
- "test": "vitest run"
- },
- "dependencies": {
- "@hono/node-server": "^1.19.9",
- "hono": "^4.11.9"
- },
- "devDependencies": {
- "@biomejs/biome": "^2.3.15",
- "vitest": "^3.2.1"
- }
+ "name": "albatross-2026-worker-php",
+ "private": true,
+ "type": "module",
+ "main": "index.mjs",
+ "scripts": {
+ "check": "npm run check:biome",
+ "check:biome": "biome check --write",
+ "test": "vitest run"
+ },
+ "dependencies": {
+ "@hono/node-server": "^1.19.9",
+ "hono": "^4.11.9"
+ },
+ "devDependencies": {
+ "@biomejs/biome": "^2.3.15",
+ "vitest": "^3.2.1"
+ }
}
diff --git a/worker/php/vitest.config.mjs b/worker/php/vitest.config.mjs
index def6022..77a73cf 100644
--- a/worker/php/vitest.config.mjs
+++ b/worker/php/vitest.config.mjs
@@ -1,5 +1,5 @@
import { defineConfig } from "vitest/config";
export default defineConfig({
- test: {},
+ test: {},
});