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

David Carr

Demos Tutorials Blog PHP & MySQL

Table of Contents

Blog Series


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

Demo

admin demo: https://demos.dcblog.dev/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.

Fathom Analytics $10 discount on your first invoice using this link

Help support the blog so that I can continue creating new content!

Sponsor

Fathom Analytics $10 discount on your first invoice using this link

Subscribe to my newsletter

Subscribe and get my books and product announcements.

© 2006 - 2024 DC Blog. All code MIT license. All rights reserved.