diff --git a/phpgwapi/inc/class.egw_sharing.inc.php b/phpgwapi/inc/class.egw_sharing.inc.php index 28c8474da8..ebcc274211 100644 --- a/phpgwapi/inc/class.egw_sharing.inc.php +++ b/phpgwapi/inc/class.egw_sharing.inc.php @@ -24,8 +24,11 @@ class egw_sharing { /** * Length of base64 encoded token (real length is only 3/4 of it) + * + * Dropbox uses just 15 chars (letters/numbers 5-6 bit), php sessions use 32 chars (hex = 4bits), + * so 32 chars of base64 = 6bits should be plenty. */ - const TOKEN_LENGTH = 64; + const TOKEN_LENGTH = 32; /** * Name of table used for storing tokens @@ -237,9 +240,12 @@ class egw_sharing public static function token() { // generate random token (using oppenssl if available otherwise mt_rand based auth::randomstring) - $token = function_exists('openssl_random_pseudo_bytes') ? - base64_encode(openssl_random_pseudo_bytes(3*self::TOKEN_LENGTH/4)) : - auth::randomstring(self::TOKEN_LENGTH); + do { + $token = function_exists('openssl_random_pseudo_bytes') ? + base64_encode(openssl_random_pseudo_bytes(3*self::TOKEN_LENGTH/4)) : + auth::randomstring(self::TOKEN_LENGTH); + // base64 can contain chars not allowed in our vfs-urls eg. / or # + } while ($token != egw_vfs::encodePathComponent($token)); return $token; } @@ -276,7 +282,7 @@ class egw_sharing $path = 'vfs://default'.($path[0] == '/' ? '' : '/').$path; } // check if file exists and is readable - if (!file_exists($path) || is_readable($path)) + if (!file_exists($path) || !is_readable($path)) { throw new egw_exception_not_found("'$path' NOT found!"); } @@ -323,7 +329,9 @@ class egw_sharing $tmp_file = egw_vfs::concat($user_tmp, ($n?$n.'.':'').egw_vfs::basename($name)); } while(!(is_dir($path) && egw_vfs::mkdir($tmp_file) || - !is_dir($path) && ($fp = egw_vfs::fopen($tmp_file, 'x'))) && $n++ < 100); + !is_dir($path) && (!egw_vfs::file_exists($tmp_file) && ($fp = egw_vfs::fopen($tmp_file, 'x')) || + // do not copy identical files again to users tmp dir, just re-use them + egw_vfs::file_exists($tmp_file) && egw_vfs::compare(egw_vfs::PREFIX.$tmp_file, $path))) && $n++ < 100); if ($n >= 100) { @@ -340,6 +348,13 @@ class egw_sharing $path2tmp[$path] = $tmp_file; $path = $tmp_file; + + // if not already installed, install periodic cleanup of tmp files + $async = new asyncservice(); + if (!$async->read('egw_sharing-tmp-cleanup')) + { + $async->set_timer(array('day' => 28),'egw_sharing-tmp_cleanup','egw_sharing::tmp_cleanup',null); + } } $i = 0; @@ -366,6 +381,28 @@ class egw_sharing return $share; } + /** + * Periodic (monthly) cleanup of temp. sharing files + */ + public static function tmp_cleanup() + { + try { + egw_vfs::$is_root = true; + /* not yet ready + egw_vfs::find('/home', array( + 'path_preg' => '|^/home/[^/]+/.tmp', + 'maxdepth' => 3, + ), function($path, $stat) + { + error_log(__METHOD__."() path=$path"); + });*/ + } + catch (Exception $e) { + unset($e); + } + egw_vfs::$is_root = false; + } + /** * Generate link from share or share-token * diff --git a/phpgwapi/inc/class.egw_vfs.inc.php b/phpgwapi/inc/class.egw_vfs.inc.php index b72c52fc3e..65dd99d9c7 100644 --- a/phpgwapi/inc/class.egw_vfs.inc.php +++ b/phpgwapi/inc/class.egw_vfs.inc.php @@ -2005,6 +2005,36 @@ class egw_vfs extends vfs_stream_wrapper if (self::LOG_LEVEL > 1 || !$ret && self::LOG_LEVEL) error_log(__METHOD__."($tmp_name, $target, ".array2string($props).") returning ".array2string($ret)); return $ret; } + + /** + * Compare two files from vfs or local file-system for identical content + * + * VFS files must use URL, to be able to distinguish them eg. from temp. files! + * + * @param string $file1 vfs-url or local path, eg. /tmp/some-file.txt or vfs://default/home/user/some-file.txt + * @param string $file2 -- " -- + * @return boolean true: if files are identical, false: if not or file not found + */ + public static function compare($file1, $file2) + { + if (filesize($file1) != filesize($file2) || + !($fp1 = fopen($file1, 'r')) || !($fp2 = fopen($file2, 'r'))) + { + //error_log(__METHOD__."($file1, $file2) returning FALSE (different size)"); + return false; + } + while (($read1 = fread($fp1, 8192)) !== false && + ($read2 = fread($fp2, 8192)) !== false && + $read1 === $read2 && !feof($fp1) && !feof($fp2)) + { + // just loop until we find a difference + } + + fclose($fp1); + fclose($fp2); + //error_log(__METHOD__."($file1, $file2) returning ".array2string($read1 === $read2)." (content differs)"); + return $read1 === $read2; + } } egw_vfs::init_static();