I am trying to upload image by cakephp 3. I have tried the code below which was working in cakephp 2. Now in cakephp 3 I have tried the code below
database field
ALTER TABLE `users` ADD `avatar` VARCHAR(255) NOT NULL ;
Then in users add.ctp I have created below form
<?= $this->Form->create($user,['type' => 'file']) ?>
<?= $this->Form->input('avatar',['type' => 'file']);?>
<?= $this->Form->button(__('Submit')) ?>
<?= $this->Form->end() ?>
In user model I have added this validation
$validator
->add('avatar', [
'uploadError' => [
'rule' => 'uploadError',
'message' => 'The cover image upload failed.',
'allowEmpty' => TRUE,
],
'mimeType' => [
'rule' => array('mimeType', array('image/gif', 'image/png', 'image/jpg', 'image/jpeg')),
'message' => 'Please only upload images (gif, png, jpg).',
'allowEmpty' => TRUE,
],
'fileSize' => [
'rule' => array('fileSize', '<=', '1MB'),
'message' => 'Cover image must be less than 1MB.',
'allowEmpty' => TRUE,
],
'processCoverUpload' => [
'rule' => 'processCoverUpload',
'message' => 'Unable to process cover image upload.',
'allowEmpty' => TRUE,
],
]);
After that I found this error
ext/fileinfo is required for validating file mime types
After ndm's comment, I have changed
;extension=php_fileinfo.dll
to
extension=php_fileinfo.dll
in the php.ini file
Then this error has been gone. But the new error that I found
error : Method processCoverUpload does not exist
But in the method below I have added
public function processCoverUpload($check = array()) {
if (!is_uploaded_file($check['avatar']['tmp_name'])) {
return FALSE;
}
if (!move_uploaded_file($check['avatar']['tmp_name'], WWW_ROOT . 'img' . DS . 'uploads' . DS . $check['avatar']['name'])) {
return FALSE;
}
$this->data[$this->alias]['avatar'] = 'uploads/'. $check['avatar']['name'];
return TRUE;
}
I don't know why Method processCoverUpload does not exist. Can you explain?
As already mentioned in the comments, CakePHP 3.x now requires the fileinfo extension for validating mime types.
http://php.net/manual/en/fileinfo.installation.php
The other error happens because you haven't defined a provider where your custom method can be found. You've most likely added the method to your table class, so in that case you should use the table provider
'processCoverUpload' => [
'provider' => 'table', // <<<< there you go
'rule' => 'processCoverUpload',
'message' => 'Unable to process cover image upload.',
'allowEmpty' => TRUE,
],
The default provider is defined to use the \Cake\Validation\Validation class.
On a side note, $check wont contain the field name as a key, validation methods will receive the plain value that the key in the data holds.
Also $this->data doesn't exist anymore, things are working different now in 3.x. If you want to modify the data, then you should use the beforeMarshal or beforeSave events. However, with the latter you'll run into problems in case the upload field is using the same name as the column in the database which stores the file path, as this will cause the array to be marshalled to the type of the column, which is most probably a string type: https://github.com/cakephp/cakephp/issues/5998
See also
Cookbook > Database Access & ORM > Validation > Validation Providers
Cookbook > Validation > Adding Validation Providers
Cookbook > ... ORM > Saving Data > Modifying Request Data Before Building Entities
Related
I am working with backpackforlaravel ( "backpack/crud": "3.5.*"), it is great.
I made an image CRUD section. I have a Requests file validation with the following code.
return [
'name' => 'required|min:5|max:255',
'code' => 'required|min:2|max:20',
'image' => 'required|mimes:jpeg,png,jpg,gif|max:2048',
];
And in my controller I have this code
$this->crud->addField([ // image
'label' => "Bandera",
'name' => "image",
'type' => 'image',
'upload' => true,
'crop' => false, // set to true to allow cropping, false to disable
'aspect_ratio' => 1, // ommit or set to 0 to allow any aspect ratio
'mime_types' => ['image'],
'filesize' => 5,
// 'disk' => 's3_bucket', // in case you need to show images from a different disk
// 'prefix' => 'uploads/images/profile_pictures/' // in case your db value is only the file name (no path), you can use this to prepend your path to the image src (in HTML), before it's shown to the user;
]);
Right now it is showing
The image must be a file of type: jpeg, png, jpg, gif.
The image may not be greater than 2048 characters.
It is validation the image weigh as a string and I need a normal weight and type validation
You are validating an image correctly when using that array of validators.
Validating mimes:jpeg,png,jpg,gif checks if it is an image.
Validating max:2048 puts a maximum on the filesize.
Here is my validator for the field article where pdf files should be uploaded:
$validator
->add('article', [
'rule' => [
'extension' => [
['article', 'pdf'],
'message' => 'Only pdf!'
]
]
])
->notEmpty('article');
This gives an error:
"Unable to call method "" in "default" provider for field "article""
How can I fix this to enable uploading only pdf files to the field article?
The order of the elements in your code is wrong.
Also worth a look: API Class Validation - Extension
$validator
->add('article', [
'extension' => [
'rule' => [ 'extension', ['pdf'] ],
'message' => 'Only PDF!'
]
])
->notEmpty('article', 'This field is required')
;
You should also check the mimeType to enhance security. Works similar, see also the example in the book in the chapter conditional validation
To validate a single file (a single input-file-field) is no problem in Yii and it works very well:
public function rules() {
return CMap::mergeArray(parent::rules(), array(
array(
'image',
'file',
'allowEmpty'=>false,
'types'=>'pdf,jpg,gif,png',
'on' => 'CaseA, CaseB',
'maxSize'=>1024000,
'tooLarge' => 'Max File size is 1MB',
'message' => 'You have to upload a file at least'
),
....
....
What if image is an array of files? Created Form-Elements by Yii looks like this (Firebug-Output):
<input type="file" id="MyFormModel[image][0]" name="MyFormModel[image][0]">
<input type="file" id="MyFormModel[image][1]" name="MyFormModel[image][1]">
What exactly should I modify in my rules? A simple "image[]" does not help.
EDIT: Solution
public function rules() {
return CMap::mergeArray(parent::rules(), array(
array(
'image',
'file',
'allowEmpty'=>false,
'types'=>'pdf,jpg,gif,png',
'on' => 'CaseA, CaseB',
'maxSize'=>1024000,
'maxFiles' => 5, // <----- THAT'S IT
'tooLarge' => 'Max File size is 1MB',
'message' => 'You have to upload a file at least'
),
....
....
Set the maxFiles attribute appropriately and the validator will work for all of the inputs. You don't need to change the input control names.
I have a form where users can upload images, and I'm printing it to the page like so:
<?php echo $this->Form->label('file', 'Image file', array('class' => 'col-lg-1 control-label')); ?>
Then, in the model I'm setting up validation like so:
public $validate = array(
'file' => array(
'required' => array(
'rule' => array('notEmpty'),
'message' => 'You must select an image to upload'
),
'extension' => array(
'rule' => array('extension', array('png')),
'message' => 'Images must be in PNG format'
),
'size' => array(
'rule' => array('fileSize', '<', '1MB'),
'message' => 'Images must be no larger than 1MB'
),
'goodUpload' => array(
'rule' => 'uploadError',
'message' => 'Something went wrong with the upload, please try again'
)
)
);
However, Cake doesn't seem to be associating the form field with the validation rule, as if I select an image to upload I always get "You must select an image to upload" as a form error. I've made sure the form has enctype="multipart/form-data".
Is this happening because file isn't a database field? How can I make cake run some validation on file?
Edit: Here's my entire form, as requested: http://pastebin.com/SbSbtDP9
You can validate fields that are not in the database, long as you have the correct field name in the correct model.
From what I can see in your code it seems your outputting a label instead of an actual input, for the image upload I would try
echo $this->Form->create('Model', array('type'=>'file'));
echo $this->Form->input('file', array('type'=>'file'));
echo $this->Form->submit('Upload Image'):
echo $this->Form->end();
For the validation I would try something like with the rest of your validate options (size, etc...) CakePHP usually throws an error on notEmpty on File Uploads. So just checking for the extension type is usually good enough.
public $validate = array(
'file' => array(
'rule' => array(
'extension', array('jpeg', 'jpg')
'message' => 'You must supply a file.'
)
)
);
Majority of time in CakePHP for Image Uploading I resort to a plugin such as https://github.com/josegonzalez/cakephp-upload it does validation and upload handling all in one.
Managed to figure it out. Turns out having the notEmpty validation on a file fieldnever works, it always thinks there's nothing there and so always throws that validation message.
Worked around it by writing my own validation method.
I have an upload form that has validation checks whether an item is a valid CSS file or not. I do try to upload a .css file but the validation fails.
Here's the bit where I try to validate the code on my controller:
private function _queueArticle($ref = NULL)
{
$input = Input::all();
$vrules = Config::get('validation.queue_article');
//validate inputs
$validation = Validator::make($input, $vrules);
if ( $validation->fails() ) {
return ( $ref === NULL ) ?
Redirect::to($redir_path)->withErrors($validation)->withInput() :
Redirect::to($redir_path)->withErrors($validation);
}
}
Here's what's $vrules:
'queue_article' => array(
'title' => 'required|max:255',
'body' => 'required',
'slug' => 'unique:articles,slug',
'hero' => 'required|image',
'custom_css' => 'mimes:css'
)
I believe it's failing because it's using PHP's finfo, which is known to fail detecting css not as text/css, but rather text/plain. Doesn't Symfony, Laravel's 'companion code' here (don't know the term), has its own validation class that successfully clears CSS for what it is?
More importantly, what can I do about this?
UPDATE: Error message shows my custom error 'Please upload a valid CSS file.' From app/lang/en/validation.php:
'custom' => array(
'password_old' => array( 'required' => 'Please enter your current password.' ),
'password' => array( 'confirmed' => 'The new passwords don\'t match.' ),
'hero' => array(
'required' => 'A header image is required.',
'image' => 'The header file you included is not valid. Please upload a valid image.'
),
'custom_css' => array('mimes' => 'Please upload a valid CSS file.')
)
UPDATE 2: I checked var_dump($validation) and showed zero contents on array messages and failedRules. It also shows the CSS file having mime type as text/css. All is well, eh, except when I var_dump($validation->fails()) it returns a bool of true.
Additional info will be provided upon request.
Thanks!