修复curl_exec在Windows 8 apache中挂起

时间:2013-07-19 15:58:28

标签: php curl windows-8

我一直在研究和试验这个问题一段时间了,还没有找到一个可行的解决方案,所以我认为是时候寻求帮助了。

我遇到curl_exec的问题,但只在特定的服务器上。这是一些背景知识,首先:

  • CPU:Intel Core I7
  • RAM:64GB
  • 操作系统:Windows 8.0
  • 服务器:Apache 2.4.4 x86 TS
  • PHP版本:5.5.1 x86 TS w / xDebug 2.2.3
  • cURL版本:7.30.0

显示问题的PHP代码:

$input_vars = (!empty($_POST)) ? filter_input_array(INPUT_POST) : array();
$url = 'http://192.168.1.100/geekcavecreations/Morti/chatbot/conversation_start.php';
$qs = '?';
foreach ($input_vars as $key => $value)
{
  $qs .= "$key=$value&";
}
$qs= rtrim($qs, '&');
$url .= $qs;
$bot_id = $input_vars['bot_id'];
$options = array(
    CURLOPT_USERAGENT => 'Program O XML API',
    CURLOPT_RETURNTRANSFER => true,
    //CURLOPT_POST => 1,
    CURLOPT_MAXREDIRS => 5,
    CURLOPT_CONNECTTIMEOUT => 5,
    CURLOPT_TIMEOUT => 5,
);
$ch = curl_init($url);
curl_setopt_array($ch, $options);
//curl_setopt($ch, CURLOPT_POSTFIELDS, $input_vars);
$data = curl_exec($ch);
$debug = curl_getinfo($ch);
curl_close($ch);
echo '<pre>Data = ', htmlentities($data), '</pre><br>';
var_dump($debug);

可以看出,我已经尝试了GET和POST,并且都给出了相同的结果。上面列出的超时选项是存在的,因此脚本将无法无限运行。在我停止Apache服务停止挂断之前,我已经挂了超过3个小时(只是在浏览器中取消不会这样做)。脚本的输出如下:

array (size=26)
  'url' => string 'ht tp://192.168.1.100/geekcavecreations/Morti/chatbot/conversation_start.php?say=hello&bot_id=1&convo_id=78a9s39gut34lurq055in5s6r4&format=xml' (length=141)
  'content_type' => null
  'http_code' => int 0
  'header_size' => int 0
  'request_size' => int 203
  'filetime' => int -1
  'ssl_verify_result' => int 0
  'redirect_count' => int 0
  'total_time' => float 5
  'namelookup_time' => float 0
  'connect_time' => float 0
  'pretransfer_time' => float 0
  'size_upload' => float 0
  'size_download' => float 0
  'speed_download' => float 0
  'speed_upload' => float 0
  'download_content_length' => float -1
  'upload_content_length' => float 0
  'starttransfer_time' => float 0
  'redirect_time' => float 0
  'redirect_url' => string '' (length=0)
  'primary_ip' => string '192.168.1.100' (length=13)
  'certinfo' => 
    array (size=0)
      empty
  'primary_port' => int 80
  'local_ip' => string '192.168.1.100' (length=13)
  'local_port' => int 2546

Data = 

(无法想出更好的格式化方法,抱歉)

同样在这台计算机上还有几台虚拟机,每台都有不同的OS / Server / PHP版本,并且都具有完全相同的物理文档根目录,它位于主机上。这些机器的范围从Windows 7 / IIS到CentOS / Apache 2.2,以及其他组合,所有这些机器毫无例外地运行同一个脚本,并输出预期的XML文档。如果我只在Web浏览器中运行URL,则输出如下:

<?xml version="1.0"?>
<program_o>
  <version>2.3.0</version>
  <status><success>1</success></status>
  <bot_id>1</bot_id>
  <bot_name>Morti</bot_name>
  <user_id>1</user_id>
  <user_name>Seeker</user_name>
  <chat>
    <line>
      <input>hello</input>
      <response>And a good failed to you, undefined. How are you?</response>
    </line>
  </chat>
</program_o>

我还采用了上面的XML输出并将其保存到文件中,并且问题脚本对该保存的XML文件的URL执行cURL调用,并且脚本在那时工作没有问题,所以我还创建了一个模拟脚本,它只创建一个SimpleXMLElement对象,填充一些新标签,然后回显来自创建对象的asXML()输出(基本上是conversation_start.php所做的,但远不那么复杂),我得到了同样的问题。模拟脚本的代码如下:

$xml = new SimpleXMLElement('<program_o></program_o>');
$xml->addChild('version', '2.3.0');
$status = $xml->addChild('status');
$status->addChild('success', '1');
$xml->addChild('bot_id', '1');
$xml->addChild('bot_name', 'Morti');
$xml->addChild('user_id', '1');
$xml->addChild('user_name', 'Seeker');
$chat = $xml->addChild('chat');
$line = $chat->addChild('line');
$line->addChild('input', 'hello');
$line->addChild('response', 'And a good failed to you, undefined. How are you?');
$output = $xml->asXML();
header('Content-type: text/xml');
exit($output);

我非常关注我的智慧。我已经更改了PHP版本,Apache版本,尝试了我在这里找到的无数建议,其中包括cURL冻结的其他问题,如hereherehere二十几个或更多。

现在我已经写了一本书来介绍我的问题,我不得不问:我怎样才能让cURL不再挂在Windows 8平台上?

1 个答案:

答案 0 :(得分:1)

好吧,我似乎终于找到了问题的根源。似乎当你执行cURL调用与执行调用的脚本相同的服务器时,如果“调用者”和“被调用者”脚本都试图使用相同的会话ID ,发生死锁,导致两个脚本一直等到另一个脚本释放会话。我最后添加了一个测试,以查看是否已经使用了会话ID,如果是,则调用脚本不会启动会话。如果没有会话ID,则调用者启动会话,获取会话ID,然后销毁会话,这允许“被调用者”脚本不受限制地访问所述会话,从而消除死锁情况。以下是我用来执行此操作的代码:

$convo_id = (isset ($request_vars['convo_id'])) ? $request_vars['convo_id'] : get_convo_id();
// do stuff here
function get_convo_id()
{
  session_name('Program O XML GUI');
  session_start();
  $convo_id = session_id();
  session_destroy();
  return $convo_id;
}

使用此方法,一切都按预期工作。我真诚地希望这对未来的其他人有用。