Example #1
0
 public function itemToAtom($itemID)
 {
     if (!is_int($itemID)) {
         throw new Exception("itemID must be an integer (was " . gettype($itemID) . ")");
     }
     if (!$this->loaded) {
         $this->load();
     }
     //$groupUserData = $this->getUserData($itemID);
     $item = Zotero_Items::get($this->libraryID, $itemID);
     if (!$item) {
         throw new Exception("Item {$itemID} doesn't exist");
     }
     $xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?>' . '<entry xmlns="' . Zotero_Atom::$nsAtom . '" ' . 'xmlns:zapi="' . Zotero_Atom::$nsZoteroAPI . '" ' . 'xmlns:xfer="' . Zotero_Atom::$nsZoteroTransfer . '"/>');
     $title = $item->getDisplayTitle(true);
     $title = $title ? $title : '[Untitled]';
     // Strip HTML from note titles
     if ($item->isNote()) {
         // Clean and strip HTML, giving us an HTML-encoded plaintext string
         $title = strip_tags(Zotero_Notes::sanitize($title));
         // Unencode plaintext string
         $title = html_entity_decode($title);
     }
     $xml->title = $title;
     $author = $xml->addChild('author');
     $author->name = Zotero_Libraries::getName($item->libraryID);
     $author->uri = Zotero_URI::getLibraryURI($item->libraryID);
     $xml->id = Zotero_URI::getItemURI($item);
     $xml->published = Zotero_Date::sqlToISO8601($item->dateAdded);
     $xml->updated = Zotero_Date::sqlToISO8601($item->dateModified);
     $link = $xml->addChild("link");
     $link['rel'] = "self";
     $link['type'] = "application/atom+xml";
     $link['href'] = Zotero_API::getItemURI($item);
     $link = $xml->addChild('link');
     $link['rel'] = 'alternate';
     $link['type'] = 'text/html';
     $link['href'] = Zotero_URI::getItemURI($item, true);
     $xml->content['type'] = 'application/xml';
     $itemXML = new SimpleXMLElement('<item xmlns="' . Zotero_Atom::$nsZoteroTransfer . '"/>');
     // This method of adding the element seems to be necessary to get the
     // namespace prefix to show up
     $fNode = dom_import_simplexml($xml->content);
     $subNode = dom_import_simplexml($itemXML);
     $importedNode = $fNode->ownerDocument->importNode($subNode, true);
     $fNode->appendChild($importedNode);
     $xml->content->item['id'] = $itemID;
     return $xml;
 }
Example #2
0
	private function getNoteHash() {
		if (!$this->isNote() && !$this->isAttachment()) {
			trigger_error("getNoteHash() can only be called on notes and attachments", E_USER_ERROR);
		}
		
		if (!$this->id) {
			return '';
		}
		
		// Store access time for later garbage collection
		//$this->noteAccessTime = new Date();
		
		return Zotero_Notes::getHash($this->libraryID, $this->id);
	}
Example #3
0
 /**
  * Handle uploaded data, overwriting existing data
  */
 public function upload()
 {
     $this->sessionCheck();
     // Another session is either queued or writing — upload data won't be valid,
     // so client should wait and return to /updated with 'upload' flag
     Zotero_DB::beginTransaction();
     if (Zotero_Sync::userIsReadLocked($this->userID) || Zotero_Sync::userIsWriteLocked($this->userID)) {
         Zotero_DB::commit();
         $locked = $this->responseXML->addChild('locked');
         $locked['wait'] = $this->getWaitTime($this->sessionID);
         $this->end();
     }
     Zotero_DB::commit();
     $this->clearWaitTime($this->sessionID);
     if (empty($_REQUEST['updateKey'])) {
         $this->error(400, 'INVALID_UPLOAD_DATA', 'Update key not provided');
     }
     if ($_REQUEST['updateKey'] != Zotero_Users::getUpdateKey($this->userID)) {
         $this->e409("Server data has changed since last retrieval");
     }
     // TODO: change to POST
     if (empty($_REQUEST['data'])) {
         $this->error(400, 'MISSING_UPLOAD_DATA', 'Uploaded data not provided');
     }
     $xmldata =& $_REQUEST['data'];
     try {
         $doc = new DOMDocument();
         $doc->loadXML($xmldata, LIBXML_PARSEHUGE);
         // For huge uploads, make sure notes aren't bigger than SimpleXML can parse
         if (strlen($xmldata) > 7000000) {
             $xpath = new DOMXPath($doc);
             $results = $xpath->query('/data/items/item/note[string-length(text()) > ' . Zotero_Notes::$MAX_NOTE_LENGTH . ']');
             if ($results->length) {
                 $noteElem = $results->item(0);
                 $text = $noteElem->textContent;
                 $libraryID = $noteElem->parentNode->getAttribute('libraryID');
                 $key = $noteElem->parentNode->getAttribute('key');
                 // UTF-8 &nbsp; (0xC2 0xA0) isn't trimmed by default
                 $whitespace = chr(0x20) . chr(0x9) . chr(0xa) . chr(0xd) . chr(0x0) . chr(0xb) . chr(0xc2) . chr(0xa0);
                 $excerpt = iconv("UTF-8", "UTF-8//IGNORE", Zotero_Notes::noteToTitle(trim($text), true));
                 $excerpt = trim($excerpt, $whitespace);
                 // If tag-stripped version is empty, just return raw HTML
                 if ($excerpt == '') {
                     $excerpt = iconv("UTF-8", "UTF-8//IGNORE", preg_replace('/\\s+/', ' ', mb_substr(trim($text), 0, Zotero_Notes::$MAX_TITLE_LENGTH)));
                     $excerpt = html_entity_decode($excerpt);
                     $excerpt = trim($excerpt, $whitespace);
                 }
                 $msg = "=Note '" . $excerpt . "...' too long";
                 if ($key) {
                     $msg .= " for item '" . $libraryID . "/" . $key . "'";
                 }
                 throw new Exception($msg, Z_ERROR_NOTE_TOO_LONG);
             }
         }
     } catch (Exception $e) {
         $this->handleUploadError($e, $xmldata);
     }
     function relaxNGErrorHandler($errno, $errstr)
     {
         //Z_Core::logError($errstr);
     }
     set_error_handler('relaxNGErrorHandler');
     set_time_limit(60);
     if (!$doc->relaxNGValidate(Z_ENV_MODEL_PATH . 'relax-ng/upload.rng')) {
         $id = substr(md5(uniqid(rand(), true)), 0, 10);
         $str = date("D M j G:i:s T Y") . "\n";
         $str .= "IP address: " . $_SERVER['REMOTE_ADDR'] . "\n";
         if (isset($_SERVER['HTTP_X_ZOTERO_VERSION'])) {
             $str .= "Version: " . $_SERVER['HTTP_X_ZOTERO_VERSION'] . "\n";
         }
         $str .= "Error: RELAX NG validation failed\n\n";
         $str .= $xmldata;
         if (!file_put_contents(Z_CONFIG::$SYNC_ERROR_PATH . $id, $str)) {
             error_log("Unable to save error report to " . Z_CONFIG::$SYNC_ERROR_PATH . $id);
         }
         $this->error(500, 'INVALID_UPLOAD_DATA', "Uploaded data not well-formed (Report ID: {$id})");
     }
     restore_error_handler();
     try {
         $xml = simplexml_import_dom($doc);
         $queue = true;
         if (Z_ENV_TESTING_SITE && !empty($_GET['noqueue'])) {
             $queue = false;
         }
         if ($queue) {
             $affectedLibraries = Zotero_Sync::parseAffectedLibraries($xmldata);
             // Relations-only uploads don't have affected libraries
             if (!$affectedLibraries) {
                 $affectedLibraries = array(Zotero_Users::getLibraryIDFromUserID($this->userID));
             }
             Zotero_Sync::queueUpload($this->userID, $this->sessionID, $xmldata, $affectedLibraries);
             try {
                 Zotero_Processors::notifyProcessors('upload');
                 Zotero_Processors::notifyProcessors('error');
                 usleep(750000);
             } catch (Exception $e) {
                 Z_Core::logError($e);
             }
             // Give processor a chance to finish while we're still here
             $this->uploadstatus();
         } else {
             set_time_limit(210);
             $timestamp = Zotero_Sync::processUpload($this->userID, $xml);
             $this->responseXML['timestamp'] = $timestamp;
             $this->responseXML->addChild('uploaded');
             $this->end();
         }
     } catch (Exception $e) {
         $this->handleUploadError($e, $xmldata);
     }
 }