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. */ 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) { if(!rename($fullpath,$newpath)) { $f['error'] = "Couldn't rename $fullpath to $newpath"; } } $f['fname'] = $newfile; return $f; } function setMode($mode) { $this->mode= $mode; } /** * 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)) { $xx = $this->get_files($path.'/'.$file, $fmask, $omit, $recurse_level - 1); $ret = array_merge($ret,$xx); } } else { // Now check against standard reject list and caller-specified list if (($fmask == '') || ($invert != preg_match("#".$fmask."#", $file))) { // File passes caller's filter here $rejected = FALSE; // Check against the generic file reject filter foreach($omit as $rmask) { if(preg_match("#".$rmask."#", $file)) { $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->get_file_info($path."/".$file, ('file' != $this->finfo)); // -> 'all' & 'image' } $finfo['path'] = $path."/"; // important: leave this slash here and update other file instead. $finfo['fname'] = $file; $ret[] = $finfo; break; } } } } } return $ret; } /** * Collect file information * @param string $path_to_file * @param boolean $imgcheck * @return array */ function get_file_info($path_to_file, $imgcheck = true) { $finfo = array(); if(filesize($path_to_file) < 2) // Don't try and read 0 byte files. { return false; } if($imgcheck && ($tmp = getimagesize($path_to_file))) { $finfo['img-width'] = $tmp[0]; $finfo['img-height'] = $tmp[1]; $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['pathinfo'] = pathinfo($path_to_file); $finfo['mime'] = vartrue($finfo['mime'],'application/'.$finfo['pathinfo']['extension']); return $finfo; } /** * Grab a remote file and save it in the /temp directory. requires CURL * * @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; $fp = fopen($path.$local_file, 'w'); // media-directory is the root. $cp = curl_init($remote_url); curl_setopt($cp, CURLOPT_FILE, $fp); curl_setopt($cp, CURLOPT_REFERER, e_REQUEST_HTTP); curl_setopt($cp, CURLOPT_HEADER, 0); curl_setopt($cp, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)"); curl_setopt($cp, CURLOPT_COOKIEFILE, e_SYSTEM.'cookies.txt'); $buffer = curl_exec($cp); curl_close($cp); fclose($fp); return ($buffer) ? true : false; } /** * 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 $postData = varset($options['post'], null); $timeout = (integer) vartrue($options['timeout'], 10); $timeout = min($timeout, 120); $timeout = max($timeout, 3); $fileContents = ''; $this->error = ''; $this->errornum = null; $mes = e107::getMessage(); $address = str_replace(array("\r", "\n", "\t"), '', $address); // May be paranoia, but streaky thought it might be a good idea // ... 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 = curl_init(); curl_setopt($cu, CURLOPT_URL, $address); curl_setopt($cu, CURLOPT_RETURNTRANSFER, true); curl_setopt($cu, CURLOPT_HEADER, 0); curl_setopt($cu, CURLOPT_TIMEOUT, $timeout); curl_setopt($cu, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($cu, CURLOPT_REFERER, e_REQUEST_HTTP); curl_setopt($cu, CURLOPT_FOLLOWLOCATION, 0); 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($postData !== null) { 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, $postData); $requireCurl = true; } if(isset($options['header']) && is_array($options['header'])) { curl_setopt($cu, CURLOPT_HTTPHEADER, $options['header']); $requireCurl = true; } if(!file_exists(e_SYSTEM.'cookies.txt')) { file_put_contents(e_SYSTEM.'cookies.txt',''); } $fileContents = curl_exec($cu); if (curl_error($cu)) { $this->errornum = curl_errno($cu); $this->error = "Curl error: ".$this->errornum.", ".curl_error($cu); return FALSE; } curl_close($cu); return $fileContents; } // CURL is required, abort... if($requireCurl == true) return false; if (function_exists('file_get_contents') && ini_get('allow_url_fopen')) { $old_timeout = e107_ini_set('default_socket_timeout', $timeout); $data = file_get_contents($address); // $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 strig $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. * 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); if (strtolower(substr($source, -1, 1)) == 'b') $source = substr($source, 0, -1); // Trim a trailing byte indicator $mult = 1; if (strlen($source) && (strtoupper(substr($source, -1, 1)) == 'B')) $source = substr($source, 0, -1); if (!$source || is_numeric($source)) { $val = $source; } else { $val = substr($source, 0, -1); switch (substr($source, -1, 1)) { case 'T': $val = $val * 1024; case 'G': $val = $val * 1024; case 'M': $val = $val * 1024; case 'K': case 'k': $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 * * @return string formatted size */ function file_size_encode($size, $retrieve = false) { 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, 2)." ".CORE_LAN_KB; } else if($size < $gb) { return round($size/$mb, 2)." ".CORE_LAN_MB; } else if($size < $tb) { return round($size/$gb, 2)." ".CORE_LAN_GB; } else { return round($size/$tb, 2)." ".CORE_LAN_TB; } } /** Recursive Chmod function. * @param string path to folder * @param string perms for files * @param string 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; } } } /** * File retrieval function. by Cam. * @param $file actual path or {e_} path to file. * */ function send($file) { global $e107; $pref = e107::getPref(); $tp = e107::getParser(); $DOWNLOADS_DIRECTORY = e_BASE.e107::getFolder('DOWNLOADS'); $FILES_DIRECTORY = e_BASE.e107::getFolder('FILES'); $MEDIA_DIRECTORY = realpath(e_MEDIA); // could be image, file or other type. $file = $tp->replaceConstants($file); @set_time_limit(10 * 60); @session_write_close(); @e107_ini_set("max_execution_time", 10 * 60); while (@ob_end_clean()); // kill all output buffering else it eats server resources @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)) { if(E107_DEBUG_LEVEL > 0 && ADMIN) { echo "Failed to Download ".$file."
"; echo "The file-path ".$path." didn't match with either {$path_downloads} or {$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(); } } } } /** * Runs through the zip archive array and finds the root directory. */ 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 .= "\\n test=".$test; $text .= "\\n target=".$target; if(E107_DEBUG_LEVEL > 0) { echo ""; } return $target; } } return false; } }