diff --git a/classes/router.php b/classes/router.php index d74617e7..e3459e45 100644 --- a/classes/router.php +++ b/classes/router.php @@ -8,10 +8,11 @@ class router private string $method; private array $routes; private array $routeClasses; // Contains the classes that have the route_t trait + public function __construct() { - $this->url = $_SERVER['REQUEST_URI']; - $this->method = $_SERVER['REQUEST_METHOD']; + $this->url = $_SERVER['REQUEST_URI'] ?? ($argv[1] ?? '/'); // Get the URL (Or the first argument if it's a CLI request) + $this->method = $_SERVER['REQUEST_METHOD'] ?? ($argv[2] ?? 'GET'); // Get the method (Or the second argument if it's a CLI request) $this->routes = []; $this->routeClasses = []; } @@ -21,22 +22,11 @@ class router $this->routes[] = ['route' => $route, 'method' => $method, 'function' => $function]; } - public function run(): void - { - foreach ($this->routeClasses as $class) { - $route = new $class(); - // Add the routes to the router - $route->run(); - } - - $this->routeRequest(); - } - public function auto_load_routes(string $path): void { global $response; $files = scandir($path); - foreach ($files as $file) { + foreach ( $files as $file ) { if ($file == '.' || $file == '..') { continue; } @@ -45,7 +35,7 @@ class router // Get all the classes in the files with the route_t trait $classes = get_declared_classes(); - foreach ($classes as $class) { + foreach ( $classes as $class ) { if (in_array('traits\route_t', class_uses($class))) { $this->routeClasses[] = $class; } @@ -59,21 +49,22 @@ class router } } - public function ERROR_HANDLER($callback): void + public function run(): void { - try { - $callback(); - } catch (\Exception $e) { - global $response; - $response->internal_server_error($e->getMessage()); + foreach ( $this->routeClasses as $class ) { + $route = new $class(); + // Add the routes to the router + $route->run(); } + + $this->routeRequest(); } private function routeRequest(): void { global $response; $matching_route_found = false; - foreach ($this->routes as $route) { + foreach ( $this->routes as $route ) { if ($this->doesRouteMatchCurrent($route['route']) && $route['method'] == $this->method) { $route['function'](); $matching_route_found = true; @@ -105,4 +96,14 @@ class router // None of the matches were found return false; } + + public function ERROR_HANDLER($callback): void + { + try { + $callback(); + } catch (\Exception $e) { + global $response; + $response->internal_server_error($e->getMessage()); + } + } } \ No newline at end of file diff --git a/classes/wash_certificate_store.php b/classes/wash_certificate_store.php new file mode 100644 index 00000000..01aee625 --- /dev/null +++ b/classes/wash_certificate_store.php @@ -0,0 +1,30 @@ +listObjects([ + 'Bucket' => self::getBucket(), + 'Prefix' => $certificate_id + ]); + return count($objects['Contents'] ?? []) > 0; + } + +} \ No newline at end of file diff --git a/cli.php b/cli.php new file mode 100644 index 00000000..9854b553 --- /dev/null +++ b/cli.php @@ -0,0 +1,23 @@ + '', // IP address of the database server e.g. 127.0.0.1 'user' => '', // Username of the database server e.g. root @@ -22,4 +22,9 @@ if ($DEBUG && !$USE_PROD_ECONOMIC_IN_DEBUG) { ]; } $WORDPRESS_STATIC_TOKEN = ''; // Static token used to authenticate the WordPress plugin -$EMAIL_WASH_CERTIFICATE_TOKEN = ''; // Token used to authenticate the wash certificate generator \ No newline at end of file +$EMAIL_WASH_CERTIFICATE_TOKEN = ''; // Token used to authenticate the wash certificate generator +$MINIO = [ + 'endpoint' => '', // Minio endpoint e.g. http://0.0.0.0:9000 + 'access_key' => '', // Minio access + 'secret_key' => '' // Minio secret key +]; \ No newline at end of file diff --git a/index.php b/index.php index 51895b55..ad7c76be 100644 --- a/index.php +++ b/index.php @@ -19,11 +19,11 @@ header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS"); /** Autoload */ require_once 'vendor/autoload.php'; /** Load all Interfaces */ -foreach (glob(WD . '/interfaces/*.php') as $interface) { +foreach ( glob(WD . '/interfaces/*.php') as $interface ) { require_once $interface; } /** Load all Traits */ -foreach (glob(WD . '/traits/*.php') as $trait) { +foreach ( glob(WD . '/traits/*.php') as $trait ) { require_once $trait; } @@ -36,6 +36,7 @@ require_once 'classes/db.php'; require_once 'classes/response.php'; require_once 'classes/request.php'; require_once 'classes/ratelimit.php'; +require_once 'classes/wash_certificate_store.php'; /** * Modules @@ -47,9 +48,9 @@ require_once 'modules/economic/customers/economic_customer_mo.php'; require_once 'modules/economic/invoices/draft/economicInvoicesDrafts.php'; require_once 'modules/economic/invoices/draft/economic_invoice_draft_mo.php'; -use classes\response; -use classes\request; use classes\db; +use classes\request; +use classes\response; use classes\router; // Start the session @@ -65,17 +66,17 @@ try { $response->error($e->getMessage(), 500); } // Load all the traits -foreach (glob(WD . '/traits/*.php') as $trait) { +foreach ( glob(WD . '/traits/*.php') as $trait ) { require_once $trait; } // Load all the routes -foreach (glob(WD . '/routes/*.php') as $route) { +foreach ( glob(WD . '/routes/*.php') as $route ) { require_once $route; } /** Load all Objects */ -foreach (glob(WD . '/objects/*.php') as $object) { +foreach ( glob(WD . '/objects/*.php') as $object ) { try { require_once $object; } catch (Exception $e) { @@ -83,6 +84,12 @@ foreach (glob(WD . '/objects/*.php') as $object) { } } +// If the program was called from the command line, run the cli script +if (php_sapi_name() === 'cli') { + require_once 'cli.php'; + exit; +} + // Autoload all the routes $router->auto_load_routes(WD . '/routes'); diff --git a/interfaces/minio_wash_certificates_i.php b/interfaces/minio_wash_certificates_i.php new file mode 100644 index 00000000..e985ad9b --- /dev/null +++ b/interfaces/minio_wash_certificates_i.php @@ -0,0 +1,13 @@ +washCertificateExists("wash_certificate_" . $_GET['bookingId'] . ".pdf")) { // Return the certificate url - echo $generatedCertificatePath; + echo $wash_certificate_store->getPresignedUrl("wash_certificate_" . $_GET['bookingId'] . ".pdf"); // Exit the script exit; } @@ -74,12 +80,21 @@ if (file_exists("output/certificates/wash_certificate_" . $_GET['bookingId'] . " // Usage example $template = "templates/template2024julv3.xlsx"; $generator = new WashCertificateGenerator($template, $_GET['department']); -$generator->generateCertificate("output/certificates/wash_certificate_" . $_GET['bookingId'] . ".pdf", $_GET['sealOrPlumber'], $_GET['regNumber'], $_GET['regNumberTrailer'], $_GET['performedBy']); +$generator->generateCertificate(dirname(__FILE__) . "/output/certificates/wash_certificate_" . $_GET['bookingId'] . ".pdf", $_GET['sealOrPlumber'], $_GET['regNumber'], $_GET['regNumberTrailer'], $_GET['performedBy']); + +// Determine the generated certificate name +$generatedCertificateName = "wash_certificate_" . $_GET['bookingId'] . ".pdf"; // Return the generated certificate path $generatedCertificatePath = "output/certificates/wash_certificate_" . $_GET['bookingId'] . ".pdf"; -// Return the generated certificate path -echo $generatedCertificatePath; +// Upload the certificate to the bucket +$wash_certificate_store->uploadFile($generatedCertificateName, dirname(__FILE__) . '/' . $generatedCertificatePath); + +// Delete the local copy of the certificate +unlink(dirname(__FILE__) . '/' . $generatedCertificatePath); + +// Return the generated certificate object URL +$wash_certificate_store->getObjectUrl($generatedCertificateName); // Exit the script exit; \ No newline at end of file diff --git a/tests/minio/minioTest.php b/tests/minio/minioTest.php new file mode 100644 index 00000000..50b0bd15 --- /dev/null +++ b/tests/minio/minioTest.php @@ -0,0 +1,79 @@ +listFiles(); +// Check if the request was successful +if (count($wash_certificates) > 0) { + // Return the count of wash certificates + echo "\nWash certificates found: " . count($wash_certificates); +} else { + // Show warning message + warn('No wash certificates found'); +} + +// Create a new wash certificate +$wash_certificate = $wash_certificate_store->createObject('test.txt', 'Hello, World!'); +// Check if the request was successful +if ($wash_certificate) { + // Show success message + echo "\nWash certificate created successfully"; +} else { + // Show error message + warn('Failed to create wash certificate'); +} + +// Check if a wash certificate exists +$wash_certificate_exists = $wash_certificate_store->washCertificateExists('test.txt'); +// Check if the request was successful +if ($wash_certificate_exists) { + // Show success message + echo "\nWash certificate exists"; +} else { + // Show warning message + warn('Wash certificate does not exist'); +} + +// Create a download link for the wash certificate +$wash_certificate_download_link = $wash_certificate_store->getPresignedUrl('test.txt'); +// Check if the request was successful +if ($wash_certificate_download_link) { + // Show the download link + echo "\nDownload link: $wash_certificate_download_link"; +} else { + // Show error message + warn('Failed to create download link'); +} + +// Upload a wash certificate from a file +$wash_certificate_upload = $wash_certificate_store->uploadFile('test.txt', 'tests/minio/testUpload.txt'); +// Check if the request was successful +if ($wash_certificate_upload) { + // Show success message + echo "\nWash certificate uploaded successfully from file"; +} else { + // Show error message + warn('Failed to upload wash certificate from file'); +} \ No newline at end of file diff --git a/tests/minio/testUpload.txt b/tests/minio/testUpload.txt new file mode 100644 index 00000000..af27ff49 --- /dev/null +++ b/tests/minio/testUpload.txt @@ -0,0 +1 @@ +This is a test file. \ No newline at end of file diff --git a/traits/minio_t.php b/traits/minio_t.php new file mode 100644 index 00000000..9b6a8984 --- /dev/null +++ b/traits/minio_t.php @@ -0,0 +1,173 @@ +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) + * @return string + */ + public function getPresignedUrl(string $key): string + { + $command = self::getS3Client()->getCommand('GetObject', [ + 'Bucket' => self::getBucket(), + 'Key' => $key + ]); + return (string)self::getS3Client()->createPresignedRequest($command, '+20 minutes')->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; + } +} \ No newline at end of file