Приношу Вам свои извинения за то, что эта рассылка не выходила уже
больше года. Виной тому - не лень автора, а объективные и неприятные
непредвиденные обстоятельства, которые у меня появились уже после
того, как я начал выпускать эту рассылку. В результате у меня не было
ни времени, ни моральных сил. Сейчас обстоятельства
вновь изменились, выпуск рассылки продолжился и, я надеюсь, надолго.
Искренне желаю здоровья Вам и Вашим близким.
Для тех из Вас, для которых этот выпуск - первый, рекомендую прочитать
предыдущие выпуски рассылки в архиве рассылки на subscribe.ru - он
находится здесь.
Особенности вывода скриптом "бинарного" содержимого
В предыдущем выпуске мы рассматривали вывод CGI-скриптом результата
своей работы. Однако CGI-скрипты могут выводить не только "текстовое"
содержимое (в формате HTML или простого текста), но любое другое
содержимое, которое может быть распознано браузером - картинки,
скачиваемые файлы и т.п. (При этом поле ответа Content-Type должно
корректно отражать тип выводимого содержимого).
Однако здесь есть один нюанс - ввод и вывод файлов в языке perl может
производиться в двух режимах - текстовом и бинарном. А потоки стандартного
ввода, стандартного вывода и ошибок - это ведь тоже файлы!
По умолчанию файл "работает" в текстовом (ASCII) режиме.
В бинарном режиме данные передаются "как есть" - байт
в байт. В текстовом режиме данные передаются с учетом того, что это
текст.
Казалось бы, какая разница, что выводить - текст или что-то еще?
Ведь, в конце концов, текст - это ведь тоже последовательность байт?
Зачем для него нужен какой-то специальный режим?
Для начала давайте разберемся, чем текстовый режим файла отличается
от бинарного и зачем это вообще нужно.
Практически во всех операционных системах есть понятие простого
(или "плоского") текста. Это текст, который может в общем случае
содержать только текстовые символы и переводы строк (ну, и символ
конца текста). Это тот самый формат, в котором система хранит,
в частности, различные текстовые конфигурационные файлы. В таком
же виде браузеры принимают содержимое в текстовых форматах:
HTML, text, css и т.п.
В принципе, одного режима передачи, а именно бинарного, было бы
вполне достаточно, если бы ни одна неприятная "историческая" особенность:
форматы простого текста
различаются в различных операционных системах! В частности,
в системах DOS и Windows
перевод строки представлен двумя символами - "возврат каретки" (код 13)
и собственно "перевод строки" (код 10). А в UNIX и UNIX-подобных системах
- одним символом - "перевод строки".
Соответственно, если перенести "байт в байт" текст с UNIX на Windows
машину или наоборот, текст нормально читаться не будет ("Блокнот", например, покажет
весь UNIX-воский текст в одну строку).
Еще хуже обстоит дело с теми файлами, которые читаются не только
людьми, но и программами - если Вы, например, "закачаете" на сервер
своего хостинга perl-скрипт по FTP в Binary-режиме, то интерпретатор
perl не сможет с ним работать (на этом, кстати, "накалываются" многие
начинающие CGI-программисты - я в свое время тоже испытал полное недоумение
:-) ).
В принципе (теоретически, так сказать) можно было бы использовать для записи-чтения текстов
и бинарный режим, поскольку он универсальный и с его помощью можно
прочитать и записать без искажений
что угодно. Но поскольку порты интерпретатора perl существуют сейчас
практически для всех используемых платформ, то программа (скрипт) может работать
под разными системами. Веб-сервера работают на разных платформах - в
основном это системы семейства UNIX, но есть и NT, и NetWare, и другие.
Как же скрипт может определить, под какой
системой он работает, и какие переводы строк в данном случае ему
формировать?
Поэтому придумали специальный режим для передачи текстов. При передаче файлов
в текстовом (ASCII) режиме переводы строк заменяются таким образом,
чтобы файл в данной системе читался корректно. При этом программам,
читающим или записывающим текст (неважно, под какой системой они
работают) в качестве перевода строки нужно
использовать его UNIX-вариант (код 10, escape-символ '\n').
В качестве примера рассмотрим очень простую программу:
#!/usr/bin/perl
open F,">proba.txt";
print F "\n\n";
close F;
Эта программа создает файл "proba.txt" в той же директории, где она
сама находится, и записывает в него два перевода строки.
При этом, если она запущена на UNIX-машине, она создаст двухбайтный
файл - с двумя кодами "перевод строки" (шестнадцатеричное 0A 0A). Если же ее запустить на Windows
-машине, она создаст четырехбайтный файл (шестнадцатеричное 0D 0A 0D 0A).
Т.е. в каждой системе получится корректный текстовый файл в стандарте данной системы.
При чтении - наоборот: переводы строк данной системы заменяются на '\n'.
Вернемся теперь к нашим баранам, вернее, к выводу скриптом бинарного
содержимого.
Для передачи такого содержимого нам нужно обеспечить возможность
передачи информации через стандартный вывод "байт в байт". Делается
это в perl с помощью функции
binmode FILE;
где FILE - это файловый указатель (дескриптор).
В данном случае нам надо перевести в бинарный режим "файл" STDOUT.
Также в бинарный режим должны быть переведены все файлы, из которых
скрипт читает (или в которые записывает) бинарные данные (картинки и т.п.)
Поскольку HTTP-поля заголовка ответа - это текстовое содержимое,
то переводить файл в бинарный режим нужно непосредственно перед передачей
бинарного содержимого, после выдачи HTTP-заголовка ответа.
Этот пример читает из файла "picture.gif" картинку и передает ее
броузеру:
#!/usr/bin/perl
open PIC,"<picture.gif";
binmode PIC;
sysread PIC, $picture, -s PIC;
close PIC;
print "Content-Type: image/gif\n\n";
binmode STDOUT;
print $picture;
Вот вроде бы и все, что касается вывода результатов работы CGI-скрипта.
В следующем выпуске мы рассмотрим "обратную сторону" ввода-вывода,
как скрипты могут получать информацию -
параметры, условия запуска, информацию о клиенте и.т.д.