Roberto
Roberto

Reputation: 1097

CakePHP 3.x - File validators on upload always failing

I am working on an image upload. I am trying to do the image verification in the model (like it should, right?), however I can't get the validation to work.

I put the following in src/Model/Table/CommentTable:

   public function validationDefault(Validator $validator)
   {
       //...
       $validator->add('photofile', 'upload', [
           'rule' => ['uploadedFile', ['maxSize' => 1048576, 'optional' => true, 'types' => ['image/*']]],
           'message' => 'Not a valid file'
       ]);

       //...
    }

For testing my controller looks like (I hard-coded an existing file):

    $comment = $this->Comments->newEntity([
        'body' => $data['body'],
        'bin_id' => $bin_id,
        'user_id' => $this->Auth->user('id'),
        'photofile' => 'C:/Users/Robert/Downloads/test.jpg'
    ]);

This file is only a couple of bytes, yet after debugging $comment is shows an error in 'photofile':

'[errors]' => [
    'photofile' => [
        'upload' => 'Not a valid file'
    ]
],

So why is the validator always failing? Am I using it correctly?

Upvotes: 0

Views: 413

Answers (1)

ndm
ndm

Reputation: 60503

Well, it's not an uploaded file, so that's generally the expected behavior. Also a string isn't supported as a valid value at all, the value must either be a file upload array, or as of CakePHP 3.4, an object that implements \Psr\Http\Message\UploadedFileInterface.

For file upload arrays, the uploadedFile validation rule provided by CakePHP will utilize is_uploaded_file(), which will fail for files that haven't actually been uploaded, and you cannot emulate them.

As of CakePHP 3.4 you can use UploadedFileInterface objects as already mentioned. CakePHP requires \Zend\Diactoros\UploadedFile which provides an implementation that you could utilize for testing purposes, like:

$file = 'C:/Users/Robert/Downloads/test.jpg';

$comment = $this->Comments->newEntity([
    'body' => $data['body'],
    'bin_id' => $bin_id,
    'user_id' => $this->Auth->user('id'),
    'photofile' => new \Zend\Diactoros\UploadedFile(
        $file,
        filesize($file),
        \UPLOAD_ERR_OK,
        pathinfo($file, \PATHINFO_BASENAME),
        'image/jpeg'
    )
]);

However while this will pass validation, you won't be able to move that file using UploadedFile::moveTo(), as it uses move_uploaded_file(), which again only works with files that have actually been uploaded.

Also regex validation of MIME types only works when passed as a string (this currently isn't documented), and it must be a valid regex including delimiters, like

'types' => '#^image/.+$#'

Alternatively specify the exact types as an array, ie

'types' => ['image/jpeg', 'image/png', /* ... */]

See also

Upvotes: 2

Related Questions