<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Brian Bell &#187; google charts</title>
	<atom:link href="http://webguru.org/tag/google-charts/feed/" rel="self" type="application/rss+xml" />
	<link>http://webguru.org</link>
	<description>Bits of web-dev, travel and personal musings...</description>
	<lastBuildDate>Mon, 09 Nov 2009 21:36:16 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.5</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>How to use Google Charts API in your Secure, HTTPS webpage</title>
		<link>http://webguru.org/2009/11/09/php/how-to-use-google-charts-api-in-your-secure-https-webpage/</link>
		<comments>http://webguru.org/2009/11/09/php/how-to-use-google-charts-api-in-your-secure-https-webpage/#comments</comments>
		<pubDate>Mon, 09 Nov 2009 21:36:16 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[LAMP]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[WebDev]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[google charts]]></category>
		<category><![CDATA[https]]></category>

		<guid isPermaLink="false">http://webguru.org/?p=42</guid>
		<description><![CDATA[So you love Google Charts API and want to spice up your app with lots of pretty bar charts, Venn diagrams, Google-o-meters and 2D bar codes (QR Codes) &#8211; only problem is, you require that users connect to your site using a secure connection (https://yoursite.com/whatever).  Well, as you are probably aware, the Google Charts [...]]]></description>
			<content:encoded><![CDATA[<p>So you love Google Charts API and want to spice up your app with lots of pretty bar charts, Venn diagrams, Google-o-meters and 2D bar codes (QR Codes) &#8211; only problem is, you require that users connect to your site using a secure connection (<strong>https</strong>://yoursite.com/whatever).  Well, as you are probably aware, the Google Charts API doesn&#8217;t ex</p>
<p>actly support SSL connections&#8230; directly.</p>
<p>Have no fear! If you are willing to give up a little bit of your own bandwidth, you can work around this problem.  We are going to do this using a simple PHP script and if you want to get really fancy, Memcached to keep the redundant API calls to a minimum.</p>
<p>Let&#8217;s get started.<br />
<span id="more-42"></span><br />
First, let&#8217;s make sure we understand why it is a problem to include a non-secure Google Charts API into your otherwise secure page.  When your users are browsing to your page using an address starting with <strong>https://</strong>, their browser is going to negotiate an TLS/SSL connection which will encrypt all the data flowing between your client and the server.  If any element on the page (image, external CSS or JavaScript, etc.) is not being called from a secured connection as well, then the browser will throw up a warning.  Each browser is different, but most will alert the user with a broken lock and/or a popup message.  The user can usually accept this warning and proceed at their own risk, but this is not acceptable for a production website or application.</p>
<p>The obvious answer to this problem is to make sure that all external elements on the page are loaded over a secure connection.  So &#8211; how do we do that with Google Charts? Google does not allow you to just take a traditional API call and slap a &#8220;https://&#8221; in front of it in lieu of the expected http://.  Your request will be <strong>denied</strong>.</p>
<h2>Basic Implementation</h2>
<p>Here&#8217;s what we do:</p>
<ol>
<li>Create a simple PHP script that will fetch a chart from Google Charts API</li>
<li>Change your web page to call the new PHP &#8220;fetcher&#8221; instead of Google Charts directly.</li>
<li>Make sure the PHP script is being called by your page over your https:// connection</li>
</ol>
<p>It is pretty much that simple.</p>
<p>Here is the before example:</p>
<pre class="brush: xml;">
&lt;!-- HTML snippet --&gt;
&lt;img src='http://chart.apis.google.com/chart?cht=p&amp;chd=s:Uf9a&amp;chs=200x100&amp;chl=January|February|March|April' alt='Pie Chart'/&gt;
</pre>
<p>Here is the after example:</p>
<pre class="brush: xml;">
&lt;!-- HTML snippet --&gt;
&lt;img src='https://mywebsite.com/gchart.php?api_url=http%3A%2F%2Fchart.apis.google.com%2Fchart%3Fcht%3Dp%26chd%3Ds%3AUf9a%26chs%3D200x100%26chl%3DJanuary%7CFebruary%7CMarch%7CApril' alt='Pie Chart'/&gt;
</pre>
<p>Notice, the same API URI is used in the &#8220;after&#8221; example, <strong>but it is URL Encoded</strong>.  This just makes it safer to pass along to the PHP script.</p>
<p>Here is the PHP script that makes this work:</p>
<pre class="brush: php;">
&lt;?php

$url = urldecode($_GET['api_url']);

$image_contents = file_get_contents($url);
echo $image_contents;
exit;
</pre>
<p>A quick note about this: you may be saying &#8211; where is your closing PHP tag!?!  Well, PHP doesn&#8217;t require that you have a closing PHP tag, as the PHP interpreter will automatically close any open tags.  I do this on just about every file that will be used as an include of some sorts &#8211; particularly in something like this where any extra, inadvertent white space at the end of the file can alter the output adversely and cause errors in the page.</p>
<h2>Advanced Implementation w/ Caching</h2>
<p>The script as it is above, is fine and dandy, but terribly inefficient.  You see, every time the user requests the page, your script is going out and using <strong>your bandwidth</strong> to make the request to the Google Charts API instead of the client.  You are becoming the proxy for all requests to and from Google Charts.  This will not fly &#8211; especially if you are in a high volume environment.</p>
<p>So what is the solution? I chose Memcache to store a copy of the image contents for a certain period of time before having to re-query the Charts API and re-fetch the data again.</p>
<p>It looks something like this:</p>
<pre class="brush: php;">
&lt;?php

$url = urldecode($_GET['api_url']);
$cache_key = md5($url);
$item_cache_expire = 3600;
$mc_host = '127.0.0.1';
$mc_port = 11211;

# Connect to Memcache
$memcache = new Memcache;
$memcache-&gt;connect($mc_host, $mc_port) or die (&quot;Could not connect&quot;);

if ( $get_result = $memcache-&gt;get($cache_key) ) {
    $image_contents = $get_result-&gt;chart_image;
}
else {
    $image_contents = file_get_contents($url);

    $tmp_object = new stdClass;
    $tmp_object-&gt;chart_image = $image_contents;

    $memcache-&gt;set($cache_key, $tmp_object, false, $item_cache_expire) or die (&quot;Failed to save data at the server&quot;);

}
echo $image_contents;
exit;
</pre>
<p>Here&#8217;s what is happening. </p>
<pre class="brush: php;">
&lt;?php

$url = urldecode($_GET['api_url']);
$cache_key = md5($url);
$item_cache_expire = 3600;
$mc_host = '127.0.0.1';
$mc_port = 11211;
</pre>
<p>Setup some variables we&#8217;ll need in the script.  Grab the api_url value from the GET array, create an MD5 hash of the request URL (we&#8217;ll use this as our memcache item key), set the expiration time of the cached item to 3600 seconds (a.k.a. 1 hour) and finally provide the connection information to your memecached server. </p>
<pre class="brush: php;">
# Connect to Memcache
$memcache = new Memcache;
$memcache-&gt;connect($mc_host, $mc_port) or die (&quot;Could not connect&quot;);
</pre>
<p>Instantiate a new Memcache object using the connection info provided above.</p>
<pre class="brush: php;">
if ( $get_result = $memcache-&gt;get($cache_key) ) {
    $image_contents = $get_result-&gt;chart_image;
}
else {
    $image_contents = file_get_contents($url);

    $tmp_object = new stdClass;
    $tmp_object-&gt;chart_image = $image_contents;

    $memcache-&gt;set($cache_key, $tmp_object, false, $item_cache_expire) or die (&quot;Failed to save data at the server&quot;);
}
</pre>
<p>Using the MD5 hash that we created above, check to see if there is a valid cached object on the memcache server for us to retrieve.  If not, go out and grab a fresh version from Google Charts API and stick it into memcache.  Either way, we end up with a variable $image_contents which contains the desired chart image.</p>
<pre class="brush: php;">
echo $image_contents;
exit;
</pre>
<p>All that is left to do now is print out the image contents and exit the script.  Again, I do not use a closing PHP tag on purpose to avoid extra whitespace.</p>
<h2>All ye, all ye, now hear this&#8230;</h2>
<p>This is a very basic example.  It should probably be categorized more as a proof of concept. It does NOT, I repeat &#8211; DOES NOT &#8211; take into account a variety of security concerns such as SQL injection or CSRF (cross-site request forgeries), etc. Notice that I didn&#8217;t even validate the user input from the GET variable.  Who does that!?!  So, in other words, don&#8217;t just copy and paste and then come back and blame me for getting your site hacked.  Be smart about employing something like this.</p>
<p>BTW, if you want to know more about how to make your PHP scripts more secure, go see Chris Shifflet&#8217;s excellent blog at <a href="http://shiflett.org/" target="_blank">http://shiflett.org/</a>.  </p>
]]></content:encoded>
			<wfw:commentRss>http://webguru.org/2009/11/09/php/how-to-use-google-charts-api-in-your-secure-https-webpage/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

