Feed.php 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. <?php defined('SYSPATH') OR die('No direct script access.');
  2. /**
  3. * RSS and Atom feed helper.
  4. *
  5. * @package Kohana
  6. * @category Helpers
  7. * @author Kohana Team
  8. * @copyright (c) 2007-2012 Kohana Team
  9. * @license http://kohanaframework.org/license
  10. */
  11. class Kohana_Feed {
  12. /**
  13. * Parses a remote feed into an array.
  14. *
  15. * @param string $feed remote feed URL
  16. * @param integer $limit item limit to fetch
  17. * @return array
  18. */
  19. public static function parse($feed, $limit = 0)
  20. {
  21. // Check if SimpleXML is installed
  22. if ( ! function_exists('simplexml_load_file'))
  23. throw new Kohana_Exception('SimpleXML must be installed!');
  24. // Make limit an integer
  25. $limit = (int) $limit;
  26. // Disable error reporting while opening the feed
  27. $error_level = error_reporting(0);
  28. // Allow loading by filename or raw XML string
  29. if (Valid::url($feed))
  30. {
  31. // Use native Request client to get remote contents
  32. $response = Request::factory($feed)->execute();
  33. $feed = $response->body();
  34. }
  35. elseif (is_file($feed))
  36. {
  37. // Get file contents
  38. $feed = file_get_contents($feed);
  39. }
  40. // Load the feed
  41. $feed = simplexml_load_string($feed, 'SimpleXMLElement', LIBXML_NOCDATA);
  42. // Restore error reporting
  43. error_reporting($error_level);
  44. // Feed could not be loaded
  45. if ($feed === FALSE)
  46. return array();
  47. $namespaces = $feed->getNamespaces(TRUE);
  48. // Detect the feed type. RSS 1.0/2.0 and Atom 1.0 are supported.
  49. $feed = isset($feed->channel) ? $feed->xpath('//item') : $feed->entry;
  50. $i = 0;
  51. $items = array();
  52. foreach ($feed as $item)
  53. {
  54. if ($limit > 0 AND $i++ === $limit)
  55. break;
  56. $item_fields = (array) $item;
  57. // get namespaced tags
  58. foreach ($namespaces as $ns)
  59. {
  60. $item_fields += (array) $item->children($ns);
  61. }
  62. $items[] = $item_fields;
  63. }
  64. return $items;
  65. }
  66. /**
  67. * Creates a feed from the given parameters.
  68. *
  69. * @param array $info feed information
  70. * @param array $items items to add to the feed
  71. * @param string $encoding define which encoding to use
  72. * @return string
  73. */
  74. public static function create($info, $items, $encoding = 'UTF-8')
  75. {
  76. $info += array('title' => 'Generated Feed', 'link' => '', 'generator' => 'KohanaPHP');
  77. $feed = '<?xml version="1.0" encoding="'.$encoding.'"?><rss version="2.0"><channel></channel></rss>';
  78. $feed = simplexml_load_string($feed);
  79. foreach ($info as $name => $value)
  80. {
  81. if ($name === 'image')
  82. {
  83. // Create an image element
  84. $image = $feed->channel->addChild('image');
  85. if ( ! isset($value['link'], $value['url'], $value['title']))
  86. {
  87. throw new Kohana_Exception('Feed images require a link, url, and title');
  88. }
  89. if (strpos($value['link'], '://') === FALSE)
  90. {
  91. // Convert URIs to URLs
  92. $value['link'] = URL::site($value['link'], 'http');
  93. }
  94. if (strpos($value['url'], '://') === FALSE)
  95. {
  96. // Convert URIs to URLs
  97. $value['url'] = URL::site($value['url'], 'http');
  98. }
  99. // Create the image elements
  100. $image->addChild('link', $value['link']);
  101. $image->addChild('url', $value['url']);
  102. $image->addChild('title', $value['title']);
  103. }
  104. else
  105. {
  106. if (($name === 'pubDate' OR $name === 'lastBuildDate') AND (is_int($value) OR ctype_digit($value)))
  107. {
  108. // Convert timestamps to RFC 822 formatted dates
  109. $value = date('r', $value);
  110. }
  111. elseif (($name === 'link' OR $name === 'docs') AND strpos($value, '://') === FALSE)
  112. {
  113. // Convert URIs to URLs
  114. $value = URL::site($value, 'http');
  115. }
  116. // Add the info to the channel
  117. $feed->channel->addChild($name, $value);
  118. }
  119. }
  120. foreach ($items as $item)
  121. {
  122. // Add the item to the channel
  123. $row = $feed->channel->addChild('item');
  124. foreach ($item as $name => $value)
  125. {
  126. if ($name === 'pubDate' AND (is_int($value) OR ctype_digit($value)))
  127. {
  128. // Convert timestamps to RFC 822 formatted dates
  129. $value = date('r', $value);
  130. }
  131. elseif (($name === 'link' OR $name === 'guid') AND strpos($value, '://') === FALSE)
  132. {
  133. // Convert URIs to URLs
  134. $value = URL::site($value, 'http');
  135. }
  136. // Add the info to the row
  137. $row->addChild($name, $value);
  138. }
  139. }
  140. if (function_exists('dom_import_simplexml'))
  141. {
  142. // Convert the feed object to a DOM object
  143. $feed = dom_import_simplexml($feed)->ownerDocument;
  144. // DOM generates more readable XML
  145. $feed->formatOutput = TRUE;
  146. // Export the document as XML
  147. $feed = $feed->saveXML();
  148. }
  149. else
  150. {
  151. // Export the document as XML
  152. $feed = $feed->asXML();
  153. }
  154. return $feed;
  155. }
  156. } // End Feed