<?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:thr="http://purl.org/syndication/thread/1.0" xml:lang="en-US" xml:base="http://oswaldatwork.thetaoofamp.com/wp-atom.php">
	<title type="text">Oswald@Work - The Tao of AMP</title>
	<subtitle type="text">Just another WordPress weblog</subtitle>

	<updated>2012-02-06T17:05:40Z</updated>

	<link rel="alternate" type="text/html" href="http://oswaldatwork.thetaoofamp.com" />
	<id>http://oswaldatwork.thetaoofamp.com/feed/atom/</id>
	

	<generator uri="http://wordpress.org/" version="3.4.2">WordPress</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/oswaldatwork" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="oswaldatwork" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
		<author>
			<name>admin</name>
					</author>
		<title type="html"><![CDATA[Invalid MP IP Address: 0.0.0.0]]></title>
		<link rel="alternate" type="text/html" href="http://oswaldatwork.thetaoofamp.com/2011/10/invalid-mp-ip-address-0-0-0-0/" />
		<id>http://oswaldatwork.thetaoofamp.com/?p=233</id>
		<updated>2011-10-16T07:07:46Z</updated>
		<published>2011-10-16T06:49:16Z</published>
		<category scheme="http://oswaldatwork.thetaoofamp.com" term="Miscellaneous" />		<summary type="html"><![CDATA[I you ever stumble over the error message defining the title of this blog entry: OA&#62; connect server 1 Invalid MP IP Address: 0.0.0.0 Operation failed. And your EBIPA settings looks like this: OA&#62; show ebipa EBIPA Device Server Settings Bay Enabled EBIPA/Current Netmask Gateway DNS Domain --- ------- --------------- --------------- --------------- --------------- ------ 1 [...]]]></summary>
		<content type="html" xml:base="http://oswaldatwork.thetaoofamp.com/2011/10/invalid-mp-ip-address-0-0-0-0/">&lt;p&gt;I you ever stumble over the error message defining the title of this blog entry:&lt;/p&gt;
&lt;pre&gt;OA&amp;gt; &lt;b&gt;connect server 1&lt;/b&gt;
Invalid MP IP Address: 0.0.0.0
Operation failed.&lt;/pre&gt;
&lt;p&gt;And your EBIPA settings looks like this:&lt;/p&gt;
&lt;pre&gt;OA&amp;gt; &lt;b&gt;show ebipa&lt;/b&gt;
EBIPA Device Server Settings
Bay Enabled EBIPA/Current   Netmask         Gateway         DNS             Domain
--- ------- --------------- --------------- --------------- --------------- ------
  1   Yes   192.168.101.31  255.255.255.0   0.0.0.0         192.168.101.1
            0.0.0.0                                        
...&lt;/pre&gt;
&lt;p&gt;Please don't try to reset the EBIPA settings, don't try to fail-over or restart the OA, don't try to reset the specific iLO. Good ideas, but none of these actions will give you the satisfying success you're looking for.&lt;/p&gt;
&lt;p&gt;All you need to do is to power cycle the whole blade center. Easy, isn't it?&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/oswaldatwork/~4/FRNL5Gfx7To" height="1" width="1"/&gt;</content>
		<link rel="replies" type="text/html" href="http://oswaldatwork.thetaoofamp.com/2011/10/invalid-mp-ip-address-0-0-0-0/#comments" thr:count="0" />
		<link rel="replies" type="application/atom+xml" href="http://oswaldatwork.thetaoofamp.com/2011/10/invalid-mp-ip-address-0-0-0-0/feed/atom/" thr:count="0" />
		<thr:total>0</thr:total>
	</entry>
		<entry>
		<author>
			<name>admin</name>
					</author>
		<title type="html"><![CDATA[First Thoughts on HipHop for PHP]]></title>
		<link rel="alternate" type="text/html" href="http://oswaldatwork.thetaoofamp.com/2010/02/first-thoughts-on-hiphop-for-php/" />
		<id>http://oswaldatwork.thetaoofamp.com/?p=158</id>
		<updated>2010-02-10T08:37:01Z</updated>
		<published>2010-02-03T07:32:33Z</published>
		<category scheme="http://oswaldatwork.thetaoofamp.com" term="PHP" />		<summary type="html"><![CDATA[Yesterday Facebook announced the oncoming release of HipHop for PHP, a PHP to C++ compiler to speed up your PHP application. It's not a new idea to compile a scripting language to a compiler language, but as far as I know, in case of PHP it's the first time anyone has ever tried this. The [...]]]></summary>
		<content type="html" xml:base="http://oswaldatwork.thetaoofamp.com/2010/02/first-thoughts-on-hiphop-for-php/">&lt;p&gt;&lt;img src="http://oswaldatwork.thetaoofamp.com/wp-content/uploads/2010/02/26EDF8A1-7086-43DB-8825-5C7B5121089D.jpg" alt="26EDF8A1-7086-43DB-8825-5C7B5121089D.jpg" border="0" width="184" height="215" align="right" /&gt;
&lt;p&gt;Yesterday Facebook announced the oncoming release of &lt;a href="http://developers.facebook.com/news.php?blog=1&amp;#038;story=358"&gt;HipHop for PHP&lt;/a&gt;, a PHP to C++ compiler to speed up your PHP application. It's not a new idea to compile a scripting language to a compiler language, but as far as I know, in case of PHP it's the first time anyone has ever tried this.&lt;/p&gt;
&lt;p&gt;The source code is not yet available so it's hard to tell if this approach is feasible in real word scenarios. At least Facebook asserts that they use it to serve about 90% of their web traffic.&lt;/p&gt;
&lt;p&gt;I assume HipHop will be quite helpful if you're hosting a large and mature PHP application. But please. Before you jump to conclusions that all your scaling problems are now solved, they aren't. Scaling is not only about speeding up the execution of your PHP code, it's also about I/O, network and databases. So, HipHop is one single step, but it's definitely not the Holy Grail. Everyone with some years' experience knows that there is no Holy Grail. At least not in IT.&lt;/p&gt;
&lt;p&gt;Some people already complain about the lack of &lt;em&gt;eval()&lt;/em&gt; in HipHop, which is obviously impossible to implement in a compiler language. But one the other hand, the same people arguing against the use &lt;em&gt;eval()&lt;/em&gt; at all, because it's a potential security risk and also tends to support bad programming style. I don't know, I think I can live easily without &lt;em&gt;eval()&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Very curiously looking forward to the public release of HipHop.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/oswaldatwork/~4/pwJ_htWg0Tw" height="1" width="1"/&gt;</content>
		<link rel="replies" type="text/html" href="http://oswaldatwork.thetaoofamp.com/2010/02/first-thoughts-on-hiphop-for-php/#comments" thr:count="0" />
		<link rel="replies" type="application/atom+xml" href="http://oswaldatwork.thetaoofamp.com/2010/02/first-thoughts-on-hiphop-for-php/feed/atom/" thr:count="0" />
		<thr:total>0</thr:total>
	</entry>
		<entry>
		<author>
			<name>admin</name>
					</author>
		<title type="html"><![CDATA[Good Idea: Python with FastCGI (mod_fcgid)]]></title>
		<link rel="alternate" type="text/html" href="http://oswaldatwork.thetaoofamp.com/2010/01/good-idea-python-with-fastcgi-mod_fcgid/" />
		<id>http://oswaldatwork.thetaoofamp.com/?p=107</id>
		<updated>2010-01-20T03:25:11Z</updated>
		<published>2010-01-20T03:25:11Z</published>
		<category scheme="http://oswaldatwork.thetaoofamp.com" term="Miscellaneous" />		<summary type="html"><![CDATA[A couple of days ago, I stumbled over an installation in which CGI was used to run a Python-based web application. Of course the applications ran terribly slow, and as I mentioned earlier in &#187;Save energy! Stop using CGI!&#171;, it's (nowadays) always a bad idea to use CGI. Not only it's tediously slow and bad [...]]]></summary>
		<content type="html" xml:base="http://oswaldatwork.thetaoofamp.com/2010/01/good-idea-python-with-fastcgi-mod_fcgid/">&lt;p&gt;A couple of days ago, I stumbled over an installation in which CGI was used to run a Python-based web application. Of course the applications ran terribly slow, and as I mentioned earlier in &lt;a href="http://oswaldatwork.thetaoofamp.com/wp-content/entry/save_energy_stop_using_cgi"&gt;&amp;raquo;Save energy! Stop using CGI!&amp;laquo;&lt;/a&gt;, it's (nowadays) always a bad idea to use CGI. Not only it's tediously slow and bad software design, it's also soooo 90's.&lt;/p&gt;
&lt;h3&gt;What's the difference between CGI and FastCGI?&lt;/h3&gt;
&lt;p&gt;Let me use a metaphor to start. Imagine a well...&lt;/p&gt;
&lt;style&gt;
table {
border-collapse: collapse;
}
th {
border: 0px;
padding: 0px;
padding-right: 30px;
width: 330px;
}
td {
width: 330px;
border: 0px;
padding: 0px;
padding-right: 30px;
vertical-align: top;
}
&lt;/style&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th&gt;&lt;img src="http://oswaldatwork.thetaoofamp.com/wp-content/resources/_python_cgi.jpg" alt="python_cgi.jpg" border="0" width="300" height="400" alt="Well by echiner1, http://www.flickr.com/photos/decadence/249922565/" /&gt;&lt;/th&gt;
&lt;th&gt;&lt;img src="http://oswaldatwork.thetaoofamp.com/wp-content/resources/_python_fastcgi.jpg" alt="python_fastcgi.jpg" border="0" width="300" height="400" alt="Faucet by Joe Shlabotnik, http://www.flickr.com/photos/joeshlabotnik/2881872151/" /&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Here you see the old-fasioned way of CGI: For every request you have to let the bucket all the way down into the well (fork a new process), allowing water to enter the bucket (initialize and execute your application), pull the bucket up to the surface and empty it (send the data to the web server and free all allocated memory).&lt;/td&gt;
&lt;td&gt;And here is the modern FastCGI way: Install the faucet (start the FastCGI process) and every time you need water, turn it on (connect and send a request), get water (calculate and get the answer), and turn it off (close the connection). No need to fork, initialize your application, and free the allocated memory on every single request.&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Okay, seriously, let me show you how this works in practice.&lt;/p&gt;
&lt;h3&gt;Installing Python&lt;/h3&gt;
&lt;p&gt;For this demo I use &lt;a href="http://www.sun.com/software/webstack/index.xml"&gt;Sun's Web Stack&lt;/a&gt;. It's probably the easiest way to demonstrate the performance differences between CGI and FastCGI. XAMPP doesn't support FastCGI, because with mod_perl for Perl and mod_php for PHP there is no real need for a FastCGI interface.&lt;/p&gt;
&lt;p&gt;First, let me add Python to my basic &lt;a href="http://oswaldatwork.thetaoofamp.com/wp-content/entry/easy_deploy_your_web_apps"&gt;web stack installation&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;[oswald@sol10u7 ~/webstack1.5]% &lt;strong&gt;bin/pkg install sun-python26&lt;/strong&gt;
DOWNLOAD                                    PKGS       FILES     XFER (MB)
Completed                                    1/1   2784/2784   12.65/12.65
PHASE                                        ACTIONS
Install Phase                              2861/2861
PHASE                                          ITEMS
Reading Existing Index                           7/7
Indexing Packages                                1/1
[oswald@sol10u7 ~/webstack1.5]% &lt;strong&gt;bin/setup-webstack&lt;/strong&gt;&lt;/pre&gt;
&lt;p&gt;If you're familiar with Sun's Web Stack, you'll have noticed that I'm using the IPS installation of Web Stack. That's my favorite installation way, because it allows me to place the Web Stack in any directory I want and also allows me to run the stack without the need of root privileges.&lt;/p&gt;
&lt;h3&gt;Python with CGI&lt;/h3&gt;
&lt;p&gt;Setting up CGI is very, very easy and probably that's exactly the reason why so many people still use it. &lt;/p&gt;
&lt;p&gt;Let me start with a simple "Hello World!" Python CGI script:&lt;/p&gt;
&lt;pre&gt;#!/home/oswald/webstack1.5/bin/python
print ""
print "Hello World!"&lt;/pre&gt;
&lt;p&gt;I named this file &lt;em&gt;hello.py&lt;/em&gt; and put it into the &lt;em&gt;cgi-bin&lt;/em&gt; directory of my Apache installation. In the case of Web Stack it's &lt;em&gt;var/apache2/2.2/cgi-bin&lt;/em&gt;. Add execute permissions:&lt;/p&gt;
&lt;pre&gt;[oswald@sol10u7 ~]% &lt;strong&gt;chmod a+x var/apache2/2.2/cgi-bin/hello.py&lt;/strong&gt;&lt;/pre&gt;
&lt;p&gt;Now I log into another box on the same network and use my favorite command-line web browser Lynx to test the newly created Hello World CGI:&lt;/p&gt;
&lt;pre&gt;[oswald@debian50 ~]% &lt;strong&gt;lynx -source http://sol10u7/cgi-bin/hello.py&lt;/strong&gt;
Hello World!&lt;/pre&gt;
&lt;p&gt;Looks good. Now let's benchmark this script:&lt;/p&gt;
&lt;pre&gt;[oswald@debian50 ~]% &lt;strong&gt;ab -n 1000 http://sol10u7/cgi-bin/hello.py&lt;/strong&gt;
...
Time taken for tests:   31.083 seconds
...
Total transferred:      256000 bytes
HTML transferred:       13000 bytes
Requests per second:    32.17 [#/sec] (mean)
...&lt;/pre&gt;
&lt;p&gt;32 requests/second. That's nothing to be proud of!&lt;/p&gt;
&lt;h3&gt;Python with FastCGI&lt;/h3&gt;
&lt;p&gt;And now let's try FastCGI by adding Apache's &lt;a href="http://httpd.apache.org/mod_fcgid/"&gt;mod_fcgid&lt;/a&gt; to the Web Stack installation:&lt;/p&gt;
&lt;pre&gt;[oswald@sol10u7 ~/webstack1.5]% &lt;strong&gt;bin/pkg install sun-apache22-fcgid&lt;/strong&gt;
DOWNLOAD                                    PKGS       FILES     XFER (MB)
Completed                                    1/1         6/6     0.09/0.09
PHASE                                        ACTIONS
Install Phase                                  24/24
PHASE                                          ITEMS
Reading Existing Index                           7/7
Indexing Packages                                1/1
[oswald@sol10u7 ~/webstack1.5]% &lt;strong&gt;bin/setup-webstack&lt;/strong&gt;&lt;/pre&gt;
&lt;p&gt;Activate the default configuration:&lt;/p&gt;
&lt;pre&gt;[oswald@sol10u7 ~/webstack1.5]% &lt;strong&gt;cp etc/apache2/2.2/samples-conf.d/fcgid.conf etc/apache2/
2.2/conf.d/&lt;/strong&gt;&lt;/pre&gt;
&lt;p&gt;For those, who are not able or don't want to use Sun's Web Stack, the  above &lt;em&gt;fcgid.conf&lt;/em&gt; file basically contains the following directives:&lt;/p&gt;
&lt;pre&gt;LoadModule fcgid_module libexec/mod_fcgid.so
SharememPath /home/oswald/webstack1.5/var/run/apache2/2.2/fcgid_shm
SocketPath /home/oswald/webstack1.5/var/run/apache2/2.2/fcgid.sock
AddHandler fcgid-script .fcgi
&amp;lt;Location /fcgid&amp;gt;
SetHandler fcgid-script
Options ExecCGI
allow from all
&amp;lt;/Location&amp;gt;
&lt;/pre&gt;
&lt;/p&gt;
&lt;p&gt;As usual after changing Apache's configuration, we need to reload (aka &lt;em&gt;graceful&lt;/em&gt; restart) the Apache to let the new configuration take effect:&lt;/p&gt;
&lt;pre&gt;[oswald@sol10u7 ~/webstack1.5]% &lt;strong&gt;apache2/2.2/bin/apachectl graceful&lt;/strong&gt;&lt;/pre&gt;
&lt;p&gt;Now I create a new directory named &lt;em&gt;fcgid&lt;/em&gt; directly inside of Apache's document root folder and change into that folder:&lt;/p&gt;
&lt;pre&gt;[oswald@sol10u7 ~/webstack1.5]% &lt;strong&gt;mkdir var/apache2/2.2/htdocs/fcgid&lt;/strong&gt;
[oswald@sol10u7 ~/webstack1.5]% &lt;strong&gt;cd var/apache2/2.2/htdocs/fcgid&lt;/strong&gt;&lt;/pre&gt;
&lt;p&gt;To let Python to talk with my Apache's mod_fcgid I need to install a so-called &lt;em&gt;Python FastCGI/WSGI gateway&lt;/em&gt;. There are several solutions available for Python, but I personally prefer Allan Saddi's &lt;a href="http://svn.saddi.com/py-lib/trunk/fcgi.py"&gt;fcgi.py&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;[oswald@sol10u7 htdocs/fcgid]% &lt;strong&gt;wget -q http://svn.saddi.com/py-lib/trunk/fcgi.py&lt;/strong&gt;&lt;/pre&gt;
&lt;p&gt;The "Hello World!" Python FastCGI script looks a little different this time:&lt;/p&gt;
&lt;pre&gt;#!/home/oswald/webstack1.5/bin/python
from fcgi import WSGIServer
def app(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return('''Hello world!\n''')
WSGIServer(app).run()&lt;/pre&gt;
&lt;p&gt;This time it's not the output of a script which is sent back to the browser, it's the return value of a function &lt;em&gt;add()&lt;/em&gt; defining the data which goes to the user's browser. In this case it's the simple character string &lt;em&gt;"Hello World!\n"&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Like in the CGI example above, the Python script needs to be executable:&lt;/p&gt;
&lt;pre&gt;[oswald@sol10u7 htdocs/fcgid]% &lt;strong&gt;chmod a+x hello.py&lt;/strong&gt;&lt;/pre&gt;
&lt;p&gt;The content of my &lt;em&gt;fcgid&lt;/em&gt; directory now looks like this:&lt;/p&gt;
&lt;pre&gt;[oswald@sol10u7 htdocs/fcgid]% &lt;strong&gt;ls -l&lt;/strong&gt;
total 90
-rw-r--r--   1 oswald   other      44113 Jul 26  2006 fcgi.py
-rwxr-xr-x   1 oswald   other        223 Jan 19 12:48 hello.py&lt;/pre&gt;
&lt;p&gt;And - like in my CGI example above - I now test the script with Lynx:&lt;/p&gt;
&lt;pre&gt;[oswald@debian50 ~]% &lt;strong&gt;lynx -source http://sol10u7/fcgid/hello.py&lt;/strong&gt;
Hello world!&lt;/pre&gt;
&lt;p&gt;And after everything looks fine, I start a little benchmark:&lt;/p&gt;
&lt;pre&gt;[oswald@debian50 ~]% &lt;strong&gt;ab -q -n 1000 http://sol10u7/fcgid/hello.py&lt;/strong&gt;
...
Time taken for tests:   1.747 seconds
...
Total transferred:      235000 bytes
HTML transferred:       13000 bytes
Requests per second:    572.44 [#/sec] (mean)
...
&lt;/pre&gt;
&lt;p&gt;Yes, gotcha. 572 requests per seconds: that sounds reasonable. Remember the 32 requests/second from CGI? Do you want the well or do you take the faucet? Sure, implementing a FastCGI program is far more challenging then coding a simple CGI solution, but 572 against 32 requests per second? Do I need to say more?&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Fotos: On the right &lt;a href="http://www.flickr.com/photos/joeshlabotnik/2881872151/"&gt;"Faucet"&lt;/a&gt; by Joe Shlabotnik, and on the left &lt;a href="http://www.flickr.com/photos/decadence/249922565/"&gt;"Well"&lt;/a&gt; by echiner1. Both licensed under &lt;a href="http://creativecommons.org/licenses/by-sa/2.0/"&gt;Creative Commons&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/oswaldatwork/~4/iVT8v-6VN18" height="1" width="1"/&gt;</content>
		<link rel="replies" type="text/html" href="http://oswaldatwork.thetaoofamp.com/2010/01/good-idea-python-with-fastcgi-mod_fcgid/#comments" thr:count="0" />
		<link rel="replies" type="application/atom+xml" href="http://oswaldatwork.thetaoofamp.com/2010/01/good-idea-python-with-fastcgi-mod_fcgid/feed/atom/" thr:count="0" />
		<thr:total>0</thr:total>
	</entry>
		<entry>
		<author>
			<name>admin</name>
					</author>
		<title type="html"><![CDATA[Web Stack and the TLS Vulnerability]]></title>
		<link rel="alternate" type="text/html" href="http://oswaldatwork.thetaoofamp.com/2010/01/web-stack-and-the-tls-vulnerability/" />
		<id>http://oswaldatwork.thetaoofamp.com/?p=108</id>
		<updated>2010-01-12T23:56:15Z</updated>
		<published>2010-01-12T23:56:15Z</published>
		<category scheme="http://oswaldatwork.thetaoofamp.com" term="Sun" />		<summary type="html"><![CDATA[If you're a Web Stack user, please read Jyri's brief article about Web Stack and the TLS Vulnerability.]]></summary>
		<content type="html" xml:base="http://oswaldatwork.thetaoofamp.com/2010/01/web-stack-and-the-tls-vulnerability/">&lt;p&gt;If you're a Web Stack user, please read Jyri's brief article about &lt;a href="http://blogs.sun.com/jyrivirkki/entry/web_stack_and_the_tls"&gt;Web Stack and the TLS Vulnerability&lt;/a&gt;.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/oswaldatwork/~4/XiVMl4fZRNM" height="1" width="1"/&gt;</content>
		<link rel="replies" type="text/html" href="http://oswaldatwork.thetaoofamp.com/2010/01/web-stack-and-the-tls-vulnerability/#comments" thr:count="0" />
		<link rel="replies" type="application/atom+xml" href="http://oswaldatwork.thetaoofamp.com/2010/01/web-stack-and-the-tls-vulnerability/feed/atom/" thr:count="0" />
		<thr:total>0</thr:total>
	</entry>
		<entry>
		<author>
			<name>admin</name>
					</author>
		<title type="html"><![CDATA[Cache, cache, cache! (Part 3: What to cache?)]]></title>
		<link rel="alternate" type="text/html" href="http://oswaldatwork.thetaoofamp.com/2010/01/cache-cache-cache-part-3-what-to-cache/" />
		<id>http://oswaldatwork.thetaoofamp.com/?p=109</id>
		<updated>2010-01-07T13:32:27Z</updated>
		<published>2010-01-07T13:32:27Z</published>
		<category scheme="http://oswaldatwork.thetaoofamp.com" term="Miscellaneous" />		<summary type="html"><![CDATA[Happy New Year everyone! Hope you could enjoy your holidays!! Let's start this year with the third part of my little series of thoughts about caching. After my small memcached intro and thoughts about caching architectures, I now focus on the data you should consider to cache in your web application. [1] Cache HTML Obviously [...]]]></summary>
		<content type="html" xml:base="http://oswaldatwork.thetaoofamp.com/2010/01/cache-cache-cache-part-3-what-to-cache/">&lt;p&gt;Happy New Year everyone! Hope you could enjoy your holidays!!&lt;/p&gt;
&lt;p&gt;Let's start this year with the third part of my little series of thoughts about caching. After my &lt;a href="http://oswaldatwork.thetaoofamp.com/wp-content/entry/cache_cache_cache_part_1"&gt;small memcached intro&lt;/a&gt; and &lt;a href="http://oswaldatwork.thetaoofamp.com/wp-content/entry/cache_cache_cache_part_2"&gt; thoughts about caching architectures&lt;/a&gt;, I now focus on the data you should consider to cache in your web application.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://oswaldatwork.thetaoofamp.com/wp-content/resources/_cache-what.png" alt="cache-what.png" border="0" width="600" height="450" /&gt;&lt;/p&gt;
&lt;h3&gt;[1] Cache HTML&lt;/h3&gt;
&lt;p&gt;Obviously the biggest performance win you can achieve is by caching the whole output of your web application: a simple reverse proxy scenario.  This works very well for mostly static pages, but for highly dynamical and user-specific content this is not an option: there is no advantage in caching a web page, which gets obsolete within the next moment.&lt;/p&gt;
&lt;p&gt;Probably the best way to solve this dilemma is to implement a so-called &lt;em&gt;partial-page cache&lt;/em&gt;: Let your application cache just portions of the page and leave the rest, where it makes no sense to cache, dynamic.&lt;/p&gt;
&lt;p&gt;It's very important that you implement this in a very top layer of your application. Probably exactly that layer, which software architects will call presentation layer. Sure, this is likely to break you framework architecture, but to quote chapter 55 of the Tao Te Ching:&lt;/p&gt;
&lt;blockquote class="tao"&gt;&lt;p&gt;The movement of the Tao&lt;br /&gt;
By contraries proceeds;&lt;br /&gt;
And weakness marks the course&lt;br /&gt;
Of Tao's mighty deeds.
&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;But seriously: If you have to stay in the boundaries of a framework, Ajax is a good way to bypass this restrictions and helps to implement such a cache in a restricted architecture. But be aware that this will raise the number of HTTP requests on your frontend web servers.&lt;/p&gt;
&lt;p&gt;An effective caching strategy will always mess your beautifully designed software architecture up. Having just one (central) caching layer looks great in system diagrams and it's better than no cache at all, but it's definitely not the end of the rope.&lt;/p&gt;
&lt;h3&gt;[2] Cache complex data structures&lt;/h3&gt;
&lt;p&gt;If you don't want to break your framework architecture or you don't like the idea of caching HTML at all, and I totally understand your point, you should consider about caching other (lower level, but still complex) structures of data.&lt;/p&gt;
&lt;p&gt;Some examples for suitable data structures:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;user profiles&lt;/li&gt;
&lt;li&gt;friends lists&lt;/li&gt;
&lt;li&gt;current user lists&lt;/li&gt;
&lt;li&gt;list of locations, branches, countries, languages, ...&lt;/li&gt;
&lt;li&gt;top 10 (whatever) lists&lt;/li&gt;
&lt;li&gt;public statistical data&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The main challenge lies in identifying the most proper data structures. This is no easy task and strongly depends on the kind of web application you run or plan to run. Avoid caching simple data sets, like row-level data from the database. Don't think row-level.&lt;br /&gt;
That's the best advice you should keep in mind. (Note to myself: I need to put this on a t-shirt. I found this phrase in &lt;a href="http://www.igvita.com/2008/04/22/mysql-conf-memcached-internals/"&gt;Memcached Internals&lt;/a&gt;, a wonderful article inspired by a &lt;a href="http://download.tangent.org/talks/Memcached%20Study.pdf"&gt;talk&lt;/a&gt; by Brian Aker and Alan Kasindorf.)&lt;/p&gt;
&lt;p&gt;At a first glance Ajax may be an obvious technology to combine with such a cache. But please be aware that moving application logic away from the server-side application to the client side is always a very dangerous task, which easily may compromise the security of your application.&lt;/p&gt;
&lt;p&gt;Which allows me to end this post with another quote from Laozi (Tao Te Ching, chapter 63):&lt;/p&gt;
&lt;blockquote class="tao"&gt;&lt;p&gt;All difficult things in the world&lt;br /&gt;
are sure to arise from a previous state&lt;br /&gt;
in which they were easy.&lt;/p&gt;&lt;/blockquote&gt;
&lt;img src="http://feeds.feedburner.com/~r/oswaldatwork/~4/h55bh3pO7Bk" height="1" width="1"/&gt;</content>
		<link rel="replies" type="text/html" href="http://oswaldatwork.thetaoofamp.com/2010/01/cache-cache-cache-part-3-what-to-cache/#comments" thr:count="0" />
		<link rel="replies" type="application/atom+xml" href="http://oswaldatwork.thetaoofamp.com/2010/01/cache-cache-cache-part-3-what-to-cache/feed/atom/" thr:count="0" />
		<thr:total>0</thr:total>
	</entry>
		<entry>
		<author>
			<name>admin</name>
					</author>
		<title type="html"><![CDATA[Cache, cache, cache! (Part 2: Architectures)]]></title>
		<link rel="alternate" type="text/html" href="http://oswaldatwork.thetaoofamp.com/2009/12/cache-cache-cache-part-2-architectures/" />
		<id>http://oswaldatwork.thetaoofamp.com/?p=110</id>
		<updated>2009-12-17T05:26:11Z</updated>
		<published>2009-12-17T05:26:11Z</published>
		<category scheme="http://oswaldatwork.thetaoofamp.com" term="Miscellaneous" />		<summary type="html"><![CDATA[On Tuesday I focused mainly on memcached and PHP, but today I'll take a wider look at cacheing architectures in general. The main question about defining a cache architecture is to decide where to locate the caching component: [1] Status quo, the three-tier architecture In theory, the commonly accepted standard architecture of a software product [...]]]></summary>
		<content type="html" xml:base="http://oswaldatwork.thetaoofamp.com/2009/12/cache-cache-cache-part-2-architectures/">&lt;p&gt;On Tuesday I focused mainly on &lt;a href="http://oswaldatwork.thetaoofamp.com/wp-content/entry/cache_cache_cache_part_1"&gt;memcached and PHP&lt;/a&gt;, but today I'll take a wider look at cacheing architectures in general. The main question about defining a cache architecture is to decide where to locate the caching component:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://oswaldatwork.thetaoofamp.com/wp-content/resources/_cache-architectures.png" alt="cache-architectures.png" border="0" width="600" height="450" /&gt;&lt;/p&gt;
&lt;h3&gt;[1] Status quo, the three-tier architecture&lt;/h3&gt;
&lt;p&gt;In theory, the commonly accepted standard architecture of a software product is divided into three tiers: the presentation tier, the application tier and finally the data tier. In the context of web applications we rediscover this tiers in the trinity of web server, application server and database server.&lt;/p&gt;
&lt;p&gt;In the above diagram we find these three tiers with the user (or in technical terms: the browser) on top of this stack.&lt;/p&gt;
&lt;h3&gt;[2] Cache on top&lt;/h3&gt;
&lt;p&gt;One very obvious idea is to place the cache in front of the web server, between user and web server. Usually we find this architecture in a so called &lt;a href="http://en.wikipedia.org/wiki/Reverse_proxy"&gt;reverse proxy&lt;/a&gt; configuration. A reverse proxy is quite easy to set up and has a positive impact for web sites with more static content. But for highly dynamic web applications - like most of today's Web 2.0 applications - the caching benefit of a reverse proxy may be not that big.&lt;/p&gt;
&lt;p&gt;In general: having a reverse proxy is better than no caching at all. A reverse proxy will give you always a performance benefit.&lt;/p&gt;
&lt;h3&gt;[3] Cache in between of web and application server&lt;/h3&gt;
&lt;p&gt;Let's move the cache one level down the stack in between web server and application server. On the fist sight this may look like a very good idea, because the cache now protects the application server. But on the second sight you'll realize that this configuration is mostly the same as that one from architecture 2, just without the benefit also caching your web server's data.&lt;/p&gt;
&lt;p&gt;For exotic scenarios there may be a good reason for this configuration (esp. in combination with load balancing functionality) but in general you should favor architecture 2 over this one.&lt;/p&gt;
&lt;h3&gt;[4] Cache in between of application and database&lt;/h3&gt;
&lt;p&gt;And another level down in the stack. The cache now sits between application server and database. Again this looks good, and seems to be a good idea - on the first sight. But on the second or third sight you may realize that nearly every database system has its own internal query cache and our cache is only a cache for a cache. And caching a cache is basically never a good idea and can lead to unpredictable, bad consequences.&lt;/p&gt;
&lt;p&gt;Another difficulty with this approach is that it's hard to decide when the cache gets dirty (cache jargon for obsolete) and when it's time to clear the cache.&lt;/p&gt;
&lt;h3&gt;[5] Cache inside of application&lt;/h3&gt;
&lt;p&gt;And now half a level up again: right into the application tier. This is the most challenging but also the most powerful place to implement caching strategies. Identify time-critical and frequently accessed data during the development process and implement dedicated and customized caching mechanisms. But don't try do build an abstract, unified, common cache for everything.&lt;/p&gt;
&lt;p&gt;It's very important to find a specific and suitable solutions for each kind of data you want to cache in your application. Otherwise you'll will probably just end with another row-based cache for your database (like architecture 4) or some kind of reverse proxy (like architecture 2).&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Architectures 2, 3 and 4 can be easily setup by system administration without having to involve development in any way. It's mostly a matter of clever configuration which also may add some load balancing features. In general you'll definitely achieve a better performance of your application, but there is always a given limit by the architecture and scaling quality of your core application.&lt;/p&gt;
&lt;p&gt;Architecture 5 is probably the best choice, but - to get best results - needs to be started in an early stage and during the whole development and designing process of your web application you should always have caching in mind. What data is most frequently accessed? What data is expensive (hard to retrieve)? What data depends on user sessions? How up to date does the data need to be?&lt;/p&gt;
&lt;p&gt;If you are curious about these questions, please stay tuned for part 3.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/oswaldatwork/~4/Sxbi3n3A37g" height="1" width="1"/&gt;</content>
		<link rel="replies" type="text/html" href="http://oswaldatwork.thetaoofamp.com/2009/12/cache-cache-cache-part-2-architectures/#comments" thr:count="0" />
		<link rel="replies" type="application/atom+xml" href="http://oswaldatwork.thetaoofamp.com/2009/12/cache-cache-cache-part-2-architectures/feed/atom/" thr:count="0" />
		<thr:total>0</thr:total>
	</entry>
		<entry>
		<author>
			<name>admin</name>
					</author>
		<title type="html"><![CDATA[Cache, cache, cache! (Part 1: memcached)]]></title>
		<link rel="alternate" type="text/html" href="http://oswaldatwork.thetaoofamp.com/2009/12/cache-cache-cache-part-1-memcached/" />
		<id>http://oswaldatwork.thetaoofamp.com/?p=111</id>
		<updated>2009-12-15T03:03:54Z</updated>
		<published>2009-12-15T03:03:54Z</published>
		<category scheme="http://oswaldatwork.thetaoofamp.com" term="Miscellaneous" />		<summary type="html"><![CDATA[Caching is probably the most important technique you should use in nowadays web sites or web application. Sure, scaling your hardware is still the final answer to all your load problems, but with some kind of caching your application will scale far better rather than without. Currently my favorite caching tool is memcached. It's a [...]]]></summary>
		<content type="html" xml:base="http://oswaldatwork.thetaoofamp.com/2009/12/cache-cache-cache-part-1-memcached/">&lt;p&gt;Caching is probably the most important technique you should use in nowadays web sites or web application. Sure, scaling your hardware is still the final answer to all your load problems, but with some kind of caching your application will scale far better rather than without.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://oswaldatwork.thetaoofamp.com/wp-content/resources/_cachecachecache.png" alt="cachecachecache.png" border="0" width="600" height="290" /&gt;&lt;/p&gt;
&lt;p&gt;Currently my favorite caching tool is &lt;a href="http://memcached.org/"&gt;memcached&lt;/a&gt;. It's a slim and ultra fast distributed  caching system. Memcached is basically a key-value store, which stores all data non-persistently in memory and if your server goes down all the data is also gone because it's not stored somewhere on a hard disk.&lt;/p&gt;
&lt;p&gt;Memcached is not meant to be a database, and you'll still need a database to store your data persistently.&lt;/p&gt;
&lt;h3&gt;Setting up memcached&lt;/h3&gt;
&lt;p&gt;I'm a very lazy guy and try to avoid boring duties like installing memcached. That's why I love using &lt;a href="http://www.sun.com/software/webstack/index.xml"&gt;Sun's Web Stack&lt;/a&gt;, which already includes memcached and is so easy to use. If you're not a Web Stack user please take a look at the &lt;a href="http://code.google.com/p/memcached/wiki/FAQ"&gt;memcached FAQ&lt;/a&gt; to learn how to install memcached on your system.&lt;/p&gt;
&lt;p&gt;To add memcached to my IPS-based Web Stack installation I simply call these two commands:&lt;/p&gt;
&lt;pre&gt;[oswald@localhost ~/demo]$ &lt;strong&gt;bin/pkg install sun-memcached&lt;/strong&gt;
DOWNLOAD                                    PKGS       FILES     XFER (MB)
Completed                                    1/1         9/9     0.17/0.17
PHASE                                        ACTIONS
Install Phase                                  30/30
PHASE                                          ITEMS
Reading Existing Index                           7/7
Indexing Packages                                1/1
[oswald@localhost ~/demo]$ &lt;strong&gt;bin/setup-webstack&lt;/strong&gt;&lt;/pre&gt;
&lt;p&gt;Now all I need to do is to start the daemon:&lt;/p&gt;
&lt;pre&gt;[oswald@localhost ~/demo]$ &lt;strong&gt;bin/sun-memcached start&lt;/strong&gt;
Starting memcached
&lt;/pre&gt;
&lt;p&gt;Memcached has no support for any access control at all and you should use memcached only on private networks or secure you installation with a firewall (port 11211, by the way).&lt;/p&gt;
&lt;h3&gt;Using memcached with PHP&lt;/h3&gt;
&lt;p&gt;As I already mentioned memcached is a simple key-value store which is very easy to use for programmers. To show the basic idea I put this small PHP script together:&lt;/p&gt;
&lt;pre&gt;&amp;lt;?php
$memcache = new Memcache();
if(!&lt;strong&gt;$memcache-&gt;connect('localhost', 11211)&lt;/strong&gt;)
die("Couldn't connect to memcached! Cruel world!");
$key="zaphod";
$result = &lt;strong&gt;$memcache-&gt;get($key)&lt;/strong&gt;;
if($result)
{
echo "$key is $result";
}
else
{
$value="cool";
echo "Set $key to $value";
&lt;strong&gt;$memcache-&gt;set($key,$value)&lt;/strong&gt;;
}
?&amp;gt;&lt;/pre&gt;
&lt;p&gt;There are three main functions you will need to understand in order to work with memcached:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;connect(host,port)&lt;/dt&gt;
&lt;dd&gt;to connect to your memcached server. If you have multiple memcached servers running you can use &lt;em&gt;addServer()&lt;/em&gt; to add one or more servers to the connection pool.&lt;/dd&gt;
&lt;dt&gt;get(key)&lt;/dt&gt;
&lt;dd&gt; Retrieves the value for the given key.&lt;/dd&gt;
&lt;dt&gt;set(key,value)&lt;/dt&gt;
&lt;dd&gt; Stores the given value for the given key. &lt;em&gt;set()&lt;/em&gt; also allows you to define an expiration time for the key-value pair.&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;On the first execution of this script the cache is empty and you'll get this output:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Set zaphod to cool&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;On the second execution, the value for &lt;em&gt;zaphod&lt;/em&gt; is already set and you'll see:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;zaphod is cool&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;That's all. That's the basic way to use memcached.&lt;/p&gt;
&lt;h3&gt;What's next...&lt;/h3&gt;
&lt;p&gt;The next step is to decide what information you want to cache and where do you want to cache. Both are very crucial decisions which determine success or failure of your cache. So, stay tuned for part 2. ;)&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/oswaldatwork/~4/i8QzbfA4_DY" height="1" width="1"/&gt;</content>
		<link rel="replies" type="text/html" href="http://oswaldatwork.thetaoofamp.com/2009/12/cache-cache-cache-part-1-memcached/#comments" thr:count="0" />
		<link rel="replies" type="application/atom+xml" href="http://oswaldatwork.thetaoofamp.com/2009/12/cache-cache-cache-part-1-memcached/feed/atom/" thr:count="0" />
		<thr:total>0</thr:total>
	</entry>
		<entry>
		<author>
			<name>admin</name>
					</author>
		<title type="html"><![CDATA[Restoring normality&#8230;]]></title>
		<link rel="alternate" type="text/html" href="http://oswaldatwork.thetaoofamp.com/2009/12/restoring-normality/" />
		<id>http://oswaldatwork.thetaoofamp.com/?p=112</id>
		<updated>2009-12-10T01:24:46Z</updated>
		<published>2009-12-10T01:24:46Z</published>
		<category scheme="http://oswaldatwork.thetaoofamp.com" term="Sun" />		<summary type="html"><![CDATA[&#187;...just as soon as we are sure what is normal anyway. Thank you.&#171; (HHGTTG) The last few weeks were a little quiet here in this blog. I had to do some urgent programming for the next release of our Web Stack and last week I had the great pleasure to talk about web application development [...]]]></summary>
		<content type="html" xml:base="http://oswaldatwork.thetaoofamp.com/2009/12/restoring-normality/">&lt;p&gt;&amp;raquo;...just as  soon  as  we are  sure  what  is normal anyway. Thank you.&amp;laquo; (HHGTTG)&lt;/p&gt;
&lt;p&gt;The last few weeks were a little quiet here in this blog. I had to do some urgent programming for the next release of our &lt;a href="http://www.sun.com/software/webstack/index.xml"&gt;Web Stack&lt;/a&gt; and last week I had the great pleasure to talk about &lt;a href="http://codebits.eu/intra/s/session/82"&gt;web application development&lt;/a&gt; at the &lt;a href="http://codebits.eu/"&gt;Codebits&lt;/a&gt; conference in Lisbon.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://oswaldatwork.thetaoofamp.com/wp-content/resources/_4166227540_48a7f716b6_o.jpg" alt="4166227540_48a7f716b6_o.jpg" border="0" width="600" height="450" /&gt;&lt;br /&gt;
&lt;small&gt;Photography by &lt;a href="http://www.flickr.com/photos/lenzgr/4166227540/"&gt;Lenz Grimmer&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/oswaldatwork/~4/fCN0SX6sA4s" height="1" width="1"/&gt;</content>
		<link rel="replies" type="text/html" href="http://oswaldatwork.thetaoofamp.com/2009/12/restoring-normality/#comments" thr:count="1" />
		<link rel="replies" type="application/atom+xml" href="http://oswaldatwork.thetaoofamp.com/2009/12/restoring-normality/feed/atom/" thr:count="1" />
		<thr:total>1</thr:total>
	</entry>
		<entry>
		<author>
			<name>admin</name>
					</author>
		<title type="html"><![CDATA[PHP: session.gc_maxlifetime vs. session.cookie_lifetime]]></title>
		<link rel="alternate" type="text/html" href="http://oswaldatwork.thetaoofamp.com/2009/11/php-session-gc_maxlifetime-vs-session-cookie_lifetime/" />
		<id>http://oswaldatwork.thetaoofamp.com/?p=113</id>
		<updated>2012-02-06T17:05:40Z</updated>
		<published>2009-11-19T04:49:25Z</published>
		<category scheme="http://oswaldatwork.thetaoofamp.com" term="PHP" />		<summary type="html"><![CDATA[PHP and sessions: Very simple to use, but not as simple to understand as we might want to think. session.gc_maxlifetime This value (default 1440 seconds) defines how long an unused PHP session will be kept alive. For example: A user logs in, browses through your application or web site, for hours, for days. No problem. [...]]]></summary>
		<content type="html" xml:base="http://oswaldatwork.thetaoofamp.com/2009/11/php-session-gc_maxlifetime-vs-session-cookie_lifetime/">&lt;p&gt;PHP and sessions: Very simple to use, but not as simple to understand as we might want to think.&lt;/p&gt;
&lt;h3&gt;session.gc_maxlifetime&lt;/h3&gt;
&lt;p&gt;This value (default 1440 seconds) defines how long an unused PHP session will be kept alive. For example: A user logs in, browses through your application or web site, for hours, for days. No problem. As long as the time between his clicks never exceed 1440 seconds. It's a timeout value.&lt;/p&gt;
&lt;p&gt;PHP's session garbage collector runs with a probability defined by &lt;em&gt;session.gc_probability&lt;/em&gt; divided by &lt;em&gt;session.gc_divisor&lt;/em&gt;. By default this is 1/100, which means that above timeout value is checked with a probability of 1 in 100.&lt;/p&gt;
&lt;h3&gt;session.cookie_lifetime&lt;/h3&gt;
&lt;p&gt;This value (default 0, which means until the browser's next restart) defines how long (in seconds) a session cookie will live. Sounds similar to &lt;em&gt;session.gc_maxlifetime&lt;/em&gt;, but it's a completely different approach. This value indirectly defines the "absolute" maximum lifetime of a session, whether the user is active or not. If this value is set to 60, every session ends after &lt;del&gt;an hour&lt;/del&gt; a minute.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/oswaldatwork/~4/kl_2p8xvWuY" height="1" width="1"/&gt;</content>
		<link rel="replies" type="text/html" href="http://oswaldatwork.thetaoofamp.com/2009/11/php-session-gc_maxlifetime-vs-session-cookie_lifetime/#comments" thr:count="6" />
		<link rel="replies" type="application/atom+xml" href="http://oswaldatwork.thetaoofamp.com/2009/11/php-session-gc_maxlifetime-vs-session-cookie_lifetime/feed/atom/" thr:count="6" />
		<thr:total>6</thr:total>
	</entry>
		<entry>
		<author>
			<name>admin</name>
					</author>
		<title type="html"><![CDATA[PHP&#8217;s MySQLi extension: Storing and retrieving blobs]]></title>
		<link rel="alternate" type="text/html" href="http://oswaldatwork.thetaoofamp.com/2009/11/php_s_mysqli_extension_storing/" />
		<id>http://oswaldatwork.thetaoofamp.com/?p=114</id>
		<updated>2010-10-18T09:17:58Z</updated>
		<published>2009-11-18T02:35:20Z</published>
		<category scheme="http://oswaldatwork.thetaoofamp.com" term="MySQL" />		<summary type="html"><![CDATA[There are a lot of tutorial out there describing how to use PHP's classic MySQL extension to store and retrieve blobs. There are also many tutorials how to use PHP's MySQLi extension to use prepared statements to fight SQL injections in your web application. But there are no tutorials about using MySQLi with any blob [...]]]></summary>
		<content type="html" xml:base="http://oswaldatwork.thetaoofamp.com/2009/11/php_s_mysqli_extension_storing/">&lt;p&gt;There are a lot of tutorial out there describing how to use PHP's classic MySQL extension to store and retrieve blobs. There are also many tutorials how to use PHP's MySQLi extension to use prepared statements to fight SQL injections in your web application.  But there are no tutorials about using MySQLi with any blob data at all.&lt;/p&gt;
&lt;p&gt;Until today... ;)&lt;/p&gt;
&lt;h3&gt;Preparing the database&lt;/h3&gt;
&lt;p&gt;Okay, first I need a table to store my blobs. In this example I'll store images in my database because images usually look better in a tutorial than some random raw data.&lt;/p&gt;
&lt;pre&gt;mysql&amp;gt; &lt;strong&gt;CREATE TABLE images (&lt;/strong&gt;
	&lt;strong&gt;id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,&lt;/strong&gt;
	&lt;strong&gt;image MEDIUMBLOB NOT NULL,&lt;/strong&gt;
	&lt;strong&gt;PRIMARY KEY (id)&lt;/strong&gt;
&lt;strong&gt;);&lt;/strong&gt;
Query OK, 0 rows affected (0.02 sec)&lt;/pre&gt;
&lt;p&gt;In general you don't want to store images in a relational database. But that's another discussion for another day.&lt;/p&gt;
&lt;h3&gt;Storing the blob&lt;/h3&gt;
&lt;p&gt;To make a long story short, here's the code to store a blob using MySQLi:&lt;/p&gt;
&lt;pre&gt;&amp;lt;?php
	$mysqli=mysqli_connect('localhost','user','password','db');
	if (!$mysqli)
		die("Can't connect to MySQL: ".mysqli_connect_error());
	$stmt = $mysqli-&amp;gt;prepare("INSERT INTO images (image) VALUES(?)");
	&lt;strong&gt;$null = NULL;&lt;/strong&gt;
	$stmt-&amp;gt;bind_param("b", &lt;strong&gt;$null&lt;/strong&gt;);
	&lt;strong&gt;$stmt-&amp;gt;send_long_data(0, file_get_contents("osaka.jpg"));&lt;/strong&gt;
	$stmt-&amp;gt;execute();
?&amp;gt;&lt;/pre&gt;
&lt;p&gt;If you already used MySQLi, most of the above should look familiar to you. I highlighted two pieces of code, which I think are worth looking at:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The &lt;em&gt;$null&lt;/em&gt; variable is needed, because &lt;em&gt;bind_param()&lt;/em&gt; always wants a variable reference for a given parameters. In this case the "b" (as in blob) parameter.  So &lt;em&gt;$null&lt;/em&gt; is just a dummy, to make the syntax work.&lt;/li&gt;
&lt;li&gt;In the next step I need to "fill" my blob parameter with the actual data. This is done by &lt;em&gt;send_long_data()&lt;/em&gt;. The first parameter of this method indicates which parameter to associate the data with. Parameters are numbered beginning with 0. The second parameter of &lt;em&gt;send_long_data()&lt;/em&gt; contains the actual data to be stored.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;While using &lt;em&gt;send_long_data()&lt;/em&gt;, please make sure that the blob isn't bigger than MySQL's &lt;em&gt;max_allowed_packet&lt;/em&gt;:&lt;/p&gt;
&lt;pre&gt;mysql&amp;gt; &lt;strong&gt;SHOW VARIABLES LIKE 'max_allowed_packet';&lt;/strong&gt;
+--------------------+----------+
| Variable_name      | Value    |
+--------------------+----------+
| max_allowed_packet | 16776192 |
+--------------------+----------+
1 row in set (0.00 sec)&lt;/pre&gt;
&lt;p&gt;If your data exceeds &lt;em&gt;max_allowed_packet&lt;/em&gt;, you probably don't get any errors returned from &lt;em&gt;send_long_data()&lt;/em&gt; or &lt;em&gt;execute()&lt;/em&gt;. The saved blob is just corrupt!&lt;/p&gt;
&lt;p&gt;Simply raise the value &lt;em&gt;max_allowed_packet&lt;/em&gt; to whatever you'll need. If you're not able to change MySQL's configuration, you'll need to send the data in smaller chunks:&lt;/p&gt;
&lt;pre&gt;	$fp = fopen("osaka.jpg", "r");
	while (!feof($fp))
	{
		$stmt-&amp;gt;send_long_data(0, fread($fp, 16776192));
	}&lt;/pre&gt;
&lt;p&gt;Usually the default value of 16M should be a good start.&lt;/p&gt;
&lt;h3&gt;Retrieving the blob&lt;/h3&gt;
&lt;p&gt;Getting the blob data out of the database is quite simple and follows the usual way of MySQLi:&lt;/p&gt;
&lt;pre&gt;&amp;lt;?php
	$mysqli=mysqli_connect('localhost','user','password','db');
	if (!$mysqli)
		die("Can't connect to MySQL: ".mysqli_connect_error());
	$id=1;
	$stmt = $mysqli-&amp;gt;prepare("SELECT image FROM images WHERE id=?");
	$stmt-&amp;gt;bind_param("i", $id);
	$stmt-&amp;gt;execute();
	$stmt-&amp;gt;store_result();
	$stmt-&amp;gt;bind_result($image);
	$stmt-&amp;gt;fetch();
	header("Content-Type: image/jpeg");
	echo $image;
?&amp;gt;&lt;/pre&gt;
&lt;p&gt;Connect to the database, prepare the SQL statement, bind the parameter(s), execute the statement, bind the result to a variable, and fetch the actual data from the database. In this case there is no need to worry about &lt;em&gt;max_allowed_packet&lt;/em&gt;. MySQLi will do all the work:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://oswaldatwork.thetaoofamp.com/wp-content/resources/_3925128491.jpg" border="0" alt="3925128491.jpg" width="600" height="399" /&gt;&lt;/p&gt;
&lt;h3&gt;By the way...&lt;/h3&gt;
&lt;p&gt;If you want to insert a blob from the command line using MySQL monitor, you can use &lt;em&gt;LOAD_FILE()&lt;/em&gt; to fetch the data from a file:&lt;/p&gt;
&lt;pre&gt;mysql&amp;gt; &lt;strong&gt;INSERT INTO images (image) VALUES( LOAD_FILE("/home/oswald/osaka.jpg") );&lt;/strong&gt;&lt;/pre&gt;
&lt;p&gt;Be aware that also in this case &lt;em&gt;max_allowed_packet&lt;/em&gt; limits the amount of data you're able to send to the database:&lt;/p&gt;
&lt;pre&gt;mysql&amp;gt; &lt;strong&gt;SHOW VARIABLES LIKE 'max_allowed_packet';&lt;/strong&gt;
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| max_allowed_packet | 7168  |
+--------------------+-------+
1 row in set (0.00 sec)
mysql&amp;gt; &lt;strong&gt;INSERT INTO images (image) VALUES( LOAD_FILE("/home/oswald/osaka.jpg") );&lt;/strong&gt;
ERROR 1048 (23000): Column 'image' cannot be null
mysql&amp;gt; &lt;strong&gt;SET @@max_allowed_packet=16777216;&lt;/strong&gt;
Query OK, 0 rows affected (0.00 sec)
mysql&amp;gt; &lt;strong&gt;SHOW VARIABLES LIKE 'max_allowed_packet';&lt;/strong&gt;
+--------------------+----------+
| Variable_name      | Value    |
+--------------------+----------+
| max_allowed_packet | 16777216 |
+--------------------+----------+
1 row in set (0.00 sec)
mysql&amp;gt; &lt;strong&gt;INSERT INTO images (image) VALUES( LOAD_FILE("/home/oswald/osaka.jpg") );&lt;/strong&gt;
Query OK, 1 row affected (0.03 sec)&lt;/pre&gt;
&lt;img src="http://feeds.feedburner.com/~r/oswaldatwork/~4/cPCfahrgyl4" height="1" width="1"/&gt;</content>
		<link rel="replies" type="text/html" href="http://oswaldatwork.thetaoofamp.com/2009/11/php_s_mysqli_extension_storing/#comments" thr:count="5" />
		<link rel="replies" type="application/atom+xml" href="http://oswaldatwork.thetaoofamp.com/2009/11/php_s_mysqli_extension_storing/feed/atom/" thr:count="5" />
		<thr:total>5</thr:total>
	</entry>
	</feed>
