417 lines
16 KiB
PHP
417 lines
16 KiB
PHP
<?php
|
|
|
|
################################################################################
|
|
#
|
|
# Favicon Class (work with favicons), ver. 1.0, June, 2006.
|
|
#
|
|
# (c) 2006 ControlStyle Company. All rights reserved.
|
|
# Developped by Nikolay I. Yarovoy, Dmitry V. Domojilov.
|
|
#
|
|
# http://www.controlstyle.com
|
|
# info@controlstyle.com
|
|
#
|
|
################################################################################
|
|
|
|
class favicon
|
|
{
|
|
var $ver = '1.1';
|
|
var $site_url = ''; # url of site
|
|
var $if_modified_since = 0; # cache
|
|
var $is_not_modified = false;
|
|
var $ico_type = 'ico'; # ico, gif or png only
|
|
var $ico_url = ''; # full uri to favicon
|
|
var $ico_exists = 'not checked'; # no comments
|
|
var $ico_data = ''; # ico binary data
|
|
var $output_data = ''; # output image binary data
|
|
|
|
# main proc
|
|
function favicon($site_url, $if_modified_since = 0)
|
|
{
|
|
$site_url = trim(str_replace('http://', '', trim($site_url)), '/');
|
|
$site_url = explode('/', $site_url);
|
|
$site_url = 'http://' . $site_url[0] . '/';
|
|
$this->site_url = $site_url;
|
|
$this->if_modified_since = $if_modified_since;
|
|
$this->get_ico_url();
|
|
$this->is_ico_exists();
|
|
$this->get_ico_data();
|
|
}
|
|
|
|
# get uri of favicon
|
|
function get_ico_url()
|
|
{
|
|
if ($this->ico_url == '')
|
|
{
|
|
$this->ico_url = $this->site_url . 'favicon.ico';
|
|
|
|
# get html of page
|
|
$h = @fopen($this->site_url, 'r');
|
|
if ($h)
|
|
{
|
|
$html = '';
|
|
while (!feof($h) and !preg_match('/<([s]*)body([^>]*)>/i', $html))
|
|
{
|
|
$html .= fread($h, 200);
|
|
}
|
|
fclose($h);
|
|
|
|
# search need <link> tag
|
|
if (preg_match('/<([^>]*)link([^>]*)(rel="icon"|rel="shortcut icon")([^>]*)>/iU', $html, $out))
|
|
{
|
|
|
|
$link_tag = $out[0];
|
|
if (preg_match('/href([s]*)=([s]*)"([^"]*)"/iU', $link_tag, $out))
|
|
{
|
|
$this->ico_type = (!(strpos($link_tag, 'png')===false)) ? 'png' : 'ico';
|
|
$ico_href = trim($out[3]);
|
|
if (strpos($ico_href, 'http://')===false)
|
|
{
|
|
$ico_href = rtrim($this->site_url, '/') . '/' . ltrim($ico_href, '/');
|
|
}
|
|
$this->ico_url = $ico_href;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return $this->ico_url;
|
|
}
|
|
|
|
# check that favicon is exists
|
|
function is_ico_exists()
|
|
{
|
|
if ($this->ico_exists=='not checked')
|
|
{
|
|
$h = @fopen($this->ico_url, 'r');
|
|
$this->ico_exists = ($h) ? true : false;
|
|
if ($h) fclose($h);
|
|
}
|
|
return $this->ico_exists;
|
|
}
|
|
|
|
# get ico data
|
|
function get_ico_data()
|
|
{
|
|
if ($this->ico_data=='' && $this->ico_url!='' && $this->ico_exists && !$this->is_not_modified)
|
|
{
|
|
# get ico data
|
|
$ico_z = parse_url($this->ico_url);
|
|
$ico_path = $ico_z['path'];
|
|
$ico_host = $ico_z['host'];
|
|
$ico_ims = gmdate('D, d M Y H:i:s', $this->if_modified_since) . ' GMT';
|
|
|
|
$fp = @fsockopen($ico_host, 80);
|
|
if ($fp)
|
|
{
|
|
$out = "GET {$ico_path} HTTP/1.1\r\n";
|
|
$out .= "Host: {$ico_host}\r\n";
|
|
$out .= "User-Agent=Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3\r\n";
|
|
$out .= "If-Modified-Since: {$ico_ims}\r\n";
|
|
$out .= "Connection: Close\r\n\r\n";
|
|
fwrite($fp, $out);
|
|
$data = '';
|
|
while (!feof($fp)) $data .= fgets($fp, 128);
|
|
fclose($fp);
|
|
$response = substr($data, 0, 15);
|
|
$this->is_not_modified = !(strpos($response, '304')===false);
|
|
if ($this->is_not_modified)
|
|
{
|
|
$this->ico_data = 'not modified';
|
|
}
|
|
else
|
|
{
|
|
$data = explode("\r\n\r\n", $data);
|
|
if (count($data)>0)
|
|
{
|
|
unset($data[0]);
|
|
$this->ico_data = implode("\r\n\r\n", $data);
|
|
}
|
|
}
|
|
$this->output_data = '';
|
|
}
|
|
}
|
|
return $this->ico_data;
|
|
}
|
|
|
|
# get output data
|
|
function get_output_data()
|
|
{
|
|
if ($this->output_data=='')
|
|
{
|
|
if ($this->ico_data=='not modified')
|
|
{
|
|
# icon is not modified since defined time
|
|
$this->output_data = 'not modified';
|
|
}
|
|
elseif($this->ico_data=='')
|
|
{
|
|
# error(s) in getting icon data
|
|
$this->output_data = $this->empty_png();
|
|
}
|
|
else
|
|
{
|
|
# convert ico to png, gif & return
|
|
if (substr($this->ico_data, 0, 3)==='GIF') $this->ico_type = 'gif';
|
|
$this->output_data = $this->ico_data;
|
|
if ($this->ico_type==='ico')
|
|
{
|
|
$this->output_data = $this->ico2png($this->output_data);
|
|
}
|
|
if ($this->ico_type==='gif')
|
|
{
|
|
$this->output_data = $this->gif2png($this->output_data);
|
|
}
|
|
}
|
|
}
|
|
return $this->output_data;
|
|
}
|
|
|
|
# if error or icon is not found we output empty png image
|
|
function empty_png()
|
|
{
|
|
$res = '';
|
|
$im = imagecreatetruecolor(16, 16);
|
|
$color = imagecolorallocate($im, 255, 255, 255);
|
|
imagefill($im, 1, 1, $color);
|
|
|
|
# output png
|
|
ob_start();
|
|
|
|
# imagesavealpha($im, true);
|
|
imagepng($im);
|
|
imagedestroy($im);
|
|
$res = ob_get_clean();
|
|
return $res;
|
|
}
|
|
|
|
# Convert gif to png function,
|
|
# support gif-functions by GD is needed
|
|
function gif2png($gif)
|
|
{
|
|
$im2 = imagecreatefromstring($gif);
|
|
|
|
# background alpha is disabled because IE 5.5 + have bug with alpha-channels
|
|
# by default background color is white
|
|
# imagealphablending($im, false);
|
|
# imagefilledrectangle($im, 0, 0, 16, 16, $color);
|
|
# imagealphablending($im, true);
|
|
$im = imagecreatetruecolor(16, 16);
|
|
$color = imagecolorallocate($im, 255, 255, 255);
|
|
imagefill($im, 1, 1, $color);
|
|
imagecopy($im, $im2, 0, 0, 0, 0, 16, 16);
|
|
|
|
# output png
|
|
ob_start();
|
|
# imagesavealpha($im, true);
|
|
imagepng($im);
|
|
imagedestroy($im);
|
|
imagedestroy($im2);
|
|
$res = ob_get_clean();
|
|
return $res;
|
|
}
|
|
|
|
# Convert ico to png function,
|
|
# information about ico format is accessible on a site http://kainsk.tomsk.ru/g2003/sys26/oswin.htm,
|
|
function ico2png($ico)
|
|
{
|
|
$res = '';
|
|
|
|
while(!isset($tmp))
|
|
{
|
|
$tmp = '';
|
|
|
|
# get ICONDIR struct & check that it is correct ico format
|
|
$icondir = unpack('sidReserved/sidType/sidCount', substr($ico, 0, 6));
|
|
if ($icondir['idReserved']!=0 || $icondir['idType']!=1 || $icondir['idCount']<1) break;
|
|
$icondir['idEntries'] = array();
|
|
$entry = array();
|
|
for($i=0; $i<$icondir['idCount']; $i++)
|
|
{
|
|
$entry = unpack('CbWidth/CbHeight/CbColorCount/CbReserved/swPlanes/swBitCount/LdwBytesInRes/LdwImageOffset', substr($ico, 6 + $i*16, 16));
|
|
$icondir['idEntries'][] = $entry;
|
|
}
|
|
|
|
# select need icon & get it raw data
|
|
$iconres = '';
|
|
$bpx = 1; # bits per pixel
|
|
$idx = 0; # index of need icon
|
|
foreach($icondir['idEntries'] as $k=>$entry)
|
|
{
|
|
if ($entry['bWidth']==16 && isset($entry['swBitCount']) && $entry['swBitCount']>$bpx && $entry['swBitCount']<33)
|
|
{
|
|
$idx = $k;
|
|
$bpx = $entry['swBitCount'];
|
|
}
|
|
}
|
|
$iconres = substr($ico, $icondir['idEntries'][$idx]['dwImageOffset'], $icondir['idEntries'][$idx]['dwBytesInRes']);
|
|
unset($ico);
|
|
unset($icondir);
|
|
|
|
# getting bitmap info
|
|
$bitmap_info = array();
|
|
$bitmap_info['header'] = unpack('LbiSize/LbiWidth/LbiHeight/SbiPlanes/SbiBitCount/LbiCompression/LbiSizeImage/LbiXPelsPerMeter/LbiYPelsPerMeter/LbiClrUsed/LbiClrImportant',
|
|
substr($iconres, 0, 40));
|
|
|
|
$bitmap_info['header']['biHeight'] = $bitmap_info['header']['biHeight'] / 2;
|
|
$number_color = 0;
|
|
|
|
if ($bitmap_info['header']['biBitCount'] > 16)
|
|
{
|
|
$number_color = 0;
|
|
$sizecolor = $bitmap_info['header']['biWidth']*$bitmap_info['header']['biBitCount'] * $bitmap_info['header']['biHeight'] / 8;
|
|
}
|
|
elseif ( $bitmap_info['header']['biBitCount'] < 16)
|
|
{
|
|
$number_color = (int) pow(2, $bitmap_info['header']['biBitCount']);
|
|
$sizecolor = $bitmap_info['header']['biWidth']*$bitmap_info['header']['biBitCount'] * $bitmap_info['header']['biHeight'] / 8;
|
|
if ($bitmap_info['header']['biBitCount']=='1') $sizecolor = $sizecolor * 2;
|
|
}
|
|
else return $res;
|
|
|
|
$rgb_table_size = 4 * $number_color;
|
|
for($i=0; $i<$number_color; $i++)
|
|
{
|
|
$bitmap_info['colors'][] = unpack('CrgbBlue/CrgbGreen/CrgbRed/CrgbReserved', substr($iconres, 40 + $i*4, 4));
|
|
}
|
|
$current_offset = 40 + $number_color * 4;
|
|
|
|
$arraycolor = array();
|
|
|
|
for($i=0; $i<$sizecolor; $i++)
|
|
{
|
|
$value = unpack('Cvalue', substr($iconres, $current_offset, 1));
|
|
$arraycolor[] = $value['value'];
|
|
$current_offset++;
|
|
}
|
|
|
|
# background alpha is disabled because IE 5.5 + have bug with alpha-channels
|
|
# by default background color is white
|
|
# imagealphablending($im, false);
|
|
# imagefilledrectangle($im, 0, 0, 16, 16, $color);
|
|
# imagealphablending($im, true);
|
|
$im = imagecreatetruecolor(16, 16);
|
|
$color = imagecolorallocate($im, 255, 255, 255);
|
|
imagefill($im, 1, 1, $color);
|
|
|
|
# getting mask
|
|
$alpha = '';
|
|
for($i=0; $i<16; $i++)
|
|
{
|
|
$z = unpack('Cx/Cy', substr($iconres, $current_offset, 2));
|
|
$z = str_pad(decbin($z['x']), 8, '0', STR_PAD_RIGHT) . str_pad(decbin($z['y']), 8, '0', STR_PAD_LEFT);
|
|
$alpha .= $z;
|
|
$current_offset = $current_offset + 4;
|
|
}
|
|
|
|
# drawing image
|
|
$ico_size = 16;
|
|
$off = 0; # range (0-255)
|
|
|
|
# cases for different color depth
|
|
switch ($bitmap_info['header']['biBitCount'])
|
|
{
|
|
|
|
###################### for 32 bit icons ######################
|
|
case 32:
|
|
for($y=0; $y<$ico_size; $y++)
|
|
{
|
|
for($x=0; $x<$ico_size; $x++)
|
|
{
|
|
$a = round((255-$arraycolor[$off*4+3])/2);
|
|
$a = ($a<0) ? 0 : $a;
|
|
$a = ($a>127) ? 127 : $a;
|
|
$color = imagecolorallocatealpha($im, $arraycolor[$off*4+2], $arraycolor[$off*4+1], $arraycolor[$off*4], $a);
|
|
imagesetpixel($im, $x, $ico_size-1-$y, $color);
|
|
$off++;
|
|
}
|
|
}
|
|
break;
|
|
|
|
###################### for 24 bit icons ######################
|
|
case 24:
|
|
for($y=0; $y<$ico_size; $y++)
|
|
{
|
|
for($x=0; $x<$ico_size; $x++)
|
|
{
|
|
$valpha = ($alpha[$off]=='1') ? 127 : 0;
|
|
$color = imagecolorallocatealpha($im, $arraycolor[$off*3+2], $arraycolor[$off*3+1], $arraycolor[$off*3], $valpha);
|
|
imagesetpixel ($im, $x, $ico_size-1-$y, $color);
|
|
$off++;
|
|
}
|
|
}
|
|
break;
|
|
|
|
###################### for 08 bit icons ######################
|
|
case 8:
|
|
for($y=0; $y<$ico_size; $y++)
|
|
{
|
|
for($x=0; $x<$ico_size; $x++)
|
|
{
|
|
$valpha = ($alpha[$off]=='1') ? 127 : 0;
|
|
$c = $arraycolor[$off];
|
|
$c = $bitmap_info['colors'][$c];
|
|
$color = imagecolorallocatealpha($im, $c['rgbRed'], $c['rgbGreen'], $c['rgbBlue'], $valpha);
|
|
imagesetpixel ($im, $x, $ico_size-1-$y, $color);
|
|
$off++;
|
|
}
|
|
}
|
|
break;
|
|
|
|
###################### for 04 bit icons ######################
|
|
# 318 = 22 (header) + 40 (bitmap_info) + 16 * 4 (colors) + 128 (pixels) + 64 (mask)
|
|
case 4:
|
|
for($y=0; $y<$ico_size; $y++)
|
|
{
|
|
for($x=0; $x<$ico_size; $x++)
|
|
{
|
|
$valpha = ($alpha[$off]=='1') ? 127 : 0;
|
|
$c = ($arraycolor[floor($off/2)]);
|
|
$c = str_pad(decbin($c), 8, '0', STR_PAD_LEFT);
|
|
$m = (fmod($off+1, 2)==0) ? 1 : 0;
|
|
$c = bindec(substr($c, $m*4, 4));
|
|
$c = $bitmap_info['colors'][$c];
|
|
$color = imagecolorallocatealpha($im, $c['rgbRed'], $c['rgbGreen'], $c['rgbBlue'], $valpha);
|
|
imagesetpixel ($im, $x, $ico_size-1-$y, $color);
|
|
$off++;
|
|
}
|
|
}
|
|
break;
|
|
|
|
###################### for 01 bit icons ######################
|
|
# 198 = 22 (header) + 40 (bitmap_info) + 2 * 4 (colors) + 64 (pixels, but real 32 needed?) + 64 (mask)
|
|
case 1:
|
|
for($y=0; $y<$ico_size; $y++)
|
|
{
|
|
for($x=0; $x<$ico_size; $x++)
|
|
{
|
|
$valpha = ($alpha[$off]=='1') ? 127 : 0;
|
|
$c = ($arraycolor[floor($off/8)]); # ...... .... ...... 8 ........
|
|
$c = str_pad(decbin($c), 8, '0', STR_PAD_LEFT);
|
|
$m = fmod($off+8, 8) + 1; # bit number
|
|
$c = (int) substr($c, $m-1, 1);
|
|
$c = $bitmap_info['colors'][$c];
|
|
$color = imagecolorallocatealpha($im, $c['rgbRed'], $c['rgbGreen'], $c['rgbBlue'], $valpha);
|
|
imagesetpixel ($im, $x, $ico_size-1-$y, $color);
|
|
$off++;
|
|
}
|
|
$off = $off + 16;
|
|
}
|
|
break;
|
|
|
|
##############################################################
|
|
|
|
default:
|
|
return '';
|
|
}
|
|
|
|
# output png
|
|
ob_start();
|
|
# imagesavealpha($im, true);
|
|
imagepng($im);
|
|
imagedestroy($im);
|
|
$res = ob_get_clean();
|
|
}
|
|
return $res;
|
|
}
|
|
}
|
|
|
|
?>
|