【问题标题】:preg_replace avoids some tagspreg_replace 避免了一些标签
【发布时间】:2014-05-27 12:42:08
【问题描述】:

我想使用 cURL 登录到远程域上的网站,然后导航到不同的页面并进行各种数据请求。

问题是这个网站上的一些链接是相对的。这使我的代码认为这些页面是本地的(它们当然不是)。

在挖掘之后,我意识到我需要使用 preg_match 来查找和区分相对链接,并使用 preg_replace 使它们成为实际存在的 .js 和 .js 的绝对网址。该服务器上的 css 文件。

当我运行此代码时,它会按照预期重新生成每个链接,但少数除外。 所有链接都应该经过的是:
<link rel="stylesheet" type="text/css" href="popcalendar.css"> -> <link rel="stylesheet" type="text/css" href="http://www.example.com/popcalendar.css">其余的相关链接保持原样。我不明白为什么。 正确替换的 .css 甚至不是第一个应该替换的!

这是我用来尝试访问远程站点的 PHP 脚本:

<?php
$username = 'myuser';
$password = 'mypass';
$loginUrl = 'http://www.example.com/index.php/';

//init curl
$ch = curl_init();

//Set the URL to work with
curl_setopt($ch, CURLOPT_URL, $loginUrl);

// ENABLE HTTP POST
curl_setopt($ch, CURLOPT_POST, 1);

//Set the post parameters
curl_setopt($ch, CURLOPT_POSTFIELDS, 'uName='.$username.'&uPw='.$password.'&Submit=OK');

//Handle cookies for the login
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookie.txt');

//Setting CURLOPT_RETURNTRANSFER variable to 1 will force cURL
//not to print out the results of its query.
//Instead, it will return the results as a string return value
//from curl_exec() instead of the usual true/false.
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

//execute the request (the login)
$store = curl_exec($ch);

//the login is now done and you can continue to get the
//protected content.

//set the URL to the protected file
curl_setopt($ch, CURLOPT_URL, 'http://www.example.com/ask_for_info.php');

//execute the request
$result = curl_exec($ch);
curl_close($ch);
if (!preg_match('/src="http?:\/\/"/', $result)) {
        $result = preg_replace('/src="(http:\/\/([^\/]+)\/)?([^"]+)"/', "src=\"http://www.example.com/\\3\"", $result);
        echo 'THIS';
    }
    if (!preg_match('/href="http?:\/\/"/', $result)) {
        $result = preg_replace('/href="(http:\/\/([^\/]+)\/)?([^"]+)"/', "href=\"http://www.example.com/\\3\"", $result);
        echo 'THAT';
    }


print_r($result);
?>

在运行代码时检查 Google Chrome 控制台,我得到如下信息:

Resource interpreted as Stylesheet but transferred with MIME type text/html: "http://example.com/example.css". login4.php:6
Resource interpreted as Script but transferred with MIME type text/html: "http://example.com/js/prototype.js". login4.php:7
Uncaught SyntaxError: Unexpected token < prototype.js:1
Resource interpreted as Script but transferred with MIME type text/html: "http://example.com/js/popcalendar3_ajax.js?ver=2". login4.php:9
Uncaught SyntaxError: Unexpected token < 

有什么想法吗?感谢您提供的任何帮助!

【问题讨论】:

  • 你没有使用好工具,使用 DOMDocument 更容易做到这一点。顺便说一句,if(!preg_match... 没用,如果您只需要替换相对 url,则必须检查链接不以 http:// 或 preg_replace 模式中的主机名开头。
  • curl_close()后面的代码逻辑不清楚。
  • 这些对我来说已经很有价值了!
  • @CasimiretHippolyte DOMDocument 会强迫我使用浏览器。如果稍后我想将此代码添加到 Cron 作业中怎么办?可能我仍然需要努力。其次,我确实想检查以 http:// 开头的链接。所以我做错了。但是,它确实检查并替换了除 3 之外的所有链接。我现在正在查找。对此有任何进一步的建议或例子吗?谢谢!
  • "DOMDocument 会强迫我使用浏览器。",绝对不会!您可以在服务器端将其与 PHP 一起使用。请记住 preg_replace 中的模式已经是一个检查,使用它。

标签: php curl preg-replace preg-match


【解决方案1】:

DOMDocument 和 XPath 的示例:

$scheme = 'http';
$host = 'example.com';
$path = '/';

$dom = new DOMDocument();
@$dom->loadHTML($result);
$xpath = new DOMXPath($dom);

$xquery = '//a/@href | //img/@src | //script/@src | //link/@href';
$urlAttrNodes = $xpath->query($xquery);

$pattern = '~^(?!https?:// | www\. | // | ' . preg_quote($host)
         . '(?=/|$) )  (\.?/)?~xi';

foreach($urlAttrNodes as $urlAttrNode) {
    $absoluteUrl = preg_replace($pattern, "$scheme://www.$host$path",
                                $urlAttrNode->nodeValue);
    $urlAttrNode->ownerElement->setAttribute($urlAttrNode->name, $absoluteUrl);
}

$result = $dom->saveHTML();

请注意,该模式仅跳过当前主机,如果需要,您可以轻松添加其他域。

【讨论】:

  • 这基本上回答了这个问题。有用!谢谢!我现在需要弄清楚的是为什么它会在结果中添加&lt;script&gt; window.location.reload(); &lt;/script&gt; 并不断刷新页面。然而,这可能是网站的错。我想到了。真的很有帮助!
猜你喜欢
  • 2011-09-07
  • 1970-01-01
  • 1970-01-01
  • 2020-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多