Beispiel #1
0
 public static function doExport($items, $format)
 {
     if (!in_array($format, self::$exportFormats)) {
         throw new Exception("Invalid export format '{$format}'");
     }
     $jsonItems = array();
     foreach ($items as $item) {
         $arr = $item->toJSON(true);
         $arr['uri'] = Zotero_URI::getItemURI($item);
         $jsonItems[] = $arr;
     }
     if (!$jsonItems) {
         return array('body' => "", 'mimeType' => "text/plain");
     }
     $json = json_encode($jsonItems);
     $servers = Z_CONFIG::$TRANSLATION_SERVERS;
     // Try servers in a random order
     shuffle($servers);
     foreach ($servers as $server) {
         $url = "http://{$server}/export?format={$format}";
         $start = microtime(true);
         $ch = curl_init($url);
         curl_setopt($ch, CURLOPT_POST, 1);
         curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
         curl_setopt($ch, CURLOPT_HTTPHEADER, array("Expect:", "Content-Type: application/json"));
         curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 1);
         curl_setopt($ch, CURLOPT_TIMEOUT, 4);
         curl_setopt($ch, CURLOPT_HEADER, 0);
         // do not return HTTP headers
         curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
         $response = curl_exec($ch);
         $time = microtime(true) - $start;
         $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
         $mimeType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
         if ($code != 200) {
             $response = null;
             Z_Core::logError("HTTP {$code} from translate server {$server} exporting items");
             Z_Core::logError($response);
             continue;
         }
         if (!$response) {
             $response = "";
         }
         break;
     }
     if ($response === null) {
         throw new Exception("Error exporting items");
     }
     $export = array('body' => $response, 'mimeType' => $mimeType);
     return $export;
 }
Beispiel #2
0
 /**
  * Converts a Zotero_Tag object to a SimpleXMLElement Atom object
  *
  * @param	object				$tag		Zotero_Tag object
  * @param	string				$content
  * @return	SimpleXMLElement					Tag data as SimpleXML element
  */
 public function toAtom($content = array('none'), $apiVersion = null, $fixedValues = null)
 {
     // TEMP: multi-format support
     $content = $content[0];
     $xml = new SimpleXMLElement('<entry xmlns="' . Zotero_Atom::$nsAtom . '" ' . 'xmlns:zapi="' . Zotero_Atom::$nsZoteroAPI . '" ' . 'xmlns:zxfer="' . Zotero_Atom::$nsZoteroTransfer . '"/>');
     $xml->title = $this->name;
     $author = $xml->addChild('author');
     $author->name = Zotero_Libraries::getName($this->libraryID);
     $author->uri = Zotero_URI::getLibraryURI($this->libraryID);
     $xml->id = Zotero_URI::getTagURI($this);
     $xml->published = Zotero_Date::sqlToISO8601($this->dateAdded);
     $xml->updated = Zotero_Date::sqlToISO8601($this->dateModified);
     $link = $xml->addChild("link");
     $link['rel'] = "self";
     $link['type'] = "application/atom+xml";
     $link['href'] = Zotero_Atom::getTagURI($this);
     $link = $xml->addChild('link');
     $link['rel'] = 'alternate';
     $link['type'] = 'text/html';
     $link['href'] = Zotero_URI::getTagURI($this);
     // Count user's linked items
     if (isset($fixedValues['numItems'])) {
         $numItems = $fixedValues['numItems'];
     } else {
         $itemIDs = $this->getLinkedItems();
         $numItems = sizeOf($itemIDs);
     }
     $xml->addChild('zapi:numItems', $numItems, Zotero_Atom::$nsZoteroAPI);
     if ($content == 'html') {
         $xml->content['type'] = 'xhtml';
         //$fullXML = Zotero_Tags::convertTagToXML($tag);
         $fullStr = "<div/>";
         $fullXML = new SimpleXMLElement($fullStr);
         $fullXML->addAttribute("xmlns", Zotero_Atom::$nsXHTML);
         $fNode = dom_import_simplexml($xml->content);
         $subNode = dom_import_simplexml($fullXML);
         $importedNode = $fNode->ownerDocument->importNode($subNode, true);
         $fNode->appendChild($importedNode);
         //$arr = $tag->serialize();
         //require_once("views/zotero/tags.php")
     } else {
         if ($content == 'full') {
             $xml->content['type'] = 'application/xml';
             $fullXML = $this->toXML();
             $fullXML->addAttribute("xmlns", Zotero_Atom::$nsZoteroTransfer);
             $fNode = dom_import_simplexml($xml->content);
             $subNode = dom_import_simplexml($fullXML);
             $importedNode = $fNode->ownerDocument->importNode($subNode, true);
             $fNode->appendChild($importedNode);
         }
     }
     return $xml;
 }
 public static function notify($event, $type, $ids, $extraData)
 {
     if (!isset(Z_CONFIG::$SNS_TOPIC_STREAM_EVENTS)) {
         error_log('WARNING: Z_CONFIG::$SNS_TOPIC_STREAM_EVENTS not set ' . '-- skipping stream notifications');
         return;
     }
     if ($type == "library") {
         switch ($event) {
             case "modify":
                 $event = "topicUpdated";
                 break;
             case "delete":
                 $event = "topicDeleted";
                 break;
             default:
                 return;
         }
         $entries = [];
         foreach ($ids as $id) {
             $libraryID = $id;
             // For most libraries, get topic from URI
             if ($event != 'topicDeleted') {
                 // Convert 'http://zotero.org/users/...' to '/users/...'
                 $topic = str_replace(Zotero_URI::getBaseURI(), "/", Zotero_URI::getLibraryURI($libraryID));
             } else {
                 $topic = '/' . Zotero_Libraries::getType($libraryID) . "s/" . Zotero_Libraries::getLibraryTypeID($libraryID);
             }
             $message = ["event" => $event, "topic" => $topic];
             if (!empty($extraData[$id])) {
                 foreach ($extraData[$id] as $key => $val) {
                     $message[$key] = $val;
                 }
             }
             foreach (self::$messageReceivers as $receiver) {
                 $receiver(Z_CONFIG::$SNS_TOPIC_STREAM_EVENTS, json_encode($message, JSON_UNESCAPED_SLASHES));
             }
         }
     } else {
         if ($type == "apikey-library") {
             switch ($event) {
                 case "add":
                     $event = "topicAdded";
                     break;
                 case "remove":
                     $event = "topicRemoved";
                     break;
                 default:
                     return;
             }
             $entries = [];
             foreach ($ids as $id) {
                 list($apiKey, $libraryID) = explode("-", $id);
                 // Get topic from URI
                 $topic = str_replace(Zotero_URI::getBaseURI(), "/", Zotero_URI::getLibraryURI($libraryID));
                 $message = ["event" => $event, "apiKey" => $apiKey, "topic" => $topic];
                 if (!empty($extraData[$id])) {
                     foreach ($extraData[$id] as $key => $val) {
                         $message[$key] = $val;
                     }
                 }
                 self::send($message);
             }
         }
     }
 }
Beispiel #4
0
 public static function toJSON($libraryID)
 {
     // TODO: cache
     $libraryType = Zotero_Libraries::getType($libraryID);
     if ($libraryType == 'user') {
         $objectUserID = Zotero_Users::getUserIDFromLibraryID($libraryID);
         $json = ['type' => $libraryType, 'id' => $objectUserID, 'name' => self::getName($libraryID), 'links' => ['alternate' => ['href' => Zotero_URI::getUserURI($objectUserID, true), 'type' => 'text/html']]];
     } else {
         if ($libraryType == 'publications') {
             $objectUserID = Zotero_Users::getUserIDFromLibraryID($libraryID);
             $json = ['type' => $libraryType, 'id' => $objectUserID, 'name' => self::getName($libraryID), 'links' => ['alternate' => ['href' => Zotero_URI::getUserURI($objectUserID, true) . "/publications", 'type' => 'text/html']]];
         } else {
             if ($libraryType == 'group') {
                 $objectGroupID = Zotero_Groups::getGroupIDFromLibraryID($libraryID);
                 $group = Zotero_Groups::get($objectGroupID);
                 $json = ['type' => $libraryType, 'id' => $objectGroupID, 'name' => self::getName($libraryID), 'links' => ['alternate' => ['href' => Zotero_URI::getGroupURI($group, true), 'type' => 'text/html']]];
             } else {
                 throw new Exception("Invalid library type '{$libraryType}'");
             }
         }
     }
     return $json;
 }
Beispiel #5
0
 /**
  * Generate a SimpleXMLElement Atom object for the search
  *
  * @param array $queryParams
  * @return SimpleXMLElement
  */
 public function toAtom($queryParams)
 {
     if (!$this->loaded) {
         $this->load();
     }
     // TEMP: multi-format support
     if (!empty($queryParams['content'])) {
         $content = $queryParams['content'];
     } else {
         $content = array('none');
     }
     $content = $content[0];
     $xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?>' . '<entry xmlns="' . Zotero_Atom::$nsAtom . '" xmlns:zapi="' . Zotero_Atom::$nsZoteroAPI . '"/>');
     $xml->title = $this->name ? $this->name : '[Untitled]';
     $author = $xml->addChild('author');
     // TODO: group item creator
     $author->name = Zotero_Libraries::getName($this->libraryID);
     $author->uri = Zotero_URI::getLibraryURI($this->libraryID, true);
     $xml->id = Zotero_URI::getSearchURI($this);
     $xml->published = Zotero_Date::sqlToISO8601($this->dateAdded);
     $xml->updated = Zotero_Date::sqlToISO8601($this->dateModified);
     $link = $xml->addChild("link");
     $link['rel'] = "self";
     $link['type'] = "application/atom+xml";
     $link['href'] = Zotero_API::getSearchURI($this);
     $xml->addChild('zapi:key', $this->key, Zotero_Atom::$nsZoteroAPI);
     $xml->addChild('zapi:version', $this->version, Zotero_Atom::$nsZoteroAPI);
     if ($content == 'json') {
         $xml->content['type'] = 'application/json';
         $xml->content = Zotero_Utilities::formatJSON($this->toJSON($queryParams));
     }
     return $xml;
 }
Beispiel #6
0
 public function toResponseJSON($requestParams = [])
 {
     $t = microtime(true);
     // Child collections and items can't be cached (easily)
     $numCollections = $this->numCollections();
     $numItems = $this->numItems();
     if (!$requestParams['uncached']) {
         $cacheKey = $this->getCacheKey($requestParams);
         $cached = Z_Core::$MC->get($cacheKey);
         if ($cached) {
             Z_Core::debug("Using cached JSON for {$this->libraryKey}");
             $cached['meta']->numCollections = $numCollections;
             $cached['meta']->numItems = $numItems;
             StatsD::timing("api.collections.toResponseJSON.cached", (microtime(true) - $t) * 1000);
             StatsD::increment("memcached.collections.toResponseJSON.hit");
             return $cached;
         }
     }
     $json = ['key' => $this->key, 'version' => $this->version, 'library' => Zotero_Libraries::toJSON($this->libraryID)];
     // 'links'
     $json['links'] = ['self' => ['href' => Zotero_API::getCollectionURI($this), 'type' => 'application/json'], 'alternate' => ['href' => Zotero_URI::getCollectionURI($this, true), 'type' => 'text/html']];
     $parentID = $this->getParentID();
     if ($parentID) {
         $parentCol = Zotero_Collections::get($this->libraryID, $parentID);
         $json['links']['up'] = ['href' => Zotero_API::getCollectionURI($parentCol), 'type' => "application/atom+xml"];
     }
     // 'meta'
     $json['meta'] = new stdClass();
     $json['meta']->numCollections = $numCollections;
     $json['meta']->numItems = $numItems;
     // 'include'
     $include = $requestParams['include'];
     foreach ($include as $type) {
         if ($type == 'data') {
             $json[$type] = $this->toJSON($requestParams);
         }
     }
     if (!$requestParams['uncached']) {
         Z_Core::$MC->set($cacheKey, $json);
         StatsD::timing("api.collections.toResponseJSON.uncached", (microtime(true) - $t) * 1000);
         StatsD::increment("memcached.collections.toResponseJSON.miss");
     }
     return $json;
 }
 /**
  * Converts a Zotero_Collection object to a SimpleXMLElement Atom object
  *
  * @param	object				$item		Zotero_Collection object
  * @param	string				$content
  * @return	SimpleXMLElement					Collection data as SimpleXML element
  */
 public static function convertCollectionToAtom(Zotero_Collection $collection, $content = array('none'))
 {
     // TEMP: multi-format support
     $content = $content[0];
     $xml = new SimpleXMLElement('<entry xmlns="' . Zotero_Atom::$nsAtom . '" xmlns:zapi="' . Zotero_Atom::$nsZoteroAPI . '"/>');
     $title = $collection->name ? $collection->name : '[Untitled]';
     $xml->title = $title;
     $author = $xml->addChild('author');
     // TODO: group item creator
     $author->name = Zotero_Libraries::getName($collection->libraryID);
     $author->uri = Zotero_URI::getLibraryURI($collection->libraryID);
     $xml->id = Zotero_URI::getCollectionURI($collection);
     $xml->published = Zotero_Date::sqlToISO8601($collection->dateAdded);
     $xml->updated = Zotero_Date::sqlToISO8601($collection->dateModified);
     $link = $xml->addChild("link");
     $link['rel'] = "self";
     $link['type'] = "application/atom+xml";
     $link['href'] = Zotero_Atom::getCollectionURI($collection);
     $parent = $collection->parent;
     if ($parent) {
         $parentCol = self::get($collection->libraryID, $parent);
         $link = $xml->addChild("link");
         $link['rel'] = "up";
         $link['type'] = "application/atom+xml";
         $link['href'] = Zotero_Atom::getCollectionURI($parentCol);
     }
     $link = $xml->addChild('link');
     $link['rel'] = 'alternate';
     $link['type'] = 'text/html';
     $link['href'] = Zotero_URI::getCollectionURI($collection);
     $xml->addChild('zapi:key', $collection->key, Zotero_Atom::$nsZoteroAPI);
     $collections = $collection->getChildCollections();
     $xml->addChild('zapi:numCollections', sizeOf($collections), Zotero_Atom::$nsZoteroAPI);
     $xml->addChild('zapi:numItems', $collection->numItems(), Zotero_Atom::$nsZoteroAPI);
     if ($content == 'json') {
         $xml->content['type'] = 'application/json';
         $xml->content->addAttribute('zapi:etag', $collection->etag, Zotero_Atom::$nsZoteroAPI);
         // TODO: remove non-namespaced attribute
         $xml->content['etag'] = $collection->etag;
         $xml->content = $collection->toJSON();
     } else {
         if ($content == 'full') {
             $xml->content['type'] = 'application/xml';
             $fullXML = Zotero_Collections::convertCollectionToXML($collection);
             $fullXML->addAttribute("xmlns", Zotero_Atom::$nsZoteroTransfer);
             $fNode = dom_import_simplexml($xml->content);
             $subNode = dom_import_simplexml($fullXML);
             $importedNode = $fNode->ownerDocument->importNode($subNode, true);
             $fNode->appendChild($importedNode);
         }
     }
     return $xml;
 }
Beispiel #8
0
 /**
  * Converts a Zotero_Item object to a SimpleXMLElement Atom object
  *
  * Note: Increment Z_CONFIG::$CACHE_VERSION_ATOM_ENTRY when changing
  * the response.
  *
  * @param	object				$item		Zotero_Item object
  * @param	string				$content
  * @return	SimpleXMLElement					Item data as SimpleXML element
  */
 public static function convertItemToAtom(Zotero_Item $item, $queryParams, $permissions, $sharedData = null)
 {
     $t = microtime(true);
     // Uncached stuff or parts of the cache key
     $version = $item->version;
     $parent = $item->getSource();
     $isRegularItem = !$parent && $item->isRegularItem();
     $downloadDetails = $permissions->canAccess($item->libraryID, 'files') ? Zotero_Storage::getDownloadDetails($item) : false;
     if ($isRegularItem) {
         $numChildren = $permissions->canAccess($item->libraryID, 'notes') ? $item->numChildren() : $item->numAttachments();
     }
     // <id> changes based on group visibility in v1
     if ($queryParams['v'] < 2) {
         $id = Zotero_URI::getItemURI($item, false, true);
     } else {
         $id = Zotero_URI::getItemURI($item);
     }
     $libraryType = Zotero_Libraries::getType($item->libraryID);
     // Any query parameters that have an effect on the output
     // need to be added here
     $allowedParams = array('content', 'style', 'css', 'linkwrap');
     $cachedParams = Z_Array::filterKeys($queryParams, $allowedParams);
     $cacheVersion = 2;
     $cacheKey = "atomEntry_" . $item->libraryID . "/" . $item->id . "_" . md5($version . json_encode($cachedParams) . ($downloadDetails ? 'hasFile' : '') . ($libraryType == 'group' ? 'id' . $id : '')) . "_" . $queryParams['v'] . "_" . $cacheVersion . (isset(Z_CONFIG::$CACHE_VERSION_ATOM_ENTRY) ? "_" . Z_CONFIG::$CACHE_VERSION_ATOM_ENTRY : "") . (in_array('bib', $queryParams['content']) && isset(Z_CONFIG::$CACHE_VERSION_BIB) ? "_" . Z_CONFIG::$CACHE_VERSION_BIB : "");
     $xmlstr = Z_Core::$MC->get($cacheKey);
     if ($xmlstr) {
         try {
             // TEMP: Strip control characters
             $xmlstr = Zotero_Utilities::cleanString($xmlstr, true);
             $doc = new DOMDocument();
             $doc->loadXML($xmlstr);
             $xpath = new DOMXpath($doc);
             $xpath->registerNamespace('atom', Zotero_Atom::$nsAtom);
             $xpath->registerNamespace('zapi', Zotero_Atom::$nsZoteroAPI);
             $xpath->registerNamespace('xhtml', Zotero_Atom::$nsXHTML);
             // Make sure numChildren reflects the current permissions
             if ($isRegularItem) {
                 $xpath->query('/atom:entry/zapi:numChildren')->item(0)->nodeValue = $numChildren;
             }
             // To prevent PHP from messing with namespace declarations,
             // we have to extract, remove, and then add back <content>
             // subelements. Otherwise the subelements become, say,
             // <default:span xmlns="http://www.w3.org/1999/xhtml"> instead
             // of just <span xmlns="http://www.w3.org/1999/xhtml">, and
             // xmlns:default="http://www.w3.org/1999/xhtml" gets added to
             // the parent <entry>. While you might reasonably think that
             //
             // echo $xml->saveXML();
             //
             // and
             //
             // $xml = new SimpleXMLElement($xml->saveXML());
             // echo $xml->saveXML();
             //
             // would be identical, you would be wrong.
             $multiFormat = !!$xpath->query('/atom:entry/atom:content/zapi:subcontent')->length;
             $contentNodes = array();
             if ($multiFormat) {
                 $contentNodes = $xpath->query('/atom:entry/atom:content/zapi:subcontent');
             } else {
                 $contentNodes = $xpath->query('/atom:entry/atom:content');
             }
             foreach ($contentNodes as $contentNode) {
                 $contentParts = array();
                 while ($contentNode->hasChildNodes()) {
                     $contentParts[] = $doc->saveXML($contentNode->firstChild);
                     $contentNode->removeChild($contentNode->firstChild);
                 }
                 foreach ($contentParts as $part) {
                     if (!trim($part)) {
                         continue;
                     }
                     // Strip the namespace and add it back via SimpleXMLElement,
                     // which keeps it from being changed later
                     if (preg_match('%^<[^>]+xmlns="http://www.w3.org/1999/xhtml"%', $part)) {
                         $part = preg_replace('%^(<[^>]+)xmlns="http://www.w3.org/1999/xhtml"%', '$1', $part);
                         $html = new SimpleXMLElement($part);
                         $html['xmlns'] = "http://www.w3.org/1999/xhtml";
                         $subNode = dom_import_simplexml($html);
                         $importedNode = $doc->importNode($subNode, true);
                         $contentNode->appendChild($importedNode);
                     } else {
                         if (preg_match('%^<[^>]+xmlns="http://zotero.org/ns/transfer"%', $part)) {
                             $part = preg_replace('%^(<[^>]+)xmlns="http://zotero.org/ns/transfer"%', '$1', $part);
                             $html = new SimpleXMLElement($part);
                             $html['xmlns'] = "http://zotero.org/ns/transfer";
                             $subNode = dom_import_simplexml($html);
                             $importedNode = $doc->importNode($subNode, true);
                             $contentNode->appendChild($importedNode);
                         } else {
                             $docFrag = $doc->createDocumentFragment();
                             $docFrag->appendXML($part);
                             $contentNode->appendChild($docFrag);
                         }
                     }
                 }
             }
             $xml = simplexml_import_dom($doc);
             StatsD::timing("api.items.itemToAtom.cached", (microtime(true) - $t) * 1000);
             StatsD::increment("memcached.items.itemToAtom.hit");
             // Skip the cache every 10 times for now, to ensure cache sanity
             if (Z_Core::probability(10)) {
                 $xmlstr = $xml->saveXML();
             } else {
                 return $xml;
             }
         } catch (Exception $e) {
             error_log($xmlstr);
             error_log("WARNING: " . $e);
         }
     }
     $content = $queryParams['content'];
     $contentIsHTML = sizeOf($content) == 1 && $content[0] == 'html';
     $contentParamString = urlencode(implode(',', $content));
     $style = $queryParams['style'];
     $entry = '<?xml version="1.0" encoding="UTF-8"?>' . '<entry xmlns="' . Zotero_Atom::$nsAtom . '" xmlns:zapi="' . Zotero_Atom::$nsZoteroAPI . '"/>';
     $xml = new SimpleXMLElement($entry);
     $title = $item->getDisplayTitle(true);
     $title = $title ? $title : '[Untitled]';
     $xml->title = $title;
     $author = $xml->addChild('author');
     $createdByUserID = null;
     $lastModifiedByUserID = null;
     switch (Zotero_Libraries::getType($item->libraryID)) {
         case 'group':
             $createdByUserID = $item->createdByUserID;
             // Used for zapi:lastModifiedByUser below
             $lastModifiedByUserID = $item->lastModifiedByUserID;
             break;
     }
     if ($createdByUserID) {
         $author->name = Zotero_Users::getUsername($createdByUserID);
         $author->uri = Zotero_URI::getUserURI($createdByUserID);
     } else {
         $author->name = Zotero_Libraries::getName($item->libraryID);
         $author->uri = Zotero_URI::getLibraryURI($item->libraryID);
     }
     $xml->id = $id;
     $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";
     $href = Zotero_API::getItemURI($item);
     if (!$contentIsHTML) {
         $href .= "?content={$contentParamString}";
     }
     $link['href'] = $href;
     if ($parent) {
         // TODO: handle group items?
         $parentItem = Zotero_Items::get($item->libraryID, $parent);
         $link = $xml->addChild("link");
         $link['rel'] = "up";
         $link['type'] = "application/atom+xml";
         $href = Zotero_API::getItemURI($parentItem);
         if (!$contentIsHTML) {
             $href .= "?content={$contentParamString}";
         }
         $link['href'] = $href;
     }
     $link = $xml->addChild('link');
     $link['rel'] = 'alternate';
     $link['type'] = 'text/html';
     $link['href'] = Zotero_URI::getItemURI($item, true);
     // If appropriate permissions and the file is stored in ZFS, get file request link
     if ($downloadDetails) {
         $details = $downloadDetails;
         $link = $xml->addChild('link');
         $link['rel'] = 'enclosure';
         $type = $item->attachmentMIMEType;
         if ($type) {
             $link['type'] = $type;
         }
         $link['href'] = $details['url'];
         if (!empty($details['filename'])) {
             $link['title'] = $details['filename'];
         }
         if (isset($details['size'])) {
             $link['length'] = $details['size'];
         }
     }
     $xml->addChild('zapi:key', $item->key, Zotero_Atom::$nsZoteroAPI);
     $xml->addChild('zapi:version', $item->version, Zotero_Atom::$nsZoteroAPI);
     if ($lastModifiedByUserID) {
         $xml->addChild('zapi:lastModifiedByUser', Zotero_Users::getUsername($lastModifiedByUserID), Zotero_Atom::$nsZoteroAPI);
     }
     $xml->addChild('zapi:itemType', Zotero_ItemTypes::getName($item->itemTypeID), Zotero_Atom::$nsZoteroAPI);
     if ($isRegularItem) {
         $val = $item->creatorSummary;
         if ($val !== '') {
             $xml->addChild('zapi:creatorSummary', htmlspecialchars($val), Zotero_Atom::$nsZoteroAPI);
         }
         $val = $item->getField('date', true, true, true);
         if ($val !== '') {
             if ($queryParams['v'] < 3) {
                 $val = substr($val, 0, 4);
                 if ($val !== '0000') {
                     $xml->addChild('zapi:year', $val, Zotero_Atom::$nsZoteroAPI);
                 }
             } else {
                 $sqlDate = Zotero_Date::multipartToSQL($val);
                 if (substr($sqlDate, 0, 4) !== '0000') {
                     $xml->addChild('zapi:parsedDate', Zotero_Date::sqlToISO8601($sqlDate), Zotero_Atom::$nsZoteroAPI);
                 }
             }
         }
         $xml->addChild('zapi:numChildren', $numChildren, Zotero_Atom::$nsZoteroAPI);
     }
     if ($queryParams['v'] < 3) {
         $xml->addChild('zapi:numTags', $item->numTags(), Zotero_Atom::$nsZoteroAPI);
     }
     $xml->content = '';
     //
     // DOM XML from here on out
     //
     $contentNode = dom_import_simplexml($xml->content);
     $domDoc = $contentNode->ownerDocument;
     $multiFormat = sizeOf($content) > 1;
     // Create a root XML document for multi-format responses
     if ($multiFormat) {
         $contentNode->setAttribute('type', 'application/xml');
         /*$multicontent = $domDoc->createElementNS(
         			Zotero_Atom::$nsZoteroAPI, 'multicontent'
         		);
         		$contentNode->appendChild($multicontent);*/
     }
     foreach ($content as $type) {
         // Set the target to either the main <content>
         // or a <multicontent> <content>
         if (!$multiFormat) {
             $target = $contentNode;
         } else {
             $target = $domDoc->createElementNS(Zotero_Atom::$nsZoteroAPI, 'subcontent');
             $contentNode->appendChild($target);
         }
         $target->setAttributeNS(Zotero_Atom::$nsZoteroAPI, "zapi:type", $type);
         if ($type == 'html') {
             if (!$multiFormat) {
                 $target->setAttribute('type', 'xhtml');
             }
             $div = $domDoc->createElementNS(Zotero_Atom::$nsXHTML, 'div');
             $target->appendChild($div);
             $html = $item->toHTML(true);
             $subNode = dom_import_simplexml($html);
             $importedNode = $domDoc->importNode($subNode, true);
             $div->appendChild($importedNode);
         } else {
             if ($type == 'citation') {
                 if (!$multiFormat) {
                     $target->setAttribute('type', 'xhtml');
                 }
                 if (isset($sharedData[$type][$item->libraryID . "/" . $item->key])) {
                     $html = $sharedData[$type][$item->libraryID . "/" . $item->key];
                 } else {
                     if ($sharedData !== null) {
                         //error_log("Citation not found in sharedData -- retrieving individually");
                     }
                     $html = Zotero_Cite::getCitationFromCiteServer($item, $queryParams);
                 }
                 $html = new SimpleXMLElement($html);
                 $html['xmlns'] = Zotero_Atom::$nsXHTML;
                 $subNode = dom_import_simplexml($html);
                 $importedNode = $domDoc->importNode($subNode, true);
                 $target->appendChild($importedNode);
             } else {
                 if ($type == 'bib') {
                     if (!$multiFormat) {
                         $target->setAttribute('type', 'xhtml');
                     }
                     if (isset($sharedData[$type][$item->libraryID . "/" . $item->key])) {
                         $html = $sharedData[$type][$item->libraryID . "/" . $item->key];
                     } else {
                         if ($sharedData !== null) {
                             //error_log("Bibliography not found in sharedData -- retrieving individually");
                         }
                         $html = Zotero_Cite::getBibliographyFromCitationServer(array($item), $queryParams);
                     }
                     $html = new SimpleXMLElement($html);
                     $html['xmlns'] = Zotero_Atom::$nsXHTML;
                     $subNode = dom_import_simplexml($html);
                     $importedNode = $domDoc->importNode($subNode, true);
                     $target->appendChild($importedNode);
                 } else {
                     if ($type == 'json') {
                         if ($queryParams['v'] < 2) {
                             $target->setAttributeNS(Zotero_Atom::$nsZoteroAPI, "zapi:etag", $item->etag);
                         }
                         $textNode = $domDoc->createTextNode($item->toJSON(false, $queryParams, true));
                         $target->appendChild($textNode);
                     } else {
                         if ($type == 'csljson') {
                             $arr = $item->toCSLItem();
                             $json = Zotero_Utilities::formatJSON($arr);
                             $textNode = $domDoc->createTextNode($json);
                             $target->appendChild($textNode);
                         } else {
                             if (in_array($type, Zotero_Translate::$exportFormats)) {
                                 $export = Zotero_Translate::doExport(array($item), $type);
                                 $target->setAttribute('type', $export['mimeType']);
                                 // Insert XML into document
                                 if (preg_match('/\\+xml$/', $export['mimeType'])) {
                                     // Strip prolog
                                     $body = preg_replace('/^<\\?xml.+\\n/', "", $export['body']);
                                     $subNode = $domDoc->createDocumentFragment();
                                     $subNode->appendXML($body);
                                     $target->appendChild($subNode);
                                 } else {
                                     $textNode = $domDoc->createTextNode($export['body']);
                                     $target->appendChild($textNode);
                                 }
                             }
                         }
                     }
                 }
             }
         }
     }
     // TEMP
     if ($xmlstr) {
         $uncached = $xml->saveXML();
         if ($xmlstr != $uncached) {
             $uncached = str_replace('<zapi:year></zapi:year>', '<zapi:year/>', $uncached);
             $uncached = str_replace('<content zapi:type="none"></content>', '<content zapi:type="none"/>', $uncached);
             $uncached = str_replace('<zapi:subcontent zapi:type="coins" type="text/html"></zapi:subcontent>', '<zapi:subcontent zapi:type="coins" type="text/html"/>', $uncached);
             $uncached = str_replace('<title></title>', '<title/>', $uncached);
             $uncached = str_replace('<note></note>', '<note/>', $uncached);
             $uncached = str_replace('<path></path>', '<path/>', $uncached);
             $uncached = str_replace('<td></td>', '<td/>', $uncached);
             if ($xmlstr != $uncached) {
                 error_log("Cached Atom item entry does not match");
                 error_log("  Cached: " . $xmlstr);
                 error_log("Uncached: " . $uncached);
                 Z_Core::$MC->set($cacheKey, $uncached, 3600);
                 // 1 hour for now
             }
         }
     } else {
         $xmlstr = $xml->saveXML();
         Z_Core::$MC->set($cacheKey, $xmlstr, 3600);
         // 1 hour for now
         StatsD::timing("api.items.itemToAtom.uncached", (microtime(true) - $t) * 1000);
         StatsD::increment("memcached.items.itemToAtom.miss");
     }
     return $xml;
 }
Beispiel #9
0
 /**
  * Converts a Zotero_Collection object to a SimpleXMLElement Atom object
  *
  * @param Zotero_Collection  $collection  Zotero_Collection object
  * @param array  $requestParams
  * @return SimpleXMLElement  Collection data as SimpleXML element
  */
 public static function convertCollectionToAtom(Zotero_Collection $collection, $requestParams)
 {
     // TEMP: multi-format support
     if (!empty($requestParams['content'])) {
         $content = $requestParams['content'];
     } else {
         $content = array('none');
     }
     $content = $content[0];
     $xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?>' . '<entry xmlns="' . Zotero_Atom::$nsAtom . '" xmlns:zapi="' . Zotero_Atom::$nsZoteroAPI . '"/>');
     $title = $collection->name ? $collection->name : '[Untitled]';
     $xml->title = $title;
     $author = $xml->addChild('author');
     // TODO: group item creator
     $author->name = Zotero_Libraries::getName($collection->libraryID);
     $author->uri = Zotero_URI::getLibraryURI($collection->libraryID, true);
     $xml->id = Zotero_URI::getCollectionURI($collection);
     $xml->published = Zotero_Date::sqlToISO8601($collection->dateAdded);
     $xml->updated = Zotero_Date::sqlToISO8601($collection->dateModified);
     $link = $xml->addChild("link");
     $link['rel'] = "self";
     $link['type'] = "application/atom+xml";
     $link['href'] = Zotero_API::getCollectionURI($collection);
     $parent = $collection->parent;
     if ($parent) {
         $parentCol = self::get($collection->libraryID, $parent);
         $link = $xml->addChild("link");
         $link['rel'] = "up";
         $link['type'] = "application/atom+xml";
         $link['href'] = Zotero_API::getCollectionURI($parentCol);
     }
     $link = $xml->addChild('link');
     $link['rel'] = 'alternate';
     $link['type'] = 'text/html';
     $link['href'] = Zotero_URI::getCollectionURI($collection, true);
     $xml->addChild('zapi:key', $collection->key, Zotero_Atom::$nsZoteroAPI);
     $xml->addChild('zapi:version', $collection->version, Zotero_Atom::$nsZoteroAPI);
     $collections = $collection->getChildCollections();
     $xml->addChild('zapi:numCollections', sizeOf($collections), Zotero_Atom::$nsZoteroAPI);
     $xml->addChild('zapi:numItems', $collection->numItems(), Zotero_Atom::$nsZoteroAPI);
     if ($content == 'json') {
         $xml->content['type'] = 'application/json';
         // Deprecated
         if ($requestParams['v'] < 2) {
             $xml->content->addAttribute('zapi:etag', $collection->etag, Zotero_Atom::$nsZoteroAPI);
             $xml->content['etag'] = $collection->etag;
         }
         $xml->content = Zotero_Utilities::formatJSON($collection->toJSON($requestParams));
     }
     return $xml;
 }
Beispiel #10
0
 public static function purge($libraryID)
 {
     $sql = "SELECT subject FROM relations " . "WHERE libraryID=? AND predicate!=? " . "UNION " . "SELECT object FROM relations " . "WHERE libraryID=? AND predicate!=?";
     $uris = Zotero . DB . columnQuery($sql, array($libraryID, self::$deletedItemPredicate, $libraryID, self::$deletedItemPredicate), Zotero_Shards::getByLibraryID($libraryID));
     if ($uris) {
         $prefix = Zotero_URI::getBaseURI();
         Zotero_DB::beginTransaction();
         foreach ($uris as $uri) {
             // Skip URIs that don't begin with the default prefix,
             // since they don't correspond to local items
             if (strpos($uri, $prefix) === false) {
                 continue;
             }
             if (preg_match('/\\/items\\//', $uri) && !Zotero_URI::getURIItem($uri)) {
                 self::eraseByURI($uri);
             }
             if (preg_match('/\\/collections\\//', $uri) && !Zotero_URI::getURICollection($uri)) {
                 self::eraseByURI($uri);
             }
         }
         Zotero_DB::commit();
     }
 }
Beispiel #11
0
 /**
  * Converts a Zotero_Tag object to a SimpleXMLElement Atom object
  *
  * @return	SimpleXMLElement					Tag data as SimpleXML element
  */
 public function toAtom($queryParams, $fixedValues = null)
 {
     if (!empty($queryParams['content'])) {
         $content = $queryParams['content'];
     } else {
         $content = array('none');
     }
     // TEMP: multi-format support
     $content = $content[0];
     $xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?>' . '<entry xmlns="' . Zotero_Atom::$nsAtom . '" xmlns:zapi="' . Zotero_Atom::$nsZoteroAPI . '"/>');
     $xml->title = $this->name;
     $author = $xml->addChild('author');
     $author->name = Zotero_Libraries::getName($this->libraryID);
     $author->uri = Zotero_URI::getLibraryURI($this->libraryID, true);
     $xml->id = Zotero_URI::getTagURI($this);
     $xml->published = Zotero_Date::sqlToISO8601($this->dateAdded);
     $xml->updated = Zotero_Date::sqlToISO8601($this->dateModified);
     $link = $xml->addChild("link");
     $link['rel'] = "self";
     $link['type'] = "application/atom+xml";
     $link['href'] = Zotero_API::getTagURI($this);
     $link = $xml->addChild('link');
     $link['rel'] = 'alternate';
     $link['type'] = 'text/html';
     $link['href'] = Zotero_URI::getTagURI($this, true);
     // Count user's linked items
     if (isset($fixedValues['numItems'])) {
         $numItems = $fixedValues['numItems'];
     } else {
         $numItems = sizeOf($this->getLinkedItems(true));
     }
     $xml->addChild('zapi:numItems', $numItems, Zotero_Atom::$nsZoteroAPI);
     if ($content == 'html') {
         $xml->content['type'] = 'xhtml';
         $contentXML = new SimpleXMLElement("<div/>");
         $contentXML->addAttribute("xmlns", Zotero_Atom::$nsXHTML);
         $fNode = dom_import_simplexml($xml->content);
         $subNode = dom_import_simplexml($contentXML);
         $importedNode = $fNode->ownerDocument->importNode($subNode, true);
         $fNode->appendChild($importedNode);
     } else {
         if ($content == 'json') {
             $xml->content['type'] = 'application/json';
             $xml->content = Zotero_Utilities::formatJSON($this->toJSON());
         }
     }
     return $xml;
 }
Beispiel #12
0
 public static function toJSON($userID)
 {
     $realName = Zotero_Users::getRealName($userID);
     $json = ['id' => $userID, 'username' => Zotero_Users::getUsername($userID), 'name' => $realName !== false ? $realName : ""];
     $json['links'] = ['alternate' => ['href' => Zotero_URI::getUserURI($userID, true), 'type' => 'text/html']];
     return $json;
 }
Beispiel #13
0
 public static function createAtomFeed($action, $title, $url, $entries, $totalResults = null, $queryParams = [], Zotero_Permissions $permissions = null, $fixedValues = array())
 {
     if ($queryParams) {
         $nonDefaultParams = Zotero_API::getNonDefaultParams($action, $queryParams);
     } else {
         $nonDefaultParams = [];
     }
     $feed = '<?xml version="1.0" encoding="UTF-8"?>' . '<feed xmlns="' . Zotero_Atom::$nsAtom . '" ' . 'xmlns:zapi="' . Zotero_Atom::$nsZoteroAPI . '"/>';
     $xml = new SimpleXMLElement($feed);
     $xml->title = $title;
     $path = parse_url($url, PHP_URL_PATH);
     // Generate canonical URI
     $zoteroURI = Zotero_URI::getBaseURI() . substr($path, 1) . Zotero_API::buildQueryString($queryParams['v'], $action, $nonDefaultParams, ['v']);
     $baseURI = Zotero_API::getBaseURI() . substr($path, 1);
     // API version isn't included in URLs (as with the API key)
     //
     // It could alternatively be made a private parameter so that it didn't appear
     // in the Link header either, but for now it's still there.
     $excludeParams = ['v'];
     $links = Zotero_API::buildLinks($action, $path, $totalResults, $queryParams, $nonDefaultParams, $excludeParams);
     $xml->id = $zoteroURI;
     $link = $xml->addChild("link");
     $link['rel'] = "self";
     $link['type'] = "application/atom+xml";
     $link['href'] = $links['self'];
     $link = $xml->addChild("link");
     $link['rel'] = "first";
     $link['type'] = "application/atom+xml";
     $link['href'] = $links['first'];
     if (isset($links['next'])) {
         $link = $xml->addChild("link");
         $link['rel'] = "next";
         $link['type'] = "application/atom+xml";
         $link['href'] = $links['next'];
     }
     $link = $xml->addChild("link");
     $link['rel'] = "last";
     $link['type'] = "application/atom+xml";
     $link['href'] = $links['last'];
     // Generate alternate URI
     $link = $xml->addChild("link");
     $link['rel'] = "alternate";
     $link['type'] = "text/html";
     $link['href'] = $links['alternate'];
     if ($queryParams['v'] < 3) {
         $xml->addChild("zapi:totalResults", is_numeric($totalResults) ? $totalResults : sizeOf($entries), self::$nsZoteroAPI);
     }
     if ($queryParams['v'] < 2) {
         $xml->addChild("zapi:apiVersion", 1, self::$nsZoteroAPI);
     }
     $latestUpdated = '';
     // Check memcached for bib data
     $sharedData = array();
     if ($entries && $entries[0] instanceof Zotero_Item) {
         if (in_array('citation', $queryParams['content'])) {
             $sharedData["citation"] = Zotero_Cite::multiGetFromMemcached("citation", $entries, $queryParams);
         }
         if (in_array('bib', $queryParams['content'])) {
             $sharedData["bib"] = Zotero_Cite::multiGetFromMemcached("bib", $entries, $queryParams);
         }
     }
     $xmlEntries = array();
     foreach ($entries as $entry) {
         if ($entry->dateModified > $latestUpdated) {
             $latestUpdated = $entry->dateModified;
         }
         if ($entry instanceof SimpleXMLElement) {
             $xmlEntries[] = $entry;
         } else {
             if ($entry instanceof Zotero_Collection) {
                 $entry = Zotero_Collections::convertCollectionToAtom($entry, $queryParams);
                 $xmlEntries[] = $entry;
             } else {
                 if ($entry instanceof Zotero_Item) {
                     $entry = Zotero_Items::convertItemToAtom($entry, $queryParams, $permissions, $sharedData);
                     $xmlEntries[] = $entry;
                 } else {
                     if ($entry instanceof Zotero_Search) {
                         $entry = $entry->toAtom($queryParams);
                         $xmlEntries[] = $entry;
                     } else {
                         if ($entry instanceof Zotero_Tag) {
                             $xmlEntries[] = $entry->toAtom($queryParams, isset($fixedValues[$entry->id]) ? $fixedValues[$entry->id] : null);
                         } else {
                             if ($entry instanceof Zotero_Group) {
                                 $entry = $entry->toAtom($queryParams);
                                 $xmlEntries[] = $entry;
                             }
                         }
                     }
                 }
             }
         }
     }
     if ($latestUpdated) {
         $xml->updated = Zotero_Date::sqlToISO8601($latestUpdated);
     } else {
         $xml->updated = str_replace("+00:00", "Z", date('c'));
     }
     // Import object XML nodes into document
     $doc = dom_import_simplexml($xml);
     foreach ($xmlEntries as $xmlEntry) {
         $subNode = dom_import_simplexml($xmlEntry);
         $importedNode = $doc->ownerDocument->importNode($subNode, true);
         $doc->appendChild($importedNode);
     }
     return $xml;
 }
Beispiel #14
0
 public static function delete($libraryID, $key)
 {
     $table = self::$table;
     $type = self::$objectType;
     $types = self::$objectTypePlural;
     if (!$key) {
         throw new Exception("Invalid key {$key}");
     }
     // Get object (and trigger caching)
     $obj = self::getByLibraryAndKey($libraryID, $key);
     if (!$obj) {
         return;
     }
     self::editCheck($obj);
     Z_Core::debug("Deleting {$type} {$libraryID}/{$key}", 4);
     $shardID = Zotero_Shards::getByLibraryID($libraryID);
     Zotero_DB::beginTransaction();
     // 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) {
                     self::delete($child->libraryID, $child->key);
                 }
             }
         }
         // Remove relations (except for merge tracker)
         $uri = Zotero_URI::getItemURI($obj);
         Zotero_Relations::eraseByURI($libraryID, $uri, array(Zotero_Relations::$deletedItemPredicate));
     } else {
         if ($type == 'tag') {
             $tagName = $obj->name;
         }
     }
     if ($type == 'item' && $obj->isAttachment()) {
         Zotero_FullText::deleteItemContent($obj);
     }
     $sql = "DELETE FROM {$table} WHERE libraryID=? AND `key`=?";
     $deleted = Zotero_DB::query($sql, array($libraryID, $key), $shardID);
     self::unload($obj->id);
     if ($deleted) {
         $sql = "INSERT INTO syncDeleteLogKeys\n\t\t\t\t\t\t(libraryID, objectType, `key`, timestamp, version)\n\t\t\t\t\t\tVALUES (?, '{$type}', ?, ?, ?)\n\t\t\t\t\t\tON DUPLICATE KEY UPDATE timestamp=?, version=?";
         $timestamp = Zotero_DB::getTransactionTimestamp();
         $version = Zotero_Libraries::getUpdatedVersion($libraryID);
         $params = array($libraryID, $key, $timestamp, $version, $timestamp, $version);
         Zotero_DB::query($sql, $params, $shardID);
         if ($type == 'tag') {
             $sql = "INSERT INTO syncDeleteLogKeys\n\t\t\t\t\t\t\t(libraryID, objectType, `key`, timestamp, version)\n\t\t\t\t\t\t\tVALUES (?, 'tagName', ?, ?, ?)\n\t\t\t\t\t\t\tON DUPLICATE KEY UPDATE timestamp=?, version=?";
             $params = array($libraryID, $tagName, $timestamp, $version, $timestamp, $version);
             Zotero_DB::query($sql, $params, $shardID);
         }
     }
     Zotero_DB::commit();
 }
Beispiel #15
0
 /**
  * Converts a Zotero_Item object to a SimpleXMLElement Atom object
  *
  * @param	object				$item		Zotero_Item object
  * @param	string				$content
  * @return	SimpleXMLElement					Item data as SimpleXML element
  */
 public static function convertItemToAtom(Zotero_Item $item, $queryParams, $apiVersion = null, $permissions = null, $sharedData = null)
 {
     $content = $queryParams['content'];
     $contentIsHTML = sizeOf($content) == 1 && $content[0] == 'html';
     $contentParamString = urlencode(implode(',', $content));
     $style = $queryParams['style'];
     $entry = '<entry xmlns="' . Zotero_Atom::$nsAtom . '" xmlns:zapi="' . Zotero_Atom::$nsZoteroAPI . '"/>';
     $xml = new SimpleXMLElement($entry);
     $title = $item->getDisplayTitle(true);
     $title = $title ? $title : '[Untitled]';
     $xml->title = $title;
     $author = $xml->addChild('author');
     $createdByUserID = null;
     switch (Zotero_Libraries::getType($item->libraryID)) {
         case 'group':
             $createdByUserID = $item->createdByUserID;
             break;
     }
     if ($createdByUserID) {
         $author->name = Zotero_Users::getUsername($createdByUserID);
         $author->uri = Zotero_URI::getUserURI($createdByUserID);
     } else {
         $author->name = Zotero_Libraries::getName($item->libraryID);
         $author->uri = Zotero_URI::getLibraryURI($item->libraryID);
     }
     $id = Zotero_URI::getItemURI($item);
     /*if (!$contentIsHTML) {
     			$id .= "?content=$content";
     		}*/
     $xml->id = $id;
     $xml->published = Zotero_Date::sqlToISO8601($item->getField('dateAdded'));
     $xml->updated = Zotero_Date::sqlToISO8601($item->getField('dateModified'));
     $link = $xml->addChild("link");
     $link['rel'] = "self";
     $link['type'] = "application/atom+xml";
     $href = Zotero_Atom::getItemURI($item);
     if (!$contentIsHTML) {
         $href .= "?content={$contentParamString}";
     }
     $link['href'] = $href;
     $parent = $item->getSource();
     if ($parent) {
         // TODO: handle group items?
         $parentItem = Zotero_Items::get($item->libraryID, $parent);
         $link = $xml->addChild("link");
         $link['rel'] = "up";
         $link['type'] = "application/atom+xml";
         $href = Zotero_Atom::getItemURI($parentItem);
         if (!$contentIsHTML) {
             $href .= "?content={$contentParamString}";
         }
         $link['href'] = $href;
     }
     $link = $xml->addChild('link');
     $link['rel'] = 'alternate';
     $link['type'] = 'text/html';
     $link['href'] = Zotero_URI::getItemURI($item);
     // If appropriate permissions and the file is stored in ZFS, get file request link
     if ($permissions && $permissions->canAccess($item->libraryID, 'files')) {
         $details = Zotero_S3::getDownloadDetails($item);
         if ($details) {
             $link = $xml->addChild('link');
             $link['rel'] = 'enclosure';
             $type = $item->attachmentMIMEType;
             if ($type) {
                 $link['type'] = $type;
             }
             $link['href'] = $details['url'];
             if (!empty($details['filename'])) {
                 $link['title'] = $details['filename'];
             }
             if (!empty($details['size'])) {
                 $link['length'] = $details['size'];
             }
         }
     }
     $xml->addChild('zapi:key', $item->key, Zotero_Atom::$nsZoteroAPI);
     $xml->addChild('zapi:itemType', Zotero_ItemTypes::getName($item->itemTypeID), Zotero_Atom::$nsZoteroAPI);
     if ($item->isRegularItem()) {
         $val = $item->creatorSummary;
         if ($val !== '') {
             $xml->addChild('zapi:creatorSummary', htmlspecialchars($val), Zotero_Atom::$nsZoteroAPI);
         }
         $val = substr($item->getField('date', true, true, true), 0, 4);
         if ($val !== '' && $val !== '0000') {
             $xml->addChild('zapi:year', $val, Zotero_Atom::$nsZoteroAPI);
         }
     }
     if (!$parent && $item->isRegularItem()) {
         if ($permissions && !$permissions->canAccess($item->libraryID, 'notes')) {
             $numChildren = $item->numAttachments();
         } else {
             $numChildren = $item->numChildren();
         }
         $xml->addChild('zapi:numChildren', $numChildren, Zotero_Atom::$nsZoteroAPI);
     }
     $xml->addChild('zapi:numTags', $item->numTags(), Zotero_Atom::$nsZoteroAPI);
     $xml->content = '';
     //
     // DOM XML from here on out
     //
     $contentNode = dom_import_simplexml($xml->content);
     $domDoc = $contentNode->ownerDocument;
     $multiFormat = sizeOf($content) > 1;
     // Create a root XML document for multi-format responses
     if ($multiFormat) {
         $contentNode->setAttribute('type', 'application/xml');
         /*$multicontent = $domDoc->createElementNS(
         			Zotero_Atom::$nsZoteroAPI, 'multicontent'
         		);
         		$contentNode->appendChild($multicontent);*/
     }
     foreach ($content as $type) {
         // Set the target to either the main <content>
         // or a <multicontent> <content>
         if (!$multiFormat) {
             $target = $contentNode;
         } else {
             $target = $domDoc->createElementNS(Zotero_Atom::$nsZoteroAPI, 'subcontent');
             $contentNode->appendChild($target);
         }
         $target->setAttributeNS(Zotero_Atom::$nsZoteroAPI, "zapi:type", $type);
         if ($type == 'html') {
             if (!$multiFormat) {
                 $target->setAttribute('type', 'xhtml');
             }
             $div = $domDoc->createElement('div');
             $div->setAttribute('xmlns', Zotero_Atom::$nsXHTML);
             $target->appendChild($div);
             $html = $item->toHTML(true);
             $subNode = dom_import_simplexml($html);
             $importedNode = $domDoc->importNode($subNode, true);
             $div->appendChild($importedNode);
         } else {
             if ($type == 'citation') {
                 if (!$multiFormat) {
                     $target->setAttribute('type', 'xhtml');
                 }
                 if (isset($sharedData[$type][$item->libraryID . "/" . $item->key])) {
                     $html = $sharedData[$type][$item->libraryID . "/" . $item->key];
                 } else {
                     if ($sharedData !== null) {
                         error_log("Citation not found in sharedData -- retrieving individually");
                     }
                     $html = Zotero_Cite::getCitationFromCiteServer($item, $style);
                 }
                 $html = new SimpleXMLElement($html);
                 $html['xmlns'] = Zotero_Atom::$nsXHTML;
                 $subNode = dom_import_simplexml($html);
                 $importedNode = $domDoc->importNode($subNode, true);
                 $target->appendChild($importedNode);
             } else {
                 if ($type == 'bib') {
                     if (!$multiFormat) {
                         $target->setAttribute('type', 'xhtml');
                     }
                     if (isset($sharedData[$type][$item->libraryID . "/" . $item->key])) {
                         $html = $sharedData[$type][$item->libraryID . "/" . $item->key];
                     } else {
                         if ($sharedData !== null) {
                             error_log("Bibliography not found in sharedData -- retrieving individually");
                         }
                         $html = Zotero_Cite::getBibliographyFromCitationServer(array($item), $style);
                     }
                     $html = new SimpleXMLElement($html);
                     $html['xmlns'] = Zotero_Atom::$nsXHTML;
                     $subNode = dom_import_simplexml($html);
                     $importedNode = $domDoc->importNode($subNode, true);
                     $target->appendChild($importedNode);
                 } else {
                     if ($type == 'json') {
                         $target->setAttributeNS(Zotero_Atom::$nsZoteroAPI, "zapi:etag", $item->etag);
                         $textNode = $domDoc->createTextNode($item->toJSON(false, $queryParams['pprint'], true));
                         $target->appendChild($textNode);
                     } else {
                         if ($type == 'csljson') {
                             $arr = $item->toCSLItem();
                             $mask = JSON_HEX_TAG | JSON_HEX_AMP;
                             if ($queryParams['pprint']) {
                                 $json = Zotero_Utilities::json_encode_pretty($arr, $mask);
                             } else {
                                 $json = json_encode($arr, $mask);
                             }
                             // Until JSON_UNESCAPED_SLASHES is available
                             $json = str_replace('\\/', '/', $json);
                             $textNode = $domDoc->createTextNode($json);
                             $target->appendChild($textNode);
                         } else {
                             if ($type == 'full') {
                                 if (!$multiFormat) {
                                     $target->setAttribute('type', 'xhtml');
                                 }
                                 $fullXML = Zotero_Items::convertItemToXML($item, array(), $apiVersion);
                                 $fullXML->addAttribute("xmlns", Zotero_Atom::$nsZoteroTransfer);
                                 $subNode = dom_import_simplexml($fullXML);
                                 $importedNode = $domDoc->importNode($subNode, true);
                                 $target->appendChild($importedNode);
                             } else {
                                 if (in_array($type, Zotero_Translate::$exportFormats)) {
                                     $export = Zotero_Translate::doExport(array($item), $type);
                                     $target->setAttribute('type', $export['mimeType']);
                                     // Insert XML into document
                                     if (preg_match('/\\+xml$/', $export['mimeType'])) {
                                         // Strip prolog
                                         $body = preg_replace('/^<\\?xml.+\\n/', "", $export['body']);
                                         $subNode = $domDoc->createDocumentFragment();
                                         $subNode->appendXML($body);
                                         $target->appendChild($subNode);
                                     } else {
                                         $textNode = $domDoc->createTextNode($export['body']);
                                         $target->appendChild($textNode);
                                     }
                                 }
                             }
                         }
                     }
                 }
             }
         }
     }
     return $xml;
 }
Beispiel #16
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');
	}
Beispiel #17
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;
 }
Beispiel #18
0
 /**
  * Generate self/first/prev/next/last/alternate links
  */
 public static function buildLinks($action, $path, $totalResults, $queryParams, $nonDefaultParams, $excludeParams = [])
 {
     $apiVersion = $queryParams['v'];
     $baseURI = Zotero_API::getBaseURI() . substr($path, 1);
     $alternateBaseURI = Zotero_URI::getBaseWWWURI() . substr($path, 1);
     $links = [];
     //
     // Generate URIs for 'self', 'first', 'next' and 'last' links
     //
     // 'self'
     $links['self'] = $baseURI;
     if ($nonDefaultParams) {
         $links['self'] .= Zotero_API::buildQueryString($apiVersion, $action, $nonDefaultParams, $excludeParams);
     }
     // 'first'
     $links['first'] = $baseURI;
     if ($nonDefaultParams) {
         $p = $nonDefaultParams;
         unset($p['start']);
         $links['first'] .= Zotero_API::buildQueryString($apiVersion, $action, $p, $excludeParams);
     }
     // 'prev'
     if ($queryParams['start']) {
         $p = $nonDefaultParams;
         $prevStart = $queryParams['start'] - $queryParams['limit'];
         if ($prevStart <= 0) {
             unset($p['start']);
         } else {
             $p['start'] = $prevStart;
         }
         $links['prev'] = $baseURI . Zotero_API::buildQueryString($apiVersion, $action, $p, $excludeParams);
     }
     // 'last'
     if (!$queryParams['start'] && $queryParams['limit'] >= $totalResults) {
         $links['last'] = $links['self'];
     } else {
         if ($queryParams['limit'] != 0) {
             // 'start' past results
             if ($queryParams['start'] >= $totalResults) {
                 $lastStart = $totalResults - $queryParams['limit'];
             } else {
                 $lastStart = $totalResults - $totalResults % $queryParams['limit'];
                 if ($lastStart == $totalResults) {
                     $lastStart = $totalResults - $queryParams['limit'];
                 }
             }
             $p = $nonDefaultParams;
             if ($lastStart > 0) {
                 $p['start'] = $lastStart;
             } else {
                 unset($p['start']);
             }
             $links['last'] = $baseURI . Zotero_API::buildQueryString($apiVersion, $action, $p, $excludeParams);
             // 'next'
             $nextStart = $queryParams['start'] + $queryParams['limit'];
             if ($nextStart < $totalResults) {
                 $p = $nonDefaultParams;
                 $p['start'] = $nextStart;
                 $links['next'] = $baseURI . Zotero_API::buildQueryString($apiVersion, $action, $p, $excludeParams);
             }
         }
     }
     $links['alternate'] = $alternateBaseURI;
     return $links;
 }
Beispiel #19
0
 public static function createAtomFeed($title, $url, $entries, $totalResults = null, $queryParams = null, $apiVersion = null, $permissions = null, $fixedValues = array())
 {
     if ($queryParams) {
         $nonDefaultParams = Zotero_API::getNonDefaultQueryParams($queryParams);
         // Convert 'content' array to sorted comma-separated string
         if (isset($nonDefaultParams['content'])) {
             $nonDefaultParams['content'] = implode(',', $nonDefaultParams['content']);
         }
     } else {
         $nonDefaultParams = array();
     }
     $feed = '<feed xmlns="' . Zotero_Atom::$nsAtom . '" ' . 'xmlns:zapi="' . Zotero_Atom::$nsZoteroAPI . '"';
     if ($queryParams && $queryParams['content'][0] == 'full') {
         $feed .= ' xmlns:zxfer="' . Zotero_Atom::$nsZoteroTransfer . '"';
     }
     $feed .= '/>';
     $xml = new SimpleXMLElement($feed);
     $xml->title = $title;
     $path = parse_url($url, PHP_URL_PATH);
     // Generate canonical URI
     $zoteroURI = Zotero_URI::getBaseURI() . substr($path, 1);
     if ($nonDefaultParams) {
         $zoteroURI .= "?" . http_build_query($nonDefaultParams);
     }
     $atomURI = Zotero_Atom::getBaseURI() . substr($path, 1);
     //
     // Generate URIs for 'self', 'first', 'next' and 'last' links
     //
     // 'self'
     $atomSelfURI = $atomURI;
     if ($nonDefaultParams) {
         $atomSelfURI .= "?" . http_build_query($nonDefaultParams);
     }
     // 'first'
     $atomFirstURI = $atomURI;
     if ($nonDefaultParams) {
         $p = $nonDefaultParams;
         unset($p['start']);
         if ($first = http_build_query($p)) {
             $atomFirstURI .= "?" . $first;
         }
     }
     // 'last'
     if (!$queryParams['start'] && $queryParams['limit'] >= $totalResults) {
         $atomLastURI = $atomSelfURI;
     } else {
         // 'start' past results
         if ($queryParams['start'] >= $totalResults) {
             $lastStart = $totalResults - $queryParams['limit'];
         } else {
             $lastStart = $totalResults - $totalResults % $queryParams['limit'];
             if ($lastStart == $totalResults) {
                 $lastStart = $totalResults - $queryParams['limit'];
             }
         }
         $p = $nonDefaultParams;
         if ($lastStart > 0) {
             $p['start'] = $lastStart;
         } else {
             unset($p['start']);
         }
         $atomLastURI = $atomURI;
         if ($last = http_build_query($p)) {
             $atomLastURI .= "?" . $last;
         }
         // 'next'
         $nextStart = $queryParams['start'] + $queryParams['limit'];
         if ($nextStart < $totalResults) {
             $p = $nonDefaultParams;
             $p['start'] = $nextStart;
             $atomNextURI = $atomURI . "?" . http_build_query($p);
         }
     }
     $xml->id = $zoteroURI;
     $link = $xml->addChild("link");
     $link['rel'] = "self";
     $link['type'] = "application/atom+xml";
     $link['href'] = $atomSelfURI;
     $link = $xml->addChild("link");
     $link['rel'] = "first";
     $link['type'] = "application/atom+xml";
     $link['href'] = $atomFirstURI;
     if (isset($atomNextURI)) {
         $link = $xml->addChild("link");
         $link['rel'] = "next";
         $link['type'] = "application/atom+xml";
         $link['href'] = $atomNextURI;
     }
     $link = $xml->addChild("link");
     $link['rel'] = "last";
     $link['type'] = "application/atom+xml";
     $link['href'] = $atomLastURI;
     // Generate alternate URI
     $alternateURI = Zotero_URI::getBaseURI() . substr($path, 1);
     if ($nonDefaultParams) {
         $p = $nonDefaultParams;
         if (isset($p['content'])) {
             unset($p['content']);
         }
         if ($p) {
             $alternateURI .= "?" . http_build_query($p);
         }
     }
     $link = $xml->addChild("link");
     $link['rel'] = "alternate";
     $link['type'] = "text/html";
     $link['href'] = $alternateURI;
     $xml->addChild("zapi:totalResults", is_numeric($totalResults) ? $totalResults : sizeOf($entries), self::$nsZoteroAPI);
     $xml->addChild("zapi:apiVersion", $apiVersion, self::$nsZoteroAPI);
     $latestUpdated = '';
     // Get bib data using parallel requests
     $sharedData = array();
     if ($entries && $entries[0] instanceof Zotero_Item) {
         if (in_array('citation', $queryParams['content'])) {
             $sharedData["citation"] = Zotero_Cite::multiGetFromCiteServer("citation", $entries, $queryParams['style']);
         }
         if (in_array('bib', $queryParams['content'])) {
             $sharedData["bib"] = Zotero_Cite::multiGetFromCiteServer("bib", $entries, $queryParams['style']);
         }
     }
     $xmlEntries = array();
     foreach ($entries as $entry) {
         if ($entry->dateModified > $latestUpdated) {
             $latestUpdated = $entry->dateModified;
         }
         if ($entry instanceof SimpleXMLElement) {
             $xmlEntries[] = $entry;
         } else {
             if ($entry instanceof Zotero_Collection) {
                 $entry = Zotero_Collections::convertCollectionToAtom($entry, $queryParams['content'], $apiVersion);
                 $xmlEntries[] = $entry;
             } else {
                 if ($entry instanceof Zotero_Creator) {
                     $entry = Zotero_Creators::convertCreatorToAtom($entry, $queryParams['content'], $apiVersion);
                     $xmlEntries[] = $entry;
                 } else {
                     if ($entry instanceof Zotero_Item) {
                         $entry = Zotero_Items::convertItemToAtom($entry, $queryParams, $apiVersion, $permissions, $sharedData);
                         $xmlEntries[] = $entry;
                     } else {
                         if ($entry instanceof Zotero_Search) {
                             $entry = Zotero_Searches::convertSearchToAtom($entry, $queryParams['content'], $apiVersion);
                             $xmlEntries[] = $entry;
                         } else {
                             if ($entry instanceof Zotero_Tag) {
                                 $xmlEntries[] = $entry->toAtom($queryParams['content'], $apiVersion, isset($fixedValues[$entry->id]) ? $fixedValues[$entry->id] : null);
                             } else {
                                 if ($entry instanceof Zotero_Group) {
                                     $entry = $entry->toAtom($queryParams['content'], $apiVersion);
                                     $xmlEntries[] = $entry;
                                 }
                             }
                         }
                     }
                 }
             }
         }
     }
     if ($latestUpdated) {
         $xml->updated = Zotero_Date::sqlToISO8601($latestUpdated);
     } else {
         $xml->updated = str_replace("+00:00", "Z", date('c'));
     }
     // Import object XML nodes into document
     $doc = dom_import_simplexml($xml);
     foreach ($xmlEntries as $xmlEntry) {
         $subNode = dom_import_simplexml($xmlEntry);
         $importedNode = $doc->ownerDocument->importNode($subNode, true);
         $doc->appendChild($importedNode);
     }
     return $xml;
 }