Re: Server to client file transfer with authorization: file always corrupt

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sat, 02 Feb 2008 23:08:43 -0000, Nathan Rixham <nrixham@xxxxxxxxx> wrote:

szalinski wrote:
Hi
 I am having trouble with a file transfer script, as you can see, I am
trying trying to keep the code as simple as possible.
But everytime I download a file with it, it is corrupt. For example, when
I download a small .rar file, just to test, it is always corrupt
('Unexpected end of archive'). I also cleared my browser cache just to be
sure, but same problem.
 I just can't get my head around why it wouldn't be working as it is...
 A couple of questions:
 Have I got too many header requests?
Do I need to worry about output buffering, which is possibly corrupting
the file output (if so, please tell me what to do!)?
Is there an easier way to get returned response header and get a
redirected link, instead of finding and cutting strings?
Is there maybe something wrong with the structure or order of the header
requests, and/or returned headers etc?
 Here is what I have so far:
 <?php
 //ob_start();
//ob_end_flush();
//ob_implicit_flush(TRUE);
 $rslogin = '';
$rspass = '';
$link = addslashes(trim($_POST['link']));
 function cut_str($str, $left, $right)
  {
  $str = substr(stristr($str, $left), strlen($left));
  $leftLen = strlen(stristr($str, $right));
  $leftLen = $leftLen ? -($leftLen) : strlen($str);
  $str = substr($str, 0, $leftLen);
  return $str;
  }
 // Get the full premium link, and store it in $full_link after the
redirect. *Surely* there is an easier way to get redirections?
 if(strlen($link)>0)
{
    $url = @parse_url($link);
    $fp = @fsockopen($url['host'], 80, $errno, $errstr);
    if (!$fp)
        {
$errormsg = "Error: <b>$errstr</b>, please try again later.";
            echo $errormsg;
            exit;
        }
$vars = "dl.start=PREMIUM&uri={$url['path']}&directstart=1";
            $out = "POST {$url['path']} HTTP/1.1\r\n";
            $out .= "Host: {$url['host']}\r\n";
$out .= "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows
NT 5.1)\r\n";
            $out .= "Authorization: Basic
".base64_encode("{$rslogin}:{$rspass}")."\r\n";
$out .= "Content-Type: application/x-www-form-urlencoded\r\n";
            $out .= "Content-Length: ".strlen($vars)."\r\n";
            $out .= "Connection: Close\r\n\r\n";
            fwrite($fp, $out);
            fwrite($fp, $out.$vars);
            while (!feof($fp))
            {
            $string .= fgets($fp, 256);
            }
             //Tell us what data is returned
             //print($string);
            @fclose($fp);
             if (stristr($string, "Location:"))
            {
                $redirect = trim(cut_str($string, "Location:", "\n"));
                $full_link = addslashes(trim($redirect));
            }
 //print($string);
//print("<html><body><h1>".$full_link."</h1>");
   if ($full_link)
     {
     //    Get info about the file we want to download:
         $furl = parse_url($full_link);
        $fvars = "dl.start=PREMIUM&uri={$furl['path']}&directstart=1";
        $head = "Host: {$furl['host']}\r\n";
$head .= "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT
5.1)\r\n";
        $head .= "Authorization: Basic
".base64_encode("{$rslogin}:{$rspass}")."\r\n";
        $head .= "Content-Type: application/x-www-form-urlencoded\r\n";
        $head .= "Content-Length: ".strlen($fvars)."\r\n";
        $head .= "Connection: close\r\n\r\n";
        $fp = @fsockopen($furl['host'], 80, $errno, $errstr);
        if (!$fp)
        {
echo "The script says <b>$errstr</b>, please try again later.";
            exit;
        }
        fwrite($fp, "POST {$furl['path']}  HTTP/1.1\r\n");
        fwrite($fp, $head.$fvars);
        while (!feof($fp))
        {
//Keep reading the info until we get the filename and size from
the returned Header - is there no easy way
//of doing this? I also don't like the way I have to 'find' the
redirected link (above).??
            $tmp .= fgets($fp, 256);
            $d = explode("\r\n\r\n", $tmp);
             // I tried changing this to if ($d), { etc..,  (instead of
$d[1]) and the download of the rar file *wasn't* corrupt, it just had a
filetype of x-rar-compressed instead of
            //application/octet-stream, and the filesize was 'unknown' -
now this is just confusing me...!  So i think (and guess) the problem of
the file corruption is here,
            //because it must add some data to the filestream which
corrupts it. Darn.
            if($d[1])
            {
                preg_match("#filename=(.+?)\n#", $tmp, $fname);
                preg_match("#Content-Length: (.+?)\n#", $tmp, $fsize);
                $h['filename'] = $fname[1] != "" ? $fname[1] :
basename($furl['path']);
                $h['fsize'] = $fsize[1];
                break;
            }
 }
        @fclose($fp);
         $filename = $h['filename'];
        $fsize = $h['fsize'];
 //Now automatically download the file:
         @header("Cache-Control:");
        @header("Cache-Control: public");
        @header("Content-Type: application/octet-stream");
        @header("Content-Disposition: attachment; filename=".$filename);
        @header("Accept-Ranges: bytes");
        if(isset($_SERVER['HTTP_RANGE']))
        {
            list($a, $range)=explode("=",$_SERVER['HTTP_RANGE']);
            $range = str_replace("-", "", $range);
            $new_length = $fsize - $range;
            @header("HTTP/1.1 206 Partial Content");
            @header("Content-Length: $new_length");
        }
        else
        {
            @header("Content-Length: ".$fsize);
        }
        $f2vars = "dl.start=PREMIUM&uri={$furl['path']}&directstart=1";
        $head2 = "Host: {$furl['host']}\r\n";
$head2 .= "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows
NT 5.1)\r\n";
        $head2 .= "Authorization: Basic
".base64_encode("{$rslogin}:{$rspass}")."\r\n";
        $head2 .= "Content-Type: application/x-www-form-urlencoded\r\n";
        if($range != "") $head2 .= "Range: bytes={$range}-\r\n";
        $head2 .= "Content-Length: ".strlen($fvars)."\r\n";
        $head2 .= "Connection: close\r\n\r\n";
        $fp = @fsockopen($furl['host'], 80, $errno, $errstr);
        if (!$fp)
        {
            echo "<span style='color:#688000; background-color:#BBDB54;
font-size : 10pt; text-decoration: none; font-family: Trebuchet MS;'>The
script says <b>$errstr</b>, please try again later.</span>";
            exit;
        }
        @stream_set_timeout($fp, 120);
        fwrite($fp, "POST {$furl['path']}  HTTP/1.1\r\n");
        fwrite($fp, $head2.$f2vars);
        fflush($fp);
        while (!feof($fp))
        {
            $download = fread($fp, 2048);
            echo $download;
            //ob_flush(); //php.net suggestion
        }
 //These two buggers were here originally, but I don't even know if I am
supposed to have them here.
         flush();
         ob_flush();
       @fclose($fp);
        exit;
     }
  }
else
{
        $data = "<form method=\"post\">\n";
        $data .= "<input type=\"text\" id=\"link\"
style=\"text-align:center\" name=\"link\" size=\"60\"
onfocus=\"if(this.value=='Enter rapidshare.com URL
here'){this.value=''}\">\n";
$data .= "<br><input type=\"submit\" value=\"Download\"></form>";
        echo $data;
}
?>
 Thanks to anyone who has already helped, I hope some genius can spot an
obvious error, because this is just beyond me!
 :)

I'd be correct in assuming that you have opened up the download in a text browser to see what you've actually recieved yes?

first thing to check... your doing a fsockopen, and posting a raw http request, meaning your getting a raw http response back, which you're echoing straight out, so you should expect to have full http headers and quite possibly http chunked content, rather than a nice file..

use file_get_contents with a stream_context holding all your http request headers instead, as an easy way around it.

or check out the http class, or use zends http class, or create a quick chunk decoder - whichever you do, first step is to actually check the raw content and verify it's not just a raw http response :)

Nathan

Thanks for the reply, Nathan

I actually have since found more about this 'erroneous' output; the script is outputting response headers as part of the file I download!, and also seems to chop a bit off the end of the file (checking with a text file, of course!) So I will try to do what you suggest - thanks for the help. If anyone has any suggestions on a chunk decoder, or maybe a quick example of file_get_contents() with a stream context, feel free... :)

--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php



[Index of Archives]     [PHP Home]     [Apache Users]     [PHP on Windows]     [Kernel Newbies]     [PHP Install]     [PHP Classes]     [Pear]     [Postgresql]     [Postgresql PHP]     [PHP on Windows]     [PHP Database Programming]     [PHP SOAP]

  Powered by Linux