How I Spent My Saturday — A Geeky Puzzle

I feel like I should record this, on the off-chance that it will save someone else from spending 18 hours glued to a computer screen missing the obvious. It will be of very limited interest.

Actually, let’s make it a puzzle.

So I have a php script — let’s call it A.php — which contains an html form introduced by the line < form method=POST action=”B.php” > .

There are no other calls to scripts anywhere else in A.php, and none at all in B.php.

So I enter the following in my browser’s address bar (I tried this in multiple browsers, all with the same results):

FOO/A.php?QUERYSTRING

(where of course FOO is a web address). This causes some php code to execute. That code checks to see if the query string is nonempty (which it always is at this point), and if so, it displays the form, with a submit button. Here is what happens next:

a) Roughly half the time, I hit the submit button, which calls B.php, which also executes, at which point my address bar shows FOO/B.php . This seems entirely normal.

b) The other half of the time, I hit the submit button, which causes A.php to execute a SECOND TIME (instead of calling B.php). (It now thinks the query string is empty so the form is not re-displayed.) At this point my address bar shows FOO/A.php/B.php (despite the fact that B.php was never called, or at least never executed).

There is absolutely no apparent pattern to when I get a) and when I get b). I sit at my damned screen for hours on end (this started at 6AM and ended at midnight), repeating the same input, sometimes getting a) and sometimes getting b), according to what looks to me like a series of fair coin flips.

So, because I am making **absolutely no changes** to the code, this **must** mean something is going on at the server end, right? So I move all the code to a completely different server, and get exactly the same behavior.

This is not behavior that’s easy to google for. I wasted a little time trying.

Right around midnight, the truth dawned on me.

And now I wonder: Would a programmer with the right background have been able to guess what the problem was quicker than I did? Like, maybe at least 17 hours quicker? Let’s make it a challenge.

Click here to comment or read others’ comments.

Print Friendly, PDF & Email
Share

13 Responses to “How I Spent My Saturday — A Geeky Puzzle”


  1. 1 1 David Grayson

    Hmm, why it is expected tha A.php will “execute and call” B.php? You should be able to type FOO/A.php?QUERYSTRING into your broswer, press enter, and then see the form presented by A.php without having any part of B.php execute, because you didn’t submit form yet.

  2. 2 2 Steve Landsburg

    David Grayson: Yes…. I somehow left out a step. I enter FOO/A.php?QUERYSTRING in my browser **and then hit the submit button** on the form, after which a) and b) happen seemingly randomly. I’ve edited to fix this. Thanks for catching it.

    (Also when I say that A.php “executes”, I should be more careful —- some php code executes when A.php is loaded, the form is displayed, and then I hit the submit button. At that point either a) B.php executes and the address bar shows B.php or b) A.php executes a second time and the address bar shows A.php/B.php.)

  3. 3 3 Steve Landsburg

    David Grayson: I’ve now edited a second time to clarify exactly what was happening. Apologies for leaving out key details the first time!

  4. 4 4 vmsmith

    You are soooooo . . . 20th century.

    It’s been years since I’ve coded on anything like a regular basis, but from time to time I still need to do some. Mainly in HTML/CSS, but also in R. So what do I do?

    I always ask my best coding buddy, ChatGPT, for help. Always. And so far, it’s never failed me.

    I don’t know if ChatGPT would have been able to solve your particular problem, but if you’re not a programmer by trade & working in an environment where you can ask a colleague for help, you really ought to learn how to use it in coding situations.

  5. 5 5 Steve Landsburg

    vmsmith : You don’t know the half of it. My main mail client is usr/bin/mail. And I do most of my text editing (including things like writing books) in vi. And I will never change.

  6. 6 6 David Grayson

    Thanks for clarifying. I attempted to reproduce the behavior, and I have a live demo of it up here:

    https://www.davidegrayson.com/landsburg/A.php?QUERYSTRING

    In my demo, A.php displays the form if and only if the query string is non-empty. B.php simply calculates 1+1. Everything works as expected.

    If I were able to reproduce the problem, one of the first things I would have done is open the browser’s developer tools so I can see a trace of all HTTP requests and what their answers were.

    The fact that your URL became “FOO/A.php/B.php” suggests that the part of the web browser for converting relative URLs like “B.php” to full URLs got messed up, so I would be looking carefully at that current URL and the relative URL specified by the form.

  7. 7 7 Steven Landsburg

    David Grayson: Interesting. I am unable to reproduce the exact behavior on your demo.

    Spoilers beyond this point.

    It turns out that the reason the supposedly “exact same input” seemed to yield random behavior is that the user (i.e. me) was an idiot who (apparently completely randomly and without ever noticing it) was half the time entering

    FOO/A.php?QUERYSTRING

    and the other half

    FOO/A.php/?QUERYSTRING (note the /)

    The first yields normal behavior; the second yields the aberrant behavior I described.

    On your demo, I cannot reproduce the same specific aberrant behavior. Instead the input

    https://www.davidegrayson.com/landsburg/A.php/?QUERYSTRING

    leads to a “file cannot be found” message. Maybe this has something to do with our server setups, or maybe it has something to do with the specific contents of my files A and B versus yours.

    Now my question: Ought the specific error I kept getting (with the A.php/B.php) have clued me in to the fact that I was adding that stupid slash? [In retrospect, I suppose it clearly ought to have clued me in to the fact that I was doing **something** different — but should it have clued me in to this more specifically?]

    (P.S. I see that the “file cannot be found” message is coming from your A.php, not from the server. I can’t see your php code, so I don’t know exactly what triggers the display of this message. But I’m guessing that if you deleted that part of the code maybe you’d be able to reproduce my bug.)

  8. 8 8 David Grayson

    Oh wow! I believe I would have caught this bug quickly because I said I would try “looking carefully at that current URL”.

    My web server software is nginx. To enable PHP, I have a block of code in the configuration that starts with “location ~ \.php$ {“. I copied this from some standard tutorial, and the dollar sign means “end of string”. So my PHP interpreter only runs if you request a URL ending with “.php”. The extra slash you typed breaks the pattern, so it gets interpreted as a normal, non-PHP request for a *directory* named “A.php”, and there is no such directory. So PHP is not involved, and nginx just returns my regular 404 response.

    I think you don’t want a request for “A.php/” to execute A.php and serve the user a page where none of the relative URLs work.

  9. 9 9 Olivier

    Hello sir, have you made sure that the QUERYSTRING content is harmless, i.e. does not contain characters that could confuse the webserver ?
    Anything which is part of the addressing syntax (/ : ? . and even =) could confuse the browser and then the server when trying to make sense of the URL (what is the domain name, what is the actual php file to run, what is the query string and so on).
    Anything confusing should be “url encoded”, for example the space ” ” can be translated to %20.

  10. 10 10 Steve Landsburg

    Olivier: You’ve essentially got it. See my conversation with David Grayson above.

  11. 11 11 Steve Landsburg

    David Grayson: “I think you don’t want a request for “A.php/” to execute A.php and serve the user a page where none of the relative URLs work.”

    I think the same thing. But that is in fact exactly what happened on two entirely different servers with entirely different administrative teams. [I do not run my own server; I have shell accounts and webspace at several commercial hosting companies.]

  12. 12 12 Paul Grayson

    I do think I would have figured it out at least a few hours faster, if I was lucky enough to notice it at all.

    I often have similar issues, with URLs that can be written as:

    Foo.com/mydir
    Foo.com/mydir/
    Foo.com/mydir/index.html
    etc.

    You have to be really careful with relative URLs in such situations.

  13. 13 13 Eric johnson

    The server does not come into play with your “bug”

    If the url in your action doesn’t start with a slash or a scheme, the browser assumes it’s a resource that lives in the same folder as the page you are executing.

    If the page url has a trailing slash/ then that is interpreted as a sub folder under the root by the browser

Leave a Reply