首页 > 解决方案 > 如何在不可变的情况下使用 cakephp-upload 在 cakephp 3.4.0 中保存图像

问题描述

我正在开发我的 cakephp 项目 ,目前正在从 3.3.16 升级到 3.4.0

该项目使用cakephp-upload 插件来保存图像。上传插件需要一个现有的实体来附加一个文件。在取消设置以保存用户之前,对请求进行了修改以获取头像。

我知道这不是修改请求的好习惯,但代码是这样制作的。使用 3.4.0 版本中的不可变对象,它不再可能了。但我不知道如何正确地做到这一点。

这是我的 unit-test给出的错误消息,由vendor/bin/phpunit --filter testAdd tests/TestCase/Controller/Api/V1/UsersControllerTest.php

There was 1 failure:

1) App\Test\TestCase\Controller\Api\V1\UsersControllerTest::testAdd
Failed asserting that file "/home/comptoir/Comptoir-srv/webroot/img/files/Users/photo/5/avatar/correctAvatarLogo.jpg" exists.

/home/comptoir/Comptoir-srv/tests/TestCase/Controller/Api/V1/UsersControllerTest.php:208

这是实际的代码

public function add()
    {
        if (!empty($this->request->data)) {
            $user = $this->Users->newEntity($this->request->data);
        } else {
            $user = $this->Users->newEntity();
        }

        $message = "";
        // Get the avatar before unset it to save the user.
        // The Upload plugin need an existing entity to attach a file to it.

        if ($this->request->is('post')) {
            if (isset($this->request->data['photo']) && !$user->errors()) {
                $avatar = $this->request->data['photo'];
                $this->request->data['photo'] = "";
            }

            $user = $this->Users->patchEntity($user, $this->request->data);

            if ($this->Users->save($user)) {
                $user = $this->Users->get($user->id, ['contain' => []]);

                isset($avatar) ? $this->request->data['photo'] = $avatar : null;

                $user = $this->Users->patchEntity($user, $this->request->data);

                if ($this->Users->save($user)) {
                    $message = "Success";
                    $this->Flash->success(__d("Forms", "Your are registred on the Comptoir du Libre, welcome !"));
                    if (!$this->request->is('json')) {
                        $this->Auth->setUser($this->Auth->identify());
                        $this->redirect([
                            "prefix" => false,
                            "controller" => "Pages",
                            "language" => $this->request->param("language")
                        ]);
                    }
                } else {
                    $message = "Error";
                }
            } else {
                $message = "Error";
                $this->Flash->error(__d("Forms", "Your registration failed, please follow rules in red."));
            }

            $message == "Error" ? $this->set('errors', $user->errors()) : null;
        }


        $this->ValidationRules->config('tableRegistry', "Users");
        $rules = $this->ValidationRules->get();
        $userTypes = $this->Users->UserTypes->find('list', ['limit' => 200]);
        $this->set(compact('user', 'userTypes', 'rules', 'message'));
        $this->set('_serialize', ['user', 'userTypes', 'rules', 'message', 'errors']);
    }

有谁知道如何尊重不可变规则?

标签: cakephpcakephp-3.4

解决方案


你的前提是错误的。

上传插件需要一个现有的实体来附加一个文件

这实际上是不正确的,在创建新记录的同时上传文件可以正常工作。您的控制器中不需要这些东西,应该可以通过一次基本保存来处理它,即您应该调查您遇到的问题并修复它。

但是查看您的测试,无论如何它都应该失败,因为您传递的文件数据是无效的,它既不是实际上传的文件,也不是is_uploaded_file()能够true定义临时文件路径的用户数据, 和错误代码,即如果测试按原样通过,您没有正确验证数据。接受此类数据是一个安全漏洞,它可能允许各种攻击,从路径遍历到任意文件注入!

理想情况下,您的整个上传验证和编写功能将支持\Psr\Http\Message\UploadedFileInterface对象,这将允许通过能够将该类的实例传递到测试数据中来进行非常简单的测试,这可能是值得为插件建议的东西。如果没有这样的功能,您的第二个最佳选择可能是在发出测试请求之前修改表的验证规则,这样is_uploaded_file()就被跳过了,或者您正在切换到通过 HTTP 的集成测试,而不是在 CakePHP 中的模拟。


推荐阅读