/*
***** BEGIN LICENSE BLOCK *****
This file is part of the Zotero Data Server.
Copyright © 2010 Center for History and New Media
George Mason University, Fairfax, Virginia, USA
http://zotero.org
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
***** END LICENSE BLOCK *****
*/
define('Z_ENV_START_TIME', microtime(true));
mb_language('uni');
mb_internal_encoding('UTF-8');
date_default_timezone_set('UTC');
function zotero_autoload($className) {
// Get "Zotero_" classes from model directory
if (strpos($className, 'Zotero_') === 0) {
$fileName = str_replace('Zotero_', '', $className) . '.inc.php';
if (strpos($fileName, 'AuthenticationPlugin_') === 0) {
$fileName = str_replace('AuthenticationPlugin_', '', $fileName);
$auth = true;
}
else {
$auth = false;
}
$path = Z_ENV_BASE_PATH . 'model/';
if ($auth) {
$path .= 'auth/';
}
$path .= $fileName;
require_once $path;
return;
}
// Get \Zotero-namespaced files from model directory
if (strpos($className, 'Zotero\\') === 0) {
$parts = explode('\\', $className);
require Z_ENV_BASE_PATH . 'model/' . end($parts) . '.inc.php';
return;
}
// Get everything else from include path
switch ($className) {
case 'HTTPException':
require_once $className . '.inc.php';
return;
}
// Strip "Z_" namespace
if (strpos($className, 'Z_') === 0) {
$className = str_replace('Z_', '', $className);
require_once $className . '.inc.php';
return;
}
}
spl_autoload_register('zotero_autoload');
// Read in configuration variables
require('config/config.inc.php');
if (Z_Core::isCommandLine()) {
$_SERVER['DOCUMENT_ROOT'] = realpath(dirname(dirname(__FILE__))) . '/';
$_SERVER['SERVER_NAME'] = parse_url(Z_CONFIG::$API_BASE_URI)['host'];
$_SERVER['HTTP_HOST'] = $_SERVER['SERVER_NAME'];
$_SERVER['REQUEST_URI'] = "/";
}
else {
// Allow a URI pattern to reproxy the request via Perlbal
if (!empty(Z_CONFIG::$REPROXY_MAP)) {
foreach (Z_CONFIG::$REPROXY_MAP as $prefix=>$servers) {
if (preg_match("'$prefix'", $_SERVER['REQUEST_URI'])) {
foreach ($servers as &$server) {
$server .= $_SERVER['REQUEST_URI'];
}
header("X-REPROXY-URL: " . implode(" ", $servers));
exit;
}
}
}
// Allow a URI prefix to override the domain
// e.g., to treat zotero.org/api/users as api.zotero.org/users
if (!empty(Z_CONFIG::$URI_PREFIX_DOMAIN_MAP)) {
foreach (Z_CONFIG::$URI_PREFIX_DOMAIN_MAP as $prefix=>$domain) {
if (preg_match("%^$prefix(.*)%", $_SERVER['REQUEST_URI'], $matches)) {
$_SERVER['SERVER_NAME'] = $domain;
$_SERVER['HTTP_HOST'] = $domain;
// Make sure there's a leading slash
if (substr($matches[1], 0, 1) != '/') {
$matches[1] = '/' . $matches[1];
}
$_SERVER['REQUEST_URI'] = $matches[1];
break;
}
}
}
// Turn on output buffering
ob_start();
}
// Absolute base filesystem path
define('Z_ENV_BASE_PATH', substr($_SERVER['DOCUMENT_ROOT'], 0, strrpos($_SERVER['DOCUMENT_ROOT'], '/')) . '/');
// Environmental variables that may change based on where the app is running
define('Z_ENV_CONTROLLER_PATH', Z_ENV_BASE_PATH . 'controllers/');
define('Z_ENV_MODEL_PATH', Z_ENV_BASE_PATH . 'model/');
define('Z_ENV_TMP_PATH', Z_ENV_BASE_PATH . 'tmp/');
if (!is_writable(Z_ENV_TMP_PATH)) {
throw new Exception("Temp directory '" . Z_ENV_TMP_PATH . "' is not writable");
}
// Allow per-machine config overrides
if (file_exists(Z_ENV_BASE_PATH . 'include/config/custom.inc.php')) {
require('config/custom.inc.php');
}
// Composer autoloads
require Z_ENV_BASE_PATH . 'vendor/autoload.php';
// Check if on testing port and set testing mode params if so
if (Z_CONFIG::$TESTING_SITE) {
define('Z_ENV_TESTING_SITE', true);
// Display errors on testing site
ini_set("display_errors", "1");
//error_reporting(E_ALL & ~E_DEPRECATED & ~E_NOTICE | E_STRICT);
error_reporting(-1);
ini_set('html_errors', '0');
define('Z_ENV_DEV_SITE', !empty(Z_CONFIG::$DEV_SITE));
}
else {
define('Z_ENV_TESTING_SITE', false);
define('Z_ENV_DEV_SITE', false);
ini_set("display_errors", "0");
}
// Ignore internal Apache OPTIONS request
if ($_SERVER['REQUEST_URI'] == '*') {
//error_log("Ignoring OPTIONS request");
exit;
}
// Get canonical URL without extension and query string
preg_match("/[^?]+/", $_SERVER['REQUEST_URI'], $matches);
define('Z_ENV_SELF', $matches[0]);
// Load in core functions
require('DB.inc.php');
require('IPAddress.inc.php');
require('Shards.inc.php');
require('config/dbconnect.inc.php');
require('StatsD.inc.php');
// Use DB read replicas for GET requests
if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'GET') {
Zotero_DB::readOnly(true);
}
// Database callbacks
Zotero_DB::addCallback("begin", array("Zotero_Notifier", "begin"));
Zotero_DB::addCallback("commit", array("Zotero_Notifier", "commit"));
Zotero_DB::addCallback("callback", array("Zotero_Notifier", "reset"));
Zotero_NotifierObserver::init();
// Memcached
require('Memcached.inc.php');
Z_Core::$MC = new Z_MemcachedClientLocal(
Z_CONFIG::$API_BASE_URI,
array(
'disabled' => !Z_CONFIG::$MEMCACHED_ENABLED,
'servers' => Z_CONFIG::$MEMCACHED_SERVERS
)
);
Zotero_DB::addCallback("begin", array(Z_Core::$MC, "begin"));
Zotero_DB::addCallback("commit", array(Z_Core::$MC, "commit"));
Zotero_DB::addCallback("reset", array(Z_Core::$MC, "reset"));
//
// Set up AWS service factory
//
$awsConfig = [
'region' => !empty(Z_CONFIG::$AWS_REGION) ? Z_CONFIG::$AWS_REGION : 'eu-west-1',
'version' => 'latest',
'signature' => 'v4',
'use_path_style_endpoint' => true,
'endpoint' => 'http://' . Z_CONFIG::$S3_ENDPOINT,
'scheme' => 'http',
'http' => [
'timeout' => 3
],
'retries' => 2
];
// IAM role authentication
if (empty(Z_CONFIG::$AWS_ACCESS_KEY)) {
// If APC cache is available, use that to cache temporary credentials
if (function_exists('apc_store')) {
$cache = new \Doctrine\Common\Cache\ApcCache();
}
// Otherwise use temp dir
else {
$cache = new \Doctrine\Common\Cache\FilesystemCache(Z_ENV_BASE_PATH . 'tmp/cache');
}
$awsConfig['credentials'] = new \Aws\DoctrineCacheAdapter($cache);
}
// Access key and secret
else {
$awsConfig['credentials'] = [
'key' => Z_CONFIG::$AWS_ACCESS_KEY,
'secret' => Z_CONFIG::$AWS_SECRET_KEY
];
}
Z_Core::$AWS = new Aws\Sdk($awsConfig);
unset($awsConfig);
// Elasticsearch
$esConfig = [
'hosts' => Z_CONFIG::$SEARCH_HOSTS
];
Z_Core::$ES = \Elasticsearch\ClientBuilder::fromConfig($esConfig, true);
require('interfaces/IAuthenticationPlugin.inc.php');
require('log.inc.php');
Z_Core::$debug = !empty(Z_CONFIG::$DEBUG_LOG);
// Load in functions
require('functions/string.inc.php');
require('functions/array.inc.php');
?>
require('mvc/Router.inc.php');
$router = new Router();
// Set controller to 404 to block access to an action via a particular URL
$router->map('/', array('controller' => 'Api', 'action' => 'noop', 'extra' => array('allowHTTP' => true)));
// Global items
$router->map('/globalitems', ['controller' => 'GlobalItems', 'extra' => ['globalItems' => true]]);
$router->map('/globalitems/:objectGlobalItemID/items', ['controller' => 'Items', 'extra' => ['globalItems' => true]]);
// Groups
$router->map('/groups/i:objectGroupID', array('controller' => 'Groups'));
$router->map('/groups/i:scopeObjectID/users/i:objectID', array('controller' => 'Groups', 'action' => 'groupUsers'));
// Top-level objects
$router->map('/users/i:objectUserID/publications/items/top', ['controller' => 'Items', 'extra' => ['subset' => 'top', 'publications' => true]]);
$router->map('/users/i:objectUserID/:controller/top', array('extra' => array('subset' => 'top')));
$router->map('/groups/i:objectGroupID/:controller/top', array('extra' => array('subset' => 'top')));
// Attachment files
$router->map('/users/i:objectUserID/laststoragesync', array('controller' => 'Storage', 'action' => 'laststoragesync', 'extra' => array('auth' => true)));
$router->map('/groups/i:objectGroupID/laststoragesync', array('controller' => 'Storage', 'action' => 'laststoragesync', 'extra' => array('auth' => true)));
$router->map('/users/i:objectUserID/storageadmin', array('controller' => 'Storage', 'action' => 'storageadmin'));
$router->map('/storagepurge', array('controller' => 'Storage', 'action' => 'storagepurge'));
$router->map('/users/i:objectUserID/removestoragefiles', array('controller' => 'Storage', 'action' => 'removestoragefiles', 'extra' => array('allowHTTP' => true)));
$router->map('/users/i:objectUserID/items/:objectKey/file', array('controller' => 'Items', 'extra' => array('allowHTTP' => true, 'file' => true)));
$router->map('/users/i:objectUserID/items/:objectKey/file/view', array('controller' => 'Items', 'extra' => array('allowHTTP' => true, 'file' => true, 'view' => true)));
$router->map('/users/i:objectUserID/items/:objectKey/file/view/url', ['controller' => 'Items', 'extra' => ['file' => true, 'viewurl' => true]]);
$router->map('/users/i:objectUserID/publications/items/:objectKey/file', ['controller' => 'Items', 'extra' => ['allowHTTP' => true, 'file' => true, 'publications' => true]]);
$router->map('/users/i:objectUserID/publications/items/:objectKey/file/view', ['controller' => 'Items', 'extra' => ['allowHTTP' => true, 'file' => true, 'view' => true, 'publications' => true]]);
$router->map('/users/i:objectUserID/publications/items/:objectKey/file/view/url', ['controller' => 'Items', 'extra' => ['file' => true, 'viewurl' => true, 'publications' => true]]);
$router->map('/groups/i:objectGroupID/items/:objectKey/file', array('controller' => 'Items', 'extra' => array('allowHTTP' => true, 'file' => true)));
$router->map('/groups/i:objectGroupID/items/:objectKey/file/view', array('controller' => 'Items', 'extra' => array('allowHTTP' => true, 'file' => true, 'view' => true)));
$router->map('/groups/i:objectGroupID/items/:objectKey/file/view/url', ['controller' => 'Items', 'extra' => ['file' => true, 'viewurl' => true]]);
// Full-text content
$router->map('/users/i:objectUserID/items/:objectKey/fulltext', array('controller' => 'FullText', 'action' => 'itemContent'));
//$router->map('/users/i:objectUserID/publications/items/:objectKey/fulltext', ['controller' => 'FullText', 'action' => 'itemContent', 'extra' => ['publications' => true]]);
$router->map('/groups/i:objectGroupID/items/:objectKey/fulltext', array('controller' => 'FullText', 'action' => 'itemContent'));
$router->map('/users/i:objectUserID/fulltext', array('controller' => 'FullText', 'action' => 'fulltext'));
//$router->map('/users/i:objectUserID/publications/fulltext', ['controller' => 'FullText', 'action' => 'fulltext', 'extra' => ['publications' => true]]);
$router->map('/groups/i:objectGroupID/fulltext', array('controller' => 'FullText', 'action' => 'fulltext'));
// All trashed items
$router->map('/users/i:objectUserID/items/trash', array('controller' => 'Items', 'extra' => array('subset' => 'trash')));
$router->map('/groups/i:objectGroupID/items/trash', array('controller' => 'Items', 'extra' => array('subset' => 'trash')));
// Subcollections, single and multiple
$router->map('/users/i:objectUserID/collections/:scopeObjectKey/collections/:objectKey', array('controller' => 'Collections', 'extra' => array('scopeObject' => 'collections')));
$router->map('/groups/i:objectGroupID/collections/:scopeObjectKey/collections/:objectKey', array('controller' => 'Collections','extra' => array('scopeObject' => 'collections')));
// Deleted items in a collection
$router->map('/users/i:objectUserID/:scopeObject/:scopeObjectKey/items/trash', array('controller' => 'Items', 'extra' => array('subset' => 'trash')));
// Tags, which have names instead of ids
$router->map('/users/i:objectUserID/tags/:scopeObjectName/items/:objectName/:subset', array('controller' => 'Items', 'extra' => array('scopeObject' => 'tags')));
$router->map('/groups/i:objectGroupID/tags/:scopeObjectName/items/:objectName/:subset', array('controller' => 'Items', 'extra' => array('scopeObject' => 'tags')));
$router->map('/users/i:objectUserID/tags/:objectName/:subset', array('controller' => 'Tags'));
//$router->map('/users/i:objectUserID/publications/tags/:objectName/:subset', ['controller' => 'Tags', 'extra' => ['publications' => true]]);
$router->map('/groups/i:objectGroupID/tags/:objectName/:subset', array('controller' => 'Tags'));
// Tags within items
$router->map('/users/i:objectUserID/items/tags', ['controller' => 'Tags', 'extra' => ['scopeObject' => 'items']]);
$router->map('/groups/i:objectGroupID/items/tags', ['controller' => 'Tags', 'extra' => ['scopeObject' => 'items']]);
$router->map('/users/i:objectUserID/items/top/tags', ['controller' => 'Tags', 'extra' => ['scopeObject' => 'items', 'subset' => 'top']]);
$router->map('/groups/i:objectGroupID/items/top/tags', ['controller' => 'Tags', 'extra' => ['scopeObject' => 'items', 'subset' => 'top']]);
$router->map('/users/i:objectUserID/items/trash/tags', ['controller' => 'Tags', 'extra' => ['scopeObject' => 'items', 'subset' => 'trash']]);
$router->map('/groups/i:objectGroupID/items/trash/tags', ['controller' => 'Tags', 'extra' => ['scopeObject' => 'items', 'subset' => 'trash']]);
// Tags within items within a collection
$router->map('/users/i:objectUserID/collections/:scopeObjectKey/items/tags', ['controller' => 'Tags', 'extra' => ['scopeObject' => 'collection-items']]);
$router->map('/groups/i:objectGroupID/collections/:scopeObjectKey/items/tags', ['controller' => 'Tags', 'extra' => ['scopeObject' => 'collection-items']]);
$router->map('/users/i:objectUserID/collections/:scopeObjectKey/items/top/tags', ['controller' => 'Tags', 'extra' => ['scopeObject' => 'collection-items', 'subset' => 'top']]);
$router->map('/groups/i:objectGroupID/collections/:scopeObjectKey/items/top/tags', ['controller' => 'Tags', 'extra' => ['scopeObject' => 'collection-items', 'subset' => 'top']]);
// Tags within items within My Publications
$router->map('/users/i:objectUserID/publications/items/tags', ['controller' => 'Tags', 'extra' => ['scopeObject' => 'items', 'publications' => true]]);
// Tags within something else
//$router->map('/users/i:objectUserID/publications/items/:scopeObjectKey/tags/:objectKey/:subset', ['controller' => 'Tags', 'extra' => ['publications']]);
$router->map('/users/i:objectUserID/:scopeObject/:scopeObjectKey/tags/:objectKey/:subset', array('controller' => 'Tags'));
$router->map('/groups/i:objectGroupID/:scopeObject/:scopeObjectKey/tags/:objectKey/:subset', array('controller' => 'Tags'));
// Top-level items within something else
$router->map('/users/i:objectUserID/:scopeObject/:scopeObjectKey/items/top', array('controller' => 'Items', 'extra' => array('subset' => 'top')));
$router->map('/groups/i:objectGroupID/:scopeObject/:scopeObjectKey/items/top', array('controller' => 'Items', 'extra' => array('subset' => 'top')));
// Items within something else
$router->map('/users/i:objectUserID/:scopeObject/:scopeObjectKey/items/:objectKey/:subset', array('controller' => 'Items'));
$router->map('/groups/i:objectGroupID/:scopeObject/:scopeObjectKey/items/:objectKey/:subset', array('controller' => 'Items'));
// User API keys
$router->map('/keys/:objectName', array('controller' => 'Keys'));
$router->map('/users/i:objectUserID/keys/:objectName', array('controller' => 'Keys'));
// User/library settings
$router->map('/users/i:objectUserID/settings/:objectKey', array('controller' => 'settings'));
$router->map('/groups/i:objectGroupID/settings/:objectKey', array('controller' => 'settings'));
// Clear (for testing)
$router->map('/users/i:objectUserID/clear', array('controller' => 'Api', 'action' => 'clear'));
$router->map('/groups/i:objectGroupID/clear', array('controller' => 'Api', 'action' => 'clear'));
// My Publications items
$router->map('/users/i:objectUserID/publications/settings', ['controller' => 'settings', 'extra' => ['publications' => true]]); // TEMP
$router->map('/users/i:objectUserID/publications/deleted', ['controller' => 'deleted', 'extra' => ['publications' => true]]); // TEMP
$router->map('/users/i:objectUserID/publications/items/:objectKey/children', ['controller' => 'Items', 'extra' => ['publications' => true, 'subset' => 'children']]);
$router->map('/users/i:objectUserID/publications/items/:objectKey', ['controller' => 'Items', 'extra' => ['publications' => true]]);
// Other top-level URLs, with an optional key and subset
$router->map('/users/i:objectUserID/:controller/:objectKey/:subset');
$router->map('/groups/i:objectGroupID/:controller/:objectKey/:subset');
$router->map('/itemTypes', array('controller' => 'Mappings', 'extra' => array('subset' => 'itemTypes')));
$router->map('/itemTypeFields', array('controller' => 'Mappings', 'extra' => array('subset' => 'itemTypeFields')));
$router->map('/itemFields', array('controller' => 'Mappings', 'extra' => array('subset' => 'itemFields')));
$router->map('/itemTypeCreatorTypes', array('controller' => 'Mappings', 'extra' => array('subset' => 'itemTypeCreatorTypes')));
$router->map('/creatorFields', array('controller' => 'Mappings', 'extra' => array('subset' => 'creatorFields')));
$router->map('/items/new', array('controller' => 'Mappings', 'action' => 'newItem'));
// 4.0 sync warning
$router->map('/login', ['controller' => 'Api', 'action' => 'noop']);
$router->map('/test/setup', array('controller' => 'Api', 'action' => 'testSetup'));
return $router->match($_SERVER['REQUEST_URI']);
Not Found
The page you requested could not be found.
echo ob_get_clean();
?>