sdf
This commit is contained in:
@@ -13,7 +13,7 @@ if (!is_writable($log_directory)) {
|
||||
}
|
||||
|
||||
$timestamp = date('YmdHis');
|
||||
$file_log = "$log_directory/trierPhotos_$timestamp.log";
|
||||
$file_log = "$log_directory/trierPhotos_$timestamp.log";
|
||||
$file_undo = "$log_directory/trierPhotos_$timestamp" . "_undo.log";
|
||||
|
||||
function logMessage($file, $message) {
|
||||
@@ -21,99 +21,156 @@ function logMessage($file, $message) {
|
||||
echo $message . "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Détermine le chemin de destination final selon les règles :
|
||||
* - Si dest n’existe pas -> renvoie ce chemin (string).
|
||||
* - S’il existe et SHA1 identique -> renvoie false (doublon déjà présent).
|
||||
* - Sinon, tente filename_1.ext, filename_2.ext, ... :
|
||||
* - si l’un existe et a le même SHA1 -> false (déjà présent sous variante).
|
||||
* - sinon renvoie le premier nom libre.
|
||||
*/
|
||||
function computeDestinationPath(string $src, string $destDir, string $baseName): string|false {
|
||||
$srcSha1 = @sha1_file($src);
|
||||
if ($srcSha1 === false) return false;
|
||||
|
||||
$destPath = $destDir . '/' . $baseName;
|
||||
if (!file_exists($destPath)) {
|
||||
return $destPath;
|
||||
}
|
||||
|
||||
$dstSha1 = @sha1_file($destPath);
|
||||
if ($dstSha1 !== false && hash_equals($srcSha1, $dstSha1)) {
|
||||
return false; // doublon exact déjà en place
|
||||
}
|
||||
|
||||
$pi = pathinfo($baseName);
|
||||
$name = $pi['filename'] ?? $baseName;
|
||||
$ext = isset($pi['extension']) ? ('.' . $pi['extension']) : '';
|
||||
|
||||
for ($i = 1; $i <= 10000; $i++) {
|
||||
$candidate = $destDir . '/' . $name . '_' . $i . $ext;
|
||||
if (!file_exists($candidate)) {
|
||||
return $candidate; // premier nom libre
|
||||
}
|
||||
// si existe, comparer le SHA1
|
||||
$candSha1 = @sha1_file($candidate);
|
||||
if ($candSha1 !== false && hash_equals($srcSha1, $candSha1)) {
|
||||
return false; // déjà présent sous une variante
|
||||
}
|
||||
}
|
||||
return false; // garde-fou
|
||||
}
|
||||
|
||||
/** Déplace un fichier (rename sinon copy+unlink) */
|
||||
function moveFile(string $src, string $dst): bool {
|
||||
// Essai direct
|
||||
if (@rename($src, $dst)) return true;
|
||||
// Fallback inter-filesystems
|
||||
if (@copy($src, $dst)) {
|
||||
if (@unlink($src)) return true;
|
||||
// rollback si on n'arrive pas à supprimer la source
|
||||
@unlink($dst);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
logMessage($file_log, "Début du script : " . date("c"));
|
||||
logMessage($file_log, "Lieu d'exécution : " . getcwd());
|
||||
|
||||
if ($handle = opendir('.')) {
|
||||
while (($entry = readdir($handle)) !== false) {
|
||||
if ($entry === '.' || $entry === '..') continue;
|
||||
if (!is_file($entry)) continue; // ignore dossiers et liens
|
||||
|
||||
$mime_type = explode("/", mime_content_type($entry));
|
||||
$mime = @mime_content_type($entry) ?: '';
|
||||
$mime_type = explode("/", $mime . '/');
|
||||
logMessage($file_log, "\nFichier détecté : $entry");
|
||||
logMessage($file_log, "MIME type : {$mime_type[0]}");
|
||||
|
||||
$traitement_ok = in_array($mime_type[0], ['image', 'video']);
|
||||
$traitement_ok = in_array($mime_type[0], ['image', 'video'], true);
|
||||
$dateTimeOriginal = null;
|
||||
|
||||
// Lecture des métadonnées EXIF
|
||||
if ($traitement_ok && $mime_type[0] === 'image' && $mime_type[1] === 'jpeg') {
|
||||
|
||||
// EXIF (JPEG uniquement)
|
||||
if ($traitement_ok && $mime_type[0] === 'image' && ($mime_type[1] ?? '') === 'jpeg') {
|
||||
$file_exif = @exif_read_data($entry, 'EXIF');
|
||||
if (!empty($file_exif['DateTimeOriginal'])) {
|
||||
$date_exif = explode(':', str_replace(' ', ':', $file_exif['DateTimeOriginal']));
|
||||
$dateTimeOriginal = [
|
||||
'y' => $date_exif[0],
|
||||
'm' => $date_exif[1],
|
||||
'd' => $date_exif[2]
|
||||
];
|
||||
logMessage($file_log, "EXIF DateTimeOriginal : {$file_exif['DateTimeOriginal']}");
|
||||
if (count($date_exif) >= 3) {
|
||||
$dateTimeOriginal = [
|
||||
'y' => (int)$date_exif[0],
|
||||
'm' => (int)$date_exif[1],
|
||||
'd' => (int)$date_exif[2]
|
||||
];
|
||||
logMessage($file_log, "EXIF DateTimeOriginal : {$file_exif['DateTimeOriginal']}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Détection via le nom du fichier
|
||||
|
||||
// Nom du fichier
|
||||
if (!$dateTimeOriginal) {
|
||||
if (preg_match('/^(IMG-|VID_|IMG_|VID-)(\d{4})(\d{2})(\d{2})/', $entry, $matches)) {
|
||||
$dateTimeOriginal = [
|
||||
'y' => $matches[2],
|
||||
'm' => $matches[3],
|
||||
'd' => $matches[4]
|
||||
];
|
||||
if (preg_match('/^(IMG-|VID_|IMG_|VID-)(\d{4})(\d{2})(\d{2})/i', $entry, $m)) {
|
||||
$dateTimeOriginal = ['y' => (int)$m[2], 'm' => (int)$m[3], 'd' => (int)$m[4]];
|
||||
logMessage($file_log, "Date extraite du nom de fichier.");
|
||||
} elseif (preg_match('/^Screenshot_(\d{4})(\d{2})(\d{2})/', $entry, $matches)) {
|
||||
$dateTimeOriginal = [
|
||||
'y' => $matches[1],
|
||||
'm' => $matches[2],
|
||||
'd' => $matches[3]
|
||||
];
|
||||
} elseif (preg_match('/^Screenshot_(\d{4})(\d{2})(\d{2})/i', $entry, $m)) {
|
||||
$dateTimeOriginal = ['y' => (int)$m[1], 'm' => (int)$m[2], 'd' => (int)$m[3]];
|
||||
logMessage($file_log, "Date extraite du nom de fichier (Screenshot_...).");
|
||||
}
|
||||
}
|
||||
|
||||
// Vérification et correction des dates
|
||||
|
||||
// Sanity check des dates
|
||||
if ($dateTimeOriginal) {
|
||||
if ($dateTimeOriginal['m'] < 1 || $dateTimeOriginal['m'] > 12 ||
|
||||
$dateTimeOriginal['d'] < 1 || $dateTimeOriginal['d'] > 31 ||
|
||||
$dateTimeOriginal['y'] < 1900 || $dateTimeOriginal['y'] > date('Y')) {
|
||||
$dateTimeOriginal['y'] < 1900 || $dateTimeOriginal['y'] > (int)date('Y')) {
|
||||
$dateTimeOriginal = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Utilisation de la date de modification si aucune autre date trouvée
|
||||
|
||||
// À défaut, mtime
|
||||
if (!$dateTimeOriginal) {
|
||||
$date_modif = explode(':', date('Y:m:d', filemtime($entry)));
|
||||
$date_modif = explode(':', date('Y:m:d', @filemtime($entry) ?: time()));
|
||||
$dateTimeOriginal = [
|
||||
'y' => $date_modif[0],
|
||||
'm' => $date_modif[1],
|
||||
'd' => $date_modif[2]
|
||||
'y' => (int)$date_modif[0],
|
||||
'm' => (int)$date_modif[1],
|
||||
'd' => (int)$date_modif[2]
|
||||
];
|
||||
logMessage($file_log, "Date issue du mtime : {$date_modif[0]}-{$date_modif[1]}-{$date_modif[2]}");
|
||||
}
|
||||
|
||||
// Création du dossier de destination et déplacement
|
||||
// Dossier + déplacement
|
||||
if ($dateTimeOriginal) {
|
||||
$rep_dest = "{$dateTimeOriginal['y']}/{$dateTimeOriginal['m']}/{$dateTimeOriginal['d']}";
|
||||
$rep_dest = sprintf('%04d/%02d/%02d', $dateTimeOriginal['y'], $dateTimeOriginal['m'], $dateTimeOriginal['d']);
|
||||
if (!is_dir($rep_dest)) {
|
||||
mkdir($rep_dest, 0777, true);
|
||||
if (!mkdir($rep_dest, 0777, true) && !is_dir($rep_dest)) {
|
||||
logMessage($file_log, "[ERREUR] Impossible de créer le dossier : $rep_dest");
|
||||
continue;
|
||||
}
|
||||
logMessage($file_log, "Dossier créé : $rep_dest");
|
||||
}
|
||||
|
||||
$file_dest = "$rep_dest/$entry";
|
||||
if (file_exists($file_dest)) {
|
||||
$md5_src = md5_file($entry);
|
||||
$md5_dst = md5_file($file_dest);
|
||||
|
||||
if ($md5_src === $md5_dst) {
|
||||
unlink($entry);
|
||||
logMessage($file_log, "[INFO] Doublon exact détecté et supprimé : $file_dest");
|
||||
|
||||
$finalPath = computeDestinationPath($entry, $rep_dest, basename($entry));
|
||||
if ($finalPath === false) {
|
||||
// Un doublon identique existe déjà quelque part dans $rep_dest
|
||||
if (@unlink($entry)) {
|
||||
logMessage($file_log, "[INFO] Doublon exact détecté -> source supprimée : $entry");
|
||||
// Undo = rien à faire (le fichier existe déjà en dest)
|
||||
} else {
|
||||
// Générer un nom unique en ajoutant un suffixe MD5 ou un timestamp
|
||||
$file_info = pathinfo($entry);
|
||||
$new_filename = $file_info['filename'] . "_" . substr($md5_src, 0, 8) . "." . $file_info['extension'];
|
||||
$file_dest_unique = "$rep_dest/$new_filename";
|
||||
|
||||
rename($entry, $file_dest_unique);
|
||||
logMessage($file_log, "[INFO] Conflit évité, fichier renommé et déplacé : $file_dest_unique");
|
||||
file_put_contents($file_undo, "mv \"$file_dest_unique\" \"$entry\"\n", FILE_APPEND);
|
||||
logMessage($file_log, "[ERREUR] Impossible de supprimer la source doublon : $entry");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Déplacer (rename, sinon copy+unlink)
|
||||
if (moveFile($entry, $finalPath)) {
|
||||
logMessage($file_log, "[OK] Déplacé : $entry → $finalPath");
|
||||
file_put_contents($file_undo, "mv \"$finalPath\" \"$entry\"\n", FILE_APPEND);
|
||||
} else {
|
||||
logMessage($file_log, "[ERREUR] Échec du déplacement : $entry → $finalPath");
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir($handle);
|
||||
}
|
||||
|
||||
logMessage($file_log, "Fin du script : " . date("c"));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user