Yii File Upload Details

Hi,

I have been using Yii for a couple of projects now. The API is very clear in most places, but not about files. I have fundamental doubt.

What does it mean to declare a field as a


file

? The API says it represents only uploaded files. Now if I view the table in question through (say) phpmyadmin, I see only the filename goes into the path.

Here is my table schema

Name Type Collation Attributes Null Default Extra

 1	ID	int(11)			No	None	AUTO_INCREMENT	 


 2	productID	int(11)			No	None		  


 3	path	text	utf8_unicode_ci		No	None		  

here is my model code




	public function rules() {

		return array(

			array('productID, path', 'required'),

			array('productID', 'numerical', 'integerOnly'=>true),

			array('productID', 'safe', 'on'=>'search'),

			array('path','file','types'=>'jpg, gif, png','allowEmpty'=>false),

		);

	}



So even though the table stores text, the file object holds more (more on this next post). I can’t save the object properly if I manually assign the file name like :




$image = CUploadedFile::getInstance($model,'ProductPhoto');

$this->path=$image->name;



I must assign it like :




$image = CUploadedFile::getInstance($model,'ProductPhoto');

$this->path=$image;



even though phpMyAdmin reports :

ID | productID | path

1 | 2 | Hydrangeas.jpg

Can someone throw more light on this please?

Milind

you want to save the file full path to the database path field?!

Well I am not even sure what a file attribute IS, exactly. Is it the path, or is it the file object itself? Because the file validator represents only uploaded files, its can only be used when I am writing into it. When I retrieve it, it anyway isn’t any thing more than a file name.

Which is why I am confused about the purpose, and the usage.

CUploadedFiles will help you handle uploaded files (the $_FILES)

so here is a working example




//get instance

$image = CUploadedFile::getInstance ($model, 'ProductPhoto');


//now let's save the temp file into a final folder

$image->saveAs('/path/to/final/folder/filename.jpg');


// since we already know the full file path lets add it to our model image field

$ourModel->imageField = '/path/to/final/folder/filename.jpg';


....


$model->save();



if you don’t invoke the saveAs(). you’ll let the file on your php tmp folder with a tempName. (and you probably don’t want that. :)

give a peek on /path/to/your/yii/framework/web/CUploadedFile.php and u’ll understand it very well.

Thanks for your reply.

So I can assign a full path to my file attribute and it will validate? I will try it out in just a little while.

Meanwhile, I would like to work with files that are already present on the server. In my case, I uploaded a ZIP archive and unzipped it to a temp folder. Then I run through all of them and assign them to different


ProductPhoto

s. So do I have to remove the file validator here?

Sorry for the mess, the question is too jumbled up, I can’t separate them out by myself, hope someone can help :)

In this case, yes. You can assign a full path to your file attribute (path) cos you have it like text in your DB.

I don’t really understand what you want to do (last question).

for what i understand you already have your product table populated with production data but have no image path yet, is that correct?

If so and if you have lets say 10 records why don’t you open phpmyadmin and do that by hand? if you have lets say > 100 records. then i would suggest to create a php console script to do that for you.

maybe move image files to final folder, assign them a unique name that will identify them with a single and specific record and run the script.

How else can I store a file in the DB apart from storing file separately and putting the path in the DB table?

And nope no luck. It won’t accept me assigning just a name, with a file validator. It says “Path cannot be blank”. It wants the CUploadedFile instance.

What I want to do is to process the step after this:

into individual records. I directly upload them in a zip file with unique identifiable names.

For reference, here is the code that does this, though may not contain much additional info :

ProductController.php




    public function actionBulkUpload() {

	if(isset($_FILES['allphotos'])) {

	    $logfile = fopen("bulk.log","w");


	    $zipfile = CUploadedFile::getInstanceByName('allphotos');

	    $zipper = new ZipArchive();

	    $res = $zipper->open($zipfile->tempName);

	    if ($res == true) {

		fputs($logfile,"Zip file opened.\n");


		$path = $_SERVER['DOCUMENT_ROOT'] . '../' . 'tempDir/';

		if(!is_dir($path))

		    mkdir($path, 0755);

		$zipper->extractTo($path);

		fputs($logfile,"Zip file extracted.\n");


		$files = scandir($path);

		

		

		foreach ($files as $i => $file) {

		    if ($file !== '.' && $file !== '..') {

			$filepath = $path . '/' . $file;

			$fileinfo = pathinfo($filepath);

			$ext = $fileinfo['extension'];

			$extsall = array('jpg', 'jpeg', 'gif', 'png');

			if (in_array($ext, $extsall)) {

			    $names = explode('_', $file);

			    $prodid = $names[0];

			    $prodidd = intval($prodid);

			    if (strval($prodidd) == $prodid) {

				$prod = Product::model()->findByPk($prodidd);

				$fna = $names[1];

				$prod->addFSImageFile($filepath,$fna);

				fputs($logfile,"\t$file added to Product ID $prodidd\n");

			    }

			    else

				fputs($logfile,"\t\t$file 's first part is not a pure number\n");

			}

			else

			    fputs($logfile,"\t\t$file does not have a permitted extension\n");

		    }

		    

		}

		fputs($logfile,"All files are done being copied\n");


	    }

	    else

		fputs($logfile,"Archive could not be extracted\n");

	    fclose($logfile);

	    

	}

	

	$this->render('bulkupload',array('log' => @file_get_contents("bulk.log")));

	@unlink("bulk.log");

    }




ProductPhoto.php (model)




	public function rules() {

		return array(

			array('productID, path', 'required'),

			array('productID', 'numerical', 'integerOnly'=>true),

			array('productID', 'safe', 'on'=>'search'),

			array('path','file','types'=>'jpg, gif, png','allowEmpty'=>false),

		);

	}




Product.php (model)





    public function addFSImageFile($path,$fna) {

	$res = rename($path, $this->imagePathDir.$fna);

	if ($res) {

	    $img->path = /*$this->imagePathDir.*/$fna;

	    $img = new ProductPhoto;

	    $img->productID = $this->ID;

	    if(!$img->validate())

		print_r($img->errors);

	    $img->save();

	}

    }