<?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>Web Development Tutorials &#38; Resources</description>
	<lastBuildDate>Wed, 01 Feb 2012 14:50:22 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Question of the Day with CodeIgniter and MySQL</title>
		<link>http://tutorialzine.com/2012/01/question-of-the-day-codeigniter-php-mysql/</link>
		<comments>http://tutorialzine.com/2012/01/question-of-the-day-codeigniter-php-mysql/#comments</comments>
		<pubDate>Thu, 19 Jan 2012 19:30:12 +0000</pubDate>
		<dc:creator>Martin Angelov</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://tutorialzine.com/?p=1801</guid>
		<description><![CDATA[<div><a href="http://tutorialzine.com/2012/01/question-of-the-day-codeigniter-php-mysql/"><img src="http://cdn.tutorialzine.com/img/featured/1801.jpg" /></a></div> In this tutorial we will build a small application with CodeIgniter that will be backed by a MySQL database. It will present questions and give visitors the ability to post answers.]]></description>
			<content:encoded><![CDATA[<div><a href="http://tutorialzine.com/2012/01/question-of-the-day-codeigniter-php-mysql/"><img src="http://cdn.tutorialzine.com/img/featured/1801.jpg" /></a></div> <p>In this tutorial we will build a small application with CodeIgniter that will be backed by a MySQL database. It will present questions and give visitors the ability to post answers. There isn&#8217;t an admin interface for adding or changing questions, but if you follow and understand this tutorial, you will be able to create one yourself.</p>
<p>As this might be the first exposure to CodeIgniter for some of you, we will start with a brief intro. If you know what CI is, you can skip directly to the code.</p>
<h3>First, what is CodeIgniter?</h3>
<p><a href="http://codeigniter.com/" target="_blank">CodeIgniter</a> is a framework for developing web applications in PHP. It will help you properly organize your code using the model-view-controller (MVC) pattern, and give you useful functionality for getting your site up and running quickly. It hides away the tedious work like building and validating forms, communicating with a database, managing error pages and much more.</p>
<p>There are certainly a lot of frameworks to choose from, but CI has the winning combination of a big community, nice documentation and good performance. Unless you enjoy spending time building sites from scratch (which is not a bad thing), using a framework is the smarter way to go.</p>
<p>You should probably start by reading the <a href="http://codeigniter.com/user_guide/overview/getting_started.html" target="_blank">CodeIgniter introductory guide</a>, which will give you a better understanding of how CI works. Of course, if you are experienced with PHP you can grab the zip and jump directly to the code.</p>
<p><strong>Let&#8217;s begin!</strong></p>
<h3>The database</h3>
<p>Naturally, we will need a table for the questions, and a table for the answers.</p>
<div id="attachment_1809" class="wp-caption alignnone" style="width: 630px"><img class="size-full wp-image-1809" title="The Database Schema" src="http://cdn.tutorialzine.com/wp-content/uploads/2012/01/database_schema.jpg" alt="The Database Schema" width="620" height="460" /><p class="wp-caption-text">The Database Schema</p></div>
<p>The questions table has only two fields &#8211; the <strong>ID</strong> of the question (automatically assigned with auto_increment) and the <strong>question</strong> body field. The answers also have an ID column, but they also have a <strong>qid</strong> field for the id of the question they relate to. The rest of the fields are the email and name of the author, along with the answer body and a timestamp (the dt field).</p>
<p>It is possible to create these tables with PHP code (CI gives us the ability to manipulate tables), but we will keep things simple and design them using a database management system like <em>phpMyAdmin</em>. It is even simpler for you, as I&#8217;ve included an export of the tables as an SQL file (<strong>tables.sql</strong> in the download archive). Import it into your database or copy/paste the code into the SQL tab of phpMyAdmin and you should be ready to go.</p>
<h3>Setting up CodeIgniter</h3>
<p>At this point you should <a href="http://codeigniter.com/downloads/" target="_blank">download CodeIgniter</a>. In this tutorial I am using version 2.1.0, the latest at the time of writing. Extract it in the directory where you are developing your website (move the files outside the CodeIgniter_2.1.0 folder and remove it). We will need to edit a few settings so the framework works the way we want it.</p>
<blockquote class="note"><p><strong>Important</strong><strong>:</strong> This section assumes that you are downloading a fresh copy of CodeIgniter. If you only want to make the downloaded demo work, you will only need to change your $config['base_url'] setting in config.php, and add your MySQL login details to database.php. The other changes are already made (you still need to create the MySQL tables).</p></blockquote>
<h4>Edit routes.php</h4>
<p>The application/config/routes.php file determines which controller is called by default. We need to set this to <strong>questions</strong>, which we will be creating in a moment.</p>
<pre class="brush:php">// Find this line:
$route['default_controller'] = "welcome";
// Replace it with this:
$route['default_controller'] = "questions";</pre>
<p>This will show the questions controller as the start page of the application.</p>
<h4>Edit config.php</h4>
<p>The application/config/config.php file holds much of the configuration settings of the framework.</p>
<pre class="brush:php">// Find this line:
$config['base_url'] = '';
// Replace it with the following:
$config['base_url']	= 'http://example.com/';</pre>
<p>The above setting, <strong>base_url</strong>, tells CI where your site is located. This information is used when forming links and including resources like stylesheets and images.</p>
<p>The following setting is optional. CodeIgniter adds index.php to every URL by default (like so: http://example.com/index.php/products/). If you want to hide it (so that the url becomes http://example.com/products/), you will need to edit the <strong>index_page</strong> setting:</p>
<pre class="brush:php">// Find this line:
$config['index_page'] = 'index.php';
// Replace it with the following:
$config['index_page'] = '';</pre>
<p>You will also need to create an <strong>.htaccess</strong> file, which rewrites the URLs so that they still get to index.php, although it is not included explicitly. The .htaccess I use in the demo follows:</p>
<h4>.htaccess</h4>
<pre class="brush:plain">Options +FollowSymLinks
Options +Indexes
RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

RewriteCond $1 !^(index\.php)
RewriteRule ^(.*)$ index.php/$1 [L]</pre>
<p>Now you only need to add your MySQL connection settings so that your application can connect to your database.</p>
<h4>Edit database.php</h4>
<p>Find these four lines in application/config/database.php and change them to reflect your connection settings:</p>
<pre class="brush:php">$db['default']['hostname'] = 'localhost';
$db['default']['username'] = 'user';
$db['default']['password'] = 'pass';
$db['default']['database'] = 'your_database_name';</pre>
<p>Great! We are done setting up CodeIgniter, so we can now move on with the code.</p>
<div id="attachment_1813" class="wp-caption alignnone" style="width: 630px"><a href="http://demo.tutorialzine.com/2012/01/question-of-the-day-codeigniter-php-mysql/"><img class="size-full wp-image-1813" title="Question of the Day with CodeIgniter" src="http://cdn.tutorialzine.com/wp-content/uploads/2012/01/comments.jpg" alt="Question of the Day with CodeIgniter" width="620" height="460" /></a><p class="wp-caption-text">Question of the Day with CodeIgniter</p></div>
<h3>Showing the questions</h3>
<p>To show the questions we will need to create two files &#8211; a controller, which will be called when we visit the <strong>/question/</strong> URL, and a view, which outputs the HTML code of the page. The controller will handle selecting records from the database and passing them to view. Note that we are not using any models in this app (the M in MVC). For simple applications like this one, they are purely optional and you can write CI apps without them.</p>
<h4>/application/controllers/questions.php</h4>
<pre class="brush:php">if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Questions extends CI_Controller {

	public function index(){

		// Loading only the libraries and helpers that we need.
		// This is one of the things that make CI fast.

		$this-&gt;load-&gt;database();
		$this-&gt;load-&gt;helper(array('date','url'));

		// Get the id of the last question

		$res = $this-&gt;db-&gt;
				select_max('id')-&gt;
				get('qod_questions')-&gt;
				result_array();

		$id = $res[0]['id'];

		$this-&gt;show($id);
	}

	public function show($id = -1){

		$this-&gt;load-&gt;database();
		$this-&gt;load-&gt;helper(array('date','url'));

		// Select the question

		$q = $this-&gt;db-&gt;
				where(array('id'=&gt;$id))-&gt;
				get('qod_questions')-&gt;
				result_array();

		if(empty($q)){
			// Show an error page
			show_404();
		}

		$a = $this-&gt;db-&gt;
				where(array('qid'=&gt;$id))-&gt;
				order_by('id','desc')-&gt;
				get('qod_answers')-&gt;
				result_array();

		// Get the ids of the previous
		// and next questions

		$prev = 0;
		$next = 0;

		$res = $this-&gt;db-&gt;
				select_min('id')-&gt;
				where("id &gt; $id")-&gt;
				get('qod_questions')-&gt;
				result_array();

		if(!empty($res)){
			$next = $res[0]['id'];
		}

		$res = $this-&gt;db-&gt;
				select_max('id')-&gt;
				where("id &lt; $id")-&gt;
				get('qod_questions')-&gt;
				result_array();

		if(!empty($res)){
			$prev = $res[0]['id'];
		}

		$this-&gt;load-&gt;view('question_of_the_day',array(
			'question'	=&gt; $q[0]['question'],
			'answers'	=&gt; $a,
			'previous'	=&gt; $prev,
			'next'		=&gt; $next,
			'id'		=&gt; $id
		));
	}
}</pre>
<p>The controller is basically a class that extends <strong>CI_Controller</strong> and resides in the <em>controllers</em> folder. The class methods are called by the framework depending on the URL. For example http://example.com/questions/ will execute the <em>index</em> method, and http://example.com/questions/show/213 &#8211; the <em>show</em> method. In the latter case, 213 will be passed as the id parameter.</p>
<p>In the <strong>show</strong> method we select the question with the passed ID and display it in the view. What the <strong>index</strong> method does, is to select the id of the newest question, and also call the show method. Because it is set as the default controller, this would mean that when you visit the start page of the application (the base url you set in the previous section), the latest question will be shown.</p>
<blockquote class="note"><p>Read more about the <a href="http://codeigniter.com/user_guide/general/urls.html" target="_blank">URLs</a>, <a href="http://codeigniter.com/user_guide/general/controllers.html" target="_blank">controllers</a>, <a href="http://codeigniter.com/user_guide/general/views.html" target="_blank">views</a>, <a href="http://codeigniter.com/user_guide/general/helpers.html" target="_blank">helpers</a> and the <a href="http://codeigniter.com/user_guide/database/examples.html" target="_blank">database class</a> of CodeIgniter in the docs.</p></blockquote>
<p>Now let&#8217;s see how the view works. When we load it, we pass an array. Each of the array keys (<em>question</em>, <em>answers</em>, <em>previous</em>, <em>next</em> and <em>id</em>) will be extracted and transformed into a variable. Instead of a class, the view is a simple PHP file.</p>
<h4>/application/views/question_of_the_day.php</h4>
<pre class="brush:html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
    &lt;head&gt;
        &lt;meta charset="utf-8" /&gt;
        &lt;title&gt;&lt;?php echo $question?&gt; - Question of the day | Tutorialzine Demo&lt;/title&gt;

        &lt;!-- Our CSS stylesheet file --&gt;
        &lt;link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Rancho" /&gt;
        &lt;link rel="stylesheet" href="&lt;?php echo base_url()?&gt;assets/css/styles.css" /&gt;

        &lt;!--[if lt IE 9]&gt;
          &lt;script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"&gt;&lt;/script&gt;
        &lt;![endif]--&gt;
    &lt;/head&gt;

    &lt;body&gt;

		&lt;header id="blackboard"&gt;
			&lt;h1&gt;&lt;?php echo $question?&gt;&lt;/h1&gt;
			&lt;?php if($previous) echo anchor("questions/show/$previous",'&amp;laquo;','class="arrow left"')?&gt;
			&lt;?php if($next) echo anchor("questions/show/$next",'&amp;raquo;','class="arrow right"')?&gt;
		&lt;/header&gt;

		&lt;?php 

		// This method will create a link to the answer form. It is given relative
		// to your index page, but will be transformed depending on your base in config.php

		echo anchor("answers/add/$id",'Add your answer','class="addAnswer"');

		?&gt;

		&lt;ul id="answers"&gt;

		&lt;?php foreach ($answers as $ans): ?&gt;

			&lt;li&gt;
				&lt;?php
					// Forming the URL of the gravatar image.
					$gravatar = 'http://www.gravatar.com/avatar/'.md5( strtolower( trim($ans['email']) ) ).'?d=mm';
				?&gt;

				&lt;span class="avatar" style="background-image:url(&lt;?php echo $gravatar?&gt;)"&gt;&lt;/span&gt;
				&lt;span class="meta"&gt;
					&lt;a href="#" class="author"&gt;&lt;?php echo $ans['name']?&gt;&lt;/a&gt;
					&lt;?php
						// We are using the built-in timestamp method. We are using
						// array slice to limit the shown time divisions.
						$ts = explode(',', timespan(strtotime($ans['dt'])));
						$t = implode(',',array_slice($ts,0,2));
					?&gt;
					&lt;i&gt;&lt;?php echo $t?&gt; ago&lt;/i&gt;
				&lt;/span&gt;
				&lt;p class="answer"&gt;&lt;?php echo $ans['answer']?&gt;&lt;/p&gt;
			&lt;/li&gt;

		&lt;?php endforeach; ?&gt;

		&lt;/ul&gt;

    &lt;/body&gt;
&lt;/html&gt;</pre>
<p>The script loops through the <strong>$answers</strong> array and outputs a li element for each answer. It <a href="http://en.gravatar.com/site/implement/hash/" target="_blank">assembles a gravatar URL</a> by generating an md5 hash of the email and includes it as the background-image of a rounded span element.</p>
<p>This gives us a functional answer browsing page. But how do we let people answer these questions?</p>
<div id="attachment_1814" class="wp-caption alignnone" style="width: 630px"><a href="http://demo.tutorialzine.com/2012/01/question-of-the-day-codeigniter-php-mysql/"><img class="size-full wp-image-1814" title="The Blackboard" src="http://cdn.tutorialzine.com/wp-content/uploads/2012/01/the-blackboard.jpg" alt="The Blackboard" width="620" height="260" /></a><p class="wp-caption-text">The Blackboard</p></div>
<h3>Posting answers</h3>
<p>We will again need to write a controller and a view for adding answers. Here we will use a few more of the neat CodeIgniter features &#8211; generating forms and validating them. The generation is handled by the <a href="http://codeigniter.com/user_guide/helpers/form_helper.html" target="_blank">form helper</a>, and the validation &#8211; by the <a href="http://codeigniter.com/user_guide/libraries/form_validation.html" target="_blank">form validation class</a>.</p>
<p>You can see the <strong>answers</strong> controller below.</p>
<h4>/application/controllers/answers.php</h4>
<pre class="brush:php">if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Answers extends CI_Controller {

	public function add($id = -1){

		$this-&gt;load-&gt;database();
		$this-&gt;load-&gt;helper(array('url','form'));
		$this-&gt;load-&gt;library('form_validation');

		// Check if there is such a question

		$q = $this-&gt;db-&gt;
				where(array('id'=&gt;$id))-&gt;
				get('qod_questions')-&gt;
				result_array();

		if(empty($q)){
			// Show an error page
			show_404();
		}

		// Adding validation rules.

		$this-&gt;form_validation-&gt;set_rules('name', 'Name', 'required|min_length[2]|max_length[32]');
		$this-&gt;form_validation-&gt;set_rules('email', 'Email', 'required|valid_email');
		$this-&gt;form_validation-&gt;set_rules('answer', 'Answer', 'required|min_length[5]|max_length[255]');

		// If there are errors, show the form
		if ($this-&gt;form_validation-&gt;run() == FALSE){

			$this-&gt;load-&gt;view('add_answer',array(
				'question'	=&gt; $q[0]['question'],
				'qid'		=&gt; $q[0]['id']
			));

		}
		else{

			// Otherwise insert the answer to the database

			$this-&gt;db-&gt;insert('qod_answers', array(
				'qid'	=&gt; $q[0]['id'],
				'email'	=&gt; htmlspecialchars($this-&gt;input-&gt;post('email')),
				'name'	=&gt; htmlspecialchars($this-&gt;input-&gt;post('name')),

				// preserving new lines:
				'answer'=&gt; nl2br(htmlspecialchars($this-&gt;input-&gt;post('answer')))
			));

			redirect('questions/show/'.$q[0]['id']);
		}

	}
}</pre>
<p>With the help of the form validation class, we are able to add rules by which the data should be validated. We will insert the answer in the database only when presented with correct data. I am using the <code>htmlspecialchars()</code> PHP function to escape any HTML code that might have been typed in the form fields. When the answer is inserted, we redirect to the question page. If everything went as it should, the newly added answer should be at the top.</p>
<p>Equally interesting is how the answer form is generated. For this we will take a look at the view file.</p>
<h4>/application/views/add_answer.php</h4>
<pre class="brush:html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
    &lt;head&gt;
        &lt;meta charset="utf-8" /&gt;
        &lt;title&gt;&lt;?php echo $question?&gt; - Add Answer | Tutorialzine Demo&lt;/title&gt;

        &lt;!-- Our CSS stylesheet file --&gt;
        &lt;link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Rancho" /&gt;
        &lt;link rel="stylesheet" href="&lt;?php echo base_url()?&gt;assets/css/styles.css" /&gt;

        &lt;!--[if lt IE 9]&gt;
          &lt;script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"&gt;&lt;/script&gt;
        &lt;![endif]--&gt;
    &lt;/head&gt;

    &lt;body&gt;

		&lt;header id="blackboard"&gt;
			&lt;h1&gt;&lt;?php echo $question?&gt;&lt;/h1&gt;
		&lt;/header&gt;

		&lt;?php 

		// This will print a link to the question page
		echo anchor("questions/show/$qid",'Back to the question','class="addAnswer"');

		// Creating the form using the form helper

		echo form_open('');

		echo form_label('Name','name');
		echo form_input(array(
          'name'        =&gt; 'name',
          'id'          =&gt; 'name',
          'value'       =&gt; set_value('name'),
          'maxlength'   =&gt; '64'
        ));

		echo form_label('Email (gravatar enabled)','email');
		echo form_input(array(
          'name'        =&gt; 'email',
          'id'          =&gt; 'email',
          'value'       =&gt; set_value('email'),
          'maxlength'   =&gt; '128'
        ));

		echo form_label('Answer','answer');
		echo form_textarea(array(
          'name'        =&gt; 'answer',
          'id'          =&gt; 'answer',
          'value'       =&gt; set_value('answer'),
        ));

		echo form_submit('subm', 'Add Answer!'); 

		// Showing the validation errors
		$validation = validation_errors(); 

		if($validation):
		?&gt;
			&lt;div class="errorMessages"&gt;
				&lt;?php echo $validation?&gt;
			&lt;/div&gt;

		&lt;?php endif;?&gt;

		&lt;?php echo form_close()?&gt;

    &lt;/body&gt;
&lt;/html&gt;</pre>
<p>As we included the form helper in the controller, we have access to all of its functions here, in the view. These functions make it easier to create forms and form fields. Of course, you can directly write the HTML of the forms, but you will have to update the code if you change the URL of your site.</p>
<p>At the bottom of the file we are accessing the <code>validate_errors()</code> function which will return a string with error messages, generated by the validation class. If there are any errors, we show them in a <em>.errorMessages</em> div.</p>
<p>That is it! All that is left is to add a pretty stylesheet and some images.</p>
<h3>The styling</h3>
<p>To finish this application, we need to add a stylesheet and images. Where we put them is more a matter of personal preference. I have chosen to go with an <strong>assets</strong> folder in the base directory of the application (you can see it in the zip file).</p>
<p>In the views I have specified the URL of the stylesheet like this: <code>&lt;?php echo base_url()?&gt;assets/css/styles.css</code> which gives us the correct location. <code>base_url()</code> is a function defined in the <a href="http://codeigniter.com/user_guide/helpers/url_helper.html" target="_blank">URL helper</a> of the framework, which we&#8217;ve included in the controller.</p>
<p>As the tutorial is already quite lengthy, I won&#8217;t be discussing the styling here. You can see it for yourself by opening /assets/css/styles.css in your code editor.</p>
<h3>We&#8217;re done!</h3>
<p>I am hoping that you learned a lot in this tutorial. If you decide to go with CodeIgniter for your next website, it will be a useful experience for you. Although there is a learning curve, once you understand the basics, you will appreciate just how much time you can save. And with <a href="http://getsparks.org/" target="_blank">Sparks</a>, you will become even more productive by adding easy to use open source modules to your projects.</p>
]]></content:encoded>
			<wfw:commentRss>http://tutorialzine.com/2012/01/question-of-the-day-codeigniter-php-mysql/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Building a Website with PHP, MySQL and jQuery Mobile, Part 1</title>
		<link>http://tutorialzine.com/2011/08/jquery-mobile-product-website/</link>
		<comments>http://tutorialzine.com/2011/08/jquery-mobile-product-website/#comments</comments>
		<pubDate>Fri, 19 Aug 2011 18:58:17 +0000</pubDate>
		<dc:creator>Martin Angelov</dc:creator>
				<category><![CDATA[jQuery]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://tutorialzine.com/?p=1569</guid>
		<description><![CDATA[<div><a href="http://tutorialzine.com/2011/08/jquery-mobile-product-website/"><img src="http://cdn.tutorialzine.com/img/featured/1569.jpg" /></a></div> This is the first of a two-part tutorial, in which we will be building a simple computer shop website with PHP, MySQL and jQuery Mobile using the Model-View-Controller (MVC) pattern.]]></description>
			<content:encoded><![CDATA[<div><a href="http://tutorialzine.com/2011/08/jquery-mobile-product-website/"><img src="http://cdn.tutorialzine.com/img/featured/1569.jpg" /></a></div> <p>In this two-part tutorial, we will be building a simple website with PHP and MySQL, using the Model-View-Controller (MVC) pattern. Finally, with the help of the <a href="http://jquerymobile.com/" target="_blank">jQuery Mobile framework</a>, we will turn it into a touch-friendly mobile website, that works on any device and screen size.</p>
<p>In this first part, we concentrate on the backend, discussing the database and MVC organization. <a title="Go to Part 2" href="http://tutorialzine.com/2011/08/jquery-mobile-mvc-website-part-2/">In part two</a>, we are writing the views and integrating jQuery Mobile.</p>
<h3>The File Structure</h3>
<p>As we will be implementing the MVC pattern (in effect writing a simple micro-framework), it is natural to split our site structure into different folders for the models, views and controllers. Don&#8217;t let the number of files scare you &#8211; although we are using a lot of files, the code is concise and easy to follow.</p>
<div id="attachment_1575" class="wp-caption alignnone" style="width: 630px"><a href="http://demo.tutorialzine.com/2011/08/jquery-mobile-product-website/"><img class="size-full wp-image-1575" title="The Directory Structure" src="http://cdn.tutorialzine.com/wp-content/uploads/2011/08/jquery-mobile-php-mysql-file-structure.jpg" alt="The Directory Structure" width="620" height="260" /></a><p class="wp-caption-text">The Directory Structure</p></div>
<h3>The Database Schema</h3>
<p>Our simple application operates with two types of resources &#8211; categories and products. These are given their own tables &#8211; <strong>jqm_categories</strong>, and <strong>jqm_products</strong>. Each product has a category field, which assigns it to a category.</p>
<div id="attachment_1576" class="wp-caption alignnone" style="width: 630px"><a href="http://demo.tutorialzine.com/2011/08/jquery-mobile-product-website/"><img class="size-full wp-image-1576" title="jqm_categories Table Structure" src="http://cdn.tutorialzine.com/wp-content/uploads/2011/08/categories-table-structure.jpg" alt="jqm_categories Table Structure" width="620" height="260" /></a><p class="wp-caption-text">jqm_categories Table Structure</p></div>
<p>The categories table has an <strong>ID</strong> field, a <strong>name</strong> and a <strong>contains</strong> column, which shows how many products there are in each category.</p>
<div id="attachment_1577" class="wp-caption alignnone" style="width: 630px"><a href="http://demo.tutorialzine.com/2011/08/jquery-mobile-product-website/"><img class="size-full wp-image-1577" title="jqm_products Table Structure" src="http://cdn.tutorialzine.com/wp-content/uploads/2011/08/products-table-structure.jpg" alt="jqm_products Table Structure" width="620" height="260" /></a><p class="wp-caption-text">jqm_products Table Structure</p></div>
<p>The product table has a <strong>name</strong>, <strong>manufacturer</strong>, <strong>price</strong> and a <strong>category</strong> field. The latter holds the ID of the category the product is added to.</p>
<blockquote class="note"><p>You can find the SQL code to create these tables in tables.sql in the download archive. Execute it in the SQL tab of phpMyAdmin to have a working copy of this database. Remember to also fill in your MySQL login details in config.php.</p></blockquote>
<h3>The Models</h3>
<p>The models in our application will handle the communication with the database. We have two types of resources in our application &#8211; <strong>products</strong> and <strong>categories</strong>. The models will expose an easy to use method &#8211; <code>find()</code> which will query the database behind the scenes and return an array with objects.</p>
<p>Before starting work on the models, we will need to establish a database connection. I am using the <a href="http://www.php.net/manual/en/intro.pdo.php" target="_blank">PHP PDO class</a>, which means that it would be easy to use a different database than MySQL, if you need to.</p>
<h4>includes/connect.php</h4>
<pre class="brush:php">/*
	This file creates a new MySQL connection using the PDO class.
	The login details are taken from includes/config.php.
*/

try {
	$db = new PDO(
		"mysql:host=$db_host;dbname=$db_name;charset=UTF-8",
		$db_user,
		$db_pass
	);

    $db-&gt;query("SET NAMES 'utf8'");
	$db-&gt;setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e) {
	error_log($e-&gt;getMessage());
	die("A database error was encountered");
}</pre>
<p>This will put the <strong>$db</strong> connection object in the global scope, which we will use in our models. You can see them below.</p>
<h4>includes/models/category.model.php</h4>
<pre class="brush:php">class Category{

	/*
		The find static method selects categories
		from the database and returns them as
		an array of Category objects.
	*/

	public static function find($arr = array()){
		global $db;

		if(empty($arr)){
			$st = $db-&gt;prepare("SELECT * FROM jqm_categories");
		}
		else if($arr['id']){
			$st = $db-&gt;prepare("SELECT * FROM jqm_categories WHERE id=:id");
		}
		else{
			throw new Exception("Unsupported property!");
		}

                // This will execute the query, binding the $arr values as query parameters
		$st-&gt;execute($arr);

		// Returns an array of Category objects:
		return $st-&gt;fetchAll(PDO::FETCH_CLASS, "Category");
	}
}</pre>
<p>Both models are simple class definitions with a single static method &#8211; <strong>find()</strong>. In the fragment above, this method takes an optional array as a parameter and executes different queries as prepared statements.</p>
<p>In the return declaration, we are using the <a href="http://www.php.net/manual/en/pdostatement.fetchall.php" target="_blank">fetchAll</a> method passing it the <strong>PDO::FETCH_CLASS</strong> constant. What this does, is to loop though all the result rows, and create a new object of the Category class. The columns of each row will be added as public properties to the object.</p>
<p>This is also the case with the <em>Product model</em>:</p>
<h4>includes/models/product.model.php</h4>
<pre class="brush:php">class Product{

	// The find static method returns an array
	// with Product objects from the database.

	public static function find($arr){
		global $db;

		if($arr['id']){
			$st = $db-&gt;prepare("SELECT * FROM jqm_products WHERE id=:id");
		}
		else if($arr['category']){
			$st = $db-&gt;prepare("SELECT * FROM jqm_products WHERE category = :category");
		}
		else{
			throw new Exception("Unsupported property!");
		}

		$st-&gt;execute($arr);

		return $st-&gt;fetchAll(PDO::FETCH_CLASS, "Product");
	}
}</pre>
<p>The return values of both find methods are arrays with instances of the class. We could possibly return an array of generic objects (or an array of arrays) in the find method, but creating specific instances will allow us to automatically style each object using the appropriate template in the views folder (the ones that start with an underscore). We will talk again about this in the next part of the tutorial.</p>
<p>There, now that we have our two models, lets move on with the controllers.</p>
<div id="attachment_1579" class="wp-caption alignnone" style="width: 630px"><a href="http://demo.tutorialzine.com/2011/08/jquery-mobile-product-website/"><img class="size-full wp-image-1579" title="Computer Store with PHP, MySQL and jQuery Mobile" src="http://cdn.tutorialzine.com/wp-content/uploads/2011/08/mobile-computer-store.jpg" alt="Computer Store with PHP, MySQL and jQuery Mobile" width="620" height="460" /></a><p class="wp-caption-text">Computer Store with PHP, MySQL and jQuery Mobile</p></div>
<h3>The controllers</h3>
<p>The controllers use the <strong>find()</strong> methods of the models to fetch data, and render the appropriate views. We have two controllers in our application &#8211; one for the <em>home page</em>, and another one for the <em>category pages</em>.</p>
<h4>includes/controllers/home.controller.php</h4>
<pre class="brush:php">/* This controller renders the home page */

class HomeController{
	public function handleRequest(){

		// Select all the categories:
		$content = Category::find();

		render('home',array(
			'title'		=&gt; 'Welcome to our computer store',
			'content'	=&gt; $content
		));
	}
}</pre>
<p>Each controller defines a <strong>handleRequest()</strong> method. This method is called when a specific URL is visited. We will return to this in a second, when we discuss <em>index.php</em>.</p>
<p>In the case with the <strong>HomeController</strong>, <strong>handleRequest()</strong> just selects all the categories using the model&#8217;s find() method, and renders the home view (<em>includes/views/home.php</em>) using our <em>render</em> helper function (<em>includes/helpers.php</em>), passing a title and the selected categories. Things are a bit more complex in <strong>CategoryController</strong>:</p>
<h4>includes/controllers/category.controller.php</h4>
<pre class="brush:php">/* This controller renders the category pages */

class CategoryController{
	public function handleRequest(){
		$cat = Category::find(array('id'=&gt;$_GET['category']));

		if(empty($cat)){
			throw new Exception("There is no such category!");
		}

		// Fetch all the categories:
		$categories = Category::find();

		// Fetch all the products in this category:
		$products = Product::find(array('category'=&gt;$_GET['category']));

		// $categories and $products are both arrays with objects

		render('category',array(
			'title'			=&gt; 'Browsing '.$cat[0]-&gt;name,
			'categories'	=&gt; $categories,
			'products'		=&gt; $products
		));
	}
}</pre>
<p>The first thing this controller does, is to select the category by id (it is passed as part of the URL). If everything goes to plan, it fetches a list of categories, and a list of products associated with the current one. Finally, the category view is rendered.</p>
<p>Now lets see how all of these work together, by inspecting <em>index.php</em>:</p>
<h4>index.php</h4>
<pre class="brush:php">/*
	This is the index file of our simple website.
	It routes requests to the appropriate controllers
*/

require_once "includes/main.php";

try {

	if($_GET['category']){
		$c = new CategoryController();
	}
	else if(empty($_GET)){
		$c = new HomeController();
	}
	else throw new Exception('Wrong page!');

	$c-&gt;handleRequest();
}
catch(Exception $e) {
	// Display the error page using the "render()" helper function:
	render('error',array('message'=&gt;$e-&gt;getMessage()));
}</pre>
<p>This is the first file that is called on a new request. Depending on the <strong>$_GET</strong> parameters, it creates a new controller object and executes its <strong>handleRequest()</strong> method. If something goes wrong anywhere in the application, an exception will be generated which will find its way to the catch clause, and then in the error template.</p>
<p>One more thing that is worth noting, is the very first line of this file, where we require <em>main.php</em>. You can see it below:</p>
<h4>main.php</h4>
<pre class="brush:php">/*
	This is the main include file.
	It is only used in index.php and keeps it much cleaner.
*/

require_once "includes/config.php";
require_once "includes/connect.php";
require_once "includes/helpers.php";
require_once "includes/models/product.model.php";
require_once "includes/models/category.model.php";
require_once "includes/controllers/home.controller.php";
require_once "includes/controllers/category.controller.php";

// This will allow the browser to cache the pages of the store.

header('Cache-Control: max-age=3600, public');
header('Pragma: cache');
header("Last-Modified: ".gmdate("D, d M Y H:i:s",time())." GMT");
header("Expires: ".gmdate("D, d M Y H:i:s",time()+3600)." GMT");</pre>
<p>This file holds the <strong>require_once</strong> declarations for all the models, controllers and helper files. It also defines a few headers to enable caching in the browser (PHP disables caching by default), which speeds up the performance of the jQuery mobile framework.</p>
<h3>Continue to Part 2</h3>
<p>With this the first part of the tutorial is complete! <a title="Continue to Part 2" href="http://tutorialzine.com/2011/08/jquery-mobile-mvc-website-part-2/">Continue to part 2</a>, where we will be writing the views and incorporate jQuery Mobile. Feel free to share your thoughts and suggestions in the comment section below.</p>
]]></content:encoded>
			<wfw:commentRss>http://tutorialzine.com/2011/08/jquery-mobile-product-website/feed/</wfw:commentRss>
		<slash:comments>34</slash:comments>
		</item>
		<item>
		<title>Making an AJAX Web Chat (Part 1) &#8211; PHP and MySQL</title>
		<link>http://tutorialzine.com/2010/10/ajax-web-chat-php-mysql/</link>
		<comments>http://tutorialzine.com/2010/10/ajax-web-chat-php-mysql/#comments</comments>
		<pubDate>Wed, 13 Oct 2010 18:47:03 +0000</pubDate>
		<dc:creator>Martin Angelov</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://tutorialzine.com/?p=1209</guid>
		<description><![CDATA[<div><a href="http://tutorialzine.com/2010/10/ajax-web-chat-php-mysql/"><img src="http://cdn.tutorialzine.com/img/featured/1209.jpg" /></a></div> In this two-part tutorial, we will be creating an AJAX Web Chat using PHP, MySQL and jQuery. In this first part, we will be discussing the PHP &#038; MySQL side.]]></description>
			<content:encoded><![CDATA[<div><a href="http://tutorialzine.com/2010/10/ajax-web-chat-php-mysql/"><img src="http://cdn.tutorialzine.com/img/featured/1209.jpg" /></a></div> <p>When discussing real time communication, there aren&#8217;t many solutions that can rival the power of a simple webchat. What is even better, is that you already have all the tools you need to create one &#8211; your web browser. This, coupled with the fact that this is also one of the most requested tutorials by Tutorialzine&#8217;s readers, means that it is about time to start coding.</p>
<p>In this two-part tutorial, we will be creating an AJAX Web Chat using PHP, MySQL and jQuery. In this first part, we will be discussing the PHP &amp; MySQL side, and next week we will continue with the jQuery and CSS front-end. Go to <a href="http://tutorialzine.com/2010/10/ajax-web-chat-css-jquery/" target="_blank">part two</a>.</p>
<h3>HTML</h3>
<p>As usual, the first step is to lay down the HTML markup. Our document is structured as HTML5 for convenience, as this allows us to use the new, shorter (and more memorable) doctype, and skip the type attribute on the script tags.</p>
<h4>ajax-chat.html</h4>
<pre class="brush:html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8" /&gt;
&lt;title&gt;&lt;/title&gt;

&lt;!-- Loading the jScrollPane CSS, along with the styling of the
     chat in chat.css and the rest of the page in page.css --&gt;

&lt;link rel="stylesheet" type="text/css" href="js/jScrollPane/jScrollPane.css" /&gt;
&lt;link rel="stylesheet" type="text/css" href="css/page.css" /&gt;
&lt;link rel="stylesheet" type="text/css" href="css/chat.css" /&gt;

&lt;/head&gt;

&lt;body&gt;

&lt;div id="chatContainer"&gt;

    &lt;div id="chatTopBar" class="rounded"&gt;&lt;/div&gt;
    &lt;div id="chatLineHolder"&gt;&lt;/div&gt;

    &lt;div id="chatUsers" class="rounded"&gt;&lt;/div&gt;
    &lt;div id="chatBottomBar" class="rounded"&gt;
        &lt;div class="tip"&gt;&lt;/div&gt;

        &lt;form id="loginForm" method="post" action=""&gt;
            &lt;input id="name" name="name" class="rounded" maxlength="16" /&gt;
            &lt;input id="email" name="email" class="rounded" /&gt;
            &lt;input type="submit" class="blueButton" value="Login" /&gt;
        &lt;/form&gt;

        &lt;form id="submitForm" method="post" action=""&gt;
            &lt;input id="chatText" name="chatText" class="rounded" maxlength="255" /&gt;
            &lt;input type="submit" class="blueButton" value="Submit" /&gt;
        &lt;/form&gt;

    &lt;/div&gt;

&lt;/div&gt;

&lt;!-- Loading jQuery, the mousewheel plugin and jScrollPane, along with our script.js --&gt;

&lt;script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"&gt;&lt;/script&gt;
&lt;script src="js/jScrollPane/jquery.mousewheel.js"&gt;&lt;/script&gt;
&lt;script src="js/jScrollPane/jScrollPane.min.js"&gt;&lt;/script&gt;
&lt;script src="js/script.js"&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p>To optimize the load time, the stylesheets are included in the head section, and the JavaScript files in the footer, just before the closing body tag.</p>
<p>We are using the <a href="http://jscrollpane.kelvinluck.com/index.html" target="_blank">jScrollPane plugin</a> to create the scrollable area with the chats entries. This plugin comes with its own stylesheet, which is the first thing we&#8217;ve included into the page.</p>
<p>The markup of the chat consists of four main divs &#8211; the top bar, the chat container, the user container and the bottom bar. The latter holds the login and submit forms. The submit form is hidden by default and only shown if the user has successfully logged in the chat system.</p>
<div id="attachment_1215" class="wp-caption alignnone" style="width: 630px"><a href="http://demo.tutorialzine.com/2010/10/ajax-web-chat-jquery-css3/ajax-chat.html"><img class="size-full wp-image-1215" title="An AJAX Web Chat with PHP, MySQL and jQuery" src="http://cdn.tutorialzine.com/wp-content/uploads/2010/10/ajax_web_chat_php_mysql_jQuery.jpg" alt="An AJAX Web Chat with PHP, MySQL and jQuery" width="620" height="460" /></a><p class="wp-caption-text">An AJAX Web Chat with PHP, MySQL and jQuery</p></div>
<p>Lastly we include the JavaScript files. Starting with the jQuery library, we add the mousewheel plugin (used by jScrollPane), the jScrollPane plugin itself and our script.js file.</p>
<h3>Database Schema</h3>
<p>Before we move on with the PHP part, we first have to take a closer look at how the chat data is organized in the MySQL database.</p>
<p>For the purposes of this script we use two tables. In <strong><em>webchat_users</em></strong> we are storing the chat participants. This table has na <strong><em> id</em></strong>, <em><strong>name</strong></em>, <em><strong>gravatar</strong></em> and a <em><strong>last_activity</strong></em> field. The name field is defined  as unique, so that no users have duplicate nick names in the chatroom.</p>
<div id="attachment_1213" class="wp-caption alignnone" style="width: 630px"><img class="size-full wp-image-1213" title="Webchat Users Table Structure" src="http://cdn.tutorialzine.com/wp-content/uploads/2010/10/webchat_users_table_structure.jpg" alt="Webchat Users Table Structure" width="620" height="260" /><p class="wp-caption-text">Webchat Users Table Structure</p></div>
<p>Another useful feature of the unique index fields, is that insert queries will fail and the <em><strong>inserted_rows</strong></em> property of the MySQLi object will be set to zero if we attempt to insert a duplicate row. This finds its place in the Chat PHP class you will see in the next step.</p>
<p>The <em><strong>last_activity</strong></em> column holds a timestamp, which is updated every 15 seconds for every user. It is also defined as an index, so it is faster to delete inactive users (having a last_activity column with a greater value than 15, would mean that the user is no longer viewing the chat window).</p>
<div id="attachment_1214" class="wp-caption alignnone" style="width: 630px"><img class="size-full wp-image-1214" title="Webchat Lines Table Structure" src="http://cdn.tutorialzine.com/wp-content/uploads/2010/10/webchat_lines_table_structure.jpg" alt="Webchat Lines Table Structure" width="620" height="260" /><p class="wp-caption-text">Webchat Lines Table Structure</p></div>
<p>The webchat_lines table holds the individual chat entries. Notice that we are storing the author name and gravatar here as well. This duplication is worthwhile as it frees us from using an expensive join when requesting the latest chats &#8211; the most frequently accessed feature of the application.</p>
<blockquote class="note"><p>The definitions of these tables are available in tables.sql in the download archive. You can execute the code in phpMyAdmin to create them. Also, when setting up the chat on your own host, remember to modify ajax.php with your MySQL database login details.</p></blockquote>
<h3>PHP</h3>
<p>Now that we have the database in place, lets start discussing the PHP scripts that drive the chat.</p>
<p>The first file we are going to take a closer look at, is ajax.php. It handles the AJAX requests sent from the jQuery front end and outputs JSON formatted data.</p>
<h4>ajax.php</h4>
<pre class="brush:php">require "classes/DB.class.php";
require "classes/Chat.class.php";
require "classes/ChatBase.class.php";
require "classes/ChatLine.class.php";
require "classes/ChatUser.class.php";

session_name('webchat');
session_start();

if(get_magic_quotes_gpc()){

    // If magic quotes is enabled, strip the extra slashes
    array_walk_recursive($_GET,create_function('&amp;$v,$k','$v = stripslashes($v);'));
    array_walk_recursive($_POST,create_function('&amp;$v,$k','$v = stripslashes($v);'));
}

try{

    // Connecting to the database
    DB::init($dbOptions);

    $response = array();

    // Handling the supported actions:

    switch($_GET['action']){

        case 'login':
            $response = Chat::login($_POST['name'],$_POST['email']);
        break;

        case 'checkLogged':
            $response = Chat::checkLogged();
        break;

        case 'logout':
            $response = Chat::logout();
        break;

        case 'submitChat':
            $response = Chat::submitChat($_POST['chatText']);
        break;

        case 'getUsers':
            $response = Chat::getUsers();
        break;

        case 'getChats':
            $response = Chat::getChats($_GET['lastID']);
        break;

        default:
            throw new Exception('Wrong action');
    }

    echo json_encode($response);
}
catch(Exception $e){
    die(json_encode(array('error' =&gt; $e-&gt;getMessage())));
}</pre>
<p>For convenience, I&#8217;ve used a simple switch statement to define the actions, supported by the script. These include chat submission, login/logout functionality, and actions for requesting a list of chats and online users.</p>
<p>All output is in the form of JSON messages (conveniently handled by jQuery), and errors are raised in the form of exceptions. The switch statement routes all requests to the appropriate static method of the Chat class, which we will discuss later in this section.</p>
<h4>DB.class.php</h4>
<pre class="brush:php">class DB {
	private static $instance;
	private $MySQLi;

	private function __construct(array $dbOptions){

		$this-&gt;MySQLi = @ new mysqli(	$dbOptions['db_host'],
										$dbOptions['db_user'],
										$dbOptions['db_pass'],
										$dbOptions['db_name'] );

		if (mysqli_connect_errno()) {
			throw new Exception('Database error.');
		}

		$this-&gt;MySQLi-&gt;set_charset("utf8");
	}

	public static function init(array $dbOptions){
		if(self::$instance instanceof self){
			return false;
		}

		self::$instance = new self($dbOptions);
	}

	public static function getMySQLiObject(){
		return self::$instance-&gt;MySQLi;
	}

	public static function query($q){
		return self::$instance-&gt;MySQLi-&gt;query($q);
	}

	public static function esc($str){
		return self::$instance-&gt;MySQLi-&gt;real_escape_string(htmlspecialchars($str));
	}
}</pre>
<p>The DB class is our database manager. The constructor is private, which means that no objects can be created from the outside, and the initialization is only possible from the <strong>init()</strong> static method. It takes an array with MySQL login details, and creates an instance of the class, held in the <strong>self::$instance</strong> static variable. This way we can be sure that only one connection to the database can exists in the same time.</p>
<p>The rest of the classes take advantage of the static <strong>query()</strong> method to communicate with the database.</p>
<h4>ChatBase.class.php</h4>
<pre class="brush:php">/* This is the base class, used by both ChatLine and ChatUser */

class ChatBase{

    // This constructor is used by all the chat classes:

    public function __construct(array $options){

        foreach($options as $k=&gt;$v){
            if(isset($this-&gt;$k)){
                $this-&gt;$k = $v;
            }
        }
    }
}</pre>
<p>This is a simple base class. It&#8217;s main purpose is to define the constructor, which takes an array with parameters, and saves only the ones that are defined in the class.</p>
<h4>ChatLine.class.php</h4>
<pre class="brush:php">/* Chat line is used for the chat entries */

class ChatLine extends ChatBase{

    protected $text = '', $author = '', $gravatar = '';

    public function save(){
        DB::query("
            INSERT INTO webchat_lines (author, gravatar, text)
            VALUES (
                '".DB::esc($this-&gt;author)."',
                '".DB::esc($this-&gt;gravatar)."',
                '".DB::esc($this-&gt;text)."'
        )");

        // Returns the MySQLi object of the DB class

        return DB::getMySQLiObject();
    }
}</pre>
<p>Here is the ChatLine class. It extends ChatBase, so you can easily create an object of this class by providing an array with a text, author, and gravatar elements. The gravatar property contains a md5 hash of the person&#8217;s email address. This is required so we can fetch the user&#8217;s gravatar from gravatar.com.</p>
<p>This class also defines a save method, which the object to our database. As it returns the <a href="http://php.net/manual/en/class.mysqli.php" target="_blank">MySQLi</a> object, contained in the DB class, you can check whether the save was successful by checking the <strong>affected_rows</strong> property (we will come back to this in the Chat class).</p>
<h4>ChatUser.class.php</h4>
<pre class="brush:php">class ChatUser extends ChatBase{

    protected $name = '', $gravatar = '';

    public function save(){

        DB::query("
            INSERT INTO webchat_users (name, gravatar)
            VALUES (
                '".DB::esc($this-&gt;name)."',
                '".DB::esc($this-&gt;gravatar)."'
        )");

        return DB::getMySQLiObject();
    }

    public function update(){
        DB::query("
            INSERT INTO webchat_users (name, gravatar)
            VALUES (
                '".DB::esc($this-&gt;name)."',
                '".DB::esc($this-&gt;gravatar)."'
            ) ON DUPLICATE KEY UPDATE last_activity = NOW()");
    }
}</pre>
<p>The same is also valid here. We have the name and gravatar properties (notice the protected access modifier &#8211; this means that they will be accessible in the ChatBase class, so we can set them in the constructor).</p>
<p>The difference is that we also have an <strong>update()</strong> method, which updates the <em><strong>last_activity</strong></em> timestamp to the current time. This shows that this person keeps a chat window open and is displayed as online in the users section.</p>
<h4>Chat.class.php &#8211; Part 1</h4>
<pre class="brush:php">/* The Chat class exploses public static methods, used by ajax.php */

class Chat{

    public static function login($name,$email){
        if(!$name || !$email){
            throw new Exception('Fill in all the required fields.');
        }

        if(!filter_input(INPUT_POST,'email',FILTER_VALIDATE_EMAIL)){
            throw new Exception('Your email is invalid.');
        }

        // Preparing the gravatar hash:
        $gravatar = md5(strtolower(trim($email)));

        $user = new ChatUser(array(
            'name'        =&gt; $name,
            'gravatar'    =&gt; $gravatar
        ));

        // The save method returns a MySQLi object
        if($user-&gt;save()-&gt;affected_rows != 1){
            throw new Exception('This nick is in use.');
        }

        $_SESSION['user']    = array(
            'name'        =&gt; $name,
            'gravatar'    =&gt; $gravatar
        );

        return array(
            'status'    =&gt; 1,
            'name'        =&gt; $name,
            'gravatar'    =&gt; Chat::gravatarFromHash($gravatar)
        );
    }

    public static function checkLogged(){
        $response = array('logged' =&gt; false);

        if($_SESSION['user']['name']){
            $response['logged'] = true;
            $response['loggedAs'] = array(
                'name'        =&gt; $_SESSION['user']['name'],
                'gravatar'    =&gt; Chat::gravatarFromHash($_SESSION['user']['gravatar'])
            );
        }

        return $response;
    }

    public static function logout(){
        DB::query("DELETE FROM webchat_users WHERE name = '".DB::esc($_SESSION['user']['name'])."'");

        $_SESSION = array();
        unset($_SESSION);

        return array('status' =&gt; 1);
    }</pre>
<p>This is where all the work gets done. Remember the switch statement in ajax.php above? It maps the supported actions with the corresponding methods from this class. Each of these methods returns an array, as it is later converted to a JSON object with the internal <strong>json_encode()</strong> function (this happens at the bottom of ajax.php).</p>
<p>When the user logs in, their name and gravatar get saved as elements of the $_SESSION array, and become available on consecutive requests. We will be using this to validate that the user is allowed to add chats later on.</p>
<p>You can also see how we are preparing the gravatar hash. This is done according to their <a href="http://en.gravatar.com/site/implement/hash/" target="_blank">best practices guide</a> and ensures that if the person has configured a Gravatar, it will be properly displayed.</p>
<h4>Chat.class.php &#8211; Part 2</h4>
<pre class="brush:php">    public static function submitChat($chatText){
        if(!$_SESSION['user']){
            throw new Exception('You are not logged in');
        }

        if(!$chatText){
            throw new Exception('You haven\' entered a chat message.');
        }

        $chat = new ChatLine(array(
            'author'    =&gt; $_SESSION['user']['name'],
            'gravatar'    =&gt; $_SESSION['user']['gravatar'],
            'text'        =&gt; $chatText
        ));

        // The save method returns a MySQLi object
        $insertID = $chat-&gt;save()-&gt;insert_id;

        return array(
            'status'    =&gt; 1,
            'insertID'    =&gt; $insertID
        );
    }

    public static function getUsers(){
        if($_SESSION['user']['name']){
            $user = new ChatUser(array('name' =&gt; $_SESSION['user']['name']));
            $user-&gt;update();
        }

        // Deleting chats older than 5 minutes and users inactive for 30 seconds

        DB::query("DELETE FROM webchat_lines WHERE ts &lt; SUBTIME(NOW(),'0:5:0')");
        DB::query("DELETE FROM webchat_users WHERE last_activity &lt; SUBTIME(NOW(),'0:0:30')");

        $result = DB::query('SELECT * FROM webchat_users ORDER BY name ASC LIMIT 18');

        $users = array();
        while($user = $result-&gt;fetch_object()){
            $user-&gt;gravatar = Chat::gravatarFromHash($user-&gt;gravatar,30);
            $users[] = $user;
        }

        return array(
            'users' =&gt; $users,
            'total' =&gt; DB::query('SELECT COUNT(*) as cnt FROM webchat_users')-&gt;fetch_object()-&gt;cnt
        );
    }

    public static function getChats($lastID){
        $lastID = (int)$lastID;

        $result = DB::query('SELECT * FROM webchat_lines WHERE id &gt; '.$lastID.' ORDER BY id ASC');

        $chats = array();
        while($chat = $result-&gt;fetch_object()){

            // Returning the GMT (UTC) time of the chat creation:

            $chat-&gt;time = array(
                'hours'        =&gt; gmdate('H',strtotime($chat-&gt;ts)),
                'minutes'    =&gt; gmdate('i',strtotime($chat-&gt;ts))
            );

            $chat-&gt;gravatar = Chat::gravatarFromHash($chat-&gt;gravatar);

            $chats[] = $chat;
        }

        return array('chats' =&gt; $chats);
    }

    public static function gravatarFromHash($hash, $size=23){
        return 'http://www.gravatar.com/avatar/'.$hash.'?size='.$size.'&amp;default='.
                urlencode('http://www.gravatar.com/avatar/ad516503a11cd5ca435acc9bb6523536?size='.$size);
    }
}</pre>
<p>As you will see in the next part of this tutorial, jQuery sends a <em><strong>getUsers()</strong></em> request every 15 seconds. We are using this to delete chats older than 5 minutes and inactive users from the database. We could potentially delete those records in getChats, but that is requested once every second and the extra processing time could severely impact the performance of our app.</p>
<p>Another thing worth noting, is that, in the <strong>getChats()</strong> method, we are using the <strong>gmdate</strong> function to output a GMT time. In the frontend, we use the hour and minute values to feed the JavaScript date object, and as a result all the times are displayed in the user&#8217;s local time.</p>
<p><strong>With this the first part of this tutorial is complete!</strong></p>
<h3>To be continued</h3>
<p>Go to the <a href="http://tutorialzine.com/2010/10/ajax-web-chat-css-jquery/">second part of this tutorial</a>, when we are building the slick jQuery &amp; CSS3 interface and making it all work together.</p>
]]></content:encoded>
			<wfw:commentRss>http://tutorialzine.com/2010/10/ajax-web-chat-php-mysql/feed/</wfw:commentRss>
		<slash:comments>46</slash:comments>
		</item>
		<item>
		<title>Feature Suggest App w/ PHP, MySQL &amp; jQuery</title>
		<link>http://tutorialzine.com/2010/08/ajax-suggest-vote-jquery-php-mysql/</link>
		<comments>http://tutorialzine.com/2010/08/ajax-suggest-vote-jquery-php-mysql/#comments</comments>
		<pubDate>Thu, 19 Aug 2010 16:42:27 +0000</pubDate>
		<dc:creator>Martin Angelov</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://tutorialzine.com/?p=1072</guid>
		<description><![CDATA[<div><a href="http://tutorialzine.com/2010/08/ajax-suggest-vote-jquery-php-mysql/"><img src="http://cdn.tutorialzine.com/img/featured/1072.jpg" /></a></div> In this tutorial we are making a feature suggestion app with PHP, MySQL &#038; jQuery. With it your website visitors can request features, vote and give feedback for your site.]]></description>
			<content:encoded><![CDATA[<div><a href="http://tutorialzine.com/2010/08/ajax-suggest-vote-jquery-php-mysql/"><img src="http://cdn.tutorialzine.com/img/featured/1072.jpg" /></a></div> <p>Listening to what your visitors have to say, is always beneficial when planning new features or changes in your website. For a long time we&#8217;ve been limited to just setting up a contact form and hoping that quality feedback will follow, which unfortunately is not always the case.</p>
<p>Today we are taking things up a notch &#8211; we are applying the same social principles that have brought success to sharing sites such as Digg and delicious, and encourage visitors to suggest and vote on features that they want implemented on your website.</p>
<h3>The XHTML</h3>
<p>Starting with the new HTML5 doctype, we define the opening and closing head  and title tags, and include the main stylesheet of the app &#8211;  <strong>styles.css</strong>, in the document.</p>
<h4>suggestions.php</h4>
<pre class="brush:html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8" /&gt;
&lt;title&gt;Feature Suggest w/ PHP, jQuery &amp; MySQL | Tutorialzine Demo&lt;/title&gt;

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

&lt;/head&gt;

&lt;body&gt;

&lt;div id="page"&gt;

    &lt;div id="heading" class="rounded"&gt;
    	&lt;h1&gt;Feature Suggest&lt;i&gt;for Tutorialzine.com&lt;/i&gt;&lt;/h1&gt;
    &lt;/div&gt;

    &lt;!-- The generated suggestion list comes here --&gt;

    &lt;form id="suggest" action="" method="post"&gt;
        &lt;p&gt;
            &lt;input type="text" id="suggestionText" class="rounded" /&gt;
            &lt;input type="submit" value="Submit" id="submitSuggestion" /&gt;
        &lt;/p&gt;
	&lt;/form&gt;

&lt;/div&gt;

&lt;script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"&gt;&lt;/script&gt;
&lt;script src="script.js"&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>After this comes the body tag and the <strong>#page</strong> div, which is the main container element. It holds the heading, the unordered list with all the suggestions (which is generated by PHP, as you will see in a moment), and the submit form.</p>
<p>Lastly we include the jQuery library from Google&#8217;s AJAX Library CDN, and our own script.js file, which is discussed in detail in the last section of this tutorial.</p>
<div id="attachment_1076" class="wp-caption alignnone" style="width: 630px"><a href="http://demo.tutorialzine.com/2010/08/ajax-suggest-vote-jquery-php-mysql/suggestions.php"><img class="size-full wp-image-1076" title="Feature Suggest App w/ jQuery, PHP, MySQL" src="http://cdn.tutorialzine.com/wp-content/uploads/2010/08/11.png" alt="Feature Suggest App w/ jQuery, PHP, MySQL" width="620" height="460" /></a><p class="wp-caption-text">Feature Suggest App w/ jQuery, PHP, MySQL</p></div>
<h3>The Table Schema</h3>
<p>The app uses two MySQL tables to store data. Suggestions and Suggestions_votes. The first table contains the text of the suggestion and data such as rating and the number of votes the item has received. The second table keeps record of the IPs of the voters and prevents more than one vote to be cast in a single day per IP.</p>
<div id="attachment_1080" class="wp-caption alignnone" style="width: 630px"><img class="size-full wp-image-1080" title="Suggestion Table Schema" src="http://cdn.tutorialzine.com/wp-content/uploads/2010/08/i4.png" alt="Suggestion Table Schema" width="620" height="260" /><p class="wp-caption-text">Suggestion Table Schema</p></div>
<p>To speed up the selection queries, an index is defined on the <strong>rating </strong>field. This helps when showing the suggestions ordered by popularity.</p>
<p>The suggestion votes table has a primary key consisting of three fields &#8211; the <strong>suggestion_id</strong>, the<strong> IP</strong> of the voter, and the <strong>date </strong>of the vote. And because primary keys do not allow for duplicate rows, we can be sure that users can vote only once per day by just checking the value of the affected_rows variable after the insert.</p>
<div id="attachment_1082" class="wp-caption alignnone" style="width: 630px"><img class="size-full wp-image-1082" title="Suggestions_Votes Schema" src="http://cdn.tutorialzine.com/wp-content/uploads/2010/08/i3.png" alt="Suggestions_Votes Schema" width="620" height="260" /><p class="wp-caption-text">Suggestions_Votes Schema</p></div>
<h3>The PHP</h3>
<p>Before delving into the generation of the suggestion items and the AJAX interactions, first we have to take a look at the suggestion PHP class. It uses two <a href="http://php.net/manual/en/language.oop5.magic.php" target="_blank">PHP magic methods </a>(apart  from the constructor) to provide rich functionality to our code. When  generating the front page, PHP runs a MySQL select query against the  database, and creates an object of this class for every table row. The  columns of the row are added as properties to the object.</p>
<h4>suggestion.class.php</h4>
<pre class="brush:php">class Suggestion
{
	private $data = array();

	public function __construct($arr = array())
	{
		if(!empty($arr)){

			// The $arr array is passed only when we manually
			// create an object of this class in ajax.php

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

	public function __get($property){

		// This is a magic method that is called if we
		// access a property that does not exist.

		if(array_key_exists($property,$this-&gt;data)){
			return $this-&gt;data[$property];
		}

		return NULL;
	}

	public function __toString()
	{
		// This is a magic method which is called when
		// converting the object to string:

		return '
		&lt;li id="s'.$this-&gt;id.'"&gt;
			&lt;div class="vote '.($this-&gt;have_voted ? 'inactive' : 'active').'"&gt;
				&lt;span class="up"&gt;&lt;/span&gt;
				&lt;span class="down"&gt;&lt;/span&gt;
			&lt;/div&gt;

			&lt;div class="text"&gt;'.$this-&gt;suggestion.'&lt;/div&gt;
			&lt;div class="rating"&gt;'.(int)$this-&gt;rating.'&lt;/div&gt;
		&lt;/li&gt;';
	}
}
</pre>
<p>The <strong>__toString()</strong> method is used to create a string representation of the object. With its help we can build the HTML markup, complete with the suggestion title and number of votes.</p>
<p>The <strong>__get()</strong> method is used to route the access to undefined properties of the class to the <strong>$data</strong> array. This means that if we access <strong>$obj-&gt;suggestion</strong>, and this property is undefined, it is going to be fetched from the $data array, and returned to us as if it existed. This way we can just pass an array to the constructor, instead of setting up all the properties. We are using this when creating an object in <strong>ajax.php</strong>.</p>
<p>Now lets proceed with the generation of the unordered list on the front page.</p>
<h4>suggestions.php</h4>
<pre class="brush:php">require "connect.php";
require "suggestion.class.php";

// Converting the IP to a number. This is a more effective way
// to store it in the database:

$ip	= sprintf('%u',ip2long($_SERVER['REMOTE_ADDR']));

// The following query uses a left join to select
// all the suggestions and in the same time determine
// whether the user has voted on them.

$result = $mysqli-&gt;query("
	SELECT s.*, if (v.ip IS NULL,0,1) AS have_voted
	FROM suggestions AS s
	LEFT JOIN suggestions_votes AS v
	ON(
		s.id = v.suggestion_id
		AND v.day = CURRENT_DATE
		AND v.ip = $ip
	)
	ORDER BY s.rating DESC, s.id DESC
");

$str = '';

if(!$mysqli-&gt;error)
{
	// Generating the UL

	$str = '&lt;ul class="suggestions"&gt;';

	// Using MySQLi's fetch_object method to create a new
	// object and populate it with the columns of the result query:

	while($suggestion = $result-&gt;fetch_object('Suggestion')){

		$str.= $suggestion;	// Uses the __toString() magic method.

	}

	$str .='&lt;/ul&gt;';
}</pre>
<p>After running the query, we use the <strong>fetch_object()</strong> method of the <strong>$result</strong> object. This method creates an object of the given class for every row in the result, and assigns the columns of that row to the object as public properties.</p>
<p>PHP also manages the AJAX requests sent by jQuery. This is done in <strong>ajax.php</strong>. To distinguish one AJAX action from another, the script takes a <strong>$_GET['action']</strong> parameter, which can have one of two values &#8211; &#8216;<strong>vote</strong>&#8216; or &#8216;<strong>submit</strong>&#8216;.</p>
<h4>ajax.php</h4>
<pre class="brush:php">require "connect.php";
require "suggestion.class.php";

// If the request did not come from AJAX, exit:
if($_SERVER['HTTP_X_REQUESTED_WITH'] !='XMLHttpRequest'){
	exit;
}

// Converting the IP to a number. This is a more effective way
// to store it in the database:

$ip	= sprintf('%u',ip2long($_SERVER['REMOTE_ADDR']));

if($_GET['action'] == 'vote'){

	$v = (int)$_GET['vote'];
	$id = (int)$_GET['id'];

	if($v != -1 &amp;&amp; $v != 1){
		exit;
	}

	// Checking to see whether such a suggest item id exists:
	if(!$mysqli-&gt;query("SELECT 1 FROM suggestions WHERE id = $id")-&gt;num_rows){
		exit;
	}

	// The id, ip and day fields are set as a primary key.
	// The query will fail if we try to insert a duplicate key,
	// which means that a visitor can vote only once per day.

	$mysqli-&gt;query("
		INSERT INTO suggestions_votes (suggestion_id,ip,day,vote)
		VALUES (
			$id,
			$ip,
			CURRENT_DATE,
			$v
		)
	");

	if($mysqli-&gt;affected_rows == 1)
	{
		$mysqli-&gt;query("
			UPDATE suggestions SET
				".($v == 1 ? 'votes_up = votes_up + 1' : 'votes_down = votes_down + 1').",
				rating = rating + $v
			WHERE id = $id
		");
	}

}
else if($_GET['action'] == 'submit'){

	// Stripping the content
	$_GET['content'] = htmlspecialchars(strip_tags($_GET['content']));

	if(mb_strlen($_GET['content'],'utf-8')&lt;3){
		exit;
	}

	$mysqli-&gt;query("INSERT INTO suggestions SET suggestion = '".$mysqli-&gt;real_escape_string($_GET['content'])."'");

	// Outputting the HTML of the newly created suggestion in a JSON format.
	// We are using (string) to trigger the magic __toString() method.

	echo json_encode(array(
		'html'	=&gt; (string)(new Suggestion(array(
			'id'			=&gt; $mysqli-&gt;insert_id,
			'suggestion'	=&gt; $_GET['content']
		)))
	));
}
</pre>
<p>When jQuery fires the &#8216;<strong>vote</strong>&#8216; request, it does not expect any return values, so the script does not output any. In the &#8216;<strong>submit</strong>&#8216; action, however, jQuery expects a JSON object to be returned, containing the HTML markup of the suggestion that was just inserted. This is where we create a new <strong>Suggestion</strong> object for the sole purpose of using its <strong>__toString()</strong> magic method and converting it with the inbuilt <strong>json_encode()</strong> function.</p>
<div id="attachment_1077" class="wp-caption alignnone" style="width: 630px"><a href="http://demo.tutorialzine.com/2010/08/ajax-suggest-vote-jquery-php-mysql/suggestions.php"><img class="size-full wp-image-1077" title="Suggest &amp; Vote on Features" src="http://cdn.tutorialzine.com/wp-content/uploads/2010/08/2.png" alt="Suggest &amp; Vote on Features" width="620" height="260" /></a><p class="wp-caption-text">Suggest &amp; Vote on Features</p></div>
<h3>The jQuery</h3>
<p>All of the jQuery code resides in <strong>script.js</strong>. It listens for click events on the green and red arrows. But as  suggestions can be inserted at any point, we are using the <strong>live()</strong> jQuery method, so we can listen for the event even on elements that are not yet created.</p>
<h4>script.js</h4>
<pre class="brush:js">$(document).ready(function(){

	var ul = $('ul.suggestions');

	// Listening of a click on a UP or DOWN arrow:

	$('div.vote span').live('click',function(){

		var elem		= $(this),
			parent		= elem.parent(),
			li			= elem.closest('li'),
			ratingDiv	= li.find('.rating'),
			id			= li.attr('id').replace('s',''),
			v			= 1;

		// If the user's already voted:

		if(parent.hasClass('inactive')){
			return false;
		}

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

		if(elem.hasClass('down')){
			v = -1;
		}

		// Incrementing the counter on the right:
		ratingDiv.text(v + +ratingDiv.text());

		// Turning all the LI elements into an array
		// and sorting it on the number of votes:

		var arr = $.makeArray(ul.find('li')).sort(function(l,r){
			return +$('.rating',r).text() - +$('.rating',l).text();
		});

		// Adding the sorted LIs to the UL
		ul.html(arr);

		// Sending an AJAX request
		$.get('ajax.php',{action:'vote',vote:v,'id':id});
	});

	$('#suggest').submit(function(){

		var form		= $(this),
			textField	= $('#suggestionText');

		// Preventing double submits:
		if(form.hasClass('working') || textField.val().length&lt;3){
			return false;
		}

		form.addClass('working');

		$.getJSON('ajax.php',{action:'submit',content:textField.val()},function(msg){
			textField.val('');
			form.removeClass('working');

			if(msg.html){
				// Appending the markup of the newly created LI to the page:
				$(msg.html).hide().appendTo(ul).slideDown();
			}
		});

		return false;
	});
});</pre>
<p>When a click on one of those arrows occurs, jQuery determines whether the &#8216;inactive&#8217; class is present on the LI element. This class is only assigned to the suggestion, if the user has voted during the last day, and, if present, the script will ignore any click events.</p>
<p>Notice how <strong>$.makeArray</strong> is used to turn the jQuery objects, containing the LI elements, into a true array. This is done, so we can use the <strong>array.sort()</strong> method and pass it a custom sort function, which takes two LIs at the same time and outputs a negative integer, zero or a positive integer depending on which of the two elements has a grater rating. This array is later inserted into the unordered list.</p>
<h3>The CSS</h3>
<p>Now that we have all the markup generated, we can move on with the styling. As the styling is pretty much trivial, I only want to show you the class that rounds the top-left and bottom-right corners of the elements that it is applied to. You can see the rest of the CSS rules in styles.css.</p>
<h4>styles.css</h4>
<pre class="brush:css">.rounded,
#suggest,
.suggestions li{
	-moz-border-radius-topleft:12px;
	-moz-border-radius-bottomright:12px;

	-webkit-border-top-left-radius:12px;
	-webkit-border-bottom-right-radius:12px;

	border-top-left-radius:12px;
	border-bottom-right-radius:12px;
}</pre>
<p>Notice that the Mozilla syntax differs from the standard in the way it targets the different corners of the element. Keeping that in mind, we can apply this class to pretty much every element, as you can see from the demonstration.</p>
<p><strong>With this our Feature Suggest App is complete!</strong></p>
<h3>Conclusion</h3>
<p>If you plan to set up this script on your own server, you would need to create the two suggestion tables by running the code found in <strong>tables.sql</strong> in the SQL tab of phpMyAdmin. Also remember to fill in your database connection details in <strong>connect.php</strong>.</p>
<p>You can use this script to gather precious feedback from your visitors. You can also disable the option for users to add new suggestions, and use it as a kind of an advanced poll system.</p>
<p>Be sure to share your thoughts in your comment section below.</p>
]]></content:encoded>
			<wfw:commentRss>http://tutorialzine.com/2010/08/ajax-suggest-vote-jquery-php-mysql/feed/</wfw:commentRss>
		<slash:comments>23</slash:comments>
		</item>
		<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[jQuery]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://tutorialzine.com/?p=1036</guid>
		<description><![CDATA[<div><a href="http://tutorialzine.com/2010/07/click-to-appreciate-badge-ajax-jquery-css/"><img src="http://cdn.tutorialzine.com/img/featured/1036.jpg" /></a></div> 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[<div><a href="http://tutorialzine.com/2010/07/click-to-appreciate-badge-ajax-jquery-css/"><img src="http://cdn.tutorialzine.com/img/featured/1036.jpg" /></a></div> <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://cdn.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://cdn.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://cdn.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://cdn.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>26</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[jQuery]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://tutorialzine.com/?p=990</guid>
		<description><![CDATA[<div><a href="http://tutorialzine.com/2010/06/simple-ajax-commenting-system/"><img src="http://cdn.tutorialzine.com/img/featured/990.jpg" /></a></div> 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[<div><a href="http://tutorialzine.com/2010/06/simple-ajax-commenting-system/"><img src="http://cdn.tutorialzine.com/img/featured/990.jpg" /></a></div> <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://cdn.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"]).
				'http://cdn.tutorialzine.com/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://cdn.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>82</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[<div><a href="http://tutorialzine.com/2010/05/donation-center-php-mysql-paypal-api/"><img src="http://cdn.tutorialzine.com/img/featured/891.jpg" /></a></div> 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[<div><a href="http://tutorialzine.com/2010/05/donation-center-php-mysql-paypal-api/"><img src="http://cdn.tutorialzine.com/img/featured/891.jpg" /></a></div> <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://cdn.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://cdn.tutorialzine.com/wp-content/uploads/2010/05/i5.png"><img class="size-full wp-image-900" title="Table Schema for dc_donations" src="http://cdn.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://cdn.tutorialzine.com/wp-content/uploads/2010/05/i4.png"><img class="size-full wp-image-901" title="Table Schema for dc_comments" src="http://cdn.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://cdn.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://cdn.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>34</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[jQuery]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://tutorialzine.com/?p=867</guid>
		<description><![CDATA[<div><a href="http://tutorialzine.com/2010/04/simple-banner-rotator-with-php-jquery-mysql/"><img src="http://cdn.tutorialzine.com/img/featured/867.jpg" /></a></div> 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[<div><a href="http://tutorialzine.com/2010/04/simple-banner-rotator-with-php-jquery-mysql/"><img src="http://cdn.tutorialzine.com/img/featured/867.jpg" /></a></div> <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://cdn.tutorialzine.com/wp-content/uploads/2010/04/i13.png"><img class="size-full wp-image-871" title="The Database Schema" src="http://cdn.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://cdn.tutorialzine.com/wp-content/uploads/2010/04/i41.png"><img class="size-full wp-image-872" title="The jQuery Animation" src="http://cdn.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://cdn.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://cdn.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>30</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[<div><a href="http://tutorialzine.com/2010/04/simple-bookmarking-app-php-javascript-mysql/"><img src="http://cdn.tutorialzine.com/img/featured/842.jpg" /></a></div> 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[<div><a href="http://tutorialzine.com/2010/04/simple-bookmarking-app-php-javascript-mysql/"><img src="http://cdn.tutorialzine.com/img/featured/842.jpg" /></a></div> <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://cdn.tutorialzine.com/wp-content/uploads/2010/04/i31.png"><img class="size-full wp-image-851" title="The Idea" src="http://cdn.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://cdn.tutorialzine.com/wp-content/uploads/2010/04/i12.png"><img class="size-full wp-image-848" title="Database Schema" src="http://cdn.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://cdn.tutorialzine.com/wp-content/uploads/2010/04/i21.png"><img class="size-full wp-image-849" title="The Bookmark Widget" src="http://cdn.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>34</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[jQuery]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://tutorialzine.com/?p=807</guid>
		<description><![CDATA[<div><a href="http://tutorialzine.com/2010/03/ajax-todo-list-jquery-php-mysql-css/"><img src="http://cdn.tutorialzine.com/img/featured/807.jpg" /></a></div> 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[<div><a href="http://tutorialzine.com/2010/03/ajax-todo-list-jquery-php-mysql-css/"><img src="http://cdn.tutorialzine.com/img/featured/807.jpg" /></a></div> <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://cdn.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://cdn.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://cdn.tutorialzine.com/wp-content/uploads/2010/03/i13.png"><img class="size-full wp-image-811" title="Database Schema" src="http://cdn.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://cdn.tutorialzine.com/wp-content/uploads/2010/03/i33.png"><img class="size-full wp-image-812" title="jQuery UI Dialog Box" src="http://cdn.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>51</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using apc
Page Caching using apc
Object Caching 722/789 objects using apc
Content Delivery Network via cdn.tutorialzine.com

Served from: tutorialzine.com @ 2012-02-03 22:04:58 -->
