Kỹ thuật PHP xử lý tải file có tiếp tục, mô phỏng đăng nhập qua CURL và Debug thông tin trên Nginx

Hỗ trợ tải xuống theo đoạn (Resumable Download) trong PHP

Tính năng tải lại từ vị trí dừng trước đó là một tiêu chuẩn quan trọng để cải thiện trải nghiệm người dùng khi mạng không ổn định. Thay vì phải tải lại toàn bộ dữ liệu từ đầu, trình duyệt sẽ gửi yêu cầu bắt đầu từ vị trí byte cụ thể mà phần trước đã được nhận.

Cơ chế này dựa trên tiêu chuẩn HTTP Range của phiên bản 1.1 trở lên. Khi client gửi header Range: bytes=start-end, server phản hồi trạng thái 206 (Partial Content) kèm theo lượng dữ liệu tương ứng trong header Content-Range.

Dưới đây là cách triển khai hàm truyền tải tệp với logic kiểm tra vị trí bắt đầu:

<?php
/**
 * Gửi file về trình duyệt với hỗ trợ tiếp tục tải
 * @param string $filePath Đường dẫn tới file cần tải
 */
function streamResource($filePath) {
    // Loại bỏ giới hạn thời gian thực thi script
    set_time_limit(0);

    if (!file_exists($filePath)) {
        return false;
    }

    $fileInfo = pathinfo($filePath);
    $totalBytes = filesize($filePath);

    // Lấy thông tin Range từ header request
    $rangeHeader = isset($_SERVER['HTTP_RANGE']) ? $_SERVER['HTTP_RANGE'] : '';
    $startByte = 0;

    // Regex để lấy số byte bắt đầu nếu Range tồn tại
    if ($rangeHeader !== '' && preg_match('/bytes=(\d+)-(\d*)/', $rangeHeader, $matches)) {
        $requestedStart = intval($matches[1]);
        if ($requestedStart >= 0 && $requestedStart < $totalBytes) {
            $startByte = $requestedStart;
        }
    }

    // Thiết lập các header phản hồi
    header('Cache-Control: public');
    header('Pragma: public');
    
    // Xử lý phân biệt giữa tải mới và tải tiếp tục
    if ($startByte > 0) {
        header('HTTP/1.1 206 Partial Content');
        header('Accept-Ranges: bytes');
        $endByte = $totalBytes - 1;
        header("Content-Range: bytes {$startByte}-{$endByte}/{$totalBytes}");
        header("Content-Length: " . ($totalBytes - $startByte));
    } else {
        header('Accept-Ranges: bytes');
        header("Content-Length: {$totalBytes}");
    }

    header("Content-Type: application/octet-stream"); 
    header("Content-Disposition: attachment; filename=\"{$fileInfo['basename']}\"");

    // Mở file và đẩy nội dung
    if (($handle = fopen($filePath, 'rb'))) {
        fseek($handle, $startByte);
        while (!feof($handle)) {
            echo fread($handle, 8192); // Tăng buffer size cho hiệu suất cao hơn
        }
        fclose($handle);
        return true;
    }
    
    echo 'Lỗi không thể mở file';
    return false;
}
?>

Mô phỏng trạng thái đăng nhập sử dụng CURL và Cookies

Trong các tác vụ tự động hoặc thu thập dữ liệu (scraping), đôi khi chúng ta cần thao tác như một người dùng đã đăng nhập. Cách đơn giản nhất là lưu trữ chuỗi Cookie sau lần đăng nhập thành công và sử dụng nó cho các lần gọi API sau.

Dưới đây là ví dụ về một lớp xử lý việc gửi POST dữ liệu để đăng nhập, đồng thời lưu cookie vào file để tái sử dụng:

<?php
class SessionSimulator {
    private $userPass = [
        'username' => 'demo_user',
        'password' => 'secure_pass_123'
    ];
    private $cookieJar = '/tmp/cookies_session.txt';

    /**
     * Thực hiện hành động đăng nhập và lưu cookie
     */
    public function performLogin($loginUrl) {
        $params = ['user' => $this->userPass['username'], 'pass' => $this->userPass['password']];
        return $this->executeRequest($loginUrl, $params, true);
    }

    /**
     * Thực hiện request chung, hỗ trợ lưu/read cookie tùy chọn
     */
    public function executeRequest($targetUrl, array $postData = [], $enableCookiePersistence = false) {
        $ch = curl_init();
        
        curl_setopt_array($ch, [
            CURLOPT_URL => $targetUrl,
            CURLOPT_FOLLOWLOCATION => true, // Tự động chuyển hướng
            CURLOPT_RETURNTRANSFER => true, // Trả về kết quả thay vì hiển thị
            CURLOPT_TIMEOUT => 30,
            CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
            CURLOPT_REFERER => 'https://example.com/',
            CURLOPT_HTTPHEADER => ["Connection: keep-alive"]
        ]);

        // Cấu hình Cookie nếu cần bảo mật phiên
        if ($enableCookiePersistence) {
            curl_setopt($ch, CURLOPT_COOKIEJAR, $this->cookieJar);
            curl_setopt($ch, CURLOPT_COOKIEFILE, $this->cookieJar);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // Bỏ qua verify SSL nếu cần
        }

        if (!empty($postData)) {
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
        }

        $responseBody = curl_exec($ch);
        $info = curl_getinfo($ch);
        curl_close($ch);

        return $responseBody;
    }
}

// --- Sử dụng ---
$app = new SessionSimulator();

// 1. Đăng nhập
$urlLogin = 'https://example.com/login_endpoint';
$app->performLogin($urlLogin);

// 2. Truy cập trang nội bộ đã đăng nhập (sẽ tự động dùng file cookie vừa tạo)
$urlProtected = 'https://example.com/user/dashboard.html';
$result = $app->executeRequest($urlProtected, [], true);
echo $result;
?>

Sau khi chạy xong, file chứa cookie sẽ được tạo tại đường dẫn chỉ định, cho phép bất kỳ công cụ nào đọc file này để tiếp tục hoạt động giống như phiên làm việc đang duy trì.

Debug thông tin phản hồi Header trên Nginx

Khi cấu hình Nginx, việc xác minh xem biến hoặc điều kiện quy tắc có đang được kích hoạt hay không thường khó khăn nếu không biết giá trị hiện tại của nó. Có hai phương pháp chính để đưa thông tin ra màn hình người dùng.

Phương pháp 1: Bổ sung thêm module echo

Một số dự án sử dụng module ngx_http_echo_module của nhóm NGINX Inc (hoặc Agentzh) để phát trực tiếp nội dung ra response body. Tuy nhiên, cách này đòi hỏi biên tập lại Nginx nguồn gốc, tốn kém tài nguyên hệ thống.

Phương pháp 2: Lợi dụng Add_Header để hiển thị biến toàn cục

Nginx cung cấp sẵn cơ chế chèn biến vào Custom Header. Bằng cách sử dụng câu lệnh add_header, bạn có thể nhúng mọi thông tin biến có sẵn vào header trả về, trình duyệt vẫn nhận được nhưng ta có thể xem trong tab Network (Headers).

location / {
    add_header X-Client-IP $remote_addr always;
    add_header X-Request-URI $request_uri always;
    add_header X-Server-Time $server_time always;
    # ... các biến khác
}

Dưới đây là danh sách các biến phổ biến thường dùng để gỡ lỗi trên Nginx:

  • $remote_addr: Địa chỉ IP đích đến của khách hàng.
  • $host: Giá trị trường Host trong yêu cầu.
  • $request_method: Phương thức HTTP (GET, POST, v.v.).
  • $request_uri: URI đầy đủ bao gồm cả chuỗi truy vấn.
  • $document_root: Thư mục gốc hiện tại của root.
  • $uri: URI yêu cầu không bao gồm chuỗi tham số.
  • $status: Mã trạng thái trả về cho client.
  • $http_user_agent: Thông tin User-Agent của trình duyệt.
  • $args: Chuỗi tham số truy vấn (query string).
  • $body_bytes_sent: Số lượng byte đã truyền đi.
  • $server_name: Tên miền máy chủ xử lý.

Với những biến này, kết hợp với `add_header`, bạn có thể nhanh chóng kiểm tra luồng xử lý request ngay lập tức mà không cần cài đặt thêm phần mềm bên ngoài.

Thẻ: php nginx cURL HTTP Protocol Web Debugging

Đăng vào ngày 2 tháng 6 lúc 02:49