You are checking with the status code. While that is generally correct w/ HTTP, mind that you request a PHP script.
That PHP script does exist, regardless of the query parameters.
Can’t imagine you tried 15 different answers on site, but for the code example:
- Check for 200 status code on the expected line
- Check for Content-Length
...
$headers = get_headers($url, true);
stream_context_set_default($previous);
[$status] = sscanf($headers[0] ?? '', 'HTTP/1.1 %d OK');
return $status === 200 && isset($headers['Content-Length']);
}
As you also have found out that the criteria/meaning can greatly differ across sites, I’d suggest you give it a callback function where you can adopt:
function FileExists($url, ?closure $filter): bool
{
$previous = stream_context_get_options(stream_context_get_default());
stream_context_set_default(['http' => ['method' => 'HEAD', 'follow_location' => 0]]);
$headers = get_headers($url, true);
stream_context_set_default($previous);
[$status] = sscanf($headers[0] ?? '', 'HTTP/1.1 %d OK');
return $status === 200 && $filter ? $filter($headers) : true;
}
$url1 = "https://example.net/path/to/script.php?option=a";
$url2 = "https://example.net/path/to/script.php?option=b";
var_dump(
FileExists($url1, fn (array $headers): bool => isset($headers['Content-Length'])),
FileExists($url2, fn (array $headers): bool => isset($headers['Content-Length'])),
); // bool(false), bool(true)
Work with the parts you stumble upon and make them inject able (= flexible).