Repository navigation
Network access in the browser #85
Description
Latest status
Curl and tcp over fetch() are now a part of WordPress Playground 🎉 Here's what we still need to close this issue:
- CORS: Use CORS proxy for all CORS-affected outbound requests #1940
- Enable networking by default #1225
Description
WordPress Playground only has a partial support for network calls.
Types of network calls in WordPress
wp_safe_remote_get
As of #724, Playground is capable of translating wp_safe_remote_get calls into JavaScript fetch() requests. This has limitations:
- Only https:// URLs are supported
- The server must provide valid CORS headers in the response
- Developers can't control all the headers
Arbitrary network calls
Other methods of accessing the network, such as libcurl or file_get_contents, are not supported yet.
Web browsers do not allow the WebAssembly code to access the internet directly yet. A native socket API may or may not be released in the future, but there isn't one for now. #1093 would improve the situation.
In Node.js, Playground access the network using the following method:
- Set up a same-domain API endpoint that accepts network commands from the browser
- Capture socket function calls in the WebAssembly binary
- Pass them to JavaScript
- Pass the requested operation over the API endpoint using the
fetch()orWebSocket
This may not be viable on the web as someone would have to pay for the hardware to run the proxy on, and the proxy's nature mean there are security risks related to accessing the local network.
Solution
After 1,5 years of exploring and discussing, this issue finally has a path forward:
- Merge PHP: Support http:// https:// and ssl:// stream wrappers #1093
- Merge Curl extension for the Node.js build of PHP.wasm #1273
- Ship curl in the browser
- This would enable requesting all CORS-enabled HTTPS endpoints via
file_get_contents,curl_execetc. and without going throughwp_safe_remote_get().
For full networking support, we'd also need the following:
- Expose the Node networking proxy as a separate, runnable script
- Provide an API to connect it to the in-browser version Playground
- Document the workflow
Nice to haves:
- Ship a version of the network built in PHP script to enable running a full-featured Playground build in the same environments as WordPress.
- Provide a Dockerfile to set up the network proxy and a few buttons for quickly spinning proxy cloud nodes on, e.g. CloudFlare, Digital Ocean, etc.
Limitations of the approach
Limitations without the network proxy:
- Non-CORS URLs wouldn't work
- Non-HTTPS traffic wouldn't work
- gethostname and other low-level methods still wouldn't work
- SSL certificate checks, like the ones done by Composer, wouldn't work
All of the above could be resolved by plugging in a network proxy.
Activity
adamziel commentedon Dec 16, 2022
For posterity: I tried a custom Request_Transport that tunneled all traffic through browser's
fetch()using the vrzno extension by @seanmorris and that worked well except for sites that didn't allow cross-origin requests – which is most sites.Interestingly, I remember that WordPress Plugin Directory did not work in this setup. However, @dd32 pointed out that it exposes the correct access-control headers:
So perhaps there is a way to support at least the
api.wordpress.orgrequests with the browser's nativefetch()? Let's revisit this idea.adamziel commentedon Feb 2, 2023
Networking is supported in the Node.js build as of #119 – PHP sends data through a
WebSocketto a local TCP proxy that handles the required network calls.I can think of three ways to implement in-browser support:
socket.tcpAPI for extensions.WebSocketclass could be replaced with one that concatenates all the sent data and then reconstructs afetch()call from them. Then, PHP can be compiled without OpenSSL support OR to treat allhttpsrequests ashttpones so that theWebSocketshim could read raw data. The proxy itself could work as a same-tabfetch()or as a browser-extensionfetch()to work around the CORS limitations. This wouldn't support arbitrary network traffic, but would be perhaps good enough for the most popular use-cases.adamziel commentedon Feb 3, 2023
Also linking to this related discussion.
adamziel commentedon Apr 29, 2023
Libraries like Composer require HTTPS and they verify the peer certificate by default: https://github.com/composer/composer/blob/11879ea737978fabb8127616e703e571ff71b184/src/Composer/Util/StreamContextFactory.php#L183-L197
As a workaround, networking in the browser could:
fetch()This will only work for endpoints exposing proper CORS headers, but it's a start.
dmsnell commentedon May 1, 2023
why not use a real chain of trust?
I'm very leery of building a system whose default is to strip away all security from TLS connections and present trust for everything.
particularly if we're trying to make it easy to instantly spool up systems with a blueprint, this could so easily lead to cross-site attacks: "Hey look at the plugin I wrote: [malware link]"
for what it's worth, the default Erlang net library sets
verify_peertofalseand it's a disaster because nobody remembers to activate it and supply proper certs.maybe I'm misreading this, but I'd rather us avoid that mistake if it's what I think we're talking about
adamziel commentedon May 3, 2023
We do in Node.js. Browsers can’t open raw TCP sockets so we need to re-issue the request using fetch(). The only way to do it is to MITM the PHP program to parse the encrypted request data.
[-]Support network access[/-][+]Network access in the browser[/+]adamziel commentedon Jun 25, 2023
Hosting a websocket proxy on e.g. free CloudFlare tier could solve this for now.
eliot-akira commentedon Jun 25, 2023
Possible candidates:
EDIT: Oh, I see there's already something like this implemented in
@php-wasm/node, based on maximegris/node-websockify.https://github.com/WordPress/wordpress-playground/blob/trunk/packages/php-wasm/node/src/lib/networking/outbound-ws-to-tcp-proxy.ts
adamziel commentedon Jun 25, 2023
Yup, it is used in the
@php-wasm/cli, VS Code extension, and wp-now. The same proxy would just work with the web version if it was hosted somewhere. The custom parts were added to supportsetsockopt().16 remaining items
adamziel commentedon Sep 13, 2024
Hey @jeffpaul! Unfortunately I won't be around at WCUS :( But let me loop in @dmsnell who I know will be there. Alternatively, we could connect on .org slack or zoom.
Enable CURL in Playground Web
adamziel commentedon Oct 23, 2024
I merged this significant milestone earlier today:
Next up:
Enable CURL in Playground Web (#1935)
adamziel commentedon Oct 24, 2024
Curl is available in web browsers since #1935.
fetch()is used as a network transport so the typical CORS limitations apply.To solve, say, ~80% of the problem, we'd need to open up the CORS Proxy beyond talking to git. This is coming in the short to medium term.
To solve 100% of the problem, we'd need to tunnel the raw TCP traffic coming from Playground over a persistent WebSocket connection. In this scenario, we'd need a
https://playground.wordpress.net/tcp-over-ws.phpendpoint that would use stream_select to ingest data form Playground, pipe it to the network, and pipe the response bytes back to Playground. Definitely possible, especially with AsyncHttp\Client, but it's also non-trivial and I'm not sure what kind of appetite y'all have for such a feature. For now I'm taking a wild guess this is a very low priority project. If this is something that would help you, please comment on this issue and describe your use-case – if enough people come in, I'm happy to make it happen.For now, here's what we need to close this issue:
Support quickly testing php-wasm CLI changes with bun (#85)
Support quickly testing php-wasm CLI changes with bun (#85)
[Web] Enable networking by default in Playground web (#2296)
adamziel commentedon Jun 24, 2025
With #2296 merged and #1225 resolved, we can finally close this issue after 2.5 years :) playground.wordpress.net now has a full access to HTTP and HTTPS network requests enabled by default.
Other protocols, such as connecting to MySQL on port 3306, are not supported from the browser at the moment. They could be, and if you need them I encourage you to open a new issue describing your use-case. However, that's separate from this issue so I'm marking it as resolved.
sinanisler commentedon Jun 24, 2025