- <?php
- /*
- * Lokorin.com
- * Copyright 2004-2006
- * Licensed under the GNU LGPL. See COPYING for full terms.
- */
- /**
- * This page contains elements that all pages need in almost every session. It
- * also contains a couple of function to make error loggin easier. All pages
- * should require this page.
- * @author Andreas Launila
- * @version $Revision: 1.27 $
- * @package com.lokorin.lokorin.includes
- * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
- */
-
- if(!(defined('IN_LOKORIN_PUBLIC') && (IN_LOKORIN_PUBLIC === true))) {
- //Invalid inclusion of the page.
- die('Invalid access');
- }
-
- error_reporting(E_ALL);
- session_start();
- /**
- * A microtime marking when the common page was included, i.e. when the loading
- * of the page started.
- * @var float
- * @access private
- */
- define('MICROTIME_START', microtime(true));
-
- /**#@+
- * Site specific folder name constants.
- * @access public
- * @var string
- */
- define('FOLDER_INCLUDES','_includes/');
- define('FOLDER_IMAGES','_images/');
- define('FOLDER_THUMBNAILS','_thumbnails/');
- define('FOLDER_ICONS','_icons/');
- define('FOLDER_CSS','_css/');
- define('FOLDER_JS','_js/');
- define('FOLDER_DOWNLOADS','_downloads/');
- define('FOLDER_CACHE','_cache/');
- define('FOLDER_ADMIN','admin/');
- define('FOLDER_CSS_CACHE', FOLDER_CACHE);
- define('FOLDER_RESOURCES', '_resources/');
- /**#@-*/ * Date format constants to be used with the date() function.
- * @access public
- * @var string
- */
- define('DATE_LONG','jS F Y');
- define('DATE_SHORT','jS M Y');
- define('DATE_SHORTER', 'jS M y');
- define('DATE_TIME', 'jS M y H:i');
- define('DATE_SITEMAP', 'c');
- if(!defined('DATE_RSS')) {
- define('DATE_RSS', 'r');
- }
- define('DATE_COMMENT', 'jS F Y, H:i');
- /**#@-*/ * A switch for if debug info should be displayed or not. True if it should be
- * displayed, false otherwise.
- * @var boolean
- * @access public
- */
- define('DEBUG_MODE_ON', true);
- /**
- * Whether or not the site is currently closed. If the site is currently closed
- * then all non-admin users will be redirected to a page informing them what is
- * going on. The redirect does not affect the admin login page.
- * @var boolean
- * @access public
- */
- define('SITE_CLOSED', false);
- /**
- * Path from the http host to the root.
- * @access public
- * @var string
- */
- define('ROOT_PATH', '/lokorin/');
- /**
- * The path for the requested page itself. This is the actual requested page,
- * not the page that is actually handeling it (i.e. it's not equal to
- * $_SERVER['PHP_SELF']).
- * @access public
- * @var string
- */
- define('SELF', str_replace('.php', '', str_replace('?'.$_SERVER['QUERY_STRING'],
- '', strip_tags($_SERVER['REQUEST_URI']))));
- /**
- * Relative path from the current script to the root.
- * @access public
- * @var string
- */
- define('ROOT', getRoot(strip_tags($_SERVER['SCRIPT_NAME'])));
- /**
- * Relative path from the requested uri to the root. This is not neccessarily
- * the same as the path from the current scrip to the root.
- * @access public
- * @var string
- */
- define('PAGE_ROOT', getRoot(SELF));
- /**
- * The absolute path to the root of the site.
- * @access public
- * @var string
- */
- define('DOC_ROOT', $_SERVER['DOCUMENT_ROOT'].ROOT_PATH);
-
- //Include the database abstraction library and create an instance.
- doInclude('lib_db');
- global $db;
- $db = DataBase::getInstance();
-
- //Include the error logging library.
- doInclude('lib_errors');
-
- //Include the CSS library.
- doInclude('lib_css');
-
- //Clear the css cache if we are debugging.
- if(DEBUG_MODE_ON) {
- clearCssCache();
- }
-
- /**
- * Includes a library into the code.
- * @param string $libName The name of the library, e.g. 'common' if one wants
- * to include the library 'common.php'.
- * @param boolean $required If the inclusion is required or not. If it is
- * true then a failure to include it will stop the script, otherwise
- * it will continue with a warning. The default is true.
- * @param boolean $onlyOnce If subsequent requests to include the same library
- * name should be ignored or not. If true then libraries will only be
- * included one, otherwise they will be included once for every request
- * made. The default is true.
- * @access public
- */
- function doInclude($libName, $required = true, $onlyOnce = true) {
- if(strpos($libName, '/') !== false) {
- die('Invalid library name ('.$libName.').');
- }
- $libFile = DOC_ROOT.FOLDER_INCLUDES.$libName.'.php';
-
- //Make sure the library exists.
- if(!file_exists($libFile)) {
- logFatalException(new FileNotFoundException("The library (".$libName.
- ") does not exist."));
- }
- if($onlyOnce === true) {
- if($required === true) {
- require_once($libFile);
- } else {
- @include_once($libFile);
- }
- } else {
- if($required === true) {
- require($libFile);
- } else {
- @include($libFile);
- }
- }
- }
-
- /**
- * Get the relative path from a specified file to the site's root directory.
- * This method should be concidered private to the library.
- * @param string $url The absolute url to the file that one wants the root for.
- * @return string The relative root path so that getDir($url).getRoot(result)
- * ~ ROOT_PATH.
- * @access private
- */
- function getRoot($url) {
- if(strpos($url, ROOT_PATH) === false) {
- logFatalException(new IllegalArgumentException('The page ('.$url.
- ') does not contain the root path.'));
- }
- $strpos = strpos($url, ROOT_PATH);
- $path = substr($url, 0, $strpos).substr($url, $strpos.strlen(ROOT_PATH));
- $root = '';
- for($i = substr_count($path, '/'); $i>0; $i--) {
- $root .= '../';
- }
- return $root;
- }
-
- /**
- * Cleans up and does anything that should be done before finishing. This
- * function should be called directly after a page is served to the used.
- * @param integer $size The number of bytes of the generated page.
- * @access private
- */
- function cleanUp($size) {
- global $db;
-
- //Log the time that it took to serve the page.
- $elapsedTime = round((microtime(true) - MICROTIME_START)*pow(10, 6));
- $vars = array(
- "requested_uri" => $_SERVER['REQUEST_URI'],
- "started" => round(MICROTIME_START),
- "elapsed_microseconds" => $elapsedTime,
- "db_queries" => $db->getQueryCount(),
- "db_microseconds" => $db->getElapsedQueryTime(),
- "page_size" => $size
- );
- $db->queryInsert(TABLE_PERFORMANCE, $vars);
- }
-
- /**
- * Describes something that can add contents to the <head></head> elements of
- * pages that are displayed.
- * @author Andreas Launila
- * @package com.lokorin.lokorin.lib
- */
- interface HeadAddable {
- /**
- * Gets the things that should be added to the page's head element.
- * @return string XHTML compliant code.
- */
- public function getHeadAddition();
- }
-
- /**
- * A simple implementation of HeadAddable. It's an immutable instance that
- * just takes a string of the things that should be included in the head tag.
- * @author Andreas Launila
- * @package com.lokorin.lokorin.lib
- */
- class HeadData implements HeadAddable{
- /**
- * The data that should be added to the head tag.
- */
- private $text;
-
- /**
- * Constructor for HeadData.
- * @param string The code that should be added to the head tag.
- */
- public function __construct($text) {
- $this->text = $text;
- }
-
- /**
- * @see com.lokorin.lokorin.lib.HeadAddable.getHeadAddition()
- */
- public function getHeadAddition() {
- return $this->text;
- }
- }
-
- /**
- * Describes a page that can be displayed. It's the end result of the whole
- * script.
- * @author Andreas Launila
- * @package com.lokorin.lokorin.lib
- */
- class Page implements HeadAddable {
- /**
- * The one and only instance of the class.
- * @var Page
- */
- private static $instance;
- /**
- * All instances of HeadAddable that should be added to the head contents.
- * @var array
- */
- private $headAdditions;
- /**
- * The title of the page.
- * @var string
- */
- private $title;
- /**
- * True if links in the page be followed by robots, false otherwise.
- * @var boolean
- */
- private $doFollow;
- /**
- * True if the page should be indexed by robots, false otherwise.
- * @var boolean
- */
- private $doIndex;
- /**
- * The project that the page belongs to.
- * @var Project
- */
- private $project;
-
- /**
- * Gets the one and only instance of the class.
- * @return CssTemplateConverter The one and only instance.
- */
- public static function getInstance() {
- if(!isset(Page::$instance)) {
- Page::$instance = new Page();
- }
- return Page::$instance;
- }
-
- /**
- * Constructor for Page.
- */
- private function __construct() {
- $this->headAdditions = array();
- $this->doFollow = true;
- $this->doIndex = true;
-
- //Start an output buffer for that page's contents.
- ob_start();
- }
-
- /**
- * Displays the page.
- */
- public function display() {
- if(!isset($this->title)) {
- die("No title specified.");
- }
- $this->displayContents(ob_get_clean());
- }
-
- /**
- * Flushes the page, totally unprocessed, to the output stream.
- */
- public function flush() {
- cleanUp(strlen(ob_get_flush()));
- }
-
- /**
- * Displays the page with the specified contents.
- * @param string $contents The contents that the page should contain.
- */
- private function displayContents($contents) {
- //Ensure that the common css files are included.
- CssHandler::getInstance()->includeCss('page');
- CssHandler::getInstance()->includeCss('menu');
-
- ob_start();
-
- //Add the header and footer.
- doInclude('header');
- echo $contents;
- doInclude('footer');
-
- cleanUp(strlen(ob_get_flush()));
- }
-
- /**
- * Adds something that is head addable (implements HeadAddable) to the head
- * tag of the page.
- * @param HeadAddable The data that should be added.
- */
- public function addToHead(HeadAddable $headAddable) {
- $this->headAdditions[] = $headAddable;
- }
-
- /**
- * Sets the title of the page to a new title.
- * @param string $newTitle The new title that should be sued for the page.
- */
- public function setTitle($newTitle) {
- $this->title = $newTitle;
- }
-
- /**
- * Gets all additional head data that is specified by the page.
- * @return string XHTML compliant code that can be placed inside a head
- * tag.
- * @see com.lokorin.lokorin.lib.HeadAddable.getHeadAddition()
- */
- public function getHeadAddition() {
- $code = array();
- foreach($this->headAdditions as $addition) {
- $code[] = $addition->getHeadAddition();
- }
- return implode("\n", $code);
- }
-
- /**
- * Sets whether or not the current page should be indexed by robots. This
- * is by default set to true.
- * @param boolean $shouldIndex True if pages should be indexed by robots,
- * false otherwise.
- */
- public function setShouldIndex($shouldIndex) {
- $this->doIndex = $shouldIndex;
- }
-
- /**
- * Sets whether or not links in the current page should be followed. This
- * is by default set to true.
- * @param boolean $shouldFollow True if links in the page should be
- * followed by robots, false otherwise.
- */
- public function setShouldFollow($shouldFollow) {
- $this->doFollow = $shouldFollow;
- }
-
- /**
- * Gets where or not the page should be indexed by robots.
- * @return boolean True if the page should be indexed by robots, false
- * otherwise.
- */
- public function doIndex() {
- return $this->doIndex;
- }
-
- /**
- * Gets whether or not links in the page should be followed by robots.
- * @return boolean True if the page should be indexed by robots, false
- * otherwise.
- */
- public function doFollow() {
- return $this->doFollow;
- }
-
- /**
- * Gets the description of the current page.
- * @return string A short description of the page.
- */
- public function getDescription() {
- if($this->project == null) {
- //Use a generic description.
- return "A collection of open-source programming ".
- "projects started by Andreas \"Lokorin\" Launila. ".
- "The languages used are primarily Java, PHP and Delphi.";
- } else {
- //Use the project's description.
- return $this->project->getPageDescription();
- }
- }
-
- /**
- * Gets the text that should be used in the main page header.
- * @return string A few words.
- */
- public function getMainHeader() {
- $prefix = '';
- if($this->project != null) {
- $prefix = $this->project->getName().': ';
- }
- return $prefix.$this->title;
- }
-
- /**
- * Gets the title of the page.
- * @return string A textual page title.
- */
- public function getTitle() {
- if($this->project == null) {
- $prefix = 'Lokorin\'s Projects: ';
- } else {
- $prefix = $this->project->getName().': ';
- }
- return $prefix.$this->title;
- }
-
- /**
- * Whether or not the page has a submenu that should be displayed.
- * @return boolean True if the page has a submenu, false otherwise.
- */
- public function hasSubmenu() {
- return $this->project != null && $this->project->hasMenu();
- }
-
- /**
- * Gets the submenu that should be disiplayed. The function should only
- * be called if hasSubmenu returns true.
- * @return string XHTML compliant code containing an unordered list of
- * links.
- */
- public function getSubmenu() {
- if($this->project != null) {
- return $this->project->getMenu();
- } else {
- logException(new IllegalStateException("No default submenu ".
- "exists."));
- }
- }
-
- /**
- * Sets the project that the page is contained in.
- * @param $newProject The new project that should be set. The value may be
- * null in which case the defailt project is used.
- */
- public function setProject(Project $newProject) {
- $this->project = $newProject;
- if($newProject->hasMenu()) {
- CssHandler::getInstance()->includeCss('submenu');
- }
- }
- }
-
- /**
- * Describes a table entry in a table where each entry has an unique
- * identifier with a key named 'id'.
- * @author Andreas Launila
- * @package com.lokorin.lokorin.lib
- */
- abstract class TableEntry {
- /**
- * The unique identifier for the entry.
- */
- private $id;
-
- /**
- * Constructor for TableEntry.
- * @param string $table The name of the table in which the row should be
- * searched for.
- * @param mixed $id The unique identifier for the table row that
- * describes the entry.
- * @param array $fields An array that contains all fields that should be
- * retrieved from the table. If the array is empty then all columns
- * are retrieved. The parameter is optional, if not specified then all
- * columns are retrieved.
- * @param string $idFieldName The name of table field that contains the
- * unique identifier. Defaults to 'id'.
- * @throws IllegalArgumentException If there is no entry with such and
- * identifier.
- */
- public function __construct($table, $id, $fields = array(), $idFieldName = 'id') {
- global $db;
-
- //Add the id field if it's not already included.
- if(count($fields) != 0 && !in_array($idFieldName, $fields)) {
- $fields[] = $idFieldName;
- }
-
- //Run the query.
- if(count($fields) != 0) {
- //A normal select query should be performed.
- $rows = $db->querySelect($table, $fields,
- "WHERE ".$idFieldName."=".$db->escape($id)." LIMIT 1");
- } else {
- //All fields should be selected.
- $rows = $db->querySelectAll($table,
- "WHERE ".$idFieldName."=".$db->escape($id)." LIMIT 1");
- }
-
- //Check if we got any result.
- if(count($rows) == 0) {
- throw new IllegalArgumentException("The id (".$id.") did not match " .
- "any row in the table (".$table.").");
- }
-
- $row = $rows[0];
- $this->id = $row[$idFieldName];
- $this->readRow($row);
- }
-
- /**
- * Processes the contents of a retrieved row that describes the entry.
- * @param array $row The contents of a row. Each elements has the field
- * name as key and the corresponding field value as value.
- */
- protected abstract function readRow($row);
-
- /**
- * Gets the unique identifier for the table entry.
- * @return integer A unique identifier.
- */
- public function getId() {
- return $this->id;
- }
- }
-
- //Initialise the page.
- Page::getInstance();
- ?>