SitePoint Sponsor

User Tag List

Results 1 to 6 of 6
  1. #1
    SitePoint Addict
    Join Date
    Apr 2005
    Posts
    396
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Download Manager Script Best Practices

    I was called upon recently to secure a directory of large private files using php. Basically what I did was create a script that takes a file name as an argument and serve the file based on the mime type (after authenticating the user trying to access it). It theoretically works, but I'm running into some issues here that I think a PHP expert might be able to help me with.

    The files are very large (80 to 120 megs, zips and rars), and couple things are happening:

    1) Download speeds from the server are around 300kps when you just download directly. If I grab it using the download script, it's 40 to 50 kps -- significant drop.

    2) I'm having trouble downloading multiple files at once through the script. I gather this may be related to the authentication session? This won't really work long term for the type of system it is. A user might want to download dozens of files at once.

    3) The connection is canceled pretty often, and the download fails. I think it can be resumed from there, but I'm not sure.
    Bring out our hope and reason, before we pine away.

  2. #2
    ✯✯✯ silver trophybronze trophy php_daemon's Avatar
    Join Date
    Mar 2006
    Posts
    5,284
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    What do you use in php to output the file? Any pseudo-code to illustrate?

    The way i'd do it is:
    Code php:
    //get file path from db
    $filename=$this->getfilepath();
     
    //output the correct headers
    header(header("Content-Type: ".$content_type);
    header("Content-Length: " . filesize($filename));
     
    //output the contents
    fpassthru($filename);
    exit;
    It's important here that you use fpassthru as opposed to readfile or other filesystem routines. And make sure you terminate the script with exit.
    Saul

  3. #3
    SitePoint Addict
    Join Date
    Apr 2005
    Posts
    396
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ah, ok, I didn't use fpassthru, and I didn't exit afterward, but the basic code is what you wrote. I'll try it when I get home, thanks a lot!
    Bring out our hope and reason, before we pine away.

  4. #4
    SitePoint Addict
    Join Date
    Apr 2005
    Posts
    396
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hm, that doesn't seem to be working.

    Here's the code -- it still fails to allow multiple downloads. It may be the case that the connection issue is fixed though, I'd have to have my users test that.

    PHP Code:
    <?php
        
    require_once ( 'auth.php' );
        
    $auth = new Auth ( );

        
    define 'SECURE_DIR''music/' );// Outside the HTTP root
        
    define 'MIME_ZIP''application/zip' );
        
    define 'MIME_RAR''application/x-rar-compressed' );
        
        function 
    DownloadFile $this_file )
        {
            
    $src_file SECURE_DIR $this_file;
            if ( 
    file_exists $src_file ) )
            {            
                if ( 
    substr $src_file, -) == '.zip' )
                {
                    
    $mime_type MIME_ZIP;
                }
                elseif ( 
    substr $src_file, -) == '.rar' )
                {
                    
    $mime_type MIME_RAR;
                }
                else
                {
                    
    header("HTTP/1.1 404 Not Found");
                    exit ( );
                }
                
    $file fopen $src_file'rb' );
                
    header('Content-type: ' $mime_type );
                
    header('Content-Disposition: attachment; filename="' $this_file '"' );
                
    header('Content-Length: ' filesize $src_file ) );
                
    fpassthru $file );
                exit ( );
            }
            else
            {
                
    header("HTTP/1.1 404 Not Found");
            }
        }

        if ( isset ( 
    $_GET['f'] ) )
        {
            
    DownloadFile urldecode $_GET['f'] ) );
        }
        {
            
    header("HTTP/1.1 404 Not Found");        
        }
    ?>
    Bring out our hope and reason, before we pine away.

  5. #5
    ✯✯✯ silver trophybronze trophy php_daemon's Avatar
    Join Date
    Mar 2006
    Posts
    5,284
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Well, I googled, I searched these forums and only come up with problems but not solutions. It seems that php outputs all contents to a buffer before apache serves it to the user. So it might be that you need to tweek apache to get better results.

    I'm using this very same way to serve secured files, but in my case they are small and the traffic is really low. It's interesting problem though.
    Saul

  6. #6
    SitePoint Wizard TheRedDevil's Avatar
    Join Date
    Sep 2004
    Location
    Norway
    Posts
    1,198
    Mentioned
    4 Post(s)
    Tagged
    1 Thread(s)
    It is possible to support resume downloads with a php script.

    Though, it need to be handeled the correct way.

    You need to see if the http_range variable is sent from the user. If set the correct headers, and offset the file to the correct portion before sending the user the data.

    Take a look on the user examples in the manual, there is several exampls there.
    http://no.php.net/fread

    Note. Remember to use output buffering!

    Quote Originally Posted by php_daemon
    Well, I googled, I searched these forums and only come up with problems but not solutions. It seems that php outputs all contents to a buffer before apache serves it to the user. So it might be that you need to tweek apache to get better results.

    I'm using this very same way to serve secured files, but in my case they are small and the traffic is really low. It's interesting problem though.
    That is not entirely true, it depends on how you do it.

    You can use fread and flush to the output buffer, readfile also works without reading all into memory first.

    When the output buffer is flushed depends on your php and apache settings, though default is usally at 4096 byte.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •