* @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.0
* @package WB
* @subpackage content
*/
class WBContent_SEO_Sitemap1 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 $pageUrl = "http://[[SERVER]][[SERVICE_HTML]]%s%1.2f%s\n";
/**
* URL template for index of sitemap file
* @var string
*/
protected $indexUrl = "http://[[SERVER]][[SERVICE_HTML]]%2\$s/%1\$s%2\$s.xml%3\$s\n";
/**
* Datasource sitemap
* @var WBDatasource_Sitemap
*/
private $ds;
/**
* handle to sitemap file
* @var resource
*/
private $fh;
/**
* 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->config['action'] = strtolower($this->config['action']);
$languages = $this->getLanguages();
switch ($this->config['action']) {
case 'index':
if (!empty($languages)) {
$file = $this->runIndex($languages);
break;
}
// fall through
case 'sitemap':
$file = $this->runSitemap();
break;
}
$md5 = md5_file($file->realpath());
$this->res->addStream(fopen($file->realpath(), 'r'), $md5);
$this->sendAndExit('text/xml');
}
/**
* Create sitemap index
*
* Split sitemap by language path. Well, sitemaps are equal, but
* differ in URL because of language in path. In case this site does
* not use the language path feature only one sitemap will be created -
* there is no need for an index.
*
* @param array $list of languages
* @return WBFile
*/
private function runIndex($languages)
{
WBString::setLanguagePath(null);
$file = WBClass::create('WBFile');
if ($this->isTTLOK($file, '/var/cache/sitemap/index.xml')) {
return $file;
}
$this->fh = fopen($file->realpath(), 'w');
$cnt = <<
EOT;
fputs($this->fh, $cnt);
$dir = dirname($file->realpath());
foreach ($languages as $lang => $path) {
$mTime = time();
if (file_exists($dir . '/' . $path . '.xml')) {
$mTime = filemtime($dir . '/' . $path . '.xml');
$dTime = time() - $mTime;
if ($dTime > 10 * $this->config['ttl']) {
$mTime = time();
}
}
$cnt = sprintf($this->indexUrl, $this->config['sitemappath'], $path, strftime('%Y-%m-%dT%H:%M:%S+00:00', $mTime));
fputs($this->fh, $cnt);
}
fputs($this->fh, "\n");
fclose($this->fh);
return $file;
}
/**
* Create actual sitemap per language
*
* @return WBFile
*/
private function runSitemap()
{
$lang = $this->config['__path'][0];
if (strstr($lang, '.')) {
$lang = explode('.', $lang);
$lang = $lang[0];
}
if (empty($lang)) {
WBString::setLanguagePath(null);
$lang = 'sitemap';
} else {
WBString::setLanguagePath($lang);
}
$file = WBClass::create('WBFile');
if ($this->isTTLOK($file, '/var/cache/sitemap/'. $lang . '.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()
);
}
$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 = sprintf($this->pageUrl, $path, $subject->getPriority(), $subject->getSnippet());
fputs($this->fh, $cnt);
}
/**
* Get language path mapping
*
* In case language path feature is uses, return settings
*
* @see etc-default/locale.xml
* @return array
*/
private function getLanguages()
{
$locale = WBClass::create('WBConfig');
$locale->load('locale');
$languages = $locale->get('locale/languages/requestpath', array());
if (!is_array($languages)) {
$languages = array();
}
return $languages;
}
/**
* 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;
}
}