2010-03-10 12:03:40 +00:00
< ? php
/**
* ownCloud
*
2010-05-03 20:26:34 +00:00
* @ author Frank Karlitschek
2012-05-26 17:14:24 +00:00
* @ copyright 2012 Frank Karlitschek frank @ owncloud . org
2010-05-03 20:26:34 +00:00
*
2010-03-10 12:03:40 +00: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-03 20:26:34 +00:00
* License as published by the Free Software Foundation ; either
2010-03-10 12:03:40 +00:00
* version 3 of the License , or any later version .
2010-05-03 20:26:34 +00:00
*
2010-03-10 12:03:40 +00: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-03 20:26:34 +00:00
*
2011-02-09 14:50:27 +00:00
* You should have received a copy of the GNU Affero General Public
2010-03-10 12:03:40 +00:00
* License along with this library . If not , see < http :// www . gnu . org / licenses />.
2010-05-03 20:26:34 +00:00
*
2010-03-10 12:03:40 +00:00
*/
/**
* Class for fileserver access
*
*/
2011-07-29 19:36:03 +00:00
class OC_Files {
2010-05-07 20:50:59 +00:00
static $tmpFiles = array ();
2010-04-25 12:21:04 +00:00
2012-09-21 11:30:39 +00: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' ) {
$info = OCP\Share :: getItemsSharedWith ( 'file' , OC_Share_Backend_File :: FORMAT_FILE_APP_ROOT );
}
else {
$info = OCP\Share :: getItemSharedWith ( 'file' , '/' . $name , OC_Share_Backend_File :: FORMAT_FILE_APP );
}
$info = $info [ 0 ];
}
else {
$info = OC_FileCache :: get ( $path );
}
}
2010-04-25 12:21:04 +00:00
/**
* get the content of a directory
2012-06-19 20:50:28 +00:00
* @ param dir $directory path under datadirectory
2010-04-25 12:21:04 +00:00
*/
2012-09-07 13:22:01 +00:00
public static function getDirectoryContent ( $directory , $mimetype_filter = '' ) {
2012-08-16 23:22:26 +00:00
$directory = OC_Filesystem :: normalizePath ( $directory );
2012-09-07 13:22:01 +00:00
if ( $directory == '/' ) {
2012-08-16 23:22:26 +00:00
$directory = '' ;
}
2012-07-10 22:56:22 +00:00
$files = array ();
2012-08-22 16:31:54 +00:00
if (( $directory == '/Shared' || substr ( $directory , 0 , 8 ) == '/Shared/' ) && OC_App :: isEnabled ( 'files_sharing' )) {
2012-07-10 22:56:22 +00:00
if ( $directory == '/Shared' ) {
2012-07-25 20:33:08 +00:00
$files = OCP\Share :: getItemsSharedWith ( 'file' , OC_Share_Backend_File :: FORMAT_FILE_APP , array ( 'folder' => $directory , 'mimetype_filter' => $mimetype_filter ));
2012-07-10 22:56:22 +00:00
} else {
$pos = strpos ( $directory , '/' , 8 );
// Get shared folder name
if ( $pos !== false ) {
2012-08-16 16:20:14 +00:00
$itemTarget = substr ( $directory , 7 , $pos - 7 );
2012-07-10 22:56:22 +00:00
} else {
2012-08-16 16:20:14 +00:00
$itemTarget = substr ( $directory , 7 );
2012-07-10 22:56:22 +00:00
}
$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 );
2012-07-25 20:33:08 +00:00
foreach ( $files as & $file ) {
$file [ 'directory' ] = $directory ;
$file [ 'type' ] = ( $file [ 'mimetype' ] == 'httpd/unix-directory' ) ? 'dir' : 'file' ;
2012-08-31 21:31:28 +00:00
$permissions = OCP\Share :: PERMISSION_READ ;
// NOTE: Remove check when new encryption is merged
if ( ! $file [ 'encrypted' ]) {
$permissions |= OCP\Share :: PERMISSION_SHARE ;
}
2012-07-25 20:33:08 +00:00
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 ;
}
2012-08-22 16:31:54 +00:00
if ( $directory == '' && OC_App :: isEnabled ( 'files_sharing' )) {
2012-07-10 22:56:22 +00:00
// Add 'Shared' folder
$files = array_merge ( $files , OCP\Share :: getItemsSharedWith ( 'file' , OC_Share_Backend_File :: FORMAT_FILE_APP_ROOT ));
}
2010-04-25 12:21:04 +00:00
}
2012-01-31 15:33:47 +00:00
usort ( $files , " fileCmp " ); //TODO: remove this once ajax is merged
2011-11-09 17:41:57 +00:00
return $files ;
2010-04-25 12:21:04 +00:00
}
/**
* return the content of a file or return a zip file containning multiply files
*
* @ param dir $dir
2011-04-18 13:02:10 +00:00
* @ param file $file ; seperated list of files to download
2012-05-24 22:48:10 +00:00
* @ param boolean $only_header ; boolean to only send header of the request
2010-04-25 12:21:04 +00:00
*/
2012-09-07 13:22:01 +00:00
public static function get ( $dir , $files , $only_header = false ) {
if ( strpos ( $files , ';' )) {
2010-05-01 21:09:36 +00:00
$files = explode ( ';' , $files );
}
2011-06-19 13:08:28 +00:00
2012-09-07 13:22:01 +00:00
if ( is_array ( $files )) {
2012-03-19 10:56:02 +00:00
self :: validateZipDownload ( $dir , $files );
2012-03-16 15:25:15 +00:00
$executionTime = intval ( ini_get ( 'max_execution_time' ));
set_time_limit ( 0 );
2010-04-25 12:21:04 +00:00
$zip = new ZipArchive ();
2012-04-13 20:59:47 +00:00
$filename = OC_Helper :: tmpFile ( '.zip' );
2012-03-26 23:18:38 +00:00
if ( $zip -> open ( $filename , ZIPARCHIVE :: CREATE | ZIPARCHIVE :: OVERWRITE ) !== TRUE ) {
2010-04-25 12:21:04 +00:00
exit ( " cannot open < $filename > \n " );
}
2012-09-07 13:22:01 +00:00
foreach ( $files as $file ) {
2010-05-07 20:50:59 +00:00
$file = $dir . '/' . $file ;
2012-09-07 13:22:01 +00:00
if ( OC_Filesystem :: is_file ( $file )) {
2011-07-29 19:36:03 +00:00
$tmpFile = OC_Filesystem :: toTmpFile ( $file );
2010-05-07 20:50:59 +00:00
self :: $tmpFiles [] = $tmpFile ;
$zip -> addFile ( $tmpFile , basename ( $file ));
2012-09-07 13:22:01 +00:00
} elseif ( OC_Filesystem :: is_dir ( $file )) {
2011-09-18 18:57:05 +00:00
self :: zipAddDir ( $file , $zip );
2010-04-25 12:21:04 +00:00
}
}
$zip -> close ();
2012-03-16 15:25:15 +00:00
set_time_limit ( $executionTime );
2012-09-07 13:22:01 +00:00
} elseif ( OC_Filesystem :: is_dir ( $dir . '/' . $files )) {
2012-03-19 10:56:02 +00:00
self :: validateZipDownload ( $dir , $files );
2012-03-16 15:25:15 +00:00
$executionTime = intval ( ini_get ( 'max_execution_time' ));
set_time_limit ( 0 );
2010-04-25 12:21:04 +00:00
$zip = new ZipArchive ();
2012-04-13 20:59:47 +00:00
$filename = OC_Helper :: tmpFile ( '.zip' );
2012-03-26 23:18:38 +00:00
if ( $zip -> open ( $filename , ZIPARCHIVE :: CREATE | ZIPARCHIVE :: OVERWRITE ) !== TRUE ) {
2010-04-25 12:21:04 +00:00
exit ( " cannot open < $filename > \n " );
}
2010-05-07 20:50:59 +00:00
$file = $dir . '/' . $files ;
2011-09-18 18:57:05 +00:00
self :: zipAddDir ( $file , $zip );
2010-04-25 12:21:04 +00:00
$zip -> close ();
2012-03-16 15:25:15 +00:00
set_time_limit ( $executionTime );
2010-04-25 12:21:04 +00:00
} else {
$zip = false ;
2010-05-07 20:50:59 +00:00
$filename = $dir . '/' . $files ;
2010-04-25 12:21:04 +00:00
}
2012-05-05 14:49:22 +00:00
@ ob_end_clean ();
2012-09-07 13:22:01 +00:00
if ( $zip or OC_Filesystem :: is_readable ( $filename )) {
2011-08-12 10:03:59 +00:00
header ( 'Content-Disposition: attachment; filename="' . basename ( $filename ) . '"' );
2010-06-25 11:24:27 +00:00
header ( 'Content-Transfer-Encoding: binary' );
2012-02-13 22:48:05 +00:00
OC_Response :: disableCaching ();
2012-09-07 13:22:01 +00:00
if ( $zip ) {
2012-05-15 09:57:24 +00:00
ini_set ( 'zlib.output_compression' , 'off' );
2010-09-26 17:09:16 +00:00
header ( 'Content-Type: application/zip' );
2010-07-07 10:30:30 +00:00
header ( 'Content-Length: ' . filesize ( $filename ));
} else {
2012-07-10 22:56:22 +00:00
header ( 'Content-Type: ' . OC_Filesystem :: getMimeType ( $filename ));
2010-07-07 10:30:30 +00:00
}
2012-09-07 13:22:01 +00:00
} elseif ( $zip or ! OC_Filesystem :: file_exists ( $filename )) {
2010-06-25 11:24:27 +00:00
header ( " HTTP/1.0 404 Not Found " );
2011-07-29 19:36:03 +00:00
$tmpl = new OC_Template ( '' , '404' , 'guest' );
2011-04-18 11:16:32 +00:00
$tmpl -> assign ( 'file' , $filename );
$tmpl -> printPage ();
2010-06-25 11:24:27 +00:00
} else {
header ( " HTTP/1.0 403 Forbidden " );
die ( '403 Forbidden' );
2010-05-07 20:50:59 +00:00
}
2012-09-07 13:22:01 +00:00
if ( $only_header ) {
2012-05-24 22:48:10 +00:00
if ( ! $zip )
header ( " Content-Length: " . OC_Filesystem :: filesize ( $filename ));
return ;
}
2012-09-07 13:22:01 +00:00
if ( $zip ) {
2012-05-01 18:32:13 +00:00
$handle = fopen ( $filename , 'r' );
if ( $handle ) {
$chunkSize = 8 * 1024 ; // 1 MB chunks
while ( ! feof ( $handle )) {
echo fread ( $handle , $chunkSize );
flush ();
}
}
2010-06-25 11:24:27 +00:00
unlink ( $filename );
} else {
2011-07-29 19:36:03 +00:00
OC_Filesystem :: readfile ( $filename );
2010-06-25 11:24:27 +00:00
}
2012-09-07 13:22:01 +00:00
foreach ( self :: $tmpFiles as $tmpFile ) {
if ( file_exists ( $tmpFile ) and is_file ( $tmpFile )) {
2010-05-07 20:50:59 +00:00
unlink ( $tmpFile );
}
2010-04-25 12:21:04 +00:00
}
}
2010-05-03 20:26:34 +00:00
2012-09-07 13:22:01 +00:00
public static function zipAddDir ( $dir , $zip , $internalDir = '' ) {
2011-09-18 18:57:05 +00:00
$dirname = basename ( $dir );
$zip -> addEmptyDir ( $internalDir . $dirname );
$internalDir .= $dirname .= '/' ;
$files = OC_Files :: getdirectorycontent ( $dir );
2012-09-07 13:22:01 +00:00
foreach ( $files as $file ) {
2011-09-18 18:57:05 +00:00
$filename = $file [ 'name' ];
$file = $dir . '/' . $filename ;
2012-09-07 13:22:01 +00:00
if ( OC_Filesystem :: is_file ( $file )) {
2011-09-18 18:57:05 +00:00
$tmpFile = OC_Filesystem :: toTmpFile ( $file );
OC_Files :: $tmpFiles [] = $tmpFile ;
$zip -> addFile ( $tmpFile , $internalDir . $filename );
2012-09-07 13:22:01 +00:00
} elseif ( OC_Filesystem :: is_dir ( $file )) {
2011-09-18 18:57:05 +00:00
self :: zipAddDir ( $file , $zip , $internalDir );
}
}
}
2010-04-25 12:21:04 +00:00
/**
* move a file or folder
*
* @ param dir $sourceDir
* @ param file $source
* @ param dir $targetDir
* @ param file $target
*/
2012-09-07 13:22:01 +00:00
public static function move ( $sourceDir , $source , $targetDir , $target ) {
if ( OC_User :: isLoggedIn () && ( $sourceDir != '' || $source != 'Shared' )) {
2012-01-14 20:13:46 +00:00
$targetFile = self :: normalizePath ( $targetDir . '/' . $target );
$sourceFile = self :: normalizePath ( $sourceDir . '/' . $source );
2011-07-29 19:36:03 +00:00
return OC_Filesystem :: rename ( $sourceFile , $targetFile );
2012-06-29 13:23:04 +00:00
} else {
return false ;
2010-05-11 18:35:29 +00:00
}
}
2010-05-03 20:26:34 +00:00
2010-05-11 18:35:29 +00:00
/**
* copy a file or folder
*
* @ param dir $sourceDir
* @ param file $source
* @ param dir $targetDir
* @ param file $target
*/
2012-09-07 13:22:01 +00:00
public static function copy ( $sourceDir , $source , $targetDir , $target ) {
if ( OC_User :: isLoggedIn ()) {
2010-05-11 18:35:29 +00:00
$targetFile = $targetDir . '/' . $target ;
$sourceFile = $sourceDir . '/' . $source ;
2011-07-29 19:36:03 +00:00
return OC_Filesystem :: copy ( $sourceFile , $targetFile );
2010-04-25 12:21:04 +00:00
}
}
2010-05-03 20:26:34 +00:00
2010-04-25 12:21:04 +00:00
/**
* create a new file or folder
*
* @ param dir $dir
* @ param file $name
* @ param type $type
*/
2012-09-07 13:22:01 +00:00
public static function newFile ( $dir , $name , $type ) {
if ( OC_User :: isLoggedIn ()) {
2010-05-07 20:50:59 +00:00
$file = $dir . '/' . $name ;
2012-09-07 13:22:01 +00:00
if ( $type == 'dir' ) {
2011-07-29 19:36:03 +00:00
return OC_Filesystem :: mkdir ( $file );
2012-09-07 13:22:01 +00:00
} elseif ( $type == 'file' ) {
2011-07-29 19:36:03 +00:00
$fileHandle = OC_Filesystem :: fopen ( $file , 'w' );
2012-09-07 13:22:01 +00:00
if ( $fileHandle ) {
2010-05-11 18:35:29 +00:00
fclose ( $fileHandle );
return true ;
} else {
return false ;
}
2010-04-25 12:21:04 +00:00
}
}
}
2010-05-03 20:26:34 +00:00
2010-04-25 12:21:04 +00:00
/**
* deletes a file or folder
*
* @ param dir $dir
* @ param file $name
*/
2012-09-07 13:22:01 +00:00
public static function delete ( $dir , $file ) {
2012-06-04 08:42:09 +00:00
if ( OC_User :: isLoggedIn () && ( $dir != '' || $file != 'Shared' )) {
2010-05-07 20:50:59 +00:00
$file = $dir . '/' . $file ;
2011-08-15 20:54:38 +00:00
return OC_Filesystem :: unlink ( $file );
2010-04-25 12:21:04 +00:00
}
}
2010-05-03 20:26:34 +00:00
2012-03-16 15:25:15 +00: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 10:56:02 +00:00
static function validateZipDownload ( $dir , $files ) {
2012-03-21 12:05:15 +00:00
if ( ! OC_Config :: getValue ( 'allowZipDownload' , true )) {
2012-08-30 21:51:44 +00:00
$l = OC_L10N :: get ( 'lib' );
2012-03-19 10:56:02 +00: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 12:05:15 +00:00
$zipLimit = OC_Config :: getValue ( 'maxZipInputSize' , OC_Helper :: computerFileSize ( '800 MB' ));
2012-03-16 15:25:15 +00:00
if ( $zipLimit > 0 ) {
$totalsize = 0 ;
2012-09-07 13:22:01 +00:00
if ( is_array ( $files )) {
foreach ( $files as $file ) {
2012-03-16 15:25:15 +00:00
$totalsize += OC_Filesystem :: filesize ( $dir . '/' . $file );
}
} else {
$totalsize += OC_Filesystem :: filesize ( $dir . '/' . $files );
}
if ( $totalsize > $zipLimit ) {
2012-08-30 21:51:44 +00:00
$l = OC_L10N :: get ( 'lib' );
2012-03-16 15:25:15 +00: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 13:04:13 +00:00
/**
* try to detect the mime type of a file
*
2010-05-07 20:50:59 +00:00
* @ param string path
2010-04-25 13:04:13 +00:00
* @ return string guessed mime type
*/
2012-09-07 13:22:01 +00:00
static function getMimeType ( $path ) {
2011-07-29 19:36:03 +00:00
return OC_Filesystem :: getMimeType ( $path );
2010-04-25 16:27:02 +00:00
}
2011-03-01 22:20:16 +00:00
2010-07-07 10:30:30 +00:00
/**
* get a file tree
*
* @ param string path
* @ return array
*/
2012-09-07 13:22:01 +00:00
static function getTree ( $path ) {
2011-07-29 19:36:03 +00:00
return OC_Filesystem :: getTree ( $path );
2010-07-07 10:30:30 +00:00
}
2011-03-01 22:20:16 +00:00
2010-07-06 10:50:37 +00: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-09-07 13:22:01 +00:00
static function pull ( $source , $token , $dir , $file ) {
2011-10-19 21:38:35 +00:00
$tmpfile = tempnam ( get_temp_dir (), 'remoteCloudFile' );
2010-07-06 10:50:37 +00: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-09-07 13:22:01 +00:00
if ( $httpCode == 200 or $httpCode == 0 ) {
2011-07-29 19:36:03 +00:00
OC_Filesystem :: fromTmpFile ( $tmpfile , $dir . '/' . $file );
2010-07-06 10:50:37 +00:00
return true ;
} else {
return false ;
}
}
2012-03-16 15:25:15 +00:00
2011-05-29 15:43:13 +00:00
/**
* set the maximum upload size limit for apache hosts using . htaccess
* @ param int size filesisze in bytes
2012-04-13 09:25:38 +00:00
* @ return false on failure , size on success
2011-05-29 15:43:13 +00:00
*/
2012-09-07 13:22:01 +00:00
static function setUploadLimit ( $size ) {
2012-04-13 09:25:38 +00: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 08:43:19 +00:00
2012-04-13 09:25:38 +00:00
//don't allow user to break his config -- broken or malicious size input
2012-04-13 08:43:19 +00: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 09:50:21 +00:00
//check for write permissions
if ( is_writable ( OC :: $SERVERROOT . '/.htaccess' )) {
file_put_contents ( OC :: $SERVERROOT . '/.htaccess' , $htaccess );
2012-08-29 06:38:33 +00:00
return OC_Helper :: computerFileSize ( $size );
2012-06-05 09:50:21 +00:00
} else { OC_Log :: write ( 'files' , 'Can\'t write upload limit to ' . OC :: $SERVERROOT . '/.htaccess. Please check the file permissions' , OC_Log :: WARN ); }
2012-08-29 06:38:33 +00:00
2012-04-13 08:43:19 +00:00
return false ;
2011-05-29 15:43:13 +00:00
}
2012-01-14 20:13:46 +00:00
/**
* normalize a path , removing any double , add leading / , etc
* @ param string $path
* @ return string
*/
2012-09-07 13:22:01 +00:00
static public function normalizePath ( $path ) {
2012-01-14 20:13:46 +00:00
$path = '/' . $path ;
$old = '' ;
2012-09-07 13:22:01 +00:00
while ( $old != $path ) { //replace any multiplicity of slashes with a single one
2012-01-14 20:13:46 +00:00
$old = $path ;
$path = str_replace ( '//' , '/' , $path );
}
return $path ;
}
2010-04-25 12:21:04 +00:00
}
2012-01-31 15:33:47 +00:00
2012-09-07 13:22:01 +00:00
function fileCmp ( $a , $b ) {
if ( $a [ 'type' ] == 'dir' and $b [ 'type' ] != 'dir' ) {
2012-01-31 15:33:47 +00:00
return - 1 ;
2012-09-07 13:22:01 +00:00
} elseif ( $a [ 'type' ] != 'dir' and $b [ 'type' ] == 'dir' ) {
2012-01-31 15:33:47 +00:00
return 1 ;
} else {
return strnatcasecmp ( $a [ 'name' ], $b [ 'name' ]);
}
}