| ||||||||||||||||
| ||||||||||||||||
| ||||||||||||||||
CGI программирование вывода в клиентскую среду Настоящая публикация посвещена ряду вопросов CGI-программирования на языке Perl, а именно нетипичным ситуациям генерации выходных данных в среде броузера. Рассматриваются варианты возврата выходных данных с помощью контейнерных HTML элементов: APPLET, SCRIPT, OBJECT, IFRAME (ILAYER для Netscape), а также элемента IMG. Представлены примеры программирования реальных ситуаций с использованием Perl, JavaScript, Java, событийно-управляемого языка Flash 5 (выборка новостной информации из БД, защита copyright и защита от копирования, вывод курса валют on-line без перезагрузки страницы). Показано, что активное взаимодействие сценариев CGI и программ на языках JavaScript, Java, скриптов Flash в значительной степени расширяет возможности представления и обработки выходной информации, позволяет автоматизировать процессы вывода и сократить накладные расходы. Особое внимание уделено разделению CGI программы и HTML-кода, что позволяет дизайнерам модифицировать HTML-страницы независимо от CGI-скрипта и независимо от CGI-программиста. Содержание.
Введение.
Взаимодействие между пользовательской интерактивной HTML-страницей (среда броузера, клиент) и
сервером обслуживается протоколом CGI. При передаче данных от клиентской формы серверу, последний
кодирует входные данные, а сценарий CGI декодирует их, а затем функционально обрабатывает и возвращает
выходные данные броузеру.
§1. Загрузка ресурса IMG.
Задача. <IMG src="../cgi-bin/rand_imgages.cgi">. Надо отметить, что этот прием достаточно часто используется в Web-программировании. Все сложности сводяться к написанию премлемого CGI-скрипта, который отвечал бы поставленной задаче. В качестве наглядного примера приведем давольно простой скрипт, обеспечивающий случайный вывод изображения из ограниченного списка графических файлов: #!/usr/bin/perl $path = "c:/apache/htdocs"; @pic=('c0.gif','c1.gif','c2.gif','c3.gif','c4.gif','c5.gif','c6.gif','c7.gif','c8.gif'); srand; $id=int(rand(9)); $gif=$path.'/images/'.$pic[$id]; print "Content-Type: image/gif\n\n"; open G,$gif; binmode( G ); binmode( STDOUT ); print <G>; close G; exit;Для полноты картины приведем и текст HTML-страницы: <html> <head> <title>Copyright 2002 The Web Production</title> </head> <body> <b>TOP</b> Text text ......<br><br> <center> <IMG SRC="../cgi-bin/rand_imgages.cgi"> </center> <br> <b>BOTTOM</b> Text text ......<br><br> </body> </html> В этом примере видно, что дизайн может быть реализован отдельно от загружаемых изображений (но, с учетом их ширины и высоты) и может изменяться независимо от CGI-сценария и независимо от CGI-программиста. Более сложный вариант CGI-программы, обеспечивающий случайный выбор из переменного списка изображений, должен включать код открытия обособленной директории файлов изображений: ... ... ... $DIR_PICTURES = $path.'/picturies'; opendir (ETC, $DIR_PICTURES)||die "no directory!: $!"; $i=0; foreach $filename (readdir(ETC)) { if($i > 1){ $k=$i-2; $my_pic[$k]=$filename;} $i++;} close (ETC); $leng=@my_pic; srand; $id=int(rand($leng)); $gif=$path.'/images/'.$my_pic[$id]; ... ... ...
В этом скрипте, имена файлов заносяться в массив @my_pic, причем для пропуска точек (. и ..) в верхей части директории,
выполняется условый оператор в зависимости от значения счетчика (переменная $i).
§2. Загрузка CGI-сценариев в контейнере IFRAME.
Основной привлекательностью использования элемента IFRAME является возможность выделения в
произвольном месте HTML-страницы прямоугольной области произвольных размеров. Этот прием часто
применяется для внедрения в статическую HTML-страницу, новостной, часто меняющейся информации,
как текстовой, так и графической. При этом, как правило, новостная вставка, сама представляет собой
HTML-страницу (файл). Применение, в качестве загрузочного ресурcа CGI-сценария позволит автоматизировать
процедуру смены новостей.
<IFRAME SRC="../cgi-bin/news_bulletin.cgi" HSPACE="0" VSPACE="0" FRAMEBORDER="0" MARGINHEIGHT="0" MARGINWIDTH="0" WIDTH="320" HEIGHT="100"> </IFRAME>. Напомним, что элемент IFRAME представляет собой встроенный элемент Internet Explorer (IE). Начнем рассмотрение с CGI-скрипта: #!/usr/bin/perl print "Content-Type: text/html\n\n"; $path = "c:/apache/htdocs"; $FILE_NEWS=$path.'/txt/bulletin.txt'; open(LIST,"<$FILE_NEWS"); @lines=<LIST>; close(LIST); #-------HTML-include: print <<EOT; <html> <head> <style type="text/css">P.just{text-align: justify;}</style> </head><body bgcolor='#FFFFFF' leftmargin='0'> <table border="0" cellspacing="0" cellpadding="20"> <tr> <td><p class="just"><font color='#00007b' size='4'>@lines</font></p></td> </tr> </table> </body></html> EOT exit; В процессе загрузки в броузер новостной HTML-страницы, управление передается CGI-скрипту, который считывает обычный текстовый файл bulletin.txt с диска сервера, создает на лету HTML-вставку и выводит ресурс в элемент IFRAME. Для наглядности, HTML-вставка размещена в теле CGI-скрипта. В реальной ситуации, HTML-вставка существует в виде шаблона в каталоге шаблонов на сервере или находиться в таблице шаблонов в БД. Ниже представлена собственно новостная HTML-страница (news.html): <html> <head> <title>Copyright 2002 The Web Production</title> <style type="text/css">P.just{text-align: justify;}</style> </head> <body bgcolor='#00007b' text="white"> <center><h2>News Bulletin</h2></center><hr> <table border='1' cellspacing="0" cellpadding="10"> <tr> <td align="left" valign="top" width='400'>Examples examples examples examples examples: </td> <td align="left" valign="top"> <IFRAME SRC="../cgi-bin/cgi_programming/news_bulletin.cgi" HSPACE="0" VSPACE="0" FRAMEBORDER="0" MARGINHEIGHT="0" MARGINWIDTH="0" WIDTH="320" HEIGHT="100"> </IFRAME> <ILAYER SRC="../cgi-bin/cgi_programming/news_bulletin.cgi" left="0" top="0" VISIBILITY="show" WIDTH="320" HEIGHT="100"> </ILAYER> </td> </tr> </table> </body> </html> Из этого примера видно (рис.1), что динамически обновляемая информация отделена от статического дизайна, который может модифицироваться дизайнером без ущерба CGI-cкрипту. Дополнительный элемент ILAYER будет понятен броузеру Netscape Navigator (NN). Ниже представлен простой пример CGI-скрипта, выполняющий единичную выборку новостей из базы данных MySQL: ... ... ... $table_name="news_arjive"; $dbh = DBI->connect("DBI:mysql:$database:$host:$port",$login,$pass); $sth = $dbh->prepare("SELECT text_news FROM $table_name WHERE id = 1"); $sth->execute; $news = $sth->fetchrow_array (); $sth->finish; $dbh->disconnect; #-------HTML-include: print <<EOT; <html> <head> <style type="text/css">P.just{text-align: justify;}</style> </head><body bgcolor='#FFFFFF' leftmargin='0'> <table border="0" cellspacing="0" cellpadding="20"> <tr> <td><p class="just"><font color='#00007b' size='4'>$news</font></p></td> </tr> </table> </body></html> EOT exit;
Отметим, что изменение кода HTML-вставки, выразилось лишь только в замене массива @lines на переменную
$news. §3. CGI-JavaScript программирование.
В рассмотренных выше примерах вставка возвращаемых данных осуществлялась,
со стороны броузера, пассивно. Активное взаимодействие сценариев CGI и скриптов языка JavaScript в значительной
степени расширяет возможности представления и обработки этих данных. В качестве примера, рассмотрим задачу
охраны авторского права на публикуемую новостную информацию.
<SCRIPT language="JavaScript" src="../cgi-bin/jscgi_prog.cgi"></SCRIPT>.Расссмотрим сначала код HTML-страницы: <html> <head> <style type="text/css">P.just{text-align: justify;}</style> <script> var name_copyright='Copyright 2002 The Web Production'; function test_copyright(){return name_copyright;} </script> <SCRIPT language="JavaScript" src="../cgi-bin/cgi_programming/jscgi_prog.cgi"></SCRIPT> </head> <body bgcolor='#00007b' text="white" leftmargin='0'> <center><h2>News Bulletin</h2></center><hr> <table border="0" cellspacing="0" cellpadding="20" width="800"> <tr> <td align="left" valign="top" width="400">Examples examples examples examples examples examples ......</td> <td bgcolor='#0000aa' align="left" valign="top" width="400"> <p class="just"><font color='#ffffff' size='4'> <script>test2();</script> </font></p></td> </tr> </table> </body> </html> Как видим в теле HTML-страницы располагается подпрограмма-функция test_copyright( ). Возвращаемый параметр этой функции содержит copyright. Образ этого copyright находится в одной из переменных сценария CGI: #!/usr/bin/perl print "Content-Type: text/html\n\n"; $path = "c:/apache/htdocs"; $FILE_NEWS=$path.'/txt/bulletin.txt'; open(LIST,"<$FILE_NEWS"); @lines=<LIST>; close(LIST); $txt=join("",@lines); $txt=~s/\n//g; $param='Copyright 2002 The Web Production'; #patteren print "function test2(){". "var m1= test_copyright();". "if(m1==\"$param\"){document.write(\"$txt\");". "document.write(\"<br><br>$param<br>\")}else{err();}}"; exit;
Функция test2( ) языка JavaScript, размещается в теле CGI-скрипта, а вызывается на выполнение при загрузке
HTML-страницы. В процессе выполнения сценария CGI, последний, с помощью скрипта test2( ),
анализирует информацию, возвращаемую подпрограммой-функцией test_copyright( ) и сравнивает ее с образом
copyright в переменной $param. В зависимости от совпадения или несовпадения образа с copyright, новостная информация
публикуется или возвращается ошибка JavaScript. Ошибка JavaScript, равносильная запрету на публикацию,
возникает в двух случаях: 1) если вы измените или удалите copyright из тела HTML-страницы, 2) если вы
попытаетесь удалить подпрограмму-функцию. Из кода HTML видно, что атрибуты текста новостей могут быть изменены независимо от сценария CGI и независимо от скрипта языка JavaScript. Разумеется, мы здесь представили упрощенный вариант скриптов, преследуя цель наглядности излагаемого материала. Понятно, что техника CGI-JavaScript программирования, позволяет создать весьма изощеренные средства защиты и ограничения доступа. §4. CGI-Java программирование.
Пожалуй CGI-Java технология является наиболее перспективной и наиболее интересной в области
Web-программирования. Несмотря на выросшую популярность языка Java, CGI остается фактическим стандартом
взаимодействия в модели клиент/сервер. Непоколибимость CGI объясняется просто. Во-первых протокол
HTTP является основным механизмом передачи информации. Этот механизм положен в основу WWW.
Во-вторых, это мощность языка Perl, который чаще всего используется в CGI-программировании. Perl изначально
задумывался как высокоуровневый кросс-платформенный язык системного программирования [5]. Perl 5 работает
практически везде: Unix, Linux, BSD, Windows, .NET, Sun, Macintosh. В Perl поддерживается интерфейс как к
реляционным(SQL) базам данных, так и к постреляционным СУБД типа Cache' [6]. При желании в Perl можно написать программу, в которой будет
реализован практически весь арсенал приемов объекто-ориентированного программирования [7]. И наконец, в
третьих, программе на Java можно передать всю необходимую информацию от CGI-сценария
с помощью потоков ввода-вывода. И наоборот, программы на Java сами могут передавать информацию в сценарии
CGI, например, можно "заставить" апплет записывать информацию, полученную из формы в файл на диск.
<APPLET CODE="cgi_java.class" codebase="/java_applets/" WIDTH="400" HEIGHT="330"></APPLET>,где codebase - имя каталога, в котором содержится файл cgi_java.class. Рассмотрим сначала Java-апплет: import java.awt.*; import java.net.*; import java.io.*; import java.awt.Graphics; import java.awt.Color; import java.awt.Font; import java.awt.FontMetrics; import java.lang.*; import java.net.MalformedURLException; public class cgi_java extends java.applet.Applet{ private TextArea fileArea; Font titleFont; FontMetrics titleFontMetrics; String line; int num; String text[ ] = new String[100]; public void init() { fileArea = new TextArea(); try { URL file = new URL(getDocumentBase(), "/cgi-bin/java_cgi.cgi"); BufferedInputStream my_buffer = new BufferedInputStream(file.openStream()); DataInputStream in = new DataInputStream(my_buffer); num=0; while ((line = in.readLine()) != null){ fileArea.appendText(line); fileArea.appendText("\n"); text[num]=line; num++; } in.close(); } catch(MalformedURLException e) { } catch(IOException e) { } } public void paint(Graphics g) { titleFont = new java.awt.Font("Courier", Font.BOLD, 80); titleFontMetrics = getFontMetrics(titleFont); g.setColor(Color.white); g.fillRect(0,0,600,500); g.setColor(Color.cyan); g.setFont(titleFont); g.drawString("Copyright",0, 80); g.drawString("© 2002",30, 180); g.drawString("TheWeb",30, 280); g.drawString("Production",0, 380); titleFont = new java.awt.Font("Courier", Font.BOLD, 12); titleFontMetrics = getFontMetrics(titleFont); g.setColor(Color.black); g.setFont(titleFont); int j, x=10, y=40, dy=15; for (j=0; j < num; j++){ g.drawString(text[j], x, y); y=y+dy; } } }
В этом апплете, для реализации построчного чтения выходного потока CGI-сценария, мы использовали
метод языка Java - readLine( ). Для того, чтобы этот метод работал, необходимо предварительно определить
собственно поток DataInputStream(my_buffer), а перед этим для чтения информации из открытого потока ввода,
следует сначала создать буффер: my_buffer. В процессе чтения строк, последние заполняют массив text[ ].
Графический вывод строк в броузер обеспечивает метод Paint( ) с помщью оператора g.drawString(text[j], x, y).
#!/usr/bin/perl print "Content-type: text/plain\n\n"; require 'globalvar.pm'; $table_name="news_arjive"; $dbh = DBI->connect("DBI:mysql:$database:$host:$port",$login,$pass); $sth = $dbh->prepare("SELECT text_news FROM $table_name WHERE id = 1"); $sth->execute; $txt = $sth->fetchrow_array (); $sth->finish; $dbh->disconnect; $txt=~s/\n/ /g; $txt.=" "; $start=0; $my_leng=64; $str="-"; while($str){ $str=substr($txt,$start,$my_leng); $etc_leng=rindex($str," "); $str=substr($txt,$start,$etc_leng); $start=$start + $etc_leng; print "$str\n";} exit;
Переменные $database, $host, $port, $login и $pass, для доступа и открытия БД, загружаются в сценарий
с помощью команды require из модуля globalvar.pm. Длинна строк $my_leng не превышает 64 символов.
Образом для выделения подстрок является пробельный символ " ". Циклическое формирование строк и создание
стандартного потока вывода, осуществляется всего шестью строками кода. На Java такое трудно
реализовать. Зато на Java легко реализуется графическая форма представления текста. Графический вывод
текстовой информации, преследует цель противодействовать несанкционированному копированию
новостных данных. Чтобы усилить защиту против копирования, текст выводиться на фоне
"водяных знаков" - рис.3. Теперь потенциальному взломщику потребуется выполнить копирование
экрана, обработку полученного изображения в PhotoShop, преобразование графики в текст с помощью
FineReader, редактирование текста (FineReader выполняет распознавание текста далеко не на все 100% ).
<HTML> <HEAD> <TITLE>TheWebProduction</TITLE> </HEAD> <BODY> <table align="left" border="1"> <tr><td align="center"> <h1>Result of CGI-Java programming:</h1><br> <b>Copyright (c) 2002 TheWebProduction</b> </td></tr> <tr><td valign="top"> <APPLET CODE="lastcgi_3.class" codebase="/java_applet/" WIDTH="520" HEIGHT="420"> </APPLET> </td></tr> </table> </BODY> </HTML>Последний HTML-код показывает независимость CG-Java программы от дизайна. §5. CGI-Flash программирование.
Появление технологии Flash компании Macromedia в значительной степени преобразило мир Web.
Flash, без особой шумихи (что было свойственно распространению в Web языка Java), быстро занял
свою нишу и эволюционировал от внешних plug-in к встроенным в броузеры IE и NN и является в
настоящее время полноценной частью инструментов Web-дизайна и Web-программирования.
Применение Macromedia Flash избавляет от проблемы совместимости между броузерами, Flash одинаково
работает как в IE, так и в NN. В Macromedia Flash 5 применяется специальный событийно-управляемый язык,
который поддерживает условные переходы, циклы, массивы, функции и классы, которые можно наследовать.
Процедуры ввода-вывода данных, как мы увидим ниже, могут быть реализованы с помошью всего лишь одного
оператора этого языка.
<HTML> <HEAD> <TITLE>TheWebProduction</TITLE> </HEAD> <BODY bgcolor="#FFFFFF"> <h1>CGI-Flash programming:</h1> <hr> <TABLE border='0' WIDTH='640' align='left' valign='top' cellpadding="0" Как мы видим (рис.4), файл Flash finan.swf выводит в HTML-страницу информационную вставку и идеология разделения CGI-программы и дизайна не нарушена. Программа CGI показана ниже: #!/usr/bin/perl use IO::Socket; print "Pragma: no-cache\nCache-control: no-cache\nContent-type: text/plain\n"; $port="80"; my $host="www.my_forex.com"; my $file; $valuta="EURUSD"; $file = "/rate/simulation.html"; socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp')); $iaddr = inet_aton($host); $paddr = sockaddr_in($port, $iaddr); connect(SOCK, $paddr); send (SOCK, "GET $file HTTP/1.0\nHOST:$host\n\n", 0); @data=<SOCK>; close(SOCK); $answer = join("",@data); ($etc,$iter1)=split(/$valuta/,$answer); $met='</SPAN>'; @iter2=split(/$met/,$iter1); @iter3=split(/>/,$iter2[0]); @iter4=split(/>/,$iter2[1]); ($sec, $min, $hour, $day, $month, $year, $wday, $yday, $isdst) = gmtime(time); if($sec < 10){$sec="0".$sec;} if($min < 10){$min="0".$min;} if($hour < 10){$hour="0".$hour;} $my_time=$hour.":".$min.":".$sec; print "\nmy_bid=".$iter3[3].'&my_ask='.$iter4[3].'&my_time='.$my_time; exit; Функция socket( ) создает сокет, тип которого определен как потоковый - SOCK_STREAM. После конвертации имени сокета (более удобного представления для сервера), создается соединение с помощью функции connect( ). Предварительно с помощью переменных $host и $file задаются имя сервера и имя ресурса, соответственно. Для передачи данных через сокет используется функция send( ), а для приема данных через сокет - известная процедура: @data=<SOCK>. После закрытия сокета идет разбор принятых данных ресурса simulation.html: <html> <head> <title>Rates</title> </HEAD> <SPAN class="textP" style="font:bold 11px">My Forex Group</SPAN> <BODY leftmargin="2" topmargin="0"> <SPAN id="tRates"> <TABLE width='265' height='84' border='0'cellspacing='0' cellpadding='0'> <TR><td valign='top' background='/images/home/rateb.gif'> <table class='rate' width='260' border='0' cellspacing='1' cellpadding='1' height='2'> <TR><TD class='rLeft'>Rate</TD><TD class='rLeft'>Bid</TD><TD class='rLeft'>Ask</TD><TD class='rLeft'>Time</TD> </TR> <TR><TD class='rLeft' bgcolor='#41638A'>EURUSD</TD> <TD bgcolor=#CCD2DA><SPAN class='up'>0.9807</SPAN></TD> <TD bgcolor=#CCD2DA><SPAN class='up'>0.9812</SPAN></TD> <TD nowrap bgcolor=#CCD2DA><span class='rTime'>07/31/02 11:03:04</SPAN></TD> </TR> <TR><TD class='rLeft' bgcolor='#41638A'>USDJPY</TD> <TD><SPAN class='down'>119.65</SPAN></TD> <TD><SPAN class='down'>119.70</SPAN></TD> <TD nowrap><span class='rTime'>07/31/02 11:03:04</SPAN></TD> </TR> <TR><TD class='rLeft' bgcolor='#41638A'>GBPUSD</TD> <TD bgcolor=#CCD2DA><SPAN class='up'>1.5628</SPAN></TD> <TD bgcolor=#CCD2DA><SPAN class='up'>1.5633</SPAN></TD> <TD nowrap bgcolor=#CCD2DA><span class='rTime'>07/31/02 11:03:54</SPAN></TD> </TR><TR><TD class='rLeft' bgcolor='#41638A'>USDCHF</TD> <TD><SPAN class='up'>1.4815</SPAN></TD> <TD><SPAN class='up'>1.4820</SPAN></TD> <TD nowrap><span class='rTime'>07/31/02 11:03:52</SPAN></TD></TR></Table></TD> </TR></TABLE> </SPAN> </Body> </html> Для разбора HTML-кода используется образ EURUSD, который задается переменной $valuta. Данные относящиеся к спросу (bid) помещаются в переменную $iter3[3], а данные относящиеся к предложению (ask) в переменную $iter4[3]. В конце программы фиксируется местное время и заносится в переменную $my_time. И наконец создается стандартный вывод, эмулирующий метод POST протокола HTTP (необходимо для Flash). Теперь обратимся к Flash. Прежде всего создадим форму с тремя полями ввода - рис.5.Создадим два слоя и растянем их на 20 кадров. При скорости кадров 8 fps, полное время цикла из 20 кадров составит 2.5 секунды, т.е. этот промежуток времени будет равен половине времени обновления ресурса курса валют. Затем в оконе Text Options (рис.6) зададим имя текстовой переменной Variable равой my_bid.
Аналогичную процедуру выполним для создания имен двух других
текстовых переменных: my_ask и my-time. Для верхнего слоя (рис.5) откроем окно
Frame Actions и займемся программированием, т.е. запишем:
loadVariablesNum ("http://www.mycgi.com/cgi-bin/java_applet/finan.cgi", 0); Процедура loadVariablesNum загрузит CGI-ресурс, а полученные данные от CGI-скрипта разместит в текстовых переменных: my_bid, my_ask и my-time, соответственно. Заключение. Нет сомнения, что методы программирования, представленные выше, весьма перспективны и фактически применяются Web-программистами. Здесь сделана попытка систематизации CGI-скриптов, обеспечивающих вывод информации в клиентскую среду. Привлекательность технологий CGI/Perl/JavaScript/Java/Flash, на мой взгляд, обусловлена прежде всего их взаимодополняемостью, что и обеспечивает гибкость и оперативность вывода информации. Там где приоритет Perl не оспорим, пишем скрипты на Perl, в тех случаях где лучше подходит Java, целесообразно использовать апплеты и т.д. А как известно, технологические прорывы, возникает как правило именно на стыке моно-технологий. |
|
| ||||||||||||||||
|