1<?php
2/**
3 * OrphanMedia2 Plugin: Display orphan and missing media files
4 * syntax ~~ORPHANMEDIA:<choice>
5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6 * @author  Evan Colwell <ercolwell@gmail.com>
7 */
8
9/******************************************************************************/
10if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
11if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
12require_once(DOKU_INC.'inc/search.php');
13
14define('DEBUG_MODE_ACTIVE',TRUE);         //to show some information if set to true
15
16/******************************************************************************
17 * All DokuWiki plugins to extend the parser/rendering mechanism
18 * need to inherit from this class
19 */
20class syntax_plugin_orphanmedia2 extends DokuWiki_Syntax_Plugin {
21/******************************************************************************/
22/* return some info
23*/
24    function getInfo(){
25        return confToHash(dirname(__FILE__).'/plugin.info.txt');
26    }
27
28    function getType() { return 'substition';}
29    function getPType(){ return 'block';}
30    function getSort() { return 999;}
31
32/******************************************************************************/
33/* Connect pattern to lexer
34*/
35    function connectTo($mode) {
36        $this->Lexer->addSpecialPattern('~~ORPHANMEDIA:[0-9a-zA-Z_:!;|]+~~',$mode,'plugin_orphanmedia2');
37    }
38/******************************************************************************/
39/* Handle the match
40*/
41    function handle($match, $state, $pos, Doku_Handler $handler){
42        $match_array = array();
43        $o_syntax = $match;
44        //strip ~~ORPHANMEDIA: from start and ~~ from end
45        $match = substr($match,14,-2);
46        // split parameters
47        $match_array = explode("!", $match);
48        // $match_array[0] mandatory; can be summary, missing or orphan followed by the optional perf term
49        //                 separated by colon media type/extension filter settings can be added (positive match)
50        // $match_array[1] positive match, contains a single namespace to be ignored; delimiter mandatory if Parameter 2, else optional
51        // $match_array[2] positive match, contains use cases not to be executed (relative, external); optional
52        // $match_array[99] contains the syntax of the page and will be displayed within performance measurement
53        $match_array[99] = $o_syntax;
54        return $match_array;
55    }
56
57/******************************************************************************/
58/* Create output
59*/
60    function render($format, Doku_Renderer $renderer, $data) {
61        if($format !== 'xhtml'){ return false; }  // cancel if not xhtml
62            global $INFO, $conf;
63
64            if((DEBUG_MODE_ACTIVE != false) || (stripos($data[0],"perf") !== false)) { $this->get_execution_time(); }
65
66            // skip ns
67            if (strlen($data[1])>0) {
68                $data[1] = str_replace(':','/',$data[1]);
69                // strip ending slash if exist
70                $data[1] = rtrim($data[1], '/');
71            //    echo $data[1].': Länge = '.strlen($data[1])." -> Letzte Position = ".strrpos($data[1],'/').'<br>';
72            }
73
74            // Media Filter by Extension ---------------------------------------
75            $defFileTypes = explode(':',$data[0]); // split use case entry and file extensions
76            $data[0] = $defFileTypes[0]; // store pure use case entry back to data
77            unset($defFileTypes[0]); // delete the use case entry to keep file extensions only
78            $defFileTypes2 = implode(', ',$defFileTypes); // just for output the filter on summary
79            $defFileTypes = implode('',$defFileTypes); // string of file extensions to easily compare it by strpos
80            if($defFileTypes2==false) $defFileTypes2='none';
81            // -----------------------------------------------------------------
82            // $data is an array
83            // $data[0] is the report type: 'all' or 'valid' or 'missing' or 'orphan' or 'summary'
84            // $defFileTypes is string of excluded media file types
85
86
87// -----------------------------------------------------------------------------
88// ! CHECK: Where are the excluded namespaces ?
89// -----------------------------------------------------------------------------
90
91            // retrive all media files
92            $listMediaFiles     = array();
93            $listMediaFiles     = $this->_get_allMediaFiles($conf['mediadir'], $defFileTypes);
94            $listMediaFiles     = $this->array_flat($listMediaFiles);
95            $media_file_counter = count($listMediaFiles);
96
97/*        echo '<pre>';
98        print_r($data);
99        echo '</pre>';  */
100
101
102            if((DEBUG_MODE_ACTIVE != false) || (stripos($data[0],"perf") !== false)) {
103                    $output .= '<div class="xm_perf">
104                                  <p style="margin-top:10px;"><img src="'.DOKU_URL.'/lib/plugins/orphanmedia2/images/a1.png" class="a1_img"><b><u>PERFORMANCE MEASUREMENT</u></b></p>'.NL.
105                               '<table class="xm_perf_tbl">'.NL.
106                               '<tr><td class="xm_perf_tbl"> used syntax: </td>                <td class="xm_perf_tbl"> '.$data[99].' </td></tr>'.NL.
107                               '<tr><td class="xm_perf_tbl"> list of media files created: </td><td class="xm_perf_tbl"> '.$this->get_execution_time().' s  </td></tr>'.NL; }
108
109
110            // retrieve all page files
111            $listPageFiles = array();
112            $listPageFiles = $this->_get_allPageFiles($conf['datadir'], $data);
113            $listPageFiles = $this->array_flat($listPageFiles);
114            $page_counter  = count($listPageFiles);
115
116            if((DEBUG_MODE_ACTIVE != false) || (stripos($data[0],"perf") !== false)) {
117                    $output .= '<tr><td class="xm_perf_tbl"> list of page files created: </td> <td class="xm_perf_tbl">'.$this->get_execution_time().' s </td><tr>'.NL; }
118
119            // retrieve all media links per page file
120            $listPageFile_MediaLinks = array();
121            $listPageFile_MediaLinks = $this->_get_allMediaLinks($listPageFiles, $defFileTypes, $data[1]);
122//            echo sprintf("<p>%s</p>\n", var_dump($listPageFile_MediaLinks));
123
124            if((DEBUG_MODE_ACTIVE != false) || (stripos($data[0],"perf") !== false)) {
125                    $output .= '<tr><td class="xm_perf_tbl"> media links extracted from pages: </td><td class="xm_perf_tbl">'.$this->get_execution_time().' s </td></tr>'.NL; }
126
127            // analyse matches of media files and pages->media links
128            // what if savedir option is used ? => $conf['mediadir']
129            $doku_media = $conf['mediadir'].'/';
130            $doku_pages = $conf['datadir'].'/';
131            //$doku_media = str_replace("\\","/",DOKU_MEDIA);
132            //$doku_pages = str_replace("\\","/",DOKU_PAGES);
133
134            $listMediaFiles = array($listMediaFiles,array_pad(array(),count($listMediaFiles),'0'));
135            $position = 0;
136
137            foreach($listMediaFiles[0] as &$media_file_path) {
138              // strip ...dokuwiki/data/media path
139              $media_file_path = str_replace("\\","/",$media_file_path);
140              $media_file_path = str_replace($doku_media,"",$media_file_path);
141              // underline maybe a blank on windows systems
142              // so we have to replace the blanks of $media_file_path by underline characters
143              $media_file_path = str_replace(" ","_",$media_file_path);
144
145
146              // 1. direct matches where pages->media links are identical to media file path
147              foreach($listPageFile_MediaLinks as &$perPage_MediaLinks) {
148                  for($i = 1; $i < count($perPage_MediaLinks); $i++) {
149
150                      // prevent destroying unc path
151                      if((stripos($perPage_MediaLinks[$i],":\\")===false) && stripos($perPage_MediaLinks[$i],"://")===false) {
152                          $perPage_MediaLinks[$i] = str_replace(":","/",$perPage_MediaLinks[$i]);
153                      }
154                      // strip initial slash if exist
155                      if(strpos($perPage_MediaLinks[$i],"/") === 0)  $perPage_MediaLinks[$i] = ltrim($perPage_MediaLinks[$i],"/");
156
157
158                      // case 1: find full qualified links: Page_MediaLink = media_file path
159                      if($perPage_MediaLinks[$i] === $media_file_path) {
160                          $perPage_MediaLinks[$i] .= "|valid";
161                          $listMediaFiles[1][$position] = "found";
162                          continue;
163                      }
164
165                      // case 2: find relative links: Page_path + Page_MediaLink = media_file path
166                      //example: Page = tst:start with a media link syntax like {{picture}} = mediafile(tst:picture)
167                      if (stripos($data[2],"relativ")===false) {
168                          if((strpos($perPage_MediaLinks[$i],"|valid")===false) && (strpos($perPage_MediaLinks[$i],"|relative")===false)) {
169                              $pagePath = rtrim($perPage_MediaLinks[0],end(explode("/",$perPage_MediaLinks[0] ))).$perPage_MediaLinks[$i];
170                              // strip ...dokuwiki/data/pages path
171                              $pagePath = str_replace("\\","/",$pagePath);
172                              $pagePath = str_replace($doku_pages,"",$pagePath);
173                              //echo $pagePath.'<br />';
174                              if($pagePath === $media_file_path) {
175                                  $perPage_MediaLinks[$i] .= "|relative";
176                                  $listMediaFiles[1][$position] = "found";
177                                  continue;
178                              }
179                          }
180                      }
181
182                      // case 3: it is an external linked media by http or https
183                      if (stripos($data[2],"extern")===false) {
184                          if((strpos($perPage_MediaLinks[$i],'http:')!==false) || (strpos($perPage_MediaLinks[$i],'https:')!==false)) {
185                              if((strpos($perPage_MediaLinks[$i],"|valid")===false) && (strpos($perPage_MediaLinks[$i],"|relative")===false)) {
186                                  $t_flag = $this->url_exist($perPage_MediaLinks[$i]);
187
188                                  if($t_flag !== false) {
189                                      $perPage_MediaLinks[$i] .= "|relative";
190                                      $listMediaFiles[1][$position] = "found";
191                                      continue;
192                                  }
193                              }
194                          }
195                      }
196                  }
197              }
198              $position++;
199            }
200
201            if((DEBUG_MODE_ACTIVE != false) || (stripos($data[0],"perf") !== false)) {
202                    $output .= '<tr><td class="xm_perf_tbl"> local and relative media found: </td><td  class="xm_perf_tbl">'.$this->get_execution_time().' s </td></tr>'.NL; }
203
204            // 2. missing media files
205            $ok_img = "ok.png";
206            $nok_img= "nok.png";
207            if(strlen($defFileTypes) > 1) $filterInfo.= '<span>Filter settings: '.$defFileTypes.'<br />';
208            $output_valid = '<div class="level1">'.
209                              '  <span>The following existing media files are referenced by full qualified path:</span><br />'.
210                              '<table class="inline">'.
211                              '<tr><th  class="orph_col0 centeralign">i</th>
212                                   <th  class="orph_col1 centeralign">#</th>
213                                   <th  class="orph_col2 centeralign"> Page files </th>
214                                   <th  class="orph_col3 centeralign"> valid Media </th></tr>';
215            $output_relative = '<div class="level1">'.
216                              '  <span>The following existing media files are referenced by relative path:</span><br />'.
217                              '<table class="inline">'.
218                              '<tr><th  class="orph_col0 centeralign">i</th>
219                                   <th  class="orph_col1 centeralign">#</th>
220                                   <th  class="orph_col2 centeralign"> Page files </th>
221                                   <th  class="orph_col3 centeralign"> relative Media </th></tr>';
222            $output_missing = '<div class="level1">'.
223                              '  <span>The following media files are missing:</span><br />'.
224                              '<table class="inline">'.
225                              '<tr><th  class="orph_col0 centeralign">i</th>
226                                   <th  class="orph_col1 centeralign">#</th>
227                                   <th  class="orph_col2 centeralign"> Page files </th>
228                                   <th  class="orph_col3 centeralign"> missing Media </th></tr>';
229            $output_orphan = '<div class="level1">'.
230                              '  <span>The following media files are orphan:</span><br />'.
231                              '<table class="inline">'.
232                              '<tr><th  class="orph_col0 centeralign">i</th>
233                                   <th  class="orph_col1 centeralign">#</th>
234                                   <th  class="orph_col2 centeralign"> Media files </th>
235                                   <th  class="orph_col3 centeralign"> Preview orphan Media </th></tr>';
236
237            foreach($listPageFile_MediaLinks as $perPage_MediaLinks) {
238                for($i = 1; $i < count($perPage_MediaLinks); $i++) {
239                    $refLink_counter ++;
240                    if((strpos($perPage_MediaLinks[$i],"|valid")>0)) {
241                        $valid_counter++;
242                        $output_valid .= $this->_prepare_output(rtrim($perPage_MediaLinks[$i],"|valid"),$perPage_MediaLinks[0],$ok_img,$valid_counter);
243                    }
244                    if((strpos($perPage_MediaLinks[$i],"|relative")>0)) {
245                        $relative_counter++;
246                        $output_relative .= $this->_prepare_output(rtrim($perPage_MediaLinks[$i],"|relative"),$perPage_MediaLinks[0],$ok_img,$relative_counter);
247                    }
248                    if((strpos($perPage_MediaLinks[$i],"|valid")===false) && (strpos($perPage_MediaLinks[$i],"|relative")===false)) {
249                        $missing_counter++;
250                        $output_missing .= $this->_prepare_output($perPage_MediaLinks[$i],$perPage_MediaLinks[0],$nok_img,$missing_counter);
251
252                    }
253                }
254            }
255
256            if((DEBUG_MODE_ACTIVE != false) || (stripos($data[0],"perf") !== false)) {
257                    $output .= '<tr><td class="xm_perf_tbl"> missing media detected: </td><td class="xm_perf_tbl">'.$this->get_execution_time().' s </td></tr>'.NL; }
258
259            $position = 0;
260            $prviewcounter = 0;
261            foreach($listMediaFiles[1] as $check) {
262                if($check === '0') {
263                  $orphan_counter++;
264                  if(!$conf['useslash']) $rt2 = str_replace("/", ":", $listMediaFiles[0][$position]);
265                  else $rt2 = $listMediaFiles[0][$position];
266
267                  $m_link = $conf['mediadir'].'/'.$listMediaFiles[0][$position];
268                  $style = '';
269                  $w_max = 200;
270                  $h_max = 75;
271                  if ((preg_match("/\.(jpe?g|gif|png)$/", $m_link) && file_exists($m_link)) && ($prviewcounter<$this->getConf('prev_limit'))) {
272                       $minfo = getimagesize($m_link);
273                       $w = (int) $minfo[0];
274                       $h = (int) $minfo[1];
275
276                       if($w > $w_max || $h > $h_max) {
277                           if($h > $h_max) {
278                              $ratio = $h_max / $h;
279                              $h = $h_max;
280                              $w = floor($w * $ratio);
281                           }
282                           else {
283                              $ratio = $w_max / $w;
284                              $w = $w_max;
285                              $h = floor($h * $ratio);
286                           }
287                       }
288                       $prviewcounter++;
289                       //$style = ' style="width: '.$w.'px; height: '.$h.'px;"';
290                       $picturepreview = '<a href="' . DOKU_URL . 'lib/exe/detail.php?media=' . $rt2
291                                    . '" class="media" title="'. $listMediaFiles[0][$position]
292                                    . '"><img src="'. DOKU_URL . 'lib/exe/fetch.php?media=' . $rt2 .'&w='.$w.'&h='.$h
293                                    . '" class="media" ' .$style. 'alt="' . $listMediaFiles[0][$position] .'" /></a>';
294                  }
295                  else {
296                      list($ext,$mime,$dl) = mimetype(mediaFN($m_link),false);
297
298                      if (@file_exists(DOKU_INC.'lib/images/fileicons/'.$ext.'.png')) {
299                          $icon = DOKU_BASE.'lib/images/fileicons/'.$ext.'.png';
300                      } else {
301                          $icon = DOKU_BASE.'lib/images/fileicons/file.png';
302                      }
303                      $icon = '<img src="'.$icon.'" alt="'.$m_link.'" class="icon" />';
304                      $picturepreview = '<a href="' . $m_link
305                                   . '" class="wikilink" title="'. $m_link
306                                   . '">'.$icon.'&nbsp;'.$rt2.'</a>';
307                  }
308
309
310
311
312                  $output_orphan .= '<tr>'.NL.
313                              '<td>'.NL.
314                                  '<img src="'.DOKU_URL.'/lib/plugins/orphanmedia2/images/'.$nok_img.'" alt="nok" title="orphan" align="middle" />'.NL.
315                              '</td>'.NL.
316                              '<td>'.$orphan_counter.'</td>'.NL.
317                              '<td>'.$listMediaFiles[0][$position].'</td>'.NL.
318                              '<td>'.$picturepreview.'</td>'.NL.'</tr>'.NL;
319                }
320                $position++;
321            }
322
323            if((DEBUG_MODE_ACTIVE != false) || (stripos($data[0],"perf") !== false)) {
324                    $output .= '<tr><td class="xm_perf_tbl"> orphans detected: </td><td class="xm_perf_tbl">'.$this->get_execution_time().' s </td></tr></table></div><br />'.NL; }
325
326            $output_valid    .= '</table></div>';
327            $output_relative .= '</table></div>';
328            $output_missing  .= '</table></div>';
329            $output_orphan   .= '</table></div>';
330            $output_summary = '<div class="level1">'.NL.
331                              '  <span class="orph_sum_head">Summary</span><br />'.NL.
332                              '<table class="oprph_sum_tbl">'.NL.
333                              ' <tr>'.NL.
334                              '   <td class="oprph_sum_col0" rowspan="8">&nbsp;</td>'.NL.
335                              '   <td class="oprph_sum_col1">Page files</td>'.NL.
336                              '   <td class="oprph_sum_col2">'.$page_counter.'</td>'.NL.
337                              ' </tr>'.NL.
338                              ' <tr>'.NL.
339                              '   <td>Media files</td>'.NL.
340                              '   <td>'.$media_file_counter.'</td>'.NL.
341                              ' </tr>'.NL.
342                              ' <tr>'.NL.
343                              '   <td>Media references</td>'.NL.
344                              '   <td>'.$refLink_counter.'</td>'.NL.
345                              ' </tr>'.NL.
346                              ' <tr>'.NL.
347                              '   <td>Filter</td>'.NL.
348                              '   <td>'.$defFileTypes2.'</td>'.NL.
349                              ' </tr>'.NL.
350                              ' <tr>'.NL.
351                              '   <td><b>Valid</b>, qualified references</td>'.NL.
352                              '   <td>'.$valid_counter.'</td>'.NL.
353                              ' </tr>'.NL.
354                              ' <tr>'.NL.
355                              '   <td><b>Valid</b>, relative references</td>'.NL.
356                              '   <td>'.$relative_counter.'</td>'.NL.
357                              ' </tr>'.NL.
358                              ' <tr>'.NL.
359                              '   <td><b>Missing</b> media files</td>'.NL.
360                              '   <td>'.$missing_counter.'</td>'.NL.
361                              ' </tr>'.NL.
362                              ' <tr>'.NL.
363                              '   <td><b>Orphan</b> media files</td>'.NL.
364                              '   <td>'.$orphan_counter.'</td>'.NL.
365                              ' </tr>'.NL.
366                              '</table></div>'.NL;
367
368
369            if((stristr($data[0], "valid")===false) && (stristr($data[0], "all")===false)){
370                $output_valid='';
371            }
372            if((stristr($data[0], "relative")===false) && (stristr($data[0], "all")===false)){
373                $output_relative='';
374            }
375            if((stristr($data[0], "missing")===false) && (stristr($data[0], "all")===false)){
376                $output_missing='';
377            }
378            if((stristr($data[0], "orphan")===false) && (stristr($data[0], "all")===false)){
379                $output_orphan='';
380            }
381
382            $renderer->doc .= $output.$output_summary.$output_valid.$output_relative.$output_missing.$output_orphan;
383
384            return true;
385    }
386/******************************************************************************/
387/* loop through media directory and collect all media files
388/* consider: filter for media file extension if given
389*/
390    function _get_allMediaFiles($dir, $defFileTypes) {
391        $listDir = array();
392        if(is_dir($dir)) {
393            if($handler = opendir($dir)) {
394                while (FALSE !== ($sub = readdir($handler))) {
395                    if ($sub !== "." && $sub !== "..") {
396                        if(is_file($dir."/".$sub)) {
397                            //get the current file extension ---------------------
398                            $parts = explode(".", $sub);
399                            if (is_array($parts) && count($parts) > 1) {
400                                 $extension = end($parts);
401                                 $extension = ltrim($extension, ".");
402                            }
403                            //--------------------------------------------
404                            if($defFileTypes === '') {
405                            // Thumb.db is created automatically sometimes and to be ignored always
406                            if(stripos($sub,"thumbs.db")===false) $listDir[] = $dir."/".$sub;
407                                //echo sprintf("<p><b>%s</b></p>\n", $dir."/".$sub);
408                            }
409                            // if media file extension filters are set on syntax line the $defFileTypes containing a string of all
410                            // and is the string to search the current file extension in
411                            elseif(strpos($defFileTypes, $extension)!==false) {
412                                $listDir[] = $dir."/".$sub;
413                                //echo sprintf("<p><b>%s</b></p>\n", $dir."/".$sub);
414                            }
415                        }
416                        elseif(is_dir($dir."/".$sub)) {
417                            $listDir[$sub] = $this->_get_allMediaFiles($dir."/".$sub, $defFileTypes);
418                            //echo sprintf("<p><b>%s</b></p>\n", $dir."/".$sub);;
419                        }
420                    }
421                }
422                closedir($handler);
423            }
424        }
425        return $listDir;
426    }
427/******************************************************************************/
428/* loop through data/pages directory and collect all page files
429*/
430    function _get_allPageFiles($dir, $data) {
431        $listDir = array();
432        if(is_dir($dir)) {
433
434            if($handler = opendir($dir)) {
435                while (FALSE !== ($sub = readdir($handler))) {
436                    if ($sub !== "." && $sub !== "..") {
437                        if(is_file($dir."/".$sub)) {
438                            //get the current file extension ---------------------
439                            $parts = explode(".", $sub);
440                            if (is_array($parts) && count($parts) > 1) {
441                                 $extension = end($parts);
442                                 $extension = ltrim($extension, ".");
443                            }
444                            //--------------------------------------------
445                            if(($extension === "txt")){
446                                $listDir[] = $dir."/".$sub;
447                                //echo sprintf("<p><b>%s</b></p>\n", $dir."/".$sub);
448                              }
449                        }
450                        elseif(is_dir($dir."/".$sub)) {
451//                            echo $data[1]." : ".stripos($dir."/".$sub,$data[1])."  -> dir/sub:  ".$dir."/".$sub."<br>";
452                            // $data[1] = skip ns
453                            if(stripos($dir."/".$sub,$data[1])>0) {
454//                              echo "dir/sub (skipped):  ".$perPage_MediaLinks[$i]."<br>";
455                              continue;
456                            }
457                            else $listDir[$sub] = $this->_get_allPageFiles($dir."/".$sub, $data);
458                        }
459                    }
460                }
461                closedir($handler);
462            }
463        }
464        return $listDir;
465    }
466
467/******************************************************************************/
468/* loop through pages and extract their media links
469*/
470    function _get_allMediaLinks($listPageFiles, $defFileTypes, $skip_NS) {
471        $_all_links = array();
472        $pageCounter = 0;
473        $linkCounter = 1;
474        define('LINK_PATTERN', '/\{\{.*?\}\}/s');
475        define('LINK_PATTERNtwo', "/<flashplayer.*>file=(?<link>.*)\x26.*<\/flashplayer>|<flashplayer.*>file=(?<all>.*)<\/flashplayer>/");
476        define('LINK_PATTERNthree', "/\[\[(?<link>\\\\.*)\|.*\]\]|\[\[(?<all>\\\\.*)\]\]/");
477        define('LINK_PATTERNfour', "/'\{\{gallery>*?\}\}'/");
478        define('LINK_PATTERNfive', "/'\{\{map>*?\}\}'/");
479
480        // get all defined tags where media links inbetween are to be ignored
481        $ignore_tags = array();
482        $ignore_tags = parse_ini_file(DOKU_PLUGIN."orphanmedia2/config.ini");
483        if (file_exists(DOKU_PLUGIN."orphanmedia2/user_pattern.ini")) $ignore_tags = $ignore_tags + parse_ini_file(DOKU_PLUGIN."orphanmedia2/user_pattern.ini");
484
485        foreach($listPageFiles as $page_filepath) {
486            $_all_links[$pageCounter][0] = $page_filepath;
487            // read the content of the page file to be analyzed for media links
488            $body = strtolower(file_get_contents($page_filepath));
489
490            // -----------------------------------
491            // ignore content between defined tags e.g. '<code> ... </code>'
492            $body = preg_replace($ignore_tags,' ',$body);
493            // find all page-> media links defined by Link pattern into $links
494             $links = array();
495             {
496                 preg_match_all(LINK_PATTERN, $body, $links);
497                 $links = $this->array_flat($links);
498
499/*        echo '<pre>';
500        print_r($links);
501        echo '</pre>';
502*/
503
504             }
505            // -----------------------------------
506            // Exception for flashplayer plugin where file reference is not inside curly brackets
507            // RegEx -> SubPattern and Alternate used as follows
508            // /<flashplayer.*>file=(?<link>.*)\x26.*<\/flashplayer>|<flashplayer.*>file=(?<all>.*)<\/flashplayer>/
509            // check online at http://www.solmetra.com/scripts/regex/index.php
510            // -----------------------------------
511            // Case 0: link with appended options -> initial pattern applies
512            // Case 1: link without options -> alternate pattern applies
513            // -----------------------------------
514            // results in:
515            /* Array
516              (   [0] => Array
517                      ( [0] => <flashplayer width=610 height=480>file=/doku/_media/foo/bar.flv&autostart=true</flashplayer>
518                        [1] => <flashplayer width=610 height=480>file=/doku/_media/foo/bar.flv</flashplayer> )
519                  [link] => Array
520                      ( [0] => /doku/_media/foo/bar.flv
521                        [1] => )
522                  [1] => Array
523                      ( [0] => /doku/_media/foo/bar.flv
524                        [1] => )
525                  [all] => Array
526                      ( [0] =>
527                        [1] => /doku/_media/foo/bar.flv )
528                  [2] => Array
529                      ( [0] =>
530                        [1] => /doku/_media/foo/bar.flv )
531              ) */
532            $flashpl_links = array();
533            $a_links = array();
534            if( preg_match(LINK_PATTERNtwo, $body) ) {
535                preg_match_all(LINK_PATTERNtwo, $body, $flashpl_links);
536                //finally loop through link and all and pick-up all non-empty fields
537                foreach($flashpl_links['link'] as $flashpl_link) {
538                    if(strlen($flashpl_link)>3) $a_links[] = $flashpl_link;
539                }
540                foreach($flashpl_links['all'] as $flashpl_link) {
541                    if(strlen($flashpl_link)>3) $a_links[] = $flashpl_link;
542                }
543                unset($flashpl_links);
544                $flashpl_links = $a_links;
545
546            }
547            // -----------------------------------
548            // Exception for Windows Shares like [[\\server\share|this]] are recognized, too.
549            // RegEx -> SubPattern and Alternate used as follows
550            // /\[\[(?<link>\\\\.*)\x7c.*\]\]|\[\[(?<all>\\\\.*)\]\]/
551            // check online at http://www.solmetra.com/scripts/regex/index.php
552            // -----------------------------------
553            // Case 0: link with appended options -> initial pattern applies
554            // Case 1: link without options -> alternate pattern applies
555            // -----------------------------------
556            // results in:
557            /*Array
558              ( [0] => Array
559                      ( [0] => [[\\server\share|this]]
560                        [1] => [[\\server\share]] )
561                [link] => Array
562                      ( [0] => server\share
563                        [1] => )
564                [1] => Array
565                      ( [0] => server\share
566                        [1] => )
567                [all] => Array
568                      ( [0] =>
569                        [1] => server\share )
570                [2] => Array
571                      ( [0] =>
572                        [1] => server\share )
573              ) */
574             $fileshares = array();
575             $b_links = array();
576             if( preg_match(LINK_PATTERNthree, $body) ) {
577                 preg_match_all(LINK_PATTERNthree, $body, $fileshares);
578                //finally loop through link and all and pick-up all non-empty fields
579                foreach($fileshares['link'] as $flshare_link) {
580                    if(strlen($flshare_link)>3) $b_links[] = $flshare_link;
581                }
582                foreach($fileshares['all'] as $flshare_link) {
583                    if(strlen($flshare_link)>3) $b_links[] = $flshare_link;
584                }
585                unset($fileshares);
586                $fileshares = $b_links;
587             }
588
589             $imgmaps = array();
590             $c_links = array();
591             if( preg_match(LINK_PATTERNfour, $body) ) {
592                 preg_match_all(LINK_PATTERNfour, $body, $imgmaps);
593                //finally loop through link and all and pick-up all non-empty fields
594                foreach($imgmaps['link'] as $imgmaps_link) {
595                    if(strlen($imgmaps_link)>3) $c_links[] = $imgmaps_link;
596                }
597                foreach($imgmaps['all'] as $imgmaps_link) {
598                    if(strlen($imgmaps_link)>3) $c_links[] = $imgmaps_link;
599                }
600                unset($imgmaps);
601                $imgmaps = $c_links;
602             }
603
604             $galary = array();
605             $d_links = array();
606             if( preg_match(LINK_PATTERNfive, $body) ) {
607                 preg_match_all(LINK_PATTERNfive, $body, $galary);
608
609                 echo var_dump($galary);
610                //finally loop through link and all and pick-up all non-empty fields
611                foreach($galary['link'] as $galary_link) {
612                    if(strlen($galary_link)>3) $d_links[] = $galary_link;
613                }
614                foreach($galary['all'] as $imgmaps_link) {
615                    if(strlen($galary_link)>3) $d_links[] = $galary_link;
616                }
617                unset($galary);
618                $galary = $d_links;
619             }
620
621            // -----------------------------------
622            // loop through page-> media link array and prepare links
623            foreach($links as $media_link) {
624                // exclude http, tag and topic links
625                if(strlen($media_link)<3) continue;
626                //if(stristr($media_link, "http:")!==false) continue;
627                if(stristr($media_link, "tag>")!==false) continue;
628                if(stristr($media_link, "blog>")!==false) continue;
629                if(stristr($media_link, "topic>")!==false) continue;
630                if(stristr($media_link, "wikistatistics>")!==false) continue;
631            // ---------------------------------------------------------------
632                $media_link = $this->clean_link($media_link);
633                if(!$media_link) continue;    // ignore empty fields
634            // ---------------------------------------------------------------
635
636                // filter according $defFileTypes
637                if($defFileTypes !==""){
638                    $parts = explode(".", $media_link);
639                    if (is_array($parts) && count($parts) > 1) {
640                       $extension = end($parts);
641                       $extension = ltrim($extension, ".");
642                    }
643                  if(stristr($defFileTypes, $extension)===false) continue;
644                }
645                // collect all media links of the current page
646                //$page_filepath .= "|" . strtolower($media_link);
647                $_all_links[$pageCounter][$linkCounter] = strtolower($media_link);
648                $linkCounter++;
649             }
650
651             // loop through page-> flashplayer link array and prepare links
652             if(count($flashpl_links)>0) {
653                 foreach($flashpl_links as $flashpl_link) {
654                    if(strlen($flashpl_link)<3) continue;
655                    // filter according $defFileTypes
656                    if($defFileTypes !==""){
657                        $parts = explode(".", $flashpl_link);
658                        if (is_array($parts) && count($parts) > 1) {
659                           $extension = end($parts);
660                           $extension = ltrim($extension, ".");
661                        }
662                      if(stristr($defFileTypes, $extension)===false) continue;
663                    }
664
665                    // exclude external flashplayer links
666                    if((strlen($flashpl_link)>1) && strpos($flashpl_link, "://")<1) {
667                         // collect all flashplayer links of the current page
668                         $_all_links[$pageCounter][$linkCounter] = strtolower($flashpl_link);
669                         $linkCounter++;
670                    }
671                 }
672             }
673             // loop through page-> fileshare link array and prepare links
674             if(count($fileshares)>0) {
675                 foreach($fileshares as $fileshare_link) {
676                    if(strlen($fileshare_link)<3) continue;
677                    // filter according $defFileTypes
678                    if($defFileTypes !==""){
679                        $parts = explode(".", $fileshare_link);
680                        if (is_array($parts) && count($parts) > 1) {
681                           $extension = end($parts);
682                           $extension = ltrim($extension, ".");
683                        }
684                      if(stristr($defFileTypes, $extension)===false) continue;
685                    }
686                    // exclude external flashplayer links
687                    if((strlen($fileshare_link)>1) && strpos($fileshare_link, "://")<1) {
688                         // collect all flashplayer links of the current page
689                         $_all_links[$pageCounter][$linkCounter] = strtolower($fileshare_link);
690                         $linkCounter++;
691                    }
692                 }
693             }
694
695             // loop through page-> imgmaps link array and prepare links
696             if(count($imgmaps)>0) {
697                 foreach($imgmaps as $imgmaps_link) {
698                    if(strlen($imgmaps_link)<3) continue;
699                    // filter according $defFileTypes
700                    if($defFileTypes !==""){
701                        $parts = explode(".", $imgmaps_link);
702                        if (is_array($parts) && count($parts) > 1) {
703                           $extension = end($parts);
704                           $extension = ltrim($extension, ".");
705                        }
706                      if(stristr($defFileTypes, $extension)===false) continue;
707                    }
708                    // exclude external imgmaps links
709                    if((strlen($imgmaps_link)>1) && strpos($imgmaps_link, "://")<1) {
710                         // collect all imgmaps links of the current page
711                         $_all_links[$pageCounter][$linkCounter] = strtolower($imgmaps_link);
712                         $linkCounter++;
713                    }
714                 }
715             }
716
717             // loop through page-> galary link array and prepare links
718             if(count($galary)>0) {
719                 foreach($galary as $galary_link) {
720                    if(strlen($galary_link)<3) continue;
721                    // filter according $defFileTypes
722                    if($defFileTypes !==""){
723                        $parts = explode(".", $galary_link);
724                        if (is_array($parts) && count($parts) > 1) {
725                           $extension = end($parts);
726                           $extension = ltrim($extension, ".");
727                        }
728                      if(stristr($defFileTypes, $extension)===false) continue;
729                    }
730                    // exclude external galary links
731                    if((strlen($galary_link)>1) && strpos($galary_link, "://")<1) {
732                         // collect all galary links of the current page
733                         $_all_links[$pageCounter][$linkCounter] = strtolower($galary_link);
734                         $linkCounter++;
735                    }
736                 }
737             }
738
739            // do merge media and flashplayer arrays
740            // $page_filepath string does already contain all local media and flashplayer links separated by "|"
741            //$page_filepath = preg_replace(":","/",$page_filepath);
742            //$page_filepath = preg_replace("|","<br />",$page_filepath);
743//            echo var_dump($_all_links[$pageCounter]).'<br />';
744            $pageCounter++;
745            $linkCounter = 1;
746        }
747
748        return $_all_links;
749    }
750//---------------------------------------------------------------------------------------
751    // flatten the hierarchical arry to store path + file at first "column"
752    function array_flat($array) {
753        $out=array();
754        foreach($array as $k=>$v){
755            if(is_array($array[$k]))  { $out=array_merge($out,$this->array_flat($array[$k])); }
756            else  { $out[]=$v; }
757        }
758        return $out;
759    }
760//---------------------------------------------------------------------------------------
761    function clean_link($xBody)
762    { // evaluate the media link by DW embedded function
763       $link = Doku_Handler_Parse_Media($xBody);
764       if (stripos($link['src'],'>') === false) $xBody = $link['src'];
765       else $xBody = '';
766       return $xBody;
767    }
768// ---------------------------------------------------------------
769    function _prepare_output($m_link,$page,$img,$counter,$class=NULL)
770    {
771            global $conf;
772            // all media files checked with current media link from current page
773            //extract page file name
774            $p_filename = basename($page);
775            //cut everything before pages/ from link
776            $y_pos=strpos($page, "pages");
777            $t1 = substr($page, $y_pos);
778            $t1 = substr(str_replace( ".txt" , "" , $t1 ) , 5, 9999);
779
780            if(!$conf['useslash']) $t2 = str_replace("/", ":", $t1);
781            else $t2 = $t1;
782
783            $t2 = '<a class=wikilink1 href="'. DOKU_URL . "doku.php?id=" . substr($t2, 1, strlen($t2));
784            $t1 =  $t2 . '" title="' . $t1 . '" rel="nofollow">' . $t1 . '</a>';
785
786
787            $output.= '<tr>'.NL.
788                      '   <td class="col0 centeralign"><img src="'.DOKU_URL.'lib/plugins/orphanmedia2/images/'.$img.'" align="middle" /></td>'.NL.
789                      '   <td>'.$counter.'</td>'.NL.
790                      '   <td>' . $t1 . "</td><td>" . $m_link . '</td>'.
791                      '</tr>'.NL;
792        return $output;
793    }
794// ---------------------------------------------------------------
795    function url_exist($url){
796        $fb_url = $url;
797        $url = @parse_url($url);
798        if (!$url) return false;
799        $url = array_map('trim', $url);
800        $url['port'] = (!isset($url['port'])) ? 80 : (int)$url['port'];
801        $path = (isset($url['path'])) ? $url['path'] : '';
802        if ($path == '')   $path = '/';
803        $path .= (isset($url['query'])) ?  "?$url[query] " : '';
804        if (isset($url['host']) AND $url['host'] != gethostbyname($url['host']))
805        {
806           $headers = @get_headers( "$url[scheme]://$url[host]:$url[port]$path ");
807           $headers = (is_array($headers)) ? implode( "n ", $headers) : $headers;
808//           return (bool)preg_match('#^HTTP/.*s+[(200|301|302)]+s#i', $headers);
809           return true;
810        }
811        return false;
812    }
813// ---------------------------------------------------------------
814      function getResizeRatio($maxwidth,$maxheight=0){
815          if(!$maxheight) $maxheight = $maxwidth;
816          $ratio = 1;
817          if($w >= $h) {
818              if($w >= $maxwidth){ $ratio = $maxwidth/$w; }
819              elseif($h > $maxheight) { $ratio = $maxheight/$h; }
820          }
821          else {
822              if($h >= $maxheight) { $ratio = $maxheight/$h; }
823              elseif($w > $maxwidth) { $ratio = $maxwidth/$w; }
824          }
825          return $ratio;
826      }
827// ---------------------------------------------------------------
828/******************************************************************************/
829/* get execution time in seconds at current point of call                     *
830 * @return float Execution time at this point of call                         *
831 * source: http://www.php.net/microtime                                       */
832  function get_execution_time()
833  {   static $microtime_start = null;
834      if($microtime_start === null)
835      {   $microtime_start = microtime(true);
836          return 0.0; }
837      return round(microtime(true) - $microtime_start, 3);
838  }
839// ---------------------------------------------------------------
840}
841