Continued work on new archive system, Improved file indexing performance, Added unarchive to context menu

This commit is contained in:
xevidos 2019-10-24 22:27:51 -04:00
parent 7700671b1d
commit a377b4dddd
5 changed files with 208 additions and 143 deletions

View file

@ -127,20 +127,34 @@ class Archive {
public static function decompress( $file, $output = "default" ) { public static function decompress( $file, $output = "default" ) {
$type = filetype( $file );
$response = array(); $response = array();
$path_info = pathinfo( $file );
$type = isset( $path_info["extension"] ) ? $path_info["extension"] : null;
$supported = self::supports( $type ); $supported = self::supports( $type );
$archive = self::get_instance(); $archive = self::get_instance();
if( $output == "default" ) {
$output = $path_info["dirname"] . "/" . $path_info["filename"];
}
if( $supported["status"] === "success" ) { if( $supported["status"] === "success" ) {
if( extension_loaded( self::EXTENSIONS["{$type}"] ) ) { 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 { } else {
$response = $archive->execute( $type, "decompress" ); $response = $archive->execute( $type, "decompress" );
} }
if( $response === true ) {
$response = array(
"status" => "success",
"message" => null,
);
}
} else { } else {
$response = $supported; $response = $supported;
@ -257,11 +271,17 @@ class Archive {
function zip_d( $path, $output ) { function zip_d( $path, $output ) {
if( ! is_dir( $output ) ) {
mkdir( $output );
}
$status = false; $status = false;
$output = rtrim( $output, '/' ) . '/'; $output = rtrim( $output, '/' ) . '/';
$archive = new ZipArchive(); $archive = new ZipArchive();
$open = $archive->open( $path );
if ( $archive->open( $path ) === true ) { if ( $open === true ) {
$archive->extractTo( $output ); $archive->extractTo( $output );
$archive->close(); $archive->close();

View file

@ -53,7 +53,7 @@ class Filemanager extends Common {
* trying to rename or delete it, allow the actual file name. * 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" ) ) { 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" ) ) { } elseif( $invalid_characters && ( $_GET['action'] == "modify" || $_GET['action'] == "delete" ) ) {
} else { } else {
$path = preg_replace( '/[^A-Za-z0-9\-\._\/\ ]/', '', $path ); $path = preg_replace( '/[^A-Za-z0-9\-\._@\/\(\) ]/', '', $path );
} }
return $path; return $path;
} }
@ -315,63 +315,12 @@ class Filemanager extends Common {
$index = array(); $index = array();
if( is_dir( $path ) && $handle = opendir( $path ) ) { if( is_dir( $path ) ) {
while( false !== ( $object = readdir( $handle ) ) ) { $files = $this->index_path( $path );
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 );
$response["status"] = "success"; $response["status"] = "success";
$response["data"] = array( "index" => $output ); $response["data"] = array( "index" => $files );
} else { } else {
$response["status"] = "error"; $response["status"] = "error";
@ -385,6 +334,52 @@ class Filemanager extends Common {
return $response; 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) // MODIFY (Modifies a file name/contents or directory name)
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////

View file

@ -17,6 +17,12 @@
"applies-to" : "directory-only non-root", "applies-to" : "directory-only non-root",
"onclick": "codiad.filemanager.archive( $('#context-menu').attr('data-path') );" "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", "title": "Break",
"icon": null, "icon": null,

View file

@ -258,6 +258,33 @@ switch( $action ) {
} }
break; 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': case 'upload':
$response = $Filemanager->upload( $path ); $response = $Filemanager->upload( $path );

View file

@ -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 ) { contextCheckMouse: function( e ) {
let offset = $( '#context-menu' ).offset(); let offset = $( '#context-menu' ).offset();
@ -429,7 +445,7 @@
// Loop out all files and folders in directory path // Loop out all files and folders in directory path
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
indexFiles: [], opened_folders: [],
index: function( path, rescan ) { 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' ) node.parent( 'li' )
.children( 'ul' ) .children( 'ul' )
.slideUp( 300, function() { .slideUp( 300, function() {
$( this ) $( this )
.remove(); .remove();
node.removeClass( 'open' ); node.removeClass( 'open' );
}); });
} else { } else {
node.addClass( 'loading' ); node.addClass( 'loading' );
$.get( this.controller + '?action=index&path=' + encodeURIComponent( path ), function( data ) { $.get( this.controller + '?action=index&path=' + encodeURIComponent( path ), function( data ) {
node.addClass( 'open' ); node.addClass( 'open' );
let response = codiad.jsend.parse( data ); let response = codiad.jsend.parse( data );
console.log( response );
if( response != 'error' ) { if( response != 'error' ) {
/* Notify listener */ /* Notify listener */
_this.indexFiles = response.index; files = response.index;
amplify.publish( "filemanager.onIndex", { amplify.publish( "filemanager.onIndex", {
path: path, path: path,
files: _this.indexFiles files: _this.indexFiles
}); });
let files = _this.indexFiles; if( Object.keys( files ).length > 0 ) {
if( files.length > 0 ) {
let expanded = parentNode.children( 'span' ).hasClass( 'plus' ); let expanded = parentNode.children( 'span' ).hasClass( 'plus' );
@ -495,70 +517,11 @@
if( rescan ) { if( rescan ) {
display = ''; display = '';
}
container.css( "display", display );
$.each( files, function( index ) {
let ext = '';
let name = files[index].name.replace( path, '' );
let nodeClass = 'none';
let entry = $( "<li></li>" );
let span = $( "<span></span>" );
let link = $( "<a></a>" );
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(); node.parent( 'li' ).children( 'ul' ).remove();
} }
container.css( "display", display );
_this.createIndexes( files, container );
$( container ).insertAfter( node ); $( container ).insertAfter( node );
if( ! rescan ) { if( ! rescan ) {
@ -567,21 +530,75 @@
} }
} }
} }
node.removeClass( 'loading' ); 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 = $( "<li></li>" );
let span = $( "<span></span>" );
let link = $( "<a></a>" );
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 // Listen for dbclick events on nodes
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////