Sindbad~EG File Manager

Current Path : /var/www/html/sumar.com.py/wp-content/plugins/migrator-plugin-0.1.0/includes/
Upload File :
Current File : /var/www/html/sumar.com.py/wp-content/plugins/migrator-plugin-0.1.0/includes/class-s3-uploader.php

<?php
/**
 * The class responsible for uploading files to S3 using pre-signed URLs.
 *
 * @package CustomMigrator
 */

/**
 * S3 Uploader class.
 */
class Custom_Migrator_S3_Uploader {

    /**
     * The filesystem handler.
     *
     * @var Custom_Migrator_Filesystem
     */
    private $filesystem;

    /**
     * Initialize the class.
     */
    public function __construct() {
        $this->filesystem = new Custom_Migrator_Filesystem();
    }

    /**
     * Update S3 upload status.
     *
     * @param string $status The upload status to save.
     */
    private function update_s3_status($status) {
        $status_file = WP_CONTENT_DIR . '/hostinger-migration-archives/s3-upload-status.txt';
        file_put_contents($status_file, $status);
    }

    /**
     * Upload files to S3 using pre-signed URLs.
     *
     * @param array $presigned_urls Array of file types and their pre-signed URLs.
     * @return array Result of the upload process.
     */
    public function upload_to_s3($presigned_urls) {
        // Try to increase PHP execution time limit
        @set_time_limit(0);  // Try to remove the time limit
        @ini_set('max_execution_time', 3600); // Try to set to 1 hour
        
        // Initialize results array
        $results = array(
            'success' => true,
            'messages' => array(),
            'uploaded' => array()
        );

        // Get file paths
        $file_paths = $this->filesystem->get_export_file_paths();
        
        // Update status to starting
        $this->update_s3_status("starting");
        
        // Start logging
        $this->filesystem->log("Starting S3 upload process");
        
        // Loop through each file type
        foreach ($presigned_urls as $file_type => $presigned_url) {
            // Skip if no URL provided
            if (empty($presigned_url)) {
                $this->filesystem->log("No pre-signed URL provided for $file_type file. Skipping.");
                $results['messages'][] = "No pre-signed URL provided for $file_type file.";
                continue;
            }
            
            // Preserve encoded slashes in the URL
            $presigned_url = $this->preserve_encoded_slashes($presigned_url);
            
            // Check if file exists
            if (!isset($file_paths[$file_type]) || !file_exists($file_paths[$file_type])) {
                $this->filesystem->log("File not found for $file_type: " . (isset($file_paths[$file_type]) ? $file_paths[$file_type] : 'undefined path'));
                $results['messages'][] = "File not found for $file_type.";
                $results['success'] = false;
                continue;
            }
            
            // Update status to show current file being uploaded
            $this->update_s3_status("uploading_$file_type");
            
            // Log file details
            $file_path = $file_paths[$file_type];
            $file_size = filesize($file_path);
            $this->filesystem->log("Uploading $file_type file: " . basename($file_path) . " (" . $this->filesystem->format_file_size($file_size) . ")");
            
            try {
                // Attempt to upload the file
                $upload_result = $this->upload_file_to_s3($presigned_url, $file_path);
                
                if ($upload_result['success']) {
                    $this->filesystem->log("Successfully uploaded $file_type file to S3");
                    $results['messages'][] = "Successfully uploaded $file_type file to S3.";
                    $results['uploaded'][] = $file_type;
                } else {
                    $this->filesystem->log("Failed to upload $file_type file: " . $upload_result['message']);
                    $results['messages'][] = "Failed to upload $file_type file: " . $upload_result['message'];
                    $results['success'] = false;
                }
            } catch (Exception $e) {
                $this->filesystem->log("Error uploading $file_type file: " . $e->getMessage());
                $results['messages'][] = "Error uploading $file_type file: " . $e->getMessage();
                $results['success'] = false;
            }
        }
        
        // Update final status
        if ($results['success']) {
            $this->update_s3_status("done");
            $this->filesystem->log("S3 upload process completed successfully");
        } else {
            $this->update_s3_status("error: Upload failed");
            $this->filesystem->log("S3 upload process completed with errors");
        }
        
        return $results;
    }
    
    /**
     * Ensures that URL-encoded slashes in X-Amz-Credential are preserved.
     *
     * @param string $presigned_url The pre-signed URL
     * @return string The URL with properly preserved encoded slashes
     */
    private function preserve_encoded_slashes($presigned_url) {
        $original_url = $presigned_url;
        
        // First check if the URL contains encoded slashes (%2F)
        if (strpos($presigned_url, '%2F') !== false) {
            // URL has encoded slashes, which is good. Log and return as is.
            $this->filesystem->log("Pre-signed URL contains properly encoded slashes (%2F)");
            return $presigned_url;
        }
        
        // If we get here, the URL might have decoding issues
        $this->filesystem->log("Pre-signed URL does not contain encoded slashes, checking format...");
        
        // Check if credential is missing slashes completely
        if (preg_match('/X-Amz-Credential=([A-Za-z0-9]{20})([0-9]{8})(eu-north-1)s3aws4_request/', $presigned_url, $matches)) {
            // Found malformed credential, attempt to fix
            $this->filesystem->log("Found malformed X-Amz-Credential without slashes, attempting to fix");
            
            $access_key = $matches[1];
            $date = $matches[2];
            $region = $matches[3];
            
            // Create properly encoded credential
            $encoded_credential = $access_key . '%2F' . $date . '%2F' . $region . '%2Fs3%2Faws4_request';
            
            // Replace the malformed credential with the fixed one
            $fixed_url = preg_replace(
                '/X-Amz-Credential=[A-Za-z0-9]{20}[0-9]{8}eu-north-1s3aws4_request/',
                'X-Amz-Credential=' . $encoded_credential,
                $presigned_url
            );
            
            if ($fixed_url !== $presigned_url) {
                $this->filesystem->log("Fixed X-Amz-Credential by adding encoded slashes (%2F)");
                return $fixed_url;
            }
        }
        
        // Check if it contains unencoded slashes (/)
        if (preg_match('/X-Amz-Credential=([^&]+)\/([^&]+)\/([^&]+)\/s3\/aws4_request/', $presigned_url, $matches)) {
            // Has unencoded slashes, encode them
            $this->filesystem->log("Found X-Amz-Credential with unencoded slashes, encoding them");
            
            $access_key = $matches[1];
            $date = $matches[2];
            $region = $matches[3];
            
            // Create properly encoded credential
            $encoded_credential = $access_key . '%2F' . $date . '%2F' . $region . '%2Fs3%2Faws4_request';
            
            // Replace the unencoded credential with the encoded one
            $fixed_url = str_replace(
                $matches[0],
                'X-Amz-Credential=' . $encoded_credential,
                $presigned_url
            );
            
            if ($fixed_url !== $presigned_url) {
                $this->filesystem->log("Fixed X-Amz-Credential by encoding slashes to %2F");
                return $fixed_url;
            }
        }
        
        // If we get here, we couldn't fix the URL
        $this->filesystem->log("Could not determine proper format for X-Amz-Credential");
        return $original_url;
    }

    /**
     * Upload a file to S3 using a pre-signed URL.
     *
     * @param string $presigned_url The pre-signed URL for uploading.
     * @param string $file_path The local path to the file.
     * @return array Result of the upload.
     */
    private function upload_file_to_s3($presigned_url, $file_path) {
        // Check if file exists and is readable
        if (!file_exists($file_path) || !is_readable($file_path)) {
            return array(
                'success' => false,
                'message' => 'File does not exist or is not readable'
            );
        }
        
        // Get content type based on file extension
        $content_type = $this->get_mime_type($file_path);
        $this->filesystem->log("Using content type: " . $content_type . " for file: " . basename($file_path));
        
        // Get file size
        $file_size = filesize($file_path);
        
        // Prepare headers
        $headers = array(
            'Content-Type: ' . $content_type,
            'Content-Length: ' . $file_size
        );
        
        // Log the upload details
        $this->filesystem->log("Uploading file with size: " . $this->filesystem->format_file_size($file_size));
        $this->filesystem->log("Using headers: " . json_encode($headers));
        
        // Initialize cURL session
        $ch = curl_init();
        
        // Log the URL being used (for debugging)
        $this->filesystem->log("Using pre-signed URL: " . substr($presigned_url, 0, 100) . "..." . (strlen($presigned_url) > 100 ? substr($presigned_url, -50) : ""));
        
        // Set cURL options for the upload
        curl_setopt($ch, CURLOPT_URL, $presigned_url);
        curl_setopt($ch, CURLOPT_PUT, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
        curl_setopt($ch, CURLOPT_TIMEOUT, 3600); // 1 hour timeout for large files
        
        // Enable verbose debugging
        curl_setopt($ch, CURLOPT_VERBOSE, true);
        $verbose = fopen('php://temp', 'w+');
        curl_setopt($ch, CURLOPT_STDERR, $verbose);
        
        // Set the file for upload
        $file_handle = fopen($file_path, 'rb');
        curl_setopt($ch, CURLOPT_INFILE, $file_handle);
        curl_setopt($ch, CURLOPT_INFILESIZE, $file_size);
        
        // Execute the request
        $response = curl_exec($ch);
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $curl_error = curl_error($ch);
        
        // Get verbose log
        rewind($verbose);
        $verbose_log = stream_get_contents($verbose);
        fclose($verbose);
        
        // Log detailed info if there was an error
        if ($http_code < 200 || $http_code >= 300) {
            $this->filesystem->log("HTTP Status Code: " . $http_code);
            if (!empty($curl_error)) {
                $this->filesystem->log("CURL Error: " . $curl_error);
            }
            $this->filesystem->log("Response: " . $response);
            $this->filesystem->log("Verbose Log: " . $verbose_log);
        }
        
        // Clean up resources
        fclose($file_handle);
        curl_close($ch);
        
        // Check if upload was successful
        if ($http_code >= 200 && $http_code < 300) {
            return array(
                'success' => true,
                'message' => 'File uploaded successfully'
            );
        } else {
            return array(
                'success' => false,
                'message' => "HTTP Error: " . $http_code . (!empty($curl_error) ? ", CURL Error: " . $curl_error : "")
            );
        }
    }

    /**
     * Get the MIME type of a file.
     *
     * @param string $file_path The path to the file.
     * @return string The MIME type.
     */
    private function get_mime_type($file_path) {
        $file_extension = strtolower(pathinfo($file_path, PATHINFO_EXTENSION));
        
        // Define MIME types for known file extensions
        switch ($file_extension) {
            case 'hstgr':
                return 'application/octet-stream';
            case 'sql':
                return 'text/plain';
            case 'gz':
                return 'application/gzip';
            case 'json':
                return 'application/json';
            case 'txt':
                return 'text/plain';
            default:
                // Try to use PHP's built-in function if available
                if (function_exists('mime_content_type')) {
                    return mime_content_type($file_path);
                }
                // Default for binary data
                return 'application/octet-stream';
        }
    }
}

Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists