- <?php
- /*
- * Lokorin.com
- * Copyright 2004-2006
- * Licensed under the GNU LGPL. See COPYING for full terms.
- */
- /**
- * A library that contains functions and classes related to the site's sitemap.
- * The sitemap is primarily used by indexing bots, e.g. googlebot.
- * @author Andreas Launila
- * @version $Revision: 1.2 $
- * @package com.lokorin.lokorin.lib
- * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
- */
-
- /**
- * For access to common constants and functions.
- */
- require_once('common.php');
-
- /**
- * The virtual location of the sitemap index file, the file that should
- * contain the whole sitemap index.
- * @var string
- * @access private
- */
- define('SITEMAP_INDEX', 'sitemap.xml');
- /**
- * The virtual locations that should be used for sitemap files. The name is a
- * printf pattern that accepts one string parameter, the name. The string
- * returned is the location relative to the site root.
- * @var string
- * @access private
- */
- define('SITEMAP_NAMES', 'sitemap_%s.xml');
-
- /**#@+
- * Sitemap names, they have to be unique.
- * @access private
- * @var string
- */
- define('SITEMAP_NEWS', "news");
- define('SITEMAP_PROJECTS', "projects");
- define('SITEMAP_FILES', "files");
- define('SITEMAP_FORUM', "forum");
- /**#@-*/ * The counter that should be used to count the number of the times that the
- * sitemap index has been requested.
- * @var integer
- * @access private
- */
- define('SITEMAP_INDEX_COUNTER', 58);
-
- /**
- * Formats the paramamters into a well-formed XML url element as specified
- * by the google sitemap schema. The last three parameters are optional,
- * they may be left out.
- * @param string $loc The url relative the root.
- * @param integer $lastmod The timestamp that describes the last point in
- * time when the page was modified.
- * @param float $priority The priority of the page [0,1].
- * @param string $changefreq The change frequency as specified by the
- * schema.
- * @return string A well-formed XML url element.
- */
- function formatSitemapElement($loc, $lastmod = false, $priority = false,
- $changefreq = false) {
- $element = '<url><loc>http://'.$_SERVER['HTTP_HOST'].ROOT_PATH.$loc.'</loc>';
- if($lastmod !== false) {
- $element .= '<lastmod>'.date(DATE_SITEMAP, $lastmod).'</lastmod>';
- }
- if($priority !== false) {
- $element .= '<priority>'.$priority.'</priority>';
- }
- if($changefreq !== false) {
- $element .= '<changefreq>'.$changefreq.'</changefreq>';
- }
- $element .= '</url>';
-
- return $element;
- }
-
- /**
- * Notifies that the contents of a table has been altered. This should be
- * called in order for the sitemaps to stay current.
- * @param string $table The name of the table which's contents changed.
- * @access public
- */
- function notifyTableChanged($table) {
- global $db;
-
- //Get all sitemaps that are backed by the table.
- $idFields = array(
- 'backing_table_name' => $table
- );
- $rows = $db->querySelect(TABLE_SITEMAP, array('name'),
- $db->buildSqlSelector($idFields));
- foreach($rows as $row) {
- //Invalidate the sitemap.
- $sitemap = new Sitemap($row['name']);
- $sitemap->invalidate();
- }
- }
-
- /**
- * Describes a sitemap index.
- * @author Andreas Launila
- * @package com.lokorin.lokorin.lib
- */
- class SitemapIndex {
- /**
- * An array of all sitemaps contained in the index.
- * @var array
- */
- private $sitemaps;
-
- /**
- * Constructs the sitemap index.
- */
- public function __construct() {
- $this->sitemaps = $this->getAllSitemaps();
- }
-
- /**
- * Gets all available sitemaps.
- * @return array An array of Sitemap instances, each representing one of
- * the available sitemaps.
- */
- private function getAllSitemaps() {
- global $db;
-
- $sitemaps = array();
- $rows = $db->querySelect(TABLE_SITEMAP, array('name'));
- foreach($rows as $row) {
- $sitemaps[] = new Sitemap($row['name']);
- }
-
- return $sitemaps;
- }
-
- /**
- * Gets the complete sitemap index as XML as specified by the google
- * sitemap schema.
- * @return string A complete XML document.
- */
- public function getAsXml() {
- //Increase the counter.
- doInclude('lib_counters');
- try {
- $counter = new Counter(SITEMAP_INDEX_COUNTER);
- $counter->recordHit();
- } catch(IllegalArgumentException $e) {}
-
- //Generate the index contents.
- ob_start();
- echo '<?xml version="1.0" encoding="UTF-8"?>'.
- '<sitemapindex xmlns="http://www.google.com/schemas/sitemap/0.84" '.
- 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '.
- 'xsi:schemaLocation="http://www.google.com/schemas/sitemap/0.84 '.
- 'http://www.google.com/schemas/sitemap/0.84/siteindex.xsd">'."\n";
- foreach($this->sitemaps as $sitemap) {
- echo $sitemap->getAsElementForIndex();
- }
-
- //Footer
- echo '</sitemapindex>';
-
- return ob_get_clean();
- }
-
- /**
- * Gets all sitemaps that belong to the index.
- * @return array An array of Sitemap instances, each representing one of
- * the sitemaps that belong to the index.
- */
- public function getSitemaps() {
- return $this->sitemaps;
- }
-
- /**
- * Gets the virtual location for the sitemap index.
- * @return string A location, relative to the root, for the virtual sitemap
- * index.
- */
- public function getVirtualLocation() {
- return SITEMAP_INDEX;
- }
- }
-
- /**
- * Describes a sitemap.
- * @author Andreas Launila
- * @package com.lokorin.lokorin.lib
- */
- class Sitemap extends TableEntry {
- /**
- * The unqiue name of the sitemap.
- * @var string
- */
- private $name;
- /**
- * A unix timestamp that describes the point in time when the sitemap was
- * last updated.
- * @var integer
- */
- private $timestampUpdated;
- /**
- * The actual XML document describing the sitemap.
- * @var string
- */
- private $xmlContents;
- /**
- * Whether or not the XML contents is valid. Contents that is not valid
- * should be regenerated rather than reused. True if the current XML
- * contents is valid, false otherwise.
- * @var boolean
- */
- private $isValid;
- /**
- * The name of the database table that is backing the sitemap, if any. If
- * no table is backing the sitemap then this variable should be empty. The
- * sitemap should be invalidated if the backing table's contents is
- * changed.
- * @var string
- */
- private $backingTable;
-
- /**
- * Constructs the sitemap.
- * @param string $name The unique name of the sitemap that should be
- * constructed.
- * @throws IllegalArgumentException If the name is not a valid sitemap
- * name.
- */
- public function __construct($name) {
- $fields = array(
- 'timestamp_updated',
- 'xml_contents',
- 'is_valid',
- 'backing_table_name'
- );
- parent::__construct(TABLE_SITEMAP, $name, $fields, 'name');
- }
-
- /**
- * @see com.lokorin.lokorin.TableEntry.readRow($row)
- */
- protected function readRow($row) {
- $this->name = $row['name'];
- $this->timestampUpdated = $row['timestamp_updated'];
- $this->xmlContents = $row['xml_contents'];
- $this->isValid = ($row['is_valid'] != 0) && ($row['is_valid'] != '0');
- $this->backingTable = $row['backing_table_name'];
- }
-
- /**
- * Invalidates the sitemape, causing it to be regenerated by the next time
- * it's requested.
- */
- public function invalidate() {
- global $db;
-
- $vars = array(
- 'is_valid' => 0
- );
- $idFields = array(
- 'name' => $this->name
- );
- $db->queryUpdate(TABLE_SITEMAP, $vars, $db->buildSqlSelector($idFields));
- }
-
- /**
- * Updates the sitemap with the latest available contents.
- */
- private function update() {
- //Generate the XML document.
- ob_start();
-
- //Header.
- echo '<?xml version="1.0" encoding="UTF-8"?>'."\n".
- '<urlset xmlns="http://www.google.com/schemas/sitemap/0.84" '.
- 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '.
- 'xsi:schemaLocation="http://www.google.com/schemas/sitemap/0.84 '.
- 'http://www.google.com/schemas/sitemap/0.84/sitemap.xsd">'."\n";
-
- //Handle all the names
- switch($this->name) {
- case 'news':
- echo $this->getNewsBody();
- break;
- case 'projects':
- echo $this->getProjectsBody();
- break;
- case 'menu':
- echo $this->getFilesBody();
- break;
- default:
- logException(new IllegalStateException("Unknown name (".$this->name.")"));
- }
-
- //Footer.
- echo '</urlset>';
-
- //Update the data.
- $this->xmlContents = ob_get_clean();
- $this->isValid = true;
- $this->timestampUpdated = time();
-
- //Update the database.
- global $db;
- $vars = array(
- 'timestamp_updated' => $this->timestampUpdated,
- 'xml_contents' => $this->xmlContents,
- 'is_valid' => '1',
- );
- $idFields = array(
- 'name' => $this->name
- );
- $db->queryUpdate(TABLE_SITEMAP, $vars, $db->buildSqlSelector($idFields));
- }
-
- /**
- * Gets the XML body contents for the news sitemap.
- * @return string A number of well formed XML elements.
- */
- private function getNewsBody() {
- doInclude('lib_news');
-
- $output = '';
- $news = getNews(""); //Get all news entries.
- foreach($news as $entry) {
- $output .= $entry->getAsSitemapEntry()."\n";
- }
- return $output;
- }
-
- /**
- * Gets the XML body contents for the projects sitemap.
- * @return string A number of well formed XML elements.
- */
- private function getProjectsBody() {
- doInclude('lib_projects');
-
- $output = '';
- $projects = getAllProjects();
- foreach($projects as $project) {
- $output .= $project->getAsSitemapEntries()."\n";
- }
- return $output;
- }
-
- /**
- * Gets the XML body contents for everything in the main menu.
- * @return string A number of well formed XML elements.
- */
- private function getFilesBody() {
- doInclude('lib_menu');
-
- $output = '';
- $menus = getAllRootMenus();
- foreach($menus as $menu) {
- $output .= $menu->getAsSitemapEntry();
- foreach($menu->getChildren() as $child) {
- $output .= $child->getAsSitemapEntry();
- }
- }
- return $output;
- }
-
- /**
- * Gets the contents of the sitemap as an XML document as specified by the
- * google sitemap schema.
- * @return string A complete XML document.
- */
- public function getAsXml() {
- if(!$this->isValid) {
- //Invalid contents, regenerate it.
- $this->update();
- }
- return $this->xmlContents;
- }
-
- /**
- * Gets the sitemap reference elemenet that should be used to represent
- * the sitemap in sitemap indices.
- * @return string A single well-formed XML sitemap element as specified by
- * the google sitemap schema.
- */
- public function getAsElementForIndex() {
- doInclude('lib_util');
- return sprintf('<sitemap><loc>%s</loc><lastmod>%s</lastmod></sitemap>',
- 'http://'.$_SERVER['HTTP_HOST'].ROOT_PATH.$this->getVirtualLocation(),
- date(DATE_SITEMAP, $this->timestampUpdated));
- }
-
- /**
- * Gets the virtual location for the sitemap.
- * @return string A location, relative to the root, for the virtual
- * sitemap.
- */
- public function getVirtualLocation() {
- return sprintf(SITEMAP_NAMES, $this->name);
- }
-
- /**
- * Gets the unique name of the sitemap.
- * @return string A name that is unique for the sitemap.
- */
- public function getName() {
- return $this->name;
- }
- }
-
- ?>