<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Tutorialzine &#187; MySQL</title>
	<atom:link href="http://tutorialzine.com/category/tutorials/mysql/feed/" rel="self" type="application/rss+xml" />
	<link>http://tutorialzine.com</link>
	<description>PHP MySQL jQuery CSS Tutorials, Resources and Freebies</description>
	<lastBuildDate>Wed, 28 Jul 2010 17:33:42 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>An AJAX Click to Appreciate Badge</title>
		<link>http://tutorialzine.com/2010/07/click-to-appreciate-badge-ajax-jquery-css/</link>
		<comments>http://tutorialzine.com/2010/07/click-to-appreciate-badge-ajax-jquery-css/#comments</comments>
		<pubDate>Wed, 28 Jul 2010 17:33:42 +0000</pubDate>
		<dc:creator>Martin Angelov</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://tutorialzine.com/?p=1036</guid>
		<description><![CDATA[If you've ever dropped by Behance, you've probably noticed their appreciate badge, with which you can show your appreciation for somebody's creative work. In this tutorial we are making an improved version, which you can include in every page of your site with a bit of jQuery magic.]]></description>
			<content:encoded><![CDATA[<p>When you publish something online, there are not that many ways to determine whether people like what you have to say. Comments, the cornerstone of blogging, are too demanding, and users often prefer not to post one. If you&#8217;ve dropped by <a href="http://www.behance.net/" target="_blank">Behance</a>, you&#8217;ve probably noticed their <strong>appreciate badge</strong>, which is a neat solution to this exact problem. With it people share their appreciation for somebody&#8217;s work.</p>
<p>Today we are implementing such a badge, which you can include in every page of your website with a bit of jQuery magic. So go ahead and download the zip from the button above (<em><strong>PSD included!</strong></em>) and continue with the tutorial.</p>
<h3>The Database Schema</h3>
<p>The script we are doing today uses two tables. The first holds one record for each of the pages which have the appreciate button enabled. The second one stores the IP of the person that voted along the unique ID of the page. This way we can easily determine whether the person has previously voted for the page and display the appropriate version of the button (active or disabled).</p>
<div id="attachment_1040" class="wp-caption alignnone" style="width: 630px"><img class="size-full wp-image-1040" title="Table Schema appreciate_pages" src="http://tutorialzine.com/wp-content/uploads/2010/07/i11.png" alt="Table Schema appreciate_pages" width="620" height="260" /><p class="wp-caption-text">Table Schema appreciate_pages</p></div>
<p>The hash field holds an <strong>MD5 </strong>sum of the URL of the page. This way we add an <strong>UNIQUE </strong>index which will speed up the <em>selects</em> we run on the records, as well ensure there are no duplicate records in the table. The <strong>appreciated </strong>column holds the number of appreciations of the pages.</p>
<div id="attachment_1041" class="wp-caption alignnone" style="width: 630px"><img class="size-full wp-image-1041" title="Table Schema appreciate_votes" src="http://tutorialzine.com/wp-content/uploads/2010/07/i21.png" alt="Table Schema appreciate_votes" width="620" height="260" /><p class="wp-caption-text">Table Schema appreciate_votes</p></div>
<p>The <strong>appreciate_votes</strong> table contains the IP of the person that has voted (in the form of an integer), and the id of the page from the <strong>appreciate_pages</strong> table. The timestamp is automatically updated to the current time when an insert occurs.</p>
<p>You can create these two tables by running the code from <strong>tables.sql</strong> in the <strong>SQL </strong>section of <strong>phpMyAdmin</strong> from the downloadable archive, part of this tutorial.</p>
<h3>Step 1 &#8211; XHTML</h3>
<p>Lets start with the XHTML part of the tutorial. The markup of the page is extremely simple. To have the appreciate button functioning, you just need to provide a  container in which the button is inserted, and an optional element,  which holds the total number of clicks on the button. You can safely omit the  latter one, leaving you with only one div to code.</p>
<h4>page.html</h4>
<pre class="brush:html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
&lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;
&lt;head&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8" /&gt;
&lt;title&gt;An AJAX Click To Appreciate Badge&lt;/title&gt;

&lt;link rel="stylesheet" type="text/css" href="styles.css" /&gt;
&lt;link rel="stylesheet" type="text/css" href="appreciateMe/appreciate.css"/&gt;
&lt;/head&gt;

&lt;body&gt;

&lt;div id="countDiv"&gt;&lt;/div&gt;
&lt;div id="main"&gt;&lt;/div&gt;

&lt;script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"&gt;&lt;/script&gt;
&lt;script src="appreciateMe/plugin.js" type="text/javascript"&gt;&lt;/script&gt;
&lt;script src="script.js" type="text/javascript"&gt;&lt;/script&gt;

&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>In the page above, you can see that I am  including two stylesheet files. The first is <strong>styles.css,</strong> which is used to style the page, and <strong>appreciate.css</strong>, which is located in the plugin directory, and is responsible for the styling of the appreciate button.</p>
<p>Before the closing body tag, you can see that I also include the jQuery library from Google&#8217;s CDN repository, the <strong>plugin.js</strong> file and <strong>script.js</strong>, which uses the plugin to create the button on the page. You will only need to change the contents of <strong>script.js</strong> to make the script working on your pages.</p>
<div id="attachment_1042" class="wp-caption alignnone" style="width: 630px"><a href="http://demo.tutorialzine.com/2010/07/click-to-appreciate-badge-ajax-jquery-css/page.html"><img class="size-full wp-image-1042" title="Click To Appreciate Button" src="http://tutorialzine.com/wp-content/uploads/2010/07/i3.png" alt="Click To Appreciate Button" width="620" height="460" /></a><p class="wp-caption-text">Click To Appreciate - looks good on both dark and light backgrounds</p></div>
<h3>Step 2 &#8211; PHP</h3>
<p>PHP handles the database interactions and is on the backend of the AJAX requests. Most of the script logic is located in c <strong>script.php</strong> which you can see below. But first lets take a look at <strong>connect.php,</strong> which handles the database connection.</p>
<h4>appreciateMe/connect.php</h4>
<pre class="brush:php">$db_host = 'localhost';
$db_user = 'YourUsername';
$db_pass = 'YouPassword';
$db_name = 'NameOfDB';

@$mysqli = new mysqli($db_host, $db_user, $db_pass, $db_name);

if (mysqli_connect_errno()) {
	die('&lt;h1&gt;Could not connect to the database&lt;/h1&gt;');
}

$mysqli-&gt;set_charset("utf8");
</pre>
<p>Up until now, we&#8217;ve always used the old <strong>mysql</strong> extension for database connections under PHP, as it is a bit easier to use and I wanted to keep the code compatible with PHP 4. However, with the recent announcement that WordPress (our favorite blogging engine) will be <a href="http://wordpress.org/news/2010/07/eol-for-php4-and-mysql4/" target="_blank">dropping support for that version of PHP</a>, I decided that it is time to also make the switch to the new version &#8211; MySQLi (MySQL improved).</p>
<p>As you can see from the code above, the only major difference with the old way we connected to a database, is that here we create a <strong>MySQLi</strong> object instead of using the <strong>mysql_</strong> functions. Also, as you will see in a moment, when we query the database a MySQL resource object is returned, which in turn has its own set of methods. This might sound intimidating, but it will become perfectly clear once you see it in action.</p>
<h4>appreciateMe/script.php</h4>
<pre class="brush:php">/* Setting the error reporting level */
error_reporting(E_ALL ^ E_NOTICE);
include 'connect.php';

if(!$_GET['url'] || !filter_input(INPUT_GET,'url',FILTER_VALIDATE_URL)){
	exit;
}

$pageID			= 0;
$appreciated	= 0;
$jsonArray		= array();
$hash			= md5($_GET['url']);
$ip				= sprintf('%u',ip2long($_SERVER['REMOTE_ADDR']));

// $result is an object:
$result = $mysqli-&gt;query("SELECT id,appreciated FROM appreciate_pages WHERE hash='".$hash."'");

if($result)
{
	list($pageID,$appreciated) = $result-&gt;fetch_row();
	// fetch_row() is a method of result
}

// The submit parameter denotes that we need to write to the database

if($_GET['submit'])
{
	if(!$pageID)
	{
		// If the page has not been appreciated yet, insert a new
		// record to the database.

		$mysqli-&gt;query("
			INSERT INTO appreciate_pages
			SET
				hash='".$hash."',
				url='".$mysqli-&gt;real_escape_string($_GET['url'])."'"
		);

		if($mysqli-&gt;affected_rows){

			// The insert_id property contains the value of
			// the primary key. In our case this is also the pageID.

			$pageID = $mysqli-&gt;insert_id;
		}
	}

	// Write the vote to the DB, so the user can vote only once

	$mysqli-&gt;query("
		INSERT INTO appreciate_votes
		SET
			ip = ".$ip.",
			pageid = ".$pageID
	);

	if($mysqli-&gt;affected_rows){
		$mysqli-&gt;query("
			UPDATE appreciate_pages
			SET appreciated=appreciated+1 WHERE id=".$pageID
		);

		// Increment the appreciated field
	}

	$jsonArray = array('status'=&gt;1);
}
else
{
	// Only print the stats

	$voted = 0;

	// Has the user voted?
	$res = $mysqli-&gt;query("
		SELECT 1 FROM appreciate_votes
		WHERE ip=".$ip." AND pageid=".$pageID
	);

	if($res-&gt;num_rows){
		$voted = 1;
	}

	$jsonArray = array('status'=&gt;1,'voted'=&gt;$voted,'appreciated'=&gt;$appreciated);
}

// Telling the browser to interpret the response as JSON:
header('Content-type: application/json');

echo json_encode($jsonArray);
</pre>
<p>The script handles two different types of AJAX requests &#8211; <strong>read only request</strong> (which returns a JSON object with information about the number of appreciations of the page, and whether the current user has clicked the button), and <strong>write requests </strong>(which save the visitor&#8217;s vote to the database, and if necessary, save the page URL and hash as well).</p>
<p>As you an see in the code snippet above, one of the first things that the script does is to calulate the <strong>MD5</strong> hash of the page. This is used as a unique key in the database, as URLs have unlimited length which is incompatible with MySQL&#8217;s UNIQUE keys. As an MD5 hash is unique for most practical purposes, we can safely use it in our selects and inserts, instead of the long URL addresses.</p>
<p>In the last line of the code, we convert the <strong>$jsonArray</strong> array into a valid JSON object with the inbuilt <strong>json_encode</strong> PHP function, and output it with a <strong>applicatoin/json</strong> content type.</p>
<div id="attachment_1043" class="wp-caption alignnone" style="width: 630px"><a href="http://demo.tutorialzine.com/2010/07/click-to-appreciate-badge-ajax-jquery-css/page.html"><img class="size-full wp-image-1043" title="Click To Appreciate - Inactive" src="http://tutorialzine.com/wp-content/uploads/2010/07/i4.png" alt="Click To Appreciate - Inactive" width="620" height="260" /></a><p class="wp-caption-text">Click To Appreciate - Inactive</p></div>
<h3>Step 3 &#8211; jQuery</h3>
<p>Inside the <strong>appreciateMe</strong> directory you can find the plugin.js file. You must include it in the page you wish to show the Appreciate button on. It uses AJAX to request data from the PHP backend and uses the response it receives to create the markup of the button.</p>
<h4>appreciateMe/plugin.js</h4>
<pre class="brush:js">function(){

	$.appreciateButton = function(options){

		// The options object must contain a URL and a Holder property
		// These are the URL of the Appreciate php script, and the
		// div in which the badge is inserted

		if(!'url' in options || !'holder' in options){
			return false;
		}

		var element = $(options.holder);

		// Forming the url of the current page:

		var currentURL = 	window.location.protocol+'//'+
					window.location.host+window.location.pathname;

		// Issuing a GET request. A rand parameter is passed
		// to prevent the request from being cached in IE

		$.get(options.url,{url:currentURL,rand:Math.random()},function(response){

			// Creating the appreciate button:

			var button = $('&lt;a&gt;',{
				href:'',className:'appreciateBadge',
				html:'Appreciate Me'
			});

			if(!response.voted){
				// If the user has not voted previously,
				// make the button active / clickable.
				button.addClass('active');
			}
			else button.addClass('inactive');

			button.click(function(){
				if(button.hasClass('active')){

					button.removeClass('active').addClass('inactive');

					if(options.count){
						// Incremented the total count
						$(options.count).html(1 + parseInt(response.appreciated));
					}

					// Sending a GET request with a submit parameter.
					// This will save the appreciation to the MySQL DB.

					$.getJSON(options.url,{url:currentURL,submit:1});
				}

				return false;
			});

			element.append(button);

			if(options.count){
				$(options.count).html(response.appreciated);
			}
		},'json');

		return element;
	}

})(jQuery);
</pre>
<p>The script basically creates a new method in the main jQuery object. This differs from the plugins that we usually do, in that this type of plugins are not called on a set of elements (no need to select elements). You can just call <strong>$.appreciateButton()</strong> while passing a configuration object as a parameter. This is exactly what we&#8217;ve done in <strong>script.js</strong> add a button to the page:</p>
<h4>script.js</h4>
<pre class="brush:css">$(document).ready(function(){

	// Creating an appreciate button.

	$.appreciateButton({
		url		: 'appreciateMe/script.php',	// URL to the PHP script.
		holder	: '#main',				// The button will be inserted here.
		count	: '#countDiv'			// Optional. Will show the total count.
	});

});
</pre>
<p>The configuration object, which is passed as a parameter, has to contain a <strong>url</strong> and a <strong>holder</strong> properties, whereas <strong>count</strong> is optional. Notice that I&#8217;ve specified the path to <strong>script.php</strong> relatively, as appreciateMe is a child directory of the one the page is currently in.</p>
<p>However, if you plan to add the script to a site with a variable path structure, you should probably specify an absolute path. Either add a <strong>leading slash</strong>, or provide a complete URL with <strong>http://</strong>.</p>
<h3>Step 4 &#8211; CSS</h3>
<p>Now that we have all the markup and code in place, it is time to turn to the styling. The CSS rules that style the appreciate badge are located in <strong>appreciate.css</strong>. You could optionally copy these rules to your main stylesheet file, if you&#8217;d like to avoid the extra request, but beware that you will need to change the paths to the background images.</p>
<h4>appreciateMe/appreciate.css</h4>
<pre class="brush:css">.appreciateBadge{
	width:129px;
	height:129px;
	display:block;
	text-indent:-9999px;
	overflow:hidden;
	background:url('sprite.png') no-repeat;
	text-decoration:none;
	border:none;
}

.appreciateBadge.active{
	background-position:left top;
}

.appreciateBadge.active:hover{
	background-position:0 -129px;
}

.appreciateBadge.inactive{
	background-position:left bottom;
	cursor:default;
}
</pre>
<p>There are three versions of the appreciate badge image. A default one, a hover one, and an inactive one. All three of these reside in the same file &#8211; <strong>sprite.png</strong>, one below the other. With this technique you can switch between the versions instantaneously by offsetting the background image of the hyperlink.</p>
<h4>styles.css</h4>
<pre class="brush:css">#main{
	margin:80px auto;
	width:130px;
}

#countDiv{
	color:#eee;
	font-size:35px;
	margin-right:120px;
	position:absolute;
	right:50%;
	top:265px;
}
</pre>
<p>You can find the rest of the styles, which refine the looks of <strong>page.html</strong>, in <strong>styles.css</strong>. Only two sets of styles affect the appreciate button directly. The <strong>#main</strong> div, which contains the button and centers it on the page, and <strong>#countDiv</strong> in which the total number of appreciations is inserted.</p>
<p><strong>With this our Click to Appreciate Badge is complete!</strong></p>
<h3>Conclusion</h3>
<p>Before being able to run this script on your server, you first have to replace the MySQL credentials in <strong>connect.php</strong> with your own. Also, you will need to run the contents of <strong>tables.sql</strong> in the SQL tab of <strong>phpMyAdmin, </strong>so the two tables are created. Lastly, depending on your URL paths, you may have to change the URL property of <strong>appreciateMe/script.php</strong> in the script.js JavaScript File.</p>
]]></content:encoded>
			<wfw:commentRss>http://tutorialzine.com/2010/07/click-to-appreciate-badge-ajax-jquery-css/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Simple AJAX Commenting System</title>
		<link>http://tutorialzine.com/2010/06/simple-ajax-commenting-system/</link>
		<comments>http://tutorialzine.com/2010/06/simple-ajax-commenting-system/#comments</comments>
		<pubDate>Wed, 30 Jun 2010 18:02:24 +0000</pubDate>
		<dc:creator>Martin Angelov</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://tutorialzine.com/?p=990</guid>
		<description><![CDATA[This time, we are making a Simple AJAX Commenting System. It will feature a gravatar integration and demonstrate how to achieve effective communication between jQuery and PHP/MySQL with the help of JSON.]]></description>
			<content:encoded><![CDATA[<p>This time, we are making a Simple AJAX Commenting System. It will feature a gravatar integration and demonstrate how to achieve effective communication between jQuery and PHP/MySQL with the help of JSON.</p>
<h3>Step 1 &#8211; XHTML</h3>
<p>First, lets take a look at the markup of the comments. This code is generated by PHP in the Comment class, which we are going  to take a look at in a moment.</p>
<h4>demo.php</h4>
<pre class="brush:html">&lt;div class="comment"&gt;
    &lt;div class="avatar"&gt;
        &lt;a href="http://tutorialzine.com/"&gt;
        &lt;img src="http://www.gravatar.com/avatar/112fdf7a8fe3609e7af2cd3873b5c6bd?size=50&amp;default=http%3A%2F%2Fdemo.tutorialzine.com%2F2010%2F06%2Fsimple-ajax-commenting-system%2Fimg%2Fdefault_avatar.gif"&gt;
        &lt;/a&gt;
    &lt;/div&gt;

    &lt;div class="name"&gt;&lt;a href="http://tutorialzine.com/"&gt;Person's Name&lt;/a&gt;&lt;/div&gt;
    &lt;div title="Added at 06:40 on 30 Jun 2010" class="date"&gt;30 Jun 2010&lt;/div&gt;
    &lt;p&gt;Comment Body&lt;/p&gt;
&lt;/div&gt;</pre>
<p>The avatar div contains a hyperlink (if the user entered a valid URL when submitting the comment) and an avatar image, which is fetched from <a href="http://en.gravatar.com/site/implement/images/" target="_blank">gravatar.com</a>. We will return to this in the PHP step of the tut. Lastly we have the name and time divs, and the comment body.</p>
<p>The other important element in the XHTML part is the comment form. It is sent via <strong>POST</strong>. All fields except for the URL field are required.</p>
<h4>demo.php</h4>
<pre class="brush:html">&lt;div id="addCommentContainer"&gt;
	&lt;p&gt;Add a Comment&lt;/p&gt;
	&lt;form id="addCommentForm" method="post" action=""&gt;
    	&lt;div&gt;
        	&lt;label for="name"&gt;Your Name&lt;/label&gt;
        	&lt;input type="text" name="name" id="name" /&gt;

            &lt;label for="email"&gt;Your Email&lt;/label&gt;
            &lt;input type="text" name="email" id="email" /&gt;

            &lt;label for="url"&gt;Website (not required)&lt;/label&gt;
            &lt;input type="text" name="url" id="url" /&gt;

            &lt;label for="body"&gt;Comment Body&lt;/label&gt;
            &lt;textarea name="body" id="body" cols="20" rows="5"&gt;&lt;/textarea&gt;

            &lt;input type="submit" id="submit" value="Submit" /&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;</pre>
<p>The form is submitted via AJAX. The validation is performed entirely in the backend by <strong>submit.php</strong>, as you will see in the jQuery step of the tutorial. Every field has a corresponding label element, with an appropriate <strong>for</strong> attribute.</p>
<div id="attachment_998" class="wp-caption alignnone" style="width: 630px"><a href="http://demo.tutorialzine.com/2010/06/simple-ajax-commenting-system/demo.php"><img class="size-full wp-image-998" title="Simple AJAX Commenting System" src="http://tutorialzine.com/wp-content/uploads/2010/06/i11.jpg" alt="Simple AJAX Commenting System" width="620" height="460" /></a><p class="wp-caption-text">Simple AJAX Commenting System</p></div>
<h3>Step 2 &#8211; PHP</h3>
<p>PHP handles the communication with the MySQL database and generates the markup of the comments. It is also on the receiving end of the AJAX requests and inserts the comment data to the <strong>comments</strong> table. You can see the code that prints the comments to the page below.</p>
<h4>demo.php</h4>
<pre class="brush:php">/*
/	Select all the comments and populate the $comments array with objects
*/

$comments = array();
$result = mysql_query("SELECT * FROM comments ORDER BY id ASC");

while($row = mysql_fetch_assoc($result))
{
	$comments[] = new Comment($row);
}</pre>
<p>The MySQL query selects all the entries from the database and fills the <strong>$comments</strong> array with objects of the comment class, which you will see below. This array is outputted later in the execution of the script.</p>
<h4>demo.php</h4>
<pre class="brush:php">/*
/	Output the comments one by one:
*/

foreach($comments as $c){
	echo $c-&gt;markup();
}</pre>
<p>Each comment has a<strong> markup()</strong> method, which generates valid HTML code ready to be printed to the page. You can see the definition of this method and the class below.</p>
<p>The class takes a row from the database (fetched with <strong>mysql_fetch_assoc()</strong> ) and stores it in the private variable<strong> $data</strong>. It is available only to  the methods of the class and cannot be accessed from outside.</p>
<h4>comment.class.php &#8211; Part 1</h4>
<pre class="brush:php">class Comment
{
	private $data = array();

	public function __construct($row)
	{
		/*
		/	The constructor
		*/

		$this-&gt;data = $row;
	}

	public function markup()
	{
		/*
		/	This method outputs the XHTML markup of the comment
		*/

		// Setting up an alias, so we don't have to write $this-&gt;data every time:
		$d = &amp;$this-&gt;data;

		$link_open = '';
		$link_close = '';

		if($d['url']){

			// If the person has entered a URL when adding a comment,
			// define opening and closing hyperlink tags

			$link_open = '&lt;a href="'.$d['url'].'"&gt;';
			$link_close =  '&lt;/a&gt;';
		}

		// Converting the time to a UNIX timestamp:
		$d['dt'] = strtotime($d['dt']);

		// Needed for the default gravatar image:
		$url = 'http://'.dirname($_SERVER['SERVER_NAME'].$_SERVER["REQUEST_URI"]).
				'/img/default_avatar.gif';

		return '

			&lt;div class="comment"&gt;
				&lt;div class="avatar"&gt;
					'.$link_open.'
					&lt;img src="http://www.gravatar.com/avatar/'.
				md5($d['email']).'?size=50&amp;default='.
				urlencode($url).'" /&gt;
					'.$link_close.'
				&lt;/div&gt;

				&lt;div class="name"&gt;'.$link_open.$d['name'].$link_close.'&lt;/div&gt;
				&lt;div class="date" title="Added at '.
				date('H:i \o\n d M Y',$d['dt']).'"&gt;'.
				date('d M Y',$d['dt']).'&lt;/div&gt;
				&lt;p&gt;'.$d['body'].'&lt;/p&gt;
			&lt;/div&gt;
		';
	}</pre>
<p>This script uses <a href="http://en.gravatar.com/site/implement/images/" target="_blank">gravatar</a> to present avatars in the comments. For those of you, who have not used gravatar, this is a really useful service, which lets you associate an avatar with your email address. The avatar image can easily be fetched by passing an <strong>md5()</strong> encoded hash of your email address to gravatar.com. This is exactly what we do on <strong>line 48</strong>.</p>
<p>Notice <strong>line 39</strong> above it &#8211; the script tries to figure out the URL at which it is located, and determines the exact address of the <strong>default_avatar.gif</strong> image. This gif is passed to gravatar along the md5 hash, so if no avatar was found for this particular email, the fallback image is displayed instead.</p>
<h4>comment.class.php &#8211; Part 2</h4>
<pre class="brush:php">	public static function validate(&amp;$arr)
	{
		/*
		/	This method is used to validate the data sent via AJAX.
		/
		/	It return true/false depending on whether the data is valid, and populates
		/	the $arr array passed as a paremter (notice the ampersand above) with
		/	either the valid input data, or the error messages.
		*/

		$errors = array();
		$data	= array();

		// Using the filter_input function introduced in PHP 5.2.0

		if(!($data['email'] = filter_input(INPUT_POST,'email',FILTER_VALIDATE_EMAIL)))
		{
			$errors['email'] = 'Please enter a valid Email.';
		}

		if(!($data['url'] = filter_input(INPUT_POST,'url',FILTER_VALIDATE_URL)))
		{
			// If the URL field was not populated with a valid URL,
			// act as if no URL was entered at all:

			$url = '';
		}

		// Using the filter with a custom callback function:

		if(!($data['body'] = filter_input(INPUT_POST,'body',FILTER_CALLBACK,
						array('options'=&gt;'Comment::validate_text'))))
		{
			$errors['body'] = 'Please enter a comment body.';
		}

		if(!($data['name'] = filter_input(INPUT_POST,'name',FILTER_CALLBACK,
						array('options'=&gt;'Comment::validate_text'))))
		{
			$errors['name'] = 'Please enter a name.';
		}

		if(!empty($errors)){

			// If there are errors, copy the $errors array to $arr:

			$arr = $errors;
			return false;
		}

		// If the data is valid, sanitize all the data and copy it to $arr:

		foreach($data as $k=&gt;$v){
			$arr[$k] = mysql_real_escape_string($v);
		}

		// Ensure that the email is in lower case (for a correct gravatar hash):
		$arr['email'] = strtolower(trim($arr['email']));

		return true;

	}</pre>
<p>The<strong> validate()</strong> method above (also part of the class) is defined as <strong>static</strong>. This means that it can be evoked directly like <strong>Comment::validate()</strong>, without the need of creating an object of the class. What this method does, is validate the input data which is submitted via AJAX.</p>
<p>This method uses the new filter functions, which are available as of <strong>PHP 5.2.0</strong>. These allow us to easily validate and filter any input data that is passed to the script. For example <em>filter_input(INPUT_POST,&#8217;url&#8217;,FILTER_VALIDATE_URL)</em> means that we are checking whether <strong>$_POST['url']</strong> is a valid URL address. If it is, the function returns the value of the variable, otherwise it return <strong>false</strong>.</p>
<p>This is really useful, as up until now, we had to use custom regular expressions to validate data (and have series of if statements). Also, another advantage is that this data is fetched before any configuration-specific transformations (like magic quotes) are applied.</p>
<p>We also have the option of specifying a custom function which is going to apply some more advanced modifications of the data, as you can see from lines 31 and 37.</p>
<h4>comment.class.php &#8211; Part 3</h4>
<pre class="brush:php">	private static function validate_text($str)
	{
		/*
		/	This method is used internally as a FILTER_CALLBACK
		*/

		if(mb_strlen($str,'utf8')&lt;1)
			return false;

		// Encode all html special characters (&lt;, &gt;, ", &amp; .. etc) and convert
		// the new line characters to &lt;br&gt; tags:

		$str = nl2br(htmlspecialchars($str));

		// Remove the new line characters that are left
		$str = str_replace(array(chr(10),chr(13)),'',$str);

		return $str;
	}

}</pre>
<p>The last method is <strong>validate_text,</strong> which we are passing as a callback function in the two filter_input calls above. It encodes all special HTML characters, effectively blocking XSS attacks. It also replaces the newline characters with &lt;br /&gt; line breaks.</p>
<h4>submit.php</h4>
<pre class="brush:php">/*
/	This array is going to be populated with either
/	the data that was sent to the script, or the
/	error messages:
/*/

$arr = array();

$validates = Comment::validate($arr);

if($validates)
{
	/* Everything is OK, insert to database: */

	mysql_query("	INSERT INTO comments(name,url,email,body)
					VALUES (
						'".$arr['name']."',
						'".$arr['url']."',
						'".$arr['email']."',
						'".$arr['body']."'
					)");

	$arr['dt'] = date('r',time());
	$arr['id'] = mysql_insert_id();

	/*
	/	The data in $arr is escaped for the mysql insert query,
	/	but we need the unescaped text, so we apply,
	/	stripslashes to all the elements in the array:
	/*/

	$arr = array_map('stripslashes',$arr);

	$insertedComment = new Comment($arr);

	/* Outputting the markup of the just-inserted comment: */

	echo json_encode(array('status'=&gt;1,'html'=&gt;$insertedComment-&gt;markup()));

}
else
{
	/* Outputting the error messages */
	echo '{"status":0,"errors":'.json_encode($arr).'}';
}</pre>
<p><strong>submit.php</strong> receives the comment form data via an AJAX request. It validates it and outputs a JSON object with either the XHTML markup of the successfully inserted comment, or a list of error messages. jQuery uses the status property to determine whether to display the error messages or add the comment markup to the page.</p>
<p>You can see two example responses below.</p>
<h4>Successful response</h4>
<pre class="brush:js">{
    "status": 1,
    "html": "Html Code Of The Comment Comes Here..."
}</pre>
<p>The <strong>html</strong> property contains the code of the comment, similar to markup in step one.</p>
<h4>Failure response</h4>
<pre class="brush:js">{
    "status": 0,
    "errors": {
        "email": "Please enter a valid Email.",
        "body": "Please enter a comment body.",
        "name": "Please enter a name."
    }
}</pre>
<p>On failure, jQuery loops through the errors object, and outputs the errors next to the fields that caused them.</p>
<div id="attachment_999" class="wp-caption alignnone" style="width: 630px"><a href="http://demo.tutorialzine.com/2010/06/simple-ajax-commenting-system/demo.php"><img class="size-full wp-image-999" title="Fancy CSS3 &amp; jQuery Submit Form" src="http://tutorialzine.com/wp-content/uploads/2010/06/i21.jpg" alt="Fancy CSS3 &amp; jQuery Submit Form" width="620" height="460" /></a><p class="wp-caption-text">Fancy CSS3 &amp; jQuery Submit Form</p></div>
<h3>Step 3 &#8211; CSS</h3>
<p>Now that we have all the markup properly generated and displayed on the page, we can move on to styling it.</p>
<h4>styles.css &#8211; Part 1</h4>
<pre class="brush:css">.comment,
#addCommentContainer{

	/* Syling the comments and the comment form container */

	padding:12px;
	width:400px;
	position:relative;
	background-color:#fcfcfc;
	border:1px solid white;
	color:#888;
	margin-bottom:25px;

	/* CSS3 rounded corners and drop shadows */

	-moz-border-radius:10px;
	-webkit-border-radius:10px;
	border-radius:10px;

	-moz-box-shadow:2px 2px 0 #c2c2c2;
	-webkit-box-shadow:2px 2px 0 #c2c2c2;
	box-shadow:2px 2px 0 #c2c2c2;
}

.comment .avatar{

	/*
	/	The avatar is positioned absolutely,
	/	and offset outside the comment div
	/*/

	height:50px;
	left:-70px;
	position:absolute;
	width:50px;
	background:url('img/default_avatar.gif') no-repeat #fcfcfc;

	/* Centering it vertically: */

	margin-top:-25px;
	top:50%;

	-moz-box-shadow:1px 1px 0 #c2c2c2;
	-webkit-box-shadow:1px 1px 0 #c2c2c2;
	box-shadow:1px 1px 0 #c2c2c2;
}</pre>
<p>The .comment divs and the #addCommentContainer are styled at once because they share most of the styling. A number of CSS3 rules are applied, including rounded corners and a box-shadow. Needless to say, these do not work in older browsers, but as they are purely presentational, the script will still work without them.</p>
<h4>styles.css &#8211; Part 2</h4>
<pre class="brush:css">.comment .avatar img{
	display:block;
}

.comment .name{
	font-size:20px;
	padding-bottom:10px;
	color:#ccc;
}

.comment .date{
	font-size:10px;
	padding:6px 0;
	position:absolute;
	right:15px;
	top:10px;
	color:#bbb;
}

.comment p,
#addCommentContainer p{
	font-size:18px;
	line-height:1.5;
}

#addCommentContainer input[type=text],
#addCommentContainer textarea{

	/* Styling the inputs */

	display:block;
	border:1px solid #ccc;
	margin:5px 0 5px;
	padding:3px;
	font-size:12px;
	color:#555;
	font-family:Arial, Helvetica, sans-serif;
}

#addCommentContainer textarea{
	width:300px;
}

label{
	font-size:10px;
}

label span.error{
	color:red;
	position:relative;
	right:-10px;
}

#submit{

	/* The submit button */

	background-color:#58B9EB;
	border:1px solid #40A2D4;
	color:#FFFFFF;
	cursor:pointer;
	font-family:'Myriad Pro',Arial,Helvetica,sans-serif;
	font-size:14px;
	font-weight:bold;
	padding:4px;
	margin-top:5px;

	-moz-border-radius:4px;
	-webkit-border-radius:4px;
	border-radius:4px;
}

#submit:hover{
	background-color:#80cdf5;
	border-color:#52b1e2;
}</pre>
<p>In the second part of the stylesheet, we style the comment and form elements. Notice the <strong>input[type=text]</strong> selector, which selects elements depending on the type attribute.</p>
<h3>Step 4 &#8211; jQuery</h3>
<p>Now lets continue with jQuery, which is the last step of this tutorial. After including the library to the bottom of the page (best for the perceived performance of the page) we can start coding the script file.</p>
<h4>script.js</h4>
<pre class="brush:js">$(document).ready(function(){
	/* The following code is executed once the DOM is loaded */

	/* This flag will prevent multiple comment submits: */
	var working = false;

	/* Listening for the submit event of the form: */
	$('#addCommentForm').submit(function(e){

 		e.preventDefault();
		if(working) return false;

		working = true;
		$('#submit').val('Working..');
		$('span.error').remove();

		/* Sending the form fileds to submit.php: */
		$.post('submit.php',$(this).serialize(),function(msg){

			working = false;
			$('#submit').val('Submit');

			if(msg.status){

				/*
				/	If the insert was successful, add the comment
				/	below the last one on the page with a slideDown effect
				/*/

				$(msg.html).hide().insertBefore('#addCommentContainer').slideDown();
				$('#body').val('');
			}
			else {

				/*
				/	If there were errors, loop through the
				/	msg.errors object and display them on the page
				/*/

				$.each(msg.errors,function(k,v){
					$('label[for='+k+']').append('&lt;span class="error"&gt;'+
						v+'&lt;/span&gt;');
				});
			}
		},'json');

	});

});</pre>
<p>Starting from the top, we have the <strong>$(document).ready()</strong> call, which binds a function to the <em>DOM content loaded</em> event. The working variable acts as a flag, which tells the script if an AJAX request is in progress (thus preventing double posting).</p>
<p>In the callback function for the POST AJAX request, we check the status property to determine whether the comment was successfully inserted. If it was, we add the received markup to the page after the last comment with a <em>slideDown </em>animation.</p>
<p>If there were problems, we display the error messages by appending an error span to the appropriate label element (the for attribute of the label contains the id of the input that caused the error).</p>
<p><strong>With this our Simple AJAX Commenting System is complete!</strong></p>
<h3>Conclusion</h3>
<p>To be able to run this script on your server, you need to create the <strong><em>comments</em></strong> table in your MySQL database. You can do this by executing the SQL code found in <strong>table.sql</strong> from the SQL tab of phpMyAdmin. After this you need to enter your MySQL connection details in <strong><em>connect.php</em></strong>.</p>
<p>You are free to modify and use this code any way you see fit.</p>
<p><strong>What do you think? How would you improve this script?</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://tutorialzine.com/2010/06/simple-ajax-commenting-system/feed/</wfw:commentRss>
		<slash:comments>47</slash:comments>
		</item>
		<item>
		<title>Making a Donation Center With PHP, MySQL and PayPal&#8217;s APIs</title>
		<link>http://tutorialzine.com/2010/05/donation-center-php-mysql-paypal-api/</link>
		<comments>http://tutorialzine.com/2010/05/donation-center-php-mysql-paypal-api/#comments</comments>
		<pubDate>Thu, 13 May 2010 13:27:21 +0000</pubDate>
		<dc:creator>Martin Angelov</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://tutorialzine.com/?p=891</guid>
		<description><![CDATA[Today we are making a dedicated Donation Center with PHP, MySQL &#038; PayPal's APIs. It will feature goal setting, a complete PayPal integration, and a donor list with the people who have already donated.]]></description>
			<content:encoded><![CDATA[<p>It all started last month when I received the following email:</p>
<blockquote><p>Hey there Tutorialzine!</p>
<p>Thanks for publishing such great tutorials, you have truly helped me increase my (growing) development skills. I know you enjoy getting ideas for tutorials, so I thought I&#8217;d toss one your way.</p>
<p>Donation buttons are a very common among blogs and websites in general, but they often don&#8217;t provide much else than a button for someone to click and pay. Why not kick it up a notch and create a sweet &#8220;donation center&#8221;, which doesn&#8217;t just take donations, but perhaps includes a &#8220;meter&#8221;, a top-donator list, and various other bells and whistles that may encourage the visitor to donate?</p>
<p>Devon</p></blockquote>
<p>You are right, Devon, it is always nice to hear fresh ideas for tutorials. And a donation center is a great chance to experiment with PayPal&#8217;s APIs and build something that many people can benefit from.</p>
<h3>The Idea</h3>
<p>PayPal provides numerous APIs and integration options for third-party developers. One of these is the Donation button, which you can generate straight from PayPal&#8217;s site and include directly into your pages. Conversion rate for these buttons is typically minimal, but the right incentive can make a big difference.</p>
<p>The idea is to have a dedicated <strong>Donation Center</strong>. This is a place, where you get to see what a difference your donation would make, and a list of people who have already donated.</p>
<p>After choosing the amount you wish to donate and clicking the button, you are redirected to <em>paypal.com</em> to complete the transaction. After this is done, you are redirected back to the donation center where you can fill a form and get included in the official <strong>Donor List</strong>.</p>
<div id="attachment_899" class="wp-caption alignnone" style="width: 630px"><a href="http://demo.tutorialzine.com/2010/05/donation-center-php-mysql-paypal-api/donate.php"><img class="size-full wp-image-899" title="A Complete PHP &amp; MySQL Donation Center" src="http://tutorialzine.com/wp-content/uploads/2010/05/i21.png" alt="A Complete PHP &amp; MySQL Donation Center" width="620" height="260" /></a><p class="wp-caption-text">A Complete PHP &amp; MySQL Donation Center</p></div>
<h3>Step 1 &#8211; Database</h3>
<p>The script uses two tables &#8211; <strong>dc_donations</strong> and <strong>dc_comments</strong>. The first stores the donation data which is passed in a request from PayPal (we will come back to this in the PHP step of the tutorial).</p>
<div id="attachment_900" class="wp-caption alignnone" style="width: 630px"><a href="http://tutorialzine.com/wp-content/uploads/2010/05/i5.png"><img class="size-full wp-image-900" title="Table Schema for dc_donations" src="http://tutorialzine.com/wp-content/uploads/2010/05/i5.png" alt="Table Schema for dc_donations" width="620" height="260" /></a><p class="wp-caption-text">Table Schema for dc_donations</p></div>
<p>The second table holds the information about the donors, which they fill for themselves on the thank you page.</p>
<div id="attachment_901" class="wp-caption alignnone" style="width: 630px"><a href="http://tutorialzine.com/wp-content/uploads/2010/05/i4.png"><img class="size-full wp-image-901" title="Table Schema for dc_comments" src="http://tutorialzine.com/wp-content/uploads/2010/05/i4.png" alt="Table Schema for dc_comments" width="620" height="260" /></a><p class="wp-caption-text">Table Schema for dc_comments</p></div>
<p>You can create these tables in your database by running the SQL code from <strong>tables.sql</strong> (found in the download archive) from the SQL tab of phpMyAdmin. You can also just upload the file via the &#8220;Import&#8221; feature.</p>
<p>After this remember to add your MySQL login details to <strong>connect.php</strong>.</p>
<h3>Step 2 &#8211; XHTML</h3>
<p>Moving to the markup of the donation center iself. Donate PHP is the only page which your visitors see. The other page is <strong>thankyou.php</strong>, which is displayed only to the donors, once they&#8217;ve completed the donation process.</p>
<h4>donate.php</h4>
<pre class="brush:html">&lt;div id="main"&gt;
	&lt;h1&gt;Donation Center&lt;/h1&gt;
	&lt;h2&gt;Show Your Support for our Cause&lt;/h2&gt;

	&lt;div class="lightSection"&gt;
		&lt;h3&gt;Hello, dear visitor!&lt;/h3&gt;
		&lt;p&gt;This is Tutorialzine's Donation Center...&lt;/p&gt;	

		&lt;!-- The PayPal Donation Button --&gt;

	&lt;/div&gt;

	&lt;div class="chart"&gt;
		Our Goal
	&lt;/div&gt;

	&lt;div class="donations"&gt;
		&lt;?php echo $percent?&gt;% done
	&lt;/div&gt;

	&lt;div class="clear"&gt;&lt;/div&gt;

	&lt;div class="donors"&gt;
		&lt;h3&gt;The Donor List&lt;/h3&gt;
		&lt;h4&gt;Folks Who Showed Their Support&lt;/h4&gt;

		&lt;div class="comments"&gt;

		&lt;!-- PHP Code that generates the comments --&gt;

		&lt;/div&gt; &lt;!-- Closing the comments div --&gt;

	&lt;/div&gt; &lt;!-- Closing the donors div --&gt;

&lt;/div&gt; &lt;!-- Closing the main div --&gt;</pre>
<p>The <strong>.lightSection</strong> div holds the message that we show to the visitor of the page and the markup of the PayPal donation button, which you can see below. After this is the Pie chart which shows how much of our initial goal is met. The chart is generated with <a href="http://code.google.com/apis/charttools/index.html" target="_blank">Google&#8217;s Charting API</a>. Lastly is the <strong>.donors</strong> div, which holds a list of donors that have already donated.</p>
<h4>donate.php</h4>
<pre class="brush:html">&lt;form action="&lt;?php echo $payPalURL?&gt;" method="post" class="payPalForm"&gt;
	&lt;div&gt;
		&lt;input type="hidden" name="cmd" value="_donations" /&gt;
		&lt;input type="hidden" name="item_name" value="Donation" /&gt;

		&lt;!-- Your PayPal email: --&gt;
		&lt;input type="hidden" name="business"
		value="&lt;?php echo $myPayPalEmail?&gt;"/&gt;

		&lt;!-- PayPal will send an IPN notification to this URL: --&gt;
		&lt;input type="hidden" name="notify_url"
		value="&lt;?php echo $url.'/ipn.php'?&gt;" /&gt; 

		&lt;!-- The return page to which the user is
		navigated after the donations is complete: --&gt;

		&lt;input type="hidden" name="return"
		value="&lt;?php echo $url.'/thankyou.php'?&gt;" /&gt; 

		&lt;!-- Signifies that the transaction data will be
		passed to the return page by POST: --&gt;

		&lt;input type="hidden" name="rm" value="2" /&gt; 

		&lt;!-- General configuration variables for the paypal landing page. --&gt;

		&lt;input type="hidden" name="no_note" value="1" /&gt;
		&lt;input type="hidden" name="cbt" value="Go Back To The Site" /&gt;
		&lt;input type="hidden" name="no_shipping" value="1" /&gt;
		&lt;input type="hidden" name="lc" value="US" /&gt;
		&lt;input type="hidden" name="currency_code" value="USD" /&gt;

		&lt;!-- The amount of the transaction: --&gt;

		&lt;select name="amount"&gt;
		&lt;option value="50"&gt;$50&lt;/option&gt;
		&lt;option value="20"&gt;$20&lt;/option&gt;
		&lt;option value="10" selected="selected"&gt;$10&lt;/option&gt;
		&lt;option value="5"&gt;$5&lt;/option&gt;
		&lt;option value="2"&gt;$2&lt;/option&gt;
		&lt;option value="1"&gt;$1&lt;/option&gt;
		&lt;/select&gt;

		&lt;input type="hidden" name="bn" value="
		PP-DonationsBF:btn_donate_LG.gif:NonHostedGuest" /&gt;

		&lt;!-- You can change the image of the button: --&gt;
		&lt;input type="image" src="https://www.paypal.com/en_US/i/btn/btn_donate_LG.gif" name="submit" alt="PayPal - The safer, easier way to pay online!" /&gt;

	&lt;img alt="" src="https://www.paypal.com/en_US/i/scr/pixel.gif"
	width="1" height="1" /&gt;

	&lt;/div&gt;
&lt;/form&gt;
</pre>
<p>The PayPal Donation button is structured as a regular html form. When you click the Donate graphic, the form is submitted to PayPal. A number of customizations are available, such as the the amount of the donation, the email of the recipient of the donation and many more (the full list of options is located <a href="http://www.paypal.com/IntegrationCenter/ic_std-variable-ref-donate.html" target="_blank">here</a>). Each of this options is added as a hidden field to the form.</p>
<p>Note the <strong>return</strong> and the <strong>notify_url</strong> variables. The first takes the URL of the page to which the user is redirected after the completion of the payment (in our case  <strong>thankyou.php</strong>), and the other is a special page, which listens for PayPal&#8217;s Instant Payment Notifications (<strong>IPN</strong>).</p>
<blockquote><p>When a payment occurs, PayPal sends a special IPN notification to a page on your server. Data about the transaction is passed along the way, including the amount received, the email of the payee, currency and more. For example our IPN listener page, <strong>ipn.php</strong>, inserts the amount received to the donations table, which is later used by the Donation Center to calculate how much money has been gathered and what percentage of the goal has been met.</p></blockquote>
<p>Now lets move to the PHP part of the tutorial.</p>
<div id="attachment_902" class="wp-caption alignnone" style="width: 630px"><a href="http://demo.tutorialzine.com/2010/05/donation-center-php-mysql-paypal-api/donate.php"><img class="size-full wp-image-902  " title="Setting a Goal with Google's Charting API" src="http://tutorialzine.com/wp-content/uploads/2010/05/i3.png" alt="Setting a Goal with Google's Charting API" width="620" height="260" /></a><p class="wp-caption-text">Setting a Goal with Google&#39;s Charting API</p></div>
<h3>Step 3 &#8211; PHP</h3>
<p>As mentioned in the previous step, when a payment occurs, PayPal sends an IPN notification to your script, which contains all kinds of data for the transaction. Implementing this IPN listener page involves a lot of coding, as the script must validate that the notification was issued by PayPal.</p>
<p>Lucky for us, there are nice people out there who have already implemented these validations and packed them into an easy to use <a href="http://www.phpclasses.org/package/2249-PHP-Process-Paypal-payment-interactions.html" target="_blank">PHP5 PayPal class</a>. Now lets take a look at how this is used:</p>
<h4>ipn.php</h4>
<pre class="brush:php">require "paypal_integration_class/paypal.class.php";
require "config.php";
require "connect.php";

$p = new paypal_class;
$p-&gt;paypal_url = $payPalURL; // $payPalURL is defined in config.php

if ($p-&gt;validate_ipn()) {
	if($p-&gt;ipn_data['payment_status']=='Completed')
	{
		$amount = $p-&gt;ipn_data['mc_gross'] - $p-&gt;ipn_data['mc_fee'];

		mysql_query("	INSERT INTO dc_donations (transaction_id,donor_email,amount,original_request)
						VALUES (
							'".esc($p-&gt;ipn_data['txn_id'])."',
							'".esc($p-&gt;ipn_data['payer_email'])."',
							".(float)$amount.",
							'".esc(http_build_query($_POST))."'
						)");
	}
}

function esc($str)
{
	global $link;
	return mysql_real_escape_string($str,$link);
}</pre>
<p>First we create a new <strong>paypal_class</strong> and assign it PayPal&#8217;s URL. The rest is just a matter of calling the <strong>$p-&gt;validate_ipn()</strong> method and it will do all the hard work for us. If everything went OK, we insert the amount of the transaction, the email of the payee and the transaction id to the <strong>dc_donations</strong> table. It is probably a good place to note, that this page is not visible to the end user, it only exists to listen for IPN notifications from paypal which happen on the backend.</p>
<h4>thankyou.php</h4>
<pre class="brush:php">require "config.php";
require "connect.php";

if(isset($_POST['submitform']) &amp;&amp; isset($_POST['txn_id']))
{
	$_POST['nameField'] = esc($_POST['nameField']);
	$_POST['websiteField'] =  esc($_POST['websiteField']);
	$_POST['messageField'] = esc($_POST['messageField']);

	$error = array();

	if(mb_strlen($_POST['nameField'],"utf-8")&lt;2)
	{
		$error[] = 'Please fill in a valid name.';
	}

	if(mb_strlen($_POST['messageField'],"utf-8")&lt;2)
	{
		$error[] = 'Please fill in a longer message.';
	}

	if(!validateURL($_POST['websiteField']))
	{
		$error[] = 'The URL you entered is invalid.';
	}

	$errorString = '';
	if(count($error))
	{
		$errorString = join('&lt;br /&gt;',$error);
	}
	else
	{
		mysql_query("	INSERT INTO dc_comments (transaction_id, name, url, message)
						VALUES (
							'".esc($_POST['txn_id'])."',
							'".$_POST['nameField']."',
							'".$_POST['websiteField']."',
							'".$_POST['messageField']."'
						)");

		if(mysql_affected_rows($link)==1)
		{
			$messageString = '&lt;a href="donate.php"&gt;You were added to our donor section!&lt;/a&gt;';
		}
	}
}</pre>
<p>After the use has donated, he is redirected by PayPal to our thank you page. Here he can add himself to the donor list by filling in a form. Wen redirecting, PayPal places transaction data in the <strong>$_POST</strong> array, which is available to <strong>thankyou.php</strong>. We can use this data to confirm that the user has in fact donated, and not just navigated manually to <strong>thankyou.php</strong>, bypassing PayPal. After the form is submitted, the user is added to the <strong>dc_comments</strong> table.</p>
<h4>donate.php</h4>
<pre class="brush:php">require "config.php";
require "connect.php";

// Determining the URL of the page:
$url = 'http://'.$_SERVER['SERVER_NAME'].dirname($_SERVER["REQUEST_URI"]);

// Fetching the number and the sum of the donations:
list($number,$sum) = mysql_fetch_array(mysql_query("SELECT COUNT(*),SUM(amount) FROM dc_donations"));

// Calculating how many percent of the goal are met:
$percent = round(min(100*($sum/$goal),100));

// Building a URL with Google's Chart API:
$chartURL = 'http://chart.apis.google.com/chart?chf=bg,s,f9faf7&amp;cht=p&amp;chd=t:'.$percent.',-'.(100-$percent).'&amp;chs=200x200&amp;chco=639600&amp;chp=1.57';
</pre>
<p>Google&#8217;s Chart Api is an easy way to generate any kind of chart. To use it you just have to create a URL to <a href="http://chart.apis.google.com/" target="_blank">http://chart.apis.google.com/</a> which contains settings such as background color, type of chart (in our case a Pie), and a comma-separated list of values which serve as the data. You can include this URL as you would do a regular image, and a chart will be dynamically generated for you.</p>
<h4>donate.php</h4>
<pre class="brush:php">&lt;?php
    $comments = mysql_query("SELECT * FROM dc_comments ORDER BY id DESC");

    // Building the Donor List:

    if(mysql_num_rows($comments))
    {
        while($row = mysql_fetch_assoc($comments))
        {
            ?&gt;

                &lt;div class="entry"&gt;
                    &lt;p class="comment"&gt;
                    &lt;?php
                        echo nl2br($row['message']); // Converting the newlines of the comment to &lt;br /&gt; tags
                    ?&gt;
                    &lt;span class="tip"&gt;&lt;/span&gt;
                    &lt;/p&gt;

                    &lt;div class="name"&gt;
                        &lt;?php echo $row['name']?&gt; &lt;a class="url" href="&lt;?php echo $row['url']?&gt;"&gt;&lt;?php echo $row['url']?&gt;&lt;/a&gt;
                    &lt;/div&gt;
                &lt;/div&gt;

            &lt;?php
        }
    }
?&gt;</pre>
<p>Later in <strong>donate.php</strong>, we are building the donor list after running a query against the <strong>dc_comments</strong> table.</p>
<div id="attachment_898" class="wp-caption alignnone" style="width: 630px"><a href="http://demo.tutorialzine.com/2010/05/donation-center-php-mysql-paypal-api/donate.php"><img class="size-full wp-image-898 " title="The Donor List" src="http://tutorialzine.com/wp-content/uploads/2010/05/i1.png" alt="The Donor List" width="620" height="260" /></a><p class="wp-caption-text">The Donor List</p></div>
<h3>Step 4 &#8211; CSS</h3>
<p>Having all the markup generated and included in the page, it is time to style it. You may find it surprising but the entire design is entirely CSS based and does not use a single image (apart from PayPal&#8217;s Donate button image that is).</p>
<h4>styles.css &#8211; Part 1</h4>
<pre class="brush:css">*{
	/* Universal page reset */
	margin:0;
	padding:0;
}

body{
	/* Setting default text color, background and a font stack */
	font-size:13px;
	color:#9bb370;
	background-color:#f9faf7;
	font-family:Rockwell, 'Courier New', Courier, Georgia, serif;
}

p{
	font-family:Arial, Helvetica, sans-serif;
	font-size:20px;
}

h1{
	/* The Donation Center text */
	border-bottom:1px solid #E3EBD2;
	color:#639600;
	font-size:70px;
	line-height:1;
	margin-left:-20px;
	padding:0 0 0 30px;
}

h2{
	/* The subtitle, notice the line-height property */
	border-left:1px solid #E3EBD2;
	color:#ABC084;
	font-size:35px;
	height:35px;
	line-height:75px;
	margin:-70px 0 0;
	padding:55px 0 0 10px;
}

h3{
	color:#639600;
	font-size:38px;
}

#main{
	/* The main container div */
	margin:40px auto;
	padding:0 0 0 20px;
	position:relative;
	width:860px;
}</pre>
<p>You may notice in the demo page, how the Donation Center heading and subheading form an interesting set of lines. These are in fact the bottom and left borders of the h1 and h2 respectively.</p>
<h4>styles.css &#8211; Part 2</h4>
<pre class="brush:css">.chart{
	/* The Google Chart is set as this div's background via the style attribute.
	The negative text-indent moves the text outside the box */

	margin:0 0 0 300px;
	text-indent:-300px;
	width:200px;
}

.donations,.chart{
	color:#ABC084;
	font-size:50px;
	font-weight:bold;
	float:left;
	height:200px;
	line-height:200px;
}

.donations{ text-align:right; width:340px;}
.comments{ margin-top:60px;}
.entry{ margin-bottom:50px;}

.comment{
	background-color:#edf2e4;
	padding:20px;
	position:relative;
	margin-bottom:20px;
}

.name{
	color:#639600;
	font-size:24px;
	font-style:italic;
	font-weight:bold;
	position:relative;
}

.name a.url{
	color:#C0D39C;
	font-weight:normal;
	padding-left:10px;
}

.tip{
	width:0;
	height:0;
	bottom:-40px;
	left:20px;

	/* A neat CSS trick which creates a triangle shape*/
	/* from the div's top border */

	border:20px solid #f9faf7;
	border-width:20px 15px;
	border-top-color:#edf2e4;
	position:absolute;
}</pre>
<p>Creating a triangle shape with CSS is also possible by setting the width and the height of the div to zero and specifying a big value for the widths of the borders.</p>
<p><strong>With this our PHP &amp; MySQL Donation Center is complete!</strong></p>
<h3>Conclusion</h3>
<p>You can use this donation center to turn the usually anonymous act of donating funds into a more social and open process. You can possibly modify the code to include Twitter &amp; Facebook integration or improve it in any other way you see fit.</p>
<p><strong>What do you think? How would you improve this code?</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://tutorialzine.com/2010/05/donation-center-php-mysql-paypal-api/feed/</wfw:commentRss>
		<slash:comments>27</slash:comments>
		</item>
		<item>
		<title>Simple Banner Rotator With PHP, jQuery &amp; MySQL</title>
		<link>http://tutorialzine.com/2010/04/simple-banner-rotator-with-php-jquery-mysql/</link>
		<comments>http://tutorialzine.com/2010/04/simple-banner-rotator-with-php-jquery-mysql/#comments</comments>
		<pubDate>Tue, 27 Apr 2010 20:59:49 +0000</pubDate>
		<dc:creator>Martin Angelov</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://tutorialzine.com/?p=867</guid>
		<description><![CDATA[In this tutorial we are making a simple PHP, jQuery &#038; MySQL banner rotator, with which you can create and randomly display banners on your site.]]></description>
			<content:encoded><![CDATA[<p>In this tutorial we are making a simple PHP, jQuery &amp; MySQL banner rotator, with which you can create and randomly display banners on your site. Each of the banners features a neat jQuery animation effect, which you can customize to fit your own needs.</p>
<h3>The database schema</h3>
<p>Before we start coding, lets take a look at the database. All the banners are inserted into the <strong>banners</strong> MySQL table. It has the following structure:</p>
<div id="attachment_871" class="wp-caption alignnone" style="width: 630px"><a href="http://tutorialzine.com/wp-content/uploads/2010/04/i13.png"><img class="size-full wp-image-871" title="The Database Schema" src="http://tutorialzine.com/wp-content/uploads/2010/04/i13.png" alt="The Database Schema" width="620" height="260" /></a><p class="wp-caption-text">The Database Schema</p></div>
<p><strong>ID</strong> is a primary key, which is auto-incremented, which means that you don&#8217;t need to add a number in that field if you are manually inserting new banners. Next is the <strong>image</strong> field, which holds the filename of the banner, after it is the <strong>company name</strong> and lastly the <strong>URL</strong> of the company&#8217;s site, all of which are varchar fields (regular strings).</p>
<p>If you want to run the demo on your own host, you will need to recreate this table from the definitions inside <strong>table.sql</strong> in the download archive. Just paste the SQL colde in your MySQL manager. Also don&#8217;t forget to fill in your MySQL login details in <strong>connect.php</strong>, before uploading the files to your server.</p>
<h3>Step 1 &#8211; XHTML</h3>
<p>The XHTML code of the banners is generated on the fly by PHP after a database query, and outputted to the page. Here is how the markup for a sample banner looks like:</p>
<h4>demo.php</h4>
<pre class="brush:html">&lt;div class="banner"&gt;
	&lt;a href="http://www.rapidxhtml.com/"&gt;
		&lt;img src="img/banners/rapidHTML.png" alt="Rapid HTML"
		width="125" height="125" /&gt;
	&lt;/a&gt;
	&lt;p class="companyInfo"&gt;Visit Rapid HTML&lt;/p&gt;
	&lt;div class="cornerTL"&gt;&lt;/div&gt;
	&lt;div class="cornerTR"&gt;&lt;/div&gt;
	&lt;div class="cornerBL"&gt;&lt;/div&gt;
	&lt;div class="cornerBR"&gt;&lt;/div&gt;
&lt;/div&gt;</pre>
<p>Inside each banner div, we have a hyperlink to the company&#8217;s site, a standard 125 by 125 px banner, a paragraph with the company name, and four corner divs.</p>
<p>The paragraph and the corner divs are hidden by default and are shown when the user moves their mouse over the main <strong>.banner</strong> div. This ensures that the banners are perfectly functional even with JavaScript disabled, albeit without the fancy transition.</p>
<div id="attachment_872" class="wp-caption alignnone" style="width: 630px"><a href="http://tutorialzine.com/wp-content/uploads/2010/04/i41.png"><img class="size-full wp-image-872" title="The jQuery Animation" src="http://tutorialzine.com/wp-content/uploads/2010/04/i41.png" alt="The jQuery Animation" width="620" height="260" /></a><p class="wp-caption-text">The jQuery Animation</p></div>
<h3>Step 2 &#8211; CSS</h3>
<p>Lets move to styling the page. To ensure cross-browser compatibility, we first have to reset the default styles that browsers apply to page elements. This is simple to do with a universal page reset:</p>
<h4>styles.css &#8211; Part 1</h4>
<pre class="brush:css">*{
	/* A universal page reset */
	margin:0;
	padding:0;
}

body{
	/* Setting default text color, background and a font stack */
	font-size:0.825em;
	color:#666;
	background-color:#fff;
	font-family:Arial, Helvetica, sans-serif;
}

.bannerHolder{
	/* The main banner unordered list */

	height:270px;
	width:270px;

	float:left;
	margin:20px 15px;
	padding:10px;
	background:#f7f7f7;
	border:1px solid #eee;

	/* CSS3 rounded corners */

	-moz-border-radius:12px;
	-webkit-border-radius:12px;
	border-radius:12px;
}

.bannerHolder li{
	/* Hiding the bullets of the li elements: */
	list-style:none;
	display:inline;
}

.banner{
	/* The banner divs */
	position:relative;
	width:125px;
	height:125px;
	overflow:hidden;
	float:left;
	margin:5px;
}

.banner img{
	/* The banner divs */
	display:block;
	border:none;
}</pre>
<p>As the banners are organized in an unordered list, we first style the list itself (which is assigned the <strong>bannerHolder</strong> class), then the li elements inside it and lastly the banner divs.</p>
<p>As we have two groups of banners on the page, we have to stick to class names to target the elements in the CSS, as IDs must be unique and don&#8217;t allow for more than one element with the same ID.</p>
<h4>styles.css &#8211; Part 2</h4>
<pre class="brush:css">.banner div{
	/* The dark animated divs */

	position:absolute;
	z-index:100;
	background-color:#222;
	width:60px;
	height:60px;
	cursor:pointer;

	/*	Setting a really big value for border-radius
		will make the divs perfect circles */

	-moz-border-radius:100px;
	-webkit-border-radius:100px;
	border-radius:100px;
}

/*	Positioning the animated divs outside the
	corners of the visible banner area: */

.banner .cornerTL{ left:-63px;top:-63px; }
.banner .cornerTR{ right:-63px;top:-63px; }
.banner .cornerBL{ left:-63px;bottom:-63px; }
.banner .cornerBR{ right:-63px;bottom:-63px; }

.banner p{
	/* The "Visit Company" text */

	display:none;	/* hidden by default */

	left:0;
	top:57px;
	width:100%;
	z-index:200;
	position:absolute;

	font-family:Tahoma, Arial, Helvetica, sans-serif;
	color:white;
	font-size:11px;
	text-align:center;

	cursor:pointer;
}</pre>
<p>In the second part of the code we style the animated rounded divs that slide into view on mouseenter. We are using the <strong>border-radius</strong> CSS3 property and by giving it a <strong>100px</strong> value, we turn the divs into perfect circles. We also position each of the four divs just outside its parent div.</p>
<div id="attachment_873" class="wp-caption alignnone" style="width: 630px"><a href="http://demo.tutorialzine.com/2010/04/simple-banner-rotator-php-mysql-jquery/demo.php"><img class="size-full wp-image-873" title="A PHP, MySQL &amp; jQuery Banner Rotator" src="http://tutorialzine.com/wp-content/uploads/2010/04/i22.jpg" alt="A PHP, MySQL &amp; jQuery Banner Rotator" width="620" height="460" /></a><p class="wp-caption-text">A PHP, MySQL &amp; jQuery Banner Rotator</p></div>
<h3>Step 3 &#8211; PHP</h3>
<p>Moving to the PHP part, we will first take a look at the banner class.</p>
<h4>banner.class.php</h4>
<pre class="brush:php">class Banner{

	private $data = array();

	public function __construct($row){
		$this-&gt;data = $row;
	}

	public function html(){

		/* This method returns the banner's HTML code */

		$d = &amp;$this-&gt;data;
		$d['company'] = htmlspecialchars($d['company']);

		return '
			&lt;div class="banner"&gt;
				&lt;a href="'.$d['url'].'"&gt;
					&lt;img src="img/banners/'.$d['image'].'" alt="'.$d['company'].'"
					width="125" height="125" /&gt;
				&lt;/a&gt;
				&lt;p class="companyInfo"&gt;Visit '.$d['company'].'&lt;/p&gt;
				&lt;div class="cornerTL"&gt;&lt;/div&gt;
				&lt;div class="cornerTR"&gt;&lt;/div&gt;
				&lt;div class="cornerBL"&gt;&lt;/div&gt;
				&lt;div class="cornerBR"&gt;&lt;/div&gt;
			&lt;/div&gt;';
	}

}</pre>
<p>The constructor method of the class is executed when we create a banner object. It copies the <strong>$row</strong> variable we pass as a parameter to its internal private <strong>$data</strong> array.</p>
<p>The other method &#8211; <strong>html()</strong> &#8211; returns the HTML code of the banner.</p>
<p>You can see below how this class and its methods are used:</p>
<h4>demo.php</h4>
<pre class="brush:php">$bannerResult = mysql_query("SELECT * FROM banners");

$banners = array();
while($row=mysql_fetch_assoc($bannerResult))
{
	$banners[] = new Banner($row);
}

// Randomizing the $banners array:
shuffle($banners);

// Splitting the banners array into smaller arrays with 4 banners each:
$bannerGroups = array_chunk($banners,4);</pre>
<p>After selecting all the banners from the database, PHP fetches each row of the result as an associative array, and creates banner objects. After this the resulting <strong>$banners</strong> array is shuffled and split with the help of the in-build <strong>array_chunk()</strong> function.</p>
<blockquote><p>The <strong>array_chunk()</strong> PHP function splits an array into smaller chunks. It takes an <strong>array</strong> as its first parameter and a <strong>number</strong> as its second. The number specifies how many elements you want in the resulting chunks. The function splits the original array into smaller ones and returns them as an array of arrays.<br />
<small>Read more on array_chunk() at the <a href="http://php.net/manual/en/function.array-chunk.php" target="_blank">PHP docs</a>.</small></p></blockquote>
<p>As we have 8 banners, we end up with two elements in <strong>$bannerGroups</strong>, which we can print to the page:</p>
<h4>demo.php</h4>
<pre class="brush:php">&lt;ul class="bannerHolder"&gt;
	&lt;?php

		// Looping through the first group:
		foreach($bannerGroups[0] as $ban)
		{
			echo '&lt;li&gt;'.$ban-&gt;html().'&lt;/li&gt;';
		}

	?&gt;
&lt;/ul&gt;</pre>
<p>With all the markup generated and styled, we can move on with the jQuery part of the tutorial.</p>
<div id="attachment_874" class="wp-caption alignnone" style="width: 630px"><a href="http://demo.tutorialzine.com/2010/04/simple-banner-rotator-php-mysql-jquery/demo.php"><img class="size-full wp-image-874" title="The Hover State" src="http://tutorialzine.com/wp-content/uploads/2010/04/i32.jpg" alt="The Hover State" width="620" height="260" /></a><p class="wp-caption-text">The Hover State</p></div>
<h3>Step 4 &#8211; jQuery</h3>
<p>After including the jQuery library to the page, we can start writing our own JavaScript code in script.js.</p>
<h4>script.js</h4>
<pre class="brush:js">$(document).ready(function(){

	// Lowering the opacity of all slide in divs
	$('.banner div').css('opacity',0.4);

	// Using the hover method
	$('.banner').hover(function(){

		// Executed on mouseenter

		var el = $(this);

		// Find all the divs inside the banner div,
		// and animate them with the new size

		el.find('div').stop().animate({width:200,height:200},'slow',function(){
			// Show the "Visit Company" text:
			el.find('p').fadeIn('fast');
		});

	},function(){

		// Executed on moseleave

		var el = $(this);

		// Hiding the text
		el.find('p').stop(true,true).hide();

		// Animating the divs
		el.find('div').stop().animate({width:60,height:60},'fast');

	}).click(function(){

		// When clicked, open a tab with the address of the hyperlink

		window.open($(this).find('a').attr('href'));

	});
});</pre>
<p>Using the <a href="http://tutorialzine.com/2010/02/the-jquery-hover-method/" target="_blank">hover method</a>, we bind two functions to the <strong>mouseenter </strong>and the <strong>mouseleave </strong>events. These respectively show and hide the four rounded divs and the paragraph tag.</p>
<p>Notice the use of the <strong>stop()</strong> function, which, as it name suggests, stops a running animation. Remember that if you need to stop a build-in effect like <strong>fadeOut()</strong>, you should pass two additional <strong>true</strong> parameters to the function.</p>
<p>Stopping animations is important, as firing a new animation before the old one has completed, will make them pile up, which is definitely not desired.</p>
<p>Finally, because the hyperlink is hidden below the divs and is thus unclickable, we listen to the click event on the main banner div, and open a new tab to the appropriate URL when the event occurs.</p>
<p><strong>With this our simple banner rotating script is complete!</strong></p>
<h3>Conclusion</h3>
<p>In this tutorial we demonstrated some of PHP&#8217;s OOP features, jQuery animations and some interesting CSS effects. You are free to modify this code and use it any way you like.</p>
<p><strong>What do you think? How would you modify this script?</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://tutorialzine.com/2010/04/simple-banner-rotator-with-php-jquery-mysql/feed/</wfw:commentRss>
		<slash:comments>26</slash:comments>
		</item>
		<item>
		<title>Simple Bookmarking App With PHP, JS &amp; MySQL</title>
		<link>http://tutorialzine.com/2010/04/simple-bookmarking-app-php-javascript-mysql/</link>
		<comments>http://tutorialzine.com/2010/04/simple-bookmarking-app-php-javascript-mysql/#comments</comments>
		<pubDate>Wed, 14 Apr 2010 17:37:13 +0000</pubDate>
		<dc:creator>Martin Angelov</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://tutorialzine.com/?p=842</guid>
		<description><![CDATA[We are making a link sharing app, which will give you the ability to instantly share any web page, with a simple click of a bookmarklet on your bookmarks bar, and display it in a widget on your site.]]></description>
			<content:encoded><![CDATA[<p>Part of the developer&#8217;s life, is to strive for simplicity in every aspect of their work. When searching for solutions to common problems, you have the choice to lock yourself into all kinds of third party services and API&#8217;s, or take the opportunity and develop the functionality yourself.</p>
<p>In this week&#8217;s tutorial, we are making a simple link sharing app. This app will give you the ability to instantly share any web page, with a single click of a bookmarklet in your bookmarks bar, and display it in a widget on your site.</p>
<h3>The idea</h3>
<p>Clicking the bookmarklet includes a PHP script (evaluated as a JavaScript file) to the page you are viewing, with the title and the URL passed as <strong>GET</strong> parameters. The PHP script writes the page data to the MySQL database, and outputs a success message that is treated as JavaScript code and executed by the browser.</p>
<div id="attachment_851" class="wp-caption alignnone" style="width: 630px"><a href="http://tutorialzine.com/wp-content/uploads/2010/04/i31.png"><img class="size-full wp-image-851" title="The Idea" src="http://tutorialzine.com/wp-content/uploads/2010/04/i31.png" alt="The Idea" width="620" height="260" /></a><p class="wp-caption-text">The Idea</p></div>
<h3>The database schema</h3>
<p>Before moving to any development work, we need to create the database table that will hold all the bookmarks. The table definition is stored in <strong>table.sql</strong> in the download zip. You can run it in the SQL section of phpMyAdmin to recreate the table on your server. After this remember to change the MySQL login details in <strong>connect.php</strong>.</p>
<div id="attachment_848" class="wp-caption alignnone" style="width: 630px"><a href="http://tutorialzine.com/wp-content/uploads/2010/04/i12.png"><img class="size-full wp-image-848" title="Database Schema" src="http://tutorialzine.com/wp-content/uploads/2010/04/i12.png" alt="Database Schema" width="620" height="260" /></a><p class="wp-caption-text">Database Schema</p></div>
<p>Notice the HASH column. This is a unique field that stores the <strong>md5()</strong> sum of the URL field. We are using this to ensure that there are no duplicate links in the database. Inserting a link that already exists, will cause the query to fail and the <strong>mysql_affected_rows()</strong> function will return 0. We are using this in the PHP section of the tut to determine what message is going to be displayed to the user, as you will see in a few moments.</p>
<h3>Step 1 &#8211; XHTML</h3>
<p>XHTML markup is generated on the fly by PHP. It is only needed when presenting the shared links on your website. It is basically a simple unordered list with each shared page being a li element inside it.</p>
<h4>demo.php</h4>
<pre class="brush:html">&lt;ul class="latestSharesUL"&gt;

      &lt;!-- The LI elements are populated by PHP --&gt;

      &lt;li&gt;
          &lt;div class="title"&gt;&lt;a href="http://perfectionkills.com/" class="bookmrk"&gt;Perfection kills&lt;/a&gt;&lt;/div&gt;
          &lt;div class="dt"&gt;36 seconds ago&lt;/div&gt;
      &lt;/li&gt;
      &lt;li&gt;
          &lt;div class="title"&gt;&lt;a href="http://html5test.com/" class="bookmrk"&gt;The HTML5 test - How well does your browser support HTML5?&lt;/a&gt;&lt;/div&gt;
          &lt;div class="dt"&gt;2 minutes ago&lt;/div&gt;
      &lt;/li&gt;
&lt;/ul&gt;</pre>
<p>The <strong>li</strong> elements are generated after PHP runs a query against the database for the latest bookmarks, as you will see in step 3. Each li contains the title of the page and the relative time since the bookmark was added. We will get back go this in the PHP part of the tutorial.</p>
<h3>Step 2 &#8211; CSS</h3>
<p>Again, the CSS code is only needed in the presentation part. You can modify the styling to match the rest of your site or ignore this code completely. Also, not all the styles are given here. You can see the rest in <strong>styles.css</strong> in the download archive.</p>
<h4>styles.css</h4>
<pre class="brush:css">ul.latestSharesUL{
	/* The bookmark widet */
	background-color:#f5f5f5;
	margin:0 auto;
	padding:10px;
	width:280px;
	border:1px solid #e0e0e0;
	text-shadow:1px 1px 0 white;

	font-size:13px;
	color:#666;
	font-family:Arial, Helvetica, sans-serif;
}

ul.latestSharesUL li{
	/* Each bookmark entry */
	background-color:#FAFAFA;
	border:1px solid #EAEAEA;
	border-bottom:none;
	list-style:none;
	padding:12px;
}

ul.latestSharesUL li:last-child{
	/* Targeting the last element of the set */
	border-bottom:1px solid #EAEAEA;
}

ul.latestSharesUL,
ul.latestSharesUL li{
	/* Adding regular and inset shadows */
	-moz-box-shadow:1px 1px 0 white inset, 0 0 2px white;
	-webkit-box-shadow:1px 1px 0 white inset, 0 0 2px white;
	box-shadow:1px 1px 0 white inset, 0 0 2px white;
}

.dt{
	/* The date time field */
	font-size:10px;
	padding-top:10px;
	color:#888;
}

a.bookmrk,
a.bookmrk:visited{
	/* The bookmark title in the widget */
	color:#666;
}
</pre>
<p>By using the box-shadow and border-radius CSS3 properties, we are cutting down on the number of divs that would otherwise be needed to achieve the same design. Also notice the use of the <strong>:last-child</strong> selector, which targets the last li in the unordered list, and adds a bottom border.</p>
<div id="attachment_849" class="wp-caption alignnone" style="width: 630px"><a href="http://tutorialzine.com/wp-content/uploads/2010/04/i21.png"><img class="size-full wp-image-849" title="The Bookmark Widget" src="http://tutorialzine.com/wp-content/uploads/2010/04/i21.png" alt="The Bookmark Widget" width="620" height="260" /></a><p class="wp-caption-text">The Bookmark Widget</p></div>
<h3>Step 3 &#8211; PHP</h3>
<p>First lets take a look at how the links are saved. As mentioned earlier, clicking the bookmarklet includes <strong>bookmark.php</strong> as a script in the head section of the current page. As it is served with a JavaScript content type, the browser will evaluate it as a regular JS file.</p>
<h4>bookmark.php</h4>
<pre class="brush:php">// Setting the content-type header to javascript:
header('Content-type: application/javascript');

// Validating the input data
if(empty($_GET['url']) || empty($_GET['title']) || !validateURL($_GET['url'])) die();

// Sanitizing the variables
$_GET['url'] = sanitize($_GET['url']);
$_GET['title'] = sanitize($_GET['title']);

// Inserting, notice the use of the hash field and the md5 function:
mysql_query("	INSERT INTO bookmark_app (hash,url,title)
				VALUES (
					'".md5($_GET['url'])."',
					'".$_GET['url']."',
					'".$_GET['title']."'
				)");

$message = '';
if(mysql_affected_rows($link)!=1)
{
	$message = 'This URL already exists in the database!';
}
else
$message = 'The URL was shared!';
</pre>
<p>The document title and URL are passed to this script by the bookmarklet and are available in the <strong>$_GET</strong> array. The data is sanitized and validated with our custom made <strong>sanitize()</strong> function, after which it is inserted in the database. Then, after checking the status of the <strong>mysql_affected_rows()</strong> function, we assign to the <strong>$message </strong>variable the appropriate status message that is going to be displayed to the user.</p>
<p>I would suggest to take a quick look at <strong>bookmark.php</strong> in the download zip, to see how PHP and JavaScript work together to successfully insert the bookmark and output the result.</p>
<p>Now lets move on to see how the bookmarks are displayed in a simple widget.</p>
<h4>demo.php</h4>
<pre class="brush:php">$shares = mysql_query("SELECT * FROM bookmark_app ORDER BY id DESC LIMIT 6");

while($row=mysql_fetch_assoc($shares))
{
	// Shortening the title if it is too long:
	if(mb_strlen($row['title'],'utf-8')&gt;80)
		$row['title'] = mb_substr($row['title'],0,80,'utf-8').'..';

	// Outputting the list elements:
	echo '
	&lt;li&gt;
		&lt;div class="title"&gt;&lt;a href="'.$row['url'].'" class="bookmrk"&gt;'.$row['title'].'&lt;/a&gt;&lt;/div&gt;
		&lt;div class="dt"&gt;'.relativeTime($row['dt']).'&lt;/div&gt;
	&lt;/li&gt;';
}</pre>
<p>This code selects the last 6 shared links from the database, generates the appropriate LI elements containing the title as a hyperlink to the bookmarked page, and calculate the relative time since the entry was published with our custom made <strong>relativeTime()</strong> function.</p>
<p>The custom functions we are using are defined in <strong>functions.php</strong>.</p>
<h4>functions.php</h4>
<pre class="brush:php">/* Helper functions */

function validateURL($str)
{
	return preg_match('/(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&amp;:\/~\+#]*[\w\-\@?^=%&amp;\/~\+#])?/i',$str);
}

function sanitize($str)
{
	if(ini_get('magic_quotes_gpc'))
		$str = stripslashes($str);

	$str = strip_tags($str);
	$str = trim($str);
	$str = htmlspecialchars($str);
	$str = mysql_real_escape_string($str);

	return $str;
}

function relativeTime($dt,$precision=2)
{
	if(is_string($dt)) $dt = strtotime($dt);

	$times=array(	365*24*60*60	=&gt; "year",
					30*24*60*60		=&gt; "month",
					7*24*60*60		=&gt; "week",
					24*60*60		=&gt; "day",
					60*60			=&gt; "hour",
					60				=&gt; "minute",
					1				=&gt; "second");

	$passed=time()-$dt;

	if($passed&lt;5)
	{
		$output='less than 5 seconds ago';
	}
	else
	{
		$output=array();
		$exit=0;

		foreach($times as $period=&gt;$name)
		{
			if($exit&gt;=$precision || ($exit&gt;0 &amp;&amp; $period&lt;60)) break;

			$result = floor($passed/$period);
			if($result&gt;0)
			{
				$output[]=$result.' '.$name.($result==1?'':'s');
				$passed-=$result*$period;
				$exit++;
			}
			else if($exit&gt;0) $exit++;
		}

		$output=implode(' and ',$output).' ago';
	}

	return $output;
}
</pre>
<p>One of the guiding principles when building web applications is &#8220;Do not trust your users&#8221;. This implies that all input data has to be properly escaped. This is exactly what the <strong>sanitize()</strong> function is doing &#8211; it prevents possible XSS attacks, strips any HTML tags and escapes all the HTML characters that could potentially break your markup when displayed.</p>
<p>The other interesting function is <strong>relativeTime()</strong>, which takes the timestamp field, assigned to each bookmark, and turns it into a user-friendly relative time string. It also takes an optional second argument, which limits the number of time units that are returned (setting precision to 1 will return <em>1 hour ago</em>, instead of <em>1 hour and 10 minutes</em> ago).</p>
<h3>Step 4 &#8211; JavaScript</h3>
<p>As the script is dynamically included in third party pages, it is not a good idea to rely on third party libraries like jQuery. This is why, for a change, we are going to work with pure JavaScript.</p>
<p>First, lets take a look at the bookmarklet code.</p>
<h4>bookmarklet code</h4>
<pre class="brush:js">(function () {
	var jsScript = document.createElement('script');

	jsScript.setAttribute('type', 'text/javascript');
	jsScript.setAttribute('src', '/bookmark.php?url=' + encodeURIComponent(location.href) + '&amp;title=' + encodeURIComponent(document.title));

	document.getElementsByTagName('head')[0].appendChild(jsScript);
})();</pre>
<p>The bookmarklet is just a regular hyperlink, which has the code above preceded with the <strong>javascript:</strong> protocol as its <strong>href</strong> attribute. When clicked, the snippet creates a new script element, sets <strong>bookmark.php</strong> as its URL (along with the encoded title and URL of the currently active page), and appends it to the head section of the document. It is not as pretty as it would have been if we used the jQuery library, but it gets the job done.</p>
<p>Now lets return to <strong>bookmark.php</strong>.</p>
<h4>bookmark.php</h4>
<pre class="brush:js">function displayMessage(str)
{
	// Using pure JavaScript to create and style a div element

	var d = document.createElement('div');

	with(d.style)
	{
		// Applying styles:

		position='fixed';
		width = '350px';
		height = '20px';
		top = '50%';
		left = '50%';
		margin = '-30px 0 0 -195px';
		backgroundColor = '#f7f7f7';
		border = '1px solid #ccc';
		color = '#777';
		padding = '20px';
		fontSize = '18px';
		fontFamily = '"Myriad Pro",Arial,Helvetica,sans-serif';
		textAlign = 'center';
		zIndex = 100000;

		textShadow = '1px 1px 0 white';

		MozBorderRadius = "12px";
		webkitBorderRadius = "12px";
		borderRadius = "12px";

		MozBoxShadow = '0 0 6px #ccc';
		webkitBoxShadow = '0 0 6px #ccc';
		boxShadow = '0 0 6px #ccc';
	}

	d.setAttribute('onclick','document.body.removeChild(this)');

    // Adding the message passed to the function as text:
	d.appendChild(document.createTextNode(str));

    // Appending the div to document
	document.body.appendChild(d);

    // The message will auto-hide in 3 seconds:

	setTimeout(function(){
		try{
			document.body.removeChild(d);
		}	catch(error){}
	},3000);
}</pre>
<p>The JavaScript code above is right below the PHP logic that inserts the bookmark to the database in bookmark.php. The <strong>displayMessage()</strong> JavaScript function creates a div element, styles it and displays it in the center of the page.</p>
<p>As <strong>bookmark.php</strong> is evaluated as a JS file, every text that it outputs is treated as regular JavaScirpt code. As we mentioned in the PHP step, bookmark.php receives the document title and URL, inserts them in the database, and creates the <strong>$message</strong> variable. This is later outputted as a call to the <strong>displayMessage()</strong> function, which executes the above code and shows the message:</p>
<pre class="brush:php">// Adding a line that will call the JavaScript function:
echo 'displayMessage("'.$message.'");';
</pre>
<p><strong>With this our simple bookmarking app is complete!</strong></p>
<h3>Conclusion</h3>
<p>If you plan to use this widget to share links with your visitors (or to save them for yourself) be sure to upload the script to a directory with a random name, as this script does not offer authentication. This is also the reason why it is so simple to set up and use.</p>
<p><strong>What do you think? What do you plan to use it for?</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://tutorialzine.com/2010/04/simple-bookmarking-app-php-javascript-mysql/feed/</wfw:commentRss>
		<slash:comments>27</slash:comments>
		</item>
		<item>
		<title>AJAX-ed Todo List With PHP, MySQL &amp; jQuery</title>
		<link>http://tutorialzine.com/2010/03/ajax-todo-list-jquery-php-mysql-css/</link>
		<comments>http://tutorialzine.com/2010/03/ajax-todo-list-jquery-php-mysql-css/#comments</comments>
		<pubDate>Wed, 31 Mar 2010 21:21:00 +0000</pubDate>
		<dc:creator>Martin Angelov</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://tutorialzine.com/?p=807</guid>
		<description><![CDATA[In this tutorial we are making a simple AJAX-ed Todo List App, with PHP, MySQL and jQuery. In the process we are going to demonstrate PHP's OOP capabilities, play with jQuery UI and implement some nice AJAX functionality.]]></description>
			<content:encoded><![CDATA[<p>In this tutorial we are making a simple AJAX-ed Todo List App, with PHP, MySQL and jQuery. In the process we are going to demonstrate PHP&#8217;s OOP capabilities, play with jQuery UI and implement some nice AJAX functionality.</p>
<p>For a better understanding of the steps of this tutorial, you an go ahead and download the <strong>demo archive</strong> available from the button above.</p>
<h3>Step 1 &#8211; PHP</h3>
<p>As this is more of a developer-oriented tutorial, we are going to start with the PHP part. Unlike previous tutorials, this time we are leveraging the OOP features of PHP 5.</p>
<blockquote><p>The author presumes you have a basic understanding of the core concepts behind object oriented programming, and PHP 5&#8242;s OOP implementation. For a quick reference, check out these pages of PHP&#8217;s documentation: <a href="http://php.net/manual/en/language.oop5.basic.php" target="_blank">OOP Basics</a>, <a href="http://php.net/manual/en/language.oop5.static.php" target="_blank">Static Methods</a>, <a href="http://php.net/manual/en/language.exceptions.php" target="_blank">Exceptions</a>, <a href="http://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.tostring" target="_blank">Magic Methods</a>.</p></blockquote>
<p>All of the functionality available to the end user &#8211; creating, editing, deleting and reordering the todo items &#8211; is implemented as different methods of a class, explained in detail below.</p>
<h4>todo.class.php &#8211; Part 1</h4>
<pre class="brush:php">/* Defining the ToDo class */

class ToDo{

	/* An array that stores the todo item data: */

	private $data;

	/* The constructor */
	public function __construct($par){
		if(is_array($par))
			$this-&gt;data = $par;
	}

	/*
		This is an in-build "magic" method that is automatically called
		by PHP when we output the ToDo objects with echo.
	*/

	public function __toString(){

		// The string we return is outputted by the echo statement

		return '
			&lt;li id="todo-'.$this-&gt;data['id'].'" class="todo"&gt;

				&lt;div class="text"&gt;'.$this-&gt;data['text'].'&lt;/div&gt;

				&lt;div class="actions"&gt;
					&lt;a href="" class="edit"&gt;Edit&lt;/a&gt;
					&lt;a href="" class="delete"&gt;Delete&lt;/a&gt;
				&lt;/div&gt;

			&lt;/li&gt;';
	}</pre>
<p>The constructor takes the array passed as a parameter and stores it in the <strong>$data</strong> property of the class. This array is a row fetched from the database with <strong>mysql_fetch_assoc()</strong> and contains the id and the text of the todo item.</p>
<p>After this is the magic <strong>__toString()</strong> method, which is called internally when we attempt to echo out an object of this class. The string it returns contains the markup used by each todo item &#8211; a <strong>&lt;li&gt;</strong> element with a unique id and a classname  &#8220;todo&#8221;, inside of which we have the text of the todo and the two action hyperlinks.</p>
<div id="attachment_810" class="wp-caption alignnone" style="width: 630px"><a href="http://tutorialzine.com/wp-content/uploads/2010/03/i23.png"><img class="size-full wp-image-810" title="AJAX, jQuery &amp; CSS3 To Do List" src="http://tutorialzine.com/wp-content/uploads/2010/03/i23.png" alt="AJAX, jQuery &amp; CSS3 To Do List" width="620" height="260" /></a><p class="wp-caption-text">AJAX, jQuery &amp; CSS3 To Do List</p></div>
<h4>todo.class.php &#8211; Part 2</h4>
<pre class="brush:php">	/*
		The edit method takes the ToDo item id and the new text
		of the ToDo. Updates the database.
	*/

	public static function edit($id, $text){

		$text = self::esc($text);
		if(!$text) throw new Exception("Wrong update text!");

		mysql_query("	UPDATE tz_todo
						SET text='".$text."'
						WHERE id=".$id
					);

		if(mysql_affected_rows($GLOBALS['link'])!=1)
			throw new Exception("Couldn't update item!");
	}

	/*
		The delete method. Takes the id of the ToDo item
		and deletes it from the database.
	*/

	public static function delete($id){

		mysql_query("DELETE FROM tz_todo WHERE id=".$id);

		if(mysql_affected_rows($GLOBALS['link'])!=1)
			throw new Exception("Couldn't delete item!");
	}

	/*
		The rearrange method is called when the ordering of
		the todos is changed. Takes an array parameter, which
		contains the ids of the todos in the new order.
	*/

	public static function rearrange($key_value){

		$updateVals = array();
		foreach($key_value as $k=&gt;$v)
		{
			$strVals[] = 'WHEN '.(int)$v.' THEN '.((int)$k+1).PHP_EOL;
		}

		if(!$strVals) throw new Exception("No data!");

		// We are using the CASE SQL operator to update the ToDo positions en masse:

		mysql_query("	UPDATE tz_todo SET position = CASE id
						".join($strVals)."
						ELSE position
						END");

		if(mysql_error($GLOBALS['link']))
			throw new Exception("Error updating positions!");
	}</pre>
<p>The definition of the class continues with a number of static methods. Those are special methods, which can be accessed without the need of an object of the class to be created. For example, you can call the edit method by writing: <strong>ToDo::edit($par1,$par2)</strong>.</p>
<p>Notice how we are using exceptions to handle errors. When an exception occurs the script execution halts and it is up to the rest of the script to catch it and output the appropriate status.</p>
<p>Also you may find interesting the way we are updating the database with the new positions of the todo items. We are using the <strong>CASE</strong> operator, available in MySQL.  This way, no matter how many todos are in the database, we execute only one query.</p>
<blockquote><p>Saving queries and optimizing your scripts, although tedious, is hugely beneficial in the long run. You can read more about the<strong> CASE </strong>operator (among other interesting features) in <a href="http://dev.mysql.com/doc/refman/5.0/en/case-statement.html" target="_blank">MySQL&#8217;s official documentation</a>.</p></blockquote>
<h4>todo.class.php &#8211; Part 3</h4>
<pre class="brush:php">	/*
		The createNew method takes only the text of the todo as a parameter,
		writes to the database and outputs the new todo back to
		the AJAX front-end.
	*/

	public static function createNew($text){

		$text = self::esc($text);
		if(!$text) throw new Exception("Wrong input data!");

		$posResult = mysql_query("SELECT MAX(position)+1 FROM tz_todo");

		if(mysql_num_rows($posResult))
			list($position) = mysql_fetch_array($posResult);

		if(!$position) $position = 1;

		mysql_query("INSERT INTO tz_todo SET text='".$text."', position = ".$position);

		if(mysql_affected_rows($GLOBALS['link'])!=1)
			throw new Exception("Error inserting TODO!");

		// Creating a new ToDo and outputting it directly:

		echo (new ToDo(array(
			'id'	=&gt; mysql_insert_id($GLOBALS['link']),
			'text'	=&gt; $text
		)));

		exit;
	}

	/*
		A helper method to sanitize a string:
	*/

	public static function esc($str){

		if(ini_get('magic_quotes_gpc'))
			$str = stripslashes($str);

		return mysql_real_escape_string(strip_tags($str));
	}

} // closing the class definition
</pre>
<p>Accessing static methods from the same class can easily be done with the <strong>self::</strong> keyword. This way we are using the <strong>esc()</strong> method to sanitize the incoming user data.</p>
<p>Also notice the <strong>createNew()</strong> method. In it, after running the INSERT query on the database, we use the returned auto-assigned unique id with <strong>mysql_insert_id()</strong> and create a new todo object, which is then echoed out to the front end.</p>
<p>Now lets take a look at how this class is used.</p>
<h4>demo.php &#8211; Part 1</h4>
<pre class="brush:php">// Select all the todos, ordered by position:
$query = mysql_query("SELECT * FROM `tz_todo` ORDER BY `position` ASC");

$todos = array();

// Filling the $todos array with new ToDo objects:

while($row = mysql_fetch_assoc($query)){
	$todos[] = new ToDo($row);
}</pre>
<p>After including <strong>todo.class.php</strong> in <strong>demo.php</strong>, we select the todo items and loop through the MySQL result set, filling in the <strong>$todos</strong> array with objects.</p>
<h4>demo.php &#8211; Part 2</h4>
<pre class="brush:php">// Looping and outputting the $todos array. The __toString() method
// is used internally to convert the objects to strings:

foreach($todos as $item){
	echo $item;
}</pre>
<p>Later in the page, these objects are echoed out. Thanks to the <strong>__toString()</strong> method discussed above, all the markup is automatically generated, so we do not have to deal with any of that.</p>
<p>The front end issues a number of different AJAX calls. Making a separate file to handle each of them would be a bit of overkill, so the best solution is to group them in a single AJAX handling file. This is done in <strong>ajax.php</strong>, which you can see below.</p>
<h4>ajax.php</h4>
<pre class="brush:php">$id = (int)$_GET['id'];

try{

	switch($_GET['action'])
	{
		case 'delete':
			ToDo::delete($id);
			break;

		case 'rearrange':
			ToDo::rearrange($_GET['positions']);
			break;

		case 'edit':
			ToDo::edit($id,$_GET['text']);
			break;

		case 'new':
			ToDo::createNew($_GET['text']);
			break;
	}

}
catch(Exception $e){
//	echo $e-&gt;getMessage();
	die("0");
}

echo "1";</pre>
<p>With the help of a switch statement, we decide which of the static methods of the ToDo class to execute. If an error occurs in one of these methods, an exception is dispatched. Because the whole switch is enclosed in a <strong>try statement</strong>, execution of the script halts and control is passed to the catch statement, which outputs a zero and exits the script.</p>
<p>You could potentially echo (or write to a log) exactly what kind of error occurred by uncommenting line 26.</p>
<h3>Step 2 &#8211; MySQL</h3>
<p>The <strong>tz_todo</strong> table holds and assigns the unique ids of the todo items (via the auto_increment setting of the field), the position, the text and the dt_added timestamp.</p>
<div id="attachment_811" class="wp-caption alignnone" style="width: 630px"><a href="http://tutorialzine.com/wp-content/uploads/2010/03/i13.png"><img class="size-full wp-image-811" title="Database Schema" src="http://tutorialzine.com/wp-content/uploads/2010/03/i13.png" alt="Database Schema" width="620" height="260" /></a><p class="wp-caption-text">Database Schema</p></div>
<p>You can find the SQL that will recreate the table in <strong>table.sql</strong> in the download archive. Also, if you plan to run the demo on your own server, don&#8217;t forget to fill in your login details in <strong>connect.php</strong>.</p>
<h3>Step 3 &#8211; XHTML</h3>
<p>As most of the markup is generated by PHP, we are left with taking care of the rest of the page&#8217;s XHTML. First we need to include <strong>jQuery</strong>, <strong>jQuery UI</strong>, and the stylesheets in the document. It is considered a good practice to include the stylesheets to the head section, and the JavaScript files right before the closing <strong>&lt;/body&gt;</strong> tag.</p>
<pre class="brush:html">&lt;link rel="stylesheet" href="jquery-ui.css" type="text/css" /&gt;
&lt;link rel="stylesheet" type="text/css" href="styles.css" /&gt;

&lt;script type="text/javascript" src="jquery.min.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="jquery-ui.min.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="script.js"&gt;&lt;/script&gt;</pre>
<p>After this we can move on to coding the rest of the page.</p>
<h4>demo.php</h4>
<pre class="brush:html">&lt;div id="main"&gt;

	&lt;ul class="todoList"&gt;

	&lt;?php

		// Looping and outputting the $todos array. The __toString() method
		// is used internally to convert the objects to strings:

		foreach($todos as $item){
			echo $item;
		}

		?&gt;

	&lt;/ul&gt;

	&lt;a id="addButton" class="green-button" href=""&gt;Add a ToDo&lt;/a&gt;

&lt;/div&gt;

&lt;!-- This div is used as the base for the confirmation jQuery UI dialog box. Hidden by CSS. --&gt;
&lt;div id="dialog-confirm" title="Delete TODO Item?"&gt;Are you sure you want to delete this TODO item?&lt;/div&gt;</pre>
<p>Each todo is a <strong>li</strong> item inside of the <strong>todoList</strong> unordered list. This way, we can later use the sortable method of <strong>jQuery UI</strong> to easily convert it into an interactive sortable element. Also, in the process, we enhance the semantic value of the code.</p>
<h3>Step 4 &#8211; CSS</h3>
<p>Now lets move on to the styling of the todos. Only parts of the original stylesheet are given here for better readability. You can find the rest in <strong>styles.css</strong> in the download archive.</p>
<h4>styles.css &#8211; Part 1</h4>
<pre class="brush:css">/* The todo items are grouped into an UL unordered list */

ul.todoList{
	margin:0 auto;
	width:500px;
	position:relative;
}

ul.todoList li{
	background-color:#F9F9F9;
	border:1px solid #EEEEEE;
	list-style:none;
	margin:6px;
	padding:6px 9px;
	position:relative;
	cursor:n-resize;

	/* CSS3 text shadow and rounded corners: */

	text-shadow:1px 1px 0 white;

	-moz-border-radius:6px;
	-webkit-border-radius:6px;
	border-radius:6px;
}

ul.todoList li:hover{
	border-color:#9be0f9;

	/* CSS3 glow effect: */
	-moz-box-shadow:0 0 5px #A6E5FD;
	-webkit-box-shadow:0 0 5px #A6E5FD;
	box-shadow:0 0 5px #A6E5FD;
}
</pre>
<p>The <strong>todoList</strong> <strong>ul</strong> is horizontally centered on the page and is assigned a relative positioning. The <strong>li</strong> elements inside it (the todo items) share a number of CSS3 rules. These, unfortunately, do not work in older browsers, but as they are solely for presentation purposes even browsers as old as IE6 can enjoy a fully working script, albeit not as pretty as intentioned.</p>
<h4>styles.css &#8211; Part 2</h4>
<pre class="brush:css">/* The edit textbox */

.todo input{
	border:1px solid #CCCCCC;
	color:#666666;
	font-family:Arial,Helvetica,sans-serif;
	font-size:0.725em;
	padding:3px 4px;
	width:300px;
}

/* The Save and Cancel edit links: */

.editTodo{
	display:inline;
	font-size:0.6em;
	padding-left:9px;
}

.editTodo a{
	font-weight:bold;
}

a.discardChanges{
	color:#C00 !important;
}

a.saveChanges{
	color:#4DB209 !important;
}</pre>
<p>In the second part of the code we style the input text box, shown when the todo item is edited, and the save and cancel links.</p>
<div id="attachment_812" class="wp-caption alignnone" style="width: 630px"><a href="http://tutorialzine.com/wp-content/uploads/2010/03/i33.png"><img class="size-full wp-image-812" title="jQuery UI Dialog Box" src="http://tutorialzine.com/wp-content/uploads/2010/03/i33.png" alt="jQuery UI Dialog Box" width="620" height="260" /></a><p class="wp-caption-text">jQuery UI Dialog Box</p></div>
<h3>Step 5 &#8211; jQuery</h3>
<p>Moving to the JavaScript code. Here we are using two of jQuery UI&#8217;s user interface components &#8211; <strong>sortable</strong>, and <strong>dialog</strong>. These alone save us at least a couple of hours of development time, which is one of the benefits of using a nicely thought out library like jQuery.</p>
<h4>script.js &#8211; Part 1</h4>
<pre class="brush:js">$(document).ready(function(){
	/* The following code is executed once the DOM is loaded */

	$(".todoList").sortable({
		axis		: 'y',				// Only vertical movements allowed
		containment	: 'window',			// Constrained by the window
		update		: function(){		// The function is called after the todos are rearranged

			// The toArray method returns an array with the ids of the todos
			var arr = $(".todoList").sortable('toArray');

			// Striping the todo- prefix of the ids:

			arr = $.map(arr,function(val,key){
				return val.replace('todo-','');
			});

			// Saving with AJAX
			$.get('ajax.php',{action:'rearrange',positions:arr});
		}
	});

	// A global variable, holding a jQuery object
	// containing the current todo item:

	var currentTODO;

	// Configuring the delete confirmation dialog
	$("#dialog-confirm").dialog({
		resizable: false,
		height:130,
		modal: true,
		autoOpen:false,
		buttons: {
			'Delete item': function() {

				$.get("ajax.php",{"action":"delete","id":currentTODO.data('id')},function(msg){
					currentTODO.fadeOut('fast');
				})

				$(this).dialog('close');
			},
			Cancel: function() {
				$(this).dialog('close');
			}
		}
	});</pre>
<p>To display the dialog, we need to have a base div, which is going to be converted to a dialog. The contents of the div is going to be displayed as the text of the dialog, and the contents of the title attribute of the div will become the title of the dialog window. You can find this div (id=<strong>dialog-confirm</strong>) in <strong>demo.php</strong>.</p>
<h4>script.js &#8211; Part 2</h4>
<pre class="brush:js">	// When a double click occurs, just simulate a click on the edit button:
	$('.todo').live('dblclick',function(){
		$(this).find('a.edit').click();
	});

	// If any link in the todo is clicked, assign
	// the todo item to the currentTODO variable for later use.

	$('.todo a').live('click',function(e){

		currentTODO = $(this).closest('.todo');
		currentTODO.data('id',currentTODO.attr('id').replace('todo-',''));

		e.preventDefault();
	});

	// Listening for a click on a delete button:

	$('.todo a.delete').live('click',function(){
		$("#dialog-confirm").dialog('open');
	});

	// Listening for a click on a edit button

	$('.todo a.edit').live('click',function(){

		var container = currentTODO.find('.text');

		if(!currentTODO.data('origText'))
		{
			// Saving the current value of the ToDo so we can
			// restore it later if the user discards the changes:

			currentTODO.data('origText',container.text());
		}
		else
		{
			// This will block the edit button if the edit box is already open:
			return false;
		}

		$('&lt;input type="text"&gt;').val(container.text()).appendTo(container.empty());

		// Appending the save and cancel links:
		container.append(
			'&lt;div class="editTodo"&gt;'+
				'&lt;a class="saveChanges" href=""&gt;Save&lt;/a&gt; or &lt;a class="discardChanges" href=""&gt;Cancel&lt;/a&gt;'+
			'&lt;/div&gt;'
		);

	});</pre>
<p>Notice the use of the jQuery <strong>live()</strong> method to bind events. We are using <strong>live()</strong>, instead of <strong>bind()</strong>, because live() can listen for events on any elements, even those who do not yet exist. This way we make sure that all the todo items added in the future to the page by the user, will also trigger the same event handlers, as the currently existing ones.</p>
<h4>script.js &#8211; Part 3</h4>
<pre class="brush:js">	// The cancel edit link:

	$('.todo a.discardChanges').live('click',function(){
		currentTODO.find('.text')
					.text(currentTODO.data('origText'))
					.end()
					.removeData('origText');
	});

	// The save changes link:

	$('.todo a.saveChanges').live('click',function(){
		var text = currentTODO.find("input[type=text]").val();

		$.get("ajax.php",{'action':'edit','id':currentTODO.data('id'),'text':text});

		currentTODO.removeData('origText')
					.find(".text")
					.text(text);
	});

	// The Add New ToDo button:

	var timestamp;
	$('#addButton').click(function(e){

		// Only one todo per 5 seconds is allowed:
		if(Date.now() - timestamp&lt;5000) return false;

		$.get("ajax.php",{'action':'new','text':'New Todo Item. Doubleclick to Edit.'},function(msg){

			// Appending the new todo and fading it into view:
			$(msg).hide().appendTo('.todoList').fadeIn();
		});

		// Updating the timestamp:
		timestamp = Date.now();

		e.preventDefault();
	});

}); // Closing $(document).ready()</pre>
<p>In the last part of the code we are binding events to the <strong>Save</strong> and <strong>Cancel</strong> links, which are added to the todo when editing it. We also set up an event listener for the <strong>&#8220;Add&#8221;</strong> button. Notice how we prevent flooding by limiting the submit rate of new todos to one every 5 seconds.</p>
<p><strong>With this our AJAX-ed To Do List is complete!</strong></p>
<h3>Conclusion</h3>
<p>Today we created a simple AJAX enabled ToDo web script with PHP, MySQL and jQuery. You can use it to create your own task management application or turn it into a fully fledged web app.</p>
<p><strong>What do you think? How would you modify this code?</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://tutorialzine.com/2010/03/ajax-todo-list-jquery-php-mysql-css/feed/</wfw:commentRss>
		<slash:comments>36</slash:comments>
		</item>
		<item>
		<title>&#8220;Who Is Online&#8221; Widget With PHP, MySQL &amp; jQuery</title>
		<link>http://tutorialzine.com/2010/03/who-is-online-widget-php-mysql-jquery/</link>
		<comments>http://tutorialzine.com/2010/03/who-is-online-widget-php-mysql-jquery/#comments</comments>
		<pubDate>Tue, 02 Mar 2010 22:37:22 +0000</pubDate>
		<dc:creator>Martin Angelov</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://tutorialzine.com/?p=744</guid>
		<description><![CDATA[We are making a "Who is online" widget with PHP, MySQL &#038; jQuery. It will display the number of visitors, currently viewing your site, and a list of countries they are from in a slide out panel.]]></description>
			<content:encoded><![CDATA[<p>For this week&#8217;s tutorial, we are taking a look at our ever-so-interesting inbox. It all started with a letter from one of our readers a couple of weeks ago:</p>
<blockquote><p>My boss is always coming into my office asking me to install things on our client&#8217;s sites. One of the items that&#8217;s been coming up more and more is &#8220;How can we tell who&#8217;s currently online?&#8221;  So, the next time you need a tutorial idea, there you go &#8211; a php/mysql/jquery &#8216;online users&#8217; widget. Oh, and a geomap of each visitor would be super rad too.</p>
<p>Thanks for everything you guys do,<br />
Taylor</p></blockquote>
<p>Taylor, we are always happy when we receive good tutorial ideas, so today we are doing just that &#8211; a &#8220;<strong>Who is online</strong>&#8221; widget with PHP, MySQL &amp; jQuery. It will display the number of visitors, currently viewing your site, and thanks to <a href="http://www.hostip.info/" target="_blank">Hostip&#8217;s free IP to location API</a>, it will even be able to detect the country your visitors are from and display it in a slide out panel.</p>
<h3>Step 1 &#8211; XHTML</h3>
<p>As usual, we start off with the XHTML part. The code presented here might not look like much, but it is all that we need to show off all the work that has been done by the backend. The widget features a slick slide-out panel with all the geolocation data, shown on mouse over.</p>
<h4>demo.html</h4>
<pre class="brush:html">&lt;div class="onlineWidget"&gt;

&lt;div class="panel"&gt;

	&lt;!-- Fetched with AJAX: --&gt;

	&lt;div class="geoRow"&gt;
	&lt;div class="flag"&gt;&lt;img src="who-is-online/img/famfamfam-countryflags/us.gif" width="16" height="11"&gt;&lt;/div&gt;
	&lt;div class="country" title="UNITED STATES"&gt;UNITED STATES&lt;/div&gt;
	&lt;div class="people"&gt;2&lt;/div&gt;
	&lt;/div&gt;

	&lt;div class="geoRow"&gt;
	&lt;div class="flag"&gt;&lt;img src="who-is-online/img/famfamfam-countryflags/uk.gif" width="16" height="11"&gt;&lt;/div&gt;
	&lt;div class="country" title="UNITED KINGDOM"&gt;UNITED KINGDOM&lt;/div&gt;
	&lt;div class="people"&gt;1&lt;/div&gt;
	&lt;/div&gt;

&lt;/div&gt;

&lt;div class="count"&gt;8&lt;/div&gt;
&lt;div class="label"&gt;online&lt;/div&gt;
&lt;div class="arrow"&gt;&lt;/div&gt;
&lt;/div&gt;</pre>
<p>As you may see from the markup above, the main container div &#8211; &#8220;<strong>onlineWidget</strong>&#8221; contains the slide-out panel (the div with class name &#8220;<strong>panel</strong>&#8220;), the total number of people online (the &#8220;<strong>count</strong>&#8221; div), the &#8220;<strong>online</strong>&#8221; label and the green arrow to the right.</p>
<div id="attachment_750" class="wp-caption alignnone" style="width: 630px"><a href="http://tutorialzine.com/wp-content/uploads/2010/03/i1.png"><img class="size-full wp-image-750" title="Geolocation-enabled Who Is Online Widget" src="http://tutorialzine.com/wp-content/uploads/2010/03/i1.png" alt="Geolocation-enabled Who Is Online Widget" width="620" height="460" /></a><p class="wp-caption-text">Geolocation-enabled Who Is Online Widget</p></div>
<p>The panel div is dynamically filled by AJAX with the countries with the most visitors currently online. The default content of this div is a rotating gif preloader, which is replaced with the geo data once the AJAX request is complete (usually in less than a second). We will come back to this in a moment.</p>
<h3>Step 2 &#8211; The Database</h3>
<p>Unlike the usual routine, here we are going to take a look at how the database is structured, as it is fundamental to the rest of the script.</p>
<p>All of the widget data is stored into the <strong>tz_who_is_online</strong> table. It consists of six fields (or columns). The first one &#8211; ID, is a standard primary key / auto increment field. After this is the IP field which stores the visitor&#8217;s IP address (converted to a integer beforehand with the <strong>ip2long</strong> PHP function).</p>
<p>After this are three fields fetched by Hostip&#8217;s API -<strong> Country, CountryCode</strong> and <strong>City</strong>. The widget is not using the city field at this point, but it is good to have in case somebody wants to implement it. Last is the <strong>DT</strong> timestamp field, which is updated on every page load and enables us to track who is online (users without a page load in the last 10 minutes have probably left the site).</p>
<div id="attachment_749" class="wp-caption alignnone" style="width: 630px"><a href="http://tutorialzine.com/wp-content/uploads/2010/03/i3.png"><img class="size-full wp-image-749" title="Table Structure Of tz_who_is_online" src="http://tutorialzine.com/wp-content/uploads/2010/03/i3.png" alt="Table Structure Of tz_who_is_online" width="620" height="260" /></a><p class="wp-caption-text">Table Structure Of tz_who_is_online</p></div>
<h3>Step 3 &#8211; CSS</h3>
<p>The widget is (almost) image free, and is only styled with CSS. Lets take a look at the styling, as defined in <strong>styles.css</strong>. The code is divided in two parts, so it is easier to follow.</p>
<h4>who-is-online/styles.css &#8211; Part 1</h4>
<pre class="brush:css">.onlineWidget,.panel{

	/* Styling the widget and the sliding panel at once */

	background-color:#F9F9F9;
	border:2px solid #FFFFFF;
	height:25px;
	padding:4px 8px;
	position:relative;
	width:130px;

	cursor:pointer;

	/* CSS3 rules for rounded corners, box and text shadows: */

	-moz-border-radius:6px;
	-webkit-border-radius:6px;
	border-radius:6px;

	-moz-box-shadow:0 0 3px #CCCCCC;
	-webkit-box-shadow:0 0 3px #CCCCCC;
	box-shadow:0 0 3px #CCCCCC;

	text-shadow:0 2px 0 white;
}

.onlineWidget:hover{
	background-color:#fcfcfc;
}

.onlineWidget:hover .arrow{
	/* Changing the background image for the green arrow on hover: */
	background-position:bottom center;
}

.count{
	/* The total number of people online div */

	color:#777777;
	float:left;
	font-size:26px;
	font-weight:bold;
	margin-top:-3px;
	text-align:center;
	width:30px;
}

.label{
	/* The online label */

	float:left;
	font-size:10px;
	padding:7px 0 0 7px;
	text-transform:uppercase;
}</pre>
<p>In the first step above, you can see that we style the <strong>widget</strong> and the <strong>slide-out panel</strong> at once. This is to ensure that they have consistent styling which is easy to change later on. Some rules are unique to the panel, however, so we include a individually targeted set of rules in the second part of the code.</p>
<p>We also define the hover state and style the <strong>label</strong> and <strong>count</strong> divs.</p>
<h4>who-is-online/styles.css &#8211; Part 2</h4>
<pre class="brush:css">.arrow{
	/* The green arrow on the right */

	background:url(img/arrow.png) no-repeat top center;
	position:absolute;
	right:6px;

	width:25px;
	height:25px;
}

.panel{
	/* The slideout panel */

	position:absolute;
	cursor:default;

	bottom:50px;
	left:0;
	height:auto;
	display:none;
	margin:-2px;
	z-index:1000;
}

.preloader{
	/* The rotating gif preloader image */
	display:block;
	margin:10px auto;
}

.geoRow{
	/* The div that contains each country */

	height:16px;
	overflow:hidden;
	padding:2px 0;
}

.flag{
	float:left;
	margin:0 4px;
}

.country, .people{
	float:left;
	font-size:10px;
	padding:2px;
}

.country{
	width:85px;
	overflow:hidden;
}

.people{
	font-weight:bold;
}</pre>
<p>In the second part of the file, we style the how the geolocation data that is presented in the slide-out panel, after jQuery fetches it from the back-end. With this we can continue with the next step.</p>
<div id="attachment_751" class="wp-caption alignnone" style="width: 630px"><a href="http://tutorialzine.com/wp-content/uploads/2010/03/i2.png"><img class="size-full wp-image-751" title="CSS3 &amp; jQuery Front End" src="http://tutorialzine.com/wp-content/uploads/2010/03/i2.png" alt="CSS3 &amp; jQuery Front End" width="620" height="260" /></a><p class="wp-caption-text">CSS3 &amp; jQuery Front End</p></div>
<h3>Step 4 &#8211; PHP</h3>
<p>This is where the magic happens. PHP has to keep the database of online users up to date and fetch IP-to-location data from <strong>Hostip&#8217;s API</strong>. This is later cached for future use in a cookie on the visitors PC.</p>
<h4>who-is-online/online.php</h4>
<pre class="brush:php">require "connect.php";
require "functions.php";

// We don't want web bots altering our stats:
if(is_bot()) die();

$stringIp = $_SERVER['REMOTE_ADDR'];
$intIp = ip2long($stringIp);

// Checking wheter the visitor is already marked as being online:
$inDB = mysql_query("SELECT 1 FROM tz_who_is_online WHERE ip=".$intIp);

if(!mysql_num_rows($inDB))
{
	// This user is not in the database, so we must fetch
	// the geoip data and insert it into the online table:

	if($_COOKIE['geoData'])
	{
		// A "geoData" cookie has been previously set by the script, so we will use it

		// Always escape any user input, including cookies:
		list($city,$countryName,$countryAbbrev) = explode('|',mysql_real_escape_string(strip_tags($_COOKIE['geoData'])));
	}
	else
	{
		// Making an API call to Hostip:

		$xml = file_get_contents('http://api.hostip.info/?ip='.$stringIp);

		$city = get_tag('gml:name',$xml);
		$city = $city[1];

		$countryName = get_tag('countryName',$xml);
		$countryName = $countryName[0];

		$countryAbbrev = get_tag('countryAbbrev',$xml);
		$countryAbbrev = $countryAbbrev[0];

		// Setting a cookie with the data, which is set to expire in a month:
		setcookie('geoData',$city.'|'.$countryName.'|'.$countryAbbrev, time()+60*60*24*30,'/');
	}

	$countryName = str_replace('(Unknown Country?)','UNKNOWN',$countryName);

	mysql_query("	INSERT INTO tz_who_is_online (ip,city,country,countrycode)
					VALUES(".$intIp.",'".$city."','".$countryName."', '".$countryAbbrev."')");
}
else
{
	// If the visitor is already online, just update the dt value of the row:
	mysql_query("UPDATE tz_who_is_online SET dt=NOW() WHERE ip=".$intIp);
}

// Removing entries not updated in the last 10 minutes:
mysql_query("DELETE FROM tz_who_is_online WHERE dt&lt;SUBTIME(NOW(),'0 0:10:0')");

// Counting all the online visitors:
list($totalOnline) = mysql_fetch_array(mysql_query("SELECT COUNT(*) FROM tz_who_is_online"));

// Outputting the number as plain text:
echo $totalOnline;</pre>
<p>This PHP script is initially called by jQuery in order to populate the count div with the current number of people online. Behind the scenes, however, this script writes the visitor&#8217;s IP to the database and resolves their IP-to-location data.</p>
<p>This is the best strategy in organizing the back-end, as we keep the calls to the API (which are quite time expensive) distributed to each user as they visit the site for the first time.</p>
<p>The other alternative would be to store only the IPs of the visitors and queue the geolocation data once the panel is shown. This would mean to resolve a huge number of IPs simultaneously, which would make the script unresponsive and get us black-listed from the API. Totally not cool.</p>
<p>You can queue the Hostip&#8217;s API by opening a connection to a URL similar to this: <strong>http://api.hostip.info/?ip=128.128.128.128</strong>. It returns a valid XML response, which contains all sorts of data, including a <strong>country </strong>and <strong>city </strong>name associated with the IP, country <strong>abbreviation </strong>and even <strong>absolute coordinates</strong>. We are fetching this data with the PHP <strong>file_get_contents()</strong> function and extracting the bits of information we need.</p>
<h4>who-is-online/geodata.php</h4>
<pre class="brush:php">require "connect.php";
require "functions.php";

// We don't want web bots accessing this page:
if(is_bot()) die();

// Selecting the top 15 countries with the most visitors:
$result = mysql_query("	SELECT countryCode,country, COUNT(*) AS total
						FROM tz_who_is_online
						GROUP BY countryCode
						ORDER BY total DESC
						LIMIT 15");

while($row=mysql_fetch_assoc($result))
{
	echo '
	&lt;div class="geoRow"&gt;
		&lt;div class="flag"&gt;&lt;img src="who-is-online/img/famfamfam-countryflags/'.strtolower($row['countryCode']).'.gif" width="16" height="11" /&gt;&lt;/div&gt;
		&lt;div class="country" title="'.htmlspecialchars($row['country']).'"&gt;'.$row['country'].'&lt;/div&gt;
		&lt;div class="people"&gt;'.$row['total'].'&lt;/div&gt;
	&lt;/div&gt;
	';
}</pre>
<p><strong>Geodata.php</strong> is fetched by jQuery to populate the slide-out panel with location data. This file basically queues the database with a <strong>GROUP BY</strong> query, which groups the individual users by country and orders the resulting rows in a descending order, with the most popular countries at the top.</p>
<p>For the flag icons, we are using the <a href="http://www.famfamfam.com/lab/icons/flags/" target="_blank">famfamfam flag icon set</a>, which is released as public domain. A great thing about the Hostip API, is that it returns the country code in a standard two letter format, which is also shared by the famfamfam icon set. This means that in the while loop, it is really easy to find the appropriate flag to show, by just lowering the case of the country abbreviation stored in the database and adding a <strong>gif</strong> extension.</p>
<h3>Step 5 &#8211; jQuery</h3>
<p>JavaScript manages the AJAX requests and slides the panel. This would be a daunting task with pure JS alone, which is why we are using the newest version of the jQuery library.</p>
<p>Now lets take a look at what the code looks like.</p>
<h4>who-is-online/widget.js</h4>
<pre class="brush:js">$(document).ready(function(){
	// This function is executed once the document is loaded

	// Caching the jQuery selectors:
	var count = $('.onlineWidget .count');
	var panel = $('.onlineWidget .panel');
	var timeout;

	// Loading the number of users online into the count div with the load AJAX method:
	count.load('who-is-online/online.php');

	$('.onlineWidget').hover(
		function(){
			// Setting a custom 'open' event on the sliding panel:

			clearTimeout(timeout);
			timeout = setTimeout(function(){panel.trigger('open');},500);
		},
		function(){
			// Custom 'close' event:

			clearTimeout(timeout);
			timeout = setTimeout(function(){panel.trigger('close');},500);
		}
	);

	var loaded=false;	// A flag which prevents multiple AJAX calls to geodata.php;

	// Binding functions to custom events:

	panel.bind('open',function(){
		panel.slideDown(function(){
			if(!loaded)
			{
				// Loading the countries and the flags
				// once the sliding panel is shown:

				panel.load('who-is-online/geodata.php');
				loaded=true;
			}
		});
	}).bind('close',function(){
		panel.slideUp();
	});

});</pre>
<p>You might be a bit perplexed with the use of <strong>setTimeout </strong>in the menu. This is done, so we have a bit of delay between the hovering of the mouse and the actual opening of the slide-out panel. This way, unintentional movements of the mouse cursor over the widget won&#8217;t fire the open event, and once opened, will not <strong>close</strong> it immediately once the mouse leaves it.</p>
<p><strong>With this our widget is ready!</strong></p>
<h3>Setting up the demo</h3>
<p>At this point you probably want to grab the widget and put it on your site. To make it work, you need to execute the SQL code found in <strong>table.sql</strong> in the download archive. It will create the <strong>tz_who_is_online</strong> table in your database, which is used by the widget. Later you need to upload the files to your server and include <strong>widget.js</strong> to the head section of your page (along with the jQuery  library). After this you have to fill your MySQL login details in <strong>connect.php</strong> and finally add the markup from <strong>demo.html</strong> to your web page.</p>
<h3>Conclusion</h3>
<p>Having access to real time data on your site userbase is a dream to any webmaster. Tools like Google Analytics give a great perspective on your site&#8217;s reach, but lack the real time feel a simple widget like this can provide.</p>
<p><strong>What do you think? How would you modify this code?</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://tutorialzine.com/2010/03/who-is-online-widget-php-mysql-jquery/feed/</wfw:commentRss>
		<slash:comments>60</slash:comments>
		</item>
		<item>
		<title>PHP &amp; MySQL File Download Counter</title>
		<link>http://tutorialzine.com/2010/02/php-mysql-download-counter/</link>
		<comments>http://tutorialzine.com/2010/02/php-mysql-download-counter/#comments</comments>
		<pubDate>Sun, 21 Feb 2010 15:51:53 +0000</pubDate>
		<dc:creator>Martin Angelov</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://tutorialzine.com/?p=717</guid>
		<description><![CDATA[It has been a while since we've done a proper PHP &#038; MySQL tutorial here, at Tutorialzine, so today we are creating a simple yet robust file download tracker.]]></description>
			<content:encoded><![CDATA[<p>It has been a while since we&#8217;ve done a proper PHP &amp; MySQL tutorial here, at Tutorialzine, so today we are creating a simple, yet robust, file download tracker.</p>
<p>Each file will have a corresponding row in the database, where the total number of downloads is saved. PHP will update the MySQL database and redirect the visitors to the appropriate files.</p>
<p>To track the number of downloads, you just need to upload your files to the <strong>files</strong> folder, and use a special URL to access them.</p>
<h3>Step 1 &#8211; XHTML</h3>
<p>The first step is to lay down the XHTML markup of the tracker.  It is pretty straightforward &#8211; we have the <strong>file-manager</strong> div, which contains an <strong>unordered list</strong> with each file as a <strong>li</strong> element.</p>
<p>The files, that are going to be tracked, are put into the <strong>files</strong> folder in the script root directory (you can see how the file structure is organized in  the demonstration zip file). PHP then loops through all the files and adds each one as a separate <strong>li</strong> element to the unordered list.</p>
<h4>demo.php</h4>
<pre class="brush:html">&lt;div id="file-manager"&gt;

	&lt;ul class="manager"&gt;

		&lt;!-- The LI items are generated by php --&gt;
		&lt;li&gt;&lt;a href="download.php?file=photoShoot-1.0.zip"&gt;photoShoot-1.0.zip
			&lt;span class="download-count" title="Times Downloaded"&gt;0&lt;/span&gt; &lt;span class="download-label"&gt;download&lt;/span&gt;&lt;/a&gt;
		&lt;/li&gt;
	&lt;/ul&gt;

&lt;/div&gt;
</pre>
<p>Notice the <strong>href </strong>attribute of the hyperlink &#8211; it passes  the name of the file as a parameter to <strong>download.php</strong>. This is where the download tracking happens, as you will see in a moment.</p>
<p>You are not limited to this interface in order to provide  download tracking &#8211; you can just post the links to <strong>download.php</strong> in your  blog posts or site pages, and all downloads will be correctly tracked.</p>
<div id="attachment_721" class="wp-caption alignnone" style="width: 630px"><a href="http://tutorialzine.com/wp-content/uploads/2010/02/i11.png"><img class="size-full wp-image-721" title="Download Counter Interface" src="http://tutorialzine.com/wp-content/uploads/2010/02/i11.png" alt="Download Counter Interface" width="620" height="460" /></a><p class="wp-caption-text">Download Counter Interface</p></div>
<h3>Step 2 &#8211; CSS</h3>
<p>With the XHTML markup in place, we can now concentrate on the presentation side of script. The CSS rules below target the <strong>file-manager</strong> div by <strong>id</strong> (with the <strong>hash symbol</strong>), as it is present only once in the page, and the rest of the elements by <strong>class names</strong>.</p>
<h4>styles.css</h4>
<pre class="brush:css">#file-manager{
	background-color:#EEE;
	border:1px solid #DDD;
	margin:50px auto;
	padding:10px;
	width:400px;
}

ul.manager li{
	background:url("img/bg_gradient.gif") repeat-x center bottom #F5F5F5;
	border:1px solid #DDD;
	border-top-color:#FFF;

	list-style:none;
	position:relative;
}

ul.manager li a{
	display:block;
	padding:8px;
}

ul.manager li a:hover .download-label{
	/* When a list is hovered over, show the download green text inside it: */
	display:block;
}

span.download-label{
	background-color:#64B126;
	border:1px solid #4E9416;
	color:white;
	display:none;
	font-size:10px;
	padding:2px 4px;
	position:absolute;
	right:8px;
	text-decoration:none;
	text-shadow:0 0 1px #315D0D;
	top:6px;

	/* CSS3 Rounded Corners */

	-moz-border-radius:3px;
	-webkit-border-radius:3px;
	border-radius:3px;
}

span.download-count{
	color:#999;
	font-size:10px;
	padding:3px 5px;
	position:absolute;
	text-decoration:none;
}</pre>
<p>The interesting part here is that the download label is hidden by default with <strong>display:none</strong>. It is shown with <strong>display:block</strong> only when we are hovering over its parent <strong>&lt;a&gt;</strong> element, and thus the right label is shown without a need for using JavaScript. A bit of <strong>CSS3 </strong>is also used as well to round the corners of the download label.</p>
<div id="attachment_722" class="wp-caption alignnone" style="width: 630px"><a href="http://tutorialzine.com/wp-content/uploads/2010/02/i21.png"><img class="size-full wp-image-722" title="Hover State With CSS" src="http://tutorialzine.com/wp-content/uploads/2010/02/i21.png" alt="Hover State With CSS" width="620" height="260" /></a><p class="wp-caption-text">Hover State With CSS</p></div>
<h3>Step 3 &#8211; PHP</h3>
<p>As mentioned earlier, PHP loops through the <strong>files</strong> folder, and outputs each file as a <strong>li</strong> element in the unordered list. Now lets take a closer look at how this happens.</p>
<h4>demo.php &#8211; Top Section</h4>
<pre class="brush:php">// Error reporting:
error_reporting(E_ALL^E_NOTICE);

// Including the DB connection file:
require 'connect.php';

$extension='';
$files_array = array();

/* Opening the thumbnail directory and looping through all the thumbs: */

$dir_handle = @opendir($directory) or die("There is an error with your file directory!");

while ($file = readdir($dir_handle))
{
	/* Skipping the system files: */
	if($file{0}=='.') continue;

	/* end() returns the last element of the array generated by the explode() function: */
	$extension = strtolower(end(explode('.',$file)));

	/* Skipping the php files: */
	if($extension == 'php') continue;

	$files_array[]=$file;
}

/* Sorting the files alphabetically */
sort($files_array,SORT_STRING);

$file_downloads=array();

$result = mysql_query("SELECT * FROM download_manager");

if(mysql_num_rows($result))
while($row=mysql_fetch_assoc($result))
{
	/* 	The key of the $file_downloads array will be the name of the file,
		and will contain the number of downloads: */

	$file_downloads[$row['filename']]=$row['downloads'];
}</pre>
<p>Notice how we are selecting all the rows from the <strong>download_manager </strong>table with <strong>mysql_query()</strong>, and later adding them to the <strong>$file_downloads</strong> array with the filename as a key to the number of downloads. This way, later in the code, we can write <strong>$file_downloads['archive.zip']</strong>, and output how many times this file has been downloaded.</p>
<p>You can see the code we use to generate the <strong>li</strong> items below.</p>
<h4>demo.php &#8211; Mid Section</h4>
<pre class="brush:php">foreach($files_array as $key=&gt;$val)
{
	echo '&lt;li&gt;&lt;a href="download.php?file='.urlencode($val).'"&gt;'.$val.'
		&lt;span class="download-count" title="Times Downloaded"&gt;'.(int)$file_downloads[$val].'&lt;/span&gt; &lt;span class="download-label"&gt;download&lt;/span&gt;&lt;/a&gt;
	&lt;/li&gt;';
}
</pre>
<p>It is simple as that &#8211; a <strong>foreach </strong>loop on the <strong>$files_array</strong> array, and an echo statement which prints all the markup to the page.</p>
<p>Now lets take a closer look at how exactly are the downloads tracked.</p>
<h4>download.php</h4>
<pre class="brush:php">// Error reporting:
error_reporting(E_ALL^E_NOTICE);

// Including the connection file:
require('connect.php');

if(!$_GET['file']) error('Missing parameter!');
if($_GET['file']{0}=='.') error('Wrong file!');

if(file_exists($directory.'/'.$_GET['file']))
{
	/* If the visitor is not a search engine, count the downoad: */
	if(!is_bot())
	mysql_query("	INSERT INTO download_manager SET filename='".mysql_real_escape_string($_GET['file'])."'
					ON DUPLICATE KEY UPDATE downloads=downloads+1");

	header("Location: ".$directory."/".$_GET['file']);
	exit;
}
else error("This file does not exist!");

/* Helper functions: */

function error($str)
{
	die($str);
}

function is_bot()
{
	/* This function will check whether the visitor is a search engine robot */

	$botlist = array("Teoma", "alexa", "froogle", "Gigabot", "inktomi",
	"looksmart", "URL_Spider_SQL", "Firefly", "NationalDirectory",
	"Ask Jeeves", "TECNOSEEK", "InfoSeek", "WebFindBot", "girafabot",
	"crawler", "www.galaxy.com", "Googlebot", "Scooter", "Slurp",
	"msnbot", "appie", "FAST", "WebBug", "Spade", "ZyBorg", "rabaz",
	"Baiduspider", "Feedfetcher-Google", "TechnoratiSnoop", "Rankivabot",
	"Mediapartners-Google", "Sogou web spider", "WebAlta Crawler","TweetmemeBot",
	"Butterfly","Twitturls","Me.dium","Twiceler");

	foreach($botlist as $bot)
	{
		if(strpos($_SERVER['HTTP_USER_AGENT'],$bot)!==false)
		return true;	// Is a bot
	}

	return false;	// Not a bot
}
</pre>
<p>It is important to check if, by any chance, the visitor is a search engine robot scanning your links and not a real person. Robots are a good thing, as they get you included in services like Google Search, but in a situation such as this, can skew your download statistics. This is why the database row is updated only after the visitor passes the <strong>is_bot()</strong> validation.</p>
<h3>Step 4 &#8211; MySQL</h3>
<p>As mentioned in the previous step, the download count is stored as a row in the <strong>download_manager</strong> table in your MySQL database. First, lets explain how this particular query works:</p>
<h4>download.php</h4>
<pre class="brush:sql">INSERT INTO download_manager SET filename='filename.doc'
ON DUPLICATE KEY UPDATE downloads=downloads+1</pre>
<p>It tells MySQL to insert a new row in the <strong>download_manager</strong> table, and set the <strong>filename</strong> field of the row to the value of the requested file for download. However, the <strong>filename</strong> field is defined as a <strong>unique index</strong> in the table. This means that a row can be inserted only once, otherwise a <strong>duplicate key error</strong> will occur.</p>
<p>This is where the second part of the query kicks in &#8211; <strong>ON DUPLICATE KEY UPDATE</strong> will tell MySQL to increment the downloads column by one if the file already exists in the database.</p>
<p>This way new files will be automatically inserted in the database the first time they are downloaded.</p>
<div id="attachment_727" class="wp-caption alignnone" style="width: 630px"><a href="http://tutorialzine.com/wp-content/uploads/2010/02/i31.png"><img class="size-full wp-image-727" title="Structure of the download_manager Table" src="http://tutorialzine.com/wp-content/uploads/2010/02/i31.png" alt="Structure of the download_manager Table" width="620" height="260" /></a><p class="wp-caption-text">Structure of the download_manager Table</p></div>
<h3>Step 5 &#8211; jQuery</h3>
<p>To make the download tracking feel almost like real-time, it will be a nice addition to update the counter next to the file name once the user initiates the download. Otherwise they would have to initiate a page refresh so that new stats for the counter are shown.</p>
<p>We will achieve this with a little jQuery trick:</p>
<h4>script.js</h4>
<pre class="brush:js">$(document).ready(function(){
	/* This code is executed after the DOM has been completely loaded */

	$('ul.manager a').click(function(){

		var countSpan = $('.download-count',this);
		countSpan.text( parseInt(countSpan.text())+1);
	});
});
</pre>
<p>We just assign a click handler to the links that point to the files, and every time one of them is clicked, we increment the number inside of the counter span tag.</p>
<h3>Step 6 &#8211; htaccess</h3>
<p>There is one more thing we need to do, before we call it a day. What <strong>download.php</strong> does is to  redirect the visitor to the requested file that was passed as a parameter. However you may have noticed that, for certain file types, the default browser behavior is to open them directly. We want to initiate a download instead. This is achieved with a couple of lines inside of a <strong>.htacess</strong> file, found in the <strong>files</strong> directory:</p>
<pre class="brush:plain">&lt;Files *.*&gt;
ForceType application/octet-stream
&lt;/Files&gt;
</pre>
<p><strong>With this our File Download Counter is complete!</strong></p>
<h3>Conclusion</h3>
<p>To run the demo on your own server, you will need to recreate the <strong>download_manager</strong> table in a MySQL database you have access to. You can find the needed <strong>SQL</strong> code that will create the table for you in <strong>table.sql</strong>, which you can find in the download archive.</p>
<p>After this, just add your login details for the database (as provided by your webhost) to <strong>configuration.php</strong>.</p>
<p><strong>What do you think? How would you improve this example?</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://tutorialzine.com/2010/02/php-mysql-download-counter/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
		<item>
		<title>AJAX-enabled Sticky Notes With PHP &amp; jQuery</title>
		<link>http://tutorialzine.com/2010/01/sticky-notes-ajax-php-jquery/</link>
		<comments>http://tutorialzine.com/2010/01/sticky-notes-ajax-php-jquery/#comments</comments>
		<pubDate>Mon, 18 Jan 2010 21:45:02 +0000</pubDate>
		<dc:creator>Martin Angelov</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://tutorialzine.com/?p=623</guid>
		<description><![CDATA[Today we are making an AJAX-enabled Sticky Note system. It will give visitors the ability to create notes with a live preview, and move them around on the screen.]]></description>
			<content:encoded><![CDATA[<p>Today we are making an AJAX-enabled Sticky Note management system. It will give visitors the ability to create notes with a live preview, and move them around on the screen. Every movement is going to be sent to the back-end via AJAX and saved in the database.</p>
<p>We are using version <strong>1.4</strong> of jQuery and the <a href="http://fancybox.net/" target="_blank">fancybox plugin</a> (you can also check our <a href="http://tutorialzine.com/2009/11/hovering-gallery-css3-jquery/" target="_blank">CSS3 Lightbox Gallery Tutorial</a>, where we also used fancybox).</p>
<p>You can download the example files and keep the demo site open in a tab so that it is easier to follow the steps of the tutorial.</p>
<h3>Step 1 &#8211; XHTML</h3>
<p>The first step is to create the necessary XHTML structure. The markup in the main demonstration file &#8211; <strong>demo.php</strong> is pretty straightforward, as you can see for yourself from the code below.</p>
<h4>demo.php</h4>
<pre class="brush:html">&lt;div id="main"&gt;
&lt;a id="addButton" class="green-button" href="add_note.html"&gt;Add a note&lt;/a&gt;

&lt;?php echo $notes?&gt;

&lt;/div&gt;</pre>
<p>It contains the <strong>main</strong> div, which holds all the notes and  limits their movement during the dragging process. The rest is generated dynamically by PHP after running a SELECT query against the database, and after storing the result in the <strong>$notes</strong> variable as you will see in the next step.</p>
<p>If you click the &#8220;Add a note&#8221; button on the demonstration site, you will see that a form with a live preview pops up. This functionality is provided by the fancybox, which fetches <strong>add_note.html</strong> (which contains the form) and shows it within a pop-up.</p>
<h4>add_note.html</h4>
<pre class="brush:html">&lt;h3 class="popupTitle"&gt;Add a new note&lt;/h3&gt;

&lt;!-- The preview: --&gt;
&lt;div id="previewNote" class="note yellow" style="left:0;top:65px;z-index:1"&gt;
&lt;div class="body"&gt;&lt;/div&gt;
&lt;div class="author"&gt;&lt;/div&gt;
&lt;span class="data"&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;div id="noteData"&gt; &lt;!-- Holds the form --&gt;
&lt;form action="" method="post" class="note-form"&gt;

&lt;label for="note-body"&gt;Text of the note&lt;/label&gt;
&lt;textarea name="note-body" id="note-body" class="pr-body" cols="30" rows="6"&gt;&lt;/textarea&gt;

&lt;label for="note-name"&gt;Your name&lt;/label&gt;
&lt;input type="text" name="note-name" id="note-name" class="pr-author" value="" /&gt;

&lt;label&gt;Color&lt;/label&gt; &lt;!-- Clicking one of the divs changes the color of the preview --&gt;
&lt;div class="color yellow"&gt;&lt;/div&gt;
&lt;div class="color blue"&gt;&lt;/div&gt;
&lt;div class="color green"&gt;&lt;/div&gt;

&lt;!-- The green submit button: --&gt;
&lt;a id="note-submit" href="" class="green-button"&gt;Submit&lt;/a&gt;

&lt;/form&gt;
&lt;/div&gt;</pre>
<p>In the form you can fill in the text of the note, your name and choose a color. Providing a way for users to see how their note will appear in the page in real time is a useful addition which serves another practical purpose &#8211; when clicking the submit button and the lightbox window closes, the preview note is copied to the <strong>main</strong> div, which saves us from writing additional code.</p>
<div id="attachment_628" class="wp-caption alignnone" style="width: 630px"><a href="http://tutorialzine.com/wp-content/uploads/2010/01/i11.png"><img class="size-full wp-image-628" title="Note Creation Form With Live Preview" src="http://tutorialzine.com/wp-content/uploads/2010/01/i11.png" alt="Note Creation Form With Live Preview" width="620" height="460" /></a><p class="wp-caption-text">Note Creation Form With Live Preview</p></div>
<h3>Step 2 &#8211; PHP</h3>
<p>As mentioned earlier, PHP fills the <strong>$notes</strong> variable by running a query againts the database and outputs it on the page. Lets see how this works.</p>
<h4>demo.php</h4>
<pre class="brush:php">$query = mysql_query("SELECT * FROM notes ORDER BY id DESC");

$notes = '';
$left='';
$top='';
$zindex='';
while($row=mysql_fetch_assoc($query))
{
	// The xyz column holds the position and z-index in the form 200x100x10:
	list($left,$top,$zindex) = explode('x',$row['xyz']);
	$notes.= '
		&lt;div class="note '.$row['color'].'" style="left:'.$left.'px;top:'.$top.'px;	z-index:'.$zindex.'"&gt;
		'.htmlspecialchars($row['text']).'
		&lt;div class="author"&gt;'.htmlspecialchars($row['name']).'&lt;/div&gt;
		&lt;span class="data"&gt;'.$row['id'].'&lt;/span&gt;
	&lt;/div&gt;';
}</pre>
<p>The notes table not only stores the text and the author of the note, but it also has a dedicated column for the <strong>x</strong> and <strong>y</strong> coordinates, as well for the <strong>z-index</strong> (or stacking order). Those are stored in the <strong>xyz</strong> field of the table, which is updated by AJAX.</p>
<p>After the visitor clicks on the &#8220;<strong>Add a note</strong>&#8221; button, <strong>fancybox</strong> grabs <strong>add_note.html</strong> (which was covered in step one) and displays the live preview form. When it is submitted, the data is sent via AJAX to <strong>post.php</strong>, given below.</p>
<h4>post.php</h4>
<pre class="brush:php">// Escaping the input data:
$author = mysql_real_escape_string(strip_tags($_POST['author']));
$body = mysql_real_escape_string(strip_tags($_POST['body']));
$color = mysql_real_escape_string($_POST['color']);
$zindex = (int)$_POST['zindex'];

/* Inserting a new record in the notes DB: */
mysql_query('	INSERT INTO notes (text,name,color,xyz)
VALUES ("'.$body.'","'.$author.'","'.$color.'","0x0x'.$zindex.'")');

if(mysql_affected_rows($link)==1)
{
	// Return the id of the inserted row:
	echo mysql_insert_id($link);
}
else echo '0';</pre>
<p>After escaping all the input data and inserting it in the table, the script checks whether there were any rows affected after the insert query. If <strong>mysql_affected_rows</strong> returns 1, this would mean that the insert was successful and the automatically assigned <strong>auto_increment</strong> ID is outputted.</p>
<p>AJAX is also used to save the positions of the individual notes after the end of each movement. The JavaScript code that actually requests these AJAX calls is presented in step 4 of this tutorial. The PHP code is included below:</p>
<h4>update_position.php</h4>
<pre class="brush:php">// Validating the input data:
if(!is_numeric($_GET['id']) || !is_numeric($_GET['x']) || !is_numeric($_GET['y']) || !is_numeric($_GET['z']))
die("0");

// Escaping:
$id = (int)$_GET['id'];
$x = (int)$_GET['x'];
$y = (int)$_GET['y'];
$z = (int)$_GET['z'];

// Saving the position and z-index of the note:
mysql_query("UPDATE notes SET xyz='".$x."x".$y."x".$z."' WHERE id=".$id);

echo "1";</pre>
<p>After making sure that the input data is valid, the script updates the xyz field of the row for the note in question and prints 1 on success.</p>
<p>Lets continue with step three.</p>
<h3>Step 3 &#8211; CSS</h3>
<p>All the markup is in place, so it is time to throw in some fancy styling. The styles are defined in styles.css. I divided the file in three parts.</p>
<h4>styles.css &#8211; Part 1</h4>
<pre class="brush:css">.note{
	height:150px;
	padding:10px;
	width:150px;
	position:absolute;
	overflow:hidden;
	cursor:move;

	font-family:Trebuchet MS,Tahoma,Myriad Pro,Arial,Verdana,sans-serif;
	font-size:22px;

	/* Adding a CSS3 shadow below the note, in the browsers which support it: */
	-moz-box-shadow:2px 2px 0 #DDDDDD;
	-webkit-box-shadow:2px 2px 0 #DDDDDD;
	box-shadow:2px 2px 0 #DDDDDD;
}

#fancy_ajax .note{ cursor:default; }

/* Three styles for the notes: */

.yellow{
	background-color:#FDFB8C;
	border:1px solid #DEDC65;
}

.blue{
	background-color:#A6E3FC;
	border:1px solid #75C5E7;
}

.green{
	background-color:#A5F88B;
	border:1px solid #98E775;
}

/* Each note has a data span, which holds its ID */
span.data{ display:none; }

/* The "Add a note" button: */
#addButton{
	position:absolute;
	top:-70px;
	left:0;
}</pre>
<p>In the first part we define the appearance of the notes and provide three color schemes &#8211; yellow, blue and green. Those color classes are also used in the live preview form when creating a note.</p>
<p>Every note has special span element with a class name of <strong>data</strong>, which holds the internal ID it is assigned in the database. This ID is used by jQuery and returned with the AJAX calls back to the server in order to update the note&#8217;s position and z-index.  We are hiding this span from view with <strong>display:none</strong>.</p>
<div id="attachment_627" class="wp-caption alignnone" style="width: 630px"><a href="http://tutorialzine.com/wp-content/uploads/2010/01/i22.png"><img class="size-full wp-image-627" title="Three Styles Of Notes" src="http://tutorialzine.com/wp-content/uploads/2010/01/i22.png" alt="Three Styles Of Notes" width="620" height="260" /></a><p class="wp-caption-text">Three Styles Of Notes</p></div>
<h4>styles.css &#8211; Part 2</h4>
<pre class="brush:css">/* Green button class: */
a.green-button,a.green-button:visited{
	color:black;
	display:block;
	font-size:10px;
	font-weight:bold;
	height:15px;
	padding:6px 5px 4px;
	text-align:center;
	width:60px;

	text-shadow:1px 1px 1px #DDDDDD;
	background:url(img/button_green.png) no-repeat left top;
}

a.green-button:hover{
	text-decoration:none;
	background-position:left bottom;
}

.author{
	/* The author name on the note: */
	bottom:10px;
	color:#666666;
	font-family:Arial,Verdana,sans-serif;
	font-size:12px;
	position:absolute;
	right:10px;
}

#main{
	/* Contains all the notes and limits their movement: */
	margin:0 auto;
	position:relative;
	width:980px;
	height:500px;
	z-index:10;
	background:url(img/add_a_note_help.gif) no-repeat left top;
}</pre>
<p>The second part of the file defines the green button class, complete with a hover state and a CSS3 text-shadow. These are a few tiny details that may not look like much, but leave a good overall impression to the user.</p>
<h4>styles.css &#8211; Part 3</h4>
<pre class="brush:css">h3.popupTitle{
	border-bottom:1px solid #DDDDDD;
	color:#666666;
	font-size:24px;
	font-weight:normal;
	padding:0 0 5px;
}

#noteData{
	/* The input form in the pop-up: */
	height:200px;
	margin:30px 0 0 200px;
	width:350px;
}

.note-form label{
	display:block;
	font-size:10px;
	font-weight:bold;
	letter-spacing:1px;
	text-transform:uppercase;
	padding-bottom:3px;
}

.note-form textarea, .note-form input[type=text]{
	background-color:#FCFCFC;
	border:1px solid #AAAAAA;
	font-family:Arial,Verdana,sans-serif;
	font-size:16px;
	height:60px;
	padding:5px;
	width:300px;
	margin-bottom:10px;
}

.note-form input[type=text]{	height:auto; }

.color{
	/* The color swatches in the form: */
	cursor:pointer;
	float:left;
	height:10px;
	margin:0 5px 0 0;
	width:10px;
}

#note-submit{	margin:20px auto; }</pre>
<p>In the last part of styles.css, we add CSS rules for the live preview form, staring from the H3 heading and finishing with the color swatches on the bottom.</p>
<h3>Step 4 &#8211; jQuery</h3>
<p>jQuery manages the front-end and all of the AJAX requests. In order to be able to use the library, we first need to include a few lines to the head section of demo.php:</p>
<h4>demo.php</h4>
<pre class="brush:html">&lt;link rel="stylesheet" type="text/css" href="styles.css" /&gt;
&lt;link rel="stylesheet" type="text/css" href="fancybox/jquery.fancybox-1.2.6.css" media="screen" /&gt;

&lt;script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.0/jquery.min.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="fancybox/jquery.fancybox-1.2.6.pack.js"&gt;&lt;/script&gt;

&lt;script type="text/javascript" src="script.js"&gt;&lt;/script&gt;</pre>
<p>We include jQuery and jQuery UI from Google&#8217;s content repository network, as well as the rest of the css and js files needed for this tutorial. Now lets dig a bit deeper into our jQuery script.</p>
<h4>script.js &#8211; Part 1</h4>
<pre class="brush:js">$(document).ready(function(){
	/* This code is executed after the DOM has been completely loaded */

	var tmp;

	$('.note').each(function(){
		/* Finding the biggest z-index value of the notes */

		tmp = $(this).css('z-index');
		if(tmp&gt;zIndex) zIndex = tmp;
	})

	/* A helper function for converting a set of elements to draggables: */
	make_draggable($('.note'));

	/* Configuring the fancybox plugin for the "Add a note" button: */
	$("#addButton").fancybox({
		'zoomSpeedIn'		: 600,
		'zoomSpeedOut'		: 500,
		'easingIn'			: 'easeOutBack',
		'easingOut'			: 'easeInBack',
		'hideOnContentClick': false,
		'padding'			: 15
	});

	/* Listening for keyup events on fields of the "Add a note" form: */
	$('.pr-body,.pr-author').live('keyup',function(e){

		if(!this.preview)
			this.preview=$('#previewNote');

		/* Setting the text of the preview to the contents of the input field, and stripping all the HTML tags: */
		this.preview.find($(this).attr('class').replace('pr-','.')).html($(this).val().replace(/&lt;[^&gt;]+&gt;/ig,''));
	});

	/* Changing the color of the preview note: */
	$('.color').live('click',function(){

		$('#previewNote').removeClass('yellow green blue').addClass($(this).attr('class').replace('color',''));
	});</pre>
<p>First the script finds the maximum <strong>z-index</strong> value, so that it can cache it into the <strong>zIndex</strong> variable and increment it before assigning it to the notes in the beginning of every drag movement. This way, when you start dragging a note, it is moved to the top of the stack.</p>
<p>Another interesting moment is that we use the jQuery <strong>live()</strong> method to listen for events, instead of the regular <strong>bind()</strong>. This is so, because the page elements we are listening for events on, are created only when the form is shown and, once defined, <strong>live()</strong> event listeners are active on all elements yet to be created.</p>
<h4>script.js &#8211; Part 2</h4>
<pre class="brush:js">	/* The submit button: */
	$('#note-submit').live('click',function(e){

		if($('.pr-body').val().length&lt;4)
		{
			alert("The note text is too short!")
			return false;
		}

		if($('.pr-author').val().length&lt;1)
		{
			alert("You haven't entered your name!")
			return false;
		}

		$(this).replaceWith('&lt;img src="img/ajax_load.gif" style="margin:30px auto;display:block" /&gt;');

		var data = {
			'zindex'	: ++zIndex,
			'body'		: $('.pr-body').val(),
			'author'		: $('.pr-author').val(),
			'color'		: $.trim($('#previewNote').attr('class').replace('note',''))
		};

		/* Sending an AJAX POST request: */
		$.post('ajax/post.php',data,function(msg){

			if(parseInt(msg))
			{
				/* msg contains the ID of the note, assigned by MySQL's auto increment: */
				var tmp = $('#previewNote').clone();

				tmp.find('span.data').text(msg).end().css({'z-index':zIndex,top:0,left:0});
				tmp.appendTo($('#main'));

				make_draggable(tmp)
			}

			$("#addButton").fancybox.close();
		});

		e.preventDefault();
	})
});</pre>
<p>Here we are listening for the click event on the form submit link. Once clicked, the data is validated and sent with the <strong>$.post</strong> method. If the insert was successful, the lightbox is hidden and the newly created note is added to the page. Notice that we are using the <strong>make_draggable </strong>function, which is included below.</p>
<div id="attachment_629" class="wp-caption alignnone" style="width: 630px"><a href="http://tutorialzine.com/wp-content/uploads/2010/01/i31.png"><img class="size-full wp-image-629" title="The Note Position And Stacking Are Saved With AJAX" src="http://tutorialzine.com/wp-content/uploads/2010/01/i31.png" alt="The Note Position And Stacking Are Saved With AJAX" width="620" height="260" /></a><p class="wp-caption-text">The Note Position And Stacking Are Saved With AJAX</p></div>
<h4>script.js &#8211; Part 3</h4>
<pre class="brush:js">var zIndex = 0;

function make_draggable(elements)
{
	/* Elements is a jquery object: */
	elements.draggable({
		containment:'parent',
		start:function(e,ui){ ui.helper.css('z-index',++zIndex); },
		stop:function(e,ui){

			/* Sending the z-index and positon of the note to update_position.php via AJAX GET: */
			$.get('ajax/update_position.php',{
				x		: ui.position.left,
				y		: ui.position.top,
				z		: zIndex,
				id	: parseInt(ui.helper.find('span.data').html())
			});
		}
	});
}</pre>
<p>In the last part of script.js, we have the <strong>make_draggable</strong> function. It turns a set of jQuery elements passed as a parameter into draggable objects. I&#8217;ve moved this functionality into a separate function  because we need to create draggables in twice &#8211; once on initial page load, and once when we add a new note to the page.</p>
<h3>Step 5 &#8211; MySQL</h3>
<p>If you plan on running and building upon this demo, you&#8217;ll need to set up a working version on your server. You&#8217;ll need to execute the code from <strong>table.sql</strong> of the download archive in phpMyAdmin and fill in your database credentials in <strong>connect.php</strong>.</p>
<p>With this our AJAX-ed Sticky Note system is complete!</p>
<h3>Conclusion</h3>
<p>Today we created an Ajax Enabled Sticky Note Management System and demonstrated how we could use one of the readily available plug-ins for the jQuery library to build a dynamic interface, complete with a live preview.</p>
<p><strong>What do you think? How would you improve this code?</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://tutorialzine.com/2010/01/sticky-notes-ajax-php-jquery/feed/</wfw:commentRss>
		<slash:comments>56</slash:comments>
		</item>
		<item>
		<title>Advanced Event Timeline With PHP, CSS &amp; jQuery</title>
		<link>http://tutorialzine.com/2010/01/advanced-event-timeline-with-php-css-jquery/</link>
		<comments>http://tutorialzine.com/2010/01/advanced-event-timeline-with-php-css-jquery/#comments</comments>
		<pubDate>Mon, 04 Jan 2010 21:00:46 +0000</pubDate>
		<dc:creator>Martin Angelov</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://tutorialzine.com/?p=591</guid>
		<description><![CDATA[Welcoming the new year and making an Advanced Event Timeline with the help of PHP, MySQL, CSS &#038; jQuery, that will display a pretty time line with clickable events. Adding new ones is going to be as easy as inserting a row in the database.]]></description>
			<content:encoded><![CDATA[<p>First I want to take the time to thank you, Tutorialzine&#8217;s readers, for all your support the past year and to wish you a happy new 2010! A lot of interesting tutorials are on their way and there are also some nice changes planned which I am sure you&#8217;ll like.</p>
<p>Now lets start the year with a brand new tut!</p>
<p>It all began last week, when I received this letter from one of our readers:</p>
<blockquote><p>Hi,</p>
<p>I love your site! It&#8217;s the best out there.</p>
<p>I was wondering if you could create one day a tutorial on how to create a sleek event timeline like Google&#8217;s 10th Birthday Timeline, available at <a href="http://www.google.com/tenthbirthday/#start" target="_blank">http://www.google.com/tenthbirthday/</a>. That would be much appreciated! I am sure many other people would be grateful for that tutorial too.</p>
<p>Thanks, and happy new year!</p>
<p>Vinnie</p></blockquote>
<p>I am always on the look for good tutorial ideas, so Vinnie sent his email right on time!</p>
<p>Today we are making an Advanced Event Timeline with the help of PHP, MySQL, CSS &amp; jQuery, that will display a pretty time line with clickable events. Adding new ones is going to be as easy as inserting a row in the database.</p>
<h3>Step 1 &#8211; XHTML</h3>
<p>First, be sure to grab the example files from the button above, so that you can easily follow what is going on.</p>
<p>The first step of this tut is to create the XHTML structure, as seen in <strong>demo.php</strong>.</p>
<h4>demo.php</h4>
<pre class="brush:html">&lt;div id="timelineLimiter"&gt; &lt;!-- Hides the overflowing timelineScroll div --&gt;
&lt;div id="timelineScroll"&gt; &lt;!-- Contains the timeline and expands to fit --&gt;

&lt;!-- PHP code that generates the event list --&gt;

&lt;div class="clear"&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;div id="scroll"&gt; &lt;!-- The year time line --&gt;
&lt;div id="centered"&gt; &lt;!-- Sized by jQuery to fit all the years --&gt;
&lt;div id="highlight"&gt;&lt;/div&gt; &lt;!-- The light blue highlight shown behind the years --&gt;
&lt;?php echo $scrollPoints ?&gt; &lt;!-- This PHP variable holds the years that have events --&gt;
&lt;div class="clear"&gt;&lt;/div&gt;

&lt;/div&gt;
&lt;/div&gt;

&lt;div id="slider"&gt; &lt;!-- The slider container --&gt;
&lt;div id="bar"&gt; &lt;!-- The bar that can be dragged --&gt;
&lt;div id="barLeft"&gt;&lt;/div&gt;  &lt;!-- Left arrow of the bar --&gt;
&lt;div id="barRight"&gt;&lt;/div&gt;  &lt;!-- Right arrow, both are styled with CSS --&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;</pre>
<p>I have omitted some of the PHP code that generates the events so we can take a better look at the markup (we will get back to it in the next step).</p>
<p>Te main idea is that we have two divs &#8211; <strong>timelineLimiter</strong> and <strong>timelineScroll</strong> positioned inside it. The former takes the width of the screen, and the latter is expanded to fit all the event sections that are inserted inside it. This way only a part of the larger inner div is visible and the rest can be scrolled to the left and right by a jQuery slider we will be making in step 4.</p>
<p>Now lets take a look at the PHP back-end.</p>
<div id="attachment_594" class="wp-caption alignnone" style="width: 630px"><a href="http://tutorialzine.com/wp-content/uploads/2010/01/i2.png"><img class="size-full wp-image-594" title="Advanced Event Timeline With PHP MySQL CSS jQuery" src="http://tutorialzine.com/wp-content/uploads/2010/01/i2.png" alt="Advanced Event Timeline With PHP MySQL CSS jQuery" width="620" height="260" /></a><p class="wp-caption-text">Advanced Event Timeline With PHP MySQL CSS jQuery</p></div>
<h3>Step 2 &#8211; PHP</h3>
<p>PHP selects all the events in the database and groups the events by year in the <strong>$dates</strong> array. It later loops through it and outputs all the events as <strong>&lt;li&gt;</strong> elements inside of unordered lists which belong to each of the event years.</p>
<h4>demo.php</h4>
<pre class="brush:php">// We first select all the events from the database ordered by date:

$dates = array();
$res = mysql_query("SELECT * FROM timeline ORDER BY date_event ASC");

while($row=mysql_fetch_assoc($res))
{
	// Store the events in an array, grouped by years:
	$dates[date('Y',strtotime($row['date_event']))][] = $row;
}

$colors = array('green','blue','chreme');
$scrollPoints = '';

$i=0;
foreach($dates as $year=&gt;$array)
{
	// Loop through the years:

	echo '
		&lt;div class="event"&gt;
		&lt;div class="eventHeading '.$colors[$i++%3].'"&gt;'.$year.'&lt;/div&gt;
		&lt;ul class="eventList"&gt;';

	foreach($array as $event)
	{
		// Loop through the events in the current year:

		echo '&lt;li class="'.$event['type'].'"&gt;
			&lt;span class="icon" title="'.ucfirst($event['type']).'"&gt;&lt;/span&gt;
			'.htmlspecialchars($event['title']).'

 			&lt;div class="content"&gt;
				&lt;div class="body"&gt;'.($event['type']=='image'?'&lt;div style="text-align:center"&gt;&lt;img src="'.$event['body'].'" alt="Image" /&gt;&lt;/div&gt;':nl2br($event['body'])).'&lt;/div&gt;
				&lt;div class="title"&gt;'.htmlspecialchars($event['title']).'&lt;/div&gt;
				&lt;div class="date"&gt;'.date("F j, Y",strtotime($event['date_event'])).'&lt;/div&gt;
			&lt;/div&gt;
 			&lt;/li&gt;';
	}

	echo '&lt;/ul&gt;&lt;/div&gt;';

 	// Generate a list of years for the time line scroll bar:
	$scrollPoints.='&lt;div class="scrollPoints"&gt;'.$year.'&lt;/div&gt;';

}</pre>
<p>Thus the complete markup for the page is generated. Now we are ready to apply some styles.</p>
<div id="attachment_595" class="wp-caption alignnone" style="width: 630px"><a href="http://tutorialzine.com/wp-content/uploads/2010/01/i1.png"><img class="size-full wp-image-595" title="The Event Sections" src="http://tutorialzine.com/wp-content/uploads/2010/01/i1.png" alt="The Event Sections" width="620" height="260" /></a><p class="wp-caption-text">The Event Sections</p></div>
<h3>Step 3 &#8211; CSS</h3>
<p>After we&#8217;ve inserted the CSS stylesheet to the head section of the document, we can start laying down the rules. Only the more interesting ones are included here. You can view the rest in <strong>styles.css</strong>.</p>
<h4>styles.css</h4>
<pre class="brush:css">.event{
	/* Contains the section title and list with events */
	float:left;
	padding:4px;
	text-align:left;
	width:300px;
	margin:0 5px 50px;
}

.eventList li{
	/* The individual events */
	background:#F4F4F4;
	border:1px solid #EEEEEE;
	list-style:none;
	margin:5px;
	padding:4px 7px;

	/* CSS3 rounded corners */
	-moz-border-radius:4px;
	-webkit-border-radius:4px;
	border-radius:4px;
}

.eventList li:hover{
	/* The hover state: */
	cursor:pointer;
	background:#E6F8FF;
	border:1px solid #D4E6EE;
	color:#548DA5;
}

li span{
	/* The event icon */
	display:block;
	float:left;
	height:16px;
	margin-right:5px;
	width:16px;
}

/* Individual background images for each type of event: */

li.news span.icon { 	background:url(img/icons/newspaper.png) no-repeat; }
li.image span.icon { 	background:url(img/icons/camera.png) no-repeat; }
li.milestone span.icon { 	background:url(img/icons/chart.png) no-repeat; }

#timelineLimiter{
	/* Hides the overflowing timeline */
	width:100%;
	overflow:hidden;
	padding-top:10px;
	margin:40px 0;
}

#scroll{
	/* The small timeline below the main one. Hidden here and shown by jQuery if JS is enabled: */
	display:none;
	height:30px;

	background:#F5F5F5;
	border:1px solid #EEEEEE;
	color:#999999;
}

.scrollPoints{
	/* The individual years */
	float:left;
	font-size:1.4em;
	padding:4px 10px;
	text-align:center;
	width:100px;

	position:relative;
	z-index:10;
}</pre>
<p>Here the .event class styles the event years sections (these are the divs that group events that have happened in the same year).</p>
<p>Near the middle of the code you can see that we&#8217;ve used some CSS3 rounded corners which work in the majority of browsers (not supported by IE and Opera).</p>
<p>We also define individual background images for each of the event types &#8211; image, news or milestone.</p>
<h3>Step 4 &#8211; jQuery</h3>
<p>The last step is to insert a layer of interactivity into the browser. We will be doing this with the help of the jQuery JavaScript library, included in the head section of <strong>demo.php</strong>.</p>
<p>I&#8217;ve split the code below in two parts so they are more comprehensible.</p>
<h4>script.js &#8211; Part 1</h4>
<pre class="brush:js">$(document).ready(function(){

	/* This code is executed after the DOM has been completely loaded */

	/* The number of event sections / years with events */

	var tot=$('.event').length;

	$('.eventList li').click(function(e){

		showWindow('&lt;div&gt;'+$(this).find('div.content').html()+'&lt;/div&gt;');
	});

	/* Each event section is 320 px wide */
	var timelineWidth = 320*tot;

	var screenWidth = $(document).width();

	$('#timelineScroll').width(timelineWidth);

	/* If the timeline is wider than the screen show the slider: */
	if(timelineWidth &gt; screenWidth)
	{
		$('#scroll,#slider').show();
		$('#centered,#slider').width(120*tot);

		/* Making the scrollbar draggable: */
		$('#bar').width((120/320)*screenWidth).draggable({

			containment: 'parent',
			drag: function(e, ui) {

			if(!this.elem)
			{
				/* This section is executed only the first time the function is run for performance */

				this.elem = $('#timelineScroll');

				/* The difference between the slider's width and its container: */
				this.maxSlide = ui.helper.parent().width()-ui.helper.width();

				/* The difference between the timeline's width and its container */
				this.cWidth = this.elem.width()-this.elem.parent().width();

				this.highlight = $('#highlight');
			}

			/* Translating each movement of the slider to the timeline: */
			this.elem.css({marginLeft:'-'+((ui.position.left/this.maxSlide)*this.cWidth)+'px'});

			/* Moving the highlight: */
			this.highlight.css('left',ui.position.left)
		}

	});

	$('#highlight').width((120/320)*screenWidth-3);
}
});</pre>
<p>As you may have noticed in the PHP section of the tut (if not check it out &#8211; around line 33) that with each event we include a set of div elements which contain additional information (title, text and date). Those are hidden with <strong>display:none</strong> in our CSS file, and are accessed by jQuery so that the pop-up window can be populated with data without the need of sending AJAX requests (not to mention that this content is visible to search engines and is great for SEO). So it is a win-win solution.</p>
<p>The data itself is being fetched in the second part of the script below:</p>
<h4>script.js &#8211; Part 2</h4>
<pre class="brush:js">function showWindow(data)
{
	/* Each event contains a set of hidden divs that hold
additional information about the event: */

	var title = $('.title',data).text();
	var date = $('.date',data).text();
	var body = $('.body',data).html();

	$('&lt;div id="overlay"&gt;').css({

		width:$(document).width(),
		height:$(document).height(),
		opacity:0.6

	}).appendTo('body').click(function(){

		$(this).remove();
		$('#windowBox').remove();
 	});

 	$('body').append('&lt;div id="windowBox"&gt;&lt;div id="titleDiv"&gt;'+title+'&lt;/div&gt;'+body+'&lt;div id="date"&gt;'+date+'&lt;/div&gt;&lt;/div&gt;');

 	$('#windowBox').css({

		width:500,
		height:350,
		left: ($(window).width() - 500)/2,
		top: ($(window).height() - 350)/2
	});
}</pre>
<p>In this function we are basically treating the parameter passed from Part 1 above, where the function is called, as regular HTML and use the standard jQuery selectors thus populating the title, date and body variables.</p>
<div id="attachment_596" class="wp-caption alignnone" style="width: 630px"><a href="http://tutorialzine.com/wp-content/uploads/2010/01/i3.png"><img class="size-full wp-image-596" title="The Timeline Explained" src="http://tutorialzine.com/wp-content/uploads/2010/01/i3.png" alt="The Timeline Explained" width="620" height="460" /></a><p class="wp-caption-text">The Timeline Explained</p></div>
<h3>Step 5 &#8211; MySQL</h3>
<p>This last step is only needed if you plan to run the demo on your own server, or like an addition to your current site.</p>
<p>To make it all tick, you have to recreate the timeline MySQL table from <strong>timeline.sql</strong>, provided in the download archive. You will also need to fill in your database credentials in <strong>connect.php</strong>.</p>
<p>With this our Event Timeline is complete!</p>
<h3>Conclusion</h3>
<p>Today we created a timeline that you can modify to showcase the important events that mark your days. It is easily modifiable and you are free to use it in your or your clients&#8217; projects.</p>
<p><strong>Be sure to leave a comment if you liked it : )</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://tutorialzine.com/2010/01/advanced-event-timeline-with-php-css-jquery/feed/</wfw:commentRss>
		<slash:comments>45</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk
Page Caching using disk (enhanced) (user agent is rejected)

Served from: tutorialzine.com @ 2010-08-01 02:49:18 -->