Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Очень просто о PHP, от элементарных понятий до ООП Часть 5. Работа с файлами


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

Итак, продолжим:


Детский сад

Когда вы начали читать этот курс, я обещал вам кучу веселья. Если вы - циничный тип, то вы можете подумать что я не выполнил обещания. В конце-концов, сколько вы получали удовольствия до сих пор? Всё что мы делали - это изучили кучу теоретических правил, складывали и отнимали числа, изучали примитивный процесс принятия решений и нарезали круги вокруг циклов. Чёрт, если это не пособие по PHP, то наверное это детский сад!

Я вас понимаю.

В этой части бесконечной саги мы будем изучать как сделать определённо недетские штучки. Мы погрузимся в болото файлов на диске: нахождение (опа!), чтение из содержимого (фигасе!!) и (о ужас!!!) запись в них данных. Все эти захватывающие мероприятия будут проходить под эгидой очень крутого API для манипуляции файлов в PHP, который позволяет вам видеть и изменять атрибуты файлов, читать и показывать содержимое папки, изменять права доступа к файлу, получать содержимое файла в самые разные структуры данных и искать файлы по указанной маске.

Начнём!

Обращаться осторожно

Начнём с чего попроще: открытие файла и чтение содержимого. Давайте предположим что где-то у вас на диске, в далёкой-далёкой папке /usr/local/stuff/that/should/be/elsewhere/recipes/ лежит файл, содержащий рецепт отличного испанского омлета и теперь вы хотели-бы прочитать содержимое файла в свой PHP-скрипт.

Для того чтобы сделать это, вам требуется выполнить три действия:

  • открыть файл и назначить ему дескриптор;
  • поработать с файлом через его дескриптор - извлечь содержимое в переменную PHP;
  • закрыть файл.

Вот скрипт, который делает это:

<?php

// укажем имя файла
$file = '/usr/local/stuff/that/should/be/elsewhere/recipes/omelette.txt'
or die('Не могу открыть файл!'); 
// откроем файл 
$fh = fopen($file, 'r') or die('Не могу открыть файл!'); 
// прочитаем содержимое
$data = fread($fh, filesize($file)) or die('Не могу прочитать файл!'); 
// закроем файл
fclose($fh); 
// напечатаем содержимое
echo $data;

?>

Запустите этот скрипт в вашем Web-браузере и он покажет содержимое файла.

Давайте подробно разберём три этих шага:

  • открыть файл и назначить ему дескриптор

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

Есть три разных режима открытия файла для функции fopen():

  • 'r' - открывает файл в режиме только для чтения;
  • 'w' - открывает файл в режиме для записи и уничтожает его старое содержимое;
  • 'a' - открывает файл в режиме добавления (не уничтожая его старого содержимого).
  • поработать с файлом через его дескриптор - извлечь содержимое в переменную PHP

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

Второй аргумент для функции fread() - это число байтов для чтения. Обычно эту цифру можно получить функцией filesize(), которая (кто-бы мог подумать?!) возвращает размер файла в байтах.

  • закрыть файл

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

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

То-же самое, но в профиль

Другой метод чтения данных из файла - очень крутая функция file(), которая читает весь файл в массив (помните такие?) благодаря одной строке кода. Каждый элемент массива содержит одну строку файла. Чтобы показать содержимое файла, просто пройдитесь по массиву циклом foreach() и напечатайте каждый элемент.

Следующий пример показывает это:

<?php

// укажем имя файла
$file = '/usr/local/stuff/that/should/be/elsewhere/recipes/omelette.txt'
or die('Не могу прочитать файл!'); 
// прочитаем файл в массив
$data = file($file) or die('Не могу прочитать файл!');
// проходим циклом по массиву и печатаем элементы
foreach ($data as $line) {
echo $line;
} ?>

В этом примере функция file() открывает файл, читает его в массив, а затем закрывает файл - всё в одном, простое и элегантное па-деде :). Теперь каждый элемент массива соответствует строке в файле и содержимое файла легко напечатать - просто обработать массив циклом foreach().

Вам не надо пихать данные в массив? Попробуйте функцию file_get_contents(), новую со времён PHP 4.3.0 и PHP 5.0, которая читает весь файл в одну строку:

<?php

// укажем имя файла
$file = '/usr/local/stuff/that/should/be/elsewhere/recipes/omelette.txt' ; 
// прочитаем файл в строку
$data = file_get_contents($file) or die('не могу прочитать файл!');
// напечатаем содержимое
echo $data; ?>

Кто шутит? Я шучу?!?! Я всегда использую эту одностроковую функцию вместо трёхстрочной последовательности fopen(), fread() и fclose().

Лень побеждает всё!

Когда лень - добродетель

Также PHP представляет две полезные функции: include() и require(). Они могут использоваться для включения внешних файлов в свой скрипт; это бывает полезно, например, если у вас модульная программа, которая собирает код из файлов в разных папках.

Лучший способ понять применение функций include() и require() - это пример. Предположим, что у вас есть стандартный веб-сайт с меню на каждой странице, а также стандартный текст об авторских правах. Вместо копирования и вставки верхней и нижней частей страницы в каждый файл, гуру PHP просто создают отдельные файлы верхей и нижней части, а затем импортируют их вверху и внизу каждого скрипта. Это также позволяет облегчить изменение дизайна сайта: вместо изменения тысяч файлов вручную, вы просто изменяете два и эти изменения мгновенно отразятся на всём сайте.

Давайте посмотри пример из жизни. Создадим файл шапки, header.php:

<html> 
<head> 
<title>

<?php
echo $page['title'];
?>

</title> 
</head> 
<body> 
<!-- top menu bar --> 
<table width="90%" border="0" cellspacing="5" cellpadding="5"> 
<tr> 
<td><a href="#">Главная</a></td> 
<td><a href="#">Карта сайта</a></td> 
<td><a href="#">Поиск</a></td> 
<td><a href="#">Помощь</a></td> 
</tr> 
</table> 
<!-- конец шапки -->

Далее, создадим файл низа с сообщением об авторских правах, footer.php:

<!-- низ страницы -->
<br />
<center>Использование данных на этом сайта описано в
<a href="tac.html">авторском соглашении</a>. Владелец данных -
ООО "Большая компания", 1995-<?php echo date("Y", mktime()); ?></center> 
</body> 
</html>

И, наконец, создадим скрипт для вывода основного текста на сайте, а затем включим заголовок и низ страницы в нужных местах:

<?php

// создадим массив для установки переменной заголовка страницы
$page = array(); 
$page['title'] = 'Каталог продукции'; 
/* при импорте файла эта переменная будет доступна в файле */ 

// включим заголовок страницы
include('header.php'); 

?> 

<!-- здесь основной текст страницы --> 

<?php 

// включим низ страницы 
include('footer.php');

?>

Теперь, когда вы запустите последний скрипт, PHP автоматически прочитает файлы заголовка и низа, включит их в содержимое основную страницу и покажет вам полную страницу. Просто, не так-ли?

Заметьте, что вы можете писать код PHP даже внутри импортируемых файлов. Когда такой файл читается, парсер ищет теги <?php...?> и автоматически исполняет код внутри них. (Если вы знакомы с JavaScript, вы можете использовать данную возможность аналогично обработчику событий JavaScript onLoad() ).

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

Коротенька я заметка о разнице между функциями include() и require(): require() возвращает критическую ошибку в случае если указнный файл не найден и останавливает обработку скрипта, тогда как include() возвращает предупреждение, но позволяет скрипту выполняться далее.

Письмо мамочке

После все что вы прочитали, вы (надеюсь) поняли, что чтение файла - не мозголомное занятие. Так-что давайте рассмотрим кое-что потруднее - запись в файл.

Действия при записи в файл почти такие-же, как и при его чтении: открыть файл, получить его дескриптор, использовать дескриптор при записи в файл данных, закрыть файл. Есть два отличия: превое - вы должны открыть файл функцией fopen() в режиме чтения ('w') и второе - вместо использования функции fread() используйте функцию записи fwrite(). Посмотрим на пример:

<?php

// укажем файл для записи
$file = '/tmp/dump.txt'; 
// откроем файл
$fh = fopen($file, 'w') or die('Не могу открыть файл!'); 
// запишем в файл 
fwrite($fh, "Мама, смотри, я пишу в файл!")
or die('Не могу писать в файл!'); 
// close file 
fclose($fh);

?>

После запуска этот скрипт создать файл dump.txt в папке /tmp и запишет в него строку текста.

Функции fopen(), fwrite() и fread() двоично-безопасны, что означает что вы можете применять их к бинарным (двоичным) файлам без опаски повредить данные. Прочитайте больше об особенностях безопасной работы с бинарными файлами на различных платформах на странице http://www.php.net/manual/en/function.fopen.php

Если я вас напугал, показав как одной строкой прочитать весь файл, то позвольте попугать ещё функцией file_put_contents(), новой со времён PHP 5.0, которая берёт одну строку и записывает её в файл. Вызывается одной строкой кода:

<?php

// укажем файл для записи
$filename = '/tmp/dump.txt'; 

// запишем в файл
file_put_contents($filename, "Мама, смотри, я пишу в файл!" or die('Не могу писать в файл!'); ?>

Не забывайте, что папка, в которуй вы собираетесь создать файл, должна существовать. Забыть проверить существование папки - одна из распространённых ошибок.

Знание - сила!

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

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

<html> 
<head> 
</head> 
<body> 

<?php

// если форма ещё не была отправлена,
// то покажем поле ввода
if (!isset($_POST['file'])) { 
?>

    <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post"> 
    Введите путь к файлу <input type="text" name="file"> 
    </form> 

<?php 
} 
// иначе обрабатываем ввод
else { 
    // если файл существует
    // покажет соответствующее сообщение
    if (file_exists($_POST['file'])) { 
        echo 'Файл существует!'; 
        } 
    else { 
        echo 'Файл не существует!'; 
    } 
}

?>


<body>
</html>

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

  • is_dir() - возвращает булево значение, показывающее, является-ли указанный файл папкой;
  • is_file() - возвращает булево, показывающее, является-ли указанный файл обычным файлом;
  • is_link() - возвращает булево, показывающее, является-ли указанный файл символической ссылкой;
  • is_executable() - возвращает булево, показывающее, является-ли указанный файл исполняемым;
  • is_readable()- возвращает булево, показывающее, можно-ли читать из указанного файла;
  • is_writable()- возвращает булево, показывающее, можно-ли писать в указанный файл;
  • filesize() - возвращает размер файла;
  • filemtime() - возвращает дату и время последнего изменения;
  • filamtime() - возвращает время последнего доступа;
  • fileowner() - возвращает владельца файла;
  • filegroup() - возвращает группу владельца файла;
  • fileperms() - возвращает разрешения на файл;
  • filetype() - возвращает тип файла.

Скрипт запрашивает имя файла и использует функции, перечисленные выше, для вывода информации о нём:

<html> 
<head> 
</head> 
<body> 

<?php

// если форма ещё не была отправлена,
// то покажем поле ввода
if (!isset($_POST['file'])) { 
?>

    <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post"> 
    Введите путь к файлу <input type="text" name="file"> 
    </form> 

<?php 

// иначе обрабатываем ввод
else {
echo 'Имя файоа: <b>'.$_POST['file'] .'</b><br />';
/* проверим, существует-ли файл и выведем соответствующее сообщение */
if (file_exists($_POST['file'])) {
// выведем размер файла
echo 'Размер файла: '.filesize($_POST['file']).' bytes<br />';
// напечатаем владельца файла
echo 'Владелец файла: '.fileowner($_POST['file']).'<br />';
// напечатаем группу владельца файла
echo 'Группа владельца файла: '.filegroup($_POST['file']).'<br />';
// выведем права доступа на файл
echo 'Права доступа: '.fileperms($_POST['file']).'<br />';
// напечатаем тип файла
echo 'Тип файла: '.filetype($_POST['file']).'<br />';
// напечатаем время последнего доступа
echo 'Время последнего доступа: '.date('Y-m-d', fileatime($_POST['file'])).'<br />';
// напечатаем дату последнего изменения
echo 'Последнее время изменения: '.date('Y-m-d', filemtime($_POST['file'])).'<br />';
// это папка?
if (is_dir($_POST['file'])) {
echo 'Файл является папкой <br />';
}
// это файл?
if (is_file($_POST['file'])) {
echo 'Это обычный файл <br />';
}
// это ссылка?
if (is_link($_POST['file'])) {
echo 'Файл является символьной ссылкой <br />';
}
// он исполняемый?
if (is_executable($_POST['file'])) {
echo 'Файл исполняемый <br />';
}
// его можно читать?
if (is_readable($_POST['file'])) {
echo 'Файл можно читать <br />';
}
// в него можно записывать?
if (is_writable($_POST['file'])) {
echo 'В файл можно записывать <br />';
}
}
else {
echo 'Файла не существует! <br />';
}
} ?> <body> </html>

То, что вы увидите после запуска, может выглядет вот так:

Имя файла: /usr/local/apache/logs/error_log
Размер файла: 53898 bytes
Владелец файла: 0
Группа владельца файла: 0
Права доступа: 33188
Тип файла: file
Время последнего доступа: 2004-05-26
Последнее время изменения: 2004-06-20
Это обычный файл
Файл можно читать

Разбиваем яйца

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

Вернёмся к моему рецепту испанского омлета. Допустим, я чувствую себя щедрым и решил узнать что думают люди о моих кулинарных навыках. У меня есть куча рецептов, которыми я хотел-бы поделиться с людми, и они выглядят вот так:

ИСПАНСКИЙ ОМЛЕТ
ИНГРЕДИЕНТЫ:
- один нарезанный лук;
- один нарезанный помидор;
- нарезанная половинка перца;
- четыре разбитых  яйца;
- соль и перец по вкусу.
СПОСОБ ПРИГОТОВЛЕНИЯ:
1. Поджарьте на сковородке лук.
2. Вылейте разбитые яйца на лук и слегка поджарьте
3. Добавьте помидоры, зелёный перец, соль и перец по вкусу
4. Подавайте с хлебом или тостом

Мне надо быстро сконвертировать все рецепты в HTML для того, чтобы они выглядели красиво на моём сайте. Мы уже знаем что я ленив, так-что писать их в HTML меня парит. Для этого у меня есть PHP:

<html> 
<head> 
</head> 
<body> 

<?php
// прочитаем рецепт в массив
$data = file('/usr/local/stuff/that/should/be/elsewhere/omelette.txt') or die('Не могу прочитать файл!');
/* первая строка содержим название - читаем его в переменную */
$title = $data[0];
// удалим первую строку из массива
array_shift($data); ?> <h2><?php echo $title; ?></h2> <?php /* пройдём по массиву и напечатаем его */
foreach ($data as $line) {
echo nl2br($line);
} ?> <body> </html>

Я использовал функцию file() для чтения рецепта в массив, затем назначил переменной (названию) первой строке. Это название печатается наверху страницы. Поскольку остальные данные выводятся на печать как есть, я просто печатаю строки на экран одна за другой. Переводы строк автоматически конвертируются в теги <br /> крутой функцией nl2br(). Конечный результат - HTML-версия моего рецепта, которым может восхищаться весь мир. Посмотрите:

<html> 
<head> 
</head> 
<body>
  <h2>ИСПАНСКИЙ ОМЛЕТ
    </h2>
    ИНГРЕДИЕНТЫ:<br />
    - один нарезанный лук;<br />
    - один нарезанный помидор;<br />
    - нарезанная половинка перца;<br />
    - четыре разбитых  яйца;<br />
    - соль и перец по вкусу.<br />
    СПОСОБ ПРИГОТОВЛЕНИЯ:<br />
    1. Поджарьте на сковородке лук<br />
    2. Вылейте разбитые яйца на лук и слегка поджарьте<br />
    3. Добавьте помидоры, зелёный перец, соль и перец по вкусу<br />
    4. Подавайте с хлебом или тостом<br />
  <body>
</html>

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

Оригинал перевода находится на сайте http://www.figli-migli.org.ua/books/847-php101-5


В избранное