Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like filemanager_ui often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use filemanager_ui, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 24 | class filemanager_ui |
||
| 25 | { |
||
| 26 | /** |
||
| 27 | * Methods callable via menuaction |
||
| 28 | * |
||
| 29 | * @var array |
||
| 30 | */ |
||
| 31 | var $public_functions = array( |
||
| 32 | 'index' => true, |
||
| 33 | 'file' => true, |
||
| 34 | ); |
||
| 35 | |||
| 36 | /** |
||
| 37 | * Views available from plugins |
||
| 38 | * |
||
| 39 | * @var array |
||
| 40 | */ |
||
| 41 | public static $views = array( |
||
| 42 | 'filemanager_ui::listview' => 'Listview', |
||
| 43 | ); |
||
| 44 | public static $views_init = false; |
||
| 45 | |||
| 46 | /** |
||
| 47 | * vfs namespace for document merge properties |
||
| 48 | * |
||
| 49 | */ |
||
| 50 | public static $merge_prop_namespace = ''; |
||
| 51 | |||
| 52 | /** |
||
| 53 | * Constructor |
||
| 54 | * |
||
| 55 | */ |
||
| 56 | function __construct() |
||
| 72 | |||
| 73 | /** |
||
| 74 | * Initialise and return available views |
||
| 75 | * |
||
| 76 | * @return array with method => label pairs |
||
| 77 | */ |
||
| 78 | public static function init_views() |
||
| 96 | |||
| 97 | /** |
||
| 98 | * Get active view |
||
| 99 | * |
||
| 100 | * @return string |
||
| 101 | */ |
||
| 102 | public static function get_view() |
||
| 116 | |||
| 117 | /** |
||
| 118 | * Context menu |
||
| 119 | * |
||
| 120 | * @return array |
||
| 121 | */ |
||
| 122 | public static function get_actions() |
||
| 123 | { |
||
| 124 | $actions = array( |
||
| 125 | 'open' => array( |
||
| 126 | 'caption' => lang('Open'), |
||
| 127 | 'icon' => '', |
||
| 128 | 'group' => $group=1, |
||
| 129 | 'allowOnMultiple' => false, |
||
| 130 | 'onExecute' => 'javaScript:app.filemanager.open', |
||
| 131 | 'default' => true |
||
| 132 | ), |
||
| 133 | 'saveas' => array( |
||
| 134 | 'caption' => lang('Save as'), |
||
| 135 | 'group' => $group, |
||
| 136 | 'allowOnMultiple' => true, |
||
| 137 | 'icon' => 'filesave', |
||
| 138 | 'onExecute' => 'javaScript:app.filemanager.force_download', |
||
| 139 | 'disableClass' => 'isDir', |
||
| 140 | 'enabled' => 'javaScript:app.filemanager.is_multiple_allowed' |
||
| 141 | ), |
||
| 142 | 'saveaszip' => array( |
||
| 143 | 'caption' => lang('Save as ZIP'), |
||
| 144 | 'group' => $group, |
||
| 145 | 'allowOnMultiple' => true, |
||
| 146 | 'icon' => 'save_zip', |
||
| 147 | 'postSubmit' => true |
||
| 148 | ), |
||
| 149 | 'edit' => array( |
||
| 150 | 'caption' => lang('Edit settings'), |
||
| 151 | 'group' => $group, |
||
| 152 | 'allowOnMultiple' => false, |
||
| 153 | 'onExecute' => Api\Header\UserAgent::mobile()?'javaScript:app.filemanager.viewEntry':'javaScript:app.filemanager.editprefs', |
||
| 154 | 'mobileViewTemplate' => 'file?'.filemtime(Api\Etemplate\Widget\Template::rel2path('/filemanager/templates/mobile/file.xet')) |
||
| 155 | ), |
||
| 156 | 'mkdir' => array( |
||
| 157 | 'caption' => lang('Create directory'), |
||
| 158 | 'icon' => 'filemanager/button_createdir', |
||
| 159 | 'group' => $group, |
||
| 160 | 'allowOnMultiple' => false, |
||
| 161 | 'onExecute' => 'javaScript:app.filemanager.createdir', |
||
| 162 | 'disableClass' => 'noEdit' |
||
| 163 | ), |
||
| 164 | 'mail' => array( |
||
| 165 | 'caption' => lang('Share files'), |
||
| 166 | 'icon' => 'filemanager/mail_post_to', |
||
| 167 | 'group' => $group, |
||
| 168 | 'children' => array( |
||
| 169 | 'sharelink' => array( |
||
| 170 | 'caption' => lang('Share link'), |
||
| 171 | 'group' => 1, |
||
| 172 | 'icon' => 'share', |
||
| 173 | 'allowOnMultiple' => false, |
||
| 174 | 'order' => 11, |
||
| 175 | 'onExecute' => 'javaScript:app.filemanager.share_link' |
||
| 176 | )), |
||
| 177 | ), |
||
| 178 | 'egw_paste' => array( |
||
| 179 | 'enabled' => false, |
||
| 180 | 'group' => $group + 0.5, |
||
| 181 | 'hideOnDisabled' => true |
||
| 182 | ), |
||
| 183 | 'paste' => array( |
||
| 184 | 'caption' => lang('Paste'), |
||
| 185 | 'acceptedTypes' => 'file', |
||
| 186 | 'group' => $group + 0.5, |
||
| 187 | 'order' => 10, |
||
| 188 | 'enabled' => 'javaScript:app.filemanager.paste_enabled', |
||
| 189 | 'children' => array() |
||
| 190 | ), |
||
| 191 | 'copylink' => array( |
||
| 192 | 'caption' => lang('Copy link address'), |
||
| 193 | 'group' => $group + 0.5, |
||
| 194 | 'icon' => 'copy', |
||
| 195 | 'allowOnMultiple' => false, |
||
| 196 | 'order' => 10, |
||
| 197 | 'onExecute' => 'javaScript:app.filemanager.copy_link' |
||
| 198 | ), |
||
| 199 | 'documents' => filemanager_merge::document_action( |
||
| 200 | $GLOBALS['egw_info']['user']['preferences']['filemanager']['document_dir'], |
||
| 201 | ++$group, 'Insert in document', 'document_', |
||
| 202 | $GLOBALS['egw_info']['user']['preferences']['filemanager']['default_document'] |
||
| 203 | ), |
||
| 204 | 'delete' => array( |
||
| 205 | 'caption' => lang('Delete'), |
||
| 206 | 'group' => ++$group, |
||
| 207 | 'confirm' => 'Delete these files or directories?', |
||
| 208 | 'onExecute' => 'javaScript:app.filemanager.action', |
||
| 209 | ), |
||
| 210 | // DRAG and DROP events |
||
| 211 | 'file_drag' => array( |
||
| 212 | 'dragType' => array('file','link'), |
||
| 213 | 'type' => 'drag', |
||
| 214 | 'onExecute' => 'javaScript:app.filemanager.drag' |
||
| 215 | ), |
||
| 216 | 'file_drop_mail' => array( |
||
| 217 | 'type' => 'drop', |
||
| 218 | 'acceptedTypes' => 'mail', |
||
| 219 | 'onExecute' => 'javaScript:app.filemanager.drop', |
||
| 220 | 'hideOnDisabled' => true |
||
| 221 | ), |
||
| 222 | 'file_drop_move' => array( |
||
| 223 | 'icon' => 'stylite/move', |
||
| 224 | 'acceptedTypes' => 'file', |
||
| 225 | 'caption' => lang('Move into folder'), |
||
| 226 | 'type' => 'drop', |
||
| 227 | 'onExecute' => 'javaScript:app.filemanager.drop', |
||
| 228 | 'default' => true |
||
| 229 | ), |
||
| 230 | 'file_drop_copy' => array( |
||
| 231 | 'icon' => 'stylite/edit_copy', |
||
| 232 | 'acceptedTypes' => 'file', |
||
| 233 | 'caption' => lang('Copy into folder'), |
||
| 234 | 'type' => 'drop', |
||
| 235 | 'onExecute' => 'javaScript:app.filemanager.drop' |
||
| 236 | ), |
||
| 237 | 'file_drop_symlink' => array( |
||
| 238 | 'icon' => 'linkpaste', |
||
| 239 | 'acceptedTypes' => 'file', |
||
| 240 | 'caption' => lang('Link into folder'), |
||
| 241 | 'type' => 'drop', |
||
| 242 | 'onExecute' => 'javaScript:app.filemanager.drop' |
||
| 243 | ) |
||
| 244 | ); |
||
| 245 | if (!isset($GLOBALS['egw_info']['user']['apps']['mail'])) |
||
| 246 | { |
||
| 247 | unset($actions['mail']); |
||
| 248 | } |
||
| 249 | else |
||
| 250 | { |
||
| 251 | foreach(Vfs\Sharing::$modes as $mode => $data) |
||
| 252 | { |
||
| 253 | $actions['mail']['children']['mail_'.$mode] = array( |
||
| 254 | 'caption' => $data['label'], |
||
| 255 | 'hint' => $data['title'], |
||
| 256 | 'group' => 2, |
||
| 257 | 'onExecute' => 'javaScript:app.filemanager.mail', |
||
| 258 | ); |
||
| 259 | } |
||
| 260 | } |
||
| 261 | // This would be done automatically, but we're overriding |
||
| 262 | foreach($actions as $action_id => $action) |
||
| 263 | { |
||
| 264 | if($action['type'] == 'drop' && $action['caption']) |
||
| 265 | { |
||
| 266 | $action['type'] = 'popup'; |
||
| 267 | if($action['acceptedTypes'] == 'file') |
||
| 268 | { |
||
| 269 | $action['enabled'] = 'javaScript:app.filemanager.paste_enabled'; |
||
| 270 | } |
||
| 271 | $actions['paste']['children']["{$action_id}_paste"] = $action; |
||
| 272 | } |
||
| 273 | } |
||
| 274 | |||
| 275 | // Anonymous users have limited actions |
||
| 276 | if(self::is_anonymous($GLOBALS['egw_info']['user']['account_id'])) |
||
| 277 | { |
||
| 278 | self::restrict_anonymous_actions($actions); |
||
| 279 | } |
||
| 280 | return $actions; |
||
| 281 | } |
||
| 282 | |||
| 283 | /** |
||
| 284 | * Get mergeapp property for given path |
||
| 285 | * |
||
| 286 | * @param string $path |
||
| 287 | * @param string $scope (default) or 'parents' |
||
| 288 | * $scope == 'self' query only the given path |
||
| 289 | * $scope == 'parents' query only path parents for property (first parent in hierarchy upwards wins) |
||
| 290 | * |
||
| 291 | * @return string merge application or NULL if no property found |
||
| 292 | */ |
||
| 293 | private static function get_mergeapp($path, $scope='self') |
||
| 294 | { |
||
| 295 | $app = null; |
||
| 296 | switch($scope) |
||
| 297 | { |
||
| 298 | case 'self': |
||
| 299 | $props = Vfs::propfind($path, static::$merge_prop_namespace); |
||
| 300 | $app = empty($props) ? null : $props[0]['val']; |
||
| 301 | break; |
||
| 302 | case 'parents': |
||
| 303 | // search for props in parent directories |
||
| 304 | $currentpath = $path; |
||
| 305 | while($dir = Vfs::dirname($currentpath)) |
||
| 306 | { |
||
| 307 | $props = Vfs::propfind($dir, static::$merge_prop_namespace); |
||
| 308 | if(!empty($props)) |
||
| 309 | { |
||
| 310 | // found prop in parent directory |
||
| 311 | return $app = $props[0]['val']; |
||
| 312 | } |
||
| 313 | $currentpath = $dir; |
||
| 314 | } |
||
| 315 | break; |
||
| 316 | } |
||
| 317 | |||
| 318 | return $app; |
||
| 319 | } |
||
| 320 | |||
| 321 | /** |
||
| 322 | * Main filemanager page |
||
| 323 | * |
||
| 324 | * @param array $content |
||
| 325 | * @param string $msg |
||
| 326 | */ |
||
| 327 | function index(array $content=null,$msg=null) |
||
| 328 | { |
||
| 329 | if (!is_array($content)) |
||
| 330 | { |
||
| 331 | $content = array( |
||
| 332 | 'nm' => Api\Cache::getSession('filemanager', 'index'), |
||
| 333 | ); |
||
| 334 | if (!is_array($content['nm'])) |
||
| 335 | { |
||
| 336 | $content['nm'] = array( |
||
| 337 | 'get_rows' => 'filemanager.filemanager_ui.get_rows', // I method/callback to request the data for the rows eg. 'notes.bo.get_rows' |
||
| 338 | 'filter' => '', // current dir only |
||
| 339 | 'no_filter2' => True, // I disable the 2. filter (params are the same as for filter) |
||
| 340 | 'no_cat' => True, // I disable the cat-selectbox |
||
| 341 | 'lettersearch' => True, // I show a lettersearch |
||
| 342 | 'searchletter' => false, // I0 active letter of the lettersearch or false for [all] |
||
| 343 | 'start' => 0, // IO position in list |
||
| 344 | 'order' => 'name', // IO name of the column to sort after (optional for the sortheaders) |
||
| 345 | 'sort' => 'ASC', // IO direction of the sort: 'ASC' or 'DESC' |
||
| 346 | '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 |
||
| 347 | 'csv_fields' => false, // I false=disable csv export, true or unset=enable it with auto-detected fieldnames, |
||
| 348 | //or array with name=>label or name=>array('label'=>label,'type'=>type) pairs (type is a eT widget-type) |
||
| 349 | 'row_id' => 'path', |
||
| 350 | 'row_modified' => 'mtime', |
||
| 351 | 'parent_id' => 'dir', |
||
| 352 | 'is_parent' => 'is_dir', |
||
| 353 | 'favorites' => true, |
||
| 354 | 'placeholder_actions' => array('mkdir','paste','file_drop_mail','file_drop_move','file_drop_copy','file_drop_symlink') |
||
| 355 | ); |
||
| 356 | $content['nm']['path'] = static::get_home_dir(); |
||
| 357 | } |
||
| 358 | $content['nm']['actions'] = static::get_actions(); |
||
| 359 | $content['nm']['home_dir'] = static::get_home_dir(); |
||
| 360 | $content['nm']['view'] = $GLOBALS['egw_info']['user']['preferences']['filemanager']['nm_view']; |
||
| 361 | |||
| 362 | if (isset($_GET['msg'])) $msg = $_GET['msg']; |
||
| 363 | |||
| 364 | // Blank favorite set via GET needs special handling for path |
||
| 365 | if (isset($_GET['favorite']) && $_GET['favorite'] == 'blank') |
||
| 366 | { |
||
| 367 | $content['nm']['path'] = static::get_home_dir(); |
||
| 368 | } |
||
| 369 | // switch to projectmanager folders |
||
| 370 | if (isset($_GET['pm_id'])) |
||
| 371 | { |
||
| 372 | $_GET['path'] = '/apps/projectmanager'.((int)$_GET['pm_id'] ? '/'.(int)$_GET['pm_id'] : ''); |
||
| 373 | } |
||
| 374 | if (isset($_GET['path']) && ($path = $_GET['path'])) |
||
| 375 | { |
||
| 376 | switch($path) |
||
| 377 | { |
||
| 378 | case '..': |
||
| 379 | $path = Vfs::dirname($content['nm']['path']); |
||
| 380 | break; |
||
| 381 | case '~': |
||
| 382 | $path = static::get_home_dir(); |
||
| 383 | break; |
||
| 384 | } |
||
| 385 | if ($path && $path[0] == '/' && Vfs::stat($path,true) && Vfs::is_dir($path) && Vfs::check_access($path,Vfs::READABLE)) |
||
|
|
|||
| 386 | { |
||
| 387 | $content['nm']['path'] = $path; |
||
| 388 | } |
||
| 389 | else |
||
| 390 | { |
||
| 391 | $msg .= lang('The requested path %1 is not available.', $path ? Vfs::decodePath($path) : "false"); |
||
| 392 | } |
||
| 393 | // reset lettersearch as it confuses users (they think the dir is empty) |
||
| 394 | $content['nm']['searchletter'] = false; |
||
| 395 | // switch recusive display off |
||
| 396 | if (!$content['nm']['filter']) $content['nm']['filter'] = ''; |
||
| 397 | } |
||
| 398 | } |
||
| 399 | $view = static::get_view(); |
||
| 400 | |||
| 401 | call_user_func($view,$content,$msg); |
||
| 402 | } |
||
| 403 | |||
| 404 | /** |
||
| 405 | * Make the current user (vfs) root |
||
| 406 | * |
||
| 407 | * The user/pw is either the setup config user or a specially configured vfs_root user |
||
| 408 | * |
||
| 409 | * @param string $user setup config user to become root or '' to log off as root |
||
| 410 | * @param string $password setup config password to become root |
||
| 411 | * @param boolean &$is_setup=null on return true if authenticated user is setup config user, false otherwise |
||
| 412 | * @return boolean true is root user given, false otherwise (including logout / empty $user) |
||
| 413 | */ |
||
| 414 | protected function sudo($user='',$password=null,&$is_setup=null) |
||
| 415 | { |
||
| 416 | if (!$user) |
||
| 417 | { |
||
| 418 | $is_root = $is_setup = false; |
||
| 419 | } |
||
| 420 | else |
||
| 421 | { |
||
| 422 | // config user & password |
||
| 423 | $is_setup = Api\Session::user_pw_hash($user,$password) === $GLOBALS['egw_info']['server']['config_hash']; |
||
| 424 | // or vfs root user from setup >> configuration |
||
| 425 | $is_root = $is_setup || $GLOBALS['egw_info']['server']['vfs_root_user'] && |
||
| 426 | in_array($user,preg_split('/, */',$GLOBALS['egw_info']['server']['vfs_root_user'])) && |
||
| 427 | $GLOBALS['egw']->auth->authenticate($user, $password, 'text'); |
||
| 428 | } |
||
| 429 | //error_log(__METHOD__."('$user','$password',$is_setup) user_pw_hash(...)='".Api\Session::user_pw_hash($user,$password)."', config_hash='{$GLOBALS['egw_info']['server']['config_hash']}' --> returning ".array2string($is_root)); |
||
| 430 | Api\Cache::setSession('filemanager', 'is_setup',$is_setup); |
||
| 431 | Api\Cache::setSession('filemanager', 'is_root',Vfs::$is_root = $is_root); |
||
| 432 | return Vfs::$is_root; |
||
| 433 | } |
||
| 434 | |||
| 435 | /** |
||
| 436 | * Filemanager listview |
||
| 437 | * |
||
| 438 | * @param array $content |
||
| 439 | * @param string $msg |
||
| 440 | */ |
||
| 441 | function listview(array $content=null,$msg=null) |
||
| 442 | { |
||
| 443 | $tpl = new Etemplate('filemanager.index'); |
||
| 444 | |||
| 445 | if($msg) Framework::message($msg); |
||
| 446 | |||
| 447 | if (($content['nm']['action'] || $content['nm']['rows']) && (empty($content['button']) || !isset($content['button']))) |
||
| 448 | { |
||
| 449 | if ($content['nm']['action']) |
||
| 450 | { |
||
| 451 | $msg = static::action($content['nm']['action'],$content['nm']['selected'],$content['nm']['path']); |
||
| 452 | if($msg) Framework::message($msg); |
||
| 453 | |||
| 454 | // clean up after action |
||
| 455 | unset($content['nm']['selected']); |
||
| 456 | // reset any occasion where action may be stored, as it may be ressurected out of the helpers by etemplate, which is quite unconvenient in case of action delete |
||
| 457 | if (isset($content['nm']['action'])) unset($content['nm']['action']); |
||
| 458 | if (isset($content['nm']['nm_action'])) unset($content['nm']['nm_action']); |
||
| 459 | if (isset($content['nm_action'])) unset($content['nm_action']); |
||
| 460 | // we dont use ['nm']['rows']['delete'], so unset it, if it is present |
||
| 461 | if (isset($content['nm']['rows']['delete'])) unset($content['nm']['rows']['delete']); |
||
| 462 | } |
||
| 463 | elseif($content['nm']['rows']['delete']) |
||
| 464 | { |
||
| 465 | $msg = static::action('delete',array_keys($content['nm']['rows']['delete']),$content['nm']['path']); |
||
| 466 | if($msg) Framework::message($msg); |
||
| 467 | |||
| 468 | // clean up after action |
||
| 469 | unset($content['nm']['rows']['delete']); |
||
| 470 | // reset any occasion where action may be stored, as we use ['nm']['rows']['delete'] anyhow |
||
| 471 | // we clean this up, as it may be ressurected out of the helpers by etemplate, which is quite unconvenient in case of action delete |
||
| 472 | if (isset($content['nm']['action'])) unset($content['nm']['action']); |
||
| 473 | if (isset($content['nm']['nm_action'])) unset($content['nm']['nm_action']); |
||
| 474 | if (isset($content['nm_action'])) unset($content['nm_action']); |
||
| 475 | if (isset($content['nm']['selected'])) unset($content['nm']['selected']); |
||
| 476 | } |
||
| 477 | unset($content['nm']['rows']); |
||
| 478 | Api\Cache::setSession('filemanager', 'index',$content['nm']); |
||
| 479 | } |
||
| 480 | |||
| 481 | // be tolerant with (in previous versions) not correct urlencoded pathes |
||
| 482 | if ($content['nm']['path'][0] == '/' && !Vfs::stat($content['nm']['path'],true) && Vfs::stat(urldecode($content['nm']['path']))) |
||
| 483 | { |
||
| 484 | $content['nm']['path'] = urldecode($content['nm']['path']); |
||
| 485 | } |
||
| 486 | if ($content['button']) |
||
| 487 | { |
||
| 488 | if ($content['button']) |
||
| 489 | { |
||
| 490 | list($button) = each($content['button']); |
||
| 491 | unset($content['button']); |
||
| 492 | } |
||
| 493 | switch($button) |
||
| 494 | { |
||
| 495 | case 'upload': |
||
| 496 | if (!$content['upload']) |
||
| 497 | { |
||
| 498 | Framework::message(lang('You need to select some files first!'),'error'); |
||
| 499 | break; |
||
| 500 | } |
||
| 501 | $upload_success = $upload_failure = array(); |
||
| 502 | foreach(isset($content['upload'][0]) ? $content['upload'] : array($content['upload']) as $upload) |
||
| 503 | { |
||
| 504 | // encode chars which special meaning in url/vfs (some like / get removed!) |
||
| 505 | $to = Vfs::concat($content['nm']['path'],Vfs::encodePathComponent($upload['name'])); |
||
| 506 | if ($upload && |
||
| 507 | (Vfs::is_writable($content['nm']['path']) || Vfs::is_writable($to)) && |
||
| 508 | copy($upload['tmp_name'],Vfs::PREFIX.$to)) |
||
| 509 | { |
||
| 510 | $upload_success[] = $upload['name']; |
||
| 511 | } |
||
| 512 | else |
||
| 513 | { |
||
| 514 | $upload_failure[] = $upload['name']; |
||
| 515 | } |
||
| 516 | } |
||
| 517 | $content['nm']['msg'] = ''; |
||
| 518 | if ($upload_success) |
||
| 519 | { |
||
| 520 | Framework::message( count($upload_success) == 1 && !$upload_failure ? lang('File successful uploaded.') : |
||
| 521 | lang('%1 successful uploaded.',implode(', ',$upload_success))); |
||
| 522 | } |
||
| 523 | if ($upload_failure) |
||
| 524 | { |
||
| 525 | Framework::message(lang('Error uploading file!')."\n".etemplate::max_upload_size_message(),'error'); |
||
| 526 | } |
||
| 527 | break; |
||
| 528 | } |
||
| 529 | } |
||
| 530 | $readonlys['button[mailpaste]'] = !isset($GLOBALS['egw_info']['user']['apps']['mail']); |
||
| 531 | |||
| 532 | $sel_options['filter'] = array( |
||
| 533 | '' => 'Current directory', |
||
| 534 | '2' => 'Directories sorted in', |
||
| 535 | '3' => 'Show hidden files', |
||
| 536 | '4' => 'All subdirectories', |
||
| 537 | '5' => 'Files from links', |
||
| 538 | '0' => 'Files from subdirectories', |
||
| 539 | ); |
||
| 540 | // sharing has no divAppbox, we need to set popupMainDiv instead, to be able to drop files everywhere |
||
| 541 | if (substr($_SERVER['SCRIPT_FILENAME'], -10) == '/share.php') |
||
| 542 | { |
||
| 543 | $tpl->setElementAttribute('nm[buttons][upload]', 'drop_target', 'popupMainDiv'); |
||
| 544 | } |
||
| 545 | // Set view button to match current settings |
||
| 546 | if($content['nm']['view'] == 'tile') |
||
| 547 | { |
||
| 548 | $tpl->setElementAttribute('nm[button][change_view]','statustext',lang('List view')); |
||
| 549 | $tpl->setElementAttribute('nm[button][change_view]','image','list_row'); |
||
| 550 | } |
||
| 551 | // if initial load is done via GET request (idots template or share.php) |
||
| 552 | // get_rows cant call app.filemanager.set_readonly, so we need to do that here |
||
| 553 | $content['initial_path_readonly'] = !Vfs::is_writable($content['nm']['path']); |
||
| 554 | |||
| 555 | $tpl->exec('filemanager.filemanager_ui.index',$content,$sel_options,$readonlys,array('nm' => $content['nm'])); |
||
| 556 | } |
||
| 557 | |||
| 558 | /** |
||
| 559 | * Get the configured start directory for the current user |
||
| 560 | * |
||
| 561 | * @return string |
||
| 562 | */ |
||
| 563 | static function get_home_dir() |
||
| 564 | { |
||
| 565 | $start = '/home/'.$GLOBALS['egw_info']['user']['account_lid']; |
||
| 566 | |||
| 567 | // check if user specified a valid startpath in his prefs --> use it |
||
| 568 | if (($path = $GLOBALS['egw_info']['user']['preferences']['filemanager']['startfolder']) && |
||
| 569 | $path[0] == '/' && Vfs::is_dir($path) && Vfs::check_access($path, Vfs::READABLE)) |
||
| 570 | { |
||
| 571 | $start = $path; |
||
| 572 | } |
||
| 573 | elseif (!Vfs::is_dir($start) && Vfs::check_access($start, Vfs::READABLE)) |
||
| 574 | { |
||
| 575 | $start = '/'; |
||
| 576 | } |
||
| 577 | return $start; |
||
| 578 | } |
||
| 579 | |||
| 580 | /** |
||
| 581 | * Run a certain action with the selected file |
||
| 582 | * |
||
| 583 | * @param string $action |
||
| 584 | * @param array $selected selected pathes |
||
| 585 | * @param mixed $dir current directory |
||
| 586 | * @param int &$errs=null on return number of errors |
||
| 587 | * @param int &$dirs=null on return number of dirs deleted |
||
| 588 | * @param int &$files=null on return number of files deleted |
||
| 589 | * @return string success or failure message displayed to the user |
||
| 590 | */ |
||
| 591 | static public function action($action,$selected,$dir=null,&$errs=null,&$files=null,&$dirs=null) |
||
| 592 | { |
||
| 593 | if (!count($selected)) |
||
| 594 | { |
||
| 595 | return lang('You need to select some files first!'); |
||
| 596 | } |
||
| 597 | $errs = $dirs = $files = 0; |
||
| 598 | |||
| 599 | switch($action) |
||
| 600 | { |
||
| 601 | |||
| 602 | case 'delete': |
||
| 603 | return static::do_delete($selected,$errs,$files,$dirs); |
||
| 604 | |||
| 605 | case 'mail': |
||
| 606 | case 'copy': |
||
| 607 | foreach($selected as $path) |
||
| 608 | { |
||
| 609 | if (strpos($path, 'mail::') === 0 && $path = substr($path, 6)) |
||
| 610 | { |
||
| 611 | // Support for dropping mail in filemanager - Pass mail back to mail app |
||
| 612 | if(ExecMethod2('mail.mail_ui.vfsSaveMessage', $path, $dir, false)) |
||
| 613 | { |
||
| 614 | ++$files; |
||
| 615 | } |
||
| 616 | else |
||
| 617 | { |
||
| 618 | ++$errs; |
||
| 619 | } |
||
| 620 | } |
||
| 621 | elseif (!Vfs::is_dir($path)) |
||
| 622 | { |
||
| 623 | $to = Vfs::concat($dir,Vfs::basename($path)); |
||
| 624 | if ($path != $to && Vfs::copy($path,$to)) |
||
| 625 | { |
||
| 626 | ++$files; |
||
| 627 | } |
||
| 628 | else |
||
| 629 | { |
||
| 630 | ++$errs; |
||
| 631 | } |
||
| 632 | } |
||
| 633 | else |
||
| 634 | { |
||
| 635 | $len = strlen(dirname($path)); |
||
| 636 | foreach(Vfs::find($path) as $p) |
||
| 637 | { |
||
| 638 | $to = $dir.substr($p,$len); |
||
| 639 | if ($to == $p) // cant copy into itself! |
||
| 640 | { |
||
| 641 | ++$errs; |
||
| 642 | continue; |
||
| 643 | } |
||
| 644 | if (($is_dir = Vfs::is_dir($p)) && Vfs::mkdir($to,null,STREAM_MKDIR_RECURSIVE)) |
||
| 645 | { |
||
| 646 | ++$dirs; |
||
| 647 | } |
||
| 648 | elseif(!$is_dir && Vfs::copy($p,$to)) |
||
| 649 | { |
||
| 650 | ++$files; |
||
| 651 | } |
||
| 652 | else |
||
| 653 | { |
||
| 654 | ++$errs; |
||
| 655 | } |
||
| 656 | } |
||
| 657 | } |
||
| 658 | } |
||
| 659 | if ($errs) |
||
| 660 | { |
||
| 661 | return lang('%1 errors copying (%2 diretories and %3 files copied)!',$errs,$dirs,$files); |
||
| 662 | } |
||
| 663 | return $dirs ? lang('%1 directories and %2 files copied.',$dirs,$files) : lang('%1 files copied.',$files); |
||
| 664 | |||
| 665 | case 'move': |
||
| 666 | foreach($selected as $path) |
||
| 667 | { |
||
| 668 | $to = Vfs::is_dir($dir) || count($selected) > 1 ? Vfs::concat($dir,Vfs::basename($path)) : $dir; |
||
| 669 | if ($path != $to && Vfs::rename($path,$to)) |
||
| 670 | { |
||
| 671 | ++$files; |
||
| 672 | } |
||
| 673 | else |
||
| 674 | { |
||
| 675 | ++$errs; |
||
| 676 | } |
||
| 677 | } |
||
| 678 | if ($errs) |
||
| 679 | { |
||
| 680 | return lang('%1 errors moving (%2 files moved)!',$errs,$files); |
||
| 681 | } |
||
| 682 | return lang('%1 files moved.',$files); |
||
| 683 | |||
| 684 | case 'symlink': // symlink given files to $dir |
||
| 685 | foreach((array)$selected as $target) |
||
| 686 | { |
||
| 687 | $link = Vfs::concat($dir, Vfs::basename($target)); |
||
| 688 | if (!Vfs::stat($dir) || ($ok = Vfs::mkdir($dir,0,true))) |
||
| 689 | { |
||
| 690 | if(!$ok) |
||
| 691 | { |
||
| 692 | $errs++; |
||
| 693 | continue; |
||
| 694 | } |
||
| 695 | } |
||
| 696 | if ($target[0] != '/') $target = Vfs::concat($dir, $target); |
||
| 697 | if (!Vfs::stat($target)) |
||
| 698 | { |
||
| 699 | return lang('Link target %1 not found!', Vfs::decodePath($target)); |
||
| 700 | } |
||
| 701 | if ($target != $link && Vfs::symlink($target, $link)) |
||
| 702 | { |
||
| 703 | ++$files; |
||
| 704 | } |
||
| 705 | else |
||
| 706 | { |
||
| 707 | ++$errs; |
||
| 708 | } |
||
| 709 | } |
||
| 710 | if (count((array)$selected) == 1) |
||
| 711 | { |
||
| 712 | return $files ? lang('Symlink to %1 created.', Vfs::decodePath($target)) : |
||
| 713 | lang('Error creating symlink to target %1!', Vfs::decodePath($target)); |
||
| 714 | } |
||
| 715 | $ret = lang('%1 elements linked.', $files); |
||
| 716 | if ($errs) |
||
| 717 | { |
||
| 718 | $ret = lang('%1 errors linking (%2)!',$errs, $ret); |
||
| 719 | } |
||
| 720 | return $ret;//." Vfs::symlink('$target', '$link')"; |
||
| 721 | |||
| 722 | case 'createdir': |
||
| 723 | $dst = Vfs::concat($dir, is_array($selected) ? $selected[0] : $selected); |
||
| 724 | if (Vfs::mkdir($dst, null, STREAM_MKDIR_RECURSIVE)) |
||
| 725 | { |
||
| 726 | return lang("Directory successfully created."); |
||
| 727 | } |
||
| 728 | return lang("Error while creating directory."); |
||
| 729 | |||
| 730 | case 'saveaszip': |
||
| 731 | Vfs::download_zip($selected); |
||
| 732 | exit; |
||
| 733 | |||
| 734 | default: |
||
| 735 | list($action, $settings) = explode('_', $action, 2); |
||
| 736 | switch($action) |
||
| 737 | { |
||
| 738 | View Code Duplication | case 'document': |
|
| 739 | if (!$settings) $settings = $GLOBALS['egw_info']['user']['preferences']['filemanager']['default_document']; |
||
| 740 | $document_merge = new filemanager_merge(Vfs::decodePath($dir)); |
||
| 741 | $msg = $document_merge->download($settings, $selected, '', $GLOBALS['egw_info']['user']['preferences']['filemanager']['document_dir']); |
||
| 742 | if($msg) return $msg; |
||
| 743 | $errs = count($selected); |
||
| 744 | return false; |
||
| 745 | } |
||
| 746 | } |
||
| 747 | return "Unknown action '$action'!"; |
||
| 748 | } |
||
| 749 | |||
| 750 | /** |
||
| 751 | * Delete selected files and return success or error message |
||
| 752 | * |
||
| 753 | * @param array $selected |
||
| 754 | * @param int &$errs=null on return number of errors |
||
| 755 | * @param int &$dirs=null on return number of dirs deleted |
||
| 756 | * @param int &$files=null on return number of files deleted |
||
| 757 | * @return string |
||
| 758 | */ |
||
| 759 | public static function do_delete(array $selected, &$errs=null, &$dirs=null, &$files=null) |
||
| 760 | { |
||
| 761 | $dirs = $files = $errs = 0; |
||
| 762 | // we first delete all selected links (and files) |
||
| 763 | // feeding the links to dirs to Vfs::find() deletes the content of the dirs, not just the link! |
||
| 764 | foreach($selected as $key => $path) |
||
| 765 | { |
||
| 766 | if (!Vfs::is_dir($path) || Vfs::is_link($path)) |
||
| 767 | { |
||
| 768 | if (Vfs::unlink($path)) |
||
| 769 | { |
||
| 770 | ++$files; |
||
| 771 | } |
||
| 772 | else |
||
| 773 | { |
||
| 774 | ++$errs; |
||
| 775 | } |
||
| 776 | unset($selected[$key]); |
||
| 777 | } |
||
| 778 | } |
||
| 779 | if ($selected) // somethings left to delete |
||
| 780 | { |
||
| 781 | // some precaution to never allow to (recursivly) remove /, /apps or /home |
||
| 782 | foreach((array)$selected as $path) |
||
| 783 | { |
||
| 784 | if (Vfs::isProtectedDir($path)) |
||
| 785 | { |
||
| 786 | $errs++; |
||
| 787 | return lang("Cautiously rejecting to remove folder '%1'!",Vfs::decodePath($path)); |
||
| 788 | } |
||
| 789 | } |
||
| 790 | // now we use find to loop through all files and dirs: (selected only contains dirs now) |
||
| 791 | // - depth=true to get first the files and then the dir containing it |
||
| 792 | // - hidden=true to also return hidden files (eg. Thumbs.db), as we cant delete non-empty dirs |
||
| 793 | // - show-deleted=false to not (finally) deleted versioned files |
||
| 794 | foreach(Vfs::find($selected,array('depth'=>true,'hidden'=>true,'show-deleted'=>false)) as $path) |
||
| 795 | { |
||
| 796 | if (($is_dir = Vfs::is_dir($path) && !Vfs::is_link($path)) && Vfs::rmdir($path,0)) |
||
| 797 | { |
||
| 798 | ++$dirs; |
||
| 799 | } |
||
| 800 | elseif (!$is_dir && Vfs::unlink($path)) |
||
| 801 | { |
||
| 802 | ++$files; |
||
| 803 | } |
||
| 804 | else |
||
| 805 | { |
||
| 806 | ++$errs; |
||
| 807 | } |
||
| 808 | } |
||
| 809 | } |
||
| 810 | if ($errs) |
||
| 811 | { |
||
| 812 | return lang('%1 errors deleteting (%2 directories and %3 files deleted)!',$errs,$dirs,$files); |
||
| 813 | } |
||
| 814 | if ($dirs) |
||
| 815 | { |
||
| 816 | return lang('%1 directories and %2 files deleted.',$dirs,$files); |
||
| 817 | } |
||
| 818 | return $files == 1 ? lang('File deleted.') : lang('%1 files deleted.',$files); |
||
| 819 | } |
||
| 820 | |||
| 821 | /** |
||
| 822 | * Callback to fetch the rows for the nextmatch widget |
||
| 823 | * |
||
| 824 | * @param array $query |
||
| 825 | * @param array &$rows |
||
| 826 | */ |
||
| 827 | function get_rows(&$query, &$rows) |
||
| 828 | { |
||
| 829 | // do NOT store query, if hierarchical data / children are requested |
||
| 830 | View Code Duplication | if (!$query['csv_export']) |
|
| 831 | { |
||
| 832 | Api\Cache::setSession('filemanager', 'index', |
||
| 833 | array_diff_key ($query, array_flip(array('rows','actions','action_links','placeholder_actions')))); |
||
| 834 | } |
||
| 835 | if(!$query['path']) $query['path'] = static::get_home_dir(); |
||
| 836 | |||
| 837 | // Change template to match selected view |
||
| 838 | if($query['view']) |
||
| 839 | { |
||
| 840 | $query['template'] = ($query['view'] == 'row' ? 'filemanager.index.rows' : 'filemanager.tile'); |
||
| 841 | |||
| 842 | // Store as preference but only for index, not home |
||
| 843 | if($query['get_rows'] == 'filemanager.filemanager_ui.get_rows') |
||
| 844 | { |
||
| 845 | $GLOBALS['egw']->preferences->add('filemanager','nm_view',$query['view']); |
||
| 846 | $GLOBALS['egw']->preferences->save_repository(); |
||
| 847 | } |
||
| 848 | } |
||
| 849 | // be tolerant with (in previous versions) not correct urlencoded pathes |
||
| 850 | if (!Vfs::stat($query['path'],true) && Vfs::stat(urldecode($query['path']))) |
||
| 851 | { |
||
| 852 | $query['path'] = urldecode($query['path']); |
||
| 853 | } |
||
| 854 | if (!Vfs::stat($query['path'],true) || !Vfs::is_dir($query['path']) || !Vfs::check_access($query['path'],Vfs::READABLE)) |
||
| 855 | { |
||
| 856 | // only redirect, if it would be to some other location, gives redirect-loop otherwise |
||
| 857 | if ($query['path'] != ($path = static::get_home_dir())) |
||
| 858 | { |
||
| 859 | // we will leave here, since we are not allowed, or the location does not exist. Index must handle that, and give |
||
| 860 | // an appropriate message |
||
| 861 | Egw::redirect_link('/index.php',array('menuaction'=>'filemanager.filemanager_ui.index', |
||
| 862 | 'path' => $path, |
||
| 863 | 'msg' => lang('The requested path %1 is not available.',Vfs::decodePath($query['path'])), |
||
| 864 | 'ajax' => 'true' |
||
| 865 | )); |
||
| 866 | } |
||
| 867 | $rows = array(); |
||
| 868 | return 0; |
||
| 869 | } |
||
| 870 | $rows = $dir_is_writable = array(); |
||
| 871 | if($query['searchletter'] && !empty($query['search'])) |
||
| 872 | { |
||
| 873 | $namefilter = '/^'.$query['searchletter'].'.*'.str_replace(array('\\?','\\*'),array('.{1}','.*'),preg_quote($query['search'])).'/i'; |
||
| 874 | if ($query['searchletter'] == strtolower($query['search'][0])) |
||
| 875 | { |
||
| 876 | $namefilter = '/^('.$query['searchletter'].'.*'.str_replace(array('\\?','\\*'),array('.{1}','.*'),preg_quote($query['search'])).'|'. |
||
| 877 | str_replace(array('\\?','\\*'),array('.{1}','.*'),preg_quote($query['search'])).')/i'; |
||
| 878 | } |
||
| 879 | } |
||
| 880 | elseif ($query['searchletter']) |
||
| 881 | { |
||
| 882 | $namefilter = '/^'.$query['searchletter'].'/i'; |
||
| 883 | } |
||
| 884 | elseif(!empty($query['search'])) |
||
| 885 | { |
||
| 886 | $namefilter = '/'.str_replace(array('\\?','\\*'),array('.{1}','.*'),preg_quote($query['search'])).'/i'; |
||
| 887 | } |
||
| 888 | |||
| 889 | // Re-map so 'No filters' favorite ('') is depth 1 |
||
| 890 | $filter = $query['filter'] === '' ? 1 : $query['filter']; |
||
| 891 | |||
| 892 | $maxdepth = $filter && $filter != 4 ? (int)(boolean)$filter : null; |
||
| 893 | if($filter == 5) $maxdepth = 2; |
||
| 894 | $n = 0; |
||
| 895 | $vfs_options = array( |
||
| 896 | 'mindepth' => 1, |
||
| 897 | 'maxdepth' => $maxdepth, |
||
| 898 | 'dirsontop' => $filter <= 1, |
||
| 899 | 'type' => $filter && $filter != 5 ? ($filter == 4 ? 'd' : null) : ($filter == 5 ? 'F':'f'), |
||
| 900 | 'order' => $query['order'], 'sort' => $query['sort'], |
||
| 901 | 'limit' => (int)$query['num_rows'].','.(int)$query['start'], |
||
| 902 | 'need_mime' => true, |
||
| 903 | 'name_preg' => $namefilter, |
||
| 904 | 'hidden' => $filter == 3, |
||
| 905 | 'follow' => $filter == 5, |
||
| 906 | ); |
||
| 907 | if($query['col_filter']['mime']) |
||
| 908 | { |
||
| 909 | $vfs_options['mime'] = $query['col_filter']['mime']; |
||
| 910 | } |
||
| 911 | foreach(Vfs::find(!empty($query['col_filter']['dir']) ? $query['col_filter']['dir'] : $query['path'],$vfs_options,true) as $path => $row) |
||
| 912 | { |
||
| 913 | //echo $path; _debug_array($row); |
||
| 914 | |||
| 915 | $dir = dirname($path); |
||
| 916 | if (!isset($dir_is_writable[$dir])) |
||
| 917 | { |
||
| 918 | $dir_is_writable[$dir] = Vfs::is_writable($dir); |
||
| 919 | } |
||
| 920 | if (Vfs::is_dir($path)) |
||
| 921 | { |
||
| 922 | if (!isset($dir_is_writable[$path])) |
||
| 923 | { |
||
| 924 | $dir_is_writable[$path] = Vfs::is_writable($path); |
||
| 925 | } |
||
| 926 | |||
| 927 | $row['class'] .= 'isDir '; |
||
| 928 | $row['is_dir'] = 1; |
||
| 929 | } |
||
| 930 | if(!$dir_is_writable[$path]) |
||
| 931 | { |
||
| 932 | $row['class'] .= 'noEdit '; |
||
| 933 | } |
||
| 934 | $row['download_url'] = Vfs::download_url($path); |
||
| 935 | $row['gid'] = -abs($row['gid']); // gid are positive, but we use negagive account_id for groups internal |
||
| 936 | |||
| 937 | $rows[++$n] = $row; |
||
| 938 | $path2n[$path] = $n; |
||
| 939 | } |
||
| 940 | // query comments and cf's for the displayed rows |
||
| 941 | $cols_to_show = explode(',',$GLOBALS['egw_info']['user']['preferences']['filemanager']['nextmatch-filemanager.index.rows']); |
||
| 942 | |||
| 943 | // Always include comment in tiles |
||
| 944 | if($query['view'] == 'tile') |
||
| 945 | { |
||
| 946 | $cols_to_show[] = 'comment'; |
||
| 947 | } |
||
| 948 | $all_cfs = in_array('customfields',$cols_to_show) && $cols_to_show[count($cols_to_show)-1][0] != '#'; |
||
| 949 | if ($path2n && (in_array('comment',$cols_to_show) || in_array('customfields',$cols_to_show)) && |
||
| 950 | ($path2props = Vfs::propfind(array_keys($path2n)))) |
||
| 951 | { |
||
| 952 | foreach($path2props as $path => $props) |
||
| 953 | { |
||
| 954 | unset($row); // fixes a weird problem with php5.1, does NOT happen with php5.2 |
||
| 955 | $row =& $rows[$path2n[$path]]; |
||
| 956 | if ( !is_array($props) ) continue; |
||
| 957 | foreach($props as $prop) |
||
| 958 | { |
||
| 959 | if (!$all_cfs && $prop['name'][0] == '#' && !in_array($prop['name'],$cols_to_show)) continue; |
||
| 960 | $row[$prop['name']] = strlen($prop['val']) < 64 ? $prop['val'] : substr($prop['val'],0,64).' ...'; |
||
| 961 | } |
||
| 962 | } |
||
| 963 | } |
||
| 964 | // tell client-side if directory is writeable or not |
||
| 965 | $response = Api\Json\Response::get(); |
||
| 966 | $response->call('app.filemanager.set_readonly', $query['path'], !Vfs::is_writable($query['path'])); |
||
| 967 | |||
| 968 | //_debug_array($readonlys); |
||
| 969 | if ($GLOBALS['egw_info']['flags']['currentapp'] == 'projectmanager') |
||
| 970 | { |
||
| 971 | // we need our app.css file |
||
| 972 | View Code Duplication | if (!file_exists(EGW_SERVER_ROOT.($css_file='/filemanager/templates/'.$GLOBALS['egw_info']['server']['template_set'].'/app.css'))) |
|
| 973 | { |
||
| 974 | $css_file = '/filemanager/templates/default/app.css'; |
||
| 975 | } |
||
| 976 | $GLOBALS['egw_info']['flags']['css'] .= "\n\t\t</style>\n\t\t".'<link href="'.$GLOBALS['egw_info']['server']['webserver_url']. |
||
| 977 | $css_file.'?'.filemtime(EGW_SERVER_ROOT.$css_file).'" type="text/css" rel="StyleSheet" />'."\n\t\t<style>\n\t\t\t"; |
||
| 978 | } |
||
| 979 | return Vfs::$find_total; |
||
| 980 | } |
||
| 981 | |||
| 982 | /** |
||
| 983 | * Preferences of a file/directory |
||
| 984 | * |
||
| 985 | * @param array $content |
||
| 986 | * @param string $msg |
||
| 987 | */ |
||
| 988 | function file(array $content=null,$msg='') |
||
| 989 | { |
||
| 990 | $tpl = new Etemplate('filemanager.file'); |
||
| 991 | |||
| 992 | if (!is_array($content)) |
||
| 993 | { |
||
| 994 | if (isset($_GET['msg'])) |
||
| 995 | { |
||
| 996 | $msg .= $_GET['msg']; |
||
| 997 | } |
||
| 998 | if (!($path = str_replace(array('#','?'),array('%23','%3F'),$_GET['path'])) || // ?, # need to stay encoded! |
||
| 999 | // actions enclose pathes containing comma with " |
||
| 1000 | ($path[0] == '"' && substr($path,-1) == '"' && !($path = substr(str_replace('""','"',$path),1,-1))) || |
||
| 1001 | !($stat = Vfs::lstat($path))) |
||
| 1002 | { |
||
| 1003 | $msg .= lang('File or directory not found!')." path='$path', stat=".array2string($stat); |
||
| 1004 | } |
||
| 1005 | else |
||
| 1006 | { |
||
| 1007 | $content = $stat; |
||
| 1008 | $content['name'] = $content['itempicker_merge']['name'] = Vfs::basename($path); |
||
| 1009 | $content['dir'] = $content['itempicker_merge']['dir'] = ($dir = Vfs::dirname($path)) ? Vfs::decodePath($dir) : ''; |
||
| 1010 | $content['path'] = $path; |
||
| 1011 | $content['hsize'] = Vfs::hsize($stat['size']); |
||
| 1012 | $content['mime'] = Vfs::mime_content_type($path); |
||
| 1013 | $content['gid'] *= -1; // our widgets use negative gid's |
||
| 1014 | View Code Duplication | if (($props = Vfs::propfind($path))) |
|
| 1015 | { |
||
| 1016 | foreach($props as $prop) |
||
| 1017 | { |
||
| 1018 | $content[$prop['name']] = $prop['val']; |
||
| 1019 | } |
||
| 1020 | } |
||
| 1021 | if (($content['is_link'] = Vfs::is_link($path))) |
||
| 1022 | { |
||
| 1023 | $content['symlink'] = Vfs::readlink($path); |
||
| 1024 | } |
||
| 1025 | } |
||
| 1026 | $content['tabs'] = $_GET['tabs']; |
||
| 1027 | if (!($content['is_dir'] = Vfs::is_dir($path) && !Vfs::is_link($path))) |
||
| 1028 | { |
||
| 1029 | $content['perms']['executable'] = (int)!!($content['mode'] & 0111); |
||
| 1030 | $mask = 6; |
||
| 1031 | if (preg_match('/^text/',$content['mime']) && $content['size'] < 100000) |
||
| 1032 | { |
||
| 1033 | $content['text_content'] = file_get_contents(Vfs::PREFIX.$path); |
||
| 1034 | } |
||
| 1035 | } |
||
| 1036 | else |
||
| 1037 | { |
||
| 1038 | //currently not implemented in backend $content['perms']['sticky'] = (int)!!($content['mode'] & 0x201); |
||
| 1039 | $mask = 7; |
||
| 1040 | } |
||
| 1041 | foreach(array('owner' => 6,'group' => 3,'other' => 0) as $name => $shift) |
||
| 1042 | { |
||
| 1043 | $content['perms'][$name] = ($content['mode'] >> $shift) & $mask; |
||
| 1044 | } |
||
| 1045 | $content['is_owner'] = Vfs::has_owner_rights($path,$content); |
||
| 1046 | } |
||
| 1047 | else |
||
| 1048 | { |
||
| 1049 | //_debug_array($content); |
||
| 1050 | $path =& $content['path']; |
||
| 1051 | |||
| 1052 | list($button) = @each($content['button']); unset($content['button']); |
||
| 1053 | if(!$button && $content['sudo']) |
||
| 1054 | { |
||
| 1055 | // Button to stop sudo is not in button namespace |
||
| 1056 | $button = 'sudo'; |
||
| 1057 | unset($content['sudo']); |
||
| 1058 | } |
||
| 1059 | // need to check 'setup' button (submit button in sudo popup), as some browsers (eg. chrome) also fill the hidden field |
||
| 1060 | if ($button == 'sudo' && Vfs::$is_root || $button == 'setup' && $content['sudo']['user']) |
||
| 1061 | { |
||
| 1062 | $msg = $this->sudo($button == 'setup' ? $content['sudo']['user'] : '',$content['sudo']['passwd']) ? |
||
| 1063 | lang('Root access granted.') : ($button == 'setup' && $content['sudo']['user'] ? |
||
| 1064 | lang('Wrong username or password!') : lang('Root access stopped.')); |
||
| 1065 | unset($content['sudo']); |
||
| 1066 | $content['is_owner'] = Vfs::has_owner_rights($path); |
||
| 1067 | } |
||
| 1068 | if (in_array($button,array('save','apply'))) |
||
| 1069 | { |
||
| 1070 | $props = array(); |
||
| 1071 | $perm_changed = $perm_failed = 0; |
||
| 1072 | foreach($content['old'] as $name => $old_value) |
||
| 1073 | { |
||
| 1074 | if (isset($content[$name]) && ($old_value != $content[$name] || |
||
| 1075 | // do not check for modification, if modify_subs is checked! |
||
| 1076 | $content['modify_subs'] && in_array($name,array('uid','gid','perms'))) && |
||
| 1077 | ($name != 'uid' || Vfs::$is_root)) |
||
| 1078 | { |
||
| 1079 | if ($name == 'name') |
||
| 1080 | { |
||
| 1081 | if (!($dir = Vfs::dirname($path))) |
||
| 1082 | { |
||
| 1083 | $msg .= lang('File or directory not found!')." Vfs::dirname('$path')===false"; |
||
| 1084 | if ($button == 'save') $button = 'apply'; |
||
| 1085 | continue; |
||
| 1086 | } |
||
| 1087 | $to = Vfs::concat($dir, $content['name']); |
||
| 1088 | if (file_exists(Vfs::PREFIX.$to) && $content['confirm_overwrite'] !== $to) |
||
| 1089 | { |
||
| 1090 | $tpl->set_validation_error('name',lang("There's already a file with that name!").'<br />'. |
||
| 1091 | lang('To overwrite the existing file store again.',lang($button))); |
||
| 1092 | $content['confirm_overwrite'] = $to; |
||
| 1093 | if ($button == 'save') $button = 'apply'; |
||
| 1094 | continue; |
||
| 1095 | } |
||
| 1096 | if (Vfs::rename($path,$to)) |
||
| 1097 | { |
||
| 1098 | $msg .= lang('Renamed %1 to %2.',Vfs::decodePath(basename($path)),Vfs::decodePath(basename($to))).' '; |
||
| 1099 | $content['old']['name'] = $content[$name]; |
||
| 1100 | $path = $to; |
||
| 1101 | $content['mime'] = Api\MimeMagic::filename2mime($path); // recheck mime type |
||
| 1102 | $refresh_path = Vfs::dirname($path); // for renames, we have to refresh the parent |
||
| 1103 | } |
||
| 1104 | else |
||
| 1105 | { |
||
| 1106 | $msg .= lang('Rename of %1 to %2 failed!',Vfs::decodePath(basename($path)),Vfs::decodePath(basename($to))).' '; |
||
| 1107 | if (Vfs::deny_script($to)) |
||
| 1108 | { |
||
| 1109 | $msg .= lang('You are NOT allowed to upload a script!').' '; |
||
| 1110 | } |
||
| 1111 | } |
||
| 1112 | } |
||
| 1113 | elseif ($name[0] == '#' || $name == 'comment') |
||
| 1114 | { |
||
| 1115 | $props[] = array('name' => $name, 'val' => $content[$name] ? $content[$name] : null); |
||
| 1116 | } |
||
| 1117 | elseif ($name == 'mergeapp') |
||
| 1118 | { |
||
| 1119 | $mergeprop = array( |
||
| 1120 | array( |
||
| 1121 | 'ns' => static::$merge_prop_namespace, |
||
| 1122 | 'name' => 'mergeapp', |
||
| 1123 | 'val' => (!empty($content[$name]) ? $content[$name] : null), |
||
| 1124 | ), |
||
| 1125 | ); |
||
| 1126 | View Code Duplication | if (Vfs::proppatch($path,$mergeprop)) |
|
| 1127 | { |
||
| 1128 | $content['old'][$name] = $content[$name]; |
||
| 1129 | $msg .= lang('Setting for document merge saved.'); |
||
| 1130 | } |
||
| 1131 | else |
||
| 1132 | { |
||
| 1133 | $msg .= lang('Saving setting for document merge failed!'); |
||
| 1134 | } |
||
| 1135 | } |
||
| 1136 | else |
||
| 1137 | { |
||
| 1138 | static $name2cmd = array('uid' => 'chown','gid' => 'chgrp','perms' => 'chmod'); |
||
| 1139 | $cmd = array('EGroupware\\Api\\Vfs',$name2cmd[$name]); |
||
| 1140 | $value = $name == 'perms' ? static::perms2mode($content['perms']) : $content[$name]; |
||
| 1141 | if ($content['modify_subs']) |
||
| 1142 | { |
||
| 1143 | if ($name == 'perms') |
||
| 1144 | { |
||
| 1145 | $changed = Vfs::find($path,array('type'=>'d'),$cmd,array($value)); |
||
| 1146 | $changed += Vfs::find($path,array('type'=>'f'),$cmd,array($value & 0666)); // no execute for files |
||
| 1147 | } |
||
| 1148 | else |
||
| 1149 | { |
||
| 1150 | $changed = Vfs::find($path,null,$cmd,array($value)); |
||
| 1151 | } |
||
| 1152 | $ok = $failed = 0; |
||
| 1153 | foreach($changed as &$r) |
||
| 1154 | { |
||
| 1155 | if ($r) |
||
| 1156 | { |
||
| 1157 | ++$ok; |
||
| 1158 | } |
||
| 1159 | else |
||
| 1160 | { |
||
| 1161 | ++$failed; |
||
| 1162 | } |
||
| 1163 | } |
||
| 1164 | if ($ok && !$failed) |
||
| 1165 | { |
||
| 1166 | if(!$perm_changed++) $msg .= lang('Permissions of %1 changed.',$path.' '.lang('and all it\'s childeren')); |
||
| 1167 | $content['old'][$name] = $content[$name]; |
||
| 1168 | } |
||
| 1169 | elseif($failed) |
||
| 1170 | { |
||
| 1171 | if(!$perm_failed++) $msg .= lang('Failed to change permissions of %1!',$path.lang('and all it\'s childeren'). |
||
| 1172 | ($ok ? ' ('.lang('%1 failed, %2 succeded',$failed,$ok).')' : '')); |
||
| 1173 | } |
||
| 1174 | } |
||
| 1175 | elseif (call_user_func_array($cmd,array($path,$value))) |
||
| 1176 | { |
||
| 1177 | $msg .= lang('Permissions of %1 changed.',$path); |
||
| 1178 | $content['old'][$name] = $content[$name]; |
||
| 1179 | } |
||
| 1180 | else |
||
| 1181 | { |
||
| 1182 | $msg .= lang('Failed to change permissions of %1!',$path); |
||
| 1183 | } |
||
| 1184 | } |
||
| 1185 | } |
||
| 1186 | } |
||
| 1187 | if ($props) |
||
| 1188 | { |
||
| 1189 | View Code Duplication | if (Vfs::proppatch($path,$props)) |
|
| 1190 | { |
||
| 1191 | foreach($props as $prop) |
||
| 1192 | { |
||
| 1193 | $content['old'][$prop['name']] = $prop['val']; |
||
| 1194 | } |
||
| 1195 | $msg .= lang('Properties saved.'); |
||
| 1196 | } |
||
| 1197 | else |
||
| 1198 | { |
||
| 1199 | $msg .= lang('Saving properties failed!'); |
||
| 1200 | } |
||
| 1201 | } |
||
| 1202 | } |
||
| 1203 | elseif ($content['eacl'] && $content['is_owner']) |
||
| 1204 | { |
||
| 1205 | if ($content['eacl']['delete']) |
||
| 1206 | { |
||
| 1207 | list($ino_owner) = each($content['eacl']['delete']); |
||
| 1208 | list(, $owner) = explode('-',$ino_owner,2); // $owner is a group and starts with a minus! |
||
| 1209 | $msg .= Vfs::eacl($path,null,$owner) ? lang('ACL deleted.') : lang('Error deleting the ACL entry!'); |
||
| 1210 | } |
||
| 1211 | elseif ($button == 'eacl') |
||
| 1212 | { |
||
| 1213 | if (!$content['eacl_owner']) |
||
| 1214 | { |
||
| 1215 | $msg .= lang('You need to select an owner!'); |
||
| 1216 | } |
||
| 1217 | else |
||
| 1218 | { |
||
| 1219 | $msg .= Vfs::eacl($path,$content['eacl']['rights'],$content['eacl_owner']) ? |
||
| 1220 | lang('ACL added.') : lang('Error adding the ACL!'); |
||
| 1221 | } |
||
| 1222 | } |
||
| 1223 | } |
||
| 1224 | Framework::refresh_opener($msg, 'filemanager', $refresh_path ? $refresh_path : $path, 'edit', null, '&path=[^&]*'); |
||
| 1225 | if ($button == 'save') Framework::window_close(); |
||
| 1226 | } |
||
| 1227 | if ($content['is_link'] && !Vfs::stat($path)) |
||
| 1228 | { |
||
| 1229 | $msg .= ($msg ? "\n" : '').lang('Link target %1 not found!',$content['symlink']); |
||
| 1230 | } |
||
| 1231 | $content['link'] = Egw::link(Vfs::download_url($path)); |
||
| 1232 | $content['icon'] = Vfs::mime_icon($content['mime']); |
||
| 1233 | $content['msg'] = $msg; |
||
| 1234 | |||
| 1235 | if (($readonlys['uid'] = !Vfs::$is_root) && !$content['uid']) $content['ro_uid_root'] = 'root'; |
||
| 1236 | // only owner can change group & perms |
||
| 1237 | if (($readonlys['gid'] = !$content['is_owner'] || |
||
| 1238 | Vfs::parse_url(Vfs::resolve_url($content['path']),PHP_URL_SCHEME) == 'oldvfs') ||// no uid, gid or perms in oldvfs |
||
| 1239 | !Vfs::is_writable($path)) |
||
| 1240 | { |
||
| 1241 | if (!$content['gid']) $content['ro_gid_root'] = 'root'; |
||
| 1242 | foreach($content['perms'] as $name => $value) |
||
| 1243 | { |
||
| 1244 | $readonlys['perms['.$name.']'] = true; |
||
| 1245 | } |
||
| 1246 | } |
||
| 1247 | $readonlys['gid'] = $readonlys['gid'] || !Vfs::is_writable($path); |
||
| 1248 | $readonlys['name'] = $path == '/' || !($dir = Vfs::dirname($path)) || !Vfs::is_writable($dir); |
||
| 1249 | $readonlys['comment'] = !Vfs::is_writable($path); |
||
| 1250 | $readonlys['tabs']['filemanager.file.preview'] = $readonlys['tabs']['filemanager.file.perms'] = $content['is_link']; |
||
| 1251 | |||
| 1252 | // if neither owner nor is writable --> disable save&apply |
||
| 1253 | $readonlys['button[save]'] = $readonlys['button[apply]'] = !$content['is_owner'] && !Vfs::is_writable($path); |
||
| 1254 | |||
| 1255 | if (!($cfs = Api\Storage\Customfields::get('filemanager'))) |
||
| 1256 | { |
||
| 1257 | $readonlys['tabs']['custom'] = true; |
||
| 1258 | } |
||
| 1259 | elseif (!Vfs::is_writable($path)) |
||
| 1260 | { |
||
| 1261 | foreach($cfs as $name => $data) |
||
| 1262 | { |
||
| 1263 | $readonlys['#'.$name] = true; |
||
| 1264 | } |
||
| 1265 | } |
||
| 1266 | $readonlys['tabs']['filemanager.file.eacl'] = true; // eacl off by default |
||
| 1267 | if ($content['is_dir']) |
||
| 1268 | { |
||
| 1269 | $readonlys['tabs']['filemanager.file.preview'] = true; // no preview tab for dirs |
||
| 1270 | $sel_options['rights']=$sel_options['owner']=$sel_options['group']=$sel_options['other'] = array( |
||
| 1271 | 7 => lang('Display and modification of content'), |
||
| 1272 | 5 => lang('Display of content'), |
||
| 1273 | 0 => lang('No access'), |
||
| 1274 | ); |
||
| 1275 | if(($content['eacl'] = Vfs::get_eacl($content['path'])) !== false) // backend supports eacl |
||
| 1276 | { |
||
| 1277 | unset($readonlys['tabs']['filemanager.file.eacl']); // --> switch the tab on again |
||
| 1278 | foreach($content['eacl'] as &$eacl) |
||
| 1279 | { |
||
| 1280 | $eacl['path'] = rtrim(Vfs::parse_url($eacl['path'],PHP_URL_PATH),'/'); |
||
| 1281 | $readonlys['delete['.$eacl['ino'].'-'.$eacl['owner'].']'] = $eacl['ino'] != $content['ino'] || |
||
| 1282 | $eacl['path'] != $content['path'] || !$content['is_owner']; |
||
| 1283 | } |
||
| 1284 | array_unshift($content['eacl'],false); // make the keys start with 1, not 0 |
||
| 1285 | $content['eacl']['owner'] = 0; |
||
| 1286 | $content['eacl']['rights'] = 5; |
||
| 1287 | } |
||
| 1288 | } |
||
| 1289 | else |
||
| 1290 | { |
||
| 1291 | $sel_options['owner']=$sel_options['group']=$sel_options['other'] = array( |
||
| 1292 | 6 => lang('Read & write access'), |
||
| 1293 | 4 => lang('Read access only'), |
||
| 1294 | 0 => lang('No access'), |
||
| 1295 | ); |
||
| 1296 | } |
||
| 1297 | |||
| 1298 | // mergeapp |
||
| 1299 | $content['mergeapp'] = static::get_mergeapp($path, 'self'); |
||
| 1300 | $content['mergeapp_parent'] = static::get_mergeapp($path, 'parents'); |
||
| 1301 | if(!empty($content['mergeapp'])) |
||
| 1302 | { |
||
| 1303 | $content['mergeapp_effective'] = $content['mergeapp']; |
||
| 1304 | } |
||
| 1305 | elseif(!empty($content['mergeapp_parent'])) |
||
| 1306 | { |
||
| 1307 | $content['mergeapp_effective'] = $content['mergeapp_parent']; |
||
| 1308 | } |
||
| 1309 | else |
||
| 1310 | { |
||
| 1311 | $content['mergeapp_effective'] = null; |
||
| 1312 | } |
||
| 1313 | // mergeapp select options |
||
| 1314 | $mergeapp_list = Link::app_list('merge'); |
||
| 1315 | unset($mergeapp_list[$GLOBALS['egw_info']['flags']['currentapp']]); // exclude filemanager from list |
||
| 1316 | $mergeapp_empty = !empty($content['mergeapp_parent']) |
||
| 1317 | ? $mergeapp_list[$content['mergeapp_parent']] . ' (parent setting)' : ''; |
||
| 1318 | $sel_options['mergeapp'] = array('' => $mergeapp_empty); |
||
| 1319 | $sel_options['mergeapp'] = $sel_options['mergeapp'] + $mergeapp_list; |
||
| 1320 | // mergeapp other gui options |
||
| 1321 | $content['mergeapp_itempicker_disabled'] = $content['is_dir'] || empty($content['mergeapp_effective']); |
||
| 1322 | |||
| 1323 | $preserve = $content; |
||
| 1324 | if (!isset($preserve['old'])) |
||
| 1325 | { |
||
| 1326 | $preserve['old'] = array( |
||
| 1327 | 'perms' => $content['perms'], |
||
| 1328 | 'name' => $content['name'], |
||
| 1329 | 'uid' => $content['uid'], |
||
| 1330 | 'gid' => $content['gid'], |
||
| 1331 | 'comment' => (string)$content['comment'], |
||
| 1332 | 'mergeapp' => $content['mergeapp'] |
||
| 1333 | ); |
||
| 1334 | if ($cfs) foreach($cfs as $name => $data) |
||
| 1335 | { |
||
| 1336 | $preserve['old']['#'.$name] = (string)$content['#'.$name]; |
||
| 1337 | } |
||
| 1338 | } |
||
| 1339 | if (Vfs::$is_root) |
||
| 1340 | { |
||
| 1341 | $tpl->setElementAttribute('sudouser', 'label', 'Logout'); |
||
| 1342 | $tpl->setElementAttribute('sudouser', 'help','Log out as superuser'); |
||
| 1343 | // Need a more complex submit because button type is buttononly, which doesn't submit |
||
| 1344 | $tpl->setElementAttribute('sudouser', 'onclick','app.filemanager.set_sudoButton(widget,"login")'); |
||
| 1345 | |||
| 1346 | } |
||
| 1347 | elseif ($button == 'sudo') |
||
| 1348 | { |
||
| 1349 | $tpl->setElementAttribute('sudouser', 'label', 'Superuser'); |
||
| 1350 | $tpl->setElementAttribute('sudouser', 'help','Enter setup user and password to get root rights'); |
||
| 1351 | $tpl->setElementAttribute('sudouser', 'onclick','app.filemanager.set_sudoButton(widget,"logout")'); |
||
| 1352 | } |
||
| 1353 | else if (self::is_anonymous($GLOBALS['egw_info']['user']['account_id'])) |
||
| 1354 | { |
||
| 1355 | // Just hide sudo for anonymous users |
||
| 1356 | $readonlys['sudouser'] = true; |
||
| 1357 | } |
||
| 1358 | if (($extra_tabs = Vfs::getExtraInfo($path,$content))) |
||
| 1359 | { |
||
| 1360 | // add to existing tabs in template |
||
| 1361 | $tpl->setElementAttribute('tabs', 'add_tabs', true); |
||
| 1362 | |||
| 1363 | $tabs =& $tpl->getElementAttribute('tabs','tabs'); |
||
| 1364 | if (true) $tabs = array(); |
||
| 1365 | |||
| 1366 | foreach(isset($extra_tabs[0]) ? $extra_tabs : array($extra_tabs) as $extra_tab) |
||
| 1367 | { |
||
| 1368 | $tabs[] = array( |
||
| 1369 | 'label' => $extra_tab['label'], |
||
| 1370 | 'template' => $extra_tab['name'] |
||
| 1371 | ); |
||
| 1372 | View Code Duplication | if ($extra_tab['data'] && is_array($extra_tab['data'])) |
|
| 1373 | { |
||
| 1374 | $content = array_merge($content, $extra_tab['data']); |
||
| 1375 | } |
||
| 1376 | View Code Duplication | if ($extra_tab['preserve'] && is_array($extra_tab['preserve'])) |
|
| 1377 | { |
||
| 1378 | $preserve = array_merge($preserve, $extra_tab['preserve']); |
||
| 1379 | } |
||
| 1380 | View Code Duplication | if ($extra_tab['readonlys'] && is_array($extra_tab['readonlys'])) |
|
| 1381 | { |
||
| 1382 | $readonlys = array_merge($readonlys, $extra_tab['readonlys']); |
||
| 1383 | } |
||
| 1384 | } |
||
| 1385 | } |
||
| 1386 | Framework::window_focus(); |
||
| 1387 | $GLOBALS['egw_info']['flags']['app_header'] = lang('Preferences').' '.Vfs::decodePath($path); |
||
| 1388 | |||
| 1389 | $tpl->exec('filemanager.filemanager_ui.file',$content,$sel_options,$readonlys,$preserve,2); |
||
| 1390 | } |
||
| 1391 | |||
| 1392 | /** |
||
| 1393 | * Check if the user is anonymous user |
||
| 1394 | * @param integer $account_id |
||
| 1395 | */ |
||
| 1396 | protected static function is_anonymous($account_id) |
||
| 1397 | { |
||
| 1398 | $acl = new Api\Acl($account_id); |
||
| 1399 | $acl->read_repository(); |
||
| 1400 | return $acl->check('anonymous', 1, 'phpgwapi'); |
||
| 1401 | } |
||
| 1402 | |||
| 1403 | /** |
||
| 1404 | * Remove some more dangerous actions |
||
| 1405 | * @param Array $actions |
||
| 1406 | */ |
||
| 1407 | protected static function restrict_anonymous_actions(&$actions) |
||
| 1408 | { |
||
| 1409 | $remove = array( |
||
| 1410 | 'delete' |
||
| 1411 | ); |
||
| 1412 | foreach($remove as $key) |
||
| 1413 | { |
||
| 1414 | unset($actions[$key]); |
||
| 1415 | } |
||
| 1416 | } |
||
| 1417 | |||
| 1418 | /** |
||
| 1419 | * Run given action on given path(es) and return array/object with values for keys 'msg', 'errs', 'dirs', 'files' |
||
| 1420 | * |
||
| 1421 | * @param string $action eg. 'delete', ... |
||
| 1422 | * @param array $selected selected path(s) |
||
| 1423 | * @param string $dir=null current directory |
||
| 1424 | * @see static::action() |
||
| 1425 | */ |
||
| 1426 | public static function ajax_action($action, $selected, $dir=null, $props=null) |
||
| 1427 | { |
||
| 1428 | // do we have root rights, need to run here too, as method is static and therefore does NOT run __construct |
||
| 1429 | if (Api\Cache::getSession('filemanager', 'is_root')) |
||
| 1430 | { |
||
| 1431 | Vfs::$is_root = true; |
||
| 1432 | } |
||
| 1433 | $response = Api\Json\Response::get(); |
||
| 1434 | |||
| 1435 | $arr = array( |
||
| 1436 | 'msg' => '', |
||
| 1437 | 'action' => $action, |
||
| 1438 | 'errs' => 0, |
||
| 1439 | 'dirs' => 0, |
||
| 1440 | 'files' => 0, |
||
| 1441 | ); |
||
| 1442 | |||
| 1443 | if (!isset($dir)) $dir = array_pop($selected); |
||
| 1444 | |||
| 1445 | switch($action) |
||
| 1446 | { |
||
| 1447 | case 'upload': |
||
| 1448 | $script_error = 0; |
||
| 1449 | foreach($selected as $tmp_name => &$data) |
||
| 1450 | { |
||
| 1451 | $path = Vfs::concat($dir, Vfs::encodePathComponent($data['name'])); |
||
| 1452 | |||
| 1453 | if(Vfs::deny_script($path)) |
||
| 1454 | { |
||
| 1455 | View Code Duplication | if (!isset($script_error)) |
|
| 1456 | { |
||
| 1457 | $arr['msg'] .= ($arr['msg'] ? "\n" : '').lang('You are NOT allowed to upload a script!'); |
||
| 1458 | } |
||
| 1459 | ++$script_error; |
||
| 1460 | ++$arr['errs']; |
||
| 1461 | unset($selected[$tmp_name]); |
||
| 1462 | } |
||
| 1463 | elseif (Vfs::is_dir($path)) |
||
| 1464 | { |
||
| 1465 | $data['confirm'] = 'is_dir'; |
||
| 1466 | } |
||
| 1467 | elseif (!$data['confirmed'] && Vfs::stat($path)) |
||
| 1468 | { |
||
| 1469 | $data['confirm'] = true; |
||
| 1470 | } |
||
| 1471 | else |
||
| 1472 | { |
||
| 1473 | if (is_dir($GLOBALS['egw_info']['server']['temp_dir']) && is_writable($GLOBALS['egw_info']['server']['temp_dir'])) |
||
| 1474 | { |
||
| 1475 | $tmp_path = $GLOBALS['egw_info']['server']['temp_dir'] . '/' . basename($tmp_name); |
||
| 1476 | } |
||
| 1477 | else |
||
| 1478 | { |
||
| 1479 | $tmp_path = ini_get('upload_tmp_dir').'/'.basename($tmp_name); |
||
| 1480 | } |
||
| 1481 | |||
| 1482 | if (Vfs::copy_uploaded($tmp_path, $path, $props, false)) |
||
| 1483 | { |
||
| 1484 | ++$arr['files']; |
||
| 1485 | $uploaded[] = $data['name']; |
||
| 1486 | } |
||
| 1487 | else |
||
| 1488 | { |
||
| 1489 | ++$arr['errs']; |
||
| 1490 | } |
||
| 1491 | } |
||
| 1492 | } |
||
| 1493 | View Code Duplication | if ($arr['errs'] > $script_error) |
|
| 1494 | { |
||
| 1495 | $arr['msg'] .= ($arr['msg'] ? "\n" : '').lang('Error uploading file!'); |
||
| 1496 | } |
||
| 1497 | if ($arr['files']) |
||
| 1498 | { |
||
| 1499 | $arr['msg'] .= ($arr['msg'] ? "\n" : '').lang('%1 successful uploaded.', implode(', ', $uploaded)); |
||
| 1500 | } |
||
| 1501 | $arr['uploaded'] = $selected; |
||
| 1502 | $arr['path'] = $dir; |
||
| 1503 | $arr['props'] = $props; |
||
| 1504 | break; |
||
| 1505 | |||
| 1506 | case 'sharelink': |
||
| 1507 | $share = Vfs\Sharing::create($selected, Vfs\Sharing::READONLY, basename($selected), array() ); |
||
| 1508 | $arr["share_link"] = $link = Vfs\Sharing::share2link($share); |
||
| 1509 | $arr["template"] = Api\Etemplate\Widget\Template::rel2url('/filemanager/templates/default/share_dialog.xet'); |
||
| 1510 | break; |
||
| 1511 | |||
| 1512 | // Upload, then link |
||
| 1513 | case 'link': |
||
| 1514 | // First upload |
||
| 1515 | $arr = static::ajax_action('upload', $selected, $dir, $props); |
||
| 1516 | $app_dir = Link::vfs_path($props['entry']['app'],$props['entry']['id'],'',true); |
||
| 1517 | |||
| 1518 | foreach($arr['uploaded'] as $file) |
||
| 1519 | { |
||
| 1520 | $target=Vfs::concat($dir,Vfs::encodePathComponent($file['name'])); |
||
| 1521 | if (Vfs::file_exists($target) && $app_dir) |
||
| 1522 | { |
||
| 1523 | if (!Vfs::file_exists($app_dir)) Vfs::mkdir($app_dir); |
||
| 1524 | error_log("Symlinking $target to $app_dir"); |
||
| 1525 | Vfs::symlink($target, Vfs::concat($app_dir,Vfs::encodePathComponent($file['name']))); |
||
| 1526 | } |
||
| 1527 | } |
||
| 1528 | // Must return to avoid adding to $response again |
||
| 1529 | return; |
||
| 1530 | |||
| 1531 | default: |
||
| 1532 | $arr['msg'] = static::action($action, $selected, $dir, $arr['errs'], $arr['dirs'], $arr['files']); |
||
| 1533 | } |
||
| 1534 | $response->data($arr); |
||
| 1535 | //error_log(__METHOD__."('$action',".array2string($selected).') returning '.array2string($arr)); |
||
| 1536 | return $arr; |
||
| 1537 | } |
||
| 1538 | |||
| 1539 | /** |
||
| 1540 | * Convert perms array back to integer mode |
||
| 1541 | * |
||
| 1542 | * @param array $perms with keys owner, group, other, executable, sticky |
||
| 1543 | * @return int |
||
| 1544 | */ |
||
| 1545 | private function perms2mode(array $perms) |
||
| 1558 | } |
||
| 1559 |
In PHP, under loose comparison (like
==, or!=, orswitchconditions), values of different types might be equal.For
stringvalues, the empty string''is a special case, in particular the following results might be unexpected: