Esempio n. 1
0
 public static function getName($charsetOrCharsetID)
 {
     if (isset(self::$charsets[$charsetOrCharsetID])) {
         return self::$charsets[$charsetOrCharsetID];
     }
     $sql = "(SELECT charset FROM charsets WHERE charsetID=?) UNION\n\t\t\t\t(SELECT charset FROM charsets WHERE charset=?) LIMIT 1";
     $charset = Zotero_DB::valueQuery($sql, array($charsetOrCharsetID, $charsetOrCharsetID));
     self::$charsets[$charsetOrCharsetID] = $charset;
     return $charset;
 }
Esempio n. 2
0
 public function run($id = null)
 {
     $this->id = $id;
     $this->addr = gethostbyname(gethostname());
     if (!Z_CONFIG::$PROCESSORS_ENABLED) {
         $sleep = 20;
         $this->log("Processors disabled — exiting in {$sleep} seconds");
         sleep($sleep);
         try {
             $this->notifyProcessor("LOCK" . " " . $id);
         } catch (Exception $e) {
             $this->log($e);
         }
         return;
     }
     $this->log("Starting sync processor");
     $startTime = microtime(true);
     try {
         $processed = $this->processFromQueue();
         if (Zotero_DB::transactionInProgress()) {
             error_log("WARNING: Transaction still in progress after processing!");
         }
     } catch (Exception $e) {
         $this->log($e);
         throw $e;
     }
     $duration = microtime(true) - $startTime;
     $error = false;
     // Success
     if ($processed == 1) {
         $this->log("Process completed in " . round($duration, 2) . " seconds");
         $signal = "DONE";
     } else {
         if ($processed == 0) {
             $this->log("Exiting with no processes found");
             $signal = "NONE";
         } else {
             if ($processed == -1) {
                 $this->log("Exiting on lock error");
                 $signal = "LOCK";
             } else {
                 $this->log("Exiting on error");
                 $signal = "ERROR";
             }
         }
     }
     if ($id) {
         try {
             $this->notifyProcessor($signal . " " . $id);
         } catch (Exception $e) {
             $this->log($e);
         }
     }
 }
Esempio n. 3
0
 public static function add($userID)
 {
     Z_Core::debug("Creating publications library for user {$userID}");
     Zotero_DB::beginTransaction();
     // Use same shard as user library
     $shardID = Zotero_Shards::getByUserID($userID);
     $libraryID = Zotero_Libraries::add('publications', $shardID);
     $sql = "INSERT INTO userPublications (userID, libraryID) VALUES (?, ?)";
     Zotero_DB::query($sql, [$userID, $libraryID]);
     Zotero_DB::commit();
     return $libraryID;
 }
Esempio n. 4
0
 public static function getCreatorsWithData($libraryID, $creator, $sortByItemCountDesc = false)
 {
     $sql = "SELECT creatorID FROM creators ";
     if ($sortByItemCountDesc) {
         $sql .= "LEFT JOIN itemCreators USING (creatorID) ";
     }
     $sql .= "WHERE libraryID=? AND firstName COLLATE utf8_bin = ? " . "AND lastName COLLATE utf8_bin = ? AND fieldMode=?";
     if ($sortByItemCountDesc) {
         $sql .= " ORDER BY IFNULL(COUNT(*), 0) DESC";
     }
     $ids = Zotero_DB::columnQuery($sql, array($libraryID, $creator->firstName, $creator->lastName, $creator->fieldMode), Zotero_Shards::getByLibraryID($libraryID));
     return $ids;
 }
Esempio n. 5
0
 public static function generate()
 {
     $tries = 5;
     while ($tries > 0) {
         $str = Zotero_Utilities::randomString(24, 'mixed');
         $sql = "SELECT COUNT(*) FROM `keys` WHERE `key`=?";
         if (Zotero_DB::valueQuery($sql, $str)) {
             $tries--;
             continue;
         }
         return $str;
     }
     throw new Exception("Unique key could not be generated");
 }
Esempio n. 6
0
 protected function loadChildItems($reload = false)
 {
     if ($this->loaded['childItems'] && !$reload) {
         return;
     }
     Z_Core::debug("Loading child items for collection {$this->id}");
     if (!$this->id) {
         trigger_error('$this->id not set', E_USER_ERROR);
     }
     $sql = "SELECT itemID FROM collectionItems WHERE collectionID=?";
     $ids = Zotero_DB::columnQuery($sql, $this->id, Zotero_Shards::getByLibraryID($this->libraryID));
     $this->childItems = $ids ? $ids : [];
     $this->loaded['childItems'] = true;
     $this->clearChanged('childItems');
 }
Esempio n. 7
0
 public static function getUserGroupLibraries($userID)
 {
     $sql = "SELECT libraryID FROM groupUsers JOIN groups USING (groupID) WHERE userID=?";
     $libraryIDs = Zotero_DB::columnQuery($sql, $userID);
     if (!$libraryIDs) {
         return array();
     }
     return $libraryIDs;
 }
Esempio n. 8
0
 private static function loadItems($libraryID, $itemIDs = array())
 {
     $shardID = Zotero_Shards::getByLibraryID($libraryID);
     $sql = self::getPrimaryDataSQL() . "1";
     // TODO: optimize
     if ($itemIDs) {
         foreach ($itemIDs as $itemID) {
             if (!is_int($itemID)) {
                 throw new Exception("Invalid itemID {$itemID}");
             }
         }
         $sql .= ' AND itemID IN (' . implode(',', array_fill(0, sizeOf($itemIDs), '?')) . ')';
     }
     $stmt = Zotero_DB::getStatement($sql, "loadItems_" . sizeOf($itemIDs), $shardID);
     $itemRows = Zotero_DB::queryFromStatement($stmt, $itemIDs);
     $loadedItemIDs = array();
     if ($itemRows) {
         foreach ($itemRows as $row) {
             if ($row['libraryID'] != $libraryID) {
                 throw new Exception("Item {$itemID} isn't in library {$libraryID}", Z_ERROR_OBJECT_LIBRARY_MISMATCH);
             }
             $itemID = $row['id'];
             $loadedItemIDs[] = $itemID;
             // Item isn't loaded -- create new object and stuff in array
             if (!isset(self::$objectCache[$itemID])) {
                 $item = new Zotero_Item();
                 $item->loadFromRow($row, true);
                 self::$objectCache[$itemID] = $item;
             } else {
                 self::$objectCache[$itemID]->loadFromRow($row, true);
             }
         }
     }
     if (!$itemIDs) {
         // If loading all items, remove old items that no longer exist
         $ids = array_keys(self::$objectCache);
         foreach ($ids as $id) {
             if (!in_array($id, $loadedItemIDs)) {
                 throw new Exception("Unimplemented");
                 //$this->unload($id);
             }
         }
     }
 }
Esempio n. 9
0
 /**
  * Delete data from memcached
  */
 public static function deleteCachedData($libraryID)
 {
     $shardID = Zotero_Shards::getByLibraryID($libraryID);
     // Clear itemID-specific memcache values
     $sql = "SELECT itemID FROM items WHERE libraryID=?";
     $itemIDs = Zotero_DB::columnQuery($sql, $libraryID, $shardID);
     if ($itemIDs) {
         $cacheKeys = array("itemCreators", "itemIsDeleted", "itemRelated", "itemUsedFieldIDs", "itemUsedFieldNames");
         foreach ($itemIDs as $itemID) {
             foreach ($cacheKeys as $key) {
                 Z_Core::$MC->delete($key . '_' . $itemID);
             }
         }
     }
     /*foreach (Zotero_DataObjects::$objectTypes as $type=>$arr) {
     			$className = "Zotero_" . $arr['plural'];
     			call_user_func(array($className, "clearPrimaryDataCache"), $libraryID);
     		}*/
 }
Esempio n. 10
0
 private static function load($libraryID, $ids = [], array $options = [])
 {
     $loaded = [];
     if (!$libraryID) {
         throw new Exception("libraryID must be provided");
     }
     if ($libraryID !== false && !empty(self::$loadedLibraries[$libraryID])) {
         return $loaded;
     }
     $sql = self::getPrimaryDataSQL() . ' AND O.libraryID=?';
     $params = [$libraryID];
     if ($ids) {
         $sql .= ' AND O.' . self::$idColumn . ' IN (' . implode(',', $ids) . ')';
     }
     $t = microtime();
     $rows = Zotero_DB::query($sql, $params, Zotero_Shards::getByLibraryID($libraryID));
     foreach ($rows as $row) {
         $id = $row['id'];
         // Existing object -- reload in place
         if (isset(self::$objectCache[$id])) {
             self::$objectCache[$id]->loadFromRow($row, true);
             $obj = self::$objectCache[$id];
         } else {
             $class = "Zotero_" . self::$ObjectType;
             $obj = new $class();
             $obj->loadFromRow($row, true);
             if (!$options || !$options->noCache) {
                 self::registerObject($obj);
             }
         }
         $loaded[$id] = $obj;
     }
     Z_Core::debug("Loaded " . self::$objectTypePlural . " in " . (microtime() - $t) . "ms");
     if (!$ids) {
         self::$loadedLibraries[$libraryID] = true;
         // If loading all objects, remove cached objects that no longer exist
         foreach (self::$objectCache as $obj) {
             if ($libraryID !== false && obj . libraryID !== libraryID) {
                 continue;
             }
             if (empty($loaded[$obj->id])) {
                 self::unload($obj->id);
             }
         }
     }
     return $loaded;
 }
Esempio n. 11
0
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::$SYNC_DOMAIN, 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 : 'us-east-1', 'version' => 'latest', 'signature' => 'v4'];
// 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();
    } else {
        $cache = new \Doctrine\Common\Cache\FilesystemCache(Z_ENV_BASE_PATH . 'tmp/cache');
    }
    $awsConfig['credentials'] = new \Aws\DoctrineCacheAdapter($cache);
} else {
    $awsConfig['credentials'] = ['key' => Z_CONFIG::$AWS_ACCESS_KEY, 'secret' => Z_CONFIG::$AWS_SECRET_KEY];
Esempio n. 12
0
 private static function updateLastAdded($storageFileID)
 {
     $sql = "UPDATE storageFiles SET lastAdded=NOW() WHERE storageFileID=?";
     Zotero_DB::query($sql, $storageFileID);
 }
Esempio n. 13
0
 private function loadRelatedItems()
 {
     if (!$this->id) {
         return;
     }
     Z_Core::debug("Loading related items for item {$this->id}");
     if ($this->loaded['relatedItems']) {
         trigger_error("Related items for item {$this->id} already loaded", E_USER_ERROR);
     }
     if (!$this->loaded['primaryData']) {
         $this->loadPrimaryData(true);
     }
     // TODO: use a prepared statement
     if (!is_numeric($this->id)) {
         trigger_error("Invalid itemID '{$this->id}'", E_USER_ERROR);
     }
     $cacheKey = $this->getCacheKey("itemRelated");
     //$ids = Z_Core::$MC->get($cacheKey);
     $ids = false;
     if ($ids === false) {
         $sql = "SELECT linkedItemID FROM itemRelated WHERE itemID=?";
         $stmt = Zotero_DB::getStatement($sql, true, Zotero_Shards::getByLibraryID($this->libraryID));
         $ids = Zotero_DB::columnQueryFromStatement($stmt, $this->id);
         Z_Core::$MC->set($cacheKey, $ids ? $ids : array());
     }
     $this->relatedItems = $ids ? $ids : array();
     $this->loaded['relatedItems'] = true;
 }
Esempio n. 14
0
 private function load()
 {
     //Z_Core::debug("Loading data for search $this->id");
     if (!$this->libraryID) {
         throw new Exception("Library ID not set");
     }
     if (!$this->id && !$this->key) {
         throw new Exception("ID or key not set");
     }
     $shardID = Zotero_Shards::getByLibraryID($this->libraryID);
     $sql = "SELECT searchID AS id, searchName AS name, dateAdded, dateModified, libraryID, `key`,\n\t\t\t\tMAX(searchConditionID) AS maxSearchConditionID FROM savedSearches\n\t\t\t\tLEFT JOIN savedSearchConditions USING (searchID) WHERE ";
     if ($this->id) {
         $sql .= "searchID=?";
         $params = $this->id;
     } else {
         $sql .= "libraryID=? AND `key`=?";
         $params = array($this->libraryID, $this->key);
     }
     $sql .= " GROUP BY searchID";
     $data = Zotero_DB::rowQuery($sql, $params, $shardID);
     $this->loaded = true;
     if (!$data) {
         return;
     }
     foreach ($data as $key => $val) {
         $this->{$key} = $val;
     }
     $sql = "SELECT * FROM savedSearchConditions\n\t\t\t\tWHERE searchID=? ORDER BY searchConditionID";
     $conditions = Zotero_DB::query($sql, $this->id, $shardID);
     foreach ($conditions as $condition) {
         /*
         if (!Zotero.SearchConditions.get(condition)){
         	Zotero.debug("Invalid saved search condition '"
         		+ condition + "' -- skipping", 2);
         	continue;
         }
         */
         $searchConditionID = $condition['searchConditionID'];
         $this->conditions[$searchConditionID] = array('id' => $searchConditionID, 'condition' => $condition['condition'], 'mode' => $condition['mode'], 'operator' => $condition['operator'], 'value' => $condition['value'], 'required' => $condition['required']);
     }
 }
Esempio n. 15
0
 private function end()
 {
     if (!$this->responseXML instanceof SimpleXMLElement) {
         throw new Exception("Response XML not provided");
     }
     if ($this->profile) {
         Zotero_DB::profileEnd($this->profileShard, false);
     }
     if ($this->responseCode) {
         switch ($this->responseCode) {
             case 201:
                 header("HTTP/1.1 201 Created");
                 break;
             default:
                 throw new Exception("Unsupported response code");
         }
     } else {
         $updated = (string) $this->responseXML->updated;
         if ($updated) {
             $updated = strtotime($updated);
             $ifModifiedSince = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? $_SERVER['HTTP_IF_MODIFIED_SINCE'] : false;
             $ifModifiedSince = strtotime($ifModifiedSince);
             if ($ifModifiedSince >= $updated) {
                 header('HTTP/1.1 304 Not Modified');
                 exit;
             }
             $lastModified = substr(date('r', $updated), 0, -5) . "GMT";
             header("Last-Modified: {$lastModified}");
         }
     }
     $xmlstr = $this->responseXML->asXML();
     $doc = new DOMDocument('1.0');
     $doc->loadXML($xmlstr);
     $doc->formatOutput = true;
     if ($this->queryParams['pprint']) {
         $ppdoc = new DOMDocument('1.0');
         // Zero-width spaces to push <feed> beyond Firefox's
         // feed auto-detection boundary
         $comment = $ppdoc->createComment("​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​");
         $ppdoc->appendChild($comment);
         $ppdoc->formatOutput = true;
         $rootElem = $doc->firstChild;
         $importedNode = $ppdoc->importNode($rootElem, true);
         $ppdoc->appendChild($importedNode);
         $doc = $ppdoc;
     }
     $xmlstr = $doc->saveXML();
     if ($this->queryParams['pprint']) {
         header("Content-Type: text/xml");
     } else {
         header("Content-Type: application/atom+xml");
     }
     echo $xmlstr;
     $this->logRequestTime();
     echo ob_get_clean();
     exit;
 }
Esempio n. 16
0
 public static function addCustomType($name)
 {
     if (self::getID($name)) {
         throw new Exception("Item type '{$name}' already exists");
     }
     if (!preg_match('/^[a-z][^\\s0-9]+$/', $name)) {
         throw new Exception("Invalid item type name '{$name}'");
     }
     // TODO: make sure user hasn't added too many already
     throw new Exception("Unimplemented");
     // TODO: add to cache
     Zotero_DB::beginTransaction();
     $sql = "SELECT NEXT_ID(itemTypeID) FROM itemTypes";
     $itemTypeID = Zotero_DB::valueQuery($sql);
     $sql = "INSERT INTO itemTypes (?, ?, ?)";
     Zotero_DB::query($sql, array($itemTypeID, $name, 1));
     Zotero_DB::commit();
     return $itemTypeID;
 }
Esempio n. 17
0
 private static function getDeletedObjectIDs($userID, $timestamp, $includeAllUserObjects = false)
 {
     /*
     $sql = "SELECT version FROM version WHERE schema='syncdeletelog'";
     $syncLogStart = Zotero_DB::valueQuery($sql);
     if (!$syncLogStart) {
     	throw ('Sync log start time not found');
     }
     */
     /*
     // Last sync time is before start of log
     if ($lastSyncDate && new Date($syncLogStart * 1000) > $lastSyncDate) {
     	return -1;
     }
     */
     // Personal library
     $shardID = Zotero_Shards::getByUserID($userID);
     $libraryID = Zotero_Users::getLibraryIDFromUserID($userID);
     $shardLibraryIDs[$shardID] = array($libraryID);
     // Group libraries
     if ($includeAllUserObjects) {
         $groupIDs = Zotero_Groups::getUserGroups($userID);
         if ($groupIDs) {
             // Separate groups into shards for querying
             foreach ($groupIDs as $groupID) {
                 $libraryID = Zotero_Groups::getLibraryIDFromGroupID($groupID);
                 $shardID = Zotero_Shards::getByLibraryID($libraryID);
                 if (!isset($shardLibraryIDs[$shardID])) {
                     $shardLibraryIDs[$shardID] = array();
                 }
                 $shardLibraryIDs[$shardID][] = $libraryID;
             }
         }
     }
     // Send query at each shard
     $rows = array();
     foreach ($shardLibraryIDs as $shardID => $libraryIDs) {
         $sql = "SELECT libraryID, objectType, id, timestamp\n\t\t\t\t\tFROM syncDeleteLogIDs WHERE libraryID IN (" . implode(', ', array_fill(0, sizeOf($libraryIDs), '?')) . ")";
         $params = $libraryIDs;
         if ($timestamp) {
             // Send any entries from before these were being properly sent
             if ($timestamp < 1260778500) {
                 $sql .= " AND (timestamp >= FROM_UNIXTIME(?) OR timestamp BETWEEN 1257968068 AND FROM_UNIXTIME(?))";
                 $params[] = $timestamp;
                 $params[] = 1260778500;
             } else {
                 $sql .= " AND timestamp >= FROM_UNIXTIME(?)";
                 $params[] = $timestamp;
             }
         }
         $sql .= " ORDER BY timestamp";
         $shardRows = Zotero_DB::query($sql, $params, $shardID);
         if ($shardRows) {
             $rows = array_merge($rows, $shardRows);
         }
     }
     if (!$rows) {
         return false;
     }
     $deletedIDs = array('groups' => array());
     foreach ($rows as $row) {
         $type = $row['objectType'] . 's';
         $deletedIDs[$type][] = $row['id'];
     }
     return $deletedIDs;
 }
Esempio n. 18
0
 public static function loadHashes($libraryID)
 {
     $sql = "SELECT itemID, hash FROM itemNotes JOIN items USING (itemID) WHERE libraryID=?";
     $hashes = Zotero_DB::query($sql, $libraryID, Zotero_Shards::getByLibraryID($libraryID));
     if (!$hashes) {
         return;
     }
     if (!isset(self::$hashCache[$libraryID])) {
         self::$hashCache[$libraryID] = array();
     }
     foreach ($hashes as $hash) {
         if ($hash['hash']) {
             self::$hashCache[$libraryID][$hash['itemID']] = $hash['hash'];
         }
     }
 }
Esempio n. 19
0
 public function keys()
 {
     $userID = $this->objectUserID;
     $key = $this->objectName;
     $this->allowMethods(['GET', 'POST', 'PUT', 'DELETE']);
     if ($this->method == 'GET') {
         // Single key
         if ($key) {
             $keyObj = Zotero_Keys::getByKey($key);
             if (!$keyObj) {
                 $this->e404("Key not found");
             }
             // /users/<userID>/keys/<keyID> (deprecated)
             if ($userID) {
                 // If we have a userID, make sure it matches
                 if ($keyObj->userID != $userID) {
                     $this->e404("Key not found");
                 }
             } else {
                 if ($this->apiVersion < 3) {
                     $this->e404();
                 }
             }
             if ($this->apiVersion >= 3) {
                 $json = $keyObj->toJSON();
                 // If not super-user, don't include name or recent IP addresses
                 if (!$this->permissions->isSuper()) {
                     unset($json['dateAdded']);
                     unset($json['lastUsed']);
                     unset($json['name']);
                     unset($json['recentIPs']);
                 }
                 header('application/json');
                 echo Zotero_Utilities::formatJSON($json);
             } else {
                 $this->responseXML = $keyObj->toXML();
                 // If not super-user, don't include name or recent IP addresses
                 if (!$this->permissions->isSuper()) {
                     unset($this->responseXML['dateAdded']);
                     unset($this->responseXML['lastUsed']);
                     unset($this->responseXML->name);
                     unset($this->responseXML->recentIPs);
                 }
             }
         } else {
             if (!$this->permissions->isSuper()) {
                 $this->e403();
             }
             $keyObjs = Zotero_Keys::getUserKeys($userID);
             if ($keyObjs) {
                 if ($this->apiVersion >= 3) {
                     $json = [];
                     foreach ($keyObjs as $keyObj) {
                         $json[] = $keyObj->toJSON();
                     }
                     echo Zotero_Utilities::formatJSON($json);
                 } else {
                     $xml = new SimpleXMLElement('<keys/>');
                     $domXML = dom_import_simplexml($xml);
                     foreach ($keyObjs as $keyObj) {
                         $keyXML = $keyObj->toXML();
                         $domKeyXML = dom_import_simplexml($keyXML);
                         $node = $domXML->ownerDocument->importNode($domKeyXML, true);
                         $domXML->appendChild($node);
                     }
                     $this->responseXML = $xml;
                 }
             }
         }
     } else {
         if ($this->method == 'DELETE') {
             if (!$key) {
                 $this->e400("DELETE requests must end with a key");
             }
             Zotero_DB::beginTransaction();
             $keyObj = Zotero_Keys::getByKey($key);
             if (!$keyObj) {
                 $this->e404("Key '{$key}' does not exist");
             }
             $keyObj->erase();
             Zotero_DB::commit();
             header("HTTP/1.1 204 No Content");
             exit;
         } else {
             // Require super-user for modifications
             if (!$this->permissions->isSuper()) {
                 $this->e403();
             }
             if ($this->method == 'POST') {
                 if ($key) {
                     $this->e400("POST requests cannot end with a key (did you mean PUT?)");
                 }
                 if ($this->apiVersion >= 3) {
                     $json = json_decode($this->body, true);
                     if (!$json) {
                         $this->e400("{$this->method} data is not valid JSON");
                     }
                     if (!empty($json['key'])) {
                         $this->e400("POST requests cannot contain a key in '" . $this->body . "'");
                     }
                     $fields = $this->getFieldsFromJSON($json);
                 } else {
                     try {
                         $keyXML = @new SimpleXMLElement($this->body);
                     } catch (Exception $e) {
                         $this->e400("{$this->method} data is not valid XML");
                     }
                     if (!empty($key['key'])) {
                         $this->e400("POST requests cannot contain a key in '" . $this->body . "'");
                     }
                     $fields = $this->getFieldsFromKeyXML($keyXML);
                 }
                 Zotero_DB::beginTransaction();
                 try {
                     $keyObj = new Zotero_Key();
                     $keyObj->userID = $userID;
                     foreach ($fields as $field => $val) {
                         if ($field == 'access') {
                             foreach ($val as $access) {
                                 $this->setKeyPermissions($keyObj, $access);
                             }
                         } else {
                             $keyObj->{$field} = $val;
                         }
                     }
                     $keyObj->save();
                 } catch (Exception $e) {
                     if ($e->getCode() == Z_ERROR_KEY_NAME_TOO_LONG) {
                         $this->e400($e->getMessage());
                     }
                     $this->handleException($e);
                 }
                 if ($this->apiVersion >= 3) {
                     header('application/json');
                     echo Zotero_Utilities::formatJSON($keyObj->toJSON());
                 } else {
                     $this->responseXML = $keyObj->toXML();
                 }
                 Zotero_DB::commit();
                 $url = Zotero_API::getKeyURI($keyObj);
                 $this->responseCode = 201;
                 header("Location: " . $url, false, 201);
             } else {
                 if ($this->method == 'PUT') {
                     if (!$key) {
                         $this->e400("PUT requests must end with a key (did you mean POST?)");
                     }
                     if ($this->apiVersion >= 3) {
                         $json = json_decode($this->body, true);
                         if (!$json) {
                             $this->e400("{$this->method} data is not valid JSON");
                         }
                         $fields = $this->getFieldsFromJSON($json);
                     } else {
                         try {
                             $keyXML = @new SimpleXMLElement($this->body);
                         } catch (Exception $e) {
                             $this->e400("{$this->method} data is not valid XML");
                         }
                         $fields = $this->getFieldsFromKeyXML($keyXML);
                     }
                     // Key attribute is optional, but, if it's there, make sure it matches
                     if (isset($fields['key']) && $fields['key'] != $key) {
                         $this->e400("Key '{$fields['key']}' does not match key '{$key}' from URI");
                     }
                     Zotero_DB::beginTransaction();
                     try {
                         $keyObj = Zotero_Keys::getByKey($key);
                         if (!$keyObj) {
                             $this->e404("Key '{$key}' does not exist");
                         }
                         foreach ($fields as $field => $val) {
                             if ($field == 'access') {
                                 foreach ($val as $access) {
                                     $this->setKeyPermissions($keyObj, $access);
                                 }
                             } else {
                                 $keyObj->{$field} = $val;
                             }
                         }
                         $keyObj->save();
                     } catch (Exception $e) {
                         if ($e->getCode() == Z_ERROR_KEY_NAME_TOO_LONG) {
                             $this->e400($e->getMessage());
                         }
                         $this->handleException($e);
                     }
                     if ($this->apiVersion >= 3) {
                         echo Zotero_Utilities::formatJSON($keyObj->toJSON());
                     } else {
                         $this->responseXML = $keyObj->toXML();
                     }
                     Zotero_DB::commit();
                 }
             }
         }
     }
     if ($this->apiVersion >= 3) {
         $this->end();
     } else {
         header('Content-Type: application/xml');
         $xmlstr = $this->responseXML->asXML();
         $doc = new DOMDocument('1.0');
         $doc->loadXML($xmlstr);
         $doc->formatOutput = true;
         echo $doc->saveXML();
         exit;
     }
 }
Esempio n. 20
0
 public static function deleteByLibraryMySQL($libraryID)
 {
     $sql = "DELETE IFT FROM itemFulltext IFT JOIN items USING (itemID) WHERE libraryID=?";
     Zotero_DB::query($sql, $libraryID, Zotero_Shards::getByLibraryID($libraryID));
 }
Esempio n. 21
0
 private function loadLinkedItems()
 {
     Z_Core::debug("Loading linked items for tag {$this->id}");
     if (!$this->id && !$this->key) {
         $this->linkedItemsLoaded = true;
         return;
     }
     if (!$this->loaded) {
         $this->load();
     }
     if (!$this->id) {
         $this->linkedItemsLoaded = true;
         return;
     }
     $sql = "SELECT itemID FROM itemTags WHERE tagID=?";
     $stmt = Zotero_DB::getStatement($sql, true, Zotero_Shards::getByLibraryID($this->libraryID));
     $ids = Zotero_DB::columnQueryFromStatement($stmt, $this->id);
     $this->linkedItems = array();
     if ($ids) {
         $this->linkedItems = Zotero_Items::get($this->libraryID, $ids);
     }
     $this->linkedItemsLoaded = true;
 }
Esempio n. 22
0
 public function storageadmin()
 {
     if (!$this->permissions->isSuper()) {
         $this->e404();
     }
     $this->allowMethods(array('GET', 'POST'));
     Zotero_DB::beginTransaction();
     if ($this->method == 'POST') {
         if (!isset($_POST['quota'])) {
             $this->e400("Quota not provided");
         }
         // Accept 'unlimited' via API
         if ($_POST['quota'] == 'unlimited') {
             $_POST['quota'] = self::UNLIMITED;
         }
         if (!isset($_POST['expiration'])) {
             $this->e400("Expiration not provided");
         }
         if (!is_numeric($_POST['quota']) || $_POST['quota'] < 0) {
             $this->e400("Invalid quota");
         }
         if (!is_numeric($_POST['expiration'])) {
             $this->e400("Invalid expiration");
         }
         $halfHourAgo = strtotime("-30 minutes");
         if ($_POST['expiration'] != 0 && $_POST['expiration'] < $halfHourAgo) {
             $this->e400("Expiration is in the past");
         }
         try {
             Zotero_Storage::setUserValues($this->objectUserID, $_POST['quota'], $_POST['expiration']);
         } catch (Exception $e) {
             if ($e->getCode() == Z_ERROR_GROUP_QUOTA_SET_BELOW_USAGE) {
                 $this->e409("Cannot set quota below current usage");
             }
             $this->handleException($e);
         }
     }
     // GET request
     $xml = new SimpleXMLElement('<storage/>');
     $quota = Zotero_Storage::getEffectiveUserQuota($this->objectUserID);
     $xml->quota = $quota;
     $instQuota = Zotero_Storage::getInstitutionalUserQuota($this->objectUserID);
     // If personal quota is in effect
     if (!$instQuota || $quota > $instQuota) {
         $values = Zotero_Storage::getUserValues($this->objectUserID);
         if ($values) {
             $xml->expiration = (int) $values['expiration'];
         }
     }
     // Return 'unlimited' via API
     if ($quota == self::UNLIMITED) {
         $xml->quota = 'unlimited';
     }
     $usage = Zotero_Storage::getUserUsage($this->objectUserID);
     $xml->usage->total = $usage['total'];
     $xml->usage->library = $usage['library'];
     foreach ($usage['groups'] as $group) {
         if (!isset($group['id'])) {
             throw new Exception("Group id isn't set");
         }
         if (!isset($group['usage'])) {
             throw new Exception("Group usage isn't set");
         }
         $xmlGroup = $xml->usage->addChild('group', $group['usage']);
         $xmlGroup['id'] = $group['id'];
     }
     Zotero_DB::commit();
     header('application/xml');
     echo $xml->asXML();
     exit;
 }
Esempio n. 23
0
 public function save()
 {
     if (!$this->libraryID) {
         trigger_error("Library ID must be set before saving", E_USER_ERROR);
     }
     Zotero_Creators::editCheck($this);
     // If empty, move on
     if ($this->firstName === '' && $this->lastName === '') {
         throw new Exception('First and last name are empty');
     }
     if ($this->fieldMode == 1 && $this->firstName !== '') {
         throw new Exception('First name must be empty in single-field mode');
     }
     if (!$this->hasChanged()) {
         Z_Core::debug("Creator {$this->id} has not changed");
         return false;
     }
     Zotero_DB::beginTransaction();
     try {
         $creatorID = $this->id ? $this->id : Zotero_ID::get('creators');
         $isNew = !$this->id;
         Z_Core::debug("Saving creator {$this->id}");
         $key = $this->key ? $this->key : $this->generateKey();
         $timestamp = Zotero_DB::getTransactionTimestamp();
         $dateAdded = $this->dateAdded ? $this->dateAdded : $timestamp;
         $dateModified = $this->changed['dateModified'] ? $this->dateModified : $timestamp;
         $fields = "firstName=?, lastName=?, fieldMode=?,\n\t\t\t\t\t\tlibraryID=?, `key`=?, dateAdded=?, dateModified=?, serverDateModified=?";
         $params = array($this->firstName, $this->lastName, $this->fieldMode, $this->libraryID, $key, $dateAdded, $dateModified, $timestamp);
         $shardID = Zotero_Shards::getByLibraryID($this->libraryID);
         try {
             if ($isNew) {
                 $sql = "INSERT INTO creators SET creatorID=?, {$fields}";
                 $stmt = Zotero_DB::getStatement($sql, true, $shardID);
                 Zotero_DB::queryFromStatement($stmt, array_merge(array($creatorID), $params));
                 // Remove from delete log if it's there
                 $sql = "DELETE FROM syncDeleteLogKeys WHERE libraryID=? AND objectType='creator' AND `key`=?";
                 Zotero_DB::query($sql, array($this->libraryID, $key), $shardID);
             } else {
                 $sql = "UPDATE creators SET {$fields} WHERE creatorID=?";
                 $stmt = Zotero_DB::getStatement($sql, true, $shardID);
                 Zotero_DB::queryFromStatement($stmt, array_merge($params, array($creatorID)));
             }
         } catch (Exception $e) {
             if (strpos($e->getMessage(), " too long") !== false) {
                 if (strlen($this->firstName) > 255) {
                     throw new Exception("=First name '" . mb_substr($this->firstName, 0, 50) . "…' too long");
                 }
                 if (strlen($this->lastName) > 255) {
                     if ($this->fieldMode == 1) {
                         throw new Exception("=Last name '" . mb_substr($this->lastName, 0, 50) . "…' too long");
                     } else {
                         throw new Exception("=Name '" . mb_substr($this->lastName, 0, 50) . "…' too long");
                     }
                 }
             }
             throw $e;
         }
         // The client updates the mod time of associated items here, but
         // we don't, because either A) this is from syncing, where appropriate
         // mod times come from the client or B) the change is made through
         // $item->setCreator(), which updates the mod time.
         //
         // If the server started to make other independent creator changes,
         // linked items would need to be updated.
         Zotero_DB::commit();
         Zotero_Creators::cachePrimaryData(array('id' => $creatorID, 'libraryID' => $this->libraryID, 'key' => $key, 'dateAdded' => $dateAdded, 'dateModified' => $dateModified, 'firstName' => $this->firstName, 'lastName' => $this->lastName, 'fieldMode' => $this->fieldMode));
     } catch (Exception $e) {
         Zotero_DB::rollback();
         throw $e;
     }
     // If successful, set values in object
     if (!$this->id) {
         $this->id = $creatorID;
     }
     if (!$this->key) {
         $this->key = $key;
     }
     $this->init();
     if ($isNew) {
         Zotero_Creators::cache($this);
         Zotero_Creators::cacheLibraryKeyID($this->libraryID, $key, $creatorID);
     }
     // TODO: invalidate memcache?
     return $this->id;
 }
Esempio n. 24
0
 public function collections()
 {
     // Check for general library access
     if (!$this->permissions->canAccess($this->objectLibraryID)) {
         $this->e403();
     }
     if ($this->isWriteMethod()) {
         // Check for library write access
         if (!$this->permissions->canWrite($this->objectLibraryID)) {
             $this->e403("Write access denied");
         }
         // Make sure library hasn't been modified
         if (!$this->singleObject) {
             $libraryTimestampChecked = $this->checkLibraryIfUnmodifiedSinceVersion();
         }
         Zotero_Libraries::updateVersionAndTimestamp($this->objectLibraryID);
     }
     $collectionIDs = array();
     $collectionKeys = array();
     $results = array();
     // Single collection
     if ($this->singleObject) {
         $this->allowMethods(['HEAD', 'GET', 'PUT', 'PATCH', 'DELETE']);
         if (!Zotero_ID::isValidKey($this->objectKey)) {
             $this->e404();
         }
         $collection = Zotero_Collections::getByLibraryAndKey($this->objectLibraryID, $this->objectKey);
         if ($this->isWriteMethod()) {
             $collection = $this->handleObjectWrite('collection', $collection ? $collection : null);
             $this->queryParams['content'] = ['json'];
         }
         if (!$collection) {
             $this->e404("Collection not found");
         }
         $this->libraryVersion = $collection->version;
         if ($this->method == 'HEAD') {
             $this->end();
         }
         switch ($this->queryParams['format']) {
             case 'atom':
                 $this->responseXML = Zotero_Collections::convertCollectionToAtom($collection, $this->queryParams);
                 break;
             case 'json':
                 $json = $collection->toResponseJSON($this->queryParams, $this->permissions);
                 echo Zotero_Utilities::formatJSON($json);
                 break;
             default:
                 throw new Exception("Unexpected format '" . $this->queryParams['format'] . "'");
         }
     } else {
         $this->allowMethods(['HEAD', 'GET', 'POST', 'DELETE']);
         $this->libraryVersion = Zotero_Libraries::getUpdatedVersion($this->objectLibraryID);
         if ($this->scopeObject) {
             $this->allowMethods(array('GET'));
             switch ($this->scopeObject) {
                 case 'collections':
                     $collection = Zotero_Collections::getByLibraryAndKey($this->objectLibraryID, $this->scopeObjectKey);
                     if (!$collection) {
                         $this->e404("Collection not found");
                     }
                     $title = "Child Collections of ‘{$collection->name}'’";
                     $collectionIDs = $collection->getChildCollections();
                     break;
                 default:
                     throw new Exception("Invalid collections scope object '{$this->scopeObject}'");
             }
         } else {
             // Top-level items
             if ($this->subset == 'top') {
                 $this->allowMethods(array('GET'));
                 $title = "Top-Level Collections";
                 $results = Zotero_Collections::search($this->objectLibraryID, true, $this->queryParams);
             } else {
                 // Create a collection
                 if ($this->method == 'POST') {
                     $this->queryParams['format'] = 'writereport';
                     $obj = $this->jsonDecode($this->body);
                     $results = Zotero_Collections::updateMultipleFromJSON($obj, $this->queryParams, $this->objectLibraryID, $this->userID, $this->permissions, $libraryTimestampChecked ? 0 : 1, null);
                     if ($cacheKey = $this->getWriteTokenCacheKey()) {
                         Z_Core::$MC->set($cacheKey, true, $this->writeTokenCacheTime);
                     }
                     if ($this->apiVersion < 2) {
                         $uri = Zotero_API::getCollectionsURI($this->objectLibraryID);
                         $keys = array_merge(get_object_vars($results['success']), get_object_vars($results['unchanged']));
                         $queryString = "collectionKey=" . urlencode(implode(",", $keys)) . "&format=atom&content=json&order=collectionKeyList&sort=asc";
                         if ($this->apiKey) {
                             $queryString .= "&key=" . $this->apiKey;
                         }
                         $uri .= "?" . $queryString;
                         $this->queryParams = Zotero_API::parseQueryParams($queryString, $this->action, true, $this->apiVersion);
                         $title = "Collections";
                         $results = Zotero_Collections::search($this->objectLibraryID, false, $this->queryParams);
                     }
                 } else {
                     if ($this->method == 'DELETE') {
                         Zotero_DB::beginTransaction();
                         foreach ($this->queryParams['collectionKey'] as $collectionKey) {
                             Zotero_Collections::delete($this->objectLibraryID, $collectionKey);
                         }
                         Zotero_DB::commit();
                         $this->e204();
                     } else {
                         $title = "Collections";
                         $results = Zotero_Collections::search($this->objectLibraryID, false, $this->queryParams);
                     }
                 }
             }
         }
         if ($collectionIDs) {
             $this->queryParams['collectionIDs'] = $collectionIDs;
             $results = Zotero_Collections::search($this->objectLibraryID, false, $this->queryParams);
         }
         $options = ['action' => $this->action, 'uri' => $this->uri, 'results' => $results, 'requestParams' => $this->queryParams, 'permissions' => $this->permissions, 'head' => $this->method == 'HEAD'];
         switch ($this->queryParams['format']) {
             case 'atom':
                 $this->responseXML = Zotero_API::multiResponse(array_merge($options, ['title' => $this->getFeedNamePrefix($this->objectLibraryID) . $title]));
                 break;
             case 'json':
             case 'keys':
             case 'versions':
             case 'writereport':
                 Zotero_API::multiResponse($options);
                 break;
             default:
                 throw new Exception("Unexpected format '" . $this->queryParams['format'] . "'");
         }
     }
     $this->end();
 }
Esempio n. 25
0
	protected function loadRelations($reload = false) {
		if ($this->loaded['relations'] && !$reload) return;
		
		if (!$this->id) {
			return;
		}
		
		Z_Core::debug("Loading relations for item $this->id");
		
		$this->loadPrimaryData(false, true);
		
		$itemURI = Zotero_URI::getItemURI($this);
		
		$relations = Zotero_Relations::getByURIs($this->libraryID, $itemURI);
		$relations = array_map(function ($rel) {
			return [$rel->predicate, $rel->object];
		}, $relations);
		
		// Related items are bidirectional, so include any with this item as the object
		$reverseRelations = Zotero_Relations::getByURIs(
			$this->libraryID, false, Zotero_Relations::$relatedItemPredicate, $itemURI
		);
		foreach ($reverseRelations as $rel) {
			$r = [$rel->predicate, $rel->subject];
			// Only add if not already added in other direction
			if (!in_array($r, $relations)) {
				$relations[] = $r;
			}
		}
		
		// Also include any owl:sameAs relations with this item as the object
		// (as sent by client via classic sync)
		$reverseRelations = Zotero_Relations::getByURIs(
			$this->libraryID, false, Zotero_Relations::$linkedObjectPredicate, $itemURI
		);
		foreach ($reverseRelations as $rel) {
			$relations[] = [$rel->predicate, $rel->subject];
		}
		
		// TEMP: Get old-style related items
		//
		// Add related items
		$sql = "SELECT `key` FROM itemRelated IR "
			. "JOIN items I ON (IR.linkedItemID=I.itemID) "
			. "WHERE IR.itemID=?";
		$relatedItemKeys = Zotero_DB::columnQuery($sql, $this->id, Zotero_Shards::getByLibraryID($this->libraryID));
		if ($relatedItemKeys) {
			$prefix = Zotero_URI::getLibraryURI($this->libraryID) . "/items/";
			$predicate = Zotero_Relations::$relatedItemPredicate;
			foreach ($relatedItemKeys as $key) {
				$relations[] = [$predicate, $prefix . $key];
			}
		}
		// Reverse as well
		$sql = "SELECT `key` FROM itemRelated IR JOIN items I USING (itemID) WHERE IR.linkedItemID=?";
		$reverseRelatedItemKeys = Zotero_DB::columnQuery(
			$sql, $this->id, Zotero_Shards::getByLibraryID($this->libraryID)
		);
		if ($reverseRelatedItemKeys) {
			$prefix = Zotero_URI::getLibraryURI($this->libraryID) . "/items/";
			$predicate = Zotero_Relations::$relatedItemPredicate;
			foreach ($reverseRelatedItemKeys as $key) {
				$relations[] = [$predicate, $prefix . $key];
			}
		}
		
		$this->relations = $relations;
		$this->loaded['relations'] = true;
		$this->clearChanged('relations');
	}
Esempio n. 26
0
 private static function deleteLibrary($libraryID, $shardID)
 {
     $sql = "DELETE FROM shardLibraries WHERE libraryID=?";
     Zotero_DB::query($sql, $libraryID, $shardID);
 }
Esempio n. 27
0
 public static function search($libraryID, $params)
 {
     $results = array('results' => array(), 'total' => 0);
     // Default empty library
     if ($libraryID === 0) {
         return $results;
     }
     $shardID = Zotero_Shards::getByLibraryID($libraryID);
     $sql = "SELECT SQL_CALC_FOUND_ROWS DISTINCT tagID FROM tags " . "JOIN itemTags USING (tagID) WHERE libraryID=? ";
     $sqlParams = array($libraryID);
     // Pass a list of tagIDs, for when the initial search is done via SQL
     $tagIDs = !empty($params['tagIDs']) ? $params['tagIDs'] : array();
     // Filter for specific tags with "?tag=foo || bar"
     $tagNames = !empty($params['tag']) ? explode(' || ', $params['tag']) : array();
     if ($tagIDs) {
         $sql .= "AND tagID IN (" . implode(', ', array_fill(0, sizeOf($tagIDs), '?')) . ") ";
         $sqlParams = array_merge($sqlParams, $tagIDs);
     }
     if ($tagNames) {
         $sql .= "AND `name` IN (" . implode(', ', array_fill(0, sizeOf($tagNames), '?')) . ") ";
         $sqlParams = array_merge($sqlParams, $tagNames);
     }
     if (!empty($params['q'])) {
         if (!is_array($params['q'])) {
             $params['q'] = array($params['q']);
         }
         foreach ($params['q'] as $q) {
             $sql .= "AND name LIKE ? ";
             $sqlParams[] = "%{$q}%";
         }
     }
     $tagTypeSets = Zotero_API::getSearchParamValues($params, 'tagType');
     if ($tagTypeSets) {
         $positives = array();
         $negatives = array();
         foreach ($tagTypeSets as $set) {
             if ($set['negation']) {
                 $negatives = array_merge($negatives, $set['values']);
             } else {
                 $positives = array_merge($positives, $set['values']);
             }
         }
         if ($positives) {
             $sql .= "AND type IN (" . implode(',', array_fill(0, sizeOf($positives), '?')) . ") ";
             $sqlParams = array_merge($sqlParams, $positives);
         }
         if ($negatives) {
             $sql .= "AND type NOT IN (" . implode(',', array_fill(0, sizeOf($negatives), '?')) . ") ";
             $sqlParams = array_merge($sqlParams, $negatives);
         }
     }
     if (!empty($params['since'])) {
         $sql .= "AND version > ? ";
         $sqlParams[] = $params['since'];
     }
     if (!empty($params['sort'])) {
         $order = $params['sort'];
         if ($order == 'title') {
             // Force a case-insensitive sort
             $sql .= "ORDER BY name COLLATE utf8_unicode_ci ";
         } else {
             if ($order == 'numItems') {
                 $sql .= "GROUP BY tags.tagID ORDER BY COUNT(tags.tagID)";
             } else {
                 $sql .= "ORDER BY {$order} ";
             }
         }
         if (!empty($params['direction'])) {
             $sql .= " " . $params['direction'] . " ";
         }
     }
     if (!empty($params['limit'])) {
         $sql .= "LIMIT ?, ?";
         $sqlParams[] = $params['start'] ? $params['start'] : 0;
         $sqlParams[] = $params['limit'];
     }
     $ids = Zotero_DB::columnQuery($sql, $sqlParams, $shardID);
     $results['total'] = Zotero_DB::valueQuery("SELECT FOUND_ROWS()", false, $shardID);
     if ($ids) {
         $tags = array();
         foreach ($ids as $id) {
             $tags[] = Zotero_Tags::get($libraryID, $id);
         }
         $results['results'] = $tags;
     }
     return $results;
 }
Esempio n. 28
0
 public static function delete($libraryID, $key, $updateLibrary = false)
 {
     $table = static::field('table');
     $id = static::field('id');
     $type = static::field('object');
     $types = static::field('objects');
     if (!$key) {
         throw new Exception("Invalid key {$key}");
     }
     // Get object (and trigger caching)
     $obj = static::getByLibraryAndKey($libraryID, $key);
     if (!$obj) {
         return;
     }
     static::editCheck($obj);
     Z_Core::debug("Deleting {$type} {$libraryID}/{$key}", 4);
     $shardID = Zotero_Shards::getByLibraryID($libraryID);
     Zotero_DB::beginTransaction();
     // Needed for API deletes to get propagated via sync
     if ($updateLibrary) {
         $timestamp = Zotero_Libraries::updateTimestamps($obj->libraryID);
         Zotero_DB::registerTransactionTimestamp($timestamp);
     }
     // Delete child items
     if ($type == 'item') {
         if ($obj->isRegularItem()) {
             $children = array_merge($obj->getNotes(), $obj->getAttachments());
             if ($children) {
                 $children = Zotero_Items::get($libraryID, $children);
                 foreach ($children as $child) {
                     static::delete($child->libraryID, $child->key);
                 }
             }
         }
     }
     if ($type == 'relation') {
         // TODO: add key column to relations to speed this up
         $sql = "DELETE FROM {$table} WHERE libraryID=? AND MD5(CONCAT(subject, '_', predicate, '_', object))=?";
         $deleted = Zotero_DB::query($sql, array($libraryID, $key), $shardID);
     } else {
         $sql = "DELETE FROM {$table} WHERE libraryID=? AND `key`=?";
         $deleted = Zotero_DB::query($sql, array($libraryID, $key), $shardID);
     }
     unset(self::$idCache[$type][$libraryID][$key]);
     static::uncachePrimaryData($libraryID, $key);
     if ($deleted) {
         $sql = "INSERT INTO syncDeleteLogKeys (libraryID, objectType, `key`, timestamp)\n\t\t\t\t\t\tVALUES (?, '{$type}', ?, ?) ON DUPLICATE KEY UPDATE timestamp=?";
         $timestamp = Zotero_DB::getTransactionTimestamp();
         $params = array($libraryID, $key, $timestamp, $timestamp);
         Zotero_DB::query($sql, $params, $shardID);
     }
     Zotero_DB::commit();
 }
Esempio n. 29
0
 public function checkDBTransactionState()
 {
     if (Zotero_DB::transactionInProgress()) {
         error_log("Transaction still in progress at request end! " . "[" . $this->method . " " . $_SERVER['REQUEST_URI'] . "]");
     }
 }
Esempio n. 30
0
 private function load()
 {
     $libraryID = $this->libraryID;
     $id = $this->id;
     $key = $this->key;
     Z_Core::debug("Loading data for search " . ($id ? $id : $key));
     if (!$libraryID) {
         throw new Exception("Library ID not set");
     }
     if (!$id && !$key) {
         throw new Exception("ID or key not set");
     }
     $shardID = Zotero_Shards::getByLibraryID($libraryID);
     $sql = "SELECT searchID AS id, searchName AS name, dateAdded,\n\t\t\t\tdateModified, libraryID, `key`, version\n\t\t\t\tFROM savedSearches WHERE ";
     if ($id) {
         $sql .= "searchID=?";
         $params = $id;
     } else {
         $sql .= "libraryID=? AND `key`=?";
         $params = array($libraryID, $key);
     }
     $sql .= " GROUP BY searchID";
     $data = Zotero_DB::rowQuery($sql, $params, $shardID);
     $this->loaded = true;
     if (!$data) {
         return;
     }
     foreach ($data as $key => $val) {
         $this->{$key} = $val;
     }
     $sql = "SELECT * FROM savedSearchConditions\n\t\t\t\tWHERE searchID=? ORDER BY searchConditionID";
     $conditions = Zotero_DB::query($sql, $this->id, $shardID);
     foreach ($conditions as $condition) {
         $searchConditionID = $condition['searchConditionID'];
         $this->conditions[$searchConditionID] = array('id' => $searchConditionID, 'condition' => $condition['condition'], 'mode' => $condition['mode'], 'operator' => $condition['operator'], 'value' => $condition['value'], 'required' => $condition['required']);
     }
 }