PHP Apache在执行STORED PROCEDURE时崩溃

Ste*_*one 19 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->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());
Run Code Online (Sandbox Code Playgroud)

apache崩溃了,错误:

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

我尝试了什么

  1. 此代码工作正常,它正确返回结果:
$conn->query("SET @res = ''");
$res=$conn->query("CALL retrieve_matches(5,3, 16, 2, false, @res)");
var_dump($res->fetch_assoc());
Run Code Online (Sandbox Code Playgroud)

注意:如果我只是更改存储过程的输入中的数字,上面的相同代码使Apache崩溃正常工作,如:

if (!($stmt = $mysqli->prepare("CALL retrieve_matches(5,6, 16, 2, false, @res)"))) {
Run Code Online (Sandbox Code Playgroud)
  1. 从MySQl工作台尝试,两个电话都运行正常.
  2. 我在WIN7 Enterprise 64b上使用WAMP 64b,我尝试使用WAMP 32b,但遇到了同样的问题.
  3. 我检查了Windows事件,发现httpd.exe是由php5ts.dll引起的崩溃
  4. 如果你在谷歌搜索"httpd.exe php5ts.dll",你会发现很多人遇到这个问题.但我找不到WAMP的解决方案......
  5. 尝试使用AMPPS,完全相同的问题

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.
Run Code Online (Sandbox Code Playgroud)

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.
Run Code Online (Sandbox Code Playgroud)

我真的迷失在这里,我应该在哪里寻找这个问题?非常感谢您的帮助

编辑

我意识到存储过程"retrieve_matches"正在根据更改的值调用不同的存储过程.我调试了存储过程"retrieve_standalone",这是使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;
Run Code Online (Sandbox Code Playgroud)

如果我不打开光标

open tmp_cursor;
Run Code Online (Sandbox Code Playgroud)

一切都很好!! 所以我想我现在发现了这个问题:我该如何解决?

Sjo*_*jon 6

如果php5ts.dll或apache的任何其他部分在每次运行短脚本时都以可重现的方式崩溃,那么很可能在php中遇到了一个错误.特别是如果你使用从php.net下载的最新php版本运行最新的apache,你很有可能从PHP团队获得支持.所以通过https://bugs.php.net/how-to-report.php阅读,看看你是否可以在没有apache运行脚本时重现崩溃(在使用php.exe的cli上的单独脚本中)并生成一个您可以将其作为错误提交的回溯.

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


Ste*_*one 5

我找到了如何重现它,我相信这是一个 php/apache 错误

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());
Run Code Online (Sandbox Code Playgroud)

存储过程代码:

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
Run Code Online (Sandbox Code Playgroud)

漏洞打开:Apache:https ://bz.apache.org/bugzilla/show_bug.cgi ?id=58136

php: https://bugs.php.net/bug.php?id=70073


LSe*_*rni 1

显然,PHP 人员和 MySQLi 人员之间存在一些相互推诿的情况,即互相推诿。

似乎正在发生的事情是 MySQLi 以“不正确”的方式做出反应,并向 PHP 返回一个意外的值(我敢打赌它是 NULL),PHP 会及时进行核心转储。此行为已记录在案,PHPland 的结论是:“不是 [PHP] bug”。在他们这边,MySQLi 的人坚持认为是 PHP 没有正确检查返回的结果。无论如何,“不正确”的结果取决于您的查询。

所以我冒险假设你的问题是同样的“通信困难”问题,所以问题变成:“你的查询迫使 MySQLi 断开/重新连接”。为什么会这样?显然(某些)存储过程需要mysqli_multi_query才能正常运行

并且mysqli_multi_query不兼容mysqli_prepare

因此,我建议在不准备查询的情况下进行尝试,并使用mysqli_multi_query.

$conn->query("SET @res = ''");
$conn->multi_query("CALL retrieve_matches(5,3, 16, 2, false, @res)");

do {
    if ($result = $conn->store_result()) {
        while ($row = $result->fetch_row()) {
            var_dump($row);
        }
        $result->free();
    }
} while ($conn->more_results() && $conn->next_result());
Run Code Online (Sandbox Code Playgroud)

通过这段代码,你的测试用例让我如预期的那样,

array(1) {
  [0] =>
  string(4) "test"
}
Run Code Online (Sandbox Code Playgroud)