title: Problems with preventing caching of 500 internal error page in php
body: <p>I'm having a problem completely properly configuring behavior for 500 Internal Server Error pages.</p>
  
  <p>I have two main use cases:</p>
  
  <h2>No headers sent</h2>
  
  <p>Fix here is simple, just throw http 500 errors without changing url.</p>
  
  <h2>Partial page error</h2>
  
  <p>In this case, some html &amp; http headers were already sent to the client.  In order to prevent a partly broken page from displaying, I output javascript that causes a redirect completely to an error page url, /error.html .  This is to avoid displaying part of a normal page and part of an error page, and make it clear that the resulting html is not optimal even if the section that the error message ends up being displayed in is currently hidden, by moving to a dedicated error page.</p>
  
  <p>Unfortunately, when hitting "back" from the dedicated error page, the original erroring page gets cached, and the javascript redirect is performed again, even if the error has been fixed in the meantime.</p>
  
  <p>For example, if there is an error after headers are sent in index.php, javascript will output that redirects a user to /error.html.  Once there, they can return to the homepage (which should be fine), or hit back.  When they hit back, they may get a cached page that re-redirects them to error.html.
  index.php > error.html (hit back) cached index.php > error.html</p>
  
  <p>What is the ideal way to avoid this situation?</p>
  
  <p>In the code below, I try to add #error hash in the url to redirect only the first time, and on subsequent visits to a broken partial page start a 60 second refresh attempt cycle.  Unfortunately, when I set the #error hash and the redirect, then hit back, it goes to index.php, not index.php#error, so the cached infinite loop occurs.</p>
  
  <p>How do I gracefully handle partial-page 500 errors?</p>
  
  <p>Here is the code in my php custom error handler, which causes the above listed behavior:</p>
  
  <pre><code>function showErrorPage() {
      if (headers_sent()) {
      // This is complicated due to the infastructure tending to have already sent headers, ...
      // ...requiring a tuned javascript redirection in many instances.
  
          // Output the following as html.
          ?&gt;
          &lt;meta http-equiv="Cache-control" content="no-cache, no-store"&gt;
          &lt;script type='text/javascript'&gt;
          var currentHash = location.hash;
              // UNFORTUNATELY, HERE THE HASH NEVER SHOWS AS SET!
          if(!currentHash){ // If hash wasn't already set...
              location.hash = '#error';
              location.href = 'error.html'; // Redirect once.
          } else { // Otherwise, the hash was already set, they were redirected once but came back.
              // So just display this page for a time but refresh on a slow schedule.
              setTimeout(function(){
                  location.reload(true); // Non-caching refresh.
              }, 60*1000); // Reload after 1 min delay
          }
          &lt;/script&gt;
          &lt;?php
      } else {
          // No headers sent, so set the right headers
          header("HTTP/1.1 500 Internal Server Error");
          header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
          header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
      }
      // Regardless, include the visible error output and throw exit with error.
      include(WEB_ROOT.'error.html');
      exit(1);
  }
  </code></pre>