PHP Filesystem
В этой статье рассматриваются функции файловой системы PHP для создания, чтения, записи и удаления файлов и директорий.
Введение
Функции файловой системы PHP позволяют скриптам читать данные с диска сервера и записывать их на него: создавать, читать, обновлять и удалять файлы, а также управлять директориями. Они являются основой всего, что должно хранить данные вне базы данных — лог-файлы, сгенерированные отчёты, загружаемые пользователями файлы, конфигурация, кэши и задачи импорта/экспорта.
В этой статье объясняются два основных способа работы с файлами (семейство функций на основе дескриптора, построенное вокруг fopen(), и одноразовые вспомогательные функции, например file_get_contents()), приводятся выполняемые примеры для каждого из них, а также указываются подводные камни, связанные с правами доступа и обработкой ошибок, с которыми люди сталкиваются в продакшене.
Два способа работы с файлами
PHP предоставляет два стиля, и выбор правильного позволяет сохранить код простым:
- Одноразовые вспомогательные функции —
file_get_contents()иfile_put_contents()читают или записывают весь файл в одном вызове. Используйте их, когда файл легко умещается в памяти (конфигурационные файлы, небольшие JSON/CSV, шаблоны). Это самый короткий и читаемый вариант. - Функции на основе дескриптора —
fopen(),fread(),fwrite()иfclose()предоставляют дескриптор файла (ресурс), который читается или записывается постепенно. Используйте их для больших файлов, которые нужно считывать построчно без загрузки всего содержимого в память, или когда файл нужно держать открытым на протяжении многих операций.
Операции с файлами
PHP предоставляет несколько функций для работы с файлами. Эти функции позволяют создавать, открывать, читать, записывать и удалять файлы. Наиболее часто используемые файловые функции:
fopen(): Открывает файл и возвращает дескриптор. Принимает два аргумента: имя файла и режим открытия (см. таблицу ниже).fclose(): Закрывает открытый дескриптор файла и сбрасывает буферизованные записи на диск.fwrite(): Записывает строку в открытый файл, возвращая количество записанных байтов.fread(): Читает заданное количество байтов из открытого файла.feof(): Возвращаетtrue, когда достигнут конец файла — полезно в качестве условия цикла при чтении.unlink(): Удаляет файл.filesize(): Возвращает размер файла в байтах.file_exists(): Проверяет, существует ли файл или директория, перед тем как выполнять действия с ними.
Для простых задач чтения/записи предпочтительнее использовать file_get_contents() и file_put_contents(), которые выполняют открытие, чтение/запись и закрытие в одном вызове.
Режимы файлов для fopen()
Второй аргумент fopen() определяет, что можно делать с дескриптором и что происходит с существующим содержимым. Наиболее распространённые режимы:
| Режим | Описание |
|---|---|
"r" | Только чтение. Указатель начинается с начала. Завершается ошибкой, если файл не существует. |
"w" | Только запись. Усекает файл до нулевой длины (или создаёт его). |
"a" | Только запись, дозапись. Создаёт файл, если он отсутствует; существующее содержимое сохраняется. |
"x" | Только запись, но завершается ошибкой, если файл уже существует — безопасный режим «создать новый». |
"r+" | Чтение и запись. Указатель в начале; файл должен существовать. |
Внимание:
"w"удаляет существующее содержимое в момент открытия файла. Если нужно добавлять записи в лог вместо перезаписи, используйте"a".
Операции с директориями
PHP также предоставляет функции для работы с директориями. Эти функции позволяют создавать, удалять и управлять директориями. Наиболее часто используемые функции для работы с директориями:
mkdir(): Используется для создания директории.rmdir(): Используется для удаления директории.opendir(): Используется для открытия директории.readdir(): Используется для чтения содержимого директории.closedir(): Используется для закрытия открытой директории.
Примеры
Рассмотрим, как эти функции используются на практике.
Создание и запись файла
Чтобы создать файл и записать в него данные, откройте его в режиме записи с помощью fopen(), запишите с помощью fwrite(), затем обязательно вызовите fclose():
<?php
$file = fopen("example.txt", "w");
if ($file === false) {
exit("Error opening file");
}
fwrite($file, "Hello, world!");
fclose($file);Это создаёт example.txt в той же директории, что и скрипт (заменяя его, если он уже существует), записывает Hello, world! и закрывает дескриптор.
Та же задача с одноразовой вспомогательной функцией — это одна строка, и это предпочтительный стиль для небольших файлов:
<?php
file_put_contents("example.txt", "Hello, world!");Чтение файла
Чтобы прочитать файл с помощью дескриптора, откройте его в режиме чтения и используйте fread(). Передача filesize() сообщает fread(), сколько байтов нужно прочитать:
<?php
$file = fopen("example.txt", "r");
if ($file === false) {
exit("Error opening file");
}
echo fread($file, filesize("example.txt"));
fclose($file);Для небольших файлов file_get_contents() делает то же самое в одном вызове:
<?php
echo file_get_contents("example.txt");Чтение файла построчно
Для больших файлов читайте построчно с помощью fgets(), чтобы никогда не хранить весь файл в памяти. Цикл выполняется до тех пор, пока feof() не сообщит о конце файла:
<?php
$file = fopen("example.txt", "r");
if ($file === false) {
exit("Error opening file");
}
while (!feof($file)) {
$line = fgets($file);
echo $line;
}
fclose($file);Дозапись в файл
Чтобы добавить данные в файл без удаления существующего содержимого, откройте его в режиме дозаписи ("a"). Это правильный режим для логов:
<?php
$file = fopen("log.txt", "a");
fwrite($file, "New log entry\n");
fclose($file);Создание директории
Чтобы создать директорию, используйте функцию mkdir():
<?php
mkdir("example_directory");Это создаёт директорию с именем example_directory рядом со скриптом. Чтобы создать вложенные директории в одном вызове, передайте режим и флаг рекурсии:
<?php
mkdir("parent/child/grandchild", 0755, true);Примечание:
mkdir()требует разрешения на запись в родительской директории. Третий аргумент (true) включает рекурсивное создание промежуточных директорий.
Удаление файла
Чтобы удалить файл, используйте функцию unlink():
<?php
if (file_exists("example.txt")) {
unlink("example.txt");
}Предварительная проверка с помощью file_exists() позволяет избежать предупреждения, если файл уже удалён.
Лучшие практики
- Всегда закрывайте дескрипторы. Каждый
fopen()должен быть дополненfclose(), чтобы буферизованные записи были сброшены и ресурс освобождён. - Проверяйте возвращаемые значения.
fopen(),mkdir()иunlink()возвращаютfalseпри неудаче — защититесь от этого вместо того, чтобы предполагать успех. - Следите за правами доступа. Большинство ошибок «permission denied» возникают из-за того, что пользователь веб-сервера не является владельцем целевой директории, а не из-за кода.
- Выбирайте правильный инструмент. Используйте
file_get_contents()/file_put_contents()для работы с целым файлом; семействоfopen()/fread()— только когда нужна потоковая обработка.
Заключение
Функции файловой системы обеспечивают основу для управления файлами и директориями в PHP. Понимая разницу между одноразовыми вспомогательными функциями и потоковой обработкой на основе дескриптора, выбирая правильный режим fopen() и корректно закрывая дескрипторы, вы сможете создавать надёжные приложения, которые надёжно хранят данные и конфигурацию. Для более глубокого изучения обратитесь к разделам PHP File Handling, PHP File Open/Read и работа с директориями.