Cake PHP: Объект класса Laminas \ Diactoros \ UploadedFile не может быть преобразован в строку во время загрузки файла - PullRequest
0 голосов
/ 19 марта 2020

Я пытаюсь загрузить файл в торт php версия 4.

Я слежу за этим Документы

Я пытался в контроллере

if ($this->request->is('post')) {

            $image = $this->request->getData('image');
            $fileName = $image->getClientFilename();

            $targetPath = WWW_ROOT.'img'.DS.$fileName;

            $image->moveTo($targetPath);

            $user = $this->Users->patchEntity($user, $this->request->getData());   //line 58

            $user->image = $fileName;

            $this->Users->save($user);
}

Загрузка изображений работает нормально, имя также сохраняется в базе данных. Но когда происходит ошибка проверки, я получаю

Warning (4096): Object of class Laminas\Diactoros\UploadedFile could not be converted to string [CORE\src\Database\Type\StringType.php, line 97]

logs

Cake\Database\Type\StringType::marshal() - CORE\src\Database\Type\StringType.php, line 97
Cake\ORM\Marshaller::Cake\ORM\{closure}() - CORE\src\ORM\Marshaller.php, line 78
Cake\ORM\Marshaller::merge() - CORE\src\ORM\Marshaller.php, line 558
Cake\ORM\Table::patchEntity() - CORE\src\ORM\Table.php, line 2761
App\Controller\UsersController::add() - APP/Controller\UsersController.php, line 58
Cake\Controller\Controller::invokeAction() - CORE\src\Controller\Controller.php, line 524
Cake\Controller\ControllerFactory::invoke() - CORE\src\Controller\ControllerFactory.php, line 79
Cake\Http\BaseApplication::handle() - CORE\src\Http\BaseApplication.php, line 229
Cake\Http\Runner::handle() - CORE\src\Http\Runner.php, line 77
Cake\Http\Runner::handle() - CORE\src\Http\Runner.php, line 77
Cake\Http\Middleware\CsrfProtectionMiddleware::process() - CORE\src\Http\Middleware\CsrfProtectionMiddleware.php, line 132
Cake\Http\Runner::handle() - CORE\src\Http\Runner.php, line 73
Cake\Http\Runner::run() - CORE\src\Http\Runner.php, line 58
Cake\Routing\Middleware\RoutingMiddleware::process() - CORE\src\Routing\Middleware\RoutingMiddleware.php, line 162
Cake\Http\Runner::handle() - CORE\src\Http\Runner.php, line 73
Cake\Routing\Middleware\AssetMiddleware::process() - CORE\src\Routing\Middleware\AssetMiddleware.php, line 68

1 Ответ

3 голосов
/ 19 марта 2020

Прежде всего, ваш пример кода слепо доверяет клиенту, он принимает любой файл и позволяет выбирать произвольные целевые местоположения, передавая путь в качестве имени файла! Никогда не используйте данные клиента без их проверки / очистки, если доверять дате файла, предоставленной клиентом, это может привести к всевозможным уязвимостям !!!

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

Так, например, переименуйте элемент управления формы с image на image_file (в базе данных такого столбца не должно быть), добавьте правильные правила проверки для image_file, что-то вроде этого, чтобы убедиться, что выгрузка действительна, ie проверьте тип, размер, имя и т. д. c:

$validator
    ->notEmptyFile('image_file')
    ->uploadedFile('image_file', [
        'types' => ['image/png'], // only PNG image files
        'minSize' => 1024, // Min 1 KB
        'maxSize' => 1024 * 1024 // Max 1 MB
    ])
    ->add('image_file', 'minImageSize', [
        'rule' => ['imageSize', [
            // Min 10x10 pixel
            'width' => [Validation::COMPARE_GREATER_OR_EQUAL, 10],
            'height' => [Validation::COMPARE_GREATER_OR_EQUAL, 10],
        ]]
    ])
    ->add('image_file', 'maxImageSize', [
        'rule' => ['imageSize', [
            // Max 100x100 pixel
            'width' => [Validation::COMPARE_LESS_OR_EQUAL, 100],
            'height' => [Validation::COMPARE_LESS_OR_EQUAL, 100],
        ]]
    ])
    ->add('image_file', 'filename', [
        'rule' => function (UploadedFileInterface $file) {
            // filename must not be a path
            $filename = $file->getClientFilename();
            if (strcmp(basename($filename), $filename) === 0) {
                return true;
            }

            return false;
        }
    ])
    ->add('image_file', 'extension', [
        'rule' => ['extension', ['png']] // .png file extension only
    ]);

А затем выполните загрузку после исправления, ie после проверки и только переместите файл, если проверка прошла успешно!

$user = $this->Users->patchEntity($user, $this->request->getData());
if (!$user->getErrors()) {
    // never trust anything in `$image` if you haven't properly validated it!!!
    $image = $this->request->getData('image_file');
    $fileName = $image->getClientFilename();

    $image->moveTo(WWW_ROOT . 'img' . DS . $fileName;);

    $user->image = $fileName;
}

if ($this->Users->save($user)) {
    // success
} else {
    // failure
}

Как только вы поймете, как все работает, вам, вероятно, следует рассмотреть возможность перемещения логики обработки выгрузки c в свой класс таблицы или в поведение ( beforeSave() Событие / обратный вызов очень популярны для выполнения лога загрузки c) или какой-либо службы.

Вы также можете посмотреть, как существующие плагины обрабатывают до объявления, см., например, https://github.com/FriendsOfCake/awesome-cakephp#user -content-files

...