Having difficulty with a process that creates HTML page code and then display the
Open/Save As dialog. This code is used on two different sites, and works properly
on one site (showing the Open/Save As dialog as desired) but the other site shows
the HTML code inline on the calling page (the process is called by a form button).

The code creates a full HTML page (html/head/body/etc), in the code below
that HTML content is $xoutput variable.

The $thefile is the fully-pathed file name.

I have tried many different combinations of the header() settings. Note again
that the code works properly on one site, but the exact same code shows
the HTML content inline, rather than the Open/Save As dialog. There is no
output before the header() that might cause a 'headers already sent' error
(which doesn't happen).

Both sites are running PHP 5.4.43. Both sites have the exact same code.
Note that the problem also occurs on another (customer) site. Both sites
running in the same browser (latest Firefox). Same things on both sites, but different results. Both sites are WordPress(latest); disabling all other plugins and using 2015 theme still shows inline HTML on the problem site.

Why would the code work properly on one site, but not the other? The problem
is somewhere in the header() statements, I think, but that's all I can figure out. Have tried lots of code suggested by the googles. The only variable between the two sites is the two sites. All else is the same.

The code below is based on my previous question on the same subject (here https://stackoverflow.com/questions/46019470/force-download-of-generated-html )

function output_file($post_output = "nothing found")
{
	$thefile = 'myfile.html' ;
	$size = strlen($post_output);
	header("Content-Description: File Transfer") ;
	header("Content-Type: application/octet-stream") ;
	header("Content-Disposition: attachment; filename=$thefile");
	header("Content-Transfer-Encoding: binary") ;
	header("Expires: 0") ;
	header("Cache-Control: must-revalidate, post-check=0, pre-check=0") ;
 	header("Pragma: public") ;
	header("Content-Length:" . $size);
	ob_clean() ;
	flush() ;
       echo $post_output;
	exit ;
	return ;
}

Thanks...Rick...

    I might try adding this to see if it's the root cause:

    function output_file($post_output = "nothing found")
    {
    	if(headers_sent())
    	{
    		throw new Exception('Uh-oh...headers already sent. :( ');
    	}
    	// rest of function . . .
    }
    
      NogDog;11064647 wrote:

      I might try adding this to see if it's the root cause:

      function output_file($post_output = "nothing found")
      {
      	if(headers_sent())
      	{
      		throw new Exception('Uh-oh...headers already sent. :( ');
      	}
      	// rest of function . . .
      }
      

      Hmm...at first, I thought "Nah, I've already checked that. Besides, the exact same code works on the other site. So that can't be it.". But I've tried so many other things, so I inserted that.

      Urk. Turns out there was something being output ahead of the Content commands.

      So I moved the function out of where it was and used the command to run the function when the page is initialized (it's a WordPress site):

      // Check whether the button has been pressed AND also check the nonce
      if (isset($_POST['the_button'])) {
      	// the button has been pressed AND we've passed the security check
      	add_action('admin_init', "create_the_output"); // runs the function that does the Content things
      }
      

      ...and now I get the Open/Save As dialog.

      But I still don't understand why the exact same code works on one site, but not the other (details in the original question). Is there a php.ini file setting that might 'ignore' the 'headers already sent' that is allowing the code to work on one site but not the other?

      Thanks...Rick...

        The ob_clean() in your function suggests that it expects output buffering will be on, which if turned on before anything gets output would then allow header() to work at any time (before it gets flushed). So I'm guessing one site does an ob_start() early on?

          Write a Reply...