<?php
require_once 'weave_storage.php';
require_once 'weave_basic_object.php';
function report_problem($message, $code = 503)
{
$headers = array('400' => '400 Bad Request',
'401' => '401 Unauthorized',
'404' => '404 Not Found',
'412' => '412 Precondition Failed',
'503' => '503 Service Unavailable');
header('HTTP/1.1 ' . $headers{$code},true,$code);
if ($code == 401)
{
header('WWW-Authenticate: Basic realm="Weave"');
}
exit(json_encode($message));
}
header("Content-type: application/json");
$auth_user = array_key_exists('PHP_AUTH_USER', $_SERVER) ? $_SERVER['PHP_AUTH_USER'] : null;
$auth_pw = array_key_exists('PHP_AUTH_PW', $_SERVER) ? $_SERVER['PHP_AUTH_PW'] : null;
if (is_null($auth_user) || is_null($auth_pw))
{
$auth_str = null;
if (array_key_exists('Authorization', $_SERVER))
$auth_str = $_SERVER['Authorization'];
else if (array_key_exists('AUTHORIZATION', $_SERVER))
$auth_str = $_SERVER['AUTHORIZATION'];
else if (array_key_exists('HTTP_AUTHORIZATION', $_SERVER))
$auth_str = $_SERVER['HTTP_AUTHORIZATION'];
else if (array_key_exists('REDIRECT_HTTP_AUTHORIZATION', $_SERVER))
$auth_str = $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
if (!is_null($auth_str))
{
if (preg_match('/Basic\s+(.*)$/', $auth_str))
{
$auth_str = substr($auth_str, 6);
$auth_str = base64_decode($auth_str, true);
if ($auth_str != FALSE) {
$tmp = explode(':', $auth_str);
if (count($tmp) == 2)
{
$auth_user = $tmp[0];
$auth_pw = $tmp[1];
}
}
}
}
}
$server_time = round(microtime(1), 2);
header("X-Weave-Timestamp: " . $server_time);
$path = '/';
if (!empty($_SERVER['PATH_INFO'])) {
$path = $_SERVER['PATH_INFO'];
}
else if (!empty($_SERVER['ORIG_PATH_INFO'])) {
$path = $_SERVER['ORIG_PATH_INFO'];
}
$path = substr($path, 1);
list($version, $username, $function, $collection, $id) = explode('/', $path.'//');
if ($version != '0.5' && $version != '1.0')
report_problem('Function not found', 404);
$username = strtolower($username);
$auth_user = strtolower($auth_user);
if (!$username)
report_problem(3, 400);
if ($auth_user != $username)
report_problem(5, 401);
if ($function != 'storage' && $_SERVER['REQUEST_METHOD'] != 'GET')
report_problem(1, 400);
if (!$collection && $_SERVER['REQUEST_METHOD'] != 'GET')
report_problem(1, 400);
if (!$collection)
report_problem(1, 400);
try
{
$db = new WeaveStorage($username);
}
catch(Exception $e)
{
report_problem($e->getMessage(), $e->getCode());
}
try
{
if (!$db->authenticate_user($auth_pw))
report_problem('Authentication failed', '401');
}
catch(Exception $e)
{
report_problem($e->getMessage(), $e->getCode());
}
if ($_SERVER['REQUEST_METHOD'] == 'GET')
{
if ($function == 'info')
{
switch ($collection)
{
case 'quota':
exit(json_encode(array($db->get_storage_total())));
case 'collections':
exit(json_encode($db->get_collection_list_with_timestamps()));
case 'collection_counts':
exit(json_encode($db->get_collection_list_with_counts()));
default:
report_problem(1, 400);
}
}
elseif ($function == 'storage')
{
if ($id)
{
try
{
$wbo = $db->retrieve_objects($collection, $id, 1);
}
catch(Exception $e)
{
report_problem($e->getMessage(), $e->getCode());
}
if (count($wbo) > 0)
echo $wbo[0]->json();
else
report_problem("record not found", 404);
}
else
{
$full = array_key_exists('full', $_GET) ? $_GET['full'] : null;
$outputter = new WBOJsonOutput($full);
if (array_key_exists('HTTP_ACCEPT', $_SERVER)
&& !preg_match('/\*\/\*/', $_SERVER['HTTP_ACCEPT'])
&& !preg_match('/application\/json/', $_SERVER['HTTP_ACCEPT']))
{
if (preg_match('/application\/whoisi/', $_SERVER['HTTP_ACCEPT']))
{
header("Content-type: application/whoisi");
$outputter->set_format('whoisi');
}
elseif (preg_match('/application\/newlines/', $_SERVER['HTTP_ACCEPT']))
{
header("Content-type: application/newlines");
$outputter->set_format('newlines');
}
}
try
{
$ids = $db->retrieve_objects($collection, null, $full, $outputter,
array_key_exists('parentid', $_GET) ? $_GET['parentid'] : null,
array_key_exists('predecessorid', $_GET) ? $_GET['predecessorid'] : null,
array_key_exists('newer', $_GET) ? $_GET['newer'] : null,
array_key_exists('older', $_GET) ? $_GET['older'] : null,
array_key_exists('sort', $_GET) ? $_GET['sort'] : null,
array_key_exists('limit', $_GET) ? $_GET['limit'] : null,
array_key_exists('offset', $_GET) ? $_GET['offset'] : null,
array_key_exists('ids', $_GET) ? explode(',', $_GET['ids']) : null,
array_key_exists('index_above', $_GET) ? $_GET['index_above'] : null,
array_key_exists('index_below', $_GET) ? $_GET['index_below'] : null,
array_key_exists('depth', $_GET) ? $_GET['depth'] : null
);
}
catch(Exception $e)
{
report_problem($e->getMessage(), $e->getCode());
}
}
}
}
else if ($_SERVER['REQUEST_METHOD'] == 'PUT')
{
$putdata = fopen("php://input", "r");
$json = '';
while ($data = fread($putdata,2048)) {$json .= $data;};
$wbo = new wbo();
if (!$wbo->extract_json($json))
report_problem(6, 400);
if (array_key_exists('HTTP_X_IF_UNMODIFIED_SINCE', $_SERVER)
&& $db->get_max_timestamp($collection) > round((float)$_SERVER['HTTP_X_IF_UNMODIFIED_SINCE'], 2))
report_problem(4, 412);
if (!$wbo->id() && $id) { $wbo->id($id); }
$wbo->collection($collection);
$wbo->modified($server_time);
if ($wbo->validate())
{
try
{
if ($wbo->payload_exists())
$db->store_object($wbo);
else
$db->update_object($wbo);
}
catch (Exception $e)
{
report_problem($e->getMessage(), $e->getCode());
}
echo json_encode($wbo->modified());
}
else
{
report_problem(8, 400);
}
}
else if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
$putdata = fopen("php://input", "r");
$jsonstring = '';
while ($data = fread($putdata,2048)) {$jsonstring .= $data;}
$json = json_decode($jsonstring, true);
if ($json === null)
report_problem(6, 400);
if (array_key_exists('HTTP_X_IF_UNMODIFIED_SINCE', $_SERVER)
&& $db->get_max_timestamp($collection) > round((float)$_SERVER['HTTP_X_IF_UNMODIFIED_SINCE'], 2))
report_problem(4, 412);
$success_ids = array();
$failed_ids = array();
try
{
$db->begin_transaction();
}
catch(Exception $e)
{
report_problem($e->getMessage(), $e->getCode());
}
foreach ($json as $wbo_data)
{
$wbo = new wbo();
if (!$wbo->extract_json($wbo_data))
{
$failed_ids[$wbo->id()] = $wbo->get_error();
continue;
}
$wbo->collection($collection);
$wbo->modified($server_time);
if ($wbo->validate())
{
try
{
if ($wbo->payload_exists())
{
$db->store_object($wbo);
}
else
{
$db->update_object($wbo);
}
}
catch (Exception $e)
{
$failed_ids[$wbo->id()] = $e->getMessage();
continue;
}
$success_ids[] = $wbo->id();
}
else
{
$failed_ids[$wbo->id()] = $wbo->get_error();
}
}
$db->commit_transaction();
echo json_encode(array('success' => $success_ids, 'failed' => $failed_ids));
}
else if ($_SERVER['REQUEST_METHOD'] == 'DELETE')
{
if (array_key_exists('HTTP_X_IF_UNMODIFIED_SINCE', $_SERVER)
&& $db->get_max_timestamp($collection) > round((float)$_SERVER['HTTP_X_IF_UNMODIFIED_SINCE'], 2))
report_problem(4, 412);
$timestamp = round(microtime(1), 2);
if ($id)
{
try
{
$db->delete_object($collection, $id);
}
catch(Exception $e)
{
report_problem($e->getMessage(), $e->getCode());
}
echo json_encode($timestamp);
}
else
{
try
{
$db->delete_objects($collection, null,
array_key_exists('parentid', $_GET) ? $_GET['parentid'] : null,
array_key_exists('predecessorid', $_GET) ? $_GET['predecessorid'] : null,
array_key_exists('newer', $_GET) ? $_GET['newer'] : null,
array_key_exists('older', $_GET) ? $_GET['older'] : null,
array_key_exists('sort', $_GET) ? $_GET['sort'] : null,
array_key_exists('limit', $_GET) ? $_GET['limit'] : null,
array_key_exists('offset', $_GET) ? $_GET['offset'] : null,
array_key_exists('ids', $_GET) ? explode(',', $_GET['ids']) : null,
array_key_exists('index_above', $_GET) ? $_GET['index_above'] : null,
array_key_exists('index_below', $_GET) ? $_GET['index_below'] : null
);
}
catch(Exception $e)
{
report_problem($e->getMessage(), $e->getCode());
}
echo json_encode($timestamp);
}
}
else
{
report_problem(1, 400);
}
class WBOJsonOutput
{
private $_full = null;
private $_comma_flag = 0;
private $_output_format = 'json';
function __construct ($full = null)
{
$this->_full = $full;
}
function set_format($format)
{
$this->_output_format = $format;
}
function output($sth)
{
if (($rowcount = $sth->rowCount()) > 0)
{
header('X-Weave-Records: ' . $rowcount);
}
if ($this->_output_format == 'newlines')
{
return $this->output_newlines($sth);
}
elseif ($this->_output_format == 'whoisi')
{
return $this->output_whoisi($sth);
}
else
{
return $this->output_json($sth);
}
}
function output_json($sth)
{
echo '[';
while ($result = $sth->fetch(PDO::FETCH_ASSOC))
{
if ($this->_comma_flag) { echo ','; } else { $this->_comma_flag = 1; }
if ($this->_full)
{
$wbo = new wbo();
$wbo->populate($result);
echo $wbo->json();
}
else
echo json_encode($result{'id'});
}
echo ']';
return 1;
}
function output_whoisi($sth)
{
while ($result = $sth->fetch(PDO::FETCH_ASSOC))
{
if ($this->_full)
{
$wbo = new wbo();
$wbo->populate($result);
$output = $wbo->json();
}
else
$output = json_encode($result{'id'});
echo pack('N', mb_strlen($output, '8bit')) . $output;
}
return 1;
}
function output_newlines($sth)
{
while ($result = $sth->fetch(PDO::FETCH_ASSOC))
{
if ($this->_full)
{
$wbo = new wbo();
$wbo->populate($result);
echo preg_replace('/\n/', '\u000a', $wbo->json());
}
else
echo json_encode($result{'id'});
echo "\n";
}
return 1;
}
}
?>