Archive for the ‘Programming’ Category.

Problems with PHP’s get_browser() on openSUSE 11.2

I just spent way too much time trying to debug PHP’s get_browser() on an openSUSE 11.2 server. All I wanted to do was display a funny little note about what web browser a user was surfing with, as in, “You are using Opera… AWESOME! :-D”, or “You are using Firefox… good :-)”, or even, “You are using IE… that’s sad :-(“.

I had this working just fine on openSUSE 10.3 and openSUSE 11.0, but the 11.2 server was giving me “Default Browser” for any browser I used. I debugged and looked over the configuration/logs again and again, but for some reason it appeared that while get_browser() was seeing the correct php_browscap.ini file, something was going awry.

I finally stopped the debugging process when a Google search landed me on Jonathan Stoppani’s Browscap PHP Project. I made a few minor modifications to my code in order to use his class, and now my browser detection is working great – even on the stubborn openSUSE 11.2 server. Thanks Jonathan!

Volume discounts with PayPal Merchant Services

You’re probably not going to like this solution very much.

To set the scene, PayPal’s “Merchant Services” contains a fairly straightforward webapp to generate “Buy Now” and other such buttons. When we needed to sell a product at work, I figured that the steps would be as simple as:

  1. Generate the button
  2. Slap it on our website

Unfortunately for me, we were offering a volume discount (AKA, bulk rate) so that the price of the item was different depending on the quantity. After much mucking around in help pages and documentation, I found the “solution” in the PayPal Developer Community forums: Volume Discount with Shopping Carts

Long story short:

  1. Don’t use PayPal’s button generator
  2. Download the zipped HTML file referenced in the forum
  3. Read the HTML file and its source, giving you the knowledge to:
    1. Add some generically-written javascript functions to your site
    2. Create a custom HTML button (i.e., not generated by PayPal)
    3. Add the HTML inputs and inline javascript needed to drive the functions
  4. Tell your bookkeeper to double-check the payment amounts because any tech-savvy person could submit a form with whatever prices they please

The problem is that when using your own custom buttons, PayPal cannot do any validations on their end. You send them item names and amounts, and they’ll happily charge the customer for whatever happens to come across the wire. From my limited research, I think you can do this more cleanly if you implement your own shopping cart, and interface with PayPal in a more secure way.

But for the “simple” stuff, the best way to get started would be by perusing the PayPal Developer Central’s Simple Integration section. I found the HTML Variables for Website Payments Standard to be particularly useful. It really wouldn’t be that hard for PayPal to implement volume discount functionality on their end, but I suspect that maybe it’s something they are trying to sell in a “Pro” version.

jQuery: disable the submit button, but still send the button’s value

Solving the old user-hits-the-submit-button-twice problem is fairly easy using JavaScript and even easier using jQuery. Setting up a sequence like the following is no problem:

  1. User clicks the submit button
  2. Button becomes disabled
  3. The values of the form’s inputs are submitted

My problem is that disabling the submit button causes its value to not submit. Apparently no one else on the planet uses the submit button’s value because none of my Google searches revealed anyone caring about this in the context of using JavaScript to disable the submit button.

No doubt my custom framework could be better designed, but there are a few rare instances when I want to know whether a user submitted a particular form, or even which button in the form they used to fire the submit. If I disable the button, then I don’t get the button’s name/value and thus I lose information about what is happening on the user’s end.

I have two solutions to this problem, the first of which was inspired by Ryan’s comment to my initial draft of this blog entry.

SOLUTION #1: hide the submit button after click

$(document).ready(function() {
  $("input:submit").click(function (event) {
    $(event.target).addClass("Hidden");
    var form = event.target.parentNode;
    var msg = document.createElement("i");
    msg.innerHTML = "PROCESSING...";
    form.insertBefore(msg, event.target.nextSibling);
  });
  $("form").submit(function() {
    $(":submit:not(.Hidden)", this).attr("disabled", "disabled");
  });
});

You will note that I am making use of a CSS class that I’ve called “Hidden”:

.Hidden {
  display: none;
}

Now the sequence of events looks like this:

  1. User clicks the submit button
  2. The click listener runs a function that hides the submit button and replaces it with some italicized PROCESSING… text
  3. The submit listener then disables all other submit buttons
  4. The values of the form’s inputs are submitted, including the newly hidden submit button

SOLUTION #2: copy the name/value to a hidden element

This is my original, hacky solution:

$(document).ready(function() {
  $("input:submit").click(function (event) {
    var $submitName = event.target.name;
    var $submitValue = event.target.value;
    var $form = event.target.parentNode;
    $($form).append("<input type=\"hidden\" name=\"" + $submitName + "\" value=\"" + $submitValue + "\">");
  });
  $("form").submit(function() {
    $(":submit",this).attr("disabled", "disabled");
  });
});

Can you see what horrors I’ve wrought? Now the sequence of events looks like this:

  1. User clicks the submit button
  2. The click listener runs a function that copies the name/value of the clicked submit button to a hidden input which is appended to the form
  3. The submit listener then disables the submit button
  4. The values of the form’s inputs are submitted, including the new hidden input
  5. To the rest of my code, it appears as if the submit button’s name/value came through with everything else

Now don’t be stingy, man. Pass the data, dude.

Mediawiki extension WTFs

Had a number of WTF moments when looking for a wiki2pdf type of Mediawiki extension. I came across Pdf Export which seemed to be what I wanted. But as I looked over the extension, the WTFs began to pile up:

  • The required version of Mediawiki is 1.14, but the current version of Mediawiki is 1.13.3. WTF?
  • Okay, let me download the source… WTF? I’m supposed to copy-and-paste this into four different PHP files?
  • Interesting… there are edit links next to each block of code. Can I, an anonymous user, just edit this code? Ah, yes I can. WTF??

Looks like most extensions seem to be in an SVN repo, but Pdf Export does not appear to be among them. The main page for this extension lists the version as 2.0 (4-Nov-2008), but I’m not sure what that means if the distribution code is a publicly editable moving target.

I think what’s happening here is that the extension ecosystem is far more “organic” than I had anticipated. They seem to have made the task of collaborative programming as quick and open as wikis themselves. The concept is actually kind of cool.

Still, I’d rather install an extension with a pdf_export-2.0.tgz or something than copy code off a wiki that may or may not have just been modified by h4CK3R420.

How to check if a variable exists in PHP

Go ahead, look at the PHP type comparison tables and snicker over how the language is a cobbled-together hack. I still love it, but I did run into a little bit of confusion today. Here is the basic issue:

$a = null;
//$b = 42;

Simple enough; $a is set to null and $b is commented out and therefore does not exist. The problem is that I could not find an easy way to differentiate between those two states. Sadly, isset() returns false when a variable has been set to null. I scanned over the function list and googled around some, but could not find the sort of exists() or is_defined() function that I wanted.

Amusingly, is_null() returns true for both $a and $b, but PHP will spit out a notice about an “undefined variable” when you do is_null($b) (depending on your error_reporting configuration). So PHP knows the difference between a null’ed variable and one that has never been set… but how do I get access to that knowledge?

The best way I could find was to use get_defined_vars(). For example:

$a = null;
//$b = 42;
$arr = get_defined_vars();
if (array_key_exists('a', $arr)) echo "Yes, \$a exists!\n";
if (array_key_exists('b', $arr)) echo "This will not print.\n";

If anyone knows of a better way to do this, I’d love to hear it.

Using the QuickBooks SDK via JACOB Java-COM Bridge

So you want to be a hero?

You had better be prepared for a little heroics if you want to use the QuickBooks SDK with Java because it isn’t exactly straightforward. I saw a few mentions of people having done this, but certainly didn’t find any tutorials. Maybe I will be the first person on the planet to write this up. BOW TO YOUR NEW GOD!

Anyway, the problem is that the QBSDK is done with Microsoft’s COM and Java has no built-in COM support. I should mention that you can use Java with the Online Edition or apparently by setting up a Tomcat server and sending qbXML through a SOAP-to-COM pipe or something like that. In my case, I had a bunch of existing Java code that I wanted to connect as directly as possible to QuickBooks – preferably using QBFC.

If you don’t know what I’m talking about with QBSDK, qbXML, and QBFC then you should read this informative tutorial.

After hunting around the web, I found a free library called JACOB: Java-COM Bridge. The theory is that I could go from Java -> JACOB -> QBFC -> QuickBooks. I managed to create a proof of concept for this theory that I will begin sharing with you now.

SETUP

  1. Obviously, install QuickBooks, run its updates, and create a test company file (I’m using QuickBooks Premier Nonprofit Edition 2007)
  2. Sign up with the Intuit Developer Network and then download/install the SDK. Note that you must say “yes” to installing the .NET stuff or the install will fail. (I’m using QBSDK 7.0)
  3. Download and extract JACOB (I’m using version 1.14)
  4. Being on a 32-bit OS, I copied the x86 JACOB DLL (jacob-1.14-x86.dll) into C:\WINDOWS\system32
  5. For Eclipse users, go to the Java Build Path property, click the Add External JARs button, and add jacob.jar to your project. For non-Eclipse users, make sure that the JAR is in your CLASSPATH.

NOTES ABOUT JACOB

Obviously everything you do with the QBSDK must be enveloped by JACOB API calls. The main beasts in JACOB seem to be Dispatch and Variant. Basically, you’ll use Dispatch to call functions on COM objects, and Variant to serve as parameters and outputs to those functions.

While JACOB seems to work well for me so far, the project lacks documentation of the HOWTO/tutorial variety. By cruising the web for examples and looking over the API, you can sort of figure out how things work. As I was wrestling with it, I stumbled across a QBFC wrapper for Ruby. Looking at the project’s source code helped me figure out a couple of things in the JACOB-QBFC connection.

One thing that JACOB lacks is the ability to lookup COM constants. Some of the QBFC functions require you to pass in one of their constants – hard to do when you can’t access them. The workaround for this is in the How can I get the value of constants? question in the JACOB FAQ. In short, you are supposed to use the Visual Basic editor in Excel to open the “object browser”, search for the constant, read its value, then code it into your program. Not exactly an elegant solution, but oh well. Note that when you’re in the object browser, you’ll need to go to Tools -> References and add the QBFC7Lib.

THE FIRST TIME HURTS

The first time you connect to QuickBooks through your application, you need to have QuickBooks already running. If you do not, then you’ll get an error message like:

This application is not allowed to log into this QuickBooks company data file automatically. The QuickBooks administrator can grant permission for an automatic login through the Integrated Application preferences.

The reason is that QuickBooks needs to pop open a dialog box and ask you if the application is really allowed to connect. After you’ve registered your application with QuickBooks, you’ll be able to access the data without the need to open it first.

SHOW ME THE CODE!

This code assumes that you have some vendors defined. If all goes according to plan, then it should print out all your defined vendors. Note that I am not doing all the various error, status, and type checking that the documentation mentions.

import com.jacob.com.*;

public class Foo {
  public static void main(String[] args) {
    System.out.println("Hello world!");
    // QBFC constants looked up using the object browser
    Variant ctLocalQDB = new Variant(1);
    Variant omDontCare = new Variant(2);
    // major and minor version of qbXML used to talk to QuickBooks
    Variant qbXMLMajor = new Variant(6);
    Variant qbXMLMinor = new Variant(0);
    // location of the company file to access
    String qbFile = "C:\\Documents and Settings\\rdavis\\Desktop\\FfAMETest.QBW";
    // connect to QuickBooks
    Dispatch qbsm = new Dispatch("QBFC7.QBSessionManager");
    Dispatch.call(qbsm, "OpenConnection2", "", "My Sample App", ctLocalQDB);
    Dispatch.call(qbsm, "BeginSession", qbFile, omDontCare);
    // build and execute a request to obtain all vendors
    Dispatch msgSet = Dispatch.call(qbsm, "CreateMsgSetRequest", "US", qbXMLMajor, qbXMLMinor).toDispatch();
    Dispatch.call(msgSet, "AppendVendorQueryRq");
    Dispatch resSet = Dispatch.call(qbsm, "DoRequests", msgSet).toDispatch();
    Dispatch resList = Dispatch.get(resSet, "ResponseList").toDispatch();
    int count = Dispatch.get(resList, "Count").getInt();
    for (int i = 0; i < count; i++) {
      Dispatch res = Dispatch.call(resList, "GetAt", new Variant(i)).toDispatch();
      // blindly assume that we have a vendor response
      Dispatch vendList = Dispatch.get(res, "Detail").toDispatch();
      int vcount = Dispatch.get(vendList, "Count").getInt();
      for (int j = 0; j < vcount; j++) {
        Dispatch vend = Dispatch.call(vendList, "GetAt", new Variant(j)).toDispatch();
        Dispatch dname = Dispatch.get(vend, "Name").toDispatch();
        String name = Dispatch.call(dname, "GetValue").getString();
        System.out.println("Vendor: " + name);
      }
    }
    // close the QuickBooks connection
    Dispatch.call(qbsm, "EndSession");
    Dispatch.call(qbsm, "CloseConnection");
    System.out.println("Goodbye world!");
  }
}

CONCLUSION

Using QBFC is already a somewhat verbose process and running it through JACOB certainly doesn't make the code more terse. Hopefully I'll be able to create my own little API to shield most of my code from needing to mess with all these Dispatches. My needs might be simple enough that I can wrap all the ugly stuff in a few function calls. After I get really down and dirty with QBFC I may write another post detailing my exploits.

Loving PHP in a hostile world

Reading the comments and blogs that pop up on reddit, I’ve found that a furious animosity exists towards the good ol’ PHP Hypertext Preprocessor. Any mention of PHP is met with a firestorm of derogatory remarks; the community consensus seems to be that the language is used only by the worst class of shit farmers, harvesting crap from the reeking soil with crude fecal trowels.

Using advanced data mining techniques, we can determine where PHP might stand in terms of programming language hatred:

Google Suck-Off
“java sucks” 20,100
“C++ sucks” 8,670
“php sucks” 7,730
“lisp sucks” 3,550
“ruby sucks” 2,230

One might expect phpsucks.net to provide an explanation for why the language is hated, but the site has a decidedly different message. If you want coherent, technical arguments against PHP, then certainly they exist. Here are a couple of decent ones that I found with a cursory search:

And yet, the language is not without modern-day success stories: 7 reasons I switched back to PHP after 2 years on Rails.

Having used PHP with varying degrees of intensity since 1999, I find that I still love hacking in the language. My programming skills have matured greatly over the years, and PHP in no way prohibits me from writing the well-engineered code that comes with that maturity. You don’t have to express your application in some mucous HTML/SQL/PHP death rattle. With PHP5 you can use full-on object-oriented programming and still have the nifty benefits that scripting languages give you.

But I’m not going to leap to the pulpit, implore you to open your PHP docs to the Book of Rasmus, and lead you in worship of the language. You can’t design a “hypertext preprocessor” at the dawn of web programming and expect it to be perfect over the next decade. PHP has had flaws, and one could argue that there is a cultural flaw embedded in the language that leads to a lot of poorly-written code. By that I am talking about this sort of anything-goes, quick n’ dirty approach that allows the amateur to easily produce something workable with minimal effort. For an intriguing listen about the culture of a programming language (among other things), I highly recommend this podcast with Rails’ author DHH and Extreme Programmer Martin Fowler.

Yet when it all comes down to firing up emacs and writing web code, PHP provides me with the flexibility to write good software. I know the language intimately, I know when I can use PEAR to save some time, I know the php.ini settings, I know that Apache and mod_php are rock solid. In short, I have deep knowledge of a reliable programming tool and I can use it to rapidly develop maintainable, extensible web apps.

Of course, there comes a time when the familiarity with your current tool cannot compete with the benefits of a new tool. Is Ruby on Rails that white shore and far green country? Well, no. I’m not going to learn a new language, a new API, and – in the case of Rails – a custom implementation of a certain methodology running on a new application server, just so that I can have cool syntax and maybe fool around with closures. I don’t think that writing a quality MVC in PHP is going to be earth-shatteringly different from doing the same in Ruby – at least not enough so as to cover the activation energy of making the switch.

When I see people choking back their own vomit when “PHP” crosses their lips, I know they’re thinking about a different kind of PHP from the one I use. They’re thinking about raw SQL statements in nested loops, dumped with inconsistent indentation in a mass grave of <?php tags and HTML. That’s not the PHP I hack. I’ll keep my eyes on the programming scene with an open mind. If PHP begins to stagnate while Ruby forges ahead and puts together a strong mod_ruby, then I won’t need to be a shaman to read the cast of those bones. Until that time I will continue to dally with PHP, though it be strictly forbidden by the ancient laws of my tribe.