Secure
Img.php
← Back to Folder Raw Code
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
<?php
class Img {
    private $webPath;
    private $cache;
    private $allowedImageExtensions = [
        'jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'avif', 'heic', 
        'tiff', 'bmp', 'ico', 'psd', 'cur', 'jfif',
        'cr2', 'cr3', 'nef', 'nrw', 'arw', 'raf', 'rw2', 'orf', 'pef', 'dng', '3fr', 'x3f',
        'ai', 'fig', 'sketch', 'xcf'
    ];
    public function __construct($webPath) {
        $this->webPath = $webPath;
        $this->cache = initializeCache();
    }
    public function isImageViewable($extension) {
        global $config;
        if (empty($extension) || trim($extension) === '') {
            return false;
        }
        $extension = strtolower($extension);
        if (!in_array($extension, $this->allowedImageExtensions)) {
            return false;
        }
        $settingKey = getExtensionSetting($extension, 'viewing');
        if ($settingKey !== null) {
            return isset($config['viewable_files'][$settingKey]) ? 
                   $config['viewable_files'][$settingKey] : false;
        }
        return false;
    }
    public function renderImageViewer($fullPath, $filename, $extension, $currentPath, $viewMode = 'default') {
        global $router, $config;
        $pathParts = explode('/', trim($currentPath, '/'));
        $lastPart = end($pathParts);
        if ($lastPart === $filename) {
            array_pop($pathParts);
            $currentPath = implode('/', $pathParts);
        }
        $relativePath = $currentPath ? $currentPath . '/' . $filename : $filename;
        if ($this->cache->hasValidFile($fullPath, 'imageview_' . $viewMode)) {
            echo $this->cache->getFile($fullPath, 'imageview_' . $viewMode);
            exit;
        }
        ob_start();
        $this->serveImageView($fullPath, $filename, $extension, $currentPath, $viewMode);
        $output = ob_get_clean();
        $this->cache->setFile($fullPath, $output, 'imageview_' . $viewMode);
        echo $output;
        exit;
    }
    private function serveImageView($fullPath, $filename, $extension, $currentPath, $viewMode = 'default') {
        global $router, $config;
        $disableRawImageViewing = isset($config['main']['disable_raw_image_conversion']) ? 
                                $config['main']['disable_raw_image_conversion'] : true;
        $maxResolution = isset($config['main']['max_image_resolution']) ? 
                        $config['main']['max_image_resolution'] : '1920x1080';
        list($maxWidth, $maxHeight) = explode('x', $maxResolution);
        $maxWidth = (int)$maxWidth;
        $maxHeight = (int)$maxHeight;
        $fileSize = filesize($fullPath);
        $fileSizeFormatted = $this->formatBytes($fileSize);
        $fileModified = date('Y-m-d H:i:s', filemtime($fullPath));
        $dimensions = $this->getImageDimensions($fullPath, $extension);
        $originalDimensionText = $dimensions ? $dimensions['width'] . ' × ' . $dimensions['height'] . ' px' : 'Unknown';
        $exceedsResolution = false;
        if ($dimensions && ($dimensions['width'] > $maxWidth || $dimensions['height'] > $maxHeight)) {
            $exceedsResolution = true;
        }
        $isTrueScale = ($viewMode === 'truescale');
        $isSvgTrueScale = ($extension === 'svg' && $isTrueScale);
        $needsSpecialHandling = in_array($extension, [
            'tiff', 'psd', 'heic',
            'cr2', 'cr3', 'nef', 'nrw', 'arw', 'raf', 'rw2', 'orf', 'pef', 'dng', '3fr', 'x3f',
            'ai', 'fig', 'sketch', 'xcf'
        ]);
        $downloadUrl = $router->generateFileURL($currentPath, $filename, 'download');
        $viewUrl = $router->generateFileURL($currentPath, $filename, 'view', 'default');
        $originalRawUrl = $router->generateFileURL($currentPath, $filename, 'view', 'raw');
        $trueScaleUrl = $viewUrl . '&scale=true';
        $imageDisplayUrl = $originalRawUrl;
        $currentFullUrl = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
        $backUrl = preg_replace('/\/[^\/]+\/\?.*$/', '/', $currentFullUrl);
        if (!preg_match('/\?/', $currentFullUrl)) {
            $backUrl = preg_replace('/\/[^\/]+\/$/', '/', $currentFullUrl);
        }
        $securityStatus = getSecurityStatus();
        $lockIcon = $securityStatus['secure'] 
            ? $this->webPath . '/.indexer_files/icons/app/green.png'
            : $this->webPath . '/.indexer_files/icons/app/red.png';
        $convertedDimensions = null;
        $dimensionText = $originalDimensionText;
        if ($disableRawImageViewing && $needsSpecialHandling) {
            $showError = true;
            $errorMessage = "Raw image viewing is disabled on this server.<br>Please download the file to view it.";
        } else {
            $showError = false;
            $errorMessage = '';
            if (($exceedsResolution && !$isTrueScale) || $needsSpecialHandling) {
                $conversionResult = $this->attemptImageConversion($fullPath, $extension, $maxWidth, $maxHeight);
                if ($conversionResult) {
                    $imageDisplayUrl = $conversionResult['data'];
                    $convertedDimensions = $conversionResult['dimensions'];
                    if ($convertedDimensions) {
                        $dimensionText = $originalDimensionText . ' (converted: ' . 
                                    $convertedDimensions['width'] . ' × ' . 
                                    $convertedDimensions['height'] . ' px)';
                    }
                } elseif ($needsSpecialHandling) {
                    $showError = true;
                    $errorMessage = "This image format (" . strtoupper($extension) . ") requires special server extensions to display.<br>Please download the file or view raw to see the image.";
                }
            }
        }
        ?>
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <meta name="application-name" content="5q12's Indexer">
            <meta name="apple-mobile-web-app-capable" content="yes">
            <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
            <meta name="apple-mobile-web-app-title" content="Indexer">
            <meta name="mobile-web-app-capable" content="yes">
            <meta name="theme-color" content="#2a2a2a">
            <link rel="manifest" href="<?php echo $this->webPath; ?>/.indexer_files/local_api/manifest.json">
            <title><?php echo $filename; ?></title>
            <link rel="icon" type="image/x-icon" href="<?php echo $this->webPath; ?>/.indexer_files/favicon/icon.ico">
            <link rel="icon" type="image/png" sizes="16x16" href="<?php echo $this->webPath; ?>/.indexer_files/favicon/16x16.png">
            <link rel="icon" type="image/png" sizes="32x32" href="<?php echo $this->webPath; ?>/.indexer_files/favicon/32x32.png">
            <link rel="icon" type="image/png" sizes="48x48" href="<?php echo $this->webPath; ?>/.indexer_files/favicon/48x48.png">
            <link rel="icon" type="image/png" sizes="96x96" href="<?php echo $this->webPath; ?>/.indexer_files/favicon/96x96.png">
            <link rel="icon" type="image/png" sizes="144x144" href="<?php echo $this->webPath; ?>/.indexer_files/favicon/144x144.png">
            <link rel="icon" type="image/png" sizes="192x192" href="<?php echo $this->webPath; ?>/.indexer_files/favicon/192x192.png">
            <link rel="apple-touch-icon" sizes="180x180" href="<?php echo $this->webPath; ?>/.indexer_files/favicon/180x180.png">
            <link rel="stylesheet" href="<?php echo $this->webPath; ?>/.indexer_files/local_api/style/base-2.0.0-r0.min.css">
            <link rel="stylesheet" href="<?php echo $this->webPath; ?>/.indexer_files/local_api/style/img-2.0.0-r0.min.css">
        </head>
        <body>
            <div class="security-bar">
                <span class="security-lock" data-tooltip="<?php echo $securityStatus['secure'] ? 'Connection is secure (HTTPS)' : 'Connection is not secure - Consider using HTTPS'; ?>">
                    <img src="<?php echo htmlspecialchars($lockIcon); ?>" alt="<?php echo $securityStatus['secure'] ? 'Secure' : 'Not Secure'; ?>">
                </span>
                <div class="security-bar-filename"><?php echo htmlspecialchars($filename); ?></div>
                <div class="security-bar-buttons">
                    <a href="<?php echo htmlspecialchars($originalRawUrl); ?>" class="security-bar-btn">Raw</a>
                    <a href="#" class="security-bar-btn active">View</a>
                </div>
            </div>
            <div class="image-container">
                <div class="image-wrapper <?php echo ($isTrueScale && !$isSvgTrueScale) ? 'truescale' : 'fitted'; ?>">
                    <?php if ($showError): ?>
                        <div class="error-message">
                            <?php echo $errorMessage; ?>
                        </div>
                    <?php elseif ($extension === 'svg'): ?>
                        <object data="<?php echo htmlspecialchars($rawUrl); ?>" type="image/svg+xml">
                            <img src="<?php echo htmlspecialchars($imageDisplayUrl); ?>" alt="<?php echo htmlspecialchars($filename); ?>">
                        </object>
                    <?php else: ?>
                        <img src="<?php echo htmlspecialchars($imageDisplayUrl); ?>" alt="<?php echo htmlspecialchars($filename); ?>">
                    <?php endif; ?>
                </div>
            </div>
            <div class="image-info">
                <div class="info-grid">
                    <div class="info-label">Filename:</div>
                    <div class="info-value"><?php echo htmlspecialchars($filename); ?></div>
                    <div class="info-label">Type:</div>
                    <div class="info-value"><?php echo strtoupper(htmlspecialchars($extension)); ?> Image</div>
                    <div class="info-label">Dimensions:</div>
                    <div class="info-value"><?php echo htmlspecialchars($dimensionText); ?></div>
                    <div class="info-label">File Size:</div>
                    <div class="info-value"><?php echo htmlspecialchars($fileSizeFormatted); ?></div>
                    <div class="info-label">Modified:</div>
                    <div class="info-value"><?php echo htmlspecialchars($fileModified); ?></div>
                </div>
                <div class="action-buttons">
                    <a href="<?php echo htmlspecialchars($backUrl); ?>" class="action-btn primary">← Back to Folder</a>
                    <?php if ($isTrueScale): ?>
                    <a href="<?php echo htmlspecialchars($viewUrl); ?>" class="action-btn">Fit to Screen</a>
                    <?php else: ?>
                    <a href="<?php echo htmlspecialchars($trueScaleUrl); ?>" class="action-btn">View True Scale</a>
                    <?php endif; ?>
                    <a href="<?php echo htmlspecialchars($originalRawUrl); ?>" class="action-btn" target="_blank">Open Raw</a>
                    <a href="<?php echo htmlspecialchars($downloadUrl); ?>" class="action-btn">Download</a>
                </div>
            </div>
        </body>
        </html>
        <?php
    }
    private function attemptImageConversion($fullPath, $extension, $maxWidth, $maxHeight) {
        if ($this->cache->hasValidImage($fullPath, $maxWidth, $maxHeight)) {
            $cachedData = $this->cache->getImageDataUri($fullPath, $maxWidth, $maxHeight);
            if ($cachedData) {
                return [
                    'data' => $cachedData,
                    'dimensions' => $this->getCachedImageDimensions($fullPath, $maxWidth, $maxHeight)
                ];
            }
        }
        if (extension_loaded('imagick')) {
            try {
                $imagick = new Imagick($fullPath);
                $width = $imagick->getImageWidth();
                $height = $imagick->getImageHeight();
                $newWidth = $width;
                $newHeight = $height;
                if ($width > $maxWidth || $height > $maxHeight) {
                    $ratio = min($maxWidth / $width, $maxHeight / $height);
                    $newWidth = (int)($width * $ratio);
                    $newHeight = (int)($height * $ratio);
                    $imagick->thumbnailImage($newWidth, $newHeight, true);
                }
                $imagick->setImageFormat('png');
                $imageBlob = $imagick->getImageBlob();
                $imagick->clear();
                $this->cache->setImage($fullPath, $imageBlob, $maxWidth, $maxHeight);
                return [
                    'data' => 'data:image/png;base64,' . base64_encode($imageBlob),
                    'dimensions' => [
                        'width' => $newWidth,
                        'height' => $newHeight
                    ]
                ];
            } catch (Exception $e) {
            }
        }
        if (function_exists('imagecreatefromstring')) {
            $imageData = @file_get_contents($fullPath);
            if ($imageData !== false) {
                $image = @imagecreatefromstring($imageData);
                if ($image !== false) {
                    $width = imagesx($image);
                    $height = imagesy($image);
                    $newWidth = $width;
                    $newHeight = $height;
                    if ($width > $maxWidth || $height > $maxHeight) {
                        $ratio = min($maxWidth / $width, $maxHeight / $height);
                        $newWidth = (int)($width * $ratio);
                        $newHeight = (int)($height * $ratio);
                        $resized = imagecreatetruecolor($newWidth, $newHeight);
                        imagealphablending($resized, false);
                        imagesavealpha($resized, true);
                        imagecopyresampled($resized, $image, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
                        imagedestroy($image);
                        $image = $resized;
                    }
                    ob_start();
                    imagepng($image);
                    $pngData = ob_get_clean();
                    imagedestroy($image);
                    $this->cache->setImage($fullPath, $pngData, $maxWidth, $maxHeight);
                    return [
                        'data' => 'data:image/png;base64,' . base64_encode($pngData),
                        'dimensions' => [
                            'width' => $newWidth,
                            'height' => $newHeight
                        ]
                    ];
                }
            }
        }
        return false;
    }
    private function getCachedImageDimensions($fullPath, $maxWidth, $maxHeight) {
        $originalDims = $this->getImageDimensions($fullPath, pathinfo($fullPath, PATHINFO_EXTENSION));
        if ($originalDims) {
            $width = $originalDims['width'];
            $height = $originalDims['height'];
            if ($width > $maxWidth || $height > $maxHeight) {
                $ratio = min($maxWidth / $width, $maxHeight / $height);
                return [
                    'width' => (int)($width * $ratio),
                    'height' => (int)($height * $ratio)
                ];
            }
            return $originalDims;
        }
        return null;
    }
    private function getImageDimensions($fullPath, $extension) {
        $extension = strtolower($extension);
        if ($extension === 'gif') {
            if (extension_loaded('imagick')) {
                try {
                    $imagick = new Imagick($fullPath);
                    $imagick->setIteratorIndex(0);
                    $width = $imagick->getImageWidth();
                    $height = $imagick->getImageHeight();
                    $imagick->clear();
                    return [
                        'width' => $width,
                        'height' => $height
                    ];
                } catch (Exception $e) {
                }
            }
            if (function_exists('imagecreatefromgif')) {
                $image = @imagecreatefromgif($fullPath);
                if ($image !== false) {
                    $width = imagesx($image);
                    $height = imagesy($image);
                    imagedestroy($image);
                    return [
                        'width' => $width,
                        'height' => $height
                    ];
                }
            }
        }
        if (extension_loaded('imagick')) {
            try {
                $imagick = new Imagick($fullPath);
                $width = $imagick->getImageWidth();
                $height = $imagick->getImageHeight();
                $imagick->clear();
                return [
                    'width' => $width,
                    'height' => $height
                ];
            } catch (Exception $e) {
            }
        }
        $getimagesizeFormats = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp', 'ico', 'tiff', 'jfif'];
        if (in_array($extension, $getimagesizeFormats)) {
            $imageInfo = @getimagesize($fullPath);
            if ($imageInfo !== false) {
                return [
                    'width' => $imageInfo[0],
                    'height' => $imageInfo[1]
                ];
            }
        }
        if ($extension === 'svg') {
            $svgContent = @file_get_contents($fullPath);
            if ($svgContent !== false) {
                if (preg_match('/width=["\'](\d+(?:\.\d+)?)["\']/', $svgContent, $widthMatch) &&
                    preg_match('/height=["\'](\d+(?:\.\d+)?)["\']/', $svgContent, $heightMatch)) {
                    return [
                        'width' => (int)$widthMatch[1],
                        'height' => (int)$heightMatch[1]
                    ];
                }
                if (preg_match('/viewBox=["\'][\d\s]+\s+(\d+(?:\.\d+)?)\s+(\d+(?:\.\d+)?)["\']/', $svgContent, $viewBoxMatch)) {
                    return [
                        'width' => (int)$viewBoxMatch[1],
                        'height' => (int)$viewBoxMatch[2]
                    ];
                }
            }
        }
        if ($extension === 'avif' && function_exists('exif_read_data')) {
            $exifData = @exif_read_data($fullPath);
            if ($exifData !== false && isset($exifData['COMPUTED']['Width']) && isset($exifData['COMPUTED']['Height'])) {
                return [
                    'width' => $exifData['COMPUTED']['Width'],
                    'height' => $exifData['COMPUTED']['Height']
                ];
            }
        }
        if (function_exists('imagecreatefromstring')) {
            $imageData = @file_get_contents($fullPath);
            if ($imageData !== false) {
                $image = @imagecreatefromstring($imageData);
                if ($image !== false) {
                    $width = imagesx($image);
                    $height = imagesy($image);
                    imagedestroy($image);
                    return [
                        'width' => $width,
                        'height' => $height
                    ];
                }
            }
        }
        return null;
    }
    private function formatBytes($size) {
        if ($size === null) return '-';
        $units = ['B', 'KB', 'MB', 'GB'];
        for ($i = 0; $size > 1024 && $i < count($units) - 1; $i++) {
            $size /= 1024;
        }
        return round($size, 2) . ' ' . $units[$i];
    }
}
?>