Files
api/services/nginx/app/traits/minio_t.php
T
Jeppe Bundgaard a0fd41fba1 Add image upload support, file handling improvements, and OpenAI integration
- Introduced `uploadRoute` to handle image uploads with MIME type validation and size restrictions.
- Added `upload_store` class for managing file storage and generating presigned URLs for upload/download.
- Enhanced file server to differentiate between PDFs and uploaded files, supporting dynamic content delivery.
- Integrated OpenAI module for License Plate Recognition (LPR), including API configuration and schema validation.
- Updated core structure with new interfaces (`minio_uploads_i`, `openai_i`) and classes (`openai`, `upload_store`).
- Adjusted `index.php` and file routes to support dynamic MIME checks and direct link generation.
2025-08-18 16:50:30 +02:00

258 lines
7.8 KiB
PHP

<?php
namespace traits;
use Aws\S3\S3Client;
use classes\wash_certificate_store;
trait minio_t
{
/**
* The bucket to store the files in
* @return string
*/
private string $bucket;
/**
* The S3 client to interact with the Minio server
* @return S3Client
*/
private s3Client $s3Client;
/**
* List all the files in the bucket
* @return array
*/
public function listFiles(): array
{
$objects = self::getS3Client()->listObjects([
'Bucket' => self::getBucket()
]);
// If there are no files, return an empty array
if (!isset($objects['Contents'])) {
return [];
}
return $objects['Contents'];
}
/**
* Returns the S3 client to interact with the Minio server
* @return S3Client
*/
public function getS3Client(): S3Client
{
// If the S3 client is not set, create a new one
if (!isset($this->s3Client)) {
$this->connect();
}
return $this->s3Client;
}
/**
* Connect to the Minio server
*/
private function connect(): self
{
$this->s3Client = new S3Client([
'version' => 'latest',
'region' => 'us-east-1',
'endpoint' => $this->getEndpoint(),
'use_path_style_endpoint' => true,
'credentials' => [
'key' => $this->getAccessKey(),
'secret' => $this->getSecretKey(),
],
]);
return $this;
}
/**
* Returns the endpoint of the Minio server
* @return string
*/
public function getEndpoint(): string
{
global $MINIO;
return $MINIO['endpoint'];
}
/**
* Returns the access key of the Minio server
* @return string
*/
public function getAccessKey(): string
{
global $MINIO;
return $MINIO['access_key'];
}
/**
* Returns the secret key of the Minio server
* @return string
*/
public function getSecretKey(): string
{
global $MINIO;
return $MINIO['secret_key'];
}
/**
* Returns the bucket to store the files in
* @return string
*/
public function getBucket(): string
{
return $this->bucket;
}
/**
* Sets the bucket to store the files in
* @param string $bucket
* @return wash_certificate_store|minio_t
*/
public function setBucket(string $bucket): self
{
$this->bucket = $bucket;
return $this;
}
/**
* Create a new object in the bucket
* @param string $key The key of the object (file)
* @param string $body The content of the object (file)
* @return bool
*/
public function createObject(string $key, string $body): bool
{
$result = self::getS3Client()->putObject([
'Bucket' => self::getBucket(),
'Key' => $key,
'Body' => $body
]);
return $result['@metadata']['statusCode'] == 200;
}
/**
* Get the URL of the object in the bucket
* @param string $key The key of the object (file)
* @return string
*/
public function getObjectUrl(string $key): string
{
return self::getS3Client()->getObjectUrl(self::getBucket(), $key);
}
/**
* Generate a presigned URL for the object in the bucket (valid for 20 minutes)
* @param string $key The key of the object (file)
* @param int|null $expires The expiration time in seconds (default is not set, which means 20 minutes)
* @param bool $isUpload Whether the URL is for uploading (true) or downloading (false)
* @note If $expires is null, it defaults to 1200 seconds (20 minutes).
* @note If $isUpload is true, the URL will be for uploading the object.
* @note If $isUpload is false, the URL will be for downloading the object
* @return string
*/
public function getPresignedUrl(string $key, ?int $expires = null, bool $isUpload = false): string
{
$commandAction = $isUpload ? 'PutObject' : 'GetObject';
$command = self::getS3Client()->getCommand($commandAction, [
'Bucket' => self::getBucket(),
'Key' => $key,
]);
$duration_seconds = $expires ?? 1200; // Default to 20 minutes if not specified
$duration_attribute = '+' . ($duration_seconds / 60) . ' minutes';
return (string)self::getS3Client()->createPresignedRequest($command, $duration_attribute)->getUri();
}
/**
* Upload a file to the bucket
* @param string $key The key of the object (file)
* @param string $file The path to the file to upload
* @return bool
*/
public function uploadFile(string $key, string $file): bool
{
$result = self::getS3Client()->putObject([
'Bucket' => self::getBucket(),
'Key' => $key,
'SourceFile' => $file
]);
return $result['@metadata']['statusCode'] == 200;
}
/**
* Check if the object exists in the bucket
* @param string $key The key of the object (file or folder)
* @return bool
*/
public function doesObjectExist(string $key): bool
{
return self::getS3Client()->doesObjectExist(self::getBucket(), $key);
}
/**
* Store temp image file from base64 string
* @param string $base64 The base64 encoded image string (E.g. data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAA)
* @return string|bool The path to the temporary file if successful, false otherwise
*/
public function storeTempImageFromBase64(string $base64): string|bool
{
// Check if the base64 string is valid
if (empty($base64) || !preg_match('/^data:image\/(\w+);base64,/', $base64)) {
return false; // Invalid base64 string
}
// Extract the base64 data from the string
$imageData = preg_replace('/^data:image\/\w+;base64,/', '', $base64);
// Decode the base64 data
$imageData = base64_decode($imageData);
if ($imageData === false) {
return false; // Failed to decode base64 data
}
// Temporary file path
$tempFileName = uniqid('temp_image_', true) . '.' . $this->getImageExtension($base64);
$tempFilePath = '/tmp/' . $tempFileName;
// Create a temporary file
$tempFile = fopen($tempFilePath, 'wb');
if ($tempFile === false) {
return false; // Failed to create temp file
}
// Write the image data to the temporary file
if (fwrite($tempFile, $imageData) === false) {
fclose($tempFile);
return false; // Failed to write to temp file
}
fclose($tempFile);
// Upload the temporary file to the bucket
$result = self::uploadFile($tempFileName, $tempFilePath);
// Clean up the temporary file
unlink($tempFilePath);
return $result ? $tempFileName : false;
}
/**
* Get the image extension from the base64 string
* @param string $base64 The base64 encoded image string
* @return string The image extension (e.g., 'jpg', 'png')
*/
private function getImageExtension(string $base64): string
{
// Check if the base64 string contains a data URL prefix
if (preg_match('/^data:image\/(\w+);base64,/', $base64, $matches)) {
// Return the image extension
switch ($matches[1]) {
case 'png':
return 'png';
case 'gif':
return 'gif';
case 'webp':
return 'webp';
case 'bmp':
return 'bmp';
default:
return 'jpg'; // Default to jpg if unknown
}
}
// If no match, return a default extension (e.g., 'jpg')
return 'jpg';
}
}