diff options
Diffstat (limited to 'libs/Zend/Feed')
84 files changed, 11391 insertions, 651 deletions
diff --git a/libs/Zend/Feed/Abstract.php b/libs/Zend/Feed/Abstract.php index ce59dc0793..8cd77dee7c 100644 --- a/libs/Zend/Feed/Abstract.php +++ b/libs/Zend/Feed/Abstract.php @@ -15,16 +15,16 @@ * * @category Zend * @package Zend_Feed - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Abstract.php 18293 2009-09-18 22:16:07Z padraic $ + * @version $Id: Abstract.php 20096 2010-01-06 02:05:09Z bkarwin $ */ /** * @see Zend_Feed_Element */ -require_once 'Zend/Feed/Element.php'; +// require_once 'Zend/Feed/Element.php'; /** @@ -37,7 +37,7 @@ require_once 'Zend/Feed/Element.php'; * * @category Zend * @package Zend_Feed - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ abstract class Zend_Feed_Abstract extends Zend_Feed_Element implements Iterator, Countable @@ -77,10 +77,10 @@ abstract class Zend_Feed_Abstract extends Zend_Feed_Element implements Iterator, $client->setUri($uri); $response = $client->request('GET'); if ($response->getStatus() !== 200) { - /** + /** * @see Zend_Feed_Exception */ - require_once 'Zend/Feed/Exception.php'; + // require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception('Feed failed to load, got response code ' . $response->getStatus()); } $this->_element = $response->getBody(); @@ -123,11 +123,11 @@ abstract class Zend_Feed_Abstract extends Zend_Feed_Element implements Iterator, $php_errormsg = '(error message not available)'; } } - - /** + + /** * @see Zend_Feed_Exception */ - require_once 'Zend/Feed/Exception.php'; + // require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception("DOMDocument cannot parse XML: $php_errormsg"); } diff --git a/libs/Zend/Feed/Atom.php b/libs/Zend/Feed/Atom.php index db0055c5c2..8a723f862d 100644 --- a/libs/Zend/Feed/Atom.php +++ b/libs/Zend/Feed/Atom.php @@ -15,21 +15,21 @@ * * @category Zend * @package Zend_Feed - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Atom.php 16205 2009-06-21 19:08:45Z thomas $ + * @version $Id: Atom.php 20096 2010-01-06 02:05:09Z bkarwin $ */ /** * @see Zend_Feed_Abstract */ -require_once 'Zend/Feed/Abstract.php'; +// require_once 'Zend/Feed/Abstract.php'; /** * @see Zend_Feed_Entry_Atom */ -require_once 'Zend/Feed/Entry/Atom.php'; +// require_once 'Zend/Feed/Entry/Atom.php'; /** @@ -44,7 +44,7 @@ require_once 'Zend/Feed/Entry/Atom.php'; * * @category Zend * @package Zend_Feed - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Feed_Atom extends Zend_Feed_Abstract @@ -89,10 +89,10 @@ class Zend_Feed_Atom extends Zend_Feed_Abstract // Try to find a single <entry> instead. $element = $this->_element->getElementsByTagName($this->_entryElementName)->item(0); if (!$element) { - /** + /** * @see Zend_Feed_Exception */ - require_once 'Zend/Feed/Exception.php'; + // require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception('No root <feed> or <' . $this->_entryElementName . '> element found, cannot parse feed.'); } @@ -376,10 +376,10 @@ class Zend_Feed_Atom extends Zend_Feed_Abstract public function send() { if (headers_sent()) { - /** + /** * @see Zend_Feed_Exception */ - require_once 'Zend/Feed/Exception.php'; + // require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception('Cannot send ATOM because headers have already been sent.'); } diff --git a/libs/Zend/Feed/Builder.php b/libs/Zend/Feed/Builder.php index a0adbb1643..a9517ce5be 100644 --- a/libs/Zend/Feed/Builder.php +++ b/libs/Zend/Feed/Builder.php @@ -15,26 +15,26 @@ * * @category Zend * @package Zend_Feed - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Builder.php 16205 2009-06-21 19:08:45Z thomas $ + * @version $Id: Builder.php 20096 2010-01-06 02:05:09Z bkarwin $ */ /** * @see Zend_Feed_Builder_Interface */ -require_once 'Zend/Feed/Builder/Interface.php'; +// require_once 'Zend/Feed/Builder/Interface.php'; /** * @see Zend_Feed_Builder_Header */ -require_once 'Zend/Feed/Builder/Header.php'; +// require_once 'Zend/Feed/Builder/Header.php'; /** * @see Zend_Feed_Builder_Entry */ -require_once 'Zend/Feed/Builder/Entry.php'; +// require_once 'Zend/Feed/Builder/Entry.php'; /** @@ -44,7 +44,7 @@ require_once 'Zend/Feed/Builder/Entry.php'; * * @category Zend * @package Zend_Feed - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Feed_Builder implements Zend_Feed_Builder_Interface @@ -212,7 +212,7 @@ class Zend_Feed_Builder implements Zend_Feed_Builder_Interface * @throws Zend_Feed_Builder_Exception * @return void */ - private function _createHeader(array $data) + protected function _createHeader(array $data) { $mandatories = array('title', 'link', 'charset'); foreach ($mandatories as $mandatory) { @@ -220,7 +220,7 @@ class Zend_Feed_Builder implements Zend_Feed_Builder_Interface /** * @see Zend_Feed_Builder_Exception */ - require_once 'Zend/Feed/Builder/Exception.php'; + // require_once 'Zend/Feed/Builder/Exception.php'; throw new Zend_Feed_Builder_Exception("$mandatory key is missing"); } } @@ -268,7 +268,7 @@ class Zend_Feed_Builder implements Zend_Feed_Builder_Interface /** * @see Zend_Feed_Builder_Exception */ - require_once 'Zend/Feed/Builder/Exception.php'; + // require_once 'Zend/Feed/Builder/Exception.php'; throw new Zend_Feed_Builder_Exception("you have to define $mandatory property of your cloud"); } } @@ -282,7 +282,7 @@ class Zend_Feed_Builder implements Zend_Feed_Builder_Interface /** * @see Zend_Feed_Builder_Exception */ - require_once 'Zend/Feed/Builder/Exception.php'; + // require_once 'Zend/Feed/Builder/Exception.php'; throw new Zend_Feed_Builder_Exception("you have to define $mandatory property of your textInput"); } } @@ -340,7 +340,7 @@ class Zend_Feed_Builder implements Zend_Feed_Builder_Interface * @throws Zend_Feed_Builder_Exception * @return void */ - private function _createEntries(array $data) + protected function _createEntries(array $data) { foreach ($data as $row) { $mandatories = array('title', 'link', 'description'); @@ -349,7 +349,7 @@ class Zend_Feed_Builder implements Zend_Feed_Builder_Interface /** * @see Zend_Feed_Builder_Exception */ - require_once 'Zend/Feed/Builder/Exception.php'; + // require_once 'Zend/Feed/Builder/Exception.php'; throw new Zend_Feed_Builder_Exception("$mandatory key is missing"); } } @@ -379,7 +379,7 @@ class Zend_Feed_Builder implements Zend_Feed_Builder_Interface /** * @see Zend_Feed_Builder_Exception */ - require_once 'Zend/Feed/Builder/Exception.php'; + // require_once 'Zend/Feed/Builder/Exception.php'; throw new Zend_Feed_Builder_Exception("$mandatory key of source property is missing"); } } @@ -395,4 +395,4 @@ class Zend_Feed_Builder implements Zend_Feed_Builder_Interface $this->_entries[] = $entry; } } -}
\ No newline at end of file +} diff --git a/libs/Zend/Feed/Builder/Entry.php b/libs/Zend/Feed/Builder/Entry.php index e428928717..6e7edc67b0 100644 --- a/libs/Zend/Feed/Builder/Entry.php +++ b/libs/Zend/Feed/Builder/Entry.php @@ -15,9 +15,9 @@ * * @category Zend * @package Zend_Feed - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Entry.php 16205 2009-06-21 19:08:45Z thomas $ + * @version $Id: Entry.php 20096 2010-01-06 02:05:09Z bkarwin $ */ @@ -29,7 +29,7 @@ * * @category Zend * @package Zend_Feed - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Feed_Builder_Entry extends ArrayObject @@ -224,7 +224,7 @@ class Zend_Feed_Builder_Entry extends ArrayObject /** * @see Zend_Feed_Builder_Exception */ - require_once 'Zend/Feed/Builder/Exception.php'; + // require_once 'Zend/Feed/Builder/Exception.php'; throw new Zend_Feed_Builder_Exception("you have to define the name of the category"); } @@ -263,7 +263,7 @@ class Zend_Feed_Builder_Entry extends ArrayObject /** * @see Zend_Feed_Builder_Exception */ - require_once 'Zend/Feed/Builder/Exception.php'; + // require_once 'Zend/Feed/Builder/Exception.php'; throw new Zend_Feed_Builder_Exception("you have to supply an url for your enclosure"); } $type = isset($enclosure['type']) ? $enclosure['type'] : ''; diff --git a/libs/Zend/Feed/Builder/Exception.php b/libs/Zend/Feed/Builder/Exception.php index b213ceb42b..9037cc891a 100644 --- a/libs/Zend/Feed/Builder/Exception.php +++ b/libs/Zend/Feed/Builder/Exception.php @@ -15,16 +15,16 @@ * * @category Zend * @package Zend_Feed - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Exception.php 16205 2009-06-21 19:08:45Z thomas $ + * @version $Id: Exception.php 20096 2010-01-06 02:05:09Z bkarwin $ */ /** * @see Zend_Feed_Exception */ -require_once 'Zend/Feed/Exception.php'; +// require_once 'Zend/Feed/Exception.php'; /** @@ -32,7 +32,7 @@ require_once 'Zend/Feed/Exception.php'; * * @category Zend * @package Zend_Feed - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Feed_Builder_Exception extends Zend_Feed_Exception diff --git a/libs/Zend/Feed/Builder/Header.php b/libs/Zend/Feed/Builder/Header.php index a234377a15..51a57953f2 100644 --- a/libs/Zend/Feed/Builder/Header.php +++ b/libs/Zend/Feed/Builder/Header.php @@ -15,20 +15,20 @@ * * @category Zend * @package Zend_Feed - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Header.php 16205 2009-06-21 19:08:45Z thomas $ + * @version $Id: Header.php 20096 2010-01-06 02:05:09Z bkarwin $ */ /** * @see Zend_Feed_Builder_Header_Itunes */ -require_once 'Zend/Feed/Builder/Header/Itunes.php'; +// require_once 'Zend/Feed/Builder/Header/Itunes.php'; /** * @see Zend_Uri */ -require_once 'Zend/Uri.php'; +// require_once 'Zend/Uri.php'; /** @@ -39,7 +39,7 @@ require_once 'Zend/Uri.php'; * * @category Zend * @package Zend_Feed - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Feed_Builder_Header extends ArrayObject @@ -172,13 +172,13 @@ class Zend_Feed_Builder_Header extends ArrayObject /** * @see Zend_Validate_EmailAddress */ - require_once 'Zend/Validate/EmailAddress.php'; + // require_once 'Zend/Validate/EmailAddress.php'; $validate = new Zend_Validate_EmailAddress(); if (!$validate->isValid($email)) { /** * @see Zend_Feed_Builder_Exception */ - require_once 'Zend/Feed/Builder/Exception.php'; + // require_once 'Zend/Feed/Builder/Exception.php'; throw new Zend_Feed_Builder_Exception("you have to set a valid email address into the email property"); } $this->offsetSet('email', $email); @@ -246,13 +246,13 @@ class Zend_Feed_Builder_Header extends ArrayObject /** * @see Zend_Validate_EmailAddress */ - require_once 'Zend/Validate/EmailAddress.php'; + // require_once 'Zend/Validate/EmailAddress.php'; $validate = new Zend_Validate_EmailAddress(); if (!$validate->isValid($webmaster)) { /** * @see Zend_Feed_Builder_Exception */ - require_once 'Zend/Feed/Builder/Exception.php'; + // require_once 'Zend/Feed/Builder/Exception.php'; throw new Zend_Feed_Builder_Exception("you have to set a valid email address into the webmaster property"); } $this->offsetSet('webmaster', $webmaster); @@ -272,13 +272,13 @@ class Zend_Feed_Builder_Header extends ArrayObject /** * @see Zend_Validate_Int */ - require_once 'Zend/Validate/Int.php'; + // require_once 'Zend/Validate/Int.php'; $validate = new Zend_Validate_Int(); if (!$validate->isValid($ttl)) { /** * @see Zend_Feed_Builder_Exception */ - require_once 'Zend/Feed/Builder/Exception.php'; + // require_once 'Zend/Feed/Builder/Exception.php'; throw new Zend_Feed_Builder_Exception("you have to set an integer value to the ttl property"); } $this->offsetSet('ttl', $ttl); @@ -317,7 +317,7 @@ class Zend_Feed_Builder_Header extends ArrayObject /** * @see Zend_Feed_Builder_Exception */ - require_once 'Zend/Feed/Builder/Exception.php'; + // require_once 'Zend/Feed/Builder/Exception.php'; throw new Zend_Feed_Builder_Exception('Passed parameter is not a valid HTTP URI'); } if (!$uri->getPort()) { @@ -362,7 +362,7 @@ class Zend_Feed_Builder_Header extends ArrayObject /** * @see Zend_Feed_Builder_Exception */ - require_once 'Zend/Feed/Builder/Exception.php'; + // require_once 'Zend/Feed/Builder/Exception.php'; throw new Zend_Feed_Builder_Exception("you can not have more than 24 rows in the skipHours property"); } foreach ($hours as $hour) { @@ -370,7 +370,7 @@ class Zend_Feed_Builder_Header extends ArrayObject /** * @see Zend_Feed_Builder_Exception */ - require_once 'Zend/Feed/Builder/Exception.php'; + // require_once 'Zend/Feed/Builder/Exception.php'; throw new Zend_Feed_Builder_Exception("$hour has te be between 0 and 23"); } } @@ -392,7 +392,7 @@ class Zend_Feed_Builder_Header extends ArrayObject /** * @see Zend_Feed_Builder_Exception */ - require_once 'Zend/Feed/Builder/Exception.php'; + // require_once 'Zend/Feed/Builder/Exception.php'; throw new Zend_Feed_Builder_Exception("you can not have more than 7 days in the skipDays property"); } $valid = array('monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'); @@ -401,7 +401,7 @@ class Zend_Feed_Builder_Header extends ArrayObject /** * @see Zend_Feed_Builder_Exception */ - require_once 'Zend/Feed/Builder/Exception.php'; + // require_once 'Zend/Feed/Builder/Exception.php'; throw new Zend_Feed_Builder_Exception("$day is not a valid day"); } } diff --git a/libs/Zend/Feed/Builder/Header/Itunes.php b/libs/Zend/Feed/Builder/Header/Itunes.php index cbb443bbae..9445460c07 100644 --- a/libs/Zend/Feed/Builder/Header/Itunes.php +++ b/libs/Zend/Feed/Builder/Header/Itunes.php @@ -15,9 +15,9 @@ * * @category Zend * @package Zend_Feed - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Itunes.php 16205 2009-06-21 19:08:45Z thomas $ + * @version $Id: Itunes.php 20096 2010-01-06 02:05:09Z bkarwin $ */ @@ -28,7 +28,7 @@ * * @category Zend * @package Zend_Feed - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Feed_Builder_Header_Itunes extends ArrayObject @@ -66,14 +66,14 @@ class Zend_Feed_Builder_Header_Itunes extends ArrayObject /** * @see Zend_Feed_Builder_Exception */ - require_once 'Zend/Feed/Builder/Exception.php'; + // require_once 'Zend/Feed/Builder/Exception.php'; throw new Zend_Feed_Builder_Exception("you have to set at least one itunes category"); } if ($nb > 3) { /** * @see Zend_Feed_Builder_Exception */ - require_once 'Zend/Feed/Builder/Exception.php'; + // require_once 'Zend/Feed/Builder/Exception.php'; throw new Zend_Feed_Builder_Exception("you have to set at most three itunes categories"); } foreach ($categories as $i => $category) { @@ -81,7 +81,7 @@ class Zend_Feed_Builder_Header_Itunes extends ArrayObject /** * @see Zend_Feed_Builder_Exception */ - require_once 'Zend/Feed/Builder/Exception.php'; + // require_once 'Zend/Feed/Builder/Exception.php'; throw new Zend_Feed_Builder_Exception("you have to set the main category (category #$i)"); } } @@ -112,16 +112,16 @@ class Zend_Feed_Builder_Header_Itunes extends ArrayObject public function setOwner($name = '', $email = '') { if (!empty($email)) { - /** - * @see Zend_Validate_EmailAddress - */ - require_once 'Zend/Validate/EmailAddress.php'; + /** + * @see Zend_Validate_EmailAddress + */ + // require_once 'Zend/Validate/EmailAddress.php'; $validate = new Zend_Validate_EmailAddress(); if (!$validate->isValid($email)) { /** * @see Zend_Feed_Builder_Exception */ - require_once 'Zend/Feed/Builder/Exception.php'; + // require_once 'Zend/Feed/Builder/Exception.php'; throw new Zend_Feed_Builder_Exception("you have to set a valid email address into the itunes owner's email property"); } } @@ -182,7 +182,7 @@ class Zend_Feed_Builder_Header_Itunes extends ArrayObject /** * @see Zend_Feed_Builder_Exception */ - require_once 'Zend/Feed/Builder/Exception.php'; + // require_once 'Zend/Feed/Builder/Exception.php'; throw new Zend_Feed_Builder_Exception("you have to set yes or no to the itunes block property"); } $this->offsetSet('block', $block); @@ -203,7 +203,7 @@ class Zend_Feed_Builder_Header_Itunes extends ArrayObject /** * @see Zend_Feed_Builder_Exception */ - require_once 'Zend/Feed/Builder/Exception.php'; + // require_once 'Zend/Feed/Builder/Exception.php'; throw new Zend_Feed_Builder_Exception("you have to set yes, no or clean to the itunes explicit property"); } $this->offsetSet('explicit', $explicit); diff --git a/libs/Zend/Feed/Builder/Interface.php b/libs/Zend/Feed/Builder/Interface.php index a3cce7e018..9dce55f815 100644 --- a/libs/Zend/Feed/Builder/Interface.php +++ b/libs/Zend/Feed/Builder/Interface.php @@ -15,9 +15,9 @@ * * @category Zend * @package Zend_Feed - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Interface.php 16205 2009-06-21 19:08:45Z thomas $ + * @version $Id: Interface.php 20096 2010-01-06 02:05:09Z bkarwin $ */ @@ -29,7 +29,7 @@ * * @category Zend * @package Zend_Feed - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ interface Zend_Feed_Builder_Interface diff --git a/libs/Zend/Feed/Element.php b/libs/Zend/Feed/Element.php index 2f0337d54f..b7a8e632f2 100644 --- a/libs/Zend/Feed/Element.php +++ b/libs/Zend/Feed/Element.php @@ -15,9 +15,9 @@ * * @category Zend * @package Zend_Feed - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Element.php 18568 2009-10-16 11:59:55Z sgehrig $ + * @version $Id: Element.php 20104 2010-01-06 21:26:01Z matthew $ */ @@ -26,7 +26,7 @@ * * @category Zend * @package Zend_Feed - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Feed_Element implements ArrayAccess @@ -38,6 +38,11 @@ class Zend_Feed_Element implements ArrayAccess protected $_element; /** + * @var string Character encoding to utilize + */ + protected $_encoding = 'UTF-8'; + + /** * @var Zend_Feed_Element */ protected $_parentElement; @@ -148,6 +153,27 @@ class Zend_Feed_Element implements ArrayAccess return $this->_element->ownerDocument->saveXML($this->_element); } + /** + * Get encoding + * + * @return string + */ + public function getEncoding() + { + return $this->_encoding; + } + + /** + * Set encoding + * + * @param string $value Encoding to use + * @return Zend_Feed_Element + */ + public function setEncoding($value) + { + $this->_encoding = (string) $value; + return $this; + } /** * Map variable access onto the underlying entry representation. @@ -205,18 +231,18 @@ class Zend_Feed_Element implements ArrayAccess if (strpos($var, ':') !== false) { list($ns, $elt) = explode(':', $var, 2); $node = $this->_element->ownerDocument->createElementNS(Zend_Feed::lookupNamespace($ns), - $var, htmlspecialchars($val, ENT_NOQUOTES, 'UTF-8')); + $var, htmlspecialchars($val, ENT_NOQUOTES, $this->getEncoding())); $this->_element->appendChild($node); } else { $node = $this->_element->ownerDocument->createElement($var, - htmlspecialchars($val, ENT_NOQUOTES, 'UTF-8')); + htmlspecialchars($val, ENT_NOQUOTES, $this->getEncoding())); $this->_element->appendChild($node); } } elseif (count($nodes) > 1) { - /** + /** * @see Zend_Feed_Exception */ - require_once 'Zend/Feed/Exception.php'; + // require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception('Cannot set the value of multiple tags simultaneously.'); } else { $nodes[0]->nodeValue = $val; diff --git a/libs/Zend/Feed/Entry/Abstract.php b/libs/Zend/Feed/Entry/Abstract.php index ba82f1fca1..60c10cc89a 100644 --- a/libs/Zend/Feed/Entry/Abstract.php +++ b/libs/Zend/Feed/Entry/Abstract.php @@ -15,21 +15,21 @@ * * @category Zend * @package Zend_Feed - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Abstract.php 16205 2009-06-21 19:08:45Z thomas $ + * @version $Id: Abstract.php 20096 2010-01-06 02:05:09Z bkarwin $ */ /** * @see Zend_Feed */ -require_once 'Zend/Feed.php'; +// require_once 'Zend/Feed.php'; /** * @see Zend_Feed_Element */ -require_once 'Zend/Feed/Element.php'; +// require_once 'Zend/Feed/Element.php'; /** @@ -38,7 +38,7 @@ require_once 'Zend/Feed/Element.php'; * * @category Zend * @package Zend_Feed - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ abstract class Zend_Feed_Entry_Abstract extends Zend_Feed_Element @@ -93,19 +93,19 @@ abstract class Zend_Feed_Entry_Abstract extends Zend_Feed_Element } } - /** + /** * @see Zend_Feed_Exception */ - require_once 'Zend/Feed/Exception.php'; + // require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception("DOMDocument cannot parse XML: $php_errormsg"); } $element = $doc->getElementsByTagName($this->_rootElement)->item(0); if (!$element) { - /** + /** * @see Zend_Feed_Exception */ - require_once 'Zend/Feed/Exception.php'; + // require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception('No root <' . $this->_rootElement . '> element found, cannot parse feed.'); } } else { diff --git a/libs/Zend/Feed/Entry/Atom.php b/libs/Zend/Feed/Entry/Atom.php index 7cbfce2c0e..01a17232eb 100644 --- a/libs/Zend/Feed/Entry/Atom.php +++ b/libs/Zend/Feed/Entry/Atom.php @@ -15,16 +15,16 @@ * * @category Zend * @package Zend_Feed - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Atom.php 18184 2009-09-17 18:26:40Z padraic $ + * @version $Id: Atom.php 20096 2010-01-06 02:05:09Z bkarwin $ */ /** * @see Zend_Feed_Entry_Abstract */ -require_once 'Zend/Feed/Entry/Abstract.php'; +// require_once 'Zend/Feed/Entry/Abstract.php'; /** @@ -32,15 +32,15 @@ require_once 'Zend/Feed/Entry/Abstract.php'; * * @category Zend * @package Zend_Feed - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Feed_Entry_Atom extends Zend_Feed_Entry_Abstract { - /** - * Content-Type - */ - const CONTENT_TYPE = 'application/atom+xml'; + /** + * Content-Type + */ + const CONTENT_TYPE = 'application/atom+xml'; /** * Root XML element for Atom entries. @@ -79,7 +79,7 @@ class Zend_Feed_Entry_Atom extends Zend_Feed_Entry_Abstract /** * @see Zend_Feed_Exception */ - require_once 'Zend/Feed/Exception.php'; + // require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception('Cannot delete entry; no link rel="edit" is present.'); } @@ -107,7 +107,7 @@ class Zend_Feed_Entry_Atom extends Zend_Feed_Entry_Abstract /** * @see Zend_Feed_Exception */ - require_once 'Zend/Feed/Exception.php'; + // require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception("Expected response code 2xx, got $httpStatus"); } } while (true); @@ -144,7 +144,7 @@ class Zend_Feed_Entry_Atom extends Zend_Feed_Entry_Abstract /** * @see Zend_Feed_Exception */ - require_once 'Zend/Feed/Exception.php'; + // require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception('Cannot edit entry; no link rel="edit" is present.'); } @@ -164,7 +164,7 @@ class Zend_Feed_Entry_Atom extends Zend_Feed_Entry_Abstract /** * @see Zend_Feed_Exception */ - require_once 'Zend/Feed/Exception.php'; + // require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception('Expected response code 200, got ' . $response->getStatus()); } } else { @@ -172,7 +172,7 @@ class Zend_Feed_Entry_Atom extends Zend_Feed_Entry_Abstract /** * @see Zend_Feed_Exception */ - require_once 'Zend/Feed/Exception.php'; + // require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception('PostURI must be specified to save new entries.'); } $client = Zend_Feed::getHttpClient(); @@ -185,7 +185,7 @@ class Zend_Feed_Entry_Atom extends Zend_Feed_Entry_Abstract /** * @see Zend_Feed_Exception */ - require_once 'Zend/Feed/Exception.php'; + // require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception('Expected response code 201, got ' . $response->getStatus()); } @@ -210,7 +210,7 @@ class Zend_Feed_Entry_Atom extends Zend_Feed_Entry_Abstract /** * @see Zend_Feed_Exception */ - require_once 'Zend/Feed/Exception.php'; + // require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception('XML cannot be parsed: ' . $php_errormsg); } @@ -219,7 +219,7 @@ class Zend_Feed_Entry_Atom extends Zend_Feed_Entry_Abstract /** * @see Zend_Feed_Exception */ - require_once 'Zend/Feed/Exception.php'; + // require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception('No root <feed> element found in server response:' . "\n\n" . $client->responseBody); } diff --git a/libs/Zend/Feed/Entry/Rss.php b/libs/Zend/Feed/Entry/Rss.php index 464601b5e7..a03fe8052e 100644 --- a/libs/Zend/Feed/Entry/Rss.php +++ b/libs/Zend/Feed/Entry/Rss.php @@ -15,16 +15,16 @@ * * @category Zend * @package Zend_Feed - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Rss.php 16205 2009-06-21 19:08:45Z thomas $ + * @version $Id: Rss.php 20096 2010-01-06 02:05:09Z bkarwin $ */ /** * @see Zend_Feed_Entry_Abstract */ -require_once 'Zend/Feed/Entry/Abstract.php'; +// require_once 'Zend/Feed/Entry/Abstract.php'; /** @@ -32,7 +32,7 @@ require_once 'Zend/Feed/Entry/Abstract.php'; * * @category Zend * @package Zend_Feed - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Feed_Entry_Rss extends Zend_Feed_Entry_Abstract @@ -98,7 +98,7 @@ class Zend_Feed_Entry_Rss extends Zend_Feed_Entry_Abstract return parent::__isset($var); } } - + /** * Overwrites parent::_call method to enable read access * to content:encoded element. diff --git a/libs/Zend/Feed/Exception.php b/libs/Zend/Feed/Exception.php index c77bb35495..1142c88a00 100644 --- a/libs/Zend/Feed/Exception.php +++ b/libs/Zend/Feed/Exception.php @@ -15,16 +15,16 @@ * * @category Zend * @package Zend_Feed - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Exception.php 16205 2009-06-21 19:08:45Z thomas $ + * @version $Id: Exception.php 20096 2010-01-06 02:05:09Z bkarwin $ */ /** * @see Zend_Exception */ -require_once 'Zend/Exception.php'; +// require_once 'Zend/Exception.php'; /** @@ -34,7 +34,7 @@ require_once 'Zend/Exception.php'; * * @category Zend * @package Zend_Feed - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Feed_Exception extends Zend_Exception diff --git a/libs/Zend/Feed/Pubsubhubbub.php b/libs/Zend/Feed/Pubsubhubbub.php new file mode 100644 index 0000000000..eeffd74218 --- /dev/null +++ b/libs/Zend/Feed/Pubsubhubbub.php @@ -0,0 +1,152 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Pubsubhubbub + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * @see Zend_Http_Client + */ +// require_once 'Zend/Http/Client.php'; + +/** + * @see Zend_Uri + */ +// require_once 'Zend/Uri.php'; + +/** + * @see Zend_Version + */ +// require_once 'Zend/Version.php'; + +/** + * @see Zend_Feed_Reader + */ +// require_once 'Zend/Feed/Reader.php'; + +/** + * @see Zend_Feed_Abstract + */ +// require_once 'Zend/Feed/Abstract.php'; + +/** + * @category Zend + * @package Zend_Feed_Pubsubhubbub + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Pubsubhubbub +{ + /** + * Verification Modes + */ + const VERIFICATION_MODE_SYNC = 'sync'; + const VERIFICATION_MODE_ASYNC = 'async'; + + /** + * Subscription States + */ + const SUBSCRIPTION_VERIFIED = 'verified'; + const SUBSCRIPTION_NOTVERIFIED = 'not_verified'; + const SUBSCRIPTION_TODELETE = 'to_delete'; + + /** + * Singleton instance if required of the HTTP client + * + * @var Zend_Http_Client + */ + protected static $httpClient = null; + + /** + * Simple utility function which imports any feed URL and + * determines the existence of Hub Server endpoints. This works + * best if directly given an instance of Zend_Feed_Reader_Atom|Rss + * to leverage off. + * + * @param Zend_Feed_Reader_FeedAbstract|Zend_Feed_Abstract|string $source + * @return array + */ + public static function detectHubs($source) + { + if (is_string($source)) { + $feed = Zend_Feed_Reader::import($source); + } elseif (is_object($source) && $source instanceof Zend_Feed_Reader_FeedAbstract) { + $feed = $source; + } elseif (is_object($source) && $source instanceof Zend_Feed_Abstract) { + $feed = Zend_Feed_Reader::importFeed($source); + } else { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('The source parameter was' + . ' invalid, i.e. not a URL string or an instance of type' + . ' Zend_Feed_Reader_FeedAbstract or Zend_Feed_Abstract'); + } + return $feed->getHubs(); + } + + /** + * Allows the external environment to make Zend_Oauth use a specific + * Client instance. + * + * @param Zend_Http_Client $httpClient + * @return void + */ + public static function setHttpClient(Zend_Http_Client $httpClient) + { + self::$httpClient = $httpClient; + } + + /** + * Return the singleton instance of the HTTP Client. Note that + * the instance is reset and cleared of previous parameters GET/POST. + * Headers are NOT reset but handled by this component if applicable. + * + * @return Zend_Http_Client + */ + public static function getHttpClient() + { + if (!isset(self::$httpClient)): + self::$httpClient = new Zend_Http_Client; + else: + self::$httpClient->resetParameters(); + endif; + return self::$httpClient; + } + + /** + * Simple mechanism to delete the entire singleton HTTP Client instance + * which forces an new instantiation for subsequent requests. + * + * @return void + */ + public static function clearHttpClient() + { + self::$httpClient = null; + } + + /** + * RFC 3986 safe url encoding method + * + * @param string $string + * @return string + */ + public static function urlencode($string) + { + $rawencoded = rawurlencode($string); + $rfcencoded = str_replace('%7E', '~', $rawencoded); + return $rfcencoded; + } +} diff --git a/libs/Zend/Feed/Pubsubhubbub/CallbackAbstract.php b/libs/Zend/Feed/Pubsubhubbub/CallbackAbstract.php new file mode 100644 index 0000000000..2fae31b831 --- /dev/null +++ b/libs/Zend/Feed/Pubsubhubbub/CallbackAbstract.php @@ -0,0 +1,307 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Pubsubhubbub + * @subpackage Callback + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * @see Zend_Feed_Pubsubhubbub_CallbackInterface + */ +// require_once 'Zend/Feed/Pubsubhubbub/CallbackInterface.php'; + +/** + * @see Zend_Feed_Pubsubhubbub_HttpResponse + */ +// require_once 'Zend/Feed/Pubsubhubbub/HttpResponse.php'; + +/** + * @category Zend + * @package Zend_Feed_Pubsubhubbub + * @subpackage Callback + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +abstract class Zend_Feed_Pubsubhubbub_CallbackAbstract + implements Zend_Feed_Pubsubhubbub_CallbackInterface +{ + /** + * An instance of Zend_Feed_Pubsubhubbub_Model_SubscriptionInterface used + * to background save any verification tokens associated with a subscription + * or other. + * + * @var Zend_Feed_Pubsubhubbub_Model_SubscriptionInterface + */ + protected $_storage = null; + + /** + * An instance of a class handling Http Responses. This is implemented in + * Zend_Feed_Pubsubhubbub_HttpResponse which shares an unenforced interface with + * (i.e. not inherited from) Zend_Controller_Response_Http. + * + * @var Zend_Feed_Pubsubhubbub_HttpResponse|Zend_Controller_Response_Http + */ + protected $_httpResponse = null; + + /** + * The number of Subscribers for which any updates are on behalf of. + * + * @var int + */ + protected $_subscriberCount = 1; + + /** + * Constructor; accepts an array or Zend_Config instance to preset + * options for the Subscriber without calling all supported setter + * methods in turn. + * + * @param array|Zend_Config $options Options array or Zend_Config instance + */ + public function __construct($config = null) + { + if (!is_null($config)) { + $this->setConfig($config); + } + } + + /** + * Process any injected configuration options + * + * @param array|Zend_Config $options Options array or Zend_Config instance + * @return Zend_Feed_Pubsubhubbub_CallbackAbstract + */ + public function setConfig($config) + { + if ($config instanceof Zend_Config) { + $config = $config->toArray(); + } elseif (!is_array($config)) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('Array or Zend_Config object' + . 'expected, got ' . gettype($config)); + } + if (array_key_exists('storage', $config)) { + $this->setStorage($config['storage']); + } + return $this; + } + + /** + * Send the response, including all headers. + * If you wish to handle this via Zend_Controller, use the getter methods + * to retrieve any data needed to be set on your HTTP Response object, or + * simply give this object the HTTP Response instance to work with for you! + * + * @return void + */ + public function sendResponse() + { + $this->getHttpResponse()->sendResponse(); + } + + /** + * Sets an instance of Zend_Feed_Pubsubhubbub_Model_SubscriptionInterface used + * to background save any verification tokens associated with a subscription + * or other. + * + * @param Zend_Feed_Pubsubhubbub_Model_SubscriptionInterface $storage + * @return Zend_Feed_Pubsubhubbub_CallbackAbstract + */ + public function setStorage(Zend_Feed_Pubsubhubbub_Model_SubscriptionInterface $storage) + { + $this->_storage = $storage; + return $this; + } + + /** + * Gets an instance of Zend_Feed_Pubsubhubbub_Model_SubscriptionInterface used + * to background save any verification tokens associated with a subscription + * or other. + * + * @return Zend_Feed_Pubsubhubbub_Model_SubscriptionInterface + */ + public function getStorage() + { + if ($this->_storage === null) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('No storage object has been' + . ' set that subclasses Zend_Feed_Pubsubhubbub_Model_SubscriptionInterface'); + } + return $this->_storage; + } + + /** + * An instance of a class handling Http Responses. This is implemented in + * Zend_Feed_Pubsubhubbub_HttpResponse which shares an unenforced interface with + * (i.e. not inherited from) Zend_Controller_Response_Http. + * + * @param Zend_Feed_Pubsubhubbub_HttpResponse|Zend_Controller_Response_Http $httpResponse + * @return Zend_Feed_Pubsubhubbub_CallbackAbstract + */ + public function setHttpResponse($httpResponse) + { + if (!is_object($httpResponse) + || (!$httpResponse instanceof Zend_Feed_Pubsubhubbub_HttpResponse + && !$httpResponse instanceof Zend_Controller_Response_Http) + ) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('HTTP Response object must' + . ' implement one of Zend_Feed_Pubsubhubbub_HttpResponse or' + . ' Zend_Controller_Response_Http'); + } + $this->_httpResponse = $httpResponse; + return $this; + } + + /** + * An instance of a class handling Http Responses. This is implemented in + * Zend_Feed_Pubsubhubbub_HttpResponse which shares an unenforced interface with + * (i.e. not inherited from) Zend_Controller_Response_Http. + * + * @return Zend_Feed_Pubsubhubbub_HttpResponse|Zend_Controller_Response_Http + */ + public function getHttpResponse() + { + if ($this->_httpResponse === null) { + $this->_httpResponse = new Zend_Feed_Pubsubhubbub_HttpResponse; + } + return $this->_httpResponse; + } + + /** + * Sets the number of Subscribers for which any updates are on behalf of. + * In other words, is this class serving one or more subscribers? How many? + * Defaults to 1 if left unchanged. + * + * @param string|int $count + * @return Zend_Feed_Pubsubhubbub_CallbackAbstract + */ + public function setSubscriberCount($count) + { + $count = intval($count); + if ($count <= 0) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('Subscriber count must be' + . ' greater than zero'); + } + $this->_subscriberCount = $count; + return $this; + } + + /** + * Gets the number of Subscribers for which any updates are on behalf of. + * In other words, is this class serving one or more subscribers? How many? + * + * @return int + */ + public function getSubscriberCount() + { + return $this->_subscriberCount; + } + + /** + * Attempt to detect the callback URL (specifically the path forward) + */ + protected function _detectCallbackUrl() + { + $callbackUrl = ''; + if (isset($_SERVER['HTTP_X_REWRITE_URL'])) { + $callbackUrl = $_SERVER['HTTP_X_REWRITE_URL']; + } elseif (isset($_SERVER['REQUEST_URI'])) { + $callbackUrl = $_SERVER['REQUEST_URI']; + $scheme = 'http'; + if ($_SERVER['HTTPS'] == 'on') { + $scheme = 'https'; + } + $schemeAndHttpHost = $scheme . '://' . $this->_getHttpHost(); + if (strpos($callbackUrl, $schemeAndHttpHost) === 0) { + $callbackUrl = substr($callbackUrl, strlen($schemeAndHttpHost)); + } + } elseif (isset($_SERVER['ORIG_PATH_INFO'])) { + $callbackUrl= $_SERVER['ORIG_PATH_INFO']; + if (!empty($_SERVER['QUERY_STRING'])) { + $callbackUrl .= '?' . $_SERVER['QUERY_STRING']; + } + } + return $callbackUrl; + } + + /** + * Get the HTTP host + * + * @return string + */ + protected function _getHttpHost() + { + if (!empty($_SERVER['HTTP_HOST'])) { + return $_SERVER['HTTP_HOST']; + } + $scheme = 'http'; + if ($_SERVER['HTTPS'] == 'on') { + $scheme = 'https'; + } + $name = $_SERVER['SERVER_NAME']; + $port = $_SERVER['SERVER_PORT']; + if (($scheme == 'http' && $port == 80) + || ($scheme == 'https' && $port == 443) + ) { + return $name; + } else { + return $name . ':' . $port; + } + } + + /** + * Retrieve a Header value from either $_SERVER or Apache + * + * @param string $header + */ + protected function _getHeader($header) + { + $temp = strtoupper(str_replace('-', '_', $header)); + if (!empty($_SERVER[$temp])) { + return $_SERVER[$temp]; + } + $temp = 'HTTP_' . strtoupper(str_replace('-', '_', $header)); + if (!empty($_SERVER[$temp])) { + return $_SERVER[$temp]; + } + if (function_exists('apache_request_headers')) { + $headers = apache_request_headers(); + if (!empty($headers[$header])) { + return $headers[$header]; + } + } + return false; + } + + /** + * Return the raw body of the request + * + * @return string|false Raw body, or false if not present + */ + protected function _getRawBody() + { + $body = file_get_contents('php://input'); + if (strlen(trim($body)) == 0 && isset($GLOBALS['HTTP_RAW_POST_DATA'])) { + $body = $GLOBALS['HTTP_RAW_POST_DATA']; + } + if (strlen(trim($body)) > 0) { + return $body; + } + return false; + } +} diff --git a/libs/Zend/Feed/Pubsubhubbub/CallbackInterface.php b/libs/Zend/Feed/Pubsubhubbub/CallbackInterface.php new file mode 100644 index 0000000000..ce30a6bb23 --- /dev/null +++ b/libs/Zend/Feed/Pubsubhubbub/CallbackInterface.php @@ -0,0 +1,68 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Pubsubhubbub + * @subpackage Callback + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * @category Zend + * @package Zend_Feed_Pubsubhubbub + * @subpackage Callback + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +interface Zend_Feed_Pubsubhubbub_CallbackInterface +{ + /** + * Handle any callback from a Hub Server responding to a subscription or + * unsubscription request. This should be the Hub Server confirming the + * the request prior to taking action on it. + * + * @param array $httpData GET/POST data if available and not in $_GET/POST + * @param bool $sendResponseNow Whether to send response now or when asked + */ + public function handle(array $httpData = null, $sendResponseNow = false); + + /** + * Send the response, including all headers. + * If you wish to handle this via Zend_Controller, use the getter methods + * to retrieve any data needed to be set on your HTTP Response object, or + * simply give this object the HTTP Response instance to work with for you! + * + * @return void + */ + public function sendResponse(); + + /** + * An instance of a class handling Http Responses. This is implemented in + * Zend_Feed_Pubsubhubbub_HttpResponse which shares an unenforced interface with + * (i.e. not inherited from) Zend_Controller_Response_Http. + * + * @param Zend_Feed_Pubsubhubbub_HttpResponse|Zend_Controller_Response_Http $httpResponse + */ + public function setHttpResponse($httpResponse); + + /** + * An instance of a class handling Http Responses. This is implemented in + * Zend_Feed_Pubsubhubbub_HttpResponse which shares an unenforced interface with + * (i.e. not inherited from) Zend_Controller_Response_Http. + * + * @return Zend_Feed_Pubsubhubbub_HttpResponse|Zend_Controller_Response_Http + */ + public function getHttpResponse(); +} diff --git a/libs/Zend/Feed/Pubsubhubbub/Exception.php b/libs/Zend/Feed/Pubsubhubbub/Exception.php new file mode 100644 index 0000000000..5bc562c94e --- /dev/null +++ b/libs/Zend/Feed/Pubsubhubbub/Exception.php @@ -0,0 +1,33 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Pubsubhubbub + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * @see Zend_Exception + */ +// require_once 'Zend/Exception.php'; + +/** + * @category Zend + * @package Zend_Feed_Pubsubhubbub + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Pubsubhubbub_Exception extends Zend_Exception +{} diff --git a/libs/Zend/Feed/Pubsubhubbub/HttpResponse.php b/libs/Zend/Feed/Pubsubhubbub/HttpResponse.php new file mode 100644 index 0000000000..e44f0eb86a --- /dev/null +++ b/libs/Zend/Feed/Pubsubhubbub/HttpResponse.php @@ -0,0 +1,233 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Pubsubhubbub + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * @see Zend_Feed_Pubsubhubbub + */ +// require_once 'Zend/Feed/Pubsubhubbub.php'; + +/** + * @category Zend + * @package Zend_Feed_Pubsubhubbub + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Pubsubhubbub_HttpResponse +{ + /** + * The body of any response to the current callback request + * + * @var string + */ + protected $_body = ''; + + /** + * Array of headers. Each header is an array with keys 'name' and 'value' + * + * @var array + */ + protected $_headers = array(); + + /** + * HTTP response code to use in headers + * + * @var int + */ + protected $_httpResponseCode = 200; + + /** + * Send the response, including all headers + * + * @return void + */ + public function sendResponse() + { + $this->sendHeaders(); + echo $this->getBody(); + } + + /** + * Send all headers + * + * Sends any headers specified. If an {@link setHttpResponseCode() HTTP response code} + * has been specified, it is sent with the first header. + * + * @return void + */ + public function sendHeaders() + { + if (count($this->_headers) || (200 != $this->_httpResponseCode)) { + $this->canSendHeaders(true); + } elseif (200 == $this->_httpResponseCode) { + return; + } + $httpCodeSent = false; + foreach ($this->_headers as $header) { + if (!$httpCodeSent && $this->_httpResponseCode) { + header($header['name'] . ': ' . $header['value'], $header['replace'], $this->_httpResponseCode); + $httpCodeSent = true; + } else { + header($header['name'] . ': ' . $header['value'], $header['replace']); + } + } + if (!$httpCodeSent) { + header('HTTP/1.1 ' . $this->_httpResponseCode); + $httpCodeSent = true; + } + } + + /** + * Set a header + * + * If $replace is true, replaces any headers already defined with that + * $name. + * + * @param string $name + * @param string $value + * @param boolean $replace + * @return Zend_Feed_Pubsubhubbub_HttpResponse + */ + public function setHeader($name, $value, $replace = false) + { + $name = $this->_normalizeHeader($name); + $value = (string) $value; + if ($replace) { + foreach ($this->_headers as $key => $header) { + if ($name == $header['name']) { + unset($this->_headers[$key]); + } + } + } + $this->_headers[] = array( + 'name' => $name, + 'value' => $value, + 'replace' => $replace, + ); + + return $this; + } + + /** + * Check if a specific Header is set and return its value + * + * @param string $name + * @return string|null + */ + public function getHeader($name) + { + $name = $this->_normalizeHeader($name); + foreach ($this->_headers as $header) { + if ($header['name'] == $name) { + return $header['value']; + } + } + } + + /** + * Return array of headers; see {@link $_headers} for format + * + * @return array + */ + public function getHeaders() + { + return $this->_headers; + } + + /** + * Can we send headers? + * + * @param boolean $throw Whether or not to throw an exception if headers have been sent; defaults to false + * @return boolean + * @throws Zend_Feed_Pubsubhubbub_Exception + */ + public function canSendHeaders($throw = false) + { + $ok = headers_sent($file, $line); + if ($ok && $throw) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('Cannot send headers; headers already sent in ' . $file . ', line ' . $line); + } + return !$ok; + } + + /** + * Set HTTP response code to use with headers + * + * @param int $code + * @return Zend_Feed_Pubsubhubbub_HttpResponse + */ + public function setHttpResponseCode($code) + { + if (!is_int($code) || (100 > $code) || (599 < $code)) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('Invalid HTTP response' + . ' code:' . $code); + } + $this->_httpResponseCode = $code; + return $this; + } + + /** + * Retrieve HTTP response code + * + * @return int + */ + public function getHttpResponseCode() + { + return $this->_httpResponseCode; + } + + /** + * Set body content + * + * @param string $content + * @return Zend_Feed_Pubsubhubbub_HttpResponse + */ + public function setBody($content) + { + $this->_body = (string) $content; + $this->setHeader('content-length', strlen($content)); + return $this; + } + + /** + * Return the body content + * + * @return string + */ + public function getBody() + { + return $this->_body; + } + + /** + * Normalizes a header name to X-Capitalized-Names + * + * @param string $name + * @return string + */ + protected function _normalizeHeader($name) + { + $filtered = str_replace(array('-', '_'), ' ', (string) $name); + $filtered = ucwords(strtolower($filtered)); + $filtered = str_replace(' ', '-', $filtered); + return $filtered; + } +} diff --git a/libs/Zend/Feed/Pubsubhubbub/Model/ModelAbstract.php b/libs/Zend/Feed/Pubsubhubbub/Model/ModelAbstract.php new file mode 100644 index 0000000000..eab4b56322 --- /dev/null +++ b/libs/Zend/Feed/Pubsubhubbub/Model/ModelAbstract.php @@ -0,0 +1,64 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Pubsubhubbub + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + + +/** @see Zend_Db_Table */ +// require_once 'Zend/Db/Table.php'; + +/** + * @see Zend_Registry + * Seems to fix the file not being included by Zend_Db_Table... + */ +// require_once 'Zend/Registry.php'; + +/** + * @category Zend + * @package Zend_Feed_Pubsubhubbub + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Pubsubhubbub_Model_ModelAbstract +{ + /** + * Zend_Db_Table instance to host database methods + * + * @var Zend_Db_Table + */ + protected $_db = null; + + /** + * Constructor + * + * @param array $data + * @param Zend_Db_Table_Abstract $tableGateway + * @return void + */ + public function __construct(Zend_Db_Table_Abstract $tableGateway = null) + { + if (is_null($tableGateway)) { + $parts = explode('_', get_class($this)); + $table = strtolower(array_pop($parts)); + $this->_db = new Zend_Db_Table($table); + } else { + $this->_db = $tableGateway; + } + } + +} diff --git a/libs/Zend/Feed/Pubsubhubbub/Model/Subscription.php b/libs/Zend/Feed/Pubsubhubbub/Model/Subscription.php new file mode 100644 index 0000000000..ea971b4f77 --- /dev/null +++ b/libs/Zend/Feed/Pubsubhubbub/Model/Subscription.php @@ -0,0 +1,131 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Pubsubhubbub + * @subpackage Entity + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** @see Zend_Feed_Pubsubhubbub_Model_ModelAbstract */ +// require_once 'Zend/Feed/Pubsubhubbub/Model/ModelAbstract.php'; + +/** @see Zend_Feed_Pubsubhubbub_Model_SubscriptionInterface */ +// require_once 'Zend/Feed/Pubsubhubbub/Model/SubscriptionInterface.php'; + +/** + * @category Zend + * @package Zend_Feed_Pubsubhubbub + * @subpackage Entity + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Pubsubhubbub_Model_Subscription + extends Zend_Feed_Pubsubhubbub_Model_ModelAbstract + implements Zend_Feed_Pubsubhubbub_Model_SubscriptionInterface +{ + + /** + * Save subscription to RDMBS + * + * @param array $data + * @return bool + */ + public function setSubscription(array $data) + { + if (!isset($data['id'])) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception( + 'ID must be set before attempting a save' + ); + } + $result = $this->_db->find($data['id']); + if ($result) { + $data['created_time'] = $result->current()->created_time; + $now = new Zend_Date; + if ($data['lease_seconds']) { + $data['expiration_time'] = $now->add($data['lease_seconds'], Zend_Date::SECOND) + ->get('yyyy-MM-dd HH:mm:ss'); + } + $this->_db->update( + $data, + $this->_db->getAdapter()->quoteInto('id = ?', $data['id']) + ); + return false; + } + + $this->_db->insert($data); + return true; + } + + /** + * Get subscription by ID/key + * + * @param string $key + * @return array + */ + public function getSubscription($key) + { + if (empty($key) || !is_string($key)) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('Invalid parameter "key"' + .' of "' . $key . '" must be a non-empty string'); + } + $result = $this->_db->find($key); + if ($result) { + return (array) $result->current(); + } + return false; + } + + /** + * Determine if a subscription matching the key exists + * + * @param string $key + * @return bool + */ + public function hasSubscription($key) + { + if (empty($key) || !is_string($key)) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('Invalid parameter "key"' + .' of "' . $key . '" must be a non-empty string'); + } + $result = $this->_db->find($key); + if ($result) { + return true; + } + return false; + } + + /** + * Delete a subscription + * + * @param string $key + * @return bool + */ + public function deleteSubscription($key) + { + $result = $this->_db->find($key); + if ($result) { + $this->_db->delete( + $this->_db->getAdapter()->quoteInto('id = ?', $key) + ); + return true; + } + return false; + } + +} diff --git a/libs/Zend/Feed/Pubsubhubbub/Model/SubscriptionInterface.php b/libs/Zend/Feed/Pubsubhubbub/Model/SubscriptionInterface.php new file mode 100644 index 0000000000..f8a6e6a3e3 --- /dev/null +++ b/libs/Zend/Feed/Pubsubhubbub/Model/SubscriptionInterface.php @@ -0,0 +1,64 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Pubsubhubbub + * @subpackage Entity + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * @category Zend + * @package Zend_Feed_Pubsubhubbub + * @subpackage Entity + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +interface Zend_Feed_Pubsubhubbub_Model_SubscriptionInterface +{ + + /** + * Save subscription to RDMBS + * + * @param array $data The key must be stored here as a $data['id'] entry + * @return bool + */ + public function setSubscription(array $data); + + /** + * Get subscription by ID/key + * + * @param string $key + * @return array + */ + public function getSubscription($key); + + /** + * Determine if a subscription matching the key exists + * + * @param string $key + * @return bool + */ + public function hasSubscription($key); + + /** + * Delete a subscription + * + * @param string $key + * @return bool + */ + public function deleteSubscription($key); + +} diff --git a/libs/Zend/Feed/Pubsubhubbub/Publisher.php b/libs/Zend/Feed/Pubsubhubbub/Publisher.php new file mode 100644 index 0000000000..dfc388beca --- /dev/null +++ b/libs/Zend/Feed/Pubsubhubbub/Publisher.php @@ -0,0 +1,417 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Pubsubhubbub + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * @see Zend_Feed_Pubsubhubbub + */ +// require_once 'Zend/Feed/Pubsubhubbub.php'; + +/** + * @category Zend + * @package Zend_Feed_Pubsubhubbub + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Pubsubhubbub_Publisher +{ + /** + * An array of URLs for all Hub Servers used by the Publisher, and to + * which all topic update notifications will be sent. + * + * @var array + */ + protected $_hubUrls = array(); + + /** + * An array of topic (Atom or RSS feed) URLs which have been updated and + * whose updated status will be notified to all Hub Servers. + * + * @var array + */ + protected $_updatedTopicUrls = array(); + + /** + * An array of any errors including keys for 'response', 'hubUrl'. + * The response is the actual Zend_Http_Response object. + * + * @var array + */ + protected $_errors = array(); + + /** + * An array of topic (Atom or RSS feed) URLs which have been updated and + * whose updated status will be notified to all Hub Servers. + * + * @var array + */ + protected $_parameters = array(); + + /** + * Constructor; accepts an array or Zend_Config instance to preset + * options for the Publisher without calling all supported setter + * methods in turn. + * + * @param array|Zend_Config $options Options array or Zend_Config instance + * @return void + */ + public function __construct($config = null) + { + if (!is_null($config)) { + $this->setConfig($config); + } + } + + /** + * Process any injected configuration options + * + * @param array|Zend_Config $options Options array or Zend_Config instance + * @return Zend_Feed_Pubsubhubbub_Publisher + */ + public function setConfig($config) + { + if ($config instanceof Zend_Config) { + $config = $config->toArray(); + } elseif (!is_array($config)) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('Array or Zend_Config object' + . 'expected, got ' . gettype($config)); + } + if (array_key_exists('hubUrls', $config)) { + $this->addHubUrls($config['hubUrls']); + } + if (array_key_exists('updatedTopicUrls', $config)) { + $this->addUpdatedTopicUrls($config['updatedTopicUrls']); + } + if (array_key_exists('parameters', $config)) { + $this->setParameters($config['parameters']); + } + return $this; + } + + /** + * Add a Hub Server URL supported by Publisher + * + * @param string $url + * @return Zend_Feed_Pubsubhubbub_Publisher + */ + public function addHubUrl($url) + { + if (empty($url) || !is_string($url) || !Zend_Uri::check($url)) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('Invalid parameter "url"' + .' of "' . $url . '" must be a non-empty string and a valid' + .'URL'); + } + $this->_hubUrls[] = $url; + return $this; + } + + /** + * Add an array of Hub Server URLs supported by Publisher + * + * @param array $urls + * @return Zend_Feed_Pubsubhubbub_Publisher + */ + public function addHubUrls(array $urls) + { + foreach ($urls as $url) { + $this->addHubUrl($url); + } + return $this; + } + + /** + * Remove a Hub Server URL + * + * @param string $url + * @return Zend_Feed_Pubsubhubbub_Publisher + */ + public function removeHubUrl($url) + { + if (!in_array($url, $this->getHubUrls())) { + return $this; + } + $key = array_search($url, $this->_hubUrls); + unset($this->_hubUrls[$key]); + return $this; + } + + /** + * Return an array of unique Hub Server URLs currently available + * + * @return array + */ + public function getHubUrls() + { + $this->_hubUrls = array_unique($this->_hubUrls); + return $this->_hubUrls; + } + + /** + * Add a URL to a topic (Atom or RSS feed) which has been updated + * + * @param string $url + * @return Zend_Feed_Pubsubhubbub_Publisher + */ + public function addUpdatedTopicUrl($url) + { + if (empty($url) || !is_string($url) || !Zend_Uri::check($url)) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('Invalid parameter "url"' + .' of "' . $url . '" must be a non-empty string and a valid' + .'URL'); + } + $this->_updatedTopicUrls[] = $url; + return $this; + } + + /** + * Add an array of Topic URLs which have been updated + * + * @param array $urls + * @return Zend_Feed_Pubsubhubbub_Publisher + */ + public function addUpdatedTopicUrls(array $urls) + { + foreach ($urls as $url) { + $this->addUpdatedTopicUrl($url); + } + return $this; + } + + /** + * Remove an updated topic URL + * + * @param string $url + * @return Zend_Feed_Pubsubhubbub_Publisher + */ + public function removeUpdatedTopicUrl($url) + { + if (!in_array($url, $this->getUpdatedTopicUrls())) { + return $this; + } + $key = array_search($url, $this->_updatedTopicUrls); + unset($this->_updatedTopicUrls[$key]); + return $this; + } + + /** + * Return an array of unique updated topic URLs currently available + * + * @return array + */ + public function getUpdatedTopicUrls() + { + $this->_updatedTopicUrls = array_unique($this->_updatedTopicUrls); + return $this->_updatedTopicUrls; + } + + /** + * Notifies a single Hub Server URL of changes + * + * @param string $url The Hub Server's URL + * @return void + * @throws Zend_Feed_Pubsubhubbub_Exception Thrown on failure + */ + public function notifyHub($url) + { + if (empty($url) || !is_string($url) || !Zend_Uri::check($url)) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('Invalid parameter "url"' + .' of "' . $url . '" must be a non-empty string and a valid' + .'URL'); + } + $client = $this->_getHttpClient(); + $client->setUri($url); + $response = $client->request(); + if ($response->getStatus() !== 204) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('Notification to Hub Server ' + . 'at "' . $url . '" appears to have failed with a status code of "' + . $response->getStatus() . '" and message "' + . $response->getMessage() . '"'); + } + } + + /** + * Notifies all Hub Server URLs of changes + * + * If a Hub notification fails, certain data will be retained in an + * an array retrieved using getErrors(), if a failure occurs for any Hubs + * the isSuccess() check will return FALSE. This method is designed not + * to needlessly fail with an Exception/Error unless from Zend_Http_Client. + * + * @return void + * @throws Zend_Feed_Pubsubhubbub_Exception Thrown if no hubs attached + */ + public function notifyAll() + { + $client = $this->_getHttpClient(); + $hubs = $this->getHubUrls(); + if (empty($hubs)) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('No Hub Server URLs' + . ' have been set so no notifcations can be sent'); + } + $this->_errors = array(); + foreach ($hubs as $url) { + $client->setUri($url); + $response = $client->request(); + if ($response->getStatus() !== 204) { + $this->_errors[] = array( + 'response' => $response, + 'hubUrl' => $url + ); + } + } + } + + /** + * Add an optional parameter to the update notification requests + * + * @param string $name + * @param string|null $value + * @return Zend_Feed_Pubsubhubbub_Publisher + */ + public function setParameter($name, $value = null) + { + if (is_array($name)) { + $this->setParameters($name); + return $this; + } + if (empty($name) || !is_string($name)) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('Invalid parameter "name"' + .' of "' . $name . '" must be a non-empty string'); + } + if ($value === null) { + $this->removeParameter($name); + return $this; + } + if (empty($value) || (!is_string($value) && !is_null($value))) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('Invalid parameter "value"' + .' of "' . $value . '" must be a non-empty string'); + } + $this->_parameters[$name] = $value; + return $this; + } + + /** + * Add an optional parameter to the update notification requests + * + * @param array $parameters + * @return Zend_Feed_Pubsubhubbub_Publisher + */ + public function setParameters(array $parameters) + { + foreach ($parameters as $name => $value) { + $this->setParameter($name, $value); + } + return $this; + } + + /** + * Remove an optional parameter for the notification requests + * + * @param string $name + * @return Zend_Feed_Pubsubhubbub_Publisher + */ + public function removeParameter($name) + { + if (empty($name) || !is_string($name)) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('Invalid parameter "name"' + .' of "' . $name . '" must be a non-empty string'); + } + if (array_key_exists($name, $this->_parameters)) { + unset($this->_parameters[$name]); + } + return $this; + } + + /** + * Return an array of optional parameters for notification requests + * + * @return array + */ + public function getParameters() + { + return $this->_parameters; + } + + /** + * Returns a boolean indicator of whether the notifications to Hub + * Servers were ALL successful. If even one failed, FALSE is returned. + * + * @return bool + */ + public function isSuccess() + { + if (count($this->_errors) > 0) { + return false; + } + return true; + } + + /** + * Return an array of errors met from any failures, including keys: + * 'response' => the Zend_Http_Response object from the failure + * 'hubUrl' => the URL of the Hub Server whose notification failed + * + * @return array + */ + public function getErrors() + { + return $this->_errors; + } + + /** + * Get a basic prepared HTTP client for use + * + * @return Zend_Http_Client + */ + protected function _getHttpClient() + { + $client = Zend_Feed_Pubsubhubbub::getHttpClient(); + $client->setMethod(Zend_Http_Client::POST); + $client->setConfig(array( + 'useragent' => 'Zend_Feed_Pubsubhubbub_Publisher/' . Zend_Version::VERSION, + )); + $params = array(); + $params[] = 'hub.mode=publish'; + $topics = $this->getUpdatedTopicUrls(); + if (empty($topics)) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('No updated topic URLs' + . ' have been set'); + } + foreach ($topics as $topicUrl) { + $params[] = 'hub.url=' . urlencode($topicUrl); + } + $optParams = $this->getParameters(); + foreach ($optParams as $name => $value) { + $params[] = urlencode($name) . '=' . urlencode($value); + } + $paramString = implode('&', $params); + $client->setRawData($paramString); + return $client; + } +} diff --git a/libs/Zend/Feed/Pubsubhubbub/Subscriber.php b/libs/Zend/Feed/Pubsubhubbub/Subscriber.php new file mode 100644 index 0000000000..9921bce594 --- /dev/null +++ b/libs/Zend/Feed/Pubsubhubbub/Subscriber.php @@ -0,0 +1,856 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Pubsubhubbub + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * @see Zend_Feed_Pubsubhubbub + */ +// require_once 'Zend/Feed/Pubsubhubbub.php'; + +/** + * @see Zend_Date + */ +// require_once 'Zend/Date.php'; + +/** + * @category Zend + * @package Zend_Feed_Pubsubhubbub + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Pubsubhubbub_Subscriber +{ + /** + * An array of URLs for all Hub Servers to subscribe/unsubscribe. + * + * @var array + */ + protected $_hubUrls = array(); + + /** + * An array of optional parameters to be included in any + * (un)subscribe requests. + * + * @var array + */ + protected $_parameters = array(); + + /** + * The URL of the topic (Rss or Atom feed) which is the subject of + * our current intent to subscribe to/unsubscribe from updates from + * the currently configured Hub Servers. + * + * @var string + */ + protected $_topicUrl = ''; + + /** + * The URL Hub Servers must use when communicating with this Subscriber + * + * @var string + */ + protected $_callbackUrl = ''; + + /** + * The number of seconds for which the subscriber would like to have the + * subscription active. Defaults to null, i.e. not sent, to setup a + * permanent subscription if possible. + * + * @var int + */ + protected $_leaseSeconds = null; + + /** + * The preferred verification mode (sync or async). By default, this + * Subscriber prefers synchronous verification, but is considered + * desireable to support asynchronous verification if possible. + * + * Zend_Feed_Pubsubhubbub_Subscriber will always send both modes, whose + * order of occurance in the parameter list determines this preference. + * + * @var string + */ + protected $_preferredVerificationMode + = Zend_Feed_Pubsubhubbub::VERIFICATION_MODE_SYNC; + + /** + * An array of any errors including keys for 'response', 'hubUrl'. + * The response is the actual Zend_Http_Response object. + * + * @var array + */ + protected $_errors = array(); + + /** + * An array of Hub Server URLs for Hubs operating at this time in + * asynchronous verification mode. + * + * @var array + */ + protected $_asyncHubs = array(); + + /** + * An instance of Zend_Feed_Pubsubhubbub_Model_SubscriptionInterface used to background + * save any verification tokens associated with a subscription or other. + * + * @var Zend_Feed_Pubsubhubbub_Model_SubscriptionInterface + */ + protected $_storage = null; + + /** + * An array of authentication credentials for HTTP Basic Authentication + * if required by specific Hubs. The array is indexed by Hub Endpoint URI + * and the value is a simple array of the username and password to apply. + * + * @var array + */ + protected $_authentications = array(); + + /** + * Tells the Subscriber to append any subscription identifier to the path + * of the base Callback URL. E.g. an identifier "subkey1" would be added + * to the callback URL "http://www.example.com/callback" to create a subscription + * specific Callback URL of "http://www.example.com/callback/subkey1". + * + * This is required for all Hubs using the Pubsubhubbub 0.1 Specification. + * It should be manually intercepted and passed to the Callback class using + * Zend_Feed_Pubsubhubbub_Subscriber_Callback::setSubscriptionKey(). Will + * require a route in the form "callback/:subkey" to allow the parameter be + * retrieved from an action using the Zend_Controller_Action::_getParam() + * method. + * + * @var string + */ + protected $_usePathParameter = false; + + /** + * Constructor; accepts an array or Zend_Config instance to preset + * options for the Subscriber without calling all supported setter + * methods in turn. + * + * @param array|Zend_Config $options Options array or Zend_Config instance + * @return void + */ + public function __construct($config = null) + { + if (!is_null($config)) { + $this->setConfig($config); + } + } + + /** + * Process any injected configuration options + * + * @param array|Zend_Config $options Options array or Zend_Config instance + * @return Zend_Feed_Pubsubhubbub_Subscriber + */ + public function setConfig($config) + { + if ($config instanceof Zend_Config) { + $config = $config->toArray(); + } elseif (!is_array($config)) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('Array or Zend_Config object' + . ' expected, got ' . gettype($config)); + } + if (array_key_exists('hubUrls', $config)) { + $this->addHubUrls($config['hubUrls']); + } + if (array_key_exists('callbackUrl', $config)) { + $this->setCallbackUrl($config['callbackUrl']); + } + if (array_key_exists('topicUrl', $config)) { + $this->setTopicUrl($config['topicUrl']); + } + if (array_key_exists('storage', $config)) { + $this->setStorage($config['storage']); + } + if (array_key_exists('leaseSeconds', $config)) { + $this->setLeaseSeconds($config['leaseSeconds']); + } + if (array_key_exists('parameters', $config)) { + $this->setParameters($config['parameters']); + } + if (array_key_exists('authentications', $config)) { + $this->addAuthentications($config['authentications']); + } + if (array_key_exists('usePathParameter', $config)) { + $this->usePathParameter($config['usePathParameter']); + } + if (array_key_exists('preferredVerificationMode', $config)) { + $this->setPreferredVerificationMode( + $config['preferredVerificationMode'] + ); + } + return $this; + } + + /** + * Set the topic URL (RSS or Atom feed) to which the intended (un)subscribe + * event will relate + * + * @param string $url + * @return Zend_Feed_Pubsubhubbub_Subscriber + */ + public function setTopicUrl($url) + { + if (empty($url) || !is_string($url) || !Zend_Uri::check($url)) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('Invalid parameter "url"' + .' of "' . $url . '" must be a non-empty string and a valid' + .' URL'); + } + $this->_topicUrl = $url; + return $this; + } + + /** + * Set the topic URL (RSS or Atom feed) to which the intended (un)subscribe + * event will relate + * + * @return string + */ + public function getTopicUrl() + { + if (empty($this->_topicUrl)) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('A valid Topic (RSS or Atom' + . ' feed) URL MUST be set before attempting any operation'); + } + return $this->_topicUrl; + } + + /** + * Set the number of seconds for which any subscription will remain valid + * + * @param int $seconds + * @return Zend_Feed_Pubsubhubbub_Subscriber + */ + public function setLeaseSeconds($seconds) + { + $seconds = intval($seconds); + if ($seconds <= 0) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('Expected lease seconds' + . ' must be an integer greater than zero'); + } + $this->_leaseSeconds = $seconds; + return $this; + } + + /** + * Get the number of lease seconds on subscriptions + * + * @return int + */ + public function getLeaseSeconds() + { + return $this->_leaseSeconds; + } + + /** + * Set the callback URL to be used by Hub Servers when communicating with + * this Subscriber + * + * @param string $url + * @return Zend_Feed_Pubsubhubbub_Subscriber + */ + public function setCallbackUrl($url) + { + if (empty($url) || !is_string($url) || !Zend_Uri::check($url)) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('Invalid parameter "url"' + . ' of "' . $url . '" must be a non-empty string and a valid' + . ' URL'); + } + $this->_callbackUrl = $url; + return $this; + } + + /** + * Get the callback URL to be used by Hub Servers when communicating with + * this Subscriber + * + * @return string + */ + public function getCallbackUrl() + { + if (empty($this->_callbackUrl)) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('A valid Callback URL MUST be' + . ' set before attempting any operation'); + } + return $this->_callbackUrl; + } + + /** + * Set preferred verification mode (sync or async). By default, this + * Subscriber prefers synchronous verification, but does support + * asynchronous if that's the Hub Server's utilised mode. + * + * Zend_Feed_Pubsubhubbub_Subscriber will always send both modes, whose + * order of occurance in the parameter list determines this preference. + * + * @param string $mode Should be 'sync' or 'async' + * @return Zend_Feed_Pubsubhubbub_Subscriber + */ + public function setPreferredVerificationMode($mode) + { + if ($mode !== Zend_Feed_Pubsubhubbub::VERIFICATION_MODE_SYNC + && $mode !== Zend_Feed_Pubsubhubbub::VERIFICATION_MODE_ASYNC) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('Invalid preferred' + . ' mode specified: "' . $mode . '" but should be one of' + . ' Zend_Feed_Pubsubhubbub::VERIFICATION_MODE_SYNC or' + . ' Zend_Feed_Pubsubhubbub::VERIFICATION_MODE_ASYNC'); + } + $this->_preferredVerificationMode = $mode; + return $this; + } + + /** + * Get preferred verification mode (sync or async). + * + * @return string + */ + public function getPreferredVerificationMode() + { + return $this->_preferredVerificationMode; + } + + /** + * Add a Hub Server URL supported by Publisher + * + * @param string $url + * @return Zend_Feed_Pubsubhubbub_Subscriber + */ + public function addHubUrl($url) + { + if (empty($url) || !is_string($url) || !Zend_Uri::check($url)) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('Invalid parameter "url"' + . ' of "' . $url . '" must be a non-empty string and a valid' + . ' URL'); + } + $this->_hubUrls[] = $url; + return $this; + } + + /** + * Add an array of Hub Server URLs supported by Publisher + * + * @param array $urls + * @return Zend_Feed_Pubsubhubbub_Subscriber + */ + public function addHubUrls(array $urls) + { + foreach ($urls as $url) { + $this->addHubUrl($url); + } + return $this; + } + + /** + * Remove a Hub Server URL + * + * @param string $url + * @return Zend_Feed_Pubsubhubbub_Subscriber + */ + public function removeHubUrl($url) + { + if (!in_array($url, $this->getHubUrls())) { + return $this; + } + $key = array_search($url, $this->_hubUrls); + unset($this->_hubUrls[$key]); + return $this; + } + + /** + * Return an array of unique Hub Server URLs currently available + * + * @return array + */ + public function getHubUrls() + { + $this->_hubUrls = array_unique($this->_hubUrls); + return $this->_hubUrls; + } + + /** + * Add authentication credentials for a given URL + * + * @param string $url + * @param array $authentication + * @return Zend_Feed_Pubsubhubbub_Subscriber + */ + public function addAuthentication($url, array $authentication) + { + if (empty($url) || !is_string($url) || !Zend_Uri::check($url)) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('Invalid parameter "url"' + . ' of "' . $url . '" must be a non-empty string and a valid' + . ' URL'); + } + $this->_authentications[$url] = $authentication; + return $this; + } + + /** + * Add authentication credentials for hub URLs + * + * @param array $authentications + * @return Zend_Feed_Pubsubhubbub_Subscriber + */ + public function addAuthentications(array $authentications) + { + foreach ($authentications as $url => $authentication) { + $this->addAuthentication($url, $authentication); + } + return $this; + } + + /** + * Get all hub URL authentication credentials + * + * @return array + */ + public function getAuthentications() + { + return $this->_authentications; + } + + /** + * Set flag indicating whether or not to use a path parameter + * + * @param bool $bool + * @return Zend_Feed_Pubsubhubbub_Subscriber + */ + public function usePathParameter($bool = true) + { + $this->_usePathParameter = $bool; + return $this; + } + + /** + * Add an optional parameter to the (un)subscribe requests + * + * @param string $name + * @param string|null $value + * @return Zend_Feed_Pubsubhubbub_Subscriber + */ + public function setParameter($name, $value = null) + { + if (is_array($name)) { + $this->setParameters($name); + return $this; + } + if (empty($name) || !is_string($name)) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('Invalid parameter "name"' + . ' of "' . $name . '" must be a non-empty string'); + } + if ($value === null) { + $this->removeParameter($name); + return $this; + } + if (empty($value) || (!is_string($value) && !is_null($value))) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('Invalid parameter "value"' + . ' of "' . $value . '" must be a non-empty string'); + } + $this->_parameters[$name] = $value; + return $this; + } + + /** + * Add an optional parameter to the (un)subscribe requests + * + * @param string $name + * @param string|null $value + * @return Zend_Feed_Pubsubhubbub_Subscriber + */ + public function setParameters(array $parameters) + { + foreach ($parameters as $name => $value) { + $this->setParameter($name, $value); + } + return $this; + } + + /** + * Remove an optional parameter for the (un)subscribe requests + * + * @param string $name + * @return Zend_Feed_Pubsubhubbub_Subscriber + */ + public function removeParameter($name) + { + if (empty($name) || !is_string($name)) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('Invalid parameter "name"' + . ' of "' . $name . '" must be a non-empty string'); + } + if (array_key_exists($name, $this->_parameters)) { + unset($this->_parameters[$name]); + } + return $this; + } + + /** + * Return an array of optional parameters for (un)subscribe requests + * + * @return array + */ + public function getParameters() + { + return $this->_parameters; + } + + /** + * Sets an instance of Zend_Feed_Pubsubhubbub_Model_SubscriptionInterface used to background + * save any verification tokens associated with a subscription or other. + * + * @param Zend_Feed_Pubsubhubbub_Model_SubscriptionInterface $storage + * @return Zend_Feed_Pubsubhubbub_Subscriber + */ + public function setStorage(Zend_Feed_Pubsubhubbub_Model_SubscriptionInterface $storage) + { + $this->_storage = $storage; + return $this; + } + + /** + * Gets an instance of Zend_Feed_Pubsubhubbub_Storage_StorageInterface used + * to background save any verification tokens associated with a subscription + * or other. + * + * @return Zend_Feed_Pubsubhubbub_Model_SubscriptionInterface + */ + public function getStorage() + { + if ($this->_storage === null) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('No storage vehicle ' + . 'has been set.'); + } + return $this->_storage; + } + + /** + * Subscribe to one or more Hub Servers using the stored Hub URLs + * for the given Topic URL (RSS or Atom feed) + * + * @return void + */ + public function subscribeAll() + { + return $this->_doRequest('subscribe'); + } + + /** + * Unsubscribe from one or more Hub Servers using the stored Hub URLs + * for the given Topic URL (RSS or Atom feed) + * + * @return void + */ + public function unsubscribeAll() + { + return $this->_doRequest('unsubscribe'); + } + + /** + * Returns a boolean indicator of whether the notifications to Hub + * Servers were ALL successful. If even one failed, FALSE is returned. + * + * @return bool + */ + public function isSuccess() + { + if (count($this->_errors) > 0) { + return false; + } + return true; + } + + /** + * Return an array of errors met from any failures, including keys: + * 'response' => the Zend_Http_Response object from the failure + * 'hubUrl' => the URL of the Hub Server whose notification failed + * + * @return array + */ + public function getErrors() + { + return $this->_errors; + } + + /** + * Return an array of Hub Server URLs who returned a response indicating + * operation in Asynchronous Verification Mode, i.e. they will not confirm + * any (un)subscription immediately but at a later time (Hubs may be + * doing this as a batch process when load balancing) + * + * @return array + */ + public function getAsyncHubs() + { + return $this->_asyncHubs; + } + + /** + * Executes an (un)subscribe request + * + * @param string $mode + * @return void + */ + protected function _doRequest($mode) + { + $client = $this->_getHttpClient(); + $hubs = $this->getHubUrls(); + if (empty($hubs)) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('No Hub Server URLs' + . ' have been set so no subscriptions can be attempted'); + } + $this->_errors = array(); + $this->_asyncHubs = array(); + foreach ($hubs as $url) { + if (array_key_exists($url, $this->_authentications)) { + $auth = $this->_authentications[$url]; + $client->setAuth($auth[0], $auth[1]); + } + $client->setUri($url); + $client->setRawData($this->_getRequestParameters($url, $mode)); + $response = $client->request(); + if ($response->getStatus() !== 204 + && $response->getStatus() !== 202 + ) { + $this->_errors[] = array( + 'response' => $response, + 'hubUrl' => $url, + ); + /** + * At first I thought it was needed, but the backend storage will + * allow tracking async without any user interference. It's left + * here in case the user is interested in knowing what Hubs + * are using async verification modes so they may update Models and + * move these to asynchronous processes. + */ + } elseif ($response->getStatus() == 202) { + $this->_asyncHubs[] = array( + 'response' => $response, + 'hubUrl' => $url, + ); + } + } + } + + /** + * Get a basic prepared HTTP client for use + * + * @param string $mode Must be "subscribe" or "unsubscribe" + * @return Zend_Http_Client + */ + protected function _getHttpClient() + { + $client = Zend_Feed_Pubsubhubbub::getHttpClient(); + $client->setMethod(Zend_Http_Client::POST); + $client->setConfig(array('useragent' => 'Zend_Feed_Pubsubhubbub_Subscriber/' + . Zend_Version::VERSION)); + return $client; + } + + /** + * Return a list of standard protocol/optional parameters for addition to + * client's POST body that are specific to the current Hub Server URL + * + * @param string $hubUrl + * @param mode $hubUrl + * @return string + */ + protected function _getRequestParameters($hubUrl, $mode) + { + if (!in_array($mode, array('subscribe', 'unsubscribe'))) { + // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; + throw new Zend_Feed_Pubsubhubbub_Exception('Invalid mode specified: "' + . $mode . '" which should have been "subscribe" or "unsubscribe"'); + } + + $params = array( + 'hub.mode' => $mode, + 'hub.topic' => $this->getTopicUrl(), + ); + + if ($this->getPreferredVerificationMode() + == Zend_Feed_Pubsubhubbub::VERIFICATION_MODE_SYNC + ) { + $vmodes = array( + Zend_Feed_Pubsubhubbub::VERIFICATION_MODE_SYNC, + Zend_Feed_Pubsubhubbub::VERIFICATION_MODE_ASYNC, + ); + } else { + $vmodes = array( + Zend_Feed_Pubsubhubbub::VERIFICATION_MODE_ASYNC, + Zend_Feed_Pubsubhubbub::VERIFICATION_MODE_SYNC, + ); + } + $params['hub.verify'] = array(); + foreach($vmodes as $vmode) { + $params['hub.verify'][] = $vmode; + } + + /** + * Establish a persistent verify_token and attach key to callback + * URL's path/querystring + */ + $key = $this->_generateSubscriptionKey($params, $hubUrl); + $token = $this->_generateVerifyToken(); + $params['hub.verify_token'] = $token; + + // Note: query string only usable with PuSH 0.2 Hubs + if (!$this->_usePathParameter) { + $params['hub.callback'] = $this->getCallbackUrl() + . '?xhub.subscription=' . Zend_Feed_Pubsubhubbub::urlencode($key); + } else { + $params['hub.callback'] = rtrim($this->getCallbackUrl(), '/') + . '/' . Zend_Feed_Pubsubhubbub::urlencode($key); + } + if ($mode == 'subscribe' && !is_null($this->getLeaseSeconds())) { + $params['hub.lease_seconds'] = $this->getLeaseSeconds(); + } + + // hub.secret not currently supported + $optParams = $this->getParameters(); + foreach ($optParams as $name => $value) { + $params[$name] = $value; + } + + // store subscription to storage + $now = new Zend_Date; + $expires = null; + if (isset($params['hub.lease_seconds'])) { + $expires = $now->add($params['hub.lease_seconds'], Zend_Date::SECOND) + ->get('yyyy-MM-dd HH:mm:ss'); + } + $data = array( + 'id' => $key, + 'topic_url' => $params['hub.topic'], + 'hub_url' => $hubUrl, + 'created_time' => $now->get('yyyy-MM-dd HH:mm:ss'), + 'lease_seconds' => $expires, + 'verify_token' => hash('sha256', $params['hub.verify_token']), + 'secret' => null, + 'expiration_time' => $expires, + 'subscription_state' => Zend_Feed_Pubsubhubbub::SUBSCRIPTION_NOTVERIFIED, + ); + $this->getStorage()->setSubscription($data); + + return $this->_toByteValueOrderedString( + $this->_urlEncode($params) + ); + } + + /** + * Simple helper to generate a verification token used in (un)subscribe + * requests to a Hub Server. Follows no particular method, which means + * it might be improved/changed in future. + * + * @param string $hubUrl The Hub Server URL for which this token will apply + * @return string + */ + protected function _generateVerifyToken() + { + if (!empty($this->_testStaticToken)) { + return $this->_testStaticToken; + } + return uniqid(rand(), true) . time(); + } + + /** + * Simple helper to generate a verification token used in (un)subscribe + * requests to a Hub Server. + * + * @param string $hubUrl The Hub Server URL for which this token will apply + * @return string + */ + protected function _generateSubscriptionKey(array $params, $hubUrl) + { + $keyBase = $params['hub.topic'] . $hubUrl; + $key = md5($keyBase); + return $key; + } + + /** + * URL Encode an array of parameters + * + * @param array $params + * @return array + */ + protected function _urlEncode(array $params) + { + $encoded = array(); + foreach ($params as $key => $value) { + if (is_array($value)) { + $ekey = Zend_Feed_Pubsubhubbub::urlencode($key); + $encoded[$ekey] = array(); + foreach ($value as $duplicateKey) { + $encoded[$ekey][] + = Zend_Feed_Pubsubhubbub::urlencode($duplicateKey); + } + } else { + $encoded[Zend_Feed_Pubsubhubbub::urlencode($key)] + = Zend_Feed_Pubsubhubbub::urlencode($value); + } + } + return $encoded; + } + + /** + * Order outgoing parameters + * + * @param array $params + * @return array + */ + protected function _toByteValueOrderedString(array $params) + { + $return = array(); + uksort($params, 'strnatcmp'); + foreach ($params as $key => $value) { + if (is_array($value)) { + foreach ($value as $keyduplicate) { + $return[] = $key . '=' . $keyduplicate; + } + } else { + $return[] = $key . '=' . $value; + } + } + return implode('&', $return); + } + + /** + * This is STRICTLY for testing purposes only... + */ + protected $_testStaticToken = null; + + final public function setTestStaticToken($token) + { + $this->_testStaticToken = (string) $token; + } +} diff --git a/libs/Zend/Feed/Pubsubhubbub/Subscriber/Callback.php b/libs/Zend/Feed/Pubsubhubbub/Subscriber/Callback.php new file mode 100644 index 0000000000..1f42375839 --- /dev/null +++ b/libs/Zend/Feed/Pubsubhubbub/Subscriber/Callback.php @@ -0,0 +1,328 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Pubsubhubbub + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * @see Zend_Feed_Pubsubhubbub + */ +// require_once 'Zend/Feed/Pubsubhubbub.php'; + +/** + * @see Zend_Feed_Pubsubhubbub + */ +// require_once 'Zend/Feed/Pubsubhubbub/CallbackAbstract.php'; + +/** + * @see Zend_Feed_Reader + */ +// require_once 'Zend/Feed/Reader.php'; + +/** + * @category Zend + * @package Zend_Feed_Pubsubhubbub + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Pubsubhubbub_Subscriber_Callback + extends Zend_Feed_Pubsubhubbub_CallbackAbstract +{ + /** + * Contains the content of any feeds sent as updates to the Callback URL + * + * @var string + */ + protected $_feedUpdate = null; + + /** + * Holds a manually set subscription key (i.e. identifies a unique + * subscription) which is typical when it is not passed in the query string + * but is part of the Callback URL path, requiring manual retrieval e.g. + * using a route and the Zend_Controller_Action::_getParam() method. + * + * @var string + */ + protected $_subscriptionKey = null; + + /** + * After verification, this is set to the verified subscription's data. + * + * @var array + */ + protected $_currentSubscriptionData = null; + + /** + * Set a subscription key to use for the current callback request manually. + * Required if usePathParameter is enabled for the Subscriber. + * + * @param string $key + * @return Zend_Feed_Pubsubhubbub_Subscriber_Callback + */ + public function setSubscriptionKey($key) + { + $this->_subscriptionKey = $key; + return $this; + } + + /** + * Handle any callback from a Hub Server responding to a subscription or + * unsubscription request. This should be the Hub Server confirming the + * the request prior to taking action on it. + * + * @param array $httpGetData GET data if available and not in $_GET + * @param bool $sendResponseNow Whether to send response now or when asked + * @return void + */ + public function handle(array $httpGetData = null, $sendResponseNow = false) + { + if ($httpGetData === null) { + $httpGetData = $_GET; + } + + /** + * Handle any feed updates (sorry for the mess :P) + * + * This DOES NOT attempt to process a feed update. Feed updates + * SHOULD be validated/processed by an asynchronous process so as + * to avoid holding up responses to the Hub. + */ + if (strtolower($_SERVER['REQUEST_METHOD']) == 'post' + && $this->_hasValidVerifyToken(null, false) + && ($this->_getHeader('Content-Type') == 'application/atom+xml' + || $this->_getHeader('Content-Type') == 'application/rss+xml' + || $this->_getHeader('Content-Type') == 'application/xml' + || $this->_getHeader('Content-Type') == 'text/xml' + || $this->_getHeader('Content-Type') == 'application/rdf+xml') + ) { + $this->setFeedUpdate($this->_getRawBody()); + $this->getHttpResponse() + ->setHeader('X-Hub-On-Behalf-Of', $this->getSubscriberCount()); + /** + * Handle any (un)subscribe confirmation requests + */ + } elseif ($this->isValidHubVerification($httpGetData)) { + $data = $this->_currentSubscriptionData; + $this->getHttpResponse()->setBody($httpGetData['hub_challenge']); + $data['subscription_state'] = Zend_Feed_Pubsubhubbub::SUBSCRIPTION_VERIFIED; + if (isset($httpGetData['hub_lease_seconds'])) { + $data['lease_seconds'] = $httpGetData['hub_lease_seconds']; + } + $this->getStorage()->setSubscription($data); + /** + * Hey, C'mon! We tried everything else! + */ + } else { + $this->getHttpResponse()->setHttpResponseCode(404); + } + if ($sendResponseNow) { + $this->sendResponse(); + } + } + + /** + * Checks validity of the request simply by making a quick pass and + * confirming the presence of all REQUIRED parameters. + * + * @param array $httpGetData + * @return bool + */ + public function isValidHubVerification(array $httpGetData) + { + /** + * As per the specification, the hub.verify_token is OPTIONAL. This + * implementation of Pubsubhubbub considers it REQUIRED and will + * always send a hub.verify_token parameter to be echoed back + * by the Hub Server. Therefore, its absence is considered invalid. + */ + if (strtolower($_SERVER['REQUEST_METHOD']) !== 'get') { + return false; + } + $required = array( + 'hub_mode', + 'hub_topic', + 'hub_challenge', + 'hub_verify_token', + ); + foreach ($required as $key) { + if (!array_key_exists($key, $httpGetData)) { + return false; + } + } + if ($httpGetData['hub_mode'] !== 'subscribe' + && $httpGetData['hub_mode'] !== 'unsubscribe' + ) { + return false; + } + if ($httpGetData['hub_mode'] == 'subscribe' + && !array_key_exists('hub_lease_seconds', $httpGetData) + ) { + return false; + } + if (!Zend_Uri::check($httpGetData['hub_topic'])) { + return false; + } + + /** + * Attempt to retrieve any Verification Token Key attached to Callback + * URL's path by our Subscriber implementation + */ + if (!$this->_hasValidVerifyToken($httpGetData)) { + return false; + } + return true; + } + + /** + * Sets a newly received feed (Atom/RSS) sent by a Hub as an update to a + * Topic we've subscribed to. + * + * @param string $feed + * @return Zend_Feed_Pubsubhubbub_Subscriber_Callback + */ + public function setFeedUpdate($feed) + { + $this->_feedUpdate = $feed; + return $this; + } + + /** + * Check if any newly received feed (Atom/RSS) update was received + * + * @return bool + */ + public function hasFeedUpdate() + { + if (is_null($this->_feedUpdate)) { + return false; + } + return true; + } + + /** + * Gets a newly received feed (Atom/RSS) sent by a Hub as an update to a + * Topic we've subscribed to. + * + * @return string + */ + public function getFeedUpdate() + { + return $this->_feedUpdate; + } + + /** + * Check for a valid verify_token. By default attempts to compare values + * with that sent from Hub, otherwise merely ascertains its existence. + * + * @param array $httpGetData + * @param bool $checkValue + * @return bool + */ + protected function _hasValidVerifyToken(array $httpGetData = null, $checkValue = true) + { + $verifyTokenKey = $this->_detectVerifyTokenKey($httpGetData); + if (empty($verifyTokenKey)) { + return false; + } + $verifyTokenExists = $this->getStorage()->hasSubscription($verifyTokenKey); + if (!$verifyTokenExists) { + return false; + } + if ($checkValue) { + $data = $this->getStorage()->getSubscription($verifyTokenKey); + $verifyToken = $data['verify_token']; + if ($verifyToken !== hash('sha256', $httpGetData['hub_verify_token'])) { + return false; + } + $this->_currentSubscriptionData = $data; + return true; + } + return true; + } + + /** + * Attempt to detect the verification token key. This would be passed in + * the Callback URL (which we are handling with this class!) as a URI + * path part (the last part by convention). + * + * @param null|array $httpGetData + * @return false|string + */ + protected function _detectVerifyTokenKey(array $httpGetData = null) + { + /** + * Available when sub keys encoding in Callback URL path + */ + if (isset($this->_subscriptionKey)) { + return $this->_subscriptionKey; + } + + /** + * Available only if allowed by PuSH 0.2 Hubs + */ + if (is_array($httpGetData) + && isset($httpGetData['xhub_subscription']) + ) { + return $httpGetData['xhub_subscription']; + } + + /** + * Available (possibly) if corrupted in transit and not part of $_GET + */ + $params = $this->_parseQueryString(); + if (isset($params['xhub.subscription'])) { + return rawurldecode($params['xhub.subscription']); + } + + return false; + } + + /** + * Build an array of Query String parameters. + * This bypasses $_GET which munges parameter names and cannot accept + * multiple parameters with the same key. + * + * @return array|void + */ + protected function _parseQueryString() + { + $params = array(); + $queryString = ''; + if (isset($_SERVER['QUERY_STRING'])) { + $queryString = $_SERVER['QUERY_STRING']; + } + if (empty($queryString)) { + return array(); + } + $parts = explode('&', $queryString); + foreach ($parts as $kvpair) { + $pair = explode('=', $kvpair); + $key = rawurldecode($pair[0]); + $value = rawurldecode($pair[1]); + if (isset($params[$key])) { + if (is_array($params[$key])) { + $params[$key][] = $value; + } else { + $params[$key] = array($params[$key], $value); + } + } else { + $params[$key] = $value; + } + } + return $params; + } +} diff --git a/libs/Zend/Feed/Reader.php b/libs/Zend/Feed/Reader.php index ced12cf7c7..26bf661cdf 100644 --- a/libs/Zend/Feed/Reader.php +++ b/libs/Zend/Feed/Reader.php @@ -14,49 +14,55 @@ * * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Reader.php 17391 2009-08-05 11:27:52Z padraic $ + * @version $Id: Reader.php 22093 2010-05-04 12:55:06Z padraic $ */ /** * @see Zend_Feed */ -require_once 'Zend/Feed.php'; +// require_once 'Zend/Feed.php'; /** * @see Zend_Feed_Reader_Feed_Rss */ -require_once 'Zend/Feed/Reader/Feed/Rss.php'; +// require_once 'Zend/Feed/Reader/Feed/Rss.php'; /** * @see Zend_Feed_Reader_Feed_Atom */ -require_once 'Zend/Feed/Reader/Feed/Atom.php'; +// require_once 'Zend/Feed/Reader/Feed/Atom.php'; + +/** + * @see Zend_Feed_Reader_FeedSet + */ +// require_once 'Zend/Feed/Reader/FeedSet.php'; /** * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Feed_Reader { - /** - * Namespace constants - */ - const NAMESPACE_ATOM_03 = 'http://purl.org/atom/ns#'; + /** + * Namespace constants + */ + const NAMESPACE_ATOM_03 = 'http://purl.org/atom/ns#'; const NAMESPACE_ATOM_10 = 'http://www.w3.org/2005/Atom'; const NAMESPACE_RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'; const NAMESPACE_RSS_090 = 'http://my.netscape.com/rdf/simple/0.9/'; const NAMESPACE_RSS_10 = 'http://purl.org/rss/1.0/'; /** - * Feed type constants - */ - const TYPE_ANY = 'any'; - const TYPE_ATOM_03 = 'atom-03'; + * Feed type constants + */ + const TYPE_ANY = 'any'; + const TYPE_ATOM_03 = 'atom-03'; const TYPE_ATOM_10 = 'atom-10'; + const TYPE_ATOM_10_ENTRY = 'atom-10-entry'; const TYPE_ATOM_ANY = 'atom'; const TYPE_RSS_090 = 'rss-090'; const TYPE_RSS_091 = 'rss-091'; @@ -161,7 +167,7 @@ class Zend_Feed_Reader /** * @see Zend_Http_Client */ - require_once 'Zend/Http/Client.php'; + // require_once 'Zend/Http/Client.php'; self::$_httpClient = new Zend_Http_Client(); } @@ -208,13 +214,13 @@ class Zend_Feed_Reader } /** - * Import a feed by providing a URL - * - * @param string $url The URL to the feed + * Import a feed by providing a URL + * + * @param string $url The URL to the feed * @param string $etag OPTIONAL Last received ETag for this resource * @param string $lastModified OPTIONAL Last-Modified value for this resource - * @return Zend_Feed_Reader_Feed_Interface - */ + * @return Zend_Feed_Reader_FeedInterface + */ public static function import($uri, $etag = null, $lastModified = null) { $cache = self::getCache(); @@ -245,7 +251,7 @@ class Zend_Feed_Reader } $response = $client->request('GET'); if ($response->getStatus() !== 200 && $response->getStatus() !== 304) { - require_once 'Zend/Feed/Exception.php'; + // require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception('Feed failed to load, got response code ' . $response->getStatus()); } if ($response->getStatus() == 304) { @@ -268,7 +274,7 @@ class Zend_Feed_Reader } $response = $client->request('GET'); if ($response->getStatus() !== 200) { - require_once 'Zend/Feed/Exception.php'; + // require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception('Feed failed to load, got response code ' . $response->getStatus()); } $responseXml = $response->getBody(); @@ -277,10 +283,12 @@ class Zend_Feed_Reader } else { $response = $client->request('GET'); if ($response->getStatus() !== 200) { - require_once 'Zend/Feed/Exception.php'; + // require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception('Feed failed to load, got response code ' . $response->getStatus()); } - return self::importString($response->getBody()); + $reader = self::importString($response->getBody()); + $reader->setOriginalSourceUri($uri); + return $reader; } } @@ -288,8 +296,8 @@ class Zend_Feed_Reader * Import a feed by providing a Zend_Feed_Abstract object * * @param Zend_Feed_Abstract $feed A fully instantiated Zend_Feed object - * @return Zend_Feed_Reader_Feed_Interface - */ + * @return Zend_Feed_Reader_FeedInterface + */ public static function importFeed(Zend_Feed_Abstract $feed) { $dom = $feed->getDOM()->ownerDocument; @@ -298,7 +306,7 @@ class Zend_Feed_Reader if (substr($type, 0, 3) == 'rss') { $reader = new Zend_Feed_Reader_Feed_Rss($dom, $type); } else { - $reader = new Zend_Feed_Reader_Feed_Atom($dom, $type); + $reader = new Zend_Feed_Reader_Feed_Atom($dom, $type); } return $reader; @@ -308,7 +316,7 @@ class Zend_Feed_Reader * Import a feed froma string * * @param string $string - * @return Zend_Feed_Reader_Feed_Interface + * @return Zend_Feed_Reader_FeedInterface */ public static function importString($string) { @@ -321,12 +329,12 @@ class Zend_Feed_Reader // Build error message $error = libxml_get_last_error(); if ($error && $error->message) { - $errormsg = "DOMDocument cannot parse XML: {$error->message}"; + $errormsg = "DOMDocument cannot parse XML: {$error->message}"; } else { - $errormsg = "DOMDocument cannot parse XML: Please check the XML document's validity"; + $errormsg = "DOMDocument cannot parse XML: Please check the XML document's validity"; } - require_once 'Zend/Feed/Exception.php'; + // require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception($errormsg); } @@ -336,8 +344,14 @@ class Zend_Feed_Reader if (substr($type, 0, 3) == 'rss') { $reader = new Zend_Feed_Reader_Feed_Rss($dom, $type); + } elseif (substr($type, 8, 5) == 'entry') { + $reader = new Zend_Feed_Reader_Entry_Atom($dom->documentElement, 0, Zend_Feed_Reader::TYPE_ATOM_10); + } elseif (substr($type, 0, 4) == 'atom') { + $reader = new Zend_Feed_Reader_Feed_Atom($dom, $type); } else { - $reader = new Zend_Feed_Reader_Feed_Atom($dom, $type); + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('The URI used does not point to a ' + . 'valid Atom, RSS or RDF feed that Zend_Feed_Reader can parse.'); } return $reader; } @@ -358,7 +372,7 @@ class Zend_Feed_Reader /** * @see Zend_Feed_Exception */ - require_once 'Zend/Feed/Exception.php'; + // require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception("File could not be loaded: $php_errormsg"); } return self::importString($feed); @@ -374,62 +388,48 @@ class Zend_Feed_Reader /** * @see Zend_Feed_Exception */ - require_once 'Zend/Feed/Exception.php'; + // require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception("Failed to access $uri, got response code " . $response->getStatus()); } $responseHtml = $response->getBody(); - @ini_set('track_errors', 1); + $libxml_errflag = libxml_use_internal_errors(true); $dom = new DOMDocument; - $status = @$dom->loadHTML($responseHtml); - @ini_restore('track_errors'); + $status = $dom->loadHTML($responseHtml); + libxml_use_internal_errors($libxml_errflag); if (!$status) { - if (!isset($php_errormsg)) { - if (function_exists('xdebug_is_enabled')) { - $php_errormsg = '(error message not available, when XDebug is running)'; - } else { - $php_errormsg = '(error message not available)'; - } + // Build error message + $error = libxml_get_last_error(); + if ($error && $error->message) { + $errormsg = "DOMDocument cannot parse HTML: {$error->message}"; + } else { + $errormsg = "DOMDocument cannot parse HTML: Please check the XML document's validity"; } - require_once 'Zend/Feed/Exception.php'; - throw new Zend_Feed_Exception("DOMDocument cannot parse XML: $php_errormsg"); + + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception($errormsg); } - $feedLinks = new stdClass; + $feedSet = new Zend_Feed_Reader_FeedSet; $links = $dom->getElementsByTagName('link'); - foreach ($links as $link) { - if (strtolower($link->getAttribute('rel')) !== 'alternate' - || !$link->getAttribute('type') || !$link->getAttribute('href')) { - continue; - } - if (!isset($feedLinks->rss) && $link->getAttribute('type') == 'application/rss+xml') { - $feedLinks->rss = $link->getAttribute('href'); - } elseif(!isset($feedLinks->atom) && $link->getAttribute('type') == 'application/atom+xml') { - $feedLinks->atom = $link->getAttribute('href'); - } elseif(!isset($feedLinks->rdf) && $link->getAttribute('type') == 'application/rdf+xml') { - $feedLinks->rdf = $link->getAttribute('href'); - } - if (isset($feedLinks->rss) && isset($feedLinks->atom) && isset($feedLinks->rdf)) { - break; - } - } - return $feedLinks; + $feedSet->addLinks($links, $uri); + return $feedSet; } /** * Detect the feed type of the provided feed * - * @param Zend_Feed_Abstract $feed A fully instantiated Zend_Feed object + * @param Zend_Feed_Abstract|DOMDocument|string $feed * @return string */ - public static function detectType($feed) + public static function detectType($feed, $specOnly = false) { if ($feed instanceof Zend_Feed_Reader_FeedInterface) { $dom = $feed->getDomDocument(); - } elseif($feed instanceof DomDocument) { + } elseif($feed instanceof DOMDocument) { $dom = $feed; } elseif(is_string($feed) && !empty($feed)) { @ini_set('track_errors', 1); $dom = new DOMDocument; - $status = @$doc->loadXML($string); + $status = @$dom->loadXML($feed); @ini_restore('track_errors'); if (!$status) { if (!isset($php_errormsg)) { @@ -439,12 +439,13 @@ class Zend_Feed_Reader $php_errormsg = '(error message not available)'; } } - require_once 'Zend/Feed/Exception.php'; + // require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception("DOMDocument cannot parse XML: $php_errormsg"); } } else { - require_once 'Zend/Feed/Exception.php'; - throw new Zend_Feed_Exception('Invalid object/scalar provided: must be of type Zend_Feed_Reader_FeedInterface, DomDocument or string'); + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid object/scalar provided: must' + . ' be of type Zend_Feed_Reader_FeedInterface, DomDocument or string'); } $xpath = new DOMXPath($dom); @@ -509,6 +510,14 @@ class Zend_Feed_Reader if ($xpath->query('//atom:feed')->length) { return self::TYPE_ATOM_10; } + + if ($xpath->query('//atom:entry')->length) { + if ($specOnly == true) { + return self::TYPE_ATOM_10; + } else { + return self::TYPE_ATOM_10_ENTRY; + } + } $xpath->registerNamespace('atom', self::NAMESPACE_ATOM_03); @@ -537,7 +546,7 @@ class Zend_Feed_Reader public static function getPluginLoader() { if (!isset(self::$_pluginLoader)) { - require_once 'Zend/Loader/PluginLoader.php'; + // require_once 'Zend/Loader/PluginLoader.php'; self::$_pluginLoader = new Zend_Loader_PluginLoader(array( 'Zend_Feed_Reader_Extension_' => 'Zend/Feed/Reader/Extension/', )); @@ -607,7 +616,7 @@ class Zend_Feed_Reader if (!self::getPluginLoader()->isLoaded($feedName) && !self::getPluginLoader()->isLoaded($entryName) ) { - require_once 'Zend/Feed/Exception.php'; + // require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception('Could not load extension: ' . $name . 'using Plugin Loader. Check prefix paths are configured and extension exists.'); } @@ -689,4 +698,24 @@ class Zend_Feed_Reader self::registerExtension('Thread'); self::registerExtension('Podcast'); } + + /** + * Utility method to apply array_unique operation to a multidimensional + * array. + * + * @param array + * @return array + */ + public static function arrayUnique(array $array) + { + foreach ($array as &$value) { + $value = serialize($value); + } + $array = array_unique($array); + foreach ($array as &$value) { + $value = unserialize($value); + } + return $array; + } + } diff --git a/libs/Zend/Feed/Reader/Collection.php b/libs/Zend/Feed/Reader/Collection.php new file mode 100644 index 0000000000..fba2b52b52 --- /dev/null +++ b/libs/Zend/Feed/Reader/Collection.php @@ -0,0 +1,33 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Reader + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + +/** + * @category Zend + * @package Zend_Feed_Reader + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Reader_Collection extends ArrayObject +{ + + + +} diff --git a/libs/Zend/Feed/Reader/Collection/Author.php b/libs/Zend/Feed/Reader/Collection/Author.php new file mode 100644 index 0000000000..6a039974b6 --- /dev/null +++ b/libs/Zend/Feed/Reader/Collection/Author.php @@ -0,0 +1,51 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Reader + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Author.php 20096 2010-01-06 02:05:09Z bkarwin $ + */ + +/** + * @see Zend_Feed_Reader_Collection_CollectionAbstract + */ +// require_once 'Zend/Feed/Reader/Collection/CollectionAbstract.php'; + +/** + * @category Zend + * @package Zend_Feed_Reader + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Reader_Collection_Author +extends Zend_Feed_Reader_Collection_CollectionAbstract +{ + + /** + * Return a simple array of the most relevant slice of + * the author values, i.e. all author names. + * + * @return array + */ + public function getValues() { + $authors = array(); + foreach ($this->getIterator() as $element) { + $authors[] = $element['name']; + } + return array_unique($authors); + } + +} diff --git a/libs/Zend/Feed/Reader/Collection/Category.php b/libs/Zend/Feed/Reader/Collection/Category.php new file mode 100644 index 0000000000..2587c13268 --- /dev/null +++ b/libs/Zend/Feed/Reader/Collection/Category.php @@ -0,0 +1,57 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Reader + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Category.php 20954 2010-02-06 17:56:27Z padraic $ + */ + +/** + * @see Zend_Feed_Reader_Collection_CollectionAbstract + */ +// require_once 'Zend/Feed/Reader/Collection/CollectionAbstract.php'; + +/** + * @category Zend + * @package Zend_Feed_Reader + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Reader_Collection_Category +extends Zend_Feed_Reader_Collection_CollectionAbstract +{ + + /** + * Return a simple array of the most relevant slice of + * the collection values. For example, feed categories contain + * the category name, domain/URI, and other data. This method would + * merely return the most useful data - i.e. the category names. + * + * @return array + */ + public function getValues() { + $categories = array(); + foreach ($this->getIterator() as $element) { + if (isset($element['label']) && !empty($element['label'])) { + $categories[] = $element['label']; + } else { + $categories[] = $element['term']; + } + } + return array_unique($categories); + } + +} diff --git a/libs/Zend/Feed/Reader/Collection/CollectionAbstract.php b/libs/Zend/Feed/Reader/Collection/CollectionAbstract.php new file mode 100644 index 0000000000..7b6dbd0317 --- /dev/null +++ b/libs/Zend/Feed/Reader/Collection/CollectionAbstract.php @@ -0,0 +1,41 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Reader + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: CollectionAbstract.php 20096 2010-01-06 02:05:09Z bkarwin $ + */ + +/** + * @category Zend + * @package Zend_Feed_Reader + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +abstract class Zend_Feed_Reader_Collection_CollectionAbstract extends ArrayObject +{ + + /** + * Return a simple array of the most relevant slice of + * the collection values. For example, feed categories contain + * the category name, domain/URI, and other data. This method would + * merely return the most useful data - i.e. the category names. + * + * @return array + */ + public abstract function getValues(); + +} diff --git a/libs/Zend/Feed/Reader/Entry/Atom.php b/libs/Zend/Feed/Reader/Entry/Atom.php index b788cd2533..77289b411b 100644 --- a/libs/Zend/Feed/Reader/Entry/Atom.php +++ b/libs/Zend/Feed/Reader/Entry/Atom.php @@ -14,35 +14,35 @@ * * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Atom.php 16966 2009-07-22 15:22:18Z padraic $ + * @version $Id: Atom.php 20096 2010-01-06 02:05:09Z bkarwin $ */ /** * @see Zend_Feed_Reader */ -require_once 'Zend/Feed/Reader.php'; +// require_once 'Zend/Feed/Reader.php'; /** * @see Zend_Feed_Reader_EntryInterface */ -require_once 'Zend/Feed/Reader/EntryInterface.php'; +// require_once 'Zend/Feed/Reader/EntryInterface.php'; /** * @see Zend_Feed_Reader_EntryAbstract */ -require_once 'Zend/Feed/Reader/EntryAbstract.php'; +// require_once 'Zend/Feed/Reader/EntryAbstract.php'; /** * @see Zend_Feed_Reader_Extension_Atom_Entry */ -require_once 'Zend/Feed/Reader/Extension/Atom/Entry.php'; +// require_once 'Zend/Feed/Reader/Extension/Atom/Entry.php'; /** * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Feed_Reader_Entry_Atom extends Zend_Feed_Reader_EntryAbstract implements Zend_Feed_Reader_EntryInterface @@ -74,9 +74,12 @@ class Zend_Feed_Reader_Entry_Atom extends Zend_Feed_Reader_EntryAbstract impleme $threadClass = Zend_Feed_Reader::getPluginLoader()->getClassName('Thread_Entry'); $this->_extensions['Thread_Entry'] = new $threadClass($entry, $entryKey, $type); + + $threadClass = Zend_Feed_Reader::getPluginLoader()->getClassName('DublinCore_Entry'); + $this->_extensions['DublinCore_Entry'] = new $threadClass($entry, $entryKey, $type); } - /** + /** * Get the specified author * * @param int $index @@ -295,7 +298,7 @@ class Zend_Feed_Reader_Entry_Atom extends Zend_Feed_Reader_EntryAbstract impleme return $this->_data['commentcount']; } - $commentcount = $this->getExtension('Thread')>getCommentCount(); + $commentcount = $this->getExtension('Thread')->getCommentCount(); if (!$commentcount) { $commentcount = $this->getExtension('Atom')->getCommentCount(); @@ -341,6 +344,46 @@ class Zend_Feed_Reader_Entry_Atom extends Zend_Feed_Reader_EntryAbstract impleme return $this->_data['commentfeedlink']; } + + /** + * Get category data as a Zend_Feed_Reader_Collection_Category object + * + * @return Zend_Feed_Reader_Collection_Category + */ + public function getCategories() + { + if (array_key_exists('categories', $this->_data)) { + return $this->_data['categories']; + } + + $categoryCollection = $this->getExtension('Atom')->getCategories(); + + if (count($categoryCollection) == 0) { + $categoryCollection = $this->getExtension('DublinCore')->getCategories(); + } + + $this->_data['categories'] = $categoryCollection; + + return $this->_data['categories']; + } + + /** + * Get source feed metadata from the entry + * + * @return Zend_Feed_Reader_Feed_Atom_Source|null + */ + public function getSource() + { + if (array_key_exists('source', $this->_data)) { + return $this->_data['source']; + } + + $source = $this->getExtension('Atom')->getSource(); + + $this->_data['source'] = $source; + + return $this->_data['source']; + } /** * Set the XPath query (incl. on all Extensions) diff --git a/libs/Zend/Feed/Reader/Entry/Rss.php b/libs/Zend/Feed/Reader/Entry/Rss.php index b91990a665..21a30a98fc 100644 --- a/libs/Zend/Feed/Reader/Entry/Rss.php +++ b/libs/Zend/Feed/Reader/Entry/Rss.php @@ -14,65 +14,70 @@ * * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Rss.php 18367 2009-09-22 14:55:59Z padraic $ + * @version $Id: Rss.php 22301 2010-05-26 10:15:13Z padraic $ */ /** * @see Zend_Feed_Reader */ -require_once 'Zend/Feed/Reader.php'; +// require_once 'Zend/Feed/Reader.php'; /** * @see Zend_Feed_Reader_EntryInterface */ -require_once 'Zend/Feed/Reader/EntryInterface.php'; +// require_once 'Zend/Feed/Reader/EntryInterface.php'; /** * @see Zend_Feed_Reader_EntryAbstract */ -require_once 'Zend/Feed/Reader/EntryAbstract.php'; +// require_once 'Zend/Feed/Reader/EntryAbstract.php'; /** * @see Zend_Feed_Reader_Extension_DublinCore_Entry */ -require_once 'Zend/Feed/Reader/Extension/DublinCore/Entry.php'; +// require_once 'Zend/Feed/Reader/Extension/DublinCore/Entry.php'; /** * @see Zend_Feed_Reader_Extension_Content_Entry */ -require_once 'Zend/Feed/Reader/Extension/Content/Entry.php'; +// require_once 'Zend/Feed/Reader/Extension/Content/Entry.php'; /** * @see Zend_Feed_Reader_Extension_Atom_Entry */ -require_once 'Zend/Feed/Reader/Extension/Atom/Entry.php'; +// require_once 'Zend/Feed/Reader/Extension/Atom/Entry.php'; /** * @see Zend_Feed_Reader_Extension_WellformedWeb_Entry */ -require_once 'Zend/Feed/Reader/Extension/WellFormedWeb/Entry.php'; +// require_once 'Zend/Feed/Reader/Extension/WellFormedWeb/Entry.php'; /** * @see Zend_Feed_Reader_Extension_Slash_Entry */ -require_once 'Zend/Feed/Reader/Extension/Slash/Entry.php'; +// require_once 'Zend/Feed/Reader/Extension/Slash/Entry.php'; /** * @see Zend_Feed_Reader_Extension_Thread_Entry */ -require_once 'Zend/Feed/Reader/Extension/Thread/Entry.php'; +// require_once 'Zend/Feed/Reader/Extension/Thread/Entry.php'; /** * @see Zend_Date */ -require_once 'Zend/Date.php'; +// require_once 'Zend/Date.php'; + +/** + * @see Zend_Feed_Reader_Collection_Category + */ +// require_once 'Zend/Feed/Reader/Collection/Category.php'; /** * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Feed_Reader_Entry_Rss extends Zend_Feed_Reader_EntryAbstract implements Zend_Feed_Reader_EntryInterface @@ -154,45 +159,50 @@ class Zend_Feed_Reader_Entry_Rss extends Zend_Feed_Reader_EntryAbstract implemen if (array_key_exists('authors', $this->_data)) { return $this->_data['authors']; } - + $authors = array(); - // @todo: create a list from all potential sources rather than from alternatives - if ($this->getType() !== Zend_Feed_Reader::TYPE_RSS_10 && - $this->getType() !== Zend_Feed_Reader::TYPE_RSS_090) { - $list = $this->_xpath->evaluate($this->_xpathQueryRss.'//author'); - } else { - $list = $this->_xpath->evaluate($this->_xpathQueryRdf.'//rss:author'); - } - if (!$list->length) { - if ($this->getType() !== Zend_Feed_Reader::TYPE_RSS_10 && $this->getType() !== Zend_Feed_Reader::TYPE_RSS_090) { - $list = $this->_xpath->query('//author'); - } else { - $list = $this->_xpath->query('//rss:author'); + $authors_dc = $this->getExtension('DublinCore')->getAuthors(); + if (!empty($authors_dc)) { + foreach ($authors_dc as $author) { + $authors[] = array( + 'name' => $author['name'] + ); } } - + + if ($this->getType() !== Zend_Feed_Reader::TYPE_RSS_10 + && $this->getType() !== Zend_Feed_Reader::TYPE_RSS_090) { + $list = $this->_xpath->query($this->_xpathQueryRss . '//author'); + } else { + $list = $this->_xpath->query($this->_xpathQueryRdf . '//rss:author'); + } if ($list->length) { foreach ($list as $author) { - if ($this->getType() == Zend_Feed_Reader::TYPE_RSS_20 - && preg_match("/\(([^\)]+)\)/", $author->nodeValue, $matches, PREG_OFFSET_CAPTURE) - ) { - // source name from RSS 2.0 <author> - // format "joe@example.com (Joe Bloggs)" - $authors[] = $matches[1][0]; - } else { - $authors[] = $author->nodeValue; - } + $string = trim($author->nodeValue); + $email = null; + $name = null; + $data = array(); + // Pretty rough parsing - but it's a catchall + if (preg_match("/^.*@[^ ]*/", $string, $matches)) { + $data['email'] = trim($matches[0]); + if (preg_match("/\((.*)\)$/", $string, $matches)) { + $data['name'] = $matches[1]; + } + $authors[] = $data; + } } - - $authors = array_unique($authors); } - if (empty($authors)) { - $authors = $this->getExtension('DublinCore')->getAuthors(); + if (count($authors) == 0) { + $authors = $this->getExtension('Atom')->getAuthors(); + } else { + $authors = new Zend_Feed_Reader_Collection_Author( + Zend_Feed_Reader::arrayUnique($authors) + ); } - if (empty($authors)) { - $authors = $this->getExtension('Atom')->getAuthors(); + if (count($authors) == 0) { + $authors = null; } $this->_data['authors'] = $authors; @@ -255,21 +265,27 @@ class Zend_Feed_Reader_Entry_Rss extends Zend_Feed_Reader_EntryAbstract implemen ) { $dateModified = $this->_xpath->evaluate('string('.$this->_xpathQueryRss.'/pubDate)'); if ($dateModified) { - $dateStandards = array(Zend_Date::RSS, Zend_Date::RFC_822, - Zend_Date::RFC_2822, Zend_Date::DATES); - $date = new Zend_Date; - foreach ($dateStandards as $standard) { - try { - $date->set($dateModified, $standard); - break; - } catch (Zend_Date_Exception $e) { - if ($standard == Zend_Date::DATES) { - require_once 'Zend/Feed/Exception.php'; - throw new Zend_Feed_Exception( - 'Could not load date due to unrecognised' - .' format (should follow RFC 822 or 2822):' - . $e->getMessage() - ); + $dateModifiedParsed = strtotime($dateModified); + if ($dateModifiedParsed) { + $date = new Zend_Date($dateModifiedParsed); + } else { + $dateStandards = array(Zend_Date::RSS, Zend_Date::RFC_822, + Zend_Date::RFC_2822, Zend_Date::DATES); + $date = new Zend_Date; + foreach ($dateStandards as $standard) { + try { + $date->set($dateModified, $standard); + break; + } catch (Zend_Date_Exception $e) { + if ($standard == Zend_Date::DATES) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception( + 'Could not load date due to unrecognised' + .' format (should follow RFC 822 or 2822):' + . $e->getMessage(), + 0, $e + ); + } } } } @@ -324,8 +340,6 @@ class Zend_Feed_Reader_Entry_Rss extends Zend_Feed_Reader_EntryAbstract implemen if (!$description) { $description = null; - } else { - $description = html_entity_decode($description, ENT_QUOTES, $this->getEncoding()); } $this->_data['description'] = $description; @@ -458,6 +472,46 @@ class Zend_Feed_Reader_Entry_Rss extends Zend_Feed_Reader_EntryAbstract implemen return $this->_data['links']; } + + /** + * Get all categories + * + * @return Zend_Feed_Reader_Collection_Category + */ + public function getCategories() + { + if (array_key_exists('categories', $this->_data)) { + return $this->_data['categories']; + } + + if ($this->getType() !== Zend_Feed_Reader::TYPE_RSS_10 && + $this->getType() !== Zend_Feed_Reader::TYPE_RSS_090) { + $list = $this->_xpath->query($this->_xpathQueryRss.'//category'); + } else { + $list = $this->_xpath->query($this->_xpathQueryRdf.'//rss:category'); + } + + if ($list->length) { + $categoryCollection = new Zend_Feed_Reader_Collection_Category; + foreach ($list as $category) { + $categoryCollection[] = array( + 'term' => $category->nodeValue, + 'scheme' => $category->getAttribute('domain'), + 'label' => $category->nodeValue, + ); + } + } else { + $categoryCollection = $this->getExtension('DublinCore')->getCategories(); + } + + if (count($categoryCollection) == 0) { + $categoryCollection = $this->getExtension('Atom')->getCategories(); + } + + $this->_data['categories'] = $categoryCollection; + + return $this->_data['categories']; + } /** * Get a permalink to the entry diff --git a/libs/Zend/Feed/Reader/EntryAbstract.php b/libs/Zend/Feed/Reader/EntryAbstract.php index 153149ebcc..f73e1d1e8e 100644 --- a/libs/Zend/Feed/Reader/EntryAbstract.php +++ b/libs/Zend/Feed/Reader/EntryAbstract.php @@ -14,15 +14,15 @@ * * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: EntryAbstract.php 16966 2009-07-22 15:22:18Z padraic $ + * @version $Id: EntryAbstract.php 20096 2010-01-06 02:05:09Z bkarwin $ */ /** * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ abstract class Zend_Feed_Reader_EntryAbstract @@ -118,6 +118,9 @@ abstract class Zend_Feed_Reader_EntryAbstract public function getEncoding() { $assumed = $this->getDomDocument()->encoding; + if (empty($assumed)) { + $assumed = 'UTF-8'; + } return $assumed; } @@ -134,7 +137,7 @@ abstract class Zend_Feed_Reader_EntryAbstract return $dom->saveXml(); } - /** + /** * Get the entry type * * @return string @@ -151,10 +154,13 @@ abstract class Zend_Feed_Reader_EntryAbstract */ public function getXpath() { + if (!$this->_xpath) { + $this->setXpath(new DOMXPath($this->getDomDocument())); + } return $this->_xpath; } - /** + /** * Set the XPath query * * @param DOMXPath $xpath @@ -167,16 +173,6 @@ abstract class Zend_Feed_Reader_EntryAbstract } /** - * Serialize the entry to an array - * - * @return array - */ - public function toArray() - { - return $this->_data; - } - - /** * Get registered extensions * * @return array @@ -215,7 +211,7 @@ abstract class Zend_Feed_Reader_EntryAbstract return call_user_func_array(array($extension, $method), $args); } } - require_once 'Zend/Feed/Exception.php'; + // require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception('Method: ' . $method . 'does not exist and could not be located on a registered Extension'); } diff --git a/libs/Zend/Feed/Reader/EntryInterface.php b/libs/Zend/Feed/Reader/EntryInterface.php index dafbe293dd..392a533a30 100644 --- a/libs/Zend/Feed/Reader/EntryInterface.php +++ b/libs/Zend/Feed/Reader/EntryInterface.php @@ -14,15 +14,15 @@ * * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: EntryInterface.php 16953 2009-07-22 11:57:25Z padraic $ + * @version $Id: EntryInterface.php 20096 2010-01-06 02:05:09Z bkarwin $ */ /** * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ interface Zend_Feed_Reader_EntryInterface @@ -133,4 +133,11 @@ interface Zend_Feed_Reader_EntryInterface * @return string */ public function getCommentFeedLink(); + + /** + * Get all categories + * + * @return Zend_Feed_Reader_Collection_Category + */ + public function getCategories(); } diff --git a/libs/Zend/Feed/Reader/Extension/Atom/Entry.php b/libs/Zend/Feed/Reader/Extension/Atom/Entry.php index f442115801..1efa197787 100644 --- a/libs/Zend/Feed/Reader/Extension/Atom/Entry.php +++ b/libs/Zend/Feed/Reader/Extension/Atom/Entry.php @@ -14,41 +14,51 @@ * * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Entry.php 18655 2009-10-20 14:17:39Z padraic $ + * @version $Id: Entry.php 22301 2010-05-26 10:15:13Z padraic $ */ /** * @see Zend_Feed_Reader */ -require_once 'Zend/Feed/Reader.php'; +// require_once 'Zend/Feed/Reader.php'; /** * @see Zend_Feed_Reader_Extension_EntryAbstract */ -require_once 'Zend/Feed/Reader/Extension/EntryAbstract.php'; +// require_once 'Zend/Feed/Reader/Extension/EntryAbstract.php'; /** * @see Zend_Date */ -require_once 'Zend/Date.php'; +// require_once 'Zend/Date.php'; /** * @see Zend_Uri */ -require_once 'Zend/Uri.php'; +// require_once 'Zend/Uri.php'; + +/** + * @see Zend_Feed_Reader_Collection_Category + */ +// require_once 'Zend/Feed/Reader/Collection/Category.php'; + +/** + * @see Zend_Feed_Reader_Feed_Atom_Source + */ +// require_once 'Zend/Feed/Reader/Feed/Atom/Source.php'; /** * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Feed_Reader_Extension_Atom_Entry extends Zend_Feed_Reader_Extension_EntryAbstract { - /** + /** * Get the specified author * * @param int $index @@ -76,33 +86,34 @@ class Zend_Feed_Reader_Extension_Atom_Entry return $this->_data['authors']; } - $authors = $this->_xpath->query( - $this->getXpathPrefix() . '//atom:author' . '|' - . $this->getXpathPrefix(). '//atom:contributor' - ); + $authors = array(); + $list = $this->getXpath()->query($this->getXpathPrefix() . '//atom:author'); - if (!$authors->length) { - $authors = $this->_xpath->query( - '//atom:author' . '|' . '//atom:contributor' - ); + if (!$list->length) { + /** + * TODO: Limit query to feed level els only! + */ + $list = $this->getXpath()->query('//atom:author'); } - $people = array(); - - if ($authors->length) { - foreach ($authors as $author) { + if ($list->length) { + foreach ($list as $author) { $author = $this->_getAuthor($author); - if (!empty($author)) { - $people[] = $author; + $authors[] = $author; } } } - $people = array_unique($people); - - $this->_data['authors'] = $people; + if (count($authors) == 0) { + $authors = null; + } else { + $authors = new Zend_Feed_Reader_Collection_Author( + Zend_Feed_Reader::arrayUnique($authors) + ); + } + $this->_data['authors'] = $authors; return $this->_data['authors']; } @@ -116,21 +127,65 @@ class Zend_Feed_Reader_Extension_Atom_Entry if (array_key_exists('content', $this->_data)) { return $this->_data['content']; } - - $content = $this->_xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:content)'); - - if ($content) { - $content = html_entity_decode($content, ENT_QUOTES, $this->getEncoding()); + + $content = null; + + $el = $this->getXpath()->query($this->getXpathPrefix() . '/atom:content'); + if($el->length > 0) { + $el = $el->item(0); + $type = $el->getAttribute('type'); + switch ($type) { + case '': + case 'text': + case 'text/plain': + case 'html': + case 'text/html': + $content = $el->nodeValue; + break; + case 'xhtml': + $this->getXpath()->registerNamespace('xhtml', 'http://www.w3.org/1999/xhtml'); + $xhtml = $this->getXpath()->query( + $this->getXpathPrefix() . '/atom:content/xhtml:div' + )->item(0); + //$xhtml->setAttribute('xmlns', 'http://www.w3.org/1999/xhtml'); + $d = new DOMDocument('1.0', $this->getEncoding()); + $xhtmls = $d->importNode($xhtml, true); + $d->appendChild($xhtmls); + $content = $this->_collectXhtml( + $d->saveXML(), + $d->lookupPrefix('http://www.w3.org/1999/xhtml') + ); + break; + } } + + //var_dump($content); exit; if (!$content) { $content = $this->getDescription(); } - $this->_data['content'] = $content; + $this->_data['content'] = trim($content); return $this->_data['content']; } + + /** + * Parse out XHTML to remove the namespacing + */ + protected function _collectXhtml($xhtml, $prefix) + { + if (!empty($prefix)) $prefix = $prefix . ':'; + $matches = array( + "/<\?xml[^<]*>[^<]*<" . $prefix . "div[^<]*/", + "/<\/" . $prefix . "div>\s*$/" + ); + $xhtml = preg_replace($matches, '', $xhtml); + if (!empty($prefix)) { + $xhtml = preg_replace("/(<[\/]?)" . $prefix . "([a-zA-Z]+)/", '$1$2', $xhtml); + } + return $xhtml; + } /** * Get the entry creation date @@ -145,10 +200,10 @@ class Zend_Feed_Reader_Extension_Atom_Entry $date = null; - if ($this->getType() === Zend_Feed_Reader::TYPE_ATOM_03) { - $dateCreated = $this->_xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:created)'); + if ($this->_getAtomType() === Zend_Feed_Reader::TYPE_ATOM_03) { + $dateCreated = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/atom:created)'); } else { - $dateCreated = $this->_xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:published)'); + $dateCreated = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/atom:published)'); } if ($dateCreated) { @@ -174,10 +229,10 @@ class Zend_Feed_Reader_Extension_Atom_Entry $date = null; - if ($this->getType() === Zend_Feed_Reader::TYPE_ATOM_03) { - $dateModified = $this->_xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:modified)'); + if ($this->_getAtomType() === Zend_Feed_Reader::TYPE_ATOM_03) { + $dateModified = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/atom:modified)'); } else { - $dateModified = $this->_xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:updated)'); + $dateModified = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/atom:updated)'); } if ($dateModified) { @@ -201,12 +256,10 @@ class Zend_Feed_Reader_Extension_Atom_Entry return $this->_data['description']; } - $description = $this->_xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:summary)'); + $description = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/atom:summary)'); if (!$description) { $description = null; - } else { - $description = html_entity_decode($description, ENT_QUOTES, $this->getEncoding()); } $this->_data['description'] = $description; @@ -227,7 +280,7 @@ class Zend_Feed_Reader_Extension_Atom_Entry $enclosure = null; - $nodeList = $this->_xpath->query($this->getXpathPrefix() . '/atom:link[@rel="enclosure"]'); + $nodeList = $this->getXpath()->query($this->getXpathPrefix() . '/atom:link[@rel="enclosure"]'); if ($nodeList->length > 0) { $enclosure = new stdClass(); @@ -252,7 +305,7 @@ class Zend_Feed_Reader_Extension_Atom_Entry return $this->_data['id']; } - $id = $this->_xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:id)'); + $id = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/atom:id)'); if (!$id) { if ($this->getPermalink()) { @@ -268,7 +321,7 @@ class Zend_Feed_Reader_Extension_Atom_Entry return $this->_data['id']; } - + /** * Get the base URI of the feed (if set). * @@ -279,19 +332,19 @@ class Zend_Feed_Reader_Extension_Atom_Entry if (array_key_exists('baseUrl', $this->_data)) { return $this->_data['baseUrl']; } - - $baseUrl = $this->_xpath->evaluate('string(' + + $baseUrl = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/@xml:base[1]' . ')'); - + if (!$baseUrl) { - $baseUrl = $this->_xpath->evaluate('string(//@xml:base[1])'); + $baseUrl = $this->getXpath()->evaluate('string(//@xml:base[1])'); } if (!$baseUrl) { $baseUrl = null; } - + $this->_data['baseUrl'] = $baseUrl; return $this->_data['baseUrl']; @@ -329,7 +382,7 @@ class Zend_Feed_Reader_Extension_Atom_Entry $links = array(); - $list = $this->_xpath->query( + $list = $this->getXpath()->query( $this->getXpathPrefix() . '//atom:link[@rel="alternate"]/@href' . '|' . $this->getXpathPrefix() . '//atom:link[not(@rel)]/@href' ); @@ -366,12 +419,10 @@ class Zend_Feed_Reader_Extension_Atom_Entry return $this->_data['title']; } - $title = $this->_xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:title)'); + $title = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/atom:title)'); if (!$title) { $title = null; - } else { - $title = html_entity_decode($title, ENT_QUOTES, $this->getEncoding()); } $this->_data['title'] = $title; @@ -392,8 +443,8 @@ class Zend_Feed_Reader_Extension_Atom_Entry $count = null; - $this->_xpath->registerNamespace('thread10', 'http://purl.org/syndication/thread/1.0'); - $list = $this->_xpath->query( + $this->getXpath()->registerNamespace('thread10', 'http://purl.org/syndication/thread/1.0'); + $list = $this->getXpath()->query( $this->getXpathPrefix() . '//atom:link[@rel="replies"]/@thread10:count' ); @@ -419,7 +470,7 @@ class Zend_Feed_Reader_Extension_Atom_Entry $link = null; - $list = $this->_xpath->query( + $list = $this->getXpath()->query( $this->getXpathPrefix() . '//atom:link[@rel="replies" and @type="text/html"]/@href' ); @@ -446,7 +497,7 @@ class Zend_Feed_Reader_Extension_Atom_Entry $link = null; - $list = $this->_xpath->query( + $list = $this->getXpath()->query( $this->getXpathPrefix() . '//atom:link[@rel="replies" and @type="application/'.$type.'+xml"]/@href' ); @@ -461,6 +512,72 @@ class Zend_Feed_Reader_Extension_Atom_Entry } /** + * Get all categories + * + * @return Zend_Feed_Reader_Collection_Category + */ + public function getCategories() + { + if (array_key_exists('categories', $this->_data)) { + return $this->_data['categories']; + } + + if ($this->_getAtomType() == Zend_Feed_Reader::TYPE_ATOM_10) { + $list = $this->getXpath()->query($this->getXpathPrefix() . '//atom:category'); + } else { + /** + * Since Atom 0.3 did not support categories, it would have used the + * Dublin Core extension. However there is a small possibility Atom 0.3 + * may have been retrofittied to use Atom 1.0 instead. + */ + $this->getXpath()->registerNamespace('atom10', Zend_Feed_Reader::NAMESPACE_ATOM_10); + $list = $this->getXpath()->query($this->getXpathPrefix() . '//atom10:category'); + } + + if ($list->length) { + $categoryCollection = new Zend_Feed_Reader_Collection_Category; + foreach ($list as $category) { + $categoryCollection[] = array( + 'term' => $category->getAttribute('term'), + 'scheme' => $category->getAttribute('scheme'), + 'label' => $category->getAttribute('label') + ); + } + } else { + return new Zend_Feed_Reader_Collection_Category; + } + + $this->_data['categories'] = $categoryCollection; + + return $this->_data['categories']; + } + + /** + * Get source feed metadata from the entry + * + * @return Zend_Feed_Reader_Feed_Atom_Source|null + */ + public function getSource() + { + if (array_key_exists('source', $this->_data)) { + return $this->_data['source']; + } + + $source = null; + // TODO: Investigate why _getAtomType() fails here. Is it even needed? + if ($this->getType() == Zend_Feed_Reader::TYPE_ATOM_10) { + $list = $this->getXpath()->query($this->getXpathPrefix() . '/atom:source[1]'); + if ($list->length) { + $element = $list->item(0); + $source = new Zend_Feed_Reader_Feed_Atom_Source($element, $this->getXpathPrefix()); + } + } + + $this->_data['source'] = $source; + return $this->_data['source']; + } + + /** * Attempt to absolutise the URI, i.e. if a relative URI apply the * xml:base value as a prefix to turn into an absolute URI. */ @@ -485,35 +602,28 @@ class Zend_Feed_Reader_Extension_Atom_Entry */ protected function _getAuthor(DOMElement $element) { - $email = null; - $name = null; - $uri = null; + $author = array(); $emailNode = $element->getElementsByTagName('email'); $nameNode = $element->getElementsByTagName('name'); $uriNode = $element->getElementsByTagName('uri'); - - if ($emailNode->length) { - $email = $emailNode->item(0)->nodeValue; + + if ($emailNode->length && strlen($emailNode->item(0)->nodeValue) > 0) { + $author['email'] = $emailNode->item(0)->nodeValue; } - if ($nameNode->length) { - $name = $nameNode->item(0)->nodeValue; + if ($nameNode->length && strlen($nameNode->item(0)->nodeValue) > 0) { + $author['name'] = $nameNode->item(0)->nodeValue; } - if ($uriNode->length) { - $uri = $uriNode->item(0)->nodeValue; + if ($uriNode->length && strlen($uriNode->item(0)->nodeValue) > 0) { + $author['uri'] = $uriNode->item(0)->nodeValue; } - if (!empty($email)) { - return $email . (empty($name) ? '' : ' (' . $name . ')'); - } else if (!empty($name)) { - return $name; - } else if (!empty($uri)) { - return $uri; + if (empty($author)) { + return null; } - - return null; + return $author; } /** @@ -521,18 +631,12 @@ class Zend_Feed_Reader_Extension_Atom_Entry */ protected function _registerNamespaces() { - if ($this->getType() == Zend_Feed_Reader::TYPE_ATOM_10 - || $this->getType() == Zend_Feed_Reader::TYPE_ATOM_03 - ) { - return; // pre-registered at Feed level - } - $atomDetected = $this->_getAtomType(); - switch ($atomDetected) { + switch ($this->_getAtomType()) { case Zend_Feed_Reader::TYPE_ATOM_03: - $this->_xpath->registerNamespace('atom', Zend_Feed_Reader::NAMESPACE_ATOM_03); + $this->getXpath()->registerNamespace('atom', Zend_Feed_Reader::NAMESPACE_ATOM_03); break; default: - $this->_xpath->registerNamespace('atom', Zend_Feed_Reader::NAMESPACE_ATOM_10); + $this->getXpath()->registerNamespace('atom', Zend_Feed_Reader::NAMESPACE_ATOM_10); break; } } @@ -542,17 +646,16 @@ class Zend_Feed_Reader_Extension_Atom_Entry */ protected function _getAtomType() { - $nslist = $this->getDomDocument()->documentElement->attributes; - if (!$nslist->length) { - return null; - } - foreach ($nslist as $ns) { - if ($ns->value == Zend_Feed_Reader::NAMESPACE_ATOM_10) { - return Zend_Feed_Reader::TYPE_ATOM_10; - } - if ($ns->value == Zend_Feed_Reader::NAMESPACE_ATOM_03) { - return Zend_Feed_Reader::TYPE_ATOM_03; - } + $dom = $this->getDomDocument(); + $prefixAtom03 = $dom->lookupPrefix(Zend_Feed_Reader::NAMESPACE_ATOM_03); + $prefixAtom10 = $dom->lookupPrefix(Zend_Feed_Reader::NAMESPACE_ATOM_10); + if ($dom->isDefaultNamespace(Zend_Feed_Reader::NAMESPACE_ATOM_03) + || !empty($prefixAtom03)) { + return Zend_Feed_Reader::TYPE_ATOM_03; + } + if ($dom->isDefaultNamespace(Zend_Feed_Reader::NAMESPACE_ATOM_10) + || !empty($prefixAtom10)) { + return Zend_Feed_Reader::TYPE_ATOM_10; } } } diff --git a/libs/Zend/Feed/Reader/Extension/Atom/Feed.php b/libs/Zend/Feed/Reader/Extension/Atom/Feed.php index 4b1de87ed8..3e0e2079c5 100644 --- a/libs/Zend/Feed/Reader/Extension/Atom/Feed.php +++ b/libs/Zend/Feed/Reader/Extension/Atom/Feed.php @@ -14,33 +14,38 @@ * * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Feed.php 18655 2009-10-20 14:17:39Z padraic $ + * @version $Id: Feed.php 22301 2010-05-26 10:15:13Z padraic $ */ /** * @see Zend_Feed_Reader_Extension_FeedAbstract */ -require_once 'Zend/Feed/Reader/Extension/FeedAbstract.php'; +// require_once 'Zend/Feed/Reader/Extension/FeedAbstract.php'; /** * @see Zend_Date */ -require_once 'Zend/Date.php'; +// require_once 'Zend/Date.php'; /** * @see Zend_Uri */ -require_once 'Zend/Uri.php'; +// require_once 'Zend/Uri.php'; + +/** + * @see Zend_Feed_Reader_Collection_Author + */ +// require_once 'Zend/Feed/Reader/Collection/Author.php'; /** * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ -class Zend_Feed_Reader_Extension_Atom_Feed +class Zend_Feed_Reader_Extension_Atom_Feed extends Zend_Feed_Reader_Extension_FeedAbstract { /** @@ -71,38 +76,28 @@ class Zend_Feed_Reader_Extension_Atom_Feed return $this->_data['authors']; } - $authors = $this->_xpath->query('//atom:author'); - $contributors = $this->_xpath->query('//atom:contributor'); + $list = $this->_xpath->query('//atom:author'); - $people = array(); + $authors = array(); - if ($authors->length) { - foreach ($authors as $author) { + if ($list->length) { + foreach ($list as $author) { $author = $this->_getAuthor($author); - if (!empty($author)) { - $people[] = $author; - } - } - } - - if ($contributors->length) { - foreach ($contributors as $contributor) { - $contributor = $this->_getAuthor($contributor); - - if (!empty($contributor)) { - $people[] = $contributor; + $authors[] = $author; } } } - if (empty($people)) { - $people = null; + if (count($authors) == 0) { + $authors = null; } else { - $people = array_unique($people); + $authors = new Zend_Feed_Reader_Collection_Author( + Zend_Feed_Reader::arrayUnique($authors) + ); } - $this->_data['authors'] = $people; + $this->_data['authors'] = $authors; return $this->_data['authors']; } @@ -236,8 +231,6 @@ class Zend_Feed_Reader_Extension_Atom_Feed if (!$generator) { $generator = null; - } else { - $generator = html_entity_decode($generator, ENT_QUOTES, $this->getEncoding()); } $this->_data['generator'] = $generator; @@ -245,7 +238,7 @@ class Zend_Feed_Reader_Extension_Atom_Feed return $this->_data['generator']; } - /** + /** * Get the feed ID * * @return string|null @@ -298,7 +291,31 @@ class Zend_Feed_Reader_Extension_Atom_Feed return $this->_data['language']; } - + + /** + * Get the feed image + * + * @return array|null + */ + public function getImage() + { + if (array_key_exists('image', $this->_data)) { + return $this->_data['image']; + } + + $imageUrl = $this->_xpath->evaluate('string(' . $this->getXpathPrefix() . '/atom:logo)'); + + if (!$imageUrl) { + $image = null; + } else { + $image = array('uri'=>$imageUrl); + } + + $this->_data['image'] = $image; + + return $this->_data['image']; + } + /** * Get the base URI of the feed (if set). * @@ -332,12 +349,12 @@ class Zend_Feed_Reader_Extension_Atom_Feed } $link = null; - + $list = $this->_xpath->query( $this->getXpathPrefix() . '/atom:link[@rel="alternate"]/@href' . '|' . $this->getXpathPrefix() . '/atom:link[not(@rel)]/@href' ); - + if ($list->length) { $link = $list->item(0)->nodeValue; $link = $this->_absolutiseUri($link); @@ -369,6 +386,34 @@ class Zend_Feed_Reader_Extension_Atom_Feed } /** + * Get an array of any supported Pusubhubbub endpoints + * + * @return array|null + */ + public function getHubs() + { + if (array_key_exists('hubs', $this->_data)) { + return $this->_data['hubs']; + } + $hubs = array(); + + $list = $this->_xpath->query($this->getXpathPrefix() + . '//atom:link[@rel="hub"]/@href'); + + if ($list->length) { + foreach ($list as $uri) { + $hubs[] = $this->_absolutiseUri($uri->nodeValue); + } + } else { + $hubs = null; + } + + $this->_data['hubs'] = $hubs; + + return $this->_data['hubs']; + } + + /** * Get the feed title * * @return string|null @@ -389,8 +434,49 @@ class Zend_Feed_Reader_Extension_Atom_Feed return $this->_data['title']; } + + /** + * Get all categories + * + * @return Zend_Feed_Reader_Collection_Category + */ + public function getCategories() + { + if (array_key_exists('categories', $this->_data)) { + return $this->_data['categories']; + } - /** + if ($this->getType() == Zend_Feed_Reader::TYPE_ATOM_10) { + $list = $this->_xpath->query($this->getXpathPrefix() . '/atom:category'); + } else { + /** + * Since Atom 0.3 did not support categories, it would have used the + * Dublin Core extension. However there is a small possibility Atom 0.3 + * may have been retrofittied to use Atom 1.0 instead. + */ + $this->_xpath->registerNamespace('atom10', Zend_Feed_Reader::NAMESPACE_ATOM_10); + $list = $this->_xpath->query($this->getXpathPrefix() . '/atom10:category'); + } + + if ($list->length) { + $categoryCollection = new Zend_Feed_Reader_Collection_Category; + foreach ($list as $category) { + $categoryCollection[] = array( + 'term' => $category->getAttribute('term'), + 'scheme' => $category->getAttribute('scheme'), + 'label' => $category->getAttribute('label') + ); + } + } else { + return new Zend_Feed_Reader_Collection_Category; + } + + $this->_data['categories'] = $categoryCollection; + + return $this->_data['categories']; + } + + /** * Get an author entry in RSS format * * @param DOMElement $element @@ -398,37 +484,30 @@ class Zend_Feed_Reader_Extension_Atom_Feed */ protected function _getAuthor(DOMElement $element) { - $email = null; - $name = null; - $uri = null; + $author = array(); $emailNode = $element->getElementsByTagName('email'); $nameNode = $element->getElementsByTagName('name'); $uriNode = $element->getElementsByTagName('uri'); - - if ($emailNode->length) { - $email = $emailNode->item(0)->nodeValue; + + if ($emailNode->length && strlen($emailNode->item(0)->nodeValue) > 0) { + $author['email'] = $emailNode->item(0)->nodeValue; } - if ($nameNode->length) { - $name = $nameNode->item(0)->nodeValue; + if ($nameNode->length && strlen($nameNode->item(0)->nodeValue) > 0) { + $author['name'] = $nameNode->item(0)->nodeValue; } - if ($uriNode->length) { - $uri = $uriNode->item(0)->nodeValue; + if ($uriNode->length && strlen($uriNode->item(0)->nodeValue) > 0) { + $author['uri'] = $uriNode->item(0)->nodeValue; } - if (!empty($email)) { - return $email . (empty($name) ? '' : ' (' . $name . ')'); - } else if (!empty($name)) { - return $name; - } else if (!empty($uri)) { - return $uri; + if (empty($author)) { + return null; } - - return null; + return $author; } - + /** * Attempt to absolutise the URI, i.e. if a relative URI apply the * xml:base value as a prefix to turn into an absolute URI. @@ -451,7 +530,7 @@ class Zend_Feed_Reader_Extension_Atom_Feed */ protected function _registerNamespaces() { - if ($this->getType() == Zend_Feed_Reader::TYPE_ATOM_10 + if ($this->getType() == Zend_Feed_Reader::TYPE_ATOM_10 || $this->getType() == Zend_Feed_Reader::TYPE_ATOM_03 ) { return; // pre-registered at Feed level @@ -472,17 +551,16 @@ class Zend_Feed_Reader_Extension_Atom_Feed */ protected function _getAtomType() { - $nslist = $this->getDomDocument()->documentElement->attributes; - if (!$nslist->length) { - return null; - } - foreach ($nslist as $ns) { - if ($ns->value == Zend_Feed_Reader::NAMESPACE_ATOM_10) { - return Zend_Feed_Reader::TYPE_ATOM_10; - } - if ($ns->value == Zend_Feed_Reader::NAMESPACE_ATOM_03) { - return Zend_Feed_Reader::TYPE_ATOM_03; - } + $dom = $this->getDomDocument(); + $prefixAtom03 = $dom->lookupPrefix(Zend_Feed_Reader::NAMESPACE_ATOM_03); + $prefixAtom10 = $dom->lookupPrefix(Zend_Feed_Reader::NAMESPACE_ATOM_10); + if ($dom->isDefaultNamespace(Zend_Feed_Reader::NAMESPACE_ATOM_10) + || !empty($prefixAtom10)) { + return Zend_Feed_Reader::TYPE_ATOM_10; + } + if ($dom->isDefaultNamespace(Zend_Feed_Reader::NAMESPACE_ATOM_03) + || !empty($prefixAtom03)) { + return Zend_Feed_Reader::TYPE_ATOM_03; } } } diff --git a/libs/Zend/Feed/Reader/Extension/Content/Entry.php b/libs/Zend/Feed/Reader/Extension/Content/Entry.php index 7145281ecb..ca10f24a3b 100644 --- a/libs/Zend/Feed/Reader/Extension/Content/Entry.php +++ b/libs/Zend/Feed/Reader/Extension/Content/Entry.php @@ -14,43 +14,40 @@ * * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Entry.php 16971 2009-07-22 18:05:45Z mikaelkael $ + * @version $Id: Entry.php 22301 2010-05-26 10:15:13Z padraic $ */ /** * @see Zend_Feed_Reader */ -require_once 'Zend/Feed/Reader.php'; +// require_once 'Zend/Feed/Reader.php'; /** * @see Zend_Feed_Reader_Entry_EntryAbstract */ -require_once 'Zend/Feed/Reader/Extension/EntryAbstract.php'; +// require_once 'Zend/Feed/Reader/Extension/EntryAbstract.php'; /** * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ -class Zend_Feed_Reader_Extension_Content_Entry +class Zend_Feed_Reader_Extension_Content_Entry extends Zend_Feed_Reader_Extension_EntryAbstract { public function getContent() { - if ($this->getType() !== Zend_Feed_Reader::TYPE_RSS_10 + if ($this->getType() !== Zend_Feed_Reader::TYPE_RSS_10 && $this->getType() !== Zend_Feed_Reader::TYPE_RSS_090 ) { $content = $this->_xpath->evaluate('string('.$this->getXpathPrefix().'/content:encoded)'); } else { $content = $this->_xpath->evaluate('string('.$this->getXpathPrefix().'/content:encoded)'); } - if ($content) { - $content = html_entity_decode($content, ENT_QUOTES, $this->getEncoding()); - } return $content; } diff --git a/libs/Zend/Feed/Reader/Extension/CreativeCommons/Entry.php b/libs/Zend/Feed/Reader/Extension/CreativeCommons/Entry.php index b9830089d3..5e78db10ab 100644 --- a/libs/Zend/Feed/Reader/Extension/CreativeCommons/Entry.php +++ b/libs/Zend/Feed/Reader/Extension/CreativeCommons/Entry.php @@ -14,25 +14,25 @@ * * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Entry.php 16971 2009-07-22 18:05:45Z mikaelkael $ + * @version $Id: Entry.php 20096 2010-01-06 02:05:09Z bkarwin $ */ /** * @see Zend_Feed_Reader_Extension_EntryAbstract */ -require_once 'Zend/Feed/Reader/Extension/EntryAbstract.php'; +// require_once 'Zend/Feed/Reader/Extension/EntryAbstract.php'; /** * @see Zend_Feed_Reader_Extension_CreativeCommons_Feed */ -require_once 'Zend/Feed/Reader/Extension/CreativeCommons/Feed.php'; +// require_once 'Zend/Feed/Reader/Extension/CreativeCommons/Feed.php'; /** * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Feed_Reader_Extension_CreativeCommons_Entry extends Zend_Feed_Reader_Extension_EntryAbstract diff --git a/libs/Zend/Feed/Reader/Extension/CreativeCommons/Feed.php b/libs/Zend/Feed/Reader/Extension/CreativeCommons/Feed.php index c3d0cd2d42..3d29c6911f 100644 --- a/libs/Zend/Feed/Reader/Extension/CreativeCommons/Feed.php +++ b/libs/Zend/Feed/Reader/Extension/CreativeCommons/Feed.php @@ -14,23 +14,23 @@ * * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Feed.php 16971 2009-07-22 18:05:45Z mikaelkael $ + * @version $Id: Feed.php 20096 2010-01-06 02:05:09Z bkarwin $ */ /** * @see Zend_Feed_Reader_Extension_FeedAbstract */ -require_once 'Zend/Feed/Reader/Extension/FeedAbstract.php'; +// require_once 'Zend/Feed/Reader/Extension/FeedAbstract.php'; /** * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ -class Zend_Feed_Reader_Extension_CreativeCommons_Feed +class Zend_Feed_Reader_Extension_CreativeCommons_Feed extends Zend_Feed_Reader_Extension_FeedAbstract { /** diff --git a/libs/Zend/Feed/Reader/Extension/DublinCore/Entry.php b/libs/Zend/Feed/Reader/Extension/DublinCore/Entry.php index 522e2c1498..4ad104b6ff 100644 --- a/libs/Zend/Feed/Reader/Extension/DublinCore/Entry.php +++ b/libs/Zend/Feed/Reader/Extension/DublinCore/Entry.php @@ -14,33 +14,33 @@ * * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Entry.php 16711 2009-07-14 16:10:54Z matthew $ + * @version $Id: Entry.php 20096 2010-01-06 02:05:09Z bkarwin $ */ /** * @see Zend_Feed_Reader */ -require_once 'Zend/Feed/Reader.php'; +// require_once 'Zend/Feed/Reader.php'; /** * @see Zend_Feed_Reader_Extension_EntryAbstract */ -require_once 'Zend/Feed/Reader/Extension/EntryAbstract.php'; +// require_once 'Zend/Feed/Reader/Extension/EntryAbstract.php'; /** * @see Zend_Date */ -require_once 'Zend/Date.php'; +// require_once 'Zend/Date.php'; /** * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ -class Zend_Feed_Reader_Extension_DublinCore_Entry +class Zend_Feed_Reader_Extension_DublinCore_Entry extends Zend_Feed_Reader_Extension_EntryAbstract { /** @@ -87,22 +87,56 @@ class Zend_Feed_Reader_Extension_DublinCore_Entry if ($list->length) { foreach ($list as $author) { - if ($this->getType() == Zend_Feed_Reader::TYPE_RSS_20 - && preg_match("/\(([^\)]+)\)/", $author->nodeValue, $matches, PREG_OFFSET_CAPTURE) - ) { - $authors[] = $matches[1][0]; - } else { - $authors[] = $author->nodeValue; - } + $authors[] = array( + 'name' => $author->nodeValue + ); } - - $authors = array_unique($authors); + $authors = new Zend_Feed_Reader_Collection_Author( + Zend_Feed_Reader::arrayUnique($authors) + ); + } else { + $authors = null; } $this->_data['authors'] = $authors; return $this->_data['authors']; } + + /** + * Get categories (subjects under DC) + * + * @return Zend_Feed_Reader_Collection_Category + */ + public function getCategories() + { + if (array_key_exists('categories', $this->_data)) { + return $this->_data['categories']; + } + + $list = $this->_xpath->evaluate($this->getXpathPrefix() . '//dc11:subject'); + + if (!$list->length) { + $list = $this->_xpath->evaluate($this->getXpathPrefix() . '//dc10:subject'); + } + + if ($list->length) { + $categoryCollection = new Zend_Feed_Reader_Collection_Category; + foreach ($list as $category) { + $categoryCollection[] = array( + 'term' => $category->nodeValue, + 'scheme' => null, + 'label' => $category->nodeValue, + ); + } + } else { + $categoryCollection = new Zend_Feed_Reader_Collection_Category; + } + + $this->_data['categories'] = $categoryCollection; + return $this->_data['categories']; + } + /** * Get the entry content diff --git a/libs/Zend/Feed/Reader/Extension/DublinCore/Feed.php b/libs/Zend/Feed/Reader/Extension/DublinCore/Feed.php index 68078578b2..4e4bcf4888 100644 --- a/libs/Zend/Feed/Reader/Extension/DublinCore/Feed.php +++ b/libs/Zend/Feed/Reader/Extension/DublinCore/Feed.php @@ -14,31 +14,36 @@ * * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Feed.php 16711 2009-07-14 16:10:54Z matthew $ + * @version $Id: Feed.php 20096 2010-01-06 02:05:09Z bkarwin $ */ /** * @see Zend_Feed_Reader_Extension_FeedAbstract */ -require_once 'Zend/Feed/Reader/Extension/FeedAbstract.php'; +// require_once 'Zend/Feed/Reader/Extension/FeedAbstract.php'; /** * @see Zend_Date */ -require_once 'Zend/Date.php'; +// require_once 'Zend/Date.php'; + +/** + * @see Zend_Feed_Reader_Collection_Author + */ +// require_once 'Zend/Feed/Reader/Collection/Author.php'; /** * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ -class Zend_Feed_Reader_Extension_DublinCore_Feed +class Zend_Feed_Reader_Extension_DublinCore_Feed extends Zend_Feed_Reader_Extension_FeedAbstract { - /** + /** * Get a single author * * @param int $index @@ -79,13 +84,18 @@ class Zend_Feed_Reader_Extension_DublinCore_Feed $list = $this->_xpath->query('//dc10:publisher'); } } - - foreach ($list as $authorObj) { - $authors[] = $authorObj->nodeValue; - } - - if (!empty($authors)) { - $authors = array_unique($authors); + + if ($list->length) { + foreach ($list as $author) { + $authors[] = array( + 'name' => $author->nodeValue + ); + } + $authors = new Zend_Feed_Reader_Collection_Author( + Zend_Feed_Reader::arrayUnique($authors) + ); + } else { + $authors = null; } $this->_data['authors'] = $authors; @@ -251,6 +261,40 @@ class Zend_Feed_Reader_Extension_DublinCore_Feed return $this->_data['date']; } + + /** + * Get categories (subjects under DC) + * + * @return Zend_Feed_Reader_Collection_Category + */ + public function getCategories() + { + if (array_key_exists('categories', $this->_data)) { + return $this->_data['categories']; + } + + $list = $this->_xpath->evaluate($this->getXpathPrefix() . '//dc11:subject'); + + if (!$list->length) { + $list = $this->_xpath->evaluate($this->getXpathPrefix() . '//dc10:subject'); + } + + if ($list->length) { + $categoryCollection = new Zend_Feed_Reader_Collection_Category; + foreach ($list as $category) { + $categoryCollection[] = array( + 'term' => $category->nodeValue, + 'scheme' => null, + 'label' => $category->nodeValue, + ); + } + } else { + $categoryCollection = new Zend_Feed_Reader_Collection_Category; + } + + $this->_data['categories'] = $categoryCollection; + return $this->_data['categories']; + } /** * Register the default namespaces for the current feed format diff --git a/libs/Zend/Feed/Reader/Extension/EntryAbstract.php b/libs/Zend/Feed/Reader/Extension/EntryAbstract.php index 68ae193cf7..299c1bfbaf 100644 --- a/libs/Zend/Feed/Reader/Extension/EntryAbstract.php +++ b/libs/Zend/Feed/Reader/Extension/EntryAbstract.php @@ -14,15 +14,15 @@ * * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: EntryAbstract.php 16711 2009-07-14 16:10:54Z matthew $ + * @version $Id: EntryAbstract.php 20096 2010-01-06 02:05:09Z bkarwin $ */ /** * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ abstract class Zend_Feed_Reader_Extension_EntryAbstract @@ -86,14 +86,14 @@ abstract class Zend_Feed_Reader_Extension_EntryAbstract if (!is_null($type)) { $this->_data['type'] = $type; } else { - $this->_data['type'] = Zend_Feed_Reader::detectType($feed); + $this->_data['type'] = Zend_Feed_Reader::detectType($entry->ownerDocument, true); } // set the XPath query prefix for the entry being queried - if ($this->getType() == Zend_Feed_Reader::TYPE_RSS_10 + if ($this->getType() == Zend_Feed_Reader::TYPE_RSS_10 || $this->getType() == Zend_Feed_Reader::TYPE_RSS_090 ) { $this->setXpathPrefix('//rss:item[' . ($this->_entryKey+1) . ']'); - } elseif ($this->getType() == Zend_Feed_Reader::TYPE_ATOM_10 + } elseif ($this->getType() == Zend_Feed_Reader::TYPE_ATOM_10 || $this->getType() == Zend_Feed_Reader::TYPE_ATOM_03 ) { $this->setXpathPrefix('//atom:entry[' . ($this->_entryKey+1) . ']'); @@ -123,7 +123,7 @@ abstract class Zend_Feed_Reader_Extension_EntryAbstract return $assumed; } - /** + /** * Get the entry type * * @return string @@ -153,6 +153,9 @@ abstract class Zend_Feed_Reader_Extension_EntryAbstract */ public function getXpath() { + if (!$this->_xpath) { + $this->setXpath(new DOMXPath($this->getDomDocument())); + } return $this->_xpath; } @@ -178,8 +181,8 @@ abstract class Zend_Feed_Reader_Extension_EntryAbstract /** * Set the XPath prefix - * - * @param string $prefix + * + * @param string $prefix * @return Zend_Feed_Reader_Extension_EntryAbstract */ public function setXpathPrefix($prefix) @@ -190,7 +193,7 @@ abstract class Zend_Feed_Reader_Extension_EntryAbstract /** * Register XML namespaces - * + * * @return void */ protected abstract function _registerNamespaces(); diff --git a/libs/Zend/Feed/Reader/Extension/FeedAbstract.php b/libs/Zend/Feed/Reader/Extension/FeedAbstract.php index 973dd81197..23d97d3f7a 100644 --- a/libs/Zend/Feed/Reader/Extension/FeedAbstract.php +++ b/libs/Zend/Feed/Reader/Extension/FeedAbstract.php @@ -14,36 +14,36 @@ * * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: FeedAbstract.php 16711 2009-07-14 16:10:54Z matthew $ + * @version $Id: FeedAbstract.php 20096 2010-01-06 02:05:09Z bkarwin $ */ /** * @see Zend_Feed_Reader */ -require_once 'Zend/Feed/Reader.php'; +// require_once 'Zend/Feed/Reader.php'; /** * @see Zend_Feed_Reader_Entry_Atom */ -require_once 'Zend/Feed/Reader/Entry/Atom.php'; +// require_once 'Zend/Feed/Reader/Entry/Atom.php'; /** * @see Zend_Feed_Reader_Entry_Rss */ -require_once 'Zend/Feed/Reader/Entry/Rss.php'; +// require_once 'Zend/Feed/Reader/Entry/Rss.php'; /** * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ abstract class Zend_Feed_Reader_Extension_FeedAbstract { - /** + /** * Parsed feed data * * @var array @@ -139,10 +139,33 @@ abstract class Zend_Feed_Reader_Extension_FeedAbstract return $this->_data; } - /** + /** + * Set the XPath query + * + * @param DOMXPath $xpath + * @return Zend_Feed_Reader_Extension_EntryAbstract + */ + public function setXpath(DOMXPath $xpath) + { + $this->_xpath = $xpath; + $this->_registerNamespaces(); + return $this; + } + + /** + * Get the DOMXPath object + * + * @return string + */ + public function getXpath() + { + return $this->_xpath; + } + + /** * Get the XPath prefix - * - * @return string + * + * @return string */ public function getXpathPrefix() { diff --git a/libs/Zend/Feed/Reader/Extension/Podcast/Entry.php b/libs/Zend/Feed/Reader/Extension/Podcast/Entry.php index 7af2285421..bbe340ce63 100644 --- a/libs/Zend/Feed/Reader/Extension/Podcast/Entry.php +++ b/libs/Zend/Feed/Reader/Extension/Podcast/Entry.php @@ -14,25 +14,25 @@ * * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Entry.php 16792 2009-07-17 02:52:37Z norm2782 $ + * @version $Id: Entry.php 20096 2010-01-06 02:05:09Z bkarwin $ */ /** * @see Zend_Feed_Reader */ -require_once 'Zend/Feed/Reader.php'; +// require_once 'Zend/Feed/Reader.php'; /** * @see Zend_Feed_Reader_Extension_EntryAbstract */ -require_once 'Zend/Feed/Reader/Extension/EntryAbstract.php'; +// require_once 'Zend/Feed/Reader/Extension/EntryAbstract.php'; /** * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Feed_Reader_Extension_Podcast_Entry extends Zend_Feed_Reader_Extension_EntryAbstract diff --git a/libs/Zend/Feed/Reader/Extension/Podcast/Feed.php b/libs/Zend/Feed/Reader/Extension/Podcast/Feed.php index b213d34590..c4ea180f7c 100644 --- a/libs/Zend/Feed/Reader/Extension/Podcast/Feed.php +++ b/libs/Zend/Feed/Reader/Extension/Podcast/Feed.php @@ -14,20 +14,20 @@ * * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Feed.php 16792 2009-07-17 02:52:37Z norm2782 $ + * @version $Id: Feed.php 20096 2010-01-06 02:05:09Z bkarwin $ */ /** * @see Zend_Feed_Reader_Extension_FeedAbstract */ -require_once 'Zend/Feed/Reader/Extension/FeedAbstract.php'; +// require_once 'Zend/Feed/Reader/Extension/FeedAbstract.php'; /** * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Feed_Reader_Extension_Podcast_Feed extends Zend_Feed_Reader_Extension_FeedAbstract diff --git a/libs/Zend/Feed/Reader/Extension/Slash/Entry.php b/libs/Zend/Feed/Reader/Extension/Slash/Entry.php index b2aa12457b..222c0e1062 100644 --- a/libs/Zend/Feed/Reader/Extension/Slash/Entry.php +++ b/libs/Zend/Feed/Reader/Extension/Slash/Entry.php @@ -14,28 +14,28 @@ * * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Entry.php 16971 2009-07-22 18:05:45Z mikaelkael $ + * @version $Id: Entry.php 20096 2010-01-06 02:05:09Z bkarwin $ */ /** * @see Zend_Feed_Reader */ -require_once 'Zend/Feed/Reader.php'; +// require_once 'Zend/Feed/Reader.php'; /** * @see Zend_Feed_Reader_Extension_EntryAbstract */ -require_once 'Zend/Feed/Reader/Extension/EntryAbstract.php'; +// require_once 'Zend/Feed/Reader/Extension/EntryAbstract.php'; /** * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ -class Zend_Feed_Reader_Extension_Slash_Entry +class Zend_Feed_Reader_Extension_Slash_Entry extends Zend_Feed_Reader_Extension_EntryAbstract { /** diff --git a/libs/Zend/Feed/Reader/Extension/Syndication/Feed.php b/libs/Zend/Feed/Reader/Extension/Syndication/Feed.php index bd205bcf61..5b383cfedb 100644 --- a/libs/Zend/Feed/Reader/Extension/Syndication/Feed.php +++ b/libs/Zend/Feed/Reader/Extension/Syndication/Feed.php @@ -14,25 +14,25 @@ * * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Feed.php 16971 2009-07-22 18:05:45Z mikaelkael $ + * @version $Id: Feed.php 20096 2010-01-06 02:05:09Z bkarwin $ */ /** * @see Zend_Feed_Reader_Extension_FeedAbstract */ -require_once 'Zend/Feed/Reader/Extension/FeedAbstract.php'; +// require_once 'Zend/Feed/Reader/Extension/FeedAbstract.php'; -require_once 'Zend/Date.php'; +// require_once 'Zend/Date.php'; /** * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ -class Zend_Feed_Reader_Extension_Syndication_Feed +class Zend_Feed_Reader_Extension_Syndication_Feed extends Zend_Feed_Reader_Extension_FeedAbstract { /** @@ -57,7 +57,7 @@ class Zend_Feed_Reader_Extension_Syndication_Feed case 'yearly': return $period; default: - throw new Zend_Feed_Exception("Feed specified invalid update period: '$period'." + throw new Zend_Feed_Exception("Feed specified invalid update period: '$period'." . " Must be one of hourly, daily, weekly or yearly" ); } @@ -100,13 +100,13 @@ class Zend_Feed_Reader_Extension_Syndication_Feed switch ($period) { //intentional fall through - case 'yearly': + case 'yearly': $ticks *= 52; //TODO: fix generalisation, how? - case 'weekly': + case 'weekly': $ticks *= 7; - case 'daily': + case 'daily': $ticks *= 24; - case 'hourly': + case 'hourly': $ticks *= 3600; break; default: //Never arrive here, exception thrown in getPeriod() diff --git a/libs/Zend/Feed/Reader/Extension/Thread/Entry.php b/libs/Zend/Feed/Reader/Extension/Thread/Entry.php index c8b632726c..e8a4bde92f 100644 --- a/libs/Zend/Feed/Reader/Extension/Thread/Entry.php +++ b/libs/Zend/Feed/Reader/Extension/Thread/Entry.php @@ -14,28 +14,28 @@ * * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Entry.php 16971 2009-07-22 18:05:45Z mikaelkael $ + * @version $Id: Entry.php 20096 2010-01-06 02:05:09Z bkarwin $ */ /** * @see Zend_Feed_Reader_Extension_EntryAbstract */ -require_once 'Zend/Feed/Reader/Extension/EntryAbstract.php'; +// require_once 'Zend/Feed/Reader/Extension/EntryAbstract.php'; /** * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ -class Zend_Feed_Reader_Extension_Thread_Entry +class Zend_Feed_Reader_Extension_Thread_Entry extends Zend_Feed_Reader_Extension_EntryAbstract { /** * Get the "in-reply-to" value - * + * * @return string */ public function getInReplyTo() diff --git a/libs/Zend/Feed/Reader/Extension/WellFormedWeb/Entry.php b/libs/Zend/Feed/Reader/Extension/WellFormedWeb/Entry.php index 8c96f6e316..fe47448338 100644 --- a/libs/Zend/Feed/Reader/Extension/WellFormedWeb/Entry.php +++ b/libs/Zend/Feed/Reader/Extension/WellFormedWeb/Entry.php @@ -14,28 +14,28 @@ * * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Entry.php 16971 2009-07-22 18:05:45Z mikaelkael $ + * @version $Id: Entry.php 20096 2010-01-06 02:05:09Z bkarwin $ */ /** * @see Zend_Feed_Reader */ -require_once 'Zend/Feed/Reader.php'; +// require_once 'Zend/Feed/Reader.php'; /** * @see Zend_Feed_Reader_Extension_EntryAbstract */ -require_once 'Zend/Feed/Reader/Extension/EntryAbstract.php'; +// require_once 'Zend/Feed/Reader/Extension/EntryAbstract.php'; /** * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ -class Zend_Feed_Reader_Extension_WellFormedWeb_Entry +class Zend_Feed_Reader_Extension_WellFormedWeb_Entry extends Zend_Feed_Reader_Extension_EntryAbstract { /** diff --git a/libs/Zend/Feed/Reader/Feed/Atom.php b/libs/Zend/Feed/Reader/Feed/Atom.php index 0256e36122..8199355995 100644 --- a/libs/Zend/Feed/Reader/Feed/Atom.php +++ b/libs/Zend/Feed/Reader/Feed/Atom.php @@ -14,25 +14,25 @@ * * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Atom.php 18655 2009-10-20 14:17:39Z padraic $ + * @version $Id: Atom.php 22108 2010-05-05 13:44:11Z padraic $ */ /** * @see Zend_Feed_Reader_FeedAbstract */ -require_once 'Zend/Feed/Reader/FeedAbstract.php'; +// require_once 'Zend/Feed/Reader/FeedAbstract.php'; /** * @see Zend_Feed_Reader_Extension_Atom_Feed */ -require_once 'Zend/Feed/Reader/Extension/Atom/Feed.php'; +// require_once 'Zend/Feed/Reader/Extension/Atom/Feed.php'; /** * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Feed_Reader_Feed_Atom extends Zend_Feed_Reader_FeedAbstract @@ -41,15 +41,16 @@ class Zend_Feed_Reader_Feed_Atom extends Zend_Feed_Reader_FeedAbstract /** * Constructor * - * @param Zend_Feed_Abstract $feed + * @param DOMDocument $dom * @param string $type - * @param string $xpath */ - public function __construct(DomDocument $dom, $type = null) + public function __construct(DOMDocument $dom, $type = null) { parent::__construct($dom, $type); $atomClass = Zend_Feed_Reader::getPluginLoader()->getClassName('Atom_Feed'); $this->_extensions['Atom_Feed'] = new $atomClass($dom, $this->_data['type'], $this->_xpath); + $atomClass = Zend_Feed_Reader::getPluginLoader()->getClassName('DublinCore_Feed'); + $this->_extensions['DublinCore_Feed'] = new $atomClass($dom, $this->_data['type'], $this->_xpath); foreach ($this->_extensions as $extension) { $extension->setXpathPrefix('/atom:feed'); } @@ -83,9 +84,9 @@ class Zend_Feed_Reader_Feed_Atom extends Zend_Feed_Reader_FeedAbstract return $this->_data['authors']; } - $people = $this->getExtension('Atom')->getAuthors(); + $authors = $this->getExtension('Atom')->getAuthors(); - $this->_data['authors'] = $people; + $this->_data['authors'] = $authors; return $this->_data['authors']; } @@ -157,6 +158,16 @@ class Zend_Feed_Reader_Feed_Atom extends Zend_Feed_Reader_FeedAbstract } /** + * Get the feed lastBuild date. This is not implemented in Atom. + * + * @return string|null + */ + public function getLastBuildDate() + { + return null; + } + + /** * Get the feed description * * @return string|null @@ -196,7 +207,7 @@ class Zend_Feed_Reader_Feed_Atom extends Zend_Feed_Reader_FeedAbstract return $this->_data['generator']; } - /** + /** * Get the feed ID * * @return string|null @@ -239,7 +250,7 @@ class Zend_Feed_Reader_Feed_Atom extends Zend_Feed_Reader_FeedAbstract return $this->_data['language']; } - + /** * Get a link to the source website * @@ -277,6 +288,24 @@ class Zend_Feed_Reader_Feed_Atom extends Zend_Feed_Reader_FeedAbstract } /** + * Get feed image data + * + * @return array|null + */ + public function getImage() + { + if (array_key_exists('image', $this->_data)) { + return $this->_data['image']; + } + + $link = $this->getExtension('Atom')->getImage(); + + $this->_data['image'] = $link; + + return $this->_data['image']; + } + + /** * Get a link to the feed's XML Url * * @return string|null @@ -289,6 +318,10 @@ class Zend_Feed_Reader_Feed_Atom extends Zend_Feed_Reader_FeedAbstract $link = $this->getExtension('Atom')->getFeedLink(); + if (is_null($link) || empty($link)) { + $link = $this->getOriginalSourceUri(); + } + $this->_data['feedlink'] = $link; return $this->_data['feedlink']; @@ -312,9 +345,50 @@ class Zend_Feed_Reader_Feed_Atom extends Zend_Feed_Reader_FeedAbstract return $this->_data['title']; } - /** + /** + * Get an array of any supported Pusubhubbub endpoints + * + * @return array|null + */ + public function getHubs() + { + if (array_key_exists('hubs', $this->_data)) { + return $this->_data['hubs']; + } + + $hubs = $this->getExtension('Atom')->getHubs(); + + $this->_data['hubs'] = $hubs; + + return $this->_data['hubs']; + } + + /** + * Get all categories + * + * @return Zend_Feed_Reader_Collection_Category + */ + public function getCategories() + { + if (array_key_exists('categories', $this->_data)) { + return $this->_data['categories']; + } + + $categoryCollection = $this->getExtension('Atom')->getCategories(); + + if (count($categoryCollection) == 0) { + $categoryCollection = $this->getExtension('DublinCore')->getCategories(); + } + + $this->_data['categories'] = $categoryCollection; + + return $this->_data['categories']; + } + + /** * Read all entries to the internal entries array * + * @return void */ protected function _indexEntries() { diff --git a/libs/Zend/Feed/Reader/Feed/Atom/Source.php b/libs/Zend/Feed/Reader/Feed/Atom/Source.php new file mode 100644 index 0000000000..bdd972f93e --- /dev/null +++ b/libs/Zend/Feed/Reader/Feed/Atom/Source.php @@ -0,0 +1,102 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Reader + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Atom.php 19165 2009-11-21 16:46:40Z padraic $ + */ + +/** + * @see Zend_Feed_Reader_Feed_Atom + */ +// require_once 'Zend/Feed/Reader/Feed/Atom.php'; + +/** + * @category Zend + * @package Zend_Feed_Reader + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Reader_Feed_Atom_Source extends Zend_Feed_Reader_Feed_Atom +{ + + /** + * Constructor: Create a Source object which is largely just a normal + * Zend_Feed_Reader_FeedAbstract object only designed to retrieve feed level + * metadata from an Atom entry's source element. + * + * @param DOMElement $source + * @param string $xpathPrefix Passed from parent Entry object + * @param string $type Nearly always Atom 1.0 + */ + public function __construct(DOMElement $source, $xpathPrefix, $type = Zend_Feed_Reader::TYPE_ATOM_10) + { + $this->_domDocument = $source->ownerDocument; + $this->_xpath = new DOMXPath($this->_domDocument); + $this->_data['type'] = $type; + $this->_registerNamespaces(); + $this->_loadExtensions(); + + $atomClass = Zend_Feed_Reader::getPluginLoader()->getClassName('Atom_Feed'); + $this->_extensions['Atom_Feed'] = new $atomClass($this->_domDocument, $this->_data['type'], $this->_xpath); + $atomClass = Zend_Feed_Reader::getPluginLoader()->getClassName('DublinCore_Feed'); + $this->_extensions['DublinCore_Feed'] = new $atomClass($this->_domDocument, $this->_data['type'], $this->_xpath); + foreach ($this->_extensions as $extension) { + $extension->setXpathPrefix(rtrim($xpathPrefix, '/') . '/atom:source'); + } + } + + /** + * Since this is not an Entry carrier but a vehicle for Feed metadata, any + * applicable Entry methods are stubbed out and do nothing. + */ + + /** + * @return void + */ + public function count() {} + + /** + * @return void + */ + public function current() {} + + /** + * @return void + */ + public function key() {} + + /** + * @return void + */ + public function next() {} + + /** + * @return void + */ + public function rewind() {} + + /** + * @return void + */ + public function valid() {} + + /** + * @return void + */ + protected function _indexEntries() {} + +} diff --git a/libs/Zend/Feed/Reader/Feed/Rss.php b/libs/Zend/Feed/Reader/Feed/Rss.php index 2dc2ec86f4..bff78c3455 100644 --- a/libs/Zend/Feed/Reader/Feed/Rss.php +++ b/libs/Zend/Feed/Reader/Feed/Rss.php @@ -14,35 +14,40 @@ * * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Rss.php 18367 2009-09-22 14:55:59Z padraic $ + * @version $Id: Rss.php 22301 2010-05-26 10:15:13Z padraic $ */ /** * @see Zend_Feed_Reader_FeedAbstract */ -require_once 'Zend/Feed/Reader/FeedAbstract.php'; +// require_once 'Zend/Feed/Reader/FeedAbstract.php'; /** * @see Zend_feed_Reader_Extension_Atom_Feed */ -require_once 'Zend/Feed/Reader/Extension/Atom/Feed.php'; +// require_once 'Zend/Feed/Reader/Extension/Atom/Feed.php'; /** * @see Zend_Feed_Reader_Extension_DublinCore_Feed */ -require_once 'Zend/Feed/Reader/Extension/DublinCore/Feed.php'; +// require_once 'Zend/Feed/Reader/Extension/DublinCore/Feed.php'; /** * @see Zend_Date */ -require_once 'Zend/Date.php'; +// require_once 'Zend/Date.php'; + +/** + * @see Zend_Feed_Reader_Collection_Author + */ +// require_once 'Zend/Feed/Reader/Collection/Author.php'; /** * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Feed_Reader_Feed_Rss extends Zend_Feed_Reader_FeedAbstract @@ -51,9 +56,8 @@ class Zend_Feed_Reader_Feed_Rss extends Zend_Feed_Reader_FeedAbstract /** * Constructor * - * @param Zend_Feed_Abstract $feed + * @param DOMDocument $dom * @param string $type - * @param string $xpath */ public function __construct(DomDocument $dom, $type = null) { @@ -74,7 +78,7 @@ class Zend_Feed_Reader_Feed_Rss extends Zend_Feed_Reader_FeedAbstract } } - /** + /** * Get a single author * * @param int $index @@ -101,33 +105,54 @@ class Zend_Feed_Reader_Feed_Rss extends Zend_Feed_Reader_FeedAbstract if (array_key_exists('authors', $this->_data)) { return $this->_data['authors']; } - + $authors = array(); - - if (empty($authors)) { - $authors = $this->getExtension('DublinCore')->getAuthors(); - } - - if (empty($authors)) { - if ($this->getType() !== Zend_Feed_Reader::TYPE_RSS_10 && $this->getType() !== Zend_Feed_Reader::TYPE_RSS_090) { - $list = $this->_xpath->query('//author'); - } else { - $list = $this->_xpath->query('//rss:author'); + $authors_dc = $this->getExtension('DublinCore')->getAuthors(); + if (!empty($authors_dc)) { + foreach ($authors_dc as $author) { + $authors[] = array( + 'name' => $author['name'] + ); } + } - foreach ($list as $authorObj) { - $authors[] = $authorObj->nodeValue; + /** + * Technically RSS doesn't specific author element use at the feed level + * but it's supported on a "just in case" basis. + */ + if ($this->getType() !== Zend_Feed_Reader::TYPE_RSS_10 + && $this->getType() !== Zend_Feed_Reader::TYPE_RSS_090) { + $list = $this->_xpath->query('//author'); + } else { + $list = $this->_xpath->query('//rss:author'); + } + if ($list->length) { + foreach ($list as $author) { + $string = trim($author->nodeValue); + $email = null; + $name = null; + $data = array(); + // Pretty rough parsing - but it's a catchall + if (preg_match("/^.*@[^ ]*/", $string, $matches)) { + $data['email'] = trim($matches[0]); + if (preg_match("/\((.*)\)$/", $string, $matches)) { + $data['name'] = $matches[1]; + } + $authors[] = $data; + } } } - if (empty($authors)) { + if (count($authors) == 0) { $authors = $this->getExtension('Atom')->getAuthors(); + } else { + $authors = new Zend_Feed_Reader_Collection_Author( + Zend_Feed_Reader::arrayUnique($authors) + ); } - if (empty($authors)) { + if (count($authors) == 0) { $authors = null; - } else { - $authors = array_unique($authors); } $this->_data['authors'] = $authors; @@ -170,7 +195,7 @@ class Zend_Feed_Reader_Feed_Rss extends Zend_Feed_Reader_FeedAbstract return $this->_data['copyright']; } - /** + /** * Get the feed creation date * * @return string|null @@ -201,21 +226,27 @@ class Zend_Feed_Reader_Feed_Rss extends Zend_Feed_Reader_FeedAbstract $dateModified = $this->_xpath->evaluate('string(/rss/channel/lastBuildDate)'); } if ($dateModified) { - $dateStandards = array(Zend_Date::RSS, Zend_Date::RFC_822, - Zend_Date::RFC_2822, Zend_Date::DATES); - $date = new Zend_Date; - foreach ($dateStandards as $standard) { - try { - $date->set($dateModified, $standard); - break; - } catch (Zend_Date_Exception $e) { - if ($standard == Zend_Date::DATES) { - require_once 'Zend/Feed/Exception.php'; - throw new Zend_Feed_Exception( - 'Could not load date due to unrecognised' - .' format (should follow RFC 822 or 2822):' - . $e->getMessage() - ); + $dateModifiedParsed = strtotime($dateModified); + if ($dateModifiedParsed) { + $date = new Zend_Date($dateModifiedParsed); + } else { + $dateStandards = array(Zend_Date::RSS, Zend_Date::RFC_822, + Zend_Date::RFC_2822, Zend_Date::DATES); + $date = new Zend_Date; + foreach ($dateStandards as $standard) { + try { + $date->set($dateModified, $standard); + break; + } catch (Zend_Date_Exception $e) { + if ($standard == Zend_Date::DATES) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception( + 'Could not load date due to unrecognised' + .' format (should follow RFC 822 or 2822):' + . $e->getMessage(), + 0, $e + ); + } } } } @@ -240,6 +271,60 @@ class Zend_Feed_Reader_Feed_Rss extends Zend_Feed_Reader_FeedAbstract } /** + * Get the feed lastBuild date + * + * @return Zend_Date + */ + public function getLastBuildDate() + { + if (array_key_exists('lastBuildDate', $this->_data)) { + return $this->_data['lastBuildDate']; + } + + $lastBuildDate = null; + $date = null; + + if ($this->getType() !== Zend_Feed_Reader::TYPE_RSS_10 && + $this->getType() !== Zend_Feed_Reader::TYPE_RSS_090) { + $lastBuildDate = $this->_xpath->evaluate('string(/rss/channel/lastBuildDate)'); + if ($lastBuildDate) { + $lastBuildDateParsed = strtotime($lastBuildDate); + if ($lastBuildDateParsed) { + $date = new Zend_Date($lastBuildDateParsed); + } else { + $dateStandards = array(Zend_Date::RSS, Zend_Date::RFC_822, + Zend_Date::RFC_2822, Zend_Date::DATES); + $date = new Zend_Date; + foreach ($dateStandards as $standard) { + try { + $date->set($lastBuildDate, $standard); + break; + } catch (Zend_Date_Exception $e) { + if ($standard == Zend_Date::DATES) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception( + 'Could not load date due to unrecognised' + .' format (should follow RFC 822 or 2822):' + . $e->getMessage(), + 0, $e + ); + } + } + } + } + } + } + + if (!$date) { + $date = null; + } + + $this->_data['lastBuildDate'] = $date; + + return $this->_data['lastBuildDate']; + } + + /** * Get the feed description * * @return string|null @@ -318,6 +403,60 @@ class Zend_Feed_Reader_Feed_Rss extends Zend_Feed_Reader_FeedAbstract } /** + * Get the feed image data + * + * @return array|null + */ + public function getImage() + { + if (array_key_exists('image', $this->_data)) { + return $this->_data['image']; + } + + if ($this->getType() !== Zend_Feed_Reader::TYPE_RSS_10 && + $this->getType() !== Zend_Feed_Reader::TYPE_RSS_090) { + $list = $this->_xpath->query('/rss/channel/image'); + $prefix = '/rss/channel/image[1]'; + } else { + $list = $this->_xpath->query('/rdf:RDF/rss:channel/rss:image'); + $prefix = '/rdf:RDF/rss:channel/rss:image[1]'; + } + if ($list->length > 0) { + $image = array(); + $value = $this->_xpath->evaluate('string(' . $prefix . '/url)'); + if ($value) { + $image['uri'] = $value; + } + $value = $this->_xpath->evaluate('string(' . $prefix . '/link)'); + if ($value) { + $image['link'] = $value; + } + $value = $this->_xpath->evaluate('string(' . $prefix . '/title)'); + if ($value) { + $image['title'] = $value; + } + $value = $this->_xpath->evaluate('string(' . $prefix . '/height)'); + if ($value) { + $image['height'] = $value; + } + $value = $this->_xpath->evaluate('string(' . $prefix . '/width)'); + if ($value) { + $image['width'] = $value; + } + $value = $this->_xpath->evaluate('string(' . $prefix . '/description)'); + if ($value) { + $image['description'] = $value; + } + } else { + $image = null; + } + + $this->_data['image'] = $image; + + return $this->_data['image']; + } + + /** * Get the feed language * * @return string|null @@ -404,8 +543,8 @@ class Zend_Feed_Reader_Feed_Rss extends Zend_Feed_Reader_FeedAbstract $link = $this->getExtension('Atom')->getFeedLink(); - if (!$link) { - $link = null; + if (is_null($link) || empty($link)) { + $link = $this->getOriginalSourceUri(); } $this->_data['feedlink'] = $link; @@ -438,9 +577,6 @@ class Zend_Feed_Reader_Feed_Rss extends Zend_Feed_Reader_FeedAbstract } else { $generator = $this->_xpath->evaluate('string(/rdf:RDF/rss:channel/atom:generator)'); } - if ($generator) { - $generator = html_entity_decode($generator, ENT_QUOTES, $this->getEncoding()); - } } if (empty($generator)) { @@ -493,7 +629,71 @@ class Zend_Feed_Reader_Feed_Rss extends Zend_Feed_Reader_FeedAbstract return $this->_data['title']; } - /** + /** + * Get an array of any supported Pusubhubbub endpoints + * + * @return array|null + */ + public function getHubs() + { + if (array_key_exists('hubs', $this->_data)) { + return $this->_data['hubs']; + } + + $hubs = $this->getExtension('Atom')->getHubs(); + + if (empty($hubs)) { + $hubs = null; + } else { + $hubs = array_unique($hubs); + } + + $this->_data['hubs'] = $hubs; + + return $this->_data['hubs']; + } + + /** + * Get all categories + * + * @return Zend_Feed_Reader_Collection_Category + */ + public function getCategories() + { + if (array_key_exists('categories', $this->_data)) { + return $this->_data['categories']; + } + + if ($this->getType() !== Zend_Feed_Reader::TYPE_RSS_10 && + $this->getType() !== Zend_Feed_Reader::TYPE_RSS_090) { + $list = $this->_xpath->query('/rss/channel//category'); + } else { + $list = $this->_xpath->query('/rdf:RDF/rss:channel//rss:category'); + } + + if ($list->length) { + $categoryCollection = new Zend_Feed_Reader_Collection_Category; + foreach ($list as $category) { + $categoryCollection[] = array( + 'term' => $category->nodeValue, + 'scheme' => $category->getAttribute('domain'), + 'label' => $category->nodeValue, + ); + } + } else { + $categoryCollection = $this->getExtension('DublinCore')->getCategories(); + } + + if (count($categoryCollection) == 0) { + $categoryCollection = $this->getExtension('Atom')->getCategories(); + } + + $this->_data['categories'] = $categoryCollection; + + return $this->_data['categories']; + } + + /** * Read all entries to the internal entries array * */ diff --git a/libs/Zend/Feed/Reader/FeedAbstract.php b/libs/Zend/Feed/Reader/FeedAbstract.php index 1e8da71726..bda9f23b46 100644 --- a/libs/Zend/Feed/Reader/FeedAbstract.php +++ b/libs/Zend/Feed/Reader/FeedAbstract.php @@ -14,41 +14,30 @@ * * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: FeedAbstract.php 16966 2009-07-22 15:22:18Z padraic $ + * @version $Id: FeedAbstract.php 22093 2010-05-04 12:55:06Z padraic $ */ /** * @see Zend_Feed_Reader */ -require_once 'Zend/Feed/Reader.php'; - -/** - * @see Zend_Feed_Reader_Entry_Atom - */ -require_once 'Zend/Feed/Reader/Entry/Atom.php'; - - -/** - * @see Zend_Feed_Reader_Entry_Rss - */ -require_once 'Zend/Feed/Reader/Entry/Rss.php'; +// require_once 'Zend/Feed/Reader.php'; /** * @see Zend_feed_Reader_FeedInterface */ -require_once 'Zend/Feed/Reader/FeedInterface.php'; +// require_once 'Zend/Feed/Reader/FeedInterface.php'; /** * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ abstract class Zend_Feed_Reader_FeedAbstract implements Zend_Feed_Reader_FeedInterface { - /** + /** * Parsed feed data * * @var array @@ -83,9 +72,21 @@ abstract class Zend_Feed_Reader_FeedAbstract implements Zend_Feed_Reader_FeedInt */ protected $_xpath = null; + /** + * Array of loaded extensions + * + * @var array + */ protected $_extensions = array(); /** + * Original Source URI (set if imported from a URI) + * + * @var string + */ + protected $_originalSourceUri = null; + + /** * Constructor * * @param DomDocument The DOM object for the feed's XML @@ -106,7 +107,30 @@ abstract class Zend_Feed_Reader_FeedAbstract implements Zend_Feed_Reader_FeedInt $this->_loadExtensions(); } - /** + /** + * Set an original source URI for the feed being parsed. This value + * is returned from getFeedLink() method if the feed does not carry + * a self-referencing URI. + * + * @param string $uri + */ + public function setOriginalSourceUri($uri) + { + $this->_originalSourceUri = $uri; + } + + /** + * Get an original source URI for the feed being parsed. Returns null if + * unset or the feed was not imported from a URI. + * + * @return string|null + */ + public function getOriginalSourceUri() + { + return $this->_originalSourceUri; + } + + /** * Get the number of feed entries. * Required by the Iterator interface. * @@ -117,10 +141,10 @@ abstract class Zend_Feed_Reader_FeedAbstract implements Zend_Feed_Reader_FeedInt return count($this->_entries); } - /** + /** * Return the current entry * - * @return Zend_Feed_Reader_Entry_Interface + * @return Zend_Feed_Reader_EntryInterface */ public function current() { @@ -153,6 +177,9 @@ abstract class Zend_Feed_Reader_FeedAbstract implements Zend_Feed_Reader_FeedInt public function getEncoding() { $assumed = $this->getDomDocument()->encoding; + if (empty($assumed)) { + $assumed = 'UTF-8'; + } return $assumed; } @@ -196,7 +223,7 @@ abstract class Zend_Feed_Reader_FeedAbstract implements Zend_Feed_Reader_FeedInt return $this->_data['type']; } - /** + /** * Return the current feed key * * @return unknown @@ -206,7 +233,7 @@ abstract class Zend_Feed_Reader_FeedAbstract implements Zend_Feed_Reader_FeedInt return $this->_entriesKey; } - /** + /** * Move the feed pointer forward * */ @@ -225,16 +252,6 @@ abstract class Zend_Feed_Reader_FeedAbstract implements Zend_Feed_Reader_FeedInt } /** - * Return the feed as an array - * - * @return array - */ - public function toArray() // untested - { - return $this->_data; - } - - /** * Check to see if the iterator is still valid * * @return boolean @@ -256,7 +273,7 @@ abstract class Zend_Feed_Reader_FeedAbstract implements Zend_Feed_Reader_FeedInt return call_user_func_array(array($extension, $method), $args); } } - require_once 'Zend/Feed/Exception.php'; + // require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception('Method: ' . $method . 'does not exist and could not be located on a registered Extension'); } diff --git a/libs/Zend/Feed/Reader/FeedInterface.php b/libs/Zend/Feed/Reader/FeedInterface.php index 3278f3ea75..35060bafce 100644 --- a/libs/Zend/Feed/Reader/FeedInterface.php +++ b/libs/Zend/Feed/Reader/FeedInterface.php @@ -14,15 +14,15 @@ * * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: FeedInterface.php 16953 2009-07-22 11:57:25Z padraic $ + * @version $Id: FeedInterface.php 20096 2010-01-06 02:05:09Z bkarwin $ */ /** * @category Zend * @package Zend_Feed_Reader - * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ interface Zend_Feed_Reader_FeedInterface extends Iterator, Countable @@ -111,5 +111,12 @@ interface Zend_Feed_Reader_FeedInterface extends Iterator, Countable * @return string|null */ public function getTitle(); + + /** + * Get all categories + * + * @return Zend_Feed_Reader_Collection_Category + */ + public function getCategories(); } diff --git a/libs/Zend/Feed/Reader/FeedSet.php b/libs/Zend/Feed/Reader/FeedSet.php new file mode 100644 index 0000000000..57ccbf6056 --- /dev/null +++ b/libs/Zend/Feed/Reader/FeedSet.php @@ -0,0 +1,148 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Reader + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: FeedSet.php 20096 2010-01-06 02:05:09Z bkarwin $ + */ + +/** + * @see Zend_Feed_Reader + */ +// require_once 'Zend/Feed/Reader.php'; + +/** + * @see Zend_Uri + */ +// require_once 'Zend/Uri.php'; + +/** + * @category Zend + * @package Zend_Feed_Reader + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Reader_FeedSet extends ArrayObject +{ + + public $rss = null; + + public $rdf = null; + + public $atom = null; + + /** + * Import a DOMNodeList from any document containing a set of links + * for alternate versions of a document, which will normally refer to + * RSS/RDF/Atom feeds for the current document. + * + * All such links are stored internally, however the first instance of + * each RSS, RDF or Atom type has its URI stored as a public property + * as a shortcut where the use case is simply to get a quick feed ref. + * + * Note that feeds are not loaded at this point, but will be lazy + * loaded automatically when each links 'feed' array key is accessed. + * + * @param DOMNodeList $links + * @param string $uri + * @return void + */ + public function addLinks(DOMNodeList $links, $uri) + { + foreach ($links as $link) { + if (strtolower($link->getAttribute('rel')) !== 'alternate' + || !$link->getAttribute('type') || !$link->getAttribute('href')) { + continue; + } + if (!isset($this->rss) && $link->getAttribute('type') == 'application/rss+xml') { + $this->rss = $this->_absolutiseUri(trim($link->getAttribute('href')), $uri); + } elseif(!isset($this->atom) && $link->getAttribute('type') == 'application/atom+xml') { + $this->atom = $this->_absolutiseUri(trim($link->getAttribute('href')), $uri); + } elseif(!isset($this->rdf) && $link->getAttribute('type') == 'application/rdf+xml') { + $this->rdf = $this->_absolutiseUri(trim($link->getAttribute('href')), $uri); + } + $this[] = new self(array( + 'rel' => 'alternate', + 'type' => $link->getAttribute('type'), + 'href' => $this->_absolutiseUri(trim($link->getAttribute('href')), $uri), + )); + } + } + + /** + * Attempt to turn a relative URI into an absolute URI + */ + protected function _absolutiseUri($link, $uri = null) + { + if (!Zend_Uri::check($link)) { + if (!is_null($uri)) { + $uri = Zend_Uri::factory($uri); + + if ($link[0] !== '/') { + $link = $uri->getPath() . '/' . $link; + } + + $link = $uri->getScheme() . '://' . $uri->getHost() . '/' . $this->_canonicalizePath($link); + if (!Zend_Uri::check($link)) { + $link = null; + } + } + } + return $link; + } + + /** + * Canonicalize relative path + */ + protected function _canonicalizePath($path) + { + $parts = array_filter(explode('/', $path)); + $absolutes = array(); + foreach ($parts as $part) { + if ('.' == $part) { + continue; + } + if ('..' == $part) { + array_pop($absolutes); + } else { + $absolutes[] = $part; + } + } + return implode('/', $absolutes); + } + + /** + * Supports lazy loading of feeds using Zend_Feed_Reader::import() but + * delegates any other operations to the parent class. + * + * @param string $offset + * @return mixed + * @uses Zend_Feed_Reader + */ + public function offsetGet($offset) + { + if ($offset == 'feed' && !$this->offsetExists('feed')) { + if (!$this->offsetExists('href')) { + return null; + } + $feed = Zend_Feed_Reader::import($this->offsetGet('href')); + $this->offsetSet('feed', $feed); + return $feed; + } + return parent::offsetGet($offset); + } + +} diff --git a/libs/Zend/Feed/Rss.php b/libs/Zend/Feed/Rss.php index 351dcdf2e5..19eaa8ec19 100644 --- a/libs/Zend/Feed/Rss.php +++ b/libs/Zend/Feed/Rss.php @@ -15,21 +15,21 @@ * * @category Zend * @package Zend_Feed - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Rss.php 18266 2009-09-18 18:32:30Z padraic $ + * @version $Id: Rss.php 20096 2010-01-06 02:05:09Z bkarwin $ */ /** * @see Zend_Feed_Abstract */ -require_once 'Zend/Feed/Abstract.php'; +// require_once 'Zend/Feed/Abstract.php'; /** * @see Zend_Feed_Entry_Rss */ -require_once 'Zend/Feed/Entry/Rss.php'; +// require_once 'Zend/Feed/Entry/Rss.php'; /** @@ -43,7 +43,7 @@ require_once 'Zend/Feed/Entry/Rss.php'; * * @category Zend * @package Zend_Feed - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Feed_Rss extends Zend_Feed_Abstract @@ -82,7 +82,7 @@ class Zend_Feed_Rss extends Zend_Feed_Abstract // Find the base channel element and create an alias to it. $rdfTags = $this->_element->getElementsByTagNameNS('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'RDF'); if ($rdfTags->length != 0) { - $this->_element = $rdfTags->item(0); + $this->_element = $rdfTags->item(0); } else { $this->_element = $this->_element->getElementsByTagName('channel')->item(0); } @@ -90,7 +90,7 @@ class Zend_Feed_Rss extends Zend_Feed_Abstract /** * @see Zend_Feed_Exception */ - require_once 'Zend/Feed/Exception.php'; + // require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception('No root <channel> element found, cannot parse channel.'); } @@ -282,11 +282,12 @@ class Zend_Feed_Rss extends Zend_Feed_Abstract $author = ''; $email = ''; if (isset($array->itunes->owner)) { - if (isset($array->itunes->owner['name'])) { - $author = $array->itunes->owner['name']; + $itunesOwner = $array->itunes->owner; + if (isset($itunesOwner['name'])) { + $author = $itunesOwner['name']; } - if (isset($array->itunes->owner['email'])) { - $email = $array->itunes->owner['email']; + if (isset($itunesOwner['email'])) { + $email = $itunesOwner['email']; } } if (empty($author) && isset($array->author)) { @@ -411,6 +412,9 @@ class Zend_Feed_Rss extends Zend_Feed_Abstract if (isset($dataentry->guid)) { $guid = $this->_element->createElement('guid', $dataentry->guid); + if (!Zend_Uri::check($dataentry->guid)) { + $guid->setAttribute('isPermaLink', 'false'); + } $item->appendChild($guid); } @@ -514,7 +518,7 @@ class Zend_Feed_Rss extends Zend_Feed_Abstract /** * @see Zend_Feed_Exception */ - require_once 'Zend/Feed/Exception.php'; + // require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception('Cannot send RSS because headers have already been sent.'); } diff --git a/libs/Zend/Feed/Writer.php b/libs/Zend/Feed/Writer.php new file mode 100644 index 0000000000..1a40f63cd9 --- /dev/null +++ b/libs/Zend/Feed/Writer.php @@ -0,0 +1,267 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Writer.php 20096 2010-01-06 02:05:09Z bkarwin $ + */ + +/** + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Writer +{ + /** + * Namespace constants + */ + const NAMESPACE_ATOM_03 = 'http://purl.org/atom/ns#'; + const NAMESPACE_ATOM_10 = 'http://www.w3.org/2005/Atom'; + const NAMESPACE_RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'; + const NAMESPACE_RSS_090 = 'http://my.netscape.com/rdf/simple/0.9/'; + const NAMESPACE_RSS_10 = 'http://purl.org/rss/1.0/'; + + /** + * Feed type constants + */ + const TYPE_ANY = 'any'; + const TYPE_ATOM_03 = 'atom-03'; + const TYPE_ATOM_10 = 'atom-10'; + const TYPE_ATOM_ANY = 'atom'; + const TYPE_RSS_090 = 'rss-090'; + const TYPE_RSS_091 = 'rss-091'; + const TYPE_RSS_091_NETSCAPE = 'rss-091n'; + const TYPE_RSS_091_USERLAND = 'rss-091u'; + const TYPE_RSS_092 = 'rss-092'; + const TYPE_RSS_093 = 'rss-093'; + const TYPE_RSS_094 = 'rss-094'; + const TYPE_RSS_10 = 'rss-10'; + const TYPE_RSS_20 = 'rss-20'; + const TYPE_RSS_ANY = 'rss'; + + /** + * PluginLoader instance used by component + * + * @var Zend_Loader_PluginLoader_Interface + */ + protected static $_pluginLoader = null; + + /** + * Path on which to search for Extension classes + * + * @var array + */ + protected static $_prefixPaths = array(); + + /** + * Array of registered extensions by class postfix (after the base class + * name) across four categories - data containers and renderers for entry + * and feed levels. + * + * @var array + */ + protected static $_extensions = array( + 'entry' => array(), + 'feed' => array(), + 'entryRenderer' => array(), + 'feedRenderer' => array(), + ); + + /** + * Set plugin loader for use with Extensions + * + * @param Zend_Loader_PluginLoader_Interface + */ + public static function setPluginLoader(Zend_Loader_PluginLoader_Interface $loader) + { + self::$_pluginLoader = $loader; + } + + /** + * Get plugin loader for use with Extensions + * + * @return Zend_Loader_PluginLoader_Interface + */ + public static function getPluginLoader() + { + if (!isset(self::$_pluginLoader)) { + // require_once 'Zend/Loader/PluginLoader.php'; + self::$_pluginLoader = new Zend_Loader_PluginLoader(array( + 'Zend_Feed_Writer_Extension_' => 'Zend/Feed/Writer/Extension/', + )); + } + return self::$_pluginLoader; + } + + /** + * Add prefix path for loading Extensions + * + * @param string $prefix + * @param string $path + * @return void + */ + public static function addPrefixPath($prefix, $path) + { + $prefix = rtrim($prefix, '_'); + $path = rtrim($path, DIRECTORY_SEPARATOR); + self::getPluginLoader()->addPrefixPath($prefix, $path); + } + + /** + * Add multiple Extension prefix paths at once + * + * @param array $spec + * @return void + */ + public static function addPrefixPaths(array $spec) + { + if (isset($spec['prefix']) && isset($spec['path'])) { + self::addPrefixPath($spec['prefix'], $spec['path']); + } + foreach ($spec as $prefixPath) { + if (isset($prefixPath['prefix']) && isset($prefixPath['path'])) { + self::addPrefixPath($prefixPath['prefix'], $prefixPath['path']); + } + } + } + + /** + * Register an Extension by name + * + * @param string $name + * @return void + * @throws Zend_Feed_Exception if unable to resolve Extension class + */ + public static function registerExtension($name) + { + $feedName = $name . '_Feed'; + $entryName = $name . '_Entry'; + $feedRendererName = $name . '_Renderer_Feed'; + $entryRendererName = $name . '_Renderer_Entry'; + if (self::isRegistered($name)) { + if (self::getPluginLoader()->isLoaded($feedName) + || self::getPluginLoader()->isLoaded($entryName) + || self::getPluginLoader()->isLoaded($feedRendererName) + || self::getPluginLoader()->isLoaded($entryRendererName) + ) { + return; + } + } + try { + self::getPluginLoader()->load($feedName); + self::$_extensions['feed'][] = $feedName; + } catch (Zend_Loader_PluginLoader_Exception $e) { + } + try { + self::getPluginLoader()->load($entryName); + self::$_extensions['entry'][] = $entryName; + } catch (Zend_Loader_PluginLoader_Exception $e) { + } + try { + self::getPluginLoader()->load($feedRendererName); + self::$_extensions['feedRenderer'][] = $feedRendererName; + } catch (Zend_Loader_PluginLoader_Exception $e) { + } + try { + self::getPluginLoader()->load($entryRendererName); + self::$_extensions['entryRenderer'][] = $entryRendererName; + } catch (Zend_Loader_PluginLoader_Exception $e) { + } + if (!self::getPluginLoader()->isLoaded($feedName) + && !self::getPluginLoader()->isLoaded($entryName) + && !self::getPluginLoader()->isLoaded($feedRendererName) + && !self::getPluginLoader()->isLoaded($entryRendererName) + ) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Could not load extension: ' . $name + . 'using Plugin Loader. Check prefix paths are configured and extension exists.'); + } + } + + /** + * Is a given named Extension registered? + * + * @param string $extensionName + * @return boolean + */ + public static function isRegistered($extensionName) + { + $feedName = $extensionName . '_Feed'; + $entryName = $extensionName . '_Entry'; + $feedRendererName = $extensionName . '_Renderer_Feed'; + $entryRendererName = $extensionName . '_Renderer_Entry'; + if (in_array($feedName, self::$_extensions['feed']) + || in_array($entryName, self::$_extensions['entry']) + || in_array($feedRendererName, self::$_extensions['feedRenderer']) + || in_array($entryRendererName, self::$_extensions['entryRenderer']) + ) { + return true; + } + return false; + } + + /** + * Get a list of extensions + * + * @return array + */ + public static function getExtensions() + { + return self::$_extensions; + } + + /** + * Reset class state to defaults + * + * @return void + */ + public static function reset() + { + self::$_pluginLoader = null; + self::$_prefixPaths = array(); + self::$_extensions = array( + 'entry' => array(), + 'feed' => array(), + 'entryRenderer' => array(), + 'feedRenderer' => array(), + ); + } + + /** + * Register core (default) extensions + * + * @return void + */ + public static function registerCoreExtensions() + { + self::registerExtension('DublinCore'); + self::registerExtension('Content'); + self::registerExtension('Atom'); + self::registerExtension('Slash'); + self::registerExtension('WellFormedWeb'); + self::registerExtension('Threading'); + self::registerExtension('ITunes'); + } + + public static function lcfirst($str) + { + $str[0] = strtolower($str[0]); + return $str; + } + +} diff --git a/libs/Zend/Feed/Writer/Deleted.php b/libs/Zend/Feed/Writer/Deleted.php new file mode 100644 index 0000000000..19bb56b49e --- /dev/null +++ b/libs/Zend/Feed/Writer/Deleted.php @@ -0,0 +1,202 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Feed.php 20096 2010-01-06 02:05:09Z bkarwin $ + */ + +// require_once 'Zend/Feed/Writer/Feed/FeedAbstract.php'; + + /** + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Writer_Deleted +{ + + /** + * Internal array containing all data associated with this entry or item. + * + * @var array + */ + protected $_data = array(); + + /** + * Holds the value "atom" or "rss" depending on the feed type set when + * when last exported. + * + * @var string + */ + protected $_type = null; + + /** + * Set the feed character encoding + * + * @return string|null + */ + public function setEncoding($encoding) + { + if (empty($encoding) || !is_string($encoding)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: parameter must be a non-empty string'); + } + $this->_data['encoding'] = $encoding; + } + + /** + * Get the feed character encoding + * + * @return string|null + */ + public function getEncoding() + { + if (!array_key_exists('encoding', $this->_data)) { + return 'UTF-8'; + } + return $this->_data['encoding']; + } + + /** + * Unset a specific data point + * + * @param string $name + */ + public function remove($name) + { + if (isset($this->_data[$name])) { + unset($this->_data[$name]); + } + } + + /** + * Set the current feed type being exported to "rss" or "atom". This allows + * other objects to gracefully choose whether to execute or not, depending + * on their appropriateness for the current type, e.g. renderers. + * + * @param string $type + */ + public function setType($type) + { + $this->_type = $type; + } + + /** + * Retrieve the current or last feed type exported. + * + * @return string Value will be "rss" or "atom" + */ + public function getType() + { + return $this->_type; + } + + public function setReference($reference) + { + if (empty($reference) || !is_string($reference)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: reference must be a non-empty string'); + } + $this->_data['reference'] = $reference; + } + + public function getReference() + { + if (!array_key_exists('reference', $this->_data)) { + return null; + } + return $this->_data['reference']; + } + + public function setWhen($date = null) + { + $zdate = null; + if (is_null($date)) { + $zdate = new Zend_Date; + } elseif (ctype_digit($date) && strlen($date) == 10) { + $zdate = new Zend_Date($date, Zend_Date::TIMESTAMP); + } elseif ($date instanceof Zend_Date) { + $zdate = $date; + } else { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid Zend_Date object or UNIX Timestamp passed as parameter'); + } + $this->_data['when'] = $zdate; + } + + public function getWhen() + { + if (!array_key_exists('when', $this->_data)) { + return null; + } + return $this->_data['when']; + } + + public function setBy(array $by) + { + $author = array(); + if (!array_key_exists('name', $by) + || empty($by['name']) + || !is_string($by['name']) + ) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: author array must include a "name" key with a non-empty string value'); + } + $author['name'] = $by['name']; + if (isset($by['email'])) { + if (empty($by['email']) || !is_string($by['email'])) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: "email" array value must be a non-empty string'); + } + $author['email'] = $by['email']; + } + if (isset($by['uri'])) { + if (empty($by['uri']) + || !is_string($by['uri']) + || !Zend_Uri::check($by['uri']) + ) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: "uri" array value must be a non-empty string and valid URI/IRI'); + } + $author['uri'] = $by['uri']; + } + $this->_data['by'] = $author; + } + + public function getBy() + { + if (!array_key_exists('by', $this->_data)) { + return null; + } + return $this->_data['by']; + } + + public function setComment($comment) + { + $this->_data['comment'] = $comment; + } + + public function getComment() + { + if (!array_key_exists('comment', $this->_data)) { + return null; + } + return $this->_data['comment']; + } + +} diff --git a/libs/Zend/Feed/Writer/Entry.php b/libs/Zend/Feed/Writer/Entry.php new file mode 100644 index 0000000000..01d290e6fb --- /dev/null +++ b/libs/Zend/Feed/Writer/Entry.php @@ -0,0 +1,761 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Entry.php 22065 2010-04-30 14:04:57Z padraic $ + */ + +/** + * @see Zend_Date + */ +// require_once 'Zend/Date.php'; + +/** + * @see Zend_Date + */ +// require_once 'Zend/Uri.php'; + +// require_once 'Zend/Feed/Writer/Source.php'; + +/** + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Writer_Entry +{ + + /** + * Internal array containing all data associated with this entry or item. + * + * @var array + */ + protected $_data = array(); + + /** + * Registered extensions + * + * @var array + */ + protected $_extensions = array(); + + /** + * Holds the value "atom" or "rss" depending on the feed type set when + * when last exported. + * + * @var string + */ + protected $_type = null; + + /** + * Constructor: Primarily triggers the registration of core extensions and + * loads those appropriate to this data container. + * + * @return void + */ + public function __construct() + { + Zend_Feed_Writer::registerCoreExtensions(); + $this->_loadExtensions(); + } + + /** + * Set a single author + * + * @param int $index + * @return string|null + */ + public function addAuthor($name, $email = null, $uri = null) + { + $author = array(); + if (is_array($name)) { + if (!array_key_exists('name', $name) + || empty($name['name']) + || !is_string($name['name']) + ) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: author array must include a "name" key with a non-empty string value'); + } + $author['name'] = $name['name']; + if (isset($name['email'])) { + if (empty($name['email']) || !is_string($name['email'])) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: "email" array value must be a non-empty string'); + } + $author['email'] = $name['email']; + } + if (isset($name['uri'])) { + if (empty($name['uri']) + || !is_string($name['uri']) + || !Zend_Uri::check($name['uri']) + ) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: "uri" array value must be a non-empty string and valid URI/IRI'); + } + $author['uri'] = $name['uri']; + } + /** + * @deprecated + * Array notation (above) is preferred and will be the sole supported input from ZF 2.0 + */ + } else { + if (empty($name['name']) || !is_string($name['name'])) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: "name" must be a non-empty string value'); + } + $author['name'] = $name; + if (isset($email)) { + if (empty($email) || !is_string($email)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: "email" value must be a non-empty string'); + } + $author['email'] = $email; + } + if (isset($uri)) { + if (empty($uri) || !is_string($uri) || !Zend_Uri::check($uri)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: "uri" value must be a non-empty string and valid URI/IRI'); + } + $author['uri'] = $uri; + } + } + $this->_data['authors'][] = $author; + } + + /** + * Set an array with feed authors + * + * @return array + */ + public function addAuthors(array $authors) + { + foreach($authors as $author) { + $this->addAuthor($author); + } + } + + /** + * Set the feed character encoding + * + * @return string|null + */ + public function setEncoding($encoding) + { + if (empty($encoding) || !is_string($encoding)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: parameter must be a non-empty string'); + } + $this->_data['encoding'] = $encoding; + } + + /** + * Get the feed character encoding + * + * @return string|null + */ + public function getEncoding() + { + if (!array_key_exists('encoding', $this->_data)) { + return 'UTF-8'; + } + return $this->_data['encoding']; + } + + /** + * Set the copyright entry + * + * @return string|null + */ + public function setCopyright($copyright) + { + if (empty($copyright) || !is_string($copyright)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: parameter must be a non-empty string'); + } + $this->_data['copyright'] = $copyright; + } + + /** + * Set the entry's content + * + * @return string|null + */ + public function setContent($content) + { + if (empty($content) || !is_string($content)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: parameter must be a non-empty string'); + } + $this->_data['content'] = $content; + } + + /** + * Set the feed creation date + * + * @return string|null + */ + public function setDateCreated($date = null) + { + $zdate = null; + if (is_null($date)) { + $zdate = new Zend_Date; + } elseif (ctype_digit($date) && strlen($date) == 10) { + $zdate = new Zend_Date($date, Zend_Date::TIMESTAMP); + } elseif ($date instanceof Zend_Date) { + $zdate = $date; + } else { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid Zend_Date object or UNIX Timestamp passed as parameter'); + } + $this->_data['dateCreated'] = $zdate; + } + + /** + * Set the feed modification date + * + * @return string|null + */ + public function setDateModified($date = null) + { + $zdate = null; + if (is_null($date)) { + $zdate = new Zend_Date; + } elseif (ctype_digit($date) && strlen($date) == 10) { + $zdate = new Zend_Date($date, Zend_Date::TIMESTAMP); + } elseif ($date instanceof Zend_Date) { + $zdate = $date; + } else { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid Zend_Date object or UNIX Timestamp passed as parameter'); + } + $this->_data['dateModified'] = $zdate; + } + + /** + * Set the feed description + * + * @return string|null + */ + public function setDescription($description) + { + if (empty($description) || !is_string($description)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: parameter must be a non-empty string'); + } + $this->_data['description'] = $description; + } + + /** + * Set the feed ID + * + * @return string|null + */ + public function setId($id) + { + if (empty($id) || !is_string($id)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: parameter must be a non-empty string'); + } + $this->_data['id'] = $id; + } + + /** + * Set a link to the HTML source of this entry + * + * @return string|null + */ + public function setLink($link) + { + if (empty($link) || !is_string($link) || !Zend_Uri::check($link)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: parameter must be a non-empty string and valid URI/IRI'); + } + $this->_data['link'] = $link; + } + + /** + * Set the number of comments associated with this entry + * + * @return string|null + */ + public function setCommentCount($count) + { + if (empty($count) || !is_numeric($count) || (int) $count < 0) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: "count" must be a non-empty integer number'); + } + $this->_data['commentCount'] = (int) $count; + } + + /** + * Set a link to a HTML page containing comments associated with this entry + * + * @return string|null + */ + public function setCommentLink($link) + { + if (empty($link) || !is_string($link) || !Zend_Uri::check($link)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: "link" must be a non-empty string and valid URI/IRI'); + } + $this->_data['commentLink'] = $link; + } + + /** + * Set a link to an XML feed for any comments associated with this entry + * + * @return string|null + */ + public function setCommentFeedLink(array $link) + { + if (!isset($link['uri']) || !is_string($link['uri']) || !Zend_Uri::check($link['uri'])) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: "link" must be a non-empty string and valid URI/IRI'); + } + if (!isset($link['type']) || !in_array($link['type'], array('atom', 'rss', 'rdf'))) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: "type" must be one' + . ' of "atom", "rss" or "rdf"'); + } + if (!isset($this->_data['commentFeedLinks'])) { + $this->_data['commentFeedLinks'] = array(); + } + $this->_data['commentFeedLinks'][] = $link; + } + + /** + * Set a links to an XML feed for any comments associated with this entry. + * Each link is an array with keys "uri" and "type", where type is one of: + * "atom", "rss" or "rdf". + * + * @return string|null + */ + public function setCommentFeedLinks(array $links) + { + foreach ($links as $link) { + $this->setCommentFeedLink($link); + } + } + + /** + * Set the feed title + * + * @return string|null + */ + public function setTitle($title) + { + if (empty($title) || !is_string($title)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: parameter must be a non-empty string'); + } + $this->_data['title'] = $title; + } + + /** + * Get an array with feed authors + * + * @return array + */ + public function getAuthors() + { + if (!array_key_exists('authors', $this->_data)) { + return null; + } + return $this->_data['authors']; + } + + /** + * Get the entry content + * + * @return string + */ + public function getContent() + { + if (!array_key_exists('content', $this->_data)) { + return null; + } + return $this->_data['content']; + } + + /** + * Get the entry copyright information + * + * @return string + */ + public function getCopyright() + { + if (!array_key_exists('copyright', $this->_data)) { + return null; + } + return $this->_data['copyright']; + } + + /** + * Get the entry creation date + * + * @return string + */ + public function getDateCreated() + { + if (!array_key_exists('dateCreated', $this->_data)) { + return null; + } + return $this->_data['dateCreated']; + } + + /** + * Get the entry modification date + * + * @return string + */ + public function getDateModified() + { + if (!array_key_exists('dateModified', $this->_data)) { + return null; + } + return $this->_data['dateModified']; + } + + /** + * Get the entry description + * + * @return string + */ + public function getDescription() + { + if (!array_key_exists('description', $this->_data)) { + return null; + } + return $this->_data['description']; + } + + /** + * Get the entry ID + * + * @return string + */ + public function getId() + { + if (!array_key_exists('id', $this->_data)) { + return null; + } + return $this->_data['id']; + } + + /** + * Get a link to the HTML source + * + * @return string|null + */ + public function getLink() + { + if (!array_key_exists('link', $this->_data)) { + return null; + } + return $this->_data['link']; + } + + + /** + * Get all links + * + * @return array + */ + public function getLinks() + { + if (!array_key_exists('links', $this->_data)) { + return null; + } + return $this->_data['links']; + } + + /** + * Get the entry title + * + * @return string + */ + public function getTitle() + { + if (!array_key_exists('title', $this->_data)) { + return null; + } + return $this->_data['title']; + } + + /** + * Get the number of comments/replies for current entry + * + * @return integer + */ + public function getCommentCount() + { + if (!array_key_exists('commentCount', $this->_data)) { + return null; + } + return $this->_data['commentCount']; + } + + /** + * Returns a URI pointing to the HTML page where comments can be made on this entry + * + * @return string + */ + public function getCommentLink() + { + if (!array_key_exists('commentLink', $this->_data)) { + return null; + } + return $this->_data['commentLink']; + } + + /** + * Returns an array of URIs pointing to a feed of all comments for this entry + * where the array keys indicate the feed type (atom, rss or rdf). + * + * @return string + */ + public function getCommentFeedLinks() + { + if (!array_key_exists('commentFeedLinks', $this->_data)) { + return null; + } + return $this->_data['commentFeedLinks']; + } + + /** + * Add a entry category + * + * @param string $category + */ + public function addCategory(array $category) + { + if (!isset($category['term'])) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Each category must be an array and ' + . 'contain at least a "term" element containing the machine ' + . ' readable category name'); + } + if (isset($category['scheme'])) { + if (empty($category['scheme']) + || !is_string($category['scheme']) + || !Zend_Uri::check($category['scheme']) + ) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('The Atom scheme or RSS domain of' + . ' a category must be a valid URI'); + } + } + if (!isset($this->_data['categories'])) { + $this->_data['categories'] = array(); + } + $this->_data['categories'][] = $category; + } + + /** + * Set an array of entry categories + * + * @param array $categories + */ + public function addCategories(array $categories) + { + foreach ($categories as $category) { + $this->addCategory($category); + } + } + + /** + * Get the entry categories + * + * @return string|null + */ + public function getCategories() + { + if (!array_key_exists('categories', $this->_data)) { + return null; + } + return $this->_data['categories']; + } + + /** + * Adds an enclosure to the entry. The array parameter may contain the + * keys 'uri', 'type' and 'length'. Only 'uri' is required for Atom, though the + * others must also be provided or RSS rendering (where they are required) + * will throw an Exception. + * + * @param array $enclosures + */ + public function setEnclosure(array $enclosure) + { + if (!isset($enclosure['uri'])) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Enclosure "uri" is not set'); + } + if (!Zend_Uri::check($enclosure['uri'])) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Enclosure "uri" is not a valid URI/IRI'); + } + $this->_data['enclosure'] = $enclosure; + } + + /** + * Retrieve an array of all enclosures to be added to entry. + * + * @return array + */ + public function getEnclosure() + { + if (!array_key_exists('enclosure', $this->_data)) { + return null; + } + return $this->_data['enclosure']; + } + + /** + * Unset a specific data point + * + * @param string $name + */ + public function remove($name) + { + if (isset($this->_data[$name])) { + unset($this->_data[$name]); + } + } + + /** + * Get registered extensions + * + * @return array + */ + public function getExtensions() + { + return $this->_extensions; + } + + /** + * Return an Extension object with the matching name (postfixed with _Entry) + * + * @param string $name + * @return object + */ + public function getExtension($name) + { + if (array_key_exists($name . '_Entry', $this->_extensions)) { + return $this->_extensions[$name . '_Entry']; + } + return null; + } + + /** + * Set the current feed type being exported to "rss" or "atom". This allows + * other objects to gracefully choose whether to execute or not, depending + * on their appropriateness for the current type, e.g. renderers. + * + * @param string $type + */ + public function setType($type) + { + $this->_type = $type; + } + + /** + * Retrieve the current or last feed type exported. + * + * @return string Value will be "rss" or "atom" + */ + public function getType() + { + return $this->_type; + } + + /** + * Method overloading: call given method on first extension implementing it + * + * @param string $method + * @param array $args + * @return mixed + * @throws Zend_Feed_Exception if no extensions implements the method + */ + public function __call($method, $args) + { + foreach ($this->_extensions as $extension) { + try { + return call_user_func_array(array($extension, $method), $args); + } catch (Zend_Feed_Writer_Exception_InvalidMethodException $e) { + } + } + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Method: ' . $method + . ' does not exist and could not be located on a registered Extension'); + } + + /** + * Creates a new Zend_Feed_Writer_Source data container for use. This is NOT + * added to the current feed automatically, but is necessary to create a + * container with some initial values preset based on the current feed data. + * + * @return Zend_Feed_Writer_Source + */ + public function createSource() + { + $source = new Zend_Feed_Writer_Source; + if ($this->getEncoding()) { + $source->setEncoding($this->getEncoding()); + } + $source->setType($this->getType()); + return $source; + } + + /** + * Appends a Zend_Feed_Writer_Entry object representing a new entry/item + * the feed data container's internal group of entries. + * + * @param Zend_Feed_Writer_Source $source + */ + public function setSource(Zend_Feed_Writer_Source $source) + { + $this->_data['source'] = $source; + } + + /** + * @return Zend_Feed_Writer_Source + */ + public function getSource() + { + if (isset($this->_data['source'])) { + return $this->_data['source']; + } + return null; + } + + /** + * Load extensions from Zend_Feed_Writer + * + * @return void + */ + protected function _loadExtensions() + { + $all = Zend_Feed_Writer::getExtensions(); + $exts = $all['entry']; + foreach ($exts as $ext) { + $className = Zend_Feed_Writer::getPluginLoader()->getClassName($ext); + $this->_extensions[$ext] = new $className(); + $this->_extensions[$ext]->setEncoding($this->getEncoding()); + } + } +} diff --git a/libs/Zend/Feed/Writer/Exception/InvalidMethodException.php b/libs/Zend/Feed/Writer/Exception/InvalidMethodException.php new file mode 100644 index 0000000000..4510f12b68 --- /dev/null +++ b/libs/Zend/Feed/Writer/Exception/InvalidMethodException.php @@ -0,0 +1,41 @@ +<?php + +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: InvalidMethodException.php 20096 2010-01-06 02:05:09Z bkarwin $ + */ + + +/** + * @see Zend_Feed_Exception + */ +// require_once 'Zend/Feed/Exception.php'; + + +/** + * Feed exceptions + * + * Class to represent exceptions that occur during Feed operations. + * + * @category Zend + * @package Zend_Feed + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Writer_Exception_InvalidMethodException extends Zend_Exception +{} diff --git a/libs/Zend/Feed/Writer/Extension/Atom/Renderer/Feed.php b/libs/Zend/Feed/Writer/Extension/Atom/Renderer/Feed.php new file mode 100644 index 0000000000..588a57af66 --- /dev/null +++ b/libs/Zend/Feed/Writer/Extension/Atom/Renderer/Feed.php @@ -0,0 +1,123 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Feed.php 20326 2010-01-16 00:20:43Z padraic $ + */ + +/** + * @see Zend_Feed_Writer_Extension_RendererAbstract + */ +// require_once 'Zend/Feed/Writer/Extension/RendererAbstract.php'; + +/** + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Writer_Extension_Atom_Renderer_Feed + extends Zend_Feed_Writer_Extension_RendererAbstract +{ + + /** + * Set to TRUE if a rendering method actually renders something. This + * is used to prevent premature appending of a XML namespace declaration + * until an element which requires it is actually appended. + * + * @var bool + */ + protected $_called = false; + + /** + * Render feed + * + * @return void + */ + public function render() + { + /** + * RSS 2.0 only. Used mainly to include Atom links and + * Pubsubhubbub Hub endpoint URIs under the Atom namespace + */ + if (strtolower($this->getType()) == 'atom') { + return; + } + $this->_setFeedLinks($this->_dom, $this->_base); + $this->_setHubs($this->_dom, $this->_base); + if ($this->_called) { + $this->_appendNamespaces(); + } + } + + /** + * Append namespaces to root element of feed + * + * @return void + */ + protected function _appendNamespaces() + { + $this->getRootElement()->setAttribute('xmlns:atom', + 'http://www.w3.org/2005/Atom'); + } + + /** + * Set feed link elements + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setFeedLinks(DOMDocument $dom, DOMElement $root) + { + $flinks = $this->getDataContainer()->getFeedLinks(); + if(!$flinks || empty($flinks)) { + return; + } + foreach ($flinks as $type => $href) { + $mime = 'application/' . strtolower($type) . '+xml'; + $flink = $dom->createElement('atom:link'); + $root->appendChild($flink); + $flink->setAttribute('rel', 'self'); + $flink->setAttribute('type', $mime); + $flink->setAttribute('href', $href); + } + $this->_called = true; + } + + /** + * Set PuSH hubs + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setHubs(DOMDocument $dom, DOMElement $root) + { + $hubs = $this->getDataContainer()->getHubs(); + if (!$hubs || empty($hubs)) { + return; + } + foreach ($hubs as $hubUrl) { + $hub = $dom->createElement('atom:link'); + $hub->setAttribute('rel', 'hub'); + $hub->setAttribute('href', $hubUrl); + $root->appendChild($hub); + } + $this->_called = true; + } +} diff --git a/libs/Zend/Feed/Writer/Extension/Content/Renderer/Entry.php b/libs/Zend/Feed/Writer/Extension/Content/Renderer/Entry.php new file mode 100644 index 0000000000..0036c6325e --- /dev/null +++ b/libs/Zend/Feed/Writer/Extension/Content/Renderer/Entry.php @@ -0,0 +1,92 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Entry.php 20326 2010-01-16 00:20:43Z padraic $ + */ + +/** + * @see Zend_Feed_Writer_Extension_RendererAbstract + */ +// require_once 'Zend/Feed/Writer/Extension/RendererAbstract.php'; + +/** + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Writer_Extension_Content_Renderer_Entry + extends Zend_Feed_Writer_Extension_RendererAbstract +{ + + /** + * Set to TRUE if a rendering method actually renders something. This + * is used to prevent premature appending of a XML namespace declaration + * until an element which requires it is actually appended. + * + * @var bool + */ + protected $_called = false; + + /** + * Render entry + * + * @return void + */ + public function render() + { + if (strtolower($this->getType()) == 'atom') { + return; + } + $this->_setContent($this->_dom, $this->_base); + if ($this->_called) { + $this->_appendNamespaces(); + } + } + + /** + * Append namespaces to root element + * + * @return void + */ + protected function _appendNamespaces() + { + $this->getRootElement()->setAttribute('xmlns:content', + 'http://purl.org/rss/1.0/modules/content/'); + } + + /** + * Set entry content + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setContent(DOMDocument $dom, DOMElement $root) + { + $content = $this->getDataContainer()->getContent(); + if (!$content) { + return; + } + $element = $dom->createElement('content:encoded'); + $root->appendChild($element); + $cdata = $dom->createCDATASection($content); + $element->appendChild($cdata); + $this->_called = true; + } +} diff --git a/libs/Zend/Feed/Writer/Extension/DublinCore/Renderer/Entry.php b/libs/Zend/Feed/Writer/Extension/DublinCore/Renderer/Entry.php new file mode 100644 index 0000000000..c433ea3a6c --- /dev/null +++ b/libs/Zend/Feed/Writer/Extension/DublinCore/Renderer/Entry.php @@ -0,0 +1,96 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Entry.php 20326 2010-01-16 00:20:43Z padraic $ + */ + +/** + * @see Zend_Feed_Writer_Extension_RendererAbstract + */ +// require_once 'Zend/Feed/Writer/Extension/RendererAbstract.php'; + +/** + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Writer_Extension_DublinCore_Renderer_Entry + extends Zend_Feed_Writer_Extension_RendererAbstract +{ + + /** + * Set to TRUE if a rendering method actually renders something. This + * is used to prevent premature appending of a XML namespace declaration + * until an element which requires it is actually appended. + * + * @var bool + */ + protected $_called = false; + + /** + * Render entry + * + * @return void + */ + public function render() + { + if (strtolower($this->getType()) == 'atom') { + return; + } + $this->_setAuthors($this->_dom, $this->_base); + if ($this->_called) { + $this->_appendNamespaces(); + } + } + + /** + * Append namespaces to entry + * + * @return void + */ + protected function _appendNamespaces() + { + $this->getRootElement()->setAttribute('xmlns:dc', + 'http://purl.org/dc/elements/1.1/'); + } + + /** + * Set entry author elements + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setAuthors(DOMDocument $dom, DOMElement $root) + { + $authors = $this->getDataContainer()->getAuthors(); + if (!$authors || empty($authors)) { + return; + } + foreach ($authors as $data) { + $author = $this->_dom->createElement('dc:creator'); + if (array_key_exists('name', $data)) { + $text = $dom->createTextNode($data['name']); + $author->appendChild($text); + $root->appendChild($author); + } + } + $this->_called = true; + } +} diff --git a/libs/Zend/Feed/Writer/Extension/DublinCore/Renderer/Feed.php b/libs/Zend/Feed/Writer/Extension/DublinCore/Renderer/Feed.php new file mode 100644 index 0000000000..e1a0105019 --- /dev/null +++ b/libs/Zend/Feed/Writer/Extension/DublinCore/Renderer/Feed.php @@ -0,0 +1,96 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Feed.php 20326 2010-01-16 00:20:43Z padraic $ + */ + +/** + * @see Zend_Feed_Writer_Extension_RendererAbstract + */ +// require_once 'Zend/Feed/Writer/Extension/RendererAbstract.php'; + +/** + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Writer_Extension_DublinCore_Renderer_Feed + extends Zend_Feed_Writer_Extension_RendererAbstract +{ + + /** + * Set to TRUE if a rendering method actually renders something. This + * is used to prevent premature appending of a XML namespace declaration + * until an element which requires it is actually appended. + * + * @var bool + */ + protected $_called = false; + + /** + * Render feed + * + * @return void + */ + public function render() + { + if (strtolower($this->getType()) == 'atom') { + return; + } + $this->_setAuthors($this->_dom, $this->_base); + if ($this->_called) { + $this->_appendNamespaces(); + } + } + + /** + * Append namespaces to feed element + * + * @return void + */ + protected function _appendNamespaces() + { + $this->getRootElement()->setAttribute('xmlns:dc', + 'http://purl.org/dc/elements/1.1/'); + } + + /** + * Set feed authors + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setAuthors(DOMDocument $dom, DOMElement $root) + { + $authors = $this->getDataContainer()->getAuthors(); + if (!$authors || empty($authors)) { + return; + } + foreach ($authors as $data) { + $author = $this->_dom->createElement('dc:creator'); + if (array_key_exists('name', $data)) { + $text = $dom->createTextNode($data['name']); + $author->appendChild($text); + $root->appendChild($author); + } + } + $this->_called = true; + } +} diff --git a/libs/Zend/Feed/Writer/Extension/ITunes/Entry.php b/libs/Zend/Feed/Writer/Extension/ITunes/Entry.php new file mode 100644 index 0000000000..1d7fbc5070 --- /dev/null +++ b/libs/Zend/Feed/Writer/Extension/ITunes/Entry.php @@ -0,0 +1,242 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Entry.php 20096 2010-01-06 02:05:09Z bkarwin $ + */ + +/** + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Writer_Extension_ITunes_Entry +{ + /** + * Array of Feed data for rendering by Extension's renderers + * + * @var array + */ + protected $_data = array(); + + /** + * Encoding of all text values + * + * @var string + */ + protected $_encoding = 'UTF-8'; + + /** + * Set feed encoding + * + * @param string $enc + * @return Zend_Feed_Writer_Extension_ITunes_Entry + */ + public function setEncoding($enc) + { + $this->_encoding = $enc; + return $this; + } + + /** + * Get feed encoding + * + * @return string + */ + public function getEncoding() + { + return $this->_encoding; + } + + /** + * Set a block value of "yes" or "no". You may also set an empty string. + * + * @param string + * @return Zend_Feed_Writer_Extension_ITunes_Entry + */ + public function setItunesBlock($value) + { + if (!ctype_alpha($value) && strlen($value) > 0) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('invalid parameter: "block" may only' + . ' contain alphabetic characters'); + } + if (iconv_strlen($value, $this->getEncoding()) > 255) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('invalid parameter: "block" may only' + . ' contain a maximum of 255 characters'); + } + $this->_data['block'] = $value; + } + + /** + * Add authors to itunes entry + * + * @param array $values + * @return Zend_Feed_Writer_Extension_ITunes_Entry + */ + public function addItunesAuthors(array $values) + { + foreach ($values as $value) { + $this->addItunesAuthor($value); + } + return $this; + } + + /** + * Add author to itunes entry + * + * @param string $value + * @return Zend_Feed_Writer_Extension_ITunes_Entry + */ + public function addItunesAuthor($value) + { + if (iconv_strlen($value, $this->getEncoding()) > 255) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('invalid parameter: any "author" may only' + . ' contain a maximum of 255 characters each'); + } + if (!isset($this->_data['authors'])) { + $this->_data['authors'] = array(); + } + $this->_data['authors'][] = $value; + return $this; + } + + /** + * Set duration + * + * @param int $value + * @return Zend_Feed_Writer_Extension_ITunes_Entry + */ + public function setItunesDuration($value) + { + $value = (string) $value; + if (!ctype_digit($value) + && !preg_match("/^\d+:[0-5]{1}[0-9]{1}$/", $value) + && !preg_match("/^\d+:[0-5]{1}[0-9]{1}:[0-5]{1}[0-9]{1}$/", $value) + ) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('invalid parameter: "duration" may only' + . ' be of a specified [[HH:]MM:]SS format'); + } + $this->_data['duration'] = $value; + return $this; + } + + /** + * Set "explicit" flag + * + * @param bool $value + * @return Zend_Feed_Writer_Extension_ITunes_Entry + */ + public function setItunesExplicit($value) + { + if (!in_array($value, array('yes','no','clean'))) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('invalid parameter: "explicit" may only' + . ' be one of "yes", "no" or "clean"'); + } + $this->_data['explicit'] = $value; + return $this; + } + + /** + * Set keywords + * + * @param array $value + * @return Zend_Feed_Writer_Extension_ITunes_Entry + */ + public function setItunesKeywords(array $value) + { + if (count($value) > 12) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('invalid parameter: "keywords" may only' + . ' contain a maximum of 12 terms'); + } + $concat = implode(',', $value); + if (iconv_strlen($concat, $this->getEncoding()) > 255) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('invalid parameter: "keywords" may only' + . ' have a concatenated length of 255 chars where terms are delimited' + . ' by a comma'); + } + $this->_data['keywords'] = $value; + return $this; + } + + /** + * Set subtitle + * + * @param string $value + * @return Zend_Feed_Writer_Extension_ITunes_Entry + */ + public function setItunesSubtitle($value) + { + if (iconv_strlen($value, $this->getEncoding()) > 255) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('invalid parameter: "subtitle" may only' + . ' contain a maximum of 255 characters'); + } + $this->_data['subtitle'] = $value; + return $this; + } + + /** + * Set summary + * + * @param string $value + * @return Zend_Feed_Writer_Extension_ITunes_Entry + */ + public function setItunesSummary($value) + { + if (iconv_strlen($value, $this->getEncoding()) > 4000) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('invalid parameter: "summary" may only' + . ' contain a maximum of 4000 characters'); + } + $this->_data['summary'] = $value; + return $this; + } + + /** + * Overloading to itunes specific setters + * + * @param string $method + * @param array $params + * @return mixed + */ + public function __call($method, array $params) + { + $point = Zend_Feed_Writer::lcfirst(substr($method, 9)); + if (!method_exists($this, 'setItunes' . ucfirst($point)) + && !method_exists($this, 'addItunes' . ucfirst($point)) + ) { + // require_once 'Zend/Feed/Writer/Exception/InvalidMethodException.php'; + throw new Zend_Feed_Writer_Exception_InvalidMethodException( + 'invalid method: ' . $method + ); + } + if (!array_key_exists($point, $this->_data) + || empty($this->_data[$point]) + ) { + return null; + } + return $this->_data[$point]; + } +} diff --git a/libs/Zend/Feed/Writer/Extension/ITunes/Feed.php b/libs/Zend/Feed/Writer/Extension/ITunes/Feed.php new file mode 100644 index 0000000000..caf0440a03 --- /dev/null +++ b/libs/Zend/Feed/Writer/Extension/ITunes/Feed.php @@ -0,0 +1,361 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Feed.php 20096 2010-01-06 02:05:09Z bkarwin $ + */ + +/** + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Writer_Extension_ITunes_Feed +{ + /** + * Array of Feed data for rendering by Extension's renderers + * + * @var array + */ + protected $_data = array(); + + /** + * Encoding of all text values + * + * @var string + */ + protected $_encoding = 'UTF-8'; + + /** + * Set feed encoding + * + * @param string $enc + * @return Zend_Feed_Writer_Extension_ITunes_Feed + */ + public function setEncoding($enc) + { + $this->_encoding = $enc; + return $this; + } + + /** + * Get feed encoding + * + * @return string + */ + public function getEncoding() + { + return $this->_encoding; + } + + /** + * Set a block value of "yes" or "no". You may also set an empty string. + * + * @param string + * @return Zend_Feed_Writer_Extension_ITunes_Feed + */ + public function setItunesBlock($value) + { + if (!ctype_alpha($value) && strlen($value) > 0) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('invalid parameter: "block" may only' + . ' contain alphabetic characters'); + } + if (iconv_strlen($value, $this->getEncoding()) > 255) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('invalid parameter: "block" may only' + . ' contain a maximum of 255 characters'); + } + $this->_data['block'] = $value; + return $this; + } + + /** + * Add feed authors + * + * @param array $values + * @return Zend_Feed_Writer_Extension_ITunes_Feed + */ + public function addItunesAuthors(array $values) + { + foreach ($values as $value) { + $this->addItunesAuthor($value); + } + return $this; + } + + /** + * Add feed author + * + * @param string $value + * @return Zend_Feed_Writer_Extension_ITunes_Feed + */ + public function addItunesAuthor($value) + { + if (iconv_strlen($value, $this->getEncoding()) > 255) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('invalid parameter: any "author" may only' + . ' contain a maximum of 255 characters each'); + } + if (!isset($this->_data['authors'])) { + $this->_data['authors'] = array(); + } + $this->_data['authors'][] = $value; + return $this; + } + + /** + * Set feed categories + * + * @param array $values + * @return Zend_Feed_Writer_Extension_ITunes_Feed + */ + public function setItunesCategories(array $values) + { + if (!isset($this->_data['categories'])) { + $this->_data['categories'] = array(); + } + foreach ($values as $key=>$value) { + if (!is_array($value)) { + if (iconv_strlen($value, $this->getEncoding()) > 255) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('invalid parameter: any "category" may only' + . ' contain a maximum of 255 characters each'); + } + $this->_data['categories'][] = $value; + } else { + if (iconv_strlen($key, $this->getEncoding()) > 255) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('invalid parameter: any "category" may only' + . ' contain a maximum of 255 characters each'); + } + $this->_data['categories'][$key] = array(); + foreach ($value as $val) { + if (iconv_strlen($val, $this->getEncoding()) > 255) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('invalid parameter: any "category" may only' + . ' contain a maximum of 255 characters each'); + } + $this->_data['categories'][$key][] = $val; + } + } + } + return $this; + } + + /** + * Set feed image (icon) + * + * @param string $value + * @return Zend_Feed_Writer_Extension_ITunes_Feed + */ + public function setItunesImage($value) + { + if (!Zend_Uri::check($value)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('invalid parameter: "image" may only' + . ' be a valid URI/IRI'); + } + if (!in_array(substr($value, -3), array('jpg','png'))) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('invalid parameter: "image" may only' + . ' use file extension "jpg" or "png" which must be the last three' + . ' characters of the URI (i.e. no query string or fragment)'); + } + $this->_data['image'] = $value; + return $this; + } + + /** + * Set feed cumulative duration + * + * @param string $value + * @return Zend_Feed_Writer_Extension_ITunes_Feed + */ + public function setItunesDuration($value) + { + $value = (string) $value; + if (!ctype_digit($value) + && !preg_match("/^\d+:[0-5]{1}[0-9]{1}$/", $value) + && !preg_match("/^\d+:[0-5]{1}[0-9]{1}:[0-5]{1}[0-9]{1}$/", $value) + ) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('invalid parameter: "duration" may only' + . ' be of a specified [[HH:]MM:]SS format'); + } + $this->_data['duration'] = $value; + return $this; + } + + /** + * Set "explicit" flag + * + * @param bool $value + * @return Zend_Feed_Writer_Extension_ITunes_Feed + */ + public function setItunesExplicit($value) + { + if (!in_array($value, array('yes','no','clean'))) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('invalid parameter: "explicit" may only' + . ' be one of "yes", "no" or "clean"'); + } + $this->_data['explicit'] = $value; + return $this; + } + + /** + * Set feed keywords + * + * @param array $value + * @return Zend_Feed_Writer_Extension_ITunes_Feed + */ + public function setItunesKeywords(array $value) + { + if (count($value) > 12) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('invalid parameter: "keywords" may only' + . ' contain a maximum of 12 terms'); + } + $concat = implode(',', $value); + if (iconv_strlen($concat, $this->getEncoding()) > 255) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('invalid parameter: "keywords" may only' + . ' have a concatenated length of 255 chars where terms are delimited' + . ' by a comma'); + } + $this->_data['keywords'] = $value; + return $this; + } + + /** + * Set new feed URL + * + * @param string $value + * @return Zend_Feed_Writer_Extension_ITunes_Feed + */ + public function setItunesNewFeedUrl($value) + { + if (!Zend_Uri::check($value)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('invalid parameter: "newFeedUrl" may only' + . ' be a valid URI/IRI'); + } + $this->_data['newFeedUrl'] = $value; + return $this; + } + + /** + * Add feed owners + * + * @param array $values + * @return Zend_Feed_Writer_Extension_ITunes_Feed + */ + public function addItunesOwners(array $values) + { + foreach ($values as $value) { + $this->addItunesOwner($value); + } + return $this; + } + + /** + * Add feed owner + * + * @param string $value + * @return Zend_Feed_Writer_Extension_ITunes_Feed + */ + public function addItunesOwner(array $value) + { + if (!isset($value['name']) || !isset($value['email'])) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('invalid parameter: any "owner" must' + . ' be an array containing keys "name" and "email"'); + } + if (iconv_strlen($value['name'], $this->getEncoding()) > 255 + || iconv_strlen($value['email'], $this->getEncoding()) > 255 + ) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('invalid parameter: any "owner" may only' + . ' contain a maximum of 255 characters each for "name" and "email"'); + } + if (!isset($this->_data['owners'])) { + $this->_data['owners'] = array(); + } + $this->_data['owners'][] = $value; + return $this; + } + + /** + * Set feed subtitle + * + * @param string $value + * @return Zend_Feed_Writer_Extension_ITunes_Feed + */ + public function setItunesSubtitle($value) + { + if (iconv_strlen($value, $this->getEncoding()) > 255) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('invalid parameter: "subtitle" may only' + . ' contain a maximum of 255 characters'); + } + $this->_data['subtitle'] = $value; + return $this; + } + + /** + * Set feed summary + * + * @param string $value + * @return Zend_Feed_Writer_Extension_ITunes_Feed + */ + public function setItunesSummary($value) + { + if (iconv_strlen($value, $this->getEncoding()) > 4000) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('invalid parameter: "summary" may only' + . ' contain a maximum of 4000 characters'); + } + $this->_data['summary'] = $value; + return $this; + } + + /** + * Overloading: proxy to internal setters + * + * @param string $method + * @param array $params + * @return mixed + */ + public function __call($method, array $params) + { + $point = Zend_Feed_Writer::lcfirst(substr($method, 9)); + if (!method_exists($this, 'setItunes' . ucfirst($point)) + && !method_exists($this, 'addItunes' . ucfirst($point)) + ) { + // require_once 'Zend/Feed/Writer/Exception/InvalidMethodException.php'; + throw new Zend_Feed_Writer_Exception_InvalidMethodException( + 'invalid method: ' . $method + ); + } + if (!array_key_exists($point, $this->_data) || empty($this->_data[$point])) { + return null; + } + return $this->_data[$point]; + } +} diff --git a/libs/Zend/Feed/Writer/Extension/ITunes/Renderer/Entry.php b/libs/Zend/Feed/Writer/Extension/ITunes/Renderer/Entry.php new file mode 100644 index 0000000000..046cb546fb --- /dev/null +++ b/libs/Zend/Feed/Writer/Extension/ITunes/Renderer/Entry.php @@ -0,0 +1,216 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Entry.php 20326 2010-01-16 00:20:43Z padraic $ + */ + +/** + * @see Zend_Feed_Writer_Extension_RendererAbstract + */ +// require_once 'Zend/Feed/Writer/Extension/RendererAbstract.php'; + +/** + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Writer_Extension_ITunes_Renderer_Entry + extends Zend_Feed_Writer_Extension_RendererAbstract +{ + /** + * Set to TRUE if a rendering method actually renders something. This + * is used to prevent premature appending of a XML namespace declaration + * until an element which requires it is actually appended. + * + * @var bool + */ + protected $_called = false; + + /** + * Render entry + * + * @return void + */ + public function render() + { + $this->_setAuthors($this->_dom, $this->_base); + $this->_setBlock($this->_dom, $this->_base); + $this->_setDuration($this->_dom, $this->_base); + $this->_setExplicit($this->_dom, $this->_base); + $this->_setKeywords($this->_dom, $this->_base); + $this->_setSubtitle($this->_dom, $this->_base); + $this->_setSummary($this->_dom, $this->_base); + if ($this->_called) { + $this->_appendNamespaces(); + } + } + + /** + * Append namespaces to entry root + * + * @return void + */ + protected function _appendNamespaces() + { + $this->getRootElement()->setAttribute('xmlns:itunes', + 'http://www.itunes.com/dtds/podcast-1.0.dtd'); + } + + /** + * Set entry authors + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setAuthors(DOMDocument $dom, DOMElement $root) + { + $authors = $this->getDataContainer()->getItunesAuthors(); + if (!$authors || empty($authors)) { + return; + } + foreach ($authors as $author) { + $el = $dom->createElement('itunes:author'); + $text = $dom->createTextNode($author); + $el->appendChild($text); + $root->appendChild($el); + $this->_called = true; + } + } + + /** + * Set itunes block + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setBlock(DOMDocument $dom, DOMElement $root) + { + $block = $this->getDataContainer()->getItunesBlock(); + if (is_null($block)) { + return; + } + $el = $dom->createElement('itunes:block'); + $text = $dom->createTextNode($block); + $el->appendChild($text); + $root->appendChild($el); + $this->_called = true; + } + + /** + * Set entry duration + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setDuration(DOMDocument $dom, DOMElement $root) + { + $duration = $this->getDataContainer()->getItunesDuration(); + if (!$duration) { + return; + } + $el = $dom->createElement('itunes:duration'); + $text = $dom->createTextNode($duration); + $el->appendChild($text); + $root->appendChild($el); + $this->_called = true; + } + + /** + * Set explicit flag + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setExplicit(DOMDocument $dom, DOMElement $root) + { + $explicit = $this->getDataContainer()->getItunesExplicit(); + if (is_null($explicit)) { + return; + } + $el = $dom->createElement('itunes:explicit'); + $text = $dom->createTextNode($explicit); + $el->appendChild($text); + $root->appendChild($el); + $this->_called = true; + } + + /** + * Set entry keywords + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setKeywords(DOMDocument $dom, DOMElement $root) + { + $keywords = $this->getDataContainer()->getItunesKeywords(); + if (!$keywords || empty($keywords)) { + return; + } + $el = $dom->createElement('itunes:keywords'); + $text = $dom->createTextNode(implode(',', $keywords)); + $el->appendChild($text); + $root->appendChild($el); + $this->_called = true; + } + + /** + * Set entry subtitle + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setSubtitle(DOMDocument $dom, DOMElement $root) + { + $subtitle = $this->getDataContainer()->getItunesSubtitle(); + if (!$subtitle) { + return; + } + $el = $dom->createElement('itunes:subtitle'); + $text = $dom->createTextNode($subtitle); + $el->appendChild($text); + $root->appendChild($el); + $this->_called = true; + } + + /** + * Set entry summary + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setSummary(DOMDocument $dom, DOMElement $root) + { + $summary = $this->getDataContainer()->getItunesSummary(); + if (!$summary) { + return; + } + $el = $dom->createElement('itunes:summary'); + $text = $dom->createTextNode($summary); + $el->appendChild($text); + $root->appendChild($el); + $this->_called = true; + } +} diff --git a/libs/Zend/Feed/Writer/Extension/ITunes/Renderer/Feed.php b/libs/Zend/Feed/Writer/Extension/ITunes/Renderer/Feed.php new file mode 100644 index 0000000000..192d19ec42 --- /dev/null +++ b/libs/Zend/Feed/Writer/Extension/ITunes/Renderer/Feed.php @@ -0,0 +1,320 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Feed.php 20326 2010-01-16 00:20:43Z padraic $ + */ + +/** + * @see Zend_Feed_Writer_Extension_RendererAbstract + */ +// require_once 'Zend/Feed/Writer/Extension/RendererAbstract.php'; + +/** + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Writer_Extension_ITunes_Renderer_Feed + extends Zend_Feed_Writer_Extension_RendererAbstract +{ + + /** + * Set to TRUE if a rendering method actually renders something. This + * is used to prevent premature appending of a XML namespace declaration + * until an element which requires it is actually appended. + * + * @var bool + */ + protected $_called = false; + + /** + * Render feed + * + * @return void + */ + public function render() + { + $this->_setAuthors($this->_dom, $this->_base); + $this->_setBlock($this->_dom, $this->_base); + $this->_setCategories($this->_dom, $this->_base); + $this->_setImage($this->_dom, $this->_base); + $this->_setDuration($this->_dom, $this->_base); + $this->_setExplicit($this->_dom, $this->_base); + $this->_setKeywords($this->_dom, $this->_base); + $this->_setNewFeedUrl($this->_dom, $this->_base); + $this->_setOwners($this->_dom, $this->_base); + $this->_setSubtitle($this->_dom, $this->_base); + $this->_setSummary($this->_dom, $this->_base); + if ($this->_called) { + $this->_appendNamespaces(); + } + } + + /** + * Append feed namespaces + * + * @return void + */ + protected function _appendNamespaces() + { + $this->getRootElement()->setAttribute('xmlns:itunes', + 'http://www.itunes.com/dtds/podcast-1.0.dtd'); + } + + /** + * Set feed authors + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setAuthors(DOMDocument $dom, DOMElement $root) + { + $authors = $this->getDataContainer()->getItunesAuthors(); + if (!$authors || empty($authors)) { + return; + } + foreach ($authors as $author) { + $el = $dom->createElement('itunes:author'); + $text = $dom->createTextNode($author); + $el->appendChild($text); + $root->appendChild($el); + } + $this->_called = true; + } + + /** + * Set feed itunes block + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setBlock(DOMDocument $dom, DOMElement $root) + { + $block = $this->getDataContainer()->getItunesBlock(); + if (is_null($block)) { + return; + } + $el = $dom->createElement('itunes:block'); + $text = $dom->createTextNode($block); + $el->appendChild($text); + $root->appendChild($el); + $this->_called = true; + } + + /** + * Set feed categories + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setCategories(DOMDocument $dom, DOMElement $root) + { + $cats = $this->getDataContainer()->getItunesCategories(); + if (!$cats || empty($cats)) { + return; + } + foreach ($cats as $key=>$cat) { + if (!is_array($cat)) { + $el = $dom->createElement('itunes:category'); + $el->setAttribute('text', $cat); + $root->appendChild($el); + } else { + $el = $dom->createElement('itunes:category'); + $el->setAttribute('text', $key); + $root->appendChild($el); + foreach ($cat as $subcat) { + $el2 = $dom->createElement('itunes:category'); + $el2->setAttribute('text', $subcat); + $el->appendChild($el2); + } + } + } + $this->_called = true; + } + + /** + * Set feed image (icon) + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setImage(DOMDocument $dom, DOMElement $root) + { + $image = $this->getDataContainer()->getItunesImage(); + if (!$image) { + return; + } + $el = $dom->createElement('itunes:image'); + $el->setAttribute('href', $image); + $root->appendChild($el); + $this->_called = true; + } + + /** + * Set feed cumulative duration + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setDuration(DOMDocument $dom, DOMElement $root) + { + $duration = $this->getDataContainer()->getItunesDuration(); + if (!$duration) { + return; + } + $el = $dom->createElement('itunes:duration'); + $text = $dom->createTextNode($duration); + $el->appendChild($text); + $root->appendChild($el); + $this->_called = true; + } + + /** + * Set explicit flag + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setExplicit(DOMDocument $dom, DOMElement $root) + { + $explicit = $this->getDataContainer()->getItunesExplicit(); + if (is_null($explicit)) { + return; + } + $el = $dom->createElement('itunes:explicit'); + $text = $dom->createTextNode($explicit); + $el->appendChild($text); + $root->appendChild($el); + $this->_called = true; + } + + /** + * Set feed keywords + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setKeywords(DOMDocument $dom, DOMElement $root) + { + $keywords = $this->getDataContainer()->getItunesKeywords(); + if (!$keywords || empty($keywords)) { + return; + } + $el = $dom->createElement('itunes:keywords'); + $text = $dom->createTextNode(implode(',', $keywords)); + $el->appendChild($text); + $root->appendChild($el); + $this->_called = true; + } + + /** + * Set feed's new URL + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setNewFeedUrl(DOMDocument $dom, DOMElement $root) + { + $url = $this->getDataContainer()->getItunesNewFeedUrl(); + if (!$url) { + return; + } + $el = $dom->createElement('itunes:new-feed-url'); + $text = $dom->createTextNode($url); + $el->appendChild($text); + $root->appendChild($el); + $this->_called = true; + } + + /** + * Set feed owners + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setOwners(DOMDocument $dom, DOMElement $root) + { + $owners = $this->getDataContainer()->getItunesOwners(); + if (!$owners || empty($owners)) { + return; + } + foreach ($owners as $owner) { + $el = $dom->createElement('itunes:owner'); + $name = $dom->createElement('itunes:name'); + $text = $dom->createTextNode($owner['name']); + $name->appendChild($text); + $email = $dom->createElement('itunes:email'); + $text = $dom->createTextNode($owner['email']); + $email->appendChild($text); + $root->appendChild($el); + $el->appendChild($name); + $el->appendChild($email); + } + $this->_called = true; + } + + /** + * Set feed subtitle + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setSubtitle(DOMDocument $dom, DOMElement $root) + { + $subtitle = $this->getDataContainer()->getItunesSubtitle(); + if (!$subtitle) { + return; + } + $el = $dom->createElement('itunes:subtitle'); + $text = $dom->createTextNode($subtitle); + $el->appendChild($text); + $root->appendChild($el); + $this->_called = true; + } + + /** + * Set feed summary + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setSummary(DOMDocument $dom, DOMElement $root) + { + $summary = $this->getDataContainer()->getItunesSummary(); + if (!$summary) { + return; + } + $el = $dom->createElement('itunes:summary'); + $text = $dom->createTextNode($summary); + $el->appendChild($text); + $root->appendChild($el); + $this->_called = true; + } +} diff --git a/libs/Zend/Feed/Writer/Extension/RendererAbstract.php b/libs/Zend/Feed/Writer/Extension/RendererAbstract.php new file mode 100644 index 0000000000..b381be3657 --- /dev/null +++ b/libs/Zend/Feed/Writer/Extension/RendererAbstract.php @@ -0,0 +1,179 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to padraic dot brady at yahoo dot com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Writer_Entry_Rss + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * @see Zend_Feed_Writer_Extension_RendererInterface + */ +// require_once 'Zend/Feed/Writer/Extension/RendererInterface.php'; + + /** + * @category Zend + * @package Zend_Feed_Writer_Entry_Rss + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +abstract class Zend_Feed_Writer_Extension_RendererAbstract + implements Zend_Feed_Writer_Extension_RendererInterface +{ + /** + * @var DOMDocument + */ + protected $_dom = null; + + /** + * @var mixed + */ + protected $_entry = null; + + /** + * @var DOMElement + */ + protected $_base = null; + + /** + * @var mixed + */ + protected $_container = null; + + /** + * @var string + */ + protected $_type = null; + + /** + * @var DOMElement + */ + protected $_rootElement = null; + + /** + * Encoding of all text values + * + * @var string + */ + protected $_encoding = 'UTF-8'; + + /** + * Constructor + * + * @param mixed $container + * @return void + */ + public function __construct($container) + { + $this->_container = $container; + } + + /** + * Set feed encoding + * + * @param string $enc + * @return Zend_Feed_Writer_Extension_RendererAbstract + */ + public function setEncoding($enc) + { + $this->_encoding = $enc; + return $this; + } + + /** + * Get feed encoding + * + * @return void + */ + public function getEncoding() + { + return $this->_encoding; + } + + /** + * Set DOMDocument and DOMElement on which to operate + * + * @param DOMDocument $dom + * @param DOMElement $base + * @return Zend_Feed_Writer_Extension_RendererAbstract + */ + public function setDomDocument(DOMDocument $dom, DOMElement $base) + { + $this->_dom = $dom; + $this->_base = $base; + return $this; + } + + /** + * Get data container being rendered + * + * @return mixed + */ + public function getDataContainer() + { + return $this->_container; + } + + /** + * Set feed type + * + * @param string $type + * @return Zend_Feed_Writer_Extension_RendererAbstract + */ + public function setType($type) + { + $this->_type = $type; + return $this; + } + + /** + * Get feedtype + * + * @return string + */ + public function getType() + { + return $this->_type; + } + + /** + * Set root element of document + * + * @param DOMElement $root + * @return Zend_Feed_Writer_Extension_RendererAbstract + */ + public function setRootElement(DOMElement $root) + { + $this->_rootElement = $root; + return $this; + } + + /** + * Get root element + * + * @return DOMElement + */ + public function getRootElement() + { + return $this->_rootElement; + } + + /** + * Append namespaces to feed + * + * @return void + */ + abstract protected function _appendNamespaces(); +} diff --git a/libs/Zend/Feed/Writer/Extension/RendererInterface.php b/libs/Zend/Feed/Writer/Extension/RendererInterface.php new file mode 100644 index 0000000000..e9c9014176 --- /dev/null +++ b/libs/Zend/Feed/Writer/Extension/RendererInterface.php @@ -0,0 +1,59 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to padraic dot brady at yahoo dot com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +interface Zend_Feed_Writer_Extension_RendererInterface +{ + /** + * Constructor + * + * @param mixed $container + * @return void + */ + public function __construct($container); + + /** + * Set DOMDocument and DOMElement on which to operate + * + * @param DOMDocument $dom + * @param DOMElement $base + * @return void + */ + public function setDomDocument(DOMDocument $dom, DOMElement $base); + + /** + * Render + * + * @return void + */ + public function render(); + + /** + * Retrieve container + * + * @return mixed + */ + public function getDataContainer(); +} diff --git a/libs/Zend/Feed/Writer/Extension/Slash/Renderer/Entry.php b/libs/Zend/Feed/Writer/Extension/Slash/Renderer/Entry.php new file mode 100644 index 0000000000..2814775551 --- /dev/null +++ b/libs/Zend/Feed/Writer/Extension/Slash/Renderer/Entry.php @@ -0,0 +1,91 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Entry.php 20326 2010-01-16 00:20:43Z padraic $ + */ + +/** + * @see Zend_Feed_Writer_Extension_RendererAbstract + */ +// require_once 'Zend/Feed/Writer/Extension/RendererAbstract.php'; + +/** + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Writer_Extension_Slash_Renderer_Entry + extends Zend_Feed_Writer_Extension_RendererAbstract +{ + + /** + * Set to TRUE if a rendering method actually renders something. This + * is used to prevent premature appending of a XML namespace declaration + * until an element which requires it is actually appended. + * + * @var bool + */ + protected $_called = false; + + /** + * Render entry + * + * @return void + */ + public function render() + { + if (strtolower($this->getType()) == 'atom') { + return; // RSS 2.0 only + } + $this->_setCommentCount($this->_dom, $this->_base); + if ($this->_called) { + $this->_appendNamespaces(); + } + } + + /** + * Append entry namespaces + * + * @return void + */ + protected function _appendNamespaces() + { + $this->getRootElement()->setAttribute('xmlns:slash', + 'http://purl.org/rss/1.0/modules/slash/'); + } + + /** + * Set entry comment count + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setCommentCount(DOMDocument $dom, DOMElement $root) + { + $count = $this->getDataContainer()->getCommentCount(); + if (!$count) { + $count = 0; + } + $tcount = $this->_dom->createElement('slash:comments'); + $tcount->nodeValue = $count; + $root->appendChild($tcount); + $this->_called = true; + } +} diff --git a/libs/Zend/Feed/Writer/Extension/Threading/Renderer/Entry.php b/libs/Zend/Feed/Writer/Extension/Threading/Renderer/Entry.php new file mode 100644 index 0000000000..69e731d4ba --- /dev/null +++ b/libs/Zend/Feed/Writer/Extension/Threading/Renderer/Entry.php @@ -0,0 +1,145 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Entry.php 20326 2010-01-16 00:20:43Z padraic $ + */ + +/** + * @see Zend_Feed_Writer_Extension_RendererAbstract + */ +// require_once 'Zend/Feed/Writer/Extension/RendererAbstract.php'; + +/** + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Writer_Extension_Threading_Renderer_Entry + extends Zend_Feed_Writer_Extension_RendererAbstract +{ + + /** + * Set to TRUE if a rendering method actually renders something. This + * is used to prevent premature appending of a XML namespace declaration + * until an element which requires it is actually appended. + * + * @var bool + */ + protected $_called = false; + + /** + * Render entry + * + * @return void + */ + public function render() + { + if (strtolower($this->getType()) == 'rss') { + return; // Atom 1.0 only + } + $this->_setCommentLink($this->_dom, $this->_base); + $this->_setCommentFeedLinks($this->_dom, $this->_base); + $this->_setCommentCount($this->_dom, $this->_base); + if ($this->_called) { + $this->_appendNamespaces(); + } + } + + /** + * Append entry namespaces + * + * @return void + */ + protected function _appendNamespaces() + { + $this->getRootElement()->setAttribute('xmlns:thr', + 'http://purl.org/syndication/thread/1.0'); + } + + /** + * Set comment link + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setCommentLink(DOMDocument $dom, DOMElement $root) + { + $link = $this->getDataContainer()->getCommentLink(); + if (!$link) { + return; + } + $clink = $this->_dom->createElement('link'); + $clink->setAttribute('rel', 'replies'); + $clink->setAttribute('type', 'text/html'); + $clink->setAttribute('href', $link); + $count = $this->getDataContainer()->getCommentCount(); + if (!is_null($count)) { + $clink->setAttribute('thr:count', $count); + } + $root->appendChild($clink); + $this->_called = true; + } + + /** + * Set comment feed links + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setCommentFeedLinks(DOMDocument $dom, DOMElement $root) + { + $links = $this->getDataContainer()->getCommentFeedLinks(); + if (!$links || empty($links)) { + return; + } + foreach ($links as $link) { + $flink = $this->_dom->createElement('link'); + $flink->setAttribute('rel', 'replies'); + $flink->setAttribute('type', 'application/'. $link['type'] .'+xml'); + $flink->setAttribute('href', $link['uri']); + $count = $this->getDataContainer()->getCommentCount(); + if (!is_null($count)) { + $flink->setAttribute('thr:count', $count); + } + $root->appendChild($flink); + $this->_called = true; + } + } + + /** + * Set entry comment count + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setCommentCount(DOMDocument $dom, DOMElement $root) + { + $count = $this->getDataContainer()->getCommentCount(); + if (is_null($count)) { + return; + } + $tcount = $this->_dom->createElement('thr:total'); + $tcount->nodeValue = $count; + $root->appendChild($tcount); + $this->_called = true; + } +} diff --git a/libs/Zend/Feed/Writer/Extension/WellFormedWeb/Renderer/Entry.php b/libs/Zend/Feed/Writer/Extension/WellFormedWeb/Renderer/Entry.php new file mode 100644 index 0000000000..c57244ae4b --- /dev/null +++ b/libs/Zend/Feed/Writer/Extension/WellFormedWeb/Renderer/Entry.php @@ -0,0 +1,96 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Entry.php 20326 2010-01-16 00:20:43Z padraic $ + */ + +/** + * @see Zend_Feed_Writer_Extension_RendererAbstract + */ +// require_once 'Zend/Feed/Writer/Extension/RendererAbstract.php'; + +/** + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Writer_Extension_WellFormedWeb_Renderer_Entry + extends Zend_Feed_Writer_Extension_RendererAbstract +{ + + /** + * Set to TRUE if a rendering method actually renders something. This + * is used to prevent premature appending of a XML namespace declaration + * until an element which requires it is actually appended. + * + * @var bool + */ + protected $_called = false; + + /** + * Render entry + * + * @return void + */ + public function render() + { + if (strtolower($this->getType()) == 'atom') { + return; // RSS 2.0 only + } + $this->_setCommentFeedLinks($this->_dom, $this->_base); + if ($this->_called) { + $this->_appendNamespaces(); + } + } + + /** + * Append entry namespaces + * + * @return void + */ + protected function _appendNamespaces() + { + $this->getRootElement()->setAttribute('xmlns:wfw', + 'http://wellformedweb.org/CommentAPI/'); + } + + /** + * Set entry comment feed links + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setCommentFeedLinks(DOMDocument $dom, DOMElement $root) + { + $links = $this->getDataContainer()->getCommentFeedLinks(); + if (!$links || empty($links)) { + return; + } + foreach ($links as $link) { + if ($link['type'] == 'rss') { + $flink = $this->_dom->createElement('wfw:commentRss'); + $text = $dom->createTextNode($link['uri']); + $flink->appendChild($text); + $root->appendChild($flink); + } + } + $this->_called = true; + } +} diff --git a/libs/Zend/Feed/Writer/Feed.php b/libs/Zend/Feed/Writer/Feed.php new file mode 100644 index 0000000000..724caed1a2 --- /dev/null +++ b/libs/Zend/Feed/Writer/Feed.php @@ -0,0 +1,281 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Feed.php 20519 2010-01-22 14:06:24Z padraic $ + */ + +/** + * @see Zend_Date + */ +// require_once 'Zend/Date.php'; + +/** + * @see Zend_Date + */ +// require_once 'Zend/Uri.php'; + +/** + * @see Zend_Feed_Writer + */ +// require_once 'Zend/Feed/Writer.php'; + +/** + * @see Zend_Feed_Writer_Entry + */ +// require_once 'Zend/Feed/Writer/Entry.php'; + +/** + * @see Zend_Feed_Writer_Deleted + */ +// require_once 'Zend/Feed/Writer/Deleted.php'; + +/** + * @see Zend_Feed_Writer_Renderer_Feed_Atom + */ +// require_once 'Zend/Feed/Writer/Renderer/Feed/Atom.php'; + +/** + * @see Zend_Feed_Writer_Renderer_Feed_Rss + */ +// require_once 'Zend/Feed/Writer/Renderer/Feed/Rss.php'; + +// require_once 'Zend/Feed/Writer/Feed/FeedAbstract.php'; + +/** + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Writer_Feed extends Zend_Feed_Writer_Feed_FeedAbstract +implements Iterator, Countable +{ + + /** + * Contains all entry objects + * + * @var array + */ + protected $_entries = array(); + + /** + * A pointer for the iterator to keep track of the entries array + * + * @var int + */ + protected $_entriesKey = 0; + + /** + * Creates a new Zend_Feed_Writer_Entry data container for use. This is NOT + * added to the current feed automatically, but is necessary to create a + * container with some initial values preset based on the current feed data. + * + * @return Zend_Feed_Writer_Entry + */ + public function createEntry() + { + $entry = new Zend_Feed_Writer_Entry; + if ($this->getEncoding()) { + $entry->setEncoding($this->getEncoding()); + } + $entry->setType($this->getType()); + return $entry; + } + + /** + * Appends a Zend_Feed_Writer_Deleted object representing a new entry tombstone + * to the feed data container's internal group of entries. + * + * @param Zend_Feed_Writer_Deleted $entry + */ + public function addTombstone(Zend_Feed_Writer_Deleted $deleted) + { + $this->_entries[] = $deleted; + } + + /** + * Creates a new Zend_Feed_Writer_Deleted data container for use. This is NOT + * added to the current feed automatically, but is necessary to create a + * container with some initial values preset based on the current feed data. + * + * @return Zend_Feed_Writer_Deleted + */ + public function createTombstone() + { + $deleted = new Zend_Feed_Writer_Deleted; + if ($this->getEncoding()) { + $deleted->setEncoding($this->getEncoding()); + } + $deleted->setType($this->getType()); + return $deleted; + } + + /** + * Appends a Zend_Feed_Writer_Entry object representing a new entry/item + * the feed data container's internal group of entries. + * + * @param Zend_Feed_Writer_Entry $entry + */ + public function addEntry(Zend_Feed_Writer_Entry $entry) + { + $this->_entries[] = $entry; + } + + /** + * Removes a specific indexed entry from the internal queue. Entries must be + * added to a feed container in order to be indexed. + * + * @param int $index + */ + public function removeEntry($index) + { + if (isset($this->_entries[$index])) { + unset($this->_entries[$index]); + } + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Undefined index: ' . $index . '. Entry does not exist.'); + } + + /** + * Retrieve a specific indexed entry from the internal queue. Entries must be + * added to a feed container in order to be indexed. + * + * @param int $index + */ + public function getEntry($index = 0) + { + if (isset($this->_entries[$index])) { + return $this->_entries[$index]; + } + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Undefined index: ' . $index . '. Entry does not exist.'); + } + + /** + * Orders all indexed entries by date, thus offering date ordered readable + * content where a parser (or Homo Sapien) ignores the generic rule that + * XML element order is irrelevant and has no intrinsic meaning. + * + * Using this method will alter the original indexation. + * + * @return void + */ + public function orderByDate() + { + /** + * Could do with some improvement for performance perhaps + */ + $timestamp = time(); + $entries = array(); + foreach ($this->_entries as $entry) { + if ($entry->getDateModified()) { + $timestamp = (int) $entry->getDateModified()->get(Zend_Date::TIMESTAMP); + } elseif ($entry->getDateCreated()) { + $timestamp = (int) $entry->getDateCreated()->get(Zend_Date::TIMESTAMP); + } + $entries[$timestamp] = $entry; + } + krsort($entries, SORT_NUMERIC); + $this->_entries = array_values($entries); + } + + /** + * Get the number of feed entries. + * Required by the Iterator interface. + * + * @return int + */ + public function count() + { + return count($this->_entries); + } + + /** + * Return the current entry + * + * @return Zend_Feed_Reader_Entry_Interface + */ + public function current() + { + return $this->_entries[$this->key()]; + } + + /** + * Return the current feed key + * + * @return unknown + */ + public function key() + { + return $this->_entriesKey; + } + + /** + * Move the feed pointer forward + * + * @return void + */ + public function next() + { + ++$this->_entriesKey; + } + + /** + * Reset the pointer in the feed object + * + * @return void + */ + public function rewind() + { + $this->_entriesKey = 0; + } + + /** + * Check to see if the iterator is still valid + * + * @return boolean + */ + public function valid() + { + return 0 <= $this->_entriesKey && $this->_entriesKey < $this->count(); + } + + /** + * Attempt to build and return the feed resulting from the data set + * + * @param $type The feed type "rss" or "atom" to export as + * @return string + */ + public function export($type, $ignoreExceptions = false) + { + $this->setType(strtolower($type)); + $type = ucfirst($this->getType()); + if ($type !== 'Rss' && $type !== 'Atom') { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid feed type specified: ' . $type . '.' + . ' Should be one of "rss" or "atom".'); + } + $renderClass = 'Zend_Feed_Writer_Renderer_Feed_' . $type; + $renderer = new $renderClass($this); + if ($ignoreExceptions) { + $renderer->ignoreExceptions(); + } + return $renderer->render()->saveXml(); + } + +} diff --git a/libs/Zend/Feed/Writer/Feed/FeedAbstract.php b/libs/Zend/Feed/Writer/Feed/FeedAbstract.php new file mode 100644 index 0000000000..bc2a0fa06f --- /dev/null +++ b/libs/Zend/Feed/Writer/Feed/FeedAbstract.php @@ -0,0 +1,805 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Feed.php 20096 2010-01-06 02:05:09Z bkarwin $ + */ + +/** + * @see Zend_Date + */ +// require_once 'Zend/Date.php'; + +/** + * @see Zend_Date + */ +// require_once 'Zend/Uri.php'; + +/** + * @see Zend_Feed_Writer + */ +// require_once 'Zend/Feed/Writer.php'; + +/** + * @see Zend_Feed_Writer_Entry + */ +// require_once 'Zend/Feed/Writer/Entry.php'; + +/** + * @see Zend_Feed_Writer_Renderer_Feed_Atom + */ +// require_once 'Zend/Feed/Writer/Renderer/Feed/Atom.php'; + +/** + * @see Zend_Feed_Writer_Renderer_Feed_Rss + */ +// require_once 'Zend/Feed/Writer/Renderer/Feed/Rss.php'; + +/** + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Writer_Feed_FeedAbstract +{ + /** + * Contains all Feed level date to append in feed output + * + * @var array + */ + protected $_data = array(); + + /** + * Holds the value "atom" or "rss" depending on the feed type set when + * when last exported. + * + * @var string + */ + protected $_type = null; + + /** + * Constructor: Primarily triggers the registration of core extensions and + * loads those appropriate to this data container. + * + * @return void + */ + public function __construct() + { + Zend_Feed_Writer::registerCoreExtensions(); + $this->_loadExtensions(); + } + + /** + * Set a single author + * + * @param int $index + * @return string|null + */ + public function addAuthor($name, $email = null, $uri = null) + { + $author = array(); + if (is_array($name)) { + if (!array_key_exists('name', $name) || empty($name['name']) || !is_string($name['name'])) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: author array must include a "name" key with a non-empty string value'); + } + $author['name'] = $name['name']; + if (isset($name['email'])) { + if (empty($name['email']) || !is_string($name['email'])) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: "email" array value must be a non-empty string'); + } + $author['email'] = $name['email']; + } + if (isset($name['uri'])) { + if (empty($name['uri']) || !is_string($name['uri']) || !Zend_Uri::check($name['uri'])) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: "uri" array value must be a non-empty string and valid URI/IRI'); + } + $author['uri'] = $name['uri']; + } + } else { + if (empty($name['name']) || !is_string($name['name'])) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: "name" must be a non-empty string value'); + } + $author['name'] = $name; + if (isset($email)) { + if (empty($email) || !is_string($email)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: "email" value must be a non-empty string'); + } + $author['email'] = $email; + } + if (isset($uri)) { + if (empty($uri) || !is_string($uri) || !Zend_Uri::check($uri)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: "uri" value must be a non-empty string and valid URI/IRI'); + } + $author['uri'] = $uri; + } + } + $this->_data['authors'][] = $author; + } + + /** + * Set an array with feed authors + * + * @return array + */ + public function addAuthors(array $authors) + { + foreach($authors as $author) { + $this->addAuthor($author); + } + } + + /** + * Set the copyright entry + * + * @return string|null + */ + public function setCopyright($copyright) + { + if (empty($copyright) || !is_string($copyright)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: parameter must be a non-empty string'); + } + $this->_data['copyright'] = $copyright; + } + + /** + * Set the feed creation date + * + * @param null|integer|Zend_Date + */ + public function setDateCreated($date = null) + { + $zdate = null; + if (is_null($date)) { + $zdate = new Zend_Date; + } elseif (ctype_digit($date) && strlen($date) == 10) { + $zdate = new Zend_Date($date, Zend_Date::TIMESTAMP); + } elseif ($date instanceof Zend_Date) { + $zdate = $date; + } else { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid Zend_Date object or UNIX Timestamp passed as parameter'); + } + $this->_data['dateCreated'] = $zdate; + } + + /** + * Set the feed modification date + * + * @param null|integer|Zend_Date + */ + public function setDateModified($date = null) + { + $zdate = null; + if (is_null($date)) { + $zdate = new Zend_Date; + } elseif (ctype_digit($date) && strlen($date) == 10) { + $zdate = new Zend_Date($date, Zend_Date::TIMESTAMP); + } elseif ($date instanceof Zend_Date) { + $zdate = $date; + } else { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid Zend_Date object or UNIX Timestamp passed as parameter'); + } + $this->_data['dateModified'] = $zdate; + } + + /** + * Set the feed last-build date. Ignored for Atom 1.0. + * + * @param null|integer|Zend_Date + */ + public function setLastBuildDate($date = null) + { + $zdate = null; + if (is_null($date)) { + $zdate = new Zend_Date; + } elseif (ctype_digit($date) && strlen($date) == 10) { + $zdate = new Zend_Date($date, Zend_Date::TIMESTAMP); + } elseif ($date instanceof Zend_Date) { + $zdate = $date; + } else { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid Zend_Date object or UNIX Timestamp passed as parameter'); + } + $this->_data['lastBuildDate'] = $zdate; + } + + /** + * Set the feed description + * + * @return string|null + */ + public function setDescription($description) + { + if (empty($description) || !is_string($description)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: parameter must be a non-empty string'); + } + $this->_data['description'] = $description; + } + + /** + * Set the feed generator entry + * + * @return string|null + */ + public function setGenerator($name, $version = null, $uri = null) + { + if (is_array($name)) { + $data = $name; + if (empty($data['name']) || !is_string($data['name'])) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: "name" must be a non-empty string'); + } + $generator = array('name' => $data['name']); + if (isset($data['version'])) { + if (empty($data['version']) || !is_string($data['version'])) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: "version" must be a non-empty string'); + } + $generator['version'] = $data['version']; + } + if (isset($data['uri'])) { + if (empty($data['uri']) || !is_string($data['uri']) || !Zend_Uri::check($data['uri'])) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: "uri" must be a non-empty string and a valid URI/IRI'); + } + $generator['uri'] = $data['uri']; + } + } else { + if (empty($name) || !is_string($name)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: "name" must be a non-empty string'); + } + $generator = array('name' => $name); + if (isset($version)) { + if (empty($version) || !is_string($version)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: "version" must be a non-empty string'); + } + $generator['version'] = $version; + } + if (isset($uri)) { + if (empty($uri) || !is_string($uri) || !Zend_Uri::check($uri)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: "uri" must be a non-empty string and a valid URI/IRI'); + } + $generator['uri'] = $uri; + } + } + $this->_data['generator'] = $generator; + } + + /** + * Set the feed ID - URI or URN (via PCRE pattern) supported + * + * @param string $id + */ + public function setId($id) + { + if ((empty($id) || !is_string($id) || !Zend_Uri::check($id)) && + !preg_match("#^urn:[a-zA-Z0-9][a-zA-Z0-9\-]{1,31}:([a-zA-Z0-9\(\)\+\,\.\:\=\@\;\$\_\!\*\-]|%[0-9a-fA-F]{2})*#", $id)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: parameter must be a non-empty string and valid URI/IRI'); + } + $this->_data['id'] = $id; + } + + /** + * Set a feed image (URI at minimum). Parameter is a single array with the + * required key 'uri'. When rendering as RSS, the required keys are 'uri', + * 'title' and 'link'. RSS also specifies three optional parameters 'width', + * 'height' and 'description'. Only 'uri' is required and used for Atom rendering. + * + * @param array $data + */ + public function setImage(array $data) + { + if (empty($data['uri']) || !is_string($data['uri']) + || !Zend_Uri::check($data['uri'])) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: parameter \'uri\'' + . ' must be a non-empty string and valid URI/IRI'); + } + $this->_data['image'] = $data; + } + + /** + * Set the feed language + * + * @return string|null + */ + public function setLanguage($language) + { + if (empty($language) || !is_string($language)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: parameter must be a non-empty string'); + } + $this->_data['language'] = $language; + } + + /** + * Set a link to the HTML source + * + * @param string $link + */ + public function setLink($link) + { + if (empty($link) || !is_string($link) || !Zend_Uri::check($link)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: parameter must be a non-empty string and valid URI/IRI'); + } + $this->_data['link'] = $link; + } + + /** + * Set a link to an XML feed for any feed type/version + * + * @return string|null + */ + public function setFeedLink($link, $type) + { + if (empty($link) || !is_string($link) || !Zend_Uri::check($link)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: "link"" must be a non-empty string and valid URI/IRI'); + } + if (!in_array(strtolower($type), array('rss', 'rdf', 'atom'))) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: "type"; You must declare the type of feed the link points to, i.e. RSS, RDF or Atom'); + } + $this->_data['feedLinks'][strtolower($type)] = $link; + } + + /** + * Set the feed title + * + * @return string|null + */ + public function setTitle($title) + { + if (empty($title) || !is_string($title)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: parameter must be a non-empty string'); + } + $this->_data['title'] = $title; + } + + /** + * Set the feed character encoding + * + * @param string $encoding + */ + public function setEncoding($encoding) + { + if (empty($encoding) || !is_string($encoding)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: parameter must be a non-empty string'); + } + $this->_data['encoding'] = $encoding; + } + + /** + * Set the feed's base URL + * + * @param string $url + */ + public function setBaseUrl($url) + { + if (empty($url) || !is_string($url) || !Zend_Uri::check($url)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: "url" array value' + . ' must be a non-empty string and valid URI/IRI'); + } + $this->_data['baseUrl'] = $url; + } + + /** + * Add a Pubsubhubbub hub endpoint URL + * + * @param string $url + */ + public function addHub($url) + { + if (empty($url) || !is_string($url) || !Zend_Uri::check($url)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: "url" array value' + . ' must be a non-empty string and valid URI/IRI'); + } + if (!isset($this->_data['hubs'])) { + $this->_data['hubs'] = array(); + } + $this->_data['hubs'][] = $url; + } + + /** + * Add Pubsubhubbub hub endpoint URLs + * + * @param array $urls + */ + public function addHubs(array $urls) + { + foreach ($urls as $url) { + $this->addHub($url); + } + } + + /** + * Add a feed category + * + * @param string $category + */ + public function addCategory(array $category) + { + if (!isset($category['term'])) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Each category must be an array and ' + . 'contain at least a "term" element containing the machine ' + . ' readable category name'); + } + if (isset($category['scheme'])) { + if (empty($category['scheme']) + || !is_string($category['scheme']) + || !Zend_Uri::check($category['scheme']) + ) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('The Atom scheme or RSS domain of' + . ' a category must be a valid URI'); + } + } + if (!isset($this->_data['categories'])) { + $this->_data['categories'] = array(); + } + $this->_data['categories'][] = $category; + } + + /** + * Set an array of feed categories + * + * @param array $categories + */ + public function addCategories(array $categories) + { + foreach ($categories as $category) { + $this->addCategory($category); + } + } + + /** + * Get a single author + * + * @param int $index + * @return string|null + */ + public function getAuthor($index = 0) + { + if (isset($this->_data['authors'][$index])) { + return $this->_data['authors'][$index]; + } else { + return null; + } + } + + /** + * Get an array with feed authors + * + * @return array + */ + public function getAuthors() + { + if (!array_key_exists('authors', $this->_data)) { + return null; + } + return $this->_data['authors']; + } + + /** + * Get the copyright entry + * + * @return string|null + */ + public function getCopyright() + { + if (!array_key_exists('copyright', $this->_data)) { + return null; + } + return $this->_data['copyright']; + } + + /** + * Get the feed creation date + * + * @return string|null + */ + public function getDateCreated() + { + if (!array_key_exists('dateCreated', $this->_data)) { + return null; + } + return $this->_data['dateCreated']; + } + + /** + * Get the feed modification date + * + * @return string|null + */ + public function getDateModified() + { + if (!array_key_exists('dateModified', $this->_data)) { + return null; + } + return $this->_data['dateModified']; + } + + /** + * Get the feed last-build date + * + * @return string|null + */ + public function getLastBuildDate() + { + if (!array_key_exists('lastBuildDate', $this->_data)) { + return null; + } + return $this->_data['lastBuildDate']; + } + + /** + * Get the feed description + * + * @return string|null + */ + public function getDescription() + { + if (!array_key_exists('description', $this->_data)) { + return null; + } + return $this->_data['description']; + } + + /** + * Get the feed generator entry + * + * @return string|null + */ + public function getGenerator() + { + if (!array_key_exists('generator', $this->_data)) { + return null; + } + return $this->_data['generator']; + } + + /** + * Get the feed ID + * + * @return string|null + */ + public function getId() + { + if (!array_key_exists('id', $this->_data)) { + return null; + } + return $this->_data['id']; + } + + /** + * Get the feed image URI + * + * @return array + */ + public function getImage() + { + if (!array_key_exists('image', $this->_data)) { + return null; + } + return $this->_data['image']; + } + + /** + * Get the feed language + * + * @return string|null + */ + public function getLanguage() + { + if (!array_key_exists('language', $this->_data)) { + return null; + } + return $this->_data['language']; + } + + /** + * Get a link to the HTML source + * + * @return string|null + */ + public function getLink() + { + if (!array_key_exists('link', $this->_data)) { + return null; + } + return $this->_data['link']; + } + + /** + * Get a link to the XML feed + * + * @return string|null + */ + public function getFeedLinks() + { + if (!array_key_exists('feedLinks', $this->_data)) { + return null; + } + return $this->_data['feedLinks']; + } + + /** + * Get the feed title + * + * @return string|null + */ + public function getTitle() + { + if (!array_key_exists('title', $this->_data)) { + return null; + } + return $this->_data['title']; + } + + /** + * Get the feed character encoding + * + * @return string|null + */ + public function getEncoding() + { + if (!array_key_exists('encoding', $this->_data)) { + return 'UTF-8'; + } + return $this->_data['encoding']; + } + + /** + * Get the feed's base url + * + * @return string|null + */ + public function getBaseUrl() + { + if (!array_key_exists('baseUrl', $this->_data)) { + return null; + } + return $this->_data['baseUrl']; + } + + /** + * Get the URLs used as Pubsubhubbub hubs endpoints + * + * @return string|null + */ + public function getHubs() + { + if (!array_key_exists('hubs', $this->_data)) { + return null; + } + return $this->_data['hubs']; + } + + /** + * Get the feed categories + * + * @return string|null + */ + public function getCategories() + { + if (!array_key_exists('categories', $this->_data)) { + return null; + } + return $this->_data['categories']; + } + + /** + * Resets the instance and deletes all data + * + * @return void + */ + public function reset() + { + $this->_data = array(); + } + + /** + * Set the current feed type being exported to "rss" or "atom". This allows + * other objects to gracefully choose whether to execute or not, depending + * on their appropriateness for the current type, e.g. renderers. + * + * @param string $type + */ + public function setType($type) + { + $this->_type = $type; + } + + /** + * Retrieve the current or last feed type exported. + * + * @return string Value will be "rss" or "atom" + */ + public function getType() + { + return $this->_type; + } + + /** + * Unset a specific data point + * + * @param string $name + */ + public function remove($name) + { + if (isset($this->_data[$name])) { + unset($this->_data[$name]); + } + } + + /** + * Method overloading: call given method on first extension implementing it + * + * @param string $method + * @param array $args + * @return mixed + * @throws Zend_Feed_Exception if no extensions implements the method + */ + public function __call($method, $args) + { + foreach ($this->_extensions as $extension) { + try { + return call_user_func_array(array($extension, $method), $args); + } catch (Zend_Feed_Writer_Exception_InvalidMethodException $e) { + } + } + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Method: ' . $method + . ' does not exist and could not be located on a registered Extension'); + } + + /** + * Load extensions from Zend_Feed_Writer + * + * @return void + */ + protected function _loadExtensions() + { + $all = Zend_Feed_Writer::getExtensions(); + $exts = $all['feed']; + foreach ($exts as $ext) { + $className = Zend_Feed_Writer::getPluginLoader()->getClassName($ext); + $this->_extensions[$ext] = new $className(); + $this->_extensions[$ext]->setEncoding($this->getEncoding()); + } + } +} diff --git a/libs/Zend/Feed/Writer/Renderer/Entry/Atom.php b/libs/Zend/Feed/Writer/Renderer/Entry/Atom.php new file mode 100644 index 0000000000..76095e89f0 --- /dev/null +++ b/libs/Zend/Feed/Writer/Renderer/Entry/Atom.php @@ -0,0 +1,410 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Atom.php 22065 2010-04-30 14:04:57Z padraic $ + */ + +/** + * @see Zend_Feed_Writer_Renderer_RendererAbstract + */ +// require_once 'Zend/Feed/Writer/Renderer/RendererAbstract.php'; + +// require_once 'Zend/Feed/Writer/Renderer/Feed/Atom/Source.php'; + +/** + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Writer_Renderer_Entry_Atom + extends Zend_Feed_Writer_Renderer_RendererAbstract + implements Zend_Feed_Writer_Renderer_RendererInterface +{ + /** + * Constructor + * + * @param Zend_Feed_Writer_Entry $container + * @return void + */ + public function __construct (Zend_Feed_Writer_Entry $container) + { + parent::__construct($container); + } + + /** + * Render atom entry + * + * @return Zend_Feed_Writer_Renderer_Entry_Atom + */ + public function render() + { + $this->_dom = new DOMDocument('1.0', $this->_container->getEncoding()); + $this->_dom->formatOutput = true; + $entry = $this->_dom->createElementNS(Zend_Feed_Writer::NAMESPACE_ATOM_10, 'entry'); + $this->_dom->appendChild($entry); + + $this->_setSource($this->_dom, $entry); + $this->_setTitle($this->_dom, $entry); + $this->_setDescription($this->_dom, $entry); + $this->_setDateCreated($this->_dom, $entry); + $this->_setDateModified($this->_dom, $entry); + $this->_setLink($this->_dom, $entry); + $this->_setId($this->_dom, $entry); + $this->_setAuthors($this->_dom, $entry); + $this->_setEnclosure($this->_dom, $entry); + $this->_setContent($this->_dom, $entry); + $this->_setCategories($this->_dom, $entry); + + foreach ($this->_extensions as $ext) { + $ext->setType($this->getType()); + $ext->setRootElement($this->getRootElement()); + $ext->setDomDocument($this->getDomDocument(), $entry); + $ext->render(); + } + + return $this; + } + + /** + * Set entry title + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setTitle(DOMDocument $dom, DOMElement $root) + { + if(!$this->getDataContainer()->getTitle()) { + // require_once 'Zend/Feed/Exception.php'; + $message = 'Atom 1.0 entry elements MUST contain exactly one' + . ' atom:title element but a title has not been set'; + $exception = new Zend_Feed_Exception($message); + if (!$this->_ignoreExceptions) { + throw $exception; + } else { + $this->_exceptions[] = $exception; + return; + } + } + $title = $dom->createElement('title'); + $root->appendChild($title); + $title->setAttribute('type', 'html'); + $cdata = $dom->createCDATASection($this->getDataContainer()->getTitle()); + $title->appendChild($cdata); + } + + /** + * Set entry description + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setDescription(DOMDocument $dom, DOMElement $root) + { + if(!$this->getDataContainer()->getDescription()) { + return; // unless src content or base64 + } + $subtitle = $dom->createElement('summary'); + $root->appendChild($subtitle); + $subtitle->setAttribute('type', 'html'); + $cdata = $dom->createCDATASection( + $this->getDataContainer()->getDescription() + ); + $subtitle->appendChild($cdata); + } + + /** + * Set date entry was modified + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setDateModified(DOMDocument $dom, DOMElement $root) + { + if(!$this->getDataContainer()->getDateModified()) { + // require_once 'Zend/Feed/Exception.php'; + $message = 'Atom 1.0 entry elements MUST contain exactly one' + . ' atom:updated element but a modification date has not been set'; + $exception = new Zend_Feed_Exception($message); + if (!$this->_ignoreExceptions) { + throw $exception; + } else { + $this->_exceptions[] = $exception; + return; + } + } + + $updated = $dom->createElement('updated'); + $root->appendChild($updated); + $text = $dom->createTextNode( + $this->getDataContainer()->getDateModified()->get(Zend_Date::ISO_8601) + ); + $updated->appendChild($text); + } + + /** + * Set date entry was created + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setDateCreated(DOMDocument $dom, DOMElement $root) + { + if (!$this->getDataContainer()->getDateCreated()) { + return; + } + $el = $dom->createElement('published'); + $root->appendChild($el); + $text = $dom->createTextNode( + $this->getDataContainer()->getDateCreated()->get(Zend_Date::ISO_8601) + ); + $el->appendChild($text); + } + + /** + * Set entry authors + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setAuthors(DOMDocument $dom, DOMElement $root) + { + $authors = $this->_container->getAuthors(); + if ((!$authors || empty($authors))) { + /** + * This will actually trigger an Exception at the feed level if + * a feed level author is not set. + */ + return; + } + foreach ($authors as $data) { + $author = $this->_dom->createElement('author'); + $name = $this->_dom->createElement('name'); + $author->appendChild($name); + $root->appendChild($author); + $text = $dom->createTextNode($data['name']); + $name->appendChild($text); + if (array_key_exists('email', $data)) { + $email = $this->_dom->createElement('email'); + $author->appendChild($email); + $text = $dom->createTextNode($data['email']); + $email->appendChild($text); + } + if (array_key_exists('uri', $data)) { + $uri = $this->_dom->createElement('uri'); + $author->appendChild($uri); + $text = $dom->createTextNode($data['uri']); + $uri->appendChild($text); + } + } + } + + /** + * Set entry enclosure + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setEnclosure(DOMDocument $dom, DOMElement $root) + { + $data = $this->_container->getEnclosure(); + if ((!$data || empty($data))) { + return; + } + $enclosure = $this->_dom->createElement('link'); + $enclosure->setAttribute('rel', 'enclosure'); + if (isset($data['type'])) { + $enclosure->setAttribute('type', $data['type']); + } + if (isset($data['length'])) { + $enclosure->setAttribute('length', $data['length']); + } + $enclosure->setAttribute('href', $data['uri']); + $root->appendChild($enclosure); + } + + protected function _setLink(DOMDocument $dom, DOMElement $root) + { + if(!$this->getDataContainer()->getLink()) { + return; + } + $link = $dom->createElement('link'); + $root->appendChild($link); + $link->setAttribute('rel', 'alternate'); + $link->setAttribute('type', 'text/html'); + $link->setAttribute('href', $this->getDataContainer()->getLink()); + } + + /** + * Set entry identifier + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setId(DOMDocument $dom, DOMElement $root) + { + if(!$this->getDataContainer()->getId() + && !$this->getDataContainer()->getLink()) { + // require_once 'Zend/Feed/Exception.php'; + $message = 'Atom 1.0 entry elements MUST contain exactly one ' + . 'atom:id element, or as an alternative, we can use the same ' + . 'value as atom:link however neither a suitable link nor an ' + . 'id have been set'; + $exception = new Zend_Feed_Exception($message); + if (!$this->_ignoreExceptions) { + throw $exception; + } else { + $this->_exceptions[] = $exception; + return; + } + } + + if (!$this->getDataContainer()->getId()) { + $this->getDataContainer()->setId( + $this->getDataContainer()->getLink()); + } + if (!Zend_Uri::check($this->getDataContainer()->getId()) && + !preg_match("#^urn:[a-zA-Z0-9][a-zA-Z0-9\-]{1,31}:([a-zA-Z0-9\(\)\+\,\.\:\=\@\;\$\_\!\*\-]|%[0-9a-fA-F]{2})*#", $this->getDataContainer()->getId())) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Atom 1.0 IDs must be a valid URI/IRI'); + } + $id = $dom->createElement('id'); + $root->appendChild($id); + $text = $dom->createTextNode($this->getDataContainer()->getId()); + $id->appendChild($text); + } + + /** + * Set entry content + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setContent(DOMDocument $dom, DOMElement $root) + { + $content = $this->getDataContainer()->getContent(); + if (!$content && !$this->getDataContainer()->getLink()) { + // require_once 'Zend/Feed/Exception.php'; + $message = 'Atom 1.0 entry elements MUST contain exactly one ' + . 'atom:content element, or as an alternative, at least one link ' + . 'with a rel attribute of "alternate" to indicate an alternate ' + . 'method to consume the content.'; + $exception = new Zend_Feed_Exception($message); + if (!$this->_ignoreExceptions) { + throw $exception; + } else { + $this->_exceptions[] = $exception; + return; + } + } + if (!$content) { + return; + } + $element = $dom->createElement('content'); + $element->setAttribute('type', 'xhtml'); + $xhtmlElement = $this->_loadXhtml($content); + $xhtml = $dom->importNode($xhtmlElement, true); + $element->appendChild($xhtml); + $root->appendChild($element); + } + + /** + * Load a HTML string and attempt to normalise to XML + */ + protected function _loadXhtml($content) + { + $xhtml = ''; + if (class_exists('tidy', false)) { + $tidy = new tidy; + $config = array( + 'output-xhtml' => true, + 'show-body-only' => true, + 'quote-nbsp' => false + ); + $encoding = str_replace('-', '', $this->getEncoding()); + $tidy->parseString($content, $config, $encoding); + $tidy->cleanRepair(); + $xhtml = (string) $tidy; + } else { + $xhtml = $content; + } + $xhtml = preg_replace(array( + "/(<[\/]?)([a-zA-Z]+)/" + ), '$1xhtml:$2', $xhtml); + $dom = new DOMDocument('1.0', $this->getEncoding()); + $dom->loadXML('<xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml">' + . $xhtml . '</xhtml:div>'); + return $dom->documentElement; + } + + /** + * Set entry cateories + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setCategories(DOMDocument $dom, DOMElement $root) + { + $categories = $this->getDataContainer()->getCategories(); + if (!$categories) { + return; + } + foreach ($categories as $cat) { + $category = $dom->createElement('category'); + $category->setAttribute('term', $cat['term']); + if (isset($cat['label'])) { + $category->setAttribute('label', $cat['label']); + } else { + $category->setAttribute('label', $cat['term']); + } + if (isset($cat['scheme'])) { + $category->setAttribute('scheme', $cat['scheme']); + } + $root->appendChild($category); + } + } + + /** + * Append Source element (Atom 1.0 Feed Metadata) + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setSource(DOMDocument $dom, DOMElement $root) + { + $source = $this->getDataContainer()->getSource(); + if (!$source) { + return; + } + $renderer = new Zend_Feed_Writer_Renderer_Feed_Atom_Source($source); + $renderer->setType($this->getType()); + $element = $renderer->render()->getElement(); + $imported = $dom->importNode($element, true); + $root->appendChild($imported); + } +} diff --git a/libs/Zend/Feed/Writer/Renderer/Entry/Atom/Deleted.php b/libs/Zend/Feed/Writer/Renderer/Entry/Atom/Deleted.php new file mode 100644 index 0000000000..fb75262935 --- /dev/null +++ b/libs/Zend/Feed/Writer/Renderer/Entry/Atom/Deleted.php @@ -0,0 +1,121 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Atom.php 20506 2010-01-21 22:19:05Z padraic $ + */ + +/** + * @see Zend_Feed_Writer_Renderer_RendererAbstract + */ +// require_once 'Zend/Feed/Writer/Renderer/RendererAbstract.php'; + +/** + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Writer_Renderer_Entry_Atom_Deleted + extends Zend_Feed_Writer_Renderer_RendererAbstract + implements Zend_Feed_Writer_Renderer_RendererInterface +{ + /** + * Constructor + * + * @param Zend_Feed_Writer_Deleted $container + * @return void + */ + public function __construct (Zend_Feed_Writer_Deleted $container) + { + parent::__construct($container); + } + + /** + * Render atom entry + * + * @return Zend_Feed_Writer_Renderer_Entry_Atom + */ + public function render() + { + $this->_dom = new DOMDocument('1.0', $this->_container->getEncoding()); + $this->_dom->formatOutput = true; + $entry = $this->_dom->createElement('at:deleted-entry'); + $this->_dom->appendChild($entry); + + $entry->setAttribute('ref', $this->_container->getReference()); + $entry->setAttribute('when', $this->_container->getWhen()->get(Zend_Date::ISO_8601)); + + $this->_setBy($this->_dom, $entry); + $this->_setComment($this->_dom, $entry); + + return $this; + } + + /** + * Set tombstone comment + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setComment(DOMDocument $dom, DOMElement $root) + { + if(!$this->getDataContainer()->getComment()) { + return; + } + $c = $dom->createElement('at:comment'); + $root->appendChild($c); + $c->setAttribute('type', 'html'); + $cdata = $dom->createCDATASection($this->getDataContainer()->getComment()); + $c->appendChild($cdata); + } + + /** + * Set entry authors + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setBy(DOMDocument $dom, DOMElement $root) + { + $data = $this->_container->getBy(); + if ((!$data || empty($data))) { + return; + } + $author = $this->_dom->createElement('at:by'); + $name = $this->_dom->createElement('name'); + $author->appendChild($name); + $root->appendChild($author); + $text = $dom->createTextNode($data['name']); + $name->appendChild($text); + if (array_key_exists('email', $data)) { + $email = $this->_dom->createElement('email'); + $author->appendChild($email); + $text = $dom->createTextNode($data['email']); + $email->appendChild($text); + } + if (array_key_exists('uri', $data)) { + $uri = $this->_dom->createElement('uri'); + $author->appendChild($uri); + $text = $dom->createTextNode($data['uri']); + $uri->appendChild($text); + } + } + +} diff --git a/libs/Zend/Feed/Writer/Renderer/Entry/Rss.php b/libs/Zend/Feed/Writer/Renderer/Entry/Rss.php new file mode 100644 index 0000000000..74e80f5707 --- /dev/null +++ b/libs/Zend/Feed/Writer/Renderer/Entry/Rss.php @@ -0,0 +1,346 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Rss.php 22065 2010-04-30 14:04:57Z padraic $ + */ + +/** + * @see Zend_Feed_Writer_Renderer_RendererAbstract + */ +// require_once 'Zend/Feed/Writer/Renderer/RendererAbstract.php'; + +/** + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Writer_Renderer_Entry_Rss + extends Zend_Feed_Writer_Renderer_RendererAbstract + implements Zend_Feed_Writer_Renderer_RendererInterface +{ + /** + * Constructor + * + * @param Zend_Feed_Writer_Entry $container + * @return void + */ + public function __construct (Zend_Feed_Writer_Entry $container) + { + parent::__construct($container); + } + + /** + * Render RSS entry + * + * @return Zend_Feed_Writer_Renderer_Entry_Rss + */ + public function render() + { + $this->_dom = new DOMDocument('1.0', $this->_container->getEncoding()); + $this->_dom->formatOutput = true; + $this->_dom->substituteEntities = false; + $entry = $this->_dom->createElement('item'); + $this->_dom->appendChild($entry); + + $this->_setTitle($this->_dom, $entry); + $this->_setDescription($this->_dom, $entry); + $this->_setDateCreated($this->_dom, $entry); + $this->_setDateModified($this->_dom, $entry); + $this->_setLink($this->_dom, $entry); + $this->_setId($this->_dom, $entry); + $this->_setAuthors($this->_dom, $entry); + $this->_setEnclosure($this->_dom, $entry); + $this->_setCommentLink($this->_dom, $entry); + $this->_setCategories($this->_dom, $entry); + foreach ($this->_extensions as $ext) { + $ext->setType($this->getType()); + $ext->setRootElement($this->getRootElement()); + $ext->setDomDocument($this->getDomDocument(), $entry); + $ext->render(); + } + + return $this; + } + + /** + * Set entry title + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setTitle(DOMDocument $dom, DOMElement $root) + { + if(!$this->getDataContainer()->getDescription() + && !$this->getDataContainer()->getTitle()) { + // require_once 'Zend/Feed/Exception.php'; + $message = 'RSS 2.0 entry elements SHOULD contain exactly one' + . ' title element but a title has not been set. In addition, there' + . ' is no description as required in the absence of a title.'; + $exception = new Zend_Feed_Exception($message); + if (!$this->_ignoreExceptions) { + throw $exception; + } else { + $this->_exceptions[] = $exception; + return; + } + } + $title = $dom->createElement('title'); + $root->appendChild($title); + $text = $dom->createTextNode($this->getDataContainer()->getTitle()); + $title->appendChild($text); + } + + /** + * Set entry description + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setDescription(DOMDocument $dom, DOMElement $root) + { + if(!$this->getDataContainer()->getDescription() + && !$this->getDataContainer()->getTitle()) { + // require_once 'Zend/Feed/Exception.php'; + $message = 'RSS 2.0 entry elements SHOULD contain exactly one' + . ' description element but a description has not been set. In' + . ' addition, there is no title element as required in the absence' + . ' of a description.'; + $exception = new Zend_Feed_Exception($message); + if (!$this->_ignoreExceptions) { + throw $exception; + } else { + $this->_exceptions[] = $exception; + return; + } + } + if (!$this->getDataContainer()->getDescription()) { + return; + } + $subtitle = $dom->createElement('description'); + $root->appendChild($subtitle); + $text = $dom->createCDATASection($this->getDataContainer()->getDescription()); + $subtitle->appendChild($text); + } + + /** + * Set date entry was last modified + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setDateModified(DOMDocument $dom, DOMElement $root) + { + if(!$this->getDataContainer()->getDateModified()) { + return; + } + + $updated = $dom->createElement('pubDate'); + $root->appendChild($updated); + $text = $dom->createTextNode( + $this->getDataContainer()->getDateModified()->get(Zend_Date::RSS) + ); + $updated->appendChild($text); + } + + /** + * Set date entry was created + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setDateCreated(DOMDocument $dom, DOMElement $root) + { + if (!$this->getDataContainer()->getDateCreated()) { + return; + } + if (!$this->getDataContainer()->getDateModified()) { + $this->getDataContainer()->setDateModified( + $this->getDataContainer()->getDateCreated() + ); + } + } + + /** + * Set entry authors + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setAuthors(DOMDocument $dom, DOMElement $root) + { + $authors = $this->_container->getAuthors(); + if ((!$authors || empty($authors))) { + return; + } + foreach ($authors as $data) { + $author = $this->_dom->createElement('author'); + $name = $data['name']; + if (array_key_exists('email', $data)) { + $name = $data['email'] . ' (' . $data['name'] . ')'; + } + $text = $dom->createTextNode($name); + $author->appendChild($text); + $root->appendChild($author); + } + } + + /** + * Set entry enclosure + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setEnclosure(DOMDocument $dom, DOMElement $root) + { + $data = $this->_container->getEnclosure(); + if ((!$data || empty($data))) { + return; + } + if (!isset($data['type'])) { + // require_once 'Zend/Feed/Exception.php'; + $exception = new Zend_Feed_Exception('Enclosure "type" is not set'); + if (!$this->_ignoreExceptions) { + throw $exception; + } else { + $this->_exceptions[] = $exception; + return; + } + } + if (!isset($data['length'])) { + // require_once 'Zend/Feed/Exception.php'; + $exception = new Zend_Feed_Exception('Enclosure "length" is not set'); + if (!$this->_ignoreExceptions) { + throw $exception; + } else { + $this->_exceptions[] = $exception; + return; + } + } + if (isset($data['length']) && (int) $data['length'] <= 0) { + // require_once 'Zend/Feed/Exception.php'; + $exception = new Zend_Feed_Exception('Enclosure "length" must be an integer' + . ' indicating the content\'s length in bytes'); + if (!$this->_ignoreExceptions) { + throw $exception; + } else { + $this->_exceptions[] = $exception; + return; + } + } + $enclosure = $this->_dom->createElement('enclosure'); + $enclosure->setAttribute('type', $data['type']); + $enclosure->setAttribute('length', $data['length']); + $enclosure->setAttribute('url', $data['uri']); + $root->appendChild($enclosure); + } + + /** + * Set link to entry + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setLink(DOMDocument $dom, DOMElement $root) + { + if(!$this->getDataContainer()->getLink()) { + return; + } + $link = $dom->createElement('link'); + $root->appendChild($link); + $text = $dom->createTextNode($this->getDataContainer()->getLink()); + $link->appendChild($text); + } + + /** + * Set entry identifier + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setId(DOMDocument $dom, DOMElement $root) + { + if(!$this->getDataContainer()->getId() + && !$this->getDataContainer()->getLink()) { + return; + } + + $id = $dom->createElement('guid'); + $root->appendChild($id); + if (!$this->getDataContainer()->getId()) { + $this->getDataContainer()->setId( + $this->getDataContainer()->getLink()); + } + $text = $dom->createTextNode($this->getDataContainer()->getId()); + $id->appendChild($text); + if (!Zend_Uri::check($this->getDataContainer()->getId())) { + $id->setAttribute('isPermaLink', 'false'); + } + } + + /** + * Set link to entry comments + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setCommentLink(DOMDocument $dom, DOMElement $root) + { + $link = $this->getDataContainer()->getCommentLink(); + if (!$link) { + return; + } + $clink = $this->_dom->createElement('comments'); + $text = $dom->createTextNode($link); + $clink->appendChild($text); + $root->appendChild($clink); + } + + /** + * Set entry categories + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setCategories(DOMDocument $dom, DOMElement $root) + { + $categories = $this->getDataContainer()->getCategories(); + if (!$categories) { + return; + } + foreach ($categories as $cat) { + $category = $dom->createElement('category'); + if (isset($cat['scheme'])) { + $category->setAttribute('domain', $cat['scheme']); + } + $text = $dom->createCDATASection($cat['term']); + $category->appendChild($text); + $root->appendChild($category); + } + } +} diff --git a/libs/Zend/Feed/Writer/Renderer/Feed/Atom.php b/libs/Zend/Feed/Writer/Renderer/Feed/Atom.php new file mode 100644 index 0000000000..2c88dd4298 --- /dev/null +++ b/libs/Zend/Feed/Writer/Renderer/Feed/Atom.php @@ -0,0 +1,130 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Atom.php 22098 2010-05-04 18:03:29Z padraic $ + */ + +/** @see Zend_Feed_Writer_Feed */ +// require_once 'Zend/Feed/Writer/Feed.php'; + +/** @see Zend_Version */ +// require_once 'Zend/Version.php'; + +/** @see Zend_Feed_Writer_Renderer_RendererInterface */ +// require_once 'Zend/Feed/Writer/Renderer/RendererInterface.php'; + +/** @see Zend_Feed_Writer_Renderer_Entry_Atom */ +// require_once 'Zend/Feed/Writer/Renderer/Entry/Atom.php'; + +/** @see Zend_Feed_Writer_Renderer_Entry_Atom_Deleted */ +// require_once 'Zend/Feed/Writer/Renderer/Entry/Atom/Deleted.php'; + +/** @see Zend_Feed_Writer_Renderer_RendererAbstract */ +// require_once 'Zend/Feed/Writer/Renderer/RendererAbstract.php'; + +// require_once 'Zend/Feed/Writer/Renderer/Feed/Atom/AtomAbstract.php'; + +/** + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Writer_Renderer_Feed_Atom + extends Zend_Feed_Writer_Renderer_Feed_Atom_AtomAbstract + implements Zend_Feed_Writer_Renderer_RendererInterface +{ + /** + * Constructor + * + * @param Zend_Feed_Writer_Feed $container + * @return void + */ + public function __construct (Zend_Feed_Writer_Feed $container) + { + parent::__construct($container); + } + + /** + * Render Atom feed + * + * @return Zend_Feed_Writer_Renderer_Feed_Atom + */ + public function render() + { + if (!$this->_container->getEncoding()) { + $this->_container->setEncoding('UTF-8'); + } + $this->_dom = new DOMDocument('1.0', $this->_container->getEncoding()); + $this->_dom->formatOutput = true; + $root = $this->_dom->createElementNS( + Zend_Feed_Writer::NAMESPACE_ATOM_10, 'feed' + ); + $this->setRootElement($root); + $this->_dom->appendChild($root); + $this->_setLanguage($this->_dom, $root); + $this->_setBaseUrl($this->_dom, $root); + $this->_setTitle($this->_dom, $root); + $this->_setDescription($this->_dom, $root); + $this->_setImage($this->_dom, $root); + $this->_setDateCreated($this->_dom, $root); + $this->_setDateModified($this->_dom, $root); + $this->_setGenerator($this->_dom, $root); + $this->_setLink($this->_dom, $root); + $this->_setFeedLinks($this->_dom, $root); + $this->_setId($this->_dom, $root); + $this->_setAuthors($this->_dom, $root); + $this->_setCopyright($this->_dom, $root); + $this->_setCategories($this->_dom, $root); + $this->_setHubs($this->_dom, $root); + + foreach ($this->_extensions as $ext) { + $ext->setType($this->getType()); + $ext->setRootElement($this->getRootElement()); + $ext->setDomDocument($this->getDomDocument(), $root); + $ext->render(); + } + + foreach ($this->_container as $entry) { + if ($this->getDataContainer()->getEncoding()) { + $entry->setEncoding($this->getDataContainer()->getEncoding()); + } + if ($entry instanceof Zend_Feed_Writer_Entry) { + $renderer = new Zend_Feed_Writer_Renderer_Entry_Atom($entry); + } else { + if (!$this->_dom->documentElement->hasAttribute('xmlns:at')) { + $this->_dom->documentElement->setAttribute( + 'xmlns:at', 'http://purl.org/atompub/tombstones/1.0' + ); + } + $renderer = new Zend_Feed_Writer_Renderer_Entry_Atom_Deleted($entry); + } + if ($this->_ignoreExceptions === true) { + $renderer->ignoreExceptions(); + } + $renderer->setType($this->getType()); + $renderer->setRootElement($this->_dom->documentElement); + $renderer->render(); + $element = $renderer->getElement(); + $imported = $this->_dom->importNode($element, true); + $root->appendChild($imported); + } + return $this; + } + +} diff --git a/libs/Zend/Feed/Writer/Renderer/Feed/Atom/AtomAbstract.php b/libs/Zend/Feed/Writer/Renderer/Feed/Atom/AtomAbstract.php new file mode 100644 index 0000000000..254516e5b5 --- /dev/null +++ b/libs/Zend/Feed/Writer/Renderer/Feed/Atom/AtomAbstract.php @@ -0,0 +1,427 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Atom.php 20096 2010-01-06 02:05:09Z bkarwin $ + */ + +/** @see Zend_Feed_Writer_Feed */ +// require_once 'Zend/Feed/Writer/Feed.php'; + +/** @see Zend_Version */ +// require_once 'Zend/Version.php'; + +/** @see Zend_Feed_Writer_Renderer_RendererInterface */ +// require_once 'Zend/Feed/Writer/Renderer/RendererInterface.php'; + +/** @see Zend_Feed_Writer_Renderer_Entry_Atom */ +// require_once 'Zend/Feed/Writer/Renderer/Entry/Atom.php'; + +/** @see Zend_Feed_Writer_Renderer_RendererAbstract */ +// require_once 'Zend/Feed/Writer/Renderer/RendererAbstract.php'; + +/** + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Writer_Renderer_Feed_Atom_AtomAbstract + extends Zend_Feed_Writer_Renderer_RendererAbstract +{ + /** + * Constructor + * + * @param Zend_Feed_Writer_Feed $container + * @return void + */ + public function __construct ($container) + { + parent::__construct($container); + } + + /** + * Set feed language + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setLanguage(DOMDocument $dom, DOMElement $root) + { + if ($this->getDataContainer()->getLanguage()) { + $root->setAttribute('xml:lang', $this->getDataContainer() + ->getLanguage()); + } + } + + /** + * Set feed title + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setTitle(DOMDocument $dom, DOMElement $root) + { + if(!$this->getDataContainer()->getTitle()) { + // require_once 'Zend/Feed/Exception.php'; + $message = 'Atom 1.0 feed elements MUST contain exactly one' + . ' atom:title element but a title has not been set'; + $exception = new Zend_Feed_Exception($message); + if (!$this->_ignoreExceptions) { + throw $exception; + } else { + $this->_exceptions[] = $exception; + return; + } + } + + $title = $dom->createElement('title'); + $root->appendChild($title); + $title->setAttribute('type', 'text'); + $text = $dom->createTextNode($this->getDataContainer()->getTitle()); + $title->appendChild($text); + } + + /** + * Set feed description + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setDescription(DOMDocument $dom, DOMElement $root) + { + if(!$this->getDataContainer()->getDescription()) { + return; + } + $subtitle = $dom->createElement('subtitle'); + $root->appendChild($subtitle); + $subtitle->setAttribute('type', 'text'); + $text = $dom->createTextNode($this->getDataContainer()->getDescription()); + $subtitle->appendChild($text); + } + + /** + * Set date feed was last modified + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setDateModified(DOMDocument $dom, DOMElement $root) + { + if(!$this->getDataContainer()->getDateModified()) { + // require_once 'Zend/Feed/Exception.php'; + $message = 'Atom 1.0 feed elements MUST contain exactly one' + . ' atom:updated element but a modification date has not been set'; + $exception = new Zend_Feed_Exception($message); + if (!$this->_ignoreExceptions) { + throw $exception; + } else { + $this->_exceptions[] = $exception; + return; + } + } + + $updated = $dom->createElement('updated'); + $root->appendChild($updated); + $text = $dom->createTextNode( + $this->getDataContainer()->getDateModified()->get(Zend_Date::ISO_8601) + ); + $updated->appendChild($text); + } + + /** + * Set feed generator string + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setGenerator(DOMDocument $dom, DOMElement $root) + { + if(!$this->getDataContainer()->getGenerator()) { + $this->getDataContainer()->setGenerator('Zend_Feed_Writer', + Zend_Version::VERSION, 'http://framework.zend.com'); + } + + $gdata = $this->getDataContainer()->getGenerator(); + $generator = $dom->createElement('generator'); + $root->appendChild($generator); + $text = $dom->createTextNode($gdata['name']); + $generator->appendChild($text); + if (array_key_exists('uri', $gdata)) { + $generator->setAttribute('uri', $gdata['uri']); + } + if (array_key_exists('version', $gdata)) { + $generator->setAttribute('version', $gdata['version']); + } + } + + /** + * Set link to feed + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setLink(DOMDocument $dom, DOMElement $root) + { + if(!$this->getDataContainer()->getLink()) { + return; + } + $link = $dom->createElement('link'); + $root->appendChild($link); + $link->setAttribute('rel', 'alternate'); + $link->setAttribute('type', 'text/html'); + $link->setAttribute('href', $this->getDataContainer()->getLink()); + } + + /** + * Set feed links + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setFeedLinks(DOMDocument $dom, DOMElement $root) + { + $flinks = $this->getDataContainer()->getFeedLinks(); + if(!$flinks || !array_key_exists('atom', $flinks)) { + // require_once 'Zend/Feed/Exception.php'; + $message = 'Atom 1.0 feed elements SHOULD contain one atom:link ' + . 'element with a rel attribute value of "self". This is the ' + . 'preferred URI for retrieving Atom Feed Documents representing ' + . 'this Atom feed but a feed link has not been set'; + $exception = new Zend_Feed_Exception($message); + if (!$this->_ignoreExceptions) { + throw $exception; + } else { + $this->_exceptions[] = $exception; + return; + } + } + + foreach ($flinks as $type => $href) { + $mime = 'application/' . strtolower($type) . '+xml'; + $flink = $dom->createElement('link'); + $root->appendChild($flink); + $flink->setAttribute('rel', 'self'); + $flink->setAttribute('type', $mime); + $flink->setAttribute('href', $href); + } + } + + /** + * Set feed authors + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setAuthors(DOMDocument $dom, DOMElement $root) + { + $authors = $this->_container->getAuthors(); + if (!$authors || empty($authors)) { + /** + * Technically we should defer an exception until we can check + * that all entries contain an author. If any entry is missing + * an author, then a missing feed author element is invalid + */ + return; + } + foreach ($authors as $data) { + $author = $this->_dom->createElement('author'); + $name = $this->_dom->createElement('name'); + $author->appendChild($name); + $root->appendChild($author); + $text = $dom->createTextNode($data['name']); + $name->appendChild($text); + if (array_key_exists('email', $data)) { + $email = $this->_dom->createElement('email'); + $author->appendChild($email); + $text = $dom->createTextNode($data['email']); + $email->appendChild($text); + } + if (array_key_exists('uri', $data)) { + $uri = $this->_dom->createElement('uri'); + $author->appendChild($uri); + $text = $dom->createTextNode($data['uri']); + $uri->appendChild($text); + } + } + } + + /** + * Set feed identifier + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setId(DOMDocument $dom, DOMElement $root) + { + if(!$this->getDataContainer()->getId() + && !$this->getDataContainer()->getLink()) { + // require_once 'Zend/Feed/Exception.php'; + $message = 'Atom 1.0 feed elements MUST contain exactly one ' + . 'atom:id element, or as an alternative, we can use the same ' + . 'value as atom:link however neither a suitable link nor an ' + . 'id have been set'; + $exception = new Zend_Feed_Exception($message); + if (!$this->_ignoreExceptions) { + throw $exception; + } else { + $this->_exceptions[] = $exception; + return; + } + } + + if (!$this->getDataContainer()->getId()) { + $this->getDataContainer()->setId( + $this->getDataContainer()->getLink()); + } + $id = $dom->createElement('id'); + $root->appendChild($id); + $text = $dom->createTextNode($this->getDataContainer()->getId()); + $id->appendChild($text); + } + + /** + * Set feed copyright + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setCopyright(DOMDocument $dom, DOMElement $root) + { + $copyright = $this->getDataContainer()->getCopyright(); + if (!$copyright) { + return; + } + $copy = $dom->createElement('rights'); + $root->appendChild($copy); + $text = $dom->createTextNode($copyright); + $copy->appendChild($text); + } + + /** + * Set feed level logo (image) + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setImage(DOMDocument $dom, DOMElement $root) + { + $image = $this->getDataContainer()->getImage(); + if (!$image) { + return; + } + $img = $dom->createElement('logo'); + $root->appendChild($img); + $text = $dom->createTextNode($image['uri']); + $img->appendChild($text); + } + + /** + * Set date feed was created + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setDateCreated(DOMDocument $dom, DOMElement $root) + { + if(!$this->getDataContainer()->getDateCreated()) { + return; + } + if(!$this->getDataContainer()->getDateModified()) { + $this->getDataContainer()->setDateModified( + $this->getDataContainer()->getDateCreated() + ); + } + } + + /** + * Set base URL to feed links + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setBaseUrl(DOMDocument $dom, DOMElement $root) + { + $baseUrl = $this->getDataContainer()->getBaseUrl(); + if (!$baseUrl) { + return; + } + $root->setAttribute('xml:base', $baseUrl); + } + + /** + * Set hubs to which this feed pushes + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setHubs(DOMDocument $dom, DOMElement $root) + { + $hubs = $this->getDataContainer()->getHubs(); + if (!$hubs) { + return; + } + foreach ($hubs as $hubUrl) { + $hub = $dom->createElement('link'); + $hub->setAttribute('rel', 'hub'); + $hub->setAttribute('href', $hubUrl); + $root->appendChild($hub); + } + } + + /** + * Set feed cateories + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setCategories(DOMDocument $dom, DOMElement $root) + { + $categories = $this->getDataContainer()->getCategories(); + if (!$categories) { + return; + } + foreach ($categories as $cat) { + $category = $dom->createElement('category'); + $category->setAttribute('term', $cat['term']); + if (isset($cat['label'])) { + $category->setAttribute('label', $cat['label']); + } else { + $category->setAttribute('label', $cat['term']); + } + if (isset($cat['scheme'])) { + $category->setAttribute('scheme', $cat['scheme']); + } + $root->appendChild($category); + } + } +} diff --git a/libs/Zend/Feed/Writer/Renderer/Feed/Atom/Source.php b/libs/Zend/Feed/Writer/Renderer/Feed/Atom/Source.php new file mode 100644 index 0000000000..125fed1eaf --- /dev/null +++ b/libs/Zend/Feed/Writer/Renderer/Feed/Atom/Source.php @@ -0,0 +1,110 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Atom.php 20096 2010-01-06 02:05:09Z bkarwin $ + */ + +// require_once 'Zend/Feed/Writer/Renderer/Feed/Atom/AtomAbstract.php'; + +/** + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Writer_Renderer_Feed_Atom_Source + extends Zend_Feed_Writer_Renderer_Feed_Atom_AtomAbstract + implements Zend_Feed_Writer_Renderer_RendererInterface +{ + + /** + * Constructor + * + * @param Zend_Feed_Writer_Feed_Source $container + * @return void + */ + public function __construct (Zend_Feed_Writer_Source $container) + { + parent::__construct($container); + } + + /** + * Render Atom Feed Metadata (Source element) + * + * @return Zend_Feed_Writer_Renderer_Feed_Atom + */ + public function render() + { + if (!$this->_container->getEncoding()) { + $this->_container->setEncoding('UTF-8'); + } + $this->_dom = new DOMDocument('1.0', $this->_container->getEncoding()); + $this->_dom->formatOutput = true; + $root = $this->_dom->createElement('source'); + $this->setRootElement($root); + $this->_dom->appendChild($root); + $this->_setLanguage($this->_dom, $root); + $this->_setBaseUrl($this->_dom, $root); + $this->_setTitle($this->_dom, $root); + $this->_setDescription($this->_dom, $root); + $this->_setDateCreated($this->_dom, $root); + $this->_setDateModified($this->_dom, $root); + $this->_setGenerator($this->_dom, $root); + $this->_setLink($this->_dom, $root); + $this->_setFeedLinks($this->_dom, $root); + $this->_setId($this->_dom, $root); + $this->_setAuthors($this->_dom, $root); + $this->_setCopyright($this->_dom, $root); + $this->_setCategories($this->_dom, $root); + + foreach ($this->_extensions as $ext) { + $ext->setType($this->getType()); + $ext->setRootElement($this->getRootElement()); + $ext->setDomDocument($this->getDomDocument(), $root); + $ext->render(); + } + return $this; + } + + /** + * Set feed generator string + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setGenerator(DOMDocument $dom, DOMElement $root) + { + if(!$this->getDataContainer()->getGenerator()) { + return; + } + + $gdata = $this->getDataContainer()->getGenerator(); + $generator = $dom->createElement('generator'); + $root->appendChild($generator); + $text = $dom->createTextNode($gdata['name']); + $generator->appendChild($text); + if (array_key_exists('uri', $gdata)) { + $generator->setAttribute('uri', $gdata['uri']); + } + if (array_key_exists('version', $gdata)) { + $generator->setAttribute('version', $gdata['version']); + } + } + +} diff --git a/libs/Zend/Feed/Writer/Renderer/Feed/Rss.php b/libs/Zend/Feed/Writer/Renderer/Feed/Rss.php new file mode 100644 index 0000000000..07b94e7b86 --- /dev/null +++ b/libs/Zend/Feed/Writer/Renderer/Feed/Rss.php @@ -0,0 +1,505 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Rss.php 22108 2010-05-05 13:44:11Z padraic $ + */ + +/** @see Zend_Feed_Writer_Feed */ +// require_once 'Zend/Feed/Writer/Feed.php'; + +/** @see Zend_Version */ +// require_once 'Zend/Version.php'; + +/** @see Zend_Feed_Writer_Renderer_RendererInterface */ +// require_once 'Zend/Feed/Writer/Renderer/RendererInterface.php'; + +/** @see Zend_Feed_Writer_Renderer_Entry_Rss */ +// require_once 'Zend/Feed/Writer/Renderer/Entry/Rss.php'; + +/** @see Zend_Feed_Writer_Renderer_RendererAbstract */ +// require_once 'Zend/Feed/Writer/Renderer/RendererAbstract.php'; + +/** + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Writer_Renderer_Feed_Rss + extends Zend_Feed_Writer_Renderer_RendererAbstract + implements Zend_Feed_Writer_Renderer_RendererInterface +{ + /** + * Constructor + * + * @param Zend_Feed_Writer_Feed $container + * @return void + */ + public function __construct (Zend_Feed_Writer_Feed $container) + { + parent::__construct($container); + } + + /** + * Render RSS feed + * + * @return Zend_Feed_Writer_Renderer_Feed_Rss + */ + public function render() + { + if (!$this->_container->getEncoding()) { + $this->_container->setEncoding('UTF-8'); + } + $this->_dom = new DOMDocument('1.0', $this->_container->getEncoding()); + $this->_dom->formatOutput = true; + $this->_dom->substituteEntities = false; + $rss = $this->_dom->createElement('rss'); + $this->setRootElement($rss); + $rss->setAttribute('version', '2.0'); + + $channel = $this->_dom->createElement('channel'); + $rss->appendChild($channel); + $this->_dom->appendChild($rss); + $this->_setLanguage($this->_dom, $channel); + $this->_setBaseUrl($this->_dom, $channel); + $this->_setTitle($this->_dom, $channel); + $this->_setDescription($this->_dom, $channel); + $this->_setImage($this->_dom, $channel); + $this->_setDateCreated($this->_dom, $channel); + $this->_setDateModified($this->_dom, $channel); + $this->_setLastBuildDate($this->_dom, $channel); + $this->_setGenerator($this->_dom, $channel); + $this->_setLink($this->_dom, $channel); + $this->_setAuthors($this->_dom, $channel); + $this->_setCopyright($this->_dom, $channel); + $this->_setCategories($this->_dom, $channel); + + foreach ($this->_extensions as $ext) { + $ext->setType($this->getType()); + $ext->setRootElement($this->getRootElement()); + $ext->setDomDocument($this->getDomDocument(), $channel); + $ext->render(); + } + + foreach ($this->_container as $entry) { + if ($this->getDataContainer()->getEncoding()) { + $entry->setEncoding($this->getDataContainer()->getEncoding()); + } + if ($entry instanceof Zend_Feed_Writer_Entry) { + $renderer = new Zend_Feed_Writer_Renderer_Entry_Rss($entry); + } else { + continue; + } + if ($this->_ignoreExceptions === true) { + $renderer->ignoreExceptions(); + } + $renderer->setType($this->getType()); + $renderer->setRootElement($this->_dom->documentElement); + $renderer->render(); + $element = $renderer->getElement(); + $imported = $this->_dom->importNode($element, true); + $channel->appendChild($imported); + } + return $this; + } + + /** + * Set feed language + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setLanguage(DOMDocument $dom, DOMElement $root) + { + $lang = $this->getDataContainer()->getLanguage(); + if (!$lang) { + return; + } + $language = $dom->createElement('language'); + $root->appendChild($language); + $language->nodeValue = $lang; + } + + /** + * Set feed title + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setTitle(DOMDocument $dom, DOMElement $root) + { + if(!$this->getDataContainer()->getTitle()) { + // require_once 'Zend/Feed/Exception.php'; + $message = 'RSS 2.0 feed elements MUST contain exactly one' + . ' title element but a title has not been set'; + $exception = new Zend_Feed_Exception($message); + if (!$this->_ignoreExceptions) { + throw $exception; + } else { + $this->_exceptions[] = $exception; + return; + } + } + + $title = $dom->createElement('title'); + $root->appendChild($title); + $text = $dom->createTextNode($this->getDataContainer()->getTitle()); + $title->appendChild($text); + } + + /** + * Set feed description + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setDescription(DOMDocument $dom, DOMElement $root) + { + if(!$this->getDataContainer()->getDescription()) { + // require_once 'Zend/Feed/Exception.php'; + $message = 'RSS 2.0 feed elements MUST contain exactly one' + . ' description element but one has not been set'; + $exception = new Zend_Feed_Exception($message); + if (!$this->_ignoreExceptions) { + throw $exception; + } else { + $this->_exceptions[] = $exception; + return; + } + } + $subtitle = $dom->createElement('description'); + $root->appendChild($subtitle); + $text = $dom->createTextNode($this->getDataContainer()->getDescription()); + $subtitle->appendChild($text); + } + + /** + * Set date feed was last modified + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setDateModified(DOMDocument $dom, DOMElement $root) + { + if(!$this->getDataContainer()->getDateModified()) { + return; + } + + $updated = $dom->createElement('pubDate'); + $root->appendChild($updated); + $text = $dom->createTextNode( + $this->getDataContainer()->getDateModified()->get(Zend_Date::RSS) + ); + $updated->appendChild($text); + } + + /** + * Set feed generator string + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setGenerator(DOMDocument $dom, DOMElement $root) + { + if(!$this->getDataContainer()->getGenerator()) { + $this->getDataContainer()->setGenerator('Zend_Feed_Writer', + Zend_Version::VERSION, 'http://framework.zend.com'); + } + + $gdata = $this->getDataContainer()->getGenerator(); + $generator = $dom->createElement('generator'); + $root->appendChild($generator); + $name = $gdata['name']; + if (array_key_exists('version', $gdata)) { + $name .= ' ' . $gdata['version']; + } + if (array_key_exists('uri', $gdata)) { + $name .= ' (' . $gdata['uri'] . ')'; + } + $text = $dom->createTextNode($name); + $generator->appendChild($text); + } + + /** + * Set link to feed + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setLink(DOMDocument $dom, DOMElement $root) + { + $value = $this->getDataContainer()->getLink(); + if(!$value) { + // require_once 'Zend/Feed/Exception.php'; + $message = 'RSS 2.0 feed elements MUST contain exactly one' + . ' link element but one has not been set'; + $exception = new Zend_Feed_Exception($message); + if (!$this->_ignoreExceptions) { + throw $exception; + } else { + $this->_exceptions[] = $exception; + return; + } + } + $link = $dom->createElement('link'); + $root->appendChild($link); + $text = $dom->createTextNode($value); + $link->appendChild($text); + if (!Zend_Uri::check($value)) { + $link->setAttribute('isPermaLink', 'false'); + } + } + + /** + * Set feed authors + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setAuthors(DOMDocument $dom, DOMElement $root) + { + $authors = $this->getDataContainer()->getAuthors(); + if (!$authors || empty($authors)) { + return; + } + foreach ($authors as $data) { + $author = $this->_dom->createElement('author'); + $name = $data['name']; + if (array_key_exists('email', $data)) { + $name = $data['email'] . ' (' . $data['name'] . ')'; + } + $text = $dom->createTextNode($name); + $author->appendChild($text); + $root->appendChild($author); + } + } + + /** + * Set feed copyright + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setCopyright(DOMDocument $dom, DOMElement $root) + { + $copyright = $this->getDataContainer()->getCopyright(); + if (!$copyright) { + return; + } + $copy = $dom->createElement('copyright'); + $root->appendChild($copy); + $text = $dom->createTextNode($copyright); + $copy->appendChild($text); + } + + /** + * Set feed channel image + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setImage(DOMDocument $dom, DOMElement $root) + { + $image = $this->getDataContainer()->getImage(); + if (!$image) { + return; + } + if (!isset($image['title']) || empty($image['title']) + || !is_string($image['title'])) { + // require_once 'Zend/Feed/Exception.php'; + $message = 'RSS 2.0 feed images must include a title'; + $exception = new Zend_Feed_Exception($message); + if (!$this->_ignoreExceptions) { + throw $exception; + } else { + $this->_exceptions[] = $exception; + return; + } + } + if (empty($image['link']) || !is_string($image['link']) + || !Zend_Uri::check($image['link'])) { + // require_once 'Zend/Feed/Exception.php'; + $message = 'Invalid parameter: parameter \'link\'' + . ' must be a non-empty string and valid URI/IRI'; + $exception = new Zend_Feed_Exception($message); + if (!$this->_ignoreExceptions) { + throw $exception; + } else { + $this->_exceptions[] = $exception; + return; + } + } + $img = $dom->createElement('image'); + $root->appendChild($img); + $url = $dom->createElement('url'); + $text = $dom->createTextNode($image['uri']); + $url->appendChild($text); + $title = $dom->createElement('title'); + $text = $dom->createTextNode($image['title']); + $title->appendChild($text); + $link = $dom->createElement('link'); + $text = $dom->createTextNode($image['link']); + $link->appendChild($text); + $img->appendChild($url); + $img->appendChild($title); + $img->appendChild($link); + if (isset($image['height'])) { + if (!ctype_digit((string) $image['height']) || $image['height'] > 400) { + // require_once 'Zend/Feed/Exception.php'; + $message = 'Invalid parameter: parameter \'height\'' + . ' must be an integer not exceeding 400'; + $exception = new Zend_Feed_Exception($message); + if (!$this->_ignoreExceptions) { + throw $exception; + } else { + $this->_exceptions[] = $exception; + return; + } + } + $height = $dom->createElement('height'); + $text = $dom->createTextNode($image['height']); + $height->appendChild($text); + $img->appendChild($height); + } + if (isset($image['width'])) { + if (!ctype_digit((string) $image['width']) || $image['width'] > 144) { + // require_once 'Zend/Feed/Exception.php'; + $message = 'Invalid parameter: parameter \'width\'' + . ' must be an integer not exceeding 144'; + $exception = new Zend_Feed_Exception($message); + if (!$this->_ignoreExceptions) { + throw $exception; + } else { + $this->_exceptions[] = $exception; + return; + } + } + $width = $dom->createElement('width'); + $text = $dom->createTextNode($image['width']); + $width->appendChild($text); + $img->appendChild($width); + } + if (isset($image['description'])) { + if (empty($image['description']) || !is_string($image['description'])) { + // require_once 'Zend/Feed/Exception.php'; + $message = 'Invalid parameter: parameter \'description\'' + . ' must be a non-empty string'; + $exception = new Zend_Feed_Exception($message); + if (!$this->_ignoreExceptions) { + throw $exception; + } else { + $this->_exceptions[] = $exception; + return; + } + } + $desc = $dom->createElement('description'); + $text = $dom->createTextNode($image['description']); + $desc->appendChild($text); + $img->appendChild($desc); + } + } + + /** + * Set date feed was created + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setDateCreated(DOMDocument $dom, DOMElement $root) + { + if(!$this->getDataContainer()->getDateCreated()) { + return; + } + if(!$this->getDataContainer()->getDateModified()) { + $this->getDataContainer()->setDateModified( + $this->getDataContainer()->getDateCreated() + ); + } + } + + /** + * Set date feed last build date + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setLastBuildDate(DOMDocument $dom, DOMElement $root) + { + if(!$this->getDataContainer()->getLastBuildDate()) { + return; + } + + $lastBuildDate = $dom->createElement('lastBuildDate'); + $root->appendChild($lastBuildDate); + $text = $dom->createTextNode( + $this->getDataContainer()->getLastBuildDate()->get(Zend_Date::RSS) + ); + $lastBuildDate->appendChild($text); + } + + /** + * Set base URL to feed links + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setBaseUrl(DOMDocument $dom, DOMElement $root) + { + $baseUrl = $this->getDataContainer()->getBaseUrl(); + if (!$baseUrl) { + return; + } + $root->setAttribute('xml:base', $baseUrl); + } + + /** + * Set feed categories + * + * @param DOMDocument $dom + * @param DOMElement $root + * @return void + */ + protected function _setCategories(DOMDocument $dom, DOMElement $root) + { + $categories = $this->getDataContainer()->getCategories(); + if (!$categories) { + return; + } + foreach ($categories as $cat) { + $category = $dom->createElement('category'); + if (isset($cat['scheme'])) { + $category->setAttribute('domain', $cat['scheme']); + } + $text = $dom->createTextNode($cat['term']); + $category->appendChild($text); + $root->appendChild($category); + } + } +} diff --git a/libs/Zend/Feed/Writer/Renderer/RendererAbstract.php b/libs/Zend/Feed/Writer/Renderer/RendererAbstract.php new file mode 100644 index 0000000000..b3457ed643 --- /dev/null +++ b/libs/Zend/Feed/Writer/Renderer/RendererAbstract.php @@ -0,0 +1,250 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: RendererAbstract.php 20096 2010-01-06 02:05:09Z bkarwin $ + */ + +/** @see Zend_Feed_Writer */ +// require_once 'Zend/Feed/Writer.php'; + +/** @see Zend_Version */ +// require_once 'Zend/Version.php'; + +/** + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Writer_Renderer_RendererAbstract +{ + /** + * Extensions + * @var array + */ + protected $_extensions = array(); + + /** + * @var mixed + */ + protected $_container = null; + + /** + * @var DOMDocument + */ + protected $_dom = null; + + /** + * @var bool + */ + protected $_ignoreExceptions = false; + + /** + * @var array + */ + protected $_exceptions = array(); + + /** + * Encoding of all text values + * + * @var string + */ + protected $_encoding = 'UTF-8'; + + /** + * Holds the value "atom" or "rss" depending on the feed type set when + * when last exported. + * + * @var string + */ + protected $_type = null; + + /** + * @var DOMElement + */ + protected $_rootElement = null; + + /** + * Constructor + * + * @param mixed $container + * @return void + */ + public function __construct($container) + { + $this->_container = $container; + $this->setType($container->getType()); + $this->_loadExtensions(); + } + + /** + * Save XML to string + * + * @return string + */ + public function saveXml() + { + return $this->getDomDocument()->saveXml(); + } + + /** + * Get DOM document + * + * @return DOMDocument + */ + public function getDomDocument() + { + return $this->_dom; + } + + /** + * Get document element from DOM + * + * @return DOMElement + */ + public function getElement() + { + return $this->getDomDocument()->documentElement; + } + + /** + * Get data container of items being rendered + * + * @return mixed + */ + public function getDataContainer() + { + return $this->_container; + } + + /** + * Set feed encoding + * + * @param string $enc + * @return Zend_Feed_Writer_Renderer_RendererAbstract + */ + public function setEncoding($enc) + { + $this->_encoding = $enc; + return $this; + } + + /** + * Get feed encoding + * + * @return string + */ + public function getEncoding() + { + return $this->_encoding; + } + + /** + * Indicate whether or not to ignore exceptions + * + * @param bool $bool + * @return Zend_Feed_Writer_Renderer_RendererAbstract + */ + public function ignoreExceptions($bool = true) + { + if (!is_bool($bool)) { + // require_once 'Zend/Feed/Exception.php'; + throw new Zend_Feed_Exception('Invalid parameter: $bool. Should be TRUE or FALSE (defaults to TRUE if null)'); + } + $this->_ignoreExceptions = $bool; + return $this; + } + + /** + * Get exception list + * + * @return array + */ + public function getExceptions() + { + return $this->_exceptions; + } + + /** + * Set the current feed type being exported to "rss" or "atom". This allows + * other objects to gracefully choose whether to execute or not, depending + * on their appropriateness for the current type, e.g. renderers. + * + * @param string $type + */ + public function setType($type) + { + $this->_type = $type; + } + + /** + * Retrieve the current or last feed type exported. + * + * @return string Value will be "rss" or "atom" + */ + public function getType() + { + return $this->_type; + } + + /** + * Sets the absolute root element for the XML feed being generated. This + * helps simplify the appending of namespace declarations, but also ensures + * namespaces are added to the root element - not scattered across the entire + * XML file - may assist namespace unsafe parsers and looks pretty ;). + * + * @param DOMElement $root + */ + public function setRootElement(DOMElement $root) + { + $this->_rootElement = $root; + } + + /** + * Retrieve the absolute root element for the XML feed being generated. + * + * @return DOMElement + */ + public function getRootElement() + { + return $this->_rootElement; + } + + /** + * Load extensions from Zend_Feed_Writer + * + * @return void + */ + protected function _loadExtensions() + { + Zend_Feed_Writer::registerCoreExtensions(); + $all = Zend_Feed_Writer::getExtensions(); + if (stripos(get_class($this), 'entry')) { + $exts = $all['entryRenderer']; + } else { + $exts = $all['feedRenderer']; + } + foreach ($exts as $extension) { + $className = Zend_Feed_Writer::getPluginLoader()->getClassName($extension); + $this->_extensions[$extension] = new $className( + $this->getDataContainer() + ); + $this->_extensions[$extension]->setEncoding($this->getEncoding()); + } + } +} diff --git a/libs/Zend/Feed/Writer/Renderer/RendererInterface.php b/libs/Zend/Feed/Writer/Renderer/RendererInterface.php new file mode 100644 index 0000000000..89b4294416 --- /dev/null +++ b/libs/Zend/Feed/Writer/Renderer/RendererInterface.php @@ -0,0 +1,111 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: RendererInterface.php 20096 2010-01-06 02:05:09Z bkarwin $ + */ + +/** + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +interface Zend_Feed_Writer_Renderer_RendererInterface +{ + /** + * Render feed/entry + * + * @return void + */ + public function render(); + + /** + * Save feed and/or entry to XML and return string + * + * @return string + */ + public function saveXml(); + + /** + * Get DOM document + * + * @return DOMDocument + */ + public function getDomDocument(); + + /** + * Get document element from DOM + * + * @return DOMElement + */ + public function getElement(); + + /** + * Get data container containing feed items + * + * @return mixed + */ + public function getDataContainer(); + + /** + * Should exceptions be ignored? + * + * @return mixed + */ + public function ignoreExceptions(); + + /** + * Get list of thrown exceptions + * + * @return array + */ + public function getExceptions(); + + /** + * Set the current feed type being exported to "rss" or "atom". This allows + * other objects to gracefully choose whether to execute or not, depending + * on their appropriateness for the current type, e.g. renderers. + * + * @param string $type + */ + public function setType($type); + + /** + * Retrieve the current or last feed type exported. + * + * @return string Value will be "rss" or "atom" + */ + public function getType(); + + /** + * Sets the absolute root element for the XML feed being generated. This + * helps simplify the appending of namespace declarations, but also ensures + * namespaces are added to the root element - not scattered across the entire + * XML file - may assist namespace unsafe parsers and looks pretty ;). + * + * @param DOMElement $root + */ + public function setRootElement(DOMElement $root); + + /** + * Retrieve the absolute root element for the XML feed being generated. + * + * @return DOMElement + */ + public function getRootElement(); +} diff --git a/libs/Zend/Feed/Writer/Source.php b/libs/Zend/Feed/Writer/Source.php new file mode 100644 index 0000000000..3861fc77fc --- /dev/null +++ b/libs/Zend/Feed/Writer/Source.php @@ -0,0 +1,33 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Feed.php 20096 2010-01-06 02:05:09Z bkarwin $ + */ + +// require_once 'Zend/Feed/Writer/Feed/FeedAbstract.php'; + + /** + * @category Zend + * @package Zend_Feed_Writer + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Feed_Writer_Source extends Zend_Feed_Writer_Feed_FeedAbstract +{ + +} |