<?php
require_once 'weave_basic_object.php';
class WeaveStorage
{
private $_username;
private $_dbh;
function __construct($username)
{
$this->_username = $username;
$path = explode('/', $_SERVER['SCRIPT_FILENAME']);
$db_name = 'weave_db';
array_pop($path);
array_push($path, $db_name);
$db_name = implode('/', $path);
$create_tables = !file_exists($db_name);
try
{
$this->_dbh = new PDO('sqlite:' . $db_name);
$this->_dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch( PDOException $exception )
{
throw new Exception("Database unavailable", 503);
}
if ($create_tables)
$this->setup_db();
}
function get_connection()
{
return $this->_dbh;
}
function begin_transaction()
{
try
{
$this->_dbh->beginTransaction();
}
catch( PDOException $exception )
{
error_log("begin_transaction: " . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
return 1;
}
function commit_transaction()
{
$this->_dbh->commit();
return 1;
}
function get_max_timestamp($collection)
{
if (!$collection)
{
return 0;
}
try
{
$select_stmt = 'select max(modified) from wbo where username = :username and collection = :collection';
$sth = $this->_dbh->prepare($select_stmt);
$sth->bindParam(':username', $this->_username);
$sth->bindParam(':collection', $collection);
$sth->execute();
}
catch( PDOException $exception )
{
error_log("get_max_timestamp: " . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
$result = $sth->fetchColumn();
return round((float)$result, 2);
}
function get_collection_list()
{
try
{
$select_stmt = 'select distinct(collection) from wbo where username = :username';
$sth = $this->_dbh->prepare($select_stmt);
$sth->bindParam(':username', $this->_username);
$sth->execute();
}
catch( PDOException $exception )
{
error_log("get_collection_list: " . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
$collections = array();
while ($result = $sth->fetchColumn())
{
$collections[] = $result;
}
return $collections;
}
function get_collection_list_with_timestamps()
{
try
{
$select_stmt = 'select collection, max(modified) as timestamp from wbo where username = :username group by collection';
$sth = $this->_dbh->prepare($select_stmt);
$sth->bindParam(':username', $this->_username);
$sth->execute();
}
catch( PDOException $exception )
{
error_log("get_collection_list: " . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
$collections = array();
while ($result = $sth->fetch(PDO::FETCH_NUM))
{
$collections[$result[0]] = (float)$result[1];
}
return $collections;
}
function get_collection_list_with_counts()
{
try
{
$select_stmt = 'select collection, count(*) as ct from wbo where username = :username group by collection';
$sth = $this->_dbh->prepare($select_stmt);
$sth->bindParam(':username', $this->_username);
$sth->execute();
}
catch( PDOException $exception )
{
error_log("get_collection_list_with_counts: " . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
$collections = array();
while ($result = $sth->fetch(PDO::FETCH_NUM))
{
$collections[$result[0]] = (int)$result[1];
}
return $collections;
}
function store_object(&$wbo)
{
try
{
$insert_stmt = 'replace into wbo (username, id, collection, parentid, predecessorid, sortindex, modified, payload, payload_size, depth)
values (:username, :id, :collection, :parentid, :predecessorid, :sortindex, :modified, :payload, :payload_size, :depth)';
$sth = $this->_dbh->prepare($insert_stmt);
$sth->bindParam(':username', $this->_username);
$id=$wbo->id();$sth->bindParam(':id', $id);
$col=$wbo->collection();$sth->bindParam(':collection', $coll);
$parent=$wbo->parentid();$sth->bindParam(':parentid', $parent);
$pred=$wbo->predecessorid();$sth->bindParam(':predecessorid', $pred);
$depth=$wbo->depth();$sth->bindParam(':depth', $depth);
$sort=$wbo->sortindex();$sth->bindParam(':sortindex', $sort);
$modif=$wbo->modified();$sth->bindParam(':modified', $modif);
$payload=$wbo->payload();$sth->bindParam(':payload', $payload);
$size=$wbo->payload_size();$sth->bindParam(':payload_size', $size);
$sth->execute();
}
catch( PDOException $exception )
{
error_log("store_object: " . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
return 1;
}
function update_object(&$wbo)
{
$update = "update wbo set ";
$params = array();
$update_list = array();
if (!$wbo->id() || !$wbo->collection())
{
error_log('Trying to update without a valid id or collection!');
return 0;
}
if ($wbo->parentid_exists())
{
$update_list[] = "parentid = ?";
$params[] = $wbo->parentid();
}
if ($wbo->parentid_exists())
{
$update_list[] = "predecessorid = ?";
$params[] = $wbo->predecessorid();
}
if ($wbo->depth_exists())
{
$update_list[] = "depth = ?";
$params[] = $wbo->depth();
}
if ($wbo->sortindex_exists())
{
$update_list[] = "sortindex = ?";
$params[] = $wbo->sortindex();
}
if ($wbo->payload_exists())
{
$update_list[] = "payload = ?";
$update_list[] = "payload_size = ?";
$params[] = $wbo->payload();
$params[] = $wbo->payload_size();
}
if ($wbo->parentid_exists() || $wbo->payload_exists())
{
if (!$wbo->modified_exists())
{
error_log("Called update_object with no defined timestamp. Please check");
$wbo->modified(microtime(1));
}
$update_list[] = "modified = ?";
$params[] = $wbo->modified();
}
if (count($params) == 0)
{
return 0;
}
$update .= join($update_list, ",");
$update .= " where username = ? and collection = ? and id = ?";
$params[] = $this->_username;
$params[] = $wbo->collection();
$params[] = $wbo->id();
try
{
$sth = $this->_dbh->prepare($update);
$sth->execute($params);
}
catch( PDOException $exception )
{
error_log("update_object: " . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
return 1;
}
function delete_object($collection, $id)
{
try
{
$delete_stmt = 'delete from wbo where username = :username and collection = :collection and id = :id';
$sth = $this->_dbh->prepare($delete_stmt);
$sth->bindParam(':username', $this->_username);
$sth->bindParam(':collection', $collection);
$sth->bindParam(':id', $id);
$sth->execute();
}
catch( PDOException $exception )
{
error_log("delete_object: " . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
return 1;
}
function delete_objects($collection, $id = null, $parentid = null, $predecessorid = null, $newer = null,
$older = null, $sort = null, $limit = null, $offset = null, $ids = null,
$index_above = null, $index_below = null)
{
$params = array();
$select_stmt = '';
if ($limit || $offset || $sort)
{
$params = $this->retrieve_objects($collection, $id, 0, 0, $parentid, $predecessorid, $newer, $older, $sort, $limit, $offset, $ids, $index_above, $index_below);
if (!count($params))
{
return 1;
}
$paramqs = array();
$select_stmt = "delete from wbo where username = ? and collection = ? and id in (" . join(", ", array_pad($paramqs, count($params), '?')) . ")";
array_unshift($params, $collection);
array_unshift($params, $username);
}
else
{
$select_stmt = "delete from wbo where username = ? and collection = ?";
$params[] = $this->_username;
$params[] = $collection;
if ($id)
{
$select_stmt .= " and id = ?";
$params[] = $id;
}
if ($ids && count($ids) > 0)
{
$qmarks = array();
$select_stmt .= " and id in (";
foreach ($ids as $temp)
{
$params[] = $temp;
$qmarks[] = '?';
}
$select_stmt .= implode(",", $qmarks);
$select_stmt .= ')';
}
if ($parentid)
{
$select_stmt .= " and parentid = ?";
$params[] = $parentid;
}
if ($predecessorid)
{
$select_stmt .= " and predecessorid = ?";
$params[] = $parentid;
}
if ($index_above)
{
$select_stmt .= " and sortindex > ?";
$params[] = $parentid;
}
if ($index_below)
{
$select_stmt .= " and sortindex < ?";
$params[] = $parentid;
}
if ($newer)
{
$select_stmt .= " and modified > ?";
$params[] = $newer;
}
if ($older)
{
$select_stmt .= " and modified < ?";
$params[] = $older;
}
if ($sort == 'index')
{
$select_stmt .= " order by sortindex desc";
}
else if ($sort == 'newest')
{
$select_stmt .= " order by modified desc";
}
else if ($sort == 'oldest')
{
$select_stmt .= " order by modified";
}
if ($limit)
{
$select_stmt .= " limit " . intval($limit);
if ($offset)
{
$select_stmt .= " offset " . intval($offset);
}
}
}
try
{
$sth = $this->_dbh->prepare($select_stmt);
$sth->execute($params);
}
catch( PDOException $exception )
{
error_log("delete_objects: " . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
return 1;
}
function retrieve_object($collection, $id)
{
try
{
$select_stmt = 'select * from wbo where username = :username and collection = :collection and id = :id';
$sth = $this->_dbh->prepare($select_stmt);
$sth->bindParam(':username', $this->_username);
$sth->bindParam(':collection', $collection);
$sth->bindParam(':id', $id);
$sth->execute();
}
catch( PDOException $exception )
{
error_log("retrieve_object: " . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
$result = $sth->fetch(PDO::FETCH_ASSOC);
$wbo = new wbo();
$wbo->populate($result);
return $wbo;
}
function retrieve_objects($collection, $id = null, $full = null, $direct_output = null, $parentid = null,
$predecessorid = null, $newer = null, $older = null, $sort = null,
$limit = null, $offset = null, $ids = null,
$index_above = null, $index_below = null, $depth = null)
{
$full_list = $full ? '*' : 'id';
$select_stmt = "select $full_list from wbo where username = ? and collection = ?";
$params[] = $this->_username;
$params[] = $collection;
if ($id)
{
$select_stmt .= " and id = ?";
$params[] = $id;
}
if ($ids && count($ids) > 0)
{
$qmarks = array();
$select_stmt .= " and id in (";
foreach ($ids as $temp)
{
$params[] = $temp;
$qmarks[] = '?';
}
$select_stmt .= implode(",", $qmarks);
$select_stmt .= ')';
}
if ($ids && count($ids) > 0)
{
$qmarks = array();
$select_stmt .= " and id in (";
foreach ($ids as $temp)
{
$params[] = $temp;
$qmarks[] = '?';
}
$select_stmt .= implode(",", $qmarks);
$select_stmt .= ')';
}
if ($parentid)
{
$select_stmt .= " and parentid = ?";
$params[] = $parentid;
}
if ($predecessorid)
{
$select_stmt .= " and predecessorid = ?";
$params[] = $predecessorid;
}
if ($index_above)
{
$select_stmt .= " and sortindex > ?";
$params[] = $parentid;
}
if ($index_below)
{
$select_stmt .= " and sortindex < ?";
$params[] = $parentid;
}
if ($newer)
{
$select_stmt .= " and modified > ?";
$params[] = $newer;
}
if ($older)
{
$select_stmt .= " and modified < ?";
$params[] = $older;
}
if ($depth)
{
$select_stmt .= " and depth = ?";
$params[] = $depth;
}
if ($sort == 'index')
{
$select_stmt .= " order by sortindex desc";
}
else if ($sort == 'newest')
{
$select_stmt .= " order by modified desc";
}
else if ($sort == 'oldest')
{
$select_stmt .= " order by modified";
}
if ($limit)
{
$select_stmt .= " limit " . intval($limit);
if ($offset)
{
$select_stmt .= " offset " . intval($offset);
}
}
try
{
$sth = $this->_dbh->prepare($select_stmt);
$sth->execute($params);
}
catch( PDOException $exception )
{
error_log("retrieve_collection: " . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
if ($direct_output)
return $direct_output->output($sth);
$ids = array();
while ($result = $sth->fetch(PDO::FETCH_ASSOC))
{
if ($full)
{
$wbo = new wbo();
$wbo->populate($result);
$ids[] = $wbo;
}
else
$ids[] = $result{'id'};
}
return $ids;
}
function get_storage_total()
{
try
{
$select_stmt = 'select round(sum(length(payload))/1024) from wbo where username = :username';
$sth = $this->_dbh->prepare($select_stmt);
$sth->bindParam(':username', $this->_username);
$sth->execute();
}
catch( PDOException $exception )
{
error_log("get_storage_total: " . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
return (int)$sth->fetchColumn();
}
function get_user_quota()
{
return null;
}
function delete_user($username)
{
if (!$username)
{
throw new Exception("3", 404);
}
try
{
$delete_stmt = 'delete from users where username = :username';
$sth = $this->_dbh->prepare($delete_stmt);
$sth->bindParam(':username', $username);
$sth->execute();
$sth->closeCursor();
$delete_wbo_stmt = 'delete from wbo where username = :username';
$sth = $this->_dbh->prepare($delete_wbo_stmt);
$sth->bindParam(':username', $username);
$sth->execute();
}
catch( PDOException $exception )
{
error_log("delete_user: " . $exception->getMessage());
return 0;
}
return 1;
}
function create_user($username, $password)
{
try
{
$create_statement = "insert into users values (:username, :md5)";
$sth = $this->_dbh->prepare($create_statement);
$sth->bindParam(':username', $username);
$hash = md5($password);
$sth->bindParam(':md5', $hash);
$sth->execute();
}
catch( PDOException $exception )
{
error_log("create_user:" . $exception->getMessage());
return 0;
}
return 1;
}
function change_password($username, $password)
{
try
{
$update_statement = "update users set md5 = :md5 where username = :username";
$sth = $this->_dbh->prepare($update_statement);
$sth->bindParam(':username', $username);
$hash = md5($password);
$sth->bindParam(':md5', $hash);
$sth->execute();
}
catch( PDOException $exception )
{
error_log("change_password:" . $exception->getMessage());
return 0;
}
return 1;
}
function authenticate_user($password)
{
try
{
$select_stmt = 'select username from users where username = :username and md5 = :md5';
$sth = $this->_dbh->prepare($select_stmt);
$sth->bindParam(':username', $this->_username);
$hash = md5($password);
$sth->bindParam(':md5', $hash);
$sth->execute();
}
catch( PDOException $exception )
{
error_log("authenticate_user: " . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
if (!$result = $sth->fetch(PDO::FETCH_ASSOC))
{
return null;
}
return 1;
}
function setup_db()
{
try
{
$create_statement = <<< end
create table wbo
(
username text,
id text,
collection text,
parentid text,
predecessorid int,
modified real,
sortindex int,
depth int,
payload text,
payload_size int,
primary key (username,collection,id)
)
end;
$create_statement2 = <<< end
create table users
(
username text,
md5 text,
primary key (username)
)
end;
$index1 = 'create index parentindex on wbo (username, parentid)';
$index2 = 'create index predecessorindex on wbo (username, predecessorid)';
$index3 = 'create index modifiedindex on wbo (username, collection, modified)';
$sth = $this->_dbh->prepare($create_statement);
$sth->execute();
$sth = $this->_dbh->prepare($create_statement2);
$sth->execute();
$sth = $this->_dbh->prepare($index1);
$sth->execute();
$sth = $this->_dbh->prepare($index2);
$sth->execute();
$sth = $this->_dbh->prepare($index3);
$sth->execute();
}
catch( PDOException $exception )
{
error_log("initialize_user_db:" . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
}
}
?>