void PHPQt5::zif_emit(INTERNAL_FUNCTION_PARAMETERS) { #ifdef PQDEBUG PQDBG_LVL_START(__FUNCTION__); #endif QString className = ""; void *TSRMLS_CACHE = tsrm_get_ls_cache(); zend_object *zo = zend_get_this_object(EG(current_execute_data)); if(zo && zo->ce) { zval zobject; ZVAL_OBJ(&zobject, zo); if(pq_test_ce(&zobject PQDBG_LVL_CC)) { className = QString(Z_OBJCE_NAME(zobject)); char *signal_signature; int signal_signature_len; zval *args; if(zend_parse_parameters(ZEND_NUM_ARGS(), "sa", &signal_signature, &signal_signature_len, &args) == FAILURE) { PQDBG_LVL_DONE(); return; } QObject *qo = Q_NULLPTR;//objectFactory()->getQObject(&zobject); if(qo != nullptr) { bool haveSignalConnection = false; bool haveSignal = false; QByteArray signalSignature(signal_signature); signalSignature.replace(",string",",QString") .replace("string,","QString,") .replace("(string)","(QString)"); if(!QMetaObject::invokeMethod(qo, "haveSignal", Qt::DirectConnection, Q_RETURN_ARG(bool, haveSignal), Q_ARG(QByteArray, signalSignature))) { php_error(E_WARNING, QString("ERROR %1::invokeMethod( haveSignal )") .arg(className) .toUtf8().constData()); } if(!haveSignal) { php_error(E_WARNING, QString("Undefined signal %1::%2") .arg(className) .arg(signal_signature).toUtf8().constData()); RETURN_NULL(); } if(QMetaObject::invokeMethod(qo, "haveSignalConnection", Qt::DirectConnection, Q_RETURN_ARG(bool, haveSignalConnection), Q_ARG(QByteArray, signalSignature))) { if(haveSignalConnection) { #if defined(PQDEBUG) && defined(PQDETAILEDDEBUG) PQDBGLPUP(QString("emit: %1").arg(signal_signature)); #endif pq_emit(qo, signalSignature, args); } #if defined(PQDEBUG) && defined(PQDETAILEDDEBUG) else { #if defined(PQDEBUG) && defined(PQDETAILEDDEBUG) PQDBGLPUP(QString("no have connections for %1").arg(signal_signature)); #endif } #endif } #if defined(PQDEBUG) && defined(PQDETAILEDDEBUG) else {
void PHPQt5ConnectionWorker::process() { #ifdef PQDEBUG PQDBG_LVL_START(__FUNCTION__); #endif if(this->ctx == nullptr) { PQDBGLPUP("tsrm_get_ls_cache"); this->ctx = tsrm_get_ls_cache(); if(!this->ctx) { PQDBGLPUP("tsrm_new_interpreter_context"); this->ctx = tsrm_new_interpreter_context(); PQDBGLPUP("php_request_startup"); php_request_startup(); /* PQDBGLPUP("get interpreter context from thread"); void *TSRMLS_CACHE; bool php_started; QMetaObject::invokeMethod(this->thread(), "get_ls_cache", Qt::DirectConnection, Q_RETURN_ARG(void*, TSRMLS_CACHE)); if(!TSRMLS_CACHE) { php_error(E_ERROR, "Failed getting interpreter context from thread"); } QMetaObject::invokeMethod(this->thread(), "php_started", Qt::DirectConnection, Q_RETURN_ARG(bool, php_started)); PQDBGLPUP(QString("tsrm_set_interpreter_context %1") .arg(reinterpret_cast<quint64>(TSRMLS_CACHE))); this->ctx = TSRMLS_CACHE; tsrm_set_interpreter_context(TSRMLS_CACHE); if(!php_started) { PQDBGLPUP("php_request_startup"); php_request_startup(); QMetaObject::invokeMethod(this->thread(), "set_php_started", Qt::DirectConnection); } //PQDBGLPUP("php_request_startup"); //php_request_startup(); */ } } argc++; // the first argument for PHP-slots it is a PHP-object sender zval function_name, retval, z_receiver; zval *params = new zval[argc]; ZVAL_STRING(&function_name, slotName.constData()); ZVAL_OBJ(&z_receiver, zo_receiver); ZVAL_OBJ(¶ms[0], zo_sender); for(int i = 1; i < argc; i++) { QVariant arg = args.at(i-1); params[i] = PHPQt5::pq_cast_to_zval(arg, true PQDBG_LVL_CC); } #ifdef PQDEBUG PQDBGLPUP(QString("call function (%1)").arg(reinterpret_cast<quint64>(&z_receiver))); #endif //zend_call_method(&z_receiver, Z_OBJCE(z_receiver), NULL, ZEND_STRL("run"), &retval, 0, NULL, NULL); if(call_user_function(nullptr, &z_receiver, &function_name, &retval, argc, params) == FAILURE) { QString s = QString("PHPQt5 could not call method: %1 of class: %2") .arg(Z_STRVAL(function_name)) .arg(Z_OBJCE(z_receiver)->name->val); php_error(E_ERROR, s.toUtf8().constData()); } #ifdef PQDEBUG PQDBGLPUP("dtor params"); #endif for(int i = 1; i < argc; i++) { // do not remove sender! zval_dtor(¶ms[i]); } #ifdef PQDEBUG PQDBGLPUP("dtor temps"); #endif delete params; params = nullptr; zval_dtor(&retval); zval_dtor(&function_name); /* if(createNewCtx) { #ifdef PQDEBUG PQDBGLPUP("php_request_shutdown"); #endif php_request_shutdown(nullptr); #ifdef PQDEBUG PQDBGLPUP("tsrm_free_interpreter_context"); #endif tsrm_free_interpreter_context(ctx); } */ PQDBG_LVL_DONE(); }
int32_t ScriptEngine::executeWebRequest(const std::string& path, BaseLib::HTTP& request, std::shared_ptr<BaseLib::Rpc::ServerInfo::Info>& serverInfo, std::shared_ptr<BaseLib::SocketOperations>& socket) { if(_disposing) return 1; if(!GD::bl->io.fileExists(path)) { GD::out.printError("Error: PHP script \"" + path + "\" does not exist."); return -1; } ts_resource_ex(0, NULL); //Replaces TSRMLS_FETCH() try { zend_file_handle script; script.type = ZEND_HANDLE_FILENAME; script.filename = path.c_str(); script.opened_path = NULL; script.free_filename = 0; zend_homegear_globals* globals = php_homegear_get_globals(); if(!globals) { ts_free_thread(); return -1; } globals->socket = socket.get(); globals->http = &request; if(!tsrm_get_ls_cache()) { GD::out.printCritical("Critical: Error in PHP: No thread safe resource exists (1)."); ts_free_thread(); return -1; } if(!((sapi_globals_struct *) (*((void ***) tsrm_get_ls_cache()))[((sapi_globals_id)-1)])) { GD::out.printCritical("Critical: Error in PHP: No thread safe resource exists (2)."); ts_free_thread(); return -1; } SG(server_context) = (void*)serverInfo.get(); //Must be defined! Otherwise POST data is not processed. SG(sapi_headers).http_response_code = 200; SG(default_mimetype) = nullptr; SG(default_charset) = nullptr; SG(request_info).content_length = request.getHeader()->contentLength; if(!request.getHeader()->contentType.empty()) SG(request_info).content_type = request.getHeader()->contentType.c_str(); SG(request_info).request_method = request.getHeader()->method.c_str(); SG(request_info).proto_num = request.getHeader()->protocol == BaseLib::HTTP::Protocol::http10 ? 1000 : 1001; std::string uri = request.getHeader()->path + request.getHeader()->pathInfo; if(!request.getHeader()->args.empty()) uri.append('?' + request.getHeader()->args); if(!request.getHeader()->args.empty()) SG(request_info).query_string = estrndup(&request.getHeader()->args.at(0), request.getHeader()->args.size()); if(!uri.empty()) SG(request_info).request_uri = estrndup(&uri.at(0), uri.size()); std::string pathTranslated = serverInfo->contentPath.substr(0, serverInfo->contentPath.size() - 1) + request.getHeader()->pathInfo; SG(request_info).path_translated = estrndup(&pathTranslated.at(0), pathTranslated.size()); if (php_request_startup() == FAILURE) { GD::bl->out.printError("Error calling php_request_startup..."); ts_free_thread(); return 1; } php_execute_script(&script); int32_t exitCode = EG(exit_status); if(SG(request_info).query_string) { efree(SG(request_info).query_string); SG(request_info).query_string = nullptr; } if(SG(request_info).request_uri) { efree(SG(request_info).request_uri); SG(request_info).request_uri = nullptr; } if(SG(request_info).path_translated) { efree(SG(request_info).path_translated); SG(request_info).path_translated = nullptr; } php_request_shutdown(NULL); ts_free_thread(); return exitCode; } catch(const std::exception& ex) { GD::bl->out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); } catch(BaseLib::Exception& ex) { GD::bl->out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); } catch(...) { GD::bl->out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); } std::string error("Error executing script. Check Homegear log for more details."); if(socket) php_homegear_write_socket(socket.get(), error.c_str(), error.length()); if(SG(request_info).query_string) { efree(SG(request_info).query_string); SG(request_info).query_string = nullptr; } if(SG(request_info).request_uri) { efree(SG(request_info).request_uri); SG(request_info).request_uri = nullptr; } if(SG(request_info).path_translated) { efree(SG(request_info).path_translated); SG(request_info).path_translated = nullptr; } ts_free_thread(); return 1; }
bool ScriptEngine::checkSessionId(const std::string& sessionId) { if(_disposing) return false; std::unique_ptr<BaseLib::HTTP> request(new BaseLib::HTTP()); ts_resource_ex(0, NULL); //Replaces TSRMLS_FETCH() try { zend_homegear_globals* globals = php_homegear_get_globals(); if(!globals) { ts_free_thread(); return false; } globals->http = request.get(); if(!tsrm_get_ls_cache() || !((sapi_globals_struct *) (*((void ***) tsrm_get_ls_cache()))[((sapi_globals_id)-1)])) { GD::out.printCritical("Critical: Error in PHP: No thread safe resource exists."); ts_free_thread(); return false; } SG(server_context) = (void*)request.get(); //Must be defined! Otherwise POST data is not processed. SG(sapi_headers).http_response_code = 200; SG(default_mimetype) = nullptr; SG(default_charset) = nullptr; SG(request_info).content_length = 0; SG(request_info).request_method = "GET"; SG(request_info).proto_num = 1001; request->getHeader()->cookie = "PHPSESSID=" + sessionId; if (php_request_startup(TSRMLS_C) == FAILURE) { GD::bl->out.printError("Error calling php_request_startup..."); ts_free_thread(); return false; } zval returnValue; zval function; ZVAL_STRING(&function, "session_start"); call_user_function(EG(function_table), NULL, &function, &returnValue, 0, nullptr); bool result = false; zval* reference = zend_hash_str_find(&EG(symbol_table), "_SESSION", sizeof("_SESSION") - 1); if(reference != NULL) { if(Z_ISREF_P(reference) && Z_RES_P(reference)->ptr && Z_TYPE_P(Z_REFVAL_P(reference)) == IS_ARRAY) { zval* token = zend_hash_str_find(Z_ARRVAL_P(Z_REFVAL_P(reference)), "authorized", sizeof("authorized") - 1); if(token != NULL) { result = (Z_TYPE_P(token) == IS_TRUE); } } } php_request_shutdown(NULL); ts_free_thread(); return result; } catch(const std::exception& ex) { GD::bl->out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); } catch(BaseLib::Exception& ex) { GD::bl->out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); } catch(...) { GD::bl->out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); } std::string error("Error executing script. Check Homegear log for more details."); ts_free_thread(); return false; }
void ScriptEngine::execute(const std::string path, const std::string arguments, std::shared_ptr<std::vector<char>> output, int32_t* exitCode, bool wait, int32_t threadId) { try { if(_disposing) { setThreadNotRunning(threadId); return; } if(path.empty()) { //No thread yet return; } if(!output) output.reset(new std::vector<char>()); if(!wait) { collectGarbage(); if(!scriptThreadMaxReached()) { _scriptThreadMutex.lock(); try { int32_t threadId = _currentScriptThreadID++; if(threadId == -1) threadId = _currentScriptThreadID++; _scriptThreads.insert(std::pair<int32_t, std::pair<std::thread, bool>>(threadId, std::pair<std::thread, bool>(std::thread(&ScriptEngine::execute, this, path, arguments, output, nullptr, true, threadId), true))); } catch(const std::exception& ex) { GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); } catch(...) { GD::out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); } _scriptThreadMutex.unlock(); } if(exitCode) *exitCode = 0; //No thread yet return; } } catch(const std::exception& ex) { GD::bl->out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); setThreadNotRunning(threadId); return; } catch(BaseLib::Exception& ex) { GD::bl->out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); setThreadNotRunning(threadId); return; } catch(...) { GD::bl->out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); setThreadNotRunning(threadId); return; } if(exitCode) *exitCode = -1; if(!GD::bl->io.fileExists(path)) { GD::out.printError("Error: PHP script \"" + path + "\" does not exist."); setThreadNotRunning(threadId); return; } ts_resource_ex(0, NULL); //Replaces TSRMLS_FETCH() try { zend_file_handle script; /* Set up a File Handle structure */ script.type = ZEND_HANDLE_FILENAME; script.filename = path.c_str(); script.opened_path = NULL; script.free_filename = 0; zend_homegear_globals* globals = php_homegear_get_globals(); if(!globals) { ts_free_thread(); setThreadNotRunning(threadId); return; } globals->output = output.get(); globals->commandLine = true; globals->cookiesParsed = true; if(!tsrm_get_ls_cache() || !((sapi_globals_struct *) (*((void ***) tsrm_get_ls_cache()))[((sapi_globals_id)-1)]) || !((php_core_globals *) (*((void ***) tsrm_get_ls_cache()))[((core_globals_id)-1)])) { GD::out.printCritical("Critical: Error in PHP: No thread safe resource exists."); ts_free_thread(); setThreadNotRunning(threadId); return; } PG(register_argc_argv) = 1; SG(server_context) = (void*)output.get(); //Must be defined! Otherwise php_homegear_activate is not called. SG(options) |= SAPI_OPTION_NO_CHDIR; SG(headers_sent) = 1; SG(request_info).no_headers = 1; SG(default_mimetype) = nullptr; SG(default_charset) = nullptr; SG(request_info).path_translated = estrndup(path.c_str(), path.size()); if (php_request_startup(TSRMLS_C) == FAILURE) { GD::bl->out.printError("Error calling php_request_startup..."); ts_free_thread(); setThreadNotRunning(threadId); return; } std::vector<std::string> argv = getArgs(path, arguments); php_homegear_build_argv(argv); SG(request_info).argc = argv.size(); SG(request_info).argv = (char**)malloc((argv.size() + 1) * sizeof(char*)); for(uint32_t i = 0; i < argv.size(); ++i) { SG(request_info).argv[i] = (char*)argv[i].c_str(); //Value is not modified. } SG(request_info).argv[argv.size()] = nullptr; php_execute_script(&script); if(exitCode) *exitCode = EG(exit_status); php_request_shutdown(NULL); if(output->size() > 0) { std::string outputString(&output->at(0), output->size()); if(BaseLib::HelperFunctions::trim(outputString).size() > 0) GD::out.printMessage("Script output:\n" + outputString); } } catch(const std::exception& ex) { GD::bl->out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); } catch(BaseLib::Exception& ex) { GD::bl->out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__, ex.what()); } catch(...) { GD::bl->out.printEx(__FILE__, __LINE__, __PRETTY_FUNCTION__); } if(SG(request_info).path_translated) { efree(SG(request_info).query_string); SG(request_info).query_string = nullptr; } if(SG(request_info).argv) { free(SG(request_info).argv); SG(request_info).argv = nullptr; } SG(request_info).argc = 0; ts_free_thread(); setThreadNotRunning(threadId); }