Hola, bueno aquí dejo explicado con mas detalle el proceso de subir múltiples archivos en YII Framework:
El sistema funciona asi: en el momento de seleccionar el archivo, este quedara almacenado en la carpeta llamada "uploads" esta carpeta ha sido creada en la raiz principal del proyecto Web, se forma paralela, se guarda en la base de datos la ruta donde esta almacenado el archivo (carpeta uploads) y concatenamos con el nombre del archivo. Esto dará como resultado ejemplo: "/uploads/nombre_archivo.pdf".
Esto lo hacemos porque en bases de datos MYSQ no es recomendable almacenar archivos en los campos, y si buscamos en google tutoriales de como subir imágenes en MYSQL, nos darán ejemplo para subir imágenes directamente a los campos.
EMPEZAMOS:
1. Descomprimimos la extension llamada EAjaxUpload (la cual adjunto con este mensaje) en la ruta: "/protected/extensions/". El resultado nos dara asi: "/protected/extensions/EAjaxUpload/".
2. en la carpeta EAjaxUpload, debemos editar 2 archicvos llamados: EAjaxUploadAction y qqFileUploader; Iniciamos editando el primero:
<?php
Yii::import("ext.EAjaxUpload.qqFileUploader");
class EAjaxUploadAction extends CAction
{
public function run()
{
// list of valid extensions, ex. array("jpeg", "xml", "bmp")
$allowedExtensions = array("pdf","mp3","mp4","wmv");
// max file size in bytes
$sizeLimit = 1 * 1024 * 1024;
$uploader = new qqFileUploader($allowedExtensions, $sizeLimit);
$result = $uploader->handleUpload('uploads/');
// to pass data through iframe you will need to encode all html tags
$result=htmlspecialchars(json_encode($result), ENT_NOQUOTES);
echo $result;
}
}
De este archivo, las Lineas de codigo 11 y 16 son importantes.
linea 11:
$allowedExtensions = array("pdf","mp3","mp4","wmv");
Muestra las extensiones de archivos que son permitidas subir.
linea 16:
$result = $uploader->handleUpload('uploads/');
Muestra la ruta donde se encuentra la carpeta destinada para almacenar los archivos, esta Ruta es muy importante, recomiendo no editar su nivel de profundidad, por esto yo la he dejado en la carpeta principal de nuestro proyecto Web.
Pasamos al siguiente Nivel, por el momento no editaremos el archivo "qqFileUploader", lo explicaré mas adelante.
3. Agregando el método a nuestro controlador
Es muy importante agregar el Método que llama a la extensión a nuestro controlador, el código es el siguiente:
public function actionUpload() {
Yii::import("ext.EAjaxUpload.qqFileUploader");
$folder = 'uploads/'; // folder for uploaded files
$allowedExtensions = array("pdf", "mp3", "mp4", "wmv"); //array("jpg","jpeg","gif","exe","mov" and etc...
$sizeLimit = 10 * 1024 * 1024; // maximum file size in bytes
$uploader = new qqFileUploader($allowedExtensions, $sizeLimit);
$result = $uploader->handleUpload($folder);
$return = htmlspecialchars(json_encode($result), ENT_NOQUOTES);
$fileSize = filesize($folder . $result['filename']); //GETTING FILE SIZE
$fileName = $result['filename']; //GETTING FILE NAME
echo $return; // it's array
}
De este metodo las lineas mas importantes son:
$folder = 'uploads/'; // folder for uploaded files
Esta Linea debe llevar la Ruta de la carpeta que almacena los archivos, esta ruta debe ser la misma que contiene el archivo "EAjaxUploadAction" de nuestra extension EAjaxUpload.
La siguiente linea:
$allowedExtensions = array("pdf", "mp3", "mp4", "wmv"); //array("jpg","jpeg","gif","exe","mov" and etc...
Muestra las estensiones permitidas, tengan en cuenta que el mismo orden de las extensiones debe ser el mismo como se encuentra en el archivo: "EAjaxUploadAction" de nuestra extension EAjaxUpload.
4. Dando Permisos a nuestro Método actionUpload().
Muy importante dar estos permisos en el accessRules() del controlador donde creamos nuestro método actionUpload(). Ejemplo de como quedarían los permisos:
array('allow', // allow authenticated user to perform 'create' and 'update' actions
'actions' => array('create', 'index', 'upload'),
'users' => array('*'),
),
Aqui en este código, tengan en cuenta que nuestro metodo se llama: actionUpload() y lo estamos llamando como: upload y con "u" minuscula, en yii framework la palabra Action no se usa para llamar a los métodos.
5. Llamando la extensión en la vista
Ahora por Ultimo paso, necesitamos llamar la extensión en la vista del Controlador, el codigo es el siguiente:
<?php
$this->widget('application.extensions.EAjaxUpload.EAjaxUpload', array(
'id' => 'fileUploader',
'config' => array(
'action' => Yii::app()->createUrl('/publicacion/upload'),
'allowedExtensions' => array("pdf","mp3","mp4"), //array("jpg","jpeg","gif","exe","mov" and etc...
'sizeLimit' => 1 * 1024 * 1024 * 100, // maximum file size in bytes
'minSizeLimit' => 1024, // minimum file size in bytes
'onComplete' => "js:function(id, fileName, responseJSON){ $('#archivo').val(fileName); $('#botones').css('display','inline'); }",
)
));
?>
La linea de codigo:
'action' => Yii::app()->createUrl('/publicacion/upload'),
Esta linea de codigo es muy importante, porque es la que esta llamando al metodo upload en el nuestro Controlador, para este caso, el Controlador se llama publicacion, seguido de "/" y el nombre del metodo "upload".
La siguiente linea de código explica de nuevo la extensiones que son permitidas Adjuntar.
--------------------------------------------------------------------------------------
Hasta aquí vamos todo bien, el permite adjuntar archivos en una carpeta que están dentro de nuestro proyecto Web, PERO el sistema informático no SABE donde se están guardando.
Para esto y para subir múltiples archivos me idee de la siguiente forma.
1. Para subir múltiples archivos, podríamos tener en un futuro el problema que 2 archivos coincidan con el mismo nombre y llegado este caso, el sistema informático lo que va a realizar es reemplazar y copiar el archivo nuevo por el que ya se encuentra almacenado.
LA SOLUCION:
Para solucionar este problema requerimos que los archivos no se llamen igual. Pero esta responsabilidad no se la podemos dejar encargada al usuario, para esto se deja encargado al sistema informático con lo siguiente: vamos a generar un número randomico (número al azar) entre 10 y 99 y el resultado se concatena con el nombre del archivo, osea, renombramos el archivo que subimos y le agregamos al nombre el número.
Con esto evitamos que en el futuro que 2 archivos tengan el mismo nombre, no sean reemplazados.
Y COMO HACEMOS ESTO?
Agregamos en la vista el sigueinte codigo:
<?php
Yii::app()->user->setState('salt', rand(10, 99));
?>
Esta acción funciona así: en el momento que el usuario visualiza la vista, se genera una cookie que contiene el numero randomico, esta cookie la podemos llamar como si fuera una variable global que sera utilizada.
ULTIMO PASO:
Ahora si, podemos editar el archivo "qqFileUploader" que se encuentra en la carpeta de la extension EAjaxUpload.
En este archivo buscamos la funcion handleUpload.
function handleUpload($uploadDirectory, $replaceOldFile = FALSE){
if (!is_writable($uploadDirectory)){
return array('error' => "Server error. Upload directory isn't writable.");
}
if (!$this->file){
return array('error' => 'No files were uploaded.');
}
$size = $this->file->getSize();
if ($size == 0) {
return array('error' => 'File is empty');
}
if ($size > $this->sizeLimit) {
return array('error' => 'File is too large');
}
$pathinfo = pathinfo($this->file->getName());
$filename = $pathinfo['filename'];
//$filename = md5(uniqid());
$ext = $pathinfo['extension'];
if($this->allowedExtensions && !in_array(strtolower($ext), $this->allowedExtensions)){
$these = implode(', ', $this->allowedExtensions);
return array('error' => 'File has an invalid extension, it should be one of '. $these . '.');
}
if ($this->file->save($uploadDirectory . $filename.Yii::app()->user->getState('salt'). '.' . $ext)){
$modelo = new Archivos();
$modelo->identificador = Yii::app()->user->getState('salt');
$modelo->ruta = Yii::app()->request->baseUrl.'/uploads/'.$filename.Yii::app()->user->getState('salt').'.'.$ext;
$modelo->titulo = $filename;
$modelo->save();
return array('success'=>true,'filename'=>$filename.Yii::app()->user->getState('salt').'.'.$ext);
} else {
return array('error'=> 'Could not save uploaded file.' .
'The upload was cancelled, or server error encountered');
}
}
De esta función la parte que nos interesa es donde se encuentra el último if:
if ($this->file->save($uploadDirectory . $filename.Yii::app()->user->getState('salt'). '.' . $ext)){
$modelo = new Archivos();
$modelo->identificador = Yii::app()->user->getState('salt');
$modelo->ruta = Yii::app()->request->baseUrl.'/uploads/'.$filename.Yii::app()->user->getState('salt').'.'.$ext;
$modelo->titulo = $filename;
$modelo->save();
return array('success'=>true,'filename'=>$filename.Yii::app()->user->getState('salt').'.'.$ext);
} else {
return array('error'=> 'Could not save uploaded file.' .
'The upload was cancelled, or server error encountered');
}
En esta condicional IF esta preguntando si el archivo llamado: nombre_archivo + Numero randomico + la extension del archivo, fue almacenado en la carpeta uploads.
Como vemos el sigueinte codigo esta rescatando el numero randomico que generamos como una cookie:
$filename.Yii::app()->user->getState('salt')
Y dentro de la condicional se encuentra una instancia del Modelo llamado: Archivos(), esta instancia se almacena en la variable llamada: $modelo.
Este modelo: "Archivos" es una tabla de la base de datos que esta almacenando 3 campos:
1 Identificador: este es el numero que generamos de forma randomica, la cuestion es que como vamos a subir múltiples archivos, los que se suban por un usuario, contengan el mismo numero randomico, para pode identificarlos y así saber que es una subida múltiple de 1 solo usuario.
2 la RUTA donde se encuentra almacenado el archivo, el sigueinte codigo muestra el nombre real de archivo junto con la concatenacion del numero randomico.
$modelo->ruta = Yii::app()->request->baseUrl.'/uploads/'.$filename.Yii::app()->user->getState('salt').'.'.$ext;
Esta Ruta y Nombre del archivo deben coincidir con los que se encuentran en la carpeta uploads.
3 El Titulo, guardo el titulo o nombre del archivo para poder mostrarlo al usuario sin necesidad de mostrar toda la ruta donde se encuentra almacenado.
FIN
Espero les sea de ayuda, Adjunto la extensión para que la usen: