Web International Awards

payday loan

11

MAY 2010 2

Building a live news blogging system in php. Spiced with HTML5, CSS3 and jQuery [part V]

Tutorial app preview

About a month ago I started a series of tutorials on building a live blogging system in php. In case you missed it, you should definitely start with the first part of the series, or at least check out the demo.

Until now I've covered building the database, login functionalities for administrators, adding and deleting news from the database. Today I'll cover editing existing news.

The edit form

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div class="editform hidden">
	<form action="editnews.php" method="post" accept-charset="utf-8" id="form-overlay" class="insertcontent">
		<fieldset>
 
			<label for="edittitle">Title : </label>
			<input type="text" name="edittitle" value="" id="edittitle" class="edittitle all-rounded" />
			<label for="editformcategory">Category :</label>
			<select name="editformcategory" id="editformcategory" size="1" class="editcategory">
				<option selected="selected" value="Economics">Economics</option><option value="Education">Education</option><option value="Health">Health</option><option value="IT">IT</option><option value="Politics">Politics</option><option value="Weather">Weather</option>					</select>
 
			<label for="editbody">Body text :</label>
			<textarea name="editbody" rows="8" cols="40" class="editbody all-rounded"></textarea>
			<input type="hidden" name="editid" value="" id="editid" class="editid hidden" />
			<input type="submit" name="submit" value="Edit news" id="submit" class="submit all-rounded" />
		</fieldset>
	</form>
</div>

I coded the edit form in the first article. However, this form needs be loaded with the proper content. If it shows up empty it isn't an edit form anymore. That's done by editing the html code and inserting some php snippets as follows.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div class="editform hidden">
	<form action="editnews.php" method="post" accept-charset="utf-8" id="form-overlay" class="insertcontent">
		<fieldset>
			<label for="edittitle">Title : </label>
			<input type="text" name="edittitle" value="" id="edittitle" class="edittitle all-rounded" />
			<label for="editformcategory">Category :</label>
			<select name="editformcategory" id="editformcategory" size="1" class="editcategory">
				<? list_categories("select-options") ?>
			</select>
			<label for="editbody">Body text :</label>
			<textarea name="editbody" rows="8" cols="40" class="editbody all-rounded"></textarea>
			<input type="hidden" name="editid" value="" id="editid" class="editid hidden" />
			<input type="submit" name="submit" value="Edit news" id="submit" class="submit all-rounded" />
		</fieldset>
	</form>
</div>

The only part that's changed from the raw html form is the code inside the select tag. I've started coding that function and presented it in the third part of the tutorial.

However, only with the php code above, I've fixed only the category issue. The rest of the form elements are still empty. Populating them with valid data is done via jQuery. Data is read directly from the DOM and appended accordingly into the form. I've started the overlay function in the second part of the series, and now I am altering that function to add the required functionalities. Just after the 11th line (var rel = $(this).attr('rel');) in the overlay's function code we add the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if(rel=='editform')
{
	var id = $(this).attr('title');
 
	var article = $(this).parent().parent();			
	var details = article.children('details');
	var category = details.children('span.cat').html();
	var body = article.children('p').html();
	var title = article.children('h1').text();
}
 
var modal_content = $('.'+rel).html();
$('#overlay-content div').html(modal_content);
 
$('input.editid').val(id);
$('input.edittitle').val(title);
$('textarea.editbody').text(body);

By adding the above code, when someone clicks the edit link of a news item, an overlay pops out displaying the contents of the news which are loaded from the DOM itself (directly from the article tags). Users can then edit the content and save it.

editnews.php

We need to somehow process the edit request and we do that with a script similar to the addnews.php file I talked about in part three of the series.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?
session_start();
include("includes/functions.php");
if(session_is_registered('logged in key'))
{
	$er = 0;
	if (!isset($_POST['edittitle'])) $er='1';
		else $title = $_POST['edittitle'];
	if (!isset($_POST['editformcategory'])) $er='1';
		else $formcategory = $_POST['editformcategory'];
	if (!isset($_POST['editbody'])) $er='1';
		else $body = $_POST['editbody'];
	if (!isset($_POST['editid'])) $er='1';
		else $id = $_POST['editid'];
	if($er==1)
	{
		header("location: index.php?error=Please input username and password");
	}
	else
	{
		$title = strip_all($title);
		$formcategory = strip_all($formcategory);
		$body = strip_all($body);
		$username = $_SESSION['username'];
		$query = "UPDATE News SET `body` = '$body', `title` = '$title', `category` = '$formcategory' WHERE `id`='$id';";
		echo $query;
		@mysql_query($query) or die(mysql_query());
		header("location: index.php?msg=News edited successfully");
	}
}
else header("location: index.php?error=You must be logged in to access this feature.");
?>

The above code first checks for administrator status, then form data input errors. If everything is in order the news is edited and changes saved to the database.

If you enjoyed this article you can stay updated to new content via our RSS feed or by email.

4

MAY 2010 3

How to display ratings as stars using CSS and a bit of jQuery

On a project I am working on I have different objects that can be rated by users. I need to display their rating which ranges from 0 to 5 with a 0.01 step as I am using floating numbers. I found a neat and simple way to do this, semantically correct with valid markup.

Preview of rating stars

In the above screenshot you can check out what I'm trying to achieve. See those stars right under the name of the location? Well, that is done purely with CSS and two images. Let's see the HTML markup required.

1
2
3
4
5
<div class="restaurant-stars">
	<div class="restaurant-stars-rating" title="2.5">              
		&nbsp;
	</div>
</div>

You may ask why am I using two different DIVs instead of one. Let me explain. We need the gray stars that are used to display the maximum rating achievable. We also need orange stars to display the actual rating. The orange stars must lay on top of the gray ones.

To achieve this, the restaurant-stars div has a specific width. Mine is 76 pixels. Moreover, the background image of this div is an image containing all the 5 gray stars. Background image is set not to repeat. The restaurant-stars-rating div has a width that has to be between 0 and the restaurant-stars div's width, which is 76 pixels. The one I used in the example is 38 pixels. The background image of this second div is an image that contains 5 orange stars.

The trick is right here, in the length of the inner div. As its width is lower, the background image will not span all the way to cover up the outer div's background image, resulting in an awesome way to semantically display a star based rating value.

What's the CSS?

1
2
.restaurant-stars { display:block; width:76px; height:20px; background:url('images/rating_default.jpg') no-repeat; }
.restaurant-stars-rating { display:block; width:38px; height:20px; background:url('images/rating_stared.jpg') no-repeat; }

That's all that needs to be coded!

Enhancing it with a bit of jQuery

I don't think that such a feature should be used on a static website, so how do you tackle dynamic content that has different values for ratings? I am using this rating feature on a Google Maps infoWindow. I am using jQuery to dynamically change it based on data I get from a JSON object passed along from a Rails application. Here's the code:

1
   $('.restaurant-stars-rating').width(foundRestaurant.resrating*76/5);

As you can see I am simply computing the width value of my restaurant-stars-rating div as the product between the rating I have in the database with the outer div's width, divided by the maximum rating. Simple as that!

If you enjoyed this article you can stay updated to new content via our RSS feed or by email.

27

APR 2010 2

Building a live news blogging system in php. Spiced with HTML5, CSS3 and jQuery [part IV]

Just in case you're a first time visitor, you can check out the demo of this tutorial and perhaps you should read the first, the second and the third part of the series (which are required to fully understand what we're doing here).

What we've already done

During the first three parts of the tutorial we've coded the layout, styled it, added some basic functionalities with some bits of jQuery, we added login and logout funtionalities and an add news method. Today we will tackle deleting news from our system.

Deleting news from the database

If we want to delete news from the database, we need controls to point to methods that handle the task. During the first part of the tutorial we coded the structure of the article. Now, we will add one extra line to it.

1
2
3
4
5
6
<article>
	<span class="controls"><a href="deletenews.php?id=114" target="_self" class="delete"></a><a href="" name="modal" rel="editform" title="114" target="_self" class="edit"></a></span>
	<h1>Back to tutorial</h1>
	<details>Posted by <span>news</span> in <span class="cat">Economics</span> on <span>2010-04-12</span> at <span>07:34:13</span>.</details>
	<p><a href="http://www.webia.info/articles/tutorials/building-a-live-news-blogging-system-in-php-spiced-with-html5-css3-and-jquery-part-i/">start of tutorial</a></p>
</article>

The only line we've added is line 2. This line contains two links. One to a delete method we will implement today, and one link that will be handled by the overlay, just like the login form we coded during the second part of the tutorial. The controls span we added is styled via CSS. We've seen that also in the first article. What needs to be reminded is that the span is hidden by default via display:none;. I only want to show these controls when admins hover an article, and I am doing that with the following CSS code.

1
2
article span.controls	{ display:none; width:32px; height:64px; }
article:hover span.controls { display:block; float:right; clear:right; }

As you can see, when admins hover an article, the controls pop in the right margin of the article. You could also use a jQuery technique as described in this article on Improving UIs by hiding unused elements.

deletenews.php file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?
session_start();
include("includes/functions.php");
if(session_is_registered('logged in key'))
{
	$er = 0;
	if (!isset($_REQUEST['id'])) $er='1';
		else $id = $_REQUEST['id'];
	if($er==1)
	{
		header("location: index.php?error=Please input username and password");
	}
	else
	{
		if(is_numeric($id))
		{
			@mysql_query("DEL FROM News WHERE id='$id';") or die(mysql_query());
			header("location: index.php?msg=News deleted from the system.");	
		}
		else
		{
			header("location: index.php?error=Hacking attempt.");
		}
	}
}
else header("location: index.php?error=You must be logged in to access this feature.");
?>

Please change DEL on line 17 with DELETE. Somehow I cannot save the article because wordpress thinks is a injection attack. Haven't found a solution to the problem yet.

Back to our topic, the code above checks if admin is logged in and displays a message otherwise (lines 4 and 26), then checks for form submission errors (lines 6 to 12). We then check to see if the ID of the news to be deleted is indeed numeric and display a message if the ID is not numeric (lines 15 and 22). This simple test will ensure we have no inject attacks against our database.

Finally, lines 17 and 18 handle the deletion of the news from our database, and redirect the user to the homepage of our app while displaying a success message.

You can stay updated to new content via our RSS feed or by email.

Further reading

22

APR 2010 0

Awesome Slider v1.0

Slider screenshot

Just a few weeks back I published an awesome tutorial on building a custom jQuery slider that uses XML to store data. The tutorial got really popular, therefor shortly after I published a rough demo and source codes of the tutorial.

However, I didn't stop there. The source code for the tutorial got some improvements, and I am proud to announce WebRaptor's first jQuery plugin/script release. I am saying plugin/script because Awesome Slider isn't, technically, a jQuery plugin, but a great function easy to use.

Download

You can download Awesome Slider from it's dedicated page, where you can also check out 3 demos and see the documentation on how to use it.

If you enjoyed this article you can stay updated to new content via our RSS feed or by email.

Further reading

20

APR 2010 3

Building a live news blogging system in php. Spiced with HTML5, CSS3 and jQuery [part III]

Just in case you're a first time visitor, you can check out the demo of this tutorial and perhaps you should read the first and the second part of the series (which are required to fully understand what we're doing here).

What we've already done

During the first two parts of the tutorial we've coded the layout, styled it, added some basic functionalities with some bits of jQuery (we created an overlay window which we're going to use today). We finished the second part with the login and logout funtionalities which means we still haven't created means to add, edit or delete news. Today we will tackle adding news to our system.

Adding news to the database

As described in our html code during the first article, we've seen that our webform that tackles adding new items to our database contains 3 fields: title, category and body. Title is an empty input field, category is a select field populated with all the categories our webapp has while body is an empty textarea.

Categories may change over time, therefor they are selected upon page loading and added as options to the category select tag we described just above. Basically, our select looks like this:

1
2
3
<select name="formcategory" id="formcategory" size="1">                
    <? list_categories("select-options") ?>
</select>

list_categories() is a simple php function we need to add to our functions.php file which we started in the second article. It's code is the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function list_categories($mode)
{
 
	$rows = mysql_query("SELECT name FROM Categories WHERE id>0 ORDER BY name ASC") or die(mysql_error());
 
	if($mode=="select-options")
	{
		$count = 0;
		if(mysql_num_rows($rows))
		{
			while($row = mysql_fetch_row($rows))
			{
				if($count==0) { echo "<option selected=\"selected\" value=\"".$row[0]."\">".$row[0]."</option>"; $count++; }
				else echo "<option value=\"".$row[0]."\">".$row[0]."</option>";
			}
		}
		else echo "<option value=\"none\">none</option>";
	}
}

The reason why that $mode parameter is present is because this function will also be used to list categories in the edit news webform and more. The above code selects all categories within our database and creates option tags from them, with the first option being selected.

Processing our form

The add news form is provided via an overlay. However, the script that processes it is not requested via ajax. The action of the form points directly to the file described just below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?
session_start();
include("includes/functions.php");
if(session_is_registered('logged in key'))
{
	$er = 0;
	if (!isset($_POST['title'])) $er='1';
		else $title = $_POST['title'];
	if (!isset($_POST['formcategory'])) $er='1';
		else $formcategory = $_POST['formcategory'];
	if (!isset($_POST['body'])) $er='1';
		else $body = $_POST['body'];
	if($er==1)
	{
		header("location: index.php?error=Please input username and password");
	}
	else
	{
		$title = strip_all($title);
		$formcategory = strip_all($formcategory);
		$body = strip_all($body);
		$username = $_SESSION['username'];
		$query = "INSERT %20 INTO %20 News %20 VALUES ( '".$title."', '".$body."', '".$username."', NOW( ) , NOW( ) , '".$formcategory."' )";
		@mysql_query($query) or die(mysql_query());
		header("location: index.php?msg=News added to the system.");
	}
}
else header("location: index.php?error=You must be logged in to access this feature.");
?>

addnews.php explained

  • Line 3: We include the file that contains the functions we use throughout the webapp
  • Lines 4 & 28: We check if the user is logged in. If the user is logged in, he can access the page, otherwise he's redirected to the index page and an error message is displayed
  • Lines 6 to 12: We get the input data from the add news form submitted by the user while checking for errors and unauthorized usage
  • Line 13: If we found data or form submission errors, redirect user to homepage and display error message
  • Lines 19 to 25: We strip all input data to remove any unaccepted characters. We then find out the username of the author, insert the news into the database and redirect the user to the homepage while displaying a success message
  • Line 23: For some reason WordPress had some issues with me posting the full SQL query. Please remove the %20 from your source when building the app.

What about strip_all(string) ?

strip_all(string) function is used to strip input sent to the database for minimum protection against injection attacks. This function is also included in the functions.php file.

1
2
3
4
5
6
7
8
function strip_all($string)                                            
{
	$string = htmlentities($string);
	$string = strip_tags($string);
	$string = stripslashes($string);
	$string = addslashes($string);
	return $string;
}

That's it!

To wrap up today's post, we've just finished our script that ads new items to our news database. The next part of this tutorial will tackle deleting news items. You can stay updated to new content via our RSS feed or by email.

Further reading

15

APR 2010 0

Improving UIs by hiding unused elements

As strange as it may sound, this is quite a good enhancement. I am not referring to anything similar to Windows's "unused icons on your desktop". I am referring to something that works similarly to Twitter's reply and retweet buttons.

Basically, with this short tutorial I want to achieve the following:

  1. Add CRUD controls to a list of objects (these can be users, comments etc)
  2. Display these controls by default
  3. Hide them if javascript is available
  4. Show them only when the user hovers them afterwards

UI hover event preview

I am going to apply these controls to lists of objects, users in particular. I am not going to use ul or ol tags to encapsulate data. I will be using table instead, because I am dealing with tabular data and this is where tables should be used!

HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<table cellspacing="0" cellpadding="0" >
	<tr>
 
		<th class="id">ID</th>
		<th class="avatar">Avatar</th>
		<th class="username">Username</th>
		<th class="email">Email</th>
		<th class="social" colspan="2">Social</th>
		<th class="controls">Controls</th>
	</tr>
	<tr>	
		<td>29</td>
		<td><img class="gravatar" alt="" width="45" height="45" src="http://www.gravatar.com/avatar/a9f8c8c99979f5ea2773715668f47109?rating=PG&amp;size=45" /></td>
		<td>Alex Flueras</td>
		<td>hidden-email@hidden-domain.com</td>
		<td>
			<a class="hastwitter" href="http://www.twitter.com/WebRaptor" target="_new">WebRaptor</a>
		</td>
		<td>
		</td>
		<td>
			<span>
				<a href="#/users/show/29" class="show">Show</a>
				<a href="#/users/edit/29" class="edit">Edit</a>
				<a href="#/users/destroy/29" class="destroy">Destroy</a>
			</span>
		</td>
	</tr>
	<tr>
		<td>2</td>
		<td><img class="gravatar" alt="" width="45" height="45" src="http://www.gravatar.com/avatar/b0fcab2a1048d65d9d0e4e65153484ac?rating=PG&amp;size=45" /></td>
		<td>bogdan</td>
		<td>hidden-email@hidden-domain.net</td>
		<td>
			<a class="hastwitter" href="http://www.twitter.com/WebRaptor" target="_new">WebRaptor</a>
		</td>
		<td>
		</td>
		<td>
			<span>
				<a href="#/users/show/29" class="show">Show</a>
				<a href="#/users/edit/29" class="edit">Edit</a>
				<a href="#/users/destroy/29" class="destroy">Destroy</a>
			</span>
		</td>
	</tr>
</table>

CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/* general resets and global classes */
* { margin:0; padding:0; border:0; outline:0; font-weight:inherit; font-size:inherit; }
body { font-family:Geneva, “Lucida Sans”, “Lucida Grande”, “Lucida Sans Unicode”, Verdana, sans-serif; font-size:62.5%; }
 
 
/* user management related styling */
table { border:1px solid #CECECE; border-top:none; border-left:none; margin:0px auto; margin-top:100px; }
table th,
table td { border:1px solid #CECECE; border-bottom:none; border-right:none; padding:3px; }
table th { height:40px; background:url('images/overlay_header.jpg') repeat-x; color:#FEFEFE; }
th { text-align:center; }
th.id { width:24px; }
th.avatar { width:45px; }
th.username { width:263px; }
th.email { width:354px; }
th.social { width:94px; }
th.controls { width:114px; }
tr.global { background-color:#B2FFB2; }
tr.admin { background-color:#FFFFB2; }
tr.banned { background-color:#FFB2B2; }
tr { color:#999; }
tr:hover { color:#333; }
 
 
a.hastwitter, a.hasfacebook,
a.notwitter, a.nofacebook { display:block; width:45px; height:45px; text-indent:-1000em; background:url('images/social_hover_user.png') no-repeat; }
a.hastwitter { background-position:bottom left; }
a.notwitter { background-position:top left; }
a.hasfacebook { background-position:bottom right; }
a.nofacebook { background-position:top right; }
td span a { display:block; float:left; width:37px; height:45px; background:url('images/user_list_controls.png') no-repeat; text-indent:-1000em; }
td span a.show { background-position:top left; }
td span a.edit { background-position:top center; }
td span a.destroy { background-position:top right; }
td span a.show:hover { background-position:bottom left; }
td span a.edit:hover { background-position:bottom center; }
td span a.destroy:hover { background-position:bottom right; }

Here's a demo of what we've done so far. The CSS above is not complicated at all. Just some basic background images, using css sprites — that's why the css ends with all those background-position declarations.

As you can see in the html above, the right end of each row contains three action controls. Now, if I'm going to have 50 or more users per page, that will add visual weight on the page which is not good. That's why I chose to remove the elements and display them only when someone hovers a specific row in the table. I am doing that with javascript, and here's the code:

jQuery

1
2
3
4
5
6
7
8
9
10
11
12
function admin_controls_user_list_hover()
{
	$('td span').css('display','none');
	$('tr').hover(
		function(){ $(this).find('span').css('display','block'); },
		function(){ $(this).find('span').css('display','none'); }
	);
}
 
$(document).ready(function(){
	admin_controls_user_list_hover();
});

As you can see, on page load I am simply hiding the elements, then using jQuery's hover() method together with two functions that are executed when the mouse pointer enters or leaves any row in our table. Here's the full demo and here's the full source code. Enjoy!

You can stay updated to new content via our RSS feed or by email.

Further reading

13

APR 2010 2

Building a live news blogging system in php. Spiced with HTML5, CSS3 and jQuery [demo]

Tutorial app preview

You've asked for it, it took some time to make minor adjustments, but the demo of the live news blogging system is up and running and can be seen in action right over here.

You can stay updated to new content via our RSS feed or by email.

Further reading

6

APR 2010 7

Building a live news blogging system in php. Spiced with HTML5, CSS3 and jQuery [part II]

In the first article in this series we've looked upon coding a html5 layout, styling it with css and adding some basic jQuery functionalities to it. In this second part we're going to tackle something a bit more advanced. We're going to check out our database model, create some SQL queries. Then we're going to move to the php side of the app and see what needs to be done and start building our app's foundation.

The database model

I am not going to throw up a UML design over here. I am just going to code the tables and then explain what the attributes are used for. Having that said, here's the SQL we're going to use to create the database which we're going to use with our app.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
CREATE TABLE News
(
	id INT(10) NOT NULL AUTO_INCREMENT,                           
	title VARCHAR(150),
	body text,
	owner VARCHAR(52),
	publishing_date DATE,
	publishing_time TIME,
	category VARCHAR(52),
	PRIMARY KEY(id)
);
 
CREATE TABLE Users
(
	id INT(10) NOT NULL AUTO_INCREMENT,
	username VARCHAR(52),
	email VARCHAR(52),
	password VARCHAR(52),
	PRIMARY KEY (id)
);
 
CREATE TABLE Categories
(
	id INT(10) NOT NULL AUTO_INCREMENT,
	name VARCHAR(52),
	PRIMARY KEY(id)
);

As you can see the model isn't complicated at all. The Users table contains information about administrators, as described in the first article of the series, the Categories table will contain nothing but the categories to which each news can be assigned, while the News table will contain the actual news.

MySQL explained

  • lines 3,15 and 24: Each element stored in our database, be it user, news or a category needs a unique ID. These lines, together with lines 10,19 and 26 will ensure that we have unique IDs for each element
  • line 4 to 8: Each news will have a short title, body copy, a publisher (owner), a publishing date and publishing time
  • line 9: The ID of the category to which the news belongs to
  • line 16 to 18: Basic user information, nothing special
  • line 25: Each category has a name besides the unique ID and nothing else

Basic app functionality

The app we're building isn't that complicated. However, we need to know exactly what we need to code. First of all, we'll need login and logout methods, for our admins to be able to do their work. We need an index page which will display all news. We also need the ability to add, edit and delete news which gives us 6 different methods. Therefor we need 6 different files.

login.php

Our login file will process the data sent by pressing the login button inside the login window we coded in the first part of the article. This means we only need to process a username and a password, compare it with data in our database and see if we have a valid login or not.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<?
	session_start();
	ob_start();
	include("includes/functions.php");
 
	if (!isset($_POST['username'])) $er='1';
		else $username = $_POST['username'];
	if (!isset($_POST['password'])) $er='1';
		else $password = $_POST['password'];
	if($er==1)
	{
		header("location: index.php?error=Please input username and password");
	}
	else
	{
		$chars = preg_split("//", $password, -1, PREG_SPLIT_NO_EMPTY);
		$i = 0;
		$ok = 1;
		while($chars[$i])
		{  
			$char=$chars[$i];
		    $x = checkvaliddata($char);
			if($x==0) $ok = 0;
			$i++;
		}
 
		$chars = preg_split("//", $username, -1, PREG_SPLIT_NO_EMPTY);
		$i = 0;
		while($chars[$i])
		{
			$char=$chars[$i];
			$x = checkvaliddata($char);
			if($x==0) $ok = 0;
			$i++;
		}
 
		if($ok==1)
		{
			$password = md5($password);
			$sql=mysql_query("SELECT * FROM Users WHERE username='$username' AND password='$password'");
			$login_check=mysql_num_rows($sql);
			if($login_check>0)
			{
				while($row = mysql_fetch_array($sql)) 
				{
	   				foreach( $row AS $key => $val )
						{
	       					$$key = stripslashes( $val );
	    				}
					session_register('logged_in_key');
					session_register('username');
					$_SESSION['username'] = $username;
 
					ob_end_clean();
					header("location: index.php?msg=Logged in succesfully.");
	    		}
			}
			else 
			{
	        	ob_end_clean();
	        	header("location: index.php?error=Invalid login data.");
			}
		}
		else
		{
	        header("location: index.php?error=Hacking attempt!");
		}
	}
?>

login.php explained

  • line 2: In order to handle user login we need to be able to store php sessions and check them within the entire app. This means that each of our files need to have session_start() on the first line
  • lines 3, 12,55,61 and 66: The header() allows us to send a raw HTTP header after the page has loaded. We need to do that because our login page will not display any messages, but redirect the user according to his/hers login data. The ob_end_clean() function erases the output buffering so that when we call the header() function we don't see an ugly message that goes with "Headers already sent"!
  • lines 6 to 9: We get the data the user has typed in the login form
  • lines 10 to 13: We check if the login form was submitted and we don't get bogus requests. If the webform was not submitted and this may be a remote request, we redirect the user back to the starting page of our app and display a message. As you can see the error message is embedded in the URL itself (line 12)
  • lines 16 to 35: If the request of the login page is valid we check if data users typed is valid, preventing MySQL injections and more
  • lines 16 and 27: We get the user's typed data as strings, and we need to check out each character against a set we accept as valid input. We use the preg_split() function to break the input string to characters
  • lines 63 to 67: If data is invalid (unexpected chars were found) the user is redirected to the index page and a hacking attempt message displayed
  • lines 39 to 62: We've reached the part where input data is valid. As passwords are encrypted into our database, we encrypt the inputed password, then check the username & password combination for validity. If login_check variable is positive, we've got a valid login. If not, username and passwords don't match anything in our database.
  • lines 44 to 49: If we have a valid login, we used named variables to get all data about the user from the database, then create required sessions.
  • line 50: This session key should be unique, and hard to guess for security reasons. We're going to use this session with a unique name to check if users are indeed logged in or not.

logout.php

The logout.php file is pretty simple and has one job: to distroy user sessions. Once these sessions are destroyed, the user no longer appears as logged in into our app. Here's the code:

1
2
3
4
5
6
7
<?
	session_start();
	ob_start();
	unset($_SESSION['logged_in_key']);
	ob_end_clean();
	header("location: index.php?msg=Successfully logged out");     
?>

The problem is that we can't use the session_destroy() function as we don't want to destroy all sessions. We use sessions and jQuery with ajax to make things sexy in our app. Therefor, we can't destroy all sessions when users log out. We need to destroy the one that told us that the user is actually an administrator. And that's what the unset() function does.

Issues with the login ?

We've finished the login.php file, but as you can see before running a query against our database we do not connect to it! If you check out the login script you'll see that we included the functions.php file. We did this because there are some functions that will be used throughout the app and we need to keep them all in one place. One such function may be checkvaliddata which we used to validate user input.

functions.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function db_connect(& $db) // used to connect to the database
{
	include("config.php");
	$db=mysql_connect($dbhost, $dbuser, $dbpass) or die ('Cannot connect to server' . mysql_error());
	mysql_select_db($dbname);
}
$db;
db_connect($db);
 
function checkvaliddata($char) 
{
  	$salt = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789.@ ";
    $i = 0;
	$c = 0;
	while ($i <= 63)
	{
	    $tmp = substr($salt, $i, 1);
	    if($tmp==$char) $c=1;
	    $i++;
	}
	return $c;
}

functions.php explained

  • lines 1 to 8: The db_connect function is used to connect to the database. The included config.php file contains our database information. mysql_connect() is used to connect to the mysql server and display a message if failure occurs while mysql_select_db() is used to select our database once we successfully connect to the server. As you can see, there's a call to our connection function. This way every time we include the functions.php file in our app we automatically connect to the database
  • lines 10 to 21: This function is used in the login.php file to validate data the users have typed in the login form against a set of accepted characters. The function returns 1 if data is valid and 0 otherwise

The login form

We only coded the layout and structure of our app in the first part of the tutorial. Our login form is not visible to site visitors. Therefor we need to add some jQuery code for our form to pop out when visitors click the login link located in the footer our webapp.

login window overlay

Adding some more jQuery to it

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
function overlay()
{
	//create the overlay menu
	var opacity = '0.9'; // can be up to 1
 
	$('a[name=modal]').removeAttr('href');
	//javascript on, no need to redirect to a link here
	$('a[name=modal]').click(function ()
		{ 
 
		var rel = $(this).attr('rel');
 
		var modal_content = $('.'+rel).html();
		$('#overlay-content div').html(modal_content);
 
		var maskHeight = $(document).height();  
		var maskWidth = $(document).width(); 
		var windowHeight = $(window).height();  
		var windowWidth = $(window).width(); 
		var contentWidth = $('#overlay-content').width(); // width
		var contentHeight = $('#overlay-content').height(); // and height of content area
 
		//Set height and width to mask to fill up the whole screen  
		$('#overlay-mask').css({'width':maskWidth,'height':maskHeight});
		$('#overlay-mask').css('opacity',opacity);
		$('#overlay-mask').css('display','block');
 
		// put the overlay content area in the center of the window
		$('#overlay-content').css('display','block');
		$('#overlay-content').css('left',(windowWidth-contentWidth)/2);
		$('#overlay-content').css('top',(windowHeight-contentHeight)/2);				
	});
 
	// move overlay content to center of the window
	$(window).resize(function () { 
		var maskHeight = $(document).height();  
		var maskWidth = $(window).width(); 
		var windowHeight = $(window).height();  
	 	var windowWidth = $(window).width();
		var contentWidth = $('#overlay-content').width(); // width
		var contentHeight = $('#overlay-content').height(); // and height of content area
		//Set height and width to mask to fill up the whole screen  
		$('#overlay-mask').css({'width':maskWidth,'height':maskHeight});
		$('#overlay-content').css({'left':(windowWidth-contentWidth)/2});
		$('#overlay-content').css({'top':(windowHeight-contentHeight)/2});
	});
 
	var $scrollingDiv = $("#overlay-content");	
	$(window).scroll(function() {			
		$scrollingDiv
			.stop()
			.animate({"marginTop": ($(window).scrollTop()) + "px"}, "fast" );			
	});			
	$('#overlay-mask').click(function () { $('#overlay-mask').css('display','none'); $('#overlay-content').css('display','none'); $('#overlay-content div').html(""); });
	$('.close').click(function () { $('#overlay-mask').css('display','none'); $('#overlay-content').css('display','none'); $('#overlay-content div').html(""); });
}

jQuery explained

I've embedded the login and edit/add news forms into an overlay to declutter the user interface. The opacity variable is a real number in the [0,1] range which sets the transparency of the overlay mask. 1 means it's opaque and 0 means it's transparent.

  • line 6: Prevents default behavior when login link or add/edit links are clicked
  • line 11: We use the rel attribute to map on each overlay() call which content should be loaded (login form/edit form or add news form). The rel attribute should coincide with the class attribute of the webform itself (login, editnews or addform)
  • lines 13 and 14: The relevant content according to function call is copied to the overlay content div
  • lines 16 to 21: We want our overlay to be centered in the browser window. Therefor, we calculate the widths and heights of the browser window, content area and overlay mask which spans all over the page
  • lines 24 to 26: We set the dimensions of the overlay mask and its color
  • lines 28 to 31: Display the overlay content div and put it in the middle of the browser's window
  • lines 35 to 46: Recalibrate widths and heights and reset the position of the overlay if the browser's window is resized
  • lines 29 to 53: Do the same if the users scrolls down or up the window
  • lines 54 and 55: Add close buttons and functionality so that users can get the overlay out of their face

End of part II

And we've reached the end of our second part. We've seen during the first part how we can create a pretty complex layout using html5, how to style it using CSS3 and we've also seen how we can achieve equal heights for two independent columns using javascript (we've also got a dedicated article about this, and we're using the same technique for this site too). Today we saw how our database model looks like, how we can connect to our database and how we can allow our administrators to login and manage the app. We also added some jQuery to create some nive overlays.

I hope you really enjoyed this article. Please share the link with your friends. You can stay updated to new content via our RSS feed or by email.

Further reading

1

APR 2010 0

Never deceive your visitors! based on a true story…

Just the other day I stumbled upon an unexpected ad on a television's website. The add was about IQ tests and pointed to a site where you could take one. I clicked and was taken to the website which had a thorough IQ test. At least their about page stated so. Bottom line is that this test looked serious, or at least it was more serious than the ones I've seen over the years. I've decided to take it.

There were no time penalties, a nice progress bar indicated where you were throughout the entire testing. Overall it was a nice experience, which seemed close to perfection. Oh but was I wrong! I don't know exactly how many questions were in there, but I think they were more than 50.

After roughly 30 minutes, I completed the task. I was asked to input my name and email and hit submit to have my results emailed to me. I knew ads on such a high traffic television site couldn't be cheap, and this wouldn't be a scam, so I went on and put in my details and clicked the submit button.

The next page was a disaster, completely ruining my experience, making me bounce off the website and write this article. Why? The thank you page didn't contain my test result. Instead it contained 2 phone numbers to which I could send a 5 Euro SMS to pay for the results they just said would be emailed to me. This was the first point in the entire process when I saw it is a paid service. After spending 30 minutes! And no, I won't pay and I didn't pay.

Let your users know your service isn't free right from the get go!

But would I've paid if I knew from the start it's not a free test? Probably! They lost a happy customer in added time, and they probably lost and will lose many more with this stupid system.

Tips to improve your paid service sign up process

  1. Always let your users know it's a paid service from the moment they arrive to your page
  2. Payment page should never be the last one of the signup process, unless users know from start how much the product or service costs
  3. If the signup process is lengthy provide visual progress bars
  4. Never cheat with these progress bars to fool users into thinking they're close to finish line when they're not

Conclusion

Always let your users know if they can use your paid service, and let them no before they start using it. Doing so afterward will probably make you loose almost every client. Always be honest about your offered service and price because at the slightest misinformation your customers will go straight to your competitors.

If you have any similar experiences or any other tips please share them in the comments. Please share the link with your friends. You can stay updated to new content via our RSS feed or by email.

30

MAR 2010 37

Building a live news blogging system in php. Spiced with HTML5, CSS3 and jQuery [part I]

Live news system preview

Overview of the series

During this series of posts we're going to tackle building a live news blogging system. There will be multiple administrators who can add, delete and edit news. Each news can be assigned to one category only. The visitors will be able to see all news, filter them based on categories and publishing date. If one's online and a news is published it will receive a pop-up that will let him know there's new news in the feed — just like Twitter displays the new tweets message on top of the timeline.

You can click the above screenshot to get a full preview of how the layout will look like. Remember we're building it with HTML5 which means it will look really bad on older browsers and Internet Explorer. The end goal of this task is not to build the news system alone, but to showcase some of the emerging technologies.

I have no clue how many parts this tutorial will have. However, time will tell. Today we'll tackle coding the layout, styling it and adding some basic jQuery features.

Coding the HTML5 structure

I am not going to write an introduction to HTML5. In case this is your first contact with HTML5, I suggest you to read, or at least scan W3C's draft on it.

CONTINUE READING
Page 3 of 1112345...10...Last »