@php-wasm/web 0.1.45 → 0.1.49

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.
@@ -143,12 +143,12 @@ function fe(t) {
143
143
  return [];
144
144
  }
145
145
  }
146
- class v {
146
+ class b {
147
147
  constructor(e, r, n, s = "", o = 0) {
148
148
  this.httpStatusCode = e, this.headers = r, this.bytes = n, this.exitCode = o, this.errors = s;
149
149
  }
150
150
  static fromRawData(e) {
151
- return new v(
151
+ return new b(
152
152
  e.httpStatusCode,
153
153
  e.headers,
154
154
  e.bytes,
@@ -384,13 +384,13 @@ class be {
384
384
  #c(e) {
385
385
  const r = `${this.#e}${e}`;
386
386
  if (!this.php.fileExists(r))
387
- return new v(
387
+ return new b(
388
388
  404,
389
389
  {},
390
390
  new TextEncoder().encode("404 File not found")
391
391
  );
392
392
  const n = this.php.readFileAsBuffer(r);
393
- return new v(
393
+ return new b(
394
394
  200,
395
395
  {
396
396
  "content-length": [`${n.byteLength}`],
@@ -425,13 +425,13 @@ class be {
425
425
  }, i = [];
426
426
  if (e.files && Object.keys(e.files).length) {
427
427
  s = "POST";
428
- for (const l in e.files) {
429
- const c = e.files[l];
428
+ for (const c in e.files) {
429
+ const h = e.files[c];
430
430
  i.push({
431
- key: l,
432
- name: c.name,
433
- type: c.type,
434
- data: new Uint8Array(await c.arrayBuffer())
431
+ key: c,
432
+ name: h.name,
433
+ type: h.type,
434
+ data: new Uint8Array(await h.arrayBuffer())
435
435
  });
436
436
  }
437
437
  o["content-type"]?.startsWith("multipart/form-data") && (e.formData = Ee(
@@ -439,9 +439,20 @@ class be {
439
439
  ), o["content-type"] = "application/x-www-form-urlencoded", delete e.body);
440
440
  }
441
441
  let a;
442
- return e.formData !== void 0 ? (s = "POST", o["content-type"] = o["content-type"] || "application/x-www-form-urlencoded", a = new URLSearchParams(
442
+ e.formData !== void 0 ? (s = "POST", o["content-type"] = o["content-type"] || "application/x-www-form-urlencoded", a = new URLSearchParams(
443
443
  e.formData
444
- ).toString()) : a = e.body, await this.php.run({
444
+ ).toString()) : a = e.body;
445
+ let l;
446
+ try {
447
+ l = this.#h(r.pathname);
448
+ } catch {
449
+ return new b(
450
+ 404,
451
+ {},
452
+ new TextEncoder().encode("404 File not found")
453
+ );
454
+ }
455
+ return await this.php.run({
445
456
  relativeUri: Pe(
446
457
  j(r),
447
458
  this.#s
@@ -450,7 +461,7 @@ class be {
450
461
  method: e.method || s,
451
462
  body: a,
452
463
  fileInfos: i,
453
- scriptPath: this.#h(r.pathname),
464
+ scriptPath: l,
454
465
  headers: o
455
466
  });
456
467
  } finally {
@@ -463,13 +474,18 @@ class be {
463
474
  * Fall back to index.php as if there was a url rewriting rule in place.
464
475
  *
465
476
  * @param requestedPath - The requested pathname.
477
+ * @throws {Error} If the requested path doesn't exist.
466
478
  * @returns The resolved filesystem path.
467
479
  */
468
480
  #h(e) {
469
481
  let r = G(e, this.#s);
470
482
  r.includes(".php") ? r = r.split(".php")[0] + ".php" : (r.endsWith("/") || (r += "/"), r.endsWith("index.php") || (r += "index.php"));
471
483
  const n = `${this.#e}${r}`;
472
- return this.php.fileExists(n) ? n : `${this.#e}/index.php`;
484
+ if (this.php.fileExists(n))
485
+ return n;
486
+ if (!this.php.fileExists(`${this.#e}/index.php`))
487
+ throw new Error(`File not found: ${n}`);
488
+ return `${this.#e}/index.php`;
473
489
  }
474
490
  }
475
491
  function Ee(t) {
@@ -665,7 +681,7 @@ var xe = Object.defineProperty, Te = Object.getOwnPropertyDescriptor, w = (t, e,
665
681
  (i = t[o]) && (s = (n ? i(e, r, s) : i(s)) || s);
666
682
  return n && s && xe(e, r, s), s;
667
683
  };
668
- const f = "string", b = "number", u = Symbol("__private__dont__use");
684
+ const f = "string", E = "number", u = Symbol("__private__dont__use");
669
685
  class m {
670
686
  /**
671
687
  * Initializes a PHP runtime.
@@ -812,7 +828,7 @@ class m {
812
828
  (!n || isNaN(n) || n === 80) && (n = r === "https" ? 443 : 80), this[u].ccall(
813
829
  "wasm_set_request_port",
814
830
  null,
815
- [b],
831
+ [E],
816
832
  [n]
817
833
  ), (r === "https" || !r && n === 443) && this.addServerGlobalEntry("HTTPS", "on");
818
834
  }
@@ -838,7 +854,7 @@ class m {
838
854
  ), e["content-length"] && this[u].ccall(
839
855
  "wasm_set_content_length",
840
856
  null,
841
- [b],
857
+ [E],
842
858
  [parseInt(e["content-length"], 10)]
843
859
  );
844
860
  for (const r in e)
@@ -856,7 +872,7 @@ class m {
856
872
  ), this[u].ccall(
857
873
  "wasm_set_content_length",
858
874
  null,
859
- [b],
875
+ [E],
860
876
  [new TextEncoder().encode(e).length]
861
877
  );
862
878
  }
@@ -896,7 +912,7 @@ class m {
896
912
  this[u].ccall(
897
913
  "wasm_add_uploaded_file",
898
914
  null,
899
- [f, f, f, f, b, b],
915
+ [f, f, f, f, E, E],
900
916
  [r, n, s, i, a, o.byteLength]
901
917
  );
902
918
  }
@@ -911,32 +927,21 @@ class m {
911
927
  async #m() {
912
928
  let e, r;
913
929
  try {
914
- e = await new Promise(async (o, i) => {
915
- r = (a) => {
916
- const l = new Error("Rethrown");
917
- l.cause = a.error, l.betterMessage = a.message, i(l);
930
+ e = await new Promise((o, i) => {
931
+ r = (l) => {
932
+ const c = new Error("Rethrown");
933
+ c.cause = l.error, c.betterMessage = l.message, i(c);
918
934
  }, this.#n?.addEventListener(
919
935
  "error",
920
936
  r
921
937
  );
922
- try {
923
- o(
924
- /**
925
- * This is awkward, but Asyncify makes wasm_sapi_handle_request return
926
- * Promise<Promise<number>>.
927
- *
928
- * @TODO: Determine whether this is a bug in emscripten or in our code.
929
- */
930
- await await this[u].ccall(
931
- "wasm_sapi_handle_request",
932
- b,
933
- [],
934
- []
935
- )
936
- );
937
- } catch (a) {
938
- i(a);
939
- }
938
+ const a = this[u].ccall(
939
+ "wasm_sapi_handle_request",
940
+ E,
941
+ [],
942
+ []
943
+ );
944
+ return a instanceof Promise ? a.then(o, i) : o(a);
940
945
  });
941
946
  } catch (o) {
942
947
  for (const c in this)
@@ -952,7 +957,7 @@ class m {
952
957
  this.#n?.removeEventListener("error", r), this.#r = {};
953
958
  }
954
959
  const { headers: n, httpStatusCode: s } = this.#s();
955
- return new v(
960
+ return new b(
956
961
  s,
957
962
  n,
958
963
  this.readFileAsBuffer("/tmp/stdout"),
@@ -1159,7 +1164,7 @@ function k(t) {
1159
1164
  throw new Error("Proxy has been released and is not useable");
1160
1165
  }
1161
1166
  function ee(t) {
1162
- return E(t, {
1167
+ return v(t, {
1163
1168
  type: "RELEASE"
1164
1169
  }).then(() => {
1165
1170
  Z(t);
@@ -1188,7 +1193,7 @@ function O(t, e = [], r = function() {
1188
1193
  if (i === "then") {
1189
1194
  if (e.length === 0)
1190
1195
  return { then: () => s };
1191
- const a = E(t, {
1196
+ const a = v(t, {
1192
1197
  type: "GET",
1193
1198
  path: e.map((l) => l.toString())
1194
1199
  }).then(P);
@@ -1199,7 +1204,7 @@ function O(t, e = [], r = function() {
1199
1204
  set(o, i, a) {
1200
1205
  k(n);
1201
1206
  const [l, c] = C(a);
1202
- return E(t, {
1207
+ return v(t, {
1203
1208
  type: "SET",
1204
1209
  path: [...e, i].map((h) => h.toString()),
1205
1210
  value: l
@@ -1209,13 +1214,13 @@ function O(t, e = [], r = function() {
1209
1214
  k(n);
1210
1215
  const l = e[e.length - 1];
1211
1216
  if (l === _e)
1212
- return E(t, {
1217
+ return v(t, {
1213
1218
  type: "ENDPOINT"
1214
1219
  }).then(P);
1215
1220
  if (l === "bind")
1216
1221
  return O(t, e.slice(0, -1));
1217
1222
  const [c, h] = Y(a);
1218
- return E(t, {
1223
+ return v(t, {
1219
1224
  type: "APPLY",
1220
1225
  path: e.map((g) => g.toString()),
1221
1226
  argumentList: c
@@ -1224,7 +1229,7 @@ function O(t, e = [], r = function() {
1224
1229
  construct(o, i) {
1225
1230
  k(n);
1226
1231
  const [a, l] = Y(i);
1227
- return E(t, {
1232
+ return v(t, {
1228
1233
  type: "CONSTRUCT",
1229
1234
  path: e.map((c) => c.toString()),
1230
1235
  argumentList: a
@@ -1283,7 +1288,7 @@ function P(t) {
1283
1288
  return t.value;
1284
1289
  }
1285
1290
  }
1286
- function E(t, e, r) {
1291
+ function v(t, e, r) {
1287
1292
  return new Promise((n) => {
1288
1293
  const s = Ne();
1289
1294
  t.addEventListener("message", function o(i) {
@@ -1342,7 +1347,7 @@ function se() {
1342
1347
  return [t.toRawData(), []];
1343
1348
  },
1344
1349
  deserialize(t) {
1345
- return v.fromRawData(t);
1350
+ return b.fromRawData(t);
1346
1351
  }
1347
1352
  }));
1348
1353
  }
@@ -1443,22 +1448,25 @@ class Ge {
1443
1448
  monitor: r
1444
1449
  }), this.absoluteUrl = e.absoluteUrl, this.documentRoot = e.documentRoot;
1445
1450
  }
1446
- /** @inheritDoc */
1451
+ /** @inheritDoc @php-wasm/universal!RequestHandler.pathToInternalUrl */
1447
1452
  pathToInternalUrl(e) {
1448
1453
  return d.get(this).php.pathToInternalUrl(e);
1449
1454
  }
1450
- /** @inheritDoc */
1455
+ /** @inheritDoc @php-wasm/universal!RequestHandler.internalUrlToPath */
1451
1456
  internalUrlToPath(e) {
1452
1457
  return d.get(this).php.internalUrlToPath(e);
1453
1458
  }
1459
+ /**
1460
+ * The onDownloadProgress event listener.
1461
+ */
1454
1462
  async onDownloadProgress(e) {
1455
1463
  return d.get(this).monitor?.addEventListener("progress", e);
1456
1464
  }
1457
- /** @inheritDoc */
1465
+ /** @inheritDoc @php-wasm/universal!IsomorphicLocalPHP.mv */
1458
1466
  mv(e, r) {
1459
1467
  return d.get(this).php.mv(e, r);
1460
1468
  }
1461
- /** @inheritDoc */
1469
+ /** @inheritDoc @php-wasm/universal!IsomorphicLocalPHP.rmdir */
1462
1470
  rmdir(e, r) {
1463
1471
  return d.get(this).php.rmdir(e, r);
1464
1472
  }
package/index.d.ts CHANGED
@@ -15,7 +15,7 @@ export type WithAPIState = {
15
15
  */
16
16
  isReady: () => Promise<void>;
17
17
  };
18
- export type RemoteAPI<T> = Comlink.Remote<T & WithAPIState>;
18
+ export type RemoteAPI<T> = Comlink.Remote<T> & WithAPIState;
19
19
  export declare function consumeAPI<APIType>(remote: Worker | Window): RemoteAPI<APIType>;
20
20
  export type PublicAPI<Methods, PipedAPI = unknown> = RemoteAPI<Methods & PipedAPI>;
21
21
  export declare function exposeAPI<Methods, PipedAPI>(apiMethods?: Methods, pipedApi?: PipedAPI): [
@@ -127,7 +127,33 @@ export interface RequestHandler {
127
127
  /**
128
128
  * Serves the request – either by serving a static file, or by
129
129
  * dispatching it to the PHP runtime.
130
- * Cannot be used in conjunction with `cli()`.
130
+ *
131
+ * The request() method mode behaves like a web server and only works if
132
+ * the PHP was initialized with a `requestHandler` option (which the online version
133
+ * of WordPress Playground does by default).
134
+ *
135
+ * In the request mode, you pass an object containing the request information
136
+ * (method, headers, body, etc.) and the path to the PHP file to run:
137
+ *
138
+ * ```ts
139
+ * const php = PHP.load('7.4', {
140
+ * requestHandler: {
141
+ * documentRoot: "/www"
142
+ * }
143
+ * })
144
+ * php.writeFile("/www/index.php", `<?php echo file_get_contents("php://input");`);
145
+ * const result = await php.run({
146
+ * method: "GET",
147
+ * headers: {
148
+ * "Content-Type": "text/plain"
149
+ * },
150
+ * body: "Hello world!",
151
+ * path: "/www/index.php"
152
+ * });
153
+ * // result.text === "Hello world!"
154
+ * ```
155
+ *
156
+ * The `request()` method cannot be used in conjunction with `cli()`.
131
157
  *
132
158
  * @example
133
159
  * ```js
@@ -174,7 +200,18 @@ export interface RequestHandler {
174
200
  documentRoot: string;
175
201
  }
176
202
  export interface IsomorphicLocalPHP extends RequestHandler {
203
+ /**
204
+ * Sets the path to the php.ini file to use for the PHP instance.
205
+ *
206
+ * @param path - The path to the php.ini file.
207
+ */
177
208
  setPhpIniPath(path: string): void;
209
+ /**
210
+ * Sets a value for a specific key in the php.ini file for the PHP instance.
211
+ *
212
+ * @param key - The key to set the value for.
213
+ * @param value - The value to set for the key.
214
+ */
178
215
  setPhpIniEntry(key: string, value: string): void;
179
216
  /**
180
217
  * Recursively creates a directory with the given path in the PHP filesystem.
@@ -266,24 +303,72 @@ export interface IsomorphicLocalPHP extends RequestHandler {
266
303
  chdir(path: string): void;
267
304
  /**
268
305
  * Runs PHP code.
269
- * Cannot be used in conjunction with `cli()`.
270
306
  *
271
- * @example
272
- * ```js
273
- * const output = await php.run('<?php echo "Hello world!";');
274
- * console.log(output.stdout); // "Hello world!"
307
+ * This low-level method directly interacts with the WebAssembly
308
+ * PHP interpreter.
309
+ *
310
+ * Every time you call run(), it prepares the PHP
311
+ * environment and:
312
+ *
313
+ * * Resets the internal PHP state
314
+ * * Populates superglobals ($_SERVER, $_GET, etc.)
315
+ * * Handles file uploads
316
+ * * Populates input streams (stdin, argv, etc.)
317
+ * * Sets the current working directory
318
+ *
319
+ * You can use run() in two primary modes:
320
+ *
321
+ * ### Code snippet mode
322
+ *
323
+ * In this mode, you pass a string containing PHP code to run.
324
+ *
325
+ * ```ts
326
+ * const result = await php.run({
327
+ * code: `<?php echo "Hello world!";`
328
+ * });
329
+ * // result.text === "Hello world!"
275
330
  * ```
276
331
  *
332
+ * In this mode, information like __DIR__ or __FILE__ isn't very
333
+ * useful because the code is not associated with any file.
334
+ *
335
+ * Under the hood, the PHP snippet is passed to the `zend_eval_string`
336
+ * C function.
337
+ *
338
+ * ### File mode
339
+ *
340
+ * In the file mode, you pass a scriptPath and PHP executes a file
341
+ * found at a that path:
342
+ *
343
+ * ```ts
344
+ * php.writeFile(
345
+ * "/www/index.php",
346
+ * `<?php echo "Hello world!";"`
347
+ * );
348
+ * const result = await php.run({
349
+ * scriptPath: "/www/index.php"
350
+ * });
351
+ * // result.text === "Hello world!"
352
+ * ```
353
+ *
354
+ * In this mode, you can rely on path-related information like __DIR__
355
+ * or __FILE__.
356
+ *
357
+ * Under the hood, the PHP file is executed with the `php_execute_script`
358
+ * C function.
359
+ *
360
+ * The `run()` method cannot be used in conjunction with `cli()`.
361
+ *
277
362
  * @example
278
363
  * ```js
279
- * console.log(await php.run(`<?php
364
+ * const result = await php.run(`<?php
280
365
  * $fp = fopen('php://stderr', 'w');
281
366
  * fwrite($fp, "Hello, world!");
282
- * `));
283
- * // {"exitCode":0,"stdout":"","stderr":["Hello, world!"]}
367
+ * `);
368
+ * // result.errors === "Hello, world!"
284
369
  * ```
285
370
  *
286
- * @param options - PHP run options.
371
+ * @param options - PHP runtime options.
287
372
  */
288
373
  run(options: PHPRunOptions): Promise<PHPResponse>;
289
374
  }
@@ -590,20 +675,23 @@ export declare class WebPHP extends BasePHP {
590
675
  * A PHP client that can be used to run PHP code in the browser.
591
676
  */
592
677
  export declare class WebPHPEndpoint implements IsomorphicLocalPHP {
593
- /** @inheritDoc */
678
+ /** @inheritDoc @php-wasm/universal!RequestHandler.absoluteUrl */
594
679
  absoluteUrl: string;
595
- /** @inheritDoc */
680
+ /** @inheritDoc @php-wasm/universal!RequestHandler.documentRoot */
596
681
  documentRoot: string;
597
682
  /** @inheritDoc */
598
683
  constructor(php: BasePHP, monitor?: EmscriptenDownloadMonitor);
599
- /** @inheritDoc */
684
+ /** @inheritDoc @php-wasm/universal!RequestHandler.pathToInternalUrl */
600
685
  pathToInternalUrl(path: string): string;
601
- /** @inheritDoc */
686
+ /** @inheritDoc @php-wasm/universal!RequestHandler.internalUrlToPath */
602
687
  internalUrlToPath(internalUrl: string): string;
688
+ /**
689
+ * The onDownloadProgress event listener.
690
+ */
603
691
  onDownloadProgress(callback: (progress: CustomEvent<ProgressEvent>) => void): Promise<void>;
604
- /** @inheritDoc */
692
+ /** @inheritDoc @php-wasm/universal!IsomorphicLocalPHP.mv */
605
693
  mv(fromPath: string, toPath: string): void;
606
- /** @inheritDoc */
694
+ /** @inheritDoc @php-wasm/universal!IsomorphicLocalPHP.rmdir */
607
695
  rmdir(path: string, options?: RmDirOptions): void;
608
696
  /** @inheritDoc @php-wasm/universal!RequestHandler.request */
609
697
  request(request: PHPRequest, redirects?: number): Promise<PHPResponse>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@php-wasm/web",
3
- "version": "0.1.45",
3
+ "version": "0.1.49",
4
4
  "description": "PHP.wasm for the web",
5
5
  "repository": {
6
6
  "type": "git",
@@ -29,5 +29,5 @@
29
29
  "type": "module",
30
30
  "main": "index.js",
31
31
  "types": "index.d.ts",
32
- "gitHead": "ca75514c17b912dc8b5dc529f6d123295671320a"
32
+ "gitHead": "93834fa77a89c21be2ade4c1d67430981ed92c83"
33
33
  }