* @license PHP License
* @package WB
* @subpackage content
*/
/**
* Load base class
*/
WBClass::load('WBString'
, 'WBObserver'
, 'WBContent'
,'WBContent_SEO');
/**
* Content component: SEO_Sitemap
*
* Render Google sitemaps
* @link http://www.sitemaps.org/
*
* @version 1.1.1
* @package WB
* @subpackage content
*/
class WBContent_SEO_Sitemap extends WBContent_SEO implements WBObserver
{
/**
* my parameter list
*
* - 'action' either "index" or "sitemap"
* - 'ttl' caching time of sitemaps
* - 'datasource' list of modules to use
*
* @var array
*/
protected $config = array(
'action' => 'sitemap',
'sitemappath' => 'sitemap/',
'ttl' => 300,
'datasource' => array('Page')
);
/**
* list of seen URLs
* @var array
*/
private $urls = array(
'robots.txt' => true
);
/**
* URL template for pages
* @var string
*/
protected $pageLoc = '[[PROTOCOL]]://[[SERVER]][[SERVICE_HTML]]%s%1.2f%s';
protected $pageLocAlt = '';
/**
* Datasource sitemap
* @var WBDatasource_Sitemap
*/
private $ds;
/**
* handle to sitemap file
* @var resource
*/
private $fh;
/**
* Available alternate languages
* @var array
*/
private $languages = array();
/**
* Run component
*
* Create sitemaps and sitemap index
*
* @see sendAndExit()
* @return array parameter list
*/
public function run()
{
// reset locale settings to make sure decimal point works properly
setlocale(LC_ALL, null);
$this->loadLanguages();
$this->sess->close();
$file = $this->mkSitemap();
$md5 = md5_file($file->realpath());
$this->res->addStream(fopen($file->realpath(), 'r'), $md5);
$this->sendAndExit('text/xml');
}
/**
* Create actual sitemap per language
*
* @return WBFile
*/
private function mkSitemap()
{
WBString::setLanguagePath(null);
$file = WBClass::create('WBFile');
if ($this->isTTLOK($file, '/var/cache/sitemap.xml')) {
return $file;
}
$this->fh = fopen($file->realpath(), 'w');
$cnt = <<
EOT;
fputs($this->fh, $cnt);
// run datasources
foreach ($this->config['datasource'] as $d) {
// normalize
if (!is_array($d)) {
$d = array(
'name' => $d,
'params' => array()
);
}
else if (empty($d['params']) || !is_array($d['params'])) {
// empty default value
$d['params'] = array();
}
$this->ds = WBClass::create('WBDatasource_Sitemap_' . $d['name']);
$this->ds->configure($d['params']);
$this->ds->attach($this);
$this->ds->find();
$this->ds->detach($this);
}
fputs($this->fh, "\n");
fclose($this->fh);
return $file;
}
/**
* Get informed
*
* Callback for each URL
*
* @param WBDatasource_Sitemap $subject
*/
public function update($subject)
{
$path = $subject->getPath();
if (isset($this->urls[$path])) {
return;
}
$this->urls[$path] = true;
$cnt = array('');
$cnt[] = sprintf($this->pageLoc, $path, $subject->getPriority(), $subject->getSnippet());
foreach ($this->languages as $l => $p) {
if (0 == strncmp('__default', $p, 9)) {
$p = '';
}
$cnt[] = sprintf($this->pageLocAlt, $l, $p, $path);
}
$cnt[] = "\n";
fputs($this->fh, implode("\n",$cnt));
}
/**
* Get language path mapping
*
* In case language path feature is uses, return settings
*
* @see etc-default/locale.xml
*/
private function loadLanguages()
{
$locale = WBClass::create('WBConfig');
$locale->load('locale');
$languages = $locale->get('locale/languages/requestpath', array());
if (!is_array($languages) || empty($languages)) {
return;
}
$this->languages = array();
foreach ($languages as $l => $p) {
$p .= '/';
$l = explode('_', $l);
$l = $l[0];
$this->languages[$l] = $p;
}
$this->languages['x-default'] = '';
}
/**
* Check file's age
*
* Auxialliary function that helps to cache sitemaps
*
* @param WBFile $file
* @param string $path
* @return bool true if TTL is not over, yet
*/
private function isTTLOK($file, $path)
{
if (!$file->exists($path)) {
$file->touch($path);
return false;
}
if (1 > WBParam::get('wb/cache/use', 1)) {
return false;
}
$ttl = intval($this->config['ttl']);
if (0 > $ttl) {
return false;
}
if (time() > filemtime($file->realpath()) + $ttl) {
return false;
}
return true;
}
}