I'm trying to perform validation with cake 2.3.8 on a file upload to make sure that only PDF's can be uploaded. I'm loosly basing this off of this tutorial.
My form is displaying the asterisk next to the input, and when I remove the validation from my model the asterisk goes away. I'm assuming this means it "sees" the input for validation, but I just can't figure out why even the custom validation isn't being triggered.
Here's the form
echo $this->Form->create('Upload', array('type' => 'file'));
echo $this->Form->input('file_upload', array('type' => 'file'));
echo $this->Form->input('file_title');
echo $this->Form->end(__('Upload File!', true));
Here's the code in my Upload model
public function checkUpload(){
echo "test"; //check to see if it reaches this...not displaying
return false; //the error message should be set just for testing, it's not displaying though
}
public $validate = array(
'file_upload' => array(
'extension' => array(
'rule' => array('extension', array('pdf')),
'message' => 'Only pdf files',
),
'upload-file' => array(
'rule' => array('checkUpload'),
'message' => 'Error uploading file'
)
)
);
Here is my answer (albeit for cakephp 1.3):
In your model add the following validation to your $validate variable.
$this->validate = array(...
// PDF File
'pdf_file' => array(
'extension' => array(
'rule' => array('extension', array('pdf')),
'message' => 'Only pdf files',
),
'upload-file' => array(
'rule' => array('uploadFile'), // Is a function below
'message' => 'Error uploading file'
)
)
); // End $validate
/**
* Used when validating a file upload in CakePHP
*
* #param Array $check Passed from $validate to this function containing our filename
* #return boolean True or False is passed or failed validation
*/
public function uploadFile($check)
{
// Shift the array to easily acces $_POST
$uploadData = array_shift($check);
// Basic checks
if ($uploadData['size'] == 0 || $uploadData['error'] !== 0)
{
return false;
}
// Upload folder and path
$uploadFolder = 'files'. DS .'charitylogos';
$fileName = time() . '.pdf';
$uploadPath = $uploadFolder . DS . $fileName;
// Make the dir if does not exist
if(!file_exists($uploadFolder)){ mkdir($uploadFolder); }
// Finally move from tmp to final location
if (move_uploaded_file($uploadData['tmp_name'], $uploadPath))
{
$this->set('logo', $fileName);
return true;
}
// Return false by default, should return true on success
return false;
}
You may have to display the error validation messages yourself, you can do this using:
<!-- The classes are for twitter bootstrap 3 - replace with your own -->
<?= $form->error('pdf_file', null, array('class' => 'text-danger help-block'));?>
if you try to debug sth in Cake, always use debug(sth) // sth could be variable could be string could be anything, cuz in Cake debug means
echo "<pre>";
print_r(sth);
echo "</pre>";`
it's already formatted very well.
then after that you have to put die() otherwise after echo sth it will load the view that's why you can't see it even there was an output.
Related
I'm having some issues with a form and it's driving me insane.
Whenever I try to upload an image to my database, I get
Notice: Array to string conversion [CORE\Cake\Model\Datasource\DboSource.php, line 1009]
I'm not sure what I'm doing wrong or missing. Any help is appreciated.
This is my Model
'banner_image' => array(
'not_required' => array(
'allowEmpty' => true,
'required' => false,
),
'is_image' => array(
'rule' => 'is_image_check',
'message' => 'We found that the file you uploaded is not an image.',
//'allowEmpty' => false,
'required' => false,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
),
This is my controller
/**
* admin_add method
*
* #return void
*/
public function admin_add() {
if ($this->request->is('post')) {
$this->Survey->create();
if ($this->Survey->save($this->request->data)) {
$this->Session->setFlash(__('The survey has been saved.'));
return $this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The survey could not be saved. Please, try again.'));
}
}
}
and this is my form
<?php echo $this->Form->create('Survey', array('type'=>'file')); ?>
<fieldset>
<legend><?php echo __('Admin Add Survey'); ?></legend>
<?php
echo $this->Form->input('title');
echo $this->Form->input('subtitle');
if ( empty($this->request->data['Survey']['banner_image']) or isset($this->validationErrors['Survey']['banner_image']) ):
echo $this->Form->input('banner_image', array('type'=>'file'));
else :
echo $this->Html->image('/img/surveys/' . $this->request->data['Survey']['banner_image'] ) ;
echo $this->Html->link('Remove this image?', '/admin/Surveys/remove_image/' . $this->request->data['Survey']['id'] ) ;
endif;
// echo $this->Form->input('listing_image', array('type'=>'file'));
echo $this->Form->input('url_iframe');
echo $this->Form->input('enable');
?>
</fieldset>
<?php echo $this->Form->end(__('Submit')); ?>
This is what your controller receives for field banner_image:
$this->request->data['Survey']['banner_image'] = array(
'name' => 'example_image.jpg',
'type' => 'image/jpg',
'tmp_name' => 'C:/WINDOWS/TEMP/php1EE.tmp', //path will vary on Unix-like OSes
'error' => 0,
'size' => 41737,
);
If you attempt to save this into your table, you will get
Notice: Array to string conversion in filename on line X
Therefore, you have to do some pre-processing before you can call save().
Your surveys.banner_image is probably set to accept a file name.
A typical approach is to implement the Survey::beforeSave() callback and add the necessary code to move the uploaded file from its temporary location to the destination folder of your choice.
You then overwrite the $data['Survey']['banner_image'] array with $data['Survey']['banner_image']['name'].
Or, instead of reinventing the wheel, you can use one of the multiple CakePHP plugins which handles uploads, for example josegonzalez/cakephp-upload.
For further reference, see:
FormHelper::file(string $fieldName, array $options)
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!
I use sfWidgetFormInputFileEditable in my form for file handling purpose.
Here is the code:
/* File */
$this->widgetSchema['file_addr'] = new sfWidgetFormInputFileEditable(array(
'label' => 'File',
'file_src' => sfConfig::get('sf_root_dir').'...',
'is_image' => false,
'edit_mode' => !$this->getObject()->isNew(),
'delete_label' => 'Delete?',
'template' => '...',
'with_delete' => true
));
$this->validatorSchema['file_addr'] = new sfValidatorFile(array(
'required' => $this->getObject()->isNew(),
'path' => sfConfig::get('sf_root_dir') .'/files'
));
$this->validatorSchema['file_addr_delete'] = new deleteFileValidator(...);
/* File: END */
This way it stores generated file name in file_addr field. I want to access other file data like size, file name etc and store them in database too. How can I do that?
You can override the save() method.
public function save($con = null) {
$values = $this->getValues();
$fileAddr = $values['file_addr'];
// ... Do stuff with the values ...
return parent::save($con);
}
I didn't test it, but something like that should work.
Additional uploaded file data is available in form processValues method. So I override it like this:
public function processValues($values)
{
/* File data */
if ($values['file_addr'] instanceof sfValidatedFile)
{
$file = $values['file_addr'];
$this->getObject()->setFileSize($file->getSize());
$this->getObject()->setFileType($file->getType());
$this->getObject()->setFileHash(md5_file($file->getTempName()));
}
return parent::processValues($values);
}
I am using http://milesj.me/code/cakephp/uploader#configuration to upload images. I got it to work fine (in terms of uploading images) but I can't get it to save title/description in my db.
so I have Image.php model that has the following code
<?php
class Image extends AppModel {
var $name = 'Image';
public $actsAs = array('Uploader.Attachment', 'Uploader.FileValidation');
public $validate = array(
'title' => array( 'rule' => 'notEmpty')
);
}
In my view I have bunch of fields such as
echo $this->Form->input('title');
My ImagesController.php add function looks like this
function add($number_of_images = 1){
if (!empty($this->data)) {
var_export($this->data);
exit();
$count = 1;
foreach($this->data['Images'] as $entry){
$file_name = "file" . $count;
if ($data_s = $this->Uploader->upload($file_name)) {
$this->Image->saveAll($data_s);
}
$count++;
}
$this->Session->setFlash("Your image(s) has been saved");
$this->redirect(array('action'=>'index'));
}else{
// make sure 10 is max amount of images a user can upload
if($number_of_images <= 10 ){
$this->set('number_of_images', $number_of_images);
}else{
// set to default 1
$this->set('number_of_images', '1');
}
}
}
When I click save, the image gets uploaded but title/description doesnt get uploaded or validated. This is how my var_export($this->data) looks like
array ( 'selectImages' => '1', 'Images' => array ( 'title' => 'adsafdas', 'description' => 'asdfasd', 'tags' => '', 'file1' => array ( 'name' => '308462_926071922398_11704522_41424436_637322498_n.jpg', 'type' => 'image/jpeg', 'tmp_name' => '/tmp/php7tycbu', 'error' => 0, 'size' => 81638, ), ), )
How can I fix this?
According with the link, $this->Uploader->upload() returns only data of file uploaded. So, you need merge this array with the other fields of your form $this->data before saveAll.
However, if you need validate form data before upload the file, use $this->Image->validates($this->request->data).
below code return "File '' is not readable or does not exist" always:
$filters = array(
'*' => 'stringTrim'
);
$validators = array(
'image'=> array(
'allowEmpty' => TRUE,
new Zend_Validate_File_ImageSize(array('minheight'=>0,'minwidth'=>0,'maxheight'=>1024,'maxwidth'=>1024)),
)
);
$input = new Zend_Filter_Input($filters, $validators);
$input->setData(array_merge($data, $_FILES));
if (!$input->isValid()) {
$this->_errors = $input->getMessages();
}
The input name of your file input has to be image. Also, be sure your form has enctype="multipart/form-data". The format of $_FILES is explained here.
Aside from that I don't detect any code in Zend_Validate_File_ImageSize that can operate on $_FILES. I think you've got to pass the actual path to the file, e.g. 'image' => $_FILES['image']['tmp_name'] (in your $input->setData() call).