codysnider /
tt-rss
| 1 | <?php |
||||
| 2 | class Handler_Public extends Handler { |
||||
| 3 | |||||
| 4 | private function generate_syndicated_feed($owner_uid, $feed, $is_cat, |
||||
| 5 | $limit, $offset, $search, |
||||
| 6 | $view_mode = false, $format = 'atom', $order = false, $orig_guid = false, $start_ts = false) { |
||||
| 7 | |||||
| 8 | require_once "lib/MiniTemplator.class.php"; |
||||
| 9 | |||||
| 10 | $note_style = "background-color : #fff7d5; |
||||
| 11 | border-width : 1px; ". |
||||
| 12 | "padding : 5px; border-style : dashed; border-color : #e7d796;". |
||||
| 13 | "margin-bottom : 1em; color : #9a8c59;"; |
||||
| 14 | |||||
| 15 | if (!$limit) { |
||||
| 16 | $limit = 60; |
||||
| 17 | } |
||||
| 18 | |||||
| 19 | $date_sort_field = "date_entered DESC, updated DESC"; |
||||
| 20 | |||||
| 21 | if ($feed == -2 && !$is_cat) { |
||||
| 22 | $date_sort_field = "last_published DESC"; |
||||
| 23 | } else if ($feed == -1 && !$is_cat) { |
||||
| 24 | $date_sort_field = "last_marked DESC"; |
||||
| 25 | } |
||||
| 26 | |||||
| 27 | switch ($order) { |
||||
| 28 | case "title": |
||||
| 29 | $date_sort_field = "ttrss_entries.title, date_entered, updated"; |
||||
| 30 | break; |
||||
| 31 | case "date_reverse": |
||||
| 32 | $date_sort_field = "date_entered, updated"; |
||||
| 33 | break; |
||||
| 34 | case "feed_dates": |
||||
| 35 | $date_sort_field = "updated DESC"; |
||||
| 36 | break; |
||||
| 37 | } |
||||
| 38 | |||||
| 39 | $params = array( |
||||
| 40 | "owner_uid" => $owner_uid, |
||||
| 41 | "feed" => $feed, |
||||
| 42 | "limit" => $limit, |
||||
| 43 | "view_mode" => $view_mode, |
||||
| 44 | "cat_view" => $is_cat, |
||||
| 45 | "search" => $search, |
||||
| 46 | "override_order" => $date_sort_field, |
||||
| 47 | "include_children" => true, |
||||
| 48 | "ignore_vfeed_group" => true, |
||||
| 49 | "offset" => $offset, |
||||
| 50 | "start_ts" => $start_ts |
||||
| 51 | ); |
||||
| 52 | |||||
| 53 | if (!$is_cat && is_numeric($feed) && $feed < PLUGIN_FEED_BASE_INDEX && $feed > LABEL_BASE_INDEX) { |
||||
| 54 | |||||
| 55 | $user_plugins = get_pref("_ENABLED_PLUGINS", $owner_uid); |
||||
| 56 | |||||
| 57 | $tmppluginhost = new PluginHost(); |
||||
| 58 | $tmppluginhost->load(PLUGINS, PluginHost::KIND_ALL); |
||||
| 59 | $tmppluginhost->load($user_plugins, PluginHost::KIND_USER, $owner_uid); |
||||
| 60 | $tmppluginhost->load_data(); |
||||
| 61 | |||||
| 62 | $handler = $tmppluginhost->get_feed_handler( |
||||
| 63 | PluginHost::feed_to_pfeed_id($feed)); |
||||
| 64 | |||||
| 65 | if ($handler) { |
||||
| 66 | $qfh_ret = $handler->get_headlines(PluginHost::feed_to_pfeed_id($feed), $params); |
||||
| 67 | } |
||||
| 68 | |||||
| 69 | } else { |
||||
| 70 | $qfh_ret = Feeds::queryFeedHeadlines($params); |
||||
| 71 | } |
||||
| 72 | |||||
| 73 | $result = $qfh_ret[0]; |
||||
| 74 | $feed_title = htmlspecialchars($qfh_ret[1]); |
||||
| 75 | $feed_site_url = $qfh_ret[2]; |
||||
| 76 | /* $last_error = $qfh_ret[3]; */ |
||||
| 77 | |||||
| 78 | $feed_self_url = get_self_url_prefix(). |
||||
| 79 | "/public.php?op=rss&id=$feed&key=". |
||||
| 80 | Feeds::get_feed_access_key($feed, false, $owner_uid); |
||||
| 81 | |||||
| 82 | if (!$feed_site_url) { |
||||
| 83 | $feed_site_url = get_self_url_prefix(); |
||||
| 84 | } |
||||
| 85 | |||||
| 86 | if ($format == 'atom') { |
||||
| 87 | $tpl = new MiniTemplator; |
||||
| 88 | |||||
| 89 | $tpl->readTemplateFromFile("templates/generated_feed.txt"); |
||||
| 90 | |||||
| 91 | $tpl->setVariable('FEED_TITLE', $feed_title, true); |
||||
| 92 | $tpl->setVariable('VERSION', get_version(), true); |
||||
| 93 | $tpl->setVariable('FEED_URL', htmlspecialchars($feed_self_url), true); |
||||
| 94 | |||||
| 95 | $tpl->setVariable('SELF_URL', htmlspecialchars(get_self_url_prefix()), true); |
||||
| 96 | while ($line = $result->fetch()) { |
||||
| 97 | |||||
| 98 | $line["content_preview"] = sanitize(truncate_string(strip_tags($line["content"]), 100, '...')); |
||||
| 99 | |||||
| 100 | foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_QUERY_HEADLINES) as $p) { |
||||
| 101 | $line = $p->hook_query_headlines($line); |
||||
| 102 | } |
||||
| 103 | |||||
| 104 | foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_ARTICLE_EXPORT_FEED) as $p) { |
||||
| 105 | $line = $p->hook_article_export_feed($line, $feed, $is_cat); |
||||
| 106 | } |
||||
| 107 | |||||
| 108 | $tpl->setVariable('ARTICLE_ID', |
||||
| 109 | htmlspecialchars($orig_guid ? $line['link'] : $this->make_article_tag_uri($line['id'], $line['date_entered'])), true); |
||||
| 110 | $tpl->setVariable('ARTICLE_LINK', htmlspecialchars($line['link']), true); |
||||
| 111 | $tpl->setVariable('ARTICLE_TITLE', htmlspecialchars($line['title']), true); |
||||
| 112 | $tpl->setVariable('ARTICLE_EXCERPT', $line["content_preview"], true); |
||||
| 113 | |||||
| 114 | $content = sanitize($line["content"], false, $owner_uid, |
||||
| 115 | $feed_site_url, false, $line["id"]); |
||||
| 116 | |||||
| 117 | if ($line['note']) { |
||||
| 118 | $content = "<div style=\"$note_style\">Article note: ".$line['note']."</div>". |
||||
| 119 | $content; |
||||
| 120 | $tpl->setVariable('ARTICLE_NOTE', htmlspecialchars($line['note']), true); |
||||
| 121 | } |
||||
| 122 | |||||
| 123 | $tpl->setVariable('ARTICLE_CONTENT', $content, true); |
||||
| 124 | |||||
| 125 | $tpl->setVariable('ARTICLE_UPDATED_ATOM', |
||||
| 126 | date('c', strtotime($line["updated"])), true); |
||||
| 127 | $tpl->setVariable('ARTICLE_UPDATED_RFC822', |
||||
| 128 | date(DATE_RFC822, strtotime($line["updated"])), true); |
||||
| 129 | |||||
| 130 | $tpl->setVariable('ARTICLE_AUTHOR', htmlspecialchars($line['author']), true); |
||||
| 131 | |||||
| 132 | $tpl->setVariable('ARTICLE_SOURCE_LINK', htmlspecialchars($line['site_url'] ? $line["site_url"] : get_self_url_prefix()), true); |
||||
| 133 | $tpl->setVariable('ARTICLE_SOURCE_TITLE', htmlspecialchars($line['feed_title'] ? $line['feed_title'] : $feed_title), true); |
||||
| 134 | |||||
| 135 | $tags = Article::get_article_tags($line["id"], $owner_uid); |
||||
| 136 | |||||
| 137 | foreach ($tags as $tag) { |
||||
| 138 | $tpl->setVariable('ARTICLE_CATEGORY', htmlspecialchars($tag), true); |
||||
| 139 | $tpl->addBlock('category'); |
||||
| 140 | } |
||||
| 141 | |||||
| 142 | $enclosures = Article::get_article_enclosures($line["id"]); |
||||
| 143 | |||||
| 144 | if (count($enclosures) > 0) { |
||||
| 145 | foreach ($enclosures as $e) { |
||||
| 146 | $type = htmlspecialchars($e['content_type']); |
||||
| 147 | $url = htmlspecialchars($e['content_url']); |
||||
| 148 | $length = $e['duration'] ? $e['duration'] : 1; |
||||
| 149 | |||||
| 150 | $tpl->setVariable('ARTICLE_ENCLOSURE_URL', $url, true); |
||||
| 151 | $tpl->setVariable('ARTICLE_ENCLOSURE_TYPE', $type, true); |
||||
| 152 | $tpl->setVariable('ARTICLE_ENCLOSURE_LENGTH', $length, true); |
||||
| 153 | |||||
| 154 | $tpl->addBlock('enclosure'); |
||||
| 155 | } |
||||
| 156 | } else { |
||||
| 157 | $tpl->setVariable('ARTICLE_ENCLOSURE_URL', null, true); |
||||
| 158 | $tpl->setVariable('ARTICLE_ENCLOSURE_TYPE', null, true); |
||||
| 159 | $tpl->setVariable('ARTICLE_ENCLOSURE_LENGTH', null, true); |
||||
| 160 | } |
||||
| 161 | |||||
| 162 | list ($og_image, $og_stream) = Article::get_article_image($enclosures, $line['content'], $feed_site_url); |
||||
| 163 | |||||
| 164 | $tpl->setVariable('ARTICLE_OG_IMAGE', $og_image, true); |
||||
| 165 | |||||
| 166 | $tpl->addBlock('entry'); |
||||
| 167 | } |
||||
| 168 | |||||
| 169 | $tmp = ""; |
||||
| 170 | |||||
| 171 | $tpl->addBlock('feed'); |
||||
| 172 | $tpl->generateOutputToString($tmp); |
||||
| 173 | |||||
| 174 | if (@!clean($_REQUEST["noxml"])) { |
||||
| 175 | header("Content-Type: text/xml; charset=utf-8"); |
||||
| 176 | } else { |
||||
| 177 | header("Content-Type: text/plain; charset=utf-8"); |
||||
| 178 | } |
||||
| 179 | |||||
| 180 | print $tmp; |
||||
| 181 | } else if ($format == 'json') { |
||||
| 182 | |||||
| 183 | $feed = array(); |
||||
| 184 | |||||
| 185 | $feed['title'] = $feed_title; |
||||
| 186 | $feed['feed_url'] = $feed_self_url; |
||||
| 187 | |||||
| 188 | $feed['self_url'] = get_self_url_prefix(); |
||||
| 189 | |||||
| 190 | $feed['articles'] = array(); |
||||
| 191 | |||||
| 192 | while ($line = $result->fetch()) { |
||||
| 193 | |||||
| 194 | $line["content_preview"] = sanitize(truncate_string(strip_tags($line["content_preview"]), 100, '...')); |
||||
| 195 | |||||
| 196 | foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_QUERY_HEADLINES) as $p) { |
||||
| 197 | $line = $p->hook_query_headlines($line, 100); |
||||
| 198 | } |
||||
| 199 | |||||
| 200 | foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_ARTICLE_EXPORT_FEED) as $p) { |
||||
| 201 | $line = $p->hook_article_export_feed($line, $feed, $is_cat); |
||||
| 202 | } |
||||
| 203 | |||||
| 204 | $article = array(); |
||||
| 205 | |||||
| 206 | $article['id'] = $line['link']; |
||||
| 207 | $article['link'] = $line['link']; |
||||
| 208 | $article['title'] = $line['title']; |
||||
| 209 | $article['excerpt'] = $line["content_preview"]; |
||||
| 210 | $article['content'] = sanitize($line["content"], false, $owner_uid, $feed_site_url, false, $line["id"]); |
||||
| 211 | $article['updated'] = date('c', strtotime($line["updated"])); |
||||
| 212 | |||||
| 213 | if ($line['note']) { |
||||
| 214 | $article['note'] = $line['note']; |
||||
| 215 | } |
||||
| 216 | if ($article['author']) { |
||||
| 217 | $article['author'] = $line['author']; |
||||
| 218 | } |
||||
| 219 | |||||
| 220 | $tags = Article::get_article_tags($line["id"], $owner_uid); |
||||
| 221 | |||||
| 222 | if (count($tags) > 0) { |
||||
| 223 | $article['tags'] = array(); |
||||
| 224 | |||||
| 225 | foreach ($tags as $tag) { |
||||
| 226 | array_push($article['tags'], $tag); |
||||
| 227 | } |
||||
| 228 | } |
||||
| 229 | |||||
| 230 | $enclosures = Article::get_article_enclosures($line["id"]); |
||||
| 231 | |||||
| 232 | if (count($enclosures) > 0) { |
||||
| 233 | $article['enclosures'] = array(); |
||||
| 234 | |||||
| 235 | foreach ($enclosures as $e) { |
||||
| 236 | $type = $e['content_type']; |
||||
| 237 | $url = $e['content_url']; |
||||
| 238 | $length = $e['duration']; |
||||
| 239 | |||||
| 240 | array_push($article['enclosures'], array("url" => $url, "type" => $type, "length" => $length)); |
||||
| 241 | } |
||||
| 242 | } |
||||
| 243 | |||||
| 244 | array_push($feed['articles'], $article); |
||||
| 245 | } |
||||
| 246 | |||||
| 247 | header("Content-Type: text/json; charset=utf-8"); |
||||
| 248 | print json_encode($feed); |
||||
| 249 | |||||
| 250 | } else { |
||||
| 251 | header("Content-Type: text/plain; charset=utf-8"); |
||||
| 252 | print json_encode(array("error" => array("message" => "Unknown format"))); |
||||
| 253 | } |
||||
| 254 | } |
||||
| 255 | |||||
| 256 | public function getUnread() { |
||||
| 257 | $login = clean($_REQUEST["login"]); |
||||
| 258 | $fresh = clean($_REQUEST["fresh"]) == "1"; |
||||
| 259 | |||||
| 260 | $sth = $this->pdo->prepare("SELECT id FROM ttrss_users WHERE login = ?"); |
||||
| 261 | $sth->execute([$login]); |
||||
| 262 | |||||
| 263 | if ($row = $sth->fetch()) { |
||||
| 264 | $uid = $row["id"]; |
||||
| 265 | |||||
| 266 | print Feeds::getGlobalUnread($uid); |
||||
| 267 | |||||
| 268 | if ($fresh) { |
||||
| 269 | print ";"; |
||||
| 270 | print Feeds::getFeedArticles(-3, false, true, $uid); |
||||
| 271 | } |
||||
| 272 | |||||
| 273 | } else { |
||||
| 274 | print "-1;User not found"; |
||||
| 275 | } |
||||
| 276 | } |
||||
| 277 | |||||
| 278 | public function getProfiles() { |
||||
| 279 | $login = clean($_REQUEST["login"]); |
||||
| 280 | $rv = []; |
||||
| 281 | |||||
| 282 | if ($login) { |
||||
| 283 | $sth = $this->pdo->prepare("SELECT ttrss_settings_profiles.* FROM ttrss_settings_profiles,ttrss_users |
||||
| 284 | WHERE ttrss_users.id = ttrss_settings_profiles.owner_uid AND login = ? ORDER BY title"); |
||||
| 285 | $sth->execute([$login]); |
||||
| 286 | |||||
| 287 | $rv = [["value" => 0, "label" => __("Default profile")]]; |
||||
| 288 | |||||
| 289 | while ($line = $sth->fetch()) { |
||||
| 290 | $id = $line["id"]; |
||||
| 291 | $title = $line["title"]; |
||||
| 292 | |||||
| 293 | array_push($rv, ["label" => $title, "value" => $id]); |
||||
| 294 | } |
||||
| 295 | } |
||||
| 296 | |||||
| 297 | print json_encode($rv); |
||||
| 298 | } |
||||
| 299 | |||||
| 300 | public function logout() { |
||||
| 301 | logout_user(); |
||||
| 302 | header("Location: index.php"); |
||||
| 303 | } |
||||
| 304 | |||||
| 305 | public function share() { |
||||
| 306 | $uuid = clean($_REQUEST["key"]); |
||||
| 307 | |||||
| 308 | if ($uuid) { |
||||
| 309 | $sth = $this->pdo->prepare("SELECT ref_id, owner_uid |
||||
| 310 | FROM ttrss_user_entries WHERE uuid = ?"); |
||||
| 311 | $sth->execute([$uuid]); |
||||
| 312 | |||||
| 313 | if ($row = $sth->fetch()) { |
||||
| 314 | header("Content-Type: text/html"); |
||||
| 315 | |||||
| 316 | $id = $row["ref_id"]; |
||||
| 317 | $owner_uid = $row["owner_uid"]; |
||||
| 318 | |||||
| 319 | print $this->format_article($id, $owner_uid); |
||||
| 320 | |||||
| 321 | return; |
||||
| 322 | } |
||||
| 323 | } |
||||
| 324 | |||||
| 325 | header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found"); |
||||
| 326 | print "Article not found."; |
||||
| 327 | } |
||||
| 328 | |||||
| 329 | private function format_article($id, $owner_uid) { |
||||
| 330 | |||||
| 331 | $pdo = Db::pdo(); |
||||
| 332 | |||||
| 333 | $sth = $pdo->prepare("SELECT id,title,link,content,feed_id,comments,int_id,lang, |
||||
| 334 | ".SUBSTRING_FOR_DATE."(updated,1,16) as updated, |
||||
| 335 | (SELECT site_url FROM ttrss_feeds WHERE id = feed_id) as site_url, |
||||
| 336 | (SELECT title FROM ttrss_feeds WHERE id = feed_id) as feed_title, |
||||
| 337 | (SELECT hide_images FROM ttrss_feeds WHERE id = feed_id) as hide_images, |
||||
| 338 | (SELECT always_display_enclosures FROM ttrss_feeds WHERE id = feed_id) as always_display_enclosures, |
||||
| 339 | num_comments, |
||||
| 340 | tag_cache, |
||||
| 341 | author, |
||||
| 342 | guid, |
||||
| 343 | orig_feed_id, |
||||
| 344 | note |
||||
| 345 | FROM ttrss_entries,ttrss_user_entries |
||||
| 346 | WHERE id = ? AND ref_id = id AND owner_uid = ?"); |
||||
| 347 | $sth->execute([$id, $owner_uid]); |
||||
| 348 | |||||
| 349 | $rv = ''; |
||||
| 350 | |||||
| 351 | if ($line = $sth->fetch()) { |
||||
| 352 | |||||
| 353 | $line["tags"] = Article::get_article_tags($id, $owner_uid, $line["tag_cache"]); |
||||
| 354 | unset($line["tag_cache"]); |
||||
| 355 | |||||
| 356 | $line["content"] = sanitize($line["content"], |
||||
| 357 | $line['hide_images'], |
||||
| 358 | $owner_uid, $line["site_url"], false, $line["id"]); |
||||
| 359 | |||||
| 360 | foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_RENDER_ARTICLE) as $p) { |
||||
| 361 | $line = $p->hook_render_article($line); |
||||
| 362 | } |
||||
| 363 | |||||
| 364 | $line['content'] = DiskCache::rewriteUrls($line['content']); |
||||
| 365 | |||||
| 366 | $enclosures = Article::get_article_enclosures($line["id"]); |
||||
| 367 | |||||
| 368 | header("Content-Type: text/html"); |
||||
| 369 | |||||
| 370 | $rv .= "<!DOCTYPE html> |
||||
| 371 | <html><head> |
||||
| 372 | <meta http-equiv='Content-Type' content='text/html; charset=utf-8'/> |
||||
| 373 | <title>".$line["title"]."</title>". |
||||
| 374 | stylesheet_tag("css/default.css")." |
||||
| 375 | <link rel='shortcut icon' type='image/png' href='images/favicon.png'> |
||||
| 376 | <link rel='icon' type='image/png' sizes='72x72' href='images/favicon-72px.png'>"; |
||||
| 377 | |||||
| 378 | $rv .= "<meta property='og:title' content=\"".htmlspecialchars(html_entity_decode($line["title"], ENT_NOQUOTES | ENT_HTML401))."\"/>\n"; |
||||
| 379 | $rv .= "<meta property='og:description' content=\"". |
||||
| 380 | htmlspecialchars( |
||||
| 381 | truncate_string( |
||||
| 382 | preg_replace("/[\r\n\t]/", "", |
||||
| 383 | preg_replace("/ {1,}/", " ", |
||||
| 384 | strip_tags(html_entity_decode($line["content"], ENT_NOQUOTES | ENT_HTML401)) |
||||
| 385 | ) |
||||
| 386 | ), 500, "...") |
||||
| 387 | )."\"/>\n"; |
||||
| 388 | |||||
| 389 | $rv .= "</head>"; |
||||
| 390 | |||||
| 391 | list ($og_image, $og_stream) = Article::get_article_image($enclosures, $line['content'], $line["site_url"]); |
||||
| 392 | |||||
| 393 | if ($og_image) { |
||||
| 394 | $rv .= "<meta property='og:image' content=\"".htmlspecialchars($og_image)."\"/>"; |
||||
| 395 | } |
||||
| 396 | |||||
| 397 | $rv .= "<body class='flat ttrss_utility ttrss_zoom'>"; |
||||
| 398 | $rv .= "<div class='container'>"; |
||||
| 399 | |||||
| 400 | if ($line["link"]) { |
||||
| 401 | $rv .= "<h1><a target='_blank' rel='noopener noreferrer' |
||||
| 402 | title=\"".htmlspecialchars($line['title'])."\" |
||||
| 403 | href=\"" .htmlspecialchars($line["link"])."\">".$line["title"]."</a></h1>"; |
||||
| 404 | } else { |
||||
| 405 | $rv .= "<h1>".$line["title"]."</h1>"; |
||||
| 406 | } |
||||
| 407 | |||||
| 408 | $rv .= "<div class='content post'>"; |
||||
| 409 | |||||
| 410 | /* header */ |
||||
| 411 | |||||
| 412 | $rv .= "<div class='header'>"; |
||||
| 413 | $rv .= "<div class='row'>"; # row |
||||
| 414 | |||||
| 415 | //$entry_author = $line["author"] ? " - " . $line["author"] : ""; |
||||
| 416 | $parsed_updated = make_local_datetime($line["updated"], true, |
||||
| 417 | $owner_uid, true); |
||||
| 418 | |||||
| 419 | $rv .= "<div>".$line['author']."</div>"; |
||||
| 420 | $rv .= "<div>$parsed_updated</div>"; |
||||
| 421 | |||||
| 422 | $rv .= "</div>"; # row |
||||
| 423 | |||||
| 424 | $rv .= "</div>"; # header |
||||
| 425 | |||||
| 426 | /* content */ |
||||
| 427 | |||||
| 428 | $lang = $line['lang'] ? $line['lang'] : "en"; |
||||
| 429 | $rv .= "<div class='content' lang='$lang'>"; |
||||
| 430 | |||||
| 431 | /* content body */ |
||||
| 432 | |||||
| 433 | $rv .= $line["content"]; |
||||
| 434 | |||||
| 435 | $rv .= Article::format_article_enclosures($id, |
||||
| 436 | $line["always_display_enclosures"], |
||||
| 437 | $line["content"], |
||||
| 438 | $line["hide_images"]); |
||||
| 439 | |||||
| 440 | $rv .= "</div>"; # content |
||||
| 441 | |||||
| 442 | $rv .= "</div>"; # post |
||||
| 443 | |||||
| 444 | } |
||||
| 445 | |||||
| 446 | foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_FORMAT_ARTICLE) as $p) { |
||||
| 447 | $rv = $p->hook_format_article($rv, $line, true); |
||||
| 448 | } |
||||
| 449 | |||||
| 450 | return $rv; |
||||
| 451 | |||||
| 452 | } |
||||
| 453 | |||||
| 454 | public function rss() { |
||||
| 455 | $feed = clean($_REQUEST["id"]); |
||||
| 456 | $key = clean($_REQUEST["key"]); |
||||
| 457 | $is_cat = clean($_REQUEST["is_cat"]); |
||||
| 458 | $limit = (int) clean($_REQUEST["limit"]); |
||||
| 459 | $offset = (int) clean($_REQUEST["offset"]); |
||||
| 460 | |||||
| 461 | $search = clean($_REQUEST["q"]); |
||||
| 462 | $view_mode = clean($_REQUEST["view-mode"]); |
||||
| 463 | $order = clean($_REQUEST["order"]); |
||||
| 464 | $start_ts = clean($_REQUEST["ts"]); |
||||
| 465 | |||||
| 466 | $format = clean($_REQUEST['format']); |
||||
| 467 | $orig_guid = clean($_REQUEST["orig_guid"]); |
||||
| 468 | |||||
| 469 | if (!$format) { |
||||
| 470 | $format = 'atom'; |
||||
| 471 | } |
||||
| 472 | |||||
| 473 | if (SINGLE_USER_MODE) { |
||||
| 474 | authenticate_user("admin", null); |
||||
| 475 | } |
||||
| 476 | |||||
| 477 | $owner_id = false; |
||||
| 478 | |||||
| 479 | if ($key) { |
||||
| 480 | $sth = $this->pdo->prepare("SELECT owner_uid FROM |
||||
| 481 | ttrss_access_keys WHERE access_key = ? AND feed_id = ?"); |
||||
| 482 | $sth->execute([$key, $feed]); |
||||
| 483 | |||||
| 484 | if ($row = $sth->fetch()) { |
||||
| 485 | $owner_id = $row["owner_uid"]; |
||||
| 486 | } |
||||
| 487 | } |
||||
| 488 | |||||
| 489 | if ($owner_id) { |
||||
| 490 | $this->generate_syndicated_feed($owner_id, $feed, $is_cat, $limit, |
||||
| 491 | $offset, $search, $view_mode, $format, $order, $orig_guid, $start_ts); |
||||
| 492 | } else { |
||||
| 493 | header('HTTP/1.1 403 Forbidden'); |
||||
| 494 | } |
||||
| 495 | } |
||||
| 496 | |||||
| 497 | public function updateTask() { |
||||
| 498 | PluginHost::getInstance()->run_hooks(PluginHost::HOOK_UPDATE_TASK, "hook_update_task", false); |
||||
| 499 | } |
||||
| 500 | |||||
| 501 | public function housekeepingTask() { |
||||
| 502 | PluginHost::getInstance()->run_hooks(PluginHost::HOOK_HOUSE_KEEPING, "hook_house_keeping", false); |
||||
| 503 | } |
||||
| 504 | |||||
| 505 | public function globalUpdateFeeds() { |
||||
| 506 | RPC::updaterandomfeed_real(); |
||||
| 507 | |||||
| 508 | PluginHost::getInstance()->run_hooks(PluginHost::HOOK_UPDATE_TASK, "hook_update_task", false); |
||||
| 509 | } |
||||
| 510 | |||||
| 511 | public function sharepopup() { |
||||
| 512 | if (SINGLE_USER_MODE) { |
||||
| 513 | login_sequence(); |
||||
| 514 | } |
||||
| 515 | |||||
| 516 | header('Content-Type: text/html; charset=utf-8'); |
||||
| 517 | ?> |
||||
| 518 | <!DOCTYPE html> |
||||
| 519 | <html> |
||||
| 520 | <head> |
||||
| 521 | <title><?php echo __("Share with Tiny Tiny RSS") ?></title> |
||||
| 522 | <?php |
||||
| 523 | echo stylesheet_tag("css/default.css"); |
||||
| 524 | echo javascript_tag("lib/prototype.js"); |
||||
| 525 | echo javascript_tag("lib/dojo/dojo.js"); |
||||
| 526 | echo javascript_tag("lib/dojo/tt-rss-layer.js"); |
||||
| 527 | echo javascript_tag("lib/scriptaculous/scriptaculous.js?load=effects,controls") |
||||
| 528 | ?> |
||||
| 529 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> |
||||
| 530 | <link rel="shortcut icon" type="image/png" href="images/favicon.png"> |
||||
| 531 | <link rel="icon" type="image/png" sizes="72x72" href="images/favicon-72px.png"> |
||||
| 532 | </head> |
||||
| 533 | <body class='flat ttrss_utility share_popup'> |
||||
| 534 | <script type="text/javascript"> |
||||
| 535 | require(['dojo/parser', "dojo/ready", 'dijit/form/Button','dijit/form/CheckBox', 'dijit/form/Form', |
||||
| 536 | 'dijit/form/Select','dijit/form/TextBox','dijit/form/ValidationTextBox'],function(parser, ready){ |
||||
| 537 | ready(function() { |
||||
| 538 | parser.parse(); |
||||
| 539 | |||||
| 540 | new Ajax.Autocompleter('labels_value', 'labels_choices', |
||||
| 541 | "backend.php?op=rpc&method=completeLabels", |
||||
| 542 | { tokens: ',', paramName: "search" }); |
||||
| 543 | }); |
||||
| 544 | }); |
||||
| 545 | </script> |
||||
| 546 | <div class="content"> |
||||
| 547 | |||||
| 548 | <?php |
||||
| 549 | |||||
| 550 | $action = clean($_REQUEST["action"]); |
||||
| 551 | |||||
| 552 | if ($_SESSION["uid"]) { |
||||
| 553 | |||||
| 554 | if ($action == 'share') { |
||||
| 555 | |||||
| 556 | $title = strip_tags(clean($_REQUEST["title"])); |
||||
| 557 | $url = strip_tags(clean($_REQUEST["url"])); |
||||
| 558 | $content = strip_tags(clean($_REQUEST["content"])); |
||||
| 559 | $labels = strip_tags(clean($_REQUEST["labels"])); |
||||
| 560 | |||||
| 561 | Article::create_published_article($title, $url, $content, $labels, |
||||
| 562 | $_SESSION["uid"]); |
||||
| 563 | |||||
| 564 | print "<script type='text/javascript'>"; |
||||
| 565 | print "window.close();"; |
||||
| 566 | print "</script>"; |
||||
| 567 | |||||
| 568 | } else { |
||||
| 569 | $title = htmlspecialchars(clean($_REQUEST["title"])); |
||||
| 570 | $url = htmlspecialchars(clean($_REQUEST["url"])); |
||||
| 571 | |||||
| 572 | ?> |
||||
| 573 | <form id='share_form' name='share_form'> |
||||
| 574 | |||||
| 575 | <input type="hidden" name="op" value="sharepopup"> |
||||
| 576 | <input type="hidden" name="action" value="share"> |
||||
| 577 | |||||
| 578 | <fieldset> |
||||
| 579 | <label><?php echo __("Title:") ?></label> |
||||
| 580 | <input style='width : 270px' dojoType='dijit.form.TextBox' name='title' value="<?php echo $title ?>"> |
||||
| 581 | </fieldset> |
||||
| 582 | |||||
| 583 | <fieldset> |
||||
| 584 | <label><?php echo __("URL:") ?></label> |
||||
| 585 | <input style='width : 270px' name='url' dojoType='dijit.form.TextBox' value="<?php echo $url ?>"> |
||||
| 586 | </fieldset> |
||||
| 587 | |||||
| 588 | <fieldset> |
||||
| 589 | <label><?php echo __("Content:") ?></label> |
||||
| 590 | <input style='width : 270px' name='content' dojoType='dijit.form.TextBox' value=""> |
||||
| 591 | </fieldset> |
||||
| 592 | |||||
| 593 | <fieldset> |
||||
| 594 | <label><?php echo __("Labels:") ?></label> |
||||
| 595 | <input style='width : 270px' name='labels' dojoType='dijit.form.TextBox' id="labels_value" |
||||
| 596 | placeholder='Alpha, Beta, Gamma' value=""> |
||||
| 597 | <div class="autocomplete" id="labels_choices" |
||||
| 598 | style="display : block"></div> |
||||
| 599 | </fieldset> |
||||
| 600 | |||||
| 601 | <hr/> |
||||
| 602 | |||||
| 603 | <fieldset> |
||||
| 604 | <button dojoType='dijit.form.Button' class="alt-primary" type="submit"><?php echo __('Share') ?></button> |
||||
| 605 | <button dojoType='dijit.form.Button' onclick="return window.close()"><?php echo __('Cancel') ?></button> |
||||
| 606 | <span class="text-muted small"><?php echo __("Shared article will appear in the Published feed.") ?></span> |
||||
| 607 | </fieldset> |
||||
| 608 | |||||
| 609 | </form> |
||||
| 610 | <?php |
||||
| 611 | |||||
| 612 | } |
||||
| 613 | |||||
| 614 | } else { |
||||
| 615 | |||||
| 616 | $return = urlencode(make_self_url()); |
||||
| 617 | print_error("Not logged in"); ?> |
||||
| 618 | |||||
| 619 | <form action="public.php?return=<?php echo $return ?>" method="post"> |
||||
| 620 | |||||
| 621 | <input type="hidden" name="op" value="login"> |
||||
| 622 | |||||
| 623 | <fieldset> |
||||
| 624 | <label><?php echo __("Login:") ?></label> |
||||
| 625 | <input name="login" id="login" dojoType="dijit.form.TextBox" type="text" |
||||
| 626 | onchange="fetchProfiles()" onfocus="fetchProfiles()" onblur="fetchProfiles()" |
||||
| 627 | required="1" value="<?php echo $_SESSION["fake_login"] ?>" /> |
||||
| 628 | </fieldset> |
||||
| 629 | |||||
| 630 | <fieldset> |
||||
| 631 | <label><?php echo __("Password:") ?></label> |
||||
| 632 | |||||
| 633 | <input type="password" name="password" required="1" |
||||
| 634 | dojoType="dijit.form.TextBox" |
||||
| 635 | class="input input-text" |
||||
| 636 | value="<?php echo $_SESSION["fake_password"] ?>"/> |
||||
| 637 | </fieldset> |
||||
| 638 | |||||
| 639 | <hr/> |
||||
| 640 | |||||
| 641 | <fieldset> |
||||
| 642 | <label> </label> |
||||
| 643 | |||||
| 644 | <button dojoType="dijit.form.Button" type="submit" class="alt-primary"><?php echo __('Log in') ?></button> |
||||
| 645 | </fieldset> |
||||
| 646 | |||||
| 647 | </form> |
||||
| 648 | <?php |
||||
| 649 | } |
||||
| 650 | |||||
| 651 | print "</div></body></html>"; |
||||
| 652 | } |
||||
| 653 | |||||
| 654 | public function login() { |
||||
| 655 | if (!SINGLE_USER_MODE) { |
||||
| 656 | |||||
| 657 | $login = clean($_POST["login"]); |
||||
| 658 | $password = clean($_POST["password"]); |
||||
| 659 | $remember_me = clean($_POST["remember_me"]); |
||||
| 660 | |||||
| 661 | if ($remember_me) { |
||||
| 662 | session_set_cookie_params(SESSION_COOKIE_LIFETIME); |
||||
| 663 | } else { |
||||
| 664 | session_set_cookie_params(0); |
||||
| 665 | } |
||||
| 666 | |||||
| 667 | if (authenticate_user($login, $password)) { |
||||
| 668 | $_POST["password"] = ""; |
||||
| 669 | |||||
| 670 | if (get_schema_version() >= 120) { |
||||
| 671 | $_SESSION["language"] = get_pref("USER_LANGUAGE", $_SESSION["uid"]); |
||||
| 672 | } |
||||
| 673 | |||||
| 674 | $_SESSION["ref_schema_version"] = get_schema_version(true); |
||||
| 675 | $_SESSION["bw_limit"] = !!clean($_POST["bw_limit"]); |
||||
| 676 | |||||
| 677 | if (clean($_POST["profile"])) { |
||||
| 678 | |||||
| 679 | $profile = (int) clean($_POST["profile"]); |
||||
| 680 | |||||
| 681 | $sth = $this->pdo->prepare("SELECT id FROM ttrss_settings_profiles |
||||
| 682 | WHERE id = ? AND owner_uid = ?"); |
||||
| 683 | $sth->execute([$profile, $_SESSION['uid']]); |
||||
| 684 | |||||
| 685 | if ($sth->fetch()) { |
||||
| 686 | $_SESSION["profile"] = $profile; |
||||
| 687 | } else { |
||||
| 688 | $_SESSION["profile"] = null; |
||||
| 689 | } |
||||
| 690 | } |
||||
| 691 | } else { |
||||
| 692 | |||||
| 693 | // start an empty session to deliver login error message |
||||
| 694 | @session_start(); |
||||
| 695 | |||||
| 696 | if (!isset($_SESSION["login_error_msg"])) { |
||||
| 697 | $_SESSION["login_error_msg"] = __("Incorrect username or password"); |
||||
| 698 | } |
||||
| 699 | |||||
| 700 | user_error("Failed login attempt for $login from {$_SERVER['REMOTE_ADDR']}", E_USER_WARNING); |
||||
| 701 | } |
||||
| 702 | |||||
| 703 | $return = clean($_REQUEST['return']); |
||||
| 704 | |||||
| 705 | if ($_REQUEST['return'] && mb_strpos($return, SELF_URL_PATH) === 0) { |
||||
| 706 | header("Location: ".clean($_REQUEST['return'])); |
||||
| 707 | } else { |
||||
| 708 | header("Location: ".get_self_url_prefix()); |
||||
| 709 | } |
||||
| 710 | } |
||||
| 711 | } |
||||
| 712 | |||||
| 713 | public function subscribe() { |
||||
| 714 | if (SINGLE_USER_MODE) { |
||||
| 715 | login_sequence(); |
||||
| 716 | } |
||||
| 717 | |||||
| 718 | if ($_SESSION["uid"]) { |
||||
| 719 | |||||
| 720 | $feed_url = trim(clean($_REQUEST["feed_url"])); |
||||
| 721 | |||||
| 722 | header('Content-Type: text/html; charset=utf-8'); |
||||
| 723 | ?> |
||||
| 724 | <!DOCTYPE html> |
||||
| 725 | <html> |
||||
| 726 | <head> |
||||
| 727 | <title>Tiny Tiny RSS</title> |
||||
| 728 | <?php |
||||
| 729 | echo stylesheet_tag("css/default.css"); |
||||
| 730 | echo javascript_tag("lib/prototype.js"); |
||||
| 731 | echo javascript_tag("lib/dojo/dojo.js"); |
||||
| 732 | echo javascript_tag("lib/dojo/tt-rss-layer.js"); |
||||
| 733 | ?> |
||||
| 734 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> |
||||
| 735 | <link rel="shortcut icon" type="image/png" href="images/favicon.png"> |
||||
| 736 | <link rel="icon" type="image/png" sizes="72x72" href="images/favicon-72px.png"> |
||||
| 737 | </head> |
||||
| 738 | <body class='flat ttrss_utility'> |
||||
| 739 | <script type="text/javascript"> |
||||
| 740 | require(['dojo/parser', "dojo/ready", 'dijit/form/Button','dijit/form/CheckBox', 'dijit/form/Form', |
||||
| 741 | 'dijit/form/Select','dijit/form/TextBox','dijit/form/ValidationTextBox'],function(parser, ready){ |
||||
| 742 | ready(function() { |
||||
| 743 | parser.parse(); |
||||
| 744 | }); |
||||
| 745 | }); |
||||
| 746 | </script> |
||||
| 747 | <div class="container"> |
||||
| 748 | <h1><?php echo __("Subscribe to feed...") ?></h1> |
||||
| 749 | <div class='content'> |
||||
| 750 | <?php |
||||
| 751 | |||||
| 752 | if (!$feed_url) { |
||||
| 753 | ?> |
||||
| 754 | <form method="post"> |
||||
| 755 | <input type="hidden" name="op" value="subscribe"> |
||||
| 756 | <fieldset> |
||||
| 757 | <label>Feed or site URL:</label> |
||||
| 758 | <input style="width: 300px" dojoType="dijit.form.ValidationTextBox" required="1" name="feed_url"> |
||||
| 759 | </fieldset> |
||||
| 760 | |||||
| 761 | <button class="alt-primary" dojoType="dijit.form.Button" type="submit"> |
||||
| 762 | <?php echo __("Subscribe") ?> |
||||
| 763 | </button> |
||||
| 764 | |||||
| 765 | <a href="index.php"><?php echo __("Return to Tiny Tiny RSS") ?></a> |
||||
| 766 | </form> |
||||
| 767 | <?php |
||||
| 768 | } else { |
||||
| 769 | |||||
| 770 | $rc = Feeds::subscribe_to_feed($feed_url); |
||||
| 771 | $feed_urls = false; |
||||
| 772 | |||||
| 773 | switch ($rc['code']) { |
||||
| 774 | case 0: |
||||
| 775 | print_warning(T_sprintf("Already subscribed to <b>%s</b>.", $feed_url)); |
||||
| 776 | break; |
||||
| 777 | case 1: |
||||
| 778 | print_notice(T_sprintf("Subscribed to <b>%s</b>.", $feed_url)); |
||||
| 779 | break; |
||||
| 780 | case 2: |
||||
| 781 | print_error(T_sprintf("Could not subscribe to <b>%s</b>.", $feed_url)); |
||||
| 782 | break; |
||||
| 783 | case 3: |
||||
| 784 | print_error(T_sprintf("No feeds found in <b>%s</b>.", $feed_url)); |
||||
| 785 | break; |
||||
| 786 | case 4: |
||||
| 787 | $feed_urls = $rc["feeds"]; |
||||
| 788 | break; |
||||
| 789 | case 5: |
||||
| 790 | print_error(T_sprintf("Could not subscribe to <b>%s</b>.<br>Can't download the Feed URL.", $feed_url)); |
||||
| 791 | break; |
||||
| 792 | } |
||||
| 793 | |||||
| 794 | if ($feed_urls) { |
||||
| 795 | |||||
| 796 | print "<form action='public.php'>"; |
||||
| 797 | print "<input type='hidden' name='op' value='subscribe'>"; |
||||
| 798 | |||||
| 799 | print "<fieldset>"; |
||||
| 800 | print "<label style='display : inline'>".__("Multiple feed URLs found:")."</label>"; |
||||
| 801 | print "<select name='feed_url' dojoType='dijit.form.Select'>"; |
||||
| 802 | |||||
| 803 | foreach ($feed_urls as $url => $name) { |
||||
| 804 | $url = htmlspecialchars($url); |
||||
| 805 | $name = htmlspecialchars($name); |
||||
| 806 | |||||
| 807 | print "<option value=\"$url\">$name</option>"; |
||||
| 808 | } |
||||
| 809 | |||||
| 810 | print "</select>"; |
||||
| 811 | print "</fieldset>"; |
||||
| 812 | |||||
| 813 | print "<button class='alt-primary' dojoType='dijit.form.Button' type='submit'>".__("Subscribe to selected feed")."</button>"; |
||||
| 814 | print "<a href='index.php'>".__("Return to Tiny Tiny RSS")."</a>"; |
||||
| 815 | |||||
| 816 | print "</form>"; |
||||
| 817 | } |
||||
| 818 | |||||
| 819 | $tp_uri = get_self_url_prefix()."/prefs.php"; |
||||
| 820 | |||||
| 821 | if ($rc['code'] <= 2) { |
||||
| 822 | $sth = $this->pdo->prepare("SELECT id FROM ttrss_feeds WHERE |
||||
| 823 | feed_url = ? AND owner_uid = ?"); |
||||
| 824 | $sth->execute([$feed_url, $_SESSION['uid']]); |
||||
| 825 | $row = $sth->fetch(); |
||||
| 826 | |||||
| 827 | $feed_id = $row["id"]; |
||||
| 828 | } else { |
||||
| 829 | $feed_id = 0; |
||||
| 830 | } |
||||
| 831 | |||||
| 832 | if ($feed_id) { |
||||
| 833 | print "<form method='GET' action=\"$tp_uri\"> |
||||
| 834 | <input type='hidden' name='tab' value='feedConfig'> |
||||
| 835 | <input type='hidden' name='method' value='editfeed'> |
||||
| 836 | <input type='hidden' name='methodparam' value='$feed_id'> |
||||
| 837 | <button dojoType='dijit.form.Button' class='alt-info' type='submit'>".__("Edit subscription options")."</button> |
||||
| 838 | <a href='index.php'>".__("Return to Tiny Tiny RSS")."</a> |
||||
| 839 | </form>"; |
||||
| 840 | } |
||||
| 841 | } |
||||
| 842 | |||||
| 843 | print "</div></div></body></html>"; |
||||
| 844 | |||||
| 845 | } else { |
||||
| 846 | render_login_form(); |
||||
| 847 | } |
||||
| 848 | } |
||||
| 849 | |||||
| 850 | public function index() { |
||||
| 851 | header("Content-Type: text/plain"); |
||||
| 852 | print error_json(13); |
||||
| 853 | } |
||||
| 854 | |||||
| 855 | public function forgotpass() { |
||||
| 856 | startup_gettext(); |
||||
|
0 ignored issues
–
show
|
|||||
| 857 | session_start(); |
||||
| 858 | |||||
| 859 | @$hash = clean($_REQUEST["hash"]); |
||||
| 860 | |||||
| 861 | header('Content-Type: text/html; charset=utf-8'); |
||||
| 862 | ?> |
||||
| 863 | <!DOCTYPE html> |
||||
| 864 | <html> |
||||
| 865 | <head> |
||||
| 866 | <title>Tiny Tiny RSS</title> |
||||
| 867 | <link rel="shortcut icon" type="image/png" href="images/favicon.png"> |
||||
| 868 | <link rel="icon" type="image/png" sizes="72x72" href="images/favicon-72px.png"> |
||||
| 869 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> |
||||
| 870 | <?php |
||||
| 871 | echo stylesheet_tag("css/default.css"); |
||||
| 872 | echo javascript_tag("lib/prototype.js"); |
||||
| 873 | echo javascript_tag("lib/dojo/dojo.js"); |
||||
| 874 | echo javascript_tag("lib/dojo/tt-rss-layer.js"); |
||||
| 875 | ?> |
||||
| 876 | </head> |
||||
| 877 | <body class='flat ttrss_utility'> |
||||
| 878 | <div class='container'> |
||||
| 879 | |||||
| 880 | <script type="text/javascript"> |
||||
| 881 | require(['dojo/parser', "dojo/ready", 'dijit/form/Button','dijit/form/CheckBox', 'dijit/form/Form', |
||||
| 882 | 'dijit/form/Select','dijit/form/TextBox','dijit/form/ValidationTextBox'],function(parser, ready){ |
||||
| 883 | ready(function() { |
||||
| 884 | parser.parse(); |
||||
| 885 | }); |
||||
| 886 | }); |
||||
| 887 | </script> |
||||
| 888 | <?php |
||||
| 889 | |||||
| 890 | print "<h1>".__("Password recovery")."</h1>"; |
||||
| 891 | print "<div class='content'>"; |
||||
| 892 | |||||
| 893 | @$method = clean($_POST['method']); |
||||
| 894 | |||||
| 895 | if ($hash) { |
||||
| 896 | $login = clean($_REQUEST["login"]); |
||||
| 897 | |||||
| 898 | if ($login) { |
||||
| 899 | $sth = $this->pdo->prepare("SELECT id, resetpass_token FROM ttrss_users |
||||
| 900 | WHERE login = ?"); |
||||
| 901 | $sth->execute([$login]); |
||||
| 902 | |||||
| 903 | if ($row = $sth->fetch()) { |
||||
| 904 | $id = $row["id"]; |
||||
| 905 | $resetpass_token_full = $row["resetpass_token"]; |
||||
| 906 | list($timestamp, $resetpass_token) = explode(":", $resetpass_token_full); |
||||
| 907 | |||||
| 908 | if ($timestamp && $resetpass_token && |
||||
| 909 | $timestamp >= time() - 15 * 60 * 60 && |
||||
| 910 | $resetpass_token == $hash) { |
||||
| 911 | |||||
| 912 | $sth = $this->pdo->prepare("UPDATE ttrss_users SET resetpass_token = NULL |
||||
| 913 | WHERE id = ?"); |
||||
| 914 | $sth->execute([$id]); |
||||
| 915 | |||||
| 916 | Pref_Users::resetUserPassword($id, true); |
||||
| 917 | |||||
| 918 | print "<p>"."Completed."."</p>"; |
||||
| 919 | |||||
| 920 | } else { |
||||
| 921 | print_error("Some of the information provided is missing or incorrect."); |
||||
| 922 | } |
||||
| 923 | } else { |
||||
| 924 | print_error("Some of the information provided is missing or incorrect."); |
||||
| 925 | } |
||||
| 926 | } else { |
||||
| 927 | print_error("Some of the information provided is missing or incorrect."); |
||||
| 928 | } |
||||
| 929 | |||||
| 930 | print "<a href='index.php'>".__("Return to Tiny Tiny RSS")."</a>"; |
||||
| 931 | |||||
| 932 | } else if (!$method) { |
||||
| 933 | print_notice(__("You will need to provide valid account name and email. Password reset link will be sent to your email address.")); |
||||
| 934 | |||||
| 935 | print "<form method='POST' action='public.php'> |
||||
| 936 | <input type='hidden' name='method' value='do'> |
||||
| 937 | <input type='hidden' name='op' value='forgotpass'> |
||||
| 938 | |||||
| 939 | <fieldset> |
||||
| 940 | <label>".__("Login:")."</label> |
||||
| 941 | <input dojoType='dijit.form.TextBox' type='text' name='login' value='' required> |
||||
| 942 | </fieldset> |
||||
| 943 | |||||
| 944 | <fieldset> |
||||
| 945 | <label>".__("Email:")."</label> |
||||
| 946 | <input dojoType='dijit.form.TextBox' type='email' name='email' value='' required> |
||||
| 947 | </fieldset>"; |
||||
| 948 | |||||
| 949 | $_SESSION["pwdreset:testvalue1"] = rand(1, 10); |
||||
| 950 | $_SESSION["pwdreset:testvalue2"] = rand(1, 10); |
||||
| 951 | |||||
| 952 | print "<fieldset> |
||||
| 953 | <label>".T_sprintf("How much is %d + %d:", $_SESSION["pwdreset:testvalue1"], $_SESSION["pwdreset:testvalue2"])."</label> |
||||
| 954 | <input dojoType='dijit.form.TextBox' type='text' name='test' value='' required> |
||||
| 955 | </fieldset> |
||||
| 956 | |||||
| 957 | <hr/> |
||||
| 958 | <fieldset> |
||||
| 959 | <button dojoType='dijit.form.Button' type='submit' class='alt-danger'>".__("Reset password")."</button> |
||||
| 960 | <a href='index.php'>".__("Return to Tiny Tiny RSS")."</a> |
||||
| 961 | </fieldset> |
||||
| 962 | |||||
| 963 | </form>"; |
||||
| 964 | } else if ($method == 'do') { |
||||
| 965 | |||||
| 966 | $login = clean($_POST["login"]); |
||||
| 967 | $email = clean($_POST["email"]); |
||||
| 968 | $test = clean($_POST["test"]); |
||||
| 969 | |||||
| 970 | if ($test != ($_SESSION["pwdreset:testvalue1"] + $_SESSION["pwdreset:testvalue2"]) || !$email || !$login) { |
||||
| 971 | print_error(__('Some of the required form parameters are missing or incorrect.')); |
||||
| 972 | |||||
| 973 | print "<form method='GET' action='public.php'> |
||||
| 974 | <input type='hidden' name='op' value='forgotpass'> |
||||
| 975 | <button dojoType='dijit.form.Button' type='submit' class='alt-primary'>".__("Go back")."</button> |
||||
| 976 | </form>"; |
||||
| 977 | |||||
| 978 | } else { |
||||
| 979 | |||||
| 980 | // prevent submitting this form multiple times |
||||
| 981 | $_SESSION["pwdreset:testvalue1"] = rand(1, 1000); |
||||
| 982 | $_SESSION["pwdreset:testvalue2"] = rand(1, 1000); |
||||
| 983 | |||||
| 984 | $sth = $this->pdo->prepare("SELECT id FROM ttrss_users |
||||
| 985 | WHERE login = ? AND email = ?"); |
||||
| 986 | $sth->execute([$login, $email]); |
||||
| 987 | |||||
| 988 | if ($row = $sth->fetch()) { |
||||
| 989 | print_notice("Password reset instructions are being sent to your email address."); |
||||
| 990 | |||||
| 991 | $id = $row["id"]; |
||||
| 992 | |||||
| 993 | if ($id) { |
||||
| 994 | $resetpass_token = sha1(get_random_bytes(128)); |
||||
| 995 | $resetpass_link = get_self_url_prefix()."/public.php?op=forgotpass&hash=".$resetpass_token. |
||||
| 996 | "&login=".urlencode($login); |
||||
| 997 | |||||
| 998 | require_once "lib/MiniTemplator.class.php"; |
||||
| 999 | |||||
| 1000 | $tpl = new MiniTemplator; |
||||
| 1001 | |||||
| 1002 | $tpl->readTemplateFromFile("templates/resetpass_link_template.txt"); |
||||
| 1003 | |||||
| 1004 | $tpl->setVariable('LOGIN', $login); |
||||
| 1005 | $tpl->setVariable('RESETPASS_LINK', $resetpass_link); |
||||
| 1006 | $tpl->setVariable('TTRSS_HOST', SELF_URL_PATH); |
||||
| 1007 | |||||
| 1008 | $tpl->addBlock('message'); |
||||
| 1009 | |||||
| 1010 | $message = ""; |
||||
| 1011 | |||||
| 1012 | $tpl->generateOutputToString($message); |
||||
| 1013 | |||||
| 1014 | $mailer = new Mailer(); |
||||
| 1015 | |||||
| 1016 | $rc = $mailer->mail(["to_name" => $login, |
||||
| 1017 | "to_address" => $email, |
||||
| 1018 | "subject" => __("[tt-rss] Password reset request"), |
||||
| 1019 | "message" => $message]); |
||||
| 1020 | |||||
| 1021 | if (!$rc) { |
||||
| 1022 | print_error($mailer->error()); |
||||
| 1023 | } |
||||
| 1024 | |||||
| 1025 | $resetpass_token_full = time().":".$resetpass_token; |
||||
| 1026 | |||||
| 1027 | $sth = $this->pdo->prepare("UPDATE ttrss_users |
||||
| 1028 | SET resetpass_token = ? |
||||
| 1029 | WHERE login = ? AND email = ?"); |
||||
| 1030 | |||||
| 1031 | $sth->execute([$resetpass_token_full, $login, $email]); |
||||
| 1032 | |||||
| 1033 | } else { |
||||
| 1034 | print_error("User ID not found."); |
||||
| 1035 | } |
||||
| 1036 | |||||
| 1037 | print "<a href='index.php'>".__("Return to Tiny Tiny RSS")."</a>"; |
||||
| 1038 | |||||
| 1039 | } else { |
||||
| 1040 | print_error(__("Sorry, login and email combination not found.")); |
||||
| 1041 | |||||
| 1042 | print "<form method='GET' action='public.php'> |
||||
| 1043 | <input type='hidden' name='op' value='forgotpass'> |
||||
| 1044 | <button dojoType='dijit.form.Button' type='submit'>".__("Go back")."</button> |
||||
| 1045 | </form>"; |
||||
| 1046 | |||||
| 1047 | } |
||||
| 1048 | } |
||||
| 1049 | |||||
| 1050 | } |
||||
| 1051 | |||||
| 1052 | print "</div>"; |
||||
| 1053 | print "</div>"; |
||||
| 1054 | print "</body>"; |
||||
| 1055 | print "</html>"; |
||||
| 1056 | |||||
| 1057 | } |
||||
| 1058 | |||||
| 1059 | public function dbupdate() { |
||||
| 1060 | startup_gettext(); |
||||
|
0 ignored issues
–
show
The function
startup_gettext() has been deprecated: Loaded in bootstrap
(
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. Loading history...
|
|||||
| 1061 | |||||
| 1062 | if (!SINGLE_USER_MODE && $_SESSION["access_level"] < 10) { |
||||
| 1063 | $_SESSION["login_error_msg"] = __("Your access level is insufficient to run this script."); |
||||
| 1064 | render_login_form(); |
||||
| 1065 | exit; |
||||
| 1066 | } |
||||
| 1067 | |||||
| 1068 | ?> |
||||
| 1069 | <!DOCTYPE html> |
||||
| 1070 | <html> |
||||
| 1071 | <head> |
||||
| 1072 | <title>Database Updater</title> |
||||
| 1073 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> |
||||
| 1074 | <?php echo stylesheet_tag("css/default.css") ?> |
||||
| 1075 | <link rel="shortcut icon" type="image/png" href="images/favicon.png"> |
||||
| 1076 | <link rel="icon" type="image/png" sizes="72x72" href="images/favicon-72px.png"> |
||||
| 1077 | <?php |
||||
| 1078 | echo stylesheet_tag("css/default.css"); |
||||
| 1079 | echo javascript_tag("lib/prototype.js"); |
||||
| 1080 | echo javascript_tag("lib/dojo/dojo.js"); |
||||
| 1081 | echo javascript_tag("lib/dojo/tt-rss-layer.js"); |
||||
| 1082 | ?> |
||||
| 1083 | <style type="text/css"> |
||||
| 1084 | span.ok { color : #009000; font-weight : bold; } |
||||
| 1085 | span.err { color : #ff0000; font-weight : bold; } |
||||
| 1086 | </style> |
||||
| 1087 | </head> |
||||
| 1088 | <body class="flat ttrss_utility"> |
||||
| 1089 | |||||
| 1090 | <script type="text/javascript"> |
||||
| 1091 | require(['dojo/parser', "dojo/ready", 'dijit/form/Button','dijit/form/CheckBox', 'dijit/form/Form', |
||||
| 1092 | 'dijit/form/Select','dijit/form/TextBox','dijit/form/ValidationTextBox'],function(parser, ready){ |
||||
| 1093 | ready(function() { |
||||
| 1094 | parser.parse(); |
||||
| 1095 | }); |
||||
| 1096 | }); |
||||
| 1097 | |||||
| 1098 | public function confirmOP() { |
||||
| 1099 | return confirm("Update the database?"); |
||||
| 1100 | } |
||||
| 1101 | </script> |
||||
| 1102 | |||||
| 1103 | <div class="container"> |
||||
| 1104 | <h1><?php echo __("Database Updater") ?></h1> |
||||
| 1105 | |||||
| 1106 | <div class="content"> |
||||
| 1107 | |||||
| 1108 | <?php |
||||
| 1109 | @$op = clean($_REQUEST["subop"]); |
||||
| 1110 | $updater = new DbUpdater(DB_TYPE, SCHEMA_VERSION); |
||||
| 1111 | |||||
| 1112 | if ($op == "performupdate") { |
||||
| 1113 | if ($updater->isUpdateRequired()) { |
||||
| 1114 | |||||
| 1115 | print "<h2>".T_sprintf("Performing updates to version %d", SCHEMA_VERSION)."</h2>"; |
||||
| 1116 | |||||
| 1117 | for ($i = $updater->getSchemaVersion() + 1; $i <= SCHEMA_VERSION; $i++) { |
||||
| 1118 | print "<ul>"; |
||||
| 1119 | |||||
| 1120 | print "<li class='text-info'>".T_sprintf("Updating to version %d", $i)."</li>"; |
||||
| 1121 | |||||
| 1122 | print "<li>"; |
||||
| 1123 | $result = $updater->performUpdateTo($i, true); |
||||
| 1124 | print "</li>"; |
||||
| 1125 | |||||
| 1126 | if (!$result) { |
||||
| 1127 | print "</ul>"; |
||||
| 1128 | |||||
| 1129 | print_error("One of the updates failed. Either retry the process or perform updates manually."); |
||||
| 1130 | |||||
| 1131 | print "<form method='POST'> |
||||
| 1132 | <input type='hidden' name='subop' value='performupdate'> |
||||
| 1133 | <button type='submit' dojoType='dijit.form.Button' class='alt-danger' onclick='return confirmOP()'>".__("Try again")."</button> |
||||
| 1134 | <a href='index.php'>".__("Return to Tiny Tiny RSS")."</a> |
||||
| 1135 | </form>"; |
||||
| 1136 | |||||
| 1137 | return; |
||||
| 1138 | } else { |
||||
| 1139 | print "<li class='text-success'>".__("Completed.")."</li>"; |
||||
| 1140 | print "</ul>"; |
||||
| 1141 | } |
||||
| 1142 | } |
||||
| 1143 | |||||
| 1144 | print_notice("Your Tiny Tiny RSS database is now updated to the latest version."); |
||||
| 1145 | |||||
| 1146 | print "<a href='index.php'>".__("Return to Tiny Tiny RSS")."</a>"; |
||||
| 1147 | |||||
| 1148 | } else { |
||||
| 1149 | print_notice("Tiny Tiny RSS database is up to date."); |
||||
| 1150 | |||||
| 1151 | print "<a href='index.php'>".__("Return to Tiny Tiny RSS")."</a>"; |
||||
| 1152 | } |
||||
| 1153 | } else { |
||||
| 1154 | if ($updater->isUpdateRequired()) { |
||||
| 1155 | |||||
| 1156 | print "<h2>".T_sprintf("Tiny Tiny RSS database needs update to the latest version (%d to %d).", |
||||
| 1157 | $updater->getSchemaVersion(), SCHEMA_VERSION)."</h2>"; |
||||
| 1158 | |||||
| 1159 | if (DB_TYPE == "mysql") { |
||||
| 1160 | print_error("<strong>READ THIS:</strong> Due to MySQL limitations, your database is not completely protected while updating. ". |
||||
| 1161 | "Errors may put it in an inconsistent state requiring manual rollback. <strong>BACKUP YOUR DATABASE BEFORE CONTINUING.</strong>"); |
||||
| 1162 | } else { |
||||
| 1163 | print_warning("Please backup your database before proceeding."); |
||||
| 1164 | } |
||||
| 1165 | |||||
| 1166 | print "<form method='POST'> |
||||
| 1167 | <input type='hidden' name='subop' value='performupdate'> |
||||
| 1168 | <button type='submit' dojoType='dijit.form.Button' class='alt-danger' onclick='return confirmOP()'>".__("Perform updates")."</button> |
||||
| 1169 | </form>"; |
||||
| 1170 | |||||
| 1171 | } else { |
||||
| 1172 | |||||
| 1173 | print_notice("Tiny Tiny RSS database is up to date."); |
||||
| 1174 | |||||
| 1175 | print "<a href='index.php'>".__("Return to Tiny Tiny RSS")."</a>"; |
||||
| 1176 | } |
||||
| 1177 | } |
||||
| 1178 | ?> |
||||
| 1179 | |||||
| 1180 | </div> |
||||
| 1181 | </div> |
||||
| 1182 | </body> |
||||
| 1183 | </html> |
||||
| 1184 | <?php |
||||
| 1185 | } |
||||
| 1186 | |||||
| 1187 | public function cached_url() { |
||||
| 1188 | list ($cache_dir, $filename) = explode("/", $_GET["file"], 2); |
||||
| 1189 | |||||
| 1190 | // we do not allow files with extensions at the moment |
||||
| 1191 | $filename = str_replace(".", "", $filename); |
||||
| 1192 | |||||
| 1193 | $cache = new DiskCache($cache_dir); |
||||
| 1194 | |||||
| 1195 | if ($cache->exists($filename)) { |
||||
| 1196 | $cache->send($filename); |
||||
| 1197 | } else { |
||||
| 1198 | header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found"); |
||||
| 1199 | echo "File not found."; |
||||
| 1200 | } |
||||
| 1201 | } |
||||
| 1202 | |||||
| 1203 | private function make_article_tag_uri($id, $timestamp) { |
||||
| 1204 | |||||
| 1205 | $timestamp = date("Y-m-d", strtotime($timestamp)); |
||||
| 1206 | |||||
| 1207 | return "tag:".parse_url(get_self_url_prefix(), PHP_URL_HOST).",$timestamp:/$id"; |
||||
| 1208 | } |
||||
| 1209 | |||||
| 1210 | // this should be used very carefully because this endpoint is exposed to unauthenticated users |
||||
| 1211 | // plugin data is not loaded because there's no user context and owner_uid/session may or may not be available |
||||
| 1212 | // in general, don't do anything user-related in here and do not modify $_SESSION |
||||
| 1213 | public function pluginhandler() { |
||||
| 1214 | $host = new PluginHost(); |
||||
| 1215 | |||||
| 1216 | $plugin_name = clean_filename($_REQUEST["plugin"]); |
||||
| 1217 | $method = clean($_REQUEST["pmethod"]); |
||||
| 1218 | |||||
| 1219 | $host->load($plugin_name, PluginHost::KIND_USER, 0); |
||||
| 1220 | $host->load_data(); |
||||
| 1221 | |||||
| 1222 | $plugin = $host->get_plugin($plugin_name); |
||||
| 1223 | |||||
| 1224 | if ($plugin) { |
||||
| 1225 | if (method_exists($plugin, $method)) { |
||||
| 1226 | if ($plugin->is_public_method($method)) { |
||||
| 1227 | $plugin->$method(); |
||||
| 1228 | } else { |
||||
| 1229 | user_error("PluginHandler[PUBLIC]: Requested private method '$method' of plugin '$plugin_name'.", E_USER_WARNING); |
||||
| 1230 | header("Content-Type: text/json"); |
||||
| 1231 | print error_json(6); |
||||
| 1232 | } |
||||
| 1233 | } else { |
||||
| 1234 | user_error("PluginHandler[PUBLIC]: Requested unknown method '$method' of plugin '$plugin_name'.", E_USER_WARNING); |
||||
| 1235 | header("Content-Type: text/json"); |
||||
| 1236 | print error_json(13); |
||||
| 1237 | } |
||||
| 1238 | } else { |
||||
| 1239 | user_error("PluginHandler[PUBLIC]: Requested method '$method' of unknown plugin '$plugin_name'.", E_USER_WARNING); |
||||
| 1240 | header("Content-Type: text/json"); |
||||
| 1241 | print error_json(14); |
||||
| 1242 | } |
||||
| 1243 | } |
||||
| 1244 | } |
||||
| 1245 |
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.