<?php

class Photo {
    private $conn;
    private $uploadDir = "uploads/";
    private $allowedTypes = array("jpg", "jpeg", "png", "gif");
    private $maxFileSize = 5242880; // 5MB
    private $secureTokenSalt = "FotoUpload-"; // Dosya token oluşturma için tuz
    
    public function __construct($conn) {
        $this->conn = $conn;
        
        // Uploads klasörü yoksa oluştur
        if (!file_exists($this->uploadDir)) {
            mkdir($this->uploadDir, 0777, true);
        }
    }
    
    // Dosyadan fotoğraf yükleme
    public function uploadFromFile($file, $userId = null) {
        // Dosya kontrolleri
        if ($file['error'] !== UPLOAD_ERR_OK) {
            return $this->handleUploadError($file['error']);
        }
        
        // Dosya boyutu kontrolü
        if ($file['size'] > $this->maxFileSize) {
            return array("success" => false, "message" => "Dosya boyutu çok büyük. Maksimum 5MB izin verilir.");
        }
        
        // Dosya uzantısı kontrolü
        $fileExtension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
        if (!in_array($fileExtension, $this->allowedTypes)) {
            return array("success" => false, "message" => "Geçersiz dosya türü. Sadece JPG, JPEG, PNG ve GIF formatları kabul edilir.");
        }
        
        // Benzersiz dosya adı oluşturma
        $newFileName = $this->generateSecureFileName($fileExtension);
        $uploadPath = $this->uploadDir . $newFileName;
        
        // Dosyayı taşıma
        if (!move_uploaded_file($file['tmp_name'], $uploadPath)) {
            return array("success" => false, "message" => "Dosya yüklenirken bir hata oluştu. Lütfen tekrar deneyin.");
        }
        
        // Dosya tipini doğrula (MIME kontrolü)
        if (!$this->validateFileType($uploadPath)) {
            unlink($uploadPath); // Geçersiz dosyayı sil
            return array("success" => false, "message" => "Güvenlik nedeniyle dosya reddedildi. Sadece gerçek resim dosyaları kabul edilir.");
        }
        
        // Veritabanına kaydetme
        $result = $this->saveToDatabase($newFileName, $file['name'], $fileExtension, $file['size'], $userId);
        
        if ($result["success"]) {
            // Erişim tokeni oluştur
            $token = $this->generateAccessToken($result["photo_id"]);
            
            return array(
                "success" => true, 
                "message" => "Fotoğraf başarıyla yüklendi.",
                "file_url" => $uploadPath,
                "photo_id" => $result["photo_id"],
                "access_token" => $token
            );
        } else {
            // Dosyayı sil (veritabanına kayıt başarısız)
            unlink($uploadPath);
            return array("success" => false, "message" => $result["message"]);
        }
    }
    
    // URL'den fotoğraf yükleme
    public function uploadFromUrl($url, $userId = null) {
        // URL kontrolü
        if (!filter_var($url, FILTER_VALIDATE_URL)) {
            return array("success" => false, "message" => "Geçersiz URL formatı.");
        }
        
        // Güvenlik: URL'nin güvenli olduğunu kontrol et
        $parsedUrl = parse_url($url);
        $blockedHosts = ['localhost', '127.0.0.1', '0.0.0.0', '::1'];
        
        if (in_array($parsedUrl['host'] ?? '', $blockedHosts)) {
            return array("success" => false, "message" => "Güvenlik nedeniyle yerel sunucu adreslerinden dosya yükleyemezsiniz.");
        }
        
        // Dosyayı indirme (timeout ve bağlantı hatalarına karşı kontrollü)
        $context = stream_context_create([
            'http' => [
                'timeout' => 10, // 10 saniye timeout
                'header' => 'User-Agent: FotoUpload/1.0'
            ]
        ]);
        
        $fileContent = @file_get_contents($url, false, $context);
        if ($fileContent === false) {
            return array("success" => false, "message" => "URL'den dosya indirilemedi.");
        }
        
        // Dosya boyutu kontrolü
        $fileSize = strlen($fileContent);
        if ($fileSize > $this->maxFileSize) {
            return array("success" => false, "message" => "Dosya boyutu çok büyük. Maksimum 5MB izin verilir.");
        }
        
        // Dosya uzantısını belirle
        $urlInfo = pathinfo($url);
        $fileExtension = isset($urlInfo['extension']) ? strtolower($urlInfo['extension']) : "";
        
        // Uzantı yoksa içerik tipinden belirle
        if (empty($fileExtension) || !in_array($fileExtension, $this->allowedTypes)) {
            $headers = get_headers($url, 1);
            $contentType = $headers['Content-Type'] ?? '';
            
            if (strpos($contentType, 'image/jpeg') !== false) {
                $fileExtension = 'jpg';
            } elseif (strpos($contentType, 'image/png') !== false) {
                $fileExtension = 'png';
            } elseif (strpos($contentType, 'image/gif') !== false) {
                $fileExtension = 'gif';
            } else {
                return array("success" => false, "message" => "Geçersiz dosya türü. Sadece JPG, JPEG, PNG ve GIF formatları kabul edilir.");
            }
        }
        
        // Benzersiz dosya adı oluşturma
        $newFileName = $this->generateSecureFileName($fileExtension);
        $uploadPath = $this->uploadDir . $newFileName;
        
        // Dosyayı kaydetme
        if (!file_put_contents($uploadPath, $fileContent)) {
            return array("success" => false, "message" => "Dosya kaydedilirken bir hata oluştu. Lütfen tekrar deneyin.");
        }
        
        // Dosya tipini doğrula (MIME kontrolü)
        if (!$this->validateFileType($uploadPath)) {
            unlink($uploadPath); // Geçersiz dosyayı sil
            return array("success" => false, "message" => "Güvenlik nedeniyle dosya reddedildi. Sadece gerçek resim dosyaları kabul edilir.");
        }
        
        // Veritabanına kaydetme
        $originalFileName = basename($url);
        $result = $this->saveToDatabase($newFileName, $originalFileName, $fileExtension, $fileSize, $userId);
        
        if ($result["success"]) {
            // Erişim tokeni oluştur
            $token = $this->generateAccessToken($result["photo_id"]);
            
            return array(
                "success" => true, 
                "message" => "Fotoğraf başarıyla yüklendi.",
                "file_url" => $uploadPath,
                "photo_id" => $result["photo_id"],
                "access_token" => $token
            );
        } else {
            // Dosyayı sil (veritabanına kayıt başarısız)
            unlink($uploadPath);
            return array("success" => false, "message" => $result["message"]);
        }
    }
    
    // Veriden fotoğraf yükleme (base64)
    public function uploadFromData($data, $userId = null) {
        // Base64 kontrolü
        if (strpos($data, 'base64') === false) {
            return array("success" => false, "message" => "Geçersiz görüntü verisi.");
        }
        
        // Veriyi ayıklama
        $parts = explode(',', $data);
        $dataPart = $parts[1] ?? '';
        
        if (empty($dataPart)) {
            return array("success" => false, "message" => "Geçersiz görüntü verisi.");
        }
        
        // Format belirleme
        $formatPart = $parts[0] ?? '';
        $fileExtension = 'jpg'; // Varsayılan
        
        if (strpos($formatPart, 'image/jpeg') !== false) {
            $fileExtension = 'jpg';
        } elseif (strpos($formatPart, 'image/png') !== false) {
            $fileExtension = 'png';
        } elseif (strpos($formatPart, 'image/gif') !== false) {
            $fileExtension = 'gif';
        }
        
        // Base64'ten çevirme
        $fileContent = base64_decode($dataPart);
        $fileSize = strlen($fileContent);
        
        // Dosya boyutu kontrolü
        if ($fileSize > $this->maxFileSize) {
            return array("success" => false, "message" => "Dosya boyutu çok büyük. Maksimum 5MB izin verilir.");
        }
        
        // Benzersiz dosya adı oluşturma
        $newFileName = $this->generateSecureFileName($fileExtension);
        $uploadPath = $this->uploadDir . $newFileName;
        
        // Dosyayı kaydetme
        if (!file_put_contents($uploadPath, $fileContent)) {
            return array("success" => false, "message" => "Dosya kaydedilirken bir hata oluştu. Lütfen tekrar deneyin.");
        }
        
        // Dosya tipini doğrula (MIME kontrolü)
        if (!$this->validateFileType($uploadPath)) {
            unlink($uploadPath); // Geçersiz dosyayı sil
            return array("success" => false, "message" => "Güvenlik nedeniyle dosya reddedildi. Sadece gerçek resim dosyaları kabul edilir.");
        }
        
        // Veritabanına kaydetme
        $originalFileName = "pasted_image." . $fileExtension;
        $result = $this->saveToDatabase($newFileName, $originalFileName, $fileExtension, $fileSize, $userId);
        
        if ($result["success"]) {
            // Erişim tokeni oluştur
            $token = $this->generateAccessToken($result["photo_id"]);
            
            return array(
                "success" => true, 
                "message" => "Fotoğraf başarıyla yüklendi.",
                "file_url" => $uploadPath,
                "photo_id" => $result["photo_id"],
                "access_token" => $token
            );
        } else {
            // Dosyayı sil (veritabanına kayıt başarısız)
            unlink($uploadPath);
            return array("success" => false, "message" => $result["message"]);
        }
    }
    
    // Veritabanına kaydetme
    private function saveToDatabase($fileName, $originalName, $fileType, $fileSize, $userId) {
        $fileUrl = $this->uploadDir . $fileName;
        $created_at = date('Y-m-d H:i:s');
        $userId = $userId ? $userId : null;
        
        $sql = "INSERT INTO photos (file_name, original_name, file_type, file_size, file_url, user_id, created_at) 
                VALUES (?, ?, ?, ?, ?, ?, ?)";
                
        $stmt = mysqli_prepare($this->conn, $sql);
        mysqli_stmt_bind_param($stmt, "sssisds", $fileName, $originalName, $fileType, $fileSize, $fileUrl, $userId, $created_at);
        
        if (mysqli_stmt_execute($stmt)) {
            $photoId = mysqli_insert_id($this->conn);
            mysqli_stmt_close($stmt);
            return array("success" => true, "photo_id" => $photoId);
        } else {
            $error = mysqli_stmt_error($stmt);
            mysqli_stmt_close($stmt);
            error_log("Photo database insert error: " . $error);
            return array("success" => false, "message" => "Veritabanına kayıt sırasında bir hata oluştu.");
        }
    }
    
    // Fotoğraf getirme (Güvenli erişim için token kontrolü eklenmiş)
    public function getPhoto($photoId, $token = null) {
        // ID kontrolü
        $photoId = (int)$photoId;
        if ($photoId <= 0) {
            return false;
        }
        
        $sql = "SELECT * FROM photos WHERE id = ?";
        $stmt = mysqli_prepare($this->conn, $sql);
        mysqli_stmt_bind_param($stmt, "i", $photoId);
        mysqli_stmt_execute($stmt);
        $result = mysqli_stmt_get_result($stmt);
        
        if (mysqli_num_rows($result) > 0) {
            $photo = mysqli_fetch_assoc($result);
            mysqli_stmt_close($stmt);
            
            // Token kontrol (token null ise admin veya iç sistem erişimi kabul et)
            if ($token !== null) {
                $validToken = $this->generateAccessToken($photoId);
                if ($token !== $validToken) {
                    return false; // Geçersiz token
                }
            }
            
            return $photo;
        }
        
        mysqli_stmt_close($stmt);
        return false;
    }
    
    // Son yüklenen fotoğrafları getirme
    public function getRecentPhotos($limit = 20) {
        // Limit kontrol
        $limit = (int)$limit;
        if ($limit <= 0 || $limit > 100) {
            $limit = 20; // Varsayılan limit
        }
        
        $sql = "SELECT * FROM photos ORDER BY created_at DESC LIMIT ?";
        $stmt = mysqli_prepare($this->conn, $sql);
        mysqli_stmt_bind_param($stmt, "i", $limit);
        mysqli_stmt_execute($stmt);
        $result = mysqli_stmt_get_result($stmt);
        
        $photos = array();
        while ($row = mysqli_fetch_assoc($result)) {
            $row['access_token'] = $this->generateAccessToken($row['id']);
            $photos[] = $row;
        }
        
        mysqli_stmt_close($stmt);
        return $photos;
    }
    
    // Upload hatalarını ele alma
    private function handleUploadError($errorCode) {
        $message = "";
        
        switch ($errorCode) {
            case UPLOAD_ERR_INI_SIZE:
            case UPLOAD_ERR_FORM_SIZE:
                $message = "Dosya boyutu çok büyük.";
                break;
            case UPLOAD_ERR_PARTIAL:
                $message = "Dosya kısmen yüklendi.";
                break;
            case UPLOAD_ERR_NO_FILE:
                $message = "Dosya yüklenmedi.";
                break;
            case UPLOAD_ERR_NO_TMP_DIR:
                $message = "Geçici klasör bulunamadı.";
                break;
            case UPLOAD_ERR_CANT_WRITE:
                $message = "Dosya diske yazılamadı.";
                break;
            case UPLOAD_ERR_EXTENSION:
                $message = "Bir PHP uzantısı dosya yüklemesini durdurdu.";
                break;
            default:
                $message = "Bilinmeyen bir hata oluştu.";
                break;
        }
        
        return array("success" => false, "message" => $message);
    }
    
    // Güvenli, benzersiz dosya adı oluşturma
    private function generateSecureFileName($extension) {
        // Güçlü rastgele string üretimi
        $random = bin2hex(random_bytes(10));
        $timestamp = time();
        return $random . $timestamp . '.' . $extension;
    }
    
    // Erişim tokeni oluşturma
    private function generateAccessToken($photoId) {
        // Güvenli token oluşturma (HMAC tabanlı)
        return hash_hmac('sha256', $photoId . $this->secureTokenSalt, $this->secureTokenSalt);
    }
    
    // Dosya tipini doğrulama (güvenlik)
    private function validateFileType($filePath) {
        if (!file_exists($filePath)) {
            return false;
        }
        
        // MIME kontrolü
        $finfo = new finfo(FILEINFO_MIME_TYPE);
        $mime = $finfo->file($filePath);
        
        // İzin verilen MIME tipleri
        $allowedMimes = [
            'image/jpeg',
            'image/png',
            'image/gif'
        ];
        
        return in_array($mime, $allowedMimes);
    }
    
    // Fotoğraf erişim URL oluşturma
    public function getSecurePhotoUrl($photoId) {
        $photo = $this->getPhoto($photoId);
        if (!$photo) {
            return false;
        }
        
        // Güvenli erişim için token ekle
        $token = $this->generateAccessToken($photoId);
        return 'view_photo.php?id=' . $photoId . '&token=' . $token;
    }
}
?> 