download this file: class.download.php view text/plain: class.download.php file encoding: UTF-8 [goback]
<?php
##
## this file name is 'class.download.php'
##
## download object
##
## [author]
## - Chilbong Kim, <san2(at)linuxchannel.net>
## - http://linuxchannel.net/
##
## [changes]
## - 2014.12.09 : timeout tunning
## - 2009.08.04 : bug fixed _gethttp()
## - 2008.12.03 : some stderr(), add more info(connect time, response time ...)
## - 2008.12.01 : bug fixed _parse_url()
## - 2008.06.18 : bug fixed none-blocking mode
## - 2005.03.28 : bug fixed and tunning
## - 2005.03.24 : new build
##
## [download & online source view]
## - http://ftp.linuxchannel.net/devel/php_download/
##
## [references]
##
## [usage]
##
class download
{
/***
var $sock = ''; // socket
var $blocking = FALSE; // blocking mode
var $bsize = 1048576; // socket send/receive buffer size(Bytes)
var $debug = FALSE; // debug mode or gregress view mode
var $timeout = array('sec'=>0,'usec'=>100000);
***/
function &gethttp($_url, $blocking=FALSE, $debug=FALSE)
{
static $bsize = 1048576; // socket send/receive buffer size(Bytes)
static $timeout = array('sec'=>0,'usec'=>500000);
list($host,$port,$uri) = download::_parse_url($_url);
if(!$host) return;
if(preg_match('/[a-z]/',$host)) $ip = gethostbyname($host); // to ip
else $ip = $host;
$sock = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
@socket_set_option($sock,SOL_SOCKET,SO_SNDBUF,$bsize);
@socket_set_option($sock,SOL_SOCKET,SO_RCVBUF,$bsize);
@socket_set_option($sock,SOL_SOCKET,SO_RCVTIMEO,$timeout); // good idea for blocking mode
@socket_set_option($sock,SOL_SOCKET,SO_SNDTIMEO,$timeout);
if($blocking) $bmode = 'blocking-mode';
else
{
@socket_set_nonblock($sock); // set to non-blocking mode
$bmode = 'non-blocking-mode';
}
$req = 'GET '.$uri.' HTTP/1.1'."\r\n".
'Host: '.$host."\r\n".
'User-Agent: PHP/gethttp'."\r\n".
'Connection: close'."\r\n". // good idea for blocking mode
"\r\n"; // enf of request header mark
$conn_start = microtime();
$code = download::_connect($sock,$ip,$port,5,$blocking);
$conn_stop = microtime();
if($code != 1)
{
@socket_close($sock);
if($debug) download::stderr('can not connect to '.$host.':'.$port);
return;
}
if(!@socket_write($sock,$req))
{
@socket_close($sock);
if($debug) download::stderr('can not send request '.$uri);
return;
}
$req_stop = microtime();
$header = download::_getheader($sock,1024,$blocking); // read header
$header_stop = microtime();
$header = download::_parse_header($header);
if($header['error'])
{
@socket_close($sock);
if($debug) download::stderr($header['status'].' '.$url);
return;
}
$total = $header['content-length']; // total size
$pg = $debug ? $total : 0; // debug mode with progress
$transfer_start = microtime();
$size = download::_readsize($sock,$bsize,$blocking,$pg); // check bandwidth mode
//download::_readbyall($sock,$buf='',$bsize,$blocking,$pg);
//$size = strlen($buf);
@socket_close($sock);
$transfer_stop = microtime();
//$secs = download::_getmicrotime(defined('_RESPONSE_END_')?_RESPONSE_END_:$transfer_start,$transfer_stop);
$secs = download::_getmicrotime($transfer_start,$transfer_stop);
$rr = @sprintf("%s %.1f%s\t%.1f%s\t%d Bytes\t%.2f secs",
$bmode,$size*100/$total,'%',$size/1024/$secs,'KB/sec',$size,$secs);
echo $rr;
if($debug)
{
$conn_time = download::_getmicrotime($conn_start,$conn_stop) * 1000;
$request_time = download::_getmicrotime($conn_start,$req_stop) * 1000;
$response_time = download::_getmicrotime($conn_start,$header_stop) * 1000;
$transfer_time = $secs * 1000;
$total_time = ($response_time + $transfer_time) / 1000;
printf
(
"\nconnect.time %.1f ms, request.time %.1f ms, response.time %.1f ms, ".
"transfer %.1f ms, total %.4f secs",
$conn_time, $request_time, $response_time, $transfer_time, $total_time
);
}
}
function &_gethttp($_url, $debug=FALSE)
{
list($host,$port,$uri) = download::_parse_url($_url);
if(!$host) return;
$bmode = 'blocking-mode';
$req = 'GET '.$uri.' HTTP/1.1'."\r\n".
'Host: '.$host."\r\n".
'User-Agent: PHP/gethttp'."\r\n".
'Connection: close'."\r\n". // good idea for blocking mode
"\r\n"; // enf of request header mark
if(!$fp = @fsockopen($host,$port,$errno,$errstr,3))
{
download::stderr($errstr);
return;
}
@stream_set_timeout($fp,0,500000); // 0.5 seconds, good idea for blocking mode
if(!@fwrite($fp,$req)) return;
## read header
##
$header = '';
while($buf = fgets($fp,1024))
{
if(!trim($buf))
{
fgets($fp,1024); // seek
break;
}
$header .= $buf;
}
$header = download::_parse_header($header);
if($header['error'])
{
@fclose($fp);
if($debug) download::stderr($header['status'].' '.$_url);
return;
}
$total = $header['content-length']; // total size
$pg = $debug ? $total : 0; // debug mode with progress
$size = 0;
$start = microtime();
while($buf = fread($fp,4096))
{
$size += strlen($buf);
if($pg) download::__progress($size,$total,&$op); // debug mode
}
if($pg) echo (int)($size*100/$total)."%\n"; // debug mode
@fclose($fp);
$secs = download::_getmicrotime($start,microtime());
$rr = @sprintf("%s %.1f%s\t%.1f%s\t%d Bytes\t%.2f secs",
$bmode,$size*100/$total,'%',$size/1024/$secs,'KB/sec',$size,$secs);
echo $rr;
}
## connect to host:port
##
## [return]
## 1 or TRUE : connected
## 0 or FALSE : can't connect
## -1 : connetion time out
##
function &_connect(&$sock, $host, $port, $timeout=3, $blocking=FALSE)
{
if($blocking) return @socket_connect($sock,$host,$port);
$_time = time();
while(1)
{
@socket_connect($sock,$host,$port);
if(@socket_last_error()==56 || @socket_last_error()==106) { return TRUE; break; }
else if((time()-$_time) >= $timeout) { return -1; break; }
}
return FALSE;
}
## read header by socket_read()
## PHP_NORMAL_READ : 1
## PHP_BINARY_READ : 2
##
function &__readheader(&$sock, $bsize)
{
while($buf = @socket_read($sock,$bsize,PHP_NORMAL_READ))
{
//if(!defined('_RESPONSE_END_')) define('_RESPONSE_END_',microtime());
if(!trim($obuf.$buf))
{
@socket_read($sock,$bsize,PHP_NORMAL_READ); // seek 1 bytes
break; // end of header
}
$rbuf .= $buf; $obuf = $buf;
}
return $rbuf;
}
## read HTTP all headers
##
function &_getheader(&$sock, $bsize=1024, $blocking=FALSE)
{
if($blocking) return @download::__readheader($sock,$bsize);
$stream = array($sock);
while(@socket_select($stream,$write=NULL,$except=NULL,10,0) !== FALSE)
{
//if(!in_array($sock,$stream)) break; // is bug ???
$rbuf = download::__readheader($sock,$bsize);
break; // require
}
return $rbuf;
}
function &_parse_url($_url)
{
$url = parse_url(preg_replace(';^(?:http://)*;i','http://',trim($_url)));
$host = $url['host'];
$port = $url['port'] ? $url['port'] : 80;
$uri = $url['path'] ? $url['path'] : '/';
if($url['query']) $uri .= '?'.$url['query']; // add san2@2008.12.01
return array($host,$port,$uri);
}
function &_parse_header($buf)
{
$lines = preg_split('/[\r\n]+/',trim($buf));
$size = sizeof($lines);
$r['status'] = trim($lines[0]);
if(!preg_match(';200 OK;',$lines[0]))
{
$r['error'] = TRUE;
return $r;
}
for($i=1; $i<$size; $i++)
{
$line = trim($lines[$i]);
list($k) = preg_split('/:\s+/',$line);
$r[strtolower($k)] = preg_replace(';^'.$k.':\s+;','',$line);
}
return $r;
}
function &__progress($size, $total, &$op)
{
$np = (int)($size*100/$total);
if($np != $op)
{
echo '=';
//if(!($np%25)) echo $np;
//if($size == $total) break; // good idea in while()
}
$op = $np;
flush();
}
## read by size
##
function &_readbysize(&$sock, $bsize=4096, $blocking=FALSE)
{
if($blocking) return @socket_read($sock,$bsize);
$stream = array($sock);
while(@socket_select($stream,$write=NULL,$except=NULL,10,0) !== FALSE)
{
if(!in_array($sock,$stream)) break;
return @socket_read($sock,$bsize);
break; // require
}
return;
}
## read by all
##
function &_readbyall(&$sock, &$rbuf, $bsize=1048576, $blocking=FALSE, $total=0)
{
if($blocking)
{
while(($buf = @socket_read($sock,$bsize)))
{
$rbuf .= $buf;
if($total) download::__progress($rsize+=strlen($buf),$total,&$op);
}
if($total) echo (int)($rsize*100/$total)."%\n"; // debug mode
return TRUE;
}
$stream = array($sock);
while(@socket_select($stream,$write=NULL,$except=NULL,10,0) !== FALSE)
{
if(!in_array($sock,$stream)) break;
if(($buf = @socket_read($sock,$bsize)))
{
$rbuf .= $buf;
if($total) download::__progress($rsize+=strlen($buf),$total,&$op);
} else break; // good idea, EOF
}
if($total) echo (int)($rsize*100/$total)."%\n"; // debug mode
return TRUE;
}
## only read size, this is a bandwidth test version
##
function &_readsize(&$sock, $bsize=1048576, $blocking=FALSE, $total=0)
{
if($blocking)
{
while(($tsize = strlen(@socket_read($sock,$bsize))))
{
$rsize += $tsize;
if($total) download::__progress($rsize,$total,&$op); // debug mode
}
if($total) echo (int)($rsize*100/$total)."%\n"; // debug mode
return $rsize;
}
$stream = array($sock);
while(@socket_select($stream,$write=NULL,$except=NULL,10,0) !== FALSE)
{
if(!in_array($sock,$stream)) break;
if($tsize = strlen(@socket_read($sock,$bsize)))
{
$rsize += $tsize;
if($total) download::__progress($rsize,$total,&$op); // debug mode
} else break; // good idea, EOF
}
if($total) echo (int)($rsize*100/$total)."%\n"; // debug mode
return $rsize;
}
function &_getmicrotime($_start, $_end)
{
$end = explode(' ', $_end);
$start = explode(' ', $_start);
return sprintf('%.4f', ($end[1]+$end[0]) - ($start[1]+$start[0]));
}
function &socket_info($socket)
{
$opt = array
(
'SO_DEBUG'=>SO_DEBUG,
'SO_ACCEPTCONN'=>SO_ACCEPTCONN,
'SO_BROADCAST'=>SO_BROADCAST,
'SO_REUSEADDR'=>SO_REUSEADDR,
'SO_KEEPALIVE'=>SO_KEEPALIVE,
'SO_LINGER'=>SO_LINGER,
'SO_OOBINLINE'=>SO_OOBINLINE,
'SO_SNDBUF'=>SO_SNDBUF,
'SO_RCVBUF'=>SO_RCVBUF,
'SO_ERROR'=>SO_ERROR,
'SO_TYPE'=>SO_TYPE,
'SO_DONTROUTE'=>SO_DONTROUTE,
'SO_RCVLOWAT'=>SO_RCVLOWAT,
'SO_RCVTIMEO'=>SO_RCVTIMEO,
'SO_SNDLOWAT'=>SO_SNDLOWAT,
'SO_SNDTIMEO'=>SO_SNDTIMEO,
);
foreach($opt AS $k=>$v)
{ $r[$k] = @socket_get_option($socket,SOL_SOCKET,$v); }
return $r; // array
}
## print to stderr such as error_log()
##
## arguments :
## $error string, error message
##
## return :
## $return mixed, the number of bytes written, or FALSE on error
##
function _stderr($errstr)
{
if($fp = @fopen('php://stderr','w'))
{
## add error_log format style
##
if($_SERVER['HTTP_USER_AGENT'])
{
$head = '['.date('D M d H:i:s Y').'] [PHP-stderr] '.
'[client '.$_SERVER['REMOTE_ADDR'].'] ';
}
$return = @fwrite($fp,$head.$errstr."\n");
fclose($fp);
}
return $return;
}
function stderr($errstr)
{
return error_log($errstr,0);
}
} // end of class
/*** example ***
set_time_limit(0);
ob_implicit_flush();
//ini_set('memory_limit','150M');
$host = 'www.foobar.com';
download::gethttp("http://$host/test/100M.data",0,1);
***/
?>