2013-06-12 24 views
5

Sau nhiều giờ,Cách trả lại hình ảnh cho yêu cầu https bằng PHP

Tôi đã giải thích được vấn đề liên quan đến việc tải xuống hình ảnh có yêu cầu https. Khi tôi truy cập hình ảnh với đường dẫn cứng (https://mysite/tmp/file.jpg), apache trả về hình ảnh thành công và tôi có thể xem hình ảnh trong trình duyệt mà không cần thao tác thêm. Khi tôi cố truy cập nó bằng một đường dẫn khác (https://mysite/files/file.jpg), để kiểm soát quyền truy cập của nó bằng php, tôi nhận được phản hồi từ mã php của tôi, nhưng tôi không thể xem hình ảnh trong trình duyệt.

  • VirtualHost được xác định; mysite: được đặt thành/var/www/mysite
  • $ app ['controllers'] -> requireHttps();

Mô tả về môi trường:

mysite/tmp/file.jpg   
mysite/files/.htaccess 
      //... no files; handled by Silex router. here is the .htaccess: 
      --- 
      <IfModule mod_rewrite.c> 
       RewriteEngine On 
       RewriteRule^../web/index.php [L] 
      </IfModule> 
      --- 
  • https: // mysite/tmp/file.jpg, ăn kèm với https: 200 và xem trong trình duyệt; ok
  • https: // mysite/files/file.jpg được phục vụ với https: 200 nhưng không phải được xem trong trình duyệt; ?

Dưới đây là 3 phương pháp thử:

Phương pháp 1: silex sendFile() phương pháp trực tiếp>

$app->get('/files/{onefile}', function ($onefile) use ($app) {  
    // Validate authorization; if ok, then 
    return $app->sendFile('/var/www/mysite/tmp/' . $onefile); 
}); 

Cách 2: silex streaming>

$app->get('/files/{onefile}', function ($onefile) use ($app) { 
    // Validate authorization; if ok, then 
    $stream = function() use ($file) { 
     readfile($file); 
    }; 
    return $app->stream($stream, 200, array('Content-Type' => 'image/jpeg')); 

Phương pháp 3: Symfony2 style>

$app->get('/files/{onefile}', function ($onefile) use ($app) { 
    // Validate authorization; if ok, then 
    $exactFile="/var/www/mysite/tmp/" . $onefile; 
    $response = new StreamedResponse(); 
    $response->setCallback(function() use ($exactFile) { 
     $fp = fopen($exactFile, 'rb'); 
     fpassthru($fp); 
    }); 
    $response->headers->set('Content-Type', 'image/jpg'); 
    $response->headers->set('Content-length', filesize($exactFile)); 
    $response->headers->set('Connection', 'Keep-Alive'); 
    $response->headers->set('Accept-Ranges','bytes'); 
    $response->send(); 

Đây là những gì Chrome trình bày:

enter image description here

Với hình ảnh Chrome này đây là Http (Https hay không, cùng kết quả) yêu cầu

Request URL:https://mysite/files/tmpphp0XkXn9.jpg 
Request Method:GET 
Status Code:200 OK 

Request Headers: 
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 
Accept-Encoding:gzip,deflate,sdch 
Accept-Language:en-US,en;q=0.8 
Cache-Control:no-cache 
Connection:keep-alive 
Cookie:XDEBUG_SESSION=netbeans-xdebug; _MYCOOKIE=u1k1vafhaqik2d4jknko3c94j1 
Host:mysite 
Pragma:no-cache 
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36 

Response Headers: 
Accept-Ranges:bytes 
Cache-Control:no-cache 
Connection:Keep-Alive, Keep-Alive 
Content-Length:39497 
Content-Type:image/jpg 
Date:Thu, 13 Jun 2013 13:44:55 GMT 
Keep-Alive:timeout=15, max=99 
Server:Apache/2.2.16 (Debian) 
X-Powered-By:PHP/5.3.3-7+squeeze15 

Các thử nghiệm khác được thực hiện để loại bỏ hành vi không mong muốn có thể xảy ra:

  • Tôi đã kiểm tra BOM và chắc chắn mã php đáp ứng các yêu cầu hợp lệ và không có dấu ngoặc byte-trật tự không mong muốn (BOMs) sử dụng Emacs (set-buffer-file-coding-system utf-8). Hơn nữa, để tránh các tệp BOM không xác định được gắn thẻ, tôi đã thực hiện lệnh sau trong thư mục mysite (grep -rl $'\xEF\xBB\xBF' .). Không có gì bất thường xuất hiện.

UPDATE:

Nhìn vào các tập tin (hình ảnh) nhận bởi trình duyệt (save as trên mỗi hình ảnh), đây là những gì các công cụ (Hex bè) giúp tôi để tìm, nhưng tôi vẫn làm không hiểu tại sao:

So sánh hai tập tin

  • (một với thành công: mysite/tmp/file.jpg; phục vụ trực tiếp b y Apache)
  • (một không có thành công: mysite/files/file.jpg; được phục vụ bởi tập lệnh PHP).

Vào đầu của tập tin nhị phân, tôi nhận được sự khác biệt này: enter image description here

Vào cuối của tập tin nhị phân, tôi nhận được sự khác biệt này: enter image description here

Câu hỏi : Làm cách nào để trả lại hình ảnh (trong luồng hoặc một số kỹ thuật khác) bằng mã php và xem trong trình duyệt? Tất cả các phương thức mã php trả về cùng một đầu ra, tôi nghi ngờ một vấn đề môi trường. Có một môi trường có thể tạo ra lỗi mà tôi đang thử nghiệm không?

+1

Bạn muốn gì? hiển thị hoặc tải xuống hình ảnh? câu đầu tiên trong các câu hỏi về tải xuống. thì bạn sẽ cần tiêu đề sắp xếp nội dung. btw. xóa bộ nhớ cache của trình duyệt và ứng dụng của bạn? :) – nifr

+0

Ok, tôi sẽ làm rõ câu hỏi trong phần văn bản chính. – Alain

+0

Xóa bộ nhớ cache của trình duyệt không có hiệu lực. – Alain

Trả lời

4

Tôi không hài lòng với giải pháp này (A PATCH), nhưng vấn đề là cố định, bằng cách thêm các cuộc gọi sau đây:

$app->get('/files/{onefile}', function ($onefile) use ($app) {  
    ob_end_clean(); // ob_clean() gave me the same result. 
... 
} 

Ok, nó là cố định, nhưng, ai đó có thể giải thích với tôi làm thế nào để sửa nó thông minh hơn?

CẬP NHẬT

gì đã xảy ra?

Đây là những gì giải thích của tôi:
newlines tắm vẫn nằm trong php orignal file nguyên gốc để xác định vị trí một vô ý! Nó chỉ ra rằng khi bạn có một tập tin php

<?php 
... 
?> 

nơi bạn để lại một số dòng mới (hoặc không gian) sau khi ?>, những dòng mới sẽ thêm lên trong bộ đệm đầu ra. Sau đó, cố gắng truyền một tệp tới đầu ra sẽ lấy các dòng mới này và đặt chúng vào nơi chúng thuộc về: trong luồng đầu trang hoặc tại dòng chân trang. Có kích thước cố định cho luồng (bằng với kích thước hình ảnh) sẽ đặc biệt thêm các ký tự đầu trang và thay đổi tương ứng các byte được xuất ra trình duyệt. Tôi nghi ngờ rằng tôi thêm chính xác 5 ký tự (0A 0A 20 0A 0A) tương ứng với (linefeed linefeed space linefeed linefeed) được phát hiện trong hình ảnh đã nhận từ trình duyệt. Bây giờ trình duyệt không nhận ra cấu trúc hình ảnh, đang chuyển từ offset 0, của 5 ký tự không hợp lý cho hình ảnh nhị phân. Do đó, trình duyệt chỉ có thể hiển thị biểu tượng hình ảnh bị hỏng.

Ngoài ra xem xét: Another helping SO fix

Tư vấn để phát triển khuôn khổ PHP:

Nếu bạn cung cấp một phương pháp tương đương sendFile(), có lẽ bạn nên ném một Exception, khi ob_get_contents() không trả lại một bộ đệm trống, chỉ cần trước khi phát trực tiếp đến đầu ra!

Còn bây giờ:

nhỏ tập tin Linux mẻ này ít nhất có thể cho phép bạn tìm nơi mã của bạn nên được làm sạch. Sau khi sử dụng nó, tôi đã có thể xóa ob_end_clean() ... sau khi phân tích đầu ra của tập lệnh nhỏ này. Nó cho bạn biết các tệp php đáng ngờ có thể chứa thêm không gian hoặc dòng mới ở cuối tệp php của bạn. Chỉ cần thực thi và sửa các tệp theo cách thủ công:

#!/bin/bash 

for phpfiles in $(ls -1R *.php); do 
    hexdump -e '1/1 "%.2x"' $phpfiles | tail -1 >endofphpfile; 
    if [ `cat endofphpfile` = "3f3e" ]; then 
     echo "OK.................File $phpfiles" 
    else 
     thisout=`cat endofphpfile` 
     echo "File $phpfiles: Suspucious. Check ($thisout) at the EOF; it should end with '?>' (in hex 3f3e) " 
    fi 
done 

Nó chắc chắn có thể được cải thiện, nhưng ít nhất, giúp mọi người!

+1

Bạn thưa bạn, là anh hùng của tôi! Tôi đã dành một ngày để tìm ra điều này. Thêm 'ob_end_clean();' vào đầu của một cuộc gọi lại 'StreamedResponse' là những gì tôi đã thiếu trong mã của tôi. Tôi đã cố gắng để trả lại một hình ảnh được lưu trữ bởi Postgres bytea cho người dùng, nhưng không có vấn đề gì tôi đã làm - không có gì làm việc. Cảm ơn bạn đã chia sẻ câu trả lời này! – tftd

3

không sử dụng kết thúc ?> ... không đúng tiêu chuẩn mã hóa của symfony.

Chống lại PSR-2 để cụ thể hơn.

Tất cả tệp PHP PHẢI kết thúc bằng một dòng trống.

Thẻ đóng?> PHẢI được bỏ qua khỏi các tệp chỉ chứa PHP.

Lý do cho điều đó một phần là những gì bạn gặp phải.

Hành vi này đôi khi gây ra bởi số BOM.

kiểm tra xem tệp nào của bạn có chứa dấu thứ tự byte không!

Các vấn đề liên quan