如何使用PHP检查是否存在远程文件?

时间:2009-06-11 15:52:40

标签: php file networking testing

我能找到的最好的,if fclose fopen类型的东西,使页面加载速度非常慢。

基本上我要做的是以下内容:我有一个网站列表,我想在他们旁边显示他们的favicon。但是,如果一个站点没有,我想用另一个图像替换它而不是显示损坏的图像。

23 个答案:

答案 0 :(得分:128)

您可以通过CURLOPT_NOBODY指示curl使用HTTP HEAD方法。

或多或少

$ch = curl_init("http://www.example.com/favicon.ico");

curl_setopt($ch, CURLOPT_NOBODY, true);
curl_exec($ch);
$retcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
// $retcode >= 400 -> not found, $retcode = 200, found.
curl_close($ch);

无论如何,您只能节省HTTP传输的成本,而不是TCP连接的建立和关闭。如果小的话,你可能看不到多少改进。

如果结果太慢,那么在本地缓存结果似乎是一个好主意。 HEAD检查文件的时间,并在标题中返回。您可以像浏览器一样获取图标的CURLINFO_FILETIME。 在您的缓存中,您可以存储网址=> [favicon,时间戳]。然后,您可以比较时间戳并重新加载favicon。

答案 1 :(得分:59)

如果Pies说你可以使用cURL。你可以得到cURL只给你标题,而不是身体,这可能会使它更快。糟糕的域名可能总是需要一段时间,因为您将等待请求超时;您可以使用cURL更改超时长度。

以下是示例:

function remoteFileExists($url) {
    $curl = curl_init($url);

    //don't fetch the actual page, you only want to check the connection is ok
    curl_setopt($curl, CURLOPT_NOBODY, true);

    //do request
    $result = curl_exec($curl);

    $ret = false;

    //if request did not fail
    if ($result !== false) {
        //if request was ok, check response code
        $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);  

        if ($statusCode == 200) {
            $ret = true;   
        }
    }

    curl_close($curl);

    return $ret;
}

$exists = remoteFileExists('http://stackoverflow.com/favicon.ico');
if ($exists) {
    echo 'file exists';
} else {
    echo 'file does not exist';   
}

答案 2 :(得分:32)

CoolGoose的解决方案很好,但对于大文件来说速度更快(因为它只尝试读取1个字节):

if (false === file_get_contents("http://example.com/path/to/image",0,null,0,1)) {
    $image = $default_image;
}

答案 3 :(得分:27)

这不是您原来问题的答案,而是您尝试做的更好的方式:

而不是直接尝试直接获取该网站的favicon(这可能是一个皇家的痛苦,因为它可能是/favicon.png,/ favicon.ico,/ favicon.gif,甚至/path/to/favicon.png),使用谷歌:

<img src="http://www.google.com/s2/favicons?domain=[domain]">

完成。

答案 4 :(得分:18)

如果您正在处理图片,请使用getimagesize。与file_exists不同,此内置函数支持远程文件。它将返回一个包含图像信息的数组(width,height,type..etc)。您所要做的就是检查数组中的第一个元素(宽度)。使用print_r输出数组的内容

$imageArray = getimagesize("http://www.example.com/image.jpg");
if($imageArray[0])
{
    echo "it's an image and here is the image's info<br>";
    print_r($imageArray);
}
else
{
    echo "invalid image";
}

答案 5 :(得分:13)

最投票答案的完整功能:

function remote_file_exists($url)
{
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_NOBODY, true);
    curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    if( $httpCode == 200 ){return true;}
}

你可以像这样使用它:

if(remote_file_exists($url))
{
    //file exists, do something
}

答案 6 :(得分:7)

这可以通过获取HTTP状态代码(404 =未找到)来完成,这可以使用file_get_contentsDocs利用上下文选项。以下代码将重定向考虑在内,并将返回最终目标的状态代码(Demo):

$url = 'http://example.com/';
$code = FALSE;

$options['http'] = array(
    'method' => "HEAD",
    'ignore_errors' => 1
);

$body = file_get_contents($url, NULL, stream_context_create($options));

foreach($http_response_header as $header)
    sscanf($header, 'HTTP/%*d.%*d %d', $code);

echo "Status code: $code";

如果您不想关注重定向,则可以执行类似的操作(Demo):

$url = 'http://example.com/';
$code = FALSE;

$options['http'] = array(
    'method' => "HEAD",
    'ignore_errors' => 1,
    'max_redirects' => 0
);

$body = file_get_contents($url, NULL, stream_context_create($options));

sscanf($http_response_header[0], 'HTTP/%*d.%*d %d', $code);

echo "Status code: $code";

在我撰写的博客文章中详细解释了一些正在使用的函数,选项和变量:HEAD first with PHP Streams

答案 7 :(得分:6)

if (false === file_get_contents("http://example.com/path/to/image")) {
    $image = $default_image;
}

应该工作;)

答案 8 :(得分:6)

如果出于安全原因将 allow_url_fopen 设置设置为off,则PHP的内置函数可能无法用于检查URL。 Curl是一个更好的选项,因为我们不需要更改代码在后期。以下是我用来验证有效网址的代码:

$url = str_replace(' ', '%20', $url);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_exec($ch);
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);  
curl_close($ch);
if($httpcode>=200 && $httpcode<300){  return true; } else { return false; } 

请注意 CURLOPT_SSL_VERIFYPEER 选项,该选项还会验证以HTTPS开头的网址。

答案 9 :(得分:4)

一个根本的解决方案是将favicon作为背景图像显示在默认图标上方的div中。这样,所有开销都将放在客户端上,同时仍然不显示损坏的图像(在所有浏览器AFAIK中都会忽略丢失的背景图像)。

答案 10 :(得分:3)

要检查图片是否存在,exif_imagetype应优先于getimagesize,因为速度要快得多。

要取消 E_NOTICE ,只需添加错误控制运算符(@)。

if (@exif_imagetype($filename)) {
  // Image exist
}

作为奖励,使用IMAGETYPE_XXX的返回值(exif_imagetype),我们还可以使用image_type_to_mime_type / image_type_to_extension获取mime类型或文件扩展名。< / p>

答案 11 :(得分:3)

function remote_file_exists($url){
   return(bool)preg_match('~HTTP/1\.\d\s+200\s+OK~', @current(get_headers($url)));
}  
$ff = "http://www.emeditor.com/pub/emed32_11.0.5.exe";
    if(remote_file_exists($ff)){
        echo "file exist!";
    }
    else{
        echo "file not exist!!!";
    }

答案 12 :(得分:3)

您可以使用以下内容:

$file = 'http://mysite.co.za/images/favicon.ico';
$file_exists = (@fopen($file, "r")) ? true : false;

在尝试检查网址上是否存在图片

时为我工作

答案 13 :(得分:2)

您可以使用:

$url=getimagesize(“http://www.flickr.com/photos/27505599@N07/2564389539/”);

if(!is_array($url))
{
   $default_image =”…/directoryFolder/junal.jpg”;
}

答案 14 :(得分:1)

还有一个更复杂的选择。您可以使用JQuery技巧检查所有客户端。

$('a[href^="http://"]').filter(function(){
     return this.hostname && this.hostname !== location.hostname;
}).each(function() {
    var link = jQuery(this);
    var faviconURL =
      link.attr('href').replace(/^(http:\/\/[^\/]+).*$/, '$1')+'/favicon.ico';
    var faviconIMG = jQuery('<img src="favicon.png" alt="" />')['appendTo'](link);
    var extImg = new Image();
    extImg.src = faviconURL;
    if (extImg.complete)
      faviconIMG.attr('src', faviconURL);
    else
      extImg.onload = function() { faviconIMG.attr('src', faviconURL); };
});

来自http://snipplr.com/view/18782/add-a-favicon-near-external-links-with-jquery/(原博客目前已关闭)

答案 15 :(得分:1)

这对我来说可以检查PHP中是否存在远程文件:

$url = 'https://cdn.sstatic.net/Sites/stackoverflow/img/favicon.ico';
    $header_response = get_headers($url, 1);

    if ( strpos( $header_response[0], "404" ) !== false ) {
        echo 'File does NOT exist';
        } else {
        echo 'File exists';
        }

答案 16 :(得分:1)

这里使用get_headers()的所有答案都在执行GET请求。 只是做一个HEAD请求要快得多/便宜得多。

要确保get_headers()执行HEAD请求而不是GET,您应该添加:

stream_context_set_default(
    array(
        'http' => array(
            'method' => 'HEAD'
        )
    )
);

因此要检查文件是否存在,您的代码应如下所示:

stream_context_set_default(
    array(
        'http' => array(
            'method' => 'HEAD'
        )
    )
);
$headers = get_headers('http://website.com/dir/file.jpg', 1);
$file_found = stristr($headers[0], '200');

$ file_found显然会返回false或true。

答案 17 :(得分:1)

您应该发出HEAD请求,而不是GET,因为您根本不需要URI内容。正如Pies所说,您应该检查状态代码(在200-299范围内,您可以选择遵循3xx重定向)。

答案问题包含许多可能有用的代码示例:PHP / Curl: HEAD Request takes a long time on some sites

答案 18 :(得分:0)

当文件不存在远程is_file()时,不知道这个文件是否更快,但你可以试一试。

$favIcon = 'default FavIcon';
if(is_file($remotePath)) {
   $favIcon = file_get_contents($remotePath);
}

答案 19 :(得分:0)

如果文件不是外部托管的,则可以将远程URL转换为Web服务器上的绝对路径。这样,您不必调用CURL或file_get_contents等。

function remoteFileExists($url) {

    $root = realpath($_SERVER["DOCUMENT_ROOT"]);
    $urlParts = parse_url( $url );

    if ( !isset( $urlParts['path'] ) )
        return false;

    if ( is_file( $root . $urlParts['path'] ) )
        return true;
    else
        return false;

}

remoteFileExists( 'https://www.yourdomain.com/path/to/remote/image.png' );
  

注意:您的网络服务器必须填充DOCUMENT_ROOT才能使用此功能

答案 20 :(得分:0)

如果您使用的是Symfony框架,则使用HttpClientInterface的方法也更简单:

private function remoteFileExists(string $url, HttpClientInterface $client): bool {
    $response = $client->request(
        'GET',
        $url //e.g. http://example.com/file.txt
    );

    return $response->getStatusCode() == 200;
}

HttpClient的文档也非常好,如果您需要更具体的方法,也许值得研究:https://symfony.com/doc/current/http_client.html

答案 21 :(得分:0)

如果您使用的是 Laravel 框架或 guzzle 包,那么还有一种使用 guzzle 客户端的更简单的方法,它也可以在链接重定向时工作:

$client = new \GuzzleHttp\Client(['allow_redirects' => ['track_redirects' => true]]);
try {
    $response = $client->request('GET', 'your/url');
    if ($response->getStatusCode() != 200) {
        // not exists
    }
} catch (\GuzzleHttp\Exception\GuzzleException $e) {
    // not exists
}

文档中的更多内容:https://docs.guzzlephp.org/en/latest/faq.html#how-can-i-track-redirected-requests

答案 22 :(得分:-1)

您可以使用文件系统: 使用Symfony \ Component \ Filesystem \ Filesystem; 使用Symfony \ Component \ Filesystem \ Exception \ IOExceptionInterface;

并检查         $ fileSystem = new Filesystem();         如果($ fileSystem-> exists('path_to_file')== true){...