|
Server : LiteSpeed System : Linux terra.hostitbro.com 5.14.0-611.54.3.el9_7.x86_64 #1 SMP PREEMPT_DYNAMIC Thu May 7 16:31:24 EDT 2026 x86_64 User : outerorb ( 1091) PHP Version : 8.1.34 Disable Function : mail Directory : /home2/outerorb/.trash/ | |
|
Path: /home2/outerorb/.trash/2026-04-20-rename-uploads.php
Size: 10.7 KB
Permissions: 0644
<?php
/**
* Migration: Rename existing uploaded files to include employee name + phone prefix.
*
* SAFE TO RUN:
* - Reads DB paths, renames the physical file, then updates the DB in the same transaction.
* - Skips files that are already prefixed or cannot be found on disk.
* - Dry-run mode (default) shows what WOULD be renamed without touching anything.
*
* HOW TO RUN:
* 1. Upload this file to the server (or run locally on Laragon).
* 2. Open in browser:
* https://emp.outerorbittech.in/migrations/2026-04-20-rename-uploads.php?run=1&secret=CHANGE_ME
* Or on localhost:
* http://localhost/emp.outerorbittech.in/migrations/2026-04-20-rename-uploads.php?run=1&secret=CHANGE_ME
* 3. Omit ?run=1 (or keep ?run=0) for a dry-run preview first.
* 4. DELETE this file from the server after running.
*
* SECURITY: Change the secret below before uploading to the server.
*/
define('MIGRATION_SECRET', 'OuterOrbit@2026');
if (php_sapi_name() !== 'cli') {
$secret = $_GET['secret'] ?? '';
if (!hash_equals(MIGRATION_SECRET, $secret)) {
http_response_code(403);
die('Forbidden. Pass ?secret=YOUR_SECRET in the URL.');
}
}
$dryRun = !(($_GET['run'] ?? '0') === '1' || (php_sapi_name() === 'cli' && in_array('--run', array_slice($argv ?? [], 1), true)));
require __DIR__ . '/../includes/helpers.php';
// Remove execution time limit and disable output buffering so progress is visible.
set_time_limit(0);
while (ob_get_level() > 0) {
ob_end_clean();
}
ob_implicit_flush(true);
$pdo = db();
// -----------------------------------------------------------------------
// Helper: build prefix the same way handle_upload() does
// -----------------------------------------------------------------------
function build_prefix(string $firstName, string $lastName, string $phone): string
{
return make_upload_prefix($firstName, $lastName, $phone);
}
// -----------------------------------------------------------------------
// Detect whether a filename looks like the old random-only format
// (32 hex chars with optional extension) so we skip already-prefixed files.
// -----------------------------------------------------------------------
function is_legacy_filename(string $basename): bool
{
return (bool) preg_match('/^[a-f0-9]{16,32}(\.[a-z0-9]+)?$/i', $basename);
}
// -----------------------------------------------------------------------
// Rename a file on disk and return the new path, or null on failure.
// -----------------------------------------------------------------------
function safe_rename_file(string $oldPath, string $newPath): bool
{
if (!file_exists($oldPath)) {
return false;
}
if (file_exists($newPath)) {
// Destination already exists – generate a slightly different name to avoid collision
$info = pathinfo($newPath);
$newPath = $info['dirname'] . '/' . $info['filename'] . '_1.' . ($info['extension'] ?? '');
}
return rename($oldPath, $newPath);
}
// -----------------------------------------------------------------------
// Process a single stored path value (plain path OR JSON aadhaar value)
// Returns ['updated' => bool, 'newValue' => string, 'log' => array]
// -----------------------------------------------------------------------
function process_path_value(
?string $storedValue,
string $prefix,
string $uploadDir,
bool $dryRun,
bool $isAadhaar = false
): array {
$log = [];
$stored = trim((string) $storedValue);
if ($stored === '') {
return ['updated' => false, 'newValue' => $stored, 'log' => $log];
}
if ($isAadhaar) {
// May be JSON {"front":"/path","back":"/path"} or a plain legacy path
$decoded = json_decode($stored, true);
if (is_array($decoded)) {
$changed = false;
foreach (['front', 'back', 'single'] as $part) {
if (empty($decoded[$part])) {
continue;
}
$result = process_single_path($decoded[$part], $prefix . '_aadhaar-' . $part, $uploadDir, $dryRun, $log);
if ($result['updated']) {
$decoded[$part] = $result['newPath'];
$changed = true;
}
}
return [
'updated' => $changed,
'newValue' => $changed ? json_encode($decoded, JSON_UNESCAPED_SLASHES) : $stored,
'log' => $log,
];
}
// Fallthrough: plain legacy path for aadhaar
$result = process_single_path($stored, $prefix . '_aadhaar', $uploadDir, $dryRun, $log);
return ['updated' => $result['updated'], 'newValue' => $result['newPath'], 'log' => $log];
}
$result = process_single_path($stored, $prefix, $uploadDir, $dryRun, $log);
return ['updated' => $result['updated'], 'newValue' => $result['newPath'], 'log' => $log];
}
function process_single_path(string $stored, string $prefix, string $uploadDir, bool $dryRun, array &$log): array
{
$basename = basename($stored);
if (!is_legacy_filename($basename)) {
$log[] = " SKIP (already prefixed): $basename";
return ['updated' => false, 'newPath' => $stored];
}
// Resolve actual file location
$realPath = null;
if (file_exists($stored)) {
$realPath = $stored;
} else {
$candidate = rtrim($uploadDir, '/\\') . DIRECTORY_SEPARATOR . $basename;
if (file_exists($candidate)) {
$realPath = $candidate;
}
}
if (!$realPath) {
// Check if the file was already renamed in a previous partial run.
// The new name would be: $prefix . '_' . first16charsOfHex . '.' . ext
$ext = pathinfo($basename, PATHINFO_EXTENSION);
$random = substr($basename, 0, 16);
$expectedNewBasename = $prefix . '_' . $random . ($ext ? '.' . $ext : '');
$expectedNewPath = rtrim($uploadDir, '/\\') . DIRECTORY_SEPARATOR . $expectedNewBasename;
if (file_exists($expectedNewPath)) {
// File was already renamed in a previous partial run — only update the DB.
$newStored = (dirname($stored) !== '.' ? dirname($stored) . '/' : '') . $expectedNewBasename;
$log[] = " DB-ONLY (already renamed on disk): $basename → $expectedNewBasename";
return ['updated' => true, 'newPath' => $newStored];
}
$log[] = " SKIP (file not found on disk): $basename";
return ['updated' => false, 'newPath' => $stored];
}
$ext = pathinfo($basename, PATHINFO_EXTENSION);
$random = substr($basename, 0, 16); // keep first 16 chars of old random for uniqueness
$newBasename = $prefix . '_' . $random . ($ext ? '.' . $ext : '');
$newRealPath = dirname($realPath) . DIRECTORY_SEPARATOR . $newBasename;
// The stored DB value may be an absolute path or just the basename.
// Reconstruct the new stored value in the same style.
$newStored = (dirname($stored) !== '.' ? dirname($stored) . '/' : '') . $newBasename;
$log[] = " RENAME: $basename → $newBasename";
if (!$dryRun) {
if (!safe_rename_file($realPath, $newRealPath)) {
$log[] = " ERROR: rename failed for $realPath";
return ['updated' => false, 'newPath' => $stored];
}
}
return ['updated' => true, 'newPath' => $newStored];
}
// -----------------------------------------------------------------------
// Main loop
// -----------------------------------------------------------------------
$stmt = $pdo->query(
'SELECT id, first_name, last_name, phone,
aadhaar_path, pan_path, qualification_path, bank_proof_path, photo_path
FROM employees WHERE deleted_at IS NULL ORDER BY id'
);
$employees = $stmt->fetchAll(PDO::FETCH_ASSOC);
$columns = [
'aadhaar_path' => ['isAadhaar' => true, 'label' => 'Aadhaar'],
'pan_path' => ['isAadhaar' => false, 'label' => 'PAN'],
'qualification_path' => ['isAadhaar' => false, 'label' => 'Qualification'],
'bank_proof_path' => ['isAadhaar' => false, 'label' => 'Bank Proof'],
'photo_path' => ['isAadhaar' => false, 'label' => 'Photo'],
];
$config = app_config();
$uploadDir = $config['uploads']['dir'];
$totalRenamed = 0;
$totalSkipped = 0;
$totalErrors = 0;
header('Content-Type: text/plain; charset=utf-8');
echo ($dryRun ? "DRY RUN — no files will be changed. Add ?run=1 to apply.\n" : "LIVE RUN — renaming files.\n");
echo "=========================================================\n\n";
// Ensure aadhaar_path column is wide enough for JSON with two long absolute paths.
try {
$pdo->exec("ALTER TABLE employees MODIFY COLUMN aadhaar_path TEXT NOT NULL");
echo "ALTER TABLE: aadhaar_path expanded to TEXT.\n\n";
} catch (Throwable $e) {
echo "ALTER TABLE skipped/failed: " . $e->getMessage() . "\n\n";
}
foreach ($employees as $emp) {
$prefix = build_prefix($emp['first_name'], $emp['last_name'], $emp['phone']);
$updates = [];
$allLog = [];
foreach ($columns as $col => $opts) {
$result = process_path_value(
$emp[$col],
$prefix . '_' . str_replace('_path', '', $col),
$uploadDir,
$dryRun,
$opts['isAadhaar']
);
if ($result['updated']) {
$updates[$col] = $result['newValue'];
$totalRenamed++;
}
foreach ($result['log'] as $line) {
$allLog[] = "[{$opts['label']}] $line";
}
}
if (!empty($updates) || !empty($allLog)) {
echo "Employee #{$emp['id']}: {$emp['first_name']} {$emp['last_name']} ({$emp['phone']})\n";
foreach ($allLog as $line) {
echo " $line\n";
}
}
if (!empty($updates) && !$dryRun) {
$setClauses = implode(', ', array_map(fn($c) => "`$c` = ?", array_keys($updates)));
$values = array_values($updates);
$values[] = $emp['id'];
try {
$pdo->prepare("UPDATE employees SET $setClauses WHERE id = ?")->execute($values);
echo " DB updated.\n";
} catch (Throwable $e) {
echo " DB ERROR: " . $e->getMessage() . "\n";
$totalErrors++;
}
}
// Flush output so progress is visible even under buffering/timeout.
flush();
}
echo "\n=========================================================\n";
echo "Done. Renamed: $totalRenamed | Errors: $totalErrors\n";
if ($dryRun) {
echo "\nThis was a DRY RUN. No files or DB rows were changed.\n";
echo "To apply, add ?run=1&secret=" . MIGRATION_SECRET . " to the URL.\n";
}