ФорумПрограммированиеPHP для идиотов → Код восстановления после ошибки

Код восстановления после ошибки

  • malaba

    Сообщения: 165 Репутация: N Группа: Кто попало

    Spritz 19 августа 2010 г. 2:24

    Здравствуйте..)
    Хотелось бы узнать кто как решает такую проблему:

    мы хотим записать что то в файл
    окрываем его далее->



    try{
    if ( fseek($this->file_block,0,0) === -1) {
    hrow new Exception("Невозможно установить указатель на начало файла.");
    }

    if (!ftruncate($this->file_block,0)) {
    throw new Exception("Невозможно очистить файл.");
    }

    if (fwrite($this->file_block, $data) === false) {
    throw new Exception("Не удалось записать в файл." );
    }

    if (!fflush($this->file_block)) {
    throw new Exception("бла-бла.");
    }
    flock($this->file_block, LOCK_UN);
    fclose($this->file_block);
    }


    так вот елси ошибка произошла при записи, то есть файл уже пуст
    каким образом можно вернуть все обратно..???

    С Ооп тока начал разбираться и может если что не так делаю подскажете.
  • malaba

    Сообщения: 165 Репутация: N Группа: Кто попало

    Spritz 19 августа 2010 г. 2:33, спустя 9 минут 11 секунд

    единственная мысль которая пришла в голову )

    если в файл невозможно записать то создадим другой файл допустим error_writing.dat
    в него запишем все что хотели записать,

    а потом ………блин сделаем все вручную сцука

    короче хрен знает)
  • technobulka

    Сообщения: 4540 Репутация: N Группа: Джедаи

    Spritz 19 августа 2010 г. 2:38, спустя 4 минуты 15 секунд

    перед записью сделать копию… если запись удачная, удалить копию, иначе из копии переписать в оригинал и удалить копию… как вариант))
    Высокоуровневое абстрактное говно
  • malaba

    Сообщения: 165 Репутация: N Группа: Кто попало

    Spritz 19 августа 2010 г. 2:44, спустя 5 минут 59 секунд

    такая мысль мне кажеться удачной )))

    для сервака это ведб не очн напряжно будет)))
    Спустя 106 сек.
    и если сделать копию не удастья тоже ошибку выводим )))

    бля вот это кода получится ….
  • malaba

    Сообщения: 165 Репутация: N Группа: Кто попало

    Spritz 19 августа 2010 г. 2:51, спустя 7 минут 26 секунд

    спасибо за ответ…Stasovsky,
  • technobulka

    Сообщения: 4540 Репутация: N Группа: Джедаи

    Spritz 19 августа 2010 г. 2:58, спустя 6 минут 58 секунд

    днем гуру придут, норм совет дадут)) я так, наобум сказал))
    Высокоуровневое абстрактное говно
  • malaba

    Сообщения: 165 Репутация: N Группа: Кто попало

    Spritz 19 августа 2010 г. 3:06, спустя 8 минут 24 секунды

    а можно еще вопрос такой

    если мы напишем деструктор



    function __destruct(){
    if (is_resource($this->file_block)) {
    fclose($this->file_block);
    }

       if (is_resource($this->db_connect)) {
    mysql_close($this->db_connect);
    }
    }




    он закроет автоматически файл и соединение при возникновении ошбки или это надо прописывать в catch ???
  • technobulka

    Сообщения: 4540 Репутация: N Группа: Джедаи

    Spritz 19 августа 2010 г. 3:08, спустя 1 минуту 6 секунд

    если мы напишем

    у тебя раздвоение личности?))

    деструктор

    в этом я не шарю, только учусь))
    Высокоуровневое абстрактное говно
  • malaba

    Сообщения: 165 Репутация: N Группа: Кто попало

    Spritz 19 августа 2010 г. 3:15, спустя 7 минут 12 секунд

    ну пишу на php я уже 2 года)))

    а с ООП 2 дня тока разбираюсь

    Спустя 102 сек.
    и мне тока исключения важны и восстановления после них
  • malaba

    Сообщения: 165 Репутация: N Группа: Кто попало

    Spritz 19 августа 2010 г. 4:01, спустя 46 минут 5 секунд

    Уважаемые гуру не могли бы вы мне подсказать…правильным я путем пойду если буду использовать вот этот класс для работы с файлами:




    class MyFile{

    // любой вызываемый метод класса
    // прекращает работу если $error true
    public $error = false;


    // дескриптор заблокированного файла
    // массив строк файла
    // и путь к копии файла (создается при подготоовке файла к записи)
    // путь к файлу
    public $file_block;
    public $file_data = array();
    private $file_bak_path;
    public $file_path;




    // закрываем файл
    function __destruct(){
    if (is_resource($this->file_block)) {
    fclose($this->file_block);
    }
    }







    public function prepareFileWrite($filename){

    if (!$this->error) {

    try{

    $this->file_path = $filename;
    $this->file_bak_path = $filename.".bak";

    // пытаемся создать копию файла
    if (!copy($this->file_path, $this->file_bak_path)){
    throw new Exception("Невозможно создать копию файла.", 7);
    }


    // пытаемся открыть файл
    $this->file_block = fopen($this->file_path, "r+t");
    if (!is_resource($this->file_block)) {
    throw new Exception("Невозможно открыть указанный файл.", 8);
    }


    // пытаемся установить блокировку
    if (!flock($this->file_block, LOCK_EX)) {
    throw new Exception("Невозможно установить исключительную блокировку на файл.", 9);
    }


    // получаем размер файла
    if (($size = filesize($this->file_path)) === false) {
    throw new Exception("Невозможно получить размер файла.", 10);
    }


    // записываем в массив все строки файла
    $data = array();
    if ($size > 0) {
    if (!$get_string = fread($this->file_block, $size)) {
    throw new Exception("Невозможно прочитать файл.", 11);
    }
    $data = explode("\n", $get_string);
    }

    foreach($data as $value) {
    $this->file_data[] = rtrim($value);
    }

    }

    catch (Exception $e){
    $this->error = $e->getCode();


    if ($e->getCode() >= 8 and $e->getCode() <= 11) {
    unlink($this->file_bak_path);
    }
    }

    }
    }



    public function WriteInFile($data){

    if (!$this->error) {

    try{
    if ( fseek($this->file_block,0,0) === -1) {
    throw new Exception("Невозможно установить указатель на начало файла.", 12);
    }

    if (!ftruncate($this->file_block,0)) {
    throw new Exception("Невозможно очистить файл.", 13);
    }

    if (fwrite($this->file_block, $data) === false) {
    throw new Exception("Не удалось записать в файл.", 14);
    }

    if (!fflush($this->file_block)) {
    throw new Exception("Не удалось очистить буфер.", 15);
    }

    unlink($this->file_bak_path);
    }

    catch (Exception $e) {
    $this->error = $e->getCode();


    if ($e->getCode() >= 12 and $e->getCode() <= 15) {
    flock($this->file_block, LOCK_UN);
    copy($this->file_bak_path, $this->file_path);
    unlink($this->file_bak_path);

    }


    }

    }
    }



    }




    а теперь вызываем


    $test = new MyFile();
    $test->prepareFileWrite("test.txt" );
    $test->WriteInFile("записано");

    Вот вроде все работает…буду Вам очень благодарен если укажите на ошибки или может какие улучшения для этого класса
  • Nyaah

    Сообщения: 574 Репутация: N Группа: Джедаи

    Spritz 19 августа 2010 г. 7:55, спустя 3 часа 54 минуты 35 секунд

    а) слишком жирные названия у методов, если объект типа MyFile, то итак понятно, что метод write будет писать именно в файл, какой смысл юзать этот непонятный суффикс
    б) слишком длинные методы, логику по мелкм методам нужно разделить, чтобы можно было делать как-то так (это если возвращать каждый метод будет $this):
    $test->open('test.txt')->lock(LOCK_EX)->clear()->seekStart(0)->write('test')->flush()->unlock();
    Work, buy, consume, die
  • Givi

    Сообщения: 2284 Репутация: N Группа: Адекваты

    Spritz 19 августа 2010 г. 8:51, спустя 55 минут 37 секунд

    Nyaah, гы, вот у меня с этим тоже ппц проблемы. Ты можешь привести, плиз, маленький пример сказанного? Когда это удобнее юзать?
  • krasun

    Сообщения: 1370 Репутация: N Группа: Джедаи

    Spritz 19 августа 2010 г. 13:00, спустя 4 часа 8 минут 37 секунд

    malaba, если по ООП, то я бы делал так, но это набросок всего лишь, но в тему я не вчитывался, возможно кто ответил и способы восстановления могут быть разные, короче сейчас пишу:

    <?php
    interface Command
    {
    function Execute();
    function Unexecute();
    }

    class FileWriteException extends Exception {}

    class WriteCommand implements Command
    {
    /**
    * File pointer
    *
    * @var int
    */
    private $_f = null;
    /**
    * String to be written
    *
    * @var string
    */
    private $_data = '';
    /**
    * Position at the file
    *
    * @var int
    */
    private $_beforePosition = 0;

    public function __construct($f, $data)
    {
    $this->_f = $f;
    $this->_data = $data;
    }

    /**
    * Write`s data into file
    *
    * @return void
    */
    public function execute()
    {
    $this->_beforePosition = ftell($this->_f);
    if (fwrite($this->_f, $this->_data) == false) {
    throw new FileWriteException(); // but better do it at another class, for example FileWriter
    }
    }

    /**
    * Seek position to position that has been before
    *
    * @return void
    */
    public function unexecute()
    {
    fseek($this->_f, $this->_beforePosition);
    }
    }

    $lastCommand = null;
    try {
    // …
    $lastCommand = new WriteCommand($f, $data);
    $lastCommand->execute();
    } catch (FileWriteException $e) {
    $lastCommand->unexecute();
    }


    Мы используем паттерн Command, который выполняет атомарные операции. Данная команда WriteCommand, знает как вернуть состояние системы назад, если что пойдет не так.
    В $lastCommand->execute() я записываю данные в файл и запоминаю позицию перед записью, что бы при восстановление можно было бы вернуть позицию назад.



  • malaba

    Сообщения: 165 Репутация: N Группа: Кто попало

    Spritz 19 августа 2010 г. 18:23, спустя 5 часов 23 минуты 26 секунд

    krasun, это блин мощно ))
    как отразиться это на скорости скрипта ???
    просто файл который будет изменяться очень часто и нельзя потерять данные…


    кстати по поводу класса, который я выложил насчет копирования

    перед записью сделать копию… если запись удачная, удалить копию, иначе из копии переписать в оригинал и удалить копию… как вариант))



    вобщем значит копирую я файл, затем блокирую и т.д.
    а вот гарантий то нет что между копирование и блокировкой вклинится другой процесс и все нам не испортит

    вед копировать файл после исключительной блокировки уже нельзя…. поэтому такой вариант не катит))) наверно
    Спустя 160 сек.
    Nyaah, спасибо это хороший совет, я так и сделаю.
    Спустя 35 сек.
    методы покороче)
  • malaba

    Сообщения: 165 Репутация: N Группа: Кто попало

    Spritz 19 августа 2010 г. 18:43, спустя 20 минут 3 секунды

    krasun, спасибо за пример много чего нового узнал,…

    только мы файл очищаем ( он состоит из много строк)

    вот как надо чтоб работало:
    мы весь файл сначала помещаем в массив потом делаем какието
    изменеия в нужном месте (не во всей строке) с preg_replace
    и в очищенный файл вставляем этот массив ( implode("\n",$array))

Пожалуйста, авторизуйтесь, чтобы написать комментарий!