| 1 | <?php |
|---|
| 2 | ############################################################################### |
|---|
| 3 | # Gregarius - A PHP based RSS aggregator. |
|---|
| 4 | # Copyright (C) 2003 - 2006 Marco Bonetti |
|---|
| 5 | # |
|---|
| 6 | ############################################################################### |
|---|
| 7 | # This program is free software and open source software; you can redistribute |
|---|
| 8 | # it and/or modify it under the terms of the GNU General Public License as |
|---|
| 9 | # published by the Free Software Foundation; either version 2 of the License, |
|---|
| 10 | # or (at your option) any later version. |
|---|
| 11 | # |
|---|
| 12 | # This program is distributed in the hope that it will be useful, but WITHOUT |
|---|
| 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|---|
| 14 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
|---|
| 15 | # more details. |
|---|
| 16 | # |
|---|
| 17 | # You should have received a copy of the GNU General Public License along |
|---|
| 18 | # with this program; if not, write to the Free Software Foundation, Inc., |
|---|
| 19 | # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA or visit |
|---|
| 20 | # http://www.gnu.org/licenses/gpl.html |
|---|
| 21 | # |
|---|
| 22 | ############################################################################### |
|---|
| 23 | # E-mail: mbonetti at gmail dot com |
|---|
| 24 | # Web page: http://gregarius.net/ |
|---|
| 25 | # |
|---|
| 26 | ############################################################################### |
|---|
| 27 | |
|---|
| 28 | rss_require('cls/wrappers/toolkit.php'); |
|---|
| 29 | |
|---|
| 30 | /** |
|---|
| 31 | * renders the pruning form |
|---|
| 32 | */ |
|---|
| 33 | function items() { |
|---|
| 34 | |
|---|
| 35 | echo "" |
|---|
| 36 | . "<h2 class=\"trigger\">". __('Items:') ."</h2>\n" |
|---|
| 37 | . "<div id=\"admin_items\">\n" |
|---|
| 38 | . "<form method=\"get\" action=\"" .$_SERVER['PHP_SELF'] ."\">\n" |
|---|
| 39 | . "<fieldset class=\"prune\">\n" |
|---|
| 40 | . "<legend>".__('Pruning')."</legend>\n" |
|---|
| 41 | . "<p><input type=\"hidden\" name=\"". CST_ADMIN_DOMAIN ."\" value=\"".CST_ADMIN_DOMAIN_ITEM."\"/>\n" |
|---|
| 42 | . "<label for=\"prune_older\">" . __('Delete items older than ') ."</label>\n" |
|---|
| 43 | . "<input type=\"text\" size=\"5\" name=\"prune_older\" id=\"prune_older\" value=\"\" />\n" |
|---|
| 44 | . "<select name=\"prune_period\" id=\"prune_period\">\n" |
|---|
| 45 | . "<option>" . __('days') . "</option>\n" |
|---|
| 46 | . "<option>" . __('months') . "</option>\n" |
|---|
| 47 | . "<option>" . __('years') . "</option>\n" |
|---|
| 48 | . "</select></p>\n" |
|---|
| 49 | . "<p><label for=\"prune_channel\">".__('...from these feeds').":</label>\n" |
|---|
| 50 | . rss_toolkit_channels_combo("prune_channel", ALL_CHANNELS_ID, 0, true) . "\n" |
|---|
| 51 | . "</p>\n" |
|---|
| 52 | . "<p><label for=\"prune_include_sticky\">".__('Delete Sticky items too: ')."</label>\n" |
|---|
| 53 | . "<input type=\"checkbox\" id=\"prune_include_sticky\" name=\"prune_include_sticky\" value=\"1\"/></p>\n" |
|---|
| 54 | . "<p><label for=\"prune_include_flag\">".__('Delete Flag items too: ')."</label>\n" |
|---|
| 55 | . "<input type=\"checkbox\" id=\"prune_include_flag\" name=\"prune_include_flag\" value=\"1\"/></p>\n" |
|---|
| 56 | . "<p><label for=\"prune_include_unread\">".__('Delete Unread items too: ')."</label>\n" |
|---|
| 57 | . "<input type=\"checkbox\" id=\"prune_include_unread\" name=\"prune_include_unread\" value=\"1\"/></p>\n" |
|---|
| 58 | . "<p><label for=\"prune_exclude_tags\">".__('Do not delete items tagged... ')."</label>\n" |
|---|
| 59 | . "<input type=\"text\" id=\"prune_exclude_tags\" name=\"prune_exclude_tags\" value=\"\"/></p>\n" |
|---|
| 60 | . "<p style=\"font-size:small; padding:0;margin:0\">".__('(Enter <strong>*</strong> to keep all tagged items)')."</p>\n" |
|---|
| 61 | . "<p class=\"cntr\"><input type=\"submit\" name=\"action\" value=\"". __('Delete') ."\"/></p>\n" |
|---|
| 62 | . "</fieldset>\n" |
|---|
| 63 | . "</form>\n" |
|---|
| 64 | . "</div>\n" |
|---|
| 65 | ; |
|---|
| 66 | } |
|---|
| 67 | |
|---|
| 68 | /** |
|---|
| 69 | * performs pruning action |
|---|
| 70 | */ |
|---|
| 71 | function item_admin() { |
|---|
| 72 | $ret__ = CST_ADMIN_DOMAIN_NONE; |
|---|
| 73 | switch ($_REQUEST['action']) { |
|---|
| 74 | case __('Delete'): |
|---|
| 75 | $req = rss_query('select count(*) as cnt from ' .getTable('item') |
|---|
| 76 | ." where not(unread & " . RSS_MODE_DELETED_STATE .")" |
|---|
| 77 | ); |
|---|
| 78 | list($cnt) = rss_fetch_row($req); |
|---|
| 79 | |
|---|
| 80 | $prune_older = sanitize( $_REQUEST['prune_older'], RSS_SANITIZER_NUMERIC); |
|---|
| 81 | if (array_key_exists('prune_older',$_REQUEST) && |
|---|
| 82 | strlen($_REQUEST['prune_older']) && |
|---|
| 83 | is_numeric($_REQUEST['prune_older'])) { |
|---|
| 84 | switch ($_REQUEST['prune_period']) { |
|---|
| 85 | case __('days'): |
|---|
| 86 | $period = 'day'; |
|---|
| 87 | break; |
|---|
| 88 | |
|---|
| 89 | case __('months'): |
|---|
| 90 | $period = 'month'; |
|---|
| 91 | break; |
|---|
| 92 | |
|---|
| 93 | case __('years'): |
|---|
| 94 | $period = 'year'; |
|---|
| 95 | break; |
|---|
| 96 | |
|---|
| 97 | default: |
|---|
| 98 | rss_error(__('Invalid pruning period'), RSS_ERROR_ERROR,true); |
|---|
| 99 | return CST_ADMIN_DOMAIN_ITEM; |
|---|
| 100 | break; |
|---|
| 101 | } |
|---|
| 102 | $sql = " from ".getTable('item') ." i inner join " .getTable('channels') . " c on c.id=i.cid " |
|---|
| 103 | ." where 1=1 "; |
|---|
| 104 | |
|---|
| 105 | if (array_key_exists('prune_channel', $_REQUEST)) { |
|---|
| 106 | if(ALL_CHANNELS_ID != $_REQUEST['prune_channel']) { |
|---|
| 107 | $sql .= " and c.id = " . $_REQUEST['prune_channel'] . ""; |
|---|
| 108 | } |
|---|
| 109 | } |
|---|
| 110 | |
|---|
| 111 | if ($prune_older > 0) { |
|---|
| 112 | $prune_older_date=date("Y-m-d H:i:s",strtotime("-${prune_older} ${period}")); |
|---|
| 113 | $sql .= " and ifnull(i.pubdate, i.added) < '$prune_older_date'"; |
|---|
| 114 | } |
|---|
| 115 | |
|---|
| 116 | if (!array_key_exists('prune_include_sticky', $_REQUEST) |
|---|
| 117 | || $_REQUEST['prune_include_sticky'] != '1') { |
|---|
| 118 | $sql .= " and not(unread & " .RSS_MODE_STICKY_STATE .") "; |
|---|
| 119 | } |
|---|
| 120 | |
|---|
| 121 | if (!array_key_exists('prune_include_flag', $_REQUEST) |
|---|
| 122 | || $_REQUEST['prune_include_flag'] != '1') { |
|---|
| 123 | $sql .= " and not(unread & " . RSS_MODE_FLAG_STATE . ") "; |
|---|
| 124 | } |
|---|
| 125 | |
|---|
| 126 | |
|---|
| 127 | if (!array_key_exists('prune_include_unread', $_REQUEST) |
|---|
| 128 | || $_REQUEST['prune_include_unread'] != '1') { |
|---|
| 129 | $sql .= " and not(unread & " .RSS_MODE_UNREAD_STATE .") "; |
|---|
| 130 | } |
|---|
| 131 | |
|---|
| 132 | if (array_key_exists('prune_exclude_tags', $_REQUEST) && trim($_REQUEST['prune_exclude_tags'])) { |
|---|
| 133 | |
|---|
| 134 | if ( trim($_REQUEST['prune_exclude_tags']) == '*') { |
|---|
| 135 | $tsql = " select distinct fid from ". getTable('metatag'); |
|---|
| 136 | } else { |
|---|
| 137 | $exclude_tags = explode(" ",$_REQUEST['prune_exclude_tags']); |
|---|
| 138 | |
|---|
| 139 | $trimmed_exclude_tags = array(); |
|---|
| 140 | foreach($exclude_tags as $etag) { |
|---|
| 141 | if ($tetag = rss_real_escape_string(trim($etag))) { |
|---|
| 142 | $trimmed_exclude_tags[]=$tetag; |
|---|
| 143 | } |
|---|
| 144 | } |
|---|
| 145 | |
|---|
| 146 | $tsql = " select distinct fid from ". getTable('metatag') . " m " |
|---|
| 147 | . " inner join " . getTable('tag') . " t" |
|---|
| 148 | . " on t.id = m.tid " |
|---|
| 149 | . " where t.tag in ('" |
|---|
| 150 | . implode("', '", $trimmed_exclude_tags) ."')"; |
|---|
| 151 | } |
|---|
| 152 | $tres = rss_query($tsql); |
|---|
| 153 | $fids = array(); |
|---|
| 154 | while(list($fid) = rss_fetch_row($tres)) { |
|---|
| 155 | $fids[] = $fid; |
|---|
| 156 | } |
|---|
| 157 | |
|---|
| 158 | if (count($fids)) { |
|---|
| 159 | $sql .= " and i.id not in (" . implode(",",$fids) .") "; |
|---|
| 160 | } |
|---|
| 161 | } |
|---|
| 162 | |
|---|
| 163 | if (array_key_exists(CST_ADMIN_CONFIRMED,$_REQUEST)) { |
|---|
| 164 | // Possible fix for #207: max out execution time |
|---|
| 165 | // to avoid timeouts |
|---|
| 166 | @set_time_limit(0); |
|---|
| 167 | @ini_set('max_execution_time', 60*10); |
|---|
| 168 | |
|---|
| 169 | //echo "<pre>\n"; |
|---|
| 170 | //delete the tags for these items |
|---|
| 171 | $sqlids = "select distinct i.id,i.cid " . $sql |
|---|
| 172 | . " order by i.cid, i.id desc"; |
|---|
| 173 | |
|---|
| 174 | $rs = rss_query($sqlids); |
|---|
| 175 | $ids = array(); |
|---|
| 176 | $cids = array(); |
|---|
| 177 | //echo "to be deleted\n"; |
|---|
| 178 | while (list($id,$cid) = rss_fetch_row($rs)) { |
|---|
| 179 | $cids[$cid][]= $id; |
|---|
| 180 | |
|---|
| 181 | //echo "cid=$cid, $id\n"; |
|---|
| 182 | } |
|---|
| 183 | //echo "\n\n"; |
|---|
| 184 | |
|---|
| 185 | if (count($cids)) { |
|---|
| 186 | // Righto. Lets check which of these ids still is in cache: |
|---|
| 187 | |
|---|
| 188 | $cacheIds = array(); |
|---|
| 189 | |
|---|
| 190 | // now, sort the ids to be deleted into two lists: in cache / to trash |
|---|
| 191 | $in_cache = array(); |
|---|
| 192 | $to_trash = array(); |
|---|
| 193 | foreach ($cids as $cid => $ids) { |
|---|
| 194 | $rsCache = rss_query("select itemsincache from " . getTable('channels') . " where id=$cid"); |
|---|
| 195 | list($idString) = rss_fetch_row($rsCache); |
|---|
| 196 | if ($idString) { |
|---|
| 197 | $cacheIds = unserialize($idString); |
|---|
| 198 | } else { |
|---|
| 199 | $cacheIds = array(); |
|---|
| 200 | } |
|---|
| 201 | foreach ($ids as $iid) { |
|---|
| 202 | //echo "examining: $iid (cid $cid) ->"; |
|---|
| 203 | if (array_search($iid, $cacheIds) !== FALSE) { |
|---|
| 204 | $in_cache[] = $iid; |
|---|
| 205 | //echo " in cache!\n"; |
|---|
| 206 | } else { |
|---|
| 207 | $to_trash[] = $iid; |
|---|
| 208 | //echo " not in cache!\n"; |
|---|
| 209 | } |
|---|
| 210 | } |
|---|
| 211 | } |
|---|
| 212 | |
|---|
| 213 | // cheers, we're set. Now delete the metatag links for *all* |
|---|
| 214 | // items to be deleted |
|---|
| 215 | if (count($ids)) { |
|---|
| 216 | $sqldel = "delete from " .getTable('metatag') . " where fid in (" |
|---|
| 217 | . implode(",",array_merge($in_cache,$to_trash)) .")"; |
|---|
| 218 | |
|---|
| 219 | rss_query($sqldel); |
|---|
| 220 | } |
|---|
| 221 | // finally, delete the actual items |
|---|
| 222 | if (count($to_trash)) { |
|---|
| 223 | rss_query( "delete from " . getTable('item') ." where id in (" |
|---|
| 224 | . implode(", ", $to_trash) |
|---|
| 225 | .")" |
|---|
| 226 | ); |
|---|
| 227 | } |
|---|
| 228 | if (count($in_cache)) { |
|---|
| 229 | rss_query( "update " . getTable('item') |
|---|
| 230 | ." set unread = unread | " . RSS_MODE_DELETED_STATE |
|---|
| 231 | .", description='' " |
|---|
| 232 | ." where id in (" |
|---|
| 233 | . implode(", ", $in_cache) |
|---|
| 234 | .")" |
|---|
| 235 | ); |
|---|
| 236 | } |
|---|
| 237 | rss_invalidate_cache(); |
|---|
| 238 | } |
|---|
| 239 | $ret__ = CST_ADMIN_DOMAIN_ITEM; |
|---|
| 240 | |
|---|
| 241 | } else { |
|---|
| 242 | list($cnt_d) = rss_fetch_row(rss_query("select count(distinct(i.id)) as cnt " . $sql |
|---|
| 243 | . " and not(i.unread & " . RSS_MODE_DELETED_STATE .")" |
|---|
| 244 | )); |
|---|
| 245 | rss_error(sprintf(__('Warning: you are about to delete %s items (of %s)'),$cnt_d,$cnt), RSS_ERROR_ERROR,true); |
|---|
| 246 | |
|---|
| 247 | echo "<form action=\"\" method=\"post\">\n" |
|---|
| 248 | ."<p><input type=\"hidden\" name=\"".CST_ADMIN_DOMAIN."\" value=\"".CST_ADMIN_DOMAIN_ITEM."\" />\n" |
|---|
| 249 | ."<input type=\"hidden\" name=\"prune_older\" value=\"".$_REQUEST['prune_older']."\" />\n" |
|---|
| 250 | ."<input type=\"hidden\" name=\"prune_period\" value=\"".$_REQUEST['prune_period']."\" />\n" |
|---|
| 251 | ."<input type=\"hidden\" name=\"".CST_ADMIN_CONFIRMED."\" value=\"1\" />\n" |
|---|
| 252 | ."<input type=\"submit\" name=\"action\" value=\"". __('Delete') ."\" />\n" |
|---|
| 253 | ."<input type=\"submit\" name=\"action\" value=\"". __('Cancel') ."\"/>\n" |
|---|
| 254 | ."</p>\n" |
|---|
| 255 | ."</form>\n"; |
|---|
| 256 | } |
|---|
| 257 | } else { |
|---|
| 258 | rss_error(__('oops, no period specified'), RSS_ERROR_ERROR,true); |
|---|
| 259 | $ret__ = CST_ADMIN_DOMAIN_ITEM; |
|---|
| 260 | } |
|---|
| 261 | |
|---|
| 262 | break; |
|---|
| 263 | default: |
|---|
| 264 | $ret__ = CST_ADMIN_DOMAIN_ITEM; |
|---|
| 265 | break; |
|---|
| 266 | } |
|---|
| 267 | |
|---|
| 268 | return $ret__; |
|---|
| 269 | } |
|---|
| 270 | |
|---|
| 271 | ?> |
|---|