PHP 页面 output/echo 始终为空,没有生成错误日志

PHP page output/echo always null, no generated error logs

我正在尝试创建一个可以用作 REST API 的极其基本的脚本。我在页面上显示任何输出时遇到了很多麻烦。在下面的代码中,您可以看到我尝试获取输出的几个注释方法。如果我删除 printf while 循环并只使用 responseData = json_encode($result) 行,我会得到一个格式正确但只包含空值的 JSON 输出。 (Table 列具有适当命名的 table headers 但没有别的,没有数据返回)。作为记录,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();
    }
?>

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

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


由于 assoc[=91=,数据库访问似乎存在一些问题(mysqli-获取的混合形式)和潜在的错误预期]iative 与 numeric 结果($row[0]$row[1] 尝试在 assoc 模式下)。最后,整套Mysqliconnect/prepare/query/fetch-calls被known goodPDO变体替换;即:

    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-变体本身无法修复。问题并不明显。

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

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

乍一看这看起来不错,但是 parse_str() 函数产生 没有 return 值 。它实际上将结果注入第二个参数,在本例中是一个名为 $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 **/

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

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);