egroupware/filemanager/inc/class.filemanager_ui.inc.php
Klaus Leithoff 5f42817c56 #add sidebox menue to filemanager, with Links to Home and root.
#filemanager supports the configuration of a different startfolder (other than users home directory)
#preferences for filemanager
-define links to folders, that show in sidebox menu
-specify the display characteristics in filelisting (default (all sorted), or forced folders first)
#configuration options for filemanager
-you may specify how many links to folders can be configured in filemanagers preferences

YOU HAVE TO RUN Search and Register Hooks of all Applications, and you may have to login/logout.
2008-08-27 11:17:00 +00:00

708 lines
23 KiB
PHP

<?php
/**
* eGroupWare - Filemanager - user interface
*
* @link http://www.egroupware.org
* @package filemanager
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2008 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
*/
class filemanager_ui
{
/**
* Methods callable via menuaction
*
* @var array
*/
var $public_functions = array(
'index' => true,
'file' => true,
);
/**
* Main filemanager page
*
* @param array $content=null
* @param string $msg=null
*/
function index(array $content=null,$msg=null)
{
$tpl = new etemplate('filemanager.index');
//_debug_array($content);
if (!is_array($content))
{
$content = array(
'nm' => $GLOBALS['egw']->session->appsession('index','filemanager'),
);
if (!is_array($content['nm']))
{
$content['nm'] = array(
'get_rows' => 'filemanager.filemanager_ui.get_rows', // I method/callback to request the data for the rows eg. 'notes.bo.get_rows'
'filter' => '1', // current dir only
'no_filter2' => True, // I disable the 2. filter (params are the same as for filter)
'no_cat' => True, // I disable the cat-selectbox
'lettersearch' => True, // I show a lettersearch
'searchletter' => false, // I0 active letter of the lettersearch or false for [all]
'start' => 0, // IO position in list
'order' => 'name', // IO name of the column to sort after (optional for the sortheaders)
'sort' => 'ASC', // IO direction of the sort: 'ASC' or 'DESC'
'default_cols' => '!comment,ctime', // I columns to use if there's no user or default pref (! as first char uses all but the named columns), default all columns
'csv_fields' => false, // I false=disable csv export, true or unset=enable it with auto-detected fieldnames,
//or array with name=>label or name=>array('label'=>label,'type'=>type) pairs (type is a eT widget-type)
'path' => '/home/'.$GLOBALS['egw_info']['user']['account_lid'],
);
}
if (isset($_GET['path']) && ($path = $_GET['path']) && $path[0] == '/' && egw_vfs::is_dir($path))
{
$content['nm']['path'] = $path;
}
else
{
if (!empty($GLOBALS['egw_info']['user']['preferences']['filemanager']['startfolder'])
&& egw_vfs::is_dir($GLOBALS['egw_info']['user']['preferences']['filemanager']['startfolder']))
{
$content['nm']['path'] = $GLOBALS['egw_info']['user']['preferences']['filemanager']['startfolder'];
}
}
if (isset($_GET['msg'])) $msg = $_GET['msg'];
}
// check if we have a failed upload AND upload_max_filesize >= post_max_size --> no $_POST array
if ($_GET['post_empty'] && self::km2int(ini_get('upload_max_filesize')) >= self::km2int(ini_get('post_max_size')) ||
// or size bigger as upload_max_filesize
$content['button']['upload'] && (!is_array($content['upload']) || !is_uploaded_file($content['upload']['tmp_name'])))
{
$msg = lang('Error uploading file!')."\n".self::max_upload_size_message();
unset($content['button']);
}
$content['nm']['msg'] = $msg;
if ($content['action'] || $content['nm']['rows'])
{
if ($content['action'])
{
$content['nm']['msg'] = self::action($content['action'],$content['nm']['rows']['checked'],$content['nm']['path']);
unset($content['action']);
}
elseif($content['nm']['rows']['delete'])
{
$content['nm']['msg'] = self::action('delete',array_keys($content['nm']['rows']['delete']),$content['nm']['path']);
}
unset($content['nm']['rows']);
}
$clipboard_files = $GLOBALS['egw']->session->appsession('clipboard_files','filemanager');
$clipboard_type = $GLOBALS['egw']->session->appsession('clipboard_type','filemanager');
if ($content['button'])
{
if ($content['button'])
{
list($button) = each($content['button']);
unset($content['button']);
}
switch($button)
{
case 'up':
if ($content['nm']['path'] != '/')
{
$content['nm']['path'] = dirname($content['nm']['path']);
}
break;
case 'home':
$content['nm']['path'] = '/home/'.$GLOBALS['egw_info']['user']['account_lid'];
break;
case 'createdir':
if ($content['nm']['path'][0] != '/')
{
$ses = $GLOBALS['egw']->session->appsession('index','filemanager');
$old_path = $ses['path'];
$content['nm']['path'] = egw_vfs::concat($old_path,$content['nm']['path']);
}
if (!@egw_vfs::mkdir($content['nm']['path'],null,STREAM_MKDIR_RECURSIVE))
{
$content['nm']['msg'] = !egw_vfs::is_writable(dirname($content['nm']['path'])) ?
lang('Permission denied!') : lang('Failed to create directory!');
if (!$old_path)
{
$ses = $GLOBALS['egw']->session->appsession('index','filemanager');
$old_path = $ses['path'];
}
$content['nm']['path'] = $old_path;
}
break;
case 'paste':
$content['nm']['msg'] = self::action($clipboard_type.'_paste',$clipboard_files,$content['nm']['path']);
break;
case 'upload':
$to = egw_vfs::concat($content['nm']['path'],$content['upload']['name']);
if ($content['upload'] && is_uploaded_file($content['upload']['tmp_name']) &&
(egw_vfs::is_writable($content['nm']['path']) || egw_vfs::is_writable($to)) &&
copy($content['upload']['tmp_name'],egw_vfs::PREFIX.$to))
{
$content['nm']['msg'] = lang('File successful uploaded.');
}
else
{
$content['nm']['msg'] = lang('Error uploading file!');
}
break;
}
}
if (!egw_vfs::is_dir($content['nm']['path']))
{
$content['nm']['msg'] .= lang('Directory not found or no permission to access it!');
}
else
{
$dir_is_writable = egw_vfs::is_writable($content['nm']['path']);
}
$content['paste_tooltip'] = $clipboard_files ? '<p><b>'.lang('%1 the following files into current directory',
$clipboard_type=='copy'?lang('Copy'):lang('Move')).':</b><br />'.implode('<br />',$clipboard_files).'</p>' : '';
$content['upload_size'] = self::max_upload_size_message();
//_debug_array($content);
$readonlys['button[paste]'] = !$clipboard_files;
$readonlys['button[createdir]'] = !$dir_is_writable;
$readonlys['button[upload]'] = $readonlys['upload'] = !$dir_is_writable;
if ($dir_is_writable || !$content['nm']['filter']) $sel_options['action']['delete'] = lang('Delete');
$sel_options['action']['copy'] = lang('Copy to clipboard');
if ($dir_is_writable || !$content['nm']['filter']) $sel_options['action']['cut'] = lang('Cut to clipboard');
$sel_options['filter'] = array(
'1' => 'Current directory',
'' => 'All subdirectories',
);
$tpl->exec('filemanager.filemanager_ui.index',$content,$sel_options,$readonlys,array('nm' => $content['nm']));
}
/**
* Convert numbers like '32M' or '512k' to integers
*
* @param string $size
* @return int
*/
private static function km2int($size)
{
if (!is_numeric($size))
{
switch(strtolower(substr($size,-1)))
{
case 'm':
$size = 1024*1024*(int)$size;
break;
case 'k':
$size = 1024*(int)$size;
break;
}
}
return (int)$size;
}
/**
* Message containing the max Upload size from the current php.ini settings
*
* We have to take the smaler one of upload_max_filesize AND post_max_size-2800 into account.
* memory_limit does NOT matter any more, because of the stream-interface of the vfs.
*
* @return string
*/
static function max_upload_size_message()
{
$upload_max_filesize = ini_get('upload_max_filesize');
$post_max_size = ini_get('post_max_size');
$max_upload = min(self::km2int($upload_max_filesize),self::km2int($post_max_size)-2800);
return lang('Maximum size for uploads').': '.egw_vfs::hsize($max_upload).
" (php.ini: upload_max_filesize=$upload_max_filesize, post_max_size=$post_max_size)";
}
/**
* Run a certain action with the selected file
*
* @param string $action
* @param array $selected selected pathes
* @param mixed $dir=null current directory
* @return string success or failure message displayed to the user
*/
static private function action($action,$selected,$dir=null)
{
//echo '<p>'.__METHOD__."($action,array(".implode(', ',$selected).",$dir)</p>\n";
if (!count($selected))
{
return lang('You need to select some files first!');
}
$errs = $dirs = $files = 0;
switch($action)
{
case 'delete':
$dirs = $files = $errs = 0;
foreach(egw_vfs::find($selected,array('depth'=>true)) as $path)
{
if (($is_dir = egw_vfs::is_dir($path)) && egw_vfs::rmdir($path,0))
{
++$dirs;
}
elseif (!$is_dir && egw_vfs::unlink($path))
{
++$files;
}
else
{
++$errs;
}
}
if ($errs)
{
return lang('%1 errors deleteting (%2 directories and %3 files deleted)!',$errs,$dirs,$files);
}
if ($dirs)
{
return lang('%1 directories and %2 files deleted.',$dirs,$files);
}
return $files == 1 ? lang('File deleted.') : lang('%1 files deleted.',$files);
case 'copy':
case 'cut':
$GLOBALS['egw']->session->appsession('clipboard_files','filemanager',$selected);
$GLOBALS['egw']->session->appsession('clipboard_type','filemanager',$action);
return lang('%1 URLs %2 to clipboard.',count($selected),$action=='copy'?lang('copied'):lang('cut'));
case 'copy_paste':
foreach($selected as $path)
{
if (!egw_vfs::is_dir($path))
{
$to = egw_vfs::concat($dir,egw_vfs::basename($path));
if ($path != $to && egw_vfs::copy($path,$to))
{
++$files;
}
else
{
++$errs;
}
}
else
{
$len = strlen(dirname($path));
foreach(egw_vfs::find($path) as $p)
{
$to = $dir.substr($p,$len);
if ($to == $p) // cant copy into itself!
{
++$errs;
continue;
}
if (($is_dir = egw_vfs::is_dir($p)) && egw_vfs::mkdir($to,null,STREAM_MKDIR_RECURSIVE))
{
++$dirs;
}
elseif(!$is_dir && egw_vfs::copy($p,$to))
{
++$files;
}
else
{
++$errs;
}
}
}
}
if ($errs)
{
return lang('%1 errors copying (%2 diretories and %3 files copied)!',$errs,$dirs,$files);
}
return $dirs ? lang('%1 directories and %2 files copied.',$dirs,$files) : lang('%1 files copied.',$files);
case 'cut_paste':
foreach($selected as $path)
{
$to = egw_vfs::concat($dir,egw_vfs::basename($path));
if ($path != $to && egw_vfs::rename($path,$to))
{
++$files;
}
else
{
++$errs;
}
}
$GLOBALS['egw']->session->appsession('clipboard_files','filemanager',false); // cant move again
if ($errs)
{
return lang('%1 errors moving (%2 files moved)!',$errs,$files);
}
return lang('%1 files moved.',$files);
}
return "Unknown action '$action'!";
}
/**
* Callback to fetch the rows for the nextmatch widget
*
* @param array $query
* @param array &$rows
* @param array &$readonlys
*/
function get_rows($query,&$rows,&$readonlys)
{
$GLOBALS['egw']->session->appsession('index','filemanager',$query);
//_debug_array($query);
if (!egw_vfs::is_dir($query['path']))
{
$rows = array();
$query['total'] = 0;
}
$rows = $dir_is_writable = array();
if($query['searchletter'] && !empty($query['search']))
{
$namefilter = '/^'.$query['searchletter'].'.*'.str_replace(array('\\?','\\*'),array('.{1}','.*'),preg_quote($query['search'])).'/i';
if ($query['searchletter'] == strtolower($query['search'][0]))
{
$namefilter = '/^('.$query['searchletter'].'.*'.str_replace(array('\\?','\\*'),array('.{1}','.*'),preg_quote($query['search'])).'|'.
str_replace(array('\\?','\\*'),array('.{1}','.*'),preg_quote($query['search'])).')/i';
}
}
elseif ($query['searchletter'])
{
$namefilter = '/^'.$query['searchletter'].'/i';
}
elseif(!empty($query['search']))
{
$namefilter = '/'.str_replace(array('\\?','\\*'),array('.{1}','.*'),preg_quote($query['search'])).'/i';
}
// if you want to have the folders on top, we must search for them first
if ((int)$GLOBALS['egw_info']['user']['preferences']['filemanager']['alwayssortfolderstotop']==1) {
$dirs = array();
$files = array();
foreach(egw_vfs::find($query['path'],array(
'type'=>'d',
'mindepth' => 1,
'maxdepth' => $query['filter'] ? $query['filter'] : null,
'order' => $query['order'], 'sort' => $query['sort'],
'limit' => (int)$query['num_rows'].','.(int)$query['start'],
'need_mime' => true,
'name_preg' => $namefilter,
),true) as $path => $row)
{
$row['icon'] = egw_vfs::mime_icon($row['mime']);
$row['perms'] = egw_vfs::int2mode($row['mode']);
// only show link if we have access to the file or dir
if (egw_vfs::check_access($path,egw_vfs::READABLE)) $row['link'] = '/index.php?menuaction=filemanager.filemanager_ui.index&path='.$path;
$row['user'] = $row['uid'] ? $GLOBALS['egw']->accounts->id2name($row['uid']) : 'root';
$row['group'] = $row['gid'] ? $GLOBALS['egw']->accounts->id2name(-$row['gid']) : 'root';
$row['hsize'] = egw_vfs::hsize($row['size']);
$dirs[] = $row;
$dir = dirname($path);
if (!isset($dir_is_writable[$dir])) $dir_is_writable[$dir] = egw_vfs::is_writable($dir);
if (!$dir_is_writable[$dir]) $readonlys["delete[$path]"] = true; // no rights to delete the file
}
$numofdirs = egw_vfs::$find_total;
$dirsretrieved = count($dirs);
#echo "Dirs found:$numofdirs<br>"."Rows to query:".(int)$query['num_rows']." Start at:".(int)$query['start']."<br>";
$filesdontshowjet = 0;
if ($dirsretrieved >= (int)$query['num_rows']) {
$filesdontshowjet =1;
}
// retrieve the files as well, since we need the total number of the search/listing
$numofrows = (int)$query['num_rows'] - $dirsretrieved;
$startatrow = 0;
if ($filesdontshowjet == 0 && (int)$query['start'] > $numofdirs) $startatrow = (int)$query['start']-$numofdirs;
#echo "Filessection:Dirs retrieved:$dirsretrieved<br>"."Rows to query:".$numofrows." Start at:".$startatrow."<br>";
foreach(egw_vfs::find($query['path'],array(
'type'=>'f',
'mindepth' => 1,
'maxdepth' => $query['filter'] ? $query['filter'] : null,
'order' => $query['order'], 'sort' => $query['sort'],
'limit' => $numofrows.','.$startatrow,
'need_mime' => true,
'name_preg' => $namefilter,
),true) as $path => $row)
{
$row['icon'] = egw_vfs::mime_icon($row['mime']);
$row['perms'] = egw_vfs::int2mode($row['mode']);
// only show link if we have access to the file or dir
if (egw_vfs::check_access($path,egw_vfs::READABLE)) $row['link'] = egw_vfs::download_url($path);
$row['user'] = $row['uid'] ? $GLOBALS['egw']->accounts->id2name($row['uid']) : 'root';
$row['group'] = $row['gid'] ? $GLOBALS['egw']->accounts->id2name(-$row['gid']) : 'root';
$row['hsize'] = egw_vfs::hsize($row['size']);
if ($filesdontshowjet == 0) $files[] = $row;
$dir = dirname($path);
if (!isset($dir_is_writable[$dir])) $dir_is_writable[$dir] = egw_vfs::is_writable($dir);
if (!$dir_is_writable[$dir]) $readonlys["delete[$path]"] = true; // no rights to delete the file
}
$numoffiles = egw_vfs::$find_total;
$rows = array_merge($dirs,$files);
//_debug_array($readonlys);
return egw_vfs::$find_total = $numofdirs + $numoffiles;
} else {
foreach(egw_vfs::find($query['path'],array(
'type'=>'d',
'mindepth' => 1,
'maxdepth' => $query['filter'] ? $query['filter'] : null,
'order' => $query['order'], 'sort' => $query['sort'],
'limit' => (int)$query['num_rows'].','.(int)$query['start'],
'need_mime' => true,
'name_preg' => $namefilter,
),true) as $path => $row)
{
$row['icon'] = egw_vfs::mime_icon($row['mime']);
$row['perms'] = egw_vfs::int2mode($row['mode']);
// only show link if we have access to the file or dir
if (egw_vfs::check_access($path,egw_vfs::READABLE))
{
if ($row['mime'] == egw_vfs::DIR_MIME_TYPE)
{
$row['link'] = '/index.php?menuaction=filemanager.filemanager_ui.index&path='.$path;
}
else
{
$row['link'] = egw_vfs::download_url($path);
}
}
$row['user'] = $row['uid'] ? $GLOBALS['egw']->accounts->id2name($row['uid']) : 'root';
$row['group'] = $row['gid'] ? $GLOBALS['egw']->accounts->id2name(-$row['gid']) : 'root';
$row['hsize'] = egw_vfs::hsize($row['size']);
//echo $path; _debug_array($row);
$rows[++$n] = $row;
$dir = dirname($path);
if (!isset($dir_is_writable[$dir]))
{
$dir_is_writable[$dir] = egw_vfs::is_writable($dir);
}
if (!$dir_is_writable[$dir])
{
$readonlys["delete[$path]"] = true; // no rights to delete the file
}
}
}
//_debug_array($readonlys);
return egw_vfs::$find_total;
}
/**
* Preferences of a file/directory
*
* @param array $content=null
* @param string $msg=''
*/
function file(array $content=null,$msg='')
{
static $tabs = 'general|perms|eacl|preview';
$tpl = new etemplate('filemanager.file');
if (!is_array($content))
{
if (!($stat = egw_vfs::stat($path = $_GET['path'])))
{
$content['msg'] = lang('File or directory not found!');
}
else
{
$content = $stat;
$content['name'] = egw_vfs::basename($path);
$content['dir'] = dirname($path);
$content['path'] = $path;
$content['hsize'] = egw_vfs::hsize($stat['size']);
$content['mime'] = egw_vfs::mime_content_type($path);
$content['icon'] = egw_vfs::mime_icon($content['mime']);
$content['gid'] *= -1; // our widgets use negative gid's
}
$content[$tabs] = $_GET['tabs'];
if (!($content['is_dir'] = egw_vfs::is_dir($path)))
{
$content['perms']['executable'] = (int)!!($content['mode'] & 0111);
$mask = 6;
if (preg_match('/^text/',$content['mime']) && $content['size'] < 100000)
{
$content['text_content'] = file_get_contents(egw_vfs::PREFIX.$path);
}
}
else
{
//currently not implemented in backend $content['perms']['sticky'] = (int)!!($content['mode'] & 0x201);
$mask = 7;
}
foreach(array('owner' => 6,'group' => 3,'other' => 0) as $name => $shift)
{
$content['perms'][$name] = ($content['mode'] >> $shift) & $mask;
}
$content['is_owner'] = egw_vfs::has_owner_rights($path,$content);
}
else
{
//_debug_array($content);
$path =& $content['path'];
list($button) = @each($content['button']); unset($content['button']);
if (in_array($button,array('save','apply')))
{
foreach($content['old'] as $name => $old_value)
{
if (isset($content[$name]) && $old_value != $content[$name])
{
switch($name)
{
case 'name':
if (egw_vfs::rename($path,$to = egw_vfs::concat($content['dir'],$content['name'])))
{
$msg .= lang('Renamed %1 to %2.',$path,$to).' ';
$content['old']['name'] = $content[$name];
$path = $to;
}
else
{
$msg .= lang('Rename of %1 to %2 failed!',$path,$to).' ';
}
break;
default:
static $name2cmd = array('uid' => 'chown','gid' => 'chgrp','perms' => 'chmod');
$cmd = array('egw_vfs',$name2cmd[$name]);
$value = $name == 'perms' ? self::perms2mode($content['perms']) : $content[$name];
if ($content['modify_subs'] && $name == 'perms')
{
egw_vfs::find($path,array('type'=>'d'),$cmd,array($value));
egw_vfs::find($path,array('type'=>'f'),$cmd,array($value & 0666)); // no execute for files
}
elseif ($content['modify_subs'])
{
egw_vfs::find($path,null,$cmd,array($value));
}
else
{
call_user_func_array($cmd,array($path,$value));
}
$msg .= lang('Permissions changed for %1.',$path.($content['modify_subs']?' '.lang('and all it\'s childeren'):''));
break;
}
}
}
}
elseif ($content['eacl'] && $content['is_owner'])
{
if ($content['eacl']['delete'])
{
list($ino_owner) = each($content['eacl']['delete']);
list($ino,$owner) = explode('-',$ino_owner);
$msg .= egw_vfs::eacl($path,null,$owner) ? lang('ACL deleted.') : lang('Error deleting the ACL entry!');
}
elseif ($button == 'eacl')
{
if (!$content['eacl']['owner'])
{
$msg .= lang('You need to select an owner!');
}
else
{
$msg .= egw_vfs::eacl($path,$content['eacl']['rights'],$content['eacl']['owner']) ?
lang('ACL added.') : lang('Error adding the ACL!');
}
}
}
// refresh opender and close our window
$link = egw::link('/index.php',array(
'menuaction' => 'filemanager.filemanager_ui.index',
'msg' => $msg,
));
$js = "opener.location.href='".addslashes($link)."'; ";
if ($button == 'save') $js .= "window.close();";
echo "<html>\n<body>\n<script>\n$js\n</script>\n</body>\n</html>\n";
if ($button == 'save')$GLOBALS['egw']->common->egw_exit();
}
$content['link'] = $GLOBALS['egw']->link(egw_vfs::download_url($path));
$content['msg'] = $msg;
if (($readonlys['uid'] = !egw_vfs::$is_root) && !$content['uid']) $content['ro_uid_root'] = 'root';
// only owner can change group & perms
if (($readonlys['gid'] = !$content['is_owner'] ||
parse_url(egw_vfs::resolve_url($content['path']),PHP_URL_SCHEME) == 'oldvfs')) // no uid, gid or perms in oldvfs
{
if (!$content['gid']) $content['ro_gid_root'] = 'root';
foreach($content['perms'] as $name => $value)
{
$readonlys['perms['.$name.']'] = true;
}
}
$readonlys['name'] = !egw_vfs::is_writable($content['dir']);
$readonlys[$tabs]['eacl'] = true; // eacl off by default
if ($content['is_dir'])
{
$readonlys[$tabs]['preview'] = true; // no preview tab for dirs
$sel_options['rights']=$sel_options['owner']=$sel_options['group']=$sel_options['other'] = array(
7 => lang('Display and modification of content'),
5 => lang('Display of content'),
0 => lang('No access'),
);
if(($content['eacl'] = egw_vfs::get_eacl($content['path'])) !== false) // backend supports eacl
{
unset($readonlys[$tabs]['eacl']); // --> switch the tab on again
foreach($content['eacl'] as &$eacl)
{
$eacl['path'] = parse_url($eacl['path'],PHP_URL_PATH);
$readonlys['delete['.$eacl['ino'].'-'.$eacl['owner'].']'] = $eacl['ino'] != $content['ino'] ||
$eacl['path'] != $content['path'] || !$content['is_owner'];
}
array_unshift($content['eacl'],false); // make the keys start with 1, not 0
$content['eacl']['rights'] = $content['eacl']['owner'] = 0;
}
}
else
{
$sel_options['owner']=$sel_options['group']=$sel_options['other'] = array(
6 => lang('Read & write access'),
4 => lang('Read access only'),
0 => lang('No access'),
);
}
$preserve = $content;
if (!isset($preserve['old']))
{
$preserve['old'] = array(
'perms' => $content['perms'],
'name' => $content['name'],
'uid' => $content['uid'],
'gid' => $content['gid'],
);
}
$GLOBALS['egw_info']['flags']['java_script'] = "<script>window.focus();</script>\n";
$GLOBALS['egw_info']['flags']['app_header'] = lang('Preferences').' '.$path;
$tpl->exec('filemanager.filemanager_ui.file',$content,$sel_options,$readonlys,$preserve,2);
}
/**
* Convert perms array back to integer mode
*
* @param array $perms with keys owner, group, other, executable, sticky
* @return int
*/
private function perms2mode(array $perms)
{
$mode = $perms['owner'] << 6 | $perms['group'] << 3 | $prems['other'];
if ($mode['executable'])
{
$mode |= 0111;
}
if ($mode['sticky'])
{
$mode |= 0x201;
}
return $mode;
}
}