Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add base64 upload #495

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open

Conversation

mandricmihai
Copy link

@mandricmihai mandricmihai commented Aug 6, 2018

Settings to use it

 'pathProcessor' => Base64Processor::class,
 'base64_extension' => '.jpg',
 'transformer' => Base64Transformer::class,
 'uploadValidator' => Base64UploadValidator::class,

@josegonzalez suggestions on how I could get rid of is_string() and isset()
On base64 we just get a long string of data with no filename, no type, no size.
Type and size column will also not be set.

@josegonzalez
Copy link
Member

Needs tests before I'll review, sorry.

@@ -0,0 +1,39 @@
<?php
/**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These docblocks shouldn't be here.

@mandricmihai
Copy link
Author

@josegonzalez I added unit tests

@mandricmihai
Copy link
Author

Looks like some code style fails. I will fix it later today.

@mandricmihai
Copy link
Author

@josegonzalez could you review, please?

$temp = [];
$temp['name'] = $filename;
$temp['data'] = $data;
$data = $temp;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of this?

Copy link
Author

@mandricmihai mandricmihai Aug 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When upload base64 $data is just a string f.ex
Y2FrZXBocA==
It's not an array and doesn't have an name.
Could you think about a better solution to this problem?
Here is the same thing https://github.com/FriendsOfCake/cakephp-upload/pull/495/files#diff-84c66ea1e7013949dabde1157612da57R122
$data['size'] and $data['type'] are not set when upload base64, when doing regular upload they are already provided by php.
Maybe implement another 2 interface?
The if's are there just to detect that were trying to upload base64

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also because of the https://github.com/FriendsOfCake/cakephp-upload/pull/495/files#diff-84c66ea1e7013949dabde1157612da57R122
When uploading base64 we can't use the size and type features to have them set in the database

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you show how this would be used in practice? It's not clear whats going on here.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean with the 2 extra interfaces?

Copy link
Author

@mandricmihai mandricmihai Aug 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

            $data = $entity->get($field);
            $path = $this->getPathProcessor($entity, $data, $field, $settings);
            $basepath = $path->basepath();
            $filename = $path->filename();

            $dataFormatter = $this->getDataFormatter($field, $filename);
            $data = $dataFormatter->formatData();
            $files = $this->constructFiles($entity, $data, $field, $settings, $basepath);

            $writer = $this->getWriter($entity, $data, $field, $settings);
            $success = $writer->write($files);

            if ((new Collection($success))->contains(false)) {
                return false;
            }

            $entity->set($field, $filename);
            $metaDataProcessor = $this->getGetMetaDataProcessor($files);
            $entity->set(Hash::get($settings, 'fields.dir', 'dir'), $basepath);
            $entity->set(Hash::get($settings, 'fields.size', 'size'), $metaDataProcessor->getSize());
            $entity->set(Hash::get($settings, 'fields.type', 'type'), $metaDataProcessor->getType());

Something like this.Maybe with some better names 😄

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you could come with something better?I tried to think of a design pattern to apply, but I could only think of template or strategy but is pretty much like what we already have with the interfaces in place

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant in terms of an end user. How are you planning on using this/why should this go into the core?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm using https://foliotek.github.io/Croppie/ so that the user can select his profile picture and the result is in base64.

@@ -87,7 +87,8 @@ public function beforeSave(Event $event, Entity $entity, ArrayObject $options)
continue;
}

if (Hash::get((array)$entity->get($field), 'error') !== UPLOAD_ERR_OK) {
$uploadValidator = $this->getUploadValidator($entity, $settings, $field);
if ($uploadValidator->hasUploadFailed()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice

@davidyell
Copy link
Member

davidyell commented Aug 10, 2018

I'm not quite sure why this functionality needs to be added to the core? Who will want to use this?

To me this is an edge-case and could be implemented with custom classes in userland code base.

@mandricmihai
Copy link
Author

mandricmihai commented Aug 10, 2018

I think you are right.In this case, we can close the pull.

@josegonzalez
Copy link
Member

Could be useful. Can we get documentation for this?

@mandricmihai
Copy link
Author

mandricmihai commented Aug 11, 2018

@josegonzalez before getting the doc for this, we should decide what to do with the type and the size, right now they are not supported and if we are ok with https://github.com/FriendsOfCake/cakephp-upload/pull/495/files#diff-84c66ea1e7013949dabde1157612da57R103

@jorisvaesen
Copy link
Collaborator

After some googling

Filesize:

strlen(base64_decode($data));

Filetype:

$f = finfo_open();
$mime_type = finfo_buffer($f, $data, FILEINFO_MIME_TYPE);

@josegonzalez
Copy link
Member

Those seem reasonable to me @jorisvaesen.

@mandricmihai
Copy link
Author

The problem is not how to determine the file size and type, is where do we put that code that does this?

@josegonzalez
Copy link
Member

We could have a FileProcessor or something that represents how to get that data for each type of file upload?

@mandricmihai
Copy link
Author

mandricmihai commented Aug 13, 2018

That will solve one problem.
How about this if https://github.com/FriendsOfCake/cakephp-upload/pull/495/files#diff-84c66ea1e7013949dabde1157612da57R103
Are you ok with having this if or is better to make another interface?

@josegonzalez
Copy link
Member

@mma can you add actual usage docs for this so I can see how we plan on presenting it's use for users? That'll give me a better idea of what the internals should look like.

@jorisvaesen
Copy link
Collaborator

jorisvaesen commented Aug 13, 2018

Adding a FileProcessor interface and a FileProcessor option to the config seems to me the right thing to do. Just make sure that this config option allows a callback function so an user can return the right processor based on the upload (base64, php file upload, ...)

@mandricmihai
Copy link
Author

@josegonzalez
Sure, I will add the docs this week.

{
$this->entity = $this->getMockBuilder('Cake\ORM\Entity')->getMock();
$this->table = $this->getMockBuilder('Cake\ORM\Table')->getMock();
$this->data = ['data' => 'Y2FrZXBocA==', 'name' => '5a2e69ff-c2c0-44c1-94a7-d791202f0067.txt'];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should keep in mind that using a custom array format like this makes validation tricker. Most validation methods for uploaded files won't be usable. I haven't reviewed the full PR but you need to ensure proper validation is done for this array format and someone can't sneak in whatever they want using this feature.

*/
public function hasUploadFailed()
{
return !base64_decode($this->entity->get($this->field), true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How can one do other validations like for e.g checking for particular mimetype / file type?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I now see the comments regarding adding methods/interfaces for checking size and mime type.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think is possible to do check on mimetype / file type without having the file already written on the disk

Copy link
Member

@ADmad ADmad Aug 15, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be possible having validation methods using the example code provided in this comment #495 (comment) ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just tried and it works. I wasn't aware of such method to determine the mimetype.

@ADmad
Copy link
Member

ADmad commented Aug 15, 2018

The problem is not how to determine the file size and type, is where do we put that code that does this?

It should be in validation methods shouldn't it?

@mandricmihai
Copy link
Author

mandricmihai commented Aug 15, 2018

I don't think it should be in validation.We want to use the methods to get the actual size and file type https://github.com/FriendsOfCake/cakephp-upload/pull/495/files#diff-84c66ea1e7013949dabde1157612da57R123
so that we can set on the entity.

@ADmad
Copy link
Member

ADmad commented Aug 15, 2018

Just FYI, how I provide cropping feature is use js code to just generate the cropping dimensions and submit it in a separate field without touching the actual upload file. Then use the cropping data to crop on server side.

Only drawback of this way is the full image is uploaded but in return it saves all the extra code for handing base64 encoded data and more importantly upload validation.

@ADmad
Copy link
Member

ADmad commented Aug 15, 2018

I don't think it should be in validation.

If not in validation then how can I prevent someone from submitting a non image base64 encoded data?

@mandricmihai
Copy link
Author

We can provided a method in ImageValidationTrait.php that uses https://secure.php.net/manual/en/function.imagecreatefromstring.php

@ADmad
Copy link
Member

ADmad commented Aug 15, 2018

Unless cake's validator can be used to validate the mime type of base64 encoded data before any other processing begins, I am a big "NO" on adding this feature to the plugin.

@mandricmihai
Copy link
Author

When you say cake's validators you talk about the validators already provided by cake or the custom validators?

@ADmad
Copy link
Member

ADmad commented Aug 15, 2018

Custom validation methods which will be used by Cake's Validator 🙂

@mandricmihai
Copy link
Author

@ADmad could you take a look over the validator when you have some time?

@boyteenphonui
Copy link

It is very useful, I also really need it. I am very supportive of this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants