Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
MySQL.docx
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
762.28 Кб
Скачать

Сохранение данных в базе данных

Мы научились извлекать данные из базы и выводить их на странице. Теперь давай попробуем осуществить обратное действие. С PHP это не составит большого труда.

Создадим простую форму:

<html>

<body>

<form method="post" action="<?php echo $PHP_SELF?>">

First name:<input type="Text" name="first"><br>

Last name:<input type="Text" name="last"><br>

Address:<input type="Text" name="address"><br>

Position:<input type="Text" name="position"><br>

<input type="Submit" name="submit" value="Enter information">

</form>

</body>

</html>

Обратите внимание, мы опять используем переменную $PHP_SELF. Как мы уже сказали, PHP-код можно как угодно перемешивать с обычным HTML. Также обратите внимание, что название каждого элемента формы совпадает с названием поля в базе данных.

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

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

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

Итак, давайте добавим код, который будет проверять, введены ли в форму данные. Пока это будет лишь простая проверка, при которой все переменные, передаваемые странице, будут выводиться на экран с помощью переменной $HTTP_POST_VARS. Эта переменная удобна в случае отладки. Если вы хотите вывести на экран вообще все переменные, используемые в странице, вызовите переменную $GLOBALS.

<html>

<body>

<?php

if ($submit)

{

// process form

while (list($name, $value) = each($HTTP_POST_VARS)) {

echo "$name = $value<br>\n";

}

} else

{

// display form

?>

<form method="post" action="<?php echo $PHP_SELF?>">

First name:<input type="Text" name="first"><br>

Last name:<input type="Text" name="last"><br>

Address:<input type="Text" name="address"><br>

Position:<input type="Text" name="position"><br>

<input type="Submit" name="submit" value="Enter

information">

</form>

<?php

} // end if

?>

</body>

</html>

Теперь давайте возьмем переданную через форму информацию и внесем ее в базу данных.

<html>

<body>

<?php

if ($submit)

{

// process form

$db = mysql_connect("localhost", "root");

mysql_select_db("mydb",$db);

$sql = "INSERT INTO employees (first,last,address,position)

VALUES ('$first','$last','$address','$position')";

$result = mysql_query($sql);

echo "Thank you! Information entered.\n";

} else{

// display form

?>

<form method="post" action="<?php echo $PHP_SELF?>">

First name:<input type="Text" name="first"><br>

Last name:<input type="Text" name="last"><br>

Address:<input type="Text" name="address"><br>

Position:<input type="Text" name="position"><br>

<input type="Submit" name="submit" value="Enter information">

</form>

<?php

}

// end if

?>

</body>

</html>

Листинг 12.2.

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

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

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

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

<html>

<body>

<?php

$db = mysql_connect("localhost", "root");

mysql_select_db("mydb",$db);

if ($id) {

// query the DB

$sql = "SELECT * FROM employees WHERE id=$id";

$result = mysql_query($sql);

$myrow = mysql_fetch_array($result);

?>

<form method="post" action="<?php echo $PHP_SELF?>">

<input type=hidden name="id" value="<?php echo

$myrow["id"] ?>">

First name:<input type="Text" name="first" value="<?php

echo $myrow["first"] ?>"><br>

Last name:<input type="Text" name="last" value="<?php

echo $myrow["last"] ?>"><br>

Address:<input type="Text" name="address" value="<?php

echo $myrow["address"] ?>"><br>

Position:<input type="Text" name="position" value="<?php

echo $myrow["position"] ?>"><br>

<input type="Submit" name="submit" value="Enter

information">

</form>

<?php

} else {

// display list of employees

$result = mysql_query("SELECT * FROM employees",$db);

while ($myrow = mysql_fetch_array($result)) {

printf("<a href=\"%s?id=%s\">%s %s</a><br>\n", $PHP_SELF,

$myrow["id"], $myrow["first"],

$myrow["last"]);

}

}

?>

</body>

</html>

Листинг 12.3.

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

Также мы здесь используем слегка измененное SQL-выражение.

<html>

<body>

<?php

$db = mysql_connect("localhost", "root");

mysql_select_db("mydb",$db);

if ($id) {

if ($submit) {

$sql = "UPDATE employees SET first='$first',last='$last',

address='$address',position='$position' WHERE id=$id";

$result = mysql_query($sql);

echo "Thank you! Information updated.\n";

} else {

// query the DB

$sql = "SELECT * FROM employees WHERE id=$id";

$result = mysql_query($sql);

$myrow = mysql_fetch_array($result);

?>

<form method="post" action="<?php echo $PHP_SELF?>">

<input type=hidden name="id" value="<?php echo

$myrow["id"] ?>">

First name:<input type="Text" name="first" value="<?php

echo $myrow["first"] ?>"><br>

Last name:<input type="Text" name="last" value="<?php

echo $myrow["last"] ?>"><br>

Address:<input type="Text" name="address" value="<?php

echo $myrow["address"] ?>"><br>

Position:<input type="Text" name="position" value="<?php

echo $myrow["position"] ?>"><br>

<input type="Submit" name="submit" value="Enter

information">

</form>

<?php

}

} else {

// display list of employees

$result = mysql_query("SELECT * FROM employees",$db);

while ($myrow = mysql_fetch_array($result)) {

printf("<a href=\"%s?id=%s\">%s %s</a><br>\n",

$PHP_SELF, $myrow["id"], $myrow["first"],

$myrow["last"]);

}

}

?>

</body>

</html>

Листинг 12.4.

Вот так. Нам удалось вместить все, что мы знаем и умеем в один код. Здесь вы можете увидеть, как мы используем выражениеif() внутри другого выражения if() для последовательно проверки нескольких условий.

Теперь пришло время свести все вместе.

<html>

<body>

<?php

$db = mysql_connect("localhost", "root");

mysql_select_db("mydb",$db);

if ($submit) {

// here if no ID then adding else we're editing

if ($id) {

$sql = "UPDATE employees SET first='$first',last='$last',

address='$address',position='$position'

WHERE id=$id";

} else {

$sql = "INSERT INTO employees (first,last,address,position)

VALUES

('$first','$last','$address','$position')";

}

// run SQL against the DB

$result = mysql_query($sql);

echo "Record updated/edited!<p>";

} else if ($delete) {

// delete a record

$sql = "DELETE FROM employees WHERE id=$id";

$result = mysql_query($sql);

echo "$sql Record deleted!<p>";

} else {

// this part happens if we don't press submit

if (!$id) {

// print the list if there is not editing

$result = mysql_query("SELECT * FROM employees",$db);

while ($myrow = mysql_fetch_array($result)) {

printf("<a href=\"%s?id=%s\">%s %s</a> \n", $PHP_SELF,

$myrow["id"], $myrow["first"],

$myrow["last"]);

printf("<a href=\"%s?id=%s&delete=yes\">(DELETE)</a><br>",

$PHP_SELF, $myrow["id"]);

}

}

?>

<P>

<a href="<?php echo $PHP_SELF?>">ADD A RECORD</a>

<P>

<form method="post" action="<?php echo $PHP_SELF?>">

<?php

if ($id)

{

// editing so select a record

$sql = "SELECT * FROM employees WHERE id=$id";

$result = mysql_query($sql);

$myrow = mysql_fetch_array($result);

$id = $myrow["id"];

$first = $myrow["first"];

$last = $myrow["last"];

$address = $myrow["address"];

$position = $myrow["position"];

// print the id for editing

?>

<input type=hidden name="id" value="<?php echo $id ?>">

<?php

}

?>

First name:<input type="Text" name="first" value="<?php echo

$first ?>"><br>

Last name:<input type="Text" name="last" value="<?php echo

$last ?>"><br>

Address:<input type="Text" name="address" value="<?php echo

$address ?>"><br>

Position:<input type="Text" name="position" value="<?php echo

$position ?>"><br>

<input type="Submit" name="submit" value="Enter information">

</form>

<?php

}

?>

</body>

</html>

Листинг 12.5.

На первый взгляд код выглядит сложным, однако это не так. Программа делится на три части. Первое if() выражение проверяет, была ли нажата кнопка Submit, и если была, проводится проверка, есть ли в поданных данных переменная $id. Если ее нет, значит происходит добавление новой записи. В противном случае мы редактируем уже существующую запись.

Далее мы проверяем, определена ли переменная $delete. Если да, мы удаляем запись. Обратите внимание, что в первом выражении if() мы проверяем переменную, которая была подана с помощью метода POST, а в данном if() выражении мы проверяем переменную, которая является частью данных отправленных с помощью метода GET.

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

Все, что мы рассмотрели, мы поместили в один большой код. Мы использовали циклы while() и выражения if(), а также целую гамму основных команд языка SQL - SELECT, INSERT, UPDATE, и DELETE.

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

Perl и MySQL

Язык программирования Perl превратился из инструмента, используемого преимущественно администраторами Unix-систем, в наиболее распространенную платформу разработки для World Wide Web. Perl не предназначался изначально для Web, но простота его использования и мощные функции для работы с текстом сделали естественным его применение для CGI-программирования. Сходным образом, когда mSQL впервые появилась на сцене, исключительные компактность и скорость выполнения сделали ее очень привлекательной для разработчиков Web, которым требовалось обслуживать ежедневно тысячи операций. MySQL со своей высокой скоростью и расширенными возможностями стала еще более привлекательным средством для веб-разработчиков. Естественно поэтому, что был разработан интерфейс Perl к обеим базам - MySQL и mSQL, - объединив таким образом их достоинства.

В то время, когда писался этот материал, существовали два интерфейса между Perl и MySQL с mSQL. Более ранний состоит из специализированных интерфейсов Myaql.pm и Msql.pm, которые работают только с MySQL и mSQL соответственно. Другой, более новый интерфейс является подключаемым модулем в комплекте DBI (DataBase Independent) - независимых от базы данныхмодулей. DBI является попыткой обеспечить общий Perl API для доступа к любым базам данных и предоставления более высокой переносимости. Интерфейс DBI стал наиболее надежным и стандартным, и разработчики MySQL рекомендуют пользоваться толькоDBI, поскольку дальнейшая разработка модулей Mysql.pm и Msql.pm прекращена. Именно о DBI мы и расскажем здесь.

DBI

Рекомендуемым методом доступа к базам данных MySQL и mSQL из Perl является интерфейс DBD/DBI. DBD/DBI означает DataBaseDependent/DataBase Independent (Зависимый от базы данных/Независимый от базы данных). Название связано с двухъярусной реализацией интерфейса. В нижнем ярусе находится зависимый от базы данных уровень. На нем существуют свои модули для каждого типа базы данных, доступного из Perl. Поверх этого уровня находится независимый от базы данных уровень. Это тотинтерфейс, которым вы пользуетесь при доступе к базе данных. Выгода такой схемы в том, что программисту нужно знать только один API уровня независимости от базы данных. Когда появляется новая база данных, кому-нибудь нужно лишь написать для неемодуль DBD (зависимый), и она станет доступна всем программистам, использующим DBD/DBI.

Как и в любом модуле Perl, для получения доступа нужно указать DBI в директиве use:

#!/usr/bin/perl -w

use strict;

use CGI qw(:standard);

use DBI;

При запуске программ Perl для MySQL/mSQL следует всегда задавать аргумент командной строки -w. Благодаря этому DBI будет перенаправлять все специфические для MySQL и mSQL сообщения об ошибках на STDERR, и вы сможете увидеть ошибки, вызванные работой с базой данных, не прибегая к явной проверке их в программе.

Всякое взаимодействие между Perl, с одной стороны, и MySQL и mSQL - с другой, производится с помощью объекта, известного как описатель базы данных ( handle ). Описатель базы данных ( database handle ) - это объект, представленный в Perl как скалярная ссылка и реализующий все методы, используемые для связи с базой данных. Одновременно можно открыть любое число описателей базы данных, ограничение накладывают только ресурсы системы. Метод connect() использует для создания описателя формат соединения DBI:servertype:database:hostname:port (имя узла и порта необязательны), дополнительными аргументами служат имя пользователя и пароль:

my $dbh = DBI->connect( 'DBI:mysql:mydata ', undef, undef);

my $dbh = DBI->connect( 'DBI:mSQL:mydata:myserver', undef, undef);

my $dbh = DBI->connect( 'DBI:mysql:mydata', 'me', 'mypass')',

Атрибут servertype является именем специфического для базы данных DBD-модуля, в нашем случае "mysql" или "mSQL" (обратите внимание на точное использование регистра). В первом варианте создается соединение с сервером MySQL на локальной машине через сокет Unix. Это наиболее эффективный способ связи с базой данных, который должен использоваться при соединении на локальном сервере. Если указано имя узла, оно используется для соединения с сервером на этом узле через стандартный порт, если только не задан и номер порта. Если при соединении с сервером MySQL вы не указываете имя пользователя и пароль, то пользователь, выполняющий программу, должен обладать достаточными привилегиями в базе данныхMySQL. Для баз данных mSQL имя пользователя и пароль не должны указываться.

В Perl 5 используются два соглашения по вызову модулей. В объектно-ориентированном синтаксисе для ссылки на метод определенного класса используется символ стрелки "->" (как в DBI->connect ). Другой метод - использование непрямого синтаксиса, в котором за именем метода следует имя класса, а затем - аргументы. В последнем примере метод connectследовало бы записать как connect DBI 'DBI:mysql:mydata', 'me', ' mypass. В ранних версиях Msql.pm использовался исключительно непрямой синтаксис, и требовалось придерживаться метода использования заглавных букв, обусловленного mSQL С API. Поэтому значительная часть старого кода MsqlPerl содержит строки типа SelectDB $dbh 'test' там, где можно было бы написать проще: $dbh->selectdb('test'). Если вы еще не догадались, то сообщаем, что мы неравнодушны к объектно-ориентированному синтаксису, хотя бы потому, что использование стрелки делает ясной связь между классом и методом.

Как только вы соединились с сервером MySQL или mSQL, описатель базы данных - во всех примерах этого раздела $dbh - становится шлюзом к базе данных. Например, так готовится запрос SQL:

$dbh->prepare($query);

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

Для иллюстрации использования DBI рассмотрим следующие простые программы. В примере 1 datashow.cgi принимает в качестве параметра имя узла; при отсутствии параметра принимается имя " local-host ". Затем программа выводит список всех баз данных, имеющихся на этом узле.

Пример 1. Программа CGI datashow.cgi показывает все базы данных, имеющиеся на сервере MySQL или mSQL

#!/usr/bin/perl -w

use strict;

use CGI qw( standard);

use CGI::Carp;

# Использовать модуль DBI use DBI; CGI::use_named_parameters(1);

my ($server, $sock, $host);

my $output = new CGI;

$server = param('server') or Sserver = '';

# Подготовить DBD-драйвер для MySQL

my $driver = DBI->install_driver('mysql');

my @databases = $driver->func($server, '_ListDBs');

# Если параметр @databases неопределен, предполагаем,

# что на этом узле не запущен

# сервер MySQL. Однако это может быть вызвано

# другими причинами. Полный текст сообщения об ошибке

# можно получить, проверив $DBI::errmsg.

if (not @databases) {

print header, start_html('title'=>"Данные no Sserver", 'BGCOLOR'=>'white');

print<<END_OF_HTML; <H1>$server</h1>

Ha Sserver , по-видимому, не запущен сервер mSQL. </body></html> END_OF_HTML

exit(0); }

print header, start_html('title'=>" Данные по $host",

'BGCOLOR'=>'white'); print <<END_OF_HTML; <H1>$host</h1>

<P>

Соединение с $host на сокете $sock.

<p>

Базы данных:<br>

<UL>

END_OF_HTML

foreach(@databases) {

print "<LI>$_\n"; }

print <<END_OF_HTML;

</ul>

</body></html>

HTML

exit(0)

Листинг 13.1.

В примере 2 tableshow.cgi принимает в качестве параметров имя сервера базы данных (по умолчанию " localhost ") и имябазы данных на этом сервере. Затем программа показывает все таблицы, имеющиеся в этой базе данных.

Пример 2. Программа CGI tableshow.cgi выводит список всех таблиц в базе данных

#!/usr/bin/perl -w

use strict;

use CGI qw(:standard);

use CGI::Carp;

# Использовать модуль Msql.pm use DBI;

CGI::use_named_parameters(1);

my ($db);

my $output = new CGI;

$db = param('db')'or die("He указана база данных!");

# Connect to the requested server.

my $dbh = DBI->connect("DBI:mysql:$db;$server", undef, undef);

# Если не существует $dbh, значит, попытка соединения с сервером

# базы данных не удалась. Возможно, сервер не запущен,

# или не существует указанной базы данных, if (not $dbh) {

print header, start_html('title'=>"Данные по $host => $db",

'BGCOLOR'=>'white');

print <<END_OF_HTML; <H1>$host</h1> <H2>$db</h2>

Попытка соединения не удалась по следующей причине:<BR>

$DBI::errstr

</body></html>

END_OF_HTML

exit(0); }

print header, start_html('title'=>"Данные по $host => $db",

'BGCOLOR'=>'white'); print <<END_OF_HTML; <H1>$host</h1>

<H2>$db</h2>

<р>

Таблицы:<br>

<UL>

END_OF_HTML

# $dbh->listtable возвращает массив таблиц,

# имеющихся в текущей базе данных.

my ©tables = $dbh->func( '_ListTables' );

foreach (@tables) {

print "<LI>$_\n"; }

print <<END_OF_HTML; </ul>

</body></html> END_OF_HTML

exit(0);

Листинг 13.2.

И наконец, пример 3 показывает, как вывести все сведения о некоторой таблице.

Пример 3. Программа CGI tabledump.cgi выводит сведения об указанной таблице

#!/usr/bin/perl -w

use strict;

use CGI qw(:standard);

use CGI::Carp;

# Использовать модуль DBI use DBI; CGI::use_named_parameters(1);

my ($db,Stable);

my Soutput = new CGI;

$server = param('server') or $server = ";

$db = param('db') or die("He указана база данных !");

# Соединиться с указанным сервером.

my $dbh = DBI->connect("DBI:mysql:$db:$server", undef, undef);

# Готовим запрос к серверу, требующий все данные

# таблицы.

my $table_data = $dbh->prepare("select * from Stable");

# Посылаем запрос серверу.

$table_data->execute;

# Если возвращаемое значение не определено, таблица не существует

# или пуста; мы не проверяем, что из двух верно.

if (not $table_data) {

print header, startjtml( 'title'=>

"Данные по $host => $db => Stable", 'BGCOLOR'=>'white');

print<<END_OF_HTML;

<H1>$host</h1>

<H2>$db</h2>

Таблицы'Stable' нет в $db на $host.

</body></html>

END_OF_HTML

exit(0); }

# Теперь мы знаем, что есть данные для выдачи. Сначала выведем

# структуру таблицы.

print header, start_html( title'=>"Данные по $host => $db => $table",

'BGCOLOR'=>'white');

print <<END_OF_HTML; <H1>$host</h1> <H2>$db</h2> <H3>$table</h3>

<P>

<TABLE BOROER> <CAPTION>Пoля</caption> <TR>

<ТН>Поле<ТН>Тип<ТН>Размер<ТН>МОТ NULL </tr> <UL> END_OF_HTML

If $table_data->name возвращает ссылку

# на массив полей таблицы.

my ©fields = @{$table_data->NAME};

# $table_data->type возвращает ссылку на массив типов полей.

# Возвращаемые типы имеют стандартные обозначения SQL,

# а не специфические для MySQL.

my @types = @{$table_data->TYPE};

# $table_data->is_not_null возвращает ссылку на массив типа Boolean,

# указывающий, в каких полях установлен флат 'NOT NULL'.

my @>not_null = @{$table_data->is_not_null};

# $table_data->length возвращает ссылку на массив длин полей.

Они фиксированные

# для типов INT и REAL, но переменые (заданные при создании

# таблицы) для CHAR.

my @length = @{$table_data->length};

# Все перечисленные выше массивы возвращаются в одном и том же

порядке,

# поэтому $fields[0], $types[0], $ndt_null[0] and $length[0]

относятся к одному полю.

foreach $field (0..$#fields) {

print "<TR>\n";

print "<TD>$fields[$field]<TD>$types[$field]<TD>";

print $length[$field]

if $types[$field] eq 'SQL_CHAR';

print "<TD>";

print 'Y' if ($not_null[$field]);

print "</tr>\n"; }

print <<END_OF_HTML; </table>

<P>

<B>Data</b><br>

<OL>

END_OF_HTML

# Теперь мы будем построчно перемещаться по данным с помощью

DBI::fetchrow_array().

# Мы сохраним данные в массиве в таком же порядке, как и в

информационных

# массивах (§fields, @types, etc,), которые мы создали раньше.

while(my(@data)=$table_data->fetchrow_array) {

print "<LI>\n<UL>";

for (0..$#data) {

print "<LI>$fields[$_] => $data[$_]</li>\n"; }

print "</ulx/li>"; }

print "END_OF_HTML;

</ol>

</body></html>

END_OF_HTML

Листинг 13.3.

Пример приложения, использующего DBI

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

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

CREATE TABLE test (

id INT NOT NULL AUTO_INCREMENT, name CHAR(100),

subject INT, num INT)

Для каждого отдельного экзамена структура таблицы такая:

CREATE TABLE t7 (

id INT NOT NULL,

q1 INT,

q2 INT,

q3 INT,

q4 INT,

total INT

)

К имени таблицы t присоединен идентификатор экзамена из таблицы test. При создании таблицы пользователь определяет количество вопросов. Поле total содержит сумму баллов по всем вопросам.

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

#!/usr/bin/perl -w

use strict; require my_end;

use CGI qw(:standard);

my Soutput = new CGI;

use_named_parameters(1);

# Использовать модуль DBI. use DBI;

# DBI::connect() использует формат 'DBI:driver:database', в нашем

случае

# используется драйвер MySQL и открывается база данных 'teach',

my $dbh = DBI->connect('DBI:mysql:teach');

# Операция добавления распределена между тремя отдельными функциями.

Первая функция, add,

# выводит пользователю форму шаблона для создания нового экзамена,

sub add {

$subject = param('subject')

if (param('subjects'));

$subject = ""

if $subject eq 'all';

print header, start_html('title'=>'Create a New Test',

'BGCOLOR'=>'white'); print <<END_OF_HTML;

<Н1>Создание нового экзамена</п1> <FORM ACTION="test.cgi"

METHOD=POST>

<INPUT TYPE=HIDDEN NAME="action" VALUE="add2"> Предмет: END_OF_HTML

my @ids = (); my %subjects = ();

my $out2 = $dbh->prepare("select id,name from subject order by

name" $out2->execute;

# DBI: :fetchrow_array() совершенно аналогична Msql: :fetchrow()

while(my($id,$subject)=$out2->fetchrow_array) {

push(@ids,Sid); $subjects{"$id"} = Ssubject; }

print popup_menu('name'=>'subjects', 'values'=>[@ids],

'default'=>$subject, 'labels'=>\%subjects);

print <<END_OF_HTML; <br>

Число вопросов: <INPUT NAME="num" SIZE=5><br> Название или

идентификатор (например, дата) экзамена:

<INPUT NAME="name" SIZE=20>

<Р>

<INPUT TYPE=SUBMIT VALUE=" Следующая страница ">

<INPUT TYPE=RESET> </form></body></html>

END_OF_HTML }

Листинг 13.4.

Эта функция выводит форму, позволяющую пользователю выбрать предмет для экзамена, а также количество вопросов и название. Для вывода списка имеющихся предметов выполняется запрос к таблице предметов. При выполнении в DBI запросаSELECT он должен быть сначала подготовлен, а затем выполнен. Функция DBI::prepare полезна при работе с некоторыми серверами баз данных, позволяющими осуществить операции над подготовленными запросами, прежде чем выполнить их. ДляMySQL и mSQL это означает лишь запоминание запроса до вызова функции DBI:: execute.

Результаты работы этой функции посылаются функции add2, как показано ниже:

sub add2 {

my Ssubject = param('subjects');

[

my $num = param('num');

$name = param('name') if param('name');

my $out = $dbl"prepare("select name from subject where id=$subject");

$out->execute;

my (Ssubname) = $out->fetchrow_a.rray;

print header, start_html('title'=>"Создание экзамена по предмету

$subname", ' BGCOLOR'=>'white');

print <<END_OF_HTML;

<H1> Создание экзамена по предмету $subname</h1> <h2>$name</h2>

<P>

<FORM ACTION="test.cgi" METHOD=POST>

<INPUT TYPE=HIDDEN NAME="action" VALUE="add3">

<INPUT TYPE=HIDDEN NAME="subjects" VALUE="$subject">

<INPUT TYPE=HIDOEN NAME="num" VALUE="$num">

<INPUT TYPE=HIDDEN NAME="name" VALUE="$name">

Введите количество баллов за каждый правильный ответ.

Сумма баллов не обязательно должна равняться 100.

<Р> END_OF_HTML

for (1..$num) {

print qq%$_: <INPUT NAME="q$_" SIZE=3> %; if (not.$_ % 5)

{ print "<br>\n"; } } print <<END_OF_HTML;

<P>

Введите текст экзамена:<br>

<TEXTAREA NAME="test" ROWS=20 COLS=60> </textarea> <p>

<INPUT TYPE=SUBMIT VALUE="Ввести экзамен ">

<INPUT TYPE=RESET> </form></body></html>

END_OF_HTML }

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

sub add3 {

my $subject = para'm( 'subjects');

my $num = param('num');

$name = param('name') if param('name');

my $qname;

($qname = $name) =" s/'/\\'/g;

my $q1 = "insert into test (id, name, subject, num) values ( '.'-,

'$qname', $subject, $num)";

my Sin = $dbh->prepare($q1); $in->execute;

# Извлечем значение ID , которое MySQL создал для нас

my $id = $in->insertid;

my $query = "create table t$id ( id INT NOT NULL,

my $def = "insert into t$id values ( 0, ";

my $total = 0;

my @qs = grep(/^q\d+$/,param);

foreach (@qs) {

$query .= $_ . " INT,\n";

my $value = 0;

$value = param($_) if param($_);

$def .= "lvalue, ";

$total += $value; }

$query .= "total INT\n)"; $def .=-"$total)";

my $in2 = $dbh->prepare($query);

$in2->execute;

my $in3 = $dbh->prepare($def);

$in3->execute;

# Обратите внимание, что мы запоминаем экзамены в отдельных файлах.

# Это полезно при работе с mSQL, поскольку он не поддерживает BLOB.

# (Тип TEXT, поддерживаемый в mSQL 2, можно использовать,

# но это неэффективно.)

# Поскольку мы используем MySQL, можно с таким же успехом

# поместить весь экзамен в BLOB.

open(TEST,">teach/tests/$id") or die("A: $id $!");

print TEST param('test'), "\n";

close TEST;

print header, start_html('title'=>'Экзамен создан',

'BGCOLOR'=>'white');

print <<END_OF_HTML;

<Н1>Экзамен создан</h1> <P>

Экзамен создан.

<р>

<А HREF=".">Перейти</а> на домашнюю страницу 'В помощь учителю'.<br>

<А HREF="test.cgi">nepeimi</a> на главную страницу экзаменов.<br>

<А HREF="test.cgi?actio,n=add">Добавить</a> следующий экзамен.

</body></html>

END_OF_HTML

}

Листинг 13.5.

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]