* @license PHP License * @package WB * @subpackage content */ /** * Load base class */ WBClass::load('WBContent'); /** * Content component: SearchEngineOptimizer * * Display robots.txt and sitemap * * @version 0.4.0 * @package WB * @subpackage content */ class WBContent_SearchEngineOptimizer extends WBContent { /** * my parameter list * * - 'process' select what to display (sitemap, robots.txt) * - 'page' whether to add pages to sitemap (0,1) * - 'blog' add blog articles to sitemap (blog/%day/%title) * - 'blogcategory' list of blog categories (optional) * - 'gallery' add gallery pages to sitemap (gallery/%obscureid/%title) * - 'vfs' add media files page to sitemap (vfs/%obscureid/%name) * - 'vfsmimemajor' limit to file types - don't care for mimetype if empty * * @var array */ protected $config = array( 'process' => 'sitemap', 'page' => 1, 'blog' => '', // blog/%day/%title 'blogcategory' => array(), 'gallery' => '', // gallery/%obscureid/%title 'vfs' => '', // vfs/%obscureid/%name 'vfsmimemajor' => array('video', 'image') ); /** * url template for google sitemap * * @var string */ protected $url = "http://[[SERVER]][[SERVICE_HTML]]%s%1.2f\n"; /** * list of found or not to add (to sitemap) pages * @var array */ protected $pages = array( '/robot' => true, '/robots.txt' => true, '/sitemap' => true, '/sitemap.xml' => true ); /** * current menu level * @var int */ protected $level = 0; /** * vfs gallery * @var WBVFS_Gallery */ protected $gallery; /** * Table access * @var WBDatasource_Table */ private $table; /** * config loader * @var WBConfig_Loader */ private $configLoader; /** * run * * run component * * @return array parameter list */ public function run() { switch (strtolower($this->config['process'])) { case 'robots.txt'; case 'robots'; $this->displayRobots(); break; case 'sitemap': default: $this->displaySitemap(); break; } return $this->config; } /** * create standard robots.txt * * @link http://www.robotstxt.org/ * @uses display() */ protected function displayRobots() { $cnt = <<display($cnt, 'text/plain'); } /** * create standard google sitemap * * @link http://www.sitemaps.org/ * @uses display() */ protected function displaySitemap() { // reset locale settings to make sure decimal point works properly setlocale(LC_ALL, null); $cnt = << EOT; $this->addPage2Sitemap($cnt); $this->addBlog2Sitemap($cnt); $this->addGallery2Sitemap($cnt); $this->addVFS2Sitemap($cnt); $cnt .= "\n"; $this->display($cnt, 'text/xml'); } /** * add blog article pages * * In case there are special blog article pages, list recent 100 article URLs * * See config option 'blog. If this parameter is empty, nothing will be added to * the sitemap. Otherwise path to each article is used. The placeholder %id and * %title are replaced with article's id and title. * * @param string $cnt */ protected function addBlog2Sitemap(&$cnt) { if (empty($this->config['blog'])) { return; } // basic blog path $path = $this->config['blog']; $path = str_replace(array('%id', '%title'), '', $path); $path = trim($path, '/'); $level = count(explode('/', $path)); // priority of blog article pages $prio = 1 - ($level / 10); $path = $this->config['blog']; // fetch recent 100 acticles if (!$this->table) { $this->table = WBClass::create('WBDatasource_Table'); } $opt = array( 'limit' => 500, 'column' => array('title', 'created') ); $clause = array(); if (!empty($this->config['blogcategory'])) { if (!is_array($this->config['blogcategory'])) { $this->config['blogcategory'] = array($this->config['blogcategory']); } $clause[] = array( 'field' => $this->table->getIdentifier('blogcategory'), 'relation' => 'in', 'value' => $this->config['blogcategory'] ); } $list = $this->table->get('blog', null, null, $clause, $opt); $search = array( '%id', '%day', '%title' ); foreach ($list as $l) { $replace = array( $l['id'], date('Y-m-d', strtotime($l['created'])), urlencode($l['title']) ); $p = str_replace($search, $replace, $path); $cnt .= sprintf($this->url, $p, $prio); } WBDatasource_Table::flushCache(); } /** * add list of galleries to sitemap * * In case there automatically created special pages for gallery listings, * load list of user galleries and add them to sitemap * * @param string $cnt */ protected function addGallery2Sitemap(&$cnt) { if (empty($this->config['gallery'])) { return; } // basic blog path $path = $this->config['gallery']; $path = str_replace(array('%obscureid', '%title'), '', $path); $path = trim($path, '/'); $level = count(explode('/', $path)); // priority of gallery list page $prio = 1 - ($level / 10); $path = $this->config['gallery']; $options = array(); $this->gallery = WBClass::create('WBVFS_Gallery', $options); $search = array( '%obscureid', '%title' ); $list = $this->gallery->getList(); foreach ($list as $l) { $replace = array( $l['obscureid'], urlencode($l['title']) ); $p = str_replace($search, $replace, $path); $cnt .= sprintf($this->url, $p, $prio); } WBDatasource_Table::flushCache(); } /** * add media files * * @param string $cnt */ protected function addVFS2Sitemap(&$cnt) { if (empty($this->config['vfs'])) { return; } if (!$this->table) { $this->table = WBClass::create('WBDatasource_Table'); } $opt = array( 'limit' => 500, 'order' => array( 'field' => 'created', 'asc' => 0 ) ); $clause = array(); // description is required $clause[] = array( 'field' => 'description', 'relation' => 'not', 'value' => '' ); // just a view mime-types if (!empty($this->config['vfsmimemajor'])) { if (!is_array($this->config['mimemajor'])) { $this->config['mimemajor'] = array($this->config['mimemajor']); } $clause[] = array( 'field' => 'mimemajor', 'relation' => 'in', 'value' => $this->config['vfsmimemajor'] ); } $list = $this->table->getIds('vfsfile', null, $clause, $opt); $search = array( '%obscureid', '%name' ); $file = WBClass::create('WBVFS_File'); /** @var $file WBVFS_File */ foreach ($list as $l) { $file = $file->loadById($l); if (!$file->isOK()) { continue; } /** * @todo check for file references */ $major = $file->getMime(WBVFS_File::MIME_MAJOR); // add vfs file view page $replace = array( $file->getObscureId(), urlencode($file->getName()) ); $m = array(''); $m[] = sprintf(' http://[[SERVER]][[SERVICE_HTML]]%s', str_replace($search, $replace, $this->config['vfs'])); $m[] = sprintf(' <%s:%1$s>', $major); $m[] = sprintf(' <%s:title>', $major, $file->getName()); switch ($major) { case 'image': $m[] = sprintf(' <%s:loc>http://[[SERVER]][[SERVICE_FILE]]%s', $major, $file->getUri()); $m[] = sprintf(' <%s:caption>', $major, $file->getDescription()); break; case 'video': $created = strtotime($file->getCreated()); $m[] = sprintf(' <%s:publication_date>%s', $major, strftime('%Y-%m-%dT%H:%M:%S+00:00', $created)); $m[] = sprintf(' <%s:content_loc>http://[[SERVER]][[SERVICE_FILE]]%s', $major, $file->getUri()); $m[] = sprintf(' <%s:player_loc allow_embed="yes" autoplay="autostart=true">http://[[SERVER]][[SERVICE_JAVASCRIPT]]WB/player.swf?file=[[SERVICE_FILE]]%s', $major, $file->getUri()); $m[] = sprintf(' <%s:thumbnail_loc>http://[[SERVER]][[SERVICE_FILE]]%s', $major, $file->getUri('image')); $m[] = sprintf(' <%s:description>', $major, $file->getDescription()); $m[] = sprintf(' <%s:duration>%d', $major, round($file->getInfo('seconds'))); $m[] = sprintf(' <%s:view_count>%d', $major, $file->getViews()); break; default: continue; break; } $m[] = sprintf(' ', $major); $m[] = ''; $m[] = ''; $cnt .= implode("\n", $m); } WBDatasource_Table::flushCache(); } /** * add all configured pages * * @todo implement switch for pages stored in database * @param string $cnt * @todo move old code to WBConfigLoader_File */ protected function addPage2Sitemap(&$cnt) { if (empty($this->config['page']) || intval($this->config['page']) < 1) { return; } $loader = WBParam::get('wb/config/loader/service/site', 'File'); if ($loader != 'File') { $this->configLoader = WBClass::create('WBConfig_Loader_' . WBParam::get('wb/config/loader/service/site', 'File')); $this->addPages2Sitemap($cnt); return; } $cnt .= sprintf($this->url, '', 1); // add pages from page configuration folders $etcDir = WBParam::get('wb/dir/base') . '/' . WBParam::get( 'wb/dir/config', 'etc' ); if (is_dir($etcDir . '/site/page')) { $this->addPageDir2Sitemap($cnt, $etcDir . '/site/page'); } $this->addPageDir2Sitemap($cnt, $etcDir . '-default/site/page'); } /** * list pages in sitemap * * Recursive method to load find all page configurations and add them * to sitemap. * * @param string $cnt * @param string $path */ private function addPages2Sitemap(&$cnt, $path = '') { $path = trim($path, '/'); $branch = array_pop(explode('/', $path)); if (strncmp('__', $branch, 2) == 0) { return; } if (isset($this->pages[$path])) { return; } $this->pages['/' . $path] = true; $prio = 1.1 - (count(explode('/', $path)) / 10); $cnt .= sprintf($this->url, $path, $prio); // try to find children if (!empty($path)) { $path = '/' . $path; } $children = $this->configLoader->ls('site/page' . $path); if (empty($children)) { return; } foreach ($children as $child) { $child = substr($child, 10); $this->addPages2Sitemap($cnt, $child); } } /** * add pages to sitemap * * Recursively scans folder for page definitions. It also makes sure, that each page * will be added just once. * * @uses display() * @param string $cnt * @param string $dir * @param string $prefix * @todo move to WBConfig_Loader_File */ protected function addPageDir2Sitemap(&$cnt, $dir, $prefix = '') { $iter = new DirectoryIterator($dir); foreach ($iter as $page) { if ($page->isDot()) { continue; } if ($page->isDir()) { ++$this->level; $this->addPageDir2Sitemap($cnt, $page->getPathname(), $prefix . $page->getFilename() . '/'); --$this->level; continue; } $name = explode('.', $page->getFilename()); if (array_pop($name) != 'xml') { continue; } $name = implode('.', $name); // skip index and default pages if (strncmp($name, '__', 2) == 0) { continue; } $name = $prefix . $name; // make sure each page will be added only once if (isset($this->pages[$name])) { continue; } $this->pages[$name] = true; $prio = 1 - ($this->level / 10); $cnt .= sprintf($this->url, $name, $prio); } } /** * Display * * CAUTION: This method does not return! * * @param string $content * @param string $mime */ protected function display($content, $mime) { $res = WBClass::create('WBResponse'); /** @var $res WBResponse */ $res->add($content); $res->addHeader('Content-Type', $mime); $res->send($this->req); exit(0); } } ?>