After many hours,
I nailed down my problem concerning downloading an image with an https request.
When I access an image with the hard path (https://mysite/tmp/file.jpg)
, apache
returns it with success and I can view it in the browser, without any extra manipulation.
When I try to access it with another path
(https://mysite/files/file.jpg)
, in order to control its access with php, I get
a response from my php code, but I cannot view the image in the browser.
- VirtualHost defined; mysite: set to /var/www/mysite
- $app['controllers']->requireHttps();
Description of the environment:
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, served with https:200 and viewed in browser; ok
- https:// mysite/files/file.jpg served with https:200 but not viewed in browser; ?
Here are the 3 methods tried:
Method 1: Silex sendFile() direct method >
$app->get('/files/{onefile}', function ($onefile) use ($app) {
// Validate authorization; if ok, then
return $app->sendFile('/var/www/mysite/tmp/' . $onefile);
});
Method 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'));
Method 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();
This is what Chrome presents:
With this Chrome image this is the Http (Https or not, same result) request
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
Other tests made to eliminate possible undesired behavior:
- I checked the BOM and made sure the php code responding to the request is valid
and do not have undesired byte-order marks (BOMs) using Emacs (
set-buffer-file-coding-system utf-8
). Furthermore, to avoid unknown BOM tagged files, I executed the following command in the mysite directory (grep -rl $'\xEF\xBB\xBF' .
). Nothing abnormal appeared.
UPDATE:
Looking at the files (image) received by the browser (save as
on each image), this is what the tool (Hex Friend) help me to find, but I still do not understand why:
Comparing the two files
- (one with success: mysite/tmp/file.jpg ; served directly by Apache)
- (one with NO success: mysite/files/file.jpg; served by a PHP script).
At the beginning of the binary file, I get this difference:
At the end of the binary file, I get this difference:
Question: How can I return an image (in stream or some other technique) with a php code, and view it in the browser ? All php code methods return the same output, I suspect an environment problem. Is there an environment setting that could produce the error I am experimenting ?