mirror of
https://github.com/misterunknown/ifm.git
synced 2025-08-10 18:14:00 +02:00
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
ifm.php -diff
|
||||
build/* -diff
|
30
README.md
30
README.md
@@ -1,12 +1,22 @@
|
||||
# IFM - improved file manager
|
||||
## about
|
||||
This is a simple filemanager. It is a single file solution which uses HTML5, CSS3, JavaScript and PHP. It works like a client-server system where HTML5/CSS3/JavaScript is the client part and the PHP API acts as the server, which reduces the traffic significant.
|
||||
The IFM is a web-based filemanager, which comes as a single file solution using HTML5, CSS3, JavaScript and PHP.
|
||||
|
||||
The IFM uses the following resources:
|
||||
* [ACE Editor](https://ace.c9.io)
|
||||
* [Bootstrap v3](https://getbootstrap.com)
|
||||
* [jQuery](https://jquery.com)
|
||||
* custom icon set generated with [Fontello](http://fontello.com/)
|
||||
* [jQuery](https://jquery.com)
|
||||
* [Mustache](https://mustache.github.io/)
|
||||
|
||||
## features
|
||||
* create/edit files and directories
|
||||
* copy/move files and directories
|
||||
* download files and directories
|
||||
* upload files directly or via URL
|
||||
* extract zip archives
|
||||
* change permissions
|
||||
* image preview
|
||||
|
||||
## requirements
|
||||
| Client | Server |
|
||||
@@ -19,8 +29,8 @@ Just copy the ifm.php to your webspace - thats all :)
|
||||
|
||||
## key bindings
|
||||
* <kbd>e</kbd> - edit / extract current file
|
||||
* <kbd>h</kbd><kbd>j</kbd><kbd>k</kbd><kbd>l</kbd> - vim-style navigation
|
||||
* <kbd>g</kbd> - focus path (goto)
|
||||
* <kbd>h</kbd><kbd>j</kbd><kbd>k</kbd><kbd>l</kbd> - vim-style navigation (alternative to arrow keys)
|
||||
* <kbd>g</kbd> - focus the path input field (i.e. "goto")
|
||||
* <kbd>r</kbd> - refresh file table
|
||||
* <kbd>u</kbd> - upload a file
|
||||
* <kbd>o</kbd> - remote upload a file
|
||||
@@ -29,11 +39,12 @@ Just copy the ifm.php to your webspace - thats all :)
|
||||
* <kbd>D</kbd> - new directory
|
||||
* <kbd>space</kbd> - select a highlighted item
|
||||
* <kbd>del</kbd> - delete selected files
|
||||
* <kbd>Enter</kbd> - open a file or change to the directory
|
||||
|
||||
## configuration
|
||||
The configuration is located at the top of the script in a separate configuration class. The options in the class are commented and named laconically. If you have questions anyway [write me an email](mailto:marco@misterunknown.de).
|
||||
The configuration is located at the top of the script. The options are commented and named laconically. If you have any questions [write me an email](mailto:marco@misterunknown.de).
|
||||
### authentication
|
||||
Meanwhile I added a super simple authentication feature using the configuration keys `auth` and `auth_source`. You can configure it like this:
|
||||
The IFM offers a simple authentication feature using the configuration keys `auth` and `auth_source`. You can configure it like this:
|
||||
```php
|
||||
"auth" => 1,
|
||||
"auth_source" => 'inline;<username>:<password_hash>',
|
||||
@@ -46,7 +57,7 @@ The file should contain ONLY ONE LINE:
|
||||
```
|
||||
<username>:<password_hash>
|
||||
```
|
||||
The password hash has to be a hash generated by PHPs `password_hash()` function. The default credentials are "admin:admin".
|
||||
The password hash has to be a hash generated by PHPs `password_hash()` function. The default credentials are "admin:admin".
|
||||
|
||||
## screenshots
|
||||
<a href="https://misterunknown.de/static/ifm_screenshot_desktop_filelist.png"><img src="https://misterunknown.de/static/ifm_screenshot_desktop_filelist.png" height="300px"></a>
|
||||
@@ -57,8 +68,5 @@ The password hash has to be a hash generated by PHPs `password_hash()` function.
|
||||
## issues
|
||||
Currently there are no known issues. If you find any flaws please let me know.
|
||||
|
||||
|
||||
## security information
|
||||
The IFM was developed with the assumption that the highest level of operation is the scripts base location. So it is neither possible to nagivate nor to use any API function in a level above the script root.
|
||||
|
||||
It is highly recommended to restrict access to the script e.g. using a basic authentication.
|
||||
By default, the IFM is locked to it's own directory, so you are not able to go above. You can change that by setting the $root_dir in the scripts configuration.
|
||||
|
1240
build/ifm.js
Normal file
1240
build/ifm.js
Normal file
File diff suppressed because it is too large
Load Diff
2833
build/ifmlib.php
Normal file
2833
build/ifmlib.php
Normal file
File diff suppressed because one or more lines are too long
70
compiler.php
70
compiler.php
@@ -1,32 +1,56 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
/**
|
||||
* IFM compiler
|
||||
*
|
||||
* This script compiles all sources into one single file.
|
||||
*/
|
||||
|
||||
// This compiles the source files into one file
|
||||
chdir( realpath( dirname( __FILE__ ) ) );
|
||||
|
||||
$IFM_CONFIG = "src/config.php";
|
||||
$IFM_MAIN = "src/main.php";
|
||||
$IFM_OTHER_PHPFILES = array("src/ifmzip.php");
|
||||
$IFM_SRC_MAIN = "src/main.php";
|
||||
$IFM_SRC_PHPFILES = array( "src/ifmzip.php" );
|
||||
$IFM_SRC_JS = "src/ifm.js";
|
||||
|
||||
$filename = "ifm.php";
|
||||
$IFM_BUILD_STANDALONE = "ifm.php";
|
||||
$IFM_BUILD_LIB_PHP = "build/ifmlib.php";
|
||||
|
||||
// config
|
||||
file_put_contents($filename, file_get_contents($IFM_CONFIG));
|
||||
|
||||
// other php classes
|
||||
foreach ( $IFM_OTHER_PHPFILES as $file) {
|
||||
$content_file = file($file);
|
||||
unset($content_file[0]); // remove <?php line
|
||||
file_put_contents($filename, $content_file, FILE_APPEND);
|
||||
/**
|
||||
* Prepare main script
|
||||
*/
|
||||
$main = file_get_contents( $IFM_SRC_MAIN );
|
||||
$includes = NULL;
|
||||
preg_match_all( "/\@\@\@([^\@]+)\@\@\@/", $main, $includes, PREG_SET_ORDER );
|
||||
foreach( $includes as $file ) {
|
||||
$main = str_replace( $file[0], file_get_contents( $file[1] ), $main );
|
||||
}
|
||||
|
||||
// main
|
||||
$content_main = file($IFM_MAIN);
|
||||
unset($content_main[0]);
|
||||
$content_main = implode($content_main);
|
||||
$include_files = NULL;
|
||||
preg_match_all( "/\@\@\@([^\@]+)\@\@\@/", $content_main, $include_files, PREG_SET_ORDER );
|
||||
foreach( $include_files as $file ) {
|
||||
//echo $file[0]. " " .$file[1]."\n";
|
||||
$content_main = str_replace( $file[0], file_get_contents( $file[1] ), $content_main );
|
||||
/**
|
||||
* Add PHP files
|
||||
*/
|
||||
$phpincludes = array();
|
||||
foreach( $IFM_SRC_PHPFILES as $file ) {
|
||||
$content = file( $file );
|
||||
unset( $content[0] ); // remove <?php line
|
||||
$phpincludes = array_merge( $phpincludes, $content );
|
||||
}
|
||||
file_put_contents($filename, $content_main, FILE_APPEND);
|
||||
|
||||
/**
|
||||
* Build standalone script
|
||||
*/
|
||||
file_put_contents( $IFM_BUILD_STANDALONE, $main );
|
||||
file_put_contents( $IFM_BUILD_STANDALONE, $phpincludes, FILE_APPEND );
|
||||
file_put_contents( $IFM_BUILD_STANDALONE, array(
|
||||
'',
|
||||
'/**',
|
||||
' * start IFM',
|
||||
' */',
|
||||
'$ifm = new IFM();',
|
||||
'$ifm->run();'
|
||||
), FILE_APPEND );
|
||||
|
||||
/**
|
||||
* Build library
|
||||
*/
|
||||
file_put_contents( $IFM_BUILD_LIB_PHP, $main );
|
||||
file_put_contents( $IFM_BUILD_LIB_PHP, $phpincludes, FILE_APPEND );
|
||||
|
@@ -1,87 +0,0 @@
|
||||
<?php
|
||||
|
||||
/* =======================================================================
|
||||
* Improved File Manager
|
||||
* ---------------------
|
||||
* License: This project is provided under the terms of the MIT LICENSE
|
||||
* http://github.com/misterunknown/ifm/blob/master/LICENSE
|
||||
* =======================================================================
|
||||
*
|
||||
* config
|
||||
*/
|
||||
|
||||
class IFMConfig {
|
||||
|
||||
// 0 = no/not allowed;; 1 = yes/allowed;; default: no/forbidden;
|
||||
|
||||
// action controls
|
||||
const upload = 1; // allow uploads
|
||||
const remoteupload = 1; // allow remote uploads using cURL
|
||||
const delete = 1; // allow deletions
|
||||
const rename = 1; // allow renamings
|
||||
const edit = 1; // allow editing
|
||||
const chmod = 1; // allow to change rights
|
||||
const extract = 1; // allow extracting zip archives
|
||||
const download = 1; // allow to download files and skripts (even php scripts!)
|
||||
const selfdownload = 1; // allow to download this skript itself
|
||||
const createdir = 1; // allow to create directorys
|
||||
const createfile = 1; // allow to create files
|
||||
const zipnload = 1; // allow to zip and download directorys
|
||||
|
||||
// view controls
|
||||
const multiselect = 1; // implement multiselect of files and directories
|
||||
const showlastmodified = 0; // show the last modified date?
|
||||
const showfilesize = 1; // show filesize?
|
||||
const showowner = 1; // show file owner?
|
||||
const showgroup = 1; // show file group?
|
||||
const showpermissions = 2; // show permissions 0 -> 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:
|
||||
<username>:<passwordhash>
|
||||
|
||||
examples:
|
||||
const auth_source = 'inline;admin:$2y$10$0Bnm5L4wKFHRxJgNq.oZv.v7yXhkJZQvinJYR2p6X1zPvzyDRUVRC';
|
||||
const auth_source = 'file;/path/to/file';
|
||||
*/
|
||||
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
|
||||
|
||||
static function getConstants() {
|
||||
$oClass = new ReflectionClass(__CLASS__);
|
||||
return $oClass->getConstants();
|
||||
}
|
||||
}
|
1196
src/ifm.js
1196
src/ifm.js
File diff suppressed because it is too large
Load Diff
@@ -13,6 +13,9 @@
|
||||
*/
|
||||
|
||||
class IFMZip {
|
||||
/**
|
||||
* Add a folder to the zip file
|
||||
*/
|
||||
private static function folderToZip($folder, &$zipFile, $exclusiveLength) {
|
||||
$handle = opendir( $folder );
|
||||
while( false !== $f = readdir( $handle ) ) {
|
||||
@@ -34,7 +37,10 @@ class IFMZip {
|
||||
closedir( $handle );
|
||||
}
|
||||
|
||||
public static function create_zip( $src, $out, $root=false )
|
||||
/**
|
||||
* Create a zip file
|
||||
*/
|
||||
public static function create( $src, $out, $root=false )
|
||||
{
|
||||
$z = new ZipArchive();
|
||||
$z->open( $out, ZIPARCHIVE::CREATE);
|
||||
@@ -53,11 +59,14 @@ class IFMZip {
|
||||
}
|
||||
}
|
||||
|
||||
public static function unzip_file( $file ) {
|
||||
$zip = new ZipArchive();
|
||||
/**
|
||||
* Unzip a zip file
|
||||
*/
|
||||
public static function extract( $file, $destination="./" ) {
|
||||
$zip = new ZipArchive;
|
||||
$res = $zip->open( $file );
|
||||
if( $res === true ) {
|
||||
$zip->extractTo( './' );
|
||||
$zip->extractTo( $destination );
|
||||
$zip->close();
|
||||
return true;
|
||||
} else {
|
||||
|
1
src/includes/bootstrap-treeview.min.css
vendored
Normal file
1
src/includes/bootstrap-treeview.min.css
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.treeview .list-group-item{cursor:pointer}.treeview span.indent{margin-left:10px;margin-right:10px}.treeview span.icon{width:12px;margin-right:5px}.treeview .node-disabled{color:silver;cursor:not-allowed}
|
1
src/includes/bootstrap-treeview.min.js
vendored
Normal file
1
src/includes/bootstrap-treeview.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
src/includes/ekko-lightbox.min.css
vendored
2
src/includes/ekko-lightbox.min.css
vendored
@@ -1,2 +0,0 @@
|
||||
.ekko-lightbox-nav-overlay a:focus,.ekko-lightbox-nav-overlay a>:focus{outline:0}.ekko-lightbox-container{position:relative}.ekko-lightbox-container>div.ekko-lightbox-item{position:absolute;top:0;left:0;width:100%;transition:opacity .5s ease-in-out;opacity:1}.ekko-lightbox-nav-overlay{z-index:1;position:absolute;top:0;left:0;width:100%;height:100%;display:-ms-flexbox;display:flex}.ekko-lightbox-nav-overlay a{-ms-flex:1;flex:1;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;opacity:0;transition:opacity .5s;color:#fff;font-size:30px;z-index:1}.ekko-lightbox-nav-overlay a>*{-ms-flex-positive:1;flex-grow:1}.ekko-lightbox-nav-overlay a span{padding:0 30px}.ekko-lightbox-nav-overlay a:last-child span{text-align:right}.ekko-lightbox-nav-overlay a:hover{text-decoration:none}.ekko-lightbox a:hover{opacity:1;text-decoration:none}.ekko-lightbox .modal-footer{text-align:left}.ekko-lightbox-loader{position:absolute;top:0;left:0;bottom:0;right:0;width:100%;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;-ms-flex-align:center;align-items:center}.ekko-lightbox-loader>div{width:40px;height:40px;position:relative;text-align:center}.ekko-lightbox-loader>div>div{width:100%;height:100%;border-radius:50%;background-color:#fff;opacity:.6;position:absolute;top:0;left:0;animation:a 2s infinite ease-in-out}.ekko-lightbox-loader>div>div:last-child{animation-delay:-1s}@keyframes a{0%,to{transform:scale(0);-webkit-transform:scale(0)}50%{transform:scale(1);-webkit-transform:scale(1)}}
|
||||
/*# sourceMappingURL=ekko-lightbox.min.css.map */
|
2
src/includes/ekko-lightbox.min.js
vendored
2
src/includes/ekko-lightbox.min.js
vendored
File diff suppressed because one or more lines are too long
1
src/includes/mustache.min.js
vendored
Normal file
1
src/includes/mustache.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
610
src/main.php
610
src/main.php
@@ -13,17 +13,56 @@
|
||||
error_reporting( E_ALL );
|
||||
ini_set( 'display_errors', 'OFF' );
|
||||
|
||||
class IFM {
|
||||
const VERSION = '2.3.1';
|
||||
|
||||
public function __construct() {
|
||||
session_start();
|
||||
class IFM {
|
||||
const VERSION = '2.4.0';
|
||||
|
||||
private $defaultconfig = array(
|
||||
// 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();
|
||||
public $mode = "";
|
||||
|
||||
public function __construct( $config=array() ) {
|
||||
if( session_status() !== PHP_SESSION_ACTIVE )
|
||||
session_start();
|
||||
$this->config = array_merge( $this->defaultconfig, $config );
|
||||
}
|
||||
|
||||
/*
|
||||
this function contains the client-side application
|
||||
/**
|
||||
* This function contains the client-side application
|
||||
*/
|
||||
|
||||
public function getApplication() {
|
||||
print '<!DOCTYPE HTML>
|
||||
<html>
|
||||
@@ -31,91 +70,43 @@ class IFM {
|
||||
<title>IFM - improved file manager</title>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style type="text/css">';?> @@@src/includes/bootstrap.min.css@@@ <?php print '</style>
|
||||
<style type="text/css">';?> @@@src/includes/ekko-lightbox.min.css@@@ <?php print '</style>
|
||||
<style type="text/css">';?> @@@src/includes/fontello-embedded.css@@@ <?php print '</style>
|
||||
<style type="text/css">';?> @@@src/style.css@@@ <?php print '</style>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">';
|
||||
$this->getCSS();
|
||||
print '
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<a class="navbar-brand">IFM</a>
|
||||
<button class="navbar-toggle" type="button" data-toggle="collapse" data-target="#navbar">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="navbar-collapse collapse" id="navbar">
|
||||
<form class="navbar-form navbar-left">
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon" id="currentDirLabel">Content of <span id="docroot">';
|
||||
print ( IFMConfig::showpath == 1 ) ? realpath( IFMConfig::root_dir ) : "/";
|
||||
print '</span></span><input class="form-control" id="currentDir" aria-describedby="currentDirLabel" type="text">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li><a id="refresh"><span title="refresh" class="icon icon-arrows-cw"></span> <span class="visible-xs">refresh</span></a></li>';
|
||||
if( IFMConfig::upload == 1 ) {
|
||||
print '<li><a id="upload"><span title="upload" class="icon icon-upload"></span> <span class="visible-xs">upload</span></a></li>';
|
||||
}
|
||||
if( IFMConfig::createfile == 1 ) {
|
||||
print '<li><a id="createFile"><span title="new file" class="icon icon-doc-inv"></span> <span class="visible-xs">new file</span></a></li>';
|
||||
}
|
||||
if( IFMConfig::createdir == 1 ) {
|
||||
print '<li><a id="createDir"><span title="new folder" class="icon icon-folder"></span> <span class="visible-xs">new folder</span></a></li>';
|
||||
}
|
||||
print '<li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><span class="icon icon-down-open"></span></a><ul class="dropdown-menu" role="menu">';
|
||||
$options = false;
|
||||
if( IFMConfig::remoteupload == 1 ) {
|
||||
print '<li><a onclick="ifm.remoteUploadDialog();return false;"><span class="icon icon-upload-cloud"></span> remote upload</a></li>';
|
||||
$options = true;
|
||||
}
|
||||
if( IFMConfig::ajaxrequest == 1 ) {
|
||||
print '<li><a onclick="ifm.ajaxRequestDialog();return false;"><span class="icon icon-link-ext"></span> ajax request</a></li>';
|
||||
$options = true;
|
||||
}
|
||||
if( !$options ) print '<li>No options available</li>';
|
||||
print '</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="container">
|
||||
<table id="filetable" class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Filename</th>';
|
||||
if( IFMConfig::download == 1 ) print '<th><!-- column for download link --></th>';
|
||||
if( IFMConfig::showlastmodified == 1 ) print '<th>last modified</th>';
|
||||
if( IFMConfig::showfilesize == 1 ) print '<th>size</th>';
|
||||
if( IFMConfig::showpermissions > 0 ) print '<th class="hidden-xs">permissions</th>';
|
||||
if( IFMConfig::showowner == 1 && function_exists( "posix_getpwuid" ) ) print '<th class="hidden-xs hidden-sm">owner</th>';
|
||||
if( IFMConfig::showgroup == 1 && function_exists( "posix_getgrgid" ) ) print '<th class="hidden-xs hidden-sm hidden-md">group</th>';
|
||||
if( in_array( 1, array( IFMConfig::edit, IFMConfig::rename, IFMConfig::delete, IFMConfig::zipnload, IFMConfig::extract ) ) ) print '<th class="buttons"><!-- column for buttons --></th>';
|
||||
print '</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="panel panel-default footer"><div class="panel-body">IFM - improved file manager | ifm.php hidden | <a href="http://github.com/misterunknown/ifm">Visit the project on GitHub</a></div></div>
|
||||
</div>
|
||||
<div id="ifm"></div>';
|
||||
$this->getJS();
|
||||
print '
|
||||
<script>var ifm = new IFM(); ifm.init( "ifm" );</script>
|
||||
</body>
|
||||
</html>
|
||||
';
|
||||
}
|
||||
|
||||
public function getInlineApplication() {
|
||||
$this->getCSS();
|
||||
print '<div id="ifm"></div>';
|
||||
$this->getJS();
|
||||
}
|
||||
|
||||
public function getCSS() {
|
||||
print '
|
||||
<style type="text/css">';?> @@@src/includes/bootstrap.min.css@@@ <?php print '</style>
|
||||
<style type="text/css">';?> @@@src/includes/fontello-embedded.css@@@ <?php print '</style>
|
||||
<style type="text/css">';?> @@@src/style.css@@@ <?php print '</style>
|
||||
';
|
||||
}
|
||||
|
||||
public function getJS() {
|
||||
print '
|
||||
<script>';?> @@@src/includes/ace.js@@@ <?php print '</script>
|
||||
<script>';?> @@@src/includes/jquery.min.js@@@ <?php print '</script>
|
||||
<script>';?> @@@src/includes/bootstrap.min.js@@@ <?php print '</script>
|
||||
<script>';?> @@@src/includes/bootstrap-notify.min.js@@@ <?php print '</script>
|
||||
<script>';?> @@@src/includes/ekko-lightbox.min.js@@@ <?php print '</script>
|
||||
<script>';?> @@@src/includes/bootstrap-treeview.min.js@@@ <?php print '</script>
|
||||
<script>';?> @@@src/includes/mustache.min.js@@@ <?php print '</script>
|
||||
<script>';?> @@@src/ifm.js@@@ <?php print '</script>
|
||||
</body>
|
||||
</html>
|
||||
';
|
||||
}
|
||||
|
||||
@@ -135,40 +126,55 @@ class IFM {
|
||||
$this->getFiles( $_REQUEST["dir"] );
|
||||
else
|
||||
$this->getFiles( "" );
|
||||
} else {
|
||||
}
|
||||
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 "deleteFile": $this->deleteFile( $_REQUEST ); break;
|
||||
case "renameFile": $this->renameFile( $_REQUEST ); break;
|
||||
case "downloadFile": $this->downloadFile( $_REQUEST ); break;
|
||||
case "extractFile": $this->extractFile( $_REQUEST ); break;
|
||||
case "uploadFile": $this->uploadFile( $_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 "deleteMultipleFiles": $this->deleteMultipleFiles( $_REQUEST ); break;
|
||||
default: echo json_encode(array("status"=>"ERROR", "message"=>"No valid api action given")); 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"));
|
||||
}
|
||||
}
|
||||
exit( 0 );
|
||||
}
|
||||
|
||||
public function run() {
|
||||
public function run( $mode="standalone" ) {
|
||||
if ( $this->checkAuth() ) {
|
||||
// go to our root_dir
|
||||
if( ! is_dir( realpath( IFMConfig::root_dir ) ) || ! is_readable( realpath( IFMConfig::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( IFMConfig::root_dir ) );
|
||||
if ( ! isset($_REQUEST['api']) ) {
|
||||
$this->getApplication();
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -177,61 +183,53 @@ class IFM {
|
||||
api functions
|
||||
*/
|
||||
|
||||
private function getFiles($dir) {
|
||||
// SECURITY FUNCTION (check that we don't operate on a higher level that the script itself)
|
||||
$dir=$this->getValidDir($dir);
|
||||
// now we change in our target directory
|
||||
$this->chDirIfNecessary($dir);
|
||||
// unset our file and directory arrays
|
||||
unset($files); unset($dirs); $files = array(); $dirs = array();
|
||||
// so lets loop over our directory
|
||||
if ($handle = opendir(".")) {
|
||||
while (false !== ($result = readdir($handle))) { // this awesome statement is the correct way to loop over a directory :)
|
||||
if( $result == basename( $_SERVER['SCRIPT_NAME'] ) && $this->getScriptRoot() == getcwd() ) { } // we don't want to see the script itself
|
||||
elseif( ( $result == ".htaccess" || $result==".htpasswd" ) && IFMConfig::showhtdocs != 1 ) {} // check if we are granted to see .ht-docs
|
||||
elseif( $result == "." ) {} // the folder itself will also be invisible
|
||||
elseif( $result != ".." && substr( $result, 0, 1 ) == "." && IFMConfig::showhiddenfiles != 1 ) {} // eventually hide hidden files, if we should not see them
|
||||
elseif( ! @is_readable( $result ) ) {}
|
||||
else { // thats are the files we should see
|
||||
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();
|
||||
$i = 0;
|
||||
$item["name"] = $result;
|
||||
$i++;
|
||||
if( is_dir($result) ) {
|
||||
$item["type"] = "dir";
|
||||
} else {
|
||||
$item["type"] = "file";
|
||||
}
|
||||
if( is_dir( $result ) ) {
|
||||
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( IFMConfig::showlastmodified == 1 ) { $item["lastmodified"] = date( "d.m.Y, G:i e", filemtime( $result ) ); }
|
||||
if( IFMConfig::showfilesize == 1 ) {
|
||||
$item["filesize"] = filesize( $result );
|
||||
if( $item["filesize"] > 1073741824 ) $item["filesize"] = round( ( $item["filesize"]/1073741824 ), 2 ) . " GB";
|
||||
elseif($item["filesize"]>1048576)$item["filesize"] = round( ( $item["filesize"]/1048576 ), 2 ) . " MB";
|
||||
elseif($item["filesize"]>1024)$item["filesize"] = round( ( $item["filesize"]/1024 ), 2 ) . " KB";
|
||||
else $item["filesize"] = $item["filesize"] . " Byte";
|
||||
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( IFMConfig::showpermissions > 0 ) {
|
||||
if( IFMConfig::showpermissions == 1 ) $item["fileperms"] = substr( decoct( fileperms( $result ) ), -3 );
|
||||
elseif( IFMConfig::showpermissions == 2 ) $item["fileperms"] = $this->filePermsDecode( fileperms( $result ) );
|
||||
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"] = ( IFMConfig::showpermissions == 1 ) ? "short" : "long";
|
||||
$item["filepermmode"] = ( $this->config['showpermissions'] == 1 ) ? "short" : "long";
|
||||
}
|
||||
if( IFMConfig::showowner == 1 ) {
|
||||
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( IFMConfig::showgroup == 1 ) {
|
||||
if( $this->config['showgroup'] == 1 ) {
|
||||
if( function_exists( "posix_getgrgid" ) && filegroup( $result ) !== false ) {
|
||||
$grouparr = posix_getgrgid( filegroup( $result ) );
|
||||
$item["group"] = $grouparr['name'];
|
||||
@@ -248,8 +246,71 @@ class IFM {
|
||||
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( $this->config['createDir'] != 1 ) {
|
||||
echo json_encode( array( "status" => "ERROR", "message" => "No permission to create directories.") );
|
||||
exit( 1 );
|
||||
}
|
||||
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" ) );
|
||||
@@ -264,14 +325,18 @@ class IFM {
|
||||
}
|
||||
|
||||
// save a file
|
||||
private function saveFile(array $d) {
|
||||
private function saveFile( $d ) {
|
||||
if( ( file_exists( $this->pathCombine( $d['dir'], $d['filename'] ) ) && $this->config['edit'] != 1 ) || ( ! file_exists( $this->pathCombine( $d['dir'], $d['filename'] ) ) && $this->config['createfile'] != 1 ) ) {
|
||||
echo json_encode( array( "status" => "ERROR", "message" => "You are not allowed to edit/create this file." ) );
|
||||
exit( 1 );
|
||||
}
|
||||
if( isset( $d['filename'] ) && $d['filename'] != "" ) {
|
||||
// if you are not allowed to see .ht-docs you can't save one
|
||||
if( IFMConfig::showhtdocs != 1 && substr( $d['filename'], 0, 3 ) == ".ht" ) {
|
||||
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( IFMConfig::showhiddenfiles != 1 && substr( $d['filename'], 0, 1 ) == "." ) {
|
||||
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) {
|
||||
@@ -298,7 +363,7 @@ class IFM {
|
||||
// gets the content of a file
|
||||
// notice: if the content is not JSON encodable it returns an error
|
||||
private function getContent( array $d ) {
|
||||
if( IFMConfig::edit != 1 ) echo json_encode( array( "status" => "ERROR", "message" => "No permission to edit files" ) );
|
||||
if( $this->config['edit'] != 1 ) echo json_encode( array( "status" => "ERROR", "message" => "You are not allowed to edit files." ) );
|
||||
else {
|
||||
$this->chDirIfNecessary( $d['dir'] );
|
||||
if( file_exists( $d['filename'] ) ) {
|
||||
@@ -311,7 +376,7 @@ class IFM {
|
||||
|
||||
// deletes a file or a directory (recursive!)
|
||||
private function deleteFile( array $d ) {
|
||||
if( IFMConfig::delete != 1 ) {
|
||||
if( $this->config['delete'] != 1 ) {
|
||||
echo json_encode( array( "status" => "ERROR", "message" => "No permission to delete files" ) );
|
||||
}
|
||||
else {
|
||||
@@ -336,7 +401,7 @@ class IFM {
|
||||
|
||||
// deletes a bunch of files or directories
|
||||
private function deleteMultipleFiles( array $d ) {
|
||||
if( IFMConfig::delete != 1 || IFMConfig::multiselect != 1 ) echo json_encode( array( "status" => "ERROR", "message" => "No permission to delete multiple files" ) );
|
||||
if( $this->config['delete'] != 1 ) echo json_encode( array( "status" => "ERROR", "message" => "No permission to delete files" ) );
|
||||
else {
|
||||
$this->chDirIfNecessary( $d['dir'] );
|
||||
$err = array(); $errFLAG = -1; // -1 -> no files deleted; 0 -> at least some files deleted; 1 -> all files deleted
|
||||
@@ -369,15 +434,15 @@ class IFM {
|
||||
|
||||
// renames a file
|
||||
private function renameFile( array $d ) {
|
||||
if( IFMConfig::rename != 1 ) {
|
||||
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( IFMConfig::showhtdocs != 1 && ( substr( $d['newname'], 0, 3) == ".ht" || substr( $d['filename'], 0, 3 ) == ".ht" ) )
|
||||
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( IFMConfig::showhiddenfiles != 1 && ( substr( $d['newname'], 0, 1) == "." || substr( $d['filename'], 0, 1 ) == "." ) )
|
||||
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'] ) )
|
||||
@@ -390,73 +455,58 @@ class IFM {
|
||||
|
||||
// provides a file for downloading
|
||||
private function downloadFile( array $d ) {
|
||||
if( IFMConfig::download != 1 )
|
||||
if( $this->config['download'] != 1 )
|
||||
echo json_encode( array( "status" => "ERROR", "message" => "Not allowed to download files" ) );
|
||||
elseif( IFMConfig::showhtdocs != 1 && ( substr( $d['filename'], 0, 3 ) == ".ht" || substr( $d['filename'],0,3 ) == ".ht" ) )
|
||||
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( IFMConfig::showhiddenfiles != 1 && ( substr( $d['filename'], 0, 1 ) == "." || substr( $d['filename'],0,1 ) == "." ) )
|
||||
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->file_download( $d['filename'] );
|
||||
$this->fileDownload( $d['filename'] );
|
||||
}
|
||||
}
|
||||
|
||||
// extracts a zip-archive
|
||||
private function extractFile( array $d ) {
|
||||
if( IFMConfig::extract != 1 )
|
||||
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" )
|
||||
if( ! file_exists( $d['filename'] ) || substr( $d['filename'],-4 ) != ".zip" ) {
|
||||
echo json_encode( array( "status" => "ERROR","message" => "No valid zip file found" ) );
|
||||
else {
|
||||
if( ! isset( $d['targetdir'] ) )
|
||||
$d['targetdir'] = "";
|
||||
if( strpos( $d['targetdir'], "/" ) !== false )
|
||||
echo json_encode( array( "status" => "ERROR","message" => "Target directory must not contain slashes" ) );
|
||||
else {
|
||||
switch( $d['targetdir'] ){
|
||||
case "":
|
||||
if( $this->unzip( $_POST["filename"] ) )
|
||||
echo json_encode( array( "status" => "OK","message" => "File successfully extracted." ) );
|
||||
else
|
||||
echo json_encode( array( "status" => "ERROR","message" => "File could not be extracted" ) );
|
||||
break;
|
||||
default:
|
||||
if( ! mkdir( $d['targetdir'] ) )
|
||||
echo json_encode( array( "status" => "ERROR","message" => "Could not create target directory" ) );
|
||||
else {
|
||||
chdir( $d['targetdir'] );
|
||||
if( ! $this->unzip( "../" . $d["filename"] ) ) {
|
||||
chdir( ".." );
|
||||
rmdir( $d['targetdir'] );
|
||||
echo json_encode( array( "status" => "ERROR","message" => "Could not extract file" ) );
|
||||
}
|
||||
else {
|
||||
chdir( ".." );
|
||||
echo json_encode( array( "status" => "OK","message" => "File successfully extracted" ) );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
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( IFMConfig::upload != 1 )
|
||||
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( IFMConfig::showhtdocs != 1 && ( substr( $newfilename, 0, 3 ) == ".ht" || substr( $newfilename,0,3 ) == ".ht" ) )
|
||||
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( IFMConfig::showhiddenfiles != 1 && ( substr( $newfilename, 0, 1 ) == "." || substr( $newfilename,0,1 ) == "." ) )
|
||||
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'] ) {
|
||||
@@ -478,7 +528,7 @@ class IFM {
|
||||
|
||||
// change permissions of a file
|
||||
private function changePermissions( array $d ) {
|
||||
if( IFMConfig::chmod != 1 ) echo json_encode( array( "status" => "ERROR", "message" => "No rights to change permissions" ) );
|
||||
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 {
|
||||
@@ -517,7 +567,7 @@ class IFM {
|
||||
// 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( IFMConfig::zipnload != 1 )
|
||||
if( $this->config['zipnload'] != 1 )
|
||||
echo json_encode( array( "status" => "ERROR", "message" => "No permission to download directories" ) );
|
||||
else {
|
||||
$this->chDirIfNecessary( $d['dir'] );
|
||||
@@ -527,16 +577,16 @@ class IFM {
|
||||
echo json_encode( array( "status" => "ERROR", "message" => "Filename not allowed" ) );
|
||||
else {
|
||||
unset( $zip );
|
||||
$dfile = $this->pathCombine( IFMConfig::tmp_dir, uniqid( "ifm-tmp-" ) . ".zip" ); // temporary filename
|
||||
$dfile = $this->pathCombine( $this->config['tmp_dir'], uniqid( "ifm-tmp-" ) . ".zip" ); // temporary filename
|
||||
try {
|
||||
IFMZip::create_zip( realpath( $d['filename'] ), $dfile, ( $d['filename'] == "." ) );
|
||||
IFMZip::create( realpath( $d['filename'] ), $dfile, ( $d['filename'] == "." ) );
|
||||
if( $d['filename'] == "." ) {
|
||||
if( getcwd() == $this->getScriptRoot() )
|
||||
$d['filename'] = "root";
|
||||
else
|
||||
$d['filename'] = basename( getcwd() );
|
||||
}
|
||||
$this->file_download( $dfile, $d['filename'] . ".zip" );
|
||||
$this->fileDownload( $dfile, $d['filename'] . ".zip" );
|
||||
} catch ( Exception $e ) {
|
||||
echo "An error occured: " . $e->getMessage();
|
||||
} finally {
|
||||
@@ -548,7 +598,7 @@ class IFM {
|
||||
|
||||
// uploads a file from an other server using the curl extention
|
||||
private function remoteUpload( array $d ) {
|
||||
if( IFMConfig::remoteupload != 1 )
|
||||
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']" ) );
|
||||
@@ -601,7 +651,7 @@ class IFM {
|
||||
*/
|
||||
|
||||
public function checkAuth() {
|
||||
if( IFMConfig::auth == 1 && ( ! isset( $_SESSION['auth'] ) || $_SESSION['auth'] !== true ) ) {
|
||||
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"] ) ) {
|
||||
@@ -631,21 +681,46 @@ class IFM {
|
||||
}
|
||||
}
|
||||
|
||||
private function checkCredentials($user, $pass) {
|
||||
list($src, $srcopt) = explode(";", IFMConfig::auth_source, 2);
|
||||
switch($src) {
|
||||
private function checkCredentials( $user, $pass ) {
|
||||
list( $src, $srcopt ) = explode( ";", $this->config['auth_source'], 2 );
|
||||
switch( $src ) {
|
||||
case "inline":
|
||||
list($uname, $hash) = explode(":", $srcopt);
|
||||
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')));
|
||||
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 password_verify($pass, trim($hash))?($uname == $user):false;
|
||||
return false;
|
||||
}
|
||||
|
||||
private function loginForm($loginFailed=false) {
|
||||
@@ -692,7 +767,7 @@ class IFM {
|
||||
return "";
|
||||
} else {
|
||||
$rpDir = realpath( $dir );
|
||||
$rpConfig = realpath( IFMConfig::root_dir );
|
||||
$rpConfig = realpath( $this->config['root_dir'] );
|
||||
if( $rpConfig == "/" )
|
||||
return $rpDir;
|
||||
elseif( $rpDir == $rpConfig )
|
||||
@@ -703,15 +778,25 @@ class IFM {
|
||||
}
|
||||
|
||||
private function isPathValid( $dir ) {
|
||||
$rpDir = realpath( $dir );
|
||||
$rpConfig = realpath( IFMConfig::root_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 ) ) {
|
||||
elseif( 0 === strpos( $rpDir, $rpConfig ) )
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
@@ -768,6 +853,53 @@ class IFM {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a file, or recursively copy a folder and its contents
|
||||
*
|
||||
* @author Aidan Lister <aidan@php.net>
|
||||
* @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 ) == "" )
|
||||
@@ -780,9 +912,9 @@ class IFM {
|
||||
|
||||
// check if filename is allowed
|
||||
private function allowedFileName( $f ) {
|
||||
if( IFMConfig::showhtdocs != 1 && substr( $f, 0, 3 ) == ".ht" )
|
||||
if( $this->config['showhtdocs'] != 1 && substr( $f, 0, 3 ) == ".ht" )
|
||||
return false;
|
||||
elseif( IFMConfig::showhiddenfiles != 1 && substr( $f, 0, 1 ) == "." )
|
||||
elseif( $this->config['showhiddenfiles'] != 1 && substr( $f, 0, 1 ) == "." )
|
||||
return false;
|
||||
elseif( ! $this->isPathValid( $f ) )
|
||||
return false;
|
||||
@@ -795,19 +927,6 @@ class IFM {
|
||||
return ( strtolower( $a['name'] ) < strtolower( $b['name'] ) ) ? -1 : 1;
|
||||
}
|
||||
|
||||
// unzip an archive
|
||||
private function unzip( $file ) {
|
||||
$zip = new ZipArchive;
|
||||
$res = $zip->open( $file );
|
||||
if( $res === true ) {
|
||||
$zip->extractTo( './' );
|
||||
$zip->close();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// is cURL extention avaliable?
|
||||
private function checkCurl() {
|
||||
if( !function_exists( "curl_init" ) ||
|
||||
@@ -817,7 +936,7 @@ class IFM {
|
||||
else return true;
|
||||
}
|
||||
|
||||
private function file_download( $file, $name="" ) {
|
||||
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 ) . '"' );
|
||||
@@ -835,12 +954,51 @@ class IFM {
|
||||
fclose($stdout_stream);
|
||||
}
|
||||
|
||||
///helper
|
||||
private function getTemplates() {
|
||||
$templates = array();
|
||||
$templates['app'] = <<<'f00bar'
|
||||
@@@src/templates/app.html@@@
|
||||
f00bar;
|
||||
$templates['filetable'] = <<<'f00bar'
|
||||
@@@src/templates/filetable.html@@@
|
||||
f00bar;
|
||||
$templates['file'] = <<<'f00bar'
|
||||
@@@src/templates/modal.file.html@@@
|
||||
f00bar;
|
||||
$templates['createdir'] = <<<'f00bar'
|
||||
@@@src/templates/modal.createdir.html@@@
|
||||
f00bar;
|
||||
$templates['ajaxrequest'] = <<<'f00bar'
|
||||
@@@src/templates/modal.ajaxrequest.html@@@
|
||||
f00bar;
|
||||
$templates['copymove'] = <<<'f00bar'
|
||||
@@@src/templates/modal.copymove.html@@@
|
||||
f00bar;
|
||||
$templates['createdir'] = <<<'f00bar'
|
||||
@@@src/templates/modal.createdir.html@@@
|
||||
f00bar;
|
||||
$templates['deletefile'] = <<<'f00bar'
|
||||
@@@src/templates/modal.deletefile.html@@@
|
||||
f00bar;
|
||||
$templates['extractfile'] = <<<'f00bar'
|
||||
@@@src/templates/modal.extractfile.html@@@
|
||||
f00bar;
|
||||
$templates['file'] = <<<'f00bar'
|
||||
@@@src/templates/modal.file.html@@@
|
||||
f00bar;
|
||||
$templates['multidelete'] = <<<'f00bar'
|
||||
@@@src/templates/modal.multidelete.html@@@
|
||||
f00bar;
|
||||
$templates['remoteupload'] = <<<'f00bar'
|
||||
@@@src/templates/modal.remoteupload.html@@@
|
||||
f00bar;
|
||||
$templates['renamefile'] = <<<'f00bar'
|
||||
@@@src/templates/modal.renamefile.html@@@
|
||||
f00bar;
|
||||
$templates['uploadfile'] = <<<'f00bar'
|
||||
@@@src/templates/modal.uploadfile.html@@@
|
||||
f00bar;
|
||||
|
||||
return $templates;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
start program
|
||||
*/
|
||||
|
||||
$ifm = new IFM();
|
||||
$ifm->run();
|
||||
|
@@ -7,15 +7,18 @@ body {
|
||||
font-size: 14pt;
|
||||
}
|
||||
|
||||
#filetable tr td:nth-child(5) {
|
||||
#filetable td:nth-child(5), #filetable th:nth-child(5) {
|
||||
text-align: center;
|
||||
}
|
||||
#filetable tr td:nth-child(6) {
|
||||
#filetable td:nth-child(6), #filetable th:nth-child(6) {
|
||||
text-align: center;
|
||||
}
|
||||
#filetable tr td:last-child {
|
||||
text-align: right;
|
||||
}
|
||||
#filetable td:last-child a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a { cursor: pointer !important; }
|
||||
|
||||
|
82
src/templates/app.html
Normal file
82
src/templates/app.html
Normal file
@@ -0,0 +1,82 @@
|
||||
<nav class="navbar navbar-inverse
|
||||
{{^config.inline}}
|
||||
navbar-fixed-top
|
||||
{{/config.inline}}
|
||||
">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<a class="navbar-brand">IFM</a>
|
||||
<button class="navbar-toggle" type="button" data-toggle="collapse" data-target="#navbar">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="navbar-collapse collapse" id="navbar">
|
||||
<form class="navbar-form navbar-left">
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon" id="currentDirLabel">Content of <span id="docroot">{{showpath}}</span></span>
|
||||
<input class="form-control" id="currentDir" aria-describedby="currentDirLabel" type="text">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li><a id="refresh"><span title="refresh" class="icon icon-arrows-cw"></span> <span class="visible-xs">refresh</span></a></li>
|
||||
{{#config.upload}}
|
||||
<li><a id="upload"><span title="upload" class="icon icon-upload"></span> <span class="visible-xs">upload</span></a></li>
|
||||
{{/config.upload}}
|
||||
{{#config.createfile}}
|
||||
<li><a id="createFile"><span title="new file" class="icon icon-doc-inv"></span> <span class="visible-xs">new file</span></a></li>
|
||||
{{/config.createfile}}
|
||||
{{#config.createdir}}
|
||||
<li><a id="createDir"><span title="new folder" class="icon icon-folder"></span> <span class="visible-xs">new folder</span></a></li>
|
||||
{{/config.createdir}}
|
||||
<li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><span class="icon icon-down-open"></span></a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
{{#config.remoteupload}}
|
||||
<li><a id="buttonRemoteUpload"><span class="icon icon-upload-cloud"></span> remote upload</a></li>
|
||||
{{/config.remoteupload}}
|
||||
{{#config.ajaxrequest}}
|
||||
<li><a id="buttonAjaxRequest"><span class="icon icon-link-ext"></span> ajax request</a></li>
|
||||
{{/config.ajaxrequest}}
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="container">
|
||||
<table id="filetable" class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Filename</th>
|
||||
{{#config.download}}
|
||||
<th><!-- column for download link --></th>
|
||||
{{/config.download}}
|
||||
{{#config.showlastmodified}}
|
||||
<th>last modified</th>
|
||||
{{/config.showlastmodified}}
|
||||
{{#config.showfilesize}}
|
||||
<th>size</th>
|
||||
{{/config.showfilesize}}
|
||||
{{#config.showpermissions}}
|
||||
<th class="hidden-xs">permissions</th>
|
||||
{{/config.showpermissions}}
|
||||
{{#config.showowner}}
|
||||
<th class="hidden-xs hidden-sm">owner</th>
|
||||
{{/config.showowner}}
|
||||
{{#config.showgroup}}
|
||||
<th class="hidden-xs hidden-sm hidden-md">group</th>
|
||||
{{/config.showgroup}}
|
||||
<th class="buttons"><!-- column for buttons --></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="panel panel-default footer"><div class="panel-body">IFM - improved file manager | ifm.php hidden | <a href="http://github.com/misterunknown/ifm">Visit the project on GitHub</a></div></div>
|
||||
</div>
|
52
src/templates/filetable.html
Normal file
52
src/templates/filetable.html
Normal file
@@ -0,0 +1,52 @@
|
||||
<tbody>
|
||||
{{#items}}
|
||||
<tr class="clickable-row {{rowclasses}}" data-filename="{{name}}" data-eaction="{{eaction}}">
|
||||
<td>
|
||||
<a tabindex="0" id="{{guid}}" class="ifmitem" {{{tooltip}}} data-type="{{type}}">
|
||||
<span class="{{icon}}"></span>
|
||||
{{linkname}}
|
||||
</a>
|
||||
</td>
|
||||
{{#config.download}}
|
||||
<td>
|
||||
<form id="d_{{guid}}">
|
||||
<input type="hidden" name="dir" value="{{download.currentDir}}">
|
||||
<input type="hidden" name="filename" value="{{download.name}}">
|
||||
<input type="hidden" name="api" value="{{download.action}}">
|
||||
</form>
|
||||
<a tabindex="0" name="start_download" data-guid="{{guid}}">
|
||||
<span class="{{download.icon}}"></span>
|
||||
</a>
|
||||
</td>
|
||||
{{/config.download}}
|
||||
{{#config.showlastmodified}}
|
||||
<td>{{lastmodified}}</td>
|
||||
{{/config.showlastmodified}}
|
||||
{{#config.showfilesize}}
|
||||
<td>{{size}}</td>
|
||||
{{/config.showfilesize}}
|
||||
{{#config.showpermissions}}
|
||||
<td class="hidden-xs">
|
||||
<input type="text" name="newpermissions" class="form-control {{filepermmode}}" value="{{fileperms}}" data-filename="{{name}}" {{readonly}}>
|
||||
</td>
|
||||
{{/config.showpermissions}}
|
||||
{{#config.showowner}}
|
||||
<td class="hidden-xs hidden-sm">
|
||||
{{owner}}
|
||||
</td>
|
||||
{{/config.showowner}}
|
||||
{{#config.showgroup}}
|
||||
<td class="hidden-xs hidden-sm hidden-md">
|
||||
{{group}}
|
||||
</td>
|
||||
{{/config.showgroup}}
|
||||
<td>
|
||||
{{#button}}
|
||||
<a tabindex="0" name="do-{{action}}" data-name="{{name}}">
|
||||
<span class="{{icon}}" title="{{title}}"</span>
|
||||
</a>
|
||||
{{/button}}
|
||||
</td>
|
||||
</tr>
|
||||
{{/items}}
|
||||
</tbody>
|
5
src/templates/misc.savequestion.html
Normal file
5
src/templates/misc.savequestion.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<div id="savequestion">
|
||||
<label>Do you want to save this file?</label><br>
|
||||
<button id="buttonSave">Save</button>
|
||||
<button id="buttonDismiss">Dismiss</button>
|
||||
</div>
|
16
src/templates/modal.ajaxrequest.html
Normal file
16
src/templates/modal.ajaxrequest.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<form id="formAjaxRequest">
|
||||
<div class="modal-body">
|
||||
<fieldset>
|
||||
<label>URL</label><br>
|
||||
<input class="form-control" type="text" id="ajaxurl" required><br>
|
||||
<label>Data</label><br>
|
||||
<textarea class="form-control" id="ajaxdata"></textarea><br>
|
||||
<label>Method</label><br>
|
||||
<input type="radio" name="arMethod" value="GET">GET</input><input type="radio" name="arMethod" value="POST" checked="checked">POST</input><br>
|
||||
<button type="button" class="btn btn-success" id="buttonRequest">Request</button>
|
||||
<button type="button" class="btn btn-default" id="buttonClose">Close</button><br>
|
||||
<label>Response</label><br>
|
||||
<textarea class="form-control" id="ajaxresponse"></textarea>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
13
src/templates/modal.copymove.html
Normal file
13
src/templates/modal.copymove.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<form id="formCopyMove">
|
||||
<fieldset>
|
||||
<div class="modal-body">
|
||||
<label>Select destination:</label>
|
||||
<div id="copyMoveTree"><span class="icon icon-spin5"></span></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" id="copyButton">copy</button>
|
||||
<button type="button" class="btn btn-default" id="moveButton">move</button>
|
||||
<button type="button" class="btn btn-default" id="cancelButton">cancel</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
12
src/templates/modal.createdir.html
Normal file
12
src/templates/modal.createdir.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<form id="formCreateDir">
|
||||
<div class="modal-body">
|
||||
<fieldset>
|
||||
<label>Directoy name:</label>
|
||||
<input class="form-control" type="text" name="dirname" value="" />
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" id="buttonSave">Save</button>
|
||||
<button type="button" class="btn btn-default" id="buttonCancel">Cancel</button>
|
||||
</div>
|
||||
</form>
|
9
src/templates/modal.deletefile.html
Normal file
9
src/templates/modal.deletefile.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<form id="formDeleteFile">
|
||||
<div class="modal-body">
|
||||
<label>Do you really want to delete the file {{filename}}?
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-danger" id="buttonYes">Yes</button>
|
||||
<button type="button" class="btn btn-default" id="buttonNo">No</button>
|
||||
</div>
|
||||
</form>
|
23
src/templates/modal.extractfile.html
Normal file
23
src/templates/modal.extractfile.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<form id="formExtractFile">
|
||||
<fieldset>
|
||||
<div class="modal-body">
|
||||
<label>Extract {{filename}} to:</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon"><input type="radio" name="extractTargetLocation" value="./" checked="checked"></span>
|
||||
<span class="form-control">./</span>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon"><input type="radio" name="extractTargetLocation" value="./{{destination}}"></span>
|
||||
<span class="form-control">./{{destination}}</span>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon"><input type="radio" name="extractTargetLocation" value="custom"></span>
|
||||
<input id="extractCustomLocation" type="text" class="form-control" placeholder="custom location" value="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" id="buttonExtract">extract</button>
|
||||
<button type="button" class="btn btn-default" id="buttonCancel">cancel</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
21
src/templates/modal.file.html
Normal file
21
src/templates/modal.file.html
Normal file
@@ -0,0 +1,21 @@
|
||||
<form id="formFile">
|
||||
<div class="modal-body">
|
||||
<fieldset>
|
||||
<label>Filename:</label>
|
||||
<input type="text" class="form-control" name="filename" value="{{filename}}"><br>
|
||||
<div id="content" name="content"></div><br>
|
||||
<button type="button" class="btn btn-default" id="editoroptions">editor options</button>
|
||||
<div class="hide" id="editoroptions-head">options</div>
|
||||
<div class="hide" id="editoroptions-content">
|
||||
<input type="checkbox" id="editor-wordwrap"> word wrap</input><br>
|
||||
<input type="checkbox" id="editor-softtabs"> use soft tabs</input>
|
||||
<div class="input-group"><span class="input-group-addon">tabsize</span><input class="form-control" type="text" size="2" id="editor-tabsize"title="tabsize"></div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" id="buttonSave" class="btn btn-default">Save</button>
|
||||
<button type="button" id="buttonSaveNotClose" class="btn btn-default">Save without closing</button>
|
||||
<button type="button" id="buttonClose" class="btn btn-default">Close</button>
|
||||
</div>
|
||||
</form>
|
9
src/templates/modal.multidelete.html
Normal file
9
src/templates/modal.multidelete.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<form id="formDeleteFiles">
|
||||
<div class="modal-body">
|
||||
<label>Do you really want to delete these {{count}} files?</label>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-danger" id="buttonYes">Yes</button>
|
||||
<button type="button" class="btn btn-default" id="buttonNo">No</button>
|
||||
</div>
|
||||
</form>
|
16
src/templates/modal.remoteupload.html
Normal file
16
src/templates/modal.remoteupload.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<form id="formRemoteUpload">
|
||||
<div class="modal-body">
|
||||
<fieldset>
|
||||
<label>Remote upload URL</label><br>
|
||||
<input class="form-control" type="text" id="url" name="url" required><br>
|
||||
<label>Filename (required)</label>
|
||||
<input class="form-control" type="text" id="filename" name="filename" required><br>
|
||||
<label>Method</label>
|
||||
<input type="radio" name="method" value="curl" checked="checked">cURL<input type="radio" name="method" value="file">file</input><br>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" id="buttonUpload">Upload</button>
|
||||
<button type="button" class="btn btn-default" id="buttonCancel">Cancel</button>
|
||||
</div>
|
||||
</form>
|
10
src/templates/modal.renamefile.html
Normal file
10
src/templates/modal.renamefile.html
Normal file
@@ -0,0 +1,10 @@
|
||||
<div class="modal-body">
|
||||
<form id="formRenameFile">
|
||||
<fieldset>
|
||||
<label>Rename {{filename}} to:</label>
|
||||
<input class="form-control" type="text" name="newname" /><br>
|
||||
<button class="btn btn-default" id="buttonRename">Rename</button>
|
||||
<button class="btn btn-default" id="buttonCancel">Cancel</button>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
14
src/templates/modal.uploadfile.html
Normal file
14
src/templates/modal.uploadfile.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<form id="formUploadFile">
|
||||
<div class="modal-body">
|
||||
<fieldset>
|
||||
<label>Upload file</label><br>
|
||||
<input class="file" type="file" name="ufile" id="ufile"><br>
|
||||
<label>new filename</label>
|
||||
<input class="form-control" type="text" name="newfilename"><br>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-default" id="buttonUpload">Upload</button>
|
||||
<button class="btn btn-default" id="buttonCancel">Cancel</button>
|
||||
</div>
|
||||
</form>
|
Reference in New Issue
Block a user