본문 바로가기

php

파일다운로드 - 이어받기 속도제한 인증 기타


<?
// class.httpdownload.php

/**
 @author Nguyen Quoc Bao <quocbao.coder@gmail.com>
 @version 1.3
 @desc A simple object for processing download operation , support section downloading
 Please send me an email if you find some bug or it doesn't work with download manager.
 I've tested it with
     - Reget
     - FDM
     - FlashGet
     - GetRight
     - DAP
     
 @copyright It's free as long as you keep this header .
 @example
 
 1: File Download
     $object = new downloader;
     $object->set_byfile($filename); //Download from a file
     $object->use_resume = true; //Enable Resume Mode
     $object->download(); //Download File
     
 2: Data Download
  $object = new downloader;
     $object->set_bydata($data); //Download from php data
     $object->use_resume = true; //Enable Resume Mode
     $object->set_filename($filename); //Set download name
     $object->set_mime($mime); //File MIME (Default: application/otect-stream)
     $object->download(); //Download File
     
     3: Manual Download
     $object = new downloader;
     $object->set_filename($filename);
    $object->download_ex($size);
    //output your data here , remember to use $this->seek_start and $this->seek_end value :)
    
**/

class httpdownload {

    var $data = null;
    var $data_len = 0;
    var $data_mod = 0;
    var $data_type = 0;
    var $data_section = 0; //section download
    /**
     * @var ObjectHandler
     **/
    var $handler = array('auth' => null);
    var $use_resume = true;
    var $use_autoexit = false;
    var $use_auth = false;
    var $filename = null;
    var $mime = null;
    var $bufsize = 2048;
    var $seek_start = 0;
    var $seek_end = -1;
    
    /**
     * Total bandwidth has been used for this download
     * @var int
     */
    var $bandwidth = 0;
    /**
     * Speed limit
     * @var float
     */
    var $speed = 0;
    
    /*-------------------
    | Download Function |
    -------------------*/
    /**
     * Check authentication and get seek position
     * @return bool
     **/
    function initialize() {
        global $HTTP_SERVER_VARS;
        
        if ($this->use_auth) //use authentication
        {
            if (!$this->_auth()) //no authentication
            {
                header('WWW-Authenticate: Basic realm="Please enter your username and password"');
            header('HTTP/1.0 401 Unauthorized');
            header('status: 401 Unauthorized');
            if ($this->use_autoexit) exit();
                return false;
            }
        }
        if ($this->mime == null) $this->mime = "application/octet-stream"; //default mime
        
        if (isset($_SERVER['HTTP_RANGE']) || isset($HTTP_SERVER_VARS['HTTP_RANGE']))
        {
            
            if (isset($HTTP_SERVER_VARS['HTTP_RANGE'])) $seek_range = substr($HTTP_SERVER_VARS['HTTP_RANGE'] , strlen('bytes='));
            else $seek_range = substr($_SERVER['HTTP_RANGE'] , strlen('bytes='));
            
            $range = explode('-',$seek_range);
            
            if ($range[0] > 0)
            {
                $this->seek_start = intval($range[0]);
            }
            
            if ($range[1] > 0) $this->seek_end = intval($range[1]);
            else $this->seek_end = -1;
            
            if (!$this->use_resume)
            {
                $this->seek_start = 0;
                
                //header("HTTP/1.0 404 Bad Request");
                //header("Status: 400 Bad Request");
                
                //exit;
                
                //return false;
            }
            else
            {
                $this->data_section = 1;
            }
            
        }
        else
        {
            $this->seek_start = 0;
            $this->seek_end = -1;
        }
        
        return true;
    }
    /**
     * Send download information header
     **/
    function header($size,$seek_start=null,$seek_end=null) {
        header('Content-type: ' . $this->mime);
        header('Content-Disposition: attachment; filename="' . $this->filename . '"');
        header('Last-Modified: ' . date('D, d M Y H:i:s \G\M\T' , $this->data_mod));
        
        if ($this->data_section && $this->use_resume)
        {
            header("HTTP/1.0 206 Partial Content");
            header("Status: 206 Partial Content");
            header('Accept-Ranges: bytes');
            header("Content-Range: bytes $seek_start-$seek_end/$size");
            header("Content-Length: " . ($seek_end - $seek_start + 1));
        }
        else
        {
            header("Content-Length: $size");
        }
    }
    
    function download_ex($size)
    {
        if (!$this->initialize()) return false;
        ignore_user_abort(true);
        //Use seek end here
        if ($this->seek_start > ($size - 1)) $this->seek_start = 0;
        if ($this->seek_end <= 0) $this->seek_end = $size - 1;
        $this->header($size,$seek,$this->seek_end);
        $this->data_mod = time();
        return true;
    }
    
    /**
     * Start download
     * @return bool
     **/
    function download() {
        if (!$this->initialize()) return false;
        
        $seek = $this->seek_start;
        $speed = $this->speed;
        $bufsize = $this->bufsize;
        $packet = 1;
        
        //do some clean up
        @ob_end_clean();
        $old_status = ignore_user_abort(true);
        @set_time_limit(0);
        $this->bandwidth = 0;
        
        $size = $this->data_len;
        
        if ($this->data_type == 0) //download from a file
        {
            
            $size = filesize($this->data);
            if ($seek > ($size - 1)) $seek = 0;
            if ($this->filename == null) $this->filename = basename($this->data);
            
            $res = fopen($this->data,'rb');
            if ($seek) fseek($res , $seek);
            if ($this->seek_end < $seek) $this->seek_end = $size - 1;
            
            $this->header($size,$seek,$this->seek_end); //always use the last seek
            $size = $this->seek_end - $seek + 1;
            
            while (!(connection_aborted() || connection_status() == 1) && $size > 0)
            {
                if ($size < $bufsize)
                {
                    echo fread($res , $size);
                    $this->bandwidth += $size;
                }
                else
                {
                    echo fread($res , $bufsize);
                    $this->bandwidth += $bufsize;
                }
                
                $size -= $bufsize;
                flush();
                
                if ($speed > 0 && ($this->bandwidth > $speed*$packet*1024))
                {
                    sleep(1);
                    $packet++;
                }
            }
            fclose($res);
            
        }
        
        elseif ($this->data_type == 1) //download from a string
        {
            if ($seek > ($size - 1)) $seek = 0;
            if ($this->seek_end < $seek) $this->seek_end = $this->data_len - 1;
            $this->data = substr($this->data , $seek , $this->seek_end - $seek + 1);
            if ($this->filename == null) $this->filename = time();
            $size = strlen($this->data);
            $this->header($this->data_len,$seek,$this->seek_end);
            while (!connection_aborted() && $size > 0) {
                if ($size < $bufsize)
                {
                    $this->bandwidth += $size;
                }
                else
                {
                    $this->bandwidth += $bufsize;
                }
                
                echo substr($this->data , 0 , $bufsize);
                $this->data = substr($this->data , $bufsize);
                
                $size -= $bufsize;
                flush();
                
                if ($speed > 0 && ($this->bandwidth > $speed*$packet*1024))
                {
                    sleep(1);
                    $packet++;
                }
            }
        } else if ($this->data_type == 2) {
            //just send a redirect header
            header('location: ' . $this->data);
        }
        
        if ($this->use_autoexit) exit();
        
        //restore old status
        ignore_user_abort($old_status);
        set_time_limit(ini_get("max_execution_time"));
        
        return true;
    }
    
    function set_byfile($dir) {
        if (is_readable($dir) && is_file($dir)) {
            $this->data_len = 0;
            $this->data = $dir;
            $this->data_type = 0;
            $this->data_mod = filemtime($dir);
            return true;
        } else return false;
    }
    
    function set_bydata($data) {
        if ($data == '') return false;
        $this->data = $data;
        $this->data_len = strlen($data);
        $this->data_type = 1;
        $this->data_mod = time();
        return true;
    }
    
    function set_byurl($data) {
        $this->data = $data;
        $this->data_len = 0;
        $this->data_type = 2;
        return true;
    }
    
    function set_lastmodtime($time) {
        $time = intval($time);
        if ($time <= 0) $time = time();
        $this->data_mod = $time;
    }
    
    /**
     * Check authentication
     * @return bool
     **/
    function _auth() {
        if (!isset($_SERVER['PHP_AUTH_USER'])) return false;
        if (isset($this->handler['auth']) && function_exists($this->handler['auth']))
        {
            return $this->handler['auth']('auth' , $_SERVER['PHP_AUTH_USER'],$_SERVER['PHP_AUTH_PW']);
        }
        else return true; //you must use a handler
    }
    
}

?>







<?
// test.php
$FILENAME = ""; //SET YOUR FILE HERE

if (!$FILENAME || !file_exists($FILENAME)) {
    echo "Please set your target file \$FILENAME on line 2\n";
    exit();
}

include_once "class.httpdownload.php";

$object = new httpdownload;

$bandwidth = @intval(implode('',file('bandwidth.txt'))) / 1024;
if ($bandwidth > 1024)
{
    $bandwidth = round($bandwidth / 1024 , 2);
    $bandwidth .= " MB";
}
else
{
    $bandwidth .= " KB";
}

switch (@$_GET['download']) {
case 'resume_speed':
case 'noresume_speed':
case 'resume':
case 'noresume':
    $object->set_byfile($FILENAME);
    if ($_GET['download'] == 'noresume' || $_GET['download'] == 'noresume_speed') $object->use_resume = false;
    if ($_GET['download'] == 'resume_speed' || $_GET['download'] == 'noresume_speed' ) $object->speed = 100;
    $object->download();
break;
case 'data':
case 'dataresume':
    $data = implode('' , file($FILENAME));
    $object->set_bydata($data);
    if ($_SERVER['download'] != 'dataresume') $object->use_resume = false;
    $object->filename = basename($FILENAME);
    $object->download();
break;
case 'auth':
    $object->set_byfile($FILENAME);
    $object->use_auth = true;
    $object->handler['auth'] = "test_auth";
    $object->download();
break;
case 'url':
    $object->set_byurl('http://www.php.net/get/php_manual_chm.zip/from/cr.php.net/mirror');
    $object->download();
break;
}

if ($object->bandwidth > 0)
{
    error_reporting(E_NONE);
    $b = intval(implode('',file('bandwidth.txt'))) + $object->bandwidth;
    $f = fopen('bandwidth.txt','wb');
    fwrite($f,$b);
    fclose($f);
    exit;
}

function test_auth($user,$pass) { //test authentication function
    if ($user == 'user' && $pass == 'pass') return true;
    return false;
}

?>

<head>
<style>
<!--
body        { font-family: Tahoma; font-size: 12px }
a            { color: #FF0000 }
-->
</style>
</head>

<title>HTTPDownload example</title>

<h2><font color="navy">HttpDownload</font></h2>Select a link and try it with a download manager (like <a href="http://reget.com">Reget</a>) .<br><br>

Total bandwidth used : <B><?=$bandwidth?></B>

<br><br>
<a href="test.php?download=noresume">Download file</a><br>
<a href="test.php?download=noresume_speed">Download file (speed limit 100 kbs)</a><br>
<a href="test.php?download=resume">Download file with resume</a><br>
<a href="test.php?download=resume_speed">Download file with resume (speed limit 100 kbs) </a><br>
<a href="test.php?download=data">Download file data (May slow)</a><br>
<a href="test.php?download=dataresume">Download file data with resume (May slow)</a><br>
<a href="test.php?download=auth">Authentication download (user/pass)</a><br>
<a href="test.php?download=url">URL Download (simple redirect)</a><br>

<p><font size="1"><font color="#808080">( Click
<a href="http://en.vietapi.com/wiki/index.php/PHP:_HttpDownload">
<font color="black">here</font></a><font color=""> to view class
information )</font></p>

'php' 카테고리의 다른 글

[함수] $_SERVER['PATH_INFO'] 사용하기.  (0) 2010.03.09
UTF8 문자관련  (1) 2009.12.15
php 이메일주소 유효성검사  (0) 2009.11.11
html 제거  (0) 2009.10.07
욕필터링  (0) 2009.10.07