@php-wasm/node 3.1.21 → 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 +322 -348
- package/index.js +313 -343
- package/lib/extensions/load-extensions.d.ts +59 -0
- package/lib/extensions/node-extension-resources.d.ts +20 -0
- package/lib/index.d.ts +1 -1
- package/lib/load-runtime.d.ts +21 -1
- package/package.json +19 -19
- 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
|
@@ -391,7 +391,7 @@ async function withNetworking(phpModuleArgs = {}) {
|
|
|
391
391
|
// packages/php-wasm/node/src/lib/load-runtime.ts
|
|
392
392
|
import {
|
|
393
393
|
loadPHPRuntime,
|
|
394
|
-
FSHelpers
|
|
394
|
+
FSHelpers,
|
|
395
395
|
FileLockManagerComposite,
|
|
396
396
|
createLegacyPhpIniPreRunStep,
|
|
397
397
|
isLegacyPHPVersion,
|
|
@@ -466,8 +466,8 @@ function bindUserSpace({ fileLockManager }, {
|
|
|
466
466
|
[F_WRLCK]: "exclusive",
|
|
467
467
|
[F_UNLCK]: "unlocked"
|
|
468
468
|
},
|
|
469
|
-
is_path_to_shared_fs(
|
|
470
|
-
const { node } = FS.lookupPath(
|
|
469
|
+
is_path_to_shared_fs(path3) {
|
|
470
|
+
const { node } = FS.lookupPath(path3, { noent_okay: true });
|
|
471
471
|
if (!node) {
|
|
472
472
|
return false;
|
|
473
473
|
}
|
|
@@ -1098,7 +1098,7 @@ function bindUserSpace({ fileLockManager }, {
|
|
|
1098
1098
|
}
|
|
1099
1099
|
|
|
1100
1100
|
// packages/php-wasm/node/src/lib/load-runtime.ts
|
|
1101
|
-
import
|
|
1101
|
+
import fs2 from "fs";
|
|
1102
1102
|
|
|
1103
1103
|
// packages/php-wasm/node/src/lib/file-lock-manager-for-posix.ts
|
|
1104
1104
|
import { MAX_ADDRESSABLE_FILE_OFFSET } from "@php-wasm/universal";
|
|
@@ -1116,7 +1116,7 @@ var FileLockManagerForPosix = class {
|
|
|
1116
1116
|
this.wholeFileLockMap = /* @__PURE__ */ new Map();
|
|
1117
1117
|
this.rangeLockedFds = /* @__PURE__ */ new Map();
|
|
1118
1118
|
}
|
|
1119
|
-
lockWholeFile(
|
|
1119
|
+
lockWholeFile(path3, op) {
|
|
1120
1120
|
const opType = op.type === "unlock" ? "un" : op.waitForLock ? op.type === "exclusive" ? "ex" : "sh" : op.type === "exclusive" ? "exnb" : "shnb";
|
|
1121
1121
|
try {
|
|
1122
1122
|
flockSync(op.fd, opType);
|
|
@@ -1128,7 +1128,7 @@ var FileLockManagerForPosix = class {
|
|
|
1128
1128
|
}
|
|
1129
1129
|
this.wholeFileLockMap.get(op.pid).set(op.fd, {
|
|
1130
1130
|
...op,
|
|
1131
|
-
path:
|
|
1131
|
+
path: path3
|
|
1132
1132
|
});
|
|
1133
1133
|
}
|
|
1134
1134
|
return true;
|
|
@@ -1139,7 +1139,7 @@ var FileLockManagerForPosix = class {
|
|
|
1139
1139
|
return false;
|
|
1140
1140
|
}
|
|
1141
1141
|
}
|
|
1142
|
-
lockFileByteRange(
|
|
1142
|
+
lockFileByteRange(path3, op, waitForLock) {
|
|
1143
1143
|
if (op.start === op.end) {
|
|
1144
1144
|
op = {
|
|
1145
1145
|
...op,
|
|
@@ -1160,10 +1160,10 @@ var FileLockManagerForPosix = class {
|
|
|
1160
1160
|
this.rangeLockedFds.set(op.pid, /* @__PURE__ */ new Map());
|
|
1161
1161
|
}
|
|
1162
1162
|
const pidMap = this.rangeLockedFds.get(op.pid);
|
|
1163
|
-
if (!pidMap.has(
|
|
1164
|
-
pidMap.set(
|
|
1163
|
+
if (!pidMap.has(path3)) {
|
|
1164
|
+
pidMap.set(path3, /* @__PURE__ */ new Set());
|
|
1165
1165
|
}
|
|
1166
|
-
pidMap.get(
|
|
1166
|
+
pidMap.get(path3).add(op.fd);
|
|
1167
1167
|
return true;
|
|
1168
1168
|
} catch (e) {
|
|
1169
1169
|
if (!isLockDenialError(e)) {
|
|
@@ -1172,13 +1172,13 @@ var FileLockManagerForPosix = class {
|
|
|
1172
1172
|
return false;
|
|
1173
1173
|
}
|
|
1174
1174
|
}
|
|
1175
|
-
findFirstConflictingByteRangeLock(
|
|
1175
|
+
findFirstConflictingByteRangeLock(path3, op) {
|
|
1176
1176
|
if (op.type === "unlocked") {
|
|
1177
1177
|
return void 0;
|
|
1178
1178
|
}
|
|
1179
|
-
const obtainedLock = this.lockFileByteRange(
|
|
1179
|
+
const obtainedLock = this.lockFileByteRange(path3, op, false);
|
|
1180
1180
|
if (obtainedLock) {
|
|
1181
|
-
this.lockFileByteRange(
|
|
1181
|
+
this.lockFileByteRange(path3, { ...op, type: "unlocked" }, true);
|
|
1182
1182
|
return void 0;
|
|
1183
1183
|
}
|
|
1184
1184
|
return {
|
|
@@ -1206,11 +1206,11 @@ var FileLockManagerForPosix = class {
|
|
|
1206
1206
|
}
|
|
1207
1207
|
this.wholeFileLockMap.delete(targetPid);
|
|
1208
1208
|
}
|
|
1209
|
-
for (const [
|
|
1209
|
+
for (const [path3, fdSet] of this.rangeLockedFds.get(targetPid) ?? []) {
|
|
1210
1210
|
for (const fd of fdSet) {
|
|
1211
1211
|
try {
|
|
1212
1212
|
this.lockFileByteRange(
|
|
1213
|
-
|
|
1213
|
+
path3,
|
|
1214
1214
|
{
|
|
1215
1215
|
pid: targetPid,
|
|
1216
1216
|
fd,
|
|
@@ -1222,7 +1222,7 @@ var FileLockManagerForPosix = class {
|
|
|
1222
1222
|
);
|
|
1223
1223
|
} catch (e) {
|
|
1224
1224
|
logger2.error(
|
|
1225
|
-
`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}`,
|
|
1226
1226
|
e
|
|
1227
1227
|
);
|
|
1228
1228
|
}
|
|
@@ -1286,7 +1286,7 @@ var FileLockManagerForWindows = class {
|
|
|
1286
1286
|
this.wholeFileLockMap = /* @__PURE__ */ new Map();
|
|
1287
1287
|
this.rangeLockedFds = /* @__PURE__ */ new Map();
|
|
1288
1288
|
}
|
|
1289
|
-
lockWholeFile(
|
|
1289
|
+
lockWholeFile(path3, op) {
|
|
1290
1290
|
const start = 0n;
|
|
1291
1291
|
const end = 2n ** 64n - 1n;
|
|
1292
1292
|
if (op.type === "unlock") {
|
|
@@ -1298,7 +1298,7 @@ var FileLockManagerForWindows = class {
|
|
|
1298
1298
|
}
|
|
1299
1299
|
} else {
|
|
1300
1300
|
logger3.warn(
|
|
1301
|
-
`lockWholeFile: unlock failed for pid=${op.pid} fd=${op.fd} path=${
|
|
1301
|
+
`lockWholeFile: unlock failed for pid=${op.pid} fd=${op.fd} path=${path3}`
|
|
1302
1302
|
);
|
|
1303
1303
|
}
|
|
1304
1304
|
return success2;
|
|
@@ -1366,22 +1366,22 @@ var FileLockManagerForWindows = class {
|
|
|
1366
1366
|
}
|
|
1367
1367
|
this.wholeFileLockMap.get(op.pid).set(op.fd, {
|
|
1368
1368
|
...op,
|
|
1369
|
-
path:
|
|
1369
|
+
path: path3
|
|
1370
1370
|
});
|
|
1371
1371
|
}
|
|
1372
1372
|
return success;
|
|
1373
1373
|
}
|
|
1374
|
-
lockFileByteRange(
|
|
1374
|
+
lockFileByteRange(path3, op, waitForLock) {
|
|
1375
1375
|
if (op.start === op.end) {
|
|
1376
1376
|
op = {
|
|
1377
1377
|
...op,
|
|
1378
1378
|
end: MAX_ADDRESSABLE_FILE_OFFSET2
|
|
1379
1379
|
};
|
|
1380
1380
|
}
|
|
1381
|
-
if (!this.rangeLockedFds.has(
|
|
1382
|
-
this.rangeLockedFds.set(
|
|
1381
|
+
if (!this.rangeLockedFds.has(path3)) {
|
|
1382
|
+
this.rangeLockedFds.set(path3, new FileLockIntervalTree());
|
|
1383
1383
|
}
|
|
1384
|
-
const lockedRangeTree = this.rangeLockedFds.get(
|
|
1384
|
+
const lockedRangeTree = this.rangeLockedFds.get(path3);
|
|
1385
1385
|
const overlappingLocks = lockedRangeTree.findOverlapping(op);
|
|
1386
1386
|
let preexistingLock;
|
|
1387
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,
|
|
@@ -1466,12 +1466,12 @@ var FileLockManagerForWindows = class {
|
|
|
1466
1466
|
return true;
|
|
1467
1467
|
}
|
|
1468
1468
|
}
|
|
1469
|
-
findFirstConflictingByteRangeLock(
|
|
1469
|
+
findFirstConflictingByteRangeLock(path3, op) {
|
|
1470
1470
|
if (op.type === "unlocked") {
|
|
1471
1471
|
return void 0;
|
|
1472
1472
|
}
|
|
1473
|
-
const obtainedLock = !!this.lockFileByteRange(
|
|
1474
|
-
this.lockFileByteRange(
|
|
1473
|
+
const obtainedLock = !!this.lockFileByteRange(path3, op, false);
|
|
1474
|
+
this.lockFileByteRange(path3, { ...op, type: "unlocked" }, false);
|
|
1475
1475
|
if (obtainedLock) {
|
|
1476
1476
|
return void 0;
|
|
1477
1477
|
}
|
|
@@ -1500,18 +1500,18 @@ var FileLockManagerForWindows = class {
|
|
|
1500
1500
|
}
|
|
1501
1501
|
this.wholeFileLockMap.delete(targetPid);
|
|
1502
1502
|
}
|
|
1503
|
-
for (const [
|
|
1503
|
+
for (const [path3, lockedRangeTree] of this.rangeLockedFds.entries()) {
|
|
1504
1504
|
const rangesLockedByTargetPid = lockedRangeTree.findLocksForProcess(targetPid);
|
|
1505
1505
|
for (const op of rangesLockedByTargetPid) {
|
|
1506
1506
|
try {
|
|
1507
1507
|
this.lockFileByteRange(
|
|
1508
|
-
|
|
1508
|
+
path3,
|
|
1509
1509
|
{ ...op, type: "unlocked" },
|
|
1510
1510
|
false
|
|
1511
1511
|
);
|
|
1512
1512
|
} catch (e) {
|
|
1513
1513
|
logger3.error(
|
|
1514
|
-
`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}`,
|
|
1515
1515
|
e
|
|
1516
1516
|
);
|
|
1517
1517
|
}
|
|
@@ -1547,204 +1547,63 @@ var FileLockManagerForWindows = class {
|
|
|
1547
1547
|
}
|
|
1548
1548
|
};
|
|
1549
1549
|
|
|
1550
|
-
// packages/php-wasm/node/src/lib/extensions/
|
|
1550
|
+
// packages/php-wasm/node/src/lib/extensions/load-extensions.ts
|
|
1551
1551
|
import { DEFAULT_IDE_KEY } from "@php-wasm/cli-util";
|
|
1552
1552
|
import {
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
SupportedPHPVersions
|
|
1556
|
-
SupportedPHPVersionsList
|
|
1553
|
+
withResolvedPHPExtensions,
|
|
1554
|
+
resolvePHPExtension,
|
|
1555
|
+
SupportedPHPVersions
|
|
1557
1556
|
} from "@php-wasm/universal";
|
|
1558
1557
|
import fs from "fs";
|
|
1558
|
+
import path2 from "path";
|
|
1559
1559
|
|
|
1560
|
-
// packages/php-wasm/node/src/lib/extensions/
|
|
1560
|
+
// packages/php-wasm/node/src/lib/extensions/intl/get-intl-extension-module.ts
|
|
1561
1561
|
import { LatestSupportedPHPVersion as LatestSupportedPHPVersion2 } from "@php-wasm/universal";
|
|
1562
|
-
async function
|
|
1562
|
+
async function getIntlExtensionModule(version = LatestSupportedPHPVersion2) {
|
|
1563
1563
|
switch (version) {
|
|
1564
1564
|
case "8.5":
|
|
1565
|
-
return (await import("@php-wasm/node-8-5")).
|
|
1565
|
+
return (await import("@php-wasm/node-8-5")).getIntlExtensionPath();
|
|
1566
1566
|
case "8.4":
|
|
1567
|
-
return (await import("@php-wasm/node-8-4")).
|
|
1567
|
+
return (await import("@php-wasm/node-8-4")).getIntlExtensionPath();
|
|
1568
1568
|
case "8.3":
|
|
1569
|
-
return (await import("@php-wasm/node-8-3")).
|
|
1569
|
+
return (await import("@php-wasm/node-8-3")).getIntlExtensionPath();
|
|
1570
1570
|
case "8.2":
|
|
1571
|
-
return (await import("@php-wasm/node-8-2")).
|
|
1571
|
+
return (await import("@php-wasm/node-8-2")).getIntlExtensionPath();
|
|
1572
1572
|
case "8.1":
|
|
1573
|
-
return (await import("@php-wasm/node-8-1")).
|
|
1573
|
+
return (await import("@php-wasm/node-8-1")).getIntlExtensionPath();
|
|
1574
1574
|
case "8.0":
|
|
1575
|
-
return (await import("@php-wasm/node-8-0")).
|
|
1575
|
+
return (await import("@php-wasm/node-8-0")).getIntlExtensionPath();
|
|
1576
1576
|
case "7.4":
|
|
1577
|
-
return (await import("@php-wasm/node-7-4")).
|
|
1577
|
+
return (await import("@php-wasm/node-7-4")).getIntlExtensionPath();
|
|
1578
1578
|
}
|
|
1579
1579
|
throw new Error(`Unsupported PHP version ${version}`);
|
|
1580
1580
|
}
|
|
1581
1581
|
|
|
1582
|
-
// packages/php-wasm/node/src/lib/extensions/
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
const filePath = await getXdebugExtensionModule(version);
|
|
1586
|
-
const extension = fs.readFileSync(filePath);
|
|
1587
|
-
return {
|
|
1588
|
-
...options,
|
|
1589
|
-
ENV: {
|
|
1590
|
-
...options.ENV,
|
|
1591
|
-
PHP_INI_SCAN_DIR: "/internal/shared/extensions"
|
|
1592
|
-
},
|
|
1593
|
-
onRuntimeInitialized: (phpRuntime) => {
|
|
1594
|
-
if (options.onRuntimeInitialized) {
|
|
1595
|
-
options.onRuntimeInitialized(phpRuntime);
|
|
1596
|
-
}
|
|
1597
|
-
if (!FSHelpers.fileExists(
|
|
1598
|
-
phpRuntime.FS,
|
|
1599
|
-
"/internal/shared/extensions"
|
|
1600
|
-
)) {
|
|
1601
|
-
phpRuntime.FS.mkdirTree("/internal/shared/extensions");
|
|
1602
|
-
}
|
|
1603
|
-
if (!FSHelpers.fileExists(
|
|
1604
|
-
phpRuntime.FS,
|
|
1605
|
-
`/internal/shared/extensions/${fileName}`
|
|
1606
|
-
)) {
|
|
1607
|
-
phpRuntime.FS.writeFile(
|
|
1608
|
-
`/internal/shared/extensions/${fileName}`,
|
|
1609
|
-
new Uint8Array(extension)
|
|
1610
|
-
);
|
|
1611
|
-
}
|
|
1612
|
-
if (!FSHelpers.fileExists(
|
|
1613
|
-
phpRuntime.FS,
|
|
1614
|
-
"/internal/shared/extensions/xdebug.ini"
|
|
1615
|
-
)) {
|
|
1616
|
-
const ideKey = xdebugOptions.ideKey || DEFAULT_IDE_KEY;
|
|
1617
|
-
phpRuntime.FS.writeFile(
|
|
1618
|
-
"/internal/shared/extensions/xdebug.ini",
|
|
1619
|
-
[
|
|
1620
|
-
"zend_extension=/internal/shared/extensions/xdebug.so",
|
|
1621
|
-
"xdebug.mode=debug,develop",
|
|
1622
|
-
"xdebug.start_with_request=yes",
|
|
1623
|
-
`xdebug.idekey="${ideKey}"`,
|
|
1624
|
-
// Path mapping is only available starting
|
|
1625
|
-
// from Xdebug 3.5, which is used by PHP 8.5+
|
|
1626
|
-
// Previous versions will ignore this entry.
|
|
1627
|
-
"xdebug.path_mapping=yes"
|
|
1628
|
-
].join("\n")
|
|
1629
|
-
);
|
|
1630
|
-
}
|
|
1631
|
-
const isPHP85orHigher = SupportedPHPVersionsList.indexOf(version) <= SupportedPHPVersions.indexOf("8.5");
|
|
1632
|
-
if (isPHP85orHigher) {
|
|
1633
|
-
const { pathMappings, pathSkippings } = xdebugOptions;
|
|
1634
|
-
if (!pathMappings && !pathSkippings)
|
|
1635
|
-
return;
|
|
1636
|
-
phpRuntime.FS.mkdir("/.xdebug");
|
|
1637
|
-
if (pathMappings) {
|
|
1638
|
-
phpRuntime.FS.writeFile(
|
|
1639
|
-
"/.xdebug/path.map",
|
|
1640
|
-
pathMappings.map((map) => `${map.vfsPath} = ${map.hostPath}`).join("\n")
|
|
1641
|
-
);
|
|
1642
|
-
}
|
|
1643
|
-
if (pathSkippings) {
|
|
1644
|
-
phpRuntime.FS.writeFile(
|
|
1645
|
-
"/.xdebug/skip.map",
|
|
1646
|
-
pathSkippings.map((path2) => `${path2} = SKIP`).join("\n")
|
|
1647
|
-
);
|
|
1648
|
-
}
|
|
1649
|
-
}
|
|
1650
|
-
}
|
|
1651
|
-
};
|
|
1652
|
-
}
|
|
1653
|
-
|
|
1654
|
-
// packages/php-wasm/node/src/lib/extensions/intl/with-intl.ts
|
|
1655
|
-
import { LatestSupportedPHPVersion as LatestSupportedPHPVersion5, FSHelpers as FSHelpers2 } from "@php-wasm/universal";
|
|
1656
|
-
import fs2 from "fs";
|
|
1657
|
-
import path from "path";
|
|
1658
|
-
|
|
1659
|
-
// packages/php-wasm/node/src/lib/extensions/intl/get-intl-extension-module.ts
|
|
1660
|
-
import { LatestSupportedPHPVersion as LatestSupportedPHPVersion4 } from "@php-wasm/universal";
|
|
1661
|
-
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) {
|
|
1662
1585
|
switch (version) {
|
|
1663
1586
|
case "8.5":
|
|
1664
|
-
return (await import("@php-wasm/node-8-5")).
|
|
1587
|
+
return (await import("@php-wasm/node-8-5")).getMemcachedExtensionPath();
|
|
1665
1588
|
case "8.4":
|
|
1666
|
-
return (await import("@php-wasm/node-8-4")).
|
|
1589
|
+
return (await import("@php-wasm/node-8-4")).getMemcachedExtensionPath();
|
|
1667
1590
|
case "8.3":
|
|
1668
|
-
return (await import("@php-wasm/node-8-3")).
|
|
1591
|
+
return (await import("@php-wasm/node-8-3")).getMemcachedExtensionPath();
|
|
1669
1592
|
case "8.2":
|
|
1670
|
-
return (await import("@php-wasm/node-8-2")).
|
|
1593
|
+
return (await import("@php-wasm/node-8-2")).getMemcachedExtensionPath();
|
|
1671
1594
|
case "8.1":
|
|
1672
|
-
return (await import("@php-wasm/node-8-1")).
|
|
1595
|
+
return (await import("@php-wasm/node-8-1")).getMemcachedExtensionPath();
|
|
1673
1596
|
case "8.0":
|
|
1674
|
-
return (await import("@php-wasm/node-8-0")).
|
|
1597
|
+
return (await import("@php-wasm/node-8-0")).getMemcachedExtensionPath();
|
|
1675
1598
|
case "7.4":
|
|
1676
|
-
return (await import("@php-wasm/node-7-4")).
|
|
1599
|
+
return (await import("@php-wasm/node-7-4")).getMemcachedExtensionPath();
|
|
1677
1600
|
}
|
|
1678
1601
|
throw new Error(`Unsupported PHP version ${version}`);
|
|
1679
1602
|
}
|
|
1680
1603
|
|
|
1681
|
-
// packages/php-wasm/node/src/lib/extensions/intl/with-intl.ts
|
|
1682
|
-
async function withIntl(version = LatestSupportedPHPVersion5, options) {
|
|
1683
|
-
const extensionName = "intl.so";
|
|
1684
|
-
const extensionPath = await getIntlExtensionModule(version);
|
|
1685
|
-
const extension = fs2.readFileSync(extensionPath);
|
|
1686
|
-
const dataName = "icu.dat";
|
|
1687
|
-
const moduleDir = typeof __dirname !== "undefined" ? __dirname : import.meta.dirname;
|
|
1688
|
-
const dataPath = path.join(moduleDir, "shared", dataName);
|
|
1689
|
-
const ICUData = fs2.readFileSync(dataPath);
|
|
1690
|
-
return {
|
|
1691
|
-
...options,
|
|
1692
|
-
ENV: {
|
|
1693
|
-
...options.ENV,
|
|
1694
|
-
PHP_INI_SCAN_DIR: "/internal/shared/extensions",
|
|
1695
|
-
ICU_DATA: "/internal/shared"
|
|
1696
|
-
},
|
|
1697
|
-
onRuntimeInitialized: (phpRuntime) => {
|
|
1698
|
-
if (options.onRuntimeInitialized) {
|
|
1699
|
-
options.onRuntimeInitialized(phpRuntime);
|
|
1700
|
-
}
|
|
1701
|
-
if (!FSHelpers2.fileExists(
|
|
1702
|
-
phpRuntime.FS,
|
|
1703
|
-
"/internal/shared/extensions"
|
|
1704
|
-
)) {
|
|
1705
|
-
phpRuntime.FS.mkdirTree("/internal/shared/extensions");
|
|
1706
|
-
}
|
|
1707
|
-
if (!FSHelpers2.fileExists(
|
|
1708
|
-
phpRuntime.FS,
|
|
1709
|
-
`/internal/shared/extensions/${extensionName}`
|
|
1710
|
-
)) {
|
|
1711
|
-
phpRuntime.FS.writeFile(
|
|
1712
|
-
`/internal/shared/extensions/${extensionName}`,
|
|
1713
|
-
new Uint8Array(extension)
|
|
1714
|
-
);
|
|
1715
|
-
}
|
|
1716
|
-
if (!FSHelpers2.fileExists(
|
|
1717
|
-
phpRuntime.FS,
|
|
1718
|
-
"/internal/shared/extensions/intl.ini"
|
|
1719
|
-
)) {
|
|
1720
|
-
phpRuntime.FS.writeFile(
|
|
1721
|
-
"/internal/shared/extensions/intl.ini",
|
|
1722
|
-
[
|
|
1723
|
-
`extension=/internal/shared/extensions/${extensionName}`
|
|
1724
|
-
].join("\n")
|
|
1725
|
-
);
|
|
1726
|
-
}
|
|
1727
|
-
if (!FSHelpers2.fileExists(
|
|
1728
|
-
phpRuntime.FS,
|
|
1729
|
-
`${phpRuntime.ENV.ICU_DATA}/${dataName}`
|
|
1730
|
-
)) {
|
|
1731
|
-
phpRuntime.FS.mkdirTree(phpRuntime.ENV.ICU_DATA);
|
|
1732
|
-
phpRuntime.FS.writeFile(
|
|
1733
|
-
`${phpRuntime.ENV.ICU_DATA}/icudt74l.dat`,
|
|
1734
|
-
new Uint8Array(ICUData)
|
|
1735
|
-
);
|
|
1736
|
-
}
|
|
1737
|
-
}
|
|
1738
|
-
};
|
|
1739
|
-
}
|
|
1740
|
-
|
|
1741
|
-
// packages/php-wasm/node/src/lib/extensions/redis/with-redis.ts
|
|
1742
|
-
import { LatestSupportedPHPVersion as LatestSupportedPHPVersion7, FSHelpers as FSHelpers3 } from "@php-wasm/universal";
|
|
1743
|
-
import fs3 from "fs";
|
|
1744
|
-
|
|
1745
1604
|
// packages/php-wasm/node/src/lib/extensions/redis/get-redis-extension-module.ts
|
|
1746
|
-
import { LatestSupportedPHPVersion as
|
|
1747
|
-
async function getRedisExtensionModule(version =
|
|
1605
|
+
import { LatestSupportedPHPVersion as LatestSupportedPHPVersion4 } from "@php-wasm/universal";
|
|
1606
|
+
async function getRedisExtensionModule(version = LatestSupportedPHPVersion4) {
|
|
1748
1607
|
switch (version) {
|
|
1749
1608
|
case "8.5":
|
|
1750
1609
|
return (await import("@php-wasm/node-8-5")).getRedisExtensionPath();
|
|
@@ -1764,125 +1623,230 @@ async function getRedisExtensionModule(version = LatestSupportedPHPVersion6) {
|
|
|
1764
1623
|
throw new Error(`Unsupported PHP version ${version}`);
|
|
1765
1624
|
}
|
|
1766
1625
|
|
|
1767
|
-
// packages/php-wasm/node/src/lib/extensions/
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
const extensionPath = await getRedisExtensionModule(version);
|
|
1771
|
-
const extension = fs3.readFileSync(extensionPath);
|
|
1772
|
-
return {
|
|
1773
|
-
...options,
|
|
1774
|
-
ENV: {
|
|
1775
|
-
...options.ENV,
|
|
1776
|
-
PHP_INI_SCAN_DIR: "/internal/shared/extensions"
|
|
1777
|
-
},
|
|
1778
|
-
onRuntimeInitialized: (phpRuntime) => {
|
|
1779
|
-
if (options.onRuntimeInitialized) {
|
|
1780
|
-
options.onRuntimeInitialized(phpRuntime);
|
|
1781
|
-
}
|
|
1782
|
-
if (!FSHelpers3.fileExists(
|
|
1783
|
-
phpRuntime.FS,
|
|
1784
|
-
"/internal/shared/extensions"
|
|
1785
|
-
)) {
|
|
1786
|
-
phpRuntime.FS.mkdirTree("/internal/shared/extensions");
|
|
1787
|
-
}
|
|
1788
|
-
if (!FSHelpers3.fileExists(
|
|
1789
|
-
phpRuntime.FS,
|
|
1790
|
-
`/internal/shared/extensions/${extensionName}`
|
|
1791
|
-
)) {
|
|
1792
|
-
phpRuntime.FS.writeFile(
|
|
1793
|
-
`/internal/shared/extensions/${extensionName}`,
|
|
1794
|
-
new Uint8Array(extension)
|
|
1795
|
-
);
|
|
1796
|
-
}
|
|
1797
|
-
if (!FSHelpers3.fileExists(
|
|
1798
|
-
phpRuntime.FS,
|
|
1799
|
-
"/internal/shared/extensions/redis.ini"
|
|
1800
|
-
)) {
|
|
1801
|
-
phpRuntime.FS.writeFile(
|
|
1802
|
-
"/internal/shared/extensions/redis.ini",
|
|
1803
|
-
[
|
|
1804
|
-
`extension=/internal/shared/extensions/${extensionName}`
|
|
1805
|
-
].join("\n")
|
|
1806
|
-
);
|
|
1807
|
-
}
|
|
1808
|
-
}
|
|
1809
|
-
};
|
|
1810
|
-
}
|
|
1811
|
-
|
|
1812
|
-
// packages/php-wasm/node/src/lib/extensions/memcached/with-memcached.ts
|
|
1813
|
-
import { LatestSupportedPHPVersion as LatestSupportedPHPVersion9, FSHelpers as FSHelpers4 } from "@php-wasm/universal";
|
|
1814
|
-
import fs4 from "fs";
|
|
1815
|
-
|
|
1816
|
-
// packages/php-wasm/node/src/lib/extensions/memcached/get-memcached-extension-module.ts
|
|
1817
|
-
import { LatestSupportedPHPVersion as LatestSupportedPHPVersion8 } from "@php-wasm/universal";
|
|
1818
|
-
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) {
|
|
1819
1629
|
switch (version) {
|
|
1820
1630
|
case "8.5":
|
|
1821
|
-
return (await import("@php-wasm/node-8-5")).
|
|
1631
|
+
return (await import("@php-wasm/node-8-5")).getXdebugExtensionPath();
|
|
1822
1632
|
case "8.4":
|
|
1823
|
-
return (await import("@php-wasm/node-8-4")).
|
|
1633
|
+
return (await import("@php-wasm/node-8-4")).getXdebugExtensionPath();
|
|
1824
1634
|
case "8.3":
|
|
1825
|
-
return (await import("@php-wasm/node-8-3")).
|
|
1635
|
+
return (await import("@php-wasm/node-8-3")).getXdebugExtensionPath();
|
|
1826
1636
|
case "8.2":
|
|
1827
|
-
return (await import("@php-wasm/node-8-2")).
|
|
1637
|
+
return (await import("@php-wasm/node-8-2")).getXdebugExtensionPath();
|
|
1828
1638
|
case "8.1":
|
|
1829
|
-
return (await import("@php-wasm/node-8-1")).
|
|
1639
|
+
return (await import("@php-wasm/node-8-1")).getXdebugExtensionPath();
|
|
1830
1640
|
case "8.0":
|
|
1831
|
-
return (await import("@php-wasm/node-8-0")).
|
|
1641
|
+
return (await import("@php-wasm/node-8-0")).getXdebugExtensionPath();
|
|
1832
1642
|
case "7.4":
|
|
1833
|
-
return (await import("@php-wasm/node-7-4")).
|
|
1643
|
+
return (await import("@php-wasm/node-7-4")).getXdebugExtensionPath();
|
|
1834
1644
|
}
|
|
1835
1645
|
throw new Error(`Unsupported PHP version ${version}`);
|
|
1836
1646
|
}
|
|
1837
1647
|
|
|
1838
|
-
// packages/php-wasm/node/src/lib/extensions/
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
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
|
+
}
|
|
1843
1668
|
return {
|
|
1844
|
-
...
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
"/internal/shared/extensions/memcached.ini"
|
|
1871
|
-
)) {
|
|
1872
|
-
phpRuntime.FS.writeFile(
|
|
1873
|
-
"/internal/shared/extensions/memcached.ini",
|
|
1874
|
-
[
|
|
1875
|
-
`extension=/internal/shared/extensions/${extensionName}`
|
|
1876
|
-
].join("\n")
|
|
1877
|
-
);
|
|
1878
|
-
}
|
|
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;
|
|
1879
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
|
|
1880
1843
|
};
|
|
1881
1844
|
}
|
|
1882
1845
|
|
|
1883
1846
|
// packages/php-wasm/node/src/lib/load-runtime.ts
|
|
1884
1847
|
import { dirname, joinPaths, toPosixPath } from "@php-wasm/util";
|
|
1885
1848
|
import { platform } from "os";
|
|
1849
|
+
import { jspi } from "wasm-feature-detect";
|
|
1886
1850
|
var dangerousDefaultProcessIdAllocator = process.env.VITEST ? new ProcessIdAllocator() : void 0;
|
|
1887
1851
|
async function loadNodeRuntime(phpVersion, options = {}) {
|
|
1888
1852
|
const processId = options.emscriptenOptions?.processId ?? // !! Only assign a default process ID during test.
|
|
@@ -1890,6 +1854,22 @@ async function loadNodeRuntime(phpVersion, options = {}) {
|
|
|
1890
1854
|
// could break file locking and lead to database corruption.
|
|
1891
1855
|
(process.env.VITEST ? dangerousDefaultProcessIdAllocator.claim() : void 0);
|
|
1892
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
|
+
}
|
|
1893
1873
|
let emscriptenOptions = {
|
|
1894
1874
|
/**
|
|
1895
1875
|
* Emscripten default behavior is to kill the process when
|
|
@@ -1908,6 +1888,7 @@ async function loadNodeRuntime(phpVersion, options = {}) {
|
|
|
1908
1888
|
return bindUserSpace({ fileLockManager }, userSpaceContext);
|
|
1909
1889
|
},
|
|
1910
1890
|
...options.emscriptenOptions || {},
|
|
1891
|
+
phpWasmAsyncMode,
|
|
1911
1892
|
processId,
|
|
1912
1893
|
// For legacy PHP: pre-create php.ini via a preRun step. See
|
|
1913
1894
|
// createLegacyPhpIniPreRunStep for why this must run before
|
|
@@ -1923,7 +1904,7 @@ async function loadNodeRuntime(phpVersion, options = {}) {
|
|
|
1923
1904
|
if (options?.followSymlinks === true) {
|
|
1924
1905
|
phpRuntime.FS.filesystems.NODEFS.node_ops.readlink = (node) => {
|
|
1925
1906
|
const absoluteSourcePath = phpRuntime.FS.filesystems.NODEFS.tryFSOperation(
|
|
1926
|
-
() =>
|
|
1907
|
+
() => fs2.realpathSync(
|
|
1927
1908
|
phpRuntime.FS.filesystems.NODEFS.realPath(node)
|
|
1928
1909
|
)
|
|
1929
1910
|
);
|
|
@@ -1932,9 +1913,9 @@ async function loadNodeRuntime(phpVersion, options = {}) {
|
|
|
1932
1913
|
`/internal/symlinks`,
|
|
1933
1914
|
normalizedPath
|
|
1934
1915
|
);
|
|
1935
|
-
if (
|
|
1936
|
-
const sourceStat =
|
|
1937
|
-
if (!
|
|
1916
|
+
if (fs2.existsSync(absoluteSourcePath)) {
|
|
1917
|
+
const sourceStat = fs2.statSync(absoluteSourcePath);
|
|
1918
|
+
if (!FSHelpers.fileExists(
|
|
1938
1919
|
phpRuntime.FS,
|
|
1939
1920
|
symlinkMountPath
|
|
1940
1921
|
)) {
|
|
@@ -1973,68 +1954,58 @@ async function loadNodeRuntime(phpVersion, options = {}) {
|
|
|
1973
1954
|
phpRuntime.FS.root.mount.opts.root = ".";
|
|
1974
1955
|
}
|
|
1975
1956
|
};
|
|
1976
|
-
if (isLegacy &&
|
|
1957
|
+
if (isLegacy && requestedExtensions.length) {
|
|
1977
1958
|
throw new Error(
|
|
1978
1959
|
`Extensions (xdebug, intl, redis, memcached) are not available for legacy PHP ${phpVersion}.`
|
|
1979
1960
|
);
|
|
1980
1961
|
}
|
|
1981
1962
|
if (!isLegacy) {
|
|
1982
1963
|
const modernVersion = phpVersion;
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
}
|
|
1990
|
-
if (options?.withIntl === true) {
|
|
1991
|
-
emscriptenOptions = await withIntl(
|
|
1992
|
-
modernVersion,
|
|
1993
|
-
emscriptenOptions
|
|
1994
|
-
);
|
|
1995
|
-
}
|
|
1996
|
-
if (options?.withRedis === true) {
|
|
1997
|
-
emscriptenOptions = await withRedis(
|
|
1998
|
-
modernVersion,
|
|
1999
|
-
emscriptenOptions
|
|
2000
|
-
);
|
|
2001
|
-
}
|
|
2002
|
-
if (options?.withMemcached === true) {
|
|
2003
|
-
emscriptenOptions = await withMemcached(
|
|
2004
|
-
modernVersion,
|
|
2005
|
-
emscriptenOptions
|
|
2006
|
-
);
|
|
2007
|
-
}
|
|
1964
|
+
emscriptenOptions = await withPHPExtensions(
|
|
1965
|
+
modernVersion,
|
|
1966
|
+
phpWasmAsyncMode,
|
|
1967
|
+
emscriptenOptions,
|
|
1968
|
+
requestedExtensions
|
|
1969
|
+
);
|
|
2008
1970
|
}
|
|
2009
1971
|
emscriptenOptions = await withNetworking(emscriptenOptions);
|
|
2010
1972
|
const phpLoaderModule = await getPHPLoaderModule(phpVersion);
|
|
2011
1973
|
const runtimeId = await loadPHPRuntime(phpLoaderModule, emscriptenOptions);
|
|
2012
1974
|
return runtimeId;
|
|
2013
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
|
+
}
|
|
2014
1984
|
|
|
2015
1985
|
// packages/php-wasm/node/src/lib/use-host-filesystem.ts
|
|
2016
|
-
import { lstatSync
|
|
1986
|
+
import { lstatSync, readdirSync } from "node:fs";
|
|
2017
1987
|
|
|
2018
1988
|
// packages/php-wasm/node/src/lib/node-fs-mount.ts
|
|
2019
1989
|
import {
|
|
2020
|
-
FSHelpers as
|
|
1990
|
+
FSHelpers as FSHelpers2
|
|
2021
1991
|
} from "@php-wasm/universal";
|
|
2022
1992
|
import { isParentOf } from "@php-wasm/util";
|
|
2023
|
-
import {
|
|
1993
|
+
import { realpathSync, statSync } from "fs";
|
|
2024
1994
|
import { dirname as dirname2 } from "path";
|
|
2025
1995
|
function createNodeFsMountHandler(localPath) {
|
|
2026
1996
|
return function(php, FS, vfsMountPoint) {
|
|
2027
1997
|
let removeVfsNode = false;
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
1998
|
+
const mountRoot = realpathSync(localPath);
|
|
1999
|
+
if (!FSHelpers2.fileExists(FS, vfsMountPoint)) {
|
|
2000
|
+
const stat = statSync(mountRoot);
|
|
2001
|
+
if (stat.isFile()) {
|
|
2031
2002
|
FS.mkdirTree(dirname2(vfsMountPoint));
|
|
2032
2003
|
FS.writeFile(vfsMountPoint, "");
|
|
2033
|
-
} else if (
|
|
2004
|
+
} else if (stat.isDirectory()) {
|
|
2034
2005
|
FS.mkdirTree(vfsMountPoint);
|
|
2035
2006
|
} else {
|
|
2036
2007
|
throw new Error(
|
|
2037
|
-
"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."
|
|
2038
2009
|
);
|
|
2039
2010
|
}
|
|
2040
2011
|
removeVfsNode = true;
|
|
@@ -2051,7 +2022,7 @@ function createNodeFsMountHandler(localPath) {
|
|
|
2051
2022
|
}
|
|
2052
2023
|
throw e;
|
|
2053
2024
|
}
|
|
2054
|
-
FS.mount(FS.filesystems["NODEFS"], { root:
|
|
2025
|
+
FS.mount(FS.filesystems["NODEFS"], { root: mountRoot }, vfsMountPoint);
|
|
2055
2026
|
return () => {
|
|
2056
2027
|
FS.unmount(vfsMountPoint);
|
|
2057
2028
|
if (removeVfsNode) {
|
|
@@ -2087,20 +2058,20 @@ function useHostFilesystem(php) {
|
|
|
2087
2058
|
}
|
|
2088
2059
|
php.chdir(process.cwd());
|
|
2089
2060
|
}
|
|
2090
|
-
function statPathFollowSymlinks(
|
|
2091
|
-
let stat =
|
|
2061
|
+
function statPathFollowSymlinks(path3) {
|
|
2062
|
+
let stat = lstatSync(path3);
|
|
2092
2063
|
if (stat.isSymbolicLink()) {
|
|
2093
|
-
const
|
|
2094
|
-
let target =
|
|
2064
|
+
const fs3 = __require("fs");
|
|
2065
|
+
let target = path3;
|
|
2095
2066
|
const seen = /* @__PURE__ */ new Set();
|
|
2096
2067
|
while (true) {
|
|
2097
2068
|
if (seen.has(target)) {
|
|
2098
|
-
throw new Error(`Symlink loop detected: ${
|
|
2069
|
+
throw new Error(`Symlink loop detected: ${path3}`);
|
|
2099
2070
|
}
|
|
2100
2071
|
seen.add(target);
|
|
2101
|
-
const linkStat =
|
|
2072
|
+
const linkStat = lstatSync(target);
|
|
2102
2073
|
if (linkStat.isSymbolicLink()) {
|
|
2103
|
-
target =
|
|
2074
|
+
target = fs3.realpathSync(target);
|
|
2104
2075
|
continue;
|
|
2105
2076
|
}
|
|
2106
2077
|
stat = linkStat;
|
|
@@ -2117,6 +2088,5 @@ export {
|
|
|
2117
2088
|
getPHPLoaderModule,
|
|
2118
2089
|
loadNodeRuntime,
|
|
2119
2090
|
useHostFilesystem,
|
|
2120
|
-
withNetworking
|
|
2121
|
-
withXdebug
|
|
2091
|
+
withNetworking
|
|
2122
2092
|
};
|