Subversion Repositories general

Compare Revisions

Ignore whitespace Rev 1285 → Rev 1286

/FileXch/branches/php-impl/lib/parser.php
0,0 → 1,104
<?php
class Parser
{
function checkEmpty($s, $nullable, $field)
{
if($nullable) {
return null;
}
else {
throw new Exception("'$field' must have a value");
}
}
 
function string($s)
{
return $s;
}
 
function integer($s, $nullable, $field)
{
if($s !== null) {
$s = trim($s);
}
 
if($s === null || $s === '') {
return $this->checkEmpty($s, $nullable, $field);
}
 
if(!is_numeric($s)) {
throw new Exception("'$field' is not an integer");
}
 
return intval($s);
}
 
function date($s, $nullable, $field)
{
if($s !== null) {
$s = trim($s);
}
 
if($s === null || $s === '') {
return $this->checkEmpty($s, $nullable, $field);
}
 
$d = date_create($s);
 
if(!$d) {
throw new Exception("'$field' is not a time");
}
else {
return $d;
}
}
 
function boolean($s)
{
return ($s ? true : false);
}
 
function size($s, $nullable, $field)
{
if($s !== null) {
$s = trim($s);
}
 
if($s === null || $s === '') {
return $this->checkEmpty($s, $nullable, $field);
}
 
$s = strtoupper($s);
 
// may end with 'B' - remove
if(substr($s, -1) == 'B') {
$s = substr($s, 0, -1);
if($s === '') {
throw new Exception("'$field' is not a size");
}
}
// find and remove unit
$unit = substr($s, -1);
$mul = 1;
switch($unit) {
case 'G': $mul *= 1024;
case 'M': $mul *= 1024;
case 'K': $mul *= 1024;
}
if($mul > 1) {
$s = substr($s, 0, -1);
$s = trim($s);
if($s === '') {
throw new Exception("'$field' is not a size");
}
}
 
if(!is_numeric($s)) {
throw new Exception("'$field' is not a size");
}
return intval($s) * $mul;
}
}
?>
/FileXch/branches/php-impl/lib/file.php
0,0 → 1,178
<?php
class File
{
public $name;
public $size;
}
 
class FileManager
{
private $endOfLife;
private $root;
private $umask;
 
function __construct($root, $umask)
{
$this->endOfLife = false;
$this->root = $root;
$this->umask = $umask;
 
umask($this->umask);
}
 
function endTheLife()
{
$this->checkLiveCycle();
 
$this->endOfLife = true;
}
 
function checkLiveCycle()
{
if($this->endOfLife) {
throw new Exception("I'm die");
}
}
 
function checkFileName($name)
{
if(!$name) {
throw new Exception("Empty name");
}
 
if(strpos($name, '/') !== false) {
throw new Exception("Name contains slash");
}
 
if(substr($s, 0, 1) == '.') {
throw new Exception("Name starts with dot");
}
}
 
function createDir($name)
{
$this->checkLiveCycle();
$this->checkFileName($name);
 
$fullName = "$this->root/$name";
if(!@mkdir($fullName, 0777, true)) {
if(!is_dir($fullName)) { // already exists?
throw new Exception("Cannot create dir");
}
}
}
 
function removeDir($name)
{
$this->checkLiveCycle();
$this->checkFileName($name);
 
$fullName = "$this->root/$name";
if(!@rmdir($fullName)) {
if(file_exists($fullName)) { // already removed?
throw new Exception("Cannot remove dir");
}
}
}
 
static function cmpFiles($a, $b)
{
if($a->name == $b->name) {
return 0;
}
else {
return ($a->name < $b->name ? -1 : 1);
}
}
 
function listDir($name)
{
$this->checkLiveCycle();
$this->checkFileName($name);
 
$res = array();
$fullName = "$this->root/$name";
$d = dir($fullName);
 
while(false !== ($e = $d->read())) {
if($e == '.' || $e == '..') continue;
$s = stat("$fullName/$e");
 
$f = new File();
$f->name = $e;
$f->size = $s[7];
 
array_push($res, $f);
}
 
$d->close();
 
usort($res, "FileManager::cmpFiles");
 
return $res;
}
 
function removeFile($dir, $name)
{
$this->checkLiveCycle();
$this->checkFileName($dir);
$this->checkFileName($name);
 
if(!unlink("$this->root/$dir/$name")) {
throw new Exception("Cannot remove file");
}
}
 
function removeDirWithFiles($dir)
{
$this->checkLiveCycle();
$this->checkFileName($dir);
 
$fullName = "$this->root/$dir";
$d = dir($fullName);
 
while(false !== ($e = $d->read())) {
if($e == '.' || $e == '..') continue;
 
if(!unlink("$fullName/$e")) {
throw new Exception("Cannot remove file");
}
}
 
if(!@rmdir($fullName)) {
throw new Exception("Cannot remove dir");
}
}
 
function moveFile($tmpName, $dir, $name)
{
$this->checkLiveCycle();
$this->checkFileName($dir);
$this->checkFileName($name);
 
$uniqueName = $name;
$counter = 0;
for(;;) {
$fullName = "$this->root/$dir/$uniqueName";
if(!file_exists($fullName)) {
break;
}
 
$uniqueName = $this->generateUniqueName($name, ++$counter);
}
 
move_uploaded_file($tmpName, $fullName);
}
 
function generateUniqueName($name, $counter)
{
$pos = strrpos($name, '.');
if($pos > 0) {
return substr($name, 0, $pos) . "($counter)" . substr($name, $pos);
}
else {
return "$name($counter)";
}
}
}
?>
/FileXch/branches/php-impl/lib/formatter.php
0,0 → 1,96
<?php
class Formatter
{
function integer($s, $def = '0')
{
if($s === null) {
return $def;
}
else if(!is_int($s)) {
throw new Exception("Not an integer");
}
else {
return '' . $s;
}
}
 
function string($s, $def = '')
{
if(!$s) return $def;
 
return htmlspecialchars($s);
}
 
function stringBegin($s, $len, $cont = '...', $def = '')
{
if(!$s) return $def;
 
if(strlen($s) > $len) {
return $this->string(substr($s, 0, $len) . $cont, $def);
}
else {
return $this->string($s, $def);
}
}
 
function urlPart($s, $def = '')
{
if(!$s) return $def;
 
return urlencode($s);
}
 
function htmlUrlPart($s, $def = '')
{
return $this->string($this->urlPart($s, $def));
}
 
function date($d, $def = '')
{
if(!$d) {
return $def;
}
else if($d instanceof DateTime) {
return date_format($d, 'd.m.Y H:i:s');
}
else if(is_string($d)) {
return $this->string($d, $def);
}
else {
return $def;
}
}
 
function size($s, $def = '')
{
if(!$s) {
return $def;
}
else if($s < 1024) {
return $s . ' B';
}
else if($s < 1024 * 1024) {
return round($s / 1024 * 100) / 100 . ' KB';
}
else if($s < 1024 * 1024 * 1024) {
return round($s / 1024 / 1024 * 100) / 100 . ' MB';
}
else {
return round($s / 1024 / 1024 / 1024 * 100) / 100 . ' GB';
}
}
 
function boolean($b, $true, $false, $def = '')
{
if($b === null) {
return $def;
}
else if($b) {
return $true;
}
else {
return $false;
}
}
}
?>
/FileXch/branches/php-impl/lib/session.php
0,0 → 1,535
<?php
class Session
{
private $fm;
private $id;
private $name;
private $owner;
private $created;
private $expire;
private $sizeLimit;
private $sizeCurrent;
private $countLimit;
private $countCurrent;
private $downloadable;
private $uploadable;
private $deletable;
private $publicComment;
private $privateComment;
private $blocked;
private $removed;
private $fileList;
 
function __construct($db, $fm, $dbRow = null)
{
$this->fm = $fm;
 
if($dbRow) {
$this->id = $db->parseInteger($dbRow['id']);
$this->name = $dbRow['name'];
$this->owner = $dbRow['owner'];
$this->created = $db->parseDate($dbRow['created']);
$this->expire = $db->parseDate($dbRow['expire']);
$this->sizeLimit = $db->parseInteger($dbRow['size_limit']);
$this->countLimit = $db->parseInteger($dbRow['count_limit']);
$this->downloadable = $db->parseBoolean($dbRow['downloadable']);
$this->uploadable = $db->parseBoolean($dbRow['uploadable']);
$this->deletable = $db->parseBoolean($dbRow['deletable']);
$this->publicComment = $dbRow['public_comment'];
$this->privateComment = $dbRow['private_comment'];
$this->blocked = $db->parseBoolean($dbRow['blocked']);
$this->removed = $db->parseBoolean($dbRow['removed']);
}
 
if($this->name) {
$this->fm->createDir($this->name);
$this->fileList = $this->fm->listDir($this->name);
}
else {
$this->fileList = array();
}
$this->statFileList();
}
 
function statFileList()
{
$this->countCurrent = count($this->fileList);
$this->sizeCurrent = 0;
foreach($this->fileList as $f) {
$this->sizeCurrent += $f->size;
}
}
 
function getId()
{
return $this->id;
}
 
function getName()
{
return $this->name;
}
 
function setName($name)
{
if($this->name) {
$this->fm->removeDir($this->name);
}
 
$this->name = $name;
 
if($this->name) {
$this->fm->createDir($this->name);
}
}
 
function getOwner()
{
return $this->owner;
}
 
function setOwner($owner)
{
$this->owner = $owner;
}
 
function getCreated()
{
return $this->created;
}
 
function getExpire()
{
return $this->expire;
}
 
function setExpire($expire)
{
$this->expire = $expire;
}
 
function getSizeLimit()
{
return $this->sizeLimit;
}
 
function setSizeLimit($sizeLimit)
{
$this->sizeLimit = $sizeLimit;
}
 
function getSizeCurrent()
{
return $this->sizeCurrent;
}
 
function getCountLimit()
{
return $this->countLimit;
}
 
function setCountLimit($countLimit)
{
$this->countLimit = $countLimit;
}
 
function getCountCurrent()
{
return $this->countCurrent;
}
 
function getDownloadable()
{
return $this->downloadable;
}
 
function setDownloadable($downloadable)
{
$this->downloadable = $downloadable;
}
 
function getUploadable()
{
return $this->uploadable;
}
 
function setUploadable($uploadable)
{
$this->uploadable = $uploadable;
}
 
function getDeletable()
{
return $this->deletable;
}
 
function setDeletable($deletable)
{
$this->deletable = $deletable;
}
 
function getPublicComment()
{
return $this->publicComment;
}
 
function setPublicComment($publicComment)
{
$this->publicComment = $publicComment;
}
 
function getPrivateComment()
{
return $this->privateComment;
}
 
function setPrivateComment($privateComment)
{
$this->privateComment = $privateComment;
}
 
function isExpired()
{
if(!$this->expire) return false;
 
return ($this->expire <= date_create());
}
 
function isBlocked()
{
if(!$this->blocked) return false;
 
return $this->blocked;
}
 
function isActive()
{
return (!$this->isExpired() && !$this->isBlocked());
}
 
function getBlocked()
{
return $this->blocked;
}
 
function setBlocked($blocked)
{
$this->blocked = $blocked;
}
 
function getRemoved()
{
return $this->removed;
}
 
function getFileList()
{
return $this->fileList;
}
 
function removeFile($name)
{
$this->fm->removeFile($this->name, $name);
}
 
function removeAll()
{
$this->fm->removeDirWithFiles($this->name);
}
 
function saveFile($tmpName, $name)
{
$this->fm->moveFile($tmpName, $this->name, $this->prepareSaveFileName($name));
}
 
function prepareSaveFileName($name)
{
// get tail after last (back)slash
$pos1 = strrpos($name, '/');
$pos2 = strrpos($name, '\\');
if($pos !== false && $pos1 < $pos2) {
$pos = $pos2;
}
else {
$pos = $pos1;
}
if($pos !== false) {
$name = substr($name, $pos+1);
}
 
// strip leading dot
if($name != '') {
if(substr($name, 0, 1) == '.') {
$name = substr($name, 1);
}
}
 
return $name;
}
}
 
class SessionManager
{
private $db;
private $fm;
private $endOfLife;
private $alive;
private $removed;
 
function __construct($db, $fm)
{
$this->db = $db;
$this->fm = $fm;
$this->endOfLife = false;
}
 
function endTheLife()
{
$this->checkLiveCycle();
 
$this->endOfLife = true;
}
 
function checkLiveCycle()
{
if($this->endOfLife) {
throw new Exception("I'm die");
}
}
 
function createList($removed)
{
$this->checkLiveCycle();
 
$res = array();
 
$this->db->query("select * from sessions where removed = " . $this->db->formatBoolean($removed)
. " order by created");
while($row = $this->db->fetchRow()) {
array_push($res, new Session($this->db, $this->fm, $row));
}
$this->db->freeResult();
 
return $res;
}
 
function summaryField($current, &$summary)
{
if($summary === null) {
}
else if($current === null) {
$summary = null;
}
else {
$summary += $current;
}
}
 
function summary($list)
{
$res = array("sizeLimit" => 0, "sizeCurrent" => 0, "countLimit" => 0, "countCurrent" => 0);
 
foreach($list as $e) {
$this->summaryField($e->getSizeLimit(), $res["sizeLimit"]);
$this->summaryField($e->getSizeCurrent(), $res["sizeCurrent"]);
$this->summaryField($e->getCountLimit(), $res["countLimit"]);
$this->summaryField($e->getCountCurrent(), $res["countCurrent"]);
}
 
return $res;
}
 
function newSession()
{
$this->checkLiveCycle();
 
$s = new Session($this->db, $this->fm);
 
$s->setOwner($_SERVER["REMOTE_USER"]);
$s->setDownloadable(true);
$s->setUploadable(true);
 
return $s;
}
 
function getSession($id)
{
$this->checkLiveCycle();
 
$s = null;
 
$this->db->query("select * from sessions where id = " . $this->db->formatInteger($id));
if($row = $this->db->fetchRow()) {
$s = new Session($this->db, $this->fm, $row);
}
$this->db->freeResult();
 
if($s === null) {
throw new Exception("Session not found");
}
 
return $s;
}
 
function setNewSessionName($s)
{
$name = null;
$found = true;
while($found) {
$name = $this->generateRandomName();
 
$this->db->query("select id from sessions where name = " . $this->db->formatString($name));
if(!$this->db->fetchRow()) {
$found = false;
}
$this->db->freeResult();
}
$s->setName($name);
}
 
function generateRandomName()
{
$chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
$max = strlen($chars) - 1;
$name = '';
 
for($i = 0; $i < 16; ++$i) {
$name .= $chars[mt_rand(0, $max)];
}
 
return $name;
}
 
function listAlive()
{
$this->checkLiveCycle();
 
if($this->alive === null) {
$this->alive = $this->createList(false);
}
return $this->alive;
}
 
function summaryAlive()
{
$this->checkLiveCycle();
 
if($this->alive === null) {
$this->alive = $this->createList(false);
}
 
return $this->summary($this->alive);
}
 
function listRemoved()
{
$this->checkLiveCycle();
 
if($this->removed === null) {
$this->removed = $this->createList(true);
}
return $this->removed;
}
 
function summaryRemoved()
{
$this->checkLiveCycle();
 
if($this->removed === null) {
$this->removed = $this->createList(true);
}
 
return $this->summary($this->removed);
}
 
function purge()
{
$this->checkLiveCycle();
 
if($this->removed === null) {
$this->removed = $this->createList(true);
}
$this->db->execute("delete from sessions where removed = true");
 
foreach($this->removed as $s) {
$s->removeAll();
}
 
$this->invalidateLists();
}
 
function remove($id)
{
$this->checkLiveCycle();
 
$this->db->execute("update sessions set removed = true where id = "
. $this->db->formatInteger($id));
 
$this->invalidateLists();
}
 
function restore($id)
{
$this->checkLiveCycle();
 
$this->db->execute("update sessions set removed = false where id = "
. $this->db->formatInteger($id));
 
$this->invalidateLists();
}
 
function insert($s)
{
$this->checkLiveCycle();
 
if(!$s->getName()) {
$this->setNewSessionName($s);
}
 
$this->db->execute("insert into sessions "
. " (name, owner, expire, size_limit, count_limit, downloadable, uploadable,"
. " deletable, public_comment, private_comment, blocked) values ("
. $this->db->formatString($s->getName()) . ", "
. $this->db->formatString($s->getOwner()) . ", "
. $this->db->formatDate($s->getExpire()) . ", "
. $this->db->formatInteger($s->getSizeLimit()) . ", "
. $this->db->formatInteger($s->getCountLimit()) . ", "
. $this->db->formatBoolean($s->getDownloadable()) . ", "
. $this->db->formatBoolean($s->getUploadable()) . ", "
. $this->db->formatBoolean($s->getDeletable()) . ", "
. $this->db->formatString($s->getPublicComment()) . ", "
. $this->db->formatString($s->getPrivateComment()) . ", "
. $this->db->formatBoolean($s->getBlocked()) . ")");
 
$this->invalidateLists();
}
 
function update($s)
{
$this->checkLiveCycle();
 
$this->db->execute("update sessions set"
. " expire = " . $this->db->formatDate($s->getExpire()) . ","
. " size_limit = " . $this->db->formatInteger($s->getSizeLimit()) . ","
. " count_limit = " . $this->db->formatInteger($s->getCountLimit()) . ","
. " downloadable = " . $this->db->formatBoolean($s->getDownloadable()) . ","
. " uploadable = " . $this->db->formatBoolean($s->getUploadable()) . ","
. " deletable = " . $this->db->formatBoolean($s->getDeletable()) . ","
. " public_comment = " . $this->db->formatString($s->getPublicComment()) . ","
. " private_comment = " . $this->db->formatString($s->getPrivateComment()) . ","
. " blocked = " . $this->db->formatBoolean($s->getBlocked())
. " where id = " . $this->db->formatInteger($s->getId()));
 
$this->invalidateLists();
}
 
function invalidateLists()
{
$this->alive = null;
$this->removed = null;
}
}
?>
/FileXch/branches/php-impl/lib/db.php
0,0 → 1,272
<?php
function createDbInterface($type, $host, $user, $password, $database)
{
if($type == "mysql") {
return new DbMySql($host, $user, $password, $database);
}
else {
throw new Exception("Unknown DB type '$type'");
}
}
 
class DbMySql
{
private $endOfLife;
private $host;
private $user;
private $password;
private $database;
private $conn;
private $result;
private $rollbacked;
 
function __construct($host, $user, $password, $database)
{
debugMsg("DbMySql::__construct");
 
$this->endOfLife = false;
$this->host = $host;
$this->user = $user;
$this->password = $password;
$this->database = $database;
}
 
function __destruct()
{
debugMsg("DbMySql::__destruct");
 
$this->disconnect();
}
 
function endTheLife()
{
$this->checkLiveCycle();
$this->disconnect();
 
$this->endOfLife = true;
}
 
function checkLiveCycle()
{
if($this->endOfLife) {
throw new Exception("I'm die");
}
}
 
function connect()
{
$this->checkLiveCycle();
 
if(!$this->conn) {
debugMsg("DbMySql::connect");
 
$this->conn = mysql_connect($this->host, $this->user, $this->password);
if(!$this->conn) {
throw new Exception("Cannot connect to MySql database: " . mysql_error());
}
 
mysql_select_db($this->database, $this->conn);
}
}
 
function disconnect()
{
if($this->conn) {
$this->checkLiveCycle();
 
debugMsg("DbMySql::disconnect");
 
if(!$this->rollbacked) {
$this->commit();
}
 
mysql_close($this->conn);
$this->conn = null;
}
}
 
function beginTransaction()
{
$this->execute("begin");
$this->rollbacked = false;
}
 
function commit()
{
$this->execute("commit");
}
 
function rollback()
{
$this->execute("rollback");
$this->rollbacked = true;
}
 
function query($sql)
{
$this->checkLiveCycle();
 
debugMsg("DbMySql::query [$sql]");
$this->connect();
$this->result = mysql_query($sql);
 
if(!$this->result) {
throw new Exception('Cannot execute query: ' . mysql_error() . "\n" . $sql);
}
 
return $this->result;
}
 
function freeResult()
{
$this->checkLiveCycle();
 
debugMsg("DbMySql::freeResult");
 
mysql_free_result($this->result);
}
 
function fetchRow()
{
$this->checkLiveCycle();
 
debugMsg("DbMySql::fetchRow");
 
if($this->result) {
return mysql_fetch_assoc($this->result);
}
else {
return false;
}
}
 
function execute($sql)
{
$this->checkLiveCycle();
 
debugMsg("DbMySql::execute [$sql]");
 
$this->connect();
 
$success = mysql_query($sql);
 
if(!$success) {
throw new Exception('Cannot execute query: ' . mysql_error() . "\n" . $sql);
}
}
 
function escape($s)
{
$this->checkLiveCycle();
 
$this->connect();
 
return mysql_real_escape_string($s);
}
 
function formatString($s, $nullable = true)
{
$this->checkLiveCycle();
 
if($s === null && $nullable) {
return ($nullable ? 'null' : "''");
}
else if(is_string($s)) {
return "'" . $this->escape($s) . "'";
}
else {
throw new Exception("Not a string");
}
}
 
function formatBoolean($b, $nullable = true)
{
$this->checkLiveCycle();
 
if($b === null) {
return ($nullable ? 'null' : 'false');
}
else {
return ($b ? 'true' : 'false');
}
}
 
function formatInteger($i, $def = null)
{
$this->checkLiveCycle();
 
if($i === null) {
if($def === null) {
return 'null';
}
else {
return '' . $def;
}
}
else if(is_int($i)) {
return '' . $i;
}
else {
throw new Exception("Not an integer");
}
}
 
function formatDate($d, $def = null)
{
$this->checkLiveCycle();
 
if($d === null) {
if($def === null) {
return 'null';
}
else {
return "'" . date_format($def, 'Y-m-d H:i:s') . "'";
}
}
else if($d instanceof DateTime) {
return "'" . date_format($d, 'Y-m-d H:i:s') . "'";
}
else {
throw new Exception("Not a date");
}
}
 
function parseInteger($s, $def = null)
{
$this->checkLiveCycle();
 
if($s === null) {
return $def;
}
else {
return intval($s);
}
}
 
function parseBoolean($s, $def = null)
{
$this->checkLiveCycle();
 
if($s === null) {
return $def;
}
else {
return ($s ? true : false);
}
}
 
function parseDate($s, $def = null)
{
$this->checkLiveCycle();
 
if($s === null) {
return $def;
}
else {
return date_create($s);
}
}
 
}
?>
/FileXch/branches/php-impl/lib/common.php
0,0 → 1,56
<?php
if(!$isEntryPoint) {
die("Not an entry point");
}
 
include("config/config.php");
include("lib/db.php");
include("lib/file.php");
include("lib/session.php");
include("lib/formatter.php");
include("lib/parser.php");
 
$dataAllowed = true; // interaction with DB or file system is allowed
 
$db = createDbInterface(Config::dbType, Config::dbHost, Config::dbUser, Config::dbPass, Config::dbDatabase);
$fm = new FileManager(Config::root, Config::umask);
$sm = new SessionManager($db, $fm);
$f = new Formatter();
$p = new Parser();
 
function debugMsg($msg)
{
//echo "$msg<br>\n";
}
 
function dataCollected()
{
global $dataAllowed, $db, $fm, $sm;
 
if($dataAllowed) {
// interaction with DB or file system is not more allowed
$dataAllowed = false;
$db->endTheLife();
$fm->endTheLife();
$sm->endTheLife();
}
}
 
function checkDataCollected()
{
global $dataAllowed;
 
if($dataAllowed) {
throw new Exception("Data collection is still allowed");
}
}
 
function generalError()
{
global $db;
 
$db->rollback();
dataCollected();
include("pages/general_error.php");
}
?>