Skip to content
 

Cleaning Up Some PHP And Incorporating A JavaScript-Based Image Preview

Recently asked on Yahoo! Answers:

Change image when new option selected in PHP?
This probably will also require Javascript. I am using this code:
What it does is draws from a MySQL database where an “avatars” table is set. The “avatars” table includes fields “id” (INT), “title” (VARCHAR) and “url” (VARCHAR).
Basically, the script draws the rows from the table. It puts the titles in an HTML select form as options.

{code block snipped}

When an option is selected, I would like the image that is selected to be shown, without a new page having to be loaded.

This is very easy to do with JavaScript and DOM manipulation, but based on the user’s code, it requires a bit more work that previous blog entries I’ve made on images and JavaScript.

Let’s start with looking at the original code block.

<?php
session_start();
$title = "Edit Avatar";
include("include/header.php");
if(session_is_registered('uid')){
	if(isset($_POST['submit'])){
		$avatartitle = $_POST['avatar'];
		$av = ("SELECT `url` FROM `avatars` WHERE `title`='".$avatartitle."' limit 1");
		$ava = mysql_query($av) or die (mysql_error());
		$avat = mysql_fetch_array($ava);
		$avatar = $avat[0];
		mysql_query("UPDATE `users` SET `avatar` = '$avatar' WHERE `id` ='$id' and `password` ='$password' LIMIT 1 ;");
		echo "<img src="$avatar" alt="$username's avatar" style="float: right; margin: 10px;" />";
		echo "Your avatar has been changed to <b>$avatartitle</b>.";
	} else {
		echo "<div style="width: 200px;"><form id="picsform" name="avatar_select" method="post" action="edit_avatar.php">";
		echo "<select name='avatar' onClick="showpicture(this)">rn";
		$rs = mysql_query( "SELECT title FROM avatars GROUP BY title ORDER BY id LIMIT 30" ) or die( 'Cannot parse query: ' . mysql_error());
		if( mysql_num_rows($rs) == 0 ) {
		die( 'No records found' );
	}
	while($row = mysql_fetch_array( $rs )) {
		echo "<option name="".htmlentities( $row['title'] )."">" . htmlentities( $row['title'] ) . "</option>n";
	}
	echo "</select><input type="submit" name="submit" value="submit" style="float: right;" /></form></div>";
	}
} else {	
	echo "You are not logged in.";
}
include("include/footer.php");
?>

There are some promising good practices here, but some code we can also clean up.

For example, I’m not at all a fan of outputting HTML with PHP echo statements unless we are binding data to an HTML control (for example, populating options for a select list). I prefer to hard-code HTML and place it within conditional statements, controlling if and when it is rendered.

So, rather than this:

<?php
if(isset($_POST['submit'])){
	//some code
} else {
	echo "<div style="width: 200px;"><form id="picsform" name="avatar_select" method="post" action="edit_avatar.php">";
	echo "<select name='avatar' onClick="showpicture(this)">rn";
}
?>

I prefer this:

<?php
if(isset($_POST['submit'])){
	//some code
} 
else {
?>
<div style="width: 200px;">
<form id="picsform" name="avatar_select" method="post" action="edit_avatar.php">
	<select name="avatar" onClick="showpicture('this')">
<?php
}
?>

I prefer hard-coded HTML rather than PHP because with all the escaping and nesting involved in PHP statements, it’s easier to understand and follow simple HTML placed within a PHP conditional statement.

We can also streamline this code some, which will be shown shortly.

OK, with all that in mind, let’s solve the problem. First, I’m going to exclude from further discussion this containing block, which clearly handles some sort of membership / security and is largely irrelevant to the problem noted:

<?php
session_start();
$title = "Edit Avatar";
include("include/header.php");
if(session_is_registered('uid')){
	// code we will concentrate upon
} else {	
	echo "You are not logged in.";
}
include("include/footer.php");
?>

First, I want to clean up and simplify the code block that updates the avatar image for this user.

I’m assuming the id column in the users table is a unique identifier of some sort, and that the uid session variable in PHP is holding the value from that column for the current user. In other words, if I have an id of 5 in the user table, and I log in, then $_SESSION['uid'] holds as its value the number 5.

If so, we can significantly reduce the work for the code that changes the avatar in the database.

1
2
3
4
5
6
7
8
9
10
11
//check for form submission
if(isset($_POST['submit'])){
	//if update query works, note that
	if($rs = mysql_query("UPDATE users SET avatar = '" . mysql_real_escape_string($_POST['avatar']) . "' WHERE id = '" . mysql_real_escape_string($_SESSION['uid']) . "'")) {
		echo "<strong>Your avatar has been changed.</strong>";
	}
	else {
		//if update query fails, report error
		echo "<strong>There was an error updating your avatar:</strong> " . mysql_error();
	}
}

Note that Line 9 of the code above uses mysql_error() to report the problem with the insert. You should not include mysql_error() in end-user output because the text of MySQL error messages can help crackers exploit your database. Use it for debugging only, then comment it out or remove it from your code altogether.

Before we get to cleaning up the second block of code, we need to examine the JavaScript we will use to display the selected avatar image to the user.

It’s as simple as it gets: It asks for the select list and an image, gets from the select list the selected option in that list, and sets the src attribute of the image to be the id attribute of the selected option. (This will make more sense when we get to cleaning up the second block of code.)

<script type="text/javascript">
	function showAvatar() {
		var theImg = document.getElementById('avatarimg');
		var theSelect = document.getElementById('avatar');
 
		for(var i = 0; i < theSelect.length; i++) {
			if(theSelect.options[i].selected) {
				theImg.src = theSelect.options[i].id;
				break;
			}
		}
	}
</script>

This JavaScript is best place in the head section of the header.php file. However, we can add this script at the end of the page, just before we include footer.php. I will write my demo that way, but if there are problems getting the script to work, the first fix is to move this code to the head section of header.php.

The second block of code is not properly structured — a while loop that depends on a working MySQL query is placed outside the block that checks for proper execution of the query — and also could use some cleanup, again by breaking apart the HTML and the PHP code that determines if it should be rendered. We also need to make minor corrections to other parts of the code.

To begin restructuring the second code block, we call the PHP else() statement, then immediately close the PHP code block so we can output HTML.

We output as HTML all form elements up to the opening declaration for the select list.

else {
?>	
	<div style="width: 200px;">
		<form id="picsform" name="picsform" method="post" action="edit_avatar.php">
			<select id="avatar" name="avatar" onchange="showAvatar()">

Note that we changed the select’s onclick event handler into an onchange event handler.

We then go into the PHP code block which will get all the option elements we will bind.

I am going to add the URL column to the query because, as the JavaScript block above notes, I’m going to use that URL as the id attribute for each option; in turn, whichever option is selected will provide our function with the URL to the avatar, which will, in turn, be assigned to the preview image.

<?php
	//check for proper query; if bad query, make readable option noting problem
	if(!$rs = mysql_query("SELECT title, url FROM avatars GROUP BY title, url ORDER BY id LIMIT 30")) {
		echo "<option>There was an error getting values from the database: " . mysql_error() . "</option>n";
	}
	//if no records, make readable option noting as much
	elseif(mysql_num_rows($rs) == 0) {
		echo "<option>There are no avatars in the database</option>n";
	}
	else {
		//output options
		while($row = mysql_fetch_array($rs)) {
			echo "<option id="$row[url]">$row[title]</option>n";
		}
	}
?>

We finish up by adding the final HTML elements, and the closing PHP bracket for the else statement:

			</select>
			<input type="submit" name="submit" value="submit" style="float: right;" />
		</form>
		<br />
		Avatar preview: <img id="avatarimg" src="" alt="" />
	</div>
 
	<script type="text/javascript">
		function showAvatar() {
			var theImg = document.getElementById('avatarimg');
			var theSelect = document.getElementById('avatar');
 
			for(var i = 0; i < theSelect.length; i++) {
				if(theSelect.options[i].selected) {
					theImg.src = theSelect.options[i].id;
					break;
				}
			}
		}
	</script>
 
<?php
}

So, here’s the entire code block, after sanitizing and restructuring:

<?php
session_start();
$title = "Edit Avatar";
include("include/header.php");
if(session_is_registered('uid')){
	//check for form submission
	if(isset($_POST['submit'])){
		//if update query works, note that
			if($rs = mysql_query("UPDATE users SET avatar = '" . mysql_real_escape_string($_POST['avatar']) . "' WHERE id = '" . mysql_real_escape_string($_SESSION['uid']) . "'")) {
			echo "<strong>Your avatar has been changed.</strong>";
		}
		else {
			//if update query fails, report error
			echo "<strong>There was an error updating your avatar:</strong> " . mysql_error();
		}
	} 
	else {
	?>
		<div style="width: 200px;">
			<form id="picsform" name="picsform" method="post" action="edit_avatar.php">
				<select id="avatar" name="avatar" onchange="showAvatar()">
	<?php
		//check for proper query; if bad query, make readable option noting problem
		if(!$rs = mysql_query("SELECT title, url FROM avatars GROUP BY title, url ORDER BY id LIMIT 30")) {
			echo "<option>There was an error getting values from the database: " . mysql_error() . "</option>n";
		}
		//if no records, make readable option noting as much
		elseif(mysql_num_rows($rs) == 0) {
			echo "<option>There are no avatars in the database</option>n";
		}
		else {
			//output options
			while($row = mysql_fetch_array($rs)) {
				echo "<option id="$row[url]">$row[title]</option>n";
			}
		}
	?>
				</select>
				<input type="submit" name="submit" value="submit" style="float: right;" />
			</form>
			<br />
			Avatar preview: <img id="avatarimg" src="" alt="" />
		</div>
 
		<script type="text/javascript">
			function showAvatar() {
				var theImg = document.getElementById('avatarimg');
				var theSelect = document.getElementById('avatar');
 
				for(var i = 0; i < theSelect.length; i++) {
					if(theSelect.options[i].selected) {
						theImg.src = theSelect.options[i].id;
						break;
					}
				}
			}
		</script>
 
	<?php
		}
	} 
else {	
	echo "You are not logged in.";
}
include("include/footer.php");
?>

I distribute all code under the GNU GPL version 3.

Leave a Reply

Spam Protection by WP-SpamFree