Отправляет email-рассылки с помощью сервиса Sendsay

Все о PHP и даже больше

  Все выпуски  

Все о PHP и даже больше


Информационный Канал Subscribe.Ru


Все о PHP и даже больше...

# 5
2/2003

23 января 2003г.

Проект сайта "GreatWeb Design" GreatWeb.ru


    В этом выпуске:

  • Наш проект.
  • Параллельное выполнение скриптов...
  • Отправка файлов аттачем.
  •   Ссылки Вебмастеру:

  • Лучший хостинг
  • Раскрутка
  • Советы Web-мастеру
  • Книги по программировании
  • WEB-браузеры
  • Фоны
  • Скрипты
  • HARDWARE
  • Партнерская программа

  • Здравствуйте!

    Описание нашего проекта:

     

    Идет время, наш сайт www.GreatWeb.ru становится все лучше и лучше. Добавляются новый статьи, скрипты.
    Сейчас, происходит настройка Форума. Уже в эти выходные Вы сможете там побывать...
    А так же, кипит работа над выходом нашего, нового Интернет-журнала!

    Все свои пожелания, замечания, советы присылайте на E-mail


    Параллельное выполнение скриптов может нарушить целостность информации в файлах


    Здесь рассматривается вопрос, что бывает, если запустить некий скрипт почти одновременно (что происходит, например, при большой загруженности сервера) несколько раз, т.е. запустить несколько копий одного и того же скрипта. И к чему это может привести.

    Ошибка программы простого текстового счетчика

    Давайте сделаем такую программу. Итак, у нас есть какая-то страница, на которой хочется повесить счетчик. Обсудим алгоритм:

    •  считать число из файла
    •  записать увеличенное число обратно
    •  вывести его на экран
    Согласитесь, программа простая, но может привести к ошибке, что и показано ниже.
    ---------------------------------------------------------------------------------------------------

    <?

    // верхняя часть страницы

    // код счетчика:

    $counter=file("counter.txt"); // прочитали файл в массив $counter

    $f=fopen("counter.txt","w+"); // открыли файл на запись

    fputs($f,$counter[0]+1); // записали "число + 1"

    fclose($f); // закрыли файл

    echo $counter[0]+1; // вывели число на экран

    // нижняя часть страницы

    ?>

    ---------------------------------------------------------------------------------------------------


    Если вызывать данную программу очень часто, значение счетчика иногда будет обнуляться. Это произойдет из-за того, что в некоторый момент программа прочитает из файла пустое значение, к которому потом прибавляется единица ("пусто" + число 1 = число 1). Собственно, это и есть сброс счетчика.


    Рассмотрим подробно, когда это произойдет. Представьте, что в один момент времени стартовали 2 копии данного скрипта. Одновременно ничего нигде не происходит, в т.ч. и запуск скриптов, но время между запуском может быть очень маленькое. Процессор выполняет скрипты с разной скоростью, т.е. вы не должны удивляться тому, в каком порядке далее будут рассматриваться команды. Итак, ход программы (на примере "скрипта N1" и "скрипта N2"):

    скрипт команда комментарий (что сделает данная команда)
    1 запуск первого скрипта --
    1 $counter=file("counter.txt"); в переменной (массиве $counter) теперь храниться текущее число счетчика.Допустим, там было 1234, тогда это число будет в переменной $counter[0].
    2 запуск второго скрипта --
    1 $f=fopen("counter.txt","w+");
  • открывает файл
  • обнуляет его
  • если файл не был создан, создает его (если позволят права). Но файл создан нами заранее, этот вариант исключен.
  • 2 $counter=file("counter.txt"); читает содержимое пустого файла и записывает в массив $counter пустой массив.Переменная $counter[0] не существует.
    1 fputs($f,$counter[0]+1); пишет в файл число 1234 (т.к. в $counter[0] лежит число 1234)
    2 $f=fopen("counter.txt","w+"); см. комментарий выше
    1 fclose($f); и конец работы --
    2 fputs($f,$counter[0]+1); записывает в файл число 1, т.к результат сложения несуществующей переменнойи числа 1 равен числу 1
    2 fclose($f); и конец работы --

    Как видите, если 2 параллельно работающих скрипта, выполнять именно в такой последовательности, то файл будет обнулен. Если вы попробуете этого добиться, выполняя частую перезагрузку страницы в браузере, то у вас скорее всего ничего не выйдет. Чтобы убедиться, что файл будет таки обнулен, воспользуйтесь утилитой ab (которая умеет генерировать, в течение длительного времени большое число, параллельных запросов к скиптам), либо впишите после каждой команды "sleep(1);" - команду остановки программы на 1 секунду, и понажимайте "Обновить" в браузере. Во втором случае вы это сразу и увидите.

    Чтобы решить проблему, нужно исключить опасный момент. Другими словами надо заблокировать доступ к файлу счетчика, чтобы все другие параллельно запущенные скрипты, приостановили свою работу. Делается это с помощью flock, который блокирует доступ из других PHP-скриптов (но не из других процессов ОС). Другие скрипты при попытке открыть файл остановятся и будут ждать снятия блокировки.
    ---------------------------------------------------------------------------------------------------
    <?

    // верхняя часть страницы

    // код счетчика:

    $f2=fopen("counter.txt","r"); // чтобы файл заблокировать, его надо открыть

    // открыли файл на чтение

    flock($f2,2); // заблокировали файл

    $counter=file("counter.txt"); // прочитали файл в массив $counter

    $f=fopen("counter.txt","w+"); // открыли файл на запись

    fputs($f,$counter[0]+1); // записали "число + 1"

    fclose($f); // закрыли файл

    echo $counter[0]+1; // вывели число на экран

    flock($f2,3); // сняли блокировку (при закрытии снимается автоматически)

    fclose($f2); // и закрыли файл (при выходе закрывается автоматически)

    // нижняя часть страницы

    ?>
    ---------------------------------------------------------------------------------------------------

    Программу с блокировкой можно было бы написать и в более красим (коротком) виде, но и такой вариант сойдет. Цифры "2" и "3" в функции flock обозначают следующее:

    flock (дексриптор файла, режим)

    режим:

    •  1 - другие процессы могут отрыть только в режиме чтения
    •  2 - другие процессы ничего не могут
    •  3 - снять блокировку
    Большое спасибо сайту php.SPB.ru.


    Отправка файлов аттачем


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

    Итак, исходный код класса с комментариями:

    ---------------------------------------------------------------------------------------------------

    <?
    class multi_mail
    {
    var $from; // Отправитель
    var $to; // Получатель
    var $headers; // Заголовок сообщения
    var $body; // Тело сообщения


    function multi_mail() // Конструктор класса
    // Проводим инициализацию переменных
    {
    $this -> from = "";
    $this -> to = "";
    $this -> body = "";
    $this -> headers = Array();
    $this -> subject = "";
    }

    // Присоединяем файл
    function attach_file($file_name = "" , // Имя файла
    $file_content, // Содержимое файла
    $encoding_type = "application/octet-stream" //Тип кодировки данных.
    )
    {
    $this -> headers[] = array( // Записываем заголовочную информацию.
    "name" => $file_name,
    "content" => $file_content,
    "encode" => $encoding_type
    );
    }

    function build_letter($header) // Строим Часть письма, будь то аттаченный файл или простой текст
    {
    $letter = $header["content"];
    if ($header["encode"] != "text/plain"):
    $letter = chunk_split(base64_encode($letter));
    $encoding = "base64";
    else:
    $encoding = $header["encode"];
    endif;
    return "Content-Type: ".$header["encode"].
    ($header["name"]? ".; name = "".$header["name"].""" : "")
    ."rnContent-Transfer-Encoding:
    $encodingrnrn$lettern";
    }

    function set_multipart_mail() // Собираем письмо из разрозненных частей
    {
    $boundary = 'b'.md5(uniqid(time())); // Создаем уникальное число, служащее индетификатором для чати письма

    $multipart = "Content-Type: multipart/mixed;
    boundary =$boundarynnThis is a MIME encoded letterrnrn--$boundary";
    for($step = sizeof($this->headers)-1; $step >=0; $step--)
    {
    $multipart .= "rn".$this->build_letter($this->headers[$step])."--$boundary";
    // Вставляем содержимое межу метками
    }
    return $multipart .= "--rn";
    }

    function get_full_message()
    // Вставляем тело письма (текстовую начинку) и все файлы
    // на выходе получаем полное писмо (одна большая строка :)))
    {
    $mime = "";
    if (!empty($this->from)):
    $mime .= "From: ".$this->from." rn";
    endif;
    if (!empty($this->body)):
    $this -> attach_file("",$this->body,"text/plain");
    $mime .= "MIME-Version: 1.0rn".$this->set_multipart_mail();
    endif;

    return $mime;
    }


    function send_mail() // Собственно посыл письма
    {
    $mime = $this -> get_full_message(false);
    mail($this->to,$this->subject,"",$mime);
    }
    }
    ?>
    ---------------------------------------------------------------------------------------------------

    Уложив этот класс в отдельный файл, Вы можете использовать его где угодно.


    Большое спасибо сайту www.RIP.net.ua


    © 2002-2003 Copyright by GreatWeb Design
    Копирование материалов рассылки возможно только в случае явного указания на сайт "GreatWeb.RU" как на источник информации.


    http://subscribe.ru/
    E-mail: ask@subscribe.ru
    Отписаться
    Убрать рекламу

    В избранное