diff --git a/components/filemanager/class.archive.php b/components/filemanager/class.archive.php index a8df6bb..39dab95 100644 --- a/components/filemanager/class.archive.php +++ b/components/filemanager/class.archive.php @@ -127,20 +127,34 @@ class Archive { public static function decompress( $file, $output = "default" ) { - $type = filetype( $file ); $response = array(); + $path_info = pathinfo( $file ); + $type = isset( $path_info["extension"] ) ? $path_info["extension"] : null; $supported = self::supports( $type ); $archive = self::get_instance(); + if( $output == "default" ) { + + $output = $path_info["dirname"] . "/" . $path_info["filename"]; + } + if( $supported["status"] === "success" ) { if( extension_loaded( self::EXTENSIONS["{$type}"] ) ) { - $response = call_user_func( array( $archive, "{$type}_d" ), $path ); + $response = call_user_func( array( $archive, "{$type}_d" ), $file, $output ); } else { $response = $archive->execute( $type, "decompress" ); } + + if( $response === true ) { + + $response = array( + "status" => "success", + "message" => null, + ); + } } else { $response = $supported; @@ -257,11 +271,17 @@ class Archive { function zip_d( $path, $output ) { + if( ! is_dir( $output ) ) { + + mkdir( $output ); + } + $status = false; $output = rtrim( $output, '/' ) . '/'; $archive = new ZipArchive(); + $open = $archive->open( $path ); - if ( $archive->open( $path ) === true ) { + if ( $open === true ) { $archive->extractTo( $output ); $archive->close(); diff --git a/components/filemanager/class.filemanager.php b/components/filemanager/class.filemanager.php index f103633..e0fd0ec 100755 --- a/components/filemanager/class.filemanager.php +++ b/components/filemanager/class.filemanager.php @@ -53,7 +53,7 @@ class Filemanager extends Common { * trying to rename or delete it, allow the actual file name. */ - $invalid_characters = preg_match( '/[^A-Za-z0-9\-\._@\/\ ]/', $path ); + $invalid_characters = preg_match( '/[^A-Za-z0-9\-\._@\/\(\) ]/', $path ); if( $invalid_characters && ! ( $_GET['action'] == "modify" || $_GET['action'] == "delete" ) ) { @@ -61,7 +61,7 @@ class Filemanager extends Common { } elseif( $invalid_characters && ( $_GET['action'] == "modify" || $_GET['action'] == "delete" ) ) { } else { - $path = preg_replace( '/[^A-Za-z0-9\-\._\/\ ]/', '', $path ); + $path = preg_replace( '/[^A-Za-z0-9\-\._@\/\(\) ]/', '', $path ); } return $path; } @@ -315,63 +315,12 @@ class Filemanager extends Common { $index = array(); - if( is_dir( $path ) && $handle = opendir( $path ) ) { + if( is_dir( $path ) ) { - while( false !== ( $object = readdir( $handle ) ) ) { - - if( $object != "." && $object != ".." && $object != "" ) { - - $full_path = $path . '/' . $object; - - if( is_link( $full_path ) ) { - - $full_path = readlink( $full_path ); - } - - if ( is_dir( $full_path ) ) { - - $type = "directory"; - $size = count( glob( $path . '/' . $object . '/*' ) ); - } else { - - $type = "file"; - $size = @filesize( $path . '/' . $object ); - } - $index[] = array( - - "name" => $relative_path . $object, - "type" => $type, - "size" => $size - ); - } - } - - $folders = array(); - $files = array(); - foreach( $index as $item => $data ) { - - if ( $data['type'] == 'directory' ) { - - $folders[] = array( "name" => htmlentities( $data['name'], ENT_QUOTES ), "type" => $data['type'], "size" => $data['size'] ); - } - if ( $data['type'] == 'file' ) { - - $files[] = array( "name" => htmlentities( $data['name'], ENT_QUOTES ), "type" => $data['type'], "size" => $data['size'] ); - } - } - - function sorter( $a, $b, $key = 'name' ) { - - return strnatcmp( $a[$key], $b[$key] ); - } - - usort( $folders, "sorter" ); - usort( $files, "sorter" ); - - $output = array_merge( $folders, $files ); + $files = $this->index_path( $path ); $response["status"] = "success"; - $response["data"] = array( "index" => $output ); + $response["data"] = array( "index" => $files ); } else { $response["status"] = "error"; @@ -385,6 +334,52 @@ class Filemanager extends Common { return $response; } + function index_path( $path ) { + + $paths = array(); + + if( is_dir( $path ) && $handle = opendir( $path ) ) { + + while( false !== ( $f = readdir( $handle ) ) ) { + + if ( "$f" != '.' && "$f" != '..' ) { + + $p = "$path" . DIRECTORY_SEPARATOR . "$f"; + $p = str_replace( "//", "/", $p ); + $rp = realpath( $p ); + $path_info = pathinfo( $p ); + + if( is_dir( $p ) ) { + + $paths[] = array( + + "basename" => $path_info["basename"], + "children" => $this->index_path( $p ), + "dirname" => str_replace( WORKSPACE . "/", "", $p ), + "extension" => null, + "filename" => $path_info["filename"], + "full_dirname" => $path_info["dirname"], + "full_path" => $p, + "path" => str_replace( WORKSPACE . "/", "", $p ), + ); + } else { + + $paths[] = array( + "basename" => $path_info["basename"], + "dirname" => str_replace( WORKSPACE . "/", "", $p ), + "extension" => isset( $path_info["extension"] ) ? $path_info["extension"] : null, + "filename" => $path_info["filename"], + "path" => str_replace( WORKSPACE . "/", "", $p ), + ); + } + } + } + } + + closedir( $handle ); + return $paths; + } + ////////////////////////////////////////////////////////////////// // MODIFY (Modifies a file name/contents or directory name) ////////////////////////////////////////////////////////////////// diff --git a/components/filemanager/context_menu.json b/components/filemanager/context_menu.json index 0a81862..13afc1f 100755 --- a/components/filemanager/context_menu.json +++ b/components/filemanager/context_menu.json @@ -17,6 +17,12 @@ "applies-to" : "directory-only non-root", "onclick": "codiad.filemanager.archive( $('#context-menu').attr('data-path') );" }, + { + "title": "Unarchive", + "icon": "icon-archive", + "applies-to" : "file-only non-root", + "onclick": "codiad.filemanager.unarchive( $('#context-menu').attr('data-path') );" + }, { "title": "Break", "icon": null, diff --git a/components/filemanager/controller.php b/components/filemanager/controller.php index 39dc1af..76c7d62 100755 --- a/components/filemanager/controller.php +++ b/components/filemanager/controller.php @@ -258,6 +258,33 @@ switch( $action ) { } break; + case 'unarchive': + + if( ! isset( $path ) ) { + + exit( formatJSEND( "error", "No path specified." ) ); + } + + if( ! Permissions::check_access( "create", $access ) ) { + + exit( formatJSEND( "error", "Invalid access to unzip archive." ) ); + } + + $Archive = new Archive(); + $path = $Filemanager->formatPath( $path ); + $result = $Archive->decompress( $path ); + + if( $result && $result["status"] == "success" ) { + + $response = formatJSEND( "success", $result ); + } else { + + $response = formatJSEND( "error", $result["message"] ); + } + + exit( $response ); + break; + case 'upload': $response = $Filemanager->upload( $path ); diff --git a/components/filemanager/init.js b/components/filemanager/init.js index d0ace7b..ac924f3 100755 --- a/components/filemanager/init.js +++ b/components/filemanager/init.js @@ -184,6 +184,22 @@ }); }, + unarchive: function( path ) { + + let _this = this; + + $.get( _this.controller + '?action=unarchive&path=' + encodeURIComponent( path ), function( data ) { + + console.log( data ); + let response = codiad.jsend.parse( data ); + console.log( response ); + /*parent = path.split( '/' ); + parent.pop(); + _this.rescan( parent.join( '/' ) ); + */ + }); + }, + contextCheckMouse: function( e ) { let offset = $( '#context-menu' ).offset(); @@ -429,7 +445,7 @@ // Loop out all files and folders in directory path ////////////////////////////////////////////////////////////////// - indexFiles: [], + opened_folders: [], index: function( path, rescan ) { @@ -452,35 +468,41 @@ }); } - if( node.hasClass( 'open' ) && ! rescan ) { + let open = node.hasClass( 'open' ); + + if( open ) { + + _this.opened_folders.push( path ); + } + + if( open && ! rescan ) { node.parent( 'li' ) - .children( 'ul' ) - .slideUp( 300, function() { - $( this ) - .remove(); - node.removeClass( 'open' ); - }); + .children( 'ul' ) + .slideUp( 300, function() { + $( this ) + .remove(); + node.removeClass( 'open' ); + }); } else { node.addClass( 'loading' ); $.get( this.controller + '?action=index&path=' + encodeURIComponent( path ), function( data ) { node.addClass( 'open' ); - let response = codiad.jsend.parse( data ); + let response = codiad.jsend.parse( data ); + console.log( response ); if( response != 'error' ) { /* Notify listener */ - _this.indexFiles = response.index; + files = response.index; amplify.publish( "filemanager.onIndex", { path: path, files: _this.indexFiles }); - let files = _this.indexFiles; - - if( files.length > 0 ) { + if( Object.keys( files ).length > 0 ) { let expanded = parentNode.children( 'span' ).hasClass( 'plus' ); @@ -495,70 +517,11 @@ if( rescan ) { display = ''; - } - - container.css( "display", display ); - - $.each( files, function( index ) { - - let ext = ''; - let name = files[index].name.replace( path, '' ); - let nodeClass = 'none'; - let entry = $( "
  • " ); - let span = $( "" ); - let link = $( "" ); - - entry.draggable({ - - opacity: 0.85, - revert: true, - start: _this.object_start, - stop: _this.object_stop, - zIndex: 100 - }); - name = name.split( '/' ).join( ' ' ); - - if( files[index].type == 'file' ) { - - ext = 'ext-' + name.split( '.' ).pop(); - } else { - - link.droppable({ - accept: _this.object_accept, - drop: _this.object_drop, - over: _this.object_over, - out: _this.object_out - }); - } - - if( files[index].type == 'directory' && files[index].size > 0 ) { - - if( expanded ) { - - nodeClass = 'minus'; - } else { - - nodeClass = 'plus'; - } - } - - span.addClass( nodeClass ); - - link.addClass( files[index].type ); - link.addClass( ext ); - link.attr( "data-type", files[index].type ); - link.attr( "data-path", files[index].name ); - link.text( name ); - - entry.append( span, link ); - container.append( entry ); - }); - - if( rescan ) { - node.parent( 'li' ).children( 'ul' ).remove(); } + container.css( "display", display ); + _this.createIndexes( files, container ); $( container ).insertAfter( node ); if( ! rescan ) { @@ -567,21 +530,75 @@ } } } - node.removeClass( 'loading' ); - - if( rescan && _this.rescanChildren.length > _this.rescanCounter ) { - - _this.rescan( _this.rescanChildren[_this.rescanCounter++] ); - } else { - - _this.rescanChildren = []; - _this.rescanCounter = 0; - } }); } }, + createIndexes: function( files, container = null ) { + + let _this = this; + + $.each( files, function( key, value ) { + + console.log( key, value ); + + let expanded = _this.opened_folders.includes( value.path ); + let ext = ''; + let name = ''; + let nodeClass = 'none'; + let entry = $( "
  • " ); + let span = $( "" ); + let link = $( "" ); + let type = null; + + entry.draggable({ + + opacity: 0.85, + revert: true, + start: _this.object_start, + stop: _this.object_stop, + zIndex: 100 + }); + + if( value.children == undefined ) { + + ext = "ext-" + value.extension; + name = value.basename; + type = 'file'; + link.addClass( ext ); + } else { + + link.droppable({ + accept: _this.object_accept, + drop: _this.object_drop, + over: _this.object_over, + out: _this.object_out + }); + + if( expanded ) { + + nodeClass = 'minus'; + } else { + + nodeClass = 'plus'; + } + + name = value.basename; + type = 'directory'; + } + + span.addClass( nodeClass ); + link.addClass( type ); + link.attr( "data-type", type ); + link.attr( "data-path", value.path ); + link.text( name ); + + entry.append( span, link ); + container.append( entry ); + }); + }, + ////////////////////////////////////////////////////////////////// // Listen for dbclick events on nodes //////////////////////////////////////////////////////////////////