目前,我正在使用PHP使用simplexml_load_file()
从Web(非本地)加载多个XML文件。正如您可以想象的那样,这是一个相当笨重的过程,并且显着减慢了加载时间(加载7个文件需要7秒),并且可能会有更多文件需要加载。这些文件不会经常更改,但更改应立即显示在页面上。
我的一个想法是缓存每个Feed的版本以及我在数据库中从该Feed生成的html输出。然后,每次用户加载页面时,都会比较Feed;如果它们不同,我将运行现有代码,生成HTML,输出它,并将其保存到数据库中。但是,如果它是相同的,我可以简单地输出缓存的HTML。
我对此的两个担忧是:
安全性:如果我存储的是XML文件的副本,是否会造成安全威胁,因为我无法控制该文件的内容?
速度:这里的主要目标是提高整体页面加载的速度。上面描述的过程是否会提高速度,还是会让服务器陷入更多困境?谢谢你的帮助!
答案 0 :(得分:4)
让cron作业爬过每个外部XML源,比如每小时或每小时一小时,如果有必要,可以更新它?
它不会100%实时,但会减轻你的网页负载 - 总是会使用缓存文件。我认为除了实际下载文件之外,还有一种可靠的轮询外部源更新的方法(理论上,应该可以获得正确的缓存头,但我不会依赖它们正确配置。)
安全性:如果我存储的是XML文件的副本,是否会造成安全威胁,因为我无法控制该文件的内容?
几乎没有。要完全确定,请将缓存的XML文件存储在Web根目录之外。那时剩下的任何威胁都与你通过直播传递流一样。
答案 1 :(得分:2)
我的一个想法是缓存每个Feed的版本以及我在数据库中从该Feed生成的html输出。然后,每次用户加载页面时,都会比较Feed;如果它们不同,我将运行现有代码,生成HTML,输出它,并将其保存到数据库中。但是,如果它是相同的,我可以简单地输出缓存的HTML。
您应该在请求标头中设置If-None-Match
或If-Modified-Since
字段,而不是自己缓存XML文件。这样,您可以检查文件是否已更改,而无需下载它们。
这可以通过在运行simplexml_load_file()
之前为libxml设置流上下文来完成。如果文件未更改,您将收到304 Not Modified
响应,simplexml_load_file
将失败。
您还可以使用stream_context_get_default
设置常规流上下文,然后将XML文件检索为包含file_get_contents
的字符串,并将其传递给simplexml_load_string()
。
以下是第一种方式的示例:
Class CachedXml {
public $element,$url;
private $mod_date, $etag;
public function __construct($url){
$this->url = $url;
$this->element = NULL;
$this->mod_date = FALSE;
$this->etag = FALSE;
}
public function updateXml(){
if($this->mod_date || $this->etag){
$opts = array(
'http'=>array(
'header'=>"If-Modified-Since: $this->mod_date\r\n" .
"If-None-Match: $this->etag\r\n"
)
);
$context = stream_context_create($opts);
libxml_set_streams_context($context);
}
if($attempt = @ simplexml_load_file($this->url)){
$this->element = $attempt;
$headers = get_headers($this->url,1);
$this->mod_date = $headers['Last-Modified'];
$this->etag = $headers['ETag'];
return TRUE;
}
return FALSE;
}
}
$bob = new CachedXml('http://example.com/xml/test.xml');
if($bob->updateXml()){
echo "Bob was just updated.<br />";
echo " Bob's name is " . $bob->element->getName() . ".<br />";
}
else{
echo "Bob was not updated.<br />";
}