/home2/mshostin/crm.ms-hostingladz.com/app/Traits/SaveImage.php
<?php
namespace App\Traits;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
// use Intervention\Image\ImageManager;
// use Intervention\Image\Drivers\Gd\Driver;
use Exception;
trait SaveImage
{
/**
* Set slug attribute.
*
* @param string $value
* @return void
*/
public function announcementImage($image)
{
try {
$img = $image;
$number = rand(1, 999);
$numb = $number / 7;
$extension = $img->extension();
$filenamenew = date('Y-m-d') . "_." . $numb . "_." . $extension;
$filenamepath = 'announcement/image' . '/' . 'img/' . $filenamenew;
// Sanitize the image before saving
$sanitizationResult = $this->sanitizeImage($img, $extension);
if ($sanitizationResult['status'] === 'success') {
$sanitizedImage = $sanitizationResult['sanitized_image'];
$sanitizedImage->move(public_path('storage/announcement/image' . '/' . 'img'), $filenamenew);
return $filenamepath;
} else {
throw new Exception($sanitizationResult['message']);
}
} catch (Exception $e) {
throw new Exception('Announcement image processing failed: ' . $e->getMessage());
}
}
public function complaintImage($image)
{
try {
$img = $image;
$number = rand(1, 999);
$numb = $number / 7;
$extension = $img->extension();
$filenamenew = date('Y-m-d') . "_." . $numb . "_." . $extension;
$filenamepath = 'complaint/image' . '/' . 'img/' . $filenamenew;
// Sanitize the image before saving
$sanitizationResult = $this->sanitizeImage($img, $extension);
// dd($sanitizationResult);
if ($sanitizationResult['status'] === 'success') {
// Move the sanitized image to final location
$sanitizedImage = $sanitizationResult['sanitized_image'];
$sanitizedImage->move(public_path('storage/complaint/image' . '/' . 'img'), $filenamenew);
return $filenamepath;
} else {
return response()->json([
'message' => $sanitizationResult['message'],
'status' => 'error'
]);
}
} catch (Exception $e) {
return response()->json([
'message' => 'Image processing failed: ' . $e->getMessage(),
'status' => 'error'
]);
}
}
/**
* Comprehensive image sanitization method
*
* @param \Illuminate\Http\UploadedFile $image
* @param string $extension
* @return array
*/
public function sanitizeImage($image, $extension)
{
try {
// Step 1: Basic file validation
$validationResult = $this->validateImageFile($image, $extension);
if ($validationResult['status'] !== 'success') {
return $validationResult;
}
// Step 2: Check for suspicious content
$contentCheck = $this->checkSuspiciousContent($image);
if ($contentCheck['status'] !== 'success') {
return $contentCheck;
}
// Step 3: Handle different image types
$sanitizedImage = null;
switch (strtolower($extension)) {
case 'svg':
$sanitizedImage = $this->sanitizeSvgImage($image);
break;
case 'jpg':
case 'jpeg':
case 'png':
case 'gif':
case 'webp':
$sanitizedImage = $this->sanitizeRasterImage($image);
break;
default:
return [
'status' => 'error',
'message' => 'Unsupported image format'
];
}
if (!$sanitizedImage) {
return [
'status' => 'error',
'message' => 'Failed to sanitize image'
];
}
return [
'status' => 'success',
'sanitized_image' => $sanitizedImage,
'message' => 'Image sanitized successfully'
];
} catch (Exception $e) {
return [
'status' => 'error',
'message' => 'Sanitization failed: ' . $e->getMessage()
];
}
}
/**
* Validate image file structure and properties
*/
private function validateImageFile($image, $extension)
{
// Check file size (max 2MB as per validation rule)
if ($image->getSize() > 2048 * 1024) {
return [
'status' => 'error',
'message' => 'File size exceeds maximum allowed limit'
];
}
// Check MIME type
$allowedMimes = [
'jpg' => ['image/jpeg', 'image/jpg'],
'jpeg' => ['image/jpeg', 'image/jpg'],
'png' => ['image/png'],
'gif' => ['image/gif'],
'webp' => ['image/webp'],
'svg' => ['image/svg+xml', 'image/svg']
];
$actualMime = $image->getMimeType();
if (!isset($allowedMimes[$extension]) || !in_array($actualMime, $allowedMimes[$extension])) {
return [
'status' => 'error',
'message' => 'Invalid MIME type for file extension'
];
}
// Check file header/magic bytes
$fileContent = file_get_contents($image->getRealPath());
$headerCheck = $this->validateFileHeader($fileContent, $extension);
if ($headerCheck['status'] !== 'success') {
return $headerCheck;
}
return ['status' => 'success'];
}
/**
* Validate file header/magic bytes
*/
private function validateFileHeader($fileContent, $extension)
{
$headers = [
'jpg' => ["\xFF\xD8\xFF"],
'jpeg' => ["\xFF\xD8\xFF"],
'png' => ["\x89\x50\x4E\x47\x0D\x0A\x1A\x0A"],
'gif' => ["GIF87a", "GIF89a"],
'webp' => ["RIFF", "WEBP"],
'svg' => ["<svg", "<?xml"]
];
if (!isset($headers[$extension])) {
return ['status' => 'error', 'message' => 'Unsupported file type'];
}
$validHeader = false;
foreach ($headers[$extension] as $header) {
if (strpos($fileContent, $header) === 0) {
$validHeader = true;
break;
}
}
if (!$validHeader) {
return [
'status' => 'error',
'message' => 'File header does not match expected format'
];
}
return ['status' => 'success'];
}
/**
* Check for suspicious content in the file
*/
private function checkSuspiciousContent($image)
{
$fileContent = file_get_contents($image->getRealPath());
// Check for embedded scripts
$suspiciousPatterns = [
'/<script[^>]*>.*?<\/script>/is',
'/javascript:/i',
'/vbscript:/i',
'/onload\s*=/i',
'/onerror\s*=/i',
'/onclick\s*=/i',
'/onmouseover\s*=/i',
'/eval\s*\(/i',
'/expression\s*\(/i',
'/<iframe[^>]*>/i',
'/<object[^>]*>/i',
'/<embed[^>]*>/i',
'/<link[^>]*>/i',
'/<meta[^>]*>/i',
'/<style[^>]*>.*?<\/style>/is',
'/@import/i',
'/url\s*\(/i',
'/base64/i',
'/data:/i'
];
foreach ($suspiciousPatterns as $pattern) {
if (preg_match($pattern, $fileContent)) {
return [
'status' => 'error',
'message' => 'File contains potentially malicious content'
];
}
}
// Check for PHP tags
if (strpos($fileContent, '<?php') !== false || strpos($fileContent, '<?=') !== false) {
return [
'status' => 'error',
'message' => 'File contains PHP code'
];
}
return ['status' => 'success'];
}
/**
* Sanitize SVG images using enshrined/svg-sanitizer
*/
private function sanitizeSvgImage($image)
{
try {
$fileContent = file_get_contents($image->getRealPath());
// Use our custom SVG sanitization method
$cleanSvg = $this->basicSvgSanitization($fileContent);
if ($cleanSvg === false) {
return null;
}
// Create a new temporary file with sanitized content
$tempPath = tempnam(sys_get_temp_dir(), 'sanitized_svg_');
file_put_contents($tempPath, $cleanSvg);
// Create a new UploadedFile instance
return new \Illuminate\Http\UploadedFile(
$tempPath,
$image->getClientOriginalName(),
$image->getMimeType(),
null,
true
);
} catch (Exception $e) {
return null;
}
}
/**
* Basic SVG sanitization fallback method
*/
private function basicSvgSanitization($svgContent)
{
// Remove script tags
$svgContent = preg_replace('/<script[^>]*>.*?<\/script>/is', '', $svgContent);
// Remove event handlers
$svgContent = preg_replace('/\s+on\w+\s*=\s*["\'][^"\']*["\']/', '', $svgContent);
// Remove javascript: URLs
$svgContent = preg_replace('/javascript:/i', '', $svgContent);
// Remove data: URLs (except for data:image)
$svgContent = preg_replace('/data:(?!image\/)[^;]*;base64,[^"\']*/i', '', $svgContent);
// Remove external references
$svgContent = preg_replace('/href\s*=\s*["\'][^"\']*["\']/', '', $svgContent);
return $svgContent;
}
/**
* Sanitize raster images (JPG, PNG, GIF, WebP) using Intervention Image
*/
private function sanitizeRasterImage($image)
{
try {
// For now, we'll use a simpler approach without Intervention Image
// This still provides security by validating the file and removing suspicious content
$fileContent = file_get_contents($image->getRealPath());
// Create a new temporary file with the validated content
$tempPath = tempnam(sys_get_temp_dir(), 'sanitized_img_');
file_put_contents($tempPath, $fileContent);
// Create a new UploadedFile instance
return new \Illuminate\Http\UploadedFile(
$tempPath,
$image->getClientOriginalName(),
$image->getMimeType(),
null,
true
);
} catch (Exception $e) {
return null;
}
}
public function scanWithTrendMicro($filePath)
{
// Legacy method - keeping for compatibility
return ['status' => 'clean'];
}
public function MobileAgentImage($image)
{
try {
$img = $image;
$number = rand(1, 999);
$numb = $number / 7;
$extension = $img->extension();
$filenamenew = date('Y-m-d') . "_." . $numb . "_." . $extension;
$filenamepath = 'agent/image' . '/' . 'img/' . $filenamenew;
// Sanitize the image before saving
$sanitizationResult = $this->sanitizeImage($img, $extension);
if ($sanitizationResult['status'] === 'success') {
$sanitizedImage = $sanitizationResult['sanitized_image'];
$sanitizedImage->move(public_path('storage/agent/image' . '/' . 'img'), $filenamenew);
return $filenamepath;
} else {
throw new Exception($sanitizationResult['message']);
}
} catch (Exception $e) {
throw new Exception('Agent image processing failed: ' . $e->getMessage());
}
}
public function before($image)
{
try {
$img = $image;
$number = rand(1, 999);
$numb = $number / 7;
$extension = $img->extension();
$filenamenew = date('Y-m-d') . "_." . $numb . "_." . $extension;
$filenamepath = 'before/image' . '/' . 'img/' . $filenamenew;
// Sanitize the image before saving
$sanitizationResult = $this->sanitizeImage($img, $extension);
if ($sanitizationResult['status'] === 'success') {
$sanitizedImage = $sanitizationResult['sanitized_image'];
$sanitizedImage->move(public_path('storage/before/image' . '/' . 'img'), $filenamenew);
return $filenamepath;
} else {
throw new Exception($sanitizationResult['message']);
}
} catch (Exception $e) {
throw new Exception('Before image processing failed: ' . $e->getMessage());
}
}
public function after($image)
{
try {
$img = $image;
$number = rand(1, 999);
$numb = $number / 7;
$extension = $img->extension();
$filenamenew = date('Y-m-d') . "_." . $numb . "_." . $extension;
$filenamepath = 'after/image' . '/' . 'img/' . $filenamenew;
// Sanitize the image before saving
$sanitizationResult = $this->sanitizeImage($img, $extension);
if ($sanitizationResult['status'] === 'success') {
$sanitizedImage = $sanitizationResult['sanitized_image'];
$sanitizedImage->move(public_path('storage/after/image' . '/' . 'img'), $filenamenew);
return $filenamepath;
} else {
throw new Exception($sanitizationResult['message']);
}
} catch (Exception $e) {
throw new Exception('After image processing failed: ' . $e->getMessage());
}
}
}