1<?php 2/** 3 * Matomo - free/libre analytics platform 4 * 5 * @link https://matomo.org 6 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later 7 * 8 */ 9namespace Piwik\DataTable\Renderer; 10 11use Exception; 12use Piwik\Archive; 13use Piwik\Common; 14use Piwik\DataTable\Renderer; 15use Piwik\DataTable; 16use Piwik\Date; 17use Piwik\SettingsPiwik; 18 19/** 20 * RSS Feed. 21 * The RSS renderer can be used only on Set that are arrays of DataTable. 22 * A RSS feed contains one dataTable per element in the Set. 23 * 24 */ 25class Rss extends Renderer 26{ 27 /** 28 * Computes the dataTable output and returns the string/binary 29 * 30 * @return string 31 */ 32 public function render() 33 { 34 return $this->renderTable($this->table); 35 } 36 37 /** 38 * Computes the output for the given data table 39 * 40 * @param DataTable $table 41 * @return string 42 * @throws Exception 43 */ 44 protected function renderTable($table) 45 { 46 if (!($table instanceof DataTable\Map) 47 || $table->getKeyName() != 'date' 48 ) { 49 throw new Exception("RSS feeds can be generated for one specific website &idSite=X." . 50 "\nPlease specify only one idSite or consider using &format=XML instead."); 51 } 52 53 $idSite = Common::getRequestVar('idSite', 1, 'int'); 54 $period = Common::getRequestVar('period'); 55 56 $piwikUrl = SettingsPiwik::getPiwikUrl() 57 . "?module=CoreHome&action=index&idSite=" . $idSite . "&period=" . $period; 58 $out = ""; 59 $moreRecentFirst = array_reverse($table->getDataTables(), true); 60 foreach ($moreRecentFirst as $date => $subtable) { 61 /** @var DataTable $subtable */ 62 $timestamp = $subtable->getMetadata(Archive\DataTableFactory::TABLE_METADATA_PERIOD_INDEX)->getDateStart()->getTimestamp(); 63 $site = $subtable->getMetadata(Archive\DataTableFactory::TABLE_METADATA_SITE_INDEX); 64 65 $pudDate = date('r', $timestamp); 66 67 $dateInSiteTimezone = Date::factory($timestamp); 68 if($site) { 69 $dateInSiteTimezone = $dateInSiteTimezone->setTimezone($site->getTimezone()); 70 } 71 $dateInSiteTimezone = $dateInSiteTimezone->toString('Y-m-d'); 72 $thisPiwikUrl = Common::sanitizeInputValue($piwikUrl . "&date=$dateInSiteTimezone"); 73 $siteName = $site ? $site->getName() : ''; 74 $title = $siteName . " on " . $date; 75 76 $out .= "\t<item> 77 <pubDate>$pudDate</pubDate> 78 <guid>$thisPiwikUrl</guid> 79 <link>$thisPiwikUrl</link> 80 <title>$title</title> 81 <author>https://matomo.org</author> 82 <description>"; 83 84 $out .= Common::sanitizeInputValue($this->renderDataTable($subtable)); 85 $out .= "</description>\n\t</item>\n"; 86 } 87 88 $header = $this->getRssHeader(); 89 $footer = $this->getRssFooter(); 90 91 return $header . $out . $footer; 92 } 93 94 /** 95 * Returns the RSS file footer 96 * 97 * @return string 98 */ 99 protected function getRssFooter() 100 { 101 return "\t</channel>\n</rss>"; 102 } 103 104 /** 105 * Returns the RSS file header 106 * 107 * @return string 108 */ 109 protected function getRssHeader() 110 { 111 $generationDate = date('r', Date::getNowTimestamp()); 112 $header = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> 113<rss version=\"2.0\"> 114 <channel> 115 <title>matomo statistics - RSS</title> 116 <link>https://matomo.org</link> 117 <description>Matomo RSS feed</description> 118 <pubDate>$generationDate</pubDate> 119 <generator>matomo</generator> 120 <language>en</language> 121 <lastBuildDate>$generationDate</lastBuildDate>\n"; 122 return $header; 123 } 124 125 /** 126 * @param DataTable $table 127 * 128 * @return string 129 */ 130 protected function renderDataTable($table) 131 { 132 if ($table->getRowsCount() == 0) { 133 return "<strong><em>Empty table</em></strong><br />\n"; 134 } 135 136 $i = 1; 137 $tableStructure = array(); 138 139 /* 140 * table = array 141 * ROW1 = col1 | col2 | col3 | metadata | idSubTable 142 * ROW2 = col1 | col2 (no value but appears) | col3 | metadata | idSubTable 143 * subtable here 144 */ 145 $allColumns = array(); 146 foreach ($table->getRows() as $row) { 147 foreach ($row->getColumns() as $column => $value) { 148 // for example, goals data is array: not supported in export RSS 149 // in the future we shall reuse ViewDataTable for html exports in RSS anyway 150 if (is_array($value) 151 || is_object($value) 152 ) { 153 continue; 154 } 155 $allColumns[$column] = true; 156 $tableStructure[$i][$column] = $value; 157 } 158 $i++; 159 } 160 $html = "\n"; 161 $html .= "<table border=1 width=70%>"; 162 $html .= "\n<tr>"; 163 foreach ($allColumns as $name => $toDisplay) { 164 if ($toDisplay !== false) { 165 if ($this->translateColumnNames) { 166 $name = $this->translateColumnName($name); 167 } 168 $html .= "\n\t<td><strong>$name</strong></td>"; 169 } 170 } 171 $html .= "\n</tr>"; 172 173 foreach ($tableStructure as $row) { 174 $html .= "\n\n<tr>"; 175 foreach ($allColumns as $columnName => $toDisplay) { 176 if ($toDisplay !== false) { 177 $value = "-"; 178 if (isset($row[$columnName])) { 179 $value = urldecode($row[$columnName]); 180 } 181 182 $html .= "\n\t<td>$value</td>"; 183 } 184 } 185 $html .= "</tr>"; 186 } 187 $html .= "\n\n</table>"; 188 return $html; 189 } 190} 191