| Server IP : 81.19.159.101 / Your IP : 216.73.217.111 Web Server : Apache System : Linux www58.world4you.com 4.18.0-553.126.2.lve.el8.x86_64 #1 SMP Thu May 28 14:12:30 UTC 2026 x86_64 User : ftp8817043 ( 2681) PHP Version : 8.4.21 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : OFF | Perl : OFF | Python : OFF | Sudo : OFF | Pkexec : OFF Directory : /home/.sites/103/site8817043/web/wp-content/plugins/akeebabackupwp/app/Solo/Model/ |
Upload File : |
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU General Public License version 3, or later
*/
namespace Solo\Model;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Awf\Container\Container;
use Awf\Mvc\Model;
use Awf\Pagination\Pagination;
use Awf\Text\Language;
use Awf\Text\Text;
use Exception;
class Manage extends Model
{
/** @var Pagination The pagination model for this data */
protected $pagination = null;
public function __construct(?Container $container = null, ?Language $language = null)
{
parent::__construct($container, $language);
$limit = $this->getUserStateFromRequest('solo_limit', 'limit', 10, 'int');
$limitStart = $this->getUserStateFromRequest('solo_manage_start', 'limitstart', 0, 'int');
$this->setState('limit', $limit);
$this->setState('limitStart', $limitStart);
}
/**
* Is this string a valid remote filename?
*
* We've had reports that some servers return a bogus, non-empty string for some remote_filename columns, causing
* the "Manage remote stored files" column to appear even for locally stored files. By applying more rigorous tests
* for the remote_filename column we can avoid this problem.
*
* @param string|null $filename
*
* @return bool
*
* @since 7.6.4
*/
public function isRemoteFilename(?string $filename = null): bool
{
// A remote filename has to be a string which is does not consist solely of whitespace
if (!is_string($filename) || trim($filename) === '')
{
return false;
}
// Let's remote whitespace just in case
$filename = trim($filename);
// A remote filename must be in the format engine://path
if (strpos($filename, '://') === false)
{
return false;
}
// Get the engine and path
[$engine, $path] = explode('://', $filename, 2);
$engine = trim($engine);
$path = trim($path);
// Both engine and path must be non-empty
if (empty($engine) || empty($path))
{
return false;
}
// The engine must be known to the backup engine
$classname = 'Akeeba\\Engine\\Postproc\\' . ucfirst($engine);
return class_exists($classname);
}
/**
* Returns the same list as getStatisticsList(), but includes an extra field
* named 'meta' which categorises attempts based on their backup archive status
*
* @param boolean $overrideLimits Should I override all list limits?
* @param array $filters Filters to apply, see PlatformInterface::get_statistics_list
* @param array $order Record ordering information (By and Ordering)
*
* @return array An array of backup attempt objects
*/
public function &getStatisticsListWithMeta($overrideLimits = false, $filters = null, $order = null)
{
$limitstart = $overrideLimits ? 0 : $this->getState('limitstart', 0);
$limit = $overrideLimits ? 0 : $this->getState('limit', 10);
$filters = $overrideLimits ? null : $filters;
if (is_array($order) && isset($order['order']))
{
$order['order'] = strtoupper($order['order']) === 'ASC' ? 'asc' : 'desc';
}
$allStats = Platform::getInstance()->get_statistics_list([
'limitstart' => $limitstart,
'limit' => $limit,
'filters' => $filters,
'order' => $order,
]);
$validRecords = Platform::getInstance()->get_valid_backup_records() ?: [];
$updateObsoleteRecords = [];
$ret = array_map(function (array $stat) use (&$updateObsoleteRecords, $validRecords) {
$hasRemoteFiles = false;
// Translate backup status and the existence of a remote filename to the backup record's "meta" status.
switch ($stat['status'])
{
case 'run':
$stat['meta'] = 'pending';
break;
case 'fail':
$stat['meta'] = 'fail';
break;
default:
$hasRemoteFiles = $this->isRemoteFilename($stat['remote_filename']);
$stat['meta'] = $hasRemoteFiles ? 'remote' : 'obsolete';
break;
}
$stat['hasRemoteFiles'] = $hasRemoteFiles;
// If the backup is reported to have files still stored on the server we need to investigate further
if (in_array($stat['id'], $validRecords))
{
$archives = Factory::getStatistics()->get_all_filenames($stat);
$hasLocalFiles = (is_array($archives) ? count($archives) : 0) > 0;
$stat['meta'] = $hasLocalFiles ? 'ok' : ($hasRemoteFiles ? 'remote' : 'obsolete');
// The archives exist. Set $stat['size'] to the total size of the backup archives.
if ($hasLocalFiles)
{
$stat['size'] = $stat['total_size']
?: array_reduce(
$archives,
function ($carry, $filename) {
return $carry += @filesize($filename) ?: 0;
},
0
);
return $stat;
}
// The archives do not exist or we can't find them. If the record says otherwise we need to update it.
if ($stat['filesexist'])
{
$updateObsoleteRecords[] = $stat['id'];
}
// Does the backup record report a total size even though our files no longer exist?
if ($stat['total_size'])
{
$stat['size'] = $stat['total_size'];
}
}
return $stat;
}, $allStats);
// Update records which report that their files exist on the server but, in fact, they don't.
Platform::getInstance()->invalidate_backup_records($updateObsoleteRecords);
return $ret;
}
/**
* Delete the stats record whose ID is set in the model
*
* @return boolean True on success
*
* @throws \RuntimeException
*/
public function delete()
{
$id = $this->getState('id', 0);
if ((!is_numeric($id)) || ($id <= 0))
{
throw new \RuntimeException(Text::_('COM_AKEEBA_BUADMIN_ERROR_INVALIDID'), 500);
}
// Try to delete files
$this->deleteFile();
Platform::getInstance()->delete_statistics($id);
return true;
}
/**
* Delete the backup file of the stats record whose ID is set in the model
*
* @return boolean True on success
*
* @throws \RuntimeException
*/
public function deleteFile()
{
$id = $this->getState('id', 0);
if ((!is_numeric($id)) || ($id <= 0))
{
throw new \RuntimeException(Text::_('COM_AKEEBA_BUADMIN_ERROR_INVALIDID'), 500);
}
$stat = Platform::getInstance()->get_statistics($id);
$allFiles = Factory::getStatistics()->get_all_filenames($stat, false);
// Remove the custom log file if necessary
if (!is_null($stat))
{
$this->_deleteLogs($stat);
}
// Make sure we have some files
if (empty($allFiles))
{
return true;
}
// Get a reference to the filesystem abstraction
$fs = $this->container->fileSystem;
// Set the default status
$status = true;
// Delete all archive files
foreach ($allFiles as $filename)
{
try
{
$fs->delete($filename);
}
catch (\Exception $e)
{
// Ignore file deletion failure
$status = false;
}
}
return $status;
}
/**
* Get a pagination object
*
* @param array $filters Any filters to use
*
* @return Pagination
*/
public function &getPagination($filters = null)
{
if (!is_object($this->pagination))
{
// Prepare pagination values
$total = Platform::getInstance()->get_statistics_count($filters);
$limitStart = $this->getState('limitStart');
$limit = $this->getState('limit');
// Create the pagination object
$this->pagination = new Pagination($total, $limitStart, $limit, 10, $this->container);
}
return $this->pagination;
}
/**
* Gets the post-processing engine for each backup profile
*
* @return array Key/value where key=profile ID, value=post-processing engine
*/
public function getPostProcessingEnginePerProfile()
{
// Cache the current profile
$currentProfileID = Platform::getInstance()->get_active_profile();
$db = $this->container->db;
$query = $db->getQuery(true)
->select($db->qn('id'))
->from($db->qn('#__ak_profiles'));
$db->setQuery($query);
$profiles = $db->loadColumn();
$engines = [];
foreach ($profiles as $profileID)
{
Platform::getInstance()->load_configuration($profileID);
$pConf = Factory::getConfiguration();
$engines[$profileID] = $pConf->get('akeeba.advanced.postproc_engine');
}
Platform::getInstance()->load_configuration($currentProfileID);
return $engines;
}
public function hideRestorationInstructionsModal()
{
$config = $this->container->appConfig;
$config->set('options.show_howtorestoremodal', 0);
$config->saveConfiguration();
}
/**
* Freeze or melt a backup report
*
* @param array $ids Array of backup IDs that should be updated
* @param int $freeze 1= freeze, 0= melt
*
* @throws Exception
*/
public function freezeUnfreezeRecords(array $ids, $freeze)
{
if (!$ids)
{
return;
}
$freeze = (int) $freeze;
foreach ($ids as $id)
{
// If anything wrong happens, let the exception bubble up, so it will be reported
Platform::getInstance()->set_or_update_statistics($id, ['frozen' => $freeze]);
}
}
/**
* Deletes the backup-specific log files of a stats record
*
* @param array $stat The array holding the backup stats record
*
* @return void
*/
protected function _deleteLogs(array $stat)
{
// We can't delete logs if there is no backup ID in the record
if (!isset($stat['backupid']) || empty($stat['backupid']))
{
return;
}
$fs = $this->container->fileSystem;
$logFileNames = [
'akeeba.' . $stat['tag'] . '.' . $stat['backupid'] . '.log',
'akeeba.' . $stat['tag'] . '.' . $stat['backupid'] . '.log.php',
];
foreach ($logFileNames as $logFileName)
{
$logPath = dirname($stat['absolute_path']) . '/' . $logFileName;
try
{
$fs->delete($logPath);
}
catch (\Exception $e)
{
// Ignore file deletion failure
}
}
}
}