Skip to content

Commit 04799ca

Browse files
Image validation per feedback
1 parent db94ad9 commit 04799ca

File tree

5 files changed

+215
-42
lines changed

5 files changed

+215
-42
lines changed

src/ApiBundle/Controller/Admin/UserController.php

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,19 @@ public function newAction(Request $request)
8383

8484
// If a file has been uploaded
8585
if ( null != $file ) {
86+
// First validate uploaded image. If errors found, return to same page with flash errors
87+
$imageErrors = $this->validateImage($request);
88+
if (!$imageErrors) {
89+
return $this->render('@ApiBundle/Resources/views/admin/user/new.html.twig', [
90+
'form' => $form->createView(),
91+
'attr' => array('enctype' => 'multipart/form-data'),
92+
]);
93+
}
8694
// Generate a unique name for the file before saving it
8795
$fileName = md5(uniqid()).'.'.$file->guessExtension();
8896

8997
// Move the file to the directory where images are stored
90-
$file->move($this->getParameter('images_profile_directory'), $fileName );
98+
$file->move($this->getParameter('images_profile_path'), $fileName );
9199

92100
// Update the 'image' property to store the Image file name
93101
// instead of its contents
@@ -138,7 +146,7 @@ public function editAction(User $user, Request $request)
138146
$currentFilename = $user->getImage();
139147
if ($user->getImage()) {
140148
$user->setImage(
141-
new File($this->getParameter('images_profile_directory').'/'.$currentFilename)
149+
new File($this->getParameter('images_profile_path').'/'.$currentFilename)
142150
);
143151
}
144152

@@ -168,11 +176,23 @@ public function editAction(User $user, Request $request)
168176

169177
// If a file has been uploaded
170178
if ( null != $file ) {
179+
// First validate uploaded image. If errors found, return to same page with flash errors
180+
$imageErrors = $this->validateImage($request);
181+
if (!$imageErrors) {
182+
return $this->render('@ApiBundle/Resources/views/admin/user/edit.html.twig', [
183+
'user' => $user,
184+
'current_image' => $currentFilename,
185+
'edit_form' => $editForm->createView(),
186+
'delete_form' => $deleteForm->createView(),
187+
'attr' => array('enctype' => 'multipart/form-data'),
188+
]);
189+
}
190+
171191
// Generate a unique name for the file before saving it
172192
$fileName = md5(uniqid()).'.'.$file->guessExtension();
173193

174194
// Move the file to the directory where images are stored
175-
$file->move($this->getParameter('images_profile_directory'), $fileName );
195+
$file->move($this->getParameter('images_profile_path'), $fileName );
176196

177197
// Update the 'image' property to store the Image file name
178198
// instead of its contents
@@ -259,6 +279,44 @@ private function setUserProfileData(User $user, \Symfony\Component\Form\Form $fo
259279
$user->setRoles($form['roles']->getData());
260280
}
261281

282+
private function validateImage(Request $request)
283+
{
284+
$locale = $request->getLocale();
285+
286+
// $file stores the uploaded Image file
287+
/** @var Symfony\Component\HttpFoundation\File\UploadedFile $file */
288+
$file = $request->files->get('image');
289+
290+
$imageConstraint = new Assert\Image();
291+
292+
// all constraint "options" can be set this way
293+
$imageConstraint->mimeTypes = ["image/jpeg", "image/jpg", "image/gif", "image/png"];
294+
$imageConstraint->mimeTypesMessage = 'Please upload a valid Image (jpeg/jpg/gif/png only within 1024k size';
295+
$imageConstraint->maxSize = 1024*1024;
296+
$imageConstraint->minWidth = 100;
297+
$imageConstraint->minHeight = 100;
298+
// $imageConstraint->payload->api_error = 'api.show_error_image';
299+
300+
// use the validator to validate the value
301+
$errors = $this->get('validator')->validate($file, $imageConstraint );
302+
303+
if (0 != count($errors)) {
304+
// this is *not* a valid image
305+
$errorArray = [];
306+
foreach ($errors as $error) {
307+
$constraint = $error->getConstraint();
308+
$errorItem = array(
309+
"error_description" => $error->getPropertyPath().': '.$error->getMessage().' '.$error->getInvalidValue(),
310+
"show_message" => $this->get('translator')->trans($constraint->payload['api_error'], array(), 'messages', $locale)
311+
);
312+
array_push($errorArray, $errorItem);
313+
$this->logMessageAndFlash(400, 'warning', $errorItem['error_description'], $this->get('translator')->trans('flash.image_error').' '.$errorItem['error_description'], $request->getLocale() );
314+
}
315+
return false;
316+
}
317+
318+
return true;
319+
}
262320

263321
private function logMessageAndFlash($code = 200, $type = 'success', $logMsg = '', $flashMsg = '', $locale = 'en')
264322
{

src/ApiBundle/Controller/AuthController.php

Lines changed: 87 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
use Symfony\Component\HttpFoundation\BinaryFileResponse;
4141
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
4242

43+
use Symfony\Component\Validator\Constraints as Assert;
44+
4345
/**
4446
* @Version({"1.0"})
4547
*
@@ -188,11 +190,16 @@ public function postRegisterAction(Request $request)
188190
// Validate Client credentials
189191
$this->validateClient($request);
190192

191-
// Set User data to ve validated next
192-
$this->setUserData($request, $user);
193+
// Set User data which will also return Image Validation errors, if any
194+
$validationErrorsImage = $this->setUserData($request, $user);
193195

194-
// Validate
195-
$validationGroups = array('Registration', 'profile_edit');
196+
// If Image Validtion returns error, then return errors
197+
if ( $validationErrorsImage ) {
198+
return $validationErrorsImage;
199+
}
200+
201+
// Validate rest of the input data
202+
$validationGroups = array('Registration');
196203
$validationErrors = $this->reportValidationErrors($user, $validationGroups, $request->getLocale());
197204

198205
// If Validtion returns error, then return errors
@@ -324,7 +331,8 @@ public function getProfileAction()
324331
'firstname' => $user->getFirstname(),
325332
'lastname' => $user->getLastname(),
326333
'dob' => $dobString,
327-
'email' => $user->getEmail()
334+
'email' => $user->getEmail(),
335+
'image_url' => $this->getParameter('images_profile_dir').$user->getImage()
328336
));
329337
}
330338

@@ -350,7 +358,7 @@ public function getProfilePicAction()
350358
$this->logAndThrowError(400, 'Invalid User', $this->get('translator')->trans('api.show_error_perm_show', array(), 'messages', $request->getLocale()), $request->getLocale());
351359
}
352360

353-
$file = $user->getImage() ? new File($this->getParameter('images_profile_directory').'/'.$user->getImage()) : null;
361+
$file = $user->getImage() ? new File($this->getParameter('images_profile_path').$user->getImage()) : null;
354362

355363
$response = new BinaryFileResponse($file);
356364
$response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT);
@@ -435,14 +443,10 @@ public function editProfilePicAction()
435443
$this->logAndThrowError(400, 'Invalid User', $this->get('translator')->trans('api.show_error_perm_show', array(), 'messages', $request->getLocale()), $request->getLocale());
436444
}
437445

438-
// Set User data to ve validated next
439-
$this->setUserPicData($request, $user);
446+
// Set User data which will also return Image Validation errors, if any
447+
$validationErrors = $this->setUserPicData($request, $user);
440448

441-
// Validate
442-
$validationGroups = array('profile_pic');
443-
$validationErrors = $this->reportValidationErrors($user, $validationGroups, $request->getLocale());
444-
445-
// If Validtion returns error, then return errors
449+
// If Image Validtion returns error, then return errors
446450
if ( $validationErrors ) {
447451
return $validationErrors;
448452
}
@@ -457,6 +461,7 @@ public function editProfilePicAction()
457461
return new JsonResponse(array(
458462
'code' => 201,
459463
'show_message' => $msg,
464+
'image_url' => $this->getParameter('images_profile_dir').$user->getImage()
460465
));
461466
}
462467

@@ -733,21 +738,12 @@ private function validateOldPassword(User $user, $oldPassword, $locale)
733738

734739
private function setUserData(Request $request, User $user)
735740
{
736-
// $file stores the uploaded Image file
737-
/** @var Symfony\Component\HttpFoundation\File\UploadedFile $file */
738-
$file = $request->files->get('image');
739-
740-
// If a file has been uploaded
741-
if ( null != $file ) {
742-
// Generate a unique name for the file before saving it
743-
$fileName = md5(uniqid()).'.'.$file->guessExtension();
744-
745-
// Move the file to the directory where images are stored
746-
$file->move($this->getParameter('images_profile_directory'), $fileName );
741+
// Set User data which will also return Validation errors, if any
742+
$validationErrors = $this->setUserPicData($request, $user);
747743

748-
// Update the 'image' property to store the Image file name
749-
// instead of its contents
750-
$user->setImage($this->getParameter('images_profile_directory').$fileName);
744+
// If Validtion returns error, then return errors
745+
if ( $validationErrors ) {
746+
return $validationErrors;
751747
}
752748

753749
$user->setUsername($request->request->get('username'));
@@ -765,25 +761,86 @@ private function setUserData(Request $request, User $user)
765761
if (!$timestamp) {
766762
$this->logAndThrowError(400, 'Date of Birth should be in MM/DD/YYYY format.', $this->get('translator')->trans('api.show_error_dob', array(), 'messages', $request->getLocale()), $request->getLocale());
767763
}
764+
765+
// return null to indicate success
766+
return null;
768767
}
769768

770769
private function setUserPicData(Request $request, User $user)
771770
{
771+
$locale = $request->getLocale();
772+
772773
// $file stores the uploaded Image file
773774
/** @var Symfony\Component\HttpFoundation\File\UploadedFile $file */
774775
$file = $request->files->get('image');
775776

776-
// If a file has been uploaded
777+
// File is Valid. Now save it.
777778
if ( null != $file ) {
779+
// First validate uploaded image. If errors found, return errors
780+
$imageErrors = $this->validateImage($request);
781+
if (!$imageErrors) {
782+
return $imageErrors;
783+
}
784+
778785
// Generate a unique name for the file before saving it
779786
$fileName = md5(uniqid()).'.'.$file->guessExtension();
780787

781788
// Move the file to the directory where images are stored
782-
$file->move($this->getParameter('images_profile_directory'), $fileName );
789+
$file->move($this->getParameter('images_profile_path'), $fileName );
783790

784791
// Update the 'image' property to store the Image file name
785792
// instead of its contents
786-
$user->setImage($this->getParameter('images_profile_directory').$fileName);
793+
$user->setImage($fileName);
794+
}
795+
796+
// Null is returned to indicate no errors
797+
return null;
798+
}
799+
800+
private function validateImage(Request $request)
801+
{
802+
$locale = $request->getLocale();
803+
804+
// $file stores the uploaded Image file
805+
/** @var Symfony\Component\HttpFoundation\File\UploadedFile $file */
806+
$file = $request->files->get('image');
807+
808+
$imageConstraint = new Assert\Image();
809+
810+
// all constraint "options" can be set this way
811+
$imageConstraint->mimeTypes = ["image/jpeg", "image/jpg", "image/gif", "image/png"];
812+
$imageConstraint->mimeTypesMessage = 'Please upload a valid Image (jpeg/jpg/gif/png only within 1024k size';
813+
$imageConstraint->maxSize = 1024*1024;
814+
$imageConstraint->minWidth = 100;
815+
$imageConstraint->minHeight = 100;
816+
// $imageConstraint->payload->api_error = 'api.show_error_image';
817+
818+
// use the validator to validate the value
819+
$errors = $this->get('validator')->validate($file, $imageConstraint );
820+
821+
if (0 != count($errors)) {
822+
// this is *not* a valid image
823+
$errorArray = [];
824+
foreach ($errors as $error) {
825+
$constraint = $error->getConstraint();
826+
$errorItem = array(
827+
"error_description" => $error->getPropertyPath().': '.$error->getMessage().' '.$error->getInvalidValue(),
828+
"show_message" => $this->get('translator')->trans($constraint->payload['api_error'], array(), 'messages', $locale)
829+
);
830+
array_push($errorArray, $errorItem);
831+
$this->logMessage(400, $errorItem['error_description'] );
832+
}
833+
834+
return new JsonResponse(array(
835+
"code" => 400,
836+
"error" => "Bad Request",
837+
"error_description" => $errorArray[0]['error_description'],
838+
"show_message" => $errorArray[0]['show_message'],
839+
'errors' => $errorArray
840+
));
841+
} else {
842+
// Null is returned to indicate no errors
843+
return null;
787844
}
788845
}
789846

src/ApiBundle/Controller/UserController.php

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,20 @@ public function newAction(Request $request)
7272

7373
// If a file has been uploaded
7474
if ( null != $file ) {
75+
// First validate uploaded image. If errors found, return to same page with flash errors
76+
$imageErrors = $this->validateImage($request);
77+
if (!$imageErrors) {
78+
return $this->render('@ApiBundle/Resources/views/user/new.html.twig', [
79+
'form' => $form->createView(),
80+
'attr' => array('enctype' => 'multipart/form-data'),
81+
]);
82+
}
83+
7584
// Generate a unique name for the file before saving it
7685
$fileName = md5(uniqid()).'.'.$file->guessExtension();
7786

7887
// Move the file to the directory where images are stored
79-
$file->move($this->getParameter('images_profile_directory'), $fileName );
88+
$file->move($this->getParameter('images_profile_path'), $fileName );
8089

8190
// Update the 'image' property to store the Image file name
8291
// instead of its contents
@@ -159,7 +168,7 @@ public function editAction(User $user, Request $request)
159168
$currentFilename = $user->getImage();
160169
if ($user->getImage()) {
161170
$user->setImage(
162-
new File($this->getParameter('images_profile_directory').'/'.$currentFilename)
171+
new File($this->getParameter('images_profile_path').'/'.$currentFilename)
163172
);
164173
}
165174

@@ -176,11 +185,22 @@ public function editAction(User $user, Request $request)
176185

177186
// If a file has been uploaded
178187
if ( null != $file ) {
188+
// First validate uploaded image. If errors found, return to same page with flash errors
189+
$imageErrors = $this->validateImage($request);
190+
if (!$imageErrors) {
191+
return $this->render('@ApiBundle/Resources/views/user/edit.html.twig', [
192+
'user' => $user,
193+
'current_image' => $currentFilename,
194+
'edit_form' => $editForm->createView(),
195+
'attr' => array('enctype' => 'multipart/form-data'),
196+
]);
197+
}
198+
179199
// Generate a unique name for the file before saving it
180200
$fileName = md5(uniqid()).'.'.$file->guessExtension();
181201

182202
// Move the file to the directory where images are stored
183-
$file->move($this->getParameter('images_profile_directory'), $fileName );
203+
$file->move($this->getParameter('images_profile_path'), $fileName );
184204

185205
// Update the 'image' property to store the Image file name
186206
// instead of its contents
@@ -239,6 +259,45 @@ private function setUserProfileData(User $user, \Symfony\Component\Form\Form $fo
239259
$user->setEnabled(true);
240260
}
241261

262+
private function validateImage(Request $request)
263+
{
264+
$locale = $request->getLocale();
265+
266+
// $file stores the uploaded Image file
267+
/** @var Symfony\Component\HttpFoundation\File\UploadedFile $file */
268+
$file = $request->files->get('image');
269+
270+
$imageConstraint = new Assert\Image();
271+
272+
// all constraint "options" can be set this way
273+
$imageConstraint->mimeTypes = ["image/jpeg", "image/jpg", "image/gif", "image/png"];
274+
$imageConstraint->mimeTypesMessage = 'Please upload a valid Image (jpeg/jpg/gif/png only within 1024k size';
275+
$imageConstraint->maxSize = 1024*1024;
276+
$imageConstraint->minWidth = 100;
277+
$imageConstraint->minHeight = 100;
278+
// $imageConstraint->payload->api_error = 'api.show_error_image';
279+
280+
// use the validator to validate the value
281+
$errors = $this->get('validator')->validate($file, $imageConstraint );
282+
283+
if (0 != count($errors)) {
284+
// this is *not* a valid image
285+
$errorArray = [];
286+
foreach ($errors as $error) {
287+
$constraint = $error->getConstraint();
288+
$errorItem = array(
289+
"error_description" => $error->getPropertyPath().': '.$error->getMessage().' '.$error->getInvalidValue(),
290+
"show_message" => $this->get('translator')->trans($constraint->payload['api_error'], array(), 'messages', $locale)
291+
);
292+
array_push($errorArray, $errorItem);
293+
$this->logMessageAndFlash(400, 'warning', $errorItem['error_description'], $this->get('translator')->trans('flash.image_error').' '.$errorItem['error_description'], $request->getLocale() );
294+
}
295+
return false;
296+
}
297+
298+
return true;
299+
}
300+
242301
private function logMessageAndFlash($code = 200, $type = 'success', $logMsg = '', $flashMsg = '', $locale = 'en')
243302
{
244303
$this->logMessage($code, $type, $logMsg);

0 commit comments

Comments
 (0)