Update:
My original answer got a lot of down votes. Here is my updated answer. My original answer can still be found below.
You could detect browsers that support 308 responses by checking for the upgrade-insecure-requests header. This header is used in nearly every request sent by modern browsers. The absence of this header doesn't necessarily mean lack of 308 support, but you could provide a fallback that mimics a 308 response like this:
function _308($location) {
header('vary: upgrade-insecure-requests');// Don't cache if header varies
if (!empty($_SERVER['HTTP_UPGRADE_INSECURE_REQUESTS'])) {
// Safe to use 308 response code
header('location: '.$location, true, 308);
}
elseif (in_array($_SERVER['REQUEST_METHOD'], ['GET','HEAD'])) {
// When the request method is GET or HEAD a 301 response will suffice.
header('location: '.$location, true, 301);
}
else {
// 307 responses were introduced in 1999 and are now universally supported.
// Browsers respond the same as with 308 when request method is POST.
header('location: '.$location, true, 307);
}
exit;
}
This seemed like a better answer than the solution I provided that got 4 down votes (below). HTTP/2 web browsers do universally support 308 responses, but detecting browser support for HTTP/2 server-side is frequently not feasible.
Original Answer:
308 redirects were introduced just before HTTP/2. So theoretically 308 redirects are supported on all browsers that support HTTP/2 and compatibility can be detected by detecting the use of HTTP/2 or better. Obviously this only works if your web server supports HTTP/2 and you are not behind a CDN.
So what you should do is detect the server protocol. If HTTP/2 or better is being used, you can use a 308 redirect and trust that it will work as expected. Otherwise use a 307 redirect which has been around since about 1999 and is supported in all modern browsers. In practice 308 and 307 are handled the same when the request method is POST anyway, since neither is cached in that case.
If that isn't good enough, I recommended including a form in the web page body that can be used to re-submit the submitted POST variables at the new location. If the 307/308 response code is not recognized, the form will be displayed to the user and the redirect will be able to be completed manually. See RFC 2616:
The temporary URI SHOULD be given by the Location field in the
response. Unless the request method was HEAD, the entity of the
response SHOULD contain a short hypertext note with a hyperlink to the
new URI(s) , since many pre-HTTP/1.1 user agents do not understand the
307 status. Therefore, the note SHOULD contain the information
necessary for a user to repeat the original request on the new URI.
https://www.rfc-editor.org/rfc/rfc2616#page-65