diff --git a/build/ifm.js b/build/ifm.js new file mode 100644 index 0000000..f5520dc --- /dev/null +++ b/build/ifm.js @@ -0,0 +1 @@ +src/ifm.js \ No newline at end of file diff --git a/build/ifmlib.php b/build/ifmlib.php new file mode 100644 index 0000000..4feba5b --- /dev/null +++ b/build/ifmlib.php @@ -0,0 +1,2831 @@ + 0, + "auth_source" => 'inlineadmin:$2y$10$0Bnm5L4wKFHRxJgNq.oZv.v7yXhkJZQvinJYR2p6X1zPvzyDRUVRC', + "root_dir" => "", + "tmp_dir" => "", + "defaulttimezone" => "Europe/Berlin", + + // api controls + "ajaxrequest" => 1, + "chmod" => 1, + "copymove" => 1, + "createdir" => 1, + "createfile" => 1, + "edit" => 1, + "delete" => 1, + "download" => 1, + "extract" => 1, + "upload" => 1, + "remoteupload" => 1, + "rename" => 1, + "zipnload" => 1, + + // gui controls + "showlastmodified" => 0, + "showfilesize" => 1, + "showowner" => 1, + "showgroup" => 1, + "showpermissions" => 2, + "showhtdocs" => 1, + "showhiddenfiles" => 1, + "showpath" => 0, + ); + + private $config = array(); + public $mode = ""; + + public function __construct( $config=array() ) { + session_start(); + $this->config = array_merge( $this->defaultconfig, $config ); + } + + /** + * This function contains the client-side application + */ + public function getApplication() { + print ' + + + IFM - improved file manager + + + '; + $this->getCSS(); + print ' + + +
'; + $this->getJS(); + print ' + + + '; + } + + public function getInlineApplication() { + $this->getCSS(); + print '
'; + $this->getJS(); + } + + private function getCSS() { + print ' + + + + + '; + } + + private function getJS() { + print ' + + + + + + + + + '; + } + + /* + main functions + */ + + private function handleRequest() { + if($_REQUEST["api"] == "getRealpath") { + if( isset( $_REQUEST["dir"] ) && $_REQUEST["dir"] != "" ) + echo json_encode( array( "realpath" => $this->getValidDir( $_REQUEST["dir"] ) ) ); + else + echo json_encode( array( "realpath" => "" ) ); + } + elseif( $_REQUEST["api"] == "getFiles" ) { + if( isset( $_REQUEST["dir"] ) && $this->isPathValid( $_REQUEST["dir"] ) ) + $this->getFiles( $_REQUEST["dir"] ); + else + $this->getFiles( "" ); + } + elseif( $_REQUEST["api"] == "getConfig" ) { + $this->getConfig(); + } elseif( $_REQUEST["api"] == "getTemplates" ) { + echo json_encode( $this->getTemplates() ); + } else { + if( isset( $_REQUEST["dir"] ) && $this->isPathValid( $_REQUEST["dir"] ) ) { + switch( $_REQUEST["api"] ) { + case "createDir": $this->createDir( $_REQUEST["dir"], $_REQUEST["dirname"] ); break; + case "saveFile": $this->saveFile( $_REQUEST ); break; + case "getContent": $this->getContent( $_REQUEST ); break; + case "delete": $this->deleteFile( $_REQUEST ); break; + case "rename": $this->renameFile( $_REQUEST ); break; + case "download": $this->downloadFile( $_REQUEST ); break; + case "extract": $this->extractFile( $_REQUEST ); break; + case "upload": $this->uploadFile( $_REQUEST ); break; + case "copyMove": $this->copyMove( $_REQUEST ); break; + case "changePermissions": $this->changePermissions( $_REQUEST ); break; + case "zipnload": $this->zipnload( $_REQUEST); break; + case "remoteUpload": $this->remoteUpload( $_REQUEST ); break; + case "multidelete": $this->deleteMultipleFiles( $_REQUEST ); break; + case "getFolderTree": + echo json_encode( array_merge( array( 0 => array( "text" => "/ [root]", "nodes" => array(), "dataAttributes" => array( "path" => realpath( $this->config['root_dir'] ) ) ) ), $this->getFolderTreeRecursive( $this->config['root_dir'] ) ) ); + break; + default: + echo json_encode( array( "status" => "ERROR", "message" => "No valid api action given" ) ); + break; + } + } else { + print json_encode(array("status"=>"ERROR", "message"=>"No valid working directory")); + } + } + } + + public function run( $mode="standalone" ) { + if ( $this->checkAuth() ) { + // go to our root_dir + if( ! is_dir( realpath( $this->config['root_dir'] ) ) || ! is_readable( realpath( $this->config['root_dir'] ) ) ) + die( "Cannot access root_dir."); + else + chdir( realpath( $this->config['root_dir'] ) ); + $this->mode = $mode; + if ( isset($_REQUEST['api']) || $mode == "api" ) { + $this->handleRequest(); + } elseif( $mode == "standalone" ) { + $this->getApplication(); + } else { + $this->getInlineApplication(); + } + } + } + + /* + api functions + */ + + private function getFiles( $dir ) { + $dir = $this->getValidDir( $dir ); + $this->chDirIfNecessary( $dir ); + + unset( $files ); unset( $dirs ); $files = array(); $dirs = array(); + + if( $handle = opendir( "." ) ) { + while( false !== ( $result = readdir( $handle ) ) ) { + if( $result == basename( $_SERVER['SCRIPT_NAME'] ) && $this->getScriptRoot() == getcwd() ) { } + elseif( ( $result == ".htaccess" || $result==".htpasswd" ) && $this->config['showhtdocs'] != 1 ) {} + elseif( $result == "." ) {} + elseif( $result != ".." && substr( $result, 0, 1 ) == "." && $this->config['showhiddenfiles'] != 1 ) {} + else { + $item = array(); + $item["name"] = $result; + if( is_dir($result) ) { + $item["type"] = "dir"; + if( $result == ".." ) + $item["icon"] = "icon icon-up-open"; + else + $item["icon"] = "icon icon-folder-empty"; + } else { + $item["type"] = "file"; + $type = substr( strrchr( $result, "." ), 1 ); + $item["icon"] = $this->getTypeIcon( $type ); + } + if( $this->config['showlastmodified'] == 1 ) { $item["lastmodified"] = date( "d.m.Y, G:i e", filemtime( $result ) ); } + if( $this->config['showfilesize'] == 1 ) { + $item["size"] = filesize( $result ); + if( $item["size"] > 1073741824 ) $item["size"] = round( ( $item["size"]/1073741824 ), 2 ) . " GB"; + elseif($item["size"]>1048576)$item["size"] = round( ( $item["size"]/1048576 ), 2 ) . " MB"; + elseif($item["size"]>1024)$item["size"] = round( ( $item["size"]/1024 ), 2 ) . " KB"; + else $item["size"] = $item["size"] . " Byte"; + } + if( $this->config['showpermissions'] > 0 ) { + if( $this->config['showpermissions'] == 1 ) $item["fileperms"] = substr( decoct( fileperms( $result ) ), -3 ); + elseif( $this->config['showpermissions'] == 2 ) $item["fileperms"] = $this->filePermsDecode( fileperms( $result ) ); + if( $item["fileperms"] == "" ) $item["fileperms"] = " "; + $item["filepermmode"] = ( $this->config['showpermissions'] == 1 ) ? "short" : "long"; + } + if( $this->config['showowner'] == 1 ) { + if ( function_exists( "posix_getpwuid" ) && fileowner($result) !== false ) { + $ownerarr = posix_getpwuid( fileowner( $result ) ); + $item["owner"] = $ownerarr['name']; + } else $item["owner"] = false; + } + if( $this->config['showgroup'] == 1 ) { + if( function_exists( "posix_getgrgid" ) && filegroup( $result ) !== false ) { + $grouparr = posix_getgrgid( filegroup( $result ) ); + $item["group"] = $grouparr['name']; + } else $item["group"] = false; + } + if( is_dir( $result ) ) $dirs[] = $item; + else $files[] = $item; + } + } + closedir( $handle ); + } + usort( $dirs, array( $this, "sortByName" ) ); + usort( $files, array( $this, "sortByName" ) ); + echo json_encode( array_merge( $dirs, $files ) ); + } + + private function getConfig() { + $ret = $this->config; + $ret['inline'] = ( $this->mode == "inline" ) ? true : false; + $ret['isDocroot'] = ( realpath( $this->config['root_dir'] ) == dirname( __FILE__ ) ) ? "true" : "false"; + echo json_encode( $ret ); + } + + private function getFolderTreeRecursive( $start_dir ) { + $ret = array(); + $start_dir = realpath( $start_dir ); + if( $handle = opendir( $start_dir ) ) { + while (false !== ( $result = readdir( $handle ) ) ) { + if( is_dir( $this->pathCombine( $start_dir, $result ) ) && $result != "." && $result != ".." ) { + array_push( $ret, array( "text" => $result, "dataAttributes" => array( "path" => $this->pathCombine( $start_dir, $result ) ), "nodes" => $this->getFolderTreeRecursive( $this->pathCombine( $start_dir, $result ) ) ) ); + } + } + } + sort( $ret ); + return $ret; + } + + private function copyMove( $d ) { + if( $this->config['copymove'] != 1 ) { + echo json_encode( array( "status" => "ERROR", "message" => "No permission to copy or move files." ) ); + exit( 1 ); + } + $this->chDirIfNecessary( $d['dir'] ); + if( ! isset( $d['destination'] ) || ! $this->isPathValid( realpath( $d['destination'] ) ) ) { + echo json_encode( array( "status" => "ERROR", "message" => "No valid destination directory given." ) ); + exit( 1 ); + } + if( ! file_exists( $d['filename'] ) ) { + echo json_encode( array( "status" => "ERROR", "message" => "No valid filename given." ) ); + exit( 1 ); + } + if( $d['action'] == "copy" ) { + if( $this->copyr( $d['filename'], $d['destination'] ) ) { + echo json_encode( array( "status" => "OK", "message" => "File(s) were successfully copied." ) ); + exit( 0 ); + } else { + $err = error_get_last(); + echo json_encode( array( "status" => "ERROR", "message" => $err['message'] ) ); + exit( 1 ); + } + } elseif( $d['action'] == "move" ) { + if( rename( $d['filename'], $this->pathCombine( $d['destination'], basename( $d['filename'] ) ) ) ) { + echo json_encode( array( "status" => "OK", "message" => "File(s) were successfully moved." ) ); + exit( 0 ); + } else { + $err = error_get_last(); + echo json_encode( array( "status" => "ERROR", "message" => $err['message'] ) ); + exit( 1 ); + } + } else { + echo json_encode( array( "status" => "ERROR", "message" => "No valid action given." ) ); + exit( 1 ); + } + } + + // creates a directory + private function createDir($w, $dn) { + if( $dn == "" ) { + echo json_encode( array( "status" => "ERROR", "message" => "No valid directory name") ); + } elseif( strpos( $dn, '/' ) !== false ) echo json_encode( array( "status" => "ERROR", "message" => "No slashes allowed in directory names" ) ); + else { + $this->chDirIfNecessary( $w ); + if( @mkdir( $dn ) ) { + echo json_encode( array( "status" => "OK", "message" => "Directory successful created" ) ); + } else { + echo json_encode( array( "status" => "ERROR", "message" => "Could not create directory" ) ); + } + } + } + + // save a file + private function saveFile(array $d) { + if( isset( $d['filename'] ) && $d['filename'] != "" ) { + // if you are not allowed to see .ht-docs you can't save one + if( $this->config['showhtdocs'] != 1 && substr( $d['filename'], 0, 3 ) == ".ht" ) { + echo json_encode( array( "status" => "ERROR", "message" => "You are not allowed to edit or create htdocs" ) ); + } + // same with hidden files + elseif( $this->config['showhiddenfiles'] != 1 && substr( $d['filename'], 0, 1 ) == "." ) { + echo json_encode( array( "status" => "ERROR", "message" => "You are not allowed to edit or create hidden files" ) ); + } + elseif(strpos($d['filename'],'/')!==false) { + echo json_encode( array( "status" => "ERROR", "message" => "Filenames cannot contain slashes." ) ); + } else { + if( isset( $d['content'] ) ) { + $this->chDirIfNecessary( $d['dir'] ); + // work around magic quotes + $content = get_magic_quotes_gpc() == 1 ? stripslashes( $d['content'] ) : $d['content']; + if( @file_put_contents( $d['filename'], $content ) !== false ) { + echo json_encode( array( "status" => "OK", "message" => "File successfully saved" ) ); + } else { + echo json_encode( array( "status" => "ERROR", "message" => "Could not write content" ) ); + } + } else { + echo json_encode( array( "status" => "ERROR", "message" => "Got no content" ) ); + } + } + } else { + echo json_encode( array( "status" => "ERROR", "message" => "No filename specified" ) ); + } + } + + // gets the content of a file + // notice: if the content is not JSON encodable it returns an error + private function getContent( array $d ) { + if( $this->config['edit'] != 1 ) echo json_encode( array( "status" => "ERROR", "message" => "No permission to edit files" ) ); + else { + $this->chDirIfNecessary( $d['dir'] ); + if( file_exists( $d['filename'] ) ) { + $content = @file_get_contents( $d['filename'] ); + $utf8content = mb_convert_encoding( $content, 'UTF-8', mb_detect_encoding( $content, 'UTF-8, ISO-8859-1', true ) ); + echo json_encode( array( "status" => "OK", "data" => array( "filename" => $d['filename'], "content" => $utf8content ) ) ); + } else echo json_encode( array( "status" => "ERROR", "message" => "File not found" ) ); + } + } + + // deletes a file or a directory (recursive!) + private function deleteFile( array $d ) { + if( $this->config['delete'] != 1 ) { + echo json_encode( array( "status" => "ERROR", "message" => "No permission to delete files" ) ); + } + else { + $this->chDirIfNecessary( $d['dir'] ); + if( is_dir( $d['filename'] ) ) { + $res = $this->rec_rmdir( $d['filename'] ); + if( $res != 0 ) { + echo json_encode( array( "status" => "ERROR", "message" => "No permission to delete files" ) ); + } else { + echo json_encode( array( "status" => "OK", "message" => "Directoy successful deleted" ) ); + } + } + else{ + if( @unlink( $d['filename'] ) ) { + echo json_encode( array( "status" => "OK", "message" => "File successful deleted" ) ); + } else { + echo json_encode( array( "status"=>"ERROR", "message" => "File could not be deleted" ) ); + } + } + } + } + + // deletes a bunch of files or directories + private function deleteMultipleFiles( array $d ) { + if( $this->config['delete'] != 1 ) echo json_encode( array( "status" => "ERROR", "message" => "No permission to delete multiple files" ) ); + else { + $this->chDirIfNecessary( $d['dir'] ); + $err = array(); $errFLAG = -1; // -1 -> no files deleted; 0 -> at least some files deleted; 1 -> all files deleted + foreach( $d['filenames'] as $file ) { + if( is_dir($file) ){ + $res = $this->rec_rmdir( $file ); + if( $res != 0 ) + array_push( $err, $file ); + else + $errFLAG = 0; + } else { + if( @unlink($file) ) + $errFLAG = 0; + else + array_push($err, $file); + } + } + if( empty( $err ) ) { + echo json_encode( array( "status" => "OK", "message" => "Files deleted successfully", "errflag" => "1" ) ); + } + else { + $errmsg = "The following files could not be deleted:"; + echo json_encode( array( "status" => "OK", "message" => $errmsg, "flag" => $errFLAG ) ); + } + } + } + + // renames a file + private function renameFile( array $d ) { + if( $this->config['rename'] != 1 ) { + echo json_encode( array( "status" => "ERROR", "message" => "No permission to rename files" ) ); + } else { + $this->chDirIfNecessary( $d['dir'] ); + if( strpos( $d['newname'], '/' ) !== false ) + echo json_encode( array( "status" => "ERROR", "message" => "No slashes allowed in filenames" ) ); + elseif( $this->config['showhtdocs'] != 1 && ( substr( $d['newname'], 0, 3) == ".ht" || substr( $d['filename'], 0, 3 ) == ".ht" ) ) + echo json_encode( array( "status" => "ERROR", "message" => "Not allowed to rename this file" ) ); + elseif( $this->config['showhiddenfiles'] != 1 && ( substr( $d['newname'], 0, 1) == "." || substr( $d['filename'], 0, 1 ) == "." ) ) + echo json_encode( array( "status" => "ERROR", "message" => "Not allowed to rename file" ) ); + else { + if( @rename( $d['filename'], $d['newname'] ) ) + echo json_encode( array( "status" => "OK", "message" => "File successful renamed" ) ); + else + echo json_encode( array( "status" => "ERROR", "message" => "File could not be renamed" ) ); + } + } + } + + // provides a file for downloading + private function downloadFile( array $d ) { + if( $this->config['download'] != 1 ) + echo json_encode( array( "status" => "ERROR", "message" => "Not allowed to download files" ) ); + elseif( $this->config['showhtdocs'] != 1 && ( substr( $d['filename'], 0, 3 ) == ".ht" || substr( $d['filename'],0,3 ) == ".ht" ) ) + echo json_encode( array( "status" => "ERROR", "message"=>"Not allowed to download htdocs" ) ); + elseif( $this->config['showhiddenfiles'] != 1 && ( substr( $d['filename'], 0, 1 ) == "." || substr( $d['filename'],0,1 ) == "." ) ) + echo json_encode( array( "status" => "ERROR", "message" => "Not allowed to download hidden files" ) ); + else { + $this->chDirIfNecessary( $d["dir"] ); + $this->fileDownload( $d['filename'] ); + } + } + + // extracts a zip-archive + private function extractFile( array $d ) { + if( $this->config['extract'] != 1 ) + echo json_encode( array( "status" => "ERROR", "message" => "No permission to extract files" ) ); + else { + $this->chDirIfNecessary( $d['dir'] ); + if( ! file_exists( $d['filename'] ) || substr( $d['filename'],-4 ) != ".zip" ) { + echo json_encode( array( "status" => "ERROR","message" => "No valid zip file found" ) ); + exit( 1 ); + } + if( ! isset( $d['targetdir'] ) || trim( $d['targetdir'] ) == "" ) + $d['targetdir'] = "./"; + if( ! $this->isPathValid( $d['targetdir'] ) ) { + echo json_encode( array( "status" => "ERROR","message" => "Target directory is not valid." ) ); + exit( 1 ); + } + if( ! is_dir( $d['targetdir'] ) && ! mkdir( $d['targetdir'], 0777, true ) ) { + echo json_encode( array( "status" => "ERROR","message" => "Could not create target directory." ) ); + exit( 1 ); + } + if( ! IFMZip::extract( $d['filename'], $d['targetdir'] ) ) { + echo json_encode( array( "status" => "ERROR","message" => "File could not be extracted" ) ); + } else { + echo json_encode( array( "status" => "OK","message" => "File successfully extracted." ) ); + } + } + } + + // uploads a file + private function uploadFile( array $d ) { + if( $this->config['upload'] != 1 ) + echo json_encode( array( "status" => "ERROR", "message" => "No permission to upload files" ) ); + elseif( !isset( $_FILES['file'] ) ) + echo json_encode( array( "file" => $_FILE,"files" => $_FILES ) ); + else { + $this->chDirIfNecessary( $d['dir'] ); + $newfilename = ( isset( $d["newfilename"] ) && $d["newfilename"]!="" ) ? $d["newfilename"] : $_FILES['file']['name']; + if( $this->config['showhtdocs'] != 1 && ( substr( $newfilename, 0, 3 ) == ".ht" || substr( $newfilename,0,3 ) == ".ht" ) ) + echo json_encode( array( "status" => "ERROR", "message" => "Not allowed to upload htdoc file" ) ); + elseif( $this->config['showhiddenfiles'] != 1 && ( substr( $newfilename, 0, 1 ) == "." || substr( $newfilename,0,1 ) == "." ) ) + echo json_encode( array( "status" => "ERROR", "message" => "Not allowed to upload hidden file" ) ); + else { + if( $_FILES['file']['tmp_name'] ) { + if( is_writable( getcwd( ) ) ) { + if( move_uploaded_file( $_FILES['file']['tmp_name'], $newfilename ) ) + echo json_encode( array( "status" => "OK", "message" => "The file ".$_FILES['file']['name']." was uploaded successfully", "cd" => $d['dir'] ) ); + else + echo json_encode( array( "status" => "ERROR", "message" => "File could not be uploaded" ) ); + } + else { + echo json_encode( array( "status" => "ERROR", "message" => "File could not be uploaded since it has no permissions to write in this directory" ) ); + } + } else { + echo json_encode( array( "status" => "ERROR", "message" => "No file found" ) ); + } + } + } + } + + // change permissions of a file + private function changePermissions( array $d ) { + if( $this->config['chmod'] != 1 ) echo json_encode( array( "status" => "ERROR", "message" => "No rights to change permissions" ) ); + elseif( ! isset( $d["chmod"] )||$d['chmod']=="" ) echo json_encode( array( "status" => "ERROR", "message" => "Could not identify new permissions" ) ); + elseif( ! $this->isPathValid( $this->pathCombine( $d['dir'],$d['filename'] ) ) ) { echo json_encode( array( "status" => "ERROR", "message" => "Not allowed to change the permissions" ) ); } + else { + $this->chDirIfNecessary( $d['dir'] ); $chmod = $d["chmod"]; $cmi = true; + if( ! is_numeric( $chmod ) ) { + $cmi = false; + $chmod = str_replace( " ","",$chmod ); + if( strlen( $chmod )==9 ) { + $cmi = true; + $arr = array( substr( $chmod,0,3 ),substr( $chmod,3,3 ),substr( $chmod,6,3 ) ); + $chtmp = "0"; + foreach( $arr as $right ) { + $rtmp = 0; + if( substr( $right,0,1 )=="r" ) $rtmp = $rtmp + 4; elseif( substr( $right,0,1 )<>"-" ) $cmi = false; + if( substr( $right,1,1 )=="w" ) $rtmp = $rtmp + 2; elseif( substr( $right,1,1 )<>"-" ) $cmi = false; + if( substr( $right,2,1 )=="x" ) $rtmp = $rtmp + 1; elseif( substr( $right,2,1 )<>"-" ) $cmi = false; + $chtmp = $chtmp . $rtmp; + } + $chmod = intval( $chtmp ); + } + } + else $chmod = "0" . $chmod; + + if( $cmi ) { + try { + chmod( $d["filename"], (int)octdec( $chmod ) ); + echo json_encode( array( "status" => "OK", "message" => "Permissions changed successfully" ) ); + } catch ( Exception $e ) { + echo json_encode( array( "status" => "ERROR", "message" => "Error while changing permissions" ) ); + } + } + else echo json_encode( array( "status" => "ERROR", "message" => "Could not determine permission format" ) ); + } + } + + // zips a directory and provides it for downloading + // it creates a temporary zip file in the current directory, so it has to be as much space free as the file size is + private function zipnload( array $d ) { + if( $this->config['zipnload'] != 1 ) + echo json_encode( array( "status" => "ERROR", "message" => "No permission to download directories" ) ); + else { + $this->chDirIfNecessary( $d['dir'] ); + if( ! file_exists( $d['filename'] ) ) + echo json_encode( array( "status" => "ERROR", "message" => "Directory not found" ) ); + elseif ( ! $this->allowedFileName( $d['filename'] ) ) + echo json_encode( array( "status" => "ERROR", "message" => "Filename not allowed" ) ); + else { + unset( $zip ); + $dfile = $this->pathCombine( $this->config['tmp_dir'], uniqid( "ifm-tmp-" ) . ".zip" ); // temporary filename + try { + IFMZip::create( realpath( $d['filename'] ), $dfile, ( $d['filename'] == "." ) ); + if( $d['filename'] == "." ) { + if( getcwd() == $this->getScriptRoot() ) + $d['filename'] = "root"; + else + $d['filename'] = basename( getcwd() ); + } + $this->fileDownload( $dfile, $d['filename'] . ".zip" ); + } catch ( Exception $e ) { + echo "An error occured: " . $e->getMessage(); + } finally { + if( file_exists( $dfile ) ) @unlink( $dfile ); + } + } + } + } + + // uploads a file from an other server using the curl extention + private function remoteUpload( array $d ) { + if( $this->config['remoteupload'] != 1 ) + echo json_encode( array( "status" => "ERROR", "message" => "No permission to remote upload files" ) ); + elseif( !isset( $d['method'] ) || !in_array( $d['method'], array( "curl", "file" ) ) ) + echo json_encode( array( "status" => "error", "message" => "No valid method given. Valid methods: ['curl', 'file']" ) ); + elseif( $d['method']=="curl" && $this->checkCurl( ) == false ) + echo json_encode( array( "status" => "ERROR", "message" => "cURL extention not installed. Please install the cURL extention to use remote file upload." ) ); + elseif( $d['method']=="curl" && $this->checkCurl( ) == true ) { + $filename = ( isset( $d['filename'] )&&$d['filename']!="" )?$d['filename']:"curl_".uniqid( ); + $this->chDirIfNecessary( $d['dir'] ); + $ch = curl_init( ); + if( $ch ) { + if( $this->allowedFileName( $filename ) == false ) + echo json_encode( array( "status" => "ERROR", "message" => "This filename is not allowed due to the config." ) ); + elseif( filter_var( $d['url'], FILTER_VALIDATE_URL ) === false ) + echo json_encode( array( "status" => "ERROR", "message" => "The passed URL is not valid" ) ); + else { + $fp = fopen( $filename, "w" ); + if( $fp ) { + if( !curl_setopt( $ch, CURLOPT_URL, $d['url'] ) || !curl_setopt( $ch, CURLOPT_FILE, $fp ) || !curl_setopt( $ch, CURLOPT_HEADER, 0 ) || !curl_exec( $ch ) ) + echo json_encode( array( "status" => "ERROR", "message" => "Failed to set options and execute cURL" ) ); + else { + echo json_encode( array( "status" => "OK", "message" => "File sucessfully uploaded" ) ); + } + curl_close( $ch ); + fclose( $fp ); + } else { + echo json_encode( array( "status" => "ERROR", "message" => "Failed to open file" ) ); + } + } + } else { + echo json_encode( array( "status" => "ERROR", "message" => "Failed to init cURL." ) ); + } + } + elseif( $d['method']=='file' ) { + $filename = ( isset( $d['filename'] ) && $d['filename']!="" ) ? $d['filename'] : "curl_".uniqid( ); + $this->chDirIfNecessary( $d['dir'] ); + try { + file_put_contents( $filename, file_get_contents( $d['url'] ) ); + echo json_encode( array( "status" => "OK", "message" => "File successfully uploaded" ) ); + } catch( Exception $e ) { + echo json_encode( array( "status" => "ERROR", "message" => $e->getMessage() ) ); + } + } + else echo json_encode( array( "status" => "error", "message" => "Corrupt parameter data" ) ); + } + + //apis + + /* + help functions + */ + + public function checkAuth() { + if( $this->config['auth'] == 1 && ( ! isset( $_SESSION['auth'] ) || $_SESSION['auth'] !== true ) ) { + $login_failed = false; + if( isset( $_POST["user"] ) && isset( $_POST["pass"] ) ) { + if( $this->checkCredentials( $_POST["user"], $_POST["pass"] ) ) { + $_SESSION['auth'] = true; + } + else { + $_SESSION['auth'] = false; + $login_failed = true; + } + } + + if( isset( $_SESSION['auth'] ) && $_SESSION['auth'] === true ) { + return true; + } else { + if( isset( $_POST["api"] ) ) { + if( $login_failed === true ) + echo json_encode( array( "status"=>"ERROR", "message"=>"authentication failed" ) ); + else + echo json_encode( array( "status"=>"ERROR", "message"=>"not authenticated" ) ); + } else { + $this->loginForm($login_failed); + } + return false; + } + } else { + return true; + } + } + + private function checkCredentials( $user, $pass ) { + list( $src, $srcopt ) = explode( ";", $this->config['auth_source'], 2 ); + switch( $src ) { + case "inline": + list( $uname, $hash ) = explode( ":", $srcopt ); + return password_verify( $pass, trim( $hash ) ) ? ( $uname == $user ) : false; + break; + case "file": + if( @file_exists( $srcopt ) && @is_readable( $srcopt ) ) { + list( $uname, $hash ) = explode( ":", fgets( fopen( $srcopt, 'r' ) ) ); + return password_verify( $pass, trim( $hash ) ) ? ( $uname == $user ) : false; + } else { + return false; + } + break; + case "ldap": + $authenticated = false; + list( $ldap_server, $rootdn ) = explode( ";", $srcopt ); + $u = "uid=" . $user . "," . $rootdn; + if( ! $ds = ldap_connect( $ldap_server ) ) { + trigger_error( "Could not reach the ldap server.", E_USER_ERROR ); + return false; + } + ldap_set_option( $ds, LDAP_OPT_PROTOCOL_VERSION, 3 ); + if( $ds ) { + $ldbind = @ldap_bind( $ds, $u, $pass ); + if( $ldbind ) { + $authenticated = true; + } else { + trigger_error( ldap_error( $ds ), E_USER_ERROR ); + $authenticated = false; + } + ldap_unbind( $ds ); + } else { + $authenticated = false; + } + return $authenticated; + break; + } + return false; + } + + private function loginForm($loginFailed=false) { + print ' + + + IFM - improved file manager + + + + +

IFM - Login

+
'; + if($loginFailed){ print '
Login attempt failed. Please try again.
'; } + print '
+
+ +
+ + '; + } + + private function filePermsDecode( $perms ) { + $oct = str_split( strrev( decoct( $perms ) ), 1 ); + $masks = array( '---', '--x', '-w-', '-wx', 'r--', 'r-x', 'rw-', 'rwx' ); + return( + sprintf( + '%s %s %s', + array_key_exists( $oct[ 2 ], $masks ) ? $masks[ $oct[ 2 ] ] : '###', + array_key_exists( $oct[ 1 ], $masks ) ? $masks[ $oct[ 1 ] ] : '###', + array_key_exists( $oct[ 0 ], $masks ) ? $masks[ $oct[ 0 ] ] : '###') + ); + } + + private function getValidDir( $dir ) { + if( ! $this->isPathValid( $dir ) || ! is_dir( $dir ) ) { + return ""; + } else { + $rpDir = realpath( $dir ); + $rpConfig = realpath( $this->config['root_dir'] ); + if( $rpConfig == "/" ) + return $rpDir; + elseif( $rpDir == $rpConfig ) + return ""; + else + return substr( $rpDir, strlen( $rpConfig ) + 1 ); + } + } + + private function isPathValid( $dir ) { + /** + * This function is also used to check non-existent paths, but the PHP realpath function returns false for + * nonexistent paths. Hence we need to check the path manually in the following lines. + */ + $tmp_d = $dir; + $tmp_missing_parts = array(); + while( realpath( $tmp_d ) === false ) { + $tmp_i = pathinfo( $tmp_d ); + array_push( $tmp_missing_parts, $tmp_i['filename'] ); + $tmp_d = dirname( $tmp_d ); + } + $rpDir = $this->pathCombine( realpath( $tmp_d ), implode( "/", array_reverse( $tmp_missing_parts ) ) ); + $rpConfig = ( $this->config['root_dir'] == "" ) ? realpath( dirname( __FILE__ ) ) : realpath( $this->config['root_dir'] ); + if( ! is_string( $rpDir ) || ! is_string( $rpConfig ) ) // can happen if open_basedir is in effect + return false; + elseif( $rpDir == $rpConfig ) + return true; + elseif( 0 === strpos( $rpDir, $rpConfig ) ) + return true; + else + return false; + } + + private function getScriptRoot() { + return dirname( $_SERVER["SCRIPT_FILENAME"] ); + } + + private function chDirIfNecessary($d) { + if( substr( getcwd(), strlen( $this->getScriptRoot() ) ) != $this->getValidDir($d) ) { + chdir( $d ); + } + } + + private function getTypeIcon( $type ) { + switch( $type ) { + case "aac": case "aiff": case "mid": case "mp3": case "wav": return 'icon icon-file-audio'; break; + case "ai": case "bmp": case "eps": case "tiff": case "gif": case "jpg": case "jpeg": case "png": case "psd": return 'icon icon-file-image'; break; + case "avi": case "flv": case "mp4": case "mpg": case "mkv": case "mpeg": case "webm": case "wmv": case "mov": return 'icon icon-file-video'; break; + case "c": case "cpp": case "css": case "dat": case "h": case "html": case "php": case "java": case "py": case "sql": case "xml": case "yml": return 'icon icon-file-code'; break; + case "doc": case "dotx": case "odf": case "odt": case "rtf": return 'icon icon-file-word'; break; + case "ods": case "xls": case "xlsx": return 'icon icon-file-excel'; break; + case "odp": case "ppt": case "pptx": return 'icon icon-file-powerpoint'; break; + case "pdf": return 'icon icon-file-pdf'; break; + case "tgz": case "zip": case "tar": case "7z": case "rar": return 'icon icon-file-archive'; + default: return 'icon icon-doc'; + } + } + + private function rec_rmdir( $path ) { + if( !is_dir( $path ) ) { + return -1; + } + $dir = @opendir( $path ); + if( !$dir ) { + return -2; + } + while( ( $entry = @readdir( $dir ) ) !== false ) { + if( $entry == '.' || $entry == '..' ) continue; + if( is_dir( $path . '/' . $entry ) ) { + $res = $this->rec_rmdir( $path . '/' . $entry ); + if( $res == -1 ) { @closedir( $dir ); return -2; } + else if( $res == -2 ) { @closedir( $dir ); return -2; } + else if( $res == -3 ) { @closedir( $dir ); return -3; } + else if( $res != 0 ) { @closedir( $dir ); return -2; } + } else if( is_file( $path . '/' . $entry ) || is_link( $path . '/' . $entry ) ) { + $res = @unlink( $path . '/' . $entry ); + if( !$res ) { @closedir( $dir ); return -2; } + } else { @closedir( $dir ); return -3; } + } + @closedir( $dir ); + $res = @rmdir( $path ); + if( !$res ) { return -2; } + return 0; + } + + /** + * Copy a file, or recursively copy a folder and its contents + * + * @author Aidan Lister + * @version 1.0.1 + * @link http://aidanlister.com/2004/04/recursively-copying-directories-in-php/ + * @param string $source Source path + * @param string $dest Destination path + * @return bool Returns TRUE on success, FALSE on failure + */ + private function copyr( $source, $dest ) + { + // Check for symlinks + if (is_link($source)) { + return symlink(readlink($source), $dest); + } + + // Simple copy for a file + if (is_file($source)) { + $dest = ( is_dir( $dest ) ) ? $this->pathCombine( $dest, basename( $source ) ) : $dest; + return copy($source, $dest); + } else { + $dest = $this->pathCombine( $dest, basename( $source ) ); + } + + // Make destination directory + if (!is_dir($dest)) { + mkdir($dest); + } + + // Loop through the folder + $dir = dir($source); + while (false !== $entry = $dir->read()) { + // Skip pointers + if ($entry == '.' || $entry == '..') { + continue; + } + + // Deep copy directories + $this->copyr("$source/$entry", "$dest/$entry"); + } + + // Clean up + $dir->close(); + return true; + } + + // combines two parts to a valid path + private function pathCombine( $a, $b ) { + if( trim( $a ) == "" && trim( $b ) == "" ) + return ""; + elseif( trim( $a ) == "" ) + return ltrim( $b, '/' ); + else + return rtrim( $a, '/' ) . '/' . ltrim( $b, '/' ); + } + + // check if filename is allowed + private function allowedFileName( $f ) { + if( $this->config['showhtdocs'] != 1 && substr( $f, 0, 3 ) == ".ht" ) + return false; + elseif( $this->config['showhiddenfiles'] != 1 && substr( $f, 0, 1 ) == "." ) + return false; + elseif( ! $this->isPathValid( $f ) ) + return false; + return true; + } + + // sorting function for file and dir arrays + private function sortByName( $a, $b ) { + if( strtolower( $a['name'] ) == strtolower( $b['name'] ) ) return 0; + return ( strtolower( $a['name'] ) < strtolower( $b['name'] ) ) ? -1 : 1; + } + + // is cURL extention avaliable? + private function checkCurl() { + if( !function_exists( "curl_init" ) || + !function_exists( "curl_setopt" ) || + !function_exists( "curl_exec" ) || + !function_exists( "curl_close" ) ) return false; + else return true; + } + + private function fileDownload( $file, $name="" ) { + header( 'Content-Description: File Transfer' ); + header( 'Content-Type: application/octet-stream' ); + header( 'Content-Disposition: attachment; filename="' . ( trim( $name ) == "" ? basename( $file ) : $name ) . '"' ); + header( 'Expires: 0' ); + header( 'Cache-Control: must-revalidate' ); + header( 'Pragma: public' ); + header( 'Content-Length: ' . filesize( $file ) ); + + $file_stream = fopen( $file, 'rb' ); + $stdout_stream = fopen('php://output', 'wb'); + + stream_copy_to_stream($file_stream, $stdout_stream); + + fclose($file_stream); + fclose($stdout_stream); + } + + private function getTemplates() { + $templates = array(); + $templates['app'] = <<<'f00bar' + +
+ + + + + {{#config.download}} + + {{/config.download}} + {{#config.showlastmodified}} + + {{/config.showlastmodified}} + {{#config.showfilesize}} + + {{/config.showfilesize}} + {{#config.showpermissions}} + + {{/config.showpermissions}} + {{#config.showowner}} + + {{/config.showowner}} + {{#config.showgroup}} + + {{/config.showgroup}} + + + + + +
Filenamelast modifiedsize
+
+
+ +
+ +f00bar; + $templates['filetable'] = <<<'f00bar' + +{{#items}} + + + + + {{linkname}} + + + + {{#download.allowed}} +
+ + + +
+ + + + {{/download.allowed}} + + {{#config.showlastmodified}} + {{lastmodified}} + {{/config.showlastmodified}} + {{#config.showfilesize}} + {{size}} + {{/config.showfilesize}} + {{#config.showpermissions}} + + + + {{/config.showpermissions}} + {{#config.showowner}} + + {{owner}} + + {{/config.showowner}} + {{#config.showgroup}} + + {{group}} + + {{/config.showgroup}} + + {{#button}} + + + + {{/button}} + + +{{/items}} + + +f00bar; + $templates['file'] = <<<'f00bar' +
+ + +
+ +f00bar; + $templates['createdir'] = <<<'f00bar' +
+ + +
+ +f00bar; + $templates['ajaxrequest'] = <<<'f00bar' +
+
+ +f00bar; + $templates['copymove'] = <<<'f00bar' +
+
+ + +
+
+ +f00bar; + $templates['createdir'] = <<<'f00bar' +
+ + +
+ +f00bar; + $templates['deletefile'] = <<<'f00bar' +
+ + +
+ +f00bar; + $templates['extractfile'] = <<<'f00bar' +
+
+ + +
+
+ +f00bar; + $templates['file'] = <<<'f00bar' +
+ + +
+ +f00bar; + $templates['multidelete'] = <<<'f00bar' +
+ + +
+ +f00bar; + $templates['remoteupload'] = <<<'f00bar' +
+ + +
+ +f00bar; + $templates['renamefile'] = <<<'f00bar' + + +f00bar; + $templates['uploadfile'] = <<<'f00bar' +
+ + +
+ +f00bar; + + return $templates; + } +} + +/* ======================================================================= + * Improved File Manager + * --------------------- + * License: This project is provided under the terms of the MIT LICENSE + * http://github.com/misterunknown/ifm/blob/master/LICENSE + * ======================================================================= + * + * zip class + * + * this was adapted from http://php.net/manual/de/class.ziparchive.php#110719 +*/ + +class IFMZip { + /** + * Add a folder to the zip file + */ + private static function folderToZip($folder, &$zipFile, $exclusiveLength) { + $handle = opendir( $folder ); + while( false !== $f = readdir( $handle ) ) { + if( $f != '.' && $f != '..' ) { + $filePath = "$folder/$f"; + if( file_exists( $filePath ) && is_readable( $filePath ) ) { + // Remove prefix from file path before add to zip. + $localPath = substr($filePath, $exclusiveLength); + if( is_file( $filePath ) ) { + $zipFile->addFile( $filePath, $localPath ); + } elseif( is_dir( $filePath ) ) { + // Add sub-directory. + $zipFile->addEmptyDir( $localPath ); + self::folderToZip( $filePath, $zipFile, $exclusiveLength ); + } + } + } + } + closedir( $handle ); + } + + /** + * Create a zip file + */ + public static function create( $src, $out, $root=false ) + { + $z = new ZipArchive(); + $z->open( $out, ZIPARCHIVE::CREATE); + if( $root ) { + self::folderToZip( realpath( $src ), $z, strlen( realpath( $src ) . '/' ) ); + } else { + $z->addEmptyDir( basename( $src ) ); + self::folderToZip( realpath( $src ), $z, strlen( dirname( $src ) . '/' ) ); + } + try { + if( ( $res = $z->close() ) !== true ) { + throw new Exception("Error while creating zip archive: ". $z->getStatusString()); + } + } catch ( Exception $e ) { + throw $e; + } + } + + /** + * Unzip a zip file + */ + public static function extract( $file, $destination="./" ) { + $zip = new ZipArchive; + $res = $zip->open( $file ); + if( $res === true ) { + $zip->extractTo( $destination ); + $zip->close(); + return true; + } else { + return false; + } + } +} diff --git a/ifm.php b/ifm.php index 173b0b0..89de75b 100644 --- a/ifm.php +++ b/ifm.php @@ -1,174 +1,6 @@ not; 1 -> octal, 2 -> human readable - const showhtdocs = 1; // show .htaccess and .htpasswd - const showhiddenfiles = 1; // show files beginning with a dot (e.g. ".bashrc") - const showpath = 0; // show absolute path - - /* - authentication - - This provides a super simple authentication functionality. At the moment only one user can be - configured. The credential information can be either set inline or read from a file. The - password has to be a hash generated by PHPs password_hash function. The default credentials are - admin:admin. - - If you specify a file it should only contain one line, with the credentials in the following - format: - : - - LDAP auth syntax - - const auth_source = 'ldap;;'; - - The script will add "uid=," to the rootdn for binding. If your ldap server - does not use uid for usernames you can change it in the function checkCredentials. - - examples: - const auth_source = 'inline;admin:$2y$10$0Bnm5L4wKFHRxJgNq.oZv.v7yXhkJZQvinJYR2p6X1zPvzyDRUVRC'; - const auth_source = 'file;/path/to/file'; - const auth_source = 'ldap;;'; - */ - const auth = 0; - const auth_source = 'inline;admin:$2y$10$0Bnm5L4wKFHRxJgNq.oZv.v7yXhkJZQvinJYR2p6X1zPvzyDRUVRC'; - - /* - root_dir - set a custom root directory instead of the script location - - This option is highly experimental and should only be set if you definitely know what you do. - Settings this option may cause black holes or other unwanted things. Use with special care. - - default setting: - const root_dir = ""; - */ - const root_dir = ""; - const defaulttimezone = "Europe/Berlin"; // set default timezone - - /** - * Temp directory for zip files - * - * Default is the upload_tmp_dir which is set in the php.ini, but you may also set an different path - */ - const tmp_dir = ""; - - // development tools - const ajaxrequest = 1; // formular to perform an ajax request - const debug = true; - - static function getConstants() { - $oClass = new ReflectionClass(__CLASS__); - return $oClass->getConstants(); - } -} - -/* ======================================================================= - * Improved File Manager - * --------------------- - * License: This project is provided under the terms of the MIT LICENSE - * http://github.com/misterunknown/ifm/blob/master/LICENSE - * ======================================================================= - * - * zip class - * - * this was adapted from http://php.net/manual/de/class.ziparchive.php#110719 -*/ - -class IFMZip { - /** - * Add a folder to the zip file - */ - private static function folderToZip($folder, &$zipFile, $exclusiveLength) { - $handle = opendir( $folder ); - while( false !== $f = readdir( $handle ) ) { - if( $f != '.' && $f != '..' ) { - $filePath = "$folder/$f"; - if( file_exists( $filePath ) && is_readable( $filePath ) ) { - // Remove prefix from file path before add to zip. - $localPath = substr($filePath, $exclusiveLength); - if( is_file( $filePath ) ) { - $zipFile->addFile( $filePath, $localPath ); - } elseif( is_dir( $filePath ) ) { - // Add sub-directory. - $zipFile->addEmptyDir( $localPath ); - self::folderToZip( $filePath, $zipFile, $exclusiveLength ); - } - } - } - } - closedir( $handle ); - } - - /** - * Create a zip file - */ - public static function create( $src, $out, $root=false ) - { - $z = new ZipArchive(); - $z->open( $out, ZIPARCHIVE::CREATE); - if( $root ) { - self::folderToZip( realpath( $src ), $z, strlen( realpath( $src ) . '/' ) ); - } else { - $z->addEmptyDir( basename( $src ) ); - self::folderToZip( realpath( $src ), $z, strlen( dirname( $src ) . '/' ) ); - } - try { - if( ( $res = $z->close() ) !== true ) { - throw new Exception("Error while creating zip archive: ". $z->getStatusString()); - } - } catch ( Exception $e ) { - throw $e; - } - } - - /** - * Unzip a zip file - */ - public static function extract( $file, $destination="./" ) { - $zip = new ZipArchive; - $res = $zip->open( $file ); - if( $res === true ) { - $zip->extractTo( $destination ); - $zip->close(); - return true; - } else { - return false; - } - } -} +namespace IFM; /* ======================================================================= * Improved File Manager @@ -183,16 +15,42 @@ class IFMZip { error_reporting( E_ALL ); ini_set( 'display_errors', 'OFF' ); + class IFM { const VERSION = '2.4.0'; private $defaultconfig = array( - "upload" => 1,"remoteupload" => 1,"delete" => 1,"rename" => 1,"edit" => 1,"chmod" => 1, - "extract" => 1,"download" => 1,"selfdownload" => 1,"createdir" => 1,"createfile" => 1, - "zipnload" => 1,"copymove" => 1,"showlastmodified" => 0,"showfilesize" => 1,"showowner" => 1, - "showgroup" => 1,"showpermissions" => 2,"showhtdocs" => 1,"showhiddenfiles" => 1,"showpath" => 0, - "auth" => 0,"auth_source" => 'inlineadmin:$2y$10$0Bnm5L4wKFHRxJgNq.oZv.v7yXhkJZQvinJYR2p6X1zPvzyDRUVRC', - "root_dir" => "","defaulttimezone" => "Europe/Berlin","tmp_dir" => "","ajaxrequest" => 1 + // general config + "auth" => 0, + "auth_source" => 'inlineadmin:$2y$10$0Bnm5L4wKFHRxJgNq.oZv.v7yXhkJZQvinJYR2p6X1zPvzyDRUVRC', + "root_dir" => "", + "tmp_dir" => "", + "defaulttimezone" => "Europe/Berlin", + + // api controls + "ajaxrequest" => 1, + "chmod" => 1, + "copymove" => 1, + "createdir" => 1, + "createfile" => 1, + "edit" => 1, + "delete" => 1, + "download" => 1, + "extract" => 1, + "upload" => 1, + "remoteupload" => 1, + "rename" => 1, + "zipnload" => 1, + + // gui controls + "showlastmodified" => 0, + "showfilesize" => 1, + "showowner" => 1, + "showgroup" => 1, + "showpermissions" => 2, + "showhtdocs" => 1, + "showhiddenfiles" => 1, + "showpath" => 0, ); private $config = array(); @@ -557,7 +415,7 @@ function IFM( params ) { } else { item.download.action = "download"; item.download.icon = "icon icon-download"; - if( item.icon.indexOf( 'file-image' ) !== -1 ) + if( item.icon.indexOf( 'file-image' ) !== -1 && self.config.isDocroot ) item.tooltip = 'data-toggle="tooltip" title=""'; if( item.name.toLowerCase().substr(-4) == ".zip" ) item.eaction = "extract"; @@ -1313,6 +1171,8 @@ function IFM( params ) { /** * Prevents a user to submit a form via clicking enter + * + * @param object e - click event */ this.preventEnter = function(e) { if( e.keyCode == 13 ) return false; @@ -1576,11 +1436,20 @@ function IFM( params ) { } break; case ' ': // todo: make it work only when noting other is focused - if( $(':focus').is( '.clickable-row td:first-child a:first-child' ) ) { - e.preventDefault(); - var item = $('.highlightedItem'); - if( item.is( 'tr' ) ) - item.toggleClass( 'selectedItem' ); + case 'Enter': + if( $(':focus').is( '.clickable-row td:first-child a:first-child' ) ) { + var trParent = $(':focus').parent().parent(); + if( e.key == 'Enter' && trParent.hasClass( 'isDir' ) ) { + e.preventDefault(); + e.stopPropagation(); + self.changeDirectory( trParent.data( 'filename' ) ); + } else if( e.key == ' ' && ! trParent.is( ':first-child' ) ) { + e.preventDefault(); + e.stopPropagation(); + var item = $('.highlightedItem'); + if( item.is( 'tr' ) ) + item.toggleClass( 'selectedItem' ); + } } break; } @@ -1750,7 +1619,7 @@ ifm.init( "ifm" ); else chdir( realpath( $this->config['root_dir'] ) ); $this->mode = $mode; - if ( isset($_REQUEST['api']) ) { + if ( isset($_REQUEST['api']) || $mode == "api" ) { $this->handleRequest(); } elseif( $mode == "standalone" ) { $this->getApplication(); @@ -1830,7 +1699,7 @@ ifm.init( "ifm" ); private function getConfig() { $ret = $this->config; $ret['inline'] = ( $this->mode == "inline" ) ? true : false; - $ret['isDocroot'] = ( realpath( IFMConfig::root_dir ) == dirname( __FILE__ ) ) ? "true" : "false"; + $ret['isDocroot'] = ( realpath( $this->config['root_dir'] ) == dirname( __FILE__ ) ) ? "true" : "false"; echo json_encode( $ret ); } @@ -2886,8 +2755,78 @@ f00bar; } } -/** - * start IFM - */ -$ifm = new IFM( IFMConfig::getConstants() ); -$ifm->run(); +/* ======================================================================= + * Improved File Manager + * --------------------- + * License: This project is provided under the terms of the MIT LICENSE + * http://github.com/misterunknown/ifm/blob/master/LICENSE + * ======================================================================= + * + * zip class + * + * this was adapted from http://php.net/manual/de/class.ziparchive.php#110719 +*/ + +class IFMZip { + /** + * Add a folder to the zip file + */ + private static function folderToZip($folder, &$zipFile, $exclusiveLength) { + $handle = opendir( $folder ); + while( false !== $f = readdir( $handle ) ) { + if( $f != '.' && $f != '..' ) { + $filePath = "$folder/$f"; + if( file_exists( $filePath ) && is_readable( $filePath ) ) { + // Remove prefix from file path before add to zip. + $localPath = substr($filePath, $exclusiveLength); + if( is_file( $filePath ) ) { + $zipFile->addFile( $filePath, $localPath ); + } elseif( is_dir( $filePath ) ) { + // Add sub-directory. + $zipFile->addEmptyDir( $localPath ); + self::folderToZip( $filePath, $zipFile, $exclusiveLength ); + } + } + } + } + closedir( $handle ); + } + + /** + * Create a zip file + */ + public static function create( $src, $out, $root=false ) + { + $z = new ZipArchive(); + $z->open( $out, ZIPARCHIVE::CREATE); + if( $root ) { + self::folderToZip( realpath( $src ), $z, strlen( realpath( $src ) . '/' ) ); + } else { + $z->addEmptyDir( basename( $src ) ); + self::folderToZip( realpath( $src ), $z, strlen( dirname( $src ) . '/' ) ); + } + try { + if( ( $res = $z->close() ) !== true ) { + throw new Exception("Error while creating zip archive: ". $z->getStatusString()); + } + } catch ( Exception $e ) { + throw $e; + } + } + + /** + * Unzip a zip file + */ + public static function extract( $file, $destination="./" ) { + $zip = new ZipArchive; + $res = $zip->open( $file ); + if( $res === true ) { + $zip->extractTo( $destination ); + $zip->close(); + return true; + } else { + return false; + } + } +} +/** * start IFM */$ifm = new IFM();$ifm->run(); \ No newline at end of file