PHP Universal Feed Generator
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

392 lines
10 KiB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
  1. <?php
  2. namespace FeedWriter;
  3. use \DateTime;
  4. use \FeedWriter\View\SyndicationBase;
  5. /*
  6. * Copyright (C) 2008 Anis uddin Ahmad <anisniit@gmail.com>
  7. * Copyright (C) 2010-2013 Michael Bemmerl <mail@mx-server.de>
  8. *
  9. * This file is part of the "Universal Feed Writer" project.
  10. *
  11. * This program is free software: you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License as published by
  13. * the Free Software Foundation, either version 3 of the License, or
  14. * (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  23. */
  24. /**
  25. * Universal Feed Writer
  26. *
  27. * Item class - Used as feed element in SyndicationBase class
  28. *
  29. * @package UniversalFeedWriter
  30. * @author Anis uddin Ahmad <anisniit@gmail.com>
  31. * @link http://www.ajaxray.com/projects/rss
  32. */
  33. class Item
  34. {
  35. /**
  36. * Collection of feed item elements
  37. */
  38. private $elements = array();
  39. /**
  40. * Contains the format of this feed.
  41. */
  42. private $version;
  43. /**
  44. * Is used as a suffix when multiple elements have the same name.
  45. **/
  46. private $_cpt = 0;
  47. /**
  48. * Constructor
  49. *
  50. * @param constant (RSS1/RSS2/ATOM) RSS2 is default.
  51. */
  52. function __construct($version = SyndicationBase::RSS2)
  53. {
  54. $this->version = $version;
  55. }
  56. /**
  57. * Return an unique number
  58. * @access private
  59. * @return int
  60. **/
  61. private function cpt() {
  62. return $this->_cpt++;
  63. }
  64. /**
  65. * Add an element to elements array
  66. *
  67. * @access public
  68. * @param string The tag name of an element
  69. * @param string The content of tag
  70. * @param array Attributes(if any) in 'attrName' => 'attrValue' format
  71. * @param boolean Specifies, if an already existing element is overwritten.
  72. * @return void
  73. */
  74. public function addElement($elementName, $content, $attributes = null, $overwrite = FALSE, $allowMultiple = FALSE)
  75. {
  76. $key = $elementName;
  77. // return if element already exists & if overwriting is disabled
  78. // & if multiple elements are not allowed.
  79. if (isset($this->elements[$elementName]) && !$overwrite) {
  80. if (!$allowMultiple)
  81. return;
  82. $key .= '-' . $this->cpt();
  83. }
  84. $this->elements[$key]['name'] = $elementName;
  85. $this->elements[$key]['content'] = $content;
  86. $this->elements[$key]['attributes'] = $attributes;
  87. return $this;
  88. }
  89. /**
  90. * Set multiple feed elements from an array.
  91. * Elements which have attributes cannot be added by this method
  92. *
  93. * @access public
  94. * @param array array of elements in 'tagName' => 'tagContent' format.
  95. * @return void
  96. */
  97. public function addElementArray($elementArray)
  98. {
  99. if (!is_array($elementArray))
  100. return;
  101. foreach ($elementArray as $elementName => $content)
  102. {
  103. $this->addElement($elementName, $content);
  104. }
  105. return $this;
  106. }
  107. /**
  108. * Return the collection of elements in this feed item
  109. *
  110. * @access public
  111. * @return array
  112. */
  113. public function getElements()
  114. {
  115. return $this->elements;
  116. }
  117. /**
  118. * Return the type of this feed item
  119. *
  120. * @access public
  121. * @return string The feed type, as defined in SyndicationBase.php
  122. */
  123. public function getVersion()
  124. {
  125. return $this->version;
  126. }
  127. // Wrapper functions ------------------------------------------------------
  128. /**
  129. * Set the 'description' element of feed item
  130. *
  131. * @access public
  132. * @param string The content of 'description' or 'summary' element
  133. * @return void
  134. */
  135. public function setDescription($description)
  136. {
  137. $tag = ($this->version == SyndicationBase::ATOM) ? 'summary' : 'description';
  138. return $this->addElement($tag, $description);
  139. }
  140. /**
  141. * Set the 'content' element of the feed item
  142. * For ATOM feeds only
  143. *
  144. * @access public
  145. * @param string Content for the item (i.e., the body of a blog post).
  146. * @return void
  147. */
  148. public function setContent($content)
  149. {
  150. if ($this->version != SyndicationBase::ATOM)
  151. throw new Exception('The content element is supported in ATOM feeds only.');
  152. return $this->addElement('content', $content, array('type' => 'html'));
  153. }
  154. /**
  155. * Set the 'title' element of feed item
  156. *
  157. * @access public
  158. * @param string The content of 'title' element
  159. * @return void
  160. */
  161. public function setTitle($title)
  162. {
  163. return $this->addElement('title', $title);
  164. }
  165. /**
  166. * Set the 'date' element of the feed item.
  167. *
  168. * The value of the date parameter can be either an instance of the
  169. * DateTime class, an integer containing a UNIX timestamp or a string
  170. * which is parseable by PHP's 'strtotime' function.
  171. *
  172. * @access public
  173. * @param DateTime|int|string Date which should be used.
  174. * @return void
  175. */
  176. public function setDate($date)
  177. {
  178. if(!is_numeric($date))
  179. {
  180. if ($date instanceof DateTime)
  181. $date = $date->getTimestamp();
  182. else
  183. {
  184. $date = strtotime($date);
  185. if ($date === FALSE)
  186. throw new Exception('The given date string was not parseable.');
  187. }
  188. }
  189. else if ($date < 0)
  190. throw new Exception('The given date is not an UNIX timestamp.');
  191. if($this->version == SyndicationBase::ATOM)
  192. {
  193. $tag = 'updated';
  194. $value = date(\DATE_ATOM, $date);
  195. }
  196. elseif($this->version == SyndicationBase::RSS2)
  197. {
  198. $tag = 'pubDate';
  199. $value = date(\DATE_RSS, $date);
  200. }
  201. else
  202. {
  203. $tag = 'dc:date';
  204. $value = date("Y-m-d", $date);
  205. }
  206. return $this->addElement($tag, $value);
  207. }
  208. /**
  209. * Set the 'link' element of feed item
  210. *
  211. * @access public
  212. * @param string The content of 'link' element
  213. * @return void
  214. */
  215. public function setLink($link)
  216. {
  217. if($this->version == SyndicationBase::RSS2 || $this->version == SyndicationBase::RSS1)
  218. {
  219. $this->addElement('link', $link);
  220. }
  221. else
  222. {
  223. $this->addElement('link','',array('href'=>$link));
  224. $this->addElement('id', SyndicationBase::uuid($link,'urn:uuid:'));
  225. }
  226. return $this;
  227. }
  228. /**
  229. * Attach a external media to the feed item.
  230. * Not supported in RSS 1.0 feeds.
  231. *
  232. * See RFC 4288 for syntactical correct MIME types.
  233. *
  234. * Note that you should avoid the use of more than one enclosure in one item,
  235. * since some RSS aggregators don't support it.
  236. *
  237. * @access public
  238. * @param string The URL of the media.
  239. * @param integer The length of the media.
  240. * @param string The MIME type attribute of the media.
  241. * @param boolean Specifies, if multiple enclosures are allowed
  242. * @return void
  243. * @link https://tools.ietf.org/html/rfc4288
  244. */
  245. public function addEnclosure($url, $length, $type, $multiple = TRUE)
  246. {
  247. if ($this->version == SyndicationBase::RSS1)
  248. throw new Exception('Media attachment is not supported in RSS1 feeds.');
  249. // the length parameter should be set to 0 if it can't be determined
  250. // see http://www.rssboard.org/rss-profile#element-channel-item-enclosure
  251. if (!is_numeric($length) || $length < 0)
  252. throw new Exception('The length parameter must be an integer and greater or equals to zero.');
  253. // Regex used from RFC 4287, page 41
  254. if (!is_string($type) || preg_match('/.+\/.+/', $type) != 1)
  255. throw new Exception('type parameter must be a string and a MIME type.');
  256. $attributes = array('length' => $length, 'type' => $type);
  257. if ($this->version == SyndicationBase::RSS2)
  258. {
  259. $attributes['url'] = $url;
  260. $this->addElement('enclosure', '', $attributes, FALSE, $multiple);
  261. }
  262. else
  263. {
  264. $attributes['href'] = $url;
  265. $attributes['rel'] = 'enclosure';
  266. $this->addElement('atom:link', '', $attributes, FALSE, $multiple);
  267. }
  268. return $this;
  269. }
  270. /**
  271. * Alias of addEnclosure, for backward compatibility. Using only this
  272. * method ensure that the 'enclosure' element will be present only once.
  273. *
  274. * @access public
  275. * @param string The URL of the media.
  276. * @param integer The length of the media.
  277. * @param string The MIME type attribute of the media.
  278. * @return void
  279. * @link https://tools.ietf.org/html/rfc4288
  280. *
  281. **/
  282. public function setEnclosure($url, $length, $type) {
  283. return $this->addEnclosure($url, $length, $type, false);
  284. }
  285. /**
  286. * Set the 'author' element of feed item.
  287. * Not supported in RSS 1.0 feeds.
  288. *
  289. * @access public
  290. * @param string The author of this item
  291. * @param string Optional email address of the author
  292. * @param string Optional URI related to the author
  293. * @return void
  294. */
  295. public function setAuthor($author, $email = null, $uri = null)
  296. {
  297. switch($this->version)
  298. {
  299. case SyndicationBase::RSS1: throw new Exception('The author element is not supported in RSS1 feeds.');
  300. break;
  301. case SyndicationBase::RSS2:
  302. if ($email != null)
  303. $author = $email . ' (' . $author . ')';
  304. $this->addElement('author', $author);
  305. break;
  306. case SyndicationBase::ATOM:
  307. $elements = array('name' => $author);
  308. // Regex from RFC 4287 page 41
  309. if ($email != null && preg_match('/.+@.+/', $email) == 1)
  310. $elements['email'] = $email;
  311. if ($uri != null)
  312. $elements['uri'] = $uri;
  313. $this->addElement('author', $elements);
  314. break;
  315. }
  316. return $this;
  317. }
  318. /**
  319. * Set the unique identifier of the feed item
  320. *
  321. * @access public
  322. * @param string The unique identifier of this item
  323. * @param boolean The value of the 'isPermaLink' attribute in RSS 2 feeds.
  324. * @return void
  325. */
  326. public function setId($id, $permaLink = false)
  327. {
  328. if ($this->version == SyndicationBase::RSS2)
  329. {
  330. if (!is_bool($permaLink))
  331. throw new Exception('The permaLink parameter must be boolean.');
  332. $permaLink = $permaLink ? 'true' : 'false';
  333. $this->addElement('guid', $id, array('isPermaLink' => $permaLink));
  334. }
  335. else if ($this->version == SyndicationBase::ATOM)
  336. {
  337. $this->addElement('id', SyndicationBase::uuid($id,'urn:uuid:'), NULL, TRUE);
  338. }
  339. else
  340. throw new Exception('A unique ID is not supported in RSS1 feeds.');
  341. return $this;
  342. }
  343. } // end of class Item