Заказчик заливает фаилы через фтп, нужно сделать скрипт который генерирует фотографии (в разных форматах, с водяным знаком и без). Но вот нельзя просто взять и синхронизировать каталоги (мем.jpg). Условия: 1. Имена субдиректорий и фаилов, так же как и структуру папок, в source нельзя менять. 2. В одной субпапке sourc'a может быть от 1 до 40 фотографий маленьких и средних размеров 3. Папок destination - 5 штук, но для простоты я нарисовал только 2. 4. Папки и фаилы в destination обязательно должны быть переименованы, так как в папке source могут иметь слишком длинные имена. А PHP не может удалять фаилы с слишком длинными именами... Да и вообще, есть еще пара причин. 5. Если были добавлены/удалены/изменены фотографии в субдиректориях, то изменения должны коснуться субдиректорий destination. (спс, кэп!). Причём при изменении фотографии, ее имя должно поменяться для папок destination. 6. Порядок фотографий всегда должен быть идентичным. Спойлер: Структура папок [source] ----[a, b, c] --------a, b, c-1.jpg --------a, b, c-2.jpg ----[q, e, w] --------q, e, w-1.jpg --------q, e, w-2.jpg ----[r, w, q] --------r, w, q-1.jpg --------r, w, q-2.jpg [destination-1] ----[a_b_c] --------1_(md5_file).jpg --------2_(md5_file).jpg ----[q_e_w] --------1_(md5_file).jpg --------2_(md5_file).jpg ----[r_w_q] --------1_(md5_file).jpg --------2_(md5_file).jpg [destination-2] ----[a_b_c] --------1_(md5_file).jpg --------2_(md5_file).jpg ----[q_e_w] --------1_(md5_file).jpg --------2_(md5_file).jpg ----[r_w_q] --------1_(md5_file).jpg --------2_(md5_file).jpg Вот моё решение: 1. Генерируем список фаилов source с md5_file в таком формате: Спойлер: Массив [ ----[a, b, c] => [ --------a, b, c-1.jpg => md5_file --------a, b, c-2.jpg => md5_file --------], ----[q, e, w] => [ --------q, e, w-1.jpg => md5_file --------q, e, w-2.jpg => md5_file --------], ----[r, w, q] => [ --------r, w, q-1.jpg => md5_file --------r, w, q-2.jpg => md5_file --------], ] 2. Загружаем результаты старого скана из фаила (у меня Json) 3. Ищем папки которые были удалены, и папки которые были изменены. Удаляем и те и другие. 4. Формируем список фаилов которые должны быть сгенерированы. 5. С помощью ajax генерируем фаилы в destination's, проверяя существует ли папка с новым именем. 6. Если всё прошло удачно, сохраняю новый список в фаил. Что меня не устраивает, так это при изменении одной фотографии, все фаилы в папке будут удалены и сгенерированы заного. Но иначе я не знаю как сохранить порядок фотографий... Вопрос: может быть у вас есть решение поэлегантней? где ненужно перелопачивать всю папку ради одной изменённой фотки...
Забыл сказать: загрузка фаилов должна быть только через фтп. Заказчик не желает загружать каждую субпапку отдельным архивом через форму. Он согласен только на загрузку всей папки source архивом, но ясно-понятно что ни один малобюджетный хостинг нам этого не предоставит.
вообще это о чем... что за порядок файлов? порядок - он как тебе надо - так и будет - в зависимости от того какая сортировка задана
Даже zip архив. Папок много и если ему вздумается поменять несколько, то ему лень вспоминать какие он менял, а какие - нет. Он согласен только на весь каталог сразу, но я пологаю что хостинг не позволит так как сжатый на ультрах весит 700+ мб Тут дело не в сортировке массива фотографий, а в том, что каждый раз когда он делает манипуляции с фотографиями в субпапке, он обновляет имена. Например, массив фотографий до изменений: [photo1, photo2, photo3, photo4]. Он удалил photo2 и поменял контраст в photo4 и добавил еще одну фотку в конец массива. После этого он каждый раз переименовывает все фотки : [photo1, photo2(ранее photo3), photo3 (ранее photo4), photo4(новая)]. Моя задача (в идеале) определить что фото2 была удалена и удалить ее из других каталогов, и обновить photo3 и переименовать его из 3-{md5_file() старого фаила} в 3-{md5_file() изменённого} и создать photo4 c именем 4-{md5_file() источника}. Но на данный момент я просто определяю что были изменения в папке источника, удаляю папку из каталогов и генерирую ее снова. Надеюсь, мой пример прост в понимании.
Я полностью поддерживаю ваше мнения и с удовольствием бы переписал всё, но это уже совсем другая история. Спасибо Вам за потраченное время, пойду дальше собирать Франкенштейна.
Учитывая данное условие: Код (Text): 1. Имена субдиректорий и фаилов, так же как и структуру папок, в source нельзя менять. Можно предложить следующее решение: 1. Выявить файлы, которые были изменены (по содержанию), удалены, созданы. 2. Сделать соответствующие операции по синхронизации с папкой destination-* Функция findFilesThatWereChanged() вызывается из функции synchronizeFiles(). Могут быть ошибки в синтаксисе, так как было противостояние js, c# и php. PHP: function findFilesThatWereChanged($oldTree, $newTree) { $changes = [ 'created' => [], 'removed' => [], 'changed' => [] ]; foreach($newTree as $subfolder_name => $subfolder_files) { // так как мы точно знаем, что папка [a,b,c] будет существовать, то идем дальше foreach($subfolder_files as $filename => $fileMd5) { // ловим те файлы, которые созданы if (!array_key_exists($filename, $oldTree[$subfolder_name])) { $changes['created'].push( [ $filename => [ 'subfolder' => $subfolder_name, 'md5' => $fileMd5, ] ]); } $md5Old = $oldTree[$subfolder_name][$filename]; $md5New = $newTree[$subfolder_name][$filename]; // ловим те файлы, которые изменены if (array_key_exists($fileName, $oldTree[$subfolder_name]) && $md5Old != $md5New) { $changes['changed'].push( [ $filename => [ 'subfolder' => $subfolder_name, 'md5' => $fileMd5, ] ]); } } } // чтобы узнать какие файлы были удалены найдем имена (ключи), которых нет в новом дереве foreach($oldTree as $subfolder_name => $subfolder_files) { // так как мы точно знаем, что папка [a,b,c] будет существовать, то идем дальше foreach($subfolder_files as $filename => $fileMd5) { if (!array_key_exists($filename, $newTree[$subfolder_name])) { $changes['removed'].push( [ $filename => [ 'subfolder' => $subfolder_name, 'md5' => $fileMd5, ] ]); } } } return $changes; } function synchronizeFiles() { const SOURCE_FOLDER = __DIR__. '/source'; const DESTINATIONS_AMOUNT = 5; const DESTINATION_FOLDER_PREFIX = 'destination'; // генерируем названия папок destination $destination_folders = []; for ($i = 1; $i <= 5; $i++) { $destination_folders.push(DESTINATION_FOLDER_PREFIX. '-' . $i); } // $oldTree и $newTree это представления папки source // массив сгенерированный в прошлый раз, который сейчас находится в определенном файле .json $oldTree = [ ['a, b, c'] => [ 'сamera-canon-g245.jpg' => 'md5-9000' ] ]; // массив, который сейчас сгенерировали $newTree = [ ['a, b, c'] => [ 'сamera-canon-g245.jpg' => 'md5-9999' ] ]; $changes = findFilesThatWereChanged($oldTree, $newTree); // теперь мы знаем какие файлы удалены, добавлены и изменены // синхронизируем с destination, итерируем каждый затронутый файл foreach($changes['changed'] as $filename => $fileInfo) { // ищем старую версию файла в destination-* папках foreach($destination_folders as $key => $destination_folder) { $destination = __DIR__. '/' . $destination_folder; // проверяем, что такая папка destination-* существует if (is_dir($destination)) { // 1_старый-md5.jpg $filenameRegex = "*_".$oldTree[$fileInfo['subfolder']][$filename]; // возвращается массив имен файлов, которые удовлетворяют регулярному выражению, // однако в нашем случае оно должно возвратить массив с одним именем файла, // так как такой файл по идее должен быть один. $file_names = glob($destination. "/". $fileInfo['subfolder'] . '/' . $filenameRegex); // если в данной папке destination-*/a,b,c файл найден, то ... if (!empty($file_names)) { // старый файл $old_md5_filename = $file_names[0]; // удаляем старый файл unlink($destination. "/" . $fileInfo['subfolder'] . '/' . $old_md5_filename); // где-то, как-то клеим водяной знак // и сохраняем по этому же пути с новым именем файла // а предварательно получим имя нового файла // получим порядковый номер фото 2_md5hash.jpg $number = explode('_', $old_md5_filename)[0]; // предположим, что для водяного знака нужно вызвать метод watermark($filename) // не забываем, что имя файла и поддиректория не изменны, тогда $newFile = watermark(SOURCE_FOLDER . '/' . $fileInfo['subfolder'] . '/' . $filename); // генерируем новое название файла // с расширением что-то не стал заморачиваться $newFileName = $number. "_" . md5($newFile) . ".jpg"; // сохраняем файл в destination-* file_put_contents($destination. "/".$fileInfo['subfolder']. '/'.$newFileName); break; } } } } foreach($changes['delete'] as $filename => $fileInfo) { // находим в destinations и просто удаляем } foreach($changes['created'] as $filename => $fileInfo) { // в какой из destinations добавлять файл я не знаю. // Может если в destination-1/a,b,c уже например > 100 файлов, тогда // проверять destination-2/a,b,c } // сохраняем новое дерево в .json файл file_put_contents(__DIR__. '/sourceFilesTree.json', $newTree); }
@виталий032, громнейшее спасибо! Правда я уже сделал рабочий костыль и проект уже на стадии тестирования, но мне за него стыдно. Поэтому при рефакторинге заменю свой код вашим, так как это именно то, что нужно! Еще раз спасибо!