运行 PHP 的任何 Web 服务器可使用此 PHP 代码示例,来为私有的 CloudFront 分配创建策略声明和签名。该完整示例使用签名 URL 链接创建一个正常运作的网页,这些链接使用 CloudFront 流播放视频流。您可以从 demo-php.zip 文件下载完整示例。
备注
-
创建 URL 签名只是使用签名 URL 提供私有内容过程的一部分。有关整个过程的更多信息,请参阅使用签名 URL。
-
还可以通过使用 适用于 PHP 的 AWS SDK 中的
UrlSigner
类来创建签名 URL。有关更多信息,请参阅 适用于 PHP 的 AWS SDKAPI 参考中的 Class UrlSigner。
以下部分将代码示例细分到各个单独的部分。您可在下方找到完整代码示例。
创建 RSA SHA-1 签名
本代码示例执行以下操作:
-
函数
rsa_sha1_sign
执行哈希操作并签署策略声明。所需的参数是策略语句和私有密钥,该私有密钥对应于分配的可信密钥组中的公有密钥。 -
接下来,
url_safe_base64_encode
函数创建签名 URL 安全版本。
function rsa_sha1_sign($policy, $private_key_filename) {
$signature = "";
// load the private key
$fp = fopen($private_key_filename, "r");
$priv_key = fread($fp, 8192);
fclose($fp);
$pkeyid = openssl_get_privatekey($priv_key);
// compute signature
openssl_sign($policy, $signature, $pkeyid);
// free the key from memory
openssl_free_key($pkeyid);
return $signature;
}
function url_safe_base64_encode($value) {
$encoded = base64_encode($value);
// replace unsafe characters +, = and / with
// the safe characters -, _ and ~
return str_replace(
array('+', '=', '/'),
array('-', '_', '~'),
$encoded);
}
以下代码段使用函数 get_canned_policy_stream_name()
和 get_custom_policy_stream_name()
来创建标准策略和自定义策略。CloudFront 使用这些策略来创建用于流式传输视频的 URL,包括指定过期时间。
然后,您可以使用标准策略或自定义策略来确定如何管理对内容的访问。有关选择哪一项的更多信息,请参阅决定为签名 URL 使用标准策略还是自定义策略部分。
创建标准策略
以下代码示例构建了签名的标准策略声明。
注意
$expires
变量是一个日期/时间戳,必须为整数,而不是字符串。
function get_canned_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $expires) {
// this policy is well known by CloudFront, but you still need to sign it, since it contains your parameters
$canned_policy = '{"Statement":[{"Resource":"' . $video_path . '","Condition":{"DateLessThan":{"AWS:EpochTime":'. $expires . '}}}]}';
// the policy contains characters that cannot be part of a URL, so we base64 encode it
$encoded_policy = url_safe_base64_encode($canned_policy);
// sign the original policy, not the encoded version
$signature = rsa_sha1_sign($canned_policy, $private_key_filename);
// make the signature safe to be included in a URL
$encoded_signature = url_safe_base64_encode($signature);
// combine the above into a stream name
$stream_name = create_stream_name($video_path, null, $encoded_signature, $key_pair_id, $expires);
// URL-encode the query string characters
return $stream_name;
}
更多有关标准策略的信息,请参阅 使用标准策略创建签名 URL。
创建自定义策略
以下代码示例构建了签名的自定义 策略声明。
function get_custom_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $policy) {
// the policy contains characters that cannot be part of a URL, so we base64 encode it
$encoded_policy = url_safe_base64_encode($policy);
// sign the original policy, not the encoded version
$signature = rsa_sha1_sign($policy, $private_key_filename);
// make the signature safe to be included in a URL
$encoded_signature = url_safe_base64_encode($signature);
// combine the above into a stream name
$stream_name = create_stream_name($video_path, $encoded_policy, $encoded_signature, $key_pair_id, null);
// URL-encode the query string characters
return $stream_name;
}
更多有关自定义策略的信息,请参阅 使用自定义策略创建签名 URL。
完整代码示例
以下代码示例完整演示了使用 PHP 创建 CloudFront 签名 URL。您可以从 demo-php.zip 文件下载完整示例。
在下面的示例中,您可以修改 $policy
Condition
元素,以同时允许 IPv4 和 IPv6 地址范围。有关示例,请参阅《Amazon Simple Storage Service 用户指南》中的在 IAM 策略中使用 IPv6 地址。
<?php
function rsa_sha1_sign($policy, $private_key_filename) {
$signature = "";
// load the private key
$fp = fopen($private_key_filename, "r");
$priv_key = fread($fp, 8192);
fclose($fp);
$pkeyid = openssl_get_privatekey($priv_key);
// compute signature
openssl_sign($policy, $signature, $pkeyid);
// free the key from memory
openssl_free_key($pkeyid);
return $signature;
}
function url_safe_base64_encode($value) {
$encoded = base64_encode($value);
// replace unsafe characters +, = and / with the safe characters -, _ and ~
return str_replace(
array('+', '=', '/'),
array('-', '_', '~'),
$encoded);
}
function create_stream_name($stream, $policy, $signature, $key_pair_id, $expires) {
$result = $stream;
// if the stream already contains query parameters, attach the new query parameters to the end
// otherwise, add the query parameters
$separator = strpos($stream, '?') == FALSE ? '?' : '&';
// the presence of an expires time means we're using a canned policy
if($expires) {
$result .= $separator . "Expires=" . $expires . "&Signature=" . $signature . "&Key-Pair-Id=" . $key_pair_id;
}
// not using a canned policy, include the policy itself in the stream name
else {
$result .= $separator . "Policy=" . $policy . "&Signature=" . $signature . "&Key-Pair-Id=" . $key_pair_id;
}
// new lines would break us, so remove them
return str_replace('\n', '', $result);
}
function get_canned_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $expires) {
// this policy is well known by CloudFront, but you still need to sign it, since it contains your parameters
$canned_policy = '{"Statement":[{"Resource":"' . $video_path . '","Condition":{"DateLessThan":{"AWS:EpochTime":'. $expires . '}}}]}';
// the policy contains characters that cannot be part of a URL, so we base64 encode it
$encoded_policy = url_safe_base64_encode($canned_policy);
// sign the original policy, not the encoded version
$signature = rsa_sha1_sign($canned_policy, $private_key_filename);
// make the signature safe to be included in a URL
$encoded_signature = url_safe_base64_encode($signature);
// combine the above into a stream name
$stream_name = create_stream_name($video_path, null, $encoded_signature, $key_pair_id, $expires);
// URL-encode the query string characters
return $stream_name;
}
function get_custom_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $policy) {
// the policy contains characters that cannot be part of a URL, so we base64 encode it
$encoded_policy = url_safe_base64_encode($policy);
// sign the original policy, not the encoded version
$signature = rsa_sha1_sign($policy, $private_key_filename);
// make the signature safe to be included in a URL
$encoded_signature = url_safe_base64_encode($signature);
// combine the above into a stream name
$stream_name = create_stream_name($video_path, $encoded_policy, $encoded_signature, $key_pair_id, null);
// URL-encode the query string characters
return $stream_name;
}
// Path to your private key. Be very careful that this file is not accessible
// from the web!
$private_key_filename = '/home/test/secure/example-priv-key.pem';
$key_pair_id = 'K2JCJMDEHXQW5F';
// Make sure you have "Restrict viewer access" enabled on this path behaviour and using the above Trusted key groups (recommended).
$video_path = 'https://example.com/secure/example.mp4';
$expires = time() + 300; // 5 min from now
$canned_policy_stream_name = get_canned_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $expires);
// Get the viewer real IP from the x-forward-for header as $_SERVER['REMOTE_ADDR'] will return viewer facing IP. An alternative option is to use CloudFront-Viewer-Address header. Note that this header is a trusted CloudFront immutable header. Example format: IP:PORT ("CloudFront-Viewer-Address": "1.2.3.4:12345")
$client_ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
$policy =
'{'.
'"Statement":['.
'{'.
'"Resource":"'. $video_path . '",'.
'"Condition":{'.
'"IpAddress":{"AWS:SourceIp":"' . $client_ip . '/32"},'.
'"DateLessThan":{"AWS:EpochTime":' . $expires . '}'.
'}'.
'}'.
']' .
'}';
$custom_policy_stream_name = get_custom_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $policy);
?>
<html>
<head>
<title>CloudFront</title>
</head>
<body>
<h1>Amazon CloudFront</h1>
<h2>Canned Policy</h2>
<h3>Expires at <?php echo gmdate('Y-m-d H:i:s T', $expires); ?></h3>
<br />
<div id='canned'>The canned policy video will be here: <br>
<video width="640" height="360" autoplay muted controls>
<source src="<?php echo $canned_policy_stream_name; ?>" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
<h2>Custom Policy</h2>
<h3>Expires at <?php echo gmdate('Y-m-d H:i:s T', $expires); ?> only viewable by IP <?php echo $client_ip; ?></h3>
<div id='custom'>The custom policy video will be here: <br>
<video width="640" height="360" autoplay muted controls>
<source src="<?php echo $custom_policy_stream_name; ?>" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
</body>
</html>
有关更多 URL 签名示例,请参阅以下主题:
您可以不使用签名 URL 来创建签名,而是使用签名 Cookie。有关更多信息,请参阅 使用 PHP 创建签名 Cookie。