<?php
/*
Attachment preview/download
(c) 2004-2007 by "Oleg Savchuk" <hide@address.com>
part of phpProjectMaster project
http://phpprojmaster.sourceforge.net
The contents of this file are subject to the GNU GENERAL PUBLIC LICENSE
http://www.gnu.org/copyleft/gpl.html
*/
session_cache_limiter('public'); //to prevent 'nocache' header (we really need cache here!)
session_start();
require_once "../inc/sitelib.php" ;
require_once "../inc/form_utils.php" ;
require_once "../inc/att.lib.php" ;
global_init();
//********* variables
$item_id = $_REQUEST['id']+0;
# $is_preview = $_REQUEST['ispreview']+0;
# if (!$is_preview) $is_preview='';
$is_save = $_REQUEST['download']+0;
if (!$is_save) $is_save='';
$CHUNK_SIZE=128*1024; #128Kb blocks
if ( check_access_att($item_id)<10 ){
return_forbidden();
};
//********* action!
$CGI_ACTIONS=array(
'' => 'get_att_file',
);
go_action();
exit;
//***************************
function return_empty(){
header($_SERVER["SERVER_PROTOCOL"].' 404 Not Found');
print "404 Not Found";
exit();
}
//***************************
function return_forbidden(){
header($_SERVER["SERVER_PROTOCOL"].' 403 Forbidden');
print "403 Forbidden";
exit();
}
//*************
function get_att_file(){
global $item_id, $is_preview, $att_vars, $u_id;
//check access to the post of the attachment
$hATT=get_att($item_id);
$path=get_upload_path($item_id, $att_vars['upload_path'], ($is_preview)?'_s':'', $hATT['ext']);
# echo "$item_id ".$att_vars['upload_path']." $is_preview ".$hATT['ext']." [$path]";
# exit;
if (!$path){
return return_empty();
}
$mime='application/octet-stream';
if ($hATT['ext']=='gif') $mime='image/gif';
if ($hATT['ext']=='jpg') $mime='image/jpeg';
if ($hATT['ext']=='png') $mime='image/x-png';
$fname=$hATT['iname'];
if (!preg_match("/\..{1,4}$/", $fname)) $fname.=".".$hATT['ext']; //add extension
return_file($path, $mime, $fname);
}
//************ return file via HTTP
function return_file($path, $mime_type='application/octet-stream', $fname='file.ext'){
global $is_save, $CHUNK_SIZE;
$ims=$_SERVER['HTTP_IF_MODIFIED_SINCE'];
$lastModified=filemtime($path);
header("Content-type: $mime_type");
header("Last-Modified: ".gmdate('D, d M Y H:i:s', $lastModified).' GMT');
header("Accept-Ranges: bytes");
if (strlen($ims)) {
// §¤¥«ï¥¬ If-Modified-Since (Netscape < v6 ®â¤ ñâ ¨å ¥¯à ¢¨«ì®)
$modifiedSince = explode(';', $ims);
// ८¡à §ã¥¬ § ¯à®á ª«¨¥â If-Modified-Since ¢ â ©¬èâ ¬¯
$modifiedSince = strtotime($modifiedSince[0]);
} else {
// áâ ¢«¨¢ ¥¬ ¢à¥¬ï ¬®¤¨ä¨ª 樨 ¢ ®«ì
$modifiedSince = 0;
}
// à ¢¨¢ ¥¬ ¢à¥¬ï ¯®á«¥¤¥© ¬®¤¨ä¨ª 樨 ª®â¥â á ªí襬 ª«¨¥â
if ($lastModified <= $modifiedSince) {
// §£à㦠¥¬ ª « ¯¥à¥¤ ç¨ ¤ ëå!
# logger("CACHE HIT [$path]");
header($_SERVER["SERVER_PROTOCOL"].' 304 Not Modified');
exit();
}
# logger("CACHE MISS [$path]");
//ã âãâ 㦠¢ë¤ ¥¬ ä ©« 楫¨ª®¬ (¨«¨ ç áâì) à § 㦠⮠¯®è«®
$fsize=filesize($path);
//check for Range
if (isset($_SERVER['HTTP_RANGE'])) {
# logger("RANGE REQUEST: $_SERVER[HTTP_RANGE]");
$range=substr($_SERVER['HTTP_RANGE'], strpos($_SERVER['HTTP_RANGE'], '=')+1);
$from=strtok($range, '-');
$to=strtok('/');
if ($from){
if ($to){ // bytes=0-499 or =500-999 - everything ok, no change
}else{ // bytes=0- or =500- or =9500- need to calc $to - till the end of file
$to=$fsize-1;
}
}else{
if ($to){ // bytes=-500 - final 500 bytes - need to calc $from and recalc $to
$from=$fsize-$to;
$to=$fsize-1;
}else{ // bytes=- illegal, assume return whole file
}
}
//now we have real $from and $to, i.e. $from=500, $to=999 (absolute values, zero based)
if ($from && $to){
header($_SERVER["SERVER_PROTOCOL"].' 206 Partial Content');
header("Content-Range: bytes $from-$to/$fsize"); // 0-499/1234 or 500-999/1234
# logger("Content-Range: bytes $from-$to/$fsize");
}
};
if ($from && $to){
$cont_size=$to-$from+1;
}else{
$cont_size=$fsize;
}
header("Content-Length: $cont_size");
# logger("Content-Length: $cont_size");
if ($is_save) header("Content-Disposition: attachment; filename=\"$fname\"");
$fp = fopen($path, "rb");
if ($from) fseek($fp, $from, SEEK_SET); //seek to range begin point
if (!$to || $to+1>=$fsize){
fpassthru($fp); //whole or all rest file mode
# logger('PASS THRU!');
}else{
$sent=0;
while( !feof($fp) && !connection_status() && $sent<$cont_size ) {
echo fread($fp, $CHUNK_SIZE);
$sent+=$CHUNK_SIZE;
flush();
# logger('CHUNK SENT!');
sleep(1);
}
}
fclose ($fp);
}
?>