What I Learned Today - CFEXECUTE is not Unix-friendly

Update: Based on a conversation with Paul Kukiel, this issue does not seem to exist in Ubuntu Linux. Definitely confirmed in Solaris, unsure about other Unix flavors.

For the first time ever, I needed to use the oft-maligned CFEXECUTE tag on a project. I was developing an intranet application to track the health of about 30 Unix-based servers in real time, using a variety of metrics. The application also resides on a Unix server.

One of the metrics was to ping the servers to make sure they are up. That required the usage of CFEXECUTE to run a shell script I had written to do the task.

The first issue I found was that on Unix-based systems (OS X and Unix), the tag was not returning the ping results to me, even though I was using the variable attribute. The variable was empty. After hours of trying, I ended up writing the contents of the ping to a file to read. That led me to my second issue.

My first choice was to write to the virtual filesystem. The thought was that since I would be doing 30 pings every five minutes it would be best to not have to make all those writes to the disk. The problem that brought about was that if the ping took too long to finish, CFEXECUTE wasn't waiting around for the script to finish before moving on. If the server was down it could take up to 20 seconds for the ping failure to come back. Forcing the application to wait that long every time around wasn't the answer, so I had to step back and look at the solution again.

While focusing on other aspects of the application, I ran across the third and largest issue with CFEXECUTE - it's a resource killer of alarming degree on Unix. CFEXECUTE uses the fork() method to run processes. I have found the following warning (in various forms) on multiple blogs and message boards regarding this.

"Because of the way the fork() method was implemented on unix systems (which is what cfexecute calls under the hood to run the external process) it duplicates the amount of memory of the calling process to run the external process, which is crazy. So, for example, if your JRun process is currently taking up 1 GB of RAM (a pretty common JVM size), then cfexecute will run the external process using 1 GB of RAM, which will very quickly throw an Out of Memory exception."

I ran into this problem on our QA server, which only has 384MB of swap space free and only 4GB on onboard memory. Our JVM is set for 1GB minimum so there was no way CFEXECUTE would find the space needed to make the duplicate environment.

Once I learned about this, I quickly decided to pull CFEXECUTE altogether. Instead I have a cron job that runs once a minute and outputs the ping results for each server to a separate file on the hard disk, overwriting existing files to limit space usage. The application will read these files in, and they're real-time enough in that 3-4 updates will have been made to the ping statuses by the time the next background polling is done by the application to read in the files.

I now completely understand why so many hosting services disable this tag. In addition to the security risks inherent to it, the toll it can take on your server (unless it's loaded up big time in memory) just is not worth it when there are other options to solving the problem.

Question on Managing 404 errors

I have a bit of an issue I was wondering if someone had an answer for.

I have a requirement to develop a custom 404 error handler to trap and handle 404 errors for CFM and CFC templates. That part is simple.

It also needs to still log the 404 error in the web server logs (Websphere/Apache) like it did before, for reporting purposes. That part is the sticking point.

First off, I found that setting a 404 error handler inside the CF admin will do one of two things, all based on what the error handler file does. In the first test case, the error handler logs the error in the CF logs, and then uses CFINCLUDE to display a styled error page. Because CF has now handled the file request with a fully working and existing template, it no longer tells the web server to log it as a 404 error. The web server now treats this as a 200 OK response.

Test case #2 is an error handler that logs the error, then uses CFLOCATION to send them to a safe place. Apache logs that as a 302 code for the redirect. It is interesting that CF can differentiate this, but there still is no way to alter this that I can determine.

I then took to setting up Apache's 404 error handling. I was able to get it to point to my CF 404 error handler template, which at first I thought would solve all the problems for non CFM/CFC templates. But then I found two major flaws in that.

Firstly all the Apache 404 error handler does is redirect the request to the error handler, again identifying it as a 302 status code instead of a 404.

The second issue is that it redirects the request so that CF has no way to get to the information regarding the file that was not found. When triggered through the CF admin 404 error handler, the error template has access to the CGI scope for the request to the missing file, which is how we properly log the request. Apache just does a redirect, leaving behind no CGI scope information that identifies the missing template. There is no HTTP_REFERER value, and the rest of the CGI scope refers to the error template itself, making it useless for us to use for logging.

And the Apache 404 error handler did NOT handle CFM or CFC files either. That surprised me.

So, I'm looking for any other options here to get it logged in the access_log file as a 404 while still handling and dealing with the error.

Thoughts?

My embracing of the init() function

This entry comes from the "better late than never" department.

For years I have been coding with ColdFusion components. And for years I have resisted the calls to use an init() function, mainly because none of my components to date had ever been initializing anything. I would either pass in arguments to functions as needed, or I would use the application scope for things like datasources or file directories. It was one of those "What good is it?" type of deals.

Well, for the first time I am working on a project that I might decide to release out to the public if it goes as I hope. It's an error-handling project, based on methods I have been using for over six years now. So my thoughts have turned to how to make this portable, not just to my sites where I have a very consistent approach to coding but to others who probably code completely differently from me. I wanted to keep databases out of this project (what good is an error handler storing errors in a database if the database is the problem, and also as another way to make it portable) so I am using an XML file for configuration information. Where best to read this in? An init() function! Now I have my first need of it and am using it.

In the course of my research on best practices for using it, I ran across the Object Oriented ColdFusion site and their writeup on using init() had this in it:

"When you first create a new component the init() function may have no apparent need, but as your application grows you may find that your component changes and you need to initialise your objects into a particular state."

That struck a chord in me, and so from this point forward I am embracing the standards of using an init() function in every component I write, even if at the time it does nothing. I may be slow to change, but I'm not completely stubborn. Some of the time, at least.

What I Learned Today - Tesing IE7 - IE9 in one place

This probably isn't news to many of you, but I am one of those that actively avoids Internet Explorer as a browser. In fact it's fair to say that 99% of my usage of IE comes either from testing for cross-browser support or connecting remotely to the servers at work (considering that the education field is so Mac-friendly, it's somewhat ironic that ED itself has practically no support for Macs).

That being said, I am a very vocal advocate of cross-browser support for all major browsers. Based on the logs for the sites I host and at work, that means supporting IE7 and IE8, which account for about 60% of the traffic on average combined. Thankfully IE6 is down to less than 5% overall usage, so it's off my radar unless explicitly asked for (thank God!). But IE9 has started to catch on since it's release, with about the same usage rate as IE6 but trending upwards.

Knowing that I will be needing to support IE9 going forward for my own work (and guessing that a mandate to support it is not too far off at my day job), I recently upgraded my VM from WinXP to Win7, and installed IE9 on it. I then was going to install the IE Collections software package to get all the IE browsers I needed, as I did on WinXP, when I learned that this was no longer needed for me.

IE9 has a Developer Toolbar like Firefox and Chrome, accessed by the F12 key. On it is the option to choose what version of IE to render the page in. You can choose IE7, IE8, or IE9. No more third party software for this task!

As much as it pains me to say this, Microsoft actually got something right with this one.

For those not on IE9, I would recommend giving the IE Collections site a look. It's a hack for them to be able to have multiple versions of IE on one machine, but it always worked for me.

In search of... a truly good jQuery rounded corners plugin

So a while back I blogged about a jQuery plugin I used for rounding corners, the CurvyCorners plugin. At first I thought it was great, and I have used it on two sites since finding it. But I have also found that this plugin does not play nice with IE 6-8. There are a lot of headaches involved with those browsers.

Here is a list of the issues and/or tradeoffs I had to make to get this to work in IE 6-8. Keep in mind I never ran into these issues with Firefox, Safari, or Chrome during testing.

  1. In IE 6-8, you cannot use this tag with a fluid box. Whatever proportions the box is when you load the page, that is how they will remain no matter how you resize your browser. This was not a problem for one site that had a fixed width design, but for the one that did have it, I had to turn it into a fixed width design for IE browsers using some conditional comments and CSS. I picked a width that will work for the amjority of screens, but I don't like that I had to do it to begin with.
  2. I ran into a problem where a page using jQuery for a form was not executing the jQuery (in a document.ready() block in a SCRIPT tag placed in the HEAD tag by a CFHTMLHEAD call) the first time you went to the page after opening an IE 6-8 browser. Refreshing the page or clicking a link to go to the page again fixed it, but that very first time it would not work. In the end, the issue was that I had placed the call to this plugin before the jQuery code block. I cannot fully understand why that was a problem, but because of that, the corner rounding was somehow blocking the rest of the cript being processed by the browser, for some reason. The fix for this was to place the call to the plugin as the very last tag in the HEAD. For whatever reason, that solved it.

As of today, my postings of these issues to the CurvyCorners Google Groups support forum have gone unanswered.

Because of these, I am now in search of a better solution if one exists. I could code the CSS manually, but now that I know these quicker solutions are out there my desire to do it longhand has faded. I also hate making tradeoffs when I know it should not be neccesary.

Comments are moderated solely for spam-prevention purposes.

Two jQuery plugins that saved my weekend

A client made some requests to alter his site. The two main things requested were using rounded corners for the container that the site content sits in, and the redoing of some images on the site, and having them rotate through to provide some animation.

Normally I would use the tried and true methods of creating rounded corners in photoshop, and then having to redo the container div into multiple divs to properly set them for that task. On a whim, I decided to do some searching for other ideas.

In comes jQuery to, once again, save the day. I found the Curvy Corners plugin (http://curvycorners.net/) which did this task cross-browser in about 15 minutes, give or take. Thank you very much, I'll move on.

For the animating of the images, in years past, animated GIFs or Flash was the medium of choice. But I wanted other options, especially since the Flash wouldn't be supported on anyone viewing in iOS. Again, a Google search turned up a jQuery plugin to take care of things. This time it was the Cycle plugin (http://jquery.malsup.com/cycle/). Another 15 minutes (10 of that to write a quick randomization block in CF), and task #2 complete.

If it wasn't for having to tweak 41 images in Photoshop, I'd have been done inside of an hour! Thanks jQuery! (again)

Shifting my focus a little...

(Google had this cached, so I am reposting since this got lost in the server crash)

For pretty much my entire career, I have always been more of a backend developer. I would rate myself as "good" to "very good" in that arena, especially in ColdFusion. I'm not the elite level that is always on the cutting edge, but I provide solutions that work with always a thought to performance.

But when it comes to design and front-end, I'm average at best. Creativity has always been a problem for me. I have passable graphics design skills, but mainly when given ideas first.

I also have been held back by my work environment. The last five years I have spent working as a contractor for the Federal Government. That means front-end design is done to the lowest common denomenator. For a long time, that meant things like tables instead of CSS, little or no JavaScript because everything had be coded to work with or without JavaScript, and often times projects couldn't afford the hours needed to code things twice. And most important, Section 508 accessibility standards and a mandate that sites must work in a lot of really old browsers (as far back as Netscape 4 and IE5) the same as they would in modern browsers.

Recently, the noose there has been loosened some. The oldest browser we have to accomodate now is IE6. Still means a lot of potential issues, but less than before. CSS-driven sites are now options. Solutions I have proposed that use jQuery and AJAX are gaining more traction, and in a few rare cases an assumption that JavaScript must be enabled in order for the site to work have been added to requirements documents. On the backend, until yesterday I was stuck using CFMX7. Now we have CF9 at our disposal!

So what does this all mean? A chance for me to start spreading my wings on the front end. I have had some chances to tinker on side work that I do from time to time, and while they like the solid backend processes that I can offer them (making sites not just a marketing brochure, but a tool for their business) they are seemingly most keen on a catchy design that is pleasing. To accomodate this, I find myself wanting to build more in my design arsenal. I look at a lot of sites I find aesthetically pleasing and I'll jump in with Firebug and figure out what they are doing.

One design style I have become drawn to are sites built around large photographs as a background. I really think this is an easy way to spice up a site, and it's become so easy to optimize photos for the web that you can get great images at very little file size cost. I've taken to using "sprites" and CSS for not just navigation bars, but headers and other common elements to allow for a more graphically pleasing site with less of a file size hit only having to load one image for use in multiple places. And since everything I design is checked for 508 compliance, and tested with all styling turned off, I know that the important information will be found by everyone no natter what (and that spiders will read the site properly as well!

I am a huge fan of jQuery, and I know I have only scratched the surface in terms of its capabilities. If it is feasible, using AJAX and minimizing page reloads is a preference of mine, one I'd like to find more uses for.

In all of this though, I try and keep one overridding thought in my head: "Is there a need for this?" and "What makes sense here?". It's my logical brain getting in the way of my creative brain, I know, but I can see how easy it is to get carried away with bells and whistles. But in the end, the goal of the site is to impart information to the users, so it is most critical that the information be easily found.

In the end, I'll never probably be an elite level front-end or back-end developer. But if I can become "good" or "really good" on both sides of it, I think that can be quite a good calling card for the long run.

Comments are moderated solely for spam-prevention purposes.

What I Learned Today - MAMP Pro and SSL

A couple of projects I work in involve using SSL in some places. For the longest time I could never get SSL to work right with MAMP PRO (I have v1.84). Today I ran across a blog post that finally got it working for me.

http://www.rockettheme.com/blog/coding/310-getting-ssl-to-work-with-mamp-pro

Google Chrome and missing form fields

On a legacy application that I maintain, I have seen a rash of errors recently that are new. They are all in regards to form fields missing on a form action page. The things that make this one different is that:

  1. The fields in question are empty text fields, not unchecked radio buttons or checkboxes.
  2. The browser type of all these errors in Google Chrome

Now, while the fix is the same for all of these issues (CFPARAM the form fields), I was wondering if others have been seeing this with Chrome at all, and if there's any insights as to why Chrome seems to not want to pass along empty text fields, like every other browser out there does. I have not played with Chrome at all, and our applications do not officially support that browser at this time, so I can't spend much time at all investigating these errors in light of that. So I am hoping that some of y'all might have some information you would be willing to share?

Learning PHP: Where's the security?

A couple of things have struck me so far as I have been trying out basic tasks in PHP to get a feel for how they work. One immediate concern I have right now is database security in PHP.

The first red flag I have is PHP's insistence that you type in a username and password for the database user in the clear in your database connection code. To me this is just asking for potential trouble. Let's toss out this scenario - disgruntled PHP developer gets the boot. You now have to go and change the database username and/or password on the server in order to make sure things are secure, because that coder has the information he or she needs to get in and screw with the database, not just via PHP code, but with any client tool (assuming they have access inside your network, and let's be honest rarely is there a time when a disgruntled employee isn't that way while still being employed). Even if you code smart and just include your database connection strings in a function so you only have to make the change in one place, it's still a change that shouldn't have to be made.

Compare this to CF, which sets the database access information in the datasource creation in the CF admin. This allows a lot more internal security, as the only people that really need to know that access information are the DBA and the CF administrator (in many cases I imagine this may be the same person). The point is that you can really compartmentalize this information a lot better in CF than you can in PHP. The developers need only know the datasource name, nothing about usernames or passwords are passed along in that. In the case of the disgruntled employee, their access to teh database comes in a totally separate login that can be more quickly locked down without affect to other accounts and applications in the case you need to do so.

The other thing that so far has struck me (and I am sure that this is a pure lack of PHP knowledge on my part, but...) is that there does not seem to be a PHP answer to CFQUERYPARAM in terms of speed and simplicity for locking down your SQL queries from injection attacks. It looks like I need to dig into the mysqli() functions from what I can tell, but they don't seem as clean as CFQUERYPARAM is. File this one not so much under "PHP can't do this", but under the growing list of "PHP takes a lot longer to do this than CF".

Thoughts are appreciated on how or why this impression is incorrect.

More Entries