PHP Apache在执行存储过程时崩溃 问题

PHP Apache在执行存储过程时崩溃 问题,php,mysql,apache,stored-procedures,wamp,Php,Mysql,Apache,Stored Procedures,Wamp,当我执行以下代码时,我调用了一个带有5个IN参数和1个OUT参数的存储过程 $conn->query("SET @res = ''"); $mysqli=$conn; if (!($stmt = $mysqli->prepare("CALL retrieve_matches(5,3, 16, 2, false, @res)"))) { echo "Prepare failed: (" . $mysqli->errno . ") " . $mysqli->erro

当我执行以下代码时,我调用了一个带有5个IN参数和1个OUT参数的存储过程

$conn->query("SET @res = ''");

$mysqli=$conn;
if (!($stmt = $mysqli->prepare("CALL retrieve_matches(5,3, 16, 2, false, @res)"))) {
    echo "Prepare failed: (" . $mysqli->errno . ") " . $mysqli->error;
}

if (!$stmt->execute()) {
    echo "Execute failed: (" . $stmt->errno . ") " . $stmt->error;
}

do {
    if ($res = $stmt->get_result()) { //Apache crash on this call
        printf("---\n");
        var_dump(mysqli_fetch_all($res));
        mysqli_free_result($res);
    } else {
        if ($stmt->errno) {
            echo "Store failed: (" . $stmt->errno . ") " . $stmt->error;
        }
    }
} while ($stmt->more_results() && $stmt->next_result());
apache因错误而崩溃:

AH00428:父进程:子进程9628已退出,状态为255- 重新启动

我试过的 此代码工作正常,并正确返回结果: 注意:如果我只是更改存储过程输入中的数字,则上面导致Apache崩溃的代码也可以正常工作,如下所示:

if (!($stmt = $mysqli->prepare("CALL retrieve_matches(5,6, 16, 2, false, @res)"))) {
从MySQl workbench尝试,两个调用都工作正常。 我在WIN7 Enterprise 64b上使用WAMP 64b,我尝试使用WAMP 32b,但遇到了相同的问题。 我检查了windows事件,发现httpd.exe因php5ts.dll而崩溃 如果你在谷歌上搜索httpd.exe php5ts.dll,你会发现很多人遇到这个问题。但我没有找到解决WAMP的办法。。。 尝试使用AMPS,完全相同的问题 PHP错误日志

[10-Jul-2015 15:30:03 UTC] PHP Warning:  PHP Startup: Unable to load dynamic library 'C:/Program Files/wamp/bin/php/php5.5.12/ext/php_ldap.dll' - Impossibile trovare il modulo specificato.

 in Unknown on line 0

[10-Jul-2015 15:30:04 UTC] PHP Warning:  PHP Startup: Unable to load dynamic library 'C:/Program Files/wamp/bin/php/php5.5.12/ext/php_intl.dll' - Impossibile trovare il modulo specificato.
APACHE错误日志:

[Tue Jul 14 15:02:13.038276 2015] [mpm_winnt:notice] [pid 7044:tid 404] AH00428: Parent: child process 9448 exited with status 255 -- Restarting.
[Tue Jul 14 15:02:13.324305 2015] [mpm_winnt:notice] [pid 7044:tid 404] AH00455: Apache/2.4.9 (Win32) PHP/5.5.12 configured -- resuming normal operations
[Tue Jul 14 15:02:13.329306 2015] [mpm_winnt:notice] [pid 7044:tid 404] AH00456: Apache Lounge VC11 Server built: Mar 16 2014 12:13:13
[Tue Jul 14 15:02:13.329306 2015] [core:notice] [pid 7044:tid 404] AH00094: Command line: 'C:\\Program Files\\wamp\\bin\\apache\\apache2.4.9\\bin\\httpd.exe -d C:/Program Files/wamp/bin/apache/apache2.4.9'
[Tue Jul 14 15:02:13.352308 2015] [mpm_winnt:notice] [pid 7044:tid 404] AH00418: Parent: Created child process 3140
[Tue Jul 14 15:02:14.528388 2015] [mpm_winnt:notice] [pid 3140:tid 332] AH00354: Child: Starting 64 worker threads.
我真的迷路了,我应该去哪里寻找问题? 非常感谢你的帮助

编辑

我意识到存储过程retrieve_matches正在调用不同的存储过程来处理更改后的值。我调试了导致Apache崩溃的存储过程retrieve_standalone。此过程正在执行选择/插入,我已检查并正确插入。 但在我的电脑里,我用了一种奇怪的方式使用光标:

declare bNoMoreRows bool default false;
declare tmp_cursor cursor for
    select comp_id from to_match; -- to_match is a temporary table
declare continue handler for not found set bNoMoreRows := true;
如果我不打开光标

open tmp_cursor;
一切正常!!因此,我想我现在发现了问题:我该如何解决它?

我认为您混淆了$conn和$stmt。这是我的。它将结果收集到$out中

if ($conn->multi_query($call)) {
    $raa = array();
    do {
        /* store first result set */
        if ($result = $conn->use_result()) {
            while ($row = $result->fetch_row()) {
                $raa[] = $row;
                printf("+\n");
            }
            $result->close();
        }
        $out[] = $raa;
        /* print divider */
        if ($conn->more_results()) {
            printf("-----------------\n");
        }
    } while ($conn->next_result());
}
else
    echo "err";

如果每次运行短脚本时php5ts.dll或apache的任何其他部分都以可复制的方式崩溃,那么很可能是php中出现了错误。特别是如果您使用从php.net下载的最新php版本运行最新的apache,那么您很有可能获得php团队的支持。因此,请通读一遍,看看是否可以在不使用apache的情况下在cli上使用php.exe在单独的脚本中运行脚本时重现崩溃,然后可以将其作为bug提交


这样的错误有时可以解决,但很少从脚本的上下文中修复。PHP永远不应该使Web服务器崩溃,如果它重复地这样做,那么应该提交一个bug以便修复它

我知道如何复制它,我相信这是一个PHP/apache bug

PHP代码:

if (!($stmt = $mysqli->prepare("CALL test()"))) {
    echo "Prepare failed: (" . $mysqli->errno . ") " . $mysqli->error;
}

if (!$stmt->execute()) {
    echo "Execute failed: (" . $stmt->errno . ") " . $stmt->error;
}

do {
    if ($res = $stmt->get_result()) {
        printf("---\n");
        //var_dump(mysqli_fetch_all($res));
        var_dump($res->fetch_assoc());
        mysqli_free_result($res);
    } else {
        if ($stmt->errno) {
            echo "Store failed: (" . $stmt->errno . ") " . $stmt->error;
        }
    }
} while ($stmt->more_results() && $stmt->next_result());
存储过程代码:

CREATE DEFINER=`root`@`localhost` PROCEDURE `test`()
BEGIN
declare test_var varchar(100) default "ciao";
declare bNoMoreRows bool default false;
declare test_cursor cursor for
    select id from tmp_folder;
declare continue handler for not found set bNoMoreRows := true;

create temporary table tmp_folder select "test" as id;

open test_cursor;

fetch test_cursor into test_var;

close test_cursor;

select test_var;

drop temporary table if exists tmp_folder;

END
打开的错误: 阿帕奇:


Php:

显然,Php和MySQLi之间存在一些推卸责任的行为,比如scaricabarile

似乎正在发生的事情是,MySQLi的反应方式不正确,并返回一个意外的值,我敢打赌它对PHP来说是一个空值,这会导致coredump。这种行为和PHPland的结论是:不是[PHP]bug。在他们这边,MySQLi的人坚持认为是PHP没有正确地检查返回的结果。“不正确”的结果取决于您的查询

所以我冒着很大的风险,假设你的问题也是沟通困难,那么问题就变成了:你的查询迫使MySQLi放弃/重新连接。为什么会这样?显然是一些存储过程

而mysqli_multi_查询与不兼容

因此,我建议在不准备查询的情况下进行尝试,并使用mysqli\u multi\u查询运行它

有了这段代码,您的测试用例就如预期的那样得到了我的支持

array(1) {
  [0] =>
  string(4) "test"
}

尝试更改服务器堆栈。升级WAMP或在其他环境中运行代码。这个问题表明WAMP中存在一个bug,它将导致Apache抛出255错误


另一只在这里咬灰尘。我只是顺便来提供一个解决办法

只有在使用prepare时,带有光标的SP才会崩溃

如果您将其更改为multi_query call,它将起作用。一种简单可重复的POC

<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = mysqli_connect('127.0.0.1','user','pass','db');

$mysqli->query("DROP PROCEDURE IF EXISTS mysqli_crash");
$mysqli->query("CREATE PROCEDURE mysqli_crash ()
BEGIN
    DECLARE col TEXT;
    DECLARE res CURSOR FOR SELECT 1 from dual;
    OPEN res;
    FETCH res INTO col;
    CLOSE res;
    SELECT 1 from dual;
END;");

echo  "--- multi_query ---\n";

$mysqli->multi_query("call mysqli_crash()");
$result = $mysqli->store_result();
echo json_encode($result->fetch_all(MYSQLI_ASSOC)),"\n";
$mysqli->next_result();

echo  "--- prepare ---\n";

$stmt = $mysqli->prepare("call mysqli_crash()");
$stmt->execute();
$result = $stmt->get_result();
echo json_encode($result->fetch_all(MYSQLI_ASSOC)),"\n";
$stmt->next_result();

是的,首选prepare,但如果存储过程使用游标,则别无选择。

ERR\u CONNECTION\u RESET表示这是浏览器问题,而不是编码问题$stmt->get\u result->fetch\u assoc;假设查询至少返回一行。是吗?如果第一个查询正常,浏览器怎么会出现问题?是$stmt->get\u result->fetch\u assoc;返回至少一行,事实上第一个查询返回第一行的数据err_CONNECTION_RESET是一个chrome问题,与您的代码无关,您可以看到关于该行的各种答案。我会在stmt->execute上设置一个true-false标志,并确保您返回了一些东西。我的代码没有问题。它是从PHP文档中复制粘贴的。此外,它适用于传递给存储过程的不同值,@StefanoGiacone部分并不混乱。这是mysqli方面的一个困惑。不带光标的SP可用于prepare和multiquery,但使用光标的SP可用于multi_查询,但在prepare时崩溃。还是,所以你可以用老鼠
她认为你的答案可能是一个解决办法,但如果你在谷歌上搜索httpd.exe php5ts.dll,你会发现很多人遇到这个问题。不确定我是否应该打开一个bug…如果你有一个可复制的测试用例,你有很好的机会,你能生成一个正确的回溯吗?$stmt->get_result让我调用未定义的方法mysqli_stmt::get_result-谢谢,我可以确认你,因为你可以从我的问题中看到我尝试了什么,第1点,如果我不准备查询,一切正常。可惜他们没有就解决方案达成一致。。。
array(1) {
  [0] =>
  string(4) "test"
}
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = mysqli_connect('127.0.0.1','user','pass','db');

$mysqli->query("DROP PROCEDURE IF EXISTS mysqli_crash");
$mysqli->query("CREATE PROCEDURE mysqli_crash ()
BEGIN
    DECLARE col TEXT;
    DECLARE res CURSOR FOR SELECT 1 from dual;
    OPEN res;
    FETCH res INTO col;
    CLOSE res;
    SELECT 1 from dual;
END;");

echo  "--- multi_query ---\n";

$mysqli->multi_query("call mysqli_crash()");
$result = $mysqli->store_result();
echo json_encode($result->fetch_all(MYSQLI_ASSOC)),"\n";
$mysqli->next_result();

echo  "--- prepare ---\n";

$stmt = $mysqli->prepare("call mysqli_crash()");
$stmt->execute();
$result = $stmt->get_result();
echo json_encode($result->fetch_all(MYSQLI_ASSOC)),"\n";
$stmt->next_result();