Comunidad de diseño web y desarrollo en internet online

Subir imágenes a un servidor con AIR

En este tip, voy a mostrar como subir imágenes a un servidor utilizando una Aplicación en AIR, desde la aplicación se podrán seleccionar las imágenes que se quieren subir o bien, hacer un Drag&Drop desde el sistema de archivos local. También se muestra una vista previa de la imagen y la opción para borrarla.

Lo primero que debemos de hacer, es crear un proyecto nuevo en Flex y seleccionar el tipo de aplicación que sea de escritorio, o sea, que corra con AIR.

Bien, ya que tenemos nuestro proyecto creado, procederemos a crear la interfaz, lo que mostraremos, serán controles como TileList, Botones y un componente exclusivo para AIR, el FileSystemTree. En el TileList mostraremos las imágenes que se subirán y con los botones controlaremos acciones como: “Eliminar Imágenes” y “Subir Imágenes”. Con el FileSystemTree mostraremos toda la estructura de carpetas y archivos de la computadora que este ejecutando nuestra aplicación y desde ahí se podrán agregar las imágenes también.

Código :

<mx:ApplicationControlBar x="35" y="120" dock="true" height="40">
<mx:Button label="Eliminar Imagenes" icon="{ImageUtil.imagen.Delete}" click="click_eliminar()"/>
   <mx:VRule height="100%"/>
   <mx:Button label="Subir al Servidor" icon="{ImageUtil.imagen.ServerGo}" click="click_subir()"/>
</mx:ApplicationControlBar>
<mx:HDividedBox width="100%" height="100%">
   <mx:FileSystemTree id="archivos_fst" width="250" height="100%" showIcons="true" showExtensions="true"
      allowMultipleSelection="true" 
      allowDragSelection="true" dragEnabled="true" dragMoveEnabled="false"/>
   <mx:TileList id="imagenes_tl" width="100%" height="100%" itemRenderer="ir.ImagenIR" 
      direction="horizontal" allowMultipleSelection="true" dataProvider="{imagenes_ac}"
      dragEnter="dragEnter_imagenes(event)" dragDrop="dragDrop_imagenes(event)" dragExit="dragExit_imagenes(event)"/>
</mx:HDividedBox>


Crearemos un ItemRenderer que será el que muestre la imagen y su respectivo nombre, este IR consta únicamente de un objeto de tipo Image y un Label.

Código :

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" width="100" height="130" horizontalAlign="center" verticalAlign="middle"
   dataChange="dataChange_this(event)">
   <mx:Script>
      <![CDATA[
         import mx.controls.Label;
         import mx.controls.Image;
         import mx.events.FlexEvent;
         
         private var imagen:Image;
         private var nombre_lbl:Label;
         
         private function dataChange_this(event:FlexEvent):void
         {
            try
            {
               //intentamos eliminar el Image y el Label, pues la primera vez no existen
               this.removeChild(imagen);
               this.removeChild(nombre_lbl);
            }
            catch (error:Error)
            {
               
            }
            if (this.data is File)
            {
               //como cada elemento del ArrayCollection es un File,
               //casteamos la variable data
               var f:File = File(this.data);
               //creamos el objeto que mostrara la imagen
               imagen = new Image();
               imagen.width = 95;
               imagen.height = 95;
               //le indicamos a la imagen de donde debe de cargar la imagen
               imagen.load(f.url);
               //creamos el objeto que mostrara el nombre de la imagen
               nombre_lbl = new Label();
               nombre_lbl.width = 95;
               //asignamos el nombre
               nombre_lbl.text = f.name;
               //agregamos los objetos al VBox
               this.addChild(imagen);
               this.addChild(nombre_lbl);
            }
         }
      ]]>
   </mx:Script>
</mx:VBox>


Ya creada la interfaz, procederemos con el código. El código se divide en varias partes, las principales, son para controlar los Drag&Drop desde el FileSystemTree hacia el TileList, para controlar el Drag&Drop desde el sistema de archivos local del sistema hacia nuestra Aplicación, la eliminación de imágenes y para subir las imágenes al servidor.

El Drag&Drop del FileSystemTree al TileList será controlado con los siguiente métodos:

Código :

private function dragEnter_imagenes(event:DragEvent):void
{
   //verifico que la fuente sea el FileSystemTree
   if (event.dragSource.hasFormat("treeItems"))
   {
      //le digo que el TileList que muestra las imagenes puede recibir objetos
      DragManager.acceptDragDrop(imagenes_tl);
      //deshabilito los Listeners de la aplicacion para evitar confusiones de drop
      this.removeEventListener(NativeDragEvent.NATIVE_DRAG_DROP, drag_drop_this);
      this.removeEventListener(NativeDragEvent.NATIVE_DRAG_ENTER, drag_enter_this);
   }
}
      
private function dragExit_imagenes(event:DragEvent):void
{
   //si no suelta los elementos del FileSystemTree en el TileList,
   //solamente rehabilitamos los Listeners de la aplicacion
   this.addEventListener(NativeDragEvent.NATIVE_DRAG_DROP, drag_drop_this);
   this.addEventListener(NativeDragEvent.NATIVE_DRAG_ENTER, drag_enter_this);
}

private function dragDrop_imagenes(event:DragEvent):void
{
   //creamos una variable del FileSystemTree que origino el Drag
   var fst:FileSystemTree = FileSystemTree(event.dragInitiator);
   //vemos cuales son las rutas que fueron seleccionadas
   var rutas:Array = fst.selectedPaths;
   //agregamos esas rutas a nuestro ArrayColecction de File's
   agregaAlDP(rutas);
   //rehabilito los Listeners de la aplicacion
   this.addEventListener(NativeDragEvent.NATIVE_DRAG_DROP, drag_drop_this);
   this.addEventListener(NativeDragEvent.NATIVE_DRAG_ENTER, drag_enter_this);
}


El Drag&Drop del sistema de archivos local a nuestra Aplicación será controlado con los siguiente métodos:

Código :

private function dragExit_imagenes(event:DragEvent):void
{
   //si no suelta los elementos del FileSystemTree en el TileList,
   //solamente rehabilitamos los Listeners de la aplicacion
   this.addEventListener(NativeDragEvent.NATIVE_DRAG_DROP, drag_drop_this);
   this.addEventListener(NativeDragEvent.NATIVE_DRAG_ENTER, drag_enter_this);
}

private function dragDrop_imagenes(event:DragEvent):void
{
   //creamos una variable del FileSystemTree que origino el Drag
   var fst:FileSystemTree = FileSystemTree(event.dragInitiator);
   //vemos cuales son las rutas que fueron seleccionadas
   var rutas:Array = fst.selectedPaths;
   //agregamos esas rutas a nuestro ArrayColecction de File's
   agregaAlDP(rutas);
   //rehabilito los Listeners de la aplicacion
   this.addEventListener(NativeDragEvent.NATIVE_DRAG_DROP, drag_drop_this);
   this.addEventListener(NativeDragEvent.NATIVE_DRAG_ENTER, drag_enter_this);
}


Se generó una función genérica con la cual se alimentará nuestro DataProvider del TileList, se hace una verificación para saber si recibimos un arreglo de File’s o si recibimos un arreglo de Rutas:

Código :

private function agregaAlDP(imgs:Array):void
{
   var i:int = 0;
   //cuento el numero de elementos del arreglo
   var l:int = imgs.length;
   //defino la variable que contendra al archivo
   var f:File;
   for (i = 0; i < l; i++)
   {
      if (imgs[i] is File)
      {
         //si el arreglo ya es de File, solo lo casteo
         f = File(imgs[i]);
      }
      else
      {
         //si el arreglo es de las rutas, instancio la variable
         f = new File(imgs[i]);
      }
      //si lo que se arrastra es un directorio, 
      //la propiedad extension = null, por eso lo valido 
      if (f.extension)
      {
         //lo hago minusculas, por ahi hay muchos .JPG que entrarian a ningun caso
         switch (f.extension.toLowerCase())
         {
            case "png":
            case "gif":
            case "jpg":
            case "jpeg":
            {
               //solo le permito a los archivos de algun tipo de imagen
               imagenes_ac.addItem(f);
               break;
            }
         }
      }
   }
}


Para eliminar las imágenes, únicamente eliminamos los elementos del DataProvider con el siguiente método:

Código :

private function click_eliminar():void
{
   //recupero los indices seleccionados y los asigno a un Array
   var indices:Array = imagenes_tl.selectedIndices;
   var i:int = 0;
   //veo cuantos elementos son y le resto 1
   var l:int = indices.length - 1;
   //recorro el ArrayCollection del fin al principio por que conforme voy eliminando,
   //van cambiando los indices
   for (i = l; i >= 0; i--)
   {
      //voy quitando los elementos del ArrayCollection
      imagenes_ac.removeItemAt(indices[i]);
   }
}


Para subir las imágenes de nuestro TileList al server, utilizamos los siguientes métodos:

Código :

private function click_subir():void
{
   //inicializo un arreglo nuevo
   archivosSeleccionados = [];
   var i:int = 0;
   //veo cuantos elementos tiene nuestro ArrayColection de File's
   var l:int = imagenes_ac.length;
   for (i = 0; i < l; i++)
   {
      //proceso cada elemento por separado
       agregarPendiente(File(imagenes_ac.getItemAt(i)));
   }
}

private function agregarPendiente(f:File):void
{
   //agrego el archivo al arreglo
   archivosSeleccionados.push(f);
   //agrego Listeners de progreso y de completado
   f.addEventListener(ProgressEvent.PROGRESS, progress_f);
   f.addEventListener(Event.COMPLETE, complete_f);
   //con upload le digo a File que suba el archivo usando el script
   //definido en el URLRequest
   f.upload(ur);
}

private function progress_f(event:ProgressEvent):void
{
   //aquí se puede mostrar el progreso en un ProgressBar, en un TextArea o como más te guste
   trace("progressHandler: name=" + File(event.currentTarget).name + " bytesLoaded=" + event.bytesLoaded + " bytesTotal=" + event.bytesTotal);
}

private function complete_f(event:Event):void
{
   //cuando se ha subido el archivo, lo quitamos del Array
   quitarPendiente(File(event.currentTarget))
}

private function quitarPendiente(f:File):void
{
   var i:int = 0;
   //vemos cuantos archivos tenemos
   var l:int = archivosSeleccionados.length;
   for (i = 0; i < l; i++)
   {
      if (archivosSeleccionados[i].name == f.name)
      {
         //si el archivo que se subió es el actual del Array, se quita
         archivosSeleccionados.splice(i, 1);
         if (archivosSeleccionados.length == 0)
         {
            //si el Array ya no tiene elementos, terminó de subir
            terminado();
         }
         return;
      }
   }
}

private function terminado():void
{
   //Le avisamos al usuario que se han terminado de subir las imagenes
   Alert.show("Las imagenes han sido subidas al servidor con éxito!", "Confirmación");
}


Y bien ahora va la parte de php, un pequeño script que recibe el archivo y lo mueve a nuestro servidor:

Código :

<?php
$carpeta = "";
$archivo = $carpeta . $_FILES['Filedata']['name'];
if(move_uploaded_file($_FILES['Filedata']['tmp_name'], $archivo))
{
   echo "<datos err='no'/>";
}
else
{
   echo "<datos err='si'/>";
}
?>


Ya solo queda dejar un archivo comprimido con el proyecto de Flex y este script de PHP. El archivo DragAndDrop.zip, incluye dos archivos:
DragDrop.zip que es archivo que se importa desde Flex para que se genere el proyecto.
upload.php que es el script que se encarga de mover las imagenes al servidor.
descargar archivo

¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.

Publica tu comentario

El autor de este artículo ha cerrado los comentarios. Si tienes preguntas o comentarios, puedes hacerlos en el foro

Entra al foro y participa en la discusión

o puedes...

¿Estás registrado en Cristalab y quieres
publicar tu URL y avatar?

¿No estás registrado aún pero quieres hacerlo antes de publicar tu comentario?

Registrate