Как работать с файлами (чтение, запись, загрузка)?php-42

Работа с файлами — фундаментальная задача в PHP, которая включает несколько аспектов. Рассмотрим основные операции и лучшие практики.

1. Базовые операции с файлами

Открытие и закрытие файлов

$file = fopen('example.txt', 'r') or die("Не удалось открыть файл");
// операции с файлом...
fclose($file);

Режимы открытия:

  • r - чтение (указатель в начале)
  • r+ - чтение и запись
  • w - запись (создает/очищает файл)
  • a - добавление (указатель в конце)
  • x - эксклюзивное создание (ошибка если файл существует)

Чтение файлов

Построчное чтение:

while(!feof($file)) {
    echo fgets($file) . "<br>";
}

Чтение всего файла:

$content = file_get_contents('example.txt');

Чтение в массив:

$lines = file('example.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);

Запись в файлы

Базовая запись:

fwrite($file, "Новая строка\n");

Простая запись:

file_put_contents('example.txt', $content, FILE_APPEND | LOCK_EX);

Флаги для записи:

  • FILE_APPEND - добавление в конец
  • LOCK_EX - эксклюзивная блокировка

2. Загрузка файлов на сервер

HTML форма

<form action="upload.php" method="post" enctype="multipart/form-data">
    <input type="file" name="userfile">
    <input type="submit" value="Загрузить">
</form>

Обработка загрузки

$uploadDir = __DIR__ . '/uploads/';

if ($_FILES['userfile']['error'] === UPLOAD_ERR_OK) {
    $tmpName = $_FILES['userfile']['tmp_name'];
    $name = basename($_FILES['userfile']['name']);
    $target = $uploadDir . $name;

    // Проверка типа файла
    $finfo = new finfo(FILEINFO_MIME_TYPE);
    if (in_array($finfo->file($tmpName), ['image/jpeg', 'image/png'])) {
        move_uploaded_file($tmpName, $target);
        echo "Файл загружен";
    } else {
        echo "Недопустимый тип файла";
    }
} else {
    echo "Ошибка загрузки: " . $_FILES['userfile']['error'];
}

Безопасность при загрузке

  1. Проверяйте $_FILES['file']['error']
  2. Ограничивайте типы файлов
  3. Генерируйте уникальные имена
  4. Храните вне корня веб-сервера
  5. Ограничивайте размер файлов (php.ini: upload_max_filesize)

3. Работа с директориями

Создание директории:

if (!file_exists('new_dir')) {
    mkdir('new_dir', 0755, true); // recursive create
}

Чтение директории:

$files = scandir('path/to/dir');
$files = array_diff($files, ['.', '..']);

Рекурсивное чтение:

$iterator = new RecursiveDirectoryIterator('path');
foreach (new RecursiveIteratorIterator($iterator) as $file) {
    echo $file->getPathname() . "\n";
}

4. Потоки и контексты

Пример с HTTP:

$context = stream_context_create([
    'http' => [
        'method' => 'GET',
        'header' => "Accept-language: en\r\n"
    ]
]);
$content = file_get_contents('http://example.com', false, $context);

Запись с контекстом:

$context = stream_context_create([
    'ftp' => [
        'overwrite' => true
    ]
]);
file_put_contents('ftp://user:pass@example.com/file.txt', $data, 0, $context);

5. Обработка ошибок и лучшие практики

  1. Всегда проверяйте результат операций:

    if (file_put_contents('file.txt', $data) === false) {
        throw new Exception("Ошибка записи");
    }
    
  2. Используйте блокировку для конкурентного доступа:

    $fp = fopen('counter.txt', 'r+');
    if (flock($fp, LOCK_EX)) {
        $count = (int)fread($fp, 100);
        ftruncate($fp, 0);
        fwrite($fp, $count + 1);
        flock($fp, LOCK_UN);
    }
    fclose($fp);
    
  3. Для больших файлов используйте потоковое чтение:

    $source = fopen('large.txt', 'r');
    $dest = fopen('copy.txt', 'w');
    stream_copy_to_stream($source, $dest);
    fclose($source);
    fclose($dest);
    

Резюмируем:

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