我一直在我的ErrorDocument
頁面上運行腳本,該腳本在引用者是我的站點時記錄並通過電子郵件發送給我。最近我以爲我可以使用相同的腳本來記錄外部鏈接。我試圖檢索外部頁面標題,如果它們顯示一個404留在我的網站上的錯誤消息,如果沒有,然後做重定向。這是可行的,但即使網站可用,速度也很慢。比直接訪問外部頁面慢得多。在PHP中重定向之前檢查鏈接有效性的最快方法
我認爲這個問題必須躺在我是如何檢索頭(見function is404
),而不是在錯誤報告或全部preg_replace
的,因爲它的工作原理相當快,當我使用它在我的ErrorDocument
的,但無論如何,我會發布所有代碼以防其他地方出現問題。
題外話: 我還沒有決定是否要部署還沒有這個,很明顯它是依賴於獲取速度問題固定的,但我想知道你的意見是對這種方法假定它工作加快速度的。我的網站的好處是明確的,它使用戶停留在網站上,而不是傾倒到可能無法解讀的404上,並讓我知道斷開的鏈接。但是,如果外部頁面具有自定義404,那麼在斷開鏈接後用戶可能會更好。我試圖通過在錯誤消息中包含指向404的鏈接並檢查域的可用性並提供一個指向它的鏈接(如果可用)來抵消這一點。其他的東西也是可行的,例如鏈接到谷歌的結果。那麼,如果你遇到了這個問題,你會感到高興,矛盾,輕度惹惱,還是反感?
更新: 我在最後還是決定去一個框架式的解決方案,由梅爾,因此我在iframe
加載外部頁面,並在任何允許用戶報告打破了頂部的小酒吧的建議鏈接應該存在。這個解決方案中存在的問題是,如果我實際上沒有重定向頁面,如果用戶希望爲其添加書籤,他們最終會得到一個指向我的重定向腳本的鏈接(除非引用者是我的網站,否則它會被阻止;所以他們會鏈接到禁止頁面)。這通過一個簡單的window.location=http://external.site
修復,但問題是何時調用它。 iframe onload
事件觸發頁面是404還是沒有,所以這是不好的,並使用一個簡單的超時使頁面顯然已經加載只是看起來醜陋與我的「有這個頁面錯誤」消息在頂部。我去了一個組合。當onload
觸發時,我正在對腳本進行Ajax調用,該腳本從我的服務器檢查外部站點的狀態。 (我使用的方法與我下面的方法相同,但是這次似乎運行的非常好,我認爲速度問題在其他地方,儘管我不知道在哪裏)。我認爲使用Ajax調用(使用超時)將防止Adrian指出的站點阻塞問題。如果我的服務器認爲該頁面不是404,我立即刪除橫幅。如果它認爲這是我設置了一個超時,並留下標誌(希望)足夠長的用戶想要點擊它。正如答案中指出的那樣,有些情況下我的404代碼與用戶看到的不匹配,但是最糟糕的情況是錯過了一個錯誤的機會來報告錯誤或在罰款期間停留一段時間的橫幅頁。希望大部分時間都能解決。對於沒有啓用JavaScript的用戶,我只需使用meta refresh
並立即轉發到鏈接。如果我在這裏出了問題或錯過了其他重要的東西,我會很感激你的反饋。謝謝。
下面的代碼:
// /../php/urlfns.php
1 <?php
2 function hasProtocol($uri) {
3 return preg_match('#^.+://#', $uri);
4 }
5
6 function getDomain($uri, $keepproto=false) {
7 return preg_replace('#^((.+://)?(.+?))\/.*#', $keepproto?'${1}':'${3}', $uri.'/');
8 }
9
10 function getBaseDomain($uri, $keepproto=false) {
11 $dom = getDomain($uri, $keepproto);
12 if(!$keepproto) {
13 return preg_replace('#.*\.(.+\..+)$#', '${1}', '.'.$dom);
14 }
15 else
16 if(hasProtocol($dom)) {
17 return preg_replace('#^(.+://).*\.(.+\..+)$#', '${1}${2}', $dom);
18 }
19 else {
20 return preg_replace('#^.*\.(.+\..+)$#', '${1}', '.'.$dom);
21 }
22 }
23
24 function isOnDomain($uri, $domain, $allowsubs=false) {
25 $uridom = getDomain($uri);
26
27 if(!$allowsubs) {
28 return ($uridom===$domain);
29 }
30 else {
31 $basedom = getBaseDomain($domain);
32 return (strlen($uridom) - strlen($basedom) === strrpos($uridom, $basedom));
33 }
34 }
35
36 function stripDomain($uri) {
37 return preg_replace('#^(.+://)?.*?(/.*)#', '${2}', $uri);
38 }
39
40 function is404($uri) {
41 stream_context_get_default(array(
42 'http'=>array(
43 'method' => 'HEAD'
44 )
45 ));
46 $hds = @get_headers($uri);
47 return (!$hds || strpos($hds[0], ' 404 ') !== false);
48 }
49 ?>
**
// /../php/badlink.php
1 <?php
2 require_once('urlfns.php');
3
4 function reportbadlink($lntype='generic', $subdomains=false, $blcache='../badlinks/') {
5
6 if(isset($_SERVER['HTTP_REFERER']) &&
7 isOnDomain($_SERVER['HTTP_REFERER'], $_SERVER['SERVER_NAME'], $subdomains)) {
8
9 $reffile = $_SERVER['DOCUMENT_ROOT'].'/'.stripDomain($_SERVER['HTTP_REFERER']);
10
11 $blid = md5($lntype.$_SERVER['REQUEST_URI'][email protected]($reffile));
12 $blfil = dirname(__FILE__).'/'.$blcache.'/'.$blid;
13
14 if(!file_exists($blfil)) {
15 $report = ' On: '.$_SERVER['HTTP_REFERER']."\n".
16 ' To: '.$_SERVER['REQUEST_URI']."\n".
17 'Type: '.$lntype."\n".
18 ' #: '.$blid."\n\n";
19
20 file_put_contents($blfil, $report);
21 mail('[email protected]', 'A broken link has been found.', $report);
22 }
23 }
24 }
25 ?>
**
// /ssi/extlink.php
1 <?
2 require_once('../../php/urlfns.php');
3 $uri = $_SERVER['QUERY_STRING'];
4
5 if(!hasProtocol($uri)) {
6 $uri = 'http://'.$uri;
7 }
8
9 if(!is404($uri)) {
10 header('Location: '.$uri);
11 exit;
12 }
13
14 header("Cache-Control: no-cache, must-revalidate");
15 header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");
16
17 require_once('../../php/badlink.php');
18 reportbadlink('external');
19
20 $baseuri = getDomain($uri,true);
21 if(preg_match('#^'.$baseuri.'/?$#', $uri) || is404($baseuri)) {
22 $baseuri = null;
23 }
24
25 $errtype = 'External page not found';
26 $errmesg = '<p><em><a href="'.$uri.'">'.$uri.'</a> was not found.</em></p>'.
27 '<p>This may be because the site is temporarily unavailable, or it may be a broken link.</p>'.
28 ($baseuri ? '<p><a href="'.$baseuri.'">'.$baseuri.'</a> appears to be available however and you may find '.
29 ' what you are looking for there.</p>' : '');
30 ?>
31 <!DOCTYPE html>
32 <html lang="en" dir="ltr">
...
謝謝,你說得很好。如果它對最終用戶體驗產生不利影響,那絕對是我不想做的事情。我和你一樣,是一個憤世嫉俗的人,會和你一樣做,我只是想知道我的大多數用戶是否會一樣。感謝您的輸入。 – tjm 2011-05-16 13:31:10
嗯。我也喜歡這個解決方案,並且想知道如果一次加載到框架中,我可以以某種方式訪問響應頭文件(也許通過javascript),從而獲得兩全其美的好處,但快速搜索似乎表明這是不可能的。 – tjm 2011-05-16 14:11:57