<?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:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;A0AEQ3oyeCp7ImA9WhBbEEQ.&quot;"><id>tag:blogger.com,1999:blog-3347571992315805758</id><updated>2013-05-09T23:41:42.490+12:00</updated><category term="Tidy" /><category term="tools" /><category term="3C" /><category term="socks" /><category term="Suva" /><category term="SQLite" /><category term="functions" /><category term="open source" /><category term="date" /><category term="validation" /><category term="xampp" /><category term="DOM" /><category term="RSS" /><category term="css" /><category term="configuration" /><category term="window" /><category term="website metrics" /><category term="email" /><category term="mashup" /><category term="xhtml" /><category term="IE7" /><category term="RFC" /><category term="xmpp" /><category term="mysql" /><category term="webservices" /><category term="httpd" /><category term="Firefox2" /><category term="security" /><category term="Yahoo Maps" /><category term="Opera" /><category term="object" /><category term="OpenOffice" /><category term="XML" /><category term="extend" /><category term="streams" /><category term="wireshark" /><category term="sendmail" /><category term="twittier" /><category term="networking" /><category term="wordpress" /><category term="microformats" /><category term="XHR" /><category term="timezone" /><category term="Maps" /><category term="Firefox" /><category term="Firefox3" /><category term="escape" /><category term="lively" /><category term="persistence" /><category term="IE8" /><category term="trend" /><category term="XSS" /><category term="widget" /><category term="w3c" /><category term="prototype" /><category term="web design" /><category term="google" /><category term="Google Maps" /><category term="mail" /><category term="proxy" /><category term="Microsoft" /><category term="XSRF" /><category term="loop" /><category term="smtp" /><category term="native types" /><category term="javascript" /><category term="client" /><category term="joomla" /><category term="XMLHttpRequest" /><category term="AJAX" /><category term="web development" /><category term="tunneling" /><category term="http" /><category term="jsapi" /><category term="browsers" /><category term="string" /><category term="Fiji" /><category term="developers" /><category term="ATOM" /><category term="3D world" /><category term="shell" /><category term="blogpulse" /><category term="telnet" /><category term="remoting" /><category term="CSRF" /><category term="JSON" /><category term="OpenService" /><category term="secondlife" /><category term="database" /><category term="linux" /><category term="apache" /><category term="mootools" /><category term="embedded" /><category term="geocoding" /><category term="IE6" /><category term="REST" /><category term="sockets" /><category term="website analytics" /><category term="chain" /><category term="ssh" /><category term="blog" /><category term="API" /><category term="libraries" /><category term="openssh" /><category term="PHP" /><category term="tcp" /><category term="jquery" /><category term="Sun" /><category term="MTA" /><category term="twitter" /><category term="drupal" /><category term="server" /><category term="standards" /><title>On Web Development</title><subtitle type="html">My daily take on web development. PHP, MySQL, JavaScript , AJAX, xHTML, HTML5, CSS and maybe some Flash ;).</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://onwebdevelopment.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://onwebdevelopment.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Gabe LG</name><uri>https://plus.google.com/107192546834216117000</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-St_WHaLi-Yg/AAAAAAAAAAI/AAAAAAAAB6M/EQ_v8i-FgXg/s512-c/photo.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>51</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/blogspot/hXgxP" /><feedburner:info uri="blogspot/hxgxp" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;A0EESXc6eSp7ImA9WhRVGUk.&quot;"><id>tag:blogger.com,1999:blog-3347571992315805758.post-6460633966991659910</id><published>2012-01-19T17:45:00.001+13:00</published><updated>2012-01-19T18:06:48.911+13:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-19T18:06:48.911+13:00</app:edited><title>Get Wikipedia blackout back online via hosts file work around</title><content type="html">&lt;h3&gt;


&lt;/h3&gt;
Wikipedia is on blackout for 24 hours. The blackout code is delivered via JS from the domain meta.wikimedia.org. &lt;br /&gt;
&lt;br /&gt;
To get wikipedia back online during their blackout append "127.0.0.1 meta.wikimedia.org" to your hosts file.&lt;br /&gt;
&lt;br /&gt;
The line:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;127.0.0.1 meta.wikimedia.org&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
will make the domain&amp;nbsp; meta.wikimedia.org resolve to your loopback interface for IPv4 (your local machine). It will thus NOT render the HTTP response delivering the JavaScript code that will blackout the wikipedia page. Thus you can use wikipedia as normal.&lt;br /&gt;
&lt;br /&gt;
If you're not familiar with what a hosts file is, here is a short overview. &lt;a href="http://onwebdevelopment.blogspot.com/2008/06/blocking-advertisements-with-hosts-file.html"&gt;http://onwebdevelopment.blogspot.com/2008/06/blocking-advertisements-with-hosts-file.html&lt;/a&gt;&lt;br /&gt;
Or look here on how to edit your hosts file: &lt;a href="http://www.windowsreference.com/windows-7/edit-hosts-file-in-windows-7-windows-vista/"&gt;http://www.windowsreference.com/windows-7/edit-hosts-file-in-windows-7-windows-vista/&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
These are for windows, however if you're on Linux then it's a lot simpler - like most things Linux.&lt;br /&gt;
 &lt;br /&gt;
&lt;b&gt;echo "127.0.0.1 meta.wikimedia.org" &amp;gt;&amp;gt; /etc/hosts&lt;/b&gt;&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
You need to be root to do this, so either do "sudo" or "su root" or "sudo su" etc. &lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Other workarounds to wikipedia blackout&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
If you have foxyproxy you can also use that to block meta.wikimedia.org specifically by specifying that it proxy to some blackhole.&lt;br /&gt;
&lt;br /&gt;
If you use a proxy configuration script, that would also work. Modify your script to proxy meta.wikimedia.org to your favorite blackhole.With a proxy script you can match just the JavaScript file URL, so it is more specific.&lt;br /&gt;
&lt;br /&gt;
There is a number of other ways to block &lt;b&gt;meta.wikimedia.org &lt;/b&gt;and they should all deliver the same results.&amp;nbsp; &lt;br /&gt;
&lt;br /&gt;
If you're interested in the JS file delivering the blackout code then with firebug or chrome, inspect the source and then go to "Network" tab. You should see two HTTP requests for &lt;b&gt;meta.wikimedia.org. &lt;/b&gt;The second one is delivering the JavaScript file.You can also use Wireshark to inspect the network traffic and create a Wireshark filter for &lt;b&gt;meta.wikimedia.org.&amp;nbsp;&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hXgxP/~4/X3j78TcuNUA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://onwebdevelopment.blogspot.com/feeds/6460633966991659910/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3347571992315805758&amp;postID=6460633966991659910" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/6460633966991659910?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/6460633966991659910?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hXgxP/~3/X3j78TcuNUA/get-wikipedia-blackout-back-online-via.html" title="Get Wikipedia blackout back online via hosts file work around" /><author><name>Gabe LG</name><uri>https://plus.google.com/107192546834216117000</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-St_WHaLi-Yg/AAAAAAAAAAI/AAAAAAAAB6M/EQ_v8i-FgXg/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://onwebdevelopment.blogspot.com/2012/01/get-wikipedia-blackout-back-online-via.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkcNQ3k7cCp7ImA9WhRVFE8.&quot;"><id>tag:blogger.com,1999:blog-3347571992315805758.post-4848263469809014406</id><published>2012-01-13T17:14:00.001+13:00</published><updated>2012-01-13T17:14:52.708+13:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-13T17:14:52.708+13:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="server" /><category scheme="http://www.blogger.com/atom/ns#" term="configuration" /><category scheme="http://www.blogger.com/atom/ns#" term="apache" /><category scheme="http://www.blogger.com/atom/ns#" term="httpd" /><title>Where is httpd.conf - The Apache Configuration File</title><content type="html">&lt;h3&gt;Are you tired of searching for the Apache Configuration File, httpd.conf?&lt;/h3&gt;&lt;p&gt;To find the location of httpd.conf run the following shell command:&lt;br /&gt;
 &lt;/p&gt;&lt;pre&gt;httpd -V
&lt;/pre&gt;&lt;p&gt;Note the &lt;b&gt;-V&lt;/b&gt; option is capitalized. Which will give a response similar to:&lt;/p&gt;&lt;pre&gt;Server version: Apache/2.2.21 (Unix)
Server built:   Nov 10 2011 19:22:21
Cpanel::Easy::Apache v3.7.1 rev9999
Server's Module Magic Number: 20051115:30
Server loaded:  APR 1.4.5, APR-Util 1.3.12
Compiled using: APR 1.4.5, APR-Util 1.3.12
Architecture:   32-bit
Server MPM:     Event
  threaded:     yes (fixed thread count)
    forked:     yes (variable process count)
Server compiled with....
 -D APACHE_MPM_DIR="server/mpm/experimental/event"
 -D APR_HAS_SENDFILE
 -D APR_HAS_MMAP
 -D APR_HAVE_IPV6 (IPv4-mapped addresses enabled)
 -D APR_USE_SYSVSEM_SERIALIZE
 -D APR_USE_PTHREAD_SERIALIZE
 -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT
 -D APR_HAS_OTHER_CHILD
 -D AP_HAVE_RELIABLE_PIPED_LOGS
 -D DYNAMIC_MODULE_LIMIT=128
 -D HTTPD_ROOT="/usr/local/apache"
 -D SUEXEC_BIN="/usr/local/apache/bin/suexec"
 -D DEFAULT_SCOREBOARD="logs/apache_runtime_status"
 -D DEFAULT_ERRORLOG="logs/error_log"
 -D AP_TYPES_CONFIG_FILE="conf/mime.types"
 -D SERVER_CONFIG_FILE="conf/httpd.conf"
&lt;/pre&gt;&lt;p&gt; The path to httpd.conf can be seen as the &lt;b&gt;HTTPD_ROOT/SERVER_CONFIG_FILE&lt;/b&gt; which is &lt;b&gt;/usr/local/apache/conf/httpd.conf&lt;/b&gt; in this example.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;I've always been using find / -name 'httpd.conf" but this is much faster. &lt;br /&gt;
&lt;/p&gt;&lt;p&gt;Once you've found httpd.conf you probably want to find the other files being included in the configuration. To do this you can search the httpd.conf file for the "Include" directives.&lt;br /&gt;
&lt;/p&gt;&lt;pre&gt;grep -E "^Include" /usr/local/apache/conf/httpd.conf 
&lt;/pre&gt;&lt;p&gt;The -E option gives extended regular expression so you can use "^Include" where the "^" character matches the beginning of the line. So only lines beginning with "Include" are returned. &lt;br /&gt;
&lt;/p&gt;&lt;p&gt;You could follow each included file and recursively follow every included file to get all the included files but this is a good start. Something I also find myself needing is to look at all the configuration files in the apache configuration directory. ie: &lt;br /&gt;
&lt;br /&gt;
&lt;/p&gt;&lt;pre&gt;find /usr/local/apache/conf -name '*.conf'
&lt;/pre&gt;&lt;p&gt;That returns every file ending in .conf. &lt;/p&gt;&lt;p&gt;Hope that helps.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hXgxP/~4/dKSjbUF6p3E" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://onwebdevelopment.blogspot.com/feeds/4848263469809014406/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3347571992315805758&amp;postID=4848263469809014406" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/4848263469809014406?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/4848263469809014406?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hXgxP/~3/dKSjbUF6p3E/where-is-httpdconf-apache-configuration.html" title="Where is httpd.conf - The Apache Configuration File" /><author><name>Gabe LG</name><uri>https://plus.google.com/107192546834216117000</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-St_WHaLi-Yg/AAAAAAAAAAI/AAAAAAAAB6M/EQ_v8i-FgXg/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://onwebdevelopment.blogspot.com/2012/01/where-is-httpdconf-apache-configuration.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D08ESX86fyp7ImA9WhRQFU0.&quot;"><id>tag:blogger.com,1999:blog-3347571992315805758.post-7572054939906339807</id><published>2011-12-10T10:35:00.001+13:00</published><updated>2011-12-10T21:30:08.117+13:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-10T21:30:08.117+13:00</app:edited><title>Chrome Socks Proxy using SSH Tunnel</title><content type="html">If you’re familiar with using a SOCKS proxy while browsing the internet you may have found out that Chrome will not work with a SOCKS5 proxy such as created when you create a SSH tunnel. &lt;br /&gt;
&lt;br /&gt;
This is because chrome assumes the SOCKS proxy is a SOCKS4 proxy when it is SOCKS5.&lt;br /&gt;
&lt;br /&gt;
A workaround is to have chrome read the proxy configuration from a script. &lt;br /&gt;
The configuration script is a javascript file with a function called FindProxyForUrl() that will be called for every HTTP URL to proxy. &lt;br /&gt;
Here is an example:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&lt;br /&gt;
/**&lt;br /&gt;
* .pac files are for automated proxy configuration&lt;br /&gt;
* This is a fix for chrome to use SOCKS5 as it assumes SOCKS4&lt;br /&gt;
*/&lt;br /&gt;
function FindProxyForURL(url, host)&lt;br /&gt;
{&lt;br /&gt;
// no proxy for localhost&lt;br /&gt;
if (host.match('localhost') return false;&lt;br /&gt;
// proxy for other hosts&lt;br /&gt;
return "SOCKS5 localhost:8111";&lt;br /&gt;
}&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
Make sure your port number is the port that the socks proxy is bound to.&lt;br /&gt;
&lt;br /&gt;
Save this script as ssh-tunnel.pac or similar and in chrome go to:&lt;br /&gt;
Options -&gt; Under the Hood -&gt; Network -&gt; Change Proxy Settings&lt;br /&gt;
&lt;br /&gt;
Chrome uses the same network settings as IE. So you will see the system window open and choose: &lt;br /&gt;
LAN settings -&gt; Use Automatic Configuration Script&lt;br /&gt;
&lt;br /&gt;
Enter the path to the ssh-tunnel.pac file you created. &lt;br /&gt;
Now reload the webpage in Chrome. &lt;br /&gt;
&lt;br /&gt;
Creating an SSH tunnel.&lt;br /&gt;
If you’re not familiar with creating an SSH Socks5 proxy visit: &lt;br /&gt;
&lt;a href="http://onwebdevelopment.blogspot.com/2008/02/secure-http-over-ssh-proxy-with-putty.html"&gt;Windows SSH as Proxy&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://onwebdevelopment.blogspot.com/2008/07/secure-http-over-ssh-proxy-with-linux.html"&gt;Linux SSH as Proxy&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hXgxP/~4/NHUNBgzq-J0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://onwebdevelopment.blogspot.com/feeds/7572054939906339807/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3347571992315805758&amp;postID=7572054939906339807" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/7572054939906339807?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/7572054939906339807?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hXgxP/~3/NHUNBgzq-J0/chrome-socks-proxy-using-ssh-tunnel.html" title="Chrome Socks Proxy using SSH Tunnel" /><author><name>Gabe LG</name><uri>https://plus.google.com/107192546834216117000</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-St_WHaLi-Yg/AAAAAAAAAAI/AAAAAAAAB6M/EQ_v8i-FgXg/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://onwebdevelopment.blogspot.com/2011/12/chrome-socks-proxy-using-ssh-tunnel.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Dk8BRXcyfyp7ImA9WhRQEU0.&quot;"><id>tag:blogger.com,1999:blog-3347571992315805758.post-8421273901335470975</id><published>2011-12-06T05:40:00.001+13:00</published><updated>2011-12-06T06:07:34.997+13:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-06T06:07:34.997+13:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="http" /><category scheme="http://www.blogger.com/atom/ns#" term="telnet" /><category scheme="http://www.blogger.com/atom/ns#" term="tcp" /><category scheme="http://www.blogger.com/atom/ns#" term="PHP" /><category scheme="http://www.blogger.com/atom/ns#" term="sockets" /><category scheme="http://www.blogger.com/atom/ns#" term="xmpp" /><category scheme="http://www.blogger.com/atom/ns#" term="email" /><category scheme="http://www.blogger.com/atom/ns#" term="streams" /><category scheme="http://www.blogger.com/atom/ns#" term="shell" /><title>PHP Command Line Telnet Client</title><content type="html">A while ago I wrote a single line PHP Command line client.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;while (1) { &amp;nbsp;fputs(STDOUT, "\n\-PHP$ "); eval(trim(fgets(STDIN))); }&lt;/pre&gt;&lt;br /&gt;
Recently I needed to test an XMPP server and found out that Windows7 does not have telnet enabled by default. Usually I'd just use putty as it supports telnet also but wondered if I could just do this from the command line via PHP. Well here it is, a PHP command line telnet client. &lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;echo "PHP Telnet Client. (c) 2011 Fiji Web Design, http://www.fijiwebdesign.com.\n";

$opts = getopt("h:p:") or die("Invalid options. Please supply -h [host] -p [port]");

$host = $opts['h'];
$port = $opts['p'];

$fp = fsockopen($host, $port) or die("Could not connect to host ($host) on port ($port)");
echo "Connected to server...\n";

stream_set_blocking($fp, 0);

while (1) {

  $input = (fgets(STDIN));
  fwrite($fp, $input) or die('Could not write to server');
  sleep(1); // let server respond

  $out = '';
  while($buf = fread($fp, 2028)) {
    $out .= $buf;
  }

  if ($out != '') echo $out;

}

&lt;/pre&gt;&lt;br /&gt;
Now that isn't one line like the PHP command line client. Also, if you are on windows and a version of PHP lower then 5.3, you will not have the getopt() function. To solve this here is a substitute for getopt(). &lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;if (!function_exists('getopt')) {

  function getopt($opts) {
      $argv = $_SERVER["argv"];
      $result = false;
      $opts_array = explode(':', $opts);
      foreach($opts_array as $opt) {
          $key = array_search('-' . $opt, $argv);
          if($key &amp;&amp; !in_array($argv[$key+1], $opts_array)) {
              $result[$opt] = trim($argv[$key+1]);
          } elseif($key) {
              $result[$opt] = '';
          }
      }
      return $result;
  }

}
&lt;/pre&gt;&lt;br /&gt;
Save the PHP code to a file, I call it telnet.php. Then open the shell and navigate to the directory which has telnet.php and type in:&lt;br /&gt;
&lt;br /&gt;
php telnet.php -h [hostname] -p [port]&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
php telnet.php -h google.com -p 80&lt;br /&gt;
&lt;br /&gt;
This will open a connection to google.com on the http port. Then you can type in your HTTP headers: &lt;br /&gt;
&lt;br /&gt;
GET / HTTP/1.1&lt;br /&gt;
HOST: google.com&lt;br /&gt;
&lt;br /&gt;
Then press enter twice, because HTTP requires that you send a newline to terminate the HTTP headers. Google.com should respond with the headers and HTML of the Google website. &lt;br /&gt;
&lt;br /&gt;
You can telnet into any listening TCP port so for instance you can test XMPP servers. &lt;br /&gt;
&lt;br /&gt;
php telnet.php -h talk.google.com -p 5222&lt;br /&gt;
&lt;br /&gt;
Then send your XMPP stanzas. &lt;br /&gt;
&lt;br /&gt;
Or even telnet into an email server and send or retrieve emails. &lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Notes&lt;/h3&gt;&lt;br /&gt;
The socket connection to the server your are telneting to is currently non-blocking while the read from STDIN is currently blocking. This causes the response from the server to not show until you hit enter (send \n) a few times. It would be better design to have both streams non-blocking and do a socket_select() call but the current works for now and does not require socket_select() support which I believe requires php built with &lt;a href="http://php.net/manual/en/book.sockets.php"&gt;sockets support&lt;/a&gt;. The current implementation should work without that support but does use up a lot of CPU with the while(1) loop.&lt;img src="http://feeds.feedburner.com/~r/blogspot/hXgxP/~4/nzOV4TE7jHo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://onwebdevelopment.blogspot.com/feeds/8421273901335470975/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3347571992315805758&amp;postID=8421273901335470975" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/8421273901335470975?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/8421273901335470975?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hXgxP/~3/nzOV4TE7jHo/php-command-line-telnet-client.html" title="PHP Command Line Telnet Client" /><author><name>Gabe LG</name><uri>https://plus.google.com/107192546834216117000</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-St_WHaLi-Yg/AAAAAAAAAAI/AAAAAAAAB6M/EQ_v8i-FgXg/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://onwebdevelopment.blogspot.com/2011/12/php-command-line-telnet-client.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0QNRn07cCp7ImA9WhRQFEs.&quot;"><id>tag:blogger.com,1999:blog-3347571992315805758.post-3447356676462144381</id><published>2011-12-06T05:23:00.001+13:00</published><updated>2011-12-10T11:23:17.308+13:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-10T11:23:17.308+13:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="PHP" /><category scheme="http://www.blogger.com/atom/ns#" term="sendmail" /><category scheme="http://www.blogger.com/atom/ns#" term="email" /><category scheme="http://www.blogger.com/atom/ns#" term="xampp" /><category scheme="http://www.blogger.com/atom/ns#" term="MTA" /><category scheme="http://www.blogger.com/atom/ns#" term="apache" /><title>Sending email from PHP on Windows</title><content type="html">I'm assuming you've installed Xampp or WAMP on your local windows machine. If not please visit the &lt;a href="http://www.apachefriends.org/en/xampp.html"&gt;XAMPP website&lt;/a&gt;. WAMP and XAMPP will install the full windows equivalent of the &lt;a href="http://en.wikipedia.org/wiki/LAMP_(software_bundle)"&gt;LAMP&lt;/a&gt; (Linux Apache MySQL PHP/Perl/Python) stack on your Windows Machine, and offer a GUI to manage it. Here I'll talk about sending email from windows specifically on XAMPP, but you can follow this for WAMP or your own PHP setup.&lt;br /&gt;
&lt;br /&gt;
I'm also assuming you're trying to send email through the PHP function "mail()".&lt;br /&gt;
&lt;br /&gt;
Unlike Linux, Windows is not distributed with a default mail transfer agent (MTA). Linux flavors usually come with sendmail, which acts as a local MTA. &lt;br /&gt;
&lt;br /&gt;
In order to have PHP send email, your windows machine should be able to send email, and have PHP configured to send email through it. So first you need to get your machine to send email. &lt;br /&gt;
&lt;br /&gt;
You can either install an MTA locally (not recommended since sending emails is a complicated by spam detection mechanisms built into the protocol). &lt;br /&gt;
&lt;a href="http://www.google.com/Top/Computers/Software/Internet/Servers/Mail/"&gt;http://www.google.com/Top/Computers/Software/Internet/Servers/Mail/&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://en.wikipedia.org/wiki/List_of_mail_servers"&gt;http://en.wikipedia.org/wiki/List_of_mail_servers&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Or use a free MTA such as hotmail.com or gmail.com. You need an account. &lt;br /&gt;
&lt;br /&gt;
To use a free MTA, you need to specify the MTA host, port, user and password. Luckily there are also sendmail like programs for windows and one is included with Xampp that makes this easy. &lt;br /&gt;
&lt;br /&gt;
You will just need to configure PHP to use the sendmail binary provided by Xampp, to send emails. To do this edit the PHP configuration file, php.ini. You can find this in xampp by opening the control panel, clicking "explore" and going to the folder "php". The full path should be something like:&lt;br /&gt;
&lt;br /&gt;
c:/xampp/php/php.ini &lt;br /&gt;
&lt;br /&gt;
Look for: &lt;br /&gt;
;sendmail_path = "\"C:\xampp\sendmail\sendmail.exe\" -t"&lt;br /&gt;
&lt;br /&gt;
and remove the ";" from the beginning of that line, to enable that configuration directive. &lt;br /&gt;
&lt;br /&gt;
Now your PHP is configured to use the sendmail program that comes with Xampp for win. &lt;br /&gt;
&lt;br /&gt;
You now need to configure your sendmail program to send email to your SMTP server.&lt;br /&gt;
&lt;br /&gt;
So open up the sendmail.ini in the "sendmail" folder. &lt;br /&gt;
c:\xampp\sendmail\sendmail.ini&lt;br /&gt;
&lt;br /&gt;
Create a new account configuration. Example for gmail:&lt;br /&gt;
&lt;br /&gt;
# Gmail example&lt;br /&gt;
account Gmail&lt;br /&gt;
tls on&lt;br /&gt;
tls_certcheck off&lt;br /&gt;
host smtp.gmail.com&lt;br /&gt;
from myuser@gmail.com&lt;br /&gt;
auth on&lt;br /&gt;
user myuser@gmail.com&lt;br /&gt;
password mypassword&lt;br /&gt;
&lt;br /&gt;
Substitute myuser and mypassword for your details. &lt;br /&gt;
&lt;br /&gt;
Now you need to make this account the default by editing the last line in the file to:&lt;br /&gt;
&lt;br /&gt;
# Set a default account&lt;br /&gt;
account default : Gmail&lt;br /&gt;
&lt;br /&gt;
You will then need to restart the apache service. You can do this from the Xampp control panel. (stop/start). This reloads the configuration for PHP. &lt;br /&gt;
&lt;br /&gt;
Now you should be able to send email.&lt;img src="http://feeds.feedburner.com/~r/blogspot/hXgxP/~4/iL4EJTSoTPc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://onwebdevelopment.blogspot.com/feeds/3447356676462144381/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3347571992315805758&amp;postID=3447356676462144381" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/3447356676462144381?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/3447356676462144381?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hXgxP/~3/iL4EJTSoTPc/sending-email-from-php-on-windows.html" title="Sending email from PHP on Windows" /><author><name>Gabe LG</name><uri>https://plus.google.com/107192546834216117000</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-St_WHaLi-Yg/AAAAAAAAAAI/AAAAAAAAB6M/EQ_v8i-FgXg/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://onwebdevelopment.blogspot.com/2011/12/sending-email-from-php-on-windows.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkQBQHoyfip7ImA9WxRWGUk.&quot;"><id>tag:blogger.com,1999:blog-3347571992315805758.post-2633068290280608620</id><published>2008-10-13T19:11:00.006+12:00</published><updated>2008-11-06T16:05:51.496+12:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-11-06T16:05:51.496+12:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="XHR" /><category scheme="http://www.blogger.com/atom/ns#" term="XMLHttpRequest" /><category scheme="http://www.blogger.com/atom/ns#" term="w3c" /><category scheme="http://www.blogger.com/atom/ns#" term="3C" /><title>JavaScript XMLHttpRequest Wrapper</title><content type="html">&lt;p&gt;
Here is my version of the &lt;a href="http://code.google.com/p/xhr/"&gt;XMLHttpRequest Wrapper&lt;/a&gt;, Open Source, and &lt;a href="http://code.google.com/p/xhr/source/browse/trunk/xhr.js"&gt;available &lt;/a&gt;on Google Code. Enjoy.
&lt;/p&gt;

&lt;p&gt;
Here is a simple example of a http request with the lib:
&lt;pre name="code" class="js"&gt;
new fiji.xhr('get', 'echo.php?param=value', function(xhr) {
   if (this.readyState == 4 &amp;&amp; this.status == 200) {
      alert(this.responseText);
   }
}).send();
&lt;/pre&gt;
&lt;/p&gt;

&lt;p&gt;
The readystate callback handler executes in the scope of the XHR Instance. So you can use the &lt;code&gt;this&lt;/code&gt; keyword to reference the XHR object instance. This behavior is the same as the specifications for the callback scope in the &lt;a href="http://www.w3.org/TR/XMLHttpRequest/"&gt;W3C XMLHttpRequest Specs&lt;/a&gt;. 

You can also receive a reference to the XHR library instance which is passed as the first parameter to the callback. In the case above it would be &lt;code&gt;xhr&lt;/code&gt;. 
This allows you to attach further references or objects to the XHR library instance that would be persisted for the duration of the XHR call. For example, a request ID. 

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hXgxP/~4/ulW0AQezDjE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://onwebdevelopment.blogspot.com/feeds/2633068290280608620/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3347571992315805758&amp;postID=2633068290280608620" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/2633068290280608620?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/2633068290280608620?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hXgxP/~3/ulW0AQezDjE/javascript-xmlhttprequest-wrapper.html" title="JavaScript XMLHttpRequest Wrapper" /><author><name>Gabe LG</name><uri>https://plus.google.com/107192546834216117000</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-St_WHaLi-Yg/AAAAAAAAAAI/AAAAAAAAB6M/EQ_v8i-FgXg/s512-c/photo.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://onwebdevelopment.blogspot.com/2008/10/javascript-xmlhttprequest-wrapper.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUcNRH4-fCp7ImA9WxdaF0k.&quot;"><id>tag:blogger.com,1999:blog-3347571992315805758.post-5892804404754959099</id><published>2008-08-26T22:25:00.003+12:00</published><updated>2008-08-26T22:38:15.054+12:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-08-26T22:38:15.054+12:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="SQLite" /><category scheme="http://www.blogger.com/atom/ns#" term="PHP" /><category scheme="http://www.blogger.com/atom/ns#" term="mysql" /><category scheme="http://www.blogger.com/atom/ns#" term="escape" /><category scheme="http://www.blogger.com/atom/ns#" term="string" /><title>Quoting Strings in SQLite with PHP</title><content type="html">&lt;p&gt;
Unlike MySQL, SQLite follows the quoting standards in SQL strictly and does not understand the backslash &lt;code&gt;\&lt;/code&gt; as an escape character. SQLite only understands escaping a single quote with another single quote. 
&lt;/p&gt;

&lt;p&gt;
For example, if you receive the input data &lt;code&gt;'cheeky ' string'&lt;/code&gt; and use the PHP function addslahes() to escape literal characters in the string then you will get &lt;code&gt;'cheeky \' string'&lt;/code&gt; which according to SQLite is not escaped properly. You need to escape the string so that it looks like &lt;code&gt;'cheeky '' string'&lt;/code&gt;. 
&lt;/p&gt;

&lt;p&gt;
If you have &lt;code&gt;magic_quotes&lt;/code&gt; turned on then you are in even more trouble. This PHP setting escapes all HTTP variables received by PHP with an equivalent of &lt;code&gt;addslshes()&lt;/code&gt;. So the correct way to escape strings in SQLite would be:

&lt;pre name="code" class="php"&gt;
function sqlite_quote_string($str) {
 if (get_magic_quotes_gpc()) {
  $str = stripslashes($str);
 }
 return sqlite_escape_string($str);
}
&lt;/pre&gt;
This will remove the escape characters added by the &lt;code&gt;magic_quotes&lt;/code&gt; setting, and escape strings with SQLites &lt;code&gt;sqlite_escape_string()&lt;/code&gt; function which correctly escapes the string with &lt;code&gt;'&lt;/code&gt;.
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hXgxP/~4/F5vYyfmM3WU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://onwebdevelopment.blogspot.com/feeds/5892804404754959099/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3347571992315805758&amp;postID=5892804404754959099" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/5892804404754959099?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/5892804404754959099?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hXgxP/~3/F5vYyfmM3WU/quoting-strings-in-sqlite-with-php.html" title="Quoting Strings in SQLite with PHP" /><author><name>Gabe LG</name><uri>https://plus.google.com/107192546834216117000</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-St_WHaLi-Yg/AAAAAAAAAAI/AAAAAAAAB6M/EQ_v8i-FgXg/s512-c/photo.jpg" /></author><thr:total>2</thr:total><feedburner:origLink>http://onwebdevelopment.blogspot.com/2008/08/quoting-strings-in-sqlite-with-php.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEUDRXw7eCp7ImA9WxdaF0k.&quot;"><id>tag:blogger.com,1999:blog-3347571992315805758.post-4103788109731070211</id><published>2008-08-26T21:24:00.010+12:00</published><updated>2008-08-26T22:24:34.200+12:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-08-26T22:24:34.200+12:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="server" /><category scheme="http://www.blogger.com/atom/ns#" term="SQLite" /><category scheme="http://www.blogger.com/atom/ns#" term="PHP" /><category scheme="http://www.blogger.com/atom/ns#" term="embedded" /><category scheme="http://www.blogger.com/atom/ns#" term="database" /><category scheme="http://www.blogger.com/atom/ns#" term="client" /><title>Creating a custom SQLite Function in PHP</title><content type="html">&lt;p&gt;
SQLite is available in PHP5 either by compiling PHP5 with SQLite support or enabling the SQLite extension dynamically from the PHP configuration (PHP.ini). A distinct feature of SQLite is that it is an embedded database, and thus offers some features a Server/Hosted database such as the popular MySQL database doesn't. 
&lt;/p&gt;

&lt;h3&gt;Creating Custom Functions in SQLite&lt;/h3&gt;
&lt;p&gt;
One of the really cool features of SQLite in PHP is that you can create custom PHP functions, that will be called by SQLite in your queries. Thus you can extend the SQLite functions using PHP. 
&lt;/p&gt;

&lt;h3&gt;A custom Regexp function for SQLite in PHP&lt;/h3&gt;
&lt;p&gt;
&lt;pre name="code" class="php"&gt;
// create a regex match function for sqlite
sqlite_create_function($db, 'REGEX_MATCH', 'sqlite_regex_match', 2);
function sqlite_regex_match($str, $regex) {
 if (preg_match($regex, $str, $matches)) {
  return $matches[0];
 }
 return false;
}
&lt;/pre&gt;
The above PHP code will create a custom function called &lt;code&gt;REGEX_MATCH&lt;/code&gt; for the SQLite connection referenced by &lt;code&gt;$db&lt;/code&gt;. The &lt;code&gt;REGEX_MATCH&lt;/code&gt; SQLite function is implemented by the &lt;code&gt;sqlite_regex_match&lt;/code&gt; user function we define in PHP. 
&lt;/p&gt;

&lt;p&gt;
Here is an example query that makes use of the custom function we created. Notice that in the SQLite query, we call our custom function &lt;code&gt;REGEX_MATCH&lt;/code&gt;:
&lt;pre name="code" class="php"&gt;
$query = 'SELECT REGEX_MATCH(link, \'|http://[^/]+/|i\') AS domain, link, COUNT(link) AS total'
 .' FROM links WHERE domain != 0'
 .' GROUP BY domain'
 .' LIMIT 10';
$result = sqlite_query($db, $query);
&lt;/pre&gt;
This will make SQLite call the PHP function &lt;code&gt;sqlite_regex_match&lt;/code&gt; for each database table row that is goes over when performing the select query, sending it the link field value as the first parameter, and the regular expression string as the second parameter. PHP will then process the function and return its results to SQLite, which continues to the next table row. 
&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;Custom Functions in SQLite compared to MySQL&lt;/h3&gt;
&lt;p&gt;
In comparison with MySQL, you cannot create a custom function in PHP that mysql will use. MySQL allows creation of custom functions, but they have to be written in MySQL. Thus you cannot extend MySQL's query functionality with PHP. 
&lt;/p&gt;

&lt;p&gt;
I believe the reason for this is simply because having a callback function called on the client, by the database, over a Client-Server model for each row that has to be processed would be just inefficient. Imaging processing 100,000 rows in a MySQL database and having MySQL make a callback to PHP over a TCP connection, the overhead of sending the data back and forth for the callback would be way too much. &lt;br /&gt;
With an embedded database like SQLite, this isn't the case since making the actual communication between the language and the embedded database does not pose such a high overhead. 
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hXgxP/~4/i-CN8WNfXNs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://onwebdevelopment.blogspot.com/feeds/4103788109731070211/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3347571992315805758&amp;postID=4103788109731070211" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/4103788109731070211?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/4103788109731070211?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hXgxP/~3/i-CN8WNfXNs/creating-custom-sqlite-function-in-php.html" title="Creating a custom SQLite Function in PHP" /><author><name>Gabe LG</name><uri>https://plus.google.com/107192546834216117000</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-St_WHaLi-Yg/AAAAAAAAAAI/AAAAAAAAB6M/EQ_v8i-FgXg/s512-c/photo.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://onwebdevelopment.blogspot.com/2008/08/creating-custom-sqlite-function-in-php.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DU8MRn8-fyp7ImA9WxRbEks.&quot;"><id>tag:blogger.com,1999:blog-3347571992315805758.post-1262745987913671024</id><published>2008-08-25T04:40:00.023+12:00</published><updated>2008-12-03T13:31:27.157+12:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-03T13:31:27.157+12:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="smtp" /><category scheme="http://www.blogger.com/atom/ns#" term="email" /><category scheme="http://www.blogger.com/atom/ns#" term="mail" /><category scheme="http://www.blogger.com/atom/ns#" term="RFC" /><category scheme="http://www.blogger.com/atom/ns#" term="validation" /><title>PHP Email Address validation through SMTP</title><content type="html">&lt;p&gt;
Here is a PHP class written for PHP4 and PHP5 that will validate email addresses by querying the SMTP (Simple Mail Transfer Protocol) server. This is meant to complement &lt;a href="http://code.google.com/p/php-email-address-validation/"&gt;validation of the syntax of the email address&lt;/a&gt;, which should be used before validating the email via SMTP, which is more resource and time consuming. 
&lt;/p&gt;

&lt;p&gt;
&lt;blockquote style="border: 1px dotted #c0c0c0;"&gt;
&lt;h3&gt;Update: Sept 8, 2008&lt;/h3&gt;
The class has been updated to work with Windows MTA's such as Hotmail and many other fixes have been made. &lt;a href="http://www.daniweb.com/forums/post686242.html#post686242"&gt;See changes&lt;/a&gt;. The class will no longer get you blacklisted by Hotmail due to improper HELO procedure. 
&lt;h3&gt;Update: Sept 10, 2008&lt;/h3&gt;
Window Support Added through Net_DNS (pear DNS class). Added support for validating multiple emails on the same domain through a single Socket. Improved the Email Parsing to support literal @ signs.  
&lt;h3&gt;Update: Sept 29, 2008&lt;/h3&gt;
The code for this project has been moved to &lt;a href="http://code.google.com/p/php-smtp-email-validation/"&gt;Google Code&lt;/a&gt;. The &lt;a href="http://code.google.com/p/php-smtp-email-validation/source/browse/#svn/trunk"&gt;latest source&lt;/a&gt; can be grabbed from SVN.  
&lt;h3&gt;Update: Nov 22, 2008&lt;/h3&gt;
SMTP Email Validation Class has been added to the Yii PHP Framework. 
&lt;a href="http://www.yiiframework.com/" target="_blank"&gt;http://www.yiiframework.com/&lt;/a&gt;. Yii is a high-performance component-based PHP framework for developing large-scale Web applications. 
&lt;/blockquote&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;pre name="code" class="php"&gt;
&amp;lt;?php
 
 /**
 * Validate Email Addresses Via SMTP
 * This queries the SMTP server to see if the email address is accepted.
 * @copyright http://creativecommons.org/licenses/by/2.0/ - Please keep this comment intact
 * @author gabe@fijiwebdesign.com
 * @contributers adnan@barakatdesigns.net
 * @version 0.1a
 */
class SMTP_validateEmail {

 /**
  * PHP Socket resource to remote MTA
  * @var resource $sock 
  */
 var $sock;

 /**
  * Current User being validated
  */
 var $user;
 /**
  * Current domain where user is being validated
  */
 var $domain;
 /**
  * List of domains to validate users on
  */
 var $domains;
 /**
  * SMTP Port
  */
 var $port = 25;
 /**
  * Maximum Connection Time to an MTA 
  */
 var $max_conn_time = 30;
 /**
  * Maximum time to read from socket
  */
 var $max_read_time = 5;
 
 /**
  * username of sender
  */
 var $from_user = 'user';
 /**
  * Host Name of sender
  */
 var $from_domain = 'localhost';
 
 /**
  * Nameservers to use when make DNS query for MX entries
  * @var Array $nameservers 
  */
 var $nameservers = array(
 '192.168.0.1'
);
 
 var $debug = false;

 /**
  * Initializes the Class
  * @return SMTP_validateEmail Instance
  * @param $email Array[optional] List of Emails to Validate
  * @param $sender String[optional] Email of validator
  */
 function SMTP_validateEmail($emails = false, $sender = false) {
  if ($emails) {
   $this-&gt;setEmails($emails);
  }
  if ($sender) {
   $this-&gt;setSenderEmail($sender);
  }
 }
 
 function _parseEmail($email) {
  $parts = explode('@', $email);
 $domain = array_pop($parts);
 $user= implode('@', $parts);
 return array($user, $domain);
 }
 
 /**
  * Set the Emails to validate
  * @param $emails Array List of Emails
  */
 function setEmails($emails) {
  foreach($emails as $email) {
  list($user, $domain) = $this-&gt;_parseEmail($email);
  if (!isset($this-&gt;domains[$domain])) {
    $this-&gt;domains[$domain] = array();
  }
  $this-&gt;domains[$domain][] = $user;
 }
 }
 
 /**
  * Set the Email of the sender/validator
  * @param $email String
  */
 function setSenderEmail($email) {
 $parts = $this-&gt;_parseEmail($email);
 $this-&gt;from_user = $parts[0];
 $this-&gt;from_domain = $parts[1];
 }
 
 /**
 * Validate Email Addresses
 * @param String $emails Emails to validate (recipient emails)
 * @param String $sender Sender's Email
 * @return Array Associative List of Emails and their validation results
 */
 function validate($emails = false, $sender = false) {
  
  $results = array();

  if ($emails) {
   $this-&gt;setEmails($emails);
  }
  if ($sender) {
   $this-&gt;setSenderEmail($sender);
  }

  // query the MTAs on each Domain
  foreach($this-&gt;domains as $domain=&gt;$users) {
   
  $mxs = array();
  
   // retrieve SMTP Server via MX query on domain
   list($hosts, $mxweights) = $this-&gt;queryMX($domain);

   // retrieve MX priorities
   for($n=0; $n &lt; count($hosts); $n++){
    $mxs[$hosts[$n]] = $mxweights[$n];
   }
   asort($mxs);
 
   // last fallback is the original domain
   array_push($mxs, $this-&gt;domain);
   
   $this-&gt;debug(print_r($mxs, 1));
   
   $timeout = $this-&gt;max_conn_time/count($hosts);
    
   // try each host
   while(list($host) = each($mxs)) {
    // connect to SMTP server
    $this-&gt;debug("try $host:$this-&gt;port\n");
    if ($this-&gt;sock = fsockopen($host, $this-&gt;port, $errno, $errstr, (float) $timeout)) {
     stream_set_timeout($this-&gt;sock, $this-&gt;max_read_time);
     break;
    }
   }
  
   // did we get a TCP socket
   if ($this-&gt;sock) {
    $reply = fread($this-&gt;sock, 2082);
    $this-&gt;debug("&lt;&lt;&lt;\n$reply");
    
    preg_match('/^([0-9]{3}) /ims', $reply, $matches);
    $code = isset($matches[1]) ? $matches[1] : '';
 
    if($code != '220') {
     // MTA gave an error...
     foreach($users as $user) {
      $results[$user.'@'.$domain] = false;
  }
  continue;
    }

    // say helo
    $this-&gt;send("HELO ".$this-&gt;from_domain);
    // tell of sender
    $this-&gt;send("MAIL FROM: &lt;".$this-&gt;from_user.'@'.$this-&gt;from_domain."&gt;");
    
    // ask for each recepient on this domain
    foreach($users as $user) {
    
     // ask of recepient
     $reply = $this-&gt;send("RCPT TO: &lt;".$user.'@'.$domain."&gt;");
     
      // get code and msg from response
     preg_match('/^([0-9]{3}) /ims', $reply, $matches);
     $code = isset($matches[1]) ? $matches[1] : '';
  
     if ($code == '250') {
      // you received 250 so the email address was accepted
      $results[$user.'@'.$domain] = true;
     } elseif ($code == '451' || $code == '452') {
   // you received 451 so the email address was greylisted (or some temporary error occured on the MTA) - so assume is ok
   $results[$user.'@'.$domain] = true;
     } else {
      $results[$user.'@'.$domain] = false;
     }
    
    }
    
    // quit
    $this-&gt;send("quit");
    // close socket
    fclose($this-&gt;sock);
   
   }
  }
 return $results;
 }


 function send($msg) {
  fwrite($this-&gt;sock, $msg."\r\n");

  $reply = fread($this-&gt;sock, 2082);

  $this-&gt;debug("&gt;&gt;&gt;\n$msg\n");
  $this-&gt;debug("&lt;&lt;&lt;\n$reply");
  
  return $reply;
 }
 
 /**
  * Query DNS server for MX entries
  * @return 
  */
 function queryMX($domain) {
  $hosts = array();
 $mxweights = array();
  if (function_exists('getmxrr')) {
   getmxrr($domain, $hosts, $mxweights);
  } else {
   // windows, we need Net_DNS
  require_once 'Net/DNS.php';

  $resolver = new Net_DNS_Resolver();
  $resolver-&gt;debug = $this-&gt;debug;
  // nameservers to query
  $resolver-&gt;nameservers = $this-&gt;nameservers;
  $resp = $resolver-&gt;query($domain, 'MX');
  if ($resp) {
   foreach($resp-&gt;answer as $answer) {
    $hosts[] = $answer-&gt;exchange;
    $mxweights[] = $answer-&gt;preference;
   }
  }
  
  }
 return array($hosts, $mxweights);
 }
 
 /**
  * Simple function to replicate PHP 5 behaviour. http://php.net/microtime
  */
 function microtime_float() {
  list($usec, $sec) = explode(" ", microtime());
  return ((float)$usec + (float)$sec);
 }

 function debug($str) {
  if ($this-&gt;debug) {
   echo htmlentities($str);
  }
 }

}

 
?&amp;gt;

&lt;/pre&gt;
&lt;/p&gt;

&lt;h3&gt;Using the PHP SMTP Email Address Validation Class&lt;/h3&gt;
&lt;p&gt;
Example Usage:
&lt;pre name="code" class="php"&gt;
// the email to validate
$email = 'joe@gmail.com';
// an optional sender
$sender = 'user@example.com';
// instantiate the class
$SMTP_Valid = new SMTP_validateEmail();
// do the validation
$result = $SMTP_Valid-&gt;validate($email, $sender);
// view results
var_dump($result);
echo $email.' is '.($result ? 'valid' : 'invalid')."\n";

// send email? 
if ($result) {
  //mail(...);
}

&lt;/pre&gt;

&lt;/p&gt;

&lt;h3&gt;Code Status&lt;/h3&gt;
&lt;p&gt;
This is a very basic, and alpha version of this php class. I just wrote it to demonstrate an example. There are a few limitations. One, it is not optimized. Each email you verify will create a new MX DNS query and a new TCP connection to the SMTP server. The DNS query and TCP socket is not cached for the next query at all, even if they are to the same host or the same SMTP server.&lt;br /&gt;
Second, this will only work on Linux. Windwos does not have the DNS function needed. You could replace the DNS queries with the &lt;a href="http://pear.php.net/package/Net_DNS"&gt;Pear Net_DNS Library&lt;/a&gt; if you need it on Windows.&lt;br /&gt;

&lt;/p&gt;

&lt;h3&gt;Limitations of verifying via SMTP&lt;/h3&gt;
&lt;p&gt;
Not all SMTP servers are configured to let you know that an email address does not exist on the server. If the SMTP server does respond with an "OK", it does not mean that the email address exists. It just means that the SMTP server will accept the email address and not bounce it. What it does with the actual email is different. It may deliver it to the recipient, or it may just send it to a &lt;a href="http://en.wikipedia.org/wiki/NUL_(Computer)"&gt;blackhole&lt;/a&gt;.&lt;br /&gt;
If you get an invalid response from the SMTP server however, you can be pretty sure your email will bounce if you actually send it.
&lt;br /&gt;
You should also NOT use this class to try and guess emails, for spamming purposes. You will quickly get blacklisted on Spamhaus or a similar list. 
&lt;/p&gt;

&lt;h3&gt;Good uses of verifying via SMTP&lt;/h3&gt;
&lt;p&gt;
If you have forms such as registration forms, where users enter their email addresses. It may be a good idea to first check the syntax of the email address, to see if it is valid as per the &lt;a href="http://www.ietf.org/rfc/rfc2822.txt"&gt;SMTP protocol specifications&lt;/a&gt;. Then if it is valid, you may want to verify that the email will be accepted (will not bounce). This can allow you to notify the user of a problem with their email address, in case they made a typo, knowingly entered an invalid email. This could increase the number of successful registrations. 
&lt;/p&gt;
&lt;h3&gt;How it works&lt;/h3&gt;
&lt;p&gt;
If you're interested in how it works, it is quite simple. The class will first take an email, and separate it to the user and host portions. The host portion, tells us which domain to send the email to. However, a domain may have an SMTP server on a different domain so we retrieve a list of SMTP servers that are available for the domain by doing a DNS query of type MX on that domain. We receive a list of SMTP servers, so we iterate through each trying to make a connection. Once connected, we send &lt;a href="http://www.yuki-onna.co.uk/email/smtp.html"&gt;SMTP commands&lt;/a&gt; to the SMTP server, first saying "HELO", then setting our sender, then our recipient. If the recipient is rejected, we know an actual sending of an email will fail. Thus, we close the TCP connection to the SMTP server and quit. 
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hXgxP/~4/VFNOWWvlHQo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://onwebdevelopment.blogspot.com/feeds/1262745987913671024/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3347571992315805758&amp;postID=1262745987913671024" title="7 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/1262745987913671024?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/1262745987913671024?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hXgxP/~3/VFNOWWvlHQo/php-email-address-validation-through.html" title="PHP Email Address validation through SMTP" /><author><name>Gabe LG</name><uri>https://plus.google.com/107192546834216117000</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-St_WHaLi-Yg/AAAAAAAAAAI/AAAAAAAAB6M/EQ_v8i-FgXg/s512-c/photo.jpg" /></author><thr:total>7</thr:total><feedburner:origLink>http://onwebdevelopment.blogspot.com/2008/08/php-email-address-validation-through.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEMDRX06fSp7ImA9WxdaE00.&quot;"><id>tag:blogger.com,1999:blog-3347571992315805758.post-3436164816785450694</id><published>2008-08-21T04:11:00.023+12:00</published><updated>2008-08-21T19:07:54.315+12:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-08-21T19:07:54.315+12:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="PHP" /><category scheme="http://www.blogger.com/atom/ns#" term="CSRF" /><category scheme="http://www.blogger.com/atom/ns#" term="browsers" /><category scheme="http://www.blogger.com/atom/ns#" term="XSS" /><category scheme="http://www.blogger.com/atom/ns#" term="security" /><category scheme="http://www.blogger.com/atom/ns#" term="XSRF" /><title>XSS (Cross Site Scripting)  and stealing passwords</title><content type="html">&lt;p&gt;
&lt;a href="http://en.wikipedia.org/wiki/Cross-site_scripting"&gt;XSS&lt;/a&gt; (Cross Site Scripting) would be viewed by most web developers as the stealing of users session cookies by injecting JavaScript into a web page through URL. You do not associate it with stealing passwords, but worse then stealing session cookies, it can steal a users username and password directly from the browser. 
&lt;/p&gt;

&lt;p&gt;
Many users choose to have the browser remember their login credentials. So when ever they visit a login form, their username and password fields are pre-populated by the browser. Now if there is an XSS vulnerability on that login page, then a remote attacker can successfully retrieve the users username and password.
&lt;/p&gt;

&lt;h3&gt;Hello World in XSS&lt;/h3&gt;
&lt;p&gt;
You have a page that has an XSS vulnerability. Let say a website has a PHP page, &lt;code&gt;mypage.php&lt;/code&gt; with the code:

&lt;pre name="code" class="php"&gt;
&amp;lt;?php

// the variable is returned raw to the browser
echo $_GET['name'];

?&amp;gt;
&lt;/pre&gt;

Because the variable &lt;code&gt;$_GET['name']&lt;/code&gt; is not encoded into HTML entities, or stripped of HTML, it has an XSS vulnerability. Now all an attacker has to do is create a URL that a victim will click, that exploits the vulnerability.
&lt;pre&gt;
mypage.php?name=%3Cscript%3Ealert(document.cookie);%3C/script%3E
&lt;/pre&gt;
This basically will make PHP write &lt;code&gt;&amp;lt;script&amp;gt;alert(document.cookie);&amp;lt;/script&amp;gt;&lt;/code&gt; onto the page, which displays a modal dialog with the value of the saved cookies for that domain. 
&lt;/p&gt;

&lt;h3&gt;How Does stealing passwords with XSS work?&lt;/h3&gt;
&lt;p&gt;
The example above displays the cookies on the domain the webpage is on. Now imagine the same page has a login form, and the user chose to have their passwords remembered by the browser. Lets say the PHP page looks like this:
&lt;pre name="code" class="php"&gt;
&amp;lt;?php

// the variable is returned raw to the browser
echo $_GET['name'];

?&amp;gt;

&amp;lt;form action="login.php"&amp;gt;
&amp;lt;input type="text" name="username" /&amp;gt;
&amp;lt;input type="password" name="password" /&amp;gt;
&amp;lt;input type="submit" value="Login" /&amp;gt;
&amp;lt;/form&amp;gt;

&lt;/pre&gt;

Now an attacker just needs to craft a URL that retrieves the username and password. Here is an example that retrieves the password:
&lt;pre&gt;
mypage.php?name=%3Cscript%3Ewindow.onload=function(){alert(document.forms[0].password);}%3C/script%3E
&lt;/pre&gt;

&lt;/p&gt;

&lt;p&gt;
As you can see, it is just a normal XSS exploit, except it is applied to the username and password populated by the browser after the &lt;code&gt;window.onload&lt;/code&gt; event. 
&lt;/p&gt;

&lt;h3&gt;Password stealing XSS vs Session Cookie stealing XSS&lt;/h3&gt;
&lt;p&gt;
Well, they are both suck from a developers perspective. According to Wikipedia, 70% or so of websites are vulnerable to XSS attacks. 
&lt;/p&gt;
&lt;p&gt;
As a developer, I've always thought of XSS as an exploit on a users session, just as CSRF/XSRF (Cross Site Request Forgery), which requires an active session. Now, as you can see, XSS of the type described does NOT require an active session. The user does not have to be logged into the site. They could have logged out 10 years ago, but as long as the browser remembers their login credentials, the XSS exploit can steal those login credentials.  
&lt;/p&gt;

&lt;p&gt;
Due to its ability to be executed without having the user logged into a website, this exploit should be regarded worse then session based XSS.  
&lt;/p&gt;

&lt;h3&gt;Proof of Concept&lt;/h3&gt;
&lt;p&gt;
Fill in the form below with dummy values and click the "Login" button.
&lt;fieldset&gt;
&lt;legend&gt;Login Form&lt;/legend&gt;
&lt;form name="login_form" action="http://onwebdevelopment.blogspot.com/2008/08/xss-cross-site-scrpting-and-stealing.html"&gt;
Username: &lt;input name="username"&gt;&lt;br /&gt;
Password: &lt;input type="password" name="password" /&gt;&lt;br /&gt;
&lt;input type="submit" value="Login" /&gt;
&lt;/form&gt;
&lt;/fieldset&gt;
&lt;/p&gt;
&lt;p&gt;
Now &lt;a href="http://onwebdevelopment.blogspot.com/2008/08/xss-cross-site-scrpting-and-stealing.html"&gt;return to the same page&lt;/a&gt;, to simulate logging out. 
Now click the 
&lt;a href="javascript:alert('password:'+document.forms['login_form'].password.value);"&gt;Exploit&lt;/a&gt;. This will simulate an XSS exploit on this page, and alert the saved password.
&lt;/p&gt;

&lt;p&gt;
I've set up a proof of concept based on an actual XSS exploit here: 
&lt;a href="http://xss-password.appjet.net/"&gt;http://xss-password.appjet.net/&lt;/a&gt;. 
&lt;/p&gt;

&lt;h3&gt;Preventing Stealing Passwords via XSS&lt;/h3&gt;
&lt;p&gt;
The only way I can think of right now is to give your username and password fields unique names so that the browser does not remember their values. In PHP you can do this with the time() function. 

eg:
&lt;pre name="code" class="php"&gt;
&amp;lt;input type="password" name="pass[&amp;lt;?php echo sha1(time().rand().'secret'); ?&amp;gt;]" /&amp;gt;
&lt;/pre&gt;

The unique names prevents the browser from remembering the password field. This should work universally in all browsers.
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hXgxP/~4/IvRBftqRs-A" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://onwebdevelopment.blogspot.com/feeds/3436164816785450694/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3347571992315805758&amp;postID=3436164816785450694" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/3436164816785450694?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/3436164816785450694?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hXgxP/~3/IvRBftqRs-A/xss-cross-site-scrpting-and-stealing.html" title="XSS (Cross Site Scripting)  and stealing passwords" /><author><name>Gabe LG</name><uri>https://plus.google.com/107192546834216117000</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-St_WHaLi-Yg/AAAAAAAAAAI/AAAAAAAAB6M/EQ_v8i-FgXg/s512-c/photo.jpg" /></author><thr:total>4</thr:total><feedburner:origLink>http://onwebdevelopment.blogspot.com/2008/08/xss-cross-site-scrpting-and-stealing.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0IERXoyeSp7ImA9WxdUEU4.&quot;"><id>tag:blogger.com,1999:blog-3347571992315805758.post-7320389189956675769</id><published>2008-07-27T17:46:00.005+12:00</published><updated>2008-07-27T18:18:24.491+12:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-07-27T18:18:24.491+12:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Sun" /><category scheme="http://www.blogger.com/atom/ns#" term="OpenOffice" /><category scheme="http://www.blogger.com/atom/ns#" term="Microsoft" /><title>OpenOffice Modal Dialog "JRE Required"</title><content type="html">&lt;p&gt;
Was trying to edit a chart in &lt;a href="http://www.openoffice.org/"&gt;OpenOffice&lt;/a&gt; Writer on &lt;a href="http://www.ubuntu.com/"&gt;Ubuntu&lt;/a&gt; today when it popped up a modal dialog box saying that it needed Java Runtime Environment, JRE, to complete the task (not in those words). 
&lt;img src="http://farm4.static.flickr.com/3277/2705191969_78f2cc00e3.jpg?v=0" border="0" /&gt;
&lt;/p&gt;

&lt;p&gt;
Now even after using the Ubuntu package manager, Aptitude, to install the required software OpenOffice still hangs on the modal dialog, making it impossible to close Open Office or do anything else with it. Only solution is to kill the Open Office process, which is called soffice. ie: &lt;code&gt;pkill soffice.bin&lt;/code&gt;. First annoyance I've had with OpenOffice, which apart from this 'lil quirk is the best Document Publisher/Editor - even better then the Microsoft Office Suite. 
&lt;/p&gt;

&lt;p&gt;
It appears this bug is already addressed &lt;a href="http://qa.openoffice.org/issues/show_bug.cgi?id=74940"&gt;http://qa.openoffice.org/issues/show_bug.cgi?id=74940&lt;/a&gt;.
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hXgxP/~4/6YCX2qICybI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://onwebdevelopment.blogspot.com/feeds/7320389189956675769/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3347571992315805758&amp;postID=7320389189956675769" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/7320389189956675769?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/7320389189956675769?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hXgxP/~3/6YCX2qICybI/openoffice-modal-dialog-jre-required.html" title="OpenOffice Modal Dialog &quot;JRE Required&quot;" /><author><name>Gabe LG</name><uri>https://plus.google.com/107192546834216117000</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-St_WHaLi-Yg/AAAAAAAAAAI/AAAAAAAAB6M/EQ_v8i-FgXg/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://onwebdevelopment.blogspot.com/2008/07/openoffice-modal-dialog-jre-required.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUANQ34yfyp7ImA9WxdWF0w.&quot;"><id>tag:blogger.com,1999:blog-3347571992315805758.post-7021383181683429931</id><published>2008-07-11T07:17:00.004+12:00</published><updated>2008-07-11T07:23:12.097+12:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-07-11T07:23:12.097+12:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="joomla" /><category scheme="http://www.blogger.com/atom/ns#" term="wordpress" /><category scheme="http://www.blogger.com/atom/ns#" term="blog" /><category scheme="http://www.blogger.com/atom/ns#" term="blogpulse" /><category scheme="http://www.blogger.com/atom/ns#" term="drupal" /><category scheme="http://www.blogger.com/atom/ns#" term="trend" /><category scheme="http://www.blogger.com/atom/ns#" term="google" /><title>BlogPluse Trends</title><content type="html">&lt;p&gt;
&lt;a href="http://www.blogpulse.com/"&gt;BlogPulse&lt;/a&gt; offers a &lt;a href="http://www.blogpulse.com/trend"&gt;trend search&lt;/a&gt; very similar to &lt;a href="http://www.google.com/trends"&gt;Google Trends&lt;/a&gt; but specifically targeted at blogs. 
&lt;/p&gt;

&lt;p&gt;
Here is the blog trend for the words Joomla, Drupal and Wordpress over the last 6 months. 
&lt;a href="http://www.blogpulse.com/trend?query1=joomla&amp;label1=&amp;query2=drupal&amp;label2=&amp;query3=wordpress&amp;label3=&amp;days=180&amp;x=49&amp;y=11"&gt;&lt;img src="http://farm4.static.flickr.com/3191/2655822823_c265cb073b.jpg?v=0" border="0" /&gt;&lt;/a&gt;
&lt;br /&gt;
This shows the percentage of the mentions of each word, Joomla, Drupal and Wordpress in blogs. 
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hXgxP/~4/3WeglT3Hi4M" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://onwebdevelopment.blogspot.com/feeds/7021383181683429931/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3347571992315805758&amp;postID=7021383181683429931" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/7021383181683429931?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/7021383181683429931?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hXgxP/~3/3WeglT3Hi4M/blogpluse-trends.html" title="BlogPluse Trends" /><author><name>Gabe LG</name><uri>https://plus.google.com/107192546834216117000</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-St_WHaLi-Yg/AAAAAAAAAAI/AAAAAAAAB6M/EQ_v8i-FgXg/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://onwebdevelopment.blogspot.com/2008/07/blogpluse-trends.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DE8HRX0yeyp7ImA9WxdWF0w.&quot;"><id>tag:blogger.com,1999:blog-3347571992315805758.post-7274939933482499135</id><published>2008-07-11T06:45:00.002+12:00</published><updated>2008-07-11T07:07:14.393+12:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-07-11T07:07:14.393+12:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="blog" /><category scheme="http://www.blogger.com/atom/ns#" term="REST" /><category scheme="http://www.blogger.com/atom/ns#" term="lively" /><category scheme="http://www.blogger.com/atom/ns#" term="API" /><category scheme="http://www.blogger.com/atom/ns#" term="3D world" /><category scheme="http://www.blogger.com/atom/ns#" term="widget" /><category scheme="http://www.blogger.com/atom/ns#" term="google" /><category scheme="http://www.blogger.com/atom/ns#" term="mashup" /><category scheme="http://www.blogger.com/atom/ns#" term="secondlife" /><title>Lively - Googles 3D Virtual World</title><content type="html">&lt;p&gt;
Just came across &lt;a href="http://www.lively.com/"&gt;Lively.com&lt;/a&gt; which developed by &lt;a href="http://google.com/"&gt;Google&lt;/a&gt;, creates a virtual 3D world similar to &lt;a href="http://secondlife.com/"&gt;SecondLife&lt;/a&gt;. 
&lt;/p&gt;

&lt;p&gt;
I haven't tested out Lively yet, since I'm running Ubuntu and it only supports Windows at the moment. In &lt;a href="http://googleblog.blogspot.com/2008/07/be-who-you-want-on-web-pages-you-visit.html"&gt;one of their blog posts&lt;/a&gt; however we can gather that Lively is well integrated with the Web. They have widgets that allows visitors - with Lively software installed - to jump into a Lively room embedded in a webpage.
&lt;/p&gt;

&lt;p&gt;
By contrast I believe &lt;a href="http://secondlifegrid.net/programs/api"&gt;SecondLife offer APIs&lt;/a&gt; that offers a REST interface as well as other network level interfacing. Here is a&lt;a href="http://www.facebook.com/apps/application.php?id=10242435556"&gt; SecondLife Facebook&lt;/a&gt; Application.
&lt;/p&gt;

&lt;p&gt;
I'm wondering if Google will offer the same level of integration with their Lively 3D world. Would make fun &lt;a href="http://www.programmableweb.com/"&gt;Mashups&lt;/a&gt;. 
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hXgxP/~4/4mN809y-qa0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://onwebdevelopment.blogspot.com/feeds/7274939933482499135/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3347571992315805758&amp;postID=7274939933482499135" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/7274939933482499135?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/7274939933482499135?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hXgxP/~3/4mN809y-qa0/lively-googles-3d-virtual-world.html" title="Lively - Googles 3D Virtual World" /><author><name>Gabe LG</name><uri>https://plus.google.com/107192546834216117000</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-St_WHaLi-Yg/AAAAAAAAAAI/AAAAAAAAB6M/EQ_v8i-FgXg/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://onwebdevelopment.blogspot.com/2008/07/lively-googles-3d-virtual-world.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkIDRn8zfip7ImA9WxdWEks.&quot;"><id>tag:blogger.com,1999:blog-3347571992315805758.post-1213371244965990910</id><published>2008-07-04T06:41:00.005+12:00</published><updated>2008-07-06T01:29:37.186+12:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-07-06T01:29:37.186+12:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="chain" /><category scheme="http://www.blogger.com/atom/ns#" term="prototype" /><category scheme="http://www.blogger.com/atom/ns#" term="functions" /><title>Chaining Functions in JavaScript</title><content type="html">&lt;p&gt;
A lil snippet I borrowed from the Google AJAX  libraries API:
&lt;pre name="code" class="js"&gt;
chain = function(args) {
    return function() {
     for(var i = 0; i &lt; args.length; i++) {
      args[i]();
     }
    }
   };
&lt;/pre&gt;
You're probably familiar with the &lt;a href="http://simonwillison.net/2004/May/26/addLoadEvent/"&gt;multiple window onload method&lt;/a&gt; written by Simon Willison which creates a closure of functions within functions in order to chain them.&lt;br /&gt;
Here is the same functionality using the &lt;code&gt;chain&lt;/code&gt; function defined above.
&lt;pre name="code" class="js"&gt;
function addLoad(fn) {
    window.onload = typeof(window.onload) != 'function' ? fn : chain([onload, fn]);
};
&lt;/pre&gt;
Chain can also be namespaced to the &lt;code&gt;Function.prototype&lt;/code&gt; if thats how you like your JS. 
&lt;pre name="code" class="js"&gt;
Function.prototype.chain = function(args) {
    args.push(this);
    return function() {
     for(var i = 0; i &lt; args.length; i++) {
      args[i]();
     }
    }
   };
&lt;/pre&gt;
So the multiple window onload function would be:
&lt;pre name="code" class="js"&gt;
window.addLoad = function(fn) {
    window.onload = typeof(window.onload) != 'function' 
    ? fn : window.onload.chain([fn]);
   };
&lt;/pre&gt;
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hXgxP/~4/tNlR3YXVzP4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://onwebdevelopment.blogspot.com/feeds/1213371244965990910/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3347571992315805758&amp;postID=1213371244965990910" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/1213371244965990910?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/1213371244965990910?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hXgxP/~3/tNlR3YXVzP4/chaining-functions-in-javascript.html" title="Chaining Functions in JavaScript" /><author><name>Gabe LG</name><uri>https://plus.google.com/107192546834216117000</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-St_WHaLi-Yg/AAAAAAAAAAI/AAAAAAAAB6M/EQ_v8i-FgXg/s512-c/photo.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://onwebdevelopment.blogspot.com/2008/07/chaining-functions-in-javascript.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUMCQ3c5fSp7ImA9WxdWEUw.&quot;"><id>tag:blogger.com,1999:blog-3347571992315805758.post-7863540912188486076</id><published>2008-07-04T03:58:00.009+12:00</published><updated>2008-07-04T07:31:02.925+12:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-07-04T07:31:02.925+12:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="jsapi" /><category scheme="http://www.blogger.com/atom/ns#" term="remoting" /><category scheme="http://www.blogger.com/atom/ns#" term="libraries" /><category scheme="http://www.blogger.com/atom/ns#" term="google" /><title>Hacking Google Loader and the AJAX Libraries API</title><content type="html">&lt;p&gt;
Google recently released the &lt;a href="http://code.google.com/apis/ajaxlibs/documentation/index.html"&gt;AJAX Libraries API&lt;/a&gt; which allows you to load the popular JavaScript libraries from Google Servers. The benefits of this outlined in the description of the API. 
&lt;/p&gt;
&lt;blockquote style="border:1px solid gray;background-color:#c0c0c0;"&gt;
The AJAX Libraries API is a content distribution network and loading architecture for the most popular open source JavaScript libraries. By using the google.load() method, your application has high speed, globally available access to a growing list of the most popular JavaScript open source libraries. 
&lt;/blockquote&gt;
&lt;p&gt;
I was thinking of using it for a current project that would use JS heavily, however, since the project used a CMS (Joomla) the main concern for me was really how many times MooTools would be loaded. Joomla uses a PHP based plugin system (which registers observers of events triggered during Joomla code execution) and the loading of JavaScript by multiple plugins can be redundant as there is no central way of knowing which JavaScript library has already been loaded, nor is there a central repository for JavaScript libraries within Joomla. 
&lt;/p&gt;
&lt;p&gt;
MooTools is the preferred library for Joomla and in some cases it is loaded 2 or even 3 times redundantly. I did not want our extension to add to that mess. To solve the problem I would test for the existence of MooTools, &lt;code&gt;if (typeof(MooTools) == 'undefined')&lt;/code&gt; and load it from Google only if it wasn't available. Now this would have worked well, however, I would have to add the JavaScript for &lt;a href="http://code.google.com/apis/ajaxlibs/documentation/index.html"&gt;AJAX Libraries API&lt;/a&gt; and it would only be loading 1 script, "MooTools", when I also had about 3-4 other custom libraries that I wanted loaded. 
&lt;/p&gt;
&lt;p&gt;
Now I thought, why don't I develop a JavaScript loader just like the Google AJAX Libraries API Loader. Should be just a simple function to append a Script element to the document head.  So I started with:
&lt;/p&gt;
&lt;p&gt;
&lt;pre name="code" class="js"&gt;
function loadJS(src) {
    var script = document.createElement('script');
    script.src = src;
    script.type = 'text/javascript';
    timer = setInterval(closure(this, function(script) {
     if (document.getElementsByTagName('head')[0]) {
      clearTimeout(timer);
      document.getElementsByTagName('head')[0].appendChild(script);
     }
    }, [script]), 50);
   }
function closure(obj, fn, params) {
    return function() {
     fn.apply(obj, params);
    };
   }
&lt;/pre&gt;
The function loadJS would try to attach a &lt;code&gt;script&lt;/code&gt; element to the document head, each 50 milliseconds until it succeeded. 
&lt;/p&gt;
&lt;p&gt;
This works but there is no way of knowing when the JavaScript file was fully loaded. Normally, the way to figure out if a JS file has finished loading from the remote server, is to have the JS file invoke a callback function on the Client JavaScript (aka: JavaScript Remoting). This however means you have to build a callback function into each JavaScript file, which is not what I wanted.
&lt;/p&gt;
&lt;p&gt;
So to fix this problem I though I'd add another Interval with &lt;code&gt;setInterval()&lt;/code&gt; to detect when the remote JS file had finished loading by testing a condition that exits when the file has completed. eg: for MooTools it would mean that the Object &lt;code&gt;window.MooTools&lt;/code&gt; existed.
&lt;/p&gt;
&lt;p&gt;
So I went about writing a JavaScript library for this, with a somewhat elaborate API, with JS libraries registering their "load condition test" and allowing their remote loading, about 1 wasted hour, (well not wasted if you learn something) only to realize that this wouldn't work for the purpose either. The reason is that it broke the &lt;code&gt;window.onload&lt;/code&gt; functionality. Some remote files would load before the window.onload event (cached ones) and others after. This made the JavaScript already written to rely on window.onload fail. 
&lt;/p&gt;

&lt;p&gt;
Last Resort, how did Google Do it? I had noted earlier that if you load a JavaScript file with Google's API the file would always load before the &lt;code&gt;window.onload&lt;/code&gt; method fired. Here is the simple test: (In the debug output, the google callback always fired first).
&lt;pre name="code" class="js"&gt;
google.load("prototype", "1");
   google.load("jquery", "1");
   google.load("mootools", "1");
   google.setOnLoadCallback(function() {
    addLoad(function() {
     debug('google.setOnLoadCallback - window.onload');
    });
    debug('google.setOnLoadCallback')
   });
   addLoad(function() {
    debug('window.onload');
   });
   debug('end scripts');
&lt;/pre&gt;
I had to take a look at the source code for Google's AJAX Libraries API which is: &lt;a href="http://www.google.com/jsapi"&gt;http://www.google.com/jsapi&lt;/a&gt; to see how they achieved this.
&lt;/p&gt;

&lt;p&gt;
It never occurred to me that you could force the browser to load your JavaScript before the &lt;code&gt;window.onload&lt;/code&gt; event so I was a bit baffled. Browsing through their source code I came upon what I was looking for:
&lt;pre name="code" class="js"&gt;
function q(a,b,c){if(c){var d;if(a=="script"){d=document.createElement("script");d.type="text/javascript";d.src=b}else if(a=="css"){d=document.createElement("link");d.type="text/css";d.href=b;d.rel="stylesheet"}var e=document.getElementsByTagName("head")[0];if(!e){e=document.body.parentNode.appendChild(document.createElement("head"))}e.appendChild(d)}else{if(a=="script"){document.write('&amp;lt;script src="'+b+'" type="text/javascript"&amp;gt;&amp;lt;\/script&amp;gt;')}else if(a=="css"){document.write('&amp;lt;link href="'+b+'" type="text/css" rel="stylesheet"&amp;gt;&amp;lt;/link&amp;gt;'
)}}}
&lt;/pre&gt;
The code has been minified, so its a bit hard to read. Basically its the same as any javascript remoting code you'd find on the net, the but the part that jumps out is:
&lt;pre name="code" class="js"&gt;
var e=document.getElementsByTagName("head")[0];
if(!e){e=document.body.parentNode.appendChild(document.createElement("head"))}
e.appendChild(d)
&lt;/pre&gt;
Notice how it will create a &lt;code&gt;head&lt;/code&gt; Node and append it to the parentNode of the document body if the document &lt;code&gt;head&lt;/code&gt; head does not exist yet. 
&lt;/p&gt;
&lt;p&gt;
Now that forces the browser to load the JavaScript right then, no matter what. Now following that method you can load remote JavaScript files dynamically and just used the regular old &lt;code&gt;window.onload&lt;/code&gt; event or "domready" event and the files will be available.
&lt;/p&gt;
&lt;p&gt;
Apparently this won't work on all browsers, since Google's code also has the alternative:
&lt;pre name="code" class="js"&gt;
document.write('&amp;lt;script src="'+b+'" type="text/javascript"&amp;gt;&amp;lt;\/script&amp;gt;')
&lt;/pre&gt;
with a bit of testing, you could discern which browsers worked with which and use that. I'd imagine that the latest browsers would accept the dom method and older ones would need the &lt;code&gt;document.write&lt;/code&gt;
&lt;/p&gt;
&lt;p&gt;
So my JavaScript file loading function became:
&lt;pre name="code" class="js"&gt;
function loadJS(src) {
    var script = document.createElement('script');
    script.src = src;
    script.type = 'text/javascript';
    var head = document.getElementsByTagName('head')[0];
    if (!head) {
     head = document.body.parentNode.appendChild(document.createElement('head'));
    }
    head.appendChild(script);
    
   }
&lt;/pre&gt;
&lt;/p&gt;

&lt;p&gt;
Anyways, I finally got my JavaScript library loader working just as I liked, thanks to the good work done by Google with the AJAX Libraries API. 
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hXgxP/~4/lHiekpoFCxY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://onwebdevelopment.blogspot.com/feeds/7863540912188486076/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3347571992315805758&amp;postID=7863540912188486076" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/7863540912188486076?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/7863540912188486076?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hXgxP/~3/lHiekpoFCxY/hacking-google-loader-and-ajax.html" title="Hacking Google Loader and the AJAX Libraries API" /><author><name>Gabe LG</name><uri>https://plus.google.com/107192546834216117000</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-St_WHaLi-Yg/AAAAAAAAAAI/AAAAAAAAB6M/EQ_v8i-FgXg/s512-c/photo.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://onwebdevelopment.blogspot.com/2008/07/hacking-google-loader-and-ajax.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkIFQHc-eyp7ImA9WxdWEU0.&quot;"><id>tag:blogger.com,1999:blog-3347571992315805758.post-8469356937672088553</id><published>2008-07-04T00:14:00.005+12:00</published><updated>2008-07-04T03:55:11.953+12:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-07-04T03:55:11.953+12:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="openssh" /><category scheme="http://www.blogger.com/atom/ns#" term="tunneling" /><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="ssh" /><category scheme="http://www.blogger.com/atom/ns#" term="socks" /><category scheme="http://www.blogger.com/atom/ns#" term="proxy" /><title>Secure HTTP over SSH proxy with Linux</title><content type="html">&lt;p&gt;
In an previous post I made I detailed how to create a secure your browser's HTTP communications by tunneling the &lt;a href="http://onwebdevelopment.blogspot.com/2008/02/secure-http-over-ssh-proxy-with-putty.html"&gt;HTTP session over an SSH proxy using Putty&lt;/a&gt;. 
&lt;/p&gt;

&lt;p&gt;
&lt;a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html"&gt;Putty&lt;/a&gt; is what you would use if you use a Windows desktop. If you're on a Linux Desktop you do not need Putty since you should have OpenSSH with the distribution you use. 
&lt;/p&gt;

&lt;p&gt;
Doing a &lt;code&gt;man ssh&lt;/code&gt; on your Linux Desktop should give you the manual on how to use your SSH client: 
&lt;pre&gt;
SSH(1)                                                         BSD General Commands Manual                                                         SSH(1)

NAME
     ssh - OpenSSH SSH client (remote login program)

SYNOPSIS
     ssh [-1246AaCfgKkMNnqsTtVvXxY] [-b bind_address] [-c cipher_spec] [-D  [bind_address:]port] [-e escape_char] [-F configfile] [-i identity_file] [-L
         [bind_address:]port:host:hostport] [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port] [-R  [bind_address:]port:host:hostport]
         [-S ctl_path] [-w local_tun[:remote_tun]] [user@]hostname [command]

... etc ...
&lt;/pre&gt;
The synopsis gives you the format of the command and the options that can be used with the ssh command. Of interest is the -D option. This allows you to bind the SSH session to a local address and port. Below is the part of the manual explaining the D option:
&lt;pre&gt;
     -D [bind_address:]port
             Specifies a local “dynamic” application-level port forwarding.  This works by allocating a socket to listen to port on the local side,
             optionally bound to the specified bind_address.  Whenever a connection is made to this port, the connection is forwarded over the secure
             channel, and the application protocol is then used to determine where to connect to from the remote machine.  Currently the SOCKS4 and
             SOCKS5 protocols are supported, and ssh will act as a SOCKS server.  Only root can forward privileged ports.  Dynamic port forwardings can
             also be specified in the configuration file.

             IPv6 addresses can be specified with an alternative syntax: [bind_address/]port or by enclosing the address in square brackets.  Only the
             superuser can forward privileged ports.  By default, the local port is bound in accordance with the GatewayPorts setting.  However, an
             explicit bind_address may be used to bind the connection to a specific address.  The bind_address of “localhost” indicates that the listen‐
             ing port be bound for local use only, while an empty address or ‘*’ indicates that the port should be available from all interfaces.
&lt;/pre&gt;
Basically it means that you can start an SSH session using the OpenSSH client with a command such as:
&lt;pre&gt;
ssh -D localhost:8000 user@example.com
&lt;/pre&gt;
and it will create a SOCKS proxy on port &lt;code&gt;8000&lt;/code&gt; that will tunnel your HTTP connection over SSH to the server at &lt;code&gt;example.com&lt;/code&gt; under the username &lt;code&gt;user&lt;/code&gt;.
&lt;/p&gt;
&lt;p&gt;
Now you can configure your applications that access the internet to use the secure HTTP tunnel you've created to your remote SSH server. The applications are not limited to web browsers, you can configure your Instant Messenger, Skype, Games etc. to use the socks proxy, as long at the communication protocol is supported.
&lt;/p&gt;
&lt;h3&gt;Configuring Firefox to use the Socks Proxy&lt;/h3&gt;
&lt;p&gt;
&lt;ul&gt;
&lt;li&gt;Tools -&amp;gt; Options -&amp;gt; Advanced -&amp;gt; Network&lt;/li&gt;
&lt;li&gt;Under Connection click on the Settings button&lt;/li&gt;
&lt;li&gt;Choose Manual Proxy configuration, and SOCKS v5&lt;/li&gt;
&lt;li&gt;Fill in localhost for the host, and 8000 (or the port number you used) for the port&lt;/li&gt;
&lt;li&gt;Click OK and reload the page&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;
&lt;p&gt;
Now what you can do is have the the ssh session start up when you start your desktop. Thats if you want to use your secure tunnel every time you use Firefox or whatever program you have configured to use it. On Ubuntu (Debian) you'd add a shell script to your home directory. &lt;br /&gt;
Example:
&lt;pre&gt;
#!/bin/sh
ssh -D localhost:8000 user@example.com
&lt;/pre&gt;
That should start up the ssh connection and create the socks proxy when you log in. The other alternative is to create a launcher and use &lt;code&gt;ssh -D localhost:8000 user@example.com&lt;/code&gt; as the command, allowing you to launch the proxy whenever you need. 
&lt;/p&gt;
&lt;p&gt;
You can also set up an ssh key for authentication instead of having to log in. This is detailed in other posts: &lt;a href="http://pkeck.myweb.uga.edu/ssh/"&gt;http://pkeck.myweb.uga.edu/ssh/&lt;/a&gt; and &lt;a href="http://sial.org/howto/openssh/publickey-auth/"&gt;http://sial.org/howto/openssh/publickey-auth/&lt;/a&gt;. This allows you to use the proxy transparently in the background without having to start it and log in.
&lt;/p&gt;

&lt;p&gt;
For Firefox you can switch between proxy and direct connection using the &lt;a href="http://www.mozmonkey.com/switchproxy/"&gt;switchproxy extension&lt;/a&gt;. 
&lt;/p&gt;

&lt;p&gt;
Disclaimer: Please note that it is your responsibility to use the information in this article within the legal laws of your country. Some countries do not allow encryption of internet traffic, therefore you SHOULD NOT use this resource if you live in such a country. I provide this information without warranty and free of charge and will not be held accountable for any damages lost due to its use.. etc etc.
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hXgxP/~4/L23t9HsqFOg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://onwebdevelopment.blogspot.com/feeds/8469356937672088553/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3347571992315805758&amp;postID=8469356937672088553" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/8469356937672088553?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/8469356937672088553?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hXgxP/~3/L23t9HsqFOg/secure-http-over-ssh-proxy-with-linux.html" title="Secure HTTP over SSH proxy with Linux" /><author><name>Gabe LG</name><uri>https://plus.google.com/107192546834216117000</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-St_WHaLi-Yg/AAAAAAAAAAI/AAAAAAAAB6M/EQ_v8i-FgXg/s512-c/photo.jpg" /></author><thr:total>3</thr:total><feedburner:origLink>http://onwebdevelopment.blogspot.com/2008/07/secure-http-over-ssh-proxy-with-linux.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUMBQH86eCp7ImA9WxdXEk8.&quot;"><id>tag:blogger.com,1999:blog-3347571992315805758.post-7755027629170120089</id><published>2008-06-23T23:17:00.005+12:00</published><updated>2008-06-24T00:17:31.110+12:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-06-24T00:17:31.110+12:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="website analytics" /><category scheme="http://www.blogger.com/atom/ns#" term="website metrics" /><category scheme="http://www.blogger.com/atom/ns#" term="google" /><title>Google Trends for websites</title><content type="html">&lt;p&gt;
The &lt;a href="http://trends.google.com/"&gt;Google trends for websites&lt;/a&gt;, which was released by Google &lt;a href="http://googlewebmastercentral.blogspot.com/2008/06/new-layer-to-google-trends.html"&gt;3 days ago&lt;/a&gt;, is really something to check out if you're interested in comparing website metrics between different websites and across geographical locations.
&lt;/p&gt;

&lt;p&gt;
Alexa and Compete offer similar services. One of the features that stands out with Google trends is that it displays related websites that visitors to the website being viewed visit in descending order of visitors. This related websites are also filtered when filtering down to single geographic locations. This makes Google trends for websites quite a bit more powerful for your research. It allows you to view a websites competitors in each geographic location or allows link building and search engine optimization for a website for each geographic location.
&lt;/p&gt;

&lt;h3&gt;Joomla vs Wordpress on Google Trends for websites&lt;/h3&gt;
&lt;p&gt;
&lt;a href="http://www.flickr.com/photos/bucabay/2604134970/"&gt;&lt;img src="http://farm4.static.flickr.com/3283/2604134970_4ffb255724.jpg?v=0" border="0" /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;Joomla vs Wordpress on Alexa Website Analytics&lt;/h3&gt;
&lt;p&gt;
&lt;a href="http://www.flickr.com/photos/bucabay/2604105682/"&gt;&lt;img src="http://farm4.static.flickr.com/3019/2604105682_3e4ac4a737.jpg?v=0" border="0" /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;Joomla vs Wordpress on Compete Website Analytics&lt;/h3&gt;
&lt;p&gt;
&lt;a href="http://www.flickr.com/photos/bucabay/2604105482/"&gt;&lt;img src="http://farm4.static.flickr.com/3076/2604105482_3cbc1f49b4.jpg?v=0" border="0" /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;a href="http://searchengineland.com/080620-131900.php"&gt;Search Engine Land &lt;/a&gt;and &lt;a href="http://www.mattcutts.com/blog/google-trends-for-websites/"&gt;Matt Cutts&lt;/a&gt; also blogged about the new google trends for websites.
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hXgxP/~4/OMlddxRizeQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://onwebdevelopment.blogspot.com/feeds/7755027629170120089/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3347571992315805758&amp;postID=7755027629170120089" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/7755027629170120089?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/7755027629170120089?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hXgxP/~3/OMlddxRizeQ/google-trends-for-websites.html" title="Google Trends for websites" /><author><name>Gabe LG</name><uri>https://plus.google.com/107192546834216117000</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-St_WHaLi-Yg/AAAAAAAAAAI/AAAAAAAAB6M/EQ_v8i-FgXg/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://onwebdevelopment.blogspot.com/2008/06/google-trends-for-websites.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Dk4CRXk-fip7ImA9WxdXEEg.&quot;"><id>tag:blogger.com,1999:blog-3347571992315805758.post-3274560214011931157</id><published>2008-06-22T00:59:00.008+12:00</published><updated>2008-06-22T01:29:24.756+12:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-06-22T01:29:24.756+12:00</app:edited><title>Online Application Development Platforms and Services</title><content type="html">&lt;p&gt;
Everyone is offering Application development as a service!
&lt;/p&gt;

&lt;h3&gt;Appjet&lt;/h3&gt;
&lt;p&gt;
&lt;blockquote&gt;
AppJet is the easiest way to create a web app. Just type some code into a box, and we'll host your app on our servers.
&lt;/blockquote&gt;
&lt;a href="http://appjet.com/"&gt;http://appjet.com/&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;AppPad&lt;/h3&gt;
&lt;p&gt;
&lt;blockquote&gt;
AppPad provides a place to create web applications completely in HTML and Javascript. AppPad gives you:
&lt;/blockquote&gt;
&lt;a href="http://apppad.com/"&gt;http://apppad.com/&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;Bungee Connect&lt;/h3&gt;
&lt;p&gt;
&lt;blockquote&gt;
Bungee Connect is the most comprehensive Platform-as-a-Service (PaaS) — significantly reducing the complexities, time and costs required to build and deliver web applications.
&lt;/blockquote&gt;
&lt;a href="http://www.bungeelabs.com/"&gt;http://www.bungeelabs.com/&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;CogHead&lt;/h3&gt;
&lt;p&gt;
&lt;blockquote&gt;
Coghead is a 100% web-based system that allows knowledge workers to create their own custom business applications. There’s never any software to install or servers to maintain. Just think it, build it and share it!
&lt;/blockquote&gt;
&lt;a href="http://www.coghead.com/"&gt;http://www.coghead.com/&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;Google App Engine&lt;/h3&gt;
&lt;p&gt;
&lt;blockquote&gt;
Google App Engine enables you to build web applications on the same scalable systems that power Google applications.
&lt;/blockquote&gt;
&lt;a href="http://code.google.com/appengine/"&gt;http://code.google.com/appengine/&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
I was going to add more but got bored after reaching G. Now I'm just waiting for that meta web application development environment that integrates all the above with a RESTful API. lol...
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hXgxP/~4/dmZBYtgGucc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://onwebdevelopment.blogspot.com/feeds/3274560214011931157/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3347571992315805758&amp;postID=3274560214011931157" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/3274560214011931157?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/3274560214011931157?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hXgxP/~3/dmZBYtgGucc/online-application-development.html" title="Online Application Development Platforms and Services" /><author><name>Gabe LG</name><uri>https://plus.google.com/107192546834216117000</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-St_WHaLi-Yg/AAAAAAAAAAI/AAAAAAAAB6M/EQ_v8i-FgXg/s512-c/photo.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://onwebdevelopment.blogspot.com/2008/06/online-application-development.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak4ERHwzcSp7ImA9WxdQFU0.&quot;"><id>tag:blogger.com,1999:blog-3347571992315805758.post-5544649294926874888</id><published>2008-06-15T16:38:00.005+12:00</published><updated>2008-06-15T17:48:25.289+12:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-06-15T17:48:25.289+12:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="persistence" /><category scheme="http://www.blogger.com/atom/ns#" term="object" /><category scheme="http://www.blogger.com/atom/ns#" term="window" /><title>JavaScript Cross Window Communication via Cookies</title><content type="html">&lt;p&gt;
Using JavaScript we can communicate between browser windows given that we have a reference to each window. When a new window is created the the JavaScript method &lt;code&gt;window.open()&lt;/code&gt; it returns a reference to the new window. The child window, also has a reference to the parent window that created it via the &lt;code&gt;window.opener&lt;/code&gt; window object. These references allow the two windows to communicate with and manipulate each other.
&lt;/p&gt;

&lt;p&gt;
There are times however, when we need to communicate with an open window for which there is no window object reference. A typical example of this is when a popup window is created, then the parent window is reloaded. When reloading the parent, all JavaScript objects are "trashed", along with the reference to the open popup window. Here is where cookies come into play - they are not trashed. 
&lt;/p&gt;

&lt;p&gt;
The problem with cookies is that it only saves strings, so you can't write a reference to a window object directly to a cookie, since serializing the reference is not possible. However, since both the child window and the parent window are able to read and write cookies, then they have a medium for which they can communicate. Even if the medium only allows strings. 
&lt;/p&gt;

&lt;p&gt;
To demonstrate how communicating between windows with cookies would work, lets assume we want to open a window, and then close it a few seconds later.

&lt;pre name="code" class="js"&gt;
var win = window.open('child.html');
setTimeout(function() { win.close(); }, 5000);
&lt;/pre&gt;

The code will open a child window, and close it after 5 seconds using the reference to the child window and the method &lt;code&gt;close()&lt;/code&gt;. However if we didn't have a reference for some reason, we would not be able to invoke the close method. So lets see how it could be done with cookies:

&lt;pre name="code" class="js"&gt;
window.open('child.html');
setTimeout(function() { setCookie('child', 'close'); }, 5000);
&lt;/pre&gt;

Here we open a window but do not save a reference. Then after 5 seconds we write 'close', to the cookie named 'child' (using the pseudo setCookie() function). This does not do anything by itself, but if the child window was expecting the cookie, it could close itself when it read 'close'. Lets assume the following JS is in child.html. 

&lt;pre name="code" class="js"&gt;
// child.html
setInterval(function() { getCookie('child') == 'close' ? this.close() : ''; }, 500);
&lt;/pre&gt;

This would check the cookie every half a seconds and close the window if the cookie read 'close'.

&lt;/p&gt;

&lt;p&gt;
Using this method we can send any commands to any open windows and have them execute it without having a reference to that window.
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hXgxP/~4/REBak80N8Og" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://onwebdevelopment.blogspot.com/feeds/5544649294926874888/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3347571992315805758&amp;postID=5544649294926874888" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/5544649294926874888?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/5544649294926874888?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hXgxP/~3/REBak80N8Og/javascript-cross-window-communication.html" title="JavaScript Cross Window Communication via Cookies" /><author><name>Gabe LG</name><uri>https://plus.google.com/107192546834216117000</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-St_WHaLi-Yg/AAAAAAAAAAI/AAAAAAAAB6M/EQ_v8i-FgXg/s512-c/photo.jpg" /></author><thr:total>3</thr:total><feedburner:origLink>http://onwebdevelopment.blogspot.com/2008/06/javascript-cross-window-communication.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUEGQXcyeSp7ImA9WxdRF00.&quot;"><id>tag:blogger.com,1999:blog-3347571992315805758.post-3738964601070194706</id><published>2008-06-06T04:46:00.005+12:00</published><updated>2008-06-06T10:07:00.991+12:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-06-06T10:07:00.991+12:00</app:edited><title>Blocking Advertisements with a Hosts file, Apache  and PHP</title><content type="html">&lt;p&gt;
The Hosts file is located at &lt;code&gt;/etc/hosts&lt;/code&gt; on Linux and &lt;code&gt;%SystemRoot%\system32\drivers\etc\&lt;/code&gt; on Windows XP and Vista. It maps host names to IP addresses and takes precedence over the DNS server. So if you add an entry in your hosts file:
&lt;pre&gt;
207.68.172.246 google.com 
&lt;/pre&gt;
Then every time you type google.com you will be taken to msn.com instead, since &lt;code&gt;207.68.172.246&lt;/code&gt; is the IP address of msn.com. 
&lt;/p&gt;

&lt;p&gt;
Knowing this, you can point any domain, to an IP address of choice using the Hosts file. Therefore, we can use it to block any domains that hosts unwanted advertising or malware.
&lt;/p&gt;

&lt;h3&gt;Modifying your Hosts File to block Advertisements and Malware&lt;/h3&gt;
&lt;p&gt;
There are many sites offering host files which block advertisments and malware. I use the one on &lt;a href="http://www.mvps.org/winhelp2002/hosts.htm"&gt;http://www.mvps.org/winhelp2002/hosts.htm&lt;/a&gt;. 
&lt;br /&gt;
Here is the txt version of the hosts file: &lt;a href="http://www.mvps.org/winhelp2002/hosts.txt"&gt;http://www.mvps.org/winhelp2002/hosts.txt&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Here is an example of what the entries look like, there the list contains a lot more, about 18, 000 entries at this time.
&lt;pre&gt;
# [Misc A - Z]
127.0.0.1  ad.a8.net
127.0.0.1  asy.a8ww.net
127.0.0.1  www.abx4.com #[Adware.ABXToolbar]
127.0.0.1  acezip.net #[SiteAdvisor.acezip.net]
127.0.0.1  www.acezip.net #[Win32/Adware.180Solutions]
127.0.0.1  phpadsnew.abac.com
127.0.0.1  a.abnad.net
127.0.0.1  b.abnad.net
127.0.0.1  c.abnad.net #[eTrust.Tracking.Cookie]
127.0.0.1  d.abnad.net
127.0.0.1  e.abnad.net
127.0.0.1  t.abnad.net
127.0.0.1  banners.absolpublisher.com
127.0.0.1  tracking.absolstats.com
127.0.0.1  adv.abv.bg
127.0.0.1  bimg.abv.bg
127.0.0.1  www2.a-counter.kiev.ua
127.0.0.1  accuserveadsystem.com
127.0.0.1  www.accuserveadsystem.com
127.0.0.1  gtb5.acecounter.com
127.0.0.1  gtcc1.acecounter.com
127.0.0.1  gtp1.acecounter.com #[eTrust.Tracking.Cookie]
127.0.0.1  acestats.com
127.0.0.1  www.acestats.com
127.0.0.1  achmedia.com
127.0.0.1  ads.active.com
127.0.0.1  am1.activemeter.com
127.0.0.1  www.activemeter.com #[eTrust.Tracking.Cookie]
127.0.0.1  ads.activepower.net
127.0.0.1  stat.active24stats.nl #[eTrust.Tracking.Cookie]
127.0.0.1  web.acumenpi.com #[AdvertPro]
127.0.0.1  ad.ad24.ru
127.0.0.1  at.ad2click.nl
127.0.0.1  cms.ad2click.nl
127.0.0.1  banner.ad.nu
127.0.0.1  ad-up.com
127.0.0.1  www.ad-up.com
&lt;/pre&gt;
You will need to download the txt file and append the entries to your hosts file. 
&lt;/p&gt;

&lt;p&gt;
Now once the hosts file is in effect, when you browse any website in firefox or IE or any other browser, 99% of the advertisements will not be displayed. 
&lt;/p&gt;

&lt;h3&gt;Setting up Apache to display a custom page or message for blocked Advertisements and Malware&lt;/h3&gt;
&lt;p&gt;
Each entry in the hosts file blocks unwanted sites by resolving their domain name to 127.0.0.1 which is the IP reserved for looping back to your own IP. So all the requests for advertising sites will instead be made back to your IP. The problem with this is because there is no website on your localhost, then the browser will display an error in place of the ads.
&lt;/p&gt;

&lt;p&gt;
If you're a web developer, you'll likely have a version of Apache or some other HTTP server running on your localhost. So you'll likely get a 404 error in place of the ads. You can resolve this by adding a virtual host entry into your httpd.conf file that will display a custom page instead of the 404. 
&lt;/p&gt;

&lt;p&gt;
To resolve this you can set up a virtual host to catch all requests made to your Apache server, for the blocked hosts. Assuming you always access your local server via the URL http://localhost/ then you probably don't need the other host possibilities on 127.0.0.1. So your virtual host could look something like:
&lt;pre&gt;
&amp;lt;VirtualHost 127.0.0.1&amp;gt;
ServerAdmin webmaster@adblock
DocumentRoot /var/www/adblock/
ErrorDocument 404 /404.html
ErrorLog /etc/log/adblock/error.log
TransferLog /etc/log/adblock/access.log
&amp;lt;/VirtualHost&amp;gt;
&lt;/pre&gt;
This will catch all requests made to 127.0.0.1. The requests will most likely have a path that doesn't exist in your file structure in /var/www/adblock/ so it will generate a 404 error. You therefore need a custom 404 document which is defined in &lt;code&gt;ErrorDocument 404 /404.html&lt;/code&gt;. This can have the simple line, "ad or malware blocked" or something on those lines. 
&lt;/p&gt;
&lt;p&gt;
Now localhost also resolves to 127.0.0.1 so you will need to make sure you have a virtual host for the host localhost. 
&lt;/p&gt;

&lt;p&gt;
The other thing you could do instead of setting up a virtual host, and it may be simpler, is create a custom 404 document for your current setup. You can do this via a directive directly in httpd.conf like: &lt;code&gt;ErrorDocument 404 /404.php&lt;/code&gt;. Notice that it is a PHP so you can use some PHP code to customize the error message. What you'll want is to have the PHP detect if the request was for a blocked site, and if so show your message: "site blocked", but show the regular 404 page for your actual website. 
&lt;/p&gt;

&lt;p&gt;
How you detect if the request is from a one of the blocked hosts is by comparing the requested host with the list of hosts in your hosts file that are blocked. The host requested is in the &lt;code&gt;$_SERVER['SERVER_NAME']&lt;/code&gt; variable. Since the list of blocked hosts is large and you probably do not want to read all of those with your php script each time an advertisement is blocked, you can apply the reverse comparison - if the requested host is not in the list of your valid hosts, then it is a blocked host. An example:
&lt;pre name="code" class="php"&gt;
// our valid hosts
$valid_hosts = array('localhost', 'my.host.joe', 'my.other.host.peter');
// check if the requested host is a valid one
if (!in_array($_SERVER['SERVER_NAME'], $valid_hosts)) {
    echo 'ad or malware blocked'; // display message in place of blocked ad
} else {
    include('/404.html'); // display regular 404 page
}
&lt;/pre&gt;
Now, when you visit those websites with pesky advertisements and popups, you get a neat little line saying "ad or malware blocked" in the place of those ads.
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hXgxP/~4/zRbjmkmjDMA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://onwebdevelopment.blogspot.com/feeds/3738964601070194706/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3347571992315805758&amp;postID=3738964601070194706" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/3738964601070194706?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/3738964601070194706?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hXgxP/~3/zRbjmkmjDMA/blocking-advertisements-with-hosts-file.html" title="Blocking Advertisements with a Hosts file, Apache  and PHP" /><author><name>Gabe LG</name><uri>https://plus.google.com/107192546834216117000</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-St_WHaLi-Yg/AAAAAAAAAAI/AAAAAAAAB6M/EQ_v8i-FgXg/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://onwebdevelopment.blogspot.com/2008/06/blocking-advertisements-with-hosts-file.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEcDQnY8fip7ImA9WxdRFk8.&quot;"><id>tag:blogger.com,1999:blog-3347571992315805758.post-6337871134585236947</id><published>2008-06-05T12:19:00.007+12:00</published><updated>2008-06-05T12:34:33.876+12:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-06-05T12:34:33.876+12:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="timezone" /><category scheme="http://www.blogger.com/atom/ns#" term="PHP" /><category scheme="http://www.blogger.com/atom/ns#" term="mysql" /><category scheme="http://www.blogger.com/atom/ns#" term="date" /><title>Synchronizing Date and Time in different Timezones with PHP, MySQL and JavaScript</title><content type="html">&lt;p&gt;
How do you show the correct date and time (timestamp) to users in differnet time zones? In theory it should be simple:
&lt;ul&gt;
&lt;li&gt;&lt;a href="#save_timestamp"&gt;Save your your date and time with the correct timezone&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#retrieve_timezone"&gt;Retrieve the timezone of the user to whom you will display the date and time to&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#calc_tz_diff"&gt;Calculate the difference in hours between the saved date and time and the users date and time&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#add_tz_diff"&gt;Add the difference in hours to the saved date and time and display&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;


&lt;h3&gt;&lt;a name="save_timestamp"&gt;Save your your date and time with the correct timezone&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;
The date and time with timezone is a &lt;a href="http://en.wikipedia.org/wiki/Timestamp"&gt;timestamp&lt;/a&gt;. Though implementations differ, timestamps basically contain the same information (date/time and timezone).The timezone can be explicitly recorded in the timestamp (eg: 2005-10-30 T 10:45 UTC) or implicitly taken from the context in which the timestamp was generated or recorded (eg: unix timestamp is dependent on timezone of server generating the timestamp). 
&lt;/p&gt;
&lt;p&gt;
Something as simple as saving a timestamp in mysql with PHP can be not so simple due to the difference in the timestamp representation in the two languages.
&lt;/p&gt;
&lt;p&gt;
The &lt;a href="http://www.php.net/time"&gt;PHP timestamp&lt;/a&gt; is defined as the number of seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) while the &lt;a href="http://dev.mysql.com/doc/refman/5.0/en/timestamp.html"&gt;mysql timestamp&lt;/a&gt; is a representation of the present date and time in the format YYYY-MM-DD HH:MM:SS.
&lt;/p&gt;
&lt;p&gt;
If you save the timestamp as a mysql timestamp field, then the timestamp is saved as UTC, however, when you access the timestamp it is converted to the timezone set in the mysql server, so basically you don't get to see the stored UTC version of the timestamp. If you save it as a PHP timestamp in a varchar or unsigned int field then it would be subject to the the PHP servers timezone. So in essence both the MySQL and PHP timestamp a dependent on the timezone of their respective servers. 
&lt;/p&gt;
&lt;p&gt;
Whichever format you save it in, just remember that both the PHP and MySQL timestamps reference the timezone on the server they are saved on, PHP during generation of the timestamp, and mysql during retrieval. 
&lt;/p&gt;


&lt;h3&gt;&lt;a name="retrieve_timezone"&gt;Retrieve the timezone of the user to whom you will display the date and time to&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;
The easy way to do this is ask the user what their timezone is. You see this used in many registration forms on websites as well as many open source forums, CMSs, blog software etc. However, not every user will even bother giving you the correct timezone. 
&lt;/p&gt;
&lt;p&gt;
You can use JavaScript if it is available on the browser:
&lt;pre name="code" class="javascript"&gt;
var tz = (new Date().getTimezoneOffset()/60)*(-1);
&lt;/pre&gt;
This depends on the users computer's clock, so if it is set wrong, then you will get a wrong result. Time is relative however, so if a user wants to be a few hours behind, let them be.
&lt;/p&gt;
&lt;p&gt;
You can use the users IP address to assume their geographic location and thus their timezone. This can be done server side and thus is not dependent on the users browser having JavaScript. Using the IP to determine timezone is dependent on the accuracy of your IP geocoding service you use. Here is an example using the hostip.info API for geocoding and earthtools.org for lat/long conversion to timezone. 
&lt;pre name="code" class="php"&gt;
&amp;lt;?php
/**
* Retrieves the Timezone by the IP address
* @param String $IP (optional) IP address or remote client IP address is used
*/
function getTimeZoneByIP($IP = false) {

 // timezone
 $timezone = false;

 // users IP
 $IP = $IP ? $IP : $_SERVER['REMOTE_ADDR'];

 // retrieve geocoded data from http://hostip.info/ API in plain text
 if ($geodata = file('http://api.hostip.info/get_html.php?ip='.$IP.'&amp;amp;position=true')) {
  // create an associative array from the data
  $geoarr = array();
  foreach($geodata as $line) {
   list($name, $value) = explode(': ', $line);
   $geoarr[$name] = $value;
  }
  
  // retrieve lat and lon values
  $lat = trim($geoarr['Latitude']);
  $lon = trim($geoarr['Longitude']);
  
  if (strlen($lat) &amp;gt; 0 &amp;amp;&amp;amp; strlen($lon) &amp;gt; 0) {
   // pass this lat and long to http://www.earthtools.org/ API to get Timezone Offset in xml
   $tz_xml = file_get_contents('http://www.earthtools.org/timezone-1.1/'.$lat.'/'.$lon);
   // lets parse out the timezone offset from the xml using regex
   if (preg_match("/&amp;lt;offset&amp;gt;([^&amp;lt;]+)&amp;lt;\/offset&amp;gt;/i", $tz_xml, $match)) {
    $timezone = $match[1];
   }
  }

 }
 return $timezone;
}
?&amp;gt;
&lt;/pre&gt;
&lt;/p&gt;
&lt;p&gt;
You can also use a combination of the three in order to correlate the data and get a better guess of the timezone. 
&lt;/p&gt;

&lt;h3&gt;&lt;a  name="calc_tz_diff"&gt;Calculate the difference in hours between the saved date and time and the users date and time&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;
Now that we have the timestamp and the users timezone, we just need to adjust the timestamp to their timezone. First we need to calculate the difference between the timezone the timestamp is saved in, as the users timezone. 
&lt;pre&gt;
$user_tz_offset = $tz_user - $tz_timestamp; 
&lt;/pre&gt;
where $user_tz_offset is how far ahead or behind in hours the user timezone is from the timestamps timezone.
&lt;/p&gt;

&lt;h3&gt;&lt;a  name="add_tz_diff"&gt;Add the difference in hours to the saved date and time and display&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;
Now we have all we need to show the correct time to the user based on their timezone. Example in pseudo code:
&lt;pre&gt;
$user_tz_offset = $tz_user - $tz_timestamp; 
$users_timestamp = $timestamp + $user_tz_offset;
&lt;/pre&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hXgxP/~4/7_Rxpb9JOrg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://onwebdevelopment.blogspot.com/feeds/6337871134585236947/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3347571992315805758&amp;postID=6337871134585236947" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/6337871134585236947?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/6337871134585236947?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hXgxP/~3/7_Rxpb9JOrg/synchronizing-date-and-time-in.html" title="Synchronizing Date and Time in different Timezones with PHP, MySQL and JavaScript" /><author><name>Gabe LG</name><uri>https://plus.google.com/107192546834216117000</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-St_WHaLi-Yg/AAAAAAAAAAI/AAAAAAAAB6M/EQ_v8i-FgXg/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://onwebdevelopment.blogspot.com/2008/06/synchronizing-date-and-time-in.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0YERn8_fCp7ImA9WxdRFUk.&quot;"><id>tag:blogger.com,1999:blog-3347571992315805758.post-6301796910941321587</id><published>2008-06-04T12:18:00.006+12:00</published><updated>2008-06-04T12:58:27.144+12:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-06-04T12:58:27.144+12:00</app:edited><title>PHP Code Performance Profiling on Ubuntu</title><content type="html">&lt;p&gt;
A few options for code profiling in PHP:
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://xdebug.derickrethans.nl/"&gt;XDebug&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pear.php.net/benchmark"&gt;Benchmark&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://dd.cron.ru/dbg"&gt;DPG&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pear.php.net/apd"&gt;Advanced PHP Debugger&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;

&lt;h3&gt;XDebug&lt;/h3&gt;
&lt;p&gt;
XDebug consists of a PHP extension, and requires an XDebug client to view the output generated by XDebug. It writes profiling data by default to /tmp. What we want to do is install XDebug, enable profiling and view the files generated using Kcachegrind, which is an XDebug client that comes default with Ubuntu. 
&lt;/p&gt;
&lt;p&gt;
To install XDebug on Ubuntu is as simple as the command:

&lt;pre&gt;
sudo apt-get install php5-xdebug
&lt;/pre&gt;

This assumes you installed Apache2 and PHP5 using aptitude. Otherwise you'd probably want to follow one of these instructions on installing XDebug:&lt;br /&gt;
&lt;a href="http://ubuntuforums.org/showthread.php?t=525257"&gt;http://ubuntuforums.org/showthread.php?t=525257&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://2bits.com/articles/setting-up-xdebug-dbgp-for-php-on-debian-ubuntu.html"&gt;http://2bits.com/articles/setting-up-xdebug-dbgp-for-php-on-debian-ubuntu.html&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://www.apaddedcell.com/easy-php-debugging-ubuntu-using-xdebug-and-vim"&gt;http://www.apaddedcell.com/easy-php-debugging-ubuntu-using-xdebug-and-vim&lt;/a&gt;&lt;br /&gt;
&lt;/p&gt;

&lt;p&gt;
Once you've installed xdebug you will need to enable php code profiling by setting the &lt;a href="http://www.xdebug.org/docs/profiler"&gt;xdebug.profiler_enable setting to 1 in php.ini&lt;/a&gt;. You can view the php.ini settings using the command:
&lt;pre&gt;
php -r 'phpinfo();'
&lt;/pre&gt;
To narrow down to just the xdebug settings use:
&lt;pre&gt;
php -r 'phpinfo();' | grep xdebug
&lt;/pre&gt;
Note: &lt;code&gt;php --info | xdebug&lt;/code&gt; will work also.
&lt;/p&gt;

&lt;p&gt;
If you used the simple &lt;code&gt;sudo apt-get install php5-xdebug&lt;/code&gt; to install xdebug, then it should have automatically created an ini file: &lt;code&gt; /etc/php5/conf.d/xdebug.ini&lt;/code&gt; which is included with the php.ini. 
&lt;/p&gt;

&lt;p&gt;
Edit the php.ini file or &lt;code&gt; /etc/php5/conf.d/xdebug.ini&lt;/code&gt; and add the line:
&lt;pre&gt;
xdebug.profiler_enable=1
&lt;/pre&gt;
Example: &lt;code&gt;sudo gedit /etc/php5/conf.d/xdebug.ini&lt;/code&gt;
&lt;/p&gt;
&lt;p&gt;
After saving this you will need to restart Apache in order to reload the php settings.
&lt;pre&gt;sudo /etc/init.d/apache2 restart&lt;/pre&gt;
&lt;/p&gt;

&lt;p&gt;

You will then need an xdebug client to display the profiling information. &lt;a href="http://kcachegrind.sf.net/"&gt;Kcachegrind&lt;/a&gt; is installed by default in Ubuntu. Open Kcachegrind &lt;code&gt;kcachegrind &amp;&lt;/code&gt; and use it to open a file generated by xdebug. This will be found in the directory specified in php.ini for the directive &lt;code&gt;xdebug.trace_output_dir&lt;/code&gt; which defaults to &lt;code&gt;/tmp&lt;/code&gt;. The files generated by Xdebug are prefixed with &lt;code&gt;cachegrind.out.&lt;/code&gt;. So you can view a list of these files using the command &lt;code&gt;ls /tmp | grep cachegrind.out.&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;
How to interpret the Xdebug profiling information displayed in Kcachegrind is described at: &lt;a href="http://www.xdebug.org/docs/profiler"&gt;http://www.xdebug.org/docs/profiler&lt;/a&gt; under Analysing Profiles.
&lt;/p&gt;

&lt;h3&gt;Benchmark&lt;/h3&gt;
&lt;p&gt;
Benchmark is a Pear package. Documentation is found at: &lt;a href="http://pear.php.net/package/Benchmark/docs/latest/Benchmark/Benchmark_Profiler.html"&gt;http://pear.php.net/package/Benchmark/docs/latest/Benchmark/Benchmark_Profiler.html&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
A simple usage would be:
&lt;pre name="code" class="php"&gt;
// load class and instantiate and instance
require_once 'Benchmark/Profiler.php';
$profiler = new Benchmark_Profiler();

// start profiling
$profiler-&gt;start();

// do some stuff
myFunction();

// stop
$profiler-&gt;stop();

// display directly in PHP output
$profiler-&gt;display();

&lt;/pre&gt;
myFunction could look something like:

&lt;pre name="code" class="php"&gt;
function myFunction() {
     global $profiler;

     $profiler-&gt;enterSection('myFunction');

     //do something
     $profiler-&gt;leaveSection('myFunction');

     return;
 }
&lt;/pre&gt;
&lt;/p&gt;
&lt;p&gt;
Benchmark allows you to do profiling directly in your PHP script. One of the disadvantages of XDebug is that you have to enable profiling in PHP.ini and it would start creating profiling dump files in /tmp. These files over time could get very large if you forget to turn off XDebug. Unfortunately you can't set the XDebug profiling directive, &lt;code&gt;xdebug.profiler_enable&lt;/code&gt; directly in PHP with ini_set().  
&lt;/p&gt;
&lt;p&gt;
Benchmark would seem like a bit more work compared to XDebug, however, if working with large code bases. The advantage of being able to apply it to a single file however makes it ideal for profiling live php websites. You could easily track down a problem occuring on a live site without having to recreate and &lt;a href="http://tsung.erlang-projects.org/"&gt;simulate the live site and data in a development environment&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;
For example you could have Benchmark only display profiling data if requested via the URL:

&lt;pre name="code" class="php"&gt;
// load class and instantiate and instance
require_once 'Benchmark/Profiler.php';
$profiler = new Benchmark_Profiler();

// start profiling
$profiler-&gt;start();

// do some stuff
myFunction();

// stop
$profiler-&gt;stop();

// only display if requested by me
if (isset($_GET['debug'])) $profiler-&gt;display();

&lt;/pre&gt;

&lt;/p&gt;


&lt;p&gt;
I haven't got around to the other two alternatives for PHP code profiling. I will update this entry if I do. 
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hXgxP/~4/I8re9OE7qGY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://onwebdevelopment.blogspot.com/feeds/6301796910941321587/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3347571992315805758&amp;postID=6301796910941321587" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/6301796910941321587?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/6301796910941321587?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hXgxP/~3/I8re9OE7qGY/php-code-performance-profiling-on.html" title="PHP Code Performance Profiling on Ubuntu" /><author><name>Gabe LG</name><uri>https://plus.google.com/107192546834216117000</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-St_WHaLi-Yg/AAAAAAAAAAI/AAAAAAAAB6M/EQ_v8i-FgXg/s512-c/photo.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://onwebdevelopment.blogspot.com/2008/06/php-code-performance-profiling-on.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak8ERX85fip7ImA9WxdRFEw.&quot;"><id>tag:blogger.com,1999:blog-3347571992315805758.post-8571895851909234462</id><published>2008-06-03T02:27:00.005+12:00</published><updated>2008-06-03T03:00:04.126+12:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-06-03T03:00:04.126+12:00</app:edited><title>Ringo Ends Service</title><content type="html">&lt;p&gt;
It looks like &lt;a href="http://ringo.com/" target="_blank"&gt;Ringo&lt;/a&gt;, which is a popular social network, has decided to end its service. Here is part of the email I received 2 hours ago.
&lt;/p&gt;
&lt;p&gt;
&lt;pre&gt;
Dear Ringo member,

After much consideration we have decided to end the Ringo service.

As of June 30, 2008 the Ringo service is ending and you will no longer have access to your Ringo account. 
&lt;/pre&gt;

&lt;/p&gt;

&lt;p&gt;
Twitter is faster at getting updated with news like this. A search through google won't reveal any news of this since it is only 2 or so hours old, however, a search through twitter got quite a lot of results. &lt;a href="http://twittier.com/?q=ringo" target="_blank"&gt;http://twittier.com/?q=ringo&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
The originating server of the email seems to check out. It originates from the tickle.com which is authoritative for ringo's mail transfer. (I consider all email guilty until proven innocent)
&lt;/p&gt;

&lt;p&gt;
Is this the &lt;a href="http://jennifered.tumblr.com/post/36888495/ringo-says-buh-bye"&gt;first death of a social network&lt;/a&gt;? I believe so, at least a major one. 
&lt;/p&gt;

&lt;p&gt;
It appears ringo.com hasn't been growing at all for the past year, if not slowly dying. 
&lt;img src="http://grapher.compete.com/ringo.com+twitter.com+bebo.com_uv.png" border="0" /&gt;
&lt;/p&gt;

&lt;p&gt;
Farewell Ringo.
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hXgxP/~4/4HoMxjFn8_Q" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://onwebdevelopment.blogspot.com/feeds/8571895851909234462/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3347571992315805758&amp;postID=8571895851909234462" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/8571895851909234462?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/8571895851909234462?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hXgxP/~3/4HoMxjFn8_Q/ringo-ends-service.html" title="Ringo Ends Service" /><author><name>Gabe LG</name><uri>https://plus.google.com/107192546834216117000</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-St_WHaLi-Yg/AAAAAAAAAAI/AAAAAAAAB6M/EQ_v8i-FgXg/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://onwebdevelopment.blogspot.com/2008/06/ringo-ends-service.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0MCSH84eyp7ImA9WxdbF08.&quot;"><id>tag:blogger.com,1999:blog-3347571992315805758.post-1874923804832792957</id><published>2008-05-26T06:17:00.029+12:00</published><updated>2008-08-15T02:51:09.133+12:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-08-15T02:51:09.133+12:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="JSON" /><category scheme="http://www.blogger.com/atom/ns#" term="DOM" /><category scheme="http://www.blogger.com/atom/ns#" term="standards" /><category scheme="http://www.blogger.com/atom/ns#" term="XML" /><title>Converting XML to JSON</title><content type="html">&lt;p&gt;
Why would I want to convert XML to JSON. Mainly because JSON is a subset of JavaScript (JavaScript Object Notation) and XML isn't. It is much easier to manipulate JavaScript Objects, then it is to manipulate XML. This is because Objects are native to JavaScript, where as XML requires an API, the DOM, which is harder to use. DOM implementations in browsers are not consistent, while you will find Objects and their methods more or less the same across browsers. 
&lt;/p&gt;

&lt;p&gt;
Since, most of the content/data available on the web is in XML format and not JSON, converting XML to JSON is necessary. 
&lt;/p&gt;

&lt;p&gt;
The main problem is that there is no standard way of converting XML to JSON. So when converting, we have to develop our own rules, or base them on the most widely used conversion rules. Lets see how the big boys do it.
&lt;/p&gt;

&lt;h3&gt;Rules Google GData Uses to convert XML to JSON&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;A GData service creates a JSON-format feed by converting the XML feed, using the following rules:&lt;/p&gt;
    &lt;p&gt;&lt;strong&gt;Basic&lt;/strong&gt;&lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt; The feed is represented as a JSON object; each nested element 
        or attribute is represented as a name/value property of the object.&lt;/li&gt;

      &lt;li&gt;Attributes are converted to String properties.&lt;/li&gt;
      &lt;li&gt; Child elements are converted to Object properties.&lt;/li&gt;
      &lt;li&gt;Elements that may appear more than once are converted to Array properties.&lt;/li&gt;
      &lt;li&gt;Text values of tags are converted to &lt;code&gt;$t&lt;/code&gt; properties.&lt;/li&gt;

    &lt;/ul&gt;
    &lt;p&gt;&lt;strong&gt;Namespace&lt;/strong&gt;&lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt;If an element has a namespace alias, the alias and element are concatenated 
        using "$". For example, &lt;code&gt;ns:element&lt;/code&gt; becomes &lt;code&gt;ns$element&lt;/code&gt;.&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;&lt;strong&gt;XML&lt;/strong&gt;&lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt; XML version and encoding attributes are converted to attribute version 
        and encoding of the root element, respectively.&lt;/li&gt;
    &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h3&gt;Google GData XML to JSON example&lt;/h3&gt;
&lt;p&gt;This is a hypothetical example, Google GData only deals with RSS and ATOM feeds.&lt;/p&gt;
&lt;pre rel="xml" name="code" class="xml"&gt;
&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;
&amp;lt;example:user domain="example.com"&amp;gt;
 &amp;lt;name&amp;gt;Joe&amp;lt;/name&amp;gt;
 &amp;lt;status online="true"&amp;gt;Away&amp;lt;/status&amp;gt;
 &amp;lt;idle /&amp;gt;
&amp;lt;/example:user&amp;gt;
&lt;/pre&gt;
&lt;pre rel="json" name="code" class="javascript"&gt;
{
 "version": "1.0",
 "encoding": "UTF-8",
 "example$user" : {
  "domain" : "example.com",
   "name" : { "$t" : "Joe" },
   "status" : {
    "online" : "true",
    "$t" : "Away"
   },
   "idle" : null
  }
}
&lt;/pre&gt;
&lt;p&gt;
How Google converts XML to JSON is well documented. The main points being that XML node attributes become strings properties, the node data or text becomes &lt;code&gt;$t&lt;/code&gt; properties and namespaces are concatenated with &lt;code&gt;$&lt;/code&gt;.&lt;br /&gt;
&lt;a href="http://code.google.com/apis/gdata/json.html#Background" target="_blank"&gt;http://code.google.com/apis/gdata/json.html#Background&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;Rules Yahoo Uses to convert XML to JSON&lt;/h3&gt;
&lt;p&gt;
I could not find any documentation on the rules Yahoo uses to convert its XML to JSON in Yahoo Pipes, however, by looking the output of a pipe in RSS format and the corresponding JSON format you can get an idea of the rules used. 
&lt;/p&gt;
    &lt;p&gt;&lt;strong&gt;Basic&lt;/strong&gt;&lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt; The feed is represented as a JSON object; each nested element 
        or attribute is represented as a name/value property of the object.&lt;/li&gt;

      &lt;li&gt;Attributes are converted to String properties.&lt;/li&gt;
      &lt;li&gt; Child elements are converted to Object properties.&lt;/li&gt;
      &lt;li&gt;Elements that may appear more than once are converted to Array properties.&lt;/li&gt;
      &lt;li&gt; Text values of tags are converted to string properties of the parent node, if the node has no attributes.&lt;/li&gt;
      &lt;li&gt; Text values of tags are converted to &lt;code&gt;content&lt;/code&gt; properties, if the node has attributes.&lt;/li&gt;

    &lt;/ul&gt;
    &lt;p&gt;&lt;strong&gt;Namespace&lt;/strong&gt;&lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt;Unknown.&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;&lt;strong&gt;XML&lt;/strong&gt;&lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt; XML version and encoding attributes are removed/ignored - at least in the RSS sample I looked at.&lt;/li&gt;
    &lt;/ul&gt;
&lt;p&gt;
The only problem I see with the rules Yahoo Pipes uses is that if an XML node has an attribute named "content", then it will conflict with the Text value of the node/element giving the programer an unexpected result.
&lt;/p&gt;
&lt;h3&gt;Yahoo Pipes XML to JSON example&lt;/h3&gt;
&lt;pre rel="xml" name="code" class="xml"&gt;
&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;
&amp;lt;example:user domain="example.com"&amp;gt;
 &amp;lt;name&amp;gt;Joe&amp;lt;/name&amp;gt;
 &amp;lt;status online="true"&amp;gt;Away&amp;lt;/status&amp;gt;
 &amp;lt;idle /&amp;gt;
&amp;lt;/example:user&amp;gt;
&lt;/pre&gt;
&lt;pre rel="json" name="code" class="javascript"&gt;
{
 "example??user" : {
  "domain" : "example.com",
   "name" : "Joe",
   "status" : {
    "online" : "true",
    "content" : "Away",
   },
   "idle" : ??
  }
}
&lt;/pre&gt;

&lt;h3&gt;XML.com on rules to convert XML to JSON&lt;/h3&gt;
&lt;p&gt;
The article on XML.com by Stefan Goessner gives a list of possible XML element structures and the corresponding JSON Objects.&lt;br /&gt;
&lt;a href="http://www.xml.com/pub/a/2006/05/31/converting-between-xml-and-json.html" target="_blank"&gt;http://www.xml.com/pub/a/2006/05/31/converting-between-xml-and-json.html&lt;/a&gt;
&lt;/p&gt;
&lt;blockquote&gt;
&lt;table&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td bgcolor="#cccccc"&gt;&lt;strong&gt;Pattern&lt;/strong&gt;
&lt;/td&gt;
&lt;td bgcolor="#f0f0f0"&gt;&lt;strong&gt;XML&lt;/strong&gt;
&lt;/td&gt;
&lt;td bgcolor="#cccccc"&gt;&lt;strong&gt;JSON&lt;/strong&gt;
&lt;/td&gt;
&lt;td bgcolor="#f0f0f0"&gt;&lt;strong&gt;Access&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;

&lt;td bgcolor="#cccccc"&gt;1&lt;/td&gt;
&lt;td bgcolor="#f0f0f0"&gt;
&lt;code&gt;&amp;lt;e/&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td bgcolor="#cccccc"&gt;
&lt;code&gt;"e": null&lt;/code&gt;
&lt;/td&gt;
&lt;td bgcolor="#f0f0f0"&gt;
&lt;code&gt;o.e&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;

&lt;td bgcolor="#cccccc"&gt;2&lt;/td&gt;
&lt;td bgcolor="#f0f0f0"&gt;
&lt;code&gt;&amp;lt;e&amp;gt;text&amp;lt;/e&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td bgcolor="#cccccc"&gt;
&lt;code&gt;"e": "text"&lt;/code&gt;
&lt;/td&gt;
&lt;td bgcolor="#f0f0f0"&gt;
&lt;code&gt;o.e&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td bgcolor="#cccccc"&gt;3&lt;/td&gt;
&lt;td bgcolor="#f0f0f0"&gt;
&lt;code&gt;&amp;lt;e name="value" /&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td bgcolor="#cccccc"&gt;
&lt;code&gt;"e":{"@name": "value"}&lt;/code&gt;
&lt;/td&gt;
&lt;td bgcolor="#f0f0f0"&gt;
&lt;code&gt;o.e["@name"]&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td bgcolor="#cccccc"&gt;4&lt;/td&gt;
&lt;td bgcolor="#f0f0f0"&gt;
&lt;code&gt;&amp;lt;e name="value"&amp;gt;text&amp;lt;/e&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td bgcolor="#cccccc"&gt;
&lt;code&gt;"e": {
  "@name": "value",
  "#text": "text"
}&lt;/code&gt;
&lt;/td&gt;
&lt;td bgcolor="#f0f0f0"&gt;
&lt;code&gt;o.e["@name"]
o.e["#text"]&lt;/code&gt;

&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td bgcolor="#cccccc"&gt;5&lt;/td&gt;
&lt;td bgcolor="#f0f0f0"&gt;
&lt;code&gt;&amp;lt;e&amp;gt;
  &amp;lt;a&amp;gt;text&amp;lt;/a&amp;gt;
  &amp;lt;b&amp;gt;text&amp;lt;/b&amp;gt;

&amp;lt;/e&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td bgcolor="#cccccc"&gt;
&lt;code&gt;"e": { 
  "a": "text",
  "b": "text"
}&lt;/code&gt;
&lt;/td&gt;
&lt;td bgcolor="#f0f0f0"&gt;
&lt;code&gt;o.e.a
o.e.b&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td bgcolor="#cccccc"&gt;6&lt;/td&gt;
&lt;td bgcolor="#f0f0f0"&gt;

&lt;code&gt;&amp;lt;e&amp;gt;
  &amp;lt;a&amp;gt;text&amp;lt;/a&amp;gt;
  &amp;lt;a&amp;gt;text&amp;lt;/a&amp;gt;
&amp;lt;/e&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td bgcolor="#cccccc"&gt;
&lt;code&gt;"e": {
  "a": ["text", "text"]
}&lt;/code&gt;

&lt;/td&gt;
&lt;td bgcolor="#f0f0f0"&gt;
&lt;code&gt;o.e.a[0]
o.e.a[1]&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td bgcolor="#cccccc"&gt;7&lt;/td&gt;
&lt;td bgcolor="#f0f0f0"&gt;
&lt;code&gt;&amp;lt;e&amp;gt;
  text
  &amp;lt;a&amp;gt;text&amp;lt;/a&amp;gt;

&amp;lt;/e&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td bgcolor="#cccccc"&gt;
&lt;code&gt;"e": {
  "#text": "text",
  "a": "text"
}&lt;/code&gt;
&lt;/td&gt;
&lt;td bgcolor="#f0f0f0"&gt;
&lt;code&gt;o.e["#text"]
o.e.a&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/blockquote&gt;

&lt;p&gt;
If we translate this to the rules format given by Google it would look something like:
&lt;/p&gt;
    &lt;p&gt;&lt;strong&gt;Basic&lt;/strong&gt;&lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt; The feed is represented as a JSON object; each nested element 
        or attribute is represented as a name/value property of the object.&lt;/li&gt;

      &lt;li&gt;Attributes are converted to &lt;code&gt;@attribute&lt;/code&gt; properties. (attribute name preceeded by @)&lt;/li&gt;
      &lt;li&gt;Child elements are converted to Object properties, if the node has attributes or child nodes.&lt;/li&gt;
      &lt;li&gt;Elements that may appear more than once are converted to Array properties.&lt;/li&gt;
      &lt;li&gt;Text values of tags are converted to string properties of the parent node, if the node has no attributes or child nodes.&lt;/li&gt;
      &lt;li&gt;Text values of tags are converted to &lt;code&gt;#text&lt;/code&gt; properties, if the node has attributes or child nodes.&lt;/li&gt;

    &lt;/ul&gt;
    &lt;p&gt;&lt;strong&gt;Namespace&lt;/strong&gt;&lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt;If an element has a namespace alias, the alias and element are concatenated 
        using ":". For example, &lt;code&gt;ns:element&lt;/code&gt; becomes &lt;code&gt;ns:element&lt;/code&gt;. (ie: namespaced elements are treated as any other element)&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;&lt;strong&gt;XML&lt;/strong&gt;&lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt;XML version and encoding attributes are not converted.&lt;/li&gt;
    &lt;/ul&gt;
&lt;h3&gt;XML.com XML to JSON example&lt;/h3&gt;
&lt;pre rel="xml" name="code" class="xml"&gt;
&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;
&amp;lt;example:user domain="example.com"&amp;gt;
 &amp;lt;name&amp;gt;Joe&amp;lt;/name&amp;gt;
 &amp;lt;status online="true"&amp;gt;Away&amp;lt;/status&amp;gt;
 &amp;lt;idle /&amp;gt;
&amp;lt;/example:user&amp;gt;
&lt;/pre&gt;
&lt;pre rel="json" name="code" class="javascript"&gt;
{
 "example:user" : {
  "@attributes" : { "domain" : "example.com" },
   "name" : { "#text" : "Joe" },
   "status" : {
    "@attributes" : {"online" : "true"},
    "#text" : "Away"
   },
   "idle" : null
 }
}
&lt;/pre&gt;

&lt;h3&gt;Other rules being used to convert XML to JSON&lt;/h3&gt;
&lt;p&gt;
Here is a blog on the topic of an XML to JSON standard. &lt;a href="http://khanderaotech.blogspot.com/2007/03/mapping-between-xml-json-need-standard.html"&gt;http://khanderaotech.blogspot.com/2007/03/mapping-between-xml-json-need-standard.html&lt;/a&gt;. &lt;br /&gt;
A good discussion on the differences between XML and JSON. &lt;a href="http://blog.jclark.com/2007/04/xml-and-json.html"&gt;http://blog.jclark.com/2007/04/xml-and-json.html&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;We need a standard way of converting XML to JSON&lt;/h3&gt;
&lt;p&gt;
I'm tired of hearing the "XML vs JSON" debate. Why not just make them compatible. Now, that we see just how many different rules are being used, we can definitely see another reason why a standard would come in handy. But till then, I think I'll add to the confusion and come up with my own ruleset. 
&lt;/p&gt;

&lt;h3&gt;My rules of converting XML to JSON&lt;/h3&gt;
&lt;p&gt;
My rules are simple and is based on the XML DOM. The DOM represents XML as DOM Objects and Methods. We will use the DOM objects only since JSON does not use methods. So each Element would be an Object, and each text node &lt;code&gt;#text&lt;/code&gt; property and attributes an &lt;code&gt;@attributes&lt;/code&gt; object with string properties of the attribute names. The only difference from the DOM Objects representation in JavaScript is the &lt;code&gt;@&lt;/code&gt; sign in front of the attributes Object name - this is to to avoid conflicts with elements named "attributes". The DOM goes around this by having public methods to select child nodes, and not public properties (the actual properties are private, and thus not available in an object notation). 
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Basic&lt;/strong&gt;&lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt; The feed is represented as a JSON object; each nested element 
        or attribute is represented as a name/value property of the object.&lt;/li&gt;

      &lt;li&gt;Attributes are converted to String properties of the &lt;code&gt;@attributes&lt;/code&gt; property.&lt;/li&gt;
      &lt;li&gt; Child elements are converted to Object properties.&lt;/li&gt;
      &lt;li&gt;Elements that may appear more than once are converted to Array properties.&lt;/li&gt;
      &lt;li&gt;Text values of tags are converted to &lt;code&gt;$text&lt;/code&gt; properties.&lt;/li&gt;

    &lt;/ul&gt;
    &lt;p&gt;&lt;strong&gt;Namespace&lt;/strong&gt;&lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt;Treat as any other element.&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;&lt;strong&gt;XML&lt;/strong&gt;&lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt; XML version and encoding attributes are not converted. &lt;/li&gt;
    &lt;/ul&gt;

&lt;p&gt;
In order to convert XML to JSON with JavaScript, you first have to convert the XML to a DOM Document (to make things simpler). Any major browser willd do this either automatically in the case of the XML/XHTML Document you are viewing, or an XML document retrieved via XMLHttpRequest. But if all you have is an XML string, something like this will do: 
&lt;p&gt;

&lt;pre rel="javascript" name="code" class="javascript"&gt;
function TextToXML(strXML) {
 var xmlDoc = null;
 try {
  xmlDoc = (document.all)?new ActiveXObject("Microsoft.XMLDOM"):new DOMParser();
  xmlDoc.async = false;
 } catch(e) {throw new Error("XML Parser could not be instantiated");}
 var out;
 try {
  if(document.all) {
   out = (xmlDoc.loadXML(strXML))?xmlDoc:false;
  } else {  
   out = xmlDoc.parseFromString(strXML, "text/xml");
  }
 } catch(e) { throw new Error("Error parsing XML string"); }
 return out;
} 
&lt;/pre&gt;

&lt;p&gt;
This will give you the XML represented as a DOM Document, which you can traverse using the &lt;a href="http://www.howtocreate.co.uk/tutorials/javascript/domstructure" target="_blank"&gt;DOM methods&lt;/a&gt;. 
&lt;/p&gt;

&lt;p&gt;
Now all you'll have to do to convert the DOM Document to JSON is traverse it, and for every Element, create an Object, for its attributes create an &lt;code&gt;@attributes&lt;/code&gt; Object, and a &lt;code&gt;#text&lt;/code&gt; attribute for text nodes and repeat the process for any child elements. 
&lt;/p&gt;

&lt;pre name="code" class="javascript"&gt;
/**
 * Convert XML to JSON Object
 * @param {Object} XML DOM Document
 */
xml2Json = function(xml) {
 var obj = {};
 
 if (xml.nodeType == 1) { // element
  // do attributes
  if (xml.attributes.length &gt; 0) {
   obj['@attributes'] = {};
   for (var j = 0; j &amp;lt; xml.attributes.length; j++) {
    obj['@attributes'][xml.attributes[j].nodeName] = xml.attributes[j].nodeValue;
   }
  }
  
 } else if (xml.nodeType == 3) { // text
  obj = xml.nodeValue;
 }
 
 // do children
 if (xml.hasChildNodes()) {
  for(var i = 0; i &amp;lt; xml.childNodes.length; i++) {
   if (typeof(obj[xml.childNodes[i].nodeName]) == 'undefined') {
    obj[xml.childNodes[i].nodeName] = xml2Json(xml.childNodes[i]);
   } else {
    if (typeof(obj[xml.childNodes[i].nodeName].length) == 'undefined') {
     var old = obj[xml.childNodes[i].nodeName];
     obj[xml.childNodes[i].nodeName] = [];
     obj[xml.childNodes[i].nodeName].push(old);
    }
    obj[xml.childNodes[i].nodeName].push(xml2Json(xml.childNodes[i]));
   }
   
  }
 }

 return obj;
};
&lt;/pre&gt;

&lt;h3&gt;Converting XML to Lean JSON?&lt;/h3&gt;
&lt;p&gt;
We could make the JSON encoding of the XML lean by using just "@" for attributes and "#" for text in place of "@attributes" and "#text":
&lt;/p&gt;
&lt;pre rel="json" name="code" class="javascript"&gt;
{
 "example:user" : {
  "@" : { "domain" : "example.com" },
   "name" : { "#" : "Joe" },
   "status" : {
    "@" : {"online" : "true"},
    "#" : "Away"
   },
   "idle" : null
 }
}
&lt;/pre&gt;

&lt;p&gt;
You may notice that "@" and "#" are valid as javascript property names, but not as XML attribute names. This allows us to encompass the DOM representation in object notation, since we are swapping DOM functions for Object properties that are not allowed as XML attributes and thus will not get any collisions. We could go further and use "!" for comments for example, and "%" for CDATA. I'm leaving these two out for simplicity.
&lt;/p&gt;

&lt;h3&gt;What about converting JSON to XML?&lt;/h3&gt;
&lt;p&gt;
If we follow the rules used to convert XML to JSON, it should be easy to convert JSON back to XML. We'd Just need to recurse through our JSON Object, and create the necessary XML objects using the DOM methods.
&lt;/p&gt;

&lt;pre name="code" class="javascript"&gt;
/**
 * JSON to XML
 * @param {Object} JSON
 */
json2Xml = function(json, node) {
 
 var root = false;
 if (!node) {
  node = document.createElement('root');
  root = true;
 }
 
 for (var x in json) {
  // ignore inherited properties
  if (json.hasOwnProperty(x)) {
  
   if (x == '#text') { // text
    node.appendChild(document.createTextNode(json[x]));
   } else  if (x == '@attributes') { // attributes
    for (var y in json[x]) {
     if (json[x].hasOwnProperty(y)) {
      node.setAttribute(y, json[x][y]);
     }
    }
   } else if (x == '#comment') { // comment
   // ignore
   
   } else { // elements
    if (json[x] instanceof Array) { // handle arrays
     for (var i = 0; i &amp;lt; json[x].length; i++) {
      node.appendChild(json2Xml(json[x][i], document.createElement(x)));
     }
    } else {
     node.appendChild(json2Xml(json[x], document.createElement(x)));
    }
   }
  }
 }
 
 if (root == true) {
  return this.textToXML(node.innerHTML);
 } else {
  return node;
 }
 
};
&lt;/pre&gt;

&lt;p&gt;
This really isn't a good example as I couldn't find out how to create Elements using the XML DOM with browser Javascript. Instead I had to create Elements using the document.createElement() and text nodes with document.createTextNode() and use the non-standard innerHTML property in the end. The main point demonstrated is how straight forward the conversion is. 
&lt;/p&gt;

&lt;h3&gt;What is the use of converting JSON to XML&lt;/h3&gt;
&lt;p&gt;
If you are familiar with creating xHTML via the DOM methods, you'll know how verbose it can be. By using a simple data structure to represent XML, we can remove the repetitive code needed to create the xHTML. Here is a function that creates HTML Elements out of a JSON Object.
&lt;/p&gt;
&lt;p&gt;
&lt;pre name="code" class="javascript"&gt;
/**
 * JSON to HTML Elements
 * @param {String} Root Element TagName
 * @param {Object} JSON
 */
json2HTML = function(tag, json, node) {
 
 if (!node) {
  node = document.createElement(tag);
 }
 
 for (var x in json) {
  // ignore inherited properties
  if (json.hasOwnProperty(x)) {
  
   if (x == '#text') { // text
    node.appendChild(document.createTextNode(json[x]));
   } else  if (x == '@attributes') { // attributes
    for (var y in json[x]) {
     if (json[x].hasOwnProperty(y)) {
      node.setAttribute(y, json[x][y]);
     }
    }
   } else if (x == '#comment') { // comment
   // ignore
   
   } else { // elements
    if (json[x] instanceof Array) { // handle arrays
     for (var i = 0; i &amp;lt; json[x].length; i++) {
      node.appendChild(json2HTML(json[x][i], document.createElement(x)));
     }
    } else {
     node.appendChild(json2HTML(json[x], document.createElement(x)));
    }
   }
  }
 }
 
 return node;
 
};
&lt;/pre&gt;
&lt;/p&gt;
&lt;p&gt;
Lets say you wanted a link &lt;code&gt;&amp;lt;a title="Example" href="http://example.com/"&amp;gt;example.com&amp;lt;/a&amp;gt;&lt;/code&gt;. With the regular browser DOM methods you'd do:
&lt;/p&gt;
&lt;pre  name="code" class="javascript"&gt;
var a = document.createElement('a');
a.setAttribute('href', 'http://example.com/');
a.setAttribute('title', 'Example');
a.appendChild(document.createTextNode('example.com');
&lt;/pre&gt;
This is procedural and thus not very pleasing to the eye (unstructured) as well as verbose. With JSON to XHTML you would just be dealing with the data in native JavaScript Object notation.
&lt;pre name="code" class="javascript"&gt;
var a = json2HTML('a', {
 '@attributes': { href: 'http://example.com/', title: 'Example' },
 '#text': 'example.com'
});
&lt;/pre&gt;
&lt;p&gt;
That does look a lot better. This is because JSON seperates the data into a single Object, which can be manipulated as we see fit, in this case with json2HTML().
&lt;/p&gt;
&lt;p&gt;
If you want nested elements:
&lt;/p&gt;
&lt;pre name="code" class="javascript"&gt;
var div = json2HTML('div', {
 a : {
  '@attributes': { href: 'http://example.com/', title: 'Example' },
  '#text': 'example.com'
 }
});
&lt;/pre&gt;
&lt;p&gt;Which gives you&lt;/p&gt;
&lt;pre name="code" class="html"&gt;
&amp;lt;div&amp;gt;&amp;lt;a title="Example" href="http://example.com/"&amp;gt;example.com&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;
&lt;/pre&gt;

&lt;p&gt;
The uses of converting JSON to XML are many. Another example, lets say you want to syndicate an RSS feed. Just create the JSON Object with the rules given for conversion between XML and JSON, run it through your json2Xml() function and you should have a quick and easy RSS feed. Normally you'd be using a server side language other than JavaScript to generate your RSS (however &lt;a href="http://appjet.com/" target="_blank"&gt;Server Side JavaScript&lt;/a&gt; is a good choice also) but since the rules are language independent, it doesn't make a difference which language is used, as long as it can support the DOM, and JSON. 
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hXgxP/~4/ygl8gTKTIA8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://onwebdevelopment.blogspot.com/feeds/1874923804832792957/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3347571992315805758&amp;postID=1874923804832792957" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/1874923804832792957?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/1874923804832792957?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hXgxP/~3/ygl8gTKTIA8/converting-xml-to-json.html" title="Converting XML to JSON" /><author><name>Gabe LG</name><uri>https://plus.google.com/107192546834216117000</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-St_WHaLi-Yg/AAAAAAAAAAI/AAAAAAAAB6M/EQ_v8i-FgXg/s512-c/photo.jpg" /></author><thr:total>6</thr:total><feedburner:origLink>http://onwebdevelopment.blogspot.com/2008/05/converting-xml-to-json.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUcNQn0zeyp7ImA9WxdSEkQ.&quot;"><id>tag:blogger.com,1999:blog-3347571992315805758.post-2332113907053152834</id><published>2008-05-21T02:47:00.003+12:00</published><updated>2008-05-21T03:24:53.383+12:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-05-21T03:24:53.383+12:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="twittier" /><category scheme="http://www.blogger.com/atom/ns#" term="mootools" /><category scheme="http://www.blogger.com/atom/ns#" term="twitter" /><title>Twittier - a live view of twitter</title><content type="html">&lt;p&gt;
A preview of &lt;a href="http://twittier.com/"&gt;Twittier.com&lt;/a&gt; is available. 
&lt;/p&gt;

&lt;p&gt;
What is does is retrieve updates from the &lt;a href="http://twitter.com/public_timeline"&gt;twitter public timeline&lt;/a&gt;, or specific topics using &lt;a href="http://summize.com/"&gt;summize.com&lt;/a&gt; and presents it in a simple view.
&lt;/p&gt;

&lt;p&gt;
On receiving a message it extracts "relevant" keywords and displays a "live cloud view" of keywords. This cloud view is updating in real time, and thus gives you an idea of the trending topics on twitter at any given time. 
&lt;/p&gt;

&lt;p&gt;
At the moment it doesn't work on IE6, though I haven't tested IE7. I'm developing this on Firefox3 beta but Firefox2.0 should display it fine also. 
&lt;/p&gt;

&lt;p&gt;
The mashup is fully client side, using the &lt;a href="http://mootools.net/"&gt;MooTools JavaScript library&lt;/a&gt; and &lt;a href="http://summize.com/"&gt;summize.com&lt;/a&gt; for data.
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hXgxP/~4/j6P8G6-l81c" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://onwebdevelopment.blogspot.com/feeds/2332113907053152834/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3347571992315805758&amp;postID=2332113907053152834" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/2332113907053152834?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3347571992315805758/posts/default/2332113907053152834?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hXgxP/~3/j6P8G6-l81c/twittier-live-view-of-twitter.html" title="Twittier - a live view of twitter" /><author><name>Gabe LG</name><uri>https://plus.google.com/107192546834216117000</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh4.googleusercontent.com/-St_WHaLi-Yg/AAAAAAAAAAI/AAAAAAAAB6M/EQ_v8i-FgXg/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://onwebdevelopment.blogspot.com/2008/05/twittier-live-view-of-twitter.html</feedburner:origLink></entry></feed>
