public static function getShardInfo($shardID) { if (!$shardID) { throw new Exception('$shardID not provided'); } if (isset(self::$shardInfo[$shardID])) { return self::$shardInfo[$shardID]; } $cacheKey = 'shardInfo_' . $shardID; $shardInfo = Z_Core::$MC->get($cacheKey); if ($shardInfo) { self::$shardInfo[$shardID] = $shardInfo; return $shardInfo; } $sql = "SELECT address, port, db,\n\t\t\t\tCASE\n\t\t\t\t\tWHEN shardHosts.state='up' THEN shards.state\n\t\t\t\t\tWHEN shardHosts.state='readonly' THEN\n\t\t\t\t\t\tIF(shards.state='down', 'down', 'readonly')\n\t\t\t\t\tWHEN shardHosts.state='down' THEN 'down'\n\t\t\t\tEND AS state, shardHostID\n\t\t\t\tFROM shards JOIN shardHosts USING (shardHostID) WHERE shardID=?"; $shardInfo = Zotero_DB::rowQuery($sql, $shardID); if (!$shardInfo) { throw new Exception("Shard {$shardID} not found"); } self::$shardInfo[$shardID] = $shardInfo; Z_Core::$MC->set($cacheKey, $shardInfo, 60); return $shardInfo; }
public static function getUserValues($userID) { $sql = "SELECT quota, UNIX_TIMESTAMP(expiration) AS expiration FROM storageAccounts WHERE userID=?"; return Zotero_DB::rowQuery($sql, $userID); }
/** * Get the result of a queued process for a given sync session * * If no result, return false * If success, return array('timestamp' => "123456789") * If error, return array('xmldata' => "<data ...", 'exception' => Exception) */ public static function getSessionUploadResult($sessionID) { Zotero_DB::beginTransaction(); $sql = "SELECT UNIX_TIMESTAMP(finished) AS finished, xmldata, errorCode, errorMessage\n\t\t\t\tFROM syncUploadQueue WHERE sessionID=?"; $row = Zotero_DB::rowQuery($sql, $sessionID); if (!$row) { Zotero_DB::commit(); throw new Exception("Queued upload not found for session"); } if (is_null($row['finished'])) { Zotero_DB::beginTransaction(); return false; } $sql = "DELETE FROM syncUploadQueue WHERE sessionID=?"; Zotero_DB::query($sql, $sessionID); Zotero_DB::commit(); // Success if (is_null($row['errorCode'])) { return array('timestamp' => $row['finished']); } $e = @unserialize($row['errorMessage']); return array('timestamp' => $row['finished'], 'xmldata' => $row['xmldata'], 'exception' => $e); }
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']); } }
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']); } }
/** * Get library version from the database */ public static function getVersion($libraryID) { // Default empty library if ($libraryID === 0) { return 0; } $sql = "SELECT version FROM shardLibraries WHERE libraryID=?"; $version = Zotero_DB::valueQuery($sql, $libraryID, Zotero_Shards::getByLibraryID($libraryID)); // TEMP: Remove after classic sync, and use shardLibraries only for version info? if (!$version || $version == 1) { $shardID = Zotero_Shards::getByLibraryID($libraryID); $readOnly = Zotero_DB::isReadOnly($shardID); $sql = "SELECT lastUpdated, version FROM libraries WHERE libraryID=?"; $row = Zotero_DB::rowQuery($sql, $libraryID); $sql = "UPDATE shardLibraries SET version=?, lastUpdated=? WHERE libraryID=?"; Zotero_DB::query($sql, array($row['version'], $row['lastUpdated'], $libraryID), $shardID, ['writeInReadMode' => true]); $sql = "SELECT IFNULL(IF(MAX(version)=0, 1, MAX(version)), 1) FROM items WHERE libraryID=?"; $version = Zotero_DB::valueQuery($sql, $libraryID, $shardID); $sql = "UPDATE shardLibraries SET version=? WHERE libraryID=?"; Zotero_DB::query($sql, [$version, $libraryID], $shardID, ['writeInReadMode' => true]); } // Store original version for use by getOriginalVersion() if (!isset(self::$originalVersions[$libraryID])) { self::$originalVersions[$libraryID] = $version; } return $version; }
/** * Get the result of a queued process for a given sync session * * If no result, return false * If success, return array('timestamp' => "123456789") * If error, return array('xmldata' => "<data ...", 'exception' => Exception) */ public static function getSessionUploadResult($sessionID) { Zotero_DB::beginTransaction(); $sql = "SELECT UNIX_TIMESTAMP(finished) AS finished, xmldata, errorCode, errorMessage\n\t\t\t\tFROM syncUploadQueue WHERE sessionID=?"; $row = Zotero_DB::rowQuery($sql, $sessionID); if (!$row) { Zotero_DB::commit(); throw new Exception("Queued upload not found for session"); } if (is_null($row['finished'])) { Zotero_DB::beginTransaction(); return false; } $sql = "DELETE FROM syncUploadQueue WHERE sessionID=?"; Zotero_DB::query($sql, $sessionID); Zotero_DB::commit(); // Success if (is_null($row['errorCode'])) { return array('timestamp' => $row['finished']); } $e = @unserialize($row['errorMessage']); // In case it's not a valid exception for some reason, make one // // TODO: This can probably be removed after the transition if (!$e instanceof Exception) { $e = new Exception($row['errorMessage'], $row['errorCode']); } return array('timestamp' => $row['finished'], 'xmldata' => $row['xmldata'], 'exception' => $e); }
private function load($allowFail = false) { if (!$this->libraryID) { throw new Exception("Library ID not set"); } if (!$this->id) { throw new Exception("ID not set"); } //Z_Core::debug("Loading data for relation $this->id"); $sql = "SELECT relationID AS id, libraryID, subject, object, predicate FROM relations " . "WHERE relationID=?"; $data = Zotero_DB::rowQuery($sql, $this->id, Zotero_Shards::getByLibraryID($this->libraryID)); $this->loaded = true; if (!$data) { return; } foreach ($data as $key => $val) { $this->{$key} = $val; } }
private function load($allowFail = false) { if (!$this->libraryID) { throw new Exception("Library ID not set"); } if (!$this->id) { throw new Exception("ID not set"); } //Z_Core::debug("Loading data for relation $this->id"); $sql = "SELECT * FROM relations WHERE relationID=?"; $data = Zotero_DB::rowQuery($sql, $this->id, Zotero_Shards::getByLibraryID($this->libraryID)); $this->loaded = true; if (!$data) { return; } foreach ($data as $key => $val) { // TEMP if ($key == 'serverDateModifiedMS') { continue; } if ($key == 'relationID') { $this->id = $val; continue; } $this->{$key} = $val; } }
/** * Make sure we have a valid session */ private function sessionCheck() { if (empty($_REQUEST['sessionid'])) { $this->error(403, 'NO_SESSION_ID', "Session ID not provided"); } if (!preg_match('/^[a-f0-9]{32}$/', $_REQUEST['sessionid'])) { $this->error($this->apiVersion >= 9 ? 403 : 500, 'INVALID_SESSION_ID', "Invalid session ID"); } $sessionID = $_REQUEST['sessionid']; $session = Z_Core::$MC->get("syncSession_{$sessionID}"); $userID = $session ? $session['userID'] : null; // TEMP: can switch to just $session $ipAddress = isset($session['ipAddress']) ? $session['ipAddress'] : null; if (!$userID) { $sql = "SELECT userid, (UNIX_TIMESTAMP(NOW())-UNIX_TIMESTAMP(timestamp)) AS age,\n\t\t\t\t\tINET_NTOA(ipAddress) AS ipAddress FROM sessions WHERE sessionID=?"; $session = Zotero_DB::rowQuery($sql, $sessionID); if (!$session) { $this->error($this->apiVersion >= 9 ? 403 : 500, 'INVALID_SESSION_ID', "Invalid session ID"); } if ($session['age'] > $this->sessionLifetime) { $this->error($this->apiVersion >= 9 ? 403 : 500, 'SESSION_TIMED_OUT', "Session timed out"); } $userID = $session['userid']; $ipAddress = $session['ipAddress']; } $updated = Z_Core::$MC->set("syncSession_{$sessionID}", array('sessionID' => $sessionID, 'userID' => $userID, 'ipAddress' => $ipAddress), $this->sessionLifetime - 1200); // Every 20 minutes, update the timestamp in the DB if (!Z_Core::$MC->get("syncSession_" . $sessionID . "_dbUpdated")) { $sql = "UPDATE sessions SET timestamp=NOW() WHERE sessionID=?"; Zotero_DB::query($sql, $sessionID); Z_Core::$MC->set("syncSession_" . $sessionID . "_dbUpdated", true, 1200); } $this->sessionID = $sessionID; $this->userID = $userID; $this->userLibraryID = Zotero_Users::getLibraryIDFromUserID($userID); $this->ipAddress = $ipAddress; }
private function load() { Z_Core::debug("Loading data for collection {$this->_id}"); $libraryID = $this->_libraryID; $id = $this->_id; $key = $this->_key; if (!$libraryID) { throw new Exception("Library ID not set"); } if (!$id && !$key) { throw new Exception("ID or key not set"); } // Cache collection data for the entire library if (true) { if ($id) { Z_Core::debug("Loading data for collection {$libraryID}/{$id}"); $row = Zotero_Collections::getPrimaryDataByID($libraryID, $id); } else { Z_Core::debug("Loading data for collection {$libraryID}/{$key}"); $row = Zotero_Collections::getPrimaryDataByKey($libraryID, $key); } $this->loaded = true; if (!$row) { return; } if ($row['libraryID'] != $libraryID) { throw new Exception("libraryID {$row['libraryID']} != {$this->libraryID}"); } foreach ($row as $key => $val) { $field = '_' . $key; $this->{$field} = $val; } } else { // Use cached check for existence if possible if ($libraryID && $key) { if (!Zotero_Collections::existsByLibraryAndKey($libraryID, $key)) { $this->loaded = true; return; } } $sql = Zotero_Collections::getPrimaryDataSQL(); if ($id) { $sql .= "collectionID=?"; $params = $id; } else { $sql .= "libraryID=? AND `key`=?"; $params = array($libraryID, $key); } $data = Zotero_DB::rowQuery($sql, $params, Zotero_Shards::getByLibraryID($libraryID)); $this->loaded = true; if (!$data) { return; } foreach ($data as $key => $val) { $field = '_' . $key; $this->{$field} = $val; } } }
/** * Build object from database */ public function loadPrimaryData($reload = false, $failOnMissing = false) { if (!$this->identified) { return; } if ($this->loaded['primaryData'] && !$reload) { return; } $libraryID = $this->_libraryID; $id = $this->_id; $key = $this->_key; $objectsClass = $this->objectsClass; $columns = []; $join = []; $where = []; if (!$this->_id && !$this->_key) { throw new Exception("id or key must be set to load primary data"); } $primaryFields = $objectsClass::$primaryFields; $idField = $objectsClass::$idColumn; foreach ($primaryFields as $field) { // If field not already set if ($field == $idField || $this->{'_' . $field} === null || $reload) { $columns[] = $objectsClass::getPrimaryDataSQLPart($field) . " AS `{$field}`"; } } if (!$columns) { return; } /*if ($id) { Z_Core::debug("Loading data for item $libraryID/$id"); $row = Zotero_Items::getPrimaryDataByID($libraryID, $id); } else { Z_Core::debug("Loading data for item $libraryID/$key"); $row = Zotero_Items::getPrimaryDataByKey($libraryID, $key); }*/ // This should match Zotero.*.primaryDataSQL, but without // necessarily including all columns $sql = "SELECT " . join(", ", $columns) . $objectsClass::$primaryDataSQLFrom; if ($id) { $sql .= " AND O.{$idField}=? "; $params = $id; } else { $sql .= " AND O.key=? AND O.libraryID=? "; $params = [$key, $libraryID]; } $sql .= sizeOf($where) ? ' AND ' . join(' AND ', $where) : ''; $row = Zotero_DB::rowQuery($sql, $params, Zotero_Shards::getByLibraryID($libraryID)); if (!$row) { if ($failOnMissing) { throw new Exception($this->ObjectType . " " . ($id ? $id : $libraryID . "/" . $key) . " not found"); } $this->clearChanged('primaryData'); // If object doesn't exist, mark all data types as loaded $this->markAllDataTypeLoadStates(true); return; } $this->loadFromRow($row, $reload); }
private function load() { if ($this->id) { $sql = "SELECT * FROM `keys` WHERE keyID=?"; $row = Zotero_DB::rowQuery($sql, $this->id); } else { if ($this->key) { $sql = "SELECT * FROM `keys` WHERE `key`=?"; $row = Zotero_DB::rowQuery($sql, $this->key); } } if (!$row) { return false; } $this->loadFromRow($row); $sql = "SELECT * FROM keyPermissions WHERE keyID=?"; $rows = Zotero_DB::query($sql, $this->id); foreach ($rows as $row) { $this->permissions[$row['libraryID']][$row['permission']] = !!$row['granted']; if ($row['permission'] == 'library') { // Key-based access to library provides file access as well $this->permissions[$row['libraryID']]['files'] = !!$row['granted']; // Key-based access to group libraries provides note access as well if ($row['libraryID'] === 0 || Zotero_Libraries::getType($row['libraryID']) == 'group') { $this->permissions[$row['libraryID']]['notes'] = !!$row['granted']; } } } }
/** * Get the text of an item note **/ public function getNote($sanitized = false, $htmlspecialchars = false) { if (!$this->isNote() && !$this->isAttachment()) { throw new Exception("getNote() can only be called on notes and attachments"); } if (!$this->id) { return ''; } // Store access time for later garbage collection //$this->noteAccessTime = new Date(); if ($sanitized) { if ($htmlspecialchars) { throw new Exception('$sanitized and $htmlspecialchars cannot currently be used together'); } if (is_null($this->noteText)) { $sql = "SELECT note, noteSanitized FROM itemNotes WHERE itemID=?"; $row = Zotero_DB::rowQuery($sql, $this->id, Zotero_Shards::getByLibraryID($this->libraryID)); if (!$row) { $row = array('note' => '', 'noteSanitized' => ''); } // Empty string means the note is sanitized // Null means not yet processed if ($row['noteSanitized'] === '') { $this->noteText = $row['note']; $this->noteTextSanitized =& $this->noteText; } else { $this->noteText = $row['note']; if (!is_null($row['noteSanitized'])) { $this->noteTextSanitized = $row['noteSanitized']; } } } // DEBUG: Shouldn't be necessary anymore if (is_null($this->noteTextSanitized)) { $sanitized = Zotero_Notes::sanitize($this->noteText); // If sanitized version is the same, use reference if ($this->noteText == $sanitized) { $this->noteTextSanitized =& $this->noteText; } else { $this->noteTextSanitized = $sanitized; } } return $this->noteTextSanitized; } if (is_null($this->noteText)) { $note = Zotero_Notes::getCachedNote($this->libraryID, $this->id); if ($note === false) { $sql = "SELECT note FROM itemNotes WHERE itemID=?"; $note = Zotero_DB::valueQuery($sql, $this->id, Zotero_Shards::getByLibraryID($this->libraryID)); } $this->noteText = $note ? $note : ''; } if ($this->noteText !== '' && $htmlspecialchars) { $noteHash = $this->getNoteHash(); if (!$noteHash) { throw new Exception("Note hash is empty"); } $cacheKey = "htmlspecialcharsNote_{$noteHash}"; $note = Z_Core::$MC->get($cacheKey); if ($note === false) { $note = htmlspecialchars($this->noteText); Z_Core::$MC->set($cacheKey, $note); } return $note; } return $this->noteText; }
private function load() { $sql = "SELECT * FROM groups WHERE groupID=?"; $row = Zotero_DB::rowQuery($sql, $this->id); if (!$row) { return false; } foreach ($row as $field => $value) { switch ($field) { case 'groupID': case 'slug': continue 2; } $this->{$field} = $value; } $sql = "SELECT userID FROM groupUsers WHERE groupID=? AND role='owner'"; $userID = Zotero_DB::valueQuery($sql, $this->id); if (!$userID) { throw new Exception("Group {$this->id} doesn't have an owner"); } $this->ownerUserID = $userID; $this->loaded = true; $this->changed = array(); }
/** * Get the text of an item note **/ public function getNote($sanitized=false, $htmlspecialchars=false) { if (!$this->isNote() && !$this->isAttachment()) { throw new Exception("getNote() can only be called on notes and attachments"); } if (!$this->id) { return ''; } // Store access time for later garbage collection //$this->noteAccessTime = new Date(); if ($sanitized) { if ($htmlspecialchars) { throw new Exception('$sanitized and $htmlspecialchars cannot currently be used together'); } if (is_null($this->noteText)) { $sql = "SELECT note, noteSanitized FROM itemNotes WHERE itemID=?"; $row = Zotero_DB::rowQuery($sql, $this->id, Zotero_Shards::getByLibraryID($this->libraryID)); if (!$row) { $row = array('note' => '', 'noteSanitized' => ''); } $this->noteText = $row['note']; $this->noteTextSanitized = $row['noteSanitized']; } // Empty string means the original note is sanitized return $this->noteTextSanitized === '' ? $this->noteText : $this->noteTextSanitized; } if (is_null($this->noteText)) { $note = Zotero_Notes::getCachedNote($this->libraryID, $this->id); if ($note === false) { $sql = "SELECT note FROM itemNotes WHERE itemID=?"; $note = Zotero_DB::valueQuery($sql, $this->id, Zotero_Shards::getByLibraryID($this->libraryID)); } $this->noteText = $note !== false ? $note : ''; } if ($this->noteText !== '' && $htmlspecialchars) { $noteHash = $this->getNoteHash(); if ($noteHash) { $cacheKey = "htmlspecialcharsNote_$noteHash"; $note = Z_Core::$MC->get($cacheKey); if ($note === false) { $note = htmlspecialchars($this->noteText); Z_Core::$MC->set($cacheKey, $note); } } else { error_log("WARNING: Note hash is empty"); $note = htmlspecialchars($this->noteText); } return $note; } return $this->noteText; }
public static function getPrimaryDataByKey($libraryID, $key) { $type = static::field('object'); $keyField = static::field('key'); if (!is_numeric($libraryID)) { throw new Exception("Invalid libraryID '{$libraryID}'"); } if ($type == 'relation') { if (!preg_match('/[a-f0-9]{32}/', $key)) { throw new Exception("Invalid key '{$key}'"); } } else { if (!preg_match('/[A-Z0-9]{8}/', $key) && $type != 'setting') { throw new Exception("Invalid key '{$key}'"); } } if (isset(self::$primaryDataByKey[$type][$libraryID][$key])) { return self::$primaryDataByKey[$type][$libraryID][$key]; } $sql = self::getPrimaryDataSQL() . "libraryID=? AND `{$keyField}`=?"; $row = Zotero_DB::rowQuery($sql, array($libraryID, $key), Zotero_Shards::getByLibraryID($libraryID)); self::cachePrimaryData($row, $libraryID, $key); return $row; }