2014-03-05 12:48:41 +00:00
< ? php
function make_init_params () {
$params = array ();
foreach ( array ( " ON_CATCHUP_SHOW_NEXT_FEED " , " HIDE_READ_FEEDS " ,
" ENABLE_FEED_CATS " , " FEEDS_SORT_BY_UNREAD " , " CONFIRM_FEED_CATCHUP " ,
" CDM_AUTO_CATCHUP " , " FRESH_ARTICLE_MAX_AGE " ,
" HIDE_READ_SHOWS_SPECIAL " , " COMBINED_DISPLAY_MODE " ) as $param ) {
$params [ strtolower ( $param )] = ( int ) get_pref ( $param );
}
$params [ " icons_url " ] = ICONS_URL ;
$params [ " cookie_lifetime " ] = SESSION_COOKIE_LIFETIME ;
$params [ " default_view_mode " ] = get_pref ( " _DEFAULT_VIEW_MODE " );
$params [ " default_view_limit " ] = ( int ) get_pref ( " _DEFAULT_VIEW_LIMIT " );
$params [ " default_view_order_by " ] = get_pref ( " _DEFAULT_VIEW_ORDER_BY " );
$params [ " bw_limit " ] = ( int ) $_SESSION [ " bw_limit " ];
$params [ " label_base_index " ] = ( int ) LABEL_BASE_INDEX ;
2014-12-09 12:16:53 +00:00
$theme = get_pref ( " USER_CSS_THEME " , false , false );
$params [ " theme " ] = theme_valid ( " $theme " ) ? $theme : " " ;
2014-03-14 11:06:37 +00:00
$params [ " plugins " ] = implode ( " , " , PluginHost :: getInstance () -> get_plugin_names ());
2014-03-05 12:48:41 +00:00
2014-03-14 10:38:51 +00:00
$params [ " php_platform " ] = PHP_OS ;
$params [ " php_version " ] = PHP_VERSION ;
$params [ " sanity_checksum " ] = sha1 ( file_get_contents ( " include/sanity_check.php " ));
2014-03-05 12:48:41 +00:00
$result = db_query ( " SELECT MAX(id) AS mid, COUNT(*) AS nf FROM
ttrss_feeds WHERE owner_uid = " . $_SESSION["uid"] );
$max_feed_id = db_fetch_result ( $result , 0 , " mid " );
$num_feeds = db_fetch_result ( $result , 0 , " nf " );
$params [ " max_feed_id " ] = ( int ) $max_feed_id ;
$params [ " num_feeds " ] = ( int ) $num_feeds ;
$params [ " hotkeys " ] = get_hotkeys_map ();
$params [ " csrf_token " ] = $_SESSION [ " csrf_token " ];
$params [ " widescreen " ] = ( int ) $_COOKIE [ " ttrss_widescreen " ];
$params [ 'simple_update' ] = defined ( 'SIMPLE_UPDATE_MODE' ) && SIMPLE_UPDATE_MODE ;
return $params ;
}
function get_hotkeys_info () {
$hotkeys = array (
__ ( " Navigation " ) => array (
" next_feed " => __ ( " Open next feed " ),
" prev_feed " => __ ( " Open previous feed " ),
" next_article " => __ ( " Open next article " ),
" prev_article " => __ ( " Open previous article " ),
" next_article_noscroll " => __ ( " Open next article (don't scroll long articles) " ),
" prev_article_noscroll " => __ ( " Open previous article (don't scroll long articles) " ),
" next_article_noexpand " => __ ( " Move to next article (don't expand or mark read) " ),
" prev_article_noexpand " => __ ( " Move to previous article (don't expand or mark read) " ),
" search_dialog " => __ ( " Show search dialog " )),
__ ( " Article " ) => array (
" toggle_mark " => __ ( " Toggle starred " ),
" toggle_publ " => __ ( " Toggle published " ),
" toggle_unread " => __ ( " Toggle unread " ),
" edit_tags " => __ ( " Edit tags " ),
" dismiss_selected " => __ ( " Dismiss selected " ),
" dismiss_read " => __ ( " Dismiss read " ),
" open_in_new_window " => __ ( " Open in new window " ),
" catchup_below " => __ ( " Mark below as read " ),
" catchup_above " => __ ( " Mark above as read " ),
" article_scroll_down " => __ ( " Scroll down " ),
" article_scroll_up " => __ ( " Scroll up " ),
" select_article_cursor " => __ ( " Select article under cursor " ),
" email_article " => __ ( " Email article " ),
" close_article " => __ ( " Close/collapse article " ),
" toggle_expand " => __ ( " Toggle article expansion (combined mode) " ),
" toggle_widescreen " => __ ( " Toggle widescreen mode " ),
" toggle_embed_original " => __ ( " Toggle embed original " )),
__ ( " Article selection " ) => array (
" select_all " => __ ( " Select all articles " ),
" select_unread " => __ ( " Select unread " ),
" select_marked " => __ ( " Select starred " ),
" select_published " => __ ( " Select published " ),
" select_invert " => __ ( " Invert selection " ),
" select_none " => __ ( " Deselect everything " )),
__ ( " Feed " ) => array (
" feed_refresh " => __ ( " Refresh current feed " ),
" feed_unhide_read " => __ ( " Un/hide read feeds " ),
" feed_subscribe " => __ ( " Subscribe to feed " ),
" feed_edit " => __ ( " Edit feed " ),
" feed_catchup " => __ ( " Mark as read " ),
" feed_reverse " => __ ( " Reverse headlines " ),
" feed_debug_update " => __ ( " Debug feed update " ),
" catchup_all " => __ ( " Mark all feeds as read " ),
" cat_toggle_collapse " => __ ( " Un/collapse current category " ),
" toggle_combined_mode " => __ ( " Toggle combined mode " ),
" toggle_cdm_expanded " => __ ( " Toggle auto expand in combined mode " )),
__ ( " Go to " ) => array (
" goto_all " => __ ( " All articles " ),
" goto_fresh " => __ ( " Fresh " ),
" goto_marked " => __ ( " Starred " ),
" goto_published " => __ ( " Published " ),
" goto_tagcloud " => __ ( " Tag cloud " ),
" goto_prefs " => __ ( " Preferences " )),
__ ( " Other " ) => array (
" create_label " => __ ( " Create label " ),
" create_filter " => __ ( " Create filter " ),
" collapse_sidebar " => __ ( " Un/collapse sidebar " ),
" help_dialog " => __ ( " Show help dialog " ))
);
foreach ( PluginHost :: getInstance () -> get_hooks ( PluginHost :: HOOK_HOTKEY_INFO ) as $plugin ) {
$hotkeys = $plugin -> hook_hotkey_info ( $hotkeys );
}
return $hotkeys ;
}
function get_hotkeys_map () {
$hotkeys = array (
// "navigation" => array(
" k " => " next_feed " ,
" j " => " prev_feed " ,
" n " => " next_article " ,
" p " => " prev_article " ,
" (38)|up " => " prev_article " ,
" (40)|down " => " next_article " ,
// "^(38)|Ctrl-up" => "prev_article_noscroll",
// "^(40)|Ctrl-down" => "next_article_noscroll",
" (191)|/ " => " search_dialog " ,
// "article" => array(
" s " => " toggle_mark " ,
" *s " => " toggle_publ " ,
" u " => " toggle_unread " ,
" *t " => " edit_tags " ,
" *d " => " dismiss_selected " ,
" *x " => " dismiss_read " ,
" o " => " open_in_new_window " ,
" c p " => " catchup_below " ,
" c n " => " catchup_above " ,
" *n " => " article_scroll_down " ,
" *p " => " article_scroll_up " ,
" *(38)|Shift+up " => " article_scroll_up " ,
" *(40)|Shift+down " => " article_scroll_down " ,
" a *w " => " toggle_widescreen " ,
" a e " => " toggle_embed_original " ,
" e " => " email_article " ,
" a q " => " close_article " ,
// "article_selection" => array(
" a a " => " select_all " ,
" a u " => " select_unread " ,
" a *u " => " select_marked " ,
" a p " => " select_published " ,
" a i " => " select_invert " ,
" a n " => " select_none " ,
// "feed" => array(
" f r " => " feed_refresh " ,
" f a " => " feed_unhide_read " ,
" f s " => " feed_subscribe " ,
" f e " => " feed_edit " ,
" f q " => " feed_catchup " ,
" f x " => " feed_reverse " ,
" f *d " => " feed_debug_update " ,
" f *c " => " toggle_combined_mode " ,
" f c " => " toggle_cdm_expanded " ,
" *q " => " catchup_all " ,
" x " => " cat_toggle_collapse " ,
// "goto" => array(
" g a " => " goto_all " ,
" g f " => " goto_fresh " ,
" g s " => " goto_marked " ,
" g p " => " goto_published " ,
" g t " => " goto_tagcloud " ,
" g *p " => " goto_prefs " ,
// "other" => array(
" (9)|Tab " => " select_article_cursor " , // tab
" c l " => " create_label " ,
" c f " => " create_filter " ,
" c s " => " collapse_sidebar " ,
" ^(191)|Ctrl+/ " => " help_dialog " ,
);
if ( get_pref ( 'COMBINED_DISPLAY_MODE' )) {
$hotkeys [ " ^(38)|Ctrl-up " ] = " prev_article_noscroll " ;
$hotkeys [ " ^(40)|Ctrl-down " ] = " next_article_noscroll " ;
}
foreach ( PluginHost :: getInstance () -> get_hooks ( PluginHost :: HOOK_HOTKEY_MAP ) as $plugin ) {
$hotkeys = $plugin -> hook_hotkey_map ( $hotkeys );
}
$prefixes = array ();
foreach ( array_keys ( $hotkeys ) as $hotkey ) {
$pair = explode ( " " , $hotkey , 2 );
if ( count ( $pair ) > 1 && ! in_array ( $pair [ 0 ], $prefixes )) {
array_push ( $prefixes , $pair [ 0 ]);
}
}
return array ( $prefixes , $hotkeys );
}
2015-02-03 11:39:15 +00:00
function check_for_update () {
if ( defined ( " GIT_VERSION_TIMESTAMP " )) {
$content = @ fetch_file_contents ( " http://tt-rss.org/version.json " );
if ( $content ) {
$content = json_decode ( $content , true );
if ( $content && isset ( $content [ " changeset " ])) {
if (( int ) GIT_VERSION_TIMESTAMP < ( int ) $content [ " changeset " ][ " timestamp " ] &&
GIT_VERSION_HEAD != $content [ " changeset " ][ " id " ]) {
return $content [ " changeset " ][ " id " ];
}
}
}
}
2015-02-03 11:42:20 +00:00
return " " ;
2015-02-03 11:39:15 +00:00
}
2014-03-05 12:48:41 +00:00
function make_runtime_info () {
$data = array ();
$result = db_query ( " SELECT MAX(id) AS mid, COUNT(*) AS nf FROM
ttrss_feeds WHERE owner_uid = " . $_SESSION["uid"] );
$max_feed_id = db_fetch_result ( $result , 0 , " mid " );
$num_feeds = db_fetch_result ( $result , 0 , " nf " );
$data [ " max_feed_id " ] = ( int ) $max_feed_id ;
$data [ " num_feeds " ] = ( int ) $num_feeds ;
$data [ 'last_article_id' ] = getLastArticleId ();
$data [ 'cdm_expanded' ] = get_pref ( 'CDM_EXPANDED' );
$data [ 'dep_ts' ] = calculate_dep_timestamp ();
$data [ 'reload_on_ts_change' ] = ! defined ( '_NO_RELOAD_ON_TS_CHANGE' );
2015-02-03 11:39:15 +00:00
2015-02-03 11:46:51 +00:00
if ( CHECK_FOR_UPDATES && $_SESSION [ " last_version_check " ] + 86400 + rand ( - 1000 , 1000 ) < time ()) {
2015-02-03 11:39:15 +00:00
$update_result = @ check_for_update ();
$data [ " update_result " ] = $update_result ;
$_SESSION [ " last_version_check " ] = time ();
}
2014-03-05 12:48:41 +00:00
if ( file_exists ( LOCK_DIRECTORY . " /update_daemon.lock " )) {
$data [ 'daemon_is_running' ] = ( int ) file_is_locked ( " update_daemon.lock " );
if ( time () - $_SESSION [ " daemon_stamp_check " ] > 30 ) {
$stamp = ( int ) @ file_get_contents ( LOCK_DIRECTORY . " /update_daemon.stamp " );
if ( $stamp ) {
$stamp_delta = time () - $stamp ;
if ( $stamp_delta > 1800 ) {
$stamp_check = 0 ;
} else {
$stamp_check = 1 ;
$_SESSION [ " daemon_stamp_check " ] = time ();
}
$data [ 'daemon_stamp_ok' ] = $stamp_check ;
$stamp_fmt = date ( " Y.m.d, G:i " , $stamp );
$data [ 'daemon_stamp' ] = $stamp_fmt ;
}
}
}
return $data ;
}
function search_to_sql ( $search ) {
$search_query_part = " " ;
$keywords = str_getcsv ( $search , " " );
$query_keywords = array ();
$search_words = array ();
foreach ( $keywords as $k ) {
if ( strpos ( $k , " - " ) === 0 ) {
$k = substr ( $k , 1 );
$not = " NOT " ;
} else {
$not = " " ;
}
$commandpair = explode ( " : " , mb_strtolower ( $k ), 2 );
switch ( $commandpair [ 0 ]) {
case " title " :
if ( $commandpair [ 1 ]) {
array_push ( $query_keywords , " ( $not (LOWER(ttrss_entries.title) LIKE '% " .
db_escape_string ( mb_strtolower ( $commandpair [ 1 ])) . " %')) " );
} else {
array_push ( $query_keywords , " (UPPER(ttrss_entries.title) $not LIKE UPPER('% $k %')
OR UPPER ( ttrss_entries . content ) $not LIKE UPPER ( '%$k%' )) " );
array_push ( $search_words , $k );
}
break ;
case " author " :
if ( $commandpair [ 1 ]) {
array_push ( $query_keywords , " ( $not (LOWER(author) LIKE '% " .
db_escape_string ( mb_strtolower ( $commandpair [ 1 ])) . " %')) " );
} else {
array_push ( $query_keywords , " (UPPER(ttrss_entries.title) $not LIKE UPPER('% $k %')
OR UPPER ( ttrss_entries . content ) $not LIKE UPPER ( '%$k%' )) " );
array_push ( $search_words , $k );
}
break ;
case " note " :
if ( $commandpair [ 1 ]) {
if ( $commandpair [ 1 ] == " true " )
array_push ( $query_keywords , " ( $not (note IS NOT NULL AND note != '')) " );
else if ( $commandpair [ 1 ] == " false " )
array_push ( $query_keywords , " ( $not (note IS NULL OR note = '')) " );
else
array_push ( $query_keywords , " ( $not (LOWER(note) LIKE '% " .
db_escape_string ( mb_strtolower ( $commandpair [ 1 ])) . " %')) " );
} else {
array_push ( $query_keywords , " (UPPER(ttrss_entries.title) $not LIKE UPPER('% $k %')
OR UPPER ( ttrss_entries . content ) $not LIKE UPPER ( '%$k%' )) " );
if ( ! $not ) array_push ( $search_words , $k );
}
break ;
case " star " :
if ( $commandpair [ 1 ]) {
if ( $commandpair [ 1 ] == " true " )
array_push ( $query_keywords , " ( $not (marked = true)) " );
else
array_push ( $query_keywords , " ( $not (marked = false)) " );
} else {
array_push ( $query_keywords , " (UPPER(ttrss_entries.title) $not LIKE UPPER('% $k %')
OR UPPER ( ttrss_entries . content ) $not LIKE UPPER ( '%$k%' )) " );
if ( ! $not ) array_push ( $search_words , $k );
}
break ;
case " pub " :
if ( $commandpair [ 1 ]) {
if ( $commandpair [ 1 ] == " true " )
array_push ( $query_keywords , " ( $not (published = true)) " );
else
array_push ( $query_keywords , " ( $not (published = false)) " );
} else {
array_push ( $query_keywords , " (UPPER(ttrss_entries.title) $not LIKE UPPER('% $k %')
OR UPPER ( ttrss_entries . content ) $not LIKE UPPER ( '%$k%' )) " );
if ( ! $not ) array_push ( $search_words , $k );
}
2015-03-05 13:26:10 +00:00
break ;
case " unread " :
if ( $commandpair [ 1 ]) {
if ( $commandpair [ 1 ] == " true " )
array_push ( $query_keywords , " ( $not (unread = true)) " );
else
array_push ( $query_keywords , " ( $not (unread = false)) " );
} else {
array_push ( $query_keywords , " (UPPER(ttrss_entries.title) $not LIKE UPPER('% $k %')
OR UPPER ( ttrss_entries . content ) $not LIKE UPPER ( '%$k%' )) " );
if ( ! $not ) array_push ( $search_words , $k );
}
2014-03-05 12:48:41 +00:00
break ;
default :
if ( strpos ( $k , " @ " ) === 0 ) {
$user_tz_string = get_pref ( 'USER_TIMEZONE' , $_SESSION [ 'uid' ]);
$orig_ts = strtotime ( substr ( $k , 1 ));
$k = date ( " Y-m-d " , convert_timestamp ( $orig_ts , $user_tz_string , 'UTC' ));
//$k = date("Y-m-d", strtotime(substr($k, 1)));
array_push ( $query_keywords , " ( " . SUBSTRING_FOR_DATE . " (updated,1,LENGTH(' $k ')) $not = ' $k ') " );
} else {
array_push ( $query_keywords , " (UPPER(ttrss_entries.title) $not LIKE UPPER('% $k %')
OR UPPER ( ttrss_entries . content ) $not LIKE UPPER ( '%$k%' )) " );
if ( ! $not ) array_push ( $search_words , $k );
}
}
}
$search_query_part = implode ( " AND " , $query_keywords );
return array ( $search_query_part , $search_words );
}
function getParentCategories ( $cat , $owner_uid ) {
$rv = array ();
$result = db_query ( " SELECT parent_cat FROM ttrss_feed_categories
WHERE id = '$cat' AND parent_cat IS NOT NULL AND owner_uid = $owner_uid " );
while ( $line = db_fetch_assoc ( $result )) {
array_push ( $rv , $line [ " parent_cat " ]);
$rv = array_merge ( $rv , getParentCategories ( $line [ " parent_cat " ], $owner_uid ));
}
return $rv ;
}
function getChildCategories ( $cat , $owner_uid ) {
$rv = array ();
$result = db_query ( " SELECT id FROM ttrss_feed_categories
WHERE parent_cat = '$cat' AND owner_uid = $owner_uid " );
while ( $line = db_fetch_assoc ( $result )) {
array_push ( $rv , $line [ " id " ]);
$rv = array_merge ( $rv , getChildCategories ( $line [ " id " ], $owner_uid ));
}
return $rv ;
}
2015-07-07 12:59:32 +00:00
// $search_mode is obsolete/unused
2014-03-09 17:48:22 +00:00
function queryFeedHeadlines ( $feed , $limit , $view_mode , $cat_view , $search , $search_mode , $override_order = false , $offset = 0 , $owner_uid = 0 , $filter = false , $since_id = 0 , $include_children = false , $ignore_vfeed_group = false , $override_strategy = false , $override_vfeed = false , $start_ts = false ) {
2014-03-05 12:48:41 +00:00
if ( ! $owner_uid ) $owner_uid = $_SESSION [ " uid " ];
$ext_tables_part = " " ;
$search_words = array ();
if ( $search ) {
2014-04-15 04:18:33 +00:00
foreach ( PluginHost :: getInstance () -> get_hooks ( PluginHost :: HOOK_SEARCH ) as $plugin ) {
list ( $search_query_part , $search_words ) = $plugin -> hook_search ( $search );
2014-04-23 03:28:32 +00:00
break ;
2014-04-15 04:18:33 +00:00
}
2014-03-05 12:48:41 +00:00
2014-04-15 04:18:33 +00:00
// fall back in case of no plugins
if ( ! $search_query_part ) {
2014-03-05 12:48:41 +00:00
list ( $search_query_part , $search_words ) = search_to_sql ( $search );
}
2014-04-15 04:18:33 +00:00
$search_query_part .= " AND " ;
2014-03-05 12:48:41 +00:00
} else {
$search_query_part = " " ;
}
if ( $filter ) {
if ( DB_TYPE == " pgsql " ) {
$query_strategy_part .= " AND updated > NOW() - INTERVAL '14 days' " ;
} else {
$query_strategy_part .= " AND updated > DATE_SUB(NOW(), INTERVAL 14 DAY) " ;
}
$override_order = " updated DESC " ;
$filter_query_part = filter_to_sql ( $filter , $owner_uid );
// Try to check if SQL regexp implementation chokes on a valid regexp
2014-06-19 08:29:48 +00:00
$result = db_query ( " SELECT true AS true_val
FROM ttrss_entries
JOIN ttrss_user_entries ON ttrss_entries . id = ttrss_user_entries . ref_id
JOIN ttrss_feeds ON ttrss_feeds . id = ttrss_user_entries . feed_id
2014-03-05 12:48:41 +00:00
WHERE $filter_query_part LIMIT 1 " , false);
if ( $result ) {
$test = db_fetch_result ( $result , 0 , " true_val " );
if ( ! $test ) {
$filter_query_part = " false AND " ;
} else {
$filter_query_part .= " AND " ;
}
} else {
$filter_query_part = " false AND " ;
}
} else {
$filter_query_part = " " ;
}
if ( $since_id ) {
$since_id_part = " ttrss_entries.id > $since_id AND " ;
} else {
$since_id_part = " " ;
}
$view_query_part = " " ;
if ( $view_mode == " adaptive " ) {
if ( $search ) {
$view_query_part = " " ;
} else if ( $feed != - 1 ) {
$unread = getFeedUnread ( $feed , $cat_view );
if ( $cat_view && $feed > 0 && $include_children )
$unread += getCategoryChildrenUnread ( $feed );
if ( $unread > 0 )
$view_query_part = " unread = true AND " ;
}
}
if ( $view_mode == " marked " ) {
$view_query_part = " marked = true AND " ;
}
if ( $view_mode == " has_note " ) {
$view_query_part = " (note IS NOT NULL AND note != '') AND " ;
}
if ( $view_mode == " published " ) {
$view_query_part = " published = true AND " ;
}
if ( $view_mode == " unread " && $feed != - 6 ) {
$view_query_part = " unread = true AND " ;
}
if ( $limit > 0 ) {
$limit_query_part = " LIMIT " . $limit ;
}
$allow_archived = false ;
$vfeed_query_part = " " ;
/* tags */
2015-07-07 12:59:32 +00:00
if ( ! is_numeric ( $feed )) {
2014-03-05 12:48:41 +00:00
$query_strategy_part = " true " ;
$vfeed_query_part = " (SELECT title FROM ttrss_feeds WHERE
id = feed_id ) as feed_title , " ;
} else if ( $feed > 0 ) {
if ( $cat_view ) {
if ( $feed > 0 ) {
if ( $include_children ) {
# sub-cats
$subcats = getChildCategories ( $feed , $owner_uid );
array_push ( $subcats , $feed );
$query_strategy_part = " cat_id IN ( " .
implode ( " , " , $subcats ) . " ) " ;
} else {
$query_strategy_part = " cat_id = ' $feed ' " ;
}
} else {
$query_strategy_part = " cat_id IS NULL " ;
}
$vfeed_query_part = " ttrss_feeds.title AS feed_title, " ;
} else {
$query_strategy_part = " feed_id = ' $feed ' " ;
}
} else if ( $feed == 0 && ! $cat_view ) { // archive virtual feed
$query_strategy_part = " feed_id IS NULL " ;
$allow_archived = true ;
} else if ( $feed == 0 && $cat_view ) { // uncategorized
$query_strategy_part = " cat_id IS NULL AND feed_id IS NOT NULL " ;
$vfeed_query_part = " ttrss_feeds.title AS feed_title, " ;
} else if ( $feed == - 1 ) { // starred virtual feed
$query_strategy_part = " marked = true " ;
$vfeed_query_part = " ttrss_feeds.title AS feed_title, " ;
$allow_archived = true ;
if ( ! $override_order ) {
$override_order = " last_marked DESC, date_entered DESC, updated DESC " ;
}
} else if ( $feed == - 2 ) { // published virtual feed OR labels category
if ( ! $cat_view ) {
$query_strategy_part = " published = true " ;
$vfeed_query_part = " ttrss_feeds.title AS feed_title, " ;
$allow_archived = true ;
if ( ! $override_order ) {
$override_order = " last_published DESC, date_entered DESC, updated DESC " ;
}
} else {
$vfeed_query_part = " ttrss_feeds.title AS feed_title, " ;
$ext_tables_part = " ,ttrss_labels2,ttrss_user_labels2 " ;
$query_strategy_part = " ttrss_labels2.id = ttrss_user_labels2.label_id AND
ttrss_user_labels2 . article_id = ref_id " ;
}
} else if ( $feed == - 6 ) { // recently read
$query_strategy_part = " unread = false AND last_read IS NOT NULL " ;
$vfeed_query_part = " ttrss_feeds.title AS feed_title, " ;
$allow_archived = true ;
2014-03-12 21:07:52 +00:00
$ignore_vfeed_group = true ;
2014-03-05 12:48:41 +00:00
if ( ! $override_order ) $override_order = " last_read DESC " ;
} else if ( $feed == - 3 ) { // fresh virtual feed
$query_strategy_part = " unread = true AND score >= 0 " ;
$intl = get_pref ( " FRESH_ARTICLE_MAX_AGE " , $owner_uid );
if ( DB_TYPE == " pgsql " ) {
$query_strategy_part .= " AND date_entered > NOW() - INTERVAL ' $intl hour' " ;
} else {
$query_strategy_part .= " AND date_entered > DATE_SUB(NOW(), INTERVAL $intl HOUR) " ;
}
$vfeed_query_part = " ttrss_feeds.title AS feed_title, " ;
} else if ( $feed == - 4 ) { // all articles virtual feed
$allow_archived = true ;
$query_strategy_part = " true " ;
$vfeed_query_part = " ttrss_feeds.title AS feed_title, " ;
} else if ( $feed <= LABEL_BASE_INDEX ) { // labels
$label_id = feed_to_label_id ( $feed );
$query_strategy_part = " label_id = ' $label_id ' AND
ttrss_labels2 . id = ttrss_user_labels2 . label_id AND
ttrss_user_labels2 . article_id = ref_id " ;
$vfeed_query_part = " ttrss_feeds.title AS feed_title, " ;
$ext_tables_part = " ,ttrss_labels2,ttrss_user_labels2 " ;
$allow_archived = true ;
} else {
$query_strategy_part = " true " ;
}
$order_by = " score DESC, date_entered DESC, updated DESC " ;
if ( $override_order ) {
$order_by = $override_order ;
}
if ( $override_strategy ) {
$query_strategy_part = $override_strategy ;
}
if ( $override_vfeed ) {
$vfeed_query_part = $override_vfeed ;
}
$feed_title = " " ;
if ( $search ) {
$feed_title = T_sprintf ( " Search results: %s " , $search );
} else {
if ( $cat_view ) {
$feed_title = getCategoryTitle ( $feed );
} else {
if ( is_numeric ( $feed ) && $feed > 0 ) {
$result = db_query ( " SELECT title,site_url,last_error,last_updated
FROM ttrss_feeds WHERE id = '$feed' AND owner_uid = $owner_uid " );
$feed_title = db_fetch_result ( $result , 0 , " title " );
$feed_site_url = db_fetch_result ( $result , 0 , " site_url " );
$last_error = db_fetch_result ( $result , 0 , " last_error " );
$last_updated = db_fetch_result ( $result , 0 , " last_updated " );
} else {
$feed_title = getFeedTitle ( $feed );
}
}
}
$content_query_part = " content, " ;
2015-07-07 12:59:32 +00:00
if ( $limit_query_part ) {
$offset_query_part = " OFFSET $offset " ;
} else {
$offset_query_part = " " ;
}
2014-03-05 12:48:41 +00:00
if ( is_numeric ( $feed )) {
// proper override_order applied above
if ( $vfeed_query_part && ! $ignore_vfeed_group && get_pref ( 'VFEED_GROUP_BY_FEED' , $owner_uid )) {
if ( ! $override_order ) {
$order_by = " ttrss_feeds.title, $order_by " ;
} else {
$order_by = " ttrss_feeds.title, $override_order " ;
}
}
if ( ! $allow_archived ) {
$from_qpart = " ttrss_entries,ttrss_user_entries,ttrss_feeds $ext_tables_part " ;
$feed_check_qpart = " ttrss_user_entries.feed_id = ttrss_feeds.id AND " ;
} else {
$from_qpart = " ttrss_entries $ext_tables_part ,ttrss_user_entries
LEFT JOIN ttrss_feeds ON ( feed_id = ttrss_feeds . id ) " ;
}
2015-07-07 12:59:32 +00:00
if ( $vfeed_query_part ) $vfeed_query_part .= " favicon_avg_color, " ;
2014-03-05 12:48:41 +00:00
2014-03-09 17:48:22 +00:00
if ( $start_ts ) {
$start_ts_formatted = date ( " Y/m/d H:i:s " , strtotime ( $start_ts ));
2014-03-09 22:19:26 +00:00
$start_ts_query_part = " date_entered >= ' $start_ts_formatted ' AND " ;
2014-03-09 17:48:22 +00:00
} else {
$start_ts_query_part = " " ;
}
2014-03-05 12:48:41 +00:00
$query = " SELECT DISTINCT
date_entered ,
guid ,
ttrss_entries . id , ttrss_entries . title ,
updated ,
label_cache ,
tag_cache ,
always_display_enclosures ,
site_url ,
note ,
num_comments ,
comments ,
int_id ,
uuid ,
lang ,
hide_images ,
unread , feed_id , marked , published , link , last_read , orig_feed_id ,
last_marked , last_published ,
$vfeed_query_part
$content_query_part
author , score
FROM
$from_qpart
WHERE
$feed_check_qpart
ttrss_user_entries . ref_id = ttrss_entries . id AND
ttrss_user_entries . owner_uid = '$owner_uid' AND
$search_query_part
2014-03-09 17:48:22 +00:00
$start_ts_query_part
2014-03-05 12:48:41 +00:00
$filter_query_part
$view_query_part
$since_id_part
$query_strategy_part ORDER BY $order_by
$limit_query_part $offset_query_part " ;
if ( $_REQUEST [ " debug " ]) print $query ;
$result = db_query ( $query );
} else {
// browsing by tag
2015-07-07 12:59:32 +00:00
$query = " SELECT DISTINCT
date_entered ,
guid ,
note ,
ttrss_entries . id as id ,
title ,
updated ,
unread ,
feed_id ,
orig_feed_id ,
marked ,
num_comments ,
comments ,
tag_cache ,
label_cache ,
link ,
lang ,
uuid ,
last_read ,
( SELECT hide_images FROM ttrss_feeds WHERE id = feed_id ) AS hide_images ,
last_marked , last_published ,
$since_id_part
$vfeed_query_part
$content_query_part
author , score
FROM ttrss_entries , ttrss_user_entries , ttrss_tags
WHERE
ref_id = ttrss_entries . id AND
ttrss_user_entries . owner_uid = $owner_uid AND
post_int_id = int_id AND
tag_name = '$feed' AND
$view_query_part
$search_query_part
$query_strategy_part ORDER BY $order_by
$limit_query_part $offset_query_part " ;
2014-03-05 12:48:41 +00:00
2015-07-07 12:59:32 +00:00
if ( $_REQUEST [ " debug " ]) print $query ;
2014-03-05 12:48:41 +00:00
2015-07-07 12:59:32 +00:00
$result = db_query ( $query );
2014-03-05 12:48:41 +00:00
}
return array ( $result , $feed_title , $feed_site_url , $last_error , $last_updated , $search_words );
}
2014-11-25 10:45:02 +00:00
function iframe_whitelisted ( $entry ) {
$whitelist = array ( " youtube.com " , " youtu.be " , " vimeo.com " );
@ $src = parse_url ( $entry -> getAttribute ( " src " ), PHP_URL_HOST );
if ( $src ) {
foreach ( $whitelist as $w ) {
if ( $src == $w || $src == " www. $w " )
return true ;
}
}
return false ;
}
2014-03-05 12:48:41 +00:00
function sanitize ( $str , $force_remove_images = false , $owner = false , $site_url = false , $highlight_words = false , $article_id = false ) {
if ( ! $owner ) $owner = $_SESSION [ " uid " ];
$res = trim ( $str ); if ( ! $res ) return '' ;
$charset_hack = ' < head >
< meta http - equiv = " Content-Type " content = " text/html; charset=utf-8 " />
</ head > ' ;
$res = trim ( $res ); if ( ! $res ) return '' ;
libxml_use_internal_errors ( true );
$doc = new DOMDocument ();
$doc -> loadHTML ( $charset_hack . $res );
$xpath = new DOMXPath ( $doc );
$entries = $xpath -> query ( '(//a[@href]|//img[@src])' );
foreach ( $entries as $entry ) {
if ( $site_url ) {
if ( $entry -> hasAttribute ( 'href' )) {
$entry -> setAttribute ( 'href' ,
rewrite_relative_url ( $site_url , $entry -> getAttribute ( 'href' )));
$entry -> setAttribute ( 'rel' , 'noreferrer' );
}
if ( $entry -> hasAttribute ( 'src' )) {
$src = rewrite_relative_url ( $site_url , $entry -> getAttribute ( 'src' ));
$cached_filename = CACHE_DIR . '/images/' . sha1 ( $src ) . '.png' ;
if ( file_exists ( $cached_filename )) {
2015-02-27 11:51:26 +00:00
$src = SELF_URL_PATH . '/public.php?op=cached_image&hash=' . sha1 ( $src );
2014-03-05 12:48:41 +00:00
}
$entry -> setAttribute ( 'src' , $src );
}
if ( $entry -> nodeName == 'img' ) {
if (( $owner && get_pref ( " STRIP_IMAGES " , $owner )) ||
$force_remove_images || $_SESSION [ " bw_limit " ]) {
$p = $doc -> createElement ( 'p' );
$a = $doc -> createElement ( 'a' );
$a -> setAttribute ( 'href' , $entry -> getAttribute ( 'src' ));
$a -> appendChild ( new DOMText ( $entry -> getAttribute ( 'src' )));
$a -> setAttribute ( 'target' , '_blank' );
$p -> appendChild ( $a );
$entry -> parentNode -> replaceChild ( $p , $entry );
}
}
}
if ( strtolower ( $entry -> nodeName ) == " a " ) {
$entry -> setAttribute ( " target " , " _blank " );
}
}
$entries = $xpath -> query ( '//iframe' );
foreach ( $entries as $entry ) {
2014-11-25 10:45:02 +00:00
if ( ! iframe_whitelisted ( $entry )) {
$entry -> setAttribute ( 'sandbox' , 'allow-scripts' );
2014-12-06 05:52:43 +00:00
} else {
if ( $_SERVER [ 'HTTPS' ] == " on " ) {
$entry -> setAttribute ( " src " ,
str_replace ( " http:// " , " https:// " ,
$entry -> getAttribute ( " src " )));
}
2014-11-25 10:45:02 +00:00
}
2014-03-05 12:48:41 +00:00
}
$allowed_elements = array ( 'a' , 'address' , 'audio' , 'article' , 'aside' ,
'b' , 'bdi' , 'bdo' , 'big' , 'blockquote' , 'body' , 'br' ,
'caption' , 'cite' , 'center' , 'code' , 'col' , 'colgroup' ,
'data' , 'dd' , 'del' , 'details' , 'div' , 'dl' , 'font' ,
'dt' , 'em' , 'footer' , 'figure' , 'figcaption' ,
2015-07-06 20:09:51 +00:00
'h1' , 'h2' , 'h3' , 'h4' , 'h5' , 'h6' , 'header' , 'html' , 'i' ,
2014-03-05 12:48:41 +00:00
'img' , 'ins' , 'kbd' , 'li' , 'main' , 'mark' , 'nav' , 'noscript' ,
'ol' , 'p' , 'pre' , 'q' , 'ruby' , 'rp' , 'rt' , 's' , 'samp' , 'section' ,
'small' , 'source' , 'span' , 'strike' , 'strong' , 'sub' , 'summary' ,
'sup' , 'table' , 'tbody' , 'td' , 'tfoot' , 'th' , 'thead' , 'time' ,
'tr' , 'track' , 'tt' , 'u' , 'ul' , 'var' , 'wbr' , 'video' );
if ( $_SESSION [ 'hasSandbox' ]) $allowed_elements [] = 'iframe' ;
$disallowed_attributes = array ( 'id' , 'style' , 'class' );
foreach ( PluginHost :: getInstance () -> get_hooks ( PluginHost :: HOOK_SANITIZE ) as $plugin ) {
$retval = $plugin -> hook_sanitize ( $doc , $site_url , $allowed_elements , $disallowed_attributes , $article_id );
if ( is_array ( $retval )) {
$doc = $retval [ 0 ];
$allowed_elements = $retval [ 1 ];
$disallowed_attributes = $retval [ 2 ];
} else {
$doc = $retval ;
}
}
$doc -> removeChild ( $doc -> firstChild ); //remove doctype
$doc = strip_harmful_tags ( $doc , $allowed_elements , $disallowed_attributes );
if ( $highlight_words ) {
foreach ( $highlight_words as $word ) {
// http://stackoverflow.com/questions/4081372/highlight-keywords-in-a-paragraph
$elements = $xpath -> query ( " //*/text() " );
foreach ( $elements as $child ) {
$fragment = $doc -> createDocumentFragment ();
$text = $child -> textContent ;
while (( $pos = mb_stripos ( $text , $word )) !== false ) {
$fragment -> appendChild ( new DomText ( mb_substr ( $text , 0 , $pos )));
$word = mb_substr ( $text , $pos , mb_strlen ( $word ));
$highlight = $doc -> createElement ( 'span' );
$highlight -> appendChild ( new DomText ( $word ));
$highlight -> setAttribute ( 'class' , 'highlight' );
$fragment -> appendChild ( $highlight );
$text = mb_substr ( $text , $pos + mb_strlen ( $word ));
}
if ( ! empty ( $text )) $fragment -> appendChild ( new DomText ( $text ));
$child -> parentNode -> replaceChild ( $fragment , $child );
}
}
}
$res = $doc -> saveHTML ();
return $res ;
}
function strip_harmful_tags ( $doc , $allowed_elements , $disallowed_attributes ) {
$xpath = new DOMXPath ( $doc );
$entries = $xpath -> query ( '//*' );
foreach ( $entries as $entry ) {
if ( ! in_array ( $entry -> nodeName , $allowed_elements )) {
$entry -> parentNode -> removeChild ( $entry );
}
if ( $entry -> hasAttributes ()) {
$attrs_to_remove = array ();
foreach ( $entry -> attributes as $attr ) {
if ( strpos ( $attr -> nodeName , 'on' ) === 0 ) {
array_push ( $attrs_to_remove , $attr );
}
if ( in_array ( $attr -> nodeName , $disallowed_attributes )) {
array_push ( $attrs_to_remove , $attr );
}
}
foreach ( $attrs_to_remove as $attr ) {
$entry -> removeAttributeNode ( $attr );
}
}
}
return $doc ;
}
function catchupArticlesById ( $ids , $cmode , $owner_uid = false ) {
if ( ! $owner_uid ) $owner_uid = $_SESSION [ " uid " ];
if ( count ( $ids ) == 0 ) return ;
$tmp_ids = array ();
foreach ( $ids as $id ) {
array_push ( $tmp_ids , " ref_id = ' $id ' " );
}
$ids_qpart = join ( " OR " , $tmp_ids );
if ( $cmode == 0 ) {
db_query ( " UPDATE ttrss_user_entries SET
unread = false , last_read = NOW ()
WHERE ( $ids_qpart ) AND owner_uid = $owner_uid " );
} else if ( $cmode == 1 ) {
db_query ( " UPDATE ttrss_user_entries SET
unread = true
WHERE ( $ids_qpart ) AND owner_uid = $owner_uid " );
} else {
db_query ( " UPDATE ttrss_user_entries SET
unread = NOT unread , last_read = NOW ()
WHERE ( $ids_qpart ) AND owner_uid = $owner_uid " );
}
/* update ccache */
$result = db_query ( " SELECT DISTINCT feed_id FROM ttrss_user_entries
WHERE ( $ids_qpart ) AND owner_uid = $owner_uid " );
while ( $line = db_fetch_assoc ( $result )) {
ccache_update ( $line [ " feed_id " ], $owner_uid );
}
}
function get_article_tags ( $id , $owner_uid = 0 , $tag_cache = false ) {
$a_id = db_escape_string ( $id );
if ( ! $owner_uid ) $owner_uid = $_SESSION [ " uid " ];
$query = " SELECT DISTINCT tag_name,
owner_uid as owner FROM
ttrss_tags WHERE post_int_id = ( SELECT int_id FROM ttrss_user_entries WHERE
ref_id = '$a_id' AND owner_uid = '$owner_uid' LIMIT 1 ) ORDER BY tag_name " ;
$tags = array ();
/* check cache first */
if ( $tag_cache === false ) {
$result = db_query ( " SELECT tag_cache FROM ttrss_user_entries
WHERE ref_id = '$id' AND owner_uid = $owner_uid " );
$tag_cache = db_fetch_result ( $result , 0 , " tag_cache " );
}
if ( $tag_cache ) {
$tags = explode ( " , " , $tag_cache );
} else {
/* do it the hard way */
$tmp_result = db_query ( $query );
while ( $tmp_line = db_fetch_assoc ( $tmp_result )) {
array_push ( $tags , $tmp_line [ " tag_name " ]);
}
/* update the cache */
$tags_str = db_escape_string ( join ( " , " , $tags ));
db_query ( " UPDATE ttrss_user_entries
SET tag_cache = '$tags_str' WHERE ref_id = '$id'
AND owner_uid = $owner_uid " );
}
return $tags ;
}
function trim_array ( $array ) {
$tmp = $array ;
array_walk ( $tmp , 'trim' );
return $tmp ;
}
function tag_is_valid ( $tag ) {
if ( $tag == '' ) return false ;
if ( preg_match ( " /^[0-9]* $ / " , $tag )) return false ;
if ( mb_strlen ( $tag ) > 250 ) return false ;
if ( ! $tag ) return false ;
return true ;
}
function render_login_form () {
header ( 'Cache-Control: public' );
require_once " login_form.php " ;
exit ;
}
function format_warning ( $msg , $id = " " ) {
return " <div class= \" warning \" id= \" $id\ " >
< span >< img src = \ " images/alert.png \" ></span><span> $msg </span></div> " ;
}
function format_notice ( $msg , $id = " " ) {
return " <div class= \" notice \" id= \" $id\ " >
< span >< img src = \ " images/information.png \" ></span><span> $msg </span></div> " ;
}
function format_error ( $msg , $id = " " ) {
return " <div class= \" error \" id= \" $id\ " >
< span >< img src = \ " images/alert.png \" ></span><span> $msg </span></div> " ;
}
function print_notice ( $msg ) {
return print format_notice ( $msg );
}
function print_warning ( $msg ) {
return print format_warning ( $msg );
}
function print_error ( $msg ) {
return print format_error ( $msg );
}
function T_sprintf () {
$args = func_get_args ();
return vsprintf ( __ ( array_shift ( $args )), $args );
}
function format_inline_player ( $url , $ctype ) {
$entry = " " ;
$url = htmlspecialchars ( $url );
if ( strpos ( $ctype , " audio/ " ) === 0 ) {
if ( $_SESSION [ " hasAudio " ] && ( strpos ( $ctype , " ogg " ) !== false ||
$_SESSION [ " hasMp3 " ])) {
$entry .= " <audio preload= \" none \" controls>
< source type = \ " $ctype\ " src = \ " $url\ " ></ source >
</ audio > " ;
} else {
$entry .= " <object type= \" application/x-shockwave-flash \"
data = \ " lib/button/musicplayer.swf?song_url= $url\ "
width = \ " 17 \" height= \" 17 \" style='float : left; margin-right : 5px;'>
< param name = \ " movie \"
value = \ " lib/button/musicplayer.swf?song_url= $url\ " />
</ object > " ;
}
if ( $entry ) $entry .= " <a target= \" _blank \"
href = \ " $url\ " > " . basename( $url ) . " </ a > " ;
return $entry ;
}
return " " ;
/* $filename = substr ( $url , strrpos ( $url , " / " ) + 1 );
$entry .= " <a target= \" _blank \" href= \" " . htmlspecialchars ( $url ) . " \" > " .
$filename . " ( " . $ctype . " ) " . " </a> " ; */
}
function format_article ( $id , $mark_as_read = true , $zoom_mode = false , $owner_uid = false ) {
if ( ! $owner_uid ) $owner_uid = $_SESSION [ " uid " ];
$rv = array ();
$rv [ 'id' ] = $id ;
/* we can figure out feed_id from article id anyway , why do we
* pass feed_id here ? let ' s ignore the argument : ( */
$result = db_query ( " SELECT feed_id FROM ttrss_user_entries
WHERE ref_id = '$id' " );
$feed_id = ( int ) db_fetch_result ( $result , 0 , " feed_id " );
$rv [ 'feed_id' ] = $feed_id ;
//if (!$zoom_mode) { print "<article id='$id'><![CDATA["; };
if ( $mark_as_read ) {
$result = db_query ( " UPDATE ttrss_user_entries
SET unread = false , last_read = NOW ()
WHERE ref_id = '$id' AND owner_uid = $owner_uid " );
ccache_update ( $feed_id , $owner_uid );
}
$result = db_query ( " SELECT id,title,link,content,feed_id,comments,int_id,lang,
" .SUBSTRING_FOR_DATE. " ( updated , 1 , 16 ) as updated ,
( SELECT site_url FROM ttrss_feeds WHERE id = feed_id ) as site_url ,
( SELECT title FROM ttrss_feeds WHERE id = feed_id ) as feed_title ,
( SELECT hide_images FROM ttrss_feeds WHERE id = feed_id ) as hide_images ,
( SELECT always_display_enclosures FROM ttrss_feeds WHERE id = feed_id ) as always_display_enclosures ,
num_comments ,
tag_cache ,
author ,
orig_feed_id ,
note
FROM ttrss_entries , ttrss_user_entries
WHERE id = '$id' AND ref_id = id AND owner_uid = $owner_uid " );
if ( $result ) {
$line = db_fetch_assoc ( $result );
$line [ " tags " ] = get_article_tags ( $id , $owner_uid , $line [ " tag_cache " ]);
unset ( $line [ " tag_cache " ]);
$line [ " content " ] = sanitize ( $line [ " content " ],
sql_bool_to_bool ( $line [ 'hide_images' ]),
$owner_uid , $line [ " site_url " ], false , $line [ " id " ]);
foreach ( PluginHost :: getInstance () -> get_hooks ( PluginHost :: HOOK_RENDER_ARTICLE ) as $p ) {
$line = $p -> hook_render_article ( $line );
}
$num_comments = $line [ " num_comments " ];
$entry_comments = " " ;
if ( $num_comments > 0 ) {
if ( $line [ " comments " ]) {
$comments_url = htmlspecialchars ( $line [ " comments " ]);
} else {
$comments_url = htmlspecialchars ( $line [ " link " ]);
}
$entry_comments = " <a class= \" postComments \"
target = '_blank' href = \ " $comments_url\ " > $num_comments " .
_ngettext ( " comment " , " comments " , $num_comments ) . " </a> " ;
} else {
if ( $line [ " comments " ] && $line [ " link " ] != $line [ " comments " ]) {
$entry_comments = " <a class= \" postComments \" target='_blank' href= \" " . htmlspecialchars ( $line [ " comments " ]) . " \" > " . __ ( " comments " ) . " </a> " ;
}
}
if ( $zoom_mode ) {
header ( " Content-Type: text/html " );
$rv [ 'content' ] .= " <html><head>
< meta http - equiv = \ " Content-Type \" content= \" text/html; charset=utf-8 \" />
< title > Tiny Tiny RSS - " . $line["title"] . " </ title > " .
stylesheet_tag ( " css/tt-rss.css " ) .
stylesheet_tag ( " css/zoom.css " ) .
stylesheet_tag ( " css/dijit.css " ) . "
< link rel = \ " shortcut icon \" type= \" image/png \" href= \" images/favicon.png \" >
< link rel = \ " icon \" type= \" image/png \" sizes= \" 72x72 \" href= \" images/favicon-72px.png \" >
< script type = \ " text/javascript \" >
function openSelectedAttachment ( elem ) {
try {
var url = elem [ elem . selectedIndex ] . value ;
if ( url ) {
window . open ( url );
elem . selectedIndex = 0 ;
}
} catch ( e ) {
exception_error ( \ " openSelectedAttachment \" , e);
}
}
</ script >
</ head >< body id = \ " ttrssZoom \" > " ;
}
$rv [ 'content' ] .= " <div class= \" postReply \" id= \" POST- $id\ " > " ;
$rv [ 'content' ] .= " <div class= \" postHeader \" id= \" POSTHDR- $id\ " > " ;
$entry_author = $line [ " author " ];
if ( $entry_author ) {
$entry_author = __ ( " - " ) . $entry_author ;
}
$parsed_updated = make_local_datetime ( $line [ " updated " ], true ,
$owner_uid , true );
if ( ! $zoom_mode )
$rv [ 'content' ] .= " <div class= \" postDate \" > $parsed_updated </div> " ;
if ( $line [ " link " ]) {
$rv [ 'content' ] .= " <div class='postTitle'><a target='_blank'
title = \ " " . htmlspecialchars ( $line [ 'title' ]) . " \"
href = \ " " .
htmlspecialchars ( $line [ " link " ]) . " \" > " .
$line [ " title " ] . " </a> " .
" <span class='author'> $entry_author </span></div> " ;
} else {
$rv [ 'content' ] .= " <div class='postTitle'> " . $line [ " title " ] . " $entry_author </div> " ;
}
if ( $zoom_mode ) {
$feed_title = " <a href= \" " . htmlspecialchars ( $line [ " site_url " ]) .
" \" target= \" _blank \" > " .
htmlspecialchars ( $line [ " feed_title " ]) . " </a> " ;
$rv [ 'content' ] .= " <div class= \" postFeedTitle \" > $feed_title </div> " ;
$rv [ 'content' ] .= " <div class= \" postDate \" > $parsed_updated </div> " ;
}
$tags_str = format_tags_string ( $line [ " tags " ], $id );
$tags_str_full = join ( " , " , $line [ " tags " ]);
if ( ! $tags_str_full ) $tags_str_full = __ ( " no tags " );
if ( ! $entry_comments ) $entry_comments = " " ; # placeholder
$rv [ 'content' ] .= " <div class='postTags' style='float : right'>
< img src = 'images/tag.png'
class = 'tagsPic' alt = 'Tags' title = 'Tags' >& nbsp ; " ;
if ( ! $zoom_mode ) {
$rv [ 'content' ] .= " <span id= \" ATSTR- $id\ " > $tags_str </ span >
< a title = \ " " . __ ( 'Edit tags for this article' ) . " \"
href = \ " # \" onclick= \" editArticleTags( $id , $feed_id ) \" >(+)</a> " ;
$rv [ 'content' ] .= " <div dojoType= \" dijit.Tooltip \"
id = \ " ATSTRTIP- $id\ " connectId = \ " ATSTR- $id\ "
position = \ " below \" > $tags_str_full </div> " ;
foreach ( PluginHost :: getInstance () -> get_hooks ( PluginHost :: HOOK_ARTICLE_BUTTON ) as $p ) {
$rv [ 'content' ] .= $p -> hook_article_button ( $line );
}
} else {
$tags_str = strip_tags ( $tags_str );
$rv [ 'content' ] .= " <span id= \" ATSTR- $id\ " > $tags_str </ span > " ;
}
$rv [ 'content' ] .= " </div> " ;
$rv [ 'content' ] .= " <div clear='both'> " ;
foreach ( PluginHost :: getInstance () -> get_hooks ( PluginHost :: HOOK_ARTICLE_LEFT_BUTTON ) as $p ) {
$rv [ 'content' ] .= $p -> hook_article_left_button ( $line );
}
$rv [ 'content' ] .= " $entry_comments </div> " ;
if ( $line [ " orig_feed_id " ]) {
$tmp_result = db_query ( " SELECT * FROM ttrss_archived_feeds
WHERE id = " . $line["orig_feed_id"] );
if ( db_num_rows ( $tmp_result ) != 0 ) {
$rv [ 'content' ] .= " <div clear='both'> " ;
$rv [ 'content' ] .= __ ( " Originally from: " );
$rv [ 'content' ] .= " " ;
$tmp_line = db_fetch_assoc ( $tmp_result );
$rv [ 'content' ] .= " <a target='_blank'
href = ' " . htmlspecialchars($tmp_line[' site_url ']) . "' > " .
$tmp_line [ 'title' ] . " </a> " ;
$rv [ 'content' ] .= " " ;
$rv [ 'content' ] .= " <a target='_blank' href=' " . htmlspecialchars ( $tmp_line [ 'feed_url' ]) . " '> " ;
$rv [ 'content' ] .= " <img title=' " . __ ( 'Feed URL' ) . " ' class='tinyFeedIcon' src='images/pub_set.png'></a> " ;
$rv [ 'content' ] .= " </div> " ;
}
}
$rv [ 'content' ] .= " </div> " ;
$rv [ 'content' ] .= " <div id= \" POSTNOTE- $id\ " > " ;
if ( $line [ 'note' ]) {
$rv [ 'content' ] .= format_article_note ( $id , $line [ 'note' ], ! $zoom_mode );
}
$rv [ 'content' ] .= " </div> " ;
if ( ! $line [ 'lang' ]) $line [ 'lang' ] = 'en' ;
$rv [ 'content' ] .= " <div class= \" postContent \" lang= \" " . $line [ 'lang' ] . " \" > " ;
$rv [ 'content' ] .= $line [ " content " ];
$rv [ 'content' ] .= format_article_enclosures ( $id ,
sql_bool_to_bool ( $line [ " always_display_enclosures " ]),
$line [ " content " ],
sql_bool_to_bool ( $line [ " hide_images " ]));
$rv [ 'content' ] .= " </div> " ;
$rv [ 'content' ] .= " </div> " ;
}
if ( $zoom_mode ) {
$rv [ 'content' ] .= "
< div class = 'footer' >
< button onclick = \ " return window.close() \" > " .
__ ( " Close this window " ) . " </button></div> " ;
$rv [ 'content' ] .= " </body></html> " ;
}
return $rv ;
}
function print_checkpoint ( $n , $s ) {
$ts = microtime ( true );
echo sprintf ( " <!-- CP[ $n ] %.4f seconds --> \n " , $ts - $s );
return $ts ;
}
function sanitize_tag ( $tag ) {
$tag = trim ( $tag );
$tag = mb_strtolower ( $tag , 'utf-8' );
$tag = preg_replace ( '/[\'\"\+\>\<]/' , " " , $tag );
2015-07-06 12:32:26 +00:00
if ( DB_TYPE == " mysql " ) {
$tag = preg_replace ( '/[\x{10000}-\x{10FFFF}]/u' , " \xEF \xBF \xBD " , $tag );
}
2014-03-05 12:48:41 +00:00
return $tag ;
}
function get_self_url_prefix () {
if ( strrpos ( SELF_URL_PATH , " / " ) === strlen ( SELF_URL_PATH ) - 1 ) {
return substr ( SELF_URL_PATH , 0 , strlen ( SELF_URL_PATH ) - 1 );
} else {
return SELF_URL_PATH ;
}
}
/**
* Compute the Mozilla Firefox feed adding URL from server HOST and REQUEST_URI .
*
* @ return string The Mozilla Firefox feed adding URL .
*/
function add_feed_url () {
//$url_path = ($_SERVER['HTTPS'] != "on" ? 'http://' : 'https://') . $_SERVER["HTTP_HOST"] . parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);
$url_path = get_self_url_prefix () .
" /public.php?op=subscribe&feed_url=%s " ;
return $url_path ;
} // function add_feed_url
function encrypt_password ( $pass , $salt = '' , $mode2 = false ) {
if ( $salt && $mode2 ) {
return " MODE2: " . hash ( 'sha256' , $salt . $pass );
} else if ( $salt ) {
return " SHA1X: " . sha1 ( " $salt : $pass " );
} else {
return " SHA1: " . sha1 ( $pass );
}
} // function encrypt_password
function load_filters ( $feed_id , $owner_uid , $action_id = false ) {
$filters = array ();
$cat_id = ( int ) getFeedCategory ( $feed_id );
if ( $cat_id == 0 )
$null_cat_qpart = " cat_id IS NULL OR " ;
else
$null_cat_qpart = " " ;
$result = db_query ( " SELECT * FROM ttrss_filters2 WHERE
owner_uid = $owner_uid AND enabled = true ORDER BY order_id , title " );
$check_cats = join ( " , " , array_merge (
getParentCategories ( $cat_id , $owner_uid ),
array ( $cat_id )));
while ( $line = db_fetch_assoc ( $result )) {
$filter_id = $line [ " id " ];
$result2 = db_query ( " SELECT
r . reg_exp , r . inverse , r . feed_id , r . cat_id , r . cat_filter , t . name AS type_name
FROM ttrss_filters2_rules AS r ,
ttrss_filter_types AS t
WHERE
( $null_cat_qpart ( cat_id IS NULL AND cat_filter = false ) OR cat_id IN ( $check_cats )) AND
( feed_id IS NULL OR feed_id = '$feed_id' ) AND
filter_type = t . id AND filter_id = '$filter_id' " );
$rules = array ();
$actions = array ();
while ( $rule_line = db_fetch_assoc ( $result2 )) {
# print_r($rule_line);
$rule = array ();
$rule [ " reg_exp " ] = $rule_line [ " reg_exp " ];
$rule [ " type " ] = $rule_line [ " type_name " ];
$rule [ " inverse " ] = sql_bool_to_bool ( $rule_line [ " inverse " ]);
array_push ( $rules , $rule );
}
$result2 = db_query ( " SELECT a.action_param,t.name AS type_name
FROM ttrss_filters2_actions AS a ,
ttrss_filter_actions AS t
WHERE
action_id = t . id AND filter_id = '$filter_id' " );
while ( $action_line = db_fetch_assoc ( $result2 )) {
# print_r($action_line);
$action = array ();
$action [ " type " ] = $action_line [ " type_name " ];
$action [ " param " ] = $action_line [ " action_param " ];
array_push ( $actions , $action );
}
$filter = array ();
$filter [ " match_any_rule " ] = sql_bool_to_bool ( $line [ " match_any_rule " ]);
$filter [ " inverse " ] = sql_bool_to_bool ( $line [ " inverse " ]);
$filter [ " rules " ] = $rules ;
$filter [ " actions " ] = $actions ;
if ( count ( $rules ) > 0 && count ( $actions ) > 0 ) {
array_push ( $filters , $filter );
}
}
return $filters ;
}
function get_score_pic ( $score ) {
if ( $score > 100 ) {
return " score_high.png " ;
} else if ( $score > 0 ) {
return " score_half_high.png " ;
} else if ( $score < - 100 ) {
return " score_low.png " ;
} else if ( $score < 0 ) {
return " score_half_low.png " ;
} else {
return " score_neutral.png " ;
}
}
function feed_has_icon ( $id ) {
return is_file ( ICONS_DIR . " / $id .ico " ) && filesize ( ICONS_DIR . " / $id .ico " ) > 0 ;
}
function init_plugins () {
PluginHost :: getInstance () -> load ( PLUGINS , PluginHost :: KIND_ALL );
return true ;
}
function format_tags_string ( $tags , $id ) {
if ( ! is_array ( $tags ) || count ( $tags ) == 0 ) {
return __ ( " no tags " );
} else {
$maxtags = min ( 5 , count ( $tags ));
for ( $i = 0 ; $i < $maxtags ; $i ++ ) {
$tags_str .= " <a class= \" tag \" href= \" # \" onclick= \" viewfeed(' " . $tags [ $i ] . " ') \" > " . $tags [ $i ] . " </a>, " ;
}
$tags_str = mb_substr ( $tags_str , 0 , mb_strlen ( $tags_str ) - 2 );
if ( count ( $tags ) > $maxtags )
$tags_str .= " , … " ;
return $tags_str ;
}
}
function format_article_labels ( $labels , $id ) {
if ( ! is_array ( $labels )) return '' ;
$labels_str = " " ;
foreach ( $labels as $l ) {
$labels_str .= sprintf ( " <span class='hlLabelRef'
style = 'color : %s; background-color : %s' >% s </ span > " ,
$l [ 2 ], $l [ 3 ], $l [ 1 ]);
}
return $labels_str ;
}
function format_article_note ( $id , $note , $allow_edit = true ) {
$str = " <div class='articleNote' onclick= \" editArticleNote( $id ) \" >
< div class = 'noteEdit' onclick = \ " editArticleNote( $id ) \" > " .
( $allow_edit ? __ ( '(edit note)' ) : " " ) . " </div> $note </div> " ;
return $str ;
}
function get_feed_category ( $feed_cat , $parent_cat_id = false ) {
if ( $parent_cat_id ) {
$parent_qpart = " parent_cat = ' $parent_cat_id ' " ;
$parent_insert = " ' $parent_cat_id ' " ;
} else {
$parent_qpart = " parent_cat IS NULL " ;
$parent_insert = " NULL " ;
}
$result = db_query (
" SELECT id FROM ttrss_feed_categories
WHERE $parent_qpart AND title = '$feed_cat' AND owner_uid = " . $_SESSION["uid"] );
if ( db_num_rows ( $result ) == 0 ) {
return false ;
} else {
return db_fetch_result ( $result , 0 , " id " );
}
}
function add_feed_category ( $feed_cat , $parent_cat_id = false ) {
if ( ! $feed_cat ) return false ;
db_query ( " BEGIN " );
if ( $parent_cat_id ) {
$parent_qpart = " parent_cat = ' $parent_cat_id ' " ;
$parent_insert = " ' $parent_cat_id ' " ;
} else {
$parent_qpart = " parent_cat IS NULL " ;
$parent_insert = " NULL " ;
}
$feed_cat = mb_substr ( $feed_cat , 0 , 250 );
$result = db_query (
" SELECT id FROM ttrss_feed_categories
WHERE $parent_qpart AND title = '$feed_cat' AND owner_uid = " . $_SESSION["uid"] );
if ( db_num_rows ( $result ) == 0 ) {
$result = db_query (
" INSERT INTO ttrss_feed_categories (owner_uid,title,parent_cat)
VALUES ( '".$_SESSION["uid"]."' , '$feed_cat' , $parent_insert ) " );
db_query ( " COMMIT " );
return true ;
}
return false ;
}
function getArticleFeed ( $id ) {
$result = db_query ( " SELECT feed_id FROM ttrss_user_entries
WHERE ref_id = '$id' AND owner_uid = " . $_SESSION["uid"] );
if ( db_num_rows ( $result ) != 0 ) {
return db_fetch_result ( $result , 0 , " feed_id " );
} else {
return 0 ;
}
}
/**
* Fixes incomplete URLs by prepending " http:// " .
* Also replaces feed :// with http :// , and
* prepends a trailing slash if the url is a domain name only .
*
* @ param string $url Possibly incomplete URL
*
* @ return string Fixed URL .
*/
function fix_url ( $url ) {
2015-06-08 11:18:49 +00:00
// support schema-less urls
if ( strpos ( $url , '//' ) === 0 ) {
$url = 'https:' . $url ;
}
2014-03-05 12:48:41 +00:00
if ( strpos ( $url , '://' ) === false ) {
$url = 'http://' . $url ;
} else if ( substr ( $url , 0 , 5 ) == 'feed:' ) {
$url = 'http:' . substr ( $url , 5 );
}
//prepend slash if the URL has no slash in it
// "http://www.example" -> "http://www.example/"
if ( strpos ( $url , '/' , strpos ( $url , ':' ) + 3 ) === false ) {
$url .= '/' ;
}
if ( $url != " http:/// " )
return $url ;
else
return '' ;
}
function validate_feed_url ( $url ) {
$parts = parse_url ( $url );
return ( $parts [ 'scheme' ] == 'http' || $parts [ 'scheme' ] == 'feed' || $parts [ 'scheme' ] == 'https' );
}
function get_article_enclosures ( $id ) {
$query = " SELECT * FROM ttrss_enclosures
WHERE post_id = '$id' AND content_url != '' " ;
$rv = array ();
$result = db_query ( $query );
if ( db_num_rows ( $result ) > 0 ) {
while ( $line = db_fetch_assoc ( $result )) {
array_push ( $rv , $line );
}
}
return $rv ;
}
2014-07-02 06:38:59 +00:00
/* function save_email_address ( $email ) {
2014-03-05 12:48:41 +00:00
// FIXME: implement persistent storage of emails
if ( ! $_SESSION [ 'stored_emails' ])
$_SESSION [ 'stored_emails' ] = array ();
if ( ! in_array ( $email , $_SESSION [ 'stored_emails' ]))
array_push ( $_SESSION [ 'stored_emails' ], $email );
2014-07-02 06:38:59 +00:00
} */
2014-03-05 12:48:41 +00:00
function get_feed_access_key ( $feed_id , $is_cat , $owner_uid = false ) {
if ( ! $owner_uid ) $owner_uid = $_SESSION [ " uid " ];
$sql_is_cat = bool_to_sql_bool ( $is_cat );
$result = db_query ( " SELECT access_key FROM ttrss_access_keys
WHERE feed_id = '$feed_id' AND is_cat = $sql_is_cat
AND owner_uid = " . $owner_uid );
if ( db_num_rows ( $result ) == 1 ) {
return db_fetch_result ( $result , 0 , " access_key " );
} else {
$key = db_escape_string ( uniqid ( base_convert ( rand (), 10 , 36 )));
$result = db_query ( " INSERT INTO ttrss_access_keys
( access_key , feed_id , is_cat , owner_uid )
VALUES ( '$key' , '$feed_id' , $sql_is_cat , '$owner_uid' ) " );
return $key ;
}
return false ;
}
function get_feeds_from_html ( $url , $content )
{
$url = fix_url ( $url );
$baseUrl = substr ( $url , 0 , strrpos ( $url , '/' ) + 1 );
libxml_use_internal_errors ( true );
$doc = new DOMDocument ();
$doc -> loadHTML ( $content );
$xpath = new DOMXPath ( $doc );
$entries = $xpath -> query ( '/html/head/link[@rel="alternate" and ' .
2014-03-05 14:49:52 +00:00
'(contains(@type,"rss") or contains(@type,"atom"))]|/html/head/link[@rel="feed"]' );
2014-03-05 12:48:41 +00:00
$feedUrls = array ();
foreach ( $entries as $entry ) {
if ( $entry -> hasAttribute ( 'href' )) {
$title = $entry -> getAttribute ( 'title' );
if ( $title == '' ) {
$title = $entry -> getAttribute ( 'type' );
}
$feedUrl = rewrite_relative_url (
$baseUrl , $entry -> getAttribute ( 'href' )
);
$feedUrls [ $feedUrl ] = $title ;
}
}
return $feedUrls ;
}
function is_html ( $content ) {
2015-07-09 11:39:07 +00:00
return preg_match ( " /<html|DOCTYPE html/i " , substr ( $content , 0 , 100 )) !== 0 ;
2014-03-05 12:48:41 +00:00
}
function url_is_html ( $url , $login = false , $pass = false ) {
return is_html ( fetch_file_contents ( $url , false , $login , $pass ));
}
function print_label_select ( $name , $value , $attributes = " " ) {
$result = db_query ( " SELECT caption FROM ttrss_labels2
WHERE owner_uid = '".$_SESSION["uid"]."' ORDER BY caption " );
print " <select default= \" $value\ " name = \ " " . htmlspecialchars ( $name ) .
" \" $attributes onchange= \" labelSelectOnChange(this) \" > " ;
while ( $line = db_fetch_assoc ( $result )) {
$issel = ( $line [ " caption " ] == $value ) ? " selected= \" 1 \" " : " " ;
print " <option value= \" " . htmlspecialchars ( $line [ " caption " ]) . " \"
$issel > " . htmlspecialchars( $line["caption"] ) . " </ option > " ;
}
# print "<option value=\"ADD_LABEL\">" .__("Add label...") . "</option>";
print " </select> " ;
}
function format_article_enclosures ( $id , $always_display_enclosures ,
$article_content , $hide_images = false ) {
$result = get_article_enclosures ( $id );
$rv = '' ;
2014-05-12 04:59:27 +00:00
foreach ( PluginHost :: getInstance () -> get_hooks ( PluginHost :: HOOK_FORMAT_ENCLOSURES ) as $plugin ) {
$retval = $plugin -> hook_format_enclosures ( $rv , $result , $id , $always_display_enclosures , $article_content , $hide_images );
if ( is_array ( $retval )) {
$rv = $retval [ 0 ];
$result = $retval [ 1 ];
} else {
$rv = $retval ;
}
}
2014-03-05 12:48:41 +00:00
2014-05-12 17:54:04 +00:00
if ( $rv === '' && ! empty ( $result )) {
2014-03-05 12:48:41 +00:00
$entries_html = array ();
$entries = array ();
$entries_inline = array ();
foreach ( $result as $line ) {
$url = $line [ " content_url " ];
$ctype = $line [ " content_type " ];
$title = $line [ " title " ];
2014-07-15 13:44:05 +00:00
$width = $line [ " width " ];
$height = $line [ " height " ];
2014-03-05 12:48:41 +00:00
if ( ! $ctype ) $ctype = __ ( " unknown type " );
$filename = substr ( $url , strrpos ( $url , " / " ) + 1 );
$player = format_inline_player ( $url , $ctype );
if ( $player ) array_push ( $entries_inline , $player );
# $entry .= " <a target=\"_blank\" href=\"" . htmlspecialchars($url) . "\">" .
# $filename . " (" . $ctype . ")" . "</a>";
$entry = " <div onclick= \" window.open(' " . htmlspecialchars ( $url ) . " ') \"
dojoType = \ " dijit.MenuItem \" > $filename ( $ctype )</div> " ;
array_push ( $entries_html , $entry );
$entry = array ();
$entry [ " type " ] = $ctype ;
$entry [ " filename " ] = $filename ;
$entry [ " url " ] = $url ;
$entry [ " title " ] = $title ;
2014-07-15 13:44:05 +00:00
$entry [ " width " ] = $width ;
$entry [ " height " ] = $height ;
2014-03-05 12:48:41 +00:00
array_push ( $entries , $entry );
}
if ( $_SESSION [ 'uid' ] && ! get_pref ( " STRIP_IMAGES " ) && ! $_SESSION [ " bw_limit " ]) {
if ( $always_display_enclosures ||
! preg_match ( " /<img/i " , $article_content )) {
foreach ( $entries as $entry ) {
2015-04-21 11:07:20 +00:00
foreach ( PluginHost :: getInstance () -> get_hooks ( PluginHost :: HOOK_RENDER_ENCLOSURE ) as $plugin )
$retval = $plugin -> hook_render_enclosure ( $entry , $hide_images );
2014-03-05 12:48:41 +00:00
2015-04-21 11:07:20 +00:00
if ( $retval ) {
$rv .= $retval ;
} else {
if ( preg_match ( " /image/ " , $entry [ " type " ]) ||
preg_match ( " / \ .(jpg|png|gif|bmp)/i " , $entry [ " filename " ])) {
if ( ! $hide_images ) {
$encsize = '' ;
if ( $entry [ 'height' ] > 0 )
$encsize .= ' height="' . intval ( $entry [ 'width' ]) . '"' ;
if ( $entry [ 'width' ] > 0 )
$encsize .= ' width="' . intval ( $entry [ 'height' ]) . '"' ;
$rv .= " <p><img
alt = \ " " . htmlspecialchars ( $entry [ " filename " ]) . " \"
src = \ " " . htmlspecialchars ( $entry [ " url " ]) . " \"
" . $encsize . " /></ p > " ;
} else {
$rv .= " <p><a target= \" _blank \"
href = \ " " . htmlspecialchars ( $entry [ " url " ]) . " \"
> " .htmlspecialchars( $entry["url"] ) . " </ a ></ p > " ;
}
if ( $entry [ 'title' ]) {
$rv .= " <div class= \" enclosure_title \" > ${ entry['title'] } </div> " ;
}
}
2014-03-05 12:48:41 +00:00
}
}
}
}
if ( count ( $entries_inline ) > 0 ) {
$rv .= " <hr clear='both'/> " ;
foreach ( $entries_inline as $entry ) { $rv .= $entry ; };
$rv .= " <hr clear='both'/> " ;
}
$rv .= " <select class= \" attachments \" onchange= \" openSelectedAttachment(this) \" > " .
" <option value=''> " . __ ( 'Attachments' ) . " </option> " ;
foreach ( $entries as $entry ) {
if ( $entry [ " title " ])
$title = " — " . truncate_string ( $entry [ " title " ], 30 );
else
$title = " " ;
$rv .= " <option value= \" " . htmlspecialchars ( $entry [ " url " ]) . " \" > " . htmlspecialchars ( $entry [ " filename " ]) . " $title </option> " ;
};
$rv .= " </select> " ;
}
return $rv ;
}
function getLastArticleId () {
2014-11-27 19:04:24 +00:00
$result = db_query ( " SELECT ref_id AS id FROM ttrss_user_entries
WHERE owner_uid = " . $_SESSION["uid"] . " ORDER BY ref_id DESC LIMIT 1 " );
2014-03-05 12:48:41 +00:00
if ( db_num_rows ( $result ) == 1 ) {
return db_fetch_result ( $result , 0 , " id " );
} else {
return - 1 ;
}
}
function build_url ( $parts ) {
return $parts [ 'scheme' ] . " :// " . $parts [ 'host' ] . $parts [ 'path' ];
}
/**
* Converts a ( possibly ) relative URL to a absolute one .
*
* @ param string $url Base URL ( i . e . from where the document is )
* @ param string $rel_url Possibly relative URL in the document
*
* @ return string Absolute URL
*/
function rewrite_relative_url ( $url , $rel_url ) {
if ( strpos ( $rel_url , " : " ) !== false ) {
return $rel_url ;
} else if ( strpos ( $rel_url , " :// " ) !== false ) {
return $rel_url ;
} else if ( strpos ( $rel_url , " // " ) === 0 ) {
# protocol-relative URL (rare but they exist)
return $rel_url ;
} else if ( strpos ( $rel_url , " / " ) === 0 )
{
$parts = parse_url ( $url );
$parts [ 'path' ] = $rel_url ;
return build_url ( $parts );
} else {
$parts = parse_url ( $url );
if ( ! isset ( $parts [ 'path' ])) {
$parts [ 'path' ] = '/' ;
}
$dir = $parts [ 'path' ];
if ( substr ( $dir , - 1 ) !== '/' ) {
$dir = dirname ( $parts [ 'path' ]);
$dir !== '/' && $dir .= '/' ;
}
$parts [ 'path' ] = $dir . $rel_url ;
return build_url ( $parts );
}
}
function cleanup_tags ( $days = 14 , $limit = 1000 ) {
if ( DB_TYPE == " pgsql " ) {
$interval_query = " date_updated < NOW() - INTERVAL ' $days days' " ;
} else if ( DB_TYPE == " mysql " ) {
$interval_query = " date_updated < DATE_SUB(NOW(), INTERVAL $days DAY) " ;
}
$tags_deleted = 0 ;
while ( $limit > 0 ) {
$limit_part = 500 ;
$query = " SELECT ttrss_tags.id AS id
FROM ttrss_tags , ttrss_user_entries , ttrss_entries
WHERE post_int_id = int_id AND $interval_query AND
ref_id = ttrss_entries . id AND tag_cache != '' LIMIT $limit_part " ;
$result = db_query ( $query );
$ids = array ();
while ( $line = db_fetch_assoc ( $result )) {
array_push ( $ids , $line [ 'id' ]);
}
if ( count ( $ids ) > 0 ) {
$ids = join ( " , " , $ids );
$tmp_result = db_query ( " DELETE FROM ttrss_tags WHERE id IN ( $ids ) " );
$tags_deleted += db_affected_rows ( $tmp_result );
} else {
break ;
}
$limit -= $limit_part ;
}
return $tags_deleted ;
}
function print_user_stylesheet () {
$value = get_pref ( 'USER_STYLESHEET' );
if ( $value ) {
print " <style type= \" text/css \" > " ;
print str_replace ( " <br/> " , " \n " , $value );
print " </style> " ;
}
}
function filter_to_sql ( $filter , $owner_uid ) {
$query = array ();
if ( DB_TYPE == " pgsql " )
$reg_qpart = " ~ " ;
else
$reg_qpart = " REGEXP " ;
foreach ( $filter [ " rules " ] AS $rule ) {
$rule [ 'reg_exp' ] = str_replace ( '/' , '\/' , $rule [ " reg_exp " ]);
$regexp_valid = preg_match ( '/' . $rule [ 'reg_exp' ] . '/' ,
$rule [ 'reg_exp' ]) !== FALSE ;
if ( $regexp_valid ) {
$rule [ 'reg_exp' ] = db_escape_string ( $rule [ 'reg_exp' ]);
switch ( $rule [ " type " ]) {
case " title " :
$qpart = " LOWER(ttrss_entries.title) $reg_qpart LOWER(' " .
$rule [ 'reg_exp' ] . " ') " ;
break ;
case " content " :
$qpart = " LOWER(ttrss_entries.content) $reg_qpart LOWER(' " .
$rule [ 'reg_exp' ] . " ') " ;
break ;
case " both " :
$qpart = " LOWER(ttrss_entries.title) $reg_qpart LOWER(' " .
$rule [ 'reg_exp' ] . " ') OR LOWER( " .
" ttrss_entries.content) $reg_qpart LOWER(' " . $rule [ 'reg_exp' ] . " ') " ;
break ;
case " tag " :
$qpart = " LOWER(ttrss_user_entries.tag_cache) $reg_qpart LOWER(' " .
$rule [ 'reg_exp' ] . " ') " ;
break ;
case " link " :
$qpart = " LOWER(ttrss_entries.link) $reg_qpart LOWER(' " .
$rule [ 'reg_exp' ] . " ') " ;
break ;
case " author " :
$qpart = " LOWER(ttrss_entries.author) $reg_qpart LOWER(' " .
$rule [ 'reg_exp' ] . " ') " ;
break ;
}
if ( isset ( $rule [ 'inverse' ])) $qpart = " NOT ( $qpart ) " ;
if ( isset ( $rule [ " feed_id " ]) && $rule [ " feed_id " ] > 0 ) {
$qpart .= " AND feed_id = " . db_escape_string ( $rule [ " feed_id " ]);
}
if ( isset ( $rule [ " cat_id " ])) {
if ( $rule [ " cat_id " ] > 0 ) {
$children = getChildCategories ( $rule [ " cat_id " ], $owner_uid );
array_push ( $children , $rule [ " cat_id " ]);
$children = join ( " , " , $children );
$cat_qpart = " cat_id IN ( $children ) " ;
} else {
$cat_qpart = " cat_id IS NULL " ;
}
$qpart .= " AND $cat_qpart " ;
}
$qpart .= " AND feed_id IS NOT NULL " ;
array_push ( $query , " ( $qpart ) " );
}
}
if ( count ( $query ) > 0 ) {
$fullquery = " ( " . join ( $filter [ " match_any_rule " ] ? " OR " : " AND " , $query ) . " ) " ;
} else {
$fullquery = " (false) " ;
}
if ( $filter [ 'inverse' ]) $fullquery = " (NOT $fullquery ) " ;
return $fullquery ;
}
if ( ! function_exists ( 'gzdecode' )) {
function gzdecode ( $string ) { // no support for 2nd argument
return file_get_contents ( 'compress.zlib://data:who/cares;base64,' .
base64_encode ( $string ));
}
}
function get_random_bytes ( $length ) {
if ( function_exists ( 'openssl_random_pseudo_bytes' )) {
return openssl_random_pseudo_bytes ( $length );
} else {
$output = " " ;
for ( $i = 0 ; $i < $length ; $i ++ )
$output .= chr ( mt_rand ( 0 , 255 ));
return $output ;
}
}
function read_stdin () {
$fp = fopen ( " php://stdin " , " r " );
if ( $fp ) {
$line = trim ( fgets ( $fp ));
fclose ( $fp );
return $line ;
}
return null ;
}
function tmpdirname ( $path , $prefix ) {
// Use PHP's tmpfile function to create a temporary
// directory name. Delete the file and keep the name.
$tempname = tempnam ( $path , $prefix );
if ( ! $tempname )
return false ;
if ( ! unlink ( $tempname ))
return false ;
return $tempname ;
}
function getFeedCategory ( $feed ) {
$result = db_query ( " SELECT cat_id FROM ttrss_feeds
WHERE id = '$feed' " );
if ( db_num_rows ( $result ) > 0 ) {
return db_fetch_result ( $result , 0 , " cat_id " );
} else {
return false ;
}
}
function implements_interface ( $class , $interface ) {
return in_array ( $interface , class_implements ( $class ));
}
2014-08-20 08:01:41 +00:00
function geturl ( $url , $depth = 0 , $nobody = true ){
2014-03-05 12:48:41 +00:00
if ( $depth == 20 ) return $url ;
if ( ! function_exists ( 'curl_init' ))
return user_error ( 'CURL Must be installed for geturl function to work. Ask your host to enable it or uncomment extension=php_curl.dll in php.ini' , E_USER_ERROR );
$curl = curl_init ();
$header [ 0 ] = " Accept: text/xml,application/xml,application/xhtml+xml, " ;
$header [ 0 ] .= " text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 " ;
$header [] = " Cache-Control: max-age=0 " ;
$header [] = " Connection: keep-alive " ;
$header [] = " Keep-Alive: 300 " ;
$header [] = " Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 " ;
$header [] = " Accept-Language: en-us,en;q=0.5 " ;
$header [] = " Pragma: " ;
curl_setopt ( $curl , CURLOPT_URL , $url );
curl_setopt ( $curl , CURLOPT_USERAGENT , 'Mozilla/5.0 (Windows NT 5.1; rv:5.0) Gecko/20100101 Firefox/5.0 Firefox/5.0' );
curl_setopt ( $curl , CURLOPT_HTTPHEADER , $header );
curl_setopt ( $curl , CURLOPT_HEADER , true );
2014-08-20 08:01:41 +00:00
curl_setopt ( $curl , CURLOPT_NOBODY , $nobody );
2014-03-05 12:48:41 +00:00
curl_setopt ( $curl , CURLOPT_REFERER , $url );
curl_setopt ( $curl , CURLOPT_ENCODING , 'gzip,deflate' );
curl_setopt ( $curl , CURLOPT_AUTOREFERER , true );
curl_setopt ( $curl , CURLOPT_RETURNTRANSFER , true );
//curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); //CURLOPT_FOLLOWLOCATION Disabled...
curl_setopt ( $curl , CURLOPT_TIMEOUT , 60 );
curl_setopt ( $curl , CURLOPT_SSL_VERIFYPEER , false );
if ( defined ( '_CURL_HTTP_PROXY' )) {
curl_setopt ( $curl , CURLOPT_PROXY , _CURL_HTTP_PROXY );
}
$html = curl_exec ( $curl );
$status = curl_getinfo ( $curl );
if ( $status [ 'http_code' ] != 200 ){
2014-08-20 08:01:41 +00:00
2014-08-20 08:04:22 +00:00
// idiot site not allowing http head
2014-08-20 08:01:41 +00:00
if ( $status [ 'http_code' ] == 405 ) {
curl_close ( $curl );
return geturl ( $url , $depth + 1 , false );
}
2014-03-05 12:48:41 +00:00
if ( $status [ 'http_code' ] == 301 || $status [ 'http_code' ] == 302 ) {
curl_close ( $curl );
list ( $header ) = explode ( " \r \n \r \n " , $html , 2 );
$matches = array ();
preg_match ( " /(Location:|URI:)[^( \n )]*/ " , $header , $matches );
$url = trim ( str_replace ( $matches [ 1 ], " " , $matches [ 0 ]));
$url_parsed = parse_url ( $url );
return ( isset ( $url_parsed )) ? geturl ( $url , $depth + 1 ) : '' ;
}
global $fetch_last_error ;
$fetch_last_error = curl_errno ( $curl ) . " " . curl_error ( $curl );
curl_close ( $curl );
# $oline='';
# foreach($status as $key=>$eline){$oline.='['.$key.']'.$eline.' ';}
# $line =$oline." \r\n ".$url."\r\n-----------------\r\n";
# $handle = @fopen('./curl.error.log', 'a');
# fwrite($handle, $line);
return FALSE ;
}
curl_close ( $curl );
return $url ;
}
function get_minified_js ( $files ) {
require_once 'lib/jshrink/Minifier.php' ;
$rv = '' ;
foreach ( $files as $js ) {
if ( ! isset ( $_GET [ 'debug' ])) {
$cached_file = CACHE_DIR . " /js/ " . basename ( $js ) . " .js " ;
2014-08-19 10:50:25 +00:00
if ( file_exists ( $cached_file ) && is_readable ( $cached_file ) && filemtime ( $cached_file ) >= filemtime ( " js/ $js .js " )) {
2014-03-05 12:48:41 +00:00
2014-08-19 10:50:25 +00:00
list ( $header , $contents ) = explode ( " \n " , file_get_contents ( $cached_file ), 2 );
2014-03-05 12:48:41 +00:00
2014-08-19 10:50:25 +00:00
if ( $header && $contents ) {
list ( $htag , $hversion ) = explode ( " : " , $header );
if ( $htag == " tt-rss " && $hversion == VERSION ) {
$rv .= $contents ;
continue ;
}
}
2014-03-05 12:48:41 +00:00
}
2014-08-19 10:50:25 +00:00
$minified = JShrink\Minifier :: minify ( file_get_contents ( " js/ $js .js " ));
file_put_contents ( $cached_file , " tt-rss: " . VERSION . " \n " . $minified );
$rv .= $minified ;
2014-03-05 12:48:41 +00:00
} else {
2014-08-19 10:50:25 +00:00
$rv .= file_get_contents ( " js/ $js .js " ); // no cache in debug mode
2014-03-05 12:48:41 +00:00
}
}
return $rv ;
}
function stylesheet_tag ( $filename ) {
$timestamp = filemtime ( $filename );
return " <link rel= \" stylesheet \" type= \" text/css \" href= \" $filename ? $timestamp\ " /> \n " ;
}
function javascript_tag ( $filename ) {
$query = " " ;
if ( ! ( strpos ( $filename , " ? " ) === FALSE )) {
$query = substr ( $filename , strpos ( $filename , " ? " ) + 1 );
$filename = substr ( $filename , 0 , strpos ( $filename , " ? " ));
}
$timestamp = filemtime ( $filename );
if ( $query ) $timestamp .= " & $query " ;
return " <script type= \" text/javascript \" charset= \" utf-8 \" src= \" $filename ? $timestamp\ " ></ script > \n " ;
}
function calculate_dep_timestamp () {
$files = array_merge ( glob ( " js/*.js " ), glob ( " css/*.css " ));
$max_ts = - 1 ;
foreach ( $files as $file ) {
if ( filemtime ( $file ) > $max_ts ) $max_ts = filemtime ( $file );
}
return $max_ts ;
}
function T_js_decl ( $s1 , $s2 ) {
if ( $s1 && $s2 ) {
$s1 = preg_replace ( " / \n / " , " " , $s1 );
$s2 = preg_replace ( " / \n / " , " " , $s2 );
$s1 = preg_replace ( " / \" / " , " \\ \" " , $s1 );
$s2 = preg_replace ( " / \" / " , " \\ \" " , $s2 );
return " T_messages[ \" $s1\ " ] = \ " $s2\ " ; \n " ;
}
}
function init_js_translations () {
print ' var T_messages = new Object ();
function __ ( msg ) {
if ( T_messages [ msg ]) {
return T_messages [ msg ];
} else {
return msg ;
}
}
function ngettext ( msg1 , msg2 , n ) {
return __ (( parseInt ( n ) > 1 ) ? msg2 : msg1 );
} ' ;
$l10n = _get_reader ();
for ( $i = 0 ; $i < $l10n -> total ; $i ++ ) {
$orig = $l10n -> get_original_string ( $i );
if ( strpos ( $orig , " \000 " ) !== FALSE ) { // Plural forms
$key = explode ( chr ( 0 ), $orig );
print T_js_decl ( $key [ 0 ], _ngettext ( $key [ 0 ], $key [ 1 ], 1 )); // Singular
print T_js_decl ( $key [ 1 ], _ngettext ( $key [ 0 ], $key [ 1 ], 2 )); // Plural
} else {
$translation = __ ( $orig );
print T_js_decl ( $orig , $translation );
}
}
}
function label_to_feed_id ( $label ) {
return LABEL_BASE_INDEX - 1 - abs ( $label );
}
function feed_to_label_id ( $feed ) {
return LABEL_BASE_INDEX - 1 + abs ( $feed );
}
2015-06-05 15:08:19 +00:00
function get_theme_path ( $theme ) {
$check = " themes/ $theme " ;
if ( file_exists ( $check )) return $check ;
$check = " themes.local/ $theme " ;
if ( file_exists ( $check )) return $check ;
}
function theme_valid ( $theme ) {
if ( $theme == " default.css " || $theme == " night.css " ) return true ; // needed for array_filter
$file = " themes/ " . basename ( $theme );
if ( ! file_exists ( $file )) $file = " themes.local/ " . basename ( $theme );
2014-12-09 12:16:53 +00:00
if ( file_exists ( $file ) && is_readable ( $file )) {
$fh = fopen ( $file , " r " );
if ( $fh ) {
$header = fgets ( $fh );
fclose ( $fh );
return strpos ( $header , " supports-version: " . VERSION_STATIC ) !== FALSE ;
}
}
return false ;
}
2015-03-30 10:02:24 +00:00
function error_json ( $code ) {
require_once " errors.php " ;
@ $message = $ERRORS [ $code ];
return json_encode ( array ( " error " =>
array ( " code " => $code , " message " => $message )));
}
2015-06-05 14:54:52 +00:00
function abs_to_rel_path ( $dir ) {
$tmp = str_replace ( dirname ( __DIR__ ), " " , $dir );
if ( strlen ( $tmp ) > 0 && substr ( $tmp , 0 , 1 ) == " / " ) $tmp = substr ( $tmp , 1 );
return $tmp ;
}
2014-03-05 12:48:41 +00:00
?>