The Model ¶
First declare an attribute to store the file name in the model class (either a form model or an active record model).
Also declare a file
validation rule for this attribute to ensure a file is uploaded with specific extension name.
class Item extends CActiveRecord
{
public $image;
// ... other attributes
public function rules()
{
return array(
array('image', 'file', 'types'=>'jpg, gif, png', 'safe' => false),
);
}
}
You can add others validation parameters as described in [CFileValidator]. For instance, one can add a "maxSize" restriction (the PHP ini settings will of course prevail).
The Controller ¶
Then, in the controller class define an action method to render the form and collect user-submitted data.
class ItemController extends CController
{
public function actionCreate()
{
$model=new Item;
if(isset($_POST['Item']))
{
$model->attributes=$_POST['Item'];
$model->image=CUploadedFile::getInstance($model,'image');
if($model->save())
{
$model->image->saveAs('path/to/localFile');
// redirect to success page
}
}
$this->render('create', array('model'=>$model));
}
}
[CUploadedFile::saveAs()] in one of the methods of [CUploadedFile]. You can also access directly to the file through its "tempName" property.
The View ¶
Finally, create the action view and generate a file upload field.
$form = $this->beginWidget(
'CActiveForm',
array(
'id' => 'upload-form',
'enableAjaxValidation' => false,
'htmlOptions' => array('enctype' => 'multipart/form-data'),
)
);
// ...
echo $form->labelEx($model, 'image');
echo $form->fileField($model, 'image');
echo $form->error($model, 'image');
// ...
echo CHtml::submitButton('Submit');
$this->endWidget();
Another syntax is to use static calls in [CHtml] instead of [CActiveForm]. The result is the same as above.
<?php echo CHtml::form('','post',array('enctype'=>'multipart/form-data')); ?>
...
<?php echo CHtml::activeFileField($model, 'image'); ?>
...
<?php echo CHtml::submitButton('Submit'); ?>
<?php echo CHtml::endForm(); ?>
File Handling Validation
Remember to check your CUploadFile, if null don't do saveAs or you will get an error
Here is sample of my code
public function actionCreate() { $this->layout = '//layouts/column1'; $this->pageTitle = 'Create post for '.$this->pageTitle; $model = new Article; // Uncomment the following line if AJAX validation is needed // $this->performAjaxValidation($model); if (isset($_POST['Article'])) { $model->attributes = $_POST['Article']; $model->created = date('Y:m:d H:i:s'); $model->group = $this->articleGroup; $model->fk_user_id = Yii::app()->user->id; // file handling $imageUploadFile = CUploadedFile::getInstance($model, 'image'); if($imageUploadFile !== null){ // only do if file is really uploaded $imageFileName = mktime().$imageUploadFile->name; $model->image = $imageFileName; } $voiceUploadFile = CUploadedFile::getInstance($model, 'voice_note'); if($voiceUploadFile !== null) { $voiceFileName = mktime().$voiceUploadFile->name; $model->voice_note = $voiceFileName; } if ($model->save()){ if($imageUploadFile !== null) // validate to save file $imageUploadFile->saveAs(Article::FOLDER_IMAGE.$imageFileName); if($voiceUploadFile !== null) $voiceUploadFile->saveAs(Article::FOLDER_VOICE.$voiceFileName); $this->redirect(array('view', 'id' => $model->id)); } } $this->render('//article/create', array( 'model' => $model, )); }
Validation (Response at @outrage )
I had the same problem, after investigation I have solved that way :
... $model->attributes=$_POST['MyForm']; $model->filename=CUploadedFile::getInstance($model,'filename'); if ($model->validate()){ $model->image->saveAs('path/to/localFile');
I think if your model is not an instance of CActiveRecord, then you wont be able to do the
if($model->save())
and I believe the validation step is made there. So you have to explicitly test the validation.
Add attribute 'safe'=>true to rules()
You need to add the 'safe'=>true property to array('image', 'file', 'types'=>'xxxx', 'safe'=>true), or you'll get "Failed to set unsafe attribute 'image' ":
http://www.yiiframework.com/forum/index.php/topic/26456-failed-to-set-unsafe-attribute-file/
$model->image = null
Tip: My $model->image stayed null, until I changed my json submit (with ($form).serialize()) back to a normal submit.
Also check that you have 'htmlOptions' => array('enctype' => 'multipart/form-data'), when you declare the active form - otherwise $image will stay null.
Re: How to validate a local file (removed question)
File Validation cannot be used before file uploaded on the server.
Instead of that, you could make javascript validation.
See the relative wiki
http://www.yiiframework.com/wiki/598/clientvalidation-for-files-modern-browsers/
My code is not uploading the file
Please Help! It's not working for me, after submitting the form nothing happened, here's my printscreen:
This is my action rule:
public function rules() { return array( //... array('filename', 'file', 'types'=>'jpg, gif, png, pdf'), //... ); }
Here's my controller:
public function actionCreate() { $model=new Image; if(isset($_POST['Image'])) { $model->attributes=$_POST['Image']; $tempSave=CUploadedFile::getInstance($model, 'filename'); if($model->save()) $tempSave->saveAs(Yii::app()->basePath . '/../productimages/' . $model->id.'.jpg'); $this->redirect(array('view','id'=>$model->id)); } $this->render('create',array('model'=>$model)); }
And for the view (_form.php) I have this:
<?php $form = $this->beginWidget( 'CActiveForm', array( 'id' => 'upload-form', 'enableAjaxValidation' => false, 'htmlOptions' => array('enctype' => 'multipart/form-data'), ) ); ?> <div class="row"> <?php echo $form->labelEx($model,'title'); ?> <?php echo $form->textField($model,'title',array( 'size'=>45, 'maxlength'=>45 )); ?> <?php echo $form->error($model,'title'); ?> </div> <div class="row"> <?php echo $form->labelEx($model,'filename'); ?> <?php echo $form->fileField($model,'filename',array( 'size'=>45, 'maxlength'=>45 )); ?> <?php echo $form->error($model,'filename'); ?> </div> <div class="row buttons"> <?php //echo CHtml::submitButton('Submit'); ?> <?php echo CHtml::submitButton($model->isNewRecord ? 'Upload' : 'Save'); ?> </div> <?php $this->endWidget(); ?><!--CActiveForm widget-->
PHP upload_max_filesize and post_max_size
If you are experiencing a situation where "nothing happens" after upload, depending on your settings, it is possible that PHP is killing it. Check the filesize you are trying to upload and make sure it is less than the value of upload_max_filesize in you php.ini. You can check that value on your PHP Info as well - whatever is easier. If that is your problem, assuming you have access to make changes to the php.ini file, just increase that value to what you need or want.
Depending on how big the file is, you may also need to increase the post_max_size value. PHP errors about this stuff should be in the apache error log, but will not generally show up in the Yii application log.
Hope this helps someone.
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.