【问题标题】:PHP page output/echo always null, no generated error logsPHP 页面输出/回显始终为空,不生成错误日志
【发布时间】:2025-12-17 14:15:01
【问题描述】:

我正在尝试创建一个可以用作 REST API 的非常基本的脚本。我在页面上显示任何输出时遇到了很多麻烦。在下面的代码中,您可以看到一些我试图获得输出的注释方法。如果我删除 printf while 循环并仅使用 responseData = json_encode($result) 行,我将获得格式正确但仅包含空值的 JSON 输出。 (表列具有适当命名的表头,但没有其他内容,不返回数据)。作为记录,SQL 语句, 被正确执行,没有错误。以下脚本在运行时不会生成 PHP.log 错误。如果我将 SQL 更改为插入语句,我可以在数据库中看到结果值。因此,无论这里发生什么,只是将这些值输出到页面都会出现一些问题。

这是我正在使用的整个页面脚本的代码;

<?php
define("PROJECT_ROOT_PATH", __DIR__);
define("DB_HOST", "localhost");
define("DB_USERNAME", "testuser");
define("DB_PASSWORD", "testpw");
define("DB_DATABASE", "testgb");

$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$uri = explode( '/', $uri );

/** Basic Input Filter **/
    function input_filter($data) {
        $data= trim($data);
        $data= stripslashes($data);
        $data= htmlspecialchars($data);
        return $data;
    }
 
    /**
     * Get URI elements.
     * 
     * @return array
     */
    function getUriSegments()
    {
        $uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
        $uri = explode( '/', $uri );
 
        return $uri;
    }
    
    function sendOutput($data, $httpHeaders=array())
    {
        header_remove('Set-Cookie');
 
        if (is_array($httpHeaders) && count($httpHeaders)) {
            foreach ($httpHeaders as $httpHeader) {
                header($httpHeader);
            }
        }
 
        echo $data;
        exit;
    }
    
    /**
     * "/[usertoken]/read" Endpoint - retrieve orders from db
     */
    
    function readAction()
    {
        $strErrorDesc = '';
        $requestMethod = $_SERVER["REQUEST_METHOD"];
        $arrQueryStringParams = parse_str($_SERVER['QUERY_STRING'], $query);
 
        if (strtoupper($requestMethod) == 'GET') {
            try {
                $intLimit = 100;
                if (isset($arrQueryStringParams['limit']) && $arrQueryStringParams['limit']) {
                    $intLimit = $arrQueryStringParams['limit'];
                }
                $intItemId = 0;
                if (isset($arrQueryStringParams['itemid']) && $arrQueryStringParams['itemid']) {
                    $intItemId = $arrQueryStringParams['itemid'];
                    echo $intItemId;
                }
                $conn = mysqli_connect(DB_HOST, DB_USERNAME, DB_PASSWORD, DB_DATABASE);
                if ($conn->connect_error)
                {
                    die("Connection failed: ". mysqli_connect_error());
                }
                $sql = "SELECT * FROM verified_orders WHERE itemid=?;";
                $stmt = mysqli_stmt_init($conn);

                if (!mysqli_stmt_prepare($stmt, $sql)) {
                    die("Statement preparation failed.");
                } else {

                    mysqli_stmt_bind_param($stmt, "d", $intItemId);
                    mysqli_stmt_execute($stmt);

                    $result = mysqli_stmt_get_result($stmt);
                    if ($row = mysqli_fetch_assoc($result)) {
                        while ($row = $result -> fetch_row()) {
                            printf ("%s (%s)\n", $row[0], $row[1]);
                        }
                    }
                    /*$responseData = json_encode($result);*/
                }
            } catch (Error $e) {
                $strErrorDesc = $e->getMessage().'.';
                $strErrorHeader = 'HTTP/1.1 500 Internal Server Error';
            }
        } else {
            $strErrorDesc = 'Method not supported';
            $strErrorHeader = 'HTTP/1.1 422 Unprocessable Entity';
        }
 
        // send output
        if (!$strErrorDesc) {
            /*echo $responseData;
        } else {
            echo $responseData;*/
        }
    }
    if (isset($uri[2]) && $uri[2] != 'user') {
        header("HTTP/1.1 404 Not Found");
        exit();
    }
    if ($uri[3] == "read") {
        readAction();
    }
?>

【问题讨论】:

    标签: php mysqli


    【解决方案1】:

    数据库 API 变化和误导parse_str()

    更新:最后出现了一些错误,加上缺少日志,导致线程混乱;我已经更新了这个答案事后,以巩固解决方案和实现。


    由于associative vs nummysqli-fetching 的混合形式)和潜在的错误期望/strong>eric 结果($row[0]$row[1]assoc 模式下尝试)。最后,整套 Mysqli 连接/准备/查询/获取调用被 known good PDO 变体替换;即:

        if (!($conn = new PDO(sprintf('mysql:dbname=%s;host=%s', DB_DATABASE, DB_HOST), DB_USERNAME, DB_PASSWORD, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ])))
            throw new Exception('Connection failed');
    
        if (!($stmt = $conn->prepare('
                    SELECT * 
                      FROM verified_orders 
                     WHERE itemid = :itemid
                  ORDER BY itemid
        '))) throw new Exception('Prepare failed');
    
        if (!$stmt->execute([ 'itemid' => $intItemId ]))
            throw new Exception('Execute failed');
    
        if (!($data = $stmt->fetchAll( PDO::FETCH_ASSOC|PDO::FETCH_GROUP|PDO::FETCH_UNIQUE )))
            throw new Exception('Fetch failed');
    

    这并不是说mysqli-variants 本身无法修复。这个问题并不明显。

    PDO 数据库调用解决了大多数问题,但没有解决$intItemId 变量(在 SELECT 查询中使用)中缺少任何值的问题。该变量位于$arrQueryStringParams 的下游,而后者又被设置在此处:

    $arrQueryStringParams = parse_str($_SERVER['QUERY_STRING'], $query);
    

    乍一看这看起来不错,但是parse_str() 函数产生没有返回值。它实际上将结果注入到第二个参数中,在本例中是一个名为 $query 的杂散变量(根本没有在其他任何地方使用过)。

    parse_str() 的正确语法是:

    parse_str($_SERVER['QUERY_STRING'], $arrQueryStringParams);
    

    解决方案的原始尝试


    您正在使用 mysqli_fetch_assoc 获取查询结果(注意 associative)。

    这意味着结果不会以$row[0]$row[1]、... 结尾,而是$row 是基于列名的关联数组,例如$row['itemid']

    题外话:您应该删除 SQL 查询末尾的 ;。它可以是 SQL 脚本命令的一部分,它表示语句的结束,但它不被视为单个查询的一部分。

    更新

    尝试替换

    $result = mysqli_stmt_get_result($stmt);
    if ($row = mysqli_fetch_assoc($result)) {
        while ($row = $result -> fetch_row()) {
            printf ("%s (%s)\n", $row[0], $row[1]);
        }
    }
    

    while ($row = $result->fetch_array(MYSQLI_BOTH)) {
        printf ("%s (%s)\n", $row[0], $row[1]);
    }
    

    看看这是否能解决问题。


    如果没有,则检查日志文件并显示var_dump($x) 的输出$row$result$stmt$conn。 然后在将 SQL 替换为以下内容后再次重复该过程:

    $sql = "SELECT 123 AS num, 'abc' AS str, ? AS inputval";
    

    更新 2

    奇怪的结果,没有任何东西可以继续调试,最好尝试以下方法。 (暂时)删除从该行开始的所有代码:

    /** Basic Input Filter **/
    

    从那里,一直到文件的末尾。基本上只留下你的defines;然后在文件底部复制/粘贴以下内容,然后尝试在您的网络浏览器中访问该页面,看看它打印了什么。

    try {
        echo 'A';
        if (!($conn = new PDO(sprintf('mysql:dbname=%s;host=%s', DB_DATABASE, DB_HOST), DB_USERNAME, DB_PASSWORD, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ])))
            throw new Exception('Connection failed');
        echo 'B';
        if (!($stmt = $conn->prepare('
                    SELECT * 
                      FROM verified_orders 
                     WHERE itemid = :itemid
                        OR 1=1
                  ORDER BY itemid
                     LIMIT 20
        '))) throw new Exception('Prepare failed');
        echo 'C';
        if (!$stmt->execute([ 'itemid' => 1 ]))
            throw new Exception('Execute failed');
        echo 'D';
        if (!($data = $stmt->fetchAll( PDO::FETCH_ASSOC|PDO::FETCH_GROUP|PDO::FETCH_UNIQUE )))
            throw new Exception('Fetch failed');
        echo 'E';
        echo PHP_EOL . '<br>';
        var_dump( $data );
        echo PHP_EOL . '<br>';
        echo 'F';
    } catch (Throwable $e) { echo PHP_EOL . '<br>Exception: ' . htmlentities($e->getMessage()); }
    Exit(0);
    

    【讨论】:

    • 我尝试了其他不使用mysqli_fetch_assoc的方法,你可以在我的代码中看到一些被注释掉的行。当我改为 $result = mysqli_stmt_get_result($stmt); $responseData = json_encode($result); 时,我仍然会返回空值。作为记录,将$row[0] 更改为$row['itemid'] 仍然不会向页面输出任何内容。
    • 我在上面的答案中添加了一些东西
    • 我已经完成了您在此处建议的所有三件事,但它们都不会导致任何不同的事情发生。 var_dump 结果不会显示在日志或页面上。页面仍然是空白,没有输出。日志仍然是空的。
    • 奇怪的东西。我又在答案中添加了另一种方法,如果您还没有找到,请尝试。
    • 在更新 2 中运行代码会产生 ABC Exception: SQLSTATE[HY093]: Invalid parameter number: parameter was not defined 作为旁注,我的数据库中没有 primary_key 或“itemid”为 1 的数据库条目。不确定这是否与引发的错误有关。
    最近更新 更多