写PHP程序时,判断一个URL是否有效,最直接的办法是拿它去请求一次。别想复杂了,就用`get_headers()`,这个函数会返回服务器响应头,里面藏着HTTP状态码。200、301、302都算有效,404、500这些就是无效。
代码写起来两三行就够:
$headers = @get_headers($url); if ($headers && strpos($headers[0], '200') !== false) { echo '这个URL活着'; } else { echo '这个URL死了'; } 注意那个`@`符号,这是抑制错误的。为什么?因为URL指向域名不存在时,`get_headers()`会直接抛警告,不抑制的话页面上会蹦出难看的报错信息。但说实话,用`@`是偷懒做法,严谨点应该用`file_get_contents()`配合`stream_context_create()`,设置超时时间,再检查返回结果。
有个坑得提醒你——重定向。很多URL会先返回302跳转,最后落到真实页面。你只检查第一次响应头,可能误判。比如`http://example.com`跳到`https://example.com`,第一次响应是301,第二次才是200。这时候得把`get_headers()`的第二个参数设为1,它会返回所有重定向的响应头,然后你取最后一个状态码判断。
$headers = @get_headers($url, 1); $statusLine = is_array($headers) ? end($headers) : ''; if (strpos($statusLine, '200') !== false) { echo '有效'; } 但这种方法有个致命伤——慢。遇到响应慢的服务器,`get_headers()`默认会等很久。我平时写爬虫脚本,测试一批URL,几百个链接跑下来,卡死的能等上几分钟。解决办法是设置默认socket超时时间,用`ini_set('default_socket_timeout', 5)`,五秒没响应直接判死。别心疼误判,真实场景下五秒都响应不了的服务器,你也不希望程序一直耗着。
还有一个更轻量的方案,用cURL库。它比`get_headers()`灵活得多,能自定义超时、设置UA、跳过SSL验证。比如你要检查的URL是HTTPS但证书过期了,`get_headers()`会失败,但cURL设置`CURLOPT_SSL_VERIFYPEER`为false就能正常请求。不过cURL不是PHP默认启用的扩展,得在php.ini里打开`extension=curl`。
$ch = curl_init($url); curl_setopt($ch, CURLOPT_NOBODY, true); // 只要header,不要body curl_setopt($ch, CURLOPT_TIMEOUT, 5); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $result = curl_exec($ch); $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($status >= 200 && $status < 400) { echo '有效'; } else { echo '无效'; } 实际工作中,我遇到过最烦的情况不是URL打不开,而是URL能打开但返回的是假页面。比如某些网站对非浏览器UA返回403,或者跳转到登录页。你判断状态码是200,实际上内容根本不是你要的。这时候就得结合业务逻辑,检查响应体里有没有关键词,或者URL的最终落点是不是预期域名。
另外说个冷门的——`filter_var($url, FILTER_VALIDATE_URL)`只能验证URL格式是否合法,不能判断它是否真的能访问。很多人新手容易搞混,拿这个函数去判断有效性,结果返回true,实际请求却404。格式合法和可访问是两码事,别偷懒。
写到最后,给你一个我的习惯:封装一个函数,把cURL逻辑放进去,默认不允许重定向,超时设3秒,返回布尔值。测试时先跑一遍已知有效的URL,再跑一个明显无效的,确认逻辑没毛病。做批量检查时,用`array_map`配合`usleep`错开请求时间,别把目标服务器打挂了。毕竟你只是检查URL,不是做DDoS攻击。














