1 | <?php |
||||
2 | class Opml extends Handler_Protected { |
||||
3 | |||||
4 | public function csrf_ignore($method) { |
||||
5 | $csrf_ignored = array("export", "import"); |
||||
6 | |||||
7 | return array_search($method, $csrf_ignored) !== false; |
||||
8 | } |
||||
9 | |||||
10 | public function export() { |
||||
11 | $output_name = "tt-rss_".date("Y-m-d").".opml"; |
||||
12 | $include_settings = $_REQUEST["include_settings"] == "1"; |
||||
13 | $owner_uid = $_SESSION["uid"]; |
||||
14 | |||||
15 | $rc = $this->opml_export($output_name, $owner_uid, false, $include_settings); |
||||
16 | |||||
17 | return $rc; |
||||
18 | } |
||||
19 | |||||
20 | public function import() { |
||||
21 | $owner_uid = $_SESSION["uid"]; |
||||
22 | |||||
23 | header('Content-Type: text/html; charset=utf-8'); |
||||
24 | |||||
25 | print "<html> |
||||
26 | <head> |
||||
27 | ".stylesheet_tag("css/default.css")." |
||||
0 ignored issues
–
show
|
|||||
28 | <title>".__("OPML Utility")."</title> |
||||
29 | <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/> |
||||
30 | </head> |
||||
31 | <body class='claro ttrss_utility'> |
||||
32 | <h1>".__('OPML Utility')."</h1><div class='content'>"; |
||||
33 | |||||
34 | Feeds::add_feed_category("Imported feeds"); |
||||
35 | |||||
36 | $this->opml_notice(__("Importing OPML...")); |
||||
37 | |||||
38 | $this->opml_import($owner_uid); |
||||
39 | |||||
40 | print "<br><form method=\"GET\" action=\"prefs.php\"> |
||||
41 | <input type=\"submit\" value=\"".__("Return to preferences")."\"> |
||||
42 | </form>"; |
||||
43 | |||||
44 | print "</div></body></html>"; |
||||
45 | |||||
46 | |||||
47 | } |
||||
48 | |||||
49 | // Export |
||||
50 | |||||
51 | private function opml_export_category($owner_uid, $cat_id, $hide_private_feeds = false, $include_settings = true) { |
||||
52 | |||||
53 | $cat_id = (int) $cat_id; |
||||
54 | |||||
55 | if ($hide_private_feeds) { |
||||
56 | $hide_qpart = "(private IS false AND auth_login = '' AND auth_pass = '')"; |
||||
57 | } else { |
||||
58 | $hide_qpart = "true"; |
||||
59 | } |
||||
60 | |||||
61 | $out = ""; |
||||
62 | |||||
63 | $ttrss_specific_qpart = ""; |
||||
64 | |||||
65 | if ($cat_id) { |
||||
66 | $sth = $this->pdo->prepare("SELECT title,order_id |
||||
67 | FROM ttrss_feed_categories WHERE id = ? |
||||
68 | AND owner_uid = ?"); |
||||
69 | $sth->execute([$cat_id, $owner_uid]); |
||||
70 | $row = $sth->fetch(); |
||||
71 | $cat_title = htmlspecialchars($row['title']); |
||||
72 | |||||
73 | if ($include_settings) { |
||||
74 | $order_id = (int) $row["order_id"]; |
||||
75 | $ttrss_specific_qpart = "ttrssSortOrder=\"$order_id\""; |
||||
76 | } |
||||
77 | } else { |
||||
78 | $cat_title = ""; |
||||
79 | } |
||||
80 | |||||
81 | if ($cat_title) { |
||||
82 | $out .= "<outline text=\"$cat_title\" $ttrss_specific_qpart>\n"; |
||||
83 | } |
||||
84 | |||||
85 | $sth = $this->pdo->prepare("SELECT id,title |
||||
86 | FROM ttrss_feed_categories WHERE |
||||
87 | (parent_cat = :cat OR (:cat = 0 AND parent_cat IS NULL)) AND |
||||
88 | owner_uid = :uid ORDER BY order_id, title"); |
||||
89 | |||||
90 | $sth->execute([':cat' => $cat_id, ':uid' => $owner_uid]); |
||||
91 | |||||
92 | while ($line = $sth->fetch()) { |
||||
93 | $out .= $this->opml_export_category($owner_uid, $line["id"], $hide_private_feeds, $include_settings); |
||||
94 | } |
||||
95 | |||||
96 | $fsth = $this->pdo->prepare("select title, feed_url, site_url, update_interval, order_id |
||||
97 | FROM ttrss_feeds WHERE |
||||
98 | (cat_id = :cat OR (:cat = 0 AND cat_id IS NULL)) AND owner_uid = :uid AND $hide_qpart |
||||
99 | ORDER BY order_id, title"); |
||||
100 | |||||
101 | $fsth->execute([':cat' => $cat_id, ':uid' => $owner_uid]); |
||||
102 | |||||
103 | while ($fline = $fsth->fetch()) { |
||||
104 | $title = htmlspecialchars($fline["title"]); |
||||
105 | $url = htmlspecialchars($fline["feed_url"]); |
||||
106 | $site_url = htmlspecialchars($fline["site_url"]); |
||||
107 | |||||
108 | if ($include_settings) { |
||||
109 | $update_interval = (int) $fline["update_interval"]; |
||||
110 | $order_id = (int) $fline["order_id"]; |
||||
111 | |||||
112 | $ttrss_specific_qpart = "ttrssSortOrder=\"$order_id\" ttrssUpdateInterval=\"$update_interval\""; |
||||
113 | } else { |
||||
114 | $ttrss_specific_qpart = ""; |
||||
115 | } |
||||
116 | |||||
117 | if ($site_url) { |
||||
118 | $html_url_qpart = "htmlUrl=\"$site_url\""; |
||||
119 | } else { |
||||
120 | $html_url_qpart = ""; |
||||
121 | } |
||||
122 | |||||
123 | $out .= "<outline type=\"rss\" text=\"$title\" xmlUrl=\"$url\" $ttrss_specific_qpart $html_url_qpart/>\n"; |
||||
124 | } |
||||
125 | |||||
126 | if ($cat_title) { |
||||
127 | $out .= "</outline>\n"; |
||||
128 | } |
||||
129 | |||||
130 | return $out; |
||||
131 | } |
||||
132 | |||||
133 | public function opml_export($name, $owner_uid, $hide_private_feeds = false, $include_settings = true) { |
||||
134 | if (!$owner_uid) { |
||||
135 | return; |
||||
136 | } |
||||
137 | |||||
138 | if (!isset($_REQUEST["debug"])) { |
||||
139 | header("Content-type: application/xml+opml"); |
||||
140 | header("Content-Disposition: attachment; filename=".$name); |
||||
141 | } else { |
||||
142 | header("Content-type: text/xml"); |
||||
143 | } |
||||
144 | |||||
145 | $out = "<?xml version=\"1.0\" encoding=\"utf-8\"?".">"; |
||||
146 | |||||
147 | $out .= "<opml version=\"1.0\">"; |
||||
148 | $out .= "<head> |
||||
149 | <dateCreated>" . date("r", time())."</dateCreated> |
||||
150 | <title>Tiny Tiny RSS Feed Export</title> |
||||
151 | </head>"; |
||||
152 | $out .= "<body>"; |
||||
153 | |||||
154 | $out .= $this->opml_export_category($owner_uid, 0, $hide_private_feeds, $include_settings); |
||||
155 | |||||
156 | # export tt-rss settings |
||||
157 | |||||
158 | if ($include_settings) { |
||||
159 | $out .= "<outline text=\"tt-rss-prefs\" schema-version=\"".SCHEMA_VERSION."\">"; |
||||
160 | |||||
161 | $sth = $this->pdo->prepare("SELECT pref_name, value FROM ttrss_user_prefs WHERE |
||||
162 | profile IS NULL AND owner_uid = ? ORDER BY pref_name"); |
||||
163 | $sth->execute([$owner_uid]); |
||||
164 | |||||
165 | while ($line = $sth->fetch()) { |
||||
166 | $name = $line["pref_name"]; |
||||
167 | $value = htmlspecialchars($line["value"]); |
||||
168 | |||||
169 | $out .= "<outline pref-name=\"$name\" value=\"$value\"/>"; |
||||
170 | } |
||||
171 | |||||
172 | $out .= "</outline>"; |
||||
173 | |||||
174 | $out .= "<outline text=\"tt-rss-labels\" schema-version=\"".SCHEMA_VERSION."\">"; |
||||
175 | |||||
176 | $sth = $this->pdo->prepare("SELECT * FROM ttrss_labels2 WHERE |
||||
177 | owner_uid = ?"); |
||||
178 | $sth->execute([$owner_uid]); |
||||
179 | |||||
180 | while ($line = $sth->fetch()) { |
||||
181 | $name = htmlspecialchars($line['caption']); |
||||
182 | $fg_color = htmlspecialchars($line['fg_color']); |
||||
183 | $bg_color = htmlspecialchars($line['bg_color']); |
||||
184 | |||||
185 | $out .= "<outline label-name=\"$name\" label-fg-color=\"$fg_color\" label-bg-color=\"$bg_color\"/>"; |
||||
186 | |||||
187 | } |
||||
188 | |||||
189 | $out .= "</outline>"; |
||||
190 | |||||
191 | $out .= "<outline text=\"tt-rss-filters\" schema-version=\"".SCHEMA_VERSION."\">"; |
||||
192 | |||||
193 | $sth = $this->pdo->prepare("SELECT * FROM ttrss_filters2 |
||||
194 | WHERE owner_uid = ? ORDER BY id"); |
||||
195 | $sth->execute([$owner_uid]); |
||||
196 | |||||
197 | while ($line = $sth->fetch()) { |
||||
198 | $line["rules"] = array(); |
||||
199 | $line["actions"] = array(); |
||||
200 | |||||
201 | $tmph = $this->pdo->prepare("SELECT * FROM ttrss_filters2_rules |
||||
202 | WHERE filter_id = ?"); |
||||
203 | $tmph->execute([$line['id']]); |
||||
204 | |||||
205 | while ($tmp_line = $tmph->fetch(PDO::FETCH_ASSOC)) { |
||||
206 | unset($tmp_line["id"]); |
||||
207 | unset($tmp_line["filter_id"]); |
||||
208 | |||||
209 | $cat_filter = $tmp_line["cat_filter"]; |
||||
210 | |||||
211 | if (!$tmp_line["match_on"]) { |
||||
212 | if ($cat_filter && $tmp_line["cat_id"] || $tmp_line["feed_id"]) { |
||||
213 | $tmp_line["feed"] = Feeds::getFeedTitle( |
||||
214 | $cat_filter ? $tmp_line["cat_id"] : $tmp_line["feed_id"], |
||||
215 | $cat_filter); |
||||
216 | } else { |
||||
217 | $tmp_line["feed"] = ""; |
||||
218 | } |
||||
219 | } else { |
||||
220 | $match = []; |
||||
221 | foreach (json_decode($tmp_line["match_on"], true) as $feed_id) { |
||||
222 | |||||
223 | if (strpos($feed_id, "CAT:") === 0) { |
||||
224 | $feed_id = (int) substr($feed_id, 4); |
||||
225 | if ($feed_id) { |
||||
226 | array_push($match, [Feeds::getCategoryTitle($feed_id), true, false]); |
||||
227 | } else { |
||||
228 | array_push($match, [0, true, true]); |
||||
229 | } |
||||
230 | } else { |
||||
231 | if ($feed_id) { |
||||
232 | array_push($match, [Feeds::getFeedTitle((int) $feed_id), false, false]); |
||||
233 | } else { |
||||
234 | array_push($match, [0, false, true]); |
||||
235 | } |
||||
236 | } |
||||
237 | } |
||||
238 | |||||
239 | $tmp_line["match"] = $match; |
||||
240 | unset($tmp_line["match_on"]); |
||||
241 | } |
||||
242 | |||||
243 | unset($tmp_line["feed_id"]); |
||||
244 | unset($tmp_line["cat_id"]); |
||||
245 | |||||
246 | array_push($line["rules"], $tmp_line); |
||||
247 | } |
||||
248 | |||||
249 | $tmph = $this->pdo->prepare("SELECT * FROM ttrss_filters2_actions |
||||
250 | WHERE filter_id = ?"); |
||||
251 | $tmph->execute([$line['id']]); |
||||
252 | |||||
253 | while ($tmp_line = $tmph->fetch(PDO::FETCH_ASSOC)) { |
||||
254 | unset($tmp_line["id"]); |
||||
255 | unset($tmp_line["filter_id"]); |
||||
256 | |||||
257 | array_push($line["actions"], $tmp_line); |
||||
258 | } |
||||
259 | |||||
260 | unset($line["id"]); |
||||
261 | unset($line["owner_uid"]); |
||||
262 | $filter = json_encode($line); |
||||
263 | |||||
264 | $out .= "<outline filter-type=\"2\"><![CDATA[$filter]]></outline>"; |
||||
265 | |||||
266 | } |
||||
267 | |||||
268 | |||||
269 | $out .= "</outline>"; |
||||
270 | } |
||||
271 | |||||
272 | $out .= "</body></opml>"; |
||||
273 | |||||
274 | // Format output. |
||||
275 | $doc = new DOMDocument(); |
||||
276 | $doc->formatOutput = true; |
||||
277 | $doc->preserveWhiteSpace = false; |
||||
278 | $doc->loadXML($out); |
||||
279 | |||||
280 | $xpath = new DOMXpath($doc); |
||||
281 | $outlines = $xpath->query("//outline[@title]"); |
||||
282 | |||||
283 | // cleanup empty categories |
||||
284 | foreach ($outlines as $node) { |
||||
285 | if ($node->getElementsByTagName('outline')->length == 0) { |
||||
286 | $node->parentNode->removeChild($node); |
||||
287 | } |
||||
288 | } |
||||
289 | |||||
290 | $res = $doc->saveXML(); |
||||
291 | |||||
292 | /* // saveXML uses a two-space indent. Change to tabs. |
||||
293 | $res = preg_replace_callback('/^(?: )+/mu', |
||||
294 | create_function( |
||||
295 | '$matches', |
||||
296 | 'return str_repeat("\t", intval(strlen($matches[0])/2));'), |
||||
297 | $res); */ |
||||
298 | |||||
299 | print $res; |
||||
300 | } |
||||
301 | |||||
302 | // Import |
||||
303 | |||||
304 | private function opml_import_feed($node, $cat_id, $owner_uid) { |
||||
305 | $attrs = $node->attributes; |
||||
306 | |||||
307 | $feed_title = mb_substr($attrs->getNamedItem('text')->nodeValue, 0, 250); |
||||
308 | if (!$feed_title) { |
||||
309 | $feed_title = mb_substr($attrs->getNamedItem('title')->nodeValue, 0, 250); |
||||
310 | } |
||||
311 | |||||
312 | $feed_url = $attrs->getNamedItem('xmlUrl')->nodeValue; |
||||
313 | if (!$feed_url) { |
||||
314 | $feed_url = $attrs->getNamedItem('xmlURL')->nodeValue; |
||||
315 | } |
||||
316 | |||||
317 | $site_url = mb_substr($attrs->getNamedItem('htmlUrl')->nodeValue, 0, 250); |
||||
318 | |||||
319 | if ($feed_url) { |
||||
320 | $sth = $this->pdo->prepare("SELECT id FROM ttrss_feeds WHERE |
||||
321 | feed_url = ? AND owner_uid = ?"); |
||||
322 | $sth->execute([$feed_url, $owner_uid]); |
||||
323 | |||||
324 | if (!$feed_title) { |
||||
325 | $feed_title = '[Unknown]'; |
||||
326 | } |
||||
327 | |||||
328 | if (!$sth->fetch()) { |
||||
329 | #$this->opml_notice("[FEED] [$feed_title/$feed_url] dst_CAT=$cat_id"); |
||||
330 | $this->opml_notice(T_sprintf("Adding feed: %s", $feed_title == '[Unknown]' ? $feed_url : $feed_title)); |
||||
331 | |||||
332 | if (!$cat_id) { |
||||
333 | $cat_id = null; |
||||
334 | } |
||||
335 | |||||
336 | $update_interval = (int) $attrs->getNamedItem('ttrssUpdateInterval')->nodeValue; |
||||
337 | if (!$update_interval) { |
||||
338 | $update_interval = 0; |
||||
339 | } |
||||
340 | |||||
341 | $order_id = (int) $attrs->getNamedItem('ttrssSortOrder')->nodeValue; |
||||
342 | if (!$order_id) { |
||||
343 | $order_id = 0; |
||||
344 | } |
||||
345 | |||||
346 | $sth = $this->pdo->prepare("INSERT INTO ttrss_feeds |
||||
347 | (title, feed_url, owner_uid, cat_id, site_url, order_id, update_interval) VALUES |
||||
348 | (?, ?, ?, ?, ?, ?, ?)"); |
||||
349 | |||||
350 | $sth->execute([$feed_title, $feed_url, $owner_uid, $cat_id, $site_url, $order_id, $update_interval]); |
||||
351 | |||||
352 | } else { |
||||
353 | $this->opml_notice(T_sprintf("Duplicate feed: %s", $feed_title == '[Unknown]' ? $feed_url : $feed_title)); |
||||
354 | } |
||||
355 | } |
||||
356 | } |
||||
357 | |||||
358 | private function opml_import_label($node, $owner_uid) { |
||||
359 | $attrs = $node->attributes; |
||||
360 | $label_name = $attrs->getNamedItem('label-name')->nodeValue; |
||||
361 | |||||
362 | if ($label_name) { |
||||
363 | $fg_color = $attrs->getNamedItem('label-fg-color')->nodeValue; |
||||
364 | $bg_color = $attrs->getNamedItem('label-bg-color')->nodeValue; |
||||
365 | |||||
366 | if (!Labels::find_id($label_name, $_SESSION['uid'])) { |
||||
367 | $this->opml_notice(T_sprintf("Adding label %s", htmlspecialchars($label_name))); |
||||
368 | Labels::create($label_name, $fg_color, $bg_color, $owner_uid); |
||||
369 | } else { |
||||
370 | $this->opml_notice(T_sprintf("Duplicate label: %s", htmlspecialchars($label_name))); |
||||
371 | } |
||||
372 | } |
||||
373 | } |
||||
374 | |||||
375 | private function opml_import_preference($node) { |
||||
376 | $attrs = $node->attributes; |
||||
377 | $pref_name = $attrs->getNamedItem('pref-name')->nodeValue; |
||||
378 | |||||
379 | if ($pref_name) { |
||||
380 | $pref_value = $attrs->getNamedItem('value')->nodeValue; |
||||
381 | |||||
382 | $this->opml_notice(T_sprintf("Setting preference key %s to %s", |
||||
383 | $pref_name, $pref_value)); |
||||
384 | |||||
385 | set_pref($pref_name, $pref_value); |
||||
386 | } |
||||
387 | } |
||||
388 | |||||
389 | private function opml_import_filter($node) { |
||||
390 | $attrs = $node->attributes; |
||||
391 | |||||
392 | $filter_type = $attrs->getNamedItem('filter-type')->nodeValue; |
||||
393 | |||||
394 | if ($filter_type == '2') { |
||||
395 | $filter = json_decode($node->nodeValue, true); |
||||
396 | |||||
397 | if ($filter) { |
||||
398 | $match_any_rule = bool_to_sql_bool($filter["match_any_rule"]); |
||||
399 | $enabled = bool_to_sql_bool($filter["enabled"]); |
||||
400 | $inverse = bool_to_sql_bool($filter["inverse"]); |
||||
401 | $title = $filter["title"]; |
||||
402 | |||||
403 | //print "F: $title, $inverse, $enabled, $match_any_rule"; |
||||
404 | |||||
405 | $sth = $this->pdo->prepare("INSERT INTO ttrss_filters2 (match_any_rule,enabled,inverse,title,owner_uid) |
||||
406 | VALUES (?, ?, ?, ?, ?)"); |
||||
407 | |||||
408 | $sth->execute([$match_any_rule, $enabled, $inverse, $title, $_SESSION['uid']]); |
||||
409 | |||||
410 | $sth = $this->pdo->prepare("SELECT MAX(id) AS id FROM ttrss_filters2 WHERE |
||||
411 | owner_uid = ?"); |
||||
412 | $sth->execute([$_SESSION['uid']]); |
||||
413 | |||||
414 | $row = $sth->fetch(); |
||||
415 | $filter_id = $row['id']; |
||||
416 | |||||
417 | if ($filter_id) { |
||||
418 | $this->opml_notice(T_sprintf("Adding filter %s...", $title)); |
||||
419 | |||||
420 | foreach ($filter["rules"] as $rule) { |
||||
421 | $feed_id = null; |
||||
422 | $cat_id = null; |
||||
423 | |||||
424 | if ($rule["match"]) { |
||||
425 | |||||
426 | $match_on = []; |
||||
427 | |||||
428 | foreach ($rule["match"] as $match) { |
||||
429 | list ($name, $is_cat, $is_id) = $match; |
||||
430 | |||||
431 | if ($is_id) { |
||||
432 | array_push($match_on, ($is_cat ? "CAT:" : "").$name); |
||||
433 | } else { |
||||
434 | |||||
435 | if (!$is_cat) { |
||||
436 | $tsth = $this->pdo->prepare("SELECT id FROM ttrss_feeds |
||||
437 | WHERE title = ? AND owner_uid = ?"); |
||||
438 | |||||
439 | $tsth->execute([$name, $_SESSION['uid']]); |
||||
440 | |||||
441 | if ($row = $tsth->fetch()) { |
||||
442 | $match_id = $row['id']; |
||||
443 | |||||
444 | array_push($match_on, $match_id); |
||||
445 | } |
||||
446 | } else { |
||||
447 | $tsth = $this->pdo->prepare("SELECT id FROM ttrss_feed_categories |
||||
448 | WHERE title = ? AND owner_uid = ?"); |
||||
449 | $tsth->execute([$name, $_SESSION['uid']]); |
||||
450 | |||||
451 | if ($row = $tsth->fetch()) { |
||||
452 | $match_id = $row['id']; |
||||
453 | |||||
454 | array_push($match_on, "CAT:$match_id"); |
||||
455 | } |
||||
456 | } |
||||
457 | } |
||||
458 | } |
||||
459 | |||||
460 | $reg_exp = $rule["reg_exp"]; |
||||
461 | $filter_type = (int) $rule["filter_type"]; |
||||
462 | $inverse = bool_to_sql_bool($rule["inverse"]); |
||||
463 | $match_on = json_encode($match_on); |
||||
464 | |||||
465 | $usth = $this->pdo->prepare("INSERT INTO ttrss_filters2_rules |
||||
466 | (feed_id,cat_id,match_on,filter_id,filter_type,reg_exp,cat_filter,inverse) |
||||
467 | VALUES |
||||
468 | (NULL, NULL, ?, ?, ?, ?, false, ?)"); |
||||
469 | $usth->execute([$match_on, $filter_id, $filter_type, $reg_exp, $inverse]); |
||||
470 | |||||
471 | } else { |
||||
472 | |||||
473 | if (!$rule["cat_filter"]) { |
||||
474 | $tsth = $this->pdo->prepare("SELECT id FROM ttrss_feeds |
||||
475 | WHERE title = ? AND owner_uid = ?"); |
||||
476 | |||||
477 | $tsth->execute([$rule['feed'], $_SESSION['uid']]); |
||||
478 | |||||
479 | if ($row = $tsth->fetch()) { |
||||
480 | $feed_id = $row['id']; |
||||
481 | } |
||||
482 | } else { |
||||
483 | $tsth = $this->pdo->prepare("SELECT id FROM ttrss_feed_categories |
||||
484 | WHERE title = ? AND owner_uid = ?"); |
||||
485 | |||||
486 | $tsth->execute([$rule['feed'], $_SESSION['uid']]); |
||||
487 | |||||
488 | if ($row = $tsth->fetch()) { |
||||
489 | $feed_id = $row['id']; |
||||
490 | } |
||||
491 | } |
||||
492 | |||||
493 | $cat_filter = bool_to_sql_bool($rule["cat_filter"]); |
||||
494 | $reg_exp = $rule["reg_exp"]; |
||||
495 | $filter_type = (int) $rule["filter_type"]; |
||||
496 | $inverse = bool_to_sql_bool($rule["inverse"]); |
||||
497 | |||||
498 | $usth = $this->pdo->prepare("INSERT INTO ttrss_filters2_rules |
||||
499 | (feed_id,cat_id,filter_id,filter_type,reg_exp,cat_filter,inverse) |
||||
500 | VALUES |
||||
501 | (?, ?, ?, ?, ?, ?, ?)"); |
||||
502 | $usth->execute([$feed_id, $cat_id, $filter_id, $filter_type, $reg_exp, $cat_filter, $inverse]); |
||||
503 | } |
||||
504 | } |
||||
505 | |||||
506 | foreach ($filter["actions"] as $action) { |
||||
507 | |||||
508 | $action_id = (int) $action["action_id"]; |
||||
509 | $action_param = $action["action_param"]; |
||||
510 | |||||
511 | $usth = $this->pdo->prepare("INSERT INTO ttrss_filters2_actions |
||||
512 | (filter_id,action_id,action_param) |
||||
513 | VALUES |
||||
514 | (?, ?, ?)"); |
||||
515 | $usth->execute([$filter_id, $action_id, $action_param]); |
||||
516 | } |
||||
517 | } |
||||
518 | } |
||||
519 | } |
||||
520 | } |
||||
521 | |||||
522 | private function opml_import_category($doc, $root_node, $owner_uid, $parent_id) { |
||||
523 | $default_cat_id = (int) $this->get_feed_category('Imported feeds', false); |
||||
524 | |||||
525 | if ($root_node) { |
||||
526 | $cat_title = mb_substr($root_node->attributes->getNamedItem('text')->nodeValue, 0, 250); |
||||
527 | |||||
528 | if (!$cat_title) { |
||||
529 | $cat_title = mb_substr($root_node->attributes->getNamedItem('title')->nodeValue, 0, 250); |
||||
530 | } |
||||
531 | |||||
532 | if (!in_array($cat_title, array("tt-rss-filters", "tt-rss-labels", "tt-rss-prefs"))) { |
||||
533 | $cat_id = $this->get_feed_category($cat_title, $parent_id); |
||||
534 | |||||
535 | if ($cat_id === false) { |
||||
536 | $order_id = (int) $root_node->attributes->getNamedItem('ttrssSortOrder')->nodeValue; |
||||
537 | if (!$order_id) { |
||||
538 | $order_id = 0; |
||||
539 | } |
||||
540 | |||||
541 | Feeds::add_feed_category($cat_title, $parent_id, $order_id); |
||||
542 | $cat_id = $this->get_feed_category($cat_title, $parent_id); |
||||
543 | } |
||||
544 | |||||
545 | } else { |
||||
546 | $cat_id = 0; |
||||
547 | } |
||||
548 | |||||
549 | $outlines = $root_node->childNodes; |
||||
550 | |||||
551 | } else { |
||||
552 | $xpath = new DOMXpath($doc); |
||||
553 | $outlines = $xpath->query("//opml/body/outline"); |
||||
554 | |||||
555 | $cat_id = 0; |
||||
556 | } |
||||
557 | |||||
558 | #$this->opml_notice("[CAT] $cat_title id: $cat_id P_id: $parent_id"); |
||||
559 | $this->opml_notice(T_sprintf("Processing category: %s", $cat_title ? $cat_title : __("Uncategorized"))); |
||||
560 | |||||
561 | foreach ($outlines as $node) { |
||||
562 | if ($node->hasAttributes() && strtolower($node->tagName) == "outline") { |
||||
563 | $attrs = $node->attributes; |
||||
564 | $node_cat_title = $attrs->getNamedItem('text')->nodeValue; |
||||
565 | |||||
566 | if (!$node_cat_title) { |
||||
567 | $node_cat_title = $attrs->getNamedItem('title')->nodeValue; |
||||
568 | } |
||||
569 | |||||
570 | $node_feed_url = $attrs->getNamedItem('xmlUrl')->nodeValue; |
||||
571 | |||||
572 | if ($node_cat_title && !$node_feed_url) { |
||||
573 | $this->opml_import_category($doc, $node, $owner_uid, $cat_id); |
||||
574 | } else { |
||||
575 | |||||
576 | if (!$cat_id) { |
||||
577 | $dst_cat_id = $default_cat_id; |
||||
578 | } else { |
||||
579 | $dst_cat_id = $cat_id; |
||||
580 | } |
||||
581 | |||||
582 | switch ($cat_title) { |
||||
583 | case "tt-rss-prefs": |
||||
584 | $this->opml_import_preference($node); |
||||
585 | break; |
||||
586 | case "tt-rss-labels": |
||||
587 | $this->opml_import_label($node, $owner_uid); |
||||
588 | break; |
||||
589 | case "tt-rss-filters": |
||||
590 | $this->opml_import_filter($node); |
||||
591 | break; |
||||
592 | default: |
||||
593 | $this->opml_import_feed($node, $dst_cat_id, $owner_uid); |
||||
594 | } |
||||
595 | } |
||||
596 | } |
||||
597 | } |
||||
598 | } |
||||
599 | |||||
600 | public function opml_import($owner_uid) { |
||||
601 | if (!$owner_uid) { |
||||
602 | return; |
||||
603 | } |
||||
604 | |||||
605 | $doc = false; |
||||
606 | |||||
607 | if ($_FILES['opml_file']['error'] != 0) { |
||||
608 | print_error(T_sprintf("Upload failed with error code %d", |
||||
0 ignored issues
–
show
The function
print_error() has been deprecated: Use twig function errorMessage
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||
609 | $_FILES['opml_file']['error'])); |
||||
610 | return; |
||||
611 | } |
||||
612 | |||||
613 | if (is_uploaded_file($_FILES['opml_file']['tmp_name'])) { |
||||
614 | $tmp_file = tempnam(CACHE_DIR.'/upload', 'opml'); |
||||
615 | |||||
616 | $result = move_uploaded_file($_FILES['opml_file']['tmp_name'], |
||||
617 | $tmp_file); |
||||
618 | |||||
619 | if (!$result) { |
||||
620 | print_error(__("Unable to move uploaded file.")); |
||||
0 ignored issues
–
show
The function
print_error() has been deprecated: Use twig function errorMessage
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||
621 | return; |
||||
622 | } |
||||
623 | } else { |
||||
624 | print_error(__('Error: please upload OPML file.')); |
||||
0 ignored issues
–
show
The function
print_error() has been deprecated: Use twig function errorMessage
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||
625 | return; |
||||
626 | } |
||||
627 | |||||
628 | if (is_file($tmp_file)) { |
||||
629 | $doc = new DOMDocument(); |
||||
630 | libxml_disable_entity_loader(false); |
||||
631 | $doc->load($tmp_file); |
||||
632 | libxml_disable_entity_loader(true); |
||||
633 | unlink($tmp_file); |
||||
634 | } else if (!$doc) { |
||||
635 | print_error(__('Error: unable to find moved OPML file.')); |
||||
0 ignored issues
–
show
The function
print_error() has been deprecated: Use twig function errorMessage
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||
636 | return; |
||||
637 | } |
||||
638 | |||||
639 | if ($doc) { |
||||
640 | $this->pdo->beginTransaction(); |
||||
641 | $this->opml_import_category($doc, false, $owner_uid, false); |
||||
642 | $this->pdo->commit(); |
||||
643 | } else { |
||||
644 | print_error(__('Error while parsing document.')); |
||||
0 ignored issues
–
show
The function
print_error() has been deprecated: Use twig function errorMessage
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||
645 | } |
||||
646 | } |
||||
647 | |||||
648 | private function opml_notice($msg) { |
||||
649 | print "$msg<br/>"; |
||||
650 | } |
||||
651 | |||||
652 | public static function opml_publish_url() { |
||||
653 | |||||
654 | $url_path = get_self_url_prefix(); |
||||
655 | $url_path .= "/opml.php?op=publish&key=". |
||||
656 | Feeds::get_feed_access_key('OPML:Publish', false, $_SESSION["uid"]); |
||||
657 | |||||
658 | return $url_path; |
||||
659 | } |
||||
660 | |||||
661 | public function get_feed_category($feed_cat, $parent_cat_id = false) { |
||||
662 | |||||
663 | $parent_cat_id = (int) $parent_cat_id; |
||||
664 | |||||
665 | $sth = $this->pdo->prepare("SELECT id FROM ttrss_feed_categories |
||||
666 | WHERE title = :title |
||||
667 | AND (parent_cat = :parent OR (:parent = 0 AND parent_cat IS NULL)) |
||||
668 | AND owner_uid = :uid"); |
||||
669 | |||||
670 | $sth->execute([':title' => $feed_cat, ':parent' => $parent_cat_id, ':uid' => $_SESSION['uid']]); |
||||
671 | |||||
672 | if ($row = $sth->fetch()) { |
||||
673 | return $row['id']; |
||||
674 | } else { |
||||
675 | return false; |
||||
676 | } |
||||
677 | } |
||||
678 | |||||
679 | |||||
680 | } |
||||
681 |
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.