@ Гордон - Вот более полная библиотека, основанная на вашем ответе. Он включает в себя некоторую предварительную проверку правильности URL-адреса, дополнительную обработку ошибок и анализ возвращаемых заголовков. Это также следует за любыми цепями перенаправления в течение разумного количества шагов.
class cLib {
static $lasterror = 'No error set yet';
/**
* @brief See with a URL is valid - i.e. a page can be successfully retrieved from it without error
* @param string $url The URL to be checked
* @param int $nredirects The number of redirects check so far
* @return boolean True if OK, false if the URL cannot be fetched
*/
static function checkUrl($url, $nredirects = 0) {
// First, see if the URL is sensible
if (filter_var($url, FILTER_VALIDATE_URL) === false) {
self::$lasterror = sprintf('URL "%s" did not validate', $url);
return false;
}
// Now try to fetch it
$headers = @get_headers($url);
if ($headers == false) {
$error = error_get_last();
self::$lasterror = sprintf('URL "%s" could not be read: %s', $url, $error['message']);
return false;
}
$status = $headers[0];
$rbits = explode(' ', $status);
if (count($rbits) < 2) {
self::$lasterror = sprintf('Cannot parse status "%s" from URL "%s"', $status, $url);
return false;
}
if (in_array($rbits[1], array(301, 302, 304, 307, 308))) {
// This URL has been redirected. Follow the redirection chain
foreach ($headers as $header) {
if (cLib::startsWith($header, 'Location:')) {
if (++$nredirects > 10) {
self::$lasterror = sprintf('URL "%s" was redirected over 10 times: abandoned check', $url);
return false;
}
return self::checkUrl(trim(substr($header, strlen('Location:'))), $nredirects);
}
}
self::$lasterror = sprintf('URL "%s" was redirected but location could not be identified', $url);
return false;
}
if ($rbits[1] != 200) {
self::$lasterror = sprintf('URL "%s" returned status "%s"', $url, $status);
return false;
}
return true;
}
}
С извинениями перед @FranciscoLuz - если вы ожидаете ошибок, основанных на вводе данных пользователем, метод "@ and error_get_last" кажется мне совершенно разумным - я не вижу ничего более правильного в использовании set_error_handler.
Кстати, я не уверен, что мне следовало сделать это как изменение ответа @ Гордона, а не как отдельный ответ. Может кто-нибудь посоветовать?