@php-wasm/universal 1.1.2 → 1.1.4
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.cjs +16 -10
- package/index.cjs.map +1 -1
- package/index.js +993 -615
- package/index.js.map +1 -1
- package/lib/api.d.ts +18 -0
- package/lib/index.d.ts +5 -3
- package/lib/is-exit-code.d.ts +9 -0
- package/lib/php-process-manager.d.ts +15 -1
- package/lib/php-request-handler.d.ts +2 -1
- package/lib/php-response.d.ts +54 -3
- package/lib/php-worker.d.ts +2 -1
- package/lib/php.d.ts +104 -7
- package/lib/wasm-error-reporting.d.ts +2 -2
- package/package.json +8 -8
- package/lib/is-exit-code-zero.d.ts +0 -7
package/index.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
var
|
|
2
|
-
throw TypeError(
|
|
1
|
+
var O = (r) => {
|
|
2
|
+
throw TypeError(r);
|
|
3
3
|
};
|
|
4
|
-
var
|
|
5
|
-
var c = (
|
|
4
|
+
var q = (r, e, t) => e.has(r) || O("Cannot " + t);
|
|
5
|
+
var c = (r, e, t) => (q(r, e, "read from private field"), t ? t.call(r) : e.get(r)), h = (r, e, t) => e.has(r) ? O("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(r) : e.set(r, t), f = (r, e, t, s) => (q(r, e, "write to private field"), s ? s.call(r, t) : e.set(r, t), t), d = (r, e, t) => (q(r, e, "access private method"), t);
|
|
6
6
|
import "@php-wasm/node-polyfills";
|
|
7
7
|
import { logger } from "@php-wasm/logger";
|
|
8
8
|
import { dirname, joinPaths, Semaphore, createSpawnHandler, normalizePath, AcquireTimeoutError } from "@php-wasm/util";
|
|
9
9
|
import { parse, stringify } from "ini";
|
|
10
10
|
import { StreamedFile } from "@php-wasm/stream-compression";
|
|
11
|
+
import * as Comlink from "comlink";
|
|
11
12
|
const FileErrorCodes = {
|
|
12
13
|
0: "No error occurred. System call completed successfully.",
|
|
13
14
|
1: "Argument list too long.",
|
|
@@ -87,21 +88,21 @@ const FileErrorCodes = {
|
|
|
87
88
|
75: "Cross-device link.",
|
|
88
89
|
76: "Extension: Capabilities insufficient."
|
|
89
90
|
};
|
|
90
|
-
function getEmscriptenFsError(
|
|
91
|
-
const e = typeof
|
|
91
|
+
function getEmscriptenFsError(r) {
|
|
92
|
+
const e = typeof r == "object" ? r == null ? void 0 : r.errno : null;
|
|
92
93
|
if (e in FileErrorCodes)
|
|
93
94
|
return FileErrorCodes[e];
|
|
94
95
|
}
|
|
95
|
-
function rethrowFileSystemError(
|
|
96
|
-
return function(
|
|
96
|
+
function rethrowFileSystemError(r = "") {
|
|
97
|
+
return function(t) {
|
|
97
98
|
return function(...s) {
|
|
98
99
|
try {
|
|
99
|
-
return
|
|
100
|
+
return t.apply(this, s);
|
|
100
101
|
} catch (i) {
|
|
101
|
-
const
|
|
102
|
-
if (
|
|
103
|
-
const
|
|
104
|
-
throw new Error(`${
|
|
102
|
+
const n = typeof i == "object" ? i == null ? void 0 : i.errno : null;
|
|
103
|
+
if (n in FileErrorCodes) {
|
|
104
|
+
const o = FileErrorCodes[n], a = typeof s[1] == "string" ? s[1] : null, l = a !== null ? r.replaceAll("{path}", a) : r;
|
|
105
|
+
throw new Error(`${l}: ${o}`, {
|
|
105
106
|
cause: i
|
|
106
107
|
});
|
|
107
108
|
}
|
|
@@ -119,8 +120,8 @@ class FSHelpers {
|
|
|
119
120
|
* @param path - The file path to read.
|
|
120
121
|
* @returns The file contents.
|
|
121
122
|
*/
|
|
122
|
-
static readFileAsText(e,
|
|
123
|
-
return new TextDecoder().decode(FSHelpers.readFileAsBuffer(e,
|
|
123
|
+
static readFileAsText(e, t) {
|
|
124
|
+
return new TextDecoder().decode(FSHelpers.readFileAsBuffer(e, t));
|
|
124
125
|
}
|
|
125
126
|
/**
|
|
126
127
|
* Reads a file from the PHP filesystem and returns it as an array buffer.
|
|
@@ -130,8 +131,8 @@ class FSHelpers {
|
|
|
130
131
|
* @param path - The file path to read.
|
|
131
132
|
* @returns The file contents.
|
|
132
133
|
*/
|
|
133
|
-
static readFileAsBuffer(e,
|
|
134
|
-
return e.readFile(
|
|
134
|
+
static readFileAsBuffer(e, t) {
|
|
135
|
+
return e.readFile(t);
|
|
135
136
|
}
|
|
136
137
|
/**
|
|
137
138
|
* Overwrites data in a file in the PHP filesystem.
|
|
@@ -141,8 +142,8 @@ class FSHelpers {
|
|
|
141
142
|
* @param path - The file path to write to.
|
|
142
143
|
* @param data - The data to write to the file.
|
|
143
144
|
*/
|
|
144
|
-
static writeFile(e,
|
|
145
|
-
e.writeFile(
|
|
145
|
+
static writeFile(e, t, s) {
|
|
146
|
+
e.writeFile(t, s);
|
|
146
147
|
}
|
|
147
148
|
/**
|
|
148
149
|
* Removes a file from the PHP filesystem.
|
|
@@ -151,8 +152,8 @@ class FSHelpers {
|
|
|
151
152
|
* @param FS
|
|
152
153
|
* @param path - The file path to remove.
|
|
153
154
|
*/
|
|
154
|
-
static unlink(e,
|
|
155
|
-
e.unlink(
|
|
155
|
+
static unlink(e, t) {
|
|
156
|
+
e.unlink(t);
|
|
156
157
|
}
|
|
157
158
|
/**
|
|
158
159
|
* Moves a file or directory in the PHP filesystem to a
|
|
@@ -162,14 +163,14 @@ class FSHelpers {
|
|
|
162
163
|
* @param fromPath The path to rename.
|
|
163
164
|
* @param toPath The new path.
|
|
164
165
|
*/
|
|
165
|
-
static mv(e,
|
|
166
|
+
static mv(e, t, s) {
|
|
166
167
|
try {
|
|
167
|
-
const i = e.lookupPath(
|
|
168
|
-
i.mountpoint !==
|
|
168
|
+
const i = e.lookupPath(t).node.mount, n = FSHelpers.fileExists(e, s) ? e.lookupPath(s).node.mount : e.lookupPath(dirname(s)).node.mount;
|
|
169
|
+
i.mountpoint !== n.mountpoint ? (FSHelpers.copyRecursive(e, t, s), FSHelpers.isDir(e, t) ? FSHelpers.rmdir(e, t, { recursive: !0 }) : e.unlink(t)) : e.rename(t, s);
|
|
169
170
|
} catch (i) {
|
|
170
|
-
const
|
|
171
|
-
throw
|
|
172
|
-
`Could not move ${
|
|
171
|
+
const n = getEmscriptenFsError(i);
|
|
172
|
+
throw n ? new Error(
|
|
173
|
+
`Could not move ${t} to ${s}: ${n}`,
|
|
173
174
|
{
|
|
174
175
|
cause: i
|
|
175
176
|
}
|
|
@@ -183,11 +184,11 @@ class FSHelpers {
|
|
|
183
184
|
* @param path The directory path to remove.
|
|
184
185
|
* @param options Options for the removal.
|
|
185
186
|
*/
|
|
186
|
-
static rmdir(e,
|
|
187
|
-
s != null && s.recursive && FSHelpers.listFiles(e,
|
|
188
|
-
const
|
|
189
|
-
FSHelpers.isDir(e,
|
|
190
|
-
}), e.rmdir(
|
|
187
|
+
static rmdir(e, t, s = { recursive: !0 }) {
|
|
188
|
+
s != null && s.recursive && FSHelpers.listFiles(e, t).forEach((i) => {
|
|
189
|
+
const n = `${t}/${i}`;
|
|
190
|
+
FSHelpers.isDir(e, n) ? FSHelpers.rmdir(e, n, s) : FSHelpers.unlink(e, n);
|
|
191
|
+
}), e.getPath(e.lookupPath(t).node) === e.cwd() && e.chdir(joinPaths(e.cwd(), "..")), e.rmdir(t);
|
|
191
192
|
}
|
|
192
193
|
/**
|
|
193
194
|
* Lists the files and directories in the given directory.
|
|
@@ -197,20 +198,20 @@ class FSHelpers {
|
|
|
197
198
|
* @param options - Options for the listing.
|
|
198
199
|
* @returns The list of files and directories in the given directory.
|
|
199
200
|
*/
|
|
200
|
-
static listFiles(e,
|
|
201
|
-
if (!FSHelpers.fileExists(e,
|
|
201
|
+
static listFiles(e, t, s = { prependPath: !1 }) {
|
|
202
|
+
if (!FSHelpers.fileExists(e, t))
|
|
202
203
|
return [];
|
|
203
204
|
try {
|
|
204
|
-
const i = e.readdir(
|
|
205
|
-
(
|
|
205
|
+
const i = e.readdir(t).filter(
|
|
206
|
+
(n) => n !== "." && n !== ".."
|
|
206
207
|
);
|
|
207
208
|
if (s.prependPath) {
|
|
208
|
-
const
|
|
209
|
-
return i.map((
|
|
209
|
+
const n = t.replace(/\/$/, "");
|
|
210
|
+
return i.map((o) => `${n}/${o}`);
|
|
210
211
|
}
|
|
211
212
|
return i;
|
|
212
213
|
} catch (i) {
|
|
213
|
-
return logger.error(i, { path:
|
|
214
|
+
return logger.error(i, { path: t }), [];
|
|
214
215
|
}
|
|
215
216
|
}
|
|
216
217
|
/**
|
|
@@ -220,8 +221,8 @@ class FSHelpers {
|
|
|
220
221
|
* @param path – The path to check.
|
|
221
222
|
* @returns True if the path is a directory, false otherwise.
|
|
222
223
|
*/
|
|
223
|
-
static isDir(e,
|
|
224
|
-
return FSHelpers.fileExists(e,
|
|
224
|
+
static isDir(e, t) {
|
|
225
|
+
return FSHelpers.fileExists(e, t) ? e.isDir(e.lookupPath(t, { follow: !0 }).node.mode) : !1;
|
|
225
226
|
}
|
|
226
227
|
/**
|
|
227
228
|
* Checks if a file exists in the PHP filesystem.
|
|
@@ -230,8 +231,8 @@ class FSHelpers {
|
|
|
230
231
|
* @param path – The path to check.
|
|
231
232
|
* @returns True if the path is a file, false otherwise.
|
|
232
233
|
*/
|
|
233
|
-
static isFile(e,
|
|
234
|
-
return FSHelpers.fileExists(e,
|
|
234
|
+
static isFile(e, t) {
|
|
235
|
+
return FSHelpers.fileExists(e, t) ? e.isFile(e.lookupPath(t, { follow: !0 }).node.mode) : !1;
|
|
235
236
|
}
|
|
236
237
|
/**
|
|
237
238
|
* Creates a symlink in the PHP filesystem.
|
|
@@ -240,8 +241,8 @@ class FSHelpers {
|
|
|
240
241
|
* @param target
|
|
241
242
|
* @param link
|
|
242
243
|
*/
|
|
243
|
-
static symlink(e,
|
|
244
|
-
return e.symlink(
|
|
244
|
+
static symlink(e, t, s) {
|
|
245
|
+
return e.symlink(t, s);
|
|
245
246
|
}
|
|
246
247
|
/**
|
|
247
248
|
* Checks if a path is a symlink in the PHP filesystem.
|
|
@@ -250,8 +251,8 @@ class FSHelpers {
|
|
|
250
251
|
* @param path
|
|
251
252
|
* @returns True if the path is a symlink, false otherwise.
|
|
252
253
|
*/
|
|
253
|
-
static isSymlink(e,
|
|
254
|
-
return FSHelpers.fileExists(e,
|
|
254
|
+
static isSymlink(e, t) {
|
|
255
|
+
return FSHelpers.fileExists(e, t) ? e.isLink(e.lookupPath(t).node.mode) : !1;
|
|
255
256
|
}
|
|
256
257
|
/**
|
|
257
258
|
* Reads the target of a symlink in the PHP filesystem.
|
|
@@ -260,8 +261,8 @@ class FSHelpers {
|
|
|
260
261
|
* @returns The target of the symlink.
|
|
261
262
|
* @throws {@link @php-wasm/universal:ErrnoError} – If the path is not a symlink.
|
|
262
263
|
*/
|
|
263
|
-
static readlink(e,
|
|
264
|
-
return e.readlink(
|
|
264
|
+
static readlink(e, t) {
|
|
265
|
+
return e.readlink(t);
|
|
265
266
|
}
|
|
266
267
|
/**
|
|
267
268
|
* Gets the real path of a file in the PHP filesystem.
|
|
@@ -270,8 +271,8 @@ class FSHelpers {
|
|
|
270
271
|
*
|
|
271
272
|
* @returns The real path of the file.
|
|
272
273
|
*/
|
|
273
|
-
static realpath(e,
|
|
274
|
-
return e.lookupPath(
|
|
274
|
+
static realpath(e, t) {
|
|
275
|
+
return e.lookupPath(t, { follow: !0 }).path;
|
|
275
276
|
}
|
|
276
277
|
/**
|
|
277
278
|
* Checks if a file (or a directory) exists in the PHP filesystem.
|
|
@@ -280,9 +281,9 @@ class FSHelpers {
|
|
|
280
281
|
* @param path - The file path to check.
|
|
281
282
|
* @returns True if the file exists, false otherwise.
|
|
282
283
|
*/
|
|
283
|
-
static fileExists(e,
|
|
284
|
+
static fileExists(e, t) {
|
|
284
285
|
try {
|
|
285
|
-
return e.lookupPath(
|
|
286
|
+
return e.lookupPath(t), !0;
|
|
286
287
|
} catch {
|
|
287
288
|
return !1;
|
|
288
289
|
}
|
|
@@ -295,24 +296,24 @@ class FSHelpers {
|
|
|
295
296
|
* @param FS
|
|
296
297
|
* @param path - The directory path to create.
|
|
297
298
|
*/
|
|
298
|
-
static mkdir(e,
|
|
299
|
-
e.mkdirTree(
|
|
299
|
+
static mkdir(e, t) {
|
|
300
|
+
e.mkdirTree(t);
|
|
300
301
|
}
|
|
301
|
-
static copyRecursive(e,
|
|
302
|
-
const i = e.lookupPath(
|
|
302
|
+
static copyRecursive(e, t, s) {
|
|
303
|
+
const i = e.lookupPath(t).node;
|
|
303
304
|
if (e.isDir(i.mode)) {
|
|
304
305
|
e.mkdirTree(s);
|
|
305
|
-
const
|
|
306
|
-
(
|
|
306
|
+
const n = e.readdir(t).filter(
|
|
307
|
+
(o) => o !== "." && o !== ".."
|
|
307
308
|
);
|
|
308
|
-
for (const
|
|
309
|
+
for (const o of n)
|
|
309
310
|
FSHelpers.copyRecursive(
|
|
310
311
|
e,
|
|
311
|
-
joinPaths(
|
|
312
|
-
joinPaths(s,
|
|
312
|
+
joinPaths(t, o),
|
|
313
|
+
joinPaths(s, o)
|
|
313
314
|
);
|
|
314
315
|
} else
|
|
315
|
-
e.writeFile(s, e.readFile(
|
|
316
|
+
e.writeFile(s, e.readFile(t));
|
|
316
317
|
}
|
|
317
318
|
}
|
|
318
319
|
FSHelpers.readFileAsText = rethrowFileSystemError('Could not read "{path}"')(
|
|
@@ -354,9 +355,9 @@ FSHelpers.copyRecursive = rethrowFileSystemError(
|
|
|
354
355
|
const _private = /* @__PURE__ */ new WeakMap();
|
|
355
356
|
class PHPWorker {
|
|
356
357
|
/** @inheritDoc */
|
|
357
|
-
constructor(e,
|
|
358
|
+
constructor(e, t) {
|
|
358
359
|
this.absoluteUrl = "", this.documentRoot = "", _private.set(this, {
|
|
359
|
-
monitor:
|
|
360
|
+
monitor: t
|
|
360
361
|
}), e && this.__internal_setRequestHandler(e);
|
|
361
362
|
}
|
|
362
363
|
__internal_setRequestHandler(e) {
|
|
@@ -393,16 +394,16 @@ class PHPWorker {
|
|
|
393
394
|
* The onDownloadProgress event listener.
|
|
394
395
|
*/
|
|
395
396
|
async onDownloadProgress(e) {
|
|
396
|
-
var
|
|
397
|
-
return (
|
|
397
|
+
var t;
|
|
398
|
+
return (t = _private.get(this).monitor) == null ? void 0 : t.addEventListener("progress", e);
|
|
398
399
|
}
|
|
399
400
|
/** @inheritDoc @php-wasm/universal!PHP.mv */
|
|
400
|
-
async mv(e,
|
|
401
|
-
return _private.get(this).php.mv(e,
|
|
401
|
+
async mv(e, t) {
|
|
402
|
+
return _private.get(this).php.mv(e, t);
|
|
402
403
|
}
|
|
403
404
|
/** @inheritDoc @php-wasm/universal!PHP.rmdir */
|
|
404
|
-
async rmdir(e,
|
|
405
|
-
return _private.get(this).php.rmdir(e,
|
|
405
|
+
async rmdir(e, t) {
|
|
406
|
+
return _private.get(this).php.rmdir(e, t);
|
|
406
407
|
}
|
|
407
408
|
/** @inheritDoc @php-wasm/universal!PHPRequestHandler.request */
|
|
408
409
|
async request(e) {
|
|
@@ -410,9 +411,9 @@ class PHPWorker {
|
|
|
410
411
|
}
|
|
411
412
|
/** @inheritDoc @php-wasm/universal!/PHP.run */
|
|
412
413
|
async run(e) {
|
|
413
|
-
const { php:
|
|
414
|
+
const { php: t, reap: s } = await _private.get(this).requestHandler.processManager.acquirePHPInstance();
|
|
414
415
|
try {
|
|
415
|
-
return await
|
|
416
|
+
return await t.run(e);
|
|
416
417
|
} finally {
|
|
417
418
|
s();
|
|
418
419
|
}
|
|
@@ -442,16 +443,16 @@ class PHPWorker {
|
|
|
442
443
|
return _private.get(this).php.readFileAsBuffer(e);
|
|
443
444
|
}
|
|
444
445
|
/** @inheritDoc @php-wasm/universal!/PHP.writeFile */
|
|
445
|
-
writeFile(e,
|
|
446
|
-
return _private.get(this).php.writeFile(e,
|
|
446
|
+
writeFile(e, t) {
|
|
447
|
+
return _private.get(this).php.writeFile(e, t);
|
|
447
448
|
}
|
|
448
449
|
/** @inheritDoc @php-wasm/universal!/PHP.unlink */
|
|
449
450
|
unlink(e) {
|
|
450
451
|
return _private.get(this).php.unlink(e);
|
|
451
452
|
}
|
|
452
453
|
/** @inheritDoc @php-wasm/universal!/PHP.listFiles */
|
|
453
|
-
listFiles(e,
|
|
454
|
-
return _private.get(this).php.listFiles(e,
|
|
454
|
+
listFiles(e, t) {
|
|
455
|
+
return _private.get(this).php.listFiles(e, t);
|
|
455
456
|
}
|
|
456
457
|
/** @inheritDoc @php-wasm/universal!/PHP.isDir */
|
|
457
458
|
isDir(e) {
|
|
@@ -470,16 +471,20 @@ class PHPWorker {
|
|
|
470
471
|
return _private.get(this).php.onMessage(e);
|
|
471
472
|
}
|
|
472
473
|
/** @inheritDoc @php-wasm/universal!/PHP.defineConstant */
|
|
473
|
-
defineConstant(e,
|
|
474
|
-
_private.get(this).php.defineConstant(e,
|
|
474
|
+
defineConstant(e, t) {
|
|
475
|
+
_private.get(this).php.defineConstant(e, t);
|
|
475
476
|
}
|
|
476
477
|
/** @inheritDoc @php-wasm/universal!/PHP.addEventListener */
|
|
477
|
-
addEventListener(e,
|
|
478
|
-
_private.get(this).php.addEventListener(e,
|
|
478
|
+
addEventListener(e, t) {
|
|
479
|
+
_private.get(this).php.addEventListener(e, t);
|
|
479
480
|
}
|
|
480
481
|
/** @inheritDoc @php-wasm/universal!/PHP.removeEventListener */
|
|
481
|
-
removeEventListener(e,
|
|
482
|
-
_private.get(this).php.removeEventListener(e,
|
|
482
|
+
removeEventListener(e, t) {
|
|
483
|
+
_private.get(this).php.removeEventListener(e, t);
|
|
484
|
+
}
|
|
485
|
+
async [Symbol.asyncDispose]() {
|
|
486
|
+
var e;
|
|
487
|
+
await ((e = _private.get(this).requestHandler) == null ? void 0 : e[Symbol.asyncDispose]());
|
|
483
488
|
}
|
|
484
489
|
}
|
|
485
490
|
const responseTexts = {
|
|
@@ -497,16 +502,107 @@ const responseTexts = {
|
|
|
497
502
|
201: "Created",
|
|
498
503
|
200: "OK"
|
|
499
504
|
};
|
|
505
|
+
class StreamedPHPResponse {
|
|
506
|
+
constructor(e, t, s, i) {
|
|
507
|
+
this.parsedHeaders = null, this.cachedStdoutText = null, this.cachedStderrText = null, this.headersStream = e, this.stdout = t, this.stderr = s, this.exitCode = i;
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* True if the response is successful (HTTP status code 200-399),
|
|
511
|
+
* false otherwise.
|
|
512
|
+
*/
|
|
513
|
+
async ok() {
|
|
514
|
+
try {
|
|
515
|
+
const e = await this.httpStatusCode;
|
|
516
|
+
return e >= 200 && e < 400;
|
|
517
|
+
} catch {
|
|
518
|
+
return !1;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* Resolves when the response has finished processing – either successfully or not.
|
|
523
|
+
*/
|
|
524
|
+
get finished() {
|
|
525
|
+
return Promise.allSettled([this.exitCode.finally(() => {
|
|
526
|
+
})]).then(
|
|
527
|
+
() => {
|
|
528
|
+
}
|
|
529
|
+
);
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Resolves once HTTP headers are available.
|
|
533
|
+
*/
|
|
534
|
+
get headers() {
|
|
535
|
+
return this.getParsedHeaders().then((e) => e.headers);
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* Resolves once HTTP status code is available.
|
|
539
|
+
*/
|
|
540
|
+
get httpStatusCode() {
|
|
541
|
+
return Promise.race([
|
|
542
|
+
this.getParsedHeaders().then((e) => e.httpStatusCode),
|
|
543
|
+
this.exitCode.then(
|
|
544
|
+
(e) => e !== 0 ? 500 : void 0
|
|
545
|
+
)
|
|
546
|
+
]).then((e) => e !== void 0 ? e : this.getParsedHeaders().then(
|
|
547
|
+
(t) => t.httpStatusCode,
|
|
548
|
+
() => 200
|
|
549
|
+
)).catch(() => 500);
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Exposes the stdout bytes as they're produced by the PHP instance
|
|
553
|
+
*/
|
|
554
|
+
get stdoutText() {
|
|
555
|
+
return this.cachedStdoutText || (this.cachedStdoutText = streamToText(this.stdout)), this.cachedStdoutText;
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* Exposes the stderr bytes as they're produced by the PHP instance
|
|
559
|
+
*/
|
|
560
|
+
get stderrText() {
|
|
561
|
+
return this.cachedStderrText || (this.cachedStderrText = streamToText(this.stderr)), this.cachedStderrText;
|
|
562
|
+
}
|
|
563
|
+
async getParsedHeaders() {
|
|
564
|
+
return this.parsedHeaders || (this.parsedHeaders = parseHeadersStream(this.headersStream)), await this.parsedHeaders;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
async function parseHeadersStream(r) {
|
|
568
|
+
const e = await streamToText(r);
|
|
569
|
+
let t;
|
|
570
|
+
try {
|
|
571
|
+
t = JSON.parse(e);
|
|
572
|
+
} catch {
|
|
573
|
+
return { headers: {}, httpStatusCode: 200 };
|
|
574
|
+
}
|
|
575
|
+
const s = {};
|
|
576
|
+
for (const i of t.headers) {
|
|
577
|
+
if (!i.includes(": "))
|
|
578
|
+
continue;
|
|
579
|
+
const n = i.indexOf(": "), o = i.substring(0, n).toLowerCase(), a = i.substring(n + 2);
|
|
580
|
+
o in s || (s[o] = []), s[o].push(a);
|
|
581
|
+
}
|
|
582
|
+
return {
|
|
583
|
+
headers: s,
|
|
584
|
+
httpStatusCode: t.status
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
async function streamToText(r) {
|
|
588
|
+
const e = r.pipeThrough(new TextDecoderStream()).getReader(), t = [];
|
|
589
|
+
for (; ; ) {
|
|
590
|
+
const { done: s, value: i } = await e.read();
|
|
591
|
+
if (s)
|
|
592
|
+
return t.join("");
|
|
593
|
+
i && t.push(i);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
500
596
|
class PHPResponse {
|
|
501
|
-
constructor(e,
|
|
502
|
-
this.httpStatusCode = e, this.headers =
|
|
597
|
+
constructor(e, t, s, i = "", n = 0) {
|
|
598
|
+
this.httpStatusCode = e, this.headers = t, this.bytes = s, this.exitCode = n, this.errors = i;
|
|
503
599
|
}
|
|
504
|
-
static forHttpCode(e,
|
|
600
|
+
static forHttpCode(e, t = "") {
|
|
505
601
|
return new PHPResponse(
|
|
506
602
|
e,
|
|
507
603
|
{},
|
|
508
604
|
new TextEncoder().encode(
|
|
509
|
-
|
|
605
|
+
t || responseTexts[e] || ""
|
|
510
606
|
)
|
|
511
607
|
);
|
|
512
608
|
}
|
|
@@ -519,6 +615,15 @@ class PHPResponse {
|
|
|
519
615
|
e.exitCode
|
|
520
616
|
);
|
|
521
617
|
}
|
|
618
|
+
static async fromStreamedResponse(e) {
|
|
619
|
+
return await e.finished, new PHPResponse(
|
|
620
|
+
await e.httpStatusCode,
|
|
621
|
+
await e.headers,
|
|
622
|
+
new TextEncoder().encode(await e.stdoutText),
|
|
623
|
+
await e.stderrText,
|
|
624
|
+
await e.exitCode
|
|
625
|
+
);
|
|
626
|
+
}
|
|
522
627
|
toRawData() {
|
|
523
628
|
return {
|
|
524
629
|
headers: this.headers,
|
|
@@ -543,39 +648,39 @@ class PHPResponse {
|
|
|
543
648
|
}
|
|
544
649
|
const RuntimeId = Symbol("RuntimeId"), loadedRuntimes = /* @__PURE__ */ new Map();
|
|
545
650
|
let lastRuntimeId = 0;
|
|
546
|
-
async function loadPHPRuntime(
|
|
547
|
-
const
|
|
548
|
-
onAbort(
|
|
549
|
-
|
|
651
|
+
async function loadPHPRuntime(r, ...e) {
|
|
652
|
+
const t = Object.assign({}, ...e), [s, i, n] = makePromise(), o = r.init(currentJsRuntime, {
|
|
653
|
+
onAbort(l) {
|
|
654
|
+
n(l), logger.error(l);
|
|
550
655
|
},
|
|
551
656
|
ENV: {},
|
|
552
657
|
// Emscripten sometimes prepends a '/' to the path, which
|
|
553
658
|
// breaks vite dev mode. An identity `locateFile` function
|
|
554
659
|
// fixes it.
|
|
555
|
-
locateFile: (
|
|
556
|
-
...
|
|
660
|
+
locateFile: (l) => l,
|
|
661
|
+
...t,
|
|
557
662
|
noInitialRun: !0,
|
|
558
663
|
onRuntimeInitialized() {
|
|
559
|
-
|
|
664
|
+
t.onRuntimeInitialized && t.onRuntimeInitialized(o), i();
|
|
560
665
|
}
|
|
561
666
|
});
|
|
562
667
|
await s;
|
|
563
|
-
const
|
|
564
|
-
return
|
|
565
|
-
return
|
|
566
|
-
},
|
|
668
|
+
const a = ++lastRuntimeId;
|
|
669
|
+
return o.FS, o.id = a, o.originalExit = o._exit, o._exit = function(l) {
|
|
670
|
+
return o.outboundNetworkProxyServer && (o.outboundNetworkProxyServer.close(), o.outboundNetworkProxyServer.closeAllConnections()), loadedRuntimes.delete(a), o.originalExit(l);
|
|
671
|
+
}, o[RuntimeId] = a, loadedRuntimes.set(a, o), a;
|
|
567
672
|
}
|
|
568
|
-
function getLoadedRuntime(
|
|
569
|
-
return loadedRuntimes.get(
|
|
673
|
+
function getLoadedRuntime(r) {
|
|
674
|
+
return loadedRuntimes.get(r);
|
|
570
675
|
}
|
|
571
676
|
const currentJsRuntime = function() {
|
|
572
|
-
var
|
|
573
|
-
return typeof process < "u" && ((
|
|
677
|
+
var r;
|
|
678
|
+
return typeof process < "u" && ((r = process.release) == null ? void 0 : r.name) === "node" ? "NODE" : typeof window < "u" ? "WEB" : typeof WorkerGlobalScope < "u" && self instanceof WorkerGlobalScope ? "WORKER" : "NODE";
|
|
574
679
|
}(), makePromise = () => {
|
|
575
|
-
const
|
|
576
|
-
|
|
680
|
+
const r = [], e = new Promise((t, s) => {
|
|
681
|
+
r.push(t, s);
|
|
577
682
|
});
|
|
578
|
-
return
|
|
683
|
+
return r.unshift(e), r;
|
|
579
684
|
};
|
|
580
685
|
var _a;
|
|
581
686
|
const kError = Symbol("error"), kMessage = Symbol("message");
|
|
@@ -587,8 +692,8 @@ class ErrorEvent2 extends (_a = Event, _a) {
|
|
|
587
692
|
* @param options A dictionary object that allows for setting
|
|
588
693
|
* attributes via object members of the same name.
|
|
589
694
|
*/
|
|
590
|
-
constructor(e,
|
|
591
|
-
super(e), this[kError] =
|
|
695
|
+
constructor(e, t = {}) {
|
|
696
|
+
super(e), this[kError] = t.error === void 0 ? null : t.error, this[kMessage] = t.message === void 0 ? "" : t.message;
|
|
592
697
|
}
|
|
593
698
|
get error() {
|
|
594
699
|
return this[kError];
|
|
@@ -600,49 +705,56 @@ class ErrorEvent2 extends (_a = Event, _a) {
|
|
|
600
705
|
Object.defineProperty(ErrorEvent2.prototype, "error", { enumerable: !0 });
|
|
601
706
|
Object.defineProperty(ErrorEvent2.prototype, "message", { enumerable: !0 });
|
|
602
707
|
const ErrorEvent = typeof globalThis.ErrorEvent == "function" ? globalThis.ErrorEvent : ErrorEvent2;
|
|
603
|
-
function
|
|
604
|
-
return
|
|
708
|
+
function isExitCode(r) {
|
|
709
|
+
return r instanceof Error ? "exitCode" in r || (r == null ? void 0 : r.name) === "ExitStatus" && "status" in r : !1;
|
|
605
710
|
}
|
|
606
711
|
class UnhandledRejectionsTarget extends EventTarget {
|
|
607
712
|
constructor() {
|
|
608
713
|
super(...arguments), this.listenersCount = 0;
|
|
609
714
|
}
|
|
610
|
-
addEventListener(e,
|
|
611
|
-
++this.listenersCount, super.addEventListener(
|
|
715
|
+
addEventListener(e, t, s) {
|
|
716
|
+
++this.listenersCount, super.addEventListener(
|
|
717
|
+
e,
|
|
718
|
+
t,
|
|
719
|
+
s
|
|
720
|
+
);
|
|
612
721
|
}
|
|
613
|
-
removeEventListener(e,
|
|
614
|
-
--this.listenersCount, super.removeEventListener(
|
|
722
|
+
removeEventListener(e, t, s) {
|
|
723
|
+
--this.listenersCount, super.removeEventListener(
|
|
724
|
+
e,
|
|
725
|
+
t,
|
|
726
|
+
s
|
|
727
|
+
);
|
|
615
728
|
}
|
|
616
729
|
hasListeners() {
|
|
617
730
|
return this.listenersCount > 0;
|
|
618
731
|
}
|
|
619
732
|
}
|
|
620
|
-
function improveWASMErrorReporting(
|
|
733
|
+
function improveWASMErrorReporting(r) {
|
|
621
734
|
const e = new UnhandledRejectionsTarget();
|
|
622
|
-
for (const
|
|
623
|
-
if (typeof
|
|
624
|
-
const s =
|
|
625
|
-
|
|
626
|
-
var
|
|
735
|
+
for (const t in r.wasmExports)
|
|
736
|
+
if (typeof r.wasmExports[t] == "function") {
|
|
737
|
+
const s = r.wasmExports[t];
|
|
738
|
+
r.wasmExports[t] = function(...i) {
|
|
739
|
+
var n;
|
|
627
740
|
try {
|
|
628
741
|
return s(...i);
|
|
629
|
-
} catch (
|
|
630
|
-
if (!(
|
|
631
|
-
throw
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
742
|
+
} catch (o) {
|
|
743
|
+
if (!(o instanceof Error))
|
|
744
|
+
throw o;
|
|
745
|
+
r.lastAsyncifyStackSource && (o.cause = r.lastAsyncifyStackSource);
|
|
746
|
+
const a = clarifyErrorMessage(
|
|
747
|
+
o,
|
|
748
|
+
(n = r.lastAsyncifyStackSource) == null ? void 0 : n.stack
|
|
635
749
|
);
|
|
636
|
-
if (
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
);
|
|
643
|
-
return;
|
|
750
|
+
if (e.hasListeners()) {
|
|
751
|
+
const l = new ErrorEvent("error", {
|
|
752
|
+
error: o,
|
|
753
|
+
message: a
|
|
754
|
+
});
|
|
755
|
+
throw e.dispatchEvent(l), o;
|
|
644
756
|
}
|
|
645
|
-
throw
|
|
757
|
+
throw (!isExitCode(o) || o.exitCode !== 0) && showCriticalErrorBox(a), o;
|
|
646
758
|
}
|
|
647
759
|
};
|
|
648
760
|
}
|
|
@@ -652,23 +764,33 @@ let functionsMaybeMissingFromAsyncify = [];
|
|
|
652
764
|
function getFunctionsMaybeMissingFromAsyncify() {
|
|
653
765
|
return functionsMaybeMissingFromAsyncify;
|
|
654
766
|
}
|
|
655
|
-
function clarifyErrorMessage(
|
|
656
|
-
if (
|
|
657
|
-
let
|
|
658
|
-
e || (
|
|
767
|
+
function clarifyErrorMessage(r, e) {
|
|
768
|
+
if (r.message === "unreachable") {
|
|
769
|
+
let t = UNREACHABLE_ERROR;
|
|
770
|
+
e || (t += `
|
|
659
771
|
|
|
660
772
|
This stack trace is lacking. For a better one initialize
|
|
661
773
|
the PHP runtime with { debug: true }, e.g. PHPNode.load('8.1', { debug: true }).
|
|
662
774
|
|
|
663
|
-
`)
|
|
664
|
-
|
|
775
|
+
`);
|
|
776
|
+
const s = new Set(
|
|
777
|
+
extractPHPFunctionsFromStack(e || "")
|
|
665
778
|
);
|
|
666
|
-
|
|
667
|
-
|
|
779
|
+
let i = r;
|
|
780
|
+
do {
|
|
781
|
+
for (const n of extractPHPFunctionsFromStack(
|
|
782
|
+
i.stack || ""
|
|
783
|
+
))
|
|
784
|
+
s.add(n);
|
|
785
|
+
i = i.cause;
|
|
786
|
+
} while (i);
|
|
787
|
+
functionsMaybeMissingFromAsyncify = Array.from(s);
|
|
788
|
+
for (const n of s)
|
|
789
|
+
t += ` * ${n}
|
|
668
790
|
`;
|
|
669
|
-
return
|
|
791
|
+
return t;
|
|
670
792
|
}
|
|
671
|
-
return
|
|
793
|
+
return r.message;
|
|
672
794
|
}
|
|
673
795
|
const UNREACHABLE_ERROR = `
|
|
674
796
|
"unreachable" WASM instruction executed.
|
|
@@ -696,29 +818,29 @@ CLI option:
|
|
|
696
818
|
|
|
697
819
|
`, redBg = "\x1B[41m", bold = "\x1B[1m", reset = "\x1B[0m", eol = "\x1B[K";
|
|
698
820
|
let logged = !1;
|
|
699
|
-
function showCriticalErrorBox(
|
|
700
|
-
if (!logged && (logged = !0, !(
|
|
821
|
+
function showCriticalErrorBox(r) {
|
|
822
|
+
if (!logged && (logged = !0, !(r != null && r.trim().startsWith("Program terminated with exit")))) {
|
|
701
823
|
logger.log(`${redBg}
|
|
702
824
|
${eol}
|
|
703
825
|
${bold} WASM ERROR${reset}${redBg}`);
|
|
704
|
-
for (const e of
|
|
826
|
+
for (const e of r.split(`
|
|
705
827
|
`))
|
|
706
828
|
logger.log(`${eol} ${e} `);
|
|
707
829
|
logger.log(`${reset}`);
|
|
708
830
|
}
|
|
709
831
|
}
|
|
710
|
-
function extractPHPFunctionsFromStack(
|
|
832
|
+
function extractPHPFunctionsFromStack(r) {
|
|
711
833
|
try {
|
|
712
|
-
const e =
|
|
713
|
-
`).slice(1).map((
|
|
714
|
-
const s =
|
|
834
|
+
const e = r.split(`
|
|
835
|
+
`).slice(1).map((t) => {
|
|
836
|
+
const s = t.trim().substring(3).split(" ");
|
|
715
837
|
return {
|
|
716
838
|
fn: s.length >= 2 ? s[0] : "<unknown>",
|
|
717
|
-
isWasm:
|
|
839
|
+
isWasm: t.includes("wasm:/")
|
|
718
840
|
};
|
|
719
841
|
}).filter(
|
|
720
|
-
({ fn:
|
|
721
|
-
).map(({ fn:
|
|
842
|
+
({ fn: t, isWasm: s }) => s && !t.startsWith("dynCall_") && !t.startsWith("invoke_")
|
|
843
|
+
).map(({ fn: t }) => t);
|
|
722
844
|
return Array.from(new Set(e));
|
|
723
845
|
} catch {
|
|
724
846
|
return [];
|
|
@@ -726,12 +848,12 @@ function extractPHPFunctionsFromStack(t) {
|
|
|
726
848
|
}
|
|
727
849
|
const STRING = "string", NUMBER = "number", __private__dont__use = Symbol("__private__dont__use");
|
|
728
850
|
class PHPExecutionFailureError extends Error {
|
|
729
|
-
constructor(e,
|
|
730
|
-
super(e), this.response =
|
|
851
|
+
constructor(e, t, s) {
|
|
852
|
+
super(e), this.response = t, this.source = s;
|
|
731
853
|
}
|
|
732
854
|
}
|
|
733
855
|
const PHP_INI_PATH = "/internal/shared/php.ini", AUTO_PREPEND_SCRIPT = "/internal/shared/auto_prepend_file.php";
|
|
734
|
-
var
|
|
856
|
+
var T, _, H, P, R, k, u, z, L, W, G, V, J, Y, K, X, $, Q, B, D;
|
|
735
857
|
class PHP {
|
|
736
858
|
/**
|
|
737
859
|
* Initializes a PHP runtime.
|
|
@@ -740,38 +862,38 @@ class PHP {
|
|
|
740
862
|
* @param PHPRuntime - Optional. PHP Runtime ID as initialized by loadPHPRuntime.
|
|
741
863
|
* @param requestHandlerOptions - Optional. Options for the PHPRequestHandler. If undefined, no request handler will be initialized.
|
|
742
864
|
*/
|
|
743
|
-
constructor(
|
|
865
|
+
constructor(r) {
|
|
744
866
|
h(this, u);
|
|
745
|
-
h(this,
|
|
746
|
-
h(this,
|
|
747
|
-
h(this,
|
|
748
|
-
h(this,
|
|
749
|
-
h(this,
|
|
750
|
-
h(this,
|
|
751
|
-
this.semaphore = new Semaphore({ concurrency: 1 }),
|
|
867
|
+
h(this, T);
|
|
868
|
+
h(this, _, !1);
|
|
869
|
+
h(this, H, null);
|
|
870
|
+
h(this, P, /* @__PURE__ */ new Map());
|
|
871
|
+
h(this, R, []);
|
|
872
|
+
h(this, k, {});
|
|
873
|
+
this.semaphore = new Semaphore({ concurrency: 1 }), r !== void 0 && this.initializeRuntime(r);
|
|
752
874
|
}
|
|
753
875
|
/**
|
|
754
876
|
* Adds an event listener for a PHP event.
|
|
755
877
|
* @param eventType - The type of event to listen for.
|
|
756
878
|
* @param listener - The listener function to be called when the event is triggered.
|
|
757
879
|
*/
|
|
758
|
-
addEventListener(
|
|
759
|
-
c(this,
|
|
880
|
+
addEventListener(r, e) {
|
|
881
|
+
c(this, P).has(r) || c(this, P).set(r, /* @__PURE__ */ new Set()), c(this, P).get(r).add(e);
|
|
760
882
|
}
|
|
761
883
|
/**
|
|
762
884
|
* Removes an event listener for a PHP event.
|
|
763
885
|
* @param eventType - The type of event to remove the listener from.
|
|
764
886
|
* @param listener - The listener function to be removed.
|
|
765
887
|
*/
|
|
766
|
-
removeEventListener(
|
|
767
|
-
var
|
|
768
|
-
(
|
|
888
|
+
removeEventListener(r, e) {
|
|
889
|
+
var t;
|
|
890
|
+
(t = c(this, P).get(r)) == null || t.delete(e);
|
|
769
891
|
}
|
|
770
|
-
dispatchEvent(
|
|
771
|
-
const e = c(this,
|
|
892
|
+
dispatchEvent(r) {
|
|
893
|
+
const e = c(this, P).get(r.type);
|
|
772
894
|
if (e)
|
|
773
|
-
for (const
|
|
774
|
-
r
|
|
895
|
+
for (const t of e)
|
|
896
|
+
t(r);
|
|
775
897
|
}
|
|
776
898
|
/**
|
|
777
899
|
* Listens to message sent by the PHP code.
|
|
@@ -812,10 +934,10 @@ class PHP {
|
|
|
812
934
|
*
|
|
813
935
|
* @param listener Callback function to handle the message.
|
|
814
936
|
*/
|
|
815
|
-
onMessage(
|
|
816
|
-
return c(this,
|
|
817
|
-
|
|
818
|
-
(e) => e !==
|
|
937
|
+
onMessage(r) {
|
|
938
|
+
return c(this, R).push(r), async () => {
|
|
939
|
+
f(this, R, c(this, R).filter(
|
|
940
|
+
(e) => e !== r
|
|
819
941
|
));
|
|
820
942
|
};
|
|
821
943
|
}
|
|
@@ -831,17 +953,17 @@ class PHP {
|
|
|
831
953
|
return this.requestHandler.documentRoot;
|
|
832
954
|
}
|
|
833
955
|
/** @deprecated Use PHPRequestHandler instead. */
|
|
834
|
-
pathToInternalUrl(
|
|
835
|
-
return this.requestHandler.pathToInternalUrl(
|
|
956
|
+
pathToInternalUrl(r) {
|
|
957
|
+
return this.requestHandler.pathToInternalUrl(r);
|
|
836
958
|
}
|
|
837
959
|
/** @deprecated Use PHPRequestHandler instead. */
|
|
838
|
-
internalUrlToPath(
|
|
839
|
-
return this.requestHandler.internalUrlToPath(
|
|
960
|
+
internalUrlToPath(r) {
|
|
961
|
+
return this.requestHandler.internalUrlToPath(r);
|
|
840
962
|
}
|
|
841
|
-
initializeRuntime(
|
|
963
|
+
initializeRuntime(r) {
|
|
842
964
|
if (this[__private__dont__use])
|
|
843
965
|
throw new Error("PHP runtime already initialized.");
|
|
844
|
-
const e = getLoadedRuntime(
|
|
966
|
+
const e = getLoadedRuntime(r);
|
|
845
967
|
if (!e)
|
|
846
968
|
throw new Error("Invalid PHP runtime id.");
|
|
847
969
|
this[__private__dont__use] = e, this[__private__dont__use].ccall(
|
|
@@ -889,29 +1011,29 @@ class PHP {
|
|
|
889
1011
|
require_once $file;
|
|
890
1012
|
}
|
|
891
1013
|
`
|
|
892
|
-
), e.onMessage = async (
|
|
893
|
-
for (const s of c(this,
|
|
894
|
-
const i = await s(
|
|
1014
|
+
), e.onMessage = async (t) => {
|
|
1015
|
+
for (const s of c(this, R)) {
|
|
1016
|
+
const i = await s(t);
|
|
895
1017
|
if (i)
|
|
896
1018
|
return i;
|
|
897
1019
|
}
|
|
898
1020
|
return "";
|
|
899
|
-
},
|
|
1021
|
+
}, f(this, H, improveWASMErrorReporting(e)), this.dispatchEvent({
|
|
900
1022
|
type: "runtime.initialized"
|
|
901
1023
|
});
|
|
902
1024
|
}
|
|
903
1025
|
/** @inheritDoc */
|
|
904
|
-
async setSapiName(
|
|
1026
|
+
async setSapiName(r) {
|
|
905
1027
|
if (this[__private__dont__use].ccall(
|
|
906
1028
|
"wasm_set_sapi_name",
|
|
907
1029
|
NUMBER,
|
|
908
1030
|
[STRING],
|
|
909
|
-
[
|
|
1031
|
+
[r]
|
|
910
1032
|
) !== 0)
|
|
911
1033
|
throw new Error(
|
|
912
1034
|
"Could not set SAPI name. This can only be done before the PHP WASM module is initialized.Did you already dispatch any requests?"
|
|
913
1035
|
);
|
|
914
|
-
|
|
1036
|
+
f(this, T, r);
|
|
915
1037
|
}
|
|
916
1038
|
/**
|
|
917
1039
|
* Changes the current working directory in the PHP filesystem.
|
|
@@ -921,19 +1043,19 @@ class PHP {
|
|
|
921
1043
|
*
|
|
922
1044
|
* @param path - The new working directory.
|
|
923
1045
|
*/
|
|
924
|
-
chdir(
|
|
925
|
-
this[__private__dont__use].FS.chdir(
|
|
1046
|
+
chdir(r) {
|
|
1047
|
+
this[__private__dont__use].FS.chdir(r);
|
|
926
1048
|
}
|
|
927
1049
|
/**
|
|
928
1050
|
* Do not use. Use new PHPRequestHandler() instead.
|
|
929
1051
|
* @deprecated
|
|
930
1052
|
*/
|
|
931
|
-
async request(
|
|
1053
|
+
async request(r) {
|
|
932
1054
|
if (logger.warn(
|
|
933
1055
|
"PHP.request() is deprecated. Please use new PHPRequestHandler() instead."
|
|
934
1056
|
), !this.requestHandler)
|
|
935
1057
|
throw new Error("No request handler available.");
|
|
936
|
-
return this.requestHandler.request(
|
|
1058
|
+
return this.requestHandler.request(r);
|
|
937
1059
|
}
|
|
938
1060
|
/**
|
|
939
1061
|
* Runs PHP code.
|
|
@@ -995,76 +1117,189 @@ class PHP {
|
|
|
995
1117
|
*
|
|
996
1118
|
* @example
|
|
997
1119
|
* ```js
|
|
998
|
-
* const result = await php.run(
|
|
999
|
-
*
|
|
1000
|
-
*
|
|
1001
|
-
*
|
|
1120
|
+
* const result = await php.run({
|
|
1121
|
+
* code: `<?php
|
|
1122
|
+
* $fp = fopen('php://stderr', 'w');
|
|
1123
|
+
* fwrite($fp, "Hello, world!");
|
|
1124
|
+
* `
|
|
1125
|
+
* });
|
|
1002
1126
|
* // result.errors === "Hello, world!"
|
|
1003
1127
|
* ```
|
|
1004
1128
|
*
|
|
1005
|
-
* @
|
|
1129
|
+
* @deprecated Use stream() instead.
|
|
1130
|
+
* @param request - PHP runtime options.
|
|
1131
|
+
*/
|
|
1132
|
+
async run(r) {
|
|
1133
|
+
const e = await this.runStream(r), t = await PHPResponse.fromStreamedResponse(
|
|
1134
|
+
e
|
|
1135
|
+
);
|
|
1136
|
+
if (t.exitCode !== 0) {
|
|
1137
|
+
logger.warn("PHP.run() output was:", t.text);
|
|
1138
|
+
const s = new PHPExecutionFailureError(
|
|
1139
|
+
`PHP.run() failed with exit code ${t.exitCode} and the following output: ` + t.errors + `
|
|
1140
|
+
|
|
1141
|
+
` + t.text,
|
|
1142
|
+
t,
|
|
1143
|
+
"request"
|
|
1144
|
+
);
|
|
1145
|
+
throw logger.error(s), this.dispatchEvent({
|
|
1146
|
+
type: "request.error",
|
|
1147
|
+
error: new Error(
|
|
1148
|
+
"PHP.run() failed with exit code " + t.exitCode
|
|
1149
|
+
),
|
|
1150
|
+
// Distinguish between PHP request and PHP-wasm errors
|
|
1151
|
+
source: "request"
|
|
1152
|
+
}), s;
|
|
1153
|
+
}
|
|
1154
|
+
return t;
|
|
1155
|
+
}
|
|
1156
|
+
/**
|
|
1157
|
+
* Runs PHP code and returns a StreamedPHPResponse object that can be used to
|
|
1158
|
+
* process the output incrementally.
|
|
1159
|
+
*
|
|
1160
|
+
* This low-level method directly interacts with the WebAssembly
|
|
1161
|
+
* PHP interpreter and provides streaming capabilities for processing
|
|
1162
|
+
* PHP output as it becomes available.
|
|
1163
|
+
*
|
|
1164
|
+
* Every time you call stream(), it prepares the PHP
|
|
1165
|
+
* environment and:
|
|
1166
|
+
*
|
|
1167
|
+
* * Resets the internal PHP state
|
|
1168
|
+
* * Populates superglobals ($_SERVER, $_GET, etc.)
|
|
1169
|
+
* * Handles file uploads
|
|
1170
|
+
* * Populates input streams (stdin, argv, etc.)
|
|
1171
|
+
* * Sets the current working directory
|
|
1172
|
+
*
|
|
1173
|
+
* You can use stream() in two primary modes:
|
|
1174
|
+
*
|
|
1175
|
+
* ### Code snippet mode
|
|
1176
|
+
*
|
|
1177
|
+
* In this mode, you pass a string containing PHP code to run.
|
|
1178
|
+
*
|
|
1179
|
+
* ```ts
|
|
1180
|
+
* const streamedResponse = await php.stream({
|
|
1181
|
+
* code: `<?php echo "Hello world!";`
|
|
1182
|
+
* });
|
|
1183
|
+
* // Process output incrementally
|
|
1184
|
+
* for await (const chunk of streamedResponse.text) {
|
|
1185
|
+
* console.log(chunk);
|
|
1186
|
+
* }
|
|
1187
|
+
* ```
|
|
1188
|
+
*
|
|
1189
|
+
* In this mode, information like __DIR__ or __FILE__ isn't very
|
|
1190
|
+
* useful because the code is not associated with any file.
|
|
1191
|
+
*
|
|
1192
|
+
* Under the hood, the PHP snippet is passed to the `zend_eval_string`
|
|
1193
|
+
* C function.
|
|
1194
|
+
*
|
|
1195
|
+
* ### File mode
|
|
1196
|
+
*
|
|
1197
|
+
* In the file mode, you pass a scriptPath and PHP executes a file
|
|
1198
|
+
* found at that path:
|
|
1199
|
+
*
|
|
1200
|
+
* ```ts
|
|
1201
|
+
* php.writeFile(
|
|
1202
|
+
* "/www/index.php",
|
|
1203
|
+
* `<?php echo "Hello world!";"`
|
|
1204
|
+
* );
|
|
1205
|
+
* const streamedResponse = await php.stream({
|
|
1206
|
+
* scriptPath: "/www/index.php"
|
|
1207
|
+
* });
|
|
1208
|
+
* // Process output incrementally
|
|
1209
|
+
* for await (const chunk of streamedResponse.text) {
|
|
1210
|
+
* console.log(chunk);
|
|
1211
|
+
* }
|
|
1212
|
+
* ```
|
|
1213
|
+
*
|
|
1214
|
+
* In this mode, you can rely on path-related information like __DIR__
|
|
1215
|
+
* or __FILE__.
|
|
1216
|
+
*
|
|
1217
|
+
* Under the hood, the PHP file is executed with the `php_execute_script`
|
|
1218
|
+
* C function.
|
|
1219
|
+
*
|
|
1220
|
+
* The `stream()` method cannot be used in conjunction with `cli()`.
|
|
1221
|
+
*
|
|
1222
|
+
* @example
|
|
1223
|
+
* ```js
|
|
1224
|
+
* const streamedResponse = await php.stream({
|
|
1225
|
+
* code: `<?php
|
|
1226
|
+
* for ($i = 0; $i < 5; $i++) {
|
|
1227
|
+
* echo "Line $i\n";
|
|
1228
|
+
* flush();
|
|
1229
|
+
* }
|
|
1230
|
+
* `
|
|
1231
|
+
* });
|
|
1232
|
+
*
|
|
1233
|
+
* // Process output as it becomes available
|
|
1234
|
+
* for await (const chunk of streamedResponse.text) {
|
|
1235
|
+
* console.log('Received:', chunk);
|
|
1236
|
+
* }
|
|
1237
|
+
*
|
|
1238
|
+
* // Get the final exit code
|
|
1239
|
+
* const exitCode = await streamedResponse.exitCode;
|
|
1240
|
+
* console.log('Exit code:', exitCode);
|
|
1241
|
+
* ```
|
|
1242
|
+
*
|
|
1243
|
+
* @see run() – a synchronous version of this method.
|
|
1244
|
+
* @param request - PHP runtime options.
|
|
1245
|
+
* @returns A StreamedPHPResponse object.
|
|
1006
1246
|
*/
|
|
1007
|
-
async
|
|
1247
|
+
async runStream(r) {
|
|
1008
1248
|
const e = await this.semaphore.acquire();
|
|
1009
|
-
let
|
|
1010
|
-
|
|
1011
|
-
if (c(this,
|
|
1249
|
+
let t;
|
|
1250
|
+
const s = d(this, u, D).call(this, () => {
|
|
1251
|
+
if (c(this, _) || (d(this, u, L).call(this), f(this, _, !0)), r.scriptPath && !this.fileExists(r.scriptPath))
|
|
1012
1252
|
throw new Error(
|
|
1013
|
-
`The script path "${
|
|
1253
|
+
`The script path "${r.scriptPath}" does not exist.`
|
|
1014
1254
|
);
|
|
1015
|
-
d(this, u,
|
|
1016
|
-
const
|
|
1017
|
-
if (d(this, u,
|
|
1018
|
-
this.writeFile("/internal/eval.php",
|
|
1019
|
-
else if (typeof
|
|
1020
|
-
d(this, u,
|
|
1255
|
+
d(this, u, W).call(this, r.relativeUri || ""), d(this, u, Y).call(this, r.method || "GET");
|
|
1256
|
+
const i = normalizeHeaders(r.headers || {}), n = i.host || "example.com:443", o = d(this, u, J).call(this, n, r.protocol || "http");
|
|
1257
|
+
if (d(this, u, G).call(this, n), d(this, u, V).call(this, o), d(this, u, K).call(this, i), r.body && (t = d(this, u, X).call(this, r.body)), typeof r.code == "string")
|
|
1258
|
+
this.writeFile("/internal/eval.php", r.code), d(this, u, $).call(this, "/internal/eval.php");
|
|
1259
|
+
else if (typeof r.scriptPath == "string")
|
|
1260
|
+
d(this, u, $).call(this, r.scriptPath || "");
|
|
1021
1261
|
else
|
|
1022
1262
|
throw new TypeError(
|
|
1023
1263
|
"The request object must have either a `code` or a `scriptPath` property."
|
|
1024
1264
|
);
|
|
1025
|
-
const
|
|
1026
|
-
for (const p in
|
|
1027
|
-
d(this, u,
|
|
1028
|
-
const l =
|
|
1265
|
+
const a = d(this, u, z).call(this, r.$_SERVER, i, o);
|
|
1266
|
+
for (const p in a)
|
|
1267
|
+
d(this, u, Q).call(this, p, a[p]);
|
|
1268
|
+
const l = r.env || {};
|
|
1029
1269
|
for (const p in l)
|
|
1030
|
-
d(this, u,
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
return a;
|
|
1042
|
-
} catch (s) {
|
|
1043
|
-
throw this.dispatchEvent({
|
|
1270
|
+
d(this, u, B).call(this, p, l[p]);
|
|
1271
|
+
return c(this, _) || (d(this, u, L).call(this), f(this, _, !0)), this[__private__dont__use].ccall(
|
|
1272
|
+
"wasm_sapi_handle_request",
|
|
1273
|
+
NUMBER,
|
|
1274
|
+
[],
|
|
1275
|
+
[],
|
|
1276
|
+
{ async: !0 }
|
|
1277
|
+
);
|
|
1278
|
+
});
|
|
1279
|
+
return await s.catch((i) => {
|
|
1280
|
+
this.dispatchEvent({
|
|
1044
1281
|
type: "request.error",
|
|
1045
|
-
error:
|
|
1282
|
+
error: i,
|
|
1046
1283
|
// Distinguish between PHP request and PHP-wasm errors
|
|
1047
|
-
source:
|
|
1048
|
-
})
|
|
1049
|
-
}
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
}
|
|
1057
|
-
}
|
|
1284
|
+
source: i.source ?? "php-wasm"
|
|
1285
|
+
});
|
|
1286
|
+
}).finally(() => {
|
|
1287
|
+
t && this[__private__dont__use].free(t);
|
|
1288
|
+
}).finally(() => {
|
|
1289
|
+
e(), this.dispatchEvent({
|
|
1290
|
+
type: "request.end"
|
|
1291
|
+
});
|
|
1292
|
+
}), s;
|
|
1058
1293
|
}
|
|
1059
1294
|
/**
|
|
1060
1295
|
* Defines a constant in the PHP runtime.
|
|
1061
1296
|
* @param key - The name of the constant.
|
|
1062
1297
|
* @param value - The value of the constant.
|
|
1063
1298
|
*/
|
|
1064
|
-
defineConstant(
|
|
1065
|
-
let
|
|
1299
|
+
defineConstant(r, e) {
|
|
1300
|
+
let t = {};
|
|
1066
1301
|
try {
|
|
1067
|
-
|
|
1302
|
+
t = JSON.parse(
|
|
1068
1303
|
this.fileExists("/internal/shared/consts.json") && this.readFileAsText("/internal/shared/consts.json") || "{}"
|
|
1069
1304
|
);
|
|
1070
1305
|
} catch {
|
|
@@ -1072,8 +1307,8 @@ class PHP {
|
|
|
1072
1307
|
this.writeFile(
|
|
1073
1308
|
"/internal/shared/consts.json",
|
|
1074
1309
|
JSON.stringify({
|
|
1075
|
-
...
|
|
1076
|
-
[
|
|
1310
|
+
...t,
|
|
1311
|
+
[r]: e
|
|
1077
1312
|
})
|
|
1078
1313
|
);
|
|
1079
1314
|
}
|
|
@@ -1084,14 +1319,14 @@ class PHP {
|
|
|
1084
1319
|
*
|
|
1085
1320
|
* @param path - The directory path to create.
|
|
1086
1321
|
*/
|
|
1087
|
-
mkdir(
|
|
1088
|
-
return FSHelpers.mkdir(this[__private__dont__use].FS,
|
|
1322
|
+
mkdir(r) {
|
|
1323
|
+
return FSHelpers.mkdir(this[__private__dont__use].FS, r);
|
|
1089
1324
|
}
|
|
1090
1325
|
/**
|
|
1091
1326
|
* @deprecated Use mkdir instead.
|
|
1092
1327
|
*/
|
|
1093
|
-
mkdirTree(
|
|
1094
|
-
return FSHelpers.mkdir(this[__private__dont__use].FS,
|
|
1328
|
+
mkdirTree(r) {
|
|
1329
|
+
return FSHelpers.mkdir(this[__private__dont__use].FS, r);
|
|
1095
1330
|
}
|
|
1096
1331
|
/**
|
|
1097
1332
|
* Reads a file from the PHP filesystem and returns it as a string.
|
|
@@ -1100,8 +1335,8 @@ class PHP {
|
|
|
1100
1335
|
* @param path - The file path to read.
|
|
1101
1336
|
* @returns The file contents.
|
|
1102
1337
|
*/
|
|
1103
|
-
readFileAsText(
|
|
1104
|
-
return FSHelpers.readFileAsText(this[__private__dont__use].FS,
|
|
1338
|
+
readFileAsText(r) {
|
|
1339
|
+
return FSHelpers.readFileAsText(this[__private__dont__use].FS, r);
|
|
1105
1340
|
}
|
|
1106
1341
|
/**
|
|
1107
1342
|
* Reads a file from the PHP filesystem and returns it as an array buffer.
|
|
@@ -1110,8 +1345,8 @@ class PHP {
|
|
|
1110
1345
|
* @param path - The file path to read.
|
|
1111
1346
|
* @returns The file contents.
|
|
1112
1347
|
*/
|
|
1113
|
-
readFileAsBuffer(
|
|
1114
|
-
return FSHelpers.readFileAsBuffer(this[__private__dont__use].FS,
|
|
1348
|
+
readFileAsBuffer(r) {
|
|
1349
|
+
return FSHelpers.readFileAsBuffer(this[__private__dont__use].FS, r);
|
|
1115
1350
|
}
|
|
1116
1351
|
/**
|
|
1117
1352
|
* Overwrites data in a file in the PHP filesystem.
|
|
@@ -1120,8 +1355,8 @@ class PHP {
|
|
|
1120
1355
|
* @param path - The file path to write to.
|
|
1121
1356
|
* @param data - The data to write to the file.
|
|
1122
1357
|
*/
|
|
1123
|
-
writeFile(
|
|
1124
|
-
return FSHelpers.writeFile(this[__private__dont__use].FS,
|
|
1358
|
+
writeFile(r, e) {
|
|
1359
|
+
return FSHelpers.writeFile(this[__private__dont__use].FS, r, e);
|
|
1125
1360
|
}
|
|
1126
1361
|
/**
|
|
1127
1362
|
* Removes a file from the PHP filesystem.
|
|
@@ -1129,8 +1364,8 @@ class PHP {
|
|
|
1129
1364
|
* @throws {@link @php-wasm/universal:ErrnoError} – If the file doesn't exist.
|
|
1130
1365
|
* @param path - The file path to remove.
|
|
1131
1366
|
*/
|
|
1132
|
-
unlink(
|
|
1133
|
-
return FSHelpers.unlink(this[__private__dont__use].FS,
|
|
1367
|
+
unlink(r) {
|
|
1368
|
+
return FSHelpers.unlink(this[__private__dont__use].FS, r);
|
|
1134
1369
|
}
|
|
1135
1370
|
/**
|
|
1136
1371
|
* Moves a file or directory in the PHP filesystem to a
|
|
@@ -1139,8 +1374,8 @@ class PHP {
|
|
|
1139
1374
|
* @param oldPath The path to rename.
|
|
1140
1375
|
* @param newPath The new path.
|
|
1141
1376
|
*/
|
|
1142
|
-
mv(
|
|
1143
|
-
return FSHelpers.mv(this[__private__dont__use].FS,
|
|
1377
|
+
mv(r, e) {
|
|
1378
|
+
return FSHelpers.mv(this[__private__dont__use].FS, r, e);
|
|
1144
1379
|
}
|
|
1145
1380
|
/**
|
|
1146
1381
|
* Removes a directory from the PHP filesystem.
|
|
@@ -1148,8 +1383,8 @@ class PHP {
|
|
|
1148
1383
|
* @param path The directory path to remove.
|
|
1149
1384
|
* @param options Options for the removal.
|
|
1150
1385
|
*/
|
|
1151
|
-
rmdir(
|
|
1152
|
-
return FSHelpers.rmdir(this[__private__dont__use].FS,
|
|
1386
|
+
rmdir(r, e = { recursive: !0 }) {
|
|
1387
|
+
return FSHelpers.rmdir(this[__private__dont__use].FS, r, e);
|
|
1153
1388
|
}
|
|
1154
1389
|
/**
|
|
1155
1390
|
* Lists the files and directories in the given directory.
|
|
@@ -1158,10 +1393,10 @@ class PHP {
|
|
|
1158
1393
|
* @param options - Options for the listing.
|
|
1159
1394
|
* @returns The list of files and directories in the given directory.
|
|
1160
1395
|
*/
|
|
1161
|
-
listFiles(
|
|
1396
|
+
listFiles(r, e = { prependPath: !1 }) {
|
|
1162
1397
|
return FSHelpers.listFiles(
|
|
1163
1398
|
this[__private__dont__use].FS,
|
|
1164
|
-
|
|
1399
|
+
r,
|
|
1165
1400
|
e
|
|
1166
1401
|
);
|
|
1167
1402
|
}
|
|
@@ -1171,8 +1406,8 @@ class PHP {
|
|
|
1171
1406
|
* @param path – The path to check.
|
|
1172
1407
|
* @returns True if the path is a directory, false otherwise.
|
|
1173
1408
|
*/
|
|
1174
|
-
isDir(
|
|
1175
|
-
return FSHelpers.isDir(this[__private__dont__use].FS,
|
|
1409
|
+
isDir(r) {
|
|
1410
|
+
return FSHelpers.isDir(this[__private__dont__use].FS, r);
|
|
1176
1411
|
}
|
|
1177
1412
|
/**
|
|
1178
1413
|
* Checks if a file exists in the PHP filesystem.
|
|
@@ -1180,16 +1415,16 @@ class PHP {
|
|
|
1180
1415
|
* @param path – The path to check.
|
|
1181
1416
|
* @returns True if the path is a file, false otherwise.
|
|
1182
1417
|
*/
|
|
1183
|
-
isFile(
|
|
1184
|
-
return FSHelpers.isFile(this[__private__dont__use].FS,
|
|
1418
|
+
isFile(r) {
|
|
1419
|
+
return FSHelpers.isFile(this[__private__dont__use].FS, r);
|
|
1185
1420
|
}
|
|
1186
1421
|
/**
|
|
1187
1422
|
* Creates a symlink in the PHP filesystem.
|
|
1188
1423
|
* @param target
|
|
1189
1424
|
* @param path
|
|
1190
1425
|
*/
|
|
1191
|
-
symlink(
|
|
1192
|
-
return FSHelpers.symlink(this[__private__dont__use].FS,
|
|
1426
|
+
symlink(r, e) {
|
|
1427
|
+
return FSHelpers.symlink(this[__private__dont__use].FS, r, e);
|
|
1193
1428
|
}
|
|
1194
1429
|
/**
|
|
1195
1430
|
* Checks if a path is a symlink in the PHP filesystem.
|
|
@@ -1197,8 +1432,8 @@ class PHP {
|
|
|
1197
1432
|
* @param path
|
|
1198
1433
|
* @returns True if the path is a symlink, false otherwise.
|
|
1199
1434
|
*/
|
|
1200
|
-
isSymlink(
|
|
1201
|
-
return FSHelpers.isSymlink(this[__private__dont__use].FS,
|
|
1435
|
+
isSymlink(r) {
|
|
1436
|
+
return FSHelpers.isSymlink(this[__private__dont__use].FS, r);
|
|
1202
1437
|
}
|
|
1203
1438
|
/**
|
|
1204
1439
|
* Reads the target of a symlink in the PHP filesystem.
|
|
@@ -1206,16 +1441,16 @@ class PHP {
|
|
|
1206
1441
|
* @param path
|
|
1207
1442
|
* @returns The target of the symlink.
|
|
1208
1443
|
*/
|
|
1209
|
-
readlink(
|
|
1210
|
-
return FSHelpers.readlink(this[__private__dont__use].FS,
|
|
1444
|
+
readlink(r) {
|
|
1445
|
+
return FSHelpers.readlink(this[__private__dont__use].FS, r);
|
|
1211
1446
|
}
|
|
1212
1447
|
/**
|
|
1213
1448
|
* Resolves the real path of a file in the PHP filesystem.
|
|
1214
1449
|
* @param path
|
|
1215
1450
|
* @returns The real path of the file.
|
|
1216
1451
|
*/
|
|
1217
|
-
realpath(
|
|
1218
|
-
return FSHelpers.realpath(this[__private__dont__use].FS,
|
|
1452
|
+
realpath(r) {
|
|
1453
|
+
return FSHelpers.realpath(this[__private__dont__use].FS, r);
|
|
1219
1454
|
}
|
|
1220
1455
|
/**
|
|
1221
1456
|
* Checks if a file (or a directory) exists in the PHP filesystem.
|
|
@@ -1223,8 +1458,8 @@ class PHP {
|
|
|
1223
1458
|
* @param path - The file path to check.
|
|
1224
1459
|
* @returns True if the file exists, false otherwise.
|
|
1225
1460
|
*/
|
|
1226
|
-
fileExists(
|
|
1227
|
-
return FSHelpers.fileExists(this[__private__dont__use].FS,
|
|
1461
|
+
fileExists(r) {
|
|
1462
|
+
return FSHelpers.fileExists(this[__private__dont__use].FS, r);
|
|
1228
1463
|
}
|
|
1229
1464
|
/**
|
|
1230
1465
|
* Hot-swaps the PHP runtime for a new one without
|
|
@@ -1236,17 +1471,17 @@ class PHP {
|
|
|
1236
1471
|
* is fully decoupled from the request handler and
|
|
1237
1472
|
* accepts a constructor-level cwd argument.
|
|
1238
1473
|
*/
|
|
1239
|
-
async hotSwapPHPRuntime(
|
|
1240
|
-
const
|
|
1241
|
-
for (const [i,
|
|
1242
|
-
s.push({ mountHandler:
|
|
1474
|
+
async hotSwapPHPRuntime(r, e) {
|
|
1475
|
+
const t = this[__private__dont__use].FS, s = [];
|
|
1476
|
+
for (const [i, n] of Object.entries(c(this, k)))
|
|
1477
|
+
s.push({ mountHandler: n.mountHandler, vfsPath: i }), await n.unmount();
|
|
1243
1478
|
try {
|
|
1244
1479
|
this.exit();
|
|
1245
1480
|
} catch {
|
|
1246
1481
|
}
|
|
1247
|
-
this.initializeRuntime(
|
|
1248
|
-
for (const { mountHandler: i, vfsPath:
|
|
1249
|
-
this.mkdir(
|
|
1482
|
+
this.initializeRuntime(r), c(this, T) && this.setSapiName(c(this, T)), copyFS(t, this[__private__dont__use].FS, "/internal"), e && copyFS(t, this[__private__dont__use].FS, e);
|
|
1483
|
+
for (const { mountHandler: i, vfsPath: n } of s)
|
|
1484
|
+
this.mkdir(n), await this.mount(n, i);
|
|
1250
1485
|
}
|
|
1251
1486
|
/**
|
|
1252
1487
|
* Mounts a filesystem to a given path in the PHP filesystem.
|
|
@@ -1255,18 +1490,18 @@ class PHP {
|
|
|
1255
1490
|
* @param mountHandler - The mount handler to use.
|
|
1256
1491
|
* @return Unmount function to unmount the filesystem.
|
|
1257
1492
|
*/
|
|
1258
|
-
async mount(
|
|
1259
|
-
const
|
|
1493
|
+
async mount(r, e) {
|
|
1494
|
+
const t = await e(
|
|
1260
1495
|
this,
|
|
1261
1496
|
this[__private__dont__use].FS,
|
|
1262
|
-
|
|
1497
|
+
r
|
|
1263
1498
|
), s = {
|
|
1264
1499
|
mountHandler: e,
|
|
1265
1500
|
unmount: async () => {
|
|
1266
|
-
await
|
|
1501
|
+
await t(), delete c(this, k)[r];
|
|
1267
1502
|
}
|
|
1268
1503
|
};
|
|
1269
|
-
return c(this,
|
|
1504
|
+
return c(this, k)[r] = s, () => {
|
|
1270
1505
|
s.unmount();
|
|
1271
1506
|
};
|
|
1272
1507
|
}
|
|
@@ -1283,53 +1518,45 @@ class PHP {
|
|
|
1283
1518
|
* @param argv - The arguments to pass to the CLI.
|
|
1284
1519
|
* @returns The exit code of the CLI session.
|
|
1285
1520
|
*/
|
|
1286
|
-
async cli(
|
|
1287
|
-
|
|
1521
|
+
async cli(r, e = {}) {
|
|
1522
|
+
const t = await this.semaphore.acquire(), s = e.env || {};
|
|
1523
|
+
for (const [i, n] of Object.entries(s))
|
|
1524
|
+
d(this, u, B).call(this, i, n);
|
|
1525
|
+
r = [r[0], "-c", PHP_INI_PATH, ...r.slice(1)];
|
|
1526
|
+
for (const i of r)
|
|
1288
1527
|
this[__private__dont__use].ccall(
|
|
1289
1528
|
"wasm_add_cli_arg",
|
|
1290
1529
|
null,
|
|
1291
1530
|
[STRING],
|
|
1292
|
-
[
|
|
1531
|
+
[i]
|
|
1293
1532
|
);
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
null,
|
|
1298
|
-
[],
|
|
1299
|
-
[],
|
|
1300
|
-
{
|
|
1301
|
-
async: !0
|
|
1302
|
-
}
|
|
1303
|
-
);
|
|
1304
|
-
} catch (e) {
|
|
1305
|
-
if (isExitCodeZero(e))
|
|
1306
|
-
return 0;
|
|
1307
|
-
throw e;
|
|
1308
|
-
}
|
|
1533
|
+
return await d(this, u, D).call(this, () => this[__private__dont__use].ccall("run_cli", null, [], [], {
|
|
1534
|
+
async: !0
|
|
1535
|
+
})).then((i) => (i.exitCode.finally(t), i));
|
|
1309
1536
|
}
|
|
1310
|
-
setSkipShebang(
|
|
1537
|
+
setSkipShebang(r) {
|
|
1311
1538
|
this[__private__dont__use].ccall(
|
|
1312
1539
|
"wasm_set_skip_shebang",
|
|
1313
1540
|
null,
|
|
1314
1541
|
[NUMBER],
|
|
1315
|
-
[
|
|
1542
|
+
[r ? 1 : 0]
|
|
1316
1543
|
);
|
|
1317
1544
|
}
|
|
1318
|
-
exit(
|
|
1545
|
+
exit(r = 0) {
|
|
1319
1546
|
this.dispatchEvent({
|
|
1320
1547
|
type: "runtime.beforedestroy"
|
|
1321
1548
|
});
|
|
1322
1549
|
try {
|
|
1323
|
-
this[__private__dont__use]._exit(
|
|
1550
|
+
this[__private__dont__use]._exit(r);
|
|
1324
1551
|
} catch {
|
|
1325
1552
|
}
|
|
1326
|
-
|
|
1553
|
+
f(this, _, !1), f(this, H, null), this[__private__dont__use] && (delete this[__private__dont__use].onMessage, delete this[__private__dont__use]);
|
|
1327
1554
|
}
|
|
1328
1555
|
[Symbol.dispose]() {
|
|
1329
|
-
c(this,
|
|
1556
|
+
c(this, _) && this.exit(0);
|
|
1330
1557
|
}
|
|
1331
1558
|
}
|
|
1332
|
-
|
|
1559
|
+
T = new WeakMap(), _ = new WeakMap(), H = new WeakMap(), P = new WeakMap(), R = new WeakMap(), k = new WeakMap(), u = new WeakSet(), /**
|
|
1333
1560
|
* Prepares the $_SERVER entries for the PHP runtime.
|
|
1334
1561
|
*
|
|
1335
1562
|
* @param defaults Default entries to include in $_SERVER.
|
|
@@ -1338,107 +1565,90 @@ F = new WeakMap(), P = new WeakMap(), v = new WeakMap(), _ = new WeakMap(), x =
|
|
|
1338
1565
|
* was provided.
|
|
1339
1566
|
* @returns Computed $_SERVER entries.
|
|
1340
1567
|
*/
|
|
1341
|
-
|
|
1568
|
+
z = function(r, e, t) {
|
|
1342
1569
|
const s = {
|
|
1343
|
-
...
|
|
1570
|
+
...r || {}
|
|
1344
1571
|
};
|
|
1345
|
-
s.HTTPS = s.HTTPS ||
|
|
1572
|
+
s.HTTPS = s.HTTPS || t === 443 ? "on" : "off";
|
|
1346
1573
|
for (const i in e) {
|
|
1347
|
-
let
|
|
1348
|
-
["content-type", "content-length"].includes(i.toLowerCase()) && (
|
|
1574
|
+
let n = "HTTP_";
|
|
1575
|
+
["content-type", "content-length"].includes(i.toLowerCase()) && (n = ""), s[`${n}${i.toUpperCase().replace(/-/g, "_")}`] = e[i];
|
|
1349
1576
|
}
|
|
1350
1577
|
return s;
|
|
1351
|
-
},
|
|
1578
|
+
}, L = function() {
|
|
1352
1579
|
this[__private__dont__use].ccall("php_wasm_init", null, [], []);
|
|
1353
|
-
},
|
|
1354
|
-
const t = "/internal/headers.json";
|
|
1355
|
-
if (!this.fileExists(t))
|
|
1356
|
-
throw new Error(
|
|
1357
|
-
"SAPI Error: Could not find response headers file."
|
|
1358
|
-
);
|
|
1359
|
-
const e = JSON.parse(this.readFileAsText(t)), r = {};
|
|
1360
|
-
for (const s of e.headers) {
|
|
1361
|
-
if (!s.includes(": "))
|
|
1362
|
-
continue;
|
|
1363
|
-
const i = s.indexOf(": "), o = s.substring(0, i).toLowerCase(), n = s.substring(i + 2);
|
|
1364
|
-
o in r || (r[o] = []), r[o].push(n);
|
|
1365
|
-
}
|
|
1366
|
-
return {
|
|
1367
|
-
headers: r,
|
|
1368
|
-
httpStatusCode: e.status
|
|
1369
|
-
};
|
|
1370
|
-
}, U = function(t) {
|
|
1580
|
+
}, W = function(r) {
|
|
1371
1581
|
this[__private__dont__use].ccall(
|
|
1372
1582
|
"wasm_set_request_uri",
|
|
1373
1583
|
null,
|
|
1374
1584
|
[STRING],
|
|
1375
|
-
[
|
|
1585
|
+
[r]
|
|
1376
1586
|
);
|
|
1377
1587
|
let e = "";
|
|
1378
|
-
|
|
1588
|
+
r.includes("?") && (e = r.substring(r.indexOf("?") + 1)), this[__private__dont__use].ccall(
|
|
1379
1589
|
"wasm_set_query_string",
|
|
1380
1590
|
null,
|
|
1381
1591
|
[STRING],
|
|
1382
1592
|
[e]
|
|
1383
1593
|
);
|
|
1384
|
-
},
|
|
1594
|
+
}, G = function(r) {
|
|
1385
1595
|
this[__private__dont__use].ccall(
|
|
1386
1596
|
"wasm_set_request_host",
|
|
1387
1597
|
null,
|
|
1388
1598
|
[STRING],
|
|
1389
|
-
[
|
|
1599
|
+
[r]
|
|
1390
1600
|
);
|
|
1391
|
-
},
|
|
1601
|
+
}, V = function(r) {
|
|
1392
1602
|
this[__private__dont__use].ccall(
|
|
1393
1603
|
"wasm_set_request_port",
|
|
1394
1604
|
null,
|
|
1395
1605
|
[NUMBER],
|
|
1396
|
-
[
|
|
1606
|
+
[r]
|
|
1397
1607
|
);
|
|
1398
|
-
},
|
|
1399
|
-
let
|
|
1608
|
+
}, J = function(r, e) {
|
|
1609
|
+
let t;
|
|
1400
1610
|
try {
|
|
1401
|
-
|
|
1611
|
+
t = parseInt(new URL(r).port, 10);
|
|
1402
1612
|
} catch {
|
|
1403
1613
|
}
|
|
1404
|
-
return (!
|
|
1405
|
-
},
|
|
1614
|
+
return (!t || isNaN(t) || t === 80) && (t = e === "https" ? 443 : 80), t;
|
|
1615
|
+
}, Y = function(r) {
|
|
1406
1616
|
this[__private__dont__use].ccall(
|
|
1407
1617
|
"wasm_set_request_method",
|
|
1408
1618
|
null,
|
|
1409
1619
|
[STRING],
|
|
1410
|
-
[
|
|
1620
|
+
[r]
|
|
1411
1621
|
);
|
|
1412
|
-
},
|
|
1413
|
-
|
|
1622
|
+
}, K = function(r) {
|
|
1623
|
+
r.cookie && this[__private__dont__use].ccall(
|
|
1414
1624
|
"wasm_set_cookies",
|
|
1415
1625
|
null,
|
|
1416
1626
|
[STRING],
|
|
1417
|
-
[
|
|
1418
|
-
),
|
|
1627
|
+
[r.cookie]
|
|
1628
|
+
), r["content-type"] && this[__private__dont__use].ccall(
|
|
1419
1629
|
"wasm_set_content_type",
|
|
1420
1630
|
null,
|
|
1421
1631
|
[STRING],
|
|
1422
|
-
[
|
|
1423
|
-
),
|
|
1632
|
+
[r["content-type"]]
|
|
1633
|
+
), r["content-length"] && this[__private__dont__use].ccall(
|
|
1424
1634
|
"wasm_set_content_length",
|
|
1425
1635
|
null,
|
|
1426
1636
|
[NUMBER],
|
|
1427
|
-
[parseInt(
|
|
1637
|
+
[parseInt(r["content-length"], 10)]
|
|
1428
1638
|
);
|
|
1429
|
-
},
|
|
1430
|
-
let e,
|
|
1431
|
-
typeof
|
|
1639
|
+
}, X = function(r) {
|
|
1640
|
+
let e, t;
|
|
1641
|
+
typeof r == "string" ? (logger.warn(
|
|
1432
1642
|
"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"
|
|
1433
|
-
),
|
|
1643
|
+
), t = this[__private__dont__use].lengthBytesUTF8(r), e = t + 1) : (t = r.byteLength, e = r.byteLength);
|
|
1434
1644
|
const s = this[__private__dont__use].malloc(e);
|
|
1435
1645
|
if (!s)
|
|
1436
1646
|
throw new Error("Could not allocate memory for the request body.");
|
|
1437
|
-
return typeof
|
|
1438
|
-
|
|
1647
|
+
return typeof r == "string" ? this[__private__dont__use].stringToUTF8(
|
|
1648
|
+
r,
|
|
1439
1649
|
s,
|
|
1440
1650
|
e + 1
|
|
1441
|
-
) : this[__private__dont__use].HEAPU8.set(
|
|
1651
|
+
) : this[__private__dont__use].HEAPU8.set(r, s), this[__private__dont__use].ccall(
|
|
1442
1652
|
"wasm_set_request_body",
|
|
1443
1653
|
null,
|
|
1444
1654
|
[NUMBER],
|
|
@@ -1447,119 +1657,155 @@ N = function(t, e, r) {
|
|
|
1447
1657
|
"wasm_set_content_length",
|
|
1448
1658
|
null,
|
|
1449
1659
|
[NUMBER],
|
|
1450
|
-
[
|
|
1660
|
+
[t]
|
|
1451
1661
|
), s;
|
|
1452
|
-
},
|
|
1662
|
+
}, $ = function(r) {
|
|
1453
1663
|
this[__private__dont__use].ccall(
|
|
1454
1664
|
"wasm_set_path_translated",
|
|
1455
1665
|
null,
|
|
1456
1666
|
[STRING],
|
|
1457
|
-
[
|
|
1667
|
+
[r]
|
|
1458
1668
|
);
|
|
1459
|
-
},
|
|
1669
|
+
}, Q = function(r, e) {
|
|
1460
1670
|
this[__private__dont__use].ccall(
|
|
1461
1671
|
"wasm_add_SERVER_entry",
|
|
1462
1672
|
null,
|
|
1463
1673
|
[STRING, STRING],
|
|
1464
|
-
[
|
|
1674
|
+
[r, e]
|
|
1465
1675
|
);
|
|
1466
|
-
},
|
|
1676
|
+
}, B = function(r, e) {
|
|
1467
1677
|
this[__private__dont__use].ccall(
|
|
1468
1678
|
"wasm_add_ENV_entry",
|
|
1469
1679
|
null,
|
|
1470
1680
|
[STRING, STRING],
|
|
1471
|
-
[
|
|
1681
|
+
[r, e]
|
|
1472
1682
|
);
|
|
1473
|
-
},
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1683
|
+
}, D = async function(r) {
|
|
1684
|
+
const e = this[__private__dont__use], t = await createInvertedReadableStream();
|
|
1685
|
+
e.onHeaders = (m) => {
|
|
1686
|
+
a || s || t.controller.enqueue(m.slice());
|
|
1687
|
+
};
|
|
1688
|
+
let s = !1;
|
|
1689
|
+
const i = () => {
|
|
1690
|
+
s || (s = !0, t.controller.close());
|
|
1691
|
+
}, n = await createInvertedReadableStream();
|
|
1692
|
+
e.onStdout = (m) => {
|
|
1693
|
+
i(), !a && n.controller.enqueue(m.slice());
|
|
1694
|
+
};
|
|
1695
|
+
const o = await createInvertedReadableStream();
|
|
1696
|
+
e.onStderr = (m) => {
|
|
1697
|
+
a || o.controller.enqueue(m.slice());
|
|
1698
|
+
};
|
|
1699
|
+
let a = !1, l;
|
|
1700
|
+
const E = (async () => {
|
|
1701
|
+
var m;
|
|
1702
|
+
try {
|
|
1703
|
+
return await Promise.race([
|
|
1704
|
+
r(),
|
|
1705
|
+
new Promise((N, U) => {
|
|
1706
|
+
var b;
|
|
1707
|
+
l = (w) => {
|
|
1708
|
+
if (logger.error(w), logger.error(w.error), !isExitCode(w.error)) {
|
|
1709
|
+
const j = new Error("Rethrown");
|
|
1710
|
+
j.cause = w.error, j.betterMessage = w.message, U(j);
|
|
1711
|
+
}
|
|
1712
|
+
}, (b = c(this, H)) == null || b.addEventListener(
|
|
1713
|
+
"error",
|
|
1714
|
+
l,
|
|
1715
|
+
{ once: !0 }
|
|
1716
|
+
);
|
|
1717
|
+
})
|
|
1718
|
+
]);
|
|
1719
|
+
} catch (S) {
|
|
1720
|
+
if (isExitCode(S))
|
|
1721
|
+
return S.exitCode;
|
|
1722
|
+
n.controller.error(S), o.controller.error(S), t.controller.error(S), a = !0;
|
|
1723
|
+
for (const w in this)
|
|
1724
|
+
typeof this[w] == "function" && (this[w] = () => {
|
|
1725
|
+
throw new Error(
|
|
1726
|
+
"PHP runtime has crashed – see the earlier error for details."
|
|
1727
|
+
);
|
|
1728
|
+
});
|
|
1729
|
+
this.functionsMaybeMissingFromAsyncify = getFunctionsMaybeMissingFromAsyncify();
|
|
1730
|
+
const N = S, U = "betterMessage" in N ? N.betterMessage : N.message, b = new Error(U);
|
|
1731
|
+
throw b.cause = N, logger.error(b), b;
|
|
1732
|
+
} finally {
|
|
1733
|
+
a || (n.controller.close(), o.controller.close(), i(), a = !0), (m = c(this, H)) == null || m.removeEventListener(
|
|
1484
1734
|
"error",
|
|
1485
|
-
|
|
1735
|
+
l
|
|
1486
1736
|
);
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
return l instanceof Promise ? l.then(o, n) : o(l);
|
|
1495
|
-
});
|
|
1496
|
-
} catch (o) {
|
|
1497
|
-
for (const p in this)
|
|
1498
|
-
typeof this[p] == "function" && (this[p] = () => {
|
|
1499
|
-
throw new Error(
|
|
1500
|
-
"PHP runtime has crashed – see the earlier error for details."
|
|
1501
|
-
);
|
|
1502
|
-
});
|
|
1503
|
-
this.functionsMaybeMissingFromAsyncify = getFunctionsMaybeMissingFromAsyncify();
|
|
1504
|
-
const n = o, l = "betterMessage" in n ? n.betterMessage : n.message, a = new Error(l);
|
|
1505
|
-
throw a.cause = n, logger.error(a), a;
|
|
1506
|
-
} finally {
|
|
1507
|
-
(i = c(this, v)) == null || i.removeEventListener("error", e);
|
|
1508
|
-
}
|
|
1509
|
-
const { headers: r, httpStatusCode: s } = d(this, u, j).call(this);
|
|
1510
|
-
return new PHPResponse(
|
|
1511
|
-
t === 0 ? s : 500,
|
|
1512
|
-
r,
|
|
1513
|
-
this.readFileAsBuffer("/internal/stdout"),
|
|
1514
|
-
this.readFileAsText("/internal/stderr"),
|
|
1515
|
-
t
|
|
1737
|
+
}
|
|
1738
|
+
})();
|
|
1739
|
+
return new StreamedPHPResponse(
|
|
1740
|
+
t.stream,
|
|
1741
|
+
n.stream,
|
|
1742
|
+
o.stream,
|
|
1743
|
+
E
|
|
1516
1744
|
);
|
|
1517
1745
|
};
|
|
1518
|
-
function normalizeHeaders(
|
|
1746
|
+
function normalizeHeaders(r) {
|
|
1519
1747
|
const e = {};
|
|
1520
|
-
for (const
|
|
1521
|
-
e[
|
|
1748
|
+
for (const t in r)
|
|
1749
|
+
e[t.toLowerCase()] = r[t];
|
|
1522
1750
|
return e;
|
|
1523
1751
|
}
|
|
1524
|
-
function copyFS(
|
|
1752
|
+
function copyFS(r, e, t) {
|
|
1525
1753
|
let s;
|
|
1526
1754
|
try {
|
|
1527
|
-
s =
|
|
1755
|
+
s = r.lookupPath(t);
|
|
1528
1756
|
} catch {
|
|
1529
1757
|
return;
|
|
1530
1758
|
}
|
|
1531
1759
|
if (!("contents" in s.node))
|
|
1532
1760
|
return;
|
|
1533
|
-
if (!
|
|
1534
|
-
e.writeFile(
|
|
1761
|
+
if (!r.isDir(s.node.mode)) {
|
|
1762
|
+
e.writeFile(t, r.readFile(t));
|
|
1535
1763
|
return;
|
|
1536
1764
|
}
|
|
1537
|
-
e.mkdirTree(
|
|
1538
|
-
const i =
|
|
1539
|
-
for (const
|
|
1540
|
-
copyFS(
|
|
1765
|
+
e.mkdirTree(t);
|
|
1766
|
+
const i = r.readdir(t).filter((n) => n !== "." && n !== "..");
|
|
1767
|
+
for (const n of i)
|
|
1768
|
+
copyFS(r, e, joinPaths(t, n));
|
|
1769
|
+
}
|
|
1770
|
+
async function createInvertedReadableStream(r = {}) {
|
|
1771
|
+
let e;
|
|
1772
|
+
const t = new Promise(
|
|
1773
|
+
(n) => {
|
|
1774
|
+
e = n;
|
|
1775
|
+
}
|
|
1776
|
+
), s = new ReadableStream({
|
|
1777
|
+
...r,
|
|
1778
|
+
start(n) {
|
|
1779
|
+
if (e(n), r.start)
|
|
1780
|
+
return r.start(n);
|
|
1781
|
+
}
|
|
1782
|
+
}), i = await t;
|
|
1783
|
+
return {
|
|
1784
|
+
stream: s,
|
|
1785
|
+
controller: i
|
|
1786
|
+
};
|
|
1541
1787
|
}
|
|
1542
|
-
async function getPhpIniEntries(
|
|
1543
|
-
const
|
|
1788
|
+
async function getPhpIniEntries(r, e) {
|
|
1789
|
+
const t = parse(await r.readFileAsText(PHP_INI_PATH));
|
|
1544
1790
|
if (e === void 0)
|
|
1545
|
-
return
|
|
1791
|
+
return t;
|
|
1546
1792
|
const s = {};
|
|
1547
1793
|
for (const i of e)
|
|
1548
|
-
s[i] =
|
|
1794
|
+
s[i] = t[i];
|
|
1549
1795
|
return s;
|
|
1550
1796
|
}
|
|
1551
|
-
async function setPhpIniEntries(
|
|
1552
|
-
const
|
|
1797
|
+
async function setPhpIniEntries(r, e) {
|
|
1798
|
+
const t = parse(await r.readFileAsText(PHP_INI_PATH));
|
|
1553
1799
|
for (const [s, i] of Object.entries(e))
|
|
1554
|
-
i == null ? delete
|
|
1555
|
-
await
|
|
1800
|
+
i == null ? delete t[s] : t[s] = i;
|
|
1801
|
+
await r.writeFile(PHP_INI_PATH, stringify(t));
|
|
1556
1802
|
}
|
|
1557
|
-
async function withPHPIniValues(
|
|
1558
|
-
const s = await
|
|
1803
|
+
async function withPHPIniValues(r, e, t) {
|
|
1804
|
+
const s = await r.readFileAsText(PHP_INI_PATH);
|
|
1559
1805
|
try {
|
|
1560
|
-
return await setPhpIniEntries(
|
|
1806
|
+
return await setPhpIniEntries(r, e), await t();
|
|
1561
1807
|
} finally {
|
|
1562
|
-
await
|
|
1808
|
+
await r.writeFile(PHP_INI_PATH, s);
|
|
1563
1809
|
}
|
|
1564
1810
|
}
|
|
1565
1811
|
class HttpCookieStore {
|
|
@@ -1568,50 +1814,50 @@ class HttpCookieStore {
|
|
|
1568
1814
|
}
|
|
1569
1815
|
rememberCookiesFromResponseHeaders(e) {
|
|
1570
1816
|
if (e != null && e["set-cookie"])
|
|
1571
|
-
for (const
|
|
1817
|
+
for (const t of e["set-cookie"])
|
|
1572
1818
|
try {
|
|
1573
|
-
if (!
|
|
1819
|
+
if (!t.includes("="))
|
|
1574
1820
|
continue;
|
|
1575
|
-
const s =
|
|
1576
|
-
this.cookies[i] =
|
|
1821
|
+
const s = t.indexOf("="), i = t.substring(0, s), n = t.substring(s + 1).split(";")[0];
|
|
1822
|
+
this.cookies[i] = n;
|
|
1577
1823
|
} catch (s) {
|
|
1578
1824
|
logger.error(s);
|
|
1579
1825
|
}
|
|
1580
1826
|
}
|
|
1581
1827
|
getCookieRequestHeader() {
|
|
1582
1828
|
const e = [];
|
|
1583
|
-
for (const
|
|
1584
|
-
e.push(`${
|
|
1829
|
+
for (const t in this.cookies)
|
|
1830
|
+
e.push(`${t}=${this.cookies[t]}`);
|
|
1585
1831
|
return e.join("; ");
|
|
1586
1832
|
}
|
|
1587
1833
|
}
|
|
1588
|
-
function streamReadFileFromPHP(
|
|
1834
|
+
function streamReadFileFromPHP(r, e) {
|
|
1589
1835
|
return new ReadableStream({
|
|
1590
|
-
async pull(
|
|
1591
|
-
const s = await
|
|
1592
|
-
|
|
1836
|
+
async pull(t) {
|
|
1837
|
+
const s = await r.readFileAsBuffer(e);
|
|
1838
|
+
t.enqueue(s), t.close();
|
|
1593
1839
|
}
|
|
1594
1840
|
});
|
|
1595
1841
|
}
|
|
1596
|
-
async function* iteratePhpFiles(
|
|
1597
|
-
relativePaths:
|
|
1842
|
+
async function* iteratePhpFiles(r, e, {
|
|
1843
|
+
relativePaths: t = !0,
|
|
1598
1844
|
pathPrefix: s,
|
|
1599
1845
|
exceptPaths: i = []
|
|
1600
1846
|
} = {}) {
|
|
1601
1847
|
e = normalizePath(e);
|
|
1602
|
-
const
|
|
1603
|
-
for (;
|
|
1604
|
-
const
|
|
1605
|
-
if (!
|
|
1848
|
+
const n = [e];
|
|
1849
|
+
for (; n.length; ) {
|
|
1850
|
+
const o = n.pop();
|
|
1851
|
+
if (!o)
|
|
1606
1852
|
return;
|
|
1607
|
-
const
|
|
1608
|
-
for (const
|
|
1609
|
-
const p = `${
|
|
1853
|
+
const a = await r.listFiles(o);
|
|
1854
|
+
for (const l of a) {
|
|
1855
|
+
const p = `${o}/${l}`;
|
|
1610
1856
|
if (i.includes(p.substring(e.length + 1)))
|
|
1611
1857
|
continue;
|
|
1612
|
-
await
|
|
1613
|
-
streamReadFileFromPHP(
|
|
1614
|
-
|
|
1858
|
+
await r.isDir(p) ? n.push(p) : yield new StreamedFile(
|
|
1859
|
+
streamReadFileFromPHP(r, p),
|
|
1860
|
+
t ? joinPaths(
|
|
1615
1861
|
s || "",
|
|
1616
1862
|
p.substring(e.length + 1)
|
|
1617
1863
|
) : p
|
|
@@ -1619,13 +1865,13 @@ async function* iteratePhpFiles(t, e, {
|
|
|
1619
1865
|
}
|
|
1620
1866
|
}
|
|
1621
1867
|
}
|
|
1622
|
-
function writeFilesStreamToPhp(
|
|
1868
|
+
function writeFilesStreamToPhp(r, e) {
|
|
1623
1869
|
return new WritableStream({
|
|
1624
|
-
async write(
|
|
1625
|
-
const s = joinPaths(e,
|
|
1626
|
-
|
|
1870
|
+
async write(t) {
|
|
1871
|
+
const s = joinPaths(e, t.name);
|
|
1872
|
+
t.type === "directory" ? await r.mkdir(s) : (await r.mkdir(dirname(s)), await r.writeFile(
|
|
1627
1873
|
s,
|
|
1628
|
-
new Uint8Array(await
|
|
1874
|
+
new Uint8Array(await t.arrayBuffer())
|
|
1629
1875
|
));
|
|
1630
1876
|
}
|
|
1631
1877
|
});
|
|
@@ -1661,11 +1907,7 @@ class PHPProcessManager {
|
|
|
1661
1907
|
throw new Error(
|
|
1662
1908
|
"phpFactory or primaryPhp must be set before calling getPrimaryPhp()."
|
|
1663
1909
|
);
|
|
1664
|
-
|
|
1665
|
-
const e = await this.spawn({ isPrimary: !0 });
|
|
1666
|
-
this.primaryPhp = e.php;
|
|
1667
|
-
}
|
|
1668
|
-
return this.primaryPhp;
|
|
1910
|
+
return this.primaryPhp || (this.primaryPhpPromise || (this.primaryPhpPromise = this.spawn({ isPrimary: !0 })), this.primaryPhp = (await this.primaryPhpPromise).php, this.primaryPhpPromise = void 0), this.primaryPhp;
|
|
1669
1911
|
}
|
|
1670
1912
|
/**
|
|
1671
1913
|
* Get a PHP instance.
|
|
@@ -1674,17 +1916,32 @@ class PHPProcessManager {
|
|
|
1674
1916
|
* instance, or a newly spawned PHP instance – depending on the resource
|
|
1675
1917
|
* availability.
|
|
1676
1918
|
*
|
|
1919
|
+
* @param considerPrimary - Whether to consider the primary PHP instance.
|
|
1920
|
+
* It matters because PHP.cli() sets the SAPI to CLI and
|
|
1921
|
+
* kills the entire process after it finishes running,
|
|
1922
|
+
* making the primary PHP instance non-reusable for
|
|
1923
|
+
* subsequent .run() calls. This is fine for one-off
|
|
1924
|
+
* child PHP instances, but not for the primary PHP
|
|
1925
|
+
* that's meant to continue working for the entire duration
|
|
1926
|
+
* of the ProcessManager lifetime. Therefore, we don't
|
|
1927
|
+
* consider the primary PHP instance by default unless
|
|
1928
|
+
* the caller explicitly requests it.
|
|
1929
|
+
*
|
|
1677
1930
|
* @throws {MaxPhpInstancesError} when the maximum number of PHP instances is reached
|
|
1678
1931
|
* and the waiting timeout is exceeded.
|
|
1679
1932
|
*/
|
|
1680
|
-
async acquirePHPInstance(
|
|
1681
|
-
|
|
1933
|
+
async acquirePHPInstance({
|
|
1934
|
+
considerPrimary: e = !0
|
|
1935
|
+
} = {}) {
|
|
1936
|
+
if (this.primaryPhp || await this.getPrimaryPhp(), this.primaryIdle && e)
|
|
1682
1937
|
return this.primaryIdle = !1, {
|
|
1683
1938
|
php: await this.getPrimaryPhp(),
|
|
1684
|
-
reap: () =>
|
|
1939
|
+
reap: () => {
|
|
1940
|
+
this.primaryIdle = !0;
|
|
1941
|
+
}
|
|
1685
1942
|
};
|
|
1686
|
-
const
|
|
1687
|
-
return this.semaphore.remaining > 0 ? this.nextInstance = this.spawn({ isPrimary: !1 }) : this.nextInstance = null, await
|
|
1943
|
+
const t = this.nextInstance || this.spawn({ isPrimary: !1 });
|
|
1944
|
+
return this.semaphore.remaining > 0 ? this.nextInstance = this.spawn({ isPrimary: !1 }) : this.nextInstance = null, await t;
|
|
1688
1945
|
}
|
|
1689
1946
|
/**
|
|
1690
1947
|
* Initiated spawning of a new PHP instance.
|
|
@@ -1693,18 +1950,18 @@ class PHPProcessManager {
|
|
|
1693
1950
|
* for PHP to spawn.
|
|
1694
1951
|
*/
|
|
1695
1952
|
spawn(e) {
|
|
1696
|
-
if (e.isPrimary && this.
|
|
1953
|
+
if (e.isPrimary && this.primaryPhpPromise && !this.primaryPhp)
|
|
1697
1954
|
throw new Error(
|
|
1698
1955
|
"Requested spawning a primary PHP instance when another primary instance already started spawning."
|
|
1699
1956
|
);
|
|
1700
|
-
const
|
|
1701
|
-
this.allInstances.push(
|
|
1957
|
+
const t = this.doSpawn(e);
|
|
1958
|
+
this.allInstances.push(t);
|
|
1702
1959
|
const s = () => {
|
|
1703
1960
|
this.allInstances = this.allInstances.filter(
|
|
1704
|
-
(i) => i !==
|
|
1961
|
+
(i) => i !== t
|
|
1705
1962
|
);
|
|
1706
1963
|
};
|
|
1707
|
-
return
|
|
1964
|
+
return t.catch((i) => {
|
|
1708
1965
|
throw s(), i;
|
|
1709
1966
|
}).then((i) => ({
|
|
1710
1967
|
...i,
|
|
@@ -1717,9 +1974,9 @@ class PHPProcessManager {
|
|
|
1717
1974
|
* Actually acquires the lock and spawns a new PHP instance.
|
|
1718
1975
|
*/
|
|
1719
1976
|
async doSpawn(e) {
|
|
1720
|
-
let
|
|
1977
|
+
let t;
|
|
1721
1978
|
try {
|
|
1722
|
-
|
|
1979
|
+
t = await this.semaphore.acquire();
|
|
1723
1980
|
} catch (s) {
|
|
1724
1981
|
throw s instanceof AcquireTimeoutError ? new MaxPhpInstancesError(this.maxPhpInstances) : s;
|
|
1725
1982
|
}
|
|
@@ -1728,17 +1985,17 @@ class PHPProcessManager {
|
|
|
1728
1985
|
return {
|
|
1729
1986
|
php: s,
|
|
1730
1987
|
reap() {
|
|
1731
|
-
s.exit(),
|
|
1988
|
+
s.exit(), t();
|
|
1732
1989
|
}
|
|
1733
1990
|
};
|
|
1734
1991
|
} catch (s) {
|
|
1735
|
-
throw
|
|
1992
|
+
throw t(), s;
|
|
1736
1993
|
}
|
|
1737
1994
|
}
|
|
1738
1995
|
async [Symbol.asyncDispose]() {
|
|
1739
1996
|
this.primaryPhp && this.primaryPhp.exit(), await Promise.all(
|
|
1740
1997
|
this.allInstances.map(
|
|
1741
|
-
(e) => e.then(({ reap:
|
|
1998
|
+
(e) => e.then(({ reap: t }) => t())
|
|
1742
1999
|
)
|
|
1743
2000
|
);
|
|
1744
2001
|
}
|
|
@@ -1753,37 +2010,37 @@ const SupportedPHPVersions = [
|
|
|
1753
2010
|
"7.3",
|
|
1754
2011
|
"7.2"
|
|
1755
2012
|
], LatestSupportedPHPVersion = SupportedPHPVersions[0], SupportedPHPVersionsList = SupportedPHPVersions, DEFAULT_BASE_URL = "http://example.com";
|
|
1756
|
-
function toRelativeUrl(
|
|
1757
|
-
return
|
|
2013
|
+
function toRelativeUrl(r) {
|
|
2014
|
+
return r.toString().substring(r.origin.length);
|
|
1758
2015
|
}
|
|
1759
|
-
function removePathPrefix(
|
|
1760
|
-
return !e || !
|
|
2016
|
+
function removePathPrefix(r, e) {
|
|
2017
|
+
return !e || !r.startsWith(e) ? r : r.substring(e.length);
|
|
1761
2018
|
}
|
|
1762
|
-
function ensurePathPrefix(
|
|
1763
|
-
return !e ||
|
|
2019
|
+
function ensurePathPrefix(r, e) {
|
|
2020
|
+
return !e || r.startsWith(e) ? r : e + r;
|
|
1764
2021
|
}
|
|
1765
|
-
async function encodeAsMultipart(
|
|
1766
|
-
const e = `----${Math.random().toString(36).slice(2)}`,
|
|
1767
|
-
for (const [
|
|
2022
|
+
async function encodeAsMultipart(r) {
|
|
2023
|
+
const e = `----${Math.random().toString(36).slice(2)}`, t = `multipart/form-data; boundary=${e}`, s = new TextEncoder(), i = [];
|
|
2024
|
+
for (const [l, p] of Object.entries(r))
|
|
1768
2025
|
i.push(`--${e}\r
|
|
1769
|
-
`), i.push(`Content-Disposition: form-data; name="${
|
|
2026
|
+
`), i.push(`Content-Disposition: form-data; name="${l}"`), p instanceof File && i.push(`; filename="${p.name}"`), i.push(`\r
|
|
1770
2027
|
`), p instanceof File && (i.push("Content-Type: application/octet-stream"), i.push(`\r
|
|
1771
2028
|
`)), i.push(`\r
|
|
1772
2029
|
`), p instanceof File ? i.push(await fileToUint8Array(p)) : i.push(p), i.push(`\r
|
|
1773
2030
|
`);
|
|
1774
2031
|
i.push(`--${e}--\r
|
|
1775
2032
|
`);
|
|
1776
|
-
const
|
|
1777
|
-
let
|
|
1778
|
-
for (const
|
|
1779
|
-
|
|
1780
|
-
typeof
|
|
1781
|
-
|
|
1782
|
-
),
|
|
1783
|
-
return { bytes:
|
|
2033
|
+
const n = i.reduce((l, p) => l + p.length, 0), o = new Uint8Array(n);
|
|
2034
|
+
let a = 0;
|
|
2035
|
+
for (const l of i)
|
|
2036
|
+
o.set(
|
|
2037
|
+
typeof l == "string" ? s.encode(l) : l,
|
|
2038
|
+
a
|
|
2039
|
+
), a += l.length;
|
|
2040
|
+
return { bytes: o, contentType: t };
|
|
1784
2041
|
}
|
|
1785
|
-
function fileToUint8Array(
|
|
1786
|
-
return
|
|
2042
|
+
function fileToUint8Array(r) {
|
|
2043
|
+
return r.arrayBuffer().then((e) => new Uint8Array(e));
|
|
1787
2044
|
}
|
|
1788
2045
|
const _default = "application/octet-stream", asx = "video/x-ms-asf", atom = "application/atom+xml", avi = "video/x-msvideo", avif = "image/avif", bin = "application/octet-stream", bmp = "image/x-ms-bmp", cco = "application/x-cocoa", css = "text/css", data = "application/octet-stream", deb = "application/octet-stream", der = "application/x-x509-ca-cert", dmg = "application/octet-stream", doc = "application/msword", docx = "application/vnd.openxmlformats-officedocument.wordprocessingml.document", eot = "application/vnd.ms-fontobject", flv = "video/x-flv", gif = "image/gif", gz = "application/gzip", hqx = "application/mac-binhex40", htc = "text/x-component", html = "text/html", ico = "image/x-icon", iso = "application/octet-stream", jad = "text/vnd.sun.j2me.app-descriptor", jar = "application/java-archive", jardiff = "application/x-java-archive-diff", jng = "image/x-jng", jnlp = "application/x-java-jnlp-file", jpg = "image/jpeg", jpeg = "image/jpeg", js = "application/javascript", json = "application/json", kml = "application/vnd.google-earth.kml+xml", kmz = "application/vnd.google-earth.kmz", m3u8 = "application/vnd.apple.mpegurl", m4a = "audio/x-m4a", m4v = "video/x-m4v", md = "text/plain", mid = "audio/midi", mml = "text/mathml", mng = "video/x-mng", mov = "video/quicktime", mp3 = "audio/mpeg", mp4 = "video/mp4", mpeg = "video/mpeg", msi = "application/octet-stream", odg = "application/vnd.oasis.opendocument.graphics", odp = "application/vnd.oasis.opendocument.presentation", ods = "application/vnd.oasis.opendocument.spreadsheet", odt = "application/vnd.oasis.opendocument.text", ogg = "audio/ogg", otf = "font/otf", pdf = "application/pdf", pl = "application/x-perl", png = "image/png", ppt = "application/vnd.ms-powerpoint", pptx = "application/vnd.openxmlformats-officedocument.presentationml.presentation", prc = "application/x-pilot", ps = "application/postscript", ra = "audio/x-realaudio", rar = "application/x-rar-compressed", rpm = "application/x-redhat-package-manager", rss = "application/rss+xml", rtf = "application/rtf", run = "application/x-makeself", sea = "application/x-sea", sit = "application/x-stuffit", svg = "image/svg+xml", swf = "application/x-shockwave-flash", tcl = "application/x-tcl", tar = "application/x-tar", tif = "image/tiff", ts = "video/mp2t", ttf = "font/ttf", txt = "text/plain", wasm = "application/wasm", wbmp = "image/vnd.wap.wbmp", webm = "video/webm", webp = "image/webp", wml = "text/vnd.wap.wml", wmlc = "application/vnd.wap.wmlc", wmv = "video/x-ms-wmv", woff = "font/woff", woff2 = "font/woff2", xhtml = "application/xhtml+xml", xls = "application/vnd.ms-excel", xlsx = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", xml = "text/xml", xpi = "application/x-xpinstall", xspf = "application/xspf+xml", zip = "application/zip", mimeTypes = {
|
|
1789
2046
|
_default,
|
|
@@ -1881,7 +2138,7 @@ const _default = "application/octet-stream", asx = "video/x-ms-asf", atom = "app
|
|
|
1881
2138
|
xspf,
|
|
1882
2139
|
zip
|
|
1883
2140
|
};
|
|
1884
|
-
var g,
|
|
2141
|
+
var g, C, M, F, I, y, A, v, x, Z, ee, te;
|
|
1885
2142
|
class PHPRequestHandler {
|
|
1886
2143
|
/**
|
|
1887
2144
|
* The request handler needs to decide whether to serve a static asset or
|
|
@@ -1895,42 +2152,42 @@ class PHPRequestHandler {
|
|
|
1895
2152
|
* @param config - Request Handler configuration.
|
|
1896
2153
|
*/
|
|
1897
2154
|
constructor(e) {
|
|
1898
|
-
h(this,
|
|
2155
|
+
h(this, x);
|
|
1899
2156
|
h(this, g);
|
|
1900
|
-
h(this,
|
|
1901
|
-
h(this,
|
|
1902
|
-
h(this,
|
|
1903
|
-
h(this,
|
|
1904
|
-
h(this, f);
|
|
1905
|
-
h(this, b);
|
|
2157
|
+
h(this, C);
|
|
2158
|
+
h(this, M);
|
|
2159
|
+
h(this, F);
|
|
2160
|
+
h(this, I);
|
|
1906
2161
|
h(this, y);
|
|
2162
|
+
h(this, A);
|
|
2163
|
+
h(this, v);
|
|
1907
2164
|
const {
|
|
1908
|
-
documentRoot:
|
|
2165
|
+
documentRoot: t = "/www/",
|
|
1909
2166
|
absoluteUrl: s = typeof location == "object" ? location.href : DEFAULT_BASE_URL,
|
|
1910
2167
|
rewriteRules: i = [],
|
|
1911
|
-
getFileNotFoundAction:
|
|
2168
|
+
getFileNotFoundAction: n = () => ({ type: "404" })
|
|
1912
2169
|
} = e;
|
|
1913
2170
|
"processManager" in e ? this.processManager = e.processManager : this.processManager = new PHPProcessManager({
|
|
1914
|
-
phpFactory: async (
|
|
2171
|
+
phpFactory: async (l) => {
|
|
1915
2172
|
const p = await e.phpFactory({
|
|
1916
|
-
...
|
|
2173
|
+
...l,
|
|
1917
2174
|
requestHandler: this
|
|
1918
2175
|
});
|
|
1919
|
-
return p.requestHandler = this, p;
|
|
2176
|
+
return p.isDir(t) || p.mkdir(t), p.chdir(t), p.requestHandler = this, p;
|
|
1920
2177
|
},
|
|
1921
2178
|
maxPhpInstances: e.maxPhpInstances
|
|
1922
|
-
}),
|
|
1923
|
-
const
|
|
1924
|
-
|
|
1925
|
-
const
|
|
1926
|
-
|
|
1927
|
-
c(this,
|
|
1928
|
-
|
|
1929
|
-
].join("")),
|
|
1930
|
-
`${c(this,
|
|
1931
|
-
c(this,
|
|
1932
|
-
c(this,
|
|
1933
|
-
].join("")), this.rewriteRules = i, this.getFileNotFoundAction =
|
|
2179
|
+
}), f(this, v, e.cookieStore === void 0 ? new HttpCookieStore() : e.cookieStore), f(this, g, t);
|
|
2180
|
+
const o = new URL(s);
|
|
2181
|
+
f(this, M, o.hostname), f(this, F, o.port ? Number(o.port) : o.protocol === "https:" ? 443 : 80), f(this, C, (o.protocol || "").replace(":", ""));
|
|
2182
|
+
const a = c(this, F) !== 443 && c(this, F) !== 80;
|
|
2183
|
+
f(this, I, [
|
|
2184
|
+
c(this, M),
|
|
2185
|
+
a ? `:${c(this, F)}` : ""
|
|
2186
|
+
].join("")), f(this, y, o.pathname.replace(/\/+$/, "")), f(this, A, [
|
|
2187
|
+
`${c(this, C)}://`,
|
|
2188
|
+
c(this, I),
|
|
2189
|
+
c(this, y)
|
|
2190
|
+
].join("")), this.rewriteRules = i, this.getFileNotFoundAction = n;
|
|
1934
2191
|
}
|
|
1935
2192
|
async getPrimaryPhp() {
|
|
1936
2193
|
return await this.processManager.getPrimaryPhp();
|
|
@@ -1953,14 +2210,14 @@ class PHPRequestHandler {
|
|
|
1953
2210
|
* @returns The relative path.
|
|
1954
2211
|
*/
|
|
1955
2212
|
internalUrlToPath(e) {
|
|
1956
|
-
const
|
|
1957
|
-
return
|
|
2213
|
+
const t = new URL(e);
|
|
2214
|
+
return t.pathname.startsWith(c(this, y)) && (t.pathname = t.pathname.slice(c(this, y).length)), toRelativeUrl(t);
|
|
1958
2215
|
}
|
|
1959
2216
|
/**
|
|
1960
2217
|
* The absolute URL of this PHPRequestHandler instance.
|
|
1961
2218
|
*/
|
|
1962
2219
|
get absoluteUrl() {
|
|
1963
|
-
return c(this,
|
|
2220
|
+
return c(this, A);
|
|
1964
2221
|
}
|
|
1965
2222
|
/**
|
|
1966
2223
|
* The directory in the PHP filesystem where the server will look
|
|
@@ -2018,73 +2275,76 @@ class PHPRequestHandler {
|
|
|
2018
2275
|
* @param request - PHP Request data.
|
|
2019
2276
|
*/
|
|
2020
2277
|
async request(e) {
|
|
2021
|
-
const
|
|
2278
|
+
const t = URL.canParse(e.url), s = new URL(
|
|
2022
2279
|
// Remove the hash part of the URL as it's not meant for the server.
|
|
2023
2280
|
e.url.split("#")[0],
|
|
2024
|
-
|
|
2281
|
+
t ? void 0 : DEFAULT_BASE_URL
|
|
2025
2282
|
), i = applyRewriteRules(
|
|
2026
2283
|
removePathPrefix(
|
|
2027
2284
|
decodeURIComponent(s.pathname),
|
|
2028
|
-
c(this,
|
|
2285
|
+
c(this, y)
|
|
2029
2286
|
),
|
|
2030
2287
|
this.rewriteRules
|
|
2031
|
-
),
|
|
2032
|
-
let
|
|
2033
|
-
if (
|
|
2034
|
-
if (!
|
|
2288
|
+
), n = await this.getPrimaryPhp();
|
|
2289
|
+
let o = joinPaths(c(this, g), i);
|
|
2290
|
+
if (n.isDir(o)) {
|
|
2291
|
+
if (!o.endsWith("/"))
|
|
2035
2292
|
return new PHPResponse(
|
|
2036
2293
|
301,
|
|
2037
2294
|
{ Location: [`${s.pathname}/`] },
|
|
2038
2295
|
new Uint8Array(0)
|
|
2039
2296
|
);
|
|
2040
|
-
for (const
|
|
2041
|
-
const
|
|
2042
|
-
if (
|
|
2043
|
-
|
|
2297
|
+
for (const a of ["index.php", "index.html"]) {
|
|
2298
|
+
const l = joinPaths(o, a);
|
|
2299
|
+
if (n.isFile(l)) {
|
|
2300
|
+
o = l;
|
|
2044
2301
|
break;
|
|
2045
2302
|
}
|
|
2046
2303
|
}
|
|
2047
2304
|
}
|
|
2048
|
-
if (!
|
|
2049
|
-
const
|
|
2305
|
+
if (!n.isFile(o)) {
|
|
2306
|
+
const a = this.getFileNotFoundAction(
|
|
2050
2307
|
i
|
|
2051
2308
|
);
|
|
2052
|
-
switch (
|
|
2309
|
+
switch (a.type) {
|
|
2053
2310
|
case "response":
|
|
2054
|
-
return
|
|
2311
|
+
return a.response;
|
|
2055
2312
|
case "internal-redirect":
|
|
2056
|
-
|
|
2313
|
+
o = joinPaths(c(this, g), a.uri);
|
|
2057
2314
|
break;
|
|
2058
2315
|
case "404":
|
|
2059
2316
|
return PHPResponse.forHttpCode(404);
|
|
2060
2317
|
default:
|
|
2061
2318
|
throw new Error(
|
|
2062
|
-
`Unsupported file-not-found action type: '${
|
|
2319
|
+
`Unsupported file-not-found action type: '${a.type}'`
|
|
2063
2320
|
);
|
|
2064
2321
|
}
|
|
2065
2322
|
}
|
|
2066
|
-
if (
|
|
2067
|
-
if (
|
|
2068
|
-
const
|
|
2323
|
+
if (n.isFile(o))
|
|
2324
|
+
if (o.endsWith(".php")) {
|
|
2325
|
+
const a = {
|
|
2069
2326
|
...e,
|
|
2070
2327
|
// Pass along URL with the #fragment filtered out
|
|
2071
2328
|
url: s.toString()
|
|
2072
2329
|
};
|
|
2073
|
-
return d(this,
|
|
2330
|
+
return d(this, x, ee).call(this, a, o);
|
|
2074
2331
|
} else
|
|
2075
|
-
return d(this,
|
|
2332
|
+
return d(this, x, Z).call(this, n, o);
|
|
2076
2333
|
else
|
|
2077
2334
|
return PHPResponse.forHttpCode(404);
|
|
2078
2335
|
}
|
|
2336
|
+
async [Symbol.asyncDispose]() {
|
|
2337
|
+
await this.processManager[Symbol.asyncDispose]();
|
|
2338
|
+
}
|
|
2079
2339
|
}
|
|
2080
|
-
g = new WeakMap(),
|
|
2340
|
+
g = new WeakMap(), C = new WeakMap(), M = new WeakMap(), F = new WeakMap(), I = new WeakMap(), y = new WeakMap(), A = new WeakMap(), v = new WeakMap(), x = new WeakSet(), /**
|
|
2081
2341
|
* Serves a static file from the PHP filesystem.
|
|
2082
2342
|
*
|
|
2083
2343
|
* @param fsPath - Absolute path of the static file to serve.
|
|
2084
2344
|
* @returns The response.
|
|
2085
2345
|
*/
|
|
2086
|
-
|
|
2087
|
-
const s = e.readFileAsBuffer(
|
|
2346
|
+
Z = function(e, t) {
|
|
2347
|
+
const s = e.readFileAsBuffer(t);
|
|
2088
2348
|
return new PHPResponse(
|
|
2089
2349
|
200,
|
|
2090
2350
|
{
|
|
@@ -2092,78 +2352,80 @@ V = function(e, r) {
|
|
|
2092
2352
|
// @TODO: Infer the content-type from the arrayBuffer instead of the
|
|
2093
2353
|
// file path. The code below won't return the correct mime-type if the
|
|
2094
2354
|
// extension was tampered with.
|
|
2095
|
-
"content-type": [inferMimeType(
|
|
2355
|
+
"content-type": [inferMimeType(t)],
|
|
2096
2356
|
"accept-ranges": ["bytes"],
|
|
2097
2357
|
"cache-control": ["public, max-age=0"]
|
|
2098
2358
|
},
|
|
2099
2359
|
s
|
|
2100
2360
|
);
|
|
2101
|
-
},
|
|
2361
|
+
}, ee = async function(e, t) {
|
|
2102
2362
|
let s;
|
|
2103
2363
|
try {
|
|
2104
|
-
s = await this.processManager.acquirePHPInstance(
|
|
2364
|
+
s = await this.processManager.acquirePHPInstance({
|
|
2365
|
+
considerPrimary: !0
|
|
2366
|
+
});
|
|
2105
2367
|
} catch (i) {
|
|
2106
2368
|
return i instanceof MaxPhpInstancesError ? PHPResponse.forHttpCode(502) : PHPResponse.forHttpCode(500);
|
|
2107
2369
|
}
|
|
2108
2370
|
try {
|
|
2109
|
-
return await d(this,
|
|
2371
|
+
return await d(this, x, te).call(this, s.php, e, t);
|
|
2110
2372
|
} finally {
|
|
2111
2373
|
s.reap();
|
|
2112
2374
|
}
|
|
2113
|
-
},
|
|
2375
|
+
}, te = async function(e, t, s) {
|
|
2114
2376
|
let i = "GET";
|
|
2115
|
-
const
|
|
2116
|
-
host: c(this,
|
|
2117
|
-
...normalizeHeaders(
|
|
2377
|
+
const n = {
|
|
2378
|
+
host: c(this, I),
|
|
2379
|
+
...normalizeHeaders(t.headers || {})
|
|
2118
2380
|
};
|
|
2119
|
-
c(this,
|
|
2120
|
-
let
|
|
2121
|
-
if (typeof
|
|
2381
|
+
c(this, v) && (n.cookie = c(this, v).getCookieRequestHeader());
|
|
2382
|
+
let o = t.body;
|
|
2383
|
+
if (typeof o == "object" && !(o instanceof Uint8Array)) {
|
|
2122
2384
|
i = "POST";
|
|
2123
|
-
const { bytes:
|
|
2124
|
-
|
|
2385
|
+
const { bytes: a, contentType: l } = await encodeAsMultipart(o);
|
|
2386
|
+
o = a, n["content-type"] = l;
|
|
2125
2387
|
}
|
|
2126
2388
|
try {
|
|
2127
|
-
const
|
|
2389
|
+
const a = await e.run({
|
|
2128
2390
|
relativeUri: ensurePathPrefix(
|
|
2129
|
-
toRelativeUrl(new URL(
|
|
2130
|
-
c(this,
|
|
2391
|
+
toRelativeUrl(new URL(t.url)),
|
|
2392
|
+
c(this, y)
|
|
2131
2393
|
),
|
|
2132
|
-
protocol: c(this,
|
|
2133
|
-
method:
|
|
2394
|
+
protocol: c(this, C),
|
|
2395
|
+
method: t.method || i,
|
|
2134
2396
|
$_SERVER: {
|
|
2135
2397
|
REMOTE_ADDR: "127.0.0.1",
|
|
2136
2398
|
DOCUMENT_ROOT: c(this, g),
|
|
2137
|
-
HTTPS: c(this,
|
|
2399
|
+
HTTPS: c(this, A).startsWith("https://") ? "on" : ""
|
|
2138
2400
|
},
|
|
2139
|
-
body:
|
|
2401
|
+
body: o,
|
|
2140
2402
|
scriptPath: s,
|
|
2141
|
-
headers:
|
|
2403
|
+
headers: n
|
|
2142
2404
|
});
|
|
2143
|
-
return c(this,
|
|
2144
|
-
|
|
2145
|
-
),
|
|
2146
|
-
} catch (
|
|
2147
|
-
const
|
|
2148
|
-
if (
|
|
2149
|
-
return
|
|
2150
|
-
throw
|
|
2405
|
+
return c(this, v) && c(this, v).rememberCookiesFromResponseHeaders(
|
|
2406
|
+
a.headers
|
|
2407
|
+
), a;
|
|
2408
|
+
} catch (a) {
|
|
2409
|
+
const l = a;
|
|
2410
|
+
if (l != null && l.response)
|
|
2411
|
+
return l.response;
|
|
2412
|
+
throw a;
|
|
2151
2413
|
}
|
|
2152
2414
|
};
|
|
2153
|
-
function inferMimeType(
|
|
2154
|
-
const e =
|
|
2415
|
+
function inferMimeType(r) {
|
|
2416
|
+
const e = r.split(".").pop();
|
|
2155
2417
|
return mimeTypes[e] || mimeTypes._default;
|
|
2156
2418
|
}
|
|
2157
|
-
function applyRewriteRules(
|
|
2158
|
-
for (const
|
|
2159
|
-
if (new RegExp(
|
|
2160
|
-
return
|
|
2161
|
-
return
|
|
2419
|
+
function applyRewriteRules(r, e) {
|
|
2420
|
+
for (const t of e)
|
|
2421
|
+
if (new RegExp(t.match).test(r))
|
|
2422
|
+
return r.replace(t.match, t.replacement);
|
|
2423
|
+
return r;
|
|
2162
2424
|
}
|
|
2163
2425
|
function rotatePHPRuntime({
|
|
2164
|
-
php:
|
|
2426
|
+
php: r,
|
|
2165
2427
|
cwd: e,
|
|
2166
|
-
recreateRuntime:
|
|
2428
|
+
recreateRuntime: t,
|
|
2167
2429
|
/*
|
|
2168
2430
|
* 400 is an arbitrary number that should trigger a rotation
|
|
2169
2431
|
* way before the memory gets too fragmented. If it doesn't,
|
|
@@ -2175,64 +2437,180 @@ function rotatePHPRuntime({
|
|
|
2175
2437
|
maxRequests: s = 400
|
|
2176
2438
|
}) {
|
|
2177
2439
|
let i = 0;
|
|
2178
|
-
async function
|
|
2179
|
-
const
|
|
2440
|
+
async function n() {
|
|
2441
|
+
const l = await r.semaphore.acquire();
|
|
2180
2442
|
try {
|
|
2181
|
-
await
|
|
2443
|
+
await r.hotSwapPHPRuntime(await t(), e), i = 0;
|
|
2182
2444
|
} finally {
|
|
2183
|
-
|
|
2445
|
+
l();
|
|
2184
2446
|
}
|
|
2185
2447
|
}
|
|
2186
|
-
async function
|
|
2187
|
-
++i < s || await
|
|
2448
|
+
async function o() {
|
|
2449
|
+
++i < s || await n();
|
|
2188
2450
|
}
|
|
2189
|
-
async function l
|
|
2190
|
-
|
|
2451
|
+
async function a(l) {
|
|
2452
|
+
l.type === "request.error" && l.source === "php-wasm" && await n();
|
|
2191
2453
|
}
|
|
2192
|
-
return
|
|
2193
|
-
|
|
2454
|
+
return r.addEventListener("request.error", a), r.addEventListener("request.end", o), function() {
|
|
2455
|
+
r.removeEventListener("request.error", a), r.removeEventListener("request.end", o);
|
|
2194
2456
|
};
|
|
2195
2457
|
}
|
|
2196
|
-
async function writeFiles(
|
|
2197
|
-
s && await
|
|
2198
|
-
for (const [i,
|
|
2199
|
-
const
|
|
2200
|
-
await
|
|
2458
|
+
async function writeFiles(r, e, t, { rmRoot: s = !1 } = {}) {
|
|
2459
|
+
s && await r.isDir(e) && await r.rmdir(e, { recursive: !0 });
|
|
2460
|
+
for (const [i, n] of Object.entries(t)) {
|
|
2461
|
+
const o = joinPaths(e, i);
|
|
2462
|
+
await r.fileExists(dirname(o)) || await r.mkdir(dirname(o)), n instanceof Uint8Array || typeof n == "string" ? await r.writeFile(o, n) : await writeFiles(r, o, n);
|
|
2201
2463
|
}
|
|
2202
2464
|
}
|
|
2203
|
-
function proxyFileSystem(
|
|
2204
|
-
const s = Object.getOwnPropertySymbols(
|
|
2205
|
-
for (const i of
|
|
2206
|
-
e.fileExists(i) || e.mkdir(i),
|
|
2465
|
+
function proxyFileSystem(r, e, t) {
|
|
2466
|
+
const s = Object.getOwnPropertySymbols(r)[0];
|
|
2467
|
+
for (const i of t)
|
|
2468
|
+
e.fileExists(i) || e.mkdir(i), r.fileExists(i) || r.mkdir(i), e[s].FS.mount(
|
|
2207
2469
|
// @ts-ignore
|
|
2208
2470
|
e[s].PROXYFS,
|
|
2209
2471
|
{
|
|
2210
2472
|
root: i,
|
|
2211
2473
|
// @ts-ignore
|
|
2212
|
-
fs:
|
|
2474
|
+
fs: r[s].FS
|
|
2213
2475
|
},
|
|
2214
2476
|
i
|
|
2215
2477
|
);
|
|
2216
2478
|
}
|
|
2479
|
+
/**
|
|
2480
|
+
* @license
|
|
2481
|
+
* Copyright 2019 Google LLC
|
|
2482
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
2483
|
+
*/
|
|
2484
|
+
function nodeEndpoint(r) {
|
|
2485
|
+
const e = /* @__PURE__ */ new WeakMap();
|
|
2486
|
+
return {
|
|
2487
|
+
postMessage: r.postMessage.bind(r),
|
|
2488
|
+
addEventListener: (t, s) => {
|
|
2489
|
+
const i = (n) => {
|
|
2490
|
+
"handleEvent" in s ? s.handleEvent({ data: n }) : s({ data: n });
|
|
2491
|
+
};
|
|
2492
|
+
r.on("message", i), e.set(s, i);
|
|
2493
|
+
},
|
|
2494
|
+
removeEventListener: (t, s) => {
|
|
2495
|
+
const i = e.get(s);
|
|
2496
|
+
i && (r.off("message", i), e.delete(s));
|
|
2497
|
+
},
|
|
2498
|
+
start: r.start && r.start.bind(r)
|
|
2499
|
+
};
|
|
2500
|
+
}
|
|
2501
|
+
function consumeAPI(r, e = void 0) {
|
|
2502
|
+
setupTransferHandlers();
|
|
2503
|
+
let t;
|
|
2504
|
+
import.meta.url.startsWith("file://") ? t = nodeEndpoint(r) : t = r instanceof Worker ? r : Comlink.windowEndpoint(r, e);
|
|
2505
|
+
const i = Comlink.wrap(t), n = proxyClone(i);
|
|
2506
|
+
return new Proxy(n, {
|
|
2507
|
+
get: (o, a) => a === "isConnected" ? async () => {
|
|
2508
|
+
for (; ; )
|
|
2509
|
+
try {
|
|
2510
|
+
await runWithTimeout(i.isConnected(), 200);
|
|
2511
|
+
break;
|
|
2512
|
+
} catch {
|
|
2513
|
+
}
|
|
2514
|
+
} : i[a]
|
|
2515
|
+
});
|
|
2516
|
+
}
|
|
2517
|
+
async function runWithTimeout(r, e) {
|
|
2518
|
+
return new Promise((t, s) => {
|
|
2519
|
+
setTimeout(s, e), r.then(t);
|
|
2520
|
+
});
|
|
2521
|
+
}
|
|
2522
|
+
function exposeAPI(r, e, t) {
|
|
2523
|
+
setupTransferHandlers();
|
|
2524
|
+
const s = Promise.resolve();
|
|
2525
|
+
let i, n;
|
|
2526
|
+
const o = new Promise((E, m) => {
|
|
2527
|
+
i = E, n = m;
|
|
2528
|
+
}), a = proxyClone(r), l = new Proxy(a, {
|
|
2529
|
+
get: (E, m) => m === "isConnected" ? () => s : m === "isReady" ? () => o : m in E ? E[m] : e == null ? void 0 : e[m]
|
|
2530
|
+
});
|
|
2531
|
+
let p;
|
|
2532
|
+
return t ? p = nodeEndpoint(t) : p = typeof window < "u" ? Comlink.windowEndpoint(self.parent) : void 0, Comlink.expose(l, p), [i, n, l];
|
|
2533
|
+
}
|
|
2534
|
+
let isTransferHandlersSetup = !1;
|
|
2535
|
+
function setupTransferHandlers() {
|
|
2536
|
+
if (isTransferHandlersSetup)
|
|
2537
|
+
return;
|
|
2538
|
+
isTransferHandlersSetup = !0, Comlink.transferHandlers.set("EVENT", {
|
|
2539
|
+
canHandle: (t) => t instanceof CustomEvent,
|
|
2540
|
+
serialize: (t) => [
|
|
2541
|
+
{
|
|
2542
|
+
detail: t.detail
|
|
2543
|
+
},
|
|
2544
|
+
[]
|
|
2545
|
+
],
|
|
2546
|
+
deserialize: (t) => t
|
|
2547
|
+
}), Comlink.transferHandlers.set("FUNCTION", {
|
|
2548
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
2549
|
+
canHandle: (t) => typeof t == "function",
|
|
2550
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
2551
|
+
serialize(t) {
|
|
2552
|
+
const { port1: s, port2: i } = new MessageChannel();
|
|
2553
|
+
return Comlink.expose(t, s), [i, [i]];
|
|
2554
|
+
},
|
|
2555
|
+
deserialize(t) {
|
|
2556
|
+
return t.start(), Comlink.wrap(t);
|
|
2557
|
+
}
|
|
2558
|
+
}), Comlink.transferHandlers.set("PHPResponse", {
|
|
2559
|
+
canHandle: (t) => typeof t == "object" && t !== null && "headers" in t && "bytes" in t && "errors" in t && "exitCode" in t && "httpStatusCode" in t,
|
|
2560
|
+
serialize(t) {
|
|
2561
|
+
return [t.toRawData(), []];
|
|
2562
|
+
},
|
|
2563
|
+
deserialize(t) {
|
|
2564
|
+
return PHPResponse.fromRawData(t);
|
|
2565
|
+
}
|
|
2566
|
+
});
|
|
2567
|
+
const r = Comlink.transferHandlers.get("throw"), e = r == null ? void 0 : r.serialize;
|
|
2568
|
+
r.serialize = ({ value: t }) => {
|
|
2569
|
+
const s = e({ value: t });
|
|
2570
|
+
return t.response && (s[0].value.response = t.response), t.source && (s[0].value.source = t.source), s;
|
|
2571
|
+
};
|
|
2572
|
+
}
|
|
2573
|
+
function proxyClone(r) {
|
|
2574
|
+
return new Proxy(r, {
|
|
2575
|
+
get(e, t) {
|
|
2576
|
+
switch (typeof e[t]) {
|
|
2577
|
+
case "function":
|
|
2578
|
+
return (...s) => e[t](...s);
|
|
2579
|
+
case "object":
|
|
2580
|
+
return e[t] === null ? e[t] : proxyClone(e[t]);
|
|
2581
|
+
case "undefined":
|
|
2582
|
+
case "number":
|
|
2583
|
+
case "string":
|
|
2584
|
+
return e[t];
|
|
2585
|
+
default:
|
|
2586
|
+
return Comlink.proxy(e[t]);
|
|
2587
|
+
}
|
|
2588
|
+
}
|
|
2589
|
+
});
|
|
2590
|
+
}
|
|
2217
2591
|
export {
|
|
2218
2592
|
DEFAULT_BASE_URL,
|
|
2219
2593
|
FSHelpers,
|
|
2220
2594
|
HttpCookieStore,
|
|
2221
2595
|
LatestSupportedPHPVersion,
|
|
2222
2596
|
PHP,
|
|
2597
|
+
PHPExecutionFailureError,
|
|
2223
2598
|
PHPProcessManager,
|
|
2224
2599
|
PHPRequestHandler,
|
|
2225
2600
|
PHPResponse,
|
|
2226
2601
|
PHPWorker,
|
|
2602
|
+
StreamedPHPResponse,
|
|
2227
2603
|
SupportedPHPVersions,
|
|
2228
2604
|
SupportedPHPVersionsList,
|
|
2229
2605
|
UnhandledRejectionsTarget,
|
|
2230
2606
|
__private__dont__use,
|
|
2231
2607
|
applyRewriteRules,
|
|
2608
|
+
consumeAPI,
|
|
2232
2609
|
ensurePathPrefix,
|
|
2610
|
+
exposeAPI,
|
|
2233
2611
|
getLoadedRuntime,
|
|
2234
2612
|
getPhpIniEntries,
|
|
2235
|
-
|
|
2613
|
+
isExitCode,
|
|
2236
2614
|
iteratePhpFiles as iterateFiles,
|
|
2237
2615
|
loadPHPRuntime,
|
|
2238
2616
|
proxyFileSystem,
|