4316

Web-программирование Лекции

Конспект

Информатика, кибернетика и программирование

Предмет Web-программирования. Программирование на стороне клиента и сервера. Инструменты и технологии программирования Предмет Web-программирования. Язык HTML. За последние годы разработки для Интернета эволюционировали от статических страниц до дин...

Русский

2012-11-16

2.21 MB

229 чел.

Предмет Web-программирования. Программирование на стороне клиента и сервера. Инструменты и технологии программирования

Предмет Web-программирования.

Язык HTML. За последние годы разработки для Интернета эволюционировали от статических страниц до динамических информационных систем. Некоторое время назад создание современных Web-страниц не требовало практически ничего, кроме совершенного владения языком разметки гипертекста (Hypertext Markup Language, HTML). HTML представляет собой простой язык обработки текстов; на этом языке при помощи набора тегов (tags) создается документ, который можно просматривать специальной программой просмотра Web (browser). Так, HTML-код из листинга 1.1 создает простую Web-страницу.

Листинг 1.1. Исходный код простой Web-страницы.

<HTML>

<HEAD><TITLE>My First Web Page</TITLE></HEAD>

<BODY BGCOLOR="WHITE">

<H2><CENTER>Добро пожаловать на мою первую Web-страничку! </CENTER></H2>

</BODY></HTML>

HTML — не язык программирования в том смысле, как C++ или Visual Basic; он больше напоминает средства форматирования документов с использованием управляющих последовательностей. Кодирование на HTML часто сравнивают с созданием документа в формате Microsoft Word путем набивки кодов форматирования прямо в Notepad. Очевидно, что функциональность этого крайне мала.

По многим причинам HTML — бедный язык с точки зрения программирования. Во-первых, возьмем гиперссылки (hyperlinks) — эти подчеркнутые и выделенные голубым цветом слова, которые Вы щелкаете, чтобы перейти к другой странице. Гиперссылка — это, по сути, облагороженный оператор перехода GOTO, обеспечивающий переход к жестко указанному месту приложения. Об операторе GOTO и его недостатках написана масса статей. Жестко закодированные ссылки порождают код, который очень трудно сопровождать, и если вы когда-либо писали HTML-код, то знаете, как трудно его повторно использовать и модифицировать.

Во-вторых, HTML не предоставляет никакой реальной возможности сохранять данные в процессе работы приложения. Да и вообще, в этом случае трудно даже говорить о приложении в Web. Когда каждая страница представляет собой лишенную состояния транзакцию с сервером, как вообще можно определить, где приложение начинается и где заканчивается? Сравните это с типичным клиент-серверным приложением, о начале работы которого сигнализирует двойной щелчок значка на рабочем столе, а о конце — выбор пункта Exit в меню File.

В-третьих, у HTML очень ограниченные возможности для взаимодействия. Стандартный HTML довольствуется статическими Web-страницами с текстом, рисунками и ссылками на другие страницы. Подобные узлы называют Желтыми Страницами WWW (World Wide Yellow Pages), так как их формат очень напоминает страницы телефонной книги.

Разумеется, HTML обеспечивает некоторую интерактивность при помощи встроенных элементов управления (intrinsic controls) — тех самых полей ввода, которые обычно присутствуют в HTML-формах. Простые формы можно создать, например, при помощи тегов <INPUT>. Тег <INPUT> допускает применение текстовых полей (text boxes), флажков (check boxes), переключателей (radio buttons) и кнопок (buttons). Листинг 1.2 определяет HTML-форму, которая содержит текстовые поля ввода для имени, номера телефона и адреса электронной почты.

Листинг 1.2. Код для HTML-формы.

<HTML><HEAD><TITLE>Simple HTML Form</TITLE></HEAD>

<B0DY BGCOLOR="WHITE">

<FORM>

<INPUT TYPE="TEXT" NAME="txtName">Имя<P>

<INPUT TYPE="TEXT" NAME="txtPhone">Телефон<Р>

<INPUT TYPE="TEXT" NAME="txtEMail">Адрес электронной почты<Р>

</FORM></BODY></HTML>

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

HTML представляет собой обычный текст, поэтому первоначально большинство разработчиков писали свои программы непосредственно в текстовых редакторах, таких как Notepad. Co временем ряд фирм предложили графические средства разработки, например, Microsoft FrontPage, дающие возможность создавать Web-страницы, не зная в явном виде HTML. Эти графические редакторы позволяют непосредственно макетировать Web-страницы без трудоемкой возни с тегами. К сожалению, мощь подобных графических редакторов оборачивается и серьезным их недостатком: у разработчиков создается впечатление, что им ни к чему изучать синтаксис и теги HTML, — а между тем трудно придумать что-нибудь более далекое от истины, чем это утверждение. Если вы даже ничего больше не вынесете из этого краткого введения в HTML, то запомните хотя бы это: чтобы быть настоящим Web-разработчиком, вы должны знать HTML. Навыки редактирования страницы непосредственно в виде исходного текста позволят вам добиться желаемого эффекта независимо от того, поддерживает ли его ваш любимый графический редактор.

Программирование на стороне клиента.

В своих первых попытках повысить интерактивность HTML Web-страниц разработчики обратились к сценариям (scripting), добавляя функциональность путем комбинирования языка программирования с HTML. В результате зачастую получается странный гибрид кода и тегов, что вынуждает разработчиков вернуться к текстовым редакторам. Был введен специальный тег <SCRIPT>, который определяет раздел кода на Web-странице. Код из листинга 1.3 при помощи VBScript создает пример, выводящий приветствие «Hello, World!».

Листинг 1.3. Код на VBScript, выводящий «Hello, World!».

<HTML><HEAD>

<META HTTP-EQUIV="Content-Type content=text/html, charset=windows-1251">

<TITLE>Yet Another Hello, World! Example</TITLE>

<SCRIPT LANGUAGE="VBScript”> <!--

Sub cmdClickMe_OnClick()

MsgBox "Hello, World!"

End Sub

-->

</SCRIPT>

</HEAD>

<BODY BGCOLOR= WHITE >

<FORM>

<INPUT TYPE= BUTTON NAME= cmdClickMe VALUE="Click Me!”>

</FORM></BODY></HTML>

VBScript представляет собой язык описания сценариев, в основе которого лежит Visual Basic for Applications (VBA), популярный язык, применяемый, например, в Microsoft Office 97. VBScript — это не полная версия VBA, а скорее его подмножество, которое сохраняет многие ключевые возможности VBA, но в то же время не реализует те, которые сделали бы его чересчур громоздким и небезопасным. Так, VBScript не поддерживает типы данных: все переменные объявляются как Variant.

Как и его старший брат, VBA, язык VBScript управляется событиями. Это означает, что написанный Вами код выполняется в ответ на событие (event), возникшее в результате взаимодействия пользователя с графическим интерфейсом (graphical user interface, GUI). В нашем случае GUI представляет собой Web-страницу. Так, в приведенном выше примере, когда пользователь взаимодействует с GUI, нажимая кнопку «Click Me!», это действие вызывает событие OnClick. Это событие, в свою очередь, обрабатывается кодом на VBScript, организованным в виде процедуры обработки события. Имена таких процедур имеют вид ИмяЭлементаУправления_ИмяСобытия, представляя собой произвольные комбинации из имен элементов управления и событий.

Хотя сценарии и представляют собой шаг вперед в развитии интерактивности, у них есть и определенные ограничения. Например, не все программы просмотра распознают и обрабатывают сценарии, а те, которые это делают, используют разные языки. Главным образом это касается Netscape Navigator, который не распознает VBScript, однако работает с JavaScript — языком описания сценариев, первоначально разработанным для Netscape Navigator. По функциональности JavaScript очень похож на VBScript, но по синтаксису эти языки сильно различаются. В отличие от VBScript, JavaScript не поддерживает концепцию процедур обработки событий. Все процедуры в JavaScript — это функции, вызываемые при помощи атрибутов событий, расположенных в HTML-теге. JavaScript-версия предыдущего примера на VBScript представлена в листинге 1.4.

Листинг 1.4. Код на JavaScript, выводящий «Hello, World!».

<HTML><HEAD>

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

<TITLE>JavaScript Hello, World! Example</TITLE>

<SCRIPT LANGUAGE="JavaScript"> <!--

function clickme() {

alert("Hello, World!");

return true; }

-->

</SCRIPT>

</HEAD><BODY BGCOLOR="WHITE">

<FORM>

<INPUT TYPE="BUTTON" NAME="cmdClickMe"

VALUE="ClickMe!" OnClick="var rtn=clickme();">

</FORM> </BODY> </HTML>

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

Как только к возможностям программ просмотра добавляются сценарии, возрастает сложность клиентской платформы. Очевидно также, что раз отсутствует универсальный язык описания сценариев, то теряются все разрекламированные преимущества платформенной независимости Web. Для многих Web-мастеров и разработчиков постоянная война между программами просмотра за преобладание на рынке создает необходимость поддерживать две версии Web-узла: для Microsoft Internet Explorer и для Netscape Navigator.

Компоненты ActiveX. По мере совершенствования технологии программ просмотра зависимость от платформы усилилась — она была привнесена компонентами ActiveX, технологией, основанной на СОМ — модели многокомпонентных объектов Microsoft (Component Object Model). Компоненты ActiveX варьируются от причудливых элементов управления, таких как движки (spinners), до невизуальных компонентов, обеспечивающих доступ к базам данных или электронной почте. Подобные компоненты делают страницы в Internet Explorer более функциональными и привлекательными, но практически бесполезными в среде, не поддерживающей ActiveX, например, в Netscape Navigator.

Компонент ActiveX добавляется в Web-страницу при помощи тега <OBJECT>, однозначно определяющего компонент для программы просмотра. Приведенный ниже код, используя тег <OBJECT>, помещает на Web-страницу элемент управления ActiveX — метку (label).

<OBJECT ID="Label1" WIDTH=291 HEIGHT=41 CLASSID="CLSID:978C9E23-D4B0-11CE-BF2D-00AA003F40D0"

CODEBASE="http://www.microsoft.com/activex/controls/FM20.DLL">

<PARAM NAME="ForeColor" VALUE="65408">

<PARAM NAME="VariousPropertyBits" VALUE="276824091">

<PARAM NAME="Caption" VALUE="Щелкни меня!">

<PARAM NAME="Size" VALUE="7691;1094">

<PARAM NAME="SpecialEffect" VALUE="1">

<PARAM NAME="FontEffects" VALUE="1073741827">

<PARAM NAME="FontHeight" VALUE="480">

<PARAM NAME="FontCharSet" VALUE="204">

<PARAM NAME="ParagraphAlign" VALUE="3">

<PARAM NAME="FontWeight" VALUE="700">

</OBJECT>

Значения GUID в любой операционной системе хранятся в реестре — централизованной базе данных, которая отвечает за поддержание информации о программных объектах, используемых приложениями. Когда Internet Explorer обнаруживает тег <OBJECT>, он обращается к реестру и ищет там GUID, совпадающий со значением атрибута CLASSID. Когда такой GUID найден, из реестра выбирается дополнительная информация, позволяющая отыскать файл, который соответствует данному элементу управления ActiveX.

В теге <OBJECT> можно выделить несколько ключевых составных частей, которые определяют, как именно компонент ActiveX будет размещен на странице. Атрибут ID задает имя элемента управления, посредством которого ко всем его свойствам, методам и событиям можно будет получить доступ из текста сценария.

CLASSID представляет собой буквенно-цифровой код, который однозначно идентифицирует данный компонент ActiveX среди всех остальных. Этот код, известный как глобально уникальный идентификатор (Globally Unique Identifier, GUID), не использует больше ни один компонент ActiveX. При помощи GUID Internet Explorer однозначно определяет требуемый компонент и создает его на странице. Если нужный элемент управления ActiveX на клиентской машине отсутствует, Internet Explorer обращается к атрибуту CODEBASE за информацией о том, где находится этот элемент на сервере. Следуя этой информации, файлы данного элемента управления загружаются с сервера, и элемент устанавливается на клиентской машине. Теперь Internet Explorer может свободно работать с ним.

Доступ к компонентам ActiveX посредством тега <OBJECT> не ограничивается элементами управления. Этот тег может активизировать произвольный компонент ActiveX, в том числе и те компоненты, которые можно написать на языках Visual Basic, C++ и Microsoft FoxPro. В сущности, вы легко можете расширить функциональность, доступную клиенту, написав свои собственные компоненты ActiveX и загрузив их в программу просмотра. Следует, правда, помнить, что Internet Explorer по умолчанию не загружает и не выполняет компоненты без цифровой подписи разработчика.

Окончательное обеспечение компонента данными происходит через тег <PARAM>, имеющий атрибуты NAME и VALUE, при помощи которых задаются начальные значения свойств данного компонента, когда он впервые создается на Web-странице. После того, как начальные значения установлены, значения свойств легко изменить во время выполнения из текста сценария.

<SCRIPT LANGUAGE="VBScript"><!--

Sub Label1_DblClick(Cancel)

Label1.Font.Weight=24

Label1.Caption="Щелкни снова!"

end sub

Sub Label1_Click()

Label1.AutoSize = false

Label1.Font.Weight = 30

Label1.Caption="Еще два раза!!!!!"

Label1.SpecialEffect=1

end sub

-->

</SCRIPT>

Документы ActiveX. Visual Basic, начиная с версии 5.0, позволяет, помимо элементов управления ActiveX, создавать документы ActiveX. Документы ActiveX представляют собой программные объекты, которые могут загружаться и работать внутри ActiveX-контейнера, такого как Internet Explorer. Документы ActiveX позволяют разработчикам на Visual Basic немедленно применить свой опыт работы на Visual Basic для создания приложений для Интернета. Что самое существенное, документы ActiveX предоставляют доступ к большей части ключевых возможностей Visual Basic в загружаемом формате.

Java. Не будем забывать и о Java! Этот язык очень быстро приобрел популярность, и его поддерживают как Internet Explorer, так и Netscape Navigator. Апплеты, разработанные на Java при помощи таких средств, как Microsoft J++, во многом напоминают компоненты ActiveX: это самодостаточные, загружаемые фрагменты Web-страницы. Так же, как и у компонентов ActiveX, у апплетов имеется свой особый тег — <APPLET>, который дает программе просмотра указание загрузить код на Java и выполнить его. Нижеследующий код исполняет апплет на Web-странице:

<APPLET CODE="DBLBULB.CLASS"  HEIGHT=35 WIDTH=26> </APPLET>

Атрибут CODE тега <APPLET> идентифицирует исходный код апплета Java практически так же, как атрибут CODEBASE определяет источник для компонента ActiveX. У апплетов могут также быть теги <PARAM>, задающие начальные значения. Во многих случаях апплеты представляют собой функциональные эквиваленты элементов управления ActiveX. Во всяком случае, языки описания сценариев могут обращаться к открытым функциям апплетов точно так же, как они обращаются к методам компонентов ActiveX.

Dynamic HTML. Да, различия между платформами не облегчают жизнь Web-разработчикам. В версии Internet Explorer 4.0 Microsoft добавила к клиентской функциональности еще одну особенность — Dynamic (динамический) HTML, который позволяет посредством сценариев программно изменять теги. Это необычайно мощное средство. Код из листинга 1.5 при помощи VBScript определяет, когда указатель мыши находится поверх какого-то участка текста Web-страницы, и изменяет размер и цвет текста.

Листинг 1.5. Dynamic HTML.

<HTML><HEAD>

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

<TITLE>Dynamic HTML</TITLE>

<SCRIPT LANGUAGE="VBScript">

Function MyFont_OnMouseOver()

MyFont.Color = "Red"

MyFont.Size = "5"

End Function

Function MyFont_OnMouseOut()

MyFont.Color = "Blue"

MyFont.Size = "4"

End Function

</SCRIPT> </HEAD>

<BODY BGCOLOR="WHITE">

<FONT ID="MyFont" FACE="ARIAL" SIZE="4" COLOR="BLUE">

Эй, укажи-ка сюда мышкой!

</BODY></HTML>

В Dynamic HTML определяется набор событий, которые можно ассоциировать с тегами HTML. Это расширяет парадигму VBScript управляемости событиями на все элементы Web-страницы — теги HTML, элементы управления ActiveX; даже программа просмотра сама по себе обладает определенными событиями. Если у вас еще сохранились сомнения в необходимости глубокого владения HTML для эффективного создания Web-страниц, то предыдущий пример должен вас убедить. В нем текст на VBScript динамически изменяет атрибуты COLOR и SIZE тега <FONT> при обнаружении определенных действий с мышью. Подобный код нельзя написать, не зная в точности, что представляет собой тег <FONT>, и не понимая смысла атрибутов COLOR и SIZE. Так что прощайте, графические редакторы!

Dynamic HTML заметно увеличивает мощность Web-клиента и его интерактивность, причем не только за счет динамического стиля манипулирования, но и другими средствами. Так, он умеет располагать элементы на Web-странице. Вы можете, например, изменить изображение, просто изменив атрибуты тега <IMG>. Для изменения содержимого страницы вы можете также добавлять или удалять теги. И наконец, Internet Explorer 4.0 поддерживает привязку данных (data binding) к полям формы. Это означает, что данные из базы данных на сервере могут быть напрямую связаны с полем формы в программе просмотра Web, и тем самым будут мгновенно редактироваться и обновляться. Все это делает Dynamic HTML мощным орудием, достойным вашего внимания. Но не забывайте одну важную вещь: в настоящее время Dynamic HTML доступен только для Internet Explorer.

Программирование на стороне сервера.

Еще одна эпохальная технология — это технология серверных сценариев, примером которой является Active Server Page (ASP). Эта технология позволяет создавать великолепные, не зависящие от платформ Web-страницы, которые можно просматривать любой программой просмотра. Или, если вы хотите максимально воспользоваться преимуществами зависящих от платформы технологий, таких как Dynamic HTML, то можете создавать ASP-страницы, которые могут общаться напрямую с Internet Explorer.

В своей основе ASP — это сценарий, исполняемый на сервере IIS. Этот код динамически выполняется при запросе страницы, а получившийся HTML-текст отправляется программе просмотра. Посмотрите, как код в листинге 1.6 использует ASP для создания шести последовательных строк текста, набранных все увеличивающимся шрифтом.

Листинг 1.6. Web-страница с ASP.

<SCRIPT LANGUAGE="VBSCRIPT"></SCRIPT>

<HTML><HEAD>

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

<TITLE> ASP Example</TITLE>

</HEAD>

<BODY BGCOLOR="WHITE">

<%For x = 1 to 6%>

<FONT FACE="ARIAL"  SIZE=<%=X%>>ActiveX - это круто!</FONT><P>

<%Next%>

</BODY> </HTML>

В тексте примера присутствует тег <SCRIPT>, хоть он и не обязателен, но обратите внимание, что внутри скобок появился знак процента. Этот синтаксис означает, что код должен быть выполнен на сервере, перед тем как страница будет отправлена клиенту. Обратите также внимание, что знаки процента окружают все фрагменты кода на данной странице, т. е. весь он выполняется до того, как программа просмотра получит страницу. Полученный HTML-текст выглядит так:

<HTML><HEAD>

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

<TITLE>ASP Example</TITLE></HEAD>

<BODY BGCOLOR="WHITE">

<FONT FACE="ARIAL" SIZE=1>ActiveX - это круто!</FONT>

<P><FONT FACE="ARIAL" SIZE=2>ActiveX - это круто!</FONT>

<P><FONT FACE="ARIAL" SIZE=3>ActiveX - это круто!</FONT>

<P><FONT FACE="ARIAL" SIZE=4>ActiveX - это круто!</FONT>

<P><FONT FACE="ARIAL" SIZE=5>ActiveX - это круто!</FONT>

<P><FONT FACE="ARIAL" SIZE=6>ActiveX - это круто!</FONT>

<P></BODY></HTML>

В получившемся HTML и скрывается красота ASP. Результирующая страница может содержать чистый HTML, понятный любой программе просмотра! Это делает ASP идеальным для приложений, которые должны выполняться в Интернете, где со страницей может работать любая программа просмотра. Однако ASP не ограничивается минимальным общим знаменателем, и вы можете добавлять в результирующую страницу клиентский сценарий, элементы управления ActiveX и Dynamic HTML. Таким образом, ASP гибки настолько, насколько Вы этого сами захотите.

К серверным языкам сценариев относятся также широко известные языки Perl и PHP. В отличие от ASP, они совместимы практически с любым Web-сервером, включая и IIS (PWS), которые по умолчанию поддерживают только ASP (IIS - сразу после установки, PWS - после установки свободно распространяемого модуля ASP.EXE). Существует, правда, Java-пакет Instant ASP фирмы ChillySoft, позволяющий программировать на ASP и под другими Web-серверами, но он коммерческий. В то же время весьма популярный свободно распространяемый кросс-платформенный web-сервер Apache имеет в комплекте интерпретаторы Perl и PHP. Эти интерпретаторы существуют в версиях для Windows и UNIX-совместимых ОС, поэтому также могут считаться платформно-независимыми. В общем же случае выбор серверного языка сценариев обусловлен конфигурацией web-сервера заказчика, поскольку, даже имея навыки конфигурирования web-серверов, порой невозможно добраться до сервера, на котором расположен сайт заказчика.

В рамках данного курса будут рассматриваться серверные языки сценариев ASP, Perl, PHP.

Инструменты и технологии программирования.

Минимальным набором инструментов web-программиста является текстовый редактор и браузер, под который оптимизируется сайт. При использовании серверных сценариев требуется и web-сервер, желательно такой же, как и у заказчика. Избегайте отладки сценариев на сервере клиента - ваши ошибки могут привести к его зависанию, и не всегда у вас есть права и возможность его перезагрузки! Лучше всего установить web-сервер на рабочей станции или домашнем компьютере и подключить к нему требуемый интерпретатор. Следует, правда, иметь в виду, что функциональные возможности web-серверов и интерпретаторов под разными ОС (Windows и UNIX) зачастую различны.

Что касается редактора, то можно использовать как стандартный «Блокнот» или встроенный редактор файлового менеджера FAR (желательно с плагином Colorer для подсветки тегов и операторов), так и какой-либо специализированный WYSIWYG (What You See Is What You Get) HTML-редактор. Однако среди их многообразия практически отсутствует такой, который поддерживает ОДНОВРЕМЕННО ВСЕ серверные языки сценариев, хотя поддержка клиентских языков, как правило, присутствует. Кроме того, зачастую эти редакторы преобразуют русские буквы в их коды, что существенно затрудняет последующее редактирование. Приведем небольшой перечень.

Несомненно, самым мощным, хоть и громоздким средством программирования на ASP является Microsoft Visual InterDev, входящий в комплект Microsoft Visual Studio. Будучи интегрирован со справочной системой MSDN, он позволяет быстро получить справку по любому оператору, функции или объекту. Возможен также предварительный просмотр как в окне редактора, так и в браузере по умолчанию, а также пошаговая отладка.

Для программирования на Perl, пожалуй, лучше всего подходит NetObject Fusion, обладающий обширной справкой по этому языку. Поддержкой PHP может похвастаться довольно большое количество редакторов: как небольшие EditPlus, HTML-Kit, PHPEd и UltraEdit, так и достаточно громоздкий HomeSite. Здесь не ставится цель делать их детальный обзор, желающие могут посетить раздел HTML-редакторов на http://tucows.com.

Что касается технологий программирования, то все современные языки сценариев поддерживают как классическую процедурную, так и объектно-ориентированную, хотя и в различной степени. В любом из перечисленных языков вы можете использовать встроенные и внешние объекты, их методы и свойства, но создать полноценный собственный класс можно лишь на С-подобных языках: Perl и PHP.

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

  •  ASP:
  •  Хилайер С., Мизик Д. Программирование Active Server Pages. - М: «Русская редакция», 1999. – 296 с.
  •  http://www.activeserverpages.ru
  •  http://www.oduv.ru/doc/asp/book/
  •  http://asp.ablogic.ru/
  •  Perl:
  •  Холзнер С. Perl: специальный справочник. – СПб.: «Питер». 2000. – 496 с.
  •  Шварц Р., Кристиансен Т. Изучаем Perl. - К.: «BHV», 2000. - 320 с.
  •  http://www.citforum.ru/internet/perl_tut/index.shtml
  •  http://www.citforum.ru/database/cnit/6.shtml
  •  http://reference.perl.com/
  •  http://www.webscript.ru/
  •  PHP:
  •  Ратшиллер Т.,  Геркен Т. PHP4: разработка Web-приложений. - СПб: Питер, 2001. - 384 с.
  •  Томсон Л., Веллинг Л. Разработка Web-приложений на PHP и MySQL. - К.: "ДиаСофт", 2001. - 672 с.
  •  http://www.citforum.ru/internet/php3/index.shtml
  •  http://php.spb.ru/
  •  http://www.php4all.ru/
  •  http://rusphp.chat.ru/


  1.  Программирование на стороне сервера. Протокол HTTP. CGI. Передача параметров серверу. Запоминание состояния. Меры безопасности. CGI и базы данных

Основные задачи.

Как и большинство акронимов, Common Gateway Interface (CGI - общий шлюзовой интерфейс) мало что говорит по сути. Интерфейс с чем? Где этот шлюз? О какой общности речь? Чтобы ответить на эти вопросы, вернемся назад и бросим взгляд на WWW в целом.

Тим Бернерс-Ли, физик, работавший в CERN, придумал Web в 1990 году, хотя план возник еще в 1988. Идея состояла в том, чтобы дать возможность легко и быстро обмениваться мультимедийными данными - текстом, изображениями и звуком - через Интернет. WWW состояла из трех основных частей: HTML, URL и HTTP. HTML - язык форматирования, используемый для представления содержания в Web. URL - это адрес, используемый для получения содержимого в формате HTML (или каком-либо ином) с веб-сервера. HTTP - это язык, который понятен веб-серверу и позволяет клиентам запрашивать у сервера документы.

Протокол HTTP.

Работа по протоколу HTTP происходит следующим образом: программа-клиент устанавливает TCP-соединение с сервером (стандартный номер порта-80) и выдает ему HTTP-запрос. Сервер обрабатывает этот запрос и выдает HTTP-ответ клиенту.

Структура HTTP-запроса. HTTP-запрос состоит из заголовка запроса и тела запроса, разделенных пустой строкой. Тело запроса может отсутствовать. Заголовок запроса состоит из главной (первой) строки запроса и последующих строк, уточняющих запрос в главной строке. Последующие строки также могут отсутствовать. Запрос в главной строке состоит из трех частей, разделенных пробелами:

  1.  Метод (иначе говоря, команда HTTP):
  •  GET - запрос документа. Наиболее часто употребляемый метод; в HTTP/0.9, говорят, он был единственным.
  •  HEAD - запрос заголовка документа. Отличается от GET тем, что выдается только заголовок запроса с информацией о документе. Сам документ не выдается.
  •  POST - этот метод применяется для передачи данных CGI-скриптам. Сами данные следуют в последующих строках запроса в виде параметров.
  •  PUT - разместить документ на сервере. Используется редко. Запрос с этим методом имеет тело, в котором передается сам документ.
  1.  Ресурс - это путь к определенному файлу на сервере, который клиент хочет получить (или разместить - для метода PUT). Если ресурс - просто какой-либо файл для считывания, сервер должен по этому запросу выдать его в теле ответа. Если же это путь к какому-либо CGI-скрипту, то сервер запускает скрипт и возвращает результат его выполнения. Кстати, благодаря такой унификации ресурсов для клиента практически безразлично, что он представляет собой на сервере.
  2.  Версия протокола - версия протокола HTTP, с которой работает клиентская программа.

Таким образом, простейший HTTP-запрос может выглядеть следующим образом:

GET / HTTP/1.0 - запрашивается корневой файл из корневой директории web-сервера.

Строки после главной строки запроса имеют следующий формат: Параметр: значение.

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

Перечислим некоторые наиболее употребительные параметры HTTP-запроса:

  •  Connection (соединение)- может принимать значения Keep-Alive и close.
  •  Keep-Alive ("оставить в живых") означает, что после выдачи данного документа соединение с сервером не разрывается, и можно выдавать еще запросы. Большинство браузеров работают именно в режиме Keep-Alive, так как он позволяет за одно соединение с сервером "скачать" html-страницу и рисунки к ней. Будучи однажды установленным, режим Keep-Alive сохраняется до первой ошибки или до явного указания в очередном запросе Connection: close.
  •  close ("закрыть") - соединение закрывается после ответа на данный запрос.
  •  User-Agent - значением является "кодовое обозначение" браузера, например: Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt) 
  •  Accept - список поддерживаемых браузером типов содержимого в порядке их предпочтения данным браузером, например, для IE5: Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/msword, application/vnd.ms-powerpoint, */*.  Значение этого параметра используется в основном CGI-скриптами для формирования ответа, адаптированного для данного браузера.
  •  Referer - URL, с которого перешли на этот ресурс.
  •  Host - имя хоста, с которого запрашивается ресурс. Полезно, если на сервере имеется несколько виртуальных серверов под одним IP-адресом. В этом случае имя виртуального сервера определяется по этому полю.
  •  Accept-Language - поддерживаемый язык. Имеет значение для сервера, который может выдавать один и тот же документ в разных языковых версиях.

Формат HTTP-ответа. Формат ответа очень похож на формат запроса: он также имеет заголовок и тело, разделенное пустой строкой. Заголовок также состоит из основной строки и строк параметров, но формат основной строки отличается от таковой в заголовке запроса. Основная строка запроса состоит из 3-х полей, разделенных пробелами:

  •  Версия протокола - аналогичен соответствующему параметру запроса.
  •  Код ошибки - кодовое обозначение "успешности" выполнения запроса. Код 200 означает "все нормально" (OK).
  •  Словесное описание ошибки - "расшифровка" предыдущего кода. Например, для 200 это OK, для 500 - Internal Server Error.

Наиболее употребительные параметры http-ответа:

  •  Connection - аналогичен соответствующему параметру запроса. Если сервер не поддерживает Keep-Alive (есть и такие), то значение Connection в ответе всегда close.
  •  Content-Type ("тип содержимого") - содержит обозначение типа содержимого ответа.
  •  В зависимости от значения Content-Type браузер воспринимает ответ как HTML-страницу, картинку gif или jpeg, как файл, который надо сохранить на диске, или как что-либо еще и предпринимает соответствующие действия. Значение Content-Type для браузера аналогично значению расширения файла для Windows.

Некоторые типы содержимого:

  •  text/html - текст в формате HTML (веб-страница);
  •  text/plain - простой текст (аналогичен "блокнотовскому");
  •  image/jpeg - картинка в формате JPEG;
  •  image/gif - то же, в формате GIF;
  •  application/octet-stream - поток "октетов" (т.е. просто байт) для записи на диск.
  •  Content-Length ("длина содержимого") - длина содержимого ответа в байтах.
  •  Last-Modified ("Модифицирован в последний раз") - дата последнего изменения документа.

Возможность пересылки через Интернет информации всех типов явилась революцией, но вскоре была обнаружена и другая возможность. Если можно переслать через Web любой текст, то почему нельзя переслать текст, созданный программой, а не взятый из готового файла? При этом открывается море возможностей. Простой пример: можно использовать программу, выводящую текущее время, так, чтобы читатель видел правильное время при каждом просмотре страницы. Несколько умных голов в National Center for Supercomputing Applications (Национальный центр разработки приложений для суперкомпьютеров - NCSA), которые создавали веб-сервер, такую возможность увидели, и вскоре появился CGI.

CGI - это набор правил, согласно которым программы на сервере могут через веб-сервер посылать данные клиентам. Спецификация CGI сопровождалась изменениями в HTML и HTTP, вводившими новую характеристику, известную как формы.

Если CGI позволяет программам посылать данные клиенту, то формы расширяют эту возможность, позволяя клиенту посылать данные для этой CGI-программы. Распространенные приложения CGI включают в себя:

  •  Динамический HTML. Целые сайты могут генерироваться одной CGI-программой.
  •  Поисковые механизмы, находящие документы с заданными пользователем словами.
  •  Гостевые книги и доски объявлений, в которые пользователи могут добавлять свои сообщения.
  •  Бланки заказов.
  •  Анкеты.
  •  Извлечение информации из размещенной на сервере базы данных.

Все они дают возможность соединения CGI с базой данных, что нас особенно интересует.

Спецификация CGI

Итак, что в точности представляет собой «набор правил», позволяющий CGI-программе, скажем, в Батавии, штат Иллинойс, обмениваться данными с веб-броузером во Внешней Монголии? Официальную спецификацию CGI наряду с массой других сведений о CGI можно найти на сервере NCSA по адресу http://hoohoo.ncsa.uiuc.edu/cgi/.

Есть четыре способа, которыми CGI передает данные между CGI-программой и веб-сервером, а следовательно, и клиентом Web:

  •  Переменные окружения.
  •  Командная строка.
  •  Стандартное устройство ввода.
  •  Стандартное устройство вывода.

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

Эти данные приводятся с прикидкой на сервер HTTP Apache. Apache - наиболее распространенный веб-сервер, работающий практически на любой платформе, включая Windows 9х и Windows NT. Однако они могут быть применимы ко всем HTTP-серверам, поддерживающим CGI. Некоторые патентованные серверы, например, от Microsoft и Netscape, могут иметь дополнительные функции или работать несколько иначе. Поскольку лицо Web продолжает изменяться с невероятной скоростью, стандарты все еще развиваются, и в будущем, несомненно, произойдут изменения. Однако, технология CGI представляется устоявшейся - расплачиваться за это приходится тем, что другие технологии, такие как апплеты, ее потеснили. Все CGI-программы, которые вы напишете, используя эти сведения, почти наверное смогут работать еще долгие годы на большинстве веб-серверов.

Когда CGI-программа вызывается посредством формы - наиболее распространенного интерфейса, броузер передает серверу длинную строку, в начале которой стоит путь к CGI-программе и ее имя. Затем следуют различные другие данные, которые называются информацией пути и передаются CGI-программе через переменную окружения PATH_INFO (табл. 2-1). После информации пути следует символ «?», а за ним - данные формы, которые посылаются серверу с помощью метода HTTP GET. Эти данные становятся доступными CGI-программе через переменную окружения QUERY_STRING. Любые данные, которые страница посылает с использованием метода HTTP POST, который используется чаще всего, будут переданы CGI-программе через стандартное устройство ввода. Типичная строка, которую может получить сервер от броузера, показана в табл. 3-1. Программа с именем formread в каталоге cgi-bin вызывается сервером с дополнительной информацией пути extra/information и данными запроса choice=help - по-видимому, как часть исходного URL. Наконец, данные самой формы (текст «CGI programming» в поле «keywords») пересылаются через метод HTTP POST.

Таблица 2-1. Части строки, переданной броузером серверу

http://www.myserver.com/cgi-bin

/formread

/extra/information

?choice=help

название программы

информация о пути

строка запроса

Переменные окружения

Когда сервер выполняет CGI-программу, то прежде всего передает ей некоторые данные для работы в виде переменных окружения. В спецификации официально определены семнадцать переменных, но неофициально используется значительно больше - с помощью описываемого ниже механизма, называемого HTTP_mechanism. CGI-программа имеет доступ к этим переменным так же, как и к любым переменным среды командного процессора при запуске из командной строки. В сценарии командного процессора, например, к переменной окружения FOO можно обращаться как $FOO; в Perl это обращение выглядит, как $ENV{'FOO'}; в С - getenv("FOO"); и т. д. В таблице 2-2 перечислены переменные, которые всегда устанавливаются сервером - хотя бы и в значение null. Помимо этих переменных данные, возвращаемые клиентом в заголовке запроса, присваиваются переменным вида HTTP_FOO, где FOO - имя заголовка. Например, большинство веб-броузеров включает данные о версии в заголовок с именем USER_AGENT . Ваша CGI-программа может получить эти данные из переменной HTTP_USER_AGENT .

Таблица 2-2. Переменные окружения CGI

Переменная окружения

Описание

CONTENT LENGTH

Длина данных, переданных методами POST или PUT, в байтах

CONTENT_TYPE

Тип MIME данных, присоединенных с помощью методов POST или PUT.

GATEWAY_INTERFACE

Номер версии спецификации CGI, поддерживаемой сервером.

PATH_INFO

Дополнительная информация пути, переданная клиентом. Например, для запроса http://www.myserver.com/test.cgi/this/is/a/ path?field=green значением переменной РАTH_INFO будет /this/is/a/path.

PATH_TRANSLATED

То же, что PATH_INFO, но сервер производит всю возможную  трансляцию, например, расширение имен типа «~account».

QUERY_STRING

Все данные, следующие за символом «?» в URL. Это также данные, передаваемые, когда REQUEST_METOD формы есть GEТ.

REMOTE_ADDR

IP-адрес клиента, делающего запрос.

REMOTE_HOST

Имя узла машины клиента, если оно доступно.

REMOTE_IDENT

Если веб-сервер и клиент поддерживают идентификацию типа identd, то это имя пользователя учетной записи, которая делает запрос.

REQUEST_METHOD

Метод, используемый клиентом для запроса. Для CGI-программ, которые мы собираемся создавать, это обычно будет POST или GET.

SCRIPT_NAME

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

SERVER_NAME

Имя узла - или IP-адрес, если имя недоступно, машины, на которой выполняется веб-сервер.

SERVER_PORT

Номер порта, используемого веб-сервером.

SERVER_PROTOCOL

Протокол, используемый клиентом для связи с сервером. В нашем случае этот протокол почти всегда HTTP.

SERVER_SOFTWARE

Данные о версии веб-сервера,  выполняющего CGI-программу.

Приведем пример сценария CGI на Perl, который выводит все переменные окружения, установленные сервером, а также все унаследованные переменные, установленные командным процессором, запустившим сервер.

Листинг 2.1. Вывод значений переменных окружения.

print "Content-Type: text/html\n\n

<HTML><HEAD><TITLE></title></head><BODY>\n

<p>Переменные окружения:<p>\n";

foreach (keys %ENV) {print "$_: $ENV{$_}<br>\n" }

print "</body></html>";

Все эти переменные могут быть использованы и даже изменены вашей CGI-программой. Однако эти изменения не затрагивают веб-сервер, запустивший программу.

Передача параметров серверу.

Командная строка. CGI допускает передачу CGI-программе аргументов в качестве параметров командной строки, которая редко используется. Редко используется она потому, что практические применения ее немногочисленны, и мы не будем останавливаться на ней подробно. Суть в том, что если переменная окружения QUERY_STRING не содержит символа « = », то CGI-программа будет выполняться с параметрами командной строки, взятыми из OUERY_STRING . Например, http://www.myseruer.com/cgi-bin/finger?root запустит finger root на www.myserver.com.

Параметры командной строки чаще всего используются вместе с тегом HTML <ISINDEX> . Тег <ISINDEX> обозначает миниформу, содержащуюся в одном теге. Обнаружив тег <ISINDEX> , броузер выводит окно, в которое пользователь может ввести текст запроса. При подаче запроса (нажатии пользователем клавиши «Enter»), броузер извлекает URL из тега <ISINDEX> и обращается к нему, передавая текст запроса в качестве командной строки.

Предшествующий finger можно написать так, что при вызове без аргументов он выведет HTML-страницу с тегом <ISINDEX> . После ввода пользователем адреса finger исполнится так же, как описано.

Стандартное устройство ввода. Как сказано выше, если клиент использует для передачи информации HTTP-методы PUT или POST, длина и тип MIME этих данных помещаются в переменные CONTENT_LENGTH и CONTENT_TYPE соответственно. Передаваемые данные посылаются на стандартное устройство ввода CGI-программы. Признак конца данных может не посылаться программе, поэтому она должна взять значение переменной CONTENT_LENGTH и прочесть столько байтов, сколько в ней указано. Это основной метод передачи данных из форм, и в наших примерах мы будем почти исключительно использовать только его.

Существуют многочисленные библиотеки почти для всех языков, которые выполняют важные задачи настройки CGI-программ, в том числе определяют, каким методом - GET или POST — переданы данные, и, соответственно, разбирают переменную окружения QUERY_STRING или читают с устройства стандартного ввода. Затем эти библиотеки помещают данные в легко доступные переменные. Обширный список ресурсов CGI для разных языков есть на Yahoo по адресу: http://www.yahoo.com/Computers_and_Internet/Internet/ World_Wide_Web/CGI_Common_Gateway_Interface/

Стандартное устройство вывода. Данные, посылаемые CGI-программой на стандартное устройство вывода, читаются веб-сервером и отправляются клиенту. Если имя сценария начинается с nph-, то данные посылаются прямо клиенту без вмешательства со стороны веб-сервера. В этом случае CGI-программа должна сформировать правильный заголовок HTTP, который будет понятен клиенту. В противном случае предоставьте веб-серверу сформировать HTTP-заголовок.

Даже если вы не используете nph-сценарий, серверу нужно дать одну директиву, которая сообщит ему сведения о вашей выдаче. Обычно это HTTP-заголовок Content-Type , но может быть и заголовок Location . За заголовком должна следовать пустая строка, то есть перевод строки или комбинация CR/LF.

Заголовок Content-Type сообщает серверу, какого типа данные выдает ваша CGI-программа. Если это страница HTML, то строка должна быть Content-Type: text/html. Заголовок Location сообщает серверу другой URL или другой путь на том же сервере, куда нужно направить клиента. Заголовок должен иметь следующий вид: Location: http:// www.myserver.com/another/place/.

После заголовков HTTP и пустой строки можно посылать собственно данные, выдаваемые вашей программой - страницу HTML, изображение, текст или что-либо еще. Среди CGI-программ, поставляемых с сервером Apache, есть nph-test-cgi и test-cgi, которые хорошо демонстрируют разницу между заголовками в стилях nph и не-nph, соответственно.

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

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

Запоминание состояния

Запоминание состояния является жизненно важным средством предоставления хорошего обслуживания вашим пользователям, а не только служит для борьбы с закоренелыми преступниками. Проблема вызвана тем, что HTTP является так называемым протоколом «без памяти». Это значит, что клиент посылает данные серверу, сервер возвращает данные клиенту, и дальше каждый идет своей дорогой. Сервер не сохраняет о клиенте данных, которые могут понадобиться в последующих операциях. Аналогично, нет уверенности, что клиент сохранит о совершенной операции какие-либо данные, которые можно будет использовать позднее. Это накладывает существенное ограничение на использование World Wide Web.

Рис. 2-1. Множественные запросы форм

Составление сценариев CGI при таком протоколе аналогично неспособности запоминать разговор. Всякий раз, разговаривая с кем-либо, независимо от того, как часто вы общались с ним раньше, вам приходится представляться и искать общую тему для разговора. Рисунок 3-1 показывает, что всякий раз, когда запрос достигает программы CGI, это совершенно новый экземпляр программы, не имеющий связи с предыдущим.

В части клиента с появлением Netscape Navigator появилось выглядящее наспех сделанным решение под названием cookies. Оно состоит в создании нового HTTP-заголовка, который можно пересылать туда-сюда между клиентом и сервером, похожего на заголовки Content-Type и Location. Броузер клиента, получив заголовок cookie, должен сохранить в cookie данные, а также имя домена, в котором действует этот соokie. После этого всякий раз при посещении URL в пределах указанного домена заголовок cookie должен возвращаться серверу для использования в CGI-программах на этом сервере.

Метод cookie используется в основном для хранения идентификатора пользователя. Сведения о посетителе можно сохранить в файле на сервере. Уникальный ID этого пользователя можно послать в качестве cookie броузеру пользователя, после чего при каждом посещении сайта пользователем броузер автоматически посылает серверу этот ID. Сервер передает ID программе CGI, которая открывает соответствующий файл и получает доступ ко всем данным о пользователе. Все это происходит незаметно для пользователя.

Несмотря на всю полезность этого метода, большинство больших сайтов не использует его в качестве единственного средства запоминания состояния. Для этого есть ряд причин. Во-первых, не все броузеры поддерживают cookie. До недавнего времени основной броузер для людей с недостаточным зрением (не говоря уже о людях с недостаточной скоростью подключения к сети) - Lynx - не поддерживал cookie. «Официально» он до сих пор их не поддерживает, хотя это делают некоторые его широко доступные «боковые ветви». Во-вторых, что более важно, cookie привязывают пользователя к определенной машине. Одним из великих достоинств Web является то, что она доступна из любой точки света. Независимо от того, где была создана или где хранится ваша веб-страница, ее можно показать с любой подключенной к Интернет машины. Однако если вы попытаетесь получить доступ к поддерживающему cookie сайту с чужой машины, все ваши персональные данные, поддерживавшиеся с помощью cookie, будут утрачены.

Многие сайты по-прежнему используют cookie для персонализации страниц пользователей, но большинство дополняет их традиционным интерфейсом в стиле «имя регистрации/пароль». Если доступ к сайту осуществляется из броузера, не поддерживающего cookie, то страница содержит форму, в которую пользователь вводит имя регистрации и пароль, присвоенные ему при первом посещении сайта. Обычно эта форма маленькая и скромная, чтобы не отпугивать большинство пользователей, не заинтересованных ни в какой персонализации, а просто желающих пройти дальше. После ввода пользователем в форму имени регистрации и пароля CGI находит файл с данными об этом пользователе, как если бы имя посылалось с cookie. Используя этот метод, пользователь может регистрироваться на персонализированном веб-сайте из любой точки света.

Помимо задач учета предпочтений пользователя и длительного хранения сведений о нем можно привести более тонкий пример запоминания состояния, который дают популярные поисковые машины. Осуществляя поиск с помощью таких служб, как AltaVista или Yahoo, вы обычно получаете значительно больше результатов, чем можно отобразить в удобном для чтения виде. Эта проблема решается тем, что показывается небольшое количество результатов - обычно 10 или 20 — и дается какое-либо средство перемещения для просмотра следующей группы результатов. Хотя обычному путешественнику по Web такое поведение кажется обычным и ожидаемым, действительная его реализация нетривиальна и требует запоминания состояния. Когда пользователь впервые делает запрос поисковому механизму, тот собирает все результаты, возможно, ограничиваясь некоторым предустановленным предельным количеством. Фокус состоит в том, чтобы выдавать эти результаты одновременно в небольшом количестве, запомнив при этом, что за пользователь запрашивал эти результаты и какую порцию он ожидает следующей. Оставляя в стороне сложности самого поискового механизма, мы встаем перед проблемой последовательного предоставления пользователю некоторой информации по одной странице.

Однако если вам требуется нечто большее, чем возможность просто листать файл, то полагаться на URL бывает обременительно. Облегчить эту трудность можно через использование формы HTML и включение данных о состоянии в теги <INPUT> типа HIDDEN . Этот метод с успехом используется на многих сайтах, позволяя делать ссылки между взаимосвязанными CGI-программами или расширяя возможности использования одной CGI-программы. Вместо ссылки на определенный объект, такой как начальная страница, данные URL могут указывать на автоматически генерируемый ID пользователя.

Так работают AltaVista и другие поисковые машины. При первом поиске генерируется ID пользователя, который скрыто включается в последующие URL. С этим ID связаны один или несколько файлов, содержащих результаты запроса. В URL включаются еще две величины: текущее положение в файле результатов и направление, в котором вы хотите перемещаться в нем дальше. Эти три значения - все, что нужно для работы мощных систем навигации больших поисковых машин.

Меры безопасности

При работе серверов Интернет, будь они серверами HTTP или другого рода, соблюдение мер безопасности является важнейшей заботой. Обмен данными между клиентом и сервером, совершаемый в рамках CGI, выдвигает ряд важных проблем, связанных с защитой данных. Сам протокол CGI достаточно защищен. CGI-программа получает данные от сервера через стандартное устройство ввода или переменные окружения, и оба эти метода являются безопасными. Но как только CGI-программа получает управление данными, ее действия ничем не ограничены. Плохо написанная CGI-программа может позволить злоумышленнику получить доступ к системе сервера. Рассмотрим следующий пример CGI-программы:

Листинг 2.2. Действующий CGI-интерфейс к команде finger.

#!/usr/bin/perl -w

use CGI;

my $output = new CGI;

my $username = $output->param('username');

print $output->header, $output->start_html('Finger Output'), "<pre>", `finger $username`, "</pre>", $output->end_html;

Если запустить программу просто как finger.cgi, она выведет список всех текущих пользователей на сервере. Если запустить ее как finger.cgi?username=fred, то она выведет информацию о пользователе «fred» на сервере. Можно даже запустить ее как finger. cgi?username=bob@foo.com для вывода информации об удаленном пользователе. Однако если запустить ее как finger.cgi?username=fred;mail hacker@bar.com</etc/passwd, могут произойти нежелательные вещи. Оператор обратный штрих «`` » в Perl порождает процесс оболочки и выполняет команду, возвращающую результат. В данной программе "finger $username" используется как простой способ выполнить команду finger и получить ее результат. Однако большинство командных процессоров позволяет объединять в одной строке несколько команд. Например, любой процессор, подобный процессору Борна, делает это с помощью символа «;». Поэтому `finger fred;mail hacker@bar.com</ etc/ passwd` запустит сначала команду finger, а затем команду mail hacker@bar.com</etc/passwd, которая может послать целиком файл паролей сервера нежелательному пользователю.

Одно из решений состоит в синтаксическом анализе поступивших от формы данных с целью поиска злонамеренного содержания. Можно, скажем, искать символ «;» и удалять все следующие за ним символы. Можно сделать такую атаку невозможной, используя альтернативные методы.

Другое важное соображение, касающееся безопасности, связано с правами пользователя. По умолчанию веб-сервер запускает программу CGI с правами того пользователя, который запустил сам сервер. Обычно это псевдопользователь, такой как «nobody», имеющий ограниченные права, поэтому у CGI-программы тоже мало прав. Обычно это хорошо, ибо, если злоумышленник сможет получить доступ к серверу через CGI-программу, ему не удастся причинить много вреда. Пример программы, крадущей пароли, показывает, что можно сделать, но фактический ущерб для системы, как правило, ограничен.

Однако работа в качестве пользователя с ограниченными правами ограничивает и возможности CGI. Если программе CGI нужно читать или записывать файлы, она может делать это только там, где у нее есть такое разрешение. CGI-программа должна иметь разрешение на чтение и запись в нужном ей каталоге, не говоря уже о самих файлах. Это можно сделать, создав каталог в качестве того же пользователя, что и сервер, с правами чтения и записи только для этого пользователя. Однако для такого пользователя, как «nobody», только root имеет подобную возможность. Если вы не суперпользователь, то вам придется общаться с администратором системы при каждом изменении в CGI.

Другой способ - сделать каталог свободным для чтения и записи, фактически сняв с него всякую защиту. Поскольку из внешнего мира получить доступ к этим файлам можно только через вашу программу, опасность не так велика, как может показаться. Однако если в программе обнаружится прореха, удаленный пользователь получит полный доступ ко всем файлам, в том числе возможность уничтожить их. Кроме того, законные пользователи, работающие на сервере, также получат возможность изменять эти файлы. Если вы собираетесь воспользоваться этим методом, то все пользователи сервера должны заслуживать доверия. Кроме того, используйте открытый каталог только для файлов, которые необходимы CGI-программе; иными словами, не подвергайте риску лишние файлы.

Что еще можно почитать. «CGI Programming on the World Wide Web» издательства O'Reilly and Associates охватывает материал от простых сценариев на разных языках до действительно поразительных трюков и ухищрений. Общедоступная информация имеется также в изобилии в WWW. Неплохо начать с CGI Made Really Easy (Действительно просто о CGI) по адресу http://www.jmarshall.com/easy/cgi/.

CGI и базы данных

С начала эпохи Интернет базы данных взаимодействовали с разработкой World Wide Web. На практике многие рассматривают Web просто как одну гигантскую базу данных мультимедийной информации.

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

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

Одна из причин подключения баз данных к Web регулярно дает о себе знать: значительная часть мировой информации уже находится в базах данных. Базы данных, существовавшие до возникновения Web, называются унаследованными (legacy) базами данных (в противоположность неподключенным к Web базам данных, созданным в недавнее время и которые следует назвать «дурной идеей»). Многие корпорации (и даже частные лица) стоят сейчас перед задачей обеспечения доступа к этим унаследованным базам данных через Web.

Как сказано выше, только ваше воображение может ограничить возможности связи между базами данных и Web. В настоящее время существуют тысячи уникальных и полезных баз данных, имеющие доступ из Web. Типы баз данных, действующих за пределами этих приложений, весьма различны. Некоторые из них используют CGI-программы в качестве интерфейса с сервером баз данных, таким как MySQL или используют коммерческие приложения для взаимодействия с популярными настольными базами данных, такими как Microsoft Access. А другие просто работают с плоскими текстовыми файлами, являющимися самыми простыми базами данных изо всех возможных.

С помощью этих трех типов баз данных можно разрабатывать полезные веб-сайты любого размера и степени сложности.


  1.  Доступ к базам данных. СУБД MySQL. Система безопасности. Утилиты. Язык SQL

Доступ к базам данных.

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

Самыми простыми базами данных изо всех возможных являются плоские текстовые файлы. Для доступа к ним можно использовать средства DHTML либо файловые операции, включенные в состав серверных языков сценариев. Для взаимодействия с популярными настольными базами данных, такими как хорошо известная вам СУБД Microsoft Access, используются свои технологии. Поскольку самыми популярными настольными операционными системами по-прежнему остаются представители семейства Microsoft Windows, средства доступа к настольным СУБД будут рассмотрены в теме, посвященной серверному языку сценариев Active Server Pages (ASP). Самыми же продвинутыми средствами доступа располагают серверы баз данных, такие как MS SQL или MySQL, особенностям которого и посвящена данная тема.

СУБД MySQL.

MySQL является, возможно, самым ярким программным проектом после выхода Linux. Сейчас она серьезный конкурент большим СУБД в области разработки баз данных малого и среднего масштаба. Особыми целями проектирования MySQL были скорость, надежность и простота использования. Чтобы достичь такой производительности, ее разработчик - шведская фирма ТсХ приняла решение сделать многопоточным внутренний механизм MySQL. Многопоточное приложение одновременно выполняет несколько задач - так, как если бы одновременно выполнялось несколько экземпляров приложения.

Сделав MySQL многопоточной, ТсХ дала пользователям много выгод. Каждое входящее соединение обрабатывается отдельным потоком, при этом еще один всегда выполняющийся поток управляет соединениями, поэтому клиентам не приходится ждать завершения выполнения запросов других клиентов. Одновременно может выполняться любое количество запросов. Пока какой-либо поток записывает данные в таблицу, все другие запросы, требующие доступа к этой таблице, просто ждут, пока она освободится. Клиент может выполнять все допустимые операции, не обращая внимания на другие одновременные соединения. Управляющий поток предотвращает одновременную запись какими-либо двумя потоками в одну и ту же таблицу. Такая архитектура более сложна, чем однопоточная. Однако выигрыш в скорости благодаря одновременному выполнению нескольких запросов значительно превосходит потери скорости, вызванные увеличением сложности.

Рис. 3.1. Клиент-серверная архитектура MySQL

Другое преимущество многопоточной обработки присуще всем многопоточным приложениям. Несмотря на то, что потоки совместно используют память процесса, они выполняются раздельно. Благодаря этому разделению выполнение потоков на многопроцессорных машинах может быть распределено по нескольким ЦП. На рис. 3-1 показана эта многопоточная природа сервера MySQL.

Помимо выигрыша в производительности, полученного благодаря многопоточности, MySQL поддерживает большое подмножество языка запросов SQL. MySQL поддерживает более десятка типов данных, а также функции SQL. Ваше приложение может получить доступ к этим функциям через команды ANSI SQL. MySQL фактически расширяет ANSI SQL несколькими новыми возможностями. В их числе новые функции (ENCRYPT, WEEKDAY, IF и другие), возможность инкрементирования полей (AUTO_INCREMENT и LAST_INSERT ID), а также возможность различать верхний и нижний регистры.

ТсХ намеренно опустила некоторые возможности SQL, встречающиеся в больших базах данных. Наиболее заметно отсутствие транзакций и встроенных процедур. ТсХ решила, что реализация этих возможностей нанесет слишком сильный удар по производительности. Однако ТсХ продолжает работу в этом направлении, но так, чтобы от потери производительности страдали только те пользователи, которым такие возможности действительно необходимы.

С 1996 года ТсХ использует MySQL в среде, где имеется более 40 баз данных, содержащих 10 000 таблиц. Из этих 10 000 более 500 таблиц имеют, в свою очередь, более 7 миллионов записей - около 100 Гбайт данных.

Система безопасности MySQL

Вам не только нужно иметь надежный доступ к своим данным, но и быть уверенным, что у других нет никакого доступа к ним. MySQL использует собственный сервер баз данных для обеспечения безопасности. При первоначальной установке MySQL создается база данных под названием «mysql». В этой базе есть пять таблиц: db, host, user, tables_priv, и columns_priv. Более новые версии MySQL создают также базу данных с названием func, но она не имеет отношения к безопасности. MySQL использует эти таблицы для определения того, кому что позволено делать. Таблица user содержит данные по безопасности, относящиеся к серверу в целом. Таблица host содержит права доступа к серверу для удаленных компьютеров. И наконец, db, tables_priv и соlumns_priv управляют доступом к отдельным базам данных, таблицам и колонкам.

Мы кратко рассмотрим все таблицы, поддерживающие безопасность в MySQL, а затем рассмотрим технологию их использования при обеспечении защиты ядром MySQL.

Таблица user. Таблица user имеет вид, показанный в Таблице 3.1:

Таблица 3.1. Таблица user

Поле

Тип

Null

Ключ

Значение по умолчанию

Host

char(60)

PRI

User

char(16)

PRI

Password

char(16)

Select_priv

enum('N','Y')

N

Insert_priv

enum('N','Y')

N

Update_priv

enum('N','Y')

N

Delete_priv

enum('N','Y')

N

Create_priv

enum('N','Y')

N

Drop_priv

enum('N','Y')

N

Reload_priv

enum('N','Y')

N

Shutdown_priv

enum('N','Y')

N

Process_priv

enum('N','Y')

N

File_priv

enum('N','Y')

N

Grant_priv

enum('N','Y')

N

References_priv

enum('N','Y')

N

Index_priv

enum('N','Y')

N

Alter_priv

enum('N','Y')

N

В колонках Host и User можно использовать символ «%», заменяющий произвольную последовательность символов. Например, имя узла «chem%lab» включает в себя «chembiolab», «chemtestlab» и т. д. Специальное имя пользователя «nobody» действует как одиночный «%», то есть охватывает всех пользователей, не упомянутых где-либо в другом месте. Ниже разъясняется смысл различных прав доступа:

Select_priv - Возможность выполнять команды SELECT.

Insert_priv - Возможность выполнять команды INSERT.

Update_priv - Возможность выполнять команды UPDATE.

Delete_priv - Возможность выполнять команды DELETE.

Create_priv - Возможность выполнять команды CREATE или создавать базы данных.

Drop_priv - Возможность выполнять команды DROP для удаления баз данных.

Reload_priv - Возможность обновлять информацию о доступе с помощью mysqladmin reload.

Shutdown_priv - Возможность останавливать сервер через mysqladmin shutdown.

Process_priv - Возможность управлять процессами сервера.

File_priv - Возможность читать и записывать файлы с помощью команд типа SELECT INTO OUTFILE и LOAD DATA INFILE.

Grant_priv - Возможность давать привилегии другим пользователям.

Index_priv - Возможность создавать и уничтожать индексы.

Alter_priv - Возможность выполнять команду ALTER TABLE.

В MySQL есть специальная функция, позволяющая скрыть пароли от любопытных глаз. Функция password() зашифровывает пароль. Ниже показано, как использовать функцию password() в процессе добавления пользователей в систему.

INSERT INTO user (Host, User, Password, Select_priv, Insert_priv, Update_priv, Delete_priv)

VALUES ('%', 'bob', password('mypass'), 'Y', 'Y', 'Y', 'Y')

INSERT INTO user (Host, User, Password, Select_priv)

VALUES ('athens.imaginary.com', 'jane', '', 'Y')

INSERT INTO user(Host, User, Password)

VALUES ('%', 'nobody', '')

INSERT INTO user (Host, User, Password, Select_priv, Insert_priv, Update_priv, Delete_priv)

VALUES ('athens.imaginary.com', 'nobody', password('thispass'), 'Y', 'Y', 'Y', 'Y')

И

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

Первый созданный нами пользователь, «bob», может подключаться к базе данных с любого компьютера и выполнять команды SELECT, INSERT, UPDATE и DELETE. Второй пользователь, «jane», может подключаться с «athens.imaginary.com», не имеет пароля и может выполнять только SELECT. Третий пользователь - «nobody» - с любой машины. Этот пользователь вообще ничего не может делать. Последний пользователь - «nobody» - с машины «athens.imaginary.com», он может выполнять SELECT, INSERT, UPDATE и DELETE, как и пользователь «bob».

Как MySQL производит сопоставление? Некоторое имя может соответствовать на деле нескольким записям. Например, «nobody @athens.imaginary.com» соответствует и «nobody@%», и «nobody@athens.imaginary.com». Прежде чем осуществлять поиск в таблице user, MySQL сортирует данные следующим образом:

  1.  Сначала ищется соответствие для узлов, не содержащих масок «%», при этом пустое поле Host трактуется как «%».
  2.  Для одного и того же узла сначала проверяется соответствие имен, не содержащих масок. Пустое поле User трактуется как содержащее «%».
  3.  Первое найденное соответствие считается окончательным.

В предыдущем примере пользователь сначала будет сравниваться с «nobody» из «athens.imaginary.com», поскольку «athens.imaginary.com» в порядке сортировки стоит выше «%». Поскольку имена компьютеров сортируются раньше имен пользователей, значения привилегий для компьютера, с которого вы подключаетесь, имеют приоритет перед любыми конкретными правами, которые у вас могут быть. Если таблица user содержит записи:

Host

User

%

jane

athens.imaginary.com

и jane подключается с «athens.imaginary.com», то MySQL будет использовать привилегии, данные «athens.imaginary.com».

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

Таблица 3.2. Таблица db

Поле

Тип

Null

Ключ

Значение по умолчанию

Host

char(60)

PRI

Db

char(32)

PRI

User

char(16)

PRI

Select_priv

enum('N','Y')

N

Insert_priv

enum('N','Y')

N

Update_priv

enum('N','Y')

N

Delete_priv

enum('N','Y')

N

Create_priv

enum('N','Y')

N

Drop_priv

enum('N','Y')

N

References_priv

enum('N','Y')

N

Index_priv

enum('N','Y')

N

Alter_priv

enum('N','Y')

N

Эта таблица во многом похожа на таблицу user. Основное отличие в том, что вместо колонки Password имеется колонка Db. Таблица управляет правами пользователей в отношении определенных баз данных. Поскольку привилегии, указанные в таблице user, относятся ко всему серверу в целом, права, присвоенные пользователю в таблице user, перекрывают права, присвоенные тому же пользователю в таблице. Например, если пользователю в таблице user разрешают доступ типа INSERT, это право действует в отношении всех баз данных, вне зависимости от того, что указано в таблице db.

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

Те же правила, которые действуют в отношении колонок User и Host в таблице user, действуют и в таблице db, но с некоторой особенностью. Пустое поле Host вынуждает MySQL найти запись, соответствующую имени узла пользователя, в таблице host. Если такой записи не найдено, MySQL отказывает в доступе. Если соответствие найдено, MySQL определяет права как пересечение прав, определяемых таблицами host и db. Иными словами, в обеих записях разрешение должно иметь значение «Y», иначе в доступе отказывается.

Таблица host. Таблица host служит особой цели. Ее структура показана в таблице 3.3:

Таблица 3.3. Таблица Host

Поле

Тип

Null

Ключ

Значение по умолчанию

Host

char(60)

PRI

Db

char(32)

PRI

Select_priv

enum('N','Y')

N

Insert_priv

enum('N','Y')

N

Update_priv

enum('N','Y')

N

Delete_priv

enum('N','Y')

N

Create_priv

enum('N','Y')

N

Drop_priv

enum('N','Y')

N

Grant_priv

enum('N','Y')

N

References_priv

enum('N','Y')

N

Index_priv

enum('N','Y')

N

Alter_priv

enum('N','Y')

N

Таблица host позволяет задать основные разрешения на межкомпьютерном уровне. При проверке прав доступа MySQL ищет в таблице db соответствие имени пользователя и его машине. Если он находит запись, соответствующую имени пользователя, поле host которой пусто, MySQL обращается к таблице host и использует пересечение обоих прав для определения окончательного права доступа. Если у вас есть группа серверов, которые вы считаете менее защищенными, то вы можете запретить для них все права записи. Если «bob» заходит с одной из таких машин, и его запись в таблице db содержит пустое поле host, ему будет запрещена операция записи, даже если она разрешена ему согласно таблице db.

Таблицы tables_priv и columns_priv. Эти две таблицы, по сути, уточняют данные, имеющиеся в таблице db. Именно, право на всякую операцию сначала проверяется по таблице db, затем по таблице tables_priv , затем по таблице columns_priv. Операция разрешается, если одна из них дает разрешение. С помощью этих таблиц можно сузить область действия разрешений до уровня таблиц и колонок. Управлять этими таблицами можно через команды SQL GRANT и REVOKE.

Последовательность контроля доступа. Соединим элементы системы защиты MySQL вместе и покажем, как можно ими пользоваться в реальных ситуациях. MySQL осуществляет контроль доступа в два этапа. Первый этап - подключение. Необходимо подключиться к серверу, прежде чем пытаться что-либо сделать.

При подключении проводятся две проверки. Сначала MySQL проверяет, есть ли в таблице user запись, соответствующая имени пользователя и машины, с которой он подключается. Поиск соответствия основывается на правилах, которые мы обсудили раньше. Если соответствие не найдено, в доступе отказывается. В случае, когда соответствующая запись найдена и имеет непустое поле Password , необходимо ввести правильный пароль. Неправильный пароль приводит к отклонению запроса на подключение.

Если соединение установлено, MySQL переходит к этапу верификации запроса. При этом сделанные вами запросы сопоставляются с вашими правами. Эти права MySQL проверяет по таблицам user, db, host, tables_pnv и columns_priv. Как только найдено соответствие в таблице user с положительным разрешением, команда немедленно выполняется. В противном случае MySQL продолжает поиск в следующих таблицах в указанном порядке:

  1.  db
  2.  tables_priv
  3.  columns_priv

Если таблица db содержит разрешение, дальнейшая проверка прекращается и выполняется команда. Если нет, то MySQL ищет соответствие в таблице tables_priv . Если это команда SELECT, объединяющая две таблицы, то пользователь должен иметь разрешения для обеих этих таблиц. Если хотя бы одна из записей отказывает в доступе или отсутствует, MySQL точно таким же способом проверяет все колонки в таблице columns_priv.


Изменение прав доступа. MySQL загружает таблицы доступа при запуске сервера. Преимуществом такого подхода по сравнению с динамическим обращением к таблицам является скорость. Отрицательная сторона состоит в том, что изменения, производимые в таблицах доступа MySQL, не сразу начинают действовать. Для того чтобы сервер увидел эти изменения, необходимо выполнить команду mysqladmin reload. Если таблицы изменяются с помощью SQL-команд GRANT или REVOKE, явно перегружать таблицы не требуется.

Утилиты MySQL

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

Утилиты командной строки (Command Line Tools):

Isamchk - Производит проверку файлов, содержащих данные базы. Эти файлы называются ISAM-файлами (ISAM — метод индексированного последовательного доступа). Эта утилита может устранить большую часть повреждений ISAM-файлов.

Isamlog - Читает создаваемые MySQL журналы, относящиеся к ISAM-файлам. Эти журналы можно использовать для воссоздания таблиц или воспроизведения изменений, внесенных в таблицы в течение некоторого промежутка времени.

mysql - Создает прямое подключение к серверу баз данных и позволяет вводить запросы непосредственно из приглашения MySQL.

mysqlaccess - Модифицирует таблицы прав доступа MySQL и отображает их в удобном для чтения виде. Использование этой утилиты - хороший способ изучения структуры таблиц доступа MySQL.

Mysqladmin - Осуществляет административные функции. С помощью этой утилиты можно добавлять и удалять целые базы данных, а также завершать работу сервера.

Mysqlbug - Составляет для ТсХ отчет о возникшей в MySQL неполадке. Отчет будет также послан в почтовый список рассылки MySQL, и армия добровольцев MySQL будет исследовать проблему.

Mysqldump - Записывает все содержимое таблицы, включая ее структуру, в файл в виде SQL-команд, которыми можно воссоздать таблицу. Выходные данные этой утилиты можно использовать для воссоздания таблицы в другой базе или на другом сервере. Синтаксис ее применения: mysqldump -u user -p dbname --tab=path, где path - путь для сохранения файлов.

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

Mysqlshow - Выводит на экран структуру баз данных, имеющихся на сервере, и таблицы, из которых они состоят.

Утилиты сторонних разработчиков. Ни один поставщик или разработчик не может самостоятельно предоставить все необходимые для программного продукта средства поддержки. За самым свежим списком обратитесь на домашнюю страницу MySQL: http://www.mysql.com/Contrib.

Утилиты преобразования баз данных:

access_to_mysql - Преобразует базы данных Microsoft Access в таблицы MySQL. Включается в Access в виде функции, позволяющей сохранять таблицы в формате, позволяющем экспортировать их в MySQL.

dbf2mysql - Конвертирует файлы dBASE (DBF) в таблицы MySQL. Хотя dBASE утратил популярность, формат DBF установился как наиболее распространенный для передачи данных между различными приложениями баз данных. Все главные настольные приложения баз данных могут читать и писать DBF-файлы. Это приложение полезно для экспорта/импорта данных в коммерческие настольные базы данных.

Exportsql/Importsql - Конвертирует базы данных Microsoft Access в MySQL и обратно. Эти утилиты являются функциями Access, которые можно использовать для экспорта таблиц Access в формате, пригодном для чтения MySQL. С их помощью можно также преобразовывать SQL-выход MySQL в вид, пригодный для чтения Access.

Интерфейсы CGI:

PHP - Создает HTML-страницы с использованием специальных тегов, распознаваемых анализатором РНР. РНР имеет интерфейсы к большинству основных баз данных, включая MySQL и mSQL.

Mysql-webadmin - Осуществляет веб-администрирование баз данных MySQL. Используя это средство, можно просматривать таблицы и изменять их содержимое с помощью HTML-форм.

Mysqladm - Осуществляет веб-администрирование баз данных MySQL. Эта CGI-программа позволяет просматривать таблицы через WWW, добавлять таблицы и изменять их содержимое.

www-sql - Создает HTML-страницы из таблиц баз данных MySQL. Эта программа осуществляет разбор HTML-страниц в поисках специальных тегов и использует извлеченные данные для выполнения команд SQL на сервере MySQL.

Клиентские приложения:

Mysqlwinadmn - Позволяет администрировать MySQL из Windows. С помощью этого средства можно выполнять функции mysqladmin из графического интерфейса.

Xmysql - Обеспечивает полный доступ к таблицам баз данных MySQL для клиента X Window System. Поддерживает групповые вставки и удаления.

Xmysqladmin - Позволяет осуществлять администрирование MySQL из X Window System. Это инструмент для графического интерфейса, позволяющий создавать и удалять базы данных и управлять таблицами. С его помощью можно также проверять, запущен ли сервер, перегружать таблицы доступа и управлять потоками.

Интерфейсы программирования:

MyODBC - Реализует ODBC API к MySQL в Windows.

mm.mysql.jdbc - Реализует стандартный API JDBC (Java Database Connectivity -доступ к базам данных из Java).

TwzJdbcForMysql - Реализация JDBC API для Java.

Язык SQL.

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

SQL является разновидностью «естественного языка». Иными словами, команда SQL должна читаться, по крайней мере на первый взгляд, как предложение английского языка. У такого подхода есть как преимущества, так и недостатки, но факт заключается в том, что этот язык очень непохож на традиционные языки программирования, такие как С, Java или Perl. Здесь мы рассмотрим язык SQL, как он реализован в MySQL.

Основы SQL. SQL «структурирован» в том отношении, что он следует определенному набору правил. Компьютерной программе легко разобрать на части сформулированный запрос SQL. Действительно, в книге издательства O'Reilly «lex & уасс», написанной Дж. Ливайном, Т. Мэйсоном и Д. Брауном (John Levine, Tony Mason, Doug Brown), реализована грамматика SQL для демонстрации процесса создания программы, интерпретирующей язык! Запрос (query) - это полностью заданная команда, посылаемая серверу баз данных, который выполняет запрошенное действие. Ниже приведен пример SQL-запроса:

SELECT name FROM people WHERE name LIKE Stac%'

Как можно видеть, это предложение выглядит почти как фраза на ломаном английском языке: «Выбрать имена из список люди, где имена похожи на Stac». SQL в очень незначительной мере использует форматирование и специальные символы, обычно ассоциируемые с компьютерными языками. Сравните, к примеру, «$++;($*++/$!);$&$",,;$!» в Perl и «SELECT value FROM table» в SQL.

История SQL. В IBM изобрели SQL в начале 1970-х, вскоре после введения д-ром Е. Ф. Коддом (Е. F. Codd) понятия реляционной базы данных. С самого начала SQL был легким в изучении, но мощным языком. Он напоминает естественный язык, такой как английский, и поэтому не утомляет тех, кто не является техническим специалистом.

SQL действительно был настолько популярен среди пользователей, для которых предназначался, что в 1980-х компания Oracle выпустила первую в мире общедоступную коммерческую SQL-систему. Oracle SQL был хитом сезона и породил вокруг SQL целую индустрию. Sybase, Informix, Microsoft и ряд других компаний вышли на рынок с собственными разработками реляционных систем управления базами данных (РСУБД), основанных на SQL.

В то время когда Oracle и ее конкуренты вышли на сцену, SQL был новинкой, и для него не существовало стандартов. Лишь в 1989 году комиссия по стандартам ANSI выпустила первый общедоступный стандарт SQL. Сегодня его называют SQL89. К несчастью, этот новый стандарт не слишком углублялся в определение технической структуры языка. Поэтому, хотя различные коммерческие реализации языка SQL сближались, различия в синтаксисе делали задачу перехода с одной реализации языка на другую нетривиальной. Только в 1992 году стандарт ANSI SQL вступил в свои права.

Стандарт 1992 года обозначают как SQL92 или SQL2. Стандарт SQL2 включил в себя максимально возможное количество расширений, добавленных в коммерческих реализациях языка. Большинство инструментов, работающих с различными базами данных, основывается на SQL2 как на способе взаимодействия с реляционными базами данных. Однако, из-за очень большой широты стандарта SQL2, реляционные базы, реализующие полный стандарт, очень сложные и ресурсоемкие.

SQL2 - не последнее слово в стандартах SQL. В связи с ростом популярности объектно-ориентированных СУБД (ООСУБД) и объектно-реляционных СУБД (ОРСУБД) возрастает давление с целью принятия объектно-ориентированного доступа к базам данных в качестве стандарта SQL. Ответом на эту проблему должен послужить SQL3. Он не является пока официальным стандартом, но в настоящее время вполне определился и может стать официальным стандартом.

С появлением MySQL проявился новый подход к разработке серверов баз данных. Вместо создания очередной гигантской РСУБД с риском не предложить ничего нового в сравнении с «большими парнями», были предложены небольшие и быстрые реализации наиболее часто используемых функций SQL.

Архитектура SQL. SQL больше напоминает естественный человеческий, а не компьютерный язык. SQL добивается этого сходства благодаря четкой императивной структуре. Во многом походя на предложение английского языка, отдельные команды SQL, называемые запросами, могут быть разбиты на части речи. Рассмотрим примеры:

CREATE

TABLE

people (name CHAR(10))

глагол

дополнение

расширенное определение

INSERT

INTO people

VALUES('me')

глагол

косвенное дополнение

прямое дополнение

SELECT

name

FROM people

WHERE name LIKE '%e'

глагол

прямое дополнение

косвенное дополнение

придаточное предложение

Большинство реализаций SQL, включая MySQL, нечувствительны к регистру: неважно, в каком регистре вы вводите ключевые слова SQL, если орфография верна. Например, CREATE из верхнего примера можно записать и так:

cREatE ТАblЕ people (name cHaR(10))

Нечувствительность к регистру относится только к ключевым словам SQL. В MySQL имена баз данных, таблиц и колонок к регистру чувствительны. Но это характерно не для всех СУБД. Поэтому, если вы пишете приложение, которое должно работать с любыми СУБД, не следует использовать имена, различающиеся одним только регистром.

Первый элемент SQL-запроса - всегда глагол. Глагол выражает действие, которое должно выполнить ядро базы данных. Хотя остальная часть команды зависит от глагола, она всегда следует общему формату: указывается имя объекта, над которым осуществляется действие, а затем описываются используемые при действии данные. Например, в запросе CREATE TABLE people (char(10)) используется глагол CREATE, за которым следует дополнение (объект) TABLE. Оставшаяся часть запроса описывает таблицу, которую нужно создать.

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

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

Создание и удаление таблиц. Успешно установив MySQL, вы можете приступить к созданию своей первой таблицы. Таблица, структурированное вместилище данных, является основным понятием реляционных баз. Прежде чем начать вводить данные в таблицу, вы должны определить ее структуру. Рассмотрим следующую раскладку:

people

name

char(10) not null

address

text(100)

id

int

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

Общий синтаксис для создания таблиц следующий:

CREATE TABLE table_name (column_name1 type [modifiers]

[,  column_name2 type [modifiers]] )

Какие идентификаторы - имена таблиц и колонок - являются допустимыми, зависит от конкретной СУБД. В MySQL длина идентификатора может быть до 64 символов, допустим символ «$», и первым символом может быть цифра. Более важно, однако, что MySQL допускает использование любых символов из установленного в системе локального набора. Для хорошей переносимости SQL избегайте имен, начинающихся не с допустимой буквы.

Колонка - это отдельная единица данных в таблице. В таблице может содержаться произвольное число колонок, но использование больших таблиц бывает неэффективным. Создав правильно нормализованные таблицы, можно объединять их («join») для осуществления поиска в данных, размещенных в нескольких таблицах. Механику объединения таблиц мы обсудим позднее.

Как и бывает в жизни, разрушить легче, чем создать. Следующая команда удаляет таблицу:

DROP TABLE table_name

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

В MySQL можно одной командой удалить несколько таблиц, разделяя их имена запятыми. Например, DROP TABLE people, animals, plants удалит эти три таблицы. Можно также использовать модификатор IF EXISTS для подавления ошибки в случае отсутствия удаляемой таблицы. Этот модификатор полезен в больших сценариях, предназначенных для создания базы данных и всех ее таблиц. Прежде чем создавать таблицу, выполните команду DROP TABLE table_name IF EXISTS.

Типы данных в SQL. Каждая колонка таблицы имеет тип. Типы данных SQL сходны с типами данных традиционных языков программирования. В то время как во многих языках определен самый минимум типов, необходимых для работы, в SQL для удобства пользователей определены дополнительные типы, такие как MONEY и DATE. Данные типа MONEY можно было бы хранить и как один из основных числовых типов данных, однако использование типа, специально учитывающего особенности денежных расчетов, повышает легкость использования SQL.

Таблица 3.4. Наиболее употребительные типы данных, поддерживаемые MySQL

Тип данных

Описание

INT

Целое число, может быть со знаком или без знака.

REAL

Число с плавающей запятой. Этот тип допускает больший диапазон значений, чем INT, но не обладает его точностью.

CHAR(length)

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

TEXT(length)

Символьная величина переменной длины. TEXT - лишь один из нескольких типов данных переменного размера.

DATE

Стандартное значение даты.

TIME

Стандартное значение времени. Этот тип используется для хранения времени дня безотносительно какой-либо даты. При использовании вместе с датой  позволяет хранить конкретную дату и время. Есть дополнительный тип DATETIME для совместного хранения даты и времени в одном поле.

MySQL поддерживает атрибут UNSIGNED для всех числовых типов. Этот модификатор позволяет вводить в колонку только положительные (беззнаковые) числа. Беззнаковые поля имеют верхний предел значений вдвое больший, чем у соответствующих знаковых типов. Беззнаковый TINYINT - однобайтовый числовой тип MySQL - имеет диапазон от 0 до 255, а не от -127 до 127, как у своего знакового аналога.

MySQL имеет больше типов, чем перечислено выше. Однако на практике в основном используются перечисленные типы. Размер данных, которые вы собираетесь хранить, играет гораздо большую роль при разработке таблиц MySQL.

Числовые типы данных. Прежде чем создавать таблицу, вы должны хорошо представить себе, какого рода данные вы будете в ней хранить. Помимо очевидного решения о том, будут это числовые или символьные данные, следует выяснить примерный размер хранимых данных. Если это числовое поле, то каким окажется максимальное значение? Может ли оно измениться в будущем? Если минимальное значение всегда положительно, следует рассмотреть использование беззнакового типа. Всегда следует выбирать самый маленький числовой тип, способный хранить самое большое мыслимое значение. Если бы требовалось хранить в поле численность населения штата, следовало бы выбрать беззнаковый INT. В штате не может быть отрицательной численности населения, а чтобы беззнаковое поле типа INT не могло вместить число, представляющее его население, численность населения штата должна примерно равняться численности населения всей Земли.

Символьные типы. С символьными типами работать немного труднее. Вы должны подумать не только о максимальной и минимальной длине строки, но также о среднем размере, частоте отклонения от него и необходимости в индексировании. В данном контексте мы называем индексом поле или группу полей, в которых вы собираетесь осуществлять поиск — в основном, в предложении WHERE. Индексирование, однако, значительно сложнее, чем такое упрощенное определение, и мы займемся им далее. Здесь важно лишь отметить, что индексирование по символьным полям происходит значительно быстрее, если они имеют фиксированную длину. Если длина строк не слишком колеблется или, что еще лучше, постоянна, то, вероятно, лучше выбрать для поля тип CHAR. Хороший кандидат на тип CHAR - код страны. Стандартом ISO определены двух символьные коды для всех стран. CHAR(2) будет правильным выбором для данного поля.

Чтобы подходить для типа CHAR, поле необязательно должно быть фиксированной длины, но длина не должна сильно колебаться. Телефонные номера, к примеру, можно смело хранить в поле CHAR(13), хотя длина номеров различна в разных странах. Просто различие не столь велико, поэтому нет смысла делать поле для номера телефона переменным по длине. В отношении поля типа CHAR важно помнить, что, вне зависимости от реальной длины хранимой строки, в поле будет ровно столько символов, сколько указано в его размере - не больше и не меньше. Разность в длине между размером сохраняемого текста и размером поля заполняется пробелами. Не стоит беспокоиться по поводу нескольких лишних символов при хранении телефонных номеров, но не хотелось бы тратить много места в некоторых других случаях. Для этого существуют текстовые поля переменной длины.

Хороший пример поля, для которого требуется тип данных с переменной длиной, дает URL Интернет. По большей части адреса Web занимают сравнительно немного места - http://www.ora.com, http://www.hughes.com.au, http://www.mysql.com - и не представляют проблемы. Иногда, однако, можно наткнуться на адреса подобного вида:

http://www.winespectator.com/Wine/Spectator/notes\5527293926834323221480431354?XvlI=&Xr5=&Xvl =&type-region-search-code=&Xa14=flora+springs&Xv4=.

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

Поля переменной длины. Преимуществом текстовых полей переменной длины является то, что они используют ровно столько места, сколько необходимо для хранения отдельной величины. Например, поле типа VARCHAR(255) , в котором хранится строка «hello, world», занимает только двенадцать байтов (по одному байту на каждый символ плюс еще один байт для хранения длины). В отличие от стандарта ANSI, в MySQL поля типа VARCHAR не дополняются пробелами. Перед записью из строки удаляются лишние пробелы.

Сохранить строки, длина которых больше, чем заданный размер поля, нельзя. В поле VARCHAR(4) можно сохранить строку не длиннее 4 символов. Если вы попытаетесь сохранить строку «happy birthday», MySQL сократит ее до «happ». Недостатком подхода MySQL к хранению полей переменной длины является то, что не существует способа сохранить необычную строку, длина которой превосходит заданное вами значение. В таблице 3.5 показан размер пространства, необходимого для хранения 144-символьного URL, продемонстрированного выше, и обычного, 30-символьного URL.

Таблица 3.5. Пространство памяти, необходимое для различных символьных типов MySQL

Тип данных

Пространство для хранения строки из 144 символов

Пространство для хранения строки из 30 символов

Максимальная длина строки

СНАR(150)

150

150

255

VARCHAR(150)

145

31

255

TINYTEXT(150)

145

31

255

ТЕХТ(150)

146

32

65535

MEDIUMTEXT(150)

147

33

16777215

LONGTEXT(150)

148

34

4294967295

Если через годы работы со своей базой данных вы обнаружите, что мир изменился, и поле, уютно чувствовавшее себя в типе VARCHAR(25), должно теперь вмещать строки длиной 30 символов, не все потеряно. В MySQL есть команда ALTER TABLE , позволяющая переопределить размер поля без потери данных.

ALTER TABLE mytable MODIFY mycolumn LONGTEXT

Двоичные типы данных. В MySQL есть целый ряд двоичных типов данных, соответствующих своим символьным аналогам. Двоичными типами, поддерживаемыми MySQL, являются CHAR BINARY, VARCHAR BINARY, TINYBLOB, BLOB, MEDIUMBLOB и LONGBLOB. Практическое отличие между символьными типами и их двоичными аналогами основано на принципе кодировки. Двоичные данные просто являются куском данных, которые MySQL не пытается интерпретировать. Напротив, символьные данные предполагаются представляющими текстовые данные из используемых человеком алфавитов. Поэтому они кодируются и сортируются, основываясь на правилах, соответствующих рассматриваемому набору символов. Двоичные же данные MySQL сортирует в порядке ASCII без учета регистра.

Перечисления и множества. MySQL предоставляет еще два особых типа данных. Тип ENUM позволяет при создании таблицы указать список возможных значений некоторого поля. Например, если бы у вас была колонка с именем «фрукт», в которую вы разрешили бы помещать только значения «яблоко», «апельсин», «киви» и «банан», ей следовало бы присвоить тип ENUM:

CREATE TABLE meal(meal_id INT NOT NULL PRIMARY KEY,

фрукт ENUM('яблоко', 'апельсин', 'киви', 'банан'))

При записи значения в эту колонку оно должно быть одним из перечисленных фруктов. Поскольку MySQL заранее знает, какие значения допустимы для этой колонки, она может абстрагировать их каким-либо числовым типом. Иными словами, вместо того, чтобы хранить в колонке «яблоко» в виде строки, MySQL заменяет его однобайтовым числом, а «яблоко» вы видите, когда обращаетесь к таблице или выводите из нее результаты.

Тип MySQL SET позволяет одновременно хранить в поле несколько значений.

Другие типы данных. Любые мыслимые данные можно хранить с помощью числовых или символьных типов. В принципе, даже числа можно хранить в символьном виде. Однако то, что это можно сделать, не означает, что это нужно делать. Рассмотрим, к примеру, как хранить в базе данных денежные суммы. Можно делать это, используя INT или REAL. Хотя интуитивно REAL может показаться более подходящим - в конце концов, в денежных суммах нужны десятичные знаки, - на самом деле более правильно использовать INT. В полях, содержащих значения с плавающей запятой, таких как REAL, часто невозможно найти число с точным десятичным значением. Например, если вы вводите число 0.43, которое должно представлять сумму $0.43, MySQL может записать его как 0.42999998. Это небольшое отличие может вызвать проблемы при совершении большого числа математических операций.

MySQL предоставляет специальные типы данных для таких денежных сумм. Одним из них является тип MONEY, другим - DATE.

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

Индексы способствуют хранению данных в базе, таким образом, который позволяет осуществлять быстрый поиск. К несчастью, ради скорости поиска приходится жертвовать дисковым пространством и скоростью изменения данных. Наиболее эффективно создавать индексы для тех колонок, в которых вы чаще всего собираетесь осуществлять поиск. MySQL поддерживает следующий синтаксис для создания индексов:

CREATE INDEX index_name ON tablename (column1, column2, columnN)

MySQL позволяет также создавать индекс одновременно с созданием таблицы, используя следующий синтаксис:

CREATE TABLE materials (id INT NOT NULL,

name CHAR(50) NOT NULL,

resistance INT,

melting_pt REAL,

INDEX index1 (id, name),

UNIQUE INDEX index2 (name))

В этом примере для таблицы создается два индекса. Первый индекс index1 состоит из полей id и name. Второй индекс включает в себя только поле name и указывает, что значения поля name должны быть уникальными. Если вы попытаетесь вставить в поле name значение, которое уже есть в этом поле в какой-либо строке, операция не будет осуществлена. Все поля, указанные в уникальном индексе, должны быть объявлены как NOT NULL .

Хотя мы создали отдельный индекс для поля name, отдельно для поля id мы не создавали индекса. Если такой индекс нам понадобится, создавать его не нужно - он уже есть. Когда индекс содержит более одной колонки (например, name, rank, и serial_number), MySQL читает колонки в порядке слева направо. Благодаря используемой MySQL структуре индекса всякое подмножество колонок с левого края автоматически становится индексом внутри «главного» индекса. Например, когда вы создаете индекс name, rank, serial_number, создаются также «свободные» индексы name и name вместе с rank. Однако индексы rank или name и serial_number не создаются, если не потребовать этого явно.

MySQL поддерживает также семантику ANSI SQL для особого индекса, называемого первичным ключом. В MySQL первичный ключ - это уникальный индекс с именем PRIMARY. Назначив при создании таблицы колонку первичным ключом, вы делаете ее уникальным индексом, который будет поддерживать объединения таблиц. В следующем примере создается таблица cities с первичным ключом id.

CREATE TABLE cities (id INT NOT NULL PRIMARY KEY,

name VARCHAR(100),

pop MEDIUMINT,

founded DATE)

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

Последовательности и автоинкрементирование. Лучше всего, когда первичный ключ не имеет в таблице никакого иного значения, кроме значения первичного ключа. Для достижения этого лучшим способом является создание числового первичного ключа, значение которого увеличивается при добавлении в таблицу новой строки. Если вернуться к примеру с таблицей cities, то первый введенный вами город должен иметь id, равный 1, второй - 2, третий - 3, и т. д. Чтобы успешно управлять такой последовательностью первичных ключей, нужно иметь какое-то средство, гарантирующее, что в данный конкретный момент только один клиент может прочесть число и увеличить его на единицу. В базе данных с транзакциями можно создать таблицу, скажем, с именем sequence, содержащую число, представляющее очередной id. Когда необходимо добавить новую строку в таблицу, вы читаете число из этой таблицы и вставляете число на единицу большее. Чтобы эта схема работала, нужно быть уверенным, что никто другой не сможет произвести чтение из таблицы, пока вы не ввели новое число. В противном случае два клиента могут прочесть одно и то же значение и попытаться использовать его в качестве значения первичного ключа в одной и той же таблице.

MySQL не поддерживает транзакции, поэтому описанный механизм нельзя использовать для генерации уникальных чисел. Использовать для этих целей команду MySQL LOCK TABLE обременительно. Тем не менее СУБД предоставляет свой вариант понятия последовательности, позволяющий генерировать уникальные идентификаторы, не беспокоясь о транзакциях.

Последовательности. При создании таблицы в MySQL можно одну из колонок специфицировать как AUTO_INCREMENT. В этом случае, при добавлении новой строки, имеющей значение NULL или 0 в данной колонке, автоматически будет происходить замена на значение на единицу больше, чем наибольшее текущее значение в колонке. Колонка с модификатором AUTO_INCREMENT должна быть индексирована. Ниже приведен пример использования поля типа AUTO_INCREMENT:

CREATE TABLE cities (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,

name VARCHAR(100),

pop MEDIUMINT,

founded DATE)

Когда вы первый раз добавляете строку, поле id получает значение 1, если в команде INSERT для него используется значение NULL или 0. Например, следующая команда использует возможность AUTO_INCREMENT:

INSERT INTO cities (id, name, pop)

VALUES (NULL, 'Houston', 3000000)

Если вы выполните эту команду, когда в таблице нет строк, поле id получит значение 1, а не NULL. В случае, когда в таблице уже есть строки, полю будет присвоено значение на 1 большее, чем наибольшее значение id в данный момент.

Другим способом реализации последовательностей является использование значения, возвращаемого функцией LAST_INSERT_ID:

UPDATE table SET id=LAST_INSERT_ID (id+1);

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

Добавление данных. Добавление данных в таблицу является одной из наиболее простых операций SQL. Несколько примеров этого вы уже видели. MySQL поддерживает стандартный синтаксис INSERT:

INSERT INTO table_name (column1, column2, ..., columnN)

VALUES (value1, value2, ..., valueN)

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

INSERT INTO addresses (name, address, city, state, phone, age)

VALUES('Irving Forbush', '123 Mockingbird Lane', 'Corbin', 'KY', '(800) 555-1234', 26)

Кроме того, управляющий символ - по умолчанию '\' - позволяет вводить в литералы одиночные кавычки и сам символ '\':

# Ввести данные в каталог Stacie's Directory, который находится

# в c:\Personal\Stacie

INSERT INTO files (description, location)

VALUES ('Stacie\'s Directory', 'C:\\Personal\\Stacie')

MySQL позволяет опустить названия колонок, если значения задаются для всех колонок и в том порядке, в котором они были указаны при создании таблицы командой CREATE. Однако если вы хотите использовать значения по умолчанию, нужно задать имена тех колонок, в которые вы вводите значения, отличные от установленных по умолчанию. Если для колонки не установлено значение по умолчанию, и она определена как NOT NULL, необходимо включить эту колонку в команду INSERT со значением, отличным от NULL. MySQL позволяет указать значение по умолчанию при создании таблицы в команде CREATE.

Новые версии MySQL поддерживают INSERT для одновременной вставки нескольких строк:

INSERT INTO foods VALUES  (NULL, 'Oranges', 133, 0, 2, 39),

(NULL, 'Bananas', 122, 0, 4, 29),

(NULL, 'Liver', 232, 3, 15. 10)

Хотя поддерживаемый MySQL нестандартный синтаксис удобно использовать для быстрого выполнения задач администрирования, не следует без крайней нужды пользоваться им при написании приложений. Как правило, следует придерживаться стандарта ANSI SQL2 настолько близко, насколько MySQL это позволяет. Благодаря этому вы получаете возможность перейти в будущем на какую-нибудь другую базу данных. Переносимость особенно важна для тех, у кого потребности среднего масштаба, поскольку такие пользователи предполагают когда-нибудь перейти на полномасштабную базу данных.

MySQL поддерживает синтаксис SQL2, позволяющий вводить в таблицу результаты запроса:

INSERT INTO foods (name, fat)

SELECT food_name, fat_grams FROM recipes

Обратите внимание, что число колонок в INSERT соответствует числу колонок в SELECT. Кроме того, типы данных колонок в INSERT должны совпадать с типами данных в соответствующих колонках SELECT. И, наконец, предложение SELECT внутри команды INSERT не должно содержать модификатора ORDER BY и не может производить выборку из той же таблицы, в которую вставляются данные командой INSERT.

Изменение данных. Если ваша база не является базой данных «только для чтения», вам, вероятно, понадобится периодически изменять данные. Стандартная команда SQL для изменения данных выглядит так:

UPDATE table_name

SET column1=value1, column2=value2, ..., columnN=valueN

[WHERE clause]

MySQL позволяет вычислять присваиваемое значение. Можно даже вычислять значение, используя значение другой колонки:

UPDATE years

SET end_year = begin_year+5

В этой команде значение колонки end_year устанавливается равным значению колонки begin_year плюс 5 для каждой строки таблицы.

Предложение WHERE. Возможно, вы уже обратили внимание на предложение WHERE. В SQL предложение WHERE позволяет отобрать строки таблицы с заданным значением в указанной колонке, например:

UPDATE bands

SET lead_singer = 'Ian Anderson'

WHERE band_name = 'Jethro Tull'

Эта команда - UPDATE - указывает, что нужно изменить значение в колонке lead_singer для тех строк, в которых band_name совпадает с «Jethro Tull». Если рассматриваемая колонка не является уникальным индексом, предложение WHERE может соответствовать нескольким строкам. Многие команды SQL используют предложение WHERE, чтобы отобрать строки, над которыми нужно совершить операции. Поскольку по колонкам, участвующим в предложении WHERE, осуществляется поиск, следует иметь индексы по тем их комбинациям, которые обычно используются.

Удаление. Для удаления данных вы просто указываете таблицу, из которой нужно удалить строки, и в предложении WHERE задавая строки, которые хотите удалить:

DELETE FROM table_name [WHERE clause] 

Как и в других командах, допускающих использование предложения WHERE, его использование является необязательным. Если предложение WHERE опущено, то из таблицы будут удалены все записи!

Запросы. Самая часто используемая команда SQL - та, которая позволяет просматривать данные в базе: SELECT. Ввод и изменение данных производятся лишь от случая к случаю, и большинство баз данных в основном занято тем, что предоставляет данные для чтения. Общий вид команды SELECT следующий:

SELECT column1, column2, ..., columnN

FROM table1, table2, ..., tableN

[WHERE clause]

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

В первой части команды SELECT перечисляются колонки, которые вы хотите извлечь. Можно задать «*», чтобы указать, что вы хотите извлечь все колонки. В предложении FROM указываются таблицы, в которых находятся эти колонки. Предложение WHERE указывает, какие именно строки должны использоваться, и позволяет определить, каким образом должны объединяться две таблицы.

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

SELECT book, title, author. name

FROM author, book

WHERE book.author = author.id

Рассмотрим базу данных, в которой таблица book имеет вид, как в таблице 3.6.

Таблица 3.6. Таблица книг

ID

Title

Author

Pages

1

The Green Mile

4

894

2

Guards, Guards!

2

302

3

Imzadi

3

354

4

Gold

1

405

5

Howling Mad

3

294

А таблица авторов author имеет вид таблицы 3.7.

Таблица 3.7. Таблица авторов

ID

Name

Citizen

1

Isaac Asimov

US

2

Terry Pratchet

UK

3

Peter David

US

4

Stephen King

US

5

Neil Gaiman

UK

В результате внутреннего объединения создается таблица, в которой объединяются поля обеих таблиц для строк, удовлетворяющих запросу в обеих таблицах. В нашем примере запрос указывает, что поле author в таблице book должно совпадать с полем id таблицы author. Результат выполнения этого запроса представлен в таблице 3.8.

Таблица 3.8. Результаты запроса с внутренним объединением

Book Title

Author Name

The Green Mile

Stephen King

Guards, Guards!

Terry Pratchet

Imzadi

Peter David

Gold

Isaac Asimov

Howling Mad

Peter David

В этих результатах нет автора с именем Neil Gaiman, поскольку его author.id не найден в таблице book.author. Внутреннее объединение содержит только те строки, которые точно соответствуют запросу. Ниже мы обсудим понятие внешнего объединения, которое оказывается полезным в случае, когда в базу данных внесен писатель, у которого нет в этой базе книг.

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

# Псевдоним колонки

SELECT long_field_names_are_annoying AS myfield

FROM table_name

WHERE myfield = 'Joe'

# Псевдоним таблицы в MySQL

SELECT people.names, tests.score

FROM tests really_long_people_table_name AS people

Группировка и упорядочение. По умолчанию порядок, в котором появляются результаты выборки, не определен. К счастью, SQL предоставляет некоторые средства наведения порядка в этой случайной последовательности. Первое средство - упорядочение. Вы можете потребовать от базы данных, чтобы выводимые результаты были упорядочены по некоторой колонке. Например, если вы укажете, что запрос должен упорядочить результаты по полю last_name, то результаты будут выведены в алфавитном порядке по значению поля last_name. Упорядочение осуществляется с помощью предложения ORDER BY:

SELECT last_name, first_name, age

FROM people

ORDER BY last_name, first_name

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

Группировка - это средство ANSI SQL, реализованное в MySQL. Как и предполагает название, группировка позволяет объединять в одну строки с аналогичными значениями с целью их совместной обработки. Обычно это делается для применения к результатам агрегатных функций. О функциях мы поговорим несколько позднее.

Рассмотрим пример:

mysql> SELECT name, rank, salary FROM people\g

name

rank

salary

Jack Smith

Private

23000

Jane Walker

General

125000

June Sanders

Private

22000

John Barker

Sergeant

45000

Jim Castle

Sergeant

38000

5 rows in set (0.01 sec)

После группировки по званию (rank) выдача изменяется:

mysql> SELECT rank FROM people GROUP BY rank\g

rank

General

Private

Sergeant

3 rows in set (0.01 sec)

После применения группировки можно, наконец, найти среднюю зарплату (salary) для каждого звания. О функциях, используемых в этом примере, мы поговорим позднее.

mysql> SELECT rank, AVG(salary) AS income FROM people GROUP BY rank\g

rank

income

General

125000

Private

22500

Sergeant

41500

3 rows in set (0 04 sec)

Упорядочение и группировка в сочетании с использованием функций SQL позволяет производить большой объем обработки данных на сервере до их извлечения. Но этой мощью нужно пользоваться с осторожностью. Хотя может показаться, что перенос максимального объема обработки на сервер базы данных дает выигрыш в производительности, на самом деле это не так. Ваше приложение-клиент обслуживает потребности отдельного клиента, в то время как сервер используется многими клиентами. Из-за большого объема работы на сервере, почти всегда более эффективно возложить на сервер минимально возможную нагрузку. MySQL, возможно, наиболее быстрая из имеющихся баз данных, но не нужно использовать эту скорость для той работы, к которой лучше приспособлено клиентское приложение.

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

Функции в MySQL. MySQL предоставляет возможность работы с функциями. Функции в SQL аналогичны функциям в других языках программирования, таких как С и Perl. Функция может принимать аргументы и возвращает некоторое значение. В MySQL в команде SELECT функции могут использоваться в двух местах:

Как извлекаемая величина

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

# Функция FROM_UnixTIME()

# преобразует стандартное значение времени Unix в читаемый вид.

SELECT name, FROM_UnixTIME(date)

FROM events

# Функция LENGTH() возвращает длину заданной строки в символах.

SELECT title, text, LENGTH(text)

FROM papers

WHERE author = 'Stacie Sheldon'

Как часть предложения WHERE

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

# Функция RAND() генерирует случайное число

# между 0 и 1 (умножается на 34, чтобы сделать его между О

# и 34, и увеличивается на 1 , чтобы сделать его между 1 и

# 35) Функция ROUND() возвращает данное число округленным

# до ближайшего целого, что приводит к целому числу

# между 1 и 35 которое должно соответствовать одному из чисел ID 

SELECT name

FROM entries

WHERE id = ROUND((RAND()*34) + 1 )

# Можно использовать функции в списке значений и предложении WHERE

# Функция UNIX_TIMESTAMP()без аргументов возвращает текущее время # в формате Unix.

SELECT name, FROM_UnixTIME(date)

FROM events

WHERE time > (Unix_TIMESTAMP() - (60 * 60 * 24))

# Функция ENCRYPT() # возвращает зашифрованную в стиле пароля Unix

# заданную строку, используя 2-символьный ключ.

# Функция LEFT() возвращает n левых символов переданной строки.

SELECT name

FROM people

WHERE password = ENCRYPT(name, LEFT(name, 2))

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

Кроме того, имеются агрегатные функции, выполняемые над набором данных. Обычно этот метод используется для выполнения некоторого действия над всем набором возвращаемых данных. Например, функция SELECT AVG(height) FROM kids возвращала бы среднее от значений поля height в таблице kids.

Таблица 3.9. Агрегатные функции MySQL

AVG(expression )

Возвращает среднее значение из значений в expression (например, SELECT AVG(score) FROM tests).

BIT_AND( expression )

Возвращает результат побитового И, агрегирующего все значения в expression (например, SELECT BIT_AND(flags) FROM options).

BIT_OR( expression )

Возвращает побитовое ИЛИ, агрегирующее все значения в expression (например, SELECT BIT_OR(flags) FROM options).

COUNT(expression )

Возвращает количество раз, когда значение expression было не нулевым. COUNT(*) вернет число записей с какими-либо данными во всей таблице (например, SELECT COUNT( *) FROM folders).

MAX(expression )

Возвращает наибольшее из значений в expression (например, SELECT MAX (elevation) FROM mountains ).

MIN( expression )

Возвращает наименьшее из значений в expression (например, SELECT MIN(level) FROM toxic_waste ).

STD(expression )/STDDEV( expression )

Возвращает среднеквадратичное отклонение значения в expression (например, SELECT STDDEV(points) FROM data ).

SUM( expression )

Возвращает сумму значений в expression (например, SELECT SUM(calories) FROM daily_diet ).

Объединения в MySQL. MySQL поддерживает более сильный тип объединения, чем простое внутреннее объединение, которое мы до сих пор использовали. Именно, MySQL поддерживает так называемое левое внешнее объединение (известное также просто как внешнее объединение). Объединение этого типа похоже на внутреннее объединение, за исключением того, что в него включаются данные из левой колонки, которым нет соответствия в правой колонке. Если вы обратитесь к нашим таблицам с авторами и книгами, то вспомните, что в наше объединение не вошли авторы, у которых в базе данных не было книг. Часто вы можете пожелать вывести записи из одной таблицы, для которых нет соответствия в другой таблице, с которой производится объединение. Это можно сделать с помощью внешнего объединения:

SELECT book.title, author.name

FROM author

LEFT JOIN book ON book.author = author.id

Обратите внимание, что во внешнем объединении вместо WHERE используется ключевое слово ON. Результат нашего запроса будет выглядеть так:

book title

author name

The Green Mile

Stephen King

Guards, Guards!

Terry Pratchet

Imzadi

Peter David

Gold

Isaac Asimov

Howling Mad

Peter David

NULL

Neil Gaiman

MySQL делает следующий шаг, позволяя использовать естественное внешнее объединение (natural outer join). Естественное внешнее объединение соединяет строки двух таблиц, в которых две колонки имеют одинаковые имена и тип, и значения в этих колонках совпадают:

SELECT my_prod name

FROM my_prod

NATURAL LEFT JOIN their_prod


  1.  ASP. Основы. Объекты и компоненты. Доступ к базам данных

Основы ASP.

Dynamic HTML представляет собой основное средство программирования клиента для Microsoft Internet Explorer 4.0 и выше, но такие программы просмотра Web, как Netscape Navigator, не поддерживают Dynamic HTML. На самом деле очень малая часть функциональности клиентской части, поддерживаемой различными программами просмотра, может рассматриваться как действительно кросс-платформенная.

Если Вы хотите разработать Интернет-узел, открытый для доступа самым различным программам просмотра, то должны перенести программирование с клиента на сервер. Такую возможность предоставляют Microsoft ASP (Active Server Pages — активные серверные страницы). По сути ASP не что иное, как сценарий на VBScript, который исполняется на сервере. Когда запрашивается страница, этот сценарий порождает HTML-текст. Это ключевая особенность ASP — клиент никогда не видит вашего кода, а только результирующий HTML, который воспринимает любая программа просмотра.

Листинг 4.1 демонстрирует простую ASP-страницу, которая создает приветствие в соответствии со временем суток. В нем текущий час определяется при помощи кода Hour(Now), где Now — функция VBScript, возвращающая текущий момент времени и дату. Если текущий час меньше 12, то приветствие задается в форме «Доброе утро!» От полудня до шести вечера сообщение имеет вид «Добрый день!», а после шести — «Добрый вечер!»

Листинг 4.1. Простой пример ASP.

<%@ LANGUAGE="VBSCRIPT" %>

<HTML> <head>

<MEТА HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=windows-1251">

<TITLE>Simple ASP Example</TITLE> </HEAD><BODY BGCOLOR="#FFFFFF">

<%

Dim strGreeting

If Hour(Now) < 12 Then

strGreeting = "Доброе утро!"

ElseIf Hour(Now) > 11 And Hour(Now) < 18 Then

StrGreeting = "Добрый день"

ElseIf Hour(Now) > 17 Then

 strGreeting = "Добрый вечер!"

End If

%>

<CENTER><H1><%=strGreeting%> </Н1>

</BODY></HTML>

Обратите внимание на код в листинге, окруженный специальными символами: угловыми скобками и знаками процента (<%...%>). Такие символы означают, что это серверный код, который выполняется перед тем, как страница будет на самом деле послана программе просмотра. Если бы Вы посмотрели в Internet Explorer на результирующий HTML-текст, то увидели бы следующее (в предположении, что сейчас еще не вечер, но уже не утро):

<%@ LANGUAGE="VBSCRIPT" %>

<HTML><HEAD>

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

<TITLE>Simple ASP Example</TITLE> </HEAD>

<BODY BGCOLOR="#FFFFFF"> <Н1>Добрый день!</Н1> </BODY> </HTML>

В этом-то и состоит суть ASP. Результат исполнения кода — обыкновенный HTML! Эту страницу можно просматривать любой программой просмотра: не только Internet Explorer, но и, например, Netscape Navigator. Иными словами, ASP предоставляет разработчику подлинную платформенную независимость

У представленного кода есть еще несколько особенностей. Обратите внимание на самую верхнюю строчку — она определяет, на каком языке написан сценарий на данной странице:

<%@ LANGUAGE="VBSCRIPT" %>

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

А теперь обратите внимание на ту строку, где и происходит генерация HTML-текста. Здесь для вывода приветствия используется переменная:

<H1><%=strGreeting%> </H1>

Переменная strGreeting заключена в угловые скобки со знаками процента, как и весь остальной серверный код, но, кроме того, ей предшествует знак равенства. Такая конструкция играет важную роль в ASP, указывая, что в данное место HTML-страницы нужно вставить текущее значение этой переменной.

Объекты и компоненты. На самом простом уровне создание ASP-страницы — это ни что иное, как написание серверного кода для получения ожидаемого результата. Но VBScript не является полнофункциональным языком и, как только Вы приступаете к построению более сложных страниц, его выразительных средств начинает не хватать. Так, в VBScript нет встроенных функций доступа к данным; не умеет он и открывать текстовые файлы. Собственно говоря, в VBScript отсутствуют какие-либо встроенные средства доступа к каким бы то ни было внешним источникам данных. Так как же в таком случае при помощи ASP выполняются такие сложные действия, как доступ к данным? Ответ будет таким: нужно дополнить VBScript объектами и компонентами ASP.

ASP-объекты и компоненты — это не что иное, как компоненты ActiveX, подобные обычным DLL ActiveX, с которыми Вы наверняка работали в Microsoft Visual Basic. Различие между объектами и компонентами ASP состоит в том, каким образом они появляются в программе. ASP-объекты — это элементы управления ActiveX, которые в коде на VBScript доступны всегда: их не нужно создавать явно. В число объектов ASP входят Application, Session, Request, Response и Server. А вот ASP-компоненты представляют собой DLL, существующие вне структуры ASP. Эти компоненты могут быть написаны на любом языке, а некоторые полезные ASP-компоненты просто поставляются в комплекте с Visual InterDev. ASP-компоненты нужно явно создавать в коде. ASP поддерживает компоненты Database Access, File Access, Browser Capabilities, Ad Rotator и Content Linking.

Файл GLOBAL.ASA. Одна из главных трудностей разработчика для Интернета, независимо от того, какую технологию он использует, состоит в том, как сложно создать в Интернете настоящее приложение. Взаимодействие программы просмотра и Web-сервера представляет собой по сути лишенную состояния транзакцию, в ходе которой сервер посылает клиенту Web-страницу и затем забывает о его существовании. Когда клиент запрашивает другую Web-страницу, сервер ничего не помнит о предыдущем запросе. Коренная проблема для всех Web-приложений такова: как показать, что это именно приложение?

Определить приложение в среде Microsoft Windows довольно просто. Приложение запускается двойным щелчком значка и завершается, когда в меню File выбран пункт Exit. В промежутке между двумя этими событиями данные хранятся в переменных. Но для Интернет-приложений это не так. Как определить, когда приложение начинается, а когда заканчивается? Можно сказать, что приложение начало работу, если пользователь зашел на узел и просматривает одну из его страниц. Но что если он переходит к другому узлу, а через пять минут возвращается? Приложение все еще активно? А если пользователь отсутствовал час или два?

Проблема определения моментов запуска и завершения приложения оказывает серьезное влияние на правильное управление переменными и последовательностью выполнения. К счастью, ASP предлагает решение. Оно состоит в том, что для определения начала и завершения — как всего приложения, так и отдельных пользовательских сессий — используется специальный файл под названием GLOBAL.ASA. На этот файл возложено реагирование на четыре ключевых события узла: Application_OnStart (запуск приложения), Application_OnEnd (завершение приложения), Session_OnStart (начало сессии) и Session_OnEnd (завершение сессии). В листинге 4.2 приведен типичный файл GLOBAL.ASA.

Листинг 4.2. Файл GLOBAL.ASA.

<SCRIPT LANGUAGE="VBSCRIPT" RUNAT="Server">

' В этот файл можно добавить обработчики событий ASP.

' Для создания обработчиков внесите в файл подпрограмму с именем,

' соответствующим событию, на которое Вы бы хотели среагировать.

'Название события  Описание

'SessionOnStart  Происходит, когда пользователь в первый раз вы-

' полняет любую страницу Вашего приложения

SessionOnEnd  Происходит, когда превышен лимит времени,

' в течение которого пользователь не обращается

' к страницам Вашего приложения, или если имел

' место явный выход

'Application_OnStart Происходит один раз, когда любой

' пользователь впервые выполняет первую страницу

' Вашего приложения

'Application_OnEnd  Происходит один раз при остановке Web-сервера

Sub SessionOnStart

End Sub

Sub Session_OnEnd

End Sub

Sub ApplicationOnStart

End Sub

Sub Application On_End

End Sub

</SCRIPT>

Для обозначения разделов сценария GLOBAL.ASA содержит теги <SCRIPT>. Эти теги имеют особый атрибут RUNAT=Server, который означает, что содержащийся в теге код на VBScript должен исполняться на сервере, а не на клиенте. Функционально RUNAT=Server означает то же, что и сочетания угловых скобок и знака процента, используемые для обозначения серверного сценария на Web-страницах. Обработка стандартных событий на сервере записывается в GLOBAL.ASA в стандартном синтаксисе. Например, обработку запуска приложения выполняет следующий фрагмент кода:

<SCRIPT LANGUAGE=VBScript RUNAT=Server>

Sub Application_OnStart

' Конкретный код приложения

End Sub </SCRIPT>

Хотя GLOBAL.ASA отмечает начало и завершение приложения при помощи событий, остается неясным, что же все-таки составляет собственно приложение. Одна из рабочих формулировок, предложенная Microsoft, определяет Интернет-приложение как виртуальный каталог со всеми его файлами. Если пользователь запрашивает Web-страницу из виртуального каталога под названием Bookstore, то тем самым он запускает приложение Bookstore, и в GLOBAL.ASA возбуждаются события Application_OnStart и Session_OnStart.

Согласно этому определению с приложением одновременно могут работать несколько программ просмотра. Но событие Application_OnStart происходит только один раз: когда первый пользователь запрашивает Web-страницу из виртуального каталога. Когда затем страницы из этого ката­лога запрашивают другие пользователи, возбуждается только событие Session_OnStart.

В то время как приложение может относиться к нескольким программам просмотра, обращающимся к одному и тому же множеству Web-страниц, сессия касается какой-то одной программы просмотра, обращающейся к тем же Web-страницам. Для конкретной программы просмотра сессия длится, пока программа продолжает запрашивать страницы виртуального каталога. Если же пользователь не запрашивает Web-страницы (из данного виртуального каталога) на протяжении 20 минут (по умолчанию), сессия завершается, и возбуждается событие Session_OnEnd. Когда в данном виртуальном каталоге завершаются все сессии, возбуждается событие Application_OnEnd.

В качестве примера рассмотрим следующий сценарий. Два пользователя намереваются посетить на Web-узле приложение Magazine. Пользователь 1 оказывается проворнее и быстренько запрашивает Web-страницу DEFAULT.ASP. Тут же возбуждаются события Application_OnStart и Session_OnStart. Буквально пятью минутами позже к приложению обращается пользователь 2. Поскольку пользователь 1 как-то проявлял себя в течение последних 20 минут, приложение Magazine активно. Следовательно, возбуждается только событие Session_OnStart, сигнализируя о начале новой сессии. Кроме того, теперь для завершения приложения необходимо, чтобы завершились обе сессии.

В течение следующих 15 минут пользователь 1 не запрашивает ни­каких страниц приложения Magazine. Поскольку он не проявлял активности на протяжении 20 минут, ASP приходит к выводу, что пользователь 1 закончил свою работу с приложением, и возбуждает событие Session_OnEnd. Но приложение все еще активно, поскольку в течение последних 20 минут к нему обращался пользователь 2.

Пользователь 2 работает с приложением еще час, то и дело запрашивая новые Web-страницы. Но в конце концов он отключается, а через 20 минут после того, как он покинул узел (точнее, в последний раз запросил Web-страницу приложения), возбуждается событие Session_OnEnd. Поскольку пользователь 2 был последним пользователем данного приложения, оно завершается, и возбуждается событие Application_OnEnd.

Объекты.

В ASP есть несколько встроенных объектов, которые доступны разработчику. Эти объекты помогают управлять многими вещами: от переменных, до передачи форм. Работать с ними легко, они вызываются из кода напрямую без какого-то особого синтаксиса.

Объект Application. Объект Application (приложение) позволяет создавать переменные приложения (application variables) - переменные, доступные всем пользователям данного приложения. Все, кто обращается к Web-страницам данного виртуального каталога, могут совместно использовать любую переменную приложения определенную для этого каталога.

В листинге 4.3 приведен пример программы, которая использует Объект Application. В нем переменная приложения служит для отслеживания времени последнего обращения к страницам приложения.

Листинг 4.3. Объект Application.

<%@ LANGUAGE ="VBScript"%>

<html><head><title>Application Variables</TITLE>

</HEAD><BODY><CENTER>

Эта страница последний раз посещалась: <%=Application("Time")%>

<% Application.Lock

Application("Time")=Now

Application.UnLock %>

</BODY></HTML>

Создание переменной приложения сводится к адресации объекта Application именем новой переменной, которую вы хотите создать. Например, следующий код создает новую переменную приложения с именем Company и присваивает ей значение NewTech.

Application("Company")="NewTech"

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

Поскольку такие переменные доступны нескольким пользователям одновременно, вы не сможете гарантировать, что два пользователя не попытаются одновременно присвоить одной и той же переменной разные значения. Для разрешения подобных коллизий объект Application поддерживает методы Lock и UnLock. Метод Lock блокирует весь объект Application, а не только переменную, вы хотите изменить, поэтому сразу же после изменения значения переменной разблокируйте объект:

Application.Lock

Application("Company")="NewTech"

Application.UnLock

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

Объект Session. Зачастую разработчиков меньше интересуют данные, совместно используемые несколькими пользователями, зато гораздо больше - данные, связанные с конкретным пользователем. ASP поддерживает переменные для индивидуального пользователя при помощи объекта Session (сессия), который позволяет создавать переменные сессии (session variables).

Листинг 4.4 демонстрирует, как определить несколько переменных сессии в файле GLOBAL.ASA. Само по себе их определение так же просто, как и в случае переменных приложения. Все, что нужно сделать - это адресовать объект Session именем переменной, которую вы хотите создать. Основное различие между переменными этих объектов - их области видимости. Переменные сессии предназначаются для одного пользователя и живут, пока пользователь поддерживает сессию. Как только в течение 20 минут (по умолчанию) пользователь не обращается к страницам данного виртуального каталога, данные пропадают.

Листинг 4-.. Создание переменных сессии.

<SCRIPT LANGUAGE="VBSCRIPT" RUNAT="Server">

Sub Session_OnStart

Session("Company")="NewTech"

Session("Email")="info@newtech.com"

End Sub

</SCRIPT>

Переменные сессии можно создавать на любой Web-странице или в файле GLOBAL.ASA, а доступны они на любой Web-странице приложения, в котором эти переменные были первоначально созданы. Получить значения переменных сессии можно, считывая их из объекта Session. Следующий фрагмент кода считывает переменные сессии, созданные в листинге 4.4, и выводит их в полях ввода:

<FORM>

<P><INPUT TYPE="TEXT" VALUE=<%=Session("Company")%>Компания</P>

<P><INPUT TYPE="TEXT" VALUE=<%=Session("Email")%>Эл. Почта</P>

</FORM>

Ранее мы определили Интернет-приложение как лишенные статуса транзакции между Web-сервером и программой просмотра. Как же тогда ASP запоминает переменные сессии для каждого пользователя приложения? Ответ будет таким: эти переменные сохраняются на сервере для каждого клиента. Программа просмотра получает от сервера уникальный идентификатор, позволяющий определить, какой набор переменных кому принадлежит. Клиент этот идентификатор (Globally Unique Identifier, GUID) сохраняет, а впоследствии посылает серверу и получает именно ему предназначенные данные. Таким образом каждый клиент может иметь свой набор данных в каждом Интернет-приложении.

Осталось сказать, что для установки или считывания впемени жизни сессии (в минутах) применяется свойство Timeout объекта Session:

Session.Timeout=30

Объект Request. Для передачи данные клиенту создается Web-страница, а для передачи данных в обратном направлении программа просмотра использует отправку формы (form submission). В форме содержатся текстовые поля, переключатели и т.п. Клиент размещает введенные данные в этих полях и пересылает пакет серверу. Процессом передачи формы управляют два атрибута тега <FORM>: METHOD и ACTION. Первый атрибут - METHOD - определяет, каким именно образом данные пересылаются серверу. Атрибут может иметь два значения: POST и GET. POST диктует программе просмотра, что данные нужно поместить внутрь формы, а GET пересылает данные как составную часть URL целевой страницы. Второй атрибут - ACTION - задает целевую страницу для обработки отправленных данных. Следующий код посылает все данные формы сценарию DATA.ASP методом POST:

<FORM METHOD="POST" ACTION="/l5/data.asp">

<P><INPUT TYPE="TEXT" NAME="Name"></P>

<P><INPUT TYPE="TEXT" NAME="EMail"></P>

<P><INPUT TYPE="SUBMIT"></P>

</FORM>

Элемент формы с типом SUBMIT - это кнопка, нажатие которой пользователем заставляет программу просмотра упаковать данные формы и отправить их. Формат пересылки данных определен строго и сервер знает, чего ожидать от клиента. Данные имеют вид пар Поле=Значение, отсылаемых серверу в формате открытого текста. Если в предыдущем примере ввести в поле Name NewTech и info@newtech.com в поле Email, то сценарию DATA.ASP будет послан следующий текст:

Name=NewTech&Email=info@newtech.com

На сервере эти данные можно вновь разобрать по полям и использовать в любых целях. Вот тут-то и нужен объект Request. Он используется в ASP для разбора полученных от клиента данных. Для работы с объектом Request просто сообщите ему имя поля, значение которого хотите получить, и объект вернет вам это значение. Например, следующий код вернет вам значение поля Name:

<%=Request.Form("Name")%>

Request.Form применяется, когда данные были отправлены методом POST и именно этому сценарию. Если для отправки данных используется метод GET или сценарий вызывается с передачей параметров прямо в гиперссылке

<A HREF=/l5/data.asp?Name=NewTech&Email=info@newtech.com> Чтобы отправить данные, щелкните здесь!</A>

то для разбота данных применяют свойство Request.QueryString, который работает так же, как Request.Form. Следующий фрагмент кода вернет значение поля Name из гиперссылки:

<%=Request.QueryString("Name")%>

Другое свойство - Request.Cookies используются для извлечения информации из кукисов (cookies), отосланных вместе с запросом строке пользовательского агента программы просмотра. А листинг 4.5 демонстрирует применение свойства ServerVariables для определения имени компьютера, с которого клиент вызвал сценарий.

Листинг 4.5. Определение компьютера пользователя.

<%@ LANGUAGE="VBSCRIPT"%>

<html><head><title>Server Variables</TITLE>

</HEAD><BODY><CENTER>Вы вошли с компьютера

<%=Request.ServerVariables("Remote_Host")%>

</BODY></HTML>

Переменные сервера представляют широкий круг информации о клиенте и Web-сервере. Доступ к каждой конкретной переменной сводится к чтению соответствующей переменной.

Объект Response. Этот объект управляет содержимым страницы, которую ASP возвращает программе просмотра. Фактически в комбинации <%=переменная%> знак равенства представляет собой сокращенное обозначение метода Write объекта Response. Так что следующие две строки кода эквивалентны:

<%="NewTech"%>

<%Response.Write "NewTech"%>

Поскольку объект Response используется очень часто, такое сокращение оправдано.

Полезное свойство объекта Response - Expires. Оно задает время (в минутах) за которое страница устаревает. Если установить его в нуль, то страница будет устаревать в момент загрузки и Internet Explorer не будет ее кэшировать. Кэширование сильно влияет на разработку и может привести к тому, что приложение будет функционировать неправильно. IE кэширует страницы двумя способами: на диске и в памяти. Рассмотрим такой фрагмент кода, показывающий текущее время и дату:

<CENTER>Сейчас <%=Now%>

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

Листинг 4.6. Страница, устаревающая уже в момент загрузки.

<%@ LANGUAGE="VBSCRIPT"%>

<%Response.Expires=-1%>

<HTML><HEAD><TITLE>Forcing a Page to Expire</TITLE></HEAD><BODY>

<Н1>Сейчас <%Response.Write Now%>

</BODY> </HTML>

Еще один полезный метод объекта Response - Redirect, перенаправляющий программу просмотра на указанный URL:

<% Response.Redirect "enter.asp"%>

Объект Server. Объект Server (сервер) представляет собой в некотором роде свалку — в том смысле, что предоставляемые им функции никак не связаны между собой, за тем исключением, что все они полезны разработчику для Интернета. Пожалуй, самая важная из всех функций объекта Server — это метод CreateObject, который создает экземпляр компонента ActiveX. Причем это может быть как встроенный компонент, входящий в комплект поставки, так и тот, который написали Вы сами на любом языке. В любом случае использование компонента ActiveX на сервере требует вызова метода CreateObject.

Аргументом метода CreateObject служит ProgID (программный идентификатор) требуемого компонента ActiveX. ProgID — это содержательное имя компонента, такое как Excel.Sheet или Word.Basic. Следующая строчка показывает, как при помощи CreateObject создать экземпляр компонента с ProgID Excel.Sheet.

Set MyObject = Server.CreateObject("Excel.Sheet")

Другим полезным методом объекта Server является MapPath, возвращающий фактический путь, соответствующий заданному виртуальному каталогу.

Компоненты.

Компоненты ASP — это на самом деле просто компоненты ActiveX, наподобие тех, что Вы можете сами создать на Visual Basic или Visual C++. Но эти компоненты написаны Microsoft и поставляются вместе с Visual InterDev. Они предназначены для выполнения полезных для Web-узлов задач общего характера, включая доступ к данным. Создать их на своей странице Вы можете при помощи метода CreateObject объекта Server, а как только они созданы, смело обращайтесь к их свойствам и методам для выполнения нужных Вам задач.

Компонент ActiveX Data Objects. Самым полезным изо всех компонентов ASP следует признать компонент доступа к базам данных, называемый также ActiveX Data Objects, или сокращенно ADO. Он и содержащиеся в нем объекты применяются для чтения и записи данных в источники данных ODBC при публикации в Web информации из баз данных.

Объект Connection (подсоединение) создается методом CreateObject объекта Server, и ссылка на него помещается в переменную. Когда объект создан, его можно использовать для открытия подсоединения к любому источнику данных ODBC. Следующий фрагмент кода устанавливает подсоединение к источнику данных ODBC с названием Publications:

<%

' Объявляем переменную

Dim objConnection

' Создаем объект Connection

Set objConnection = Server.CreateObject("ADODB.Connection")

' Открываем подсоединение к источнику данных

objConnection.Open "Publications", "sa", "" %>

Здесь objConnection — переменная для объектной ссылки на экземпляр объекта Connection. Метод Open устанавливает подсоединение, принимая в качестве аргументов имя источника данных, идентификатор пользователя и пароль.

Когда подсоединение установлено, получать информацию из источника данных можно при помощи объекта Recordset (набор записей). Этот объект умеет выполнять оператор SELECT языка SQL и возвращать набор записей, удовлетворяющих этому запросу. Как и объект Connection, Recordset создается методом CreateObject. В следующем примере программа выполняет оператор SELECT над источником данных, представленным переменной objConnection:

<%

' Объявляем переменную

Dim objRecordset

' Создаем объект 

Recordset Set objRecordset =

Server.CreateObject("ADODB.Recordset")

' Выполняем запрос SQL

objRecordset.Open "SELECT *", objConnection

%>

После того, как записи получены, для передвижения по ним можно обращаться к методам MoveFirst, MoveLast, MoveNext и MovePrevious. Затем метод Write объекта Response помещает данные на Web-страницу, которая и посылается программе просмотра. В листинге 4.7 приведен полный пример ASP-страницы, которая строит список пользователей, содержащихся в источнике данных Data.

Листинг 4.7. Построение списка при помощи ADO.

<HTML><HEAD>

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

<TITLE>Using ADO</TITLE></HEAD><BODY>

<%

'Объявляем переменные

Dim objConnection

Dim objRecordset

' cоздаем объекты

Set objConnection = Server.CreateObject("ADODB.Connection")

Set objRecordset = Server.CreateObject("ADODB.Recordset")

' Устанавливаем подсоединение и выполняем запрос

objConnection.Open "Data", "", ""

objRecordset.Open "SELECT Name FROM Users", objConnection

%>

<!-- Строим список SELECT по набору данных -->

<SELECT SIZE=8>

<% Do While Not ObjRecordset.EOF %>

<!-- Создаем очередной элемент списка -->

<OPTION><%=objRecordset("Name")%>

</OPTION>

<% objRecordset.MoveNext

Loop %>

</SELECT></BODY></HTML>

Одна из основных задач в управляемом данными Web-приложении — управление информацией в объекте Recordset. Очень часто простой запрос возвращает гораздо больше данных, чем имеет смысл показывать. Давайте, например, посмотрим, что происходит, когда Вы обращаетесь к какой-либо поисковой системе в Интернете. Поисковая машина, получив ключевое слово, возвращает ссылки на узлы, где это ключевое слово встречается. Но зачастую обнаруживаются тысячи узлов, содержащих данное ключевое слово. Совершенно очевидно, что показать все эти узлы на одной Web-странице совершенно невозможно.

Выход состоит в разбиении на страницы (paging). Этот механизм реализован во всех поисковых системах для передачи за один раз некоей порции результатов запроса, скажем, из 10 записей. Теперь пользователь может эффективно работать с полученной информацией. Поддерживает разбиение на страницы и ADO — посредством нескольких свойств объекта Recordset: PageSize, PageCount и AbsolutePage.

При получении набора данных можно указать, что записи следует разбить на страницы. Количество строк набора данных, составляющих страницу, задается значением свойства PageSize. Затем можно определить общее количество страниц в наборе данных посредством свойства PageCount. А доступ к заданной странице обеспечивает свойство AbsolutePage.

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

Листинг 4.8. Разбиение набора данных на страницы средствами ADO.

<%@LANGUAGE="VBScript" %>

<%Response.Expires=-1 %>

<HTML><HEAD>

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

<TITLE>Paging Records</TITLE> </HEAD> <BODY>

<%

' На какой мы странице?

Select Case Request.QueryString("Direction")

Case ""  Session("CurrentPage") = 1

Case "Next"  Session("CurrentPage") = Session("CurrentPage") + 1

Case "Prev" Session("CurrentPage") = Session("CurrentPage") - 1

End Select

' Константы

Const adOpenKeyset = 1

' Объявляем переменные

Dim objConnection

Dim objRecordset

' Открываем базу данных

Set objConnection = Server.CreateObject("ADODB.Connection")

objConnection.Open "Data", "", ""

' Конструируем оператор SQL

Dim strSQL

strSQL ="SELECT Name, About FROM Users"

' Создаем набор данных

Set objRecordset = Server.CreateObject("ADODB.Recordset")

objRecordset.PageSize = 10

objRecordset.Open strSQL, objConnection, adOpenKeyset

objRecordset.AbsolutePage = CLng(Session("CurrentPage"))

' Выводим результаты

%>

<P>Page <%=Session("CurrentPage")%> of

<%=objRecordset.PageCount%></P>

<TABLE BORDER>

<TR><TH>Пользователь</TH><TH>Сведения</TH>

</TR><%

Dim i

For i = 1 To objRecordset.PageSize

if NOT objRecordset.EOF Then

%>

<TR><TD><%=objRecordset("Name")%></TD>

<TD><%=objRecordset("About")%></TD>

</TR> <%

objRecordset.MoveNext

end if

Next %>

</TABLE>

<!-- Ссылка на СЛЕДУЮЩУЮ страницу -->

<% If CLng(Session("CurrentPage")) < objRecordset. PageCount Then %>

<P><A HREF="e8.asp?Direction=Next">Следующая страница</A></P>

<%End If%>

<!-- Ссылка на ПРЕДЫДУЩУЮ страницу -->

<% If CLng(Session("CurrentPage")) > 1 Then %>

<P><A HREF="e8.asp?Direction=Prev">Предыдущая страница</A></P>

<%End If%>

<%

' Закрываем базу данных

objRecordset.Close

objConnection.Close

Set objRecordset = Nothing

Set ObjConnection = Nothing %>

</BODY></HTML>

В этом примере применяются определенные приемы, которые стоит обсудить подробнее. Обратите внимание, что весь процесс разбиения на страницы обеспечивается одним ASP-файлом. Для каждой страницы данных вновь вызывается тот же самый ASP-файл. Обычно при вызове страницы Internet Explorer получает ее из памяти клиентского компьютера. В нашем примере страница всегда будет находиться в памяти, поскольку вызывается постоянно. Налицо проблема: ведь запрос выполняется только тогда, когда выполняется код на сервере. Поэтому мы должны предотвратить использование ASP-файлов из памяти. Для этого следует установить свойство Expires объекта Response в нуль. Тогда файл будет обновляться при каждом новом обращении к странице, что нам и требуется.

Обратите также внимание, что при каждом обращении к странице выполняется один и тот же запрос, меняется только свойство Absolute-Page. Такая стратегия кажется достаточно расточительной, но требует меньше ресурсов, чем запоминание объектов Recordset большого объема в переменных сессии и хранение их в период между обращениями к странице. Представьте себе узел с тысячами пользователей, у каждого из которых в переменной сессии хранится объект Recordset. Ресурсы сервера будут моментально истощены.

При помощи ADO можно выполнять доступ к данным на сервере на основе любого оператора SQL. Запросы можно закодировать как хранимые процедуры SQL-сервера или непосредственно в виде SQL-операторов SELECT. Модифицировать данные можно при помощи SQL-операторов UPDATE и метода Execute объекта Connection. ADO может применяться и на клиентской стороне в сочетании с Advanced Data Control (ADC). По сути ADC очень мало отличается от просто ActiveX-оболочки вокруг большей части функциональности ADO. Основную роль в доступе к данным посредством ADC играет его свойство Recordset.

Компонент File Access. Компонент File Access (компонент доступа к файлам) предоставляет доступ к текстовым файлам на Web-узле. На самом деле он состоит из двух отдельных объектов: FileSystem, который служит для открытия и закрытия файлов, и TextStream, предназначенного для чтения и записи.

Итак, чтобы получить доступ к файлу, сначала создайте (методом CreateObject объекта Server) объект FileSystem. Затем для создания нового файла следует вызвать метод CreateTextFile только что созданного объекта, а для открытия существующего файла — метод OpenTextFile. В любом случае оба метода вернут объект TextStream. Ниже показано, как получить доступ к файлу DATA.TXT:

Set objFile = Server. CreateObject("Scripting. FileSystemObject") Set objStream = objFile.OpenTextFile("DATA.TXT")

После создания объекта TextStream можно свободно вызывать любые его методы для чтения или записи информации. Не забывайте, однако, что обычно файл открывается только для чтения или только для записи, но не для того и другого одновременно. Этот факт требует определенной организации кода ASP-страниц: если над одним и тем же файлом необходимо выполнить разные операции, его следует открыть, закрыть и вновь открыть.

Помимо просто чтения и записи компонент File Access служит для создания динамического информационного наполнения. Давайте попробуем реализовать генератор «дежурных советов» (tip-of-the-day), выводящий подсказки или сообщения, которые обновляются при каждой новой загрузке страницы. Полный текст примера, посвященного советам по программированию на Visual Basic, приведен в листинге 4.9. Главное в этой задаче — написать текстовый файл, каждая строчка которого содержит одну подсказку. Затем эти строчки считываются по одной в случайном порядке методом ReadLine объекта TextStream и помещаются на страницу методом Write объекта Response.

Листинг 4.9. Генерация «дежурного совета».

<HEAD>

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

<TITLE>VB Tips</TITLE> </HEAD>

<BODY BGCOLOR="#FFFFFF">

<%

' Объявляем переменные

Dim objFile 

Dim objStream

' Открываем файл

Set objFile =Server.CreateObject("Scripting.FileSystemObject")

Set objStream =objFile.OpenTextFile(Server.MapPath("/scripts") &_ "\web\l5\tips.txt")

Randomize Timer

intLine = Int(Rnd * 19)

For i = 0 to intLine

objStream.SkipLine

Next

strText = objStream.ReadLine

objStream.Close

Set objStream = Nothing

Set objFile = Nothing

%>

<CENTER><H1>Дежурный совет по VB</H1></CENTER>

<%=strText%>

</BODY></HTML> 

Компонент Browser Capabilities. Компонент Browser Capabilities (компонент характеристик программы просмотра) идентифицирует программу просмотра Web, которая в данный момент осуществляет доступ к узлу, а также предоставляет программный доступ к ряду поддерживаемых этой программой возможностей. Это огромная ценность для Web-разработчиков, которые должны поддерживать как Internet Explorer, так и Netscape Navigator. При помощи этого компонента можно приспособить Web-страницу к определенному типу программы просмотра.

Действие компонента Browser Capabilities основано на строке пользовательского агента программы просмотра, в которой указан тип последней. Эту строку программа просмотра передает серверу каждый раз при запросе Web-страницы. Для IE 4.0 строка выглядит так:

Mozilla/4.0 (compatible;  MSIE 4.0; Windows 95)

Чтобы определить, какие возможности поддерживает данная программа просмотра, компонент пытается найти соответствие полученной строке среди образцов в специальном файле инициализации BROWSCAP.INI. Как только такой образец найден, все возможности, свойственные этой программе просмотра, немедленно становятся доступны как свойства компонента характеристик. В листинге 4.10 приведен фрагмент файла BROWSCAP.INI, соответствующий IE 4.0.

Листинг 4.10. Фрагмент файла BROWSCAP.INI для IE 4.0.

Mozilla/4.0 (compatible; MSIE 4.0; Windows 95)

browser=IE

Version=4.0

majorver=#4

minorver=#0

frames=TRUE

tables=TRUE

cookies=TRUE

backgroundsounds=TRUE

vbscript=TRUE

javascript=TRUE

javaapplets=TRUE

ActiveXControls=TRUE

Win16=False

beta=False

Использование компонента Browser Capabilities заменяет в ASP-страницах операторы условной компиляции. Можно построить такие простые операторы If...Then, которые очень заметно влияют на конечный результат. Так, код из листинга 4.11 посылает тег <OBJECT> программе просмотра, поддерживающей элементы управления ActiveX, тег <APPLET> — программе просмотра с поддержкой Java и текстовое сообщение — всем остальным.

Листинг 4.11. Определение характеристик программы просмотра Web.

<%@LANGUAGE="VBScript"%>

<%Response.Expires=-1%>

<HTML><HEAD>

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

<TITLE>Browser Capabilities</TITLE> </HEAD> <BODY> <CENTER>

<%

' Создаем компонент Browser Capabilities

Dim objBrowser

Set objBrowser = Server.CreateObject("MSWC.BrowserType")

' Выясняем, какие возможности поддерживаются

If objBrowser.ActiveXControls Then

%>

<H1>Элементы управления ActiveX</H1>

<OBJECT ID="mylabel" WIDTH="300" HEIGHT="51"

CLASSID="CLSID:978C9E23-D4B0-11CE-BF2D-00AA003F40D0"

CODEBASE="http://www.microsoft.com/activex/controls/FM20.DLL">

<PARAM NAME="ForeColor" VALUE="98776">

<PARAM NAME="VariousPropertyBits" VALUE="276824091">

<PARAM NAME="Caption" VALUE="Щелкни меня!">

<PARAM NAME="Size" VALUE="7691;1094">

<PARAM NAME="SpecialEffect" VALUE="1">

<PARAM NAME="FontEffects" VALUE="1073741827">

<PARAM NAME="FontHeight" VALUE="480">

<PARAM NAME="FontCharSet" VALUE="204">

<PARAM NAME="ParagraphAlign" VALUE="3">

<PARAM NAME="FontWeight" VALUE="700">

</OBJECT>

<%ElseIf objBrowser.JavaApplets Then%>

<H1>Апплет Java</H1>

<applet code="marquee.class" codebase="http://inna/scripts/web/l5" align="baseline" HEIGHT=40 WIDTH=400>

<PARAM NAME="CAPTION" VALUE="Java is Cool!">

</APPLET>

<%Else%>

<!-- Чисто текстовая программа просмотра -->

<H1>Никакие компоненты не поддерживаются!</Н1>

<%End If%>

</CENTER> </BODY> </HTML>

Компонент Ad Rotator. Компонент Ad Rotator (ротация рекламных объявлений) специально предназначен для узлов, продающих рекламную площадь. Он позволяет управлять ротацией рекламных картинок на узле. Ad Rotator считывает информацию о рекламных объявлениях из специального текстового файла и указывает, какое объявление следует показывать и как долго. Использование данного компонента сводится к его созданию и чтению текстового файла, как в следующем фрагменте кода:

<%

Dim Ad

Set Ad = Server.CreateObject("MSWC.AdRotator")

Response.Write Ad.GetAdvertisement("ADS.TXT")

%>

Файл, считываемый компонентом Ad Rotator, имеет четко заданную структуру, которая определяет, какое изображение выводить и какую часть времени его показывать, а также обеспечивает гипертекстовую ссылку, активизируемую при щелчке данного объявления. От Вас требуется только составить текстовый файл определенного формата, а компонент сделает все остальное.

Компонент Content Linking. Компонент Content Linking (компонент связывания содержания) предназначен для публикаций электронных журналов и газет. Он связывает вместе несколько Web-страниц, позволяя их прокручивать. Как и Ad Rotator, компонент Content Linking для создания публикации использует текстовый файл. Этот файл, известный как список информационных ссылок (Content Linking List), содержит список связанных Web-страниц и их описаний. Использование данного компонента сводится к его созданию и последующему считыванию ассоциированного текстового файла, как в следующем фрагменте кода:

<%Set objLinker = Server.CreateObject("MSWC.NextLink")%>

Когда публикация скомпонована, для перемещения по страницам используются методы GetNextURL и GetPreviousURL, а описания каждой конкретной страницы можно получить, вызвав методы GetNextDescription и GetPreviousDescription. Полученные значения служат для генерации ссылок на другие страницы публикации. Пример такой ссылки:

<А HREF="<%=objLinker.GetNextURL%>">

<%=objLinker.GetNextDescriptiion%> </A>

Использование других компонентов ActiveX. Кроме использования компонентов, поставляемых с Visual InterDev, Вы можете создавать свои собственные компоненты ActiveX для ASP. Когда такой компонент разработан, работать с ним можно посредством метода CreateObject объекта Server. Все, что нужно - это указать его ProgID.

Написание собственных компонентов позволяет расширить возможности ASP.

Доступ к базам данных.

Хотя доступ к базам данных средствами ADO уже обсуждался, уделим еще некоторое время этому вопросу. Дело в том, что приведенные ранее примеры работоспособны, только если на сервере создан источник данных ODBC. Его создание обычно производится апплетом Панели управления Windows, который при удаленной работе с сервером оказывается недоступен. Для выхода из этой ситуации применяют файловый DSN (Data Source Name), создав который, можно скопировать файл с расширением .dsn в тот же каталог, что и сценарий, обращающийся к базе данных. В листинге 4.12 приведен пример файла для доступа к базе данных MS Access, а в листинге 4.13 - для доступа к БД MySQL.

Листинг 4.12. Файл для доступа к БД MS Access'97.

[ODBC]

DRIVER=Microsoft Access Driver (*.mdb)

UID=admin

UserCommitSync=Yes

Threads=3

SafeTransactions=0

ReadOnly=0

PageTimeout=5

MaxScanRows=8

MaxBufferSize=512

ImplicitCommitSync=Yes

FIL=MS Access

DriverId=281

DefaultDir=C:\Inetpub\scripts\bookcd

DBQ=C:\Inetpub\scripts\bookcd\bakal1.mdb

Сценарий, использующий этот файл, приведен в листинге 4.14.

Листинг 4.13. Файл для доступа к БД MySQL.

[ODBC]

DRIVER=MySQL ODBC 3.51 Driver

UID=gun

STMT=

OPTION=3

PORT=

PASSWORD=

SERVER=inna

DATABASE=test

Листинг 4.14. Сценарий формирования DSN.

<%

Dim sDB, sPath, sDSNFil, sDSN, sScriptDir

'This is the entire DB path

sDB = "C:\Inetpub\scripts\bookcd\bakal1.mdb"

' Retrieve the script directory

sScriptDir = Request.ServerVariables("SCRIPT_NAME")

sScriptDir = StrReverse(sScriptDir)

sScriptDir = Mid(sScriptDir, InStr(1, sScriptDir, "/"))

sScriptDir = StrReverse(sScriptDir)

' Set the virtual Directory

sPath = Server.MapPath(sScriptDir) & "\"

' This is the DSN file Name for Access database

sDSNFil = "Access.dsn" ' This is the resulting DSN string

sDSN="filedsn="&sPath&sDSNFil&";DefaultDir="&sPath&";DBQ="&sPath&sDB&";"

%>

Чтобы не вставлять данный код в каждый сценарий, в котором требуется обращение к базе данных, применяют файлы включения (подобно include-файлам в языке С):

<!-- #include file ="dsn.asp" -->

<!-- #include file="adovbs.inc" -->

Заметим, что файл adovbs.inc не может быть вызван, как сценарий, хотя и содержит код. Как правило, в файлы с расширением .inc помещают часто употребляемые константы и функции, как это показано в листинге 4.15:

Листинг 4.15. Файл включения.

<%

' ADO constants include file for VBScript

'---- CursorTypeEnum Values ----

Const adOpenForwardOnly = 0

Const adOpenKeyset = 1

Const adOpenDynamic = 2

Const adOpenStatic = 3

%>

<FONT FACE="Verdana, Arial" SIZE=2>

<FORM ACTION="<% =sScript%>" METHOD=GET>

<SELECT NAME=YEAR>

<OPTION VALUE=1998 SELECTED>1998

<OPTION VALUE=1999>1999

<OPTION VALUE=2000>2000

<OPTION VALUE=2001>2001

<OPTION VALUE=2002>2002

</SELECT></FONT>

<P><INPUT TYPE="Image" SRC="images/go.gif" BORDER="0" WIDTH="35" HEIGHT="20"> </P>

</FORM>

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

Листинг 4.16. Сценарий авторизации посетителя.

<!-- #include file ="dsn.asp" -->

<!-- #include file="adovbs.inc" -->

<html><head>

<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">

<title>Идентификация пользователя</title></head>

<body BGCOLOR="#CCCCFF" TEXT="#0000FF" LEFTMARGIN="3">

<%

If not isEmpty(Session("userlevel")) then  

  Session("userlevel") = Empty

  Session("userid") = Empty

end if

user = Request.Form.Item("T1")

pswd = Request.Form.Item("T2")

b1 = Request.Form.Item("B1")

If not isEmpty(user) and not isEmpty(pswd) then  

  Set Rs = Server.CreateObject("ADODB.RecordSet")

sSQL = "SELECT Users.Pswd, Users.Access_ID, Users.User_ID FROM Users WHERE Users.Login = '"&user&"'"

Rs.Open sSQL, sDSN

if not RS.EOF then

    if RS.fields(0).value = pswd then

      Session("userlevel") = RS.fields(1).value

      Session("userid") = RS.fields(2).value

      Response.Redirect("menu.asp")

    end if  

  end if

  Session("userlevel") = 3

  Response.Redirect("menu.asp")

end if

%>

<form method="POST" action="enter.asp">

<center>

<table border="0" width="50%" cellspacing="1" cellpadding="4">

<tr><td width="100%" colspan="2" bgcolor="#000080">

<b><font size="4">Идентификация пользователя </font> </b></td> </tr>

<tr><td width="50%" align="right">Имя:</td>

<td width="50%"><input type="text" name="T1" size="20"></td>

</tr>

<tr><td width="50%" align="right">Пароль:</td>

<td width="50%"><input type="password" name="T2" size="20"></td>

</tr>

<tr><td width="100%" align="right" colspan="2">

<center><input type="submit" value="Войти" name="B1" ></td>

</tr>

</table></center>

</form></body></html>

Доступ к базам данных MySQL осуществляется аналогично, с использованием файлового источника данных (листинг 4.13) и модификации сценария доступа (листинг 4.14), где последняя строка имеет вид:

sDSN = "filedsn=" & sPath & sDSNFil & ";"

Ниже приводится аналог листинга 4.10, но обращающегося к базе данных MySQL (из примера 3.14).

Листинг 4.17. Сценарий доступа к БД MySQL.

<%@ LANGUAGE="VBScript"%>

<!-- #include file ="e14a.asp" -->

<HTML><HEAD>

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

<TITLE>Using MySQL</TITLE></HEAD><BODY>

<%

Dim objRecordset

Set objRecordset = Server.CreateObject("ADODB.Recordset")

' Устанавливаем подсоединение и выполняем запрос

objRecordset.Open "SELECT name FROM people", sDSN

%><!-- Строим список SELECT по набору данных -->

<SELECT SIZE=3>

<% Do While Not ObjRecordset.EOF %>

<!-- Создаем очередной элемент списка -->

<OPTION><%=objRecordset("name")%></OPTION>

<% objRecordset.MoveNext

Loop %>

</SELECT></BODY></HTML>


  1.  Perl. Синтаксис языка. Переменные. Регулярные выражения.

Операторы, функции и подпрограммы. Модули. CGI-программирование.

Примеры приложений. Доступ к базам данных

Прежде чем приступить к последовательному ознакомлению с новым для вас языком, должен оговориться и сказать, что все примеры да и сам язык, описание которого следует ниже - это Perl версии 5.6.0 для операционной системы Linux Red Hat версии 7.1 и ActivePerl 5.6.1 для Windows 9x/NT/2000. Существуют реализации этого языка для операционных систем OS/2 , MS-DOS, но они отстают по возможностям от оригинала, рожденного в Unix.

На пятнадцатый год своего существования Практический Язык для Извлечения текстов и Генерации отчетов (Practical Extraction and Reporting Language) по-прежнему популярен не только среди линуксоидов, но и среди Web-программистов.

Начнем с самого простого. Введите в файл test1.pl следующие строки:

#!/usr/local/bin/perl

# Содержимое файла test1.pl

print "Наше Вам с кисточкой!\n";

А теперь подробно разберем каждую строку.

#!/usr/local/bin/perl

Данная строка должна быть первой в любой Perl-программе. Она указывает системному интерпретатору, что данный файл - это Perl-программа.

# Содержимое файла test1.pl

Эта строка комментария. Она всегда начинается символом '#'.

print "Наше Вам с кисточкой!\n";

Самая последняя строка просто выводит на экран надпись "Наше Вам с кисточкой!".

Здесь слово print - это команда "вывести". Все что в кавычках - это символы, \n - перевод строки и ';' - признак конца команды. Он обязателен. В одной строке может быть несколько команд и все они должны завершаться символом ';'. После него может быть символ '#' - тогда остаток строки считается комментарием.

Чтобы этот пример заработал, вам надо иметь установленный Perl и набрать в командной строке: perl test1.plWindows) или ./test.pl (в *nix).

Синтаксис Perl.

Perl программа (скрипт) состоит из последовательности деклараций и предложений. Что должно быть обязательно декларировано, так это форматы отчетов и подпрограммы (функции). Все необъявленные переменные, массивы имеют значение 0 или null.

Декларации (объявления). Perl имеет свободный формат. Комментарии начинаются с символа '#' и продолжаются до конца строки. Декларации могут использоваться в любом месте программы так же как и предложения (statements), но действуют они только в фазе компиляции программы. Обычно их помещают или в начале или в конце программы. Декларация подпрограмм позволяет использовать имя подпрограммы как списковый оператор, начиная с момента декларирования:

sub test; # Декларация подпрограммы test

$var1 = test $0; # Использование как оператора списка.

Декларации подпрограмм могут быть загружены из отдельного файла предложением require или загружены и импортированы в текущую область имен предложением use.

Простое предложение. Простое предложение обязательно заканчивается символом ';', если только это не последнее предложение в блоке, где ';' можно опустить. Существуют операторы, такие как eval{} и do{}, которые выглядят как сложные предложения, но на самом деле это термы и требуют обязательного указания конца предложения.

Любое простое предложение может содержать модификатор перед ';'. Существуют следующие модификаторы:

if EXPR, unless EXPR, while EXPR, until EXPR

где EXPR - выражение, возвращающее логическое значение true или false. Модификаторы while и until вычисляются в начале предложения, кроме do, который выполняется первым.

if EXPR- Модификатор "если". Предложение выполняется, если EXPR возвращает true.

$var = 1;

if $var > 0 $var2 = 3; # Результат: $var2 = 3

while EXPR - Модификатор "пока". Предложение выполняется пока EXPR = true

$var = 1;

print $var++ while $var < 5; # Результат: 1234

until EXPR- Модификатор "до ". Предложение выполняется до тех пор пока EXPR = false

$var = 1;

print $var++ until $var > 5; # Результат: 12345

unless EXPR - Модификатор "если не". Обратный к if. Выражение выполняется, если EXPR = false.

$var = 1;

print $var++ unless $var > 5; # Результат: 1

Сложные предложения. Последовательность простых предложений, ограниченная функциональными ограничителями, называется блоком. В Perl это может быть целый файл, последовательность предложений в операторе eval{} или чаще всего это множество простых предложений, ограниченных круглыми скобками '{}'.

Существуют следующие виды сложных предложений:

if (EXPR) BLOCK, if (EXPR) BLOCK else BLOCK, if (EXPR) BLOCK elsif (EXPR) BLOCK ... else BLOCK

LABEL while (EXPR) BLOCK, LABEL while (EXPR) BLOCK continue BLOCK

LABEL for (EXPR; EXPR; EXPR) BLOCK, LABEL foreach VAR (LIST) BLOCK

LABEL BLOCK continue BLOCK

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

if (EXPR) BLOCK - Вычисляется логическое выражение EXPR и если true блок выполняется.

$var =1;

if ($var == 1)

{ print $var,"\n";

}

Результат: 1

if (EXPR) BLOCK else BLOCK2 - Если EXPR=true выполняется BLOCK иначе BLOCK2.

$var =2;

if ($var == 1)

{ print "\$var = 1\n";

}

else

{ print "\$var не равно 1\n";

}

Результат: $var не равно 1

if (EXPR1) BLOCK1 elsif (EXPR2) BLOCK2 ... else BLOCK - Если EXPR1=true выполняется BLOCK1 иначе если EXPR2=true выполняется BLOCK2 иначе ... иначе BLOCK.

$var = 1;

if ($var == 0)

{ print "\$var = 0\n";

}

elsif ($var == 1)

{ print "\$var = 1\n";

}

else

{ print "Не известное \$var\n";

}

Результат: $var = 1

Цикл While. Выполняет BLOCK до тех пор пока EXPR = true. Метка LABEL не обязательна и состоит из идентификатора, завершающегося символом ':'. Метка необходима при использовании внутри блока цикла управляющих операторов next, last и redo. Если метка отсутствует, то эти операторы ссылаются к началу ближайшего цикла. Блок после continue выполняется всегда перед тем, как вычисляется логическое выражение EXPR. Это подобно EXPR3 в предложении for, поэтому в этом блоке удобно изменять счетчики и флаги цикла, даже если применяется оператор next.

Операторы управления циклом. next - подобен continue в С. Переходит к началу текущего цикла, т.е. повторяет итерацию.

M1:

while ($i < 6)

{

++$i; # Увеличиваем счетчик на 1

next M1 if $i < 3; # Переходим в начало если $i < 3

++$i; # иначе увеличиваем счетчик еще раз на 1

}

continue

{

print "$i "; # Результат: 1 2 4 6

}

last - подобен оператору break в языке С. Немедленно прерывает цикл. Блок continue пропускается.

M1:

while ($i < 6)

{

++$i;       # Увеличиваем счетчик на 1

last M1 if $i > 3; # Выход из цикла если $i > 3

++$i;       # иначе увеличиваем счетчик еще раз на 1

}

continue {

print "$i "; # Результат: 2 4

}

redo - начать новый цикл, не вычисляя EXPR и не выполняя continue блок.

M1:

while ($i < 6)

{

++$i;       # Увеличиваем счетчик на 1

redo M1 if $i == 3; # Далее пропустить для $i = 3

++$i;       # иначе увеличиваем счетчик еще раз на 1

}

continue {

print "$i "; # Результат: 2 5 7

}

Цикл for. LABEL for (EXPR1; EXPR2; EXPR3) BLOCK. Оператор for полностью аналогичен оператору for в С. Перед началом цикла выполняется EXPR1, если EXPR2 = true выполняется блок, затем выполняется EXPR3.

for ($i = 2; $i < 5; ++$i){

print $i, " "; # Результат: 2 3 4

}

print "\nПосле цикла i = $i\n"; # После цикла i = 5

Цикл foreach. LABEL foreach VAR (LIST) BLOCK. Переменной VAR присваивается поочередно каждый элемент списка LIST и выполняется блок. Если VAR опущено, то элементы присваиваются встроенной переменной $_. Если в теле блока изменять значение VAR то это вызовет изменение и элементов списка т.к. VAR фактически указывает на текущий элемент списка. Вместо слова foreach можно писать просто for - это слова синонимы.

@month = ("январь","февраль","март");  # Создали массив

foreach $i (@month)

{ print $i," ";       # Результат: январь февраль март

}

foreach $i (@month)

{ $i = uc($i); # Перевели в верхний регистр

}

print @ month; # Результат: ЯНВАРЬФЕВРАЛЬМАРТ

for $i (3,5,7)

{ print "$i "; # Результат: 3 5 7

}

Блоки и оператор switch. Блок не зависимо от того имеет он метку или нет семантически представляет собой цикл который выполняется один раз. Поэтому действие операторов цикла next, last, redo - аналогично описанному выше. Блоки удобны для построения switch (переключатель) структур. В Perl нет специального оператора switch подобного языку С поэтому вы сами можете создавать удобные для вас конструкции. Опыт автора показывает что для простоты написания лучше всего подходит конструкция вида if ... elsif ... else ... хотя можно сочинить и нечто подобное:

SWITCH:

{

if ($i ==1 ) { .....; last SWITCH; }

if ($i ==2 ) { .....; last SWITCH; }

if ($i ==3 ) { .....; last SWITCH; }

$default = 13;

}

Выбирайте сами по своему вкусу.

Оператор goto. В Perl существует оператор goto. При создании больших производственных задач на последнем этапе, особенно при отработке ошибочных ситуаций конечно goto нужен.

В Perl реализовано три формы goto. goto - метка, goto - выражение и goto - подпрограмма.

goto метка - выполняет непосредственный переход на указанную метку.

goto - выражение - Вычисляет имя метки и делает соответствующий переход. Например, если мы хотим сделать переход на одну из трех меток "M1:", "M2:" или "M3:" в зависимости от значений переменной $i равной 0, 1 или 2 то это лучше сделать следующим образом:

goto ("M1", "M2", "M3")[$i];

здесь $i используется как индекс массива указанного непосредственно в выражении.

goto подпрограмма - довольно редкий случай т.к. всегда проще и надежней вызвать подпрограмму "естественным" образом.

POD операторы. Документирование программ. В Perl реализован очень удобный механизм для написания документации в момент создания программы. Для этого применяются специальные POD операторы. Если в теле программы интерпретатор встречает оператор начинающийся с символа '=' например:

= head Набор стандартных процедур

то пропускается все до слова '=cut'. Это удобно для включения длинных на несколько строк или страниц комментариев. Затем с помощью специальной программы pod можно отделить текст документации от текста программы.

Переменные.

В Perl существует три типа структур данных: скаляры, массивы скаляров и хеши (hashes) - ассоциативные массивы скаляров. Обычно элементы массивов индексируются целыми числами, первый элемент - нулевой. Отрицательное значение индекса обозначает номер позиции элемента с конца. Хеши индексируются строками символов.

Имена скаляров всегда начинаются с символа '$' - даже когда обозначают элемент массива:

$var1  # Простой скаляр 'var1'

$var1[0] # Первый элемент массива 'var1'

$var1{'first'} # Элемент с индексом 'first'

В случае использования имени массива "целиком" или его "среза" перед именем массива ставится символ '@':

@var1 #Все элементы массива var1 ($var1[0],$var1[1],..., $var1[n])

@var1[1,3,10] # Элементы $var1[1], $var1[3], $var1[10]

@var1{'first','last'} #то же что и ($var1{'first'}, $var1{'last'})

Хеш "целиком" начинается с символа '%':

%var, %key, %years

Имена подпрограмм начинаются символом '&', если из контекста не видно, что это подпрограмма:

&sub1, &test_prog, test(12)

Имена таблиц символов всегда начинаются символом '*'.

Каждый тип переменных имеет свою область памяти поэтому $var1 и $var1[0] совершенно разные переменные, хотя $var1[0] часть массива @var1. Так же @var1 и %var1 - разные массивы переменных.

Имена переменных могут содержать любые буквенно-цифровые символы за исключением пробела и табуляции. Эти символы используются в качестве разделителей. Большие и малые буквы различаются поэтому $var1 и $Var1 - разные переменные. В Perl по умолчанию имена меток и указателей файлов пишут большими буквами.

Контекст. Большое значение для правильного употребления встроенных функций имеет контекст использования результата этих функций, т.к. в противном случае они возвращают совершенно "непонятный" результат. В Perl имеется два главных контекста: скалярный и список (list). Если в левой части выражения имеется ввиду одно единственное значение, то это скалярный контекст. Если множество значений - то список:

$var1 = <>; # Прочитать одну строку файла

@var1 = <>; # Прочитать все строки файла в массив @var1

$var1 = (1,2,3); # $var = 3 - количество элементов

@var1 = (1,2,3); # Создание массива @var1 с элементами 1,2,3

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

В Perl не существует типов "строка" или "число" или "файл" или что-то еще. Это контекстно зависимый полиморфный язык для работы с текстами. Скаляр имеет логическое значение "TRUE" (истина), если это не нулевая строка или число не равное 0.

В Perl существует два типа нулевых (null) скаляров - определенные (defined) и неопределенные (undefined). Неопределенное значение возвращается, когда что-то не существует. Например, неизвестная переменная, конец файла или ошибка. С помощью функции defined() вы можете заранее обнаружить подобное состояние.

Количество элементов массива так же является скаляром и начинается символами $#. Фактически $#var1 - это индекс последнего элемента массива. Нужно помнить, что первый элемент имеет индекс 0, поэтому количество элементов определяется как $#var1+1 . Присвоение значения $#var1 изменит длину массива и разрушит "оставленные" значения. Присвоение значения элементу массива с индексом больше чем $#var1 увеличит размер массива, а присвоение ему нулевого списка - обнулит.

В скалярном контексте имя массива возвращает его длину (для списка возвращается последний элемент):

@var1 = (4, 3, 2, 1);# Присвоение значения элементам массива

$i = @var1;  # Использование скалярного контекста

print $i;  # Печать результата 4 - кол-во элементов

print @var1;  # Списковый контекст, печать всех элементов.

Для принудительного получения скалярного значения удобно применять функцию scalar():

print scalar(@var1);# Вывод длины массива а не его значений

Хеш в скалярном контексте возвращает "true", если существует хотя бы одна пара "ключ-значение". Фактически возвращается строка типа 2/8 где 8 - количество выделенных "ячеек" памяти, а 2 - количество использованных.

Конструкторы скаляров. Числа пишутся стандартно:

123

123.123

0.12

.12E-10

0xABCD  # Шестнадцатиричная запись

0377  # Если 0 в начале - восьмеричная

123_456_123 # Так тоже можно для удобства чтения.

Строки ограничиваются одинарными (') или двойными (") кавычками:

'Равняйсь, смирно!' или "Построимся и спасемся."

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

$var1{first} то же что и $var1{'first'}

Обратите внимание на то, что перед первой одинарной кавычкой должен стоять пробел, иначе строка воспримется как имя переменной, т. к. в именах разрешено использование одинарных кавычек. Запрещается в кавычках применять зарезервированные литералы __LINE__ (номер текущей строки программы), __FILE__ (текущий файл). Для обозначения конца программы можно применять литерал __END__. Весь последующий текст игнорируется, но его можно прочитать, используя указатель файла DATA.

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

В Perl есть возможность вставлять текст документа прямо в программу, используя "here-doc" (здесь текст) метод. Обозначается символами <<, за которыми идет слово-ограничитель:

print <<EOF; # Все строки до EOF - текст для печати.

Эй вы трое, идите оба сюда!

Что стоишь! Я тебе говорю!!

Полковник Савонькин.

EOF

Конструкторы списков. Список - множество значений, перечисленных через запятую и заключенных в круглые скобки. В списковом контексте список возвращает последний элемент списка:

@var1 = (1, 2, 'привет', 1.2); # Присвоить значение элементам.где

 $var1[0] = 1,

$var1[1] = 2,

$var1[2] = 'привет'

 $var1[3] = 1.2

$var1 = (1, 2, 'привет', 1.2);

а здесь $var1 = 1.2 т.е. последнее значение списка.

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

@s1 = (1, 2, 3); #  Первый список

@s2 = (6, 7, 8); # Второй

@s = (0, @s1, 4, 5, @s2, 9, 10); # Включаем списки @s1 и @s2

print @s; # Результат: 012345678910  - значения без пробелов.

Список без элементов обозначается, как (), и называется нуль-списком. Списковое выражение можно употреблять как имя массива, но при этом брать в круглые скобки:

print ('январь','февраль','март')[1];

Результат: февраль

Список может быть присвоен списку, только если каждый элемент в списке в левой части выражения допустим по типу списку в правой части:

($a, $b, $c) = (1, 2, 3); # $a = 1, $b

Встроенные переменные Perl.

Описанные ниже переменные имеют в Perl специальные значения. Они обозначаются несколько непривычно для "глаза" программистов, т.к. состоят обычно только из двух символов, причем первый это '$' символ, с которого начинаются имена всех переменных, и произвольный часто не буквенно-цифровой символ. Если вы хотите пользоваться их "нормальными" буквенными синонимами, то вам нужно указать в начале программы:

use English;

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

$_ ($ARG) - переменная - по умолчанию для операторов ввода и поиска. То есть если в качестве аргумента не указана никакая переменная, то используется именно эта.

$цифра - содержит найденную в последнем поиске подстроку, когда шаблон содержит метасимволы в круглых скобках. Цифра - это номер скобок. Первая подстрока - номер 1.

$& ($MATCH) - найденная подстрока в последнем поиске по шаблону.

$` - подстрока, предшествующая найденной подстроке.

$' ($POSTMATCH) - подстрока, последующая за найденной подстрокой.

$+ ($LAST_PAREN_MATCH) - подстрока, найденная в поиске с выбором по "или".

$* ($MULTILINE_MATCHING) - если ее значение установить равным 1, то переменная, в которой осуществляется поиск, будет считаться многострочной, т.е. содержащей символы '\n' - перевод строки. Если значение равно 0, то переменная считается однострочной.

$. ($INPUT_LINE_NUMBER), ($NR) - номер прочитанной строки последнего оператора ввода. Закрытие файла вызывает очистку значения этой переменной.

$/ ($RS), ($INPUT_RECORD_SEPARATOR) - символ - признак конца входной строки. По умолчанию это '\n'

$| ($OUTPUT_AUTOFLUSH) - если присвоить этой переменной ненулевое значение, то будет сброс буфера вывода после каждой операции вывода. Значение по умолчанию - 0

$, ($OFS), ($OUTPUT_FIELD_SEPARATOR) - символ, добавляемый оператором print после каждого элемента из списка параметров.

$\ ($ORS), ($OUTPUT_RECORD_SEPARATOR) - символ, добавляемый print после вывода всех параметров.

$" ($LIST_SEPARATOR) - аналогичен "$,", но добавляется после каждого элемента массива, указанного в "....".

$# ($OFMT) - формат по умолчанию для вывода чисел.

$% ($FORMAT_PAGE_NUMBER) - формат по умолчанию для вывода номеров страниц.

$= ($FORMAT_LINES_PER_PAGE) - длина одной страницы. По умолчанию 60 строк.

$- ($FORMAT_LINES_LEFT) - количество оставшихся строк на странице.

$~ ($FORMAT_NAME) - имя формата текущего вывода. По умолчанию имя указателя.

$^ ($FORMAT_TOP_NAME) - имя текущего формата для заголовка страницы.

$: ($FORMAT_LINE_BREAK_CHARACTERS) - символы переноса строки для многострочных полей. В строке формата такие поля начинаются с '^'. По умолчанию '\n-'.

$^L ($FORMAT_FORMFEED) - символ перевода формата (листа). По умолчанию '\f'.

$^A ($ACCUMULATOR) - текущее значение аккумулятора функции write() для format(). Значение этой переменной можно увидеть только при использовании функции formline(), т.к. write() очищает ее после каждого вывода.

$? ($CHILD_ERROR) - данная переменная содержит статус завершения таких процессов как: закрытие pipe, завершение функций system(), wait() и `...`.

$! ($ERRNO $OS_ERROR) - в числовом контексте возвращает код ошибки errno. В строковом - строку сообщения об ошибке. Можно принудительно присвоить этой переменной код ошибки, что бы получить системное сообщение для данного кода или установить код завершения для функции die().

$@ ($EVAL_ERROR) - сообщение об ошибке последней команды eval().

$$ ($PID), ($PROCESS_ID) - номер текущего процесса.

$O ($PROGRAM_NAME) - имя файла программы.

$[ - номер первого элемента массива или символа строки. Значение по умолчанию - 0.

$] ($PERL_VERSION) - строка - сообщение версии Perl. Печатается по команде perl -v В числовом контексте это номер версии плюс номер модификации / 1000.

$^T ($BASETIME ) - Время в секундах с начала 1970 года старта текущей программы.

$^X ($EXECUTABLE_NAME) - команда запуска Perl. Аналогично argv[0] в С.

$ARGV - имя текущего файла, читаемого оператором '<>'.

@ARGV - массив параметров строки запуска программы. Внимание! @#ARGV - меньше количества параметров на 1, т.к. $ARGV[0] это первый параметр (не имя программы).

@INC - список директорий диска, которые просматривает Perl для выполнения команд do, require или use.

%INC - этот хеш содержит имена директорий для имен использованных файлов командами do или require. Ключ - имя файла, а значение - директория.

$ENV{выражение} - хеш %ENV содержит значения переменных окружения. Изменение этих значений вызывает изменение окружения для процессов потомков.

$SIG{выражение} - хеш %SIG содержит имена подпрограмм для таких системных сигналов как INT, QUIT, PIPE, ... Значение 'DEFAULT' - для системной обработки. 'IGNORE' - игнорировать данный сигнал.

Регулярные выражения (шаблоны).

Регулярные выражения в Perl чаще всего используются в операторах поиска и замены таких как s/, m/, операторах связки =~ или != и т.д. Все эти операторы имеют схожие опции:

i 

- не различать строчные и заглавные буквы.

m 

- считать строку многострочной.

s 

- однострочная строка.

x 

- расширенный синтаксис (использование пробелов и комментариев)

Эти опции, обозначаемые как '/x', можно использовать внутри шаблонов, используя конструкцию (?...). В шаблонах используются следующие метасимволы (символы, обозначающие группы других символов):

\ 

- считать следующий метасимвол как обычный символ.

^ 

- начало строки

. 

- один произвольный символ. Кроме '\n' - конец строки.

$ 

- конец строки

| 

- альтернатива (или)

() 

- группировка

[] 

- класс символов

Метасимволы имеют модификаторы (пишутся после метасимвола):

* 

- повторяется 0 или большее число раз

+ 

- -//- 1 или большее число раз

? 

- 1 или 0 раз

{n} 

- точно n раз

{n,} 

- по меньшей мере раз

{n,m} 

- не меньше n, но и не больше m

Во все других случаях фигурные скобки считаются обычными (регулярными) символами. Таким образом '*' эквивалентна {0,} , '+' - {1,} и '?' - {0,1}. n и m не могут быть больше 65536.

По умолчанию действие метасимволов "жадно" (greedy). Совпадение распространяется столько раз, сколько возможно, не учитывая результат действия следующих метасимволов. Если вы хотите "уменьшить их аппетит", то используйте символ '?'. Это не изменяет значение метасимволов, просто уменьшает распространение. Таким образом:

*? 

- станет 0 и более

+? 

- 1 и более

?? 

- 0 или 1 раз

{n}? 

- точно n раз

{n,}? 

- не меньше n раз

{n,m}? 

- больше или равно n и меньше m раз

Шаблоны работают так же, как и двойные кавычки, поэтому в них можно использовать `\` - символы (бэкслэш-символы):

\t 

- символ табуляции

\n 

- новая строка

\r 

- перевод каретки

 

- перевод формата

\v 

- вертикальная табуляция

\a 

- звонок

\e 

- escape

\033 

- восьмеричная запись символа

\x1A 

- шестнадцатеричная

\c[ 

- control символ

\l 

- нижний регистр следующего символа

\u 

- верхний регистр -//-

\L 

- все символы в нижнем регистре до \E

\U 

- в верхнем -//-

\E 

- ограничитель смены регистра

\Q 

- отмена действия как метасимвола

Дополнительно в Perl добавлены следующие метасимволы:

\w 

- алфавитно-цифровой или '_' символ

\W 

- не -//-

\s 

- один пробел

\S 

- один не пробел

\d 

- одна цифра

\D 

- одна не цифра

Обратите внимание, что все это "один" символ. Для обозначения последовательности применяйте модификаторы. Так:

\w+ 

- слово

\d+ 

- целое число

[+-]?\d+ 

- целое со знаком

[+-]?\d+\.?\d*

- число с точкой

Существуют мнимые метасимволы, обозначающие места смены значения:

\b 

- граница слова

\B 

- не граница слова

\A 

- начало строки

\Z 

- конец строки

\G 

- конец действия m//g

Граница слова (\b) - это мнимая точка между символами \w и \W. Внутри класса символов '\b' обозначает символ backspace (стирания). Метасимволы \A и \Z - аналогичны '^' и '$', но если начало строки '^' и конец строки '$' действуют для каждой строки в многострочной строке, то \A и \Z обозначают начало и конец всей многострочной строки.

Если внутри шаблона применяется группировка (круглые скобки), то номер подстроки группы обозначается как '\цифра'. Заметьте, что за шаблоном в пределах выражения или блока эти группы обозначаются как '$цифра'. Существуют и дополнительные переменные:

$+ 

- обозначает последнее совпадение

$& 

- все совпадение

$` 

- все до совпадения

$' 

- все после совпадения

Листинг 5.1. Переменные совпадений.

$s = "Один 1 два 2 и три 3";

if ($s =~ /(\d+)\D+(\d+)/) {

print "$1\n";    # Результат '1'

print "$2\n";    # '2'

print "$+\n";    # '2'

print "$&\n";    # '1 два 2'

print "$`\n";    # 'Один '

print "$'\n";    # ' и три 3'

}

Perl версии 5 содержит дополнительные конструкции шаблонов:

(?#комментарий) 

- комментарий в теле шаблона.

(?:шаблон) 

- группировка как и '( )', но без обратной ссылки

(?=шаблон) 

- "заглядывание" вперед. Например /\w+(?=\t)/ соответствует слову, за которым идет табуляция, но символ '\t' не включается в результат.

(?!шаблон)

- "заглядывание" вперед по отрицанию.

Листинг 5.2. Конструкции шаблонов.

$s = "1+2-3*4";

if ($s =~ /(\d)(?=-)/)  # Найти цифру за которой стоит '-'

{ print "$1\n";   # Результат '2'

}

else { print "ошибка поиска\n";}

$s = "1+2-3*4";

if ($s =~ /(\d)(?!\+)/) # Найти цифру за которой не стоит '+'

{ print "$1\n";   # Результат '2'

}

else { print "ошибка поиска\n";}

Правила регулярного выражения. (regex)

  1.  Любой символ обозначает себя самого, если это не метасимвол. Если вам нужно отменить действие метасимвола, то поставьте перед ним '\'.
  2.  Строка символов обозначает строку этих символов.
  3.  Множество возможных символов (класс) заключается в квадратные скобки '[]', это значит, что в данном месте может стоять один из указанных в скобках символов. Если первый символ в скобках это '^' - значит, ни один из указанных символов не может стоять в данном месте выражения. Внутри класса можно употреблять символ '-', обозначающий диапазон символов. Например, a-z - одна из малых букв латинского алфавита, 0-9 - цифра.
  4.  Все символы, включая специальные, можно обозначать с помощью '\' как в языке С.
  5.  Альтернативные последовательности разделяются символом '|' Заметьте что внутри квадратных скобок это обычный символ.
  6.  Внутри регулярного выражения можно указывать "подшаблоны" заключая их в круглые скобки и ссылаться на них как '\номер' Первая скобка обозначается как '\1'.

Операторы и приоритеты.

В Perl ассоциативность и приоритетность операторов аналогична языку С. Ниже перечислены все операторы в порядке уменьшения приоритета с указанием ассоциативности.

ассоц.

операторы

левая 

термы и левосторонние списковые операторы

левая 

->

- 

++ --

правая 

**

правая 

! ~ \ унарные + и -

левая 

=~ !~

левая 

* / % x

левая 

+ - .

левая 

<< >>

- 

именованные унарные операторы

- 

< > <= >= lt gt le ge

- 

== != <=> eq ne cmp

левая 

&

левая 

| ^

левая 

&&

левая 

||

- 

..

правая 

?:

правая 

= += -= *= и т.д.

левая 

, =>

- 

правосторонние списковые операторы

левая 

not

левая 

and

левая 

or xor

Термы и левосторонние списковые операторы. Любой терм имеет самый высокий приоритет. К терму относятся переменные, кавычки и их операторы, арифметические и логические выражения в скобках, любые функции с параметрами в скобках. Фактически таких функций нет, так как это просто унарные и списковые операторы. Просто они ведут себя подобно функциям с параметрами в скобках. Если после любого спискового оператора (print(), и т.д.) или унарного оператора (chdir(), и т.д.) следует левая круглая скобка, то операторы внутри скобок имеют наивысший приоритет. Так же как и обычные функции.

Если скобки отсутствуют, то приоритет списковых операторов или наивысший или наименьший в отношении операторов справа или слева от него:

@i = ('a ','b ', print 'c ', 'd ');

print "\n",@i,"\n"; #Результат: c d и a b 1

Здесь мы имеем списковый оператор print. Для запятых слева от него он имеет наименьший приоритет, но повышает приоритет правой запятой. Поэтому правая запятая воспринимается как параметр для print и печатается 'c d', а левая просто записывает код завершения операции в массив @i и последний print показывает это.

Оператор '->' Как и в С - это инфиксный оператор переадресации. Если справа от него стоит [...] или {...} выражение, то правая часть может быть непосредственной или символической ссылкой на массив или хеш. В противном случае правая сторона это метод или простой скаляр, содержащий имя метода, а правая - или объект, или имя класса.

Операторы ++ (инкремент) и -- (декремент). Работают, как и в С. Если оператор - перед переменной, то значение переменной изменяется на 1 и полученное значение используется. Если после - то ее величина изменяется после применения. Употребление инкремента к строковым переменным в Perl имеет особенность. Каждый символ остается в своем классе (большие, малые, цифры) и учитывается перенос предыдущего символа. Таким образом, строковые переменные с цифрами работают как числовые переменные:

print ++($i = "09");     # Результат "10"

print ++($i = "a9");     # "b0"

print ++($i = "az");     # "ba"

print ++($i = "aZ");     # "bA"

Оператор ** (возведение в степень):

print 4**2     # Результат 16

print -4**2     # Результат -16 т.е. -(4**2)

Унарные операторы. 

'!' 

- логическое отрицание

'-' 

- арифметический минус

'~' 

- побитная инверсия (дополнение до 1)

'+' 

- арифметический плюс

'\' 

- получение ссылки на переменную (как & в С)

Операторы "привязки" =~ и !=. Эти оригинальные операторы имеют очень широкое применение в Perl. Оператор =~ логически связывает левую часть выражения с патерном (pattern - образец, шаблон) в правой. По умолчанию поиск или изменение по патерну выполняется в переменной $_. Операторы привязки позволяют делать это с любой переменной, указанной в левой части. Логическим результатом будет успех операции. Если в правой части вместо патерна присутствует выражение, то результат этого выражения воспринимается как патерн. Однако это не очень эффективно, т.к. патерн будет компилироваться во время исполнения программы, что заметно снизит быстродействие. Оператор != аналогичен =~, только результат совпадения инвертируется (логическое "нет").

Мультипликативные операторы. 

'*' 

- арифметическое умножение

'/' 

- арифметическое деление

'%' 

- арифметический модуль

'x' 

- оператор повторения

'x' в скалярном контексте возвращает строку левой части, повторенную величиной, указанной в правой части. В списковом контексте, если в левой части список, то в круглых скобках - повторенный список:

print '*' x 5;     # Результат '*****'

print (1,2) x 3; # Результат 121212

Аддитивные операторы. 

'+' 

- арифметический плюс

'-' 

- арифметический минус

'.' 

- конкатенация (объединение) строк

Операторы сдвига. 

'<<' 

- Сдвигает побитно влево значение выражения в левой части на количество бит, указанное в правой.

'>>' 

- Сдвигает побитно вправо значение выражения в левой части на количество бит указанное в правой

Именованные унарные операторы. Фактически это функции с одним аргументом. Круглые скобки можно опускать.

Операторы отношений. 

'<' 

- арифметическое меньше

'>' 

- арифметическое больше

'<=' 

- арифметическое меньше или равно

'>=' 

- арифметическое больше или равно

'lt' 

- строковое меньше

'gt' 

- строковое больше

'le' 

- строковое меньше или равно

'ge' 

- строковое больше или равно

Операторы равенства. 

'==' 

результат true если левая часть равна правой (равно)

'!=' 

- не равно

'<=>' 

- -1 если левая часть меньше правой, 0 если равна,

1 если больше.

'eq' 

- строковое равно

'ne' 

- строковое не равно

'cmp' 

- как и '<=>' применительно к строкам

Операторы работы с битами. 

'&' 

- побитное AND

'|' 

- побитное OR

'^' 

- побитное XOR

Логические операторы && (AND) и || (OR). 

'&&' 

- если левое выражение возвращает false, правое не выполняется.

'||' 

- если левое выражение возвращает true, правое не выполняется.

Отличие от подобных операторов в С заключается в том, что в С возвращаемое значение либо 0, либо 1, тогда как в Perl возвращается результат выражения.

Оператор диапазона '..' Результат его работы зависит от контекста. В списковом контексте результат есть список с элементами, первый элемент которого это левое выражение и последнее - правое. Значение каждого элемента внутри списка увеличивается на 1. Данный оператор удобен для небольших циклов, т.к. память отводится для всего списка целиком. Поэтому будьте внимательны и не задавайте слишком большой диапазон.

for $i (1..4)

{ print "$i "; # Результат: 1 2 3 4

}

В скалярном контексте результат - логическое значение. Каждая '..' операция устанавливает свое собственное состояние. Это false до тех пор, пока левый операнд false. Как только он стал true, результат - true до тех пока правый true, после чего опять - false. Если вы не хотите проверять правый операнд, то используйте оператор '...'.

Правый операнд не вычисляется, пока результат false и левый операнд не вычисляется, пока результат true. Приоритетность оператора '..' немного ниже чем '&&' и '||'. Возвращаемое значение если flase - нулевая строка, если true - порядковый номер, начиная с 1. Порядковый номер обнуляется для каждого нового диапазона.

@abc = ('a'..'z'); # Массив малых букв латинского алфавита

@digits = (0..9);     # Массив цифр

Условный оператор '?:' Этот оператор работает так же как и в С. Если выражение перед '?' истинно, то выполняется аргумент перед ':' - иначе после ':'.

$i = 1;

$i > 1 ? print "больше" : print "меньше"; #Результат: меньше

Операторы присваивания. '=' - обычный оператор "присвоить" правое значение переменной слева. Вся эта группа операторов подобна операторам С, т.е.

$i += 2; #эквивалентно $i = $i + 2;

Остальные операторы этой группы работают аналогично. Допустимы следующие операторы:

**=, +=, -=, .=, *=, /=, %=, x=, &=, |=, ^=, <<=, >>=, &&=, ||=

Приоритет всей этой группы операторов равен приоритету '='.

Оператор ',' (запятая) В скалярном контексте выполняется левый аргумент, результат игнорируется, затем правый, и его результат есть результат действия оператора. В списковом контексте это разделитель элементов списка, включает указанные элементы в список.

Операторы not, and, or, xor Оператор логическое not (отрицание). - унарный not возвращает противоположное значение, полученное выражением справа. Он эквивалентен '!'.

Оператор логическое and (И). Выполняет логическую конъюнкцию двух выражений. Эквивалентен '&&', но имеет очень низкий приоритет и "краткость" действия, т. е. если левое выражение равно false - правое не выполняется.

Логическое or (ИЛИ). Выполняет логическую дизъюнкцию двух выражений. Эквивалентен '||', но имеет очень низкий приоритет и "краткость" действия, т. е. если левое выражение равно true - левое не выполняется.

Логическое xor (исключающее ИЛИ). Выполняет логическое исключающие или. Всегда выполняются оба правое и левое выражение.

В Perl отсутствуют операторы языка С, такие как:

унарное & 

- получить адрес. Для этого применяется '\'.

унарный * 

- переадресация.

(TYPE)

- совмещение типов.

Операторы ограничители строк. Обычно ограничителями строк мы считаем литералы, но в Perl это операторы, выполняющие разного рода интерполяцию и поиск по шаблону. Вы можете сами задавать удобные для вас ограничители. В следующей таблице приведен полный перечень вариантов. Фигурные скобки '{}' обозначают любой символ, используемый для ограничителя. В случае использования скобок (круглых '( )', квадратных '[ ]', фигурных '{ }', угловых '< >') в начале ставится открывающаяся скобка, а в конце закрывающая.

По умолчанию

Полное

Функция

Интерполяция

'' 

q{}

Literal

нет

"" 

qq{}

Литерал

да

`` 

qx{}

Команда

да

qw{}

Список слов

нет

// 

m{}

Шаблон

да

s{}{}

Подстановка

да

tr{}{}

Трансляция

нет

В строках, допускающих интерполяцию, имена переменных, начинающиеся с символов '$' или '@' - интерполируются, т.е. в строку вставляется значение строки или массива. Данные последовательности символов имеют специальное значение:

\t 

символ табуляции

\n 

символ новой строки

\r 

возврат

\f