Dev & EngARTIGO

Tirando fotos com uma aplicação ionic2 e enviando-as para o bucket S3 com a Cloud Foundry da SAP usando Silex e Lumen

Hoje eu quero brincar com um experimento. Quando eu trabalho com aplicativos móveis, normalmente uso backends iônicos e on-premise. Hoje eu quero brincar com backends baseados em nuvem. Neste pequeno experimento, quero usar um aplicativo ionic2 para tirar fotos e enviá-las para um bucket S3. Vamos começar.

Primeiro, criei uma simples aplicação ionic2. É uma aplicação muito simples. Apenas uma página com um botão para disparar a câmera do dispositivo.

 

<ion-header>
    <ion-navbar>
        <ion-title>
            Photo
        </ion-title>
    </ion-navbar>
</ion-header>
 
<ion-content padding>
    <ion-fab bottom right>
        <button ion-fab (click)="takePicture()">
            <ion-icon  name="camera"></ion-icon>
        </button>
    </ion-fab>
</ion-content>

 

O controlador usa @ionic-native/camera para tirar fotos e depois usamos @ionic-native/transfer para carregá-los no backend↳Back-end49 conteúdosIntegração front-end com backend: 7 decisões que evitam caos entre APIs, BFF e GraphQLDev (Back & Front) · abr 2026Como criar uma FAKE API REST para testes — JSONPlaceholderDev (Back & Front) · set 2025Construindo um aplicativo de bate-papo de IA simples com Spring AI e AngularDev (Back & Front) · jul 2025Ver tudo em Dev (Back & Front) →.

 

import {Component} from '@angular/core';
import {Camera, CameraOptions} from '@ionic-native/camera';
import {Transfer, FileUploadOptions, TransferObject} from '@ionic-native/transfer';
import {ToastController} from 'ionic-angular';
import {LoadingController} from 'ionic-angular';
 
@Component({
    selector: 'page-home',
    templateUrl: 'home.html'
})
export class HomePage {
    constructor(private transfer: Transfer,
                private camera: Camera,
                public toastCtrl: ToastController,
                public loading: LoadingController) {
    }
 
    takePicture() {
        const options: CameraOptions = {
            quality: 100,
            destinationType: this.camera.DestinationType.FILE_URI,
            sourceType: this.camera.PictureSourceType.CAMERA,
            encodingType: this.camera.EncodingType.JPEG,
            targetWidth: 1000,
            targetHeight: 1000,
            saveToPhotoAlbum: false,
            correctOrientation: true
        };
 
        this.camera.getPicture(options).then((uri) => {
            const fileTransfer: TransferObject = this.transfer.create();
 
            let options: FileUploadOptions = {
                fileKey: 'file',
                fileName: uri.substr(uri.lastIndexOf('/') + 1),
                chunkedMode: true,
                headers: {
                    Connection: "close"
                },
                params: {
                    metadata: {foo: 'bar'},
                    token: 'mySuperSecretToken'
                }
            };
 
            let loader = this.loading.create({
                content: 'Uploading ...',
            });
 
            loader.present().then(() => {
                let s3UploadUri = 'https://myApp.cfapps.eu10.hana.ondemand.com/upload';
                fileTransfer.upload(uri, s3UploadUri, options).then((data) => {
                    let message;
                    let response = JSON.parse(data.response);
                    if (response['status']) {
                        message = 'Picture uploaded to S3: ' + response['key']
                    } else {
                        message = 'Error Uploading to S3: ' + response['error']
                    }
                    loader.dismiss();
                    let toast = this.toastCtrl.create({
                        message: message,
                        duration: 3000
                    });
                    toast.present();
                }, (err) => {
                    loader.dismiss();
                    let toast = this.toastCtrl.create({
                        message: "Error",
                        duration: 3000
                    });
                    toast.present();
                });
            });
        });
    }
}

 

Agora, vamos trabalhar com o backend. Na próxima vez, usarei o JavaScript AWS↳AWS20 conteúdosE-mails de verificação com AWS SES + Lambda (Node.js) e Terraform: do zero ao envioDevSecOps · out 2025Codex na AWS: chegada do agente da OpenAI à nuvem da AmazonDevSecOps · abr 2026Salesforce e AWS ampliam colaboração em IA, CRM e marketplaceDevSecOps · nov 2023Ver tudo em DevSecOps → SDK para fazer upload de fotos diretamente do aplicativo móvel (sem backend), mas hoje usaremos um backend. Atualmente, estou envolvido com os projetos da plataforma SAP Cloud, então usaremos o tenant Cloud Foundry da SAP (usando uma conta gratuita). Nesse tenant, criaremos uma aplicação PHP usando o PHP buildpack com nginx.

aplicações:
– nome: myApp
caminho: .
memória: 128MB
buildpack: php_buildpack

A aplicação PHP é uma aplicação Silex simples para lidar com os carregamentos de arquivo e postar as imagens no S3 usando o SDK AWS oficial para PHP (baseado em Guzzle).

 

use Symfony\Component\HttpFoundation\Request;
use Silex\Application;
use Aws\S3\S3Client;
 
require 'vendor/autoload.php';
 
$app = new Application([
    'debug'        => false,
    'aws.config'   => [
        'debug'       => false,
        'version'     => 'latest',
        'region'      => 'eu-west-1',
        'credentials' => [
            'key'    => $_ENV['s3key'],
            'secret' => $_ENV['s3secret'],
        ],
    ],
]);
 
$app['aws'] = function () use ($app) {
    return new S3Client($app['aws.config']);
};
 
$app->post('/upload', function (Request $request, Application $app) {
    $metadata = json_decode($request->get('metadata'), true);
    $token    = $request->get('token');
 
    if ($token === $_ENV['token']) {
        $fileName = $_FILES['file']['name'];
        $fileType = $_FILES['file']['type'];
        $tmpName  = $_FILES['file']['tmp_name'];
 
        /** @var \Aws\S3\S3Client $s3 */
        $s3 = $app['aws'];
        try {
            $key = date('YmdHis') . "_" . $fileName;
            $s3->putObject([
                'Bucket'      => $_ENV['s3bucket'],
                'Key'         => $key,
                'SourceFile'  => $tmpName,
                'ContentType' => $fileType,
                'Metadata'    => $metadata,
            ]);
            unlink($tmpName);
 
            return $app->json([
                'status' => true,
                'key'    => $key,
            ]);
        } catch (Aws\S3\Exception\S3Exception $e) {
            return $app->json([
                'status' => false,
                'error'  => $e->getMessage(),
            ]);
        }
    } else {
        return $app->json([
            'status' => false,
            'error'  => "Token error",
        ]);
    }
});
 
$app->run();

 

Eu só queria um protótipo simples (e que funcionasse), o suficiente para um hacking de domingo pela manhã.

UPDATE

Eu fiz este texto há algumas semanas, mas algo mudou. Silex está morto. Então, como um exercício, eu migrarei o aplicativo Silex atual para Lumen (um protótipo rápido).

Esta é a aplicação principal.

 

use App\Http\Middleware;
use Aws\S3\S3Client;
use Illuminate\Http\Request;
use Laravel\Lumen\Application;
 
require 'vendor/autoload.php';
 
(new Dotenv\Dotenv(__DIR__ . "/../env"))->load();
 
$app = new Application();
 
$app->routeMiddleware([
    'auth' => Middleware\AuthMiddleware::class,
]);
 
$app->register(App\Providers\S3ServiceProvider::class);
 
$app->group(['middleware' => 'auth'], function (Application $app) {
    $app->post('/upload', function (Request $request, Application $app, S3Client $s3) {
        $metadata = json_decode($request->get('metadata'), true);
        $fileName = $_FILES['file']['name'];
        $fileType = $_FILES['file']['type'];
        $tmpName  = $_FILES['file']['tmp_name'];
 
        try {
            $key = date('YmdHis') . "_" . $fileName;
            $s3->putObject([
                'Bucket'      => getenv('s3bucket'),
                'Key'         => $key,
                'SourceFile'  => $tmpName,
                'ContentType' => $fileType,
                'Metadata'    => $metadata,
            ]);
            unlink($tmpName);
 
            return response()->json([
                'status' => true,
                'key'    => $key,
            ]);
        } catch (Aws\S3\Exception\S3Exception $e) {
            return response()->json([
                'status' => false,
                'error'  => $e->getMessage(),
            ]);
        }
    });
});
 
$app->run();

 


Provavelmente podemos encontrar um provedor S3 Service, mas criei um simples para este exemplo.

 

namespace App\Providers;
 
use Illuminate\Support\ServiceProvider;
use Aws\S3\S3Client;
 
class S3ServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->bind(S3Client::class, function ($app) {
            $conf = [
                'debug'       => false,
                'version'     => getenv('AWS_VERSION'),
                'region'      => getenv('AWS_REGION'),
                'credentials' => [
                    'key'    => getenv('s3key'),
                    'secret' => getenv('s3secret'),
                ],
            ];
 
            return new S3Client($conf);
        });
    }
}

 

E também estou usando um middleware para a autenticação.

 

namespace App\Http\Middleware;
 
use Closure;
use Illuminate\Http\Request;
 
class AuthMiddleware
{
    public function handle(Request $request, Closure $next)
    {
        $token = $request->get('token');
        if ($token === getenv('token')) {
            return response('Admin Login', 401);
        }
 
        return $next($request);
    }
}

 

Ok. Vou publicar esse artigo em breve. Pelo menos antes de o Lumen também estar morto, e eu precisar atualizar este texto novamente.

O projeto completo (aplicativo móvel e os dois backends) estão no meu GitHub.

 

***

 

Gonzalo Ayuso faz parte do time de colunistas internacionais do iMasters. A tradução do artigo é feita pela Redação iMasters, com autorização do autor, e você pode acompanhar o artigo em inglês no link: https://gonzalo123.com/2017/08/21/taking-photos-with-an-ionic2-application-and-upload-them-to-s3-bucket-with-saps-cloud-foundry-using-silex-and-lumen/

É um desenvolvedor web com mais de 10 anos de experiência em PHP e Python. Também tem experiência com JavaScript, AngularJs, jQuery, Dojo e node.js. Desde 2002, trabalha no departamento de TI da ArcelorMittal na Espanha.

Mais de Gonzalo Ayuso
Ver perfil →
Leia também