237 lines
5.3 KiB
PHP
237 lines
5.3 KiB
PHP
<?php
|
|
/**
|
|
* Akeeba Engine
|
|
*
|
|
* @package akeebaengine
|
|
* @copyright Copyright (c)2006-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
|
|
* @license GNU General Public License version 3, or later
|
|
*/
|
|
|
|
namespace Akeeba\Engine\Util;
|
|
|
|
defined('AKEEBAENGINE') || die();
|
|
|
|
use Akeeba\Engine\Factory;
|
|
use Akeeba\Engine\Platform;
|
|
use Exception;
|
|
|
|
/**
|
|
* This helper class is used to migrate Akeeba Backup profiles to the new storage format implemented since version
|
|
* 6.4.1
|
|
*
|
|
* @since 6.4.1
|
|
*/
|
|
abstract class ProfileMigration
|
|
{
|
|
/**
|
|
* Tries to migrate a backup profile to the new JSON-based storage format used since version 6.4.1.
|
|
*
|
|
* @param int $profileID The ID of the profile to migrate
|
|
*
|
|
* @return bool Whether we converted the profile
|
|
*
|
|
* @since 6.4.1
|
|
*/
|
|
public static function migrateProfile($profileID)
|
|
{
|
|
$platform = Platform::getInstance();
|
|
$db = Factory::getDatabase($platform->get_platform_database_options());
|
|
|
|
// Is the database connected?
|
|
if (!$db->connected())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Load the raw data from the database
|
|
try
|
|
{
|
|
$sql = $db->getQuery(true)
|
|
->select('*')
|
|
->from($db->qn($platform->tableNameProfiles))
|
|
->where($db->qn('id') . ' = ' . $db->q($profileID));
|
|
|
|
$rawData = $db->setQuery($sql)->loadAssoc();
|
|
}
|
|
catch (Exception $e)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Decrypt the configuration data if required
|
|
$rawData['configuration'] = self::decryptConfiguration($rawData['configuration']);
|
|
$migrated = false;
|
|
|
|
// Migrate the configuration from INI to JSON format
|
|
if (self::looksLikeIni($rawData['configuration']))
|
|
{
|
|
$rawData['configuration'] = self::convertINItoJSON($rawData['configuration']);
|
|
|
|
$migrated = true;
|
|
}
|
|
|
|
// Migrate the filters from INI to JSON format
|
|
if (self::looksLikeSerialized($rawData['filters']))
|
|
{
|
|
$rawData['filters'] = self::convertSerializedToJSON($rawData['filters']);
|
|
|
|
$migrated = true;
|
|
}
|
|
|
|
if (!$migrated)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
$rawData['configuration'] = self::encryptConfiguration($rawData['configuration']);
|
|
|
|
$sql = $db->getQuery(true)
|
|
->update($db->qn($platform->tableNameProfiles))
|
|
->set($db->qn('configuration') . ' = ' . $db->q($rawData['configuration']))
|
|
->set($db->qn('filters') . ' = ' . $db->q($rawData['filters']))
|
|
->where($db->qn('id') . ' = ' . $db->q($profileID));
|
|
|
|
$db->setQuery($sql);
|
|
|
|
try
|
|
{
|
|
$result = $db->query();
|
|
}
|
|
catch (Exception $exc)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return ($result == true);
|
|
}
|
|
|
|
/**
|
|
* Decrypt the configuration data if necessary. Returns the decrypted data.
|
|
*
|
|
* @param string $configData The possibly encrypted data.
|
|
*
|
|
* @return string The decrypted data
|
|
*
|
|
* @since 6.4.1
|
|
*/
|
|
public static function decryptConfiguration($configData)
|
|
{
|
|
$noData = empty($configData);
|
|
$signature = ($noData || (strlen($configData) < 12)) ? '' : substr($configData, 0, 12);
|
|
|
|
if (in_array($signature, ['###AES128###', '###CTR128###']))
|
|
{
|
|
return Factory::getSecureSettings()->decryptSettings($configData);
|
|
}
|
|
|
|
return $configData;
|
|
}
|
|
|
|
/**
|
|
* Encrypt the configuration data if necessary.
|
|
*
|
|
* @param string $configData The raw configuration data
|
|
*
|
|
* @return string The possibly encrypted configuration data
|
|
*
|
|
* @since 6.4.1
|
|
*/
|
|
public static function encryptConfiguration($configData)
|
|
{
|
|
$secureSettings = Factory::getSecureSettings();
|
|
|
|
return $secureSettings->encryptSettings($configData);
|
|
}
|
|
|
|
/**
|
|
* Does the provided configuration data look like it's INI encoded?
|
|
*
|
|
* @param string $configData The unencrypted configuration data we read from the database.
|
|
*
|
|
* @return bool
|
|
*
|
|
* @since 6.4.1
|
|
*/
|
|
public static function looksLikeIni($configData)
|
|
{
|
|
if (empty($configData))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (strlen($configData) < 8)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ((substr($configData, 0, 8) == '[global]') || substr($configData, 0, 8) == '[akeeba]')
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Convert the INI-encoded data to JSON-encoded data
|
|
*
|
|
* @param string $configData The INI-encoded data
|
|
*
|
|
* @return string The JSON-encoded data
|
|
*
|
|
* @since 6.4.1
|
|
*/
|
|
public static function convertINItoJSON($configData)
|
|
{
|
|
$dataArray = ParseIni::parse_ini_file($configData, true, true);
|
|
|
|
return json_encode($dataArray, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_FORCE_OBJECT | JSON_PRETTY_PRINT);
|
|
}
|
|
|
|
/**
|
|
* Does the raw filters string provided seems to use serialized data? We actually check if it looks like JSON.
|
|
* If it's not, we assume it's serialized data.
|
|
*
|
|
* @param string $rawFilters The raw filters string
|
|
*
|
|
* @return bool Does it look like a serialized string?
|
|
*
|
|
* @since 6.4.1
|
|
*/
|
|
public static function looksLikeSerialized($rawFilters)
|
|
{
|
|
if (empty($rawFilters))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (substr($rawFilters, 0, 1) == '{')
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Convert the serialized array in $rawFilters to JSON representation
|
|
*
|
|
* @param string $rawFilters Raw serialized string
|
|
*
|
|
* @return string JSON-encoded string
|
|
*
|
|
* @since 6.4.1
|
|
*/
|
|
public static function convertSerializedToJSON($rawFilters)
|
|
{
|
|
$filters = unserialize($rawFilters);
|
|
|
|
if (empty($filters))
|
|
{
|
|
$filters = [];
|
|
}
|
|
|
|
return json_encode($filters, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_FORCE_OBJECT | JSON_PRETTY_PRINT);
|
|
}
|
|
}
|