diff --git a/compiler.php b/compiler.php index ea65c96..a5d40ca 100755 --- a/compiler.php +++ b/compiler.php @@ -9,21 +9,21 @@ chdir(realpath(dirname(__FILE__))); // output files and common attrs -define( "IFM_VERSION", "v2.6.3" ); +define( "IFM_VERSION", "v4.0" ); define( "IFM_RELEASE_DIR", "dist/"); define( "IFM_STANDALONE", "ifm.php" ); define( "IFM_STANDALONE_GZ", "ifm.min.php" ); define( "IFM_LIB", "libifm.php" ); // php source files -$IFM_SRC_PHP = array( +$IFM_SRC_PHP = [ 0 => "src/main.php", 1 => "src/ifmarchive.php", 2 => "src/htpasswd.php" -); +]; // get options -$options = getopt(null, array("language::", "languages::", "lang::", "cdn")); +$options = getopt(null, ["language::", "languages::", "lang::", "cdn"]); // build CDN version? if (isset($options['cdn'])) @@ -36,6 +36,7 @@ $langs = []; foreach ($options as $key => $value) if (substr($key, 0, 4) == "lang") $langs = array_merge($langs, explode(",", $value)); + $langs = array_unique($langs); if (!empty($langs)) { $vars['default_lang'] = ($langs[0] == "all") ? "en" : $langs[0]; @@ -65,68 +66,65 @@ foreach ($langs as $l) print "WARNING: Language file src/i18n/".$l.".json not found.\n"; // Concat PHP Files -$compiled = array( "run(); -', FILE_APPEND ); +', FILE_APPEND); // build compressed ifm file_put_contents( IFM_RELEASE_DIR . (IFM_CDN ? 'cdn.' : '') . IFM_STANDALONE_GZ, '' - . gzencode( file_get_contents( IFM_RELEASE_DIR . (IFM_CDN ? 'cdn.' : '') .IFM_STANDALONE, false, null, 5 ) ) + . gzencode(file_get_contents(IFM_RELEASE_DIR . (IFM_CDN ? 'cdn.' : '') . IFM_STANDALONE, false, null, 5)) ); // build lib -file_put_contents( IFM_RELEASE_DIR . (IFM_CDN ? 'cdn.' : '') . IFM_LIB, $compiled ); +file_put_contents(IFM_RELEASE_DIR . (IFM_CDN ? 'cdn.' : '') . IFM_LIB, $compiled); diff --git a/src/assets.cdn.css b/src/assets.cdn.css new file mode 100644 index 0000000..104faf8 --- /dev/null +++ b/src/assets.cdn.css @@ -0,0 +1,8 @@ + + + diff --git a/src/assets.cdn.js b/src/assets.cdn.js new file mode 100644 index 0000000..bf4c71a --- /dev/null +++ b/src/assets.cdn.js @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/src/assets.cdn.part b/src/assets.cdn.part deleted file mode 100644 index d010ebe..0000000 --- a/src/assets.cdn.part +++ /dev/null @@ -1,31 +0,0 @@ - public function getCSS() { - print ' - - - - - - - '; - } - - public function getJS() { - print ' - - - - - - - - - - '; - echo <<<'f00bar' - -f00bar; - } \ No newline at end of file diff --git a/src/assets.css b/src/assets.css new file mode 100644 index 0000000..b8e4b3d --- /dev/null +++ b/src/assets.css @@ -0,0 +1,8 @@ + diff --git a/src/assets.js b/src/assets.js new file mode 100644 index 0000000..ff959bb --- /dev/null +++ b/src/assets.js @@ -0,0 +1,16 @@ + diff --git a/src/assets.part b/src/assets.part deleted file mode 100644 index 490fe47..0000000 --- a/src/assets.part +++ /dev/null @@ -1,30 +0,0 @@ - public function getCSS() { - print ' - - - - - - - '; - } - - public function getJS() { - echo <<<'f00bar' - -f00bar; - } diff --git a/src/ifm.js b/src/ifm.js index 4cc075b..70d2a82 100644 --- a/src/ifm.js +++ b/src/ifm.js @@ -105,10 +105,10 @@ function IFM(params) { */ this.rebuildFileTable = function( data ) { if( data.status == "ERROR" ) { - this.showMessage( data.message, "e" ); + self.showMessage( data.message, "e" ); return; } else if ( ! Array.isArray( data ) ) { - this.showMessage( self.i18n.invalid_data, "e" ); + self.showMessage( self.i18n.invalid_data, "e" ); return; } data.forEach( function( item ) { @@ -217,8 +217,8 @@ function IFM(params) { if( self.datatable ) self.datatable.destroy(); self.datatable = $('#filetable').DataTable({ - paging: self.config.pagination, - pageLength: 50, + paging: !!self.config.paging, + pageLength: self.config.pageLength||50, info: false, autoWidth: false, columnDefs: [ @@ -359,6 +359,39 @@ function IFM(params) { self.copyToClipboard( link ); } }, + }, + extract: { + name: self.i18n.extract, + onClick: function( data ) { + self.showExtractFileDialog( data.clicked.name ); + }, + iconClass: "icon icon-archive", + isShown: function( data ) { + return !!( self.config.extract && data.clicked.eaction == "extract" && !data.selected.length ); + } + }, + rename: { + name: self.i18n.rename, + onClick: function( data ) { + self.showRenameFileDialog( data.clicked.name ); + }, + iconClass: "icon icon-terminal", + isShown: function( data ) { return !!( self.config.rename && !data.selected.length && data.clicked.name != ".." ); } + }, + copylink: { + name: self.i18n.copylink, + onClick: function( data ) { + if( data.clicked.link.toLowerCase().substr(0,4) == "http" ) + self.copyToClipboard( data.clicked.link ); + else { + var pathname = window.location.pathname.replace( /^\/*/g, '' ).split( '/' ); + pathname.pop(); + var link = self.pathCombine( window.location.origin, data.clicked.link ) + if( pathname.length > 0 ) + link = self.pathCombine( window.location.origin, pathname.join( '/' ), data.clicked.link ) + self.copyToClipboard( link ); + } + }, iconClass: "icon icon-link-ext", isShown: function( data ) { return !!( !data.selected.length && data.clicked.name != ".." ); } }, @@ -1548,9 +1581,9 @@ function IFM(params) { * * @param string m - message text */ - this.log = function( m ) { - if( self.config.debug ) { - console.log( "IFM (debug): " + m ); + this.log = function(m) { + if (self.config.debug) { + console.log("IFM (debug): " + m); } }; @@ -1849,8 +1882,8 @@ function IFM(params) { dataType: "json", success: function(d) { self.i18n = d; - self.log( "I18N loaded" ); - self.initApplication(); + self.log("I18N loaded"); + self.initCheckAuth(); }, error: function() { throw new Error( self.i18n.load_text_error ); @@ -1858,6 +1891,50 @@ function IFM(params) { }); }; + this.initCheckAuth = function() { + $.ajax({ + url: self.api, + type: "POST", + data: { + api: "checkAuth" + }, + dataType: "json", + success: function(d) { + if (d.status == "ERROR") { + self.showModal(Mustache.render(self.templates.login, {i18n: self.i18n}), {large: true}); + + var form = document.forms.loginForm; + form.addEventListener('click', function(e) { + if (e.target.id == "buttonLogin") { + $.ajax({ + url: self.api, + type: "POST", + data: { + api: "checkAuth", + inputLogin: form.elements[0].value, + inputPassword: form.elements[1].value + }, + dataType: "json", + success: function(e) { + self.hideModal(); + self.initApplication(); + }, + error: function(e) { + self.showMessage("Authentication failed", "e"); + } + }); + } + }); + } else { + self.initApplication(); + } + }, + error: function(resp) { + throw new Error("Not authenticated"); + } + }); + }; + this.initApplication = function() { self.rootElement.innerHTML = Mustache.render( self.templates.app, @@ -2012,8 +2089,8 @@ function IFM(params) { } }; - this.init = function( id ) { - self.rootElement = document.getElementById( id ); + this.init = function(id) { + self.rootElement = document.getElementById(id); this.initLoadConfig(); }; } diff --git a/src/includes/popper.min.js b/src/includes/popper.min.js new file mode 100644 index 0000000..8a17212 --- /dev/null +++ b/src/includes/popper.min.js @@ -0,0 +1,5 @@ +/* + Copyright (C) Federico Zivolo 2019 + Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT). + */(function(e,t){'object'==typeof exports&&'undefined'!=typeof module?module.exports=t():'function'==typeof define&&define.amd?define(t):e.Popper=t()})(this,function(){'use strict';function e(e){return e&&'[object Function]'==={}.toString.call(e)}function t(e,t){if(1!==e.nodeType)return[];var o=e.ownerDocument.defaultView,n=o.getComputedStyle(e,null);return t?n[t]:n}function o(e){return'HTML'===e.nodeName?e:e.parentNode||e.host}function n(e){if(!e)return document.body;switch(e.nodeName){case'HTML':case'BODY':return e.ownerDocument.body;case'#document':return e.body;}var i=t(e),r=i.overflow,p=i.overflowX,s=i.overflowY;return /(auto|scroll|overlay)/.test(r+s+p)?e:n(o(e))}function i(e){return e&&e.referenceNode?e.referenceNode:e}function r(e){return 11===e?re:10===e?pe:re||pe}function p(e){if(!e)return document.documentElement;for(var o=r(10)?document.body:null,n=e.offsetParent||null;n===o&&e.nextElementSibling;)n=(e=e.nextElementSibling).offsetParent;var i=n&&n.nodeName;return i&&'BODY'!==i&&'HTML'!==i?-1!==['TH','TD','TABLE'].indexOf(n.nodeName)&&'static'===t(n,'position')?p(n):n:e?e.ownerDocument.documentElement:document.documentElement}function s(e){var t=e.nodeName;return'BODY'!==t&&('HTML'===t||p(e.firstElementChild)===e)}function d(e){return null===e.parentNode?e:d(e.parentNode)}function a(e,t){if(!e||!e.nodeType||!t||!t.nodeType)return document.documentElement;var o=e.compareDocumentPosition(t)&Node.DOCUMENT_POSITION_FOLLOWING,n=o?e:t,i=o?t:e,r=document.createRange();r.setStart(n,0),r.setEnd(i,0);var l=r.commonAncestorContainer;if(e!==l&&t!==l||n.contains(i))return s(l)?l:p(l);var f=d(e);return f.host?a(f.host,t):a(e,d(t).host)}function l(e){var t=1=o.clientWidth&&n>=o.clientHeight}),l=0a[e]&&!t.escapeWithReference&&(n=Q(f[o],a[e]-('right'===e?f.width:f.height))),ae({},o,n)}};return l.forEach(function(e){var t=-1===['left','top'].indexOf(e)?'secondary':'primary';f=le({},f,m[t](e))}),e.offsets.popper=f,e},priority:['left','right','top','bottom'],padding:5,boundariesElement:'scrollParent'},keepTogether:{order:400,enabled:!0,fn:function(e){var t=e.offsets,o=t.popper,n=t.reference,i=e.placement.split('-')[0],r=Z,p=-1!==['top','bottom'].indexOf(i),s=p?'right':'bottom',d=p?'left':'top',a=p?'width':'height';return o[s]r(n[s])&&(e.offsets.popper[d]=r(n[s])),e}},arrow:{order:500,enabled:!0,fn:function(e,o){var n;if(!K(e.instance.modifiers,'arrow','keepTogether'))return e;var i=o.element;if('string'==typeof i){if(i=e.instance.popper.querySelector(i),!i)return e;}else if(!e.instance.popper.contains(i))return console.warn('WARNING: `arrow.element` must be child of its popper element!'),e;var r=e.placement.split('-')[0],p=e.offsets,s=p.popper,d=p.reference,a=-1!==['left','right'].indexOf(r),l=a?'height':'width',f=a?'Top':'Left',m=f.toLowerCase(),h=a?'left':'top',c=a?'bottom':'right',u=S(i)[l];d[c]-us[c]&&(e.offsets.popper[m]+=d[m]+u-s[c]),e.offsets.popper=g(e.offsets.popper);var b=d[m]+d[l]/2-u/2,w=t(e.instance.popper),y=parseFloat(w['margin'+f],10),E=parseFloat(w['border'+f+'Width'],10),v=b-e.offsets.popper[m]-y-E;return v=ee(Q(s[l]-u,v),0),e.arrowElement=i,e.offsets.arrow=(n={},ae(n,m,$(v)),ae(n,h,''),n),e},element:'[x-arrow]'},flip:{order:600,enabled:!0,fn:function(e,t){if(W(e.instance.modifiers,'inner'))return e;if(e.flipped&&e.placement===e.originalPlacement)return e;var o=v(e.instance.popper,e.instance.reference,t.padding,t.boundariesElement,e.positionFixed),n=e.placement.split('-')[0],i=T(n),r=e.placement.split('-')[1]||'',p=[];switch(t.behavior){case ce.FLIP:p=[n,i];break;case ce.CLOCKWISE:p=G(n);break;case ce.COUNTERCLOCKWISE:p=G(n,!0);break;default:p=t.behavior;}return p.forEach(function(s,d){if(n!==s||p.length===d+1)return e;n=e.placement.split('-')[0],i=T(n);var a=e.offsets.popper,l=e.offsets.reference,f=Z,m='left'===n&&f(a.right)>f(l.left)||'right'===n&&f(a.left)f(l.top)||'bottom'===n&&f(a.top)f(o.right),g=f(a.top)f(o.bottom),b='left'===n&&h||'right'===n&&c||'top'===n&&g||'bottom'===n&&u,w=-1!==['top','bottom'].indexOf(n),y=!!t.flipVariations&&(w&&'start'===r&&h||w&&'end'===r&&c||!w&&'start'===r&&g||!w&&'end'===r&&u),E=!!t.flipVariationsByContent&&(w&&'start'===r&&c||w&&'end'===r&&h||!w&&'start'===r&&u||!w&&'end'===r&&g),v=y||E;(m||b||v)&&(e.flipped=!0,(m||b)&&(n=p[d+1]),v&&(r=z(r)),e.placement=n+(r?'-'+r:''),e.offsets.popper=le({},e.offsets.popper,C(e.instance.popper,e.offsets.reference,e.placement)),e=P(e.instance.modifiers,e,'flip'))}),e},behavior:'flip',padding:5,boundariesElement:'viewport',flipVariations:!1,flipVariationsByContent:!1},inner:{order:700,enabled:!1,fn:function(e){var t=e.placement,o=t.split('-')[0],n=e.offsets,i=n.popper,r=n.reference,p=-1!==['left','right'].indexOf(o),s=-1===['top','left'].indexOf(o);return i[p?'left':'top']=r[o]-(s?i[p?'width':'height']:0),e.placement=T(t),e.offsets.popper=g(i),e}},hide:{order:800,enabled:!0,fn:function(e){if(!K(e.instance.modifiers,'hide','preventOverflow'))return e;var t=e.offsets.reference,o=D(e.instance.modifiers,function(e){return'preventOverflow'===e.name}).boundaries;if(t.bottomo.right||t.top>o.bottom||t.rightwindow.devicePixelRatio||!fe),c='bottom'===o?'top':'bottom',g='right'===n?'left':'right',b=B('transform');if(d='bottom'==c?'HTML'===l.nodeName?-l.clientHeight+h.bottom:-f.height+h.bottom:h.top,s='right'==g?'HTML'===l.nodeName?-l.clientWidth+h.right:-f.width+h.right:h.left,a&&b)m[b]='translate3d('+s+'px, '+d+'px, 0)',m[c]=0,m[g]=0,m.willChange='transform';else{var w='bottom'==c?-1:1,y='right'==g?-1:1;m[c]=d*w,m[g]=s*y,m.willChange=c+', '+g}var E={"x-placement":e.placement};return e.attributes=le({},E,e.attributes),e.styles=le({},m,e.styles),e.arrowStyles=le({},e.offsets.arrow,e.arrowStyles),e},gpuAcceleration:!0,x:'bottom',y:'right'},applyStyle:{order:900,enabled:!0,fn:function(e){return V(e.instance.popper,e.styles),j(e.instance.popper,e.attributes),e.arrowElement&&Object.keys(e.arrowStyles).length&&V(e.arrowElement,e.arrowStyles),e},onLoad:function(e,t,o,n,i){var r=L(i,t,e,o.positionFixed),p=O(o.placement,r,t,e,o.modifiers.flip.boundariesElement,o.modifiers.flip.padding);return t.setAttribute('x-placement',p),V(t,{position:o.positionFixed?'fixed':'absolute'}),o},gpuAcceleration:void 0}}},ge}); +//# sourceMappingURL=popper.min.js.map diff --git a/src/main.php b/src/main.php index 4571ab4..f194e1c 100644 --- a/src/main.php +++ b/src/main.php @@ -10,19 +10,28 @@ * main */ -error_reporting( E_ALL ); -ini_set( 'display_errors', 'OFF' ); +error_reporting(E_ALL); +ini_set('display_errors', 0); + +class IFMException extends Exception { + public $forUser = true; + public function __construct($message, $forUser = true, $code = 0, Exception $previous = null) { + $this->forUser = $forUser; + parent::__construct($message, $code, $previous); + } +} class IFM { - private $defaultconfig = array( + private $defaultconfig = [ // general config "auth" => 0, "auth_source" => 'inline;admin:$2y$10$0Bnm5L4wKFHRxJgNq.oZv.v7yXhkJZQvinJYR2p6X1zPvzyDRUVRC', + "auth_ignore_basic" => 0, "root_dir" => "", "root_public_url" => "", "tmp_dir" => "", "timezone" => "", - "forbiddenChars" => array(), + "forbiddenChars" => [], "dateLocale" => "en-US", "language" => "@@@vars:default_lang@@@", "selfoverwrite" => 0, @@ -43,7 +52,8 @@ class IFM { "zipnload" => 1, "createarchive" => 1, "search" => 1, - "pagination" => 0, + "paging" => 0, + "pageLength" => 50, // gui controls "showlastmodified" => 0, @@ -59,73 +69,190 @@ class IFM { "showrefresh" => 1, "forceproxy" => 0, "confirmoverwrite" => 1 - ); + ]; - private $config = array(); - private $templates = array(); - private $i18n = array(); + private $config = []; + private $templates = []; + private $i18n = []; public $mode = "standalone"; - public function __construct( $config=array() ) { - + public function __construct($config=[]) { // load the default config $this->config = $this->defaultconfig; // load config from environment variables - $this->config['auth'] = getenv('IFM_AUTH') !== false ? intval( getenv('IFM_AUTH') ) : $this->config['auth'] ; - $this->config['auth_source'] = getenv('IFM_AUTH_SOURCE') !== false ? getenv('IFM_AUTH_SOURCE') : $this->config['auth_source'] ; - $this->config['root_dir'] = getenv('IFM_ROOT_DIR') !== false ? getenv('IFM_ROOT_DIR') : $this->config['root_dir'] ; - $this->config['root_public_url'] = getenv('IFM_ROOT_PUBLIC_URL') !== false ? getenv('IFM_ROOT_PUBLIC_URL') : $this->config['root_public_url'] ; - $this->config['tmp_dir'] = getenv('IFM_TMP_DIR') !== false ? getenv('IFM_TMP_DIR') : $this->config['tmp_dir'] ; - $this->config['timezone'] = getenv('IFM_TIMEZONE') !== false ? getenv('IFM_TIMEZONE') : $this->config['timezone'] ; - $this->config['dateLocale'] = getenv('IFM_DATELOCALE') !== false ? getenv('IFM_DATELOCALE') : $this->config['dateLocale'] ; - $this->config['forbiddenChars'] = getenv('IFM_FORBIDDENCHARS') !== false ? str_split( getenv('IFM_FORBIDDENCHARS') ) : $this->config['forbiddenChars'] ; - $this->config['language'] = getenv('IFM_LANGUAGE') !== false ? getenv('IFM_LANGUAGE') : $this->config['language'] ; - $this->config['selfoverwrite'] = getenv('IFM_SELFOVERWRITE') !== false ? getenv('IFM_SELFOVERWRITE') : $this->config['selfoverwrite'] ; - $this->config['ajaxrequest'] = getenv('IFM_API_AJAXREQUEST') !== false ? intval( getenv('IFM_API_AJAXREQUEST') ) : $this->config['ajaxrequest'] ; - $this->config['chmod'] = getenv('IFM_API_CHMOD') !== false ? intval( getenv('IFM_API_CHMOD') ) : $this->config['chmod'] ; - $this->config['copymove'] = getenv('IFM_API_COPYMOVE') !== false ? intval( getenv('IFM_API_COPYMOVE') ) : $this->config['copymove'] ; - $this->config['createdir'] = getenv('IFM_API_CREATEDIR') !== false ? intval( getenv('IFM_API_CREATEDIR') ) : $this->config['createdir'] ; - $this->config['createfile'] = getenv('IFM_API_CREATEFILE') !== false ? intval( getenv('IFM_API_CREATEFILE') ) : $this->config['createfile'] ; - $this->config['edit'] = getenv('IFM_API_EDIT') !== false ? intval( getenv('IFM_API_EDIT') ) : $this->config['edit'] ; - $this->config['delete'] = getenv('IFM_API_DELETE') !== false ? intval( getenv('IFM_API_DELETE') ) : $this->config['delete'] ; - $this->config['download'] = getenv('IFM_API_DOWNLOAD') !== false ? intval( getenv('IFM_API_DOWNLOAD') ) : $this->config['download'] ; - $this->config['extract'] = getenv('IFM_API_EXTRACT') !== false ? intval( getenv('IFM_API_EXTRACT') ) : $this->config['extract'] ; - $this->config['upload'] = getenv('IFM_API_UPLOAD') !== false ? intval( getenv('IFM_API_UPLOAD') ) : $this->config['upload'] ; - $this->config['remoteupload'] = getenv('IFM_API_REMOTEUPLOAD') !== false ? intval( getenv('IFM_API_REMOTEUPLOAD') ) : $this->config['remoteupload'] ; - $this->config['rename'] = getenv('IFM_API_RENAME') !== false ? intval( getenv('IFM_API_RENAME') ) : $this->config['rename'] ; - $this->config['zipnload'] = getenv('IFM_API_ZIPNLOAD') !== false ? intval( getenv('IFM_API_ZIPNLOAD') ) : $this->config['zipnload'] ; - $this->config['createarchive'] = getenv('IFM_API_CREATEARCHIVE') !== false ? intval( getenv('IFM_API_CREATEARCHIVE') ) : $this->config['createarchive'] ; - $this->config['showlastmodified'] = getenv('IFM_GUI_SHOWLASTMODIFIED') !== false ? intval( getenv('IFM_GUI_SHOWLASTMODIFIED') ) : $this->config['showlastmodified'] ; - $this->config['showfilesize'] = getenv('IFM_GUI_SHOWFILESIZE') !== false ? intval( getenv('IFM_GUI_SHOWFILESIZE') ) : $this->config['showfilesize'] ; - $this->config['showowner'] = getenv('IFM_GUI_SHOWOWNER') !== false ? intval( getenv('IFM_GUI_SHOWOWNER') ) : $this->config['showowner'] ; - $this->config['showgroup'] = getenv('IFM_GUI_SHOWGROUP') !== false ? intval( getenv('IFM_GUI_SHOWGROUP') ) : $this->config['showgroup'] ; - $this->config['showpermissions'] = getenv('IFM_GUI_SHOWPERMISSIONS') !== false ? intval( getenv('IFM_GUI_SHOWPERMISSIONS') ) : $this->config['showpermissions'] ; - $this->config['showhtdocs'] = getenv('IFM_GUI_SHOWHTDOCS') !== false ? intval( getenv('IFM_GUI_SHOWHTDOCS') ) : $this->config['showhtdocs'] ; - $this->config['showhiddenfiles'] = getenv('IFM_GUI_SHOWHIDDENFILES') !== false ? intval( getenv('IFM_GUI_SHOWHIDDENFILES') ) : $this->config['showhiddenfiles'] ; - $this->config['showpath'] = getenv('IFM_GUI_SHOWPATH') !== false ? intval( getenv('IFM_GUI_SHOWPATH') ) : $this->config['showpath'] ; - $this->config['contextmenu'] = getenv('IFM_GUI_CONTEXTMENU') !== false ? intval( getenv('IFM_GUI_CONTEXTMENU') ) : $this->config['contextmenu'] ; - $this->config['search'] = getenv('IFM_API_SEARCH') !== false ? intval( getenv('IFM_API_SEARCH') ) : $this->config['search'] ; - $this->config['showrefresh'] = getenv('IFM_GUI_REFRESH') !== false ? intval( getenv('IFM_GUI_REFRESH') ) : $this->config['showrefresh'] ; - $this->config['forceproxy'] = getenv('IFM_GUI_FORCEPROXY') !== false ? intval( getenv('IFM_GUI_FORCEPROXY') ) : $this->config['forceproxy'] ; - $this->config['confirmoverwrite'] = getenv('IFM_GUI_CONFIRMOVERWRITE') !== false ? intval( getenv('IFM_GUI_CONFIRMOVERWRITE') ) : $this->config['confirmoverwrite'] ; - - // optional settings - if( getenv('IFM_SESSION_LIFETIME') !== false ) - $this->config['session_lifetime'] = getenv('IFM_SESSION_LIFETIME'); - if( getenv('IFM_FORCE_SESSION_LIFETIME') !== false ) - $this->config['session_lifetime'] = getenv('IFM_FORCE_SESSION_LIFETIME'); + foreach (array_keys($this->config) as $key) { + if (($value = getenv('IFM_' . strtoupper($key))) !== false) { + if (is_numeric($value)) + $value = intval($value); + $this->config[$key] = $value; + } + } // load config from passed array - $this->config = array_merge( $this->config, $config ); + $this->config = array_merge($this->config, $config); - // get list of ace includes - $this->config['ace_includes'] = <<<'f00bar' -@@@vars:ace_includes@@@ + $i18n = []; + @@@vars:languageincludes@@@ + $this->i18n = $i18n; + + if ($this->config['timezone']) + date_default_timezone_set($this->config['timezone']); + } + + /** + * This function contains the client-side application + */ + public function getApplication() { + $this->getHTMLHeader(); + print '
'; + $this->getJS(); + print ''; + $this->getHTMLFooter(); + } + + public function getInlineApplication() { + $this->getCSS(); + print '
'; + $this->getJS(); + } + + public function getCSS() { + echo <<<'f00bar' + @@@ASSETS_CSS@@@ f00bar; + } + public function getJS() { + echo <<<'f00bar' + @@@ASSETS_JS@@@ +f00bar; + } + + public function getHTMLHeader() { + print ' + + + IFM - improved file manager + + + '; + $this->getCSS(); + print ''; + } + + public function getHTMLFooter() { + print ''; + } + + /** + * main functions + */ + + public function run($mode="standalone") { + try { + if (!is_dir(realpath($this->config['root_dir'])) || !is_readable(realpath($this->config['root_dir']))) + throw new IFMException("Cannot access root_dir.", false); + + chdir(realpath($this->config['root_dir'])); + + $this->mode = $mode; + if (isset($_REQUEST['api']) || $mode == "api") + $this->jsonResponse($this->dispatch()); + elseif ($mode == "standalone") + $this->getApplication(); + else + $this->getInlineApplication(); + } catch (IFMException $e) { + $this->jsonResponse(["status" => "ERROR", "message" => $e->getMessage()]); + } catch (Exception $e) { + $this->jsonResponse(["status" => "ERROR", "message" => $e->getMessage()]); + } + } + + private function dispatch() { + // APIs which do not need authentication + switch ($_REQUEST['api']) { + case "checkAuth": + if ($this->checkAuth()) + return ["status" => "OK", "message" => "Authenticated"]; + else + return ["status" => "ERROR", "message" => "Not authenticated"]; + case "getConfig": + return $this->getConfig(); + case "getTemplates": + return $this->getTemplates(); + case "getI18N": + return $this->getI18N($_REQUEST); + case "logout": + session_start(); + unset($_SESSION); + session_destroy(); + header("Location: " . strtok($_SERVER["REQUEST_URI"], '?')); + exit; + } + + // check authentication + if (!$this->checkAuth()) + throw new IFMException("Not authenticated"); + + // api requests which work without a valid working directory + switch ($_REQUEST['api']) { + case "getRealpath": + if (isset($_REQUEST["dir"]) && $_REQUEST["dir"] != "") + return ["realpath" => $this->getValidDir($_REQUEST["dir"])]; + else + return ["realpath" => ""]; + case "getFiles": + if (isset($_REQUEST["dir"]) && $this->isPathValid($_REQUEST["dir"])) + return $this->getFiles($_REQUEST["dir"]); + else + return $this->getFiles(""); + case "getFolders": + return $this->getFolders($_REQUEST); + } + + // checking working directory + if (!isset($_REQUEST["dir"]) || !$this->isPathValid($_REQUEST["dir"])) + throw new IFMException($this->l("invalid_dir")); + + $this->chDirIfNecessary($_REQUEST['dir']); + switch ($_REQUEST["api"]) { + case "createDir": return $this->createDir($_REQUEST); + case "saveFile": return $this->saveFile($_REQUEST); + case "getContent": return $this->getContent($_REQUEST); + case "delete": return $this->deleteFiles($_REQUEST); + case "rename": return $this->renameFile($_REQUEST); + case "download": return $this->downloadFile($_REQUEST); + case "extract": return $this->extractFile($_REQUEST); + case "upload": return $this->uploadFile($_REQUEST); + case "copyMove": return $this->copyMove($_REQUEST); + case "changePermissions": return $this->changePermissions($_REQUEST); + case "zipnload": return $this->zipnload($_REQUEST); + case "remoteUpload": return $this->remoteUpload($_REQUEST); + case "searchItems": return $this->searchItems($_REQUEST); + case "getFolderTree": return $this->getFolderTree($_REQUEST); + case "createArchive": return $this->createArchive($_REQUEST); + case "proxy": return $this->downloadFile($_REQUEST, false); + default: + throw new IFMException($this->l("invalid_action")); + } + } + + /** + * api functions + */ + + private function getI18N($lang="en") { + if (in_array($lang, array_keys($this->i18n))) + return array_merge($this->i18n['en'], $this->i18n[$lang]); + else + return $this->i18n['en']; + } + + private function getTemplates() { // templates - $templates = array(); + $templates = []; $templates['app'] = <<<'f00bar' @@@file:src/templates/app.html@@@ f00bar; @@ -183,217 +310,94 @@ f00bar; $templates['uploadconfirmoverwrite'] = <<<'f00bar' @@@file:src/templates/modal.uploadconfirmoverwrite.html@@@ f00bar; - $this->templates = $templates; - - $i18n = array(); - @@@vars:languageincludes@@@ - $this->i18n = $i18n; - - if( in_array( $this->config['language'], array_keys( $this->i18n ) ) ) - // Merge english with the language in case of missing keys - $this->l = array_merge($this->i18n['en'], $this->i18n[$this->config['language']]); - else - $this->l = $this->i18n['en']; - - if ($this->config['timezone']) - date_default_timezone_set($this->config['timezone']); + return $templates; } - /** - * This function contains the client-side application - */ - public function getApplication() { - $this->getHTMLHeader(); - print '
'; - $this->getJS(); - print ''; - $this->getHTMLFooter(); - } + private function getFiles($dir) { + $this->chDirIfNecessary($dir); - public function getInlineApplication() { - $this->getCSS(); - print '
'; - $this->getJS(); - } + unset($files); unset($dirs); $files = []; $dirs = []; -IFM_ASSETS - - public function getHTMLHeader() { - print ' - - - IFM - improved file manager - - - '; - $this->getCSS(); - print ''; - } - - public function getHTMLFooter() { - print ''; - } - - /* - main functions - */ - - private function handleRequest() { - if( $_REQUEST["api"] == "getRealpath" ) { - if( isset( $_REQUEST["dir"] ) && $_REQUEST["dir"] != "" ) - $this->jsonResponse( array( "realpath" => $this->getValidDir( $_REQUEST["dir"] ) ) ); - else - $this->jsonResponse( array( "realpath" => "" ) ); - } - elseif( $_REQUEST["api"] == "getFiles" ) { - if( isset( $_REQUEST["dir"] ) && $this->isPathValid( $_REQUEST["dir"] ) ) - $this->getFiles( $_REQUEST["dir"] ); - else - $this->getFiles( "" ); - } - elseif( $_REQUEST["api"] == "getConfig" ) { - $this->getConfig(); - } - elseif( $_REQUEST["api"] == "getFolders" ) { - $this->getFolders( $_REQUEST ); - } elseif( $_REQUEST["api"] == "getTemplates" ) { - $this->jsonResponse( $this->templates ); - } elseif( $_REQUEST["api"] == "getI18N" ) { - $this->jsonResponse( $this->l ); - } elseif( $_REQUEST["api"] == "logout" ) { - unset( $_SESSION['ifmauth'] ); - session_destroy(); - header( "Location: " . strtok( $_SERVER["REQUEST_URI"], '?' ) ); - exit( 0 ); - } else { - if( isset( $_REQUEST["dir"] ) && $this->isPathValid( $_REQUEST["dir"] ) ) { - $this->chDirIfNecessary( $_REQUEST['dir'] ); - switch( $_REQUEST["api"] ) { - case "createDir": $this->createDir( $_REQUEST["dir"], $_REQUEST["dirname"] ); break; - case "saveFile": $this->saveFile( $_REQUEST ); break; - case "getContent": $this->getContent( $_REQUEST ); break; - case "delete": $this->deleteFiles( $_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 "searchItems": $this->searchItems( $_REQUEST ); break; - case "getFolderTree": $this->getFolderTree( $_REQUEST ); break; - case "createArchive": $this->createArchive( $_REQUEST ); break; - case "proxy": $this->downloadFile( $_REQUEST, false ); break; - default: - $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid api action given" ) ); - break; - } - } else { - print $this->jsonResponse( array( "status" => "ERROR", "message" => "Invalid working directory" ) ); - } - } - exit( 0 ); - } - - public function run( $mode="standalone" ) { - if ( $this->checkAuth() ) { - // go to our root_dir - if( ! is_dir( realpath( $this->config['root_dir'] ) ) || ! is_readable( realpath( $this->config['root_dir'] ) ) ) - die( "Cannot access root_dir."); - else - chdir( realpath( $this->config['root_dir'] ) ); - $this->mode = $mode; - if( isset( $_REQUEST['api'] ) || $mode == "api" ) { - $this->handleRequest(); - } elseif( $mode == "standalone" ) { - $this->getApplication(); - } else { - $this->getInlineApplication(); - } - } - } - - /* - api functions - */ - - - private function getFiles( $dir ) { - $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 ) {} + if ($handle = opendir(".")) { + while (false !== ($result = readdir($handle))) { + if ($result == basename($_SERVER['SCRIPT_NAME']) && $this->getScriptRoot() == getcwd()) + continue; + elseif (($result == ".htaccess" || $result==".htpasswd") && $this->config['showhtdocs'] != 1) + continue; + elseif ($result == ".") + continue; + elseif ($result != ".." && substr($result, 0, 1) == "." && $this->config['showhiddenfiles'] != 1) + continue; else { - $item = $this->getItemInformation( $result ); - if( $item['type'] == "dir" ) $dirs[] = $item; - else $files[] = $item; + $item = $this->getItemInformation($result); + if ($item['type'] == "dir") + $dirs[] = $item; + else + $files[] = $item; } } - closedir( $handle ); + closedir($handle); } - usort( $dirs, array( $this, "sortByName" ) ); - usort( $files, array( $this, "sortByName" ) ); + usort($dirs, [$this, "sortByName"]); + usort($files, [$this, "sortByName"]); - $this->jsonResponse( array_merge( $dirs, $files ) ); + return array_merge($dirs, $files); } - private function getItemInformation( $name ) { - $item = array(); + private function getItemInformation($name) { + $item = []; $item["name"] = $name; - if( is_dir( $name ) ) { + if (is_dir($name)) { $item["type"] = "dir"; - if( $name == ".." ) + 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" ) + if (in_array(substr($name, -7), [".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 ); + $type = substr(strrchr($name, "."), 1); + $item["icon"] = $this->getTypeIcon($type); $item["ext"] = strtolower($type); - if( !$this->config['disable_mime_detection'] ) - $item["mime_type"] = mime_content_type( $name ); + if (!$this->config['disable_mime_detection']) + $item["mime_type"] = mime_content_type($name); } - if( $this->config['showlastmodified'] == 1 ) { $item["lastmodified"] = filemtime( $name ); } - if( $this->config['showfilesize'] == 1 ) { - if( $item['type'] == "dir" ) { + if ($this->config['showlastmodified'] == 1) + $item["lastmodified"] = filemtime($name); + if ($this->config['showfilesize'] == 1) { + if ($item['type'] == "dir") { $item['size_raw'] = 0; $item['size'] = ""; } else { - $item["size_raw"] = filesize( $name ); - if( $item["size_raw"] > 1073741824 ) $item["size"] = round( ( $item["size_raw"]/1073741824 ), 2 ) . " GB"; - elseif($item["size_raw"]>1048576)$item["size"] = round( ( $item["size_raw"]/1048576 ), 2 ) . " MB"; - elseif($item["size_raw"]>1024)$item["size"] = round( ( $item["size_raw"]/1024 ), 2 ) . " KB"; + $item["size_raw"] = filesize($name); + if ($item["size_raw"] > 1073741824) $item["size"] = round(($item["size_raw"]/1073741824 ), 2) . " GB"; + elseif($item["size_raw"]>1048576)$item["size"] = round(($item["size_raw"]/1048576), 2) . " MB"; + elseif($item["size_raw"]>1024)$item["size"] = round(($item["size_raw"]/1024), 2) . " KB"; else $item["size"] = $item["size_raw"] . " 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['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 ) ); + 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 ) ); + 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; } @@ -402,530 +406,500 @@ IFM_ASSETS private function getConfig() { $ret = $this->config; - $ret['inline'] = ( $this->mode == "inline" ) ? true : false; + $ret['inline'] = ($this->mode == "inline") ? true : false; $ret['isDocroot'] = ($this->getRootDir() == $this->getScriptRoot()); - foreach (array("auth_source", "root_dir") as $field) { + foreach (["auth_source", "root_dir"] as $field) unset($ret[$field]); - } - $this->jsonResponse($ret); - } - private function getFolders( $d ) { - if( ! isset( $d['dir'] ) ) - $d['dir'] = $this->getRootDir(); - if( ! $this->isPathValid( $d['dir'] ) ) - echo "[]"; - else { - $ret = array(); - foreach( glob( $this->pathCombine( $d['dir'], "*" ), GLOB_ONLYDIR ) as $dir ) { - array_push( $ret, array( - "text" => htmlspecialchars( basename( $dir ) ), - "lazyLoad" => true, - "dataAttr" => array( "path" => $dir ) - )); - } - sort( $ret ); - if( $this->getScriptRoot() == realpath( $d['dir'] ) ) - $ret = array_merge( - array( - 0 => array( - "text" => "/ [root]", - "dataAttr" => array( "path" => $this->getRootDir() ) - ) - ), - $ret - ); - $this->jsonResponse( $ret ); - } - } - - private function searchItems( $d ) { - if( $this->config['search'] != 1 ) { - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['nopermissions'] ) ); - return; - } - - if( strpos( $d['pattern'], '/' ) !== false ) { - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['pattern_error_slashes'] ) ); - exit( 1 ); - } - try { - $results = $this->searchItemsRecursive( $d['pattern'] ); - $this->jsonResponse( $results ); - } catch( Exception $e ) { - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['error'] . " " . $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 ) { - $this->jsonResponse( - array_merge( - array( - 0 => array( - "text" => "/ [root]", - "nodes" => array(), - "dataAttributes" => array( "path" => $this->getRootDir() ) - ) - ), - $this->getFolderTreeRecursive( $d['dir'] ) - ) - ); - } - - 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" => htmlspecialchars( $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 ) { - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['nopermissions'] ) ); - exit( 1 ); - } - if( ! isset( $d['destination'] ) || ! $this->isPathValid( realpath( $d['destination'] ) ) ) { - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['invalid_dir'] ) ); - exit( 1 ); - } - if( ! is_array( $d['filenames'] ) ) { - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['invalid_params'] ) ); - exit( 1 ); - } - if( ! in_array( $d['action'], array( 'copy', 'move' ) ) ) { - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['invalid_action'] ) ); - exit( 1 ); - } - $err = array(); $errFlag = -1; // -1 -> all errors; 0 -> at least some errors; 1 -> no errors - foreach( $d['filenames'] as $file ) { - if( ! file_exists( $file ) || $file == ".." || ! $this->isFilenameValid( $file ) ) { - array_push( $err, $file ); - } - if( $d['action'] == "copy" ) { - if( $this->xcopy( $file, $d['destination'] ) ) - $errFlag = 0; - else - array_push( $err, $file ); - } elseif( $d['action'] == "move" ) { - if( rename( $file, $this->pathCombine( $d['destination'], basename( $file ) ) ) ) - $errFlag = 0; - else - array_push( $err, $file ); - } - } - $action = ( $d['action'] == "copy" ? "copied" : "moved" ); - if( empty( $err ) ) { - $this->jsonResponse( array( "status" => "OK", "message" => ( $d['action'] == "copy" ? $this->l['copy_success'] : $this->l['move_success'] ), "errflag" => "1" ) ); - } + private function getFolders($d) { + if (!isset($d['dir'])) + $d['dir'] = $this->getRootDir(); + + if (!$this->isPathValid($d['dir'])) + return []; else { - $errmsg = ( $d['action'] == "copy" ? $this->l['copy_error'] : $this->l['move_error'] ) . "
    "; - foreach( $err as $item ) + $ret = []; + foreach (glob($this->pathCombine($d['dir'], "*"), GLOB_ONLYDIR) as $dir) { + array_push($ret, [ + "text" => htmlspecialchars(basename($dir)), + "lazyLoad" => true, + "dataAttr" => ["path" => $dir] + ]); + } + sort($ret); + if ($this->getScriptRoot() == realpath($d['dir'])) + $ret = array_merge( + [ + 0 => [ + "text" => "/ [root]", + "dataAttr" => ["path" => $this->getRootDir()] + ] + ], + $ret + ); + return $ret; + } + } + + private function searchItems($d) { + if ($this->config['search'] != 1) + throw new IFMException($this->l('nopermissions')); + + if (strpos($d['pattern'], '/') !== false) + throw new IFMException($this->l('pattern_error_slashes')); + + $results = $this->searchItemsRecursive($d['pattern']); + return $results; + } + + private function searchItemsRecursive($pattern, $dir="") { + $items = []; + $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) { + return array_merge( + [ + 0 => [ + "text" => "/ [root]", + "nodes" => [], + "dataAttributes" => ["path" => $this->getRootDir()] + ] + ], + $this->getFolderTreeRecursive($d['dir']) + ); + } + + private function getFolderTreeRecursive($start_dir) { + $ret = []; + $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, [ + "text" => htmlspecialchars($result), + "dataAttributes" => ["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) + throw new IFMException($this->l('nopermissions')); + + if (!isset($d['destination']) || !$this->isPathValid(realpath($d['destination']))) + throw new IFMException($this->l('invalid_dir')); + + if (!is_array($d['filenames'])) + throw new IFMException($this->l('invalid_params')); + + if (!in_array($d['action'], ['copy', 'move'])) + throw new IFMException($this->l('invalid_action')); + + $err = []; $errFlag = -1; // -1 -> all errors; 0 -> at least some errors; 1 -> no errors + foreach ($d['filenames'] as $file) { + if (!file_exists($file) || $file == ".." || !$this->isFilenameValid($file)) { + array_push($err, $file); + } + if ($d['action'] == "copy") { + if ($this->xcopy($file, $d['destination'])) + $errFlag = 0; + else + array_push($err, $file); + } elseif ($d['action'] == "move") { + if (rename($file, $this->pathCombine($d['destination'], basename($file)))) + $errFlag = 0; + else + array_push($err, $file); + } + } + $action = ($d['action'] == "copy") ? "copied" : "moved"; + if (empty($err)) { + return [ + "status" => "OK", + "message" => ($d['action'] == "copy" ? $this->l('copy_success') : $this->l('move_success')), + "errflag" => "1" + ]; + } else { + $errmsg = ($d['action'] == "copy" ? $this->l('copy_error') : $this->l('move_error')) . "
      "; + foreach ($err as $item) $errmsg .= "
    • ".$item."
    • "; $errmsg .= "
    "; - $this->jsonResponse( array( "status" => "OK", "message" => $errmsg, "flag" => $errFlag ) ); + throw new IFMException($errmsg); } } // creates a directory - private function createDir($w, $dn) { - if( $this->config['createdir'] != 1 ) { - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['nopermissions'] ) ); - exit( 1 ); - } - if( $dn == "" ) - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['invalid_dir'] ) ); - elseif( ! $this->isFilenameValid( $dn ) ) - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['invalid_dir'] ) ); - else { - if( @mkdir( $dn ) ) - $this->jsonResponse( array( "status" => "OK", "message" => $this->l['folder_create_success'] ) ); - else - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['folder_create_error'] ) ); - } + private function createDir($d) { + if ($this->config['createdir'] != 1) + throw new IFMException($this->l('nopermissions')); + + if ($d['dirname'] == "" || !$this->isFilenameValid($d['dirname'])) + throw new IFMException($this->l('invalid_dir')); + + if (@mkdir($d['dirname'])) + return ["status" => "OK", "message" => $this->l('folder_create_success')]; + else + throw new IFMException($this->l('folder_create_error').". ".error_get_last()['message']); } // save a file - 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 ) ) { - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['nopermissions'] ) ); - exit( 1 ); - } - if( isset( $d['filename'] ) && $this->isFilenameValid( $d['filename'] ) ) { - if( isset( $d['content'] ) ) { + 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) + ) + throw new IFMException($this->l('nopermissions')); + + if (isset($d['filename']) && $this->isFilenameValid($d['filename'])) { + if (isset($d['content'])) { // work around magic quotes - $content = get_magic_quotes_gpc() == 1 ? stripslashes( $d['content'] ) : $d['content']; - if( @file_put_contents( $d['filename'], $content ) !== false ) { - $this->jsonResponse( array( "status" => "OK", "message" => $this->l['file_save_success'] ) ); - } else - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['file_save_error'] ) ); + $content = get_magic_quotes_gpc() == 1 ? stripslashes($d['content']) : $d['content']; + if (@file_put_contents($d['filename'], $content) !== false) + return ["status" => "OK", "message" => $this->l('file_save_success')]; + else + throw new Exception($this->l('file_save_error')); } else - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['file_save_error'] ) ); + throw new IFMException($this->l('file_save_error')); } else - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['invalid_filename'] ) ); + throw new IFMException($this->l('invalid_filename')); } // gets the content of a file // notice: if the content is not JSON encodable it returns an error - private function getContent( array $d ) { - if( $this->config['edit'] != 1 ) - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['nopermissions'] ) ); - else { - if( isset( $d['filename'] ) && $this->isFilenameAllowed( $d['filename'] ) && file_exists( $d['filename'] ) && is_readable( $d['filename'] ) ) { - $content = @file_get_contents( $d['filename'] ); - if( function_exists( "mb_check_encoding" ) && ! mb_check_encoding( $content, "UTF-8" ) ) - $content = utf8_encode( $content ); - $this->jsonResponse( array( "status" => "OK", "data" => array( "filename" => $d['filename'], "content" => $content ) ) ); - } else $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['file_not_found'] ) ); - } + private function getContent($d) { + if ($this->config['edit'] != 1) + throw new IFMException($this->l('nopermissions')); + + if (isset($d['filename']) && $this->isFilenameAllowed($d['filename']) && file_exists($d['filename']) && is_readable($d['filename'])) { + $content = @file_get_contents($d['filename']); + if (function_exists("mb_check_encoding") && !mb_check_encoding($content, "UTF-8")) + $content = utf8_encode($content); + return ["status" => "OK", "data" => ["filename" => $d['filename'], "content" => $content]]; + } else + throw new IFMException($this->l('file_not_found')); } // deletes a bunch of files or directories - private function deleteFiles( array $d ) { - if( $this->config['delete'] != 1 ) $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['nopermissions'] ) ); - else { - $err = array(); $errFLAG = -1; // -1 -> no files deleted; 0 -> at least some files deleted; 1 -> all files deleted - foreach( $d['filenames'] as $file ) { - if( $this->isFilenameAllowed( $file ) ) { - if( is_dir( $file ) ) { - $res = $this->rec_rmdir( $file ); - if( $res != 0 ) - array_push( $err, $file ); - else - $errFLAG = 0; - } else { - if( @unlink($file) ) - $errFLAG = 0; - else - array_push($err, $file); - } + private function deleteFiles($d) { + if ($this->config['delete'] != 1) + throw new IFMException($this->l('nopermissions')); + + $err = []; $errFLAG = -1; // -1 -> no files deleted; 0 -> at least some files deleted; 1 -> all files deleted + foreach ($d['filenames'] as $file) { + if ($this->isFilenameAllowed($file)) { + if (is_dir($file)) { + $res = $this->rec_rmdir($file); + if ($res != 0) + array_push($err, $file); + else + $errFLAG = 0; } else { - array_push( $err, $file ); + if (@unlink($file)) + $errFLAG = 0; + else + array_push($err, $file); } + } else { + array_push($err, $file); } - if( empty( $err ) ) { - $this->jsonResponse( array( "status" => "OK", "message" => $this->l['file_delete_success'], "errflag" => "1" ) ); - } - else { - $errmsg = $this->l['file_delete_error'] . "
      "; - foreach($err as $item) - $errmsg .= "
    • ".$item."
    • "; - $errmsg .= "
    "; - $this->jsonResponse( array( "status" => "ERROR", "message" => $errmsg, "flag" => $errFLAG ) ); - } + } + if (empty($err)) + return ["status" => "OK", "message" => $this->l('file_delete_success'), "errflag" => "1"]; + else { + $errmsg = $this->l('file_delete_error') . "
      "; + foreach ($err as $item) + $errmsg .= "
    • ".$item."
    • "; + $errmsg .= "
    "; + throw new IFMException($errmsg); } } // renames a file - private function renameFile( array $d ) { - if( $this->config['rename'] != 1 ) { - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['nopermissions'] ) ); - } elseif( ! $this->isFilenameValid( $d['filename'] ) ) { - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['invalid_filename'] ) ); - } elseif( ! $this->isFilenameValid( $d['newname'] ) ) { - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['invalid_filename'] ) ); - } else { - if( strpos( $d['newname'], '/' ) !== false ) - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['filename_slashes'] ) ); - elseif( $this->config['showhtdocs'] != 1 && ( substr( $d['newname'], 0, 3) == ".ht" || substr( $d['filename'], 0, 3 ) == ".ht" ) ) - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['nopermissions'] ) ); - elseif( $this->config['showhiddenfiles'] != 1 && ( substr( $d['newname'], 0, 1) == "." || substr( $d['filename'], 0, 1 ) == "." ) ) - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['nopermissions'] ) ); - else { - if( @rename( $d['filename'], $d['newname'] ) ) - $this->jsonResponse( array( "status" => "OK", "message" => $this->l['file_rename_success'] ) ); - else - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['file_rename_error'] ) ); - } - } + private function renameFile(array $d) { + if ($this->config['rename'] != 1) + throw new IFMException($this->l('nopermissions')); + elseif (!$this->isFilenameValid($d['filename']) || !$this->isFilenameValid($d['newname'])) + throw new IFMException($this->l('invalid_filename')); + + if (@rename($d['filename'], $d['newname'])) + return ["status" => "OK", "message" => $this->l('file_rename_success')]; + else + throw new IFMException($this->l('file_rename_error')); } // provides a file for downloading - private function downloadFile( array $d, $forceDL=true ) { - if( $this->config['download'] != 1 ) - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['nopermissions'] ) ); - elseif( ! $this->isFilenameValid( $d['filename'] ) ) - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['invalid_filename'] ) ); - elseif( $this->config['showhtdocs'] != 1 && ( substr( $d['filename'], 0, 3 ) == ".ht" || substr( $d['filename'],0,3 ) == ".ht" ) ) - $this->jsonResponse( array( "status" => "ERROR", "message"=> $this->l['nopermissions'] ) ); - elseif( $this->config['showhiddenfiles'] != 1 && ( substr( $d['filename'], 0, 1 ) == "." || substr( $d['filename'],0,1 ) == "." ) ) - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['nopermissions'] ) ); - else { - if( ! is_file( $d['filename' ] ) ) - http_response_code( 404 ); - else - $this->fileDownload( array( "file" => $d['filename'], "forceDL" => $forceDL ) ); - } + private function downloadFile(array $d, $forceDL=true) { + if ($this->config['download'] != 1) + throw new IFMException($this->l('nopermissions')); + + if (!$this->isFilenameValid($d['filename'])) + throw new IFMException($this->l('invalid_filename')); + + if (!is_file($d['filename'])) + http_response_code(404); + else + $this->fileDownload(["file" => $d['filename'], "forceDL" => $forceDL]); } // extracts a zip-archive - private function extractFile( array $d ) { + private function extractFile(array $d) { $restoreIFM = false; $tmpSelfContent = null; $tmpSelfChecksum = null; - if( $this->config['extract'] != 1 ) - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['nopermissions'] ) ); - else { - if( ! file_exists( $d['filename'] ) ) { - $this->jsonResponse( array( "status" => "ERROR","message" => $this->l['invalid_filename'] ) ); - exit( 1 ); - } - if( ! isset( $d['targetdir'] ) || trim( $d['targetdir'] ) == "" ) - $d['targetdir'] = "./"; - if( ! $this->isPathValid( $d['targetdir'] ) ) { - $this->jsonResponse( array( "status" => "ERROR","message" => $this->l['invalid_dir'] ) ); - exit( 1 ); - } - if( ! is_dir( $d['targetdir'] ) && ! mkdir( $d['targetdir'], 0777, true ) ) { - $this->jsonResponse( array( "status" => "ERROR","message" => $this->l['folder_create_error'] ) ); - exit( 1 ); - } - if( realpath( $d['targetdir'] ) == substr( $this->getScriptRoot(), 0, strlen( realpath( $d['targetdir'] ) ) ) ) { - $tmpSelfContent = tmpfile(); - fwrite( $tmpSelfContent, file_get_contents( __FILE__ ) ); - $tmpSelfChecksum = hash_file( "sha256", __FILE__ ); - $restoreIFM = true; - } - if( substr( strtolower( $d['filename'] ), -4 ) == ".zip" ) { - if( ! IFMArchive::extractZip( $d['filename'], $d['targetdir'] ) ) { - $this->jsonResponse( array( "status" => "ERROR","message" => $this->l['extract_error'] ) ); - } else { - $this->jsonResponse( array( "status" => "OK","message" => $this->l['extract_success'] ) ); - } - } else { - if( ! IFMArchive::extractTar( $d['filename'], $d['targetdir'] ) ) { - $this->jsonResponse( array( "status" => "ERROR","message" => $this->l['extract_error'] ) ); - } else { - $this->jsonResponse( array( "status" => "OK","message" => $this->l['extract_success'] ) ); - } - } - if( $restoreIFM ) { - if( $tmpSelfChecksum != hash_file( "sha256", __FILE__ ) ) { - rewind( $tmpSelfContent ); - $fh = fopen( __FILE__, "w" ); - while( ! feof( $tmpSelfContent ) ) { - fwrite( $fh, fread( $tmpSelfContent, 8196 ) ); - } - fclose( $fh ); - } - fclose( $tmpSelfContent ); + if ($this->config['extract'] != 1) + throw new IFMException($this->l('nopermissions')); + + if (!file_exists($d['filename'])) + throw new IFMException($this->l('invalid_filename')); + + if (!isset($d['targetdir']) || trim($d['targetdir']) == "") + $d['targetdir'] = "./"; + + if (!$this->isPathValid($d['targetdir'])) + throw new IFMException($this->l('invalid_dir')); + + if (!is_dir($d['targetdir']) && !mkdir($d['targetdir'], 0777, true)) + throw new IFMException($this->l('folder_create_error')); + + if (realpath($d['targetdir']) == substr($this->getScriptRoot(), 0, strlen(realpath($d['targetdir'])))) { + $tmpSelfContent = tmpfile(); + fwrite($tmpSelfContent, file_get_contents(__FILE__)); + $tmpSelfChecksum = hash_file("sha256", __FILE__); + $restoreIFM = true; + } + + if (substr(strtolower($d['filename']), -4) == ".zip") { + if (!IFMArchive::extractZip($d['filename'], $d['targetdir'])) + throw new IFMException($this->l('extract_error')); + else + return ["status" => "OK","message" => $this->l('extract_success')]; + } else { + if (!IFMArchive::extractTar($d['filename'], $d['targetdir'])) + throw new IFMException($this->l('extract_error')); + else + return ["status" => "OK","message" => $this->l('extract_success')]; + } + + if ($restoreIFM) { + if ($tmpSelfChecksum != hash_file("sha256", __FILE__)) { + rewind($tmpSelfContent); + $fh = fopen(__FILE__, "w"); + while (!feof($tmpSelfContent)) + fwrite($fh, fread($tmpSelfContent, 8196)); + fclose($fh); } + fclose($tmpSelfContent); } } // uploads a file - private function uploadFile( array $d ) { - if( $this->config['upload'] != 1 ) - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['nopermissions'] ) ); - elseif( !isset( $_FILES['file'] ) ) - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['file_upload_error'] ) ); - else { - $newfilename = ( isset( $d["newfilename"] ) && $d["newfilename"]!="" ) ? $d["newfilename"] : $_FILES['file']['name']; - if( ! $this->isFilenameValid( $newfilename ) ) - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['invalid_filename'] ) ); - else { - if( $_FILES['file']['tmp_name'] ) { - if( is_writable( getcwd( ) ) ) { - if( move_uploaded_file( $_FILES['file']['tmp_name'], $newfilename ) ) - $this->jsonResponse( array( "status" => "OK", "message" => $this->l['file_upload_success'], "cd" => $d['dir'] ) ); - else - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['file_upload_error'] ) ); - } - else - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['file_upload_error'] ) ); - } else - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['file_not_found'] ) ); - } - } + private function uploadFile(array $d) { + if($this->config['upload'] != 1) + throw new IFMException($this->l('nopermissions')); + + if (!isset($_FILES['file'])) + throw new IFMException($this->l('file_upload_error')); + + $newfilename = (isset($d["newfilename"]) && $d["newfilename"]!="") ? $d["newfilename"] : $_FILES['file']['name']; + if (!$this->isFilenameValid($newfilename)) + throw new IFMException($this->l('invalid_filename')); + + if ($_FILES['file']['tmp_name']) { + if (is_writable(getcwd())) { + if (move_uploaded_file($_FILES['file']['tmp_name'], $newfilename)) + return ["status" => "OK", "message" => $this->l('file_upload_success'), "cd" => $d['dir']]; + else + throw new IFMException($this->l('file_upload_error')); + } else + throw new IFMException($this->l('file_upload_error')); + } else + throw new IFMException($this->l('file_not_found')); } // change permissions of a file - private function changePermissions( array $d ) { - if( $this->config['chmod'] != 1 ) $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['nopermissions'] ) ); - elseif( ! isset( $d["chmod"] )||$d['chmod']=="" ) $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['permission_parse_error'] ) ); - elseif( ! $this->isPathValid( $this->pathCombine( $d['dir'],$d['filename'] ) ) ) { $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['nopermissions'] ) ); } - else { - $chmod = $d["chmod"]; $cmi = true; - if( ! is_numeric( $chmod ) ) { - $cmi = false; - $chmod = str_replace( " ","",$chmod ); - if( strlen( $chmod )==9 ) { - $cmi = true; - $arr = array( substr( $chmod,0,3 ),substr( $chmod,3,3 ),substr( $chmod,6,3 ) ); - $chtmp = "0"; - foreach( $arr as $right ) { - $rtmp = 0; - if( substr( $right,0,1 )=="r" ) $rtmp = $rtmp + 4; elseif( substr( $right,0,1 )<>"-" ) $cmi = false; - if( substr( $right,1,1 )=="w" ) $rtmp = $rtmp + 2; elseif( substr( $right,1,1 )<>"-" ) $cmi = false; - if( substr( $right,2,1 )=="x" ) $rtmp = $rtmp + 1; elseif( substr( $right,2,1 )<>"-" ) $cmi = false; - $chtmp = $chtmp . $rtmp; - } - $chmod = intval( $chtmp ); - } - } - else $chmod = "0" . $chmod; + private function changePermissions(array $d) { + if ($this->config['chmod'] != 1) + throw new IFMException($this->l('nopermissions')); - if( $cmi ) { - try { - chmod( $d["filename"], (int)octdec( $chmod ) ); - $this->jsonResponse( array( "status" => "OK", "message" => $this->l['permission_change_success'] ) ); - } catch ( Exception $e ) { - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['permission_change_error'] ) ); + if (!isset($d["chmod"]) || $d['chmod'] == "" ) + throw new IFMException($this->l('permission_parse_error')); + + if (!$this->isPathValid($this->pathCombine($d['dir'], $d['filename']))) + throw new IFMException($this->l('nopermissions')); + + $chmod = $d["chmod"]; $cmi = true; + if (!is_numeric($chmod)) { + $cmi = false; + $chmod = str_replace(" ", "", $chmod); + + if (strlen($chmod) == 9) { + $cmi = true; + $arr = [substr($chmod, 0, 3), substr($chmod, 3, 3), substr($chmod, 6, 3)]; + $chtmp = "0"; + foreach ($arr as $right) { + $rtmp = 0; + if (substr($right, 0, 1) == "r") $rtmp = $rtmp + 4; elseif (substr($right, 0, 1) <> "-") $cmi = false; + if (substr($right, 1, 1) == "w") $rtmp = $rtmp + 2; elseif (substr($right, 1, 1) <> "-") $cmi = false; + if (substr($right, 2, 1) == "x") $rtmp = $rtmp + 1; elseif (substr($right, 2, 1) <> "-") $cmi = false; + $chtmp = $chtmp . $rtmp; } + $chmod = intval($chtmp); } - else $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['permission_parse_error'] ) ); - } + } else + $chmod = "0" . $chmod; + + if ($cmi) { + try { + chmod($d["filename"], (int)octdec($chmod)); + return ["status" => "OK", "message" => $this->l('permission_change_success')]; + } catch (Exception $e) { + throw new IFMException($this->l('permission_change_error')); + } + } else + throw new IFMException($this->l('permission_parse_error')); } // zips a directory and provides it for downloading // it creates a temporary zip file in the current directory, so it has to be as much space free as the file size is - private function zipnload( array $d ) { - if( $this->config['zipnload'] != 1 ) - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['nopermission'] ) ); - else { - if( ! file_exists( $d['filename'] ) ) - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['folder_not_found'] ) ); - elseif (!$this->isPathValid($d['filename'])) - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['invalid_dir'] ) ); - elseif ($d['filename'] != "." && !$this->isFilenameValid($d['filename'])) - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['invalid_filename'] ) ); - else { - unset( $zip ); - if ($this->isAbsolutePath($this->config['tmp_dir'])) - $dfile = $this->pathCombine( $this->config['tmp_dir'], uniqid( "ifm-tmp-" ) . ".zip" ); // temporary filename - else - $dfile = $this->pathCombine( __DIR__, $this->config['tmp_dir'], uniqid( "ifm-tmp-" ) . ".zip" ); // temporary filename + private function zipnload(array $d) { + if ($this->config['zipnload'] != 1) + throw new IFMException($this->l('nopermission')); - try { - IFMArchive::createZip(realpath($d['filename']), $dfile, array($this, 'isFilenameValid')); - if( $d['filename'] == "." ) { - if( getcwd() == $this->getScriptRoot() ) - $d['filename'] = "root"; - else - $d['filename'] = basename( getcwd() ); - } - $this->fileDownload( array( "file" => $dfile, "name" => $d['filename'] . ".zip", "forceDL" => true ) ); - } catch ( Exception $e ) { - echo $this->l['error'] . " " . $e->getMessage(); - } finally { - if( file_exists( $dfile ) ) @unlink( $dfile ); - } + if (!file_exists($d['filename'])) + throw new IFMException($this->l('folder_not_found')); + + if (!$this->isPathValid($d['filename'])) + throw new IFMException($this->l('invalid_dir')); + + if ($d['filename'] != "." && !$this->isFilenameValid($d['filename'])) + throw new IFMException($this->l('invalid_filename')); + + unset($zip); + if ($this->isAbsolutePath($this->config['tmp_dir'])) + $dfile = $this->pathCombine($this->config['tmp_dir'], uniqid("ifm-tmp-") . ".zip"); // temporary filename + else + $dfile = $this->pathCombine(__DIR__, $this->config['tmp_dir'], uniqid("ifm-tmp-") . ".zip"); // temporary filename + + try { + IFMArchive::createZip(realpath($d['filename']), $dfile, [$this, 'isFilenameValid']); + if ($d['filename'] == ".") { + if (getcwd() == $this->getScriptRoot()) + $d['filename'] = "root"; + else + $d['filename'] = basename(getcwd()); } + $this->fileDownload(["file" => $dfile, "name" => $d['filename'] . ".zip", "forceDL" => true]); + } catch (Exception $e) { + throw new IFMException($this->l('error') . " " . $e->getMessage()); + } finally { + if (file_exists($dfile)) + @unlink($dfile); } } // uploads a file from an other server using the curl extention - private function remoteUpload( array $d ) { - if( $this->config['remoteupload'] != 1 ) - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['nopermissions'] ) ); - elseif( !isset( $d['method'] ) || !in_array( $d['method'], array( "curl", "file" ) ) ) - $this->jsonResponse( array( "status" => "error", "message" => $this->l['invalid_params'] ) ); - elseif( $d['method']=="curl" && $this->checkCurl( ) == false ) - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['error']." cURL extention not installed." ) ); - elseif( $d['method']=="curl" && $this->checkCurl( ) == true ) { - $filename = ( isset( $d['filename'] )&&$d['filename']!="" )?$d['filename']:"curl_".uniqid( ); - $ch = curl_init( ); - if( $ch ) { - if( $this->isFilenameValid( $filename ) == false ) - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['invalid_filename'] ) ); - elseif( filter_var( $d['url'], FILTER_VALIDATE_URL ) === false ) - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['invalid_url'] ) ); + private function remoteUpload(array $d) { + if ($this->config['remoteupload'] != 1) + throw new IFMException($this->l('nopermissions')); + + if (!isset($d['method']) || !in_array($d['method'], ["curl", "file"])) + throw new IFMException($this->l('invalid_params')); + + if ($d['method'] == "curl" && $this->checkCurl() == false) + throw new IFMException($this->l('error')." cURL extention not installed."); + + if ($d['method'] == "curl" && $this->checkCurl() == true) { + $filename = (isset($d['filename']) && $d['filename'] != "") ? $d['filename'] : "curl_".uniqid(); + $ch = curl_init(); + if ($ch) { + if ($this->isFilenameValid($filename) == false) + throw new IFMException($this->l('invalid_filename')); + elseif (filter_var($d['url'], FILTER_VALIDATE_URL) === false) + throw new IFMException($this->l('invalid_url')); else { - $fp = fopen( $filename, "w" ); - if( $fp ) { - if( !curl_setopt( $ch, CURLOPT_URL, urldecode( $d['url'] ) ) || !curl_setopt( $ch, CURLOPT_FILE, $fp ) || !curl_setopt( $ch, CURLOPT_HEADER, 0 ) || !curl_exec( $ch ) ) - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['error']." ".curl_error( $ch ) ) ); - else { - $this->jsonResponse( array( "status" => "OK", "message" => $this->l['file_upload_success'] ) ); - } - curl_close( $ch ); - fclose( $fp ); - } else { - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['file_open_error'] ) ); - } + $fp = fopen($filename, "w"); + if ($fp) { + if ( + !curl_setopt($ch, CURLOPT_URL, urldecode($d['url'])) + || !curl_setopt($ch, CURLOPT_FILE, $fp) + || !curl_setopt($ch, CURLOPT_HEADER, 0) + || !curl_exec($ch) + ) + throw new IFMException($this->l('error')." ".curl_error($ch)); + else + return ["status" => "OK", "message" => $this->l('file_upload_success')]; + curl_close($ch); + fclose($fp); + } else + throw new IFMException($this->l('file_open_error')); } - } else { - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['error']." curl init" ) ); - } - } - elseif( $d['method']=='file' ) { - $filename = ( isset( $d['filename'] ) && $d['filename']!="" ) ? $d['filename'] : "curl_".uniqid( ); - if( $this->isFilenameValid( $filename ) == false ) - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['invalid_filename'] ) ); + } else + throw new IFMException($this->l('error')." curl init"); + } elseif ($d['method'] == 'file') { + $filename = (isset($d['filename']) && $d['filename'] != "") ? $d['filename'] : "curl_".uniqid(); + if ($this->isFilenameValid($filename) == false) + throw new IFMException($this->l('invalid_filename')); else { try { - file_put_contents( $filename, file_get_contents( $d['url'] ) ); - $this->jsonResponse( array( "status" => "OK", "message" => $this->l['file_upload_success'] ) ); - } catch( Exception $e ) { - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['error'] . " " . $e->getMessage() ) ); + file_put_contents($filename, file_get_contents($d['url'])); + return ["status" => "OK", "message" => $this->l('file_upload_success')]; + } catch (Exception $e) { + throw new IFMException($this->l('error') . " " . $e->getMessage()); } } - } - else - $this->jsonResponse( array( "status" => "error", "message" => $this->l['invalid_params'] ) ); + } else + throw new IFMException($this->l('invalid_params')); } - private function createArchive( $d ) { - if( $this->config['createarchive'] != 1 ) { - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['nopermissions'] ) ); - return false; - } - if( ! $this->isFilenameValid( $d['archivename'] ) ) { - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['invalid_filename'] ) ); - return false; - } - $filenames = array(); - foreach( $d['filenames'] as $file ) - if( ! $this->isFilenameValid( $file ) ) { - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['invalid_filename'] ) ); - exit( 1 ); - } else - array_push( $filenames, realpath( $file ) ); - switch( $d['format'] ) { + private function createArchive($d) { + if ($this->config['createarchive'] != 1) + throw new IFMException($this->l('nopermissions')); + + if (!$this->isFilenameValid($d['archivename'])) + throw new IFMException($this->l('invalid_filename')); + + $filenames = []; + foreach ($d['filenames'] as $file) + if (!$this->isFilenameValid($file)) + throw new IFMException($this->l('invalid_filename')); + else + array_push($filenames, realpath($file)); + + switch ($d['format']) { case "zip": - if( IFMArchive::createZip( $filenames, $d['archivename'] ) ) - $this->jsonResponse( array( "status" => "OK", "message" => $this->l['archive_create_success'] ) ); + if (IFMArchive::createZip($filenames, $d['archivename'])) + return ["status" => "OK", "message" => $this->l('archive_create_success')]; else - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['archive_create_error'] ) ); + throw new IFMException($this->l('archive_create_error')); break; case "tar": case "tar.gz": case "tar.bz2": - if( IFMArchive::createTar( $filenames, $d['archivename'], $d['format'] ) ) - $this->jsonResponse( array( "status" => "OK", "message" => $this->l['archive_create_success'] ) ); + if (IFMArchive::createTar($filenames, $d['archivename'], $d['format'])) + return ["status" => "OK", "message" => $this->l('archive_create_success')]; else - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['archive_create_error'] ) ); + throw new IFMException($this->l('archive_create_error')); break; default: - $this->jsonResponse( array( "status" => "ERROR", "message" => $this->l['archive_invalid_format'] ) ); + throw new IFMException($this->l('archive_invalid_format')); break; } } @@ -934,155 +908,146 @@ IFM_ASSETS help functions */ - private function log( $d ) { - file_put_contents( $this->pathCombine( $this->getRootDir(), "debug.ifm.log" ), ( is_array( $d ) ? print_r( $d, true ) . "\n" : $d . "\n" ), 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" => $this->l['json_encode_error'] . " " . $err ) ); - } else { - echo $json; - } - } - - private function convertToUTF8( &$item ) { - if( is_array( $item ) ) - array_walk( - $item, - array( $this, 'convertToUTF8' ) - ); + private function l($str) { + if (isset($_REQUEST['lang']) + && in_array($_REQUEST['lang'], array_keys($this->i18n)) + && isset($this->i18n[$_REQUEST['lang']][$str])) + return $this->i18n[$_REQUEST['lang']][$str]; else - if( function_exists( "mb_check_encoding" ) && ! mb_check_encoding( $item, "UTF-8" ) ) - $item = utf8_encode( $item ); + return $this->i18n['en'][$str]; } - function checkAuth() { - if( $this->config['auth'] == 0 ) + private function log($d) { + file_put_contents($this->pathCombine($this->getRootDir(), "debug.ifm.log"), (is_array($d) ? print_r($d, true)."\n" : $d."\n"), 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; + } + + throw new IFMException($this->l('json_encode_error')." ".$err); + } else + echo $json; + } + + private function convertToUTF8(&$item) { + if (is_array($item)) + array_walk($item, [$this, 'convertToUTF8']); + else + if (function_exists("mb_check_encoding") && !mb_check_encoding($item, "UTF-8")) + $item = utf8_encode($item); + } + + private function checkAuth() { + if ($this->config['auth'] == 0) return true; - if( isset( $_SERVER['HTTP_X_IFM_AUTH'] ) && ! empty( $_SERVER['HTTP_X_IFM_AUTH'] ) ) { - $cred = explode( ":", base64_decode( str_replace( "Basic ", "", $_SERVER['HTTP_X_IFM_AUTH'] ) ) ); - if( count( $cred ) == 2 && $this->checkCredentials( $cred[0], $cred[1] ) ) + $credentials_header = $_SERVER['HTTP_X_IFM_AUTH'] ?? $_SERVER['HTTP_AUTHORIZATION'] ?? false; + if ($credentials_header && !$this->config['auth_ignore_basic']) { + $cred = explode(":", base64_decode(str_replace("Basic ", "", $credentials_header))); + if (count($cred) == 2 && $this->checkCredentials($cred[0], $cred[1])) return true; } - if( session_status() !== PHP_SESSION_ACTIVE ) { - if( isset( $this->config['session_lifetime'] ) ) - ini_set( 'session.gc_maxlifetime', $this->config['session_lifetime'] ); - if( isset( $this->config['force_session_lifetime'] ) && $this->config['force_session_lifetime'] ) { - ini_set( 'session.gc_divisor', 1 ); - ini_set( 'session.gc_probability', 1 ); - } + if (session_status() !== PHP_SESSION_ACTIVE) session_start(); + + if (isset($_SESSION['ifmauth']) && $_SESSION['ifmauth'] == true) + return true; + + $login_failed = false; + if (isset($_POST["inputLogin"]) && isset($_POST["inputPassword"])) { + if ($this->checkCredentials($_POST["inputLogin"], $_POST["inputPassword"])) { + $_SESSION['ifmauth'] = true; + } else { + $_SESSION['ifmauth'] = false; + $login_failed = true; + } } - if( ! isset( $_SESSION['ifmauth'] ) || $_SESSION['ifmauth'] !== true ) { - $login_failed = false; - if( isset( $_POST["inputLogin"] ) && isset( $_POST["inputPassword"] ) ) { - if( $this->checkCredentials( $_POST["inputLogin"], $_POST["inputPassword"] ) ) { - $_SESSION['ifmauth'] = true; - } - else { - $_SESSION['ifmauth'] = false; - $login_failed = true; - } - } - - if( isset( $_SESSION['ifmauth'] ) && $_SESSION['ifmauth'] === true ) { - return true; - } else { - if( isset( $_POST["api"] ) ) { - if( $login_failed === true ) - $this->jsonResponse( array( "status"=>"ERROR", "message"=>"authentication failed" ) ); - else - $this->jsonResponse( array( "status"=>"ERROR", "message"=>"not authenticated" ) ); - } else { - $this->loginForm($login_failed); - } - return false; - } - } else { + if (isset($_SESSION['ifmauth']) && $_SESSION['ifmauth'] === true) return true; + else { + if ($login_failed === true) + throw new IFMException("Authentication failed: Wrong credentials", true); + else + throw new IFMException("Not authenticated" , true); } } - private function checkCredentials( $user, $pass ) { - list( $src, $srcopt ) = explode( ";", $this->config['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); $htpasswd = new Htpasswd(); - return $htpasswd->verifyPassword( $pass, $hash ) ? ( $uname == $user ) : false; + return $htpasswd->verifyPassword($pass, $hash) ? ($uname == $user) : false; break; case "file": - if( @file_exists( $srcopt ) && @is_readable( $srcopt ) ) { - $htpasswd = new Htpasswd( $srcopt ); - return $htpasswd->verify( $user, $pass ); + if (@file_exists($srcopt) && @is_readable($srcopt)) { + $htpasswd = new Htpasswd($srcopt); + return $htpasswd->verify($user, $pass); } else { - trigger_error( "IFM: Fatal: Credential file does not exist or is not readable" ); + trigger_error("IFM: Fatal: Credential file does not exist or is not readable"); return false; } break; case "ldap": $authenticated = false; - $ldapopts = explode( ";", $srcopt ); - if( count( $ldapopts ) === 3 ) { - list( $ldap_server, $rootdn, $ufilter ) = explode( ";", $srcopt ); + $ldapopts = explode(";", $srcopt); + if (count($ldapopts) === 3) { + list($ldap_server, $rootdn, $ufilter) = explode(";", $srcopt); } else { - list( $ldap_server, $rootdn ) = explode( ";", $srcopt ); + list($ldap_server, $rootdn) = explode(";", $srcopt); $ufilter = false; } $u = "uid=" . $user . "," . $rootdn; - if( ! $ds = ldap_connect( $ldap_server ) ) { - trigger_error( "Could not reach the ldap server.", E_USER_ERROR ); + 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 ) { - if( $ufilter ) { - if( ldap_count_entries( $ds, ldap_search( $ds, $rootdn, $ufilter ) ) > 0 ){ + ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3); + if ($ds) { + $ldbind = @ldap_bind($ds, $u, $pass); + if ($ldbind) { + if ($ufilter) { + if (ldap_count_entries($ds, ldap_search($ds, $rootdn, $ufilter)) > 0) { $authenticated = true; } else { - trigger_error( "User not allowed.", E_USER_ERROR ); + trigger_error("User not allowed.", E_USER_ERROR); $authenticated = false; } - } else { + } else $authenticated = true; - } } else { - trigger_error( ldap_error( $ds ), E_USER_ERROR ); + trigger_error(ldap_error($ds), E_USER_ERROR); $authenticated = false; } - ldap_unbind( $ds ); + ldap_unbind($ds); } else $authenticated = false; return $authenticated; @@ -1091,103 +1056,90 @@ IFM_ASSETS return false; } - private function loginForm($loginFailed=false, $loginMessage="") { - $err = ""; - if( $loginFailed ) - $err = ''; - $this->getHTMLHeader(); - $html = str_replace( "{{error}}", $err, $this->templates['login'] ); - $html = str_replace( "{{i18n.username}}", $this->l['username'], $html ); - $html = str_replace( "{{i18n.password}}", $this->l['password'], $html ); - $html = str_replace( "{{i18n.login}}", $this->l['login'], $html ); - print $html; - $this->getHTMLFooter(); - } - - private function filePermsDecode( $perms ) { - $oct = str_split( strrev( decoct( $perms ) ), 1 ); - $masks = array( '---', '--x', '-w-', '-wx', 'r--', 'r-x', 'rw-', 'rwx' ); + private function filePermsDecode($perms) { + $oct = str_split(strrev(decoct($perms)), 1); + $masks = ['---', '--x', '-w-', '-wx', 'r--', 'r-x', 'rw-', 'rwx']; return( sprintf( '%s %s %s', - array_key_exists( $oct[ 2 ], $masks ) ? $masks[ $oct[ 2 ] ] : '###', - array_key_exists( $oct[ 1 ], $masks ) ? $masks[ $oct[ 1 ] ] : '###', - array_key_exists( $oct[ 0 ], $masks ) ? $masks[ $oct[ 0 ] ] : '###') + array_key_exists($oct[2], $masks) ? $masks[$oct[2]] : '###', + array_key_exists($oct[1], $masks) ? $masks[$oct[1]] : '###', + array_key_exists($oct[0], $masks) ? $masks[$oct[0]] : '###') ); } - private function isAbsolutePath( $path ) { - if( $path === null || $path === '' ) + private function isAbsolutePath($path) { + if ($path === null || $path === '') return false; - return $path[0] === DIRECTORY_SEPARATOR || preg_match('~\A[A-Z]:(?![^/\\\\])~i',$path) > 0; + return $path[0] === DIRECTORY_SEPARATOR || preg_match('~^[A-Z]:(?![^/\\\\])~i',$path) > 0; } private function getRootDir() { - if( $this->config['root_dir'] == "" ) - return realpath( $this->getScriptRoot() ); - elseif( $this->isAbsolutePath( $this->config['root_dir'] ) ) - return realpath( $this->config['root_dir'] ); + if ($this->config['root_dir'] == "") + return realpath($this->getScriptRoot()); + elseif ($this->isAbsolutePath($this->config['root_dir'])) + return realpath($this->config['root_dir']); else - return realpath( $this->pathCombine( $this->getScriptRoot(), $this->config['root_dir'] ) ); + return realpath($this->pathCombine($this->getScriptRoot(), $this->config['root_dir'])); } private function getScriptRoot() { - return ( defined( 'IFM_FILENAME' ) ? dirname( realpath( IFM_FILENAME ) ) : dirname( __FILE__ ) ); + return dirname(__FILE__); } - private function getValidDir( $dir ) { - if( ! $this->isPathValid( $dir ) || ! is_dir( $dir ) ) + private function getValidDir($dir) { + if (!$this->isPathValid($dir) || !is_dir($dir)) return ""; else { - $rpDir = realpath( $dir ); + $rpDir = realpath($dir); $rpConfig = $this->getRootDir(); - if( $rpConfig == "/" ) + if ($rpConfig == "/") return $rpDir; - elseif( $rpDir == $rpConfig ) + elseif ($rpDir == $rpConfig) return ""; else { - $part = substr( $rpDir, strlen( $rpConfig ) ); - $part = ( in_array( substr( $part, 0, 1 ), ["/", "\\"] ) ) ? substr( $part, 1 ) : $part; + $part = substr($rpDir, strlen($rpConfig)); + $part = (in_array(substr($part, 0, 1), ["/", "\\"])) ? substr($part, 1) : $part; return $part; } } } - private function isPathValid( $dir ) { + private function isPathValid($dir) { /** * This function is also used to check non-existent paths, but the PHP realpath function returns false for * nonexistent paths. Hence we need to check the path manually in the following lines. */ $tmp_d = $dir; - $tmp_missing_parts = array(); - while( realpath( $tmp_d ) === false ) { - $tmp_i = pathinfo( $tmp_d ); - array_push( $tmp_missing_parts, $tmp_i['filename'] ); - $tmp_d = dirname( $tmp_d ); - if( $tmp_d == dirname( $tmp_d ) ) break; + $tmp_missing_parts = []; + while (realpath($tmp_d) === false) { + $tmp_i = pathinfo($tmp_d); + array_push($tmp_missing_parts, $tmp_i['filename']); + $tmp_d = dirname($tmp_d); + if ($tmp_d == dirname($tmp_d)) + break; } - $rpDir = $this->pathCombine( realpath( $tmp_d ), implode( "/", array_reverse( $tmp_missing_parts ) ) ); + $rpDir = $this->pathCombine(realpath($tmp_d), implode("/", array_reverse($tmp_missing_parts))); $rpConfig = $this->getRootDir(); - if( ! is_string( $rpDir ) || ! is_string( $rpConfig ) ) // can happen if open_basedir is in effect + if (!is_string($rpDir) || !is_string($rpConfig)) // can happen if open_basedir is in effect return false; - elseif( $rpDir == $rpConfig ) + elseif ($rpDir == $rpConfig) return true; - elseif( 0 === strpos( $rpDir, $rpConfig ) ) + elseif (0 === strpos($rpDir, $rpConfig)) return true; else return false; } private function chDirIfNecessary($d) { - if( substr( getcwd(), strlen( $this->getScriptRoot() ) ) != $this->getValidDir($d) && !empty( $d ) ) { - chdir( $d ); - } + if (substr(getcwd(), strlen($this->getScriptRoot())) != $this->getValidDir($d) && !empty($d)) + chdir($d); } - private function getTypeIcon( $type ) { + private function getTypeIcon($type) { $type = strtolower($type); - switch( $type ) { + switch ($type) { case "aac": case "aiff": case "mid": case "mp3": case "wav": return 'icon icon-file-audio'; break; case "ai": case "bmp": case "eps": case "tiff": case "gif": case "jpg": case "jpeg": case "png": case "psd": case "svg": return 'icon icon-file-image'; break; case "avi": case "flv": case "mp4": case "mpg": case "mkv": case "mpeg": case "webm": case "wmv": case "mov": return 'icon icon-file-video'; break; @@ -1202,126 +1154,144 @@ IFM_ASSETS } } - private function rec_rmdir( $path ) { - if( !is_dir( $path ) ) { + private function rec_rmdir($path) { + if (!is_dir($path)) return -1; - } - $dir = @opendir( $path ); - if( !$dir ) { + + $dir = @opendir($path); + if (!$dir) return -2; + while (($entry = @readdir($dir)) !== false) { + if ($entry == '.' || $entry == '..') continue; + if (is_dir($path . '/' . $entry)) { + $res = $this->rec_rmdir($path.'/'.$entry); + if ($res == -1) { + @closedir($dir); + return -2; + } else if ($res == -2) { + @closedir($dir); + return -2; + } else if ($res == -3) { + @closedir($dir); + return -3; + } else if ($res != 0) { + @closedir($dir); + return -2; + } + } else if (is_file($path.'/'.$entry) || is_link($path.'/'.$entry)) { + $res = @unlink($path.'/'.$entry); + if (!$res) { + @closedir($dir); + return -2; + } + } else { + @closedir($dir); + return -3; + } } - while( ( $entry = @readdir( $dir ) ) !== false ) { - if( $entry == '.' || $entry == '..' ) continue; - if( is_dir( $path . '/' . $entry ) ) { - $res = $this->rec_rmdir( $path . '/' . $entry ); - if( $res == -1 ) { @closedir( $dir ); return -2; } - else if( $res == -2 ) { @closedir( $dir ); return -2; } - else if( $res == -3 ) { @closedir( $dir ); return -3; } - else if( $res != 0 ) { @closedir( $dir ); return -2; } - } else if( is_file( $path . '/' . $entry ) || is_link( $path . '/' . $entry ) ) { - $res = @unlink( $path . '/' . $entry ); - if( !$res ) { @closedir( $dir ); return -2; } - } else { @closedir( $dir ); return -3; } - } - @closedir( $dir ); - $res = @rmdir( $path ); - if( !$res ) { return -2; } + @closedir($dir); + $res = @rmdir($path); + if (!$res) + return -2; return 0; } - private function xcopy( $source, $dest ) { - $isDir = is_dir( $source ); - if( $isDir ) - $dest = $this->pathCombine( $dest, basename( $source ) ); - if( ! is_dir( $dest ) ) + private function xcopy($source, $dest) { + $isDir = is_dir($source); + if ($isDir) + $dest = $this->pathCombine($dest, basename($source)); + if (!is_dir($dest)) mkdir($dest, 0777, true); - if( is_file( $source ) ) - return copy( $source, $this->pathCombine( $dest, basename( $source ) ) ); + if (is_file($source)) + return copy($source, $this->pathCombine($dest, basename($source))); - chdir( $source ); - foreach( glob( '*' ) as $item ) - $this->xcopy( $item, $dest ); - chdir( '..' ); + chdir($source); + foreach (glob('*') as $item) + $this->xcopy($item, $dest); + chdir('..'); return true; } // combines two parts to a valid path private function pathCombine(...$parts) { $ret = ""; - foreach($parts as $part) + foreach ($parts as $part) if (trim($part) != "") - $ret .= (empty($ret)?rtrim($part,"/"):trim($part, '/'))."/"; + $ret .= (empty($ret) ? rtrim($part,"/") : trim($part, '/'))."/"; return rtrim($ret, "/"); } // check if filename is allowed - public function isFilenameValid( $f ) { - if( ! $this->isFilenameAllowed( $f ) ) + public function isFilenameValid($f) { + if (!$this->isFilenameAllowed($f)) return false; - if( strtoupper( substr( PHP_OS, 0, 3 ) ) == "WIN" ) { + + if (strtoupper(substr(PHP_OS, 0, 3)) == "WIN") { // windows-specific limitations - foreach( array( '\\', '/', ':', '*', '?', '"', '<', '>', '|' ) as $char ) - if( strpos( $f, $char ) !== false ) + foreach (['\\', '/', ':', '*', '?', '"', '<', '>', '|'] as $char) + if (strpos($f, $char) !== false) return false; } else { // *nix-specific limitations - foreach( array( '/', '\0' ) as $char ) - if( strpos( $f, $char ) !== false ) + foreach (['/', '\0'] as $char) + if (strpos($f, $char) !== false) return false; } + // custom limitations - foreach( $this->config['forbiddenChars'] as $char ) - if( strpos( $f, $char ) !== false ) + foreach ($this->config['forbiddenChars'] as $char) + if (strpos($f, $char) !== false) return false; return true; } - private function isFilenameAllowed( $f ) { - if( $this->config['showhtdocs'] != 1 && substr( $f, 0, 3 ) == ".ht" ) + private function isFilenameAllowed($f) { + if ($this->config['showhtdocs'] != 1 && substr($f, 0, 3) == ".ht") return false; - elseif( $this->config['showhiddenfiles'] != 1 && substr( $f, 0, 1 ) == "." ) + elseif ($this->config['showhiddenfiles'] != 1 && substr($f, 0, 1) == ".") return false; - elseif( $this->config['selfoverwrite'] != 1 && getcwd() == $this->getScriptRoot() && $f == basename( __FILE__ ) ) + elseif ($this->config['selfoverwrite'] != 1 && getcwd() == $this->getScriptRoot() && $f == basename(__FILE__)) return false; else return true; } // sorting function for file and dir arrays - private function sortByName( $a, $b ) { - if( strtolower( $a['name'] ) == strtolower( $b['name'] ) ) return 0; - return ( strtolower( $a['name'] ) < strtolower( $b['name'] ) ) ? -1 : 1; + private function sortByName($a, $b) { + if (strtolower($a['name']) == strtolower($b['name'])) + return 0; + return (strtolower($a['name']) < strtolower($b['name'])) ? -1 : 1; } // is cURL extention avaliable? private function checkCurl() { - if( !function_exists( "curl_init" ) || - !function_exists( "curl_setopt" ) || - !function_exists( "curl_exec" ) || - !function_exists( "curl_close" ) ) return false; - else return true; + if (!function_exists("curl_init") + || !function_exists("curl_setopt") + || !function_exists("curl_exec") + || !function_exists("curl_close") + ) + return false; + else + return true; } - private function fileDownload( array $options ) { - if( ! isset( $options['name'] ) || trim( $options['name'] ) == "" ) - $options['name'] = basename( $options['file'] ); + private function fileDownload(array $options) { + if (!isset($options['name']) || trim($options['name']) == "") + $options['name'] = basename($options['file']); - if( isset( $options['forceDL'] ) && $options['forceDL'] ) { + if (isset($options['forceDL']) && $options['forceDL']) { $content_type = "application/octet-stream"; - header( 'Content-Disposition: attachment; filename="' . $options['name'] . '"' ); - } else { - $content_type = mime_content_type( $options['file'] ); - } + header('Content-Disposition: attachment; filename="'.$options['name'].'"'); + } else + $content_type = mime_content_type($options['file']); - // This header was quite some time present, but I don't know why... - //header( 'Content-Description: File Transfer' ); - header( 'Content-Type: ' . $content_type ); - header( 'Expires: 0' ); - header( 'Cache-Control: must-revalidate' ); - header( 'Pragma: public' ); - header( 'Content-Length: ' . filesize( $options['file'] ) ); + header('Content-Type: '.$content_type); + header('Expires: 0'); + header('Cache-Control: must-revalidate'); + header('Pragma: public'); + header('Content-Length: '.filesize($options['file'])); - $file_stream = fopen( $options['file'], 'rb' ); + $file_stream = fopen($options['file'], 'rb'); $stdout_stream = fopen('php://output', 'wb'); stream_copy_to_stream($file_stream, $stdout_stream); @@ -1329,5 +1299,4 @@ IFM_ASSETS fclose($file_stream); fclose($stdout_stream); } - } diff --git a/src/templates/app.html b/src/templates/app.html index 3787323..875ff79 100644 --- a/src/templates/app.html +++ b/src/templates/app.html @@ -21,27 +21,27 @@