Problema Sull'upload Di Una Immagine

Ciao a tutti.

Ho da poco iniziato ad utilizzare Yii e, dopo aver dato un’occhiata all’applicazione Trackstar che viene sviluppata sulla guida, mi stavo cimentando con l’upload delle immagini.

In sostanza ho tabella lingua(ID, nome, codice, bandiera) sul DB (con una entry ad esempio lingua(1, italiano, ITA, ita.png) e vorrei effettuare l’upload e/o sostituire l’immagine della bandiera. Queste due funzionalità a quanto ho capito sono implementate rispettivamente nei metodi actionCreate() ed actionUpdate() del controller. Ho però un problema nella fase di update, sostanzialmente devo cliccare due volte sul tasto save() per effettuare correttamente l’upload della bandiera. Ho notato che il path nella barra degli indirizzi del browser non cambia come dovrebbe, (ovvero si sistema quando clicco la seconda volta su tasto save) e quindi vorrei avere una dritta su come risolvere questo problema.

Seguendo gli svariati suggerimenti presenti su questo forum sono riuscito a realizzare quanto segue:

Model:




	public function rules()

	{

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

		// will receive user inputs.

		return array(

			array('nome, codice, bandiera', 'required'),

			array('nome','length', 'max'=>255, 'on'=>'insert, update'),

			array('codice','length', 'max'=>3, 'on'=>'insert, update'),

			array('bandiera', 'file', 'types' => 'jpg, gif, png', 'allowEmpty'=>false, 'on'=>'insert'),

			array('bandiera', 'file', 'types' => 'jpg, gif, png', 'allowEmpty'=>true, 'on'=>'update'),


			array('nome, codice', 'safe', 'on'=>'search'),

		);

	}



Controller:




	public function actionUpdate($id)

	{

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

		//salvo il nome del file già caricato

		$oldFile = $model->bandiera;			

		// Uncomment the following line if AJAX validation is needed

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


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

		{

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

			

			$newFile = CUploadedFile::getInstance($model,'bandiera');


			//Controllo se bisogna salvare un nuovo file

			if(is_object($newFile) && get_class($newFile)==='CUploadedFile' && isset($newFile))

				$model->bandiera = $newFile;

			else

				$model->bandiera = $oldFile;

				

			if($model->save()) {				

				/*************************************/

				if (is_object($newFile) && get_class($newFile)==='CUploadedFile' && isset($newFile)) {				

					$percorso = Yii::app()->basePath."/../uploads/images/foto_bandiera/".$model->id."/".$newFile;

					$percorsoThumb = Yii::app()->basePath."/../uploads/images/foto_bandiera/thumb/".$model->id."/".$newFile;

					$percorsoBig = Yii::app()->basePath."/../uploads/images/foto_bandiera/big/".$model->id."/".$newFile;

					

					$cartella = Yii::app()->basePath."/../uploads/images/foto_bandiera/".$model->id;

					$cartellaThumb = Yii::app()->basePath."/../uploads/images/foto_bandiera/thumb/".$model->id;

					$cartellaBig = Yii::app()->basePath."/../uploads/images/foto_bandiera/big/".$model->id;

						

					if (!is_dir($cartella)) {

						if (!mkdir($cartella, 0777, true)) {

							error_log('Failed to create base folder...');

						}

					}

					if (!is_dir($cartellaThumb)) {

						if (!mkdir($cartellaThumb, 0777, true)) {

							error_log('Failed to create thumb folder...');

						}

					}

					if (!is_dir($cartellaBig)){

						if (!mkdir($cartellaBig, 0777, true)) {

							error_log('Failed to create big folder...');

						}

					}

					

					$model->bandiera->saveAs($percorso);


					if ($oldFile != $model->bandiera) {

						$oldPercorso = getcwd().'/uploads/images/foto_bandiera/'.$model->id.'/'.$oldFile;

						$oldPercorsoThumb = getcwd().'/uploads/images/foto_bandiera/thumb/'.$model->id.'/'.$oldFile;

						$oldPercorsoBig = getcwd().'/uploads/images/foto_bandiera/big/'.$model->id.'/'.$oldFile;

					

						unlink($oldPercorso);

						unlink($oldPercorsoBig);

						unlink($oldPercorsoThumb);

					}

					

					$imageTemp = new Imagick($percorso);

					$imageTempProps = $imageTemp->getimagegeometry();

					

					if($imageTempProps['width']<=1000 && $imageTempProps['height']<=1000) {

						//non scalare

					} else $imageTemp->resizeimage(1000, 1000, Imagick::FILTER_LANCZOS, 0.9, true);

					$imageTemp->writeimage($percorsoBig);

					

					if($imageTempProps['width']<=600 && $imageTempProps['height']<=600) {

						//non scalare

					} else $imageTemp->resizeimage(600, 600, Imagick::FILTER_LANCZOS, 0.9, true);

					$imageTemp->writeimage($percorso);

					

					if($imageTempProps['width']<=200 && $imageTempProps['height']<=200) {

						//non scalare

					} else $imageTemp->resizeimage(200, 200, Imagick::FILTER_LANCZOS, 0.9, true);

					$imageTemp->writeimage($percorsoThumb);					

				}

				/*******************************/

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

			}

		}

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

				'model'=>$model,

		));

	}



View:




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

	'id'=>'lingua-form',

	'enableAjaxValidation'=>false,

	'htmlOptions' => array('enctype' => 'multipart/form-data'),

)); ?>

	<div class="row">

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

		<?php echo CHtml::activeFileField($model, 'bandiera'); ?>

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

	</div>



Facendo una piccola modifica, ovvero eliminando il blocco if relativo alla cancellazione della vecchia bandiera, funziona tutto correttamente ma rimangono salvate entrambe le bandiere nel filesystem. vorrei poter eliminare la vecchia bandiera e salvare la nuova. Nonostante tutto mi rendo conto che questa parte di codice andrebbe ancora migliorata…

Grazie ragazzi, un aiuto e dei consigli sarebbero graditissimi!

Per esempio eviterei di usare chmod tutte le volte e mi limiterei ad impostare i permessi della cartella di destrinazione una volta per tutte. Non via codice, in ogni caso.

E poi ripeti lo stesso codice molte volte. Questo lo rende decisamente difficile da manutenere o anche solo da leggere. Per il resto, se va, va bene. Se devi aggiungere altro codice per eliminare dei file, … cosa ti serve? Ti serve sapere come si fa ad eliminare un file con php?

Ciao, si è vero, me ne sono reso conto anche io, ripeto molto codice, ma avevo iniziato da poco a scrivere questo metodo e quindi doveva essere ancora ordinato, ora è decisamente meglio. Credo di aver risolto il problema, nella view dovevo utilizzare $form->fileField anziché CHtml::activeFileField. Per eliminare il file utilizzo unlink().

Poiché vorrei creare delle cartelle in base all’id della tupla, come mi consigli gestire la creazione delle cartelle?

Il codice relativo alla actionUpdate() l’ho risistemato così, secondo te va bene?




	public function actionUpdate($id)

	{

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

		

		$oldFile = $model->bandiera;

		// Uncomment the following line if AJAX validation is needed

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

		

		$cartella = Yii::app()->basePath."/../uploads/images/foto_bandiera/".$model->id;

		if (!is_dir($cartella)) {

			if (!mkdir($cartella, 0777, true)) {

				error_log('Failed to create base folder...');

			}

		}

			

		$cartellaThumb = Yii::app()->basePath."/../uploads/images/foto_bandiera/thumb/".$model->id;

		if (!is_dir($cartellaThumb)) {

			if (!mkdir($cartellaThumb, 0777, true)) {

				error_log('Failed to create thumb folder...');

			}

		}

			

		$cartellaBig = Yii::app()->basePath."/../uploads/images/foto_bandiera/big/".$model->id;

		if (!is_dir($cartellaBig)){

			if (!mkdir($cartellaBig, 0777, true)) {

				error_log('Failed to create big folder...');

			}

		}

				

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

		{			

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


			$newFile = CUploadedFile::getInstance($model,'bandiera');

						

			if (is_object($newFile) && get_class($newFile)==='CUploadedFile') {

				$model->bandiera = $newFile;

			}

			else {

				$model->bandiera = $oldFile;

			}

			

			if($model->save()) {

				if (is_object($newFile) && get_class($newFile)==='CUploadedFile') {

					$newPercorso = $cartella."/".$newFile;

					$newPercorsoThumb = $cartellaThumb."/".$newFile;

					$newPercorsoBig = $cartellaBig."/".$newFile;

								

					$model->bandiera->saveAs($newPercorso);

									

					$imageTemp = new Imagick($newPercorso);

					$imageTempProps = $imageTemp->getimagegeometry();

				

					if($imageTempProps['width']<=1000 && $imageTempProps['height']<=1000) {

						//non scalare

					} else $imageTemp->resizeimage(1000, 1000, Imagick::FILTER_LANCZOS, 0.9, true);

					$imageTemp->writeimage($newPercorsoBig);

					

					if($imageTempProps['width']<=600 && $imageTempProps['height']<=600) {

						//non scalare

					} else $imageTemp->resizeimage(600, 600, Imagick::FILTER_LANCZOS, 0.9, true);

					$imageTemp->writeimage($newPercorso);

				

					if($imageTempProps['width']<=200 && $imageTempProps['height']<=200) {

						//non scalare

					} else $imageTemp->resizeimage(200, 200, Imagick::FILTER_LANCZOS, 0.9, true);

					$imageTemp->writeimage($newPercorsoThumb);

					

					/****** Inizio Gestione della vecchia immagine ******/

					$oldPercorso = $cartella."/".$oldFile;

					$oldPercorsoThumb = $cartellaThumb."/".$oldFile;

					$oldPercorsoBig = $cartellaBig."/".$oldFile;

					//se la nuova immagine non ha lo stesso nome della vecchia viene cancellata

					if (file_exists($oldPercorso) && $oldFile != $newFile) {

						unlink($oldPercorso);

					}

					if (file_exists($oldPercorsoBig) && $oldFile != $newFile) {

						unlink($oldPercorsoBig);

					}

					if (file_exists($oldPercorsoThumb) && $oldFile != $newFile) {

						unlink($oldPercorsoThumb);

					}

					/****** Fine Gestione della vecchia immagine ******/

				}

				

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

			}

			

		}

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

				'model'=>$model,

		));

	}



Grazie mille!

Scusami ma non ragiono a soluzioni: a me piace capire i problemi per eliminarli. Tu hai bisogno di avere le cartelle con l’id del record?