PHP无限循环问题

时间:2010-05-26 14:35:45

标签: php sockets

function httpGet( $url, $followRedirects=true ) {
    global $final_url;
    $url_parsed = parse_url($url);
    if ( empty($url_parsed['scheme']) ) {
        $url_parsed = parse_url('http://'.$url);
    }
    $final_url = $url_parsed;

    $port = $url_parsed["port"];
    if ( !$port ) {
        $port = 80;
    }
    $rtn['url']['port'] = $port;

    $path = $url_parsed["path"];
    if ( empty($path) ) {
        $path="/";
    }
    if ( !empty($url_parsed["query"]) ) {
        $path .= "?".$url_parsed["query"];
    }
    $rtn['url']['path'] = $path;

    $host = $url_parsed["host"];
    $foundBody = false;

    $out = "GET $path HTTP/1.0\r\n";
    $out .= "Host: $host\r\n";
    $out .= "User-Agent:      Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0\r\n";
    $out .= "Connection: Close\r\n\r\n";

    if ( !$fp = @fsockopen($host, $port, $errno, $errstr, 30) ) {
        $rtn['errornumber'] = $errno;
        $rtn['errorstring'] = $errstr;

    }
    fwrite($fp, $out);
    while (!@feof($fp)) {

        $s = @fgets($fp, 128);
        if ( $s == "\r\n" ) {
            $foundBody = true;
            continue;
        }
        if ( $foundBody ) {
            $body .= $s;
        } else {
            if ( ($followRedirects) && (stristr($s, "location:") != false) ) {
                $redirect = preg_replace("/location:/i", "", $s);
                return httpGet( trim($redirect) );
            }
            $header .= $s;
        }
    }

    fclose($fp);

    return(trim($body));
}

这段代码有时会无限循环。这有什么不对?

3 个答案:

答案 0 :(得分:3)

feof() documentation中有一个大的红色警告框:

  

警告

     

如果服务器未关闭fsockopen()打开的连接,则feof()将挂起。要解决此问题,请参阅以下示例:

     

示例#1使用feof()

处理超时
    <?php
        function safe_feof($fp, &start = NULL) {
             $start = microtime(true); 
             return feof($fp);
        }   
        /* Assuming $fp is previously opened by fsockopen() */

        $start = NULL;
        $timeout = ini_get('default_socket_timeout');

        while(!safe_feof($fp, $start) && (microtime(true) - $start) < $timeout)
        {
          /* Handle */
        }
    ?>

此外,您应该只写入或读取文件指针,如果它有效(您没有做什么,只需设置错误消息): 这导致了第二个大红色警告框:

  

警告

     

如果传递的文件指针无效,则可能会出现无限循环,因为feof()无法返回TRUE

更好的是:

$result = '';

if ( !$fp = @fsockopen($host, $port, $errno, $errstr, 30) ) {
    $rtn['errornumber'] = $errno;
    $rtn['errorstring'] = $errstr;
}
else {
    fwrite($fp, $out);
    while (!@feof($fp)) {
        //...
    }
    fclose($fp);
    $result = trim(body);
}
return $result;

最后一条话:如果您使用

进行重定向
 if ( ($followRedirects) && (stristr($s, "location:") != false) ) {
     $redirect = preg_replace("/location:/i", "", $s);
     return httpGet( trim($redirect) );
 }

你永远不会关闭文件指针。我认为更好的是:

 if ( ($followRedirects) && (stristr($s, "location:") != false) ) {
     $redirect = preg_replace("/location:/i", "", $s);
     $result = httpGet( trim($redirect) );
     break;
 }
 // ...
 return $result;

答案 1 :(得分:0)

如果连接仍然在tcp / ip流中打开,

feof将返回false。

答案 2 :(得分:0)

function httpGet( $url, $followRedirects=true ) {
[...]
                return httpGet( trim($redirect) );
}

没有什么可以阻止您一次又一次地获取相同的URL。