144 lines
4.9 KiB
PHP
144 lines
4.9 KiB
PHP
<?php
|
||
/**
|
||
* scan_uploads.php
|
||
* Rebuild/repair per-folder metadata used by FileRise models.
|
||
* - Uses UPLOAD_DIR / META_DIR / DATE_TIME_FORMAT from config.php
|
||
* - Per-folder metadata naming matches FileModel/FolderModel:
|
||
* "root" -> root_metadata.json
|
||
* "<sub/dir>" -> str_replace(['/', '\\', ' '], '-', '<sub/dir>') . '_metadata.json'
|
||
*/
|
||
|
||
require_once __DIR__ . '/../config/config.php';
|
||
|
||
// ---------- helpers that mirror model behavior ----------
|
||
|
||
/** Compute the metadata JSON path for a folder key (e.g., "root", "invoices/2025"). */
|
||
function folder_metadata_path(string $folderKey): string {
|
||
if (strtolower(trim($folderKey)) === 'root' || trim($folderKey) === '') {
|
||
return rtrim(META_DIR, '/\\') . '/root_metadata.json';
|
||
}
|
||
$safe = str_replace(['/', '\\', ' '], '-', trim($folderKey));
|
||
return rtrim(META_DIR, '/\\') . '/' . $safe . '_metadata.json';
|
||
}
|
||
|
||
/** Turn an absolute path under UPLOAD_DIR into a folder key (“root” or relative with slashes). */
|
||
function to_folder_key(string $absPath): string {
|
||
$base = rtrim(UPLOAD_DIR, '/\\') . DIRECTORY_SEPARATOR;
|
||
if (realpath($absPath) === realpath(rtrim(UPLOAD_DIR, '/\\'))) {
|
||
return 'root';
|
||
}
|
||
$rel = ltrim(str_replace('\\', '/', substr($absPath, strlen($base))), '/');
|
||
return $rel;
|
||
}
|
||
|
||
/** List immediate files in a directory (no subdirs). */
|
||
function list_files(string $dir): array {
|
||
$out = [];
|
||
$entries = @scandir($dir);
|
||
if ($entries === false) return $out;
|
||
foreach ($entries as $name) {
|
||
if ($name === '.' || $name === '..') continue;
|
||
$p = $dir . DIRECTORY_SEPARATOR . $name;
|
||
if (is_file($p)) $out[] = $name;
|
||
}
|
||
sort($out, SORT_NATURAL | SORT_FLAG_CASE);
|
||
return $out;
|
||
}
|
||
|
||
/** Recursively list subfolders (relative folder keys), skipping trash/. */
|
||
function list_all_folders(string $root): array {
|
||
$root = rtrim($root, '/\\');
|
||
$folders = ['root'];
|
||
$it = new RecursiveIteratorIterator(
|
||
new RecursiveDirectoryIterator($root, FilesystemIterator::SKIP_DOTS),
|
||
RecursiveIteratorIterator::SELF_FIRST
|
||
);
|
||
foreach ($it as $path => $info) {
|
||
if ($info->isDir()) {
|
||
// relative key like "foo/bar"
|
||
$rel = ltrim(str_replace(['\\'], '/', substr($path, strlen($root) + 1)), '/');
|
||
if ($rel === '') continue;
|
||
// skip trash and profile_pics subtrees
|
||
if ($rel === 'trash' || strpos($rel, 'trash/') === 0) continue;
|
||
if ($rel === 'profile_pics' || strpos($rel, 'profile_pics/') === 0) continue;
|
||
// obey the app’s folder-name regex to stay consistent
|
||
if (preg_match(REGEX_FOLDER_NAME, basename($rel))) {
|
||
$folders[] = $rel;
|
||
}
|
||
}
|
||
}
|
||
// de-dup and sort
|
||
$folders = array_values(array_unique($folders));
|
||
sort($folders, SORT_NATURAL | SORT_FLAG_CASE);
|
||
return $folders;
|
||
}
|
||
|
||
// ---------- main ----------
|
||
|
||
$uploads = rtrim(UPLOAD_DIR, '/\\');
|
||
$metaDir = rtrim(META_DIR, '/\\');
|
||
|
||
// Ensure metadata dir exists
|
||
if (!is_dir($metaDir)) {
|
||
@mkdir($metaDir, 0775, true);
|
||
}
|
||
|
||
$now = date(DATE_TIME_FORMAT);
|
||
$folders = list_all_folders($uploads);
|
||
|
||
$totalCreated = 0;
|
||
$totalPruned = 0;
|
||
|
||
foreach ($folders as $folderKey) {
|
||
$absFolder = ($folderKey === 'root')
|
||
? $uploads
|
||
: $uploads . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $folderKey);
|
||
|
||
if (!is_dir($absFolder)) continue;
|
||
|
||
$files = list_files($absFolder);
|
||
|
||
$metaPath = folder_metadata_path($folderKey);
|
||
$metadata = [];
|
||
if (is_file($metaPath)) {
|
||
$decoded = json_decode(@file_get_contents($metaPath), true);
|
||
if (is_array($decoded)) $metadata = $decoded;
|
||
}
|
||
|
||
// Build a quick lookup of existing entries
|
||
$existing = array_keys($metadata);
|
||
|
||
// ADD missing files
|
||
foreach ($files as $name) {
|
||
// Keep same filename validation used in FileModel
|
||
if (!preg_match(REGEX_FILE_NAME, $name)) continue;
|
||
|
||
if (!isset($metadata[$name])) {
|
||
$metadata[$name] = [
|
||
'uploaded' => $now,
|
||
'modified' => $now,
|
||
'uploader' => 'Imported'
|
||
];
|
||
$totalCreated++;
|
||
echo "Indexed: " . ($folderKey === 'root' ? '' : $folderKey . '/') . $name . PHP_EOL;
|
||
}
|
||
}
|
||
|
||
// PRUNE stale metadata entries for files that no longer exist
|
||
foreach ($existing as $name) {
|
||
if (!in_array($name, $files, true)) {
|
||
unset($metadata[$name]);
|
||
$totalPruned++;
|
||
}
|
||
}
|
||
|
||
// Ensure parent dir exists and write metadata
|
||
@mkdir(dirname($metaPath), 0775, true);
|
||
if (@file_put_contents($metaPath, json_encode($metadata, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)) === false) {
|
||
fwrite(STDERR, "Failed to write metadata for folder: {$folderKey}\n");
|
||
}
|
||
}
|
||
|
||
echo "Done. Created {$totalCreated} entr" . ($totalCreated === 1 ? "y" : "ies") .
|
||
", pruned {$totalPruned}.\n";
|