You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何阻止PHP eval执行用户代码时因die退出程序?

解决用户代码执行die/exit导致统计逻辑中断的方案

方案1:注册脚本终止回调(推荐)

PHP的register_shutdown_function()可以注册一个在脚本终止时自动执行的函数——无论脚本是正常结束、调用die/exit,还是触发致命错误。我们可以把统计执行时间、收集输出、返回响应的核心逻辑放到这个回调里,确保用户代码的终止操作不会打断后续统计。

修改后的完整代码示例:

<?php

$path = $_SERVER['DOCUMENT_ROOT'];
require_once $path . '/wp-load.php';

require WP_PLUGIN_DIR . '/php-editor/vendor/autoload.php';

$output = [];
$data = json_decode( file_get_contents( "php://input" ), true );

// 调整错误输出设置
error_reporting(E_ALL ^ E_WARNING);
ini_set('display_errors', true);

if ( $data['data'] ) {
    ob_start();
    $start_time = microtime(1);
    
    // 注册终止回调,引用外部变量确保能访问统计所需数据
    register_shutdown_function(function() use (&$output, $start_time) {
        // 收集输出内容与统计数据
        $output['output'] = ob_get_contents();
        $output['execution_time'] = number_format(microtime(1) - $start_time, 2, '.', '') * 100 . 'ms';
        $output['buffer_length'] = number_format((float)ob_get_length(), 0, ',', '.') . 'B';
        ob_end_clean();

        // 返回格式化后的JSON响应
        echo json_encode($output, JSON_PRETTY_PRINT);
    });

    try {
        // 执行用户提交的代码
        eval( $data['data'] );
    } catch (\Exception $e) {
        $output['error'] = $e->getMessage();
    }    
} 

该方案无需依赖额外扩展,兼容性强,能覆盖所有脚本终止场景。

方案2:重定义die/exit函数(需扩展支持)

如果服务器安装了runkit扩展,可以通过runkit_function_redefine()重定义die和exit函数,让它们仅标记终止状态而非直接中断脚本,从而保留后续统计逻辑的执行机会。不过此方案依赖特定扩展,通用性不如方案1。

示例代码(需runkit扩展):

<?php
// 其他初始化代码...

if ( $data['data'] ) {
    ob_start();
    $start_time = microtime(1);
    $user_code_terminated = false;

    // 重定义die函数
    runkit_function_redefine('die', function($message = '') use (&$user_code_terminated) {
        $user_code_terminated = true;
        if (!empty($message)) {
            echo $message;
        }
    });

    // 重定义exit函数(与die逻辑一致)
    runkit_function_redefine('exit', function($message = '') use (&$user_code_terminated) {
        $user_code_terminated = true;
        if (!empty($message)) {
            echo $message;
        }
    });

    try {
        eval( $data['data'] );
    } catch (\Exception $e) {
        $output['error'] = $e->getMessage();
    }

    // 无论用户代码是否终止,都执行统计与响应逻辑
    $output['output'] = ob_get_contents();
    $output['execution_time'] = number_format(microtime(1) - $start_time, 2, '.', '') * 100 . 'ms';
    $output['buffer_length'] = number_format((float)ob_get_length(), 0, ',', '.') . 'B';
    ob_end_clean();

    echo json_encode($output, JSON_PRETTY_PRINT);
}

补充说明

  • 方案1的回调函数会在所有脚本执行流程结束后触发,即使用户代码抛出未捕获的非Exception类致命错误,也能通过error_get_last()捕获错误信息并补充到响应中。
  • 注意回调函数中需通过use关键字正确引用外部变量,避免变量作用域问题。

内容的提问来源于stack exchange,提问作者Maramal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 05:34:54