ace33b60fe
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Access control (push) Successful in 2s
Universal: Auto Version Bump / Version Bump (push) Successful in 10s
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
Renames all sub-extensions from mokojoombackup to mokosuitebackup
(package, component, 7 plugins, language files, manifests).
Adds [HOME] placeholder to BackupDirectory and PlaceholderResolver
so users can set backup_dir to [HOME]/backups (outside web root).
Fixes folder browser "access denied" on PHP-FPM shared hosting
where getenv('HOME') returns empty by adding POSIX and JPATH_ROOT
fallback detection.
92 lines
2.5 KiB
PHP
92 lines
2.5 KiB
PHP
<?php
|
|
|
|
/**
|
|
* @package MokoSuiteBackup
|
|
* @subpackage com_mokosuitebackup
|
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
|
* @license GNU General Public License version 3 or later; see LICENSE
|
|
*
|
|
* Differential file scanner — compares current filesystem against a
|
|
* stored manifest from the last full backup. Only returns files that
|
|
* are new or modified since the base backup.
|
|
*
|
|
* Manifest format (JSON):
|
|
* {"path/to/file": {"size": 1234, "mtime": 1717350000}, ...}
|
|
*/
|
|
|
|
namespace Joomla\Component\MokoSuiteBackup\Administrator\Engine;
|
|
|
|
defined('_JEXEC') or die;
|
|
|
|
class DifferentialScanner
|
|
{
|
|
/**
|
|
* Build a file manifest for the current state of the site.
|
|
*
|
|
* @param string[] $filePaths Array of relative file paths (from FileScanner)
|
|
* @param string $rootDir Joomla root directory
|
|
*
|
|
* @return array<string, array{size: int, mtime: int}>
|
|
*/
|
|
public static function buildManifest(array $filePaths, string $rootDir): array
|
|
{
|
|
$manifest = [];
|
|
|
|
foreach ($filePaths as $relativePath) {
|
|
$fullPath = rtrim($rootDir, '/') . '/' . $relativePath;
|
|
|
|
if (!is_file($fullPath)) {
|
|
continue;
|
|
}
|
|
|
|
$manifest[$relativePath] = [
|
|
'size' => (int) filesize($fullPath),
|
|
'mtime' => (int) filemtime($fullPath),
|
|
];
|
|
}
|
|
|
|
return $manifest;
|
|
}
|
|
|
|
/**
|
|
* Compare current files against a base manifest and return only changed/new files.
|
|
*
|
|
* @param array $currentFiles Array of relative file paths from FileScanner
|
|
* @param array $baseManifest Manifest from the base full backup
|
|
* @param string $rootDir Joomla root directory
|
|
*
|
|
* @return string[] Array of relative paths that are new or modified
|
|
*/
|
|
public static function getChangedFiles(array $currentFiles, array $baseManifest, string $rootDir): array
|
|
{
|
|
$changed = [];
|
|
|
|
foreach ($currentFiles as $relativePath) {
|
|
$fullPath = rtrim($rootDir, '/') . '/' . $relativePath;
|
|
|
|
if (!is_file($fullPath)) {
|
|
continue;
|
|
}
|
|
|
|
// New file — not in base manifest
|
|
if (!isset($baseManifest[$relativePath])) {
|
|
$changed[] = $relativePath;
|
|
|
|
continue;
|
|
}
|
|
|
|
// Check if modified (size or mtime changed)
|
|
$currentSize = (int) filesize($fullPath);
|
|
$currentMtime = (int) filemtime($fullPath);
|
|
$baseEntry = $baseManifest[$relativePath];
|
|
|
|
if ($currentSize !== $baseEntry['size'] || $currentMtime !== $baseEntry['mtime']) {
|
|
$changed[] = $relativePath;
|
|
}
|
|
}
|
|
|
|
return $changed;
|
|
}
|
|
}
|