2010-03-10 15:03:40 +03:00
< ? php
/**
* ownCloud
*
2010-05-04 00:26:34 +04:00
* @ author Frank Karlitschek
2012-05-26 21:14:24 +04:00
* @ copyright 2012 Frank Karlitschek frank @ owncloud . org
2010-05-04 00:26:34 +04:00
*
2010-03-10 15:03:40 +03:00
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
2010-05-04 00:26:34 +04:00
* License as published by the Free Software Foundation ; either
2010-03-10 15:03:40 +03:00
* version 3 of the License , or any later version .
2010-05-04 00:26:34 +04:00
*
2010-03-10 15:03:40 +03:00
* 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 .
2010-05-04 00:26:34 +04:00
*
2011-02-09 17:50:27 +03:00
* You should have received a copy of the GNU Affero General Public
2010-03-10 15:03:40 +03:00
* License along with this library . If not , see < http :// www . gnu . org / licenses />.
2010-05-04 00:26:34 +04:00
*
2010-03-10 15:03:40 +03:00
*/
/**
* Class for fileserver access
*
*/
2011-07-29 23:36:03 +04:00
class OC_Files {
2010-05-08 00:50:59 +04:00
static $tmpFiles = array ();
2010-04-25 16:21:04 +04:00
2012-10-16 19:57:07 +04:00
/**
* get the filesystem info
* @ param string path
* @ return array
*
* returns an associative array with the following keys :
* - size
* - mtime
* - ctime
* - mimetype
* - encrypted
* - versioned
*/
public static function getFileInfo ( $path ) {
if (( $path == '/Shared' || substr ( $path , 0 , 8 ) == '/Shared/' ) && OC_App :: isEnabled ( 'files_sharing' )) {
if ( $path == '/Shared' ) {
list ( $info ) = OCP\Share :: getItemsSharedWith ( 'file' , OC_Share_Backend_File :: FORMAT_FILE_APP_ROOT );
} else {
$info [ 'size' ] = OC_Filesystem :: filesize ( $path );
$info [ 'mtime' ] = OC_Filesystem :: filemtime ( $path );
$info [ 'ctime' ] = OC_Filesystem :: filectime ( $path );
$info [ 'mimetype' ] = OC_Filesystem :: getMimeType ( $path );
$info [ 'encrypted' ] = false ;
$info [ 'versioned' ] = false ;
}
} else {
$info = OC_FileCache :: get ( $path );
}
return $info ;
}
2010-04-25 16:21:04 +04:00
/**
* get the content of a directory
2012-06-20 00:50:28 +04:00
* @ param dir $directory path under datadirectory
2010-04-25 16:21:04 +04:00
*/
2012-10-16 19:57:07 +04:00
public static function getDirectoryContent ( $directory , $mimetype_filter = '' ) {
$directory = OC_Filesystem :: normalizePath ( $directory );
if ( $directory == '/' ) {
$directory = '' ;
}
$files = array ();
if (( $directory == '/Shared' || substr ( $directory , 0 , 8 ) == '/Shared/' ) && OC_App :: isEnabled ( 'files_sharing' )) {
if ( $directory == '/Shared' ) {
$files = OCP\Share :: getItemsSharedWith ( 'file' , OC_Share_Backend_File :: FORMAT_FILE_APP , array ( 'folder' => $directory , 'mimetype_filter' => $mimetype_filter ));
} else {
$pos = strpos ( $directory , '/' , 8 );
// Get shared folder name
if ( $pos !== false ) {
$itemTarget = substr ( $directory , 7 , $pos - 7 );
} else {
$itemTarget = substr ( $directory , 7 );
}
$files = OCP\Share :: getItemSharedWith ( 'folder' , $itemTarget , OC_Share_Backend_File :: FORMAT_FILE_APP , array ( 'folder' => $directory , 'mimetype_filter' => $mimetype_filter ));
}
} else {
$files = OC_FileCache :: getFolderContent ( $directory , false , $mimetype_filter );
foreach ( $files as & $file ) {
$file [ 'directory' ] = $directory ;
$file [ 'type' ] = ( $file [ 'mimetype' ] == 'httpd/unix-directory' ) ? 'dir' : 'file' ;
$permissions = OCP\Share :: PERMISSION_READ ;
// NOTE: Remove check when new encryption is merged
if ( ! $file [ 'encrypted' ]) {
$permissions |= OCP\Share :: PERMISSION_SHARE ;
}
if ( $file [ 'type' ] == 'dir' && $file [ 'writable' ]) {
$permissions |= OCP\Share :: PERMISSION_CREATE ;
}
if ( $file [ 'writable' ]) {
$permissions |= OCP\Share :: PERMISSION_UPDATE | OCP\Share :: PERMISSION_DELETE ;
}
$file [ 'permissions' ] = $permissions ;
}
if ( $directory == '' && OC_App :: isEnabled ( 'files_sharing' )) {
// Add 'Shared' folder
$files = array_merge ( $files , OCP\Share :: getItemsSharedWith ( 'file' , OC_Share_Backend_File :: FORMAT_FILE_APP_ROOT ));
}
2010-04-25 16:21:04 +04:00
}
2012-01-31 19:33:47 +04:00
usort ( $files , " fileCmp " ); //TODO: remove this once ajax is merged
2011-11-09 21:41:57 +04:00
return $files ;
2010-04-25 16:21:04 +04:00
}
2012-10-16 19:57:07 +04:00
public static function searchByMime ( $mimetype_filter ) {
$files = array ();
$dirs_to_check = array ( '' );
while ( ! empty ( $dirs_to_check )) {
// get next subdir to check
$dir = array_pop ( $dirs_to_check );
$dir_content = self :: getDirectoryContent ( $dir , $mimetype_filter );
foreach ( $dir_content as $file ) {
if ( $file [ 'type' ] == 'file' ) {
$files [] = $dir . '/' . $file [ 'name' ];
}
else {
$dirs_to_check [] = $dir . '/' . $file [ 'name' ];
}
}
}
return $files ;
}
2010-04-25 16:21:04 +04:00
/**
* return the content of a file or return a zip file containning multiply files
*
* @ param dir $dir
2011-04-18 17:02:10 +04:00
* @ param file $file ; seperated list of files to download
2012-05-25 02:48:10 +04:00
* @ param boolean $only_header ; boolean to only send header of the request
2010-04-25 16:21:04 +04:00
*/
2012-10-16 19:57:07 +04:00
public static function get ( $dir , $files , $only_header = false ) {
if ( strpos ( $files , ';' )) {
2010-05-02 01:09:36 +04:00
$files = explode ( ';' , $files );
}
2011-06-19 17:08:28 +04:00
2012-10-16 19:57:07 +04:00
if ( is_array ( $files )) {
2012-03-19 14:56:02 +04:00
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-04-14 00:59:47 +04:00
$filename = OC_Helper :: tmpFile ( '.zip' );
2012-03-27 03:18:38 +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-16 19:57:07 +04:00
foreach ( $files as $file ) {
2010-05-08 00:50:59 +04:00
$file = $dir . '/' . $file ;
2012-10-16 19:57:07 +04:00
if ( OC_Filesystem :: is_file ( $file )) {
2011-07-29 23:36:03 +04:00
$tmpFile = OC_Filesystem :: toTmpFile ( $file );
2010-05-08 00:50:59 +04:00
self :: $tmpFiles [] = $tmpFile ;
$zip -> addFile ( $tmpFile , basename ( $file ));
2012-10-16 19:57:07 +04:00
} elseif ( OC_Filesystem :: is_dir ( $file )) {
2011-09-18 22:57:05 +04:00
self :: zipAddDir ( $file , $zip );
2010-04-25 16:21:04 +04:00
}
}
$zip -> close ();
2012-03-16 19:25:15 +04:00
set_time_limit ( $executionTime );
2012-10-16 19:57:07 +04:00
} elseif ( OC_Filesystem :: is_dir ( $dir . '/' . $files )) {
2012-03-19 14:56:02 +04:00
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-04-14 00:59:47 +04:00
$filename = OC_Helper :: tmpFile ( '.zip' );
2012-03-27 03:18:38 +04:00
if ( $zip -> open ( $filename , ZIPARCHIVE :: CREATE | ZIPARCHIVE :: OVERWRITE ) !== TRUE ) {
2010-04-25 16:21:04 +04:00
exit ( " cannot open < $filename > \n " );
}
2010-05-08 00:50:59 +04:00
$file = $dir . '/' . $files ;
2011-09-18 22:57:05 +04:00
self :: zipAddDir ( $file , $zip );
2010-04-25 16:21:04 +04:00
$zip -> close ();
2012-03-16 19:25:15 +04:00
set_time_limit ( $executionTime );
2010-04-25 16:21:04 +04:00
} else {
$zip = false ;
2010-05-08 00:50:59 +04:00
$filename = $dir . '/' . $files ;
2010-04-25 16:21:04 +04:00
}
2012-05-05 18:49:22 +04:00
@ ob_end_clean ();
2012-10-16 19:57:07 +04:00
if ( $zip or OC_Filesystem :: is_readable ( $filename )) {
2011-08-12 14:03:59 +04:00
header ( 'Content-Disposition: attachment; filename="' . basename ( $filename ) . '"' );
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-16 19:57:07 +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 ));
} else {
2012-10-16 19:57:07 +04:00
header ( 'Content-Type: ' . OC_Filesystem :: getMimeType ( $filename ));
2010-07-07 14:30:30 +04:00
}
2012-10-16 19:57:07 +04:00
} elseif ( $zip or ! OC_Filesystem :: file_exists ( $filename )) {
2010-06-25 15:24:27 +04:00
header ( " HTTP/1.0 404 Not Found " );
2011-07-29 23:36:03 +04:00
$tmpl = new OC_Template ( '' , '404' , 'guest' );
2011-04-18 15:16:32 +04:00
$tmpl -> assign ( 'file' , $filename );
$tmpl -> printPage ();
2010-06-25 15:24:27 +04:00
} else {
header ( " HTTP/1.0 403 Forbidden " );
die ( '403 Forbidden' );
2010-05-08 00:50:59 +04:00
}
2012-10-16 19:57:07 +04:00
if ( $only_header ) {
2012-05-25 02:48:10 +04:00
if ( ! $zip )
header ( " Content-Length: " . OC_Filesystem :: filesize ( $filename ));
return ;
}
2012-10-16 19:57:07 +04:00
if ( $zip ) {
2012-05-01 22:32:13 +04:00
$handle = fopen ( $filename , 'r' );
if ( $handle ) {
$chunkSize = 8 * 1024 ; // 1 MB chunks
while ( ! feof ( $handle )) {
echo fread ( $handle , $chunkSize );
flush ();
}
}
2010-06-25 15:24:27 +04:00
unlink ( $filename );
} else {
2011-07-29 23:36:03 +04:00
OC_Filesystem :: readfile ( $filename );
2010-06-25 15:24:27 +04:00
}
2012-10-16 19:57:07 +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-16 19:57:07 +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 .= '/' ;
$files = OC_Files :: getdirectorycontent ( $dir );
2012-10-16 19:57:07 +04:00
foreach ( $files as $file ) {
2011-09-18 22:57:05 +04:00
$filename = $file [ 'name' ];
$file = $dir . '/' . $filename ;
2012-10-16 19:57:07 +04:00
if ( OC_Filesystem :: is_file ( $file )) {
2011-09-18 22:57:05 +04:00
$tmpFile = OC_Filesystem :: toTmpFile ( $file );
OC_Files :: $tmpFiles [] = $tmpFile ;
$zip -> addFile ( $tmpFile , $internalDir . $filename );
2012-10-16 19:57:07 +04:00
} elseif ( OC_Filesystem :: is_dir ( $file )) {
2011-09-18 22:57:05 +04:00
self :: zipAddDir ( $file , $zip , $internalDir );
}
}
}
2010-04-25 16:21:04 +04:00
/**
* move a file or folder
*
* @ param dir $sourceDir
* @ param file $source
* @ param dir $targetDir
* @ param file $target
*/
2012-10-16 19:57:07 +04:00
public static function move ( $sourceDir , $source , $targetDir , $target ) {
if ( OC_User :: isLoggedIn () && ( $sourceDir != '' || $source != 'Shared' )) {
2012-01-15 00:13:46 +04:00
$targetFile = self :: normalizePath ( $targetDir . '/' . $target );
$sourceFile = self :: normalizePath ( $sourceDir . '/' . $source );
2011-07-29 23:36:03 +04:00
return OC_Filesystem :: rename ( $sourceFile , $targetFile );
2012-06-29 17:23:04 +04:00
} else {
return false ;
2010-05-11 22:35:29 +04:00
}
}
2010-05-04 00:26:34 +04:00
2010-05-11 22:35:29 +04:00
/**
* copy a file or folder
*
* @ param dir $sourceDir
* @ param file $source
* @ param dir $targetDir
* @ param file $target
*/
2012-10-16 19:57:07 +04:00
public static function copy ( $sourceDir , $source , $targetDir , $target ) {
if ( OC_User :: isLoggedIn ()) {
2010-05-11 22:35:29 +04:00
$targetFile = $targetDir . '/' . $target ;
$sourceFile = $sourceDir . '/' . $source ;
2011-07-29 23:36:03 +04:00
return OC_Filesystem :: copy ( $sourceFile , $targetFile );
2010-04-25 16:21:04 +04:00
}
}
2010-05-04 00:26:34 +04:00
2010-04-25 16:21:04 +04:00
/**
* create a new file or folder
*
* @ param dir $dir
* @ param file $name
* @ param type $type
*/
2012-10-16 19:57:07 +04:00
public static function newFile ( $dir , $name , $type ) {
if ( OC_User :: isLoggedIn ()) {
2010-05-08 00:50:59 +04:00
$file = $dir . '/' . $name ;
2012-10-16 19:57:07 +04:00
if ( $type == 'dir' ) {
2011-07-29 23:36:03 +04:00
return OC_Filesystem :: mkdir ( $file );
2012-10-16 19:57:07 +04:00
} elseif ( $type == 'file' ) {
2011-07-29 23:36:03 +04:00
$fileHandle = OC_Filesystem :: fopen ( $file , 'w' );
2012-10-16 19:57:07 +04:00
if ( $fileHandle ) {
2010-05-11 22:35:29 +04:00
fclose ( $fileHandle );
return true ;
} else {
return false ;
}
2010-04-25 16:21:04 +04:00
}
}
}
2010-05-04 00:26:34 +04:00
2010-04-25 16:21:04 +04:00
/**
* deletes a file or folder
*
* @ param dir $dir
* @ param file $name
*/
2012-10-16 19:57:07 +04:00
public static function delete ( $dir , $file ) {
2012-06-04 12:42:09 +04:00
if ( OC_User :: isLoggedIn () && ( $dir != '' || $file != 'Shared' )) {
2010-05-08 00:50:59 +04:00
$file = $dir . '/' . $file ;
2011-08-16 00:54:38 +04:00
return OC_Filesystem :: unlink ( $file );
2010-04-25 16:21:04 +04:00
}
}
2010-05-04 00:26:34 +04:00
2012-03-16 19:25:15 +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-03-21 16:05:15 +04:00
if ( ! OC_Config :: getValue ( 'allowZipDownload' , true )) {
2012-10-16 19:57:07 +04:00
$l = OC_L10N :: get ( 'lib' );
2012-03-19 14:56:02 +04:00
header ( " HTTP/1.0 409 Conflict " );
$tmpl = new OC_Template ( '' , 'error' , 'user' );
$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-03-16 19:25:15 +04:00
if ( $zipLimit > 0 ) {
$totalsize = 0 ;
2012-10-16 19:57:07 +04:00
if ( is_array ( $files )) {
foreach ( $files as $file ) {
2012-03-16 19:25:15 +04:00
$totalsize += OC_Filesystem :: filesize ( $dir . '/' . $file );
}
} else {
$totalsize += OC_Filesystem :: filesize ( $dir . '/' . $files );
}
if ( $totalsize > $zipLimit ) {
2012-10-16 19:57:07 +04:00
$l = OC_L10N :: get ( 'lib' );
2012-03-16 19:25:15 +04:00
header ( " HTTP/1.0 409 Conflict " );
$tmpl = new OC_Template ( '' , 'error' , 'user' );
$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 ;
}
}
}
2010-04-25 17:04:13 +04:00
/**
* try to detect the mime type of a file
*
2010-05-08 00:50:59 +04:00
* @ param string path
2010-04-25 17:04:13 +04:00
* @ return string guessed mime type
*/
2012-10-16 19:57:07 +04:00
static function getMimeType ( $path ) {
2011-07-29 23:36:03 +04:00
return OC_Filesystem :: getMimeType ( $path );
2010-04-25 20:27:02 +04:00
}
2011-03-02 01:20:16 +03:00
2010-07-07 14:30:30 +04:00
/**
* get a file tree
*
* @ param string path
* @ return array
*/
2012-10-16 19:57:07 +04:00
static function getTree ( $path ) {
2011-07-29 23:36:03 +04:00
return OC_Filesystem :: getTree ( $path );
2010-07-07 14:30:30 +04:00
}
2011-03-02 01:20:16 +03:00
2010-07-06 14:50:37 +04:00
/**
* pull a file from a remote server
* @ param string source
* @ param string token
* @ param string dir
* @ param string file
* @ return string guessed mime type
*/
2012-10-16 19:57:07 +04:00
static function pull ( $source , $token , $dir , $file ) {
2011-10-20 01:38:35 +04:00
$tmpfile = tempnam ( get_temp_dir (), 'remoteCloudFile' );
2010-07-06 14:50:37 +04:00
$fp = fopen ( $tmpfile , 'w+' );
$url = $source .= " /files/pull.php?token= $token " ;
$ch = curl_init ();
curl_setopt ( $ch , CURLOPT_URL , $url );
curl_setopt ( $ch , CURLOPT_FILE , $fp );
curl_exec ( $ch );
fclose ( $fp );
$info = curl_getinfo ( $ch );
$httpCode = $info [ 'http_code' ];
curl_close ( $ch );
2012-10-16 19:57:07 +04:00
if ( $httpCode == 200 or $httpCode == 0 ) {
2011-07-29 23:36:03 +04:00
OC_Filesystem :: fromTmpFile ( $tmpfile , $dir . '/' . $file );
2010-07-06 14:50:37 +04:00
return true ;
} else {
return false ;
}
}
2012-03-16 19:25:15 +04:00
2011-05-29 19:43:13 +04:00
/**
* set the maximum upload size limit for apache hosts using . htaccess
* @ 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-10-16 19:57:07 +04:00
static function setUploadLimit ( $size ) {
2012-04-13 13:25:38 +04:00
//don't allow user to break his config -- upper boundary
if ( $size > PHP_INT_MAX ) {
//max size is always 1 byte lower than computerFileSize returns
if ( $size > PHP_INT_MAX + 1 )
return false ;
$size -= 1 ;
} else {
$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 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-04-13 12:43:19 +04:00
if ( intval ( $size ) == 0 ) {
return false ;
}
$htaccess = @ file_get_contents ( OC :: $SERVERROOT . '/.htaccess' ); //supress errors in case we don't have permissions for
if ( ! $htaccess ) {
return false ;
}
$phpValueKeys = array (
'upload_max_filesize' ,
'post_max_size'
);
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 ) {
$htaccess = $content ;
}
if ( $hasReplaced == 0 ) {
$htaccess .= " \n " . $setting ;
}
}
2012-06-05 13:50:21 +04:00
//check for write permissions
if ( is_writable ( OC :: $SERVERROOT . '/.htaccess' )) {
file_put_contents ( OC :: $SERVERROOT . '/.htaccess' , $htaccess );
2012-10-16 19:57:07 +04:00
return OC_Helper :: computerFileSize ( $size );
2012-06-05 13:50:21 +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-10-16 19:57:07 +04:00
2012-04-13 12:43:19 +04:00
return false ;
2011-05-29 19:43:13 +04:00
}
2012-01-15 00:13:46 +04:00
/**
* normalize a path , removing any double , add leading / , etc
* @ param string $path
* @ return string
*/
2012-10-16 19:57:07 +04:00
static public function normalizePath ( $path ) {
2012-01-15 00:13:46 +04:00
$path = '/' . $path ;
$old = '' ;
2012-10-16 19:57:07 +04:00
while ( $old != $path ) { //replace any multiplicity of slashes with a single one
2012-01-15 00:13:46 +04:00
$old = $path ;
$path = str_replace ( '//' , '/' , $path );
}
return $path ;
}
2010-04-25 16:21:04 +04:00
}
2012-01-31 19:33:47 +04:00
2012-10-16 19:57:07 +04:00
function fileCmp ( $a , $b ) {
if ( $a [ 'type' ] == 'dir' and $b [ 'type' ] != 'dir' ) {
2012-01-31 19:33:47 +04:00
return - 1 ;
2012-10-16 19:57:07 +04:00
} elseif ( $a [ 'type' ] != 'dir' and $b [ 'type' ] == 'dir' ) {
2012-01-31 19:33:47 +04:00
return 1 ;
} else {
return strnatcasecmp ( $a [ 'name' ], $b [ 'name' ]);
}
}