Issues (1270)

classes/opml.php (1 issue)

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")."
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 call to print_error() has too many arguments starting with T_sprintf('Upload failed...['opml_file']['error']). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

608
            /** @scrutinizer ignore-call */ 
609
            print_error(T_sprintf("Upload failed with error code %d",

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
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."));
621
                return;
622
            }
623
        } else {
624
            print_error(__('Error: please upload OPML file.'));
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.'));
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.'));
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