From fc332acf8a8ecff6cebd929a24e008648138a46d Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 7 Aug 2013 16:38:57 +0200 Subject: [PATCH 1/6] split of mimetype detection code from OC_Helper, adding the option for apps to register additional mimetype mappings --- lib/files/type/detection.php | 121 ++++++++++ lib/helper.php | 430 ++++++++++++++++------------------- 2 files changed, 315 insertions(+), 236 deletions(-) create mode 100644 lib/files/type/detection.php diff --git a/lib/files/type/detection.php b/lib/files/type/detection.php new file mode 100644 index 0000000000..1fe49a9bc4 --- /dev/null +++ b/lib/files/type/detection.php @@ -0,0 +1,121 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Type; + +/** + * Class Detection + * + * Mimetype detection + * + * @package OC\Files\Type + */ +class Detection { + protected $mimetypes = array(); + + /** + * add an extension -> mimetype mapping + * + * @param string $extension + * @param string $mimetype + */ + public function registerType($extension, $mimetype) { + $this->mimetypes[$extension] = $mimetype; + } + + /** + * add an array of extension -> mimetype mappings + * + * @param array $types + */ + public function registerTypeArray($types) { + $this->mimetypes = array_merge($this->mimetypes, $types); + } + + /** + * detect mimetype only based on filename, content of file is not used + * + * @param string $path + * @return string + */ + public function detectPath($path) { + if (strpos($path, '.')) { + //try to guess the type by the file extension + $extension = strtolower(strrchr(basename($path), ".")); + $extension = substr($extension, 1); //remove leading . + return (isset($this->mimetypes[$extension])) ? $this->mimetypes[$extension] : 'application/octet-stream'; + } else { + return 'application/octet-stream'; + } + } + + /** + * detect mimetype based on both filename and content + * + * @param string $path + * @return string + */ + public function detect($path) { + $isWrapped = (strpos($path, '://') !== false) and (substr($path, 0, 7) == 'file://'); + + if (@is_dir($path)) { + // directories are easy + return "httpd/unix-directory"; + } + + $mimeType = $this->detectPath($path); + + if ($mimeType == 'application/octet-stream' and function_exists('finfo_open') + and function_exists('finfo_file') and $finfo = finfo_open(FILEINFO_MIME) + ) { + $info = @strtolower(finfo_file($finfo, $path)); + if ($info) { + $mimeType = substr($info, 0, strpos($info, ';')); + } + finfo_close($finfo); + } + if (!$isWrapped and $mimeType == 'application/octet-stream' && function_exists("mime_content_type")) { + // use mime magic extension if available + $mimeType = mime_content_type($path); + } + if (!$isWrapped and $mimeType == 'application/octet-stream' && \OC_Helper::canExecute("file")) { + // it looks like we have a 'file' command, + // lets see if it does have mime support + $path = escapeshellarg($path); + $fp = popen("file -b --mime-type $path 2>/dev/null", "r"); + $reply = fgets($fp); + pclose($fp); + + //trim the newline + $mimeType = trim($reply); + + } + return $mimeType; + } + + /** + * detect mimetype based on the content of a string + * + * @param string $data + * @return string + */ + public function detectString($data) { + if (function_exists('finfo_open') and function_exists('finfo_file')) { + $finfo = finfo_open(FILEINFO_MIME); + return finfo_buffer($finfo, $data); + } else { + $tmpFile = \OC_Helper::tmpFile(); + $fh = fopen($tmpFile, 'wb'); + fwrite($fh, $data, 8024); + fclose($fh); + $mime = $this->detect($tmpFile); + unset($tmpFile); + return $mime; + } + } +} diff --git a/lib/helper.php b/lib/helper.php index ca508e1d93..801f06352d 100644 --- a/lib/helper.php +++ b/lib/helper.php @@ -25,9 +25,9 @@ * Collection of useful functions */ class OC_Helper { - private static $mimetypes=array(); - private static $tmpFiles=array(); + private static $tmpFiles = array(); private static $mimetypeIcons = array(); + private static $mimetypeDetector; /** * @brief Creates an url using a defined route @@ -39,7 +39,7 @@ class OC_Helper { * * Returns a url to the given app and file. */ - public static function linkToRoute( $route, $parameters = array() ) { + public static function linkToRoute($route, $parameters = array()) { $urlLinkTo = OC::getRouter()->generate($route, $parameters); return $urlLinkTo; } @@ -49,38 +49,35 @@ class OC_Helper { * @param string $app app * @param string $file file * @param array $args array with param=>value, will be appended to the returned url - * The value of $args will be urlencoded + * The value of $args will be urlencoded * @return string the url * * Returns a url to the given app and file. */ - public static function linkTo( $app, $file, $args = array() ) { - if( $app != '' ) { + public static function linkTo($app, $file, $args = array()) { + if ($app != '') { $app_path = OC_App::getAppPath($app); // Check if the app is in the app folder - if( $app_path && file_exists( $app_path.'/'.$file )) { - if(substr($file, -3) == 'php' || substr($file, -3) == 'css') { - $urlLinkTo = OC::$WEBROOT . '/index.php/apps/' . $app; - $urlLinkTo .= ($file!='index.php') ? '/' . $file : ''; - }else{ - $urlLinkTo = OC_App::getAppWebPath($app) . '/' . $file; + if ($app_path && file_exists($app_path . '/' . $file)) { + if (substr($file, -3) == 'php' || substr($file, -3) == 'css') { + $urlLinkTo = OC::$WEBROOT . '/index.php/apps/' . $app; + $urlLinkTo .= ($file != 'index.php') ? '/' . $file : ''; + } else { + $urlLinkTo = OC_App::getAppWebPath($app) . '/' . $file; } + } else { + $urlLinkTo = OC::$WEBROOT . '/' . $app . '/' . $file; } - else{ - $urlLinkTo = OC::$WEBROOT . '/' . $app . '/' . $file; - } - } - else{ - if( file_exists( OC::$SERVERROOT . '/core/'. $file )) { - $urlLinkTo = OC::$WEBROOT . '/core/'.$file; - } - else{ - $urlLinkTo = OC::$WEBROOT . '/'.$file; + } else { + if (file_exists(OC::$SERVERROOT . '/core/' . $file)) { + $urlLinkTo = OC::$WEBROOT . '/core/' . $file; + } else { + $urlLinkTo = OC::$WEBROOT . '/' . $file; } } if ($args && $query = http_build_query($args, '', '&')) { - $urlLinkTo .= '?'.$query; + $urlLinkTo .= '?' . $query; } return $urlLinkTo; @@ -91,13 +88,13 @@ class OC_Helper { * @param string $app app * @param string $file file * @param array $args array with param=>value, will be appended to the returned url - * The value of $args will be urlencoded + * The value of $args will be urlencoded * @return string the url * * Returns a absolute url to the given app and file. */ - public static function linkToAbsolute( $app, $file, $args = array() ) { - $urlLinkTo = self::linkTo( $app, $file, $args ); + public static function linkToAbsolute($app, $file, $args = array()) { + $urlLinkTo = self::linkTo($app, $file, $args); return self::makeURLAbsolute($urlLinkTo); } @@ -108,9 +105,8 @@ class OC_Helper { * * Returns a absolute url to the given app and file. */ - public static function makeURLAbsolute( $url ) - { - return OC_Request::serverProtocol(). '://' . OC_Request::serverHost() . $url; + public static function makeURLAbsolute($url) { + return OC_Request::serverProtocol() . '://' . OC_Request::serverHost() . $url; } /** @@ -120,8 +116,8 @@ class OC_Helper { * * Returns a url to the given service. */ - public static function linkToRemoteBase( $service ) { - return self::linkTo( '', 'remote.php') . '/' . $service; + public static function linkToRemoteBase($service) { + return self::linkTo('', 'remote.php') . '/' . $service; } /** @@ -132,9 +128,9 @@ class OC_Helper { * * Returns a absolute url to the given service. */ - public static function linkToRemote( $service, $add_slash = true ) { + public static function linkToRemote($service, $add_slash = true) { return self::makeURLAbsolute(self::linkToRemoteBase($service)) - . (($add_slash && $service[strlen($service)-1]!='/')?'/':''); + . (($add_slash && $service[strlen($service) - 1] != '/') ? '/' : ''); } /** @@ -146,8 +142,8 @@ class OC_Helper { * Returns a absolute url to the given service. */ public static function linkToPublic($service, $add_slash = false) { - return self::linkToAbsolute( '', 'public.php') . '?service=' . $service - . (($add_slash && $service[strlen($service)-1]!='/')?'/':''); + return self::linkToAbsolute('', 'public.php') . '?service=' . $service + . (($add_slash && $service[strlen($service) - 1] != '/') ? '/' : ''); } /** @@ -158,25 +154,25 @@ class OC_Helper { * * Returns the path to the image. */ - public static function imagePath( $app, $image ) { + public static function imagePath($app, $image) { // Read the selected theme from the config file $theme = OC_Util::getTheme(); // Check if the app is in the app folder - if( file_exists( OC::$SERVERROOT."/themes/$theme/apps/$app/img/$image" )) { - return OC::$WEBROOT."/themes/$theme/apps/$app/img/$image"; - }elseif( file_exists(OC_App::getAppPath($app)."/img/$image" )) { - return OC_App::getAppWebPath($app)."/img/$image"; - }elseif( !empty( $app ) and file_exists( OC::$SERVERROOT."/themes/$theme/$app/img/$image" )) { - return OC::$WEBROOT."/themes/$theme/$app/img/$image"; - }elseif( !empty( $app ) and file_exists( OC::$SERVERROOT."/$app/img/$image" )) { - return OC::$WEBROOT."/$app/img/$image"; - }elseif( file_exists( OC::$SERVERROOT."/themes/$theme/core/img/$image" )) { - return OC::$WEBROOT."/themes/$theme/core/img/$image"; - }elseif( file_exists( OC::$SERVERROOT."/core/img/$image" )) { - return OC::$WEBROOT."/core/img/$image"; - }else{ - throw new RuntimeException('image not found: image:'.$image.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT); + if (file_exists(OC::$SERVERROOT . "/themes/$theme/apps/$app/img/$image")) { + return OC::$WEBROOT . "/themes/$theme/apps/$app/img/$image"; + } elseif (file_exists(OC_App::getAppPath($app) . "/img/$image")) { + return OC_App::getAppWebPath($app) . "/img/$image"; + } elseif (!empty($app) and file_exists(OC::$SERVERROOT . "/themes/$theme/$app/img/$image")) { + return OC::$WEBROOT . "/themes/$theme/$app/img/$image"; + } elseif (!empty($app) and file_exists(OC::$SERVERROOT . "/$app/img/$image")) { + return OC::$WEBROOT . "/$app/img/$image"; + } elseif (file_exists(OC::$SERVERROOT . "/themes/$theme/core/img/$image")) { + return OC::$WEBROOT . "/themes/$theme/core/img/$image"; + } elseif (file_exists(OC::$SERVERROOT . "/core/img/$image")) { + return OC::$WEBROOT . "/core/img/$image"; + } else { + throw new RuntimeException('image not found: image:' . $image . ' webroot:' . OC::$WEBROOT . ' serverroot:' . OC::$SERVERROOT); } } @@ -197,28 +193,28 @@ class OC_Helper { } // Replace slash and backslash with a minus $icon = str_replace('/', '-', $mimetype); - $icon = str_replace( '\\', '-', $icon); + $icon = str_replace('\\', '-', $icon); // Is it a dir? if ($mimetype === 'dir') { - self::$mimetypeIcons[$mimetype] = OC::$WEBROOT.'/core/img/filetypes/folder.png'; - return OC::$WEBROOT.'/core/img/filetypes/folder.png'; + self::$mimetypeIcons[$mimetype] = OC::$WEBROOT . '/core/img/filetypes/folder.png'; + return OC::$WEBROOT . '/core/img/filetypes/folder.png'; } // Icon exists? - if (file_exists(OC::$SERVERROOT.'/core/img/filetypes/'.$icon.'.png')) { - self::$mimetypeIcons[$mimetype] = OC::$WEBROOT.'/core/img/filetypes/'.$icon.'.png'; - return OC::$WEBROOT.'/core/img/filetypes/'.$icon.'.png'; + if (file_exists(OC::$SERVERROOT . '/core/img/filetypes/' . $icon . '.png')) { + self::$mimetypeIcons[$mimetype] = OC::$WEBROOT . '/core/img/filetypes/' . $icon . '.png'; + return OC::$WEBROOT . '/core/img/filetypes/' . $icon . '.png'; } // Try only the first part of the filetype $mimePart = substr($icon, 0, strpos($icon, '-')); - if (file_exists(OC::$SERVERROOT.'/core/img/filetypes/'.$mimePart.'.png')) { - self::$mimetypeIcons[$mimetype] = OC::$WEBROOT.'/core/img/filetypes/'.$mimePart.'.png'; - return OC::$WEBROOT.'/core/img/filetypes/'.$mimePart.'.png'; + if (file_exists(OC::$SERVERROOT . '/core/img/filetypes/' . $mimePart . '.png')) { + self::$mimetypeIcons[$mimetype] = OC::$WEBROOT . '/core/img/filetypes/' . $mimePart . '.png'; + return OC::$WEBROOT . '/core/img/filetypes/' . $mimePart . '.png'; } else { - self::$mimetypeIcons[$mimetype] = OC::$WEBROOT.'/core/img/filetypes/file.png'; - return OC::$WEBROOT.'/core/img/filetypes/file.png'; + self::$mimetypeIcons[$mimetype] = OC::$WEBROOT . '/core/img/filetypes/file.png'; + return OC::$WEBROOT . '/core/img/filetypes/file.png'; } } @@ -229,25 +225,25 @@ class OC_Helper { * * Makes 2048 to 2 kB. */ - public static function humanFileSize( $bytes ) { - if( $bytes < 0 ) { + public static function humanFileSize($bytes) { + if ($bytes < 0) { $l = OC_L10N::get('lib'); return $l->t("couldn't be determined"); } - if( $bytes < 1024 ) { + if ($bytes < 1024) { return "$bytes B"; } - $bytes = round( $bytes / 1024, 1 ); - if( $bytes < 1024 ) { + $bytes = round($bytes / 1024, 1); + if ($bytes < 1024) { return "$bytes kB"; } - $bytes = round( $bytes / 1024, 1 ); - if( $bytes < 1024 ) { + $bytes = round($bytes / 1024, 1); + if ($bytes < 1024) { return "$bytes MB"; } // Wow, heavy duty for owncloud - $bytes = round( $bytes / 1024, 1 ); + $bytes = round($bytes / 1024, 1); return "$bytes GB"; } @@ -260,21 +256,21 @@ class OC_Helper { * * Inspired by: http://www.php.net/manual/en/function.filesize.php#92418 */ - public static function computerFileSize( $str ) { - $str=strtolower($str); + public static function computerFileSize($str) { + $str = strtolower($str); $bytes_array = array( 'b' => 1, 'k' => 1024, 'kb' => 1024, 'mb' => 1024 * 1024, - 'm' => 1024 * 1024, + 'm' => 1024 * 1024, 'gb' => 1024 * 1024 * 1024, - 'g' => 1024 * 1024 * 1024, + 'g' => 1024 * 1024 * 1024, 'tb' => 1024 * 1024 * 1024 * 1024, - 't' => 1024 * 1024 * 1024 * 1024, + 't' => 1024 * 1024 * 1024 * 1024, 'pb' => 1024 * 1024 * 1024 * 1024 * 1024, - 'p' => 1024 * 1024 * 1024 * 1024 * 1024, + 'p' => 1024 * 1024 * 1024 * 1024 * 1024, ); $bytes = floatval($str); @@ -299,18 +295,17 @@ class OC_Helper { return chmod($path, $filemode); $dh = opendir($path); while (($file = readdir($dh)) !== false) { - if($file != '.' && $file != '..') { - $fullpath = $path.'/'.$file; - if(is_link($fullpath)) + if ($file != '.' && $file != '..') { + $fullpath = $path . '/' . $file; + if (is_link($fullpath)) return false; - elseif(!is_dir($fullpath) && !@chmod($fullpath, $filemode)) - return false; - elseif(!self::chmodr($fullpath, $filemode)) + elseif (!is_dir($fullpath) && !@chmod($fullpath, $filemode)) + return false; elseif (!self::chmodr($fullpath, $filemode)) return false; } } closedir($dh); - if(@chmod($path, $filemode)) + if (@chmod($path, $filemode)) return true; else return false; @@ -323,8 +318,8 @@ class OC_Helper { * */ static function copyr($src, $dest) { - if(is_dir($src)) { - if(!is_dir($dest)) { + if (is_dir($src)) { + if (!is_dir($dest)) { mkdir($dest); } $files = scandir($src); @@ -333,7 +328,7 @@ class OC_Helper { self::copyr("$src/$file", "$dest/$file"); } } - }elseif(file_exists($src) && !\OC\Files\Filesystem::isFileBlacklisted($src)) { + } elseif (file_exists($src) && !\OC\Files\Filesystem::isFileBlacklisted($src)) { copy($src, $dest); } } @@ -344,105 +339,61 @@ class OC_Helper { * @return bool */ static function rmdirr($dir) { - if(is_dir($dir)) { - $files=scandir($dir); - foreach($files as $file) { + if (is_dir($dir)) { + $files = scandir($dir); + foreach ($files as $file) { if ($file != "." && $file != "..") { self::rmdirr("$dir/$file"); } } rmdir($dir); - }elseif(file_exists($dir)) { + } elseif (file_exists($dir)) { unlink($dir); } - if(file_exists($dir)) { + if (file_exists($dir)) { return false; - }else{ + } else { return true; } } + static public function getMimetypeDetector() { + if (!self::$mimetypeDetector) { + self::$mimetypeDetector = new \OC\Files\Type\Detection(); + self::$mimetypeDetector->registerTypeArray(include 'mimetypes.list.php'); + } + return self::$mimetypeDetector; + } + /** * Try to guess the mimetype based on filename * * @param string $path * @return string */ - static public function getFileNameMimeType($path){ - if(strpos($path, '.')) { - //try to guess the type by the file extension - if(!self::$mimetypes || self::$mimetypes != include 'mimetypes.list.php') { - self::$mimetypes=include 'mimetypes.list.php'; - } - $extension=strtolower(strrchr(basename($path), ".")); - $extension=substr($extension, 1);//remove leading . - return (isset(self::$mimetypes[$extension]))?self::$mimetypes[$extension]:'application/octet-stream'; - }else{ - return 'application/octet-stream'; - } + static public function getFileNameMimeType($path) { + return self::getMimetypeDetector()->detectPath($path); } /** * get the mimetype form a local file + * * @param string $path * @return string * does NOT work for ownClouds filesystem, use OC_FileSystem::getMimeType instead */ static function getMimeType($path) { - $isWrapped=(strpos($path, '://')!==false) and (substr($path, 0, 7)=='file://'); - - if (@is_dir($path)) { - // directories are easy - return "httpd/unix-directory"; - } - - $mimeType = self::getFileNameMimeType($path); - - if($mimeType=='application/octet-stream' and function_exists('finfo_open') - and function_exists('finfo_file') and $finfo=finfo_open(FILEINFO_MIME)) { - $info = @strtolower(finfo_file($finfo, $path)); - if($info) { - $mimeType=substr($info, 0, strpos($info, ';')); - } - finfo_close($finfo); - } - if (!$isWrapped and $mimeType=='application/octet-stream' && function_exists("mime_content_type")) { - // use mime magic extension if available - $mimeType = mime_content_type($path); - } - if (!$isWrapped and $mimeType=='application/octet-stream' && OC_Helper::canExecute("file")) { - // it looks like we have a 'file' command, - // lets see if it does have mime support - $path=escapeshellarg($path); - $fp = popen("file -b --mime-type $path 2>/dev/null", "r"); - $reply = fgets($fp); - pclose($fp); - - //trim the newline - $mimeType = trim($reply); - - } - return $mimeType; + return self::getMimetypeDetector()->detect($path); } /** * get the mimetype form a data string + * * @param string $data * @return string */ static function getStringMimeType($data) { - if(function_exists('finfo_open') and function_exists('finfo_file')) { - $finfo=finfo_open(FILEINFO_MIME); - return finfo_buffer($finfo, $data); - }else{ - $tmpFile=OC_Helper::tmpFile(); - $fh=fopen($tmpFile, 'wb'); - fwrite($fh, $data, 8024); - fclose($fh); - $mime=self::getMimeType($tmpFile); - unset($tmpFile); - return $mime; - } + return self::getMimetypeDetector()->detectString($data); } /** @@ -454,9 +405,9 @@ class OC_Helper { */ //FIXME: should also check for value validation (i.e. the email is an email). - public static function init_var($s, $d="") { + public static function init_var($s, $d = "") { $r = $d; - if(isset($_REQUEST[$s]) && !empty($_REQUEST[$s])) { + if (isset($_REQUEST[$s]) && !empty($_REQUEST[$s])) { $r = OC_Util::sanitizeHTML($_REQUEST[$s]); } @@ -466,12 +417,13 @@ class OC_Helper { /** * returns "checked"-attribute if request contains selected radio element * OR if radio element is the default one -- maybe? + * * @param string $s Name of radio-button element name * @param string $v Value of current radio-button element * @param string $d Value of default radio-button element */ public static function init_radio($s, $v, $d) { - if((isset($_REQUEST[$s]) && $_REQUEST[$s]==$v) || (!isset($_REQUEST[$s]) && $v == $d)) + if ((isset($_REQUEST[$s]) && $_REQUEST[$s] == $v) || (!isset($_REQUEST[$s]) && $v == $d)) print "checked=\"checked\" "; } @@ -503,17 +455,17 @@ class OC_Helper { $dirs = explode(PATH_SEPARATOR, $path); // WARNING : We have to check if open_basedir is enabled : $obd = ini_get('open_basedir'); - if($obd != "none") { + if ($obd != "none") { $obd_values = explode(PATH_SEPARATOR, $obd); - if(count($obd_values) > 0 and $obd_values[0]) { + if (count($obd_values) > 0 and $obd_values[0]) { // open_basedir is in effect ! // We need to check if the program is in one of these dirs : $dirs = $obd_values; } } - foreach($dirs as $dir) { - foreach($exts as $ext) { - if($check_fn("$dir/$name".$ext)) + foreach ($dirs as $dir) { + foreach ($exts as $ext) { + if ($check_fn("$dir/$name" . $ext)) return true; } } @@ -522,18 +474,19 @@ class OC_Helper { /** * copy the contents of one stream to another + * * @param resource $source * @param resource $target * @return int the number of bytes copied */ public static function streamCopy($source, $target) { - if(!$source or !$target) { + if (!$source or !$target) { return false; } $result = true; $count = 0; - while(!feof($source)) { - if ( ( $c = fwrite($target, fread($source, 8192)) ) === false) { + while (!feof($source)) { + if (($c = fwrite($target, fread($source, 8192))) === false) { $result = false; } else { $count += $c; @@ -544,37 +497,39 @@ class OC_Helper { /** * create a temporary file with an unique filename + * * @param string $postfix * @return string * * temporary files are automatically cleaned up after the script is finished */ - public static function tmpFile($postfix='') { - $file=get_temp_dir().'/'.md5(time().rand()).$postfix; - $fh=fopen($file, 'w'); + public static function tmpFile($postfix = '') { + $file = get_temp_dir() . '/' . md5(time() . rand()) . $postfix; + $fh = fopen($file, 'w'); fclose($fh); - self::$tmpFiles[]=$file; + self::$tmpFiles[] = $file; return $file; } /** * move a file to oc-noclean temp dir + * * @param string $filename * @return mixed * */ - public static function moveToNoClean($filename='') { + public static function moveToNoClean($filename = '') { if ($filename == '') { return false; } - $tmpDirNoClean=get_temp_dir().'/oc-noclean/'; + $tmpDirNoClean = get_temp_dir() . '/oc-noclean/'; if (!file_exists($tmpDirNoClean) || !is_dir($tmpDirNoClean)) { if (file_exists($tmpDirNoClean)) { unlink($tmpDirNoClean); } mkdir($tmpDirNoClean); } - $newname=$tmpDirNoClean.basename($filename); + $newname = $tmpDirNoClean . basename($filename); if (rename($filename, $newname)) { return $newname; } else { @@ -584,34 +539,35 @@ class OC_Helper { /** * create a temporary folder with an unique filename + * * @return string * * temporary files are automatically cleaned up after the script is finished */ public static function tmpFolder() { - $path=get_temp_dir().'/'.md5(time().rand()); + $path = get_temp_dir() . '/' . md5(time() . rand()); mkdir($path); - self::$tmpFiles[]=$path; - return $path.'/'; + self::$tmpFiles[] = $path; + return $path . '/'; } /** * remove all files created by self::tmpFile */ public static function cleanTmp() { - $leftoversFile=get_temp_dir().'/oc-not-deleted'; - if(file_exists($leftoversFile)) { - $leftovers=file($leftoversFile); - foreach($leftovers as $file) { + $leftoversFile = get_temp_dir() . '/oc-not-deleted'; + if (file_exists($leftoversFile)) { + $leftovers = file($leftoversFile); + foreach ($leftovers as $file) { self::rmdirr($file); } unlink($leftoversFile); } - foreach(self::$tmpFiles as $file) { - if(file_exists($file)) { - if(!self::rmdirr($file)) { - file_put_contents($leftoversFile, $file."\n", FILE_APPEND); + foreach (self::$tmpFiles as $file) { + if (file_exists($file)) { + if (!self::rmdirr($file)) { + file_put_contents($leftoversFile, $file . "\n", FILE_APPEND); } } } @@ -621,34 +577,34 @@ class OC_Helper { * remove all files in PHP /oc-noclean temp dir */ public static function cleanTmpNoClean() { - $tmpDirNoCleanFile=get_temp_dir().'/oc-noclean/'; - if(file_exists($tmpDirNoCleanFile)) { + $tmpDirNoCleanFile = get_temp_dir() . '/oc-noclean/'; + if (file_exists($tmpDirNoCleanFile)) { self::rmdirr($tmpDirNoCleanFile); } } /** - * Adds a suffix to the name in case the file exists - * - * @param $path - * @param $filename - * @return string - */ + * Adds a suffix to the name in case the file exists + * + * @param $path + * @param $filename + * @return string + */ public static function buildNotExistingFileName($path, $filename) { $view = \OC\Files\Filesystem::getView(); return self::buildNotExistingFileNameForView($path, $filename, $view); } /** - * Adds a suffix to the name in case the file exists - * - * @param $path - * @param $filename - * @return string - */ + * Adds a suffix to the name in case the file exists + * + * @param $path + * @param $filename + * @return string + */ public static function buildNotExistingFileNameForView($path, $filename, \OC\Files\View $view) { - if($path==='/') { - $path=''; + if ($path === '/') { + $path = ''; } if ($pos = strrpos($filename, '.')) { $name = substr($filename, 0, $pos); @@ -660,10 +616,10 @@ class OC_Helper { $newpath = $path . '/' . $filename; if ($view->file_exists($newpath)) { - if(preg_match_all('/\((\d+)\)/', $name, $matches, PREG_OFFSET_CAPTURE)) { + if (preg_match_all('/\((\d+)\)/', $name, $matches, PREG_OFFSET_CAPTURE)) { //Replace the last "(number)" with "(number+1)" - $last_match = count($matches[0])-1; - $counter = $matches[1][$last_match][0]+1; + $last_match = count($matches[0]) - 1; + $counter = $matches[1][$last_match][0] + 1; $offset = $matches[0][$last_match][1]; $match_length = strlen($matches[0][$last_match][0]); } else { @@ -671,9 +627,9 @@ class OC_Helper { $offset = false; } do { - if($offset) { + if ($offset) { //Replace the last "(number)" with "(number+1)" - $newname = substr_replace($name, '('.$counter.')', $offset, $match_length); + $newname = substr_replace($name, '(' . $counter . ')', $offset, $match_length); } else { $newname = $name . ' (' . $counter . ')'; } @@ -700,17 +656,17 @@ class OC_Helper { } /** - * @brief Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is. - * - * @param array $input The array to work on - * @param int $case Either MB_CASE_UPPER or MB_CASE_LOWER (default) - * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8 - * @return array - * - * Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is. - * based on http://www.php.net/manual/en/function.array-change-key-case.php#107715 - * - */ + * @brief Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is. + * + * @param array $input The array to work on + * @param int $case Either MB_CASE_UPPER or MB_CASE_LOWER (default) + * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8 + * @return array + * + * Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is. + * based on http://www.php.net/manual/en/function.array-change-key-case.php#107715 + * + */ public static function mb_array_change_key_case($input, $case = MB_CASE_LOWER, $encoding = 'UTF-8') { $case = ($case != MB_CASE_UPPER) ? MB_CASE_LOWER : MB_CASE_UPPER; $ret = array(); @@ -736,26 +692,26 @@ class OC_Helper { $length = intval($length); $string = mb_substr($string, 0, $start, $encoding) . $replacement . - mb_substr($string, $start+$length, mb_strlen($string, 'UTF-8')-$start, $encoding); + mb_substr($string, $start + $length, mb_strlen($string, 'UTF-8') - $start, $encoding); return $string; } /** - * @brief Replace all occurrences of the search string with the replacement string - * - * @param string $search The value being searched for, otherwise known as the needle. - * @param string $replace The replacement - * @param string $subject The string or array being searched and replaced on, otherwise known as the haystack. - * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8 - * @param int $count If passed, this will be set to the number of replacements performed. - * @return string - * - */ + * @brief Replace all occurrences of the search string with the replacement string + * + * @param string $search The value being searched for, otherwise known as the needle. + * @param string $replace The replacement + * @param string $subject The string or array being searched and replaced on, otherwise known as the haystack. + * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8 + * @param int $count If passed, this will be set to the number of replacements performed. + * @return string + * + */ public static function mb_str_replace($search, $replace, $subject, $encoding = 'UTF-8', &$count = null) { $offset = -1; $length = mb_strlen($search, $encoding); - while(($i = mb_strrpos($subject, $search, $offset, $encoding)) !== false ) { + while (($i = mb_strrpos($subject, $search, $offset, $encoding)) !== false) { $subject = OC_Helper::mb_substr_replace($subject, $replace, $i, $length); $offset = $i - mb_strlen($subject, $encoding); $count++; @@ -764,21 +720,21 @@ class OC_Helper { } /** - * @brief performs a search in a nested array - * @param array $haystack the array to be searched - * @param string $needle the search string - * @param string $index optional, only search this key name - * @return mixed the key of the matching field, otherwise false - * - * performs a search in a nested array - * - * taken from http://www.php.net/manual/en/function.array-search.php#97645 - */ + * @brief performs a search in a nested array + * @param array $haystack the array to be searched + * @param string $needle the search string + * @param string $index optional, only search this key name + * @return mixed the key of the matching field, otherwise false + * + * performs a search in a nested array + * + * taken from http://www.php.net/manual/en/function.array-search.php#97645 + */ public static function recursiveArraySearch($haystack, $needle, $index = null) { $aIt = new RecursiveArrayIterator($haystack); $it = new RecursiveIteratorIterator($aIt); - while($it->valid()) { + while ($it->valid()) { if (((isset($index) AND ($it->key() == $index)) OR (!isset($index))) AND ($it->current() == $needle)) { return $aIt->key(); } @@ -792,6 +748,7 @@ class OC_Helper { /** * Shortens str to maxlen by replacing characters in the middle with '...', eg. * ellipsis('a very long string with lots of useless info to make a better example', 14) becomes 'a very ...example' + * * @param string $str the string * @param string $maxlen the maximum length of the result * @return string with at most maxlen characters @@ -822,7 +779,7 @@ class OC_Helper { $maxUploadFilesize = min($upload_max_filesize, $post_max_size); } - if($freeSpace !== \OC\Files\FREE_SPACE_UNKNOWN){ + if ($freeSpace !== \OC\Files\FREE_SPACE_UNKNOWN) { $freeSpace = max($freeSpace, 0); return min($maxUploadFilesize, $freeSpace); @@ -833,6 +790,7 @@ class OC_Helper { /** * Checks if a function is available + * * @param string $function_name * @return bool */ @@ -861,7 +819,7 @@ class OC_Helper { $used = 0; } $free = \OC\Files\Filesystem::free_space(); - if ($free >= 0){ + if ($free >= 0) { $total = $free + $used; } else { $total = $free; //either unknown or unlimited @@ -869,7 +827,7 @@ class OC_Helper { if ($total == 0) { $total = 1; // prevent division by zero } - if ($total >= 0){ + if ($total >= 0) { $relative = round(($used / $total) * 10000) / 100; } else { $relative = 0; From 9321eceed6a94f74ccdb908c05e97dfb1585d211 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 7 Aug 2013 16:53:09 +0200 Subject: [PATCH 2/6] add the option to have templates for newly created files --- apps/files/ajax/newfile.php | 72 ++++++++++++++++-------------- lib/files/type/templatemanager.php | 46 +++++++++++++++++++ lib/helper.php | 14 ++++++ 3 files changed, 98 insertions(+), 34 deletions(-) create mode 100644 lib/files/type/templatemanager.php diff --git a/apps/files/ajax/newfile.php b/apps/files/ajax/newfile.php index 8548fc95dd..21db0a7834 100644 --- a/apps/files/ajax/newfile.php +++ b/apps/files/ajax/newfile.php @@ -3,29 +3,29 @@ // Init owncloud global $eventSource; -if(!OC_User::isLoggedIn()) { +if (!OC_User::isLoggedIn()) { exit; } session_write_close(); // Get the params -$dir = isset( $_REQUEST['dir'] ) ? '/'.trim($_REQUEST['dir'], '/\\') : ''; -$filename = isset( $_REQUEST['filename'] ) ? trim($_REQUEST['filename'], '/\\') : ''; -$content = isset( $_REQUEST['content'] ) ? $_REQUEST['content'] : ''; -$source = isset( $_REQUEST['source'] ) ? trim($_REQUEST['source'], '/\\') : ''; +$dir = isset($_REQUEST['dir']) ? '/' . trim($_REQUEST['dir'], '/\\') : ''; +$filename = isset($_REQUEST['filename']) ? trim($_REQUEST['filename'], '/\\') : ''; +$content = isset($_REQUEST['content']) ? $_REQUEST['content'] : ''; +$source = isset($_REQUEST['source']) ? trim($_REQUEST['source'], '/\\') : ''; -if($source) { - $eventSource=new OC_EventSource(); +if ($source) { + $eventSource = new OC_EventSource(); } else { OC_JSON::callCheck(); } -if($filename == '') { - OCP\JSON::error(array("data" => array( "message" => "Empty Filename" ))); +if ($filename == '') { + OCP\JSON::error(array("data" => array("message" => "Empty Filename"))); exit(); } -if(strpos($filename, '/')!==false) { - OCP\JSON::error(array("data" => array( "message" => "Invalid Filename" ))); +if (strpos($filename, '/') !== false) { + OCP\JSON::error(array("data" => array("message" => "Invalid Filename"))); exit(); } @@ -34,7 +34,7 @@ function progress($notification_code, $severity, $message, $message_code, $bytes static $lastsize = 0; global $eventSource; - switch($notification_code) { + switch ($notification_code) { case STREAM_NOTIFY_FILE_SIZE_IS: $filesize = $bytes_max; break; @@ -43,52 +43,56 @@ function progress($notification_code, $severity, $message, $message_code, $bytes if ($bytes_transferred > 0) { if (!isset($filesize)) { } else { - $progress = (int)(($bytes_transferred/$filesize)*100); - if($progress>$lastsize) {//limit the number or messages send + $progress = (int)(($bytes_transferred / $filesize) * 100); + if ($progress > $lastsize) { //limit the number or messages send $eventSource->send('progress', $progress); } - $lastsize=$progress; + $lastsize = $progress; } } break; } } -if($source) { - if(substr($source, 0, 8)!='https://' and substr($source, 0, 7)!='http://') { - OCP\JSON::error(array("data" => array( "message" => "Not a valid source" ))); +if ($source) { + if (substr($source, 0, 8) != 'https://' and substr($source, 0, 7) != 'http://') { + OCP\JSON::error(array("data" => array("message" => "Not a valid source"))); exit(); } - $ctx = stream_context_create(null, array('notification' =>'progress')); - $sourceStream=fopen($source, 'rb', false, $ctx); - $target=$dir.'/'.$filename; - $result=\OC\Files\Filesystem::file_put_contents($target, $sourceStream); - if($result) { + $ctx = stream_context_create(null, array('notification' => 'progress')); + $sourceStream = fopen($source, 'rb', false, $ctx); + $target = $dir . '/' . $filename; + $result = \OC\Files\Filesystem::file_put_contents($target, $sourceStream); + if ($result) { $meta = \OC\Files\Filesystem::getFileInfo($target); - $mime=$meta['mimetype']; + $mime = $meta['mimetype']; $id = $meta['fileid']; - $eventSource->send('success', array('mime'=>$mime, 'size'=>\OC\Files\Filesystem::filesize($target), 'id' => $id)); + $eventSource->send('success', array('mime' => $mime, 'size' => \OC\Files\Filesystem::filesize($target), 'id' => $id)); } else { - $eventSource->send('error', "Error while downloading ".$source. ' to '.$target); + $eventSource->send('error', "Error while downloading " . $source . ' to ' . $target); } $eventSource->close(); exit(); } else { - if($content) { - if(\OC\Files\Filesystem::file_put_contents($dir.'/'.$filename, $content)) { - $meta = \OC\Files\Filesystem::getFileInfo($dir.'/'.$filename); + if ($content) { + if (\OC\Files\Filesystem::file_put_contents($dir . '/' . $filename, $content)) { + $meta = \OC\Files\Filesystem::getFileInfo($dir . '/' . $filename); $id = $meta['fileid']; - OCP\JSON::success(array("data" => array('content'=>$content, 'id' => $id))); + OCP\JSON::success(array("data" => array('content' => $content, 'id' => $id))); exit(); } - }elseif(\OC\Files\Filesystem::touch($dir . '/' . $filename)) { - $meta = \OC\Files\Filesystem::getFileInfo($dir.'/'.$filename); + } elseif (\OC\Files\Filesystem::touch($dir . '/' . $filename)) { + $meta = \OC\Files\Filesystem::getFileInfo($dir . '/' . $filename); + $templateManager = OC_Helper::getFileTemplateManager(); + if ($content = $templateManager->getTemplate($meta['mimetype'])) { + \OC\Files\Filesystem::file_put_contents($dir . '/' . $filename, $content); + } $id = $meta['fileid']; - OCP\JSON::success(array("data" => array('content'=>$content, 'id' => $id, 'mime' => $meta['mimetype']))); + OCP\JSON::success(array("data" => array('content' => $content, 'id' => $id, 'mime' => $meta['mimetype']))); exit(); } } -OCP\JSON::error(array("data" => array( "message" => "Error when creating the file" ))); +OCP\JSON::error(array("data" => array("message" => "Error when creating the file"))); diff --git a/lib/files/type/templatemanager.php b/lib/files/type/templatemanager.php new file mode 100644 index 0000000000..cd1536d273 --- /dev/null +++ b/lib/files/type/templatemanager.php @@ -0,0 +1,46 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Type; + +class TemplateManager { + protected $templates = array(); + + public function registerTemplate($mimetype, $path) { + $this->templates[$mimetype] = $path; + } + + /** + * get the path of the template for a mimetype + * + * @param string $mimetype + * @return string | null + */ + public function getTemplatePath($mimetype) { + if (isset($this->templates[$mimetype])) { + return $this->templates[$mimetype]; + } else { + return null; + } + } + + /** + * get the template content for a mimetype + * + * @param string $mimetype + * @return string + */ + public function getTemplate($mimetype) { + $path = $this->getTemplatePath($mimetype); + if ($path) { + return file_get_contents($path); + } else { + return ''; + } + } +} diff --git a/lib/helper.php b/lib/helper.php index 801f06352d..8b64baaea7 100644 --- a/lib/helper.php +++ b/lib/helper.php @@ -28,6 +28,7 @@ class OC_Helper { private static $tmpFiles = array(); private static $mimetypeIcons = array(); private static $mimetypeDetector; + private static $templateManager; /** * @brief Creates an url using a defined route @@ -357,6 +358,9 @@ class OC_Helper { } } + /** + * @return \OC\Files\Type\Detection + */ static public function getMimetypeDetector() { if (!self::$mimetypeDetector) { self::$mimetypeDetector = new \OC\Files\Type\Detection(); @@ -365,6 +369,16 @@ class OC_Helper { return self::$mimetypeDetector; } + /** + * @return \OC\Files\Type\TemplateManager + */ + static public function getFileTemplateManager() { + if (!self::$templateManager) { + self::$templateManager = new \OC\Files\Type\TemplateManager(); + } + return self::$templateManager; + } + /** * Try to guess the mimetype based on filename * From 1c1ede57034343830696667820115435db5509ba Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 7 Aug 2013 16:53:33 +0200 Subject: [PATCH 3/6] add template for html files --- core/templates/filetemplates/template.html | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 core/templates/filetemplates/template.html diff --git a/core/templates/filetemplates/template.html b/core/templates/filetemplates/template.html new file mode 100644 index 0000000000..f16e80cb7e --- /dev/null +++ b/core/templates/filetemplates/template.html @@ -0,0 +1,9 @@ + + + + + + + + + From a0243e03effc1a1a60a80c3b95f9499bbd0b661f Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 7 Aug 2013 17:17:30 +0200 Subject: [PATCH 4/6] use === --- lib/files/type/detection.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/files/type/detection.php b/lib/files/type/detection.php index 1fe49a9bc4..242a81cb5a 100644 --- a/lib/files/type/detection.php +++ b/lib/files/type/detection.php @@ -61,7 +61,7 @@ class Detection { * @return string */ public function detect($path) { - $isWrapped = (strpos($path, '://') !== false) and (substr($path, 0, 7) == 'file://'); + $isWrapped = (strpos($path, '://') !== false) and (substr($path, 0, 7) === 'file://'); if (@is_dir($path)) { // directories are easy @@ -70,7 +70,7 @@ class Detection { $mimeType = $this->detectPath($path); - if ($mimeType == 'application/octet-stream' and function_exists('finfo_open') + if ($mimeType === 'application/octet-stream' and function_exists('finfo_open') and function_exists('finfo_file') and $finfo = finfo_open(FILEINFO_MIME) ) { $info = @strtolower(finfo_file($finfo, $path)); @@ -79,11 +79,11 @@ class Detection { } finfo_close($finfo); } - if (!$isWrapped and $mimeType == 'application/octet-stream' && function_exists("mime_content_type")) { + if (!$isWrapped and $mimeType === 'application/octet-stream' && function_exists("mime_content_type")) { // use mime magic extension if available $mimeType = mime_content_type($path); } - if (!$isWrapped and $mimeType == 'application/octet-stream' && \OC_Helper::canExecute("file")) { + if (!$isWrapped and $mimeType === 'application/octet-stream' && \OC_Helper::canExecute("file")) { // it looks like we have a 'file' command, // lets see if it does have mime support $path = escapeshellarg($path); From d91104e120d570eaf3d80c23c5caf6b597b24db7 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 7 Aug 2013 23:48:44 +0200 Subject: [PATCH 5/6] actually register html template --- apps/files/appinfo/app.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/apps/files/appinfo/app.php b/apps/files/appinfo/app.php index 99739cb4ce..aa839b81d1 100644 --- a/apps/files/appinfo/app.php +++ b/apps/files/appinfo/app.php @@ -5,11 +5,11 @@ $l = OC_L10N::get('files'); OCP\App::registerAdmin('files', 'admin'); -OCP\App::addNavigationEntry( array( "id" => "files_index", - "order" => 0, - "href" => OCP\Util::linkTo( "files", "index.php" ), - "icon" => OCP\Util::imagePath( "core", "places/files.svg" ), - "name" => $l->t("Files") )); +OCP\App::addNavigationEntry(array("id" => "files_index", + "order" => 0, + "href" => OCP\Util::linkTo("files", "index.php"), + "icon" => OCP\Util::imagePath("core", "places/files.svg"), + "name" => $l->t("Files"))); OC_Search::registerProvider('OC_Search_Provider_File'); @@ -21,3 +21,7 @@ OC_Search::registerProvider('OC_Search_Provider_File'); \OC_Hook::connect('OC_Filesystem', 'post_rename', '\OC\Files\Cache\Updater', 'renameHook'); \OCP\BackgroundJob::addRegularTask('\OC\Files\Cache\BackgroundWatcher', 'checkNext'); + +$templateManager = OC_Helper::getFileTemplateManager(); +$templateManager->registerTemplate('text/html', 'core/templates/filetemplates/template.html'); + From 57f7ff2dbdbef977483c0078048181ea1b7630f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Fri, 16 Aug 2013 00:31:27 +0200 Subject: [PATCH 6/6] communicate size of newly created file back and update UI --- apps/files/ajax/newfile.php | 2 + apps/files/js/file-upload.js | 672 ++++++++++++++++++----------------- apps/files/js/files.js | 2 + 3 files changed, 341 insertions(+), 335 deletions(-) diff --git a/apps/files/ajax/newfile.php b/apps/files/ajax/newfile.php index 8f5b1d98c3..d224e79d01 100644 --- a/apps/files/ajax/newfile.php +++ b/apps/files/ajax/newfile.php @@ -93,9 +93,11 @@ if($source) { $meta = \OC\Files\Filesystem::getFileInfo($target); $id = $meta['fileid']; $mime = $meta['mimetype']; + $size = $meta['size']; OCP\JSON::success(array('data' => array( 'id' => $id, 'mime' => $mime, + 'size' => $size, 'content' => $content, ))); exit(); diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js index 942a07dfcc..0eddd7e9cd 100644 --- a/apps/files/js/file-upload.js +++ b/apps/files/js/file-upload.js @@ -1,343 +1,345 @@ $(document).ready(function() { - file_upload_param = { - dropZone: $('#content'), // restrict dropZone to content div - //singleFileUploads is on by default, so the data.files array will always have length 1 - add: function(e, data) { + file_upload_param = { + dropZone: $('#content'), // restrict dropZone to content div + //singleFileUploads is on by default, so the data.files array will always have length 1 + add: function(e, data) { - if(data.files[0].type === '' && data.files[0].size == 4096) - { - data.textStatus = 'dirorzero'; - data.errorThrown = t('files','Unable to upload your file as it is a directory or has 0 bytes'); - var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload'); - fu._trigger('fail', e, data); - return true; //don't upload this file but go on with next in queue - } - - var totalSize=0; - $.each(data.originalFiles, function(i,file){ - totalSize+=file.size; - }); - - if(totalSize>$('#max_upload').val()){ - data.textStatus = 'notenoughspace'; - data.errorThrown = t('files','Not enough space available'); - var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload'); - fu._trigger('fail', e, data); - return false; //don't upload anything - } - - // start the actual file upload - var jqXHR = data.submit(); - - // remember jqXHR to show warning to user when he navigates away but an upload is still in progress - if (typeof data.context !== 'undefined' && data.context.data('type') === 'dir') { - var dirName = data.context.data('file'); - if(typeof uploadingFiles[dirName] === 'undefined') { - uploadingFiles[dirName] = {}; - } - uploadingFiles[dirName][data.files[0].name] = jqXHR; - } else { - uploadingFiles[data.files[0].name] = jqXHR; - } - - //show cancel button - if($('html.lte9').length === 0 && data.dataType !== 'iframe') { - $('#uploadprogresswrapper input.stop').show(); - } - }, - /** - * called after the first add, does NOT have the data param - * @param e - */ - start: function(e) { - //IE < 10 does not fire the necessary events for the progress bar. - if($('html.lte9').length > 0) { - return; - } - $('#uploadprogressbar').progressbar({value:0}); - $('#uploadprogressbar').fadeIn(); - }, - fail: function(e, data) { - if (typeof data.textStatus !== 'undefined' && data.textStatus !== 'success' ) { - if (data.textStatus === 'abort') { - $('#notification').text(t('files', 'Upload cancelled.')); - } else { - // HTTP connection problem - $('#notification').text(data.errorThrown); - } - $('#notification').fadeIn(); - //hide notification after 5 sec - setTimeout(function() { - $('#notification').fadeOut(); - }, 5000); - } - delete uploadingFiles[data.files[0].name]; - }, - progress: function(e, data) { - // TODO: show nice progress bar in file row - }, - progressall: function(e, data) { - //IE < 10 does not fire the necessary events for the progress bar. - if($('html.lte9').length > 0) { - return; - } - var progress = (data.loaded/data.total)*100; - $('#uploadprogressbar').progressbar('value',progress); - }, - /** - * called for every successful upload - * @param e - * @param data - */ - done:function(e, data) { - // handle different responses (json or body from iframe for ie) - var response; - if (typeof data.result === 'string') { - response = data.result; - } else { - //fetch response from iframe - response = data.result[0].body.innerText; - } - var result=$.parseJSON(response); - - if(typeof result[0] !== 'undefined' && result[0].status === 'success') { - var file = result[0]; - } else { - data.textStatus = 'servererror'; - data.errorThrown = t('files', result.data.message); - var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload'); - fu._trigger('fail', e, data); - } - - var filename = result[0].originalname; - - // delete jqXHR reference - if (typeof data.context !== 'undefined' && data.context.data('type') === 'dir') { - var dirName = data.context.data('file'); - delete uploadingFiles[dirName][filename]; - if ($.assocArraySize(uploadingFiles[dirName]) == 0) { - delete uploadingFiles[dirName]; - } - } else { - delete uploadingFiles[filename]; - } - - }, - /** - * called after last upload - * @param e - * @param data - */ - stop: function(e, data) { - if(data.dataType !== 'iframe') { - $('#uploadprogresswrapper input.stop').hide(); - } - - //IE < 10 does not fire the necessary events for the progress bar. - if($('html.lte9').length > 0) { - return; - } - - $('#uploadprogressbar').progressbar('value',100); - $('#uploadprogressbar').fadeOut(); - } - } - var file_upload_handler = function() { - $('#file_upload_start').fileupload(file_upload_param); - }; - - - - if ( document.getElementById('data-upload-form') ) { - $(file_upload_handler); - } - $.assocArraySize = function(obj) { - // http://stackoverflow.com/a/6700/11236 - var size = 0, key; - for (key in obj) { - if (obj.hasOwnProperty(key)) size++; - } - return size; - }; - - // warn user not to leave the page while upload is in progress - $(window).bind('beforeunload', function(e) { - if ($.assocArraySize(uploadingFiles) > 0) - return t('files','File upload is in progress. Leaving the page now will cancel the upload.'); - }); - - //add multiply file upload attribute to all browsers except konqueror (which crashes when it's used) - if(navigator.userAgent.search(/konqueror/i)==-1){ - $('#file_upload_start').attr('multiple','multiple') - } - - //if the breadcrumb is to long, start by replacing foldernames with '...' except for the current folder - var crumb=$('div.crumb').first(); - while($('div.controls').height()>40 && crumb.next('div.crumb').length>0){ - crumb.children('a').text('...'); - crumb=crumb.next('div.crumb'); - } - //if that isn't enough, start removing items from the breacrumb except for the current folder and it's parent - var crumb=$('div.crumb').first(); - var next=crumb.next('div.crumb'); - while($('div.controls').height()>40 && next.next('div.crumb').length>0){ - crumb.remove(); - crumb=next; - next=crumb.next('div.crumb'); - } - //still not enough, start shorting down the current folder name - var crumb=$('div.crumb>a').last(); - while($('div.controls').height()>40 && crumb.text().length>6){ - var text=crumb.text() - text=text.substr(0,text.length-6)+'...'; - crumb.text(text); - } - - $(document).click(function(){ - $('#new>ul').hide(); - $('#new').removeClass('active'); - $('#new li').each(function(i,element){ - if($(element).children('p').length==0){ - $(element).children('form').remove(); - $(element).append('

'+$(element).data('text')+'

'); - } - }); - }); - $('#new li').click(function(){ - if($(this).children('p').length==0){ - return; - } - - $('#new li').each(function(i,element){ - if($(element).children('p').length==0){ - $(element).children('form').remove(); - $(element).append('

'+$(element).data('text')+'

'); - } - }); - - var type=$(this).data('type'); - var text=$(this).children('p').text(); - $(this).data('text',text); - $(this).children('p').remove(); - var form=$('
'); - var input=$(''); - form.append(input); - $(this).append(form); - input.focus(); - form.submit(function(event){ - event.stopPropagation(); - event.preventDefault(); - var newname=input.val(); - if(type == 'web' && newname.length == 0) { - OC.Notification.show(t('files', 'URL cannot be empty.')); - return false; - } else if (type != 'web' && !Files.isFileNameValid(newname)) { - return false; - } else if( type == 'folder' && $('#dir').val() == '/' && newname == 'Shared') { - OC.Notification.show(t('files','Invalid folder name. Usage of \'Shared\' is reserved by ownCloud')); - return false; - } - if (FileList.lastAction) { - FileList.lastAction(); - } - var name = getUniqueName(newname); - if (newname != name) { - FileList.checkName(name, newname, true); - var hidden = true; - } else { - var hidden = false; - } - switch(type){ - case 'file': - $.post( - OC.filePath('files','ajax','newfile.php'), - {dir:$('#dir').val(),filename:name}, - function(result){ - if (result.status == 'success') { - var date=new Date(); - FileList.addFile(name,0,date,false,hidden); - var tr=$('tr').filterAttr('data-file',name); - tr.attr('data-mime',result.data.mime); - tr.attr('data-id', result.data.id); - getMimeIcon(result.data.mime,function(path){ - tr.find('td.filename').attr('style','background-image:url('+path+')'); - }); - } else { - OC.dialogs.alert(result.data.message, t('core', 'Error')); + if(data.files[0].type === '' && data.files[0].size == 4096) + { + data.textStatus = 'dirorzero'; + data.errorThrown = t('files','Unable to upload your file as it is a directory or has 0 bytes'); + var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload'); + fu._trigger('fail', e, data); + return true; //don't upload this file but go on with next in queue } - } - ); - break; - case 'folder': - $.post( - OC.filePath('files','ajax','newfolder.php'), - {dir:$('#dir').val(),foldername:name}, - function(result){ - if (result.status == 'success') { - var date=new Date(); - FileList.addDir(name,0,date,hidden); - var tr=$('tr').filterAttr('data-file',name); - tr.attr('data-id', result.data.id); - } else { - OC.dialogs.alert(result.data.message, t('core', 'Error')); - } - } - ); - break; - case 'web': - if(name.substr(0,8)!='https://' && name.substr(0,7)!='http://'){ - name='http://'+name; - } - var localName=name; - if(localName.substr(localName.length-1,1)=='/'){//strip / - localName=localName.substr(0,localName.length-1) - } - if(localName.indexOf('/')){//use last part of url - localName=localName.split('/').pop(); - } else { //or the domain - localName=(localName.match(/:\/\/(.[^\/]+)/)[1]).replace('www.',''); - } - localName = getUniqueName(localName); - //IE < 10 does not fire the necessary events for the progress bar. - if($('html.lte9').length > 0) { - } else { - $('#uploadprogressbar').progressbar({value:0}); - $('#uploadprogressbar').fadeIn(); - } - var eventSource=new OC.EventSource(OC.filePath('files','ajax','newfile.php'),{dir:$('#dir').val(),source:name,filename:localName}); - eventSource.listen('progress',function(progress){ - //IE < 10 does not fire the necessary events for the progress bar. - if($('html.lte9').length > 0) { - } else { + var totalSize=0; + $.each(data.originalFiles, function(i,file){ + totalSize+=file.size; + }); + + if(totalSize>$('#max_upload').val()){ + data.textStatus = 'notenoughspace'; + data.errorThrown = t('files','Not enough space available'); + var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload'); + fu._trigger('fail', e, data); + return false; //don't upload anything + } + + // start the actual file upload + var jqXHR = data.submit(); + + // remember jqXHR to show warning to user when he navigates away but an upload is still in progress + if (typeof data.context !== 'undefined' && data.context.data('type') === 'dir') { + var dirName = data.context.data('file'); + if(typeof uploadingFiles[dirName] === 'undefined') { + uploadingFiles[dirName] = {}; + } + uploadingFiles[dirName][data.files[0].name] = jqXHR; + } else { + uploadingFiles[data.files[0].name] = jqXHR; + } + + //show cancel button + if($('html.lte9').length === 0 && data.dataType !== 'iframe') { + $('#uploadprogresswrapper input.stop').show(); + } + }, + /** + * called after the first add, does NOT have the data param + * @param e + */ + start: function(e) { + //IE < 10 does not fire the necessary events for the progress bar. + if($('html.lte9').length > 0) { + return; + } + $('#uploadprogressbar').progressbar({value:0}); + $('#uploadprogressbar').fadeIn(); + }, + fail: function(e, data) { + if (typeof data.textStatus !== 'undefined' && data.textStatus !== 'success' ) { + if (data.textStatus === 'abort') { + $('#notification').text(t('files', 'Upload cancelled.')); + } else { + // HTTP connection problem + $('#notification').text(data.errorThrown); + } + $('#notification').fadeIn(); + //hide notification after 5 sec + setTimeout(function() { + $('#notification').fadeOut(); + }, 5000); + } + delete uploadingFiles[data.files[0].name]; + }, + progress: function(e, data) { + // TODO: show nice progress bar in file row + }, + progressall: function(e, data) { + //IE < 10 does not fire the necessary events for the progress bar. + if($('html.lte9').length > 0) { + return; + } + var progress = (data.loaded/data.total)*100; $('#uploadprogressbar').progressbar('value',progress); - } - }); - eventSource.listen('success',function(data){ - var mime=data.mime; - var size=data.size; - var id=data.id; - $('#uploadprogressbar').fadeOut(); - var date=new Date(); - FileList.addFile(localName,size,date,false,hidden); - var tr=$('tr').filterAttr('data-file',localName); - tr.data('mime',mime).data('id',id); - tr.attr('data-id', id); - getMimeIcon(mime,function(path){ - tr.find('td.filename').attr('style','background-image:url('+path+')'); - }); - }); - eventSource.listen('error',function(error){ - $('#uploadprogressbar').fadeOut(); - alert(error); - }); - break; - } - var li=form.parent(); - form.remove(); - li.append('

'+li.data('text')+'

'); - $('#new>a').click(); + }, + /** + * called for every successful upload + * @param e + * @param data + */ + done:function(e, data) { + // handle different responses (json or body from iframe for ie) + var response; + if (typeof data.result === 'string') { + response = data.result; + } else { + //fetch response from iframe + response = data.result[0].body.innerText; + } + var result=$.parseJSON(response); + + if(typeof result[0] !== 'undefined' && result[0].status === 'success') { + var file = result[0]; + } else { + data.textStatus = 'servererror'; + data.errorThrown = t('files', result.data.message); + var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload'); + fu._trigger('fail', e, data); + } + + var filename = result[0].originalname; + + // delete jqXHR reference + if (typeof data.context !== 'undefined' && data.context.data('type') === 'dir') { + var dirName = data.context.data('file'); + delete uploadingFiles[dirName][filename]; + if ($.assocArraySize(uploadingFiles[dirName]) == 0) { + delete uploadingFiles[dirName]; + } + } else { + delete uploadingFiles[filename]; + } + + }, + /** + * called after last upload + * @param e + * @param data + */ + stop: function(e, data) { + if(data.dataType !== 'iframe') { + $('#uploadprogresswrapper input.stop').hide(); + } + + //IE < 10 does not fire the necessary events for the progress bar. + if($('html.lte9').length > 0) { + return; + } + + $('#uploadprogressbar').progressbar('value',100); + $('#uploadprogressbar').fadeOut(); + } + } + var file_upload_handler = function() { + $('#file_upload_start').fileupload(file_upload_param); + }; + + + + if ( document.getElementById('data-upload-form') ) { + $(file_upload_handler); + } + $.assocArraySize = function(obj) { + // http://stackoverflow.com/a/6700/11236 + var size = 0, key; + for (key in obj) { + if (obj.hasOwnProperty(key)) size++; + } + return size; + }; + + // warn user not to leave the page while upload is in progress + $(window).bind('beforeunload', function(e) { + if ($.assocArraySize(uploadingFiles) > 0) + return t('files','File upload is in progress. Leaving the page now will cancel the upload.'); + }); + + //add multiply file upload attribute to all browsers except konqueror (which crashes when it's used) + if(navigator.userAgent.search(/konqueror/i)==-1){ + $('#file_upload_start').attr('multiple','multiple') + } + + //if the breadcrumb is to long, start by replacing foldernames with '...' except for the current folder + var crumb=$('div.crumb').first(); + while($('div.controls').height()>40 && crumb.next('div.crumb').length>0){ + crumb.children('a').text('...'); + crumb=crumb.next('div.crumb'); + } + //if that isn't enough, start removing items from the breacrumb except for the current folder and it's parent + var crumb=$('div.crumb').first(); + var next=crumb.next('div.crumb'); + while($('div.controls').height()>40 && next.next('div.crumb').length>0){ + crumb.remove(); + crumb=next; + next=crumb.next('div.crumb'); + } + //still not enough, start shorting down the current folder name + var crumb=$('div.crumb>a').last(); + while($('div.controls').height()>40 && crumb.text().length>6){ + var text=crumb.text() + text=text.substr(0,text.length-6)+'...'; + crumb.text(text); + } + + $(document).click(function(){ + $('#new>ul').hide(); + $('#new').removeClass('active'); + $('#new li').each(function(i,element){ + if($(element).children('p').length==0){ + $(element).children('form').remove(); + $(element).append('

'+$(element).data('text')+'

'); + } + }); + }); + $('#new li').click(function(){ + if($(this).children('p').length==0){ + return; + } + + $('#new li').each(function(i,element){ + if($(element).children('p').length==0){ + $(element).children('form').remove(); + $(element).append('

'+$(element).data('text')+'

'); + } + }); + + var type=$(this).data('type'); + var text=$(this).children('p').text(); + $(this).data('text',text); + $(this).children('p').remove(); + var form=$('
'); + var input=$(''); + form.append(input); + $(this).append(form); + input.focus(); + form.submit(function(event){ + event.stopPropagation(); + event.preventDefault(); + var newname=input.val(); + if(type == 'web' && newname.length == 0) { + OC.Notification.show(t('files', 'URL cannot be empty.')); + return false; + } else if (type != 'web' && !Files.isFileNameValid(newname)) { + return false; + } else if( type == 'folder' && $('#dir').val() == '/' && newname == 'Shared') { + OC.Notification.show(t('files','Invalid folder name. Usage of \'Shared\' is reserved by ownCloud')); + return false; + } + if (FileList.lastAction) { + FileList.lastAction(); + } + var name = getUniqueName(newname); + if (newname != name) { + FileList.checkName(name, newname, true); + var hidden = true; + } else { + var hidden = false; + } + switch(type){ + case 'file': + $.post( + OC.filePath('files','ajax','newfile.php'), + {dir:$('#dir').val(),filename:name}, + function(result){ + if (result.status == 'success') { + var date=new Date(); + FileList.addFile(name,0,date,false,hidden); + var tr=$('tr').filterAttr('data-file',name); + tr.attr('data-size',result.data.size); + tr.attr('data-mime',result.data.mime); + tr.attr('data-id', result.data.id); + tr.find('.filesize').text(humanFileSize(result.data.size)); + getMimeIcon(result.data.mime,function(path){ + tr.find('td.filename').attr('style','background-image:url('+path+')'); + }); + } else { + OC.dialogs.alert(result.data.message, t('core', 'Error')); + } + } + ); + break; + case 'folder': + $.post( + OC.filePath('files','ajax','newfolder.php'), + {dir:$('#dir').val(),foldername:name}, + function(result){ + if (result.status == 'success') { + var date=new Date(); + FileList.addDir(name,0,date,hidden); + var tr=$('tr').filterAttr('data-file',name); + tr.attr('data-id', result.data.id); + } else { + OC.dialogs.alert(result.data.message, t('core', 'Error')); + } + } + ); + break; + case 'web': + if(name.substr(0,8)!='https://' && name.substr(0,7)!='http://'){ + name='http://'+name; + } + var localName=name; + if(localName.substr(localName.length-1,1)=='/'){//strip / + localName=localName.substr(0,localName.length-1) + } + if(localName.indexOf('/')){//use last part of url + localName=localName.split('/').pop(); + } else { //or the domain + localName=(localName.match(/:\/\/(.[^\/]+)/)[1]).replace('www.',''); + } + localName = getUniqueName(localName); + //IE < 10 does not fire the necessary events for the progress bar. + if($('html.lte9').length > 0) { + } else { + $('#uploadprogressbar').progressbar({value:0}); + $('#uploadprogressbar').fadeIn(); + } + + var eventSource=new OC.EventSource(OC.filePath('files','ajax','newfile.php'),{dir:$('#dir').val(),source:name,filename:localName}); + eventSource.listen('progress',function(progress){ + //IE < 10 does not fire the necessary events for the progress bar. + if($('html.lte9').length > 0) { + } else { + $('#uploadprogressbar').progressbar('value',progress); + } + }); + eventSource.listen('success',function(data){ + var mime=data.mime; + var size=data.size; + var id=data.id; + $('#uploadprogressbar').fadeOut(); + var date=new Date(); + FileList.addFile(localName,size,date,false,hidden); + var tr=$('tr').filterAttr('data-file',localName); + tr.data('mime',mime).data('id',id); + tr.attr('data-id', id); + getMimeIcon(mime,function(path){ + tr.find('td.filename').attr('style','background-image:url('+path+')'); + }); + }); + eventSource.listen('error',function(error){ + $('#uploadprogressbar').fadeOut(); + alert(error); + }); + break; + } + var li=form.parent(); + form.remove(); + li.append('

'+li.data('text')+'

'); + $('#new>a').click(); + }); }); - }); }); diff --git a/apps/files/js/files.js b/apps/files/js/files.js index 53fc25f41b..e1c53184dd 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -365,7 +365,9 @@ $(document).ready(function() { FileList.addFile(name,0,date,false,hidden); var tr=$('tr').filterAttr('data-file',name); tr.attr('data-mime',result.data.mime); + tr.attr('data-size',result.data.size); tr.attr('data-id', result.data.id); + tr.find('.filesize').text(humanFileSize(result.data.size)); getMimeIcon(result.data.mime,function(path){ tr.find('td.filename').attr('style','background-image:url('+path+')'); });