The following wiki is to explain how to make use of the TbFileUpload widget from YiiBooster. I have received a couple of requests and I thought was worth writing a wiki for it.
First, we need to make sure we have a folder with write permissions, that will be the place where we are going to save our uploaded files.
I normally create a files folder and I allocate it within my www one, that is where I keep my css, js, images files. So, even though you can place it where ever you wish and for the sake of the example, I will use the files folder name.
I also assume that you have configured a path alias that references the files folder. On this example, the path alias is frontend.www.files.
Thanks Don Felipe
The way you handle validation on the server is up to you, the configuration I am going to provide now is just an example.
We are going to add one extra attribute to the model picture, which is going to hold any $_FILE type resource uploaded and validated when model is on upload scenario.
class MyModel extends CActiveRecord { // ... more code here /** * This is the attribute holding the uploaded picture * @var CUploadedFile */ public $picture; // ... more code /** * @return array validation rules for model attributes. */ public function rules() { return array( // ... more rules here array('picture', 'length', 'max' => 255, 'tooLong' => '{attribute} is too long (max {max} chars).', 'on' => 'upload'), array('picture', 'file', 'types' => 'jpg,jpeg,gif,png', 'maxSize' => 1024 * 1024 * 2, 'tooLarge' => 'Size should be less then 2MB !!!', 'on' => 'upload'), // ... more rules here ); }
To render the widget on your view is quite straightforward, the are a couple of things very important to configure:
Now, lets render it:
$this->widget('bootstrap.widgets.TbFileUpload', array( 'url' => $this->createUrl("my/upload"), 'model' => $model, 'attribute' => 'picture', // see the attribute? 'multiple' => true, 'options' => array( 'maxFileSize' => 2000000, 'acceptFileTypes' => 'js:/(\.|\/)(gif|jpe?g|png)$/i', )));
Everything is ready now but the controller. We have to configure the action that will handle the upload process. Here you go, the upload action of our controller -very, very basic - and not fully tested:
class myController extends CController { // ... more code here /** * Handles resource upload * @throws CHttpException */ public function actionUpload() { header('Vary: Accept'); if (isset($_SERVER['HTTP_ACCEPT']) && (strpos($_SERVER['HTTP_ACCEPT'], 'application/json') !== false)) { header('Content-type: application/json'); } else { header('Content-type: text/plain'); } $data = array(); $model = new MyModel('upload'); $model->picture = CUploadedFile::getInstance($model, 'picture'); if ($model->picture !== null && $model->validate(array('picture'))) { $model->picture->saveAs( Yii::getPathOfAlias('frontend.www.files').'/'.$model->picture->name); $model->file_name = $model->picture->name; // save picture name if( $model->save()) { // return data to the fileuploader $data[] = array( 'name' => $model->picture->name, 'type' => $model->picture->type, 'size' => $model->picture->size, // we need to return the place where our image has been saved 'url' => $model->getImageUrl(), // Should we add a helper method? // we need to provide a thumbnail url to display on the list // after upload. Again, the helper method now getting thumbnail. 'thumbnail_url' => $model->getImageUrl(MyModel::IMG_THUMBNAIL), // we need to include the action that is going to delete the picture // if we want to after loading 'delete_url' => $this->createUrl('my/delete', array('id' => $model->id, 'method' => 'uploader')), 'delete_type' => 'POST'); } else { $data[] = array('error' => 'Unable to save model after saving picture'); } } else { if ($model->hasErrors('picture')) { $data[] = array('error', $model->getErrors('picture')); } else { throw new CHttpException(500, "Could not upload file ". CHtml::errorSummary($model)); } } // JQuery File Upload expects JSON data echo json_encode($data); } // .... more code here } // end of controller
The upload action example was not really tested, if any of you had problems with it, please submit your changes to the YiiBooster Forum Topic. Any help would be highly appreciated to improve this wiki.
Total 7 comments
I got it working what I needed but with some work around.
Hi Don,
Thanks ! I had something wrong with my model, so I used your tips to make it work. Great stuff :)
Hi Don what am trying is that I have a yii extension from class.upload.php upload extension. I have been using it in normal html and has been working fine. But now want to add the ajax function tbfileupload. The following is my code but the problem is what to pass in Upload method $handle = new Upload($model->avatar);. The way I use it is $handle = new Upload($_FILES["avatar"]); for normal way and works file but with tbfileupload things are not same I thing because the data is json. Here is what I have been trying to do.
From the official page it says. How to process a file uploaded via XMLHttpRequest? Use the class as following, the rest being the same as above:
$handle = new upload('php:'.$_SERVER['HTTP_X_FILE_NAME']);
Prefixing the argument with "php:" tells the class to retrieve the uploaded data in php://input, and the rest is the stream's filename, which is generally in $_SERVER['HTTP_X_FILE_NAME'] class.upload.php
The Internal Server Error most likely means there is something wrong with your $model (missing attributes), the database table of the model, or the server side path for the file upload. Please check the following:
1) Make sure the file upload folder exists and the absolute path is set correctly. Ideally the upload folder is under htdocs/ (or Sites/) or even in your webapp-folder (but not inside protected). Then add the absolute path to the config file ./protected/config/main.php
Alternatively you can set 2 aliases in main config:
2) Add the 2 attributes $picture and $file_name to the model class accordingly. In fact, we will not use $file_name in 3). Check if you are using the same $model in the view and controller action.
3) Use the following code block in your controller action. We do this only for a quick test that only consists of the file upload and ignores the database. Be careful when replacing the block
from $model = new MyModel up to } else {
Adjust URL-TO-WEBAPP!
If it still does not work, then you need to use firebug and post the console output here. If it is working, add everything else step by step again.
Last not least, I will re-do this wiki and add more details asap.
Did you get any solution staticblue.
Hi Don,
Thanks for the great tutorial. When I click the upload button, I get an internal server error. Is this something you have encountered before ?
Thanks, Jonathan
There's a closing bracket missing at the end of this line
Then, of course and to avoid any confusion:
Adding the jQuery file upload to YiiBooster is awesome and saves a lot of extra work. Thanks, Antonio.
Leave a comment
Please login to leave your comment.