【问题标题】:Force download on GCS via App Engine using Signed URL使用签名 URL 通过 App Engine 在 GCS 上强制下载
【发布时间】:2016-04-25 10:56:24
【问题描述】:

我通过以下方式获取我的文件:

require_once 'google/appengine/api/cloud_storage/CloudStorageTools.php';    
use google\appengine\api\cloud_storage\CloudStorageTools;

$public_link = CloudStorageTools::getPublicUrl("gs://bucket/file.pdf", false);

如果我在浏览器中转到$public_link,它会在浏览器中显示 PDF。我正在尝试弄清楚如何强制下载此文件。

Google App Engine 只有 60 秒超时,所以恐怕 serve 功能无法通过 GAE 工作。有人有什么建议吗?

--

编辑

Andrei Volga 在这篇文章中的先前回答建议我使用带有 response-content-distribution 标头的签名 URL。

到目前为止,我能够创建一个成功显示文件的签名 URL,但我无法生成一个具有任何类型标题的签名 URL,也就是创建一个签名 URL将强制下载而不是仅仅显示它。

这是我目前所拥有的,大部分是courtesy of mloureiro

function googleBuildConfigurationString($method, $expiration, $file, array $options = [])
{
    $allowedMethods = ['GET', 'HEAD', 'PUT', 'DELETE'];
    // initialize
    $method = strtoupper($method);
    $contentType = $options['Content_Type'];
    $contentMd5 = $options['Content_MD5'] ? base64_encode($options['Content_MD5']) : '';
     $headers = $options['Canonicalized_Extension_Headers'] ? $options['Canonicalized_Extension_Headers'] . PHP_EOL : '';
     $file = $file ? $file : $options['Canonicalized_Resource'];

     // validate
    if(array_search($method, $allowedMethods) === false)
    {
        throw new RuntimeException("Method '{$method}' is not allowed");
    }

    if(!$expiration)
    {
        throw new RuntimeException("An expiration date should be provided.");
    }

    return <<<TXT
{$method}
{$contentMd5}
{$contentType}
{$expiration}
{$headers}{$file}
TXT;
    }

function googleSignString($p12FilePath, $string)
{
    $certs = [];

    if (!openssl_pkcs12_read(file_get_contents($p12FilePath), $certs, 'notasecret'))
    {
        echo "Unable to parse the p12 file. OpenSSL error: " . openssl_error_string(); exit();
    }

    $RSAPrivateKey = openssl_pkey_get_private($certs["pkey"]);
    $signed = '';

    if(!openssl_sign( $string, $signed, $RSAPrivateKey, 'sha256' ))
    {
        error_log( 'openssl_sign failed!' );
        $signed = 'failed';
    }
    else $signed = base64_encode($signed);

    return $signed;
}

function googleBuildSignedUrl($serviceEmail, $file, $expiration, $signature)
{
    return "http://storage.googleapis.com{$file}" . "?GoogleAccessId={$serviceEmail}" . "&Expires={$expiration}" . "&Signature=" . urlencode($signature);
}

$serviceEmail = '<EMAIL>';
$p12FilePath = '../../path/to/cert.p12';
$expiration = (new DateTime())->modify('+3hours')->getTimestamp();
$bucket = 'bucket';
$fileToGet = 'picture.jpg';

$file = "/{$bucket}/{$fileToGet}";
$string = googleBuildConfigurationString('GET', $expiration, $file, array("Canonicalized_Extension_Headers" => ''));
$signedString = googleSignString($p12FilePath, $string);
$signedUrl = googleBuildSignedUrl($serviceEmail, $file, $expiration, $signedString);

echo $signedUrl;

【问题讨论】:

    标签: php google-app-engine google-cloud-storage pre-signed-url


    【解决方案1】:

    您只能添加额外的查询字符串。

    https://cloud.google.com/storage/docs/xml-api/reference-headers#responsecontentdisposition

    响应内容处置

    一个查询字符串参数,允许为经过身份验证的 GET 请求覆盖内容处置。

    返回的有效值是 URL 编码的标头,而不是基础对象的内容配置。

    例子

    ?response-content-disposition=attachment%3B%20filename%3D%22foo%22
    

    【讨论】:

      【解决方案2】:

      对于小文件,您可以使用 serve 选项而不是公共 URL,并将 save-as 选项设置为 true。见documentation

      对于大文件,您可以使用带有response-content-disposition 参数的Signed URL

      【讨论】:

      • 但是如果我提供一个 1GB 的文件,这不会超过 60 秒的限制吗?
      • 它不适用于任何超过 32MB 的文件 - 这是 App Engine 上任何响应的限制。我会更新我的答案。
      • 我能够成功获取签名 URL(检查以前的编辑),但我不知道如何正确获取标题。有什么建议吗?
      • 这是我的 Java 代码片段。你可以调整它:.append("&amp;response-content-disposition=") .append(URLEncoder.encode("attachment;filename=" + "\"" + file.name + "\"", "UTF-8"))
      • 所以基本上,您需要添加&amp;response-content-disposition=attachment;filename=,后跟一个文件名。我对其进行 URL 编码,但如果您事先知道文件名并且它是 URL 安全的(例如,没有空格等),则没有必要
      猜你喜欢
      • 2011-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-28
      • 2012-08-26
      • 1970-01-01
      相关资源
      最近更新 更多