<?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:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>giancarlo.dimassa.net</title>
	
	<link>http://giancarlo.dimassa.net</link>
	<description>A web programmer's blog</description>
	<lastBuildDate>Sun, 01 Feb 2009 20:33:44 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</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/giancarlodimassa" /><feedburner:info uri="giancarlodimassa" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><creativeCommons:license>http://creativecommons.org/licenses/by/3.0/</creativeCommons:license><feedburner:emailServiceId>giancarlodimassa</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><feedburner:feedFlare href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Ffeeds.feedburner.com%2Fgiancarlodimassa" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Fgiancarlodimassa" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare href="http://feeds.my.aol.com/add.jsp?url=http%3A%2F%2Ffeeds.feedburner.com%2Fgiancarlodimassa" src="http://o.aolcdn.com/favorites.my.aol.com/webmaster/ffclient/webroot/locale/en-US/images/myAOLButtonSmall.gif">Subscribe with My AOL</feedburner:feedFlare><feedburner:feedFlare href="http://www.bloglines.com/sub/http://feeds.feedburner.com/giancarlodimassa" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Fgiancarlodimassa" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare href="http://fusion.google.com/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2Fgiancarlodimassa" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Fgiancarlodimassa" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><feedburner:feedFlare href="http://www.plusmo.com/add?url=http%3A%2F%2Ffeeds.feedburner.com%2Fgiancarlodimassa" src="http://plusmo.com/res/graphics/fbplusmo.gif">Subscribe with Plusmo</feedburner:feedFlare><feedburner:feedFlare href="http://www.thefreedictionary.com/_/hp/AddRSS.aspx?http%3A%2F%2Ffeeds.feedburner.com%2Fgiancarlodimassa" src="http://img.tfd.com/hp/addToTheFreeDictionary.gif">Subscribe with The Free Dictionary</feedburner:feedFlare><feedburner:feedFlare href="http://www.bitty.com/manual/?contenttype=rssfeed&amp;contentvalue=http%3A%2F%2Ffeeds.feedburner.com%2Fgiancarlodimassa" src="http://www.bitty.com/img/bittychicklet_91x17.gif">Subscribe with Bitty Browser</feedburner:feedFlare><feedburner:feedFlare href="http://www.newsalloy.com/?rss=http%3A%2F%2Ffeeds.feedburner.com%2Fgiancarlodimassa" src="http://www.newsalloy.com/subrss3.gif">Subscribe with NewsAlloy</feedburner:feedFlare><feedburner:feedFlare href="http://www.live.com/?add=http%3A%2F%2Ffeeds.feedburner.com%2Fgiancarlodimassa" src="http://tkfiles.storage.msn.com/x1piYkpqHC_35nIp1gLE68-wvzLZO8iXl_JMledmJQXP-XTBOLfmQv4zhj4MhcWEJh_GtoBIiAl1Mjh-ndp9k47If7hTaFno0mxW9_i3p_5qQw">Subscribe with Live.com</feedburner:feedFlare><feedburner:feedFlare href="http://mix.excite.eu/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2Fgiancarlodimassa" src="http://image.excite.co.uk/mix/addtomix.gif">Subscribe with Excite MIX</feedburner:feedFlare><feedburner:feedFlare href="http://www.yourminis.com/subscribe.aspx?u=http%3A%2F%2Ffeeds.feedburner.com%2Fgiancarlodimassa" src="http://www.yourminis.com/images/addtoyourminisbadge.gif">Subscribe with Yourminis.com</feedburner:feedFlare><feedburner:feedFlare href="http://download.attensa.com/app/get_attensa.html?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2Fgiancarlodimassa" src="http://www.attensa.com/blogs/attensa/WindowsLiveWriter/BadgeredintoBadges_10C02/attensa_feed_button5.gif">Subscribe with Attensa for Outlook</feedburner:feedFlare><feedburner:feedFlare href="http://www.webwag.com/wwgthis.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Fgiancarlodimassa" src="http://www.webwag.com/images/wwgthis.gif">Subscribe with Webwag</feedburner:feedFlare><feedburner:feedFlare href="http://hub.netomat.net/account/account.autoSubscribe.jspa?urls=http%3A%2F%2Ffeeds.feedburner.com%2Fgiancarlodimassa" src="http://www.netomat.net/blogger/images/icon_netomat_feedbutton.gif">Subscribe with netomat Hub</feedburner:feedFlare><feedburner:feedFlare href="http://www.podcastready.com/oneclick_bookmark.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Fgiancarlodimassa" src="http://www.podcastready.com/images/podcastready_button.gif">Subscribe with Podcast Ready</feedburner:feedFlare><feedburner:feedFlare href="http://www.flurry.com/pushRssFeed.do?r=fb&amp;url=http%3A%2F%2Ffeeds.feedburner.com%2Fgiancarlodimassa" src="http://www.flurry.com/images/flurry_rss_logo2.gif">Subscribe with Flurry</feedburner:feedFlare><feedburner:feedFlare href="http://www.wikio.com/subscribe?url=http%3A%2F%2Ffeeds.feedburner.com%2Fgiancarlodimassa" src="http://www.wikio.com/shared/img/add2wikio.gif">Subscribe with Wikio</feedburner:feedFlare><feedburner:feedFlare href="http://www.dailyrotation.com/index.php?feed=http%3A%2F%2Ffeeds.feedburner.com%2Fgiancarlodimassa" src="http://www.dailyrotation.com/rss-dr2.gif">Subscribe with Daily Rotation</feedburner:feedFlare><item>
		<title>Website localization in PHP episode 1: Translate strings</title>
		<link>http://feedproxy.google.com/~r/giancarlodimassa/~3/p297UFSUQGs/</link>
		<comments>http://giancarlo.dimassa.net/2009/02/01/website-localization-in-php-episode-1-translate-strings/#comments</comments>
		<pubDate>Sun, 01 Feb 2009 19:52:21 +0000</pubDate>
		<dc:creator>giancarlo</dc:creator>
				<category><![CDATA[Localization]]></category>
		<category><![CDATA[Pear]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://giancarlo.dimassa.net/2009/02/01/website-localization-in-php-episode-1-translate-strings/</guid>
		<description><![CDATA[Presenting a web site in multiple languages is a serious problem even when using dynamic server side technologies. In this article series, we'll try to figure out how to come out of common troubles. We'll start talking about string translation using a Pear module called Translation2.
 

Before doing that, allow me to make a premise.
Back [...]]]></description>
			<content:encoded><![CDATA[<p>Presenting a web site in <strong>multiple languages</strong> is a serious problem even when using <strong>dynamic server side technologies</strong>. In this article series, we'll try to figure out how to come out of common troubles. We'll start talking about <strong>string translation</strong> using a <a href="http://pear.php.net/"  target="_blank">Pear</a> module called <a target="_blank" href="http://pear.php.net/package/Translation2" >Translation2</a>.</p>
<p> <span id="more-173"></span>
</p>
<p>Before doing that, allow me to make a <strong>premise</strong>.</p>
<p>Back in the old days, we could <strong>copy</strong> our site structure <strong>as many times</strong> as the number of languages we had to work on, go deep into the pages and <strong>make necessary changes</strong>.</p>
<p>This worked well enough for <strong>static content</strong>, but had its <strong>downsides</strong>:</p>
<ul>
<li><font color="#55554e">There were problems <strong>updating</strong> content</font> </li>
<li><font color="#55554e">If you wanted to <strong>send</strong> the <strong>text</strong> to a <strong>translation service</strong>, you had to pull it from the pages <strong>yourself</strong></font> </li>
<li><font color="#55554e">When the text <strong>came back</strong> from the translator, you had to work <strong>again</strong> to insert it into the pages</font> </li>
<li><font color="#55554e">There isn't a <strong>standard way</strong> to format the text and many translation services <strong>don't understand HTML</strong>, so you had to exchange <strong>Word documents</strong> and manually convert the text into HTML again to preserve code <strong>cleaniness</strong></font> </li>
<li><font color="#55554e">There are problems with foreign <strong>character sets</strong>, you have to translate the <strong>HTML entities</strong> or convert between <strong>encodings</strong></font> </li>
<li><font color="#55554e">The first page on your site was nothing more than a <strong>list of languages</strong> and <strong>flags</strong>, that meant the <strong>first</strong> and <strong>most important</strong> page of all the site has <strong>no content</strong></font> </li>
<li><font color="#55554e">If you made a <strong>guess</strong> choosing your first page <strong>language</strong>, your other languages had to be <strong>manually selected</strong> by the user to make the switch.</font> </li>
<li><font color="#55554e">If you <strong>positioned certain elements</strong> into the text, you had to <strong>insert them manually again</strong> when you put the new content.</font> </li>
<li><font color="#55554e">There was no way for the <strong>translators to make the changes their selves</strong> without asking the webmaster, if they had not basic design skills.</font> </li>
<li><font color="#55554e">If they claimed such skills, <strong>you had to trust them enough</strong> to give them access the site source files and have faith in the fact they will not screw up anything.</font> </li>
</ul>
<p>The list can go on forever. Guess what? <strong>Dynamic websites are even worse!</strong> The problem is that most of the programmers build up websites <strong>pulling data</strong> from an <strong>archive</strong> (text files, a database connection, a service on the Intertubes) and <strong>put</strong> this materials into <strong><a href="http://giancarlo.dimassa.net/2007/07/06/how-to-separe-php-code-and-html-presentation-with-smarty-part-1/"  target="_blank">template</a> pages</strong>. When preparing or upgrading a site to be multilanguage, you had to have a way to pull <strong>different data</strong> from database <strong>for each idiom</strong>. Then you have to <strong>figure out</strong> how to translate the text into the templates.</p>
<p>There are many ways to solve these problems.</p>
<p><strong>You could manually change all the tables to hold the data for all idioms, and prepare a very big array that holds the strings you put into the template</strong>, put this big array in different files, one array for each language, and include the files as the user switches language.</p>
<p>This would be only the beginning, because then you should <strong>mantain</strong> all these arrays <strong>in sync</strong>. If you wanted to <strong>change</strong> this data from a control panel you have to <strong>put all the strings in a database</strong>. Manage language <strong>fallbacks</strong> (what if a string is not translated in a language?). What about <strong>caching</strong>? Then you had to <strong>write the procedures</strong> for <strong>querying, inserting and modifying</strong> such data.</p>
<p>Meet <a href="http://pear.php.net/package/Translation2"  target="_blank">Translation2</a>, the <a href="http://pear.php.net/"  target="_blank">Pear</a> module that does all of this for us, <strong>and much more</strong>. After installing it from the repository, we initialize it using this code:</p>
<blockquote><p>require_once 'Translation2.php';</p>
<p>$tr =&amp; Translation2::factory('mdb2',$db, array(      <br />'langs_avail_table'&#160;&#160;&#160;&#160;&#160;&#160;&#160; =&gt; 'translation_langs',       <br />'lang_id_col'&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; =&gt; 'id',       <br />'lang_name_col'&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; =&gt; 'name',       <br />'lang_meta_col'&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; =&gt; 'meta',       <br />'lang_errmsg_col'&#160;&#160;&#160;&#160;&#160;&#160;&#160; =&gt; 'error_text',       <br />'lang_encoding_col'&#160;&#160;&#160;&#160;&#160;&#160;&#160; =&gt; 'encoding',       <br />'strings_default_table'&#160;&#160;&#160; =&gt; 'translation_strings',&#160; <br /> 'string_id_col'&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; =&gt; 'ID',&#160; <br /> 'string_page_id_col'&#160;&#160;&#160; =&gt; 'page_id',&#160; <br /> 'string_text_col'&#160;&#160;&#160;&#160;&#160;&#160;&#160; =&gt; '%s',&#160; <br /> 'autoCleanCache'&#160;&#160;&#160;&#160;&#160;&#160;&#160; =&gt; true&#160; <br /> ) );</p>
</blockquote>
<p>Translation2 uses <a href="http://giancarlo.dimassa.net/2009/01/18/database-abstraction-in-php-with-mdb2/"  target="_blank">MDB2</a> as an archive foundation, so you have either to <strong>create</strong> a MDB2 connection, or <strong>reuse</strong> an existing one by passing the database object. As I presume you already use a database connection, I'll skip this part. Let's assume the database object is called $db. </p>
<p>Next we pass an array of <strong>parameters</strong>, specifying the <strong>gory details </strong>of the <strong>tables</strong> holding out our translation data. The example depicts two tables, <strong>translation_langs</strong> (that lists all <strong>languages</strong>) and <strong>translation_strings</strong> (that contains all the <strong>text</strong>). </p>
<p>The table that holds all the <strong>languages</strong> needs a column for the language <strong>id</strong> (like for example '<em>it</em>' or '<em>en</em>' or '<em>fr</em>'), <strong>name</strong> (like '<em>English</em>', or '<em>Espanol</em>', '<em>Italiano</em>',' '<em>Francais</em>'), <strong>meta</strong> (extended name, like '<em>American English</em>', usually matches the name), <strong>error text</strong> (when the string is not translated, for example '<em>not available</em>','<em>non disponibile</em>','<em>non traduit</em>') and encoding ('<em>iso-8859-1</em>','<em>utf-8</em>' and so on). You can call these columns and tables <strong>as you want</strong>, you just need to pass the names into the parameters array.</p>
<p>The <strong>strings table</strong> instead has an <strong>ID</strong> column (I put there an MD5 hash of the strings I want to be translated, but any text will do), the <strong>page ID</strong> column (so you separate and query strings for different pages), the <strong>text column</strong> for each language ('<em>%s</em>' in the example means the columns are called after the language ID) and any other parameter you wish to use.</p>
<p>To set the <strong>language ID</strong> and <strong>page ID</strong>, simply issue these two commands:</p>
<blockquote><p>$tr-&gt;setLang("it");     <br />$tr-&gt;setPageID("LOGIN_PAGE");</p>
</blockquote>
<p>You then start to initialize the so called '<strong><em>decorators</em></strong>', additional <strong>features</strong> of the translation system. The most useful ones are the <strong>Cache</strong> decorator (that uses the <a href="http://pear.php.net/package/Cache_Lite"  target="_blank">Cache Lite</a> Pear module) and the <strong>fallback</strong> decorator (to provide fallback strings in other languages).</p>
<p>An initialization sample of the Cache decorator follows:</p>
<blockquote><p>require_once &quot;Cache/Lite.php&quot;;&#160; <br /> $tr =&amp; $tr-&gt;getDecorator 'CacheLiteFunction');&#160; <br /> $tr-&gt;setOption('cacheDir', '/cache/lang/');&#160; <br /> $tr-&gt;setOption('lifeTime', 3600);</p>
</blockquote>
<p>with <em>getDecorator</em> you call the decorator. As you see we had to <strong>require</strong> the cache module file. Then we set the <strong>options</strong>: the <strong>time</strong> the system has to cache strings and the <strong>directory</strong> to use for caching. There are other options, feel free to explore.</p>
<p>The fallback system is even easier:</p>
<blockquote><p>$tr =&amp; $tr-&gt;getDecorator('Lang');      <br />$tr-&gt;setOption('fallbackLang', 'en');      <br />$tr-&gt;setOption('fallbackLang', 'it');</p>
</blockquote>
<p>that means "<em>if you can't find the string in the chosen language, fall back to english. If there isn't an english string, fall back to italian</em>". You can <strong>cascade languages</strong> as you wish. <strong>The function works on a string level</strong>, so you can have a complete translated website with only a pair of strings defaulted to another language.</p>
<p>To do queries you use commands like:</p>
<blockquote><p>$tr-&gt;get('PLEASE_LOGIN');</p>
</blockquote>
<p>to ask for a translated string,</p>
<blockquote><p>$tr-&gt;getRaw('PLEASE_LOGIN','LOGIN_PAGE');</p>
</blockquote>
<p>to ask all translations for a string specifying the Page ID,</p>
<blockquote><p>$tr-&gt;getLangs();</p>
</blockquote>
<p>to enumerate all languages, and so on.</p>
<p>You can at this point insert data into the tables yourself, or use the <strong>handy administration API</strong> that the translation system exposes. Simply initialize it (the parameters array is the same):</p>
<blockquote><p>$tr_admin = &amp;Translation2_Admin::factory([...continue the same way as the Translation2 constructor...]);</p>
</blockquote>
<p>Then you can <strong>issue commands</strong> like:</p>
<blockquote><p>$tr_admin -&gt;cleanCache();</p>
</blockquote>
<p>to <strong>clean the cache</strong></p>
<blockquote><p>$tr_admin-&gt;add("PLEASE_LOGIN', 'LOGIN_PAGE', array("en"=&gt;"Please insert your user name and password in the fields","it"=&gt;"Prego inserire il tuo nome utente e password"));</p>
</blockquote>
<p>to <strong>insert a new string</strong> into the database. </p>
<p>The API enables to easily <strong>add, modify and remove languages and strings</strong>.</p>
<p>If you want, Translation2 can use as a <strong>data source</strong> even an <strong>XML</strong> file or <strong>Gettext GNU .po / .mo compiled files</strong>. The decorators can also be used to <strong>convert between encodings</strong>.</p>
<p><strong>That's all, folks</strong>!</p>
<p>I hope you liked the article, stay tuned for the next episode of <strong>Web localization in PHP: language detection</strong> by subscribing to the <strong><a href="http://giancarlo.dimassa.net/feed/"  target="_blank">RSS</a> feed</strong>. </p>
<p>I would also be happy to answer to any <strong>questions</strong> you could have on the Translation2 module. In particular, I've tightly integrated it into a Markdown parser (a PHPBB code like language) and some plugins to provide realtime translations into <a href="http://giancarlo.dimassa.net/2007/07/06/how-to-separe-php-code-and-html-presentation-with-smarty-part-1/"  target="_blank"><strong>Smarty</strong></a><strong> templates</strong>.</p>
<p class="fbconnect_share"><fb:share-button class="url" href="http://giancarlo.dimassa.net/2009/02/01/website-localization-in-php-episode-1-translate-strings/" /></p>
<p><a href="http://feedads.g.doubleclick.net/~a/18hWvwTSA_ZUHXokxw4kaF7lEGA/0/da"><img src="http://feedads.g.doubleclick.net/~a/18hWvwTSA_ZUHXokxw4kaF7lEGA/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/18hWvwTSA_ZUHXokxw4kaF7lEGA/1/da"><img src="http://feedads.g.doubleclick.net/~a/18hWvwTSA_ZUHXokxw4kaF7lEGA/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=s8tKG98t"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=41" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=Or8nrAfd"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=Or8nrAfd" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=23iR7NPn"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=23iR7NPn" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=dw8pgwBw"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=dw8pgwBw" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=o5S9Rq7k"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=52" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=1wt9evqa"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=1wt9evqa" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=ls1JIqWi"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=80" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/giancarlodimassa/~4/p297UFSUQGs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://giancarlo.dimassa.net/2009/02/01/website-localization-in-php-episode-1-translate-strings/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://giancarlo.dimassa.net/2009/02/01/website-localization-in-php-episode-1-translate-strings/</feedburner:origLink></item>
		<item>
		<title>Database abstraction in PHP with MDB2</title>
		<link>http://feedproxy.google.com/~r/giancarlodimassa/~3/hMrnPPeY-fE/</link>
		<comments>http://giancarlo.dimassa.net/2009/01/18/database-abstraction-in-php-with-mdb2/#comments</comments>
		<pubDate>Sun, 18 Jan 2009 17:20:05 +0000</pubDate>
		<dc:creator>giancarlo</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[Pear]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://giancarlo.dimassa.net/2009/01/18/database-abstraction-in-php-with-mdb2/</guid>
		<description><![CDATA[Coming from a Windows environment, the first thing I noticed about PHP was the lack of a standardized way to access databases across vendors. That is, you want to connect to a MySQL server, you use the command mysql_connect(); , for PostgreSQL it is pg_connect(); , for Microsoft SQL server is mssql_connect(); .

On Windows, instead, [...]]]></description>
			<content:encoded><![CDATA[<p>Coming from a Windows environment, the first thing I noticed about PHP was the <strong>lack of a standardized way</strong> to access databases <strong>across vendors</strong>. That is, you want to connect to a MySQL server, you use the command mysql_connect(); , for PostgreSQL it is pg_connect(); , for Microsoft SQL server is mssql_connect(); .</p>
<p><span id="more-169"></span></p>
<p>On <strong>Windows</strong>, instead, there is a layer called Open Database Connectivity (<strong>ODBC</strong>) that translates the calls from the software to the database, providing a <strong>common interface</strong> and <strong>emulating missing features</strong>. Each vendor provides a <strong>specific driver</strong>, that plugs into the architecture. Via ODBC even a <strong>text file</strong> or an <strong>Excel spreadsheet</strong> can be <strong>connected</strong> and <strong>queried</strong> like it was a <strong>database</strong>.</p>
<p>It has been natural to me to start searching the net for a PHP equivalent of that layer. Shortly after starting I found the <strong>de facto standard</strong> for database abstraction in PHP, called <strong>MDB2</strong>. Even if it has <strong>not the flexibility</strong> of a real ODBC layer, it's <strong>lack of complexity</strong> made it very popular among fellow web programmers at first, just to find out it's <strong>ability to grow</strong> via <strong>extensions</strong> and performing in a <strong>relatively easy way</strong> a set of very <strong>powerful</strong> and <strong>demanding operations</strong>.</p>
<p>MDB2 is a <strong>Pear</strong> library, so you need to follow a procedure to install it. Refer to the <a target="_blank" href="http://pear.php.net" >Pear website</a> for details.</p>
<p>Just after <strong>including</strong> the MDB2 scripts into your PHP file</p>
<blockquote><p>&lt;?</p>
<p>require_once ("MDB2.php");</p>
<p>?&gt;</p></blockquote>
<p>you need toÂ  create an <strong>instance</strong> of the database class, like this</p>
<blockquote><p>&lt;?</p>
<p>$dsn = "your database type://your user name:your password@your server/your database name";</p>
<p>$db = MDB2::factory($dsn);</p>
<p>?&gt;</p></blockquote>
<p>so you have a <strong>connection string</strong> that explains how to connect to the database, and an <strong>object</strong> with multiple methods to perform database operations. You don't need to know other details about the database apart from the ones you put in the Data Source Name (<strong>DSN</strong>), everything else is handled by the MDB2 object.</p>
<p>After that, you perform <strong>vendor agnostic</strong> <strong>queries</strong> like this</p>
<blockquote><p>$result = $db-&gt;queryAll ($sql);</p></blockquote>
<p>But, as said, the real power behind MDB2 is it's <strong>extensions system</strong>, for example</p>
<blockquote><p>$db-&gt;loadModule('Extended');</p>
<p>$tablename = "customers";</p>
<p>$data = array("name"=&gt;"Bob","surname"=&gt;"Michael");</p>
<p>$result= $db-&gt;extended-&gt;autoExecute($tablename,$data, MDB2_AUTOQUERY_INSERT);</p></blockquote>
<p>I've effectively <strong>inserted</strong> a new customer into my table <strong>without writing a single word of SQL</strong>, and without <strong>worrying</strong> of the actual<strong> table structure</strong>.</p>
<p>The same applies to <strong>interrogation queries</strong>, like this</p>
<blockquote><p>$tablename = "customers";</p>
<p>$where = "`NAME` = 'BOB' AND `SURNAME` = 'MICHAEL'";</p>
<p>$result= $db-&gt;extended-&gt;autoExecute($tablename,null,<br />
MDB2_AUTOQUERY_SELECT,<br />
$where,null,true,true);</p></blockquote>
<p>the only SQL here is the <strong>where clause</strong>, everything else is managed by the library.</p>
<p>You can even store an <strong>XML backup</strong> of your entire database with a few commands</p>
<blockquote><p>$db_schema_options = array(<br />
'use_transactions' =&gt; true,<br />
'log_line_break' =&gt; '&lt;br&gt;',<br />
'idxname_format' =&gt; '%s',<br />
'debug' =&gt; true,<br />
'quote_identifier' =&gt; true,<br />
'force_defaults' =&gt; true,<br />
'portability' =&gt; true<br />
);</p>
<p>$schema = MDB2_Schema::factory($dsn, $db_schema_options);</p>
<p>$definition = $schema-&gt;getDefinitionFromDatabase();</p>
<p>$schema_dump = $schema-&gt;dumpDatabase($definition, array(<br />
'output_mode' =&gt; 'file',<br />
'output' =&gt; $dumpfile<br />
), MDB2_SCHEMA_DUMP_ALL);</p></blockquote>
<p>where $dumpfile is the <strong>file name</strong> you want your backup to go to.</p>
<p>The notion of <strong>schemas</strong> enables your application to <strong>seamless</strong> <strong>update</strong> the <strong>database</strong> across <strong>updates</strong>. The MDB2 can made <strong>automatic modifications</strong> of your table definitions to match the ones into the schema.</p>
<p>The library enables to use complex database functions, like <strong>transactions</strong>, to make your web applications <strong>secure</strong> and overcome stability problems when <strong>delicate procedures</strong> are performed, like the cart checkout on a e-commerce website, a money transfer, or any other situation where a <strong>power outage</strong> or a <strong>software interruption</strong> can lead to an <strong>partial update</strong>. Transactions <strong>group</strong> the <strong>operations</strong> so that any error will lead to a <strong>rollback</strong>, preserving the state your data was prior to updating.</p>
<p>If later in the process you want to <strong>change</strong> your database, for example from MySQL to Microsoft SQL server? Simply <strong>change</strong> your <strong>DSN</strong> from mysql to mssql and <strong>you are ready</strong>!</p>
<p>Did you like this article? Subscribe to my <em>transactional</em> feeds and leave a comment!</p>
<p class="fbconnect_share"><fb:share-button class="url" href="http://giancarlo.dimassa.net/2009/01/18/database-abstraction-in-php-with-mdb2/" /></p>
<p><a href="http://feedads.g.doubleclick.net/~a/1aZhzUlmFrEJq--gm9g1ey9Ya14/0/da"><img src="http://feedads.g.doubleclick.net/~a/1aZhzUlmFrEJq--gm9g1ey9Ya14/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/1aZhzUlmFrEJq--gm9g1ey9Ya14/1/da"><img src="http://feedads.g.doubleclick.net/~a/1aZhzUlmFrEJq--gm9g1ey9Ya14/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=HUVFDVad"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=41" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=cE97M5Tg"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=cE97M5Tg" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=2k6Gh00O"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=2k6Gh00O" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=JLuY4VY4"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=JLuY4VY4" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=yqzo7lB1"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=52" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=4trKQC1v"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=4trKQC1v" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=yFmee1ES"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=80" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/giancarlodimassa/~4/hMrnPPeY-fE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://giancarlo.dimassa.net/2009/01/18/database-abstraction-in-php-with-mdb2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://giancarlo.dimassa.net/2009/01/18/database-abstraction-in-php-with-mdb2/</feedburner:origLink></item>
		<item>
		<title>How to speed up JavaScript using the DOMready event</title>
		<link>http://feedproxy.google.com/~r/giancarlodimassa/~3/PDyFExOLqJI/</link>
		<comments>http://giancarlo.dimassa.net/2009/01/18/how-to-speed-up-javascript-using-the-domready-event/#comments</comments>
		<pubDate>Sun, 18 Jan 2009 12:35:00 +0000</pubDate>
		<dc:creator>giancarlo</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Prototype]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[dom]]></category>
		<category><![CDATA[domready]]></category>
		<category><![CDATA[load]]></category>
		<category><![CDATA[prototype]]></category>
		<category><![CDATA[speedup]]></category>

		<guid isPermaLink="false">http://giancarlo.dimassa.net/?p=160</guid>
		<description><![CDATA[One of the problems many JavaScript programmers meet when trying to produce their own page control is timing and event cluttering.

As always, let's use an example
function startslideshow() {
dosomething();
};
window.onload="startslideshow";
This makes the function startslideshow (an example used through the article) execute when the window loads. But what happens if another function wants to execute on window load [...]]]></description>
			<content:encoded><![CDATA[<p>One of the problems many JavaScript programmers meet when trying to produce their own page control is <strong>timing</strong> and <strong>event cluttering</strong>.</p>
<p><span id="more-160"></span></p>
<p>As always, let's use an example</p>
<blockquote><p>function startslideshow() {</p>
<p>dosomething();</p>
<p>};</p>
<p>window.onload="startslideshow";</p></blockquote>
<p>This makes the function <strong>startslideshow</strong> (an example used through the article) execute when the window loads. But what happens if <strong>another function</strong> wants to execute on window load <strong>too</strong>? If you added, <strong>later</strong> in the chain of scripts, the code</p>
<blockquote><p>window.onload="startanotherthing";</p></blockquote>
<p>the other function <strong>gets executed</strong>, but <strong>replaces the first one</strong>.</p>
<p>The <strong>same</strong> happens if you use this code</p>
<blockquote><p>&lt;body onload="startslideshow()"&gt;</p></blockquote>
<p>That means the function startslideshow will be executed after the <strong>body</strong> of the document has loaded.</p>
<p>If you instead write this code</p>
<blockquote><p>function startslideshow() {</p>
<p>dosomething();</p>
<p>};</p>
<p>startslideshow();</p></blockquote>
<p>You'll have a <strong>timing</strong> problem, because when executing startslideshow(), you will not be sure that the HTML of the page is <strong>completely loaded</strong> and available to the script. <strong>Don't even think</strong> using a <strong>setTimeout</strong> and try to <strong>guess</strong> how much time it takes. It would be a so <strong>bad</strong> solution police would come to your home and arrest you for 'bad programming'.</p>
<p>So, you are faced with these two problems:</p>
<ul>
<li><span style="color: #55554e;">You need the code to execute when the page loads</span></li>
<li><span style="color: #55554e;">You need the code to be self encapsulated, so you can plug and play it in the page without worrying it will disturb other code</span></li>
</ul>
<p>Nothing else? Indeed, <strong>there is more</strong>. If you execute the code on page loads, it means all of the page should be downloaded, even <strong>all the images</strong>. If you have a slideshow, and the user clicks on an image <strong>before all the others on the page are loaded</strong>, you will have problems because your initial function <strong>has not executed yet</strong>.</p>
<p>Enter the realm of <strong>DOMready</strong>. Many experienced programmers now let their code execute <strong>not</strong> when the <strong>entire page</strong> has <strong>loaded</strong>, but only when the <strong>Document Object Model (DOM)</strong> is <strong>ready</strong>, that is, all the HTML and javascript files have been <strong>loaded</strong> and are <strong>available</strong> to the <strong>JavaScript interpreter</strong>. The DOMready event fires way <strong>earlier</strong> during <strong>page rendering</strong>.</p>
<p>Unfortunately, the DOMready event is <strong>not very easily approachable</strong>, as <strong>browsers</strong> have <strong>slightly</strong> <strong>different</strong> implementation of the technique.</p>
<p>Chances are you already use a <strong>JavaScript framework</strong> to address cross browser incompatibilities.</p>
<p>If you use <strong>prototype.js</strong>, probably you access the window load event with this code</p>
<blockquote><p>Event.observe(window, 'load', startslideshow);</p></blockquote>
<p>replace startslideshow with your function. You can <strong>chain</strong> more Event.observe and prototype.js will <strong>take care by itself</strong> of executing the functions one after the other on window load.</p>
<p>To access the <strong>earlier</strong>, faster DOMready event, <strong>replace</strong> that code with</p>
<blockquote><p>document.observe("dom:loaded",startslideshow);</p></blockquote>
<p>the function is <strong>brand new</strong> and requires a version of <strong>prototype.js</strong> <strong>not lower than 1.6</strong> .</p>
<p>What if you use <strong>jQuery</strong>? The code is</p>
<blockquote><p>$(document).ready(startslideshow);</p></blockquote>
<p>That's all. Indeed, the code is not faster di per se, just the perception of responsiveness of the page is, because the code gets executed earlier.</p>
<p>If you use the debugger plugin <strong>Firebug</strong> for Firefox, in the <strong>Net</strong> panel of the latest version there are <strong>two vertical lines</strong> drawn. The <strong>first</strong> one detects the <strong>point in time the DOM is ready</strong>. The <strong>second</strong> one when the <strong>page is loaded</strong>.</p>
<p>The only things you're left to do is <strong>subscribe</strong> to my feeds and leave a <strong>comment</strong> if you liked the article, and... happy coding!</p>
<p class="fbconnect_share"><fb:share-button class="url" href="http://giancarlo.dimassa.net/2009/01/18/how-to-speed-up-javascript-using-the-domready-event/" /></p>
<p><a href="http://feedads.g.doubleclick.net/~a/AcpV3QYT65MfH51hgqqVZsCdhQI/0/da"><img src="http://feedads.g.doubleclick.net/~a/AcpV3QYT65MfH51hgqqVZsCdhQI/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/AcpV3QYT65MfH51hgqqVZsCdhQI/1/da"><img src="http://feedads.g.doubleclick.net/~a/AcpV3QYT65MfH51hgqqVZsCdhQI/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=TD4Rglqp"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=41" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=Yzx6nTJe"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=Yzx6nTJe" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=Kpi0kwRl"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=Kpi0kwRl" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=7aGJ9gLK"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=7aGJ9gLK" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=YjZLtoV6"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=52" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=F8d22mRL"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=F8d22mRL" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=PHtkNwSu"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=80" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/giancarlodimassa/~4/PDyFExOLqJI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://giancarlo.dimassa.net/2009/01/18/how-to-speed-up-javascript-using-the-domready-event/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://giancarlo.dimassa.net/2009/01/18/how-to-speed-up-javascript-using-the-domready-event/</feedburner:origLink></item>
		<item>
		<title>Website project management</title>
		<link>http://feedproxy.google.com/~r/giancarlodimassa/~3/9CtIRiQAlvw/</link>
		<comments>http://giancarlo.dimassa.net/2009/01/13/website-project-management/#comments</comments>
		<pubDate>Tue, 13 Jan 2009 12:05:12 +0000</pubDate>
		<dc:creator>giancarlo</dc:creator>
				<category><![CDATA[Management]]></category>
		<category><![CDATA[legal]]></category>
		<category><![CDATA[time]]></category>

		<guid isPermaLink="false">http://giancarlo.dimassa.net/2009/01/13/website-project-management/</guid>
		<description><![CDATA[In a preceding article we found out what can happen if a project, like a train, derails. "Dividi et impera", separe and conquer. The first thing to do, is split processes in smaller, more digestible pieces. At the end of each process, a written and confirmed documentation should be created, in a way that no [...]]]></description>
			<content:encoded><![CDATA[<p>In a preceding article we found out what can happen if a project, like a train, derails. "Dividi et impera", separe and conquer. The first thing to do, is <strong>split processes</strong> in <strong>smaller</strong>, more digestible <strong>pieces</strong>. At the end of each process, a <strong>written</strong> and <strong>confirmed</strong> documentation should be created, in a way that <strong>no</strong> one can <strong>go back</strong> on his steps and try to change what is already done. The payment can be divided into smaller sums, to ensure you get paid along the way, and gets the customer motivated. You also get the feedbacks right when it's needed.</p>
<p><span id="more-155"></span></p>
<p>This is the plan I've found effective enough to overcome management problems. Before starting, remember to keep each meeting one hour only, and no more than a meeting a week with the same client.</p>
<p>The <strong>initial briefing</strong>, that is from <strong>one </strong>to <strong>three meetings </strong>with the client, so you can <strong>hear their idea </strong>and <strong>sketch up a concept</strong>. After the first meeting, you produce at least <strong>two proposals</strong>, with <strong>time </strong>and <strong>compensation</strong>. Try <strong>not </strong>to <strong>talk</strong>, but to <strong>hear</strong>. The client <strong>has not chosen you</strong>, not yet. So any <strong>information</strong> disclosed now, will be <strong>passed </strong>to your <strong>competitor</strong>. Include any <strong>hidden</strong> costs, like <strong>hosting</strong>, <strong>copywriting</strong>, <strong>design </strong>and <strong>maintenance</strong>, like <strong>changes</strong>, <strong>updates </strong>and <strong>SEO</strong>. Be sure to be <strong>crystal clear </strong>about all costs after the project goes live.</p>
<p>As the customer agrees on a proposal, you produce a <strong>project</strong>, where you list any and all the feature of the web site. It's better to keep this document <strong>simple</strong>, as it doesn't force you to omit functions. It states the functions the project will end with, <strong>regardless of the path chosen</strong>. It's basically a <strong>guarantee </strong>to the client.</p>
<p>Accompanied to the project comes the <strong>standard contract</strong>. Do some <strong>research</strong>, and try to explore all the possibilities, <strong>protecting yourself </strong>in a reasonable way. In the contract you mention the project as an attachment. Have your contract perfected by a <strong>lawyer</strong>.</p>
<p><strong>Contract signage </strong>comes with a <strong>payment </strong>by the client. As a contract is a <strong>deal</strong>, <strong>you</strong> are <strong>obliged </strong>to respect your part of the deal, so should the <strong>client</strong>.</p>
<p><strong>The day after </strong>the agreement, look for the <strong>tasks the client should accomplish</strong>, that is a list of categories for an online store, the list of products with relative prices to put online, pieces of text regarding company presentation, and so on. Many times, <strong>the customer </strong>is the <strong>slowest </strong>of all the <strong>actors </strong>involved, so have him/her <strong>busy</strong> from day one.</p>
<p>Start producing <strong>paper sketches </strong>on the product, it's time to be creative. <strong>Don't</strong> let the <strong>computer</strong> in your way, it will probably only <strong>slow you down</strong>. Take a <strong>bloc notes </strong>with you, and if you manage multiple projects, put the name of the relative project, the date and the title,on top of each sheet.</p>
<p>At this stage, turn on the computer and <strong>start researching </strong>for <strong>user interface patterns </strong>on the web. That is, look at login forms, search boxes, product details pages, lightboxes, carousels, footers. Try to analyze which of these make a <strong>better user experience </strong>(the so called UX), <strong>faster</strong>, <strong>easier</strong>, more <strong>complete</strong>, <strong>responsive</strong> and <strong>enjoyable</strong>.</p>
<p>Using a <strong>mindmapping</strong> software, produce a complete <strong>sitemap</strong>. I prefer <a href="http://www.conceptdraw.com"  target="_blank">Conceptdraw Mindmap</a>. Don't leave out important <strong>service pages</strong>, like the login, register, password retrieval, legal and privacy information, the contact form. Make a <strong>meeting </strong>with the client and change the sitemap if needed. The map can be made of <strong>multiple sheets</strong>, so, for example on the second sheet you can list all the categories of an e-catalog, and list a single category page on the first sheet.</p>
<p>Open a <strong>prototyping program</strong>, like <a href="http://www.axure.com"  target="_blank">Axure RP</a>, and start drawing the <strong>wireframe </strong>of your application. Try to go deep into the <strong>interations</strong>. If you're producing an e-commerce website, you should be able to actually see a product put into the cart and the entire checkout process, for example. Have another <strong>meeting </strong>with the client, have him/her <strong>check out </strong>the HTML prototype, make the suggested modifications. Let the program <strong>autogenerate</strong> a specification document (the <strong>spec</strong>).</p>
<p>Attach a print of your complete <strong>sitemap</strong> and <strong>specification document </strong>to a document with the <strong>date</strong>, have the client <strong>sign it</strong> for approval. This makes a <strong>milestone</strong>, you cannot go back on already done work without the client paying more.</p>
<p>Give the same documents to the <strong>designer</strong>, or if you do the design yourself or are the designer, it's time to fire up your <strong>graphic program</strong>.</p>
<p>While you <strong>wait </strong>for the graphics to be done, the same applies to the <strong>developer</strong>. If you are the same person, better have the graphics before start coding.</p>
<p>When the graphics are done and from time to time, <strong>call</strong> the <strong>client</strong> and <strong>ask</strong> for any task he/she <strong>had</strong> to do, that is, any <strong>material</strong> he/she had to produce, and that you asked from <strong>day one</strong>. Have a <strong>meeting</strong>, review the graphic design with the client, make the suggested modifications. If you're the graphic designer, <strong>send </strong>the <strong>modifications</strong> to the <strong>developer</strong>.</p>
<p><strong>Print </strong>the <strong>design</strong> and any <strong>material</strong> produced, attach to a document with the <strong>date</strong>, have the client <strong>sign</strong> it. Ask for a part of the <strong>payment</strong> of the entire web site. This is another <strong>milestone</strong>, also you should have about <strong>50%</strong> of all the <strong>money</strong> now, and <strong>half of all the work done</strong>, <strong>confirmed </strong>by the client, so you can't go back.</p>
<p>If you're the <strong>developer</strong>, start <strong>chopping</strong> the design into HTML. <strong>Refer</strong> to the <strong>prototype</strong> and the <strong>specs</strong>, there should be <strong>all</strong> the material and design elements to complete each interation, you only need to <strong>focus</strong> on <strong>programming</strong>. Use a <strong>test server</strong>. By the way, use <strong>progressive enhancement</strong>, make sure everything works without <strong>javascript</strong>, then start <strong>leveraging </strong>the interface. Make sure to <strong>complete </strong>the <strong>administration control panel</strong>.</p>
<p><strong>Show</strong> the site to the customer, on the <strong>test server</strong>. Make note of the <strong>modifications</strong> he/she asks for, <strong>agree </strong>on the <strong>price </strong>and <strong>factuality</strong> of any changes after the steps above.</p>
<p>Do the modifications as <strong>fast </strong>as possible, to dodge the possibility of the client <strong>changing</strong> <strong>his/her mind </strong>and looking for more changes. Ask for a <strong>payment</strong>, you should have <strong>three quarters </strong>of the sum now.</p>
<p><strong>Leave </strong>the <strong>site </strong>on the <strong>test server</strong>. The client should be able to look at the work done live. <strong>Start testing</strong>, look for <strong>inconsistencies </strong>between <strong>browsers</strong>. <strong>It's not possible to produce modifications anymore at this stage</strong>. Produce <strong>training documentation </strong>on the administration of the site. I prefer <a href="http://www.techsmith.com"  target="_blank">Techsmith Camtasia</a> because you can a record a <strong>screencast</strong>, instead of writing pages and pages of documentation.</p>
<p>If the site is <strong>closed source </strong>and the <strong>contract </strong>permits this, <strong>encrypt </strong>the source code. Make a <strong>DVD </strong>with the <strong>source code</strong>, the <strong>graphics</strong>, all the <strong>documents</strong> and the <strong>screencasts</strong>, <strong>compressed</strong> in <strong>ZIP </strong>form with a <strong>password</strong>.</p>
<p>Ask the client for the <strong>last payment</strong>. <strong>After </strong>you're sure you received the payment, put the site <strong>live</strong>, and <strong>send</strong> or give the client the DVD. <strong>Store</strong> the DVD, <strong>paired </strong>with <strong>another one</strong> with any any <strong>intermediate material</strong> used for future changes, and <strong>unencrypted </strong>source code.</p>
<p>Repeat <strong>again </strong>and <strong>again</strong>.</p>
<p>Have you got any comments or questions?</p>
<p class="fbconnect_share"><fb:share-button class="url" href="http://giancarlo.dimassa.net/2009/01/13/website-project-management/" /></p>
<p><a href="http://feedads.g.doubleclick.net/~a/FGQIFCVddp9qLiyuJz24Z-SHNgM/0/da"><img src="http://feedads.g.doubleclick.net/~a/FGQIFCVddp9qLiyuJz24Z-SHNgM/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/FGQIFCVddp9qLiyuJz24Z-SHNgM/1/da"><img src="http://feedads.g.doubleclick.net/~a/FGQIFCVddp9qLiyuJz24Z-SHNgM/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=e8xbgwKx"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=41" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=6DfkIrkO"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=6DfkIrkO" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=LM3gYDET"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=LM3gYDET" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=YGpOTr03"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=YGpOTr03" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=fpqfcnON"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=52" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=SFIEWPZi"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=SFIEWPZi" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=LFfMzJbg"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=80" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/giancarlodimassa/~4/9CtIRiQAlvw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://giancarlo.dimassa.net/2009/01/13/website-project-management/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://giancarlo.dimassa.net/2009/01/13/website-project-management/</feedburner:origLink></item>
		<item>
		<title>When a website project goes wrong</title>
		<link>http://feedproxy.google.com/~r/giancarlodimassa/~3/XTU8qyHFCeY/</link>
		<comments>http://giancarlo.dimassa.net/2009/01/13/when-a-website-project-goes-wrong/#comments</comments>
		<pubDate>Tue, 13 Jan 2009 07:07:51 +0000</pubDate>
		<dc:creator>giancarlo</dc:creator>
				<category><![CDATA[Management]]></category>
		<category><![CDATA[money]]></category>
		<category><![CDATA[time]]></category>

		<guid isPermaLink="false">http://giancarlo.dimassa.net/?p=147</guid>
		<description><![CDATA[The first thing many web designers do when asked for a new website is fire up Dreamweaver and start coding.
Managing even a small project, however, requires some planning beforehand, to overcome some series of unfortunate events that may happen. 
 
Some of these events are your fault: you're late on schedule, don't test your web [...]]]></description>
			<content:encoded><![CDATA[<p>The first thing many web designers do when asked for a new website is <strong>fire up Dreamweaver</strong> and <strong>start coding</strong>.</p>
<p><strong>Managing</strong> even a <strong>small</strong> project, however, requires some <strong>planning</strong> beforehand, to overcome some series of unfortunate <strong>events</strong> that may happen. </p>
<p> <span id="more-147"></span>
<p><strong>Some</strong> of these events are <strong>your fault</strong>: you're <strong>late</strong> on schedule, don't <strong>test</strong> your web site thoroughly, lose <strong>interest</strong> over time on the job.</p>
<p>Some others are the <strong>client's fault</strong>: they want to <strong>change</strong> things when it's too late, they don't <strong>pay</strong> in time or don't pay at all, demand exhausting <strong>meetings</strong> over details you're not even <strong>supposed</strong> to know. </p>
<p>Then come the <strong>partners fault</strong>: if you are a developer, chances are you prefer to team up with a <strong>graphic designer</strong>, who produce wonderful website designs, but clunky and <strong>unusable</strong>, with large visual content and maybe almost no text at all. If you are a graphic designer, you strive to push a really good product, but your <strong>developer</strong> chops it up and it becomes butt <strong>ugly</strong>, you need to design new parts of the site and redraw some others. </p>
<p>There come the <strong>technical problems</strong>, like <strong>bugs</strong>, <strong>incompatibilities</strong> between <strong>browsers</strong>, the control panel doesn't work, the <strong>client tests</strong> the site on a Windows 2000 or <strong>older computer</strong> full of viruses and spyware, with Internet Explorer 5 on it on a 640k DSL connection shared with two hundred other people downloading from emule (I'm not kidding).</p>
<p><strong>You only want to do the thing you like best</strong>, that is <strong>coding</strong> or <strong>drawing</strong> <strong>beautiful</strong> and <strong>standard compliant websites</strong>.</p>
<p><strong>Each</strong> of these <strong>reiterations </strong>has other <strong>disadvantages</strong>, I call them <strong>task serialization</strong> and <strong>latency</strong>. </p>
<p>Each piece of work depends on others pieces, and <strong>without planning, much of the time you or others sit idle</strong> trough all the project time because other people need to do something. You thought having more people meant reducing the time by dividing it, but <strong>the work that can be done in parallel</strong>, that means in the same timeframe by more than one person, <strong>is not that much</strong>.</p>
<p>The <strong>task latency</strong> means a <strong>one hour task will get done in two weeks</strong>, just because of a missed telephone call or holidays or contingencies. </p>
<p>Sometimes the <strong>client </strong>wants to save money by writing his own copy or doing the graphics <strong>itself</strong>. 80% of the time, the customer <strong>doesn't provide the requested work in promised time</strong>, and if he/she does it, it's <strong>sub par</strong> with the rest of the project, as it is done unprofessionally.</p>
<p>At the end of this <strong>mess</strong>, you have all your <strong>materials </strong>and open up Dreamweaver or notepad or your choice of HTML editor, <strong>starting as fast as you can </strong>to <strong>redraw </strong>and <strong>rewrite</strong> parts upon parts of your initial work, because <strong>the customer threats</strong> to <strong>sue </strong>you or <strong>abandon </strong>the <strong>project </strong>if it is not done in a timely fashion.</p>
<p>The <strong>code</strong> and <strong>graphics</strong> you do, at this point, are <strong>not accurate</strong> and <strong>perfect</strong>, as the <strong>pressure </strong>of the work is too much and you simply don't have <strong>time</strong> to apply the <strong>finishes</strong>. <strong>Testing</strong> is reduced to <strong>minimum</strong>, and many <strong>bugfixes</strong> are solved by applying <strong>patches</strong> over code. <strong>You even find yourself making decisions outside your area of expertise</strong>, like if you are the developer on color, aspect and position of elements, because it would take too much time if asked to the designer to do. You're a designer, but you start writing the text materials to fill in the voids.</p>
<p>Next article I'll provide useful information on how to solve these common problems.</p>
<p>Do you recognize some situations that happened to you? I would be happy to receive comments.</p>
<p class="fbconnect_share"><fb:share-button class="url" href="http://giancarlo.dimassa.net/2009/01/13/when-a-website-project-goes-wrong/" /></p>
<p><a href="http://feedads.g.doubleclick.net/~a/9TfMBMb41m0_93C0vPjxedkzs7M/0/da"><img src="http://feedads.g.doubleclick.net/~a/9TfMBMb41m0_93C0vPjxedkzs7M/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/9TfMBMb41m0_93C0vPjxedkzs7M/1/da"><img src="http://feedads.g.doubleclick.net/~a/9TfMBMb41m0_93C0vPjxedkzs7M/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=ox5wmzPc"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=41" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=DmNVytUz"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=DmNVytUz" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=NMP0SXxX"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=NMP0SXxX" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=WkIaeM0q"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=WkIaeM0q" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=cPeiPwdW"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=52" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=qLjrtSHI"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=qLjrtSHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=0QBmfU3d"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=80" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/giancarlodimassa/~4/XTU8qyHFCeY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://giancarlo.dimassa.net/2009/01/13/when-a-website-project-goes-wrong/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://giancarlo.dimassa.net/2009/01/13/when-a-website-project-goes-wrong/</feedburner:origLink></item>
		<item>
		<title>What is del.icio.us</title>
		<link>http://feedproxy.google.com/~r/giancarlodimassa/~3/E1pPaRCqGHk/</link>
		<comments>http://giancarlo.dimassa.net/2007/07/16/what-is-delicious/#comments</comments>
		<pubDate>Mon, 16 Jul 2007 12:40:23 +0000</pubDate>
		<dc:creator>giancarlo</dc:creator>
				<category><![CDATA[Social Networks]]></category>
		<category><![CDATA[bookmark]]></category>
		<category><![CDATA[del.icio.us]]></category>
		<category><![CDATA[links]]></category>
		<category><![CDATA[search]]></category>

		<guid isPermaLink="false">http://giancarlo.dimassa.net/2007/07/16/what-is-delicious/</guid>
		<description><![CDATA[As it's about page says, del.icio.us is a collection of bookmarks, yours and the collectivity ones. You use it to pin your favourite sites and organize them not in folders anymore but by tags. By saving your links on a remote server, you don't have to import/export/backup them, they are always there, even from another [...]]]></description>
			<content:encoded><![CDATA[<p>As it's <a target="_blank" href="http://del.icio.us/about/" >about </a>page says, <a target="_blank" href="http://del.icio.us" >del.icio.us</a> is a <strong>collection of bookmarks</strong>, yours and the collectivity ones. You use it to <strong>pin your favourite sites</strong> and <strong>organize</strong> them <strong>not in folders</strong> anymore but by tags. By saving your links on a remote server, you don't have to import/export/backup them, they are always there, even from another computer.</p>
<p><span id="more-39"></span></p>
<p>It is extremely useful if you want to:</p>
<ul>
<li>Organize all your bookmarks in a useful way</li>
<li>Have a link under the attention of a friend or coworker</li>
<li>Discover new links by looking at what other people are bookmarking</li>
<li>Assign a link the collective tags, so you don't have to write them yourself</li>
<li>Have a network of friends, whose links are more relevant for your activies.</li>
<li>Add a person's feed to your RSS reader</li>
</ul>
<p>How to access to all this information goodness? You start from the <a target="_blank" href="http://del.icio.us" >del.icio.us homepage</a>, create a free account by clicking on "get started". Fill the form and you are ready to go.<br />
Now, you can add your links from the del.icio.us website, or by using a third party tool. The service itself promotes an extension for Firefox, but I suggest to use <a target="_blank" href="https://addons.mozilla.org/it/firefox/addon/3615" >the one provided by Yahoo! Inc.</a> because it is more feature complete.<br />
Upon installation, the extension starts to import all your existing bookmarks into your del.icio.us account, automatically tagging them. Let it be and wait for a pair of minutes. Next operation in line is to hide your existing bookmarks interface to use only the del.icio.us one. On the upper part of the Firefox windows you'll notice, amongst others, a del.icio.us menu. From there, the last voice is 'Hide bookmarks menu'. Now you can add a bookmark clicking the 'tag' icon or by pressing CTRL+D, browse bookmarks clicking the 'search your bookmarks' icon or by pressing CTRL+B, or do the same actions from the menu.<br />
When you add a bookmark, a new window will appear, with Recommended, Network and Popular tags.<br />
Clicking on these words will tag the link, the recommended tags are from your existing link library, while I sometimes find the popular ones to be more fitting. If you are unsure, better more than less, you can refine these later. If nobody has the link in his del.icio.us (this means you're the first to discover this resource, in the network) you have to manually add the tags. Remember, tags are separated by spaces, so you can't write for example 'web 2.0', but 'web2.0', not 'New York' but 'NewYork'.<br />
To exchange links with your friends (they should have a del.icio.us account too) simply click on the Network tags of your friends. When you're ready, you press 'Save' and the bookmark will be saved.<br />
Adding a friend is done by going on your friend del.icio.us site, then clicking on the link 'add ... to your network'. Many blogs (like this) have ready made links to add an article to del.icio.us (if you don't have the extension installed) and even add a person to your network (like my <a target="_blank" href="http://del.icio.us/network?add=giank" >Add me to your network</a> link).<br />
To check the links inbox, from the del.icio.us menu, choose del.icio.us website, then Links for you. Be sure to have a look to Popular and Recent bookmarks, there are very interesting things there. Nearly all the pages can be formatted as RSS feeds to use in your favourite aggregator.</p>
<p class="fbconnect_share"><fb:share-button class="url" href="http://giancarlo.dimassa.net/2007/07/16/what-is-delicious/" /></p>
<p><a href="http://feedads.g.doubleclick.net/~a/FMmhTwXb9NDf5P3ZvjF2YtN6Eek/0/da"><img src="http://feedads.g.doubleclick.net/~a/FMmhTwXb9NDf5P3ZvjF2YtN6Eek/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/FMmhTwXb9NDf5P3ZvjF2YtN6Eek/1/da"><img src="http://feedads.g.doubleclick.net/~a/FMmhTwXb9NDf5P3ZvjF2YtN6Eek/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=FzZkjx9t"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=41" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=xlrhKr6Y"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=xlrhKr6Y" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=FnU58212"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=FnU58212" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=jMB6TYZO"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=jMB6TYZO" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=L43OiuDp"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=52" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=cgzBfRHu"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=cgzBfRHu" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=Tl59bQL0"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=80" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/giancarlodimassa/~4/E1pPaRCqGHk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://giancarlo.dimassa.net/2007/07/16/what-is-delicious/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://giancarlo.dimassa.net/2007/07/16/what-is-delicious/</feedburner:origLink></item>
		<item>
		<title>Elastic and bouncing transitions in scriptaculous</title>
		<link>http://feedproxy.google.com/~r/giancarlodimassa/~3/I9fItyeXVTQ/</link>
		<comments>http://giancarlo.dimassa.net/2007/07/11/elastic-and-bouncing-transitions-in-scriptaculous/#comments</comments>
		<pubDate>Wed, 11 Jul 2007 05:46:09 +0000</pubDate>
		<dc:creator>giancarlo</dc:creator>
				<category><![CDATA[Scriptaculous]]></category>
		<category><![CDATA[elastic]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[prototype]]></category>
		<category><![CDATA[transitions]]></category>

		<guid isPermaLink="false">http://giancarlo.dimassa.net/2007/07/11/elastic-and-bouncing-transitions-in-scriptaculous/</guid>
		<description><![CDATA[Scriptaculous has a lot of transitions, but in some situations, you want to sprinkle up a dull animation, applying a different, custom transition type.
Back in 2003, Robert Penner wrote the easing equations, a set of math formulas in Flash Actionscript released under the BSD license, that simulate various types of physical effects, the most notable [...]]]></description>
			<content:encoded><![CDATA[<p>Scriptaculous has a lot of transitions, but in some situations, you want to sprinkle up a dull animation, applying a different, custom transition type.<br />
Back in 2003, <a target="_blank" href="http://www.robertpenner.com" >Robert Penner</a> wrote the <a target="_blank" href="http://www.robertpenner.com/easing/penner_easing_as2.zip" >easing equations</a>, a set of math formulas in Flash Actionscript released under the BSD license, that simulate various types of physical effects, the most notable are the overshooting elastic and bouncing ones. For an example, <a target="_blank" href="http://www.robertpenner.com/easing/easing_demo.html" >look at the demo here</a>.<br />
Three years later, <a href="mailto:kendsnyderREMOVETHIS@gmail.com">Ken Snyder</a> adapted the equations for scriptaculous, enabling builtin and custom animations to use these new nice effects as transitions. However the Penner easing equations were highly configurable, where instead in the Snyder ones you can only set the duration, because the other parameters are fixed in the source code. Also, not all (indeed, only a few) of the transitions have been ported, and their names have been changed too.</p>
<p><span id="more-29"></span></p>
<p>To use these new transitions, the easiest way is to open the effects.js file inside the src folder of your scriptaculous library, and add these lines at the end:</p>
<blockquote><p>/*<br />
transitions.js</p>
<p>Based on Easing Equations v2.0<br />
(c) 2003 Robert Penner, all rights reserved.<br />
This work is subject to the terms in http://www.robertpenner.com/easing_terms_of_use.html</p>
<p>Adapted for Scriptaculous by Ken Snyder (kendsnyder ~at~ gmail ~dot~ com) June 2006<br />
*/</p>
<p>/*<br />
Overshooting Transitions<br />
*/<br />
// Elastic (adapted from "EaseOutElastic")<br />
Effect.Transitions.Elastic = function(pos) {<br />
return -1*Math.pow(4,-8*pos) * Math.sin((pos*6-1)*(2*Math.PI)/2) + 1;<br />
};<br />
// SwingFromTo (adapted from "BackEaseInOut")<br />
Effect.Transitions.SwingFromTo = function(pos) {<br />
var s = 1.70158;<br />
if ((pos/=0.5) &lt; 1) return 0.5*(pos*pos*(((s*=(1.525))+1)*pos - s));<br />
return 0.5*((pos-=2)*pos*(((s*=(1.525))+1)*pos + s) + 2);<br />
};<br />
// SwingFrom (adapted from "BackEaseIn")<br />
Effect.Transitions.SwingFrom = function(pos) {<br />
var s = 1.70158;<br />
return pos*pos*((s+1)*pos - s);<br />
};<br />
// SwingTo (adapted from "BackEaseOut")<br />
Effect.Transitions.SwingTo = function(pos) {<br />
var s = 1.70158;<br />
return (pos-=1)*pos*((s+1)*pos + s) + 1;<br />
};</p>
<p>/*<br />
Bouncing Transitions<br />
*/<br />
// Bounce (adapted from "EaseOutBounce")<br />
Effect.Transitions.Bounce = function(pos) {<br />
if (pos &lt; (1/2.75)) {<br />
return (7.5625*pos*pos);<br />
} else if (pos &lt; (2/2.75)) {<br />
return (7.5625*(pos-=(1.5/2.75))*pos + .75);<br />
} else if (pos &lt; (2.5/2.75)) {<br />
return (7.5625*(pos-=(2.25/2.75))*pos + .9375);<br />
} else {<br />
return (7.5625*(pos-=(2.625/2.75))*pos + .984375);<br />
}<br />
};<br />
// BouncePast (new creation based on "EaseOutBounce")<br />
Effect.Transitions.BouncePast = function(pos) {<br />
if (pos &lt; (1/2.75)) {<br />
return (7.5625*pos*pos);<br />
} else if (pos &lt; (2/2.75)) {<br />
return 2 - (7.5625*(pos-=(1.5/2.75))*pos + .75);<br />
} else if (pos &lt; (2.5/2.75)) {<br />
return 2 - (7.5625*(pos-=(2.25/2.75))*pos + .9375);<br />
} else {<br />
return 2 - (7.5625*(pos-=(2.625/2.75))*pos + .984375);<br />
}<br />
};</p>
<p>/*<br />
Gradual Transitions<br />
*/<br />
// EaseFromTo (adapted from "Quart.EaseInOut")<br />
Effect.Transitions.EaseFromTo = function(pos) {<br />
if ((pos/=0.5) &lt; 1) return 0.5*Math.pow(pos,4);<br />
return -0.5 * ((pos-=2)*Math.pow(pos,3) - 2);<br />
};<br />
// EaseFrom (adapted from "Quart.EaseIn")<br />
Effect.Transitions.EaseFrom = function(pos) {<br />
return Math.pow(pos,4);<br />
};<br />
// EaseTo (adapted from "Quart.EaseOut")<br />
Effect.Transitions.EaseTo = function(pos) {<br />
return Math.pow(pos,0.25);<br />
};</p></blockquote>
<p>That's all you need to do to add the transitions. To use them, simply add the transition to the effect, for example</p>
<blockquote><p>transition:Effect.Transitions.Bounce</p></blockquote>
<p>like here</p>
<blockquote><p>new Effect.BlindDown(el,{duration:2, transition:Effect.Transitions.Bounce});</p></blockquote>
<p>note that as some time is spent accelerating and decelerating the element, the animation will seem to "endure" less, it will seem to be faster, so it's better to at least double the duration time. Also I suggest tweaking the transitions parameters for further personalization.<br />
As you can see skimming trough the code, the effects name (case sensitive) are: Elastic, SwingFromTo, SwingFrom, SwingTo, Bounce, BouncePast, EaseFromTo, EaseFrom and EaseTo.<br />
Remember that if you upgrade your scriptaculous, you'll need to paste again this code at the end of the effects.js file. You could also consider adding it to your code, as it is not really as important where it is, as soon as the new transitions are loaded after the effects.js code. A third option can be creating a pennier.js file in the scriptaculous folder and change the script tag to add it, as an example</p>
<blockquote><p>&lt;script src="/lib/scriptaculous/src/scriptaculous.js?load=effects,pennier" type="text/javascript"&gt;&lt;/script&gt;</p></blockquote>
<p>but if you prefer to aggregate as much files as possible to reduce network delays during page loads, that's not you'll want to do.<br />
Ah, if you use Flash and plan adding the tweening Pennier equations to your actionscripts, check out his book "Programming Macromedia Flash MX", part III:Dynamic Visuals, chapter 7:Motion, Tweening, and Easing. The book details are available on <a target="_blank" href="http://www.robertpenner.com/" >his website</a>, where the chapter is freely downloadable <a target="_blank" href="http://www.robertpenner.com/easing/penner_chapter7_tweening.pdf" >here</a>.<br />
In a forthcoming article, I'll discuss about an animation library (the technical name is "tween sequencer") for Flash that incorporates the Robert Penner tweens, think of it as the scriptaculous for Flash: <a target="_blank" href="http://www.mosessupposes.com/Fuse/" >The FUSE Kit</a>.</p>
<p class="fbconnect_share"><fb:share-button class="url" href="http://giancarlo.dimassa.net/2007/07/11/elastic-and-bouncing-transitions-in-scriptaculous/" /></p>
<p><a href="http://feedads.g.doubleclick.net/~a/qbeh0B1_1vuMCM-v4hZ9gnv0UeE/0/da"><img src="http://feedads.g.doubleclick.net/~a/qbeh0B1_1vuMCM-v4hZ9gnv0UeE/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/qbeh0B1_1vuMCM-v4hZ9gnv0UeE/1/da"><img src="http://feedads.g.doubleclick.net/~a/qbeh0B1_1vuMCM-v4hZ9gnv0UeE/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=pCT5iFUV"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=41" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=wJUGhCnh"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=wJUGhCnh" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=7EQEV25V"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=7EQEV25V" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=C8F5JADN"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=C8F5JADN" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=vSGsEf3N"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=52" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=PTGD1amR"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=PTGD1amR" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=DhovTYqF"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=80" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/giancarlodimassa/~4/I9fItyeXVTQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://giancarlo.dimassa.net/2007/07/11/elastic-and-bouncing-transitions-in-scriptaculous/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://giancarlo.dimassa.net/2007/07/11/elastic-and-bouncing-transitions-in-scriptaculous/</feedburner:origLink></item>
		<item>
		<title>How to separe PHP code and HTML presentation with Smarty, part 2: installation</title>
		<link>http://feedproxy.google.com/~r/giancarlodimassa/~3/eKH-tFHcgpo/</link>
		<comments>http://giancarlo.dimassa.net/2007/07/10/how-to-separe-php-code-and-html-presentation-with-smarty-part-2-installation/#comments</comments>
		<pubDate>Tue, 10 Jul 2007 12:05:23 +0000</pubDate>
		<dc:creator>giancarlo</dc:creator>
				<category><![CDATA[Smarty]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[presentation]]></category>
		<category><![CDATA[template]]></category>

		<guid isPermaLink="false">http://giancarlo.dimassa.net/2007/07/10/how-to-separe-php-code-and-html-presentation-with-smarty-part-2-installation-2/</guid>
		<description><![CDATA[Note: this is article is cut in parts, this is the the second one. Visit the first one if you don't know what Smarty is and why to use it. The post supposes basic PHP programming skills.
Ok, last time we examined the goods and bads of using Smarty, this time we'll install it.

First, make sure [...]]]></description>
			<content:encoded><![CDATA[<p>Note: this is article is cut in parts, this is the the second one. <a href="http://giancarlo.dimassa.net/2007/07/06/how-to-separe-php-code-and-html-presentation-with-smarty-part-1/" >Visit the first one</a> if you don't know what <a target="_blank" href="http://smarty.php.net" >Smarty</a> is and why to use it. The post supposes basic PHP programming skills.</p>
<p>Ok, last time we examined the goods and bads of using Smarty, this time we'll install it.</p>
<p><span id="more-27"></span></p>
<p>First, make sure you got the right PHP version, it needs at least the 4.0.6. This can be seen by writing an empy page and writing in it, then calling that page.</p>
<p>Next, download the <a target="_blank" href="http://smarty.php.net/download.php" >latest stable release</a> from the smarty web site.</p>
<p>I prefer to have all my external libraries and programs in the /lib folder, I strongly racommend it, so decompress the source in the /lib/smarty folder.</p>
<p>I group all my site files in the /site folder, that's very useful too, so create a site folder and put a php file in it, let's call it page.php.</p>
<p>First line in you should configure and initialize smarty, then put your commands to produce some data, and at the end call smarty to output the data in the templates.</p>
<p>The reduced minimal sample is</p>
<blockquote><p>&lt;?<br />
require ('/absolute/path/to/your/website/root/lib/smarty/Smarty.class.php');<br />
$smarty = new Smarty;<br />
?&gt;</p></blockquote>
<p>Keep an eye on capitals, as the code is case sensitive! This sample initializes adds the smarty code on top of your php file by inclusion. You'll need the absolute path to your smarty class, substitute as needed.</p>
<p>The smarty code defines a class, it explains to php what a "Smarty" is.<br />
Second line actually defines a variable, called $smarty. This variable points to a new object called Smarty. An object is an "istantiation" of a class, speaking simple an "item" made by following the "instructions". You can have more than a Smarty object in a php file, but rarely you need to.<br />
This Smarty item (let's call it object again and from now on) has properties (attributes) and can execute commands.</p>
<p>Now let's configure a thing or two. As I find it boring to always go checking out the document and site root and substituting, before going on let's write some code to autodetect this.</p>
<p>add this code on top</p>
<blockquote><p>define('DR', $_SERVER['DOCUMENT_ROOT']);</p></blockquote>
<p>Now the constant DR contains our document root, we can then modify the subsequent line this way:</p>
<blockquote><p>require (DR . '/lib/smarty/Smarty.class.php');</p></blockquote>
<p>each time you need the absolute path to your document root, you can refer to it by using DR.</p>
<p>Ok, this is all good, but if you load the script in the browser, it spits out a blank page.</p>
<p>What remains to do? Configure and execute some commands with the smarty object, of course! But before going on, I need to make a break for a security advice: templates doesn't "need" to be in your document root, they can stay everywhere, and it's highly suggested moving them outside this folder because they could be accessible from the web directly otherwise! Also, you'll need to set some permissions, if you're too loose it's possible you enable complete strangers to write their files everywhere, compromising your hosting server.</p>
<p>Now that I did some information technology terrorism, we can go on!</p>
<p>To give Smarty a command, you use the PHP syntax</p>
<blockquote><p>$smarty -&gt; command(argument [...]);</p></blockquote>
<p>while to set a property we use</p>
<blockquote><p>$smarty -&gt; property = value;</p></blockquote>
<p>We'll need to set up at least two directories, better three, and two of them should be writable by the web server (not the web users!).</p>
<p>So we create the /templates, /templates_compiled and /templates_cache folders, have templates_compiled and templates_cache writable (you can chmod them 770 from shell or even from the majority of the ftp clients, including the one in Dreamweaver!). Then we make smarty aware of the presence of these directories by adding these lines on bottom of the php file:</p>
<blockquote><p>$smarty-&gt;template_dir = DR . '/templates';<br />
$smarty-&gt;compile_dir = DR . '/templates_compiled';<br />
$smarty-&gt;config_dir = DR . '/site';<br />
$smarty-&gt;cache_dir = DR . '/templates_cache';</p></blockquote>
<p>Perfect, and we added en passant the config_dir, that tells the Smarty object where to find auxiliary configuration files. We set it to the /site folder itself.</p>
<p>Now, to assign some templates variables, use this</p>
<blockquote><p>$smarty-&gt;assign('firstname','Giancarlo');<br />
$smarty-&gt;assign('lastname','Di Massa');</p></blockquote>
<p>to load, parse and output a template, use</p>
<blockquote><p>$smarty-&gt;display('page.tpl');</p></blockquote>
<p>This will make the Smarty object go fetch the page.tpl file in the templates directory, so better have something here. Create a page.tpl file and put in it</p>
<blockquote><p>Hi {$firstname} {$lastname}, how are you?</p></blockquote>
<p>Save and reload the page.php file. It should output</p>
<blockquote><p>Hi Giancarlo Di Massa, how are you?</p></blockquote>
<p>Smarty substituted the two tags with the assigned variables in the page.php file!</p>
<p>If you are a programmer, go study the smarty syntax for programmers, it tells all the commands you can issue on the smarty object. If you're a designer instead, there is a list of all the tags you can use in the templates, you can edit them as if they were static HTML files sprinkled with "programmer's magic".</p>
<p>Most of the other template engines work the same way, for example the <a target="_blank" href="http://en.wikipedia.org/wiki/VlibTemplate" >VlibTemplate</a> or the <a target="_blank" href="http://www.raintpl.com/" >RainTPL </a>libraries.</p>
<p>One last word is about the MVC architectures. MVC stays for Model-View-Controller, is a way of separating content (the model) from the code (the controller) and the html (the view). A complete MVC system that takes care of all the aspects of data fetching and manipulation, from database queries to the output, is often called a framework. Smarty can be part of a MVC framework but it's not itself one. Some good PHP frameworks are <a target="_blank" href="http://www.cakephp.org/" >CakePHP</a> and <a target="_blank" href="http://www.symfony-project.com/" >Symfony</a>.</p>
<p>I use a MVC framework I did myself called Presenza.</p>
<p>Next time we'll better organize our php code and start having something more complex of an Hello World template, so stay tuned.</p>
<p class="fbconnect_share"><fb:share-button class="url" href="http://giancarlo.dimassa.net/2007/07/10/how-to-separe-php-code-and-html-presentation-with-smarty-part-2-installation/" /></p>
<p><a href="http://feedads.g.doubleclick.net/~a/8pQJCZj5vzQR8aUaBvQMHLL5K7E/0/da"><img src="http://feedads.g.doubleclick.net/~a/8pQJCZj5vzQR8aUaBvQMHLL5K7E/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/8pQJCZj5vzQR8aUaBvQMHLL5K7E/1/da"><img src="http://feedads.g.doubleclick.net/~a/8pQJCZj5vzQR8aUaBvQMHLL5K7E/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=n0jbTLEW"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=41" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=V2gPVDUV"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=V2gPVDUV" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=WhYNxppR"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=WhYNxppR" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=VLlFZxxq"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=VLlFZxxq" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=pq2OKtlu"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=52" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=h5npqcNm"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=h5npqcNm" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=l9pZ3xx8"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=80" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/giancarlodimassa/~4/eKH-tFHcgpo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://giancarlo.dimassa.net/2007/07/10/how-to-separe-php-code-and-html-presentation-with-smarty-part-2-installation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://giancarlo.dimassa.net/2007/07/10/how-to-separe-php-code-and-html-presentation-with-smarty-part-2-installation/</feedburner:origLink></item>
		<item>
		<title>How to separe PHP code and HTML presentation with Smarty, part 1</title>
		<link>http://feedproxy.google.com/~r/giancarlodimassa/~3/Jfssxz5XrQo/</link>
		<comments>http://giancarlo.dimassa.net/2007/07/06/how-to-separe-php-code-and-html-presentation-with-smarty-part-1/#comments</comments>
		<pubDate>Thu, 05 Jul 2007 23:09:03 +0000</pubDate>
		<dc:creator>giancarlo</dc:creator>
				<category><![CDATA[Smarty]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[presentation]]></category>
		<category><![CDATA[template]]></category>

		<guid isPermaLink="false">http://giancarlo.dimassa.net/2007/07/06/how-to-separe-php-code-and-html-presentation-with-smarty-part-1/</guid>
		<description><![CDATA[Note: this is article is cut in parts, this is the only the first one. More to come.
Programming in PHP without separating content and code can lead to unwanted results, low mantainability and slower production. Even nowadays you can find tons of scripts written by filling HTML pages with chunks of code.
If you do that,

Web [...]]]></description>
			<content:encoded><![CDATA[<p>Note: this is article is cut in parts, this is the only the first one. More to come.</p>
<p>Programming in PHP without separating content and code can lead to <strong>unwanted results</strong>, <strong>low mantainability </strong>and <strong>slower production</strong>. Even nowadays you can find tons of scripts written by filling HTML pages with chunks of code.</p>
<p><span id="more-20"></span>If you do that,</p>
<ul>
<li><strong>Web designers </strong>with no programming skills <strong>will not be able </strong>to customize easily your script's appearance.</li>
<li>If you want to change a site, for example a festivity or a redesign, you will need to face a <strong>big amount of work </strong>adding again all the PHP code to the new HTML pages.</li>
<li>You will <strong>not be able to focus </strong>on the project because you'll have to manage yourself all the aspect of HTML production, from loops to file inclusion.</li>
</ul>
<p>At my first web works I had these problems too. Building a new site required more work that I expected, because it was also difficult to reuse the code built for preceding customers. Then I started putting all my HTML in separate files, reading it with PHP and doing substitutions where needed. That was really better, I was able to change HTML when I wanted, but nothing more. Data that needed to be presented by "looping" the same HTML needed to be built in PHP, and in some situations I needed some sort of conditional programming in these so called 'template files'. I started to write a full fledged 'template engine' myself when a project saved me. I customized an e-commerce script for a project, and that script used an open source template engine. At first I was... how to say? Puzzled! As I looked over the template files I saw heaps of strange code.. it wasn't PHP so I tought that It was a really bad idea to push the things so further. Half of the script functionality lied in the template files themselves, and I was even a bit angry because <strong>I tought I had to learn a new language... inside the language</strong>!<br />
But as I was changing the look and feel of that site, so was my opinion of that system. It's not bad after all... no, it's good indeed.. wait, <strong>it's great</strong>! I <strong>never went back</strong> and used that engine myself for all my other projects: <strong>it's name is <a target="_blank" href="http://smarty.php.net" >Smarty</a></strong>.<br />
Here are some interesting functions:</p>
<ul>
<li>You can <strong>edit the template files </strong>as if they are HTML documents and <strong>separe </strong>them from the code with a <strong>little effort</strong>, if you don't want to learn the Smarty language.</li>
<li>Smarty language is much <strong>natural </strong>and <strong>template oriented </strong>than PHP, some things like iterate an array and outputting the same HTML code with the array data inside are <strong>very easy </strong>to do.</li>
<li>You can <strong>include other files </strong>from your templates, these files <strong>will be parsed </strong>too.</li>
<li>There's <strong>support </strong>for <strong>variables </strong>and <strong>constants</strong></li>
<li>You can <strong>produce </strong>a piece of HTML, then save it into a variable and <strong>reuse </strong>it later in the page, even modify it.</li>
<li>You can <strong>put decisional code in the templates</strong>, do <strong>math operations </strong>and <strong>store results </strong>in new variables.</li>
<li>Smarty has a <strong>plugin system </strong>with a very good repository, it's <strong>easy to write </strong>new plugins and they are <strong>autoloaded </strong>after you put them into their folder.</li>
<li>Has an <strong>advanced cache system </strong>that builds already decoded chunks of templates for <strong>speed </strong>purposes, so you actually can go <strong>even faster </strong>than mixing PHP with HTML.</li>
<li>There are many <strong>output buffering </strong>functions that give you abilities to change the whole page after it is generated and before is sent to the client, just for example <strong>you can with a single line change all your website</strong> and tell the system to add target="_new" to all external links.</li>
<li>You can "<strong>skin</strong>" your site as you want, it's really possible to do a complete makeup of a whole web project in a day or two, even <strong>change skins in realtime</strong>!</li>
<li>There's a <strong>template debugger</strong> to show data being passed to the engine!</li>
</ul>
<p>So, by now you would think that <strong>Smarty is the best thing after chocolate milk</strong>, but it has some negative aspects worth exploring:</p>
<ul>
<li><strong>All the HTML</strong> is sent <strong>at the same time</strong>, while with PHP you can send the page in chunks. However that required special attention when you wanted to set cookies, because these need to be sent before everything else.</li>
<li>Smarty is <strong>written in PHP itself</strong>. A C++ templating engine maybe would be faster (there are some out there), but then you would need to write new plugins in C++ too. You use smarty by <strong>actually loading it entirely in memory</strong> each time you need to access template files. If you need to output really simple HTML code in little pieces of code, and these pieces are in separate pages, don't use it. Just an example, if <strong>your script just outputs "OK"</strong> after the computations, it's <strong>better to use echo </strong>for the text.</li>
<li>You will need to <strong>learn a new language</strong>. It's simple and everything, but it's not rich as PHP itself, it's only a template language. The thing I miss more is the switch conditional construct, you need a series of if..elseif...elseif to emulate it. However this language is always used only to produce the presentation, you'll end up moving everything related to visualization to the templates, <strong>never using echo again</strong> if not for debug purposes.</li>
<li>It's <strong>not always easy to upgrade</strong> an existing project to using a template engine.</li>
<li>If you use an <strong>aggressive caching </strong>mode and make changes to the templates, those <strong>will not reflect online </strong>until you clean the template cache directory.</li>
<li>Smarty <strong>adds memory </strong>to your <strong>requirements</strong>, better have a look at the PHP memory_limit setting.</li>
<li>It has some good builtin plugins to produce drop downs listboxes, radio buttons and dates inputs in forms, but <strong>these elements require formatting the data in a certain way</strong>.</li>
<li>If you dive other scripts directly into the page, some symbols, like the <strong>curly braces</strong>, <strong>can collide with Smarty</strong>, that will think you are initiating a template command sequence, so you'll need to surround these pieces of code with literal tags, that tell Smarty not to parse them.</li>
</ul>
<p>As this argument is very long, I decided to cut it in parts. Next part will be about installing Smarty and starting using it. We'll also have a look at other template engines, and talk about full PHP frameworks that use the MVC paradigm, but don't worry about that right now.</p>
<p class="fbconnect_share"><fb:share-button class="url" href="http://giancarlo.dimassa.net/2007/07/06/how-to-separe-php-code-and-html-presentation-with-smarty-part-1/" /></p>
<p><a href="http://feedads.g.doubleclick.net/~a/13P6HBMjpoyET9RF5ofaN8W90to/0/da"><img src="http://feedads.g.doubleclick.net/~a/13P6HBMjpoyET9RF5ofaN8W90to/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/13P6HBMjpoyET9RF5ofaN8W90to/1/da"><img src="http://feedads.g.doubleclick.net/~a/13P6HBMjpoyET9RF5ofaN8W90to/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=bbf5GIsq"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=41" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=tsnpXhC9"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=tsnpXhC9" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=ia9woPMy"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=ia9woPMy" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=WTgNxXT8"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=WTgNxXT8" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=VUlfYtcy"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=52" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=h7zunlIt"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=h7zunlIt" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=83sEpUXg"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=80" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/giancarlodimassa/~4/Jfssxz5XrQo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://giancarlo.dimassa.net/2007/07/06/how-to-separe-php-code-and-html-presentation-with-smarty-part-1/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://giancarlo.dimassa.net/2007/07/06/how-to-separe-php-code-and-html-presentation-with-smarty-part-1/</feedburner:origLink></item>
		<item>
		<title>How to set up a test server that supports multiple sites and is accessible from outside</title>
		<link>http://feedproxy.google.com/~r/giancarlodimassa/~3/AI0ldwc0c5c/</link>
		<comments>http://giancarlo.dimassa.net/2007/07/04/how-to-set-up-a-test-server-that-supports-multiple-sites-and-is-accessible-from-outside/#comments</comments>
		<pubDate>Wed, 04 Jul 2007 11:40:43 +0000</pubDate>
		<dc:creator>giancarlo</dc:creator>
				<category><![CDATA[Stuff]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[lamp]]></category>
		<category><![CDATA[mail]]></category>
		<category><![CDATA[mercury]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[Server side]]></category>
		<category><![CDATA[test]]></category>
		<category><![CDATA[virtualhost]]></category>
		<category><![CDATA[wamp]]></category>
		<category><![CDATA[windows]]></category>
		<category><![CDATA[xampp]]></category>

		<guid isPermaLink="false">http://giancarlo.dimassa.net/2007/07/04/how-to-set-up-a-test-server-that-supports-multiple-sites-and-is-accessible-from-outside/</guid>
		<description><![CDATA[Before using a test server, my web programming experience was really slower. In fact, every time I had to modify something or try a piece of code, I had to upload it first to my remote server. If the Internet connection had a fluctuation, I could not continue working at all. This also meant I [...]]]></description>
			<content:encoded><![CDATA[<p>Before using a test server, my web programming experience was really slower. In fact, every time I had to modify something or try a piece of code, I had to upload it first to my remote server. If the Internet connection had a fluctuation, I could not continue working at all. This also meant I had to first set up a test website if I didn't work on the live address. One day I had the curiosity of checking out one of these LAMP distributions (Linux, Apache, MySQL and PHP), just with the Linux variable taken out. They call them a LAMP package for Windows. It contains a preconfigured Apache 2 server with PHP 4 and 5, a switcher between the two, MySQL 5 (you even got a phpMyAdmin script already set up) and a mail server called Mercury32 that enables you to send and receive mails from your own scripts, check out newsletters and so on.</p>
<p><span id="more-17"></span></p>
<p>I installed the package only once, because after that, I used the same setup over the next Windows installations, just copying the old directory. The package has a cool script that sets up the MySQL and Apache servers as system services and makes them start up at the computer boot (simply remember that this script needs to run with Administrator priviledges under Windows Vista).<br />
As I didn't want to touch the preconfigured website (a nice panel that shows the working services, has examples of the various functionalities and a phpMyAdmin script) I ended setting up a virtualhost for each website I was working. Apache (the web server) has a function that makes you share multiple sites on the same machine and using the same web server. Every decent webserver today has these functions, Apache calls these sites virtualhosts.<br />
In a production environment, you would set up each virtualhost with his domain name (I did so for my test server initially), but this meant each time you had to test the site, you had to be connected to Internet or set up a name server, because otherwise the system couldn't find the virtualhost. I assigned a different port for each server, starting from 81 (80 is the standard HTTP port) and going on. However, I suggest always use a port higher than 1024 for custom services like these, because the web server could collide with other services or use reserved ports.<br />
Configuring these virtualhosts means creating a new folder that contains the site files (a new site root) and modify two configuration files (don't worry, they are explained in plain english, it's very simple), in the main file we tell Apache to start listening to another port, in the other file we add the virtualhost directive (some lines you always end up copy and paste and maybe customizing later).<br />
As for simplification purposes I imagine you already downloaded and installed the LAMP distro, I personally use <a target="_blank" href="http://www.apachefriends.org/en/xampp.html" >XAMPP</a> (my installation folder is D:\xampp, because my OS stays in the C: drive and this way I don't have to move anything when I reinstall, adjust as you need, but I really recommend for a x:\XAMPP path).<br />
Open D:\xampp\apache\conf\httpd.conf with a text editor, after the line</p>
<blockquote><p>Listen 80</p></blockquote>
<p>that tells the server to listen to port 80, add this</p>
<blockquote><p>Listen 81</p></blockquote>
<p>then scroll at the bottom, and before the last block</p>
<blockquote><p>#<br />
# Note: The following must must be present to support<br />
# starting without SSL on platforms with no /dev/random equivalent<br />
# but a statically compiled-in mod_ssl.<br />
#<br />
&lt;IfModule ssl_module&gt;<br />
SSLRandomSeed startup builtin<br />
SSLRandomSeed connect builtin<br />
&lt;/IfModule&gt;</p></blockquote>
<p>add this two lines</p>
<blockquote><p># Virtual hosts<br />
Include conf/extra/httpd-vhosts.conf</p></blockquote>
<p>this tells the server to include a new text file in the configuration, where we'll put everything related to virtualhosts.<br />
Next time we'll need to add a new virtualhost, in the main httpd.conf file we will only need to add a Listen 82, Listen 83, Listen 84 [...].<br />
Now save, go in D:\xampp\apache\conf\extra and create this httpd-vhosts.conf file.<br />
Add these lines</p>
<blockquote><p># Virtualhost domainname.com - port 81<br />
&lt;VirtualHost *:81&gt;<br />
DocumentRoot D:\xampp\htdocs\virtualhosts\domainname.com<br />
ServerName localhost:81<br />
&lt;/VirtualHost&gt;</p></blockquote>
<p>then save and exit. Ah, remember that domainname.com should be replaced with your site domain's, for example ebay.com or yahoo.com.<br />
We're almost done, you just need to go to D:\xampp\htdocs, create here a virtualhosts folder (here well'put the document root of each of our virtualhosts) and in the virtualhosts folder put a domainname.com folder (replace with your site domain's).<br />
If you want to be sure everything works, put a file called index.htm in the domainname.com folder and add this line in it</p>
<blockquote><p>If you can read this, the domainname.com - port 81 virtualhost works correctly.</p></blockquote>
<p>then save and exit.<br />
Now stop and restart Apache (Administration Tools/Show local services in the Control Panel, find Apache2, click Stop, then click Start) and if everything is right, you will see the message wrote in the index.htm file by going with the browser to the url</p>
<blockquote><p>http://localhost:81</p></blockquote>
<p>Congratulations. And now? There are some optional steps you can make</p>
<ul>
<li>If you got a dynamic IP, you will need to set up a dynamic DNS service to bind it to a domain name. I use <a target="_blank" href="http://www.dyndns.com/" >DynDNS</a>, it's the most famous I think. You'll need to open a free account, add a dynamic DNS service. If your router natively supports dynamic DNS refreshes (has a dyndns client in the firmware) log on to the router, find the function, insert your dyndns domain, username and password, save and restart. If you're not sure, you'll need a dyndns refresh client you can find <a target="_blank" href="http://www.dyndns.com/support/clients/" >here</a>.</li>
<li>If you're behind a firewall, you will need to open the ports you are using.</li>
<li>If you are using a router, you will need to use the port forwarding feature of the NAT to explain your router how to serve requests from outside.</li>
<li>If you want to use MySQL, the default password is blank, that means everyone from outside will be able to read your test data. Not a big problem, but better change it using the phpMyAdmin script (located at http://localhost/phpmyadmin). While you're using the phpmyadmin script, add a database to each domain in the form domainname_com, so you can access it.</li>
<li>The mail server has not a startup script yet, you will need to call it when you will need it. I created a shortcut to D:\xampp\MercuryMail\mercury.exe in my Quick Launch bar. When started, an icon will appear on the tray, double click it to bring the server control panel. I suggest you add a test POP3 account by clicking the Configuration menu, Manage local users, username test and password test. You will be able to add this mailbox to your email software.</li>
</ul>
<p>Now your server is visible from outside, you got a database for each domain, you know how to add virtualhosts. What to add to the list? Really simple, you should make your PHP scripts server-aware!<br />
This means having the remote, live settings and the test server settings on the same script, and having the script "detect" if it's running on a test server or on the live server.<br />
You can do it this way:</p>
<blockquote><p>$testserver = $_SERVER["SERVER_NAME"]=="localhost";<br />
now if the $testserver variable is true, you use some settings, send email to the test account and so on.<br />
Example:<br />
if ($testserver) {<br />
$dbuser = "root";<br />
$dbpass = "";<br />
$dbhost = "localhost";<br />
$dbname = "domainname_com";<br />
} else {<br />
// your hosting provider's data<br />
}</p></blockquote>
<p>and if you use mail functions</p>
<blockquote><p>if ($testserver) {<br />
// mail to the 'test' account<br />
} else {<br />
// mail to the real user<br />
}</p></blockquote>
<p>To syncronize your test site with your live site, simply copy the virtualhost document root in a D:\sites folder (always do that! you will know exactly the state of the live server and it will provide a backup, do not load from the virtualhost document root!).<br />
To load the MySQL database, export it to SQL and import it on the live server with the phpMyAdmin script of the hosting provider.</p>
<p class="fbconnect_share"><fb:share-button class="url" href="http://giancarlo.dimassa.net/2007/07/04/how-to-set-up-a-test-server-that-supports-multiple-sites-and-is-accessible-from-outside/" /></p>
<p><a href="http://feedads.g.doubleclick.net/~a/gNSwJUKylUwq0CDEuEgrVzm3ogo/0/da"><img src="http://feedads.g.doubleclick.net/~a/gNSwJUKylUwq0CDEuEgrVzm3ogo/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/gNSwJUKylUwq0CDEuEgrVzm3ogo/1/da"><img src="http://feedads.g.doubleclick.net/~a/gNSwJUKylUwq0CDEuEgrVzm3ogo/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=x6yqVvNs"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=41" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=qJxTDumQ"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=qJxTDumQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=nzud7sIC"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=nzud7sIC" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=aBy0oZIQ"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=aBy0oZIQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=oOWSsuzB"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=52" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=LyZl1xRQ"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?i=LyZl1xRQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/giancarlodimassa?a=xEzZWw2G"><img src="http://feeds.feedburner.com/~f/giancarlodimassa?d=80" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/giancarlodimassa/~4/AI0ldwc0c5c" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://giancarlo.dimassa.net/2007/07/04/how-to-set-up-a-test-server-that-supports-multiple-sites-and-is-accessible-from-outside/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://giancarlo.dimassa.net/2007/07/04/how-to-set-up-a-test-server-that-supports-multiple-sites-and-is-accessible-from-outside/</feedburner:origLink></item>
	</channel>
</rss>
