<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:gd="http://schemas.google.com/g/2005" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;AkEMQnc7eSp7ImA9Wx5TFUQ.&quot;"><id>tag:blogger.com,1999:blog-4774158543320836267</id><updated>2010-08-01T03:51:23.901+10:00</updated><title>24 Hour Apps</title><subtitle type="html" /><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://www.24hourapps.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://www.24hourapps.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Paul Chiu</name><uri>http://www.blogger.com/profile/16416350337923371068</uri><email>noreply@blogger.com</email></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>92</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/24hourapps" /><feedburner:info uri="24hourapps" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" /><entry gd:etag="W/&quot;C0MARX8-fSp7ImA9WxNWFE8.&quot;"><id>tag:blogger.com,1999:blog-4774158543320836267.post-1905821763564217948</id><published>2009-10-13T17:57:00.002+10:00</published><updated>2009-10-13T18:10:44.155+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-13T18:10:44.155+10:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="reflections" /><title>Returning to blogging</title><content type="html">It has been quite a while since I posted a blog. It was taking up quite a bit of my spare time and I needed that time to focus on my professional work and my personal life. Writing this blog was an enjoyable hobby for me, to share knowledge and receive comments from readers was quite fulfilling. That is why I have decided to return.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I posted at the start of the year that I would like to make one post a day. It then slowed down to approximately one every other day. Even then the rate was a bit too much for me. I was finding myself sharing a lot more trivial knowledge while spending more time to write longer articles that actually delved into programming topics that were more of my forté.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My new goal for this blog is to focus more on programming topics and less on minor tips. There are already plenty of sites out there that post tips on *nix administration and use. However, this does not mean I will no longer post them. Just that I will do my best to write useful articles about programming.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The main change though will be the posting schedule, which will now be twice a week. So hopefully my new plans go well and there will be renewed, sustainable activity on this blog!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4774158543320836267-1905821763564217948?l=www.24hourapps.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/1-7QUj4y-jLxPk3a4v6gjvhl62M/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/1-7QUj4y-jLxPk3a4v6gjvhl62M/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/1-7QUj4y-jLxPk3a4v6gjvhl62M/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/1-7QUj4y-jLxPk3a4v6gjvhl62M/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=Ud6PdwsS5c4:LzQibPAuQMQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=Ud6PdwsS5c4:LzQibPAuQMQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=Ud6PdwsS5c4:LzQibPAuQMQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=Ud6PdwsS5c4:LzQibPAuQMQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=Ud6PdwsS5c4:LzQibPAuQMQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=Ud6PdwsS5c4:LzQibPAuQMQ:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=Ud6PdwsS5c4:LzQibPAuQMQ:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=Ud6PdwsS5c4:LzQibPAuQMQ:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=Ud6PdwsS5c4:LzQibPAuQMQ:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/24hourapps/~4/Ud6PdwsS5c4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.24hourapps.com/feeds/1905821763564217948/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.24hourapps.com/2009/10/returning-to-blogging.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/1905821763564217948?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/1905821763564217948?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/24hourapps/~3/Ud6PdwsS5c4/returning-to-blogging.html" title="Returning to blogging" /><author><name>Paul Chiu</name><uri>http://www.blogger.com/profile/16416350337923371068</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10755322441250465748" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.24hourapps.com/2009/10/returning-to-blogging.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkcGQXo5fyp7ImA9WxVbE0Q.&quot;"><id>tag:blogger.com,1999:blog-4774158543320836267.post-1961057111289041884</id><published>2009-03-30T17:27:00.003+10:00</published><updated>2009-03-30T17:27:00.427+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-30T17:27:00.427+10:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="tips" /><title>Linux Tips 17: Find and replace text in multiple files</title><content type="html">Multiple file find and replace is a rarely used, but an extremely time saving, ability of Linux that I cannot live without. It can be achieved by chaining a few commands together to get the list of files you want to change (&lt;a href="http://content.hccfl.edu/pollock/Unix/FindCmd.htm"&gt;find&lt;/a&gt;), make sure the files contain the strings you want to replace (&lt;a href="http://linux.about.com/od/commands/l/blcmdl1_grep.htm"&gt;grep&lt;/a&gt;), and do the replacements (&lt;a href="http://lowfatlinux.com/linux-sed.html"&gt;sed&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;Lets say we have a lot of code that uses the function &lt;span style="font-style: italic;"&gt;registerUser&lt;/span&gt; that was implemented when there was only one class of users, but now another class of users need to access the system and what were "users" are now called "admins" so we need to change all calls to &lt;span style="font-style: italic;"&gt;registerUser&lt;/span&gt; to &lt;span style="font-weight: bold;"&gt;registerAdmin&lt;/span&gt;. The command needed would be:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;find . -type f | xargs grep -l 'registerUser' | xargs sed -i '' -e 's/registerUser/registerAdmin/g'&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;The first part of the command is &lt;span style="font-style: italic;"&gt;find&lt;/span&gt;, which finds all files and excludes directories. That result is then piped to &lt;span style="font-style: italic;"&gt;grep&lt;/span&gt;, which lists all files that contain &lt;span style="font-style: italic;"&gt;registerUser&lt;/span&gt;. The results of is then sent to &lt;span style="font-style: italic;"&gt;sed&lt;/span&gt;, which replaces all occurances of &lt;span style="font-style: italic;"&gt;registerUser&lt;/span&gt; with &lt;span style="font-style: italic;"&gt;registerAdmin&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;The command is quite long and hard to remember, which is why I normally write it down somewhere. Having it archived on my blog means I can just look here in the future.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4774158543320836267-1961057111289041884?l=www.24hourapps.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/aMIbCKyj0iuzgR6mBDF4nmlaJOo/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/aMIbCKyj0iuzgR6mBDF4nmlaJOo/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/aMIbCKyj0iuzgR6mBDF4nmlaJOo/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/aMIbCKyj0iuzgR6mBDF4nmlaJOo/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=JWywHN4nAG0:uWc-Qx3BUro:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=JWywHN4nAG0:uWc-Qx3BUro:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=JWywHN4nAG0:uWc-Qx3BUro:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=JWywHN4nAG0:uWc-Qx3BUro:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=JWywHN4nAG0:uWc-Qx3BUro:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=JWywHN4nAG0:uWc-Qx3BUro:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=JWywHN4nAG0:uWc-Qx3BUro:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=JWywHN4nAG0:uWc-Qx3BUro:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=JWywHN4nAG0:uWc-Qx3BUro:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/24hourapps/~4/JWywHN4nAG0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.24hourapps.com/feeds/1961057111289041884/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.24hourapps.com/2009/03/linux-tips-17-find-and-replace-text-in.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/1961057111289041884?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/1961057111289041884?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/24hourapps/~3/JWywHN4nAG0/linux-tips-17-find-and-replace-text-in.html" title="Linux Tips 17: Find and replace text in multiple files" /><author><name>Paul Chiu</name><uri>http://www.blogger.com/profile/16416350337923371068</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10755322441250465748" /></author><thr:total>1</thr:total><feedburner:origLink>http://www.24hourapps.com/2009/03/linux-tips-17-find-and-replace-text-in.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0QEQXY8eCp7ImA9WxVUGUs.&quot;"><id>tag:blogger.com,1999:blog-4774158543320836267.post-8389944508905729951</id><published>2009-03-25T17:15:00.000+10:00</published><updated>2009-03-25T17:15:00.870+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-25T17:15:00.870+10:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="cakephp" /><category scheme="http://www.blogger.com/atom/ns#" term="tips" /><title>CakePHP - Using custom form tags without losing form auto fill magic</title><content type="html">The CakePHP &lt;a href="http://book.cakephp.org/view/182/Form"&gt;FormHelper&lt;/a&gt; is one of the biggest time savers in the whole framework. It not only takes care of generating common elements as well as performs auto-filling of pretty much all input fields. The only problem I find with it is the difficulty in generating forms using &lt;span style="font-style: italic;"&gt;$form-&amp;gt;create(...)&lt;/span&gt; that submit to the current page, ie a form with &lt;span style="font-style: italic;"&gt;action=""&lt;/span&gt;. This is because when the URL in &lt;span style="font-style: italic;"&gt;$form-&amp;gt;create(...)&lt;/span&gt; is set as '' or null, the default action URL of &lt;span style="font-style: italic;"&gt;/model/add&lt;/span&gt; takes over.&lt;br /&gt;&lt;br /&gt;The solution I end up with is often writing my own &amp;lt;form&amp;gt; and &amp;lt;/form&amp;gt; tags instead of using &lt;span style="font-style: italic;"&gt;$form-&amp;gt;create()&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;$form-&amp;gt;end()&lt;/span&gt;. The issue with using custom form tags is that CakePHP will no longer auto fill input fields meaning that a lot of code has to be implemented to detect and specify input values. Overcoming this is quite simple and simply requires the use of &lt;span style="font-style: italic;"&gt;$form-&amp;gt;end()&lt;/span&gt; with a custom form tag, such that your form code looks like:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="php"&gt;&lt;br /&gt;&amp;lt;form action="" method="POST"&amp;gt;&lt;br /&gt;   &amp;lt;?= $form-&amp;gt;input("User.name") ?&amp;gt;&lt;br /&gt;   &amp;lt;?= $form-&amp;gt;input("User.email") ?&amp;gt;&lt;br /&gt;&amp;lt;?= $form-&amp;gt;end() ?&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4774158543320836267-8389944508905729951?l=www.24hourapps.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/S5rpriGnRuDhW-yYCAa0TtBvO8w/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/S5rpriGnRuDhW-yYCAa0TtBvO8w/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/S5rpriGnRuDhW-yYCAa0TtBvO8w/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/S5rpriGnRuDhW-yYCAa0TtBvO8w/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=gQl1nNCWABE:3niryapaL10:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=gQl1nNCWABE:3niryapaL10:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=gQl1nNCWABE:3niryapaL10:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=gQl1nNCWABE:3niryapaL10:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=gQl1nNCWABE:3niryapaL10:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=gQl1nNCWABE:3niryapaL10:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=gQl1nNCWABE:3niryapaL10:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=gQl1nNCWABE:3niryapaL10:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=gQl1nNCWABE:3niryapaL10:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/24hourapps/~4/gQl1nNCWABE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.24hourapps.com/feeds/8389944508905729951/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.24hourapps.com/2009/03/cakephp-using-custom-form-tags-without.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/8389944508905729951?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/8389944508905729951?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/24hourapps/~3/gQl1nNCWABE/cakephp-using-custom-form-tags-without.html" title="CakePHP - Using custom form tags without losing form auto fill magic" /><author><name>Paul Chiu</name><uri>http://www.blogger.com/profile/16416350337923371068</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10755322441250465748" /></author><thr:total>2</thr:total><feedburner:origLink>http://www.24hourapps.com/2009/03/cakephp-using-custom-form-tags-without.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DE8MQX09eip7ImA9WxVUF00.&quot;"><id>tag:blogger.com,1999:blog-4774158543320836267.post-681010969848389134</id><published>2009-03-22T17:28:00.000+10:00</published><updated>2009-03-22T17:28:00.362+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-22T17:28:00.362+10:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="tips" /><title>Linux Tips 16: Removing crashed processes</title><content type="html">In my previous tip on &lt;a href="http://www.24hourapps.com/2009/03/linux-tips-15-using-top-to-identify.html"&gt;monitoring Linux processes&lt;/a&gt; I wrote about &lt;span style="font-style: italic;"&gt;top&lt;/span&gt; as a tool for doing just that. In this post I will extend on that and explain the main commands used to stop processes that are taking over the system with excessive CPU or memory usage. There are two commands.&lt;br /&gt;&lt;br /&gt;The &lt;span style="font-style: italic;"&gt;kill&lt;/span&gt; command will stop a process for a given process id (PID). To use it on a process with the PID 21194 simply execute &lt;span style="font-weight: bold;"&gt;kill -9 21194&lt;/span&gt; and the process will be killed. If you need to remove more processes belonging to the same name, ie remove all Apache instances, you need to use the command &lt;span style="font-weight: bold;"&gt;killall -SIGKILL apache&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you need to kill all processes with a common name, ie PostgreSQL, which can create processes based on the database that it is serving you can use a combination of &lt;span style="font-style: italic;"&gt;ps&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;grep&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;awk&lt;/span&gt;, and &lt;span style="font-style: italic;"&gt;kill&lt;/span&gt;. The command is: &lt;span style="font-weight: bold;"&gt;kill `ps aux | grep "postgre" | grep -v "grep" | awk '{print $2}'`&lt;/span&gt; The main command is the &lt;span style="font-style: italic;"&gt;ps aux&lt;/span&gt;... that takes the results of &lt;span style="font-style: italic;"&gt;ps aux&lt;/span&gt;, finds &amp;quto;postgre" using &lt;span style="font-style: italic;"&gt;grep&lt;/span&gt;, then removes lines with "grep" and uses &lt;span style="font-style: italic;"&gt;awk&lt;/span&gt; to get all secondary field values (the PID). &lt;span style="font-style: italic;"&gt;kill&lt;/span&gt; then loops through all matching PIDs effectively killing all processes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4774158543320836267-681010969848389134?l=www.24hourapps.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/77TBFyALngsxoKGm7YUuCLKmAh0/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/77TBFyALngsxoKGm7YUuCLKmAh0/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/77TBFyALngsxoKGm7YUuCLKmAh0/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/77TBFyALngsxoKGm7YUuCLKmAh0/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=rpnwO4Pnq1I:B18Q3meetiU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=rpnwO4Pnq1I:B18Q3meetiU:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=rpnwO4Pnq1I:B18Q3meetiU:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=rpnwO4Pnq1I:B18Q3meetiU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=rpnwO4Pnq1I:B18Q3meetiU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=rpnwO4Pnq1I:B18Q3meetiU:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=rpnwO4Pnq1I:B18Q3meetiU:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=rpnwO4Pnq1I:B18Q3meetiU:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=rpnwO4Pnq1I:B18Q3meetiU:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/24hourapps/~4/rpnwO4Pnq1I" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.24hourapps.com/feeds/681010969848389134/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.24hourapps.com/2009/03/linux-tips-16-removing-crashed.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/681010969848389134?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/681010969848389134?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/24hourapps/~3/rpnwO4Pnq1I/linux-tips-16-removing-crashed.html" title="Linux Tips 16: Removing crashed processes" /><author><name>Paul Chiu</name><uri>http://www.blogger.com/profile/16416350337923371068</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10755322441250465748" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.24hourapps.com/2009/03/linux-tips-16-removing-crashed.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0MAQ3w-eip7ImA9WxVUGU8.&quot;"><id>tag:blogger.com,1999:blog-4774158543320836267.post-9058589592955782745</id><published>2009-03-21T16:17:00.004+10:00</published><updated>2009-03-25T05:04:02.252+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-25T05:04:02.252+10:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="images" /><category scheme="http://www.blogger.com/atom/ns#" term="reflections" /><title>A good summary of web development ...</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_29yMocwFCms/Sckuk4hJidI/AAAAAAAAAKg/4_bJgorTjTQ/s1600-h/simplicity.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 166px; height: 320px;" src="http://4.bp.blogspot.com/_29yMocwFCms/Sckuk4hJidI/AAAAAAAAAKg/4_bJgorTjTQ/s320/simplicity.png" alt="" id="BLOGGER_PHOTO_ID_5316832046269172178" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Why is this true? I think because most developers are not that invested in the products they produce and most customers want everything done yesterday, which leads to a lack of thought and consideration as to what is really important. Really, try asking a client what is important on a list of features and most of them will pick at least half, and when everything is important nothing can be. Although when everything is implemented 80% of the client's time will be spent using only 20% of features.&lt;br /&gt;&lt;br /&gt;Is there a solution to this problem? I don't know. Contracting companies and clients both want to keep hours to a minimum and most are simply unable to picture perfection so whatever works well enough is often what is delivered and accepted. However I think that it would be beneficial with willing clients to try to reverse the default time allocation and spend the most time on design and testing and far less time on coding and ad-hoc changes. While I do not consider changes to be bad when working in an agile process there must be a clear vision for what the software is intended for so that feature creep does not become an issue.&lt;br /&gt;&lt;br /&gt;Personally I do not mind creating a few solutions to give clients a real choice. Although in today's economic circumstances some may say that it is not financially wise to do so, however I believe that good products will keep on delivering value to both the creator and the client and is really more of an investment by both parties instead of just the end result of a simple transaction.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4774158543320836267-9058589592955782745?l=www.24hourapps.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/_t_floO_oQzQKbGkYWe5KLEmMzU/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/_t_floO_oQzQKbGkYWe5KLEmMzU/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/_t_floO_oQzQKbGkYWe5KLEmMzU/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/_t_floO_oQzQKbGkYWe5KLEmMzU/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=bxih8kAYv5E:0qxG0IcJwFQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=bxih8kAYv5E:0qxG0IcJwFQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=bxih8kAYv5E:0qxG0IcJwFQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=bxih8kAYv5E:0qxG0IcJwFQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=bxih8kAYv5E:0qxG0IcJwFQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=bxih8kAYv5E:0qxG0IcJwFQ:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=bxih8kAYv5E:0qxG0IcJwFQ:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=bxih8kAYv5E:0qxG0IcJwFQ:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=bxih8kAYv5E:0qxG0IcJwFQ:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/24hourapps/~4/bxih8kAYv5E" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.24hourapps.com/feeds/9058589592955782745/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.24hourapps.com/2009/03/good-summary-of-web-development.html#comment-form" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/9058589592955782745?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/9058589592955782745?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/24hourapps/~3/bxih8kAYv5E/good-summary-of-web-development.html" title="A good summary of web development ..." /><author><name>Paul Chiu</name><uri>http://www.blogger.com/profile/16416350337923371068</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10755322441250465748" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_29yMocwFCms/Sckuk4hJidI/AAAAAAAAAKg/4_bJgorTjTQ/s72-c/simplicity.png" height="72" width="72" /><thr:total>3</thr:total><feedburner:origLink>http://www.24hourapps.com/2009/03/good-summary-of-web-development.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEQMQn86fyp7ImA9WxVUFkQ.&quot;"><id>tag:blogger.com,1999:blog-4774158543320836267.post-2622061882233716096</id><published>2009-03-20T18:37:00.004+10:00</published><updated>2009-03-22T13:26:23.117+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-22T13:26:23.117+10:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="tips" /><title>Linux Tips 15: Using top to identify slow processes</title><content type="html">For a long time I had been using &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;ps - aux&lt;/span&gt; as a way of seeing just what processes were slowing down a server or *nix based computer. However &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;top &lt;/span&gt;is a far better tool for this task as it shows a real time view of processes. There are very few commands available and they can be found by typing &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;?&lt;/span&gt; once the program has launched. The most useful for my purposes is &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;o&lt;/span&gt;, after pressing &lt;span class="Apple-style-span" style="font-style: italic;"&gt;o&lt;/span&gt;, type &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;cpu&lt;/span&gt;, to have &lt;span class="Apple-style-span" style="font-style: italic;"&gt;top &lt;/span&gt;order all processes by cpu usage to find any runaway processes.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Top is an interactive command line program and looks like:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_29yMocwFCms/ScWvwQ0PeBI/AAAAAAAAAKY/LPaU2AgemF4/s1600-h/Picture+41.PNG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 316px;" src="http://4.bp.blogspot.com/_29yMocwFCms/ScWvwQ0PeBI/AAAAAAAAAKY/LPaU2AgemF4/s320/Picture+41.PNG" alt="" id="BLOGGER_PHOTO_ID_5315848178863405074" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4774158543320836267-2622061882233716096?l=www.24hourapps.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/DZA3AfVoFxG8tUB1uJunc2_GPWs/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/DZA3AfVoFxG8tUB1uJunc2_GPWs/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/DZA3AfVoFxG8tUB1uJunc2_GPWs/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/DZA3AfVoFxG8tUB1uJunc2_GPWs/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=GaOH4HxMtBQ:2S32kgRBzow:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=GaOH4HxMtBQ:2S32kgRBzow:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=GaOH4HxMtBQ:2S32kgRBzow:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=GaOH4HxMtBQ:2S32kgRBzow:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=GaOH4HxMtBQ:2S32kgRBzow:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=GaOH4HxMtBQ:2S32kgRBzow:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=GaOH4HxMtBQ:2S32kgRBzow:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=GaOH4HxMtBQ:2S32kgRBzow:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=GaOH4HxMtBQ:2S32kgRBzow:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/24hourapps/~4/GaOH4HxMtBQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.24hourapps.com/feeds/2622061882233716096/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.24hourapps.com/2009/03/linux-tips-15-using-top-to-identify.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/2622061882233716096?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/2622061882233716096?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/24hourapps/~3/GaOH4HxMtBQ/linux-tips-15-using-top-to-identify.html" title="Linux Tips 15: Using top to identify slow processes" /><author><name>Paul Chiu</name><uri>http://www.blogger.com/profile/16416350337923371068</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10755322441250465748" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_29yMocwFCms/ScWvwQ0PeBI/AAAAAAAAAKY/LPaU2AgemF4/s72-c/Picture+41.PNG" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.24hourapps.com/2009/03/linux-tips-15-using-top-to-identify.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkcAQXc5cCp7ImA9WxVUFEk.&quot;"><id>tag:blogger.com,1999:blog-4774158543320836267.post-5248105869403408795</id><published>2009-03-19T17:34:00.001+10:00</published><updated>2009-03-19T17:34:00.928+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-19T17:34:00.928+10:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="cakephp" /><category scheme="http://www.blogger.com/atom/ns#" term="phpmailer" /><category scheme="http://www.blogger.com/atom/ns#" term="email" /><title>Using PHPMailer to create a centralized email system in Cake PHP</title><content type="html">Prior to Cake PHP 1.2 there were no built-in &lt;a href="http://api.cakephp.org/class/email-component"&gt;email components&lt;/a&gt; that were readily available and people had to resort to using their &lt;a href="http://bakery.cakephp.org/articles/view/sending-email-with-phpmailer"&gt;own&lt;/a&gt; &lt;a href="http://bakery.cakephp.org/articles/view/phpmailer-with-native-api-for-php-5-x"&gt;components&lt;/a&gt; with &lt;a href="http://phpmailer.codeworxtech.com/"&gt;PHPMailer&lt;/a&gt;. I do still believe it is better to use a custom PHPMailer component under most circumstances as it is easier to configure, supports more services (ie Gmail), and gives people far greater email authoring options. However currently the number one reason for me to continue using a PHPMailer component is that fact that it allows me to centralize all email communication within an application; although my approach may strike some as mixing the controller/model boundaries too much.&lt;br /&gt;&lt;br /&gt;The component is a basic wrapper around PHPMailer, which you should download and unpack into a folder called &lt;span style="font-weight: bold;"&gt;yourapp/app/vendors/mailer&lt;/span&gt; such that y&lt;span style="font-style: italic;"&gt;ourapp/app/vendors/mailer/class.phpmailer.php&lt;/span&gt; exist. Then in your components directory create the file &lt;span style="font-weight: bold;"&gt;mailer.php&lt;/span&gt; with the following content:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="php"&gt;&lt;br /&gt;&amp;lt;?php&lt;br /&gt;/*&lt;br /&gt; Emails:&lt;br /&gt;  sendSampleEmail&lt;br /&gt;  (I normally list all emails here for quick reference)&lt;br /&gt;*/&lt;br /&gt;class MailerComponent extends Object {&lt;br /&gt; var $phpMailer;&lt;br /&gt; var $testMode = false;&lt;br /&gt; var $from = 'automailer@example.com';&lt;br /&gt; var $fromName = 'Example.com Automailer';&lt;br /&gt; var $sig = "Regards,&lt;br /&gt;&lt;br /&gt;  Automailer";&lt;br /&gt; var $parent;&lt;br /&gt;&lt;br /&gt; // Create test email for use in testing mode&lt;br /&gt; function createTestEmail($email) {&lt;br /&gt;  $email = preg_replace('/(.*?)@(.*)/', "testmail+\$1@gmail.com", $email);&lt;br /&gt;  return $email;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; // Startup functions&lt;br /&gt; function startup(&amp;amp;$controller) {&lt;br /&gt;  App::import('vendor', 'Mailer', array('file' =&amp;gt; 'mailer/class.phpmailer.php'));&lt;br /&gt;  $this-&amp;gt;parent =&amp;amp; $controller;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; // Send an email&lt;br /&gt; function send($to = null, $subject = null, $message = null, $attachments = array(), $riders = array(), $replyTo = null, $replyToName = '', $from = null, $fromName = null) {&lt;br /&gt;  // Set up mail&lt;br /&gt;  $this-&amp;gt;phpMailer = new PHPMailer();&lt;br /&gt;  $this-&amp;gt;phpMailer-&amp;gt;IsSendmail();&lt;br /&gt;  $this-&amp;gt;phpMailer-&amp;gt;From = ($from) ? $from : $this-&amp;gt;from;&lt;br /&gt;  $this-&amp;gt;phpMailer-&amp;gt;FromName = ($fromName) ? $fromName : $this-&amp;gt;fromName;&lt;br /&gt;  $this-&amp;gt;phpMailer-&amp;gt;Subject = $subject;&lt;br /&gt;  $this-&amp;gt;phpMailer-&amp;gt;MsgHTML($message);&lt;br /&gt;&lt;br /&gt;  // Set reply to&lt;br /&gt;  if ($replyTo) $this-&amp;gt;phpMailer-&amp;gt;AddReplyTo($replyTo, $replyToName);&lt;br /&gt;&lt;br /&gt;  // Test mode switching, can also do domain based switching&lt;br /&gt;  if (true) {&lt;br /&gt;   $this-&amp;gt;testMode = true;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // Add address(s)&lt;br /&gt;  if (!is_array($to)) $to = array($to);&lt;br /&gt;  foreach ($to as $address) {&lt;br /&gt;   if ($this-&amp;gt;testMode) $address = $this-&amp;gt;createTestEmail($address);&lt;br /&gt;   $this-&amp;gt;phpMailer-&amp;gt;AddAddress($address);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // Add rider(s)&lt;br /&gt;  if (!$this-&amp;gt;testMode) $this-&amp;gt;phpMailer-&amp;gt;AddBCC('backup@example.com');&lt;br /&gt;  if (!empty($riders)) {&lt;br /&gt;   foreach ($riders as $r) {&lt;br /&gt;    if ($this-&amp;gt;testMode) $r = 'tester@example.com';&lt;br /&gt;    $this-&amp;gt;phpMailer-&amp;gt;AddBCC($r);&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // Add attachments&lt;br /&gt;  foreach ($attachments as $a) {&lt;br /&gt;   $this-&amp;gt;phpMailer-&amp;gt;AddAttachment($a);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // Send email&lt;br /&gt;  $success = $this-&amp;gt;phpMailer-&amp;gt;Send();&lt;br /&gt;  $this-&amp;gt;phpMailer-&amp;gt;ClearAddresses();&lt;br /&gt;  $this-&amp;gt;phpMailer-&amp;gt;ClearAttachments();&lt;br /&gt;  return $success;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; // Send sample email with data from a form&lt;br /&gt; function sendSampleEmail($data) {&lt;br /&gt;  $subject = "Sample Email - Contact from {$data['name']} ({$data['ip']})";&lt;br /&gt;  $contents = array();&lt;br /&gt;  foreach ($data as $field =&amp;gt; $value) $contents[] = ucwords($field) . ": {$value}";&lt;br /&gt;  $contents = join("\n", $contents);&lt;br /&gt;  $message = nl2br("Dear Admin,&lt;br /&gt;&lt;br /&gt;   The following contact request was received.&lt;br /&gt;&lt;br /&gt;   ---- Begin contact contents ----&lt;br /&gt;&lt;br /&gt;   {$contents}&lt;br /&gt;&lt;br /&gt;   ---- End contact contents   ----&lt;br /&gt;&lt;br /&gt;   {$this-&amp;gt;sig}");&lt;br /&gt;  $this-&amp;gt;send('admin@example.com', $subject, $message);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;?&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The component has support for sending all emails to a testing account and centers around the &lt;span style="font-style: italic;"&gt;send&lt;/span&gt; function. The send function parameters are pretty self explanatory with the only weird parameter being &lt;span style="font-style: italic;"&gt;$riders&lt;/span&gt;, which is my unconventional way of saying bccs. Each call of the &lt;span style="font-style: italic;"&gt;send&lt;/span&gt; function creates a new PHPMailer object, which may seem wasteful but in my experience prevents a lot of strange issues such as person B receiving email content intended for person A that was sent previously.&lt;br /&gt;&lt;br /&gt;The sample email function in the component sends a very simple contact form to the administrator of &lt;span style="font-style: italic;"&gt;example.com&lt;/span&gt;. The &lt;span style="font-style: italic;"&gt;$data&lt;/span&gt; variable is provided by the controller and is then used to compose a unique email. The message that is composed is very plain HTML that is simply a string with all new lines converted to HTML line breaks. For those needing to send complex HTML emails I normally have the message data be retrieve by calling something like &lt;span style="font-weight: bold;"&gt;$this-&gt;parent-&gt;requestAction("/mycontroller/emailFor/12"); &lt;/span&gt;which means the email is rendered by just another function in a controller that can be styled and tested easily.&lt;br /&gt;&lt;br /&gt;As the &lt;span style="font-style: italic;"&gt;$this-&gt;parent&lt;/span&gt; refers to the calling controller one can use that to load models, perform finds, access submitted variables, etc. The only thing to keep in mind is the level of dependency between the component and the calling controller. Although I do not find this to be a problem as the component is more of a function-based container that makes managing email content easier. Under extremely simple circumstances one would have the email functions be stored in the relevant controller instead of in a separate component.&lt;br /&gt;&lt;br /&gt;To use the component just include it as a component in your controller with:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="php"&gt;&lt;br /&gt;var $components = array('Mailer');&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And allow sending with a function like:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="php"&gt;&lt;br /&gt;function contact() {&lt;br /&gt; if ($this-&amp;gt;data) {&lt;br /&gt;  $this-&amp;gt;Mailer-&amp;gt;sendSampleEmail($this-&amp;gt;data['Contact']);&lt;br /&gt;  $this-&amp;gt;Session-&amp;gt;setFlash('Your message has been received. We will get back to you shortly.');&lt;br /&gt;  $this-&amp;gt;redirect('/contact');&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;While the component is set up to use the default mail sender it is also possible to set it up using a hosted provider like Gmail. Just see my post on using &lt;a href="http://www.24hourapps.com/2009/02/php-mail-using-gmail-smtp-and-phpmailer.html"&gt;Gmail with PHPMailer&lt;/a&gt; to view the configuration settings and place them in the "Set up mail" section of the &lt;span style="font-style: italic;"&gt;send&lt;/span&gt; function.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4774158543320836267-5248105869403408795?l=www.24hourapps.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Dc_NReKHOS_tVfxGdkcHsHC_pQU/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Dc_NReKHOS_tVfxGdkcHsHC_pQU/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Dc_NReKHOS_tVfxGdkcHsHC_pQU/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Dc_NReKHOS_tVfxGdkcHsHC_pQU/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=6-c0Hxu73j4:EMMFzl5q0K0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=6-c0Hxu73j4:EMMFzl5q0K0:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=6-c0Hxu73j4:EMMFzl5q0K0:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=6-c0Hxu73j4:EMMFzl5q0K0:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=6-c0Hxu73j4:EMMFzl5q0K0:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=6-c0Hxu73j4:EMMFzl5q0K0:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=6-c0Hxu73j4:EMMFzl5q0K0:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=6-c0Hxu73j4:EMMFzl5q0K0:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=6-c0Hxu73j4:EMMFzl5q0K0:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/24hourapps/~4/6-c0Hxu73j4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.24hourapps.com/feeds/5248105869403408795/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.24hourapps.com/2009/03/using-phpmailer-to-create-centralized.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/5248105869403408795?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/5248105869403408795?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/24hourapps/~3/6-c0Hxu73j4/using-phpmailer-to-create-centralized.html" title="Using PHPMailer to create a centralized email system in Cake PHP" /><author><name>Paul Chiu</name><uri>http://www.blogger.com/profile/16416350337923371068</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10755322441250465748" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.24hourapps.com/2009/03/using-phpmailer-to-create-centralized.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkEMQX8zfCp7ImA9WxVUE0s.&quot;"><id>tag:blogger.com,1999:blog-4774158543320836267.post-2088161867457623432</id><published>2009-03-18T17:18:00.000+10:00</published><updated>2009-03-18T17:18:00.184+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-18T17:18:00.184+10:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="bash" /><category scheme="http://www.blogger.com/atom/ns#" term="tips" /><title>Linux Tips 14: Changing the default cron editor to vim</title><content type="html">&lt;div&gt;For some reason a lot of servers I work with have set up the default cron editor, the one that is launched using &lt;b&gt;crontab -e&lt;/b&gt;, to &lt;a href="http://linuxreviews.org/man/nano/"&gt;nano&lt;/a&gt;. As a long time vim user I find nano to be too slow and strange for quick editing. Therefore I found the need to set up the account to use vim instead. To enable vim for use in crontab is easy, simply execute the following line at the command prompt:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;code&gt;export VISUAL=vim&lt;/code&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You can check that it worked using the command &lt;b&gt;env &lt;/b&gt;The output of &lt;i&gt;env &lt;/i&gt;should show &lt;i&gt;VISUAL=vim&lt;/i&gt; if the export command was executed successfully, alternatively you can just execute crontab -e to see which editor loaded. If you want the setting to be set all the time you need to add the line to your &lt;i&gt;.bashrc&lt;/i&gt; or .&lt;i&gt;bash_profile&lt;/i&gt;, depending on your *nix distro.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Please note that you can also use any other editor that can be launched from the command line. Just replace &lt;i&gt;vim &lt;/i&gt;with your editor of choice.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4774158543320836267-2088161867457623432?l=www.24hourapps.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Kwkqv3Blm3xTCjzt64Mcao9XWZQ/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Kwkqv3Blm3xTCjzt64Mcao9XWZQ/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Kwkqv3Blm3xTCjzt64Mcao9XWZQ/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Kwkqv3Blm3xTCjzt64Mcao9XWZQ/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=NuaXhhKYQ4Q:JAHElYrCHac:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=NuaXhhKYQ4Q:JAHElYrCHac:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=NuaXhhKYQ4Q:JAHElYrCHac:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=NuaXhhKYQ4Q:JAHElYrCHac:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=NuaXhhKYQ4Q:JAHElYrCHac:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=NuaXhhKYQ4Q:JAHElYrCHac:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=NuaXhhKYQ4Q:JAHElYrCHac:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=NuaXhhKYQ4Q:JAHElYrCHac:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=NuaXhhKYQ4Q:JAHElYrCHac:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/24hourapps/~4/NuaXhhKYQ4Q" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.24hourapps.com/feeds/2088161867457623432/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.24hourapps.com/2009/03/linux-tips-14-changing-default-cron.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/2088161867457623432?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/2088161867457623432?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/24hourapps/~3/NuaXhhKYQ4Q/linux-tips-14-changing-default-cron.html" title="Linux Tips 14: Changing the default cron editor to vim" /><author><name>Paul Chiu</name><uri>http://www.blogger.com/profile/16416350337923371068</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10755322441250465748" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.24hourapps.com/2009/03/linux-tips-14-changing-default-cron.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkcCR3w_fyp7ImA9WxVUGU8.&quot;"><id>tag:blogger.com,1999:blog-4774158543320836267.post-2258305066182979006</id><published>2009-03-17T17:11:00.004+10:00</published><updated>2009-03-25T05:47:46.247+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-25T05:47:46.247+10:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="cakephp" /><category scheme="http://www.blogger.com/atom/ns#" term="tips" /><category scheme="http://www.blogger.com/atom/ns#" term="css" /><title>Improved Cake PHP debug log messages CSS style</title><content type="html">&lt;div style="text-align: left;"&gt;As much as I like the &lt;a href="http://thechaw.com/debug_kit"&gt;CakePHP DebugKit component&lt;/a&gt; it sometimes appears to cause PHP fatal errors to not be shown, leaving me scratching my head at a white screen. At which point I need to remove the component inclusion code to see what I have done wrong.&lt;br /&gt;&lt;br /&gt;In search of a lighter weight solution I went to Google and found a nice &lt;a href="http://snook.ca/archives/cakephp/debug_styles/"&gt;CSS style&lt;/a&gt; for the class &lt;span class="Apple-style-span" style="font-style: italic;"&gt;cake-sql-log&lt;/span&gt; that automatically hid the SQL log table thereby removing much of the CakePHP debug mode output.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;However the problem with the style is that when working with a lot of queries it is too easy for the SQL log to fill up the whole screen and make it very difficult to view the queries. Therefore I have included my modified version below that creates a zoom effect on cells that makes readable only the cell that you are hovering over. The CSS styling code required are:&lt;div&gt;&lt;br /&gt;&lt;code&gt;.cake-sql-log { font-family:monospace; position:fixed; top:99%; z-index:100000; width:100%; background:#000; color:#FFF; border-collapse:collapse; }&lt;br /&gt;.cake-sql-log caption { background:#900; color:#FFF;    }&lt;br /&gt;.cake-sql-log:hover { top:auto; bottom:0; }&lt;br /&gt;.cake-sql-log td { font-size:3px; padding:1px; border:1px solid #999; background:#FFF; color:#000; }&lt;br /&gt;.cake-sql-log td:hover { font-size:10px; background:#FFA; }&lt;/code&gt;&lt;br /&gt;When the style is applied the default view of the SQL log will just show a minimal red bar at the bottom of the window:&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_29yMocwFCms/Sb7ftfO5tgI/AAAAAAAAAKI/6KtZ0cGdhyc/s1600-h/default.png"&gt;&lt;img src="http://3.bp.blogspot.com/_29yMocwFCms/Sb7ftfO5tgI/AAAAAAAAAKI/6KtZ0cGdhyc/s320/default.png" alt="" id="BLOGGER_PHOTO_ID_5313930582914872834" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 19px;" border="0" /&gt;&lt;/a&gt;And when you hover over the red bar the full log will be shown as with only the hovered cell readable:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_29yMocwFCms/Sb7ft32gl5I/AAAAAAAAAKQ/NrZry_YDkRw/s1600-h/hover.png"&gt;&lt;img src="http://4.bp.blogspot.com/_29yMocwFCms/Sb7ft32gl5I/AAAAAAAAAKQ/NrZry_YDkRw/s320/hover.png" alt="" id="BLOGGER_PHOTO_ID_5313930589523449746" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 51px;" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4774158543320836267-2258305066182979006?l=www.24hourapps.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/JGjZf_VvDoDQOlZviUcJaWb-JII/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/JGjZf_VvDoDQOlZviUcJaWb-JII/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/JGjZf_VvDoDQOlZviUcJaWb-JII/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/JGjZf_VvDoDQOlZviUcJaWb-JII/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=tbB3FquoDBk:KNesZ1FPOts:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=tbB3FquoDBk:KNesZ1FPOts:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=tbB3FquoDBk:KNesZ1FPOts:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=tbB3FquoDBk:KNesZ1FPOts:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=tbB3FquoDBk:KNesZ1FPOts:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=tbB3FquoDBk:KNesZ1FPOts:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=tbB3FquoDBk:KNesZ1FPOts:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=tbB3FquoDBk:KNesZ1FPOts:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=tbB3FquoDBk:KNesZ1FPOts:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/24hourapps/~4/tbB3FquoDBk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.24hourapps.com/feeds/2258305066182979006/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.24hourapps.com/2009/03/improved-cake-php-debug-log-messages.html#comment-form" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/2258305066182979006?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/2258305066182979006?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/24hourapps/~3/tbB3FquoDBk/improved-cake-php-debug-log-messages.html" title="Improved Cake PHP debug log messages CSS style" /><author><name>Paul Chiu</name><uri>http://www.blogger.com/profile/16416350337923371068</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10755322441250465748" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_29yMocwFCms/Sb7ftfO5tgI/AAAAAAAAAKI/6KtZ0cGdhyc/s72-c/default.png" height="72" width="72" /><thr:total>3</thr:total><feedburner:origLink>http://www.24hourapps.com/2009/03/improved-cake-php-debug-log-messages.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A08CQXc8eCp7ImA9WxVUEUU.&quot;"><id>tag:blogger.com,1999:blog-4774158543320836267.post-8690465903457284162</id><published>2009-03-16T17:51:00.003+10:00</published><updated>2009-03-16T17:51:00.970+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-16T17:51:00.970+10:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="mysql" /><category scheme="http://www.blogger.com/atom/ns#" term="tips" /><title>Working with multiple UTC/GMT timezones in MySQL</title><content type="html">&lt;div&gt;When working with international timezones it is not always possible to work off UTC/GMT time. At times the webhost may prevent you from changing configuration settings or data may already exist that prevent you from updating the system timezone.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Luckily with MySQL's date functionality it is not too hard to work around this problem. In this MySQL tip I will show how it is possible to work with GMT timezones for any record with a little date manipulation. Please note that I assume the dates you are working with are recognized MySQL date formats of either DATE, DATETIME, or TIMESTAMP.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The first thing that you need to do is find out the time offset between your database and GMT. You can do this by using the query &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;SELECT NOW() &lt;/span&gt;and checking the difference using a &lt;a href="http://www.google.com.au/search?q=gmt+time"&gt;Google query&lt;/a&gt;. As an example the server I am working on shows the time as "2009-03-16 01:35:15" while Google tells me the current GMT time is "6:35am Monday". This means the GMT offset of the server is +5 hours (6 - 1).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The second thing that you need is for your users to tell you what their GMT offset is. For example I am on the Australian east coast so my GMT offset is +10. For demonstration purposes I will assume this value is stored in the "settings" table in the field "gmt_offset". Using this two bits of information we can get the user's local time by using the following query.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;SELECT&lt;br /&gt;  DATE_ADD(NOW(), INTERVAL 5 HOUR) as gmt_time,&lt;br /&gt;  DATE_ADD(NOW(), INTERVAL (5 + gmt_offset) HOUR) as local_time&lt;br /&gt;FROM&lt;br /&gt;  settings&lt;br /&gt;WHERE&lt;br /&gt;  settings.user = 'Paul'&lt;/code&gt;&lt;br /&gt;A more complex example where manual time offsetting is required is for time related user notifications such as in a calendar application. In this example I will show how a notification table where a user set notification time is stored in the server's default time can be used so that we can retrieve notifications that need to be sent out correctly.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;code&gt;SELECT&lt;br /&gt;   n.*,&lt;br /&gt;   DATE_ADD(NOW(), INTERVAL (5 + s.gmt_offset) HOUR) as local_time_start,&lt;br /&gt;   DATE_ADD(DATE_ADD(NOW(), INTERVAL (5 + s.gmt_offset) HOUR), INTERVAL 1 MINUTE) as local_time_end&lt;br /&gt;FROM&lt;br /&gt;   notifications AS n&lt;br /&gt;   LEFT OUTER JOIN settings AS s ON (n.user = s.user)&lt;br /&gt;HAVING&lt;br /&gt;   local_time_start &amp;lt;= n.notify_at&lt;br /&gt;   AND n.notify_at &amp;lt; local_time_end&lt;/code&gt;&lt;br /&gt;&lt;div&gt;The trick with the above query is we are treating &lt;span class="Apple-style-span" style="font-style: italic;"&gt;notify_at&lt;/span&gt; as the user would expect, in the user's local time, therefore instead of adjusting it to the server time we simply calculate what the user's local time is at the current server time and see if any users need to have their notifications sent within this minute. While it is possible to shift the notification time to the server time and retrive required notification records based on that I find it more intuitive to leave user input as is.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Using the above method means that the system does not actually need to worry about any timezone issues unless the system in actioning a user set timezone as we can expect all users to work within their own. However such a method can mean more complications if your application's users are allowed to share date related information, in which case 3 offsets need to be combined (server offset, sharer offset, sharee offset) to show an accurate local time.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4774158543320836267-8690465903457284162?l=www.24hourapps.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/n7OXfrxnarJ0jKPEB5LIrVYxWMQ/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/n7OXfrxnarJ0jKPEB5LIrVYxWMQ/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/n7OXfrxnarJ0jKPEB5LIrVYxWMQ/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/n7OXfrxnarJ0jKPEB5LIrVYxWMQ/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=Occo4L8qFwM:AlsM0tN8EU0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=Occo4L8qFwM:AlsM0tN8EU0:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=Occo4L8qFwM:AlsM0tN8EU0:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=Occo4L8qFwM:AlsM0tN8EU0:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=Occo4L8qFwM:AlsM0tN8EU0:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=Occo4L8qFwM:AlsM0tN8EU0:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=Occo4L8qFwM:AlsM0tN8EU0:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=Occo4L8qFwM:AlsM0tN8EU0:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=Occo4L8qFwM:AlsM0tN8EU0:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/24hourapps/~4/Occo4L8qFwM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.24hourapps.com/feeds/8690465903457284162/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.24hourapps.com/2009/03/working-with-multiple-utcgmt-timezones.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/8690465903457284162?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/8690465903457284162?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/24hourapps/~3/Occo4L8qFwM/working-with-multiple-utcgmt-timezones.html" title="Working with multiple UTC/GMT timezones in MySQL" /><author><name>Paul Chiu</name><uri>http://www.blogger.com/profile/16416350337923371068</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10755322441250465748" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.24hourapps.com/2009/03/working-with-multiple-utcgmt-timezones.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEUCRnc7cSp7ImA9WxVUEUw.&quot;"><id>tag:blogger.com,1999:blog-4774158543320836267.post-9086029165474851593</id><published>2009-03-15T19:50:00.002+10:00</published><updated>2009-03-15T20:17:47.909+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-15T20:17:47.909+10:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="cakephp" /><category scheme="http://www.blogger.com/atom/ns#" term="tips" /><title>Managing semi-static select options in Cake PHP using table-less models</title><content type="html">In Cake PHP a model normally represents a database table. However there are times when it is not necessary to create a table to store data, in most cases this data would be a semi-static enumeration, as the size of an application increases the use of such semi-static lists increases.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For example options such as "Yes", "No", "Active", "Inactive" would simply be stored as tinyints in MySQL however they may need to be presented to the user as "Yes" or "No". For Cake PHP to automatically generate a drop down list with "Yes" and "No" a foreign key would need to be used instead, adding an unnecessary join to make select generation simpler.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The solution is to create a model that does not use a table at all. For most of my programs I call this model &lt;span class="Apple-style-span" style="font-style: italic;"&gt;Staticselect &lt;/span&gt;as its main purpose is to give me quick access to commonly used drop down options that I can set in my controllers for the FormHelper to use in views. The model code is:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre name="code" class="php"&gt;&amp;lt;?php&lt;br /&gt;class Staticselect extends AppModel {&lt;br /&gt;var $name = 'Staticselect';&lt;br /&gt;var $useTable = false;&lt;br /&gt;&lt;br /&gt;// Person titles&lt;br /&gt;function titles() {&lt;br /&gt;    $titles = array('Mr.', 'Mrs.', 'Ms.', 'Miss.');&lt;br /&gt;    return $this-&amp;gt;toOptions($titles);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Convert array to key value options&lt;br /&gt;function toOptions($a) {&lt;br /&gt;    $os = array();&lt;br /&gt;    foreach ($a as $v) $os[$v] = $v;&lt;br /&gt;    return $os;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// No/yes options with int values&lt;br /&gt;function noYesInt() {&lt;br /&gt;    return array('0' =&amp;gt; 'No', '1' =&amp;gt; 'Yes');&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;?&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The above code shows a few sample functions. The most useful is probably &lt;span class="Apple-style-span" style="font-style: italic;"&gt;toOptions&lt;/span&gt;, which will take an array and turn it into a hash where the keys and values are the same so that when generating selects the value selected by the user is also submitted with the form. The function &lt;span class="Apple-style-span" style="font-style: italic;"&gt;noYesInt&lt;/span&gt; is a simple example of data I commonly store in such a model.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For those less familiar with the way Cake PHP works with options I will also show how the model can be used in a controller and view. The controller function where the static options are to be used should contain a line with:&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="php"&gt;&lt;br /&gt;$this-&amp;gt;set('nyOptions', $this-&amp;gt;Staticselect-&amp;gt;noYesInt());&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;While the view would use the data in a form input using the code:&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="php"&gt;&lt;br /&gt;&amp;lt;?= $form-&amp;gt;input('Settings.hideEmail', array('options' =&amp;gt; $nyOptions)) ?&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4774158543320836267-9086029165474851593?l=www.24hourapps.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/YAD9J9XmXM4ql6RHco3lDbJvhRU/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/YAD9J9XmXM4ql6RHco3lDbJvhRU/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/YAD9J9XmXM4ql6RHco3lDbJvhRU/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/YAD9J9XmXM4ql6RHco3lDbJvhRU/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=eBMU9r_8bGs:SBR0BbY1sxs:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=eBMU9r_8bGs:SBR0BbY1sxs:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=eBMU9r_8bGs:SBR0BbY1sxs:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=eBMU9r_8bGs:SBR0BbY1sxs:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=eBMU9r_8bGs:SBR0BbY1sxs:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=eBMU9r_8bGs:SBR0BbY1sxs:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=eBMU9r_8bGs:SBR0BbY1sxs:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=eBMU9r_8bGs:SBR0BbY1sxs:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=eBMU9r_8bGs:SBR0BbY1sxs:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/24hourapps/~4/eBMU9r_8bGs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.24hourapps.com/feeds/9086029165474851593/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.24hourapps.com/2009/03/managing-semi-static-select-options-in.html#comment-form" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/9086029165474851593?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/9086029165474851593?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/24hourapps/~3/eBMU9r_8bGs/managing-semi-static-select-options-in.html" title="Managing semi-static select options in Cake PHP using table-less models" /><author><name>Paul Chiu</name><uri>http://www.blogger.com/profile/16416350337923371068</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10755322441250465748" /></author><thr:total>5</thr:total><feedburner:origLink>http://www.24hourapps.com/2009/03/managing-semi-static-select-options-in.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEYEQX08eCp7ImA9WxVUEEw.&quot;"><id>tag:blogger.com,1999:blog-4774158543320836267.post-6051559320559450086</id><published>2009-03-14T17:35:00.000+10:00</published><updated>2009-03-14T17:35:00.370+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-14T17:35:00.370+10:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="dates" /><category scheme="http://www.blogger.com/atom/ns#" term="tips" /><category scheme="http://www.blogger.com/atom/ns#" term="php" /><title>Converting Australian (little endian) date to ISO using just one line in PHP or Javascript</title><content type="html">Working with dates can often be problematic when dealing with Australian localization (dd/mm/yyyy, little endian) as most server software tends to understand either ISO based (yyyy-mm-dd, big endian) formats or US formats (mm/dd/yyyy, middle endian). Having seen various solutions that involve regular expressions or reconstruction of date strings using string concatenation I realized there is a much simpler way to go from Australian dates to ISO dates that MySQL and PHP's strtotime will happily work with.&lt;br /&gt;&lt;br /&gt;In PHP the code is:&lt;br /&gt;&lt;pre name="code" class="php"&gt;&lt;br /&gt;// Original: '31-12-2008'&lt;br /&gt;// $isoDate: '2008-12-31'&lt;br /&gt;$isoDate = join('-', array_reverse(split('-', '31-12-2008')));&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In Javascript the code is:&lt;br /&gt;&lt;pre name="code" class="js"&gt;&lt;br /&gt;// Original: '31-12-2008'&lt;br /&gt;// isoDate: '2008-12-31'&lt;br /&gt;var isoDate = '31-12-2008'.split('-').reverse().join('-');&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The above one liners can be expanded to turn the given Australian dates into usable time with just a little bit more code as well.&lt;br /&gt;&lt;br /&gt;In PHP the code is:&lt;br /&gt;&lt;pre name="code" class="php"&gt;&lt;br /&gt;$t = strtotime(join('-', array_reverse(split('-', '31-12-2008'))));&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In Javascript the code is:&lt;br /&gt;&lt;pre name="code" class="js"&gt;&lt;br /&gt;var t = new Date('31-12-2008'.split('-').reverse().join(''));&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Looking at the above code it appears that it is actually easier to turn a little endian date into an ISO date than it is to covert a middle endian date into an ISO date as the array reverse trick will not be applicable when a flip is required between the first and second date elements. In such cases regular expressions would do the trick much more nicely.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4774158543320836267-6051559320559450086?l=www.24hourapps.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/VDaq6Nf5ZeEQOq10wFN-DTZVlNk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/VDaq6Nf5ZeEQOq10wFN-DTZVlNk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/VDaq6Nf5ZeEQOq10wFN-DTZVlNk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/VDaq6Nf5ZeEQOq10wFN-DTZVlNk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=2B0LLeeeQcU:mcaDMz_wfdE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=2B0LLeeeQcU:mcaDMz_wfdE:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=2B0LLeeeQcU:mcaDMz_wfdE:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=2B0LLeeeQcU:mcaDMz_wfdE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=2B0LLeeeQcU:mcaDMz_wfdE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=2B0LLeeeQcU:mcaDMz_wfdE:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=2B0LLeeeQcU:mcaDMz_wfdE:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=2B0LLeeeQcU:mcaDMz_wfdE:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=2B0LLeeeQcU:mcaDMz_wfdE:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/24hourapps/~4/2B0LLeeeQcU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.24hourapps.com/feeds/6051559320559450086/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.24hourapps.com/2009/03/converting-australian-little-endian.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/6051559320559450086?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/6051559320559450086?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/24hourapps/~3/2B0LLeeeQcU/converting-australian-little-endian.html" title="Converting Australian (little endian) date to ISO using just one line in PHP or Javascript" /><author><name>Paul Chiu</name><uri>http://www.blogger.com/profile/16416350337923371068</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10755322441250465748" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.24hourapps.com/2009/03/converting-australian-little-endian.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkYGQXo9fip7ImA9WxVVGU4.&quot;"><id>tag:blogger.com,1999:blog-4774158543320836267.post-2558773436064291919</id><published>2009-03-13T17:42:00.000+10:00</published><updated>2009-03-13T17:42:00.466+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-13T17:42:00.466+10:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="jquery" /><category scheme="http://www.blogger.com/atom/ns#" term="tips" /><title>How to check if jQuery is loaded</title><content type="html">This post is a result of my analysis of my Google Analytics logs. It seems a lot of people need to know how to check whether jQuery is loaded. I will demonstrate two options here. To check if jQuery exists use:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="js"&gt;&lt;br /&gt;if (jQuery) {&lt;br /&gt;alert('jQuery is loaded!');&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Alternatively you can check if jQuery is not loaded by using:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="js"&gt;&lt;br /&gt;if (typeof jQuery == 'undefined') {&lt;br /&gt;alert('jQuery has not been loaded!');&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4774158543320836267-2558773436064291919?l=www.24hourapps.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/SgeBhCCNuO5gk-IoqaOuHRe4k1I/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/SgeBhCCNuO5gk-IoqaOuHRe4k1I/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/SgeBhCCNuO5gk-IoqaOuHRe4k1I/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/SgeBhCCNuO5gk-IoqaOuHRe4k1I/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=raYlz4_53Bs:DhJijU8_sGY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=raYlz4_53Bs:DhJijU8_sGY:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=raYlz4_53Bs:DhJijU8_sGY:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=raYlz4_53Bs:DhJijU8_sGY:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=raYlz4_53Bs:DhJijU8_sGY:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=raYlz4_53Bs:DhJijU8_sGY:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=raYlz4_53Bs:DhJijU8_sGY:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=raYlz4_53Bs:DhJijU8_sGY:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=raYlz4_53Bs:DhJijU8_sGY:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/24hourapps/~4/raYlz4_53Bs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.24hourapps.com/feeds/2558773436064291919/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.24hourapps.com/2009/03/how-to-check-if-jquery-is-loaded_13.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/2558773436064291919?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/2558773436064291919?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/24hourapps/~3/raYlz4_53Bs/how-to-check-if-jquery-is-loaded_13.html" title="How to check if jQuery is loaded" /><author><name>Paul Chiu</name><uri>http://www.blogger.com/profile/16416350337923371068</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10755322441250465748" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.24hourapps.com/2009/03/how-to-check-if-jquery-is-loaded_13.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0ICQXc-fSp7ImA9WxVVGEk.&quot;"><id>tag:blogger.com,1999:blog-4774158543320836267.post-7966707652934201796</id><published>2009-03-12T17:06:00.001+10:00</published><updated>2009-03-12T17:06:00.955+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-12T17:06:00.955+10:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="yui" /><category scheme="http://www.blogger.com/atom/ns#" term="tips" /><title>Javascript loading optimization with YUICompressor and output piping</title><content type="html">The &lt;a href="http://developer.yahoo.com/yui/compressor/"&gt;YUI Compressor&lt;/a&gt; is a Java tool that will take any Javascript file you give it and output a minified version. The minified version will remove all unnecessary characters as well as optimize the code so that it takes up as little space as possible; there is also a side benefit of code obsfucation that makes it a little harder for visitors to view your source code.&lt;br /&gt;&lt;br /&gt;While using the minfier will improve the performance of your site, it is much better to reduce the number of asset requests by combining as many Javascript files as possible. This can be achieved using a script similar to the following:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;#!/bin/sh&lt;br /&gt;echo "Creating default layout min js ..."&lt;br /&gt;java -jar ~/tmp/bin/yuic.jar jquery.min.js &gt; layouts/min.default.js&lt;br /&gt;java -jar ~/tmp/bin/yuic.jar layouts/default.js &gt;&gt; layouts/min.default.js&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;With the above script the two files that I use in the default template of my application is combined into just one file. Please note that the first compression line pipes the output by replacing, using &amp;gt;, the contents of min.default.js and the second (and any other lines) will append to min.default.js using &amp;gt;&amp;gt;. Please note that the script assumes that you have installed the YUI Compressor in your &lt;span style="font-style: italic;"&gt;tmp&lt;/span&gt; directory, your actual YUI Compressor path and executable file name will be different.&lt;br /&gt;&lt;br /&gt;The example I used is a very simple case that doesn't actually require such optimization. However if you have a complicated website that utilizes 10 different jQuery plugins that even if all are cached with change timestamp checking time of 200ms, the script can save almost two seconds from your page's loading time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4774158543320836267-7966707652934201796?l=www.24hourapps.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Ji9JFmYQJQpeabDWLaHzvcZ2vBY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Ji9JFmYQJQpeabDWLaHzvcZ2vBY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Ji9JFmYQJQpeabDWLaHzvcZ2vBY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Ji9JFmYQJQpeabDWLaHzvcZ2vBY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=IhcNbOBU0fE:nnMBXUd_mmI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=IhcNbOBU0fE:nnMBXUd_mmI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=IhcNbOBU0fE:nnMBXUd_mmI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=IhcNbOBU0fE:nnMBXUd_mmI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=IhcNbOBU0fE:nnMBXUd_mmI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=IhcNbOBU0fE:nnMBXUd_mmI:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=IhcNbOBU0fE:nnMBXUd_mmI:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=IhcNbOBU0fE:nnMBXUd_mmI:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=IhcNbOBU0fE:nnMBXUd_mmI:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/24hourapps/~4/IhcNbOBU0fE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.24hourapps.com/feeds/7966707652934201796/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.24hourapps.com/2009/03/javascript-loading-optimization-with.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/7966707652934201796?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/7966707652934201796?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/24hourapps/~3/IhcNbOBU0fE/javascript-loading-optimization-with.html" title="Javascript loading optimization with YUICompressor and output piping" /><author><name>Paul Chiu</name><uri>http://www.blogger.com/profile/16416350337923371068</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10755322441250465748" /></author><thr:total>1</thr:total><feedburner:origLink>http://www.24hourapps.com/2009/03/javascript-loading-optimization-with.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUEMQXg8eCp7ImA9WxVVF0g.&quot;"><id>tag:blogger.com,1999:blog-4774158543320836267.post-2695618927022764334</id><published>2009-03-11T17:48:00.000+10:00</published><updated>2009-03-11T17:48:00.670+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-11T17:48:00.670+10:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="tips" /><category scheme="http://www.blogger.com/atom/ns#" term="squid" /><category scheme="http://www.blogger.com/atom/ns#" term="ubuntu" /><title>Linux Tips 13: Ubuntu Squid server setup how to</title><content type="html">Squid is a Linux proxy server that allows you to cache requests to boost speed as well as allowing you to hide your real IP. This guide will cover how to set up a Squid proxy server in Ubuntu. The first step is to install squid using apt-get with the command: &lt;span style="font-weight: bold;"&gt;sudo apt-get install squid&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;With Squid installed you can modify the configuration file in /etc/squid/squid.conf Before being able to use the server the configuration file must be updated to allow your host. I have updated my proxy to allow access from my IP by adding the line &lt;span style="font-weight: bold;"&gt;acl our_networks src 1.2.3.4&lt;/span&gt;; you should replace &lt;span style="font-style: italic;"&gt;1.2.3.4&lt;/span&gt; with your IP address. I added it to just above the line &lt;span style="font-style: italic;"&gt;http_access allow our_networks&lt;/span&gt;, which I also removed the commenting of.&lt;br /&gt;&lt;br /&gt;To enable anonymizing of your IP address you also want to uncomment the line: &lt;span style="font-style: italic;"&gt;forwarded_for on&lt;/span&gt;, and change it to &lt;span style="font-weight: bold;"&gt;forwarded_for off&lt;/span&gt; which will make all requests through the proxy look as though it came from the proxy it self.&lt;br /&gt;&lt;br /&gt;To test and use your proxy just check the proxy setting instructions for your web browser then set the server address to the IP address of your Ubuntu server and the port to 3128.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4774158543320836267-2695618927022764334?l=www.24hourapps.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/SXhJLbjE2MGj7ZtUzPwA-e3Hf4Y/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/SXhJLbjE2MGj7ZtUzPwA-e3Hf4Y/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/SXhJLbjE2MGj7ZtUzPwA-e3Hf4Y/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/SXhJLbjE2MGj7ZtUzPwA-e3Hf4Y/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=w2rUxIefjwo:oYCqRdWaXV4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=w2rUxIefjwo:oYCqRdWaXV4:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=w2rUxIefjwo:oYCqRdWaXV4:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=w2rUxIefjwo:oYCqRdWaXV4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=w2rUxIefjwo:oYCqRdWaXV4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=w2rUxIefjwo:oYCqRdWaXV4:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=w2rUxIefjwo:oYCqRdWaXV4:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=w2rUxIefjwo:oYCqRdWaXV4:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=w2rUxIefjwo:oYCqRdWaXV4:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/24hourapps/~4/w2rUxIefjwo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.24hourapps.com/feeds/2695618927022764334/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.24hourapps.com/2009/03/linux-tips-13-ubuntu-squid-server-setup.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/2695618927022764334?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/2695618927022764334?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/24hourapps/~3/w2rUxIefjwo/linux-tips-13-ubuntu-squid-server-setup.html" title="Linux Tips 13: Ubuntu Squid server setup how to" /><author><name>Paul Chiu</name><uri>http://www.blogger.com/profile/16416350337923371068</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10755322441250465748" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.24hourapps.com/2009/03/linux-tips-13-ubuntu-squid-server-setup.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0UERHkyfyp7ImA9WxVVGE0.&quot;"><id>tag:blogger.com,1999:blog-4774158543320836267.post-1370233461388487789</id><published>2009-03-10T17:14:00.005+10:00</published><updated>2009-03-12T05:53:25.797+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-12T05:53:25.797+10:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="jquery" /><category scheme="http://www.blogger.com/atom/ns#" term="ajax" /><title>Object oriented event handling in Javascript using the jQuery plugin model</title><content type="html">When coding my &lt;a href="http://passbook.24hourapps.com/"&gt;online password manager&lt;/a&gt;, Passbook, I found it hard to wrangle the Javascript code to fit into the many elements that could have been generated on the screen. It is not a new problem to me as I have worked with refactored combination pages that attempts to bring together what used to be 10 or so pages of functionality into an AJAX enabled super page. The result of which is normally a thousand plus lines of unmaintainable code.&lt;br /&gt;&lt;br /&gt;For Passbook I decided to solve this problem once and for all. The solution I believe is in objectifying page elements as a block so that a panel with an edit and delete button can be duplicated quickly without having the Javascript code keep track of which panel on the page was clicked and trying to modify that page element. An object oriented approach would mean the page object could edit or delete it self because it knows what it is and what it represents.&lt;br /&gt;&lt;br /&gt;While there are some existing solutions that use custom methods to streamline the object oriented process and &lt;a href="http://www.brockman.se/writing/method-references.html.utf8"&gt;work around Javascript's event target scoping&lt;/a&gt; of "this". I believe a better method existed that did not require so much prototype modification and was more self contained and flexible. My solution is to use &lt;a href="http://www.learningjquery.com/2007/10/a-plugin-development-pattern"&gt;jQuery's plugin model&lt;/a&gt; to control on page elements, or widgets.&lt;br /&gt;&lt;br /&gt;To see the basic pattern it is easiest to first checkout the &lt;a href="http://blog.24hourapps.com/jquery-oo-events.html"&gt;functional demo&lt;/a&gt;. The demo contains two main elements: a widgets container where an add action exists, and a widget controller that offers the user the ability to submit it or remove it. The demo shows the widget manipulating it self, its parent, as well as using a basic ajax callback within it self.&lt;br /&gt;&lt;br /&gt;The sequence in which I would normally code this is to first create my HTML code. In this case it is very simple and consists of the following:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"&lt;br /&gt;"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&amp;gt;&lt;br /&gt;&amp;lt;html xmlns="http://www.w3.org/1999/xhtml"&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;&amp;lt;title&amp;gt;Object oriented event handling in Javascript using JQuery plugins&amp;lt;/title&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;&amp;lt;!-- HTML --&amp;gt;&lt;br /&gt;&amp;lt;h1&amp;gt;My widgets&amp;lt;/h1&amp;gt;&lt;br /&gt;&amp;lt;div class="widgetContainer"&amp;gt;&lt;br /&gt; &amp;lt;div&amp;gt;&amp;lt;a href="#" id="add"&amp;gt;Add widget&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;amp;nbsp;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Then the widget container plugin would be created with the add link hooked up to an event. By creating the widget container as a plugin it means the code is not restricted to any page or element. As long as the element ids or classes within the widget matches it can be turned into a functional GUI element. The basic plugin code with the onload initializer is:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="js"&gt;&lt;br /&gt;// Widget container&lt;br /&gt;(function($) {&lt;br /&gt;// Widget container plugin&lt;br /&gt;$.fn.widgetContainer = function() {&lt;br /&gt; this.each(function() {&lt;br /&gt;  // Vars&lt;br /&gt;  var wc = $(this);&lt;br /&gt;&lt;br /&gt;  // Set events&lt;br /&gt;  wc.find('#add').click(function(e) { if (e) e.preventDefault(); add(wc) });&lt;br /&gt; });&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Add a widget to the container&lt;br /&gt;function add(wc) {&lt;br /&gt; console.log("add clicked");&lt;br /&gt;}&lt;br /&gt;})(jQuery);&lt;br /&gt;&lt;br /&gt;// Main&lt;br /&gt;$(function() {&lt;br /&gt;$('.widgetContainer').widgetContainer();&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The above code is quite compact and by using the plugin model we can have multiple widget containers on the page without making any changes to the code. The benefits of object oriented event handling becomes clearer when we actually create the widget, which is designed to exist with other widgets in the widget container. The widget code is:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="js"&gt;&lt;br /&gt;// Widget&lt;br /&gt;(function() {&lt;br /&gt;// Widget plugin&lt;br /&gt;$.fn.widget = function(container) {&lt;br /&gt; this.each(function() {&lt;br /&gt;  // Vars&lt;br /&gt;  var w = $(this);&lt;br /&gt;  w.parent = container;&lt;br /&gt;&lt;br /&gt;  // Set events&lt;br /&gt;  w.find('form').submit(function(e) { if (e) e.preventDefault(); submit(w) });&lt;br /&gt;  w.find('.remove').click(function(e) { if (e) e.preventDefault(); remove(w) });&lt;br /&gt; });&lt;br /&gt;}&lt;br /&gt;$.fn.widget.template = '&amp;lt;div class="widget"&amp;gt;&amp;lt;form action="" method="post"&amp;gt;&amp;lt;input value="" type="text"&amp;gt;&amp;lt;input value="Action!" type="submit"&amp;gt;&amp;lt;a href="#" class="remove"&amp;gt;Remove&amp;lt;/a&amp;gt;&amp;lt;/form&amp;gt;&amp;lt;/div&amp;gt;';&lt;br /&gt;&lt;br /&gt;// Remove widget&lt;br /&gt;function remove(w) {&lt;br /&gt; w.remove();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Submit widget data&lt;br /&gt;function submit(w) {&lt;br /&gt; w.css('background', 'red');&lt;br /&gt; $.post('/', w.find('form').serialize(), function(data) {&lt;br /&gt;  w.find(':text').val((new Date()).toString());&lt;br /&gt;  w.parent.fadeOut();&lt;br /&gt;  setTimeout(function() { w.parent.fadeIn() }, 500);&lt;br /&gt; });&lt;br /&gt;}&lt;br /&gt;})();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The above code does not re-use the jQuery parameter because I have it residing in the original widget container code so that it is loaded at the same time. However if you decide to abstract it out into its own file that can be done easily by simply including the jQuery parameter in the last &lt;span style="font-style: italic;"&gt;();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The widget code follows the same pattern as the widget container however as one can see it does a lot more. The widget HTML is stored in $.fn.widget.template, however it can also be placed on page and retrieved using a jQuery selected on initialization, it all depends on how you want to balance dependencies and ease of editability.&lt;br /&gt;&lt;br /&gt;The pattern works around Javascript's event limitations by passing the widget object into a new function attached to widget events. This is a simple way to be able to refer back to the object of interest and not just the event target. I will often include the event target (&lt;span style="font-style: italic;"&gt;this&lt;/span&gt;) as a parameter for functions like &lt;span style="font-style: italic;"&gt;submit&lt;/span&gt; when there is extra data that needs to be taken into consideration before actions are to be taken.&lt;br /&gt;&lt;br /&gt;The final bit of code that ties the widget to the widget container is to update the widget container's add function. The add function needs to be updated to the following so that the widget is inserted into the widget container and initialized with all event handlers.&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="js"&gt;&lt;br /&gt;// Add a widget to the container&lt;br /&gt;function add(wc) {&lt;br /&gt;var widget = $($.fn.widget.template);&lt;br /&gt;widget&lt;br /&gt; .appendTo(wc)&lt;br /&gt; .fadeIn('slow')&lt;br /&gt; .widget(wc);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Putting it all together, the full javascript required to make a widget container that can add multiple widget becomes:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="js"&gt;&lt;br /&gt;// Widget container&lt;br /&gt;(function($) {&lt;br /&gt;// Widget container plugin&lt;br /&gt;$.fn.widgetContainer = function() {&lt;br /&gt; this.each(function() {&lt;br /&gt;  // Vars&lt;br /&gt;  var wc = $(this);&lt;br /&gt;&lt;br /&gt;  // Set events&lt;br /&gt;  wc.find('#add').click(function(e) { if (e) e.preventDefault(); add(wc) });&lt;br /&gt; });&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Add a widget to the container&lt;br /&gt;function add(wc) {&lt;br /&gt; var widget = $($.fn.widget.template);&lt;br /&gt; widget&lt;br /&gt;  .appendTo(wc)&lt;br /&gt;  .fadeIn('slow')&lt;br /&gt;  .widget(wc);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Widget&lt;br /&gt;(function() {&lt;br /&gt; // Widget plugin&lt;br /&gt; $.fn.widget = function(container) {&lt;br /&gt;  this.each(function() {&lt;br /&gt;   // Vars&lt;br /&gt;   var w = $(this);&lt;br /&gt;   w.parent = container;&lt;br /&gt;&lt;br /&gt;   // Set events&lt;br /&gt;   w.find('form').submit(function(e) { if (e) e.preventDefault(); submit(w) });&lt;br /&gt;   w.find('.remove').click(function(e) { if (e) e.preventDefault(); remove(w) });&lt;br /&gt;  });&lt;br /&gt; }&lt;br /&gt; $.fn.widget.template = '&amp;lt;div class="widget"&amp;gt;&amp;lt;form action="" method="POST"&amp;gt;&amp;lt;input type="text" value=""/&amp;gt;&amp;lt;input type="submit" value="Action!"/&amp;gt;&amp;lt;a href="#" class="remove"&amp;gt;Remove&amp;lt;/a&amp;gt;&amp;lt;/form&amp;gt;&amp;lt;/div&amp;gt;';&lt;br /&gt;&lt;br /&gt; // Remove widget&lt;br /&gt; function remove(w) {&lt;br /&gt;  w.remove();&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; // Submit widget data&lt;br /&gt; function submit(w) {&lt;br /&gt;  w.css('background', 'red');&lt;br /&gt;  $.post('/', w.find('form').serialize(), function(data) {&lt;br /&gt;   w.find(':text').val((new Date()).toString());&lt;br /&gt;   w.parent.fadeOut();&lt;br /&gt;   setTimeout(function() { w.parent.fadeIn() }, 500);&lt;br /&gt;  });&lt;br /&gt; }&lt;br /&gt;})();&lt;br /&gt;})(jQuery);&lt;br /&gt;&lt;br /&gt;// Main&lt;br /&gt;$(function() {&lt;br /&gt;$('.widgetContainer').widgetContainer();&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Once again, please see the &lt;a href="http://blog.24hourapps.com/jquery-oo-events.html"&gt;demo&lt;/a&gt; for the full source code and to see it in action. Hopefully this will make your development of Javascript based GUIs much simpler as it has done for me. I understand that it is not a perfect solution but it has served me well in my work and projects by limiting the scope of what I need to focus on into very manageable objects.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4774158543320836267-1370233461388487789?l=www.24hourapps.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/1ON5S6OTGH2PsUfktu3HdnwzRCA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/1ON5S6OTGH2PsUfktu3HdnwzRCA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/1ON5S6OTGH2PsUfktu3HdnwzRCA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/1ON5S6OTGH2PsUfktu3HdnwzRCA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=0rTla7phUKc:cCtGvkq8g30:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=0rTla7phUKc:cCtGvkq8g30:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=0rTla7phUKc:cCtGvkq8g30:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=0rTla7phUKc:cCtGvkq8g30:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=0rTla7phUKc:cCtGvkq8g30:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=0rTla7phUKc:cCtGvkq8g30:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=0rTla7phUKc:cCtGvkq8g30:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=0rTla7phUKc:cCtGvkq8g30:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=0rTla7phUKc:cCtGvkq8g30:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/24hourapps/~4/0rTla7phUKc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.24hourapps.com/feeds/1370233461388487789/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.24hourapps.com/2009/03/object-oriented-event-handling-in.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/1370233461388487789?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/1370233461388487789?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/24hourapps/~3/0rTla7phUKc/object-oriented-event-handling-in.html" title="Object oriented event handling in Javascript using the jQuery plugin model" /><author><name>Paul Chiu</name><uri>http://www.blogger.com/profile/16416350337923371068</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10755322441250465748" /></author><thr:total>1</thr:total><feedburner:origLink>http://www.24hourapps.com/2009/03/object-oriented-event-handling-in.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CU4MQXY7eCp7ImA9WxVVFUU.&quot;"><id>tag:blogger.com,1999:blog-4774158543320836267.post-9003639653201658606</id><published>2009-03-09T17:33:00.003+10:00</published><updated>2009-03-09T17:33:00.800+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-09T17:33:00.800+10:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="traffic" /><category scheme="http://www.blogger.com/atom/ns#" term="analytics" /><title>February 2009 traffic review</title><content type="html">The progress of my blog has surpassed my expectations in February. My original quarterly goal for March was a high of 50 visitors a day. However on February 28 the Google Analytics traffic report shows a visitor count of 82. The traffic is still largely coming from Google search, with RSS subscriber numbers embarrassingly low. The traffic chart is below.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_29yMocwFCms/SbMXdyXZzDI/AAAAAAAAAKA/-hCRDki5JPI/s1600-h/Picture+30.PNG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 46px;" src="http://2.bp.blogspot.com/_29yMocwFCms/SbMXdyXZzDI/AAAAAAAAAKA/-hCRDki5JPI/s320/Picture+30.PNG" alt="" id="BLOGGER_PHOTO_ID_5310614186103524402" border="0" /&gt;&lt;/a&gt;With my modest traffic goals met I have set a new quarterly goal, for the end of June, of archiving 200 visitors a day. Based on current growth of each week giving me a new high that is approximately 10 higher than the previous week, it should be achievable; although I am waiting for the figures to plateau as these things seem to do.&lt;br /&gt;&lt;br /&gt;The traffic numbers also seem to correlate tightly to the number of posts I have. The current post count is 75. So once I hit 200 posts I should be able to achieve the 2nd quater goal I have set. While I understand this post is rather different than my regular posts on programming and tech hopefully this will help others put their ventures into building a blog in perspective in terms of realistic grow rates.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4774158543320836267-9003639653201658606?l=www.24hourapps.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/1EpG9gDv4x9AB5yJU6Q40ZFTC3M/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/1EpG9gDv4x9AB5yJU6Q40ZFTC3M/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/1EpG9gDv4x9AB5yJU6Q40ZFTC3M/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/1EpG9gDv4x9AB5yJU6Q40ZFTC3M/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=8KoMCxlOWF8:US49Uqp4lFQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=8KoMCxlOWF8:US49Uqp4lFQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=8KoMCxlOWF8:US49Uqp4lFQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=8KoMCxlOWF8:US49Uqp4lFQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=8KoMCxlOWF8:US49Uqp4lFQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=8KoMCxlOWF8:US49Uqp4lFQ:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=8KoMCxlOWF8:US49Uqp4lFQ:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=8KoMCxlOWF8:US49Uqp4lFQ:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=8KoMCxlOWF8:US49Uqp4lFQ:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/24hourapps/~4/8KoMCxlOWF8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.24hourapps.com/feeds/9003639653201658606/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.24hourapps.com/2009/03/february-2009-traffic-review.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/9003639653201658606?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/9003639653201658606?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/24hourapps/~3/8KoMCxlOWF8/february-2009-traffic-review.html" title="February 2009 traffic review" /><author><name>Paul Chiu</name><uri>http://www.blogger.com/profile/16416350337923371068</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10755322441250465748" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_29yMocwFCms/SbMXdyXZzDI/AAAAAAAAAKA/-hCRDki5JPI/s72-c/Picture+30.PNG" height="72" width="72" /><thr:total>2</thr:total><feedburner:origLink>http://www.24hourapps.com/2009/03/february-2009-traffic-review.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkEEQX8yeCp7ImA9WxVVFEQ.&quot;"><id>tag:blogger.com,1999:blog-4774158543320836267.post-6367244798284067584</id><published>2009-03-08T17:50:00.000+10:00</published><updated>2009-03-08T17:50:00.190+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-08T17:50:00.190+10:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="email" /><category scheme="http://www.blogger.com/atom/ns#" term="php" /><title>Simple PHP email testing with regular expressions</title><content type="html">When working with system generated emails in PHP it can be difficult as email is often considered unique data in the system. To create and check various email accounts can become tedious and when testing on a live system the results of sending a test email to a client can be rather embarrassing.&lt;br /&gt;&lt;br /&gt;The solution is a simple PHP function that you can call with any email address and it will convert it into a unique email address for an existing mailbox. The function will take an email address like &lt;span style="font-style: italic;"&gt;realclient@client.com&lt;/span&gt; to &lt;span style="font-style: italic;"&gt;myaccount+realclient@gmail.com&lt;/span&gt; Please note that the testing destination email address needs to support the + operator (ie Gmail).&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="php"&gt;&lt;br /&gt;// Create test email for use in testing mode&lt;br /&gt;function createTestEmail($email) {&lt;br /&gt;   $email = preg_replace('/(.*?)@(.*)/', "myaccount+\$1@gmail.com", $email);&lt;br /&gt;   return $email;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To use the above function simply replace &lt;span style="font-style: italic;"&gt;myaccount&lt;/span&gt; with your email address's name and &lt;span style="font-style: italic;"&gt;gmail.com&lt;/span&gt; with your email's domain then put through it any email address your system sends to when you are testing. I would recommend automatically replace any destination address with the results of the function if the URL from &lt;span style="font-style: italic;"&gt;$_SERVER['HTTP_HOST']&lt;/span&gt; matches your development domain; this way the process is automatic and you don't need to worry about changing configuration or debugging flags.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4774158543320836267-6367244798284067584?l=www.24hourapps.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/xhrXBJvKuUjVGs_Oh3VRRBmJYFU/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/xhrXBJvKuUjVGs_Oh3VRRBmJYFU/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/xhrXBJvKuUjVGs_Oh3VRRBmJYFU/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/xhrXBJvKuUjVGs_Oh3VRRBmJYFU/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=FkbHWxx4IdY:bnU9YnB0hUo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=FkbHWxx4IdY:bnU9YnB0hUo:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=FkbHWxx4IdY:bnU9YnB0hUo:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=FkbHWxx4IdY:bnU9YnB0hUo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=FkbHWxx4IdY:bnU9YnB0hUo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=FkbHWxx4IdY:bnU9YnB0hUo:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=FkbHWxx4IdY:bnU9YnB0hUo:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=FkbHWxx4IdY:bnU9YnB0hUo:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=FkbHWxx4IdY:bnU9YnB0hUo:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/24hourapps/~4/FkbHWxx4IdY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.24hourapps.com/feeds/6367244798284067584/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.24hourapps.com/2009/03/simple-php-email-testing-with-regular.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/6367244798284067584?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/6367244798284067584?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/24hourapps/~3/FkbHWxx4IdY/simple-php-email-testing-with-regular.html" title="Simple PHP email testing with regular expressions" /><author><name>Paul Chiu</name><uri>http://www.blogger.com/profile/16416350337923371068</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10755322441250465748" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.24hourapps.com/2009/03/simple-php-email-testing-with-regular.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkIMQX49eip7ImA9WxVVFEw.&quot;"><id>tag:blogger.com,1999:blog-4774158543320836267.post-1349676955014055160</id><published>2009-03-07T17:23:00.000+10:00</published><updated>2009-03-07T17:23:00.062+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-07T17:23:00.062+10:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="dns" /><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="tips" /><category scheme="http://www.blogger.com/atom/ns#" term="ubuntu" /><title>Linux Tips 12: Ubuntu DNS server setup and configuration</title><content type="html">Being on &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;Linode&lt;/span&gt;, the service offers its own &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;DNS&lt;/span&gt; server, and I know that many &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_2"&gt;web hosts&lt;/span&gt;, &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;VPS&lt;/span&gt;, and dedicated server companies also do the same. However there are real benefits in running your own &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;DNS&lt;/span&gt; server, with editing speed and ease of use being one of them. Although for full disclosure I have decided to use &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;Linode's&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;DNS&lt;/span&gt; service to reduce load on my own server. Nonetheless, this guide will go through the relatively simple process of setting up a &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;DNS&lt;/span&gt; server in &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;Ubuntu&lt;/span&gt; &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_9"&gt;Linux&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;The first thing one needs to do is to install &lt;a href="http://www.bind9.org/"&gt;Bind&lt;/a&gt;. Bind is a file based &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;DNS&lt;/span&gt; server that is pretty simple to use once you understand it; however there are multiple files to edit. When installed using &lt;span style="font-weight: bold;"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;sudo&lt;/span&gt; apt-get install bind9&lt;/span&gt; a default configuration file is created for you as well.&lt;br /&gt;&lt;br /&gt;The second step is to update the &lt;span style="font-style: italic;"&gt;/etc/bind/named.conf.local&lt;/span&gt; configuration file to add our zone. Our zone specifies what domains this &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;DNS&lt;/span&gt; server is responsible for. For this tutorial I will use &lt;span style="font-style: italic;"&gt;example.com&lt;/span&gt; as the sample domain. Therefore in &lt;span style="font-style: italic;"&gt;name.conf.local&lt;/span&gt; you will add both the zone definition as well as the reverse &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;DNS&lt;/span&gt; entry for your &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_14"&gt;IP&lt;/span&gt;. They should be written as:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class=""&gt;&lt;br /&gt;zone "example.com" in {&lt;br /&gt; type master;&lt;br /&gt; file "/etc/bind/zones/example.com.db";&lt;br /&gt; allow-transfer { any;};&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;zone "1.0.168.192.in-addr.arpa" {&lt;br /&gt; type master;&lt;br /&gt; file "/etc/bind/zones/1.0.168.192.db";&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Please remember to replace &lt;span style="font-style: italic;"&gt;example.com&lt;/span&gt; with your real domain name and &lt;span style="font-style: italic;"&gt;192.168.0.1&lt;/span&gt; (written in reverse) with your real &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_15"&gt;IP&lt;/span&gt; address.&lt;br /&gt;&lt;br /&gt;The third, and optional step, is to configure some default &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_16"&gt;DNS&lt;/span&gt; server options. The file used to do this is &lt;span style="font-style: italic;"&gt;/etc/bind/named.conf.options&lt;/span&gt; The main settings that ought to be of interest are: &lt;span style="font-style: italic;"&gt;forwarders&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;notify&lt;/span&gt;, and &lt;span style="font-style: italic;"&gt;directory&lt;/span&gt;. &lt;span style="font-style: italic;"&gt;Forwarders&lt;/span&gt; specify which &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_17"&gt;DNS&lt;/span&gt; server should be used when your &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_18"&gt;DNS&lt;/span&gt; server is queried for a domain that it is not responsible for. &lt;span style="font-style: italic;"&gt;Notify&lt;/span&gt; specifies whether slave &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_19"&gt;DNS&lt;/span&gt; servers should be notified of changes when they are made on this server. &lt;span style="font-style: italic;"&gt;Directory&lt;/span&gt; specifies where &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_20"&gt;DNS&lt;/span&gt; configuration files should be looked for if a full file parameter is not used in our zone entries in step two. Samples of three options are:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class=""&gt;&lt;br /&gt;forwarders { 208.67.222.222; 208.67.222.220; }&lt;br /&gt;notify { yes; }&lt;br /&gt;directory { "/&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_21"&gt;dns&lt;/span&gt;/zones"; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The fourth step in our &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_22"&gt;Ubuntu&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_23"&gt;DNS&lt;/span&gt; server setup is creating our zone file. I am assuming that you did not specify a custom zone directory like the options example above. Therefore you will want to create your zone files in the folder &lt;span style="font-style: italic;"&gt;/etc/bind/zones&lt;/span&gt; by just creating &lt;span style="font-style: italic;"&gt;example.com.db&lt;/span&gt; and filling it with entries such as:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class=""&gt;&lt;br /&gt;// &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_24"&gt;TTL&lt;/span&gt; = Time to live for records on slave (2 days)&lt;br /&gt;// 2009030700 = Serial for Bind to check whether an update has &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_25"&gt;occured&lt;/span&gt;&lt;br /&gt;// 6H = Time between refresh requests&lt;br /&gt;// 1H = Time between retry attempts&lt;br /&gt;// 1W = Expiry time for the record on slave&lt;br /&gt;// 1D = Amount of time an invalid response is stored on slave&lt;br /&gt;$&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_26"&gt;TTL&lt;/span&gt; 2D&lt;br /&gt;@ IN &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_27"&gt;SOA&lt;/span&gt; ns1.example.com. root.example.com. (&lt;br /&gt;   2009030700&lt;br /&gt;   6H&lt;br /&gt;   1H&lt;br /&gt;   1W&lt;br /&gt;   1D&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;// ns1.example.com. = Name server&lt;br /&gt;// mail.example.com. = Mail server&lt;br /&gt;// www.example.com. = HTTP server&lt;br /&gt;// *.example.com. = &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_28"&gt;Wildcard&lt;/span&gt; entry&lt;br /&gt;example.com. IN NS ns1.example.com.&lt;br /&gt;example.com. IN &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_29"&gt;MX&lt;/span&gt; 10 mail.example.com.&lt;br /&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_30"&gt;ns&lt;/span&gt;1  IN A 192.168.0.1&lt;br /&gt;www  IN A 192.168.0.1&lt;br /&gt;mail  IN A 192.168.0.1&lt;br /&gt;*  IN A 192.168.0.1&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The above zone definition file sets some basic servers and points them to the computer with the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_31"&gt;IP&lt;/span&gt; address &lt;span style="font-style: italic;"&gt;192.168.0.1&lt;/span&gt;. You can host each service on a different &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_32"&gt;IP&lt;/span&gt; if they are on different servers. You can also point to other name servers by using &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_33"&gt;CNAME&lt;/span&gt; instead of A records. Please note that all domain names end with a ".".&lt;br /&gt;&lt;br /&gt;While a reverse &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_34"&gt;DNS&lt;/span&gt; zone file is optional, for things like mail servers if a reverse entry is not available it can be flagged as a possible spam server. So it is good practice to do it. For our example zone file the reverse would be in the file &lt;span style="font-style: italic;"&gt;1.0.168.192.db&lt;/span&gt; and look like:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class=""&gt;&lt;br /&gt;// &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_35"&gt;TTL&lt;/span&gt; = Time to live for records on slave (2 days)&lt;br /&gt;// 2009030700 = Serial for Bind to check whether an update has &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_36"&gt;occured&lt;/span&gt;&lt;br /&gt;// 6H = Time between refresh requests&lt;br /&gt;// 1H = Time between retry attempts&lt;br /&gt;// 1W = Expiry time for the record on slave&lt;br /&gt;// 1D = Amount of time an invalid response is stored on slave&lt;br /&gt;$&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_37"&gt;TTL&lt;/span&gt; 2D&lt;br /&gt;@ IN &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_38"&gt;SOA&lt;/span&gt; ns1.example.com. root.example.com. (&lt;br /&gt;   2009030700&lt;br /&gt;   6H&lt;br /&gt;   1H&lt;br /&gt;   1W&lt;br /&gt;   1D&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;   IN NS ns1.example.com.&lt;br /&gt;1   IN &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_39"&gt;PTR&lt;/span&gt; example.com.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;After the files have been created restart bind through the command &lt;span style="font-weight: bold;"&gt;/etc/init.d/bind9 restart&lt;/span&gt; and using the command &lt;span style="font-weight: bold;"&gt;dig @192.168.0.1 www.example.com&lt;/span&gt; to use your own &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_40"&gt;DNS&lt;/span&gt; server to query the record &lt;span style="font-style: italic;"&gt;www.example.com&lt;/span&gt;. If an answer is given (should look like your entry for www in the &lt;span style="font-style: italic;"&gt;example.com.db&lt;/span&gt; file) then everything is set up correctly. You should now update your domain name registar's DNS records to point to your server.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4774158543320836267-1349676955014055160?l=www.24hourapps.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/zial388C252p5D-PxaJDNntZVr0/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/zial388C252p5D-PxaJDNntZVr0/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/zial388C252p5D-PxaJDNntZVr0/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/zial388C252p5D-PxaJDNntZVr0/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=S8YykVY67rk:q-YEe0_gHHM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=S8YykVY67rk:q-YEe0_gHHM:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=S8YykVY67rk:q-YEe0_gHHM:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=S8YykVY67rk:q-YEe0_gHHM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=S8YykVY67rk:q-YEe0_gHHM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=S8YykVY67rk:q-YEe0_gHHM:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=S8YykVY67rk:q-YEe0_gHHM:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=S8YykVY67rk:q-YEe0_gHHM:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=S8YykVY67rk:q-YEe0_gHHM:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/24hourapps/~4/S8YykVY67rk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.24hourapps.com/feeds/1349676955014055160/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.24hourapps.com/2009/03/linux-tips-12-ubuntu-dns-server-setup.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/1349676955014055160?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/1349676955014055160?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/24hourapps/~3/S8YykVY67rk/linux-tips-12-ubuntu-dns-server-setup.html" title="Linux Tips 12: Ubuntu DNS server setup and configuration" /><author><name>Paul Chiu</name><uri>http://www.blogger.com/profile/16416350337923371068</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10755322441250465748" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.24hourapps.com/2009/03/linux-tips-12-ubuntu-dns-server-setup.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkAMQXw7eSp7ImA9WxVVE08.&quot;"><id>tag:blogger.com,1999:blog-4774158543320836267.post-1067132592133676307</id><published>2009-03-06T17:33:00.003+10:00</published><updated>2009-03-06T17:33:00.201+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-06T17:33:00.201+10:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="phpmailer" /><category scheme="http://www.blogger.com/atom/ns#" term="mysql" /><category scheme="http://www.blogger.com/atom/ns#" term="backup" /><category scheme="http://www.blogger.com/atom/ns#" term="gmail" /><category scheme="http://www.blogger.com/atom/ns#" term="php" /><title>Backup MySQL database to Gmail using PHPMailer</title><content type="html">Sometimes client database data is so small that it is unnecessary to sign up to a dedicated 3rd party backup provider. In such cases &lt;a href="http://www.gmail.com"&gt;Gmail &lt;/a&gt;becomes a rather useful tool for sending and storing backups as Gmail maintains a copy of all sent emails. This functionality can be achieved quite easily with &lt;a href="http://www.php.net/"&gt;PHP&lt;/a&gt; and &lt;a href="http://phpmailer.codeworxtech.com/"&gt;PHPMailer&lt;/a&gt;. The script required to perform the MySQL database backup is below.&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="php"&gt;&lt;br /&gt;&amp;lt;?&lt;br /&gt;// Import mailer&lt;br /&gt;ini_set("memory_limit","128M");&lt;br /&gt;require "/cms/phpmailer/class.phpmailer.php";&lt;br /&gt;&lt;br /&gt;// Perform backup&lt;br /&gt;$filename = "/tmp/" . date('Ymd-Hi') . ".sql";&lt;br /&gt;exec("mysqldump -u root -p --all-databases &amp;gt; {$filename}");&lt;br /&gt;exec("gzip $filename");&lt;br /&gt;$filename .= ".gz";&lt;br /&gt;$filesize = number_format(filesize($filename) / 1048576, 0);&lt;br /&gt;&lt;br /&gt;// Send backup&lt;br /&gt;$date = date('d/m/Y');&lt;br /&gt;$m = new PHPMailer();&lt;br /&gt;$m-&amp;gt;IsSMTP(true);&lt;br /&gt;$m-&amp;gt;SMTPAuth = true;&lt;br /&gt;$m-&amp;gt;Username = 'username@gmail.com';&lt;br /&gt;$m-&amp;gt;Password = 'password';&lt;br /&gt;$m-&amp;gt;FromName = 'Database Backup Mailer';&lt;br /&gt;$m-&amp;gt;Host = 'ssl://smtp.gmail.com:465';&lt;br /&gt;$m-&amp;gt;AddAddress('secondarybackup@gmail.com');&lt;br /&gt;$m-&amp;gt;AddAttachment($filename);&lt;br /&gt;$m-&amp;gt;Subject = "Database Backup";&lt;br /&gt;$m-&amp;gt;MsgHTML(nl2br("The Database Backup for {$date} is attached, the filesize is: {$filesize}MB."));&lt;br /&gt;if ($m-&amp;gt;Send()) {&lt;br /&gt;   echo "Success";&lt;br /&gt;   unlink($filename);&lt;br /&gt;} else {&lt;br /&gt;   echo "Error, could not send: {$m-&amp;gt;ErrorInfo}";&lt;br /&gt;}&lt;br /&gt;?&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The script assumes that PHPMailer is installed in the same directory as the script in a folder called &lt;span style="font-style: italic;"&gt;phpmailer&lt;/span&gt; and that MySQL has a password-less root account; change the line with &lt;span style="font-style: italic;"&gt;mysqldump&lt;/span&gt; if your MySQL access details are different. Furthermore the script should be placed in folder where it can be accessed via HTTP so that you do not need to install the PHP CLI to make it work. The script can then be called using &lt;span style="font-weight: bold;"&gt;wget &lt;/span&gt;and added to &lt;span style="font-weight: bold;"&gt;cron &lt;/span&gt;to perform periodic backups.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4774158543320836267-1067132592133676307?l=www.24hourapps.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/ffwHi3ntnej-uzzilFUgoNQe3Yg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ffwHi3ntnej-uzzilFUgoNQe3Yg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/ffwHi3ntnej-uzzilFUgoNQe3Yg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ffwHi3ntnej-uzzilFUgoNQe3Yg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=F3Pgft2-QKI:e56OVV2K5RE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=F3Pgft2-QKI:e56OVV2K5RE:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=F3Pgft2-QKI:e56OVV2K5RE:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=F3Pgft2-QKI:e56OVV2K5RE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=F3Pgft2-QKI:e56OVV2K5RE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=F3Pgft2-QKI:e56OVV2K5RE:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=F3Pgft2-QKI:e56OVV2K5RE:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=F3Pgft2-QKI:e56OVV2K5RE:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=F3Pgft2-QKI:e56OVV2K5RE:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/24hourapps/~4/F3Pgft2-QKI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.24hourapps.com/feeds/1067132592133676307/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.24hourapps.com/2009/03/backup-mysql-database-to-gmail-using.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/1067132592133676307?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/1067132592133676307?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/24hourapps/~3/F3Pgft2-QKI/backup-mysql-database-to-gmail-using.html" title="Backup MySQL database to Gmail using PHPMailer" /><author><name>Paul Chiu</name><uri>http://www.blogger.com/profile/16416350337923371068</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10755322441250465748" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.24hourapps.com/2009/03/backup-mysql-database-to-gmail-using.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A08MQX07cCp7ImA9WxVVEk4.&quot;"><id>tag:blogger.com,1999:blog-4774158543320836267.post-4354247342278520694</id><published>2009-03-05T17:58:00.008+10:00</published><updated>2009-03-05T17:58:00.308+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-05T17:58:00.308+10:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="smtp" /><category scheme="http://www.blogger.com/atom/ns#" term="spam" /><category scheme="http://www.blogger.com/atom/ns#" term="gmail" /><category scheme="http://www.blogger.com/atom/ns#" term="linode" /><category scheme="http://www.blogger.com/atom/ns#" term="google" /><category scheme="http://www.blogger.com/atom/ns#" term="ubuntu" /><title>Linode Ubuntu Mail Server: Part 3 - Stop Gmail putting your emails into the spam folder</title><content type="html">In part 2 of my Ubuntu mail server set up guide on Linode I wrote about my experience with Gmail soft failing all emails sent from my server and my work around of just using Google Apps to send my mail. Such a solution works well if you are only dealing with end-user accounts however I have recently had to use the system SMTP server to send out emails for my &lt;a href="http://passbook.24hourapps.com/"&gt;online password keeper &lt;/a&gt;application, Passbook.&lt;br /&gt;&lt;br /&gt;The solution to getting your emails out of Gmail's spam filter and into users' folders is to set up a SPF TXT record. You can do this by using the &lt;a href="http://old.openspf.org/wizard.html"&gt;Open SPF wizard&lt;/a&gt; or just use the settings below in your Linode DNS Manager.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_29yMocwFCms/SalzZEgZtTI/AAAAAAAAAJw/V5Zk-SMCG9o/s1600-h/Picture+25.PNG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 41px;" src="http://1.bp.blogspot.com/_29yMocwFCms/SalzZEgZtTI/AAAAAAAAAJw/V5Zk-SMCG9o/s320/Picture+25.PNG" alt="" id="BLOGGER_PHOTO_ID_5307900510376408370" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;To create those settings simply add a new TXT record and leave the name empty and use &lt;span style="font-weight: bold;"&gt;"v=spf1 a mx ~all&lt;/span&gt;" as the value. What that TXT record means is that it is a SPF record saying that for your domain all servers pointed to by an &lt;span style="font-style: italic;"&gt;A&lt;/span&gt; or &lt;span style="font-style: italic;"&gt;MX&lt;/span&gt; record can send emails on behalf of your server. The &lt;span style="font-weight: bold;"&gt;~all&lt;/span&gt; means that any other server that sends email on behalf of your domain may or may not have permission to do so. To disallow any other hosts from sending email with an @yourdomain.com address use &lt;span style="font-weight: bold;"&gt;-all&lt;/span&gt; and to allow use &lt;span style="font-weight: bold;"&gt;?all&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;After you make these changes you can query whether they have worked using &lt;span style="font-weight: bold;"&gt;dig @ns1.linode.com TXT yourdomain.com&lt;/span&gt; from a *nix command line. The answer section should show the TXT record. You will need to wait for this data to propagate (I waited about 3 hours) before testing by sending a brand new email to your Gmail account. The email needs to have a new subject and message so that Gmail does not flag it as being the same as a previously marked spam message.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4774158543320836267-4354247342278520694?l=www.24hourapps.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/KdBhAmisSzzbnQao3tX0PfzZbug/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/KdBhAmisSzzbnQao3tX0PfzZbug/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/KdBhAmisSzzbnQao3tX0PfzZbug/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/KdBhAmisSzzbnQao3tX0PfzZbug/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=6n4swoIFVcw:x433lo3Qw64:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=6n4swoIFVcw:x433lo3Qw64:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=6n4swoIFVcw:x433lo3Qw64:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=6n4swoIFVcw:x433lo3Qw64:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=6n4swoIFVcw:x433lo3Qw64:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=6n4swoIFVcw:x433lo3Qw64:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=6n4swoIFVcw:x433lo3Qw64:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=6n4swoIFVcw:x433lo3Qw64:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=6n4swoIFVcw:x433lo3Qw64:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/24hourapps/~4/6n4swoIFVcw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.24hourapps.com/feeds/4354247342278520694/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.24hourapps.com/2009/03/linode-ubuntu-mail-server-part-3-stop.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/4354247342278520694?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/4354247342278520694?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/24hourapps/~3/6n4swoIFVcw/linode-ubuntu-mail-server-part-3-stop.html" title="Linode Ubuntu Mail Server: Part 3 - Stop Gmail putting your emails into the spam folder" /><author><name>Paul Chiu</name><uri>http://www.blogger.com/profile/16416350337923371068</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10755322441250465748" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_29yMocwFCms/SalzZEgZtTI/AAAAAAAAAJw/V5Zk-SMCG9o/s72-c/Picture+25.PNG" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.24hourapps.com/2009/03/linode-ubuntu-mail-server-part-3-stop.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0cMQXk8fip7ImA9WxVVEUg.&quot;"><id>tag:blogger.com,1999:blog-4774158543320836267.post-5307427687902050721</id><published>2009-03-04T17:18:00.001+10:00</published><updated>2009-03-04T17:18:00.776+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-04T17:18:00.776+10:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="tips" /><category scheme="http://www.blogger.com/atom/ns#" term="ubuntu" /><title>Linux Tips 11: Ubuntu user management</title><content type="html">One thing that I find myself doing a lot on my Linode server is adding and managing users. Sometimes I need to create accounts for clients, friends, or family. So some accounts are temporary and some are persistent. Nonetheless, they all require the use of the following few simply Ubuntu user management commands.&lt;br /&gt;&lt;br /&gt;Ubuntu has four basic user management commands they are: &lt;span style="font-style: italic;"&gt;adduser&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;deluser&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;passwd&lt;/span&gt;, and &lt;span style="font-style: italic;"&gt;usermod&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Adduser&lt;/span&gt; is a script that presents common functions of useradd in a user friendly manner, which basically allows you to add a user to the system. To use it type (as root): &lt;span style="font-weight: bold;"&gt;adduser [newuser]&lt;/span&gt; and you will be prompted with basic user information such as name, password, etc. The user home directory will be created for you as well.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Deluser&lt;/span&gt; is the equivalent script to adduser. If called by it self it will simply delete a user's account, thus revoking their system access. If you want to completely remove a user you need to call: &lt;span style="font-weight: bold;"&gt;deluser --removehome --remove-all-files [new user]&lt;/span&gt; which will remove a user's home directory as well as all files that belongs to that user.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Passwd&lt;/span&gt; gives you much greater control over a user's password in terms of policy enforcement. You can lock an account &lt;span style="font-weight: bold;"&gt;passwd -l [newuser]&lt;/span&gt; and unlock it using &lt;span style="font-weight: bold;"&gt;passwd -u [newuser]&lt;/span&gt; You can also force the user to change their password immediately using &lt;span style="font-weight: bold;"&gt;passwd -e [newuser]&lt;/span&gt; or after a number of days &lt;span style="font-weight: bold;"&gt;passwd -c 7 -x 30 [newuser]&lt;/span&gt; (the user must change his/her password every 30 days, with a warning shown 7 days before).&lt;br /&gt;&lt;br /&gt;Finally you can modify existing users' settings by using &lt;span style="font-style: italic;"&gt;usermod&lt;/span&gt;. You can add them to new group &lt;span style="font-weight: bold;"&gt;usermod -a [newgroup] [newuser]&lt;/span&gt; or change their home directory &lt;span style="font-weight: bold;"&gt;usermod -d /home/newhome [newuser]&lt;/span&gt; or change their login name &lt;span style="font-weight: bold;"&gt;usermod -l [newnewuser] [newuser]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I have only gone through the most common use cases for myself with these Ubuntu user management functions, you can find more information as well as a list of all options from their man (manual) pages.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4774158543320836267-5307427687902050721?l=www.24hourapps.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/NSjTqBt9KG8n9E7H7oz8Za1n2lM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/NSjTqBt9KG8n9E7H7oz8Za1n2lM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/NSjTqBt9KG8n9E7H7oz8Za1n2lM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/NSjTqBt9KG8n9E7H7oz8Za1n2lM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=Oe65EfcjDcg:HRG0nz5Enwk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=Oe65EfcjDcg:HRG0nz5Enwk:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=Oe65EfcjDcg:HRG0nz5Enwk:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=Oe65EfcjDcg:HRG0nz5Enwk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=Oe65EfcjDcg:HRG0nz5Enwk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=Oe65EfcjDcg:HRG0nz5Enwk:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=Oe65EfcjDcg:HRG0nz5Enwk:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=Oe65EfcjDcg:HRG0nz5Enwk:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=Oe65EfcjDcg:HRG0nz5Enwk:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/24hourapps/~4/Oe65EfcjDcg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.24hourapps.com/feeds/5307427687902050721/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.24hourapps.com/2009/03/linux-tips-11-ubuntu-user-management.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/5307427687902050721?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/5307427687902050721?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/24hourapps/~3/Oe65EfcjDcg/linux-tips-11-ubuntu-user-management.html" title="Linux Tips 11: Ubuntu user management" /><author><name>Paul Chiu</name><uri>http://www.blogger.com/profile/16416350337923371068</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10755322441250465748" /></author><thr:total>2</thr:total><feedburner:origLink>http://www.24hourapps.com/2009/03/linux-tips-11-ubuntu-user-management.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkIEQXoyeip7ImA9WxVVEEs.&quot;"><id>tag:blogger.com,1999:blog-4774158543320836267.post-4661356735215199450</id><published>2009-03-03T17:15:00.001+10:00</published><updated>2009-03-03T17:15:00.492+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-03T17:15:00.492+10:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="dates" /><category scheme="http://www.blogger.com/atom/ns#" term="tips" /><title>Javascript GMT/UTC timezone offset detection</title><content type="html">Continuing from my previous date related PHP tip here is a very quick tip about how to detect the GMT/UTC timezone offset in Javascript. It really only takes two lines of code.&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="js"&gt;&lt;br /&gt;var today = new Date();&lt;br /&gt;var offset = -(today.getTimezoneOffset()/60);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The above code will place the offset in hours in the &lt;em&gt;offset&lt;/em&gt; variable in whatever context you made those two calls.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4774158543320836267-4661356735215199450?l=www.24hourapps.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/tVSK7z30vAWZNN0Y0SsfFEIT_y4/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/tVSK7z30vAWZNN0Y0SsfFEIT_y4/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/tVSK7z30vAWZNN0Y0SsfFEIT_y4/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/tVSK7z30vAWZNN0Y0SsfFEIT_y4/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=L9nuAPSVf-4:HV1dlQwsQNI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=L9nuAPSVf-4:HV1dlQwsQNI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=L9nuAPSVf-4:HV1dlQwsQNI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=L9nuAPSVf-4:HV1dlQwsQNI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=L9nuAPSVf-4:HV1dlQwsQNI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=L9nuAPSVf-4:HV1dlQwsQNI:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=L9nuAPSVf-4:HV1dlQwsQNI:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=L9nuAPSVf-4:HV1dlQwsQNI:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=L9nuAPSVf-4:HV1dlQwsQNI:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/24hourapps/~4/L9nuAPSVf-4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.24hourapps.com/feeds/4661356735215199450/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.24hourapps.com/2009/03/javascript-gmtutc-timezone-offset.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/4661356735215199450?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/4661356735215199450?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/24hourapps/~3/L9nuAPSVf-4/javascript-gmtutc-timezone-offset.html" title="Javascript GMT/UTC timezone offset detection" /><author><name>Paul Chiu</name><uri>http://www.blogger.com/profile/16416350337923371068</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10755322441250465748" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.24hourapps.com/2009/03/javascript-gmtutc-timezone-offset.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkADRHg8cCp7ImA9WxVVFUg.&quot;"><id>tag:blogger.com,1999:blog-4774158543320836267.post-4634225769490072690</id><published>2009-03-02T17:40:00.004+10:00</published><updated>2009-03-09T09:26:15.678+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-09T09:26:15.678+10:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="dates" /><category scheme="http://www.blogger.com/atom/ns#" term="tips" /><category scheme="http://www.blogger.com/atom/ns#" term="php" /><title>PHP dates between two dates tutorial</title><content type="html">For any calendar or time management application it is useful to be able to generate dates between two given dates. Doing it is actually quite easy. Just see the code below for the function.&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="php"&gt;&lt;br /&gt;function getDaysInBetween($start, $end) {&lt;br /&gt; // Vars&lt;br /&gt; $day = 86400; // Day in seconds&lt;br /&gt; $format = 'Y-m-d'; // Output format (see PHP date funciton)&lt;br /&gt; $sTime = strtotime($start); // Start as time&lt;br /&gt; $eTime = strtotime($end); // End as time&lt;br /&gt; $numDays = round(($eTime - $sTime) / $day) + 1;&lt;br /&gt; $days = array();&lt;br /&gt;&lt;br /&gt; // Get days&lt;br /&gt; for ($d = 0; $d &lt; $numDays; $d++) {&lt;br /&gt;  $days[] = date($format, ($sTime + ($d * $day)));&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; // Return days&lt;br /&gt; return $days;&lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The above code accepts a start and end date that is understood by &lt;a href="http://au2.php.net/strtotime"&gt;strtotime&lt;/a&gt;. The function returns an array of days, the format of which is specified in the $format variable which accepts all formats used by &lt;a href="http://au.php.net/manual/en/function.date.php"&gt;date&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;To use the function simply call it like &lt;strong&gt;getDaysInBetween('2009-03-01', '2009-03-06');&lt;/strong&gt; Please note that the results are inclusive of the original start and end dates.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4774158543320836267-4634225769490072690?l=www.24hourapps.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/kNMbtbNspimh5mRQyJO-l7BERcM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/kNMbtbNspimh5mRQyJO-l7BERcM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/kNMbtbNspimh5mRQyJO-l7BERcM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/kNMbtbNspimh5mRQyJO-l7BERcM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=OQKIXM7rPhk:dFQ0_wwi2Js:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=OQKIXM7rPhk:dFQ0_wwi2Js:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=OQKIXM7rPhk:dFQ0_wwi2Js:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=OQKIXM7rPhk:dFQ0_wwi2Js:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=OQKIXM7rPhk:dFQ0_wwi2Js:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=OQKIXM7rPhk:dFQ0_wwi2Js:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=OQKIXM7rPhk:dFQ0_wwi2Js:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=OQKIXM7rPhk:dFQ0_wwi2Js:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=OQKIXM7rPhk:dFQ0_wwi2Js:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/24hourapps/~4/OQKIXM7rPhk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.24hourapps.com/feeds/4634225769490072690/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.24hourapps.com/2009/03/php-dates-between-two-dates-tutorial.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/4634225769490072690?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/4634225769490072690?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/24hourapps/~3/OQKIXM7rPhk/php-dates-between-two-dates-tutorial.html" title="PHP dates between two dates tutorial" /><author><name>Paul Chiu</name><uri>http://www.blogger.com/profile/16416350337923371068</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10755322441250465748" /></author><thr:total>1</thr:total><feedburner:origLink>http://www.24hourapps.com/2009/03/php-dates-between-two-dates-tutorial.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEMMQXo9eSp7ImA9WxVWGEQ.&quot;"><id>tag:blogger.com,1999:blog-4774158543320836267.post-2310706030640187393</id><published>2009-03-01T17:28:00.000+10:00</published><updated>2009-03-01T17:28:00.461+10:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-01T17:28:00.461+10:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="tips" /><title>Linux Tips 10: Rename multiple files</title><content type="html">Renaming multiple files in Linux is surprisingly difficult given the simplistic power provided by many other system commands. Unlike DOS, which provided a &lt;span style="font-style: italic;"&gt;rename&lt;/span&gt; command that allowed wild cards, Linux's &lt;span style="font-style: italic;"&gt;rename&lt;/span&gt;/&lt;span style="font-style: italic;"&gt;mv&lt;/span&gt; command is less versatile. Therefore to rename files one needs to write a loop. Luckily bash helps a lot here.&lt;br /&gt;&lt;br /&gt;Lets say we have in our directory a number of &lt;span style="font-style: italic;"&gt;.txt&lt;/span&gt; files that we need to rename to &lt;span style="font-style: italic;"&gt;.nfo&lt;/span&gt;. To do this we would need to use the command:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;for f in *.txt; do mv "${f}" "${f/.txt/.nfo}"; done;&lt;/code&gt;&lt;br /&gt;It is quite a long command, but it basically executes a loop and tells it to take each &lt;span style="font-style: italic;"&gt;f&lt;/span&gt; file name in &lt;span style="font-style: italic;"&gt;*.txt&lt;/span&gt; and give it a name where a match for &lt;span style="font-style: italic;"&gt;.txt&lt;/span&gt; is replaced with &lt;span style="font-style: italic;"&gt;.nfo&lt;/span&gt;. While I have not tried more complex patterns it should be possible to use any regular expression. Please note that the above code only does one replacement. If multiple is needed then two slashes are required after &lt;span style="font-style: italic;"&gt;f&lt;/span&gt;, ie. &lt;span style="font-weight: bold;"&gt;{$f//.txt/.nfo}&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4774158543320836267-2310706030640187393?l=www.24hourapps.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/-eQRqNqxsG6nkxMeAuOrQKZsTho/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/-eQRqNqxsG6nkxMeAuOrQKZsTho/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/-eQRqNqxsG6nkxMeAuOrQKZsTho/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/-eQRqNqxsG6nkxMeAuOrQKZsTho/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=V84VWIfo4Cc:o4Q37LZthGE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=V84VWIfo4Cc:o4Q37LZthGE:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=V84VWIfo4Cc:o4Q37LZthGE:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=V84VWIfo4Cc:o4Q37LZthGE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=V84VWIfo4Cc:o4Q37LZthGE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=V84VWIfo4Cc:o4Q37LZthGE:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?i=V84VWIfo4Cc:o4Q37LZthGE:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=V84VWIfo4Cc:o4Q37LZthGE:TzevzKxY174"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=TzevzKxY174" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/24hourapps?a=V84VWIfo4Cc:o4Q37LZthGE:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/24hourapps?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/24hourapps/~4/V84VWIfo4Cc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.24hourapps.com/feeds/2310706030640187393/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.24hourapps.com/2009/03/linux-tips-10-rename-multiple-files.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/2310706030640187393?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4774158543320836267/posts/default/2310706030640187393?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/24hourapps/~3/V84VWIfo4Cc/linux-tips-10-rename-multiple-files.html" title="Linux Tips 10: Rename multiple files" /><author><name>Paul Chiu</name><uri>http://www.blogger.com/profile/16416350337923371068</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10755322441250465748" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.24hourapps.com/2009/03/linux-tips-10-rename-multiple-files.html</feedburner:origLink></entry></feed>
