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