La idea de escribir esta biblioteca surgió cuando quería aprovechar al máximo la oferta gratuita de Oracle Cloud Infrastructure, es decir, 10 GB de almacenamiento de objetos y 10 TB de tráfico saliente por mes. La diferencia con AWS S3 es enorme . Desafortunadamente, Oracle Cloud no tiene un SDK disponible para el lenguaje de programación aún más popular para el desarrollo de sitios web. La buena noticia es que el servicio es parcialmente compatible con Amazon S3, lo que significa que puede utilizar herramientas de desarrollo existentes y bien documentadas , incluso para PHP.
Para aquellos que estén ansiosos por ver el código, bienvenidos a https://github.com/hitrov/oci-api-php-request-sign .
De hecho, con las herramientas disponibles, puede realizar casi todas las operaciones imaginables: crear, leer y eliminar depósitos y objetos (archivos). Las papeleras de reciclaje pueden ser públicas (con o sin archivos de lista) y privadas. Es posible cargar archivos en una canasta privada, teniendo solo una URL "secreta" (generada manualmente usando la CLI o la interfaz web - consola de Oracle Cloud). De hecho, esto puede ser suficiente para muchos escenarios, especialmente si genera nombres de archivo de fuerza bruta en caso de que no quiera exponerlos al público.
Estaba interesado en la capacidad de "compartir" archivos, es decir, compartir enlaces públicos a archivos y, por supuesto, restringir el acceso si es necesario. Con una pequeña cantidad de archivos, puede hacerlo manualmente, pero estamos reunidos aquí para tener acceso mediante programación. AWS S3 llama a esto una URL pre-firmada , mientras que Oracle la llama Solicitud pre-autenticada .
Instalación de AWS PHP SDK
composer require aws/aws-sdk-php
A continuación, se mostrará dónde obtener acceso ( AWS_ACCESS_KEY_ID
y AWS_SECRET_ACCESS_KEY
.
Se puede ver el espacio de nombres
require('vendor/autoload.php');
$namespaceName = 'frpegp***';
$bucketName = 'test******05';
$region = 'eu-frankfurt-1';
$endpoint = "https://$namespaceName.compat.objectstorage.$region.oraclecloud.com";
$s3 = new Aws\S3\S3Client([
'version' => 'latest',
'region' => $region,
'endpoint' => $endpoint,
'signature_version' => 'v4',
'use_path_style_endpoint' => true,
'credentials' => [
'key' => 'AKI***YYJ', // remove if you have env var AWS_ACCESS_KEY_ID
'secret' => 'ndK***cIf', // remove if you have env var AWS_SECRET_ACCESS_KEY
],
]);
$cmd = $s3->getCommand('GetObject', [
'Bucket' => $bucketName,
'Key' => 'fff.txt'
]);
$request = $s3->createPresignedRequest($cmd, '+20 minutes');
var_dump($request);
object(GuzzleHttp\Psr7\Request)#146 (7) {
["method":"GuzzleHttp\Psr7\Request":private]=>
string(3) "GET"
["uri":"GuzzleHttp\Psr7\Request":private]=>
object(GuzzleHttp\Psr7\Uri)#148 (7) {
["scheme":"GuzzleHttp\Psr7\Uri":private]=>
string(5) "https"
...
["host":"GuzzleHttp\Psr7\Uri":private]=>
string(64) "{namespace}.compat.objectstorage.eu-frankfurt-1.oraclecloud.com"
...
["path":"GuzzleHttp\Psr7\Uri":private]=>
string(21) "/{bucket}/fff.txt"
["query":"GuzzleHttp\Psr7\Uri":private]=>
string(329) "X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=&&&%2F20210211%2Feu-frankfurt-1%2Fs3%2Faws4_request&X-Amz-Date=20210211T093350Z&X-Amz-SignedHeaders=host&X-Amz-Expires=1200&X-Amz-Signature=1e1b1***6ac992"
...
}
}
Esta operación devuelve una solicitud de PSR-7 en respuesta , desde la cual puede generar una URL del formulario
https://{namespace}.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/{bucket}/fff.txt?X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=***%2F20210210%2Feu-frankfurt-1%2Fs3%2Faws4_request&X-Amz-Date=20210210T185244Z&X-Amz-SignedHeaders=host&X-Amz-Expires=1200&X-Amz-Signature=a167a***9a857
Pero, lamentablemente, esto no permite revocar el acceso, por ejemplo, si el enlace es "de larga duración".
, \\ , DNS Email. API Reference and Endpoints.
, , , , - () Oracle Cloud User Settings
API Keys — Add API Key
Download private key ( ), Add
,
, AWS PHP SDK, Customer Secret Keys ( AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
Amazon.
Oracle Cloud Infrastructure mini PHP SDK ( !)
composer require hitrov/oci-api-php-request-sign
PSR-4 .
require 'vendor/autoload.php';
use Hitrov\OCI\Signer;
( , , ).
OCI_TENANCY_ID=ocid1.tenancy.oc1..aaaaaaaaba3pv6wkcr4jqae5f15p2b2m2yt2j6rx32uzr4h25vqstifsfdsq OCI_USER_ID=ocid1.user.oc1..aaaaaaaat5nvwcna5j6aqzjcaty5eqbb6qt2jvpkanghtgdaqedqw3rynjq OCI_KEY_FINGERPRINT=20:3b:97:13:55:1c:5b:0d:d3:37:d8:50:4e:c5:3a:34 OCI_PRIVATE_KEY_FILENAME=/path/to/privatekey.pem
.
$signer = new Signer;
https://github.com/hitrov/oci-api-php-request-sign#alternatives-for-providing-credentials , .
CreatePreauthenticatedRequest.
( )
public function getHeaders(
string $url, string $method = 'GET', ?string $body = null, ?string $contentType = 'application/json', string $dateString = null
): array
$curl = curl_init();
$url = 'https://objectstorage.eu-frankfurt-1.oraclecloud.com/n/{namespaceName}/b/{bucketName}/p/';
$method = 'POST';
$body = '{"accessType": "ObjectRead", "name": "read-access-to-image.png", "objectName": "path/to/image.png", "timeExpires": "2021-03-01T00:00:00-00:00"}';
$headers = $signer->getHeaders($url, $method, $body, 'application/json');
var_dump($headers);
$curlOptions = [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 5,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => $headers,
];
if ($body) {
// not needed for GET or HEAD requests
$curlOptions[CURLOPT_POSTFIELDS] = $body;
}
curl_setopt_array($curl, $curlOptions);
$response = curl_exec($curl);
echo $response;
curl_close($curl);
array(6) {
[0]=>
string(35) "date: Mon, 08 Feb 2021 20:49:22 GMT"
[1]=>
string(50) "host: objectstorage.eu-frankfurt-1.oraclecloud.com"
[2]=>
string(18) "content-length: 76"
[3]=>
string(30) "content-type: application/json"
[4]=>
string(62) "x-content-sha256: X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE="
[5]=>
string(538) "Authorization: Signature version=\"1\",keyId=\"ocid1.tenancy.oc1..aaaaaaaaba3pv6wkcr4jqae5f15p2b2m2yt2j6rx32uzr4h25vqstifsfdsq/ocid1.user.oc1..aaaaaaaat5nvwcna5j6aqzjcaty5eqbb6qt2jvpkanghtgdaqedqw3rynjq/20:3b:97:13:55:1c:5b:0d:d3:37:d8:50:4e:c5:3a:34\",algorithm=\"rsa-sha256\",headers=\"date (request-target) host content-length content-type x-content-sha256\",signature=\"LXWXDA8VmXXc1NRbMmXtW61IS97DfIOMAnlj+Gm+oBPNc2svXYdhcXNJ+oFPoi9qJHLnoUiHqotTzuVPXSG5iyXzFntvkAn3lFIAja52iwwwcJflEIXj/b39eG2dCsOTmmUJguut0FsLhCRSX0eylTSLgxTFGoQi7K/m18nafso=\""
}
{
"accessUri": "/p/AlIlOEsMok7oE7YkN30KJUDjDKQjk493BKbuM-ANUNGdBBAHzHT_5lFlzYC9CQiA/n/{namespaceName}/b/{bucketName}/o/path/to/image.png",
"id": "oHJQWGxpD+2PhDqtoewvLCf8/lYNlaIpbZHYx+mBryAad/q0LnFy37Me/quKhxEi:path/to/image.png",
"name": "read-access-to-image.png",
"accessType": "ObjectRead",
"objectName": "path/to/image.png",
"timeCreated": "2021-02-09T11:52:45.053Z",
"timeExpires": "2021-03-01T00:00:00Z"
}
!
, . , – .
1) , « » (SIGNING_HEADERS_NAMES).
date
· (request-target)
· host
POST|PUT|PATCH
· content-length
· content-type
· x-content-sha256
$signingHeadersNames = $signer->getSigningHeadersNames('POST');
2) SHA256 «» – base64
$bodyHashBase64 = $signer->getBodyHashBase64($body);
3) ,
date: Mon, 08 Feb 2021 20:51:33 GMT (request-target): post /n/{namespaceName}/b/{bucketName}/p/ host: objectstorage.eu-frankfurt-1.oraclecloud.com content-length: 76 content-type: application/json x-content-sha256: X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=
$signingString = $signer->getSigningString($url, $method, $body, 'application/json');
(2). , , 5 .
4) (3) RSA-SHA256
$signature = $signer->calculateSignature($signingString, $privateKeyString);
5) KEY_ID , API Key, ,
"{OCITENANCYID}/{OCIUSERID}/{OCIKEY_FINGERPRINT}"
$keyId = $signer->getKeyId();
6) ( 1
Oracle)
Authorization: Signature version=\"1\",keyId=\"{KEY_ID}\",algorithm=\"rsa-sha256\",headers=\"{SIGNING_HEADERS_NAMES_STRING}\",signature=\"{SIGNATURE}\"
SIGNING_HEADERS_NAMES_STRING – (1), .
date (request-target) host content-length content-type x-content-sha256
$signingHeadersNamesString = implode(' ', $signingHeadersNames);
$authorizationHeader = $signer->getAuthorizationHeader($keyId, $signingHeadersNamesString, $signature);
Authorization: Signature version=\"1\",keyId=\"ocid1.tenancy.oc1..aaaaaaaaba3pv6wkcr4jqae5f15p2b2m2yt2j6rx32uzr4h25vqstifsfdsq/ocid1.user.oc1..aaaaaaaat5nvwcna5j6aqzjcaty5eqbb6qt2jvpkanghtgdaqedqw3rynjq/20:3b:97:13:55:1c:5b:0d:d3:37:d8:50:4e:c5:3a:34\",algorithm=\"rsa-sha256\",headers=\"date (request-target) host content-length content-type x-content-sha256\",signature=\"LXWXDA8VmXXc1NRbMmXtW61IS97DfIOMAnlj+Gm+oBPNc2svXYdhcXNJ+oFPoi9qJHLnoUiHqotTzuVPXSG5iyXzFntvkAn3lFIAja52iwwwcJflEIXj/b39eG2dCsOTmmUJguut0FsLhCRSX0eylTSLgxTFGoQi7K/m18nafso=\"
- . var_dump()
- (3), (request-target) . , , (6).
Me ayudó el tutorial de llamadas REST de Oracle Cloud Infrastructure (OCI) con artículo curl . Algunos de los nombres de los métodos se tomaron prestados del SDK oficial de GoLang . Casos de prueba: desde el mismo lugar .