diff --git a/common.php b/common.php index c58637eb8..caaf7e207 100644 --- a/common.php +++ b/common.php @@ -302,8 +302,18 @@ function make_rand_str(int $length = 10): string return $randomString; } -function array_deep(&$var, $fn, $one_dimensional = false, $array_only = false) +function array_deep(&$var, $fn, $one_dimensional = false, $array_only = false, $timeout = false) { + if ($timeout) { + static $recursions = 0; + if (time() > (TIMENOW + $timeout)) { + return [ + 'timeout' => true, + 'recs' => $recursions + ]; + } + $recursions++; + } if (is_array($var)) { foreach ($var as $k => $v) { if (is_array($v)) { @@ -312,7 +322,7 @@ function array_deep(&$var, $fn, $one_dimensional = false, $array_only = false) } elseif ($array_only) { $var[$k] = $fn($v); } else { - array_deep($var[$k], $fn); + array_deep($var[$k], $fn, timeout: $timeout); } } elseif (!$array_only) { $var[$k] = $fn($v); diff --git a/feed.php b/feed.php index 0f1736032..6409116f7 100644 --- a/feed.php +++ b/feed.php @@ -27,7 +27,6 @@ if ($mode === 'get_feed_url' && ($type === 'f' || $type === 'u') && $id >= 0) { if ($type == 'f') { // Check if the user has actually sent a forum ID $sql = "SELECT allow_reg_tracker, forum_name FROM " . BB_FORUMS . " WHERE forum_id = $id LIMIT 1"; - //DIE($sql); if (!$forum_data = DB()->fetch_row($sql)) { if ($id == 0) { $forum_data = []; diff --git a/library/config.php b/library/config.php index d018ec6fe..2dc6fd77d 100644 --- a/library/config.php +++ b/library/config.php @@ -540,7 +540,7 @@ $bb_cfg['mem_on_start'] = memory_get_usage(); $bb_cfg['translate_dates'] = true; // in displaying time $bb_cfg['use_word_censor'] = true; $bb_cfg['show_jumpbox'] = true; // Whether to show jumpbox (on viewtopic.php and viewforum.php) - +$bb_cfg['flist_time_limit'] = 15; // Max number of seconds to process file lists before throwing an error $bb_cfg['last_visit_date_format'] = 'd-M H:i'; $bb_cfg['last_post_date_format'] = 'd-M-y H:i'; $bb_cfg['poll_max_days'] = 180; // How many days will the poll be active diff --git a/src/Legacy/TorrentFileList.php b/src/Legacy/TorrentFileList.php index 25e152096..19a126f90 100644 --- a/src/Legacy/TorrentFileList.php +++ b/src/Legacy/TorrentFileList.php @@ -41,10 +41,12 @@ class TorrentFileList */ public function get_filelist() { - global $html; - if (($this->tor_decoded['info']['meta version'] ?? 1) === 2) { - if (is_array($this->tor_decoded['info']['file tree'] ?? null)) { - return $this->fileTreeList($this->tor_decoded['info']['file tree'], $this->tor_decoded['info']['name'] ?? ''); //v2 + global $bb_cfg, $html; + + $info = &$this->tor_decoded['info']; + if (isset($info['meta version'], $info['file tree'])) { //v2 + if (($info['meta version']) === 2 && is_array($info['file tree'])) { + return $this->fileTreeList($info['file tree'], $info['name'] ?? '', $bb_cfg['flist_time_limit']); } } @@ -69,7 +71,9 @@ class TorrentFileList */ private function build_filelist_array() { - $info = $this->tor_decoded['info']; + global $bb_cfg; + + $info = &$this->tor_decoded['info']; if (isset($info['name.utf-8'])) { $info['name'] =& $info['name.utf-8']; @@ -90,7 +94,11 @@ class TorrentFileList if (isset($f['attr']) && $f['attr'] === 'p') { continue; } - array_deep($f['path'], 'clean_tor_dirname'); + + $structure = array_deep($f['path'], 'clean_tor_dirname', timeout: $bb_cfg['flist_time_limit']); + if (isset($structure['timeout'])) { + bb_die("Timeout, too many nested files/directories for file listing, aborting after \n{$structure['recs']} recursive calls.\nNesting level: " . count($info['files'], COUNT_RECURSIVE)); + } $length = isset($f['length']) ? (float)$f['length'] : 0; $subdir_count = \count($f['path']) - 1; @@ -137,14 +145,22 @@ class TorrentFileList * @param string $name * @return string */ - public function fileTreeList(array $array, string $name = ''): string + public function fileTreeList(array $array, string $name = '', int $timeout = 0, bool $child = false): string { $allItems = ''; + if ($timeout) { + static $recursions = 0; + if (time() > (TIMENOW + $timeout)) { + bb_die("Timeout, too many nested files/directories for file listing, aborting after \n$recursions recursive calls.\nNesting level: " . count($this->tor_decoded['info']['file tree'], COUNT_RECURSIVE)); + } + $recursions++; + } + foreach ($array as $key => $value) { - $key = htmlCHR($key); + $key = clean_tor_dirname($key); if (!isset($value[''])) { - $html_v2 = $this->fileTreeList($value); + $html_v2 = $this->fileTreeList($value, timeout: $timeout, child: true); $allItems .= "