up index search
   UP: 10.25 Интернет вчера, сегодня и завтра

10.25.1 Некоторые примеры и приемы WEB-программирования

Семенов Ю.А. (ИТЭФ-МФТИ)
Yu. Semenov (ITEP-MIPT)

Работа с таблицами в JavaScript
Передача параметров в подпрограммы Perl
Техника отладки CGI и JavaScript
Обратный отсчет таймера с отображение в поле рамки Window
Обновление диаграмм с блокировкой влияния кэша
Динамическое обновление мнемосхем сети
Некоторые экзотические решения
Суммирование чисел в колонке таблицы на WEB-странице
Некоторые советы из собственного опыта

Работа с таблицами в JavaScript

Пусть имеется таблица (оглавление для содержимого сервера) с ID="mytable".

<table style=border-style:ridge;border-color:lightblue; BORDER=8 CELLPADDING=5 WIDTH=600 bgcolor=ghostwhite id="mytable>
........................
<tr> <td VALIGN=TOP WIDTH=8% align=LEFT font-family:arial font-size:11pt>1</td> <td VALIGN=TOP WIDTH=67% align=LEFT font-family:arial font-size:11pt><a href=".././1/intr_1.htm">Введение. Общие принципы построения каналов передачи данных и сетей
</td> <td VALIGN=TOP WIDTH=15% text-align:center font-family:arial font-size:11pt>37</td> <td VALIGN=TOP WIDTH=10% text-align:center font-family:arial font-size:11pt>775</td> </tr>
........................
<tr><td VALIGN=TOP bgcolor=gainsboro>Итого</td><td ID=n_art">  </td><td ID=kbytes> </td></tr> </table>

Далее следует JavaScript "extract()".

<script language="JavaScript1.2">
function extract()
{
var sum_p=0; // pages in the first two rows
var sum_b=0; // bytes in the first two rows
var table = document.getElementById ("mytable");
var cells = document.getElementById('mytable').getElementsByTagName('td'); # form array of -fild values
var r = document.getElementById('mytable').rows.length; # calculate the number of articles
pages_n.innerHTML=r;
r=r*4;
var ind=6;
do {
sum_p = sum_p - -(cells[ind].innerHTML);
sum_b = sum_b - -(cells[ind+1].innerHTML);
ind += 4;
}
while (ind<(r-4));
//var ttt=t_st - - content.cells[ind].innerHTML;
pages_n.innerHTML=sum_p; # Put page number
kbytes.innerHTML=sum_b; # Put byte number
n_art.innerHTML="Articles= "+n_artic; # Total articles number //document.write(ind+" "+content.cells[ind-4].innerHTML);
}
extract();
</script>
<center>

Передача параметров в подпрограммы Perl

>

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

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

Ключевое слово my ограничивает доступ к переменной текущим блоком – будь то одиночный блок, условный оператор, оператор цикла, подпрограмма, команда eval или файл, подключенный командами do, require или use.

Переменные, описанные словом local, доступны также подпрограммам, которые вызываются из текущего блока.

Если что-то определено с помощью my в подпрограмме, то это не будет видно вне ее. При входе в подпрограмму такая переменная сбрасывается в нуль.

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

Ну а теперь пример из моей практики.

Пусть имеется обращение к подпрограмме some_sub($var1,\@array) (символ "\" здесь обязателен). Тогда в самой подппрограмме параметры устанавливаются командами:

$var1=$_[0];
local *bins=$_[1]
; # а не local @bins=$_[1];. Вариант @bins не позволяет передать массив @bins подпрограмме. Обратите внимание на звездочку перед именем массива (*bins).

Бывают случаи, когда файл открывается в основной подпрограмме, а запись в него производится в подпрограмме. Например, имеем подпрограмму ill_tex, где среди параметров имеется handle (Fil) файла illegal.txt, куда заносятся журнальные рекорды: ill_tex($line,$lin,*Fil);. Обратите внимание на символ "*" перед именем handle. Предполагается, что операция OPEN (формирование handle Fil) выполнена в основной программе до обращения к подпрограмме ill_tex. Внутри подпрограммы имеются команды:

local *FH=$_[2];
.........
print FH $line;

Если нужно, чтобы массив был доступен в подпрограмме без передачи его в качестве параметра, можно это сделать с помощью оператора our, делая массив глобальным:
our @records=("","","","","","","","","","","");

Появление протокола HTTP, а также языков HTML и XML открыла для разработчиков и пользователей разнообразные возможности WEB-приложений. Мощным инструментом придания динамичноcти WWW-страницам является JavaScript, а также CGI (Common Gateway Interface), PHP и другие средства. По существу JavaScript позволяет сделать HTML объектно-ориентированным. Важную роль при этом может играть использование баз данных.

Огромным преимуществом WEB-программирования является многовариантность решений (использование HTML/XML, JavaScript/VBS и т.д.). Такое многообразие, помимо адаптации к вкусам программистов, делает менее уязвимым прикладные продукты для тотального поражения их каким-то одним вирусом, червем или spyware. Кроме того, WEB-технология обеспечивает попутно удобный графический интерфейс для любого приложения.

Данная статья не ставит своей задачей обучение WEB-программированию. Для этого имеется достаточно много хороших книг. Например:


Дэвид Флэнаган, "JavaScript. Подробное руководство", (O'REILY, 2004),
Дэнни Гудман, "JavaScript. Библия пользователя" , 4-е издание, Диалектика, 2002,
Владимир Дронов, "JavaScript в WEB-дизайне", bhv, 2001
Молли Э. Хольцшлаг, "Специальное издание. Использование HTML-4", (Вильямс, 2000),
Т.Кристиансен, Н.Торкингтон, "Perl. Библиотека программиста", (O'REILY, Питер, 2000),
Томас Пауэл и Фриц Шнайдер, "Полный справочник по JavaScript", Вильямс (McGraw-Hill), 2007 и т.д.
Много материалов, включая книги и справочники по JavaScript, можно найти на сайте javascript.ru

Я привожу примеры решений, которые мне представляются удобными и практичными. Не стану утверждать, что такие решения нигде не описаны, скажу только, что я таких описаний не видел. Здесь обобщается опыт решения задач сетевой диагностики и мониторинга безопасности сотрудников лаборатории и бывших студентов кафедры ТСС (МФТИ).


Для начинающих хочу обратить внимание на несовместимость некоторых библиотечных функций JavaScript для разных браузеров, например, Internet Explorer, NetScape, или FireFox, что может приводить к тому, что некоторые функции не будут реализовываться на тех или иных браузерах. Немалую роль в замедлении отладки скриптов играет неразвитость диагностики при работе с CGI-JavaScript.

Если вы намерены передавать строки символов из CGI в JavaScript, а эти строки берутся из текстового файла, не забудьте после извлечения строки выполнить для нее операцию chop или chomp. Кроме того, такие строки при передаче из CGI в JavaScript должны помещаться между символьными последовательностями \" \". Для некоторых текстовых файлов надо удалять два символа <CR> и <LF>. В противном случае никакая диагностика вам об этом не напомнит, а программа работать не будет.

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


<script language="JavaScript" >

var bAgentNetscape4 = (navigator.appName == "Netscape" && navigator.appVersion.substring(0,1) >= "4");

var bAgentExplorer4 = (navigator.appName == "Microsoft Internet Explorer" && navigator.appVersion.substring(0,1) >= "4");

if (bAgentExplorer4) {

document.writeln("<frameset rows='70%,*' framespacing=0 frameborder=0>");

document.writeln("<frame src='trap2.htm' name=main_up frameborder=0 marginwidth=0 marginheight=0 framespacing=0>");

document.writeln("<frame src='' name=data frameborder=0 scrolling=No noresize framespacing=0>");

document.write("</frameset>");

}

if (((bAgentExplorer4)||(bAgentNetscape4))!=true) {

document.writeln("<frameset rows='80%,*' framespacing=0 frameborder=0>");

document.writeln("<frame src='trap.htm' name=main_up frameborder=0 marginwidth=0 marginheight=0 framespacing=0>");

document.writeln("<frame src='' name=data frameborder=0 scrolling=No noresize framespacing=0>");

}

</script>


Обратите внимание, что файлы, загружаемые для разных браузеров, имеют разные названия, что предполагает отличие и в текстах. Имена отладочных полей-рамок в обоих вариантах идентичны ("data"). В предлагаемом варианте можно заранее задать минимальный номер версии браузера, с которым будет успешно работать ваша программа.

Техника отладки CGI и JavaScript

Особую проблему составляет отладка WEB-программ, где помимо JavaScript используются CGI, написанные, например, на PERL. Этой задаче здесь уделено особое внимание. Связано это с тем, что операции типа parent.data.document.write(" S="); при некорректном применении приводят к нежелательным последствиям. Чтобы исключить такого рода проблемы, поле экрана делится на две части с помощью набора из двух рамок (frameset, см. ниже).


<html>

<head>

<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1251>

<title>Tracing of external routes</title>

<script language="JavaScript">

document.writeln("<frameset rows='70%,*' framespacing=0 frameborder=0>");

document.writeln("<frame src='trap.htm' name=main_up frameborder=0 marginwidth=0 marginheight=0 framespacing=0>");

document.writeln("<frame src='' name=data frameborder=0 scrolling=No noresize framespacing=0>");

</script>

</head>

</HTML>


При формировании набора рамок (frameset) задается размер их по высоте в процентах. В представленном примере верхняя рамка с именем main_up имеет ширину 70%, соответственно вторая - 30%. Число рамок может быть сделано и большим двум, что позволит разделить некоторые виды распечаток, но разрешения экрана может для этого не хватить. В первую рамку загружается отлаживаемая WEB-страница, а вторая - служит для отображения отладочных распечаток, осуществляемых CGI и JavaScript WEB-страницы (например, операции типа parent.data.document.write(" S=", S1," ",S2," ",S3);, где S1-S3, переменные JavaScript). Если ширину верхней рамки сделать равной 100%, результаты отладочных выдач на экране отображаться не будут.

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

Разумеется, существуют и другие методы вывода промежуточных данных для JavaScrip'ов. Для этого надо заранее выделить именованное поле на базовой WEB-странице (в предлагаемом ниже примере это поле представляет собой ячейку таблицы и имеет имя target). Данная программа (xyclick) позволяет выделить текстовый параметр, отображенный на WEB-странице, с помощью щелчка левой клавишей мыши (при этом определяется положение маркера мыши на странице). Значение параметра отображается в заданном поле на странице (в одной из ячеек таблицы) и может быть передано какой-либо обрабатывающей подпрограмме. При решении такой задачи нужно решить проблему абсолютной и относительной привязки нужного поля к системе координат WEB-страницы. Это делается с помощью стандартных функций tab.offsetLeft, maxi.offsetLeft, maxi.offsetTop и т.д. Сходный прием использован в программе, размещенной по адресу col_matrix. Пример работы скрипта показан на рис. 1. (Гистограмма IP-адресов, откуда предпринимались сетевые атаки).

Скрипт получает данные (IP-адреса и число событий с этим адресом) от соответствующего CGI, а JavaScript (IPS) преобразует эту информацию в гистограмму, которая формируется на основе таблицы. Длины синих линеек пропорциональны числу атак с данного адреса. Маркер мыши был установлен на третьем сверху IP-адресе, после чего была нажата левая клавиша мыши.


<script language="JavaScript">

function xyclick()

{

var X0=tab.offsetLeft+zero.offsetLeft+1;

var Y0=tab.offsetTop+zero.offsetTop+1;

var XL=event.x;

XL=Math.floor([XL-X0]*63/(maxi.offsetLeft-zero.offsetLeft));

var YL=event.y;

YL=Math.floor([YL-Y0]*40/(maxi.offsetTop-zero.offsetTop));

var cod= 0x000000 + XL*16 + YL*1024;

Ny=Math.floor((YL*24)/41);

target.innerHTML="X0="+X0+" Y0="+Y0+" XL="+XL+" YL="+YL+" NY="+Ny+" ip0="+ipa[Ny];

}

</script>


Рис. 1. Внизу таблицы в ячейке отображены некоторые отладочные данные и IP-адрес, на котором произведен клик мышью. См. текст третьей строки снизу JavaScript xyclick(), которая определяет формат и содержимое выдачи.

Вызов CGI (например, pingou.cgi, размещенного в каталоге cgi-bin) из скрипта JavaScript может осуществляться различными способами, например, с помощью команда: parent.data.document.location = "/cgi-bin/pingou.cgi". Поле data указывает, где будет действовать данный CGI, и в какой рамке будут отображаться результаты команд print данного CGI (предполагается, что скрипт IGI написан на PERL). Для возвращения результата работы скрипта pingou.cgi служит код:


print "<script language='JavaScript'>";

print "parent.main_up.Result($S, \"$node\",$cnt_cgi)";

print "</script>";


Обратите внимание, что здесь выполняется операция JavaScript в процессе реализация CGI, написанного на языке PERL. Переменные $S, $node и $cnt_cgi вычисляются в ходе выполнения скрипта CGI. Но $node является строковой переменной и по этой причине она передается между двумя последовательностями \". Код main_up указывает, в какое окно передать данные. В данном случае речь идет о первой рамке, которой было выделено выше 70% ширины окна. Объект Result указывает на имя скрипта JavaScript на странице main_up, куда должен быть передан результат работы CGI.


Здесь важно иметь в виду, что, если в следующей строке JavaScript после вызова CGI вы попытаетесь использовать результат работы CGI, ничего хорошего не получится. Это сопряжено с тем, что обращение к CGI запускает новый процесс в машине и нельзя быть уверенным, что к началу исполнения следующей строки JavaScript этот процесс завершится. То-есть, обращение к CGI не имеет аналогии с вызовом подпрограммы!

Обратный отсчет таймера с отображение в поле рамки Window

В некоторых задачах сетевой диагностики бывает нужно периодически запускать некоторые процессы, например, контролировать связность мониторируемой сети. При этом оператору удобно знать, сколько времени нужно ждать до обновления картинки. Решить эту задачу можно с помощью следующего простого скрипта. Скрипт start_Timer служит для запуска раз в секунду скрипта indi(). Значение TimerInterval определяет период перезапуска процесса в секундах (значение, с которого начинается обратный отсчет). Скрипт onLoadDoc() запускает процесс при загрузке WEB-страницы. Для этого тело страницы диагностической программы должно начинаться со строки типа: <BODY onload="onLoadDoc()" bgcolor=steelblue>


/* Таймер */

function start_Timer(interval)

{

timerID = setInterval("indi()", 1000);

}


function onLoadDoc()

{

Timer();

start_Timer(TimerInterval)

}

</script>


function indi()

{

str=str-1;

window.status=str;

if(str<=0)

{

str=count;

Timer();

}

}


Результат обратного отсчета времени (работа скрипта indi()) отображается в статусной строке открытого окна (window.status - нижняя левая часть рамки экрана). Смотри рис.2. Отсчет начинается с исходного значения и продолжается до нуля. При достижении нуля отсчет продолжается с исходного значения, одновременно (по таймеру) запускается определенный JavaScript.

Рис. 2. Значение счетчика выделено красным овалом

Обновление диаграмм с блокировкой влияния кэша

Для сетевой диагностики часто приходится пользоваться отображением временных зависимостей потоков или событий. Для этого, например, может использоваться программный пакет MRTG. Этот пакет генерирует файлы в формате png, которые он сам обновляет с определенной периодичностью. Обновленные файлы имеют то же самое имя. Вам бы хотелось, чтобы на экране монитора диаграммы автоматически обновлялись. Реализовать это можно, например, с помощью таймера. Но этому может помешать кэширование файлов в вашем браузере. Браузер, видя имя файла, проверяет наличие файла с таким именем в кэше и, если такой файл имеется, использует его. С этой проблемой приходится сталкиваться и в процессе отладки программ. Например, вы отредактировали CGI-скрипт, запускаете программу, но не видите изменений. Просто, при этом запускается скрипт, текст которого лежит в кэше. В случае отладки можно воспользоваться меню IE: сервис - свойства обозревателя - удалить файлы - ОК, очистив кэш вручную.

Пусть в нашей диагностической программе имеется фрагмент:


<img ID="day" src="../../mrtg/c7206.itep.ru_1-day.png" border=0>

То же за неделю

<img ID="week" src="../../mrtg/c7206.itep.ru_1-week.png">

То же за месяц

<img ID="month" src="../../mrtg/c7206.itep.ru_1-month.png">

Packet flow for C-7206

<img ID="pkt" src="../../mrtg/c7206.itep.ru_0-day.png">


Сразу заметим, что каждый элемент графики снабжен именем (ID). Это открывает еще одну возможность обновления диаграмм.

В JavaScript'е Result вводятся строки (см. ниже), которые и осуществляют обновление диаграмм. Для решения проблемы, несмотря на влияние кэша, используется генератор случайных чисел (объект Math.random()). Благодаря этому подходу кэш блокируется, так как объект модифицирует свое наименование.


......

day.src="../../mrtg/c7206.itep.ru_1-day.png?"+Math.random();

week.src="../../mrtg/c7206.itep.ru_1-week.png?"+Math.random();

month.src="../../mrtg/c7206.itep.ru_1-month.png?"+Math.random();

pkt.src="../../mrtg/c7206.itep.ru_0-day.png?"+Math.random();

......

Динамическое обновление мнемосхем сети

При решении задач сетевой диагностики бывает нужно отслеживать доступность определенных сетевых объектов (рабочих станций, серверов, маршрутизаторов и.т.д.). Удобно отображать результат такой проверки на некоторой мнемосхеме, где доступные объекты, например, отображаются зеленым, а недоступные объекты - красным цветом. Проверка доступности обычно выполняется с помощью команд типа ping, которые могут быть встроены в некоторый CGI-скрипт. Число мониторируемых объектов практически не ограничено. Число состояний объекта может быть юольше двух. Скрипт возвращает результат проверки доступности в виде списка переменных. На базовой странице значения этих переменных проверяются и производится модификация объектов мнемосхемы. Это может быть сделано с помощью следующей простой программы JavaScript.


cataly.filters.blendTrans.Apply();

if(S1 !=0) { cataly.src="Catalyst_g.jpg"; }

else { cataly.src="Catalyst_r.jpg"; }

cataly.filters.blendTrans.Play();


Здесь сетевой объект с именем cataly опсан на базовой странице. Если значение присланной скриптом переменной S1 равно 0 будет выполнена команда cataly.src="Catalyst_r.jpg"; и объект на мнемосхеме станет красным, в противном случае - зеленым. Причем смену цвета можно сделать плавной (метод и свойства filters.blendTrans.Play()). Файлы рисунков Catalyst_g.jpg и Catalyst_r.jpg (желательна прямоугольная форма) должны содержатьс в том же каталоге, что и файл базовой страницы. Для описания объекта cataly может быть использована строка:


<img name="cataly" style="position:absolute; top:46px; left:157px; z-index:auto;filter:blendTrans(duration=4);" src=Catalyst_r.jpg>


Мнемосхема обычно представляет собой графический образ формата jpg, gif или bmp. Геометрическое положение объекта на странице здесь задается абсолютно, что не слишком удобно. Для определения абсолютных координат на странице можно использовать специальные утилиты, написать скрипт на основе приведенного выше текста xyclick() или даже написать программу, которая будет формировать строки типа приведенной выше автоматически. Время перехода от одного вида (цвета) объекта к другому задано равным 4 сек (duration=4).

Иногда бывает нужно динамически размещать объекты, положение которых заранее не известно. Например, нужно отмечать города, откуда произошла атака. Конечно можно возразить, что положение городов на карте известно, но их много и задать положение всех городов слишком трудоемко. В перспективе дело идет к тому, что координаты всех машин будут определяться с помощью GPS. А где будет некоторый laptop, который украли накануне, знать уж точно нельзя. Решение задачи отображения объектов на карте по известным координатам, когда требуемая точность отображения не слишком велика, достаточно просто. Фрагмент карты размещается к рамке или таблице. Координаты верхнего левого угла такой рамки или таблицы определяется с помощью функций tab.offsetLeft и tab.offsetTop (tab - идентификатор таблицы или рамки). Положение размещаемого на карте объекта отсчитывается от точки с этими координатами. Такой подход позволяет исключить влияние разрешающей способности дисплея, на котором производится просмотр результата. Далее вычисляются истинные координаты объекта на карте YC и XC. А для отображения объекта (в данном случае квадратика square1.gif) используется код JavaScript document.write:

document.write("<img style=position:absolute;top:"+YC+"px;left:"+XC+"px;z-index:auto;filter:blendTrans(duration=4); src=e:/WWW/attack_map/square1.gif>");}

Результат работы подобной программы представлен на рис. 3. В данном случае это карта мира с отображенными на ней точками, откуда производились в течение часа сетевые атаки МСЦ РАН.

Рис. 3.

Для решения данной задачи пришлось сформировать набор фреймов (смотри ниже). Из них четвертый служит для целей отладки. Основная динамическая секция является второй (trace_s4.htm). Именно здесь реализуются процедуры отображения точек, откуда происходят атаки. Связано это с тем, что процесс document.write стирает изображение, полученное в данном фрейме другим процессом.

document.writeln(("<frameset rows='8%,65%,7%,0%' framespacing=0 frameborder=0>");
document.writeln(("<frame src='trace_s3.htm' name=second_up frameborder=0 marginwidth=0 marginheight=0 framespacing=0>");
document.writeln(("<frame src='trace_s4.htm' name=main_up frameborder=0 marginwidth=0 marginheight=0 framespacing=0>");
document.writeln(("<frame src='trace_s5.htm' name=main_up1 frameborder=0 marginwidth=0 marginheight=0 framespacing=0>");
document.writeln("<frame src='' name=data frameborder=1 scrolling=No noresize framespacing=1>");

Фрагмент кода отображающего признаки (красные квадратики) уровня атаки в точках, откуда они предприняты, показан ниже. Для преобразования IP-адреса в абсолютные географичесикие координаты использовалась база данных GeoIP. Предварительно географические координаты источника атаки преобразуются в значения переменных SS и YC, определяющих координаты точки, где на карте мира будет размещен соответствующий "квадратик" (массив Array содержит в себе числа атак):

if(Array[2] <= 10) {SS=SS-2;
	YC=YC-2;
	document.write("");}
.

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

Рис. 3а. Нанесение ограничителей на диаграмму для последующей обработки событий из выделенной области (темно-синии вертикальные линии).

Пометка определенных точек на диаграмме нужно, чтобы потом установить соответствие этих точек и определенных моментов времени. При этом WEB-страница должна быть полностью развернута (кнопка на верхней рамке окна справа). Для того чтобы минимизировать ошибки, связанные с разными возможностями дисплеев, нужно учитывать масштаб. для этого могут быть использованы некоторые объекты и атрибуты JavaScript. Смотри рис. 3б ("corner" идентификатор рисунка, размещенного по центру). Переменная Width в данном случае будет равна ширине экрана в пикселях на дисплее машины, где исполняется этот JavaScript.

Рис. 3б.

Фрагмент программы, отображающей число атак, предпринятых с территории США, показан ниже. Реальное число атак содержится в переменной S31.

SS=(screen.width - world.offsetWidth)/2+175;
document.write("

 

"); SC=SS; ... if(S31 !=0) { usa.innerHTML="<b>"+S31+"</b>";}

Некоторые экзотические решения

Замена имени загруженного файла, отображаемого в поле верхней части рамки окна (слева). Ситуация когда поле окна перегружено, а нужно уведомить пользователя о некотором событии, достаточно типична. Ниже описано решение этой задачи, где, кроме того, демонстрируются комплексно многие приемы, рассмотренные ранее. Приведенная версия самая компактная. Посколько в данном примере используется CGI-скрипт, перед началом отладки следует установить Apache (сконфигурировать его, если это не было сделано раньше). Начинать надо с запуска процесса Apache. После этого надо загрузить Internet Explorer. Если по какой-то причине браузер автоматически не выдает список каталога www. Следует ввести в качестве имени сервера localhost. Запуск отлаживаемой программы нужно производить через Internet Explorer, перейдя предварительно в каталог, где размещены отлаживаемые файлы.

Формируем файл start.htm, содержимое которого представлено ниже. Приведенная версия самая компактная (здесь и далее предполагается, что вы работаете с браузером Internet Explorer):


<html>

<head>

<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1251">

<title>Testing of changing header</title>

<frameset rows='20%,*' framespacing=0 frameborder=0>

<frame src='ch_head.htm' name=main_up frameborder=0 marginwidth=0 marginheight=0 framespacing=0>;

<frame src='' name=data frameborder=0 scrolling=No noresize framespacing=0>

</frameset>

</head>

</HTML>


Имя загружаемой страницы "ch_head.htm", а заголовок файла "Testing of changing header". Ради экономии места ширина первой из рамок выбрана равной 20% (окраска фона рамки - темно-синяя).

Текст основной программы (файл ch_head.htm) представлен ниже.


<html>

<head>

<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1251">

<title>Changing header</title>

<script LANGUAGE="JavaScript">

TimerInterval = 5000 // This=10 sec (in millisecs)

function writetitle()

{

parent.document.title = "This is a new state";

}

function Timer()

{

parent.data.document.location = "/cgi-bin/test.cgi"

}

function setupElement() {

window.setInterval("Timer();",TimerInterval);

}

function Result(S1)

{

if(S1==1) {

parent.data.document.write("Flag=",S1);

parent.data.document.write(" Title=",document.title)

writetitle();

}

}

</SCRIPT>

</head>

<BODY bgcolor=darkblue LINK="#0000FF">

<script LANGUAGE="JavaScript">

setupElement();

</script>

</body>

</HTML>


В программе ch_head.htm в скрипте Timer() имеется вызов CGI-скрипта /cgi-bin/test.cgi. Положение каталога /cgi-bin/ определяется конфигурацией Apache. Для реализации рассматриваемой функции это не является обязательным. Просто здесь показан пример возможного расширения функциональности предлагаемого метода, попутно демонстрируются возможности отладочных распечаток. Текст CGI-скрита test.cgi приведен ниже:


#!c:/perl/bin/perl

print "Content-type: text/html \n\n";

use IO::File;

use Socket;

$AF=1;

print "FF=",$AF,"\n";

print "<html><head>";

print "<script language='JavaScript'>";

print "parent.main_up.Result($AF)";

print "</script>";

print "</head></html>";


Команда скрипта print "FF=",$AF,"\n"; выдает результат в поле нижней рамки (Data). Вспомним форму вызова скрипта (parent.data.document.location ="/cgi-bin/test.cgi";). Объяснение смотри выше. Результат работы скрипта test.cgi возвращается JavaScript'у Result в окно страницы ch_head.htm. Смотри форму команды test.cgi print "parent.main_up.Result($AF)". parent указывает, что возврат данных следует произвести вызвавшей скрипт программа, а main_up фиксирует, что данные (если таковые имеются) нужно передать в верхнюю рамку (вспомните текст программа start.htm). При запуске программы start.htm на экране появится картинка, показанная на рис. 3а.

Рис. 3a. Исходная запись в поле рамки - заголовок загруженного файла, выделенный метками <title> ... </title> - "Testing of changing header".

В поле рамки окна будет записано: "Testing of changing header - Microsoft Internet Explorer", что соответствует заголовку программы start.htm. В программе ch.head.htm в скрипте setupElement() запускается таймер с постоянной времени 5000 миллисекунд (5 сек), по истечении этого времени надпись в поле рамки будет заменена на "This is a new state - Microsoft Internet Explorer". В реальности часть надписи после тире не изменяется. Смотри рис. 4. В нижней части рисунка (в поле "Data") вы видите: FF=1 Flag=1 Title=Changing header. Здесь FF=1 является выдачей CGI-скрипта test.cgi, а остальная часть является результатом работы двух команд программы ch.head.htm:


parent.data.document.write("Flag=",S1);
parent.data.document.write(" Title=",document.title);


Убрать эти отладочные распечатки можно, закомментировав или стерев эти команды, а также сделав ширину рамки main_up равной 100%. Объект document.title характеризует надпись в поле рамки. Перезапись его содержимого и меняет эту надпись. Конечно, если бы было нужно получить приведенную надпись, проблему можно было решить на порядок проще. Но если вам нужно уведомить пользователя о том, что произошло некоторое событие, или сообщать в каком режиме работает программа (в случае, если этот режим динамически меняется), то предлагаемый вариант может оказаться полезным.

Рис. 4. - надпись в поле рамки заменена на "This is a new state - Microsoft Internet Explorer"

Обратите внимание на то, что команда перезаписи надписи в поле рамки имеет формат: parent.document.title = "This is a new state";. Собственно я здесь хочу привлечь ваше внимание к элементу parent. Этот элемент введен для того, чтобы изменить атрибут title именно в том объекте, который нужно. Ведь загрузка страницы была произведена программой start.htm, которая является прародителем программы ch_head.htm.


Плавно движущийся фон. (Владимир Дронов, "JavaScript в WEB-дизайне", bhv, 2001; Roy Sinclair - roysincler@email.msn.com). Исходная картинка может быть выполнена в любом приемлемом формате (jpg, gif, bmp и т.д., в данном примере это natur17m.jpg, воспроизводящий облака). Скрипт (смотри текст ниже) плавно (циклически) перемещает картинку в вертикальном направлении.


<html>

<head>

<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1251">

<title>Moving background</title>

<BODY background= "natur17m.jpg">

<script language="JavaScript1.2">

var backgroundOffset = 0;

var bgObject = eval('document.body');

function scrollBG(maxSize) {

backgroundOffset = backgroundOffset-1;

if (backgroundOffset > maxSize) backgroundOffset = 0;

bgObject.style.backgroundPosition = "0 " + backgroundOffset; }

var ScrollTimer = window.setInterval("scrollBG(307)", 64);

</script>

</body>

</HTML>


Суммирование чисел в колонке таблицы на WEB-странице

Иногда появляется необходимость извлечения какого-либо фрагмента текста, содержащегося на WEB-странице. Например, если на странице имеется таблица, где нужно просуммировать числа, размещенные в одной из колонок. Для решения задачи можно привлечь метод innerHTML. То что этот метод используется для занесения нужного текста в позиции страницы, помеченные с помощью идентификаторов, достаточно широко известно. Но этот метод применим и для обратной процедуры.

Программа пишется исключительно на JavaScript. В области заголовка страницы размешается текст скрипта:

<script language="JavaScript1.2">

function extract()

// Функция для извлечения фрагмента текста WEB-страницы

{

var sum_p=0; // pages in the first two rows

var r=content.rows.length; // Определение числа строк в таблице

r=r*4-4; // Вычисление предельного значения счетчика циклов, если число колонок в таблице равно 4

var ind=6; //задание начального значения индеуса цикла

do { // начало цикла

sum_p = sum_p - -(content.cells[ind].innerHTML); //суммируем значения чисел, размещенных в третей колонке

// оператор content.cells[ind].innerHTML извлекает содержимое из ячейки с номером ind таблицы с идентификатором content.

ind += 4; // инкрементация индекса цикла (в таблице 4 колонки)

}

while (ind

pages_n.innerHTML=sum_p; //занесение результата суммирования в итоговую ячейку с ID=pages_n

}

</script>

Пусть в теле страницы имеется таблица c идентификатором ID=content (см. ниже). В конце таблицы имеются две ячейки для размещения итоговых сумм (в данном примере используется только одна с идентификатором pages_n, куда и заносится результат суммированя ячеек 3-ей колонки таблицы (ряд таблицы с записью "Итого").


<table ID="content" BORDER=8 CELLPADDING=5 bgcolor=ghostwhite>

Номер раздела Название раздела Объем в страницах Объем в кбайт
2.3 Цифровые каналы T1 и Е1 2 1
2.4 Методы преобразования и передачи звуковых сигналов 6 5
2.4.1 Дельта-модуляция 1 1
2.4.2 Кодировщики голоса (Vocoder) 2 2
2.4.3 Передача голоса по каналам Интернет 5 2
Итого  

....

<script language="JavaScript1.2">

extract()

</script>

Где-то далее размещается обращение к JavaScript extract. Скрипт исполнится, когда таблица уже загружена на страницу. В ячейке результата для данного примера будет занесено число 16.


Если вы захотите скопировать тексы программ себе, лучше это делать с экрана браузера, а не пытаться брать код из позиции меню "просмотр HTML кода" (ведь там символ < закодирован в виде последовательности символов & l t и ; и т.д.).

Некоторые советы из собственного опыта

При постороении системы скриптов, запускаемых по crontab, иногда возникают проблемы из-за нестабильности их времени выполнения. Можно такие скрипты оформить в виде подпрограмм некоторой библиотеки, и запускать из предыдущего скрипта, но это не всегда удобно и относительно трудоемко. Решением может служить запуск скрипта в конце исполнения предыдущего. При этом не будет перегружаться процессор исполнением нескольких скриптов в параллель. В учебниках, там где это есть, рекомендуется воспользоваться операцией do "next_script.pl".

Если следовать этому совету буквально, программа будет работать при запуске с консоли (если оба скрипта находятся в одном и том же каталоге) и не будет - при запуске по crontab. Это связано с тем, что при запуске посредством crontab необходимо для любой ссылки указывать полный проход до файла или программы.

Эта техника может использоваться и, например, при перезапуске Apache: /usr/local/apache/bin/httpd.


   UP: 10.25 Интернет вчера, сегодня и завтра