Bootstrap Profile Image
Users are usually given the opportunity to change their profile image via some sort of profile form. The old school way of uploading an image via a form submission is to use a file <input> within the form and retrieve the image server-side using the php $_FILES variable and move_uploaded_file( ). The problem with this approach is that it is awkward because you need to deal with different image types, sizes and error handling. In addition, the user must wait for the form submission and page reload to complete before they see how the profile image looks. What if there was a better approach? The following outlines one such approach.
Creating The Form
The form utilizes a jquery plugin called Croppie. As stated on their website, Croppie is a fast, easy to use image cropping plugin with tons of configuration options! It allows the user to upload an image to their local browser, zoom and pan the image to get it just right, and then crop out a circular image for use. It pulls the croppie plugin up in a bootstrap modal dialog. The user then uploads and crops their image. The resulting image is then base64 encoded and inserted into both the background image for viewing and the hidden input for the form submission. My relevant form markup is shown below.
<h3>Profile Picture</h3> <div class="profile-pic-container h1"> <div class="profile-pic"> <input id="profile-picture-data" type="hidden" name="profile-picture-data" value=""> <a href="" data-toggle="modal" data-target="#imageupload"> <div id="profile-picture" class="profile-pic-text" style="background-image:url();"> S </div> </a> </div> </div> </div> <a href="" data-toggle="modal" data-target="#imageupload" class="btn btn-md btn-default light-icon">Add or Change</a>
The included CSS and javascript files are from Croppie except profile_image.js which is shown below:
$(document).ready(function(e){ demoUpload(); }); function dataURItoBlob(dataURI) { var split = dataURI.split(','), dataTYPE = split[0].match(/:(.*?);/)[1], binary = atob(split[1]), array = [] for(var i = 0; i < binary.length; i++) array.push(binary.charCodeAt(i)) return new Blob([new Uint8Array(array)], { type: dataTYPE }) } function demoUpload() { var $uploadCrop; function readFile(input) { if (input.files && input.files[0]) { var reader = new FileReader(); reader.onload = function (e) { $uploadCrop.croppie('bind', { url: e.target.result }); $('.upload-msg').hide(); $('#upload-demo').show(); $("#croppie-controls").show(); } reader.readAsDataURL(input.files[0]); } else { swal("Sorry - you're browser doesn't support the FileReader API"); } } $uploadCrop = $('#upload-demo').croppie({ viewport: { width: 200, height: 200, type: 'circle' }, boundary: { width: 300, height: 300 }, exif: true }); $('#uploadcroppie').on('change', function () { readFile(this); }); $('.upload-result').on('click', function (ev) { ev.preventDefault(); $uploadCrop.croppie('result', { type: 'canvas', size: 'viewport' }).then(function (resp) { $('#profile-picture').removeClass("profile-pic-text").addClass("profile-pic-img-bg").html(""); $('#profile-picture').css('background-image', 'url(' + resp + ')'); $('#profile-picture-data').val(resp); $("#imageupload").modal("hide"); }); }); $("#imageupload-cancel").on('click', function (e) { $("#imageupload").modal("hide"); }); }
Server-Side Image Handling
This is the best part in the eyes of a developer because it is extremely easy. All you need to do is decode the data string and put the resulting image where you want. Here’s the code:
$image_data = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $_POST["profile-picture-data")); if(!empty($image_data)) file_put_contents($path, $image_data);