【问题标题】:PHP prepared sql statement breaks when calling column with special chars使用特殊字符调用列时 PHP 准备的 sql 语句中断
【发布时间】:2017-12-26 18:32:45
【问题描述】:

我正在调用一个 php 脚本,每次我调用一个列时都会中断(其中包含一个 url,例如 http://www.sample.com/something)。

我得到的错误是 PHP 致命错误:允许的内存大小为 134217728 字节已用尽(尝试分配 4294967296 字节)

我不想通过扩展内存来解决问题,我怀疑无论如何都会解决问题。

我尝试执行准备好的语句后出现问题(在这行代码之后我的脚本中断$stmt->execute();

问题肯定是因为我的网址列中的斜杠字符“/”。如果我调用没有“/”符号的任何其他列,则该语句将正确执行并呈现数据。

这是我的更多代码:

$stmt = $conn->prepare("
SELECT post.id, content_cite, url FROM post, data 
WHERE post.id = data.post_FK AND data.age < ? AND data.age <> ?");


$stmt->bind_param("ii", $one, $two);

// params
$one = 35;
$two = 0;
$stmt->execute();

// select header params
$stmt->bind_result($col_1, $col_2, $col_3);
while ($stmt->fetch()) {
    $json = array(
        'id' => $col_1,
        'content_cite' => $col_2,
        'url'=> $col_3

    );

    array_push($contentArray, $json);
}

正如我所说,url 列是问题所在。如果此语句在 SQL 编辑器中运行,则它会毫无问题地执行。

有什么想法吗?

【问题讨论】:

  • url 的列类型是什么? longtext?
  • 哪种字符串类型? varchar?斑点?文本?等等?
  • longtext,对不起各位...这会导致问题吗?
  • 哦,我知道@CMiller 要去哪里了。如果您在LONGTEXT 上使用bindResult(),PHP 不知道其中可能会转储多大的结果,因此它会尝试分配最大大小的内存段来容纳它。对于LONGTEXT,这是 4GB。跳过 bindResult() 并在循环中使用 $row = fetch()
  • 天啊,我从来没有想过!我会努力解决这个问题... tnx 计算机科学的家伙...

标签: php mysql sql prepared-statement


【解决方案1】:

我看不到 / 字符与此有关,但我敢打赌 url 列比您尝试过的其他列大,因此检索其中许多可能会让您失望内存限制。

尝试改变:

FROM post, data 
WHERE post.id = data.post_FK

收件人:

FROM post INNER JOIN data 
  ON post.id = data.post_FK

为了更高效的JOIN 操作。

【讨论】:

  • 好的,我会尝试,但不确定为什么会导致问题,因为当我使用没有准备好的语句的 php 脚本执行时,它可以工作......
  • @Sammitch。我一直认为两者之间的唯一区别只是语法。不知道表现五花八门。现在我对它很感兴趣。有什么地方可以读到这个吗?
  • @CMiller 在我的脑海中无处不在,但是使用 JOIN 的原始形式,您完全依赖于查询优化器捕获条件并在内部将其更改为INNER JOIN。如果它不聪明,[mysql 经常出现这种情况],它将执行FULL JOIN [又名将post 中的每一列与data 中的每一列] 和 then 取 N ^2 结果集并在 WHERE 子句中对其进行过滤。 @CMiller 发现了问题的实际原因,但更明确地使用 JOIN 语法是你应该养成的习惯。
  • 非常酷。如果我过去有点懒惰并且不知道这一点,我可能不得不重新审视一些查询。我现在使用 INNER JOIN 命令,但它更便于阅读,并且有很多我没有的旧代码。
  • OP 当前使用的隐式连接并不比您推荐的显式连接效率低/效率高。所有 RDMS 都应该有相同的执行计划。见Inner join vs Where。但 OP 仍应使用 JOIN,因为它是当前标准并且有助于提高可读性。
【解决方案2】:
  • 无需释放/放弃bind_param
  • 不需要 INNER JOIN 而不是 WHERE

这样就解决了问题:

 $stmt = $conn->prepare("
    SELECT post.id, content_cite, url FROM post, data 
    WHERE post.id = data.post_FK AND data.age < ? AND data.age <> ?");


    $stmt->bind_param("ii", $one, $two);

    // params
    $one = 35;
    $two = 0;
    $stmt->execute();


// if you have longtext as a type in your database you must call this method
        mysqli_stmt_store_result($stmt);


$stmt->bind_result($col_1, $col_2, $col_3);
    while ($stmt->fetch()) {
         $json = array(
            'id' => $col_1,
            'content_cite' => $col_2,
            'url'=> $col_3

        );

        array_push($contentArray, $json);
    }

Tnx Prepared mysqli select statement on longtext field is coming back empty

【讨论】:

  • 不需要 INNER JOIN 而不是 WHERE ...您当前使用的是隐式连接,而不是显式连接 25 年前引入的当前 ANSI SQL 标准。它不会影响性能,但会影响可读性和可维护性。见Inner join vs Where
  • 我知道先生,我知道 where 和 inner join 对我的问题没有任何影响(也不会对任何其他问题产生影响)只是想指出这一点我的回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-06-26
  • 2014-10-31
  • 2021-10-24
  • 2011-09-22
  • 1970-01-01
  • 2020-05-03
相关资源
最近更新 更多