b2evolution PHP Cross Reference Blogging Systems

Source: /inc/files/files.ctrl.php - 1736 lines - 57329 bytes - Text - Print

Description: This file implements the UI controller for file management. NOTE: $fm_mode is used for modes. Modes stay visible when browsing to a different location. Examples of modes: link item, copy file. Actions disappear if you browse to a different location. Examples of actions: file properties, file edit.

   1  <?php
   2  /**
   3   * This file implements the UI controller for file management.
   4   *
   5   * NOTE: $fm_mode is used for modes. Modes stay visible when browsing to a different location.
   6   * Examples of modes: link item, copy file.
   7   * Actions disappear if you browse to a different location.
   8   * Examples of actions: file properties, file edit.
   9   *
  10   * fp>> Move/copy should not be a mode (too geeky). All we need is a dir selection tree inside of upload and move.
  11   *
  12   * This file is part of the evoCore framework - {@link http://evocore.net/}
  13   * See also {@link http://sourceforge.net/projects/evocms/}.
  14   *
  15   * @copyright (c)2003-2014 by Francois Planque - {@link http://fplanque.com/}
  16   * Parts of this file are copyright (c)2004-2006 by Daniel HAHLER - {@link http://thequod.de/contact}.
  17   * Parts of this file are copyright (c)2005-2006 by PROGIDISTRI - {@link http://progidistri.com/}.
  18   *
  19   * {@internal License choice
  20   * - If you have received this file as part of a package, please find the license.txt file in
  21   *   the same folder or the closest folder above for complete license terms.
  22   * - If you have received this file individually (e-g: from http://evocms.cvs.sourceforge.net/)
  23   *   then you must choose one of the following licenses before using the file:
  24   *   - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php
  25   *   - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php
  26   * }}
  27   *
  28   * {@internal Open Source relicensing agreement:
  29   * Daniel HAHLER grants Francois PLANQUE the right to license
  30   * Daniel HAHLER's contributions to this file and the b2evolution project
  31   * under any OSI approved OSS license (http://www.opensource.org/licenses/).
  32   *
  33   * PROGIDISTRI S.A.S. grants Francois PLANQUE the right to license
  34   * PROGIDISTRI S.A.S.'s contributions to this file and the b2evolution project
  35   * under any OSI approved OSS license (http://www.opensource.org/licenses/).
  36   * }}
  37   *
  38   * @package admin
  39   *
  40   * {@internal Below is a list of authors who have contributed to design/coding of this file: }}
  41   * @author blueyed: Daniel HAHLER.
  42   * @author fplanque: Francois PLANQUE.
  43   *
  44   * @version $Id: files.ctrl.php 6136 2014-03-08 07:59:48Z manuel $
  45   */
  46  if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );
  47  
  48  /**
  49   * Filelist
  50   * fp>> TODO: When the user is viewing details for a file he should (by default) not be presented with the filelist in addition to the file properties
  51   * In cases like that, we should try to avoid instanciating a Filelist.
  52   */
  53  load_class( 'files/model/_filelist.class.php', 'FileList' );
  54  
  55  /**
  56   * @var User
  57   */
  58  global $current_User;
  59  
  60  global $dispatcher;
  61  
  62  global $blog;
  63  
  64  global $filename_max_length, $dirpath_max_length;
  65  
  66  // Check permission:
  67  $current_User->check_perm( 'files', 'view', true, $blog ? $blog : NULL );
  68  
  69  $AdminUI->set_path( 'files', 'browse' );
  70  
  71  
  72  // INIT params:
  73  if( param( 'root_and_path', 'string', '', false ) /* not memorized (default) */ && strpos( $root_and_path, '::' ) )
  74  { // root and path together: decode and override (used by "radio-click-dirtree")
  75      list( $root, $path ) = explode( '::', $root_and_path, 2 );
  76      // Memorize new root:
  77      memorize_param( 'root', 'string', NULL );
  78      memorize_param( 'path', 'string', NULL );
  79  }
  80  else
  81  {
  82      param( 'root', 'string', NULL, true ); // the root directory from the dropdown box (user_X or blog_X; X is ID - 'user' for current user (default))
  83      param( 'path', 'string', '/', true );  // the path relative to the root dir
  84      if( param( 'new_root', 'string', '' )
  85          && $new_root != $root )
  86      { // We have changed root in the select list
  87          $root = $new_root;
  88          $path = '';
  89      }
  90  }
  91  
  92  
  93  /*
  94   * Load linkable objects:
  95   */
  96  if( param( 'link_type', 'string', NULL, true, false, false ) && param( 'link_object_ID', 'integer', NULL, true, false, false ) )
  97  { // Load Requested LinkOwner object:
  98      $LinkOwner = get_link_owner( $link_type, $link_object_ID );
  99      if( empty( $LinkOwner ) )
 100      { // We could not find the owner object to link:
 101          $Messages->add( T_('Requested object does not exist any longer.'), 'error' );
 102          forget_param( 'link_type' );
 103          forget_param( 'link_object_ID' );
 104          unset( $link_type );
 105          unset( $link_object_ID );
 106      }
 107  }
 108  
 109  if( param( 'user_ID', 'integer', NULL, true, false, false ) )
 110  { // Load Requested user:
 111      $UserCache = & get_UserCache();
 112      if( ($edited_User = & $UserCache->get_by_ID( $user_ID, false )) === false )
 113      {    // We could not find the contact to link:
 114          $Messages->add( sprintf( T_('Requested &laquo;%s&raquo; object does not exist any longer.'), T_('User') ), 'error' );
 115          unset( $edited_User );
 116          forget_param( 'user_ID' );
 117          unset( $user_ID );
 118      }
 119      else
 120      {    // Found User, check perm:
 121          if( $edited_User->ID != $current_User->ID )
 122          {    // if not editing himself, must have user edit permission:
 123              if( ! $current_User->check_perm( 'users', 'edit' ) )
 124              {
 125                  $Messages->add( T_('No permission to edit this user.'), 'error' );
 126                  unset( $edited_User );
 127                  forget_param( 'user_ID' );
 128                  unset( $user_ID );
 129              }
 130          }
 131  
 132      }
 133  }
 134  
 135  
 136  /**
 137   * @global string The file manager mode we're in ('fm_upload', 'fm_move')
 138   */
 139  $fm_mode = param( 'fm_mode', 'string', NULL, true );
 140  
 141  $action = param_action();
 142  if( $action == 'group_action' )
 143  { // Get the real action from the select:
 144      $action = param( 'group_action', 'string', '' );
 145      // NOTE/TODO: dh> action "img_tag" appears to be unimplemented for non-JS
 146  }
 147  
 148  if( !empty($action) && substr( $fm_mode, 0, 5 ) != 'link_' )
 149  {    // The only modes which can tolerate simultaneous actions at this time are link_* modes (item, user...)
 150      // file_move & file_copy shouldn't actually be modes
 151      $fm_mode = '';
 152  }
 153  
 154  // Abstract data we want to pass through:
 155  param( 'linkctrl', 'string', '', true );
 156  param( 'linkdata', 'string', '', true );
 157  
 158  // Name of the iframe we want some actions to come back to:
 159  param( 'iframe_name', 'string', '', true );
 160  
 161  // Get root:
 162  $ads_list_path = false; // false by default, gets set if we have a valid root
 163  /**
 164   * @var FileRoot
 165   */
 166  $fm_FileRoot = NULL;
 167  
 168  $FileRootCache = & get_FileRootCache();
 169  
 170  $available_Roots = $FileRootCache->get_available_FileRoots();
 171  
 172  if( ! empty($root) )
 173  { // We have requested a root folder by string:
 174      $fm_FileRoot = & $FileRootCache->get_by_ID($root, true);
 175  
 176      if( ! $fm_FileRoot || ! isset( $available_Roots[$fm_FileRoot->ID] ) || ! $current_User->check_perm( 'files', 'view', false, $fm_FileRoot ) )
 177      { // Root not found or not in list of available ones
 178          $Messages->add( T_('You don\'t have access to the requested root directory.'), 'error' );
 179          $fm_FileRoot = false;
 180      }
 181  }
 182  elseif( !empty($edited_User) )
 183  {    // We have a user, check if it already has a linked file in a particular root, in which case we want to use that root!
 184      // This is useful so users can find their existing avatar
 185      // Get list of attached files:
 186      /**
 187       * @var File
 188       */
 189      if( ( $avatar_File = & $edited_User->get_avatar_File() ) && ( $current_User->check_perm( 'files', 'view', false, $avatar_File->get_FileRoot() ) ) )
 190      {
 191          $fm_FileRoot = & $avatar_File->get_FileRoot();
 192          $path = dirname( $avatar_File->get_rdfs_rel_path() ).'/';
 193      }
 194  }
 195  elseif( !empty($LinkOwner) )
 196  {    // We have a post, check if it already has a linked file in a particular root, in which case we want to use that root!
 197      // This is useful when clicking "attach files" from the post edit screen: it takes you to the root where you have
 198      // already attached files from. Otherwise the next block below will default to the Blog's fileroot.
 199      // Get list of attached files:
 200      if( $FileList = $LinkOwner->get_attachment_FileList( 1 ) )
 201      {    // Get first file:
 202          /**
 203           * @var File
 204           */
 205          $File = & $FileList->get_next();
 206          if( !empty( $File ) && $current_User->check_perm( 'files', 'view', false, $File->get_FileRoot() ) )
 207          {    // Obtain and use file root of first file:
 208              $fm_FileRoot = & $File->get_FileRoot();
 209              $path = dirname( $File->get_rdfs_rel_path() ).'/';
 210          }
 211      }
 212  }
 213  
 214  if( $fm_FileRoot && ! $current_User->check_perm( 'files', 'view', false, $fm_FileRoot ) )
 215  {
 216      $fm_FileRoot = false;
 217  };
 218  
 219  if( empty($fm_FileRoot) && !empty($edited_User) )
 220  {    // Still not set a root, try to get it for the edited User
 221      $fm_FileRoot = & $FileRootCache->get_by_type_and_ID( 'user', $edited_User->ID );
 222      if( ! $fm_FileRoot || ! isset( $available_Roots[$fm_FileRoot->ID] ) )
 223      { // Root not found or not in list of available ones
 224          $fm_FileRoot = false;
 225      }
 226  }
 227  
 228  if( empty($fm_FileRoot) && !empty($Blog) )
 229  {    // Still not set a root, try to get it for the current Blog
 230      $fm_FileRoot = & $FileRootCache->get_by_type_and_ID( 'collection', $Blog->ID );
 231      if( ! $fm_FileRoot || ! isset( $available_Roots[$fm_FileRoot->ID] ) )
 232      { // Root not found or not in list of available ones
 233          $fm_FileRoot = false;
 234      }
 235  }
 236  
 237  
 238  if( ! $fm_FileRoot )
 239  { // No root requested (or the requested is invalid),
 240      // get the first one available:
 241      if( $available_Roots )
 242      {
 243          foreach( $available_Roots as $l_FileRoot )
 244          {
 245              if( $current_User->check_perm( 'files', 'view', false, $l_FileRoot ) )
 246              {
 247                  $fm_FileRoot = $l_FileRoot;
 248                  break;
 249              }
 250          }
 251      }
 252      if( ! $fm_FileRoot )
 253      {
 254          $Messages->add( T_('You don\'t have access to any root directory.'), 'error' );
 255      }
 256  }
 257  
 258  if( $fm_FileRoot )
 259  { // We have access to a file root:
 260      if( empty($fm_FileRoot->ads_path) )
 261      {    // Not sure it's possible to get this far, but just in case...
 262          $Messages->add( sprintf( T_('The root directory &laquo;%s&raquo; does not exist.'), $fm_FileRoot->ads_path ), 'error' );
 263      }
 264      else
 265      { // Root exists
 266  
 267          // Make sure $root is set:
 268          $root = $fm_FileRoot->ID;
 269  
 270          // Let's get into requested list dir...
 271          $non_canonical_list_path = $fm_FileRoot->ads_path.$path;
 272  
 273          // Dereference any /../ just to make sure, and CHECK if directory exists:
 274          $ads_list_path = get_canonical_path( $non_canonical_list_path );
 275  
 276          if( !is_dir( $ads_list_path ) )
 277          { // This should never happen, but just in case the diretory does not exist:
 278              $Messages->add( sprintf( T_('The directory &laquo;%s&raquo; does not exist.'), $path ), 'error' );
 279              $path = '';        // fp> added
 280              $ads_list_path = NULL;
 281          }
 282          elseif( ! preg_match( '#^'.preg_quote($fm_FileRoot->ads_path, '#').'#', $ads_list_path ) )
 283          { // cwd is OUTSIDE OF root!
 284              $Messages->add( T_( 'You are not allowed to go outside your root directory!' ), 'error' );
 285              $path = '';        // fp> added
 286              $ads_list_path = $fm_FileRoot->ads_path;
 287          }
 288          elseif( $ads_list_path != $non_canonical_list_path )
 289          {    // We have reduced the absolute path, we should also reduce the relative $path (used in urls params)
 290              $path = get_canonical_path( $path );
 291          }
 292  
 293          if( ( $Messages->count() == 0 ) && ( strlen( $ads_list_path ) > $dirpath_max_length ) && $current_User->check_perm( 'options', 'edit' ) )
 294          { // This folder absolute path exceed the max allowed length, a warning message must be displayed, if there were no other message yet. ( If there are other messages then this one should have been already added )
 295              $Messages->add( sprintf( T_( 'This folder has an access path that is too long and cannot be properly handled by b2evolution. Please check and increase the &laquo;%s&raquo; variable.'), '$dirpath_max_length' ), 'warning' );
 296          }
 297      }
 298  }
 299  
 300  
 301  file_controller_build_tabs();
 302  
 303  
 304  if( empty($ads_list_path) )
 305  { // We have no Root / list path, there was an error. Unset any action or mode.
 306      $action = 'nil';
 307      $fm_mode = NULL;
 308  
 309      $AdminUI->disp_html_head();
 310      // Display title, menu, messages, etc. (Note: messages MUST be displayed AFTER the actions)
 311      $AdminUI->disp_body_top();
 312      // Begin payload block:
 313      $AdminUI->disp_payload_begin();
 314      // nothing!
 315      // End payload block:
 316      $AdminUI->disp_payload_end();
 317      $AdminUI->disp_global_footer();
 318      exit(0);
 319  }
 320  
 321  $Debuglog->add( 'root: '.var_export( $root, true ), 'files' );
 322  $Debuglog->add( 'FM root: '.var_export( $fm_FileRoot, true ), 'files' );
 323  $Debuglog->add( 'FM _ads_list_path: '.var_export( $ads_list_path, true ), 'files' );
 324  $Debuglog->add( 'path: '.var_export( $path, true ), 'files' );
 325  
 326  
 327  /**
 328   * A list of filepaths which are selected in the FM list.
 329   *
 330   * @todo fp> This could probably be further simplified by using "fm_sources" for selections.
 331   * Note: fm_sources is better because it also handles sources/selections on a different fileroot
 332   *
 333   * @global array
 334   */
 335  $fm_selected = param( 'fm_selected', 'array/string', array(), true );
 336  $Debuglog->add( count($fm_selected).' selected files/directories', 'files' );
 337  /**
 338   * The selected files (must be within current fileroot)
 339   *
 340   * @global Filelist
 341   */
 342  $selected_Filelist = new Filelist( $fm_FileRoot, false );
 343  foreach( $fm_selected as $l_source_path )
 344  {
 345      // echo '<br>'.$l_source_path;
 346      $selected_Filelist->add_by_subpath( urldecode($l_source_path), true );
 347  }
 348  
 349  
 350  
 351  /*
 352   * Load editable objects:
 353   */
 354  if( param( 'link_ID', 'integer', NULL, false, false, false ) )
 355  {
 356      $LinkCache = & get_LinkCache();
 357      if( ($edited_Link = & $LinkCache->get_by_ID( $link_ID, false )) === false )
 358      {    // We could not find the link to edit:
 359          $Messages->add( sprintf( T_('Requested &laquo;%s&raquo; object does not exist any longer.'), T_('Link') ), 'error' );
 360          unset( $edited_Link );
 361          forget_param( 'link_ID' );
 362          unset( $link_ID );
 363      }
 364  }
 365  
 366  
 367  
 368  // Check actions that need early processing:
 369  if( $action == 'createnew' )
 370  {
 371      // Check permission:
 372      $current_User->check_perm( 'files', 'add', true, $blog ? $blog : NULL );
 373  
 374      // create new file/dir
 375      param( 'create_type', 'string', true ); // 'file', 'dir'
 376  
 377      $action = ( $create_type == 'file' ? 'createnew_file' : 'createnew_dir'  );
 378  }
 379  
 380  switch( $action )
 381  {
 382      case 'filter':
 383          $action = 'list';
 384          break;
 385  
 386      case 'filter_unset':
 387          // Clear filters!
 388          $fm_filter = '';
 389          $action = 'list';
 390          break;
 391  
 392      case 'createnew_dir':
 393          // We are probably comming from 'createnew' but there is no guarantee!
 394          // Check that this action request is not a CSRF hacked request:
 395          $Session->assert_received_crumb( 'file' );
 396  
 397          // Check permission:
 398          $current_User->check_perm( 'files', 'add', true, $blog ? $blog : NULL );
 399  
 400          if( ! $Settings->get( 'fm_enable_create_dir' ) )
 401          { // Directory creation is gloablly disabled:
 402              $Messages->add( T_('Directory creation is disabled.'), 'error' );
 403              break;
 404          }
 405  
 406          if( ! param( 'create_name', 'string', '' ) )
 407          { // No name was supplied:
 408              $Messages->add( T_('Cannot create a directory without name.'), 'error' );
 409              break;
 410          }
 411          if( $error_dirname = validate_dirname( $create_name ) )
 412          { // Not valid dirname
 413              $Messages->add( $error_dirname, 'error' );
 414              break;
 415          }
 416  
 417          // Try to get File object:
 418          /**
 419           * @var FileCache
 420           */
 421          $FileCache = & get_FileCache();
 422          /**
 423           * @var File
 424           */
 425          $newFile = & $FileCache->get_by_root_and_path( $fm_FileRoot->type, $fm_FileRoot->in_type_ID, $path.$create_name );
 426  
 427          if( strlen( $newFile->get_full_path() ) > $dirpath_max_length )
 428          {
 429              $Messages->add( T_('The new file access path is too long, shorter folder names would be required.'), 'error' );
 430              break;
 431          }
 432  
 433          if( $newFile->exists() )
 434          {
 435              $Messages->add( sprintf( T_('The file &laquo;%s&raquo; already exists.'), $create_name ), 'error' );
 436              break;
 437          }
 438  
 439          if( ! $newFile->create( $create_type ) )
 440          {
 441              $Messages->add( sprintf( T_('Could not create directory &laquo;%s&raquo; in &laquo;%s&raquo;.'), $create_name, $path )
 442                  .' '.get_file_permissions_message(), 'error' );
 443              break;
 444          }
 445  
 446          $Messages->add( sprintf( T_('The directory &laquo;%s&raquo; has been created.'), $create_name ), 'success' );
 447  
 448          header_redirect( regenerate_url( '', '', '', '&' ) );
 449          // $action = 'list';
 450          break;
 451  
 452  
 453      case 'createnew_file':
 454          // We are probably comming from 'createnew' but there is no guarantee!
 455          // Check that this action request is not a CSRF hacked request:
 456          $Session->assert_received_crumb( 'file' );
 457  
 458          // Check permission:
 459          $current_User->check_perm( 'files', 'add', true, $blog ? $blog : NULL );
 460  
 461          if( ! $Settings->get( 'fm_enable_create_file' ) )
 462          { // File creation is gloablly disabled:
 463              $Messages->add( T_('File creation is disabled.'), 'error' );
 464              break;
 465          }
 466  
 467          if( ! param( 'create_name', 'string', '' ) )
 468          { // No name was supplied:
 469              $Messages->add( T_('Cannot create a file without name.'), 'error' );
 470              break;
 471          }
 472          if( $error_filename = validate_filename( $create_name, $current_User->check_perm( 'files', 'all' ) ) )
 473          { // Not valid filename or extension
 474              $Messages->add( $error_filename, 'error' );
 475              break;
 476          }
 477  
 478          // Try to get File object:
 479          $FileCache = & get_FileCache();
 480          $newFile = & $FileCache->get_by_root_and_path( $fm_FileRoot->type, $fm_FileRoot->in_type_ID, $path.$create_name );
 481  
 482          if( $newFile->exists() )
 483          {
 484              $Messages->add( sprintf( T_('The file &laquo;%s&raquo; already exists.'), $create_name ), 'error' );
 485              break;
 486          }
 487  
 488          if( ! $newFile->create( $create_type ) )
 489          {
 490              $Messages->add( sprintf( T_('Could not create file &laquo;%s&raquo; in &laquo;%s&raquo;.'), $create_name, $newFile->get_dir() )
 491                  .' '.get_file_permissions_message(), 'error' );
 492              break;
 493          }
 494  
 495          $Messages->add( sprintf( T_('The file &laquo;%s&raquo; has been created.'), $create_name ), 'success' );
 496  
 497          header_redirect( regenerate_url( '', '', '', '&' ) );
 498          // $action = 'list';
 499          break;
 500  
 501  
 502    case 'update_settings':
 503          // Check that this action request is not a CSRF hacked request:
 504          $Session->assert_received_crumb( 'file' );
 505  
 506          // Update settings NOW since they may affect the FileList
 507          $UserSettings->set( 'fm_dirsnotattop',   1-param( 'option_dirsattop',        'integer', 0 ) );
 508          $UserSettings->set( 'fm_permlikelsl',      param( 'option_permlikelsl',      'integer', 0 ) );
 509          $UserSettings->set( 'fm_imglistpreview',   param( 'option_imglistpreview',   'integer', 0 ) );
 510          $UserSettings->set( 'fm_getimagesizes',    param( 'option_getimagesizes',    'integer', 0 ) );
 511  
 512          $UserSettings->set( 'fm_showtypes',        param( 'option_showtypes',        'integer', 0 ) );
 513          $UserSettings->set( 'fm_showdate',         param( 'option_showdate',         'string', 'compact' ) );
 514          $UserSettings->set( 'fm_showfsperms',      param( 'option_showfsperms',      'integer', 0 ) );
 515          $UserSettings->set( 'fm_showfsowner',      param( 'option_showfsowner',      'integer', 0 ) );
 516          $UserSettings->set( 'fm_showfsgroup',      param( 'option_showfsgroup',      'integer', 0 ) );
 517  
 518          $UserSettings->set( 'fm_showhidden',       param( 'option_showhidden',       'integer', 0 ) );
 519          $UserSettings->set( 'fm_showevocache',     param( 'option_showevocache',     'integer', 0 ) );
 520          $UserSettings->set( 'fm_recursivedirsize', param( 'option_recursivedirsize', 'integer', 0 ) );
 521          $UserSettings->set( 'fm_allowfiltering',   param( 'option_allowfiltering', 'string', 'simple' ) );
 522  
 523          if( $UserSettings->dbupdate() )
 524          {
 525              $Messages->add( T_('Your user settings have been updated.'), 'success' );
 526          }
 527  
 528          header_redirect( regenerate_url( '', '', '', '&' ) );
 529          // $action = 'list';
 530          break;
 531  
 532      case 'update_file':
 533          // Update File:
 534  
 535          # TODO: dh> Changes linebreaks! e.g. "\n" => "\r\n", when only saving again.
 536  
 537          // Check that this action request is not a CSRF hacked request:
 538          $Session->assert_received_crumb( 'file' );
 539  
 540          if( $demo_mode )
 541          {
 542              $Messages->add( 'Sorry, you cannot update files in demo mode!', 'error' );
 543              break;
 544          }
 545  
 546          // Check permission!
 547           $current_User->check_perm( 'files', 'edit', true, $blog ? $blog : NULL );
 548  
 549           // Get the file we want to update:
 550          $edited_File = & $selected_Filelist->get_by_idx(0);
 551  
 552          // Check that the file is editable:
 553          if( ! $edited_File->is_editable( $current_User->check_perm( 'files', 'all' ) ) )
 554          {
 555              $Messages->add( sprintf( T_( 'You are not allowed to edit &laquo;%s&raquo;.' ), $edited_File->dget('name') ), 'error' );
 556              break;
 557          }
 558  
 559          param( 'file_content', 'html', '', false );
 560  
 561  
 562          $fpath = $edited_File->get_full_path();
 563          if( file_exists($fpath) && ! is_writeable($fpath) ) {
 564              $Messages->add( sprintf('The file &laquo;%s&raquo; is not writable.', rel_path_to_base($fpath)), 'error' );
 565              break;
 566          }
 567  
 568          if( save_to_file( $file_content, $fpath, 'w+' ) )
 569          {
 570              $Messages->add( sprintf( T_( 'The file &laquo;%s&raquo; has been updated.' ), $edited_File->dget('name') ), 'success' );
 571          }
 572          else
 573          {
 574              $Messages->add( sprintf( T_( 'The file &laquo;%s&raquo; could not be updated.' ), $edited_File->dget('name') ), 'error' );
 575          }
 576          header_redirect( regenerate_url( '', '', '', '&' ) );
 577          // $action = 'list';
 578          break;
 579  }
 580  
 581  
 582  // Do we want to display the directory tree next to the files table
 583  $UserSettings->param_Request( 'fm_hide_dirtree', 'fm_hide_dirtree', 'integer', 0, true );
 584  
 585  
 586  /**
 587   * Filelist
 588   */
 589  $fm_Filelist = new Filelist( $fm_FileRoot, $ads_list_path );
 590  $Debuglog->add( 'FM _rds_list_path: '.var_export( $fm_Filelist->_rds_list_path, true ), 'files' );
 591  
 592  param( 'fm_filter', '', NULL, true );
 593  param( 'fm_filter_regex', 'integer', 0, true );
 594  $fm_Filelist->set_Filter( $fm_filter, $fm_filter_regex );
 595  
 596  if( $UserSettings->param_Request( 'fm_dirsnotattop', 'fm_dirsnotattop', 'integer', 0 ) )
 597  {
 598      $fm_Filelist->_dirs_not_at_top = true;
 599  }
 600  if( $UserSettings->param_Request( 'fm_recursivedirsize', 'fm_recursivedirsize', 'integer', 0 ) ) // TODO: check for permission? (Server load)
 601  {
 602      $fm_Filelist->_use_recursive_dirsize = true;
 603  }
 604  check_showparams( $fm_Filelist );
 605  if( param( 'fm_flatmode', '', NULL, true ) )
 606  {
 607      $fm_Filelist->flatmode = true;
 608  }
 609  
 610  /*
 611   * Load Filelist (with meta data):
 612   */
 613  $fm_Filelist->load();
 614  
 615  // Sort Filelist
 616  param( 'fm_order', 'string', NULL, true );
 617  if( ! in_array( $fm_order, array( 'name', 'path', 'type', 'size', 'lastmod', 'perms', 'fsowner', 'fsgroup' ) ) )
 618  {
 619      $fm_order = NULL;
 620  }
 621  param( 'fm_orderasc', '', NULL, true );
 622  $fm_Filelist->sort( $fm_order, $fm_orderasc );
 623  
 624  
 625  switch( $action )
 626  {
 627      case 'download':
 628          // TODO: We don't need the Filelist, move UP!
 629          // TODO: provide optional zip formats (tgz, ..) - the used lib provides more..
 630          // TODO: use "inmemory"=>false, so that you can download bigger archives faster!
 631  
 632          $action_title = T_('Download');
 633  
 634          if( !$selected_Filelist->count() )
 635          {
 636              $Messages->add( T_('Nothing selected.'), 'error' );
 637              $action = 'list';
 638              break;
 639          }
 640  
 641          param( 'zipname', 'string', '' );
 642          param( 'exclude_sd', 'integer', 0 );
 643  
 644          if( empty($zipname) )
 645          {
 646              if( param( 'action_invoked', 'integer', 0 ) )
 647              { // Action was invoked, add "hint"
 648                  param_error( 'zipname', T_('Please provide the name of the archive.') );
 649              }
 650              if( $selected_Filelist->count() == 1 )
 651              {
 652                  $only_File = $selected_Filelist->get_array();
 653                  $only_File = $only_File[0];
 654  
 655                  // TODO: once we support additional formats, use the default extension here:
 656                  $zipname = $only_File->get_name().'.zip';
 657              }
 658              break;
 659          }
 660  
 661          // Downloading
 662          load_class( '_ext/_zip_archives.php', 'zip_file' );
 663  
 664          $arraylist = $selected_Filelist->get_array( 'get_name' );
 665  
 666          $options = array (
 667              'basedir' => $fm_Filelist->get_ads_list_path(),
 668              'inmemory' => 1,
 669              'recurse' => (1 - $exclude_sd),
 670          );
 671  
 672          $zipfile = new zip_file( $zipname );
 673          $zipfile->set_options( $options );
 674          $zipfile->add_files( $arraylist, array( '_evocache' ) );
 675          $zipfile->create_archive();
 676  
 677          if( $zipfile->error )
 678          {
 679              foreach($zipfile->error as $v)
 680              {
 681                  $Messages->add( $v, 'error' );
 682              }
 683              break;
 684          }
 685  
 686          $zipfile->download_file();
 687          exit(0);
 688          /* EXITED! */
 689  
 690  
 691      case 'rename':
 692          // TODO: We don't need the Filelist, move UP!
 693          // Rename a file:
 694  
 695          // This will not allow to overwrite existing files, the same way Windows and MacOS do not allow it. Adding an option will only clutter the interface and satisfy geeks only.
 696          if( ! $current_User->check_perm( 'files', 'edit', false, $blog ? $blog : NULL ) )
 697          { // We do not have permission to edit files
 698              $Messages->add( T_('You have no permission to edit/modify files.'), 'error' );
 699              $action = 'list';
 700              break;
 701          }
 702  
 703          $allow_locked_filetypes = $current_User->check_perm( 'files', 'all' );
 704  
 705          if( ! $selected_Filelist->count() )
 706          { // There is nothing to rename
 707              $Messages->add( T_('Nothing selected.'), 'error' );
 708              $action = 'list';
 709              break;
 710          }
 711  
 712          param( 'confirmed', 'integer', 0 );
 713          param( 'new_names', 'array/string', array() );
 714  
 715          // Check params for each file to rename:
 716          while( $loop_src_File = & $selected_Filelist->get_next() )
 717          {
 718              if( ! isset( $new_names[$loop_src_File->get_md5_ID()] ) )
 719              { // We have not yet provided a name to rename to...
 720                  $confirmed = 0;
 721                  $new_names[$loop_src_File->get_md5_ID()] = $loop_src_File->get_name();
 722                  continue;
 723              }
 724  
 725              // Check if provided name is okay:
 726              if( $check_error = check_rename( $new_names[$loop_src_File->get_md5_ID()], $loop_src_File->is_dir(), $loop_src_File->get_dir(), $allow_locked_filetypes ) )
 727              {
 728                  $confirmed = 0;
 729                  param_error( 'new_names['.$loop_src_File->get_md5_ID().']', $check_error );
 730                  continue;
 731              }
 732          }
 733  
 734          if( $confirmed )
 735          { // Rename is confirmed, let's proceed:
 736              // Check that this action request is not a CSRF hacked request:
 737              $Session->assert_received_crumb( 'file' );
 738              $selected_Filelist->restart();
 739              while( $loop_src_File = & $selected_Filelist->get_next() )
 740              {
 741                  $old_name = $loop_src_File->get_name();
 742                  $new_name = $new_names[$loop_src_File->get_md5_ID()];
 743  
 744                  if( $new_name == $old_name )
 745                  { // Name has not changed...
 746                      $Messages->add( sprintf( T_('&laquo;%s&raquo; has not been renamed'), $old_name ), 'note' );
 747                      continue;
 748                  }
 749                  // Perform rename:
 750                  if( ! $loop_src_File->rename_to( $new_name ) )
 751                  {
 752                      $Messages->add( sprintf( T_('&laquo;%s&raquo; could not be renamed to &laquo;%s&raquo;'),
 753                          $old_name, $new_name ), 'error' );
 754                      continue;
 755                  }
 756  
 757                  // We have moved in same dir, update caches:
 758                  $fm_Filelist->update_caches();
 759  
 760                  if( $fm_Filelist->contains( $loop_src_File ) === false )
 761                  { // File not in filelist (expected if not same dir)
 762                      $fm_Filelist->add( $File );
 763                  }
 764  
 765                  $Messages->add( sprintf( T_('&laquo;%s&raquo; has been successfully renamed to &laquo;%s&raquo;'),
 766                          $old_name, $new_name ), 'success' );
 767              }
 768  
 769              // REDIRECT / EXIT
 770               header_redirect( regenerate_url( '', '', '', '&' ) );
 771             // $action = 'list';
 772          }
 773          break;
 774  
 775  
 776      case 'delete':
 777          // TODO: We don't need the Filelist, move UP!
 778          // Delete a file or directory:
 779  
 780          // Check that this action request is not a CSRF hacked request:
 781          $Session->assert_received_crumb( 'file' );
 782  
 783          if( ! $current_User->check_perm( 'files', 'edit', false, $blog ? $blog : NULL ) )
 784          { // We do not have permission to edit files
 785              $Messages->add( T_('You have no permission to edit/modify files.'), 'error' );
 786              $action = 'list';
 787              break;
 788          }
 789  
 790          if( ! $selected_Filelist->count() )
 791          {
 792              $Messages->add( T_('Nothing selected.'), 'error' );
 793              $action = 'list';
 794              break;
 795          }
 796  
 797          param( 'confirmed', 'integer', 0 );
 798          // fplanque>> We cannot actually offer to delete subdirs since we cannot pre-check DB
 799  
 800          $selected_Filelist->restart();
 801          if( $confirmed )
 802          { // Unlink files:
 803              while( $l_File = & $selected_Filelist->get_next() )
 804              {
 805                  if( $l_File->unlink() )
 806                  {
 807                      $Messages->add( sprintf( ( $l_File->is_dir() ? T_('The directory &laquo;%s&raquo; has been deleted.')
 808                                      : T_('The file &laquo;%s&raquo; has been deleted.') ), $l_File->dget('name') ), 'success' );
 809                      $fm_Filelist->remove( $l_File );
 810                  }
 811                  else
 812                  {
 813                      $Messages->add( sprintf( ( $l_File->is_dir() ? T_('Could not delete the directory &laquo;%s&raquo; (not empty?).')
 814                                      : T_('Could not delete the file &laquo;%s&raquo;.') ), $l_File->dget('name') ), 'error' );
 815                  }
 816              }
 817              $action = 'list';
 818              // Redirect so that a reload doesn't write to the DB twice:
 819              header_redirect( '?ctrl=files&blog='.$blog.'&root='.$root.'&path='.$path, 303 ); // Will EXIT
 820              // We have EXITed already at this point!!
 821          }
 822          else
 823          {
 824              // make sure we have loaded metas for all files in selection!
 825              $selected_Filelist->load_meta();
 826  
 827              $index = 0;
 828              // Check if there are delete restrictions on the files:
 829              while( $l_File = & $selected_Filelist->get_next() )
 830              {
 831                  // Check if there are delete restrictions on this file:
 832                  $restriction_Messages = $l_File->check_relations( 'delete_restrictions', array(), true );
 833  
 834                  if( $restriction_Messages->count() )
 835                  { // There are restrictions:
 836                      $Messages->add( $l_File->get_prefixed_name().': '.T_('cannot be deleted because of the following relations')
 837                          .$restriction_Messages->display( NULL, NULL, false, false ) );
 838  
 839                      // remove it from the list of selected files (that will be offered to delete):
 840                      $selected_Filelist->remove( $l_File );
 841                      unset( $fm_selected[$index] );
 842                  }
 843                  $index++;
 844              }
 845  
 846              if( ! $selected_Filelist->count() )
 847              { // no files left in list, cancel action
 848                  $action = 'list';
 849                  // Redirect so that a reload doesn't write to the DB twice:
 850                  header_redirect( '?ctrl=files&blog='.$blog.'&root='.$root.'&path='.$path, 303 ); // Will EXIT
 851                  // We have EXITed already at this point!!
 852              }
 853          }
 854          break;
 855  
 856  
 857      case 'make_post':
 858          // TODO: We don't need the Filelist, move UP!
 859          // Make posts with selected images:
 860  
 861          // Check that this action request is not a CSRF hacked request:
 862          $Session->assert_received_crumb( 'file' );
 863  
 864          if( ! $selected_Filelist->count() )
 865          {
 866              $Messages->add( T_('Nothing selected.'), 'error' );
 867              $action = 'list';
 868              break;
 869          }
 870  
 871          // fp> TODO: this block should move to a general level
 872          // Try to go to the right blog:
 873          if( $fm_Filelist->get_root_type() == 'collection' )
 874          {
 875              set_working_blog( $fm_Filelist->get_root_ID() );
 876        // Load the blog we're in:
 877              $Blog = & $BlogCache->get_by_ID( $blog );
 878          }
 879          // ---
 880  
 881  
 882          if( empty( $Blog ) )
 883          {
 884              $Messages->add( T_('No destination blog is selected.'), 'error' );
 885              break;
 886          }
 887          //$Blog->disp('name');
 888  
 889          // Get default status (includes PERM CHECK):
 890          $item_status = $Blog->get_allowed_item_status();
 891          if( empty($item_status) )
 892          {
 893              $Messages->add( T_('Sorry, you have no permission to post into this blog.'), 'error' );
 894              break;
 895          }
 896  
 897          // make sure we have loaded metas for all files in selection!
 898          $selected_Filelist->load_meta();
 899  
 900          // Ready to create post(s):
 901          load_class( 'items/model/_item.class.php', 'Item' );
 902  
 903          switch( $action )
 904          {
 905              case 'make_post':
 906                  // SINGLE POST:
 907                  // Create a post:
 908                  $edited_Item = new Item();
 909                  $edited_Item->set( 'status', $item_status );
 910                  $edited_Item->set( 'main_cat_ID', $Blog->get_default_cat_ID() );
 911  
 912                  $l_File = & $selected_Filelist->get_next();
 913  
 914                  $title = $l_File->get('title');
 915                  if( empty($title) )
 916                  {
 917                      $title = $l_File->get('name');
 918                  }
 919                  $edited_Item->set( 'title', $title );
 920  
 921                  $DB->begin( 'SERIALIZABLE' );
 922  
 923                  // INSERT NEW POST INTO DB:
 924                  if( $edited_Item->dbinsert() )
 925                  {
 926                      $order = 1;
 927                      $LinkOwner = new LinkItem( $edited_Item );
 928                      do
 929                      { // LOOP through files:
 930                          // echo '<br>file meta: '.$l_File->meta;
 931                          if(    $l_File->meta == 'notfound' )
 932                          {    // That file has no meta data yet, create it now!
 933                              $l_File->dbsave();
 934                          }
 935  
 936                          // Let's make the link!
 937                          $LinkOwner->add_link( $l_File->ID, 'teaser', $order++ );
 938  
 939                          $Messages->add( sprintf( T_('&laquo;%s&raquo; has been attached.'), $l_File->dget('name') ), 'success' );
 940  
 941                      } while( $l_File = & $selected_Filelist->get_next() );
 942  
 943                      $DB->commit();
 944                  }
 945                  else
 946                  {
 947                      $Messages->add( T_('Couldn\'t create the new post'), 'error' );
 948                      $DB->rollback();
 949                  }
 950  
 951                  header_redirect( $dispatcher.'?ctrl=items&action=edit&p='.$edited_Item->ID );    // Will save $Messages
 952                  break;
 953          }
 954  
 955          // Note: we should have EXITED here. In case we don't (error, or sth...)
 956  
 957          // Reset stuff so it doesn't interfere with upcomming display
 958          unset( $edited_Item );
 959          unset( $edited_Link );
 960          $selected_Filelist = new Filelist( $fm_Filelist->get_FileRoot(), false );
 961          break;
 962  
 963  
 964      case 'edit_file':
 965          // TODO: We don't need the Filelist, move UP!
 966          // Edit Text File
 967  
 968          // Check that this action request is not a CSRF hacked request:
 969          $Session->assert_received_crumb( 'file' );
 970  
 971          // Check permission!
 972           $current_User->check_perm( 'files', 'edit', true, $blog ? $blog : NULL );
 973  
 974           // Get the file we want to edit:
 975          $edited_File = & $selected_Filelist->get_by_idx(0);
 976  
 977          // Check that the file is editable:
 978          if( ! $edited_File->is_editable( $current_User->check_perm( 'files', 'all' ) ) )
 979          {
 980              $Messages->add( sprintf( T_( 'You are not allowed to edit &laquo;%s&raquo;.' ), $edited_File->dget('name') ), 'error' );
 981               // Leave special display mode:
 982              $action = 'list';
 983              break;
 984          }
 985  
 986          $full_path = $edited_File->get_full_path();
 987          if( $size = filesize($full_path) )
 988          {
 989              $rsc_handle = fopen( $full_path, 'r');
 990              $edited_File->content = fread( $rsc_handle, $size );
 991              fclose( $rsc_handle );
 992          }
 993          else
 994          {    // Empty file
 995              $edited_File->content = '';
 996          }
 997          break;
 998  
 999  
1000      case 'edit_properties':
1001          // TODO: We don't need the Filelist, move UP!
1002          // Edit File properties (Meta Data)
1003  
1004          // Check that this action request is not a CSRF hacked request:
1005          $Session->assert_received_crumb( 'file' );
1006  
1007          // Check permission!
1008           $current_User->check_perm( 'files', 'edit', true, $blog ? $blog : NULL );
1009  
1010          $edited_File = & $selected_Filelist->get_by_idx(0);
1011          $edited_File->load_meta();
1012          break;
1013  
1014  
1015      case 'update_properties':
1016          // TODO: We don't need the Filelist, move UP!
1017          // Update File properties (Meta Data); on success this ends the file_properties mode:
1018  
1019          // Check that this action request is not a CSRF hacked request:
1020          $Session->assert_received_crumb( 'file' );
1021  
1022          // Check permission!
1023           $current_User->check_perm( 'files', 'edit', true, $blog ? $blog : NULL );
1024  
1025          $edited_File = & $selected_Filelist->get_by_idx(0);
1026          // Load meta data:
1027          $edited_File->load_meta();
1028  
1029          $edited_File->set( 'title', param( 'title', 'string', '' ) );
1030          $edited_File->set( 'alt', param( 'alt', 'string', '' ) );
1031          $edited_File->set( 'desc', param( 'desc', 'string', '' ) );
1032  
1033          // Store File object into DB:
1034          if( $edited_File->dbsave() )
1035          {
1036              $Messages->add( sprintf( T_( 'File properties for &laquo;%s&raquo; have been updated.' ), $edited_File->dget('name') ), 'success' );
1037          }
1038          else
1039          {
1040              $Messages->add( sprintf( T_( 'File properties for &laquo;%s&raquo; have not changed.' ), $edited_File->dget('name') ), 'note' );
1041          }
1042  
1043          $old_name = $edited_File->get_name();
1044          $new_name = param( 'name', 'string', '' );
1045          $error_occured = false;
1046  
1047          if( $new_name != $old_name)
1048          { // Name has changed...
1049              $allow_locked_filetypes = $current_User->check_perm( 'files', 'all' );
1050              if( $check_error = check_rename( $new_name, $edited_File->is_dir(), $edited_File->get_dir(), $allow_locked_filetypes ) )
1051              {
1052                  $error_occured = true;
1053                  param_error( 'new_name', $check_error );
1054              }
1055              else
1056              { // Perform rename:
1057                  if( $edited_File->rename_to( $new_name ) )
1058                  {
1059                      $Messages->add( sprintf( T_('&laquo;%s&raquo; has been successfully renamed to &laquo;%s&raquo;'),
1060                              $old_name, $new_name ), 'success' );
1061  
1062                      // We have renamed teh file, update caches:
1063                      $fm_Filelist->update_caches();
1064                  }
1065                  else
1066                  {
1067                      $error_occured = true;
1068                      $Messages->add( sprintf( T_('&laquo;%s&raquo; could not be renamed to &laquo;%s&raquo;'),
1069                              $old_name, $new_name ), 'error' );
1070                  }
1071              }
1072          }
1073  
1074          // Redirect so that a reload doesn't write to the DB twice:
1075          if( $error_occured )
1076          {
1077              header_redirect( regenerate_url( 'fm_selected', 'action=edit_properties&amp;fm_selected[]='.rawurlencode($edited_File->get_rdfp_rel_path() ).'&amp;'.url_crumb('file'), '', '&' ), 303 );
1078              // We have EXITed already, no need else.
1079          }
1080          header_redirect( '?ctrl=files&blog='.$blog.'&root='.$root.'&path='.$path, 303 ); // Will EXIT
1081          // We have EXITed already at this point!!
1082          break;
1083  
1084  
1085      case 'link_user':
1086          // TODO: We don't need the Filelist, move UP!
1087  
1088          // Check that this action request is not a CSRF hacked request:
1089          $Session->assert_received_crumb( 'file' );
1090  
1091          // Link File to User:
1092          if( ! isset($edited_User) )
1093          {    // No User to link to
1094              $fm_mode = NULL;    // not really needed but just  n case...
1095              break;
1096          }
1097  
1098          // Permission HAS been checked on top of controller!
1099  
1100          // Get the file we want to link:
1101          if( !$selected_Filelist->count() )
1102          {
1103              $Messages->add( T_('Nothing selected.'), 'error' );
1104              break;
1105          }
1106          $edited_File = & $selected_Filelist->get_by_idx(0);
1107  
1108          // Load meta data AND MAKE SURE IT IS CREATED IN DB:
1109          $edited_File->load_meta( true );
1110  
1111          // Check a file for min size
1112          $min_size = $Settings->get( 'min_picture_size' );
1113          $image_sizes = $edited_File->get_image_size( 'widthheight' );
1114          if( $image_sizes[0] < $min_size || $image_sizes[1] < $min_size )
1115          {    // Don't use this file as profile picture because it has small sizes
1116              $Messages->add( sprintf( T_( 'Your profile picture must have a minimum size of %dx%d pixels.' ), $min_size, $min_size ), 'error' );
1117              break;
1118          }
1119  
1120          // Link file to user
1121          $LinkOwner = get_link_owner( 'user', $edited_User->ID );
1122          $edited_File->link_to_Object( $LinkOwner );
1123          // Assign avatar:
1124          $edited_User->set( 'avatar_file_ID', $edited_File->ID );
1125          // update profileupdate_date, because a publicly visible user property was changed
1126          $edited_User->set_profileupdate_date();
1127          // Save to DB:
1128           $edited_User->dbupdate();
1129  
1130          $Messages->add( T_('Your profile picture has been changed.'), 'success' );
1131  
1132          // REDIRECT / EXIT
1133          header_redirect( $admin_url.'?ctrl=user&user_tab=avatar&user_ID='.$edited_User->ID );
1134          break;
1135  
1136      case 'link_data':
1137          // fp> do we need to go through this block + redirect or could the link icons link directly to $linkctrl ?
1138  
1139          // Check that this action request is not a CSRF hacked request:
1140          $Session->assert_received_crumb( 'file' );
1141  
1142          // Get the file we want to link:
1143          if( !$selected_Filelist->count() )
1144          {
1145              $Messages->add( T_('Nothing selected.'), 'error' );
1146              break;
1147          }
1148          $edited_File = & $selected_Filelist->get_by_idx(0);
1149  
1150          // Load meta data AND MAKE SURE IT IS CREATED IN DB:
1151          $edited_File->load_meta( true );
1152  
1153          // REDIRECT / EXIT
1154          header_redirect( $admin_url.'?ctrl='.$linkctrl.'&linkdata='.$linkdata.'&file_ID='.$edited_File->ID );
1155  
1156          break;
1157  
1158      case 'link':
1159      case 'link_inpost':    // In the context of a post
1160          // TODO: We don't need the Filelist, move UP!
1161          // Link File to a LinkOwner
1162  
1163          // Check that this action request is not a CSRF hacked request:
1164          $Session->assert_received_crumb( 'file' );
1165  
1166          // Note: we are not modifying any file here, we're just linking it
1167          // we only need read perm on file, but we'll need write perm on destination object (to be checked below)
1168  
1169          if( ! isset( $LinkOwner ) )
1170          {    // No Owner to link to - end link_object mode.
1171              $fm_mode = NULL;
1172              break;
1173          }
1174  
1175          // Check item EDIT permissions:
1176          $LinkOwner->check_perm( 'edit', true );
1177  
1178          // Get the file we want to link:
1179          if( !$selected_Filelist->count() )
1180          {
1181              $Messages->add( T_('Nothing selected.'), 'error' );
1182              break;
1183          }
1184  
1185          $files_count = $selected_Filelist->count();
1186          while( $edited_File = & $selected_Filelist->get_next() )
1187          {    // Let's make the link!
1188              $edited_File->link_to_Object( $LinkOwner );
1189  
1190              // Reset LinkCache to autoincrement link_order
1191              if( $files_count > 1 ) unset($GLOBALS['LinkCache']);
1192          }
1193  
1194          // Forget selected files
1195          if( $files_count > 1 ) $fm_selected = NULL;
1196  
1197          $Messages->add( $LinkOwner->translate( 'Selected files have been linked to owner.' ), 'success' );
1198  
1199          // In case the mode had been closed, reopen it:
1200          $fm_mode = 'link_object';
1201  
1202          // REDIRECT / EXIT
1203          if( $action == 'link_inpost' )
1204          {
1205              header_redirect( $admin_url.'?ctrl=links&link_type='.$LinkOwner->type.'&action=edit_links&mode=iframe&link_object_ID='.$LinkOwner->get_ID() );
1206          }
1207          else
1208          {
1209              header_redirect( regenerate_url( '', '', '', '&' ) );
1210          }
1211          break;
1212  
1213  
1214      case 'edit_perms':
1215          // TODO: We don't need the Filelist, move UP!
1216          // Edit file or directory permissions:
1217  
1218          // Check that this action request is not a CSRF hacked request:
1219          $Session->assert_received_crumb( 'file' );
1220  
1221          if( ! $current_User->check_perm( 'files', 'edit', false, $blog ? $blog : NULL ) )
1222          { // We do not have permission to edit files
1223              $Messages->add( T_('You have no permission to edit/modify files.'), 'error' );
1224              $action = 'list';
1225              break;
1226          }
1227  
1228          if( ! $selected_Filelist->count() )
1229          {
1230              $Messages->add( T_('Nothing selected.'), 'error' );
1231              $action = 'list';
1232              break;
1233          }
1234  
1235  
1236          param( 'perms', 'array/integer', array() );
1237          param( 'edit_perms_default' ); // default value when multiple files are selected
1238          param( 'use_default_perms', 'array/string', array() ); // array of file IDs that should be set to default
1239  
1240          if( count( $use_default_perms ) && $edit_perms_default === '' )
1241          {
1242              param_error( 'edit_perms_default', T_('You have to give a default permission!') );
1243              break;
1244          }
1245  
1246          // form params
1247          $perms_read_readonly = is_windows();
1248          $field_options_read_readonly = array(
1249                  array( 'value' => 444, 'label' => T_('Read-only') ),
1250                  array( 'value' => 666, 'label' => T_('Read and write') ) );
1251          $more_than_one_selected_file = ( $selected_Filelist->count() > 1 );
1252  
1253          if( count( $perms ) || count( $use_default_perms ) )
1254          { // New permissions given, change them
1255              $selected_Filelist->restart();
1256              while( $l_File = & $selected_Filelist->get_next() )
1257              {
1258                  if( in_array( $l_File->get_md5_ID(), $use_default_perms ) )
1259                  { // use default
1260                      $chmod = $edit_perms_default;
1261                  }
1262                  elseif( !isset($perms[ $l_File->get_md5_ID() ]) )
1263                  { // happens for an empty text input or when no radio option is selected
1264                      $Messages->add( sprintf( T_('Permissions for &laquo;%s&raquo; have not been changed.'), $l_File->dget('name') ), 'note' );
1265                      continue;
1266                  }
1267                  else
1268                  { // provided for this file
1269                      $chmod = $perms[ $l_File->get_md5_ID() ];
1270                  }
1271  
1272                  $oldperms = $l_File->get_perms( 'raw' );
1273                  $newperms = $l_File->chmod( octdec( $chmod ) );
1274  
1275                  if( $newperms === false )
1276                  {
1277                      $Messages->add( sprintf( T_('Failed to set permissions on &laquo;%s&raquo; to &laquo;%s&raquo;.'), $l_File->dget('name'), $chmod ), 'error' );
1278                  }
1279                  else
1280                  {
1281                      // Success, remove the file from the list of selected files:
1282                      $selected_Filelist->remove( $l_File );
1283  
1284                      if( $newperms === $oldperms )
1285                      {
1286                          $Messages->add( sprintf( T_('Permissions for &laquo;%s&raquo; have not been changed.'), $l_File->dget('name') ), 'note' );
1287                      }
1288                      else
1289                      {
1290                          $Messages->add( sprintf( T_('Permissions for &laquo;%s&raquo; changed to &laquo;%s&raquo;.'), $l_File->dget('name'), $l_File->get_perms() ), 'success' );
1291                      }
1292                  }
1293              }
1294          }
1295  
1296          if( !$selected_Filelist->count() )
1297          { // No file left selected... (everything worked fine)
1298              $action = 'list';
1299          }
1300          break;
1301  }
1302  
1303  
1304  /*
1305   * Prepare for modes:
1306   */
1307  switch( $fm_mode )
1308  {
1309      case 'file_copy':
1310      case 'file_move':
1311          // ------------------------
1312          // copy/move a file:
1313          // ------------------------
1314          /*
1315           * fplanque>> This whole thing is flawed:
1316           * 1) only geeks can possibly like to use the same interface for renaming, moving and copying
1317           * 2) even the geeky unix commands won't pretend copying and moving are the same thing. They are not!
1318           *    Only moving and renaming are similar, and again FOR GEEKS ONLY.
1319           * 3) The way this works it breaks the File meta data (I'm working on it).
1320           * 4) For Move and Copy, this should use a "destination directory tree" on the right (same as for upload)
1321           * 5) Given all the reasons above copy, move and rename should be clearly separated into 3 different interfaces.
1322           *
1323           * blueyed>> it was never meant to only use a single interface. The original mode
1324           *   'file_cmr' was just a mode to handle it internally easier/more central.
1325           *   'copy' is just 'move and keep the source', while 'rename' is 'move in the same dir'
1326           *
1327           */
1328  
1329          /*
1330          TODO: On error notes use prefixed names, if the roots differ.
1331                Something like $fm_Filelist->get_names_realtive_to( $a_File, $b_File, $root_type, $root_ID, $rel_path )
1332                that returns an array containing the name of $a_File and $b_File relative to the Root path given as
1333                param 3, 4, 5.
1334                This would allow to say "Copied «users/admin/test_me.jpg» to «test_me.jpg»." rather than just
1335                "Copied «test_me.jpg» to «test_me.jpg».".
1336              // fp>> I don't really understand this (probably missing a verb) but I do think that extending the Fileman object is not the right direction to go on the long term
1337              // blueyed>> Tried to make it clearer. If it wasn't a Filemanager method, it has to be a function or
1338              //   a method of the File class. IMHO it should be a method of the (to be killed) Filemanager object.
1339              // fp>> Okay. It should *definitely* be a method of the File object and we should ask for ONE file at a time. Any question about 'where is the file?' (what/where/when/who, etc) should be asked to the File object itself.
1340          */
1341  
1342          if( ! $current_User->check_perm( 'files', 'edit', false, $blog ? $blog : NULL ) )
1343          { // We do not have permission to edit files
1344              $Messages->add( T_('You have no permission to edit/modify files.'), 'error' );
1345              $fm_mode = NULL;
1346              break;
1347          }
1348  
1349          // Get the source list
1350          if( $fm_sources = param( 'fm_sources', 'array/string', array(), true ) )
1351          {
1352              $fm_sources_root = param( 'fm_sources_root', 'string', '', true );
1353  
1354              $sources_Root = & $FileRootCache->get_by_ID( $fm_sources_root );
1355  
1356              if( $sources_Root )
1357              { // instantiate the source list for the selected sources
1358                  $fm_source_Filelist = new Filelist( $sources_Root );
1359              }
1360              else
1361              { // Fallback: source files are considered to be in the current root
1362                  $fm_source_Filelist = new Filelist( $fm_Filelist->get_FileRoot() );
1363                  $Debuglog->add( 'SourceList without explicit root!', 'error' );
1364              }
1365  
1366              if( $fm_source_Filelist )
1367              {
1368                  // TODO: should fail for non-existant sources, or sources where no read-perm
1369                  foreach( $fm_sources as $l_source_path )
1370                  {
1371                      // echo '<br>'.$lSourcePath;
1372                      $fm_source_Filelist->add_by_subpath( urldecode($l_source_path), true );
1373                  }
1374              }
1375              else
1376              { // Without SourceList there's no mode
1377                  $fm_mode = false;
1378              }
1379          }
1380          else
1381          {
1382              $fm_source_Filelist = false;
1383              $fm_sources = NULL;
1384              $fm_sources_root = NULL;
1385          }
1386  
1387          if( ! $fm_source_Filelist || ! $fm_source_Filelist->count() )
1388          {
1389              $Messages->add( T_('No source files!'), 'error' );
1390              $fm_mode = NULL;
1391              break;
1392          }
1393  
1394          param( 'confirm', 'integer', 0 );
1395          param( 'new_names', 'array/string', array() );
1396          param( 'overwrite', 'array/integer', array() );
1397  
1398          // Check params for each file to rename:
1399          while( $loop_src_File = & $fm_source_Filelist->get_next() )
1400          {
1401              if( ! $loop_src_File->exists() )
1402              { // this can happen on reloading the page
1403                  $fm_source_Filelist->remove($loop_src_File);
1404                  continue;
1405              }
1406              if( ! isset( $new_names[$loop_src_File->get_md5_ID()] ) )
1407              { // We have not yet provided a name to rename to...
1408                  $confirm = 0;
1409                  $new_names[$loop_src_File->get_md5_ID()] = $loop_src_File->get('name');
1410                  continue;
1411              }
1412  
1413              // Check if provided name is okay:
1414              $new_names[$loop_src_File->get_md5_ID()] = trim(strip_tags($new_names[$loop_src_File->get_md5_ID()]));
1415  
1416              if( !$loop_src_File->is_dir() )
1417              {
1418                  if( $error_filename = validate_filename( $new_names[$loop_src_File->get_md5_ID()] ) )
1419                  { // Not a file name or not an allowed extension
1420                      $confirm = 0;
1421                      $Messages->add( $error_filename , 'error' );
1422                      continue;
1423                  }
1424              }
1425              elseif( $error_dirname = validate_dirname( $new_names[$loop_src_File->get_md5_ID()] ) )
1426              { // Not a directory name
1427                  $confirm = 0;
1428                  $Messages->add( $error_dirname, 'error' );
1429                  continue;
1430              }
1431  
1432              // If the source is a directory, then we must check if the target path length is allowed or not
1433              $FileCache = & get_FileCache();
1434              $dest_File = & $FileCache->get_by_root_and_path( $fm_Filelist->get_root_type(), $fm_Filelist->get_root_ID(), $fm_Filelist->get_rds_list_path().$new_names[$loop_src_File->get_md5_ID()] );
1435              if( $loop_src_File->is_dir() && ( strlen( $dest_File->get_full_path() ) > $dirpath_max_length ) )
1436              { // The path would be too long we can not allowe to move this folder
1437                  param_error( 'new_names['.$loop_src_File->get_md5_ID().']', T_('The target path is too long for this folder.') );
1438                  $confirm = 0;
1439                  continue;
1440              }
1441  
1442              // Check if destination file exists:
1443              if( $dest_File && $dest_File->exists() )
1444              { // Target exists
1445                  if( $dest_File === $loop_src_File )
1446                  {
1447                      param_error( 'new_names['.$loop_src_File->get_md5_ID().']', T_('Source and target files are the same. Please choose another name or directory.') );
1448                      $confirm = 0;
1449                      continue;
1450                  }
1451  
1452                  if( ! isset( $overwrite[$loop_src_File->get_md5_ID()] ) )
1453                  { // We have not yet asked to overwrite:
1454                      param_error( 'new_names['.$loop_src_File->get_md5_ID().']', sprintf( T_('The file &laquo;%s&raquo; already exists.'), $dest_File->get_rdfp_rel_path() ) );
1455                      $overwrite[$loop_src_File->get_md5_ID()] = 0;
1456                      $confirm = 0;
1457                      continue;
1458                  }
1459  
1460                  // We have asked to overwite...
1461                  if( $fm_mode == 'file_copy' )
1462                  { // We are making a copy: no problem, we'll recycle the file ID anyway.
1463                      continue;
1464                  }
1465  
1466                  // We are moving, we'll need to unlink the target file and drop it's meta data:
1467                  // Check if there are delete restrictions on this file:
1468                  $restriction_Messages = $dest_File->check_relations( 'delete_restrictions' );
1469  
1470                  if( $restriction_Messages->count() )
1471                  { // There are restrictions:
1472                      // TODO: work on a better output display here...
1473                      param_error( 'new_names['.$loop_src_File->get_md5_ID().']', sprintf( T_('Cannot overwrite the file &laquo;%s&raquo; because of the following relations'), $dest_File->get_rdfp_rel_path() ) );
1474  
1475                      $confirm = 0;
1476                      break;    // stop whole file list processing
1477                  }
1478              }
1479          }
1480  
1481          if( $confirm && $fm_source_Filelist->count() )
1482          { // Copy/move is confirmed (and we still have files to copy/move), let's proceed:
1483  
1484              // Check that this action request is not a CSRF hacked request:
1485              $Session->assert_received_crumb( 'file' );
1486  
1487              // Loop through files:
1488              $fm_source_Filelist->restart();
1489              while( $loop_src_File = & $fm_source_Filelist->get_next() )
1490              {
1491                  // Get a pointer on dest file
1492                  $FileCache = & get_FileCache();
1493                  $dest_File = & $FileCache->get_by_root_and_path( $fm_Filelist->get_root_type(), $fm_Filelist->get_root_ID(), $fm_Filelist->get_rds_list_path().$new_names[$loop_src_File->get_md5_ID()] );
1494  
1495                  if( $fm_mode == 'file_copy' )
1496                  { // COPY
1497  
1498                      // Do the copy
1499                      if( $loop_src_File->copy_to( $dest_File ) )
1500                      { // Success:
1501                          $Messages->add( sprintf( T_('Copied &laquo;%s&raquo; to &laquo;%s&raquo;.'),
1502                                                                          $loop_src_File->get_rdfp_rel_path(), $dest_File->get_rdfp_rel_path() ), 'success' );
1503  
1504                          if( $fm_Filelist->contains( $dest_File ) === false )
1505                          {
1506                              $fm_Filelist->add( $dest_File );
1507                          }
1508                      }
1509                      else
1510                      { // Failure:
1511                          param_error( 'new_names['.$loop_src_File->get_md5_ID().']', sprintf( T_('Could not copy &laquo;%s&raquo; to &laquo;%s&raquo;.'),
1512                                                                          $loop_src_File->get_rdfp_rel_path(), $dest_File->get_rdfp_rel_path() ) );
1513                      }
1514                      // Redirect so that a reload doesn't write to the DB twice:
1515                      header_redirect( '?ctrl=files&blog='.$blog.'&root='.$root.'&path='.$path, 303 ); // Will EXIT
1516                      // We have EXITed already at this point!!
1517                  }
1518                  elseif( $fm_mode == 'file_move' )
1519                  { // MOVE
1520                      // NOTE: DB integrity is handled by the File object itself
1521                      $DB->begin();
1522  
1523                      if( isset( $overwrite[$loop_src_File->get_md5_ID()] )
1524                              && $overwrite[$loop_src_File->get_md5_ID()] )
1525                      { // We want to overwrite, let's unlink the old file:
1526                          if( ! $dest_File->unlink() )
1527                          { // Unlink failed:
1528                              $DB->rollback();
1529  
1530                              $Messages->add( sprintf( ( $dest_File->is_dir() ? T_('Could not delete the directory &laquo;%s&raquo; (not empty?).') : T_('Could not delete the file &laquo;%s&raquo;.') ), $dest_File->dget('name') ), 'error' );
1531  
1532                              // Move on to next file:
1533                              continue;
1534                          }
1535                      }
1536  
1537                      // Do the move:
1538                      $rdfp_oldpath = $loop_src_File->get_rdfp_rel_path();
1539                      $rdfp_newpath = $fm_Filelist->get_rds_list_path().$new_names[$loop_src_File->get_md5_ID()];
1540  
1541                      if( $loop_src_File->move_to( $fm_Filelist->get_root_type(), $fm_Filelist->get_root_ID(), $rdfp_newpath ) )
1542                      { // successfully moved
1543                          $Messages->add( sprintf( T_('Moved &laquo;%s&raquo; to &laquo;%s&raquo;.'), $rdfp_oldpath, $rdfp_newpath ), 'success' );
1544  
1545                          // We may have moved in same dir, update caches:
1546                          $fm_Filelist->update_caches();
1547                          // We remove the file from the source list, after refreshing the cache
1548                          $fm_source_Filelist->update_caches();
1549                          $fm_source_Filelist->remove( $loop_src_File );
1550  
1551                          if( $fm_Filelist->contains( $loop_src_File ) === false )
1552                          { // File not in filelist (expected if not same dir)
1553                              $fm_Filelist->add( $loop_src_File );
1554                          }
1555                      }
1556                      else
1557                      { // move failed
1558                          param_error( 'new_names['.$loop_src_File->get_md5_ID().']', sprintf( T_('Could not move &laquo;%s&raquo; to &laquo;%s&raquo;.'), $rdfp_oldpath, $rdfp_newpath ) );
1559                          // Note: we do not rollback, since unlinking is already done on disk :'(
1560                      }
1561  
1562                      $DB->commit();
1563                      // Redirect so that a reload doesn't write to the DB twice:
1564                      header_redirect( '?ctrl=files&blog='.$blog.'&root='.$root.'&path='.$path, 303 ); // Will EXIT
1565                      // We have EXITed already at this point!!
1566                  }
1567                  else debug_die( 'Unhandled file copy/move mode' );
1568              }
1569  
1570              // EXIT MODE:
1571              $fm_mode = NULL;
1572          }
1573          break;
1574  
1575  
1576      case 'link_object':
1577          // We want to link file(s) to an object or view linked files to an object:
1578          // TODO: maybe this should not be a mode and maybe we should handle linking as soon as we have an $edited_Item ...
1579  
1580          // Add JavaScript to handle links modifications.
1581          require_js( 'links.js' );
1582  
1583          if( !isset( $LinkOwner ) )
1584          { // No Object to link to...
1585              $fm_mode = NULL;
1586              break;
1587          }
1588  
1589          $LinkOwner->check_perm( 'view', true );
1590          break;
1591  
1592  }
1593  
1594  
1595  // fp> TODO: this here is a bit sketchy since we have Blog & fileroot not necessarilly in sync. Needs investigation / propositions.
1596  // Note: having both allows to post from any media dir into any blog.
1597  $AdminUI->breadcrumbpath_init( false );
1598  $AdminUI->breadcrumbpath_add( T_('Files'), '?ctrl=files&amp;blog=$blog$' );
1599  if( !isset($Blog) || $fm_FileRoot->type != 'collection' || $fm_FileRoot->in_type_ID != $Blog->ID )
1600  {    // Display only if we're not browsing our home blog
1601      $AdminUI->breadcrumbpath_add( $fm_FileRoot->name, '?ctrl=files&amp;blog=$blog$&amp;root='.$fm_FileRoot->ID,
1602              (isset($Blog) && $fm_FileRoot->type == 'collection') ? sprintf( T_('You are ready to post files from %s into %s...'),
1603              $fm_FileRoot->name, $Blog->get('shortname') ) : '' );
1604  }
1605  
1606  // require colorbox js
1607  require_js_helper( 'colorbox' );
1608  
1609  // Display <html><head>...</head> section! (Note: should be done early if actions do not redirect)
1610  $AdminUI->disp_html_head();
1611  
1612  // Display title, menu, messages, etc. (Note: messages MUST be displayed AFTER the actions)
1613  $AdminUI->disp_body_top();
1614  
1615  // Display reload-icon in the opener window if we're a popup in the same CWD and the
1616  // Filemanager content differs.
1617  ?>
1618  <script type="text/javascript">
1619      <!--
1620      if( opener
1621              && opener.document.FilesForm
1622              && typeof(opener.document.FilesForm.md5_filelist.value) != 'undefined'
1623              && typeof(opener.document.FilesForm.md5_cwd.value) != 'undefined'
1624              && opener.document.FilesForm.md5_cwd.value == '<?php echo md5($fm_Filelist->get_ads_list_path()); ?>'
1625          )
1626      {
1627          opener.document.getElementById( 'fm_reloadhint' ).style.display =
1628              opener.document.FilesForm.md5_filelist.value == '<?php echo $fm_Filelist->md5_checksum(); ?>'
1629              ? 'none'
1630              : 'inline';
1631      }
1632      // -->
1633  </script>
1634  <?php
1635  
1636  $AdminUI->disp_payload_begin();
1637  
1638  /*
1639   * Display payload:
1640   */
1641  if( !empty($action ) && $action != 'list' && $action != 'nil' )
1642  {
1643  
1644      // Action displays:
1645      switch( $action )
1646      {
1647          case 'rename':
1648              // Rename files dialog:
1649              $AdminUI->disp_view( 'files/views/_file_rename.form.php' );
1650              break;
1651  
1652          case 'delete':
1653              // Delete file(s). We arrive here either if not confirmed or in case of error(s).
1654              $AdminUI->disp_view( 'files/views/_file_delete.form.php' );
1655              break;
1656  
1657          case 'download':
1658              $AdminUI->disp_view( 'files/views/_file_download.form.php' );
1659              break;
1660  
1661          case 'edit_perms':
1662              // Filesystem permissions for specific files
1663              $AdminUI->disp_view( 'files/views/_file_permissions.form.php' );
1664              break;
1665  
1666          case 'edit_file':
1667              // File Edit dialog:
1668              $AdminUI->disp_view( 'files/views/_file_edit.form.php' );
1669              break;
1670  
1671          case 'edit_properties':
1672              // File properties (Meta data) dialog:
1673              $AdminUI->disp_view( 'files/views/_file_properties.form.php' );
1674              break;
1675  
1676          case 'edit_settings':
1677              // Display settings dialog:
1678              $AdminUI->disp_view( 'files/views/_file_browse_set.form.php' );
1679              break;
1680  
1681          case 'download':
1682              // Deferred action message:
1683              if( isset($action_title) )
1684              {
1685                  echo "\n<h2>$action_title</h2>\n";
1686              }
1687  
1688              if( isset($action_msg) )
1689              {
1690                  echo $action_msg;
1691  
1692                  if( isset( $js_focus ) )
1693                  { // we want to auto-focus a field
1694                      echo '
1695                      <script type="text/javascript">
1696                          <!--
1697                          '.$js_focus.'.focus();
1698                          // -->
1699                      </script>';
1700                  }
1701              }
1702      }
1703  }
1704  
1705  /*
1706   * Diplay mode payload:
1707   */
1708  switch( $fm_mode )
1709  {
1710      case 'file_copy':
1711      case 'file_move':
1712          // CMR dialog:
1713          $AdminUI->disp_view( 'files/views/_file_copy_move.form.php' );
1714          break;
1715  
1716      case 'link_object':
1717          // Links dialog:
1718          $AdminUI->disp_view( 'files/views/_file_links.view.php' );
1719          break;
1720  }
1721  
1722  
1723  // -------------------
1724  // Browsing interface:
1725  // -------------------
1726  // Display VIEW:
1727  $AdminUI->disp_view( 'files/views/_file_browse.view.php' );
1728  
1729  
1730  // End payload block:
1731  $AdminUI->disp_payload_end();
1732  
1733  // Display body bottom, debug info and close </html>:
1734  $AdminUI->disp_global_footer();
1735  
1736  ?>

title

Description

title

Description

title

Description

title

title

Body