检测PHP链接是否会导致c#中的文件下载

本文关键字:文件下载 PHP 链接 是否 检测 | 更新日期: 2023-09-27 17:49:42

我似乎找不到一个有效的答案来解决我的问题,我想知道是否有人可以帮助我。基本上,我的网站上有一个链接,可以下载一个zip文件:

http://***.com/download.php?id=1

如果你在网页上激活这个链接,它会弹出一个另存为对话框,让你用默认名称ThisIsMyZipFile.zip保存文件

我的问题是,在c#下,如果我使用new Uri("http://***.com/download.pgp?id=1").IsFile,它返回false,所以我似乎无法检测到这是一个文件,而不执行webclient DownloadString并查看前两个字节是否为PK

也即使手动下载作为字符串检测PK头并保存文件,我无法找出我的网站想要使用的默认文件名是ThisIsMyZipFile.zip在这个例子中,因为我想使用相同的文件名。

有谁知道解决这两个问题的好方法吗?

更新

感谢Paul和他的回答,我创建了下面的函数,它正好满足了我的需求:

/// <summary>
/// Returns the responded HTTP headers of the given URL and if the link refers to the file it returns extra information about it.
/// </summary>
/// <param name="Url">The address.</param>
/// <returns>
/// null if a WebException is thrown
/// otherwise:
/// List of headers:
///     Keep-Alive          - Timeout value (i.e. timeout=2, max=100)
///     Connection          - The type of connection (i.e. Keep-Alive)
///     Transfer-Encoding   - The type of encoding used for the transfer (i.e. chunked)
///     Content-Type        - The type of Content that will be transferred (i.e. application/zip)
///     Date                - The servers date and time
///     Server              - The server that is handling the request (i.e. Apache)
///     AbsoluteUri         - The full Uri of the resulting link that will be followed.
/// The following key will be present if the link refers to a file
///     Filename            - The filename (not path) of the file that will be downloaded if the link if followed.
/// </returns>
public Dictionary<string, string> GetHTTPResponseHeaders(string Url)
{
    WebRequest WebRequestObject = HttpWebRequest.Create(Url);
    WebResponse ResponseObject = null;
    try
    {
        ResponseObject = WebRequestObject.GetResponse();
    }
    catch(WebException ex)
    {
        return null;
    }
    // Add the header inforamtion to the resulting list
    Dictionary<string, string> HeaderList = new Dictionary<string, string>();
    foreach (string HeaderKey in ResponseObject.Headers)
        HeaderList.Add(HeaderKey, ResponseObject.Headers[HeaderKey]);
    // Add the resolved Uri to the resulting list
    HeaderList.Add("AbsoluteUri", ResponseObject.ResponseUri.AbsoluteUri);
    // If this is a zip file then add the download filename specified by the server to the resulting list
    if (ResponseObject.ContentType.ToLower() == "application/zip")
    {
        HeaderList.Add("Filename", ResponseObject.ResponseUri.Segments[ResponseObject.ResponseUri.Segments.Length-1]);
    }
    // We are now finished with our response object
    ResponseObject.Close();
    // Return the resulting list
    return HeaderList;
}

检测PHP链接是否会导致c#中的文件下载

Uri.IsFile对URI执行静态检查,即它查看'scheme'部分(包括冒号的第一个位)是否为file:。它不查看通过请求驻留在URI中的资源返回的实际内容。(事实上,因为它实际上根本没有尝试联系服务器,所以URI实际上可能指向丢失的资源,而IsFile仍然可以工作。)

如果您希望查看资源的内容是否属于特定类型,那么您必须:

  1. 检索资源的HTTP报头(如果它是HTTP或HTTPs资源:也就是说,如果'方案'是httphttps)。
  2. 检索(至少部分)资源并检查它。

您目前正在执行2,但对于HTTP资源(带有HTTP URL),那么执行1将更干净,更便宜。您可以通过执行HTTP HEAD请求(与GETPOST相反,&c.)来实现这一点。这将返回HTTP标头,而不返回资源本身。代码看起来像这样:

var request = WebRequest.Create("http://somewhere.overtherainbow.com/?a=b");
request.Method = "HEAD";
WebResponse response = request.GetResponse();
//TODO check status code
string contentType = response.ContentType;
response.Close();

内容类型将为您提供文件类型的一些指示,但是许多二进制文件只是作为八位元组流返回,因此如果您希望区分不同的二进制文件类型,您可能仍然需要检索和检查资源本身的神奇字节。(内容类型应该足以让你区分二进制文件和网页。)

因此,完整的解决方案可能是:

  1. 为资源发送GET请求
  2. 检查响应状态以确保没有错误。
  3. 检查内容类型头,看看我们是否有二进制八字节流。
  4. 从响应流中读取两个字节,看看文件是否开始"PK"。

如果不向该URL发送HTTP请求,您绝对无法检测到给定的URL会导致文件被下载。

现在讨论第二个问题。你可以发送一个HTTP请求来下载文件,然后检查Content-Disposition头,它将包含文件名:

using (var client = new WebClient())
{
    using (var stream = client.OpenRead("http://*.com/download.php?id=1"))
    {
        var disposition = client.ResponseHeaders["Content-Disposition"];
        if (disposition != null)
        {
            var cd = new ContentDisposition(disposition);
            if (!cd.Inline && !string.IsNullOrEmpty(cd.FileName))
            {
                using (var outputStream = File.OpenWrite(cd.FileName))
                {
                    stream.CopyTo(outputStream);
                }
            }
        }
        else
        {
            // The web server didn't send a Content-Disposition response header
            // so we have absolutely no means of determining the filename
            // you will have to use some default value here if you want to store it
        }
    }
}