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" — в противном случае. |
Таблица 6.5. Продолжение.
Код | Описание |
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.
Таблица 6.6. Режимы файла для функции fopen
Режим | Значение |
г | Режим чтения — Открытие файла для чтения, начиная с начала файла. |
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]);
Обе функции используют имя базы данных и соединение. Если соединения нет, б
Дата добавления: 2015-11-04; просмотров: 1729;