1 | <?php |
||
5 | class Crss { |
||
6 | |||
7 | private $table = 'RSSFeed'; |
||
8 | private $rssFile; |
||
9 | private $valid = false; |
||
10 | private $dbOptions = []; |
||
11 | private $dbStructure; |
||
12 | private $db; |
||
13 | private $newsCount; |
||
14 | private $feedDescription; |
||
15 | private $sendHeader; |
||
16 | /** |
||
17 | * Initiates the class, takes parameters as input but should work with standard settings. |
||
18 | * Connects to the DB and makes sure the table exists. |
||
19 | * @param $params is the input to adjust standard settings. I recommend to change only the 'feedDescription' part. |
||
20 | */ |
||
21 | 3 | public function __construct($params = []) |
|
22 | { |
||
23 | 3 | date_default_timezone_set('Europe/Stockholm'); |
|
24 | $options = [ |
||
25 | 3 | 'rssFile' => REALPATH(__DIR__) . '/rsscache/rss.xml', |
|
26 | 3 | 'table' => $this->table, |
|
27 | 3 | 'newsCount' => 5, |
|
28 | 3 | 'sendHeader' => true, |
|
29 | 'db' => [ |
||
30 | 3 | 'dsn' => 'sqlite:' . REALPATH(__DIR__) . '/src.sqlite', |
|
31 | 3 | 'username' => null, |
|
32 | 3 | 'password' => null, |
|
33 | 3 | 'driver_options' => null, |
|
34 | 'debug' => false |
||
35 | 3 | ], |
|
36 | 'feedDescription' => [ |
||
37 | 3 | 'title' => 'CRSS easy feed', |
|
38 | 3 | 'link' => 'http://www.github.com', |
|
39 | 'description' => 'Description of the amazing feed.' |
||
40 | 3 | ] |
|
41 | 3 | ]; |
|
42 | |||
43 | 3 | foreach ($params as $key => $value) { |
|
44 | 3 | if (is_array($value)) { |
|
45 | 1 | foreach ($value as $subKey => $subValue) { |
|
46 | 1 | $options[$key][$subKey] = $subValue; |
|
47 | 1 | } |
|
48 | 1 | } else { |
|
49 | 2 | $options[$key] = $value; |
|
50 | } |
||
51 | 3 | } |
|
52 | |||
53 | 3 | $this->rssFile = $options['rssFile']; |
|
54 | 3 | $this->table = $options['table']; |
|
55 | 3 | $this->dbOptions = $options['db']; |
|
56 | 3 | $this->newsCount = $options['newsCount']; |
|
57 | 3 | $this->feedDescription = $options['feedDescription']; |
|
58 | 3 | $this->sendHeader = $options['sendHeader']; |
|
59 | |||
60 | 3 | $this->dbStructure = 'CREATE TABLE IF NOT EXISTS ' . $this->table . ' ( |
|
61 | ID INTEGER PRIMARY KEY NOT NULL, |
||
62 | TITLE CHAR(50) NOT NULL, |
||
63 | LINK CHAR(50) NOT NULL, |
||
64 | DESCRIPTION CHAR(255) NOT NULL, |
||
65 | CREATED DATETIME |
||
66 | 3 | )'; |
|
67 | |||
68 | 3 | $this->connect(); |
|
69 | 2 | $this->createDB(); |
|
70 | 2 | } |
|
71 | |||
72 | /** |
||
73 | * Function to clear the whole database from rss input |
||
74 | * |
||
75 | * @return void |
||
76 | */ |
||
77 | 1 | public function clearRSS() |
|
82 | |||
83 | /** |
||
84 | * Internal function for connecting to the database |
||
85 | * |
||
86 | * @return void |
||
87 | */ |
||
88 | 3 | private function connect() |
|
89 | { |
||
90 | try { |
||
91 | 3 | $this->db = new \PDO( |
|
92 | 3 | $this->dbOptions['dsn'], |
|
93 | 3 | $this->dbOptions['username'], |
|
94 | 3 | $this->dbOptions['password'], |
|
95 | 3 | $this->dbOptions['driver_options'] |
|
96 | 3 | ); |
|
97 | |||
98 | 3 | } catch (\Exception $e) { |
|
99 | //Change to true to debug database connection |
||
100 | 1 | if ($this->dbOptions['debug']) { |
|
101 | // For debug purpose, shows all connection details |
||
102 | 1 | throw $e; |
|
103 | } else { |
||
104 | // Hide connection details. |
||
105 | throw new \PDOException("Could not connect to database, hiding connection details."); |
||
106 | } |
||
107 | } |
||
108 | 2 | $this->db->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_OBJ); |
|
109 | 2 | } |
|
110 | |||
111 | 2 | public function createDB() { |
|
115 | |||
116 | /** |
||
117 | * Compares RSS file created timestamp and database timestamp to judge if new RSS file is needed |
||
118 | * |
||
119 | * Sets internal variable $this->valid to true/false depending if new file needs to be generate |
||
120 | * @return void |
||
121 | */ |
||
122 | 2 | private function checkValidity() |
|
123 | { |
||
124 | |||
125 | 2 | if (!is_writable($this->rssFile)) { |
|
126 | 1 | $this->valid = false; |
|
127 | 1 | return; |
|
128 | } |
||
129 | |||
130 | 1 | $stmt = $this->db->prepare('SELECT CREATED FROM ' . $this->table . ' ORDER BY CREATED DESC LIMIT 1'); |
|
131 | 1 | $stmt->execute(); |
|
132 | 1 | $res = $stmt->fetchAll(); |
|
133 | |||
134 | 1 | if (count($res) == 0) { |
|
135 | $this->valid = false; |
||
136 | return; |
||
137 | } |
||
138 | |||
139 | 1 | $latestInput = strtotime($res[0]->CREATED); |
|
140 | |||
141 | 1 | $rssCreated = filemtime($this->rssFile); |
|
142 | |||
143 | 1 | if ($latestInput > $rssCreated) { |
|
144 | $this->valid = false; |
||
145 | } else { |
||
146 | 1 | $this->valid = true; |
|
147 | } |
||
148 | 1 | } |
|
149 | |||
150 | /** |
||
151 | * Creates a new RSS File with information from the database. Max amount of news is configured in the initiation. |
||
152 | * |
||
153 | * @return void |
||
154 | */ |
||
155 | 1 | private function createRSS() |
|
156 | { |
||
157 | 1 | $file = fopen($this->rssFile, "w+"); |
|
158 | |||
159 | 1 | $stmt = $this->db->prepare('SELECT * FROM ' . $this->table . ' ORDER BY CREATED DESC LIMIT ?'); |
|
160 | 1 | $stmt->execute([$this->newsCount]); |
|
161 | 1 | $res = $stmt->fetchAll(); |
|
162 | |||
163 | 1 | $xmlVersion = '<?xml version="1.0" encoding="UTF-8" ?>'; |
|
164 | |||
165 | $startString = <<<EOD |
||
166 | 1 | {$xmlVersion} |
|
167 | <rss version="2.0"> |
||
168 | <channel> |
||
169 | 1 | <title>{$this->feedDescription['title']}</title> |
|
170 | 1 | <link>{$this->feedDescription['link']}</link> |
|
171 | 1 | <description>{$this->feedDescription['description']}</description> |
|
172 | 1 | EOD; |
|
173 | 1 | fwrite($file, $startString); |
|
174 | |||
175 | 1 | foreach ($res as $post) { |
|
176 | 1 | $date = date("D, d M y H:i:s O", strtotime($post->CREATED)); |
|
177 | $string = <<<EOD |
||
178 | |||
179 | <item> |
||
180 | 1 | <title>{$post->TITLE}</title> |
|
181 | 1 | <link>{$post->LINK}</link> |
|
182 | 1 | <description>{$post->DESCRIPTION}</description> |
|
183 | 1 | <pubDate>{$date}</pubDate> |
|
184 | 1 | </item> |
|
185 | 1 | EOD; |
|
186 | 1 | fwrite($file, $string); |
|
187 | 1 | } |
|
188 | |||
189 | 1 | fwrite($file, ' |
|
190 | </channel> |
||
191 | 1 | </rss>'); |
|
192 | 1 | } |
|
193 | |||
194 | /** |
||
195 | * Function that should be called to receive the RSS feed. |
||
196 | * Checks if the latest RSS File is up to date, if not, generates a new one. |
||
197 | * @return void |
||
198 | */ |
||
199 | 2 | public function getRSS() |
|
200 | { |
||
201 | 2 | $this->checkValidity(); |
|
202 | |||
203 | 2 | if (!$this->valid) { |
|
204 | 1 | $this->createRSS(); |
|
205 | 1 | } |
|
206 | |||
207 | 2 | if ($this->sendHeader) { |
|
208 | header('Content-type: application/rss+xml; charset=UTF-8'); |
||
209 | } |
||
210 | |||
211 | 2 | readfile($this->rssFile); |
|
212 | 2 | } |
|
213 | |||
214 | /** |
||
215 | * Inserts information to RSS database |
||
216 | * @param $input should be an associative array with three pars TITLE, LINK, DESCRIPTION |
||
217 | * |
||
218 | * @return void |
||
219 | */ |
||
220 | 1 | public function insertRSS($input = []) |
|
225 | } |
||
226 |