* @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; } }