Search
Write a publication
Pull to refresh

Восстановление данных с флешки средствами PHP

— Привет, это Иван Иваныч. Мы говорили с программистами сайта, у них уйдет больше времени на разработку движка. Ты не мог бы сегодня мне прислать макеты дизайна?
— Ок. Там осталось совсем не много работы.

Проблема


Недолго думая и понимая, что работы осталось не совсем то и не много, достаю флешку с макетами, вставляю в юсб и вижу перед собой сообщение подобного характера: «Диск поврежден. Произвести восстановление раздела?». Я наивно согласился с предложением Виндовс. После проверки ужаснулся. Флешка была пуста, не было ни одой папки, ни одного файла, но размер занятого пространства оставался прежним ~3.5 Гб. Я как любой здравомыслящий пользователь сдержал панику и обратился с вопросами к знакомым, которые, по моему мнению, что-то в этом понимают, и к Яндексу. Из поисковика я узнал что утилита Виндовс ScanDisk посчитала все файлы «битыми» и перенесла в скрытую папку FOUND.000 и переименовала все файлы к такому образцу file0001.chk, file0002.chk. К сожалению, эта утилита не умеет восстанавливать созданные ей файлы. Ссылкой ниже я нашел решение проблемы, которое на первый взгляд было работающим и спасительным. Сторонний разработчик создал программу, которая восстанавливает такие файлы. Осталось сделать папку видимой и указать программе путь к ней. Включив отображение скрытых файлов и папок на флешке изменений не было. Не появились не файлы ни та злополучная папка FOUND.000. С этого момента я и начал действовать сам.

Поиск решения


Я воспользовался силой PHP, потому что это единственный из языков, которые я знаю не относящийся к языкам «песочница».
Первым делом я просканировал корень флешки на наличие каталогов и файлов. И вот оно чудо, папка FOUND.000 существует, но через проводник Виндовс не отображается, странно… Радостный и довольный я просканировал и этот каталог, что бы в дальнейшем просто скопировать из него все файлы .chk в другую папку и пробовать открывать программами. Скан каталога вывел мне массив из 10000 ключей. Открывать каждый файл было не благоразумно. Опять обратился к Яндексу и узнал что существуют сигнатуры файлов. Сигнатура файла – это константа, некий постоянный набор символов, позволяющий однозначно идентифицировать, какого типа данные содержатся в данном файле. Изъясняясь проще – это фрагмент кода в файле, по которому однозначно можно понять, что это за файл, какой программой он создан и другую информацию. К примеру, exe-файл всегда начинается с символов «MZ», Rar-архив имеет в своём коде «Rar!» и т.д. Соответственно, посмотрев файл и изучив его сигнатуру, можно понять какие данные он содержит. Изучив это, я и начал писать программу.

Реализация


Для начала я создал файл signature.ini, содержащий в себе данные о сигнатуре и относящемуся к ней расширению. Записи сигнатур стоит размещать в зависимости от синтаксиса самого файла, к примеру, <?xml, <?php, <?.. Если сделать наоборот выйдет что xml-файл будет с расширением php.

psd=8BPS
ai=application/vnd.adobe.illustrator
pdf=%PDF-1.
eps=%!PS-Adobe
fla=Saved by Adobe Flash
svg=<svg
jpg=0xFFD8FF
png=PNG
png=0x89504E47
png=0x89504E470D0A1A0A
jpg=0xFFD8FF
png=0x89504E470D0A1A0A
gif=GIF8
tif=0x49492A00
tif=0x4D4D002A
html=<html
html=<!DOCTYPE html
xml=<?xml
php=<?php

На тот момент это были те расширения, за которые я переживал больше всего, поэтому другие не привожу в пример. По данным ассоциациям расширений и сигнатур пошла дальнейшая разработка скрипта.

<?php

ini_set('memory_limit', '512M');

set_time_limit(0);

//директория поиска
$found = "J:/FOUND.000";

//директория обработанных файлов
$repair = "C:/repair";

//список успешно обработанных файлов
$done = array();

$farray = glob($found."/*.CHK");

echo "Скан директории...\n";
flush();

if (scandir($found)) {
  
  echo "Загрузка сигнатур...\n";
  flush();
  
  //загружаем сигнатуры
  $param = file('./signature.ini');
  
  echo "Восстановление...\n";
  flush();

  //сканируем директорию
  foreach ($farray as $file) {
  
    //нужна проверка файлу?
    if(array_search($file, $done) != false) continue;
      
    //получаем содержимое файла
    $f = file_get_contents($file);

    //пускаем цикл сигнаитур
    foreach ($param as $line) {
        
      //отделяем расширение от сигнатуры
      $patern = explode("=", $line);
      $pat = rtrim($patern[1]);

      //ищем необходимые сигнатуры в содержимом файла
      if(strpos($f, $pat) === false){
        continue;
      }
      
      //создание директории  
      if(!is_dir($repair."/".$patern[0])){
        @mkdir($repair."/".$patern[0]);  
      }
  
      $file_name = explode("/", substr($file, 0, -strlen(strrchr ($file, "."))));

      //формируем строку к будущему файлу
      $fput = $repair."/".$patern[0]."/".$file_name[count($file_name) - 1].".".$patern[0];
        
      //записываем полученный файл
      file_put_contents($fput, $f);
          
      //пишим в массив обработанный файл
      $done[] = $file;
          
      echo "Восстановлен файл: ".$fput."\n";
      flush();
      break;
        
    }
  
    //убираем все ненужное
    unset($f);
}
  
  //создаем директорию для непрошедших
  @mkdir($repair."/bad_files");  
    
  //копируем не прошедшие файлы
  foreach($farray as $file) {
      
    if(array_search($file, $done) == false){

      $file_name = explode("/", substr($file, 0, -strlen(strrchr ($file, "."))));
      copy($file, $repair."/bad_files/".$file_name[count($file_name) - 1]);
      
    }  
    
  }
    
  $all_files = count($farray);
  $all_done = count($done);
  $procent  = round($all_done / ($all_files / 100));
  echo "Из ".$all_files." восстановлено ".$all_done." (".$procent."%)";
  
}
?>


* This source code was highlighted with Source Code Highlighter.

Прошу прощения за корявый код.

Скрипт раскладывает файлы по папкам одноименным с расширением. Файлы, которые обработать не удалось, помещает в папку «bad_files».

Заключение


Функционал этого скрипта далеко не идеален, сказать, что работает без косяков нельзя, но он идеально справился с основной поставленной ему задачей – спасти psd-файлы. Оригинальные имена файлов естественно не получить, но это не проблема. После мне дали программ, которые восстанавливают файлы и этот скрипт ушел в категорию «Эксперименты».

3,5 Гб он обработал примерно за 20 минут. Из 10000 восстановлено 1160 файлов (12%), хотя в сигнатуры были занесены не все типы файлов хранящихся на флешке.

Примерно по такому же алгоритму работают и антивирусы. В полнее возможно реализовать антивирус для простого файлообменника на PHP.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.