Files
MokoSuiteBackup/source/packages/com_mokosuitebackup/src/Engine/DifferentialScanner.php
T
Jonathan Miller 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
feat: rename mokojoombackup → mokosuitebackup, add [HOME] placeholder for backup directory
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.
2026-06-11 12:24:27 -05:00

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;
}
}