PHP5_nachinayushim
.pdf334 Глава 7
$file_info_array["fileowner"] = fileowner($file);
}else {
$file_info_array["fileatime"] = "недоступно"; $file_info_array["filegroup"] = "недоступно";
$file_info_array["fileowner"] = "недоступно";
}
$extension = array_pop(explode(".", $file));
if (in_array($extension, $text_file_array)) { $file_info_array["filetype"] = "текстовый";
} else {
$file_info_array["filetype"] = "двоичный";
}
return $file_info_array;
}
Обратите внимание, как с помощью функции explode(".", $file) из задан+ ного имени файла выделяется расширение. Функция разделяет имя файла, используя в качестве разделителя точку (.), и возвращает в виде массива полученные в резуль+ тате части имени. Последний элемент извлекается из массива с помощью функции array_pop() и сохраняется в переменной $extension. В данном случае расшире+ ние не является вторым элементом.
В последнем блоке файла common_php5_02.inc.php создается массив расшире+ ний файлов:
// задаем расширения обрабатываемых файлов
$text_file_array = array( "txt", "htm", "html", "php", "inc", "dat" );
Теперь можно создавать структуру главного файла обработки, editor_php5.php. Сначала вводится заголовок для обычной HTML+страницы:
<html>
<head><title>Текстовый редактор</title></head> <body>
<form method="POST" action="<?php echo $_SERVER['PHP_SELF']; ?>"> <input type="hidden" name="posted" value="true">
Затем начинается PHP+код и подключается (с помощью функции require()) файл common_php5.inc.php. После чего задается используемый каталог:
require("common_php5_02.inc.php"); //определение каталога по умолчанию
$dir = "./docs";
Следующий фрагмент кода проверяет, нажал ли пользователь кнопку, и если это так, то устанавливает соответствующее значение для окончательного оператора select..case:
if (isset($_POST['save_edited_file'])) { $action_chosen = "save_file";
} elseif (isset($_POST['create_new_file'])) {
$action_chosen = "save_file"; } elseif (isset($_POST['edit_existing_file])) { $action_chosen = "edit_existing_file";
}
Далее начинается оператор select..case и создается case+блок save_file. Этот код проверяет существование файла, и если файл существует, то используется JavaScript+сценарий, запрашивающий у пользователя подтверждение на перезапись данного файла:
switch ($action_chosen) { case "save_file";
Файлы и каталоги 335
if (file_exists("$dir/$_POST[filename]")) {
echo "<script>result = confirm(\"Перезаписать файл '$dir/$_POST[filename]'?\"); if(!result) history.go
(-1);</script>";
}
Для отправки пользователю сообщения об ошибке, в случае если попытка открыть (или создать) файл оказалась неудачной, используется функция error_message():
if ($file = fopen("$dir/$_POST[filename]", "w")) { fputs($file, $_POST[filebody]);
fclose($file);
}else {
error_message("Невозможно сохранить файл $dir/$_POST[filename].");
}
Последний фрагмент кода в case+блоке save_file использует HTML для отобра+ жения простых кнопок, позволяющих пользователю выполнять доступные в прило+ жении операции. Обратите внимание на отличие кода создания листинга каталогов для наполнения выпадающего списка. Тот же код используется в case+блоке по умол+ чанию. В конце этого блока необходимо поместить ключевое слово break:
//отображение основных кнопок
?>
<table border="1" align="center"><tr><td>
<strong>Создать (или перезаписать) новый файл или редактировать существующий файл</strong>
</td></tr>
<tr><td>
<input type="submit" name="create_new_file" value="Создать новый файл"> <input type="text" name="filename" value="new.txt">
</td></tr>
<tr><td>
<input type="submit" name="edit_existing_file" value="Редактировать существующий файл">
<select name="existing_file"> <?php
if($dp = opendir($dir)) { while($file = readdir($dp)) {
if($file !== '.' && $file !== '..' && is_file($dir."/".$file)) {
?>
<option value="<?php echo $file; ?>"> <?php echo $file; ?></option>
<?php
}
}
} else {
error_msg("Невозможно открыть каталог $dir.");
}
closedir($dp);
?>
</select>
</td></tr></table>
<?php
break;
336 Глава 7
Рассмотрим case+блок edit_existing_file. Сценарий устанавливает свойства файла, включая filebody, и помещает результаты работы функции file_info() в мас+ сив $file_info_array:
case "edit_existing_file";
$filepath = "$dir/$_POST[existing_file]"; $filebody = implode("",file($filepath)); $file_info_array = file_info("$filepath");
Затем необходимо проверить, является ли данный файл текстовым, и если это не так, то записать в свойство filebody уведомление о том, что данный файл редакти+ рованию не подлежит:
if ($file_info_array["filetype"] != "text") {
$filebody = $filepath . " не является текстовым файлом. Редактирование невозможно.";
$editable = 0; } else {
$editable = 1;
}
Отображение информации о файле:
?>
<table border="1" width="70%" align="center">
<tr><th width="100%" colspan="2"> <center><strong>Информация о существующем файле <?php echo
"$dir/$_POST[existing_file]"; ?> </td></tr>
<?php
$file_info_array = file_info("$dir/$_POST[existing_file]");
foreach ($file_info_array as $key=>$val) {
echo "<tr><th width=\"30%\">". ucfirst($key)
. "</td><td width=\"70%\">" . $val
. "</td></tr>\n";
}
?>
</table>
Последние строки case+блока edit_existing_file позволяют пользователю от+ редактировать и сохранить файл:
<br>
<table border="1" align="center"><tr><td> <strong>Редактирование существующего файла <?php echo
$_POST['existing_file']; ?></strong> </td></tr>
<tr><td>
<?php
if ($editable == 0) { echo $filebody;
} else { ?>
<input type="hidden" name="filename" value="<?php echo $_POST['existing_file]; ?>">
<textarea rows="4" name="filebody" cols="40" wrap="soft"> <?php
echo "$filebody"; ?>
</textarea><br>
<input type="submit" name="save_edited_file" value="Сохранить файл"> <?php
Файлы и каталоги 337
}
?>
</td></tr></table>
<?php
break;
Блок default представляет собой копию последней части case+блока save_file:
default;
//отображение основных кнопок
?>
<table border="1" align="center"><tr><td>
<strong>Создать (или перезаписать) новый файл или отредактировать существующий</strong>
</td></tr>
<tr><td>
<input type="submit" name="create_new_file" value="Создать новый файл"> <input type="text" name="filename" value="new.txt">
</td></tr>
<tr><td>
<input type="submit" name="edit_existing_file" value="Редактировать существующий файл">
<select name="existing_file"> <?php
if($dp = opendir($dir)) { while($file = readdir($dp)) {
if($file !== '.' && $file !== '..' && is_file ($dir."/".$file)) {
?>
<option value="<?php echo $file; ?>"><?php echo $file; ?></option> <?php
}
}
} else {
error_msg("Невозможно открыть каталог $dir.");
}
closedir($dp);
?>
</select> </td></tr></table> <?php
break;
В последней части сценария закрывается оператор select..case, а также завер+ шается HTML+код для страницы, включая закрывающий тег </form>.
}
?>
</form>
</body>
</html>
Данный сценарий очень хорошо иллюстрирует использование функций для рабо+ ты с файловой системой.
Загрузка файлов на сервер
Созданный только что ‘‘навигатор’’ можно улучшить, добавив в него возмож+ ность загружать файлы с локальной машины на сервер. PHP предоставляет простой способ для внедрения в приложение подобной функциональности. Загружать файлы
338 Глава 7
с помощью браузера позволяет элемент HTML+формы <input>, имеющий тип file. Для загрузки файлов также необходимо установить в теге <form> атрибут enctype (со значением multipart/form-data), который при создании обычной формы, как правило, опускается.
Ниже приведен примерный код формы для загрузки файлов:
<form method="POST" enctype="multipart/form-data"
action="<?php echo "$_SERVER[PHP_SELF]?action=upload_file&dir=$dir"; ?>">
Локальный файл <input type="file" name="userfile"> <input type="submit" name="submit" value="Загрузить">
</form>
Атрибут action данной формы должен указывать на PHP+сценарий, который бу+ дет обрабатывать загружаемый файл. Вводить второе текстовое поле необходимо только в том случае, если желательно предоставить пользователю возможность зада+ вать имя, с которым загружаемый файл будет сохраняться на сервере.
Как только файл загружается, через суперглобальный массив $_FILES становятся доступны следующие переменные:
Переменная |
Описание |
|
|
$_FILES[userfile] |
Массив в $_FILES, содержащий другие значения |
$_FILES[userfile][name] |
Исходный (на пользовательской машине) путь и имя |
|
загруженного файла |
$_FILES[userfile][size] |
Размер загруженного файла в байтах |
$_FILE[userfile][type] |
Тип файла (если браузер предоставляет данную |
|
информацию) |
Предположим, пользователь с помощью формы только что загрузил zip+файл C:\bsdocs\projects.zip размером 20 000 байт. В таком случае указанные пере+ менные содержат следующие значения:
$_FILES[userfile][tmp_name]: путь к файлу во временном каталоге (который устанавливается в php.ini) и временное имя файла в формате "php-###" (где "###" ++++++ номер, автоматически генерируемый PHP), например, "/tmp/php-512".
$_FILES[userfile][name]: "C:\bsdocs\projects.zip". $_FILES[userfile][size]: 20000.
$_FILES[userfile][type]: "application/x-zip-compressed".
Эти значения при желании можно записать в обычные переменные, например, так:
//определение параметров пользовательского файла $userfile_name = $_FILES['userfile']['name']; $userfile_tmp_name = $_FILES['userfile']['tmp_name']; $userfile_size = $_FILES['userfile']['size']; $userfile_type = $_FILES['userfile']['type']; if(isset($_ENV['WINDIR'])) {
$userfile = str_replace("\\\\","\\", $_FILES['userfile']['name']);
}
Загружаемый файл сохраняется во временном каталоге, заданном в файле php.ini, и уничтожается по окончании данного запроса, поэтому его необходимо скопировать в какой+либо другой каталог. По соображениям безопасности для этого рекомендуется использовать функцию move_uploaded_file() вместо copy():
Файлы и каталоги 339
$archive_dir = "./docs";
$filename = basename($userfile_name);
if(!@move_uploaded_file($userfile, "$archive_dir/$filename")) echo "Ошибка: невозможно скопировать файл $filename.";
else echo "Файл $filename успешно загружен.";
Можно установить ограничение на размер загружаемых файлов и с помощью пе+ ременной $userfile_size проверять, не превышает ли размер загружаемого файла заданное ограничение:
$archive_dir = "./docs"; $max_filesize = 200000;
$filename = basename($userfile_name);
if($userfile_size > $max_filesize)
echo "Ошибка: файл $filename слишком велик. " .
. "Максимальный размер загружаемого файла: " . number_format($max_filesize) . " байтов.";
else if(!copy($userfile, "$archive_dir/$filename"))
echo "Ошибка: невозможно скопировать файл $filename."; else echo "Файл $filename успешно загружен.";
Еще один способ ограничить размер загружаемых файлов заключается в использо+ вании скрытого поля формы:
<input type="hidden" name="max_file_size" value="200000">
...
if($userfile_size > $max_file_size)
echo "Ошибка: файл $filename слишком велик. " .
. "Максимальный размер загружаемого файла: " . number_format($max_filesize) . " байт.";
Установка данного ограничения внутри сценария ++++++ гораздо более безопасный ме+ тод, потому что злоумышленник может отредактировать содержимое Web+страницы, содержащей форму для загрузки, и установить любое ограничение.
Практика Загрузка файлов
Ниже приведен завершенный пример реализации функции загрузки файлов:
<?php //file_upload.php
function upload_form() { ?>
<table border="1" align="center"> <tr><td>
<form method="POST" enctype="multipart/form-data"
action="<? echo $_SERVER['PHP_SELF'] ?>">
Выберите файл для загрузки
<input type="file" name="userfile">
<input type="submit" name="action" value="Загрузить"> </form>
</td></tr>
</table>
<?
}
function upload_file() { //установка архивного каталога
$archive_dir = "./docs";
//определение параметров пользовательского файла $userfile_name = $_FILES['userfile']['name']; $userfile_tmp_name = $_FILES['userfile']['tmp_name']; $userfile_size = $_FILES['userfile']['size']; $userfile_type = $_FILES['userfile']['type'];
340 Глава 7
if(isset($_ENV['WINDIR'])) {
$userfile = str_replace("\\\\","\\", $_FILES['userfile']['name']);
}
$filename = basename($userfile_name); if($userfile_size <= 0) die ("Файл $filename пуст.");
if(!@move_uploaded_file($userfile_tmp_name, "$archive_dir/$filename")) die("Невозможно скопировать файл $userfile_name в $filename.");
if(isset($_ENV['WINDIR']) && !@unlink($userfile)) die ("Невозможно удалить файл $userfile_name.");
echo "Файл $filename был успешно загружен.<BR>";
echo "Размер файла: " . number_format($userfile_size) . "<BR>"; echo "Тип файла: $userfile_type<BR>";
}
?>
<html>
<head><title>Загрузка файла</title></head> <body>
<?php
if($_POST[action] == 'Загрузить') { upload_file();
} else { upload_form();
}
?>
</body>
</html>
На рис. 7.11 изображена форма для загрузки (в данном случае для загрузки выбран файл 2.gif).
Рис. 7.11.
Файлы и каталоги 341
Пользователь, загружающий данный файл, в случае успешной загрузки увидит страницу, показанную на рис. 7.12.
Рис. 7.12.
Как это работает
Когда пользователь загружает файл со своей локальной машины, сценарий снача+ ла получает значения массива $_FILES, а затем определяет платформу, на которой работает. Если таковой является Windows, то все вхождения двойной обратной косой черты необходимо заменить на одинарную обратную косую черту:
//установка архивного каталога
$archive_dir = ./docs";
//определение параметров пользовательского файла $userfile_name = $_FILES['userfile']['name']; $userfile_tmp_name = $_FILES['userfile']['tmp_name']; $userfile_size = $_FILES['userfile']['size']; $userfile_type = $_FILES['userfile']['type']; if(isset($_ENV['WINDIR'])) {
$userfile = str_replace("\\\\","\\", $_FILES['userfile']['name']);
Если размер файла меньше нуля, то пользователь отправил форму, не указав за+ гружаемый файл:
if($userfile_size <= 0) die ("Файл $filename пуст.");
Если все в порядке, то сценарий копирует загруженный файл в архивный каталог и определяет платформу, на которой выполняется. Если это не Windows, то для уда+ ления временного файла можно использовать функцию unlink(). После этого выво+ дится сообщение о том, что файл загружен, а также размер и тип данного файла.
342 Глава 7
Резюме
В настоящей главе рассматривались функции для работы с файлами, в том числе функции для чтения и записи файлов. На примерах было продемонстрировано созда+ ние простого текстового редактора на Web+странице, а также работа с каталогами и создание сценария для обхода дерева каталогов.
Данная глава охватывает большинство основных PHP+функций для работы с фай+ лами и каталогами. В некоторых из них используется дескриптор файла или катало+ га ++++++ указатель, ссылающийся на открытый файл или каталог. Работа с такими функ+ циями состоит из следующих этапов:
1.Открытие файла или каталога с помощью функции fopen() или opendir().
2.Работа с открытым файлом или каталогом с помощью функций fread(), fgets(), fpassthru() и readdir() др.
3.Закрытие файла или каталога с помощью функций fclose() или closedir().
Наконец, в главе рассматривалось создание текстового редактора, который может сканировать дерево каталогов и манипулировать записями в нем.
В главе не обсуждались некоторые редко применяемые в Web+приложениях функ+ ции. Полный перечень функций для работы с файлами и каталогами можно просмот+ реть на Web+сайте PHP http://php.net/manual/ref.filesystem.php.
Упражнение
Создайте PHP+приложение, которое можно использовать для поиска определен+ ного каталога в правильно заданном родительском каталоге. Приложение должно просматривать указанный каталог, а также все каталоги, которые в нем находятся.
8
XML
XML (eXtensible Markup Language ++++++ расширяемый язык разметки) ++++++ сравнитель+ но новая идея. Первоначально XML разрабатывался как удобный для человека способ обмена структурированными данными, но впоследствии весьма быстро получил ши+ рокое распространение также как средство хранения структурированной информа+ ции. Хотя XML во многом отличается от баз данных, он, как и базы данных, представ+ ляет собой метод форматирования и/или постоянного хранения данных, а также имеет свои преимущества и недостатки.
XML на самом деле является не языком, а спецификацией для создания собствен+ ных языков разметки. XML представляет собой подмножество языка SGML (Standard Generalized Markup Language ++++++ стандартный обобщенный язык разметки, предшест+ венник HTML). XML предназначен для упрощения обмена данными между несовмес+ тимыми приложениями. Форматирование XML+документов очень похоже на форма+ тирование HTML+документов. В отличие от HTML, который имеет фиксированное множество дескрипторов и атрибутов, определенных в спецификации HTML, XML позволяет писать собственные дескрипторы (которые также называются элементами) и атрибуты и, таким образом, предоставляет возможность определения собственного языка в XML+ или любом другом определении. В сущности, с помощью XML можно форматировать любые данные.
В дополнение к этому XML предоставляет средства для создания определений данных, которые будут доступны другим приложениям в сети. Таким образом, два приложения, которые ничего ‘‘не знают’’ друг о друге, но оба способны анализиро+ вать XML+документы, смогут обмениваться данными друг с другом.
По этим причинам XML быстро становится стандартом обмена данными, а в PHP5 имеется множество новых средств и функций, которые ускоряют работу с XML+ данными и делают ее эффективнее и понятнее. В PHP5 включены все XML+функции PHP4, а также новые функции, основанные на simpleXML (встроенное PHP+ расширение, поддерживающее общие XML+операции).