Getting burned on PHP operator precedence

With a POST form, you need to be careful when you return the response that the user might just issue a refresh and in doing so resubmit the form, resulting in a duplicated entry.  A quick google on the subject shows many cases were PHP programmers get burned on this.  In most circumstances the simplest thing to do is to issue a location header to navigate away from the form, or to timestamp the form on a hidden field and have double entry detection logic in your form processing.  However, I want ‘to put my hand up here’ to falling into another classic coding trap whilst doing this.  I have one admin form where on one path the form didn’t refresh as I intended.   The offending line of code was:

header( "Location: " . isset( $check_id ) ? "article-$check_id" : "admin" );

Can you see the error?  It was staring me in the face yet I didn’t spot it, and in fact I only twigged when I passed the line through the VLD disassembler to look at the generated PHP opcode listing.   It’s the classic issue of operator precedence: the string concatenation operator has higher precedence than the selection operator.  Hence this evaluates as:

header( ( "Location: " . isset( $check_id ) ) ? "article-$check_id" : "admin" ); # which is the same as
header( "<some non-blank string>" ? "article-$check_id" : "admin" );             # which is the same as
header( true ? "article-$check_id" : "admin" );                                  # which is the same as
header( "article-$check_id" );

Bugger.  Moral: it’s always safer to use explicit parenthesis. I “always” do this after being tripped up too many times in C and C++, but this was a case where I got sloppy .  At worst, doing this is syntactic sugar which improves readability – and it might just prevent you coding up some horrible and hard to spot error.  The line now reads:

header( "Location: " . ( isset( $check_id ) ? "article-$check_id" : "admin" ) );

Leave a Reply