/**
  * {@inheritdoc}
  * @param $args
  * * destination_dir - Path to dir where the downloaded files must be placed
  * * source - Path to dir or zip file
  */
 public function download(array $args, array $state = array())
 {
     // Note: destination_dir is already validated
     if (empty($args['source'])) {
         return new WP_Error('no_source', __('Source not specified', 'fw'));
     } elseif (!($args['source'] = fw_fix_path(realpath($args['source'])))) {
         return new WP_Error('invalid_source', __('Invalid source', 'fw'));
     } elseif (!($is_dir = is_dir($args['source'])) || !($is_zip = substr($args['source'], -4, 4) !== '.zip')) {
         return new WP_Error('invalid_source_type', __('Invalid source type', 'fw'));
     }
     if ($is_dir) {
         return fw_ext_backups_copy_dir_recursive($args['source'], $args['destination_dir']);
     } elseif ($is_zip) {
         if (!class_exists('ZipArchive')) {
             return new WP_Error('zip_ext_missing', __('Zip extension missing', 'fw'));
         }
         $zip = new ZipArchive();
         if (true === $zip->open($args['source'])) {
             return new WP_Error('zip_open_fail', sprintf(__('Cannot open zip: %s', 'fw'), $args['source']));
         }
         $zip->extractTo($args['destination_dir']);
         $zip->close();
         unset($zip);
         return true;
     } else {
         return new WP_Error('unhandled_type', __('Unhandled type', 'fw'));
     }
 }
 /**
  * {@inheritdoc}
  * @param array $args
  * * zip - file path
  * * dir - where the zip file will be extract
  */
 public function execute(array $args, array $state = array())
 {
     if (!isset($args['zip'])) {
         return new WP_Error('no_zip', __('Zip file not specified', 'fw'));
     } else {
         $args['zip'] = fw_fix_path($args['zip']);
     }
     if (!isset($args['dir'])) {
         return new WP_Error('no_dir', __('Destination dir not specified', 'fw'));
     } else {
         $args['dir'] = fw_fix_path($args['dir']);
     }
     if (empty($state)) {
         if (!fw_ext_backups_is_dir_empty($args['dir'])) {
             return new WP_Error('destination_not_empty', __('Destination dir is not empty', 'fw'));
         }
         $state = array('entry' => '', 'extracted_files' => 0);
     }
     wp_cache_flush();
     FW_Cache::clear();
     if (is_wp_error($extract_result = fw_ext_backups_unzip_partial($args['zip'], $args['dir'], $state['entry']))) {
         return $extract_result;
     } else {
         if ($extract_result['finished']) {
             return true;
         } else {
             $state['entry'] = $extract_result['last_entry'];
             $state['extracted_files'] += $extract_result['extracted_files'];
             return $state;
         }
     }
 }
 /**
  * @return FW_Ext_Backups_Demo[]
  */
 private function get_demos()
 {
     if (is_null(self::$demos)) {
         $demos = array();
         foreach (apply_filters('fw_ext_backups_demo_dirs', array(fw_fix_path(get_template_directory()) . '/demo-content' => get_template_directory_uri() . '/demo-content')) as $dir_path => $dir_uri) {
             if (!is_dir($dir_path) || !($dirs = glob($dir_path . '/*', GLOB_ONLYDIR))) {
                 continue;
             }
             foreach (array_map('fw_fix_path', $dirs) as $demo_dir) {
                 $demo_dir_name = basename($demo_dir);
                 if (!file_exists($demo_dir . '/manifest.php')) {
                     continue;
                 }
                 $manifest = fw_get_variables_from_file($demo_dir . '/manifest.php', array('manifest' => array()), array('uri' => $dir_uri . '/' . $demo_dir_name));
                 $manifest = array_merge(array('title' => fw_id_to_title($demo_dir_name), 'screenshot' => fw_get_framework_directory_uri('/static/img/no-image.png'), 'preview_link' => '', 'extra' => array()), $manifest['manifest']);
                 $demo = new FW_Ext_Backups_Demo('local-' . md5($demo_dir), 'local', array('source' => $demo_dir));
                 $demo->set_title($manifest['title']);
                 $demo->set_screenshot($manifest['screenshot']);
                 $demo->set_preview_link($manifest['preview_link']);
                 $demo->set_extra($manifest['extra']);
                 $demos[$demo->get_id()] = $demo;
                 unset($demo);
             }
         }
         self::$demos = array_merge(apply_filters('fw:ext:backups-demo:demos', array()), $demos);
     }
     return self::$demos;
 }
/**
 * @param string $source_dir
 * @param string $destination_dir
 * @return bool|WP_Error
 */
function fw_ext_backups_copy_dir_recursive($source_dir, $destination_dir)
{
    $source_dir = fw_fix_path($source_dir);
    $destination_dir = fw_fix_path($destination_dir);
    $dir_chmod = 0755;
    if (!file_exists($destination_dir)) {
        if (!mkdir($destination_dir, $dir_chmod)) {
            return new WP_Error('mkdir_fail', sprintf(__('Failed to create dir: %s'), $destination_dir));
        }
    }
    try {
        foreach ($iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source_dir), RecursiveIteratorIterator::SELF_FIRST) as $item) {
            if (in_array(basename($iterator->getSubPathName()), array('.', '..'), true)) {
                continue;
                // We can't use RecursiveDirectoryIterator::SKIP_DOTS, it was added in php 5.3
            }
            $destination_path = $destination_dir . '/' . $iterator->getSubPathName();
            if ($item->isDir()) {
                if (!mkdir($destination_path, $dir_chmod)) {
                    return new WP_Error('mk_sub_dir_fail', sprintf(__('Failed to create dir: %s'), $destination_path));
                }
            } else {
                if (!copy($item->getPathname(), $destination_path)) {
                    return new WP_Error('copy_fail', sprintf(__('Failed to copy: %s'), $destination_path));
                }
            }
        }
    } catch (UnexpectedValueException $e) {
        return new WP_Error('dir_copy_fail', (string) $e->getMessage());
    }
    return true;
}
 /**
  * {@inheritdoc}
  * @param array $args
  * * uploads_dir - path to exported uploads dir (not the actual WP uploads dir! that remains untouched)
  */
 public function execute(array $args, array $state = array())
 {
     $backups = fw_ext('backups');
     if (empty($args['uploads_dir'])) {
         return new WP_Error('no_uploads_dir', __('Uploads dir not specified', 'fw'));
     } else {
         $args['uploads_dir'] = fw_fix_path($args['uploads_dir']);
         if (!file_exists($args['uploads_dir'])) {
             /**
              * The uploads directory was not exported, nothing to do.
              */
             return true;
         }
     }
     if (empty($state)) {
         $state = array('attachment_id' => 0);
     }
     /**
      * @var WPDB $wpdb
      */
     global $wpdb;
     $sql = implode(array("SELECT * FROM {$wpdb->posts}", "WHERE post_type = 'attachment' AND post_mime_type LIKE %s AND ID > %d", "ORDER BY ID", "LIMIT 7"), " \n");
     $wp_uploads_dir = wp_upload_dir();
     $wp_uploads_dir_length = mb_strlen($wp_uploads_dir['basedir']);
     $started_time = time();
     $timeout = $backups->get_timeout() - 7;
     while (time() - $started_time < $timeout) {
         $attachments = $wpdb->get_results($wpdb->prepare($sql, $wpdb->esc_like('image/') . '%', $state['attachment_id']), ARRAY_A);
         if (empty($attachments)) {
             return true;
         }
         foreach ($attachments as $attachment) {
             if (($meta = wp_get_attachment_metadata($attachment['ID'])) && isset($meta['sizes']) && is_array($meta['sizes'])) {
                 $attachment_path = get_attached_file($attachment['ID']);
                 $filename_length = mb_strlen(basename($attachment_path));
                 foreach ($meta['sizes'] as $size => $sizeinfo) {
                     // replace wp_uploads_dir path
                     $file_path = $args['uploads_dir'] . mb_substr($attachment_path, $wp_uploads_dir_length);
                     // replace file name with resize name
                     $file_path = mb_substr($file_path, 0, -$filename_length) . $sizeinfo['file'];
                     if (file_exists($file_path)) {
                         @unlink($file_path);
                     }
                 }
             }
             if (is_array($backup_sizes = get_post_meta($attachment['ID'], '_wp_attachment_backup_sizes', true))) {
                 foreach ($backup_sizes as $size) {
                     $del_file = path_join(dirname($meta['file']), $size['file']);
                     @unlink(path_join($args['uploads_dir'], $del_file));
                 }
             }
         }
         $state['attachment_id'] = $attachment['ID'];
     }
     return $state;
 }
 /**
  * {@inheritdoc}
  * @param array $args
  * * source_dir - everything from this directory will be added in zip
  * * destination_dir - where the zip file will be created
  *
  * Warning!
  *  Zip can't be executed in steps, it will execute way too long,
  *  because it is impossible to update a zip file, every time you add a file to zip,
  *  a new temp copy of original zip is created with new modifications, it is compressed,
  *  and the original zip is replaced. So when the zip will grow in size,
  *  just adding a single file, will take a very long time.
  */
 public function execute(array $args, array $state = array())
 {
     if (!isset($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 (!isset($args['destination_dir'])) {
         return new WP_Error('no_destination_dir', __('Destination dir not specified', 'fw'));
     } else {
         $args['destination_dir'] = fw_fix_path($args['destination_dir']);
     }
     if (!class_exists('ZipArchive')) {
         return new WP_Error('zip_ext_missing', __('Zip extension missing', 'fw'));
     }
     $zip_path = $args['source_dir'] . '/' . implode('-', array('fw-backup', date('Y_m_d-H_i_s'), fw_ext('backups')->manifest->get_version())) . '.zip';
     $zip = new ZipArchive();
     if (false === ($zip_error_code = $zip->open($zip_path, ZipArchive::CREATE))) {
         return new WP_Error('cannot_open_zip', sprintf(__('Cannot open zip (Error code: %s)', 'fw'), $zip_error_code));
     }
     $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($args['source_dir']), RecursiveIteratorIterator::LEAVES_ONLY);
     foreach ($files as $name => $file) {
         if (!$file->isDir()) {
             // Skip directories (they would be added automatically)
             if (($file_path = $file->getRealPath()) !== $zip_path) {
                 $zip->addFile($file_path, substr(fw_fix_path($file_path), strlen($args['source_dir']) + 1));
             }
         }
     }
     wp_cache_flush();
     FW_Cache::clear();
     // Zip archive will be created only after closing object
     if (!$zip->close()) {
         return new WP_Error('cannot_close_zip', __('Cannot close the zip file', 'fw'));
     }
     if (!rename($zip_path, $args['destination_dir'] . '/' . basename($zip_path))) {
         return new WP_Error('cannot_move_zip', __('Cannot move zip in destination dir', 'fw'));
     }
     return true;
 }
 /**
  * {@inheritdoc}
  * @param array $args
  * * dir - source directory in which is located `database.json.txt`
  * * [full] - (bool) force full or content restore. if not specified, will be detected automatically
  * * [required] - (default: false) if database file must exist, else if db restore is optional
  */
 public function execute(array $args, array $state = array())
 {
     if (!isset($args['dir'])) {
         return new WP_Error('no_source_dir', __('Source dir not specified', 'fw'));
     } else {
         $args['dir'] = fw_fix_path($args['dir']);
     }
     if (!isset($args['required'])) {
         $args['required'] = false;
     } else {
         $args['required'] = (bool) $args['required'];
     }
     if (empty($state)) {
         if (!file_exists($args['dir'] . '/database.json.txt')) {
             if ($args['required']) {
                 return new WP_Error('no_db_file', __('Database file not found', 'fw'));
             } else {
                 return true;
             }
         }
         $state = array('task' => 'cleanup', 'step' => 0, 'params' => array(), 'tables' => array(), 'full' => isset($args['full']) ? (bool) $args['full'] : null);
     }
     if (!class_exists('SplFileObject')) {
         return new WP_Error('no_spl_file_object', __('PHP class SplFileObject is required but not available. Please contact your hosting', 'fw'));
     }
     if ($state['task'] === 'cleanup') {
         return $this->do_cleanup($args, $state);
     } elseif ($state['task'] === 'inspect') {
         return $this->do_inspect($args, $state);
     } elseif ($state['task'] === 'import') {
         return $this->do_import($args, $state);
     } elseif ($state['task'] === 'keep:options') {
         return $this->do_keep_options($args, $state);
     } elseif ($state['task'] === 'replace') {
         return $this->do_replace($args, $state);
     } else {
         return new WP_Error('invalid_sub_task', sprintf(__('Invalid sub task %s', 'fw'), $state['task']));
     }
     return $state;
 }
 private function get_wp_fs_tmp_dir()
 {
     return FW_WP_Filesystem::real_path_to_filesystem_path(apply_filters('fw_tmp_dir', fw_fix_path(WP_CONTENT_DIR) . '/tmp'));
 }
 private static function get_path()
 {
     if (is_null(self::$path)) {
         self::$path = wp_upload_dir();
         self::$path = fw_fix_path(self::$path['basedir']) . '/fw/file-cache.php';
     }
     return self::$path;
 }
 /**
  * Add restore tasks to a collection
  * @param FW_Ext_Backups_Task_Collection $collection
  * @param bool $full
  * @param string|null $zip_path
  * @param array $filesystem_args {}|{hostname: '', username: '', password: '', connection_type: ''}
  * @return FW_Ext_Backups_Task_Collection
  */
 public function add_restore_tasks(FW_Ext_Backups_Task_Collection $collection, $full = false, $zip_path = null, $filesystem_args = array())
 {
     $full = (bool) $full;
     $tmp_dir = self::backups()->get_tmp_dir();
     $dirs = $this->get_dirs($full);
     $id_prefix = 'restore:';
     if ($zip_path) {
         $collection->add_task(new FW_Ext_Backups_Task($id_prefix . 'unzip', 'unzip', array('zip' => $zip_path, 'dir' => $tmp_dir)));
     }
     $collection->add_task(new FW_Ext_Backups_Task($id_prefix . 'files-restore', 'files-restore', array('source_dir' => $tmp_dir . '/f', 'destinations' => $dirs, 'filesystem_args' => $filesystem_args, 'skip_dirs' => is_multisite() && ($wp_upload_dir = wp_upload_dir()) ? array(fw_fix_path($wp_upload_dir['basedir']) . '/sites' => true) : array())));
     $collection->add_task(new FW_Ext_Backups_Task($id_prefix . 'db-restore', 'db-restore', array('dir' => $tmp_dir, 'full' => $full)));
     if (!$full && apply_filters('fw:ext:backups:add-restore-task:image-sizes-restore', true, $collection)) {
         $collection->add_task(new FW_Ext_Backups_Task($id_prefix . 'image-sizes-restore', 'image-sizes-restore', array()));
     }
     $collection->add_task(new FW_Ext_Backups_Task($id_prefix . 'tmp-dir-clean:after', 'dir-clean', array('dir' => $tmp_dir)));
     /** @since 2.0.16 */
     do_action('fw:ext:backups:add-restore-tasks', $collection, array('is_full' => $full, 'tmp_dir' => $tmp_dir, 'dirs' => $dirs));
     return $collection;
 }
 private function get_tmp_dir($append = '')
 {
     return apply_filters('fw_tmp_dir', fw_fix_path(WP_CONTENT_DIR) . '/tmp') . $append;
 }
 /**
  * {@inheritdoc}
  * @param array $args
  *  * type - registered download type
  *  * type_args - args for registered type instance
  *  * destination_dir - Where must be placed the downloaded files
  */
 public function execute(array $args, array $state = array())
 {
     if (empty($args['destination_dir'])) {
         return new WP_Error('no_destination_dir', __('Destination dir not specified', 'fw'));
     } elseif (!($args['destination_dir'] = fw_fix_path($args['destination_dir']))) {
         return new WP_Error('invalid_destination_dir', __('Invalid destination dir', 'fw'));
     }
     if (empty($args['type']) || !($type = self::get_types()) || !isset($type[$args['type']])) {
         return new WP_Error('invalid_type', sprintf(__('Invalid type: %s', 'fw'), $args['type']));
     }
     $type = $type[$args['type']];
     if (empty($args['type_args'])) {
         return new WP_Error('no_type_args', sprintf(__('Args not specified for type: %s', 'fw'), $type->get_type()));
     }
     $args['type_args'] = array_merge($args['type_args'], array('destination_dir' => $args['destination_dir']));
     return $type->download($args['type_args'], $state);
 }
 /**
  * Create wp filesystem directory recursive
  * @param string $wp_filesystem_dir_path
  * @return bool
  */
 public static final function mkdir_recursive($wp_filesystem_dir_path)
 {
     /** @var WP_Filesystem_Base $wp_filesystem */
     global $wp_filesystem;
     if (!$wp_filesystem) {
         trigger_error('Filesystem is not available', E_USER_WARNING);
         return false;
     }
     $wp_filesystem_dir_path = fw_fix_path($wp_filesystem_dir_path);
     $path = '';
     $check_if_exists = true;
     $firs_loop = true;
     foreach (explode('/', $wp_filesystem_dir_path) as $dir_name) {
         if (empty($dir_name)) {
             if ($firs_loop) {
                 // in first loop $dir_name can be empty because it's starting with
             } else {
                 trigger_error('Invalid path: ' . $wp_filesystem_dir_path, E_USER_WARNING);
                 return false;
             }
         }
         $firs_loop = false;
         $path .= '/' . $dir_name;
         if ($check_if_exists) {
             if ($wp_filesystem->is_dir($path)) {
                 // do nothing if exists
                 continue;
             } else {
                 // do not check anymore, next directories sure does not exists
                 $check_if_exists = false;
             }
         }
         $wp_filesystem->mkdir($path, FS_CHMOD_DIR);
     }
     return true;
 }
 /**
  * @internal
  */
 public function _action_update_framework()
 {
     $nonce_name = '_nonce_fw_ext_update_framework';
     if (!isset($_POST[$nonce_name]) || !wp_verify_nonce($_POST[$nonce_name])) {
         wp_die(__('Invalid nonce.', 'fw'));
     }
     if (!class_exists('_FW_Ext_Update_Framework_Upgrader_Skin')) {
         fw_include_file_isolated($this->get_declared_path('/includes/classes/class--fw-ext-update-framework-upgrader-skin.php'));
     }
     $skin = new _FW_Ext_Update_Framework_Upgrader_Skin(array('title' => __('Update Framework', 'fw')));
     require_once ABSPATH . 'wp-admin/admin-header.php';
     $skin->header();
     $update = $this->get_framework_update(true);
     do {
         if ($update === false) {
             $skin->error(__('Failed to get framework latest version.', 'fw'));
             break;
         } elseif (is_wp_error($update)) {
             $skin->error($update);
             break;
         }
         $context = $this->context;
         if (!FW_WP_Filesystem::request_access($context, fw_current_url(), array($nonce_name))) {
             break;
         }
         $this->maintenance_mode(true);
         /** @var WP_Filesystem_Base $wp_filesystem */
         global $wp_filesystem;
         $tmp_download_dir = FW_WP_Filesystem::real_path_to_filesystem_path(fw_fix_path(WP_CONTENT_DIR) . '/cache/framework/update');
         // just in case it already exists, clear everything, it may contain broken/old files
         $wp_filesystem->rmdir($tmp_download_dir, true);
         if (!FW_WP_Filesystem::mkdir_recursive($tmp_download_dir)) {
             $skin->error(__('Cannot create directory: ' . $tmp_download_dir, 'fw'));
             break;
         }
         $skin->feedback(__('Downloading framework...', 'fw'));
         /** @var FW_Ext_Update_Service $service */
         $service = $this->get_child($update['service']);
         $downloaded_files_dir = $service->_download_framework($update['latest_version'], $tmp_download_dir);
         if (!$downloaded_files_dir) {
             $skin->error(__('Failed to download framework.', 'fw'));
             break;
         } elseif (is_wp_error($downloaded_files_dir)) {
             $skin->error($downloaded_files_dir);
             break;
         }
         $skin->feedback(__('Installing framework...', 'fw'));
         $framework_dir = FW_WP_Filesystem::real_path_to_filesystem_path(fw_get_framework_directory());
         // remove entire framework directory
         $wp_filesystem->rmdir($framework_dir, true);
         // move downloaded directory as new framework directory
         $wp_filesystem->move($downloaded_files_dir, $framework_dir);
         $skin->feedback(__('Framework updated.', 'fw'));
         $wp_filesystem->delete($tmp_download_dir, true, 'd');
         $skin->set_result(true);
         $skin->after();
     } while (false);
     $this->maintenance_mode(false);
     $skin->footer();
     require_once ABSPATH . 'wp-admin/admin-footer.php';
 }
 private function get_dirs($full = false)
 {
     $wp_upload_dir = wp_upload_dir();
     $dirs = array('uploads' => fw_fix_path($wp_upload_dir['basedir']), 'plugins' => fw_fix_path(WP_PLUGIN_DIR), 'themes' => fw_fix_path(get_theme_root()));
     if (is_multisite() && WPMU_PLUGIN_DIR) {
         $dirs['mu-plugins'] = fw_fix_path(WPMU_PLUGIN_DIR);
     }
     if (!$full) {
         unset($dirs['plugins']);
         unset($dirs['mu-plugins']);
         unset($dirs['themes']);
     }
     return $dirs;
 }
Example #16
0
/**
 * Try everything to create and make a path (file or directory) writable
 * Works only within /wp-content dir, cannot make writable something outside it
 * @param string $path
 * @return bool
 * @deprecated It's not safe to make files writable or create files as php user. Use http://codex.wordpress.org/Filesystem_API
 */
function fw_try_make_writable($path)
{
    static $root_dir = null;
    if ($root_dir === null) {
        $root_dir = fw_fix_path(WP_CONTENT_DIR);
    }
    $chmod_writable_dir = 0777;
    $chmod_writable_file = 0666;
    do {
        if (is_writable($path)) {
            return true;
        }
        $path = fw_fix_path($path);
        $rel_path = explode($root_dir, $path);
        if (!empty($rel_path[0])) {
            break;
        }
        // is not located in root dir
        array_shift($rel_path);
        // remove first empty element
        $rel_path = implode($root_dir, $rel_path);
        $rel_path_arr = explode('/', $rel_path);
        array_shift($rel_path_arr);
        // remove first empty element
        if (empty($rel_path_arr)) {
            break;
        }
        $file_name = '';
        if (!is_dir($path)) {
            if (file_exists($path)) {
                // file exists, we can only try to make it writable
                if (@chmod($path, $chmod_writable_file)) {
                    true;
                } else {
                    break;
                }
            }
            $file_name = array_pop($rel_path_arr);
        }
        if (!empty($rel_path_arr)) {
            // check if parent directories exists, if not, create and make writable
            $dir_path = $root_dir . '/' . implode('/', $rel_path_arr);
            if (!file_exists($dir_path)) {
                $created = @mkdir($dir_path, $chmod_writable_dir, true);
                if (!$created) {
                    break;
                }
            }
            if (!is_writable($dir_path)) {
                if (@chmod($dir_path, $chmod_writable_dir)) {
                    true;
                } else {
                    break;
                }
            }
        }
        if ($file_name) {
            // file not exists, need to create
            if (false === file_put_contents($path, '')) {
                break;
            }
            if (is_writable($path)) {
                return true;
            }
            if (@chmod($path, $chmod_writable_file)) {
                true;
            } else {
                break;
            }
        }
        return true;
    } while (false);
    return false;
}
Example #17
0
    /** @deprecated */
    define('FW_CT_EXTENSIONS_URI', FW_CT_CUSTOM_URI . '/extensions');
}
/** @deprecated */
define('FW_PT_DIR', fw_fix_path(get_template_directory()));
/** @deprecated */
define('FW_PT_CUSTOM_DIR', FW_PT_DIR . '/framework-customizations');
/** @deprecated */
define('FW_PT_THEME_DIR', FW_PT_CUSTOM_DIR . '/theme');
/** @deprecated */
define('FW_PT_EXTENSIONS_DIR', FW_PT_CUSTOM_DIR . '/extensions');
/** @deprecated */
define('FW_PT_URI', get_template_directory_uri());
/** @deprecated */
define('FW_PT_CUSTOM_URI', FW_PT_URI . '/framework-customizations');
/** @deprecated */
define('FW_PT_THEME_URI', FW_PT_CUSTOM_URI . '/theme');
/** @deprecated */
define('FW_PT_EXTENSIONS_URI', FW_PT_CUSTOM_URI . '/extensions');
/** @deprecated */
define('FW_DIR', FW_PT_DIR . '/framework');
/** @deprecated */
define('FW_EXTENSIONS_DIR', FW_DIR . '/extensions');
/** @deprecated */
define('FW_URI', FW_PT_URI . '/framework');
/** @deprecated */
define('FW_EXTENSIONS_URI', FW_URI . '/extensions');
/** @deprecated */
define('FW_CACHE_DIR', fw_fix_path(WP_CONTENT_DIR) . '/cache/framework');
/** @deprecated */
define('FW_CACHE_URI', WP_CONTENT_URL . '/cache/framework');
 private function do_install(FW_Ext_Backups_Demo $demo)
 {
     $tmp_dir = self::backups()->get_tmp_dir();
     $wp_upload_dir = wp_upload_dir();
     $dirs = array('uploads' => fw_fix_path($wp_upload_dir['basedir']));
     $id_prefix = 'demo:';
     $collection = new FW_Ext_Backups_Task_Collection(self::$task_collection_id);
     if (!self::backups()->is_disabled()) {
         $collection = self::backups()->tasks()->add_backup_tasks($collection, false);
     }
     $collection->set_title(__('Demo Content Install', 'fw'));
     $collection->add_task(new FW_Ext_Backups_Task($id_prefix . 'tmp-dir-clean:before', 'dir-clean', array('dir' => $tmp_dir)));
     $collection->add_task(new FW_Ext_Backups_Task($id_prefix . 'demo-download', 'download', array('type' => $demo->get_source_type(), 'type_args' => $demo->get_source_args(), 'destination_dir' => $tmp_dir)));
     $collection->add_task(new FW_Ext_Backups_Task($id_prefix . 'files-restore', 'files-restore', array('source_dir' => $tmp_dir . '/f', 'destinations' => $dirs)));
     $collection->add_task(new FW_Ext_Backups_Task($id_prefix . 'db-restore', 'db-restore', array('dir' => $tmp_dir)));
     $collection->add_task(new FW_Ext_Backups_Task($id_prefix . 'tmp-dir-clean:after', 'dir-clean', array('dir' => $tmp_dir)));
     $this->set_active_demo(array('id' => $demo->get_id(), 'result' => null));
     self::backups()->tasks()->execute_task_collection($collection);
 }
 /**
  * @param string $root_dir
  * @param array $dirs
  * @param string $previous_file
  * @param array $exclude_paths
  * @return array|true|WP_Error ['file.txt', 'file.php', ...]
  *         Important: It will never return an empty array. Only: (array)files, true, WP_Error
  */
 private function get_next_files($root_dir, array &$dirs, $previous_file, array $exclude_paths)
 {
     $rel_dir = empty($dirs) ? '' : '/' . implode('/', $dirs);
     $included_hidden_names = fw_ext('backups')->get_config('included_hidden_names');
     if ($paths = glob($root_dir . $rel_dir . '/{,.}[!.,!..]*', GLOB_MARK | GLOB_BRACE)) {
         $files = array();
         // result
         $file_found = empty($previous_file);
         // find previous file and return next files
         $count = 0;
         foreach ($paths as $path) {
             $file = basename($path);
             if (!$file_found) {
                 $file_found = $file === $previous_file;
                 continue;
             }
             if ($file[0] === '.' && !isset($included_hidden_names[$file])) {
                 continue;
             }
             if (is_dir($path)) {
                 if (isset($exclude_paths[fw_fix_path($path)])) {
                     continue;
                 } elseif ($files) {
                     // return collected files, will go inside directory on next call
                     return $files;
                 } else {
                     $dirs[] = $file;
                     return $this->get_next_files($root_dir, $dirs, '', $exclude_paths);
                 }
             } else {
                 $files[] = $file;
                 if (++$count > $this->get_max_files_per_cycle()) {
                     return $files;
                 }
             }
         }
         if (empty($files)) {
             if ($file_found) {
                 // reached end of the directory
                 if ($dirs) {
                     // go a directory back
                     $previous_file = array_pop($dirs);
                     return $this->get_next_files($root_dir, $dirs, $previous_file, $exclude_paths);
                 } else {
                     // root directory end reached
                     return true;
                 }
             } else {
                 return new WP_Error('previous_file_not_found', sprintf(__('Failed to restore dir listing from: %s', 'fw'), $root_dir . $rel_dir . '/' . $previous_file));
             }
         }
         return $files;
     } else {
         // directory is empty
         if ($dirs) {
             // go a directory back
             $previous_file = array_pop($dirs);
             return $this->get_next_files($root_dir, $dirs, $previous_file, $exclude_paths);
         } else {
             // root directory end reached
             return true;
         }
     }
 }
 /**
  * {@inheritdoc}
  * @param array $args
  * * dir - source directory in which is located `database.json.txt`
  * * [full] - (bool) force full or content restore. if not specified, will be detected automatically
  * * [required] - (default: false) if database file must exist, else if db restore is optional
  */
 public function execute(array $args, array $state = array())
 {
     if (!isset($args['dir'])) {
         return new WP_Error('no_source_dir', __('Source dir not specified', 'fw'));
     } else {
         $args['dir'] = fw_fix_path($args['dir']);
     }
     if (!isset($args['required'])) {
         $args['required'] = false;
     } else {
         $args['required'] = (bool) $args['required'];
     }
     if (empty($state)) {
         if (!file_exists($args['dir'] . '/database.json.txt')) {
             if ($args['required']) {
                 return new WP_Error('no_db_file', __('Database file not found', 'fw'));
             } else {
                 return true;
             }
         }
         $state = array('task' => 'cleanup', 'step' => 0, 'params' => array(), 'tables' => array(), 'full' => isset($args['full']) ? (bool) $args['full'] : null);
     }
     global $wpdb;
     /** @var WPDB $wpdb */
     if ($state['task'] === 'cleanup') {
         // delete all tables with temporary prefix $this->get_tmp_table_prefix()
         if ($table_names = $wpdb->get_col($wpdb->prepare('SHOW TABLES LIKE %s', $wpdb->esc_like($this->get_tmp_table_prefix()) . '%'))) {
             if (!$wpdb->query('DROP TABLE ' . esc_sql($table_name = array_pop($table_names)))) {
                 return new WP_Error('drop_tmp_table_fail', sprintf(__('Cannot drop temporary table: %s', 'fw'), $table_name));
             }
             return $state;
         } else {
             $state['task'] = 'inspect';
             $state['step'] = 0;
             return $state;
         }
     } elseif ($state['task'] === 'inspect') {
         try {
             $fo = new SplFileObject($args['dir'] . '/database.json.txt');
         } catch (RuntimeException $e) {
             $fo = null;
             return new WP_Error('cannot_open_file', __('Cannot open db file', 'fw'));
         }
         try {
             $fo->seek($state['step']);
         } catch (RuntimeException $e) {
             $fo = null;
             return new WP_Error('cannot_move_file_cursor', __('Cannot move cursor in db file', 'fw'));
         }
         $started_time = time();
         $timeout = fw_ext('backups')->get_timeout() - 7;
         while (time() - $started_time < $timeout) {
             if ($line = $fo->current()) {
                 if (is_null($line = json_decode($line, true))) {
                     $fo = null;
                     return new WP_Error('line_decode_fail', sprintf(__('Failed to decode line %d from db file.', 'fw') . ' ' . fw_get_json_last_error_message(), $state['step'] + 1));
                 }
                 if ($line['type'] === 'row' && $line['data']['table'] === 'options' && isset($line['data']['row']['option_name']) && in_array($line['data']['row']['option_name'], array('siteurl', 'home'))) {
                     $state['params'][$line['data']['row']['option_name']] = $line['data']['row']['option_value'];
                 } elseif ($line['type'] === 'table' && !isset($state['tables'][$line['data']['name']])) {
                     $state['tables'][$line['data']['name']] = true;
                 } elseif ($line['type'] === 'param') {
                     $state['params'][$line['data']['name']] = $line['data']['value'];
                 }
             } elseif ($line === false && !$fo->eof()) {
                 $fo = null;
                 return new WP_Error('line_read_fail', sprintf(__('Cannot read line %d from db file', 'fw'), $state['step'] + 1));
             } else {
                 if (!isset($state['params']['siteurl']) || !isset($state['params']['home'])) {
                     return new WP_Error('params_not_found', __('Required params not found', 'fw'));
                 }
                 $is_full_backup = isset($state['tables']['commentmeta']) && isset($state['tables']['comments']) && isset($state['tables']['links']) && isset($state['tables']['options']) && isset($state['tables']['postmeta']) && isset($state['tables']['posts']) && isset($state['tables']['terms']) && isset($state['tables']['term_relationships']) && isset($state['tables']['term_taxonomy']) && isset($state['tables']['usermeta']) && isset($state['tables']['users']);
                 if (is_multisite()) {
                     /* @link https://codex.wordpress.org/Database_Description */
                     $is_full_backup = $is_full_backup && (isset($state['tables']['blogs']) && isset($state['tables']['blog_versions']) && isset($state['tables']['registration_log']) && isset($state['tables']['signups']) && isset($state['tables']['site']) && isset($state['tables']['sitemeta']));
                 }
                 if (is_null($state['full'])) {
                     $state['full'] = $is_full_backup;
                 } elseif ($state['full'] && !$is_full_backup) {
                     return new WP_Error('full_db_restore_impossible', __('Cannot do full db restore because backup is missing some tables', 'fw'));
                 }
                 $skip_tables = array('users' => true, 'usermeta' => true);
                 if (!$state['full']) {
                     $skip_tables = array_merge($skip_tables, array('blogs' => true, 'blog_versions' => true, 'registration_log' => true, 'signups' => true, 'site' => true, 'sitemeta' => true, 'sitecategories' => true));
                 }
                 foreach (array_keys($skip_tables) as $table_name) {
                     if (isset($state['tables'][$table_name])) {
                         $state['tables'][$table_name] = false;
                     }
                 }
                 unset($skip_tables);
                 $state['step'] = 0;
                 $state['task'] = 'import';
                 $fo = null;
                 return $state;
             }
             $state['step']++;
             $fo->next();
         }
         $fo = null;
     } elseif ($state['task'] === 'import') {
         try {
             $fo = new SplFileObject($args['dir'] . '/database.json.txt');
         } catch (RuntimeException $e) {
             $fo = null;
             return new WP_Error('cannot_open_file', __('Cannot open db file', 'fw'));
         }
         try {
             $fo->seek($state['step']);
         } catch (RuntimeException $e) {
             $fo = null;
             return new WP_Error('cannot_move_file_cursor', __('Cannot move cursor in db file', 'fw'));
         }
         $params = array('search' => array(), 'replace' => array());
         /**
          * Note: rtrim(..., '/') is used to prevent wrong link replace
          *       'http://abc.com/img.jpg' -> 'http://def.comimg.jpg'
          * Note: First links should be the longest, to prevent the short part replace
          *       when the long part must be replaced (thus making wrong replace)
          */
         $search_replace = array();
         /**
          * This parameter (fix) was added after extension release
          * so some demo installs may not have it
          */
         if (isset($state['params']['wp_upload_dir_baseurl'])) {
             $wp_upload_dir = wp_upload_dir();
             $search_replace[rtrim($state['params']['wp_upload_dir_baseurl'], '/')] = rtrim($wp_upload_dir['baseurl'], '/');
             unset($wp_upload_dir);
         }
         $search_replace[rtrim($state['params']['siteurl'], '/')] = rtrim(get_option('siteurl'), '/');
         $search_replace[rtrim($state['params']['home'], '/')] = rtrim(get_option('home'), '/');
         foreach ($search_replace as $search => $replace) {
             $search_replace[fw_get_url_without_scheme($search)] = fw_get_url_without_scheme($replace);
         }
         foreach ($search_replace as $search => $replace) {
             if ($search === $replace) {
                 continue;
             }
             foreach (array($search => $replace, json_encode($search) => json_encode($replace)) as $search => $replace) {
                 $params['search'][] = $search;
                 $params['replace'][] = $replace;
                 $params['search'][] = str_replace('/', '\\/', $search);
                 $params['replace'][] = str_replace('/', '\\/', $replace);
                 $params['search'][] = str_replace('/', '\\\\/', $search);
                 $params['replace'][] = str_replace('/', '\\\\/', $replace);
                 $params['search'][] = str_replace('/', '\\\\\\/', $search);
                 $params['replace'][] = str_replace('/', '\\\\\\/', $replace);
             }
         }
         unset($search_replace, $search, $replace);
         $utf8mb4_is_supported = defined('DB_CHARSET') && DB_CHARSET === 'utf8mb4';
         $started_time = time();
         $timeout = fw_ext('backups')->get_timeout() - 7;
         while (time() - $started_time < $timeout) {
             if ($line = $fo->current()) {
                 if (is_null($line = json_decode($line, true))) {
                     $fo = null;
                     return new WP_Error('line_decode_fail', sprintf(__('Failed to decode line %d from db file.', 'fw') . ' ' . fw_get_json_last_error_message(), $state['step'] + 1));
                 }
                 switch ($line['type']) {
                     case 'table':
                         if (!$state['tables'][$line['data']['name']]) {
                             break;
                             // skip
                         }
                         $tmp_table_name = $this->get_tmp_table_prefix() . $line['data']['name'];
                         if (false === $wpdb->query('DROP TABLE IF EXISTS ' . esc_sql($tmp_table_name))) {
                             $fo = null;
                             return new WP_Error('tmp_table_drop_fail', sprintf(__('Failed to drop tmp table %s', 'fw'), $tmp_table_name));
                         }
                         $sql = 'CREATE TABLE `' . esc_sql($tmp_table_name) . "` (\n";
                         $cols_sql = array();
                         foreach ($line['data']['columns'] as $col_name => $col_opts) {
                             $cols_sql[] = '`' . esc_sql($col_name) . '` ' . ($utf8mb4_is_supported ? $col_opts : str_replace('utf8mb4', 'utf8', $col_opts));
                         }
                         foreach ($line['data']['indexes'] as $index) {
                             $cols_sql[] = $index;
                         }
                         $sql .= implode(", \n", $cols_sql);
                         unset($cols_sql);
                         $sql .= ') ' . ($utf8mb4_is_supported ? $line['data']['opts'] : str_replace('utf8mb4', 'utf8', $line['data']['opts']));
                         if (false === $wpdb->query($sql)) {
                             $fo = null;
                             return new WP_Error('tmp_table_create_fail', sprintf(__('Failed to create tmp table %s', 'fw'), $tmp_table_name));
                         }
                         unset($sql);
                         break;
                     case 'row':
                         if (!isset($state['tables'][$line['data']['table']])) {
                             $fo = null;
                             return new WP_Error('invalid_table', sprintf(__('Tried to insert data in table that was not imported %s', 'fw'), $line['data']['table']));
                         } elseif (!$state['tables'][$line['data']['table']]) {
                             break;
                             // the table was skipped
                         } elseif ('options' === $line['data']['table'] && apply_filters('fw_ext_backups_db_restore_exclude_option', false, $line['data']['row']['option_name'], $state['full'])) {
                             break;
                         }
                         $tmp_table_name = $this->get_tmp_table_prefix() . $line['data']['table'];
                         if (!empty($params['search'])) {
                             $this->array_str_replace_recursive($params['search'], $params['replace'], $line['data']['row']);
                         }
                         if (isset($state['params']['wpdb_prefix'])) {
                             $column = $search = null;
                             switch ($line['data']['table']) {
                                 case 'options':
                                     $column = 'option_name';
                                     $search = array('user_roles');
                                     break;
                                 case 'usermeta':
                                     $column = 'meta_key';
                                     $search = array('capabilities', 'user_level', 'dashboard_quick_press_last_post_id', 'user-settings', 'user-settings-time');
                                     break;
                             }
                             if ($column && $search) {
                                 foreach ($search as $name) {
                                     if (substr($line['data']['row'][$column], -strlen($name)) === $name && substr($line['data']['row'][$column], 0, strlen($state['params']['wpdb_prefix'])) === $state['params']['wpdb_prefix']) {
                                         $line['data']['row'][$column] = $wpdb->prefix . substr($line['data']['row'][$column], strlen($state['params']['wpdb_prefix']));
                                     }
                                 }
                             }
                         }
                         /**
                          * Insert pieces of rows to prevent mysql error when inserting very big strings.
                          * Do this only if table has index column so we can do 'UPDATE ... WHERE index_column = %s'
                          */
                         if ($index_column = $this->get_index_column($tmp_table_name)) {
                             /**
                              * Tested, and maximum value which works is 950000
                              * but may be tables with many columns with big strings
                              * so set this value lower to be sure the limit is not reached.
                              */
                             $value_max_length = 500000;
                             $update_count = 0;
                             $index_column_value = $line['data']['row'][$index_column];
                             $row_lengths = array();
                             while ($line['data']['row']) {
                                 $row = array();
                                 foreach (array_keys($line['data']['row']) as $column_name) {
                                     $row[$column_name] = mb_substr($line['data']['row'][$column_name], 0, $value_max_length);
                                     $row_length = mb_strlen($row[$column_name]);
                                     if (!isset($row_lengths[$column_name])) {
                                         $row_lengths[$column_name] = mb_strlen($line['data']['row'][$column_name]);
                                     }
                                     /**
                                      * The string was cut between a slashed character, for e.g. \" or \\
                                      * Append next characters until the slashing is closed
                                      */
                                     while (($last_char = mb_substr($row[$column_name], -1)) === '\\' && $row_length < $row_lengths[$column_name]) {
                                         $row[$column_name] .= mb_substr($line['data']['row'][$column_name], $row_length - 1, 1);
                                         $row_length++;
                                         // do not call mb_strlen() on every loop
                                     }
                                     $line['data']['row'][$column_name] = mb_substr($line['data']['row'][$column_name], $row_length);
                                     if (empty($line['data']['row'][$column_name])) {
                                         unset($line['data']['row'][$column_name]);
                                     }
                                 }
                                 if ($update_count) {
                                     $set_sql = array();
                                     foreach (array_keys($row) as $column_name) {
                                         $set_sql[] = '`' . esc_sql($column_name) . '` = CONCAT( `' . esc_sql($column_name) . '`' . ' , ' . $wpdb->prepare('%s', $row[$column_name]) . ')';
                                     }
                                     $set_sql = implode(', ', $set_sql);
                                     $sql = implode(" \n", array("UPDATE {$tmp_table_name} SET", $set_sql, 'WHERE `' . esc_sql($index_column) . '` = ' . $wpdb->prepare('%s', $index_column_value)));
                                 } else {
                                     $sql = implode(" \n", array("INSERT INTO {$tmp_table_name} (", '`' . implode('`, `', array_map('esc_sql', array_keys($row))) . '`', ") VALUES (", implode(', ', array_map(array($this, '_wpdb_prepare_string'), $row)), ")"));
                                 }
                                 if (false === $wpdb->query($sql)) {
                                     $fo = null;
                                     return new WP_Error('insert_fail', sprintf(__('Failed insert row from line %d', 'fw'), $state['step'] + 1));
                                 }
                                 unset($sql);
                                 $update_count++;
                             }
                         } else {
                             $sql = implode(" \n", array("INSERT INTO {$tmp_table_name} (", '`' . implode('`, `', array_map('esc_sql', array_keys($line['data']['row']))) . '`', ") VALUES (", implode(', ', array_map(array($this, '_wpdb_prepare_string'), $line['data']['row'])), ")"));
                             if (false === $wpdb->query($sql)) {
                                 $fo = null;
                                 return new WP_Error('insert_fail', sprintf(__('Failed insert row from line %d', 'fw'), $state['step'] + 1));
                             }
                             unset($sql);
                         }
                         break;
                     case 'param':
                         break;
                     default:
                         $fo = null;
                         return new WP_Error('invalid_json_type', sprintf(__('Invalid json type %s in db file', 'fw'), $line['type']));
                 }
             } elseif ($line === false && !$fo->eof()) {
                 $fo = null;
                 return new WP_Error('line_read_fail', __('Cannot read line from db file', 'fw'));
             } else {
                 $fo = null;
                 $state['step'] = 0;
                 $state['task'] = 'keep:options';
                 return $state;
             }
             $state['step']++;
             $fo->next();
         }
         $fo = null;
     } elseif ($state['task'] === 'keep:options') {
         if ($state['full'] && !isset($state['tables']['options'])) {
             // on full backup nothing is kept
         } else {
             $keep_options = array_merge(fw_ext('backups')->get_config('db.restore.keep_options'), apply_filters('fw_ext_backups_db_restore_keep_options', array(), $state['full']));
             $started_time = time();
             $timeout = fw_ext('backups')->get_timeout() - 7;
             // restore array pointer position
             if ($state['step']) {
                 while (($option_name = key($keep_options)) && $option_name !== $state['step']) {
                     next($keep_options);
                 }
                 if (empty($option_name)) {
                     return new WP_Error('keep_options_continue_fail', __('Failed to restore options keeping step', 'fw'));
                 }
             } else {
                 $state['step'] = key($keep_options);
             }
             do {
                 $tmp_options_table = esc_sql($this->get_tmp_table_prefix() . 'options');
                 while (time() - $started_time < $timeout) {
                     if ($row = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->options} WHERE option_name = %s LIMIT 1", $state['step']), ARRAY_A)) {
                         $wpdb->query($wpdb->prepare("DELETE FROM {$tmp_options_table} WHERE option_name = %s", $state['step']));
                         /**
                          * Prevent error: Duplicate entry '90' for key 'PRIMARY' for query INSERT INTO ...options
                          * Option id will be auto incremented on insert
                          */
                         unset($row['option_id']);
                         if (false === $wpdb->query("INSERT INTO {$tmp_options_table} ( \n" . '`' . implode('`, `', array_map('esc_sql', array_keys($row))) . "`  \n" . ") VALUES ( \n" . implode(', ', array_map(array($this, '_wpdb_prepare_string'), $row)) . " \n" . ')')) {
                             return new WP_Error('option_keep_fail', sprintf(__('Failed to keep option: %s', 'fw'), $state['step']));
                         }
                     }
                     next($keep_options);
                     if (is_null($state['step'] = key($keep_options))) {
                         break 2;
                     }
                 }
                 return $state;
             } while (false);
         }
         $state['step'] = 0;
         $state['task'] = 'replace';
         return $state;
     } elseif ($state['task'] === 'replace') {
         /**
          * P.P. We can't rename tables one by one, that can cause errors on next request (db corrupt)
          *      so the only solution is to rename all table at once
          *      and hope that the execution will not exceed timeout limit
          * P.P.S. Table rename should be fast http://dba.stackexchange.com/a/53850
          */
         $current_tables = $this->get_tables();
         $rename_sql = array();
         $drop_sql = array();
         foreach ($state['tables'] as $name => $restored) {
             if ($restored) {
                 if (isset($current_tables[$name])) {
                     // drop only if exists. to prevent sql error
                     $drop_sql[] = esc_sql($wpdb->prefix . $name);
                 }
                 $rename_sql[] = esc_sql($this->get_tmp_table_prefix() . $name) . ' TO ' . esc_sql($wpdb->prefix . $name);
             }
         }
         if (!empty($rename_sql)) {
             if (!empty($drop_sql)) {
                 $drop_sql = "DROP TABLE \n" . implode(" , \n", $drop_sql);
                 if (!$wpdb->query($drop_sql)) {
                     return new WP_Error('tables_drop_fail', __('Tables drop failed', 'fw'));
                 }
             }
             $rename_sql = "RENAME TABLE \n" . implode(" , \n", $rename_sql);
             $wpdb->query($rename_sql);
             // RENAME query doesn't return bool, so use the below method to detect error
             if ($rename_sql === $wpdb->last_query && $wpdb->last_error) {
                 return new WP_Error('tables_rename_fail', __('Tables rename failed.', 'fw') . ' ' . $wpdb->last_error);
             }
         }
         wp_cache_flush();
         return true;
     } else {
         return new WP_Error('invalid_sub_task', sprintf(__('Invalid sub task %s', 'fw'), $state['task']));
     }
     return $state;
 }
 /**
  * Create wp filesystem directory recursive
  * @param string $wp_filesystem_dir_path
  * @return bool
  */
 public static final function mkdir_recursive($wp_filesystem_dir_path)
 {
     /** @var WP_Filesystem_Base $wp_filesystem */
     global $wp_filesystem;
     if (!$wp_filesystem) {
         trigger_error('Filesystem is not available', E_USER_ERROR);
     } elseif (is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code()) {
         trigger_error('Filesystem: ' . $wp_filesystem->errors->get_error_message(), E_USER_ERROR);
     }
     $wp_filesystem_dir_path = fw_fix_path($wp_filesystem_dir_path);
     $path = false;
     foreach (self::get_base_dirs_map() as $base_real_path => $base_wp_filesystem_path) {
         $prefix_regex = '/^' . preg_quote($base_wp_filesystem_path, '/') . '/';
         // check if path is inside base path
         if (!preg_match($prefix_regex, $wp_filesystem_dir_path)) {
             continue;
         }
         $path = $base_wp_filesystem_path;
         break;
     }
     if (!$path) {
         trigger_error(sprintf(__('Cannot create directory "%s". It must be inside "%s"', 'fw'), $wp_filesystem_dir_path, implode(__('" or "', 'fw'), self::get_base_dirs_map())), E_USER_WARNING);
         return false;
     }
     if ($path === '/') {
         $rel_path = $wp_filesystem_dir_path;
     } else {
         $rel_path = preg_replace('/^' . preg_quote($path, '/') . '/', '', $wp_filesystem_dir_path);
     }
     // improvement: do not check directory for existence if it's known that sure it doesn't exist
     $check_if_exists = true;
     foreach (explode('/', ltrim($rel_path, '/')) as $dir_name) {
         $path .= '/' . $dir_name;
         // When WP FS abspath is '/', $path can be '//wp-content'. Fix it '/wp-content'
         $path = fw_fix_path($path);
         if ($check_if_exists) {
             if ($wp_filesystem->is_dir($path)) {
                 // do nothing if exists
                 continue;
             } else {
                 // do not check anymore, next directories sure doesn't exist
                 $check_if_exists = false;
             }
         }
         if (!$wp_filesystem->mkdir($path, FS_CHMOD_DIR)) {
             return false;
         }
     }
     return true;
 }
 /**
  * All backups (zip) will go in this directory
  * @return string
  */
 public function get_backups_dir()
 {
     $cache_key = $this->get_cache_key('/dir');
     try {
         return FW_Cache::get($cache_key);
     } catch (FW_Cache_Not_Found_Exception $e) {
         $uploads = wp_upload_dir();
         $dir = fw_fix_path($uploads['basedir']) . '/fw-backup';
         FW_Cache::set($cache_key, $dir);
         return $dir;
     }
 }
 /**
  * Download (and activate) extensions
  * After refresh they should be active, if all dependencies will be met and if parent-extension::_init() will not return false
  * @param array $extensions {'ext_1' => array(), 'ext_2' => array(), ...}
  * @param array $opts
  * @return WP_Error|bool|array
  *         true:  when all extensions succeeded
  *         array: when some/all failed
  */
 public function install_extensions(array $extensions, $opts = array())
 {
     $opts = array_merge(array('cancel_on_error' => false, 'activate' => true, 'verbose' => false), $opts);
     $cancel_on_error = $opts['cancel_on_error'];
     // fixme: remove successfully installed extensions before error?
     $activate = $opts['activate'];
     $verbose = $opts['verbose'];
     unset($opts);
     if (!$this->can_install()) {
         return new WP_Error('access_denied', __('You have no permissions to install extensions', 'fw'));
     }
     if (empty($extensions)) {
         return new WP_Error('no_extensions', __('No extensions provided', 'fw'));
     }
     global $wp_filesystem;
     if (!$wp_filesystem || is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code()) {
         return new WP_Error('fs_not_initialized', __('WP Filesystem is not initialized', 'fw'));
     }
     if (function_exists('ini_get')) {
         $timeout = intval(ini_get('max_execution_time'));
     } else {
         $timeout = false;
     }
     $available_extensions = $this->get_available_extensions();
     $installed_extensions = $this->get_installed_extensions();
     $result = $downloaded_extensions = array();
     $has_errors = false;
     while (!empty($extensions)) {
         $not_used_var = reset($extensions);
         $extension_name = key($extensions);
         unset($extensions[$extension_name]);
         $extensions_before_install = array_keys($installed_extensions);
         if (isset($installed_extensions[$extension_name])) {
             $result[$extension_name] = new WP_Error('extension_installed', sprintf(__('Extension "%s" is already installed.', 'fw'), $this->get_extension_title($extension_name)));
             $has_errors = true;
             if ($cancel_on_error) {
                 break;
             } else {
                 continue;
             }
         }
         if (!isset($available_extensions[$extension_name])) {
             $result[$extension_name] = new WP_Error('extension_not_available', sprintf(__('Extension "%s" is not available for install.', 'fw'), $this->get_extension_title($extension_name)));
             $has_errors = true;
             if ($cancel_on_error) {
                 break;
             } else {
                 continue;
             }
         }
         $parents = array($extension_name);
         $current_parent = $extension_name;
         while (!empty($available_extensions[$current_parent]['parent'])) {
             $current_parent = $available_extensions[$current_parent]['parent'];
             if (!isset($available_extensions[$current_parent])) {
                 $result[$extension_name] = new WP_Error('parent_extension_not_available', sprintf(__('Parent extension "%s" not available.', 'fw'), $this->get_extension_title($current_parent)));
                 $has_errors = true;
                 if ($cancel_on_error) {
                     break 2;
                 } else {
                     continue 2;
                 }
             }
             $parents[] = $current_parent;
         }
         $parents = array_reverse($parents);
         $destination_path = array('framework' => fw_get_framework_directory(), 'theme' => fw_fix_path(get_template_directory()) . fw_get_framework_customizations_dir_rel_path());
         $current_extension_path = '';
         foreach ($parents as $parent_extension_name) {
             $current_extension_path .= '/extensions/' . $parent_extension_name;
             $destination = isset($available_extensions[$parent_extension_name]['theme']) && $available_extensions[$parent_extension_name]['theme'] ? 'theme' : 'framework';
             if (isset($installed_extensions[$parent_extension_name])) {
                 continue;
                 // skip already installed extensions
             }
             if ($verbose) {
                 $verbose_message = sprintf(__('Downloading the "%s" extension...', 'fw'), $this->get_extension_title($parent_extension_name));
                 if (is_subclass_of($verbose, 'WP_Upgrader_Skin')) {
                     $verbose->feedback($verbose_message);
                 } else {
                     echo fw_html_tag('p', array(), $verbose_message);
                 }
             }
             // increase timeout
             if ($timeout !== false && function_exists('set_time_limit')) {
                 $timeout += 30;
                 set_time_limit($timeout);
             }
             $wp_fw_downloaded_dir = $this->download($parent_extension_name, $available_extensions[$parent_extension_name]);
             if (is_wp_error($wp_fw_downloaded_dir)) {
                 if ($verbose) {
                     $verbose_message = $wp_fw_downloaded_dir->get_error_message();
                     if (is_subclass_of($verbose, 'WP_Upgrader_Skin')) {
                         $verbose->error($verbose_message);
                     } else {
                         echo fw_html_tag('p', array(), $verbose_message);
                     }
                 }
                 $result[$extension_name] = $wp_fw_downloaded_dir;
                 $has_errors = true;
                 if ($cancel_on_error) {
                     break 2;
                 } else {
                     continue 2;
                 }
             }
             if ($verbose) {
                 $verbose_message = sprintf(__('Installing the "%s" extension...', 'fw'), $this->get_extension_title($parent_extension_name));
                 if (is_subclass_of($verbose, 'WP_Upgrader_Skin')) {
                     $verbose->feedback($verbose_message);
                 } else {
                     echo fw_html_tag('p', array(), $verbose_message);
                 }
             }
             $merge_result = $this->merge_extension($wp_fw_downloaded_dir, FW_WP_Filesystem::real_path_to_filesystem_path($destination_path[$destination] . $current_extension_path));
             if (is_wp_error($merge_result)) {
                 if ($verbose) {
                     $verbose_message = $merge_result->get_error_message();
                     if (is_subclass_of($verbose, 'WP_Upgrader_Skin')) {
                         $verbose->error($verbose_message);
                     } else {
                         echo fw_html_tag('p', array(), $verbose_message);
                     }
                 }
                 $result[$extension_name] = $merge_result;
                 $has_errors = true;
                 if ($cancel_on_error) {
                     break 2;
                 } else {
                     continue 2;
                 }
             }
             if ($verbose) {
                 $verbose_message = sprintf(__('The %s extension has been successfully installed.', 'fw'), $this->get_extension_title($parent_extension_name));
                 if (is_subclass_of($verbose, 'WP_Upgrader_Skin')) {
                     $verbose->feedback($verbose_message);
                 } else {
                     echo fw_html_tag('p', array(), $verbose_message);
                 }
             }
             $downloaded_extensions[$parent_extension_name] = array();
             unset($installed_extensions);
             $installed_extensions = $this->get_installed_extensions(true);
         }
         $result[$extension_name] = true;
         /**
          * Collect required extensions of the newly installed extensions
          */
         foreach (array_diff(array_keys($installed_extensions), $extensions_before_install) as $new_extension_name) {
             foreach (array_keys(fw_akg('requirements/extensions', $installed_extensions[$new_extension_name]['manifest'], array())) as $required_extension_name) {
                 if (isset($installed_extensions[$required_extension_name])) {
                     // already installed
                     continue;
                 }
                 $extensions[$required_extension_name] = array();
             }
         }
     }
     if ($activate) {
         $activate_extensions = array();
         foreach ($result as $extension_name => $extension_result) {
             if (!is_wp_error($extension_result)) {
                 $activate_extensions[$extension_name] = array();
             }
         }
         if (!empty($activate_extensions)) {
             if ($verbose) {
                 $verbose_message = _n('Activating extension...', 'Activating extensions...', count($activate_extensions), 'fw');
                 if (is_subclass_of($verbose, 'WP_Upgrader_Skin')) {
                     $verbose->feedback($verbose_message);
                 } else {
                     echo fw_html_tag('p', array(), $verbose_message);
                 }
             }
             $activation_result = $this->activate_extensions($activate_extensions);
             if ($verbose) {
                 if (is_wp_error($activation_result)) {
                     if (is_subclass_of($verbose, 'WP_Upgrader_Skin')) {
                         $verbose->error($activation_result->get_error_message());
                     } else {
                         echo fw_html_tag('p', array(), $activation_result->get_error_message());
                     }
                 } elseif (is_array($activation_result)) {
                     $verbose_message = array();
                     foreach ($activation_result as $extension_name => $extension_result) {
                         if (is_wp_error($extension_result)) {
                             $verbose_message[] = $extension_result->get_error_message();
                         }
                     }
                     $verbose_message = '<ul><li>' . implode('</li><li>', $verbose_message) . '</li></ul>';
                     if (is_subclass_of($verbose, 'WP_Upgrader_Skin')) {
                         $verbose->error($verbose_message);
                     } else {
                         echo fw_html_tag('p', array(), $verbose_message);
                     }
                 } elseif ($activation_result === true) {
                     $verbose_message = _n('Extension has been successfully activated.', 'Extensions has been successfully activated.', count($activate_extensions), 'fw');
                     if (is_subclass_of($verbose, 'WP_Upgrader_Skin')) {
                         $verbose->feedback($verbose_message);
                     } else {
                         echo fw_html_tag('p', array(), $verbose_message);
                     }
                 }
             }
         }
     }
     do_action('fw_extensions_install', $result);
     if ($cancel_on_error && $has_errors) {
         if (($last_result = end($result)) && is_wp_error($last_result)) {
             return $last_result;
         } else {
             // this should not happen, but just to be sure (for the future, if the code above will be changed)
             return new WP_Error('installation_failed', _n('Cannot install extension', 'Cannot install extensions', count($extensions), 'fw'));
         }
     }
     if ($has_errors) {
         return $result;
     } else {
         return true;
     }
 }
Example #24
0
 /**
  * Log debug information in ABSPATH/fw-update.log
  * @param string $message
  * @return bool|void
  */
 private static function _fw_update_debug_log($message)
 {
     /** @var WP_Filesystem_Base $wp_filesystem */
     global $wp_filesystem;
     if (!$wp_filesystem) {
         return;
     }
     $file_fs_path = fw_fix_path($wp_filesystem->abspath()) . '/fw-update.log';
     if ($wp_filesystem->exists($file_fs_path)) {
         $current_log = $wp_filesystem->get_contents($file_fs_path);
         if ($current_log === false) {
             return false;
         }
     } else {
         $current_log = '';
     }
     $message = '[' . date('Y-m-d H:i:s') . '] ' . $message;
     $wp_filesystem->put_contents($file_fs_path, $current_log . $message . "\n");
 }
 /**
  * @param string $source_dir path
  * @param string $destination_dir path
  * @param bool $fs Use WP_Filesystem or not
  * @param array $skip_dirs {'path': mixed}
  *
  * @return WP_Error|true
  */
 private function copy_dir($source_dir, $destination_dir, $fs, $skip_dirs)
 {
     $included_hidden_names = fw_ext('backups')->get_config('included_hidden_names');
     if ($fs) {
         global $wp_filesystem;
         /** @var WP_Filesystem_Base $wp_filesystem */
         $fs_source_dir = fw_fix_path(FW_WP_Filesystem::real_path_to_filesystem_path($source_dir));
         if (empty($fs_source_dir)) {
             return new WP_Error('dir_to_fs_failed', sprintf(__('Cannot convert Filesystem path: %s', 'fw'), $source_dir));
         } elseif (false === ($list = $wp_filesystem->dirlist($fs_source_dir, true))) {
             return new WP_Error('dir_list_failed', sprintf(__('Failed to list dir: %s', 'fw'), $source_dir));
         }
         foreach ($list as $file) {
             if ($file['name'][0] === '.' && !isset($included_hidden_names[$file['name']])) {
                 continue;
             }
             $file_path = $source_dir . '/' . $file['name'];
             $fs_file_path = $fs_source_dir . '/' . $file['name'];
             $destination_file_path = $destination_dir . '/' . $file['name'];
             $fs_destination_file_path = fw_fix_path(FW_WP_Filesystem::real_path_to_filesystem_path($destination_file_path));
             if (empty($fs_destination_file_path)) {
                 return new WP_Error('path_to_fs_failed', sprintf(__('Cannot convert Filesystem path: %s', 'fw'), $destination_file_path));
             }
             if ($file['type'] === 'd') {
                 if (isset($skip_dirs[$destination_file_path])) {
                     continue;
                 } else {
                     foreach ($skip_dirs as $skip_dir => $skip_dir_data) {
                         if (strlen(preg_replace('/^' . preg_quote($destination_file_path, '/') . '/', '', $skip_dir)) != strlen($skip_dir)) {
                             continue 2;
                             // skip dir if it's inside current dir
                         }
                     }
                 }
                 if (!$wp_filesystem->mkdir($fs_destination_file_path)) {
                     return new WP_Error('fs_mkdir_fail', sprintf(__('Failed to create dir: %s', 'fw'), $destination_file_path));
                 }
                 if (is_wp_error($result = copy_dir($fs_file_path, $fs_destination_file_path))) {
                     return $result;
                 }
             } else {
                 if (!$wp_filesystem->copy($fs_file_path, $fs_destination_file_path)) {
                     return new WP_Error('file_copy_fail', sprintf(__('Failed to copy file: %s', 'fw'), $file_path));
                 }
             }
         }
         return true;
     } else {
         $names = array_diff(($names = scandir($source_dir)) ? $names : array(), array('.', '..'));
         foreach ($names as $file_name) {
             $file_path = $source_dir . '/' . $file_name;
             $destination_file_path = $destination_dir . '/' . $file_name;
             if ($file_name[0] === '.' && !isset($included_hidden_names[$file_name])) {
                 continue;
             }
             if (is_dir($file_path)) {
                 if (isset($skip_dirs[$destination_file_path])) {
                     continue;
                 } else {
                     foreach ($skip_dirs as $skip_dir => $skip_dir_data) {
                         if (strlen(preg_replace('/^' . preg_quote($destination_file_path, '/') . '/', '', $skip_dir)) != strlen($skip_dir)) {
                             continue 2;
                             // skip dir it's inside current dir
                         }
                     }
                 }
                 if (is_dir($destination_file_path)) {
                     /**
                      * Some times empty directories are not deleted ( @see fw_ext_backups_rmdir_recursive() )
                      * even if rmdir() returns true, the directory remains (I don't know why),
                      * so a workaround is to check if it exists and do not try to created it
                      * (because create will return false)
                      */
                 } elseif (!mkdir($destination_file_path)) {
                     return new WP_Error('dir_mk_fail', sprintf(__('Failed to create dir: %s', 'fw'), $destination_file_path));
                 }
                 if (is_wp_error($result = $this->copy_dir($file_path, $destination_file_path, $fs, array()))) {
                     return $result;
                 }
             } else {
                 if (!copy($file_path, $destination_file_path)) {
                     return new WP_Error('file_copy_fail', sprintf(__('Failed to copy file: %s', 'fw'), $file_path));
                 }
             }
         }
         return true;
     }
 }
 /**
  * {@inheritdoc}
  * @param array $args
  * * source_dir - everything from this directory will be added in zip
  * * destination_dir - where the zip file will be created
  *
  * Warning!
  *  Zip can't be executed in steps, it will execute way too long,
  *  because it is impossible to update a zip file, every time you add a file to zip,
  *  a new temp copy of original zip is created with new modifications, it is compressed,
  *  and the original zip is replaced. So when the zip will grow in size,
  *  just adding a single file, will take a very long time.
  */
 public function execute(array $args, array $state = array())
 {
     if (!isset($args['source_dir'])) {
         return new WP_Error('no_source_dir', __('Source dir not specified', 'fw'));
     } elseif (!file_exists($args['source_dir'] = fw_fix_path($args['source_dir']))) {
         return new WP_Error('invalid_source_dir', __('Source dir does not exist', 'fw'));
     }
     if (!isset($args['destination_dir'])) {
         return new WP_Error('no_destination_dir', __('Destination dir not specified', 'fw'));
     } else {
         $args['destination_dir'] = fw_fix_path($args['destination_dir']);
     }
     if (empty($state)) {
         $state = array('files_count' => 0);
     }
     if (!class_exists('ZipArchive')) {
         return new WP_Error('zip_ext_missing', __('Zip extension missing', 'fw'));
     }
     $zip_path = $args['source_dir'] . '/' . implode('-', array('fw-backup', date('Y_m_d-H_i_s'), fw_ext('backups')->manifest->get_version())) . '.zip';
     $zip = new ZipArchive();
     if (false === ($zip_error_code = $zip->open($zip_path, ZipArchive::CREATE))) {
         return new WP_Error('cannot_open_zip', sprintf(__('Cannot open zip (Error code: %s)', 'fw'), $zip_error_code));
     }
     /** @var FW_Extension_Backups $ext */
     $ext = fw_ext('backups');
     $max_time = time() + min(abs($ext->get_timeout() / 2), 10);
     // $zip->setCompression*() was introduced in PHP 7.0
     $set_compression_is_available = method_exists($zip, 'setCompressionName');
     $files_count = 0;
     $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($args['source_dir']), RecursiveIteratorIterator::LEAVES_ONLY);
     foreach ($files as $file) {
         if ($execution_not_finished = time() > $max_time) {
             break;
         }
         if (!$this->file_is_zipable($file, $zip_path)) {
             continue;
         }
         ++$files_count;
         if ($state['files_count'] > $files_count) {
             // skip already compressed files in previous step
             continue;
         }
         $zip->addFile($file_path = $file->getRealPath(), $file_zip_path = substr(fw_fix_path($file_path), strlen($args['source_dir']) + 1));
         if ($set_compression_is_available) {
             $zip->setCompressionName($file_zip_path, ZipArchive::CM_STORE);
         }
     }
     // Zip archive will be created only after closing the object
     if (!$zip->close()) {
         return new WP_Error('cannot_close_zip', __('Cannot close the zip file', 'fw'));
     }
     $state['files_count'] = $files_count;
     if ($execution_not_finished) {
         // There are more files to be processed, the execution hasn't finished
         return $state;
     }
     if (!$files_count) {
         /**
          * Happens on Content Backup when uploads/ is empty
          */
         return true;
     }
     if (!rename($zip_path, $args['destination_dir'] . '/' . basename($zip_path))) {
         return new WP_Error('cannot_move_zip', __('Cannot move zip in destination dir', 'fw'));
     }
     return true;
 }