Making CubeCart 6+ Work For You (bonus: on Windows/IIS)

I just started working with CubeCart and I like the general aesthetic and workflow. It’s less needlessly complex than OpenCart, lacks the WordPress baggage and square-peg/round-hole feeling of WooCommerce. However, it needs some tweaking to work the way I want it to and it’s not that easy to do.

Part of that stems from the lack of low-level settings in the interface, some of it from the fact that CubeCart’s documentation (especially vis a vis Windows Server) is, to be charitable, underwhelming. CubeCart is written assuming Apache as your web server, so let’s get that Windows thing out of the way right up front.

By default, I’m going to assume you know how to use FTP and a text editor. If you don’t, you should hire someone who does: don’t try to muck around in the files on your site if you don’t know what you’re doing. You can end up breaking your site and not have the wherewithal to fix it. This article is for the tech-savvy.

Making CubeCart work on IIS

When I first started with CubeCart, I read several posts from its developers that CubeCart doesn’t work in Internet Information Server on Windows. (Rule of Thumb: Just because you don’t know how, doesn’t mean something can’t be done.) I run a Windows web host, and run several PHP apps in IIS, so I knew going into it that CubeCart absolutely would work on Windows, but would require an extra step with an IIS Rewrite Rule or two. Onward.

Be default – and I haven’t (yet) found a way to change this – CubeCart forms product urls in an SEO-friendly fashion, e.g.:

In IIS, that’s going to give you a 404 error since there is no HTML page of that name. To make this work, you have to create a rewrite rule in IIS. There is a forum post on this topic, but it’s not easy to find and, because of the formatting on the page swallowing the XML, wrong, so I’m not even going to link to it. (Searching Google won’t help: the cached link goes 404; you have to search the forum itself, but like I said, the info you’ll get is useless.)

If you have access to IIS, you can create a rewrite rule using the XML below as a guide. If you don’t, you need to create a file called web.config in the root of your website with these contents:

<?xml version="1.0" encoding="UTF-8"?>
                <rule name="generic rewrite" stopProcessing="true">
                    <match url="^(.*)\.html$" />
                    <action type="Rewrite" url="/index.php?seo_path={R:1}" />
        <httpErrors errorMode="Detailed" />

These rules assume that you have installed CubeCart into the root of your website, and not behind some sub-folder like “store.” If that’s the case, you’ll see to change the rules to accommodate. (NOTE: the second rule is there so that people get your homepage when they only enter “;.)

Error Logs

In the CubeCart admin section, left hand menu, you find an entry for “error logs.” Don’t ignore it! You can find very useful information there.

GoShippo Plug-In (and plug-ins in general)

The great thing about CubeCart is that all the basic extensions you could ever need to get going right out of the gate are free. PayPal, Stripe, Square, GoShippo, they’re all there. The downside of free stuff, though, is that support is often lacking.

For instance: I installed the GoShippo plug-in, but I didn’t configure it. I figured I’d get it in there, configure it later, and that’s where I ran into a problem. The site loaded normally until I tried to view my basket: the page came up blank. No error message, nothing in the PHP logs. (As of this writing, I’ve got error reporting set up in PHP and IIS to show me everything that goes wrong, so there should have been something. Nope. Just a blank screen.) I viewed the source, and there was no output to the browser at all. I went to the forums looking for help and (surprise!) found nothing useful.

The only way I’ve found to solve it (as of this writing) is to disable the plug-in. Checking the CubeCart error logs showed me the issue was a certificate failure.

04/05/2020: I’m waiting on an email from GoShippo. I’ll update as new information becomes available.

Changing The Dropzone Upload File Size

This is one of those items that should be a configuration change in the interface, but inexplicably isn’t. You have to manually change this in the applications files, and there are two places to do it.

\admin\skins\default\js\admin.js, line 359

$("div.cc_dropzone").dropzone({url: cc_dropzone_url, maxFilesize: '1.0', init: function () {

The default is .35, or 35kb. In red, I’ve upped that limit to 1mb. We’ll make a similar change in \classes\filemanager.class.php, line 26

private $_max_upload_image_size = 1000000;

The default is 350000, which I’ve upped to 1 million. (Tested: Windows 10, Chrome and Firefox)

The Register/Checkout Buttons Don’t Work

When you have a form to be filled out – new customer registration on either the Register or Checkout pages, for instance – CubeCart uses jquery.validate.js to validate the fields. It’s a hugely powerful library, but for some reason, on my implementation validation always fails and the forms don’t submit.

It works like this: when there is a form element that needs the validation to take place server-side, email for instance, a reference to that element is added to a stack. In theory, as a remote validation/ajax call completes, the element should be removed from the stack. When the stack is empty, the form submits. The ajax call uses the success method to decrement the stack:

$.ajax( $.extend( true, {
	mode: "abort",
	port: "validate" +, 
	dataType: "json", // << this setting needs to stay as it is!
	data: data,
	context: validator.currentForm,
	success: function( response ) {
		var valid = response === true || response === "true",
			errors, message, submitted;
		validator.settings.messages[ ][ method ] = previous.originalMessage;
		if ( valid ) {
			submitted = validator.formSubmitted;
			validator.toHide = validator.errorsFor( element );
			validator.formSubmitted = submitted;
			validator.successList.push( element );
			validator.invalid[ ] = false;
		} else {
			errors = {};
			message = response || validator.defaultMessage( element, { method: method, parameters: value } );
			errors[ ] = previous.message = message;
			validator.invalid[ ] = true;
			validator.showErrors( errors );
		previous.valid = valid;
		validator.stopRequest( element, valid ); // << this function decrements the stack, but we never get here!
}, param ) );

You may see a fix that suggests changing the dataType parameter to “text” from “json.” This works on the Register form, but NOT on the New Customer form: the response isn’t understood by the success method and validation fails.

The only reliable way to fix this that I’ve found is to use the complete method instead of success. The downside of this is that success only fires if the ajax call was successful (return code 200), complete fires every time (any return code, including 500 and 404). Still, I can see any way around it.

port: "validate" +,
dataType: "json", // << this setting needs to stay as it is!
data: data,
context: validator.currentForm,
complete: function( response ) {
    var valid = response.responseText === "true",
    errors, message, submitted;

Plans for the Future

First: like so many carts out there, the “Add Product” interface is clunky as all hell. It’s the best 90’s methodology has to offer: configure a few settings; click “Save”; wait for the page to reload; go to the next tab; make a few changes; click “Save” and wait…repeat until you want to scream. It’s goddamn frustrating considering that every browser with any market share supports ajax, and ajax through jQuery is stupidly-simple (and which we have seen is already integral to the damn cart!), there’s no reason why you couldn’t have an “Add Product” screen in ONE TAB that saves your changes as you go. Are there no adults in the room? I mean to write an extension to address this.

However. On the “Why Use CubeCart” page, there’s a bullet point that reads, “Easy to extend.” Yeah, that’s bullshit. There is no real documentation that I can find on the subject of extensibility, and the people that have figured it out aren’t sharing their experiences. You just have to keep poking at it until something lights up.

Here is every link I’ve found as of 2020-04-09 that might be remotely useful:

Yes, that’s it. Sucks, doesn’t it? As I get the system worked out, I’ll post new articles.

Second: I don’t know yet if CubeCart supports this, but my current cart* doesn’t care what you link to for images. I have a product that I offer that has two configurable color settings: the image of the product is displayed based on your choices, and it’s handled by a PHP file applying css filters to two individual images and merging them into one and feeding them to the browser with an “image/jpeg” header. If CubeCart doesn’t support this, trust me: it will when I’m done with it.

* an ancient and heavily modified CandyPress. If they’d gone PHP in their upgrade path I’d still want it, but they went .NET, so that’s out. I have no desire to lock myself in to a Microsoft ecosystem. I’d even thought about writing a PHP port, but I just don’t want to take the time on a program that’s nearly twenty years old.

Apropos of nothing, I cannot express strongly enough how much I despise the new blocks editor in WordPress and the fact that the old editor is not available as a choice. I’ll be replacing this blog as soon as is practical.

I just fixed your computer.


I just spent about six hours fixing your computer. It was infected with several viruses, about two dozen bits of malware, and more than one thousand individual malicious registry keys, cookies, and Internet Explorer add-ons.  No, I’m not exaggerating.

As a part of this process, I did the following things:

1. I ran no fewer than five different virus and malware scanners. Each one found different infections.

2. I installed WinPatrol, SuperAntiSpyware, and Microsoft Security Essentials, each of which will monitor your PC and help to prevent future infections.

3. I installed a HOSTS file, to prevent any malicious connections.

4. I installed Google Chrome and made it the default browser. I also set the homepage to this blog entry, so you could see what I did.

Now, to prevent this from ever happening again, I have some advice to offer:

1. Stop downloading stuff.

If a program pops up offering to fix your PC, never ever click “Yes”. You had at least two of these installed. Often as not, these are themselves viruses by definition, and they’re hard as hell to get rid of. If you didn’t specifically go looking for it, do not install it!

If you see an offer for software that will make your internet experience better, don’t install it. It’s lying.

If you see a new toolbar, don’t install it. It won’t help you.

See a new search utility? Don’t install it. It’s just running google in the background anyway.

Seeing a pattern? Stop downloading stuff.

2. Use Google Chrome to browse the web. Stop using Internet Explorer right now. Here’s why.

3. Never play games or accept app invitations on Facebook. At least two of the infections on your PC were related to a Facebook app. No kidding, Facebook is not your friend. You’ve got better things to be doing with your time anyway.


Viruses and malware don’t just happen. They’re like vampires: you have to invite them in. Every virus I cleaned today was the result of a browser helper, toolbar, search utility, web helper, or Facebook app that you installed by downloading something.

Stop downloading stuff. Really.

HOSTS file.

Whenever I am asked to work on a PC, the first thing I do – every time – is install a HOSTS file. It’s one of the simplest security measures you can take – just a text file in a folder – and the least well known. Everybody knows about virus scanners, many users know about malware scanners, but very few people know about the HOSTS file.

So let’s start with what a HOSTS file is.

You may already know what a DNS is: for our purposes here, it’s a map that points a domain name to the address of a computer somewhere on the internet. For instance, “” maps to That number, or “i.p. address”, refers to a specific end-point, or node, on the internet. Tables of DNS records are stored on special servers, so when you type “” in your browser, a request is sent out, the i.p.address is returned, the connection is made, and the computer Out There and your computer Right Here begin sharing information, in this example, a web page.

The HOSTS file is the first stop on your browser’s trip. You’ve got one on your computer now: if you have a Windows PC, go to c:\windows\system32\drivers\etc. Open the file in Notepad. What you’ll see – after all the #comments at the beginning – is an i.p.address and domain name, probably this:     localhost

Another way that us computer guys say is “home”. (It also goes by the term, “loopback.”)

In short, it’s the i.p.address that your computer uses internally to refer to itself. Your computer’s way of saying, “me.”

What this means is that if you type http://localhost into your browser’s address bar, your browser looks to the local computer for that content. (Unless you have a web server installed, it won’t find anything, but you’re welcome to try.)

Here’s the important part:

Because you provided an i.p.address for the domain, the browser stops looking. It doesn’t go to the internet for the content because the HOSTS file says it’s local. Because there’s nothing there, the request dies.


Let’s pretend, instead of an innocent internet user, you’re a piece of malware, and you need to send the information you’ve collected back to the lair of the evil mastermind. You’re programmed to look for, which is, unfortunately for you, an entry in our hosts file. You can’t phone home.

Let’s pretend, instead of a piece of malware, you’re a browser add-on, and your job is to pop open advertising windows. You do this by connecting to the server of your Evil Mastermind to determine which gambling or porn sites you’re supposed to load. Unfortunately, again for you, is blocked. No windows open because you can’t get your instructions and if you do open any, they will be blank.

Isn’t that awesome?

So, that’s all?

That’s all? We’ve blocked malware from transmitting your credit card number and prevented your mother-in-law – who’s checking her email while you’re fixing yourself a stiff drink – from getting a dozen pop-ups for Asian scat and bondage porn, and you say, “that’s all?”

No, as it happens, that’s not all.

You can be a jerk about it.

Go to one of your co-worker’s PCs and put this entry into the HOSTS file:

I’m sure you could find an interesting i.p.address to plug in. You can repoint a website to ANY i.p.address, though you should note that just because you type in the i.p.address of some objectionable site, doesn’t mean that the site will load. Many times, the domain and the i.p.address are linked on the host: you’ll connect to the server, but it won’t show you anything worthwhile. Might be fun to experiment, though.

But seriously…

Your browsing experience will be, just generally, different. Cleaner for one. Take this LiveJournal blog, for instance:

Those ugly purple blocks are ads. This poor user is browsing the internet without a HOSTS file. Tsk tsk tsk.
This is the same blog, viewed on a PC with a HOSTS file. Look ma, no ads!

Now, there are two warnings I need to offer here.

First, you won’t see ads and much content in the margins of your browsing experience, so you might forward a web page you think is hysterical and get an angry email from your best friend complaining about the porn ads on the page. (Use that as an opportunity to set her up with a HOSTS file.)

Two, many websites track button clicks through ad hosting/tracking services that a full HOSTS file blocks, and if that’s the case you’ll get on the site but won’t be able to navigate. is that way: if I want to browse the site, I have to disable my HOSTS file. The “sponsored” links in yellow at the top of your Google search? Blocked.

Those are minor issues, though. It’s very worth it for better, faster, and most importantly, safer browsing.

OK, so where do I get one?


First Wedding Video

Several weeks ago I videotaped a wedding. My friend Lezlie referred the couple to me, and I accepted. I’ve always said no to that sort of thing because I’ve heard horror stories about bridezillas, but even moreso because it matters: I don’t want to be the guy that people point at and say, “That’s him…that’s the man that fucked up the record of the most important day of my life.”

There is a man named Mark with whom I have kept a casual friendship for a few years. My brother knows him: they both work for Entercom Radio/Media. We’ve met once in person, and stayed in touch through Facebook, and I knew through that venue that he’d recently purchased a set of studio lights. I sent him a message, asking if that was true. He wrote back, “Yes, why?”

I don’t know why I did it, but it was an inspired choice to contact him. My initial thought was to just ask if I could rent his lights. The question was typed and sent before my brain registered the action: “Want to help me shoot a wedding?”

I didn’t even know he had a video camera – as it turns out he has two. Between the two of us, we ended up with four cameras to shoot the wedding: bride-cam (static), groom-cam (static), Mark-cam (mobile), Me-cam (mobile). The plan ended up being to let the two front cameras capture the entire service from different angles at a fixed point of view; that would be the foundation. Then, Mark and I with our two cameras moved from place to place, capturing whatever looked interesting: reaction shots from the congregation; the ring bearer (cute but precocious kid) handing the ring to the best man; the scripture readings; things like that.

A year ago, I might have called a couple of old friends to help me with this, and I would have been nervous the entire time, wondering if they were capturing what I needed. They’re really good behind a camera, if they have very strong direction, but if you just point them in a direction and push to get them started, they will eventually wander. Their idea of “good enough” is nowhere near mine.

I finally saw his footage after finally getting a card reader and downloading it, and my impression from watching him at the service was correct: he paid attention – very close attention – and captured everything I needed him to. It was like dancing: we each just moved with the “music” of the service and reception in a loose step, me leading, him following from across the room. He even caught some moments I didn’t expect, but were absolutely beautiful choices: a close-up of the organist’s hands for instance.

Adobe Premiere Multi-Camera Monitor

The groom said to us at the reception: “Man, you guys were everywhere and nowhere.” That was the best compliment he could have given us. The priest even thanked us for our discretion at staying unobtrusive.

I learned through this process that Adobe Premiere has a multi-camera feature, where it will place four separate tracks of video into an interface where you can watch them simultaneously and pick and choose your shots on the fly. It saved me hours of time I’m sure.

I’ve nearly done editing. The finished product looks amazing.

Sending credit card information by email

There’s a lot of discussion on the web on this subject. Most writers recoil in horror from the very thought with the attitude of, “Better to be paranoid than sorry.”

Yeah, I can see it, but only to a point.

Let’s pretend that I’m going to send my credit card info in not one, but three emails: the first email gets the first half, second email the second half, and the third gets the CCV number. In each email I’m going to place the numbers inside blocks of random text. I will assume that the merchant I’m contacting already has my billing address.

I contend that this as safe as sending all that information in a webpage form over an SSL connection.

Let’s examine some points.

According to Verisign in a document published in 2005, approximately 2.25 billion emails are sent per day. Since that document doesn’t track domains such as .edu, we can assume that the number is much, MUCH higher. Let’s say, conservatively, 5 billion. That was six years ago. Assuming a growth rate of 10% (a ridiculously low number), we land on approximately 8.9 billion emails. Each. Day. It is safe to assume that number is much higher.

Let’s say there are one million hackers in the world whose sole purpose in life is to watch emails for credit card numbers. Each hacker gets 8900 emails to deal with: with 86,400 seconds in a day, he has about 9 seconds to process each one. Any good programmer can write a program to do this automatically. We’re not done, yet, though.

Now, the average email takes an average of ten to fourteen steps through various servers before it lands in your inbox. It is extremely rare for two consecutive emails to take the same path. Thus, our hacker will in all likelyhood, not see all three of the emails. That’s okay, though, because some other hacker has the other missing pieces.

Maybe. And even if so, which one (or two) of the million hackers has the other pieces?

Can you see how hopelessly complex this problem is? Working on the theory of diminishing returns, the amount of effort required to harvest one credit card number this way just isn’t worth the effort.

Now, another scenario:

Tonight, I will go out to dinner with my family. When the meal is done, I will hand my credit card to the waiter. He or she will disappear with my card for as long as ten minutes. During that time, that card is out of my control: the waiter can do whatever he or she wants with it. If I’m not otherwise careful online, Facebook or some blog somewhere will divulge my home address – all the information anyone would ever need to steal my identity.

I do this at least once a week without a second thought.

One wonders if the paranoia isn’t a little misplaced.