比较XML文档以了解PHP中的更改

时间:2010-07-19 19:47:34

标签: php html xml comparison performance

目前,我正在使用PHP使用simplexml_load_file()从Web(非本地)加载多个XML文件。正如您可以想象的那样,这是一个相当笨重的过程,并且显着减慢了加载时间(加载7个文件需要7秒),并且可能会有更多文件需要加载。这些文件不会经常更改,但更改应立即显示在页面上。

我的一个想法是缓存每个Feed的版本以及我在数据库中从该Feed生成的html输出。然后,每次用户加载页面时,都会比较Feed;如果它们不同,我将运行现有代码,生成HTML,输出它,并将其保存到数据库中。但是,如果它是相同的,我可以简单地输出缓存的HTML。

我对此的两个担忧是:

安全性:如果我存储的是XML文件的副本,是否会造成安全威胁,因为我无法控制该文件的内容?

速度:这里的主要目标是提高整体页面加载的速度。上面描述的过程是否会提高速度,还是会让服务器陷入更多困境?谢谢你的帮助!

2 个答案:

答案 0 :(得分:4)

让cron作业爬过每个外部XML源,比如每小时或每小时一小时,如果有必要,可以更新它?

它不会100%实时,但会减轻你的网页负载 - 总是会使用缓存文件。我认为除了实际下载文件之外,还有一种可靠的轮询外部源更新的方法(理论上,应该可以获得正确的缓存头,但我不会依赖它们正确配置。)

  

安全性:如果我存储的是XML文件的副本,是否会造成安全威胁,因为我无法控制该文件的内容?

几乎没有。要完全确定,请将缓存的XML文件存储在Web根目录之外。那时剩下的任何威胁都与你通过直播传递流一样。

答案 1 :(得分:2)

  

我的一个想法是缓存每个Feed的版本以及我在数据库中从该Feed生成的html输出。然后,每次用户加载页面时,都会比较Feed;如果它们不同,我将运行现有代码,生成HTML,输出它,并将其保存到数据库中。但是,如果它是相同的,我可以简单地输出缓存的HTML。

您应该在请求标头中设置If-None-MatchIf-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 />";
}