русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

Аутентификация с помощью PHP и MySQL.


Дата добавления: 2013-12-23; просмотров: 1717; Нарушение авторских прав


Таблица 6.6. Режимы файла для функции fopen

Таблица 6.5. Продолжение.

Таблица 6.4. Операторы Сравнения

Таблица 6.3. Логические операторы

Логические операторы.

Table 6.2.Бинарные Операторы

Таблица 6.1. Арифметические операторы

пример название результат
$a + $b Сложение Сумма $a и $b.
$a - $b Вычитание Вычитает $b из $a.
$a * $b Умножение Произведение $a и $b.
$a / $b Деление Деление $a на $b.
$a % $b Остаток деления Остаток от деления $a на $b.

Оператор деления("/") возвращает целую величину(результат целочисленного деления) если оба оператора - целые (или строка преобразованная в целое). Если каждый операнд является величиной с плавающей запятой, выполнится деление с плавающей запятой.

Операторы строк.B действительности есть только один оператор - конкатенации (".").

$a = "Hello ";

$b = $a . "World!"; // теперь $b = "Hello World!"

Операторы присваивания.Основным оператором присваивания является "=". Это означает, что левый операнд получает значение выражения справа (собирательное присваивание). Значением выражения присваивания является присваиваемая величина. Так что если "$a = 3", то это 3.

$a = ($b = 4) + 5; // теперь $a равно 9, а $b стало равным 4.

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

$a = 3; $a += 5; // теперь $a равно 8

$b = "Hello ";



$b .= "There!"; // теперь $b равно "Hello There

Бинарные Операторы (Побитовые Логические Операторы).Бинарные Операторы позволяют вам изменять биты в целых числах.

пример название результат
$a & $b И Будут установлены биты, которые были установлены и в $a и в $b. $a=5; /* 0101 */ $b=12; /* 1100 */ $c=$a & $b; /* $c будет равно 4 (0100) */
$a | $b Или Будут установлены биты, установленные в $a или $b . $a=5; /* 0101 */ $b=12; /* 1100 */ $c=$a|$b; /* $c будет (1101) */
~ $a Не Будут установлены не_присутствующие в $a биты (реверс) $a=5; /* 0101 */ ~ $a /* $a будет равно x (1010) */
пример название результат
$a and $b И Истина, если истинны $a и $b.
$a or $b Или Истина, если истинны $a или $b.
$a xor $b Или Истина, если истинны $a или $b, но не оба.
! $a Не Истина, если не истинно $a.
$a && $b И Истина, если истинны и $a и $b.
$a || $b Или Истина, если истинны $a или $b.

Разница двух различных вариантов операторов "and" и "or" - в различии приоритетов.

Операторы Сравнения.Операторы Сравнения позволяют Вам сравнивать две величины.

пример название результат
$a == $b равно истина, если $a эквивалентно $b.
$a != $b Не равно Истина, если $a не эквивалентно $b.
$a < $b Меньше чем Истина если $a меньше чем $b.
$a > $b Больше чем Истина если $a больше $b.
$a <= $b Меньше или равно Истина, если $a меньше или равно $b.
$a >= $b Больше или равно Истина, если $a больше или равно $b.

Регулярные выражения.Регулярные выражения используются для сложного манипулирования строками в PHP. Функции, которые поддерживают регулярные выражения:

ereg()

ereg_replace()

eregi()

eregi_replace()

split()

Все эти функции принимают строку регулярного выражения как их первый параметр. Для полного описания регулярных выражений см. соответствующие разделы руководства (regex), в каталоге regex дистрибутива PHP.

Примеры регулярных выражений

ereg("abc",$string); /* Возвращает 'истина', если "abc" найдено в $string. */

ereg("^abc",$string);

/* Возвращает 'истина', если "abc" найдено в начале $string. */

ereg("abc$",$string);

/* Возвращает 'истина', если "abc" найдено в конце $string.*/

eregi("(ozilla.[23]|MSIE.3)",$HTTP_USER_AGENT);

/* Возвращает 'истина', если браузер клиента - Netscape 2, 3 или MSIE 3.*/

ereg("([[:alnum:]]+) ([[:alnum:]]+) ([[:alnum:]]+)",

$string,$regs);

/* Помещает три слова - $regs[1], $regs[2] и $regs[3], разделенные пробелом. */

ereg_replace("^","<BR>",$string);

/* Устанавливает тег <BR> в начало строки $string. */

ereg_replace("$","<BR>",$string);

/* Устанавливает тег <BR> в конец строки $string. */

ereg_replace("\n","",$string);

/* Отсекает символ "возврат каретки" в строке $string. */

Встроенные функции

Их очень много (более 1200!), и, чтобы не дублировать справочники, самые популярные рассматриваются в примерах.

Работа с файлами.

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

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

Расмотрим работу с файлами на примере сбора заказов. Форма заказа имеет вид:

Листинг 6.1. Form.htm - форма заказа.

<html><head><title> Auto Parts</title></head><body>

<h1> Auto Parts</h1><h2>Order Form</h2>

<form action="processorder.php" method=post><table border=0>

<tr><td width=150>Item</td><td width=15>Quantity</td></tr>

<tr><td>Tyres</td><td <input type="text" name="tyreqty" size=3 maxlength=3></td></tr>

<tr><td>Oil</td><td><input type="text" name="oilqty" size=3 maxlength=3></td></tr>

<tr><td colspan=2 align=center><input type=submit value="Submit Order"></td></tr>

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

Отображение переменных формы производит следующий сценарий:

Листинг 6.2. processorder.php - обработка формы.

<html><head><title> Auto Parts: Order Results</title></head><body>

<h1>Auto Parts</h1><h2>Order Results</h2>

<?

echo "<p>Order processed at "; // Start printing order

echo date("H:i, jS F");

echo "<br><p>Your order is as follows: <br>";

echo $tireqty." tires<br>";

echo $oilqty." bottles of oil<br>";

$totalqty = 0; $totalamount = 0.00;

define("TYREPRICE", 100); define("OILPRICE", 10);

$totalqty = $tyreqty + $oilqty;

$totalamount = $tyreqty * TYREPRICE + $oilqty * OILPRICE;

$totalamount = number_format($totalamount, 2);

echo "<br>\n Items ordered: ".$totalqty."<br>\n";

echo "Subtotal: $".$totalamount."<br>\n";

$taxrate = 0.10; // local sales tax is 10%

$totalamount = $totalamount * (1 + $taxrate);

$totalamount = number_format($totalamount, 2);

echo "Total including tax: $".$totalamount."<br>\n";

?></body></html>

Использование функции date().Функция date() принимает два аргумента, один из которых является необязательным. Первый аргумент представляет собой строку формата, а второй, необязательный, — метку времени UNIX. Если метка времени не указана, то функция date() обрабатывает текущую дату и время. Она возвращает отформатированную строку, содержащую дату. Типовой вызов функции выглядит так:

echo date("jS F Y");

Вывод этого выражения имеет вид "31th July 2001". Коды форматирования, используемые функцией date(), Перечислены в табл. 6.5.

Таблица 6.5 Коды форматирования РНР-функции date()

Код Описание
а Утро или время после полудня, с двумя строчными символами, "am" или "pm,"
А Утро или время после полудня, с двумя прописными символами, "AM" или "PM".
В Internet-время Swatch — универсальная временная схема. Более подробно о ней можно узнать на сайте http://www.swatch.com.
d День месяца в виде двузначного числа с ведущим нулем. Диапазон значений — от "01" до "31".
D День недели в виде трехбуквенной аббревиатуры. Диапазон значений — от "Mon" (понедельник) до "Sun" (воскресенье).
F Месяц в полнотекстовом формате. Диапазон значений — от "January" до "December".
g Часы в 12-часовом формате без ведущих нулей. Диапазон значений — от "1" до "12".
G Часы в 24-часовом формате без ведущих нулей. Диапазон значений — от "0" до "23".
h Часы в 12-часовом формате с ведущими нулями. Диапазон значений — от "01" до "12"
H Часы в 24-часовом формате с ведущими нулями. Диапазон значений — от "00" до "23"
i Минуты с ведущими нулями. Диапазон значений — от "00" до "59".
I Переход на летнее время, представленный значением логического типа. Если переход на летнее время установлен, функция возвращает значение "1", иначе — "0".
j День месяца в виде числа без ведущих нулей. Диапазон значений — от "1" до "31".
I День недели в полнотекстовом формате. Диапазон значений — от "Monday" (понедельник) до "Sunday" (воскресенье).
L Високосный год, представленный значением логического типа. Функция возвращает значение "1", если дата принадлежит високосному году, и "0" — в противном случае.
Код Описание
L Високосный год, представленный значением логического типа. Функция возвращает значение "1", если дата принадлежит високосному году, и "0" — в противном случае.
m Месяц в двузначном числовом формате с ведущими нулями. Диапазон значений — от "01" до "12".
M Месяц в виде трехбуквенной аббревиатуры. Диапазон значений — от "Jan" (январь) до "Dec" (декабрь).
n Месяц в виде числа без ведущих нулей. Диапазон значений — от "1" до "12".
s Секунды с ведущими нулями. Диапазон значений от "00" до "59".
S Порядковый суффикс для дат в двухбуквенном формате. Он может принимать значение "st", "nd", "rd" или "th" в зависимости от числа, за которым он следует.
t Полное количество дней в месяце. Диапазон значений — от "28" до "31".
Т Временная зона сервера, заданная в трехбуквенном формате, например, "EST".
U Число секунд с 1 января 1970 г. до текущего момента; его также называют меткой времени UNIX для текущей даты.
w День недели в виде числа. Диапазон значений — от "0" (воскресенье) до "6" (суббота).
У Год в двузначном формате, например, "00".
Y Год в четырехзначном формате, например, "2000".
z День года в виде числа. Диапазон значений — от "0" до "365".
Z Смещение текущей временной зоны в секундах. Диапазон значений — от "-43200" до "43200".

Обзор обработки файлов.Запись данных в файл реализуется в три шага:

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

2. Запись данных в файл.

3. Закрытие файла.

Аналогично, считывание данных из файла также связано с выполнением трех шагов:

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

2. Считывание данных из файла.

3. Закрытие файла.

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

Открытие файла.Для открытия файла в среде РНР используется функция fopen(). При открытии файла необходимо указать режим его использования.

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

При открытии файла следует принять три решения:

1. Файл можно открыть только для чтения, только для записи или для чтения и за­писи.

2. При выполнении записи в файл можно перезаписать любое существующее содер­жимое файла либо же дописать новые данные в конец файла.

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

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

$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", "w');

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

Первым параметром должен быть файл, который необходимо открыть. При этом можно указать путь к файлу, как было сделано в приведенной выше строке кода — orders.txt находится в каталоге orders. Мы использовали встроенную переменную $DOCUMENT_ROOT PHP. Эта переменная указывает на основание дерева докумен­тов Web-сервера. Кроме того, мы использовали символ "..", означающий "родительский каталог каталога $DOCUMENT_ROOT. В целях повышения безопасности этот каталог находится вне дерева документов. Нежелательно, чтобы этот файл был доступен в Web помимо предоставляемого нами интерфейса. Этот путь называется относительным, поскольку он описывает позицию в файловой системе относительно $DOCUMENT_ROOT.

Можно было бы задать и абсолютный путь к файлу — путь от корневого каталога (/ в системе UNIX и, как правило, С:\ в системе Windows). На сервере UNIX такой путь выглядит как /home/book/orders. Проблема, связанная с подобным указанием пути, особенно в случае размещения своего сайта на чужом сервере, заключается в том, что абсолютный путь может изменяться, когда системные администраторы без предупреждения "сочтут необходимым" изменить структуру каталогов. Если путь вообще не указан, файл будет создаваться или отыскиваться в том же каталоге, в котором находится собственно сценарий. Упомянутое поведение будет иным при запуске РНР через какую-то CGI-оболочку и зависит от конфигурации сервера.

В среде UNIX в качестве разделителя каталогов используется символ прямой (с уклоном вправо) косой черты (/). На платформах Windows можно применять символы прямой или обратной косой черты. При использовании символа обратной черты они должны быть помечены как специальные (т.е. отменены), чтобы функция fopen смогла их корректно интерпретировать. Для отмены перед символом следует просто поместить дополнительный символ обратной косой черты, как показано в следующей строке:

$fp = fopen("..\\..\\orders\\orders.txt", "w") ;

Второй параметр функции fopen() — это режим файла, который должен иметь строковый тип. Этот параметр определяет, что необходимо делать с файлом. В данном случае в функцию fopen() передается параметр "w" — это означает открытие файла для записи. Режимы файла перечислены в табл. 6.6.

Режим Значение
г Режим чтения — Открытие файла для чтения, начиная с начала файла.
r+ Режим чтения — Открытие файл для чтения и записи, начиная с начала файла.
w Режим записи — Открытие файла для записи, начиная с начала файла. Если файл уже существует, его содержимое удаляется. Если файл не существует, предпринимается попытка его открытия и в результате файл создается.
w+ Режим записи — Открытие файла для записи и чтения, начиная с начала файла. Если файл уже существует, его содержимое удаляется. Если файл не существует, предпринимается попытка его открытия и в результате файл создается.
a Режим добавления — Открытие файла только для добавления (записи), начиная с конца существующего содержимого, если оно имеется. Если файл не существует, предпринимается попытка его открытия и в результате файл создается.
a+ Режим добавления — Открытие файла для добавления (записи) и чтения, начиная с конца существующего содержимого, если оно имеется. Если файл не существует, предпринимается попытка его открытия и в результате файл создается.
b Двоичный режим — Используется в сочетании с одним из остальных режимов. Его указание требуется, если файловая система различает двоичные и текстовые файлы. Операционная система Windows различает эти файлы, а UNIX - нет.

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

$fp = fopen("../../orders/orders.txt", "a");

Третий параметр функции fopen() не является обязательным. Его можно использовать, если файл необходимо искать в пути include_path (определенном в конфигурации РНР). Если это требуется, установите параметр равным 1 и не задавайте имя каталога или путь:

$fp = fopen("orders.txt", "a", 1);

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

Открытие удаленных файлов через FTP или HTTP.Используя функцию fopen(), можно открывать для чтения или записи не только локальные файлы, но и удаленные с использованием протоколов FTP и HTTP. Если используемое имя файла начинается с ftp://, открывается FTP-соединение с указанным сервером в пассивном режиме и возвращается указатель на начало файла. Если используемое имя файла начинается с http://, открывается HTTP-соединение с указанным сервером и возвращается указатель на ответ от сервера. В случае применения режима HTTP обязательно следует указывать завершающие символы косой черты в именах каталогов, как показано в следующем примере:

http://www.server.com/

но не

http://www.server.com

При второй форме указания адреса (без завершающей косой черты) Web-сервер, как правило, будет использовать перенаправление HTTP с целью обращения по первому адресу (с косой чертой). Проверьте это в своем браузере.

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

Проблемы, возникающие при открытии файлов.Обычная ошибка, связанная с откры­тием файла — попытка открыть файл, для которого отсутствуют права на чтение или запись. В этом случае РНР выводит соответствующее предупреждение.

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

В большинстве систем сценарий будет выполняться как пользователь Web-сервера. Если бы сценарий находился в системе UNIX в каталоге ~/public_html/chapter2/, общедоступный для записи каталог для хранения заказов можно было бы создать, набрав следующие команды:

mkdir ~/orders chmod 777 -/orders

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

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

Если обращение к функции fopen() оказывается безуспешным, функция возвращает значение false. Обработку ошибок можно сделать более удобной для пользователя, подавив сообщение об ошибке от РНР, и реализовав собственное сообщение:

@$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", "a", 1);

if ('$fp) {

echo "<p><strong> Your order could not be processed at this time. ."Please try again later.</strong></p></body></html>";

exit;}

Символ @ перед обращением к функции fopen() указывает РНР на необходимость подавления любых сообщений об ошибках, генерируемых после вызова функции. Обычно важно только знать, когда что-то выполняется неправильно, но в данной ситуации в любом случае следует разобраться с подобного рода проблемой. Обратите внимание, что символ @ должен располагаться в самом начале строки.

Оператор if проверяет переменную $fp с целью выяснения, возвращался ли из функции fopen допустимый указатель файла, и если нет, выводится сообщение об ошибке и выполнение сценария завершается. Поскольку здесь завершается и страница, обратите внимание на генерацию закрывающего дескриптора </html>, что обеспечивает допустимость HTML-кода.

Запись в файл.Запись в файл в РНР выполняется сравнительно просто. Для этого можно воспользоваться любой из функций fwrite() (file write — запись в файл) или fputs() (file put string — запись строки в файл); fputs() — это псевдоним функции fwrite(). Функцию fwrite() можно вызвать следующим образом:

fwrite($fp, $outputstring);

Это указывает РНР на необходимость записи строки из переменной $outputstring в файл, указанный $fp. Рассмотрим функцию fwrite() более подробно, прежде чем приступать к исследованию содержимого переменной $outputstring.

Параметры функции fwrite().В действительности функция fwrite() принимает три параметра, однако третий из них не является обязательным. Прототип fwrite() имеет вид

int fputs(int fp, string str, int [length]);

Третий параметр length представляет собой максимальное количество байтов, которые требуется записать. При передаче этого параметра функция fwrite() будет записывать строку str в файл, указанный параметром fp, пока не встретит конец строки или не запишет length байтов, в зависимости от того, что произойдет раньше.

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

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

$outputstring = $date."\t".$tireqty."tires \t".$oilqty." oil\t"

.$total ."\t\n";

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

После обработки нескольких заказов содержимое файла будет выглядеть, как в листинге 6.3.

Листинг 6.3. orders.txt - пример содержимого файла заказов

15:42, 20th April 4 tires 1 oil $434.00

15:43, 20th April 1 tires 0 oil $100.00

15:43, 20th April 0 tires 1 oil $26

Закрытие файла.По завершении использования файла его следует закрыть при помощи функции fclose(), как показано ниже:

fclose($fp);

Эта функция возвращает значение true в случае успешного закрытия файла и false, если файл не был закрыт. Ошибка при этом значительно менее вероятна, чем при открытии файла, поэтому в данном случае проверка выполнения функции не выполняется.

Считывание из файла.Уже сейчас клиенты могут отправлять свои заказы через Web, однако если сотрудники компании захотят взглянуть на заказы, им придется открывать файлы самостоятельно. Давайте создадим Web-интерфейс, который позволит служащим компании легко читать файлы. Код этого интерфейса приведен в листинге 6.4.

Листинг 6.4. vieworders.php — интерфейс для просмотра файла заказов

<html><head>

<title> Auto Parts - Customer Orders</title></head><body>

<hl> Auto Parts</hl> <h2>Customer Orders</h2>

<?

@$fp = fopen("$DOCUMENTROOT/../orders/orders.txt" , "r");

if (!$fp) {

echo "<p><strong>No orders pending."

."Please try again later.</strong></p></body></html>";

exit; }

while (!feof($fp)) {

$order= fgets($fp, 100);

echo $order."<br>"; }

fclose($fp); ?>

</body> </html>

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

Открытие файла для чтения: fopen().Как и ранее, мы открываем файл с помощью функции fopen(). На этот раз файл открывается только для чтения, поэтому используется режим файла "r":

$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", "r");

Определение конца файла: feof().В этом примере используется цикл while для считывания из файла до тех пор, пока не будет достигнут конец файла. Проверка на наличие конца файла осуществляется при помощи функции feof():

while (!feof($fp))

Функция feof() принимает в единственном параметре указатель файла. Она будет возвращать значение true, если указатель файла находится в конце файла. Имя функции легко запомнить, если знать, что feof означает File End Of File (Файл: конец файла).

В данном случае (и вообще при считывании) считывание из файла выполняется до тех пор, пока не будет достигнут EOF.

Построчное считывание: fgets(), fgetss() и fgetcsv().В рассматриваемом примере для считывания из файла используется функция fgets(): $order= fgets($fp, 100);

Эта функция используется для считывания из файла по одной строке за один раз. В данном случае считывание будет выполняться до тех пор, пока не встретится символ новой строки (\n), EOF или из файла не будут прочитаны 99 байт. Максимальная длина считываемой строки равна указанной длине минус один байт.

Интересным вариантом функции fgets() является fgetss(), имеющая следующий прототип:

string fgetss (int fp, int length, string [allowable_tags] ) ;

Эта функция во многом подобна функции fgets() за исключением того, что она будет избавляться от любых дескрипторов РНР и HTML, найденных в строке. Если в файле необходимо оставить конкретные дескрипторы, они должны быть включены в строку allowable_tags. Функцию fgetss() следует использовать для обеспечения безопасности при считывании файла, записанного кем-либо другим или содержащего данные, введенные пользователем. Отсутствие ограничений на наличие в файле HTML-кода может привести к нарушению тщательно спланированного форматирования. Отсутствие ограничений на наличие в файле РНР-кода может предоставить злонамеренному пользователю почти полную свободу действий на сервере.

Функция fgetcsv() — еще одна вариация функции fgets(). Она имеет следующий прототип:

array fgetcsv(int fp, int length, string [delimiter]);

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

$order = fgetcsv($fp, 100, "\t");

получает строку из файла и разбивает ее при каждом обнаружении символа табуляции (\t). Результирующие данные помещаются в массив (в этом примере — в $order).

Параметр length должен быть больше длины самой длинной строки считываемого файла, выраженной в символах.

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

Первый заключается в использовании функции readfile(). Весь ранее созданный сценарий можно заменить одной строкой:

readfile("$DOCUMENT_ROOT/../orders/orders.txt");

Функция readfilc() открывает файл, повторяет его содержимое в стандартном выводе (окне браузера), а затем закрывает файл. Прототип этой функции имеет вид

int readfile (string имя_файла, int [use_include_path]) ;

Необязательный второй параметр указывает, должен ли РНР искать файл в пути use_include_path, и действует так же, как в функции fopen(). Функция возвращает общее количество байтов, считанных из файла.

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

Ранее приведенный сценарий можно заменить функцией fpassthru() следующим образом:

$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", "r");

fpassthru($fp);

Функция fpassthru() возвращает значение true, если считывание было выполнено Успешно, и false — в противном случае.

Третья возможность считывания всего файла — использование функции file(). Эта Функция идентична функции readfile() за исключением того, что вместо повторения файла в стандартном выводе она преобразует его в массив. Ее вызов выглядит так:

$filearray = file($fp);

Эта строка приведет к считыванию всего файла в массив, названный $filearray. каждая строка файла сохраняется в отдельном элементе массива.

Считывание символа: fgetc().Еще одна возможность обработки файлов — считывание из файла по одному символу. Это выполняется с помощью функции fgetc(). В качестве своего единственного параметра она принимает указатель файла и возвращает следующий символ файла Цикл while в первоначальном сценарии можно заменить циклом, в котором используется функция fgetc():

while (!feof($fp))

{

$char = fgetc($fp); if (!feof($fp))

echo ($char=="\n" ? "<br>": $char);

}

Используя функцию fgetc(), этот код считывает из файла по одному символу за раз и сохраняет его в переменной $char, пока не будет достигнут конец файла. Затем выполняется небольшая дополнительная обработка с целью замещения текстовых символов конца строки \n HTML-разделителями строк <bг>. Это делается лишь для приведения в порядок форматирования. Поскольку без этого кода браузеры не распознают новые строки, весь файл был бы выведен в виде единой строки. (Попытайтесь сделать это и посмотрите, что получится.) Для выполнения этой задачи используется тернарная операция.

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

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

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

string fread(int fp, int length);

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

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

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

if (file_exists("$DOCUMENT_ROOT/../orders/orders.txt"))

echo "There are orders waiting to be processed."; else

echo "There are currently no orders.";

Выяснение размера файла: filesize().Размер файла можно проверить с помощью функции filesize(). Она возвращает размер файла, выраженный в байтах:

echo filesize("$DOCUMENT_ROOT/../orders/orders.txt");

Эта функция может применяться в сочетании с функцией fread() для одновременного считывания всего файла (или определенной его части). Весь первоначальный сценарий можно заменить следующим кодом:

$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", "r");

echo fread( $fp, filesize("$DOCUMENT_ROOT/../orders/orders.txt"));

fclose( $fp ) ;

Удаление файла unlink().Если файл заказов необходимо удалить, это выполняется с помощью функции unlink(). (Нет ни одной функции с именем delete.) Например:

unlink("$DOCUMENT_ROOT/../orders/orders.txt");

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

Перемещение внутри файла: rewind(), fseek и ftell().Выяснять позицию указателя файла внутри файла и изменять ее можно с помощью функций rewind(), fseek() и ftell().

Функция rewind() переустанавливает указатель файла на начало файла. Функция ftell() сообщает в байтах позицию указателя относительно начала файла. В нижнюю часть первоначального сценария (перед командой fclose()) можно добавить следующие строки:

echo "Final position of the file pointer is ".(ftell($fp));

rewind($fp);

echo ""<br>After rewind, the position is ". (ftell ($fp) );

echo "<br>";

Функция fseek() может использоваться для установки указателя файла в некоторую точку внутри файла. Ее прототип имеет вид

int fseek(int fp, int offset);

В результате вызова функции fseek() указатель файла fp устанавливается в точку файла, имеющую смещение offset байтов относительно начала файла. Вызов функции rewind() эквивалентен вызову функции fseek() со смещением, равным нолю. Например, функцию fseek() можно использовать для нахождения средней записи в файле или для выполнения бинарного поиска. Часто, когда подобные задачи требуется решать применительно к достаточно сложному файлу данных, имеет смысл использовать базу данных.

Блокирование файлов.Представьте себе ситуацию, когда два клиента одновременно пытаются заказать товар. (Эта ситуация возникает не столь уж редко, особенно когда Web-сайт начинает обрабатывать значительные информационные потоки.) Что произойдет, если один клиент вызовет функцию fopen() и начнет запись, а затем второй клиент также вызовет функцию fopen() и тоже попытается выполнить запись? Ответ на этот вопрос зависит от используемой операционной системы, но часто точно ответить на них невозможно.

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

Прототип функции flock() выглядит так:

bool flock(int fp, int operation);

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

Возможные значения параметра operation перечислены в табл. 6.7.

Таблица 6.7. Значения параметра operation функции flock()

Значение параметра operation Описание
\ Блокировка чтения. Это означает, что файл может использоваться совместно с другими читающими приложениями.
Блокировка записи. Это монопольный режим. Файл не доступен для совместного использования.
Снятие существующей блокировки.
+4 Добавление 4 к текущему значению параметра operation предотвращает другие попытки блокирования во время выполнения текущего блокирования.

Если решено использовать функцию flock(), ее следует включить во все сценарии, в которых используется данный файл; в противном случае ее применение лишено смысла.

Для использования блокирования в рассматриваемом примере программу processorder.php необходимо изменить следующим образом:

$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", "a", 1) ;

flock($fp, 2); // блокирование файла для записи

fwrite($fp, $outputstring);

flock($fp, 3); // снятие блокировки записи

fclose($fp) ;//Следует добавить блокировки в файл vieworders.php:

$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt" , "r");

flock($fp, 1); // блокирование файла для чтения

flock($fp, 3); // снятие блокировки записи

fclose($fp);

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

Более рациональный способ обработки: системы управления базами данных.До сих пор во всех рассмотренных примерах использовались двумерные файлы. Далее будет рассматриваться применение MySQL — системы управления реляционными базами данных. Для чего это нужно?

Проблемы, связанные с использованием двумерных файлов.При работе с двумерными файлами возникает ряд проблем:

· Когда двумерные файлы становятся большими, работа с ними существенно замедляется.

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

· Конкурирующий доступ может порождать проблемы. Уже было показано, как блокируются файлы, но это может привести к возникновению описанной ранее конфликтной ситуации. Кроме того, это может привести к образованию "узкого места" в сети. При достаточно интенсивном информационном потоке большой группе пользователей может потребоваться ожидать разблокирования файла, прежде чем они смогут разместить свои заказы. Если ожидание продлится слишком долго, люди обратятся за покупкой куда-либо в другое место.

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

· Кроме ограничений, налагаемых правами доступа к файлам, не существует никакого способа обеспечения различных уровней доступа к данным.

Как эти проблемы решаются с помощью СУРБД.Системы управления реляционными базами данных (СУРБД) решают все эти проблемы:

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

· В СУРБД можно легко отправлять запрос для извлечения наборов данных, со­ответствующих определенным критериям.

· СУРБД обладают встроенными механизмами обработки конкурирующих обращений, что позволяет программисту не беспокоиться об этом.

· СУРБД обеспечивают произвольный доступ к данным.

· СУРБД обладают встроенными системами определения прав доступа. MySQL обладает особенно большими возможностями в этой области.

Вероятно, главная побудительная причина использования СУРБД заключается в том, что все (или, по меньшей мере, большинство) функциональные возможности, требуемые от системы хранения данных, в ней уже реализованы. Конечно, можно было бы создать собственную библиотеку РНР-функций, но зачем же заново изобретать колесо?

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

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

Запустив монитор mysql и зарегистрировавшись в системе, создадим базу данных books:

mysql> create database books;

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

mysql> use dbname;

где dbname — имя соответствующей базы данных.

Можно и не набирать команду use, но тогда следует указать базу данных при входе систему:

mysql dbname -h hostname -u username -p

В этом примере воспользуемся базой данных books:

mysql> use books;

Для соединения РНР-сценариев с MySQL потребуется настроить пользователя. В этом случае нужно применить принцип наименьших привилегий: зачем права сценариям?

В большинстве случаев сценариям понадобится проводить над строками таблиц только такие операции: SELECT, INSERT, DELETE и UPDATE. Можно поступить следующим образом:

mysql> grant select, insert, delete, update

-> on books.*

-> to bookorama identified by 'bookoramal23' ;

He забывайте о безопасности! Такой пароль, конечно, никуда не годится.

Следующий этап настройки базы данных — создание таблиц. Это делается при помощи SQL-команды CREATE TABLE.

Листинг 7.5 содержит SQL-код для создания этих таблиц, при этом подразумевается, что база данных books уже создана.

SQL-код создания таблиц запускается следующим образом:

> mysql -h host -u bookorama books -p < books.sql

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

Листинг 6.5. books.sql - SQL-код создания таблицы для базы данных books

create table books

( isbn char(13) not null primary key,

author char(30),

title char(60),

price float(4,2)

);

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

Листинг 6.6. book_insert.sql — SQL-код для заполнения данными таблицу Books

use books;

insert into books values

("0-672-31697-8", "Michael Morgan", "Java 2 for Professional Developers", 34.99) ,

("0-672-31745-1", "Thomas Down", "Installing Debian GNU/Linux", 24.99),

("0-672-31509-2", "Pruitt, et al.", "Sams Teach Yourself GIMP in 24 Hours", 24.99),

("0-672-31769-9", "Thomas Schenk", "Caldera OpenLinux System Administration Unleashed", 49.99);

Как работает архитектура Web-баз данных.Распишем ее по шагам:

1. Web-браузер пользователя выдает HTTP-запрос определенной Web-страницы. На­пример, пользователь ищет в Book все книги, написанные Майклом Морганом, используя HTML-форму. Страница с результатами поиска будет называться results.php.

2. Web-сервер принимает запрос на results.php, извлекает этот файл и передает на обработку механизму РНР.

3. Механизм РНР приступает к разбору сценария. Сценарий содержит команду соединения с базой данных и выполнения запроса (поиска книг). РНР открывает соединение с MySQL-сервером и отправляет соответствующий запрос.

4. Сервер MySQL принимает запрос к базе данных, обрабатывает его и отправляет результат (список книг) обратно механизму РНР.

5. Механизм РНР завершает выполнение сценария, что обычно включает в себя форматирование результатов запроса в HTML. После этого результат в виде HTML возвращается Web-серверу.

6. Web-сервер пересылает HTML в браузер, и пользователь имеет возможность просмотреть запрошенный список книг.

У нас имеется база данных MySQL, поэтому можем подготовить код РНР, чтобы выполнялись предыдущие шаги. Начнем с поисковой формы. Это простая HTML-форма. Код для этой формы показан в листинге 6.7.

Листинг 6.7. search.html — поисковая страница для базы данных Book

<html><head><title>Book Catalog Search</title> </head><body>

<hl>Book Catalog Search</hl>

<form action="results.php" method="post"> Choose Search Type:<br>

<select name="searchtype">

<option value="author">Author

<option value="title">Title

<option value="isbn">ISBN </select> <br>

Enter Search Term:<br> <input name="searchterm" type=text> <br>

<input type=submit value="Search"> </form>

</body> </html>

После того как пользователь нажмет на кнопке Search, вызывается сценарий results.php. Все это представлено в листинге 6.8. Далее мы рассмотрим, что делает упомянутый сценарий и как он работает.

Листинг 6.8. results.php - извлечение результатов запроса и форматирование их

<html><head><title>Book Search Results</title></head> <body>

<hl>Book Search Results</hl> <?

trim($searchterm);

if (!$searchtype || !$searchterm) {

echo "You have not entered search details. Please go back and try again.";

exit; }

$searchtype = addslashes($searchtype);

$searchterm = addslashes($searchterm);

@$db = mysql_pconnect("localhost", "bookorama", "bookorama");

if (!$db) {

echo "Error: Could not connect to database. Please try again later.";

exit; }

mysql_select_db("books");

$query = "select * from books where ".$searchtype." Like '%".$searchterm."%'";

$result = mysql_query($query);

$num_results = mysql_num_rows($result);

echo "<p>Number of books found: ".$num_results."</p>";

for ($i = 0; $i <$num_results; $i ++) {

$row = mysql_fetch_array($result);

echo "<p><strong>".($i+l).". Title:";

echo htmlspecialchars( stripslashes($row["titie"]));

echo "</strong><br>Author: ";

echo htmlspecialchars (stripslashes($row["author"]));

echo "<br>ISBN:

echo htmlspecialchars (stripslashes($row["isbn"]));

echo "<br>Price: " ;

echo htmlspecialchars (stripslashes($row["price"] ));

echo "</p>"; }

?>

</body> </html>

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

1. Проверка и фильтрация данных, исходящих от пользователя.

2. Установка соединения с требуемой базой данных.

3. Передача запроса в базу данных.

4. Получение результатов.

5. Представление результатов пользователю.

То же самое делает и сценарий results.php, и сейчас мы исследуем каждый из этих этапов.

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

trim($searchterm);

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

if (!$searchtype || !$searchterm) {

echo "You have not entered search details. Please go back and try again.";

exit; }

В этом случае выдается сообщение о том, что критерий поиска не введен.

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

В случае задействования данных, которые вводят другие пользователи, необходимо тщательно фильтровать вводимые данные от управляющих символов. Если записывать данные, введенные пользователем, в базу данных типа MySQL, следует вызывать addslashes(), а при возврате пользователю выходных данных — stripslashes().

В нашем случае к критерию поиска применяется функция addslashes():

$searchterm = addslashes ($searchterm);

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

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

Установка соединения.Для подключения к серверу MySQL в сценарии есть такая строка:

@ $db = mysql_pconnect("localhost", "bookorama", "bookorama");

Для подключения к базе данных используется функция mysql_pconnect() с прототипом:

int mysql_pconnect ([string host [:port] [:/socketpath]],

[string user], [string password]);

Потребуется указать имя узла (host), на котором размещен сервер MySQL, имя пользователя (user), чтобы войти в него, и пароль (password). Все это необязательно и если не указать все вышеперечисленное, функция воспользуется значениями по умолчанию — локальная машина вместо узла, имя пользователя, под которым запущен РНР, и пустой пароль.

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

if (!$db) {

echo "Error: Could not connect to database. Please try again later."; exit; }

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

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

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

Однако если РНР выполняется как CGI, то постоянное соединение окажется не таким уж и постоянным. (Каждый вызов сценария РНР запускает новую копию механизма РНР и закрывает ее, когда сценарий завершает свою работу. Это, в свою очередь, также закрывает любое постоянное соединение.)

Количество соединений в MySQL, которые существуют одновременно, ограничено. Границу устанавливает параметр max_connections. Его задача (как и родственного ему параметра Apache MaxClients) — заставить сервер отвергать новые запросы на соединение, когда ресурсы узла заняты или когда программное обеспечение не функционирует.

Значения этих параметров можно изменять, редактируя файл конфигурации. Чтобы настроить MaxClients в Apache, следует править файл httpd.conf. Настройка max_connections в MySQL осуществляется за счет редактирования файла my.conf.

Если вы пользуетесь постоянными соединениями, и практически каждой странице на вашем сайте требуется доступ к базе данных, вам, пожалуй, понадобится постоянное соединение для каждого процесса Apache. Если же используются значения параметров, принятые по умолчанию, могут возникнуть определенные сложности. По умолчанию Apache допускает до 150 соединений, а MySQL — только 100. В особо напряженное время соединений может не хватить. Поэтому лучше всего настроить параметры так, чтобы у каждого процесса Web-сервера было свое соединение, конечно, с оглядкой на технические возможности применяемых аппаратных средств.

Выбор базы данных.Работая с MySQL, необходимо указывать, какая база данных нужна. Это может сделать РНР-функиия mysql_select_db():

mysql_select_db("books");

Прототип этой функции выглядит так:

int mysql_select_db(string database, [int database_connection]);

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

Выполнение запроса к базе данных.Чтобы осуществить запрос, можно воспользоваться функцией mysql_query(). Однако прежде запрос необходимо настроить:

$query = "select * from books where ".$searchtype." like '%".$searchterm."%'";

В этом случае будет отыскиваться значение, введенное пользователем ($searchterm), в поле, которое указал пользователь ($searchtype). Обратите внимание на то, что мы употребили like, отдав ему предпочтение перед equal — толерантность никогда не бывает излишней. Не забывайте, что запрос, отправляемый вами в MySQL, не требует в конце точки с запятой, в отличие от запроса, который вводится в среде монитора MySQL.

Теперь можно выполнить запрос:

$result = mysql_query ($query);

Прототип функции mysql_query() таков:

int mysql_query(string query, [int database_connection]);

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

Вместо этого можно воспользоваться функцией mysql_db_query() Рассмотрим ее прототип:

int mysql_db_query(string database, string query,

[int database_connection]);

Здесь можно указать базу данных, в которой требуется производить поиск. В каком-то смысле это комбинация функций mysql_select_db() и mysql_query(). Обе функции возвращают идентификатор результата (что позволяет получить результаты поиска) в случае успеха и значение false в случае неудачи. Идентификатор результата следует сохранить (так же, как в нашем случае с $result), чтобы извлечь из него некоторую пользу.

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

В нашем примере использовались две функции: mysql_numrows() и mysql_fetch_array().

Функция mysql_numrows() сообщает количество строк, которые возвращает запрос В нее следует передать идентификатор результата:

$num_results = mysql_num_rows($result);

Это полезно знать, если планируется обрабатывать или отображать результаты. Зная их количество, можно организовать цикл:

for ($i=0; $i <num_results; $i++)

{ // обработка результатов

}

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

$row = mysql_fetch_array($result);

Имея $row в ассоциативном массиве, можно пройти каждое поле и отобразить его:

echo "<br>ISBN: ";

echo stripslashes($row["isbn"]);

Как уже упоминалось, stripslashes() вызывают для того, чтобы "подчистить" значение, прежде чем отображать его пользователю.

Существуют несколько вариантов получения результата из идентификатора результата. Вместо ассоциативного массива можно воспользоваться нумерованным массивом, применив mysql_fetch_row():

$row = mysql_fetch_row($result);

Значения атрибутов будут храниться в каждом порядковом значении $row[0], $row[l] и т.д.

С помощью функции mysql_fetch_object() можно выбрать строку внутрь объекта:

$row = mysql_fetch_object ($result);

После этого к атрибутам можно получить доступ через $row->title, $row->author и т.д.

Каждый из этих вариантов подразумевает выборку строки за раз. Другой вариант — получить доступ, используя mysql_result() Для этого потребуется указать номер строки (от 0 до количества строк минус 1) и название поля, например

$row = mysql_result($result, $i, "title");

Название поля можно задать в виде строки (либо в форме "title" либо в форме books.title") или номером (как в mysql_fetch_row()). He стоит смешивать mysql_result() с другими функциями выборки.

Строчно-ориентированные функции выборки намного более эффективны, нежели mysql_result(), так что лучше использовать одну из них

Отсоединение от базы данных.Для закрытия непостоянного соединения применяется функция:

mysql_close(database_connect±on);

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

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

Листинг 6.9. newbookhtml — HTML-код страницы добавления новых книг

<html><head><title>Book - New Book Entry</title> </head> <body>

<hl>Book- New Book Entry</hl>

<form action="insert_book.php" method="post"> <table border=0>

<tr><td>ISBN</td><td><input type=text name=isbn maxlength=13 size=13><br></td> </tr>

<tr><td>Author</td><td> <input type=text name=author maxlength=30 size=30><br></td> </tr>

<tr><td>Title</td><td> <input type=text name=title maxlength=60 size=30><br></td> </tr>

<tr><td>Price $</td><td><input type=text name=price maxlength=7 size=7><br></td> </tr>

<tr><td colspan=2><input type=submit value="Register"></td></tr>

</table>

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

Результаты заполнения этой формы передаются в insert_book.php, а сценарий выполняет определенную аутентификацию и пытается записать данные в базу данных. Код для сценария представлен в листинге 6.10.

Листинг 6.10. insert_book.php — сценарий записывает новые книги в базу данных

<html><head><title> Book Entry Results</title></head> <body>

<hl> Book Entry Results</hl>

<?

if (!$isbn || !$author || !$title || !$price)

echo "You have not entered all the required details .<br>"

."Please go back and try again."; exit ; }

$isbn = addslashes($isbn);

$author = addslashes($author);

$title = addslashes($title) ;

$price = doubleval($price);

@$db = mysql_pconnect("localhost", "bookorama", "bookorama");

if (!$db) {

echo "Error: Could not connect to database. Please try again later."; exit;}

mysql_select_db ("books");

$query = "insert into books values

('".$isbn."', '".$author."', ' ".$title."', '".$price."')";

$result = mysql_query($query);

if ($result)

echo mysql_affected_rows()." book inserted into database.";

?>

</body> </html>

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

$isbn = addslashes($isbn); $author = addslashes($author);

$title = addslashes($title); $price = doubleval($price);

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

Мы снова соединяемся с базой данных, используя mysql_pconnect(), и настраиваем запрос. В данном случае это INSERT.

$query = "insert into books values

('".$isbn."', '".$author."', '''.$title."', '''.$price.''')";

$result = mysql_query($query);

Выполнение происходит не без помощи mysql_query().

Одно существенное различие между INSERT и SELECT заключается в использовании mysql_affected_rows():

echo mysql_af£ected_rows(). " book inserted into database.";

В предыдущем сценарии функция mysql_num_rows() применялась для определения количества строк, которые будет возвращать SELECT. При написании запросов, которые изменяют базу данных, например, INSERT, DELETE, UPDATE, следует использовать mysql_affected_rows().

Мы рассмотрели основы использования баз данных MySQL из РНР. Взглянем еще на некоторые полезные функции, не упомянутые ранее.

Рассмотрим кратко несколько полезных функций PHP-MySQL.

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

int mysql_free_result(int result);

Она вызывается с идентификатором результата:

mysql_free_result($result);

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

Создание и удаление баз данных.Для создания новой базы данных MySQL из РНР-сценария применяется функция mysql_create_db(), а для удаления базы данных — mysql_drop_db(). Рассмотрим прототипы этих функций:

int mysql_create_db(string database, [int database_connection]);

int mysql_drop_db(string database, [int database_connection]);

Обе функции используют имя базы данных и соединение. Если соединения нет, будет использоваться последнее открытое. Функции создают либо удаляют указанную базу данных. В случае успеха функции возвращают значение true, а в случае неудачи — false.

Другие интерфейсы РНР-баз данных.РНР поддерживает различные библиотеки, что дает возможность подключаться к огромному количеству баз данных, включая Oracle, Microsoft SQL Server, mSQL и PostgreSQL. В целом принципы подключения и подачи запросов любой из этих баз данных одни и те же. Названия функций могут быть разными, разные базы данных могут иметь разную функциональность, но если вы можете подключиться к MySQL, то другие базы вряд ли поставят вас в безвыходное положение.

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

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

Технологии применения.

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

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

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

Листинг 6.11. secret.php — РНР-код для реализации простого механизма аутентификации

<?

if(!isset($name)&&!isset($password))

{// Посетитель должен ввести имя и пароль

?>

<h1>Please Log In</h1>This page is secret.

<form method = post action = "secret.php">

<table border = 1>

<tr><th>Username</th><td><input type = text name = name></td></tr>

<tr><th>Password</th><td><input type = password name = password>

</td></tr><tr><td colspan =2 align = center>

<input type = submit value = "Log In"></td></tr>

</table></form>

<? }

else if($name=="user"&&$password=="pass")

<? // Комбинация имени и пароля посетителя правильная

echo "<h1>Here it is!</h1>";

echo "I bet you are glad you can see this secret page."; }

else

{ // Комбинация имени и пароля посетителя неправильная

echo "<hl>Go Away!</hl>";

echo "You are not authorized to view this resource."; }

?>

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

· поддерживает только одно жестко закодированное имя пользователя и пароль

· хранит пароль в виде простого текста

· защищает только одну страницу

· передает пароль в виде простого текста

Упомянутые проблемы можно разрешить с различной степенью усилий и успеха.

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

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

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

Сценарий для аутентификации посетителей страницы с использованием базы данных приведен в листинге 6.12.

Листинг 6.12. secretdb.php — применение MySQL для простого механизма аутентификации.

<?

if(!isset($name)&&!isset($password))

{ // Посетитель должен ввести имя и пароль

?>

<hl>Please Log In</hl>This page is secret.

<form method = post action = "secretdb.php"><table border = l>

<tr><th>Username</th><td><input type = text name = name></td></tr>

<tr><th>Password</th><td><input type = password name = password>

</td></tr><tr><td colspan =2 align = center>

<input type = submit value = "Log In"></td> </tr>

</table></form>

<? }

else

{ // Подключиться к MySQL

$mysql = mysql_connect( 'localhost', 'webauth', 'webauth' );

if(!$mysql)

{echo 'Cannot connect to database.'; exit;}

// Выбрать соответствующую базу данных

$mysql = mysql_select_db('auth');

if(!$mysql)

{ echo 'Cannot elect database.'; exit; }

// Запрос к базе данных, чтобы проверить,

// существует ли соответствующая запись

$query = "select count (*) from auth where name = '$name' and

pass = '$password'";

$result = mysql_query($query);

if (!$result)

{echo 'Cannot run query.';exit; }

$count = mysql_result($result, 0, 0 );

if ( $count > 0 )

{// Комбинация имени и пароля посетителя правильная

echo "<hl>Here it is!</hl>";

echo "I bet you are glad you can see this secret page."; }

else

<?

// Комбинация имени и пароля посетителя не правильная

echo "<hl>Go Away!</hl>";

echo "You are not authorized to view this resource."; }

}

?>

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

Листинг 6.13. createauthdb.sql —создание базы данных, таблицы и двоих пользователей.

create database auth;

use auth;

create table auth (

name varchar(10) not null,

pass varchar(30) not null,

primary key (name)

);

insert into auth values ('user', 'pass');

insert into auth values

( 'testuser', password('test123') );

grant select, insert, update, delete

on auth.*

to webauth@localhost

identified by 'webauth';

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

РНР-функция crypt() представляет собой однонаправленную криптографическую хэш-функцию. Прототип этой функции таков:

string crypt (string str[, string salt])

Получив на входе строку str, эта функция возвращает псевдослучайную строку. Например, если передать в функцию строку "pass" и аргумент salt равный "хх", то crypt() вернет строку "xxkTlmYjlikoII". Эта строка не может быть дешифрована и превращена обратно в "pass" даже ее создателем, поэтому на первый взгляд строка может и не показаться столь уж полезной. Что делает функцию crypt() полезной, так это то, что результат этой функции детерминирован. При каждом вызове с одними и теми же параметрами str и salt эта функция будет возвращать один и тот же результат.

Вместо РНР-кода, такого как

if( $username == "user" && password == "pass" )

{ // Пароль совпадает

}

можно воспользоваться таким кодом

if($username= 'user' && crypt($password,'хх') == 'xxkTlmYjlikoII')

{ // Пароль совпадает

}

Нам не требуется знать, как выглядела строка "xxkTlmYjlikoH" перед использованием функции crypt(). Необходимо только знать, совпадает ли введенный пароль тем паролем, для которого применялась функция crypt().

Как уже упоминалось, жесткое кодирование правильных имен и паролей посетителей - плохая идея. Для этого следует организовать отдельный файл или базу данных. Если для хранения данных аутентификации используется база данных MySQL, можно воспользоваться РНР-функцией crypt() или MySQL-функцией PASSWORD(). результат этих функций не совпадает, но они имеют одно предназначение. Обе функции — crypt() и PASSWORD() — получают строку как аргумент и применяют к поденной строке необращаемый алгоритм хэширования.

Чтобы задействовать функцию PASSWORD() в листинге 14.2 запрос SQL следует переписать так:

select count (*) from auth where

name = '$name' and

pass = password('$password')

Этот запрос посчитает количество строк в таблице auth, в которых значение поля name совпадает с содержимым переменной $name, а поля pass - с результатом функции PASSWORD(), примененной к значению переменной $password. Если мы заставляем посетителей выбирать уникальные имена, результатом запроса может быть 0 или 1.

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

Чтобы самостоятельно создать такую функциональность, потребуется включить части листинга 6.11 в каждую страницу, которую необходимо защитить. При помощи директив auto_prepend_file и auto_append_file требуемый файл можно автоматически вставить в начало (prepend) или в конец (append) каждого файла в указанных каталогах.

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

Можно включить введенную пользователем информацию в каждую гиперссылку на странице. Так как пользователи могут применять пробелы или другие символы, запре­щенные в URL, следует обратиться к функции urlencode(), чтобы безопасно упаковать подобные символы.

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

Решить проблему можно с помощью двух механизмов — базовой HTTP-аутентификации и поддержки сеансов. Базовая аутентификация позволяет решить проблему кэширования, но сервер все равно отправляет пароль Web-браузеру в каждом запросе. Управление сеансами позволяет решить обе проблемы. Сначала рассмотрим базовую HTTP-аутентификацию, а управление сеансами освещается далее.

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

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

Описанная возможность HTTP-протокола называется базовой аутентификацией. Ба­овую аутентификацию можно включить средствами РНР или с помощью Web-сервера, Apache и IIS. Далее рассматриваются методы, предполагающие использование РНР.

Базовая аутентификация передает имя пользователя и пароль в виде простого текста и поэтому не особо безопасна. Протокол HTTP 1.1 обладает более безопасным методом, называемым дайджест-аутентификацией (digest authentication). Этот метод использует алгоритм хэширования (как правило, MD5) для маскировки деталей транзакции. Дайджест-аутентификация поддерживается во многих Web-серверах, но не поддерживается в значительном числе браузеров. Дайджест-аутентификация поддерживается в браузере Microsoft Internet Explorer начиная с версии 5.0. Поддержка дайджест-аутентификации включена в Netscape Navigator версию 6.0.

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

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

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

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

Использование базовой аутентификации в РНР.РНР-сценарии, в основном, можно назвать кросс-платформенными, но использование базовой аутентификации базируется на переменных среды, устанавливаемых сервером. Сценарий HTTP-аутентификации должен определять тип сервера и вести себя соответствующим образом в зависимости от того, выполняется ли он как модуль Apache на сервере Apache или как ISAPI-модуль на сервере IIS. Показанный в листинге 6.14 сценарий будет выполняться на обоих серверах.

Листинг 6.14. http.php — включение базовой HTTP-аутентификации средствами РНР.

<?

// Если используется сервер IIS, потребуется установить переменные

// среды $PHP_AUTH_USER и $PHP_AUTH_PW

if (substr($SERVER_SOFTWARE, 0, 9) == "Microsoft" &&

!isset($PHP_AUTH_USER) && !isset($PHP_AUTH_PW) &&

substr($HTTP_AUTHORIZATION, 0, 6) == "Basic" )

{ list($PHP_AUTH_USER, $PHP_AUTH_PW) =

explode(":", base64_decode(substr($HTTP_AUTHORIZATION, 6))); }

// Замените этот оператор if запросом к базе данных

if ($PHP_AUTH_USER != "user" || $PHP_AUTH_PW != "pass")

{

// Посетитель еще не передал деталей или имя и пароль неправильные

header('WWW-Authenticate: Basic realm="Realm-Name"');

if (substr($SERVER_SOFTWARE, 0, 9) == "Microsoft")

header("Status: 401 Unauthorized");

else header("HTTP/1.0 401 Unauthorized");

echo "<hl>Go Away!</hl>";

echo "You are not authorized to view this resource."; }

else {

// посетитель предоставил правильную информацию

echo "<h1>Here it is!</hl>";

echo "<p>I bet you are glad you can see this secret page.";

}

?>

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

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

Поскольку для аутентификации применяются встроенные возможности браузеров, последние демонстрируют некоторую осторожность в обработке неудачных попыток аутентификации. Internet Explorer дает пользователю три попытки аутентификации, и если все они проходят неудачно, выводится сообщение об отказе в доступе. Netscape Navigator предоставляет неограниченное число попыток, но между попытками выводит диалоговое окно с запросом о повторе "Authentication Failed. Retry?". Netscape отображает сообщение об отказе в доступе, только когда пользователь щелкает на кнопке Cancel.

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



<== предыдущая лекция | следующая лекция ==>
PHP. Синтаксис языка. Доступ к базам данных. Технологии применения. Примеры программ | Управление сеансами в РНР.


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.112 сек.