1<?php
2/**
3 * Remove outdated files after upgrade -> administration function
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     Taggic <taggic@t-online.de>
7 */
8/******************************************************************************/
9// must be run within Dokuwiki
10if(!defined('DOKU_INC')) die();
11
12/******************************************************************************/
13/**
14 * All DokuWiki plugins to extend the admin function
15 * need to inherit from this class
16 */
17class admin_plugin_removeold extends DokuWiki_Admin_Plugin {
18    /**
19     * return some info
20     */
21    function getInfo(){
22        return confToHash(dirname(__FILE__).'/plugin.info.txt');
23    }
24/******************************************************************************/
25    /**
26     * return prompt for admin menu
27     */
28    function getMenuText($language) {
29        return $this->getLang('admin_removeold');
30    }
31/******************************************************************************/
32    /**
33     * return sort order for position in admin menu
34     */
35    function getMenuSort() {
36        return 20;
37    }
38/******************************************************************************/
39    /**
40     * handle user request
41     *
42     * Initializes internal vars and handles modifications
43     *
44     * @author Taggic <taggic@t-online.de>
45     */
46    function handle() {
47        global $ID;
48    }
49/******************************************************************************/
50    /**
51     * removeold Output function
52     *
53     * print a table with all found lanuage folders
54     *
55     * @author  Taggic <taggic@t-online.de>
56     */
57    function html() {
58        global $ID;
59
60        echo '<div id="removeold__manager">'.NL;
61        echo '<h1>'.$this->getLang('admin_removeold').'</h1>'.NL;
62        echo '<div class="level1">'.NL;
63
64        echo '<div id="removeold__intro">'.NL;
65        echo $this->locale_xhtml('help');
66        echo '</div>'.NL;
67
68        echo '<div id="removeold__detail">'.NL;
69        $this->_html_uinput();
70        echo '</div>'.NL;
71
72        $filelist       = $_REQUEST['removeold_w'];
73        $dryrun         = $_REQUEST['dryrun'];
74        $summary_option = $_REQUEST['summary_only'];
75
76        // language given?
77        if ($filelist!=false) {
78            if (($dryrun==true) && ($summary_option==false)) {
79              echo '<br /><div class="level4"><strong><div class="it__standard_feedback">'.$this->getLang('removeold_willmsg').'</div></strong><br />';
80            }
81            elseif ($summary_option==false) {
82              echo '<br /><div class="level4"><strong><div class="it__standard_feedback">'.$this->getLang('removeold_delmsg').'</div></strong><br />';
83            }
84
85            $this->_list_removeold_files($filelist, $dryrun, $summary_option);
86        }
87        echo '</div>'.NL;
88        echo '<div class="footnotes"><div class="fn">'.NL;
89        echo '<sup><a id="fn__1" class="fn_bot" name="fn__1" href="#fnt__1">1)</a></sup>'.NL;
90        echo $this->getLang('p_include');
91        echo '</div></div>'.NL;
92
93        echo '</div>'.NL;
94    }
95/******************************************************************************/
96    /**
97     * Display the form with input control to let the user specify
98     * the files to be deleted
99     *
100     * @author  Taggic <taggic@t-online.de>
101     */
102    function _html_uinput(){
103        global $conf;
104        global $ID;
105
106        // load deleted.files from data folder and show it in textarea
107        if(is_dir($conf["savedir"])=== false) {
108            $deleted_files = file_get_contents(DOKU_INC."/".$conf["savedir"]."/deleted.files");
109        }
110        else $deleted_files = file_get_contents($conf["savedir"]."/deleted.files");
111
112        if($deleted_files !== "") {
113            echo '<div class="level4" id="removeold__input">'.$this->getLang('i_choose').'<br />'.NL;
114            echo   '<div class="no">'.NL;
115            echo   '<fieldset class="removeold__fieldset"><legend class="removeold_i_legend">'.$this->getLang('i_legend').'</legend>'.NL;
116            echo      '<form action="'.wl($ID).'" method="post">';
117            echo          '<input type="hidden" name="do" value="admin" />'.NL;
118            echo          '<input type="hidden" name="page" value="removeold" />'.NL;
119            echo          '<input type="hidden" name="sectok" value="'.getSecurityToken().'" />'.NL;
120            echo          '<div class="removeold__divinput">';
121            echo            '<textarea type="text" name="removeold_w" class="edit removeold_edit" value="'.$_REQUEST['removeold_w'].'" rows="20" cols="50" />'.$deleted_files.'</textarea><br />'.NL;
122            echo            '<input type="checkbox" name="dryrun" checked="checked">&nbsp;'.$this->getLang('i_dryrun').'&nbsp;</input><br />'.NL;
123            echo            '<input type="checkbox" name="summary_only" >&nbsp;'.$this->getLang('summary_option').'&nbsp;</input><br />'.NL;
124            echo            '<div class="removeold__divright">';
125            echo              '<input type="submit" value="'.$this->getLang('btn_start').'" class="button"/>';
126            echo            '</div>'.NL;
127            echo          '</div>'.NL;
128            echo      '</form>'.NL;
129            echo   '</fieldset>';
130            echo   '</div>'.NL;
131            echo '</div>'.NL;
132            echo '<div style="clear:both"></div>'.NL;
133        }
134        else {
135          msg("File not found: ".$deleted_files,-1);
136        }
137    }
138
139/******************************************************************************/
140  /**
141   * This function will loop through the given files.
142   * It checks if the entry is not empty or comment and if such a file does exist.
143   * If the file does exist then it will be deleted. The result will be stored
144   * into the filelist array for user feddback.
145   */
146    function _list_removeold_files($afilelist, $dryrun, $summary_option){
147        # statistic counters
148        # $empty          = count empty lines
149        # $comments       = count comments
150        # $files_found    = count existing files
151        # $files_notFound = count missing files
152        # $files_deleted  = count deleted files
153        # $files_delError = count files impossible to delete
154
155        $filelist = explode(chr(10),$afilelist);
156        echo '<div class="level4" id="removeold__input"><p>'.NL;
157
158        foreach($filelist as &$file) {
159            $file = trim($file);
160            # check if item is empty   => continue, do nothing
161            if(strlen($file)<1)        { $empty++; continue; }
162            # check if item is comment => continue, do nothing
163            if(stripos($file,"#")===0) { $comments++; continue; }
164            # check if file does exist
165            if(file_exists(DOKU_INC.$file)===true) {
166                # delete file (except on dryrun)
167                $files_found++;
168                $result = $this->getLang('exists');
169
170                if(($dryrun==true) && ($this->is__writable(DOKU_INC.$file)==true)) {
171                  $result = $this->getLang('deleted');
172                  $files_deleted++;
173                }
174                elseif(($dryrun==true) && ($this->is__writable(DOKU_INC.$file)===false)) {
175                  $result = $this->getLang('delError');
176                  $files_delError++;
177                }
178
179                if($dryrun==false) {
180                    $result = unlink(DOKU_INC.$file);
181                    if($result === true) {
182                        $result = $this->getLang('deleted');
183                        $files_deleted++;
184                    }
185                    else {
186                        $result = $this->getLang('delError');
187                        $files_delError++;
188                    }
189                }
190            }
191            else {
192                # file not found
193                $result = $this->getLang('not_found');
194            }
195            # echo file and result
196            if($summary_option==false)  {
197                echo DOKU_INC.$file."<span style=\"float:right;\">".$result."</span><br />".NL;
198            }
199            # write log on delete and error if execution mode
200            if(($result===$this->getLang('delError')) || ($result === $this->getLang('deleted'))) {
201                if($dryrun==false) $this->__removeold_logging($file, $result);
202            }
203        }
204        echo '</p></div><br />'.NL;
205        echo '<div class="level4"><strong><div class="it__standard_feedback">'.$this->getLang('removeold_summary').'</div></strong>';
206        echo '<div class="level2">'.NL;
207        echo '<table><tr><td>'.$this->getLang('exists').': </td><td>'.$files_found.'</td></tr>'.NL;
208        echo '<tr><td>'.$this->getLang('deleted').': </td><td>'.$files_deleted.'</td></tr>'.NL;
209        echo '<tr><td>'.$this->getLang('delError').' </td><td>'.$files_delError.'</td></tr></table>'.NL;
210
211        echo '</div><br />'.NL;
212    }
213/******************************************************************************/
214# Since looks like the Windows ACLs bug "wont fix"
215# (see http://bugs.php.net/bug.php?id=27609)
216# alternative function proposed on php.net:
217    function is__writable($path) {
218        if ($path{strlen($path)-1}=='/')
219             return is__writable($path.uniqid(mt_rand()).'.tmp');
220
221        if (file_exists($path)) {
222             if (!($f = @fopen($path, 'r+')))
223                 return false;
224             fclose($f);
225             return true;
226         }
227
228        if (!($f = @fopen($path, 'w')))
229             return false;
230         fclose($f);
231         unlink($path);
232         return true;
233     }
234/******************************************************************************/
235/* logging of deleted files and deletion errors                               */
236    function __removeold_logging($file, $result) {
237      global $conf;
238      $timestamp = date('d/M/Y G:i:s');
239      if(is_dir($conf["savedir"])=== false) {
240        $log_file = DOKU_INC."/".$conf["savedir"].'/tmp/removeold.log';
241      }
242      else $log_file = $conf["savedir"].'/tmp/removeold.log';
243
244      $record = "[".$timestamp."]".chr(9).$result.chr(9).chr(9).$file.chr(10);
245
246      // Save logging records
247      $fh = fopen($log_file, 'a+');
248      if (!fwrite($fh, $record)) {
249        echo "<span style=\"color:red;\">".$this->getLang('ro_err_msg')."</span><br />".NL;
250      }
251      fclose($fh);
252    }
253/******************************************************************************/
254}
255