413 lines
13 KiB
PHP
413 lines
13 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use Hypervel\Http\Request;
|
|
use App\Models\FileList;
|
|
use App\Models\FileContent;
|
|
use Hypervel\Http\UploadedFile;
|
|
use Hypervel\Support\Facades\File;
|
|
use Hypervel\Support\Facades\Storage;
|
|
use Hypervel\Support\Facades\Auth;
|
|
use Hypervel\Support\Facades\DB;
|
|
use \PDO;
|
|
use Hypervel\Support\Facades\Response;
|
|
use Hypervel\Support\Carbon;
|
|
use App\Http\Controllers\Helpers\Permissions\UserPermissions;
|
|
use App\Http\Controllers\Helpers\Permissions\ProductPermissions;
|
|
use App\Enums\UserActions;
|
|
|
|
class FilesMainController
|
|
{
|
|
|
|
private static function isLikelyBinary($string, $threshold = 0.3)
|
|
{
|
|
// Null byte check: very likely binary
|
|
if (strpos($string, "\x00") !== false) {
|
|
return true;
|
|
}
|
|
|
|
// If string is empty, consider it not binary
|
|
$len = strlen($string);
|
|
if ($len === 0)
|
|
return false;
|
|
|
|
// Count non-printable characters
|
|
$nonPrintable = preg_match_all('~[^\x09\x0A\x0D\x20-\x7E]~', $string);
|
|
|
|
// If more than $threshold of the content is non-printable, likely binary
|
|
return ($nonPrintable / $len) > $threshold;
|
|
}
|
|
|
|
private static function insertFileContentPostgresPDO(array $data)
|
|
{
|
|
$pdo = DB::getPdo();
|
|
|
|
$stmt = $pdo->prepare('
|
|
INSERT INTO file_content
|
|
(hashkey, filehash, titlename, description, size_in_bytes, content, filelocation, created_by, updated_by, details, created_at, updated_at)
|
|
VALUES
|
|
(:hashkey, :filehash, :titlename, :description, :size_in_bytes, :content, :filelocation, :created_by, :updated_by, :details, :created_at, :updated_at)
|
|
');
|
|
|
|
$now = now()->toDateTimeString();
|
|
|
|
$stmt->bindParam(':hashkey', $data['hashkey']);
|
|
$stmt->bindParam(':filehash', $data['filehash']);
|
|
$stmt->bindParam(':titlename', $data['titlename']);
|
|
$stmt->bindParam(':description', $data['description']);
|
|
$stmt->bindParam(':size_in_bytes', $data['size_in_bytes']);
|
|
$stmt->bindParam(':content', $data['content'], PDO::PARAM_LOB);
|
|
$stmt->bindParam(':filelocation', $data['filelocation']);
|
|
$stmt->bindParam(':created_by', $data['created_by']);
|
|
$stmt->bindParam(':updated_by', $data['updated_by']);
|
|
$detailsJson = json_encode($data['details']);
|
|
$stmt->bindParam(':details', $detailsJson);
|
|
$stmt->bindParam(':created_at', $now);
|
|
$stmt->bindParam(':updated_at', $now);
|
|
|
|
$stmt->execute();
|
|
|
|
// Optionally, get the inserted ID and fetch the model
|
|
$id = DB::getPdo()->lastInsertId();
|
|
|
|
return FileContent::find($id);
|
|
}
|
|
|
|
private static function insertFileContentSql(array $data)
|
|
{
|
|
$now = Carbon::now();
|
|
|
|
$data['content'] = base64_encode($data['content']);
|
|
$data['details'] = json_encode($data['details']);
|
|
$data['created_at'] = $now;
|
|
$data['updated_at'] = $now;
|
|
|
|
return FileContent::create($data);
|
|
}
|
|
|
|
|
|
private static function insertFileContent(array $data)
|
|
{
|
|
$driver = DB::connection()->getDriverName();
|
|
|
|
if ($driver === 'pgsql') {
|
|
return self::insertFileContentPostgresPDO($data);
|
|
}
|
|
|
|
if ($driver === 'mysql') {
|
|
return self::insertFileContentSql($data);
|
|
}
|
|
|
|
throw new \RuntimeException("Unsupported database driver: {$driver}");
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Upload file content and store metadata in DB.
|
|
*
|
|
* @param \Hypervel\Http\UploadedFile|string $fileData // filepath, filebinaryData, UploadedFileRequest
|
|
* @param string $title
|
|
* @param string|null $description
|
|
* @param string|null $filelocation
|
|
* @param array|null $details
|
|
*/
|
|
private static function uploadFileContent(UploadedFile|string $fileData, string $title, ?string $description = null, ?array $details = [])
|
|
{
|
|
|
|
|
|
if ($fileData instanceof UploadedFile) {
|
|
$fileHash = hash_file('sha256', $fileData->getRealPath());
|
|
$fileSize = $fileData->getSize();
|
|
$filename = $fileHash;
|
|
$fileContent = File::get($fileData->getRealPath());
|
|
$path = $fileData->storeAs('files', $filename);
|
|
} elseif (is_string($fileData) && file_exists($fileData)) {
|
|
|
|
$fileHash = hash_file('sha256', $fileData);
|
|
$fileSize = filesize($fileData);
|
|
$fileContent = file_get_contents($fileData);
|
|
$path = Storage::put("files/{$fileHash}", $fileContent);
|
|
|
|
} elseif (self::isLikelyBinary($fileData)) {
|
|
$fileHash = hash('sha256', $fileData);
|
|
$fileSize = strlen($fileData);
|
|
// $path = Storage::putFile('files', $fileData);
|
|
$fileContent = $fileData;
|
|
$path = Storage::put("files/{$fileHash}", $fileContent);
|
|
} else {
|
|
throw new \InvalidArgumentException('Invalid file data provided.');
|
|
}
|
|
|
|
$hashKey = hash('sha256', uniqid((string) now(), true));
|
|
|
|
|
|
$finfo = new \finfo(FILEINFO_MIME_TYPE);
|
|
$mimetype = $finfo->buffer($fileContent);
|
|
|
|
// $fileContent = FileContent::create([
|
|
// 'hashkey' => $hashKey,
|
|
// 'filehash' => $fileHash,
|
|
// 'titlename' => $title,
|
|
// 'description' => $description,
|
|
// 'size_in_bytes' => $fileSize,
|
|
// 'content' => $fileContent,
|
|
// 'filelocation' => $filelocation ?? $path,
|
|
// 'created_by' => Auth::id(),
|
|
// 'updated_by' => Auth::id(),
|
|
// 'details' => $details ?? [],
|
|
// ]);
|
|
|
|
$fileContentDB = FileContent::where('filehash', $fileHash)->first();
|
|
|
|
if ($fileContentDB) {
|
|
return $fileContentDB;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$fileContentDB = self::insertFileContent([
|
|
'hashkey' => $hashKey,
|
|
'filehash' => $fileHash,
|
|
'titlename' => $title,
|
|
'description' => $description,
|
|
'size_in_bytes' => $fileSize,
|
|
'content' => $fileContent,
|
|
'filelocation' => $filelocation ?? $path,
|
|
'created_by' => Auth::id(),
|
|
'updated_by' => Auth::id(),
|
|
'details' => $details ?? [],
|
|
'mimetype' => $mimetype
|
|
]);
|
|
|
|
return $fileContentDB;
|
|
}
|
|
|
|
|
|
private static function insertFileList(int $contentuid, string $title, string $filename, string $description, $categories, $details, $tags = [], $hidden = 0, ?string $file_type = null)
|
|
{
|
|
$filecontent_exists = FileContent::where('id', $contentuid)->exists();
|
|
if (!$filecontent_exists) {
|
|
throw new \Exception("File Content Does not Exist", 1);
|
|
}
|
|
|
|
$data = [
|
|
'contentuid' => $contentuid,
|
|
'hashkey' => hash('sha256', uniqid((string) now(), true)),
|
|
'title' => $title,
|
|
'filename' => $filename,
|
|
'description' => $description,
|
|
'categories' => $categories,
|
|
'details' => $details,
|
|
'tags' => $tags,
|
|
'hidden' => $hidden,
|
|
'file_type' => $file_type,
|
|
'is_public' => false,
|
|
'created_by' => Auth::id(),
|
|
'updated_by' => Auth::id(),
|
|
];
|
|
$filelist = FileList::create($data);
|
|
|
|
|
|
|
|
return $filelist;
|
|
|
|
}
|
|
|
|
public static function uploadFileList(string|UploadedFile $fileData, string $title, string $filename, ?string $description = null, ?array $details = [], $categories = null, $tags = [], $hidden = 0, ?string $file_type = null)
|
|
{
|
|
try {
|
|
$fileContent = self::uploadFileContent($fileData, $title, $description, $details);
|
|
$filecontent_id = $fileContent->id;
|
|
// print_r($fileContent);
|
|
return self::insertFileList($filecontent_id, $title, $filename, $description, $categories, $details, $tags, $hidden, $file_type);
|
|
} catch (\Throwable $th) {
|
|
return Response::json($th->getMessage(), 500);
|
|
// return Response::make('Error uploading file content: ' . $th->getMessage(), 500);
|
|
return false;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
public static function viewFilebyFileListHash(string $filelist_hash)
|
|
{
|
|
$filelist = FileList::where('hashkey', $filelist_hash)->first();
|
|
|
|
// return Response::json($filelist, 500);
|
|
|
|
if (!$filelist) {
|
|
abort(404, 'File not found');
|
|
}
|
|
|
|
$cdnUrl = trim((string) ($filelist->cdn_url ?? ''));
|
|
if ($cdnUrl !== '') {
|
|
return redirect($cdnUrl);
|
|
}
|
|
|
|
$fileContent = $filelist->fileContent;
|
|
|
|
if (!$fileContent) {
|
|
abort(404, 'File content not found');
|
|
}
|
|
|
|
$content = $fileContent->content;
|
|
|
|
$driver = DB::connection()->getDriverName();
|
|
|
|
if (is_resource($content) && $driver !== 'mysql') {
|
|
$content = stream_get_contents($content);
|
|
}
|
|
|
|
if ($driver === 'mysql') {
|
|
$content = base64_decode($content);
|
|
}
|
|
|
|
|
|
$finfo = new \finfo(FILEINFO_MIME_TYPE);
|
|
$mimeType = $finfo->buffer($content);
|
|
|
|
// Map common MIME types to extensions
|
|
$mimeMap = [
|
|
'image/jpeg' => 'jpg',
|
|
'image/png' => 'png',
|
|
'image/gif' => 'gif',
|
|
'image/webp' => 'webp',
|
|
'application/pdf' => 'pdf',
|
|
'text/plain' => 'txt',
|
|
'text/html' => 'html',
|
|
'application/zip' => 'zip',
|
|
'application/json' => 'json',
|
|
'audio/mpeg' => 'mp3',
|
|
'video/mp4' => 'mp4',
|
|
// add more as needed
|
|
];
|
|
|
|
// Pick extension from map, or fallback
|
|
$extension = $mimeMap[$mimeType] ?? pathinfo($filelist->filename, PATHINFO_EXTENSION);
|
|
|
|
// Build safe filename with extension
|
|
$filename = pathinfo($filelist->filename, PATHINFO_FILENAME) . '.' . $extension;
|
|
|
|
return Response::make($content, 200, [
|
|
'Content-Type' => $mimeType,
|
|
'Content-Disposition' => 'inline; filename="' . $filename . '"',
|
|
'Content-Length' => strlen($content),
|
|
]);
|
|
|
|
// return Response::make($content, 200, [
|
|
// 'Content-Type' => 'application/octet-stream',
|
|
// 'Content-Disposition' => 'inline; filename="' . $filelist->filename . '"',
|
|
// 'Content-Length' => strlen($content),
|
|
// ]);
|
|
}
|
|
|
|
private static function canUploadCategory(string $category): bool
|
|
{
|
|
if (!Auth::check()) {
|
|
return false;
|
|
}
|
|
|
|
if (UserPermissions::isActionPermitted(Auth::user()->acct_type, UserActions::UploadAllFiles)) {
|
|
return true;
|
|
}
|
|
|
|
if (strcasecmp($category, 'ProductMarket') === 0) {
|
|
return ProductPermissions::isActionAllowed(UserActions::CreateProductForOwnStore)
|
|
|| ProductPermissions::isActionAllowed(UserActions::AddProducttoOwnStore);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public static function UploadFilefromRequest(Request $request, string $category)
|
|
{
|
|
if (!self::canUploadCategory($category)) {
|
|
return response()->json(['error' => 'Unauthorized'], 403);
|
|
}
|
|
|
|
if (!$request->hasFile('file')) {
|
|
// $responseData =['success' => false, 'message' => 'No file uploaded'];
|
|
|
|
$responseData = false;
|
|
return response()->json(false, 400);
|
|
}
|
|
|
|
|
|
$file = $request->file('file');
|
|
$filename = $file->getClientFilename();
|
|
$result = self::uploadFileList(
|
|
$file,
|
|
'',
|
|
$filename ?? '',
|
|
'',
|
|
[],
|
|
$category,
|
|
[],
|
|
0,
|
|
null,
|
|
);
|
|
|
|
// return response()->json(['success' => false, 'error' => 'File upload failed'], 500);
|
|
|
|
// return $result;
|
|
$file_url = $result->resolvedUrl();
|
|
|
|
try {
|
|
|
|
if (is_string($result->hashkey) && !empty($result->hashkey)) {
|
|
return response()->json(['success' => true, 'hashkey' => $result->hashkey, 'message' => 'File uploaded successfully', 'url' => $file_url, 'name' => $filename], 200);
|
|
} else {
|
|
throw new \Exception("File upload failed", 1);
|
|
}
|
|
} catch (\Throwable $th) {
|
|
return response()->json(['success' => false, 'error' => 'File upload failed'], 500);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static function generateURLforFileListHash(string $filelist_hashkey)
|
|
{
|
|
$cdnUrl = FileList::where('hashkey', $filelist_hashkey)->value('cdn_url');
|
|
if (is_string($cdnUrl) && trim($cdnUrl) !== '') {
|
|
return $cdnUrl;
|
|
}
|
|
return "/RequestData/File/$filelist_hashkey";
|
|
// return route('requestdata.file.view', ['hash' => $filelist_hashkey]);
|
|
}
|
|
|
|
public static function bladePreloadFileScript(string|FileList $FileHash): null|string
|
|
{
|
|
try {
|
|
if ($FileHash instanceof FileList) {
|
|
|
|
$filecontent = $FileHash->fileContent->content;
|
|
|
|
$mimeType = $FileHash->fileContent->mimetype ?? 'application/octet-stream';
|
|
$FileHash = $FileHash->hashkey;
|
|
} else {
|
|
$FileHash = FileList::where('hashkey', $FileHash)->firstOrFail();
|
|
$filecontent = $FileHash->fileContent->content;
|
|
$mimeType = $FileHash->fileContent->mimetype;
|
|
$FileHash = $FileHash->hashkey;
|
|
}
|
|
} catch (\Throwable $th) {
|
|
return '';
|
|
}
|
|
|
|
|
|
$base64 = base64_encode($filecontent);
|
|
|
|
$htmlString = "reqcacheupdateBase64toFile('$FileHash','$base64','$mimeType')";
|
|
return $htmlString;
|
|
}
|
|
|
|
}
|