@php-wasm/universal 3.0.18 → 3.0.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -1,8 +1,8 @@
1
- var z = (t) => {
1
+ var B = (t) => {
2
2
  throw TypeError(t);
3
3
  };
4
- var O = (t, e, r) => e.has(t) || z("Cannot " + r);
5
- var u = (t, e, r) => (O(t, e, "read from private field"), r ? r.call(t) : e.get(t)), m = (t, e, r) => e.has(t) ? z("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(t) : e.set(t, r), w = (t, e, r, s) => (O(t, e, "write to private field"), s ? s.call(t, r) : e.set(t, r), r), y = (t, e, r) => (O(t, e, "access private method"), r);
4
+ var O = (t, e, r) => e.has(t) || B("Cannot " + r);
5
+ var u = (t, e, r) => (O(t, e, "read from private field"), r ? r.call(t) : e.get(t)), y = (t, e, r) => e.has(t) ? B("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(t) : e.set(t, r), w = (t, e, r, s) => (O(t, e, "write to private field"), s ? s.call(t, r) : e.set(t, r), r), f = (t, e, r) => (O(t, e, "access private method"), r);
6
6
  import "@php-wasm/node-polyfills";
7
7
  import { logger } from "@php-wasm/logger";
8
8
  import { dirname, joinPaths, Semaphore, createSpawnHandler, basename, normalizePath, AcquireTimeoutError } from "@php-wasm/util";
@@ -363,12 +363,12 @@ FSHelpers.copyRecursive = rethrowFileSystemError(
363
363
  'Could not copy files from "{path}"'
364
364
  )(FSHelpers.copyRecursive);
365
365
  const _private = /* @__PURE__ */ new WeakMap();
366
- var P;
366
+ var S;
367
367
  class PHPWorker {
368
368
  /** @inheritDoc */
369
369
  constructor(e, r) {
370
- m(this, P);
371
- this.absoluteUrl = "", this.documentRoot = "", this.chroot = null, w(this, P, /* @__PURE__ */ new Map()), this.onMessageListeners = [], _private.set(this, {
370
+ y(this, S);
371
+ this.absoluteUrl = "", this.documentRoot = "", this.chroot = null, w(this, S, /* @__PURE__ */ new Map()), this.onMessageListeners = [], _private.set(this, {
372
372
  monitor: r
373
373
  }), e && this.__internal_setRequestHandler(e);
374
374
  }
@@ -524,7 +524,7 @@ class PHPWorker {
524
524
  }
525
525
  /** @inheritDoc @php-wasm/universal!/PHP.addEventListener */
526
526
  addEventListener(e, r) {
527
- u(this, P).has(e) || u(this, P).set(e, /* @__PURE__ */ new Set()), u(this, P).get(e).add(r);
527
+ u(this, S).has(e) || u(this, S).set(e, /* @__PURE__ */ new Set()), u(this, S).get(e).add(r);
528
528
  }
529
529
  /**
530
530
  * Removes an event listener for a PHP event.
@@ -533,10 +533,10 @@ class PHPWorker {
533
533
  */
534
534
  removeEventListener(e, r) {
535
535
  var s;
536
- (s = u(this, P).get(e)) == null || s.delete(r);
536
+ (s = u(this, S).get(e)) == null || s.delete(r);
537
537
  }
538
538
  dispatchEvent(e) {
539
- const r = u(this, P).get(e.type);
539
+ const r = u(this, S).get(e.type);
540
540
  if (r)
541
541
  for (const s of r)
542
542
  s(e);
@@ -558,7 +558,7 @@ class PHPWorker {
558
558
  await ((e = _private.get(this).requestHandler) == null ? void 0 : e[Symbol.asyncDispose]());
559
559
  }
560
560
  }
561
- P = new WeakMap();
561
+ S = new WeakMap();
562
562
  function isExitCode(t) {
563
563
  return t instanceof Error ? (t == null ? void 0 : t.name) === "ExitStatus" && "status" in t : !1;
564
564
  }
@@ -950,7 +950,7 @@ class PHPExecutionFailureError extends Error {
950
950
  }
951
951
  }
952
952
  const PHP_INI_PATH = "/internal/shared/php.ini", AUTO_PREPEND_SCRIPT = "/internal/shared/auto_prepend_file.php", OPCACHE_FILE_FOLDER = "/internal/shared/opcache";
953
- var C, H, T, E, F, M, _, h, B, $, V, G, J, Y, K, X, U, Q, q, D;
953
+ var M, H, T, v, F, k, _, h, z, $, V, G, J, Y, Q, K, U, X, j, D;
954
954
  class PHP {
955
955
  /**
956
956
  * Initializes a PHP runtime.
@@ -960,17 +960,17 @@ class PHP {
960
960
  * @param requestHandlerOptions - Optional. Options for the PHPRequestHandler. If undefined, no request handler will be initialized.
961
961
  */
962
962
  constructor(t) {
963
- m(this, h);
964
- m(this, C);
965
- m(this, H, !1);
966
- m(this, T, null);
967
- m(this, E, /* @__PURE__ */ new Map([
963
+ y(this, h);
964
+ y(this, M);
965
+ y(this, H, !1);
966
+ y(this, T, null);
967
+ y(this, v, /* @__PURE__ */ new Map([
968
968
  // Listen to all events
969
969
  ["*", /* @__PURE__ */ new Set()]
970
970
  ]));
971
- m(this, F, []);
972
- m(this, M, {});
973
- m(this, _, {
971
+ y(this, F, []);
972
+ y(this, k, {});
973
+ y(this, _, {
974
974
  enabled: !1,
975
975
  recreateRuntime: () => 0,
976
976
  needsRotating: !1,
@@ -987,7 +987,7 @@ class PHP {
987
987
  * @param listener - The listener function to be called when the event is triggered.
988
988
  */
989
989
  addEventListener(t, e) {
990
- u(this, E).has(t) || u(this, E).set(t, /* @__PURE__ */ new Set()), u(this, E).get(t).add(e);
990
+ u(this, v).has(t) || u(this, v).set(t, /* @__PURE__ */ new Set()), u(this, v).get(t).add(e);
991
991
  }
992
992
  /**
993
993
  * Removes an event listener for a PHP event.
@@ -996,12 +996,12 @@ class PHP {
996
996
  */
997
997
  removeEventListener(t, e) {
998
998
  var r;
999
- (r = u(this, E).get(t)) == null || r.delete(e);
999
+ (r = u(this, v).get(t)) == null || r.delete(e);
1000
1000
  }
1001
1001
  dispatchEvent(t) {
1002
1002
  const e = [
1003
- ...u(this, E).get(t.type) || [],
1004
- ...u(this, E).get("*") || []
1003
+ ...u(this, v).get(t.type) || [],
1004
+ ...u(this, v).get("*") || []
1005
1005
  ];
1006
1006
  if (e)
1007
1007
  for (const r of e)
@@ -1163,7 +1163,7 @@ class PHP {
1163
1163
  throw new Error(
1164
1164
  "Could not set SAPI name. This can only be done before the PHP WASM module is initialized.Did you already dispatch any requests?"
1165
1165
  );
1166
- w(this, C, t);
1166
+ w(this, M, t);
1167
1167
  }
1168
1168
  /**
1169
1169
  * Changes the current working directory in the PHP filesystem.
@@ -1387,7 +1387,7 @@ class PHP {
1387
1387
  async runStream(t) {
1388
1388
  const e = await this.semaphore.acquire();
1389
1389
  let r;
1390
- const s = y(this, h, D).call(this, async () => {
1390
+ const s = f(this, h, D).call(this, async () => {
1391
1391
  if (u(this, H) || (await this[__private__dont__use].ccall(
1392
1392
  "php_wasm_init",
1393
1393
  null,
@@ -1400,22 +1400,22 @@ class PHP {
1400
1400
  throw new Error(
1401
1401
  `The script path "${t.scriptPath}" does not exist.`
1402
1402
  );
1403
- y(this, h, $).call(this, t.relativeUri || ""), y(this, h, Y).call(this, t.method || "GET");
1404
- const i = normalizeHeaders(t.headers || {}), o = i.host || "example.com:443", a = y(this, h, J).call(this, o, t.protocol || "http");
1405
- if (y(this, h, V).call(this, o), y(this, h, G).call(this, a), y(this, h, K).call(this, i), t.body && (r = y(this, h, X).call(this, t.body)), typeof t.code == "string")
1406
- this.writeFile("/internal/eval.php", t.code), y(this, h, U).call(this, "/internal/eval.php");
1403
+ f(this, h, $).call(this, t.relativeUri || ""), f(this, h, Y).call(this, t.method || "GET");
1404
+ const i = normalizeHeaders(t.headers || {}), o = i.host || "example.com:443", a = f(this, h, J).call(this, o, t.protocol || "http");
1405
+ if (f(this, h, V).call(this, o), f(this, h, G).call(this, a), f(this, h, Q).call(this, i), t.body && (r = f(this, h, K).call(this, t.body)), typeof t.code == "string")
1406
+ this.writeFile("/internal/eval.php", t.code), f(this, h, U).call(this, "/internal/eval.php");
1407
1407
  else if (typeof t.scriptPath == "string")
1408
- y(this, h, U).call(this, t.scriptPath || "");
1408
+ f(this, h, U).call(this, t.scriptPath || "");
1409
1409
  else
1410
1410
  throw new TypeError(
1411
1411
  "The request object must have either a `code` or a `scriptPath` property."
1412
1412
  );
1413
- const c = y(this, h, B).call(this, t.$_SERVER, i, a);
1413
+ const c = f(this, h, z).call(this, t.$_SERVER, i, a);
1414
1414
  for (const d in c)
1415
- y(this, h, Q).call(this, d, c[d]);
1415
+ f(this, h, X).call(this, d, c[d]);
1416
1416
  const l = t.env || {};
1417
1417
  for (const d in l)
1418
- y(this, h, q).call(this, d, l[d]);
1418
+ f(this, h, j).call(this, d, l[d]);
1419
1419
  return await this[__private__dont__use].ccall(
1420
1420
  "wasm_sapi_handle_request",
1421
1421
  NUMBER,
@@ -1661,28 +1661,35 @@ class PHP {
1661
1661
  * @param runtime
1662
1662
  */
1663
1663
  async hotSwapPHPRuntime(t) {
1664
- const e = this[__private__dont__use].FS, r = this.listFiles("/").map((a) => `/${a}`), s = this[__private__dont__use].spawnProcess, n = e.cwd();
1664
+ const e = this[__private__dont__use].FS, r = this.listFiles("/").map((c) => `/${c}`), s = this[__private__dont__use].spawnProcess, n = e.cwd();
1665
1665
  e.chdir("/");
1666
- const i = [];
1667
- for (const [a, c] of Object.entries(u(this, M)))
1668
- i.push({ mountHandler: c.mountHandler, vfsPath: a }), await c.unmount();
1666
+ const i = Object.entries(u(this, k)).map(
1667
+ ([c, l]) => ({
1668
+ mountHandler: l.mountHandler,
1669
+ vfsPath: c
1670
+ })
1671
+ ), o = Object.values(
1672
+ u(this, k)
1673
+ ).reverse();
1674
+ for (const c of o)
1675
+ await c.unmount();
1669
1676
  try {
1670
1677
  this.exit();
1671
1678
  } catch {
1672
1679
  }
1673
- this.initializeRuntime(t), s && (this[__private__dont__use].spawnProcess = s), u(this, C) && this.setSapiName(u(this, C));
1674
- const o = this[__private__dont__use].FS;
1675
- for (const a of r)
1676
- a && a !== "/request" && copyMEMFSNodes(e, o, a);
1677
- for (const { mountHandler: a, vfsPath: c } of i)
1678
- this.mkdir(c), await this.mount(c, a);
1680
+ this.initializeRuntime(t), s && (this[__private__dont__use].spawnProcess = s), u(this, M) && this.setSapiName(u(this, M));
1681
+ const a = this[__private__dont__use].FS;
1682
+ for (const c of r)
1683
+ c && c !== "/request" && copyMEMFSNodes(e, a, c);
1684
+ for (const { mountHandler: c, vfsPath: l } of i)
1685
+ this.mkdir(l), await this.mount(l, c);
1679
1686
  try {
1680
- o.chdir(n);
1681
- } catch (a) {
1687
+ a.chdir(n);
1688
+ } catch (c) {
1682
1689
  throw new Error(
1683
1690
  `Failed to restore CWD to ${n} after PHP runtime rotation.`,
1684
1691
  {
1685
- cause: a
1692
+ cause: c
1686
1693
  }
1687
1694
  );
1688
1695
  }
@@ -1702,10 +1709,10 @@ class PHP {
1702
1709
  ), s = {
1703
1710
  mountHandler: e,
1704
1711
  unmount: async () => {
1705
- await r(), delete u(this, M)[t];
1712
+ await r(), delete u(this, k)[t];
1706
1713
  }
1707
1714
  };
1708
- return u(this, M)[t] = s, () => {
1715
+ return u(this, k)[t] = s, () => {
1709
1716
  s.unmount();
1710
1717
  };
1711
1718
  }
@@ -1727,10 +1734,10 @@ class PHP {
1727
1734
  return this.subProcess(t, e);
1728
1735
  u(this, H) && (u(this, _).needsRotating = !0);
1729
1736
  const r = await this.semaphore.acquire();
1730
- return await y(this, h, D).call(this, () => {
1737
+ return await f(this, h, D).call(this, () => {
1731
1738
  const s = e.env || {};
1732
1739
  for (const [n, i] of Object.entries(s))
1733
- y(this, h, q).call(this, n, i);
1740
+ f(this, h, j).call(this, n, i);
1734
1741
  t = [t[0], "-c", PHP_INI_PATH, ...t.slice(1)];
1735
1742
  for (const n of t)
1736
1743
  this[__private__dont__use].ccall(
@@ -1821,7 +1828,7 @@ class PHP {
1821
1828
  this.exit(0);
1822
1829
  }
1823
1830
  }
1824
- C = new WeakMap(), H = new WeakMap(), T = new WeakMap(), E = new WeakMap(), F = new WeakMap(), M = new WeakMap(), _ = new WeakMap(), h = new WeakSet(), /**
1831
+ M = new WeakMap(), H = new WeakMap(), T = new WeakMap(), v = new WeakMap(), F = new WeakMap(), k = new WeakMap(), _ = new WeakMap(), h = new WeakSet(), /**
1825
1832
  * Prepares the $_SERVER entries for the PHP runtime.
1826
1833
  *
1827
1834
  * @param defaults Default entries to include in $_SERVER.
@@ -1830,7 +1837,7 @@ C = new WeakMap(), H = new WeakMap(), T = new WeakMap(), E = new WeakMap(), F =
1830
1837
  * was provided.
1831
1838
  * @returns Computed $_SERVER entries.
1832
1839
  */
1833
- B = function(t, e, r) {
1840
+ z = function(t, e, r) {
1834
1841
  const s = {
1835
1842
  ...t || {}
1836
1843
  };
@@ -1882,7 +1889,7 @@ B = function(t, e, r) {
1882
1889
  [STRING],
1883
1890
  [t]
1884
1891
  );
1885
- }, K = function(t) {
1892
+ }, Q = function(t) {
1886
1893
  t.cookie && this[__private__dont__use].ccall(
1887
1894
  "wasm_set_cookies",
1888
1895
  null,
@@ -1899,7 +1906,7 @@ B = function(t, e, r) {
1899
1906
  [NUMBER],
1900
1907
  [parseInt(t["content-length"], 10)]
1901
1908
  );
1902
- }, X = function(t) {
1909
+ }, K = function(t) {
1903
1910
  let e, r;
1904
1911
  typeof t == "string" ? (logger.warn(
1905
1912
  "Passing a string as the request body is deprecated. Please use a Uint8Array instead. See https://github.com/WordPress/wordpress-playground/issues/997 for more details"
@@ -1929,14 +1936,14 @@ B = function(t, e, r) {
1929
1936
  [STRING],
1930
1937
  [t]
1931
1938
  );
1932
- }, Q = function(t, e) {
1939
+ }, X = function(t, e) {
1933
1940
  this[__private__dont__use].ccall(
1934
1941
  "wasm_add_SERVER_entry",
1935
1942
  null,
1936
1943
  [STRING, STRING],
1937
1944
  [t, e]
1938
1945
  );
1939
- }, q = function(t, e) {
1946
+ }, j = function(t, e) {
1940
1947
  this[__private__dont__use].ccall(
1941
1948
  "wasm_add_ENV_entry",
1942
1949
  null,
@@ -1967,27 +1974,27 @@ B = function(t, e, r) {
1967
1974
  return await Promise.race([
1968
1975
  t(),
1969
1976
  new Promise((g, b) => {
1970
- var j;
1977
+ var q;
1971
1978
  c = (W) => {
1972
1979
  isExitCode(W.error) || b(W.error);
1973
- }, (j = u(this, T)) == null || j.addEventListener(
1980
+ }, (q = u(this, T)) == null || q.addEventListener(
1974
1981
  "error",
1975
1982
  c,
1976
1983
  { once: !0 }
1977
1984
  );
1978
1985
  })
1979
1986
  ]);
1980
- } catch (f) {
1981
- if (isExitCode(f))
1982
- return f.status;
1983
- i.controller.error(f), o.controller.error(f), r.controller.error(f), a = !0;
1987
+ } catch (m) {
1988
+ if (isExitCode(m))
1989
+ return m.status;
1990
+ i.controller.error(m), o.controller.error(m), r.controller.error(m), a = !0;
1984
1991
  for (const g in this)
1985
1992
  typeof this[g] == "function" && (this[g] = () => {
1986
1993
  throw new Error(
1987
1994
  "PHP runtime has crashed – see the earlier error for details."
1988
1995
  );
1989
1996
  });
1990
- throw this.functionsMaybeMissingFromAsyncify = getFunctionsMaybeMissingFromAsyncify(), f;
1997
+ throw this.functionsMaybeMissingFromAsyncify = getFunctionsMaybeMissingFromAsyncify(), m;
1991
1998
  } finally {
1992
1999
  a || (i.controller.close(), o.controller.close(), n(), a = !0), (p = u(this, T)) == null || p.removeEventListener(
1993
2000
  "error",
@@ -2004,11 +2011,11 @@ B = function(t, e, r) {
2004
2011
  source: "php-wasm"
2005
2012
  }), p),
2006
2013
  (p) => {
2007
- const f = p.source ?? "php-wasm";
2014
+ const m = p.source ?? "php-wasm";
2008
2015
  throw this.dispatchEvent({
2009
2016
  type: "request.error",
2010
2017
  error: p,
2011
- source: f
2018
+ source: m
2012
2019
  }), p;
2013
2020
  }
2014
2021
  );
@@ -2473,7 +2480,7 @@ const _default = "application/octet-stream", asx = "video/x-ms-asf", atom = "app
2473
2480
  xspf,
2474
2481
  zip
2475
2482
  };
2476
- var S, I, L, k, A, x, N, v, R, Z, ee, te;
2483
+ var P, I, L, C, A, E, N, R, x, Z, ee, te, re;
2477
2484
  class PHPRequestHandler {
2478
2485
  /**
2479
2486
  * The request handler needs to decide whether to serve a static asset or
@@ -2487,15 +2494,15 @@ class PHPRequestHandler {
2487
2494
  * @param config - Request Handler configuration.
2488
2495
  */
2489
2496
  constructor(e) {
2490
- m(this, R);
2491
- m(this, S);
2492
- m(this, I);
2493
- m(this, L);
2494
- m(this, k);
2495
- m(this, A);
2496
- m(this, x);
2497
- m(this, N);
2498
- m(this, v);
2497
+ y(this, x);
2498
+ y(this, P);
2499
+ y(this, I);
2500
+ y(this, L);
2501
+ y(this, C);
2502
+ y(this, A);
2503
+ y(this, E);
2504
+ y(this, N);
2505
+ y(this, R);
2499
2506
  const {
2500
2507
  documentRoot: r = "/www/",
2501
2508
  absoluteUrl: s = typeof location == "object" ? location.href : DEFAULT_BASE_URL,
@@ -2511,17 +2518,17 @@ class PHPRequestHandler {
2511
2518
  return l.isDir(r) || l.mkdir(r), l.chdir(r), l.requestHandler = this, l;
2512
2519
  },
2513
2520
  maxPhpInstances: e.maxPhpInstances
2514
- }), w(this, v, e.cookieStore === void 0 ? new HttpCookieStore() : e.cookieStore), w(this, S, r);
2521
+ }), w(this, R, e.cookieStore === void 0 ? new HttpCookieStore() : e.cookieStore), w(this, P, r);
2515
2522
  const o = new URL(s);
2516
- w(this, L, o.hostname), w(this, k, o.port ? Number(o.port) : o.protocol === "https:" ? 443 : 80), w(this, I, (o.protocol || "").replace(":", ""));
2517
- const a = u(this, k) !== 443 && u(this, k) !== 80;
2523
+ w(this, L, o.hostname), w(this, C, o.port ? Number(o.port) : o.protocol === "https:" ? 443 : 80), w(this, I, (o.protocol || "").replace(":", ""));
2524
+ const a = u(this, C) !== 443 && u(this, C) !== 80;
2518
2525
  w(this, A, [
2519
2526
  u(this, L),
2520
- a ? `:${u(this, k)}` : ""
2521
- ].join("")), w(this, x, o.pathname.replace(/\/+$/, "")), w(this, N, [
2527
+ a ? `:${u(this, C)}` : ""
2528
+ ].join("")), w(this, E, o.pathname.replace(/\/+$/, "")), w(this, N, [
2522
2529
  `${u(this, I)}://`,
2523
2530
  u(this, A),
2524
- u(this, x)
2531
+ u(this, E)
2525
2532
  ].join("")), this.rewriteRules = n, this.getFileNotFoundAction = i;
2526
2533
  }
2527
2534
  async getPrimaryPhp() {
@@ -2546,7 +2553,7 @@ class PHPRequestHandler {
2546
2553
  */
2547
2554
  internalUrlToPath(e) {
2548
2555
  const r = new URL(e, "https://playground.internal");
2549
- return r.pathname.startsWith(u(this, x)) && (r.pathname = r.pathname.slice(u(this, x).length)), toRelativeUrl(r);
2556
+ return r.pathname.startsWith(u(this, E)) && (r.pathname = r.pathname.slice(u(this, E).length)), toRelativeUrl(r);
2550
2557
  }
2551
2558
  /**
2552
2559
  * The absolute URL of this PHPRequestHandler instance.
@@ -2559,7 +2566,7 @@ class PHPRequestHandler {
2559
2566
  * for the files to serve. Default: `/var/www`.
2560
2567
  */
2561
2568
  get documentRoot() {
2562
- return u(this, S);
2569
+ return u(this, P);
2563
2570
  }
2564
2571
  /**
2565
2572
  * Serves the request – either by serving a static file, or by
@@ -2614,38 +2621,61 @@ class PHPRequestHandler {
2614
2621
  // Remove the hash part of the URL as it's not meant for the server.
2615
2622
  e.url.split("#")[0],
2616
2623
  r ? void 0 : DEFAULT_BASE_URL
2617
- ), n = applyRewriteRules(
2624
+ ), n = f(this, x, Z).call(this, s), i = await this.getPrimaryPhp();
2625
+ let o = joinPaths(
2626
+ u(this, P),
2627
+ /**
2628
+ * Turn a URL such as `https://playground/scope:my-site/wp-admin/index.php`
2629
+ * into a site-relative path, such as `/wp-admin/index.php`.
2630
+ */
2618
2631
  removePathPrefix(
2619
- decodeURIComponent(s.pathname),
2620
- u(this, x)
2621
- ),
2622
- this.rewriteRules
2623
- ), i = await this.getPrimaryPhp();
2624
- let o = joinPaths(u(this, S), n);
2632
+ /**
2633
+ * URL.pathname returns a URL-encoded path. We need to decode it
2634
+ * before using it as a filesystem path.
2635
+ */
2636
+ decodeURIComponent(n.pathname),
2637
+ u(this, E)
2638
+ )
2639
+ );
2625
2640
  if (i.isDir(o)) {
2626
2641
  if (!o.endsWith("/"))
2627
2642
  return new PHPResponse(
2628
2643
  301,
2629
- { Location: [`${s.pathname}/`] },
2644
+ { Location: [`${n.pathname}/`] },
2630
2645
  new Uint8Array(0)
2631
2646
  );
2632
2647
  for (const a of ["index.php", "index.html"]) {
2633
2648
  const c = joinPaths(o, a);
2634
2649
  if (i.isFile(c)) {
2635
- o = c;
2650
+ o = c, n.pathname = joinPaths(
2651
+ n.pathname,
2652
+ a
2653
+ );
2654
+ break;
2655
+ }
2656
+ }
2657
+ }
2658
+ if (!i.isFile(o)) {
2659
+ let a = n.pathname;
2660
+ for (; a.startsWith("/") && a !== dirname(a); ) {
2661
+ a = dirname(a);
2662
+ const c = joinPaths(u(this, P), a);
2663
+ if (i.isFile(c) && // Only run partial path resolution for PHP files.
2664
+ c.endsWith(".php")) {
2665
+ o = joinPaths(u(this, P), a);
2636
2666
  break;
2637
2667
  }
2638
2668
  }
2639
2669
  }
2640
2670
  if (!i.isFile(o)) {
2641
2671
  const a = this.getFileNotFoundAction(
2642
- n
2672
+ n.pathname
2643
2673
  );
2644
2674
  switch (a.type) {
2645
2675
  case "response":
2646
2676
  return a.response;
2647
2677
  case "internal-redirect":
2648
- o = joinPaths(u(this, S), a.uri);
2678
+ o = joinPaths(u(this, P), a.uri);
2649
2679
  break;
2650
2680
  case "404":
2651
2681
  return PHPResponse.forHttpCode(404);
@@ -2657,34 +2687,153 @@ class PHPRequestHandler {
2657
2687
  }
2658
2688
  if (i.isFile(o))
2659
2689
  if (o.endsWith(".php")) {
2660
- const a = {
2661
- ...e,
2662
- // Pass along URL with the #fragment filtered out
2663
- url: s.toString()
2664
- }, c = await y(this, R, ee).call(this, a, o);
2665
- return c.ok() && c.exitCode !== 0 ? new PHPResponse(
2690
+ const a = await f(this, x, te).call(this, e, s, n, o);
2691
+ return a.ok() && a.exitCode !== 0 ? new PHPResponse(
2666
2692
  500,
2667
- c.headers,
2668
- c.bytes,
2669
- c.errors,
2670
- c.exitCode
2671
- ) : c;
2693
+ a.headers,
2694
+ a.bytes,
2695
+ a.errors,
2696
+ a.exitCode
2697
+ ) : a;
2672
2698
  } else
2673
- return y(this, R, Z).call(this, i, o);
2699
+ return f(this, x, ee).call(this, i, o);
2674
2700
  else
2675
2701
  return PHPResponse.forHttpCode(404);
2676
2702
  }
2703
+ /**
2704
+ * Computes the essential $_SERVER entries for a request.
2705
+ *
2706
+ * php_wasm.c sets some defaults, assuming it runs as a CLI script.
2707
+ * This function overrides them with the values correct in the request
2708
+ * context.
2709
+ *
2710
+ * @TODO: Consolidate the $_SERVER setting logic into a single place instead
2711
+ * of splitting it between the C SAPI and the TypeScript code. The PHP
2712
+ * class has a `.cli()` method that could take care of the CLI-specific
2713
+ * $_SERVER values.
2714
+ *
2715
+ * Path and URL-related $_SERVER entries are theoretically documented
2716
+ * at https://www.php.net/manual/en/reserved.variables.server.php,
2717
+ * but that page is not very helpful in practice. Here are tables derived
2718
+ * by interacting with PHP servers:
2719
+ *
2720
+ * ## PHP Dev Server
2721
+ *
2722
+ * Setup:
2723
+ * – `/home/adam/subdir/script.php` file contains `<?php phpinfo(); ?>`
2724
+ * – `php -S 127.0.0.1:8041` running in `/home/adam` directory
2725
+ * – A request is sent to `http://127.0.0.1:8041/subdir/script.php/b.php/c.php`
2726
+ *
2727
+ * Results:
2728
+ *
2729
+ * $_SERVER['REQUEST_URI'] | `/subdir/script.php/b.php/c.php`
2730
+ * $_SERVER['SCRIPT_NAME'] | `/subdir/script.php`
2731
+ * $_SERVER['SCRIPT_FILENAME']| `/home/adam/subdir/script.php`
2732
+ * $_SERVER['PATH_INFO'] | `/b.php/c.php`
2733
+ * $_SERVER['PHP_SELF'] | `/subdir/script.php/b.php/c.php`
2734
+ *
2735
+ * ## Apache – rewriting rules
2736
+ *
2737
+ * Setup:
2738
+ * – `/var/www/html/subdir/script.php` file contains `<?php phpinfo(); ?>`
2739
+ * – Apache is listening on port 8041
2740
+ * – The document root is `/var/www/html`
2741
+ * – A request is sent to `http://127.0.0.1:8041/api/v1/user/123`
2742
+ *
2743
+ * .htaccess file:
2744
+ *
2745
+ * ```apache
2746
+ * RewriteEngine On
2747
+ * RewriteRule ^api/v1/user/([0-9]+)$ /subdir/script.php?endpoint=user&id=$1 [L,QSA]
2748
+ * ```
2749
+ *
2750
+ * Results:
2751
+ *
2752
+ * ```
2753
+ * $_SERVER['REQUEST_URI'] | /api/v1/user/123
2754
+ * $_SERVER['SCRIPT_NAME'] | /subdir/script.php
2755
+ * $_SERVER['SCRIPT_FILENAME'] | /var/www/html/subdir/script.php
2756
+ * $_SERVER['PATH_INFO'] | (key not set)
2757
+ * $_SERVER['PHP_SELF'] | /subdir/script.php
2758
+ * $_SERVER['QUERY_STRING'] | endpoint=user&id=123
2759
+ * $_SERVER['REDIRECT_STATUS'] | 200
2760
+ * $_SERVER['REDIRECT_URL'] | /api/v1/user/123
2761
+ * $_SERVER['REDIRECT_QUERY_STRING'] | endpoint=user&id=123
2762
+ * === $_GET Variables ===
2763
+ * $_GET['endpoint'] | user
2764
+ * $_GET['id'] | 123
2765
+ * ```
2766
+ *
2767
+ * ## Apache – vanilla request
2768
+ *
2769
+ * Setup:
2770
+ * – The same as above.
2771
+ * – A request sent http://localhost:8041/subdir/script.php?param=value
2772
+ *
2773
+ * Results:
2774
+ *
2775
+ * ```
2776
+ * $_SERVER['REQUEST_URI'] | /subdir/script.php?param=value
2777
+ * $_SERVER['SCRIPT_NAME'] | /subdir/script.php
2778
+ * $_SERVER['SCRIPT_FILENAME'] | /var/www/html/subdir/script.php
2779
+ * $_SERVER['PATH_INFO'] | (key not set)
2780
+ * $_SERVER['PHP_SELF'] | /subdir/script.php
2781
+ * $_SERVER['REDIRECT_URL'] | (key not set)
2782
+ * $_SERVER['REDIRECT_STATUS'] | (key not set)
2783
+ * $_SERVER['QUERY_STRING'] | param=value
2784
+ * $_SERVER['REQUEST_METHOD'] | GET
2785
+ * $_SERVER['DOCUMENT_ROOT'] | /var/www/html
2786
+ *
2787
+ * === $_GET Variables ===
2788
+ * $_GET['param'] | value
2789
+ * ```
2790
+ */
2791
+ prepare_$_SERVER_superglobal(e, r, s) {
2792
+ const n = {
2793
+ REMOTE_ADDR: "127.0.0.1",
2794
+ DOCUMENT_ROOT: u(this, P),
2795
+ HTTPS: u(this, N).startsWith("https://") ? "on" : ""
2796
+ };
2797
+ return n.REQUEST_URI = e.pathname + e.search, s.startsWith(u(this, P)) && (n.SCRIPT_NAME = s.substring(
2798
+ u(this, P).length
2799
+ ), n.PHP_SELF = r.pathname, n.REQUEST_URI.startsWith(n.SCRIPT_NAME) && (n.PATH_INFO = n.REQUEST_URI.substring(
2800
+ n.SCRIPT_NAME.length
2801
+ ), n.PATH_INFO.includes("?") && (n.PATH_INFO = n.PATH_INFO.substring(
2802
+ 0,
2803
+ n.PATH_INFO.indexOf("?")
2804
+ )))), n.QUERY_STRING = r.search.substring(1), n;
2805
+ }
2677
2806
  async [Symbol.asyncDispose]() {
2678
2807
  await this.processManager[Symbol.asyncDispose]();
2679
2808
  }
2680
2809
  }
2681
- S = new WeakMap(), I = new WeakMap(), L = new WeakMap(), k = new WeakMap(), A = new WeakMap(), x = new WeakMap(), N = new WeakMap(), v = new WeakMap(), R = new WeakSet(), /**
2810
+ P = new WeakMap(), I = new WeakMap(), L = new WeakMap(), C = new WeakMap(), A = new WeakMap(), E = new WeakMap(), N = new WeakMap(), R = new WeakMap(), x = new WeakSet(), /**
2811
+ * Apply the rewrite rules to the original request URL.
2812
+ *
2813
+ * @param originalRequestUrl - The original request URL.
2814
+ * @returns The rewritten request URL.
2815
+ */
2816
+ Z = function(e) {
2817
+ const r = removePathPrefix(
2818
+ decodeURIComponent(e.pathname),
2819
+ u(this, E)
2820
+ ), s = applyRewriteRules(
2821
+ r,
2822
+ this.rewriteRules
2823
+ ), n = new URL(
2824
+ joinPaths(u(this, E), s),
2825
+ e.toString()
2826
+ );
2827
+ for (const [i, o] of e.searchParams.entries())
2828
+ n.searchParams.append(i, o);
2829
+ return n;
2830
+ }, /**
2682
2831
  * Serves a static file from the PHP filesystem.
2683
2832
  *
2684
2833
  * @param fsPath - Absolute path of the static file to serve.
2685
2834
  * @returns The response.
2686
2835
  */
2687
- Z = function(e, r) {
2836
+ ee = function(e, r) {
2688
2837
  const s = e.readFileAsBuffer(r);
2689
2838
  return new PHPResponse(
2690
2839
  200,
@@ -2699,58 +2848,58 @@ Z = function(e, r) {
2699
2848
  },
2700
2849
  s
2701
2850
  );
2702
- }, ee = async function(e, r) {
2703
- let s;
2851
+ }, te = async function(e, r, s, n) {
2852
+ let i;
2704
2853
  try {
2705
- s = await this.processManager.acquirePHPInstance({
2854
+ i = await this.processManager.acquirePHPInstance({
2706
2855
  considerPrimary: !0
2707
2856
  });
2708
- } catch (n) {
2709
- return n instanceof MaxPhpInstancesError ? PHPResponse.forHttpCode(502) : PHPResponse.forHttpCode(500);
2857
+ } catch (o) {
2858
+ return o instanceof MaxPhpInstancesError ? PHPResponse.forHttpCode(502) : PHPResponse.forHttpCode(500);
2710
2859
  }
2711
2860
  try {
2712
- return await y(this, R, te).call(this, s.php, e, r);
2861
+ return await f(this, x, re).call(this, i.php, e, r, s, n);
2713
2862
  } finally {
2714
- s.reap();
2863
+ i.reap();
2715
2864
  }
2716
- }, te = async function(e, r, s) {
2717
- let n = "GET";
2718
- const i = {
2865
+ }, re = async function(e, r, s, n, i) {
2866
+ let o = "GET";
2867
+ const a = {
2719
2868
  host: u(this, A),
2720
2869
  ...normalizeHeaders(r.headers || {})
2721
2870
  };
2722
- u(this, v) && (i.cookie = u(this, v).getCookieRequestHeader());
2723
- let o = r.body;
2724
- if (typeof o == "object" && !(o instanceof Uint8Array)) {
2725
- n = "POST";
2726
- const { bytes: a, contentType: c } = await encodeAsMultipart(o);
2727
- o = a, i["content-type"] = c;
2871
+ u(this, R) && (a.cookie = u(this, R).getCookieRequestHeader());
2872
+ let c = r.body;
2873
+ if (typeof c == "object" && !(c instanceof Uint8Array)) {
2874
+ o = "POST";
2875
+ const { bytes: l, contentType: d } = await encodeAsMultipart(c);
2876
+ c = l, a["content-type"] = d;
2728
2877
  }
2729
2878
  try {
2730
- const a = await e.run({
2879
+ const l = await e.run({
2731
2880
  relativeUri: ensurePathPrefix(
2732
- toRelativeUrl(new URL(r.url)),
2733
- u(this, x)
2881
+ toRelativeUrl(new URL(n.toString())),
2882
+ u(this, E)
2734
2883
  ),
2735
2884
  protocol: u(this, I),
2736
- method: r.method || n,
2737
- $_SERVER: {
2738
- REMOTE_ADDR: "127.0.0.1",
2739
- DOCUMENT_ROOT: u(this, S),
2740
- HTTPS: u(this, N).startsWith("https://") ? "on" : ""
2741
- },
2742
- body: o,
2743
- scriptPath: s,
2744
- headers: i
2885
+ method: r.method || o,
2886
+ $_SERVER: this.prepare_$_SERVER_superglobal(
2887
+ s,
2888
+ n,
2889
+ i
2890
+ ),
2891
+ body: c,
2892
+ scriptPath: i,
2893
+ headers: a
2745
2894
  });
2746
- return u(this, v) && u(this, v).rememberCookiesFromResponseHeaders(
2747
- a.headers
2748
- ), a;
2749
- } catch (a) {
2750
- const c = a;
2751
- if (c != null && c.response)
2752
- return c.response;
2753
- throw a;
2895
+ return u(this, R) && u(this, R).rememberCookiesFromResponseHeaders(
2896
+ l.headers
2897
+ ), l;
2898
+ } catch (l) {
2899
+ const d = l;
2900
+ if (d != null && d.response)
2901
+ return d.response;
2902
+ throw l;
2754
2903
  }
2755
2904
  };
2756
2905
  function inferMimeType(t) {
@@ -2759,8 +2908,10 @@ function inferMimeType(t) {
2759
2908
  }
2760
2909
  function applyRewriteRules(t, e) {
2761
2910
  for (const r of e)
2762
- if (new RegExp(r.match).test(t))
2763
- return t.replace(r.match, r.replacement);
2911
+ if (new RegExp(r.match).test(t)) {
2912
+ t = t.replace(r.match, r.replacement);
2913
+ break;
2914
+ }
2764
2915
  return t;
2765
2916
  }
2766
2917
  function rotatePHPRuntime({
@@ -3044,10 +3195,10 @@ function expose(t, e = globalThis, r = ["*"], s) {
3044
3195
  }, l = (i.data.argumentList || []).map(fromWireValue);
3045
3196
  let d;
3046
3197
  try {
3047
- const p = c.slice(0, -1).reduce((g, b) => g[b], t), f = c.reduce((g, b) => g[b], t);
3198
+ const p = c.slice(0, -1).reduce((g, b) => g[b], t), m = c.reduce((g, b) => g[b], t);
3048
3199
  switch (a) {
3049
3200
  case MessageType.GET:
3050
- d = f;
3201
+ d = m;
3051
3202
  break;
3052
3203
  case MessageType.SET:
3053
3204
  p[c.slice(-1)[0]] = fromWireValue(
@@ -3055,11 +3206,11 @@ function expose(t, e = globalThis, r = ["*"], s) {
3055
3206
  ), d = !0;
3056
3207
  break;
3057
3208
  case MessageType.APPLY:
3058
- d = f.apply(p, l);
3209
+ d = m.apply(p, l);
3059
3210
  break;
3060
3211
  case MessageType.CONSTRUCT:
3061
3212
  {
3062
- const g = new f(...l);
3213
+ const g = new m(...l);
3063
3214
  d = proxy(g);
3064
3215
  }
3065
3216
  break;
@@ -3079,14 +3230,14 @@ function expose(t, e = globalThis, r = ["*"], s) {
3079
3230
  d = { value: p, [throwMarker]: 0 };
3080
3231
  }
3081
3232
  Promise.resolve(d).catch((p) => ({ value: p, [throwMarker]: 0 })).then((p) => {
3082
- const [f, g] = toWireValue(p);
3083
- e.postMessage({ ...f, id: o }, g), a === MessageType.RELEASE && (e.removeEventListener("message", n), closeEndPoint(e), finalizer in t && typeof t[finalizer] == "function" && t[finalizer]());
3233
+ const [m, g] = toWireValue(p);
3234
+ e.postMessage({ ...m, id: o }, g), a === MessageType.RELEASE && (e.removeEventListener("message", n), closeEndPoint(e), finalizer in t && typeof t[finalizer] == "function" && t[finalizer]());
3084
3235
  }).catch(() => {
3085
- const [p, f] = toWireValue({
3236
+ const [p, m] = toWireValue({
3086
3237
  value: new TypeError("Unserializable return value"),
3087
3238
  [throwMarker]: 0
3088
3239
  });
3089
- e.postMessage({ ...p, id: o }, f);
3240
+ e.postMessage({ ...p, id: o }, m);
3090
3241
  }).finally(() => {
3091
3242
  s == null || s(i);
3092
3243
  });
@@ -3184,7 +3335,7 @@ function createProxy(t, e, r = [], s = function() {
3184
3335
  e,
3185
3336
  {
3186
3337
  type: MessageType.APPLY,
3187
- path: r.map((f) => f.toString()),
3338
+ path: r.map((m) => m.toString()),
3188
3339
  argumentList: d
3189
3340
  },
3190
3341
  p