- <?php
- /*
- * Lokorin.com
- * Copyright 2004-2006
- * Licensed under the GNU LGPL. See COPYING for full terms.
- */
- /**
- * A library that contains everything that is connected to MPLF's online filter
- * archive.
- * @author Andreas Launila
- * @version $Revision: 1.9 $
- * @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');
-
- global $archive;
- $archive = new FilterArchive();
-
- /**
- * Describes a filter archive. It contains categories structured into a
- * navigatable tree. Each category can then contain filters.
- * @author Andreas Launila
- * @package com.lokorin.lokorin.lib
- */
- class FilterArchive {
- /**
- * Stores categories that have been loaded. Key is the id, value is the
- * Category instance.
- * @var array
- */
- private $categories;
- /**
- * Stores the top level categories in the category tree, key is irrelevant,
- * vaue is a Category instance.
- * @var array
- */
- private $topCategories;
- /**
- * Stores filters that have been loaded. Key is the id, value is the Filter
- * instance.
- * @var array
- */
- private $filters;
- /**
- * Stores edits that have been loaded. Key is the id, value is the Edit
- * instance.
- * @var array
- */
- private $edits;
- /**
- * Stores moderators that have been loaded. Key is the id, value is the
- * Moderator instance.
- * @var array
- */
- private $moderators;
-
- /**
- * Constructor for FilterArchive.
- */
- public function __construct() {
- global $db;
-
- //Initialize local variables.
- $this->categories = array();
- $this->filters = array();
- $this->edits = array();
- $this->moderators = array();
-
- //Get all categories.
- $fields = array(
- "id",
- "name",
- "description"
- );
- $rows = $db->querySelect(TABLE_MPLF_CATEGORIES, $fields);
- $categories = array();
- foreach($rows as $row) {
- $categories[$row['id']] = new Category($row['id'], $row['name'],
- $row['description']);
- }
-
- //Structure the categories into the tree.
- $topCategoryIds = array();
- $rows = $db->querySelect(TABLE_MPLF_CATEGORIES,
- array("id", "parent_id"), "ORDER by parent_id DESC");
- foreach($rows as $row) {
- if($row['parent_id'] == 0) {
- $topCategoryIds[] = $row['id'];
- } else {
- $categories[$row['parent_id']]->addChild($categories[$row['id']]);
- }
- }
- $topCategories = array();
- foreach($topCategoryIds as $id) {
- $topCategories[] = $categories[$id];
- }
- $this->categories = $categories;
- $this->topCategories = $topCategories;
- }
-
- /**
- * Constructs the Category tree and returns the top level categories.
- * @return array All top level categories.
- */
- public function getCategoryTree() {
- return $this->topCategories;
- }
-
- /**
- * Gets a list of all category names.
- * @return array Key is the id, value is the corresponding category name.
- */
- public function getAllCategoryNames() {
- $categories = $this->getCategoryTree();
- $names = array();
- foreach($categories as $cat) {
- $names += $this->getCategoryNames($cat);
- }
-
- return $names;
- }
-
- /**
- * Gets the category names for the specified category and all sub
- * categories.
- * @param Category $category The category that should be traversed.
- * @param string $base The prefix that should be used for all category
- * names.
- * @return array An array of string where each value represent a category
- * name.
- */
- private function getCategoryNames(Category $category, $base = '') {
- $result = array();
- $result[$category->getId()] = $base.$category->getName();
-
- $children = $category->getChildren();
- if(sizeof($children) == 0) {
- return $result;
- }
- foreach($children as $cat) {
- $result += $this->getCategoryNames($cat, $base.$category->getName().'->');
- }
- return $result;
- }
-
- /**
- * Gets the path to that a specified category through the tree.
- * @param integer $categoryId The id of the category for which the path
- * should be found.
- * @return array The category ids sorted so that the id with key 0 is
- * the top level, 1 the next step, 2 the step after that etc. An
- * empty array means that the category could not be found.
- */
- public function getPathTo($categoryId) {
- //We are forced to do a DFS because of how the tree is arranged.
- $topLevel = $this->getCategoryTree();
- foreach($topLevel as $category) {
- $path = $this->recursiveFind($category, $categoryId);
- if(count($path) > 0) {
- return $path;
- }
- }
- return array();
- }
-
- /**
- * A recursive function for finding the correct path via DFS.
- * @param Category $startCategory The Category instance where the
- * search should start.
- * @param integer $stopId The id of the category where the search
- * should stop, i.e. the category to find.
- * @return array All steps that were taken to find the stopId,
- * including the stopId itself. An empty array means that the
- * stopId could not be found.
- */
- private function recursiveFind($startCategory, $stopId) {
- if($startCategory->getId() == $stopId) {
- return array($startCategory->getId());
- }
- $children = $startCategory->getChildren();
- foreach($children as $child) {
- $find = $this->recursiveFind($child, $stopId);
- if(sizeof($find) > 0) {
- return array_merge(array($startCategory->getId()), $find);
- }
- }
- return array();
- }
-
- /**
- * Adds a filter to the archive.
- * @param string $contents The XML contents of the filter file.
- * @param string $description A short description of the filter.
- * @param integer $categoryId The unique identifier of the category that
- * the filter should be placed in.
- * @param string $author The name of the author of the filter.
- * @return boolean True on success, false otherwise.
- */
- public function addFilter($contents, $description, $categoryId, $author) {
- function xml2array($text) {
- $reg_exp = '/<(.*?)>(.*?)<\/\\1>/s';
- $match = array();
- preg_match_all($reg_exp, $text, $match);
- foreach($match[1] as $key=>$val) {
- if(preg_match($reg_exp, $match[2][$key])) {
- $array[$val] = xml2array($match[2][$key]);
- } else {
- $value = $match[2][$key];
- if(strstr($value, '<![CDATA[') !== false) {
- $value = str_replace('<![CDATA[', '', $value);
- $value = str_replace(']]>', '', $value);
- }
- $array[$val] = $value;
- }
- }
- return $array;
- }
-
- //Parse the contents.
- $parsedData = array();
- $curItem = '';
- $parsedData = xml2array($contents);
- if(!(isset($parsedData['filter']['name']) &&
- isset($parsedData['filter']['version']))) {
- return false;
- }
-
- $vars = array(
- 'id' => '',
- 'category_id' => $categoryId,
- 'name' => $parsedData['filter']['name'],
- 'description' => $description,
- 'time_added' => time(),
- 'version' => $parsedData['filter']['version'],
- 'contents' => $contents,
- 'author' => $author,
- 'moderator_id' => 0
- );
-
- global $db;
- $db->queryInsert(TABLE_MPLF_FILTERS, $vars);
- return true;
- }
-
- /**
- * Adds a suggestion of a filter for the moderators to concider.
- * @param integer $filterId The unique identifier of the filter that the
- * change should affect.
- * @param string $description A description of what the change is.
- * @param string $contents The new suggested contents for the filter file.
- */
- public function suggestFilterChange($filterId, $description, $contents) {
- global $db;
-
- $vars = array(
- 'id' => '',
- 'filter_id' => $filterId,
- 'timestamp' => time(),
- 'description' => $description,
- 'contents_after' => $contents,
- 'ip' => $_SERVER['REMOTE_ADDR']
- );
- $db->queryInsert(TABLE_MPLF_CHANGES, $vars);
- }
-
- /**
- * Get the category with the specified id.
- * @param integer $id The unique identifier for the category.
- * @return Category The requested Category instance, null if none could be
- * loaded.
- */
- public function getCategory($id) {
- if(!isset($this->categories[$id])) {
- //Attempt to load it.
- try {
- $this->categories[$id] = new Category($id);
- } catch(Exception $e) {}
- }
- if(isset($this->categories[$id])) {
- //Now loaded, return it.
- return $this->categories[$id];
- }
- return null;
- }
-
- /**
- * Get the edit with the specified id.
- * @param integer $id The unique identifier for the edit.
- * @return Edit The requested Edit instance, null if none could be
- * loaded.
- */
- public function getEdit($id) {
- if(!isset($this->edits[$id])) {
- //Attempt to load it.
- try {
- $this->edits[$id] = new Edit($id);
- } catch(Exception $e) {}
- }
- if(isset($this->edits[$id])) {
- //Now loaded, return it.
- return $this->edits[$id];
- }
- return null;
- }
-
- /**
- * Get the filter with the specified id.
- * @param integer $id The unique identifier for the filter.
- * @return Filter The requested Filter instance, null if none could be
- * loaded.
- */
- public function getFilter($id) {
- if(!isset($this->filters[$id])) {
- //Attempt to load it.
- try {
- $this->filters[$id] = new Filter($id);
- } catch(Exception $e) {}
- }
- if(isset($this->filters[$id])) {
- //Now loaded, return it.
- return $this->filters[$id];
- }
- return null;
- }
-
- /**
- * Get the moderator with the specified id.
- * @param integer $id The unique identifier for the moderator.
- * @return Moderator The requested Moderator instance, null if none could
- * be loaded.
- */
- public function getModerator($id) {
- if(!isset($this->moderators[$id])) {
- //Attempt to load it.
- $moderator = new Moderator($id);
- if($moderator->isValid()) {
- $this->moderators[$id] = $moderator;
- }
- }
- if(isset($this->filters[$id])) {
- //Now loaded, return it.
- return $this->moderators[$id];
- }
- return null;
- }
- }
-
- /**
- * Describes a link category.
- * @author Andreas Launila
- * @package com.lokorin.lokorin.lib
- */
- class Category extends TableEntry {
- /**
- * The name of the category.
- * @var string
- */
- private $name;
- /**
- * The description of the category.
- * @var string
- */
- private $description;
- /**
- * The Category instances that are direct children to this instance.
- * @var array
- */
- private$children;
-
- /**
- * Constructor for Category.
- * @param integer $id The unique identifier to be used.
- */
- public function __construct($id) {
- $this->children = array();
-
- $fields = array(
- "name",
- "description"
- );
- parent::__construct(TABLE_MPLF_CATEGORIES, $id, $fields);
- }
-
- /**
- * @see com.lokorin.lokorin.includes.TableEntry.readRow($row)
- */
- protected function readRow($row) {
- $this->name = $row['name'];
- $this->description = $row['description'];
- }
-
- /**
- * Gets the name for the specific instance (not including parents).
- * @return string A single category name.
- */
- public function getName() {
- return $this->name;
- }
-
- /**
- * Gets the description of the category.
- * @return sring A category description.
- */
- public function getDescription() {
- return $this->description;
- }
-
- /**
- * Adds a child (Category instance).
- * @param string $childToAdd The Category instance that should be added
- * as child element.
- */
- public function addChild(Category $childToAdd) {
- $this->children[] = $childToAdd;
- }
-
- /**
- * Gets all the direct children instances.
- * @return array Key is irrelevant, value is a Category instance.
- */
- public function getChildren() {
- return $this->children;
- }
-
- /**
- * Gets all filters associated with the category, e.g. all filters that
- * have the category as their category.
- * @return array Key is irrelevant, Value is Filter instance.
- */
- public function getAssociatedFilters() {
- global $db, $archive;
-
- $rows = $db->querySelect(TABLE_MPLF_FILTERS, array('id'),
- "WHERE (category_id=".$this->getId().") AND (moderator_id != 0)");
- $filters = array();
- foreach($rows as $row) {
- try {
- $filters[] = $archive->getFilter($row['id']);
- } catch(Exception $e) {}
- }
- return $filters;
- }
- }
-
- /**
- * Describes a filter.
- * @author Andreas Launila
- * @package com.lokorin.lokorin.lib
- */
- class Filter extends TableEntry {
- /**
- * The name of the filter.
- * @var string
- */
- private $name;
- /**
- * A description of the filter.
- * @var string
- */
- private $description;
- /**
- * The timestamp representing the time when the filter was first added.
- * @var integer
- */
- private $timeAdded;
- /**
- * The MPLF version that the filter was designed for.
- * @var string
- */
- private $version;
- /**
- * The author of the filter.
- * @var string
- */
- private $author;
- /**
- * The unique identifiers of Edits that belong to the filter.
- * @var array
- */
- private $edits;
- /**
- * The unique identifier of the category that the filter belongs to.
- * @var integer
- */
- private $categoryId;
- /**
- * The contents of the associated XML file.
- * @var string
- */
- private $contents;
-
- /**
- * Constructor for Filter.
- * @param integer $id The id of the filter.
- */
- public function __construct($id) {
- $fields = array(
- 'category_id',
- 'name',
- 'description',
- 'time_added',
- 'version',
- 'author',
- 'contents'
- );
- parent::__construct(TABLE_MPLF_FILTERS, $id, $fields);
- }
-
- /**
- * @see com.lokorin.lokorin.includes.TableEntry.readRow($row)
- */
- protected function readRow($row) {
- $this->categoryId = $row['category_id'];
- $this->name = htmlspecialchars($row['name']);
- $this->description = htmlspecialchars($row['description']);
- $this->timeAdded = $row['time_added'];
- $this->version = $row['version'];
- $this->author = htmlspecialchars($row['author']);
- $this->contents = $row['contents'];
- }
-
- /**
- * Gets the name of the filter.
- * @return string A filter name.
- */
- public function getName() {
- return $this->name;
- }
-
- /**
- * Gets the description of the filter.
- * @return string A filter description.
- */
- public function getDescription() {
- return $this->description;
- }
-
- /**
- * Gets the timestamp for when the filter was added.
- * @return integer An Unix timestamp.
- */
- public function getAddedTimestamp() {
- return $this->timeAdded;
- }
-
- /**
- * Gets the MPLF version that the filter was designed for.
- * @return string A version string, e.g. "1.3".
- */
- public function getVersion() {
- return $this->version;
- }
-
- /**
- * Gets the author of the filter.
- * @return string An author name.
- */
- public function getAuthor() {
- return $this->author;
- }
-
- /**
- * Gets the category that the filter belongs to.
- * @return Category An instance of Category..
- */
- public function getCategory() {
- return new Category($this->categoryId);
- }
-
- /**
- * Gets all Edit instances that are associated with the filter.
- * @return array Key is the chronological order with 0 being the most
- * recent and so on. Value is an Edit instance.
- */
- public function getAssociatedEdits() {
- global $db;
-
- $edits = array();
- $rows = $db->querySelect(TABLE_MPLF_EDITS, array('id'),
- "WHERE filter_id=".$db->escape(parent::$this->getId())." ORDER BY timestamp");
- foreach($rows as $row) {
- $edits[] = new Edit($row['id']);
- }
- return $edits;
- }
-
- /**
- * Gets the contents of the associated XML file.
- * @return string An XML file.
- * @access public
- */
- public function getContents() {
- return $this->contents;
- }
- }
-
- /**
- * Describes an edit to an filter.
- * @author Andreas Launila
- * @package com.lokorin.lokorin.lib
- */
- class Edit extends TableEntry {
- /**
- * The timestamp when the edit was performed.
- * @var integer
- */
- private $timeEdited;
- /**
- * The description of what was done during the edit.
- * @var string
- */
- private $description;
- /**
- * The id of the moderator that approved the edit.
- * @var integer
- */
- private $moderatorId;
- /**
- * The id of the filter that was edited.
- * @var integer
- */
- private $filterId;
-
- /**
- * Constructor for Edit.
- * @param integer $id The id of the edit to be constructed.
- */
- public function __construct($id) {
- $fields = array(
- 'timestamp',
- 'description',
- 'moderator_id',
- 'filter_id'
- );
- parent::__construct(TABLE_MPLF_EDITS, $id, $fields);
- }
-
- /**
- * @see com.lokorin.lokorin.includes.TableEntry.readRow($row)
- */
- protected function readRow($row) {
- $this->timeEdited = $row['timestamp'];
- $this->description = htmlspecialchars($row['description']);
- $this->moderatorId = $row['moderator_id'];
- $this->filterId = $row['filter_id'];
- }
-
- /**
- * Gets the time when the edit was performed.
- * @return integer A unix timestamp.
- */
- public function getEditedTimestamp() {
- return $this->timeEdited;
- }
-
- /**
- * Gets the description connected to the edit.
- * @return string A description of what has changed.
- */
- public function getDescription() {
- return $this->description;
- }
-
- /**
- * Get the id of the moderator that approved the edit.
- * @return integer An unique moderator identificator.
- */
- public function getModeratorId() {
- return $this->moderatorId;
- }
-
- /**
- * Get the id of the filter that was edited.
- * @return integer An unique filter identificator.
- */
- public function getFilterId() {
- return $this->filterId;
- }
- }
-
- /**
- * Describes a moderator.
- * @author Andreas Launila
- * @package com.lokorin.lokorin.lib
- */
- class Moderator extends TableEntry {
- /**
- * The username of the moderator.
- * @var string
- */
- private $name;
-
- /**
- * Constructor for Moderator.
- * @param integer $id The unique identifier for the Moderator.
- */
- public function __construct($id) {
- parent::__construct(TABLE_MPLF_MODERATORS, $id, array('name'));
- }
-
- /**
- * @see com.lokorin.lokorin.includes.TableEntry.readRow($row)
- */
- protected function readRow($row) {
- $this->name = $row['name'];
- }
-
- /**
- * Gets the name of the moderator.
- * @return string A moderator name.
- */
- public function getName() {
- return $this->name;
- }
- }
- ?>