InaByDesign
asked on
php: How do I display binary data as an image (png) on a browser?
I am building a website for a corporation that would like to display a stock chart on one of its pages.
I am accessing a URL: http://www.stockwatch.com/webservice/CorporateServices.asmx/CorporateChart (username & password needed)
It returns an XML file where the tag ChartImage contains a png image.
The closest I have come to displaying it is to show a series of binary data on the browser:
Question: Would your code "translate" the binary data to png?
Here is my code so far:
mainpage.php (I have included 3 versions of trying to embed the data; the third one -include- returns binary data-)
------------------
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body >
<div id="wrapper">
<div class="main">
<div class="mainRight">
<H1>SHARE QUOTES AND CHARTS</H1>
<object type="image/png" data="../stock/chart.php" width="100" height="100"></object>
<img src="../stock/chart.php" width="420px" height="400px" border="1"/>
<?php include "../stock/chart.php" ?>
</div>
chart.php
------------
<?php //header('Content-type: image/png');
function value_in($element_name, $xml, $content_only = true) {
if ($xml == false) {
return false;
}
$found = preg_match('#<'.$element_n ame.'(?:\s +[^>]+)?>( .*?)'.
'</'.$element_name.'>#s', $xml, $matches);
if ($found != false) {
if ($content_only) {
return $matches[1]; //ignore the enclosing tags
} else {
return $matches[0]; //return the full pattern match
}
}
// No match found: return false.
return false;
}
$xml = file_get_contents('http://www.stockwatch.com/webservice/CorporateServices.asmx/CorporateChart?Id=xyz&Pw=123&pars=width=420%26ph=400%26ih=100%26npdivs=20%26bc=0xfefefe%26fc=0x007dd0%26tc=ox007dd0%26sf=a%26sfs=8');
$channel_ChartImage = value_in('ChartImage', $xml);
echo $channel_ChartImage;
?>
Thank you,
Ina
I am accessing a URL: http://www.stockwatch.com/webservice/CorporateServices.asmx/CorporateChart (username & password needed)
It returns an XML file where the tag ChartImage contains a png image.
The closest I have come to displaying it is to show a series of binary data on the browser:
Question: Would your code "translate" the binary data to png?
Here is my code so far:
mainpage.php (I have included 3 versions of trying to embed the data; the third one -include- returns binary data-)
------------------
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body >
<div id="wrapper">
<div class="main">
<div class="mainRight">
<H1>SHARE QUOTES AND CHARTS</H1>
<object type="image/png" data="../stock/chart.php" width="100" height="100"></object>
<img src="../stock/chart.php" width="420px" height="400px" border="1"/>
<?php include "../stock/chart.php" ?>
</div>
chart.php
------------
<?php //header('Content-type: image/png');
function value_in($element_name, $xml, $content_only = true) {
if ($xml == false) {
return false;
}
$found = preg_match('#<'.$element_n
'</'.$element_name.'>#s', $xml, $matches);
if ($found != false) {
if ($content_only) {
return $matches[1]; //ignore the enclosing tags
} else {
return $matches[0]; //return the full pattern match
}
}
// No match found: return false.
return false;
}
$xml = file_get_contents('http://www.stockwatch.com/webservice/CorporateServices.asmx/CorporateChart?Id=xyz&Pw=123&pars=width=420%26ph=400%26ih=100%26npdivs=20%26bc=0xfefefe%26fc=0x007dd0%26tc=ox007dd0%26sf=a%26sfs=8');
$channel_ChartImage = value_in('ChartImage', $xml);
echo $channel_ChartImage;
?>
Thank you,
Ina
ASKER
If I decode the binary data I still do not get a picture:
Data before encoding:
iVBORw0KGgoAAAANSUhEUgAAAa QAAAIfCAYA
...
6nfvmXtlf9pcPyAc+ xgc+RlF9bkKfm5APyAfkA1f7wP 8H9aWOxVfj Z80AAAAASU VORK5CYII=
Data after encoding:
ÿýPNG ýýý IHDRýýýýýýýý?ýýýýýsRGBýýýýýýýgAMAýýýýýaýýý cHRMýýz&ýýýýýýýýýýýýýýu0ýý ý`ýý:ýý
....
ýtý`ýýýý|ýCRýHýhýýýý@ýv &9ýfu)ý>; xýýýýýýmy÷ ýýý>ýý{ ý'ýtýLý{+ ýfuýýý^ý_ýý>ý>FQ}nBýýý ýýWýýýý ýWýgýýýýýI ENDýB`ý
Modified code:
<?php //header('Content-type: image/png');
function value_in($element_name, $xml, $content_only = true) {
if ($xml == false) {
return false;
}
$found = preg_match('#<'.$element_n ame.'(?:\s +[^>]+)?>( .*?)'.
'</'.$element_name.'>#s', $xml, $matches);
if ($found != false) {
if ($content_only) {
return $matches[1]; //ignore the enclosing tags
} else {
return $matches[0]; //return the full pattern match
}
}
// No match found: return false.
return false;
}
$xml = file_get_contents('http://www.stockwatch.com/webservice/CorporateServices.asmx/CorporateChart?Id=AeroplanXML&Pw=1000842&pars=width=420%26ph=400%26ih=100%26npdivs=20%26bc=0xfefefe%26fc=0x007dd0%26tc=ox007dd0%26sf=a%26sfs=8');
$channel_ChartImage = value_in('ChartImage', $xml);
$image_64 = base64_decode($channel_Cha rtImage);
echo $image_64;
?>
Data before encoding:
iVBORw0KGgoAAAANSUhEUgAAAa
...
6nfvmXtlf9pcPyAc+ xgc+RlF9bkKfm5APyAfkA1f7wP
Data after encoding:
ÿýPNG ýýý IHDRýýýýýýýý?ýýýýýsRGBýýýýýýýgAMAýýýýýaýýý cHRMýýz&ýýýýýýýýýýýýýýu0ýý
....
ýtý`ýýýý|ýCRýHýhýýýý@ýv
Modified code:
<?php //header('Content-type: image/png');
function value_in($element_name, $xml, $content_only = true) {
if ($xml == false) {
return false;
}
$found = preg_match('#<'.$element_n
'</'.$element_name.'>#s', $xml, $matches);
if ($found != false) {
if ($content_only) {
return $matches[1]; //ignore the enclosing tags
} else {
return $matches[0]; //return the full pattern match
}
}
// No match found: return false.
return false;
}
$xml = file_get_contents('http://www.stockwatch.com/webservice/CorporateServices.asmx/CorporateChart?Id=AeroplanXML&Pw=1000842&pars=width=420%26ph=400%26ih=100%26npdivs=20%26bc=0xfefefe%26fc=0x007dd0%26tc=ox007dd0%26sf=a%26sfs=8');
$channel_ChartImage = value_in('ChartImage', $xml);
$image_64 = base64_decode($channel_Cha
echo $image_64;
?>
The 'PNG' at the start of the decoded data indicates that the conversion was correct.
You need to un-comment the first line:
header('Content-type: image/png');
You need to un-comment the first line:
header('Content-type: image/png');
ASKER
I still do not get an image:
The output on the browser is the following:
from <img src="../images/layout/clea r.gif" width="100%" height="18px" /> ==> nothing
from <object type="image/png" data="../stock/chart.php" width="100" height="100"></object> ==> nothing
from <img src="../stock/chart.php" width="420px" height="400px" border="1"/> ==> empty box in FF
from <?php include "../stock/chart.php" ?> ==> the following in FF: ÿ
Warning: Cannot modify header information - headers already sent by (output started at E:\XAMPP\htdocs\aeroplan\g a\pages\in vQuote.php :8) in E:\XAMPP\htdocs\aeroplan\g a\stock\ch art.php on line 1
ýPNG ýýý IHDRýýýýýýýý?ýýýýýsRGBýýýýýýýgAMAýýýýýaýýý
the following in IE7: Warning: Cannot modify header information - headers already sent by (output started at E:\XAMPP\htdocs\aeroplan\g a\pages\in vQuote.php :8) in E:\XAMPP\htdocs\aeroplan\g a\stock\ch art.php on line 1
ýPNG IHDRý?ýýsRGBýýýgAMAýý ýa cHRMz&ýýýýýu0ý`:ýpýýQ<`ýI DATx^ýýaý$ )ýlý-ýýaýý |ýý"ýýýýý ýý
The output on the browser is the following:
from <img src="../images/layout/clea
from <object type="image/png" data="../stock/chart.php" width="100" height="100"></object> ==> nothing
from <img src="../stock/chart.php" width="420px" height="400px" border="1"/> ==> empty box in FF
from <?php include "../stock/chart.php" ?> ==> the following in FF: ÿ
Warning: Cannot modify header information - headers already sent by (output started at E:\XAMPP\htdocs\aeroplan\g
ýPNG ýýý IHDRýýýýýýýý?ýýýýýsRGBýýýýýýýgAMAýýýýýaýýý
the following in IE7: Warning: Cannot modify header information - headers already sent by (output started at E:\XAMPP\htdocs\aeroplan\g
ýPNG IHDRý?ýýsRGBýýýgAMAýý ýa cHRMz&ýýýýýu0ý`:ýpýýQ<`ýI
Use only <img src="../stock/chart.php" width="420px" height="400px" border="1"/> in your html, remove the <object> element and the PHP include. The latter is probably the cause of the warning.
There seems to be a space in the base64 data provided above, before the decoding, it should not be there...
Try using the below function to check if the bas64 encoded data is valid. Insert the comment on the header() function again, and run/include chart.php to see the output.
There seems to be a space in the base64 data provided above, before the decoding, it should not be there...
Try using the below function to check if the bas64 encoded data is valid. Insert the comment on the header() function again, and run/include chart.php to see the output.
function is_base64_encoded($data) {
return preg_match('%^[a-zA-Z0-9/+]*={0,2}$%', $data));
}
$channel_ChartImage = value_in('ChartImage', $xml);
echo is_base64_encoded($channel_ChartImage) ?
'This is a valid base64 string':
'This is NOT valid base64';
Btw, the correct <img> should be like this, no "px" and no border attribute, but you need an alt attribute (mandatory according to html spec):
<img src="../stock/chart.php" width="420" height="400" alt="Bad image data" />
ASKER
When I ran the function preg_match I get "This is a valid base64 string" ==> so that is good
No image yet:
mainpage.php
------------------
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body >
<div id="wrapper">
<div class="main">
<div class="mainRight">
<H1>SHARE QUOTES AND CHARTS</H1>
<img src="../stock/chart.php" width="420px" height="400px" border="1"/>
</div>
<!--class main -->
</div><!--class wrapper -->
</html>
<?php header('Content-type: image/png');
function is_base64_encoded($data) {
return preg_match('%^[a-zA-Z0-9/+ ]*={0,2}$% ', $data);
}
function value_in($element_name, $xml, $content_only = true) {
if ($xml == false) {
return false;
}
$found = preg_match('#<'.$element_n ame.'(?:\s +[^>]+)?>( .*?)'.
'</'.$element_name.'>#s', $xml, $matches);
if ($found != false) {
if ($content_only) {
return $matches[1]; //ignore the enclosing tags
} else {
return $matches[0]; //return the full pattern match
}
}
// No match found: return false.
return false;
}
$channel_ChartImage = value_in('ChartImage', $xml);
//echo is_base64_encoded($channel _ChartImag e) ?
// 'This is a valid base64 string':
// 'This is NOT valid base64';
$xml = file_get_contents('http://www.stockwatch.com/webservice/CorporateServices.asmx/CorporateChart?Id=ABC&Pw=123&pars=width=420%26ph=400%26ih=100%26npdivs=20%26bc=0xfefefe%26fc=0x007dd0%26tc=ox007dd0%26sf=a%26sfs=8');
$channel_ChartImage = value_in('ChartImage', $xml);
$image_64 = base64_decode($channel_Cha rtImage);
echo $image_64;
?>
No image yet:
mainpage.php
------------------
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body >
<div id="wrapper">
<div class="main">
<div class="mainRight">
<H1>SHARE QUOTES AND CHARTS</H1>
<img src="../stock/chart.php" width="420px" height="400px" border="1"/>
</div>
<!--class main -->
</div><!--class wrapper -->
</html>
<?php header('Content-type: image/png');
function is_base64_encoded($data) {
return preg_match('%^[a-zA-Z0-9/+
}
function value_in($element_name, $xml, $content_only = true) {
if ($xml == false) {
return false;
}
$found = preg_match('#<'.$element_n
'</'.$element_name.'>#s', $xml, $matches);
if ($found != false) {
if ($content_only) {
return $matches[1]; //ignore the enclosing tags
} else {
return $matches[0]; //return the full pattern match
}
}
// No match found: return false.
return false;
}
$channel_ChartImage = value_in('ChartImage', $xml);
//echo is_base64_encoded($channel
// 'This is a valid base64 string':
// 'This is NOT valid base64';
$xml = file_get_contents('http://www.stockwatch.com/webservice/CorporateServices.asmx/CorporateChart?Id=ABC&Pw=123&pars=width=420%26ph=400%26ih=100%26npdivs=20%26bc=0xfefefe%26fc=0x007dd0%26tc=ox007dd0%26sf=a%26sfs=8');
$channel_ChartImage = value_in('ChartImage', $xml);
$image_64 = base64_decode($channel_Cha
echo $image_64;
?>
Change your <img> tag, include an alt attribute. Is the value of the alt attribute output where the image should have been?
There is a missing </div> in your html, but that is not the reason for your problem.
Make sure there is no newline after the ?> in chart.php.
Try adding this before the echo statement:
There is a missing </div> in your html, but that is not the reason for your problem.
Make sure there is no newline after the ?> in chart.php.
Try adding this before the echo statement:
header('Content-Length: '.strlen($image_64;));
Sorry, one ; too much:
header('Content-Length: '.strlen($image_64));
A blank line before <?php will break the image, make sure <?php is on the very first line of chart.php.
ASKER
No, still nothing, but it displays 'chart data' thanks to the alt tag
Change your <img> tag, include an alt attribute. Is the value of the alt attribute output where the image should have been?
==> <img src="../stock/chart.php" width="420" height="400" alt="chart data" />
There is a missing </div> in your html, but that is not the reason for your problem.
==> thanks fixed it
Make sure there is no newline after the ?> in chart.php.
==> no newline; ?> is the last item
Try adding this before the echo statement:
==> done:
<?php header('Content-type: image/png');
function is_base64_encoded($data) {
return preg_match('%^[a-zA-Z0-9/+ ]*={0,2}$% ', $data);
}
function value_in($element_name, $xml, $content_only = true) {
if ($xml == false) {
return false;
}
$found = preg_match('#<'.$element_n ame.'(?:\s +[^>]+)?>( .*?)'.
'</'.$element_name.'>#s', $xml, $matches);
if ($found != false) {
if ($content_only) {
return $matches[1]; //ignore the enclosing tags
} else {
return $matches[0]; //return the full pattern match
}
}
// No match found: return false.
return false;
}
$channel_ChartImage = value_in('ChartImage', $xml);
$xml = file_get_contents('http://www.stockwatch.com/webservice/CorporateServices.asmx/CorporateChart?Id=abc&Pw=123&pars=width=420%26ph=400%26ih=100%26npdivs=20%26bc=0xfefefe%26fc=0x007dd0%26tc=ox007dd0%26sf=a%26sfs=8');
$channel_ChartImage = value_in('ChartImage', $xml);
$image_64 = base64_decode($channel_Cha rtImage);
header('Content-Length: '.strlen($image_64));
echo $image_64;
?>
Change your <img> tag, include an alt attribute. Is the value of the alt attribute output where the image should have been?
==> <img src="../stock/chart.php" width="420" height="400" alt="chart data" />
There is a missing </div> in your html, but that is not the reason for your problem.
==> thanks fixed it
Make sure there is no newline after the ?> in chart.php.
==> no newline; ?> is the last item
Try adding this before the echo statement:
==> done:
<?php header('Content-type: image/png');
function is_base64_encoded($data) {
return preg_match('%^[a-zA-Z0-9/+
}
function value_in($element_name, $xml, $content_only = true) {
if ($xml == false) {
return false;
}
$found = preg_match('#<'.$element_n
'</'.$element_name.'>#s', $xml, $matches);
if ($found != false) {
if ($content_only) {
return $matches[1]; //ignore the enclosing tags
} else {
return $matches[0]; //return the full pattern match
}
}
// No match found: return false.
return false;
}
$channel_ChartImage = value_in('ChartImage', $xml);
$xml = file_get_contents('http://www.stockwatch.com/webservice/CorporateServices.asmx/CorporateChart?Id=abc&Pw=123&pars=width=420%26ph=400%26ih=100%26npdivs=20%26bc=0xfefefe%26fc=0x007dd0%26tc=ox007dd0%26sf=a%26sfs=8');
$channel_ChartImage = value_in('ChartImage', $xml);
$image_64 = base64_decode($channel_Cha
header('Content-Length: '.strlen($image_64));
echo $image_64;
?>
hm... try running chart.php directly in the browser. Still no image output?
Try writing the data to a file, and check if the file is a valid png file, i.e. if it is viewable.
Try writing the data to a file, and check if the file is a valid png file, i.e. if it is viewable.
$image_64 = base64_decode($channel_ChartImage);
$f = fopen('test_chart.png','w');
fwrite($f,$image_64);
fclose($f);
ASKER
It DID create the file test_chart.png successfully.
It opens fine, is viewable and is exactly as should be.
It opens fine, is viewable and is exactly as should be.
ok, thats good.
Check the image src attribute, is the path "../stock/chart.php" correct? If chart.php is in the same directory as the html page, it should be only "chart.php".
Check the image src attribute, is the path "../stock/chart.php" correct? If chart.php is in the same directory as the html page, it should be only "chart.php".
ASKER
It is not in the same directory, the path is correct.
Can you post your current chart.php as an attachment? I'll replace file_get_contents() with some local png file I have, and check if it will run for me.
ASKER
Here you go!
chart.php.txt
chart.php.txt
Why is the Content-Length header at the start? That won't work, the $image_64 is not defined yet. This header must come after this line:
$image_64 = base64_decode($channel_Cha rtImage);
Also, you must remove the file writing and include the echo... try this:
$image_64 = base64_decode($channel_Cha
Also, you must remove the file writing and include the echo... try this:
<?php
header('Content-type: image/png');
function value_in($element_name, $xml, $content_only = true) {
if ($xml == false) {
return false;
}
$found = preg_match('#<'.$element_name.'(?:\s+[^>]+)?>(.*?)'.
'</'.$element_name.'>#s', $xml, $matches);
if ($found != false) {
if ($content_only) {
return $matches[1]; //ignore the enclosing tags
} else {
return $matches[0]; //return the full pattern match
}
}
// No match found: return false.
return false;
}
$xml = file_get_contents('url goes here');
$channel_ChartImage = value_in('ChartImage', $xml);
$image_64 = base64_decode($channel_ChartImage);
header('Content-Length: '.strlen($image_64));
echo $image_64;
?>
ASKER
no... it did not work
Did you remember to replace 'url goes here' with the actual url?
ASKER
yes, and I am attaching the 'calling' php
main.php.txt
main.php.txt
I think this part is ok. When you run chart.php directly in the browser, you should get the image.
I think it is very strange, writing $image_64 to a file results in a valid png file, but echoing it does not...
If you remove the content-type header again and call chart.php directly in the browser, do you se "rubbish" with PNG at the start? Or just a blank screen?
I think it is very strange, writing $image_64 to a file results in a valid png file, but echoing it does not...
If you remove the content-type header again and call chart.php directly in the browser, do you se "rubbish" with PNG at the start? Or just a blank screen?
ASKER
No I do not get the image.
I removed both headers, otherwise I get warnings.
I removed both headers, otherwise I get warnings.
Without the headers, it shouldn't output an image.
If you remove the headers and call chart.php DIRECTLY in the browser, do you se "rubbish" with PNG at the start? Or just a blank screen?
If you remove the headers and call chart.php DIRECTLY in the browser, do you se "rubbish" with PNG at the start? Or just a blank screen?
ASKER
"rubbish" with PNG at the start:
ýPNG ýýý IHDRýýýýýýýý?ýýýýýsRGBýýýýýýýgAMAýýýýýaýýý cHRMýýz&ýýýýýýýýýýýýýýu0ýý ý`ýý:ýýýp ýýQ<ýý`ýID ATx^ýaý$)ý lý-ýýaýý| ýý"ýýýýýý ýsýLW8ýýý pýýýýýýý ýýý, ýýýýýý'ýýýýýý ýýýýýýOýý|@> ýýýH@ýýv>SýýýýLýý\lýý»ýVýu6ýý^}ý2cýýýýýýýYý
ýPNG ýýý IHDRýýýýýýýý?ýýýýýsRGBýýýýýýýgAMAýýýýýaýýý cHRMýýz&ýýýýýýýýýýýýýýu0ýý
ok, thats good. That means we probably have the correct data, we just have problems outputting it correctly.
I'm running out of ideas here, so I am thinking about a work-around.
What if you create a file, and the <img> references the png file directly? You could check the age of the file, and re-create it every x minutes, depending on how often the data returned from the web service changes. You could include the company id in the file name. This would also ease the burden on the server. Is this a feasable approach?
I'm running out of ideas here, so I am thinking about a work-around.
What if you create a file, and the <img> references the png file directly? You could check the age of the file, and re-create it every x minutes, depending on how often the data returned from the web service changes. You could include the company id in the file name. This would also ease the burden on the server. Is this a feasable approach?
ASKER
If we can successfully create a file and then read it can we not somehow bypass that step and show the result on the screen?
The following code works, but I how does writing to a file withstand heavy traffic?:
The following code works, but I how does writing to a file withstand heavy traffic?:
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
I just found out that the chart needs to be updated only once a day!
There is only one company and only one chart.
So your solution (which started as a workaround) is better than what I wanted to implement in the first place.
Writing to a file once a day has to be less work for the server than the combination of accessing the web service, parsing the xml and base64-decoding it EVERY time.
Thank you and you deserve your points!
There is only one company and only one chart.
So your solution (which started as a workaround) is better than what I wanted to implement in the first place.
Writing to a file once a day has to be less work for the server than the combination of accessing the web service, parsing the xml and base64-decoding it EVERY time.
Thank you and you deserve your points!
ASKER
Thank you very much!
This was a rush job and I really appreciate your help.
This was a rush job and I really appreciate your help.
http://se2.php.net/manual/en/function.base64-decode.php