1<?php
2/**
3 *
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     Myron Turner <turnermm02@shaw.ca>
7 */
8
9
10/**
11 * All DokuWiki plugins to extend the admin function
12 * need to inherit from this class
13 */
14class admin_plugin_snippets extends DokuWiki_Admin_Plugin {
15
16    private $output = '';
17    private $metaFn;
18    private $debug;
19
20    function __construct() {
21       $metafile= 'snippets_upd';
22       $this->metaFn = metaFN($metafile,'.ser');
23       $this->debug = false;
24    }
25    /**
26     * handle user request
27     */
28    function handle() {
29
30      if (!isset($_REQUEST['cmd'])) return;   // first time - nothing to do
31
32      $this->output = 'invalid';
33
34      if (!checkSecurityToken()) return;
35      if (!is_array($_REQUEST['cmd'])) return;
36
37      // verify valid values
38      switch (key($_REQUEST['cmd'])) {
39        case 'prune' :
40         $this->output = 'prune';
41         break;
42        case 'docs' :
43        $this->output = 'doc';
44      //  $this->secure_datafile() ;
45        break;
46      }
47
48
49    }
50
51    /**
52     * output appropriate html
53     */
54    function html() {
55    ptln('<a href="javascript:snippets_Inf.toggle();void 0"><span style="line-height: 175%">Toggle info</span></a><br />');
56     ptln('<div id="prereg_info" style="border: 1px solid silver; padding:4px;">'.     $this->locale_xhtml('info') . '</div><br>' );
57
58
59      ptln('<form action="'.wl($ID).'" method="post">');
60
61      // output hidden values to ensure dokuwiki will return back to this plugin
62      ptln('  <input type="hidden" name="do"   value="admin" />');
63      ptln('  <input type="hidden" name="page" value="'.$this->getPluginName().'" />');
64      formSecurityToken();
65
66      $but_1 = $this->getLang('cleanup_but')| 'START';
67      ptln('  <input type="submit" name="cmd[docs]"  value="'. $but_1.'" />');
68       ptln('<br /><br /><div>');
69
70       if($this->output == 'doc') {
71           echo $this->prune_datafile('doc');
72      }
73
74      ptln('</div>');
75      ptln('</form>');
76      $this->js();
77    }
78
79
80    function prune_datafile() {
81   $ret = '<b>'. $this->getLang("dbase") .  '</b>' . $this->metaFn;
82    $data_all = unserialize(io_readFile($this->metaFn,false));
83    $data = $data_all['doc'];
84    $snip_data = array();
85    if (!is_array($data)) $data = array();
86    foreach($data as $id=>$snips) {
87         $ar = array();  // will hold snips currently in page file
88         $found = $this->update_all($id, $snips, $ar) ;
89         $ret .= '<br /><h2>id: ' .  $id .'</h2>';
90         $snips =implode('<br />',$snips);
91
92         $ret .= "<b><u>" . $this->getLang("logged_for") ." $id:</u></b><br />$snips<br /><b>" . $this->getLang("in_page") ."</b><br />$found<br />";
93         $data[$id]   = $ar;
94         for($i=0; $i<count($ar); $i++) {
95             $snip_data[$ar[$i]][] = $id;
96         }
97     }
98     $final = array();
99     $final['doc'] = $data;
100     $final['snip'] = $snip_data;
101     io_saveFile($this->metaFn,serialize($final));
102     return $ret;
103    }
104
105    function update_all($id, $snips, &$ar) {
106        $file=wikiFN($id);
107        $text = file_get_contents($file);
108        preg_match_all("/~~SNIPPET_C~~(.*?)~~/",$text,$matches);
109        $ar = $matches[1];
110        preg_match_all("/~~SNIPPET_O(.*?)~~(.*?)~~/",$text,$matches_tm);
111
112       $page_entries = array();
113       for($i=0; $i<count($matches_tm[1]);$i++) {
114               $tm = $matches_tm[1][$i];
115               $sfile =   $matches_tm[2][$i];
116                $res .=  "&nbsp;&nbsp;&nbsp;&nbsp;<b>$sfile</b>   timestamp:  " . $tm . ", date: " .date('r', $tm) .  "<br />";
117                $page_entries[$sfile] = $tm;
118       }
119
120        /* from metafile */
121          $isref = p_get_metadata($id, 'relation isreferencedby');
122         $res .=   '<br /><b>' .$this->getLang("in_meta") . '</b><br />';
123         $refs = $isref['snippets'];
124         foreach ($refs as $fnam=>$tm) {
125             $res .= "$fnam: " .date('r', $tm) . '<br />';
126         }
127         $refs_keys = array_keys($refs);
128         //get snippets in $refs_keys which are not in matches[1], i.e snips in metafile which are not in page file
129         $refs_diff_1 = array_diff($refs_keys,$matches[1]);
130         $refs_diff_2 = array_diff($matches[1],$refs_keys);
131         if(!empty( $refs_diff_1 ))
132            $res .= $this->dbg('<b>Snippets in metafile not in page:</b><br />&nbsp;&nbsp; ', $refs_diff_1,"132") ;
133         else $res .= $this->dbg("No snippets found in metafile not in page","133");
134         if(!empty($refs_diff_2)) {
135             $res .= $this->dbg('<b>Snippets in page not in meta file:</b><br />&nbsp;&nbsp;', $refs_diff_2,"135");
136         }
137         else $res .= $this->dbg("No snippets found in page which are not logged in metafile","137");
138
139        $res .= $this->update_metafile($refs_diff_2,$refs_diff_1,$id,  $matches_tm[1][0] ,$page_entries);
140
141         $diff = array_diff($snips,$matches[1]) ;
142         if(empty($diff)) {
143            $diff = $this->getLang('finished');
144         }
145         else $diff = implode('<br />',$diff);
146
147        $res .= "<br><b>" . $this->getLang("remove_from_db") . "</b></br>" . $diff;
148        return $res;
149    }
150
151  function update_metafile($add_array,$remove_array, $id,$tm,$page_ar )   {
152      $ret ="";
153
154      $to_add = false;
155      $to_remove = false;
156      if(empty($add_array) && empty($remove_array)) return "Nothing to be done for $id<br />";
157      $isref = p_get_metadata($id, 'relation isreferencedby');
158      if(!empty($add_array)) {
159          $to_add = true;
160          $ret .= $this->dbg('Add to metafile: ',$add_array);
161      }
162      else $ret .=$this->dbg("No additions to metafile&nbsp;&nbsp;'","163");
163
164       if(!empty($remove_array)) {
165         $to_remove=true;
166        $ret .= $this->dbg('Remove from metafile&nbsp;&nbsp; ', $remove_array,"167");
167       }
168       else $ret .=$this->dbg("No snippets to remove from metafile");
169
170      $snippet_array = $isref['snippets'];
171      $ret .= $this->dbg('metafile snippet_array: ', $snippet_array,"172");
172      $ret .= "<b>" . $this->getLang("updating_mf")."</b><br/>";
173     if($to_remove) {
174         $ret .= "<b>" . $this->getLang("removing"). "</b><br/>";
175         foreach($snippet_array as $snippet=>$date) {
176             if(in_array($snippet,$remove_array)) {
177                    $ret .=  "&nbsp;&nbsp;&nbsp;&nbsp;$snippet<br />";
178                   continue;
179             }
180             $updated['snippets'][$snippet]=$date;
181          }
182            $ret .= "<br/>";
183            if(count($updated))  {
184             $ret .= $this->dbg('updated: ', $updated,"185");
185            }
186            else $ret .= $this->dbg('No snippets remaining in ' . $id);
187      }
188
189      if($to_add) {
190      $ret  .="<b>" . $this->getLang("adding") . "</b><br />";
191      foreach($add_array as $add){
192              $updated ['snippets'] [$add] =$tm;
193              $ret .= "&nbsp; &nbsp;&nbsp;&nbsp;$add<br />";
194          }
195      }
196
197
198    // merge page entries with updates
199    foreach($page_ar as $snip=>$tm) {
200        if(!array_key_exists ( $snip , $updated ['snippets'] )) {
201          $updated ['snippets'][$snip] = $tm;
202      }
203    }
204
205      $ret .= $this->getLang("updated") .   print_r($updated ,1) . "<br />";
206
207     $data['relation']['isreferencedby']['snippets']=$updated['snippets'];
208     p_set_metadata($id, $data);
209      return $ret;
210
211  }
212
213  function dbg($text, $ar = array(),$line="") {
214  if(!$this->debug) return;
215  if($ar) {
216          $text .= print_r( $ar, 1);
217      }
218      if($line) $text .= " [$line]";
219      return "dbg: " . $text . "<br />";
220  }
221
222    function js() {
223echo <<<SCRIPT
224<script type="text/javascript">
225    //<![CDATA[
226var snippets_Inf = {
227dom_style: document.getElementById('prereg_info').style,
228open: function() { this.dom_style.display = 'block'; },
229close: function() { this.dom_style.display = "none"; },
230toggle: function() {
231if(this.is_open) { this.close(); this.is_open=false; return; }
232this.open(); this.is_open=true;
233},
234is_open: true,
235};
236    //]]>
237 </script>
238SCRIPT;
239
240    }
241}