diff --git a/e107_handlers/e_marketplace.php b/e107_handlers/e_marketplace.php
index 64cfc4645..6f4ff74b1 100644
--- a/e107_handlers/e_marketplace.php
+++ b/e107_handlers/e_marketplace.php
@@ -560,8 +560,8 @@ class e_marketplace_adapter_wsdl extends e_marketplace_adapter_abstract
public function __construct()
{
- e107_ini_set('soap.wsdl_cache_enabled', 0);
- e107_ini_set('soap.wsdl_cache_ttl', 0);
+ ini_set('soap.wsdl_cache_enabled', 0);
+ ini_set('soap.wsdl_cache_ttl', 0);
$options = array(
"trace" => true,
diff --git a/e107_handlers/file_class.php b/e107_handlers/file_class.php
index e71b925bd..5ae595d56 100644
--- a/e107_handlers/file_class.php
+++ b/e107_handlers/file_class.php
@@ -1,2252 +1,2479 @@
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)
- return $this;
- }
-
- /**
- * Set fileinfo mode
- * @param string $val
- * @return e_file
- */
- public function setFileInfo($val='default')
- {
- $this->finfo = $val;
- return $this;
- }
-
-
- public function setFileFilter($filter)
- {
- $this->fileFilter = $filter;
- 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)
- {
- $fullpath = $f['path'].$f['fname'];
- $newfile = preg_replace("/[^a-z0-9-\._]/", "-", strtolower($f['fname']));
- $newpath = $f['path'].$newfile;
-
- if($rename == true)
+ /**
+ * Constructor
+ */
+ function __construct()
{
-
- if(!rename($fullpath,$newpath))
+
+ $this->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)
+
+ return $this;
+ }
+
+ /**
+ * Set fileinfo mode
+ *
+ * @param string $val
+ * @return e_file
+ */
+ public function setFileInfo($val = 'default')
+ {
+
+ $this->finfo = $val;
+
+ return $this;
+ }
+
+
+ public function setFileFilter($filter)
+ {
+
+ $this->fileFilter = $filter;
+
+ 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)
+ {
+
+ $fullpath = $f['path'] . $f['fname'];
+ $newfile = preg_replace("/[^a-z0-9-\._]/", "-", strtolower($f['fname']));
+ $newpath = $f['path'] . $newfile;
+
+ if($rename == true)
{
- $f['error'] = "Couldn't rename $fullpath to $newpath";
- }
- }
-
- $f['fname'] = $newfile;
-
- return $f;
- }
-
- function setMode($mode)
- {
- $this->mode= $mode;
- }
-
- public function getErrorMessage()
- {
- return $this->error;
- }
-
-
- public function getErrorCode()
- {
- 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)
- {
- $ret = array();
- $invert = FALSE;
- if (substr($fmask,0,1) == '~')
- {
- $invert = TRUE; // Invert selection - exclude files which match selection
- $fmask = substr($fmask,1);
- }
-
- if($recurse_level < 0)
- {
- return $ret;
- }
- if(substr($path,-1) == '/')
- {
- $path = substr($path, 0, -1);
- }
-
- if(!is_dir($path) || !$handle = opendir($path))
- {
- return $ret;
- }
- if (($omit == 'standard') || ($omit == ''))
- {
- $omit = $this->fileFilter;
- }
- else
- {
- if (!is_array($omit))
- {
- $omit = array($omit);
- }
- }
-
- while (false !== ($file = readdir($handle)))
- {
- 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(($file != '.') && ($file != '..') && !in_array($file, $this->dirFilter) && !in_array($file, $omit) && ($recurse_level > 0))
+ if(!rename($fullpath, $newpath))
{
- $xx = $this->get_files($path.'/'.$file, $fmask, $omit, $recurse_level - 1);
- $ret = array_merge($ret,$xx);
+ $f['error'] = "Couldn't rename $fullpath to $newpath";
}
}
+
+ $f['fname'] = $newfile;
+
+ return $f;
+ }
+
+ function setMode($mode)
+ {
+
+ $this->mode = $mode;
+ }
+
+
+ public function getErrorMessage()
+ {
+
+ return $this->error;
+ }
+
+
+ public function getErrorCode()
+ {
+
+ 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)
+ {
+
+ $ret = array();
+ $invert = false;
+ if(substr($fmask, 0, 1) == '~')
+ {
+ $invert = true; // Invert selection - exclude files which match selection
+ $fmask = substr($fmask, 1);
+ }
+
+ if($recurse_level < 0)
+ {
+ return $ret;
+ }
+ if(substr($path, -1) == '/')
+ {
+ $path = substr($path, 0, -1);
+ }
+
+ if(!is_dir($path) || !$handle = opendir($path))
+ {
+ return $ret;
+ }
+ if(($omit == 'standard') || ($omit == ''))
+ {
+ $omit = $this->fileFilter;
+ }
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;
+ if(!is_array($omit))
+ {
+ $omit = array($omit);
+ }
+ }
- // Check against the generic file reject filter
- foreach($omit as $rmask)
+ while(false !== ($file = readdir($handle)))
+ {
+ 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(($file != '.') && ($file != '..') && !in_array($file, $this->dirFilter) && !in_array($file, $omit) && ($recurse_level > 0))
{
- if(preg_match("#".$rmask."#", $file))
- {
- $rejected = TRUE;
- $this->filesRejected[] = $file;
- break; // continue 2 may well work
- }
+ $xx = $this->get_files($path . '/' . $file, $fmask, $omit, $recurse_level - 1);
+ $ret = array_merge($ret, $xx);
}
- if($rejected == FALSE)
- {
- 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->get_file_info($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 an extension for a specific mime-type.
- * @param $mimeType
- * @return mixed|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;
- }
-
-
-
- /**
- * Collect file information
- * @param string $path_to_file
- * @param boolean $imgcheck
- * @param boolean $auto_fix_ext
- * @return array|bool
- */
- public function get_file_info($path_to_file, $imgcheck = true, $auto_fix_ext = true)
- {
- $finfo = array();
-
- if(!file_exists($path_to_file) || filesize($path_to_file) < 2) // Don't try and read 0 byte files.
- {
- return false;
- }
-
- $finfo['pathinfo'] = pathinfo($path_to_file);
-
- 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;
- }
-
- unset($other);
-
- }
-
- if($auto_fix_ext)
- {
- // Auto-Fix Files without an extensions using known mime-type.
- if(empty($finfo['pathinfo']['extension']) && !is_dir($path_to_file) && !empty($finfo['mime']))
- {
- if($ext = $this->getFileExtension($finfo['mime']))
- {
- $finfo['pathinfo']['extension'] = $ext;
-
-
- $newFile = $path_to_file . $ext;
- if(!file_exists($newFile))
- {
- if(rename($path_to_file,$newFile)===true)
- {
- $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'];
- }
-
- }
-
- $tmp = stat($path_to_file);
-
- if($tmp)
- {
-
- $finfo['fsize'] = $tmp['size'];
- $finfo['modified'] = $tmp['mtime'];
- }
-
- // associative array elements: dirname, basename, extension, filename
-
-
- $finfo['fullpath'] = $path_to_file;
- $finfo['fname'] = basename($path_to_file);
- $finfo['path'] = dirname($path_to_file).'/';
-
- if(empty($finfo['mime'])) // last resort.
- {
- switch($finfo['pathinfo']['extension'])
- {
- case "svg":
- $finfo['mime'] = 'image/svg+xml';
- break;
-
- case "mp3":
- $finfo['mime'] = 'audio/mpeg';
- break;
-
- case "ogg":
- $finfo['mime'] = 'audio/ogg';
- break;
-
- case "mp4":
- $finfo['mime'] = 'video/mp4';
- break;
-
- case "3gp":
- $finfo['mime'] = 'video/3gpp';
- break;
-
- default:
- $finfo['mime'] = 'application/'.$finfo['pathinfo']['extension'];
- }
-
- }
-
-
-
- return $finfo;
- }
-
-
- /**
- * Grab a remote file and save it in the /temp directory. requires CURL
- * @param string $remote_url
- * @param $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')
- {
- // check for cURL
- if (!function_exists('curl_init'))
- {
- if(E107_DEBUG_LEVEL > 0)
- {
- e107::getAdminLog()->addDebug('getRemoteFile() requires cURL to be installed in file_class.php');
- }
- return FALSE; // May not be installed
- }
-
- $path = ($type == 'media') ? e_MEDIA : e_TEMP;
-
- if($type == 'import')
- {
- $path = e_IMPORT;
- }
-
- $fp = fopen($path.$local_file, 'w'); // media-directory is the root.
-
- $cp = $this->initCurl($remote_url);
- curl_setopt($cp, CURLOPT_FILE, $fp);
- curl_setopt($cp, CURLOPT_TIMEOUT, 40);//FIXME Make Pref - avoids get file timeout on slow connections
-
- $buffer = curl_exec($cp);
- //FIXME addDebug curl_error output - here see #1936
-
- curl_close($cp);
- fclose($fp);
-
- return ($buffer) ? true : false;
- }
-
- /**
- * @param string $address
- * @param array|null $options
- * @return CurlHandle|false|resource
- */
- function initCurl($address, $options =null)
- {
- $cu = curl_init();
-
- $timeout = (integer) vartrue($options['timeout'], 10);
- $timeout = min($timeout, 120);
- $timeout = max($timeout, 3);
-
- $urlData = parse_url($address);
- $referer = $urlData['scheme']."://".$urlData['host'];
-
- if(empty($referer))
- {
- $referer = e_REQUEST_HTTP;
- }
-
- 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/4.0 (compatible; MSIE 5.01; Windows NT 5.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
- }
-
- 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']);
- }
-
- if(isset($options['header']) && is_array($options['header']))
- {
- curl_setopt($cu, CURLOPT_HTTPHEADER, $options['header']);
- }
-
- if(!file_exists(e_SYSTEM.'cookies.txt'))
- {
- file_put_contents(e_SYSTEM.'cookies.txt','');
- }
-
- return $cu;
-
- }
-
-
-
- /**
- * 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
- */
- function getRemoteContent($address, $options = array())
- {
- // Could do something like: if ($timeout <= 0) $timeout = $pref['get_remote_timeout']; here
-
- // $fileContents = '';
- $this->error = '';
- $this->setErrorNum(null);
-
- // $mes = e107::getMessage();
-
- $address = str_replace(array("\r", "\n", "\t"), '', $address); // May be paranoia, but streaky thought it might be a good idea
-
- $address = str_replace('&', '&', $address);
-
- // ... and there shouldn't be unprintable characters in the URL anyway
- $requireCurl = false;
-
- if(vartrue($options['decode'], false)) $address = urldecode($address);
-
- // Keep this in first position.
- if (function_exists("curl_init")) // Preferred.
- {
-
- $cu = $this->initCurl($address, $options);
-
- $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);
- return $fileContents;
- }
-
- // CURL is required, abort...
- if($requireCurl == true) return false;
-
- $timeout = 5;
-
- if (function_exists('file_get_contents') && ini_get('allow_url_fopen'))
- {
- $old_timeout = e107_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)
- {
- e107_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
- return FALSE;
- }
-
- if (ini_get("allow_url_fopen"))
- {
- $old_timeout = e107_ini_set('default_socket_timeout', $timeout);
- $remote = @fopen($address, "r");
- if (!$remote)
- {
- $this->error = "fopen: Unable to open remote XML file: ".$address;
- 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;
- return FALSE;
- }
- else
- {
- socket_set_timeout($remote, $timeout);
- fputs($remote, "GET ".urlencode($address)." HTTP/1.0\r\n\r\n");
- }
- }
- $fileContents = "";
- while (!feof($remote))
- {
- $fileContents .= fgets($remote, 4096);
- }
- fclose($remote);
- if ($old_timeout != $timeout)
- {
- if ($old_timeout !== FALSE)
- {
- e107_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();
- if(substr($path,-1) == '/')
- {
- $path = substr($path, 0, -1);
- }
-
- if(!$handle = opendir($path))
- {
- return $ret;
- }
-
- if($omit == 'standard')
- {
- $omit = array();
- }
- else
- {
- if (!is_array($omit))
- {
- $omit = array($omit);
- }
- }
- while (false !== ($file = readdir($handle)))
- {
- if(is_dir($path.'/'.$file) && ($file != '.') && ($file != '..') && !in_array($file, $this->dirFilter) && !in_array($file, $omit) && ($fmask == '' || preg_match("#".$fmask."#", $file)))
- {
- $ret[] = $file;
- }
- }
- 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))
- {
- if ($obj != '.' && $obj != '..')
- {
- if (is_dir($dir.$obj))
- {
- if (!$this->rmtree($dir.$obj))
- {
- return false;
- }
- }
- elseif (is_file($dir.$obj))
- {
- if (!unlink($dir.$obj))
- {
- return false;
- }
- }
- }
- }
-
- closedir($handle);
-
- if (!@rmdir($dir))
- {
- return false;
- }
- return true;
- }
- return false;
- }
-
- /**
- * 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 = '')
- {
-
- $source = trim($source);
- $source = strtoupper($source);
-
- list($val, $unit) = array_pad(preg_split('#(?<=\d)(?=[a-z])#i', $source), 2, '');
-
- $val = (int) $val;
-
- 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;
- }
-
- 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)
- {
- 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;
- }
- else if($size < $mb)
- {
- return round($size/$kb, $decimal)." ".CORE_LAN_KB;
- }
- else if($size < $gb)
- {
- return round($size/$mb, $decimal)." ".CORE_LAN_MB;
- }
- else if($size < $tb)
- {
- return round($size/$gb, $decimal)." ".CORE_LAN_GB;
- }
- else
- {
- return round($size/$tb, 2)." ".CORE_LAN_TB;
- }
- }
-
-
- /** 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))
- {
- $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)
- {
- if($file != '.' && $file != '..') // skip self and parent pointing directories
- {
- $fullpath = $path.'/'.$file;
- $this->chmod($fullpath, $filemode,$dirmode);
- }
- }
- closedir($dh);
- }
- else
- {
- if (is_link($path))
- {
- print "link '$path' is skipped\n";
- return;
- }
-
- if (!chmod($path, $filemode))
- {
- $filemode_str=decoct($filemode);
- print "Failed applying filemode '$filemode_str' on file '$path'\n";
- 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())
- {
-
- $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);
- }
-
- // Make destination directory
- if(!is_dir($dest))
- {
- mkdir($dest, $perm);
- }
-
- // Directory - so copy it.
- $dir = scandir($source);
- foreach($dir as $folder)
- {
- // Skip pointers
- if($folder === '.' || $folder == '..' || $folder === $filter)
- {
- continue;
- }
-
- $this->copy("$source/$folder", "$dest/$folder", $perm);
- }
-
- return true;
- }
-
-
- /**
- * File retrieval function. by Cam.
- * @param $file string actual path or {e_xxxx} path to file.
- *
- */
- function send($file)
- {
- global $e107;
-
- // $pref = e107::getPref();
- $tp = e107::getParser();
-
- $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();
- @e107_ini_set("max_execution_time", 10 * 60);
- while (ob_get_length() !== false) // destroy all ouput buffering
- {
- ob_end_clean();
- }
- @ob_implicit_flush(TRUE);
-
-
- $filename = $file;
- $file = basename($file);
- $path = realpath($filename);
- $path_downloads = realpath($DOWNLOADS_DIRECTORY);
- $path_public = realpath($FILES_DIRECTORY."public/");
-
-
- if(!strstr($path, $path_downloads) && !strstr($path,$path_public) && !strstr($path, $MEDIA_DIRECTORY) && !strstr($path, $SYSTEM_DIRECTORY))
- {
- if(E107_DEBUG_LEVEL > 0 && ADMIN)
- {
- 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();
- }
- }
- else
- {
- if (is_file($filename) && is_readable($filename) && connection_status() == 0)
- {
- $seek = 0;
- if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE"))
- {
- $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;
- header("Expires: 0");
- header("Cache-Control: max-age=30" );
- header("Content-Type: application/force-download");
- header("Content-Disposition: attachment; filename=\"{$file}\"");
- header("Content-Length: {$data_len}");
- header("Pragma: public");
- 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)
- {
- echo "file failed =".$file."
";
- echo "path =".$path."
";
- exit();
}
else
{
- header("location: ".e_BASE."index.php");
- exit();
+ // 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))
+ {
+ $rejected = true;
+ $this->filesRejected[] = $file;
+ break; // continue 2 may well work
+ }
+ }
+ if($rejected == false)
+ {
+ 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;
+ }
+ }
+ }
}
}
- }
- }
-
- /**
- * 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 bool|string
- */
- public function getUserDir($user, $create = false, $subDir = null)
- {
- $tp = e107::getParser();
-
- $baseDir = e_MEDIA.'plugins/'.e_CURRENT_PLUGIN.'/';
-
- if(!empty($subDir))
- {
- $subDir = e107::getParser()->filter($subDir,'w');
- $baseDir .= rtrim($subDir,'/').'/';
+ return $ret;
}
- if(is_numeric($user))
+
+ /**
+ * Return an extension for a specific mime-type.
+ *
+ * @param $mimeType
+ * @return mixed|null
+ */
+ function getFileExtension($mimeType)
{
- $baseDir .= ($user > 0) ? "user_". $tp->leadingZeros($user, 6) : "anon";
- }
- if($create == true && !is_dir($baseDir))
- {
- mkdir($baseDir, 0755, true); // recursively
- }
+ $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',
+ );
- $baseDir = rtrim($baseDir,'/')."/";
-
- return $baseDir;
- }
-
-
- /**
- * 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'],'/');
-
- $test = basename(str_replace(e_TEMP,"", $d['stored_filename']),'/');
-
- if($d['folder'] == 1 && $target == $test) //
+ if(isset($extensions[$mimeType]))
+ {
+ return $extensions[$mimeType];
+ }
+
+ return null;
+ }
+
+ /**
+ * 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)
+ {
+ return $this->getFileInfo($path_to_file, $imgcheck, $auto_fix_ext);
+ }
+
+ /**
+ * 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)
+ {
+
+ $finfo = array();
+
+ if(!file_exists($path_to_file) || filesize($path_to_file) < 2) // Don't try and read 0 byte files.
+ {
+ return false;
+ }
+
+ $finfo['pathinfo'] = pathinfo($path_to_file);
+ $finfo['mime'] = $this->getMime($path_to_file);
+
+ if($auto_fix_ext && $finfo['mime'] === false)
+ {
+
+ 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;
+ }
+
+ unset($other);
+
+ }
+
+ // Auto-Fix Files without an extensions using known mime-type.
+ if(empty($finfo['pathinfo']['extension']) && !is_dir($path_to_file) && !empty($finfo['mime']))
+ {
+ if($ext = $this->getFileExtension($finfo['mime']))
+ {
+ $finfo['pathinfo']['extension'] = $ext;
+
+
+ $newFile = $path_to_file . $ext;
+ if(!file_exists($newFile))
+ {
+ if(rename($path_to_file, $newFile) === true)
+ {
+ $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($tmp = stat($path_to_file))
+ {
+
+ $finfo['fsize'] = $tmp['size'];
+ $finfo['modified'] = $tmp['mtime'];
+ }
+
+ $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 $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')
+ {
+
+ // check for cURL
+ if(!function_exists('curl_init'))
{
- // $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 "";
- }
- return $target;
-
- }
- }
-
- 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())
- {
- if(empty($newFile))
- {
- $newFile = e_BACKUP.eHelper::title2sef(SITENAME)."_".date("Y-m-d-H-i-s").".zip";
- }
-
- if(is_null($filePaths))
- {
- return "No file-paths set!";
- }
-
- require_once(e_HANDLER.'pclzip.lib.php');
- $archive = new PclZip($newFile);
-
- $removePath = (!empty($options['remove_path'])) ? $options['remove_path'] : e_BASE;
-
- if ($archive->create($filePaths, PCLZIP_OPT_REMOVE_PATH, $removePath) == 0)
- {
- $error = $archive->errorInfo(true);
- e107::getAdminLog()->addError($error)->save('FILE',E_LOG_NOTICE);
- return false;
- }
- else
- {
- return $newFile;
- }
- }
-
-
- /**
- * Delete a file.
- * @param $file
- * @return bool
- */
- public function delete($file)
- {
- if(empty($file))
- {
- return false;
- }
-
- $file = e107::getParser()->replaceConstants($file);
-
- if(file_exists($file))
- {
- return unlink($file);
- }
-
- return false;
-
- }
-
-
- /**
- * Recursive Directory removal .
- *
- * @param $dir
- */
- public function removeDir($dir)
- {
- if (is_dir($dir))
- {
- $objects = scandir($dir);
- foreach ($objects as $object)
- {
- if ($object != "." && $object != "..")
- {
- if (filetype($dir."/".$object) == "dir")
- {
- $this->removeDir($dir."/".$object);
- }
- else
- {
- @unlink($dir."/".$object);
- }
- }
- }
-
- 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
- * @param string $fileinfo = '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).
- * @param string $fileinfo = 'prefix+extra_text' - indicates an attachment or file, and specifies some optional text which is prefixed to the file name
- * @param string $fileinfo = '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
- * @param string $fileinfo = '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:
- * @param $options['filetypes'] 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)
- * @param string $options['file_mask'] 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.
- * @param bool $options['extra_file_types'] - if is FALSE or undefined, rejects totally unknown file extensions (even if in $options['filetypes'] 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
- * @param int $options['final_chmod'] - 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)
- * @param int $options['max_upload_size'] - 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)
- * @param string $options['file_array_name'] - the name of the 'input' array - defaults to file_userfile[] - otherwise as set.
- * @param int $options['max_file_count'] - maximum number of files which can be uploaded - default is 'unlimited' if this is zero or not set.
- * @param bool $options['overwrite'] - if TRUE, existing file of the same name is overwritten; otherwise returns 'duplicate file' error (default FALSE)
- * @param int $options['save_to_db'] - [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;
- }
-
- return process_uploaded_files($path, $fileinfo, $options);
-
- }
-
-
- /**
- * 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)
- {
- $list = array();
-
- $ext = str_replace(",","|",$extensions);
-
- $tmp = scandir($dir);
- foreach($tmp as $v)
- {
- if($v == '.' || $v == '..')
- {
- continue;
- }
-
- if(!empty($ext) && !preg_match("/\.(".$ext.")$/i", $v))
- {
-
- continue;
- }
-
- $list[] = $v;
- }
-
- return $list ;
- }
-
-
- /**
- * @param string $folder
- * @param null $type
- * @return bool|string
- */
- public function gitPull($folder='', $type=null)
- {
- $gitPath = defset('e_GIT','git'); // addo to e107_config.php to
- $mes = e107::getMessage();
-
-
- // $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;
-
- case "theme":
- $dir = realpath(e_THEME.basename($folder));
- break;
-
- default:
- $dir = e_ROOT;
- }
-
-
-
- // $cmd1 = 'cd '.$dir;
- $cmd2 = 'cd '.$dir.'; '.$gitPath.' reset --hard'; // Remove any local changes.
- $cmd3 = 'cd '.$dir.'; '.$gitPath.' pull'; // Run Pull request
-
-
-
- $text = '';
-
-
- $mes->addDebug($cmd2);
- $mes->addDebug($cmd3);
-
- // $text = `$cmd1 2>&1`;
- $text .= `$cmd2 2>&1`;
- $text .= `$cmd3 2>&1`;
-
-
-
- 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`;
-
- // $text .= `$cmd5 2>&1`;
-
- return print_a($text,true);
-
- }
-
-
-
- /**
- * Returns true is the URL is valid and false if it is not.
- * @param $url
- * @return bool
- */
- public function isValidURL($url)
- {
- ini_set('default_socket_timeout', 1);
- $headers = get_headers($url);
- // print_a($headers);
-
- return (stripos($headers[0],"200 OK") || stripos($headers[0],"302")) ? true : 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)
- {
- $mes = e107::getMessage();
-
- chmod(e_TEMP.$localfile, 0755);
-
- $fileinfo = array();
-
- $dir = false;
-
- 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);
-
- $fileinfo = pathinfo($filename);
-
- if($fileinfo['dirname'] === '.')
- {
- $dir = $fileinfo['basename'];
- break;
- }
- elseif($fileinfo['basename'] === 'plugin.php' || $fileinfo['basename'] === 'theme.php')
- {
- $dir = $fileinfo['dirname'];
- }
-
- // $stat = $zip->statIndex( $i );
- // print_a( $stat['name'] );
+ e107::getAdminLog()->addDebug('getRemoteFile() requires cURL to be installed in file_class.php');
}
-
- $zip->extractTo(e_TEMP);
- chmod(e_TEMP.$dir, 0755);
-
- if(empty($dir) && e_DEBUG)
- {
- print_a($fileinfo);
- }
-
-
- $zip->close();
+ return false; // May not be installed
}
+ $path = ($type == 'media') ? e_MEDIA : e_TEMP;
-
-
- }
- 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);
-
- @copy(e_TEMP.$localfile, e_BACKUP.$dir.".zip"); // Make a Backup in the system folder.
-
- if($dir && is_dir($destpath.$dir))
- {
- if($overwrite === true)
+ if($type == 'import')
{
- if(file_exists(e_TEMP.$localfile))
+ $path = e_IMPORT;
+ }
+
+ $fp = fopen($path . $local_file, 'w'); // media-directory is the root.
+
+ $cp = $this->initCurl($remote_url);
+ curl_setopt($cp, CURLOPT_FILE, $fp);
+ curl_setopt($cp, CURLOPT_TIMEOUT, 40);//FIXME Make Pref - avoids get file timeout on slow connections
+
+ $buffer = curl_exec($cp);
+ //FIXME addDebug curl_error output - here see #1936
+
+ curl_close($cp);
+ fclose($fp);
+
+ return ($buffer) ? true : false;
+ }
+
+ /**
+ * @param string $address
+ * @param array|null $options
+ * @return CurlHandle|false|resource
+ */
+ function initCurl($address, $options = null)
+ {
+
+ $cu = curl_init();
+
+ $timeout = (integer) vartrue($options['timeout'], 10);
+ $timeout = min($timeout, 120);
+ $timeout = max($timeout, 3);
+
+ $urlData = parse_url($address);
+ $referer = $urlData['scheme'] . "://" . $urlData['host'];
+
+ if(empty($referer))
+ {
+ $referer = e_REQUEST_HTTP;
+ }
+
+ 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/4.0 (compatible; MSIE 5.01; Windows NT 5.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
+ }
+
+ 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']);
+ }
+
+ if(isset($options['header']) && is_array($options['header']))
+ {
+ curl_setopt($cu, CURLOPT_HTTPHEADER, $options['header']);
+ }
+
+ if(!file_exists(e_SYSTEM . 'cookies.txt'))
+ {
+ file_put_contents(e_SYSTEM . 'cookies.txt', '');
+ }
+
+ return $cu;
+
+ }
+
+
+ /**
+ * 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
+ */
+ function getRemoteContent($address, $options = array())
+ {
+
+ // Could do something like: if ($timeout <= 0) $timeout = $pref['get_remote_timeout']; here
+
+ // $fileContents = '';
+ $this->error = '';
+ $this->setErrorNum(null);
+
+ // $mes = e107::getMessage();
+
+ $address = str_replace(array("\r", "\n", "\t"), '', $address); // May be paranoia, but streaky thought it might be a good idea
+
+ $address = str_replace('&', '&', $address);
+
+ // ... and there shouldn't be unprintable characters in the URL anyway
+ $requireCurl = false;
+
+ if(vartrue($options['decode'], false))
+ {
+ $address = urldecode($address);
+ }
+
+ // Keep this in first position.
+ if(function_exists("curl_init")) // Preferred.
+ {
+
+ $cu = $this->initCurl($address, $options);
+
+ $fileContents = curl_exec($cu);
+ if(curl_error($cu))
{
- $time = date("YmdHi");
- if(rename($destpath.$dir, e_BACKUP.$dir."_".$time))
- {
- $mes->addSuccess(ADLAN_195);
- }
+ $errorCode = curl_errno($cu);
+ $this->setErrorNum($errorCode);
+ $this->error = "Curl error: " . $errorCode . ", " . curl_error($cu);
+
+ return false;
+ }
+ curl_close($cu);
+
+ return $fileContents;
+ }
+
+ // CURL is required, abort...
+ if($requireCurl == true)
+ {
+ return false;
+ }
+
+ $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)
+ {
+ @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
+
+ return false;
+ }
+
+ 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 false;
}
}
else
{
-
- $mes->addError("(".ucfirst($type).") Already Downloaded - ".basename($destpath).'/'.$dir);
-
- if(file_exists(e_TEMP.$localfile))
+ $old_timeout = $timeout;
+ $tmp = parse_url($address);
+ if(!$remote = fsockopen($tmp['host'], 80, $errno, $errstr, $timeout))
{
- @unlink(e_TEMP.$localfile);
+ $this->error = "Sockets: Unable to open remote XML file: " . $address;
+
+ return false;
+ }
+ else
+ {
+ socket_set_timeout($remote, $timeout);
+ fputs($remote, "GET " . urlencode($address) . " HTTP/1.0\r\n\r\n");
}
-
- $this->removeDir(e_TEMP.$dir);
- return false;
}
- }
-
- if(empty($dir))
- {
- $mes->addError("Couldn't detect the root folder in the zip."); // flush();
- @unlink(e_TEMP.$localfile);
- return false;
- }
-
- if(is_dir(e_TEMP.$dir))
- {
- $res = rename(e_TEMP.$dir,$destpath.$dir);
- if($res === false)
+ $fileContents = "";
+ while(!feof($remote))
{
- $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);
-
- return $dir;
- }
-
- return false;
- }
-
-
- /**
- * 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);
- 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)
- {
-
- 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:
- $localfile = str_replace('https://github.com/e107translations/','',$url); // 'e107-master.zip';
- $localfile = str_replace('/archive/v','-',$localfile); //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);
- }
-
- $result = $this->getRemoteFile($remotefile, $localfile);
-
- if($result === false)
- {
- return false;
- }
-
-
-
- chmod(e_TEMP.$localfile, 0755);
- require_once(e_HANDLER."pclzip.lib.php");
-
- $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
- );
-
- $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.
-
- $error = array();
- $success = array();
- $skipped = array();
-
-
-
- foreach($unarc as $k=>$v)
- {
- if($this->matchFound($v['stored_filename'],$excludeMatch) ||
- in_array($v['stored_filename'],$excludes))
+ $fileContents .= fgets($remote, 4096);
+ }
+ fclose($remote);
+ if($old_timeout != $timeout)
{
- $skipped[] = $v['stored_filename'];
- continue;
+ if($old_timeout !== false)
+ {
+ ini_set('default_socket_timeout', $old_timeout);
+ }
}
- $oldPath = $v['filename'];
- $newPath = str_replace($srch,$repl, $v['stored_filename']);
+ return $fileContents;
+ }
- if($v['folder'] ==1 && is_dir($newPath))
+
+ /**
+ * 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();
+ if(substr($path, -1) == '/')
{
- // $skipped[] = $newPath. " (already exists)";
- continue;
+ $path = substr($path, 0, -1);
}
- @mkdir(dirname($newPath), 0755, true);
- if(!rename($oldPath,$newPath))
+
+ if(!$handle = opendir($path))
{
- $error[] = $newPath;
+ return $ret;
+ }
+
+ if($omit == 'standard')
+ {
+ $omit = array();
}
else
{
- $success[] = $newPath;
+ if(!is_array($omit))
+ {
+ $omit = array($omit);
+ }
+ }
+ while(false !== ($file = readdir($handle)))
+ {
+ if(is_dir($path . '/' . $file) && ($file != '.') && ($file != '..') && !in_array($file, $this->dirFilter) && !in_array($file, $omit) && ($fmask == '' || preg_match("#" . $fmask . "#", $file)))
+ {
+ $ret[] = $file;
+ }
}
+ return $ret;
}
- return array('success'=>$success, 'error'=>$error, 'skipped'=>$skipped);
- }
-
-
-
-
- private function matchFound($file,$array)
- {
- if(empty($array))
+ /**
+ * Delete a complete directory tree
+ *
+ * @param string $dir
+ * @return boolean success
+ */
+ function rmtree($dir)
{
- return false;
- }
- foreach($array as $term)
- {
- if(strpos($file,$term)!==false)
+ if(substr($dir, -1) != '/')
{
+ $dir .= '/';
+ }
+ if($handle = opendir($dir))
+ {
+ while($obj = readdir($handle))
+ {
+ if($obj != '.' && $obj != '..')
+ {
+ if(is_dir($dir . $obj))
+ {
+ if(!$this->rmtree($dir . $obj))
+ {
+ return false;
+ }
+ }
+ elseif(is_file($dir . $obj))
+ {
+ if(!unlink($dir . $obj))
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ closedir($handle);
+
+ if(!@rmdir($dir))
+ {
+ return false;
+ }
+
return true;
}
+ return false;
}
- 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, '/\\');
-
- // Check if directory exists.
- if(!is_dir($directory))
+ /**
+ * 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 = '')
{
- // Let mkdir() recursively create directories and use the default directory permissions.
- if(($options & FILE_CREATE_DIRECTORY) && @$this->mkDir($directory, null, true))
+
+ $source = trim($source);
+ $source = strtoupper($source);
+
+ list($val, $unit) = array_pad(preg_split('#(?<=\d)(?=[a-z])#i', $source), 2, '');
+
+ $val = (int) $val;
+
+ 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;
+ }
+
+ 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)
+ {
+
+ 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;
+ }
+ }
+
+
+ /** 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))
+ {
+ $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)
+ {
+ if($file != '.' && $file != '..') // skip self and parent pointing directories
+ {
+ $fullpath = $path . '/' . $file;
+ $this->chmod($fullpath, $filemode, $dirmode);
+ }
+ }
+ closedir($dh);
+ }
+ else
+ {
+ if(is_link($path))
+ {
+ print "link '$path' is skipped\n";
+
+ return;
+ }
+
+ if(!chmod($path, $filemode))
+ {
+ $filemode_str = decoct($filemode);
+ print "Failed applying filemode '$filemode_str' on file '$path'\n";
+
+ 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())
+ {
+
+ $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);
+ }
+
+ // Make destination directory
+ if(!is_dir($dest))
+ {
+ mkdir($dest, $perm);
+ }
+
+ // Directory - so copy it.
+ $dir = scandir($source);
+ foreach($dir as $folder)
+ {
+ // Skip pointers
+ if($folder === '.' || $folder == '..' || $folder === $filter)
+ {
+ continue;
+ }
+
+ $this->copy("$source/$folder", "$dest/$folder", $perm);
+ }
+
+ return true;
+ }
+
+
+ /**
+ * File retrieval function. by Cam.
+ *
+ * @param $file string actual path or {e_xxxx} path to file.
+ *
+ */
+ function send($file)
+ {
+
+ global $e107;
+
+ // $pref = e107::getPref();
+ $tp = e107::getParser();
+
+ $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(true);
+
+
+ $filename = $file;
+ $file = basename($file);
+ $path = realpath($filename);
+ $path_downloads = realpath($DOWNLOADS_DIRECTORY);
+ $path_public = realpath($FILES_DIRECTORY . "public/");
+
+
+ if(!strstr($path, $path_downloads) && !strstr($path, $path_public) && !strstr($path, $MEDIA_DIRECTORY) && !strstr($path, $SYSTEM_DIRECTORY))
+ {
+ if(E107_DEBUG_LEVEL > 0 && ADMIN)
+ {
+ 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();
+ }
+ }
+ else
+ {
+ if(is_file($filename) && is_readable($filename) && connection_status() == 0)
+ {
+ $seek = 0;
+ if(strstr($_SERVER['HTTP_USER_AGENT'], "MSIE"))
+ {
+ $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;
+ header("Expires: 0");
+ header("Cache-Control: max-age=30");
+ header("Content-Type: application/force-download");
+ header("Content-Disposition: attachment; filename=\"{$file}\"");
+ header("Content-Length: {$data_len}");
+ header("Pragma: public");
+ 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)
+ {
+ echo "file failed =" . $file . "
";
+ echo "path =" . $path . "
";
+ exit();
+ }
+ else
+ {
+ 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 bool|string
+ */
+ public function getUserDir($user, $create = false, $subDir = null)
+ {
+
+ $tp = e107::getParser();
+
+ $baseDir = e_MEDIA . 'plugins/' . e_CURRENT_PLUGIN . '/';
+
+ 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($create == true && !is_dir($baseDir))
+ {
+ mkdir($baseDir, 0755, true); // recursively
+ }
+
+ $baseDir = rtrim($baseDir, '/') . "/";
+
+ return $baseDir;
+ }
+
+
+ /**
+ * 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'], '/');
+
+ $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(E107_DEBUG_LEVEL > 0)
+ {
+ e107::getMessage()->addDebug($text);
+ // echo "";
+ }
+
+ return $target;
+
+ }
+ }
+
+ 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())
+ {
+
+ if(empty($newFile))
+ {
+ $newFile = e_BACKUP . eHelper::title2sef(SITENAME) . "_" . date("Y-m-d-H-i-s") . ".zip";
+ }
+
+ if(is_null($filePaths))
+ {
+ return "No file-paths set!";
+ }
+
+ require_once(e_HANDLER . 'pclzip.lib.php');
+ $archive = new PclZip($newFile);
+
+ $removePath = (!empty($options['remove_path'])) ? $options['remove_path'] : e_BASE;
+
+ if($archive->create($filePaths, PCLZIP_OPT_REMOVE_PATH, $removePath) == 0)
+ {
+ $error = $archive->errorInfo(true);
+ e107::getAdminLog()->addError($error)->save('FILE', E_LOG_NOTICE);
+
+ return false;
+ }
+ else
+ {
+ return $newFile;
+ }
+ }
+
+
+ /**
+ * Delete a file.
+ *
+ * @param $file
+ * @return bool
+ */
+ public function delete($file)
+ {
+
+ if(empty($file))
+ {
+ return false;
+ }
+
+ $file = e107::getParser()->replaceConstants($file);
+
+ if(file_exists($file))
+ {
+ return unlink($file);
+ }
+
+ return false;
+
+ }
+
+
+ /**
+ * Recursive Directory removal .
+ *
+ * @param $dir
+ */
+ public function removeDir($dir)
+ {
+
+ if(is_dir($dir))
+ {
+ $objects = scandir($dir);
+ foreach($objects as $object)
+ {
+ if($object != "." && $object != "..")
+ {
+ if(filetype($dir . "/" . $object) == "dir")
+ {
+ $this->removeDir($dir . "/" . $object);
+ }
+ else
+ {
+ @unlink($dir . "/" . $object);
+ }
+ }
+ }
+
+ 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
+ * @param string $fileinfo = '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).
+ * @param string $fileinfo = 'prefix+extra_text' - indicates an attachment or file, and specifies some optional text which is prefixed to the file name
+ * @param string $fileinfo = '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
+ * @param string $fileinfo = '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:
+ * @param $options ['filetypes'] 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)
+ * @param string $options ['file_mask'] 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.
+ * @param bool $options ['extra_file_types'] - if is FALSE or undefined, rejects totally unknown file extensions (even if in $options['filetypes'] 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
+ * @param int $options ['final_chmod'] - 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)
+ * @param int $options ['max_upload_size'] - 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)
+ * @param string $options ['file_array_name'] - the name of the 'input' array - defaults to file_userfile[] - otherwise as set.
+ * @param int $options ['max_file_count'] - maximum number of files which can be uploaded - default is 'unlimited' if this is zero or not set.
+ * @param bool $options ['overwrite'] - if TRUE, existing file of the same name is overwritten; otherwise returns 'duplicate file' error (default FALSE)
+ * @param int $options ['save_to_db'] - [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;
+ }
+
+ return process_uploaded_files($path, $fileinfo, $options);
+
+ }
+
+
+ /**
+ * 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)
+ {
+
+ $list = array();
+
+ $ext = str_replace(",", "|", $extensions);
+
+ $tmp = scandir($dir);
+ foreach($tmp as $v)
+ {
+ if($v == '.' || $v == '..')
+ {
+ continue;
+ }
+
+ if(!empty($ext) && !preg_match("/\.(" . $ext . ")$/i", $v))
+ {
+
+ continue;
+ }
+
+ $list[] = $v;
+ }
+
+ return $list;
+ }
+
+
+ /**
+ * @param string $folder
+ * @param null $type
+ * @return bool|string
+ */
+ public function gitPull($folder = '', $type = null)
+ {
+
+ $gitPath = defset('e_GIT', 'git'); // addo to e107_config.php to
+ $mes = e107::getMessage();
+
+
+ // $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;
+
+ case "theme":
+ $dir = realpath(e_THEME . basename($folder));
+ break;
+
+ default:
+ $dir = e_ROOT;
+ }
+
+
+ // $cmd1 = 'cd '.$dir;
+ $cmd2 = 'cd ' . $dir . '; ' . $gitPath . ' reset --hard'; // Remove any local changes.
+ $cmd3 = 'cd ' . $dir . '; ' . $gitPath . ' pull'; // Run Pull request
+
+
+ $text = '';
+
+
+ $mes->addDebug($cmd2);
+ $mes->addDebug($cmd3);
+
+ // $text = `$cmd1 2>&1`;
+ $text .= `$cmd2 2>&1`;
+ $text .= `$cmd3 2>&1`;
+
+
+ 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`;
+
+ // $text .= `$cmd5 2>&1`;
+
+ return print_a($text, true);
+
+ }
+
+
+ /**
+ * Returns true is the URL is valid and false if it is not.
+ *
+ * @param $url
+ * @return bool
+ */
+ public function isValidURL($url)
+ {
+
+ ini_set('default_socket_timeout', 1);
+ $headers = get_headers($url);
+
+ // print_a($headers);
+
+ return (stripos($headers[0], "200 OK") || stripos($headers[0], "302")) ? true : 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)
+ {
+
+ $mes = e107::getMessage();
+
+ chmod(e_TEMP . $localfile, 0755);
+
+ $fileinfo = array();
+
+ $dir = false;
+
+ 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);
+
+ $fileinfo = pathinfo($filename);
+
+ if($fileinfo['dirname'] === '.')
+ {
+ $dir = $fileinfo['basename'];
+ break;
+ }
+ elseif($fileinfo['basename'] === 'plugin.php' || $fileinfo['basename'] === 'theme.php')
+ {
+ $dir = $fileinfo['dirname'];
+ }
+
+ // $stat = $zip->statIndex( $i );
+ // print_a( $stat['name'] );
+ }
+
+
+ $zip->extractTo(e_TEMP);
+ chmod(e_TEMP . $dir, 0755);
+
+ if(empty($dir) && 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);
+ }
+
+
+ $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.
+
+ if($dir && is_dir($destpath . $dir))
+ {
+ if($overwrite === true)
+ {
+ if(file_exists(e_TEMP . $localfile))
+ {
+ $time = date("YmdHi");
+ if(rename($destpath . $dir, e_BACKUP . $dir . "_" . $time))
+ {
+ $mes->addSuccess(ADLAN_195);
+ }
+ }
+ }
+ else
+ {
+
+ $mes->addError("(" . ucfirst($type) . ") Already Downloaded - " . basename($destpath) . '/' . $dir);
+
+ if(file_exists(e_TEMP . $localfile))
+ {
+ @unlink(e_TEMP . $localfile);
+ }
+
+ $this->removeDir(e_TEMP . $dir);
+
+ return false;
+ }
+ }
+
+ if(empty($dir))
+ {
+ $mes->addError("Couldn't detect the root folder in the zip."); // flush();
+ @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);
+
+ return $dir;
+ }
+
+ return false;
+ }
+
+
+ /**
+ * 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);
+
+ 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)
+ {
+
+ 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:
+ $localfile = str_replace('https://github.com/e107translations/', '', $url); // 'e107-master.zip';
+ $localfile = str_replace('/archive/v', '-', $localfile); //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);
+ }
+
+ $result = $this->getRemoteFile($remotefile, $localfile);
+
+ if($result === false)
+ {
+ return false;
+ }
+
+
+ chmod(e_TEMP . $localfile, 0755);
+ require_once(e_HANDLER . "pclzip.lib.php");
+
+ $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
+ );
+
+ $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.
+
+ $error = array();
+ $success = array();
+ $skipped = array();
+
+
+ foreach($unarc as $k => $v)
+ {
+ 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']);
+
+ 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);
+ }
+
+
+ private function matchFound($file, $array)
+ {
+
+ if(empty($array))
+ {
+ return false;
+ }
+
+ foreach($array as $term)
+ {
+ if(strpos($file, $term) !== false)
+ {
+ 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, '/\\');
+
+ // 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;
+ }
+
+ // The directory exists, so check to see if it is writable.
+ $writable = is_writable($directory);
+
+ if(!$writable && ($options & FILE_MODIFY_PERMISSIONS))
{
return $this->_chMod($directory);
}
- return false;
+ return $writable;
}
- // The directory exists, so check to see if it is writable.
- $writable = is_writable($directory);
-
- if(!$writable && ($options & FILE_MODIFY_PERMISSIONS))
+ /**
+ * (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)
{
- return $this->_chMod($directory);
- }
- return $writable;
- }
-
- /**
- * (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)
- {
- if(!isset($mode))
- {
- if(is_dir($path))
+ if(!isset($mode))
{
- $mode = 0775;
- }
- else
- {
- $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)
- {
- if(!isset($mode))
- {
- $mode = 0775;
- }
-
- 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);
-
- $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);
-
- if($tstr === false)
- {
- $this->setErrorNum(2); // If can't read file, not much use carrying on!
- return false;
- }
-
- $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) && strpos($tstr, '') !== false) // Bit more tricky - can sometimes be OK
- {
- if(stripos($tstr, 'setErrorNum(7);
- 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)
+ if(is_dir($path))
{
- $this->setErrorNum(4); // exif_imagetype didn't recognize the image mime
- return false;
+ $mode = 0775;
}
+ else
+ {
+ $mode = 0664;
+ }
+ }
- // 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':
-
- 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;
-
- default: // Unknown file type.
-
- $this->setErrorNum(8);
- return false;
- }
-
- return true; // Accepted here
- }
-
-
- /**
- * New in v2.1.9
- * Check filename or path against filetypes.xml
- *
- * @param $file - real path to file.
- * @param string $targetFile
- * @return boolean
- */
- public function isAllowedType($file,$targetFile='')
- {
- if(empty($targetFile))
- {
- $targetFile = $file;
- }
-
- $ext = pathinfo($targetFile, PATHINFO_EXTENSION);
-
- $types = $this->getAllowedFileTypes();
-
- if(isset($types[$ext]))
- {
- $maxSize = $types[$ext] * 1024;
- $fileSize = filesize($file);
-
- // echo "\nisAllowedType(".basename($file).") ".$fileSize ." / ".$maxSize;
-
- if($fileSize <= $maxSize)
+ if(@chmod($path, $mode))
{
return true;
}
+ return false;
}
- return 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|false
- */
- 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'),
- );
-
- $ret = image_type_to_mime_type(exif_imagetype($filename));
-
- if($extended)
+ /**
+ * 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)
{
- 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 $file_mask - comma-separated list of allowed file types - only those specified in both $file_mask and $def_file are returned
- * @return array - where key is the file type (extension); value is max upload size
- */
- public function getAllowedFileTypes($file_mask = '')
- {
- $ret = array();
- $file_array = array();
-
- if ($file_mask)
- {
- $file_array = explode(',', $file_mask);
- foreach ($file_array as $k=>$f)
+ if(!isset($mode))
{
- $file_array[$k] = trim($f);
+ $mode = 0775;
+ }
+
+ if(!isset($context))
+ {
+ return mkdir($path, $mode, $recursive);
+ }
+ else
+ {
+ return mkdir($path, $mode, $recursive, $context);
}
}
- if(!is_readable(e_SYSTEM."filetypes.xml"))
+
+ /**
+ * @param int|null $int
+ */
+ private function setErrorNum($int)
{
- return array();
+
+ $this->errornum = $int;
}
- $xml = e107::getXml();
- $xml->setOptArrayTags('class'); // class tag should be always array
- $temp_vars = $xml->loadXMLfile(e_SYSTEM."filetypes.xml", 'filetypes');
- if ($temp_vars === false)
+ /**
+ * 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 '";
- return $ret;
- }
- foreach ($temp_vars['class'] as $v1)
- {
- $v = $v1['@attributes'];
- if (check_class($v['name']))
+ if(empty($target_name)) // no temp file, just use the filename.
{
- $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
+ $target_name = $filename;
+ }
- if (!$file_mask || in_array($ftype, $file_array)) // We can load this 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);
+
+ // 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!
+
+ return false;
+ }
+
+ $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) && strpos($tstr, '') !== false) // Bit more tricky - can sometimes be OK
+ {
+ if(stripos($tstr, 'setErrorNum(7);
+
+ 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)
{
- if (isset($ret[$ftype]))
+ $this->setErrorNum(4); // exif_imagetype didn't recognize the image mime
+
+ 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;
+
+ 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':
+
+ 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;
+
+ default: // Unknown file type.
+
+ $this->setErrorNum(8);
+
+ return false;
+ }
+
+ return true; // Accepted here
+ }
+
+
+ /**
+ * New in v2.1.9
+ * Check filename or path against filetypes.xml
+ *
+ * @param $file - real path to file.
+ * @param string $targetFile
+ * @return boolean
+ */
+ public function isAllowedType($file, $targetFile = '')
+ {
+
+ if(empty($targetFile))
+ {
+ $targetFile = $file;
+ }
+
+ $ext = pathinfo($targetFile, PATHINFO_EXTENSION);
+
+ $types = $this->getAllowedFileTypes();
+
+ if(isset($types[$ext]))
+ {
+ $maxSize = $types[$ext] * 1024;
+ $fileSize = filesize($file);
+
+ // echo "\nisAllowedType(".basename($file).") ".$fileSize ." / ".$maxSize;
+
+ if($fileSize <= $maxSize)
+ {
+ return true;
+ }
+
+ }
+
+ return false;
+
+ }
+
+ 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 the mime-type based on the file's extension.
+ * @param string $filename
+ * @return string
+ */
+ public function getMime($filename)
+ {
+ $filename = basename($filename);
+
+ $tmp = explode('.', $filename);
+
+ if(count($tmp) < 2) // no extension.
+ {
+ return false;
+ }
+
+ $ext = strtolower(end($tmp));
+
+ $types = $this->getMimeTypes();
+
+ 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|false
+ */
+ 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'),
+ );
+
+ $ret = image_type_to_mime_type(exif_imagetype($filename));
+
+ 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 $file_mask - comma-separated list of allowed file types - only those specified in both $file_mask and $def_file are returned
+ * @return array - where key is the file type (extension); value is max upload size
+ */
+ public function getAllowedFileTypes($file_mask = '')
+ {
+
+ $ret = array();
+ $file_array = array();
+
+ if($file_mask)
+ {
+ $file_array = explode(',', $file_mask);
+ foreach($file_array as $k => $f)
+ {
+ $file_array[$k] = trim($f);
+ }
+ }
+
+ if(!is_readable(e_SYSTEM . "filetypes.xml"))
+ {
+ return array();
+ }
+
+ $xml = e107::getXml();
+ $xml->setOptArrayTags('class'); // class tag should be always array
+ $temp_vars = $xml->loadXMLfile(e_SYSTEM . "filetypes.xml", 'filetypes');
+
+ if($temp_vars === false)
+ {
+ echo "Error reading filetypes.xml
";
+
+ return $ret;
+ }
+
+ foreach($temp_vars['class'] as $v1)
+ {
+ $v = $v1['@attributes'];
+ if(check_class($v['name']))
+ {
+ $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
+
+ if(!$file_mask || in_array($ftype, $file_array)) // We can load this extension
{
- $ret[$ftype] = $this->file_size_decode($v['maxupload'], $ret[$ftype], 'gt'); // Use largest value
- }
- else
- {
- $ret[$ftype] = $this->file_size_decode($v['maxupload']);
+ 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']);
+ }
}
}
}
}
+
+ return $ret;
}
- return $ret;
+
}
-
-
-
-}
diff --git a/e107_handlers/language_class.php b/e107_handlers/language_class.php
index cfad9ff64..4acb838f2 100644
--- a/e107_handlers/language_class.php
+++ b/e107_handlers/language_class.php
@@ -525,7 +525,7 @@ class language{
{
$detect_language = (e_SUBDOMAIN) ? $this->isValid(e_SUBDOMAIN) : $pref['sitelanguage'];
// Done in session handler now, based on MULTILANG_SUBDOMAIN value
- //e107_ini_set("session.cookie_domain", ".".e_DOMAIN); // Must be before session_start()
+ //ini_set("session.cookie_domain", ".".e_DOMAIN); // Must be before session_start()
$this->_cookie_domain = ".".e_DOMAIN;
define('MULTILANG_SUBDOMAIN',true);
}
@@ -558,7 +558,7 @@ class language{
}
// Done in session handler now
- // e107_ini_set("session.cookie_path", e_HTTP);
+ // ini_set("session.cookie_path", e_HTTP);
$this->detect = $detect_language;
return $detect_language;
diff --git a/e107_plugins/gsitemap/admin_config.php b/e107_plugins/gsitemap/admin_config.php
index d8de7df10..f9cc51cab 100644
--- a/e107_plugins/gsitemap/admin_config.php
+++ b/e107_plugins/gsitemap/admin_config.php
@@ -542,7 +542,7 @@ class gsitemap
'gsitemap_id' => 0,
'gsitemap_name' => $tp->toDB($name),
'gsitemap_url' => $tp->toDB($url),
- 'gsitemap_table' => $tp->toDB($id),
+ 'gsitemap_table' => $tp->toDB($table),
'gsitemap_table_id' => (int) $id,
'gsitemap_lastmod' => time(),
'gsitemap_freq' => $_POST['import_freq'],
diff --git a/e107_plugins/pm/pm_class.php b/e107_plugins/pm/pm_class.php
index b6eaf1b6b..181eae5a7 100755
--- a/e107_plugins/pm/pm_class.php
+++ b/e107_plugins/pm/pm_class.php
@@ -850,7 +850,7 @@ class private_message
@set_time_limit(10 * 60);
- @e107_ini_set("max_execution_time", 10 * 60);
+ @ini_set("max_execution_time", 10 * 60);
while (@ob_end_clean()); // kill all output buffering else it eats server resources
if (connection_status() == 0)
{
diff --git a/e107_tests/tests/unit/e_fileTest.php b/e107_tests/tests/unit/e_fileTest.php
index 801429ca4..ac1419f4b 100644
--- a/e107_tests/tests/unit/e_fileTest.php
+++ b/e107_tests/tests/unit/e_fileTest.php
@@ -88,6 +88,25 @@ class e_fileTest extends \Codeception\Test\Unit
}
+
+ public function testGetMime()
+ {
+ $test = array(
+ array('path'=> 'somefile', 'expected' => false), // no extension
+ array('path'=> 'somefile.bla', 'expected' => 'application/octet-stream'), // unknown
+ array('path'=> "{e_PLUGIN}filetypes.xml", 'expected' => 'application/xml'),
+ array('path'=> "gallery/images/butterfly.jpg", 'expected' => 'image/jpeg'),
+ array('path'=> "image.webp", 'expected' => 'image/webp'),
+ );
+
+ foreach($test as $var)
+ {
+ $actual = $this->fl->getMime($var['path']);
+
+ $this->assertSame($var['expected'], $actual);
+ }
+ }
+
public function testIsAllowedType()
{
@@ -235,25 +254,49 @@ class e_fileTest extends \Codeception\Test\Unit
}*/
- public function testGet_file_info()
+ public function testGetFileInfo()
{
$tests = array(
- 0 => array('input' => "e107_web/lib/font-awesome/4.7.0/fonts/fontawesome-webfont.svg", 'expected'=>'image/svg+xml'),
- 1 => array('input' => "e107_plugins/gallery/images/beach.webp", 'expected'=>'image/webp'),
- 2 => array('input' => "e107_tests/tests/_data/fileTest/corrupted_image.webp", 'expected'=>false),
+ 0 => array(
+ 'input' => "e107_web/lib/font-awesome/4.7.0/fonts/fontawesome-webfont.svg",
+ 'imgchk' => false,
+ 'expected' => ['mime'=>'image/svg+xml']
+ ),
+ 1 => array(
+ 'input' => "e107_plugins/gallery/images/beach.webp",
+ 'imgchk' => true,
+ 'expected' => ['mime'=>'image/webp', 'img-width'=>1920, 'img-height'=>1440]
+ ),
+ 2 => array(
+ 'input' => "e107_tests/tests/_data/fileTest/corrupted_image.webp",
+ 'imgchk' => false,
+ 'expected' => ['mime' => false]
+ ),
+ 3 => array(
+ 'input' => "none-existent-file.png",
+ 'imgchk' => false,
+ 'expected' => ['mime' => false]
+ ),
);
foreach($tests as $item)
{
$path = APP_PATH.'/'.$item['input'];
- $ret = $this->fl->get_file_info($path);
+ $ret = $this->fl->getFileInfo($path);
if($ret === false)
{
$ret = array('mime'=>false);
}
- $this->assertEquals($item['expected'], $ret['mime']);
+var_dump($ret);
+ $this->assertEquals($item['expected']['mime'], $ret['mime']);
+
+ if($item['imgchk'])
+ {
+ $this->assertEquals($item['expected']['img-width'], $ret['img-width']);
+ $this->assertEquals($item['expected']['img-height'], $ret['img-height']);
+ }
}
}
@@ -262,12 +305,84 @@ class e_fileTest extends \Codeception\Test\Unit
{
}
-
+*/
public function testGetFileExtension()
{
+ $test = 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',
+ );
+ foreach($test as $mime=>$ext)
+ {
+ $actual = $this->fl->getFileExtension($mime);
+
+ $this->assertSame($ext, $actual);
+ }
}
-
+/*
public function testRmtree()
{
diff --git a/e107_tests/tests/unit/e_parseTest.php b/e107_tests/tests/unit/e_parseTest.php
index 25e22730d..b9245ba5d 100644
--- a/e107_tests/tests/unit/e_parseTest.php
+++ b/e107_tests/tests/unit/e_parseTest.php
@@ -997,9 +997,10 @@ while($row = $sql->fetch())
';
- $tempDir = str_replace(['C:','\\'],['','/'], sys_get_temp_dir()).'/'; // FIXME
+ // $tempDir = str_replace(['C:','\\'],['','/'], sys_get_temp_dir()).'/'; // FIXME
+ $result6 = preg_replace('/"([^"]*)thumb.php/','"thumb.php', $result6);
- $result6 = str_replace($tempDir, '', $result6);
+ // $result6 = str_replace($tempDir, '', $result6);
$this->assertSame($expected,$result6);
$this->tp->setConvertToWebP(false);