2010-03-10 15:03:40 +03:00
< ? php
/**
2012-10-22 00:05:29 +04:00
* ownCloud
*
* @ author Frank Karlitschek
* @ copyright 2012 Frank Karlitschek frank @ owncloud . org
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation ; either
* version 3 of the License , or any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details .
*
* You should have received a copy of the GNU Affero General Public
* License along with this library . If not , see < http :// www . gnu . org / licenses />.
*
*/
2010-03-10 15:03:40 +03:00
/**
* Class for fileserver access
*
*/
2011-07-29 23:36:03 +04:00
class OC_Files {
2012-10-22 00:05:29 +04:00
static $tmpFiles = array ();
2010-04-25 16:21:04 +04:00
2012-12-15 05:22:09 +04:00
static public function getFileInfo ( $path ){
2012-11-16 01:08:08 +04:00
return \OC\Files\Filesystem :: getFileInfo ( $path );
}
2012-12-15 05:22:09 +04:00
static public function getDirectoryContent ( $path ){
2012-11-16 01:08:08 +04:00
return \OC\Files\Filesystem :: getDirectoryContent ( $path );
}
2010-04-25 16:21:04 +04:00
/**
2013-01-29 08:51:35 +04:00
* return the content of a file or return a zip file containing multiple files
2012-10-22 00:05:29 +04:00
*
2012-10-24 17:32:29 +04:00
* @ param string $dir
2013-01-29 08:51:35 +04:00
* @ param string $file ; separated list of files to download
2012-10-22 00:05:29 +04:00
* @ param boolean $only_header ; boolean to only send header of the request
*/
public static function get ( $dir , $files , $only_header = false ) {
2012-10-19 02:11:20 +04:00
$xsendfile = false ;
2013-01-14 23:30:39 +04:00
if ( isset ( $_SERVER [ 'MOD_X_SENDFILE_ENABLED' ]) ||
2012-10-31 02:37:31 +04:00
isset ( $_SERVER [ 'MOD_X_ACCEL_REDIRECT_ENABLED' ])) {
2012-10-19 02:11:20 +04:00
$xsendfile = true ;
2012-10-31 02:37:31 +04:00
}
2012-10-23 02:28:12 +04:00
if ( strpos ( $files , ';' )) {
$files = explode ( ';' , $files );
2010-05-02 01:09:36 +04:00
}
2011-06-19 17:08:28 +04:00
2012-10-22 00:05:29 +04:00
if ( is_array ( $files )) {
self :: validateZipDownload ( $dir , $files );
2012-03-16 19:25:15 +04:00
$executionTime = intval ( ini_get ( 'max_execution_time' ));
set_time_limit ( 0 );
2010-04-25 16:21:04 +04:00
$zip = new ZipArchive ();
2012-10-31 02:37:31 +04:00
if ( $xsendfile ) {
2012-10-19 02:11:20 +04:00
$filename = OC_Helper :: tmpFileNoClean ( '.zip' );
2012-10-31 02:37:31 +04:00
} else {
2012-10-19 02:11:20 +04:00
$filename = OC_Helper :: tmpFile ( '.zip' );
2012-10-31 02:37:31 +04:00
}
if ( $zip -> open ( $filename , ZIPARCHIVE :: CREATE | ZIPARCHIVE :: OVERWRITE ) !== true ) {
2010-04-25 16:21:04 +04:00
exit ( " cannot open < $filename > \n " );
}
2012-10-22 00:05:29 +04:00
foreach ( $files as $file ) {
$file = $dir . '/' . $file ;
if ( \OC\Files\Filesystem :: is_file ( $file )) {
2012-10-24 17:32:29 +04:00
$tmpFile = \OC\Files\Filesystem :: toTmpFile ( $file );
2012-10-22 00:05:29 +04:00
self :: $tmpFiles [] = $tmpFile ;
$zip -> addFile ( $tmpFile , basename ( $file ));
} elseif ( \OC\Files\Filesystem :: is_dir ( $file )) {
self :: zipAddDir ( $file , $zip );
2010-04-25 16:21:04 +04:00
}
}
$zip -> close ();
2013-01-29 08:51:35 +04:00
$name = basename ( $dir ) . '.zip' ;
2012-03-16 19:25:15 +04:00
set_time_limit ( $executionTime );
2012-10-22 00:05:29 +04:00
} elseif ( \OC\Files\Filesystem :: is_dir ( $dir . '/' . $files )) {
self :: validateZipDownload ( $dir , $files );
2012-03-16 19:25:15 +04:00
$executionTime = intval ( ini_get ( 'max_execution_time' ));
set_time_limit ( 0 );
2010-04-25 16:21:04 +04:00
$zip = new ZipArchive ();
2012-10-31 02:37:31 +04:00
if ( $xsendfile ) {
2012-10-19 02:11:20 +04:00
$filename = OC_Helper :: tmpFileNoClean ( '.zip' );
2012-10-31 02:37:31 +04:00
} else {
2012-10-19 02:11:20 +04:00
$filename = OC_Helper :: tmpFile ( '.zip' );
2012-10-31 02:37:31 +04:00
}
if ( $zip -> open ( $filename , ZIPARCHIVE :: CREATE | ZIPARCHIVE :: OVERWRITE ) !== true ) {
2010-04-25 16:21:04 +04:00
exit ( " cannot open < $filename > \n " );
}
2012-10-22 00:05:29 +04:00
$file = $dir . '/' . $files ;
self :: zipAddDir ( $file , $zip );
2010-04-25 16:21:04 +04:00
$zip -> close ();
2013-01-29 08:51:35 +04:00
$name = $files . '.zip' ;
2012-03-16 19:25:15 +04:00
set_time_limit ( $executionTime );
2012-10-22 00:05:29 +04:00
} else {
$zip = false ;
$filename = $dir . '/' . $files ;
2013-01-29 08:51:35 +04:00
$name = $files ;
2010-04-25 16:21:04 +04:00
}
2012-11-29 21:01:21 +04:00
OC_Util :: obEnd ();
2012-12-28 00:49:48 +04:00
if ( $zip or \OC\Files\Filesystem :: isReadable ( $filename )) {
2012-12-17 19:23:12 +04:00
if ( preg_match ( " /MSIE/ " , $_SERVER [ " HTTP_USER_AGENT " ] ) ) {
2013-01-29 08:51:35 +04:00
header ( 'Content-Disposition: attachment; filename="' . rawurlencode ( $name ) . '"' );
2012-12-17 19:23:12 +04:00
} else {
2013-01-29 08:51:35 +04:00
header ( 'Content-Disposition: attachment; filename*=UTF-8\'\'' . rawurlencode ( $name )
. '; filename="' . rawurlencode ( $name ) . '"' );
2012-12-17 19:23:12 +04:00
}
2010-06-25 15:24:27 +04:00
header ( 'Content-Transfer-Encoding: binary' );
2012-02-14 02:48:05 +04:00
OC_Response :: disableCaching ();
2012-10-22 00:05:29 +04:00
if ( $zip ) {
2012-05-15 13:57:24 +04:00
ini_set ( 'zlib.output_compression' , 'off' );
2010-09-26 21:09:16 +04:00
header ( 'Content-Type: application/zip' );
2010-07-07 14:30:30 +04:00
header ( 'Content-Length: ' . filesize ( $filename ));
2012-10-19 02:11:20 +04:00
self :: addSendfileHeader ( $filename );
2010-07-07 14:30:30 +04:00
} else {
2012-11-18 17:07:52 +04:00
header ( 'Content-Type: ' . \OC\Files\Filesystem :: getMimeType ( $filename ));
2012-12-25 17:29:29 +04:00
header ( " Content-Length: " . \OC\Files\Filesystem :: filesize ( $filename ));
2012-12-28 01:53:32 +04:00
list ( $storage ) = \OC\Files\Filesystem :: resolvePath ( $filename );
2012-11-18 17:07:52 +04:00
if ( $storage instanceof \OC\File\Storage\Local ) {
self :: addSendfileHeader ( \OC\Files\Filesystem :: getLocalFile ( $filename ));
2012-10-31 02:37:31 +04:00
}
2010-07-07 14:30:30 +04:00
}
2012-10-22 00:05:29 +04:00
} elseif ( $zip or ! \OC\Files\Filesystem :: file_exists ( $filename )) {
2010-06-25 15:24:27 +04:00
header ( " HTTP/1.0 404 Not Found " );
2012-10-22 00:05:29 +04:00
$tmpl = new OC_Template ( '' , '404' , 'guest' );
2013-01-29 08:51:35 +04:00
$tmpl -> assign ( 'file' , $name );
2011-04-18 15:16:32 +04:00
$tmpl -> printPage ();
2012-10-22 00:05:29 +04:00
} else {
2010-06-25 15:24:27 +04:00
header ( " HTTP/1.0 403 Forbidden " );
die ( '403 Forbidden' );
2010-05-08 00:50:59 +04:00
}
2012-09-07 17:22:01 +04:00
if ( $only_header ) {
2012-05-25 02:48:10 +04:00
return ;
}
2012-10-22 00:05:29 +04:00
if ( $zip ) {
$handle = fopen ( $filename , 'r' );
2012-05-01 22:32:13 +04:00
if ( $handle ) {
2012-10-22 00:05:29 +04:00
$chunkSize = 8 * 1024 ; // 1 MB chunks
2012-05-01 22:32:13 +04:00
while ( ! feof ( $handle )) {
echo fread ( $handle , $chunkSize );
flush ();
}
}
2012-10-31 02:37:31 +04:00
if ( ! $xsendfile ) {
2012-10-19 02:11:20 +04:00
unlink ( $filename );
2012-10-31 02:37:31 +04:00
}
2010-06-25 15:24:27 +04:00
} else {
2012-10-10 15:18:36 +04:00
\OC\Files\Filesystem :: readfile ( $filename );
2010-06-25 15:24:27 +04:00
}
2012-10-22 00:05:29 +04:00
foreach ( self :: $tmpFiles as $tmpFile ) {
if ( file_exists ( $tmpFile ) and is_file ( $tmpFile )) {
2010-05-08 00:50:59 +04:00
unlink ( $tmpFile );
}
2010-04-25 16:21:04 +04:00
}
}
2010-05-04 00:26:34 +04:00
2012-10-19 02:11:20 +04:00
private static function addSendfileHeader ( $filename ) {
if ( isset ( $_SERVER [ 'MOD_X_SENDFILE_ENABLED' ])) {
header ( " X-Sendfile: " . $filename );
}
2012-10-31 02:37:31 +04:00
if ( isset ( $_SERVER [ 'MOD_X_ACCEL_REDIRECT_ENABLED' ])) {
2012-10-19 02:11:20 +04:00
header ( " X-Accel-Redirect: " . $filename );
2012-10-31 02:37:31 +04:00
}
2012-10-19 02:11:20 +04:00
}
2012-11-02 22:53:02 +04:00
public static function zipAddDir ( $dir , $zip , $internalDir = '' ) {
2011-09-18 22:57:05 +04:00
$dirname = basename ( $dir );
$zip -> addEmptyDir ( $internalDir . $dirname );
$internalDir .= $dirname .= '/' ;
2012-10-19 02:11:20 +04:00
$files = OC_Files :: getDirectoryContent ( $dir );
2012-09-07 17:22:01 +04:00
foreach ( $files as $file ) {
2011-09-18 22:57:05 +04:00
$filename = $file [ 'name' ];
$file = $dir . '/' . $filename ;
2012-11-18 17:07:52 +04:00
if ( \OC\Files\Filesystem :: is_file ( $file )) {
$tmpFile = \OC\Files\Filesystem :: toTmpFile ( $file );
2011-09-18 22:57:05 +04:00
OC_Files :: $tmpFiles [] = $tmpFile ;
2012-10-23 02:28:12 +04:00
$zip -> addFile ( $tmpFile , $internalDir . $filename );
2012-11-18 17:07:52 +04:00
} elseif ( \OC\Files\Filesystem :: is_dir ( $file )) {
2012-10-22 00:05:29 +04:00
self :: zipAddDir ( $file , $zip , $internalDir );
2011-09-18 22:57:05 +04:00
}
}
}
2012-10-22 00:05:29 +04:00
2012-03-16 19:25:15 +04:00
/**
2012-10-22 00:05:29 +04:00
* checks if the selected files are within the size constraint . If not , outputs an error page .
*
* @ param dir $dir
* @ param files $files
*/
2012-03-19 14:56:02 +04:00
static function validateZipDownload ( $dir , $files ) {
2012-10-22 00:05:29 +04:00
if ( ! OC_Config :: getValue ( 'allowZipDownload' , true )) {
2012-08-31 01:51:44 +04:00
$l = OC_L10N :: get ( 'lib' );
2012-03-19 14:56:02 +04:00
header ( " HTTP/1.0 409 Conflict " );
2012-10-22 00:05:29 +04:00
$tmpl = new OC_Template ( '' , 'error' , 'user' );
2012-03-19 14:56:02 +04:00
$errors = array (
array (
'error' => $l -> t ( 'ZIP download is turned off.' ),
'hint' => $l -> t ( 'Files need to be downloaded one by one.' ) . '<br/><a href="javascript:history.back()">' . $l -> t ( 'Back to Files' ) . '</a>' ,
)
);
$tmpl -> assign ( 'errors' , $errors );
$tmpl -> printPage ();
exit ;
}
2012-03-21 16:05:15 +04:00
$zipLimit = OC_Config :: getValue ( 'maxZipInputSize' , OC_Helper :: computerFileSize ( '800 MB' ));
2012-10-22 00:05:29 +04:00
if ( $zipLimit > 0 ) {
2012-03-16 19:25:15 +04:00
$totalsize = 0 ;
2012-10-22 00:05:29 +04:00
if ( is_array ( $files )) {
foreach ( $files as $file ) {
$totalsize += \OC\Files\Filesystem :: filesize ( $dir . '/' . $file );
2012-03-16 19:25:15 +04:00
}
2012-10-22 00:05:29 +04:00
} else {
$totalsize += \OC\Files\Filesystem :: filesize ( $dir . '/' . $files );
2012-03-16 19:25:15 +04:00
}
2012-10-22 00:05:29 +04:00
if ( $totalsize > $zipLimit ) {
2012-08-31 01:51:44 +04:00
$l = OC_L10N :: get ( 'lib' );
2012-03-16 19:25:15 +04:00
header ( " HTTP/1.0 409 Conflict " );
2012-10-22 00:05:29 +04:00
$tmpl = new OC_Template ( '' , 'error' , 'user' );
2012-03-16 19:25:15 +04:00
$errors = array (
array (
'error' => $l -> t ( 'Selected files too large to generate zip file.' ),
'hint' => 'Download the files in smaller chunks, seperately or kindly ask your administrator.<br/><a href="javascript:history.back()">' . $l -> t ( 'Back to Files' ) . '</a>' ,
)
);
$tmpl -> assign ( 'errors' , $errors );
$tmpl -> printPage ();
exit ;
}
}
}
2011-05-29 19:43:13 +04:00
/**
* set the maximum upload size limit for apache hosts using . htaccess
2012-10-22 00:05:29 +04:00
*
2011-05-29 19:43:13 +04:00
* @ param int size filesisze in bytes
2012-04-13 13:25:38 +04:00
* @ return false on failure , size on success
2011-05-29 19:43:13 +04:00
*/
2012-09-07 17:22:01 +04:00
static function setUploadLimit ( $size ) {
2012-04-13 13:25:38 +04:00
//don't allow user to break his config -- upper boundary
2012-10-22 00:05:29 +04:00
if ( $size > PHP_INT_MAX ) {
2012-04-13 13:25:38 +04:00
//max size is always 1 byte lower than computerFileSize returns
2012-10-22 00:05:29 +04:00
if ( $size > PHP_INT_MAX + 1 )
2012-04-13 13:25:38 +04:00
return false ;
2012-10-22 00:05:29 +04:00
$size -= 1 ;
2012-04-13 13:25:38 +04:00
} else {
2012-10-22 00:05:29 +04:00
$size = OC_Helper :: humanFileSize ( $size );
$size = substr ( $size , 0 , - 1 ); //strip the B
$size = str_replace ( ' ' , '' , $size ); //remove the space between the size and the postfix
2012-04-13 13:25:38 +04:00
}
2012-04-13 12:43:19 +04:00
2012-04-13 13:25:38 +04:00
//don't allow user to break his config -- broken or malicious size input
2012-10-22 00:05:29 +04:00
if ( intval ( $size ) == 0 ) {
2012-04-13 12:43:19 +04:00
return false ;
}
2012-10-22 00:05:29 +04:00
$htaccess = @ file_get_contents ( OC :: $SERVERROOT . '/.htaccess' ); //supress errors in case we don't have permissions for
if ( ! $htaccess ) {
2012-04-13 12:43:19 +04:00
return false ;
}
$phpValueKeys = array (
'upload_max_filesize' ,
'post_max_size'
);
2012-10-22 00:05:29 +04:00
foreach ( $phpValueKeys as $key ) {
$pattern = '/php_value ' . $key . ' (\S)*/' ;
$setting = 'php_value ' . $key . ' ' . $size ;
$hasReplaced = 0 ;
$content = preg_replace ( $pattern , $setting , $htaccess , 1 , $hasReplaced );
if ( $content !== null ) {
2012-04-13 12:43:19 +04:00
$htaccess = $content ;
}
2012-10-22 00:05:29 +04:00
if ( $hasReplaced == 0 ) {
2012-04-13 12:43:19 +04:00
$htaccess .= " \n " . $setting ;
}
}
2012-06-05 13:50:21 +04:00
//check for write permissions
2012-10-22 00:05:29 +04:00
if ( is_writable ( OC :: $SERVERROOT . '/.htaccess' )) {
file_put_contents ( OC :: $SERVERROOT . '/.htaccess' , $htaccess );
2012-08-29 10:38:33 +04:00
return OC_Helper :: computerFileSize ( $size );
2012-10-22 00:05:29 +04:00
} else {
OC_Log :: write ( 'files' , 'Can\'t write upload limit to ' . OC :: $SERVERROOT . '/.htaccess. Please check the file permissions' , OC_Log :: WARN );
}
2012-04-13 12:43:19 +04:00
return false ;
2011-05-29 19:43:13 +04:00
}
2010-04-25 16:21:04 +04:00
}