autoaction/vbn-php-client

Pacote para geração de URLs assinadas do GCP CDN.

v2.1.0 2025-09-30 21:29 UTC

README

É necessário que o usuário que vai acessar o GCP tenha essa permissão, caso contrário o cache não poderá ser invalidado

compute.urlMaps.invalidateCache

Certifique-se que o bucket está mapeado em um Load Balancer no GCP

Consulte o Notion específico para realizar as etapas abaixo: :: Acesse o Load Balancer :: Cria um backend de Bucket :: Crie o mapeamento do backent e o bucket

Em caso de atualização da lib

:: Fazer o push dentro da branch master :: criar uma tag vxxxxx (Ex: v1.0.8)

git tag v1.0.8

:: Fazer o push da tag

git push origin v1.0.8

Documento do Client para VBN

Inspirado em DSL(Domain Specific Language) internas, para controle e solicitação fluída

Abaixo um exemplo prático de como o cliente deve se comportar

Para tests

Subir os containers

make up

Executar testes em versões PHP 5.6 e PHP 7.1

make test

Fase de configuração

<?php
namespace NAMESPACE\Libs;

use AutoAction\VBNAutoAction\Response\CollectionResponses;
use AutoAction\VBNAutoAction\Response\SingleResponse;
use AutoAction\VBNAutoAction\VBNAutoAction;
use Config\ConfigStatic;
use Google\Cloud\Storage\StorageClient;
use Exception;
use GuzzleHttp\Psr7\Response;

class VBNHelper extends VBNAutoAction
{
    const VBN_PROD_URL = 'https://url_da_cdn';
    const GOOGLE_LOAD_BALANCE = 'nome_do_load_balance';
    const DEFAULT_BUCKET = '';
    const GOOGLE_URL_MAP_NAME = 'nome_da_url_map';
    const CDN_TO_BUCKET = [
        'url_do_cdn_1' => [
            'bucket_mapeado_1',
            'bucket_mapeado_2'
        ],
        'url_do_cdn_2' => 'bucket_mapeado_1',
    ];

    /**
     * Inicializa a configuração com as chaves e valores necessários.
     *
     * @return array
     *
     * A função retorna um array associativo com os seguintes itens:
     * - 'cdn_key_name' (string): Nome da chave criada no balanceador de carga.
     * - 'cdn_key_value' (string): Valor da chave criada no balanceador de carga.
     * - 'google_key_file_path' (string): Caminho para o arquivo com as credenciais do Google Cloud Platform (GCP).
     * - 'google_bucket_mapped' (array): Lista de nomes de buckets mapeados no balanceador de carga.
     * - 'cdn_hostname' (string): url completa do cdn sem http/https.
     * - 'google_key_json' (json) json com os valores das credenciais do Google Cloud Platform (GCP).
     */
    private static function initConfig(): array
    {
        return [
            'cdn_key_name' => nome_da_key_criado_no_load_balance,
            'cdn_key_value' => valor_da_key_criado_no_load_balance,
            'google_key_file_path' => arquivo_com_as_credenciais_do_gcp,
            'google_bucket_mapped' => array_com_nomes_dos_bucket_mapeados_no_load_balance,
            'cdn_hostname' => parse_url(self::VBN_PROD_URL, PHP_URL_HOST),
            'google_key_json' => arquivo_com_as_credenciais_do_gcp_em_formato_json,
        ];
    }

    /**
     * @param string $bucketName
     * @param string $prefix
     * @return SingleResponse
     * @throws Exception
     */
    public static function getOneSingleImage(string $bucketName, string $prefix): SingleResponse
    {
        self::init(self::initConfig());
        $imagePath = "/{$bucketName}/{$prefix}";
        $collection = self::getOneImage($imagePath);
        /*
         * FIXME: Função utilizada para pegar os metadados do arquivo e agrupar com as url's assinadas
         *  os metadados vêem do bucket no GCP, então tem um custo para fazer essas requisições
        $metadata = self::getSingleFileMetadata($imagePath, $bucketName);
        if (!empty($metadata)) {
            self::addMetadataToSingle($collection, $metadata);
        }
        */
        return $collection;
    }


    /**
     * @param string $bucketName
     * @param string $prefix
     * @return CollectionResponses
     * @throws Exception
     */
    public static function getImagesByPrefix(string $bucketName, string $prefix): CollectionResponses
    {
        self::init(self::initConfig());
        self::setBucket($bucketName);
        self::getGcpCredentials();
        if (!self::$credentials) {
            $response = new Response(200, [], []);
            return new CollectionResponses($response);
        }

        $storage = new StorageClient([
            'credentials' => self::$credentials
        ]);
        $bucket = $storage->bucket($bucketName);
        $objects = $bucket->objects([
            'prefix' => $prefix
        ]);

        try {
            $images = [];
            foreach ($objects as $object) {
                $images[] = "{$bucketName}/{$object->name()}";
            }
            $collection = self::getMultiplesImage($images);
            /*
             * FIXME: Função utilizada para pegar os metadados do arquivo e agrupar com as url's assinadas
             *  os metadados vêem do bucket no GCP, então tem um custo para fazer essas requisições
            $metadatas = self::getFileMetadataByPrefix($prefix, $bucketName);
            if (!empty($metadatas)) {
                foreach ($collection as $item) {
                    self::addMetadataToCollection($item, $metadatas);
                }
            }
            */
            return $collection;
        } catch (\Exception $e) {
            $error = [[
                'fileName' => '',
                'message' => $e->getMessage()
            ]];
            $response = new Response(200, [], json_encode($error));
            return new CollectionResponses($response);
        }
    }

    /**
     * @param array $images
     * @return CollectionResponses
     * @throws Exception
     */
    public static function getMultiplesImage(array $images): CollectionResponses
    {
        self::init(self::initConfig());
        $collection = self::getMultiplesImageSignature($images);
        /*
         * FIXME: Função utilizada para pegar os metadados do arquivo e agrupar com as url's assinadas
         *  os metadados vêem do bucket no GCP, então tem um custo para fazer essas requisições
        $metadatas = self::getMultiplesFileMetadata($images, self::$bucketName);
        if (!empty($metadatas)) {
            foreach ($collection as $item) {
                self::addMetadataToCollection($item, $metadatas);
            }
        }
        */
        return $collection;
    }

    /**
     * @param array|string $imagePaths
     * @return bool
     * @throws Exception
     * $imagePaths pode ser o nome completo do arquivo ou por prefix
     * Ex: /bucket/caminho_do_arquivo/nome_do_arquivo_1.jpg
     * ou /bucket/caminho_do_arquivo/nome_do_arquivo_*
     */
    public static function invalidateVBNCache($imagePaths): bool
    {
        self::init(self::initConfig());
        return self::invalidateCache($imagePaths);
    }

    /**
     * @param string $imagePath
     * @param string $bucketName
     * @return array
     * @throws Exception
     * $imagePaths pode ser o nome completo do arquivo ou por prefix
     * Ex: /caminho_do_arquivo/nome_do_arquivo_1.jpg
     */
    public static function getSingleFileMetadata(string $imagePath, string $bucketName): array
    {
        self::init(self::initConfig());
        self::setBucket($bucketName);
        $imagePath = self::removeBucketFromUrl($imagePath, $bucketName);

        return self::getFileMetadata($imagePath);
    }

    /**
     * @param array $imagePaths
     * @param string $bucketName
     * @return array
     * @throws Exception
     * $imagePaths pode ser o nome completo do arquivo
     * Ex: ['/caminho_do_arquivo/nome_do_arquivo_1.jpg', '/caminho_do_arquivo/nome_do_arquivo_2.jpg']
     */
    public static function getMultiplesFileMetadata(array $imagePaths,  string $bucketName): array
    {
        self::init(self::initConfig());
        self::setBucket($bucketName);
        $data = [];
        foreach ($imagePaths as $path) {
            $imagePath = self::removeBucketFromUrl($path, $bucketName);
            $result = self::getFileMetadata($imagePath);
            $data = array_merge($data, $result);
        }
        return $data;
    }

    /**
     * @param string $imagePath
     * @param string $bucketName
     * @return array
     * @throws Exception
     * $imagePath é o nome por prefix
     * Ex: /caminho_do_arquivo/nome_do_arquivo_*
     */
    public static function getFileMetadataByPrefix(string $imagePath,  string $bucketName): array
    {
        self::init(self::initConfig());
        self::setBucket($bucketName);
        return self::getFileMetadata($imagePath, 'prefix');
    }

    /**
     * @param array $file
     * @param string $bucketName
     * @return array
     * @throws Exception
     *  $file tem que ser um array com as chaves:
     *   localPath: caminho completo do arquivo local
     *   remotePath: caminho completo do arquivo no bucket
     *   metadata: array com os metadados do arquivo
     *   Ex: [
     *           'localPath' => '/caminho_do_arquivo/nome_do_arquivo_1.jpg',
     *           'remotePath' => 'caminho_no_bucket/nome_do_arquivo_1.jpg',
     *           'metadata' => [
     *               'key1' => 'value1',
     *               'key2' => 'value2'
     *      ],
     */
    public function uploadFileByPath(array $file, $bucketName): array
    {
        self::init(self::initConfig());
        self::setBucket($bucketName);
        unset($file['base64']);
        return self::uploadFileInBucket($file);
    }

    /**
     * @param array $file
     * @param string $bucketName
     * @return array
     * @throws Exception
     *   $file tem que ser um array com as chaves:
     *    localPath: caminho completo do arquivo local
     *    remotePath: caminho completo do arquivo no bucket
     *    metadata: array com os metadados do arquivo
     *    Ex: [
     *            'base64' => 'base64 do arquivo',
     *            'remotePath' => 'caminho_no_bucket/nome_do_arquivo_1.jpg',
     *            'metadata' => [
     *                'key1' => 'value1',
     *                'key2' => 'value2'
     *       ],
     */
    public function uploadFileByBase64(array $file, $bucketName): array
    {
        self::init(self::initConfig());
        self::setBucket($bucketName);
        unset($file['localPath']);
        return self::uploadFileInBucket($file);
    }

    /**
     * @param string $filePath
     * @param string $bucketName
     * @return bool
     * @throws Exception
     */
    public function deleteSingleFile(string $filePath, string $bucketName): bool
    {
        self::init(self::initConfig());
        self::setBucket($bucketName);
        return self::deleteFileInBucket($filePath, 'single');
    }

    /**
     * @param string $filePrefix
     * @param string $bucketName
     * @return bool
     * @throws Exception
     */
    public function deleteFileByPrefix(string $filePrefix, string $bucketName): bool
    {
        self::init(self::initConfig());
        self::setBucket($bucketName);
        return self::deleteFileInBucket($filePrefix, 'prefix');
    }
}