@php-wasm/node 3.1.20 → 3.1.22
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/README.md +45 -6
- package/index.cjs +337 -333
- package/index.js +332 -330
- package/lib/extensions/load-extensions.d.ts +59 -0
- package/lib/extensions/node-extension-resources.d.ts +20 -0
- package/lib/get-php-loader-module.d.ts +2 -2
- package/lib/index.d.ts +1 -1
- package/lib/load-runtime.d.ts +23 -3
- package/package.json +19 -18
- package/lib/extensions/intl/with-intl.d.ts +0 -2
- package/lib/extensions/memcached/with-memcached.d.ts +0 -2
- package/lib/extensions/redis/with-redis.d.ts +0 -2
- package/lib/extensions/xdebug/with-xdebug.d.ts +0 -11
package/index.js
CHANGED
|
@@ -25,6 +25,8 @@ async function getPHPLoaderModule(version = LatestSupportedPHPVersion) {
|
|
|
25
25
|
return (await import("@php-wasm/node-8-0")).getPHPLoaderModule();
|
|
26
26
|
case "7.4":
|
|
27
27
|
return (await import("@php-wasm/node-7-4")).getPHPLoaderModule();
|
|
28
|
+
case "5.2":
|
|
29
|
+
return (await import("@php-wasm/node-5-2")).getPHPLoaderModule();
|
|
28
30
|
}
|
|
29
31
|
throw new Error(`Unsupported PHP version ${version}`);
|
|
30
32
|
} catch (errorCandidate) {
|
|
@@ -389,8 +391,10 @@ async function withNetworking(phpModuleArgs = {}) {
|
|
|
389
391
|
// packages/php-wasm/node/src/lib/load-runtime.ts
|
|
390
392
|
import {
|
|
391
393
|
loadPHPRuntime,
|
|
392
|
-
FSHelpers
|
|
394
|
+
FSHelpers,
|
|
393
395
|
FileLockManagerComposite,
|
|
396
|
+
createLegacyPhpIniPreRunStep,
|
|
397
|
+
isLegacyPHPVersion,
|
|
394
398
|
ProcessIdAllocator
|
|
395
399
|
} from "@php-wasm/universal";
|
|
396
400
|
|
|
@@ -462,8 +466,8 @@ function bindUserSpace({ fileLockManager }, {
|
|
|
462
466
|
[F_WRLCK]: "exclusive",
|
|
463
467
|
[F_UNLCK]: "unlocked"
|
|
464
468
|
},
|
|
465
|
-
is_path_to_shared_fs(
|
|
466
|
-
const { node } = FS.lookupPath(
|
|
469
|
+
is_path_to_shared_fs(path3) {
|
|
470
|
+
const { node } = FS.lookupPath(path3, { noent_okay: true });
|
|
467
471
|
if (!node) {
|
|
468
472
|
return false;
|
|
469
473
|
}
|
|
@@ -1094,7 +1098,7 @@ function bindUserSpace({ fileLockManager }, {
|
|
|
1094
1098
|
}
|
|
1095
1099
|
|
|
1096
1100
|
// packages/php-wasm/node/src/lib/load-runtime.ts
|
|
1097
|
-
import
|
|
1101
|
+
import fs2 from "fs";
|
|
1098
1102
|
|
|
1099
1103
|
// packages/php-wasm/node/src/lib/file-lock-manager-for-posix.ts
|
|
1100
1104
|
import { MAX_ADDRESSABLE_FILE_OFFSET } from "@php-wasm/universal";
|
|
@@ -1112,7 +1116,7 @@ var FileLockManagerForPosix = class {
|
|
|
1112
1116
|
this.wholeFileLockMap = /* @__PURE__ */ new Map();
|
|
1113
1117
|
this.rangeLockedFds = /* @__PURE__ */ new Map();
|
|
1114
1118
|
}
|
|
1115
|
-
lockWholeFile(
|
|
1119
|
+
lockWholeFile(path3, op) {
|
|
1116
1120
|
const opType = op.type === "unlock" ? "un" : op.waitForLock ? op.type === "exclusive" ? "ex" : "sh" : op.type === "exclusive" ? "exnb" : "shnb";
|
|
1117
1121
|
try {
|
|
1118
1122
|
flockSync(op.fd, opType);
|
|
@@ -1124,7 +1128,7 @@ var FileLockManagerForPosix = class {
|
|
|
1124
1128
|
}
|
|
1125
1129
|
this.wholeFileLockMap.get(op.pid).set(op.fd, {
|
|
1126
1130
|
...op,
|
|
1127
|
-
path:
|
|
1131
|
+
path: path3
|
|
1128
1132
|
});
|
|
1129
1133
|
}
|
|
1130
1134
|
return true;
|
|
@@ -1135,7 +1139,7 @@ var FileLockManagerForPosix = class {
|
|
|
1135
1139
|
return false;
|
|
1136
1140
|
}
|
|
1137
1141
|
}
|
|
1138
|
-
lockFileByteRange(
|
|
1142
|
+
lockFileByteRange(path3, op, waitForLock) {
|
|
1139
1143
|
if (op.start === op.end) {
|
|
1140
1144
|
op = {
|
|
1141
1145
|
...op,
|
|
@@ -1156,10 +1160,10 @@ var FileLockManagerForPosix = class {
|
|
|
1156
1160
|
this.rangeLockedFds.set(op.pid, /* @__PURE__ */ new Map());
|
|
1157
1161
|
}
|
|
1158
1162
|
const pidMap = this.rangeLockedFds.get(op.pid);
|
|
1159
|
-
if (!pidMap.has(
|
|
1160
|
-
pidMap.set(
|
|
1163
|
+
if (!pidMap.has(path3)) {
|
|
1164
|
+
pidMap.set(path3, /* @__PURE__ */ new Set());
|
|
1161
1165
|
}
|
|
1162
|
-
pidMap.get(
|
|
1166
|
+
pidMap.get(path3).add(op.fd);
|
|
1163
1167
|
return true;
|
|
1164
1168
|
} catch (e) {
|
|
1165
1169
|
if (!isLockDenialError(e)) {
|
|
@@ -1168,13 +1172,13 @@ var FileLockManagerForPosix = class {
|
|
|
1168
1172
|
return false;
|
|
1169
1173
|
}
|
|
1170
1174
|
}
|
|
1171
|
-
findFirstConflictingByteRangeLock(
|
|
1175
|
+
findFirstConflictingByteRangeLock(path3, op) {
|
|
1172
1176
|
if (op.type === "unlocked") {
|
|
1173
1177
|
return void 0;
|
|
1174
1178
|
}
|
|
1175
|
-
const obtainedLock = this.lockFileByteRange(
|
|
1179
|
+
const obtainedLock = this.lockFileByteRange(path3, op, false);
|
|
1176
1180
|
if (obtainedLock) {
|
|
1177
|
-
this.lockFileByteRange(
|
|
1181
|
+
this.lockFileByteRange(path3, { ...op, type: "unlocked" }, true);
|
|
1178
1182
|
return void 0;
|
|
1179
1183
|
}
|
|
1180
1184
|
return {
|
|
@@ -1202,11 +1206,11 @@ var FileLockManagerForPosix = class {
|
|
|
1202
1206
|
}
|
|
1203
1207
|
this.wholeFileLockMap.delete(targetPid);
|
|
1204
1208
|
}
|
|
1205
|
-
for (const [
|
|
1209
|
+
for (const [path3, fdSet] of this.rangeLockedFds.get(targetPid) ?? []) {
|
|
1206
1210
|
for (const fd of fdSet) {
|
|
1207
1211
|
try {
|
|
1208
1212
|
this.lockFileByteRange(
|
|
1209
|
-
|
|
1213
|
+
path3,
|
|
1210
1214
|
{
|
|
1211
1215
|
pid: targetPid,
|
|
1212
1216
|
fd,
|
|
@@ -1218,7 +1222,7 @@ var FileLockManagerForPosix = class {
|
|
|
1218
1222
|
);
|
|
1219
1223
|
} catch (e) {
|
|
1220
1224
|
logger2.error(
|
|
1221
|
-
`releaseLocksForProcess: failed to unlock byte range for pid=${targetPid} fd=${fd} path=${
|
|
1225
|
+
`releaseLocksForProcess: failed to unlock byte range for pid=${targetPid} fd=${fd} path=${path3}`,
|
|
1222
1226
|
e
|
|
1223
1227
|
);
|
|
1224
1228
|
}
|
|
@@ -1282,7 +1286,7 @@ var FileLockManagerForWindows = class {
|
|
|
1282
1286
|
this.wholeFileLockMap = /* @__PURE__ */ new Map();
|
|
1283
1287
|
this.rangeLockedFds = /* @__PURE__ */ new Map();
|
|
1284
1288
|
}
|
|
1285
|
-
lockWholeFile(
|
|
1289
|
+
lockWholeFile(path3, op) {
|
|
1286
1290
|
const start = 0n;
|
|
1287
1291
|
const end = 2n ** 64n - 1n;
|
|
1288
1292
|
if (op.type === "unlock") {
|
|
@@ -1294,7 +1298,7 @@ var FileLockManagerForWindows = class {
|
|
|
1294
1298
|
}
|
|
1295
1299
|
} else {
|
|
1296
1300
|
logger3.warn(
|
|
1297
|
-
`lockWholeFile: unlock failed for pid=${op.pid} fd=${op.fd} path=${
|
|
1301
|
+
`lockWholeFile: unlock failed for pid=${op.pid} fd=${op.fd} path=${path3}`
|
|
1298
1302
|
);
|
|
1299
1303
|
}
|
|
1300
1304
|
return success2;
|
|
@@ -1362,22 +1366,22 @@ var FileLockManagerForWindows = class {
|
|
|
1362
1366
|
}
|
|
1363
1367
|
this.wholeFileLockMap.get(op.pid).set(op.fd, {
|
|
1364
1368
|
...op,
|
|
1365
|
-
path:
|
|
1369
|
+
path: path3
|
|
1366
1370
|
});
|
|
1367
1371
|
}
|
|
1368
1372
|
return success;
|
|
1369
1373
|
}
|
|
1370
|
-
lockFileByteRange(
|
|
1374
|
+
lockFileByteRange(path3, op, waitForLock) {
|
|
1371
1375
|
if (op.start === op.end) {
|
|
1372
1376
|
op = {
|
|
1373
1377
|
...op,
|
|
1374
1378
|
end: MAX_ADDRESSABLE_FILE_OFFSET2
|
|
1375
1379
|
};
|
|
1376
1380
|
}
|
|
1377
|
-
if (!this.rangeLockedFds.has(
|
|
1378
|
-
this.rangeLockedFds.set(
|
|
1381
|
+
if (!this.rangeLockedFds.has(path3)) {
|
|
1382
|
+
this.rangeLockedFds.set(path3, new FileLockIntervalTree());
|
|
1379
1383
|
}
|
|
1380
|
-
const lockedRangeTree = this.rangeLockedFds.get(
|
|
1384
|
+
const lockedRangeTree = this.rangeLockedFds.get(path3);
|
|
1381
1385
|
const overlappingLocks = lockedRangeTree.findOverlapping(op);
|
|
1382
1386
|
let preexistingLock;
|
|
1383
1387
|
if (overlappingLocks.length === 1 && overlappingLocks[0].pid === op.pid && // NOTE: FD shouldn't matter for fcntl() F_SETLK because it is a process-level lock,
|
|
@@ -1462,12 +1466,12 @@ var FileLockManagerForWindows = class {
|
|
|
1462
1466
|
return true;
|
|
1463
1467
|
}
|
|
1464
1468
|
}
|
|
1465
|
-
findFirstConflictingByteRangeLock(
|
|
1469
|
+
findFirstConflictingByteRangeLock(path3, op) {
|
|
1466
1470
|
if (op.type === "unlocked") {
|
|
1467
1471
|
return void 0;
|
|
1468
1472
|
}
|
|
1469
|
-
const obtainedLock = !!this.lockFileByteRange(
|
|
1470
|
-
this.lockFileByteRange(
|
|
1473
|
+
const obtainedLock = !!this.lockFileByteRange(path3, op, false);
|
|
1474
|
+
this.lockFileByteRange(path3, { ...op, type: "unlocked" }, false);
|
|
1471
1475
|
if (obtainedLock) {
|
|
1472
1476
|
return void 0;
|
|
1473
1477
|
}
|
|
@@ -1496,18 +1500,18 @@ var FileLockManagerForWindows = class {
|
|
|
1496
1500
|
}
|
|
1497
1501
|
this.wholeFileLockMap.delete(targetPid);
|
|
1498
1502
|
}
|
|
1499
|
-
for (const [
|
|
1503
|
+
for (const [path3, lockedRangeTree] of this.rangeLockedFds.entries()) {
|
|
1500
1504
|
const rangesLockedByTargetPid = lockedRangeTree.findLocksForProcess(targetPid);
|
|
1501
1505
|
for (const op of rangesLockedByTargetPid) {
|
|
1502
1506
|
try {
|
|
1503
1507
|
this.lockFileByteRange(
|
|
1504
|
-
|
|
1508
|
+
path3,
|
|
1505
1509
|
{ ...op, type: "unlocked" },
|
|
1506
1510
|
false
|
|
1507
1511
|
);
|
|
1508
1512
|
} catch (e) {
|
|
1509
1513
|
logger3.error(
|
|
1510
|
-
`releaseLocksForProcess: failed to unlock byte range for pid=${targetPid} fd=${op.fd} path=${
|
|
1514
|
+
`releaseLocksForProcess: failed to unlock byte range for pid=${targetPid} fd=${op.fd} path=${path3}`,
|
|
1511
1515
|
e
|
|
1512
1516
|
);
|
|
1513
1517
|
}
|
|
@@ -1543,204 +1547,63 @@ var FileLockManagerForWindows = class {
|
|
|
1543
1547
|
}
|
|
1544
1548
|
};
|
|
1545
1549
|
|
|
1546
|
-
// packages/php-wasm/node/src/lib/extensions/
|
|
1550
|
+
// packages/php-wasm/node/src/lib/extensions/load-extensions.ts
|
|
1547
1551
|
import { DEFAULT_IDE_KEY } from "@php-wasm/cli-util";
|
|
1548
1552
|
import {
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
SupportedPHPVersions
|
|
1552
|
-
SupportedPHPVersionsList
|
|
1553
|
+
withResolvedPHPExtensions,
|
|
1554
|
+
resolvePHPExtension,
|
|
1555
|
+
SupportedPHPVersions
|
|
1553
1556
|
} from "@php-wasm/universal";
|
|
1554
1557
|
import fs from "fs";
|
|
1558
|
+
import path2 from "path";
|
|
1555
1559
|
|
|
1556
|
-
// packages/php-wasm/node/src/lib/extensions/
|
|
1560
|
+
// packages/php-wasm/node/src/lib/extensions/intl/get-intl-extension-module.ts
|
|
1557
1561
|
import { LatestSupportedPHPVersion as LatestSupportedPHPVersion2 } from "@php-wasm/universal";
|
|
1558
|
-
async function
|
|
1562
|
+
async function getIntlExtensionModule(version = LatestSupportedPHPVersion2) {
|
|
1559
1563
|
switch (version) {
|
|
1560
1564
|
case "8.5":
|
|
1561
|
-
return (await import("@php-wasm/node-8-5")).
|
|
1565
|
+
return (await import("@php-wasm/node-8-5")).getIntlExtensionPath();
|
|
1562
1566
|
case "8.4":
|
|
1563
|
-
return (await import("@php-wasm/node-8-4")).
|
|
1567
|
+
return (await import("@php-wasm/node-8-4")).getIntlExtensionPath();
|
|
1564
1568
|
case "8.3":
|
|
1565
|
-
return (await import("@php-wasm/node-8-3")).
|
|
1569
|
+
return (await import("@php-wasm/node-8-3")).getIntlExtensionPath();
|
|
1566
1570
|
case "8.2":
|
|
1567
|
-
return (await import("@php-wasm/node-8-2")).
|
|
1571
|
+
return (await import("@php-wasm/node-8-2")).getIntlExtensionPath();
|
|
1568
1572
|
case "8.1":
|
|
1569
|
-
return (await import("@php-wasm/node-8-1")).
|
|
1573
|
+
return (await import("@php-wasm/node-8-1")).getIntlExtensionPath();
|
|
1570
1574
|
case "8.0":
|
|
1571
|
-
return (await import("@php-wasm/node-8-0")).
|
|
1575
|
+
return (await import("@php-wasm/node-8-0")).getIntlExtensionPath();
|
|
1572
1576
|
case "7.4":
|
|
1573
|
-
return (await import("@php-wasm/node-7-4")).
|
|
1577
|
+
return (await import("@php-wasm/node-7-4")).getIntlExtensionPath();
|
|
1574
1578
|
}
|
|
1575
1579
|
throw new Error(`Unsupported PHP version ${version}`);
|
|
1576
1580
|
}
|
|
1577
1581
|
|
|
1578
|
-
// packages/php-wasm/node/src/lib/extensions/
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
const filePath = await getXdebugExtensionModule(version);
|
|
1582
|
-
const extension = fs.readFileSync(filePath);
|
|
1583
|
-
return {
|
|
1584
|
-
...options,
|
|
1585
|
-
ENV: {
|
|
1586
|
-
...options.ENV,
|
|
1587
|
-
PHP_INI_SCAN_DIR: "/internal/shared/extensions"
|
|
1588
|
-
},
|
|
1589
|
-
onRuntimeInitialized: (phpRuntime) => {
|
|
1590
|
-
if (options.onRuntimeInitialized) {
|
|
1591
|
-
options.onRuntimeInitialized(phpRuntime);
|
|
1592
|
-
}
|
|
1593
|
-
if (!FSHelpers.fileExists(
|
|
1594
|
-
phpRuntime.FS,
|
|
1595
|
-
"/internal/shared/extensions"
|
|
1596
|
-
)) {
|
|
1597
|
-
phpRuntime.FS.mkdirTree("/internal/shared/extensions");
|
|
1598
|
-
}
|
|
1599
|
-
if (!FSHelpers.fileExists(
|
|
1600
|
-
phpRuntime.FS,
|
|
1601
|
-
`/internal/shared/extensions/${fileName}`
|
|
1602
|
-
)) {
|
|
1603
|
-
phpRuntime.FS.writeFile(
|
|
1604
|
-
`/internal/shared/extensions/${fileName}`,
|
|
1605
|
-
new Uint8Array(extension)
|
|
1606
|
-
);
|
|
1607
|
-
}
|
|
1608
|
-
if (!FSHelpers.fileExists(
|
|
1609
|
-
phpRuntime.FS,
|
|
1610
|
-
"/internal/shared/extensions/xdebug.ini"
|
|
1611
|
-
)) {
|
|
1612
|
-
const ideKey = xdebugOptions.ideKey || DEFAULT_IDE_KEY;
|
|
1613
|
-
phpRuntime.FS.writeFile(
|
|
1614
|
-
"/internal/shared/extensions/xdebug.ini",
|
|
1615
|
-
[
|
|
1616
|
-
"zend_extension=/internal/shared/extensions/xdebug.so",
|
|
1617
|
-
"xdebug.mode=debug,develop",
|
|
1618
|
-
"xdebug.start_with_request=yes",
|
|
1619
|
-
`xdebug.idekey="${ideKey}"`,
|
|
1620
|
-
// Path mapping is only available starting
|
|
1621
|
-
// from Xdebug 3.5, which is used by PHP 8.5+
|
|
1622
|
-
// Previous versions will ignore this entry.
|
|
1623
|
-
"xdebug.path_mapping=yes"
|
|
1624
|
-
].join("\n")
|
|
1625
|
-
);
|
|
1626
|
-
}
|
|
1627
|
-
const isPHP85orHigher = SupportedPHPVersionsList.indexOf(version) <= SupportedPHPVersions.indexOf("8.5");
|
|
1628
|
-
if (isPHP85orHigher) {
|
|
1629
|
-
const { pathMappings, pathSkippings } = xdebugOptions;
|
|
1630
|
-
if (!pathMappings && !pathSkippings)
|
|
1631
|
-
return;
|
|
1632
|
-
phpRuntime.FS.mkdir("/.xdebug");
|
|
1633
|
-
if (pathMappings) {
|
|
1634
|
-
phpRuntime.FS.writeFile(
|
|
1635
|
-
"/.xdebug/path.map",
|
|
1636
|
-
pathMappings.map((map) => `${map.vfsPath} = ${map.hostPath}`).join("\n")
|
|
1637
|
-
);
|
|
1638
|
-
}
|
|
1639
|
-
if (pathSkippings) {
|
|
1640
|
-
phpRuntime.FS.writeFile(
|
|
1641
|
-
"/.xdebug/skip.map",
|
|
1642
|
-
pathSkippings.map((path2) => `${path2} = SKIP`).join("\n")
|
|
1643
|
-
);
|
|
1644
|
-
}
|
|
1645
|
-
}
|
|
1646
|
-
}
|
|
1647
|
-
};
|
|
1648
|
-
}
|
|
1649
|
-
|
|
1650
|
-
// packages/php-wasm/node/src/lib/extensions/intl/with-intl.ts
|
|
1651
|
-
import { LatestSupportedPHPVersion as LatestSupportedPHPVersion5, FSHelpers as FSHelpers2 } from "@php-wasm/universal";
|
|
1652
|
-
import fs2 from "fs";
|
|
1653
|
-
import path from "path";
|
|
1654
|
-
|
|
1655
|
-
// packages/php-wasm/node/src/lib/extensions/intl/get-intl-extension-module.ts
|
|
1656
|
-
import { LatestSupportedPHPVersion as LatestSupportedPHPVersion4 } from "@php-wasm/universal";
|
|
1657
|
-
async function getIntlExtensionModule(version = LatestSupportedPHPVersion4) {
|
|
1582
|
+
// packages/php-wasm/node/src/lib/extensions/memcached/get-memcached-extension-module.ts
|
|
1583
|
+
import { LatestSupportedPHPVersion as LatestSupportedPHPVersion3 } from "@php-wasm/universal";
|
|
1584
|
+
async function getMemcachedExtensionModule(version = LatestSupportedPHPVersion3) {
|
|
1658
1585
|
switch (version) {
|
|
1659
1586
|
case "8.5":
|
|
1660
|
-
return (await import("@php-wasm/node-8-5")).
|
|
1587
|
+
return (await import("@php-wasm/node-8-5")).getMemcachedExtensionPath();
|
|
1661
1588
|
case "8.4":
|
|
1662
|
-
return (await import("@php-wasm/node-8-4")).
|
|
1589
|
+
return (await import("@php-wasm/node-8-4")).getMemcachedExtensionPath();
|
|
1663
1590
|
case "8.3":
|
|
1664
|
-
return (await import("@php-wasm/node-8-3")).
|
|
1591
|
+
return (await import("@php-wasm/node-8-3")).getMemcachedExtensionPath();
|
|
1665
1592
|
case "8.2":
|
|
1666
|
-
return (await import("@php-wasm/node-8-2")).
|
|
1593
|
+
return (await import("@php-wasm/node-8-2")).getMemcachedExtensionPath();
|
|
1667
1594
|
case "8.1":
|
|
1668
|
-
return (await import("@php-wasm/node-8-1")).
|
|
1595
|
+
return (await import("@php-wasm/node-8-1")).getMemcachedExtensionPath();
|
|
1669
1596
|
case "8.0":
|
|
1670
|
-
return (await import("@php-wasm/node-8-0")).
|
|
1597
|
+
return (await import("@php-wasm/node-8-0")).getMemcachedExtensionPath();
|
|
1671
1598
|
case "7.4":
|
|
1672
|
-
return (await import("@php-wasm/node-7-4")).
|
|
1599
|
+
return (await import("@php-wasm/node-7-4")).getMemcachedExtensionPath();
|
|
1673
1600
|
}
|
|
1674
1601
|
throw new Error(`Unsupported PHP version ${version}`);
|
|
1675
1602
|
}
|
|
1676
1603
|
|
|
1677
|
-
// packages/php-wasm/node/src/lib/extensions/intl/with-intl.ts
|
|
1678
|
-
async function withIntl(version = LatestSupportedPHPVersion5, options) {
|
|
1679
|
-
const extensionName = "intl.so";
|
|
1680
|
-
const extensionPath = await getIntlExtensionModule(version);
|
|
1681
|
-
const extension = fs2.readFileSync(extensionPath);
|
|
1682
|
-
const dataName = "icu.dat";
|
|
1683
|
-
const moduleDir = typeof __dirname !== "undefined" ? __dirname : import.meta.dirname;
|
|
1684
|
-
const dataPath = path.join(moduleDir, "shared", dataName);
|
|
1685
|
-
const ICUData = fs2.readFileSync(dataPath);
|
|
1686
|
-
return {
|
|
1687
|
-
...options,
|
|
1688
|
-
ENV: {
|
|
1689
|
-
...options.ENV,
|
|
1690
|
-
PHP_INI_SCAN_DIR: "/internal/shared/extensions",
|
|
1691
|
-
ICU_DATA: "/internal/shared"
|
|
1692
|
-
},
|
|
1693
|
-
onRuntimeInitialized: (phpRuntime) => {
|
|
1694
|
-
if (options.onRuntimeInitialized) {
|
|
1695
|
-
options.onRuntimeInitialized(phpRuntime);
|
|
1696
|
-
}
|
|
1697
|
-
if (!FSHelpers2.fileExists(
|
|
1698
|
-
phpRuntime.FS,
|
|
1699
|
-
"/internal/shared/extensions"
|
|
1700
|
-
)) {
|
|
1701
|
-
phpRuntime.FS.mkdirTree("/internal/shared/extensions");
|
|
1702
|
-
}
|
|
1703
|
-
if (!FSHelpers2.fileExists(
|
|
1704
|
-
phpRuntime.FS,
|
|
1705
|
-
`/internal/shared/extensions/${extensionName}`
|
|
1706
|
-
)) {
|
|
1707
|
-
phpRuntime.FS.writeFile(
|
|
1708
|
-
`/internal/shared/extensions/${extensionName}`,
|
|
1709
|
-
new Uint8Array(extension)
|
|
1710
|
-
);
|
|
1711
|
-
}
|
|
1712
|
-
if (!FSHelpers2.fileExists(
|
|
1713
|
-
phpRuntime.FS,
|
|
1714
|
-
"/internal/shared/extensions/intl.ini"
|
|
1715
|
-
)) {
|
|
1716
|
-
phpRuntime.FS.writeFile(
|
|
1717
|
-
"/internal/shared/extensions/intl.ini",
|
|
1718
|
-
[
|
|
1719
|
-
`extension=/internal/shared/extensions/${extensionName}`
|
|
1720
|
-
].join("\n")
|
|
1721
|
-
);
|
|
1722
|
-
}
|
|
1723
|
-
if (!FSHelpers2.fileExists(
|
|
1724
|
-
phpRuntime.FS,
|
|
1725
|
-
`${phpRuntime.ENV.ICU_DATA}/${dataName}`
|
|
1726
|
-
)) {
|
|
1727
|
-
phpRuntime.FS.mkdirTree(phpRuntime.ENV.ICU_DATA);
|
|
1728
|
-
phpRuntime.FS.writeFile(
|
|
1729
|
-
`${phpRuntime.ENV.ICU_DATA}/icudt74l.dat`,
|
|
1730
|
-
new Uint8Array(ICUData)
|
|
1731
|
-
);
|
|
1732
|
-
}
|
|
1733
|
-
}
|
|
1734
|
-
};
|
|
1735
|
-
}
|
|
1736
|
-
|
|
1737
|
-
// packages/php-wasm/node/src/lib/extensions/redis/with-redis.ts
|
|
1738
|
-
import { LatestSupportedPHPVersion as LatestSupportedPHPVersion7, FSHelpers as FSHelpers3 } from "@php-wasm/universal";
|
|
1739
|
-
import fs3 from "fs";
|
|
1740
|
-
|
|
1741
1604
|
// packages/php-wasm/node/src/lib/extensions/redis/get-redis-extension-module.ts
|
|
1742
|
-
import { LatestSupportedPHPVersion as
|
|
1743
|
-
async function getRedisExtensionModule(version =
|
|
1605
|
+
import { LatestSupportedPHPVersion as LatestSupportedPHPVersion4 } from "@php-wasm/universal";
|
|
1606
|
+
async function getRedisExtensionModule(version = LatestSupportedPHPVersion4) {
|
|
1744
1607
|
switch (version) {
|
|
1745
1608
|
case "8.5":
|
|
1746
1609
|
return (await import("@php-wasm/node-8-5")).getRedisExtensionPath();
|
|
@@ -1760,131 +1623,253 @@ async function getRedisExtensionModule(version = LatestSupportedPHPVersion6) {
|
|
|
1760
1623
|
throw new Error(`Unsupported PHP version ${version}`);
|
|
1761
1624
|
}
|
|
1762
1625
|
|
|
1763
|
-
// packages/php-wasm/node/src/lib/extensions/
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
const extensionPath = await getRedisExtensionModule(version);
|
|
1767
|
-
const extension = fs3.readFileSync(extensionPath);
|
|
1768
|
-
return {
|
|
1769
|
-
...options,
|
|
1770
|
-
ENV: {
|
|
1771
|
-
...options.ENV,
|
|
1772
|
-
PHP_INI_SCAN_DIR: "/internal/shared/extensions"
|
|
1773
|
-
},
|
|
1774
|
-
onRuntimeInitialized: (phpRuntime) => {
|
|
1775
|
-
if (options.onRuntimeInitialized) {
|
|
1776
|
-
options.onRuntimeInitialized(phpRuntime);
|
|
1777
|
-
}
|
|
1778
|
-
if (!FSHelpers3.fileExists(
|
|
1779
|
-
phpRuntime.FS,
|
|
1780
|
-
"/internal/shared/extensions"
|
|
1781
|
-
)) {
|
|
1782
|
-
phpRuntime.FS.mkdirTree("/internal/shared/extensions");
|
|
1783
|
-
}
|
|
1784
|
-
if (!FSHelpers3.fileExists(
|
|
1785
|
-
phpRuntime.FS,
|
|
1786
|
-
`/internal/shared/extensions/${extensionName}`
|
|
1787
|
-
)) {
|
|
1788
|
-
phpRuntime.FS.writeFile(
|
|
1789
|
-
`/internal/shared/extensions/${extensionName}`,
|
|
1790
|
-
new Uint8Array(extension)
|
|
1791
|
-
);
|
|
1792
|
-
}
|
|
1793
|
-
if (!FSHelpers3.fileExists(
|
|
1794
|
-
phpRuntime.FS,
|
|
1795
|
-
"/internal/shared/extensions/redis.ini"
|
|
1796
|
-
)) {
|
|
1797
|
-
phpRuntime.FS.writeFile(
|
|
1798
|
-
"/internal/shared/extensions/redis.ini",
|
|
1799
|
-
[
|
|
1800
|
-
`extension=/internal/shared/extensions/${extensionName}`
|
|
1801
|
-
].join("\n")
|
|
1802
|
-
);
|
|
1803
|
-
}
|
|
1804
|
-
}
|
|
1805
|
-
};
|
|
1806
|
-
}
|
|
1807
|
-
|
|
1808
|
-
// packages/php-wasm/node/src/lib/extensions/memcached/with-memcached.ts
|
|
1809
|
-
import { LatestSupportedPHPVersion as LatestSupportedPHPVersion9, FSHelpers as FSHelpers4 } from "@php-wasm/universal";
|
|
1810
|
-
import fs4 from "fs";
|
|
1811
|
-
|
|
1812
|
-
// packages/php-wasm/node/src/lib/extensions/memcached/get-memcached-extension-module.ts
|
|
1813
|
-
import { LatestSupportedPHPVersion as LatestSupportedPHPVersion8 } from "@php-wasm/universal";
|
|
1814
|
-
async function getMemcachedExtensionModule(version = LatestSupportedPHPVersion8) {
|
|
1626
|
+
// packages/php-wasm/node/src/lib/extensions/xdebug/get-xdebug-extension-module.ts
|
|
1627
|
+
import { LatestSupportedPHPVersion as LatestSupportedPHPVersion5 } from "@php-wasm/universal";
|
|
1628
|
+
async function getXdebugExtensionModule(version = LatestSupportedPHPVersion5) {
|
|
1815
1629
|
switch (version) {
|
|
1816
1630
|
case "8.5":
|
|
1817
|
-
return (await import("@php-wasm/node-8-5")).
|
|
1631
|
+
return (await import("@php-wasm/node-8-5")).getXdebugExtensionPath();
|
|
1818
1632
|
case "8.4":
|
|
1819
|
-
return (await import("@php-wasm/node-8-4")).
|
|
1633
|
+
return (await import("@php-wasm/node-8-4")).getXdebugExtensionPath();
|
|
1820
1634
|
case "8.3":
|
|
1821
|
-
return (await import("@php-wasm/node-8-3")).
|
|
1635
|
+
return (await import("@php-wasm/node-8-3")).getXdebugExtensionPath();
|
|
1822
1636
|
case "8.2":
|
|
1823
|
-
return (await import("@php-wasm/node-8-2")).
|
|
1637
|
+
return (await import("@php-wasm/node-8-2")).getXdebugExtensionPath();
|
|
1824
1638
|
case "8.1":
|
|
1825
|
-
return (await import("@php-wasm/node-8-1")).
|
|
1639
|
+
return (await import("@php-wasm/node-8-1")).getXdebugExtensionPath();
|
|
1826
1640
|
case "8.0":
|
|
1827
|
-
return (await import("@php-wasm/node-8-0")).
|
|
1641
|
+
return (await import("@php-wasm/node-8-0")).getXdebugExtensionPath();
|
|
1828
1642
|
case "7.4":
|
|
1829
|
-
return (await import("@php-wasm/node-7-4")).
|
|
1643
|
+
return (await import("@php-wasm/node-7-4")).getXdebugExtensionPath();
|
|
1830
1644
|
}
|
|
1831
1645
|
throw new Error(`Unsupported PHP version ${version}`);
|
|
1832
1646
|
}
|
|
1833
1647
|
|
|
1834
|
-
// packages/php-wasm/node/src/lib/extensions/
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1648
|
+
// packages/php-wasm/node/src/lib/extensions/node-extension-resources.ts
|
|
1649
|
+
import { readFile } from "fs/promises";
|
|
1650
|
+
import path from "path";
|
|
1651
|
+
import { fileURLToPath, pathToFileURL } from "url";
|
|
1652
|
+
function normalizeNodeExtensionSource(source) {
|
|
1653
|
+
if (source.format === "url") {
|
|
1654
|
+
return {
|
|
1655
|
+
...source,
|
|
1656
|
+
url: toNodeResourceUrl(source.url)
|
|
1657
|
+
};
|
|
1658
|
+
}
|
|
1659
|
+
if (source.format !== "manifest") {
|
|
1660
|
+
return source;
|
|
1661
|
+
}
|
|
1662
|
+
if ("manifest" in source) {
|
|
1663
|
+
return source.baseUrl ? {
|
|
1664
|
+
...source,
|
|
1665
|
+
baseUrl: toNodeResourceUrl(source.baseUrl)
|
|
1666
|
+
} : source;
|
|
1667
|
+
}
|
|
1839
1668
|
return {
|
|
1840
|
-
...
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
"/internal/shared/extensions/memcached.ini"
|
|
1867
|
-
)) {
|
|
1868
|
-
phpRuntime.FS.writeFile(
|
|
1869
|
-
"/internal/shared/extensions/memcached.ini",
|
|
1870
|
-
[
|
|
1871
|
-
`extension=/internal/shared/extensions/${extensionName}`
|
|
1872
|
-
].join("\n")
|
|
1873
|
-
);
|
|
1874
|
-
}
|
|
1669
|
+
...source,
|
|
1670
|
+
manifestUrl: toNodeResourceUrl(source.manifestUrl)
|
|
1671
|
+
};
|
|
1672
|
+
}
|
|
1673
|
+
async function fetchNodeExtensionResource(input) {
|
|
1674
|
+
const url = input instanceof Request ? new URL(input.url) : input instanceof URL ? input : toNodeResourceUrl(String(input));
|
|
1675
|
+
if (url.protocol === "file:") {
|
|
1676
|
+
try {
|
|
1677
|
+
return new Response(await readFile(fileURLToPath(url)));
|
|
1678
|
+
} catch (error) {
|
|
1679
|
+
return new Response(String(error), {
|
|
1680
|
+
status: 404,
|
|
1681
|
+
statusText: "Not Found"
|
|
1682
|
+
});
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
return fetch(input);
|
|
1686
|
+
}
|
|
1687
|
+
function toNodeResourceUrl(urlOrPath) {
|
|
1688
|
+
if (urlOrPath instanceof URL) {
|
|
1689
|
+
return urlOrPath;
|
|
1690
|
+
}
|
|
1691
|
+
try {
|
|
1692
|
+
const url = new URL(urlOrPath);
|
|
1693
|
+
if (url.protocol === "http:" || url.protocol === "https:" || url.protocol === "file:") {
|
|
1694
|
+
return url;
|
|
1875
1695
|
}
|
|
1696
|
+
} catch {
|
|
1697
|
+
}
|
|
1698
|
+
return pathToFileURL(path.resolve(urlOrPath));
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
// packages/php-wasm/node/src/lib/extensions/load-extensions.ts
|
|
1702
|
+
async function withPHPExtensions(version, asyncMode, options, extensions = []) {
|
|
1703
|
+
if (!extensions.length) {
|
|
1704
|
+
return options;
|
|
1705
|
+
}
|
|
1706
|
+
const resolvedExtensions = await Promise.all(
|
|
1707
|
+
extensions.map(
|
|
1708
|
+
(extension) => resolveRuntimePHPExtension(version, asyncMode, extension)
|
|
1709
|
+
)
|
|
1710
|
+
);
|
|
1711
|
+
return withResolvedPHPExtensions(options, resolvedExtensions);
|
|
1712
|
+
}
|
|
1713
|
+
async function resolveRuntimePHPExtension(version, asyncMode, extension) {
|
|
1714
|
+
if (typeof extension === "object" && "source" in extension) {
|
|
1715
|
+
return await resolvePHPExtension({
|
|
1716
|
+
...extension,
|
|
1717
|
+
source: normalizeNodeExtensionSource(extension.source),
|
|
1718
|
+
phpVersion: version,
|
|
1719
|
+
asyncMode,
|
|
1720
|
+
fetch: extension.fetch ?? fetchNodeExtensionResource
|
|
1721
|
+
});
|
|
1722
|
+
}
|
|
1723
|
+
const builtIn = typeof extension === "string" ? { name: extension } : extension;
|
|
1724
|
+
switch (builtIn.name) {
|
|
1725
|
+
case "intl": {
|
|
1726
|
+
const extensionPath = await getIntlExtensionModule(version);
|
|
1727
|
+
const soBytes = new Uint8Array(fs.readFileSync(extensionPath));
|
|
1728
|
+
const dataName = "icu.dat";
|
|
1729
|
+
const moduleDir = typeof __dirname !== "undefined" ? __dirname : import.meta.dirname;
|
|
1730
|
+
const ICUData = fs.readFileSync(
|
|
1731
|
+
resolveIntlDataPath(moduleDir, dataName)
|
|
1732
|
+
);
|
|
1733
|
+
return await resolvePHPExtension({
|
|
1734
|
+
source: {
|
|
1735
|
+
format: "so",
|
|
1736
|
+
name: "intl",
|
|
1737
|
+
bytes: soBytes
|
|
1738
|
+
},
|
|
1739
|
+
phpVersion: version,
|
|
1740
|
+
asyncMode,
|
|
1741
|
+
env: {
|
|
1742
|
+
ICU_DATA: "/internal/shared"
|
|
1743
|
+
},
|
|
1744
|
+
extraFiles: {
|
|
1745
|
+
targetPath: "/internal/shared",
|
|
1746
|
+
files: {
|
|
1747
|
+
// The Intl extension looks for the hard-coded ICU data name.
|
|
1748
|
+
"icudt74l.dat": new Uint8Array(ICUData)
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1751
|
+
});
|
|
1752
|
+
}
|
|
1753
|
+
case "redis": {
|
|
1754
|
+
const extensionPath = await getRedisExtensionModule(version);
|
|
1755
|
+
return await resolvePHPExtension({
|
|
1756
|
+
source: {
|
|
1757
|
+
format: "so",
|
|
1758
|
+
name: "redis",
|
|
1759
|
+
bytes: new Uint8Array(fs.readFileSync(extensionPath))
|
|
1760
|
+
},
|
|
1761
|
+
phpVersion: version,
|
|
1762
|
+
asyncMode
|
|
1763
|
+
});
|
|
1764
|
+
}
|
|
1765
|
+
case "memcached": {
|
|
1766
|
+
const extensionPath = await getMemcachedExtensionModule(version);
|
|
1767
|
+
return await resolvePHPExtension({
|
|
1768
|
+
source: {
|
|
1769
|
+
format: "so",
|
|
1770
|
+
name: "memcached",
|
|
1771
|
+
bytes: new Uint8Array(fs.readFileSync(extensionPath))
|
|
1772
|
+
},
|
|
1773
|
+
phpVersion: version,
|
|
1774
|
+
asyncMode
|
|
1775
|
+
});
|
|
1776
|
+
}
|
|
1777
|
+
case "xdebug": {
|
|
1778
|
+
const xdebugOptions = builtIn.options ?? {};
|
|
1779
|
+
const filePath = await getXdebugExtensionModule(version);
|
|
1780
|
+
const ideKey = xdebugOptions.ideKey || DEFAULT_IDE_KEY;
|
|
1781
|
+
return await resolvePHPExtension({
|
|
1782
|
+
source: {
|
|
1783
|
+
format: "so",
|
|
1784
|
+
name: "xdebug",
|
|
1785
|
+
bytes: new Uint8Array(fs.readFileSync(filePath))
|
|
1786
|
+
},
|
|
1787
|
+
phpVersion: version,
|
|
1788
|
+
asyncMode,
|
|
1789
|
+
loadWithIniDirective: "zend_extension",
|
|
1790
|
+
iniEntries: {
|
|
1791
|
+
"xdebug.mode": "debug,develop",
|
|
1792
|
+
"xdebug.start_with_request": "yes",
|
|
1793
|
+
"xdebug.idekey": `"${ideKey}"`,
|
|
1794
|
+
// Path mapping is only available starting from Xdebug 3.5,
|
|
1795
|
+
// which is used by PHP 8.5+. Previous versions ignore it.
|
|
1796
|
+
"xdebug.path_mapping": "yes"
|
|
1797
|
+
},
|
|
1798
|
+
extraFiles: resolveXdebugExtraFiles(version, xdebugOptions)
|
|
1799
|
+
});
|
|
1800
|
+
}
|
|
1801
|
+
default:
|
|
1802
|
+
throw new Error(
|
|
1803
|
+
`Unknown bundled PHP extension: ${String(builtIn.name)}.`
|
|
1804
|
+
);
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
function resolveIntlDataPath(moduleDir, dataName) {
|
|
1808
|
+
const candidatePaths = [
|
|
1809
|
+
// Built package layout: dist/packages/php-wasm/node/shared/icu.dat.
|
|
1810
|
+
path2.join(moduleDir, "shared", dataName),
|
|
1811
|
+
// Source/test layout: src/lib/extensions/intl/shared/icu.dat.
|
|
1812
|
+
path2.join(moduleDir, "intl", "shared", dataName)
|
|
1813
|
+
];
|
|
1814
|
+
const dataPath = candidatePaths.find(
|
|
1815
|
+
(candidate) => fs.existsSync(candidate)
|
|
1816
|
+
);
|
|
1817
|
+
if (!dataPath) {
|
|
1818
|
+
throw new Error(
|
|
1819
|
+
`Could not find ${dataName}. Checked: ${candidatePaths.join(", ")}`
|
|
1820
|
+
);
|
|
1821
|
+
}
|
|
1822
|
+
return dataPath;
|
|
1823
|
+
}
|
|
1824
|
+
function resolveXdebugExtraFiles(version, xdebugOptions) {
|
|
1825
|
+
const isPHP85orHigher = SupportedPHPVersions.indexOf(version) <= SupportedPHPVersions.indexOf("8.5");
|
|
1826
|
+
if (!isPHP85orHigher) {
|
|
1827
|
+
return void 0;
|
|
1828
|
+
}
|
|
1829
|
+
const { pathMappings, pathSkippings } = xdebugOptions;
|
|
1830
|
+
if (!pathMappings && !pathSkippings) {
|
|
1831
|
+
return void 0;
|
|
1832
|
+
}
|
|
1833
|
+
const files = {};
|
|
1834
|
+
if (pathMappings) {
|
|
1835
|
+
files["path.map"] = pathMappings.map((map) => `${map.vfsPath} = ${map.hostPath}`).join("\n");
|
|
1836
|
+
}
|
|
1837
|
+
if (pathSkippings) {
|
|
1838
|
+
files["skip.map"] = pathSkippings.map((path3) => `${path3} = SKIP`).join("\n");
|
|
1839
|
+
}
|
|
1840
|
+
return {
|
|
1841
|
+
targetPath: "/.xdebug",
|
|
1842
|
+
files
|
|
1876
1843
|
};
|
|
1877
1844
|
}
|
|
1878
1845
|
|
|
1879
1846
|
// packages/php-wasm/node/src/lib/load-runtime.ts
|
|
1880
1847
|
import { dirname, joinPaths, toPosixPath } from "@php-wasm/util";
|
|
1881
1848
|
import { platform } from "os";
|
|
1849
|
+
import { jspi } from "wasm-feature-detect";
|
|
1882
1850
|
var dangerousDefaultProcessIdAllocator = process.env.VITEST ? new ProcessIdAllocator() : void 0;
|
|
1883
1851
|
async function loadNodeRuntime(phpVersion, options = {}) {
|
|
1884
1852
|
const processId = options.emscriptenOptions?.processId ?? // !! Only assign a default process ID during test.
|
|
1885
1853
|
// Otherwise, multiple workers with duplicate process IDs
|
|
1886
1854
|
// could break file locking and lead to database corruption.
|
|
1887
1855
|
(process.env.VITEST ? dangerousDefaultProcessIdAllocator.claim() : void 0);
|
|
1856
|
+
const isLegacy = isLegacyPHPVersion(phpVersion);
|
|
1857
|
+
const phpWasmAsyncMode = await jspi() ? "jspi" : "asyncify";
|
|
1858
|
+
const requestedExtensions = [...options.extensions ?? []];
|
|
1859
|
+
if (options.withIntl && !hasBuiltInExtension(requestedExtensions, "intl")) {
|
|
1860
|
+
requestedExtensions.push("intl");
|
|
1861
|
+
}
|
|
1862
|
+
if (options.withRedis && !hasBuiltInExtension(requestedExtensions, "redis")) {
|
|
1863
|
+
requestedExtensions.push("redis");
|
|
1864
|
+
}
|
|
1865
|
+
if (options.withMemcached && !hasBuiltInExtension(requestedExtensions, "memcached")) {
|
|
1866
|
+
requestedExtensions.push("memcached");
|
|
1867
|
+
}
|
|
1868
|
+
if (options.withXdebug && !hasBuiltInExtension(requestedExtensions, "xdebug")) {
|
|
1869
|
+
requestedExtensions.push(
|
|
1870
|
+
typeof options.withXdebug === "object" ? { name: "xdebug", options: options.withXdebug } : "xdebug"
|
|
1871
|
+
);
|
|
1872
|
+
}
|
|
1888
1873
|
let emscriptenOptions = {
|
|
1889
1874
|
/**
|
|
1890
1875
|
* Emscripten default behavior is to kill the process when
|
|
@@ -1903,12 +1888,23 @@ async function loadNodeRuntime(phpVersion, options = {}) {
|
|
|
1903
1888
|
return bindUserSpace({ fileLockManager }, userSpaceContext);
|
|
1904
1889
|
},
|
|
1905
1890
|
...options.emscriptenOptions || {},
|
|
1891
|
+
phpWasmAsyncMode,
|
|
1906
1892
|
processId,
|
|
1893
|
+
// For legacy PHP: pre-create php.ini via a preRun step. See
|
|
1894
|
+
// createLegacyPhpIniPreRunStep for why this must run before
|
|
1895
|
+
// the PHP SAPI starts. Merge with any caller-provided preRun
|
|
1896
|
+
// hooks (the spread above may have set them).
|
|
1897
|
+
...isLegacy ? {
|
|
1898
|
+
preRun: [
|
|
1899
|
+
createLegacyPhpIniPreRunStep(),
|
|
1900
|
+
...options.emscriptenOptions?.preRun ?? []
|
|
1901
|
+
]
|
|
1902
|
+
} : {},
|
|
1907
1903
|
onRuntimeInitialized: (phpRuntime) => {
|
|
1908
1904
|
if (options?.followSymlinks === true) {
|
|
1909
1905
|
phpRuntime.FS.filesystems.NODEFS.node_ops.readlink = (node) => {
|
|
1910
1906
|
const absoluteSourcePath = phpRuntime.FS.filesystems.NODEFS.tryFSOperation(
|
|
1911
|
-
() =>
|
|
1907
|
+
() => fs2.realpathSync(
|
|
1912
1908
|
phpRuntime.FS.filesystems.NODEFS.realPath(node)
|
|
1913
1909
|
)
|
|
1914
1910
|
);
|
|
@@ -1917,9 +1913,9 @@ async function loadNodeRuntime(phpVersion, options = {}) {
|
|
|
1917
1913
|
`/internal/symlinks`,
|
|
1918
1914
|
normalizedPath
|
|
1919
1915
|
);
|
|
1920
|
-
if (
|
|
1921
|
-
const sourceStat =
|
|
1922
|
-
if (!
|
|
1916
|
+
if (fs2.existsSync(absoluteSourcePath)) {
|
|
1917
|
+
const sourceStat = fs2.statSync(absoluteSourcePath);
|
|
1918
|
+
if (!FSHelpers.fileExists(
|
|
1923
1919
|
phpRuntime.FS,
|
|
1924
1920
|
symlinkMountPath
|
|
1925
1921
|
)) {
|
|
@@ -1958,51 +1954,58 @@ async function loadNodeRuntime(phpVersion, options = {}) {
|
|
|
1958
1954
|
phpRuntime.FS.root.mount.opts.root = ".";
|
|
1959
1955
|
}
|
|
1960
1956
|
};
|
|
1961
|
-
if (
|
|
1962
|
-
|
|
1963
|
-
phpVersion
|
|
1964
|
-
emscriptenOptions,
|
|
1965
|
-
typeof options.withXdebug === "object" ? options.withXdebug : {}
|
|
1957
|
+
if (isLegacy && requestedExtensions.length) {
|
|
1958
|
+
throw new Error(
|
|
1959
|
+
`Extensions (xdebug, intl, redis, memcached) are not available for legacy PHP ${phpVersion}.`
|
|
1966
1960
|
);
|
|
1967
1961
|
}
|
|
1968
|
-
if (
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1962
|
+
if (!isLegacy) {
|
|
1963
|
+
const modernVersion = phpVersion;
|
|
1964
|
+
emscriptenOptions = await withPHPExtensions(
|
|
1965
|
+
modernVersion,
|
|
1966
|
+
phpWasmAsyncMode,
|
|
1967
|
+
emscriptenOptions,
|
|
1968
|
+
requestedExtensions
|
|
1969
|
+
);
|
|
1976
1970
|
}
|
|
1977
1971
|
emscriptenOptions = await withNetworking(emscriptenOptions);
|
|
1978
1972
|
const phpLoaderModule = await getPHPLoaderModule(phpVersion);
|
|
1979
1973
|
const runtimeId = await loadPHPRuntime(phpLoaderModule, emscriptenOptions);
|
|
1980
1974
|
return runtimeId;
|
|
1981
1975
|
}
|
|
1976
|
+
function hasBuiltInExtension(extensions, name) {
|
|
1977
|
+
return extensions.some((extension) => {
|
|
1978
|
+
if (typeof extension === "string") {
|
|
1979
|
+
return extension === name;
|
|
1980
|
+
}
|
|
1981
|
+
return !("source" in extension) && extension.name === name;
|
|
1982
|
+
});
|
|
1983
|
+
}
|
|
1982
1984
|
|
|
1983
1985
|
// packages/php-wasm/node/src/lib/use-host-filesystem.ts
|
|
1984
|
-
import { lstatSync
|
|
1986
|
+
import { lstatSync, readdirSync } from "node:fs";
|
|
1985
1987
|
|
|
1986
1988
|
// packages/php-wasm/node/src/lib/node-fs-mount.ts
|
|
1987
1989
|
import {
|
|
1988
|
-
FSHelpers as
|
|
1990
|
+
FSHelpers as FSHelpers2
|
|
1989
1991
|
} from "@php-wasm/universal";
|
|
1990
1992
|
import { isParentOf } from "@php-wasm/util";
|
|
1991
|
-
import {
|
|
1993
|
+
import { realpathSync, statSync } from "fs";
|
|
1992
1994
|
import { dirname as dirname2 } from "path";
|
|
1993
1995
|
function createNodeFsMountHandler(localPath) {
|
|
1994
1996
|
return function(php, FS, vfsMountPoint) {
|
|
1995
1997
|
let removeVfsNode = false;
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1998
|
+
const mountRoot = realpathSync(localPath);
|
|
1999
|
+
if (!FSHelpers2.fileExists(FS, vfsMountPoint)) {
|
|
2000
|
+
const stat = statSync(mountRoot);
|
|
2001
|
+
if (stat.isFile()) {
|
|
1999
2002
|
FS.mkdirTree(dirname2(vfsMountPoint));
|
|
2000
2003
|
FS.writeFile(vfsMountPoint, "");
|
|
2001
|
-
} else if (
|
|
2004
|
+
} else if (stat.isDirectory()) {
|
|
2002
2005
|
FS.mkdirTree(vfsMountPoint);
|
|
2003
2006
|
} else {
|
|
2004
2007
|
throw new Error(
|
|
2005
|
-
"Unsupported file type. PHP-wasm supports only symlinks that
|
|
2008
|
+
"Unsupported file type. PHP-wasm supports mounting only files and directories, including symlinks that resolve to files or directories."
|
|
2006
2009
|
);
|
|
2007
2010
|
}
|
|
2008
2011
|
removeVfsNode = true;
|
|
@@ -2019,7 +2022,7 @@ function createNodeFsMountHandler(localPath) {
|
|
|
2019
2022
|
}
|
|
2020
2023
|
throw e;
|
|
2021
2024
|
}
|
|
2022
|
-
FS.mount(FS.filesystems["NODEFS"], { root:
|
|
2025
|
+
FS.mount(FS.filesystems["NODEFS"], { root: mountRoot }, vfsMountPoint);
|
|
2023
2026
|
return () => {
|
|
2024
2027
|
FS.unmount(vfsMountPoint);
|
|
2025
2028
|
if (removeVfsNode) {
|
|
@@ -2055,20 +2058,20 @@ function useHostFilesystem(php) {
|
|
|
2055
2058
|
}
|
|
2056
2059
|
php.chdir(process.cwd());
|
|
2057
2060
|
}
|
|
2058
|
-
function statPathFollowSymlinks(
|
|
2059
|
-
let stat =
|
|
2061
|
+
function statPathFollowSymlinks(path3) {
|
|
2062
|
+
let stat = lstatSync(path3);
|
|
2060
2063
|
if (stat.isSymbolicLink()) {
|
|
2061
|
-
const
|
|
2062
|
-
let target =
|
|
2064
|
+
const fs3 = __require("fs");
|
|
2065
|
+
let target = path3;
|
|
2063
2066
|
const seen = /* @__PURE__ */ new Set();
|
|
2064
2067
|
while (true) {
|
|
2065
2068
|
if (seen.has(target)) {
|
|
2066
|
-
throw new Error(`Symlink loop detected: ${
|
|
2069
|
+
throw new Error(`Symlink loop detected: ${path3}`);
|
|
2067
2070
|
}
|
|
2068
2071
|
seen.add(target);
|
|
2069
|
-
const linkStat =
|
|
2072
|
+
const linkStat = lstatSync(target);
|
|
2070
2073
|
if (linkStat.isSymbolicLink()) {
|
|
2071
|
-
target =
|
|
2074
|
+
target = fs3.realpathSync(target);
|
|
2072
2075
|
continue;
|
|
2073
2076
|
}
|
|
2074
2077
|
stat = linkStat;
|
|
@@ -2085,6 +2088,5 @@ export {
|
|
|
2085
2088
|
getPHPLoaderModule,
|
|
2086
2089
|
loadNodeRuntime,
|
|
2087
2090
|
useHostFilesystem,
|
|
2088
|
-
withNetworking
|
|
2089
|
-
withXdebug
|
|
2091
|
+
withNetworking
|
|
2090
2092
|
};
|