Ошибки PHP и журнал error_reporting
Библиотека PHP может генерировать ряд ошибок, не относящихся к уровню исключений – ошибок OOP.
В PHP обрабатываются три уровня ошибок: информационные ошибки, ошибки с возможностью действия (предупреждения) и неустранимые (фатальные) ошибки. Информационные ошибки: E_STRICT (устаревшая конструкция), E_NOTICE – компилятор столкнулся с логической проблемой, которая может привести к ошибке выполнения. Аналогично E_USER_NOTICE генерируемое пользователем уведомление
Ошибки с возможностью действия (предупреждения) означают, что возможно придется завершить работу с выдачей сообщения из-за того, что нельзя открыть файл и т.д. Ошибка - E_WARNING предупреждение времени выполнения связанное с возможностью выполнения функции или блока. Аналогично E_USER_WARNING генерируемое пользователем предупреждение. E_COMPILE_WARNING предупреждения времени компиляции.
Неустранимые (фатальные) ошибки возникают тогда, когда выполнение или загрузка программы невозможны. E_ERROR фатальные ошибки времени выполнения. E_PARSE ошибки разбора времени компиляции. E_COMPILE_ERROR фатальные ошибки времени компиляции. E_CORE_ERROR фатальные ошибки при начальном старте PHP.
Приведем значения нескольких констант, определяющих вывод типов ошибок и предупреждений: 1 - E_ERROR , 2 - E_WARNING, 4 - E_PARSE, 8 - E_NOTICE, 16 - E_CORE_ERROR, 32 - E_CORE_WARNING, 64 - E_COMPILE_ERROR, 128 - E_COMPILE_WARNING, 256 - E_USER_ERROR, 512 - E_USER_WARNING, 1024 - E_USER_NOTICE, E_ALL всё вышеуказанное.
Уровень сообщений об ошибках устанавливается как значение директивы error_reporting. В PHP установлено значение по умолчанию error_reporting = E_ALL & ~E_NOTICE, что означает отображение всех ошибок и предупреждений, за исключением логических ошибок, которые имеют уровень E_NOTICE.
Начальное значение error_reporting может быть изменено в php.ini-файле директивой error_reporting, в Apache httpd.conf-файле директивой php_error_reporting и, наконец, оно может быть установлено на этапе прогона скрипта функцией error_reporting().
Параметр error_reporting в php.ini файле устанавливает уровень строгости ошибок E_ERRORLEVEL, которые будут обрабатыватся внутренним обработчиком ошибок. Параметр display_error устанавливает вывод сообщений об ошибках на экран. Параметр log_errors регистрацию ошибок в журнальном файле, указанном в параметре error_log.
Слабая устойчивость к ошибкам.
В природе существует огромное количество скриптов абсолютно не справляющихся с пользовательскими ошибками. Своим появлением такие скрипты обязаны программистам, которые не удосуживаются правильно распланировать будущий проект и определить все места возможных ошибок. Причём этим следует заняться до того, как скрипт был написан. Недоработки подобного рода приводят к сбоям программы, что чревато не только получением некорректных результатов, но и падением системы!
Предусмотреть худшее.
Любой скрипт может "свалиться" при наступлении каких-либо "критичных" условий. Чтобы свести такой риск к минимуму всегда нужно:
проверять результаты вызова функций:
проверять результаты системных вызовов:
в файле php.ini устанавливать уровень error_reporting на E_ALL
Проверка результатов вызова функций
При вызове функции, результаты которой подвергаются дальнейшей обработке, обязательно убедитесь, что возвращаемые данные находятся в интервале допустимых значений.
В приведённом ниже примере на шестом витке цикла возникает ошибка "деление на ноль", поскольку $i наращивается на 1, а $j уменьшается на 1. На шестом проходе $i=$j=1.
<?php
mt_srand((double)microtime() * 10000000);
function do_math ($a, $b) {
return (($a - $b) * 2) / mt_rand();
}
for ($i = 5, $j = -5; $i > -5; $i--, $j++){
print $j / do_math ($i, $j) . "\n";
}
?>
Проверка результатов системных вызовов
При обращении к внешним файлам или процессам всегда проверяйте, всё ли работает корректно.
Хороший пример - проверка ответа системы при вызове функции sql_connect(). Стоит проверить этот ответ и убедиться, что подключение к БД действительно имело место. Если этого не сделать, то все запросы к БД могут не состояться, а некоторые данные могут быть утеряны.
<?php
$conn = @sql_connect ($host, $user, $pass);
if (!$conn) {
die (sprintf ("Ошибка [%d]: %s", sql_errno (), sql_error ()));
}
?>
Установка уровня error_reporting в файле php.ini на E_ALL
Убедитесь, что PHP правильно сконфигурирован, то есть уровень error_reporting (отображение сообщений об ошибках) выставлено на наивысший уровень. При другой конфигурации, по крайней мере, на время отладки скриптов, многие ошибки типа "неверное регулярное выражение", "недопустимое значение" ускользнут от вашего внимания.
Обратимся ещё раз к примеру, приведённому в части "Проверка результатов вызова функций". Предположим, что error_reporting выставлен не на максимум, а, скажем, на E_ERROR.
Обратите внимание на то, как скрипт выполняет функцию do_math, но не сообщает об ошибке "деление на ноль", которая, однако, имела место (при $i=$j=0 вывода результата просто не было).
<?php
error_reporting(E_ERROR);
mt_srand ((double)microtime() * 1000000);
function do_math ($a, $b) {
return (($a - $b) * 2) / mt_rand();
}
for ($i = 5, $j = -5; $i > -5; $i--, $j++){
print $j / do_math ($i, $j) . "\n";
}
?>
Результат работы скрипта:
-5148.25
-5271
-323.75
-4931
-7713.5
-4702.5
-488.5
-928.5
-1394.75
Свои обработчики ошибок
Как правило, PHP выдаёт сообщения об ошибках непосредственно в браузер и не позволяет разработчику подавить или перехватить их. Однако в PHP имеется возможность перехвата таких сообщений с помощью функции set_error_handler().
В следующем примере set_error_handler() назначает обработчиком по умолчанию функцию error_handler(). В случае возникновения ошибки вызывается error_handler(), и встроенная функция error_log() регистрирует сбой в файле лога error_file.
Если происходит ошибка класса E_ERROR, работа скрипта прекращается и выводится сообщение об ошибке.
<?php
// void error_handler(string type, string message, string file, int line)
// Индивидуальный обработчик ошибок, определён функцией
// set_error_handler()
function error_handler ($type, $message, $file = __FILE__, $line = __LINE__) {
error_log("$message, $file, $line", 3, 'error_file');
if ($type & E_ERROR) {
print 'Произошла ошибка, зарегистирована.';
exit;
}
}
set_error_handler('error_handler');
?>
Файлы
Файлы могут быть текстовыми, содержащими строки переменной длины и бинарными, представляющими последовательность байт. В языке PHP имеются различные средства для реализации работы с файлами.
Для того, чтобы вставить другие файлы в текущий текстовый файл PHP, может использоваться директива include "filename". Строка filename содержит имя включаемого файла.
При работе с файлами в PHP используются три действия: 1) открытие файла для чтения или записи, 2) чтения или записи, 3) закрытие файла.
Открытие файла:
fopen ($filename, $mode [, use_include_path]). Функция осуществляет открытие файла с именем, указанным в $filename, и возвращает его дескриптор (номер). Режим открытия файла mode, может принимать следующие значения:
"r" - файл открывается только для чтения. "r+" - открывается на чтение и на запись. Текущий указатель файла устанавливается в его начало.
"w" - Файл открывается только для перезаписи. Указатель файла устанавливается в его начало. Всё старое содержимое файла теряется, счётчик длины файла устанавливается равным 0. Если файл с указанным именем не существует, функция пытается его создать. "w+" - Файл открывается на чтение и на запись. Указатель файла устанавливается в его начало. Всё старое содержимое файла теряется.
"a" - Файл открывается на добавление (запись). Указатель файла помещается в конец файла. Если файл с указанным именем не существует, функция пытается его создать. "a+" - Файл открывается на чтение и на запись. Вот несколько примеров открытия файлов с помощью fopen()
$fp = fopen ("/home/a/bases.dat", "r");
$fp = fopen ("/home_dir/client/count.txt", "w+");
$fp = fopen ("http://www.yahoo.com/pp.txt", "r");
В случае успешного завершения функция fopen() возвращает "ссылку" на открытый файл, а в случае ошибки эта функция возвращает булевское значение false.
В РНР имеется возможность удаленного открытия файлов путем указания URL-адреса в качестве параметра $filename функции fopen (). Осуществлять запись в такие файлы, невозможно, но зато можно их читать.
URL, содержащие недопустимые символы (например, пробельные символы в имени файла), необходимо кодировать перед их использованием с помощью функции urlencode (). Функция urlencode () принимает единственный параметр (URL, подлежащий кодированию) и возвращает закодированный URL. Использование функции fореn()
<?php
/* Открыть файл для чтения */
$fr = fopen("myfile.txt", 'r');
/* Открыть бинарный файл для чтения/добавления */
$fr = fopen("myfile.dat", 'ba+');
/* Открыть файл для чтения/записи (искать файл в пути,
заданном директивой include_path)*/
$fr = fopen("code.php", 'w+', true);
/* Открыть файл index.php, для чтения по протоколу HTTP */
$fr = fopen("http://www.php.net/index.php", 'r');
/* Открыть файл index.php, для чтения по протоколу FTP */
$fr = fopen("ftp://ftp.php.net/index.php", 'r');
/*Закодировать URL, затем открыть для чтения по протоколу HTTP */
$url = "http://www.php.net/this is my invalid URL.php";
$url = urlencode($url);
$fr = fopen($url, 'r');
?>
Закрытие файла: bool fclose ($fp).
Для работы с текстовыми файлами наиболее часто используются функции: fgets (), которая извлекает строку из файла, и fputs (), которая записывает строку в файл.
Функция считывания строки string fgets ( $fp, $length) возвращает строку длиной до length-1 байт, считанную из файла $fp. Операция чтения завершается после загрузки length-1 символов, либо после обнаружения символа конца строки, либо при обнаружении признака конца файла. Вот пример построчного вывода на экран, содержимого файла:
<? //pr415
$fp = fopen ("pr415.php", "r");
while (!feof ($fp)) {
$stroka = fgets ($fp, 80);
echo $stroka."<BR>";
}
fclose($fp);
?>
Загрузка строки с пропуском HTML-тегов выполняется функцией: string fgetss ($fp, $length [, string allowable_tags]). Функция работает идентично fgets(), однако считанной строки удаляются все HTML-теги, которые в ней присутствуют. Есть возможность использовать необязательный третий аргумент, для указания разрешенных тегов, которые удалены не будут.
Альтернативой fgets () является функция fscanf (). Синтаксис функции fscanf () показан ниже:
fscanf ($filename, $format , $var_one [, $var_two ...]]])
где $filename — входной поток, $format задает шаблон для чтения, а $var_one, $var_two представляют собой переменные, в которых сохраняются разобранные фрагменты данных (эти параметры необходимо передавать по ссылке). В случае успешного завершения ввода fscanf () возвращает количество разобранных элементов, а случае ошибки возвращает значение false.
Допустимые символы форматирования функции fscanf ()
%b Двоичное число.
%с Одиночный символ.
%d Десятичное число со знаком.
%u Десятичное число без знака.
%f Число с плавающей запятой.
%о Восьмеричное число.
%s Строка.
%x Шестнадцатиричное число.
Функция fputs () служит для записи строки (или любых других данных) в указанный поток и имеет следующийсинтаксис: fputs($filename, $data [, int $length]), где $filename представляет выходной поток, $data содержит записываемые данные, а необязательный параметр $length задает размер фактически записываемых данных.
Чтение и запись бинарных файлов
Чтение данных из файла: string fread (int $fp, int length). Функция осуществляет чтение до length байт из файла, адресуемого указателем fp. Чтение прекращается, если будет считано указанное количество байт, или будет достигнут конец файла.
Запись данных в файл: int fwrite (int $fp, string str [, int length])
Функция производит запись содержимого строки string в файл, адресуемый указателем fp. Если задан аргумент length, операция записи прекращается после вывода указанного количества символов, либо при достижении конца строки.
<? //pr416
$open=fopen("my_file.txt","w+");
//Очищаем файл и добавляем в него строку,
//если файл не существует, то он создаётся:
fwrite($open,"строка\r\n");
fclose($open);
//Добавляем новую строку в конец файла:
$open=fopen("my_file.txt","a");
fwrite($open,"новая строка\r\n");
fclose($open);
?>
В созданном файле my_file.txt будут записаны две строки
строка
новая строка
Загрузка всего файла: array file (string filename [, int use_include_path]). Функция file() записывает запрошенный файл в массив. При этом каждый элемент массива представляет собой одну строку файла. Символ новой строки, является последним символом каждой строки.
<? //pr417
//Создаём массив $array, где каждый индекс будет равняться номеру строки в файле:
$array=file("pr417.php");
print_r($array);
$count=count($array); // количество строк в файле
echo $count;
?>
Будет выведено:
Array ( [0] => //Создаём массив $array, где каждый индекс будет равняться номеру строки в файле: [2] => $array=file("php416.php"); [3] => print_r($array); [4] => //Подсчитываем количество строк в файле: [5] => $count=count($array); [6] => echo $count; [7] => ?> ) 8
<?php //php418.php - вывод строк из файла
$fi="php418.php"; // имя файла
$array=file($fi);
//Считываем из файла первые 3 строки:
echo "<hr>";
$n=3; //количество считываемых строк
for($i=0;$i<$n;$i++)
{print "$i : $array[$i],'\n'"; }
for($i=(count($array)-$n-1);$i<count($array)-1;$i++)
{ echo "$i : $file[$i],'\n'"; }
?>
Будет выведено три первых и три последних строки:
0 : <?php //php418.php - вывод строк из файла ,
' '1 : $fi="pr418.php"; // имя файла ,
' '2 : $array=file($fi); ,
' '10 : { echo "$i : $array[$i],'\n'"; } ,
' '11 : ,
' '12 : ?> ,' '
Объединяем 2 файла в один массив $new_array:
<? //pr419
$files=array(
"php416.php", # первый файл
"php417.php" # второй файл
);
for($i=0;$i<count($files);$i++)
{
$array[]=file($files[$i]);
}
while(list(,$result)=each($array))
{
for($i=0;$i<count($result);$i++)
{ $new_array[]=$result[$i]; }
}
print_r($new_array); #выводим массив
?>
Пример. Удаление указанной строки из файла:
<?
$line="1"; # строка, которую нужно удалить
$file=file("my_file.txt");
$open=fopen("my_file.txt","w");
for($i=0;$i<count($file);$i++)
{
if(($i+1)!=$line){fwrite($open,$file[$i]);}
}
fclose($open);
?>
В следующем примере массив устанавливается в файл. Затем выполняется замена строки в файле на указанную с помощью функции fwrite():
<?
$line="1"; # строка, которую нужно изменить
$replace="du du du"; # на что нужно заменить
$filarr=file("my_file.txt");
$f=fopen("my_file.txt","w");
for($i=0;$i<count($filarr);$i++)
{
if(($i+1)!=$line){fwrite($f,$file[$i]);}
else{fwrite($f,$replace."\r\n");}
}
fclose($f);
?>
Поиск слова в файле. Ищем в файле file.txt слово привет:
<?PHP
$word="привет"; # искомое
$f="file.txt"; # имя файла, в котором будем искать слово
$open=fopen($file,"r");
while(!feof($open)) $search.=fgets($open,1024);
fclose($open);
if(eregi(strtolower($word),strtolower($search)))
{ echo "Слово ".$word." - найдено"; }
else
{ echo "Слово ".$word." - не найдено"; }
?>
Прямой доступ к указанной позиции бинарного файла осуществляется с помощью функции fseek (): fseek($file, $offset [, $reference]);
где $offset указывает число байт смещения от начала файла ($reference =SEEK_SET или по умолчанию) от текущей позиции файла ($reference=SEEK_CUR), от конца файла ($reference= SEEK_END). Функция fseek () может использоваться только для файлов, расположенных в локальной файловой системе и не работает с файлами, которые открываются удаленно по протоколу HTTP или FTP. Функция fseek () возвращает нуль в случае успешного завершения и -1 в случае, если указатель файла не может быть установлен. Отсчет смещений указателя в fseek () начинается с нуля. Чтобы установить указатель файла в позицию $offset, функции fseek () необходимо передать параметр $offset-l.
Копирование одного файла в другой можно выполнить с помощью функции copy(filefrom,fileto);. Функция unlink(filename) –удаляет файл. Функция rename(oldname, newname)-переименовывает файл.
Работа с каталогами в РНР
РНР предоставляет набор функций для работы с каталогами, а именно — функции для создания, удаления и вывода оглавления каталогов. Для этого в РНР имеются функции opendir() и closedir (), аналогичные функциям fopen () и f close () для файлов. Функция opendir () имеет следующий синтаксис:
$dir_reference =opendir($dir_path)
где $dir_path представляет собой путь к открываемому каталогу. Функция opendir () выведет сообщение об ошибке, если указанный каталог не существует. При успешном завершении функция opendir () возвратит дескриптор каталога. Функция closedir() принимает единственный параметр - дескриптор каталога из вызова opendir ().
После открытия каталога, каждый его элемент можно прочитать с помощью функции readdir (): readdir($dir_reference), где $dir_reference — это значение, которое возвращает вызов функции opendir (). При успешном завершении эта функция возвращает строку, содержащую имя одного из файлов каталога, связанного с параметром $dir_reference. Каждый последующий вызов функции readdir () возвращает очередной файл каталога (в порядке, в котором они хранятся в файловой системе), пока весь список файлов не будет исчерпан. Если файлов в каталоге больше нет, или произошла какая-нибудь ошибка, readdir () вернет значение false. Использование функций $OpenDir=opendir($dir) и readdir($OpenDir). Выведем содержимое папки c:/windows
<?
$dir="c:/windows"; # папка, которую нужно прочитать
if($OpenDir=opendir($dir))
{
while(($file=readdir($OpenDir)) !== false)
if($file != "." && $file != "..")
echo $file."<br>";
}
else echo "нет прав";
?>
Для создания каталога можно использовать функцию mkdir(name), для удаления – rmdir(), для изменения – chdir(). Чтение содержимого каталога:
<?php
$dr = @opendir(' /tmp/') ;
if(!$dr) {
echo "Ошибка при открытии каталога /tmp/!<BR>"; exit;
while (($filesf] = readdir($dr)) !== false);
print_r(Sfiles);
?>
Поскольку функция readdir () возвращает каждый раз новое имя файла, то каждый файл заданного каталога в отдельности можно просмотреть только однажды. Для тех случаев, когда необходимо повторно просмотреть содержимое каталога, РНР предоставляет функцию, которая позволяет "перемотать" оглавление каталога в исходное состояние, которое он имел перед первым вызовом функции readdir (). Эта функция, называемая rewinddir (), имеет следующий синтаксис: rewinddir($dir_reference)
Хотя функция opendir () и другие родственные ей функции имеют свои преимущества, особенно полезным является альтернативный метод получения списка файлов, удовлетворяющих определенному критерию (или шаблону). Этой цели служит функцияglob ():
glob($filemask [, flags])
Здесь $filemask — это строка, содержащая шаблон поиска (например, *.txt), a flags представляет одну или несколько констант, перечисленных ниже. Значения flags: GL0B_MARK -Добавлять слэш к именам, которые являются каталогами; GL0B_N0S0RT -Не сортировать возвращаемый список файлов; GL0B_N0CHECK -Если нет файлов, совпадающих с шаблоном, вернуть шаблон вместо пустого массива; GL0B_0NLYDIR -Вернуть только каталоги, совпадающие с шаблоном.
Использование функции glob ():
<?php
Sdirectories = glob("/tmp/*", GL0B_0NLYDIR);
$complete = glob("/tmp/*");
Sfiles = array_diff(Sdirectories, $complete);
echo "Каталоги в /tmp/<BR>";
foreach(Sdirectories as $val) ( echo "$val<BR>\n";)
echo "<BR><&aunbi в /tmp/<BR>";
foreach($files as Sval) ( echo "$val<BR>\n";)
?>
PHP и MySQL
MySQL – это многопоточный быстрый сервер баз данных, разработанный компанией TcX. MySQL является идеальным решением для малых и средних приложений, созданных на PHP и работает на множестве платформ. MySQL поддерживает стандарт языка запросов SQL и имеет множество расширений к стандарту. MySql сервер загружается автоматически вместе с web – сервером и постоянно работает на компьютере – сервере. MySQL поддерживает трехуровневую структуру: базы данных, таблицы, записи и может работать сразу с несколькими базами данных:
MySql – сервер: БД1; БД2; БД3; БД4;
Под БД понимается совокупность взаимосвязанных таблиц, объединенных общим управлением. Перед началом работы с MySql надо: спроектировать БД; спроектировать структуру таблиц БД; создать таблицы БД; создать БД.
Каждая таблица состоит из записей. В MySql используются следующие типы полей записей:
Целые числа: INT(-2147483648..2147483647), TINYINT(-128..127), SMALLINT, MEDIUMINT, BIGINT;
Вещественные числа: DOUBLE, REAL(синоним DOUBLE), FLOAT, DECIMAL (числовая строка), NUMERIC;
Строки: VARCHAR (1..255), TINYTEXT (1..255), TEXT(1..65535); MEDIUMTEXT,
LONGTEXT;
Блочно-бинарные данные: BLOB(до 65535 символов), TINYBLOB(до 255 символов), MEDIUMBLOB, LONGBLOB: при поиске, в отличие от TEXT, учитывается нижний и верхний регистр символов;
Дата и время: DATE(гггг-мм-дд), TIME(чч:мм:сс), DATETIME(гггг-мм-дд чч:мм:сс ), TIMESTAMP.
К полям могут присоединяться модификаторы primary key, auto_increment, Default.
Создание БД и таблиц может быть выполнено вручную, например c помощью приложения phpmyadmin, входящего в состав MySql. Набирается www.localhost/phpmyadmin и выполняются действия по созданию БД и таблиц.
Другой способ создание БД и таблиц состоит в использовании команд языка SQL, являющегося частью MySql.
Язык запросов SQL
Язык запросов SQL – основной язык для работы с реляционнми базами данных, построенными в соответствии с правилами реляционной алгебры. Состав языка SQL следующий:
Язык манипулирования данными состоящий из команд: SELECT (выбрать), INSERT (вставить), UPDATE (обновить), DELETE (удалить).
Язык определения данных используемый для создания и изменения структуры БД и ее составных частей – таблиц, индексов, представлений (виртуальных таблиц). Основными его командами являются: CREATE DATABASE (создать базу данных), CREATE TABLE(создать таблицу), CREATE INDEX(создать индекс), ALTER DATABASE (модифицировать базу данных), ALTER TABLE(модифицировать таблицу), ALTER INDEX(модифицировать индекс), DROP DATABASE (удалить базу данных), DROP TABLE(удалить таблицу), DROP INDEX(удалить индекс).
Язык управления данными (управления доступом) состоит из двух основных команд: GRANT (дать права), REVOKE (забрать права).
Наиболее важной и часто используемой командой языка манипулирования данными SQL является команда SELECT. Формат команды SELECT в языке SQL:
SELECT поля FROM таблицы WHERE условие;
Базовыми операциями команды SELECT являются: выборка, проекция, соединение, объединение.
Операция выборки позволяет получить все строки либо часть строк таблицы.
SELECT * FROM Student; – Получить все строки таблицы Student
SELECT * FROM Student WHERE Kurs=2; – Получить подмножество строк таблицы, удовлетворяющих условию Kurs=2. Точка с запятой является стандартным признаком конца команды, который вставляется автоматически.
Операция проекции позволяет выделить подмножество столбцов таблицы.
SELECT StudName FROM Student WHERE Kurs=2; – Получить имена студентов второго курса.
Операция соединения позволяет соединять строки из более чем одной таблицы:
SELECT StudName, Exammark FROM Students, Exams WHERE Students.Stud_Id =Exams.Stud_Id – Получить список студентов и экзаменационных оценок.
Операция объединения позволяет объединять результаты отдельных запросов. Предложение UNION объединяет вывод двух или более SQL-запросов.
SELECT name FROM employee WHERE country = "Беларусь" UNION SELECT contact_nаме, FROM customer WHERE country = "Беларусь"; – Получить список работников и заказчиков, проживающих в Беларуси.
Условия отбора. Директива WHERE содержит условия отбора (предикат). Запрос возвращает только строки, для которых предикат имеет значение true. Типы предикатов, используемых в предложении WHERE:
Сравнение: = (равно); <> (не равно); != (не равно); > (больше); < (меньше); >= (больше или равно); <= (меньше или равно); BETWEEN, IN , LIKE, CONTAINING, IS NULL, EXIST, ANY, ALL.
Предикат BETWEEN задает диапазон значений, для которого истинно значение выражения. Например:
SELECT StudName, Stipend FROM Student WHERE Stipend BETWEEN 120 AND 200 – получить список студентов стипендия которых больше 120 и меньше 200.
Тот же запрос с использованием операторов сравнения будет выглядеть следующим образом:
SELECT StudName, Stipend FROM Student WHERE Stipend>=120000 AND Stipend<=200000
Предикат IN (NOT IN) проверяет, входит ли заданное значение, предшествующее ключевому слову “IN”, в указанный в скобках список. Например:
SELECT name FROM employee WHERE job_code IN ("VP", "Admin", "Finan") – получить список сотрудников, занимающих должности “вице-президент”, “администратор”, “финансовый директор”.
Предикат LIKE проверяет, соответствует ли данное символьное значение строке с указанной маской. В качестве маски используются все разрешенные символы (с учетом верхнего и нижнего регистров), а также специальные символы: % – замещает любое количество символов, _ – замещает только один символ. Например:
SELECT StudName FROM Student WHERE StudName LIKE "Ф%" – получить список студентов, фамилии которых начинаются с буквы ‘Ф’.
Предикат CONTAINING аналогичен предикату LIKE, однако он не чувствителен к регистру букв.
Предикат IS NULL принимает значение true только тогда, когда выражение слева от “IS NULL” имеет значение null (пусто, не определено).
Логические операторы. К логическим операторам относятся NOT, AND, OR.В одном предикате логические операторы выполняются в указанном порядке.
Преобразование типов. В SQL имеется возможность преобразовать значение к другому типу для выполнения операций сравнения. Для этого используется функция CAST.
Изменение порядка выводимых строк. Порядок выводимых строк может быть изменен с помощью предложения ORDER BY в конце SQL-запроса. Это предложение имеет вид: ORDER BY [ASC | DESC]
Способом по умолчанию является упорядочивание “по возрастанию” (ASC). Если указано “DESC”, упорядочивание производится “по убыванию”. Например:
SELECT StudName, Stipend FROM Student ORDER BY StudName – получить список в алфавитном порядке.
Операция соединения.
Внутреннее соединение возвращает только те строки, для которых условие соединения принимает значение true. Рассмотрим пример запроса:
SELECT StudName, ExamMark FROM Student, Exams WHERE Kurs=2 AND ExamMark=5 – получить список студентов 2-го курса, сдававших экзамен на 5.
Внешнее соединение возвращает все строки из одной таблицы и те строки из другой таблицы, для которых условие соединения принимает значение true. Существуют два вида внешнего соединения: в левом соединении (LEFT JOIN) запрос возвращает все строки изтаблицы, стоящей слева от LEFT JOIN и только те из правой таблицы, которые удовлетворяют условию соединения. Для правого соединения – все наоборот. Например:
SELECT name, department FROM employee e LEFT JOIN department d ON e.dept_no = d.dept_no – получить список сотрудников и название их отделов, включая сотрудников, еще не назначенных ни в какой отдел.
Команды SQL для создания баз данных и таблиц
CREATE DATABASE database_name - создать базу данных,
CREATE TABLEtable_name(Имя_поля1 тип1, Имя_поля2 тип2…)-создать таблицу,
DROP DATABASE database_name - удалить базу данных,
DROP TABLE table_name-удалить таблицу,
ALTER DATABASE database_name - модифицировать базу данных,
ALTER TABLEtable_name-модифицировать таблицу,
INSERT INTO table_name(Имя_поля1 тип1, Имя_поля2 тип2…) values(‘val1’,’val2’,…) - вставка записи со значениями полей val1, val2, … .
DELETE FROM table_name WHERE выражение -удаление записи, для которой выполнено выражение
UPDATE table_nameSET(Имя_поля1 ‘val1’, ‘Имя_поля2 val2’…) where выражение –обновить таблицу.
Для выполнения SQL запроса используется функция mysql_query($sql);. Сначала создается строка, содержащая SQL – запрос. Затем эта строка передается для выполнения. Рассмотрим пример выполнения команд SQL по созданию базы данных из PHP:
//соединяемся с сервером
int mysql_connect();
// создаем базу данных:
$sql=”create database ‘mydb’”;
mysql_query($sql);//выполнение директивы SQL
//Cоздаем таблицу:
$sql=”CREATE TABLE userstable
(name VARCHAR(25), email VARCHAR(25), choise VARCHAR(15))”
mysql_query($sql); );//выполнение директивы SQL
Аналогично порядок работы с MySQL для выборки данных из базы в PHP устанавливается следующий:
Создать соединение с сервером MySQL, расположенным на $hostname:
int mysql_connect([string $hostname],[string $username],[string password]);
или mysql_pconnect().
Здесь hostname - имя хоста (по умолчанию localhost), username - имя пользователя, password - пароль пользователя. Функция возвращает параметр ID соединения (link_identifier), который равен 0, если соединение не прошло успешно.
Выбрать базу данных для работы:
int mysql_select_db($database_name[, int link_identifier]);
Здесь: database_name - имя базы данных, link_identifier – необязательный параметр, содержащий ID соединения из mysql_connect. Если этот параметр отсутствует, выбирается последнее открытое соединение. Функция возвращает значение true или false.
Выполнить запрос к базе данных.
int mysql_query(string $query[, int $link_identifier]);
Здесь $query - строка, содержащая SQL запрос, link_identifier –ID соединения. Функция возвращает ID результата или 0, если произошла ошибка.
Закрыть соединение с MySQL.
int mysql_close(int link_identifier); Параметры: link_identifier - ID соединения. Функция возвращает значение true или false.
Пример: Создание базы данных и таблицы.
<html>
<head>
<title>Запрос информации</title>
<body>
<center> Введите Ваши данные <p>
<table width = 400><tr><td align = right>
<form action="pr1BD.php" method="post">
Ваше имя:<BR>
<input type="text" name="name" size="20" maxlength="30">
<P>
Ваш email:<BR>
<input type="text" name="email" size="20" maxlength="30">
<p>
<input type="submit" value="Отправить запрос!">
</form>
</td></tr></table></center>
</body>
</html>
<?php // pr1bd.php - скрипт создает БД и таблицу
$dbName ='mydb';
/* создать соединение */
$link = mysql_connect( "localhost" , "root" ) or exit("Could not connect");;
/* уничтожить старую БД */
$sql= sprintf("DROP DATABASE %s ",$dbName);
if (mysql_query($sql, $link)) {
echo "Database drop successfully\n";
} else { echo 'Error drop database: ' . mysql_error() . "\n"; }
/* создать новую БД */
$sql="create database $dbName";
//выполнение директивы SQL
if (mysql_query($sql, $link)) {
echo "Database created successfully\n";
} else { echo 'Error creating database: ' . mysql_error() . "\n"; }
//Cоздаем таблицу: mydb.clients
$tablename = 'clients' ;
$sql=sprintf("CREATE TABLE %s.%s (
`name` VARCHAR( 25 ) NOT NULL , `email` VARCHAR( 25 ) NOT NULL ) ENGINE = MYISAM ",$dbName,$tablename);
if (mysql_query($sql, $link)) {
echo "Table created successfully\n";
} else { echo 'Error creating Table: ' . mysql_error() . "\n"; }
$name=$_POST['name'];
$email=$_POST['email'];
// вставка записи со значениями полей val1, val2,
$sql=sprintf("INSERT INTO %s.%s values('$name', '$email')", $dbName, $tablename);
if (mysql_query($sql, $link)) {
echo "Table insert successfully\n";
} else { echo 'Error insert Table: ' . mysql_error() . "\n"; }
mysql_close($link); /* Закрыть соединение */
$link = mysql_connect( "localhost" , "root" )or die("Не могу создать соединение ");;
//Выбрать БД
$result =mysql_select_db("$dbName",$link) or die("Не могу выбрать базу данных ");
//создать SQL - запрос
$sql=sprintf("Select * from %s", $tablename);
$result = mysql_query($sql,$link);
if (!$result) { die('Invalid query: ' . mysql_error()); }
$myrow=mysql_fetch_array($result); //установка первой записи
echo"<br>", $myrow['name'];//вывод поля “name” первой записи
echo $myrow['email'];
mysql_close($link);/* Закрыть соединение */
?>
Phpmyadmin
Программное средство phpmyadmin представляет удобные средства и инструменты для создания баз данных, для проектирования и создания таблиц. Вызвать утилиту возможно следующим образом: http://www.localhost/phpmyadmin
Здесь можно вручную создать базу данных и установить права доступа. Затем создается структура таблиц и сами таблицы.
Выборка данных из таблиц БД
Создать соединение с MySQL.
int mysql_connect(string hostname, string username, string password);
Выбрать базу данных для работы.
int mysql_select_db(string database_name, int link_identifier);
SQL запрос к базе данных на выборку данных.
int mysql_query(string query, int link_identifier);
Функция возвращает ID результата или 0, если произошла ошибка.
Закрытие соединения с MySQL.
int mysql_close(int link_identifier);
Выборка данных из базы производится SQL командой SELECT.
В PHP имеются ряд функций, позволяющих сохранять и обрабатывать данные, на которые указывает дескриптор, $result=mysql_query(“SELECT …”);
int mysql_result(int result, int i, column);
Функция возвращает значение поля в столбце column и в строке i.
int mysql_num_rows(int result);
Функция возвращает количество строк в результате запроса.
mysql_fetch_row($result))
Возвращает массив соответствующий очередной записи таблицы
mysql_fetch_array(result)
Возвращает результаты запроса в виде ассоциированного массива
<?php
$db = mysql_connect("localhost", "root");
mysql_select_db("mydb",$db);
$result = mysql_query("SELECT * FROM employees",$db);
$str= mysql_result($result,0,"first");
printf("First Name: %s<br>\n",$str);
$str= mysql_result($result,0,"last");
printf("Last Name: %s<br>\n",$str);
$str= mysql_result($result,0,"address");
printf("Address: %s<br>\n",$str);
$str= mysql_result($result,0,"position");
printf("Position: %s<br>\n",$str);
mysql_close($db);
?>
Функция mysql_connect() открывает связь с сервером баз данных MySQL. В результате выполнения этой функции получаем значение идентификатора соединения, которое присваиваем переменной $db. C помощью функции mysql_select_db() выбираем базу данных. В качестве параметров передаем название нужной нам базы данных и идентификатор соединения, полученный нами при выполнении предыдущей команды.
В результате выполнения функции mysql_select_db() получаем значение true, если соединение с базой данных произошло успешно иначе false. Наконец, мы обращаемся к базе данных с запросом на языке SQL. Для этого служит функция mysql_query(). Результаты выполнения функции mysql_query() – записи, удовлетворяющие нашему запросу - помещаем в переменную $result.
С помощью функции mysql_result() извлекаем из переменной $result, первую запись (порядковый номер 0), и значение определенного поля (по его имени). Перебирая друг за другом записи, выберем все записи, что хранятся в базе данных.
Далее мы познакомимся с более интеллектуальными, чем mysql_result(), функциями выборки данных из БД mysql_fetch_row() и mysql_fetch_array(). Попробуем вывести все записи, хранящиеся в нашей базе данных. Обратимся к базе данных со следующим кодом:
<html>
<body>
<?php
$db = mysql_connect("localhost", "root");
mysql_select_db("mydb",$db);
$result = mysql_query("SELECT * FROM employees",$db);
echo "<table border=1>\n";
echo "<tr><td>Name</td><td>Position</tr>\n";
while ($myrow = mysql_fetch_row($result))
{
printf("<tr><td>%s %s</td><td>%s</td></tr>\n", $myrow[1], $myrow[2], $myrow[3]);
}
echo "</table>\n";
?>
</body>
</html>
Цикл while() говорит, что пока в переменной $result остается запись для выборки, ее необходимо извлечь с помощью функции mysql_fetch_row и присвоить переменной $myrow. А после этого выполнить код, что расположен внутри фигурных скобок "{}". Функции mysql_fetch_row в качестве параметра подается массив $result. Функция выбирает из него строку, которую мы можем записать в переменную $myrow и автоматически переходит на следующую строку. Вызвав снова mysql_fetch_row, мы выберем следующую строку из массива, и так далее до тех пор, пока не достигнем конца массива. В этом случае mysql_fetch_row вернет значение false, которое послужит сигналом, что все записи выбраны и можно завершить цикл.
Теперь наша задача как-то вывести в теле цикла полученную запись. Выбранный ряд у нас хранится в переменной $myrow. Она также, как и $result, является массивом, только одномерным. На первый взгляд процедура извлечения данных весьма сложна, но она вполне логически понятна и объяснима. Главное не забывайте, что элементы массивов нумеруются от 0, а не от 1, так как здесь мы имеем дело с компьютерной, а не человеческой логикой. Наш код грешит одним недостатком: если в базе данных не будут найдены записи, удовлетворяющие нашему запросу, мы не получим никакого сообщения об этом. Неплохо было бы, чтобы программа выдавала какое нибудь сообщение. Сделаем ее более дружественной. Взгляните на следующий код:
Пример: Соединение с БД и выборка записей
<?// php428bd.php - скрипт создает БД и таблицу
$dbName ="mydb";
/* создать соединение */
$link = mysql_connect("localhost", "valera", "12345")
or exit("Could not connect");
mysql_select_db("$dbName",$link) or die("Не могу выбрать базу данных ");
//создать SQL - запрос
$sqlq="Select * from students";
//
$result = mysql_query($sqlq,$link) or die ("Invalid query");
$myrow=mysql_fetch_array($result); //установка первой записи
echo $myrow["name"];//вывод поля “name” первой записи
do//цикл просмотра всех записей
{
echo “сотрудник-”, $myrow[‘id’];
echo $myrow["name"];
}
while($myrow=mysql_fetch_array($result));
MYSQL_CLOSE();/* Закрыть соединение */
?>
<html>
<body>
<?php
$db = mysql_connect("localhost", "root");
mysql_select_db("mydb",$db);
$result = mysql_query("SELECT * FROM employees",$db);
if ($myrow = mysql_fetch_array($result))
{
echo "<table border=1>\n";
echo "<tr><td>Name</td><td>Position</td></tr>\n";
do
{
printf("<tr><td>%s %s</td><td>%s</tr>\n", $myrow["first"], $myrow["last"],
$myrow["address"]);
}
while ($myrow = mysql_fetch_array($result));
echo "</table>\n";
}
else
{
echo "Sorry, no records were found!";
}
?>
</body>
</html>
В данном коде вместо функции mysql_fetch_row() мы использовали функцию mysql_fetch_array(). Она работает точно так же, как и mysql_fetch_row() за одним замечательным исключением: с помощью этой функции мы можем обращаться к каждому полю массива не по номеру, а по имени. Например, если раньше для получения имени нам приходилось писать $myrow[1] (1 – второй столбец массива), то теперь мы можем писать $myrow["first"] ("first" – название столбца в базе данных и в массиве). Второй вариант естественно гораздо информативнее и удобнее. Кроме этого, в коде использован цикл do/while и условная конструкция if-else. Выражение if-else говорит, что если мы можем присвоить значение $myrow, то надо начать выборку, в противном случае мы понимаем, что записей нет, переходим к блоку else и выводим соответствующее сообщение. Чтобы проверить, как работает эта часть кода, замените SQL-выражение на "SELECT * FROM employees WHERE id=6" или на какое-нибудь другое, которое не даст результата.
Сейчас мы поработаем со параметрами запроса. Как вы уже наверняка знаете, существует три способа передачи параметров запроса. Первый, использовать метод GET в форме (с ним мы разобрались в главе "Работа с формами"). Второй – набрать параметры прямо в адресной строке броузера. И третий, это вставить параметры в обычную ссылку на странице. То есть сделать ссылку примерно такого вида
<a href="http://my_machine/mypage.php3?id=1">
Для начала, давайте обратимся к базе данных и выведем список персонала. Взгляните на следующий код.
<html>
<body>
<?php
$db = mysql_connect("localhost", "root");
mysql_select_db("mydb",$db);
$result = mysql_query("SELECT * FROM employees",$db);
if ($myrow = mysql_fetch_array($result))
{
do
{
printf("<a href=\"%s?id=%s\">%s %s</a><br>\n", $PHP_SELF, $myrow["id"],$myrow["first"],
$myrow["last"]);
}
while ($myrow = mysql_fetch_array($result));
}
else
{
echo "Sorry, no records were found!";
}
?>
</body>
</html>
Все вам должно быть знакомо, кроме функции printf(). Поэтому, давайте рассмотрим ее поближе. Во-первых, обратите внимание на обратные косые черты. Они говорят PHP-движку, что необходимо вывести символ, следующий за чертой, а не рассматривать его, как служебный символ или как часть кода. В данном случае это касается кавычки, которая нам нужна в тексте ссылки, но для PHP является символом окончания текстовой строки.
Далее, в коде используется интересная переменная $PHP_SELF. В этой переменной всегда хранится имя и URL текущей страницы. В данном случае эта переменная важна для нас потому, что мы хотим через ссылку вызвать страницу из нее самой. То есть вместо того, чтобы делать две страницы, содержащие разные коды для разных действий, мы все действия запихнули в одну страницу. С помощью условий if-else мы будем переводить стрелки с одного кода на другой, гоняя одну и ту же страницу по кругу. Это конечно увеличит размер страницы и время, необходимое на ее обработку, но в некоторых случая, такой трюк очень удобен. Переменная $PHP_SELF гарантирует нам, что наша страница будет работать даже в том случае, если мы перенесем ее в другой каталог или даже на другую машину. Как мы уже сказали, ссылки, сгенерированные в цикле ссылаются на ту же самую страницу, только к имени самой страницы на лету добавлена некоторая информация: переменные и их значения. Переменные, которые передаются в строке-ссылке, автоматически создаются PHP-движком, и к ним можно обращаться так, как если бы вы их создавали в коде сами. При втором проходе страницы наша программа отреагирует на эти пары name=value и направит ход исполнения на другие рельсы. В данном случае мы проверим, есть ли переменная $id, и в зависимости от результата выполним тот или иной код. Вот как это будет выглядеть:
<html>
<body>
<?php
$db = mysql_connect("localhost", "root");
mysql_select_db("mydb",$db);
// display individual record
if ($id)
{
$result = mysql_query("SELECT * FROM employees WHERE id=$id",$db);
$myrow = mysql_fetch_array($result);
printf("First name: %s\n<br>", $myrow["first"]);
printf("Last name: %s\n<br>", $myrow["last"]);
printf("Address: %s\n<br>", $myrow["address"]);
printf("Position: %s\n<br>", $myrow["position"]);
}
else
{
// show employee list
$result = mysql_query("SELECT * FROM employees",$db);
if ($myrow = mysql_fetch_array($result))
{
// display list if there are records to display
do
{
printf("<a href=\"%s?id=%s\">%s %s</a><br>\n", $PHP_SELF, $myrow["id"],
$myrow["first"], $myrow["last"]);
}
while ($myrow = mysql_fetch_array($result));
}
else
{
// no records to display
echo "Sorry, no records were found!";
}
}
?>
</body>
</html>