[SOLVED !!] Upload file to database

Grrr… I can’t make it work. Following Wiki example, trying to save a Photo attribute of the model Samples:


	<div class="row">

		<?php echo $form->labelEx($model,'Photo'); ?>

		

		<?php echo $form->fileField($model, 'Photo'); ?>

		<?php echo $form->error($model,'Photo'); ?>

	</div>






	

class Samples extends CActiveRecord

{

       public function rules()

	{

		// NOTE: you should only define rules for those attributes that

		// will receive user inputs.

          array('Photo,PhotoFilename', 'file', 'types'=>'jpg'),

        }




This beforeSave() is in the Model (which is called Samples in my app) I think? Or should it be in the Controller?


	public function beforeSave()

	{

		if($file=CUploadedFile::getInstance($this,'Photo'))


		$this->file_name=$file->name;

		$this->file_type=$file->type;

		$this->file_size=$file->size;

		$this->file_content=file_get_contents($file->tempName);

	

	

	

		

		

		}

in the COntroller:


	public function actionCreate()

	{

		$model=new Samples;


		// Uncomment the following line if AJAX validation is needed

		$this->performAjaxValidation($model);

	

		if(isset($_POST['Samples']))

		{

			

			$model->attributes=$_POST['Samples'];

			$model->Photo = CUploadedFile::getInstance($model, 'Photo');

			$model->PhotoFilename = CUploadedFile::getInstance($model, 'PhotoFilename');

			

			if($model->save())

				{

				

				mkdir('uploadedfiles/SampleID_' . strval($model->SampleID));

				$model->Photo->saveAs('uploadedfiles/SampleID_' . strval($model->SampleID) . '/' . $model->Photo);

				$model->PhotoFilename->saveAs('uploadedfiles/sampleID_' . strval($model->SampleID) . '/' . $model->PhotoFilename);


				$this->redirect(array('id'=>$model->SampleID));

				

				}

				

		}

All I’m getting is “Property “Samples.file_name” is not defined.” I can upload a Photo onto server OK (by omitting the beforeSave code), but not blobbing into a table ( putting in the beforeSave code)… I’ve tried “$this->Photo_name=$file->name;” too. There must be something I’m not getting.

I am truly puzzled. Sorry if the example is supposed to be clear… :(

I have been looking for information on uploading a file and this thread seems to come the closest to what I want to do. However quit often replies (here or in Wiki) seem to assume certain knowledge levels that us newbies don’t have yet :( This is not a criticism, just an observation. Although I try not to, I do it to sometimes when replying to posts on here. With that in mind, could those of you who answered in this thread correct me if I am wrong?

Given a SQLite3 database table:




CREATE TABLE [tbl_podcasts] ( 

   [ID]             INTEGER        PRIMARY KEY AUTOINCREMENT

                                   NOT NULL,

   [file_name]      VARCHAR( 48 )  NOT NULL,

   [file_type]      VARCHAR( 32 )  NOT NULL,

   [file_size]      INTEGER        NOT NULL DEFAULT ( 0 ),

);



In the Podcasts model:




class Podcasts extends CActiveRecord

{

    /**

     * Property for receiving the file from the form

     * It should be different from any other field in the database

     */

    public $uploadedFile;

    private $_audioFile=null;   //used to pass CUploadedFile() to afterSave() 


    public function rules()

    {

        return array(

            array('uploadedFile', 'file', 'types'=>'mp3, wav'),

        );


    public function getAttributeLabel(...)

    {

       ...

       'uploadedFile'=>'What file?',      // <-- Do I need to add this?

       ...

    }

  /**

    * Saves the name, size, type and data of the uploaded file

    */

    public function beforeSave()

    {

        if($_file=CUploadedFile::getInstance($this,'uploadedFile'))

        {

            $this->file_name=$_file->name;

            $this->file_type=$_file->type;

            $this->file_size=$_file->size;

            //Save the contents to database blob OR use afterSave() to save 

            // to filesystem.

            $this->file_content=file_get_contents($_file->tempName);

        }

        return parent::beforeSave();

    }

  /**

    * Saves the uploaded file to file if wanted

    */

    public function afterSave()

    {

        if($_file!==null)

        {

            $_file->saveAs(...);

        }

        return parent::afterSave();

    }

}

and the form/view would be:




<?php echo CHtml::form('','post',array('enctype'=>'multipart/form-data')); ?>

...

<div class="row">

<?php echo $form->labelEx($model,'uploadedFile'); ?>

<?php echo $form->fileField($model,'uploadedFile'); ?>

<?php echo $form->error($model,'uploadedFile'); ?>

</div>

...

<?php echo CHtml::endForm(); ?>



The above is a translation of what I understand from the various posting in this thread.

It looks like I need a separate/temp field name for the actual file upload from the db field name.

If saving to the filesystem, would it be MVC correct to it in the afterSave() of the model?

If I want to display the db file_name on the update form as an indicator of a file is already assigns, How? I think it would just be a $form->???label().

Does any of this make sense? Thanks in advanced.

This works fine, however it doesn’t display the “incorrect file type” error message.

I have been fighting with it for a while now :huh:

Nevermind, I figured it out.

Apparently if you try and upload a file that is larger than your upload_max_filesize (as set in php.ini) then the file validator will not return ANY error messages.

I also ran into this problem. I changed the upload_max_filesize but was still not getting any thing. Then I found that the max_postsize (or something like that) also had to be increased. Then all worked. Just a heads up to check both.

Hi,

I’ve followed your Wiki example, however now I am getting an error ‘Uploaded File cannot be blank.’

1896

Chitter - Create AbstractImageDev.jpg

I’m really unsure as to why this is occurring; my model and view are near exact to yours - have you made any changes to the controller?

Many thanks in advance,

krslynx

hi guy,

what i need to write inside controller site if i wan save into database.

[color="#FF0000"]view site[/color]

<div class="row">

<?php echo $form->labelEx($model,‘uploadedFile’); ?>

<?php echo $form->fileField($model,‘uploadedFile’); ?>

<?php echo $form->error($model,‘uploadedFile’); ?>

</div>

[color="#FF0000"]Model Site[/color]

class Candidate extends CActiveRecord

{

/* PROPERTY FOR RECEIVING THE FILE FROM FORM*/

public $uploadedFile;

/* MUST BE THE SAME AS FORM INPUT FIELD NAME*/

/**

*saves the name, size ,type and data of the uploaded file

*/

public function beforeSave()

{

if($file=CUploadedFile::getInstance($this,‘uploadedFile’))

{

$this->cv_file_name=$file->name;

$this->cv_file_type=$file->type;

$this->cv_file_size=$file->size;

$this->cv_file_content=file_get_contents($file->tempName);

}

return parent::beforeSave();;

}

pls help… i find the wiki is save the image to file folder and to show saved image only.

You’ll need to create a Database schema that holds information in BLOB type - this will be where the content is stored. I’ve attached my Model, Controller and View so you can compare the code etcetera and figure things out …

The SQL:




CREATE TABLE `tbl_abstract_img` (

  `id` int(11) NOT NULL AUTO_INCREMENT,

  `chit_id` int(11) DEFAULT NULL,

  `create_time` datetime DEFAULT NULL,

  `create_user_id` int(11) DEFAULT NULL,

  `update_time` datetime DEFAULT NULL,

  `update_user_id` int(11) DEFAULT NULL,

  `file_name` varchar(128) DEFAULT NULL,

  `file_type` varchar(128) DEFAULT NULL,

  `file_size` int(11) DEFAULT NULL,

  `file_content` blob,

  PRIMARY KEY (`id`),

  UNIQUE KEY `id` (`id`),

  KEY `FK_abstract_img_chit` (`chit_id`),

  KEY `FK_abstract_img_author` (`create_user_id`),

  CONSTRAINT `FK_abstract_img_author` FOREIGN KEY (`create_user_id`) REFERENCES `tbl_user` (`id`),

  CONSTRAINT `FK_abstract_img_chit` FOREIGN KEY (`chit_id`) REFERENCES `tbl_chit` (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=latin1 |



The View:


 

<div class="form">


<?php $form=$this->beginWidget('CActiveForm', array(

	'id'=>'abstract-image-form',

	'enableAjaxValidation'=>false,

        'htmlOptions'=>array(

            'enctype' => 'multipart/form-data',

        )

)); ?>


	<p class="note">Fields with <span class="required">*</span> are required.</p>


	<?php echo $form->errorSummary($model); ?>


        <div class="row">

            <?php echo $form->labelEx($model,'uploadedFile'); ?>

            <?php echo $form->fileField($model,'uploadedFile'); ?>

            <?php echo $form->error($model,'uploadedFile'); ?>

        </div>

        

	<div class="row buttons">

		<?php echo CHtml::submitButton($model->isNewRecord ? 'Create' : 'Save'); ?>

	</div>


<?php $this->endWidget(); ?>


</div><!-- form -->




The Model:




class AbstractImage extends CActiveRecord

{

    

        public $uploadedFile;

    

	/**

	 * Returns the static model of the specified AR class.

	 * @return AbstractImage the static model class

	 */

	public static function model($className=__CLASS__)

	{

		return parent::model($className);

	}


	/**

	 * @return string the associated database table name

	 */

	public function tableName()

	{

		return 'tbl_abstract_img';

	}


	/**

	 * @return array validation rules for model attributes.

	 */

	public function rules()

	{

		// NOTE: you should only define rules for those attributes that

		// will receive user inputs.

		return array(

			//array('chit_id, create_user_id, update_user_id, file_size', 'numerical', 'integerOnly'=>true),

			//array('file_name, file_type', 'length', 'max'=>128),

			//array('create_time, update_time, file_content', 'safe'),

			// The following rule is used by search().

			// Please remove those attributes that should not be searched.

			//array('id, chit_id, create_time, create_user_id, update_time, update_user_id, file_name, file_type, file_size, file_content', 'safe', 'on'=>'search'),

                        array('uploadedFile', 'file', 'allowEmpty'=>false, 'on' => 'insert'),

                        array('uploadedFile', 'file', 'allowEmpty'=>true, 'on' => 'update'),                    

                );

	}


	/**

	 * @return array relational rules.

	 */

	public function relations()

	{

		// NOTE: you may need to adjust the relation name and the related

		// class name for the relations automatically generated below.

		return array(

                    'createUser' => array(self::BELONGS_TO, 'User', 'create_user_id'),

                    'chit' => array(self::BELONGS_TO, 'Chit', 'chit_id'),

                    'author' => array(self::BELONGS_TO, 'User', 'create_user_id'),

		);

	}


	/**

	 * @return array customized attribute labels (name=>label)

	 */

	public function attributeLabels()

	{

		return array(

			'id' => 'ID',

			'chit_id' => 'Chit',

			'create_time' => 'Create Time',

			'create_user_id' => 'Create User',

			'update_time' => 'Update Time',

			'update_user_id' => 'Update User',

			'file_name' => 'File Name',

			'file_type' => 'File Type',

			'file_size' => 'File Size',

			'file_content' => 'File Content',

		);

	}


	/**

	 * Retrieves a list of models based on the current search/filter conditions.

	 * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.

	 */

	public function search()

	{

		// Warning: Please modify the following code to remove attributes that

		// should not be searched.


		$criteria=new CDbCriteria;


		$criteria->compare('id',$this->id);

		$criteria->compare('chit_id',$this->chit_id);

		$criteria->compare('create_time',$this->create_time,true);

		$criteria->compare('create_user_id',$this->create_user_id);

		$criteria->compare('update_time',$this->update_time,true);

		$criteria->compare('update_user_id',$this->update_user_id);

		$criteria->compare('file_name',$this->file_name,true);

		$criteria->compare('file_type',$this->file_type,true);

		$criteria->compare('file_size',$this->file_size);

		$criteria->compare('file_content',$this->file_content,true);


		return new CActiveDataProvider($this, array(

			'criteria'=>$criteria,

		));

	}

        

        public function beforeSave()

        {

            $file=CUploadedFile::getInstance($this,'uploadedFile');

                if($file)

                {

                        $this->file_name=$file->name;

                        $this->file_type=$file->type;

                        $this->file_size=$file->size;

                        $this->file_content=file_get_contents($file->tempName);

                }

                

                if(!empty ($this->create_user_id)) {

                        $this->update_user_id=Yii::app()->user->id;

                        $this->update_time=date('Y-m-d H:i:s');

                }

                

                if(empty($this->create_user_id)) {

                        $this->create_user_id=Yii::app()->user->id;

                        $this->create_time=date('Y-m-d H:i:s');

                }

         

                

        return parent::beforeSave();

        }

}




The Controller:




<?php


class AbstractImageController extends Controller

{

	/**

	 * @var string the default layout for the views. Defaults to '//layouts/column2', meaning

	 * using two-column layout. See 'protected/views/layouts/column2.php'.

	 */

	public $layout='//layouts/column2';


	/**

	 * @return array action filters

	 */

	public function filters()

	{

		return array(

			'accessControl', // perform access control for CRUD operations

		);

	}


	/**

	 * Specifies the access control rules.

	 * This method is used by the 'accessControl' filter.

	 * @return array access control rules

	 */

	public function accessRules()

	{

		return array(

			array('allow',  // allow all users to perform 'index' and 'view' actions

				'actions'=>array('index','view','displaysavedimage'),

				'users'=>array('*'),

			),

			array('allow', // allow authenticated user to perform 'create' and 'update' actions

				'actions'=>array('create','update'),

				'users'=>array('@'),

			),

			array('allow', // allow admin user to perform 'admin' and 'delete' actions

				'actions'=>array('admin','delete'),

				'users'=>array('admin'),

			),

			array('deny',  // deny all users

				'users'=>array('*'),

			),

		);

	}


	/**

	 * Displays a particular model.

	 * @param integer $id the ID of the model to be displayed

	 */

	public function actionView($id)

	{

		$this->render('view',array(

			'model'=>$this->loadModel($id),

		));

	}


	/**

	 * Creates a new model.

	 * If creation is successful, the browser will be redirected to the 'view' page.

	 */

	public function actionCreate()

	{

		$model=new AbstractImage;


		// Uncomment the following line if AJAX validation is needed

		// $this->performAjaxValidation($model);


		if(isset($_POST['AbstractImage']))

		{

			$model->attributes=$_POST['AbstractImage'];

			if($model->save())

				$this->redirect(array('view','id'=>$model->id));

		}


		$this->render('create',array(

			'model'=>$model,

		));

	}


	/**

	 * Updates a particular model.

	 * If update is successful, the browser will be redirected to the 'view' page.

	 * @param integer $id the ID of the model to be updated

	 */

	public function actionUpdate($id)

	{

		$model=$this->loadModel($id);


		// Uncomment the following line if AJAX validation is needed

		// $this->performAjaxValidation($model);


		if(isset($_POST['AbstractImage']))

		{

			$model->attributes=$_POST['AbstractImage'];

			if($model->save())

				$this->redirect(array('view','id'=>$model->id));

		}


		$this->render('update',array(

			'model'=>$model,

		));

	}


	/**

	 * Deletes a particular model.

	 * If deletion is successful, the browser will be redirected to the 'admin' page.

	 * @param integer $id the ID of the model to be deleted

	 */

	public function actionDelete($id)

	{

		if(Yii::app()->request->isPostRequest)

		{

			// we only allow deletion via POST request

			$this->loadModel($id)->delete();


			// if AJAX request (triggered by deletion via admin grid view), we should not redirect the browser

			if(!isset($_GET['ajax']))

				$this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('admin'));

		}

		else

			throw new CHttpException(400,'Invalid request. Please do not repeat this request again.');

	}


	/**

	 * Lists all models.

	 */

	public function actionIndex()

	{

		$dataProvider=new CActiveDataProvider('AbstractImage');

		$this->render('index',array(

			'dataProvider'=>$dataProvider,

		));

	}


	/**

	 * Manages all models.

	 */

	public function actionAdmin()

	{

		$model=new AbstractImage('search');

		$model->unsetAttributes();  // clear any default values

		if(isset($_GET['AbstractImage']))

			$model->attributes=$_GET['AbstractImage'];


		$this->render('admin',array(

			'model'=>$model,

		));

	}


	/**

	 * Returns the data model based on the primary key given in the GET variable.

	 * If the data model is not found, an HTTP exception will be raised.

	 * @param integer the ID of the model to be loaded

	 */

	public function loadModel($id)

	{

		$model=AbstractImage::model()->findByPk($id);

		if($model===null)

			throw new CHttpException(404,'The requested page does not exist.');

		return $model;

	}


	/**

	 * Performs the AJAX validation.

	 * @param CModel the model to be validated

	 */

	protected function performAjaxValidation($model)

	{

		if(isset($_POST['ajax']) && $_POST['ajax']==='abstract-image-form')

		{

			echo CActiveForm::validate($model);

			Yii::app()->end();

		}

	}

        

        public function actionDisplaySavedImage()

        {

            $model=$this->loadModel($_GET['id']);


            header('Pragma: public');

            header('Expires: 0');

            header('Cache-Control: must-revalidate, post-check=0, pre-check=0');

            header('Content-Transfer-Encoding: binary');

            header('Content-length: '.$model->file_size);

            header('Content-Type: '.$model->file_type);

            header('Content-Disposition: attachment; filename='.$model->file_name);


                echo $model->file_content;

        }

}




I hope this helps.

Hi!,

What is the size of the uploaded file?

Try to remove


'allowEmpty'=>false

I had the same issue, but solved using beforeSave() method:

Model




Class myModel extends CActiveRecord

{

     public $uploadedFile;

     ...

     public function rules()

     {

          ...

          return array(

              ...

              array('uploadedFile','file'); //Note: not allowEmpty condition

          );

    }

    ...

    public function beforeSave()

    {

        if($_file=CUploadedFile::getInstance($this,'uploadedFile'))

        {

            $this->file_name=$_file->name;

            $this->file_type=$_file->type;

            $this->file_size=$_file->size;

            $this->file_content=file_get_contents($_file->tempName);

        }

        return parent::beforeSave();

    }


}



Controller




class myController extends Controller

{

    ...

    public function actionMyAction()

    {

        $model=new myModel;

        ...

        if($model->validate())

        {

            ...

            $model->save();

            ...

        }

        ...

    }

    ...

}



hi,

i already remove my post cos not really related to it, change blob to mediumblob. blob only allow file <=60kb.

thank.

I followed the way you did. But when i try to upload it says that the file field cannot be blanked.I have included my model and view contents here.

this is the View

<div class="form">

&#036;model=new Mytbl;

<?php $form=$this->beginWidget(‘CActiveForm’, array(

'id'=&gt;'mytbl-form',


'enableAjaxValidation'=&gt;false,

)); ?>

&lt;p class=&quot;note&quot;&gt;Fields with &lt;span class=&quot;required&quot;&gt;*&lt;/span&gt; are required.&lt;/p&gt;





&lt;?php echo &#036;form-&gt;errorSummary(&#036;model); ?&gt;





&lt;div class=&quot;row&quot;&gt;


	&lt;?php echo &#036;form-&gt;labelEx(&#036;model,'preview'); ?&gt;


	&lt;?php echo &#036;form-&gt;fileField(&#036;model,'preview'); ?&gt;


	&lt;?php echo &#036;form-&gt;error(&#036;model,'preview'); ?&gt;


&lt;/div&gt;





&lt;div class=&quot;row buttons&quot;&gt;


	&lt;?php echo CHtml::submitButton(&#036;model-&gt;isNewRecord ? 'Create' : 'Save'); ?&gt;


&lt;/div&gt;

<?php $this->endWidget(); ?>

</div><!-- form -->

My Model

<?php

class Mytbl extends CActiveRecord {

public &#036;preview;





public static function model(&#036;className = __CLASS__) {


    return parent::model(&#036;className);


}





public function tableName() {


    return 'mytbl';


}





public function rules() {


    return array(


        array('preview', 'file', 'types' =&gt; 'png,jpg,gif'),


        array('id, image', 'safe', 'on' =&gt; 'search'),


    );


}





public function beforeSave() {


    &#036;file = CUploadedFile::getInstance(&#036;this, 'preview');


    if (&#33;&#036;file-&gt;getHasError()) {





        &#036;this-&gt;image = file_get_contents(&#036;file-&gt;tempName);


    }





    return parent::beforeSave();


    ;


}





public function relations() {


    return array(


    );


}





public function attributeLabels() {


    return array(


        'id' =&gt; 'ID',


        'image' =&gt; 'Image',


    );


}





public function search() {


    &#036;criteria = new CDbCriteria;





    &#036;criteria-&gt;compare('id', &#036;this-&gt;id);


    &#036;criteria-&gt;compare('image', &#036;this-&gt;image, true);





    return new CActiveDataProvider(&#036;this, array(


        'criteria' =&gt; &#036;criteria,


    ));


}

}