Angular, PHP, and File Uploads
After having to take a few weeks off from development of my website, I’m happy to say that I’m back...and running headfirst into massive snags.
I’ve managed to connect Angularjs and MySQL with PHP after a long and protracted battle. I can now create articles/blog posts that have titles, dates, authors, and actual body content (though I’ve not gotten around to fetching it to display yet - that’s coming up).
Angularjs doesn’t really play well with FILE uploads - in my case I really want my beautiful blog to have header images...and it’s not really worked out well so far.
Upload a header image at the same time as the title/body of the blog but have the image go into my server file structure while only retaining a url for the purposes of the mysql database (it’s a bad idea to store images inside a database).
It seems that angular http.post doesn’t allow you to just plain old pass through a file, meaning that the only way to do this would be to have angular convert the image into something else. After a lot of research (going on 10 hours or so probably) I’ve figured out a solution - I think. There we some shortcuts (downloading premade angular controllers & services) but as that wouldn’t really have TAUGHT me anything (which is the primary goal of this exercise) I chose to ignore them aside from looking through the code for ideas.
The (potential) solution:
HTML5! I know, after all this work with php and javascript it’s weird to find a solution inside HTML of all things (at least it was to me), but there you have it.
Here’s my upload controller as it currently stands.
(function() {
var UploadController = function($scope, $http, $location) { //scope lets me pull stuff from the html, http lets me do a post pass to php, and location lets me redirect afterwards.
$scope.upload = function() {
var x;
var file = document.getElementById('blogheader').files[0], //javascript to pull out the FILE
reader = new FileReader(); //html5 filereader to convert it into base64
reader.onloadend = function(event){
x = event.target.result.match(/,(.*)$/)[1]; //here's my actual base64 result and a regex to discard things that get in the way.
$http.post('../../php/upload.php', { // this is my php file for the actual upload.
'posttitle': $scope.posttitle, // passing post title...
'postcontent': $scope.postcontent, // passing post content...
'blogheader': x // passing blog header!
})
.success(function(data) {
console.log(data); //Just used for debugging purposes to see what PHP returns, will get rid of this later.
$location.url('/'); // redirect to homepage after blog is submitted.
})
.error(function(data, status) {
console.log(data, status); //just used for debugging.
});
}
reader.readAsDataURL(file); // calling the html5 reader for the conversion.
};
};
.controller('UploadController', UploadController);
UploadController.$inject = ['$scope', '$http', '$location']; //this is a property of angularjs used to avoid getting your code broken by minify. I have this in all my controllers.
angular.module('myApp')
}());
<div ng-controller="UploadController">
<img ng-src="images/photos/{{windowSize}}/egypt-soccer-{{windowSize}}.jpg" alt="Soccer on the Nile" class="image__main">
<form name="submitForm" enctype="multipart/form-data" class="login__fields" method="post" novalidate ng-submit="upload()">
<input type="text" ng-model="posttitle" name="posttitle" placeholder="enter title here" required>
<br />
<textarea ng-model="postcontent" name="postcontent" placeholder="enter text here" required></textarea>
<br />
<input type="file" id="blogheader" name="blogheader" required>
<br />
<input type="submit" name="submit" value="Upload" ng-disabled="!submitForm.$valid">
</form>
</div>
And finally where my PHP currently stands (not finished yet):
$postdata = json_decode(file_get_contents("php://input"));
$posttitle = mysqli_real_escape_string($link, $postdata->posttitle);
$postcontent = mysqli_real_escape_string($link, $postdata->postcontent);
$blogheader = $postdata->blogheader;
echo base64_decode($blogheader);
Decode the json that I’m getting from angularjs and putting it into $postdata - NOTHING WILL WORK WITHOUT THIS
Assigning $posttitle, $postcontent, and $blogheader to their relevant POST-passed values.
Echoing the base64_decoded value of the $blogheader (image) to see where I’m at.
Getting blog posts into mysql (again), but this time also uploading the image to my server and getting the relevant url into the blog table.