diff -r 5b37998e522e -r 162c1de6545a web/lib/Zend/Feed.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/lib/Zend/Feed.php Fri Mar 11 15:05:35 2011 +0100 @@ -0,0 +1,411 @@ + 'http://a9.com/-/spec/opensearchrss/1.0/', + 'atom' => 'http://www.w3.org/2005/Atom', + 'rss' => 'http://blogs.law.harvard.edu/tech/rss', + ); + + + /** + * Set the HTTP client instance + * + * Sets the HTTP client object to use for retrieving the feeds. + * + * @param Zend_Http_Client $httpClient + * @return void + */ + public static function setHttpClient(Zend_Http_Client $httpClient) + { + self::$_httpClient = $httpClient; + } + + + /** + * Gets the HTTP client object. If none is set, a new Zend_Http_Client will be used. + * + * @return Zend_Http_Client_Abstract + */ + public static function getHttpClient() + { + if (!self::$_httpClient instanceof Zend_Http_Client) { + /** + * @see Zend_Http_Client + */ + require_once 'Zend/Http/Client.php'; + self::$_httpClient = new Zend_Http_Client(); + } + + return self::$_httpClient; + } + + + /** + * Toggle using POST instead of PUT and DELETE HTTP methods + * + * Some feed implementations do not accept PUT and DELETE HTTP + * methods, or they can't be used because of proxies or other + * measures. This allows turning on using POST where PUT and + * DELETE would normally be used; in addition, an + * X-Method-Override header will be sent with a value of PUT or + * DELETE as appropriate. + * + * @param boolean $override Whether to override PUT and DELETE. + * @return void + */ + public static function setHttpMethodOverride($override = true) + { + self::$_httpMethodOverride = $override; + } + + + /** + * Get the HTTP override state + * + * @return boolean + */ + public static function getHttpMethodOverride() + { + return self::$_httpMethodOverride; + } + + + /** + * Get the full version of a namespace prefix + * + * Looks up a prefix (atom:, etc.) in the list of registered + * namespaces and returns the full namespace URI if + * available. Returns the prefix, unmodified, if it's not + * registered. + * + * @return string + */ + public static function lookupNamespace($prefix) + { + return isset(self::$_namespaces[$prefix]) ? + self::$_namespaces[$prefix] : + $prefix; + } + + + /** + * Add a namespace and prefix to the registered list + * + * Takes a prefix and a full namespace URI and adds them to the + * list of registered namespaces for use by + * Zend_Feed::lookupNamespace(). + * + * @param string $prefix The namespace prefix + * @param string $namespaceURI The full namespace URI + * @return void + */ + public static function registerNamespace($prefix, $namespaceURI) + { + self::$_namespaces[$prefix] = $namespaceURI; + } + + + /** + * Imports a feed located at $uri. + * + * @param string $uri + * @throws Zend_Feed_Exception + * @return Zend_Feed_Abstract + */ + public static function import($uri) + { + $client = self::getHttpClient(); + $client->setUri($uri); + $response = $client->request('GET'); + if ($response->getStatus() !== 200) { + /** + * @see Zend_Feed_Exception + */ + require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Feed failed to load, got response code ' . $response->getStatus()); + } + $feed = $response->getBody(); + return self::importString($feed); + } + + + /** + * Imports a feed represented by $string. + * + * @param string $string + * @throws Zend_Feed_Exception + * @return Zend_Feed_Abstract + */ + public static function importString($string) + { + // Load the feed as an XML DOMDocument object + $libxml_errflag = libxml_use_internal_errors(true); + $doc = new DOMDocument; + if (trim($string) == '') { + require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Document/string being imported' + . ' is an Empty string or comes from an empty HTTP response'); + } + $status = $doc->loadXML($string); + libxml_use_internal_errors($libxml_errflag); + + + if (!$status) { + // prevent the class to generate an undefined variable notice (ZF-2590) + // Build error message + $error = libxml_get_last_error(); + if ($error && $error->message) { + $errormsg = "DOMDocument cannot parse XML: {$error->message}"; + } else { + $errormsg = "DOMDocument cannot parse XML"; + } + + + /** + * @see Zend_Feed_Exception + */ + require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception($errormsg); + } + + // Try to find the base feed element or a single of an Atom feed + if ($doc->getElementsByTagName('feed')->item(0) || + $doc->getElementsByTagName('entry')->item(0)) { + /** + * @see Zend_Feed_Atom + */ + require_once 'Zend/Feed/Atom.php'; + // return a newly created Zend_Feed_Atom object + return new Zend_Feed_Atom(null, $string); + } + + // Try to find the base feed element of an RSS feed + if ($doc->getElementsByTagName('channel')->item(0)) { + /** + * @see Zend_Feed_Rss + */ + require_once 'Zend/Feed/Rss.php'; + // return a newly created Zend_Feed_Rss object + return new Zend_Feed_Rss(null, $string); + } + + // $string does not appear to be a valid feed of the supported types + /** + * @see Zend_Feed_Exception + */ + require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid or unsupported feed format'); + } + + + /** + * Imports a feed from a file located at $filename. + * + * @param string $filename + * @throws Zend_Feed_Exception + * @return Zend_Feed_Abstract + */ + public static function importFile($filename) + { + @ini_set('track_errors', 1); + $feed = @file_get_contents($filename); + @ini_restore('track_errors'); + if ($feed === false) { + /** + * @see Zend_Feed_Exception + */ + require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception("File could not be loaded: $php_errormsg"); + } + return self::importString($feed); + } + + + /** + * Attempts to find feeds at $uri referenced by tags. Returns an + * array of the feeds referenced at $uri. + * + * @todo Allow findFeeds() to follow one, but only one, code 302. + * + * @param string $uri + * @throws Zend_Feed_Exception + * @return array + */ + public static function findFeeds($uri) + { + // Get the HTTP response from $uri and save the contents + $client = self::getHttpClient(); + $client->setUri($uri); + $response = $client->request(); + if ($response->getStatus() !== 200) { + /** + * @see Zend_Feed_Exception + */ + require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception("Failed to access $uri, got response code " . $response->getStatus()); + } + $contents = $response->getBody(); + + // Parse the contents for appropriate tags + @ini_set('track_errors', 1); + $pattern = '~(]+)/?>~i'; + $result = @preg_match_all($pattern, $contents, $matches); + @ini_restore('track_errors'); + if ($result === false) { + /** + * @see Zend_Feed_Exception + */ + require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception("Internal error: $php_errormsg"); + } + + // Try to fetch a feed for each link tag that appears to refer to a feed + $feeds = array(); + if (isset($matches[1]) && count($matches[1]) > 0) { + foreach ($matches[1] as $link) { + // force string to be an utf-8 one + if (!mb_check_encoding($link, 'UTF-8')) { + $link = mb_convert_encoding($link, 'UTF-8'); + } + $xml = @simplexml_load_string(rtrim($link, ' /') . ' />'); + if ($xml === false) { + continue; + } + $attributes = $xml->attributes(); + if (!isset($attributes['rel']) || !@preg_match('~^(?:alternate|service\.feed)~i', $attributes['rel'])) { + continue; + } + if (!isset($attributes['type']) || + !@preg_match('~^application/(?:atom|rss|rdf)\+xml~', $attributes['type'])) { + continue; + } + if (!isset($attributes['href'])) { + continue; + } + try { + // checks if we need to canonize the given uri + try { + $uri = Zend_Uri::factory((string) $attributes['href']); + } catch (Zend_Uri_Exception $e) { + // canonize the uri + $path = (string) $attributes['href']; + $query = $fragment = ''; + if (substr($path, 0, 1) != '/') { + // add the current root path to this one + $path = rtrim($client->getUri()->getPath(), '/') . '/' . $path; + } + if (strpos($path, '?') !== false) { + list($path, $query) = explode('?', $path, 2); + } + if (strpos($query, '#') !== false) { + list($query, $fragment) = explode('#', $query, 2); + } + $uri = Zend_Uri::factory($client->getUri(true)); + $uri->setPath($path); + $uri->setQuery($query); + $uri->setFragment($fragment); + } + + $feed = self::import($uri); + } catch (Exception $e) { + continue; + } + $feeds[$uri->getUri()] = $feed; + } + } + + // Return the fetched feeds + return $feeds; + } + + /** + * Construct a new Zend_Feed_Abstract object from a custom array + * + * @param array $data + * @param string $format (rss|atom) the requested output format + * @return Zend_Feed_Abstract + */ + public static function importArray(array $data, $format = 'atom') + { + $obj = 'Zend_Feed_' . ucfirst(strtolower($format)); + if (!class_exists($obj)) { + require_once 'Zend/Loader.php'; + Zend_Loader::loadClass($obj); + } + + /** + * @see Zend_Feed_Builder + */ + require_once 'Zend/Feed/Builder.php'; + return new $obj(null, null, new Zend_Feed_Builder($data)); + } + + /** + * Construct a new Zend_Feed_Abstract object from a Zend_Feed_Builder_Interface data source + * + * @param Zend_Feed_Builder_Interface $builder this object will be used to extract the data of the feed + * @param string $format (rss|atom) the requested output format + * @return Zend_Feed_Abstract + */ + public static function importBuilder(Zend_Feed_Builder_Interface $builder, $format = 'atom') + { + $obj = 'Zend_Feed_' . ucfirst(strtolower($format)); + if (!class_exists($obj)) { + require_once 'Zend/Loader.php'; + Zend_Loader::loadClass($obj); + } + return new $obj(null, null, $builder); + } +}