<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Anant Garg | on web development</title>
	
	<link>http://anantgarg.com</link>
	<description>on web development</description>
	<pubDate>Thu, 18 Feb 2010 12:20:49 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.7.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/anantgarg" /><feedburner:info uri="anantgarg" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId>anantgarg</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><item>
		<title>Cross-domain cookies/sessions in Safari and all other browsers</title>
		<link>http://feedproxy.google.com/~r/anantgarg/~3/QTb4FOnkAgg/</link>
		<comments>http://anantgarg.com/2010/02/18/cross-domain-cookies-in-safari/#comments</comments>
		<pubDate>Thu, 18 Feb 2010 12:20:49 +0000</pubDate>
		<dc:creator>Anant Garg</dc:creator>
		
		<category><![CDATA[Javascript]]></category>

		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://anantgarg.com/?p=336</guid>
		<description><![CDATA[Safari does not allow cross-domain cookies. In other words, if on X.com, you load an iFrame with contents of Y.com and set a cookie in the iFrame, Safari will not save the cookie. This post contains a possible solution to this problem.]]></description>
			<content:encoded><![CDATA[<script type="text/javascript">dzone_url = "http://anantgarg.com/2010/02/18/cross-domain-cookies-in-safari/";</script><p><strong>The Problem</strong></p>
<p>Safari does not allow cross-domain cookies. In other words, if on X.com, you load an iFrame with contents of Y.com and set a cookie in the iFrame, Safari will not save the cookie. This problem also occurs in IE6/7 but can be resolved by sending a P3P header. </p>
<p><strong>The Solution</strong></p>
<p>I am not entirely sure why this works, but the cookie gets saved if a post is made to the iFrame. This solution relies of jQuery but can be adapted to any other.</p>
<p>Here is the code that goes on the remote domain:</p>
<pre class="brush: php">
&lt;script src=&quot;http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
&lt;script&gt;
var isSafari = (/Safari/.test(navigator.userAgent));
var firstTimeSession = 0;

function submitSessionForm() {
	if (firstTimeSession == 0) {
		firstTimeSession = 1;
		$(&quot;#sessionform&quot;).submit();
		setTimeout(processApplication(),2000);
  	}
}

if (isSafari) {
	$(&quot;body&quot;).append(&#039;&lt;iframe id=&quot;sessionframe&quot; name=&quot;sessionframe&quot; onload=&quot;submitSessionForm()&quot; src=&quot;http://www.yourdomain.com/blank.php&quot; style=&quot;display:none;&quot;&gt;&lt;/iframe&gt;&lt;form id=&quot;sessionform&quot; enctype=&quot;application/x-www-form-urlencoded&quot; action=&quot;http://www.yourdomain.com/startsession.php&quot; target=&quot;sessionframe&quot; action=&quot;post&quot;&gt;&lt;/form&gt;&#039;);
} else {
	processApplication();
}

function processApplication() {
	alert(&#039;Session has been set. Now you can start your application!&#039;);
}
&lt;/script&gt;
</pre>
<p>The contents for startsession.php would be as simple as:</p>
<pre class="brush: php">
&lt;?php
header(&#039;P3P: CP=&quot;IDC DSP COR CURa ADMa OUR IND PHY ONL COM STA&quot;&#039;);
session_start();
</pre>
<p>To make sure that your site is compatible with IE6/7, always output the following header:</p>
<pre class="brush: php">
&lt;?php
header(&#039;P3P: CP=&quot;IDC DSP COR CURa ADMa OUR IND PHY ONL COM STA&quot;&#039;);
</pre>
<p>Unfortunately, there is no way to find out when the browser has completed submitting the form. Thus, I have placed a delay of 2 seconds. This form needs to be submitted only once per user session. Then you can set your session data in PHP and it will be picked up by your remote domain. You can adapt the same example if you want to set cookies instead of starting a PHP session.</p>
<p><strong>Comments/Suggestions?</strong><br />
Do let me know your suggestions on how we can improve this code.</p>
<p><strong>Spread The Word</strong><br />
If you like what you are reading, then please help spread the word by re-tweeting, blogging or using the ShareThis button below. Thank you.</p>
<img src="http://feeds.feedburner.com/~r/anantgarg/~4/QTb4FOnkAgg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://anantgarg.com/2010/02/18/cross-domain-cookies-in-safari/feed/</wfw:commentRss>
		<feedburner:origLink>http://anantgarg.com/2010/02/18/cross-domain-cookies-in-safari/</feedburner:origLink></item>
		<item>
		<title>SQLBuddyLite - phpMyAdmin alternative</title>
		<link>http://feedproxy.google.com/~r/anantgarg/~3/PfZUj-eViDs/</link>
		<comments>http://anantgarg.com/2009/12/11/sqlbuddylite-phpmyadmin-alternative/#comments</comments>
		<pubDate>Fri, 11 Dec 2009 09:54:15 +0000</pubDate>
		<dc:creator>Anant Garg</dc:creator>
		
		<category><![CDATA[PHP]]></category>

		<category><![CDATA[mySQL]]></category>

		<guid isPermaLink="false">http://anantgarg.com/?p=325</guid>
		<description><![CDATA[SQLBuddyLite is a lighter version of the excellent SQLBuddy available from http://www.sqlbuddy.com. It combines the entire package into only 4 files.]]></description>
			<content:encoded><![CDATA[<script type="text/javascript">dzone_url = "http://anantgarg.com/2009/12/11/sqlbuddylite-phpmyadmin-alternative/";</script><p>SQLBuddyLite is a lighter version of the excellent SQLBuddy available from http://www.sqlbuddy.com</p>
<p>The lite version is an exact copy of the original version but all the files have been combined into only 4 files.</p>
<p><strong>Acknowledgments</strong></p>
<p>SQLBuddyLite is a lighter version of <a href="http://www.sqlbuddy.com">SQLBuddy</a> by Calvin Lough</p>
<p><strong>Why do you need a lite version?</strong></p>
<p>A typical situation is where you have limited access to the user&#8217;s site say only FTP access and you need to verify the database structures. The easiest way to tackle the problem is to upload SQLBuddy and view the data structures.</p>
<p>The lite version makes it quicker to upload files. The lite version does not compromise on the functions; it only reduces the files drastically to only 4 files, thus speeding up remote site management.</p>
<p>Only English language is supported in the latest release.</p>
<p><strong>Demonstration</strong></p>
<p>For security reasons, there is no demonstration version available.</p>
<p><strong>Screenshot</strong></p>
<p><a href="http://anantgarg.com/wp-content/uploads/2009/12/sqlbuddy.jpg" rel="shadowbox[post-325];player=img;"><img src="http://anantgarg.com/wp-content/uploads/2009/12/sqlbuddy-300x156.jpg" alt="sqlbuddy" title="sqlbuddy" width="300" height="156" class="alignnone size-medium wp-image-326" /></a></p>
<p><strong>Requirements</strong></p>
<p>1. PHP<br />
2. mySQL<br />
3. Apache mod-rewrite</p>
<p><strong>Getting Started</strong></p>
<p>Download and upload all the sqlbuddylite folder to your server</p>
<p><strong>Download</strong></p>
<p><a href="http://code.google.com/p/sqlbuddylite/">SQLBuddyLite is hosted on Google Code</a><br />
<a href="http://sqlbuddylite.googlecode.com/files/sqlbuddylite%201.1.zip">Direct download link for SQLBuddyLite</a></p>
<p><strong>License</strong></p>
<p>MIT-style license</p>
<p><strong>Comments/Suggestions?</strong></p>
<p>Do let me know your suggestions on how we can improve this code or any other features you would like to add.</p>
<p><strong>Spread The Word</strong></p>
<p>If you like what you are reading, then please help spread the word by re-tweeting, blogging or using the ShareThis button below. Thank you.</p>
<img src="http://feeds.feedburner.com/~r/anantgarg/~4/PfZUj-eViDs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://anantgarg.com/2009/12/11/sqlbuddylite-phpmyadmin-alternative/feed/</wfw:commentRss>
		<feedburner:origLink>http://anantgarg.com/2009/12/11/sqlbuddylite-phpmyadmin-alternative/</feedburner:origLink></item>
		<item>
		<title>PHP StackOverflow Clone</title>
		<link>http://feedproxy.google.com/~r/anantgarg/~3/wBEs53X3FKA/</link>
		<comments>http://anantgarg.com/2009/12/09/php-stackoverflow-clone/#comments</comments>
		<pubDate>Wed, 09 Dec 2009 09:37:01 +0000</pubDate>
		<dc:creator>Anant Garg</dc:creator>
		
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://anantgarg.com/?p=317</guid>
		<description><![CDATA[A PHP/mySQL based Stack Overflow clone. Features point system, beautiful CSS layout and many unique features.]]></description>
			<content:encoded><![CDATA[<script type="text/javascript">dzone_url = "http://anantgarg.com/2009/12/09/php-stackoverflow-clone/";</script><p>Qwench is a PHP/mySQL based StackOverflow clone.  </p>
<p><strong>Features</strong><br />
1. Allow users to post questions and answers<br />
2. Points system similar to StackOverflow<br />
3. Ability to post an article as a knowledge-base (for corporates)<br />
4. Ability to lock site to registered users only<br />
5. Clean CSS layout<br />
6. Works in all major browsers</p>
<p><strong>Demonstration</strong><br />
<a href="/qwench" target="_blank">Launch Qwench - StackOverflow Clone Demo</a></p>
<p><strong>Screenshot</strong></p>
<p><a href="http://anantgarg.com/wp-content/uploads/2009/12/qwench.jpg" rel="shadowbox[post-317];player=img;"><img src="http://anantgarg.com/wp-content/uploads/2009/12/qwench-300x144.jpg" alt="Qwench StackOverflow Clone" title="Qwench StackOverflow Clone" width="300" height="144" class="alignnone size-medium wp-image-318" /></a></p>
<p><strong>Requirements</strong><br />
1. PHP 4+<br />
2. mySQL</p>
<p><strong>Getting Started</strong><br />
Download and follow the instructions in README.txt file</p>
<p><strong>Download</strong><br />
<a href="http://github.com/anantgarg/Qwench">Qwench is hosted at GitHub</a></p>
<p><strong>License</strong><br />
Qwench licence can be found in the LICENSE.txt file.</p>
<p><strong>Comments/Suggestions?</strong><br />
Do let me know your suggestions on how we can improve this code or any other features you would like to add.</p>
<p><strong>Spread The Word</strong><br />
If you like what you are reading, then please help spread the word by re-tweeting, blogging or using the ShareThis button below. Thank you.</p>
<img src="http://feeds.feedburner.com/~r/anantgarg/~4/wBEs53X3FKA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://anantgarg.com/2009/12/09/php-stackoverflow-clone/feed/</wfw:commentRss>
		<feedburner:origLink>http://anantgarg.com/2009/12/09/php-stackoverflow-clone/</feedburner:origLink></item>
		<item>
		<title>jQuery Fancy Gestures</title>
		<link>http://feedproxy.google.com/~r/anantgarg/~3/qYEQ3cq_35c/</link>
		<comments>http://anantgarg.com/2009/05/21/jquery-fancy-gestures/#comments</comments>
		<pubDate>Thu, 21 May 2009 16:26:31 +0000</pubDate>
		<dc:creator>Anant Garg</dc:creator>
		
		<category><![CDATA[Javascript]]></category>

		<guid isPermaLink="false">http://anantgarg.com/?p=296</guid>
		<description><![CDATA[Enable complex mouse gestures (letters, alphabets, symbols and your own custom gestures) on your website.]]></description>
			<content:encoded><![CDATA[<script type="text/javascript">dzone_url = "http://anantgarg.com/2009/05/21/jquery-fancy-gestures/";</script><p>Enable complex mouse gestures (letters, alphabets, symbols and your own custom gestures) on your website!</p>
<p><strong>Features</strong><br />
1. Create your own custom gestures<br />
2. Create multiple areas where you can accept gestures<br />
3. Visual feedback<br />
4. Works in all major browsers</p>
<p><strong>Acknowledgment</strong><br />
This script is a port of the <a href="http://www.bytearray.org/?p=91">mouse gesture recognition action script</a> by Didier Brun.</p>
<p><strong>Demonstration</strong><br />
<a href="/fancygestures" target="_blank">Launch Fancy Gestures Demo</a></p>
<p><strong>Screenshot</strong></p>
<p><a href="http://anantgarg.com/wp-content/uploads/2009/05/screenshot.jpg" rel="shadowbox[post-296];player=img;"><img style="border:1px solid #666666" src="http://anantgarg.com/wp-content/uploads/2009/05/screenshot-300x165.jpg" alt="jQuery Fancy Gestures Screenshot" title="jQuery Fancy Gestures Screenshot" width="300" height="165" class="alignnone size-medium wp-image-302" /></a></p>
<p><strong>Requirements</strong><br />
1. <a href="http://www.jquery.com">jQuery</a><br />
2. <a href="http://www.walterzorn.com/jsgraphics/jsgraphics_e.htm#download">Walter Zorn&#8217;s VectorGraphics Library</a></p>
<p><strong>Getting Started</strong></p>
<p>Create a new html file with the following code. The function will return data i.e. the recognized character/symbol/name:</p>
<pre class="brush: php">
&lt;div id=&quot;sample&quot; style=&quot;border:1px solid black;position:relative;height:150px;width:150px;&quot;&gt;&lt;/div&gt;

&lt;script type=&quot;text/javascript&quot; src=&quot;wz_jsgraphics.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;jquery.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;jquery.fancygestures.js&quot;&gt;&lt;/script&gt;

&lt;script&gt;

$(document).ready(function () {
	$(&#039;#sample&#039;).fancygestures(function (data) {
		alert(data);
	});
});

&lt;/script&gt;
</pre>
<p><strong>Customization</strong></p>
<p>Please use the key below to generate a string of numbers for your gesture: e.g. L will be something like 2 then 0. The following letters are already mapped into the script:</p>
<p><img src="http://anantgarg.com/wp-content/uploads/2009/05/fancygestures.gif" alt="Fancy Gestures Customization" title="Fancy Gestures Customization" width="537" height="152" class="alignnone size-full wp-image-297" /></p>
<p>Suppose you want to add a &#8220;CIRCLE&#8221; symbol with the sequence &#8220;432107654&#8243;, then simply edit jquery.fancygestures.js and add the following after line 7:</p>
<pre class="brush: php">
     gestures[&quot;CIRCLE&quot;] = &quot;432107654&quot;;
</pre>
<p>The above code will return &#8220;CIRCLE&#8221; as data in the function when you make a circle. However, make sure you do not have similar gestures, or you will get unpredictable results e.g. having same gesture for zero and letter O.</p>
<p><strong>Download</strong><br />
<a href="/fancygestures.zip">Download Fancy Gestures</a></p>
<p><strong>License</strong><br />
Fancy Gestures is licensed under MIT license. Let me know if you make any interesting use of the script.</p>
<p><strong>Comments/Suggestions?</strong><br />
Do let me know your suggestions on how we can improve this code or any other features you would like to add.</p>
<p><strong>Spread The Word</strong><br />
If you like what you are reading, then please help spread the word by re-tweeting, blogging or using the ShareThis button below. Thank you.</p>
<img src="http://feeds.feedburner.com/~r/anantgarg/~4/qYEQ3cq_35c" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://anantgarg.com/2009/05/21/jquery-fancy-gestures/feed/</wfw:commentRss>
		<feedburner:origLink>http://anantgarg.com/2009/05/21/jquery-fancy-gestures/</feedburner:origLink></item>
		<item>
		<title>Collabtweet - Multiple Users, Single Twitter Account</title>
		<link>http://feedproxy.google.com/~r/anantgarg/~3/1R99mgS-IM0/</link>
		<comments>http://anantgarg.com/2009/05/20/collabtweet-multiple-users-single-twitter-account/#comments</comments>
		<pubDate>Wed, 20 May 2009 14:18:53 +0000</pubDate>
		<dc:creator>Anant Garg</dc:creator>
		
		<category><![CDATA[PHP]]></category>

		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://anantgarg.com/?p=273</guid>
		<description><![CDATA[Enable multiple users to post to a single collaborative twitter account.]]></description>
			<content:encoded><![CDATA[<script type="text/javascript">dzone_url = "http://anantgarg.com/2009/05/20/collabtweet-multiple-users-single-twitter-account/";</script><p>Enable multiple users to post to a single collaborative twitter account. </p>
<p><b>Why would you need such a program?</b><br />
1. You run a small company/group which you would like twitter users to follow<br />
2. You would like twitter users to follow a single brand (twitter account) and not separate multiple users<br />
3. You would like a simple <em>slick</em> interface to enable your users to post to your collaborative twitter account<br />
4. You would like to hide your real twitter account password from your users<br />
5. You would like to automatically add &#8220;-username&#8221; to all tweets by a user<br />
6. You would like to host this service on your own server</p>
<p><b>Demonstration</b><br />
Please login with one of the following username/password combination:<br />
johndoe/johndoe<br />
janedoe/janedoe<br />
babydoe/babydoe</p>
<p><a href="/collabtweet/collabtweet.php" target="_blank">Click here to launch Collabtweet demo</a></p>
<p>For demonstration purposes, I am using a dummy twitter account- <a href="http://www.twitter.com/collabtweet" target="_blank">http://www.twitter.com/collabtweet</a></p>
<p><b>Screenshots</b></p>
<table style="border:0;margin:0;background-color:white" border=0 bgcolor="white" >
<tr>
<td style="background-color:white"><a href="http://anantgarg.com/wp-content/uploads/2009/05/collabtweet-screen-1.jpg" rel="shadowbox[post-273];player=img;"><img style="border:1px solid black" src="http://anantgarg.com/wp-content/uploads/2009/05/collabtweet-screen-1-300x218.jpg" alt="Collabtweet Login Screen" title="Collabtweet Login Screen" width="300" height="218" class="alignnone size-medium wp-image-274" /></a></td>
<td style="background-color:white">
<a href="http://anantgarg.com/wp-content/uploads/2009/05/collabtweet-screen-2.jpg" rel="shadowbox[post-273];player=img;"><img style="border:1px solid black" src="http://anantgarg.com/wp-content/uploads/2009/05/collabtweet-screen-2-300x215.jpg" alt="Collabtweet Tweet Screen" title="Collabtweet Tweet Screen" width="300" height="215" class="alignnone size-medium wp-image-275" /></a>
</td>
</tr>
<tr>
<td style="background-color:white">
<a href="http://anantgarg.com/wp-content/uploads/2009/05/collabtweet-screen-3.jpg" rel="shadowbox[post-273];player=img;"><img style="border:1px solid black" src="http://anantgarg.com/wp-content/uploads/2009/05/collabtweet-screen-3-300x168.jpg" alt="Collabtweet Tweeted!" title="Collabtweet Tweeted!" width="300" height="168" class="alignnone size-medium wp-image-276" /></a>
</td>
<td style="background-color:white">
<a href="http://anantgarg.com/wp-content/uploads/2009/05/collabtweet-screen-4.jpg" rel="shadowbox[post-273];player=img;"><img style="border:1px solid black" src="http://anantgarg.com/wp-content/uploads/2009/05/collabtweet-screen-4-300x181.jpg" alt="Twitter Outcome!" title="Twitter Outcome!" width="300" height="181" class="alignnone size-medium wp-image-277" /></a>
</td>
</tr>
</table>
<p><b>Download</b><br />
<a href="/collabtweet.zip">Collabtweet - Multiple Users, Single Twitter Account</a></p>
<p><b>Requirements</b><br />
Web server capable of running PHP</p>
<p><b>Configuration</b><br />
Simple edit config.php and modify the users which can access your account and your twitter username and password.</p>
<pre class="brush: php">
&lt;?php

// Username =&gt; Password
// Username will be used as nickname
$users = array(
&quot;USER1&quot; =&gt; &quot;PASS1&quot;,
&quot;USER2&quot; =&gt; &quot;PASS2&quot;,
&quot;USER3&quot; =&gt; &quot;PASS3&quot;
);

$twitterUser = &quot;YOURTWITTERUSERNAME&quot;;
$twitterPass = &quot;YOURTWITTERPASSWORD&quot;;
</pre>
<p><b>Future Updates</b><br />
1. Ability to manage users using a web interface</p>
<p><b>Comments/Suggestions?</b><br />
Do let me know your suggestions on how we can improve this code or any other features you would like to add.</p>
<p><b>Spread The Word</b><br />
If you like what you are reading, then please help spread the word by re-tweeting, blogging or using the ShareThis button below. Thank you.</p>
<img src="http://feeds.feedburner.com/~r/anantgarg/~4/1R99mgS-IM0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://anantgarg.com/2009/05/20/collabtweet-multiple-users-single-twitter-account/feed/</wfw:commentRss>
		<feedburner:origLink>http://anantgarg.com/2009/05/20/collabtweet-multiple-users-single-twitter-account/</feedburner:origLink></item>
		<item>
		<title>Gmail/Facebook Style jQuery Chat</title>
		<link>http://feedproxy.google.com/~r/anantgarg/~3/W-PpfT0sDq0/</link>
		<comments>http://anantgarg.com/2009/05/13/gmail-facebook-style-jquery-chat/#comments</comments>
		<pubDate>Wed, 13 May 2009 17:18:23 +0000</pubDate>
		<dc:creator>Anant Garg</dc:creator>
		
		<category><![CDATA[Javascript]]></category>

		<category><![CDATA[PHP]]></category>

		<category><![CDATA[jquery]]></category>

		<category><![CDATA[plugin]]></category>

		<guid isPermaLink="false">http://anantgarg.com/?p=255</guid>
		<description><![CDATA[This jQuery chat module enables you to seamlessly integrate Gmail/Facebook style chat into your existing website.]]></description>
			<content:encoded><![CDATA[<script type="text/javascript">dzone_url = "http://anantgarg.com/2009/05/13/gmail-facebook-style-jquery-chat/";</script><p><strong>Introduction</strong><br />
Everyone loves the <a href="http://mail.google.com/mail/help/chat.html">gmail</a> and <a href="http://blog.facebook.com/blog.php?post=12811122130">facebook</a> inline chat modules. This jQuery chat module enables you to seamlessly integrate Gmail/Facebook style chat into your existing website.</p>
<p><img src="http://anantgarg.com/wp-content/uploads/2009/05/jquery-chat-module.jpg" alt="jQuery Chat" title="jQuery Chat" width="234" height="317" class="alignnone size-full wp-image-256" /></p>
<p><strong>Features</strong><br />
1. Gmail style bottom right display of chat boxes<br />
2. Keeps chat boxes open and stores state (data) even when pages are browsed/refreshed similar to Facebook<br />
3. Displays &#8220;Sent at&#8230;&#8221; after 3 minutes of inactivity<br />
4. Displays &#8220;X says&#8230;&#8221; &#038; blinks chat boxes when window is not in focus<br />
5. Minimize and close chat boxes<br />
6. Auto-resize of text input box<br />
7. Auto-scrolling of chat text<br />
8. Auto-back-off polling policy (hits the server less-often when chat activity is low)<br />
9. Extremely simple to integrate into existing site</p>
<p><strong>Demo</strong><br />
Please load the following links in different browsers otherwise it wont work:<br />
(Note that due to users trying out the chat links below at the same time, it might work slightly erratically because the username is actually not supposed to be used by multiple users at the same time)</p>
<p><a href="/chat/samplea.php">Sample Chat User One</a><br />
<a href="/chat/sampleb.php">Sample Chat User Two</a><br />
<a href="/chat/samplec.php">Sample Chat User Three</a></p>
<p><strong>Getting Started</strong><br />
First download the module (link below)</p>
<p>The script does not manage rosters (i.e. which users are online etc.), it only enables users to chat with each other. I assume your current application already provides that functionality. You must also make sure that $_SESSION['username'] is being set when your website session begins. You will understand the logic better after you try the sample files that I have provided.</p>
<p>You must first create a mySQL table as below (or import db.txt)</p>
<pre class="brush: php">
CREATE TABLE `chat` (
  `id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
  `from` VARCHAR(255) NOT NULL DEFAULT &#039;&#039;,
  `to` VARCHAR(255) NOT NULL DEFAULT &#039;&#039;,
  `message` TEXT NOT NULL,
  `sent` DATETIME NOT NULL DEFAULT &#039;0000-00-00 00:00:00&#039;,
  `recd` INTEGER UNSIGNED NOT NULL DEFAULT 0,
  PRIMARY KEY (`id`),
 INDEX `to` (`to`),
 INDEX `from` (`from`)
)
ENGINE = InnoDB;
</pre>
<p>Add the following scripts to your page template</p>
<p><code>
<pre class="brush: php">
&lt;script type=&quot;text/javascript&quot; src=&quot;js/jquery.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;js/chat.js&quot;&gt;&lt;/script&gt;
</pre>
<p></code></p>
<p>Add the following CSS to your page template<br />
<code></p>
<pre class="brush: php">
&lt;link type=&quot;text/css&quot; rel=&quot;stylesheet&quot; media=&quot;all&quot; href=&quot;css/chat.css&quot; /&gt;
&lt;link type=&quot;text/css&quot; rel=&quot;stylesheet&quot; media=&quot;all&quot; href=&quot;css/screen.css&quot; /&gt;

&lt;!--[if lte IE 7]&gt;
&lt;link type=&quot;text/css&quot; rel=&quot;stylesheet&quot; media=&quot;all&quot; href=&quot;css/screen_ie.css&quot; /&gt;
&lt;![endif]--&gt;
</pre>
<p></code></p>
<p>Now in your list of users online, add &#8220;javascript:chatWith(&#8217;USERNAME&#8217;);&#8221; function where USERNAME is the username for that particular user who he/she wants to chat with.</p>
<p>Once that is done, edit chat.php and set your database parameters and try your website. </p>
<p>For better understanding, load 3 different browsers (internet explorer, firefox, safari) and point them to samplea.php, sampleb.php and samplec.php.</p>
<p>Click on &#8220;chat with john doe&#8221; link and watch the chat functionality come alive!</p>
<p>Inorder to integrate your existing website, you must place all your content between the &#8220;main_container&#8221; div tag.</p>
<p><strong>Browser Compatibility</strong><br />
1. Firefox 2+<br />
2. Internet Explorer 6+<br />
3. Safari 2+<br />
4. Opera 9+</p>
<p><strong>Licensing</strong><br />
This chat script can be used for <strong>free</strong> under GPL-style license for <strong>non-commercial purposes</strong>. For commercial purposes, please purchase a license.</p>
<p><strong>Download</strong></p>
<p><a href='http://anantgarg.com/wp-content/uploads/2009/05/jquerychat.zip'>jQuery Chat Module</a>. If you would like a more <a href='http://www.cometchat.com'>full featured inline chat software</a>, have a look at <b><a href='http://www.cometchat.com'>CometChat</a></b></p>
<p><strong>Purchase</strong></p>
<p>Your purchase includes free updates for life! If you have any queries, please contact me using the form below.</p>
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_blank">
<input type="hidden" name="cmd" value="_s-xclick">
<input type="hidden" name="hosted_button_id" value="5458118">
<input type="hidden" name="on0" value="Type">
<select name="os0">
	<option value="Single Domain License">Single Domain License $49.00<br />
	<option value="5 Domains License">5 Domains License $199.00<br />
	<option value="10 Domains License">10 Domains License $349.00<br />
	<option value="Unlimited Domains License">Unlimited Domains License $499.00<br />
</select>
<input type="hidden" name="currency_code" value="USD">
<input type="image" src="https://www.paypal.com/en_US/i/btn/btn_buynow_SM.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!" style="vertical-align: -5px; padding-left: 5px;">
<img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1"><br />
</form>
<p><strong>Future Updates</strong><br />
1. Gmail style pop-out functionality<br />
2. Gmail style emoticons<br />
3. Gmail style video chat<br />
4. Comet integration<br />
5. Jabber integration</p>
<p><strong>Comments/Suggestions?</strong><br />
Do let me know your suggestions on how we can improve this code or any other features you would like to add.</p>
<p><strong>Spread The Word</strong><br />
If you like what you are reading, then please help spread the word by re-tweeting, blogging and dzone upvoting or use the ShareThis button below. Thank you.</p>
<img src="http://feeds.feedburner.com/~r/anantgarg/~4/W-PpfT0sDq0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://anantgarg.com/2009/05/13/gmail-facebook-style-jquery-chat/feed/</wfw:commentRss>
		<feedburner:origLink>http://anantgarg.com/2009/05/13/gmail-facebook-style-jquery-chat/</feedburner:origLink></item>
		<item>
		<title>Bulletproof Subversion Web Workflow</title>
		<link>http://feedproxy.google.com/~r/anantgarg/~3/WDbLG1mOkhc/</link>
		<comments>http://anantgarg.com/2009/04/22/bulletproof-subversion-web-workflow/#comments</comments>
		<pubDate>Wed, 22 Apr 2009 16:26:29 +0000</pubDate>
		<dc:creator>Anant Garg</dc:creator>
		
		<category><![CDATA[PHP]]></category>

		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://anantgarg.com/?p=234</guid>
		<description><![CDATA[This workflow will help you perform systematic version control (including database versioning) on your web development projects. Two methods have been detailed. Depending on how critical your web-application is, you can adopt either the bulletproof or the semi bulletproof method.]]></description>
			<content:encoded><![CDATA[<script type="text/javascript">dzone_url = "http://anantgarg.com/2009/04/22/bulletproof-subversion-web-workflow/";</script><p><strong>The Problem</strong></p>
<p>If you do not have subversion installed already, you can borrow parts from the <a href="http://anantgarg.com/2009/03/25/subversion-trac-multiple-projects/">subversion + trac installation</a> tutorial. Once you have subversion installed, its important to integrate it in your web development workflow. Simply running <em>SVN commit</em> everytime you complete a feature is not enough. So let us see how we can fully integrate subversion into our web development. This workflow also includes database versioning (using a simple PHP script).</p>
<p><strong>The Solution</strong></p>
<p>Before we begin, scroll down and download the database backup and version control script that I have written in PHP.</p>
<p><strong><em>The Bulletproof Method</em></strong></p>
<p>This process is slightly lengthy and complicated, but once you get the hang of it, your web development process will be greatly streamlined. Also, you will be able to test your deployed versions before making them live. This method allows you to switch between versions really really quickly. It is advised for all heavy traffic websites.</p>
<p><em>Assumption:</em> You have a heavy traffic website. You release version upgrades to your site regularly. Once in a while, you also modify the database schema. You would like to test your builds on the live server before letting your users view it.</p>
<p><strong>Phase 1: Launching of version 1.0</strong></p>
<p>Development Server</p>
<p>1. Design the database schema and program the first version of your script.<br />
2. Before committing the script to the repository perform the following steps:<br />
a. Create a folder called db and assign appropriate permissions<br />
b. Run dbbvc.php in your browser and create a baseline. The baseline can be created with data or without data as per your requirements. This will create db/1.sql file which is basically mysqldump of the current database.<br />
3. Once that is done, you can safely commit your script (to the trunk folder). Be sure to commit the db folder, along with 1.sql.</p>
<p><a href="http://anantgarg.com/wp-content/uploads/2009/04/dbbvc.png" rel="shadowbox[post-234];player=img;"><img src="http://anantgarg.com/wp-content/uploads/2009/04/dbbvc.png" alt="Db Backup &amp; Versioning Script" title="Db Backup &amp; Versioning Script" width="696" height="417" class="alignnone size-full wp-image-236" /></a></p>
<p>Note: When committing to your repository, make sure you do not commit any configuration files. All configuration files should go in as <em>config.default.php</em> etc. (This will help you as your server <em>config.php</em> will not get updated when you run <em>svn update</em> on the server.) As a rule, any file that differs from your development to production server, must be a .default file.</p>
<p>Production Server</p>
<p>Now suppose you want to launch this version you have committed.</p>
<p>4. First copy your trunk folder to a suitable version in your tags directory (e.g. tags/1.0) using the <a href="http://svnbook.red-bean.com/en/1.0/re07.html">svn copy</a>.<br />
5. Now go to your server and use <a href="http://svnbook.red-bean.com/en/1.0/re10.html">svn export</a> to export the contents of tag/1.0 to /yourserver/www/1.0<br />
6. Now create a folder called static in your www. The static folder is used to store those folders which will have user uploaded data. </p>
<p>For example, you may have /yourserver/www/1.0/images/profilepics<br />
a. First create a folder called profilepics in www/static<br />
b. Delete the /yourserver/www/1.0/images/profilepics folder<br />
c. Create a <a href="http://en.wikipedia.org/wiki/Symbolic_link">symbolic link</a> in your images folder using the following command:<br />
<b>sudo ln -s /yourserver/static/profilepics /yourserver/www/1.0</b></p>
<p>7. Once that is done, create your database and modify your config.php as per your server settings. Now run dbbvc.php in your server and select <em>Backup &#038; Version Upgrade</em>. This will create add all the schema/data to your database.<br />
8. Now make sure your server supports <a href="http://httpd.apache.org/docs/1.3/mod/mod_rewrite.html">mod_rewrite</a>  and add the following file to the /yourserver/www folder.</p>
<pre class="brush: php">
&amp;amp;amp;amp;amp;lt;IfModule mod_rewrite.c&amp;amp;amp;amp;amp;gt;
RewriteEngine On

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

RewriteRule    ^$  VERSION/    [L]
RewriteRule    (.*) VERSION/$1    [L]

&amp;amp;amp;amp;amp;lt;/IfModule&amp;amp;amp;amp;amp;gt;
&amp;amp;amp;amp;amp;lt;IfModule !mod_rewrite.c&amp;amp;amp;amp;amp;gt;
	ErrorDocument 404 index.php
&amp;amp;amp;amp;amp;lt;/IfModule&amp;amp;amp;amp;amp;gt;
</pre>
<p>In our example we replace VERSION with 1.0 in the above code.</p>
<p>9. Now create a .htaccess file in the /yourserver/www/1.0 folder with the following contents. (just to be safe, not necessary)</p>
<pre class="brush: php">
&amp;amp;amp;amp;amp;lt;IfModule mod_rewrite.c&amp;amp;amp;amp;amp;gt;
RewriteEngine Off
&amp;amp;amp;amp;amp;lt;/IfModule&amp;amp;amp;amp;amp;gt;
</pre>
<p>10. Once that is done, you can point your browser to your server url and it should work! If you encounter any errors, then feel free to post a comment.</p>
<p><strong>Phase 2: Launching of subsequent versions</strong></p>
<p>Development Server</p>
<p>11. Now let us say you are ready to roll out a couple of changes on the server. Also, let us assume you have made modifications to the database schema. Now everytime you make changes to the schema, you must create a sequential file (2.sql,3.sql&#8230;) in the db folder. If you forget to create this file and have already modified the database schema, you can use <a href="http://dev.mysql.com/workbench/">MySQL Workbench</a> to <a href="http://simpcode.blogspot.com/2008/06/using-mysql-workbench-to-generate.html">reverse engineer and find out the changes.</a><br />
12. Now you can safely commit this version to trunk. Be sure to include your 2.sql&#8230; files also. You may use a single .sql file containing all the db changes for that revision.<br />
13. Once that is done, create a tag of your new version and head over to the production server.</p>
<p>Production Server</p>
<p>14. Now svn export the tags folder to /yourserver/www/1.1 and create your symlinks<br />
15. Duplicate your database (create a new database for this tag and import the current database)<br />
16. Point your browser to dbbvc.php, use the Backup &#038; Version Upgrade option. This will upgrade the database to the latest version.<br />
17. Now you can test your script, once your a ready to do the switch, all you have to do is edit /yourserver/www/.htaccess and change the VERSION to your latest version.</p>
<p>Now, the above steps may appear to be an overkill for a small website which can afford a bit of downtime. Also, you may not have permission to create symlinks and thus can&#8217;t use the above method. For that let us have a look at a semi bulletproof svn workflow.</p>
<p><strong><em>The Semi Bulletproof Method</em></strong></p>
<p><strong>Phase 1: Launching of version 1.0</strong></p>
<p>Development Server</p>
<p>Follow the same steps as the bulletproof method (Steps 1,2,3).</p>
<p>Deployment Server</p>
<p>1. Make sure you have created your tag, and use <a href="http://svnbook.red-bean.com/en/1.0/re04.html">svn checkout</a> to checkout the contents of your tags/1.0 folder to /yourserver/www folder<br />
2. Edit your config.php file, create your database and run dbbvc.php to import your database.<br />
3. Create .htaccess file in your /yourserver/www folder with the following contents:</p>
<pre class="brush: php">
&amp;amp;amp;amp;amp;lt;IfModule mod_rewrite.c&amp;amp;amp;amp;amp;gt;
   RewriteEngine On
   RewriteRule ^(.*)(.svn)(.*)$ http://www.yourserver.com [L]
&amp;amp;amp;amp;amp;lt;/IfModule&amp;amp;amp;amp;amp;gt;
</pre>
<p>4. Now you can point your browser to yourserver.com and it should work!</p>
<p><strong>Phase 2: Launching of subsequent versions</strong></p>
<p>Development Server</p>
<p>Follow the same steps as the bulletproof method (Steps 11,12,13).</p>
<p>Production Server</p>
<p>5. Now use the <a href="http://svnbook.red-bean.com/en/1.0/re27.html">svn switch</a> command to update the contents of your /yourserver/www folder.<br />
6. Point your browser to dbbvc.php and update your database (if you have made any changes to schema).</p>
<p>Although the above method is simpler, and will work for most of your projects, there will be a definite downtime during your revision update and db schema update. During this upgrade, you may want to redirect all users to a temporary page using .htaccess.</p>
<p><strong>Download the database versioning script (dbbvc)</strong></p>
<p>Download the <a href='http://anantgarg.com/wp-content/uploads/2009/04/dbbvc.zip'>Database Version Control</a> script. You will need to rename config.default.php to config.php and update the database details or you may edit dbbvc.php and <em>require</em> your own config.php/db.php.</p>
<p><strong>Comments/Suggestions?</strong></p>
<p>Do let me know your suggestions on how we can improve this workflow or anything else you want to add.</p>
<p><strong>Spread The Word</strong></p>
<p>If you like what you are reading, then please help spread the word by <a href="http://twitter.com/home/?status=RT+%40anant_garg+Bulletproof%20Subversion%20Web%20Workflow%20http:%2F%2Ftinyurl.com%2Fdhzxwj">re-tweeting</a>, blogging and dzone upvoting or use the ShareThis button below. Thank you.</p>
<img src="http://feeds.feedburner.com/~r/anantgarg/~4/WDbLG1mOkhc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://anantgarg.com/2009/04/22/bulletproof-subversion-web-workflow/feed/</wfw:commentRss>
		<feedburner:origLink>http://anantgarg.com/2009/04/22/bulletproof-subversion-web-workflow/</feedburner:origLink></item>
		<item>
		<title>Write your own PHP MVC Framework (Part 2)</title>
		<link>http://feedproxy.google.com/~r/anantgarg/~3/8rAT03zQ0BE/</link>
		<comments>http://anantgarg.com/2009/03/30/write-your-own-php-mvc-framework-part-2/#comments</comments>
		<pubDate>Mon, 30 Mar 2009 06:25:20 +0000</pubDate>
		<dc:creator>Anant Garg</dc:creator>
		
		<category><![CDATA[PHP]]></category>

		<category><![CDATA[framework]]></category>

		<category><![CDATA[mvc]]></category>

		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://anantgarg.com/?p=200</guid>
		<description><![CDATA[The much awaited Part 2 of the Write your own PHP MVC Framework tutorial series. This part drastically enhances the feature-set of the framework including object-relational mapping, routing and caching.]]></description>
			<content:encoded><![CDATA[<script type="text/javascript">dzone_url = "http://anantgarg.com/2009/03/30/write-your-own-php-mvc-framework-part-2/";</script><p>If you haven&#8217;t already, please read <a href="http://anantgarg.com/2009/03/13/write-your-own-php-mvc-framework-part-1/">Part 1</a> of the <a href="http://anantgarg.com/2009/03/13/write-your-own-php-mvc-framework-part-1/">PHP MVC tutorial</a>. A lot of changes have been incorporated in this part. Unlike the last tutorial, I have not pasted the code directly here, and I suggest you <a href='http://anantgarg.com/wp-content/uploads/2009/03/framework-2.zip'>download the framework</a> before reading on. In the example, we have implemented a simple e-commerce website consisting of categories, subcategories, products and tags (for products). The example will help you understand the various relationships between the tables and most of the new functionality provided by this part of the framework.</p>
<p><strong>What&#8217;s New</strong></p>
<p><em>config/inflection.php</em><br />
The inflection configuration file enables us to use irregular words i.e. words which do not have a standard plural name. This file is used in conjunction with <em>library/inflection.class.php</em></p>
<p><em>config/routing.php</em><br />
The routing configuration file enables us to specify default controller and action. We can also specify custom redirects using regular expressions. Currently I have specified only one redirect i.e. http://localhost/framework/admin/categories/view will become http://localhost/framework/admin/categories_view where admin is the controller and categories_view is the action. This will enable us to create an administration centre with pretty URLs. You can specify others as per your requirements. For more information on how to use regular expressions have a look at <a href="http://www.roscripts.com/PHP_regular_expressions_examples-136.html">one</a> <a href="http://weblogtoolscollection.com/regex/regex.php">of</a> <a href="http://www.phpf1.com/tutorial/php-regular-expression.html">these</a> <a href="http://www.webcheatsheet.com/php/regular_expressions.php">tutorials</a>.</p>
<p><em>library/cache.class.php</em><br />
The cache class is in its infancy. Currently there are two simple functions- set and get. The data is stored in a flat text-file in the cache directory. Currently only the <em>describe</em> function of the SQLQuery class uses this cache function.</p>
<p><em>library/html.class.php</em><br />
The HTML class is used to aid the template class. It allows you to use a few standard functions for creating links, adding javascript and css. I have also added a function to convert links to tinyurls. This class can be used only in the views e.g. $html->includeJs(&#8217;generic.js&#8217;);</p>
<p><em>library/inflection.class.php</em><br />
In the previous part, plural of words were created by adding only &#8220;s&#8221; to the word. However, for a more full-fledged version, we now use the inflection class originally created by <a href="http://kuwamoto.org/2007/12/17/improved-pluralizing-in-php-actionscript-and-ror">Sho Kuwamoto</a> with slight modifications. If you have a look at the class, it makes use of simple regular expressions. It would be nice to add a cache function to this class in future.</p>
<p><em>library/template.class.php</em><br />
I have added a new variable called doNotRenderHeader which will enable you to not output headers for a particular action. This can be used in AJAX calls when you do not want to return the headers. It has to be called by the controller e.g. $this->doNotRenderHeader = 1;</p>
<p><em>library/vanillacontroller.class.php &#038; vanillamodel.class.php</em><br />
Pretty much unchanged, but I have added a prefix vanilla to them to emphasize on its simplicity <img src='http://anantgarg.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><em>library/sqlquery.class.php</em><br />
The SQLQuery class is the heart of this framework. This class will enable you to use your tables as objects.</p>
<p>Let us understand the easy functions first - save() and delete()</p>
<p>The save() function must be used from the controller. The save() function can have two options- if an id is set, then it will update the entry; if it is not set, then it will create a new entry. For example let us consider the categories class i.e. application/controllers/categoriescontroller.php. We can have a function like the one below.</p>
<pre class="brush: php">
function new() {
   $this-&gt;Category-&gt;id = $_POST[&#039;id&#039;];
   $this-&gt;Category-&gt;name = $_POST[&#039;name&#039;];
   $this-&gt;Category-&gt;save();
}
</pre>
<p>If $this->Category->id = null; then it will create a new record in the categories table.</p>
<p>The delete() function enables you to delete a record from the table. A sample code could be as below. Although you should use POST instead of GET queries for deleting records. As a rule idempotent operations should use GET. Idempotent operations are those which do not change the state of the database (i.e. do not update/delete/insert rows or modify the database in anyway)</p>
<pre class="brush: php">
function delete($categoryId) {
   $this-&gt;Category-&gt;id = $categoryId;
   $this-&gt;Category-&gt;delete();
}
</pre>
<p>Now let us look at the search() function. I know it is a bit intimidating at first. But it is pretty straight forward after we break it down. If you are unaware of database table relationships (1:1, 1:Many and Many:Many) have a quick look <a href="http://www.databaseprimer.com/relationship.html">here</a>. During database design, we use the following convention:</p>
<p>1:1 Relationship<br />
For a one is to one relationship, suppose we have two tables students and mentors and each student hasOne mentor, then in the students table we will have a field called &#8216;mentor_id&#8217; which will store the id of the mentor from the mentors table.</p>
<p>1:Many Relationship<br />
For a one is to many relationship, suppose we have two tables parents and children and each parent hasMany children, then in the children table we will have a field called &#8216;parent_id&#8217; which will store the id of the parent from the parents table.</p>
<p>Many:Many Relationship<br />
For a many is to many relationship, suppose we have two tables students and teachers and each student hasManyAndBelongsToMany teachers, then we create a new table called students_teachers with three fields: id, student_id and teacher_id. The naming convention for this table is alphabetical. i.e. if our tables are cars and animals, then the table should be named animals_cars and not cars_animals.</p>
<p>Now once we have created our database as per these conventions, we must tell our framework about their existence. Let us have a look at models/product.php.</p>
<pre class="brush: php">
class Product extends VanillaModel {
	var $hasOne = array(&#039;Category&#039; =&gt; &#039;Category&#039;);
	var $hasManyAndBelongsToMany = array(&#039;Tag&#039; =&gt; &#039;Tag&#039;);
}
</pre>
<p>The first Category is the alias and the second Category is the actual model. In most cases both will be the same. Let us consider the models/category.php where they are not.</p>
<pre class="brush: php">
&lt;?php

class Category extends VanillaModel {
		var $hasMany = array(&#039;Product&#039; =&gt; &#039;Product&#039;);
		var $hasOne = array(&#039;Parent&#039; =&gt; &#039;Category&#039;);

}
</pre>
<p>Here each category has a parent category, thus our alias is <em>Parent</em> while model is <em>Category</em>. Thus we will have a field called parent_id in the categories table. To clearly understand these relationships, I suggest you create a couple of tables and test them out for yourself. In order to see the output, use code similar to the following in your controller.</p>
<pre class="brush: php">
function view() {
   $this-&gt;Category-&gt;id = 1;
   $this-&gt;Category-&gt;showHasOne();
   $this-&gt;Category-&gt;showHasMany();
   $this-&gt;Category-&gt;showHMABTM();
   $data = $this-&gt;Category-&gt;search();
   print_r($data);
}
</pre>
<p>Now let us try and understand the search() function. If there are no relationships, then the function simply does a <em>select * from tableName</em> (tableName is same as controllerName). We can influence this statement, by using the following commands:</p>
<p><em>where(&#8217;fieldName&#8217;,'value&#8217;)</em> => Appends WHERE &#8216;fieldName&#8217; = &#8216;value&#8217;<br />
<em>like(&#8217;fieldName&#8217;,'value&#8217;)</em> => Appends WHERE &#8216;fieldName&#8217; LIKE &#8216;%value%&#8217;<br />
<em>setPage(&#8217;pageNumber&#8217;)</em> => Enables pagination and display only results for the set page number<br />
<em>setLimit(&#8217;fieldName&#8217;,'value&#8217;)</em> => Allows you to modify the number of results per page if pageNumber is set. Its default value is the one set in config.php.<br />
<em>orderBy(&#8217;fieldName&#8217;,'Order&#8217;)</em> => Appends ORDER BY &#8216;fieldName&#8217; ASC/DESC<br />
<em>id = X</em> => Will display only a single result of the row matching the id</p>
<p>Now let us consider when showHasOne() function has be called, then for each hasOne relationship, a LEFT JOIN is done (see line 91-99).</p>
<p>Now if showHasMany() function has been called, then for each result returned by the above query and for each hasMany relationship, it will find all those records in the second table which match the current result&#8217;s id (see line 150). Then it will push all those results in the same array. For example, if teachers hasMany students, then $this->Teacher->showHasMany() will search for <em>teacher_id</em> in the <em>students</em> table.</p>
<p>Finally if showHMABTM() function has been called, then for each result returned by the first query and for each hasManyAndBelongsToMany relationship, it will find all those records which match the current result&#8217;s id (see line 200-201). For example, if teachers hasManyAndBelongsToMany students, then $this->Teacher->showHMABTM() will search for <em>teacher_id</em> in <em>students_teachers</em> table.</p>
<p>On line 236, if <em>id</em> is set, then it will return a single result (and not an array), else it will return an array. The function then calls the clear() function which resets all the variables (line 368-380). </p>
<p>Now let us consider an example to enable pagination on products. The code in the controllers/productscontroller.php should look something similar to the following.</p>
<pre class="brush: php">
function page ($pageNumber = 1) {
  $this-&gt;Product-&gt;setPage($pageNumber);
  $this-&gt;Product-&gt;setLimit(&#039;10&#039;);
  $products = $this-&gt;Product-&gt;search();
  $totalPages = $this-&gt;Product-&gt;totalPages();
  $this-&gt;set(&#039;totalPages&#039;,$totalPages);
  $this-&gt;set(&#039;products&#039;,$products);
  $this-&gt;set(&#039;currentPageNumber&#039;,$pageNumber);
}
</pre>
<p>Now our corresponding view i.e. views/products/page.php will be something like below.</p>
<pre class="brush: php">
&lt;?php foreach ($products as $product):?&gt;
&lt;div&gt;
&lt;?php echo $product[&#039;Product&#039;][&#039;name&#039;]?&gt;
&lt;/div&gt;
&lt;?php endforeach?&gt;

&lt;?php for ($i = 1; $i &lt;= $totalPages; $i++):?&gt;
&lt;div&gt;
&lt;?php if ($i == $currentPageNumber):?&gt;
&lt;?php echo $currentPageNumber?&gt;
&lt;?php else: ?&gt;
&lt;?php echo $html-&gt;link($i,&#039;products/page/&#039;.$i)?&gt;
&lt;?php endif?&gt;
&lt;/div&gt;
&lt;?php endfor?&gt;
</pre>
<p>Thus with a few lines of code we have enabled pagination on our products page with pretty URLs!<br />
(/products/page/1, products/page/2 &#8230;)</p>
<p>If you look at the totalPages() function on line 384-397, you will see that it takes the existing query and strips of the LIMIT condition and returns the count. This count/limit gives us the totalPages.</p>
<p>Now suppose that we are in the categories controller and we want to implement a query on the products table. One way to implement this is using a custom query i.e. $this->Category->custom(&#8217;select * from products where &#8230;.&#8217;);</p>
<p>Alternatively, we can use the performAction function (line 49-57 in shared.php) to call an action of another controller. An example call in categoriescontroller.php would be something like below.</p>
<pre class="brush: php">
function view($categoryId = null, $categoryName = null) {
  $categories = performAction(&#039;products&#039;,&#039;findProducts&#039;,array($categoryId,$categoryName));
}
</pre>
<p>And the corresponding code in productscontroller.php should be as below.</p>
<pre class="brush: php">
function findProducts ($categoryId = null, $categoryName = null) {
  $this-&gt;Product-&gt;where(&#039;category_id&#039;,$categoryId);
  $this-&gt;Product-&gt;orderBy(&#039;name&#039;);
  return $this-&gt;Product-&gt;search();
}
</pre>
<p>The above more or less sums up all the functionality of the SQLQuery class. You can easily extend this as per your requirements e.g. to cache results, add conditions to hasMany, hasOne, hasMABTM queries also etc.</p>
<p>I have also laid the foundation for implementing user registration functionality by specifying a beforeAction and afterAction function which will be executed for each controller action. This will enable us to call a function which checks whether the user cookie is set and is a valid user.</p>
<p>One more feature that I have implemented is to have an administration centre. For this purpose we create a dummy model called models/admin.php and set a variable called $abstract = true. This will tell our VanillaModel to not look for a corresponding table in the database. As stated before I have created a routing for admin/X/Y as admin/X_Y. Thus we can have URLs like admin/categories/delete/15 which will actually call the categories_delete(15) function in the controllers/admincontroller.php file.</p>
<p><strong>Where do we go from here?</strong></p>
<p>I hope this tutorial is not too complicated. I have tried to break it down as much as possible. A couple of functions that we need to implement include -> redirectAction which will be similar to performAction, but instead redirect. performAction can only return results. redirectAction will perform only the redirected action and display that corresponding view only. This will be helpful during user authentication. If the user is not logged in, then we call a function like -> redirectAction(&#8217;user&#8217;,'login&#8217;,array($returnUrl));</p>
<p>Various classes are in their infancy like the cache class, HTML class etc. These classes can be expanded to add more functionality. </p>
<p>More scripts can be added like dbimport, clearcache etc. can be added. Currently there is only one script dbexport.php which dumps the entire database. Classes for managing sessions, cookies etc. also need to be developed.</p>
<p><strong>Download link here</strong></p>
<p><a href='http://anantgarg.com/wp-content/uploads/2009/03/framework-2.zip'>Download Framework (Part 2)</a> (ZIP File)</p>
<p>Make sure you edit config/config.php and add your database details. Point your browser to localhost/FRAMEWORKDIR to see output. Also before executing, import the database that I have created in the db folder. </p>
<p><strong>Suggestions?</strong></p>
<p>Do let me know your suggestions on how we can improve this code/any particular features you would like to see implemented/any other unrelated topic you would like a tutorial on. </p>
<p><strong>Spread The Word</strong></p>
<p>If you like what you are reading, then please help spread the word by <a href="http://twitter.com/home/?status=RT+%40anant_garg+Write%20your%20own%20PHP%20MVC%20Framework%20(Part%202) http%3A%2F%2Ftinyurl.com%2Fca3kls">re-tweeting</a>, blogging and dzone upvoting or use the ShareThis button below. Thank you.</p>
<p><script type="text/javascript">var dzone_url = 'http://anantgarg.com/2009/03/30/write-your-own-php-mvc-framework-part-2/';var dzone_title = 'Write your own PHP MVC Framework (Part 2)';var dzone_blurb = '';var dzone_style = '1';</script><script language="javascript" src="/dzone.js"></script></p>
<img src="http://feeds.feedburner.com/~r/anantgarg/~4/8rAT03zQ0BE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://anantgarg.com/2009/03/30/write-your-own-php-mvc-framework-part-2/feed/</wfw:commentRss>
		<feedburner:origLink>http://anantgarg.com/2009/03/30/write-your-own-php-mvc-framework-part-2/</feedburner:origLink></item>
		<item>
		<title>Subversion + Trac for Multiple Projects (One Click Build)</title>
		<link>http://feedproxy.google.com/~r/anantgarg/~3/PmNTLbJKqmg/</link>
		<comments>http://anantgarg.com/2009/03/25/subversion-trac-multiple-projects/#comments</comments>
		<pubDate>Tue, 24 Mar 2009 20:30:22 +0000</pubDate>
		<dc:creator>Anant Garg</dc:creator>
		
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://anantgarg.com/?p=169</guid>
		<description><![CDATA[This tutorial will guide you through the installation of Subversion + Trac on Ubuntu and configuration to support multiple projects. The build file enables you to create new projects with a single click.]]></description>
			<content:encoded><![CDATA[<script type="text/javascript">dzone_url = "http://anantgarg.com/2009/03/25/subversion-trac-multiple-projects/";</script><p><strong>The Problem</strong></p>
<p>If you are wondering why exactly you need version control, then you should probably <a href="http://stackoverflow.com/questions/250984/do-i-really-need-version-control">read this</a>. <a href="http://subversion.tigris.org">Subversion</a> is a great open-source version control system. And <a href="http://trac.edgewall.org">Trac</a> is a good project management and bug/issue tracking system which works seamlessly with Subversion. The problem is how to create and manage multiple projects using a single build procedure.</p>
<p><img src="http://anantgarg.com/wp-content/uploads/2009/03/spt.png" alt="Subversion + Trac" title="spt" width="183" height="64" class="alignnone size-full wp-image-192" /></p>
<p><strong>The Solution</strong></p>
<p>First we need a machine running <a href="http://www.ubuntu.com">Ubuntu</a>. The steps below have been tested for Ubuntu 8.04.</p>
<p>Launch terminal and run the following command to install Apache, Python and Subversion.</p>
<pre class="brush: php">
sudo apt-get install apache2 libapache2-mod-python libapache2-svn python-setuptools subversion python-subversion
</pre>
<p>You can use sudo apt-get install Trac, but the version it installs is 0.10.4. Inorder to get the latest version of Trac use the following command. I suggest you specify the <a href="http://trac.edgewall.org/wiki/TracDownload">latest stable version of Trac</a> in the command line. As of writing this guide, it is 0.11.3. Also, execute the commands below i.e. create directories svn and trac; create a htpasswd file with your usernames.</p>
<pre class="brush: php">
sudo easy_install http://ftp.edgewall.com/pub/trac/Trac-0.11.3.tar.gz
sudo mkdir /svn
sudo mkdir /trac
sudo htpasswd -cm /etc/svnauth yourusername
sudo htpasswd -m /etc/svnauth nextusername
</pre>
<p>Next you have to create a file for permissions</p>
<pre class="brush: php">
sudo gpedit /etc/svnaccess
</pre>
<p>Add the following contents to the file. Make sure you change <em>yourusername</em> and <em>nextusername</em> to the usernames you have created.</p>
<pre class="brush: php">
[groups]
developers = yourusername, nextusername
[ / ]
@developers = rw
* = r
</pre>
<p>Then you have to create a new configuration file for Apache by executing: </p>
<pre class="brush: php">
sudo gedit /etc/apache2/sites-available/myserver
</pre>
<p>Add the following contents to the file. Make sure you change <strong>your@email.com</strong> to you email address.</p>
<pre class="brush: php">
&lt;VirtualHost *&gt;

	ServerAdmin your@email.com

	DocumentRoot /var/www/
	&lt;Directory /&gt;
		Options FollowSymLinks
		AllowOverride None
	&lt;/Directory&gt;
	&lt;Directory /var/www/&gt;
		Options Indexes FollowSymLinks MultiViews
		AllowOverride None
		Order allow,deny
		allow from all
	&lt;/Directory&gt;

	ErrorLog /var/log/apache2/error.log
	LogLevel warn
	CustomLog /var/log/apache2/access.log combined
	ServerSignature On

&lt;Location /svn&gt;

   DAV svn
   SVNParentPath /svn

   AuthType Basic
   AuthName &quot;Subversion Repository&quot;
   AuthUserFile /etc/svnauth
   Require valid-user

   AuthzSVNAccessFile /etc/svnaccess
&lt;/Location&gt;

&lt;Location /trac&gt;

   SetHandler mod_python
   PythonHandler trac.web.modpython_frontend
   PythonOption TracEnvParentDir /trac
   PythonOption TracUriRoot /trac

   AuthType Basic
   AuthName &quot;Trac&quot;
   AuthUserFile /etc/svnauth
   Require valid-user

&lt;/Location&gt;

&lt;/VirtualHost&gt;
</pre>
<p>Once that is done, activate your newly created configuration file by using the <strong>a2ensite</strong> command as follows. Reload Apache, set permissions and edit trac.ini.</p>
<pre class="brush: php">
sudo a2ensite /etc/apache2/sites-available/myserver
sudo /etc/init.d/apache2 reload
sudo chown -R www-data /trac
sudo gpedit /etc/trac.ini
</pre>
<p>Add the following contents to trac.ini. </p>
<pre class="brush: php">
[header_logo]
alt = Logo
height = -1
link =
src = /logo.gif
width = -1
</pre>
<p><em>/etc/trac.ini</em> will store the default configuration for each Trac project instance. Copy your logo.gif to /var/www folder.</p>
<p>Finally, create a perl file called init.pl and add the following contents. Make sure you change <em>yourusername</em> to your username. This step will grant you administration rights so that you can add milestones etc. straight from the web interface.</p>
<pre class="brush: perl">
#!/usr/bin/perl
$sName = $ARGV[0];
$lName = $ARGV[1];
if ($lName eq &quot;&quot;) {
   $lName = $sName;
}
$sName =~ tr/A-Z/a-z/;
$path = &quot;sudo svnadmin create /svn/$sName&quot;;
system ($path);
$path = &quot;sudo chown -R www-data /svn/$sName&quot;;
system ($path);
$path = &quot;sudo trac-admin /trac/$sName initenv &#039;$lName&#039; &#039;sqlite:db/trac.db&#039; &#039;svn&#039; &#039;/svn/$sName&#039; --inherit=/etc/trac.ini&quot;;
system ($path);
$path = &quot;sudo chown -R www-data /trac/$sName&quot;;
system ($path);
$path = &quot;sudo trac-admin /trac/$sName permission add yourusername TRAC_ADMIN permission list yourusername&quot;;
system ($path);
print &quot;Done!\n\n&quot;;
</pre>
<p>Once the above file is created, your one click build is ready!</p>
<p>Now every time you want to create a new project, all you have to do is execute:</p>
<p>init.pl &#8217;shortprojname&#8217; &#8216;fullprojname&#8217;</p>
<p>where shortprojname is the name of your project with no spaces e.g. todoapp<br />
fullprojname is the expanded name of your project e.g. To-Do Application</p>
<p>Create your first sample project and point your browser to http://localhost/trac/shortprojname for Trac<br />
The path for your SVN repository will be http://localhost/svn/shortprojname</p>
<p>If you are looking for a GUI client for Subversion, I suggest you download <a href="http://tortoisesvn.net">TortoiseSVN for Windows</a> or <a href="http://versionsapp.com">Versions for Mac</a>. If you are not sure on how to use TortoiseSVN, here are a <a href="http://www.shokhirev.com/nikolai/programs/SVN/svn.html">couple</a> <a href="http://www.igorexchange.com/node/87">of</a> <a href="http://www.mind.ilstu.edu/research/robots/iris4/developers/svntutorial/">tutorials</a>.</p>
<p>Comments/Suggestions<br />
Feel free to let me know if there are any suggestions or comments you have. To learn more about Subversion, do take time off to read the <a href="http://svnbook.red-bean.com">Subversion Book</a>.</p>
<img src="http://feeds.feedburner.com/~r/anantgarg/~4/PmNTLbJKqmg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://anantgarg.com/2009/03/25/subversion-trac-multiple-projects/feed/</wfw:commentRss>
		<feedburner:origLink>http://anantgarg.com/2009/03/25/subversion-trac-multiple-projects/</feedburner:origLink></item>
		<item>
		<title>WordPress Internet Explorer 8 Accelerator</title>
		<link>http://feedproxy.google.com/~r/anantgarg/~3/-SJdauG096Y/</link>
		<comments>http://anantgarg.com/2009/03/20/wordpress-internet-explorer-8-accelerator/#comments</comments>
		<pubDate>Fri, 20 Mar 2009 13:12:22 +0000</pubDate>
		<dc:creator>Anant Garg</dc:creator>
		
		<category><![CDATA[PHP]]></category>

		<category><![CDATA[internet explorer]]></category>

		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://anantgarg.com/?p=132</guid>
		<description><![CDATA[The Internet Explorer 8 Accelerator plugin enables you to post an entry with selected text of any web-page to your WordPress blog.]]></description>
			<content:encoded><![CDATA[<script type="text/javascript">dzone_url = "http://anantgarg.com/2009/03/20/wordpress-internet-explorer-8-accelerator/";</script><p><strong>The Problem</strong><br />
Many a times while browsing the internet we come across text which we would like to blog about. A straight-forward solution is to copy the text and paste it in our WordPress text editor. However, we have to copy the site URL separately as well as the title of the page. To ease this process, the new <a href="http://www.microsoft.com/windows/internet-explorer/default.aspx">Internet Explorer</a> includes a useful feature called <a href="http://www.microsoft.com/windows/internet-explorer/features/accelerators.aspx">Accelerators</a>. Great! So now we need a plugin for WordPress.</p>
<p><img src="http://anantgarg.com/wp-content/uploads/2009/03/accelerator.jpg" alt="Internet Explorer 8 WordPress Accelerator" title="Internet Explorer 8 WordPress Accelerator" width="112" height="97" class="alignnone size-full wp-image-162" /></p>
<p><strong>The Plugin</strong><br />
Unfortunately, we cannot use the Internet Explorer Accelerator out-of-the-box. We need to install a small plugin for WordPress which will enable you to pre-populate the title and content of your new post. Also the Accelerator has to be generated on-the-fly because each WordPress URL is unique.</p>
<p>I have developed a two-step hassle free procedure to enable Internet Explorer Accelerator on your WordPress blog:</p>
<p><b>Note: This solution works only for self hosted blogs and not for blogs hosted on WordPress.com because plugin installation is not allowed on WordPress.com</b> </p>
<p>1. <a href="http://anantgarg.com/wp-internet-explorer-accelerator.zip">Download the plugin</a><br />
2. Copy accelerator.php to your wp-content/plugins directory and activate the plugin<br />
3. Now fill in the form below:</p>
<p><script type="text/javascript" src="/accelerator.js"></script></p>
<style>
.aform td {
background-color:#eeeeee;
}
.aform table td {
background-color:#eeeeee;
}
</style>
<form>
<div class="aform" style="border:1px dotted #cccccc;padding:6px;background-color:#eeeeee;width:400px">
<table style="margin:0" bgcolor=#eeeeee cellpadding=5 border=0 cellspacing=0>
<tr>
<td>Website (required)</td>
<td>
<input type="text" name="acceleratorurl" id="acceleratorurl" value="http://www.yoursite.com" class="textfield">
</td>
</tr>
<tr>
<td>Admin directory (advanced setting)</td>
<td>
<input type="text" name="wpadmin" id="wpadmin" value="wp-admin" class="textfield"><label class="text"></td>
</tr>
<tr>
<td>New Post file (advanced setting)</td>
<td>
<input type="text" name="postnew" id="postnew" value="post-new.php" class="textfield"><label class="text"></td>
</tr>
<tr>
<td colspan=2>
<div class="formactions" align="right">
<input type="button" value="Generate &#038; Add Accelerator to Internet Explorer" onclick="javascript:generate()" class="submit"></div>
</td>
</tr>
</table>
</div>
</form>
<p><strong>Screenshot</strong></p>
<p>Once you have added the custom accelerator, select any text and &#8220;Blog with WordPress&#8221;!</p>
<p><img src="http://anantgarg.com/wp-content/uploads/2009/03/blogwithwp.jpg" alt="Blog with WordPress Accelerator" title="Blog with WordPress Accelerator" width="250" height="200" class="alignnone size-full wp-image-164" style="border:1px dotted #333333" /></p>
<p><strong>Suggestions</strong><br />
Feel free to let me know if there are any suggestions or comments you have. One feature currently missing is that your text will not get posted if you are not logged-in to WordPress. I will be adding this in the next version along with customizing the output.</p>
<img src="http://feeds.feedburner.com/~r/anantgarg/~4/-SJdauG096Y" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://anantgarg.com/2009/03/20/wordpress-internet-explorer-8-accelerator/feed/</wfw:commentRss>
		<feedburner:origLink>http://anantgarg.com/2009/03/20/wordpress-internet-explorer-8-accelerator/</feedburner:origLink></item>
	</channel>
</rss><!-- Dynamic page generated in 1.156 seconds. --><!-- Page not cached by WP Super Cache. Could not get mutex lock. -->
