root/functions.php

Revision 2615, 155.4 kB (checked in by www-ttrss, 1 week ago)

[project @ add link to invert headline/article selection (closes #216)]

Line 
1 <?php
2
3 /*    if ($_GET["debug"]) {
4         define('DEFAULT_ERROR_LEVEL', E_ALL);
5     } else {
6         define('DEFAULT_ERROR_LEVEL', E_ERROR | E_WARNING | E_PARSE);
7     } */
8
9     require_once 'config.php';
10
11     if (DB_TYPE == "pgsql") {
12         define('SUBSTRING_FOR_DATE', 'SUBSTRING_FOR_DATE');
13     } else {
14         define('SUBSTRING_FOR_DATE', 'SUBSTRING');
15     }
16
17     /**
18      * Return available translations names.
19      *
20      * @access public
21      * @return array A array of available translations.
22      */
23     function get_translations() {
24         $tr = array(
25                     "auto"  => "Detect automatically",
26                     "en_US" => "English",
27                     "fr_FR" => "Franц╖ais",
28                     "hu_HU" => "Magyar (Hungarian)",
29                     "nb_NO" => "Norwegian bokmц╔l",
30                     "ru_RU" => "п═я┐я│я│п╨п╦п╧",
31                     "pt_BR" => "Portuguese/Brazil",
32                     "zh_CN" => "Simplified Chinese");
33
34         return $tr;
35     }
36
37     if (ENABLE_TRANSLATIONS == true) { // If translations are enabled.
38         require_once "accept-to-gettext.php";
39         require_once "gettext/gettext.inc";
40
41         function startup_gettext() {
42     
43             # Get locale from Accept-Language header
44             $lang = al2gt(array_keys(get_translations()), "text/html");
45
46             if (defined('_TRANSLATION_OVERRIDE_DEFAULT')) {
47                 $lang = _TRANSLATION_OVERRIDE_DEFAULT;
48             }
49
50             if ($_COOKIE["ttrss_lang"] && $_COOKIE["ttrss_lang"] != "auto") {               
51                 $lang = $_COOKIE["ttrss_lang"];
52             }
53
54             if ($lang) {
55                 if (defined('LC_MESSAGES')) {
56                     _setlocale(LC_MESSAGES, $lang);
57                 } else if (defined('LC_ALL')) {
58                     _setlocale(LC_ALL, $lang);
59                 } else {
60                     die("can't setlocale(): please set ENABLE_TRANSLATIONS to false in config.php");
61                 }
62                 _bindtextdomain("messages", "locale");
63                 _textdomain("messages");
64                 _bind_textdomain_codeset("messages", "UTF-8");
65             }
66         }
67
68         startup_gettext();
69
70     } else { // If translations are enabled.
71         function __($msg) {
72             return $msg;
73         }
74         function startup_gettext() {
75             // no-op
76             return true;
77         }
78     } // If translations are enabled.
79
80     require_once 'db-prefs.php';
81     require_once 'compat.php';
82     require_once 'errors.php';
83     require_once 'version.php';
84
85     require_once 'phpmailer/class.phpmailer.php';
86
87     define('MAGPIE_USER_AGENT_EXT', ' (Tiny Tiny RSS/' . VERSION . ')');
88     define('MAGPIE_OUTPUT_ENCODING', 'UTF-8');
89
90     require_once "simplepie/simplepie.inc";
91     require_once "magpierss/rss_fetch.inc";
92     require_once 'magpierss/rss_utils.inc';
93
94     /**
95      * Print a timestamped debug message.
96      *
97      * @param string $msg The debug message.
98      * @return void
99      */
100     function _debug($msg) {
101         $ts = strftime("%H:%M:%S", time());
102         if (function_exists('posix_getpid')) {
103             $ts = "$ts/" . posix_getpid();
104         }
105         print "[$ts] $msg\n";
106     } // function _debug
107
108     /**
109      * Purge a feed old posts.
110      *
111      * @param mixed $link A database connection.
112      * @param mixed $feed_id The id of the purged feed.
113      * @param mixed $purge_interval Olderness of purged posts.
114      * @param boolean $debug Set to True to enable the debug. False by default.
115      * @access public
116      * @return void
117      */
118     function purge_feed($link, $feed_id, $purge_interval, $debug = false) {
119
120         if (!$purge_interval) $purge_interval = feed_purge_interval($link, $feed_id);
121
122         $rows = -1;
123
124         $result = db_query($link,
125             "SELECT owner_uid FROM ttrss_feeds WHERE id = '$feed_id'");
126
127         $owner_uid = false;
128
129         if (db_num_rows($result) == 1) {
130             $owner_uid = db_fetch_result($result, 0, "owner_uid");
131         }
132
133         if (!$owner_uid) return;
134
135         $purge_unread = get_pref($link, "PURGE_UNREAD_ARTICLES",
136             $owner_uid, false);
137
138         if (!$purge_unread) $query_limit = " unread = false AND ";
139
140         if (DB_TYPE == "pgsql") {
141 /*            $result = db_query($link, "DELETE FROM ttrss_user_entries WHERE
142                 marked = false AND feed_id = '$feed_id' AND
143                 (SELECT date_entered FROM ttrss_entries WHERE
144                     id = ref_id) < NOW() - INTERVAL '$purge_interval days'"); */
145
146             $pg_version = get_pgsql_version($link);
147
148             if (preg_match("/^7\./", $pg_version) || preg_match("/^8\.0/", $pg_version)) {
149
150                 $result = db_query($link, "DELETE FROM ttrss_user_entries WHERE
151                     ttrss_entries.id = ref_id AND
152                     marked = false AND
153                     feed_id = '$feed_id' AND
154                     $query_limit
155                     ttrss_entries.date_entered < NOW() - INTERVAL '$purge_interval days'");
156
157             } else {
158
159                 $result = db_query($link, "DELETE FROM ttrss_user_entries
160                     USING ttrss_entries
161                     WHERE ttrss_entries.id = ref_id AND
162                     marked = false AND
163                     feed_id = '$feed_id' AND
164                     $query_limit
165                     ttrss_entries.date_entered < NOW() - INTERVAL '$purge_interval days'");
166             }
167
168             $rows = pg_affected_rows($result);
169             
170         } else {
171         
172 /*            $result = db_query($link, "DELETE FROM ttrss_user_entries WHERE
173                 marked = false AND feed_id = '$feed_id' AND
174                 (SELECT date_entered FROM ttrss_entries WHERE
175                     id = ref_id) < DATE_SUB(NOW(), INTERVAL $purge_interval DAY)"); */
176
177             $result = db_query($link, "DELETE FROM ttrss_user_entries
178                 USING ttrss_user_entries, ttrss_entries
179                 WHERE ttrss_entries.id = ref_id AND
180                 marked = false AND
181                 feed_id = '$feed_id' AND
182                 $query_limit
183                 ttrss_entries.date_entered < DATE_SUB(NOW(), INTERVAL $purge_interval DAY)");
184                     
185             $rows = mysql_affected_rows($link);
186
187         }
188
189         if ($debug) {
190             _debug("Purged feed $feed_id ($purge_interval): deleted $rows articles");
191         }
192     } // function purge_feed
193
194     /**
195      * Purge old posts from old feeds.
196      *
197      * @param mixed $link A database connection
198      * @param boolean $do_output Set to true to enable printed output, false by default.
199      * @param integer $limit The maximal number of removed posts.
200      * @access public
201      * @return void
202      */
203     function global_purge_old_posts($link, $do_output = false, $limit = false) {
204
205         $random_qpart = sql_random_function();
206
207         if ($limit) {
208             $limit_qpart = "LIMIT $limit";
209         } else {
210             $limit_qpart = "";
211         }
212         
213         $result = db_query($link,
214             "SELECT id,purge_interval,owner_uid FROM ttrss_feeds
215                 ORDER BY $random_qpart $limit_qpart");
216
217         while ($line = db_fetch_assoc($result)) {
218
219             $feed_id = $line["id"];
220             $purge_interval = $line["purge_interval"];
221             $owner_uid = $line["owner_uid"];
222
223             if ($purge_interval == 0) {
224             
225                 $tmp_result = db_query($link,
226                     "SELECT value FROM ttrss_user_prefs WHERE
227                         pref_name = 'PURGE_OLD_DAYS' AND owner_uid = '$owner_uid'");
228
229                 if (db_num_rows($tmp_result) != 0) {           
230                     $purge_interval = db_fetch_result($tmp_result, 0, "value");
231                 }
232             }
233
234             if ($do_output) {
235 //                print "Feed $feed_id: purge interval = $purge_interval\n";
236             }
237
238             if ($purge_interval > 0) {
239                 purge_feed($link, $feed_id, $purge_interval, $do_output);
240             }
241         }   
242
243         // purge orphaned posts in main content table
244         $result = db_query($link, "DELETE FROM ttrss_entries WHERE
245             (SELECT COUNT(int_id) FROM ttrss_user_entries WHERE ref_id = id) = 0");
246
247         if ($do_output) {
248             $rows = db_affected_rows($link, $result);
249             _debug("Purged $rows orphaned posts.");
250         }
251
252     } // function global_purge_old_posts
253
254     function feed_purge_interval($link, $feed_id) {
255
256         $result = db_query($link, "SELECT purge_interval, owner_uid FROM ttrss_feeds
257             WHERE id = '$feed_id'");
258
259         if (db_num_rows($result) == 1) {
260             $purge_interval = db_fetch_result($result, 0, "purge_interval");
261             $owner_uid = db_fetch_result($result, 0, "owner_uid");
262
263             if ($purge_interval == 0) $purge_interval = get_pref($link,
264                 'PURGE_OLD_DAYS', $user_id);
265
266             return $purge_interval;
267
268         } else {
269             return -1;
270         }
271     }
272
273     function purge_old_posts($link) {
274
275         $user_id = $_SESSION["uid"];
276     
277         $result = db_query($link, "SELECT id,purge_interval FROM ttrss_feeds
278             WHERE owner_uid = '$user_id'");
279
280         while ($line = db_fetch_assoc($result)) {
281
282             $feed_id = $line["id"];
283             $purge_interval = $line["purge_interval"];
284
285             if ($purge_interval == 0) $purge_interval = get_pref($link, 'PURGE_OLD_DAYS');
286
287             if ($purge_interval > 0) {
288                 purge_feed($link, $feed_id, $purge_interval);
289             }
290         }   
291
292         // purge orphaned posts in main content table
293         db_query($link, "DELETE FROM ttrss_entries WHERE
294             (SELECT COUNT(int_id) FROM ttrss_user_entries WHERE ref_id = id) = 0");
295     }
296
297     function get_feed_update_interval($link, $feed_id) {
298         $result = db_query($link, "SELECT owner_uid, update_interval FROM
299             ttrss_feeds WHERE id = '$feed_id'");
300
301         if (db_num_rows($result) == 1) {
302             $update_interval = db_fetch_result($result, 0, "update_interval");
303             $owner_uid = db_fetch_result($result, 0, "owner_uid");
304
305             if ($update_interval != 0) {
306                 return $update_interval;
307             } else {
308                 return get_pref($link, 'DEFAULT_UPDATE_INTERVAL', $owner_uid, false);
309             }
310
311         } else {
312             return -1;
313         }
314     }
315
316     function update_all_feeds($link, $fetch, $user_id = false, $force_daemon = false) {
317
318         if (WEB_DEMO_MODE) return;
319
320         if (!$user_id) {
321             $user_id = $_SESSION["uid"];
322             purge_old_posts($link);
323         }
324
325 //        db_query($link, "BEGIN");
326
327         if (MAX_UPDATE_TIME > 0) {
328             if (DB_TYPE == "mysql") {
329                 $q_order = "RAND()";
330             } else {
331                 $q_order = "RANDOM()";
332             }
333         } else {
334             $q_order = "last_updated DESC";
335         }
336
337         $result = db_query($link, "SELECT feed_url,id,
338             ".SUBSTRING_FOR_DATE."(last_updated,1,19) AS last_updated,
339             update_interval FROM ttrss_feeds WHERE owner_uid = '$user_id'
340             ORDER BY $q_order");
341
342         $upd_start = time();
343
344         while ($line = db_fetch_assoc($result)) {
345             $upd_intl = $line["update_interval"];
346
347             if (!$upd_intl || $upd_intl == 0) {
348                 $upd_intl = get_pref($link, 'DEFAULT_UPDATE_INTERVAL', $user_id, false);
349             }
350
351             if ($upd_intl < 0) {
352                 // Updates for this feed are disabled
353                 continue;
354             }
355
356             if ($fetch || (!$line["last_updated"] ||
357                 time() - strtotime($line["last_updated"]) > ($upd_intl * 60))) {
358
359 //                print "<!-- feed: ".$line["feed_url"]." -->";
360
361                 update_rss_feed($link, $line["feed_url"], $line["id"], $force_daemon);
362
363                 $upd_elapsed = time() - $upd_start;
364
365                 if (MAX_UPDATE_TIME > 0 && $upd_elapsed > MAX_UPDATE_TIME) {
366                     return;
367                 }
368             }
369         }
370
371 //        db_query($link, "COMMIT");
372
373     }
374
375     function fetch_file_contents($url) {
376         if (USE_CURL_FOR_ICONS) {
377             $tmpfile = tempnam(TMP_DIRECTORY, "ttrss-tmp");
378
379             $ch = curl_init($url);
380             $fp = fopen($tmpfile, "w");
381
382             if ($fp) {
383                 curl_setopt($ch, CURLOPT_FILE, $fp);
384                 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15);
385                 curl_setopt($ch, CURLOPT_TIMEOUT, 45);
386                 curl_exec($ch);
387                 curl_close($ch);
388                 fclose($fp);                   
389             }
390
391             $contents file_get_contents($tmpfile);
392             unlink($tmpfile);
393
394             return $contents;
395
396         } else {
397             return file_get_contents($url);
398         }
399
400     }
401
402     /**
403      * Try to determine the favicon URL for a feed.
404      * adapted from wordpress favicon plugin by Jeff Minard (http://thecodepro.com/)
405      * http://dev.wp-plugins.org/file/favatars/trunk/favatars.php
406      *
407      * @param string $url A feed or page URL
408      * @access public
409      * @return mixed The favicon URL, or false if none was found.
410      */
411     function get_favicon_url($url) {
412
413         if ($html = @fetch_file_contents($url)) {
414
415             if ( preg_match('/<link[^>]+rel="(?:shortcut )?icon"[^>]+?href="([^"]+?)"/si', $html, $matches)) {
416                 // Attempt to grab a favicon link from their webpage url
417                 $linkUrl = html_entity_decode($matches[1]);
418
419                 if (substr($linkUrl, 0, 1) == '/') {
420                     $urlParts = parse_url($url);
421                     $faviconURL = $urlParts['scheme'].'://'.$urlParts['host'].$linkUrl;
422                 } else if (substr($linkUrl, 0, 7) == 'http://') {
423                     $faviconURL = $linkUrl;
424                 } else if (substr($url, -1, 1) == '/') {
425                     $faviconURL = $url.$linkUrl;
426                 } else {
427                     $faviconURL = $url.'/'.$linkUrl;
428                 }
429
430             } else {
431                 // If unsuccessful, attempt to "guess" the favicon location
432                 $urlParts = parse_url($url);
433                 $faviconURL = $urlParts['scheme'].'://'.$urlParts['host'].'/favicon.ico';
434             }
435         }
436
437         // Run a test to see if what we have attempted to get actually exists.
438         if(USE_CURL_FOR_ICONS || url_validate($faviconURL)) {
439             return $faviconURL;
440         } else {
441             return false;
442         }
443     } // function get_favicon_url
444
445     /**
446      * Check if a link is a valid and working URL.
447      *
448      * @param mixed $link A URL to check
449      * @access public
450      * @return boolean True if the URL is valid, false otherwise.
451      */
452     function url_validate($link) {
453                 
454         $url_parts = @parse_url($link);
455
456         if ( empty( $url_parts["host"] ) )
457                 return false;
458
459         if ( !empty( $url_parts["path"] ) ) {
460                 $documentpath = $url_parts["path"];
461         } else {
462                 $documentpath = "/";
463         }
464
465         if ( !empty( $url_parts["query"] ) )
466                 $documentpath .= "?" . $url_parts["query"];
467
468         $host = $url_parts["host"];
469         $port = $url_parts["port"];
470         
471         if ( empty($port) )
472                 $port = "80";
473
474         $socket = @fsockopen( $host, $port, $errno, $errstr, 30 );
475         
476         if ( !$socket )
477                 return false;
478                 
479         fwrite ($socket, "HEAD ".$documentpath." HTTP/1.0\r\nHost: $host\r\n\r\n");
480
481         $http_response = fgets( $socket, 22 );
482
483         $responses = "/(200 OK)|(30[0-9] Moved)/";
484         if ( preg_match($responses, $http_response) ) {
485                 fclose($socket);
486                 return true;
487         } else {
488                 return false;
489         }
490
491     } // function url_validate
492
493     function check_feed_favicon($site_url, $feed, $link) {
494         $favicon_url = get_favicon_url($site_url);
495
496 #        print "FAVICON [$site_url]: $favicon_url\n";
497
498         error_reporting(0);
499
500         $icon_file = ICONS_DIR . "/$feed.ico";
501
502         if ($favicon_url && !file_exists($icon_file)) {
503             $contents = fetch_file_contents($favicon_url);
504
505             $fp = fopen($icon_file, "w");
506
507             if ($fp) {
508                 fwrite($fp, $contents);
509                 fclose($fp);
510                 chmod($icon_file, 0644);
511             }
512         }
513
514         error_reporting(DEFAULT_ERROR_LEVEL);
515
516     }
517
518     function update_rss_feed($link, $feed_url, $feed, $ignore_daemon = false) {
519
520         if (!$_GET["daemon"] && !$ignore_daemon) {
521             return false;
522         }
523
524         if (defined('DAEMON_EXTENDED_DEBUG') || $_GET['xdebug']) {
525             _debug("update_rss_feed: start");
526         }
527
528         if (!$ignore_daemon) {
529
530             if (DB_TYPE == "pgsql") {
531                     $updstart_thresh_qpart = "(ttrss_feeds.last_update_started IS NULL OR ttrss_feeds.last_update_started < NOW() - INTERVAL '120 seconds')";
532                 } else {
533                     $updstart_thresh_qpart = "(ttrss_feeds.last_update_started IS NULL OR ttrss_feeds.last_update_started < DATE_SUB(NOW(), INTERVAL 120 SECOND))";
534                 }           
535     
536             $result = db_query($link, "SELECT id,update_interval,auth_login,
537                 auth_pass,cache_images,update_method
538                 FROM ttrss_feeds WHERE id = '$feed' AND $updstart_thresh_qpart");
539
540         } else {
541
542             $result = db_query($link, "SELECT id,update_interval,auth_login,
543                 auth_pass,cache_images,update_method
544                 FROM ttrss_feeds WHERE id = '$feed'");
545
546         }
547
548         if (db_num_rows($result) == 0) {
549             if (