diff --git a/build/libifm.php b/build/libifm.php index fc3617f..8af65ab 100644 --- a/build/libifm.php +++ b/build/libifm.php @@ -1,5 +1,4 @@ 0, "showhiddenfiles" => 1, "showpath" => 0, + "contextmenu" => 1 ); private $config = array(); @@ -480,6 +480,33 @@ f00bar; +f00bar; + $templates['search'] = <<<'f00bar' +
+ +
+ +f00bar; + $templates['searchresults'] = <<<'f00bar' + +{{#items}} + + + + {{linkname}} ({{folder}}) + + + +{{/items}} + + f00bar; $templates['uploadfile'] = <<<'f00bar'
@@ -835,6 +862,22 @@ if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires j this.activeTarget=b,this.clear();var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")},b.prototype.clear=function(){a(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new c(this)),"string"==typeof b&&e[b]()})}var c=function(b){this.element=a(b)};c.VERSION="3.3.7",c.TRANSITION_DURATION=150,c.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a"),f=a.Event("hide.bs.tab",{relatedTarget:b[0]}),g=a.Event("show.bs.tab",{relatedTarget:e[0]});if(e.trigger(f),b.trigger(g),!g.isDefaultPrevented()&&!f.isDefaultPrevented()){var h=a(d);this.activate(b.closest("li"),c),this.activate(h,h.parent(),function(){e.trigger({type:"hidden.bs.tab",relatedTarget:b[0]}),b.trigger({type:"shown.bs.tab",relatedTarget:e[0]})})}}},c.prototype.activate=function(b,d,e){function f(){g.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.7",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return e=a-d&&"bottom"},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); + + - - - - - - + + + + + + + + '; } @@ -258,6 +266,7 @@ f00bar; case "zipnload": $this->zipnload( $_REQUEST); break; case "remoteUpload": $this->remoteUpload( $_REQUEST ); break; case "multidelete": $this->deleteMultipleFiles( $_REQUEST ); break; + case "searchItems": $this->searchItems( $_REQUEST ); break; case "getFolderTree": $this->getFolderTree( $_REQUEST ); break; default: echo json_encode( array( "status" => "ERROR", "message" => "Invalid api action given" ) ); @@ -293,7 +302,6 @@ f00bar; */ private function getFiles( $dir ) { - $dir = $this->getValidDir( $dir ); $this->chDirIfNecessary( $dir ); unset( $files ); unset( $dirs ); $files = array(); $dirs = array(); @@ -305,52 +313,8 @@ f00bar; elseif( $result == "." ) {} elseif( $result != ".." && substr( $result, 0, 1 ) == "." && $this->config['showhiddenfiles'] != 1 ) {} else { - $item = array(); - $item["name"] = $result; - if( is_dir( $result ) ) { - $item["type"] = "dir"; - if( $result == ".." ) - $item["icon"] = "icon icon-up-open"; - else - $item["icon"] = "icon icon-folder-empty"; - } else { - $item["type"] = "file"; - if( in_array( substr( $result, -7 ), array( ".tar.gz", ".tar.xz" ) ) ) - $type = substr( $result, -6 ); - elseif( substr( $result, -8 ) == ".tar.bz2" ) - $type = "tar.bz2"; - else - $type = substr( strrchr( $result, "." ), 1 ); - $item["icon"] = $this->getTypeIcon( $type ); - $item["ext"] = strtolower($type); - } - if( $this->config['showlastmodified'] == 1 ) { $item["lastmodified"] = date( "d.m.Y, G:i e", filemtime( $result ) ); } - if( $this->config['showfilesize'] == 1 ) { - $item["size"] = filesize( $result ); - if( $item["size"] > 1073741824 ) $item["size"] = round( ( $item["size"]/1073741824 ), 2 ) . " GB"; - elseif($item["size"]>1048576)$item["size"] = round( ( $item["size"]/1048576 ), 2 ) . " MB"; - elseif($item["size"]>1024)$item["size"] = round( ( $item["size"]/1024 ), 2 ) . " KB"; - else $item["size"] = $item["size"] . " Byte"; - } - if( $this->config['showpermissions'] > 0 ) { - if( $this->config['showpermissions'] == 1 ) $item["fileperms"] = substr( decoct( fileperms( $result ) ), -3 ); - elseif( $this->config['showpermissions'] == 2 ) $item["fileperms"] = $this->filePermsDecode( fileperms( $result ) ); - if( $item["fileperms"] == "" ) $item["fileperms"] = " "; - $item["filepermmode"] = ( $this->config['showpermissions'] == 1 ) ? "short" : "long"; - } - if( $this->config['showowner'] == 1 ) { - if ( function_exists( "posix_getpwuid" ) && fileowner($result) !== false ) { - $ownerarr = posix_getpwuid( fileowner( $result ) ); - $item["owner"] = $ownerarr['name']; - } else $item["owner"] = false; - } - if( $this->config['showgroup'] == 1 ) { - if( function_exists( "posix_getgrgid" ) && filegroup( $result ) !== false ) { - $grouparr = posix_getgrgid( filegroup( $result ) ); - $item["group"] = $grouparr['name']; - } else $item["group"] = false; - } - if( is_dir( $result ) ) $dirs[] = $item; + $item = $this->getItemInformation( $result ); + if( $item['type'] == "dir" ) $dirs[] = $item; else $files[] = $item; } } @@ -358,7 +322,57 @@ f00bar; } usort( $dirs, array( $this, "sortByName" ) ); usort( $files, array( $this, "sortByName" ) ); - echo json_encode( array_merge( $dirs, $files ) ); + + $this->jsonResponse( array_merge( $dirs, $files ) ); + } + + private function getItemInformation( $name ) { + $item = array(); + $item["name"] = $name; + if( is_dir( $name ) ) { + $item["type"] = "dir"; + if( $name == ".." ) + $item["icon"] = "icon icon-up-open"; + else + $item["icon"] = "icon icon-folder-empty"; + } else { + $item["type"] = "file"; + if( in_array( substr( $name, -7 ), array( ".tar.gz", ".tar.xz" ) ) ) + $type = substr( $name, -6 ); + elseif( substr( $name, -8 ) == ".tar.bz2" ) + $type = "tar.bz2"; + else + $type = substr( strrchr( $name, "." ), 1 ); + $item["icon"] = $this->getTypeIcon( $type ); + $item["ext"] = strtolower($type); + } + if( $this->config['showlastmodified'] == 1 ) { $item["lastmodified"] = date( "d.m.Y, G:i e", filemtime( $name ) ); } + if( $this->config['showfilesize'] == 1 ) { + $item["size"] = filesize( $name ); + if( $item["size"] > 1073741824 ) $item["size"] = round( ( $item["size"]/1073741824 ), 2 ) . " GB"; + elseif($item["size"]>1048576)$item["size"] = round( ( $item["size"]/1048576 ), 2 ) . " MB"; + elseif($item["size"]>1024)$item["size"] = round( ( $item["size"]/1024 ), 2 ) . " KB"; + else $item["size"] = $item["size"] . " Byte"; + } + if( $this->config['showpermissions'] > 0 ) { + if( $this->config['showpermissions'] == 1 ) $item["fileperms"] = substr( decoct( fileperms( $name ) ), -3 ); + elseif( $this->config['showpermissions'] == 2 ) $item["fileperms"] = $this->filePermsDecode( fileperms( $name ) ); + if( $item["fileperms"] == "" ) $item["fileperms"] = " "; + $item["filepermmode"] = ( $this->config['showpermissions'] == 1 ) ? "short" : "long"; + } + if( $this->config['showowner'] == 1 ) { + if ( function_exists( "posix_getpwuid" ) && fileowner($name) !== false ) { + $ownerarr = posix_getpwuid( fileowner( $name ) ); + $item["owner"] = $ownerarr['name']; + } else $item["owner"] = false; + } + if( $this->config['showgroup'] == 1 ) { + if( function_exists( "posix_getgrgid" ) && filegroup( $name ) !== false ) { + $grouparr = posix_getgrgid( filegroup( $name ) ); + $item["group"] = $grouparr['name']; + } else $item["group"] = false; + } + return $item; } private function getConfig() { @@ -397,6 +411,32 @@ f00bar; } } + private function searchItems( $d ) { + $this->chDirIfNecessary( $d['dir'] ); + if( strpos( $d['pattern'], '/' ) !== false ) { + echo json_decode( array( "status" => "ERROR", "message" => "Pattern must not contain slashes" ) ); + exit( 1 ); + } + try { + $results = $this->searchItemsRecursive( $d['pattern'] ); + echo json_encode( $results ); + } catch( Exception $e ) { + echo json_encode( array( "status" => "ERROR", "message" => $e->getMessage() ) ); + } + } + + private function searchItemsRecursive( $pattern, $dir="" ) { + $items = array(); + $dir = $dir ? $dir : '.'; + foreach( glob( $this->pathCombine( $dir, $pattern ) ) as $result ) { + array_push( $items, $this->getItemInformation( $result ) ); + } + foreach( glob( $this->pathCombine( $dir, '*') , GLOB_ONLYDIR ) as $subdir ) { + $items = array_merge( $items, $this->searchItemsRecursive( $pattern, $subdir ) ); + } + return $items; + } + private function getFolderTree( $d ) { echo json_encode( array_merge( @@ -812,12 +852,59 @@ f00bar; echo json_encode( array( "status" => "error", "message" => "Corrupt parameter data" ) ); } - //apis - /* help functions */ + private function log( $d ) { + file_put_contents( $this->pathCombine( $this->getRootDir(), "debug.ifm.log" ), ( is_array( $d ) ? print_r( $d, true ) : $d ), FILE_APPEND ); + } + + private function jsonResponse( $array ) { + $this->convertToUTF8( $array ); + $json = json_encode( $array ); + if( $json === false ) { + switch(json_last_error()) { + case JSON_ERROR_NONE: + echo ' - No errors'; + break; + case JSON_ERROR_DEPTH: + echo ' - Maximum stack depth exceeded'; + break; + case JSON_ERROR_STATE_MISMATCH: + echo ' - Underflow or the modes mismatch'; + break; + case JSON_ERROR_CTRL_CHAR: + echo ' - Unexpected control character found'; + break; + case JSON_ERROR_SYNTAX: + echo ' - Syntax error, malformed JSON'; + break; + case JSON_ERROR_UTF8: + echo ' - Malformed UTF-8 characters, possibly incorrectly encoded'; + break; + default: + echo ' - Unknown error'; + break; + } + + $this->jsonResponse( array( "status" => "ERROR", "message" => "Could not encode json: " . $err ) ); + } else { + echo $json; + } + } + + private function convertToUTF8( &$item ) { + if( is_array( $item ) ) + array_walk( + $item, + array( $this, 'convertToUTF8' ) + ); + else + if( function_exists( "mb_check_encoding" ) && ! mb_check_encoding( $item, "UTF-8" ) ) + $item = utf8_encode( $item ); + } + public function checkAuth() { if( $this->config['auth'] == 1 && ( ! isset( $_SESSION['auth'] ) || $_SESSION['auth'] !== true ) ) { $login_failed = false; diff --git a/src/templates/modal.search.html b/src/templates/modal.search.html new file mode 100644 index 0000000..469ffda --- /dev/null +++ b/src/templates/modal.search.html @@ -0,0 +1,10 @@ + + + diff --git a/src/templates/modal.searchresults.html b/src/templates/modal.searchresults.html new file mode 100644 index 0000000..486d9dd --- /dev/null +++ b/src/templates/modal.searchresults.html @@ -0,0 +1,11 @@ + +{{#items}} + + + + {{linkname}} ({{folder}}) + + + +{{/items}} +