751 lines
18 KiB
PHP
751 lines
18 KiB
PHP
<?php
|
|
/**
|
|
* @package akeebabackupwp
|
|
* @copyright Copyright (c)2014-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
|
|
* @license GNU GPL version 3 or later
|
|
*/
|
|
|
|
namespace Akeeba\WPCLI\Command;
|
|
|
|
use Akeeba\Engine\Factory;
|
|
use Akeeba\Engine\Platform;
|
|
use Awf\Mvc\Model;
|
|
use Solo\Application;
|
|
use WP_CLI;
|
|
use WP_CLI\Utils as CliUtils;
|
|
|
|
/**
|
|
* Add, remove, reset, modify, import or export your Akeeba Backup profiles.
|
|
*
|
|
* @package Akeeba\WPCLI\Command
|
|
*
|
|
* @since 3.0.0
|
|
*/
|
|
class Profile
|
|
{
|
|
/**
|
|
* Lists the Akeeba Backup backup profiles
|
|
*
|
|
* ## OPTIONS
|
|
*
|
|
* [--format=<format>]
|
|
* : The format for the returned list
|
|
* ---
|
|
* default: table
|
|
* options:
|
|
* - table
|
|
* - json
|
|
* - csv
|
|
* - yaml
|
|
* - count
|
|
* ---
|
|
*
|
|
* ## EXAMPLES
|
|
*
|
|
* wp akeeba profile list
|
|
*
|
|
* wp akeeba profile list --format=json
|
|
*
|
|
* @when after_wp_load
|
|
* @subcommand list
|
|
*
|
|
* @param array $args Positional arguments (literal arguments)
|
|
* @param array $assoc_args Associative arguments (--flag, --no-flag, --key=value)
|
|
*
|
|
* @return void
|
|
*
|
|
* @throws WP_CLI\ExitException
|
|
*
|
|
* @since 3.0.0
|
|
*/
|
|
public function _list($args, $assoc_args)
|
|
{
|
|
/** @var Application $akeebaBackupApplication */
|
|
global $akeebaBackupApplication;
|
|
|
|
$format = isset($assoc_args['format']) ? $assoc_args['format'] : 'table';
|
|
$container = $akeebaBackupApplication->getContainer();
|
|
|
|
/** @var \Solo\Model\Profiles $model */
|
|
$model = Model::getTmpInstance($container->application_name, 'Profiles', $container);
|
|
$profiles = $model->get();
|
|
|
|
CliUtils\format_items($format, $profiles->toArray(), ['id', 'description', 'quickicon']);
|
|
}
|
|
|
|
/**
|
|
* Creates a copy of an Akeeba Backup profile
|
|
*
|
|
* ## OPTIONS
|
|
*
|
|
* <id>
|
|
* : The numeric ID of the profile to copy
|
|
*
|
|
* [--filters]
|
|
* : Include filters in the copy. Enabled by default. Use --no-filters to disable.
|
|
*
|
|
* [--description=<description>]
|
|
* : Description for the new backup profile. Uses the old profile's description if not specified.
|
|
*
|
|
* [--quickicon=<quickicon>]
|
|
* : Should the new backup profile have a one-click backup icon? Copies the old profile's setting if not specified.
|
|
*
|
|
* [--format=<format>]
|
|
* : The format for the response. Use JSON to get a JSON-parseable numeric ID of the new backup profile.
|
|
* ---
|
|
* default: text
|
|
* options:
|
|
* - text
|
|
* - json
|
|
* ---
|
|
*
|
|
* ## EXAMPLES
|
|
*
|
|
* wp akeeba profile copy 1
|
|
*
|
|
* wp akeeba profile copy 1 --description="Default profile without any filters" --no-filters
|
|
*
|
|
* wp akeeba profile copy 1 --quickicon=0 --description="Cloned default profile"
|
|
*
|
|
* @when after_wp_load
|
|
*
|
|
* @param array $args Positional arguments (literal arguments)
|
|
* @param array $assoc_args Associative arguments (--flag, --no-flag, --key=value)
|
|
*
|
|
* @return void
|
|
*
|
|
* @throws WP_CLI\ExitException
|
|
*
|
|
* @since 3.0.0
|
|
*/
|
|
public function copy($args, $assoc_args)
|
|
{
|
|
/** @var Application $akeebaBackupApplication */
|
|
global $akeebaBackupApplication;
|
|
|
|
if (!isset($args[0]))
|
|
{
|
|
WP_CLI::error("You must specify the backup profile ID to copy.");
|
|
}
|
|
|
|
$profileID = (int) $args[0];
|
|
|
|
if ($profileID <= 0)
|
|
{
|
|
WP_CLI::error("The backup profile ID to copy from must be a positive integer.");
|
|
}
|
|
|
|
$withFilters = isset($assoc_args['filters']) ? (bool) $assoc_args['filters'] : true;
|
|
|
|
$container = $akeebaBackupApplication->getContainer();
|
|
|
|
/** @var \Solo\Model\Profiles $model */
|
|
$model = Model::getTmpInstance($container->application_name, 'Profiles', $container);
|
|
|
|
try
|
|
{
|
|
$source = $model->findOrFail($profileID);
|
|
}
|
|
catch (\RuntimeException $e)
|
|
{
|
|
WP_CLI::error("Cannot copy profile $profileID; profile not found.");
|
|
}
|
|
|
|
$profileData = $source->getData();
|
|
unset($profileData['id']);
|
|
|
|
if (!$withFilters)
|
|
{
|
|
$profileData['filters'] = '';
|
|
}
|
|
|
|
if (isset($assoc_args['description']))
|
|
{
|
|
$profileData['description'] = trim($assoc_args['description']);
|
|
}
|
|
|
|
if (isset($assoc_args['quickicon']))
|
|
{
|
|
$profileData['quickicon'] = (bool) $assoc_args['quickicon'] ? 1 : 0;
|
|
}
|
|
|
|
try
|
|
{
|
|
$newProfile = $model->create($profileData);
|
|
}
|
|
catch (\Exception $e)
|
|
{
|
|
WP_CLI::error("Cannot copy profile #$profileID: {$e->getMessage()}");
|
|
}
|
|
|
|
$format = isset($assoc_args['format']) ? $assoc_args['format'] : 'text';
|
|
|
|
if ($format == 'json')
|
|
{
|
|
echo json_encode($newProfile->getData());
|
|
|
|
return;
|
|
}
|
|
|
|
WP_CLI::success("Copy successful. Created new profile with ID {$newProfile->getId()}.");
|
|
}
|
|
|
|
/**
|
|
* Creates a new Akeeba Backup profile
|
|
*
|
|
* ## OPTIONS
|
|
*
|
|
* [--description=<description>]
|
|
* : Description for the new backup profile. Default: "New backup profile".
|
|
*
|
|
* [--quickicon=<quickicon>]
|
|
* : Should the new backup profile have a one-click backup icon? Default: 1.
|
|
*
|
|
* [--format=<format>]
|
|
* : The format for the response. Use JSON to get a JSON-parseable numeric ID of the new backup profile.
|
|
* ---
|
|
* default: text
|
|
* options:
|
|
* - text
|
|
* - json
|
|
* ---
|
|
*
|
|
* ## EXAMPLES
|
|
*
|
|
* wp akeeba profile create
|
|
*
|
|
* wp akeeba profile create --description="For moving site to example.com"
|
|
*
|
|
* wp akeeba profile create --description="Backup after post creation" --quickicon=1
|
|
*
|
|
* @when after_wp_load
|
|
*
|
|
* @param array $args Positional arguments (literal arguments)
|
|
* @param array $assoc_args Associative arguments (--flag, --no-flag, --key=value)
|
|
*
|
|
* @return void
|
|
*
|
|
* @throws WP_CLI\ExitException
|
|
*
|
|
* @since 3.0.0
|
|
*/
|
|
public function create($args, $assoc_args)
|
|
{
|
|
/** @var Application $akeebaBackupApplication */
|
|
global $akeebaBackupApplication;
|
|
|
|
$container = $akeebaBackupApplication->getContainer();
|
|
|
|
/** @var \Solo\Model\Profiles $model */
|
|
$model = Model::getTmpInstance($container->application_name, 'Profiles', $container);
|
|
|
|
// Set up the new profile data
|
|
$profileData = [
|
|
'description' => 'New backup profile',
|
|
'quickicon' => '1',
|
|
'configuration' => '',
|
|
'filters' => '',
|
|
];
|
|
|
|
if (isset($assoc_args['description']))
|
|
{
|
|
$profileData['description'] = trim($assoc_args['description']);
|
|
}
|
|
|
|
if (isset($assoc_args['quickicon']))
|
|
{
|
|
$profileData['quickicon'] = (bool) $assoc_args['quickicon'] ? 1 : 0;
|
|
}
|
|
|
|
// Create the profile
|
|
try
|
|
{
|
|
$newProfile = $model->create($profileData);
|
|
}
|
|
catch (\Exception $e)
|
|
{
|
|
WP_CLI::error("Cannot create profile: {$e->getMessage()}");
|
|
}
|
|
|
|
/**
|
|
* Create a new profile configuration.
|
|
*
|
|
* Loading the new profile's empty configuration causes the Platform code to revert to the default options and
|
|
* save them automatically to the database.
|
|
*/
|
|
$profileId = $newProfile->getId();
|
|
Platform::getInstance()->load_configuration($profileId);
|
|
|
|
// Display the results
|
|
$format = isset($assoc_args['format']) ? $assoc_args['format'] : 'text';
|
|
|
|
if ($format == 'json')
|
|
{
|
|
echo json_encode($newProfile->getId());
|
|
|
|
return;
|
|
}
|
|
|
|
WP_CLI::success("Copy successful. Created new profile with ID {$newProfile->getId()}.");
|
|
}
|
|
|
|
/**
|
|
* Deletes an Akeeba Backup profile
|
|
*
|
|
* ## OPTIONS
|
|
*
|
|
* <id>
|
|
* : The numeric ID of the profile to copy. It CAN NOT be 1; the default backup profile must always be present.
|
|
*
|
|
* ## EXAMPLES
|
|
*
|
|
* wp akeeba profile delete 2
|
|
*
|
|
* @when after_wp_load
|
|
*
|
|
* @param array $args Positional arguments (literal arguments)
|
|
* @param array $assoc_args Associative arguments (--flag, --no-flag, --key=value)
|
|
*
|
|
* @return void
|
|
*
|
|
* @throws WP_CLI\ExitException
|
|
*
|
|
* @since 3.0.0
|
|
*/
|
|
public function delete($args, $assoc_args)
|
|
{
|
|
/** @var Application $akeebaBackupApplication */
|
|
global $akeebaBackupApplication;
|
|
|
|
if (!isset($args[0]))
|
|
{
|
|
WP_CLI::error("You must specify the backup profile ID to delete.");
|
|
}
|
|
|
|
$profileID = (int) $args[0];
|
|
|
|
if ($profileID <= 0)
|
|
{
|
|
WP_CLI::error("The backup profile ID to delete must be a positive integer.");
|
|
}
|
|
|
|
$container = $akeebaBackupApplication->getContainer();
|
|
|
|
/** @var \Solo\Model\Profiles $model */
|
|
$model = Model::getTmpInstance($container->application_name, 'Profiles', $container);
|
|
|
|
try
|
|
{
|
|
$profile = $model->findOrFail($profileID);
|
|
}
|
|
catch (\RuntimeException $e)
|
|
{
|
|
WP_CLI::error("Cannot delete profile $profileID; profile not found.");
|
|
}
|
|
|
|
try
|
|
{
|
|
$profile->forceDelete($profile->getId());
|
|
}
|
|
catch (\Exception $e)
|
|
{
|
|
WP_CLI::error("Cannot delete profile $profileID; {$e->getMessage()}.");
|
|
}
|
|
|
|
WP_CLI::success("Profile $profileID has been deleted.");
|
|
}
|
|
|
|
/**
|
|
* Change the description or quick icon setting of an Akeeba Backup profile.
|
|
*
|
|
* ## OPTIONS
|
|
*
|
|
* <id>
|
|
* : The numeric ID of the profile to modify
|
|
*
|
|
* [--description=<description>]
|
|
* : Description for the new backup profile. Uses the old profile's description if not specified.
|
|
*
|
|
* [--quickicon=<quickicon>]
|
|
* : Should the new backup profile have a one-click backup icon? Copies the old profile's setting if not specified.
|
|
*
|
|
* ## EXAMPLES
|
|
*
|
|
* wp akeeba profile modify 1 --description="Foo bar"
|
|
*
|
|
* wp akeeba profile modify 1 --quickicon=0
|
|
*
|
|
* wp akeeba profile modify 1 --description="Foo bar" --quickicon=0
|
|
*
|
|
* @when after_wp_load
|
|
*
|
|
* @param array $args Positional arguments (literal arguments)
|
|
* @param array $assoc_args Associative arguments (--flag, --no-flag, --key=value)
|
|
*
|
|
* @return void
|
|
*
|
|
* @throws WP_CLI\ExitException
|
|
*
|
|
* @since 3.0.0
|
|
*/
|
|
public function modify($args, $assoc_args)
|
|
{
|
|
/** @var Application $akeebaBackupApplication */
|
|
global $akeebaBackupApplication;
|
|
|
|
if (!isset($args[0]))
|
|
{
|
|
WP_CLI::error("You must specify the backup profile ID to modify.");
|
|
}
|
|
|
|
$profileID = (int) $args[0];
|
|
|
|
if ($profileID <= 0)
|
|
{
|
|
WP_CLI::error("The backup profile ID to modify must be a positive integer.");
|
|
}
|
|
|
|
$container = $akeebaBackupApplication->getContainer();
|
|
|
|
/** @var \Solo\Model\Profiles $model */
|
|
$model = Model::getTmpInstance($container->application_name, 'Profiles', $container);
|
|
|
|
try
|
|
{
|
|
$profile = $model->findOrFail($profileID);
|
|
}
|
|
catch (\RuntimeException $e)
|
|
{
|
|
WP_CLI::error("Cannot modify profile $profileID; profile not found.");
|
|
}
|
|
|
|
if (isset($assoc_args['description']))
|
|
{
|
|
$profile->description = trim($assoc_args['description']);
|
|
}
|
|
|
|
if (isset($assoc_args['quickicon']))
|
|
{
|
|
$profile->quickicon = (bool) $assoc_args['quickicon'] ? 1 : 0;
|
|
}
|
|
|
|
try
|
|
{
|
|
$profile->save();
|
|
}
|
|
catch (\Exception $e)
|
|
{
|
|
WP_CLI::error("Cannot save profile #$profileID: {$e->getMessage()}");
|
|
}
|
|
|
|
WP_CLI::success("Profile $profileID modified successfully.");
|
|
}
|
|
|
|
/**
|
|
* Reset the filters and / or backup engine configuration of an Akeeba Backup profile.
|
|
*
|
|
* ## OPTIONS
|
|
*
|
|
* <id>
|
|
* : The numeric ID of the profile to reset
|
|
*
|
|
* [--filters]
|
|
* : Reset filters. Enabled by default. Use --no-filters to disable.
|
|
*
|
|
* [--configuration]
|
|
* : Reset the engine configuration. Enabled by default. Use --no-configuration to disable.
|
|
*
|
|
* ## EXAMPLES
|
|
*
|
|
* wp akeeba profile reset 1
|
|
*
|
|
* wp akeeba profile reset 1 --no-filters
|
|
*
|
|
* wp akeeba profile reset 1 --no-configuration
|
|
*
|
|
* @when after_wp_load
|
|
*
|
|
* @param array $args Positional arguments (literal arguments)
|
|
* @param array $assoc_args Associative arguments (--flag, --no-flag, --key=value)
|
|
*
|
|
* @return void
|
|
*
|
|
* @throws WP_CLI\ExitException
|
|
*
|
|
* @since 3.0.0
|
|
*/
|
|
public function reset($args, $assoc_args)
|
|
{
|
|
/** @var Application $akeebaBackupApplication */
|
|
global $akeebaBackupApplication;
|
|
|
|
if (!isset($args[0]))
|
|
{
|
|
WP_CLI::error("You must specify the backup profile ID to reset.");
|
|
}
|
|
|
|
$profileID = (int) $args[0];
|
|
|
|
if ($profileID <= 0)
|
|
{
|
|
WP_CLI::error("The backup profile ID to reset must be a positive integer.");
|
|
}
|
|
|
|
$container = $akeebaBackupApplication->getContainer();
|
|
|
|
/** @var \Solo\Model\Profiles $model */
|
|
$model = Model::getTmpInstance($container->application_name, 'Profiles', $container);
|
|
|
|
try
|
|
{
|
|
$profile = $model->findOrFail($profileID);
|
|
}
|
|
catch (\RuntimeException $e)
|
|
{
|
|
WP_CLI::error("Cannot reset profile $profileID; profile not found.");
|
|
}
|
|
|
|
$filters = isset($assoc_args['filters']) ? $assoc_args['filters'] : true;
|
|
$configuration = isset($assoc_args['configuration']) ? $assoc_args['configuration'] : true;
|
|
|
|
if ($filters)
|
|
{
|
|
$profile->filters = '';
|
|
}
|
|
|
|
if ($configuration)
|
|
{
|
|
$profile->configuration = '';
|
|
}
|
|
|
|
if (!$filters && !$configuration)
|
|
{
|
|
WP_CLI::error("You have chosen to reset neither filters nor configuration. There is nothing for me to do.");
|
|
}
|
|
|
|
try
|
|
{
|
|
$profile->save();
|
|
}
|
|
catch (\Exception $e)
|
|
{
|
|
WP_CLI::error("Cannot save profile #$profileID: {$e->getMessage()}");
|
|
}
|
|
|
|
/**
|
|
* Loading the new profile's empty configuration causes the Platform code to revert to the default options and
|
|
* save them automatically to the database.
|
|
*/
|
|
if ($configuration)
|
|
{
|
|
Platform::getInstance()->load_configuration($profileID);
|
|
}
|
|
|
|
WP_CLI::success("Profile $profileID reset successfully.");
|
|
}
|
|
|
|
/**
|
|
* Exports an Akeeba Backup profile as a JSON string.
|
|
*
|
|
* ## OPTIONS
|
|
*
|
|
* <id>
|
|
* : The numeric ID of the profile to export
|
|
*
|
|
* [--filters]
|
|
* : Include filter settings. Enabled by default. Use --no-filters to disable.
|
|
*
|
|
* ## EXAMPLES
|
|
*
|
|
* wp akeeba profile export 1
|
|
*
|
|
* wp akeeba profile export 1 --no-filters
|
|
*
|
|
* @when after_wp_load
|
|
*
|
|
* @param array $args Positional arguments (literal arguments)
|
|
* @param array $assoc_args Associative arguments (--flag, --no-flag, --key=value)
|
|
*
|
|
* @return void
|
|
*
|
|
* @throws WP_CLI\ExitException
|
|
*
|
|
* @since 3.0.0
|
|
*/
|
|
public function export($args, $assoc_args)
|
|
{
|
|
/** @var Application $akeebaBackupApplication */
|
|
global $akeebaBackupApplication;
|
|
|
|
if (!isset($args[0]))
|
|
{
|
|
WP_CLI::error("You must specify the backup profile ID to export.");
|
|
}
|
|
|
|
$profileID = (int) $args[0];
|
|
|
|
if ($profileID <= 0)
|
|
{
|
|
WP_CLI::error("The backup profile ID to export must be a positive integer.");
|
|
}
|
|
|
|
$container = $akeebaBackupApplication->getContainer();
|
|
|
|
/** @var \Solo\Model\Profiles $model */
|
|
$model = Model::getTmpInstance($container->application_name, 'Profiles', $container);
|
|
|
|
try
|
|
{
|
|
$profile = $model->findOrFail($profileID);
|
|
}
|
|
catch (\RuntimeException $e)
|
|
{
|
|
WP_CLI::error("Cannot export profile $profileID; profile not found.");
|
|
}
|
|
|
|
$data = $profile->toArray();
|
|
$filters = isset($assoc_args['filters']) ? $assoc_args['filters'] : true;
|
|
|
|
if (!$filters)
|
|
{
|
|
unset($data['filters']);
|
|
}
|
|
|
|
// The ID must not be included in the export
|
|
unset($data['id']);
|
|
|
|
// Decrypt configuration data if necessary
|
|
if (substr($data['configuration'], 0, 12) == '###AES128###')
|
|
{
|
|
// Load the server key file if necessary
|
|
$key = Factory::getSecureSettings()->getKey();
|
|
|
|
$data['configuration'] = Factory::getSecureSettings()->decryptSettings($data['configuration'], $key);
|
|
}
|
|
|
|
echo json_encode($data);
|
|
}
|
|
|
|
/**
|
|
* Exports an Akeeba Backup profile from JSON.
|
|
*
|
|
* ## OPTIONS
|
|
*
|
|
* [<fileOrJSON>]
|
|
* : A path to an Akeeba Backup profile export JSON file or a literal JSON string. Uses STDIN if ommited.
|
|
*
|
|
* [--format=<format>]
|
|
* : The format for the response. Use JSON to get a JSON-parseable numeric ID of the new backup profile.
|
|
* ---
|
|
* default: text
|
|
* options:
|
|
* - text
|
|
* - json
|
|
* ---
|
|
*
|
|
* ## EXAMPLES
|
|
*
|
|
* wp akeeba profile import /path/to/profile.json --format=json
|
|
*
|
|
* cat /path/to/profile.json | wp akeeba profile
|
|
*
|
|
* @when after_wp_load
|
|
*
|
|
* @param array $args Positional arguments (literal arguments)
|
|
* @param array $assoc_args Associative arguments (--flag, --no-flag, --key=value)
|
|
*
|
|
* @return void
|
|
*
|
|
* @throws WP_CLI\ExitException
|
|
*
|
|
* @since 3.0.0
|
|
*/
|
|
public function import($args, $assoc_args)
|
|
{
|
|
global $akeebaBackupApplication;
|
|
|
|
$json = null;
|
|
$filename = isset($args[0]) ? $args[0] : '';
|
|
|
|
$json = $this->getJSON($filename);
|
|
$decoded = json_decode($json, true);
|
|
|
|
if (empty($decoded))
|
|
{
|
|
WP_CLI::error("Cannot process input; invalid JSON string or file not found.");
|
|
}
|
|
|
|
// We must never pass an ID, forcing the model to create a new record
|
|
if (isset($decoded['id']))
|
|
{
|
|
unset($decoded['id']);
|
|
}
|
|
|
|
$container = $akeebaBackupApplication->getContainer();
|
|
|
|
/** @var \Solo\Model\Profiles $model */
|
|
$model = Model::getTmpInstance($container->application_name, 'Profiles', $container);
|
|
|
|
try
|
|
{
|
|
$newProfile = $model->create($decoded);
|
|
}
|
|
catch (\Exception $e)
|
|
{
|
|
WP_CLI::error("Cannot import profile: {$e->getMessage()}");
|
|
}
|
|
|
|
$profileID = $newProfile->getId();
|
|
$format = isset($assoc_args['format']) ? $assoc_args['format'] : 'text';
|
|
|
|
if ($format == 'json')
|
|
{
|
|
echo json_encode($profileID);
|
|
|
|
return;
|
|
}
|
|
|
|
WP_CLI::success("Successfully imported JSON as profile #$profileID");
|
|
}
|
|
|
|
/**
|
|
* Get the JSON input for import()
|
|
*
|
|
* @param string $filename The filename to read from, raw JSON data or an empty string
|
|
*
|
|
* @return string The JSON data
|
|
*
|
|
* @since 3.0.0
|
|
*/
|
|
private function getJSON($filename)
|
|
{
|
|
// No filename or JSON string passed to script; use STDIN
|
|
if (empty($filename))
|
|
{
|
|
$json = '';
|
|
|
|
while (!feof(STDIN))
|
|
{
|
|
$json .= fgets(STDIN) . "\n";
|
|
}
|
|
|
|
return rtrim($json);
|
|
}
|
|
|
|
// An existing file path was passed. Return the contents of the file.
|
|
if (@file_exists($filename))
|
|
{
|
|
$ret = @file_get_contents($filename);
|
|
|
|
if ($ret === false)
|
|
{
|
|
return '';
|
|
}
|
|
}
|
|
|
|
// Otherwise assume raw JSON was passed back to us.
|
|
return $filename;
|
|
}
|
|
|
|
}
|