Making a Server Side Image Cache in PHP

Tagged:  

Yesterday, I wrote about an application that I wrote called scovry and I mentioned that in writing the application I used a lot of caching. This included caching of images from an external thumbnail service server.

I thought that I would post the code that I am using to do this and quickly go over how it works. This code might be useful to any application that loads images from another server, to lessen the dependency on the other server. Below is the code that caches the images.

<?php
$imageurl =urldecode( $_GET['imageurl']);

$cachefile = 'caching_folder/'.urlencode($imageurl).'.jpg';
$cachetime = 604800;
// Serve from the cache if it is younger than $cachetime
if (file_exists($cachefile) && time() - $cachetime < filemtime($cachefile)) {
    header("Content-type: image/jpeg");
    readfile($cachefile);
    exit;
}
ob_start(); // Start the output buffer

$imginfo = getimagesize($imageurl);
header("Content-type: image/jpeg");
readfile($remoteImage);

// Cache the output to a file
$fp = fopen($cachefile, 'wb');
fwrite($fp, ob_get_contents());
fclose($fp);
ob_end_flush(); // Send the output to the browser
?>

The above code is used like an image proxy, but it adds the benefit of doing the image caching. So, the first thing to notice is that in my application the imageurl variable that is passed in through the url query string is an encoded url, so we decode it. This variable will hold the url encoded url of the image that we want to load. You may also notice that this code assumes that the image is a JPEG image, because that is what I was always going to be dealing with. So, if you use this code, you may need to add code to handle other image types.

The next import variable is the $cachetime as it sets how long (in seconds) the image will be cached before the cache is refreshed. The if statement checks if it should load the image on disk. The important part here is that it sets the document header content type to be an image and then loads the image using the readfile() method.

Now If the file does not exist or if it needs to be re-cached it loads the file from the server and writes it to the output buffer. Once again the document header content type is set to an image value and it gets the file via the readfile() method. In addition to this it writes the file to disk using the fopen() and fwrite() methods.

That is basically all there is to it. You can take a look at it in action by checking out scovry.

What I Did on My Winter Holiday

This winter break (or as we used to call it when I was still in school, Christmas vacation), I worked on a little web application. The application was going to be for an automotive related blog that I write on, but once I started working on it I realized that the application was better if it wasn't restricted to just automotive information.

The application is called scovry and it is a web discovery application. You may notice that we at Ajaxonomy love spy applications (notice that in Ajaxonomy labs we wrote delicious Spy and TubeSpy). scovry is kind of a blend of these spy applications along with gathering information from many other social media sites and social networks. Beyond this the site adds a social element by allowing comments and easy sharing of items found on the site.

scovry

From a programming side, in order to load all of the data and keep the server happy I used a lot of caching. The caching code I used was based on the Easy Server Side Caching in PHP article that I wrote a while back. With some small changes, the biggest of which was using readfile() instead of include(). I even modified the caching script to cache images that are loaded from the thumbnail service to make loading much faster (not to mention to reduce requests for images).

You can check out scovry here.

JavaFX 2.0 Released

Tagged:  

Shortly after acquiring Sun, Oracle announced they would be dropping support for JavaFX Script, the domain-specific language that would have been the only way to write "Swing 2.0" applications. Instead, Oracle decided to start work on JavaFX 2.0, which would feature a Java-only API. The fruits of that effort were released today. You can download the SDK and code samples here.

Ever felt excited about a single line of code? Well this one

WebView view = new WebView();

did it for me. Since there are too many features to cover here, I'd recommend going to the web site or downloading the samples, launching ensemble.jnlp, and exploring.

Reloading in Java

Tagged:  

When Ruby on Rails was all the rage a few years ago, it really shook up the Java community. Many people tried to understand the impact of Rails, what made it so appealing, and how its success could be translated into Java. As a result of all this soul-searching, lots of reasons were given for Rails' popularity, but the most compelling one was the fact that its fast turnaround allowed developers to stay in the "hot zone" while they were coding: make a change and--bam!--see it instantaneously. This was, at the time, the very antithesis of the compile and (re-)deploy cycle that Java developers were used to.

But how could this be done in Java? It was certainly no easy task: though Java could load classes dynamically, redefining their definitions during execution was entirely another matter. In 2002 Sun had introduced a promising experimental technology in to the 1.4 JVM called Hotswap that was incorporated into the Debugger API. The idea was that you could recompile your code while you were still in debug mode and have the JVM pick it up instantly without needing a restart, thus enabling all kinds of developer productivity. The problem was, though, that Hotswap was very limited--it could only replace the body of a method--and most of the time you needed to restart the program anyway, so the productivity never really materialized.

Well, years passed (imagine a tableau of changing seasons) and Rails, though still a popular framework, never really gained the larger foothold among developers that its initial trajectory promised. The buzz died down, and Java developers by and large stuck to their old habits. But the promise of greater productivity in Java still remained, and has inspired a few to pursue it...

JRebel

One of those few is ZeroTurnaround, maker of the award-winning JRebel. (They've even released a free version recently, though it has a few string attached.) JRebel makes use of some pretty sophisticated classloading tricks (with just a dash of instrumentation) to accomplish dynamic reloading of class definitions: within the classloader, it uses one master class and several anonymous support classes backed by the JIT transformation runtime. JRebel has its limitations as well, most notably in the area of redefining class hierarchies.

JRebel is by far the most well-known product in this area, and presumably with the one with the most commercial success. But it does have competition...

FastSwap

Weblogic 10.3 (+) has a new feature called FastSwap. It has its limitations, but is generally a step forward--if you program on Weblogic, that is.

Javeleon

There's another product, Javeleon, which also does dynamic redefinition of Java classes at run time. Javeleon has been developed at the University of Southern Denmark in collaboration with Sun Microsystems/Oracle as a research project. It also claims to have advantages over JRebel and FastSwap in what type of redefinitions it can support at runtime.

DCEVM

But you're thinking: shouldn't this type of functionality just be provided within the JDK itself?

Well that's exactly what another, less-known alternative does: the Dynamic Code Evolution VM. DCEVM is a modification of the Java HotSpot VM (applied directly as a patch) that allows unlimited redefinition of loaded classes at runtime. DCEVM was developed as a research project of the Institute for System Software at the Johannes Kepler University Linz, and supported by Oracle and Guidewire Software.

In my personal experience with DCEVM (full disclosure: it is the only product listed in this article that I have direct experience with), I've found it to be really rock-solid and dependable. The only drawback that I have noticed is that it has stayed at version 0.2 for quite some time now, and seems to be slipping in its support of newer versions of the JDK. Now that one of the leads of the project (Thomas Würthinger) is an Oracle employee, one would hope that Oracle would eventually integrate this into the JDK itself. This would give all Java developers access to the amazing productivity gains that class redefinition provides.

Conclusion

Class redefinition is really a no-risk technology: in the worst-case scenario, the redefinition fails and you have to restart the Java program to debug--something you would have had to do anyway. So you really can't go wrong in upgrading your current option (Hotswap) with something far more capable. You won't just be saving yourself those reboots: you'll also be keeping yourself mentally in the "hot zone" where true productivity is found.

Proxy4J

Tagged:  

Proxy4J is a Java library for creating proxies. The project has recently released a stable snapshot (I'm not going to consider it "1.0" until the remoting is done). I originally created Proxy4J as a spin-off from my development on Workhorse, mainly because I wasn't really satisfied with other libraries out there that do proxying (the Commons Proxy library was the closest I could find, but its inability to leverage Java 5+ made it a non-starter).

Proxy4J was designed to allow you to quickly create a proxy for any one of a number of common use cases:

  • Virtual Proxies. Also known as delegation proxies, these proxies simply pass the method invocation directly to the "real subject", which may have some indirection in how it is created or fetched (e.g. the classic lazy-loading proxy).
  • Invocation Handlers. These are a direct parallel to proxies in the JDK, with a slight twist to include type safety in the common case where only one interface is being proxied. Method calls on these proxies are passed to an invocation handler which decides how to handle the call.
  • Interceptors. These are proxies where one or more interceptors may get called prior to invoking the method on the "real subject". In Proxy4J interceptors are very granular and may be specified on a per-method basis.

Interceptors in particular are pretty slick: they allow you to keep a stack of MethodInterceptors (note that the library supports the AOP Alliance API), which are invoked in order prior to invoking the intercepted method. Proxy4J allows different underlying implementations, including CGLIB, Javassist, and the built-in proxying in the JDK itself.

Documentation for Proxy4J can be found here. You can also download the jar here.

Firefox 6 Released

The much anticipated Firefox 6 release is out. In keeping with its new Chrome-like strategy, Mozilla has done away with large, major releases and is instead releasing on a faster, more "agile" schedule, releases batches of features and improvements as they get fully baked.

So What's New?

  • Mozilla claims that Firefox 6 is 20% than Firefox 5. This is a nice speed boost.
  • The new JavaScript scratchpad (in Web Console). Yes, LISP fans, JavaScript now has a REPL. Awesome. This should prove to be a really nice tool for web developers.
  • Added support for EventSource (server-sent events). This API permits push notifications from the server in the form of DOM events.
  • A touch event for touch-sensitive screens.
  • Support for the latest draft of WebSockets.
  • The result of a media query string can be evaluated programmatically using the window.matchMedia() method.
  • Support for HMTL 5's progress element has been added.
  • Support for HTML 5's track element has been added.
  • A host of -moz-* CSS properties for styling progress bars, text decorations, and hyphens.

The release notes are here.

Java 7 Arrives

Tagged:  

5 years since its last release, a new Java release finally gets out of the gates. Though less ambitious than the initial plans for the new release, it is shipping now--and, as a wise man once said, shipping is a feature. Oracle clearly recognized this after taking over at the helm of Java, and paired down the feature list in order to get some of the momentum that Java had lost in the waning years of Sun. Java 7 is hence being billed as an evolutionary release (that's code for "no lambdas yet"); nevertheless it is a much bigger step forward than Java 6 was, and a push that the platform really needed.

Getting a Google+ Invite

Tagged:  

Right now It seems that everyone that is not on Google+ wants to be on Google+. I personally just received an invite and have been playing with the service this morning.

So far I have found Google+ to be a good social network, but I'm not sure yet if it will be a Facebook or Twitter killer. I think it might be incredible, but as we all know the most important thing in a social network is the size of the network. So, we won't really know how well Google+ will do until it is released to the entire public.

In the mean time everyone wants to be in the fairly exclusive club of people that have received invites. If you happen to be in the tech industry then you probably know someone that has an account. The key to getting an invite (outside of trying one of the many hacks that has been published) is simply to ask all of your friends. The chances are that after you check with all of your friends that someone will at least know someone that has an account and can be your ticket to an invite. So, before you can get on this social network (at least in it's early form), you will need to be social and network.

Generating Email with View Engines

Tagged:  

Recently in working on a C# MVC project I had an issue with how outgoing e-mails where formed. The e-mails where all formed through a large string that contained all of the formatting XHTML. This began to become very messy and very hard to deal with. Since the project was a MVC project I thought it would be cool if I could just use a View for the e-mail template.

Well, over at Channel 9 Andrew Davey has a good presentation about solving this very problem. Below you can watch the presentation.

jQuery Dialog Box Tutorial

Tagged:  

Recently on a coding project for my day job I had a requirement to display a dialog box to confirm that when someone clicked a cancel link that they meant to do the cancel action. The dialog box was on a page that built a list of links with multiple cancel links, each with a different url. Since we are using jQuery and since I didn't want a browser dialog box to display I decided to use the jQuery dialog box.

Since I am a firm believer in the first rule of programming (never re-write something that has already been written) I did a quick Google search and found a good example of the jQuery dialog box for when a form is submitted at jensbits.com. The code was close to what I wanted to do, but not exactly. So, I took the code and modified it to work for me.

Below is the portion of the jQuery code that I changed from the code in the jensbits.com post.


$(function(){
// jQuery UI Dialog

$('#dialog').dialog({
autoOpen: false,
width: 400,
modal: true,
resizable: false,
buttons: {
"Yes": function() {
$(this).dialog("close");
$(location).attr('href',$(this).dialog('option', 'anchor'));
return true;
},
"No": function() {
$(this).dialog("close");
return false;
}
}
});

$('.closebutton').click(function(){
$('#dialog').dialog('option', 'anchor', $(this).attr('href'));
$('#dialog').dialog('open');
return false;
});
});

My first modification was to have the dialog open when someone clicks on a link that has a closebutton class assigned to it. I also attached an anchor option to the dialog box that holds the href attribute value of the link.


$('.closebutton').click(function(){
$('#dialog').dialog('option', 'anchor', $(this).attr('href'));
$('#dialog').dialog('open');
return false;
});

The below code shows the setup of the buttons and the major change is that the "Yes" button sets the location attribute to the anchor option value that we set in the code above.


buttons: {
"Yes": function() {
$(this).dialog("close");
$(location).attr('href',$(this).dialog('option', 'anchor'));
return true;
},
"No": function() {
$(this).dialog("close");
return false;
}
}

Below is the code in the body of the html that sets up the links and the dialog box. Notice that each link has the class set to closebutton.


<a id="closebutton1" href="http://ocell.us" class="closebutton">Close</a><br />
<a id="closebutton2" href="http://wastingtimegames.com" class="closebutton">Close</a><br />
<a id="closebutton3" href="http://theporscheguys.com" class="closebutton">Close</a>
<div id="dialog" title="Cancel"><p><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 0 0;"></span> Are you sure you want to do that?</p><p>
If you are sure, click Yes.</p><p>If not click No.<p></div>

You can see the full demo code here. It is a text file for easy code viewing, but you can save it to your computer if you want to see it in action.

Syndicate content