oraoto / pib

PHP in Browser (powered by WebAssembly)
https://oraoto.github.io/pib/
Apache License 2.0
953 stars 109 forks source link

how to get error message from zend_eval_string? #27

Open audiorecorder opened 5 years ago

audiorecorder commented 5 years ago

I tried in several ways but failed. Is there any other good way?

#include "sapi/embed/php_embed.h"
#include "zend.h"
#include "zend_interfaces.h"
#include <emscripten.h>
#include <stdlib.h>

/*int EMSCRIPTEN_KEEPALIVE pib_eval(char *code) {
    int ret = 0;
    putenv("USE_ZEND_ALLOC=0");
    PHP_EMBED_START_BLOCK(0, NULL)
        ret = zend_eval_string(code, NULL, "PIB");
    PHP_EMBED_END_BLOCK()
    return ret;
}*/

zend_class_entry *default_exception_ce;
char * exception_error(zval *exception, int severity TSRMLS_DC) {
    char * result;
    zend_class_entry *ce_exception = Z_OBJCE_P(exception);
    if (instanceof_function(ce_exception, default_exception_ce TSRMLS_CC)) {
        zval *str, *file, *line;
    zval rv;

        EG(exception) = NULL;
        zend_call_method(&exception, ce_exception, NULL, "__tostring", 10, &str, 0, NULL, NULL TSRMLS_CC);
        if (!EG(exception)) {
            if (Z_TYPE_P(str) != IS_STRING) {
                result = "Exception::__toString() must return a string";
            } else {
                zend_update_property_string(default_exception_ce, exception, "string", sizeof("string")-1, EG(exception) ? ce_exception->name : Z_STRVAL_P(str) TSRMLS_CC);
            }
        }
        zval_ptr_dtor(&str);

        if (EG(exception)) {
            /* do the best we can to inform about the inner exception */
            if (instanceof_function(ce_exception, default_exception_ce TSRMLS_CC)) {
                file = zend_read_property(default_exception_ce, EG(exception), "file", sizeof("file")-1, 1 TSRMLS_CC, &rv);
                line = zend_read_property(default_exception_ce, EG(exception), "line", sizeof("line")-1, 1 TSRMLS_CC, &rv);
            } else {
                file = NULL;
                line = NULL;
            }
            result = "Uncaught in exception handling during call to __tostring()";
        }

        str = zend_read_property(default_exception_ce, exception, "string", sizeof("string")-1, 1 TSRMLS_CC, &rv);
        file = zend_read_property(default_exception_ce, exception, "file", sizeof("file")-1, 1 TSRMLS_CC, &rv);
        line = zend_read_property(default_exception_ce, exception, "line", sizeof("line")-1, 1 TSRMLS_CC, &rv);

        result = "Uncaught %s\n  thrown";
    } else {
        size_t n = snprintf(NULL, 0, "Uncaught exception '%s'", ce_exception->name);
        result = malloc(n + 1);
        snprintf(result, n + 1, "Uncaught exception '%s'", ce_exception->name);
    }
    return result;
}

char * EMSCRIPTEN_KEEPALIVE pib_eval(char *code) {
    char *result = NULL;
    putenv("USE_ZEND_ALLOC=0");
    PHP_EMBED_START_BLOCK(0, NULL)

    zend_first_try {
        zend_eval_string(code, NULL, "PIB" TSRMLS_CC);
    } zend_catch {
        if (PG(last_error_message)) {
            result = strdup(PG(last_error_message));
            free(PG(last_error_message));
            PG(last_error_message) = NULL;
        }

/*        if (PG(last_error_message)) {
            result = strdup(PG(last_error_message));
            free(PG(last_error_message));
            PG(last_error_message) = NULL;
        }

        if (!result && EG(exception)) {
            result = exception_error(EG(exception), E_ERROR TSRMLS_CC);
            EG(exception) = NULL;
        }*/

    if(!result){
        result="No Error."; 
    }
    } zend_end_try();

    PHP_EMBED_END_BLOCK()
    return result;
}
TysonAndre commented 4 years ago

I encountered the same issue when working on a fork of pib used as a demo of an application written in php. https://github.com/phan/demo/commit/9aee19e82016e03b0c84fece3559fd1648579a4b#diff-36895ff0c01bd9f24c9c22438b7f7414 has the relevant INI settings that need to be changed. I can create a PR for that patch if the maintainers think it's useful.

    // Show fatal E_COMPILE_ERRORs and other errors properly (startup errors are normally hidden)
    PG(display_startup_errors)=1;
    PG(during_request_startup)=0;