Skip to content

Instantly share code, notes, and snippets.

@jeremeamia
Last active December 10, 2015 23:19
Show Gist options
  • Save jeremeamia/4508451 to your computer and use it in GitHub Desktop.
Save jeremeamia/4508451 to your computer and use it in GitHub Desktop.
Funny face sharing Silex app using Amazon S3 and Amazon DynamoDB for a presentation at the Seattle PHP Meetup group (<http://joind.in/8035>). This app is meant to be run on an AWS Elastic Beanstalk stack. The contents of the assets folder are excluded, but it mainly contained the Twitter Bootstrap CSS and JavaScript code.
Resources:
AWSEBAutoScalingLaunchConfiguration:
Properties:
IamInstanceProfile: arn:aws:iam::123456789012:instance-profile/demo
{
"require": {
"aws/aws-sdk-php": "2.*",
"silex/silex": "1.0.*@dev",
"twig/twig": ">=1.8,<2.0-dev"
},
"minimum-stability": "dev"
}
<?php
// Load Composer Autoloader
require __DIR__ . '/vendor/autoload.php';
use Aws\Common\Aws;
use Aws\Common\Enum\Region;
use Aws\S3\Enum\CannedAcl;
use Guzzle\Iterator\MapIterator;
use Silex\Application;
use Silex\Provider\TwigServiceProvider;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Request;
// Configure Silex App
$app = new Application;
$app->register(new TwigServiceProvider, array(
'twig.path' => __DIR__ . '/views',
));
$app['aws'] = $app->share(function () {
return Aws::factory(['region' => Region::OREGON]);
});
// Index Route
$app->get('/', function () use ($app) {
// Get funny-face records from DynamoDB
$faces = $app['aws']->get('dynamodb')->getIterator('Scan', ['TableName' => 'demo']);
// Transform DynamoDB results into simple key-value pairs via closure
$faces = new MapIterator($faces, function($face) {
foreach ($face as &$value) {
$value = $value['S'];
}
return $face;
});
return $app['twig']->render('index.twig', [
'title' => 'Show Me Some Funny Faces!',
'faces' => $faces
]);
});
// Add Route
$app->match('/add', function (Request $request) use ($app) {
// If the form was submitted, process the input
if ('POST' == $request->getMethod()) {
try {
// Make sure the image was uploaded
$file = $request->files->get('faceImage');
if (!$file instanceof UploadedFile || $file->getError()) {
throw new RuntimeException('The file was not uploaded to the server.');
}
// Write the image to S3
$app['aws']->get('s3')->putObject([
'Bucket' => 'funny-face',
'Key' => $file->getFileName(),
'Body' => fopen($file->getPathname(), 'r'),
'ACL' => CannedAcl::PUBLIC_READ,
]);
// Write the funny-face record to DynamoDB
$app['aws']->get('dynamodb')->putItem([
'TableName' => 'demo',
'Item' => [
'src' => ['S' => 'http://funny-face.s3.amazonaws.com/' . $file->getFileName()],
'caption' => ['S' => $request->request->get('faceCaption', 'No caption.')],
],
]);
// Display a success message
$alert = ['type' => 'success', 'message' => 'Congrats, you uploaded a new funny face.'];
} catch (Exception $e) {
// Display an error message
$alert = ['type' => 'error', 'message' => 'Sorry, there was a problem uploading the new funny face.'];
}
}
return $app['twig']->render('add.twig', [
'title' => 'Add a New Funny Face!',
'alert' => isset($alert) ? $alert : null,
]);
});
// Run the App
$app->run();
{% include 'header.twig' %}
{% if data %}<pre>{{ data }}</pre>{% endif %}
<form action="{{ app.request.baseUrl ~ '/add' }}" method="post" class="form-horizontal" enctype="multipart/form-data">
<div class="control-group">
<label class="control-label" for="faceImage">Funny Face</label>
<div class="controls">
<input type="file" name="faceImage" id="faceImage">
</div>
</div>
<div class="control-group">
<label class="control-label" for="faceCaption">Caption</label>
<div class="controls">
<input type="text" name="faceCaption" id="faceCaption" placeholder="e.g. MOAR FOOD!!!" class="input-xxlarge" maxlength="75">
</div>
</div>
<div class="control-group">
<div class="controls">
<button type="submit" class="btn btn-primary"><b class="icon-ok icon-white"></b> Add Funny Face</button>
<a href="{{ app.request.baseUrl ~ '/' }}" class="btn"><b class="icon-chevron-left"></b> Go Back</a>
</div>
</div>
</form>
{% include 'footer.twig' %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{{ title }}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="author" content="Jeremy Lindblom">
<link href="assets/css/bootstrap.min.css" rel="stylesheet">
<style>
body {background: url(assets/img/subtlenet2.png) repeat;}
.funny-face {display: inline-block; width: 190px; margin: 0 30px 10px 0;}
.funny-face .caption {text-align: center; font-size: 85%;}
</style>
<link href="assets/css/bootstrap-responsive.min.css" rel="stylesheet">
<!--[if lt IE 9]><script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
</head>
<body>
<div class="container">
<h1>{{ title }}</h1>
{% if alert %}
<div class="alert alert-{{ alert.type }}">
<button type="button" class="close" data-dismiss="alert">&times;</button>
<strong>{{ alert.type|capitalize }}!</strong> {{ alert.message }}
</div>
{% endif %}
{% include 'header.twig' %}
<p><a href="{{ app.request.baseUrl ~ '/add' }}" class="btn"><b class="icon-plus-sign"></b> Add a Funny Face</a></p>
<div class="row-fluid">
{% for face in faces %}
<div class="funny-face">
<img src="{{ face.src }}" class="img-polaroid">
<p class="caption">{{ face.caption }}</p>
</div>
{% endfor %}
</div>
{% include 'footer.twig' %}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment