开发者

Odd PHP header() behavior from POST to php_self - inconsistent across environments

I'm having a problem with sending back header(location:) as a response from an HTML form POST to PHP_SELF.

The essential parts of the use case:

  • I'm including inside the main page, a page which contains all of the form UI echoed out. This form POSTs to itself ($_SERVER['PHP_SELF']).
  • This form contains a "file" field and passes some text (login, password, etc) to itself to do an FTP upload.
  • If the upload is successful, I output header() where location is the main page (along with some parameters which tells the containing page to print a successful upload message).
  • The main page (upon receiving the header) should display the include with the form echoed out again for the next upload.
  • Everything works just as expected in Dev, but in Prod, I never get my form back - it's like the header isn't getting sent.

The three things that have made this so mysterious:

  • I have two environments, dev is windows/apache 1.3.37/php 5.2.11 fast cgi, prod is linux/apache (2.2.16)/php 5.2.14 fast cgi, and I've configured as much of the relevant looking PHP params the same across both dev and prod. In Dev, the aforementioned use case works great. In Prod, the file does upload, but it's as though the header is not getting sent back. The block where the included content should be is completely empty.
  • If I separate the include so that the form content (the UI stuff) is the only thing in the include, and the form POSTs to a separate file which contains the FTP upload logic, the header sent back at the completion of a successful upload does work in both dev and prod...the file uploads, the header gets sent back, the main page refreshes, and the contents of the include are displayed.
  • In Dev, through Fiddler, I can see the POST to PHP_SELF with all the form content, and I clearly see the header returned back. In Prod, I can see the POST to PHP_SELF, everything looks good, but there is never a header returned returned back. Howe开发者_如何学Gover, in debugging, headers_sent told me the header was being sent to the right location. Echo'ing headers_sent shows up in my main page.

Extra trivia:

  • I thought at first, .htaccess was getting in the way, but again, everything works if I split out the UI and FTP upload stuff, and .htaccess in this environment is very basic.
  • I also thought, maybe output buffering would change the behavior - I tried ob_start in a variety of logical places, behavior never changed.
  • Lastly, I tried a number options in header location - in some cases, just pointing to http://www.google.com - still it's as though no header is being sent at all.

I'm out of ideas - can someone offer some direction on this??

Here is a simplified test case - which, interestingly enough, behaves the same in dev as prod, so at least it's consistent now.

  • Test.php is included in a page called "upload.php" with a couple of buttons rendered.
  • "Try" POSTs to PHP_SELF and the rendered contents of test.php never come back when header('Location: ./upload.php') is called...the space in the including page is blank.
  • However, "Try2" POSTs to test2.php which calls header('Location: ./upload.php') and re-renders the buttons of the included test.php page no problem.

Here is a test.php:

<?php
if($_POST['submit']) {
Header('Location: ./upload.php');
} else {
echo
'<form name="test" action="'.htmlentities($_SERVER['PHP_SELF']).'" method="POST">
<input type=submit value=try name=submit>
</form>
<form name="test2" action="test2.php" method="POST">
<input type=submit value=try2 name=submit>
</form>';
}
?>

and here is test.php...pretty simple.

<?php
Header('Location: ./upload.php');
?>

and here is a snippet from upload.php:

<!--    <div id="flashcontent"></div> -->
</fieldset><?php require_once('test.php'); ?></div></div>
</body>
</html>

Today's update - in fact, the behavior of the simple test case was not as I originally thought. I was already including the real-life file above the simple test case include which I think was resulting in the classic headers-already-sent problem. Once I commented out the real-life file, the behavior of the simple test case now matches the original case outlined at the start of this post. So, the simple test case loads the header if called from within the include on form submit, and loads the header if called from another page posted-to from the included file...no problem. However, in production, the results of the header call are only realized if called from a page posted-to, and not if called when posting to php_self.

<div class="panel_wrapper">
<div id="general_panel" class="panel currentmod">
<fieldset>
<legend><?php echo TB_UPLOADFILES; ?></legend>
<?php
//define('upload_opt',TRUE);
//require_once('upload_opt.php');
?>
<!--    <div id="flashcontent"></div> -->
</fieldset><?php require_once('test.php'); ?></div></div>
</body>
</html>


It could be that the header is being sent after an error. Try turning errors off on the production server.

Also check that no white space is being output before the header.

File names in Linux are case sensitive, so make sure your cases are correct too. If it can't find the new location, that could do the trick (although I doubt this, because google.com didn't work.)

Try adding "exit()" after the header declaration.

Make sure your header has the correct syntax and is absolute if the resource is external.

header("Location: http://www.google.com");
exit();

Try doing a dumbed down example on your production server to test. Remove the post altogether and make sure header redirects are working. It could be a restricted function if you are using a shared host and aren't in control of the PHP.ini file.

If none of those work, a snippet of your header code would be interesting to look at.


Somehow, this all has to do with output order, buffering and headers, and is ultimately solved using output buffering (ob_start / ob_end_flush). Despite the fact that output buffering is set the same in both environments (output_buffering: 4096), for some reason, I seem to be enjoying the buffering in Dev that I'm not in Prod. By wrapping the including page in ob_start() and ob_end_flush(), the behavior is now consistent and as-desired in both environments.

I'm not thrilled about this as it seems a workaround, and I still don't have a clue as to why the behavior is different across the two environments. It seems the more sure solution would be not to POST to PHP_SELF to call header(Location), but to POST to another file which calls header(Location). Somewhere, it's probably written that this is best practice, don't try to call header(Location) from within, and avoid the use of output buffering.

Should anyone want to really dig into this mystery, feel free to contact me offline because I've managed to fix the symptoms, but I still don't know what the problem is.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜