Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wp-now: Error on stackblitz.com #79

Open
adamziel opened this issue Jun 14, 2023 · 8 comments
Open

wp-now: Error on stackblitz.com #79

adamziel opened this issue Jun 14, 2023 · 8 comments
Labels
Bug Something isn't working wp-now

Comments

@adamziel
Copy link
Collaborator

@schlessera and I tried running wp-now on Stackblitz, but it failed with the following error. My guess is it attempted to make a network connection but Stackblitz doesn't support those:

npx @wp-now/wp-now php test.php
You are running Node.js version 16, but this application recommends at least Node.js 18 and isn't guaranteed to work on lower versions. Please upgrade your Node.js version.
Error: socket hang up
    at connResetException (https://wpcli-xt3q.w-credentialless.staticblitz.com/blitz.bf38680a.js:35:8261)
    at TLSSocket.socketOnEnd (https://wpcli-xt3q.w-credentialless.staticblitz.com/blitz.bf38680a.js:35:1190705)
    at EventEmitter.emit (https://wpcli-xt3q.w-credentialless.staticblitz.com/blitz.bf38680a.js:35:156947)
    at endReadableNT (https://wpcli-xt3q.w-credentialless.staticblitz.com/blitz.bf38680a.js:35:731446)
    at _0x202448 (https://wpcli-xt3q.w-credentialless.staticblitz.com/blitz.bf38680a.js:44:153173)
    at https://wpcli-xt3q.w-credentialless.staticblitz.com/blitz.bf38680a.js:44:152912 {
  code: 'ECONNRESET'
} (

The same command worked in @php-wasm/cli so it's not a Playground issue.

@adamziel adamziel added Bug Something isn't working wp-now labels Jun 14, 2023
@rhildred
Copy link

rhildred commented Sep 22, 2023

I am really eager to see this work as well. I made a fork https://github.com/rhildred/playground-tools and a npm package @rhildred/wp-now. The hangup error was due to cors. I fixed that by adding a corsproxy and now I get the code all downloaded. The bindings seem to work in that I see the .sqlite file in the database folder and such. It says it is listening but when I go there I get 422 errors. My current thinking is that there is an issue with php.request on stackblitz. I did try php.run instead and I was able to get phpinfo.php to display. Then it crashed:

listening on 8080

Aborted()

Aborted()
Error: Aborted(). Build with -sASSERTIONS for more info.
    at #handleRequest (/home/projects/stackblitz-starters-9vskuh/node_modules/@php-wasm/node/index.cjs:67911:24)
    at async _NodePHP.run (/home/projects/stackblitz-starters-9vskuh/node_modules/@php-wasm/node/index.cjs:67682:12)
    at async eval (/home/projects/stackblitz-starters-9vskuh/index.js:32:20) {
  cause: Error: Rethrown
      at UnhandledRejectionsTarget.errorListener (/home/projects/stackblitz-starters-9vskuh/node_modules/@php-wasm/node/index.cjs:67878:28)
      at [nodejs.internal.kHybridDispatch] (node:internal/event_target:68:8281)
      at UnhandledRejectionsTarget.dispatchEvent (node:internal/event_target:68:7702)
      at runtime.asm.<computed> (/home/projects/stackblitz-starters-9vskuh/node_modules/@php-wasm/node/index.cjs:66773:20)
      at invoke_ii (/home/projects/stackblitz-starters-9vskuh/node_modules/@php-wasm/node/index.cjs:10428:14)
      at ret.<computed> (/home/projects/stackblitz-starters-9vskuh/node_modules/@php-wasm/node/index.cjs:9698:33)
      at runtime.asm.<computed> (/home/projects/stackblitz-starters-9vskuh/node_modules/@php-wasm/node/index.cjs:66760:18)
      at Module._wasm_sapi_handle_request (/home/projects/stackblitz-starters-9vskuh/node_modules/@php-wasm/node/index.cjs:10278:100)
      at Object.ccall (/home/projects/stackblitz-starters-9vskuh/node_modules/@php-wasm/node/index.cjs:9868:20) {
    cause: RuntimeError: Aborted(). Build with -sASSERTIONS for more info.
        at abort (file:///home/projects/stackblitz-starters-9vskuh/node_modules/@php-wasm/node/index.cjs:3877:13)
        at _abort (file:///home/projects/stackblitz-starters-9vskuh/node_modules/@php-wasm/node/index.cjs:8401:5)
        at zend_mm_panic (wasm://wasm/0274e61e:wasm-function[998]:0x90378)
        at _efree (wasm://wasm/0274e61e:wasm-function[108]:0x810e)
        at php_fopen_primary_script (wasm://wasm/0274e61e:wasm-function[10574]:0x598b84)
        at dynCall_ii (wasm://wasm/0274e61e:wasm-function[12114]:0x631c7a)
        at ret.<computed> (file:///home/projects/stackblitz-starters-9vskuh/node_modules/@php-wasm/node/index.cjs:9698:33)
        at runtime.asm.<computed> (file:///home/projects/stackblitz-starters-9vskuh/node_modules/@php-wasm/node/index.cjs:66760:18)
        at invoke_ii (file:///home/projects/stackblitz-starters-9vskuh/node_modules/@php-wasm/node/index.cjs:10428:14)
        at wasm_sapi_handle_request (wasm://wasm/0274e61e:wasm-function[9259]:0x532881),
    betterMessage: 'Aborted(). Build with -sASSERTIONS for more info.'
  }
}

As I said, I would really like to get it running. I have a class coming next term that I would like to use with stackblitz.

@rhildred
Copy link

rhildred commented Sep 23, 2023

I have an express server that works for a get on stackblitz, using @php-wasm/node:

import express from 'express';
import { NodePHP } from '@php-wasm/node';

const app = express();

app.get(/\.php$/, async (req, res) => {
  const php = await NodePHP.load('8.2', {
    emscriptenOptions: {
      ENV: {
        ...process.env,
        TERM: 'xterm',
      },
    },
  });
  php.useHostFilesystem();
  let sUrl = req.path;
  if (sUrl[sUrl.length - 1] == '/') {
    sUrl += 'index.php';
  }
  sUrl = sUrl.replace(/^\//, '');
  const args = [sUrl];

  const originalStdoutWrite = process.stdout.write.bind(process.stdout);
  process.stdout.write = (chunk) => {
    res.write(chunk);
  };
  await php.cli(['php', ...args]);
  res.end();
  process.stdout.write = originalStdoutWrite;
});

const server = app.listen(3001, () =>
  console.log(`listening on ${server.address().port}`)
);

@rhildred
Copy link

I have the feeling that it won't work for post unless we use the cgi version of php. Will dig in to that next.

@adamziel
Copy link
Collaborator Author

@rhildred thank you so much for sharing all these useful details!

I have the feeling that it won't work for post unless we use the cgi version of php.

Interesting! What makes the CGI version special here?

@rhildred
Copy link

the post variables are in the request body (written to stdin after a blank line and the headers) according to the CGI spec. I was thinking that the php cli doesnt' read from stdin. When I read the docs, I see that the cli does read from php://stdin. The request headers are encoded as environment variables in the spec so maybe I am wrong. I am away until Wednesday, so I will check after that.

@adamziel
Copy link
Collaborator Author

adamziel commented Oct 4, 2023

@rhildred You seem to be running into this issue: WordPress/wordpress-playground#416

About CGI and to clarify how Playground works. Playground uses a custom SAPI, see php_wasm.c. Request body is passed from JavaScript using the internal #setRequestBody method.

@rhildred
Copy link

rhildred commented Oct 5, 2023

Wow! #setRequestBody could be a project saver! I am just getting back to it now. I really had hoped to be ready to launch my browser based prototyping product and be in selling mode now. A quick win with wordpress would be a big help right now. I also have students that need it for a class next (January) term.

@rhildred
Copy link

rhildred commented Oct 5, 2023

I found out how wp.run uses wp.#setRequestBody and got it working with wp.run on stackblitz and on vslite.dev. Now it comes with a php error:

Warning: Undefined array key "path" in /var/www/html/wp-includes/canonical.php on line 705

the working code is mostly taken from startServer.ts:

const requestBodyToString = async (req) =>
	await new Promise((resolve) => {
		let body = '';
		req.on('data', (chunk) => {
			body += chunk.toString(); // convert Buffer to string
		});
		req.on('end', () => {
			resolve(body);
		});
	});



const phpHandler = async (req, res) => {
    const php = await NodePHP.load('8.2', {
        emscriptenOptions: {
            ENV: {
                ...process.env,
                TERM: 'xterm',
            },
        },
    });
    php.useHostFilesystem();
    try {
        const requestHeaders = {};
        if (req.rawHeaders && req.rawHeaders.length) {
            for (let i = 0; i < req.rawHeaders.length; i += 2) {
                requestHeaders[req.rawHeaders[i].toLowerCase()] =
                    req.rawHeaders[i + 1];
            }
        }

        const body = requestHeaders['content-type']?.startsWith(
            'multipart/form-data'
        )
            ? requestBodyToMultipartFormData(
                req.body,
                requestHeaders['content-type'].split('; boundary=')[1]
            )
            : await requestBodyToString(req);
        let sUrl = req.path;
        if (sUrl[sUrl.length - 1] == '/') {
            sUrl += 'index.php';
        }
        sUrl = sUrl.replace(/^\//, '');
        const data = {
            url: req.url,
            headers: requestHeaders,
            method: req.method,
            files: Object.fromEntries(
                Object.entries((req).files || {}).map (
                    ([key, file]) => [
                        key,
                        {
                            key,
                            name: file.name,
                            size: file.size,
                            type: file.mimetype,
                            arrayBuffer: () => file.data.buffer,
                        },
                    ]
                )
            ),
            body: body,
            scriptPath: sUrl,
        };
        const resp = await php.run(data);
        res.statusCode = resp.httpStatusCode;
        Object.keys(resp.headers).forEach((key) => {
            res.setHeader(key, resp.headers[key]);
        });
        res.end(resp.bytes);
    } catch (e) {
        console.log(e);
    }

}

app.get(/\.php$/, async (req, res) => {
    return phpHandler(req, res);
});

app.get("/", async (req, res) => {
    return phpHandler(req, res);
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Something isn't working wp-now
Projects
None yet
Development

No branches or pull requests

2 participants