Captura de imagen con la cámara y subida a un servidor (PHP)

Hoy vamos a preparar un pequeño tutorial sobre como hacer una foto con la cámara del móvil y subirla a un servidor, en este caso voy a usar un servidor PHP y aportaré el código, pero podríais hacerlo en cualquier otro si tenéis experiencia.

Empezamos creando el proyecto:

create subirImagen es.phonegap.subirimagen subirImagen

vamos al directorio del proyecto, añadimos los plugins de cámara y file transfer y las plataformas ios y android (yo voy a trabajar con iOS, pero el código es igual para ambas)

cd subirImagen
cordova plugin add cordova-plugin-camera
cordova plugin add cordova-plugin-file-transfer
cordova platform add ios android

Para simplificar, vamos a trabajar diréctamente en el index.html, así que eliminamos las carpetas css y js que hay dentro de la carpeta www y abrimos el index.html y lo dejamos así:

<!DOCTYPE html>
<html>
    <head>
        <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
        <title>Subir imagen</title>
        <script>
        </script>
    </head>
    <body>
        <div class="app">
            <h1>Apache Cordova</h1>
          
        </div>
        <script type="text/javascript" src="cordova.js"></script>
    </body>
</html>

Parte 1: Hacer la foto

Dentro del div con clase app añadimos un botón que llamará a la función de hacer la foto, y una etiqueta img para mostrar la imagen que hemos hecho:

<input type="button" onclick="hacerFoto();"  value="Hacer Foto">
<img id="fotoLocal" src="" width="100px" height="100px">

Y dentro de la etiqueta script definimos la función hacerFoto

function hacerFoto(){
    navigator.camera.getPicture(onSuccess, onFail, { quality: 50,
                                            destinationType: Camera.DestinationType.FILE_URI });
}
            
function onSuccess(imageURI) {
    var image = document.getElementById('fotoLocal');
    image.src = imageURI;
}
        
function onFail(message) {
    alert('Failed because: ' + message);
}

Parte 2: subir la foto al servidor

Vamos a añadir otra etiqueta img más para mostrar la imagen una vez subida al servidor

<img id="fotoServidor" src="" width="100px" height="100px">

Y definimos la función subirImagen que llamaremos en el success de la cámara pasando la ruta de la imagen

function subirImagen(fileURL) {
            
    var options = new FileUploadOptions();
    options.fileKey = "imagen";
    options.fileName = fileURL.substr(fileURL.lastIndexOf('/') + 1);

    var ft = new FileTransfer();
    ft.upload(fileURL, encodeURI("http://jcesar.16mb.com/upload/upload.php"), uploadSuccess, uploadFail, options);

}

function uploadSuccess(r) {
    alert("Code = " + r.responseCode+" Response = " + r.response+" Sent = " + r.bytesSent);
}

function uploadFail(error) {
    alert("An error has occurred: Code = " + error.code+ " upload error source " + error.source+" upload error target " + error.target);

}

Ya estaría todo, simplemente hacemos que en al recibir el success de la subida, cogemos la url que nos devuelve y se lo asignamos a nuestra segunda img.  Nuestro index.html debería haber quedado así:

<!DOCTYPE html>
<html>
    <head>
        <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
        <title>Subir imagen</title>
        <script>
            function hacerFoto(){
                navigator.camera.getPicture(onSuccess, onFail, { quality: 50, destinationType: Camera.DestinationType.FILE_URI });
            }
            
            function onSuccess(imageURI) {
                var image = document.getElementById('fotoLocal');
                image.src = imageURI;
                subirImagen(imageURI)                             
            }
        
            function onFail(message) {
                alert('Failed because: ' + message);
            }
            
            function subirImagen(fileURL) {
            
                var options = new FileUploadOptions();
                options.fileKey = "imagen";
                options.fileName = fileURL.substr(fileURL.lastIndexOf('/') + 1);

                var ft = new FileTransfer();
                ft.upload(fileURL, encodeURI("http://jcesar.16mb.com/upload/upload.php"), uploadSuccess, uploadFail, options);
            }

            function uploadSuccess(r) {
                alert("Code = " + r.responseCode+" Response = " + r.response+" Sent = " + r.bytesSent);
                var image = document.getElementById('fotoServidor');
                image.src = r.response;
            }

            function uploadFail(error) {
                alert("An error has occurred: Code = " + error.code+ " upload error source " + error.source+" upload error target " + error.target);
            }
                                        
        </script>
    </head>
    <body>
        <div class="app">
            <h1>Apache Cordova</h1>
            <input type="button" onclick="hacerFoto();"  value="Hacer Foto">
            <img id="fotoLocal" src="" width="100px" height="100px">
            <img id="fotoServidor" src="" width="100px" height="100px">
        </div>
        <script type="text/javascript" src="cordova.js"></script>
    </body>
</html>

Parte 3 y final

Ya solo queda que nuestro servidor pueda recibir la imagen, para ello, como dije al principio, vamos a usar PHP. Para la prueba he usado un servidor gratuito de hostinger, pero no lo recomiendo para producción, podeis usar esa misma url para hacer pruebas o crearos uno vosotros mismos.

Este es el código PHP que se necesitaría:

<?php

$target_dir = "upload/";
$target_file = $target_dir . basename($_FILES["imagen"]["name"]);
move_uploaded_file($_FILES["imagen"]["tmp_name"], "./" . $_FILES["imagen"]["name"]);
echo "http://" . $_SERVER['SERVER_NAME'] . "/" . $target_file;

?>

Lo único que hace es coger la imagen subida y moverla (con move_uploade_file) de la carpeta temporal de subidas a la carpeta que nosotros queremos, en este caso la misma donde está el upload.php, y una vez subida, devuelve la ruta de la imagen donde se ha almacenado para que se la asignemos al src de nuestra imagen.

Fijaos en $_FILES[“imagen”], imagen es el nombre que pusimos en options.filekey, si cambiasemos ese nombre habría que cambiarlo también en el .php.

Espero que os haya gustado, y si tenéis algún problema no dudeis en comentar.

 

30 comentarios en “Captura de imagen con la cámara y subida a un servidor (PHP)

      1. Buen día

        Tengo el mismo problema, la app no muestra ningùn mensaje de error, pero no carga ni muestra la imágen en el servidor,
        tengo montado un servidor local en debian 8 php 5.6

        1. En que dispositivo estás probando? versiones de cordova CLI y de la plataforma en la que pruebas? versión del plugin? has intentado la depuración remota a ver si te sale algún error? porque es muy raro que no te salga ningún error en los callbacks si está fallando

  1. Excelente tutorial, muy bien explicado. Me ha sido de gran ayuda, muchas gracias por compartir tus conocimientos. Una pregunta, si quisiera enviar al server un formulario con 4 fotografías o menos, ¿qué me recomendarías?.

    1. Hola buenos dias, te comento hace algunos dias cree un proyecto con el cordova que instale en eclipse y me resulto un proyecto con una version de cordova muy antiguo, desarrolle una app y funciona muy bien, el problema esta al momento de colgarlo en google, que no acepta versionces de cordova intefiores a 3.5.0 o 4.1.0 … despues cree un nuevo proyecto pero desde la terminal de Ubuntu alli me salio un proyecto con version de cordova 5.1.1 suficiente para aprobar la restriccion, luego agregue los plugins como se indican en varios tutoriales y no tuve ningun problema, la dificultar es que a pesar de agregar los plugins estos no se enlazan de forma correcta con el codigo que uso para lebantar mi camara, detectar mi geolocalizacion o conectarme a la red, no esta reconociendo ningun plugin, algo que en la version antigua de mi proyecto si funcionaba, nose si estoy omitiendo algo o estoy haciendo algo mal, el codigo que uso en mi proyecto es el mismo que expones en este post, nose por que ahora en la version mas reciente de cordova, esos perifericos no funcionan, espero me puedas ayudar, gracias de antemano, saludos.

      1. Intenta empezar desde 0 siguiendo el tutorial desde el principio, porque se explica como crear el proyecto con el CLI y como añadir los plugins necesarios.

  2. ola amigo la verdad es que sube la imagen pero codificada como la descodificas en php osea una imagen que se llama photo.png me la guarda de esta manera acc%3D1%3Bdoc%3D10133 como descodificas esta imagen ??

    1. Hola. El problema en esos casos es el plugin camera que no devuelve el nombre correcto. Estás usando la última versión del plugin?
      Si usas la última versión y sigues con el problema, puedes cambiar varias cosas para poner tu el nombre que quieras.
      Si cambias esta linea del javascript
      options.fileName = fileURL.substr(fileURL.lastIndexOf(‘/’) + 1);
      por
      options.fileName = “ElNombreQueTuQuieras.png”; puedes mandar ya el nombre que tu quieras desde la app, pero hay el problema de que la imagen que estés subiendo no sea un .png
      Otra opción sería poner el nombre que tu quieras en el servidor, que ahí con PHP si podrás saber el mime type de la imagen y con ello poner tu la extensión que corresponda.

        1. Te estoy diciendo que es el plugin camera el que hace eso, cuando es de la galería a veces no obtiene el nombre original de la imagen y saca esas cosas raras.

          1. Yo utilizo ionic y el plugin es de ng-cordova creo que el plugin esta actualizado verificaré de nuevo sugieres que php haga un correo condiciones con el mimetype gracias bro por tus respuesta

  3. Hola, puedes ayudarme por favor he buscado como abrir imagénes desde la galeria pero siempre termina abriendo la cámara, por favor indicame que debería cambiar para escoger la imagen desde la galeria, aquí la función como está actualmente.

    navigator.camera.getPicture(onSuccess, onFail, { quality: 50, destinationType: Camera.DestinationType.DATA_URL});
    function onSuccess(imageURI) {
    var image = document.getElementById(‘fotoLocal’);
    image.src = imageURI;
    subirImagen(imageURI)
    }
    function onFail(message) {
    alert(‘Failed because: ‘ + message);
    }

    Gracias!!!!

    1. Buenas. Para usar la galería tienes que pasar la opción sourceType Camera.PictureSourceType.PHOTOLIBRARY

      sourceType: Camera.PictureSourceType.PHOTOLIBRARY

  4. Hola.
    Muy bueno el tutorial . Claro y bien explicado.
    Tengo un problema enla subida al servidor que me lanza el error Code 1 upload error source file…..

    Alguna pista?
    Gracias

    1. Hola.
      Estaba probando en un terminal con la Android 6.0.
      He probado en el emulador y sí funciona.
      Puede ser cosa de permisos?
      Creo recordar que en el mismo terminal, es decir con el mismo Android, unas pruebas que hice con el tutorial me funcionaron.

      1. Si usas las últimas versiones de los plugins no deberías tener problemas de permisos porque todos están actualizados para funcionar bien con los permisos de Android 6.

  5. Hola buen día, tengo una duda, he ejecutado el código y mi archivo upload.php esta en un proyecto local dentro de htdocs, por lo que la ruta queda algo asi

    ft.upload(Archivo,”http://ipdemiPc/zizicom/trizApi/images/upload.php”, win, fail, options);

    Y funciona, es decir, me sube la imagen, todo bien.

    El detalle viene cuando ya tengo el proyecto en un hosting real, es decir, ya no está en mi PC

    ft.upload(Archivo,”http://urlsitioweb/zizicom/trizApi/images/upload.php”, win, fail, options);

    me aparece en la ubicación un archivo con este mensaje:

    [18-Nov-2016 03:50:43 UTC] PHP Notice: Undefined index: file in /home/zizicom/public_html/trizApi/images/server.php on line 2

    ¿tengo que configurar en el servidor alguna especie de permisos de escritura en el directorio donde quiero que se guarden las imagenes?

    1. Pero estás usando el mismo código tanto en el javascript como en el PHP?

      Porque lo que te está diciendo es que “file” no está definido, pero en mi ejemplo he usado “imagen”, no “file” $_FILES[“imagen”][“name”].
      El primer valor (“imagen” en mi ejemplo), tiene que coincidir con el valor que uses en options.fileKey.

      También, si estás usando la versión 1.6.x del plugin, prueba con la versión 1.5.1, que parece que hay algunos errores en la versión 1.6.x

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *