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