prod/native/phpbridge_extension/code/BridgeModuleFunctions.cpp (306 lines of code) (raw):

/* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch B.V. licenses this file to you under * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include "BridgeModuleFunctions.h" #include "BridgeModuleGlobals.h" #include "AutoZval.h" #include "PhpBridge.h" #include <main/php.h> #include <Zend/zend_API.h> PHP_FUNCTION(detectOpcachePreload) { BRIDGE_G(globals)->logger->printf(LogLevel::logLevel_info, "detectOpcachePreload: %d", BRIDGE_G(globals)->bridge.detectOpcachePreload()); } PHP_FUNCTION(isOpcacheEnabled) { BRIDGE_G(globals)->logger->printf(LogLevel::logLevel_info, "isOpcacheEnabled: %d", BRIDGE_G(globals)->bridge.isOpcacheEnabled()); } PHP_FUNCTION(getExtensionList) { auto extensions = BRIDGE_G(globals)->bridge.getExtensionList(); for (auto const &extension : extensions) { BRIDGE_G(globals)->logger->printf(LogLevel::logLevel_info, "name: '%s' version: '%s'", extension.name.c_str(), extension.version.c_str()); } } PHP_FUNCTION(getPhpInfo) { auto info = BRIDGE_G(globals)->bridge.getPhpInfo(); BRIDGE_G(globals)->logger->printf(LogLevel::logLevel_info, "PHP-INFO: %s", info.c_str()); } PHP_FUNCTION(getPhpSapiName) { auto info = BRIDGE_G(globals)->bridge.getPhpSapiName(); RETURN_STRINGL(info.data(), info.length()); } PHP_FUNCTION(compileAndExecuteFile) { char *fileName = nullptr; size_t fileNameLen = 0; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(fileName, fileNameLen) ZEND_PARSE_PARAMETERS_END(); try { BRIDGE_G(globals)->bridge.compileAndExecuteFile(std::string_view(fileName, fileNameLen)); } catch (std::exception const &msg) { BRIDGE_G(globals)->logger->printf(LogLevel::logLevel_error, "Native exception caught: '%s'", msg.what()); } } PHP_FUNCTION(findClassEntry) { char *className = nullptr; size_t classNameLen = 0; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(className, classNameLen) ZEND_PARSE_PARAMETERS_END(); BRIDGE_G(globals)->logger->printf(LogLevel::logLevel_info, "findClassEntry found: %d", static_cast<bool>(elasticapm::php::findClassEntry(std::string_view(className, classNameLen)))); } PHP_FUNCTION(getClassStaticPropertyValue) { char *className = nullptr; size_t classNameLen = 0; char *propName = nullptr; size_t propNameLen = 0; ZEND_PARSE_PARAMETERS_START(2, 2) Z_PARAM_STRING(className, classNameLen) Z_PARAM_STRING(propName, propNameLen) ZEND_PARSE_PARAMETERS_END(); auto ce = elasticapm::php::findClassEntry(std::string_view(className, classNameLen)); if (!ce) { BRIDGE_G(globals)->logger->printf(LogLevel::logLevel_info, "getClassStaticPropertyValue class not found"); RETURN_NULL(); return; } auto prop = elasticapm::php::getClassStaticPropertyValue(ce, std::string_view(propName, propNameLen)); if (!prop) { BRIDGE_G(globals)->logger->printf(LogLevel::logLevel_info, "getClassStaticPropertyValue property not found"); RETURN_NULL(); return; } RETURN_COPY(prop); } PHP_FUNCTION(getClassPropertyValue) { char *className = nullptr; size_t classNameLen = 0; char *propName = nullptr; size_t propNameLen = 0; zval *object = nullptr; ZEND_PARSE_PARAMETERS_START(3, 3) Z_PARAM_STRING(className, classNameLen) Z_PARAM_STRING(propName, propNameLen) Z_PARAM_ZVAL(object) ZEND_PARSE_PARAMETERS_END(); auto ce = elasticapm::php::findClassEntry(std::string_view(className, classNameLen)); if (!ce) { BRIDGE_G(globals)->logger->printf(LogLevel::logLevel_info, "getClassPropertyValue class not found"); RETURN_NULL(); return; } auto prop = elasticapm::php::getClassPropertyValue(ce, object, std::string_view(propName, propNameLen)); if (!prop) { BRIDGE_G(globals)->logger->printf(LogLevel::logLevel_info, "getClassPropertyValue property not found"); RETURN_NULL(); return; } RETURN_COPY(prop); } PHP_FUNCTION(callMethod) { char *methodName = nullptr; size_t methodNameLen = 0; zval *object = nullptr; HashTable *args = nullptr; zval returnValue; ZEND_PARSE_PARAMETERS_START(3, 3) Z_PARAM_ZVAL(object) Z_PARAM_STRING(methodName, methodNameLen) Z_PARAM_ARRAY_HT(args) ZEND_PARSE_PARAMETERS_END(); zend_string *key; zval *value; std::vector<elasticapm::php::AutoZval> argsZval; argsZval.resize(zend_hash_num_elements(args)); size_t index = 0; ZEND_HASH_FOREACH_STR_KEY_VAL(args, key, value) { (void)key; ZVAL_COPY(argsZval[index].get(), value); index++; } ZEND_HASH_FOREACH_END(); bool rv = elasticapm::php::callMethod(object, std::string_view(methodName, methodNameLen), argsZval.data()->get(), argsZval.size(), &returnValue); BRIDGE_G(globals)->logger->printf(LogLevel::logLevel_info, "callMethod rv: %d", rv); RETURN_COPY(&returnValue); } PHP_FUNCTION(isObjectOfClass) { char *className = nullptr; size_t classNameLen = 0; zval *object = nullptr; ZEND_PARSE_PARAMETERS_START(2, 2) Z_PARAM_STRING(className, classNameLen) Z_PARAM_ZVAL(object) ZEND_PARSE_PARAMETERS_END(); RETURN_BOOL(elasticapm::php::isObjectOfClass(object, std::string_view(className, classNameLen))); } PHP_FUNCTION(getFunctionName) { elasticapm::php::AutoZval zv; long framesBack = 0; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_LONG(framesBack) ZEND_PARSE_PARAMETERS_END(); auto execData = EG(current_execute_data); for (auto frame = 0; frame < framesBack; ++frame) { execData = execData->prev_execute_data; if (!execData) { BRIDGE_G(globals)->logger->printf(LogLevel::logLevel_error, "test failure, can't go %d frames back", framesBack); RETURN_NULL(); return; } } elasticapm::php::getFunctionName(zv.get(), execData); RETURN_COPY(zv.get()); } PHP_FUNCTION(getFunctionDeclaringScope) { elasticapm::php::AutoZval zv; long framesBack = 0; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_LONG(framesBack) ZEND_PARSE_PARAMETERS_END(); auto execData = EG(current_execute_data); for (auto frame = 0; frame < framesBack; ++frame) { execData = execData->prev_execute_data; if (!execData) { BRIDGE_G(globals)->logger->printf(LogLevel::logLevel_error, "test failure, can't go %d frames back", framesBack); RETURN_NULL(); return; } } elasticapm::php::getFunctionDeclaringScope(zv.get(), execData); RETURN_COPY(zv.get()); } PHP_FUNCTION(getFunctionDeclarationFileName) { elasticapm::php::AutoZval zv; long framesBack = 0; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_LONG(framesBack) ZEND_PARSE_PARAMETERS_END(); auto execData = EG(current_execute_data); for (auto frame = 0; frame < framesBack; ++frame) { execData = execData->prev_execute_data; if (!execData) { BRIDGE_G(globals)->logger->printf(LogLevel::logLevel_error, "test failure, can't go %d frames back", framesBack); RETURN_NULL(); return; } } elasticapm::php::getFunctionDeclarationFileName(zv.get(), execData); RETURN_COPY(zv.get()); } PHP_FUNCTION(getFunctionDeclarationLineNo) { elasticapm::php::AutoZval zv; long framesBack = 0; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_LONG(framesBack) ZEND_PARSE_PARAMETERS_END(); auto execData = EG(current_execute_data); for (auto frame = 0; frame < framesBack; ++frame) { execData = execData->prev_execute_data; if (!execData) { BRIDGE_G(globals)->logger->printf(LogLevel::logLevel_error, "test failure, can't go %d frames back", framesBack); RETURN_NULL(); return; } } elasticapm::php::getFunctionDeclarationLineNo(zv.get(), execData); RETURN_COPY(zv.get()); } PHP_FUNCTION(getCallArguments) { elasticapm::php::AutoZval zv; long framesBack = 0; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_LONG(framesBack) ZEND_PARSE_PARAMETERS_END(); auto execData = EG(current_execute_data); for (auto frame = 0; frame < framesBack; ++frame) { execData = execData->prev_execute_data; if (!execData) { BRIDGE_G(globals)->logger->printf(LogLevel::logLevel_error, "test failure, can't go %d frames back", framesBack); RETURN_NULL(); return; } } elasticapm::php::getCallArguments(zv.get(), execData); RETURN_COPY(zv.get()); } PHP_FUNCTION(getScopeNameOrThis) { elasticapm::php::AutoZval zv; long framesBack = 0; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_LONG(framesBack) ZEND_PARSE_PARAMETERS_END(); auto execData = EG(current_execute_data); for (auto frame = 0; frame < framesBack; ++frame) { execData = execData->prev_execute_data; if (!execData) { BRIDGE_G(globals)->logger->printf(LogLevel::logLevel_error, "test failure, can't go %d frames back", framesBack); RETURN_NULL(); return; } } elasticapm::php::getScopeNameOrThis(zv.get(), execData); RETURN_COPY(zv.get()); } PHP_FUNCTION(getExceptionName) { zval *object = nullptr; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ZVAL(object) ZEND_PARSE_PARAMETERS_END(); auto name = elasticapm::php::getExceptionName(Z_OBJ_P(object)); RETURN_STRINGL(name.data(), name.length()); } PHP_FUNCTION(getCurrentException) { zend_object *object = nullptr; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_OBJ(object) ZEND_PARSE_PARAMETERS_END(); elasticapm::php::AutoZval zv; elasticapm::php::getCurrentException(zv.get(), object); RETURN_COPY(zv.get()); } PHP_FUNCTION(getCompiledFiles) { BRIDGE_G(globals)->bridge.getCompiledFiles([](std::string_view file) { BRIDGE_G(globals)->logger->printf(LogLevel::logLevel_info, PRsv, PRsvArg(file)); }); RETURN_NULL(); } PHP_FUNCTION(getNewlyCompiledFiles) { long lastClass = 0; long lastFunction = 0; ZEND_PARSE_PARAMETERS_START(2, 2) Z_PARAM_LONG(lastClass) Z_PARAM_LONG(lastFunction) ZEND_PARSE_PARAMETERS_END(); auto [retLastClass, retLastFunc] = BRIDGE_G(globals)->bridge.getNewlyCompiledFiles([](std::string_view file) { BRIDGE_G(globals)->logger->printf(LogLevel::logLevel_info, PRsv, PRsvArg(file)); }, lastClass, lastFunction); zval zlastClass, zlastFunc; ZVAL_LONG(&zlastClass, retLastClass); ZVAL_LONG(&zlastFunc, retLastFunc); RETURN_ARR(zend_new_pair(&zlastClass, &zlastFunc)); } PHP_FUNCTION(getPhpVersionMajorMinor) { auto [major, minor] = BRIDGE_G(globals)->bridge.getPhpVersionMajorMinor(); zval zMajor, zMinor; ZVAL_LONG(&zMajor, major); ZVAL_LONG(&zMinor, minor); RETURN_ARR(zend_new_pair(&zMajor, &zMinor)); } ZEND_BEGIN_ARG_INFO(no_paramters_arginfo, 0) ZEND_END_ARG_INFO() // clang-format off const zend_function_entry phpbridge_functions[] = { PHP_FE( detectOpcachePreload, no_paramters_arginfo ) PHP_FE( isOpcacheEnabled, no_paramters_arginfo ) PHP_FE( getExtensionList, no_paramters_arginfo ) PHP_FE( getPhpInfo, no_paramters_arginfo ) PHP_FE( getPhpSapiName, no_paramters_arginfo ) PHP_FE( compileAndExecuteFile, no_paramters_arginfo ) PHP_FE( findClassEntry, no_paramters_arginfo ) PHP_FE( getClassStaticPropertyValue, no_paramters_arginfo ) PHP_FE( getClassPropertyValue, no_paramters_arginfo ) PHP_FE( callMethod, no_paramters_arginfo ) PHP_FE( isObjectOfClass, no_paramters_arginfo ) PHP_FE( getFunctionName, no_paramters_arginfo ) PHP_FE( getFunctionDeclaringScope, no_paramters_arginfo ) PHP_FE( getFunctionDeclarationFileName, no_paramters_arginfo ) PHP_FE( getFunctionDeclarationLineNo, no_paramters_arginfo ) PHP_FE( getCallArguments, no_paramters_arginfo ) PHP_FE( getScopeNameOrThis, no_paramters_arginfo ) PHP_FE( getExceptionName, no_paramters_arginfo ) PHP_FE( getCurrentException, no_paramters_arginfo ) PHP_FE( getCompiledFiles, no_paramters_arginfo ) PHP_FE( getNewlyCompiledFiles, no_paramters_arginfo ) PHP_FE( getPhpVersionMajorMinor, no_paramters_arginfo ) PHP_FE_END }; // clang-format on