@php-wasm/universal 0.7.0 → 0.7.3
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 +14 -12
- package/index.js +1360 -1032
- package/lib/base-php.d.ts +10 -6
- package/lib/index.d.ts +3 -0
- package/lib/php-process-manager.d.ts +104 -0
- package/lib/php-request-handler.d.ts +38 -8
- package/lib/php-response.d.ts +1 -0
- package/lib/universal-php.d.ts +7 -1
- package/package.json +2 -2
package/index.js
CHANGED
|
@@ -2,11 +2,11 @@ var Q = (e, t, r) => {
|
|
|
2
2
|
if (!t.has(e))
|
|
3
3
|
throw TypeError("Cannot " + r);
|
|
4
4
|
};
|
|
5
|
-
var
|
|
5
|
+
var u = (e, t, r) => (Q(e, t, "read from private field"), r ? r.call(e) : t.get(e)), h = (e, t, r) => {
|
|
6
6
|
if (t.has(e))
|
|
7
7
|
throw TypeError("Cannot add the same private member more than once");
|
|
8
8
|
t instanceof WeakSet ? t.add(e) : t.set(e, r);
|
|
9
|
-
},
|
|
9
|
+
}, d = (e, t, r, s) => (Q(e, t, "write to private field"), s ? s.call(e, r) : t.set(e, r), r);
|
|
10
10
|
var p = (e, t, r) => (Q(e, t, "access private method"), r);
|
|
11
11
|
const currentJsRuntime$1 = function() {
|
|
12
12
|
var e;
|
|
@@ -19,8 +19,8 @@ const currentJsRuntime$1 = function() {
|
|
|
19
19
|
if (currentJsRuntime$1 === "NODE") {
|
|
20
20
|
let e = function(r) {
|
|
21
21
|
return new Promise(function(s, n) {
|
|
22
|
-
r.onload = r.onerror = function(
|
|
23
|
-
r.onload = r.onerror = null,
|
|
22
|
+
r.onload = r.onerror = function(i) {
|
|
23
|
+
r.onload = r.onerror = null, i.type === "load" ? s(r.result) : n(new Error("Failed to read the blob/file"));
|
|
24
24
|
};
|
|
25
25
|
});
|
|
26
26
|
}, t = function() {
|
|
@@ -33,10 +33,10 @@ if (currentJsRuntime$1 === "NODE") {
|
|
|
33
33
|
};
|
|
34
34
|
if (typeof File > "u") {
|
|
35
35
|
class r extends Blob {
|
|
36
|
-
constructor(n,
|
|
36
|
+
constructor(n, i, o) {
|
|
37
37
|
super(n);
|
|
38
38
|
let a;
|
|
39
|
-
|
|
39
|
+
o != null && o.lastModified && (a = /* @__PURE__ */ new Date()), (!a || isNaN(a.getFullYear())) && (a = /* @__PURE__ */ new Date()), this.lastModifiedDate = a, this.lastModified = a.getMilliseconds(), this.name = i || "";
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
global.File = r;
|
|
@@ -56,13 +56,13 @@ if (currentJsRuntime$1 === "NODE") {
|
|
|
56
56
|
// this if needed.
|
|
57
57
|
autoAllocateChunkSize: 512 * 1024,
|
|
58
58
|
async pull(n) {
|
|
59
|
-
const
|
|
59
|
+
const i = n.byobRequest.view, a = await s.slice(
|
|
60
60
|
r,
|
|
61
|
-
r +
|
|
62
|
-
).arrayBuffer(),
|
|
63
|
-
new Uint8Array(
|
|
64
|
-
const
|
|
65
|
-
n.byobRequest.respond(
|
|
61
|
+
r + i.byteLength
|
|
62
|
+
).arrayBuffer(), l = new Uint8Array(a);
|
|
63
|
+
new Uint8Array(i.buffer).set(l);
|
|
64
|
+
const c = l.byteLength;
|
|
65
|
+
n.byobRequest.respond(c), r += c, r >= s.size && n.close();
|
|
66
66
|
}
|
|
67
67
|
});
|
|
68
68
|
});
|
|
@@ -102,6 +102,171 @@ const ErrorEvent = typeof globalThis.ErrorEvent == "function" ? globalThis.Error
|
|
|
102
102
|
function isExitCodeZero(e) {
|
|
103
103
|
return e instanceof Error ? "exitCode" in e && (e == null ? void 0 : e.exitCode) === 0 || (e == null ? void 0 : e.name) === "ExitStatus" && "status" in e && e.status === 0 : !1;
|
|
104
104
|
}
|
|
105
|
+
const logToConsole = (e, ...t) => {
|
|
106
|
+
switch (e.severity) {
|
|
107
|
+
case "Debug":
|
|
108
|
+
console.debug(e.message, ...t);
|
|
109
|
+
break;
|
|
110
|
+
case "Info":
|
|
111
|
+
console.info(e.message, ...t);
|
|
112
|
+
break;
|
|
113
|
+
case "Warn":
|
|
114
|
+
console.warn(e.message, ...t);
|
|
115
|
+
break;
|
|
116
|
+
case "Error":
|
|
117
|
+
console.error(e.message, ...t);
|
|
118
|
+
break;
|
|
119
|
+
case "Fatal":
|
|
120
|
+
console.error(e.message, ...t);
|
|
121
|
+
break;
|
|
122
|
+
default:
|
|
123
|
+
console.log(e.message, ...t);
|
|
124
|
+
}
|
|
125
|
+
}, prepareLogMessage = (e, ...t) => [
|
|
126
|
+
typeof e == "object" ? JSON.stringify(e) : e,
|
|
127
|
+
...t.map((r) => JSON.stringify(r))
|
|
128
|
+
].join(" "), logs = [], addToLogArray = (e) => {
|
|
129
|
+
logs.push(e);
|
|
130
|
+
}, logToMemory = (e) => {
|
|
131
|
+
if (e.raw === !0)
|
|
132
|
+
addToLogArray(e.message);
|
|
133
|
+
else {
|
|
134
|
+
const t = formatLogEntry(
|
|
135
|
+
typeof e.message == "object" ? prepareLogMessage(e.message) : e.message,
|
|
136
|
+
e.severity ?? "Info",
|
|
137
|
+
e.prefix ?? "JavaScript"
|
|
138
|
+
);
|
|
139
|
+
addToLogArray(t);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
class Logger extends EventTarget {
|
|
143
|
+
// constructor
|
|
144
|
+
constructor(t = []) {
|
|
145
|
+
super(), this.handlers = t, this.fatalErrorEvent = "playground-fatal-error";
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Get all logs.
|
|
149
|
+
* @returns string[]
|
|
150
|
+
*/
|
|
151
|
+
getLogs() {
|
|
152
|
+
return this.handlers.includes(logToMemory) ? [...logs] : (this.error(`Logs aren't stored because the logToMemory handler isn't registered.
|
|
153
|
+
If you're using a custom logger instance, make sure to register logToMemory handler.
|
|
154
|
+
`), []);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Log message with severity.
|
|
158
|
+
*
|
|
159
|
+
* @param message any
|
|
160
|
+
* @param severity LogSeverity
|
|
161
|
+
* @param raw boolean
|
|
162
|
+
* @param args any
|
|
163
|
+
*/
|
|
164
|
+
logMessage(t, ...r) {
|
|
165
|
+
for (const s of this.handlers)
|
|
166
|
+
s(t, ...r);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Log message
|
|
170
|
+
*
|
|
171
|
+
* @param message any
|
|
172
|
+
* @param args any
|
|
173
|
+
*/
|
|
174
|
+
log(t, ...r) {
|
|
175
|
+
this.logMessage(
|
|
176
|
+
{
|
|
177
|
+
message: t,
|
|
178
|
+
severity: void 0,
|
|
179
|
+
prefix: "JavaScript",
|
|
180
|
+
raw: !1
|
|
181
|
+
},
|
|
182
|
+
...r
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Log debug message
|
|
187
|
+
*
|
|
188
|
+
* @param message any
|
|
189
|
+
* @param args any
|
|
190
|
+
*/
|
|
191
|
+
debug(t, ...r) {
|
|
192
|
+
this.logMessage(
|
|
193
|
+
{
|
|
194
|
+
message: t,
|
|
195
|
+
severity: "Debug",
|
|
196
|
+
prefix: "JavaScript",
|
|
197
|
+
raw: !1
|
|
198
|
+
},
|
|
199
|
+
...r
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Log info message
|
|
204
|
+
*
|
|
205
|
+
* @param message any
|
|
206
|
+
* @param args any
|
|
207
|
+
*/
|
|
208
|
+
info(t, ...r) {
|
|
209
|
+
this.logMessage(
|
|
210
|
+
{
|
|
211
|
+
message: t,
|
|
212
|
+
severity: "Info",
|
|
213
|
+
prefix: "JavaScript",
|
|
214
|
+
raw: !1
|
|
215
|
+
},
|
|
216
|
+
...r
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Log warning message
|
|
221
|
+
*
|
|
222
|
+
* @param message any
|
|
223
|
+
* @param args any
|
|
224
|
+
*/
|
|
225
|
+
warn(t, ...r) {
|
|
226
|
+
this.logMessage(
|
|
227
|
+
{
|
|
228
|
+
message: t,
|
|
229
|
+
severity: "Warn",
|
|
230
|
+
prefix: "JavaScript",
|
|
231
|
+
raw: !1
|
|
232
|
+
},
|
|
233
|
+
...r
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Log error message
|
|
238
|
+
*
|
|
239
|
+
* @param message any
|
|
240
|
+
* @param args any
|
|
241
|
+
*/
|
|
242
|
+
error(t, ...r) {
|
|
243
|
+
this.logMessage(
|
|
244
|
+
{
|
|
245
|
+
message: t,
|
|
246
|
+
severity: "Error",
|
|
247
|
+
prefix: "JavaScript",
|
|
248
|
+
raw: !1
|
|
249
|
+
},
|
|
250
|
+
...r
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
const logger = new Logger([logToMemory, logToConsole]), formatLogEntry = (e, t, r) => {
|
|
255
|
+
const s = /* @__PURE__ */ new Date(), n = new Intl.DateTimeFormat("en-GB", {
|
|
256
|
+
year: "numeric",
|
|
257
|
+
month: "short",
|
|
258
|
+
day: "2-digit",
|
|
259
|
+
timeZone: "UTC"
|
|
260
|
+
}).format(s).replace(/ /g, "-"), i = new Intl.DateTimeFormat("en-GB", {
|
|
261
|
+
hour: "2-digit",
|
|
262
|
+
minute: "2-digit",
|
|
263
|
+
second: "2-digit",
|
|
264
|
+
hour12: !1,
|
|
265
|
+
timeZone: "UTC",
|
|
266
|
+
timeZoneName: "short"
|
|
267
|
+
}).format(s);
|
|
268
|
+
return `[${n + " " + i}] ${r} ${t}: ${e}`;
|
|
269
|
+
};
|
|
105
270
|
class UnhandledRejectionsTarget extends EventTarget {
|
|
106
271
|
constructor() {
|
|
107
272
|
super(...arguments), this.listenersCount = 0;
|
|
@@ -125,26 +290,26 @@ function improveWASMErrorReporting(e) {
|
|
|
125
290
|
if (typeof e.asm[r] == "function") {
|
|
126
291
|
const s = e.asm[r];
|
|
127
292
|
e.asm[r] = function(...n) {
|
|
128
|
-
var
|
|
293
|
+
var i;
|
|
129
294
|
try {
|
|
130
295
|
return s(...n);
|
|
131
|
-
} catch (
|
|
132
|
-
if (!(
|
|
133
|
-
throw
|
|
296
|
+
} catch (o) {
|
|
297
|
+
if (!(o instanceof Error))
|
|
298
|
+
throw o;
|
|
134
299
|
const a = clarifyErrorMessage(
|
|
135
|
-
|
|
136
|
-
(
|
|
300
|
+
o,
|
|
301
|
+
(i = e.lastAsyncifyStackSource) == null ? void 0 : i.stack
|
|
137
302
|
);
|
|
138
|
-
if (e.lastAsyncifyStackSource && (
|
|
303
|
+
if (e.lastAsyncifyStackSource && (o.cause = e.lastAsyncifyStackSource), t.hasListeners()) {
|
|
139
304
|
t.dispatchEvent(
|
|
140
305
|
new ErrorEvent("error", {
|
|
141
|
-
error:
|
|
306
|
+
error: o,
|
|
142
307
|
message: a
|
|
143
308
|
})
|
|
144
309
|
);
|
|
145
310
|
return;
|
|
146
311
|
}
|
|
147
|
-
throw isExitCodeZero(
|
|
312
|
+
throw isExitCodeZero(o) || showCriticalErrorBox(a), o;
|
|
148
313
|
}
|
|
149
314
|
};
|
|
150
315
|
}
|
|
@@ -200,13 +365,13 @@ CLI option:
|
|
|
200
365
|
let logged = !1;
|
|
201
366
|
function showCriticalErrorBox(e) {
|
|
202
367
|
if (!logged && (logged = !0, !(e != null && e.trim().startsWith("Program terminated with exit")))) {
|
|
203
|
-
|
|
368
|
+
logger.log(`${redBg}
|
|
204
369
|
${eol}
|
|
205
370
|
${bold} WASM ERROR${reset}${redBg}`);
|
|
206
371
|
for (const t of e.split(`
|
|
207
372
|
`))
|
|
208
|
-
|
|
209
|
-
|
|
373
|
+
logger.log(`${eol} ${t} `);
|
|
374
|
+
logger.log(`${reset}`);
|
|
210
375
|
}
|
|
211
376
|
}
|
|
212
377
|
function extractPHPFunctionsFromStack(e) {
|
|
@@ -226,6 +391,29 @@ function extractPHPFunctionsFromStack(e) {
|
|
|
226
391
|
return [];
|
|
227
392
|
}
|
|
228
393
|
}
|
|
394
|
+
class HttpCookieStore {
|
|
395
|
+
constructor() {
|
|
396
|
+
this.cookies = {};
|
|
397
|
+
}
|
|
398
|
+
rememberCookiesFromResponseHeaders(t) {
|
|
399
|
+
if (t != null && t["set-cookie"])
|
|
400
|
+
for (const r of t["set-cookie"])
|
|
401
|
+
try {
|
|
402
|
+
if (!r.includes("="))
|
|
403
|
+
continue;
|
|
404
|
+
const s = r.indexOf("="), n = r.substring(0, s), i = r.substring(s + 1).split(";")[0];
|
|
405
|
+
this.cookies[n] = i;
|
|
406
|
+
} catch (s) {
|
|
407
|
+
logger.error(s);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
getCookieRequestHeader() {
|
|
411
|
+
const t = [];
|
|
412
|
+
for (const r in this.cookies)
|
|
413
|
+
t.push(`${r}=${this.cookies[r]}`);
|
|
414
|
+
return t.join("; ");
|
|
415
|
+
}
|
|
416
|
+
}
|
|
229
417
|
const SleepFinished = Symbol("SleepFinished");
|
|
230
418
|
function sleep(e) {
|
|
231
419
|
return new Promise((t) => {
|
|
@@ -308,28 +496,33 @@ function normalizePathsArray(e, t) {
|
|
|
308
496
|
}
|
|
309
497
|
function splitShellCommand(e) {
|
|
310
498
|
let s = 0, n = "";
|
|
311
|
-
const
|
|
312
|
-
let
|
|
499
|
+
const i = [];
|
|
500
|
+
let o = "";
|
|
313
501
|
for (let a = 0; a < e.length; a++) {
|
|
314
|
-
const
|
|
315
|
-
|
|
502
|
+
const l = e[a];
|
|
503
|
+
l === "\\" ? ((e[a + 1] === '"' || e[a + 1] === "'") && a++, o += e[a]) : s === 0 ? l === '"' || l === "'" ? (s = 1, n = l) : l.match(/\s/) ? (o.trim().length && i.push(o.trim()), o = l) : i.length && !o ? o = i.pop() + l : o += l : s === 1 && (l === n ? (s = 0, n = "") : o += l);
|
|
316
504
|
}
|
|
317
|
-
return
|
|
505
|
+
return o && i.push(o.trim()), i;
|
|
318
506
|
}
|
|
319
507
|
function createSpawnHandler(e) {
|
|
320
508
|
return function(t, r = [], s = {}) {
|
|
321
|
-
const n = new ChildProcess(),
|
|
509
|
+
const n = new ChildProcess(), i = new ProcessApi(n);
|
|
322
510
|
return setTimeout(async () => {
|
|
323
|
-
let
|
|
511
|
+
let o = [];
|
|
324
512
|
if (r.length)
|
|
325
|
-
|
|
513
|
+
o = [t, ...r];
|
|
326
514
|
else if (typeof t == "string")
|
|
327
|
-
|
|
515
|
+
o = splitShellCommand(t);
|
|
328
516
|
else if (Array.isArray(t))
|
|
329
|
-
|
|
517
|
+
o = t;
|
|
330
518
|
else
|
|
331
519
|
throw new Error("Invalid command ", t);
|
|
332
|
-
|
|
520
|
+
try {
|
|
521
|
+
await e(o, i, s);
|
|
522
|
+
} catch (a) {
|
|
523
|
+
n.emit("error", a), typeof a == "object" && a !== null && "message" in a && typeof a.message == "string" && i.stderr(a.message), i.exit(1);
|
|
524
|
+
}
|
|
525
|
+
n.emit("spawn", !0);
|
|
333
526
|
}), n;
|
|
334
527
|
};
|
|
335
528
|
}
|
|
@@ -430,14 +623,14 @@ function limitBytes(e, t) {
|
|
|
430
623
|
let s = 0;
|
|
431
624
|
return new ReadableStream({
|
|
432
625
|
async pull(n) {
|
|
433
|
-
const { value:
|
|
626
|
+
const { value: i, done: o } = await r.read(
|
|
434
627
|
new Uint8Array(t - s)
|
|
435
628
|
);
|
|
436
|
-
if (
|
|
629
|
+
if (o) {
|
|
437
630
|
r.releaseLock(), n.close();
|
|
438
631
|
return;
|
|
439
632
|
}
|
|
440
|
-
s +=
|
|
633
|
+
s += i.length, n.enqueue(i), s >= t && (r.releaseLock(), n.close());
|
|
441
634
|
},
|
|
442
635
|
cancel() {
|
|
443
636
|
r.cancel();
|
|
@@ -519,22 +712,22 @@ async function* iteratePhpFiles(e, t, {
|
|
|
519
712
|
exceptPaths: n = []
|
|
520
713
|
} = {}) {
|
|
521
714
|
t = normalizePath(t);
|
|
522
|
-
const
|
|
523
|
-
for (;
|
|
524
|
-
const
|
|
525
|
-
if (!
|
|
715
|
+
const i = [t];
|
|
716
|
+
for (; i.length; ) {
|
|
717
|
+
const o = i.pop();
|
|
718
|
+
if (!o)
|
|
526
719
|
return;
|
|
527
|
-
const a = await e.listFiles(
|
|
528
|
-
for (const
|
|
529
|
-
const
|
|
530
|
-
if (n.includes(
|
|
720
|
+
const a = await e.listFiles(o);
|
|
721
|
+
for (const l of a) {
|
|
722
|
+
const c = `${o}/${l}`;
|
|
723
|
+
if (n.includes(c.substring(t.length + 1)))
|
|
531
724
|
continue;
|
|
532
|
-
await e.isDir(
|
|
533
|
-
streamReadFileFromPHP(e,
|
|
725
|
+
await e.isDir(c) ? i.push(c) : yield new StreamedFile(
|
|
726
|
+
streamReadFileFromPHP(e, c),
|
|
534
727
|
r ? joinPaths(
|
|
535
728
|
s || "",
|
|
536
|
-
|
|
537
|
-
) :
|
|
729
|
+
c.substring(t.length + 1)
|
|
730
|
+
) : c
|
|
538
731
|
);
|
|
539
732
|
}
|
|
540
733
|
}
|
|
@@ -550,9 +743,145 @@ function writeFilesStreamToPhp(e, t) {
|
|
|
550
743
|
}
|
|
551
744
|
});
|
|
552
745
|
}
|
|
746
|
+
class MaxPhpInstancesError extends Error {
|
|
747
|
+
constructor(t) {
|
|
748
|
+
super(
|
|
749
|
+
`Requested more concurrent PHP instances than the limit (${t}).`
|
|
750
|
+
), this.name = this.constructor.name;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
class PHPProcessManager {
|
|
754
|
+
constructor(t) {
|
|
755
|
+
this.primaryIdle = !0, this.nextInstance = null, this.allInstances = [], this.maxPhpInstances = (t == null ? void 0 : t.maxPhpInstances) ?? 5, this.phpFactory = t == null ? void 0 : t.phpFactory, this.primaryPhp = t == null ? void 0 : t.primaryPhp, this.semaphore = new Semaphore({
|
|
756
|
+
concurrency: this.maxPhpInstances,
|
|
757
|
+
/**
|
|
758
|
+
* Wait up to 5 seconds for resources to become available
|
|
759
|
+
* before assuming that all the PHP instances are deadlocked.
|
|
760
|
+
*/
|
|
761
|
+
timeout: (t == null ? void 0 : t.timeout) || 5e3
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
/**
|
|
765
|
+
* Get the primary PHP instance.
|
|
766
|
+
*
|
|
767
|
+
* If the primary PHP instance is not set, it will be spawned
|
|
768
|
+
* using the provided phpFactory.
|
|
769
|
+
*
|
|
770
|
+
* @throws {Error} when called twice before the first call is resolved.
|
|
771
|
+
*/
|
|
772
|
+
async getPrimaryPhp() {
|
|
773
|
+
if (!this.phpFactory && !this.primaryPhp)
|
|
774
|
+
throw new Error(
|
|
775
|
+
"phpFactory or primaryPhp must be set before calling getPrimaryPhp()."
|
|
776
|
+
);
|
|
777
|
+
if (!this.primaryPhp) {
|
|
778
|
+
const t = await this.spawn({ isPrimary: !0 });
|
|
779
|
+
this.primaryPhp = t.php;
|
|
780
|
+
}
|
|
781
|
+
return this.primaryPhp;
|
|
782
|
+
}
|
|
783
|
+
/**
|
|
784
|
+
* Get a PHP instance.
|
|
785
|
+
*
|
|
786
|
+
* It could be either the primary PHP instance, an idle disposable PHP instance,
|
|
787
|
+
* or a newly spawned PHP instance – depending on the resource availability.
|
|
788
|
+
*
|
|
789
|
+
* @throws {MaxPhpInstancesError} when the maximum number of PHP instances is reached
|
|
790
|
+
* and the waiting timeout is exceeded.
|
|
791
|
+
*/
|
|
792
|
+
async acquirePHPInstance() {
|
|
793
|
+
if (this.primaryIdle)
|
|
794
|
+
return this.primaryIdle = !1, {
|
|
795
|
+
php: await this.getPrimaryPhp(),
|
|
796
|
+
reap: () => this.primaryIdle = !0
|
|
797
|
+
};
|
|
798
|
+
const t = this.nextInstance || this.spawn({ isPrimary: !1 });
|
|
799
|
+
return this.semaphore.remaining > 0 ? this.nextInstance = this.spawn({ isPrimary: !1 }) : this.nextInstance = null, await t;
|
|
800
|
+
}
|
|
801
|
+
/**
|
|
802
|
+
* Initiated spawning of a new PHP instance.
|
|
803
|
+
* This function is synchronous on purpose – it needs to synchronously
|
|
804
|
+
* add the spawn promise to the allInstances array without waiting
|
|
805
|
+
* for PHP to spawn.
|
|
806
|
+
*/
|
|
807
|
+
spawn(t) {
|
|
808
|
+
if (t.isPrimary && this.allInstances.length > 0)
|
|
809
|
+
throw new Error(
|
|
810
|
+
"Requested spawning a primary PHP instance when another primary instance already started spawning."
|
|
811
|
+
);
|
|
812
|
+
const r = this.doSpawn(t);
|
|
813
|
+
this.allInstances.push(r);
|
|
814
|
+
const s = () => {
|
|
815
|
+
this.allInstances = this.allInstances.filter(
|
|
816
|
+
(n) => n !== r
|
|
817
|
+
);
|
|
818
|
+
};
|
|
819
|
+
return r.catch((n) => {
|
|
820
|
+
throw s(), n;
|
|
821
|
+
}).then((n) => ({
|
|
822
|
+
...n,
|
|
823
|
+
reap: () => {
|
|
824
|
+
s(), n.reap();
|
|
825
|
+
}
|
|
826
|
+
}));
|
|
827
|
+
}
|
|
828
|
+
/**
|
|
829
|
+
* Actually acquires the lock and spawns a new PHP instance.
|
|
830
|
+
*/
|
|
831
|
+
async doSpawn(t) {
|
|
832
|
+
let r;
|
|
833
|
+
try {
|
|
834
|
+
r = await this.semaphore.acquire();
|
|
835
|
+
} catch (s) {
|
|
836
|
+
throw s instanceof AcquireTimeoutError ? new MaxPhpInstancesError(this.maxPhpInstances) : s;
|
|
837
|
+
}
|
|
838
|
+
try {
|
|
839
|
+
const s = await this.phpFactory(t);
|
|
840
|
+
return {
|
|
841
|
+
php: s,
|
|
842
|
+
reap() {
|
|
843
|
+
s.exit(), r();
|
|
844
|
+
}
|
|
845
|
+
};
|
|
846
|
+
} catch (s) {
|
|
847
|
+
throw r(), s;
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
async [Symbol.asyncDispose]() {
|
|
851
|
+
this.primaryPhp && this.primaryPhp.exit(), await Promise.all(
|
|
852
|
+
this.allInstances.map(
|
|
853
|
+
(t) => t.then(({ reap: r }) => r())
|
|
854
|
+
)
|
|
855
|
+
);
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
const responseTexts = {
|
|
859
|
+
500: "Internal Server Error",
|
|
860
|
+
502: "Bad Gateway",
|
|
861
|
+
404: "Not Found",
|
|
862
|
+
403: "Forbidden",
|
|
863
|
+
401: "Unauthorized",
|
|
864
|
+
400: "Bad Request",
|
|
865
|
+
301: "Moved Permanently",
|
|
866
|
+
302: "Found",
|
|
867
|
+
307: "Temporary Redirect",
|
|
868
|
+
308: "Permanent Redirect",
|
|
869
|
+
204: "No Content",
|
|
870
|
+
201: "Created",
|
|
871
|
+
200: "OK"
|
|
872
|
+
};
|
|
553
873
|
class PHPResponse {
|
|
554
|
-
constructor(t, r, s, n = "",
|
|
555
|
-
this.httpStatusCode = t, this.headers = r, this.bytes = s, this.exitCode =
|
|
874
|
+
constructor(t, r, s, n = "", i = 0) {
|
|
875
|
+
this.httpStatusCode = t, this.headers = r, this.bytes = s, this.exitCode = i, this.errors = n;
|
|
876
|
+
}
|
|
877
|
+
static forHttpCode(t, r = "") {
|
|
878
|
+
return new PHPResponse(
|
|
879
|
+
t,
|
|
880
|
+
{},
|
|
881
|
+
new TextEncoder().encode(
|
|
882
|
+
r || responseTexts[t] || ""
|
|
883
|
+
)
|
|
884
|
+
);
|
|
556
885
|
}
|
|
557
886
|
static fromRawData(t) {
|
|
558
887
|
return new PHPResponse(
|
|
@@ -603,726 +932,327 @@ const SupportedPHPVersions = [
|
|
|
603
932
|
], SupportedPHPExtensionBundles = {
|
|
604
933
|
"kitchen-sink": SupportedPHPExtensionsList,
|
|
605
934
|
light: []
|
|
606
|
-
},
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
935
|
+
}, FileErrorCodes = {
|
|
936
|
+
0: "No error occurred. System call completed successfully.",
|
|
937
|
+
1: "Argument list too long.",
|
|
938
|
+
2: "Permission denied.",
|
|
939
|
+
3: "Address in use.",
|
|
940
|
+
4: "Address not available.",
|
|
941
|
+
5: "Address family not supported.",
|
|
942
|
+
6: "Resource unavailable, or operation would block.",
|
|
943
|
+
7: "Connection already in progress.",
|
|
944
|
+
8: "Bad file descriptor.",
|
|
945
|
+
9: "Bad message.",
|
|
946
|
+
10: "Device or resource busy.",
|
|
947
|
+
11: "Operation canceled.",
|
|
948
|
+
12: "No child processes.",
|
|
949
|
+
13: "Connection aborted.",
|
|
950
|
+
14: "Connection refused.",
|
|
951
|
+
15: "Connection reset.",
|
|
952
|
+
16: "Resource deadlock would occur.",
|
|
953
|
+
17: "Destination address required.",
|
|
954
|
+
18: "Mathematics argument out of domain of function.",
|
|
955
|
+
19: "Reserved.",
|
|
956
|
+
20: "File exists.",
|
|
957
|
+
21: "Bad address.",
|
|
958
|
+
22: "File too large.",
|
|
959
|
+
23: "Host is unreachable.",
|
|
960
|
+
24: "Identifier removed.",
|
|
961
|
+
25: "Illegal byte sequence.",
|
|
962
|
+
26: "Operation in progress.",
|
|
963
|
+
27: "Interrupted function.",
|
|
964
|
+
28: "Invalid argument.",
|
|
965
|
+
29: "I/O error.",
|
|
966
|
+
30: "Socket is connected.",
|
|
967
|
+
31: "There is a directory under that path.",
|
|
968
|
+
32: "Too many levels of symbolic links.",
|
|
969
|
+
33: "File descriptor value too large.",
|
|
970
|
+
34: "Too many links.",
|
|
971
|
+
35: "Message too large.",
|
|
972
|
+
36: "Reserved.",
|
|
973
|
+
37: "Filename too long.",
|
|
974
|
+
38: "Network is down.",
|
|
975
|
+
39: "Connection aborted by network.",
|
|
976
|
+
40: "Network unreachable.",
|
|
977
|
+
41: "Too many files open in system.",
|
|
978
|
+
42: "No buffer space available.",
|
|
979
|
+
43: "No such device.",
|
|
980
|
+
44: "There is no such file or directory OR the parent directory does not exist.",
|
|
981
|
+
45: "Executable file format error.",
|
|
982
|
+
46: "No locks available.",
|
|
983
|
+
47: "Reserved.",
|
|
984
|
+
48: "Not enough space.",
|
|
985
|
+
49: "No message of the desired type.",
|
|
986
|
+
50: "Protocol not available.",
|
|
987
|
+
51: "No space left on device.",
|
|
988
|
+
52: "Function not supported.",
|
|
989
|
+
53: "The socket is not connected.",
|
|
990
|
+
54: "Not a directory or a symbolic link to a directory.",
|
|
991
|
+
55: "Directory not empty.",
|
|
992
|
+
56: "State not recoverable.",
|
|
993
|
+
57: "Not a socket.",
|
|
994
|
+
58: "Not supported, or operation not supported on socket.",
|
|
995
|
+
59: "Inappropriate I/O control operation.",
|
|
996
|
+
60: "No such device or address.",
|
|
997
|
+
61: "Value too large to be stored in data type.",
|
|
998
|
+
62: "Previous owner died.",
|
|
999
|
+
63: "Operation not permitted.",
|
|
1000
|
+
64: "Broken pipe.",
|
|
1001
|
+
65: "Protocol error.",
|
|
1002
|
+
66: "Protocol not supported.",
|
|
1003
|
+
67: "Protocol wrong type for socket.",
|
|
1004
|
+
68: "Result too large.",
|
|
1005
|
+
69: "Read-only file system.",
|
|
1006
|
+
70: "Invalid seek.",
|
|
1007
|
+
71: "No such process.",
|
|
1008
|
+
72: "Reserved.",
|
|
1009
|
+
73: "Connection timed out.",
|
|
1010
|
+
74: "Text file busy.",
|
|
1011
|
+
75: "Cross-device link.",
|
|
1012
|
+
76: "Extension: Capabilities insufficient."
|
|
1013
|
+
};
|
|
1014
|
+
function getEmscriptenFsError(e) {
|
|
1015
|
+
const t = typeof e == "object" ? e == null ? void 0 : e.errno : null;
|
|
1016
|
+
if (t in FileErrorCodes)
|
|
1017
|
+
return FileErrorCodes[t];
|
|
615
1018
|
}
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
n.
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
return { bytes: i, contentType: r };
|
|
1019
|
+
function rethrowFileSystemError(e = "") {
|
|
1020
|
+
return function(r, s, n) {
|
|
1021
|
+
const i = n.value;
|
|
1022
|
+
n.value = function(...o) {
|
|
1023
|
+
try {
|
|
1024
|
+
return i.apply(this, o);
|
|
1025
|
+
} catch (a) {
|
|
1026
|
+
const l = typeof a == "object" ? a == null ? void 0 : a.errno : null;
|
|
1027
|
+
if (l in FileErrorCodes) {
|
|
1028
|
+
const c = FileErrorCodes[l], g = typeof o[0] == "string" ? o[0] : null, me = g !== null ? e.replaceAll("{path}", g) : e;
|
|
1029
|
+
throw new Error(`${me}: ${c}`, {
|
|
1030
|
+
cause: a
|
|
1031
|
+
});
|
|
1032
|
+
}
|
|
1033
|
+
throw a;
|
|
1034
|
+
}
|
|
1035
|
+
};
|
|
1036
|
+
};
|
|
635
1037
|
}
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
1038
|
+
const RuntimeId = Symbol("RuntimeId"), loadedRuntimes = /* @__PURE__ */ new Map();
|
|
1039
|
+
let lastRuntimeId = 0;
|
|
1040
|
+
async function loadPHPRuntime(e, t = {}) {
|
|
1041
|
+
const [r, s, n] = makePromise(), i = e.init(currentJsRuntime, {
|
|
1042
|
+
onAbort(a) {
|
|
1043
|
+
n(a), logger.error(a);
|
|
1044
|
+
},
|
|
1045
|
+
ENV: {},
|
|
1046
|
+
// Emscripten sometimes prepends a '/' to the path, which
|
|
1047
|
+
// breaks vite dev mode. An identity `locateFile` function
|
|
1048
|
+
// fixes it.
|
|
1049
|
+
locateFile: (a) => a,
|
|
1050
|
+
...t,
|
|
1051
|
+
noInitialRun: !0,
|
|
1052
|
+
onRuntimeInitialized() {
|
|
1053
|
+
t.onRuntimeInitialized && t.onRuntimeInitialized(), s();
|
|
1054
|
+
}
|
|
642
1055
|
});
|
|
1056
|
+
await r;
|
|
1057
|
+
const o = ++lastRuntimeId;
|
|
1058
|
+
return i.id = o, i.originalExit = i._exit, i._exit = function(a) {
|
|
1059
|
+
return loadedRuntimes.delete(o), i.originalExit(a);
|
|
1060
|
+
}, i[RuntimeId] = o, loadedRuntimes.set(o, i), o;
|
|
643
1061
|
}
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
1062
|
+
function getLoadedRuntime(e) {
|
|
1063
|
+
return loadedRuntimes.get(e);
|
|
1064
|
+
}
|
|
1065
|
+
const currentJsRuntime = function() {
|
|
1066
|
+
var e;
|
|
1067
|
+
return typeof process < "u" && ((e = process.release) == null ? void 0 : e.name) === "node" ? "NODE" : typeof window < "u" ? "WEB" : typeof WorkerGlobalScope < "u" && self instanceof WorkerGlobalScope ? "WORKER" : "NODE";
|
|
1068
|
+
}(), makePromise = () => {
|
|
1069
|
+
const e = [], t = new Promise((r, s) => {
|
|
1070
|
+
e.push(r, s);
|
|
1071
|
+
});
|
|
1072
|
+
return e.unshift(t), e;
|
|
1073
|
+
};
|
|
1074
|
+
var __defProp = Object.defineProperty, __getOwnPropDesc = Object.getOwnPropertyDescriptor, __decorateClass = (e, t, r, s) => {
|
|
1075
|
+
for (var n = s > 1 ? void 0 : s ? __getOwnPropDesc(t, r) : t, i = e.length - 1, o; i >= 0; i--)
|
|
1076
|
+
(o = e[i]) && (n = (s ? o(t, r, n) : o(n)) || n);
|
|
1077
|
+
return s && n && __defProp(t, r, n), n;
|
|
1078
|
+
};
|
|
1079
|
+
const STRING = "string", NUMBER = "number", __private__dont__use = Symbol("__private__dont__use");
|
|
1080
|
+
class PHPExecutionFailureError extends Error {
|
|
1081
|
+
constructor(t, r, s) {
|
|
1082
|
+
super(t), this.response = r, this.source = s;
|
|
665
1083
|
}
|
|
666
1084
|
}
|
|
667
|
-
var
|
|
668
|
-
class
|
|
1085
|
+
var w, v, R, f, P, _, S, C, Z, I, Y, A, K, k, X, M, ee, B, te, L, re, N, se, U, ne, O, ie, D, oe, $, ae, q, le, j, ce, z, ue;
|
|
1086
|
+
class BasePHP {
|
|
669
1087
|
/**
|
|
670
|
-
*
|
|
671
|
-
*
|
|
1088
|
+
* Initializes a PHP runtime.
|
|
1089
|
+
*
|
|
1090
|
+
* @internal
|
|
1091
|
+
* @param PHPRuntime - Optional. PHP Runtime ID as initialized by loadPHPRuntime.
|
|
1092
|
+
* @param requestHandlerOptions - Optional. Options for the PHPRequestHandler. If undefined, no request handler will be initialized.
|
|
672
1093
|
*/
|
|
673
|
-
constructor(
|
|
674
|
-
/**
|
|
675
|
-
* Serves a static file from the PHP filesystem.
|
|
676
|
-
*
|
|
677
|
-
* @param fsPath - Absolute path of the static file to serve.
|
|
678
|
-
* @returns The response.
|
|
679
|
-
*/
|
|
680
|
-
d(this, A);
|
|
681
|
-
/**
|
|
682
|
-
* Runs the requested PHP file with all the request and $_SERVER
|
|
683
|
-
* superglobals populated.
|
|
684
|
-
*
|
|
685
|
-
* @param request - The request.
|
|
686
|
-
* @returns The response.
|
|
687
|
-
*/
|
|
688
|
-
d(this, k);
|
|
1094
|
+
constructor(e) {
|
|
689
1095
|
/**
|
|
690
|
-
*
|
|
691
|
-
*
|
|
692
|
-
* Fall back to index.php as if there was a url rewriting rule in place.
|
|
1096
|
+
* Prepares the $_SERVER entries for the PHP runtime.
|
|
693
1097
|
*
|
|
694
|
-
* @param
|
|
695
|
-
* @
|
|
696
|
-
* @
|
|
1098
|
+
* @param defaults Default entries to include in $_SERVER.
|
|
1099
|
+
* @param headers HTTP headers to include in $_SERVER (as HTTP_ prefixed entries).
|
|
1100
|
+
* @param port HTTP port, used to determine infer $_SERVER['HTTPS'] value if none
|
|
1101
|
+
* was provided.
|
|
1102
|
+
* @returns Computed $_SERVER entries.
|
|
697
1103
|
*/
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
h(this,
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
h(this,
|
|
717
|
-
|
|
718
|
-
h(this,
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
].join("")), h(this, _, i.pathname.replace(/\/+$/, "")), h(this, b, [
|
|
722
|
-
`${c(this, v)}://`,
|
|
723
|
-
c(this, S),
|
|
724
|
-
c(this, _)
|
|
725
|
-
].join("")), this.rewriteRules = o;
|
|
1104
|
+
h(this, C);
|
|
1105
|
+
h(this, I);
|
|
1106
|
+
h(this, A);
|
|
1107
|
+
h(this, k);
|
|
1108
|
+
h(this, M);
|
|
1109
|
+
h(this, B);
|
|
1110
|
+
h(this, L);
|
|
1111
|
+
h(this, N);
|
|
1112
|
+
h(this, U);
|
|
1113
|
+
h(this, O);
|
|
1114
|
+
h(this, D);
|
|
1115
|
+
h(this, $);
|
|
1116
|
+
h(this, q);
|
|
1117
|
+
h(this, j);
|
|
1118
|
+
h(this, z);
|
|
1119
|
+
h(this, w, void 0);
|
|
1120
|
+
h(this, v, void 0);
|
|
1121
|
+
h(this, R, void 0);
|
|
1122
|
+
h(this, f, void 0);
|
|
1123
|
+
h(this, P, void 0);
|
|
1124
|
+
h(this, _, void 0);
|
|
1125
|
+
h(this, S, void 0);
|
|
1126
|
+
d(this, w, []), d(this, f, !1), d(this, P, null), d(this, _, /* @__PURE__ */ new Map()), d(this, S, []), this.semaphore = new Semaphore({ concurrency: 1 }), e !== void 0 && this.initializeRuntime(e);
|
|
726
1127
|
}
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
* root.
|
|
730
|
-
*
|
|
731
|
-
* @param path The server path to convert to an absolute URL.
|
|
732
|
-
* @returns The absolute URL.
|
|
733
|
-
*/
|
|
734
|
-
pathToInternalUrl(t) {
|
|
735
|
-
return `${this.absoluteUrl}${t}`;
|
|
1128
|
+
addEventListener(e, t) {
|
|
1129
|
+
u(this, _).has(e) || u(this, _).set(e, /* @__PURE__ */ new Set()), u(this, _).get(e).add(t);
|
|
736
1130
|
}
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
*
|
|
741
|
-
* @param internalUrl An absolute URL based at the PHPRequestHandler root.
|
|
742
|
-
* @returns The relative path.
|
|
743
|
-
*/
|
|
744
|
-
internalUrlToPath(t) {
|
|
745
|
-
const r = new URL(t);
|
|
746
|
-
return r.pathname.startsWith(c(this, _)) && (r.pathname = r.pathname.slice(c(this, _).length)), toRelativeUrl(r);
|
|
1131
|
+
removeEventListener(e, t) {
|
|
1132
|
+
var r;
|
|
1133
|
+
(r = u(this, _).get(e)) == null || r.delete(t);
|
|
747
1134
|
}
|
|
748
|
-
|
|
749
|
-
|
|
1135
|
+
dispatchEvent(e) {
|
|
1136
|
+
const t = u(this, _).get(e.type);
|
|
1137
|
+
if (t)
|
|
1138
|
+
for (const r of t)
|
|
1139
|
+
r(e);
|
|
750
1140
|
}
|
|
751
|
-
/**
|
|
752
|
-
|
|
753
|
-
|
|
1141
|
+
/** @inheritDoc */
|
|
1142
|
+
async onMessage(e) {
|
|
1143
|
+
u(this, S).push(e);
|
|
1144
|
+
}
|
|
1145
|
+
/** @inheritDoc */
|
|
1146
|
+
async setSpawnHandler(handler) {
|
|
1147
|
+
typeof handler == "string" && (handler = createSpawnHandler(eval(handler))), this[__private__dont__use].spawnProcess = handler;
|
|
1148
|
+
}
|
|
1149
|
+
/** @inheritDoc */
|
|
754
1150
|
get absoluteUrl() {
|
|
755
|
-
return
|
|
1151
|
+
return this.requestHandler.absoluteUrl;
|
|
756
1152
|
}
|
|
757
|
-
/**
|
|
758
|
-
* The directory in the PHP filesystem where the server will look
|
|
759
|
-
* for the files to serve. Default: `/var/www`.
|
|
760
|
-
*/
|
|
1153
|
+
/** @inheritDoc */
|
|
761
1154
|
get documentRoot() {
|
|
762
|
-
return
|
|
1155
|
+
return this.requestHandler.documentRoot;
|
|
1156
|
+
}
|
|
1157
|
+
/** @inheritDoc */
|
|
1158
|
+
pathToInternalUrl(e) {
|
|
1159
|
+
return this.requestHandler.pathToInternalUrl(e);
|
|
1160
|
+
}
|
|
1161
|
+
/** @inheritDoc */
|
|
1162
|
+
internalUrlToPath(e) {
|
|
1163
|
+
return this.requestHandler.internalUrlToPath(e);
|
|
1164
|
+
}
|
|
1165
|
+
initializeRuntime(e) {
|
|
1166
|
+
if (this[__private__dont__use])
|
|
1167
|
+
throw new Error("PHP runtime already initialized.");
|
|
1168
|
+
const t = getLoadedRuntime(e);
|
|
1169
|
+
if (!t)
|
|
1170
|
+
throw new Error("Invalid PHP runtime id.");
|
|
1171
|
+
this[__private__dont__use] = t, t.onMessage = async (r) => {
|
|
1172
|
+
for (const s of u(this, S)) {
|
|
1173
|
+
const n = await s(r);
|
|
1174
|
+
if (n)
|
|
1175
|
+
return n;
|
|
1176
|
+
}
|
|
1177
|
+
return "";
|
|
1178
|
+
}, d(this, P, improveWASMErrorReporting(t)), this.dispatchEvent({
|
|
1179
|
+
type: "runtime.initialized"
|
|
1180
|
+
});
|
|
1181
|
+
}
|
|
1182
|
+
/** @inheritDoc */
|
|
1183
|
+
async setSapiName(e) {
|
|
1184
|
+
if (this[__private__dont__use].ccall(
|
|
1185
|
+
"wasm_set_sapi_name",
|
|
1186
|
+
NUMBER,
|
|
1187
|
+
[STRING],
|
|
1188
|
+
[e]
|
|
1189
|
+
) !== 0)
|
|
1190
|
+
throw new Error(
|
|
1191
|
+
"Could not set SAPI name. This can only be done before the PHP WASM module is initialized.Did you already dispatch any requests?"
|
|
1192
|
+
);
|
|
1193
|
+
d(this, R, e);
|
|
1194
|
+
}
|
|
1195
|
+
/** @inheritDoc */
|
|
1196
|
+
setPhpIniPath(e) {
|
|
1197
|
+
if (u(this, f))
|
|
1198
|
+
throw new Error("Cannot set PHP ini path after calling run().");
|
|
1199
|
+
d(this, v, e), this[__private__dont__use].ccall(
|
|
1200
|
+
"wasm_set_phpini_path",
|
|
1201
|
+
null,
|
|
1202
|
+
["string"],
|
|
1203
|
+
[e]
|
|
1204
|
+
);
|
|
1205
|
+
}
|
|
1206
|
+
/** @inheritDoc */
|
|
1207
|
+
setPhpIniEntry(e, t) {
|
|
1208
|
+
if (u(this, f))
|
|
1209
|
+
throw new Error("Cannot set PHP ini entries after calling run().");
|
|
1210
|
+
u(this, w).push([e, t]);
|
|
1211
|
+
}
|
|
1212
|
+
/** @inheritDoc */
|
|
1213
|
+
chdir(e) {
|
|
1214
|
+
this[__private__dont__use].FS.chdir(e);
|
|
763
1215
|
}
|
|
764
1216
|
/**
|
|
765
|
-
*
|
|
766
|
-
*
|
|
767
|
-
*
|
|
768
|
-
* The request() method mode behaves like a web server and only works if
|
|
769
|
-
* the PHP was initialized with a `requestHandler` option (which the online version
|
|
770
|
-
* of WordPress Playground does by default).
|
|
771
|
-
*
|
|
772
|
-
* In the request mode, you pass an object containing the request information
|
|
773
|
-
* (method, headers, body, etc.) and the path to the PHP file to run:
|
|
774
|
-
*
|
|
775
|
-
* ```ts
|
|
776
|
-
* const php = PHP.load('7.4', {
|
|
777
|
-
* requestHandler: {
|
|
778
|
-
* documentRoot: "/www"
|
|
779
|
-
* }
|
|
780
|
-
* })
|
|
781
|
-
* php.writeFile("/www/index.php", `<?php echo file_get_contents("php://input");`);
|
|
782
|
-
* const result = await php.request({
|
|
783
|
-
* method: "GET",
|
|
784
|
-
* headers: {
|
|
785
|
-
* "Content-Type": "text/plain"
|
|
786
|
-
* },
|
|
787
|
-
* body: "Hello world!",
|
|
788
|
-
* path: "/www/index.php"
|
|
789
|
-
* });
|
|
790
|
-
* // result.text === "Hello world!"
|
|
791
|
-
* ```
|
|
792
|
-
*
|
|
793
|
-
* The `request()` method cannot be used in conjunction with `cli()`.
|
|
794
|
-
*
|
|
795
|
-
* @example
|
|
796
|
-
* ```js
|
|
797
|
-
* const output = await php.request({
|
|
798
|
-
* method: 'GET',
|
|
799
|
-
* url: '/index.php',
|
|
800
|
-
* headers: {
|
|
801
|
-
* 'X-foo': 'bar',
|
|
802
|
-
* },
|
|
803
|
-
* body: {
|
|
804
|
-
* foo: 'bar',
|
|
805
|
-
* },
|
|
806
|
-
* });
|
|
807
|
-
* console.log(output.stdout); // "Hello world!"
|
|
808
|
-
* ```
|
|
809
|
-
*
|
|
810
|
-
* @param request - PHP Request data.
|
|
1217
|
+
* Do not use. Use new PHPRequestHandler() instead.
|
|
1218
|
+
* @deprecated
|
|
811
1219
|
*/
|
|
812
|
-
async request(
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
removePathPrefix(
|
|
819
|
-
decodeURIComponent(s.pathname),
|
|
820
|
-
c(this, _)
|
|
821
|
-
),
|
|
822
|
-
this.rewriteRules
|
|
823
|
-
), o = joinPaths(c(this, m), n);
|
|
824
|
-
return seemsLikeAPHPRequestHandlerPath(o) ? await p(this, k, K).call(this, t, s) : p(this, A, Y).call(this, o);
|
|
1220
|
+
async request(e) {
|
|
1221
|
+
if (logger.warn(
|
|
1222
|
+
"PHP.request() is deprecated. Please use new PHPRequestHandler() instead."
|
|
1223
|
+
), !this.requestHandler)
|
|
1224
|
+
throw new Error("No request handler available.");
|
|
1225
|
+
return this.requestHandler.request(e);
|
|
825
1226
|
}
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
404,
|
|
831
|
-
// Let the service worker know that no static file was found
|
|
832
|
-
// and that it's okay to issue a real fetch() to the server.
|
|
833
|
-
{
|
|
834
|
-
"x-file-type": ["static"]
|
|
835
|
-
},
|
|
836
|
-
new TextEncoder().encode("404 File not found")
|
|
837
|
-
);
|
|
838
|
-
const r = this.php.readFileAsBuffer(t);
|
|
839
|
-
return new PHPResponse(
|
|
840
|
-
200,
|
|
841
|
-
{
|
|
842
|
-
"content-length": [`${r.byteLength}`],
|
|
843
|
-
// @TODO: Infer the content-type from the arrayBuffer instead of the file path.
|
|
844
|
-
// The code below won't return the correct mime-type if the extension
|
|
845
|
-
// was tampered with.
|
|
846
|
-
"content-type": [inferMimeType(t)],
|
|
847
|
-
"accept-ranges": ["bytes"],
|
|
848
|
-
"cache-control": ["public, max-age=0"]
|
|
849
|
-
},
|
|
850
|
-
r
|
|
851
|
-
);
|
|
852
|
-
}, k = new WeakSet(), K = async function(t, r) {
|
|
853
|
-
var n;
|
|
854
|
-
if (c(this, E).running > 0 && ((n = t.headers) == null ? void 0 : n["x-request-issuer"]) === "php")
|
|
855
|
-
return console.warn(
|
|
856
|
-
"Possible deadlock: Called request() before the previous request() have finished. PHP likely issued an HTTP call to itself. Normally this would lead to infinite waiting as Request 1 holds the lock that the Request 2 is waiting to acquire. That's not useful, so PHPRequestHandler will return error 502 instead."
|
|
857
|
-
), new PHPResponse(
|
|
858
|
-
502,
|
|
859
|
-
{},
|
|
860
|
-
new TextEncoder().encode("502 Bad Gateway")
|
|
861
|
-
);
|
|
862
|
-
const s = await c(this, E).acquire();
|
|
863
|
-
try {
|
|
864
|
-
let o = "GET";
|
|
865
|
-
const i = {
|
|
866
|
-
host: c(this, S),
|
|
867
|
-
...normalizeHeaders(t.headers || {}),
|
|
868
|
-
cookie: c(this, x).getCookieRequestHeader()
|
|
869
|
-
};
|
|
870
|
-
let a = t.body;
|
|
871
|
-
if (typeof a == "object" && !(a instanceof Uint8Array)) {
|
|
872
|
-
o = "POST";
|
|
873
|
-
const { bytes: l, contentType: f } = await encodeAsMultipart(a);
|
|
874
|
-
a = l, i["content-type"] = f;
|
|
875
|
-
}
|
|
876
|
-
let u;
|
|
1227
|
+
/** @inheritDoc */
|
|
1228
|
+
async run(e) {
|
|
1229
|
+
const t = await this.semaphore.acquire();
|
|
1230
|
+
let r;
|
|
877
1231
|
try {
|
|
878
|
-
u
|
|
879
|
-
} catch {
|
|
880
|
-
return new PHPResponse(
|
|
881
|
-
404,
|
|
882
|
-
{},
|
|
883
|
-
new TextEncoder().encode("404 File not found")
|
|
884
|
-
);
|
|
885
|
-
}
|
|
886
|
-
try {
|
|
887
|
-
const l = await this.php.run({
|
|
888
|
-
relativeUri: ensurePathPrefix(
|
|
889
|
-
toRelativeUrl(r),
|
|
890
|
-
c(this, _)
|
|
891
|
-
),
|
|
892
|
-
protocol: c(this, v),
|
|
893
|
-
method: t.method || o,
|
|
894
|
-
$_SERVER: {
|
|
895
|
-
REMOTE_ADDR: "127.0.0.1",
|
|
896
|
-
DOCUMENT_ROOT: c(this, m),
|
|
897
|
-
HTTPS: c(this, b).startsWith("https://") ? "on" : ""
|
|
898
|
-
},
|
|
899
|
-
body: a,
|
|
900
|
-
scriptPath: u,
|
|
901
|
-
headers: i
|
|
902
|
-
});
|
|
903
|
-
return c(this, x).rememberCookiesFromResponseHeaders(
|
|
904
|
-
l.headers
|
|
905
|
-
), l;
|
|
906
|
-
} catch (l) {
|
|
907
|
-
const f = l;
|
|
908
|
-
if (f != null && f.response)
|
|
909
|
-
return f.response;
|
|
910
|
-
throw l;
|
|
911
|
-
}
|
|
912
|
-
} finally {
|
|
913
|
-
s();
|
|
914
|
-
}
|
|
915
|
-
}, B = new WeakSet(), Z = function(t) {
|
|
916
|
-
let r = removePathPrefix(t, c(this, _));
|
|
917
|
-
r = applyRewriteRules(r, this.rewriteRules), r.includes(".php") ? r = r.split(".php")[0] + ".php" : this.php.isDir(`${c(this, m)}${r}`) ? (r.endsWith("/") || (r = `${r}/`), r = `${r}index.php`) : r = "/index.php";
|
|
918
|
-
const s = `${c(this, m)}${r}`;
|
|
919
|
-
if (this.php.fileExists(s))
|
|
920
|
-
return s;
|
|
921
|
-
throw new Error(`File not found: ${s}`);
|
|
922
|
-
};
|
|
923
|
-
function inferMimeType(e) {
|
|
924
|
-
switch (e.split(".").pop()) {
|
|
925
|
-
case "css":
|
|
926
|
-
return "text/css";
|
|
927
|
-
case "js":
|
|
928
|
-
return "application/javascript";
|
|
929
|
-
case "png":
|
|
930
|
-
return "image/png";
|
|
931
|
-
case "jpg":
|
|
932
|
-
case "jpeg":
|
|
933
|
-
return "image/jpeg";
|
|
934
|
-
case "gif":
|
|
935
|
-
return "image/gif";
|
|
936
|
-
case "svg":
|
|
937
|
-
return "image/svg+xml";
|
|
938
|
-
case "woff":
|
|
939
|
-
return "font/woff";
|
|
940
|
-
case "woff2":
|
|
941
|
-
return "font/woff2";
|
|
942
|
-
case "ttf":
|
|
943
|
-
return "font/ttf";
|
|
944
|
-
case "otf":
|
|
945
|
-
return "font/otf";
|
|
946
|
-
case "eot":
|
|
947
|
-
return "font/eot";
|
|
948
|
-
case "ico":
|
|
949
|
-
return "image/x-icon";
|
|
950
|
-
case "html":
|
|
951
|
-
return "text/html";
|
|
952
|
-
case "json":
|
|
953
|
-
return "application/json";
|
|
954
|
-
case "xml":
|
|
955
|
-
return "application/xml";
|
|
956
|
-
case "txt":
|
|
957
|
-
case "md":
|
|
958
|
-
return "text/plain";
|
|
959
|
-
case "pdf":
|
|
960
|
-
return "application/pdf";
|
|
961
|
-
case "webp":
|
|
962
|
-
return "image/webp";
|
|
963
|
-
case "mp3":
|
|
964
|
-
return "audio/mpeg";
|
|
965
|
-
case "mp4":
|
|
966
|
-
return "video/mp4";
|
|
967
|
-
case "csv":
|
|
968
|
-
return "text/csv";
|
|
969
|
-
case "xls":
|
|
970
|
-
return "application/vnd.ms-excel";
|
|
971
|
-
case "xlsx":
|
|
972
|
-
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
|
973
|
-
case "doc":
|
|
974
|
-
return "application/msword";
|
|
975
|
-
case "docx":
|
|
976
|
-
return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
|
977
|
-
case "ppt":
|
|
978
|
-
return "application/vnd.ms-powerpoint";
|
|
979
|
-
case "pptx":
|
|
980
|
-
return "application/vnd.openxmlformats-officedocument.presentationml.presentation";
|
|
981
|
-
case "zip":
|
|
982
|
-
return "application/zip";
|
|
983
|
-
case "rar":
|
|
984
|
-
return "application/x-rar-compressed";
|
|
985
|
-
case "tar":
|
|
986
|
-
return "application/x-tar";
|
|
987
|
-
case "gz":
|
|
988
|
-
return "application/gzip";
|
|
989
|
-
case "7z":
|
|
990
|
-
return "application/x-7z-compressed";
|
|
991
|
-
default:
|
|
992
|
-
return "application-octet-stream";
|
|
993
|
-
}
|
|
994
|
-
}
|
|
995
|
-
function seemsLikeAPHPRequestHandlerPath(e) {
|
|
996
|
-
return seemsLikeAPHPFile(e) || seemsLikeADirectoryRoot(e);
|
|
997
|
-
}
|
|
998
|
-
function seemsLikeAPHPFile(e) {
|
|
999
|
-
return e.endsWith(".php") || e.includes(".php/");
|
|
1000
|
-
}
|
|
1001
|
-
function seemsLikeADirectoryRoot(e) {
|
|
1002
|
-
return !e.split("/").pop().includes(".");
|
|
1003
|
-
}
|
|
1004
|
-
function applyRewriteRules(e, t) {
|
|
1005
|
-
for (const r of t)
|
|
1006
|
-
if (new RegExp(r.match).test(e))
|
|
1007
|
-
return e.replace(r.match, r.replacement);
|
|
1008
|
-
return e;
|
|
1009
|
-
}
|
|
1010
|
-
const FileErrorCodes = {
|
|
1011
|
-
0: "No error occurred. System call completed successfully.",
|
|
1012
|
-
1: "Argument list too long.",
|
|
1013
|
-
2: "Permission denied.",
|
|
1014
|
-
3: "Address in use.",
|
|
1015
|
-
4: "Address not available.",
|
|
1016
|
-
5: "Address family not supported.",
|
|
1017
|
-
6: "Resource unavailable, or operation would block.",
|
|
1018
|
-
7: "Connection already in progress.",
|
|
1019
|
-
8: "Bad file descriptor.",
|
|
1020
|
-
9: "Bad message.",
|
|
1021
|
-
10: "Device or resource busy.",
|
|
1022
|
-
11: "Operation canceled.",
|
|
1023
|
-
12: "No child processes.",
|
|
1024
|
-
13: "Connection aborted.",
|
|
1025
|
-
14: "Connection refused.",
|
|
1026
|
-
15: "Connection reset.",
|
|
1027
|
-
16: "Resource deadlock would occur.",
|
|
1028
|
-
17: "Destination address required.",
|
|
1029
|
-
18: "Mathematics argument out of domain of function.",
|
|
1030
|
-
19: "Reserved.",
|
|
1031
|
-
20: "File exists.",
|
|
1032
|
-
21: "Bad address.",
|
|
1033
|
-
22: "File too large.",
|
|
1034
|
-
23: "Host is unreachable.",
|
|
1035
|
-
24: "Identifier removed.",
|
|
1036
|
-
25: "Illegal byte sequence.",
|
|
1037
|
-
26: "Operation in progress.",
|
|
1038
|
-
27: "Interrupted function.",
|
|
1039
|
-
28: "Invalid argument.",
|
|
1040
|
-
29: "I/O error.",
|
|
1041
|
-
30: "Socket is connected.",
|
|
1042
|
-
31: "There is a directory under that path.",
|
|
1043
|
-
32: "Too many levels of symbolic links.",
|
|
1044
|
-
33: "File descriptor value too large.",
|
|
1045
|
-
34: "Too many links.",
|
|
1046
|
-
35: "Message too large.",
|
|
1047
|
-
36: "Reserved.",
|
|
1048
|
-
37: "Filename too long.",
|
|
1049
|
-
38: "Network is down.",
|
|
1050
|
-
39: "Connection aborted by network.",
|
|
1051
|
-
40: "Network unreachable.",
|
|
1052
|
-
41: "Too many files open in system.",
|
|
1053
|
-
42: "No buffer space available.",
|
|
1054
|
-
43: "No such device.",
|
|
1055
|
-
44: "There is no such file or directory OR the parent directory does not exist.",
|
|
1056
|
-
45: "Executable file format error.",
|
|
1057
|
-
46: "No locks available.",
|
|
1058
|
-
47: "Reserved.",
|
|
1059
|
-
48: "Not enough space.",
|
|
1060
|
-
49: "No message of the desired type.",
|
|
1061
|
-
50: "Protocol not available.",
|
|
1062
|
-
51: "No space left on device.",
|
|
1063
|
-
52: "Function not supported.",
|
|
1064
|
-
53: "The socket is not connected.",
|
|
1065
|
-
54: "Not a directory or a symbolic link to a directory.",
|
|
1066
|
-
55: "Directory not empty.",
|
|
1067
|
-
56: "State not recoverable.",
|
|
1068
|
-
57: "Not a socket.",
|
|
1069
|
-
58: "Not supported, or operation not supported on socket.",
|
|
1070
|
-
59: "Inappropriate I/O control operation.",
|
|
1071
|
-
60: "No such device or address.",
|
|
1072
|
-
61: "Value too large to be stored in data type.",
|
|
1073
|
-
62: "Previous owner died.",
|
|
1074
|
-
63: "Operation not permitted.",
|
|
1075
|
-
64: "Broken pipe.",
|
|
1076
|
-
65: "Protocol error.",
|
|
1077
|
-
66: "Protocol not supported.",
|
|
1078
|
-
67: "Protocol wrong type for socket.",
|
|
1079
|
-
68: "Result too large.",
|
|
1080
|
-
69: "Read-only file system.",
|
|
1081
|
-
70: "Invalid seek.",
|
|
1082
|
-
71: "No such process.",
|
|
1083
|
-
72: "Reserved.",
|
|
1084
|
-
73: "Connection timed out.",
|
|
1085
|
-
74: "Text file busy.",
|
|
1086
|
-
75: "Cross-device link.",
|
|
1087
|
-
76: "Extension: Capabilities insufficient."
|
|
1088
|
-
};
|
|
1089
|
-
function getEmscriptenFsError(e) {
|
|
1090
|
-
const t = typeof e == "object" ? e == null ? void 0 : e.errno : null;
|
|
1091
|
-
if (t in FileErrorCodes)
|
|
1092
|
-
return FileErrorCodes[t];
|
|
1093
|
-
}
|
|
1094
|
-
function rethrowFileSystemError(e = "") {
|
|
1095
|
-
return function(r, s, n) {
|
|
1096
|
-
const o = n.value;
|
|
1097
|
-
n.value = function(...i) {
|
|
1098
|
-
try {
|
|
1099
|
-
return o.apply(this, i);
|
|
1100
|
-
} catch (a) {
|
|
1101
|
-
const u = typeof a == "object" ? a == null ? void 0 : a.errno : null;
|
|
1102
|
-
if (u in FileErrorCodes) {
|
|
1103
|
-
const l = FileErrorCodes[u], f = typeof i[0] == "string" ? i[0] : null, fe = f !== null ? e.replaceAll("{path}", f) : e;
|
|
1104
|
-
throw new Error(`${fe}: ${l}`, {
|
|
1105
|
-
cause: a
|
|
1106
|
-
});
|
|
1107
|
-
}
|
|
1108
|
-
throw a;
|
|
1109
|
-
}
|
|
1110
|
-
};
|
|
1111
|
-
};
|
|
1112
|
-
}
|
|
1113
|
-
const RuntimeId = Symbol("RuntimeId"), loadedRuntimes = /* @__PURE__ */ new Map();
|
|
1114
|
-
let lastRuntimeId = 0;
|
|
1115
|
-
async function loadPHPRuntime(e, t = {}) {
|
|
1116
|
-
const [r, s, n] = makePromise(), o = e.init(currentJsRuntime, {
|
|
1117
|
-
onAbort(a) {
|
|
1118
|
-
n(a), console.error(a);
|
|
1119
|
-
},
|
|
1120
|
-
ENV: {},
|
|
1121
|
-
// Emscripten sometimes prepends a '/' to the path, which
|
|
1122
|
-
// breaks vite dev mode. An identity `locateFile` function
|
|
1123
|
-
// fixes it.
|
|
1124
|
-
locateFile: (a) => a,
|
|
1125
|
-
...t,
|
|
1126
|
-
noInitialRun: !0,
|
|
1127
|
-
onRuntimeInitialized() {
|
|
1128
|
-
t.onRuntimeInitialized && t.onRuntimeInitialized(), s();
|
|
1129
|
-
}
|
|
1130
|
-
});
|
|
1131
|
-
await r;
|
|
1132
|
-
const i = ++lastRuntimeId;
|
|
1133
|
-
return o.id = i, o.originalExit = o._exit, o._exit = function(a) {
|
|
1134
|
-
return loadedRuntimes.delete(i), o.originalExit(a);
|
|
1135
|
-
}, o[RuntimeId] = i, loadedRuntimes.set(i, o), i;
|
|
1136
|
-
}
|
|
1137
|
-
function getLoadedRuntime(e) {
|
|
1138
|
-
return loadedRuntimes.get(e);
|
|
1139
|
-
}
|
|
1140
|
-
const currentJsRuntime = function() {
|
|
1141
|
-
var e;
|
|
1142
|
-
return typeof process < "u" && ((e = process.release) == null ? void 0 : e.name) === "node" ? "NODE" : typeof window < "u" ? "WEB" : typeof WorkerGlobalScope < "u" && self instanceof WorkerGlobalScope ? "WORKER" : "NODE";
|
|
1143
|
-
}(), makePromise = () => {
|
|
1144
|
-
const e = [], t = new Promise((r, s) => {
|
|
1145
|
-
e.push(r, s);
|
|
1146
|
-
});
|
|
1147
|
-
return e.unshift(t), e;
|
|
1148
|
-
};
|
|
1149
|
-
var __defProp = Object.defineProperty, __getOwnPropDesc = Object.getOwnPropertyDescriptor, __decorateClass = (e, t, r, s) => {
|
|
1150
|
-
for (var n = s > 1 ? void 0 : s ? __getOwnPropDesc(t, r) : t, o = e.length - 1, i; o >= 0; o--)
|
|
1151
|
-
(i = e[o]) && (n = (s ? i(t, r, n) : i(n)) || n);
|
|
1152
|
-
return s && n && __defProp(t, r, n), n;
|
|
1153
|
-
};
|
|
1154
|
-
const STRING = "string", NUMBER = "number", __private__dont__use = Symbol("__private__dont__use");
|
|
1155
|
-
class PHPExecutionFailureError extends Error {
|
|
1156
|
-
constructor(t, r, s) {
|
|
1157
|
-
super(t), this.response = r, this.source = s;
|
|
1158
|
-
}
|
|
1159
|
-
}
|
|
1160
|
-
var R, F, H, y, w, P, T, I, X, N, ee, U, te, L, re, O, se, M, ne, $, ie, D, oe, q, ae, j, le, z, ce, W, ue, G, de, V, he, J, pe;
|
|
1161
|
-
class BasePHP {
|
|
1162
|
-
/**
|
|
1163
|
-
* Initializes a PHP runtime.
|
|
1164
|
-
*
|
|
1165
|
-
* @internal
|
|
1166
|
-
* @param PHPRuntime - Optional. PHP Runtime ID as initialized by loadPHPRuntime.
|
|
1167
|
-
* @param serverOptions - Optional. Options for the PHPRequestHandler. If undefined, no request handler will be initialized.
|
|
1168
|
-
*/
|
|
1169
|
-
constructor(e, t) {
|
|
1170
|
-
/**
|
|
1171
|
-
* Prepares the $_SERVER entries for the PHP runtime.
|
|
1172
|
-
*
|
|
1173
|
-
* @param defaults Default entries to include in $_SERVER.
|
|
1174
|
-
* @param headers HTTP headers to include in $_SERVER (as HTTP_ prefixed entries).
|
|
1175
|
-
* @param port HTTP port, used to determine infer $_SERVER['HTTPS'] value if none
|
|
1176
|
-
* was provided.
|
|
1177
|
-
* @returns Computed $_SERVER entries.
|
|
1178
|
-
*/
|
|
1179
|
-
d(this, I);
|
|
1180
|
-
d(this, N);
|
|
1181
|
-
d(this, U);
|
|
1182
|
-
d(this, L);
|
|
1183
|
-
d(this, O);
|
|
1184
|
-
d(this, M);
|
|
1185
|
-
d(this, $);
|
|
1186
|
-
d(this, D);
|
|
1187
|
-
d(this, q);
|
|
1188
|
-
d(this, j);
|
|
1189
|
-
d(this, z);
|
|
1190
|
-
d(this, W);
|
|
1191
|
-
d(this, G);
|
|
1192
|
-
d(this, V);
|
|
1193
|
-
d(this, J);
|
|
1194
|
-
d(this, R, void 0);
|
|
1195
|
-
d(this, F, void 0);
|
|
1196
|
-
d(this, H, void 0);
|
|
1197
|
-
d(this, y, void 0);
|
|
1198
|
-
d(this, w, void 0);
|
|
1199
|
-
d(this, P, void 0);
|
|
1200
|
-
d(this, T, void 0);
|
|
1201
|
-
h(this, R, []), h(this, y, !1), h(this, w, null), h(this, P, /* @__PURE__ */ new Map()), h(this, T, []), this.semaphore = new Semaphore({ concurrency: 1 }), e !== void 0 && this.initializeRuntime(e), t && (this.requestHandler = new PHPRequestHandler(this, t));
|
|
1202
|
-
}
|
|
1203
|
-
addEventListener(e, t) {
|
|
1204
|
-
c(this, P).has(e) || c(this, P).set(e, /* @__PURE__ */ new Set()), c(this, P).get(e).add(t);
|
|
1205
|
-
}
|
|
1206
|
-
removeEventListener(e, t) {
|
|
1207
|
-
var r;
|
|
1208
|
-
(r = c(this, P).get(e)) == null || r.delete(t);
|
|
1209
|
-
}
|
|
1210
|
-
dispatchEvent(e) {
|
|
1211
|
-
const t = c(this, P).get(e.type);
|
|
1212
|
-
if (t)
|
|
1213
|
-
for (const r of t)
|
|
1214
|
-
r(e);
|
|
1215
|
-
}
|
|
1216
|
-
/** @inheritDoc */
|
|
1217
|
-
async onMessage(e) {
|
|
1218
|
-
c(this, T).push(e);
|
|
1219
|
-
}
|
|
1220
|
-
/** @inheritDoc */
|
|
1221
|
-
async setSpawnHandler(handler) {
|
|
1222
|
-
typeof handler == "string" && (handler = createSpawnHandler(eval(handler))), this[__private__dont__use].spawnProcess = handler;
|
|
1223
|
-
}
|
|
1224
|
-
/** @inheritDoc */
|
|
1225
|
-
get absoluteUrl() {
|
|
1226
|
-
return this.requestHandler.absoluteUrl;
|
|
1227
|
-
}
|
|
1228
|
-
/** @inheritDoc */
|
|
1229
|
-
get documentRoot() {
|
|
1230
|
-
return this.requestHandler.documentRoot;
|
|
1231
|
-
}
|
|
1232
|
-
/** @inheritDoc */
|
|
1233
|
-
pathToInternalUrl(e) {
|
|
1234
|
-
return this.requestHandler.pathToInternalUrl(e);
|
|
1235
|
-
}
|
|
1236
|
-
/** @inheritDoc */
|
|
1237
|
-
internalUrlToPath(e) {
|
|
1238
|
-
return this.requestHandler.internalUrlToPath(e);
|
|
1239
|
-
}
|
|
1240
|
-
initializeRuntime(e) {
|
|
1241
|
-
if (this[__private__dont__use])
|
|
1242
|
-
throw new Error("PHP runtime already initialized.");
|
|
1243
|
-
const t = getLoadedRuntime(e);
|
|
1244
|
-
if (!t)
|
|
1245
|
-
throw new Error("Invalid PHP runtime id.");
|
|
1246
|
-
this[__private__dont__use] = t, t.onMessage = async (r) => {
|
|
1247
|
-
for (const s of c(this, T)) {
|
|
1248
|
-
const n = await s(r);
|
|
1249
|
-
if (n)
|
|
1250
|
-
return n;
|
|
1251
|
-
}
|
|
1252
|
-
return "";
|
|
1253
|
-
}, h(this, w, improveWASMErrorReporting(t)), this.dispatchEvent({
|
|
1254
|
-
type: "runtime.initialized"
|
|
1255
|
-
});
|
|
1256
|
-
}
|
|
1257
|
-
/** @inheritDoc */
|
|
1258
|
-
async setSapiName(e) {
|
|
1259
|
-
if (this[__private__dont__use].ccall(
|
|
1260
|
-
"wasm_set_sapi_name",
|
|
1261
|
-
NUMBER,
|
|
1262
|
-
[STRING],
|
|
1263
|
-
[e]
|
|
1264
|
-
) !== 0)
|
|
1265
|
-
throw new Error(
|
|
1266
|
-
"Could not set SAPI name. This can only be done before the PHP WASM module is initialized.Did you already dispatch any requests?"
|
|
1267
|
-
);
|
|
1268
|
-
h(this, H, e);
|
|
1269
|
-
}
|
|
1270
|
-
/** @inheritDoc */
|
|
1271
|
-
setPhpIniPath(e) {
|
|
1272
|
-
if (c(this, y))
|
|
1273
|
-
throw new Error("Cannot set PHP ini path after calling run().");
|
|
1274
|
-
h(this, F, e), this[__private__dont__use].ccall(
|
|
1275
|
-
"wasm_set_phpini_path",
|
|
1276
|
-
null,
|
|
1277
|
-
["string"],
|
|
1278
|
-
[e]
|
|
1279
|
-
);
|
|
1280
|
-
}
|
|
1281
|
-
/** @inheritDoc */
|
|
1282
|
-
setPhpIniEntry(e, t) {
|
|
1283
|
-
if (c(this, y))
|
|
1284
|
-
throw new Error("Cannot set PHP ini entries after calling run().");
|
|
1285
|
-
c(this, R).push([e, t]);
|
|
1286
|
-
}
|
|
1287
|
-
/** @inheritDoc */
|
|
1288
|
-
chdir(e) {
|
|
1289
|
-
this[__private__dont__use].FS.chdir(e);
|
|
1290
|
-
}
|
|
1291
|
-
/** @inheritDoc */
|
|
1292
|
-
async request(e) {
|
|
1293
|
-
if (!this.requestHandler)
|
|
1294
|
-
throw new Error("No request handler available.");
|
|
1295
|
-
return this.requestHandler.request(e);
|
|
1296
|
-
}
|
|
1297
|
-
/** @inheritDoc */
|
|
1298
|
-
async run(e) {
|
|
1299
|
-
const t = await this.semaphore.acquire();
|
|
1300
|
-
let r;
|
|
1301
|
-
try {
|
|
1302
|
-
if (c(this, y) || (p(this, N, ee).call(this), h(this, y, !0)), e.scriptPath && !this.fileExists(e.scriptPath))
|
|
1232
|
+
if (u(this, f) || (p(this, I, Y).call(this), d(this, f, !0)), e.scriptPath && !this.fileExists(e.scriptPath))
|
|
1303
1233
|
throw new Error(
|
|
1304
1234
|
`The script path "${e.scriptPath}" does not exist.`
|
|
1305
1235
|
);
|
|
1306
|
-
p(this,
|
|
1307
|
-
const s = normalizeHeaders(e.headers || {}), n = s.host || "example.com:443",
|
|
1308
|
-
p(this,
|
|
1309
|
-
const
|
|
1310
|
-
for (const
|
|
1311
|
-
p(this,
|
|
1236
|
+
p(this, D, oe).call(this, e.scriptPath || ""), p(this, k, X).call(this, e.relativeUri || ""), p(this, N, se).call(this, e.method || "GET");
|
|
1237
|
+
const s = normalizeHeaders(e.headers || {}), n = s.host || "example.com:443", i = p(this, L, re).call(this, n, e.protocol || "http");
|
|
1238
|
+
p(this, M, ee).call(this, n), p(this, B, te).call(this, i), p(this, U, ne).call(this, s), e.body && (r = p(this, O, ie).call(this, e.body)), typeof e.code == "string" && p(this, j, ce).call(this, " ?>" + e.code);
|
|
1239
|
+
const o = p(this, C, Z).call(this, e.$_SERVER, s, i);
|
|
1240
|
+
for (const c in o)
|
|
1241
|
+
p(this, $, ae).call(this, c, o[c]);
|
|
1312
1242
|
const a = e.env || {};
|
|
1313
|
-
for (const
|
|
1314
|
-
p(this,
|
|
1315
|
-
const
|
|
1316
|
-
if (
|
|
1317
|
-
|
|
1318
|
-
const
|
|
1319
|
-
`PHP.run() failed with exit code ${
|
|
1320
|
-
|
|
1243
|
+
for (const c in a)
|
|
1244
|
+
p(this, q, le).call(this, c, a[c]);
|
|
1245
|
+
const l = await p(this, z, ue).call(this);
|
|
1246
|
+
if (l.exitCode !== 0) {
|
|
1247
|
+
logger.warn("PHP.run() output was:", l.text);
|
|
1248
|
+
const c = new PHPExecutionFailureError(
|
|
1249
|
+
`PHP.run() failed with exit code ${l.exitCode} and the following output: ` + l.errors,
|
|
1250
|
+
l,
|
|
1321
1251
|
"request"
|
|
1322
1252
|
);
|
|
1323
|
-
throw
|
|
1253
|
+
throw logger.error(c), c;
|
|
1324
1254
|
}
|
|
1325
|
-
return
|
|
1255
|
+
return l;
|
|
1326
1256
|
} catch (s) {
|
|
1327
1257
|
throw this.dispatchEvent({
|
|
1328
1258
|
type: "request.error",
|
|
@@ -1407,7 +1337,7 @@ class BasePHP {
|
|
|
1407
1337
|
}
|
|
1408
1338
|
return r;
|
|
1409
1339
|
} catch (r) {
|
|
1410
|
-
return
|
|
1340
|
+
return logger.error(r, { path: e }), [];
|
|
1411
1341
|
}
|
|
1412
1342
|
}
|
|
1413
1343
|
isDir(e) {
|
|
@@ -1415,309 +1345,705 @@ class BasePHP {
|
|
|
1415
1345
|
this[__private__dont__use].FS.lookupPath(e).node.mode
|
|
1416
1346
|
) : !1;
|
|
1417
1347
|
}
|
|
1418
|
-
fileExists(e) {
|
|
1419
|
-
try {
|
|
1420
|
-
return this[__private__dont__use].FS.lookupPath(e), !0;
|
|
1421
|
-
} catch {
|
|
1422
|
-
return !1;
|
|
1423
|
-
}
|
|
1348
|
+
fileExists(e) {
|
|
1349
|
+
try {
|
|
1350
|
+
return this[__private__dont__use].FS.lookupPath(e), !0;
|
|
1351
|
+
} catch {
|
|
1352
|
+
return !1;
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
/**
|
|
1356
|
+
* Hot-swaps the PHP runtime for a new one without
|
|
1357
|
+
* interrupting the operations of this PHP instance.
|
|
1358
|
+
*
|
|
1359
|
+
* @param runtime
|
|
1360
|
+
* @param cwd. Internal, the VFS path to recreate in the new runtime.
|
|
1361
|
+
* This arg is temporary and will be removed once BasePHP
|
|
1362
|
+
* is fully decoupled from the request handler and
|
|
1363
|
+
* accepts a constructor-level cwd argument.
|
|
1364
|
+
*/
|
|
1365
|
+
hotSwapPHPRuntime(e, t) {
|
|
1366
|
+
const r = this[__private__dont__use].FS;
|
|
1367
|
+
try {
|
|
1368
|
+
this.exit();
|
|
1369
|
+
} catch {
|
|
1370
|
+
}
|
|
1371
|
+
this.initializeRuntime(e), u(this, v) && this.setPhpIniPath(u(this, v)), u(this, R) && this.setSapiName(u(this, R)), t && copyFS(r, this[__private__dont__use].FS, t);
|
|
1372
|
+
}
|
|
1373
|
+
exit(e = 0) {
|
|
1374
|
+
this.dispatchEvent({
|
|
1375
|
+
type: "runtime.beforedestroy"
|
|
1376
|
+
});
|
|
1377
|
+
try {
|
|
1378
|
+
this[__private__dont__use]._exit(e);
|
|
1379
|
+
} catch {
|
|
1380
|
+
}
|
|
1381
|
+
d(this, f, !1), d(this, P, null), delete this[__private__dont__use].onMessage, delete this[__private__dont__use];
|
|
1382
|
+
}
|
|
1383
|
+
[Symbol.dispose]() {
|
|
1384
|
+
u(this, f) && this.exit(0);
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
w = new WeakMap(), v = new WeakMap(), R = new WeakMap(), f = new WeakMap(), P = new WeakMap(), _ = new WeakMap(), S = new WeakMap(), C = new WeakSet(), Z = function(e, t, r) {
|
|
1388
|
+
const s = {
|
|
1389
|
+
...e || {}
|
|
1390
|
+
};
|
|
1391
|
+
s.HTTPS = s.HTTPS || r === 443 ? "on" : "off";
|
|
1392
|
+
for (const n in t) {
|
|
1393
|
+
let i = "HTTP_";
|
|
1394
|
+
["content-type", "content-length"].includes(n.toLowerCase()) && (i = ""), s[`${i}${n.toUpperCase().replace(/-/g, "_")}`] = t[n];
|
|
1395
|
+
}
|
|
1396
|
+
return s;
|
|
1397
|
+
}, I = new WeakSet(), Y = function() {
|
|
1398
|
+
if (this.setPhpIniEntry("auto_prepend_file", "/internal/consts.php"), this.fileExists("/internal/consts.php") || this.writeFile(
|
|
1399
|
+
"/internal/consts.php",
|
|
1400
|
+
`<?php
|
|
1401
|
+
if(file_exists('/internal/consts.json')) {
|
|
1402
|
+
$consts = json_decode(file_get_contents('/internal/consts.json'), true);
|
|
1403
|
+
foreach ($consts as $const => $value) {
|
|
1404
|
+
if (!defined($const) && is_scalar($value)) {
|
|
1405
|
+
define($const, $value);
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
}`
|
|
1409
|
+
), u(this, w).length > 0) {
|
|
1410
|
+
const e = u(this, w).map(([t, r]) => `${t}=${r}`).join(`
|
|
1411
|
+
`) + `
|
|
1412
|
+
|
|
1413
|
+
`;
|
|
1414
|
+
this[__private__dont__use].ccall(
|
|
1415
|
+
"wasm_set_phpini_entries",
|
|
1416
|
+
null,
|
|
1417
|
+
[STRING],
|
|
1418
|
+
[e]
|
|
1419
|
+
);
|
|
1420
|
+
}
|
|
1421
|
+
this[__private__dont__use].ccall("php_wasm_init", null, [], []);
|
|
1422
|
+
}, A = new WeakSet(), K = function() {
|
|
1423
|
+
const e = "/internal/headers.json";
|
|
1424
|
+
if (!this.fileExists(e))
|
|
1425
|
+
throw new Error(
|
|
1426
|
+
"SAPI Error: Could not find response headers file."
|
|
1427
|
+
);
|
|
1428
|
+
const t = JSON.parse(this.readFileAsText(e)), r = {};
|
|
1429
|
+
for (const s of t.headers) {
|
|
1430
|
+
if (!s.includes(": "))
|
|
1431
|
+
continue;
|
|
1432
|
+
const n = s.indexOf(": "), i = s.substring(0, n).toLowerCase(), o = s.substring(n + 2);
|
|
1433
|
+
i in r || (r[i] = []), r[i].push(o);
|
|
1434
|
+
}
|
|
1435
|
+
return {
|
|
1436
|
+
headers: r,
|
|
1437
|
+
httpStatusCode: t.status
|
|
1438
|
+
};
|
|
1439
|
+
}, k = new WeakSet(), X = function(e) {
|
|
1440
|
+
if (this[__private__dont__use].ccall(
|
|
1441
|
+
"wasm_set_request_uri",
|
|
1442
|
+
null,
|
|
1443
|
+
[STRING],
|
|
1444
|
+
[e]
|
|
1445
|
+
), e.includes("?")) {
|
|
1446
|
+
const t = e.substring(e.indexOf("?") + 1);
|
|
1447
|
+
this[__private__dont__use].ccall(
|
|
1448
|
+
"wasm_set_query_string",
|
|
1449
|
+
null,
|
|
1450
|
+
[STRING],
|
|
1451
|
+
[t]
|
|
1452
|
+
);
|
|
1453
|
+
}
|
|
1454
|
+
}, M = new WeakSet(), ee = function(e) {
|
|
1455
|
+
this[__private__dont__use].ccall(
|
|
1456
|
+
"wasm_set_request_host",
|
|
1457
|
+
null,
|
|
1458
|
+
[STRING],
|
|
1459
|
+
[e]
|
|
1460
|
+
);
|
|
1461
|
+
}, B = new WeakSet(), te = function(e) {
|
|
1462
|
+
this[__private__dont__use].ccall(
|
|
1463
|
+
"wasm_set_request_port",
|
|
1464
|
+
null,
|
|
1465
|
+
[NUMBER],
|
|
1466
|
+
[e]
|
|
1467
|
+
);
|
|
1468
|
+
}, L = new WeakSet(), re = function(e, t) {
|
|
1469
|
+
let r;
|
|
1470
|
+
try {
|
|
1471
|
+
r = parseInt(new URL(e).port, 10);
|
|
1472
|
+
} catch {
|
|
1473
|
+
}
|
|
1474
|
+
return (!r || isNaN(r) || r === 80) && (r = t === "https" ? 443 : 80), r;
|
|
1475
|
+
}, N = new WeakSet(), se = function(e) {
|
|
1476
|
+
this[__private__dont__use].ccall(
|
|
1477
|
+
"wasm_set_request_method",
|
|
1478
|
+
null,
|
|
1479
|
+
[STRING],
|
|
1480
|
+
[e]
|
|
1481
|
+
);
|
|
1482
|
+
}, U = new WeakSet(), ne = function(e) {
|
|
1483
|
+
e.cookie && this[__private__dont__use].ccall(
|
|
1484
|
+
"wasm_set_cookies",
|
|
1485
|
+
null,
|
|
1486
|
+
[STRING],
|
|
1487
|
+
[e.cookie]
|
|
1488
|
+
), e["content-type"] && this[__private__dont__use].ccall(
|
|
1489
|
+
"wasm_set_content_type",
|
|
1490
|
+
null,
|
|
1491
|
+
[STRING],
|
|
1492
|
+
[e["content-type"]]
|
|
1493
|
+
), e["content-length"] && this[__private__dont__use].ccall(
|
|
1494
|
+
"wasm_set_content_length",
|
|
1495
|
+
null,
|
|
1496
|
+
[NUMBER],
|
|
1497
|
+
[parseInt(e["content-length"], 10)]
|
|
1498
|
+
);
|
|
1499
|
+
}, O = new WeakSet(), ie = function(e) {
|
|
1500
|
+
let t, r;
|
|
1501
|
+
typeof e == "string" ? (logger.warn(
|
|
1502
|
+
"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"
|
|
1503
|
+
), r = this[__private__dont__use].lengthBytesUTF8(e), t = r + 1) : (r = e.byteLength, t = e.byteLength);
|
|
1504
|
+
const s = this[__private__dont__use].malloc(t);
|
|
1505
|
+
if (!s)
|
|
1506
|
+
throw new Error("Could not allocate memory for the request body.");
|
|
1507
|
+
return typeof e == "string" ? this[__private__dont__use].stringToUTF8(
|
|
1508
|
+
e,
|
|
1509
|
+
s,
|
|
1510
|
+
t + 1
|
|
1511
|
+
) : this[__private__dont__use].HEAPU8.set(e, s), this[__private__dont__use].ccall(
|
|
1512
|
+
"wasm_set_request_body",
|
|
1513
|
+
null,
|
|
1514
|
+
[NUMBER],
|
|
1515
|
+
[s]
|
|
1516
|
+
), this[__private__dont__use].ccall(
|
|
1517
|
+
"wasm_set_content_length",
|
|
1518
|
+
null,
|
|
1519
|
+
[NUMBER],
|
|
1520
|
+
[r]
|
|
1521
|
+
), s;
|
|
1522
|
+
}, D = new WeakSet(), oe = function(e) {
|
|
1523
|
+
this[__private__dont__use].ccall(
|
|
1524
|
+
"wasm_set_path_translated",
|
|
1525
|
+
null,
|
|
1526
|
+
[STRING],
|
|
1527
|
+
[e]
|
|
1528
|
+
);
|
|
1529
|
+
}, $ = new WeakSet(), ae = function(e, t) {
|
|
1530
|
+
this[__private__dont__use].ccall(
|
|
1531
|
+
"wasm_add_SERVER_entry",
|
|
1532
|
+
null,
|
|
1533
|
+
[STRING, STRING],
|
|
1534
|
+
[e, t]
|
|
1535
|
+
);
|
|
1536
|
+
}, q = new WeakSet(), le = function(e, t) {
|
|
1537
|
+
this[__private__dont__use].ccall(
|
|
1538
|
+
"wasm_add_ENV_entry",
|
|
1539
|
+
null,
|
|
1540
|
+
[STRING, STRING],
|
|
1541
|
+
[e, t]
|
|
1542
|
+
);
|
|
1543
|
+
}, j = new WeakSet(), ce = function(e) {
|
|
1544
|
+
this[__private__dont__use].ccall(
|
|
1545
|
+
"wasm_set_php_code",
|
|
1546
|
+
null,
|
|
1547
|
+
[STRING],
|
|
1548
|
+
[e]
|
|
1549
|
+
);
|
|
1550
|
+
}, z = new WeakSet(), ue = async function() {
|
|
1551
|
+
var n;
|
|
1552
|
+
let e, t;
|
|
1553
|
+
try {
|
|
1554
|
+
e = await new Promise((i, o) => {
|
|
1555
|
+
var l;
|
|
1556
|
+
t = (c) => {
|
|
1557
|
+
logger.error(c), logger.error(c.error);
|
|
1558
|
+
const g = new Error("Rethrown");
|
|
1559
|
+
g.cause = c.error, g.betterMessage = c.message, o(g);
|
|
1560
|
+
}, (l = u(this, P)) == null || l.addEventListener(
|
|
1561
|
+
"error",
|
|
1562
|
+
t
|
|
1563
|
+
);
|
|
1564
|
+
const a = this[__private__dont__use].ccall(
|
|
1565
|
+
"wasm_sapi_handle_request",
|
|
1566
|
+
NUMBER,
|
|
1567
|
+
[],
|
|
1568
|
+
[],
|
|
1569
|
+
{ async: !0 }
|
|
1570
|
+
);
|
|
1571
|
+
return a instanceof Promise ? a.then(i, o) : i(a);
|
|
1572
|
+
});
|
|
1573
|
+
} catch (i) {
|
|
1574
|
+
for (const c in this)
|
|
1575
|
+
typeof this[c] == "function" && (this[c] = () => {
|
|
1576
|
+
throw new Error(
|
|
1577
|
+
"PHP runtime has crashed – see the earlier error for details."
|
|
1578
|
+
);
|
|
1579
|
+
});
|
|
1580
|
+
this.functionsMaybeMissingFromAsyncify = getFunctionsMaybeMissingFromAsyncify();
|
|
1581
|
+
const o = i, a = "betterMessage" in o ? o.betterMessage : o.message, l = new Error(a);
|
|
1582
|
+
throw l.cause = o, logger.error(l), l;
|
|
1583
|
+
} finally {
|
|
1584
|
+
(n = u(this, P)) == null || n.removeEventListener("error", t);
|
|
1585
|
+
}
|
|
1586
|
+
const { headers: r, httpStatusCode: s } = p(this, A, K).call(this);
|
|
1587
|
+
return new PHPResponse(
|
|
1588
|
+
e === 0 ? s : 500,
|
|
1589
|
+
r,
|
|
1590
|
+
this.readFileAsBuffer("/internal/stdout"),
|
|
1591
|
+
this.readFileAsText("/internal/stderr"),
|
|
1592
|
+
e
|
|
1593
|
+
);
|
|
1594
|
+
};
|
|
1595
|
+
__decorateClass([
|
|
1596
|
+
rethrowFileSystemError('Could not create directory "{path}"')
|
|
1597
|
+
], BasePHP.prototype, "mkdir", 1);
|
|
1598
|
+
__decorateClass([
|
|
1599
|
+
rethrowFileSystemError('Could not create directory "{path}"')
|
|
1600
|
+
], BasePHP.prototype, "mkdirTree", 1);
|
|
1601
|
+
__decorateClass([
|
|
1602
|
+
rethrowFileSystemError('Could not read "{path}"')
|
|
1603
|
+
], BasePHP.prototype, "readFileAsText", 1);
|
|
1604
|
+
__decorateClass([
|
|
1605
|
+
rethrowFileSystemError('Could not read "{path}"')
|
|
1606
|
+
], BasePHP.prototype, "readFileAsBuffer", 1);
|
|
1607
|
+
__decorateClass([
|
|
1608
|
+
rethrowFileSystemError('Could not write to "{path}"')
|
|
1609
|
+
], BasePHP.prototype, "writeFile", 1);
|
|
1610
|
+
__decorateClass([
|
|
1611
|
+
rethrowFileSystemError('Could not unlink "{path}"')
|
|
1612
|
+
], BasePHP.prototype, "unlink", 1);
|
|
1613
|
+
__decorateClass([
|
|
1614
|
+
rethrowFileSystemError('Could not remove directory "{path}"')
|
|
1615
|
+
], BasePHP.prototype, "rmdir", 1);
|
|
1616
|
+
__decorateClass([
|
|
1617
|
+
rethrowFileSystemError('Could not list files in "{path}"')
|
|
1618
|
+
], BasePHP.prototype, "listFiles", 1);
|
|
1619
|
+
__decorateClass([
|
|
1620
|
+
rethrowFileSystemError('Could not stat "{path}"')
|
|
1621
|
+
], BasePHP.prototype, "isDir", 1);
|
|
1622
|
+
__decorateClass([
|
|
1623
|
+
rethrowFileSystemError('Could not stat "{path}"')
|
|
1624
|
+
], BasePHP.prototype, "fileExists", 1);
|
|
1625
|
+
function normalizeHeaders(e) {
|
|
1626
|
+
const t = {};
|
|
1627
|
+
for (const r in e)
|
|
1628
|
+
t[r.toLowerCase()] = e[r];
|
|
1629
|
+
return t;
|
|
1630
|
+
}
|
|
1631
|
+
function copyFS(e, t, r) {
|
|
1632
|
+
let s;
|
|
1633
|
+
try {
|
|
1634
|
+
s = e.lookupPath(r);
|
|
1635
|
+
} catch {
|
|
1636
|
+
return;
|
|
1637
|
+
}
|
|
1638
|
+
if (!("contents" in s.node))
|
|
1639
|
+
return;
|
|
1640
|
+
if (!e.isDir(s.node.mode)) {
|
|
1641
|
+
t.writeFile(r, e.readFile(r));
|
|
1642
|
+
return;
|
|
1424
1643
|
}
|
|
1644
|
+
t.mkdirTree(r);
|
|
1645
|
+
const n = e.readdir(r).filter((i) => i !== "." && i !== "..");
|
|
1646
|
+
for (const i of n)
|
|
1647
|
+
copyFS(e, t, joinPaths(r, i));
|
|
1648
|
+
}
|
|
1649
|
+
function isLocalPHP(e) {
|
|
1650
|
+
return !(e instanceof BasePHP);
|
|
1651
|
+
}
|
|
1652
|
+
function isRemotePHP(e) {
|
|
1653
|
+
return !isLocalPHP(e);
|
|
1654
|
+
}
|
|
1655
|
+
const DEFAULT_BASE_URL = "http://example.com";
|
|
1656
|
+
function toRelativeUrl(e) {
|
|
1657
|
+
return e.toString().substring(e.origin.length);
|
|
1658
|
+
}
|
|
1659
|
+
function removePathPrefix(e, t) {
|
|
1660
|
+
return !t || !e.startsWith(t) ? e : e.substring(t.length);
|
|
1661
|
+
}
|
|
1662
|
+
function ensurePathPrefix(e, t) {
|
|
1663
|
+
return !t || e.startsWith(t) ? e : t + e;
|
|
1664
|
+
}
|
|
1665
|
+
async function encodeAsMultipart(e) {
|
|
1666
|
+
const t = `----${Math.random().toString(36).slice(2)}`, r = `multipart/form-data; boundary=${t}`, s = new TextEncoder(), n = [];
|
|
1667
|
+
for (const [l, c] of Object.entries(e))
|
|
1668
|
+
n.push(`--${t}\r
|
|
1669
|
+
`), n.push(`Content-Disposition: form-data; name="${l}"`), c instanceof File && n.push(`; filename="${c.name}"`), n.push(`\r
|
|
1670
|
+
`), c instanceof File && (n.push("Content-Type: application/octet-stream"), n.push(`\r
|
|
1671
|
+
`)), n.push(`\r
|
|
1672
|
+
`), c instanceof File ? n.push(await fileToUint8Array(c)) : n.push(c), n.push(`\r
|
|
1673
|
+
`);
|
|
1674
|
+
n.push(`--${t}--\r
|
|
1675
|
+
`);
|
|
1676
|
+
const i = n.reduce((l, c) => l + c.length, 0), o = new Uint8Array(i);
|
|
1677
|
+
let a = 0;
|
|
1678
|
+
for (const l of n)
|
|
1679
|
+
o.set(
|
|
1680
|
+
typeof l == "string" ? s.encode(l) : l,
|
|
1681
|
+
a
|
|
1682
|
+
), a += l.length;
|
|
1683
|
+
return { bytes: o, contentType: r };
|
|
1684
|
+
}
|
|
1685
|
+
function fileToUint8Array(e) {
|
|
1686
|
+
return new Promise((t) => {
|
|
1687
|
+
const r = new FileReader();
|
|
1688
|
+
r.onload = () => {
|
|
1689
|
+
t(new Uint8Array(r.result));
|
|
1690
|
+
}, r.readAsArrayBuffer(e);
|
|
1691
|
+
});
|
|
1692
|
+
}
|
|
1693
|
+
var y, b, T, E, x, m, F, H, W, he, G, de, J, pe, V, fe;
|
|
1694
|
+
class PHPRequestHandler {
|
|
1425
1695
|
/**
|
|
1426
|
-
*
|
|
1427
|
-
*
|
|
1696
|
+
* The request handler needs to decide whether to serve a static asset or
|
|
1697
|
+
* run the PHP interpreter. For static assets it should just reuse the primary
|
|
1698
|
+
* PHP even if there's 50 concurrent requests to serve. However, for
|
|
1699
|
+
* dynamic PHP requests, it needs to grab an available interpreter.
|
|
1700
|
+
* Therefore, it cannot just accept PHP as an argument as serving requests
|
|
1701
|
+
* requires access to ProcessManager.
|
|
1428
1702
|
*
|
|
1429
|
-
* @param
|
|
1430
|
-
* @param
|
|
1431
|
-
* This arg is temporary and will be removed once BasePHP
|
|
1432
|
-
* is fully decoupled from the request handler and
|
|
1433
|
-
* accepts a constructor-level cwd argument.
|
|
1703
|
+
* @param php - The PHP instance.
|
|
1704
|
+
* @param config - Request Handler configuration.
|
|
1434
1705
|
*/
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1706
|
+
constructor(t) {
|
|
1707
|
+
/**
|
|
1708
|
+
* Serves a static file from the PHP filesystem.
|
|
1709
|
+
*
|
|
1710
|
+
* @param fsPath - Absolute path of the static file to serve.
|
|
1711
|
+
* @returns The response.
|
|
1712
|
+
*/
|
|
1713
|
+
h(this, W);
|
|
1714
|
+
/**
|
|
1715
|
+
* Spawns a new PHP instance and dispatches a request to it.
|
|
1716
|
+
*/
|
|
1717
|
+
h(this, G);
|
|
1718
|
+
/**
|
|
1719
|
+
* Runs the requested PHP file with all the request and $_SERVER
|
|
1720
|
+
* superglobals populated.
|
|
1721
|
+
*
|
|
1722
|
+
* @param request - The request.
|
|
1723
|
+
* @returns The response.
|
|
1724
|
+
*/
|
|
1725
|
+
h(this, J);
|
|
1726
|
+
/**
|
|
1727
|
+
* Resolve the requested path to the filesystem path of the requested PHP file.
|
|
1728
|
+
*
|
|
1729
|
+
* Fall back to index.php as if there was a url rewriting rule in place.
|
|
1730
|
+
*
|
|
1731
|
+
* @param requestedPath - The requested pathname.
|
|
1732
|
+
* @throws {Error} If the requested path doesn't exist.
|
|
1733
|
+
* @returns The resolved filesystem path.
|
|
1734
|
+
*/
|
|
1735
|
+
h(this, V);
|
|
1736
|
+
h(this, y, void 0);
|
|
1737
|
+
h(this, b, void 0);
|
|
1738
|
+
h(this, T, void 0);
|
|
1739
|
+
h(this, E, void 0);
|
|
1740
|
+
h(this, x, void 0);
|
|
1741
|
+
h(this, m, void 0);
|
|
1742
|
+
h(this, F, void 0);
|
|
1743
|
+
h(this, H, void 0);
|
|
1744
|
+
const {
|
|
1745
|
+
documentRoot: r = "/www/",
|
|
1746
|
+
absoluteUrl: s = typeof location == "object" ? location == null ? void 0 : location.href : "",
|
|
1747
|
+
rewriteRules: n = []
|
|
1748
|
+
} = t;
|
|
1749
|
+
"processManager" in t ? this.processManager = t.processManager : this.processManager = new PHPProcessManager({
|
|
1750
|
+
phpFactory: async (a) => {
|
|
1751
|
+
const l = await t.phpFactory({
|
|
1752
|
+
...a,
|
|
1753
|
+
requestHandler: this
|
|
1754
|
+
});
|
|
1755
|
+
return l.requestHandler = this, l;
|
|
1756
|
+
},
|
|
1757
|
+
maxPhpInstances: t.maxPhpInstances
|
|
1758
|
+
}), d(this, H, new HttpCookieStore()), d(this, y, r);
|
|
1759
|
+
const i = new URL(s);
|
|
1760
|
+
d(this, T, i.hostname), d(this, E, i.port ? Number(i.port) : i.protocol === "https:" ? 443 : 80), d(this, b, (i.protocol || "").replace(":", ""));
|
|
1761
|
+
const o = u(this, E) !== 443 && u(this, E) !== 80;
|
|
1762
|
+
d(this, x, [
|
|
1763
|
+
u(this, T),
|
|
1764
|
+
o ? `:${u(this, E)}` : ""
|
|
1765
|
+
].join("")), d(this, m, i.pathname.replace(/\/+$/, "")), d(this, F, [
|
|
1766
|
+
`${u(this, b)}://`,
|
|
1767
|
+
u(this, x),
|
|
1768
|
+
u(this, m)
|
|
1769
|
+
].join("")), this.rewriteRules = n;
|
|
1770
|
+
}
|
|
1771
|
+
async getPrimaryPhp() {
|
|
1772
|
+
return await this.processManager.getPrimaryPhp();
|
|
1442
1773
|
}
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1774
|
+
/**
|
|
1775
|
+
* Converts a path to an absolute URL based at the PHPRequestHandler
|
|
1776
|
+
* root.
|
|
1777
|
+
*
|
|
1778
|
+
* @param path The server path to convert to an absolute URL.
|
|
1779
|
+
* @returns The absolute URL.
|
|
1780
|
+
*/
|
|
1781
|
+
pathToInternalUrl(t) {
|
|
1782
|
+
return `${this.absoluteUrl}${t}`;
|
|
1452
1783
|
}
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1784
|
+
/**
|
|
1785
|
+
* Converts an absolute URL based at the PHPRequestHandler to a relative path
|
|
1786
|
+
* without the server pathname and scope.
|
|
1787
|
+
*
|
|
1788
|
+
* @param internalUrl An absolute URL based at the PHPRequestHandler root.
|
|
1789
|
+
* @returns The relative path.
|
|
1790
|
+
*/
|
|
1791
|
+
internalUrlToPath(t) {
|
|
1792
|
+
const r = new URL(t);
|
|
1793
|
+
return r.pathname.startsWith(u(this, m)) && (r.pathname = r.pathname.slice(u(this, m).length)), toRelativeUrl(r);
|
|
1462
1794
|
}
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
if(file_exists('/internal/consts.json')) {
|
|
1469
|
-
$consts = json_decode(file_get_contents('/internal/consts.json'), true);
|
|
1470
|
-
foreach ($consts as $const => $value) {
|
|
1471
|
-
if (!defined($const) && is_scalar($value)) {
|
|
1472
|
-
define($const, $value);
|
|
1473
|
-
}
|
|
1474
|
-
}
|
|
1475
|
-
}`
|
|
1476
|
-
), c(this, R).length > 0) {
|
|
1477
|
-
const e = c(this, R).map(([t, r]) => `${t}=${r}`).join(`
|
|
1478
|
-
`) + `
|
|
1479
|
-
|
|
1480
|
-
`;
|
|
1481
|
-
this[__private__dont__use].ccall(
|
|
1482
|
-
"wasm_set_phpini_entries",
|
|
1483
|
-
null,
|
|
1484
|
-
[STRING],
|
|
1485
|
-
[e]
|
|
1486
|
-
);
|
|
1795
|
+
/**
|
|
1796
|
+
* The absolute URL of this PHPRequestHandler instance.
|
|
1797
|
+
*/
|
|
1798
|
+
get absoluteUrl() {
|
|
1799
|
+
return u(this, F);
|
|
1487
1800
|
}
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
);
|
|
1495
|
-
const t = JSON.parse(this.readFileAsText(e)), r = {};
|
|
1496
|
-
for (const s of t.headers) {
|
|
1497
|
-
if (!s.includes(": "))
|
|
1498
|
-
continue;
|
|
1499
|
-
const n = s.indexOf(": "), o = s.substring(0, n).toLowerCase(), i = s.substring(n + 2);
|
|
1500
|
-
o in r || (r[o] = []), r[o].push(i);
|
|
1801
|
+
/**
|
|
1802
|
+
* The directory in the PHP filesystem where the server will look
|
|
1803
|
+
* for the files to serve. Default: `/var/www`.
|
|
1804
|
+
*/
|
|
1805
|
+
get documentRoot() {
|
|
1806
|
+
return u(this, y);
|
|
1501
1807
|
}
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1808
|
+
/**
|
|
1809
|
+
* Serves the request – either by serving a static file, or by
|
|
1810
|
+
* dispatching it to the PHP runtime.
|
|
1811
|
+
*
|
|
1812
|
+
* The request() method mode behaves like a web server and only works if
|
|
1813
|
+
* the PHP was initialized with a `requestHandler` option (which the online version
|
|
1814
|
+
* of WordPress Playground does by default).
|
|
1815
|
+
*
|
|
1816
|
+
* In the request mode, you pass an object containing the request information
|
|
1817
|
+
* (method, headers, body, etc.) and the path to the PHP file to run:
|
|
1818
|
+
*
|
|
1819
|
+
* ```ts
|
|
1820
|
+
* const php = PHP.load('7.4', {
|
|
1821
|
+
* requestHandler: {
|
|
1822
|
+
* documentRoot: "/www"
|
|
1823
|
+
* }
|
|
1824
|
+
* })
|
|
1825
|
+
* php.writeFile("/www/index.php", `<?php echo file_get_contents("php://input");`);
|
|
1826
|
+
* const result = await php.request({
|
|
1827
|
+
* method: "GET",
|
|
1828
|
+
* headers: {
|
|
1829
|
+
* "Content-Type": "text/plain"
|
|
1830
|
+
* },
|
|
1831
|
+
* body: "Hello world!",
|
|
1832
|
+
* path: "/www/index.php"
|
|
1833
|
+
* });
|
|
1834
|
+
* // result.text === "Hello world!"
|
|
1835
|
+
* ```
|
|
1836
|
+
*
|
|
1837
|
+
* The `request()` method cannot be used in conjunction with `cli()`.
|
|
1838
|
+
*
|
|
1839
|
+
* @example
|
|
1840
|
+
* ```js
|
|
1841
|
+
* const output = await php.request({
|
|
1842
|
+
* method: 'GET',
|
|
1843
|
+
* url: '/index.php',
|
|
1844
|
+
* headers: {
|
|
1845
|
+
* 'X-foo': 'bar',
|
|
1846
|
+
* },
|
|
1847
|
+
* body: {
|
|
1848
|
+
* foo: 'bar',
|
|
1849
|
+
* },
|
|
1850
|
+
* });
|
|
1851
|
+
* console.log(output.stdout); // "Hello world!"
|
|
1852
|
+
* ```
|
|
1853
|
+
*
|
|
1854
|
+
* @param request - PHP Request data.
|
|
1855
|
+
*/
|
|
1856
|
+
async request(t) {
|
|
1857
|
+
const r = t.url.startsWith("http://") || t.url.startsWith("https://"), s = new URL(
|
|
1858
|
+
// Remove the hash part of the URL as it's not meant for the server.
|
|
1859
|
+
t.url.split("#")[0],
|
|
1860
|
+
r ? void 0 : DEFAULT_BASE_URL
|
|
1861
|
+
), n = applyRewriteRules(
|
|
1862
|
+
removePathPrefix(
|
|
1863
|
+
decodeURIComponent(s.pathname),
|
|
1864
|
+
u(this, m)
|
|
1865
|
+
),
|
|
1866
|
+
this.rewriteRules
|
|
1867
|
+
), i = joinPaths(u(this, y), n);
|
|
1868
|
+
return seemsLikeAPHPRequestHandlerPath(i) ? p(this, G, de).call(this, t, s) : p(this, W, he).call(this, await this.processManager.getPrimaryPhp(), i);
|
|
1520
1869
|
}
|
|
1521
|
-
}
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1870
|
+
}
|
|
1871
|
+
y = new WeakMap(), b = new WeakMap(), T = new WeakMap(), E = new WeakMap(), x = new WeakMap(), m = new WeakMap(), F = new WeakMap(), H = new WeakMap(), W = new WeakSet(), he = function(t, r) {
|
|
1872
|
+
if (!t.fileExists(r))
|
|
1873
|
+
return new PHPResponse(
|
|
1874
|
+
404,
|
|
1875
|
+
// Let the service worker know that no static file was found
|
|
1876
|
+
// and that it's okay to issue a real fetch() to the server.
|
|
1877
|
+
{
|
|
1878
|
+
"x-file-type": ["static"]
|
|
1879
|
+
},
|
|
1880
|
+
new TextEncoder().encode("404 File not found")
|
|
1881
|
+
);
|
|
1882
|
+
const s = t.readFileAsBuffer(r);
|
|
1883
|
+
return new PHPResponse(
|
|
1884
|
+
200,
|
|
1885
|
+
{
|
|
1886
|
+
"content-length": [`${s.byteLength}`],
|
|
1887
|
+
// @TODO: Infer the content-type from the arrayBuffer instead of the file path.
|
|
1888
|
+
// The code below won't return the correct mime-type if the extension
|
|
1889
|
+
// was tampered with.
|
|
1890
|
+
"content-type": [inferMimeType(r)],
|
|
1891
|
+
"accept-ranges": ["bytes"],
|
|
1892
|
+
"cache-control": ["public, max-age=0"]
|
|
1893
|
+
},
|
|
1894
|
+
s
|
|
1534
1895
|
);
|
|
1535
|
-
},
|
|
1536
|
-
let
|
|
1896
|
+
}, G = new WeakSet(), de = async function(t, r) {
|
|
1897
|
+
let s;
|
|
1537
1898
|
try {
|
|
1538
|
-
|
|
1539
|
-
} catch {
|
|
1899
|
+
s = await this.processManager.acquirePHPInstance();
|
|
1900
|
+
} catch (n) {
|
|
1901
|
+
return n instanceof MaxPhpInstancesError ? PHPResponse.forHttpCode(502) : PHPResponse.forHttpCode(500);
|
|
1540
1902
|
}
|
|
1541
|
-
return (!r || isNaN(r) || r === 80) && (r = t === "https" ? 443 : 80), r;
|
|
1542
|
-
}, D = new WeakSet(), oe = function(e) {
|
|
1543
|
-
this[__private__dont__use].ccall(
|
|
1544
|
-
"wasm_set_request_method",
|
|
1545
|
-
null,
|
|
1546
|
-
[STRING],
|
|
1547
|
-
[e]
|
|
1548
|
-
);
|
|
1549
|
-
}, q = new WeakSet(), ae = function(e) {
|
|
1550
|
-
e.cookie && this[__private__dont__use].ccall(
|
|
1551
|
-
"wasm_set_cookies",
|
|
1552
|
-
null,
|
|
1553
|
-
[STRING],
|
|
1554
|
-
[e.cookie]
|
|
1555
|
-
), e["content-type"] && this[__private__dont__use].ccall(
|
|
1556
|
-
"wasm_set_content_type",
|
|
1557
|
-
null,
|
|
1558
|
-
[STRING],
|
|
1559
|
-
[e["content-type"]]
|
|
1560
|
-
), e["content-length"] && this[__private__dont__use].ccall(
|
|
1561
|
-
"wasm_set_content_length",
|
|
1562
|
-
null,
|
|
1563
|
-
[NUMBER],
|
|
1564
|
-
[parseInt(e["content-length"], 10)]
|
|
1565
|
-
);
|
|
1566
|
-
}, j = new WeakSet(), le = function(e) {
|
|
1567
|
-
let t, r;
|
|
1568
|
-
typeof e == "string" ? (console.warn(
|
|
1569
|
-
"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"
|
|
1570
|
-
), r = this[__private__dont__use].lengthBytesUTF8(e), t = r + 1) : (r = e.byteLength, t = e.byteLength);
|
|
1571
|
-
const s = this[__private__dont__use].malloc(t);
|
|
1572
|
-
if (!s)
|
|
1573
|
-
throw new Error("Could not allocate memory for the request body.");
|
|
1574
|
-
return typeof e == "string" ? this[__private__dont__use].stringToUTF8(
|
|
1575
|
-
e,
|
|
1576
|
-
s,
|
|
1577
|
-
t + 1
|
|
1578
|
-
) : this[__private__dont__use].HEAPU8.set(e, s), this[__private__dont__use].ccall(
|
|
1579
|
-
"wasm_set_request_body",
|
|
1580
|
-
null,
|
|
1581
|
-
[NUMBER],
|
|
1582
|
-
[s]
|
|
1583
|
-
), this[__private__dont__use].ccall(
|
|
1584
|
-
"wasm_set_content_length",
|
|
1585
|
-
null,
|
|
1586
|
-
[NUMBER],
|
|
1587
|
-
[r]
|
|
1588
|
-
), s;
|
|
1589
|
-
}, z = new WeakSet(), ce = function(e) {
|
|
1590
|
-
this[__private__dont__use].ccall(
|
|
1591
|
-
"wasm_set_path_translated",
|
|
1592
|
-
null,
|
|
1593
|
-
[STRING],
|
|
1594
|
-
[e]
|
|
1595
|
-
);
|
|
1596
|
-
}, W = new WeakSet(), ue = function(e, t) {
|
|
1597
|
-
this[__private__dont__use].ccall(
|
|
1598
|
-
"wasm_add_SERVER_entry",
|
|
1599
|
-
null,
|
|
1600
|
-
[STRING, STRING],
|
|
1601
|
-
[e, t]
|
|
1602
|
-
);
|
|
1603
|
-
}, G = new WeakSet(), de = function(e, t) {
|
|
1604
|
-
this[__private__dont__use].ccall(
|
|
1605
|
-
"wasm_add_ENV_entry",
|
|
1606
|
-
null,
|
|
1607
|
-
[STRING, STRING],
|
|
1608
|
-
[e, t]
|
|
1609
|
-
);
|
|
1610
|
-
}, V = new WeakSet(), he = function(e) {
|
|
1611
|
-
this[__private__dont__use].ccall(
|
|
1612
|
-
"wasm_set_php_code",
|
|
1613
|
-
null,
|
|
1614
|
-
[STRING],
|
|
1615
|
-
[e]
|
|
1616
|
-
);
|
|
1617
|
-
}, J = new WeakSet(), pe = async function() {
|
|
1618
|
-
var n;
|
|
1619
|
-
let e, t;
|
|
1620
1903
|
try {
|
|
1621
|
-
|
|
1622
|
-
var u;
|
|
1623
|
-
t = (l) => {
|
|
1624
|
-
console.error(l), console.error(l.error);
|
|
1625
|
-
const f = new Error("Rethrown");
|
|
1626
|
-
f.cause = l.error, f.betterMessage = l.message, i(f);
|
|
1627
|
-
}, (u = c(this, w)) == null || u.addEventListener(
|
|
1628
|
-
"error",
|
|
1629
|
-
t
|
|
1630
|
-
);
|
|
1631
|
-
const a = this[__private__dont__use].ccall(
|
|
1632
|
-
"wasm_sapi_handle_request",
|
|
1633
|
-
NUMBER,
|
|
1634
|
-
[],
|
|
1635
|
-
[],
|
|
1636
|
-
{ async: !0 }
|
|
1637
|
-
);
|
|
1638
|
-
return a instanceof Promise ? a.then(o, i) : o(a);
|
|
1639
|
-
});
|
|
1640
|
-
} catch (o) {
|
|
1641
|
-
for (const l in this)
|
|
1642
|
-
typeof this[l] == "function" && (this[l] = () => {
|
|
1643
|
-
throw new Error(
|
|
1644
|
-
"PHP runtime has crashed – see the earlier error for details."
|
|
1645
|
-
);
|
|
1646
|
-
});
|
|
1647
|
-
this.functionsMaybeMissingFromAsyncify = getFunctionsMaybeMissingFromAsyncify();
|
|
1648
|
-
const i = o, a = "betterMessage" in i ? i.betterMessage : i.message, u = new Error(a);
|
|
1649
|
-
throw u.cause = i, console.error(u), u;
|
|
1904
|
+
return await p(this, J, pe).call(this, s.php, t, r);
|
|
1650
1905
|
} finally {
|
|
1651
|
-
|
|
1906
|
+
s.reap();
|
|
1907
|
+
}
|
|
1908
|
+
}, J = new WeakSet(), pe = async function(t, r, s) {
|
|
1909
|
+
let n = "GET";
|
|
1910
|
+
const i = {
|
|
1911
|
+
host: u(this, x),
|
|
1912
|
+
...normalizeHeaders(r.headers || {}),
|
|
1913
|
+
cookie: u(this, H).getCookieRequestHeader()
|
|
1914
|
+
};
|
|
1915
|
+
let o = r.body;
|
|
1916
|
+
if (typeof o == "object" && !(o instanceof Uint8Array)) {
|
|
1917
|
+
n = "POST";
|
|
1918
|
+
const { bytes: l, contentType: c } = await encodeAsMultipart(o);
|
|
1919
|
+
o = l, i["content-type"] = c;
|
|
1652
1920
|
}
|
|
1653
|
-
|
|
1654
|
-
return new PHPResponse(
|
|
1655
|
-
e === 0 ? s : 500,
|
|
1656
|
-
r,
|
|
1657
|
-
this.readFileAsBuffer("/internal/stdout"),
|
|
1658
|
-
this.readFileAsText("/internal/stderr"),
|
|
1659
|
-
e
|
|
1660
|
-
);
|
|
1661
|
-
};
|
|
1662
|
-
__decorateClass([
|
|
1663
|
-
rethrowFileSystemError('Could not create directory "{path}"')
|
|
1664
|
-
], BasePHP.prototype, "mkdir", 1);
|
|
1665
|
-
__decorateClass([
|
|
1666
|
-
rethrowFileSystemError('Could not create directory "{path}"')
|
|
1667
|
-
], BasePHP.prototype, "mkdirTree", 1);
|
|
1668
|
-
__decorateClass([
|
|
1669
|
-
rethrowFileSystemError('Could not read "{path}"')
|
|
1670
|
-
], BasePHP.prototype, "readFileAsText", 1);
|
|
1671
|
-
__decorateClass([
|
|
1672
|
-
rethrowFileSystemError('Could not read "{path}"')
|
|
1673
|
-
], BasePHP.prototype, "readFileAsBuffer", 1);
|
|
1674
|
-
__decorateClass([
|
|
1675
|
-
rethrowFileSystemError('Could not write to "{path}"')
|
|
1676
|
-
], BasePHP.prototype, "writeFile", 1);
|
|
1677
|
-
__decorateClass([
|
|
1678
|
-
rethrowFileSystemError('Could not unlink "{path}"')
|
|
1679
|
-
], BasePHP.prototype, "unlink", 1);
|
|
1680
|
-
__decorateClass([
|
|
1681
|
-
rethrowFileSystemError('Could not remove directory "{path}"')
|
|
1682
|
-
], BasePHP.prototype, "rmdir", 1);
|
|
1683
|
-
__decorateClass([
|
|
1684
|
-
rethrowFileSystemError('Could not list files in "{path}"')
|
|
1685
|
-
], BasePHP.prototype, "listFiles", 1);
|
|
1686
|
-
__decorateClass([
|
|
1687
|
-
rethrowFileSystemError('Could not stat "{path}"')
|
|
1688
|
-
], BasePHP.prototype, "isDir", 1);
|
|
1689
|
-
__decorateClass([
|
|
1690
|
-
rethrowFileSystemError('Could not stat "{path}"')
|
|
1691
|
-
], BasePHP.prototype, "fileExists", 1);
|
|
1692
|
-
function normalizeHeaders(e) {
|
|
1693
|
-
const t = {};
|
|
1694
|
-
for (const r in e)
|
|
1695
|
-
t[r.toLowerCase()] = e[r];
|
|
1696
|
-
return t;
|
|
1697
|
-
}
|
|
1698
|
-
function copyFS(e, t, r) {
|
|
1699
|
-
let s;
|
|
1921
|
+
let a;
|
|
1700
1922
|
try {
|
|
1701
|
-
|
|
1923
|
+
a = p(this, V, fe).call(this, t, decodeURIComponent(s.pathname));
|
|
1702
1924
|
} catch {
|
|
1703
|
-
return;
|
|
1925
|
+
return PHPResponse.forHttpCode(404);
|
|
1704
1926
|
}
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1927
|
+
try {
|
|
1928
|
+
const l = await t.run({
|
|
1929
|
+
relativeUri: ensurePathPrefix(
|
|
1930
|
+
toRelativeUrl(s),
|
|
1931
|
+
u(this, m)
|
|
1932
|
+
),
|
|
1933
|
+
protocol: u(this, b),
|
|
1934
|
+
method: r.method || n,
|
|
1935
|
+
$_SERVER: {
|
|
1936
|
+
REMOTE_ADDR: "127.0.0.1",
|
|
1937
|
+
DOCUMENT_ROOT: u(this, y),
|
|
1938
|
+
HTTPS: u(this, F).startsWith("https://") ? "on" : ""
|
|
1939
|
+
},
|
|
1940
|
+
body: o,
|
|
1941
|
+
scriptPath: a,
|
|
1942
|
+
headers: i
|
|
1943
|
+
});
|
|
1944
|
+
return u(this, H).rememberCookiesFromResponseHeaders(
|
|
1945
|
+
l.headers
|
|
1946
|
+
), l;
|
|
1947
|
+
} catch (l) {
|
|
1948
|
+
const c = l;
|
|
1949
|
+
if (c != null && c.response)
|
|
1950
|
+
return c.response;
|
|
1951
|
+
throw l;
|
|
1952
|
+
}
|
|
1953
|
+
}, V = new WeakSet(), fe = function(t, r) {
|
|
1954
|
+
let s = removePathPrefix(r, u(this, m));
|
|
1955
|
+
s = applyRewriteRules(s, this.rewriteRules), s.includes(".php") ? s = s.split(".php")[0] + ".php" : t.isDir(`${u(this, y)}${s}`) ? (s.endsWith("/") || (s = `${s}/`), s = `${s}index.php`) : s = "/index.php";
|
|
1956
|
+
const n = `${u(this, y)}${s}`;
|
|
1957
|
+
if (t.fileExists(n))
|
|
1958
|
+
return n;
|
|
1959
|
+
throw new Error(`File not found: ${n}`);
|
|
1960
|
+
};
|
|
1961
|
+
function inferMimeType(e) {
|
|
1962
|
+
switch (e.split(".").pop()) {
|
|
1963
|
+
case "css":
|
|
1964
|
+
return "text/css";
|
|
1965
|
+
case "js":
|
|
1966
|
+
return "application/javascript";
|
|
1967
|
+
case "png":
|
|
1968
|
+
return "image/png";
|
|
1969
|
+
case "jpg":
|
|
1970
|
+
case "jpeg":
|
|
1971
|
+
return "image/jpeg";
|
|
1972
|
+
case "gif":
|
|
1973
|
+
return "image/gif";
|
|
1974
|
+
case "svg":
|
|
1975
|
+
return "image/svg+xml";
|
|
1976
|
+
case "woff":
|
|
1977
|
+
return "font/woff";
|
|
1978
|
+
case "woff2":
|
|
1979
|
+
return "font/woff2";
|
|
1980
|
+
case "ttf":
|
|
1981
|
+
return "font/ttf";
|
|
1982
|
+
case "otf":
|
|
1983
|
+
return "font/otf";
|
|
1984
|
+
case "eot":
|
|
1985
|
+
return "font/eot";
|
|
1986
|
+
case "ico":
|
|
1987
|
+
return "image/x-icon";
|
|
1988
|
+
case "html":
|
|
1989
|
+
return "text/html";
|
|
1990
|
+
case "json":
|
|
1991
|
+
return "application/json";
|
|
1992
|
+
case "xml":
|
|
1993
|
+
return "application/xml";
|
|
1994
|
+
case "txt":
|
|
1995
|
+
case "md":
|
|
1996
|
+
return "text/plain";
|
|
1997
|
+
case "pdf":
|
|
1998
|
+
return "application/pdf";
|
|
1999
|
+
case "webp":
|
|
2000
|
+
return "image/webp";
|
|
2001
|
+
case "mp3":
|
|
2002
|
+
return "audio/mpeg";
|
|
2003
|
+
case "mp4":
|
|
2004
|
+
return "video/mp4";
|
|
2005
|
+
case "csv":
|
|
2006
|
+
return "text/csv";
|
|
2007
|
+
case "xls":
|
|
2008
|
+
return "application/vnd.ms-excel";
|
|
2009
|
+
case "xlsx":
|
|
2010
|
+
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
|
2011
|
+
case "doc":
|
|
2012
|
+
return "application/msword";
|
|
2013
|
+
case "docx":
|
|
2014
|
+
return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
|
2015
|
+
case "ppt":
|
|
2016
|
+
return "application/vnd.ms-powerpoint";
|
|
2017
|
+
case "pptx":
|
|
2018
|
+
return "application/vnd.openxmlformats-officedocument.presentationml.presentation";
|
|
2019
|
+
case "zip":
|
|
2020
|
+
return "application/zip";
|
|
2021
|
+
case "rar":
|
|
2022
|
+
return "application/x-rar-compressed";
|
|
2023
|
+
case "tar":
|
|
2024
|
+
return "application/x-tar";
|
|
2025
|
+
case "gz":
|
|
2026
|
+
return "application/gzip";
|
|
2027
|
+
case "7z":
|
|
2028
|
+
return "application/x-7z-compressed";
|
|
2029
|
+
default:
|
|
2030
|
+
return "application-octet-stream";
|
|
1710
2031
|
}
|
|
1711
|
-
t.mkdirTree(r);
|
|
1712
|
-
const n = e.readdir(r).filter((o) => o !== "." && o !== "..");
|
|
1713
|
-
for (const o of n)
|
|
1714
|
-
copyFS(e, t, joinPaths(r, o));
|
|
1715
2032
|
}
|
|
1716
|
-
function
|
|
1717
|
-
return
|
|
2033
|
+
function seemsLikeAPHPRequestHandlerPath(e) {
|
|
2034
|
+
return seemsLikeAPHPFile(e) || seemsLikeADirectoryRoot(e);
|
|
1718
2035
|
}
|
|
1719
|
-
function
|
|
1720
|
-
return
|
|
2036
|
+
function seemsLikeAPHPFile(e) {
|
|
2037
|
+
return e.endsWith(".php") || e.includes(".php/");
|
|
2038
|
+
}
|
|
2039
|
+
function seemsLikeADirectoryRoot(e) {
|
|
2040
|
+
return !e.split("/").pop().includes(".");
|
|
2041
|
+
}
|
|
2042
|
+
function applyRewriteRules(e, t) {
|
|
2043
|
+
for (const r of t)
|
|
2044
|
+
if (new RegExp(r.match).test(e))
|
|
2045
|
+
return e.replace(r.match, r.replacement);
|
|
2046
|
+
return e;
|
|
1721
2047
|
}
|
|
1722
2048
|
function rotatePHPRuntime({
|
|
1723
2049
|
php: e,
|
|
@@ -1734,32 +2060,34 @@ function rotatePHPRuntime({
|
|
|
1734
2060
|
maxRequests: s = 400
|
|
1735
2061
|
}) {
|
|
1736
2062
|
let n = 0;
|
|
1737
|
-
async function
|
|
2063
|
+
async function i() {
|
|
1738
2064
|
if (++n < s)
|
|
1739
2065
|
return;
|
|
1740
2066
|
n = 0;
|
|
1741
|
-
const
|
|
2067
|
+
const o = await e.semaphore.acquire();
|
|
1742
2068
|
try {
|
|
1743
2069
|
e.hotSwapPHPRuntime(await r(), t);
|
|
1744
2070
|
} finally {
|
|
1745
|
-
|
|
2071
|
+
o();
|
|
1746
2072
|
}
|
|
1747
2073
|
}
|
|
1748
|
-
return e.addEventListener("request.end",
|
|
1749
|
-
e.removeEventListener("request.end",
|
|
2074
|
+
return e.addEventListener("request.end", i), function() {
|
|
2075
|
+
e.removeEventListener("request.end", i);
|
|
1750
2076
|
};
|
|
1751
2077
|
}
|
|
1752
2078
|
async function writeFiles(e, t, r, { rmRoot: s = !1 } = {}) {
|
|
1753
2079
|
s && await e.isDir(t) && await e.rmdir(t, { recursive: !0 });
|
|
1754
|
-
for (const [n,
|
|
1755
|
-
const
|
|
1756
|
-
await e.fileExists(dirname(
|
|
2080
|
+
for (const [n, i] of Object.entries(r)) {
|
|
2081
|
+
const o = joinPaths(t, n);
|
|
2082
|
+
await e.fileExists(dirname(o)) || await e.mkdir(dirname(o)), await e.writeFile(o, i);
|
|
1757
2083
|
}
|
|
1758
2084
|
}
|
|
1759
2085
|
export {
|
|
1760
2086
|
BasePHP,
|
|
1761
2087
|
DEFAULT_BASE_URL,
|
|
2088
|
+
HttpCookieStore,
|
|
1762
2089
|
LatestSupportedPHPVersion,
|
|
2090
|
+
PHPProcessManager,
|
|
1763
2091
|
PHPRequestHandler,
|
|
1764
2092
|
PHPResponse,
|
|
1765
2093
|
SupportedPHPExtensionBundles,
|