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

Программирование скриптов на Perl'e (Выпуск №8)


Служба Рассылок Subscribe.Ru проекта Citycat.Ru

Программирование скриптов на Perl'e (выпуск 8).


Здравствуйте дорогие мои подписчики.


Сегодня в выпуске:




Несколько слов перед началом


Я приношу свои глубочайшие извинения всем подписчикам, но по независящим от меня причинам возник столь длительный перерыв в выпуске рассылки.

Я убрал из рассылки два раздела и хочу услышать Ваше мнение по этому поводу, уважаемые подписчики.

Ну а теперь, наконец-то, мы продолжим изучение Perl'а.   Сегодняшние темы:

  • Perl для начинающих - Операторы для работы с файлами
  • CGI-программирование - Счетчик посещений




    Perl для начинающих - Операторы для работы с файлами


    Perl содержит обширный список операторов для работы с файлами.   Имеется не менее 27 операторов, возвращающих специфическую информацию о файле, даже не открывая его.   Многие операторы языка Perl ориентированы на системы UNIX, но следующие операторы работают на любых системах:
        -d проверяет наличие каталога
        -е определяет наличие файла
        -s определяет размер файла
        -w определяет, можно ли писать в данный файл
    
    Следующий текст иллюстрирует использование этих операторов:
            if (-e "perl.exe")
              {  print "Размер файла: ". -s "perl.exe";
              }
            else
              {  print "Не могу найти perl.exe\n";
              }
            (-w "File") || die "Не могу записать в File.";
    
    Существуют и другие подобные операторы:
        -r  - определяет, можно ли читать данный файл
        -x  - определяет, можно ли исполнять данный файл
        -z  - проверяет, является ли файл пустым
        -s  - проверяет, является ли файл не пустым
        -T  - проверяет, является ли файл текстовым
        -B  - проверяет, является ли файл двоичным
        -М  - "возраст" файла в днях на момент старта скрипта
    
    Но это операторы так сказать "проверочные", которые не выполняют явных действий над файлом.   Далее дается описание операторов непосредственной работы с файлами.

    binmode файл
    Открыть файл для двоичного (binary) режима доступа.   В обычном режиме при вводе символы CR LF транслируются в LF, а при выводе LF транслируется в CR LF.

    close файл
    Закрыть открытый файл или поток.   Можно не использовать, если один и тот же файл открывается повторно т. к. он будет автоматически закрываться новым вызовом open().

    eof файл
    eof()
    eof
    Возвращает 1, если выполняется чтение после конца или чтение из не открытого файла.   Аргументом должно быть выражение, возвращающее существующий указатель файла.   Данную функцию нельзя использовать для чтения файлов открытых как терминалы.   Если аргумент не указан, то используется последний читаемый файл.   Использование в форме eof() целесообразно применять в циклах while(<>) для определения конца только последнего файла из списка.   Применяйте eof(ARGV) или eof для определения конца каждого файла из списка.

    fileno файл
    Возвращает описатель файла для данного указателя файла.

    flock файл, операция
    Системный вызов flock().   О нем упоминалось в одной из прошлых выпусков рассылок (см. выпуск №6).

    getc файл
    getc

    Читает и возвращает символ из указанного файла.   Если файл не указан, то читается STDIN.   После конца файла возвращает пустую строку.

    open файл, выражение
    open файл

    Открыть файл с указанным именем.   Аргумент "файл" - это фактически указатель на блок описания файла.   Если имя (выражение) файла отсутствует, то имя считается таким же, как и указатель файла.   Если перед именем стоит символ '<' то файл открывается только на чтение (значение по умолчанию).   Если '>' - на запись.   Если '>>' - на добавление записей.   '+>' или '+<' - файл открыт на чтение и запись одновременно.
    Если имя файла начинается с символа '|', то имя считается системной командой, на вход которой выводятся данные (поток).   Имя '-' стандартный вход (STDIN), '>-' - стандартный вывод (STDOUT).   Функция возвращает true при успехе и false при неудаче.   Если имя (выражение) начинается с символов '>&' то остаток имени считается именем указателя файла, который открывается повторно.   Символ '&' может стоять после '<', '>>', '+>', '+>>' и '+<'.   Режим повторного открытия должен соответствовать первому.
    Выражение вида '<&="N"' где N число, эквивалентно системному вызову fdopen().   Если имя '|-' или '-|' то происходит "расщепление" (fork) процесса на потомка и родителя.   При этом возвращается номер процесса потомка (PID) внутри родительского процесса и 0 внутри потомка.   При этом запись/чтение в файл родительским процессом воспринимается как чтение/запись потомком.   Для потомка это стандартный ввод/вывод.   Родительский процесс ждет завершения потомка после закрытия потока и получает код завершения в переменной $?.   Имя файла не должно содержать пробелов как в начале так и в конце.

    print файл список
    print список
    print

    Выводит строку или список строк в файл.   Возвращает true при успехе.   Аргумент файл может быть скалярной переменной, содержащей имя указателя файла, если он отсутствует то осуществляется вывод в стандартный выходной поток STDOUT (если не было вызова select()).   Если список отсутствует, то выводится значение переменной $_.   Для вывода по умолчанию в другой файл необходимо использовать функцию select().   Так как print работает в списковом контексте, то все элементы списка так же вычисляются в списковом контексте т. е. функции будут возвращать списковые значения.   Аргументы можно заключать в круглые скобки.   Если указатель файла элемент массива, то элемент нужно заключить в фигурные скобки для вычисления блока.

    printf файл список
    printf список

    Аналогичен вызову "print файл sprintf(список)". Первый элемент списка должен быть форматом printf() как и в С.

    read файл, скаляр, длина, смещение
    read файл, скаляр, длина

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

    rename старое_имя, новое_имя_файла
    Переименовать файл.   Возвращает 1 в случае успеха иначе 0.

    seek файл, позиция, отсчет
    Установить указатель на произвольную позицию в файле.   Если отсчет равен 0 - позиционировать от начала файла, если 1 - от текущего положения, 2 - от конца файла.   Возвращает 1 при успехе и 0 неудаче.

    select файл
    select

    Возвращает текущий указатель файла по умолчанию или делает текущим указанный.   Таким образом, если в функциях print или write не указан файл вывода, то это осуществляется в файл указанный select.   Переменные, связанные с выводом так же действуют на вывод в этот файл.

    stat файл
    stat выражение
    Возвращает 13 элементный массив параметров указанного файла или пустой список при ошибке.   Применяется обычно следующим образом:
    ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks)=stat($filename);
    где
    $dev - имя устройства
    $ino - номер i-узла
    $mode - права доступа
    $nlink - количество связей
    $uid - идентификатор владельца
    $gid - идентификатор группы
    $rdev - тип устройства
    $size - размер файла в байтах
    $atime - дата последнего обращения
    $mtime - дата последней модификации
    $ctime - дата последнего изменения статуса
    $blksize - размер блока на диске
    $blocks - количество блоков в файле
    Если указан аргумент '_' то возвращается результата предыдущего вызова stat().

    sysread файл, скаляр, длина, смещение
    sysread файл, скаляр, длина

    Прочитать из файла указанное число байт в скаляр с помощью системного вызова read().   Смещение обозначает позицию в скаляре, после которой будут вставлены прочитанные байты.

    syswrite файл, скаляр, длина, смещение
    syswrite файл, скаляр, длина

    Записать в файл указанное число байт скаляра с помощью системного вызова write().   Смещение указывает позицию в скаляре, откуда начинается запись.

    tell файл
    tell

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

    truncate файл, длина
    truncate выражение, длина

    Усекает длину указанного файла.

    unlink список
    Удаляет файлы, указанные в списке.   Возвращает количество удаленных файлов.   Только супервизор может удалять директории с файлами, если Perl запущен с ключом U.

    utime список
    Изменяет дату обращения и модификации файлов из списка.   Первые два элемента списка должны указывать новое значение даты обращения и модификации.   Возвращает количество измененных файлов.

    write файл
    write выражение
    write

    Выводит в файл форматированные данные по оператору format.   По умолчанию имя формата совпадает с именем указателя файла.   Имя файла по умолчанию можно изменить функцией select(), а имя формата при этом надо присвоить переменной $~.   Заголовок листа пишется автоматически.   Если на листе не хватает места для вывода, то выводится "перевод формата" и специальная форма заголовка листа затем сами записи.   По умолчанию имя формата заголовка листа состоит из имени указателя файла и добавленной строки "_TOP".   Динамически это можно делать, присваивая формат переменной $^.   Количество оставшихся строк листа содержится в переменной $- и если присвоить ей 0, то произойдет смена листа.  


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

    format
    Декларативная функция Perl.   Определяет формат вывода для оператора write.

    formline формат, список
    Внутренняя функция, используемая в format. Форматирует вывод параметров из списка.   Результат помещается в переменную $^A.   Функция write просто выводит значение этой переменной, но ее так же можно читать, а затем обнулять.
    Обычно format выполняет один вызов formline для одной строки формы, но formline не разделяет строки формата.
    Это значит что символы '~' и '~~' рассматривают весь формат как одну строку, поэтому необходимо использовать многострочные формы для описания одной записи формата.

    С помощью оператора format Вы описываете заголовки, размеры полей, указываете положение данных на листе в удобной текстовой форме.   Затем выполняете команду write(файл) которая выводит отформатированные данные в указанный файл.

    Оператор format имеет следующий синтаксис:

    format имя =
    FORMLIST
     .
    
    Обратите внимание на то что описание формата идет после строки format и заканчивается символом '.' в начале строки.

    Здесь 'имя' - это имя формата, такое же, как и имя указателя выходного файла.   Если 'имя' отсутствует, то значение по умолчанию - STDOUT.

    FORMLIST - это строки формата.   Они бывают трех типов:
        1. Комментарий.   Строка начинается символом '#'.
        2. Описатель полей данных (picture).
        3. Строка аргументов используемых описателем.

    Описатель - это строка, которая выводится в виде "как есть" за исключением специально обозначенных форматов полей данных.   Каждое поле начинается либо символом '@' либо '^'.

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

    Размер и вид поля в описателе обозначается следующими символами:
    ">>>>"     - выровнять значение по правому краю.
    "<<<<"     - по левому.
    "||||"     - по центру.
    "####.###" - формат числа с точкой.
    "@*"       - многострочная строка.  Данные выводятся в колонку.
                 Размер поля равен количеству указанных символов.
    
    Символ '^' в начале поля имеет специальное значение.  Так:
    "^####"    - пусто если переменная не определена.
    "^<<<<<"   - Выводится сколько возможно символов строки, а
                 значение переменной меняется на остаток, вывод
                 которого можно продолжить на следующих строках,
                 которые могут иметь свои поля.
    
    И это все на сегодня об операторах работы с файлами.




    CGI-программирование - Счетчик посещений


    Честно говоря, я очень разочарован столь низкой Вашей активностью участия в конкурсе.

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

    Итак - счетчики.   Прежде всего, я напомню основные требования к скрипту счетчика:

    1. Счетчик должен работать с любым количеством клиентов - это подразумевает наличие файла записей, в котором будет содержаться (в простейшем варианте) имя пользователя и его персональный счет.   И таких записей может быть произвольное количество.
    2. Скрипт должен вызываться через тэг <img scr="..."> - это означает, что надо формировать полное изображение из отдельных картинок с изображением цифр, а не выводить в поток браузера цепочку кодов <img scr="..."> <img scr="..."> <img scr="...">, с изображением каждой цифры в отдельности.
    3. Скрипт должен быть прост в установке - это, я думаю понятно.
    4. Скрипт должен быть по возможности коротким.

    Сегодня я представляю Вашему вниманию простейший вариант скрипта счетчика посещений.

    Вызов скрипта осуществляется следующим образом:
    <img scr="http://www.domain.ru/cgi-bin/counter.cgi?user=Name&digit=5">

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

    Формат файла записей для скрипта следующий:
        Vitalij||13995
        Sasha||237
        Booka||6
        Igos||3
    
    После прихода запроса, скрипт разбирает его, используя слегка усеченных версию подпрограммы разбора входного запроса, так как метод запроса - GET - известен заранее и заполняет хэш %FORM:
    sub parseform
    {  local($name, $value, $pair, $buffer, @pairs);
    
       @pairs=split(/&/, $ENV{'QUERY_STRING'});
       foreach $pair (@pairs)
         {  ($name, $value)=split(/=/, $pair);
            $value=~tr/+/ /;
            $value=~s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
            $FORM{$name}=$value;
         }
       return(1);
    }
    
    После разбора запроса происходит чтение файла с информацией о пользователях и поиск нужного.

    Если пользователь найден, то значение счетчика для него увеличивается на 1 и сохраняется в файле.   Если запрошенный пользователь не существует, то производится выход из программы.

    open COUNTF, "<counter.dat";
    @countrec=<COUNTF>          # прочитали файл с записями
    close COUNTF;
    $counter=0;
    for ($i=0; $i<@countrec; $i++)
      {  if ($countrec[$i]=~/$FORM{user}/)       # ищем нужного пользователя
           {  @records=split(/\|\|/, $countrec[$i]);
              $records[1]++;                     # увеличиваем счетчик на 1
              $counter=$records[1];
              $countrec[$i]=$records[0]."||".$records[1]."\n"; # обновили запись
           }
      }
    exit if ($counter==0);# если счетчик=0 (пользователь не существует), то выход
    open COUNTF, ">counter.dat";   # обновляем файл с записями
    flock COUNTF, 2;
    print COUNTF @countrec;
    flock COUNTF, 8;
    close COUNTF;
    
    Далее происходит вычисление размеров изображения в соответствии с запросом пользователя.   Сразу отмечу, что в качестве исходных используются изображения цифр формата 16х24 пикселов.

    После этого происходит формирование заголовка изображения в соответствии с вычисленными размерами.

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

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

    @count=split (//, $counter);  # разбиваем число счетчика на отдельные цифры
            # если число цифр, указанное в запросе превышает число цифр
            # в числе счетчика, то дополняем впереди нулями
    if (($digits_in_image)>scalar(@count))
      {  for ($i=0; $i<($digits_in_image-scalar(@count)); $i++)
           {  unshift @count, 0;
           }
      }
    # формируем изображение
    for ($i=0; $i<24; $i++)
      {  for ($j=0; $j<8; $j++)
           {  push @ret, $logo[$i*8+$j];
           }
         for ($k=0; $k<@count; $k++)
           {  for ($j=0; $j<8; $j++)
                {  push @ret, $dig[$count[$k]][$i*8+$j];
                }
           }
      }
    
    И теперь, после того, как изображение сформировано, можно отправить его в браузер пользователя:
    print "Content-Type: image/bmp\n\n";  # указали тип возвращаемой информации
    foreach $byte (@ret)
      {  print chr($byte);
      }
    
    В некоторых случаях, если не увидите в браузере изображение, то попробуйте в качестве типа указать: image/x-bitmap.

    При желании Вы можете сохранить полученное изображение в файл:

    open BMPF, ">counter.bmp";
    foreach $byte (@ret)
      {  print BMPF chr($byte);
      }
    close BMPF;
    
    В файле скрипта описаны массивы @header, @dig и @logo представляющие, соответственно, заголовок для изображения, массив из кодов изображений десяти цифр и изображение небольшого логотипчика, выводимого, перед цифрами в счетчике.

    А теперь полный текст скрипта counter.cgi:

    #!/usr/bin/perl
    
    @header=(
    0x42,0x4D,0xF6,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x76,0x00,0x00,0x00,0x28,0x00,
    0x00,0x00,0x10,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x01,0x00,0x04,0x00,0x00,0x00,
    0x00,0x00,0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x04,0xFC,0xFC,0x00,0xFC,0x84,0x84,0x00,0x00,0x00,
    0x00,0x83,0x00,0x00,0x00,0x83,0x00,0x00,0x00,0x83,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x83,0x00,0x00,0x00,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x82,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x82,0x00,0x00,0x00,0x83,0x00,0x00,
    0x00,0x83,0x00,0x00,0x00,0x00);
    
    @dig=(
    [0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x10,0x00,0x00,0x01,0x11,0x11,
    0x11,0x11,0x00,0x00,0x00,0x00,0x11,0x11,0x11,0x10,0x00,0x01,0x10,0x00,0x01,0x11,
    0x11,0x10,0x00,0x11,0x11,0x00,0x01,0x11,0x11,0x00,0x01,0x11,0x11,0x10,0x00,0x11,
    0x11,0x00,0x01,0x11,0x11,0x10,0x00,0x11,0x11,0x00,0x01,0x11,0x11,0x10,0x00,0x11,
    0x11,0x00,0x01,0x11,0x11,0x10,0x00,0x11,0x11,0x00,0x01,0x11,0x11,0x10,0x00,0x11,
    0x11,0x00,0x01,0x11,0x11,0x10,0x00,0x11,0x11,0x00,0x01,0x11,0x11,0x10,0x00,0x11,
    0x11,0x10,0x00,0x11,0x11,0x00,0x01,0x11,0x11,0x10,0x00,0x01,0x10,0x00,0x01,0x11,
    0x11,0x11,0x00,0x00,0x00,0x00,0x11,0x11,0x11,0x11,0x10,0x00,0x00,0x01,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11],
    
    [0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x00,0x00,0x00,0x00,0x01,0x11,
    0x11,0x11,0x00,0x00,0x00,0x00,0x01,0x11,0x11,0x11,0x11,0x10,0x00,0x11,0x11,0x11,
    0x11,0x11,0x11,0x10,0x00,0x11,0x11,0x11,0x11,0x11,0x11,0x10,0x00,0x11,0x11,0x11,
    0x11,0x11,0x11,0x10,0x00,0x11,0x11,0x11,0x11,0x11,0x11,0x10,0x00,0x11,0x11,0x11,
    0x11,0x11,0x11,0x10,0x00,0x11,0x11,0x11,0x11,0x11,0x11,0x10,0x00,0x11,0x11,0x11,
    0x11,0x11,0x11,0x10,0x00,0x11,0x11,0x11,0x11,0x11,0x11,0x10,0x00,0x11,0x11,0x11,
    0x11,0x11,0x11,0x10,0x00,0x11,0x11,0x11,0x11,0x11,0x00,0x00,0x00,0x11,0x11,0x11,
    0x11,0x11,0x00,0x00,0x00,0x11,0x11,0x11,0x11,0x11,0x11,0x10,0x00,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11],
    
    [0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x00,0x00,0x00,0x00,0x00,0x01,0x11,
    0x11,0x00,0x00,0x00,0x00,0x00,0x01,0x11,0x11,0x10,0x00,0x00,0x11,0x11,0x00,0x11,
    0x11,0x11,0x00,0x00,0x01,0x11,0x00,0x11,0x11,0x11,0x10,0x00,0x00,0x01,0x11,0x11,
    0x11,0x11,0x11,0x10,0x00,0x00,0x11,0x11,0x11,0x11,0x11,0x11,0x00,0x00,0x01,0x11,
    0x11,0x11,0x11,0x11,0x10,0x00,0x01,0x11,0x11,0x11,0x11,0x11,0x11,0x00,0x00,0x11,
    0x11,0x00,0x11,0x11,0x11,0x10,0x00,0x11,0x11,0x00,0x11,0x11,0x11,0x10,0x00,0x11,
    0x11,0x00,0x01,0x11,0x11,0x10,0x00,0x11,0x11,0x10,0x00,0x11,0x11,0x00,0x01,0x11,
    0x11,0x11,0x00,0x00,0x00,0x00,0x11,0x11,0x11,0x11,0x10,0x00,0x00,0x01,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11],
    
    [0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x10,0x00,0x00,0x01,0x11,0x11,
    0x11,0x10,0x00,0x00,0x00,0x00,0x01,0x11,0x11,0x10,0x00,0x01,0x11,0x00,0x01,0x11,
    0x11,0x00,0x00,0x11,0x11,0x10,0x00,0x11,0x11,0x00,0x00,0x11,0x11,0x10,0x00,0x11,
    0x11,0x10,0x01,0x11,0x11,0x10,0x00,0x11,0x11,0x11,0x11,0x11,0x11,0x00,0x00,0x11,
    0x11,0x11,0x11,0x10,0x00,0x00,0x01,0x11,0x11,0x11,0x11,0x10,0x00,0x00,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x00,0x01,0x11,0x11,0x10,0x01,0x11,0x11,0x10,0x00,0x11,
    0x11,0x10,0x01,0x11,0x11,0x10,0x00,0x11,0x11,0x10,0x00,0x11,0x11,0x00,0x00,0x11,
    0x11,0x11,0x00,0x00,0x00,0x00,0x01,0x11,0x11,0x11,0x11,0x00,0x00,0x01,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11],
    
    [0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x10,0x00,0x11,0x11,
    0x11,0x11,0x11,0x11,0x10,0x00,0x11,0x11,0x11,0x11,0x11,0x11,0x10,0x00,0x11,0x11,
    0x11,0x11,0x11,0x11,0x10,0x00,0x11,0x11,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
    0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x11,0x00,0x11,0x11,0x10,0x00,0x11,0x11,
    0x11,0x00,0x01,0x11,0x10,0x00,0x11,0x11,0x11,0x10,0x00,0x11,0x10,0x00,0x11,0x11,
    0x11,0x11,0x00,0x01,0x10,0x00,0x11,0x11,0x11,0x11,0x10,0x00,0x10,0x00,0x11,0x11,
    0x11,0x11,0x11,0x00,0x00,0x00,0x11,0x11,0x11,0x11,0x11,0x10,0x00,0x00,0x11,0x11,
    0x11,0x11,0x11,0x11,0x00,0x00,0x11,0x11,0x11,0x11,0x11,0x11,0x10,0x00,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11],
    
    [0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x10,0x00,0x00,0x01,0x11,0x11,
    0x11,0x10,0x00,0x00,0x00,0x00,0x11,0x11,0x11,0x00,0x00,0x11,0x11,0x00,0x01,0x11,
    0x11,0x00,0x00,0x11,0x11,0x10,0x00,0x11,0x11,0x00,0x01,0x11,0x11,0x10,0x00,0x11,
    0x11,0x11,0x11,0x11,0x11,0x10,0x00,0x11,0x11,0x11,0x11,0x11,0x11,0x10,0x00,0x11,
    0x11,0x10,0x11,0x11,0x10,0x00,0x01,0x11,0x11,0x10,0x00,0x00,0x00,0x00,0x01,0x11,
    0x11,0x10,0x00,0x00,0x00,0x01,0x11,0x11,0x11,0x10,0x01,0x11,0x11,0x11,0x11,0x11,
    0x11,0x10,0x01,0x11,0x11,0x11,0x11,0x11,0x11,0x10,0x01,0x11,0x11,0x11,0x11,0x11,
    0x11,0x10,0x00,0x00,0x00,0x00,0x01,0x11,0x11,0x10,0x00,0x00,0x00,0x00,0x01,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11],
    
    [0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x10,0x00,0x00,0x01,0x11,0x11,
    0x11,0x11,0x00,0x00,0x00,0x00,0x11,0x11,0x11,0x10,0x00,0x11,0x11,0x00,0x01,0x11,
    0x11,0x10,0x01,0x11,0x11,0x10,0x00,0x11,0x11,0x00,0x01,0x11,0x11,0x10,0x00,0x11,
    0x11,0x00,0x01,0x11,0x11,0x10,0x00,0x11,0x11,0x00,0x01,0x11,0x11,0x10,0x00,0x11,
    0x11,0x00,0x00,0x11,0x11,0x00,0x01,0x11,0x11,0x00,0x00,0x00,0x00,0x00,0x01,0x11,
    0x11,0x00,0x01,0x00,0x00,0x01,0x11,0x11,0x11,0x10,0x00,0x11,0x11,0x11,0x11,0x11,
    0x11,0x10,0x00,0x01,0x11,0x11,0x11,0x11,0x11,0x11,0x00,0x00,0x01,0x11,0x11,0x11,
    0x11,0x11,0x10,0x00,0x00,0x00,0x11,0x11,0x11,0x11,0x11,0x11,0x00,0x00,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11],
    
    [0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x10,0x00,0x11,0x11,0x11,0x11,
    0x11,0x11,0x10,0x00,0x11,0x11,0x11,0x11,0x11,0x11,0x10,0x00,0x11,0x11,0x11,0x11,
    0x11,0x11,0x10,0x00,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x00,0x01,0x11,0x11,0x11,
    0x11,0x11,0x11,0x00,0x01,0x11,0x11,0x11,0x11,0x11,0x11,0x00,0x01,0x11,0x11,0x11,
    0x11,0x11,0x11,0x10,0x00,0x11,0x11,0x11,0x11,0x11,0x11,0x10,0x00,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x00,0x01,0x11,0x11,0x11,0x01,0x11,0x11,0x00,0x00,0x11,0x11,
    0x10,0x01,0x11,0x11,0x10,0x00,0x01,0x11,0x11,0x00,0x11,0x11,0x11,0x00,0x00,0x11,
    0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11],
    
    [0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x10,0x00,0x00,0x11,0x11,0x11,
    0x11,0x10,0x00,0x00,0x00,0x00,0x11,0x11,0x11,0x00,0x00,0x11,0x10,0x00,0x01,0x11,
    0x11,0x00,0x01,0x11,0x11,0x00,0x01,0x11,0x11,0x00,0x01,0x11,0x11,0x00,0x01,0x11,
    0x11,0x10,0x00,0x11,0x00,0x00,0x01,0x11,0x11,0x10,0x00,0x00,0x00,0x00,0x11,0x11,
    0x11,0x11,0x10,0x00,0x00,0x01,0x11,0x11,0x11,0x10,0x00,0x00,0x00,0x11,0x11,0x11,
    0x11,0x00,0x00,0x01,0x00,0x00,0x11,0x11,0x11,0x00,0x00,0x11,0x10,0x00,0x01,0x11,
    0x11,0x00,0x01,0x11,0x11,0x00,0x01,0x11,0x11,0x00,0x01,0x11,0x11,0x00,0x01,0x11,
    0x11,0x10,0x00,0x00,0x00,0x00,0x11,0x11,0x11,0x11,0x10,0x00,0x00,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11],
    
    [0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x00,0x00,0x11,0x11,0x11,0x11,
    0x11,0x11,0x00,0x00,0x00,0x01,0x11,0x11,0x11,0x11,0x11,0x11,0x00,0x00,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x00,0x01,0x11,0x11,0x11,0x11,0x11,0x11,0x00,0x01,0x11,
    0x11,0x11,0x10,0x00,0x00,0x10,0x00,0x11,0x11,0x10,0x00,0x00,0x00,0x00,0x00,0x11,
    0x11,0x10,0x00,0x11,0x11,0x00,0x00,0x11,0x11,0x00,0x01,0x11,0x11,0x10,0x00,0x11,
    0x11,0x00,0x01,0x11,0x11,0x10,0x00,0x11,0x11,0x00,0x01,0x11,0x11,0x10,0x00,0x11,
    0x11,0x00,0x01,0x11,0x11,0x10,0x01,0x11,0x11,0x10,0x00,0x11,0x11,0x00,0x01,0x11,
    0x11,0x11,0x00,0x00,0x00,0x00,0x11,0x11,0x11,0x11,0x10,0x00,0x00,0x01,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11]);
    
    @logo=(
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x01,0x11,0x11,0x10,0x11,0x11,0x11,0x11,0x00,0x00,0x00,0x00,0x11,0x11,
    0x11,0x11,0x00,0x00,0x00,0x00,0x11,0x11,0x11,0x11,0x01,0x11,0x11,0x10,0x11,0x11,
    0x11,0x11,0x01,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x00,0x01,0x11,0x11,0x11,0x11,
    0x11,0x11,0x00,0x00,0x00,0x11,0x11,0x11,0x11,0x11,0x01,0x11,0x00,0x00,0x11,0x11,
    0x11,0x11,0x11,0x11,0x00,0x00,0x11,0x11,0x11,0x11,0x00,0x00,0x00,0x11,0x11,0x11,
    0x11,0x11,0x00,0x01,0x11,0x11,0x11,0x11,0x11,0x11,0x01,0x11,0x11,0x11,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x00,0x11,0x11,0x11,0x11,0x11,0x00,0x00,0x00,0x11,0x11,
    0x11,0x11,0x00,0x00,0x00,0x10,0x11,0x11,0x11,0x11,0x00,0x11,0x10,0x11,0x11,0x11,
    0x11,0x11,0x00,0x00,0x00,0x10,0x11,0x11,0x11,0x11,0x11,0x00,0x00,0x00,0x11,0x11,
    0x11,0x11,0x11,0x11,0x10,0x00,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x10,0x11,0x11,
    0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11);
    
    %FORM={};
    $x_size=16;
    $y_size=24;
    
    &parseform;
    
    $user=$FORM{'user'};
    $digits_in_image=$FORM{'digit'};
    
    open COUNTF, "<counter.dat";
    @countrec=<COUNTF>;
    close COUNTF;
    $counter=0;
    for ($i=0; $i<@countrec; $i++)
      {  if ($countrec[$i]=~/$FORM{user}/)
           {  @records=split(/\|\|/, $countrec[$i]);
              $records[1]++;
              $counter=$records[1];
              $countrec[$i]=$records[0]."||".$records[1]."\n";
           }
      }
    exit if ($counter==0);
    open COUNTF, ">counter.dat";
    flock COUNTF, 2;
    print COUNTF @countrec;
    flock COUNTF, 8;
    close COUNTF;
    
    $digits_in_image+=1;
    
    $image_size=$digits_in_image*$x_size*$y_size*2; # полный размер изображения
    $ret_size=$image_size+118;                      # полный размер файла
    
    @ret=@header;
    
    $ret[2]=$ret_size-(int($ret_size/256)*256);     # младший байт размера файла
    $ret[3]=int($ret_size/256);                     # старший байт размера файла
    $ret[34]=$image_size-(int($image_size/256)*256);# младший байт размера изображения
    $ret[35]=int($image_size/256);                  # старший байт размера изображения
    $ret[18]=$digits_in_image*$x_size;              # размер изображения по оси Х
    
    @count=split (//, $counter);
    if (($digits_in_image)>scalar(@count))
      {  for ($i=0; $i<($digits_in_image-scalar(@count)); $i++)
           {  unshift @count, 0;
           }
      }
    
    for ($i=0; $i<24; $i++)
      {  for ($j=0; $j<8; $j++)
           {  push @ret, $logo[$i*8+$j];
           }
         for ($k=0; $k<@count; $k++)
           {  for ($j=0; $j<8; $j++)
                {  push @ret, $dig[$count[$k]][$i*8+$j];
                }
           }
      }
    
    # ---------- For write to file -----------
    # open BMPF, ">counter.bmp";
    # foreach $byte (@ret)
    #   {  print BMPF chr($byte);
    #   }
    # close BMPF;
    # ----------------------------------------
    
    # -------- For write to brouser ----------
    print "Content-Type: image/bmp\n\n";
    foreach $byte (@ret)
      {  print chr($byte);
      }
    # ----------------------------------------
    
    sub parseform
    {  local($name, $value, $pair, $buffer, @pairs);
    
       @pairs=split(/&/, $ENV{'QUERY_STRING'});
       foreach $pair (@pairs)
         {  ($name, $value)=split(/=/, $pair);
            $value=~tr/+/ /;
            $value=~s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
            $FORM{$name}=$value;
         }
       return(1);
    }
    
    На сегодня с CGI-программированием закончили. Удачных Вам подсчетов посещений.




    "Лучшая ссылка"


    Путешествуя как-то во всемирной паутине, я в "ихнем" домене наткнулся на "наше" название, которое показалось мне весьма интересным, и я решил заглянуть, что называется "на огонек", поглядеть что тут хорошего дают. Как оказалось довольно много и весьма интересно.

    Заходите - сами увидите: http://properl.com




    О рассылке


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

    Домашняя страница этой рассылки в Каталоге subscribe.ru: http://subscribe.ru/catalog/comp.soft.prog.perlprog/, здесь же Вы можете и подписаться на данную рассылку.

    Архив этой рассылки находится на subscribe.ru по адресу: http://subscribe.ru/archive/comp.soft.prog.perlprog/

    Данная рассылка распространяется только через subscribe.ru.

    Если Вам понравилась эта рассылка, и Вы считаете, что она может быть полезна и другим, то отправьте ее своим друзьям.




    Ну, на этом позвольте на сегодня закончить.   До новых встреч.


    Виталий Ярошевский vitalij@newmail.ru


    При подготовке данной рассылки были использованы следующие материалы:

    1. "Основы программирования на языке Перл"     Маслов В. В. - "Радио и связь" 1999
    2. "Спецификация языка Perl"     Алена Федосеева


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



    http://subscribe.ru/
    E-mail: ask@subscribe.ru
    Поиск

    В избранное