5

I'm writing simple php proxy and I have trouble displaying png file, the output is

enter image description here

and it should be:

enter image description here

The images are opened in Notepad++. My php curl code look like this:

$ua = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_USERAGENT, $ua);
curl_setopt($ch, CURLOPT_HEADER_OUT, 1);
curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);
$content = curl_exec($ch);
$info = curl_getinfo($ch);
header('Content-Type:' . $info['content_type']);
echo $content

I try with and without CURLOPT_BINARYTRANSFER the output is the same and the image is not displaying. How can I display the image?

EDIT: when I'm saving the data to the file and redirect using Location header the image is displayed correctly:

$file = fopen('proxy_tmp~', 'w');
fwrite($file, $content);
fclose($file);
header('Location: ' . DIR . 'proxy_tmp~');

EDIT 2: I had gzip compression, bu when I disabled it I have the same issue, when I open both files in Notepad++ one is DOS/Windows ANSI (original) and the other is DOS/Windows UTF-8 (the file opened by a script). When I open a file in Notepad and change encoding to ANSI and save the file, everything is ok.

EDIT 3: I think I did the same thing on GNU/Linux but without CURLOPT_BINARYTRANSFER option and it's working fine, here is my project https://github.com/jcubic/yapp. I've also test it on Windows 10 with Wamp and also work fine.

jcubic
  • 61,973
  • 54
  • 229
  • 402

7 Answers7

1

Here is how to send the file directly back to the user for download (uses your $content var):

$file_array = explode("\n\r", $content, 2);
$header_array = explode("\n", $file_array[0]);
foreach($header_array as $header_value) {
$header_pieces = explode(':', $header_value);
  if(count($header_pieces) == 2) {
    $headers[$header_pieces[0]] = trim($header_pieces[1]);
  }
}
header('Content-type: ' . $headers['Content-Type']);
header('Content-Disposition: ' . $headers['Content-Disposition']);
echo substr($file_array[1], 1);

There is a full example here:

http://ryansechrest.com/2012/07/send-and-receive-binary-files-using-php-and-curl/

timstermatic
  • 1,710
  • 14
  • 32
  • I don't want send a file for download, I want to display the image directly because I'm creating a proxy where I'm changing the url of the images on the page. I'm simple get different data then when I'm load the file directly without my script. – jcubic Jul 08 '13 at 07:46
1

never use the 'w' mode. it means the "text mode", because the default is, unfortunately, text mode.

on Windows, "text mode" means: whenever you try to write an \n byte (ascii 10, newline) and it's not preceded by an \r byte (ascii 13, carriage-return), insert an \r byte before writing the \n byte. (it also means text mode on linux/modern MacOS, but on Linux/modern MacOS, the text mode does absolutely nothing and is treated the same way as binary mode. * not true for classic MacOS <=9 from <=2001, on Classic MacOS, text mode did weird shit like it does weird shit on Windows)

always use the binary mode, eg wb, to make your program portable across both Windows and Linux

(actually modern versions of PHP automatically convert it to binary mode when not specified, but this question was asked in 2013, and this is still a very important rule-of-thumb if you ever use any other language than PHP. if you actually want text mode, explicitly enable text mode with wt, but you pretty much never want text mode, it's a horrible thing, made worse by the fact that it's the default mode for the underlying fopen() C api.. it's so horrible in fact, that Linux never supported it at all, and Apple/MacOS dropped support in 2001 with the release of MacOS X.. AFAIK Windows is the last major OS to actually support it, somethingsomething backwards-compatibility )

hanshenrik
  • 19,904
  • 4
  • 43
  • 89
0

Which php version are you using? Are you above PHP version 5.1.3? Then the CURLOPT_BINARYTRANSFER will have no effect.

Source: http://php.net/manual/en/function.curl-setopt.php

Looking at the file, you should add the following header to you're page:

header('Content-Type: image/png');
Benz
  • 2,317
  • 12
  • 19
  • I use `header('Content-Type:' . $info['content_type']);` which will be image/png if the server send that header. I'm using php 5.2.17. – jcubic Jul 08 '13 at 07:44
  • Which header is in the $info['content_type']? – Benz Jul 08 '13 at 07:52
  • Content type of the response from the server. if server return `image/png` then `$info['content_type']` will be `image/png` http://pl1.php.net/manual/en/function.curl-getinfo.php . the content type is ok I get different data then when I open a file directly without a script. – jcubic Jul 08 '13 at 08:18
  • After searching for a while I found the following function to be used over and over again, can you try to add the following line to you're code (after $content/$info) $content = imagecreatefromstring($content); – Benz Jul 08 '13 at 08:53
  • I use `if (preg_match('/image/', $info['content_type'])) { $image = imagecreatefromstring($content); header('Content-Type: image/png'); imagepng($image); imagedestroy($image); }` but the image is not displayed. – jcubic Jul 08 '13 at 10:28
0

I have used following with basic header authentication.. used postman to get auth key

// key : > converted to basic auth

// Content type
header('Content-Type: image/jpeg');

$url = 'http://com.com.com/api/images/products/264/7971';
$headers = array(
    'Content-Type: image/png',
    'Authorization: Basic @#$%@#$%@#$%@#$%@#$%@#$%' );

$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
//curl_setopt($ch, CURLOPT_USERPWD, "$login:$password");
$file = curl_exec($ch);
curl_close($ch);  
//echo($result);

// create image from output of the screen
$img = @imagecreatefromstring($file);

if ($img === false) {
    echo $file;
    exit;
}

$width = imagesx($img);
$height = imagesy($img);

$newWidth = 300;

$ratio = $newWidth / $width;
$newHeight = $ratio * $height;


$resized = @imagecreatetruecolor($newWidth, $newHeight);

if ($resized === false) {
    echo $file;
    exit;
}

$quality = 90;

if (@imagecopyresampled($resized, $img, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height)) {
    @imagejpeg($resized, NULL, $quality);
} else {
    echo $file;
}
Vinod Joshi
  • 7,696
  • 1
  • 50
  • 51
0

Use $content_arr = explode("\r\n\r\n",$content,2); to divide the content into headers and body, set the image/png header and then do echo trim($content_arr[1]); to get rid of spaces or blank lines that prevent the browser from being able to read the image.

George
  • 1
  • 1
0

In my case adding Content-Length header fixed problems with binary files proxy.

Cezary Daniel Nowak
  • 1,096
  • 13
  • 21
0

I have this issue, even if I read png content from disk (file_get_contents function). One php source file's encoding was UTF-8 with signature and that was the source of "my" problem.

So I remove the signature with Notepad2. There is option to change file encoding.

  • How did you fix it? You've explained a mechanism for something that might be related to the question, but haven't provided the solution you used. – Jason Aller Mar 25 '20 at 16:01