<?php
/*
IndexFile.php, provides functions to edit index files
Copyright (C) 2003-2005 Arend van Beelen, Auton Rijnsburg
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
For any questions, comments or whatever, you may mail me at: hide@address.com
*/
require_once('Login.php');
require_once('Signal.php');
require_once('URI.php');
// define sections to read for reading XML files
define('ADMS_IndexFileReadingNothing', 0);
define('ADMS_IndexFileReadingRoot', 1);
define('ADMS_IndexFileReadingEntry', 2);
define('ADMS_IndexFileReadingMeta', 3);
define('ADMS_IndexFileReadingIpAccess', 4);
define('ADMS_IndexFileReadingUserAccess', 5);
define('ADMS_IndexFileReadingGroupAccess', 6);
define('ADMS_IndexFileReadingOtherAccess', 7);
class ADMS_IndexFileEntry
{
public $id = 0;
public $meta = array();
public $ipAccess = array();
public $userAccess = array();
public $groupAccess = array();
public $otherAccess = PERMISSION_NONE;
}
// class for handling folders and their entries through index.xml files
class ADMS_IndexFile
{
// constructor
function __construct()
{
if(isset(self::$permissions) == false)
{
self::$permissions = array();
self::$permissions[PERMISSION_NONE] = 'none';
self::$permissions[PERMISSION_READ] = 'read';
self::$permissions[PERMISSION_APPEND] = 'append';
self::$permissions[PERMISSION_MODIFY] = 'modify';
self::$permissions[PERMISSION_DELETE] = 'delete';
self::$permissions[PERMISSION_ADMINISTRATE] = 'administrate';
}
$this->reset();
}
// resets class
public function reset()
{
$this->filename = '';
$this->entries = array();
$this->changed = false;
}
// handles opening tags in XML files
private function open_StartElement($parser, $name, $attrs)
{
if($this->unknown == true)
{
$this->level++;
return;
}
$id = isset($attrs['ID']) ? $attrs['ID'] : '';
$key = isset($attrs['KEY']) ? $attrs['KEY'] : '';
$value = isset($attrs['VALUE']) ? $attrs['VALUE'] : '';
$i18n = isset($attrs['I18N']) ? $attrs['I18N'] : '';
switch($this->readingmode)
{
case ADMS_IndexFileReadingNothing:
switch($name)
{
case 'XML':
$this->readingmode = ADMS_IndexFileReadingRoot;
break;
default:
if($this->level++ == 0)
{
trigger_error("Unknown element \"$name\" outside <xml>");
}
$this->unknown = true;
}
break;
case ADMS_IndexFileReadingRoot:
switch($name)
{
case 'ENTRY':
if($id != '')
{
$this->readingmode = ADMS_IndexFileReadingEntry;
$this->entries[$this->currententry] = new ADMS_IndexFileEntry;
$this->entries[$this->currententry]->id = $id;
}
else
{
if($this->level++ == 0)
{
trigger_error("Entry without required id tag");
}
$this->unknown = true;
}
break;
default:
if($this->level++ == 0)
{
trigger_error("Unknown element \"$name\" inside <xml>");
}
$this->unknown = true;
}
break;
case ADMS_IndexFileReadingEntry:
if($i18n == 'true')
{
$value = i18n($value);
}
switch($name)
{
case 'META':
$this->readingmode = ADMS_IndexFileReadingMeta;
$this->entries[$this->currententry]->meta[$key] = $value;
break;
case 'IPACCESS':
$this->readingmode = ADMS_IndexFileReadingIpAccess;
$this->entries[$this->currententry]->ipAccess[$key] = self::interpretPermissionsString($value);
break;
case 'USERACCESS':
$this->readingmode = ADMS_IndexFileReadingUserAccess;
$this->entries[$this->currententry]->userAccess[$key] = self::interpretPermissionsString($value);
break;
case 'GROUPACCESS':
$this->readingmode = ADMS_IndexFileReadingGroupAccess;
$this->entries[$this->currententry]->groupAccess[$key] = self::interpretPermissionsString($value);
break;
case 'OTHERACCESS':
$this->readingmode = ADMS_IndexFileReadingOtherAccess;
$this->entries[$this->currententry]->otherAccess = self::interpretPermissionsString($value);
break;
default:
if($this->level++ == 0)
{
trigger_error("Unknown element \"$name\" inside <entry>");
}
$this->unknown = true;
}
break;
default:
if($this->level++ == 0)
{
trigger_error("Element \"$name\" opened in element without children");
}
$this->unknown = true;
}
}
// handles closing tags in XML files
private function open_EndElement($parser, $name)
{
if($this->unknown == true)
{
if(--$this->level == 0)
{
$this->unknown = false;
}
return;
}
switch($this->readingmode)
{
case ADMS_IndexFileReadingRoot:
if($name == 'XML')
{
$this->readingmode = ADMS_IndexFileReadingNothing;
}
else
{
trigger_error("Unknown element \"$name\" closed in <xml>");
}
break;
case ADMS_IndexFileReadingEntry:
if($name == 'ENTRY')
{
$this->readingmode = ADMS_IndexFileReadingRoot;
$this->currententry++;
}
else
{
trigger_error("Unknown element \"$name\" closed in <entry>");
}
break;
case ADMS_IndexFileReadingMeta:
if($name == 'META')
{
$this->readingmode = ADMS_IndexFileReadingEntry;
}
else
{
trigger_error("Unknown element \"$name\" closed in <meta>");
}
break;
case ADMS_IndexFileReadingIpAccess:
if($name == 'IPACCESS')
{
$this->readingmode = ADMS_IndexFileReadingEntry;
}
else
{
trigger_error("Unknown element \"$name\" closed in <ipaccess>");
}
break;
case ADMS_IndexFileReadingUserAccess:
if($name == 'USERACCESS')
{
$this->readingmode = ADMS_IndexFileReadingEntry;
}
else
{
trigger_error("Unknown element \"$name\" closed in <useraccess>");
}
break;
case ADMS_IndexFileReadingGroupAccess:
if($name == 'GROUPACCESS')
{
$this->readingmode = ADMS_IndexFileReadingEntry;
}
else
{
trigger_error("Unknown element \"$name\" closed in <groupaccess>");
}
break;
case ADMS_IndexFileReadingOtherAccess:
if($name == 'OTHERACCESS')
{
$this->readingmode = ADMS_IndexFileReadingEntry;
}
else
{
trigger_error("Unknown element \"$name\" closed in <otheracces>");
}
break;
}
}
// handles XML data
private function open_Data($parser, $data)
{
return;
}
// opens the index.xml file in a directory
public function open($filename, $mode = 'r')
{
$this->reset();
// open the file
if($fp = fopen($filename, 'r'))
{
// initialize XML parser
$xml_parser = xml_parser_create();
xml_set_element_handler($xml_parser, array($this, 'open_StartElement'), array($this, 'open_EndElement'));
xml_set_character_data_handler($xml_parser, array($this, 'open_Data'));
$this->readingmode = ADMS_IndexFileReadingNothing;
$this->unknown = false;
$this->level = 0;
$this->currententry = 0;
while($data = str_replace("\n", "", fread($fp, 4096)))
{
if(!xml_parse($xml_parser, $data, feof($fp)))
{
trigger_error("Couldn't parse XML index file: ".xml_error_string(xml_get_error_code($xml_parser)));
$this->reset();
return false;
}
}
// clean up
fclose($fp);
xml_parser_free($xml_parser);
$this->filename = $filename;
Signal::emit('ADMS_IndexFileOpened', $this);
return true;
}
trigger_error("Couldn't open XML index file");
return false;
}
// saves the XML document in memory to file
public function save($filename = false)
{
if($filename == false)
{
if($this->changed == false)
{
return true;
}
$filename = $this->filename;
}
// open the file
if($fp = fopen($filename, 'w'))
{
// write heading
fwrite($fp, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".
"<xml>\n");
// write entries
foreach($this->entries as $entry)
{
fwrite($fp, " <entry id=\"{$entry->id}\">\n");
foreach($entry->meta as $key => $value)
{
if($value == '')
{
continue;
}
if($value == i18n("(top of the system)"))
{
$value = "(top of the system)";
$i18nOption = ' i18n="true"';
}
else
{
$i18nOption = '';
}
fwrite($fp, " <meta key=\"$key\" value=\"".htmlspecialchars($value)."\"$i18nOption/>\n");
}
foreach($entry->ipAccess as $ipRange => $access)
{
$access = self::createPermissionsString($access);
fwrite($fp, " <ipaccess key=\"".htmlspecialchars($ipRange)."\" value=\"$access\"/>\n");
}
foreach($entry->userAccess as $user => $access)
{
$access = self::createPermissionsString($access);
fwrite($fp, " <useraccess key=\"".htmlspecialchars($user)."\" value=\"$access\"/>\n");
}
foreach($entry->groupAccess as $group => $access)
{
$access = self::createPermissionsString($access);
fwrite($fp, " <groupaccess key=\"".htmlspecialchars($group)."\" value=\"$access\"/>\n");
}
if(isset($entry->otherAccess))
{
$access = self::createPermissionsString($entry->otherAccess);
fwrite($fp, " <otheraccess value=\"$access\"/>\n");
}
fwrite($fp, " </entry>\n");
}
// closing tag
fwrite($fp, "</xml>\n");
// clean up
fclose($fp);
Signal::emit('ADMS_IndexFileSaved', $this, $filename);
return true;
}
trigger_error("Couldn't save XML index file");
return false;
}
// returns the filename of the opened file
public function filename()
{
return $this->filename;
}
// sets a new filename, this filename will be used as default when saving the file
public function setFilename($filename)
{
$this->changed = true;
$this->filename = $filename;
}
// returns all entries
public function entries()
{
return $this->entries;
}
// returns the first free ID in this directory
public function freeID()
{
for($id = 0; true; $id++)
{
if(glob(dirname($this->filename)."/$id*") == false)
{
return $id;
}
}
}
// adds an entry to the file
public function addEntry($name)
{
$this->changed = true;
$entrynum = sizeof($this->entries);
$this->entries[$entrynum] = new ADMS_IndexFileEntry;
$this->entries[$entrynum]->id = $this->freeID();
$this->entries[$entrynum]->meta['name'] = $name;
$this->entries[$entrynum]->meta['ctime'] = ''.time();
$this->entries[$entrynum]->meta['mtime'] = ''.time();
$this->entries[$entrynum]->meta['owner'] = Login::username();
return $entrynum;
}
// searches for an entry given the id
public function searchEntry($id)
{
foreach($this->entries as $entrynum => $entry)
{
if($entry->id == $id)
{
return $entrynum;
}
}
return false;
}
// removes an entry from a file
public function removeEntry($entrynum)
{
$this->changed = true;
array_splice($this->entries, $entrynum, 1);
}
// returns the value of a meta key
public function meta($entrynum, $key)
{
if(isset($this->entries[$entrynum]))
{
return (isset($this->entries[$entrynum]->meta[$key]) ? $this->entries[$entrynum]->meta[$key] : false);
}
return false;
}
// set a new meta key for an entry
public function setMeta($entrynum, $key, $value = false)
{
if(isset($this->entries[$entrynum]))
{
$this->changed = true;
if($value === false)
{
unset($this->entries[$entrynum]->meta[$key]);
}
else
{
$this->entries[$entrynum]->meta[$key] = $value;
}
$this->entries[$entrynum]->meta['mtime'] = ''.time();
}
}
// returns all meta data in an array
public function metaArray($entrynum)
{
if(isset($this->entries[$entrynum]))
{
return $this->entries[$entrynum]->meta;
}
return array();
}
// sets all meta data through an array
public function setMetaArray($entrynum, $metaArray)
{
if(isset($this->entries[$entrynum]))
{
$this->entries[$entrynum]->meta = $metaArray;
$this->entries[$entrynum]->meta['mtime'] = ''.time();
}
}
// returns the access for a given IP range
public function ipAccess($entrynum, $ipRange)
{
if(isset($this->entries[$entrynum]))
{
return (isset($this->entries[$entrynum]->ipAccess[$ipRange]) ? $this->entries[$entrynum]->ipAccess[$ipRange] : false);
}
return false;
}
// sets access rights for an IP range for an entry
public function setIpAccess($entrynum, $ipRange, $access = false)
{
if(isset($this->entries[$entrynum]))
{
$this->changed = true;
if($access === false)
{
unset($this->entries[$entrynum]->ipAccess[$ipRange]);
}
else
{
$this->entries[$entrynum]->ipAccess[$ipRange] = $access;
}
}
}
// returns the access permissions of all IP ranges in an array
public function ipAccessArray($entrynum)
{
if(isset($this->entries[$entrynum]))
{
return $this->entries[$entrynum]->ipAccess;
}
return array();
}
// sets the access permissions for all IP ranges through an array
public function setIpAccessArray($entrynum, $accessArray)
{
if(isset($this->entries[$entrynum]))
{
$this->changed = true;
$this->entries[$entrynum]->ipAccess = $accessArray;
}
}
// returns the access for a certain user
public function userAccess($entrynum, $user)
{
if(isset($this->entries[$entrynum]))
{
return (isset($this->entries[$entrynum]->userAccess[$user]) ? $this->entries[$entrynum]->userAccess[$user] : false);
}
return false;
}
// sets access rights for a user for an entry
public function setUserAccess($entrynum, $user, $access = false)
{
if(isset($this->entries[$entrynum]))
{
$this->changed = true;
if($access === false)
{
unset($this->entries[$entrynum]->userAccess[$user]);
}
else
{
$this->entries[$entrynum]->userAccess[$user] = $access;
}
}
}
// returns the access permissions of all users in an array
public function userAccessArray($entrynum)
{
if(isset($this->entries[$entrynum]))
{
return $this->entries[$entrynum]->userAccess;
}
return array();
}
// sets the access permissions for all users through an array
public function setUserAccessArray($entrynum, $accessArray)
{
if(isset($this->entries[$entrynum]))
{
$this->changed = true;
$this->entries[$entrynum]->userAccess = $accessArray;
}
}
// returns the access for a certain group
public function groupAccess($entrynum, $group)
{
if(isset($this->entries[$entrynum]))
{
return (isset($this->entries[$entrynum]->groupAccess[$group]) ? $this->entries[$entrynum]->groupAccess[$group] : false);
}
return false;
}
// sets access rights for a group for an entry
public function setGroupAccess($entrynum, $group, $access = false)
{
if(isset($this->entries[$entrynum]))
{
$this->changed = true;
if($access === false)
{
unset($this->entries[$entrynum]->groupAccess[$group]);
}
else
{
$this->entries[$entrynum]->groupAccess[$group] = $access;
}
}
}
// returns the access permissions of all groups in an array
public function groupAccessArray($entrynum)
{
if(isset($this->entries[$entrynum]))
{
return $this->entries[$entrynum]->groupAccess;
}
return array();
}
// sets the access permissions for all groups through an array
public function setGroupAccessArray($entrynum, $accessArray)
{
if(isset($this->entries[$entrynum]))
{
$this->changed = true;
$this->entries[$entrynum]->groupAccess = $accessArray;
}
}
// returns the access for others
public function otherAccess($entrynum)
{
if(isset($this->entries[$entrynum]))
{
return (isset($this->entries[$entrynum]->otherAccess) ? $this->entries[$entrynum]->otherAccess : false);
}
return false;
}
// sets access rights for others for an entry
public function setOtherAccess($entrynum, $access = false)
{
if(isset($this->entries[$entrynum]))
{
$this->changed = true;
if($access === false)
{
unset($this->entries[$entrynum]->otherAccess);
}
else
{
$this->entries[$entrynum]->otherAccess = $access;
}
}
}
// interprets a comma-seperated string containing permissions
protected static function interpretPermissionsString($permissionsString)
{
$permissions = PERMISSION_NONE;
$permissionStrings = explode(',', $permissionsString);
for($permission = PERMISSION_READ; $permission <= PERMISSION_ADMINISTRATE; $permission <<= 1)
{
if(array_search(self::$permissions[$permission], $permissionStrings) !== false)
{
$permissions |= $permission;
}
}
return $permissions;
}
// creates a comma-seperated string listed all permissions
protected static function createPermissionsString($permissions)
{
$permissionsString = 'none';
for($permission = PERMISSION_READ; $permission <= PERMISSION_ADMINISTRATE; $permission <<= 1)
{
if($permissions & $permission)
{
if($permissionsString == 'none')
{
$permissionsString = self::$permissions[$permission];
}
else
{
$string = self::$permissions[$permission];
$permissionsString .= ",$string";
}
}
}
return $permissionsString;
}
protected static $permissions; // strings for specifying permissions
protected $filename; // name of the current file
protected $entries; // array containing the entries
protected $changed; // boolean telling when the indexfile needs to be changed
}
?>