@php-wasm/universal 0.9.22 → 0.9.23
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 +7 -7
- package/index.js +206 -180
- package/lib/fs-helpers.d.ts +7 -0
- package/lib/index.d.ts +1 -0
- package/lib/php-request-handler.d.ts +19 -17
- package/lib/php-worker.d.ts +2 -0
- package/lib/php.d.ts +7 -0
- package/package.json +7 -7
package/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var G=(t,e,r)=>{if(!e.has(t))throw TypeError("Cannot "+r)};var c=(t,e,r)=>(G(t,e,"read from private field"),r?r.call(t):e.get(t)),u=(t,e,r)=>{if(e.has(t))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(t):e.set(t,r)},h=(t,e,r,s)=>(G(t,e,"write to private field"),s?s.call(t,r):e.set(t,r),r);var d=(t,e,r)=>(G(t,e,"access private method"),r);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});require("@php-wasm/node-polyfills");const logger=require("@php-wasm/logger"),util=require("@php-wasm/util"),ini=require("ini"),streamCompression=require("@php-wasm/stream-compression"),FileErrorCodes={0:"No error occurred. System call completed successfully.",1:"Argument list too long.",2:"Permission denied.",3:"Address in use.",4:"Address not available.",5:"Address family not supported.",6:"Resource unavailable, or operation would block.",7:"Connection already in progress.",8:"Bad file descriptor.",9:"Bad message.",10:"Device or resource busy.",11:"Operation canceled.",12:"No child processes.",13:"Connection aborted.",14:"Connection refused.",15:"Connection reset.",16:"Resource deadlock would occur.",17:"Destination address required.",18:"Mathematics argument out of domain of function.",19:"Reserved.",20:"File exists.",21:"Bad address.",22:"File too large.",23:"Host is unreachable.",24:"Identifier removed.",25:"Illegal byte sequence.",26:"Operation in progress.",27:"Interrupted function.",28:"Invalid argument.",29:"I/O error.",30:"Socket is connected.",31:"There is a directory under that path.",32:"Too many levels of symbolic links.",33:"File descriptor value too large.",34:"Too many links.",35:"Message too large.",36:"Reserved.",37:"Filename too long.",38:"Network is down.",39:"Connection aborted by network.",40:"Network unreachable.",41:"Too many files open in system.",42:"No buffer space available.",43:"No such device.",44:"There is no such file or directory OR the parent directory does not exist.",45:"Executable file format error.",46:"No locks available.",47:"Reserved.",48:"Not enough space.",49:"No message of the desired type.",50:"Protocol not available.",51:"No space left on device.",52:"Function not supported.",53:"The socket is not connected.",54:"Not a directory or a symbolic link to a directory.",55:"Directory not empty.",56:"State not recoverable.",57:"Not a socket.",58:"Not supported, or operation not supported on socket.",59:"Inappropriate I/O control operation.",60:"No such device or address.",61:"Value too large to be stored in data type.",62:"Previous owner died.",63:"Operation not permitted.",64:"Broken pipe.",65:"Protocol error.",66:"Protocol not supported.",67:"Protocol wrong type for socket.",68:"Result too large.",69:"Read-only file system.",70:"Invalid seek.",71:"No such process.",72:"Reserved.",73:"Connection timed out.",74:"Text file busy.",75:"Cross-device link.",76:"Extension: Capabilities insufficient."};function getEmscriptenFsError(t){const e=typeof t=="object"?t==null?void 0:t.errno:null;if(e in FileErrorCodes)return FileErrorCodes[e]}function rethrowFileSystemError(t=""){return function(r,s,i){const n=i.value;i.value=function(...o){try{return n.apply(this,o)}catch(p){const l=typeof p=="object"?p==null?void 0:p.errno:null;if(l in FileErrorCodes){const a=FileErrorCodes[l],y=typeof o[1]=="string"?o[1]:null,de=y!==null?t.replaceAll("{path}",y):t;throw new Error(`${de}: ${a}`,{cause:p})}throw p}}}}var __defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__decorateClass=(t,e,r,s)=>{for(var i=s>1?void 0:s?__getOwnPropDesc(e,r):e,n=t.length-1,o;n>=0;n--)(o=t[n])&&(i=(s?o(e,r,i):o(i))||i);return s&&i&&__defProp(e,r,i),i};const _FSHelpers=class m{static readFileAsText(e,r){return new TextDecoder().decode(m.readFileAsBuffer(e,r))}static readFileAsBuffer(e,r){return e.readFile(r)}static writeFile(e,r,s){e.writeFile(r,s)}static unlink(e,r){e.unlink(r)}static mv(e,r,s){try{const i=e.lookupPath(r).node.mount,n=m.fileExists(e,s)?e.lookupPath(s).node.mount:e.lookupPath(util.dirname(s)).node.mount;i.mountpoint!==n.mountpoint?(m.copyRecursive(e,r,s),m.rmdir(e,r,{recursive:!0})):e.rename(r,s)}catch(i){const n=getEmscriptenFsError(i);throw n?new Error(`Could not move ${r} to ${s}: ${n}`,{cause:i}):i}}static rmdir(e,r,s={recursive:!0}){s!=null&&s.recursive&&m.listFiles(e,r).forEach(i=>{const n=`${r}/${i}`;m.isDir(e,n)?m.rmdir(e,n,s):m.unlink(e,n)}),e.rmdir(r)}static listFiles(e,r,s={prependPath:!1}){if(!m.fileExists(e,r))return[];try{const i=e.readdir(r).filter(n=>n!=="."&&n!=="..");if(s.prependPath){const n=r.replace(/\/$/,"");return i.map(o=>`${n}/${o}`)}return i}catch(i){return logger.logger.error(i,{path:r}),[]}}static isDir(e,r){return m.fileExists(e,r)?e.isDir(e.lookupPath(r).node.mode):!1}static fileExists(e,r){try{return e.lookupPath(r),!0}catch{return!1}}static mkdir(e,r){e.mkdirTree(r)}static copyRecursive(e,r,s){const i=e.lookupPath(r).node;if(e.isDir(i.mode)){e.mkdirTree(s);const n=e.readdir(r).filter(o=>o!=="."&&o!=="..");for(const o of n)m.copyRecursive(e,util.joinPaths(r,o),util.joinPaths(s,o))}else e.writeFile(s,e.readFile(r))}};__decorateClass([rethrowFileSystemError('Could not read "{path}"')],_FSHelpers,"readFileAsText",1);__decorateClass([rethrowFileSystemError('Could not read "{path}"')],_FSHelpers,"readFileAsBuffer",1);__decorateClass([rethrowFileSystemError('Could not write to "{path}"')],_FSHelpers,"writeFile",1);__decorateClass([rethrowFileSystemError('Could not unlink "{path}"')],_FSHelpers,"unlink",1);__decorateClass([rethrowFileSystemError('Could not remove directory "{path}"')],_FSHelpers,"rmdir",1);__decorateClass([rethrowFileSystemError('Could not list files in "{path}"')],_FSHelpers,"listFiles",1);__decorateClass([rethrowFileSystemError('Could not stat "{path}"')],_FSHelpers,"isDir",1);__decorateClass([rethrowFileSystemError('Could not stat "{path}"')],_FSHelpers,"fileExists",1);__decorateClass([rethrowFileSystemError('Could not create directory "{path}"')],_FSHelpers,"mkdir",1);__decorateClass([rethrowFileSystemError('Could not copy files from "{path}"')],_FSHelpers,"copyRecursive",1);let FSHelpers=_FSHelpers;const _private=new WeakMap;class PHPWorker{constructor(e,r){this.absoluteUrl="",this.documentRoot="",_private.set(this,{monitor:r}),e&&this.__internal_setRequestHandler(e)}__internal_setRequestHandler(e){this.absoluteUrl=e.absoluteUrl,this.documentRoot=e.documentRoot,_private.set(this,{..._private.get(this),requestHandler:e})}__internal_getPHP(){return _private.get(this).php}async setPrimaryPHP(e){_private.set(this,{..._private.get(this),php:e})}pathToInternalUrl(e){return _private.get(this).requestHandler.pathToInternalUrl(e)}internalUrlToPath(e){return _private.get(this).requestHandler.internalUrlToPath(e)}async onDownloadProgress(e){var r;return(r=_private.get(this).monitor)==null?void 0:r.addEventListener("progress",e)}async mv(e,r){return _private.get(this).php.mv(e,r)}async rmdir(e,r){return _private.get(this).php.rmdir(e,r)}async request(e){return await _private.get(this).requestHandler.request(e)}async run(e){const{php:r,reap:s}=await _private.get(this).requestHandler.processManager.acquirePHPInstance();try{return await r.run(e)}finally{s()}}chdir(e){return _private.get(this).php.chdir(e)}setSapiName(e){_private.get(this).php.setSapiName(e)}mkdir(e){return _private.get(this).php.mkdir(e)}mkdirTree(e){return _private.get(this).php.mkdirTree(e)}readFileAsText(e){return _private.get(this).php.readFileAsText(e)}readFileAsBuffer(e){return _private.get(this).php.readFileAsBuffer(e)}writeFile(e,r){return _private.get(this).php.writeFile(e,r)}unlink(e){return _private.get(this).php.unlink(e)}listFiles(e,r){return _private.get(this).php.listFiles(e,r)}isDir(e){return _private.get(this).php.isDir(e)}fileExists(e){return _private.get(this).php.fileExists(e)}onMessage(e){_private.get(this).php.onMessage(e)}defineConstant(e,r){_private.get(this).php.defineConstant(e,r)}addEventListener(e,r){_private.get(this).php.addEventListener(e,r)}removeEventListener(e,r){_private.get(this).php.removeEventListener(e,r)}}const responseTexts={500:"Internal Server Error",502:"Bad Gateway",404:"Not Found",403:"Forbidden",401:"Unauthorized",400:"Bad Request",301:"Moved Permanently",302:"Found",307:"Temporary Redirect",308:"Permanent Redirect",204:"No Content",201:"Created",200:"OK"};class PHPResponse{constructor(e,r,s,i="",n=0){this.httpStatusCode=e,this.headers=r,this.bytes=s,this.exitCode=n,this.errors=i}static forHttpCode(e,r=""){return new PHPResponse(e,{},new TextEncoder().encode(r||responseTexts[e]||""))}static fromRawData(e){return new PHPResponse(e.httpStatusCode,e.headers,e.bytes,e.errors,e.exitCode)}toRawData(){return{headers:this.headers,bytes:this.bytes,errors:this.errors,exitCode:this.exitCode,httpStatusCode:this.httpStatusCode}}get json(){return JSON.parse(this.text)}get text(){return new TextDecoder().decode(this.bytes)}}const RuntimeId=Symbol("RuntimeId"),loadedRuntimes=new Map;let lastRuntimeId=0;async function loadPHPRuntime(t,e={}){const[r,s,i]=makePromise(),n=t.init(currentJsRuntime,{onAbort(p){i(p),logger.logger.error(p)},ENV:{},locateFile:p=>p,...e,noInitialRun:!0,onRuntimeInitialized(){e.onRuntimeInitialized&&e.onRuntimeInitialized(),s()}});await r;const o=++lastRuntimeId;return n.id=o,n.originalExit=n._exit,n._exit=function(p){return loadedRuntimes.delete(o),n.originalExit(p)},n[RuntimeId]=o,loadedRuntimes.set(o,n),o}function getLoadedRuntime(t){return loadedRuntimes.get(t)}const currentJsRuntime=function(){var t;return typeof process<"u"&&((t=process.release)==null?void 0:t.name)==="node"?"NODE":typeof window<"u"?"WEB":typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope?"WORKER":"NODE"}(),makePromise=()=>{const t=[],e=new Promise((r,s)=>{t.push(r,s)});return t.unshift(e),t},kError=Symbol("error"),kMessage=Symbol("message");class ErrorEvent2 extends Event{constructor(e,r={}){super(e),this[kError]=r.error===void 0?null:r.error,this[kMessage]=r.message===void 0?"":r.message}get error(){return this[kError]}get message(){return this[kMessage]}}Object.defineProperty(ErrorEvent2.prototype,"error",{enumerable:!0});Object.defineProperty(ErrorEvent2.prototype,"message",{enumerable:!0});const ErrorEvent=typeof globalThis.ErrorEvent=="function"?globalThis.ErrorEvent:ErrorEvent2;function isExitCodeZero(t){return t instanceof Error?"exitCode"in t&&(t==null?void 0:t.exitCode)===0||(t==null?void 0:t.name)==="ExitStatus"&&"status"in t&&t.status===0:!1}class UnhandledRejectionsTarget extends EventTarget{constructor(){super(...arguments),this.listenersCount=0}addEventListener(e,r){++this.listenersCount,super.addEventListener(e,r)}removeEventListener(e,r){--this.listenersCount,super.removeEventListener(e,r)}hasListeners(){return this.listenersCount>0}}function improveWASMErrorReporting(t){const e=new UnhandledRejectionsTarget;for(const r in t.wasmExports)if(typeof t.wasmExports[r]=="function"){const s=t.wasmExports[r];t.wasmExports[r]=function(...i){var n;try{return s(...i)}catch(o){if(!(o instanceof Error))throw o;const p=clarifyErrorMessage(o,(n=t.lastAsyncifyStackSource)==null?void 0:n.stack);if(t.lastAsyncifyStackSource&&(o.cause=t.lastAsyncifyStackSource),e.hasListeners()){e.dispatchEvent(new ErrorEvent("error",{error:o,message:p}));return}throw isExitCodeZero(o)||showCriticalErrorBox(p),o}}}return e}let functionsMaybeMissingFromAsyncify=[];function getFunctionsMaybeMissingFromAsyncify(){return functionsMaybeMissingFromAsyncify}function clarifyErrorMessage(t,e){if(t.message==="unreachable"){let r=UNREACHABLE_ERROR;e||(r+=`
|
|
1
|
+
"use strict";var V=(t,e,r)=>{if(!e.has(t))throw TypeError("Cannot "+r)};var p=(t,e,r)=>(V(t,e,"read from private field"),r?r.call(t):e.get(t)),u=(t,e,r)=>{if(e.has(t))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(t):e.set(t,r)},h=(t,e,r,s)=>(V(t,e,"write to private field"),s?s.call(t,r):e.set(t,r),r);var d=(t,e,r)=>(V(t,e,"access private method"),r);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});require("@php-wasm/node-polyfills");const logger=require("@php-wasm/logger"),util=require("@php-wasm/util"),ini=require("ini"),streamCompression=require("@php-wasm/stream-compression"),FileErrorCodes={0:"No error occurred. System call completed successfully.",1:"Argument list too long.",2:"Permission denied.",3:"Address in use.",4:"Address not available.",5:"Address family not supported.",6:"Resource unavailable, or operation would block.",7:"Connection already in progress.",8:"Bad file descriptor.",9:"Bad message.",10:"Device or resource busy.",11:"Operation canceled.",12:"No child processes.",13:"Connection aborted.",14:"Connection refused.",15:"Connection reset.",16:"Resource deadlock would occur.",17:"Destination address required.",18:"Mathematics argument out of domain of function.",19:"Reserved.",20:"File exists.",21:"Bad address.",22:"File too large.",23:"Host is unreachable.",24:"Identifier removed.",25:"Illegal byte sequence.",26:"Operation in progress.",27:"Interrupted function.",28:"Invalid argument.",29:"I/O error.",30:"Socket is connected.",31:"There is a directory under that path.",32:"Too many levels of symbolic links.",33:"File descriptor value too large.",34:"Too many links.",35:"Message too large.",36:"Reserved.",37:"Filename too long.",38:"Network is down.",39:"Connection aborted by network.",40:"Network unreachable.",41:"Too many files open in system.",42:"No buffer space available.",43:"No such device.",44:"There is no such file or directory OR the parent directory does not exist.",45:"Executable file format error.",46:"No locks available.",47:"Reserved.",48:"Not enough space.",49:"No message of the desired type.",50:"Protocol not available.",51:"No space left on device.",52:"Function not supported.",53:"The socket is not connected.",54:"Not a directory or a symbolic link to a directory.",55:"Directory not empty.",56:"State not recoverable.",57:"Not a socket.",58:"Not supported, or operation not supported on socket.",59:"Inappropriate I/O control operation.",60:"No such device or address.",61:"Value too large to be stored in data type.",62:"Previous owner died.",63:"Operation not permitted.",64:"Broken pipe.",65:"Protocol error.",66:"Protocol not supported.",67:"Protocol wrong type for socket.",68:"Result too large.",69:"Read-only file system.",70:"Invalid seek.",71:"No such process.",72:"Reserved.",73:"Connection timed out.",74:"Text file busy.",75:"Cross-device link.",76:"Extension: Capabilities insufficient."};function getEmscriptenFsError(t){const e=typeof t=="object"?t==null?void 0:t.errno:null;if(e in FileErrorCodes)return FileErrorCodes[e]}function rethrowFileSystemError(t=""){return function(r,s,i){const n=i.value;i.value=function(...o){try{return n.apply(this,o)}catch(a){const l=typeof a=="object"?a==null?void 0:a.errno:null;if(l in FileErrorCodes){const c=FileErrorCodes[l],y=typeof o[1]=="string"?o[1]:null,pe=y!==null?t.replaceAll("{path}",y):t;throw new Error(`${pe}: ${c}`,{cause:a})}throw a}}}}var __defProp=Object.defineProperty,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__decorateClass=(t,e,r,s)=>{for(var i=s>1?void 0:s?__getOwnPropDesc(e,r):e,n=t.length-1,o;n>=0;n--)(o=t[n])&&(i=(s?o(e,r,i):o(i))||i);return s&&i&&__defProp(e,r,i),i};const _FSHelpers=class m{static readFileAsText(e,r){return new TextDecoder().decode(m.readFileAsBuffer(e,r))}static readFileAsBuffer(e,r){return e.readFile(r)}static writeFile(e,r,s){e.writeFile(r,s)}static unlink(e,r){e.unlink(r)}static mv(e,r,s){try{const i=e.lookupPath(r).node.mount,n=m.fileExists(e,s)?e.lookupPath(s).node.mount:e.lookupPath(util.dirname(s)).node.mount;i.mountpoint!==n.mountpoint?(m.copyRecursive(e,r,s),m.rmdir(e,r,{recursive:!0})):e.rename(r,s)}catch(i){const n=getEmscriptenFsError(i);throw n?new Error(`Could not move ${r} to ${s}: ${n}`,{cause:i}):i}}static rmdir(e,r,s={recursive:!0}){s!=null&&s.recursive&&m.listFiles(e,r).forEach(i=>{const n=`${r}/${i}`;m.isDir(e,n)?m.rmdir(e,n,s):m.unlink(e,n)}),e.rmdir(r)}static listFiles(e,r,s={prependPath:!1}){if(!m.fileExists(e,r))return[];try{const i=e.readdir(r).filter(n=>n!=="."&&n!=="..");if(s.prependPath){const n=r.replace(/\/$/,"");return i.map(o=>`${n}/${o}`)}return i}catch(i){return logger.logger.error(i,{path:r}),[]}}static isDir(e,r){return m.fileExists(e,r)?e.isDir(e.lookupPath(r).node.mode):!1}static isFile(e,r){return m.fileExists(e,r)?e.isFile(e.lookupPath(r).node.mode):!1}static fileExists(e,r){try{return e.lookupPath(r),!0}catch{return!1}}static mkdir(e,r){e.mkdirTree(r)}static copyRecursive(e,r,s){const i=e.lookupPath(r).node;if(e.isDir(i.mode)){e.mkdirTree(s);const n=e.readdir(r).filter(o=>o!=="."&&o!=="..");for(const o of n)m.copyRecursive(e,util.joinPaths(r,o),util.joinPaths(s,o))}else e.writeFile(s,e.readFile(r))}};__decorateClass([rethrowFileSystemError('Could not read "{path}"')],_FSHelpers,"readFileAsText",1);__decorateClass([rethrowFileSystemError('Could not read "{path}"')],_FSHelpers,"readFileAsBuffer",1);__decorateClass([rethrowFileSystemError('Could not write to "{path}"')],_FSHelpers,"writeFile",1);__decorateClass([rethrowFileSystemError('Could not unlink "{path}"')],_FSHelpers,"unlink",1);__decorateClass([rethrowFileSystemError('Could not remove directory "{path}"')],_FSHelpers,"rmdir",1);__decorateClass([rethrowFileSystemError('Could not list files in "{path}"')],_FSHelpers,"listFiles",1);__decorateClass([rethrowFileSystemError('Could not stat "{path}"')],_FSHelpers,"isDir",1);__decorateClass([rethrowFileSystemError('Could not stat "{path}"')],_FSHelpers,"fileExists",1);__decorateClass([rethrowFileSystemError('Could not create directory "{path}"')],_FSHelpers,"mkdir",1);__decorateClass([rethrowFileSystemError('Could not copy files from "{path}"')],_FSHelpers,"copyRecursive",1);let FSHelpers=_FSHelpers;const _private=new WeakMap;class PHPWorker{constructor(e,r){this.absoluteUrl="",this.documentRoot="",_private.set(this,{monitor:r}),e&&this.__internal_setRequestHandler(e)}__internal_setRequestHandler(e){this.absoluteUrl=e.absoluteUrl,this.documentRoot=e.documentRoot,_private.set(this,{..._private.get(this),requestHandler:e})}__internal_getPHP(){return _private.get(this).php}async setPrimaryPHP(e){_private.set(this,{..._private.get(this),php:e})}pathToInternalUrl(e){return _private.get(this).requestHandler.pathToInternalUrl(e)}internalUrlToPath(e){return _private.get(this).requestHandler.internalUrlToPath(e)}async onDownloadProgress(e){var r;return(r=_private.get(this).monitor)==null?void 0:r.addEventListener("progress",e)}async mv(e,r){return _private.get(this).php.mv(e,r)}async rmdir(e,r){return _private.get(this).php.rmdir(e,r)}async request(e){return await _private.get(this).requestHandler.request(e)}async run(e){const{php:r,reap:s}=await _private.get(this).requestHandler.processManager.acquirePHPInstance();try{return await r.run(e)}finally{s()}}chdir(e){return _private.get(this).php.chdir(e)}setSapiName(e){_private.get(this).php.setSapiName(e)}mkdir(e){return _private.get(this).php.mkdir(e)}mkdirTree(e){return _private.get(this).php.mkdirTree(e)}readFileAsText(e){return _private.get(this).php.readFileAsText(e)}readFileAsBuffer(e){return _private.get(this).php.readFileAsBuffer(e)}writeFile(e,r){return _private.get(this).php.writeFile(e,r)}unlink(e){return _private.get(this).php.unlink(e)}listFiles(e,r){return _private.get(this).php.listFiles(e,r)}isDir(e){return _private.get(this).php.isDir(e)}isFile(e){return _private.get(this).php.isFile(e)}fileExists(e){return _private.get(this).php.fileExists(e)}onMessage(e){_private.get(this).php.onMessage(e)}defineConstant(e,r){_private.get(this).php.defineConstant(e,r)}addEventListener(e,r){_private.get(this).php.addEventListener(e,r)}removeEventListener(e,r){_private.get(this).php.removeEventListener(e,r)}}const responseTexts={500:"Internal Server Error",502:"Bad Gateway",404:"Not Found",403:"Forbidden",401:"Unauthorized",400:"Bad Request",301:"Moved Permanently",302:"Found",307:"Temporary Redirect",308:"Permanent Redirect",204:"No Content",201:"Created",200:"OK"};class PHPResponse{constructor(e,r,s,i="",n=0){this.httpStatusCode=e,this.headers=r,this.bytes=s,this.exitCode=n,this.errors=i}static forHttpCode(e,r=""){return new PHPResponse(e,{},new TextEncoder().encode(r||responseTexts[e]||""))}static fromRawData(e){return new PHPResponse(e.httpStatusCode,e.headers,e.bytes,e.errors,e.exitCode)}toRawData(){return{headers:this.headers,bytes:this.bytes,errors:this.errors,exitCode:this.exitCode,httpStatusCode:this.httpStatusCode}}get json(){return JSON.parse(this.text)}get text(){return new TextDecoder().decode(this.bytes)}}const RuntimeId=Symbol("RuntimeId"),loadedRuntimes=new Map;let lastRuntimeId=0;async function loadPHPRuntime(t,e={}){const[r,s,i]=makePromise(),n=t.init(currentJsRuntime,{onAbort(a){i(a),logger.logger.error(a)},ENV:{},locateFile:a=>a,...e,noInitialRun:!0,onRuntimeInitialized(){e.onRuntimeInitialized&&e.onRuntimeInitialized(),s()}});await r;const o=++lastRuntimeId;return n.id=o,n.originalExit=n._exit,n._exit=function(a){return loadedRuntimes.delete(o),n.originalExit(a)},n[RuntimeId]=o,loadedRuntimes.set(o,n),o}function getLoadedRuntime(t){return loadedRuntimes.get(t)}const currentJsRuntime=function(){var t;return typeof process<"u"&&((t=process.release)==null?void 0:t.name)==="node"?"NODE":typeof window<"u"?"WEB":typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope?"WORKER":"NODE"}(),makePromise=()=>{const t=[],e=new Promise((r,s)=>{t.push(r,s)});return t.unshift(e),t},kError=Symbol("error"),kMessage=Symbol("message");class ErrorEvent2 extends Event{constructor(e,r={}){super(e),this[kError]=r.error===void 0?null:r.error,this[kMessage]=r.message===void 0?"":r.message}get error(){return this[kError]}get message(){return this[kMessage]}}Object.defineProperty(ErrorEvent2.prototype,"error",{enumerable:!0});Object.defineProperty(ErrorEvent2.prototype,"message",{enumerable:!0});const ErrorEvent=typeof globalThis.ErrorEvent=="function"?globalThis.ErrorEvent:ErrorEvent2;function isExitCodeZero(t){return t instanceof Error?"exitCode"in t&&(t==null?void 0:t.exitCode)===0||(t==null?void 0:t.name)==="ExitStatus"&&"status"in t&&t.status===0:!1}class UnhandledRejectionsTarget extends EventTarget{constructor(){super(...arguments),this.listenersCount=0}addEventListener(e,r){++this.listenersCount,super.addEventListener(e,r)}removeEventListener(e,r){--this.listenersCount,super.removeEventListener(e,r)}hasListeners(){return this.listenersCount>0}}function improveWASMErrorReporting(t){const e=new UnhandledRejectionsTarget;for(const r in t.wasmExports)if(typeof t.wasmExports[r]=="function"){const s=t.wasmExports[r];t.wasmExports[r]=function(...i){var n;try{return s(...i)}catch(o){if(!(o instanceof Error))throw o;const a=clarifyErrorMessage(o,(n=t.lastAsyncifyStackSource)==null?void 0:n.stack);if(t.lastAsyncifyStackSource&&(o.cause=t.lastAsyncifyStackSource),e.hasListeners()){e.dispatchEvent(new ErrorEvent("error",{error:o,message:a}));return}throw isExitCodeZero(o)||showCriticalErrorBox(a),o}}}return e}let functionsMaybeMissingFromAsyncify=[];function getFunctionsMaybeMissingFromAsyncify(){return functionsMaybeMissingFromAsyncify}function clarifyErrorMessage(t,e){if(t.message==="unreachable"){let r=UNREACHABLE_ERROR;e||(r+=`
|
|
2
2
|
|
|
3
3
|
This stack trace is lacking. For a better one initialize
|
|
4
4
|
the PHP runtime with { debug: true }, e.g. PHPNode.load('8.1', { debug: true }).
|
|
@@ -32,7 +32,7 @@ CLI option:
|
|
|
32
32
|
${eol}
|
|
33
33
|
${bold} WASM ERROR${reset}${redBg}`);for(const e of t.split(`
|
|
34
34
|
`))logger.logger.log(`${eol} ${e} `);logger.logger.log(`${reset}`)}}function extractPHPFunctionsFromStack(t){try{const e=t.split(`
|
|
35
|
-
`).slice(1).map(r=>{const s=r.trim().substring(3).split(" ");return{fn:s.length>=2?s[0]:"<unknown>",isWasm:r.includes("wasm://")}}).filter(({fn:r,isWasm:s})=>s&&!r.startsWith("dynCall_")&&!r.startsWith("invoke_")).map(({fn:r})=>r);return Array.from(new Set(e))}catch{return[]}}const STRING="string",NUMBER="number",__private__dont__use=Symbol("__private__dont__use");class PHPExecutionFailureError extends Error{constructor(e,r,s){super(e),this.response=r,this.source=s}}const PHP_INI_PATH="/internal/shared/php.ini",AUTO_PREPEND_SCRIPT="/internal/shared/auto_prepend_file.php";var x,P,
|
|
35
|
+
`).slice(1).map(r=>{const s=r.trim().substring(3).split(" ");return{fn:s.length>=2?s[0]:"<unknown>",isWasm:r.includes("wasm://")}}).filter(({fn:r,isWasm:s})=>s&&!r.startsWith("dynCall_")&&!r.startsWith("invoke_")).map(({fn:r})=>r);return Array.from(new Set(e))}catch{return[]}}const STRING="string",NUMBER="number",__private__dont__use=Symbol("__private__dont__use");class PHPExecutionFailureError extends Error{constructor(e,r,s){super(e),this.response=r,this.source=s}}const PHP_INI_PATH="/internal/shared/php.ini",AUTO_PREPEND_SCRIPT="/internal/shared/auto_prepend_file.php";var x,g,P,_,E,k,J,I,Y,C,Z,A,K,N,X,M,Q,U,ee,j,te,L,re,q,se,b,G,$,ie,B,ne,O,oe;class PHP{constructor(t){u(this,k);u(this,I);u(this,C);u(this,A);u(this,N);u(this,M);u(this,U);u(this,j);u(this,L);u(this,q);u(this,b);u(this,$);u(this,B);u(this,O);u(this,x,void 0);u(this,g,void 0);u(this,P,void 0);u(this,_,void 0);u(this,E,void 0);h(this,g,!1),h(this,P,null),h(this,_,new Map),h(this,E,[]),this.semaphore=new util.Semaphore({concurrency:1}),t!==void 0&&this.initializeRuntime(t)}addEventListener(t,e){p(this,_).has(t)||p(this,_).set(t,new Set),p(this,_).get(t).add(e)}removeEventListener(t,e){var r;(r=p(this,_).get(t))==null||r.delete(e)}dispatchEvent(t){const e=p(this,_).get(t.type);if(e)for(const r of e)r(t)}onMessage(t){p(this,E).push(t)}async setSpawnHandler(handler){typeof handler=="string"&&(handler=util.createSpawnHandler(eval(handler))),this[__private__dont__use].spawnProcess=handler}get absoluteUrl(){return this.requestHandler.absoluteUrl}get documentRoot(){return this.requestHandler.documentRoot}pathToInternalUrl(t){return this.requestHandler.pathToInternalUrl(t)}internalUrlToPath(t){return this.requestHandler.internalUrlToPath(t)}initializeRuntime(t){if(this[__private__dont__use])throw new Error("PHP runtime already initialized.");const e=getLoadedRuntime(t);if(!e)throw new Error("Invalid PHP runtime id.");this[__private__dont__use]=e,this[__private__dont__use].ccall("wasm_set_phpini_path",null,["string"],[PHP_INI_PATH]),this.fileExists(PHP_INI_PATH)||this.writeFile(PHP_INI_PATH,["auto_prepend_file="+AUTO_PREPEND_SCRIPT,"memory_limit=256M","ignore_repeated_errors = 1","error_reporting = E_ALL","display_errors = 1","html_errors = 1","display_startup_errors = On","log_errors = 1","always_populate_raw_post_data = -1","upload_max_filesize = 2000M","post_max_size = 2000M","disable_functions = curl_exec,curl_multi_exec","allow_url_fopen = Off","allow_url_include = Off","session.save_path = /home/web_user","implicit_flush = 1","output_buffering = 0","max_execution_time = 0","max_input_time = -1"].join(`
|
|
36
36
|
`)),this.fileExists(AUTO_PREPEND_SCRIPT)||this.writeFile(AUTO_PREPEND_SCRIPT,`<?php
|
|
37
37
|
// Define constants set via defineConstant() calls
|
|
38
38
|
if(file_exists('/internal/shared/consts.json')) {
|
|
@@ -47,10 +47,10 @@ ${bold} WASM ERROR${reset}${redBg}`);for(const e of t.split(`
|
|
|
47
47
|
foreach (glob('/internal/shared/preload/*.php') as $file) {
|
|
48
48
|
require_once $file;
|
|
49
49
|
}
|
|
50
|
-
`),e.onMessage=async r=>{for(const s of c(this,E)){const i=await s(r);if(i)return i}return""},h(this,w,improveWASMErrorReporting(e)),this.dispatchEvent({type:"runtime.initialized"})}async setSapiName(t){if(this[__private__dont__use].ccall("wasm_set_sapi_name",NUMBER,[STRING],[t])!==0)throw new Error("Could not set SAPI name. This can only be done before the PHP WASM module is initialized.Did you already dispatch any requests?");h(this,x,t)}chdir(t){this[__private__dont__use].FS.chdir(t)}async request(t){if(logger.logger.warn("PHP.request() is deprecated. Please use new PHPRequestHandler() instead."),!this.requestHandler)throw new Error("No request handler available.");return this.requestHandler.request(t)}async run(t){const e=await this.semaphore.acquire();let r;try{if(c(this,P)||(d(this,I,Z).call(this),h(this,P,!0)),t.scriptPath&&!this.fileExists(t.scriptPath))throw new Error(`The script path "${t.scriptPath}" does not exist.`);d(this,A,X).call(this,t.relativeUri||""),d(this,L,re).call(this,t.method||"GET");const s=normalizeHeaders(t.headers||{}),i=s.host||"example.com:443",n=d(this,j,te).call(this,i,t.protocol||"http");d(this,N,Q).call(this,i),d(this,M,ee).call(this,n),d(this,U,se).call(this,s),t.body&&(r=d(this,q,ie).call(this,t.body)),typeof t.code=="string"?(this.writeFile("/internal/eval.php",t.code),d(this,b,J).call(this,"/internal/eval.php")):d(this,b,J).call(this,t.scriptPath||"");const o=d(this,k,Y).call(this,t.$_SERVER,s,n);for(const a in o)d(this,$,ne).call(this,a,o[a]);const p=t.env||{};for(const a in p)d(this,B,oe).call(this,a,p[a]);const l=await d(this,O,ae).call(this);if(l.exitCode!==0){logger.logger.warn("PHP.run() output was:",l.text);const a=new PHPExecutionFailureError(`PHP.run() failed with exit code ${l.exitCode} and the following output: `+l.errors,l,"request");throw logger.logger.error(a),a}return l}catch(s){throw this.dispatchEvent({type:"request.error",error:s,source:s.source??"php-wasm"}),s}finally{try{r&&this[__private__dont__use].free(r)}finally{e(),this.dispatchEvent({type:"request.end"})}}}defineConstant(t,e){let r={};try{r=JSON.parse(this.fileExists("/internal/shared/consts.json")&&this.readFileAsText("/internal/shared/consts.json")||"{}")}catch{}this.writeFile("/internal/shared/consts.json",JSON.stringify({...r,[t]:e}))}mkdir(t){return FSHelpers.mkdir(this[__private__dont__use].FS,t)}mkdirTree(t){return FSHelpers.mkdir(this[__private__dont__use].FS,t)}readFileAsText(t){return FSHelpers.readFileAsText(this[__private__dont__use].FS,t)}readFileAsBuffer(t){return FSHelpers.readFileAsBuffer(this[__private__dont__use].FS,t)}writeFile(t,e){return FSHelpers.writeFile(this[__private__dont__use].FS,t,e)}unlink(t){return FSHelpers.unlink(this[__private__dont__use].FS,t)}mv(t,e){return FSHelpers.mv(this[__private__dont__use].FS,t,e)}rmdir(t,e={recursive:!0}){return FSHelpers.rmdir(this[__private__dont__use].FS,t,e)}listFiles(t,e={prependPath:!1}){return FSHelpers.listFiles(this[__private__dont__use].FS,t,e)}isDir(t){return FSHelpers.isDir(this[__private__dont__use].FS,t)}fileExists(t){return FSHelpers.fileExists(this[__private__dont__use].FS,t)}hotSwapPHPRuntime(t,e){const r=this[__private__dont__use].FS;try{this.exit()}catch{}this.initializeRuntime(t),c(this,x)&&this.setSapiName(c(this,x)),e&©FS(r,this[__private__dont__use].FS,e)}async mount(t,e){return await e(this,this[__private__dont__use].FS,t)}async cli(t){for(const e of t)this[__private__dont__use].ccall("wasm_add_cli_arg",null,[STRING],[e]);try{return await this[__private__dont__use].ccall("run_cli",null,[],[],{async:!0})}catch(e){if(isExitCodeZero(e))return 0;throw e}}setSkipShebang(t){this[__private__dont__use].ccall("wasm_set_skip_shebang",null,[NUMBER],[t?1:0])}exit(t=0){this.dispatchEvent({type:"runtime.beforedestroy"});try{this[__private__dont__use]._exit(t)}catch{}h(this,P,!1),h(this,w,null),delete this[__private__dont__use].onMessage,delete this[__private__dont__use]}[Symbol.dispose](){c(this,P)&&this.exit(0)}}x=new WeakMap,P=new WeakMap,w=new WeakMap,g=new WeakMap,E=new WeakMap,k=new WeakSet,Y=function(t,e,r){const s={...t||{}};s.HTTPS=s.HTTPS||r===443?"on":"off";for(const i in e){let n="HTTP_";["content-type","content-length"].includes(i.toLowerCase())&&(n=""),s[`${n}${i.toUpperCase().replace(/-/g,"_")}`]=e[i]}return s},I=new WeakSet,Z=function(){this[__private__dont__use].ccall("php_wasm_init",null,[],[])},C=new WeakSet,K=function(){const t="/internal/headers.json";if(!this.fileExists(t))throw new Error("SAPI Error: Could not find response headers file.");const e=JSON.parse(this.readFileAsText(t)),r={};for(const s of e.headers){if(!s.includes(": "))continue;const i=s.indexOf(": "),n=s.substring(0,i).toLowerCase(),o=s.substring(i+2);n in r||(r[n]=[]),r[n].push(o)}return{headers:r,httpStatusCode:e.status}},A=new WeakSet,X=function(t){if(this[__private__dont__use].ccall("wasm_set_request_uri",null,[STRING],[t]),t.includes("?")){const e=t.substring(t.indexOf("?")+1);this[__private__dont__use].ccall("wasm_set_query_string",null,[STRING],[e])}},N=new WeakSet,Q=function(t){this[__private__dont__use].ccall("wasm_set_request_host",null,[STRING],[t])},M=new WeakSet,ee=function(t){this[__private__dont__use].ccall("wasm_set_request_port",null,[NUMBER],[t])},j=new WeakSet,te=function(t,e){let r;try{r=parseInt(new URL(t).port,10)}catch{}return(!r||isNaN(r)||r===80)&&(r=e==="https"?443:80),r},L=new WeakSet,re=function(t){this[__private__dont__use].ccall("wasm_set_request_method",null,[STRING],[t])},U=new WeakSet,se=function(t){t.cookie&&this[__private__dont__use].ccall("wasm_set_cookies",null,[STRING],[t.cookie]),t["content-type"]&&this[__private__dont__use].ccall("wasm_set_content_type",null,[STRING],[t["content-type"]]),t["content-length"]&&this[__private__dont__use].ccall("wasm_set_content_length",null,[NUMBER],[parseInt(t["content-length"],10)])},q=new WeakSet,ie=function(t){let e,r;typeof t=="string"?(logger.logger.warn("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"),r=this[__private__dont__use].lengthBytesUTF8(t),e=r+1):(r=t.byteLength,e=t.byteLength);const s=this[__private__dont__use].malloc(e);if(!s)throw new Error("Could not allocate memory for the request body.");return typeof t=="string"?this[__private__dont__use].stringToUTF8(t,s,e+1):this[__private__dont__use].HEAPU8.set(t,s),this[__private__dont__use].ccall("wasm_set_request_body",null,[NUMBER],[s]),this[__private__dont__use].ccall("wasm_set_content_length",null,[NUMBER],[r]),s},b=new WeakSet,J=function(t){this[__private__dont__use].ccall("wasm_set_path_translated",null,[STRING],[t])},$=new WeakSet,ne=function(t,e){this[__private__dont__use].ccall("wasm_add_SERVER_entry",null,[STRING,STRING],[t,e])},B=new WeakSet,oe=function(t,e){this[__private__dont__use].ccall("wasm_add_ENV_entry",null,[STRING,STRING],[t,e])},O=new WeakSet,ae=async function(){var i;let t,e;try{t=await new Promise((n,o)=>{var l;e=a=>{logger.logger.error(a),logger.logger.error(a.error);const y=new Error("Rethrown");y.cause=a.error,y.betterMessage=a.message,o(y)},(l=c(this,w))==null||l.addEventListener("error",e);const p=this[__private__dont__use].ccall("wasm_sapi_handle_request",NUMBER,[],[],{async:!0});return p instanceof Promise?p.then(n,o):n(p)})}catch(n){for(const a in this)typeof this[a]=="function"&&(this[a]=()=>{throw new Error("PHP runtime has crashed – see the earlier error for details.")});this.functionsMaybeMissingFromAsyncify=getFunctionsMaybeMissingFromAsyncify();const o=n,p="betterMessage"in o?o.betterMessage:o.message,l=new Error(p);throw l.cause=o,logger.logger.error(l),l}finally{(i=c(this,w))==null||i.removeEventListener("error",e)}const{headers:r,httpStatusCode:s}=d(this,C,K).call(this);return new PHPResponse(t===0?s:500,r,this.readFileAsBuffer("/internal/stdout"),this.readFileAsText("/internal/stderr"),t)};function normalizeHeaders(t){const e={};for(const r in t)e[r.toLowerCase()]=t[r];return e}function copyFS(t,e,r){let s;try{s=t.lookupPath(r)}catch{return}if(!("contents"in s.node))return;if(!t.isDir(s.node.mode)){e.writeFile(r,t.readFile(r));return}e.mkdirTree(r);const i=t.readdir(r).filter(n=>n!=="."&&n!=="..");for(const n of i)copyFS(t,e,util.joinPaths(r,n))}async function getPhpIniEntries(t,e){const r=ini.parse(await t.readFileAsText(PHP_INI_PATH));if(e===void 0)return r;const s={};for(const i of e)s[i]=r[i];return s}async function setPhpIniEntries(t,e){const r=ini.parse(await t.readFileAsText(PHP_INI_PATH));for(const[s,i]of Object.entries(e))i==null?delete r[s]:r[s]=i;await t.writeFile(PHP_INI_PATH,ini.stringify(r))}async function withPHPIniValues(t,e,r){const s=await t.readFileAsText(PHP_INI_PATH);try{return await setPhpIniEntries(t,e),await r()}finally{await t.writeFile(PHP_INI_PATH,s)}}class HttpCookieStore{constructor(){this.cookies={}}rememberCookiesFromResponseHeaders(e){if(e!=null&&e["set-cookie"])for(const r of e["set-cookie"])try{if(!r.includes("="))continue;const s=r.indexOf("="),i=r.substring(0,s),n=r.substring(s+1).split(";")[0];this.cookies[i]=n}catch(s){logger.logger.error(s)}}getCookieRequestHeader(){const e=[];for(const r in this.cookies)e.push(`${r}=${this.cookies[r]}`);return e.join("; ")}}function streamReadFileFromPHP(t,e){return new ReadableStream({async pull(r){const s=await t.readFileAsBuffer(e);r.enqueue(s),r.close()}})}async function*iteratePhpFiles(t,e,{relativePaths:r=!0,pathPrefix:s,exceptPaths:i=[]}={}){e=util.normalizePath(e);const n=[e];for(;n.length;){const o=n.pop();if(!o)return;const p=await t.listFiles(o);for(const l of p){const a=`${o}/${l}`;if(i.includes(a.substring(e.length+1)))continue;await t.isDir(a)?n.push(a):yield new streamCompression.StreamedFile(streamReadFileFromPHP(t,a),r?util.joinPaths(s||"",a.substring(e.length+1)):a)}}}function writeFilesStreamToPhp(t,e){return new WritableStream({async write(r){const s=util.joinPaths(e,r.name);r.type==="directory"?await t.mkdir(s):(await t.mkdir(util.dirname(s)),await t.writeFile(s,new Uint8Array(await r.arrayBuffer())))}})}class MaxPhpInstancesError extends Error{constructor(e){super(`Requested more concurrent PHP instances than the limit (${e}).`),this.name=this.constructor.name}}class PHPProcessManager{constructor(e){this.primaryIdle=!0,this.nextInstance=null,this.allInstances=[],this.maxPhpInstances=(e==null?void 0:e.maxPhpInstances)??5,this.phpFactory=e==null?void 0:e.phpFactory,this.primaryPhp=e==null?void 0:e.primaryPhp,this.semaphore=new util.Semaphore({concurrency:this.maxPhpInstances,timeout:(e==null?void 0:e.timeout)||5e3})}async getPrimaryPhp(){if(!this.phpFactory&&!this.primaryPhp)throw new Error("phpFactory or primaryPhp must be set before calling getPrimaryPhp().");if(!this.primaryPhp){const e=await this.spawn({isPrimary:!0});this.primaryPhp=e.php}return this.primaryPhp}async acquirePHPInstance(){if(this.primaryIdle)return this.primaryIdle=!1,{php:await this.getPrimaryPhp(),reap:()=>this.primaryIdle=!0};const e=this.nextInstance||this.spawn({isPrimary:!1});return this.semaphore.remaining>0?this.nextInstance=this.spawn({isPrimary:!1}):this.nextInstance=null,await e}spawn(e){if(e.isPrimary&&this.allInstances.length>0)throw new Error("Requested spawning a primary PHP instance when another primary instance already started spawning.");const r=this.doSpawn(e);this.allInstances.push(r);const s=()=>{this.allInstances=this.allInstances.filter(i=>i!==r)};return r.catch(i=>{throw s(),i}).then(i=>({...i,reap:()=>{s(),i.reap()}}))}async doSpawn(e){let r;try{r=await this.semaphore.acquire()}catch(s){throw s instanceof util.AcquireTimeoutError?new MaxPhpInstancesError(this.maxPhpInstances):s}try{const s=await this.phpFactory(e);return{php:s,reap(){s.exit(),r()}}}catch(s){throw r(),s}}async[Symbol.asyncDispose](){this.primaryPhp&&this.primaryPhp.exit(),await Promise.all(this.allInstances.map(e=>e.then(({reap:r})=>r())))}}const SupportedPHPVersions=["8.3","8.2","8.1","8.0","7.4","7.3","7.2","7.1","7.0"],LatestSupportedPHPVersion=SupportedPHPVersions[0],SupportedPHPVersionsList=SupportedPHPVersions,SupportedPHPExtensionsList=["iconv","mbstring","xml-bundle","gd"],SupportedPHPExtensionBundles={"kitchen-sink":SupportedPHPExtensionsList,light:[]},DEFAULT_BASE_URL="http://example.com";function toRelativeUrl(t){return t.toString().substring(t.origin.length)}function removePathPrefix(t,e){return!e||!t.startsWith(e)?t:t.substring(e.length)}function ensurePathPrefix(t,e){return!e||t.startsWith(e)?t:e+t}async function encodeAsMultipart(t){const e=`----${Math.random().toString(36).slice(2)}`,r=`multipart/form-data; boundary=${e}`,s=new TextEncoder,i=[];for(const[l,a]of Object.entries(t))i.push(`--${e}\r
|
|
51
|
-
`),i.push(`Content-Disposition: form-data; name="${l}"`),
|
|
52
|
-
`),
|
|
50
|
+
`),e.onMessage=async r=>{for(const s of p(this,E)){const i=await s(r);if(i)return i}return""},h(this,P,improveWASMErrorReporting(e)),this.dispatchEvent({type:"runtime.initialized"})}async setSapiName(t){if(this[__private__dont__use].ccall("wasm_set_sapi_name",NUMBER,[STRING],[t])!==0)throw new Error("Could not set SAPI name. This can only be done before the PHP WASM module is initialized.Did you already dispatch any requests?");h(this,x,t)}chdir(t){this[__private__dont__use].FS.chdir(t)}async request(t){if(logger.logger.warn("PHP.request() is deprecated. Please use new PHPRequestHandler() instead."),!this.requestHandler)throw new Error("No request handler available.");return this.requestHandler.request(t)}async run(t){const e=await this.semaphore.acquire();let r;try{if(p(this,g)||(d(this,I,Y).call(this),h(this,g,!0)),t.scriptPath&&!this.fileExists(t.scriptPath))throw new Error(`The script path "${t.scriptPath}" does not exist.`);d(this,A,K).call(this,t.relativeUri||""),d(this,j,te).call(this,t.method||"GET");const s=normalizeHeaders(t.headers||{}),i=s.host||"example.com:443",n=d(this,U,ee).call(this,i,t.protocol||"http");d(this,N,X).call(this,i),d(this,M,Q).call(this,n),d(this,L,re).call(this,s),t.body&&(r=d(this,q,se).call(this,t.body)),typeof t.code=="string"?(this.writeFile("/internal/eval.php",t.code),d(this,b,G).call(this,"/internal/eval.php")):d(this,b,G).call(this,t.scriptPath||"");const o=d(this,k,J).call(this,t.$_SERVER,s,n);for(const c in o)d(this,$,ie).call(this,c,o[c]);const a=t.env||{};for(const c in a)d(this,B,ne).call(this,c,a[c]);const l=await d(this,O,oe).call(this);if(l.exitCode!==0){logger.logger.warn("PHP.run() output was:",l.text);const c=new PHPExecutionFailureError(`PHP.run() failed with exit code ${l.exitCode} and the following output: `+l.errors,l,"request");throw logger.logger.error(c),c}return l}catch(s){throw this.dispatchEvent({type:"request.error",error:s,source:s.source??"php-wasm"}),s}finally{try{r&&this[__private__dont__use].free(r)}finally{e(),this.dispatchEvent({type:"request.end"})}}}defineConstant(t,e){let r={};try{r=JSON.parse(this.fileExists("/internal/shared/consts.json")&&this.readFileAsText("/internal/shared/consts.json")||"{}")}catch{}this.writeFile("/internal/shared/consts.json",JSON.stringify({...r,[t]:e}))}mkdir(t){return FSHelpers.mkdir(this[__private__dont__use].FS,t)}mkdirTree(t){return FSHelpers.mkdir(this[__private__dont__use].FS,t)}readFileAsText(t){return FSHelpers.readFileAsText(this[__private__dont__use].FS,t)}readFileAsBuffer(t){return FSHelpers.readFileAsBuffer(this[__private__dont__use].FS,t)}writeFile(t,e){return FSHelpers.writeFile(this[__private__dont__use].FS,t,e)}unlink(t){return FSHelpers.unlink(this[__private__dont__use].FS,t)}mv(t,e){return FSHelpers.mv(this[__private__dont__use].FS,t,e)}rmdir(t,e={recursive:!0}){return FSHelpers.rmdir(this[__private__dont__use].FS,t,e)}listFiles(t,e={prependPath:!1}){return FSHelpers.listFiles(this[__private__dont__use].FS,t,e)}isDir(t){return FSHelpers.isDir(this[__private__dont__use].FS,t)}isFile(t){return FSHelpers.isFile(this[__private__dont__use].FS,t)}fileExists(t){return FSHelpers.fileExists(this[__private__dont__use].FS,t)}hotSwapPHPRuntime(t,e){const r=this[__private__dont__use].FS;try{this.exit()}catch{}this.initializeRuntime(t),p(this,x)&&this.setSapiName(p(this,x)),e&©FS(r,this[__private__dont__use].FS,e)}async mount(t,e){return await e(this,this[__private__dont__use].FS,t)}async cli(t){for(const e of t)this[__private__dont__use].ccall("wasm_add_cli_arg",null,[STRING],[e]);try{return await this[__private__dont__use].ccall("run_cli",null,[],[],{async:!0})}catch(e){if(isExitCodeZero(e))return 0;throw e}}setSkipShebang(t){this[__private__dont__use].ccall("wasm_set_skip_shebang",null,[NUMBER],[t?1:0])}exit(t=0){this.dispatchEvent({type:"runtime.beforedestroy"});try{this[__private__dont__use]._exit(t)}catch{}h(this,g,!1),h(this,P,null),delete this[__private__dont__use].onMessage,delete this[__private__dont__use]}[Symbol.dispose](){p(this,g)&&this.exit(0)}}x=new WeakMap,g=new WeakMap,P=new WeakMap,_=new WeakMap,E=new WeakMap,k=new WeakSet,J=function(t,e,r){const s={...t||{}};s.HTTPS=s.HTTPS||r===443?"on":"off";for(const i in e){let n="HTTP_";["content-type","content-length"].includes(i.toLowerCase())&&(n=""),s[`${n}${i.toUpperCase().replace(/-/g,"_")}`]=e[i]}return s},I=new WeakSet,Y=function(){this[__private__dont__use].ccall("php_wasm_init",null,[],[])},C=new WeakSet,Z=function(){const t="/internal/headers.json";if(!this.fileExists(t))throw new Error("SAPI Error: Could not find response headers file.");const e=JSON.parse(this.readFileAsText(t)),r={};for(const s of e.headers){if(!s.includes(": "))continue;const i=s.indexOf(": "),n=s.substring(0,i).toLowerCase(),o=s.substring(i+2);n in r||(r[n]=[]),r[n].push(o)}return{headers:r,httpStatusCode:e.status}},A=new WeakSet,K=function(t){if(this[__private__dont__use].ccall("wasm_set_request_uri",null,[STRING],[t]),t.includes("?")){const e=t.substring(t.indexOf("?")+1);this[__private__dont__use].ccall("wasm_set_query_string",null,[STRING],[e])}},N=new WeakSet,X=function(t){this[__private__dont__use].ccall("wasm_set_request_host",null,[STRING],[t])},M=new WeakSet,Q=function(t){this[__private__dont__use].ccall("wasm_set_request_port",null,[NUMBER],[t])},U=new WeakSet,ee=function(t,e){let r;try{r=parseInt(new URL(t).port,10)}catch{}return(!r||isNaN(r)||r===80)&&(r=e==="https"?443:80),r},j=new WeakSet,te=function(t){this[__private__dont__use].ccall("wasm_set_request_method",null,[STRING],[t])},L=new WeakSet,re=function(t){t.cookie&&this[__private__dont__use].ccall("wasm_set_cookies",null,[STRING],[t.cookie]),t["content-type"]&&this[__private__dont__use].ccall("wasm_set_content_type",null,[STRING],[t["content-type"]]),t["content-length"]&&this[__private__dont__use].ccall("wasm_set_content_length",null,[NUMBER],[parseInt(t["content-length"],10)])},q=new WeakSet,se=function(t){let e,r;typeof t=="string"?(logger.logger.warn("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"),r=this[__private__dont__use].lengthBytesUTF8(t),e=r+1):(r=t.byteLength,e=t.byteLength);const s=this[__private__dont__use].malloc(e);if(!s)throw new Error("Could not allocate memory for the request body.");return typeof t=="string"?this[__private__dont__use].stringToUTF8(t,s,e+1):this[__private__dont__use].HEAPU8.set(t,s),this[__private__dont__use].ccall("wasm_set_request_body",null,[NUMBER],[s]),this[__private__dont__use].ccall("wasm_set_content_length",null,[NUMBER],[r]),s},b=new WeakSet,G=function(t){this[__private__dont__use].ccall("wasm_set_path_translated",null,[STRING],[t])},$=new WeakSet,ie=function(t,e){this[__private__dont__use].ccall("wasm_add_SERVER_entry",null,[STRING,STRING],[t,e])},B=new WeakSet,ne=function(t,e){this[__private__dont__use].ccall("wasm_add_ENV_entry",null,[STRING,STRING],[t,e])},O=new WeakSet,oe=async function(){var i;let t,e;try{t=await new Promise((n,o)=>{var l;e=c=>{logger.logger.error(c),logger.logger.error(c.error);const y=new Error("Rethrown");y.cause=c.error,y.betterMessage=c.message,o(y)},(l=p(this,P))==null||l.addEventListener("error",e);const a=this[__private__dont__use].ccall("wasm_sapi_handle_request",NUMBER,[],[],{async:!0});return a instanceof Promise?a.then(n,o):n(a)})}catch(n){for(const c in this)typeof this[c]=="function"&&(this[c]=()=>{throw new Error("PHP runtime has crashed – see the earlier error for details.")});this.functionsMaybeMissingFromAsyncify=getFunctionsMaybeMissingFromAsyncify();const o=n,a="betterMessage"in o?o.betterMessage:o.message,l=new Error(a);throw l.cause=o,logger.logger.error(l),l}finally{(i=p(this,P))==null||i.removeEventListener("error",e)}const{headers:r,httpStatusCode:s}=d(this,C,Z).call(this);return new PHPResponse(t===0?s:500,r,this.readFileAsBuffer("/internal/stdout"),this.readFileAsText("/internal/stderr"),t)};function normalizeHeaders(t){const e={};for(const r in t)e[r.toLowerCase()]=t[r];return e}function copyFS(t,e,r){let s;try{s=t.lookupPath(r)}catch{return}if(!("contents"in s.node))return;if(!t.isDir(s.node.mode)){e.writeFile(r,t.readFile(r));return}e.mkdirTree(r);const i=t.readdir(r).filter(n=>n!=="."&&n!=="..");for(const n of i)copyFS(t,e,util.joinPaths(r,n))}async function getPhpIniEntries(t,e){const r=ini.parse(await t.readFileAsText(PHP_INI_PATH));if(e===void 0)return r;const s={};for(const i of e)s[i]=r[i];return s}async function setPhpIniEntries(t,e){const r=ini.parse(await t.readFileAsText(PHP_INI_PATH));for(const[s,i]of Object.entries(e))i==null?delete r[s]:r[s]=i;await t.writeFile(PHP_INI_PATH,ini.stringify(r))}async function withPHPIniValues(t,e,r){const s=await t.readFileAsText(PHP_INI_PATH);try{return await setPhpIniEntries(t,e),await r()}finally{await t.writeFile(PHP_INI_PATH,s)}}class HttpCookieStore{constructor(){this.cookies={}}rememberCookiesFromResponseHeaders(e){if(e!=null&&e["set-cookie"])for(const r of e["set-cookie"])try{if(!r.includes("="))continue;const s=r.indexOf("="),i=r.substring(0,s),n=r.substring(s+1).split(";")[0];this.cookies[i]=n}catch(s){logger.logger.error(s)}}getCookieRequestHeader(){const e=[];for(const r in this.cookies)e.push(`${r}=${this.cookies[r]}`);return e.join("; ")}}function streamReadFileFromPHP(t,e){return new ReadableStream({async pull(r){const s=await t.readFileAsBuffer(e);r.enqueue(s),r.close()}})}async function*iteratePhpFiles(t,e,{relativePaths:r=!0,pathPrefix:s,exceptPaths:i=[]}={}){e=util.normalizePath(e);const n=[e];for(;n.length;){const o=n.pop();if(!o)return;const a=await t.listFiles(o);for(const l of a){const c=`${o}/${l}`;if(i.includes(c.substring(e.length+1)))continue;await t.isDir(c)?n.push(c):yield new streamCompression.StreamedFile(streamReadFileFromPHP(t,c),r?util.joinPaths(s||"",c.substring(e.length+1)):c)}}}function writeFilesStreamToPhp(t,e){return new WritableStream({async write(r){const s=util.joinPaths(e,r.name);r.type==="directory"?await t.mkdir(s):(await t.mkdir(util.dirname(s)),await t.writeFile(s,new Uint8Array(await r.arrayBuffer())))}})}class MaxPhpInstancesError extends Error{constructor(e){super(`Requested more concurrent PHP instances than the limit (${e}).`),this.name=this.constructor.name}}class PHPProcessManager{constructor(e){this.primaryIdle=!0,this.nextInstance=null,this.allInstances=[],this.maxPhpInstances=(e==null?void 0:e.maxPhpInstances)??5,this.phpFactory=e==null?void 0:e.phpFactory,this.primaryPhp=e==null?void 0:e.primaryPhp,this.semaphore=new util.Semaphore({concurrency:this.maxPhpInstances,timeout:(e==null?void 0:e.timeout)||5e3})}async getPrimaryPhp(){if(!this.phpFactory&&!this.primaryPhp)throw new Error("phpFactory or primaryPhp must be set before calling getPrimaryPhp().");if(!this.primaryPhp){const e=await this.spawn({isPrimary:!0});this.primaryPhp=e.php}return this.primaryPhp}async acquirePHPInstance(){if(this.primaryIdle)return this.primaryIdle=!1,{php:await this.getPrimaryPhp(),reap:()=>this.primaryIdle=!0};const e=this.nextInstance||this.spawn({isPrimary:!1});return this.semaphore.remaining>0?this.nextInstance=this.spawn({isPrimary:!1}):this.nextInstance=null,await e}spawn(e){if(e.isPrimary&&this.allInstances.length>0)throw new Error("Requested spawning a primary PHP instance when another primary instance already started spawning.");const r=this.doSpawn(e);this.allInstances.push(r);const s=()=>{this.allInstances=this.allInstances.filter(i=>i!==r)};return r.catch(i=>{throw s(),i}).then(i=>({...i,reap:()=>{s(),i.reap()}}))}async doSpawn(e){let r;try{r=await this.semaphore.acquire()}catch(s){throw s instanceof util.AcquireTimeoutError?new MaxPhpInstancesError(this.maxPhpInstances):s}try{const s=await this.phpFactory(e);return{php:s,reap(){s.exit(),r()}}}catch(s){throw r(),s}}async[Symbol.asyncDispose](){this.primaryPhp&&this.primaryPhp.exit(),await Promise.all(this.allInstances.map(e=>e.then(({reap:r})=>r())))}}const SupportedPHPVersions=["8.3","8.2","8.1","8.0","7.4","7.3","7.2","7.1","7.0"],LatestSupportedPHPVersion=SupportedPHPVersions[0],SupportedPHPVersionsList=SupportedPHPVersions,SupportedPHPExtensionsList=["iconv","mbstring","xml-bundle","gd"],SupportedPHPExtensionBundles={"kitchen-sink":SupportedPHPExtensionsList,light:[]},DEFAULT_BASE_URL="http://example.com";function toRelativeUrl(t){return t.toString().substring(t.origin.length)}function removePathPrefix(t,e){return!e||!t.startsWith(e)?t:t.substring(e.length)}function ensurePathPrefix(t,e){return!e||t.startsWith(e)?t:e+t}async function encodeAsMultipart(t){const e=`----${Math.random().toString(36).slice(2)}`,r=`multipart/form-data; boundary=${e}`,s=new TextEncoder,i=[];for(const[l,c]of Object.entries(t))i.push(`--${e}\r
|
|
51
|
+
`),i.push(`Content-Disposition: form-data; name="${l}"`),c instanceof File&&i.push(`; filename="${c.name}"`),i.push(`\r
|
|
52
|
+
`),c instanceof File&&(i.push("Content-Type: application/octet-stream"),i.push(`\r
|
|
53
53
|
`)),i.push(`\r
|
|
54
|
-
`),
|
|
54
|
+
`),c instanceof File?i.push(await fileToUint8Array(c)):i.push(c),i.push(`\r
|
|
55
55
|
`);i.push(`--${e}--\r
|
|
56
|
-
`);const n=i.reduce((l,
|
|
56
|
+
`);const n=i.reduce((l,c)=>l+c.length,0),o=new Uint8Array(n);let a=0;for(const l of i)o.set(typeof l=="string"?s.encode(l):l,a),a+=l.length;return{bytes:o,contentType:r}}function fileToUint8Array(t){return new Promise(e=>{const r=new FileReader;r.onload=()=>{e(new Uint8Array(r.result))},r.readAsArrayBuffer(t)})}const _default="application/octet-stream",asx="video/x-ms-asf",atom="application/atom+xml",avi="video/x-msvideo",avif="image/avif",bin="application/octet-stream",bmp="image/x-ms-bmp",cco="application/x-cocoa",css="text/css",data="application/octet-stream",deb="application/octet-stream",der="application/x-x509-ca-cert",dmg="application/octet-stream",doc="application/msword",docx="application/vnd.openxmlformats-officedocument.wordprocessingml.document",eot="application/vnd.ms-fontobject",flv="video/x-flv",gif="image/gif",gz="application/gzip",hqx="application/mac-binhex40",htc="text/x-component",html="text/html",ico="image/x-icon",iso="application/octet-stream",jad="text/vnd.sun.j2me.app-descriptor",jar="application/java-archive",jardiff="application/x-java-archive-diff",jng="image/x-jng",jnlp="application/x-java-jnlp-file",jpg="image/jpeg",jpeg="image/jpeg",js="application/javascript",json="application/json",kml="application/vnd.google-earth.kml+xml",kmz="application/vnd.google-earth.kmz",m3u8="application/vnd.apple.mpegurl",m4a="audio/x-m4a",m4v="video/x-m4v",md="text/plain",mid="audio/midi",mml="text/mathml",mng="video/x-mng",mov="video/quicktime",mp3="audio/mpeg",mp4="video/mp4",mpeg="video/mpeg",msi="application/octet-stream",odg="application/vnd.oasis.opendocument.graphics",odp="application/vnd.oasis.opendocument.presentation",ods="application/vnd.oasis.opendocument.spreadsheet",odt="application/vnd.oasis.opendocument.text",ogg="audio/ogg",otf="font/otf",pdf="application/pdf",pl="application/x-perl",png="image/png",ppt="application/vnd.ms-powerpoint",pptx="application/vnd.openxmlformats-officedocument.presentationml.presentation",prc="application/x-pilot",ps="application/postscript",ra="audio/x-realaudio",rar="application/x-rar-compressed",rpm="application/x-redhat-package-manager",rss="application/rss+xml",rtf="application/rtf",run="application/x-makeself",sea="application/x-sea",sit="application/x-stuffit",svg="image/svg+xml",swf="application/x-shockwave-flash",tcl="application/x-tcl",tar="application/x-tar",tif="image/tiff",ts="video/mp2t",ttf="font/ttf",txt="text/plain",wasm="application/wasm",wbmp="image/vnd.wap.wbmp",webm="video/webm",webp="image/webp",wml="text/vnd.wap.wml",wmlc="application/vnd.wap.wmlc",wmv="video/x-ms-wmv",woff="font/woff",woff2="font/woff2",xhtml="application/xhtml+xml",xls="application/vnd.ms-excel",xlsx="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",xml="text/xml",xpi="application/x-xpinstall",xspf="application/xspf+xml",zip="application/zip",mimeTypes={_default,"3gpp":"video/3gpp","7z":"application/x-7z-compressed",asx,atom,avi,avif,bin,bmp,cco,css,data,deb,der,dmg,doc,docx,eot,flv,gif,gz,hqx,htc,html,ico,iso,jad,jar,jardiff,jng,jnlp,jpg,jpeg,js,json,kml,kmz,m3u8,m4a,m4v,md,mid,mml,mng,mov,mp3,mp4,mpeg,msi,odg,odp,ods,odt,ogg,otf,pdf,pl,png,ppt,pptx,prc,ps,ra,rar,rpm,rss,rtf,run,sea,sit,svg,swf,tcl,tar,tif,ts,ttf,txt,wasm,wbmp,webm,webp,wml,wmlc,wmv,woff,woff2,xhtml,xls,xlsx,xml,xpi,xspf,zip};var w,R,T,v,F,f,H,S,D,ae,z,le,W,ce;class PHPRequestHandler{constructor(e){u(this,D);u(this,z);u(this,W);u(this,w,void 0);u(this,R,void 0);u(this,T,void 0);u(this,v,void 0);u(this,F,void 0);u(this,f,void 0);u(this,H,void 0);u(this,S,void 0);const{documentRoot:r="/www/",absoluteUrl:s=typeof location=="object"?location==null?void 0:location.href:"",rewriteRules:i=[],getFileNotFoundAction:n=()=>({type:"404"})}=e;"processManager"in e?this.processManager=e.processManager:this.processManager=new PHPProcessManager({phpFactory:async l=>{const c=await e.phpFactory({...l,requestHandler:this});return c.requestHandler=this,c},maxPhpInstances:e.maxPhpInstances}),h(this,S,new HttpCookieStore),h(this,w,r);const o=new URL(s);h(this,T,o.hostname),h(this,v,o.port?Number(o.port):o.protocol==="https:"?443:80),h(this,R,(o.protocol||"").replace(":",""));const a=p(this,v)!==443&&p(this,v)!==80;h(this,F,[p(this,T),a?`:${p(this,v)}`:""].join("")),h(this,f,o.pathname.replace(/\/+$/,"")),h(this,H,[`${p(this,R)}://`,p(this,F),p(this,f)].join("")),this.rewriteRules=i,this.getFileNotFoundAction=n}async getPrimaryPhp(){return await this.processManager.getPrimaryPhp()}pathToInternalUrl(e){return`${this.absoluteUrl}${e}`}internalUrlToPath(e){const r=new URL(e);return r.pathname.startsWith(p(this,f))&&(r.pathname=r.pathname.slice(p(this,f).length)),toRelativeUrl(r)}get absoluteUrl(){return p(this,H)}get documentRoot(){return p(this,w)}async request(e){const r=e.url.startsWith("http://")||e.url.startsWith("https://"),s=new URL(e.url.split("#")[0],r?void 0:DEFAULT_BASE_URL),i=applyRewriteRules(removePathPrefix(decodeURIComponent(s.pathname),p(this,f)),this.rewriteRules),n=await this.getPrimaryPhp();let o=util.joinPaths(p(this,w),i);if(n.isDir(o)){if(!o.endsWith("/"))return new PHPResponse(301,{Location:[`${s.pathname}/`]},new Uint8Array(0));for(const a of["index.php","index.html"]){const l=util.joinPaths(o,a);if(n.isFile(l)){o=l;break}}}if(!n.isFile(o)){const a=this.getFileNotFoundAction(i);switch(a.type){case"response":return a.response;case"internal-redirect":o=util.joinPaths(p(this,w),a.uri);break;case"404":return PHPResponse.forHttpCode(404);default:throw new Error(`Unsupported file-not-found action type: '${a.type}'`)}}if(n.isFile(o))if(o.endsWith(".php")){const a={...e,url:s.toString()};return d(this,z,le).call(this,a,o)}else return d(this,D,ae).call(this,n,o);else return PHPResponse.forHttpCode(404)}}w=new WeakMap,R=new WeakMap,T=new WeakMap,v=new WeakMap,F=new WeakMap,f=new WeakMap,H=new WeakMap,S=new WeakMap,D=new WeakSet,ae=function(e,r){const s=e.readFileAsBuffer(r);return new PHPResponse(200,{"content-length":[`${s.byteLength}`],"content-type":[inferMimeType(r)],"accept-ranges":["bytes"],"cache-control":["public, max-age=0"]},s)},z=new WeakSet,le=async function(e,r){let s;try{s=await this.processManager.acquirePHPInstance()}catch(i){return i instanceof MaxPhpInstancesError?PHPResponse.forHttpCode(502):PHPResponse.forHttpCode(500)}try{return await d(this,W,ce).call(this,s.php,e,r)}finally{s.reap()}},W=new WeakSet,ce=async function(e,r,s){let i="GET";const n={host:p(this,F),...normalizeHeaders(r.headers||{}),cookie:p(this,S).getCookieRequestHeader()};let o=r.body;if(typeof o=="object"&&!(o instanceof Uint8Array)){i="POST";const{bytes:a,contentType:l}=await encodeAsMultipart(o);o=a,n["content-type"]=l}try{const a=await e.run({relativeUri:ensurePathPrefix(toRelativeUrl(new URL(r.url)),p(this,f)),protocol:p(this,R),method:r.method||i,$_SERVER:{REMOTE_ADDR:"127.0.0.1",DOCUMENT_ROOT:p(this,w),HTTPS:p(this,H).startsWith("https://")?"on":""},body:o,scriptPath:s,headers:n});return p(this,S).rememberCookiesFromResponseHeaders(a.headers),a}catch(a){const l=a;if(l!=null&&l.response)return l.response;throw a}};function inferMimeType(t){const e=t.split(".").pop();return mimeTypes[e]||mimeTypes._default}function applyRewriteRules(t,e){for(const r of e)if(new RegExp(r.match).test(t))return t.replace(r.match,r.replacement);return t}function rotatePHPRuntime({php:t,cwd:e,recreateRuntime:r,maxRequests:s=400}){let i=0;async function n(){if(++i<s)return;i=0;const o=await t.semaphore.acquire();try{t.hotSwapPHPRuntime(await r(),e)}finally{o()}}return t.addEventListener("request.end",n),function(){t.removeEventListener("request.end",n)}}async function writeFiles(t,e,r,{rmRoot:s=!1}={}){s&&await t.isDir(e)&&await t.rmdir(e,{recursive:!0});for(const[i,n]of Object.entries(r)){const o=util.joinPaths(e,i);await t.fileExists(util.dirname(o))||await t.mkdir(util.dirname(o)),n instanceof Uint8Array||typeof n=="string"?await t.writeFile(o,n):await writeFiles(t,o,n)}}function proxyFileSystem(t,e,r){const s=Object.getOwnPropertySymbols(t)[0];for(const i of r)e.fileExists(i)||e.mkdir(i),t.fileExists(i)||t.mkdir(i),e[s].FS.mount(e[s].PROXYFS,{root:i,fs:t[s].FS},i)}exports.DEFAULT_BASE_URL=DEFAULT_BASE_URL;exports.FSHelpers=FSHelpers;exports.HttpCookieStore=HttpCookieStore;exports.LatestSupportedPHPVersion=LatestSupportedPHPVersion;exports.PHP=PHP;exports.PHPProcessManager=PHPProcessManager;exports.PHPRequestHandler=PHPRequestHandler;exports.PHPResponse=PHPResponse;exports.PHPWorker=PHPWorker;exports.SupportedPHPExtensionBundles=SupportedPHPExtensionBundles;exports.SupportedPHPExtensionsList=SupportedPHPExtensionsList;exports.SupportedPHPVersions=SupportedPHPVersions;exports.SupportedPHPVersionsList=SupportedPHPVersionsList;exports.UnhandledRejectionsTarget=UnhandledRejectionsTarget;exports.__private__dont__use=__private__dont__use;exports.applyRewriteRules=applyRewriteRules;exports.ensurePathPrefix=ensurePathPrefix;exports.getPhpIniEntries=getPhpIniEntries;exports.isExitCodeZero=isExitCodeZero;exports.iterateFiles=iteratePhpFiles;exports.loadPHPRuntime=loadPHPRuntime;exports.proxyFileSystem=proxyFileSystem;exports.removePathPrefix=removePathPrefix;exports.rotatePHPRuntime=rotatePHPRuntime;exports.setPhpIniEntries=setPhpIniEntries;exports.toRelativeUrl=toRelativeUrl;exports.withPHPIniValues=withPHPIniValues;exports.writeFiles=writeFiles;exports.writeFilesStreamToPhp=writeFilesStreamToPhp;
|
package/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
var
|
|
1
|
+
var G = (t, e, r) => {
|
|
2
2
|
if (!e.has(t))
|
|
3
3
|
throw TypeError("Cannot " + r);
|
|
4
4
|
};
|
|
5
|
-
var
|
|
5
|
+
var p = (t, e, r) => (G(t, e, "read from private field"), r ? r.call(t) : e.get(t)), u = (t, e, r) => {
|
|
6
6
|
if (e.has(t))
|
|
7
7
|
throw TypeError("Cannot add the same private member more than once");
|
|
8
8
|
e instanceof WeakSet ? e.add(t) : e.set(t, r);
|
|
9
|
-
}, h = (t, e, r, s) => (
|
|
10
|
-
var d = (t, e, r) => (
|
|
9
|
+
}, h = (t, e, r, s) => (G(t, e, "write to private field"), s ? s.call(t, r) : e.set(t, r), r);
|
|
10
|
+
var d = (t, e, r) => (G(t, e, "access private method"), r);
|
|
11
11
|
import "@php-wasm/node-polyfills";
|
|
12
12
|
import { logger } from "@php-wasm/logger";
|
|
13
13
|
import { dirname, joinPaths, Semaphore, createSpawnHandler, normalizePath, AcquireTimeoutError } from "@php-wasm/util";
|
|
@@ -103,15 +103,15 @@ function rethrowFileSystemError(t = "") {
|
|
|
103
103
|
i.value = function(...o) {
|
|
104
104
|
try {
|
|
105
105
|
return n.apply(this, o);
|
|
106
|
-
} catch (
|
|
107
|
-
const l = typeof
|
|
106
|
+
} catch (a) {
|
|
107
|
+
const l = typeof a == "object" ? a == null ? void 0 : a.errno : null;
|
|
108
108
|
if (l in FileErrorCodes) {
|
|
109
|
-
const
|
|
110
|
-
throw new Error(`${
|
|
111
|
-
cause:
|
|
109
|
+
const c = FileErrorCodes[l], y = typeof o[1] == "string" ? o[1] : null, pe = y !== null ? t.replaceAll("{path}", y) : t;
|
|
110
|
+
throw new Error(`${pe}: ${c}`, {
|
|
111
|
+
cause: a
|
|
112
112
|
});
|
|
113
113
|
}
|
|
114
|
-
throw
|
|
114
|
+
throw a;
|
|
115
115
|
}
|
|
116
116
|
};
|
|
117
117
|
};
|
|
@@ -180,6 +180,15 @@ const _FSHelpers = class m {
|
|
|
180
180
|
static isDir(e, r) {
|
|
181
181
|
return m.fileExists(e, r) ? e.isDir(e.lookupPath(r).node.mode) : !1;
|
|
182
182
|
}
|
|
183
|
+
/**
|
|
184
|
+
* Checks if a file exists in the PHP filesystem.
|
|
185
|
+
*
|
|
186
|
+
* @param path – The path to check.
|
|
187
|
+
* @returns True if the path is a file, false otherwise.
|
|
188
|
+
*/
|
|
189
|
+
static isFile(e, r) {
|
|
190
|
+
return m.fileExists(e, r) ? e.isFile(e.lookupPath(r).node.mode) : !1;
|
|
191
|
+
}
|
|
183
192
|
static fileExists(e, r) {
|
|
184
193
|
try {
|
|
185
194
|
return e.lookupPath(r), !0;
|
|
@@ -344,6 +353,10 @@ class PHPWorker {
|
|
|
344
353
|
isDir(e) {
|
|
345
354
|
return _private.get(this).php.isDir(e);
|
|
346
355
|
}
|
|
356
|
+
/** @inheritDoc @php-wasm/universal!/PHP.isFile */
|
|
357
|
+
isFile(e) {
|
|
358
|
+
return _private.get(this).php.isFile(e);
|
|
359
|
+
}
|
|
347
360
|
/** @inheritDoc @php-wasm/universal!/PHP.fileExists */
|
|
348
361
|
fileExists(e) {
|
|
349
362
|
return _private.get(this).php.fileExists(e);
|
|
@@ -428,14 +441,14 @@ const RuntimeId = Symbol("RuntimeId"), loadedRuntimes = /* @__PURE__ */ new Map(
|
|
|
428
441
|
let lastRuntimeId = 0;
|
|
429
442
|
async function loadPHPRuntime(t, e = {}) {
|
|
430
443
|
const [r, s, i] = makePromise(), n = t.init(currentJsRuntime, {
|
|
431
|
-
onAbort(
|
|
432
|
-
i(
|
|
444
|
+
onAbort(a) {
|
|
445
|
+
i(a), logger.error(a);
|
|
433
446
|
},
|
|
434
447
|
ENV: {},
|
|
435
448
|
// Emscripten sometimes prepends a '/' to the path, which
|
|
436
449
|
// breaks vite dev mode. An identity `locateFile` function
|
|
437
450
|
// fixes it.
|
|
438
|
-
locateFile: (
|
|
451
|
+
locateFile: (a) => a,
|
|
439
452
|
...e,
|
|
440
453
|
noInitialRun: !0,
|
|
441
454
|
onRuntimeInitialized() {
|
|
@@ -444,8 +457,8 @@ async function loadPHPRuntime(t, e = {}) {
|
|
|
444
457
|
});
|
|
445
458
|
await r;
|
|
446
459
|
const o = ++lastRuntimeId;
|
|
447
|
-
return n.id = o, n.originalExit = n._exit, n._exit = function(
|
|
448
|
-
return loadedRuntimes.delete(o), n.originalExit(
|
|
460
|
+
return n.id = o, n.originalExit = n._exit, n._exit = function(a) {
|
|
461
|
+
return loadedRuntimes.delete(o), n.originalExit(a);
|
|
449
462
|
}, n[RuntimeId] = o, loadedRuntimes.set(o, n), o;
|
|
450
463
|
}
|
|
451
464
|
function getLoadedRuntime(t) {
|
|
@@ -510,7 +523,7 @@ function improveWASMErrorReporting(t) {
|
|
|
510
523
|
} catch (o) {
|
|
511
524
|
if (!(o instanceof Error))
|
|
512
525
|
throw o;
|
|
513
|
-
const
|
|
526
|
+
const a = clarifyErrorMessage(
|
|
514
527
|
o,
|
|
515
528
|
(n = t.lastAsyncifyStackSource) == null ? void 0 : n.stack
|
|
516
529
|
);
|
|
@@ -518,12 +531,12 @@ function improveWASMErrorReporting(t) {
|
|
|
518
531
|
e.dispatchEvent(
|
|
519
532
|
new ErrorEvent("error", {
|
|
520
533
|
error: o,
|
|
521
|
-
message:
|
|
534
|
+
message: a
|
|
522
535
|
})
|
|
523
536
|
);
|
|
524
537
|
return;
|
|
525
538
|
}
|
|
526
|
-
throw isExitCodeZero(o) || showCriticalErrorBox(
|
|
539
|
+
throw isExitCodeZero(o) || showCriticalErrorBox(a), o;
|
|
527
540
|
}
|
|
528
541
|
};
|
|
529
542
|
}
|
|
@@ -612,7 +625,7 @@ class PHPExecutionFailureError extends Error {
|
|
|
612
625
|
}
|
|
613
626
|
}
|
|
614
627
|
const PHP_INI_PATH = "/internal/shared/php.ini", AUTO_PREPEND_SCRIPT = "/internal/shared/auto_prepend_file.php";
|
|
615
|
-
var x,
|
|
628
|
+
var x, g, P, _, E, k, J, I, Y, C, Z, A, K, N, X, M, Q, j, ee, U, te, L, re, q, se, b, V, $, ie, B, ne, O, oe;
|
|
616
629
|
class PHP {
|
|
617
630
|
/**
|
|
618
631
|
* Initializes a PHP runtime.
|
|
@@ -640,17 +653,17 @@ class PHP {
|
|
|
640
653
|
u(this, j);
|
|
641
654
|
u(this, U);
|
|
642
655
|
u(this, L);
|
|
643
|
-
u(this, $);
|
|
644
|
-
u(this, b);
|
|
645
656
|
u(this, q);
|
|
657
|
+
u(this, b);
|
|
658
|
+
u(this, $);
|
|
646
659
|
u(this, B);
|
|
647
660
|
u(this, O);
|
|
648
661
|
u(this, x, void 0);
|
|
649
|
-
u(this, P, void 0);
|
|
650
|
-
u(this, w, void 0);
|
|
651
662
|
u(this, g, void 0);
|
|
663
|
+
u(this, P, void 0);
|
|
664
|
+
u(this, _, void 0);
|
|
652
665
|
u(this, E, void 0);
|
|
653
|
-
h(this,
|
|
666
|
+
h(this, g, !1), h(this, P, null), h(this, _, /* @__PURE__ */ new Map()), h(this, E, []), this.semaphore = new Semaphore({ concurrency: 1 }), t !== void 0 && this.initializeRuntime(t);
|
|
654
667
|
}
|
|
655
668
|
/**
|
|
656
669
|
* Adds an event listener for a PHP event.
|
|
@@ -658,7 +671,7 @@ class PHP {
|
|
|
658
671
|
* @param listener - The listener function to be called when the event is triggered.
|
|
659
672
|
*/
|
|
660
673
|
addEventListener(t, e) {
|
|
661
|
-
|
|
674
|
+
p(this, _).has(t) || p(this, _).set(t, /* @__PURE__ */ new Set()), p(this, _).get(t).add(e);
|
|
662
675
|
}
|
|
663
676
|
/**
|
|
664
677
|
* Removes an event listener for a PHP event.
|
|
@@ -667,10 +680,10 @@ class PHP {
|
|
|
667
680
|
*/
|
|
668
681
|
removeEventListener(t, e) {
|
|
669
682
|
var r;
|
|
670
|
-
(r =
|
|
683
|
+
(r = p(this, _).get(t)) == null || r.delete(e);
|
|
671
684
|
}
|
|
672
685
|
dispatchEvent(t) {
|
|
673
|
-
const e =
|
|
686
|
+
const e = p(this, _).get(t.type);
|
|
674
687
|
if (e)
|
|
675
688
|
for (const r of e)
|
|
676
689
|
r(t);
|
|
@@ -715,7 +728,7 @@ class PHP {
|
|
|
715
728
|
* @param listener Callback function to handle the message.
|
|
716
729
|
*/
|
|
717
730
|
onMessage(t) {
|
|
718
|
-
|
|
731
|
+
p(this, E).push(t);
|
|
719
732
|
}
|
|
720
733
|
async setSpawnHandler(handler) {
|
|
721
734
|
typeof handler == "string" && (handler = createSpawnHandler(eval(handler))), this[__private__dont__use].spawnProcess = handler;
|
|
@@ -789,13 +802,13 @@ class PHP {
|
|
|
789
802
|
}
|
|
790
803
|
`
|
|
791
804
|
), e.onMessage = async (r) => {
|
|
792
|
-
for (const s of
|
|
805
|
+
for (const s of p(this, E)) {
|
|
793
806
|
const i = await s(r);
|
|
794
807
|
if (i)
|
|
795
808
|
return i;
|
|
796
809
|
}
|
|
797
810
|
return "";
|
|
798
|
-
}, h(this,
|
|
811
|
+
}, h(this, P, improveWASMErrorReporting(e)), this.dispatchEvent({
|
|
799
812
|
type: "runtime.initialized"
|
|
800
813
|
});
|
|
801
814
|
}
|
|
@@ -907,28 +920,28 @@ class PHP {
|
|
|
907
920
|
const e = await this.semaphore.acquire();
|
|
908
921
|
let r;
|
|
909
922
|
try {
|
|
910
|
-
if (
|
|
923
|
+
if (p(this, g) || (d(this, I, Y).call(this), h(this, g, !0)), t.scriptPath && !this.fileExists(t.scriptPath))
|
|
911
924
|
throw new Error(
|
|
912
925
|
`The script path "${t.scriptPath}" does not exist.`
|
|
913
926
|
);
|
|
914
|
-
d(this, A,
|
|
915
|
-
const s = normalizeHeaders(t.headers || {}), i = s.host || "example.com:443", n = d(this, j,
|
|
916
|
-
d(this, N,
|
|
917
|
-
const o = d(this, k,
|
|
918
|
-
for (const
|
|
919
|
-
d(this,
|
|
920
|
-
const
|
|
921
|
-
for (const
|
|
922
|
-
d(this, B,
|
|
923
|
-
const l = await d(this, O,
|
|
927
|
+
d(this, A, K).call(this, t.relativeUri || ""), d(this, U, te).call(this, t.method || "GET");
|
|
928
|
+
const s = normalizeHeaders(t.headers || {}), i = s.host || "example.com:443", n = d(this, j, ee).call(this, i, t.protocol || "http");
|
|
929
|
+
d(this, N, X).call(this, i), d(this, M, Q).call(this, n), d(this, L, re).call(this, s), t.body && (r = d(this, q, se).call(this, t.body)), typeof t.code == "string" ? (this.writeFile("/internal/eval.php", t.code), d(this, b, V).call(this, "/internal/eval.php")) : d(this, b, V).call(this, t.scriptPath || "");
|
|
930
|
+
const o = d(this, k, J).call(this, t.$_SERVER, s, n);
|
|
931
|
+
for (const c in o)
|
|
932
|
+
d(this, $, ie).call(this, c, o[c]);
|
|
933
|
+
const a = t.env || {};
|
|
934
|
+
for (const c in a)
|
|
935
|
+
d(this, B, ne).call(this, c, a[c]);
|
|
936
|
+
const l = await d(this, O, oe).call(this);
|
|
924
937
|
if (l.exitCode !== 0) {
|
|
925
938
|
logger.warn("PHP.run() output was:", l.text);
|
|
926
|
-
const
|
|
939
|
+
const c = new PHPExecutionFailureError(
|
|
927
940
|
`PHP.run() failed with exit code ${l.exitCode} and the following output: ` + l.errors,
|
|
928
941
|
l,
|
|
929
942
|
"request"
|
|
930
943
|
);
|
|
931
|
-
throw logger.error(
|
|
944
|
+
throw logger.error(c), c;
|
|
932
945
|
}
|
|
933
946
|
return l;
|
|
934
947
|
} catch (s) {
|
|
@@ -1066,6 +1079,15 @@ class PHP {
|
|
|
1066
1079
|
isDir(t) {
|
|
1067
1080
|
return FSHelpers.isDir(this[__private__dont__use].FS, t);
|
|
1068
1081
|
}
|
|
1082
|
+
/**
|
|
1083
|
+
* Checks if a file exists in the PHP filesystem.
|
|
1084
|
+
*
|
|
1085
|
+
* @param path – The path to check.
|
|
1086
|
+
* @returns True if the path is a file, false otherwise.
|
|
1087
|
+
*/
|
|
1088
|
+
isFile(t) {
|
|
1089
|
+
return FSHelpers.isFile(this[__private__dont__use].FS, t);
|
|
1090
|
+
}
|
|
1069
1091
|
/**
|
|
1070
1092
|
* Checks if a file (or a directory) exists in the PHP filesystem.
|
|
1071
1093
|
*
|
|
@@ -1091,7 +1113,7 @@ class PHP {
|
|
|
1091
1113
|
this.exit();
|
|
1092
1114
|
} catch {
|
|
1093
1115
|
}
|
|
1094
|
-
this.initializeRuntime(t),
|
|
1116
|
+
this.initializeRuntime(t), p(this, x) && this.setSapiName(p(this, x)), e && copyFS(r, this[__private__dont__use].FS, e);
|
|
1095
1117
|
}
|
|
1096
1118
|
/**
|
|
1097
1119
|
* Mounts a filesystem to a given path in the PHP filesystem.
|
|
@@ -1160,13 +1182,13 @@ class PHP {
|
|
|
1160
1182
|
this[__private__dont__use]._exit(t);
|
|
1161
1183
|
} catch {
|
|
1162
1184
|
}
|
|
1163
|
-
h(this,
|
|
1185
|
+
h(this, g, !1), h(this, P, null), delete this[__private__dont__use].onMessage, delete this[__private__dont__use];
|
|
1164
1186
|
}
|
|
1165
1187
|
[Symbol.dispose]() {
|
|
1166
|
-
|
|
1188
|
+
p(this, g) && this.exit(0);
|
|
1167
1189
|
}
|
|
1168
1190
|
}
|
|
1169
|
-
x = new WeakMap(),
|
|
1191
|
+
x = new WeakMap(), g = new WeakMap(), P = new WeakMap(), _ = new WeakMap(), E = new WeakMap(), k = new WeakSet(), J = function(t, e, r) {
|
|
1170
1192
|
const s = {
|
|
1171
1193
|
...t || {}
|
|
1172
1194
|
};
|
|
@@ -1176,9 +1198,9 @@ x = new WeakMap(), P = new WeakMap(), w = new WeakMap(), g = new WeakMap(), E =
|
|
|
1176
1198
|
["content-type", "content-length"].includes(i.toLowerCase()) && (n = ""), s[`${n}${i.toUpperCase().replace(/-/g, "_")}`] = e[i];
|
|
1177
1199
|
}
|
|
1178
1200
|
return s;
|
|
1179
|
-
}, I = new WeakSet(),
|
|
1201
|
+
}, I = new WeakSet(), Y = function() {
|
|
1180
1202
|
this[__private__dont__use].ccall("php_wasm_init", null, [], []);
|
|
1181
|
-
}, C = new WeakSet(),
|
|
1203
|
+
}, C = new WeakSet(), Z = function() {
|
|
1182
1204
|
const t = "/internal/headers.json";
|
|
1183
1205
|
if (!this.fileExists(t))
|
|
1184
1206
|
throw new Error(
|
|
@@ -1195,7 +1217,7 @@ x = new WeakMap(), P = new WeakMap(), w = new WeakMap(), g = new WeakMap(), E =
|
|
|
1195
1217
|
headers: r,
|
|
1196
1218
|
httpStatusCode: e.status
|
|
1197
1219
|
};
|
|
1198
|
-
}, A = new WeakSet(),
|
|
1220
|
+
}, A = new WeakSet(), K = function(t) {
|
|
1199
1221
|
if (this[__private__dont__use].ccall(
|
|
1200
1222
|
"wasm_set_request_uri",
|
|
1201
1223
|
null,
|
|
@@ -1210,35 +1232,35 @@ x = new WeakMap(), P = new WeakMap(), w = new WeakMap(), g = new WeakMap(), E =
|
|
|
1210
1232
|
[e]
|
|
1211
1233
|
);
|
|
1212
1234
|
}
|
|
1213
|
-
}, N = new WeakSet(),
|
|
1235
|
+
}, N = new WeakSet(), X = function(t) {
|
|
1214
1236
|
this[__private__dont__use].ccall(
|
|
1215
1237
|
"wasm_set_request_host",
|
|
1216
1238
|
null,
|
|
1217
1239
|
[STRING],
|
|
1218
1240
|
[t]
|
|
1219
1241
|
);
|
|
1220
|
-
}, M = new WeakSet(),
|
|
1242
|
+
}, M = new WeakSet(), Q = function(t) {
|
|
1221
1243
|
this[__private__dont__use].ccall(
|
|
1222
1244
|
"wasm_set_request_port",
|
|
1223
1245
|
null,
|
|
1224
1246
|
[NUMBER],
|
|
1225
1247
|
[t]
|
|
1226
1248
|
);
|
|
1227
|
-
}, j = new WeakSet(),
|
|
1249
|
+
}, j = new WeakSet(), ee = function(t, e) {
|
|
1228
1250
|
let r;
|
|
1229
1251
|
try {
|
|
1230
1252
|
r = parseInt(new URL(t).port, 10);
|
|
1231
1253
|
} catch {
|
|
1232
1254
|
}
|
|
1233
1255
|
return (!r || isNaN(r) || r === 80) && (r = e === "https" ? 443 : 80), r;
|
|
1234
|
-
}, U = new WeakSet(),
|
|
1256
|
+
}, U = new WeakSet(), te = function(t) {
|
|
1235
1257
|
this[__private__dont__use].ccall(
|
|
1236
1258
|
"wasm_set_request_method",
|
|
1237
1259
|
null,
|
|
1238
1260
|
[STRING],
|
|
1239
1261
|
[t]
|
|
1240
1262
|
);
|
|
1241
|
-
}, L = new WeakSet(),
|
|
1263
|
+
}, L = new WeakSet(), re = function(t) {
|
|
1242
1264
|
t.cookie && this[__private__dont__use].ccall(
|
|
1243
1265
|
"wasm_set_cookies",
|
|
1244
1266
|
null,
|
|
@@ -1255,7 +1277,7 @@ x = new WeakMap(), P = new WeakMap(), w = new WeakMap(), g = new WeakMap(), E =
|
|
|
1255
1277
|
[NUMBER],
|
|
1256
1278
|
[parseInt(t["content-length"], 10)]
|
|
1257
1279
|
);
|
|
1258
|
-
},
|
|
1280
|
+
}, q = new WeakSet(), se = function(t) {
|
|
1259
1281
|
let e, r;
|
|
1260
1282
|
typeof t == "string" ? (logger.warn(
|
|
1261
1283
|
"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"
|
|
@@ -1278,64 +1300,64 @@ x = new WeakMap(), P = new WeakMap(), w = new WeakMap(), g = new WeakMap(), E =
|
|
|
1278
1300
|
[NUMBER],
|
|
1279
1301
|
[r]
|
|
1280
1302
|
), s;
|
|
1281
|
-
}, b = new WeakSet(),
|
|
1303
|
+
}, b = new WeakSet(), V = function(t) {
|
|
1282
1304
|
this[__private__dont__use].ccall(
|
|
1283
1305
|
"wasm_set_path_translated",
|
|
1284
1306
|
null,
|
|
1285
1307
|
[STRING],
|
|
1286
1308
|
[t]
|
|
1287
1309
|
);
|
|
1288
|
-
},
|
|
1310
|
+
}, $ = new WeakSet(), ie = function(t, e) {
|
|
1289
1311
|
this[__private__dont__use].ccall(
|
|
1290
1312
|
"wasm_add_SERVER_entry",
|
|
1291
1313
|
null,
|
|
1292
1314
|
[STRING, STRING],
|
|
1293
1315
|
[t, e]
|
|
1294
1316
|
);
|
|
1295
|
-
}, B = new WeakSet(),
|
|
1317
|
+
}, B = new WeakSet(), ne = function(t, e) {
|
|
1296
1318
|
this[__private__dont__use].ccall(
|
|
1297
1319
|
"wasm_add_ENV_entry",
|
|
1298
1320
|
null,
|
|
1299
1321
|
[STRING, STRING],
|
|
1300
1322
|
[t, e]
|
|
1301
1323
|
);
|
|
1302
|
-
}, O = new WeakSet(),
|
|
1324
|
+
}, O = new WeakSet(), oe = async function() {
|
|
1303
1325
|
var i;
|
|
1304
1326
|
let t, e;
|
|
1305
1327
|
try {
|
|
1306
1328
|
t = await new Promise((n, o) => {
|
|
1307
1329
|
var l;
|
|
1308
|
-
e = (
|
|
1309
|
-
logger.error(
|
|
1330
|
+
e = (c) => {
|
|
1331
|
+
logger.error(c), logger.error(c.error);
|
|
1310
1332
|
const y = new Error("Rethrown");
|
|
1311
|
-
y.cause =
|
|
1312
|
-
}, (l =
|
|
1333
|
+
y.cause = c.error, y.betterMessage = c.message, o(y);
|
|
1334
|
+
}, (l = p(this, P)) == null || l.addEventListener(
|
|
1313
1335
|
"error",
|
|
1314
1336
|
e
|
|
1315
1337
|
);
|
|
1316
|
-
const
|
|
1338
|
+
const a = this[__private__dont__use].ccall(
|
|
1317
1339
|
"wasm_sapi_handle_request",
|
|
1318
1340
|
NUMBER,
|
|
1319
1341
|
[],
|
|
1320
1342
|
[],
|
|
1321
1343
|
{ async: !0 }
|
|
1322
1344
|
);
|
|
1323
|
-
return
|
|
1345
|
+
return a instanceof Promise ? a.then(n, o) : n(a);
|
|
1324
1346
|
});
|
|
1325
1347
|
} catch (n) {
|
|
1326
|
-
for (const
|
|
1327
|
-
typeof this[
|
|
1348
|
+
for (const c in this)
|
|
1349
|
+
typeof this[c] == "function" && (this[c] = () => {
|
|
1328
1350
|
throw new Error(
|
|
1329
1351
|
"PHP runtime has crashed – see the earlier error for details."
|
|
1330
1352
|
);
|
|
1331
1353
|
});
|
|
1332
1354
|
this.functionsMaybeMissingFromAsyncify = getFunctionsMaybeMissingFromAsyncify();
|
|
1333
|
-
const o = n,
|
|
1355
|
+
const o = n, a = "betterMessage" in o ? o.betterMessage : o.message, l = new Error(a);
|
|
1334
1356
|
throw l.cause = o, logger.error(l), l;
|
|
1335
1357
|
} finally {
|
|
1336
|
-
(i =
|
|
1358
|
+
(i = p(this, P)) == null || i.removeEventListener("error", e);
|
|
1337
1359
|
}
|
|
1338
|
-
const { headers: r, httpStatusCode: s } = d(this, C,
|
|
1360
|
+
const { headers: r, httpStatusCode: s } = d(this, C, Z).call(this);
|
|
1339
1361
|
return new PHPResponse(
|
|
1340
1362
|
t === 0 ? s : 500,
|
|
1341
1363
|
r,
|
|
@@ -1433,17 +1455,17 @@ async function* iteratePhpFiles(t, e, {
|
|
|
1433
1455
|
const o = n.pop();
|
|
1434
1456
|
if (!o)
|
|
1435
1457
|
return;
|
|
1436
|
-
const
|
|
1437
|
-
for (const l of
|
|
1438
|
-
const
|
|
1439
|
-
if (i.includes(
|
|
1458
|
+
const a = await t.listFiles(o);
|
|
1459
|
+
for (const l of a) {
|
|
1460
|
+
const c = `${o}/${l}`;
|
|
1461
|
+
if (i.includes(c.substring(e.length + 1)))
|
|
1440
1462
|
continue;
|
|
1441
|
-
await t.isDir(
|
|
1442
|
-
streamReadFileFromPHP(t,
|
|
1463
|
+
await t.isDir(c) ? n.push(c) : yield new StreamedFile(
|
|
1464
|
+
streamReadFileFromPHP(t, c),
|
|
1443
1465
|
r ? joinPaths(
|
|
1444
1466
|
s || "",
|
|
1445
|
-
|
|
1446
|
-
) :
|
|
1467
|
+
c.substring(e.length + 1)
|
|
1468
|
+
) : c
|
|
1447
1469
|
);
|
|
1448
1470
|
}
|
|
1449
1471
|
}
|
|
@@ -1601,22 +1623,22 @@ function ensurePathPrefix(t, e) {
|
|
|
1601
1623
|
}
|
|
1602
1624
|
async function encodeAsMultipart(t) {
|
|
1603
1625
|
const e = `----${Math.random().toString(36).slice(2)}`, r = `multipart/form-data; boundary=${e}`, s = new TextEncoder(), i = [];
|
|
1604
|
-
for (const [l,
|
|
1626
|
+
for (const [l, c] of Object.entries(t))
|
|
1605
1627
|
i.push(`--${e}\r
|
|
1606
|
-
`), i.push(`Content-Disposition: form-data; name="${l}"`),
|
|
1607
|
-
`),
|
|
1628
|
+
`), i.push(`Content-Disposition: form-data; name="${l}"`), c instanceof File && i.push(`; filename="${c.name}"`), i.push(`\r
|
|
1629
|
+
`), c instanceof File && (i.push("Content-Type: application/octet-stream"), i.push(`\r
|
|
1608
1630
|
`)), i.push(`\r
|
|
1609
|
-
`),
|
|
1631
|
+
`), c instanceof File ? i.push(await fileToUint8Array(c)) : i.push(c), i.push(`\r
|
|
1610
1632
|
`);
|
|
1611
1633
|
i.push(`--${e}--\r
|
|
1612
1634
|
`);
|
|
1613
|
-
const n = i.reduce((l,
|
|
1614
|
-
let
|
|
1635
|
+
const n = i.reduce((l, c) => l + c.length, 0), o = new Uint8Array(n);
|
|
1636
|
+
let a = 0;
|
|
1615
1637
|
for (const l of i)
|
|
1616
1638
|
o.set(
|
|
1617
1639
|
typeof l == "string" ? s.encode(l) : l,
|
|
1618
|
-
|
|
1619
|
-
),
|
|
1640
|
+
a
|
|
1641
|
+
), a += l.length;
|
|
1620
1642
|
return { bytes: o, contentType: r };
|
|
1621
1643
|
}
|
|
1622
1644
|
function fileToUint8Array(t) {
|
|
@@ -1723,7 +1745,7 @@ const _default = "application/octet-stream", asx = "video/x-ms-asf", atom = "app
|
|
|
1723
1745
|
xspf,
|
|
1724
1746
|
zip
|
|
1725
1747
|
};
|
|
1726
|
-
var
|
|
1748
|
+
var w, R, T, v, F, f, S, H, D, ae, z, le, W, ce;
|
|
1727
1749
|
class PHPRequestHandler {
|
|
1728
1750
|
/**
|
|
1729
1751
|
* The request handler needs to decide whether to serve a static asset or
|
|
@@ -1756,50 +1778,41 @@ class PHPRequestHandler {
|
|
|
1756
1778
|
* @returns The response.
|
|
1757
1779
|
*/
|
|
1758
1780
|
u(this, W);
|
|
1759
|
-
|
|
1760
|
-
* Resolve the requested path to the filesystem path of the requested PHP file.
|
|
1761
|
-
*
|
|
1762
|
-
* Fall back to index.php as if there was a url rewriting rule in place.
|
|
1763
|
-
*
|
|
1764
|
-
* @param requestedPath - The requested pathname.
|
|
1765
|
-
* @throws {Error} If the requested path doesn't exist.
|
|
1766
|
-
* @returns The resolved filesystem path.
|
|
1767
|
-
*/
|
|
1768
|
-
u(this, G);
|
|
1769
|
-
u(this, f, void 0);
|
|
1781
|
+
u(this, w, void 0);
|
|
1770
1782
|
u(this, R, void 0);
|
|
1771
1783
|
u(this, T, void 0);
|
|
1772
1784
|
u(this, v, void 0);
|
|
1785
|
+
u(this, F, void 0);
|
|
1786
|
+
u(this, f, void 0);
|
|
1773
1787
|
u(this, S, void 0);
|
|
1774
|
-
u(this, _, void 0);
|
|
1775
1788
|
u(this, H, void 0);
|
|
1776
|
-
u(this, F, void 0);
|
|
1777
1789
|
const {
|
|
1778
1790
|
documentRoot: r = "/www/",
|
|
1779
1791
|
absoluteUrl: s = typeof location == "object" ? location == null ? void 0 : location.href : "",
|
|
1780
|
-
rewriteRules: i = []
|
|
1792
|
+
rewriteRules: i = [],
|
|
1793
|
+
getFileNotFoundAction: n = () => ({ type: "404" })
|
|
1781
1794
|
} = e;
|
|
1782
1795
|
"processManager" in e ? this.processManager = e.processManager : this.processManager = new PHPProcessManager({
|
|
1783
|
-
phpFactory: async (
|
|
1784
|
-
const
|
|
1785
|
-
...
|
|
1796
|
+
phpFactory: async (l) => {
|
|
1797
|
+
const c = await e.phpFactory({
|
|
1798
|
+
...l,
|
|
1786
1799
|
requestHandler: this
|
|
1787
1800
|
});
|
|
1788
|
-
return
|
|
1801
|
+
return c.requestHandler = this, c;
|
|
1789
1802
|
},
|
|
1790
1803
|
maxPhpInstances: e.maxPhpInstances
|
|
1791
|
-
}), h(this,
|
|
1792
|
-
const
|
|
1793
|
-
h(this, T,
|
|
1794
|
-
const
|
|
1795
|
-
h(this,
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
].join("")), h(this,
|
|
1799
|
-
`${
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
].join("")), this.rewriteRules = i;
|
|
1804
|
+
}), h(this, H, new HttpCookieStore()), h(this, w, r);
|
|
1805
|
+
const o = new URL(s);
|
|
1806
|
+
h(this, T, o.hostname), h(this, v, o.port ? Number(o.port) : o.protocol === "https:" ? 443 : 80), h(this, R, (o.protocol || "").replace(":", ""));
|
|
1807
|
+
const a = p(this, v) !== 443 && p(this, v) !== 80;
|
|
1808
|
+
h(this, F, [
|
|
1809
|
+
p(this, T),
|
|
1810
|
+
a ? `:${p(this, v)}` : ""
|
|
1811
|
+
].join("")), h(this, f, o.pathname.replace(/\/+$/, "")), h(this, S, [
|
|
1812
|
+
`${p(this, R)}://`,
|
|
1813
|
+
p(this, F),
|
|
1814
|
+
p(this, f)
|
|
1815
|
+
].join("")), this.rewriteRules = i, this.getFileNotFoundAction = n;
|
|
1803
1816
|
}
|
|
1804
1817
|
async getPrimaryPhp() {
|
|
1805
1818
|
return await this.processManager.getPrimaryPhp();
|
|
@@ -1823,20 +1836,20 @@ class PHPRequestHandler {
|
|
|
1823
1836
|
*/
|
|
1824
1837
|
internalUrlToPath(e) {
|
|
1825
1838
|
const r = new URL(e);
|
|
1826
|
-
return r.pathname.startsWith(
|
|
1839
|
+
return r.pathname.startsWith(p(this, f)) && (r.pathname = r.pathname.slice(p(this, f).length)), toRelativeUrl(r);
|
|
1827
1840
|
}
|
|
1828
1841
|
/**
|
|
1829
1842
|
* The absolute URL of this PHPRequestHandler instance.
|
|
1830
1843
|
*/
|
|
1831
1844
|
get absoluteUrl() {
|
|
1832
|
-
return
|
|
1845
|
+
return p(this, S);
|
|
1833
1846
|
}
|
|
1834
1847
|
/**
|
|
1835
1848
|
* The directory in the PHP filesystem where the server will look
|
|
1836
1849
|
* for the files to serve. Default: `/var/www`.
|
|
1837
1850
|
*/
|
|
1838
1851
|
get documentRoot() {
|
|
1839
|
-
return
|
|
1852
|
+
return p(this, w);
|
|
1840
1853
|
}
|
|
1841
1854
|
/**
|
|
1842
1855
|
* Serves the request – either by serving a static file, or by
|
|
@@ -1894,24 +1907,59 @@ class PHPRequestHandler {
|
|
|
1894
1907
|
), i = applyRewriteRules(
|
|
1895
1908
|
removePathPrefix(
|
|
1896
1909
|
decodeURIComponent(s.pathname),
|
|
1897
|
-
|
|
1910
|
+
p(this, f)
|
|
1898
1911
|
),
|
|
1899
1912
|
this.rewriteRules
|
|
1900
|
-
), n =
|
|
1901
|
-
|
|
1913
|
+
), n = await this.getPrimaryPhp();
|
|
1914
|
+
let o = joinPaths(p(this, w), i);
|
|
1915
|
+
if (n.isDir(o)) {
|
|
1916
|
+
if (!o.endsWith("/"))
|
|
1917
|
+
return new PHPResponse(
|
|
1918
|
+
301,
|
|
1919
|
+
{ Location: [`${s.pathname}/`] },
|
|
1920
|
+
new Uint8Array(0)
|
|
1921
|
+
);
|
|
1922
|
+
for (const a of ["index.php", "index.html"]) {
|
|
1923
|
+
const l = joinPaths(o, a);
|
|
1924
|
+
if (n.isFile(l)) {
|
|
1925
|
+
o = l;
|
|
1926
|
+
break;
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1930
|
+
if (!n.isFile(o)) {
|
|
1931
|
+
const a = this.getFileNotFoundAction(
|
|
1932
|
+
i
|
|
1933
|
+
);
|
|
1934
|
+
switch (a.type) {
|
|
1935
|
+
case "response":
|
|
1936
|
+
return a.response;
|
|
1937
|
+
case "internal-redirect":
|
|
1938
|
+
o = joinPaths(p(this, w), a.uri);
|
|
1939
|
+
break;
|
|
1940
|
+
case "404":
|
|
1941
|
+
return PHPResponse.forHttpCode(404);
|
|
1942
|
+
default:
|
|
1943
|
+
throw new Error(
|
|
1944
|
+
`Unsupported file-not-found action type: '${a.type}'`
|
|
1945
|
+
);
|
|
1946
|
+
}
|
|
1947
|
+
}
|
|
1948
|
+
if (n.isFile(o))
|
|
1949
|
+
if (o.endsWith(".php")) {
|
|
1950
|
+
const a = {
|
|
1951
|
+
...e,
|
|
1952
|
+
// Pass along URL with the #fragment filtered out
|
|
1953
|
+
url: s.toString()
|
|
1954
|
+
};
|
|
1955
|
+
return d(this, z, le).call(this, a, o);
|
|
1956
|
+
} else
|
|
1957
|
+
return d(this, D, ae).call(this, n, o);
|
|
1958
|
+
else
|
|
1959
|
+
return PHPResponse.forHttpCode(404);
|
|
1902
1960
|
}
|
|
1903
1961
|
}
|
|
1904
|
-
|
|
1905
|
-
if (!e.fileExists(r))
|
|
1906
|
-
return new PHPResponse(
|
|
1907
|
-
404,
|
|
1908
|
-
// Let the service worker know that no static file was found
|
|
1909
|
-
// and that it's okay to issue a real fetch() to the server.
|
|
1910
|
-
{
|
|
1911
|
-
"x-file-type": ["static"]
|
|
1912
|
-
},
|
|
1913
|
-
new TextEncoder().encode("404 File not found")
|
|
1914
|
-
);
|
|
1962
|
+
w = new WeakMap(), R = new WeakMap(), T = new WeakMap(), v = new WeakMap(), F = new WeakMap(), f = new WeakMap(), S = new WeakMap(), H = new WeakMap(), D = new WeakSet(), ae = function(e, r) {
|
|
1915
1963
|
const s = e.readFileAsBuffer(r);
|
|
1916
1964
|
return new PHPResponse(
|
|
1917
1965
|
200,
|
|
@@ -1926,7 +1974,7 @@ f = new WeakMap(), R = new WeakMap(), T = new WeakMap(), v = new WeakMap(), S =
|
|
|
1926
1974
|
},
|
|
1927
1975
|
s
|
|
1928
1976
|
);
|
|
1929
|
-
}, z = new WeakSet(),
|
|
1977
|
+
}, z = new WeakSet(), le = async function(e, r) {
|
|
1930
1978
|
let s;
|
|
1931
1979
|
try {
|
|
1932
1980
|
s = await this.processManager.acquirePHPInstance();
|
|
@@ -1934,76 +1982,54 @@ f = new WeakMap(), R = new WeakMap(), T = new WeakMap(), v = new WeakMap(), S =
|
|
|
1934
1982
|
return i instanceof MaxPhpInstancesError ? PHPResponse.forHttpCode(502) : PHPResponse.forHttpCode(500);
|
|
1935
1983
|
}
|
|
1936
1984
|
try {
|
|
1937
|
-
return await d(this, W,
|
|
1985
|
+
return await d(this, W, ce).call(this, s.php, e, r);
|
|
1938
1986
|
} finally {
|
|
1939
1987
|
s.reap();
|
|
1940
1988
|
}
|
|
1941
|
-
}, W = new WeakSet(),
|
|
1989
|
+
}, W = new WeakSet(), ce = async function(e, r, s) {
|
|
1942
1990
|
let i = "GET";
|
|
1943
1991
|
const n = {
|
|
1944
|
-
host:
|
|
1992
|
+
host: p(this, F),
|
|
1945
1993
|
...normalizeHeaders(r.headers || {}),
|
|
1946
|
-
cookie:
|
|
1994
|
+
cookie: p(this, H).getCookieRequestHeader()
|
|
1947
1995
|
};
|
|
1948
1996
|
let o = r.body;
|
|
1949
1997
|
if (typeof o == "object" && !(o instanceof Uint8Array)) {
|
|
1950
1998
|
i = "POST";
|
|
1951
|
-
const { bytes:
|
|
1952
|
-
o =
|
|
1953
|
-
}
|
|
1954
|
-
let p;
|
|
1955
|
-
try {
|
|
1956
|
-
p = d(this, G, ue).call(this, e, decodeURIComponent(s.pathname));
|
|
1957
|
-
} catch {
|
|
1958
|
-
return PHPResponse.forHttpCode(404);
|
|
1999
|
+
const { bytes: a, contentType: l } = await encodeAsMultipart(o);
|
|
2000
|
+
o = a, n["content-type"] = l;
|
|
1959
2001
|
}
|
|
1960
2002
|
try {
|
|
1961
|
-
const
|
|
2003
|
+
const a = await e.run({
|
|
1962
2004
|
relativeUri: ensurePathPrefix(
|
|
1963
|
-
toRelativeUrl(
|
|
1964
|
-
|
|
2005
|
+
toRelativeUrl(new URL(r.url)),
|
|
2006
|
+
p(this, f)
|
|
1965
2007
|
),
|
|
1966
|
-
protocol:
|
|
2008
|
+
protocol: p(this, R),
|
|
1967
2009
|
method: r.method || i,
|
|
1968
2010
|
$_SERVER: {
|
|
1969
2011
|
REMOTE_ADDR: "127.0.0.1",
|
|
1970
|
-
DOCUMENT_ROOT:
|
|
1971
|
-
HTTPS:
|
|
2012
|
+
DOCUMENT_ROOT: p(this, w),
|
|
2013
|
+
HTTPS: p(this, S).startsWith("https://") ? "on" : ""
|
|
1972
2014
|
},
|
|
1973
2015
|
body: o,
|
|
1974
|
-
scriptPath:
|
|
2016
|
+
scriptPath: s,
|
|
1975
2017
|
headers: n
|
|
1976
2018
|
});
|
|
1977
|
-
return
|
|
1978
|
-
|
|
1979
|
-
),
|
|
1980
|
-
} catch (
|
|
1981
|
-
const
|
|
1982
|
-
if (
|
|
1983
|
-
return
|
|
1984
|
-
throw
|
|
1985
|
-
}
|
|
1986
|
-
}, G = new WeakSet(), ue = function(e, r) {
|
|
1987
|
-
let s = removePathPrefix(r, c(this, _));
|
|
1988
|
-
s = applyRewriteRules(s, this.rewriteRules), s.includes(".php") ? s = s.split(".php")[0] + ".php" : e.isDir(`${c(this, f)}${s}`) ? (s.endsWith("/") || (s = `${s}/`), s = `${s}index.php`) : s = "/index.php";
|
|
1989
|
-
let i = `${c(this, f)}${s}`;
|
|
1990
|
-
if (e.fileExists(i) || (i = `${c(this, f)}/index.php`), e.fileExists(i))
|
|
1991
|
-
return i;
|
|
1992
|
-
throw new Error(`File not found: ${i}`);
|
|
2019
|
+
return p(this, H).rememberCookiesFromResponseHeaders(
|
|
2020
|
+
a.headers
|
|
2021
|
+
), a;
|
|
2022
|
+
} catch (a) {
|
|
2023
|
+
const l = a;
|
|
2024
|
+
if (l != null && l.response)
|
|
2025
|
+
return l.response;
|
|
2026
|
+
throw a;
|
|
2027
|
+
}
|
|
1993
2028
|
};
|
|
1994
2029
|
function inferMimeType(t) {
|
|
1995
2030
|
const e = t.split(".").pop();
|
|
1996
2031
|
return mimeTypes[e] || mimeTypes._default;
|
|
1997
2032
|
}
|
|
1998
|
-
function seemsLikeAPHPRequestHandlerPath(t) {
|
|
1999
|
-
return seemsLikeAPHPFile(t) || seemsLikeADirectoryRoot(t);
|
|
2000
|
-
}
|
|
2001
|
-
function seemsLikeAPHPFile(t) {
|
|
2002
|
-
return t.endsWith(".php") || t.includes(".php/");
|
|
2003
|
-
}
|
|
2004
|
-
function seemsLikeADirectoryRoot(t) {
|
|
2005
|
-
return !t.split("/").pop().includes(".");
|
|
2006
|
-
}
|
|
2007
2033
|
function applyRewriteRules(t, e) {
|
|
2008
2034
|
for (const r of e)
|
|
2009
2035
|
if (new RegExp(r.match).test(t))
|
package/lib/fs-helpers.d.ts
CHANGED
|
@@ -75,6 +75,13 @@ export declare class FSHelpers {
|
|
|
75
75
|
* @returns True if the path is a directory, false otherwise.
|
|
76
76
|
*/
|
|
77
77
|
static isDir(FS: Emscripten.RootFS, path: string): boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Checks if a file exists in the PHP filesystem.
|
|
80
|
+
*
|
|
81
|
+
* @param path – The path to check.
|
|
82
|
+
* @returns True if the path is a file, false otherwise.
|
|
83
|
+
*/
|
|
84
|
+
static isFile(FS: Emscripten.RootFS, path: string): boolean;
|
|
78
85
|
/**
|
|
79
86
|
* Checks if a file (or a directory) exists in the PHP filesystem.
|
|
80
87
|
*
|
package/lib/index.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ export type * from './emscripten-types';
|
|
|
24
24
|
export type { DataModule, EmscriptenOptions, PHPLoaderModule, PHPRuntime, PHPRuntimeId, RuntimeType, } from './load-php-runtime';
|
|
25
25
|
export type { PHPRequestHandlerConfiguration, RewriteRule, } from './php-request-handler';
|
|
26
26
|
export { PHPRequestHandler, applyRewriteRules } from './php-request-handler';
|
|
27
|
+
export type { FileNotFoundGetActionCallback, FileNotFoundToInternalRedirect, FileNotFoundToResponse, FileNotFoundAction, } from './php-request-handler';
|
|
27
28
|
export { rotatePHPRuntime } from './rotate-php-runtime';
|
|
28
29
|
export { writeFiles } from './write-files';
|
|
29
30
|
export type { FileTree } from './write-files';
|
|
@@ -6,6 +6,19 @@ export type RewriteRule = {
|
|
|
6
6
|
match: RegExp;
|
|
7
7
|
replacement: string;
|
|
8
8
|
};
|
|
9
|
+
export type FileNotFoundToResponse = {
|
|
10
|
+
type: 'response';
|
|
11
|
+
response: PHPResponse;
|
|
12
|
+
};
|
|
13
|
+
export type FileNotFoundToInternalRedirect = {
|
|
14
|
+
type: 'internal-redirect';
|
|
15
|
+
uri: string;
|
|
16
|
+
};
|
|
17
|
+
export type FileNotFoundTo404 = {
|
|
18
|
+
type: '404';
|
|
19
|
+
};
|
|
20
|
+
export type FileNotFoundAction = FileNotFoundToResponse | FileNotFoundToInternalRedirect | FileNotFoundTo404;
|
|
21
|
+
export type FileNotFoundGetActionCallback = (relativePath: string) => FileNotFoundAction;
|
|
9
22
|
interface BaseConfiguration {
|
|
10
23
|
/**
|
|
11
24
|
* The directory in the PHP filesystem where the server will look
|
|
@@ -20,6 +33,11 @@ interface BaseConfiguration {
|
|
|
20
33
|
* Rewrite rules
|
|
21
34
|
*/
|
|
22
35
|
rewriteRules?: RewriteRule[];
|
|
36
|
+
/**
|
|
37
|
+
* A callback that decides how to handle a file-not-found condition for a
|
|
38
|
+
* given request URI.
|
|
39
|
+
*/
|
|
40
|
+
getFileNotFoundAction?: FileNotFoundGetActionCallback;
|
|
23
41
|
}
|
|
24
42
|
export type PHPRequestHandlerFactoryArgs = PHPFactoryOptions & {
|
|
25
43
|
requestHandler: PHPRequestHandler;
|
|
@@ -103,6 +121,7 @@ export declare class PHPRequestHandler {
|
|
|
103
121
|
#private;
|
|
104
122
|
rewriteRules: RewriteRule[];
|
|
105
123
|
processManager: PHPProcessManager;
|
|
124
|
+
getFileNotFoundAction: FileNotFoundGetActionCallback;
|
|
106
125
|
/**
|
|
107
126
|
* The request handler needs to decide whether to serve a static asset or
|
|
108
127
|
* run the PHP interpreter. For static assets it should just reuse the primary
|
|
@@ -191,23 +210,6 @@ export declare class PHPRequestHandler {
|
|
|
191
210
|
*/
|
|
192
211
|
request(request: PHPRequest): Promise<PHPResponse>;
|
|
193
212
|
}
|
|
194
|
-
/**
|
|
195
|
-
* Guesses whether the given path looks like a PHP file.
|
|
196
|
-
*
|
|
197
|
-
* @example
|
|
198
|
-
* ```js
|
|
199
|
-
* seemsLikeAPHPRequestHandlerPath('/index.php') // true
|
|
200
|
-
* seemsLikeAPHPRequestHandlerPath('/index.php') // true
|
|
201
|
-
* seemsLikeAPHPRequestHandlerPath('/index.php/foo/bar') // true
|
|
202
|
-
* seemsLikeAPHPRequestHandlerPath('/index.html') // false
|
|
203
|
-
* seemsLikeAPHPRequestHandlerPath('/index.html/foo/bar') // false
|
|
204
|
-
* seemsLikeAPHPRequestHandlerPath('/') // true
|
|
205
|
-
* ```
|
|
206
|
-
*
|
|
207
|
-
* @param path The path to check.
|
|
208
|
-
* @returns Whether the path seems like a PHP server path.
|
|
209
|
-
*/
|
|
210
|
-
export declare function seemsLikeAPHPRequestHandlerPath(path: string): boolean;
|
|
211
213
|
/**
|
|
212
214
|
* Applies the given rewrite rules to the given path.
|
|
213
215
|
*
|
package/lib/php-worker.d.ts
CHANGED
|
@@ -64,6 +64,8 @@ export declare class PHPWorker implements LimitedPHPApi {
|
|
|
64
64
|
listFiles(path: string, options?: ListFilesOptions): string[];
|
|
65
65
|
/** @inheritDoc @php-wasm/universal!/PHP.isDir */
|
|
66
66
|
isDir(path: string): boolean;
|
|
67
|
+
/** @inheritDoc @php-wasm/universal!/PHP.isFile */
|
|
68
|
+
isFile(path: string): boolean;
|
|
67
69
|
/** @inheritDoc @php-wasm/universal!/PHP.fileExists */
|
|
68
70
|
fileExists(path: string): boolean;
|
|
69
71
|
/** @inheritDoc @php-wasm/universal!/PHP.onMessage */
|
package/lib/php.d.ts
CHANGED
|
@@ -267,6 +267,13 @@ export declare class PHP implements Disposable {
|
|
|
267
267
|
* @returns True if the path is a directory, false otherwise.
|
|
268
268
|
*/
|
|
269
269
|
isDir(path: string): boolean;
|
|
270
|
+
/**
|
|
271
|
+
* Checks if a file exists in the PHP filesystem.
|
|
272
|
+
*
|
|
273
|
+
* @param path – The path to check.
|
|
274
|
+
* @returns True if the path is a file, false otherwise.
|
|
275
|
+
*/
|
|
276
|
+
isFile(path: string): boolean;
|
|
270
277
|
/**
|
|
271
278
|
* Checks if a file (or a directory) exists in the PHP filesystem.
|
|
272
279
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@php-wasm/universal",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.23",
|
|
4
4
|
"description": "PHP.wasm – emscripten bindings for PHP",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"module": "./index.js",
|
|
38
38
|
"types": "index.d.ts",
|
|
39
39
|
"license": "GPL-2.0-or-later",
|
|
40
|
-
"gitHead": "
|
|
40
|
+
"gitHead": "254500c0c65525d3c5bfb61d04eb8ccdb5e8e5bf",
|
|
41
41
|
"engines": {
|
|
42
42
|
"node": ">=18.18.0",
|
|
43
43
|
"npm": ">=8.11.0"
|
|
@@ -45,10 +45,10 @@
|
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"comlink": "^4.4.1",
|
|
47
47
|
"ini": "4.1.2",
|
|
48
|
-
"@php-wasm/node-polyfills": "0.9.
|
|
49
|
-
"@php-wasm/logger": "0.9.
|
|
50
|
-
"@php-wasm/util": "0.9.
|
|
51
|
-
"@php-wasm/stream-compression": "0.9.
|
|
52
|
-
"@php-wasm/progress": "0.9.
|
|
48
|
+
"@php-wasm/node-polyfills": "0.9.23",
|
|
49
|
+
"@php-wasm/logger": "0.9.23",
|
|
50
|
+
"@php-wasm/util": "0.9.23",
|
|
51
|
+
"@php-wasm/stream-compression": "0.9.23",
|
|
52
|
+
"@php-wasm/progress": "0.9.23"
|
|
53
53
|
}
|
|
54
54
|
}
|