From bdbda018d27f69c9a49c696100f09577140b102e Mon Sep 17 00:00:00 2001 From: camer0n Date: Wed, 17 Apr 2024 14:17:04 -0700 Subject: [PATCH] Issue #5208 - Start of PCLZip removal. --- e107_handlers/file_class.php | 3984 +++++++++++---------- e107_tests/tests/unit/e_jsmanagerTest.php | 2 +- 2 files changed, 2014 insertions(+), 1972 deletions(-) diff --git a/e107_handlers/file_class.php b/e107_handlers/file_class.php index 799c04b191..f9836a3ba5 100644 --- a/e107_handlers/file_class.php +++ b/e107_handlers/file_class.php @@ -1,165 +1,165 @@ setDefaults(); - } + $this->setDefaults(); + } - /** - * Set default parameters - * - * @return e_file - */ - function setDefaults() - { + /** + * Set default parameters + * + * @return e_file + */ + function setDefaults() + { - $this->dirFilter = array('/', 'CVS', '.svn'); // Default directory filter (exact matches only) - $this->fileFilter = array('^thumbs\.db$', '^Thumbs\.db$', '.*\._$', '^\.htaccess$', '^\.cvsignore$', '^\.ftpquota$', '^index\.html$', '^null\.txt$', '\.bak$', '^.tmp'); // Default file filter (regex format) + $this->dirFilter = array('/', 'CVS', '.svn'); // Default directory filter (exact matches only) + $this->fileFilter = array('^thumbs\.db$', '^Thumbs\.db$', '.*\._$', '^\.htaccess$', '^\.cvsignore$', '^\.ftpquota$', '^index\.html$', '^null\.txt$', '\.bak$', '^.tmp'); // Default file filter (regex format) - return $this; - } + return $this; + } - /** - * Set fileinfo mode - * - * @param string $val - * @return e_file - */ - public function setFileInfo($val = 'default') - { + /** + * Set fileinfo mode + * + * @param string $val + * @return e_file + */ + public function setFileInfo($val = 'default') + { - $this->finfo = $val; + $this->finfo = $val; - return $this; - } + return $this; + } /** @@ -167,1746 +167,1787 @@ public function setFileInfo($val = 'default') * @return $this */ public function setFileFilter($filter) - { + { - $this->fileFilter = $filter; + $this->fileFilter = $filter; - return $this; - } + return $this; + } - /** - * Clean and rename file name - * - * @param $f array as returned by get_files(); - * @param $rename boolean - set to true to rename file. - * @return array - */ - public function cleanFileName($f, $rename = false) - { + /** + * Clean and rename file name + * + * @param $f array as returned by get_files(); + * @param $rename boolean - set to true to rename file. + * @return array + */ + public function cleanFileName($f, $rename = false) + { - $fullpath = $f['path'] . $f['fname']; - $newfile = preg_replace("/[^a-z0-9-\._]/", "-", strtolower($f['fname'])); - $newpath = $f['path'] . $newfile; + $fullpath = $f['path'] . $f['fname']; + $newfile = preg_replace("/[^a-z0-9-\._]/", "-", strtolower($f['fname'])); + $newpath = $f['path'] . $newfile; - if($rename == true) - { + if($rename == true) + { - if(!rename($fullpath, $newpath)) - { - $f['error'] = "Couldn't rename $fullpath to $newpath"; - } + if(!rename($fullpath, $newpath)) + { + $f['error'] = "Couldn't rename $fullpath to $newpath"; } + } - $f['fname'] = $newfile; + $f['fname'] = $newfile; - return $f; - } + return $f; + } /** * @param $mode * @return void */ function setMode($mode) - { + { - $this->mode = $mode; - } + $this->mode = $mode; + } /** * @return null */ public function getErrorMessage() - { + { - return $this->error; - } + return $this->error; + } /** * @return null */ public function getErrorCode() - { + { - return $this->errornum; - } + return $this->errornum; + } - /** - * Read files from given path - * - * @param string $path - * @param string $fmask [optional] - * @param string $omit [optional] - * @param integer $recurse_level [optional] - * @return array of file names/paths - */ - function get_files($path, $fmask = '', $omit = 'standard', $recurse_level = 0) + /** + * Read files from given path + * + * @param string $path + * @param string $fmask [optional] + * @param string $omit [optional] + * @param integer $recurse_level [optional] + * @return array of file names/paths + */ + function get_files($path, $fmask = '', $omit = 'standard', $recurse_level = 0) + { + + $ret = array(); + $invert = false; + if(!empty($fmask) && strpos($fmask, '~') === 0) { - $ret = array(); - $invert = false; - if(!empty($fmask) && strpos($fmask, '~') === 0) - { - $invert = true; // Invert selection - exclude files which match selection - $fmask = substr($fmask, 1); - } + $invert = true; // Invert selection - exclude files which match selection + $fmask = substr($fmask, 1); + } - if($recurse_level < 0) - { - return $ret; - } + if($recurse_level < 0) + { + return $ret; + } - if(substr($path, -1) == '/') - { - $path = substr($path, 0, -1); - } + if(substr($path, -1) == '/') + { + $path = substr($path, 0, -1); + } - if(!is_dir($path) || !$handle = opendir($path)) + if(!is_dir($path) || !$handle = opendir($path)) + { + return $ret; + } + if(($omit == 'standard') || ($omit == '')) + { + $omit = $this->fileFilter; + } + else + { + if(!is_array($omit)) { - return $ret; + $omit = array($omit); } - if(($omit == 'standard') || ($omit == '')) + } + + while(false !== ($file = readdir($handle))) + { + if($file === '.' || $file === '..') { - $omit = $this->fileFilter; + continue; } - else - { - if(!is_array($omit)) + + if(is_dir($path . '/' . $file)) + { // Its a directory - recurse into it unless a filtered directory or required depth achieved + // Must always check for '.' and '..' + if(($recurse_level > 0) && !in_array($file, $this->dirFilter) && !in_array($file, $omit)) { - $omit = array($omit); + $xx = $this->get_files($path . '/' . $file, $fmask, $omit, $recurse_level - 1); + $ret = array_merge($ret, $xx); } } - - while(false !== ($file = readdir($handle))) + else { - if($file === '.' || $file === '..') - { - continue; - } + // Now check against standard reject list and caller-specified list + if(($fmask == '') || ($invert != preg_match("#" . $fmask . "#", $file))) + { // File passes caller's filter here + $rejected = false; - if(is_dir($path . '/' . $file)) - { // Its a directory - recurse into it unless a filtered directory or required depth achieved - // Must always check for '.' and '..' - if(($recurse_level > 0) && !in_array($file, $this->dirFilter) && !in_array($file, $omit)) + // Check against the generic file reject filter + foreach($omit as $rmask) { - $xx = $this->get_files($path . '/' . $file, $fmask, $omit, $recurse_level - 1); - $ret = array_merge($ret, $xx); - } - } - else - { - // Now check against standard reject list and caller-specified list - if(($fmask == '') || ($invert != preg_match("#" . $fmask . "#", $file))) - { // File passes caller's filter here - $rejected = false; - - // Check against the generic file reject filter - foreach($omit as $rmask) + if(preg_match("#" . $rmask . "#", $file)) { - if(preg_match("#" . $rmask . "#", $file)) - { - $rejected = true; - $this->filesRejected[] = $file; - break; // continue 2 may well work - } + $rejected = true; + $this->filesRejected[] = $file; + break; // continue 2 may well work } - if($rejected == false) + } + if($rejected == false) + { + switch($this->mode) { - switch($this->mode) - { - case 'fname': - $ret[] = $file; - break; - - case 'path': - $ret[] = $path . "/"; - break; - - case 'full': - $ret[] = $path . "/" . $file; - break; - - case 'all': - default: - if('default' != $this->finfo) - { - $finfo = $this->getFileInfo($path . "/" . $file, ('file' != $this->finfo)); // -> 'all' & 'image' - } - else - { - $finfo['path'] = $path . '/'; // important: leave this slash here and update other file instead. - $finfo['fname'] = $file; - } - // $finfo['path'] = $path.'/'; // important: leave this slash here and update other file instead. - // $finfo['fname'] = $file; - - $ret[] = $finfo; - break; - } + case 'fname': + $ret[] = $file; + break; + + case 'path': + $ret[] = $path . "/"; + break; + + case 'full': + $ret[] = $path . "/" . $file; + break; + + case 'all': + default: + if('default' != $this->finfo) + { + $finfo = $this->getFileInfo($path . "/" . $file, ('file' != $this->finfo)); // -> 'all' & 'image' + } + else + { + $finfo['path'] = $path . '/'; // important: leave this slash here and update other file instead. + $finfo['fname'] = $file; + } + // $finfo['path'] = $path.'/'; // important: leave this slash here and update other file instead. + // $finfo['fname'] = $file; + + $ret[] = $finfo; + break; } } } } - - return $ret; } + return $ret; + } - /** - * Return an extension for a specific mime-type. - * - * @param $mimeType - * @return string|null - */ - function getFileExtension($mimeType) - { - - $extensions = array( - 'application/ecmascript' => '.es', - 'application/epub+zip' => '.epub', - 'application/java-archive' => '.jar', - 'application/javascript' => '.js', - 'application/json' => '.json', - 'application/msword' => '.doc', - 'application/octet-stream' => '.bin', - 'application/ogg' => '.ogx', - 'application/pdf' => '.pdf', - 'application/rtf' => '.rtf', - 'application/typescript' => '.ts', - 'application/vnd.amazon.ebook' => '.azw', - 'application/vnd.apple.installer+xml' => '.mpkg', - 'application/vnd.mozilla.xul+xml' => '.xul', - 'application/vnd.ms-excel' => '.xls', - 'application/vnd.ms-fontobject' => '.eot', - 'application/vnd.ms-powerpoint' => '.ppt', - 'application/vnd.oasis.opendocument.presentation' => '.odp', - 'application/vnd.oasis.opendocument.spreadsheet' => '.ods', - 'application/vnd.oasis.opendocument.text' => '.odt', - 'application/vnd.openxmlformats-officedocument.presentationml.presentation' => '.pptx', - 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => '.xlsx', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => '.docx', - 'application/vnd.visio' => '.vsd', - 'application/x-7z-compressed' => '.7z', - 'application/x-abiword' => '.abw', - 'application/x-bzip' => '.bz', - 'application/x-bzip2' => '.bz2', - 'application/x-csh' => '.csh', - 'application/x-rar-compressed' => '.rar', - 'application/x-sh' => '.sh', - 'application/x-shockwave-flash' => '.swf', - 'application/x-tar' => '.tar', - 'application/xhtml+xml' => '.xhtml', - 'application/xml' => '.xml', - 'application/zip' => '.zip', - 'audio/aac' => '.aac', - 'audio/midi' => '.midi', - 'audio/mpeg' => '.mp3', - 'audio/ogg' => '.oga', - 'audio/wav' => '.wav', - 'audio/webm' => '.weba', - 'font/otf' => '.otf', - 'font/ttf' => '.ttf', - 'font/woff' => '.woff', - 'font/woff2' => '.woff2', - 'image/bmp' => '.bmp', - 'image/gif' => '.gif', - 'image/jpeg' => '.jpg', - 'image/png' => '.png', - 'image/svg+xml' => '.svg', - 'image/tiff' => '.tiff', - 'image/webp' => '.webp', - 'image/x-icon' => '.ico', - 'text/calendar' => '.ics', - 'text/css' => '.css', - 'text/csv' => '.csv', - 'text/html' => '.html', - 'text/plain' => '.txt', - 'video/mp4' => '.mp4', - 'video/mpeg' => '.mpeg', - 'video/ogg' => '.ogv', - 'video/webm' => '.webm', - 'video/x-msvideo' => '.avi', - ); - - if(isset($extensions[$mimeType])) - { - return $extensions[$mimeType]; - } - return null; - } + /** + * Return an extension for a specific mime-type. + * + * @param $mimeType + * @return string|null + */ + function getFileExtension($mimeType) + { - /** - * Return information about a file, including mime-type - * @deprecated - use getFileInfo() instead. - * @param string $path_to_file - * @param bool $imgcheck - * @param bool $auto_fix_ext - * @return array|bool - */ - public function get_file_info($path_to_file, $imgcheck = true, $auto_fix_ext = true) + $extensions = array( + 'application/ecmascript' => '.es', + 'application/epub+zip' => '.epub', + 'application/java-archive' => '.jar', + 'application/javascript' => '.js', + 'application/json' => '.json', + 'application/msword' => '.doc', + 'application/octet-stream' => '.bin', + 'application/ogg' => '.ogx', + 'application/pdf' => '.pdf', + 'application/rtf' => '.rtf', + 'application/typescript' => '.ts', + 'application/vnd.amazon.ebook' => '.azw', + 'application/vnd.apple.installer+xml' => '.mpkg', + 'application/vnd.mozilla.xul+xml' => '.xul', + 'application/vnd.ms-excel' => '.xls', + 'application/vnd.ms-fontobject' => '.eot', + 'application/vnd.ms-powerpoint' => '.ppt', + 'application/vnd.oasis.opendocument.presentation' => '.odp', + 'application/vnd.oasis.opendocument.spreadsheet' => '.ods', + 'application/vnd.oasis.opendocument.text' => '.odt', + 'application/vnd.openxmlformats-officedocument.presentationml.presentation' => '.pptx', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => '.xlsx', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => '.docx', + 'application/vnd.visio' => '.vsd', + 'application/x-7z-compressed' => '.7z', + 'application/x-abiword' => '.abw', + 'application/x-bzip' => '.bz', + 'application/x-bzip2' => '.bz2', + 'application/x-csh' => '.csh', + 'application/x-rar-compressed' => '.rar', + 'application/x-sh' => '.sh', + 'application/x-shockwave-flash' => '.swf', + 'application/x-tar' => '.tar', + 'application/xhtml+xml' => '.xhtml', + 'application/xml' => '.xml', + 'application/zip' => '.zip', + 'audio/aac' => '.aac', + 'audio/midi' => '.midi', + 'audio/mpeg' => '.mp3', + 'audio/ogg' => '.oga', + 'audio/wav' => '.wav', + 'audio/webm' => '.weba', + 'font/otf' => '.otf', + 'font/ttf' => '.ttf', + 'font/woff' => '.woff', + 'font/woff2' => '.woff2', + 'image/bmp' => '.bmp', + 'image/gif' => '.gif', + 'image/jpeg' => '.jpg', + 'image/png' => '.png', + 'image/svg+xml' => '.svg', + 'image/tiff' => '.tiff', + 'image/webp' => '.webp', + 'image/x-icon' => '.ico', + 'text/calendar' => '.ics', + 'text/css' => '.css', + 'text/csv' => '.csv', + 'text/html' => '.html', + 'text/plain' => '.txt', + 'video/mp4' => '.mp4', + 'video/mpeg' => '.mpeg', + 'video/ogg' => '.ogv', + 'video/webm' => '.webm', + 'video/x-msvideo' => '.avi', + ); + + if(isset($extensions[$mimeType])) { - return $this->getFileInfo($path_to_file, $imgcheck, $auto_fix_ext); + return $extensions[$mimeType]; } - /** - * Collect file information - * - * @param string $path_to_file - * @param boolean $imgcheck - * @param boolean $auto_fix_ext - * @return array|bool - */ - public function getFileInfo($path_to_file, $imgcheck = true, $auto_fix_ext = true) - { + return null; + } - $finfo = array(); + /** + * Return information about a file, including mime-type + * + * @param string $path_to_file + * @param bool $imgcheck + * @param bool $auto_fix_ext + * @return array|bool + * @deprecated - use getFileInfo() instead. + */ + public function get_file_info($path_to_file, $imgcheck = true, $auto_fix_ext = true) + { - if(!file_exists($path_to_file) || filesize($path_to_file) < 2) // Don't try and read 0 byte files. - { - return false; - } + return $this->getFileInfo($path_to_file, $imgcheck, $auto_fix_ext); + } - $finfo['pathinfo'] = pathinfo($path_to_file); - $finfo['mime'] = $this->getMime($path_to_file); + /** + * Collect file information + * + * @param string $path_to_file + * @param boolean $imgcheck + * @param boolean $auto_fix_ext + * @return array|bool + */ + public function getFileInfo($path_to_file, $imgcheck = true, $auto_fix_ext = true) + { - if($auto_fix_ext && $finfo['mime'] === false) - { + $finfo = array(); - if(class_exists('finfo')) // Best Mime detection method. - { - $fin = new finfo(FILEINFO_MIME); - list($mime, $other) = explode(";", $fin->file($path_to_file)); + if(!file_exists($path_to_file) || filesize($path_to_file) < 2) // Don't try and read 0 byte files. + { + return false; + } - if(!empty($mime)) - { - $finfo['mime'] = $mime; - } + $finfo['pathinfo'] = pathinfo($path_to_file); + $finfo['mime'] = $this->getMime($path_to_file); + + if($auto_fix_ext && $finfo['mime'] === false) + { - unset($other); + if(class_exists('finfo')) // Best Mime detection method. + { + $fin = new finfo(FILEINFO_MIME); + list($mime, $other) = explode(";", $fin->file($path_to_file)); + if(!empty($mime)) + { + $finfo['mime'] = $mime; } - // Auto-Fix Files without an extensions using known mime-type. - if(empty($finfo['pathinfo']['extension']) && !empty($finfo['mime']) && !is_dir($path_to_file)) + unset($other); + + } + + // Auto-Fix Files without an extensions using known mime-type. + if(empty($finfo['pathinfo']['extension']) && !empty($finfo['mime']) && !is_dir($path_to_file)) + { + if($ext = $this->getFileExtension($finfo['mime'])) { - if($ext = $this->getFileExtension($finfo['mime'])) - { - $finfo['pathinfo']['extension'] = $ext; + $finfo['pathinfo']['extension'] = $ext; - $newFile = $path_to_file . $ext; - if(!file_exists($newFile)) + $newFile = $path_to_file . $ext; + if(!file_exists($newFile)) + { + if(rename($path_to_file, $newFile) === true) { - if(rename($path_to_file, $newFile) === true) - { - $finfo['pathinfo'] = pathinfo($newFile); - $path_to_file = $newFile; - } + $finfo['pathinfo'] = pathinfo($newFile); + $path_to_file = $newFile; } } } } + } - if($imgcheck && ($tmp = getimagesize($path_to_file))) - { - $finfo['img-width'] = $tmp[0]; - $finfo['img-height'] = $tmp[1]; - - if(empty($finfo['mime'])) - { - $finfo['mime'] = $tmp['mime']; - } - - } + if($imgcheck && ($tmp = getimagesize($path_to_file))) + { + $finfo['img-width'] = $tmp[0]; + $finfo['img-height'] = $tmp[1]; - if($tmp = stat($path_to_file)) + if(empty($finfo['mime'])) { - - $finfo['fsize'] = $tmp['size']; - $finfo['modified'] = $tmp['mtime']; + $finfo['mime'] = $tmp['mime']; } - $finfo['fullpath'] = $path_to_file; - $finfo['fname'] = basename($path_to_file); - $finfo['path'] = dirname($path_to_file) . '/'; - - return $finfo; } - - /** - * Grab a remote file and save it in the /temp directory. requires CURL - * - * @param string $remote_url - * @param string $local_file string filename to save as - * @param string $type media, temp, or import - * @return boolean TRUE on success, FALSE on failure (which includes absence of CURL functions) - */ - function getRemoteFile($remote_url, $local_file, $type = 'temp', $timeout = 40) + if($tmp = stat($path_to_file)) { - // check for cURL - if(!function_exists('curl_init')) - { - $msg = 'e_file::getRemoteFile() requires cURL to be installed.'; - if(E107_DEBUG_LEVEL > 0) - { - e107::getLog()->addDebug($msg); - } - - error_log($msg); - return false; // May not be installed - } - - $path = ($type === 'media') ? e_MEDIA : e_TEMP; + $finfo['fsize'] = $tmp['size']; + $finfo['modified'] = $tmp['mtime']; + } - if($type === 'import') - { - $path = e_IMPORT; - } + $finfo['fullpath'] = $path_to_file; + $finfo['fname'] = basename($path_to_file); + $finfo['path'] = dirname($path_to_file) . '/'; - $fp = fopen($path . $local_file, 'w'); // media-directory or temp directory is the root. + return $finfo; + } - $cp = $this->initCurl($remote_url); - curl_setopt($cp, CURLOPT_FILE, $fp); - curl_setopt($cp, CURLOPT_TIMEOUT, $timeout); - set_time_limit($timeout); - $buffer = curl_exec($cp); + /** + * Grab a remote file and save it in the /temp directory. requires CURL + * + * @param string $remote_url + * @param string $local_file string filename to save as + * @param string $type media, temp, or import + * @return boolean TRUE on success, FALSE on failure (which includes absence of CURL functions) + */ + function getRemoteFile($remote_url, $local_file, $type = 'temp', $timeout = 40) + { - if(curl_errno($cp)) // Fixes curl_error output - here see #1936 + // check for cURL + if(!function_exists('curl_init')) + { + $msg = 'e_file::getRemoteFile() requires cURL to be installed.'; + if(E107_DEBUG_LEVEL > 0) { - error_log('cURL error: '.curl_error($cp)); + e107::getLog()->addDebug($msg); } - curl_close($cp); - fclose($fp); + error_log($msg); - return (bool) $buffer; + return false; // May not be installed } - /** - * @param string $address - * @param array|null $options - * - * @return CurlHandle|false - */ - public function initCurl($address, $options = null) + $path = ($type === 'media') ? e_MEDIA : e_TEMP; + + if($type === 'import') { + $path = e_IMPORT; + } - $cu = curl_init(); + $fp = fopen($path . $local_file, 'w'); // media-directory or temp directory is the root. - $timeout = (integer) vartrue($options['timeout'], 10); - $timeout = min($timeout, 120); - $timeout = max($timeout, 3); + $cp = $this->initCurl($remote_url); + curl_setopt($cp, CURLOPT_FILE, $fp); + curl_setopt($cp, CURLOPT_TIMEOUT, $timeout); + set_time_limit($timeout); - $urlData = parse_url($address); - $referer = $urlData['scheme'] . "://" . $urlData['host']; + $buffer = curl_exec($cp); - if(empty($referer)) - { - $referer = e_REQUEST_HTTP; - } + if(curl_errno($cp)) // Fixes curl_error output - here see #1936 + { + error_log('cURL error: ' . curl_error($cp)); + } - curl_setopt($cu, CURLOPT_URL, $address); - curl_setopt($cu, CURLOPT_TIMEOUT, $timeout); - curl_setopt($cu, CURLOPT_RETURNTRANSFER, true); - curl_setopt($cu, CURLOPT_HEADER, 0); - curl_setopt($cu, CURLOPT_REFERER, $referer); - curl_setopt($cu, CURLOPT_SSL_VERIFYPEER, false); - curl_setopt($cu, CURLOPT_FOLLOWLOCATION, true); - curl_setopt($cu, CURLOPT_USERAGENT, "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/81.0"); - curl_setopt($cu, CURLOPT_COOKIEFILE, e_SYSTEM . 'cookies.txt'); - curl_setopt($cu, CURLOPT_COOKIEJAR, e_SYSTEM . 'cookies.txt'); - - if(defined('e_CURL_PROXY')) - { - curl_setopt($cu, CURLOPT_PROXY, e_CURL_PROXY); // PROXY details with port - } + curl_close($cp); + fclose($fp); - if(defined('e_CURL_PROXYUSERPWD')) - { - curl_setopt($cu, CURLOPT_PROXYUSERPWD, e_CURL_PROXYUSERPWD); // Use if proxy have username and password - } + return (bool) $buffer; + } - if(defined('e_CURL_PROXYTYPE')) - { - curl_setopt($cu, CURLOPT_PROXYTYPE, e_CURL_PROXYTYPE); // If expected to cal - } + /** + * @param string $address + * @param array|null $options + * + * @return CurlHandle|false + */ + public function initCurl($address, $options = null) + { - if(!empty($options['post'])) - { - curl_setopt($cu, CURLOPT_POST, true); - // if array -> will encode the data as multipart/form-data, if URL-encoded string - application/x-www-form-urlencoded - curl_setopt($cu, CURLOPT_POSTFIELDS, $options['post']); - } + $cu = curl_init(); - if(!empty($options['postfields'])) - { - curl_setopt($cu, CURLOPT_POSTFIELDS, $options['postfields']); - } + $timeout = (integer) vartrue($options['timeout'], 10); + $timeout = min($timeout, 120); + $timeout = max($timeout, 3); - if(!empty($options['customrequest'])) // ie. GET, PUT, POST - { - curl_setopt($cu, CURLOPT_CUSTOMREQUEST, $options['customrequest']); - } + $urlData = parse_url($address); + $referer = $urlData['scheme'] . "://" . $urlData['host']; - if(isset($options['header']) && is_array($options['header'])) - { - curl_setopt($cu, CURLOPT_HTTPHEADER, $options['header']); - } + if(empty($referer)) + { + $referer = e_REQUEST_HTTP; + } - if(!file_exists(e_SYSTEM . 'cookies.txt')) - { - file_put_contents(e_SYSTEM . 'cookies.txt', ''); - } + curl_setopt($cu, CURLOPT_URL, $address); + curl_setopt($cu, CURLOPT_TIMEOUT, $timeout); + curl_setopt($cu, CURLOPT_RETURNTRANSFER, true); + curl_setopt($cu, CURLOPT_HEADER, 0); + curl_setopt($cu, CURLOPT_REFERER, $referer); + curl_setopt($cu, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($cu, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($cu, CURLOPT_USERAGENT, "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/81.0"); + curl_setopt($cu, CURLOPT_COOKIEFILE, e_SYSTEM . 'cookies.txt'); + curl_setopt($cu, CURLOPT_COOKIEJAR, e_SYSTEM . 'cookies.txt'); + + if(defined('e_CURL_PROXY')) + { + curl_setopt($cu, CURLOPT_PROXY, e_CURL_PROXY); // PROXY details with port + } - return $cu; + if(defined('e_CURL_PROXYUSERPWD')) + { + curl_setopt($cu, CURLOPT_PROXYUSERPWD, e_CURL_PROXYUSERPWD); // Use if proxy have username and password + } + if(defined('e_CURL_PROXYTYPE')) + { + curl_setopt($cu, CURLOPT_PROXYTYPE, e_CURL_PROXYTYPE); // If expected to cal } + if(!empty($options['post'])) + { + curl_setopt($cu, CURLOPT_POST, true); + // if array -> will encode the data as multipart/form-data, if URL-encoded string - application/x-www-form-urlencoded + curl_setopt($cu, CURLOPT_POSTFIELDS, $options['post']); + } - /** - * FIXME add POST support - * Get Remote contents - * $options array: - * - 'timeout' (integer): timeout in seconds - * - 'post' (array|urlencoded string): POST data - * - 'header' (array) headers, example: array('Content-Type: text/xml', 'X-Custom-Header: SomeValue'); - * - * @param string $address - * @param array $options [optional] - * @return string - */ - public function getRemoteContent($address, $options = array()) + if(!empty($options['postfields'])) { + curl_setopt($cu, CURLOPT_POSTFIELDS, $options['postfields']); + } - // Could do something like: if ($timeout <= 0) $timeout = $pref['get_remote_timeout']; here + if(!empty($options['customrequest'])) // ie. GET, PUT, POST + { + curl_setopt($cu, CURLOPT_CUSTOMREQUEST, $options['customrequest']); + } - // $fileContents = ''; - $this->error = ''; - $this->setErrorNum(null); + if(isset($options['header']) && is_array($options['header'])) + { + curl_setopt($cu, CURLOPT_HTTPHEADER, $options['header']); + } - // $mes = e107::getMessage(); + if(!file_exists(e_SYSTEM . 'cookies.txt')) + { + file_put_contents(e_SYSTEM . 'cookies.txt', ''); + } - // May be paranoia, but streaky thought it might be a good idea + return $cu; - $address = str_replace(array("\r", "\n", "\t", '&'), array('', '', '', '&'), $address); + } - // ... and there shouldn't be unprintable characters in the URL anyway - $requireCurl = false; - if(!empty($options['decode'])) - { - $address = urldecode($address); - } + /** + * FIXME add POST support + * Get Remote contents + * $options array: + * - 'timeout' (integer): timeout in seconds + * - 'post' (array|urlencoded string): POST data + * - 'header' (array) headers, example: array('Content-Type: text/xml', 'X-Custom-Header: SomeValue'); + * + * @param string $address + * @param array $options [optional] + * @return string + */ + public function getRemoteContent($address, $options = array()) + { - // Keep this in first position. - if(function_exists("curl_init")) // Preferred. - { + // Could do something like: if ($timeout <= 0) $timeout = $pref['get_remote_timeout']; here - $cu = $this->initCurl($address, $options); + // $fileContents = ''; + $this->error = ''; + $this->setErrorNum(null); - $fileContents = curl_exec($cu); - if(curl_error($cu)) - { - $errorCode = curl_errno($cu); - $this->setErrorNum($errorCode); - $this->error = "Curl error: " . $errorCode . ", " . curl_error($cu); + // $mes = e107::getMessage(); - return false; - } - curl_close($cu); + // May be paranoia, but streaky thought it might be a good idea - return $fileContents; - } + $address = str_replace(array("\r", "\n", "\t", '&'), array('', '', '', '&'), $address); - // CURL is required, abort... - if($requireCurl == true) - { - return false; - } - - $timeout = 5; + // ... and there shouldn't be unprintable characters in the URL anyway + $requireCurl = false; - if(function_exists('file_get_contents') && ini_get('allow_url_fopen')) - { - $old_timeout = ini_set('default_socket_timeout', $timeout); + if(!empty($options['decode'])) + { + $address = urldecode($address); + } - $context = array( - 'ssl' => array( - 'verify_peer' => false, - 'verify_peer_name' => false, - ), - ); + // Keep this in first position. + if(function_exists("curl_init")) // Preferred. + { - $data = file_get_contents($address, false, stream_context_create($context)); + $cu = $this->initCurl($address, $options); - // $data = file_get_contents(htmlspecialchars($address)); // buggy - sometimes fails. - if($old_timeout !== false) - { - @ini_set('default_socket_timeout', $old_timeout); - } - if($data !== false) - { - // $fileContents = $data; - return $data; - } - $this->error = "File_get_contents(XML) error"; // Fill in more info later + $fileContents = curl_exec($cu); + if(curl_error($cu)) + { + $errorCode = curl_errno($cu); + $this->setErrorNum($errorCode); + $this->error = "Curl error: " . $errorCode . ", " . curl_error($cu); return false; } + curl_close($cu); - if(ini_get("allow_url_fopen")) - { - $old_timeout = ini_set('default_socket_timeout', $timeout); - $remote = @fopen($address, "r"); - if(!$remote) - { - $this->error = "fopen: Unable to open remote XML file: " . $address; + return $fileContents; + } - return false; - } - } - else - { - $old_timeout = $timeout; - $tmp = parse_url($address); - if(!$remote = fsockopen($tmp['host'], 80, $errno, $errstr, $timeout)) - { - $this->error = "Sockets: Unable to open remote XML file: " . $address; + // CURL is required, abort... + if($requireCurl == true) + { + return false; + } - return false; - } - else - { - stream_set_timeout($remote, $timeout); - fwrite($remote, "GET " . urlencode($address) . " HTTP/1.0\r\n\r\n"); - } - } - $fileContents = ""; - while(!feof($remote)) + $timeout = 5; + + if(function_exists('file_get_contents') && ini_get('allow_url_fopen')) + { + $old_timeout = ini_set('default_socket_timeout', $timeout); + + $context = array( + 'ssl' => array( + 'verify_peer' => false, + 'verify_peer_name' => false, + ), + ); + + $data = file_get_contents($address, false, stream_context_create($context)); + + // $data = file_get_contents(htmlspecialchars($address)); // buggy - sometimes fails. + if($old_timeout !== false) { - $fileContents .= fgets($remote, 4096); + @ini_set('default_socket_timeout', $old_timeout); } - fclose($remote); - if($old_timeout != $timeout) + if($data !== false) { - if($old_timeout !== false) - { - ini_set('default_socket_timeout', $old_timeout); - } + // $fileContents = $data; + return $data; } + $this->error = "File_get_contents(XML) error"; // Fill in more info later - return $fileContents; + return false; } - - /** - * Get a list of directories matching $fmask, omitting any in the $omit array - same calling syntax as get_files() - * N.B. - no recursion - just looks in the specified directory. - * - * @param string $path - * @param string $fmask - * @param string $omit - * @return array - */ - function get_dirs($path, $fmask = '', $omit = 'standard') + if(ini_get("allow_url_fopen")) { - - $ret = array(); - $path = rtrim($path,'/'); - if($path[strlen($path) - 1] === '/') - // if(substr($path, -1) == '/') + $old_timeout = ini_set('default_socket_timeout', $timeout); + $remote = @fopen($address, "r"); + if(!$remote) { - $path = substr($path, 0, -1); - } + $this->error = "fopen: Unable to open remote XML file: " . $address; - if(!$handle = opendir($path)) - { - return $ret; + return false; } - - if($omit == 'standard') + } + else + { + $old_timeout = $timeout; + $tmp = parse_url($address); + if(!$remote = fsockopen($tmp['host'], 80, $errno, $errstr, $timeout)) { - $omit = array(); + $this->error = "Sockets: Unable to open remote XML file: " . $address; + + return false; } else { - if(!is_array($omit)) - { - $omit = array($omit); - } + stream_set_timeout($remote, $timeout); + fwrite($remote, "GET " . urlencode($address) . " HTTP/1.0\r\n\r\n"); } - - while(false !== ($file = readdir($handle))) + } + $fileContents = ""; + while(!feof($remote)) + { + $fileContents .= fgets($remote, 4096); + } + fclose($remote); + if($old_timeout != $timeout) + { + if($old_timeout !== false) { - if(($file != '.') && ($file != '..') && !in_array($file, $this->dirFilter) && !in_array($file, $omit) && is_dir($path . '/' . $file) && ($fmask == '' || preg_match("#" . $fmask . "#", $file))) - { - $ret[] = $file; - } + ini_set('default_socket_timeout', $old_timeout); } + } + + return $fileContents; + } + + /** + * Get a list of directories matching $fmask, omitting any in the $omit array - same calling syntax as get_files() + * N.B. - no recursion - just looks in the specified directory. + * + * @param string $path + * @param string $fmask + * @param string $omit + * @return array + */ + function get_dirs($path, $fmask = '', $omit = 'standard') + { + + $ret = array(); + $path = rtrim($path, '/'); + if($path[strlen($path) - 1] === '/') + // if(substr($path, -1) == '/') + { + $path = substr($path, 0, -1); + } + + if(!$handle = opendir($path)) + { return $ret; } - /** - * Delete a complete directory tree - * - * @param string $dir - * @return boolean success - */ - function rmtree($dir) + if($omit == 'standard') + { + $omit = array(); + } + else { + if(!is_array($omit)) + { + $omit = array($omit); + } + } - if(substr($dir, -1) != '/') + while(false !== ($file = readdir($handle))) + { + if(($file != '.') && ($file != '..') && !in_array($file, $this->dirFilter) && !in_array($file, $omit) && is_dir($path . '/' . $file) && ($fmask == '' || preg_match("#" . $fmask . "#", $file))) { - $dir .= '/'; + $ret[] = $file; } - if($handle = opendir($dir)) + } + + return $ret; + } + + /** + * Delete a complete directory tree + * + * @param string $dir + * @return boolean success + */ + function rmtree($dir) + { + + if(substr($dir, -1) != '/') + { + $dir .= '/'; + } + if($handle = opendir($dir)) + { + while($obj = readdir($handle)) { - while($obj = readdir($handle)) + if($obj != '.' && $obj != '..') { - if($obj != '.' && $obj != '..') + if(is_dir($dir . $obj)) { - if(is_dir($dir . $obj)) + if(!$this->rmtree($dir . $obj)) { - if(!$this->rmtree($dir . $obj)) - { - return false; - } + return false; } - elseif(is_file($dir . $obj)) + } + elseif(is_file($dir . $obj)) + { + if(!unlink($dir . $obj)) { - if(!unlink($dir . $obj)) - { - return false; - } + return false; } } } + } - closedir($handle); - - if(!@rmdir($dir)) - { - return false; - } + closedir($handle); - return true; + if(!@rmdir($dir)) + { + return false; } - return false; + return true; } - /** - * Parse a file size string (e.g. 16M) and compute the simple numeric value. - * - * @param string $source - input string which may include 'multiplier' characters such as 'M' or 'G'. Converted to 'decoded value' - * @param int $compare - a 'compare' value - * @param string $action - values (gt|lt) - * - * @return int file size value in bytes. - * If the decoded value evaluates to zero, returns the value of $compare - * If $action == 'gt', return the larger of the decoded value and $compare - * If $action == 'lt', return the smaller of the decoded value and $compare - */ - function file_size_decode($source, $compare = 0, $action = '') - { + return false; + } - $source = trim($source); - $source = strtoupper($source); + /** + * Parse a file size string (e.g. 16M) and compute the simple numeric value. + * + * @param string $source - input string which may include 'multiplier' characters such as 'M' or 'G'. Converted to 'decoded value' + * @param int $compare - a 'compare' value + * @param string $action - values (gt|lt) + * + * @return int file size value in bytes. + * If the decoded value evaluates to zero, returns the value of $compare + * If $action == 'gt', return the larger of the decoded value and $compare + * If $action == 'lt', return the smaller of the decoded value and $compare + */ + function file_size_decode($source, $compare = 0, $action = '') + { - list($val, $unit) = array_pad(preg_split('#(?<=\d)(?=[a-z])#i', $source), 2, ''); + $source = trim($source); + $source = strtoupper($source); - $val = (int) $val; + list($val, $unit) = array_pad(preg_split('#(?<=\d)(?=[a-z])#i', $source), 2, ''); - if(!$source || is_numeric($source)) - { - $val = (int) $source; - } - else - { - switch($unit) - { - case 'T': - case 'TB': - $val = $val * 1024 * 1024 * 1024 * 1024; - break; - case 'G': - case 'GB': - $val = $val * 1024 * 1024 * 1024; - break; - case 'M': - case 'MB': - $val = $val * 1024 * 1024; - break; - case 'K': - case 'KB': - $val = $val * 1024; - break; - } - } - if($val == 0) - { - return $compare; - } + $val = (int) $val; - switch($action) + if(!$source || is_numeric($source)) + { + $val = (int) $source; + } + else + { + switch($unit) { - case 'lt': - return min($val, $compare); - case 'gt': - return max($val, $compare); - default: - return $val; + case 'T': + case 'TB': + $val = $val * 1024 * 1024 * 1024 * 1024; + break; + case 'G': + case 'GB': + $val = $val * 1024 * 1024 * 1024; + break; + case 'M': + case 'MB': + $val = $val * 1024 * 1024; + break; + case 'K': + case 'KB': + $val = $val * 1024; + break; } - // return 0; } - - /** - * Parse bytes to human readable format - * Former Download page function - * - * @param mixed $size file size in bytes or file path if $retrieve is true - * @param boolean $retrieve defines the type of $size - * @param integer $decimal - * @return string formatted size - */ - function file_size_encode($size, $retrieve = false, $decimal = 2) + if($val == 0) { + return $compare; + } - if($retrieve) - { - $size = filesize($size); - } - $kb = 1024; - $mb = 1024 * $kb; - $gb = 1024 * $mb; - $tb = 1024 * $gb; - if(!$size) - { - return '0 ' . CORE_LAN_B; - } - if($size < $kb) - { - return $size . " " . CORE_LAN_B; - } - elseif($size < $mb) - { - return round($size / $kb, $decimal) . " " . CORE_LAN_KB; - } - elseif($size < $gb) - { - return round($size / $mb, $decimal) . " " . CORE_LAN_MB; - } - elseif($size < $tb) - { - return round($size / $gb, $decimal) . " " . CORE_LAN_GB; - } - else - { - return round($size / $tb, 2) . " " . CORE_LAN_TB; - } + switch($action) + { + case 'lt': + return min($val, $compare); + case 'gt': + return max($val, $compare); + default: + return $val; } + // return 0; + } + /** + * Parse bytes to human readable format + * Former Download page function + * + * @param mixed $size file size in bytes or file path if $retrieve is true + * @param boolean $retrieve defines the type of $size + * @param integer $decimal + * @return string formatted size + */ + function file_size_encode($size, $retrieve = false, $decimal = 2) + { - /** Recursive Chmod function. - * - * @param string $path to folder - * @param integer $filemode perms for files - * @param integer $dirmode perms for directories - * @example chmod_R('mydir', 0644, 0755); - */ - function chmod($path, $filemode = 0644, $dirmode = 0755) + if($retrieve) { + $size = filesize($size); + } + $kb = 1024; + $mb = 1024 * $kb; + $gb = 1024 * $mb; + $tb = 1024 * $gb; + if(!$size) + { + return '0 ' . CORE_LAN_B; + } + if($size < $kb) + { + return $size . " " . CORE_LAN_B; + } + elseif($size < $mb) + { + return round($size / $kb, $decimal) . " " . CORE_LAN_KB; + } + elseif($size < $gb) + { + return round($size / $mb, $decimal) . " " . CORE_LAN_MB; + } + elseif($size < $tb) + { + return round($size / $gb, $decimal) . " " . CORE_LAN_GB; + } + else + { + return round($size / $tb, 2) . " " . CORE_LAN_TB; + } + } - if(is_dir($path)) + + /** Recursive Chmod function. + * + * @param string $path to folder + * @param integer $filemode perms for files + * @param integer $dirmode perms for directories + * @example chmod_R('mydir', 0644, 0755); + */ + function chmod($path, $filemode = 0644, $dirmode = 0755) + { + + if(is_dir($path)) + { + if(!chmod($path, $dirmode)) { - if(!chmod($path, $dirmode)) - { - $dirmode_str = decoct($dirmode); - print "Failed applying filemode '$dirmode_str' on directory '$path'\n"; - print " `-> the directory '$path' will be skipped from recursive chmod\n"; + $dirmode_str = decoct($dirmode); + print "Failed applying filemode '$dirmode_str' on directory '$path'\n"; + print " `-> the directory '$path' will be skipped from recursive chmod\n"; - return; - } - $dh = opendir($path); - while(($file = readdir($dh)) !== false) + return; + } + $dh = opendir($path); + while(($file = readdir($dh)) !== false) + { + if($file != '.' && $file != '..') // skip self and parent pointing directories { - if($file != '.' && $file != '..') // skip self and parent pointing directories - { - $fullpath = $path . '/' . $file; - $this->chmod($fullpath, $filemode, $dirmode); - } + $fullpath = $path . '/' . $file; + $this->chmod($fullpath, $filemode, $dirmode); } - closedir($dh); } - else + closedir($dh); + } + else + { + if(is_link($path)) { - if(is_link($path)) - { - print "link '$path' is skipped\n"; + print "link '$path' is skipped\n"; - return; - } + return; + } - if(!chmod($path, $filemode)) - { - $filemode_str = decoct($filemode); - print "Failed applying filemode '$filemode_str' on file '$path'\n"; + if(!chmod($path, $filemode)) + { + $filemode_str = decoct($filemode); + print "Failed applying filemode '$filemode_str' on file '$path'\n"; - return; - } + return; } } + } - /** - * Copy a file, or copy the contents of a folder. - * - * @param string $source Source path - * @param string $dest Destination path - * @param array $options - * @return bool Returns true on success, false on error - */ - function copy($source, $dest, $options = array()) - { + /** + * Copy a file, or copy the contents of a folder. + * + * @param string $source Source path + * @param string $dest Destination path + * @param array $options + * @return bool Returns true on success, false on error + */ + function copy($source, $dest, $options = array()) + { - $perm = !empty($options['perm']) ? $options['perm'] : 0755; - $filter = !empty($options['git']) ? "" : ".git"; // filter out .git by default. + $perm = !empty($options['perm']) ? $options['perm'] : 0755; + $filter = !empty($options['git']) ? "" : ".git"; // filter out .git by default. - // Simple copy for a file - if(is_file($source)) - { - return copy($source, $dest); - } + // Simple copy for a file + if(is_file($source)) + { + return copy($source, $dest); + } - // Make destination directory - if(!is_dir($dest)) - { - mkdir($dest, $perm); - } + // Make destination directory + if(!is_dir($dest)) + { + mkdir($dest, $perm); + } - // Directory - so copy it. - $dir = scandir($source); - foreach($dir as $folder) + // Directory - so copy it. + $dir = scandir($source); + foreach($dir as $folder) + { + // Skip pointers + if($folder === '.' || $folder == '..' || $folder === $filter) { - // Skip pointers - if($folder === '.' || $folder == '..' || $folder === $filter) - { - continue; - } - - $this->copy("$source/$folder", "$dest/$folder", $perm); + continue; } - return true; + $this->copy("$source/$folder", "$dest/$folder", $perm); } + return true; + } - /** - * File retrieval function. by Cam. - * - * @param string $file actual path or {e_xxxx} path to file. - * @param string $opts (optional) type | disposition | encoding values. - * - */ - function send($file, $opts = array()) - { - global $e107; + /** + * File retrieval function. by Cam. + * + * @param string $file actual path or {e_xxxx} path to file. + * @param string $opts (optional) type | disposition | encoding values. + * + */ + function send($file, $opts = array()) + { - // $pref = e107::getPref(); - $tp = e107::getParser(); + global $e107; - $DOWNLOADS_DIR = e107::getFolder('DOWNLOADS'); - $DOWNLOADS_DIRECTORY = ($DOWNLOADS_DIR[0] == DIRECTORY_SEPARATOR) ? $DOWNLOADS_DIR : e_BASE . $DOWNLOADS_DIR; // support for full path eg. /home/account/folder. - $FILES_DIRECTORY = e_BASE . e107::getFolder('FILES'); - $MEDIA_DIRECTORY = realpath(e_MEDIA); // could be image, file or other type. - $SYSTEM_DIRECTORY = realpath(e_SYSTEM); // downloading of logs or hidden files etc. via browser if required. + // $pref = e107::getPref(); + $tp = e107::getParser(); - $file = $tp->replaceConstants($file); + $DOWNLOADS_DIR = e107::getFolder('DOWNLOADS'); + $DOWNLOADS_DIRECTORY = ($DOWNLOADS_DIR[0] == DIRECTORY_SEPARATOR) ? $DOWNLOADS_DIR : e_BASE . $DOWNLOADS_DIR; // support for full path eg. /home/account/folder. + $FILES_DIRECTORY = e_BASE . e107::getFolder('FILES'); + $MEDIA_DIRECTORY = realpath(e_MEDIA); // could be image, file or other type. + $SYSTEM_DIRECTORY = realpath(e_SYSTEM); // downloading of logs or hidden files etc. via browser if required. + $file = $tp->replaceConstants($file); - @set_time_limit(10 * 60); - @session_write_close(); - @ini_set("max_execution_time", 10 * 60); - while(ob_get_length() !== false) // destroy all ouput buffering - { - ob_end_clean(); - } - @ob_implicit_flush(); + + @set_time_limit(10 * 60); + @session_write_close(); + @ini_set("max_execution_time", 10 * 60); + while(ob_get_length() !== false) // destroy all ouput buffering + { + ob_end_clean(); + } + @ob_implicit_flush(); - $filename = $file; - $file = basename($file); - $path = realpath($filename); - $path_downloads = realpath($DOWNLOADS_DIRECTORY); - $path_public = realpath($FILES_DIRECTORY . "public/"); + $filename = $file; + $file = basename($file); + $path = realpath($filename); + $path_downloads = realpath($DOWNLOADS_DIRECTORY); + $path_public = realpath($FILES_DIRECTORY . "public/"); - if(strpos($path, $path_downloads) === false && strpos($path, $path_public) === false && strpos($path, $MEDIA_DIRECTORY) === false && strpos($path, $SYSTEM_DIRECTORY) === false) + if(strpos($path, $path_downloads) === false && strpos($path, $path_public) === false && strpos($path, $MEDIA_DIRECTORY) === false && strpos($path, $SYSTEM_DIRECTORY) === false) + { + if(E107_DEBUG_LEVEL > 0 && ADMIN) { - if(E107_DEBUG_LEVEL > 0 && ADMIN) - { - echo "Failed to Download " . $file . "
"; - echo "The file-path " . $path . " didn't match with either of + echo "Failed to Download " . $file . "
"; + echo "The file-path " . $path . " didn't match with either of
  • {$path_downloads}
  • {$path_public}

"; - echo "Downloads Path: " . $path_downloads . " (" . $DOWNLOADS_DIRECTORY . ")"; - exit(); - } - else - { - header("location: {$e107->base_path}"); - exit(); - } + echo "Downloads Path: " . $path_downloads . " (" . $DOWNLOADS_DIRECTORY . ")"; + exit(); } else { - if(is_file($filename) && is_readable($filename) && connection_status() == 0) + header("location: {$e107->base_path}"); + exit(); + } + } + else + { + if(is_file($filename) && is_readable($filename) && connection_status() == 0) + { + $seek = 0; + if(strpos($_SERVER['HTTP_USER_AGENT'], "MSIE") !== false) + { + $file = preg_replace('/\./', '%2e', $file, substr_count($file, '.') - 1); + } + if(isset($_SERVER['HTTP_RANGE'])) + { + $seek = intval(substr($_SERVER['HTTP_RANGE'], strlen('bytes='))); + } + $bufsize = 2048; + ignore_user_abort(true); + $data_len = filesize($filename); + if($seek > ($data_len - 1)) { $seek = 0; - if(strpos($_SERVER['HTTP_USER_AGENT'], "MSIE") !== false) - { - $file = preg_replace('/\./', '%2e', $file, substr_count($file, '.') - 1); - } - if(isset($_SERVER['HTTP_RANGE'])) - { - $seek = intval(substr($_SERVER['HTTP_RANGE'], strlen('bytes='))); - } - $bufsize = 2048; - ignore_user_abort(true); - $data_len = filesize($filename); - if($seek > ($data_len - 1)) - { - $seek = 0; - } - // if ($filename == null) { $filename = basename($this->data); } - $res = fopen($filename, 'rb'); - if($seek) - { - fseek($res, $seek); - } - $data_len -= $seek; + } + // if ($filename == null) { $filename = basename($this->data); } + $res = fopen($filename, 'rb'); + if($seek) + { + fseek($res, $seek); + } + $data_len -= $seek; - $contentType = vartrue($opts['type'], 'application/force-download'); - $contentDisp = vartrue($opts['disposition'], 'attachment'); + $contentType = vartrue($opts['type'], 'application/force-download'); + $contentDisp = vartrue($opts['disposition'], 'attachment'); - header('Expires: 0'); - header("Cache-Control: max-age=30"); - header('Content-Type: '.$contentType); - header('Content-Disposition: '.$contentDisp.'; filename="'.$file.'"'); - header("Content-Length: {$data_len}"); - header("Pragma: public"); + header('Expires: 0'); + header("Cache-Control: max-age=30"); + header('Content-Type: ' . $contentType); + header('Content-Disposition: ' . $contentDisp . '; filename="' . $file . '"'); + header("Content-Length: {$data_len}"); + header("Pragma: public"); - if(!empty($opts['encoding'])) - { - header('Content-Transfer-Encoding: '.$opts['encoding']); - } + if(!empty($opts['encoding'])) + { + header('Content-Transfer-Encoding: ' . $opts['encoding']); + } - if($seek) - { - header("Accept-Ranges: bytes"); - header("HTTP/1.0 206 Partial Content"); - header("status: 206 Partial Content"); - header("Content-Range: bytes {$seek}-" . ($data_len - 1) . "/{$data_len}"); - } - while(!connection_aborted() && $data_len > 0) - { - echo fread($res, $bufsize); - $data_len -= $bufsize; - } - fclose($res); + if($seek) + { + header("Accept-Ranges: bytes"); + header("HTTP/1.0 206 Partial Content"); + header("status: 206 Partial Content"); + header("Content-Range: bytes {$seek}-" . ($data_len - 1) . "/{$data_len}"); + } + while(!connection_aborted() && $data_len > 0) + { + echo fread($res, $bufsize); + $data_len -= $bufsize; + } + fclose($res); + } + else + { + if(E107_DEBUG_LEVEL > 0 && ADMIN) + { + $mes = __METHOD__ . " -- File failed: " . $file . "\n"; + $mes .= "Path: " . $path . "\n"; + $mes .= "Backtrace: "; + $mes .= print_r(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), true); + trigger_error($mes); + exit(); } else { - if(E107_DEBUG_LEVEL > 0 && ADMIN) - { - $mes = __METHOD__." -- File failed: " . $file . "\n"; - $mes .= "Path: " . $path . "\n"; - $mes .= "Backtrace: "; - $mes .= print_r(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), true); - trigger_error($mes); - exit(); - } - else - { - header("location: " . e_BASE . "index.php"); - exit(); - } + header("location: " . e_BASE . "index.php"); + exit(); } } } + } - /** - * Return a user specific file directory for the current plugin with the option to create one if it does not exist. - * - * @param int $user userid - * @param boolean $create - * @param null|string $subDir - * @return string - */ - public function getUserDir($user, $create = false, $subDir = null) - { + /** + * Return a user specific file directory for the current plugin with the option to create one if it does not exist. + * + * @param int $user userid + * @param boolean $create + * @param null|string $subDir + * @return string + */ + public function getUserDir($user, $create = false, $subDir = null) + { - $tp = e107::getParser(); + $tp = e107::getParser(); - $baseDir = e_MEDIA . 'plugins/' . e_CURRENT_PLUGIN . '/'; + $baseDir = e_MEDIA . 'plugins/' . e_CURRENT_PLUGIN . '/'; - if(!empty($subDir)) - { - $subDir = e107::getParser()->filter($subDir, 'w'); - $baseDir .= rtrim($subDir, '/') . '/'; - } + if(!empty($subDir)) + { + $subDir = e107::getParser()->filter($subDir, 'w'); + $baseDir .= rtrim($subDir, '/') . '/'; + } - if(is_numeric($user)) - { - $baseDir .= ($user > 0) ? "user_" . $tp->leadingZeros($user, 6) : "anon"; - } + if(is_numeric($user)) + { + $baseDir .= ($user > 0) ? "user_" . $tp->leadingZeros($user, 6) : "anon"; + } - if($create == true && !is_dir($baseDir)) - { - mkdir($baseDir, 0755, true); // recursively - } + if($create == true && !is_dir($baseDir)) + { + mkdir($baseDir, 0755, true); // recursively + } - $baseDir = rtrim($baseDir, '/') . "/"; + $baseDir = rtrim($baseDir, '/') . "/"; + + return $baseDir; + } - return $baseDir; - } + /** + * Runs through the zip archive array and finds the root directory. + * + * @param $unarc + * @return bool|string + */ + public function getRootFolder($unarc) + { - /** - * Runs through the zip archive array and finds the root directory. - * - * @param $unarc - * @return bool|string - */ - public function getRootFolder($unarc) + foreach($unarc as $d) { + $target = trim($d['stored_filename'], '/'); - foreach($unarc as $d) - { - $target = trim($d['stored_filename'], '/'); + $test = basename(str_replace(e_TEMP, "", $d['stored_filename']), '/'); - $test = basename(str_replace(e_TEMP, "", $d['stored_filename']), '/'); + if($d['folder'] == 1 && $target == $test) // + { + // $text .= "\\n test = ".$test; + $text = "getRootDirectory: " . $d['stored_filename']; + $text .= "
test=" . $test; + $text .= "
target=" . $target; - if($d['folder'] == 1 && $target == $test) // + if(E107_DEBUG_LEVEL > 0) { - // $text .= "\\n test = ".$test; - $text = "getRootDirectory: " . $d['stored_filename']; - $text .= "
test=" . $test; - $text .= "
target=" . $target; - - if(E107_DEBUG_LEVEL > 0) - { - e107::getMessage()->addDebug($text); - // echo ""; - } + e107::getMessage()->addDebug($text); + // echo ""; + } - return $target; + return $target; - } } + } - return false; + return false; - } + } - /** - * Zip up folders and files - * - * @param array $filePaths - * @param string $newFile - * @param array $options - * @return bool|string - */ - public function zip($filePaths = null, $newFile = '', $options = array()) + private function addToZip(ZipArchive $zip, $src, $localname) + { + + if(is_dir($src)) { + $dir = opendir($src); - if(empty($newFile)) + // add empty directories + $zip->addEmptyDir($localname); + + while(false !== ($file = readdir($dir))) { - $newFile = e_BACKUP . eHelper::title2sef(SITENAME) . "_" . date("Y-m-d-H-i-s") . ".zip"; + if(($file != '.') && ($file != '..')) + { + $this->addToZip($zip, $src . '/' . $file, $localname . '/' . $file); + } } - if($filePaths === null) + closedir($dir); + } + elseif(is_file($src)) + { + if(!$zip->addFile($src, $localname)) { - return "No file-paths set!"; + $this->error = "Could not add file: $src"; + e107::getLog()->addError($this->error)->save('FILE', E_LOG_NOTICE); } + } + } - require_once(e_HANDLER . 'pclzip.lib.php'); - $archive = new PclZip($newFile); - $removePath = (!empty($options['remove_path'])) ? $options['remove_path'] : e_BASE; + /** + * Zip up folders and files + * + * @param array $filePaths + * @param string $newFile + * @param array $options + * @return bool|string + */ + public function zip($filePaths = null, $newFile = '', $options = array()) + { + if(empty($newFile)) + { + $newFile = e_BACKUP . eHelper::title2sef(SITENAME) . "_" . date("Y-m-d-H-i-s") . ".zip"; + } - if($archive->create($filePaths, PCLZIP_OPT_REMOVE_PATH, $removePath) == 0) - { - $error = $archive->errorInfo(true); - e107::getLog()->addError($error)->save('FILE', E_LOG_NOTICE); + if($filePaths === null) + { + return "No file-paths set!"; + } - return false; - } - else - { - return $newFile; - } + $zip = new ZipArchive(); + + if($zip->open($newFile, ZipArchive::CREATE) !== true) + { + $this->error = "Cannot open <$newFile>\n"; + e107::getLog()->addError($this->error)->save('FILE', E_LOG_NOTICE); + + return false; } + $removePath = (!empty($options['remove_path'])) ? $options['remove_path'] : e_BASE; - /** - * Delete a file. - * - * @param $file - * @return bool - */ - public function delete($file) + foreach($filePaths as $file) { + $localname = str_replace($removePath, '', $file); + $this->addToZip($zip, $file, rtrim($localname, '/')); + } - if(empty($file)) - { - return false; - } + $zip->close(); - $file = e107::getParser()->replaceConstants($file); + return $newFile; + } - if(file_exists($file)) - { - return unlink($file); - } - return false; + /** + * Delete a file. + * + * @param $file + * @return bool + */ + public function delete($file) + { + if(empty($file)) + { + return false; } + $file = e107::getParser()->replaceConstants($file); - /** - * Recursive Directory removal . - * - * @param $dir - */ - public function removeDir($dir) + if(file_exists($file)) { + return unlink($file); + } + + return false; + + } + + + /** + * Recursive Directory removal . + * + * @param $dir + */ + public function removeDir($dir) + { - if(is_dir($dir)) + if(is_dir($dir)) + { + $objects = scandir($dir); + foreach($objects as $object) { - $objects = scandir($dir); - foreach($objects as $object) + if($object != "." && $object != "..") { - if($object != "." && $object != "..") + if(filetype($dir . "/" . $object) == "dir") { - if(filetype($dir . "/" . $object) == "dir") - { - $this->removeDir($dir . "/" . $object); - } - else - { - @unlink($dir . "/" . $object); - } + $this->removeDir($dir . "/" . $object); + } + else + { + @unlink($dir . "/" . $object); } } - - reset($objects); - @rmdir($dir); } + + reset($objects); + @rmdir($dir); } + } - /** - * File-class wrapper for upload handler. (Preferred for v2.x) - * Process files uploaded in a form post. ie. $_FILES. - * Routine processes the array of uploaded files according to both specific options set by the caller, - * and system options configured by the main admin. - * - * @param string $uploaddir Target directory (checked that it exists, but path not otherwise changed) - * - * @param string $fileinfo Determines any special handling of file name (combines previous $fileinfo and $avatar parameters): - * FALSE - default option; no processing - * = 'attachment+extra_text' Indicates an attachment (related to forum post or PM), and specifies some optional text which is - * incorporated into the final file name (the original $fileinfo parameter). - * = 'prefix+extra_text' - indicates an attachment or file, and specifies some optional text which is prefixed to the file name - * = 'unique' - * - if the proposed destination file doesn't exist, saved under given name - * - if the proposed destination file does exist, prepends time() to the file name to make it unique - * = 'avatar' - * - indicates an avatar is being uploaded (not used - options must be set elsewhere) - * - * @param array $options = [ An array of supplementary options, all of which will be given appropriate defaults if not defined: - * 'filetypes' => (string) Name of file containing list of valid file types - * - Always looks in the admin directory - * - defaults to e_ADMIN.filetypes.xml, else e_ADMIN.admin_filetypes.php for admins (if file exists), otherwise e_ADMIN.filetypes.php for users. - * - FALSE disables this option (which implies that 'extra_file_types' is used) - * 'file_mask' => (string) Comma-separated list of file types which if defined limits the allowed file types to those which are in both this list and the - * file specified by the 'filetypes' option. Enables restriction to, for example, image files. - * 'filetypes' => (bool) file). - * if TRUE, accepts totally unknown file extensions which are in $options['filetypes'] file. - * otherwise specifies a comma-separated list of additional permitted file extensions - * 'final_chmod' => (int) - chmod() to be applied to uploaded files (0644 default) (This routine expects an integer value, so watch formatting/decoding - its normally - * specified in octal. Typically use intval($permissions,8) to convert) - * 'max_upload_size' => (int) - maximum size of uploaded files in bytes, or as a string with a 'multiplier' letter (e.g. 16M) at the end. - * - otherwise uses $pref['upload_maxfilesize'] if set - * - overriding limit of the smaller of 'post_max_size' and 'upload_max_size' if set in php.ini - * (Note: other parts of E107 don't understand strings with a multiplier letter yet) - * 'file_array_name' => (string) - the name of the 'input' array - defaults to file_userfile[] - otherwise as set. - * 'max_file_count' => (int) - maximum number of files which can be uploaded - default is 'unlimited' if this is zero or not set. - * 'overwrite' => (bool) - if TRUE, existing file of the same name is overwritten; otherwise returns 'duplicate file' error (default FALSE) - * 'save_to_db' => (int) - [obsolete] storage type - if set and TRUE, uploaded files were saved in the database (rather than as flat files) - * ] - * @return boolean|array - * Returns FALSE if the upload directory doesn't exist, or various other errors occurred which restrict the amount of meaningful information. - * Returns an array, with one set of entries per uploaded file, regardless of whether saved or - * discarded (not all fields always present) - $c is array index: - * $uploaded[$c]['name'] - file name - as saved to disc - * $uploaded[$c]['rawname'] - original file name, prior to any addition of identifiers etc (useful for display purposes) - * $uploaded[$c]['type'] - mime type (if set - as sent by browser) - * $uploaded[$c]['size'] - size in bytes (should be zero if error) - * $uploaded[$c]['error'] - numeric error code (zero = OK) - * $uploaded[$c]['index'] - if upload successful, the index position from the file_userfile[] array - usually numeric, but may be alphanumeric if coded - * $uploaded[$c]['message'] - text of displayed message relating to file - * $uploaded[$c]['line'] - only if an error occurred, has line number (from __LINE__) - * $uploaded[$c]['file'] - only if an error occurred, has file name (from __FILE__) - * - * On exit, uploaded files should all have been removed from the temporary directory. - * No messages displayed - its caller's responsibility to handle errors and display info to - * user (or can use handle_upload_messages() from this module) - * - * Details of uploaded files are in $_FILES['file_userfile'] (or other array name as set) on entry. - * Elements passed (from PHP) relating to each file: - * ['name'] - the original name - * ['type'] - mime type (if provided - not checked by PHP) - * ['size'] - file size in bytes - * ['tmp_name'] - temporary file name on server - * ['error'] - error code. 0 = 'good'. 1..4 main others, although up to 8 defined for later PHP versions - * Files stored in server's temporary directory, unless another set - */ - public function getUploaded($uploaddir, $fileinfo = false, $options = array()) - { - - require_once(e_HANDLER . "upload_handler.php"); - - if($uploaddir == e_UPLOAD || $uploaddir == e_TEMP || $uploaddir == e_AVATAR_UPLOAD) - { - $path = $uploaddir; - } - elseif(defined('e_CURRENT_PLUGIN')) - { - $path = $this->getUserDir(USERID, true, str_replace("../", '', $uploaddir)); // .$this->get; - } - else - { - return false; - } + /** + * File-class wrapper for upload handler. (Preferred for v2.x) + * Process files uploaded in a form post. ie. $_FILES. + * Routine processes the array of uploaded files according to both specific options set by the caller, + * and system options configured by the main admin. + * + * @param string $uploaddir Target directory (checked that it exists, but path not otherwise changed) + * + * @param string $fileinfo Determines any special handling of file name (combines previous $fileinfo and $avatar parameters): + * FALSE - default option; no processing + * = 'attachment+extra_text' Indicates an attachment (related to forum post or PM), and specifies some optional text which is + * incorporated into the final file name (the original $fileinfo parameter). + * = 'prefix+extra_text' - indicates an attachment or file, and specifies some optional text which is prefixed to the file name + * = 'unique' + * - if the proposed destination file doesn't exist, saved under given name + * - if the proposed destination file does exist, prepends time() to the file name to make it unique + * = 'avatar' + * - indicates an avatar is being uploaded (not used - options must be set elsewhere) + * + * @param array $options = [ An array of supplementary options, all of which will be given appropriate defaults if not defined: + * 'filetypes' => (string) Name of file containing list of valid file types + * - Always looks in the admin directory + * - defaults to e_ADMIN.filetypes.xml, else e_ADMIN.admin_filetypes.php for admins (if file exists), otherwise e_ADMIN.filetypes.php for users. + * - FALSE disables this option (which implies that 'extra_file_types' is used) + * 'file_mask' => (string) Comma-separated list of file types which if defined limits the allowed file types to those which are in both this list and the + * file specified by the 'filetypes' option. Enables restriction to, for example, image files. + * 'filetypes' => (bool) file). + * if TRUE, accepts totally unknown file extensions which are in $options['filetypes'] file. + * otherwise specifies a comma-separated list of additional permitted file extensions + * 'final_chmod' => (int) - chmod() to be applied to uploaded files (0644 default) (This routine expects an integer value, so watch formatting/decoding - its normally + * specified in octal. Typically use intval($permissions,8) to convert) + * 'max_upload_size' => (int) - maximum size of uploaded files in bytes, or as a string with a 'multiplier' letter (e.g. 16M) at the end. + * - otherwise uses $pref['upload_maxfilesize'] if set + * - overriding limit of the smaller of 'post_max_size' and 'upload_max_size' if set in php.ini + * (Note: other parts of E107 don't understand strings with a multiplier letter yet) + * 'file_array_name' => (string) - the name of the 'input' array - defaults to file_userfile[] - otherwise as set. + * 'max_file_count' => (int) - maximum number of files which can be uploaded - default is 'unlimited' if this is zero or not set. + * 'overwrite' => (bool) - if TRUE, existing file of the same name is overwritten; otherwise returns 'duplicate file' error (default FALSE) + * 'save_to_db' => (int) - [obsolete] storage type - if set and TRUE, uploaded files were saved in the database (rather than as flat files) + * ] + * @return boolean|array + * Returns FALSE if the upload directory doesn't exist, or various other errors occurred which restrict the amount of meaningful information. + * Returns an array, with one set of entries per uploaded file, regardless of whether saved or + * discarded (not all fields always present) - $c is array index: + * $uploaded[$c]['name'] - file name - as saved to disc + * $uploaded[$c]['rawname'] - original file name, prior to any addition of identifiers etc (useful for display purposes) + * $uploaded[$c]['type'] - mime type (if set - as sent by browser) + * $uploaded[$c]['size'] - size in bytes (should be zero if error) + * $uploaded[$c]['error'] - numeric error code (zero = OK) + * $uploaded[$c]['index'] - if upload successful, the index position from the file_userfile[] array - usually numeric, but may be alphanumeric if coded + * $uploaded[$c]['message'] - text of displayed message relating to file + * $uploaded[$c]['line'] - only if an error occurred, has line number (from __LINE__) + * $uploaded[$c]['file'] - only if an error occurred, has file name (from __FILE__) + * + * On exit, uploaded files should all have been removed from the temporary directory. + * No messages displayed - its caller's responsibility to handle errors and display info to + * user (or can use handle_upload_messages() from this module) + * + * Details of uploaded files are in $_FILES['file_userfile'] (or other array name as set) on entry. + * Elements passed (from PHP) relating to each file: + * ['name'] - the original name + * ['type'] - mime type (if provided - not checked by PHP) + * ['size'] - file size in bytes + * ['tmp_name'] - temporary file name on server + * ['error'] - error code. 0 = 'good'. 1..4 main others, although up to 8 defined for later PHP versions + * Files stored in server's temporary directory, unless another set + */ + public function getUploaded($uploaddir, $fileinfo = false, $options = array()) + { - return process_uploaded_files($path, $fileinfo, $options); + require_once(e_HANDLER . "upload_handler.php"); + if($uploaddir == e_UPLOAD || $uploaddir == e_TEMP || $uploaddir == e_AVATAR_UPLOAD) + { + $path = $uploaddir; } - - - /** - * Quickly scan and return a list of files in a directory. - * - * @param string $dir - * @param null $extensions - * @return array - */ - public function scandir($dir, $extensions = null) + elseif(defined('e_CURRENT_PLUGIN')) { + $path = $this->getUserDir(USERID, true, str_replace("../", '', $uploaddir)); // .$this->get; + } + else + { + return false; + } - $list = array(); + return process_uploaded_files($path, $fileinfo, $options); - $ext = str_replace(",", "|", $extensions); + } - $tmp = scandir($dir); - foreach($tmp as $v) - { - if($v == '.' || $v == '..') - { - continue; - } - if(!empty($ext) && !preg_match("/\.(" . $ext . ")$/i", $v)) - { + /** + * Quickly scan and return a list of files in a directory. + * + * @param string $dir + * @param null $extensions + * @return array + */ + public function scandir($dir, $extensions = null) + { - continue; - } + $list = array(); - $list[] = $v; - } + $ext = str_replace(",", "|", $extensions); - return $list; - } + $tmp = scandir($dir); + foreach($tmp as $v) + { + if($v == '.' || $v == '..') + { + continue; + } + if(!empty($ext) && !preg_match("/\.(" . $ext . ")$/i", $v)) + { - /** - * @param string $folder - * @param null $type - * @return bool|string - */ - public function gitPull($folder = '', $type = null) - { + continue; + } - $gitPath = defset('e_GIT', 'git'); // addo to e107_config.php to - $mes = e107::getMessage(); + $list[] = $v; + } + return $list; + } - // $text = 'umask 0022'; //Could correct permissions issue with 0664 files. - // Change Dir. - $folder = e107::getParser()->filter($folder, 'file'); // extra filter to keep RIPS happy. - switch($type) - { - case "plugin": - $dir = realpath(e_PLUGIN . basename($folder)); - break; + /** + * @param string $folder + * @param null $type + * @return bool|string + */ + public function gitPull($folder = '', $type = null) + { - case "theme": - $dir = realpath(e_THEME . basename($folder)); - break; + $gitPath = defset('e_GIT', 'git'); // addo to e107_config.php to + $mes = e107::getMessage(); - default: - $dir = e_ROOT; - } + // $text = 'umask 0022'; //Could correct permissions issue with 0664 files. + // Change Dir. + $folder = e107::getParser()->filter($folder, 'file'); // extra filter to keep RIPS happy. - // $cmd1 = 'cd '.$dir; - $cmd2 = 'cd ' . $dir . '; ' . $gitPath . ' reset --hard'; // Remove any local changes. - $cmd3 = 'cd ' . $dir . '; ' . $gitPath . ' pull'; // Run Pull request + switch($type) + { + case "plugin": + $dir = realpath(e_PLUGIN . basename($folder)); + break; + case "theme": + $dir = realpath(e_THEME . basename($folder)); + break; - $text = ''; + default: + $dir = e_ROOT; + } - $mes->addDebug($cmd2); - $mes->addDebug($cmd3); + // $cmd1 = 'cd '.$dir; + $cmd2 = 'cd ' . $dir . '; ' . $gitPath . ' reset --hard'; // Remove any local changes. + $cmd3 = 'cd ' . $dir . '; ' . $gitPath . ' pull'; // Run Pull request - // $text = `$cmd1 2>&1`; - $text .= `$cmd2 2>&1`; - $text .= `$cmd3 2>&1`; + $text = ''; - if(deftrue('e_DEBUG') || deftrue('e_GIT_DEBUG')) - { - $message = date('r') . "\t\tgitPull()\t\t" . $text; - file_put_contents(e_LOG . "fileClass.log", $message, FILE_APPEND); - } - // $text .= `$cmd4 2>&1`; + $mes->addDebug($cmd2); + $mes->addDebug($cmd3); - // $text .= `$cmd5 2>&1`; + // $text = `$cmd1 2>&1`; + $text .= `$cmd2 2>&1`; + $text .= `$cmd3 2>&1`; - return print_a($text, true); + if(deftrue('e_DEBUG') || deftrue('e_GIT_DEBUG')) + { + $message = date('r') . "\t\tgitPull()\t\t" . $text; + file_put_contents(e_LOG . "fileClass.log", $message, FILE_APPEND); } + // $text .= `$cmd4 2>&1`; - /** - * Returns true is the URL is valid and false if it is not. - * - * @param $url - * @return bool - */ - public function isValidURL($url) - { + // $text .= `$cmd5 2>&1`; - ini_set('default_socket_timeout', 1); - $headers = get_headers($url); + return print_a($text, true); - // print_a($headers); + } - return (stripos($headers[0], "200 OK") || strpos($headers[0], "302")); - } + /** + * Returns true is the URL is valid and false if it is not. + * + * @param $url + * @return bool + */ + public function isValidURL($url) + { - /** - * Unzip Plugin or Theme zip file and move to plugin or theme folder. - * - * @param string $localfile - filename located in e_TEMP - * @param string $type - addon type, either 'plugin' or 'theme', (possibly 'language' in future). - * @param bool $overwrite - * @return string unzipped folder name on success or false. - */ - public function unzipArchive($localfile, $type, $overwrite = false) - { + ini_set('default_socket_timeout', 1); + $headers = get_headers($url); - $mes = e107::getMessage(); + // print_a($headers); - chmod(e_TEMP . $localfile, 0755); + return (stripos($headers[0], "200 OK") || strpos($headers[0], "302")); + } - $fileinfo = array(); - $dir = false; + /** + * Unzip Plugin or Theme zip file and move to plugin or theme folder. + * + * @param string $localfile - filename located in e_TEMP + * @param string $type - addon type, either 'plugin' or 'theme', (possibly 'language' in future). + * @param bool $overwrite + * @return string unzipped folder name on success or false. + */ + public function unzipArchive($localfile, $type, $overwrite = false) + { - if(class_exists('ZipArchive')) // PHP7 compat. method. - { - $zip = new ZipArchive; + $mes = e107::getMessage(); - if($zip->open(e_TEMP . $localfile) === true) - { - for($i = 0; $i < $zip->numFiles; $i++) - { - $filename = $zip->getNameIndex($i); + chmod(e_TEMP . $localfile, 0755); - $fileinfo = pathinfo($filename); + $fileinfo = array(); - if($fileinfo['dirname'] === '.') - { - $dir = $fileinfo['basename']; - break; - } - elseif($fileinfo['basename'] === 'plugin.php' || $fileinfo['basename'] === 'theme.php') - { - $dir = $fileinfo['dirname']; - } + $dir = false; - // $stat = $zip->statIndex( $i ); - // print_a( $stat['name'] ); - } + if(class_exists('ZipArchive')) // PHP7 compat. method. + { + $zip = new ZipArchive; + if($zip->open(e_TEMP . $localfile) === true) + { + for($i = 0; $i < $zip->numFiles; $i++) + { + $filename = $zip->getNameIndex($i); - $zip->extractTo(e_TEMP); - chmod(e_TEMP . $dir, 0755); + $fileinfo = pathinfo($filename); - if(empty($dir) && deftrue('e_DEBUG')) + if($fileinfo['dirname'] === '.') + { + $dir = $fileinfo['basename']; + break; + } + elseif($fileinfo['basename'] === 'plugin.php' || $fileinfo['basename'] === 'theme.php') { - print_a($fileinfo); + $dir = $fileinfo['dirname']; } + // $stat = $zip->statIndex( $i ); + // print_a( $stat['name'] ); + } + - $zip->close(); + $zip->extractTo(e_TEMP); + chmod(e_TEMP . $dir, 0755); + + if(empty($dir) && deftrue('e_DEBUG')) + { + print_a($fileinfo); } + $zip->close(); } - else // Legacy Method. - { - require_once(e_HANDLER . "pclzip.lib.php"); - $archive = new PclZip(e_TEMP . $localfile); - $unarc = ($fileList = $archive->extract(PCLZIP_OPT_PATH, e_TEMP, PCLZIP_OPT_SET_CHMOD, 0755)); // Store in TEMP first. - $dir = $this->getRootFolder($unarc); - } + + } + /* else // Legacy Method. + { + require_once(e_HANDLER . "pclzip.lib.php"); + + $archive = new PclZip(e_TEMP . $localfile); + $unarc = ($fileList = $archive->extract(PCLZIP_OPT_PATH, e_TEMP, PCLZIP_OPT_SET_CHMOD, 0755)); // Store in TEMP first. + $dir = $this->getRootFolder($unarc); + }*/ - $destpath = ($type == 'theme') ? e_THEME : e_PLUGIN; - // $typeDiz = ucfirst($type); + $destpath = ($type == 'theme') ? e_THEME : e_PLUGIN; + // $typeDiz = ucfirst($type); - @copy(e_TEMP . $localfile, e_BACKUP . $dir . ".zip"); // Make a Backup in the system folder. + @copy(e_TEMP . $localfile, e_BACKUP . $dir . ".zip"); // Make a Backup in the system folder. - if($dir && is_dir($destpath . $dir)) + if($dir && is_dir($destpath . $dir)) + { + if($overwrite === true) { - if($overwrite === true) + if(file_exists(e_TEMP . $localfile)) { - if(file_exists(e_TEMP . $localfile)) + $time = date("YmdHi"); + if(rename($destpath . $dir, e_BACKUP . $dir . "_" . $time)) { - $time = date("YmdHi"); - if(rename($destpath . $dir, e_BACKUP . $dir . "_" . $time)) - { - $mes->addSuccess(ADLAN_195); - } + $mes->addSuccess(ADLAN_195); } } - else - { + } + else + { - $mes->addError("(" . ucfirst($type) . ") Already Downloaded - " . basename($destpath) . '/' . $dir); + $mes->addError("(" . ucfirst($type) . ") Already Downloaded - " . basename($destpath) . '/' . $dir); - if(file_exists(e_TEMP . $localfile)) - { - @unlink(e_TEMP . $localfile); - } + if(file_exists(e_TEMP . $localfile)) + { + @unlink(e_TEMP . $localfile); + } - $this->removeDir(e_TEMP . $dir); + $this->removeDir(e_TEMP . $dir); - return false; - } + return false; } + } + + if(empty($dir)) + { + $mes->addError("Couldn't detect the root folder in the zip."); // flush(); + @unlink(e_TEMP . $localfile); - if(empty($dir)) + return false; + } + + if(is_dir(e_TEMP . $dir)) + { + $res = rename(e_TEMP . $dir, $destpath . $dir); + if($res === false) { - $mes->addError("Couldn't detect the root folder in the zip."); // flush(); + $mes->addError("Couldn't Move " . e_TEMP . $dir . " to " . $destpath . $dir . " Folder"); // flush(); usleep(50000); @unlink(e_TEMP . $localfile); return false; } - if(is_dir(e_TEMP . $dir)) - { - $res = rename(e_TEMP . $dir, $destpath . $dir); - if($res === false) - { - $mes->addError("Couldn't Move " . e_TEMP . $dir . " to " . $destpath . $dir . " Folder"); // flush(); usleep(50000); - @unlink(e_TEMP . $localfile); - - return false; - } + // $dir = basename($unarc[0]['filename']); + // $plugPath = preg_replace("/[^a-z0-9-\._]/", "-", strtolower($dir)); + //$status = "Done"; // ADMIN_TRUE_ICON; + @unlink(e_TEMP . $localfile); - // $dir = basename($unarc[0]['filename']); - // $plugPath = preg_replace("/[^a-z0-9-\._]/", "-", strtolower($dir)); - //$status = "Done"; // ADMIN_TRUE_ICON; - @unlink(e_TEMP . $localfile); + return $dir; + } - return $dir; - } + return false; + } - return false; - } + /** + * @param string|boolean $file_mask - comma-separated list of allowed file types + * @param string $filename - optional override file name - defaults ignored + * + * @return array of filetypes + * @deprecated Use getAllowedFileTypes() + * Get an array of permitted filetypes according to a set hierarchy. + * If a specific file name given, that's used. Otherwise the default hierarchy is used + * + */ + function getFiletypeLimits($file_mask = false, $filename = '') // Wrapper only for now. + { - /** - * @deprecated Use getAllowedFileTypes() - * Get an array of permitted filetypes according to a set hierarchy. - * If a specific file name given, that's used. Otherwise the default hierarchy is used - * - * @param string|boolean $file_mask - comma-separated list of allowed file types - * @param string $filename - optional override file name - defaults ignored - * - * @return array of filetypes - */ - function getFiletypeLimits($file_mask = false, $filename = '') // Wrapper only for now. - { + require_once(e_HANDLER . "upload_handler.php"); + $limits = get_filetypes($file_mask, $filename); + ksort($limits); - require_once(e_HANDLER . "upload_handler.php"); - $limits = get_filetypes($file_mask, $filename); - ksort($limits); + return $limits; + } - return $limits; - } + /** + * Download and extract a zipped copy of e107 + * + * @param string $url "core" to download the e107 core from Git master or + * a custom download URL + * @param string $destination_path The e107 root where the downloaded archive should be extracted, + * with a directory separator at the end + * @return array|bool FALSE on failure; + * An array of successful and failed path extractions + */ + public function unzipGithubArchive($url = 'core', $destination_path = e_BASE) + { - /** - * Download and extract a zipped copy of e107 - * - * @param string $url "core" to download the e107 core from Git master or - * a custom download URL - * @param string $destination_path The e107 root where the downloaded archive should be extracted, - * with a directory separator at the end - * @return array|bool FALSE on failure; - * An array of successful and failed path extractions - */ - public function unzipGithubArchive($url = 'core', $destination_path = e_BASE) + switch($url) { + case "core": + $localfile = 'e107-master.zip'; + $remotefile = 'https://codeload.github.com/e107inc/e107/zip/master'; + $excludes = array( + 'e107-master/.codeclimate.yml', + 'e107-master/.editorconfig', + 'e107-master/.gitignore', + 'e107-master/.gitmodules', + 'e107-master/CONTRIBUTING.md', # moved to ./.github/CONTRIBUTING.md + 'e107-master/LICENSE', + 'e107-master/README.md', + 'e107-master/composer.json', + 'e107-master/composer.lock', + 'e107-master/install.php', + 'e107-master/favicon.ico', + ); + $excludeMatch = array( + '/.github/', + '/e107_tests/', + ); + break; - switch($url) - { - case "core": - $localfile = 'e107-master.zip'; - $remotefile = 'https://codeload.github.com/e107inc/e107/zip/master'; - $excludes = array( - 'e107-master/.codeclimate.yml', - 'e107-master/.editorconfig', - 'e107-master/.gitignore', - 'e107-master/.gitmodules', - 'e107-master/CONTRIBUTING.md', # moved to ./.github/CONTRIBUTING.md - 'e107-master/LICENSE', - 'e107-master/README.md', - 'e107-master/composer.json', - 'e107-master/composer.lock', - 'e107-master/install.php', - 'e107-master/favicon.ico', - ); - $excludeMatch = array( - '/.github/', - '/e107_tests/', - ); - break; + // language. + // eg. https://github.com/e107translations/Spanish/archive/v2.1.5.zip + default: + // 'e107-master.zip'; + $localfile = str_replace(array('https://github.com/e107translations/', '/archive/v'), array('', '-'), $url); //remove dirs. + $remotefile = $url; + $excludes = array(); + $excludeMatch = array('alt_auth', 'tagwords', 'faqs'); - // language. - // eg. https://github.com/e107translations/Spanish/archive/v2.1.5.zip - default: - // 'e107-master.zip'; - $localfile = str_replace(array('https://github.com/e107translations/', '/archive/v'), array('', '-'), $url); //remove dirs. - $remotefile = $url; - $excludes = array(); - $excludeMatch = array('alt_auth', 'tagwords', 'faqs'); + } - } + // Delete any existing file. + if(file_exists(e_TEMP . $localfile)) + { + unlink(e_TEMP . $localfile); + } - // Delete any existing file. - if(file_exists(e_TEMP . $localfile)) - { - unlink(e_TEMP . $localfile); - } + $result = $this->getRemoteFile($remotefile, $localfile); - $result = $this->getRemoteFile($remotefile, $localfile); + if($result === false) + { + return false; + } - if($result === false) - { - return false; - } + chmod(e_TEMP . $localfile, 0755); + require_once(e_HANDLER . "pclzip.lib.php"); - chmod(e_TEMP . $localfile, 0755); - require_once(e_HANDLER . "pclzip.lib.php"); + $zipBase = str_replace('.zip', '', $localfile); // eg. e107-master + $excludes[] = $zipBase; - $zipBase = str_replace('.zip', '', $localfile); // eg. e107-master - $excludes[] = $zipBase; - - $newFolders = array( - $zipBase . '/e107_admin/' => $destination_path . e107::getFolder('ADMIN'), - $zipBase . '/e107_core/' => $destination_path . e107::getFolder('CORE'), - $zipBase . '/e107_docs/' => $destination_path . e107::getFolder('DOCS'), - $zipBase . '/e107_handlers/' => $destination_path . e107::getFolder('HANDLERS'), - $zipBase . '/e107_images/' => $destination_path . e107::getFolder('IMAGES'), - $zipBase . '/e107_languages/' => $destination_path . e107::getFolder('LANGUAGES'), - $zipBase . '/e107_media/' => $destination_path . e107::getFolder('MEDIA'), - $zipBase . '/e107_plugins/' => $destination_path . e107::getFolder('PLUGINS'), - $zipBase . '/e107_system/' => $destination_path . e107::getFolder('SYSTEM'), - $zipBase . '/e107_themes/' => $destination_path . e107::getFolder('THEMES'), - $zipBase . '/e107_web/' => $destination_path . e107::getFolder('WEB'), - $zipBase . '/' => $destination_path - ); + $newFolders = array( + $zipBase . '/e107_admin/' => $destination_path . e107::getFolder('ADMIN'), + $zipBase . '/e107_core/' => $destination_path . e107::getFolder('CORE'), + $zipBase . '/e107_docs/' => $destination_path . e107::getFolder('DOCS'), + $zipBase . '/e107_handlers/' => $destination_path . e107::getFolder('HANDLERS'), + $zipBase . '/e107_images/' => $destination_path . e107::getFolder('IMAGES'), + $zipBase . '/e107_languages/' => $destination_path . e107::getFolder('LANGUAGES'), + $zipBase . '/e107_media/' => $destination_path . e107::getFolder('MEDIA'), + $zipBase . '/e107_plugins/' => $destination_path . e107::getFolder('PLUGINS'), + $zipBase . '/e107_system/' => $destination_path . e107::getFolder('SYSTEM'), + $zipBase . '/e107_themes/' => $destination_path . e107::getFolder('THEMES'), + $zipBase . '/e107_web/' => $destination_path . e107::getFolder('WEB'), + $zipBase . '/' => $destination_path + ); - $srch = array_keys($newFolders); - $repl = array_values($newFolders); + $srch = array_keys($newFolders); + $repl = array_values($newFolders); - $archive = new PclZip(e_TEMP . $localfile); - $unarc = ($fileList = $archive->extract(PCLZIP_OPT_PATH, e_TEMP, PCLZIP_OPT_SET_CHMOD, 0755)); // Store in TEMP first. + $archive = new PclZip(e_TEMP . $localfile); + $unarc = ($fileList = $archive->extract(PCLZIP_OPT_PATH, e_TEMP, PCLZIP_OPT_SET_CHMOD, 0755)); // Store in TEMP first. - $error = array(); - $success = array(); - $skipped = array(); + $error = array(); + $success = array(); + $skipped = array(); - foreach($unarc as $k => $v) + foreach($unarc as $k => $v) + { + if( + $this->matchFound($v['stored_filename'], $excludeMatch) || + in_array($v['stored_filename'], $excludes) + ) { - if($this->matchFound($v['stored_filename'], $excludeMatch) || - in_array($v['stored_filename'], $excludes)) - { - $skipped[] = $v['stored_filename']; - continue; - } - - $oldPath = $v['filename']; - $newPath = str_replace($srch, $repl, $v['stored_filename']); + $skipped[] = $v['stored_filename']; + continue; + } - if($v['folder'] == 1 && is_dir($newPath)) - { - // $skipped[] = $newPath. " (already exists)"; - continue; - } - @mkdir(dirname($newPath), 0755, true); - if(!rename($oldPath, $newPath)) - { - $error[] = $newPath; - } - else - { - $success[] = $newPath; - } + $oldPath = $v['filename']; + $newPath = str_replace($srch, $repl, $v['stored_filename']); + if($v['folder'] == 1 && is_dir($newPath)) + { + // $skipped[] = $newPath. " (already exists)"; + continue; + } + @mkdir(dirname($newPath), 0755, true); + if(!rename($oldPath, $newPath)) + { + $error[] = $newPath; + } + else + { + $success[] = $newPath; } - return array('success' => $success, 'error' => $error, 'skipped' => $skipped); } + return array('success' => $success, 'error' => $error, 'skipped' => $skipped); + } + /** * @param $file @@ -1914,660 +1955,661 @@ public function unzipGithubArchive($url = 'core', $destination_path = e_BASE) * @return bool */ private function matchFound($file, $array) - { + { - if(empty($array)) - { - return false; - } + if(empty($array)) + { + return false; + } - foreach($array as $term) + foreach($array as $term) + { + if(strpos($file, $term) !== false) { - if(strpos($file, $term) !== false) - { - return true; - } - + return true; } - return false; - } - /** - * Checks that the directory exists and is writable. - * - * @param string $directory - * A string containing the name of a directory path. A trailing slash will be trimmed from a path. - * @param int $options - * A bitmask to indicate if the directory should be created if it does not exist (FILE_CREATE_DIRECTORY) or - * made writable if it is read-only (FILE_MODIFY_PERMISSIONS). - * - * @return bool - * TRUE if the directory exists (or was created) and is writable. FALSE otherwise. - */ - public function prepareDirectory($directory, $options = FILE_MODIFY_PERMISSIONS) - { - - $directory = e107::getParser()->replaceConstants($directory); - $directory = rtrim($directory, '/\\'); + return false; - // Check if directory exists. - if(!is_dir($directory)) - { - // Let mkdir() recursively create directories and use the default directory permissions. - if(($options & FILE_CREATE_DIRECTORY) && @$this->mkDir($directory, null, true)) - { - return $this->_chMod($directory); - } + } - return false; - } + /** + * Checks that the directory exists and is writable. + * + * @param string $directory + * A string containing the name of a directory path. A trailing slash will be trimmed from a path. + * @param int $options + * A bitmask to indicate if the directory should be created if it does not exist (FILE_CREATE_DIRECTORY) or + * made writable if it is read-only (FILE_MODIFY_PERMISSIONS). + * + * @return bool + * TRUE if the directory exists (or was created) and is writable. FALSE otherwise. + */ + public function prepareDirectory($directory, $options = FILE_MODIFY_PERMISSIONS) + { - // The directory exists, so check to see if it is writable. - $writable = is_writable($directory); + $directory = e107::getParser()->replaceConstants($directory); + $directory = rtrim($directory, '/\\'); - if(!$writable && ($options & FILE_MODIFY_PERMISSIONS)) + // Check if directory exists. + if(!is_dir($directory)) + { + // Let mkdir() recursively create directories and use the default directory permissions. + if(($options & FILE_CREATE_DIRECTORY) && @$this->mkDir($directory, null, true)) { return $this->_chMod($directory); } - return $writable; + return false; } - /** - * (Non-Recursive) Sets the permissions on a file or directory. - * - * @param string $path - * A string containing a file, or directory path. - * @param int $mode - * Integer value for the permissions. Consult PHP chmod() documentation for more information. - * - * @return bool - * TRUE for success, FALSE in the event of an error. - */ - private function _chMod($path, $mode = null) - { + // The directory exists, so check to see if it is writable. + $writable = is_writable($directory); - if(!isset($mode)) - { - if(is_dir($path)) - { - $mode = 0775; - } - else - { - $mode = 0664; - } - } + if(!$writable && ($options & FILE_MODIFY_PERMISSIONS)) + { + return $this->_chMod($directory); + } - if(@chmod($path, $mode)) - { - return true; - } + return $writable; + } - return false; - } + /** + * (Non-Recursive) Sets the permissions on a file or directory. + * + * @param string $path + * A string containing a file, or directory path. + * @param int $mode + * Integer value for the permissions. Consult PHP chmod() documentation for more information. + * + * @return bool + * TRUE for success, FALSE in the event of an error. + */ + private function _chMod($path, $mode = null) + { - /** - * Creates a directory. - * - * @param string $path - * A string containing a file path. - * @param int $mode - * Mode is used. - * @param bool $recursive - * Default to FALSE. - * @param null $context - * Refer to http://php.net/manual/ref.stream.php - * - * @return bool - * Boolean TRUE on success, or FALSE on failure. - */ - public function mkDir($path, $mode = null, $recursive = false, $context = null) - { - - if(!isset($mode)) + if(!isset($mode)) + { + if(is_dir($path)) { $mode = 0775; } - - if(!isset($context)) - { - return mkdir($path, $mode, $recursive); - } else { - return mkdir($path, $mode, $recursive, $context); + $mode = 0664; } } + if(@chmod($path, $mode)) + { + return true; + } + + return false; + } + + /** + * Creates a directory. + * + * @param string $path + * A string containing a file path. + * @param int $mode + * Mode is used. + * @param bool $recursive + * Default to FALSE. + * @param null $context + * Refer to http://php.net/manual/ref.stream.php + * + * @return bool + * Boolean TRUE on success, or FALSE on failure. + */ + public function mkDir($path, $mode = null, $recursive = false, $context = null) + { - /** - * @param int|null $int - */ - private function setErrorNum($int) + if(!isset($mode)) { + $mode = 0775; + } - $this->errornum = $int; + if(!isset($context)) + { + return mkdir($path, $mode, $recursive); } + else + { + return mkdir($path, $mode, $recursive, $context); + } + } + + /** + * @param int|null $int + */ + private function setErrorNum($int) + { + + $this->errornum = $int; + } + + + /** + * New in v2.1.9 + * Check uploaded file to try and identify dodgy content. + * + * @param string $filename is the full path+name to the uploaded file on the server + * @param string $target_name is the intended name of the file once transferred + * @param array $allowed_filetypes is an array of permitted file extensions, in lower case, no leading '.' + * (usually generated from filetypes.xml/filetypes.php) + * @param boolean|string $unknown - handling of file types unknown to us/define additional types + * if FALSE, rejects totally unknown file extensions (even if in $allowed_filetypes). + * if $unknown is TRUE, accepts totally unknown file extensions. + * otherwise $unknown is a comma-separated list of additional permitted file extensions + * @return boolean - TRUE if file acceptable, FALSE if unacceptable. Use getErrorCode() immediately after to retrieve error code: + * 1 - file type not allowed + * 2 - can't read file contents + * 3 - illegal file contents (usually 'setErrorNum(null); + // 1. Start by checking against filetypes - that's the easy one! + $file_ext = pathinfo($target_name, PATHINFO_EXTENSION); - $this->setErrorNum(null); - // 1. Start by checking against filetypes - that's the easy one! - $file_ext = pathinfo($target_name, PATHINFO_EXTENSION); + $file_ext = strtolower($file_ext); - $file_ext = strtolower($file_ext); + // 2. For all files, read the first little bit to check for any flags etc + $res = fopen($filename, 'rb'); + $tstr = fread($res, 2048); + fclose($res); - // 2. For all files, read the first little bit to check for any flags etc - $res = fopen($filename, 'rb'); - $tstr = fread($res, 2048); - fclose($res); + if($tstr === false) + { + $this->setErrorNum(2); // If can't read file, not much use carrying on! - if($tstr === false) - { - $this->setErrorNum(2); // If can't read file, not much use carrying on! + return false; + } - return false; - } + $archives = array('zip', 'gzip', 'gz', 'tar', 'bzip', '7z', 'rar'); - $archives = array('zip', 'gzip', 'gz', 'tar', 'bzip', '7z', 'rar'); + if(!in_array($file_ext, $archives) && stripos($tstr, 'setErrorNum(3); // Pretty certain exploit + + return false; + } - if(!in_array($file_ext, $archives) && stripos($tstr, 'setErrorNum(3); // Pretty certain exploit + $this->setErrorNum(7); return false; } + } - if(!in_array($file_ext, $archives) && strpos($tstr, 'getImageMime($filename); + + if($ret === false) { - $this->setErrorNum(7); + $this->setErrorNum(4); // exif_imagetype didn't recognize the image mime return false; } - } - - // 3. Now do what we can based on file extension - switch($file_ext) - { - case 'jpg': - case 'gif': - case 'png': - case 'jpeg': - case 'pjpeg': - case 'bmp': - case 'swf': - case 'fla': - // case 'flv': - case 'swc': - case 'psd': - case 'ai': - case 'eps': - case 'svg': - case 'tiff': - case 'jpc': // http://fileinfo.com/extension/jpc - case 'jpx': // http://fileinfo.com/extension/jpx - case 'jb2': // http://fileinfo.com/extension/jb2 - case 'jp2': // http://fileinfo.com/extension/jp2 - case 'iff': - case 'wbmp': - case 'xbm': - case 'ico': - case 'webp': - - $ret = $this->getImageMime($filename); - - if($ret === false) - { - $this->setErrorNum(4); // exif_imagetype didn't recognize the image mime + // getimagesize() is extremely slow + it can't handle all required media!!! Abandon this check! + // return 5; // Zero size picture or bad file format + break; + + case 'zip': + case 'gzip': + case 'gz': + case 'tar': + case 'bzip': + case 'pdf': + case 'doc': + case 'docx': + case 'xls': + case 'xlsx': + case 'rar': + case '7z': + case 'csv': + case 'mp3': + case 'wav': + case 'mp4': + case 'mpg': + case 'mpa': + case 'wma': + case 'wmv': + case 'flv': //Flash stream + case 'f4v': //Flash stream + case 'mov': //media + case 'avi': //media + case 'xml': + case 'webm': + case 'ppt': + case 'pptx': + + break; // Just accept these + + case 'php': + case 'php5': + case 'php7': + case 'htm': + case 'html': + case 'cgi': + case 'pl': + + $this->setErrorNum(9); // Never accept these! Whatever the user thinks! - return false; - } + return false; - // getimagesize() is extremely slow + it can't handle all required media!!! Abandon this check! - // return 5; // Zero size picture or bad file format - break; + default: // Unknown file type. - case 'zip': - case 'gzip': - case 'gz': - case 'tar': - case 'bzip': - case 'pdf': - case 'doc': - case 'docx': - case 'xls': - case 'xlsx': - case 'rar': - case '7z': - case 'csv': - case 'mp3': - case 'wav': - case 'mp4': - case 'mpg': - case 'mpa': - case 'wma': - case 'wmv': - case 'flv': //Flash stream - case 'f4v': //Flash stream - case 'mov': //media - case 'avi': //media - case 'xml': - case 'webm': - case 'ppt': - case 'pptx': - - break; // Just accept these - - case 'php': - case 'php5': - case 'php7': - case 'htm': - case 'html': - case 'cgi': - case 'pl': - - $this->setErrorNum(9); // Never accept these! Whatever the user thinks! + $this->setErrorNum(8); - return false; + return false; + } - default: // Unknown file type. + return true; // Accepted here + } - $this->setErrorNum(8); - return false; - } + /** + * New in v2.1.9 + * Check filename, path or URL against filetypes.xml + * + * @param $file - real path to file. + * @param string $targetFile + * @return boolean + */ + public function isAllowedType($file, $targetFile = '') + { - return true; // Accepted here + if(empty($targetFile)) + { + $targetFile = $file; } + $remote = false; - /** - * New in v2.1.9 - * Check filename, path or URL against filetypes.xml - * - * @param $file - real path to file. - * @param string $targetFile - * @return boolean - */ - public function isAllowedType($file, $targetFile = '') + if(strpos($targetFile, 'http') === 0) // remote file. { - - if(empty($targetFile)) + $tmp = parse_url($targetFile); + $targetFile = $tmp['path']; + $remote = true; + if(!empty($tmp['host']) && ($tmp['host'] === 'localhost' || $tmp['host'] === '127.0.0.1')) { - $targetFile = $file; + return false; } + } - $remote = false; + $ext = pathinfo($targetFile, PATHINFO_EXTENSION); - if(strpos($targetFile,'http') === 0) // remote file. + $types = $this->getAllowedFileTypes(); + + if(isset($types[$ext])) + { + if($remote) { - $tmp = parse_url($targetFile); - $targetFile = $tmp['path']; - $remote = true; - if(!empty($tmp['host']) && ($tmp['host'] === 'localhost' || $tmp['host'] === '127.0.0.1')) - { - return false; - } + return true; } - $ext = pathinfo($targetFile, PATHINFO_EXTENSION); + $maxSize = $types[$ext] * 1024; + $fileSize = filesize($file); - $types = $this->getAllowedFileTypes(); + // echo "\nisAllowedType(".basename($file).") ".$fileSize ." / ".$maxSize; - if(isset($types[$ext])) + if($fileSize <= $maxSize) { - if($remote) - { - return true; - } - - $maxSize = $types[$ext] * 1024; - $fileSize = filesize($file); - - // echo "\nisAllowedType(".basename($file).") ".$fileSize ." / ".$maxSize; - - if($fileSize <= $maxSize) - { - return true; - } - + return true; } - return false; - } + return false; + + } + /** * @return string[] */ private function getMimeTypes() - { - return array( - 'asc' => 'text/plain', - 'css' => 'text/css', - 'csv' => 'text/csv', - 'etx' => 'text/x-setext', - 'htm' => 'text/html', - 'html' => 'text/html', - 'ics' => 'text/calendar', - 'ini' => 'text/plain', - 'log' => 'text/plain', - 'php' => 'text/html', - 'sgm' => 'text/sgml', - 'sgml' => 'text/sgml', - 'txt' => 'text/plain', - 'yaml' => 'text/yaml', - 'yml' => 'text/yaml', - - - // images - 'bmp' => 'image/bmp', - 'gif' => 'image/gif', - 'ico' => 'image/vnd.microsoft.icon', - 'jpe' => 'image/jpeg', - 'jpeg' => 'image/jpeg', - 'jpg' => 'image/jpeg', - 'pbm' => 'image/x-portable-bitmap', - 'pgm' => 'image/x-portable-graymap', - 'png' => 'image/png', - 'pnm' => 'image/x-portable-anymap', - 'ppm' => 'image/x-portable-pixmap', - 'ras' => 'image/x-cmu-raster', - 'svg' => 'image/svg+xml', - 'svgz' => 'image/svg+xml', - 'tif' => 'image/tiff', - 'tiff' => 'image/tiff', - 'webp' => 'image/webp', - 'xbm' => 'image/x-xbitmap', - 'xpm' => 'image/x-xpixmap', - 'xwd' => 'image/x-xwindowdump', - - // archives - '7z' => 'application/x-7z-compressed', - 'cab' => 'application/vnd.ms-cab-compressed', - 'exe' => 'application/x-msdownload', - 'gz' => 'application/gzip', - 'msi' => 'application/x-msdownload', - 'rar' => 'application/x-rar-compressed', - 'zip' => 'application/zip', - - - // video - - '3gp' => 'video/3gpp', - 'asf' => 'video/x-ms-asf', - 'avi' => 'video/x-msvideo', - 'flv' => 'video/x-flv', - 'm4v' => 'video/mp4', - 'mkv' => 'video/x-matroska', - 'mov' => 'video/quicktime', - 'mp4' => 'video/mp4', - 'mp4v' => 'video/mp4', - 'mpe' => 'video/mpeg', - 'mpeg' => 'video/mpeg', - 'mpg' => 'video/mpeg', - 'mpg4' => 'video/mp4', - 'ogv' => 'video/ogg', - 'qt' => 'video/quicktime', - 'webm' => 'video/webm', - 'wmv' => 'video/x-ms-wmv', - - // audio - 'aac' => 'audio/x-aac', - 'aif' => 'audio/x-aiff', - 'flac' => 'audio/flac', - 'm4a' => 'audio/mp4', - 'mid' => 'audio/midi', - 'midi' => 'audio/midi', - 'mp3' => 'audio/mpeg', - 'mp4a' => 'audio/mp4', - 'oga' => 'audio/ogg', - 'ogg' => 'audio/ogg', - 'wav' => 'audio/x-wav', - 'wma' => 'audio/x-ms-wma', - - // adobe - 'ai' => 'application/postscript', - 'eps' => 'application/postscript', - 'pdf' => 'application/pdf', - 'ps' => 'application/postscript', - 'psd' => 'image/vnd.adobe.photoshop', - - // ms office - 'doc' => 'application/msword', - 'docx' => 'application/msword', - 'ppt' => 'application/vnd.ms-powerpoint', - 'pptx' => 'application/vnd.ms-powerpoint', - 'rtf' => 'application/rtf', - 'xls' => 'application/vnd.ms-excel', - 'xlsx' => 'application/vnd.ms-excel', - - // open office - 'odt' => 'application/vnd.oasis.opendocument.text', - 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', - - // other - 'atom' => 'application/atom+xml', - 'bz2' => 'application/x-bzip2', - 'cer' => 'application/pkix-cert', - 'crl' => 'application/pkix-crl', - 'crt' => 'application/x-x509-ca-cert', - 'cu' => 'application/cu-seeme', - 'deb' => 'application/x-debian-package', - 'dvi' => 'application/x-dvi', - 'eot' => 'application/vnd.ms-fontobject', - 'epub' => 'application/epub+zip', - 'iso' => 'application/x-iso9660-image', - 'jar' => 'application/java-archive', - 'js' => 'application/javascript', - 'json' => 'application/json', - 'latex' => 'application/x-latex', - 'ogx' => 'application/ogg', - 'rss' => 'application/rss+xml', - 'swf' => 'application/x-shockwave-flash', - 'tar' => 'application/x-tar', - 'torrent' => 'application/x-bittorrent', - 'ttf' => 'application/x-font-ttf', - 'woff' => 'application/x-font-woff', - 'wsdl' => 'application/wsdl+xml', - 'xml' => 'application/xml', + { - ); + return array( + 'asc' => 'text/plain', + 'css' => 'text/css', + 'csv' => 'text/csv', + 'etx' => 'text/x-setext', + 'htm' => 'text/html', + 'html' => 'text/html', + 'ics' => 'text/calendar', + 'ini' => 'text/plain', + 'log' => 'text/plain', + 'php' => 'text/html', + 'sgm' => 'text/sgml', + 'sgml' => 'text/sgml', + 'txt' => 'text/plain', + 'yaml' => 'text/yaml', + 'yml' => 'text/yaml', + + + // images + 'bmp' => 'image/bmp', + 'gif' => 'image/gif', + 'ico' => 'image/vnd.microsoft.icon', + 'jpe' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'pbm' => 'image/x-portable-bitmap', + 'pgm' => 'image/x-portable-graymap', + 'png' => 'image/png', + 'pnm' => 'image/x-portable-anymap', + 'ppm' => 'image/x-portable-pixmap', + 'ras' => 'image/x-cmu-raster', + 'svg' => 'image/svg+xml', + 'svgz' => 'image/svg+xml', + 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', + 'webp' => 'image/webp', + 'xbm' => 'image/x-xbitmap', + 'xpm' => 'image/x-xpixmap', + 'xwd' => 'image/x-xwindowdump', + + // archives + '7z' => 'application/x-7z-compressed', + 'cab' => 'application/vnd.ms-cab-compressed', + 'exe' => 'application/x-msdownload', + 'gz' => 'application/gzip', + 'msi' => 'application/x-msdownload', + 'rar' => 'application/x-rar-compressed', + 'zip' => 'application/zip', + + + // video + + '3gp' => 'video/3gpp', + 'asf' => 'video/x-ms-asf', + 'avi' => 'video/x-msvideo', + 'flv' => 'video/x-flv', + 'm4v' => 'video/mp4', + 'mkv' => 'video/x-matroska', + 'mov' => 'video/quicktime', + 'mp4' => 'video/mp4', + 'mp4v' => 'video/mp4', + 'mpe' => 'video/mpeg', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mpg4' => 'video/mp4', + 'ogv' => 'video/ogg', + 'qt' => 'video/quicktime', + 'webm' => 'video/webm', + 'wmv' => 'video/x-ms-wmv', + + // audio + 'aac' => 'audio/x-aac', + 'aif' => 'audio/x-aiff', + 'flac' => 'audio/flac', + 'm4a' => 'audio/mp4', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mp3' => 'audio/mpeg', + 'mp4a' => 'audio/mp4', + 'oga' => 'audio/ogg', + 'ogg' => 'audio/ogg', + 'wav' => 'audio/x-wav', + 'wma' => 'audio/x-ms-wma', + + // adobe + 'ai' => 'application/postscript', + 'eps' => 'application/postscript', + 'pdf' => 'application/pdf', + 'ps' => 'application/postscript', + 'psd' => 'image/vnd.adobe.photoshop', + + // ms office + 'doc' => 'application/msword', + 'docx' => 'application/msword', + 'ppt' => 'application/vnd.ms-powerpoint', + 'pptx' => 'application/vnd.ms-powerpoint', + 'rtf' => 'application/rtf', + 'xls' => 'application/vnd.ms-excel', + 'xlsx' => 'application/vnd.ms-excel', + + // open office + 'odt' => 'application/vnd.oasis.opendocument.text', + 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', + + // other + 'atom' => 'application/atom+xml', + 'bz2' => 'application/x-bzip2', + 'cer' => 'application/pkix-cert', + 'crl' => 'application/pkix-crl', + 'crt' => 'application/x-x509-ca-cert', + 'cu' => 'application/cu-seeme', + 'deb' => 'application/x-debian-package', + 'dvi' => 'application/x-dvi', + 'eot' => 'application/vnd.ms-fontobject', + 'epub' => 'application/epub+zip', + 'iso' => 'application/x-iso9660-image', + 'jar' => 'application/java-archive', + 'js' => 'application/javascript', + 'json' => 'application/json', + 'latex' => 'application/x-latex', + 'ogx' => 'application/ogg', + 'rss' => 'application/rss+xml', + 'swf' => 'application/x-shockwave-flash', + 'tar' => 'application/x-tar', + 'torrent' => 'application/x-bittorrent', + 'ttf' => 'application/x-font-ttf', + 'woff' => 'application/x-font-woff', + 'wsdl' => 'application/wsdl+xml', + 'xml' => 'application/xml', + + ); - } + } + /** + * Return the mime-type based on the file's extension. + * + * @param string $filename + * @return string + */ + public function getMime($filename) + { + + $filename = basename($filename); + $tmp = explode('.', $filename); - /** - * Return the mime-type based on the file's extension. - * @param string $filename - * @return string - */ - public function getMime($filename) + if(count($tmp) < 2) // no extension. { - $filename = basename($filename); - - $tmp = explode('.', $filename); + return false; + } - if(count($tmp) < 2) // no extension. - { - return false; - } + $ext = strtolower(end($tmp)); - $ext = strtolower(end($tmp)); + $types = $this->getMimeTypes(); - $types = $this->getMimeTypes(); + if(isset($types[$ext])) + { + return $types[$ext]; + } + else + { + return 'application/octet-stream'; + } - if(isset($types[$ext])) - { - return $types[$ext]; - } - else - { - return 'application/octet-stream'; - } + } - } + /** + * New in v2.1.9 + * Get image (string) mime type + * or when extended - array [(string) mime-type, (array) associated extensions)]. + * A much faster way to retrieve mimes than getimagesize() + * + * @param $filename + * @param bool|false $extended + * @return array|string + */ + function getImageMime($filename, $extended = false) + { - /** - * New in v2.1.9 - * Get image (string) mime type - * or when extended - array [(string) mime-type, (array) associated extensions)]. - * A much faster way to retrieve mimes than getimagesize() - * - * @param $filename - * @param bool|false $extended - * @return array|string - */ - function getImageMime($filename, $extended = false) - { - - // mime types as returned from image_type_to_mime_type() - // and associated file extensions - $imageExtensions = array( - 'image/gif' => array('gif'), - 'image/jpeg' => array('jpg'), - 'image/png' => array('png'), - 'application/x-shockwave-flash' => array('swf', 'swc'), - 'image/psd' => array('psd'), - 'image/bmp' => array('bmp'), - 'image/tiff' => array('tiff'), - 'application/octet-stream' => array('jpc', 'jpx', 'jb2'), - 'image/jp2' => array('jp2'), - 'image/iff' => array('iff'), - 'image/vnd.wap.wbmp' => array('wbmp'), - 'image/xbm' => array('xbm'), - 'image/vnd.microsoft.icon' => array('ico'), - 'image/webp' => array('webp'), + // mime types as returned from image_type_to_mime_type() + // and associated file extensions + $imageExtensions = array( + 'image/gif' => array('gif'), + 'image/jpeg' => array('jpg'), + 'image/png' => array('png'), + 'application/x-shockwave-flash' => array('swf', 'swc'), + 'image/psd' => array('psd'), + 'image/bmp' => array('bmp'), + 'image/tiff' => array('tiff'), + 'application/octet-stream' => array('jpc', 'jpx', 'jb2'), + 'image/jp2' => array('jp2'), + 'image/iff' => array('iff'), + 'image/vnd.wap.wbmp' => array('wbmp'), + 'image/xbm' => array('xbm'), + 'image/vnd.microsoft.icon' => array('ico'), + 'image/webp' => array('webp'), + ); + + $ret = image_type_to_mime_type(exif_imagetype($filename)); + + if($extended) + { + return array( + $ret, + $ret && isset($imageExtensions[$ret]) ? $imageExtensions[$ret] : array() ); + } - $ret = image_type_to_mime_type(exif_imagetype($filename)); + return $ret; - if($extended) - { - return array( - $ret, - $ret && isset($imageExtensions[$ret]) ? $imageExtensions[$ret] : array() - ); - } + } - return $ret; - } + /** + * New in v2.1.9 + * Get array of file types (file extensions) which are permitted - reads an XML-formatted definition file. + * (Similar to @See{get_allowed_filetypes()}, but expects an XML file) + * + * @param string $class - e_UC_MEMBER etc if a specific class of file-types is required. Otherwise, it defaults to the perms of the current user. + * @return array - where key is the file type (extension); value is max upload size + */ + public function getAllowedFileTypes($class = null) + { + + $ret = array(); + $file_array = array(); + /* if($file_mask) + { + $file_array = explode(',', $file_mask); + foreach($file_array as $k => $f) + { + $file_array[$k] = trim($f); + } + }*/ - /** - * New in v2.1.9 - * Get array of file types (file extensions) which are permitted - reads an XML-formatted definition file. - * (Similar to @See{get_allowed_filetypes()}, but expects an XML file) - * - * @param string $class - e_UC_MEMBER etc if a specific class of file-types is required. Otherwise, it defaults to the perms of the current user. - * @return array - where key is the file type (extension); value is max upload size - */ - public function getAllowedFileTypes($class = null) + if(!is_readable(e_SYSTEM . "filetypes.xml")) { + return array(); + } - $ret = array(); - $file_array = array(); + $xml = e107::getXml(); + $xml->setOptArrayTags('class'); // class tag should be always array + $temp_vars = $xml->loadXMLfile(e_SYSTEM . "filetypes.xml", 'filetypes'); - /* if($file_mask) - { - $file_array = explode(',', $file_mask); - foreach($file_array as $k => $f) - { - $file_array[$k] = trim($f); - } - }*/ + if($temp_vars === false) + { + echo "Error reading filetypes.xml
"; - if(!is_readable(e_SYSTEM . "filetypes.xml")) - { - return array(); - } + return $ret; + } - $xml = e107::getXml(); - $xml->setOptArrayTags('class'); // class tag should be always array - $temp_vars = $xml->loadXMLfile(e_SYSTEM . "filetypes.xml", 'filetypes'); + foreach($temp_vars['class'] as $v1) + { + $v = $v1['@attributes']; - if($temp_vars === false) + if(!is_numeric($v['name'])) { - echo "Error reading filetypes.xml
"; - - return $ret; + $v['name'] = e107::getUserClass()->getClassFromKey($v['name'], $v['name']); // convert 'admin' etc to numeric equivalent. } - foreach($temp_vars['class'] as $v1) + if(($class === null && check_class($v['name'])) || (int) $class === (int) $v['name']) { - $v = $v1['@attributes']; - - if(!is_numeric($v['name'])) - { - $v['name'] = e107::getUserClass()->getClassFromKey($v['name'], $v['name']); // convert 'admin' etc to numeric equivalent. - } - - if(($class === null && check_class($v['name'])) || (int) $class === (int) $v['name']) + $current_perms[$v['name']] = array('type' => $v['type'], 'maxupload' => $v['maxupload']); + $a_filetypes = explode(',', $v['type']); + foreach($a_filetypes as $ftype) { - $current_perms[$v['name']] = array('type' => $v['type'], 'maxupload' => $v['maxupload']); - $a_filetypes = explode(',', $v['type']); - foreach($a_filetypes as $ftype) - { - $ftype = strtolower(trim(str_replace('.', '', $ftype))); // File extension + $ftype = strtolower(trim(str_replace('.', '', $ftype))); // File extension // if(!$file_mask || in_array($ftype, $file_array)) // We can load this extension + { + if(isset($ret[$ftype])) { - if(isset($ret[$ftype])) - { - $ret[$ftype] = $this->file_size_decode($v['maxupload'], $ret[$ftype], 'gt'); // Use largest value - } - else - { - $ret[$ftype] = $this->file_size_decode($v['maxupload']); - } + $ret[$ftype] = $this->file_size_decode($v['maxupload'], $ret[$ftype], 'gt'); // Use largest value + } + else + { + $ret[$ftype] = $this->file_size_decode($v['maxupload']); } } } } - - return $ret; } - + return $ret; } + + +} diff --git a/e107_tests/tests/unit/e_jsmanagerTest.php b/e107_tests/tests/unit/e_jsmanagerTest.php index 1c95ffad74..a5e315586d 100644 --- a/e107_tests/tests/unit/e_jsmanagerTest.php +++ b/e107_tests/tests/unit/e_jsmanagerTest.php @@ -436,7 +436,7 @@ public function testAddLink() } $tp->setStaticUrl(null); - + e107::getParser()->setStaticUrl(null); } /*