angular tutorial

Subir archivos con Angular y PHP

Algo muy normal en cualquier proyecto es que en algún momento vamos a subir archivos con angular, para esto vamos a crear un archivo php donde podamos cargar estos documentos en nuestro servidor.

Subir archivos con angular y PHP

Componente PHP

Para subir cualquier archivo vamos a usar php, para esto vamos a utilizar algunas opciones básicas como $_FILES y las cabeceras HTTP (POST).

<?php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: X-Requested-With');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');


if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    echo json_encode(array('status' => false));
    exit;
}
$path = './subidas/';

if (isset($_FILES['file'])) {
    $originalName = $_FILES['file']['name'];
    $ext = '.'.pathinfo($originalName, PATHINFO_EXTENSION);
    $generatedName = md5($_FILES['file']['tmp_name']).$ext;
    $filePath = $path.$generatedName;

    if (!is_writable($path)) {
        echo json_encode(array(
            'status' => false,
            'msg'    => 'Destination directory not writable.'
        ));
        exit;
    }

    if (move_uploaded_file($_FILES['file']['tmp_name'], $filePath)) {
            echo json_encode(array(
                'status' => true,
                'generatedName' => $generatedName
            ));
            
    }else{
            echo json_encode(array(
                'status' => false,
                'generatedName' => $generatedName
            ));
        }
        
}else{


    echo json_encode(
        array('status' => false, 'msg' => 'No file uploaded.')
    );
    exit;
}

Vamos a explicar algunas cosas.

Tenemos que nombrar donde se subirán nuestros archivos por eso creamos la variable $path.

Vamos a comprobar que realmente se este enviado el archivo en post

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    echo json_encode(array('status' => false));
    exit;
}

Una vez comprobado que realmente nuestra petición es post vamos a comprobar si existe el archivo que vamos a subir, para esto usamos la variable reservado $_FILES y vamos a hacer una comprobación con isset, recordemos que isset comprueba que exista algo

if (isset($_FILES['file'])) {
    $originalName = $_FILES['file']['name'];
    $ext = '.'.pathinfo($originalName, PATHINFO_EXTENSION);
    $generatedName = md5($_FILES['file']['tmp_name']).$ext;
    $filePath = $path.$generatedName;

    if (!is_writable($path)) {
        echo json_encode(array(
            'status' => false,
            'msg'    => 'Destination directory not writable.'
        ));
        exit;
    }

Podemos ver que $_FILES tenemos varias propiedades, entre ellas esta name y tmp_name que usaremos para poder completar y subir archivos con angular, pathinfo en php devuelve informacion de un archivo.

para este ejemplo pongo los archivos en md5 para que no exista errores por caracteres raros y enseguida comprobamos que la carpeta (subidas) tenga los permisos necesarios para escribir, recordemos que si podemos usar ssh en nuestro servidor basta en ubicar la carpeta y poner chmod 755 o chmod 766 para que tenga permisos suficientes.

move_uploaded_file va a mover archivos subidos(seguros) por http post de php, por eso la importancia de comprobar si la petición está hecha en post, si todo esta bien vamos a recibir un mensaje con el nombre generado.

if (move_uploaded_file($_FILES['file']['tmp_name'], $filePath)) {
           echo json_encode(array(
               'status' => true,
               'generatedName' => $generatedName
           ));
           
   }else{
           echo json_encode(array(
               'status' => false,
               'generatedName' => $generatedName
           ));
       }

Subir archivos con angular 6

Para poder subir archivos con angular es muy sencillo, por no decir que lo mas dificil de todo fue el archivo php, claro esto depende lo que queremos hacer pero en este caso solo subiremos archivos de tipo imagen.

Services para subir archivos con angular

si no conoces sobre los servicios dejare dos post donde explico que son y para que sirve post1 y post2

Lo primero que vamos a hacer es crear nuestro servicio “subirarchivo” ejecutando en nuestra consola lo siguiente

ng g service services/subirarchivos

vamos a inicializar nuestro servicios usando las librerías de HttpClient y Observable de rxjs

import { Injectable } from '@angular/core';
import {HttpClient} from '@angular/common/http';
import { Observable } from 'rxjs';
import {environment} from '../../environments/environment';

@Injectable({
  providedIn: 'root'
})
export class SubirarchivoService {
  url:string = environment.subirUrl;

  constructor( private http:HttpClient) {
  }
  subirImagen(datos:any):Observable<any>{
    return this.http.post(this.url, datos);
  }
}

con esto tenemos nuestra conexión al archivo php, hay que recordar que debemos dar de alta en el app.module de angular el servicio creado.

Archivo principal ts

vamos a importar nuestros servicios que acabamos de crear

import {SubirarchivoService} from ‘../services/subirarchivo.service’;
y recuerden que debemos inicializarlo en el constructor
constructor(private subir:SubirarchivoService) { }
vamos a usar la etiqueta input de tipo file y a este vamos a agregarle una accion de change para que detecte si hay algun cambio internamente
<input type="file" name="file" (change)="subiendoando($event)" accept="image/*" />

si ven tenemos en el input accept, accept acepta varios valores que pondre en seguida

file_extensionA file extension starting with the STOP character, e.g: .gif, .jpg, .png, .doc
audio/*All sound files are accepted
video/*All video files are accepted
image/*All image files are accepted
media_typeA valid media type, with no parameters. Look at IANA Media Types for a complete list of standard media types

y el evento que vamos a crear es el siguiente

subiendoando(ev){
    let img:any = ev.target;
    if(img.files.length > 0){
      this.loader = true;
      let form = new FormData();
      form.append('file',img.files[0]);
      this.subir.subirImagen(form).subscribe(
        resp => {
          this.loader = false;
          if(resp.status){
            this.trueimg = true;
            this.myimg = environment.ruta+resp.generatedName;
            this.msn = "Gracias por visitar unprogramador.com"
          }
        },
        error => {
          this.loader = false;
          alert('Imagen supera el tamaño permitido');
          
        }
      );

    }

  }

con este evento lo que vamos a hacer es que en el html pasaremos $event que trae todo el comportamiento de este componente, enseguida vamos a verificarlo, si lo ponemos en la consola veremos que tiene un objeto llamado target y dentre de este files, que es lo que vamos a usar.

files se comporta como un array, donde vendra los archivos que queremos subir.

cuando usamos el evento subscribe tenemos dos eventos principales, resp que es la respuesta del servidor (puedes llamarlo como quieras) y error, que este recoge algun error en el momento de la respuesta, en este caso php manda un mensaje sin codificar en json, asi que podemos cacharlo y luego decir cual es el error .

el componente completo se ve asi

import { Component, OnInit } from '@angular/core';
import {SubirarchivoService} from '../services/subirarchivo.service';
import {environment} from '../../environments/environment';
import {ImagenesComponent} from '../imagenes/imagenes.component';

@Component({
  selector: 'app-subirarchivos',
  templateUrl: './subirarchivos.component.html',
  styleUrls: ['./subirarchivos.component.css']
})
export class SubirarchivosComponent implements OnInit {
  trueimg:Boolean = false;
  loader:Boolean = false;
  myimg:string;
  final:Boolean = true;
  msn:string;


  constructor(private subir:SubirarchivoService) { }

  ngOnInit() {
    this.msn = "Subir una imagen no mayor de 10MB";
  }
  
  subiendoando(ev){
    let img:any = ev.target;
    if(img.files.length > 0){
      this.loader = true;
      let form = new FormData();
      form.append('file',img.files[0]);
      this.subir.subirImagen(form).subscribe(
        resp => {
          this.loader = false;
          if(resp.status){
            this.trueimg = true;
            this.myimg = environment.ruta+resp.generatedName;
            this.msn = "Gracias por visitar unprogramador.com"
          }
        },
        error => {
          this.loader = false;
          alert('Imagen supera el tamaño permitido');
          
        }
      );

    }

  }


}

html completo

<section>
    <div class="anuncio">

    </div>
    <div class="forms">
        <label for="title">{{msn}}</label>
        <input type="file" name="file" (change)="subiendoando($event)" accept="image/*" *ngIf="!loader" />
        <div *ngIf="loader">
            <img src="../../assets/loading.gif" />
        </div>
        <div class="img" *ngIf="trueimg">
            <img src="{{myimg}}" />
        </div>
    </div>
    <div class="imagenes">
        <app-imagenes></app-imagenes>
    </div>

</section>

Compilar angular y colocarlo en una subcarpeta

Algo que generalmente pasa, es que angular debe estar en una carpeta raiz para que todo funcione bien pero … si esta en una subcarpeta angular no sabe que hacer y te redirige a raiz.

para esto vamos a compilar de la siguiente manera

ng build –prod –base-href=”myURL”

donde –base es la ruta donde estara nuestro proyecto, debe ir como una url absoluta pero tambien como relativa, pero tienen que especificar bien, mi recomendacion es que pongan la ruta absoluta.

Observacion

tuve un pequeño error y era que siempre me traia la misma respuesta mi archivo php, esto es por que el navegador toma cache y hasta refrescar vuelve a hacer una llamado, como todo se hace sin refrescar da error el cahe, podemos solucionarlo con lo siguiente

html

<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
    <meta http-equiv="Pragma" content="no-cache">
    <meta http-equiv="Expires" content="0">

php

header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");

y este es el htaccess para que funcione angular

<IfModule mod_headers.c>
    Header set Access-Control-Allow-Origin "*"
</IfModule>
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]

RewriteRule ^(.*) /index.html [NC,L]
</IfModule>

Repositorio para subir archivos con angular y php

php

Angular 6

ejemplo en vivo

2 comments

Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.