ResultCode loadPhpFile()

in agent/native/ext/util_for_PHP.cpp [49:176]


ResultCode loadPhpFile( const char* phpFilePath )
{
    ELASTIC_APM_LOG_DEBUG_FUNCTION_ENTRY_MSG( "phpFilePath: `%s'", phpFilePath );

    ResultCode resultCode;
    zval dummy;
    zend_file_handle file_handle;
    bool should_destroy_file_handle = false;
    zend_string* opened_path = NULL;
    zend_op_array* new_op_array = NULL;
    zval result;
    bool should_dtor_result = false;
    int php_stream_open_for_zend_ex_retVal = FAILURE;
    bool hasThrownException = false;

#if PHP_VERSION_ID >= ELASTIC_APM_BUILD_PHP_VERSION_ID( 8, 1, 0 ) /* if PHP version from 8.1.0 */
    zend_string* phpFilePathAsZendString = nullptr;
#endif

    size_t phpFilePathLen = strlen( phpFilePath );
    if ( phpFilePathLen == 0 )
    {
        ELASTIC_APM_LOG_ERROR( "phpFilePathLen == 0" );
        ELASTIC_APM_SET_RESULT_CODE_AND_GOTO_FAILURE();
    }

    // Copied from
    //      https://github.com/php/php-src/blob/php-8.0.0/ext/spl/php_spl.c
    //      https://github.com/php/php-src/blob/php-8.1.0/ext/spl/php_spl.c
    // the second half of spl_autoload()

#       if PHP_VERSION_ID >= ELASTIC_APM_BUILD_PHP_VERSION_ID( 8, 1, 0 ) /* if PHP version from 8.1.0 */
    phpFilePathAsZendString = zend_string_init( phpFilePath, phpFilePathLen, /* persistent: */ 0 );
    zend_stream_init_filename_ex( &file_handle, phpFilePathAsZendString );
    should_destroy_file_handle = true;
#       endif

    php_stream_open_for_zend_ex_retVal = php_stream_open_for_zend_ex(
#               if PHP_VERSION_ID < ELASTIC_APM_BUILD_PHP_VERSION_ID( 8, 1, 0 ) /* if PHP version before 8.1.0 */
            phpFilePath,
#               endif
            &file_handle
            , USE_PATH|STREAM_OPEN_FOR_INCLUDE );
    if ( php_stream_open_for_zend_ex_retVal != SUCCESS )
    {
        ELASTIC_APM_LOG_ERROR( "php_stream_open_for_zend_ex() failed. Return value: %d. phpFilePath: `%s'", php_stream_open_for_zend_ex_retVal, phpFilePath );
        logDiagnostics_for_failed_php_stream_open_for_zend_ex( phpFilePath );
        ELASTIC_APM_SET_RESULT_CODE_AND_GOTO_FAILURE();
    }
    should_destroy_file_handle = true;

    if ( ! file_handle.opened_path ) {
        file_handle.opened_path =
#               if PHP_VERSION_ID < ELASTIC_APM_BUILD_PHP_VERSION_ID( 8, 1, 0 ) /* if PHP version before 8.1.0 */
            zend_string_init( phpFilePath, phpFilePathLen, /* persistent: */ 0 );
#               else
            zend_string_copy( phpFilePathAsZendString );
#               endif
    }
    opened_path = zend_string_copy( file_handle.opened_path );

    ZVAL_NULL( &dummy );
    if ( ! zend_hash_add( &EG(included_files), opened_path, &dummy ) )
    {
#           if PHP_VERSION_ID < ELASTIC_APM_BUILD_PHP_VERSION_ID( 8, 1, 0 ) /* if PHP version before 8.1.0 */
        zend_file_handle_dtor( &file_handle );
        should_destroy_file_handle = false;
#           endif

        ELASTIC_APM_LOG_ERROR( "zend_hash_add failed. phpFilePath: `%s'", phpFilePath );
        ELASTIC_APM_SET_RESULT_CODE_AND_GOTO_FAILURE();
    }

    new_op_array = zend_compile_file( &file_handle, ZEND_REQUIRE );
    if ( new_op_array == NULL )
    {
        ELASTIC_APM_LOG_ERROR( "zend_compile_file failed. phpFilePath: `%s'", phpFilePath );
        ELASTIC_APM_SET_RESULT_CODE_AND_GOTO_FAILURE();
    }

    ZVAL_UNDEF( &result );
    zend_execute( new_op_array, &result );
    should_dtor_result = true;
    hasThrownException = ( EG( exception ) != NULL );
    destroy_op_array( new_op_array );
    efree( new_op_array );
    if ( hasThrownException )
    {
        should_dtor_result = false;
        ELASTIC_APM_LOG_ERROR( "Exception was thrown during zend_execute(). phpFilePath: `%s'", phpFilePath );
        ELASTIC_APM_SET_RESULT_CODE_AND_GOTO_FAILURE();
    }

    resultCode = resultSuccess;

    finally:

    if ( should_dtor_result )
    {
        zval_ptr_dtor( &result );
    }

    if ( opened_path != NULL )
    {
#           if PHP_VERSION_ID < ELASTIC_APM_BUILD_PHP_VERSION_ID( 7, 3, 0 ) /* if PHP version before 7.3.0 */
        zend_string_release( opened_path );
#else
        zend_string_release_ex( opened_path, /* persistent: */ 0 );
#           endif
        opened_path = NULL;
    }

    if ( should_destroy_file_handle )
    {
        zend_destroy_file_handle( &file_handle );
        should_destroy_file_handle = false;
    }

#       if PHP_VERSION_ID >= ELASTIC_APM_BUILD_PHP_VERSION_ID( 8, 1, 0 ) /* if PHP version from 8.1.0 */
    zend_string_release( phpFilePathAsZendString );
#       endif

    ELASTIC_APM_LOG_DEBUG_RESULT_CODE_FUNCTION_EXIT();
    return resultCode;

    failure:
    goto finally;
}