Работа с файлами в PHP — это фундаментальный навык, который превращает статические страницы в динамические приложения. От простого чтения логов до создания сложных систем загрузки документов — файловые операции лежат в основе большинства веб-проектов. В этом руководстве мы разберем все аспекты: от базовых функций до продвинутых техник безопасности.
Основы файловых операций в PHP
PHP предлагает богатый набор функций для работы с файловой системой. В отличие от многих других языков, здесь есть как простые "однострочные" решения, так и низкоуровневые методы для сложных сценариев.
Чтение файлов: несколько подходов
Самый простой способ прочитать файл — использовать file_get_contents():
$content = file_get_contents('data.txt');
echo $content;
Функция file_get_contents() может читать не только локальные файлы, но и URL, что делает её исключительно полезной для работы с API.
Для построчного чтения больших файлов лучше подходит fopen() в комбинации с fgets():
$handle = fopen('large_log.txt', 'r');
while (!feof($handle)) {
$line = fgets($handle);
// Обработка каждой строки
}
fclose($handle);
Запись и добавление данных
Запись в файл осуществляется через file_put_contents():
file_put_contents('log.txt', 'Новая запись', FILE_APPEND);
Флаг FILE_APPEND гарантирует, что данные добавятся в конец файла, а не перезапишут его. Для более контролируемой записи используйте fwrite():
$handle = fopen('data.csv', 'a');
fwrite($handle, "новые,данные,здесь\n");
fclose($handle);
Безопасность — прежде всего
Работа с файлами — одна из самых уязвимых точек PHP-приложений. Неправильная обработка путей или загрузок может привести к катастрофическим последствиям.
Валидация путей
Никогда не доверяйте пользовательскому вводу при формировании путей к файлам:
// ОПАСНО!
$user_file = $_GET['file'];
readfile('/uploads/' . $user_file);
Вместо этого используйте белые списки или строгую валидацию:
$allowed_files = ['report.pdf', 'data.json'];
if (in_array($_GET['file'], $allowed_files)) {
$path = '/uploads/' . basename($_GET['file']);
// Только теперь работаем с файлом
}
Функция basename() удаляет все компоненты пути, оставляя только имя файла, что предотвращает атаки через относительные пути (../../etc/passwd).
Безопасная загрузка файлов
При реализации загрузки файлов:
- Проверяйте MIME-тип через
finfo_file() - Ограничивайте максимальный размер
- Переименовывайте файлы (избегайте оригинальных имен)
- Храните загруженные файлы вне корневой директории веб-сервера
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $_FILES['file']['tmp_name']);
$allowed_types = ['image/jpeg', 'image/png'];
if (in_array($mime, $allowed_types)) {
// Безопасная обработка
}
Продвинутые техники
Работа с временными файлами
PHP автоматически удаляет временные файлы, но иногда нужно создать свой:
$temp_file = tmpfile();
fwrite($temp_file, "Временные данные");
// Файл автоматически удалится при закрытии
Блокировка файлов
Для предотвращения конкурентного доступа используйте блокировки:
$fp = fopen('counter.txt', 'r+');
if (flock($fp, LOCK_EX)) { // Эксклюзивная блокировка
$count = fread($fp, 10);
$count++;
ftruncate($fp, 0);
fwrite($fp, $count);
flock($fp, LOCK_UN); // Снятие блокировки
}
fclose($fp);
Директории и итераторы
Для работы с директориями используйте DirectoryIterator:
$dir = new DirectoryIterator('/uploads');
foreach ($dir as $fileinfo) {
if (!$fileinfo->isDot()) {
echo $fileinfo->getFilename() . "\n";
}
}
Оптимизация производительности
При работе с большими файлами:
- Используйте буферизацию для операций записи
- Читайте файлы частями, а не целиком
- Кэшируйте часто читаемые данные
- Рассмотрите использование потоков (streams) для обработки
FAQ: Часто задаваемые вопросы
Как проверить существование файла?
Используйте file_exists(), но помните — эта функция проверяет и файлы, и директории. Для точной проверки файла используйте is_file().
Чем отличается include от чтения файла?
include и require выполняют PHP-код из файла, тогда как функции чтения возвращают содержимое как строку. Никогда не используйте include для пользовательских файлов!
Как получить размер файла?
Функция filesize() возвращает размер в байтах. Для больших файлов используйте stat() для получения дополнительной информации.
Можно ли работать с Excel/PDF через файловые функции?
Да, можно читать и записывать бинарные данные, но для структурированной работы лучше использовать специализированные библиотеки (PhpSpreadsheet, TCPDF).
Как безопасно удалить файл?
Перед удалением проверьте права доступа и используйте unlink(). Для дополнительной безопасности можно перезаписать файл нулями перед удалением.