Загрузка файлов
Загрузка файла — это форма с полем выбора файла и код, который переносит присланный файл в постоянную папку. В CakePHP загруженный файл приходит в действие объектом с методами для имени, размера и перемещения.
Подготовка
Создайте вручную папку webroot/uploads — всё, что лежит в webroot, доступно по адресу сайта. Имя файла будем хранить в столбце cover таблицы статей:
bin/cake bake migration AddCoverToArticles cover:string
bin/cake migrations migrateФорма
<div>
<?= $this->Form->create($article, ['type' => 'file']) ?>
<?= $this->Form->control('title') ?>
<?= $this->Form->control('cover_file', ['type' => 'file', 'label' => 'Обложка']) ?>
<?= $this->Form->button('Сохранить') ?>
<?= $this->Form->end() ?>
</div>Настройка 'type' => 'file' в create() обязательна: без неё браузер отправит только имя файла. Поле названо cover_file, а не cover, чтобы объект файла не попал в запись вместо строки.
Получение файла
// src/Controller/ArticlesController.php
$file = $this->request->getUploadedFile('cover_file');
if ($file !== null && $file->getError() === UPLOAD_ERR_OK) {
$name = bin2hex(random_bytes(16)) . '.jpg';
$file->moveTo(WWW_ROOT . 'uploads' . DS . $name);
$article->cover = $name;
}Этот код ставят в действие add() после patchEntity() и перед save(). getUploadedFile() возвращает объект файла, moveTo() переносит его в webroot/uploads, а имя записывается в столбец cover. Константа WWW_ROOT — путь к папке webroot.
Методы файла
| Метод | Что возвращает |
|---|---|
getClientFilename() | Имя файла на компьютере посетителя |
getSize() | Размер в байтах |
getClientMediaType() | Тип, который сообщил браузер |
getError() | Код ошибки, UPLOAD_ERR_OK при успехе |
moveTo($path) | Переносит файл |
Проверка
Прежде чем сохранять файл, проверяют расширение и размер:
$extension = strtolower(pathinfo($file->getClientFilename(), PATHINFO_EXTENSION));
if (!in_array($extension, ['jpg', 'jpeg', 'png'], true)) {
$this->Flash->error('Загрузите картинку в формате JPG или PNG.');
} elseif ($file->getSize() > 2 * 1024 * 1024) {
$this->Flash->error('Файл больше 2 МБ.');
} else {
$name = bin2hex(random_bytes(16)) . '.' . $extension;
$file->moveTo(WWW_ROOT . 'uploads' . DS . $name);
$article->cover = $name;
}Файл с другим расширением или слишком большой не сохраняется, а посетитель видит сообщение.
Вывод картинки
<div>
<?php if ($article->cover): ?>
<?= $this->Html->image('/uploads/' . $article->cover, ['alt' => $article->title]) ?>
<?php endif; ?>
</div>Путь, начинающийся с косой черты, помощник Html отсчитывает от папки webroot. На странице статьи появится обложка.
Частая ошибка
Сохранять файл под именем, которое прислал посетитель, опасно: имя может содержать ../ или расширение .php, и на сервере окажется исполняемый чужой код. Всегда создавайте имя сами — случайную строку — и берите только проверенное расширение из списка разрешённых.