CakePHP:文件上传时,类Laminas\Diactoros\UploadedFile的对象无法转换为字符串

nue99wik  于 2022-11-11  发布在  PHP
关注(0)|答案(2)|浏览(119)

我正在尝试在cakephp版本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]

原木

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
enxuqcxy

enxuqcxy1#

首先,您的代码示例盲目地信任客户端,它接受任何文件,并允许通过传递路径作为文件名来选择任意目标位置!切勿在未验证/清理客户端数据的情况下使用客户端数据,信任客户端提供的文件日期可能会导致各种漏洞!!!
也就是说,通常你要么使用一个单独的字段来上传文件,要么使用一个自定义的数据库类型,当数据被编组时,它不会转换数据,这样你就可以在之后手动转换它。目前你似乎使用的上传字段应该在数据库中保存一个字符串,因此编组器会试图将输入转换为字符串,这当然会失败。
例如,将表单控件从image重命名为image_file(数据库中不应存在这样的列),为image_file添加适当的验证规则,以确保上载有效,即检查类型、大小、名称等:

$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', 'minSize', [
        'rule' => ['imageSize', [
            // Min 10x10 pixel
            'width' => [Validation::COMPARE_GREATER_OR_EQUAL, 10],
            'height' => [Validation::COMPARE_GREATER_OR_EQUAL, 10],
        ]]
    ])
    ->add('image_file', 'maxSize', [
        '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
    ]);

然后处理上传 * 后 * 修补,即验证后发生,只有移动文件,如果验证成功!

$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();
    // if you want to take it a step further, drop the user supplied filename
    // $fileName = \Cake\Utility\Security::hash($image->getClientFilename(), 'sha1');
    // and re-encode the image to remove possible dangerous payloads, meta data, etc
    // reEncodeImage($image->getStream());

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

    $user->image = $fileName;
}

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

一旦掌握了工作原理,就应该考虑将上载处理逻辑移到表类或行为(beforeSave()事件/回调在执行上载逻辑方面非常流行)或某种服务中。
您可能还想了解一下现有的插件是如何处理上传的,例如,请参见https:github.com/FriendsOfCake/awesome-cakephp#user-content-files

h79rfbju

h79rfbju2#

// add
public function add()
{
    $info = $this->Infos->newEmptyEntity();           //debug($info);
    $this->Authorization->authorize($info);           

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

        $data       = $this->request->getData();                 //debug($data);
        $dimage     = $this->request->getData('image');                 

        $name       = $dimage->getClientFilename();              //debug($name);
        $type       = $dimage->getClientMediaType();             //debug($type);           
        $size       = $dimage->getSize();                        //debug($size);
        $tmpName    = $dimage->getStream()->getMetadata('uri');  //debug($tmpName);
        $error      = $dimage->getError();                       //debug($error); 

        $targetPath = WWW_ROOT . 'img' . DS . 'infos' . DS . $name;  //debug($targetPath); 

        if ($type == 'image/jpeg' || $type == 'image/jpg'  || $type == 'image/png') {
            if (!empty($name)) {
                if ( ($size > 0) && ($size < 1048576) && ($error == 0)) {    // less 1MB    
                    $dimage->moveTo($targetPath);     
                }
            }
        } 

        $data['image'] = $name;  //debug($info); //debug($data);
        $info          = $this->Infos->patchEntity($info, $data);        
        $info->user_id = $this->request->getAttribute('identity')->getIdentifier();        

        if ($this->Infos->save($info)) {
            $this->Flash->success(__('The info has been saved.'));
            return $this->redirect(['controller' => 'Infos', 'action' => 'view', $info->id]);
        } else {
            $this->Flash->error(__('The info could not be saved. Please, try again.'));
            return $this->redirect(['controller'=>'Infos', 'action' => 'add']);
        }    
    }

    $infoCategories = $this->Infos->InfoCategories->find('list', ['limit' => 200])->all();
    $this->set(compact('info','infoCategories'));
}

相关问题