问题描述
我有一个 MysqL 查询,它获取了将近 5000 行的 url 数据(1 行包含 1 个 url)。 所以我已经实现了一个 cron,它通过分页从 MysqL 一次获取 1000 行。我需要对 url 进行一些验证,并且应该将有效的 url 附加到 xml 文件中。
这是我的代码
public function urlcheck()
{
$xFile = $this->base_path."sitemap/path/urls.xml";
$page = 0;
$cache_key = 'valid_urls';
$page = $this->cache->redis->get($cache_key);
if(!$page){
$page=0;
}
$xFile = simplexml_load_file($xFile);
$this->load->model('productnew/productnew_es6_m');
$urls= $this->db->query("SELECT url FROM product_data where `active` = 1 limit ".$page.",1000")->result();
$dom = new DOMDocument('1.0','UTF-8');
$dom->formatOutput = true;
$root = $dom->createElement('urlset');
$root->setAttribute('xsi:schemaLocation','http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd');
$root->setAttribute('xmlns:xsi','http://www.w3.org/2001/XMLSchema-instance');
$root->setAttribute('xmlns','http://www.sitemaps.org/schemas/sitemap/0.9');
$dom->appendChild($root);
foreach($urls as $val)
{
// validations here
$url = $dom->createElement('url');
$root->appendChild($url);
$lastmod = $dom->createElement('lastmod',date("Y-m-d"));
$url->appendChild($lastmod);
$page++;
}
$dom->saveXML();
$dom->save($xFile) or die('XML Create Error');
if(sizeof($urls) == 0){
$page = 0;
}
print_r($page);
$this->cache->redis->save($cache_key,$page,432000);
// echo '<xmp>'. $dom->saveXML() .'</xmp>';
// $dom->saveXML();
// $dom->save($xFile) or die('XML Create Error');
}
在我第一次执行 cron 后,1000 个 url 中的 300 个有效 url 被保存到 xml 文件中, 现在让我们说在我的第二个 cron 执行中,我有 1000 个有效网址中的 200 个。
我的预期结果是将这 200 个附加到现有的 xml 文件中,以便我的 xml 文件包含总共 500 个有效 url,并且 xml 文件应该在 5000 个 url 后刷新,如上所述。
但是每次执行 cron 后,旧的 url 数据将被替换为最新的一次。
我想知道如何在不覆盖 XML 的情况下保存 url 值。 提前致谢!
解决方法
根据上面的评论,您使用一个 api (SimpleXML) 打开文件,但使用 DOMDocument
保存一个新文档 - 从而覆盖以前的工作。如果没有 SimpleXML
,也许您可以这样尝试 - 尽管它未经测试。
public function urlcheck(){
$file=$this->base_path."sitemap/path/urls.xml";
$cache_key='valid_urls';
$page=$this->cache->redis->get($cache_key);
if(!$page)$page=0;
$dom=new DOMDocument('1.0','UTF-8');
$dom->formatOutput = true;
$col=$dom->getElementsByTagName('urlset');
if( !empty( $col ) )$root=$col->item(0);
else{
$root=$dom->createElement('urlset');
$dom->appendChild( $root );
$root->setAttribute('xsi:schemaLocation','http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd');
$root->setAttribute('xmlns:xsi','http://www.w3.org/2001/XMLSchema-instance');
$root->setAttribute('xmlns','http://www.sitemaps.org/schemas/sitemap/0.9');
}
# does a `page` node exist - if so use the value as the $page variable
$col=$com->getElementsByTagName('page');
if( !empty( $col ) )$page=intval( $col->item(0)->nodeValue );
$this->load->model('productnew/productnew_es6_m');
$urls=$this->db->query("SELECT `url` FROM `product_data` where `active` = 1 limit ".$page.",1000")->result();
foreach( $urls as $val ){
$url = $dom->createElement('url');
$root->appendChild($url);
$lastmod = $dom->createElement('lastmod',date("Y-m-d"));
$url->appendChild($lastmod);
$page++;
}
$node=$dom->createElement( 'page',$page );
$root->insertBefore( $node,$root->firstChild );
if( empty( $urls ) )$page=0;
$dom->save( $file );
$this->cache->redis->save( $cache_key,$page,432000 );
}
,
附加到文档看起来不错,但是您没有打开要从磁盘附加到的文件。因此,在每个页面上,您从 XML 中的 0 个 url 开始并附加到空的根节点。
但是每次执行 cron 后,旧的 url 数据将被替换为最新的一次。
这正是您所描述的行为,听起来您一开始并没有加载 XML 文件,只需编写即可。
所以问题可能是如何打开一个 XML 文件,根据您的描述已经 append 看起来不错。
让我们回顾一下,通过颠倒你问题的介绍句:
我需要对 url 进行一些验证,并将有效的 url 附加到 xml 文件中。
所以我实现了一个 cron,它通过分页从 mysql 中一次获取 1000 行。
我有一个 mysql 查询,它获取了将近 5000 行的 url 数据(1 行包含 1 个 url)。
假设要附加每个 1000 url-set 的文件已经在磁盘上(第 2-5 页),您需要附加。但是,如果在第 1 页上的文件已经在磁盘上,您将附加到其他一些第 1-5 页。
所以看起来您只在第一页时编写了代码 - 创建一个新文档(并附加到它)。
尽管您有问题,附加确实有效,您自己编写:
旧的 url 数据正在被最新的一次替换。
唯一不起作用的是打开第 2 - 5 页上的文件。
那么让我们重新表述这个问题:如何打开一个 XML 文件?
但首先,变量 $page
并不代表上述第 1 - 5 页中的 page。它只是一个名称有问题的变量,$page
代表循环中到目前为止处理的 URL 数量,而不是分页中的页面。
不管它的名字是什么,我都会用它作为这个答案的价值。
所以现在让我们在 $page
不是 0
时打开现有文档进行追加:
...
$dom = new DOMDocument('1.0','UTF-8');
$dom->formatOutput = true;
if ($page !== 0) {
$dom->load(dom_import_simplexml($xFile)->ownerDocument->documentURI)
}
$col=$dom->getElementsByTagName('urlset');
...
只有在第一次运行时,您才会有所描述的文件是新创建的行为 - 在这种情况下它很好(在第一次运行 $page === 0
时)。
在任何其他情况下,$page
不是 0
并且文件是从磁盘打开的。
我已将您代码的其他部分放在一边,因此本示例仅介绍了这个 3 行 if 子句。
load($file)
函数的文档可在 PHP 文档中找到,以防万一到目前为止您错过了:
如果您想跟上进度,请尽量不要重复使用相同的变量名称。在这里,我不得不回收整个 SimpleXMLElement 并将其导入到 DOM 中,只是为了获取原始 xml-file-path 以打开文档 - 尽管它曾经在变量 $xFile
下,但它不再作为纯字符串可用。但这只是作为边距中的注释。
并且由于您已经在使用 Redis,您可能希望将 URL 排入队列并从那里进行处理,然后您可能不需要数据库分页。见Lists of the Redis Data-Types。
然后,您还可以将好的 URL 放在第二个列表中。
通过两个列表,您甚至可以直接在 Redis 中不断查看进度。
最后完成后,您可以在一个事务中从 Redis 中的好 URL 中一次性写入整个文件。
如果您想在其上投入更多(最少)技术,请查看 Beanstalkd。