php多线程下载类(实例分享)

发布时间:2020-12-03编辑:脚本学堂
本文介绍下,用php实现的一个多线程下载类,用多线程下载速度快,研究php的朋友,可以参考下这个例子,深入学习下多线程的相关知识。

多线程下载类,原生php代码实现,分享给大家。

代码如下:
 

复制代码 代码示例:

<?php
/**
 * @author 野马
 * 多进程下载类
 * 主要针对curl的多进程下载进行的封装。
 * 使用代码:
<?php
include "multi_download.php";
$xml = file_get_contents('./download.xml');
preg_match_all('/<string>(http.*)</string>/', $xml, $rs);
$md = new multi_download();

foreach( $rs[1] as $line ) {
 $filepath = "./file/" . basename($line);
 $md->addtask( $line, $filepath );
}
$md->dotask();
?>
 */
class multi_download  {
 /**
  * 下载队列
  * @var array
  * array(
  *     array(
  *         'handle' => curl resource
  *         'filepath' => '/tmp/abc.png'
  *         'url' => 'http://www.jb200.com/logo.png'
  *         'info' => curl_getinfo
  *     ),
  * )
  */
 private $threads = array();
 
 /**
  * curl批处理句柄
  * @var resource
  */
 private $multi_hand = NULL;
 
 /**
  * 活动进程指针
  * @var array
  */
 private $active_points = array();
 
 /**
  * 下一个要激活的进程指针
  * @var integer
  */
 private $active_next = 0;
 
 /**
  * 最多活动进程数
  * @var integer
  */
 private $active_max = 5;

 /**
  * 模拟浏览器发送agent
  */
 private $user_agent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)";

 /**
  * 构造方法
  */
 public function __construct() {
  $this->multi_hand = curl_multi_init();
 }
 
 /**
  * 添加下载任务
  * @param string $url 下载地址
  * @param string $filepath 文件存放路径,全路径
  * @return void
  */
 public function addtask( $url, $filepath ) {
  $this->threads[] = array(
   'handle' => NULL,
   'url' => $url,
   'filepath' => $filepath,
   'info' => array()
  );
 }
 
 /**
  * 执行下载任务
  */
 public function dotask() {
  while( TRUE ) {
   $viewScreen = '';
   // 处理每一个进程的状态,清理已完成进程
   foreach( $this->active_points as $vk => $point ) {
    curl_multi_exec( $this->multi_hand, $active );
    $thr = &$this->threads[ $point ];
    $thr[ 'info' ] = curl_getinfo( $thr[ 'handle' ] );
    
    // 组织当前进程的回显内容。
    $viewScreen .= $this->viewStatus( $thr, $point );
    
    // 下载完成,释放资源
    if( $thr[ 'info' ]['http_code'] != 0 && $thr[ 'info' ][ 'size_download' ] == $thr[ 'info' ][ 'download_content_length' ] ) {
     curl_multi_remove_handle( $this->multi_hand, $thr[ 'handle' ] );
     unset( $this->active_points[ $vk ] );
    }
   }
   
   // 启动进程
   if( $this->active_max - count( $this->active_points ) > 0 ) for(
     $i = 0, $num = $this->active_max - count( $this->active_points );
     $i < $num && !empty( $this->threads[ $this->active_next ] ) ;
     $i++, $this->active_next++
     ) {
    $thr = &$this->threads[ $this->active_next ];
    $thr[ 'handle' ] = $this->createconn( $thr[ 'url' ], $thr[ 'filepath' ] );
    
    curl_multi_add_handle ( $this->multi_hand, $thr[ 'handle' ] );
    curl_multi_exec( $this->multi_hand, $active );
    $this->active_points[] = $this->active_next;
    $viewScreen .= $this->viewAddThread( $thr, $this->active_next );
   }
   
   // 显示当前状态。
   echo `clear`;
   echo $viewScreen;
   
   if( empty( $this->threads[ $this->active_next ] ) && empty( $this->active_points ) ) {
    echo "rnAll downloaded.rn";
    break;
   }
   // 间歇1秒
   sleep( 1 );
  }
 }
 
 /**
  * 格式化进程回显信息。
  * @param array $thr 进程数组
  * @param ineteger $point 进程ID
  * @return string
  * @edit www.jb200.com
  */
 private function viewStatus( &$thr, $point ) {
  if( empty( $thr[ 'info' ] ) ) return false;
  $return = "thread({$point}): ";
  
  if( $thr[ 'info' ]['http_code'] == 0 ) {
   return $return . "start.rn";
  }
  elseif( $thr[ 'info' ][ 'size_download' ] == $thr[ 'info' ][ 'download_content_length' ] ) {
   $return .= "finish. ";
  }
  else {
   $return .= "active. ";
  }
  $return .= "[use time:" . intval( $thr[ 'info' ][ 'total_time' ] ) . ",";// ]rn";
  $return .= " speed:" . $this->formateSize( $thr[ 'info' ][ 'speed_download' ] ) . ",";
  $return .= " download:" . ( intval( $thr[ 'info' ][ 'size_download' ] * 100 / $thr[ 'info' ][ 'download_content_length' ] ) ) . "%(" . $this->formateSize( $thr[ 'info' ][ 'size_download' ] ) . ")";
  $return .= " file size:" . $this->formateSize( $thr[ 'info' ][ 'download_content_length' ] );
  $return .= "]rn";
  return $return;
 }
 
 /**
  * 格式化进程回显信息。
  * @param array $thr 进程数组
  * @param ineteger $point 进程ID
  * @return string
  */
 private function viewAddThread( &$thr, $point ) {
  return "thread({$point}): initialize.rn";
 }
 
 /**
  * 格式化文件大小
  * @param integer $size 文件字节数
  * @return string
  * @edit www.jb200.com
  */
 public function formateSize($size) {
  $units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
  $unitindex = 0;
  
  while($size > 1024) {
      $size /= 1024;
      ++$unitindex;
  }
  return sprintf("%0.2f", $size) . $units[ $unitindex ];
 }
 
 /**
  * 创建curl连接
  * @param string $url 下载地址
  * @param string $filepath 文件存放路径,全路径
  * @return curl resource
  */
 public function createconn( $url, $filepath ) {
  $fp = fopen ( $filepath, "w" );
  $conn = curl_init( $url );
  curl_setopt( $conn, CURLOPT_USERAGENT, $this->user_agent );
  curl_setopt( $conn, CURLOPT_FILE, $fp );
  curl_setopt( $conn, CURLOPT_HEADER, 0 );
  curl_setopt( $conn, CURLOPT_CONNECTTIMEOUT, 60 );
  return $conn;
 }
}
?>