IE Redirect Bug with Dynamic Location Hash

I┬ádiscovered the most obscure bug today in IE. For those of you paying attention, this bug is the reason I haven’t been updating — it ate up all my god-damned time. People who aren’t programmers can stop reading here.

What Happens

The browser is redirected when it shouldn’t be after modifying the URL hash (the stuff after #).


The bug exists on IE7, possibly 6 (why not, right?).

Steps to Reproduce

Assume you are on page A and want to redirect to page B.

  • Go to page A.
  • From page A, do a header redirect to page B in PHP/ASP/whatever. As in, header(‘location: $pageB’);
  • On page B, using JavaScript, modify the document.location.hash variable.

What Should Happen

The anchor text in the address bar should change. As in, changes to This should happen without the page refreshing.

What Actually Happens

The browser refreshes. @#%!*(&$!

Solution / Fixes

On page A, rather than redirect using headers, use JavaScript:

// if page A was
document.location.href = '';
<a href="">go to page A</a>

For some dumb reason, this fixes the problem.

Damn you, Microsoft!

Five Tips for (total) PHP Beginners

Someone asked me to write this a long time ago, so here’s my list. I make the basic assumption that you at least know some SQL.

1. Use EzSQL.

It is an open source library that does database abstraction. “Database Abstraction” is a fancy term for “making the database more developer-friendly.” It well help you grasp concepts like rows vs columns, how to manage multiple results, and escaping data. See their examples. While it is (in my opinion) a lacking solution for experts, it is awesome for newbies. I used this way back when I first started. Use it if you’re new to PHP.

2. DON’T Rely on Magic Quotes.

Magic Quotes is a retarded feature that tries to sanitize your data in an automated fashion. “Sanitize” is a programming term for “making data safe.” As in, without sanitizing data, hackers can do mean things to your database.

Some may argue turning this off is *unsafe* for beginners, but it also trains beginners to be less cautious about sanitizing data. This is a problem since the majority of corporate PHP servers (as in, the real world) have Magic Quotes off.  For example, let’s assume $name is equal to michi. Some programmers might try:

DELETE FROM users WHERE name='$name'; 
— thus: DELETE FROM users WHERE name='michi'

But what if a hacker managed to make $name equal to michi’ OR TRUE. What does the query end up looking like? If Magic Quotes is relied on, you would have been protected:

DELETE FROM users WHERE name='michi\' OR TRUE'; 
-- result: no such user; no harm, no foul

So it tries to find a user called michi’ OR TRUE, which is clearly not going to be found. In this case, Magic Quotes looks like a good thing. However, if you got used to Magic Quotes and then got a job, you might forget that it isn’t enabled in the Real World, and this is what happens:

DELETE FROM users WHERE name='michi' OR TRUE; 
-- (hint: it deletes all your users!)


Just pretend like Magic Quotes is always off and use EzSQL’s escape() method or my solution (both solutions work regardless if magic quotes is on or off).

3. Always use require_once.

You will eventually see when include, require, or include_once is the better choice over require_once, but that time will come much later. As a rule of thumb for beginners, the last thing you probably expect is a silent “oops we couldn’t find the file so we’ll just continue on as if nothing happened…” bug.

4. Don’t display (echo) errors when a function has an error. 

Instead, store the errors in a class/global variable or return the error (neither of these are good practices for novice developers who should be throwing exceptions). The reason is that you never know in what context a function gets called; displaying errors could be disastrous in some situations. For example, if you were in the middle of writing a CSV file (comma delimited data file), you don’t want random unformatted error text appearing inside it saying “Error, invalid name!”. As in (notice the extra comma that got inserted in):

Charlie, Abigail, 31, California
Bob, Smith, 29, New York
Patrick, O'NeilError, invalid name!, 22, Washington
#check it out, a random extra comma got tossed in

Even if the script terminated at that point (which I assumed), the file may have been written to. Frankly, as a beginner, you or I can’t expect you to remember to *always* check if there was an error so it’s better to be defensive and just not randomly display stuff (which is why throwing exceptions is the ideal solution).

For those of you wondering why an echo statement might modify a file, note that for things like downloads in a browser, you will output the file in the browser and then change the header file-type to reflect what the user should do (i.e., download it). Thus, in this context, yes, you would echo out the entire file whether its XML, a Word document, a zip, a PDF, or HTML and then the user would be prompted to save it.

5. Use ob_start().

Put ob_start() at the beginning of your script before everything else.

// the rest of your script

This will save you lots of time when you get advanced enough to do redirection or understand what it does. The syntax for browser redirection is:

// this is a side note on redirection; don’t put this in your script ­čśŤ
header("location: another_file.php");
// always call die directly after a redirect!

Redirection means that the page should stop (if the redirection was successful) and the user never sees any output from that page. They are then immediately redirected to another page. Since they aren’t supposed to see any output, showing them output before a redirection ruins the redirect. This is often very confusing and difficult to fix for a beginner. ob_start() fixes that issue (it’s magical like that).

Note that if ob_start() is used, you don’t need to do anything else special. There is no need to use the other functions like ob_flush(), ob_end_clean(), etc. You’ll get to those later (probably a few months) once you fully understand what ob_start() does.