轉寄一個PHP抓取網頁快照程式,代碼是轉寄的,注釋是原創的,協助新人理解。
snap.class.php
<?PHP
//====================================================
// FileName: snap.class.php
// Summary: 網頁快照
// Author: millken(迷路林肯)
// LastModifed:2007-06-29
// copyright (c)2007 [email]millken@gmail.com[/email]
//====================================================
class snap{
var $dir;
var $log;
var $contents; // 緩衝檔案內容
var $filename; // 緩衝檔案的檔案地址
var $host; // 目標地址
var $name; // 緩衝檔案的檔案名稱, 值是Url的MD5碼
var $data_ts; // 緩衝檔案的時間戳記
var $ttl; // 逾時時間
var $url; // 需要抓快照的Url地址
var $ts; //
function snap(){
$this->log = "New snap() object instantiated.<br />\n";
$this->dir = dirname(__FILE__)."/";
}
/*
擷取網頁快照。
參數:
url:網頁地址
ttl:逾時時間,單位為秒。
超過這個時間後從網頁上擷取,在此時間內直接讀緩衝檔案。
傳回值:
無
*/
function fetch($url="",$ttl=10) {
$this->log .= "--------------------------------<br />fetch() called<br />\n";
$this->log .= "url: ".$url."<br />\n";
// 驗證Url是否合法。
$hosts = parse_url($url);
$this->host = $hosts['scheme'].'://'.$hosts['host'].'/';
if (!$url) {
$this->log .= "OOPS: You need to pass a URL!<br />";
return false;
}
$this->ttl = $ttl;
$this->url = $url;
$this->name = md5($this->url);
$this->filename = $this->dir.$this->name;
$this->log .= "Filename: ".$this->filename."<br />";
$this->getFile_ts();
$this->file_get_content();
}
/*
擷取快照內容。
如果逾時,則從網頁上直接擷取,否則從快取檔案擷取
參數:
無
傳回值:
true:成功, false:失敗
*/
function file_get_content(){
// 開啟緩衝區
ob_start();
$this->ts = time() - $this->data_ts;
// 如果逾時,則從網頁上取得快照,否則,直接從緩衝區內取得
if($this->data_ts <> 0 && $this->ts <= $this->ttl){
$this->log .= "cache has expired<br />";
@readfile($this->filename);
$this->contents = ob_get_contents();
ob_end_clean();
}else{
$this->log .= "cache hasn't expired<br />";
@readfile($this->url);
$this->contents = ob_get_contents();
ob_end_clean();
$this->saveToCache();
}
return true;
}
/*
儲存快照到快取檔案。
參數:
無
傳回值:
true:成功, false:失敗
*/
function saveToCache(){
$this->log .= "saveToCache() called<br />";
//建立一個新檔案使用者緩衝網頁快照
if (!$fp=@fopen($this->filename,"w")) {
$this->log .= "Could not open ".$this->filename."<br />";
return false;
}
$this->contents = $this->formaturl($this->contents, $this->host);
$this->contents = preg_replace("'<script[^>]*?>.*?</script>'si","",$this->contents);
//寫檔案
if (!@fwrite($fp,$this->contents)) {
$this->log .= "Could not write to ".$this->filename."<br />";
fclose($fp);
return false;
}
//關閉檔案
fclose($fp);
return true;
}
/*
獲得檔案的時間戳記
參數:
無
傳回值:
true:成功, false:失敗
*/
function getFile_ts() {
$this->log .= "getFile_ts() called<br />";
if (!file_exists($this->filename)) {
$this->data_ts = 0;
$this->log .= $this->filename." does not exist<br />";
return false;
}
$this->data_ts = filemtime($this->filename);
return true;
}
/*
格式化特殊的Url
參數:
無
傳回值:
格式化後的Url。
*/
function formaturl($l1, $l2){
// 查詢網頁上的所有img,link,a
if (preg_match_all("/(<img[^>]+src=\"([^\"]+)\"[^>]*>)|(<link[^>]+href=\"([^\"]+)\"[^>]*>)|(<a[^>]+href=\"([^\"]+)\"[^>]*>)|(<img[^>]+src='([^']+)'[^>]*>)|(<a[^>]+href='([^']+)'[^>]*>)/i",$l1,$regs)){
foreach($regs[0] as $num => $url) {
$l1 = str_replace($url, $this->lIIIIl($url, $l2), $l1);
}
}
return $l1;
}
/*
將畫面上的二級地址重新解析,以保證畫面顯示正確
例如:相對位址/css/sty004.css 會替換為絕對位址 http://xxx.com/css/sty004.css
參數:
$l1:要解析的地址
$l2:需要加上的host首碼
傳回值:
格式化後的Url。
*/
function lIIIIl($l1, $l2) {
if(preg_match("/(.*)(href|src)\=(.+?)( |\/\>|\>).*/i", $l1, $regs)){
$I2 = $regs[3];
}
if(strlen($I2)>0) {
// 去掉雙引號chr(34)和單引號chr(39)
$I1 = str_replace(chr(34),"",$I2);
$I1 = str_replace(chr(39),"",$I1);
} else {
return $l1;
}
$url_parsed = parse_url($l2);
$scheme = $url_parsed["scheme"];
if($scheme!="") {
$scheme = $scheme."://";
}
$host = $url_parsed["host"];
$l3 = $scheme.$host;
if(strlen($l3)==0)
{
return $l1;
}
$path = dirname($url_parsed["path"]);
if($path[0]=="\\") {
$path="";
}
$pos = strpos($I1,"#");
if($pos>0) {
$I1 = substr($I1,0,$pos);
}
//判斷類型
if(preg_match("/^(http|https|ftp):(\/\/|\\\\)(([\w\/\\\+\-~`@:%])+\.)+([\w\/\\\.\=\?\+\-~`@\':!%#]|(&)|&)+/i",$I1)) {
return $l1;
//http類型的url要跳轉;
} elseif($I1[0]=="/") {
//絕對路徑
$I1 = $l3.$I1;
} elseif(substr($I1,0,3)=="../") {
//相對路徑
while(substr($I1,0,3)=="../") {
$I1 = substr($I1,strlen($I1)-(strlen($I1)-3),strlen($I1)-3);
if(strlen($path)>0){
$path = dirname($path);
}
}
$I1 = $l3.$path."/".$I1;
} elseif(substr($I1,0,2)=="./") {
$I1 = $l3.$path.substr($I1,strlen($I1)-(strlen($I1)-1),strlen($I1)-1);
} elseif(strtolower(substr($I1,0,7))=="mailto:"||strtolower(substr($I1,0,11))=="javascript:") {
return $l1;
} else {
$I1 = $l3.$path."/".$I1;
}
return str_replace($I2,"\"$I1\"",$l1);
}
}
?>
test.php
<?php
require_once(dirname(__FILE__).'/snap.class.php');
$h = new snap();
$h->fetch($_GET['url']);
//echo $h->log;
echo $h->contents;
?>