/**
  * {@inheritdoc}
  * @param array $args
  * * source_dir
  * * destinations - {'dir_id': 'destination_path'}
  * * [filesystem_args] - {}|{hostname: '', username: '', password: '', connection_type: ''}
  */
 public function execute(array $args, array $state = array())
 {
     $backups = fw_ext('backups');
     /** @var FW_Extension_Backups $backups */
     $upload_dir = wp_upload_dir();
     $upload_dir = fw_fix_path($upload_dir['basedir']);
     if (empty($args['source_dir'])) {
         return new WP_Error('no_source_dir', __('Source dir not specified', 'fw'));
     } else {
         $args['source_dir'] = fw_fix_path($args['source_dir']);
         if (empty($args['source_dir']) || !file_exists($args['source_dir'])) {
             return new WP_Error('invalid_source_dir', __('Invalid source dir', 'fw'));
         }
     }
     if (empty($args['destinations'])) {
         return new WP_Error('no_source', __('Source dirs not specified', 'fw'));
     } else {
         $args['destinations'] = array_map('fw_fix_path', $args['destinations']);
     }
     if (empty($args['skip_dirs'])) {
         $args['skip_dirs'] = array();
     }
     $args['skip_dirs'] = array_merge($args['skip_dirs'], array($backups->get_tmp_dir() => true, $backups->get_backups_dir() => true, $upload_dir . '/backup' => true, fw_get_framework_directory() => true));
     if (empty($state)) {
         $fs_required = false;
         $upload_dir_regex = '/^' . preg_quote($upload_dir, '/') . '/';
         $destinations = array('no_fs' => array(), 'fs' => array());
         foreach ($args['destinations'] as $dir_id => $dir_path) {
             $dir_path = fw_fix_path($dir_path);
             if (!file_exists($args['source_dir'] . '/' . $dir_id) || !file_exists($dir_path)) {
                 continue;
             }
             $is_in_uploads = preg_match($upload_dir_regex, $dir_path);
             $destinations[$is_in_uploads ? 'no_fs' : 'fs'][$dir_id] = array('fs' => !$is_in_uploads, 'dir' => $dir_path);
             if (!$is_in_uploads) {
                 $fs_required = true;
             }
         }
         $destinations = array_merge($destinations['no_fs'], $destinations['fs']);
         if (empty($destinations)) {
             return true;
         }
         $state = array('pending_destinations' => $destinations, 'current_destination' => array('id' => null, 'data' => null), 'fs_required' => $fs_required);
         unset($destinations);
         $state['current_destination']['id'] = key($state['pending_destinations']);
         $state['current_destination']['data'] = array_shift($state['pending_destinations']);
     }
     if ($state['fs_required']) {
         if (!FW_WP_Filesystem::has_direct_access(ABSPATH)) {
             if (empty($args['filesystem_args'])) {
                 return new WP_Error('fs_no_access', __('No filesystem access, credentials required', 'fw'));
             } elseif (!WP_Filesystem($args['filesystem_args'])) {
                 return new WP_Error('invalid_fs_credentials', __('No filesystem access, invalid credentials', 'fw'));
             }
         } else {
             if (!WP_Filesystem()) {
                 return new WP_Error('fs_init_fail', __('Filesystem init failed', 'fw'));
             }
         }
         global $wp_filesystem;
         /** @var WP_Filesystem_Base $wp_filesystem */
         if (!$wp_filesystem || is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code()) {
             return new WP_Error('fs_init_fail', __('Filesystem init failed', 'fw'));
         }
     }
     while ($state['current_destination']['id']) {
         if (is_wp_error($result = $this->clear_dir($state['current_destination']['data']['dir'], $state['current_destination']['data']['fs'], $args['skip_dirs']))) {
             return $result;
         }
         if (is_wp_error($result = $this->copy_dir($args['source_dir'] . '/' . $state['current_destination']['id'], $state['current_destination']['data']['dir'], $state['current_destination']['data']['fs'], $args['skip_dirs']))) {
             return $result;
         }
         $state['current_destination']['id'] = key($state['pending_destinations']);
         $state['current_destination']['data'] = array_shift($state['pending_destinations']);
     }
     return true;
 }
 /**
  * @internal
  */
 public function _action_ajax_check_direct_fs_access()
 {
     if (!$this->can_install()) {
         // if can't install, no need to know if has access or not
         wp_send_json_error();
     }
     if (FW_WP_Filesystem::has_direct_access(fw_get_framework_directory('/extensions'))) {
         wp_send_json_success();
     } else {
         wp_send_json_error();
     }
 }
 /**
  * @internal
  */
 public function _action_ajax_uninstall()
 {
     if (!$this->can_install()) {
         // if can't install, no need to know if has access or not
         wp_send_json_error();
     }
     if (!FW_WP_Filesystem::has_direct_access(fw_get_framework_directory('/extensions'))) {
         wp_send_json_error();
     }
     $extension = (string) FW_Request::POST('extension');
     $install_result = $this->uninstall_extensions(array($extension => array()), array('cancel_on_error' => true));
     if ($install_result === true) {
         wp_send_json_success();
     } else {
         wp_send_json_error($install_result);
     }
 }
 /**
  * @internal
  */
 public function _action_ajax_restore()
 {
     if (!current_user_can($this->get_capability())) {
         wp_send_json_error(new WP_Error('denied', 'Access Denied'));
     }
     $archives = $this->get_archives();
     if (empty($_POST['file']) || !isset($archives[$filename = (string) $_POST['file']])) {
         wp_send_json_error(new WP_Error('no_file', __('File not specified', 'fw')));
     }
     $fs_args = array();
     if ($archives[$filename]['full'] && !FW_WP_Filesystem::has_direct_access(ABSPATH)) {
         if (empty($_POST['filesystem_args'])) {
             wp_send_json_error(array('message' => esc_html__('Filesystem access required', 'fw'), 'request_fs' => true));
         } else {
             $fs_args = $_POST['filesystem_args'];
             if (is_array($_POST['filesystem_args']) && isset($fs_args['hostname']) && is_string($fs_args['hostname']) && isset($fs_args['username']) && is_string($fs_args['username']) && isset($fs_args['password']) && is_string($fs_args['password']) && isset($fs_args['connection_type']) && is_string($fs_args['connection_type'])) {
                 $fs_args = array('hostname' => $fs_args['hostname'], 'username' => $fs_args['username'], 'password' => $fs_args['password'], 'connection_type' => $fs_args['connection_type']);
                 if (!WP_Filesystem($fs_args, ABSPATH)) {
                     wp_send_json_error(array('message' => esc_html__('Invalid filesystem credentials', 'fw')));
                 }
             } else {
                 wp_send_json_error(array('message' => esc_html__('Invalid filesystem credentials', 'fw')));
             }
         }
     }
     $this->tasks()->do_restore($archives[$filename]['full'] && fw_ext_backups_current_user_can_full(), $archives[$filename]['path'], $fs_args);
     wp_send_json_success();
 }