1

我有一个 PHP 脚本,它在使用 CURL_MULTI 函数下载的页面上查找链接。下载很好,我得到了数据,但是当我遇到一个将 url 列为非链接的页面时,我的脚本随机崩溃。这是代码:

$fishnof = strpos($nofresult, $supshorturl, 0);
$return[0] = ''; $return[1] = ''; // always good to cleanset

// Make sure we grabbed a link instead of a text url(no href)
if ($fishnof !== false) {
    $linkcheck = rev_strpos($nofresult,'href',$fishnof);
    $endthis = false;
    while($endthis !== true) {
        if($linkcheck > ($fishnof - 25)){ // 19 accounts for href="https://blog. 25 just in case
            $endthis = true;
            break;
        }
        $lastfishnof = $fishnof;
        $fishnof = strpos($nofresult,$supshorturl,$fishnof+1);
        if($fishnof === false){$fishnof = $lastfishnof;$linkcheck = rev_strpos($nofresult,'href',$fishnof);$endthis = true;break;}// This is the last occurance of our URL on this page
        if($linkcheck > $fishnof){$linkcheck = rev_strpos($nofresult,'href',$fishnof);$endthis = true;break;} // We went around past the end of the string(probably don't need this)      
        $linkcheck = rev_strpos($nofresult,'href',$fishnof);
    }
    if($linkcheck < ($fishnof - 25)){ // 19 accounts for href="https://blog. 25 just in case
        $return[0] = 'Non-link.';
        $return[1] = '-';
        $nofresult = NULL; // Clean up our memory
        unset($nofresult); // Clean up our memory
        return $return;
    }
}

这是自定义的 rev_strpos,它只是做一个反向操作strpos()

// Does a reverse stripos()
function rev_strpos(&$haystack, $needle, $foffset = 0){
    $length = strlen($haystack);
    $offset = $length - $foffset - 1;
    $pos = strpos(strrev($haystack), strrev($needle), $offset);
    return ($pos === false)?false:( $length - $pos - strlen($needle) );
}

因此,如果:

$nofresult = '
Some text.Some text.Some text.Some text.Some text.Some text.
Some text.Some text.Some text.Some text.Some text.Some text.
Some text.Some text.Some text.Some text.Some text.Some text.
google.com Some text.Some text.Some text.Some text.Some text.
Some text.Some text.Some text.Some text.Some text.Some text.
Some text.Some text.Some text.Some text.Some text.Some text.
<a href="http://www.google.com">Google</a> Some text.Some text.
Some text.Some text.Some text.Some text.Some text.Some text.';

$supshorturl = "google.com";

这应该找到 google.com 的第二次出现的位置,它位于 HTML href 标记内。问题是它在崩溃之前没有报告任何错误,我的错误设置:

ini_set("display_errors", 1);
error_reporting(E_ALL & ~E_NOTICE);
set_error_handler('handle_errors');

我的handle_errors()函数将所有错误记录在一个文件中。但是,在脚本崩溃之前不会报告任何错误。我的 curl_multi 还处理许多 URL,有时它会在某个 URL 上崩溃,有时它会在另一个 URL 上崩溃......我准备拔掉头发,因为这看起来很容易......但在这里我是。另一个注意点是,如果我删除了 while 循环,那么不会崩溃,如果页面首先在 href 标记中包含 url,那么它也不会崩溃。请帮我弄清楚这件事。太感谢了!

4

2 回答 2

0

问题是这个解析错误

$nofresult = "
Some text.Some text.Some text.Some text.Some text.Some text.
Some text.Some text.Some text.Some text.Some text.Some text.
Some text.Some text.Some text.Some text.Some text.Some text.
google.com Some text.Some text.Some text.Some text.Some text.
Some text.Some text.Some text.Some text.Some text.Some text.
Some text.Some text.Some text.Some text.Some text.Some text.
<a href="http://www.google.com">Google</a> Some text.Some text.
Some text.Some text.Some text.Some text.Some text.Some text.";

... 它应该是

$nofresult = "
Some text.Some text.Some text.Some text.Some text.Some text.
Some text.Some text.Some text.Some text.Some text.Some text.
Some text.Some text.Some text.Some text.Some text.Some text.
google.com Some text.Some text.Some text.Some text.Some text.
Some text.Some text.Some text.Some text.Some text.Some text.
Some text.Some text.Some text.Some text.Some text.Some text.
<a href=\"http://www.google.com\">Google</a> Some text.Some text.
Some text.Some text.Some text.Some text.Some text.Some text.";
于 2011-09-07T04:38:51.733 回答
0

我认为你让它变得比它需要的更难。Ifrev_strpos只需要返回搜索字符串的最后一个实例,如果您不担心 case,请strripos改用。

从 PHP 文档...

strripos — 查找不区分大小写的字符串在字符串中最后出现的位置

描述

int strripos ( string $haystack , string $needle [, int $offset = 0 ] )

查找字符串中最后一次出现的位置。与 strrpos() 不同,strripos() 不区分大小写。

如果您需要它区分大小写,或者出于某种原因只想使用您自己的函数,那么问题在于您如何计算偏移量。具体在这两行:

$offset = $length - $foffset - 1;
$pos = strpos(strrev($haystack), strrev($needle), $offset);

使用您的示例“一些文本...”并搜索“google.com”,如果我们没有指定偏移量,它会将偏移量计算为长度(500 个字符)-偏移量(0 个字符)-1。然后您使用 strpos在从偏移字符 499 开始的 500 字符长度的字符串上。您永远不会以这种方式找到任何东西。

由于您正在反转干草堆和针头,因此您需要“反转”您的偏移量。将行更改为:

$pos = strpos(strrev($haystack), strrev($needle), $length - $offset);

(实际上,您应该更改之前的行以计算您想要的 $offset ,但您明白了......)

更新:

除了关于使用正则表达式的建议之外,获取位置真的很简单:

function getOffsets( $url, $baseRegex, $text ){
    $results = array();
    $regex= str_replace( '%URL%', $url, $baseRegex );
    preg_match_all( $regex, $text, $matches, PREG_OFFSET_CAPTURE );

    foreach ( $matches[0] as $match )
        array_push( $results, ($match[1] + strpos( $match[0], $url )) );

    return $results;
}

$linkRegex = '/<a[^>]*href="[^"]*%URL%[^"]*"[^>]*>/i';
$linkLocations = getOffsets( $url, $linkRegex, $text );
//Array
//(
//    [0] => 395
//)

$anyRegex = '/%URL%/i';
$allLocations = getOffsets( $url, $anyRegex, $text );
$nonlinkLocations = array_diff( $allLocations, $linkLocations );  //all non-links
//Array
//(
//    [0] => 188
//)

这确实应该比rev_strpos&while循环噱头更可取。

于 2011-09-07T05:40:15.613 回答