Tutorials, PHP & MySQL, Blog, Demos

Creating a blog from scratch with PHP - Part 9 Cover Image

Blog Series


In this tutorial we will add the ability to add an image for each post.

admin demo: https://demos.daveismyname.blog/simpleblog-coverphoto/admin

username: demo
password: demo

The image will be added into another column of the database table so add another column your database table called postImage that's a varchar data type and uses 255 chars.

postImage

First lets update the add-post.php

After the form is submitted, set the path to where uploaded images will go. Make sure to make a folder in the root called images this is where the images will be uploaded to,

// location where initial upload will be moved to
$target = "images/" . $_FILES['postImage']['name'];
$path = '../'.$target;

Next, add a check to ensure only image extensions are used. At the same time call move_uploaded_file() and pass in the tmp name of the file and the upload path.

if(isset($_FILES['postImage'])){

	// find thevtype of image
	switch ($_FILES["postImage"]["type"]) {
	case $_FILES["postImage"]["type"] == "image/gif":
	    move_uploaded_file($_FILES["postImage"]["tmp_name"], $path);
	    break;
	case $_FILES["postImage"]["type"] == "image/jpeg":
	       move_uploaded_file($_FILES["postImage"]["tmp_name"], $path);
	    break;
	case $_FILES["postImage"]["type"] == "image/pjpeg":
	       move_uploaded_file($_FILES["postImage"]["tmp_name"], $path);
	    break;
	case $_FILES["postImage"]["type"] == "image/png":
	    move_uploaded_file($_FILES["postImage"]["tmp_name"], $path);
	    break;
	case $_FILES["postImage"]["type"] == "image/x-png":
	    move_uploaded_file($_FILES["postImage"]["tmp_name"], $path);
	    break;

	default:
	    $error[] = 'Wrong image type selected. Only JPG, PNG or GIF accepted!.';
	}

}

After the post has been saved check if there has been an image uploaded and if so then save it in the database:

if(isset($_FILES['postImage'])){

	$stmt = $db->prepare('UPDATE blog_posts SET postImage = :image WHERE postID = :postID') ;
    $stmt->execute(array(
        ':postID' => $postID,
        ':image' => $target
    ));
}

For the form to be able to upload files it needs a new attribute  enctype="multipart/form-data"

<form action='' method='post' enctype="multipart/form-data">

The file upload element is very simple, its an input with a type of file.

<p><label>Image</label><br />
<input type='file' name='postImage'></p>

Putting it all together:

<?php //include config
require_once('../includes/config.php');

//if not logged in redirect to login page
if(!$user->is_logged_in()){ header('Location: login.php'); }
?>
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Admin - Add Post</title>
  <link rel="stylesheet" href="../style/normalize.css">
  <link rel="stylesheet" href="../style/main.css">
  <script src="//tinymce.cachefly.net/4.0/tinymce.min.js"></script>
  <script>
          tinymce.init({
              selector: "textarea",
              plugins: [
                  "advlist autolink lists link image charmap print preview anchor",
                  "searchreplace visualblocks code fullscreen",
                  "insertdatetime media table contextmenu paste"
              ],
              toolbar: "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image"
          });
  </script>
  <script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-46100971-1', 'auto');
ga('send', 'pageview');
</script>
</head>
<body>

<div id="wrapper">

	<?php include('menu.php');?>
	<p><a href="./">Blog Admin Index</a></p>

	<h2>Add Post</h2>

	<?php

	//if form has been submitted process it
	if(isset($_POST['submit'])){

		// location where initial upload will be moved to
		$target = "images/" . $_FILES['postImage']['name'];
		$path = '../'.$target;

		//collect form data
		extract($_POST);

		//very basic validation
		if($postTitle ==''){
			$error[] = 'Please enter the title.';
		}

		if($postDesc ==''){
			$error[] = 'Please enter the description.';
		}

		if($postCont ==''){
			$error[] = 'Please enter the content.';
		}

		if(isset($_FILES['postImage'])){

			// find thevtype of image
			switch ($_FILES["postImage"]["type"]) {
			case $_FILES["postImage"]["type"] == "image/gif":
			    move_uploaded_file($_FILES["postImage"]["tmp_name"], $path);
			    break;
			case $_FILES["postImage"]["type"] == "image/jpeg":
			       move_uploaded_file($_FILES["postImage"]["tmp_name"], $path);
			    break;
			case $_FILES["postImage"]["type"] == "image/pjpeg":
			       move_uploaded_file($_FILES["postImage"]["tmp_name"], $path);
			    break;
			case $_FILES["postImage"]["type"] == "image/png":
			    move_uploaded_file($_FILES["postImage"]["tmp_name"], $path);
			    break;
			case $_FILES["postImage"]["type"] == "image/x-png":
			    move_uploaded_file($_FILES["postImage"]["tmp_name"], $path);
			    break;

			default:
			    $error[] = 'Wrong image type selected. Only JPG, PNG or GIF accepted!.';
			}

		}

		if(!isset($error)){

			try {

				$postSlug = slug($postTitle);

				//insert into database
				$stmt = $db->prepare('INSERT INTO blog_posts (postTitle,postSlug,postDesc,postCont,postDate,postTags) VALUES (:postTitle, :postSlug, :postDesc, :postCont, :postDate, :postTags)') ;
				$stmt->execute(array(
					':postTitle' => $postTitle,
					':postSlug' => $postSlug,
					':postDesc' => $postDesc,
					':postCont' => $postCont,
					':postDate' => date('Y-m-d H:i:s'),
                    ':postTags' => $postTags
				));
				$postID = $db->lastInsertId();

				if(isset($_FILES['postImage'])){

	            	$stmt = $db->prepare('UPDATE blog_posts SET postImage = :image WHERE postID = :postID') ;
		            $stmt->execute(array(
		                ':postID' => $postID,
		                ':image' => $target
		            ));
	        	}

				//add categories
				if(is_array($catID)){
					foreach($_POST['catID'] as $catID){
						$stmt = $db->prepare('INSERT INTO blog_post_cats (postID,catID)VALUES(:postID,:catID)');
						$stmt->execute(array(
							':postID' => $postID,
							':catID' => $catID
						));
					}
				}

				//redirect to index page
				header('Location: index.php?action=added');
				exit;

			} catch(PDOException $e) {
			    echo $e->getMessage();
			}

		}

	}

	//check for any errors
	if(isset($error)){
		foreach($error as $error){
			echo '<p class="error">'.$error.'</p>';
		}
	}
	?>

	<form action='' method='post' enctype="multipart/form-data">

		<p><label>Title</label><br />
		<input type='text' name='postTitle' value='<?php if(isset($error)){ echo $_POST['postTitle'];}?>'></p>

		<p><label>Image</label><br />
		<input type='file' name='postImage'></p>

		<p><label>Description</label><br />
		<textarea name='postDesc' cols='60' rows='10'><?php if(isset($error)){ echo $_POST['postDesc'];}?></textarea></p>

		<p><label>Content</label><br />
		<textarea name='postCont' cols='60' rows='10'><?php if(isset($error)){ echo $_POST['postCont'];}?></textarea></p>

        <p><label>Tags (comma seperated)</label><br />
        <input type='text' name='postTags' value='<?php if(isset($error)){ echo $_POST['postTags'];}?>' style="width:400px;"></p>


        <fieldset>
			<legend>Categories</legend>

			<?php	

			$stmt2 = $db->query('SELECT catID, catTitle FROM blog_cats ORDER BY catTitle');
			while($row2 = $stmt2->fetch()){

				if(isset($_POST['catID'])){

					if(in_array($row2['catID'], $_POST['catID'])){
                       $checked="checked='checked'";
                    }else{
                       $checked = null;
                    }
				}

			    echo "<input type='checkbox' name='catID[]' value='".$row2['catID']."' $checked> ".$row2['catTitle']."<br />";
			}

			?>

		</fieldset>

		<p><input type='submit' name='submit' value='Submit'></p>

	</form>

</div>

The edit-post.php page is essentially the same steps as above the only difference is postImage needs to be added to the select query:

$stmt = $db->prepare('SELECT postID, postTitle, postDesc, postCont, postTags, postImage FROM blog_posts WHERE postID = :postID');

When showing the file upload element also show the image if there has been one uploaded.

<p><label>Image</label><br />
<input type='file' name='postImage'></p>

<?php if ($row['postImage'] !=''){ ?>
	<p><img src="<?=$url.$row['postImage'];?>"></p>
<?php } ?>

I've added a new variable to config.php called $url this is the full url of the website. This allows the image to have a full path when being displayed.

Add this to config.php (put your own website address)

$url = 'https://yourdomain.com/';

The complete edit-post.php page looks like:

<?php //include config
require_once('../includes/config.php');

//if not logged in redirect to login page
if(!$user->is_logged_in()){ header('Location: login.php'); }
?>
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Admin - Edit Post</title>
  <link rel="stylesheet" href="../style/normalize.css">
  <link rel="stylesheet" href="../style/main.css">
  <script src="//tinymce.cachefly.net/4.0/tinymce.min.js"></script>
  <script>
          tinymce.init({
              selector: "textarea",
              plugins: [
                  "advlist autolink lists link image charmap print preview anchor",
                  "searchreplace visualblocks code fullscreen",
                  "insertdatetime media table contextmenu paste"
              ],
              toolbar: "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image"
          });
  </script>
  <script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-46100971-1', 'auto');
ga('send', 'pageview');
</script>
</head>
<body>

<div id="wrapper">

	<?php include('menu.php');?>
	<p><a href="./">Blog Admin Index</a></p>

	<h2>Edit Post</h2>


	<?php

	//if form has been submitted process it
	if(isset($_POST['submit'])){

		// location where initial upload will be moved to
		$target = "images/" . $_FILES['postImage']['name'];
		$path = '../'.$target;

		//collect form data
		extract($_POST);

		//very basic validation
		if($postID ==''){
			$error[] = 'This post is missing a valid id!.';
		}

		if($postTitle ==''){
			$error[] = 'Please enter the title.';
		}

		if($postDesc ==''){
			$error[] = 'Please enter the description.';
		}

		if($postCont ==''){
			$error[] = 'Please enter the content.';
		}

		if(isset($_FILES['postImage'])){

			// find thevtype of image
			switch ($_FILES["postImage"]["type"]) {
			case $_FILES["postImage"]["type"] == "image/gif":
			    move_uploaded_file($_FILES["postImage"]["tmp_name"], $path);
			    break;
			case $_FILES["postImage"]["type"] == "image/jpeg":
			       move_uploaded_file($_FILES["postImage"]["tmp_name"], $path);
			    break;
			case $_FILES["postImage"]["type"] == "image/pjpeg":
			       move_uploaded_file($_FILES["postImage"]["tmp_name"], $path);
			    break;
			case $_FILES["postImage"]["type"] == "image/png":
			    move_uploaded_file($_FILES["postImage"]["tmp_name"], $path);
			    break;
			case $_FILES["postImage"]["type"] == "image/x-png":
			    move_uploaded_file($_FILES["postImage"]["tmp_name"], $path);
			    break;

			default:
			    $error[] = 'Wrong image type selected. Only JPG, PNG or GIF accepted!.';
			}

		}

		if(!isset($error)){

			try {

				$postSlug = slug($postTitle);

				//insert into database
	            $stmt = $db->prepare('UPDATE blog_posts SET postTitle = :postTitle, postSlug = :postSlug, postDesc = :postDesc, postCont = :postCont, postTags = :postTags WHERE postID = :postID') ;
	            $stmt->execute(array(
	                ':postTitle' => $postTitle,
	                ':postSlug' => $postSlug,
	                ':postDesc' => $postDesc,
	                ':postCont' => $postCont,
	                ':postID' => $postID,
	                ':postTags' => $postTags
	            ));

	            if(isset($_FILES['postImage'])){

	            	$stmt = $db->prepare('UPDATE blog_posts SET postImage = :image WHERE postID = :postID') ;
		            $stmt->execute(array(
		                ':postID' => $postID,
		                ':image' => $target
		            ));
	        	}

				//delete all items with the current postID
				$stmt = $db->prepare('DELETE FROM blog_post_cats WHERE postID = :postID');
				$stmt->execute(array(':postID' => $postID));

				if(is_array($catID)){
					foreach($_POST['catID'] as $catID){
						$stmt = $db->prepare('INSERT INTO blog_post_cats (postID,catID)VALUES(:postID,:catID)');
						$stmt->execute(array(
							':postID' => $postID,
							':catID' => $catID
						));
					}
				}

				//redirect to index page
				header('Location: index.php?action=updated');
				exit;

			} catch(PDOException $e) {
			    echo $e->getMessage();
			}

		}

	}

	?>


	<?php
	//check for any errors
	if(isset($error)){
		foreach($error as $error){
			echo $error.'<br />';
		}
	}

		try {

			$stmt = $db->prepare('SELECT postID, postTitle, postDesc, postCont, postTags, postImage FROM blog_posts WHERE postID = :postID') ;
			$stmt->execute(array(':postID' => $_GET['id']));
			$row = $stmt->fetch(); 

		} catch(PDOException $e) {
		    echo $e->getMessage();
		}

	?>

	<form action='' method='post' enctype="multipart/form-data">
		<input type='hidden' name='postID' value='<?php echo $row['postID'];?>'>

		<p><label>Title</label><br />
		<input type='text' name='postTitle' value='<?php echo $row['postTitle'];?>'></p>

		<p><label>Image</label><br />
		<input type='file' name='postImage'></p>

		<?php if ($row['postImage'] !=''){ ?>
			<p><img src="<?=$url.$row['postImage'];?>"></p>
		<?php } ?>

		<p><label>Description</label><br />
		<textarea name='postDesc' cols='60' rows='10'><?php echo $row['postDesc'];?></textarea></p>

		<p><label>Content</label><br />
		<textarea name='postCont' cols='60' rows='10'><?php echo $row['postCont'];?></textarea></p>

        <p><label>Tags (comma seperated)</label><br />
        <input type='text' name='postTags' value='<?php echo $row['postTags'];?>' style="width:400px;"></p>

        <fieldset>
			<legend>Categories</legend>

			<?php

			$stmt2 = $db->query('SELECT catID, catTitle FROM blog_cats ORDER BY catTitle');
			while($row2 = $stmt2->fetch()){

				$stmt3 = $db->prepare('SELECT catID FROM blog_post_cats WHERE catID = :catID AND postID = :postID') ;
				$stmt3->execute(array(':catID' => $row2['catID'], ':postID' => $row['postID']));
				$row3 = $stmt3->fetch(); 

				if($row3['catID'] == $row2['catID']){
					$checked = 'checked=checked';
				} else {
					$checked = null;
				}

			    echo "<input type='checkbox' name='catID[]' value='".$row2['catID']."' $checked> ".$row2['catTitle']."<br />";
			}

			?>

		</fieldset>

		<p><input type='submit' name='submit' value='Update'></p>

		

	</form>

</div>

</body>
</html>	

Front End

Now its time to display image with the post, open index.php add postImage to your query:

$stmt = $db->query('SELECT postID, postTitle, postSlug, postDesc, postDate, postTags, postImage FROM blog_posts ORDER BY postID DESC');

This returns the column from the database, next we use an if statement where we want the image to be displayed:

if ($row['postImage'] !=''){
	echo "<p><img src='".$url.$row['postImage']."' style='max-width:100%;'></p>";
}

The image that has been uploaded will not be resized there for its a good idea to resize it before upload. Having said that here I'm using inline styling to set the image width to be 100% which should help to keep the image from expanding beyond the post.

That's it! repeat the steps above to all files displaying the posts.

David Carr

David Carr

For the past 12 years, I’ve been developing applications for the web using mostly PHP. I do this for a living and love what I do as every day there is something new and exciting to learn.

In my spare time, the web development community is a big part of my life. Whether managing online programming groups and blogs or attending a conference, I find keeping involved helps me stay up to date. This is also my chance to give back to the community that helped me get started, a place I am proud to be apart of.

Besides programming I love spending time with friends and family and can often be found together going out catching the latest movie, staying in playing games on the sofa or planning a trip to someplace I’ve never been before.