Subversion Repositories oidplus

Rev

Rev 368 | Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. <?php
  2.  
  3. /*
  4.  * OIDplus 2.0
  5.  * Copyright 2020 Daniel Marschall, ViaThinkSoft
  6.  *
  7.  * Licensed under the Apache License, Version 2.0 (the "License");
  8.  * you may not use this file except in compliance with the License.
  9.  * You may obtain a copy of the License at
  10.  *
  11.  *     http://www.apache.org/licenses/LICENSE-2.0
  12.  *
  13.  * Unless required by applicable law or agreed to in writing, software
  14.  * distributed under the License is distributed on an "AS IS" BASIS,
  15.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16.  * See the License for the specific language governing permissions and
  17.  * limitations under the License.
  18.  */
  19.  
  20. class OIDplusPagePublicResources extends OIDplusPagePluginPublic {
  21.  
  22.         private function getMainTitle() {
  23.                 return _L('Documents and Resources');
  24.         }
  25.  
  26.         public function init($html=true) {
  27.                 OIDplus::config()->prepareConfigKey('resource_plugin_autoopen_level', 'Resource plugin: How many levels should be open in the treeview when OIDplus is loaded?', '1', OIDplusConfig::PROTECTION_EDITABLE, function($value) {
  28.                         if (!is_numeric($value) || ($value < 0)) {
  29.                                 throw new OIDplusException(_L('Please enter a valid value.'));
  30.                         }
  31.                 });
  32.                 OIDplus::config()->deleteConfigKey('resource_plugin_title');
  33.                 OIDplus::config()->deleteConfigKey('resource_plugin_path');
  34.                 OIDplus::config()->prepareConfigKey('resource_plugin_hide_empty_path','Resource plugin: Hide empty paths? (0=no, 1=yes)', '1', OIDplusConfig::PROTECTION_EDITABLE, function($value) {
  35.                         if (!is_numeric($value) || (($value != 0) && ($value != 1))) {
  36.                                 throw new OIDplusException(_L('Please enter a valid value (0=no, 1=yes).'));
  37.                         }
  38.                 });
  39.         }
  40.  
  41.         private static function getDocumentContent($file) {
  42.                 $file = rtrim(OIDplus::basePath(),'/').'/'.self::realname($file);
  43.                 $file2 = preg_replace('/\.([^.]+)$/', '$'.OIDplus::getCurrentLang().'.\1', $file);
  44.                 if (file_exists($file2)) $file = $file2;
  45.  
  46.                 $cont = file_get_contents($file);
  47.                
  48.                 list($html, $js, $css) = extractHtmlContents($cont);
  49.                 $cont = '';
  50.                 if (!empty($js))  $cont .= "<script>\n$js\n</script>";
  51.                 if (!empty($css)) $cont .= "<style>\n$css\n</style>";
  52.                 $cont .= $html;
  53.                
  54.                 return $cont;
  55.         }
  56.  
  57.         private static function getDocumentTitle($file) {
  58.                 $file = rtrim(OIDplus::basePath(),'/').'/'.self::realname($file);
  59.                 $file2 = preg_replace('/\.([^.]+)$/', '$'.OIDplus::getCurrentLang().'.\1', $file);
  60.                 if (file_exists($file2)) $file = $file2;
  61.  
  62.                 $cont = file_get_contents($file);
  63.  
  64.                 // make sure the program works even if the user provided HTML is not UTF-8
  65.                 $cont = iconv(mb_detect_encoding($cont, mb_detect_order(), true), 'UTF-8//IGNORE', $cont);
  66.                 $bom = pack('H*','EFBBBF');
  67.                 $cont = preg_replace("/^$bom/", '', $cont);
  68.  
  69.                 $m = array();
  70.                 if (preg_match('@<title>(.+)</title>@ismU', $cont, $m)) return $m[1];
  71.                 if (preg_match('@<h1>(.+)</h1>@ismU', $cont, $m)) return $m[1];
  72.                 if (preg_match('@<h2>(.+)</h2>@ismU', $cont, $m)) return $m[1];
  73.                 if (preg_match('@<h3>(.+)</h3>@ismU', $cont, $m)) return $m[1];
  74.                 if (preg_match('@<h4>(.+)</h4>@ismU', $cont, $m)) return $m[1];
  75.                 if (preg_match('@<h5>(.+)</h5>@ismU', $cont, $m)) return $m[1];
  76.                 if (preg_match('@<h6>(.+)</h6>@ismU', $cont, $m)) return $m[1];
  77.                 return pathinfo($file, PATHINFO_FILENAME); // filename without extension
  78.         }
  79.  
  80.         private static function myglob($reldir, $onlydir=false) {
  81.                 $out = array();
  82.  
  83.                 $root = OIDplus::basePath().'/userdata/resources/';
  84.                 $res = $onlydir ? glob($root.ltrim($reldir,'/'), GLOB_ONLYDIR) : glob($root.ltrim($reldir,'/'));
  85.                 foreach ($res as &$x) {
  86.                         $x = substr($x, strlen($root));
  87.                         if (strpos($x,'$') !== false) continue;
  88.                         $out[] = $x;
  89.                 }
  90.  
  91.                 $root = OIDplus::basePath().'/res/';
  92.                 $res = $onlydir ? glob($root.ltrim($reldir,'/'), GLOB_ONLYDIR) : glob($root.ltrim($reldir,'/'));
  93.                 foreach ($res as $x) {
  94.                         $x = substr($x, strlen($root));
  95.                         if (strpos($x,'$') !== false) continue;
  96.                         $out[] = $x;
  97.                 }
  98.  
  99.                 return array_unique($out);
  100.         }
  101.  
  102.         private static function realname($rel) {
  103.                 $candidate1 = OIDplus::basePath().'/userdata/resources/'.$rel;
  104.                 $candidate2 = OIDplus::basePath().'/res/'.$rel;
  105.                 if (file_exists($candidate1) || is_dir($candidate1)) return "userdata/resources/$rel";
  106.                 if (file_exists($candidate2) || is_dir($candidate2)) return "res/$rel";
  107.         }
  108.  
  109.         public function gui($id, &$out, &$handled) {
  110.                 if (explode('$',$id,2)[0] === 'oidplus:resources') {
  111.                         $handled = true;
  112.  
  113.                         $file = @explode('$',$id)[1];
  114.  
  115.                         // Security checks
  116.  
  117.                         if (
  118.                                 ($file != '') && (
  119.                                 (strpos($file, chr(0)) !== false) || // Directory traversal (LFI,RFI) helper
  120.                                 (strpos($file, '../') !== false) || ($file[0] == '/') || ($file[0] == '~') || // <-- Local File Injection (LFI)
  121.                                 ($file[0] == '.') || (strpos($file, '/.') !== false) ||                       // <-- Calling hidden files e.g. ".htpasswd"
  122.                                 (strpos($file, '://') !== false)                                              // <-- Remote File Injection (RFI)
  123.                            )) {
  124.                                 if (strpos($file, chr(0)) !== false) {
  125.                                         $file = str_replace(chr(0), '[NUL]', $file);
  126.                                 }
  127.                                 OIDplus::logger()->log("[WARN]A!", "LFI/RFI attack blocked (requested file '$file')");
  128.                                 $out['title'] = _L('Access denied');
  129.                                 $out['icon'] = 'img/error_big.png';
  130.                                 $out['text'] = '<p>'._L('This request is invalid').'</p>';
  131.                                 return;
  132.                         }
  133.  
  134.                         $out['text'] = '';
  135.  
  136.                         // First, "Go back to" line
  137.  
  138.                         if ($file != '') {
  139.                                 $dir = dirname($file);
  140.  
  141.                                 if ($dir == '.') {
  142.                                         if (file_exists(__DIR__.'/treeicon.png')) {
  143.                                                 $tree_icon = OIDplus::webpath(__DIR__).'treeicon.png';
  144.                                         } else {
  145.                                                 $tree_icon = null; // default icon (folder)
  146.                                         }
  147.  
  148.                                         $ic = empty($tree_icon) ? '' : '<img src="'.$tree_icon.'" alt="">';
  149.  
  150.                                         $lng_gobackto = _L('Go back to').':';
  151.                                         $out['text'] .= '<p><a '.OIDplus::gui()->link('oidplus:resources').'><img src="img/arrow_back.png" width="16" alt="'._L('Go back').'"> '.$lng_gobackto.' '.$ic.' '.htmlentities($this->getMainTitle()).'</a></p>';
  152.                                 } else {
  153.                                         $realdir = self::realname($dir);
  154.  
  155.                                         $tree_icon = OIDplus::webpath(__DIR__).'show_icon.php?mode=treeicon_folder&lang='.OIDplus::getCurrentLang().'&file='.urlencode($dir);
  156.                                         /*
  157.                                         $icon_candidate = pathinfo($realdir)['dirname'].'/'.pathinfo($realdir)['filename'].'_tree.png';
  158.                                         if (file_exists($icon_candidate)) {
  159.                                                 $tree_icon = $icon_candidate;
  160.                                         } else if (file_exists(__DIR__.'/treeicon_folder.png')) {
  161.                                                 $tree_icon = OIDplus::webpath(__DIR__).'treeicon_folder.png';
  162.                                         } else {
  163.                                                 $tree_icon = null; // no icon
  164.                                         }
  165.                                         */
  166.  
  167.                                         $ic = empty($tree_icon) ? '' : '<img src="'.$tree_icon.'" alt="">';
  168.  
  169.                                         $out['text'] .= '<p><a '.OIDplus::gui()->link('oidplus:resources$'.rtrim($dir,'/').'/').'><img src="img/arrow_back.png" width="16" alt="'._L('Go back').'"> '._L('Go back to').': '.$ic.' '.htmlentities(self::getFolderTitle($realdir)).'</a></p><br>';
  170.                                 }
  171.                         }
  172.  
  173.                         // Then the content
  174.  
  175.                         $realfile = self::realname($file);
  176.                         // $realfile2 = preg_replace('/\.([^.]+)$/', '$'.OIDplus::getCurrentLang().'.\1', $realfile);
  177.                         // if (file_exists($realfile2)) $realfile = $realfile2;
  178.  
  179.                         if (file_exists($realfile) && (!is_dir($realfile))) {
  180.                                 if ((substr($file,-4,4) == '.url') || (substr($file,-5,5) == '.link')) {
  181.                                         $out['title'] = $this->getHyperlinkTitle($realfile);
  182.  
  183.                                         $out['icon'] = OIDplus::webpath(__DIR__).'show_icon.php?mode=icon_leaf_url_big&lang='.OIDplus::getCurrentLang().'&file='.urlencode($file);
  184.                                         /*
  185.                                         $icon_candidate = pathinfo($realfile)['dirname'].'/'.pathinfo($realfile)['filename'].'_big.png';
  186.                                         if (file_exists($icon_candidate)) {
  187.                                                 $out['icon'] = $icon_candidate;
  188.                                         } else if (file_exists(__DIR__.'/icon_leaf_url_big.png')) {
  189.                                                 $out['icon'] = OIDplus::webpath(__DIR__).'icon_leaf_url_big.png';
  190.                                         } else {
  191.                                                 $out['icon'] = '';
  192.                                         }
  193.                                         */
  194.  
  195.                                         // Should not happen though, due to conditionalselect
  196.                                         $out['text'] .= '<a href="'.htmlentities(self::getHyperlinkURL($realfile)).'" target="_blank">'._L('Open in new window').'</a>';
  197.                                 } else if ((substr($file,-4,4) == '.htm') || (substr($file,-5,5) == '.html')) {
  198.                                         $out['title'] = $this->getDocumentTitle($file);
  199.  
  200.                                         $out['icon'] = OIDplus::webpath(__DIR__).'show_icon.php?mode=icon_leaf_doc_big&lang='.OIDplus::getCurrentLang().'&file='.urlencode($file);
  201.                                         /*
  202.                                         $icon_candidate = pathinfo($realfile)['dirname'].'/'.pathinfo($realfile)['filename'].'_big.png';
  203.                                         if (file_exists($icon_candidate)) {
  204.                                                 $out['icon'] = $icon_candidate;
  205.                                         } else if (file_exists(__DIR__.'/icon_leaf_doc_big.png')) {
  206.                                                 $out['icon'] = OIDplus::webpath(__DIR__).'icon_leaf_doc_big.png';
  207.                                         } else {
  208.                                                 $out['icon'] = '';
  209.                                         }
  210.                                         */
  211.  
  212.                                         $out['text'] .= self::getDocumentContent($file);
  213.                                 } else {
  214.                                         $out['title'] = _L('Unknown file type');
  215.                                         $out['icon'] = 'img/error_big.png';
  216.                                         $out['text'] = '<p>'._L('The system does not know how to handle this file type.').'</p>';
  217.                                         return;
  218.                                 }
  219.                         } else if (is_dir($realfile)) {
  220.                                 $out['title'] = ($file == '') ? $this->getMainTitle() : self::getFolderTitle($realfile);
  221.  
  222.                                 if ($file == '') {
  223.                                         $out['icon'] = file_exists(__DIR__.'/icon_big.png') ? OIDplus::webpath(__DIR__).'icon_big.png' : '';
  224.                                 } else {
  225.                                         $out['icon'] = OIDplus::webpath(__DIR__).'show_icon.php?mode=icon_folder_big&lang='.OIDplus::getCurrentLang().'&file='.urlencode($file);
  226.                                         /*
  227.                                         $icon_candidate = pathinfo($realfile)['dirname'].'/'.pathinfo($realfile)['filename'].'_big.png';
  228.                                         if (file_exists($icon_candidate)) {
  229.                                                 $out['icon'] = $icon_candidate;
  230.                                         } else if (file_exists(__DIR__.'/icon_folder_big.png')) {
  231.                                                 $out['icon'] = OIDplus::webpath(__DIR__).'icon_folder_big.png';
  232.                                         } else {
  233.                                                 $out['icon'] = null; // no icon
  234.                                         }
  235.                                         */
  236.                                 }
  237.  
  238.                                 if (file_exists(__DIR__.'/treeicon.png')) {
  239.                                         $tree_icon = OIDplus::webpath(__DIR__).'treeicon.png';
  240.                                 } else {
  241.                                         $tree_icon = null; // default icon (folder)
  242.                                 }
  243.  
  244.                                 $count = 0;
  245.  
  246.                                 $dirs = self::myglob(rtrim($file,'/').'/'.'*', true);
  247.                                 natcasesort($dirs);
  248.                                 foreach ($dirs as $dir) {
  249.                                         $realdir = self::realname($dir);
  250.                                         $tree_icon = OIDplus::webpath(__DIR__).'show_icon.php?mode=treeicon_folder&lang='.OIDplus::getCurrentLang().'&file='.urlencode($dir);
  251.                                         /*
  252.                                         $icon_candidate = pathinfo($realdir)['dirname'].'/'.pathinfo($realdir)['filename'].'_tree.png';
  253.                                         if (file_exists($icon_candidate)) {
  254.                                                 $tree_icon = $icon_candidate;
  255.                                         } else if (file_exists(__DIR__.'/treeicon_folder.png')) {
  256.                                                 $tree_icon = OIDplus::webpath(__DIR__).'treeicon_folder.png';
  257.                                         } else {
  258.                                                 $tree_icon = null; // no icon
  259.                                         }
  260.                                         */
  261.  
  262.                                         $ic = empty($tree_icon) ? '' : '<img src="'.$tree_icon.'" alt="">';
  263.  
  264.                                         $out['text'] .= '<p><a '.OIDplus::gui()->link('oidplus:resources$'.rtrim($dir,'/').'/').'>'.$ic.' '.htmlentities(self::getFolderTitle($realdir)).'</a></p>';
  265.                                         $count++;
  266.                                 }
  267.  
  268.                                 $files = array_merge(
  269.                                         self::myglob(rtrim($file,'/').'/'.'*.htm'), // TODO: also PHP?
  270.                                         self::myglob(rtrim($file,'/').'/'.'*.html'),
  271.                                         self::myglob(rtrim($file,'/').'/'.'*.url'),
  272.                                         self::myglob(rtrim($file,'/').'/'.'*.link')
  273.                                 );
  274.                                 natcasesort($files);
  275.                                 foreach ($files as $file) {
  276.                                         $realfile = self::realname($file);
  277.                                         if ((substr($file,-4,4) == '.url') || (substr($file,-5,5) == '.link')) {
  278.                                                 $tree_icon = OIDplus::webpath(__DIR__).'show_icon.php?mode=treeicon_leaf_url&lang='.OIDplus::getCurrentLang().'&file='.urlencode($file);
  279.                                                 /*
  280.                                                 $icon_candidate = pathinfo($realfile)['dirname'].'/'.pathinfo($realfile)['filename'].'_tree.png';
  281.                                                 if (file_exists($icon_candidate)) {
  282.                                                         $tree_icon = $icon_candidate;
  283.                                                 } else if (file_exists(__DIR__.'/treeicon_leaf_url.png')) {
  284.                                                         $tree_icon = OIDplus::webpath(__DIR__).'treeicon_leaf_url.png';
  285.                                                 } else {
  286.                                                         $tree_icon = null; // default icon (folder)
  287.                                                 }
  288.                                                 */
  289.  
  290.                                                 $ic = empty($tree_icon) ? '' : '<img src="'.$tree_icon.'" alt="">';
  291.  
  292.                                                 $hyperlink_pic = ' <img src="'.OIDplus::webpath(__DIR__).'hyperlink.png" widht="13" height="13" alt="Hyperlink" style="top:-3px;position:relative">';
  293.  
  294.                                                 $out['text'] .= '<p><a href="'.htmlentities(self::getHyperlinkURL($realfile)).'" target="_blank">'.$ic.' '.htmlentities($this->getHyperlinkTitle($realfile)).' '.$hyperlink_pic.'</a></p>';
  295.                                                 $count++;
  296.                                         } else {
  297.                                                 $tree_icon = OIDplus::webpath(__DIR__).'show_icon.php?mode=treeicon_leaf_doc&lang='.OIDplus::getCurrentLang().'&file='.urlencode($file);
  298.                                                 /*
  299.                                                 $icon_candidate = pathinfo($realfile)['dirname'].'/'.pathinfo($realfile)['filename'].'_tree.png';
  300.                                                 if (file_exists($icon_candidate)) {
  301.                                                         $tree_icon = $icon_candidate;
  302.                                                 } else if (file_exists(__DIR__.'/treeicon_leaf_doc.png')) {
  303.                                                         $tree_icon = OIDplus::webpath(__DIR__).'treeicon_leaf_doc.png';
  304.                                                 } else {
  305.                                                         $tree_icon = null; // default icon (folder)
  306.                                                 }
  307.                                                 */
  308.  
  309.                                                 $ic = empty($tree_icon) ? '' : '<img src="'.$tree_icon.'" alt="">';
  310.  
  311.                                                 $out['text'] .= '<p><a '.OIDplus::gui()->link('oidplus:resources$'.$file).'>'.$ic.' '.htmlentities($this->getDocumentTitle($file)).'</a></p>';
  312.                                                 $count++;
  313.                                         }
  314.                                 }
  315.  
  316.                                 if ($count == 0) {
  317.                                         $out['text'] .= '<p>'._L('This folder does not contain any elements').'</p>';
  318.                                 }
  319.                         } else {
  320.                                 $out['title'] = _L('Not found');
  321.                                 $out['icon'] = 'img/error_big.png';
  322.                                 $out['text'] = '<p>'._L('This resource doesn\'t exist anymore.').'</p>';
  323.                         }
  324.                 }
  325.         }
  326.  
  327.         private function tree_rec(&$children, $rootdir=null, $depth=0) {
  328.                 if (is_null($rootdir)) $rootdir = '';
  329.                 if ($depth > 100) return false; // something is wrong!
  330.  
  331.                 $dirs = self::myglob($rootdir.'*'.'/', true);
  332.                 natcasesort($dirs);
  333.                 foreach ($dirs as $dir) {
  334.                         $tmp = array();
  335.  
  336.                         $this->tree_rec($tmp, $dir, $depth+1);
  337.  
  338.                         $realdir = self::realname($dir);
  339.  
  340.                         $tree_icon = OIDplus::webpath(__DIR__).'show_icon.php?mode=treeicon_folder&lang='.OIDplus::getCurrentLang().'&file='.urlencode($dir);
  341.                         /*
  342.                         $icon_candidate = pathinfo($realdir)['dirname'].'/'.pathinfo($realdir)['filename'].'_tree.png';
  343.                         if (file_exists($icon_candidate)) {
  344.                                 $tree_icon = $icon_candidate;
  345.                         } else if (file_exists(__DIR__.'/treeicon_folder.png')) {
  346.                                 $tree_icon = OIDplus::webpath(__DIR__).'treeicon_folder.png';
  347.                         } else {
  348.                                 $tree_icon = null; // default icon (folder)
  349.                         }
  350.                         */
  351.  
  352.                         $children[] = array(
  353.                                 'id' => 'oidplus:resources$'.$dir,
  354.                                 'icon' => $tree_icon,
  355.                                 'text' => self::getFolderTitle($realdir),
  356.                                 'children' => $tmp,
  357.                                 'state' => array("opened" => $depth <= OIDplus::config()->getValue('resource_plugin_autoopen_level', 1)-1)
  358.                         );
  359.                 }
  360.  
  361.                 $files = array_merge(
  362.                         self::myglob($rootdir.'*.htm'), // TODO: Also PHP?
  363.                         self::myglob($rootdir.'*.html'),
  364.                         self::myglob($rootdir.'*.url'),
  365.                         self::myglob($rootdir.'*.link')
  366.                 );
  367.                 natcasesort($files);
  368.                 foreach ($files as $file) {
  369.                         $realfile = self::realname($file);
  370.                         if ((substr($file,-4,4) == '.url') || (substr($file,-5,5) == '.link')) {
  371.                                 $tree_icon = OIDplus::webpath(__DIR__).'show_icon.php?mode=treeicon_leaf_url&lang='.OIDplus::getCurrentLang().'&file='.urlencode($file);
  372.                                 /*
  373.                                 $icon_candidate = pathinfo($realfile)['dirname'].'/'.pathinfo($realfile)['filename'].'_tree.png';
  374.                                 if (file_exists($icon_candidate)) {
  375.                                         $tree_icon = $icon_candidate;
  376.                                 } else if (file_exists(__DIR__.'/treeicon_leaf_url.png')) {
  377.                                         $tree_icon = OIDplus::webpath(__DIR__).'treeicon_leaf_url.png';
  378.                                 } else {
  379.                                         $tree_icon = null; // default icon (folder)
  380.                                 }
  381.                                 */
  382.  
  383.                                 $hyperlink_pic = ' <img src="'.OIDplus::webpath(__DIR__).'hyperlink.png" widht="13" height="13" alt="Hyperlink" style="top:-3px;position:relative">';
  384.  
  385.                                 $children[] = array(
  386.                                         'id' => 'oidplus:resources$'.$file,
  387.                                         'conditionalselect' => 'window.open('.js_escape(self::getHyperlinkURL($realfile)).'); false;',
  388.                                         'icon' => $tree_icon,
  389.                                         'text' => $this->getHyperlinkTitle($realfile).' '.$hyperlink_pic,
  390.                                         'state' => array("opened" => $depth <= OIDplus::config()->getValue('resource_plugin_autoopen_level', 1)-1)
  391.                                 );
  392.                         } else {
  393.                                 $tree_icon = OIDplus::webpath(__DIR__).'show_icon.php?mode=treeicon_leaf_doc&lang='.OIDplus::getCurrentLang().'&file='.urlencode($file);
  394.                                 /*
  395.                                 $icon_candidate = pathinfo($realfile)['dirname'].'/'.pathinfo($realfile)['filename'].'_tree.png';
  396.                                 if (file_exists($icon_candidate)) {
  397.                                         $tree_icon = $icon_candidate;
  398.                                 } else if (file_exists(__DIR__.'/treeicon_leaf_doc.png')) {
  399.                                         $tree_icon = OIDplus::webpath(__DIR__).'treeicon_leaf_doc.png';
  400.                                 } else {
  401.                                         $tree_icon = null; // default icon (folder)
  402.                                 }
  403.                                 */
  404.                                 $children[] = array(
  405.                                         'id' => 'oidplus:resources$'.$file,
  406.                                         'icon' => $tree_icon,
  407.                                         'text' => $this->getDocumentTitle($file),
  408.                                         'state' => array("opened" => $depth <= OIDplus::config()->getValue('resource_plugin_autoopen_level', 1)-1)
  409.                                 );
  410.                         }
  411.                 }
  412.         }
  413.  
  414.         private function publicSitemap_rec($json, &$out) {
  415.                 foreach ($json as $x) {
  416.                         if (isset($x['id']) && $x['id']) {
  417.                                 $out[] = $x['id'];
  418.                         }
  419.                         if (isset($x['children'])) {
  420.                                 $this->publicSitemap_rec($x['children'], $out);
  421.                         }
  422.                 }
  423.         }
  424.  
  425.         public function publicSitemap(&$out) {
  426.                 $json = array();
  427.                 $this->tree($json, null/*RA EMail*/, false/*HTML tree algorithm*/, true/*display all*/);
  428.                 $this->publicSitemap_rec($json, $out);
  429.         }
  430.  
  431.         public function tree(&$json, $ra_email=null, $nonjs=false, $req_goto='') {
  432.                 $children = array();
  433.  
  434.                 $this->tree_rec($children, '/');
  435.  
  436.                 if (!OIDplus::config()->getValue('resource_plugin_hide_empty_path', true) || (count($children) > 0)) {
  437.                         if (file_exists(__DIR__.'/treeicon.png')) {
  438.                                 $tree_icon = OIDplus::webpath(__DIR__).'treeicon.png';
  439.                         } else {
  440.                                 $tree_icon = null; // default icon (folder)
  441.                         }
  442.  
  443.                         $json[] = array(
  444.                                 'id' => 'oidplus:resources',
  445.                                 'icon' => $tree_icon,
  446.                                 'state' => array("opened" => true),
  447.                                 'text' => $this->getMainTitle(),
  448.                                 'children' => $children
  449.                         );
  450.                 }
  451.  
  452.                 return true;
  453.         }
  454.  
  455.         public function tree_search($request) {
  456.                 return false;
  457.         }
  458.  
  459.         private static function getHyperlinkTitle($file) {
  460.                 $file2 = preg_replace('/\.([^.]+)$/', '$'.OIDplus::getCurrentLang().'.\1', $file);
  461.                 if (file_exists($file2)) $file = $file2;
  462.  
  463.                 if (substr($file,-4,4) == '.url') {
  464.                         return preg_replace('/\\.[^.\\s]{3,4}$/', '', basename($file));
  465.                 } else if (substr($file,-5,5) == '.link') {
  466.                         /*
  467.                         [Link]
  468.                         Title=Report a bug
  469.                         URL=https://www.viathinksoft.com/thinkbug/thinkbug.php?id=97
  470.                         */
  471.  
  472.                         $data = @parse_ini_file($file, true);
  473.                         if (!$data) {
  474.                                 throw new OIDplusException(_L('File %1 has an invalid INI format!',$file));
  475.                         }
  476.                         if (!isset($data['Link'])) {
  477.                                 throw new OIDplusException(_L('Could not find "%1" section at %2','Link',$file));
  478.                         }
  479.                         if (!isset($data['Link']['Title'])) {
  480.                                 throw new OIDplusException(_L('"%1" is missing in %2','Title',$file));
  481.                         }
  482.                         return $data['Link']['Title'];
  483.                 } else {
  484.                         throw new OIDplusException(_L('Unexpected file extension for file %1',$file));
  485.                 }
  486.         }
  487.  
  488.         private static function getHyperlinkURL($file) {
  489.                 $file2 = preg_replace('/\.([^.]+)$/', '$'.OIDplus::getCurrentLang().'.\1', $file);
  490.                 if (file_exists($file2)) $file = $file2;
  491.  
  492.                 if (substr($file,-4,4) == '.url') {
  493.                         /*
  494.                         [{000214A0-0000-0000-C000-000000000046}]
  495.                         Prop3=19,2
  496.                         [InternetShortcut]
  497.                         URL=http://www.example.com/
  498.                         IDList=
  499.                         */
  500.  
  501.                         $data = @parse_ini_file($file, true);
  502.                         if (!$data) {
  503.                                 throw new OIDplusException(_L('File %1 has an invalid INI format!',$file));
  504.                         }
  505.                         if (!isset($data['InternetShortcut'])) {
  506.                                 throw new OIDplusException(_L('Could not find "%1" section at %2','InternetShortcut',$file));
  507.                         }
  508.                         if (!isset($data['InternetShortcut']['URL'])) {
  509.                                 throw new OIDplusException(_L('"%1" is missing in %2','URL',$file));
  510.                         }
  511.                         return $data['InternetShortcut']['URL'];
  512.                 } else if (substr($file,-5,5) == '.link') {
  513.                         /*
  514.                         [Link]
  515.                         Title=Report a bug
  516.                         URL=https://www.viathinksoft.com/thinkbug/thinkbug.php?id=97
  517.                         */
  518.  
  519.                         $data = @parse_ini_file($file, true);
  520.                         if (!$data) {
  521.                                 throw new OIDplusException(_L('File %1 has an invalid INI format!',$file));
  522.                         }
  523.                         if (!isset($data['Link'])) {
  524.                                 throw new OIDplusException(_L('Could not find "%1" section at %2','Link',$file));
  525.                         }
  526.                         if (!isset($data['Link']['URL'])) {
  527.                                 throw new OIDplusException(_L('"%1" is missing in %2','URL',$file));
  528.                         }
  529.                         return $data['Link']['URL'];
  530.                 } else {
  531.                         throw new OIDplusException(_L('Unexpected file extension for file %1',$file));
  532.                 }
  533.  
  534.         }
  535.  
  536.         private static function getFolderTitle($dir) {
  537.                 $data = @parse_ini_file("$dir/folder\$".OIDplus::getCurrentLang().".ini", true);
  538.                 if ($data && isset($data['Folder']) && isset($data['Folder']['Title'])) {
  539.                         return $data['Folder']['Title'];
  540.                 }
  541.  
  542.                 $data = @parse_ini_file("$dir/folder.ini", true);
  543.                 if ($data && isset($data['Folder']) && isset($data['Folder']['Title'])) {
  544.                         return $data['Folder']['Title'];
  545.                 }
  546.  
  547.                 return basename($dir);
  548.         }
  549. }
  550.