Yii cant validate file input - php

I'm currently doing a project in PHP Yii Framework. I have a form which requires the user to upload a file. During the registration, user uploaded the file, however, when user submits the form, the form is always detected blank on the file input, it's like as if there is no attachment on the form. below is the code:
Model - CandidateResume:
return array(
array('resume_file','file','types'=>'doc,docx,pdf', 'allowEmpty'=>true, 'safe'=>true, 'on'=>'register'),
);
Model - Candidate:
return array(
array('can_email,name,repeat_can_email, can_password,repeat_can_password','required', 'on'=>'simplereg'),
);
View:
$form = $this->beginWidget('bootstrap.widgets.TbActiveForm',array(
'id'=>'candidate-form',
'enableAjaxValidation'=>true,
'type'=>'horizontal',
'htmlOptions' => array(
'enctype' => 'multipart/form-data',
'autocomplete'=>'off', //turn off auto complete in FF
)
));
echo $form->textFieldRow($model,'can_email',array('class'=>'span5','maxlength'=>100));
echo $form->textFieldRow($model,'repeat_can_email',array('class'=>'span5','maxlength'=>100));
echo $form->passwordFieldRow($model,'can_password',array('class'=>'span5','maxlength'=>100));
echo $form->passwordFieldRow($model,'repeat_can_password',array('class'=>'span5','maxlength'=>100));
echo $form->fileFieldRow($resume,'resume_file', array('id'=>'resume_file'));
$this->endWidget();
Controller - Candidate:
public function actionCreate()
{
$model = new Candidate();
$model->setScenario('simplereg');
$resume = new CandidateResume();
$resume->setScenario('register');
// Uncomment the following line if AJAX validation is needed
//$this->performAjaxValidation($model);
if(isset($_POST['Candidate'], $_POST['CandidateResume']))
{
$_POST['CandidateResume']['resume_file'] = $resume->resume_file;
$model->attributes = $_POST['Candidate'];
$resume->attributes = $_POST['CandidateResume'];
$uploadedFile = CUploadedFile::getInstance($resume,'resume_file');
if($resume->validate() && $model->validate())
{
$model->save();
if(!empty($uploadedFile)) // check if uploaded file is set or not
{
$saved = $uploadedFile->saveAs(Yii::app()->params['RESUME_PATH'].$model->can_id.'_'.$uploadedFile->getName());
$resume->resume_file = Yii::app()->params['RESUME_DIR'].$model->can_id.'_'.$uploadedFile->getName();
$resume->resume_send_ip = Yii::app()->request->userHostAddress;
}
$resume->save();
}
}
$this->render('create',array('model'=>$model, 'resume'=>$resume));
}
If I remove the validation on the controller:
if($resume->validate() && $model->validate())
The form data can be saved and attachment is placed properly in the folder. However, I need to do the validation for the form. Therefore I cant skip this part.
Is there anything that I missed out? I have checked many times and do researches for the solutions. All provides the similar solutions, therefore I can't figure out the things. Can anyone help me? Thank you in advance.

You don't set the resume_file attribute. It cames from $_FILES not from $_POST
$resume->attributes = $_POST['CandidateResume'];
$uploadedFile = CUploadedFile::getInstance($resume,'resume_file');
$resume->resume_file = $uploadedFile; //add this line

Related

ZendForm: move a picture into a folder

I'm working on a project with ZF2 and Zend Form. I'd like to add an avatar into a user profile.
The problem is that I only get the file name and save it in the DB. I would like to insert it into a folder so I'll be able to get it and display it. The rest of the form is working.
My guess is that I have to get information from $FILES, but I have no idea how to do this. I've read the documentation but can't see how to apply this to my project.
Thank you in advance!
Here's my Controller Action
public function signinAction()
{
$this->em = $this->getServiceLocator()->get('doctrine.entitymanager.orm_default');
$form = new SignupForm($this->em);
$model = new ViewModel(array("form" => $form));
$url = $this->url()->fromRoute("signin");
$prg = $this->prg($url, true);
if($prg instanceof \Zend\Http\PhpEnvironment\Response){
return $prg;
}
else if($prg === false){
return $model;
}
$user = new User();
$form->bind($user) ;
$form->setData($prg) ;
if($form->isValid()){
$bcrypt = new Bcrypt() ;
$pwd = $bcrypt->create($user->getPassword());
$user->setPassword($pwd);
$this->em->persist($user) ;
$this->em->flush() ;
return $this->redirect()->toRoute('login');
}
return $model ;
}
Here's my form file :
class SignupForm extends Form
{
private $em = null;
public function __construct($em = null) {
$this->em = $em;
parent::__construct('frm-signup');
$this->setAttribute('method', 'post');
$this->setHydrator(new DoctrineEntity($this->em, 'Application\Entity\User'));
//Other fields
...
//File
$this->add(array(
'type' => "File",
'name' => 'avatar',
'attributes' => array(
'value' => 'Avatar',
),
));
//Submit
...
}
}
And the form in my view :
$form = $this->form;
echo $this->form()->openTag($form);
//other formRow
echo $this->formFile($form->get('avatar'));
echo $this->formSubmit($form->get('submit'));
echo $this->form()->closeTag();
There are two things you could look at for getting your avatar to work:
Using the Gravatar view helper (uses gravatar.com service that automatically links images to email addresses)
documentation on using the gravatar service can be found here
Upload images yourself with the file upload classes that are shipped with ZF2:
form class for file upload can be found here
input filter class documentation can be found here
If you follow those docs you should be able to manage what you want.
Note: check especially the use of the Zend\Filter\File\RenameUpload filter in the example in the input filter documentation. This filter renames/moves the uploaded avatar file to the desired location.

Yii PHP file uploader overwriting on update

I have a basic form in PHP framework Yii, the action to create works fine, however, when i update the record (for example if i'm not changing the file upload, but another field), it overwrites the file upload and blanks it, can anyone assist me? I've tried all the validation I can think of around the controller items, but no matter what i add it still blanks it on update.
Here's the view code
<?php $form=$this->beginWidget('booster.widgets.TbActiveForm', array(
'id'=>'company-form',
'enableAjaxValidation'=>false,
'method' => 'post',
'type' => 'horizontal',
'htmlOptions' => array(
'enctype' => 'multipart/form-data'
)
));
echo $form->textFieldGroup($model,'name',array('class'=>'col-md-5','maxlength'=>75));
echo $form->fileFieldGroup($model, 'logo',
array(
'wrapperHtmlOptions' => array(
'class' => 'col-md-9',
),
'hint' => 'You can only upload jpg, png, gif\'s – max upload filesize is 1.5mb. Square images are advised.<br/>In certain browsers, you can also drag \' drop files into the dropzone.',
)
);
if($model->isNewRecord!='1'){ ?>
<div class="row">
<label class="col-md-3 control-label" style="padding-top: 25px;">Company image</label>
<div class="col-md-6">
<?php echo CHtml::image(Yii::app()->request->baseUrl.'/images/portraits/company/'.$model->logo,"logo",array("class"=>"img-polaroid placeholder")); ?>
</div>
</div>
<?php } ?>
And this is my actionUpdate function in Controller
public function actionUpdate($id)
{
$model=$this->loadModel($id);
if(isset($_POST['Company']))
{
$model->attributes=$_POST['Company'];
$uploadedFile=CUploadedFile::getInstance($model,'logo');
if (is_object($uploadedFile) && get_class($uploadedFile)==='CUploadedFile'){
if(!$uploadedFile == null){
$rnd = rand(0,9999);
$filename_preg1 = preg_replace("/[^a-zA-Z0-9.]/", '', "{$uploadedFile}");
$fileName = "{$rnd}-{$filename_preg1}";
$company = $model->name;
$model->logo = $fileName;
}
if($model->save()){
if(!empty($uploadedFile)){
$fullPath = Yii::app()->basePath . '/../images/portraits/company/' . $fileName;
$uploadedFile->saveAs($fullPath);
}
$this->redirect(array('view','id'=>$model->company_id));
}
}
if($model->save()){
$this->redirect(array('view','id'=>$model->company_id));
}
}
$this->render('update',array(
'model'=>$model,
));
}
Can anyone see where i'm going wrong?
UPDATE
Thanks SiZE, the code you gave me worked in one form and not in the other, the one it didn't work in has validation in the model rules
array('logo', 'file','types'=>'jpg, gif, png', 'allowEmpty'=>true, 'on'=>'update'),
This only works with the allowEmpty param here as it's not a required field, however, with the rule in place in the model, it still blanks the file field regardless, anyone have any more thoughts?
CActiveForm calls CHtml::activeFileField method wich generates empty hidden field to correctly work with model's rules.
You can try this:
$model=$this->loadModel($id);
$original_logo = $model->logo;
if(isset($_POST['Company'])) {
$model->attributes = $_POST['Company'];
$logo = CUploadedFile::getInstance($model, 'logo');
$model->logo = $logo !== null ? $logo->getName() : $original_logo;
if ($model->save()) {
if ($logo !== null) {
$logo->saveAs(/* specify path with file name here */);
}
$this->redirect(array('view','id'=>$model->company_id));
}
}

Yii file field posting empty values

I am a newbie in Yii, and I am trying to make an upload form in Yii, Please i need help.
Once the form post data to the controller every other post value is posted except for the file value.
i even tried checking for Errors with var_dump($model->image); and it returned this Error string '' (length=0) specifying an empty string like an image wasn't even posted at all.
This is my controller
class TestController extends Controller
{
public function actionIndex()
{
$model=new Test;
if(isset($_POST['Test']))
{
$model->attributes=$_POST['Test'];
if($model->save()){
var_dump($model->getErrors());
if ($model->image){
var_dump($model->image);
$uploadedFile=CUploadedFile::getInstance($model,'image');
$fileName = date("Y_m_d_H_i_s").$uploadedFile;
$model->image = $fileName;
if(!empty($uploadedFile)) // check if uploaded file is set or not
{
$uploadedFile->saveAs(Yii::getPathOfAlias('webroot').'/imagefolder/'.$fileName);
}
}
}
}
}
}
And this is my View
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'test-form',
'htmlOptions' => array('enctype' => 'multipart/form-data'),
'enableAjaxValidation'=>false,
)); ?>
<?php echo CHtml::activeFileField($model,'image',array('id'=>'primaryupload')); ?>
<?php echo CHtml::submitButton($model->isNewRecord ? 'UPLOAD' : 'UPLOAD',array('id'=>'submit','class'=>'btn')); ?>
<?php $this->endWidget(); ?>
Any help will be appreciated. Because i am really frusrated at this point.
If you are only new to Yii and not in PHP, than you may know that uploaded files goes via $_FILES global variable and not via $_POST global variable. So to get uploaded file, you use
$uploadedFile = CUploadedFile::getInstance($model, 'image');
So your final code looks like this:
$post = Yii::app()->request->getPost('Test');
if ($post) {
$model->attributes = $post;
$uploadedFile = CUploadedFile::getInstance($model, 'image');
if ($uploadedFile) {
$imageName = date("Y_m_d_H_i_s").$uploadedFile->name;
$model->image = $imageName;
if ($model->save()) {
$uploadedFile->saveAs(Yii::getPathOfAlias('webroot').'/imagefolder/'.$imageName );
}
}
I think you should use $_FILES['image'] instead of $model->image.
As an option, you can "hardcode" file attribute in your form. Just:
<input type="file" id="yourid" name="yourname" />
Then in YourController, where you are parsing your POST data you could directly access to $_FILES['yourname'].
Not an elegant way, but simple and fast.
P.S.: if you are using $this->beginWidget in your view, then you should add to parameters
$this->beginWidget('CActiveForm', array(
...
'htmlOptions'=>array(
'enctype'=>'multipart/form-data'
),
));

how to update form that contains filefield without re-upload the file again in Yii?

I want to update a record in my model, and it contains a file field, here is the form code:
<div class="row">
<?php echo $form->labelEx($model,'img'); ?>
<?php echo CHtml::activeFileField($model,'img',array('width'=>25,'lentgh'=>25)); ?>
<?php echo $form->error($model,'img'); ?>
</div>
and here is the update action in the controller:
$model=$this->loadModel($id);
$img = $model->img;
if(isset($_POST['Press']))
{
$model->attributes=$_POST['Press'];
$model->img = $img;
if(isset($_POST['Press']['img'])){
if(!empty ($_POST['Press']['img']))
$model->img = CUploadedFile::getInstance($model, 'img');
So if the user didn't upload an image, the value of img attribute should not be updated and the model should be validated, but I got validation error every time I click on save and the img file filed is empty, so how I can fix this issue ?
Form validations are handeled by the model.
You can set an imagefield of filefield to be allowed to be empty like this in your model.php:
array('image', 'file', 'types'=>'jpg,png,gif',
'maxSize'=>1024 * 1024 * 5,
'allowEmpty' => true),
EDIT:
You can check if the file is empty before overwriting the current value of the object
$imageUploadFile = CUploadedFile::getInstance($model, 'image');
if($imageUploadFile !== null){ // only do if file is really uploaded
$imageFileName = mktime().$imageUploadFile->name;
$model->image = $imageFileName;
}
You can use csenario as:
array('image', 'file', 'types'=>'jpg,png,gif',
'maxSize'=>1024 * 1024 * 5,
'allowEmpty' => false, 'on'=>'insert'),
array('image', 'file', 'types'=>'jpg,png,gif',
'maxSize'=>1024 * 1024 * 5,
'allowEmpty' => true, 'on'=>'update'),
after that it will allow empty field on update
Faced the same issue and here is my solution.
But first I will describe how I work with models.
Basic POST processing
if (Yii::app()->request->getIsPostRequest()) {
$basicForm->attributes = Yii::app()->request->getParam(get_class($basicForm));
if ($basicForm->validate()) {
$logo = CUploadedFile::getInstance($basicForm, "logo");
if (!is_null($logo)) {
try {
// uploads company logo to S3
} catch (\Exception $e) {
// display any kind of error to the user or log the exception
}
}
if ($basicForm->save(false))
$this->refresh();
}
}
and my logo field has rule ["logo", "file", "mimeTypes" => ["image/png", "image/jpeg"], "allowEmpty" => true].
This rule gives me freedom to upload or not to upload the file, BUT if I want to change another form field not changing the file it will empty the model's logo field and my database too.
Problem
File gets empty if form update trying to update another form field, not file
Why it happening?
This happening because file validator expects CUploadedFile type of object when you have string in the model's logo field. String from database where you storing path to logo. And string is not CUploadedFile. And after if ($basicForm->validate()) model resets the logo field to null.
Solution
Own validation rule which will upload/reupload the file if logo is of hype `` and do nothing if logo of basic string type. Here I will put a basic "in-model" validator, it is up to you to move it into separate class, etc.
public function checkFile($attribute, $params)
{
$mimeTypes = isset($params["mimeTypes"]) ?$params["mimeTypes"] :[];
$allowEmpty = isset($params["allowEmpty"]) ?$params["allowEmpty"] :false;
/** #var CUploadedFile $value */
$value = $this->{$attribute};
if (!$allowEmpty && empty($value))
$this->addError($attribute, "{$attribute} can not be empty");
if (!empty($value)) {
if (is_object($value) && CUploadedFile::class === get_class($value) && 0 < sizeof($mimeTypes)) {
if (!is_array($value->type, $mimeTypes))
$this->addError($attribute, "{$attribute} file is of wrong type");
} elseif (!is_string($value)) {
// we can die silently cause this error won't actually ever get to the user in normal use cases
$this->addError($attribute, "{$attribute} must be of type either CUploadedFile or PHP string");
}
}
}
I called it checkFile and then the logo rule becomes ["logo", "checkFile", "mimeTypes" => ["image/png", "image/jpeg"], "allowEmpty" => true],
That is it. Enjoy.
Note: I'm putting this here as an example. Code may not be completely correct, or used as is, all the stuff like that... :)
I'had same problem. In my user model there wos a field containing path to image and i wanted to update model and fileField cleared my images.
So i figured workaround - store field containing path_to_file at start of action "update" in $tmp_variable and if there is no new upload - just set it before save():
public function actionUpdate($id)
{
$request = Yii::app()->request;
$model = $this->loadModel($id, 'YourModel');
$tmpPathToImage = $model->your_path_to_file_in_model;
$yourModelPost = $request->getPost('YourModel');
if (!empty($yourModelPost)) {
$model->setAttributes($yourModelPost);
$fileSource = Yii::getPathOfAlias('webroot.uploads.yourModel');
$imgTmp = CUploadedFile::getInstance($model, 'your_path_to_file_in_model');
if ($imgTmp !== null) {
$imgTmp->saveAs($fileSource.'/'.$imgTmp->name);
$model->your_path_to_file_in_model = '/'.UPLOADS_YOUR_MODEL_FILE_PATH_RELATIVE.'/'.$imgTmp->name;
}
else {
$model->your_path_to_file_in_model = $tmpPathToImage;
}
if ($model->save()) {
$this->redirect(['/admin/yourModel/index']);
}
}
$this->render('update', [
'model' => $model,
]);
}
Hope it helps someone... :)

Yii - updating a model and using the model to echo data in the view

I have the following code for updating a Yii model:
public function actionSettings($id) {
if (!isset($_POST['save_hostname']) && isset($_POST['Camera']) && isset($_POST['Camera']['hostname'])) {
$_POST['Camera']['hostname'] = '';
}
$model = $this->loadModel($id);
$model->setScenario('frontend');
$this->performAjaxValidation($model);
if (isset($_POST['Camera'])) {
$model->attributes = $_POST['Camera'];
unset($model->api_password);
if ($model->save()) {
Yii::app()->user->setFlash('success', "Camera settings has been saved!");
} else {
Yii::app()->user->setFlash('error', "Unable to save camera settings!");
}
}
$this->render('settings', array(
'model' => $model,
));
}
This works fine, except in my model I have code like this:
<h1>Settings For: <?php echo CHtml::encode($model->name); ?></h1>
The problem is that, even when the user input fails validation, the h1 tag is having bad input echoed out into it. If the input fails the validation, the h1 attribute should stay the same.
I can 'reset' the $model variable to what is in the database before the view is returned, but this then means I don't get any error feedback / validation failed messages.
Is my only option to have 2 $models ($model and $data perhaps), one used for handling the form and the other for sending data to the page? Or does someone have a more elegant solution?
performAjaxValidation assigns all save attributes to the model so this behavior is normal.
I would reload model if save fails.
$model->refresh();

Categories