#!./php-exec "3 weeks", "/.*\.rpm/i" => "3 weeks", "/.*\.xml.gz/i" => "12 hours", "/.*\.xml/i" => "12 hours", "/.*\.rdf/i" => "12 hours"); reset($FileTypes); while (list($Index, $Values) = each($FileTypes)) { $Results = preg_match($Index, $FileName, $Matches); if ($Results) { return($Values); } } return("unknown"); } function GetMimeType($FileName) { $FileTypes = array("/.*\.png$/i" => "image/png", "/.*\.rpm/i" => "application/x-rpm", "/.*\.xml.gz/i" => "application/x-gzip", "/.*\.xml/i" => "text/xml", "/.*\.rdf/i" => "text/plain"); # .rpm should be application/x-rpm, but ximian uses application/x-pn-realaudio-plugin reset($FileTypes); while (list($Index, $Values) = each($FileTypes)) { $Results = preg_match($Index, $FileName, $Matches); if ($Results) { return($Values); } } return("text/html"); } function GenerateETag($FileName) { # clearstatcache(); $FileStat = stat($FileName); $ETag = "" . dechex($FileStat["ino"]) . "-" . dechex($FileStat["size"]) . "-" . dechex($FileStat["mtime"]); return($ETag); } # info from http://www.experts-exchange.com/Web/Web_Languages/PHP/Q_20181691.html function SendFile($FileName) { global $DataRangeStart, $DataRangeEnd, $ActualDataRangeEnd; $BlockSize = 4096; $ShortName = basename($FileName); $Length = filesize($FileName); $FileStat = stat($FileName); # ETag: "??????-FSize_hex-???????? header("ETag: " . GenerateETag($FileName)); header("Accept-Ranges: bytes"); header("Content-Length: $Length"); header("Connection: close"); header("Content-Type: " . GetMimeType($FileName)); #header("content-disposition: attachment; filename=$filename"); $FilePointer = fopen($FileName, "rb"); if ($DataRangeEnd == 0) $ActualDataRangeEnd = $Length; else $ActualDataRangeEnd = $DataRangeEnd; if ($DataRangeStart != 0) fseek($FilePointer, $DataRangeStart); $CurrentLocation = ftell($FilePointer); if ($CurrentLocation + $BlockSize > $ActualDataRangeEnd) $BlockSize = $ActualDataRangeEnd - $CurrentLocation; while ($Buffer = fread($FilePointer, $BlockSize)) { echo $Buffer; flush(); $CurrentLocation = ftell($FilePointer); if ($CurrentLocation + $BlockSize > $ActualDataRangeEnd) { $BlockSize = $ActualDataRangeEnd - $CurrentLocation; } } # looks like speed can be limited somewhat by freading and sleeping: # http://www.php.net/manual/en/function.fread.php } function LogData($Data) { global $LogFile, $PID, $RemoteIP; $Date = date("Y-m-d-H:i:s"); $AppendString = "$Date - pid:$PID - $RemoteIP - "; fputs($LogFile, $AppendString . $Data . "\n"); fflush($LogFile); } function OldDownloadFile($RemoteFileName, $LocalFileName) { global $BaseDir, $TempDir; # $RemoteFile = fopen("http://red-carpet.ximian.com/$RequestedFileName", "rb"); $RemoteFile = fopen($RemoteFileName, "rb"); $TempFileName = tempnam($TempDir, "Download-"); $LocalFile = fopen($TempFileName, "w"); while (!feof($RemoteFile)) { $Data = fread($RemoteFile, 10240); fwrite($LocalFile, $Data); } fclose($RemoteFile); fclose($LocalFile); $ToDir = dirname($LocalFileName); if (!file_exists($ToDir)) { mkpath($ToDir, 0755); } # copy($TempFileName, $ToLocation); copy($TempFileName, $LocalFileName); unlink($TempFileName); } function DownloadFile($RemoteFileName, $LocalFileName) { global $BaseDir, $TempDir; $TempFileName = tempnam($TempDir, "Download-"); $LocalFile = fopen($TempFileName, "w"); # here, we download the file # $fp = fopen("$TempFileName", "w"); $ch = curl_init("$RemoteFileName"); curl_setopt($ch, CURLOPT_FILE, $LocalFile); # curl_setopt($ch, CURLOPT_HEADER, 0); # curl_setopt($ch, CURLOPT_NOBODY, 0); # curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $Result = curl_exec($ch); curl_close($ch); fclose($LocalFile); $ToDir = dirname($LocalFileName); if (!file_exists($ToDir)) mkpath($ToDir, 0755); copy($TempFileName, $LocalFileName); unlink($TempFileName); } function DownloadAndSendFile($RemoteFileName, $LocalFileName) { global $BaseDir, $TempDir, $DataRangeStart, $DataRangeEnd; $BlockSize = 4096; $ETag = DownloadETag($RemoteFileName); $Length = hexdec($ETag[size]); if ($DataRangeEnd == 0) $ActualDataRangeEnd = $Length; else $ActualDataRangeEnd = $DataRangeEnd; $LengthSent = $ActualDataRangeEnd - $DataRangeStart; header("ETag: " . $ETag); header("Accept-Ranges: bytes"); header("Content-Length: $LengthSent"); header("Connection: close"); header("Content-Type: " . GetMimeType($LocalFileName)); $TempFileName = tempnam($TempDir, "Download-"); $TempFile = fopen($TempFileName, "w"); $RemoteFile = fopen($RemoteFileName, "rb"); if (! $RemoteFile) { # header("HTTP/1.1 404 Not Found"); } # LogData("File: $LocalFileName, sending $DataRangeStart - $ActualDataRangeEnd ($DataRangeEnd)"); while ($Buffer = fgets($RemoteFile, $BlockSize)) { $CurrentLocation = ftell($TempFile); # where we started this buffer fwrite($TempFile, $Buffer); # Write to the temp file $StartOffset = $DataRangeStart - $CurrentLocation; $EndOffset = $ActualDataRangeEnd - $CurrentLocation; if ($StartOffset < 0) $StartOffset = 0; if ($EndOffset > $BlockSize) $EndOffset = $BlockSize; #LogData("File: $LocalFileName, CurrentLocation: $CurrentLocation, StartOffset: $StartOffset, EndOffset: $EndOffset"); if ($StartOffset < $BlockSize) { $Buffer = substr($Buffer, $StartOffset, $EndOffset - $StartOffset); } echo $Buffer; flush(); } fclose($TempFile); $ToDir = dirname($LocalFileName); if (!file_exists($ToDir)) mkpath($ToDir, 0755); copy($TempFileName, $LocalFileName); unlink($TempFileName); } function SplitETag($String) { $Pattern = "/([0-9a-f]+)-([0-9a-f]+)-([0-9a-f]+)/"; $Result = preg_match($Pattern, $String, $Matches); if ($Result) return(array("ino" => $Matches[1], "size" => $Matches[2], "mtime" => $Matches[3])); return(array("ino" => 0, "size" => 0, "mtime" => 0)); } function DownloadETag($URL) { # here we get the file headers $ch = curl_init("$URL"); curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLOPT_NOBODY, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $Headers = curl_exec($ch); curl_close($ch); $HeaderArray = explode("\n", $Headers); while ($CurrentHeader = each($HeaderArray)) { # $Pattern = "/ETag: \"([0-9a-f]+)-([0-9a-f]+)-([0-9a-f]+)\"/"; $Pattern = "/ETag: \"([0-9a-f]+-[0-9a-f]+-[0-9a-f]+)\"/"; $Result = preg_match($Pattern, rtrim($CurrentHeader[value]), $Matches); if ($Result) { return(SplitETag($Matches[1])); } # if ($Result) return(array("ino" => $Matches[1], "size" => $Matches[2], "mtime" => $Matches[3]); } return(array("ino" => 0, "size" => 0, "mtime" => 0)); } # This is a print_r that returns the data function My_print_r($Data) { ob_start(); print_r($Data); $Results = ob_get_contents(); ob_end_clean(); return ($Results); } # function to return output of phpinfo function My_phpinfo() { ob_start(); phpinfo(); $Results = ob_get_contents(); ob_end_clean(); return($Results); } $LogFile = fopen($LogFileName, "a"); $LocalFile = "$DataDir" . $RequestedFile; $RemoteFile = "http://" . RewriteHost($RequestedHost) . $RequestedFile; # LogData("$RequestedHost"); if ($DataRangeEnd == 0) $DataRangeString = "($DataRangeStart-)"; else $DataRangeString = "($DataRangeStart-$DataRangeEnd)"; LogData("http://$RequestedHost/$RequestedFile $DataRangeString -> $RemoteFile"); $RemoteETag = array("ino" => 0, "size" => 0, "mtime" => 0); if (! strncmp($RequestedFile, "/control/", 9)) { header("Content-type: text/html"); if (! strncmp($RequestedFile, "/control/phpinfo", 16)) phpinfo(); } else { #$TempLog = fopen("ZZZ", "w"); #$PhpData = My_phpinfo(); #fwrite($TempLog, $PhpData); #fclose($TempLog); if (file_exists($LocalFile)) { $LocalETagString = GenerateETag($LocalFile); $LocalETag = SplitETag($LocalETagString); $CurrentTime = strtotime("now"); $Filectime = filectime($LocalFile); $Filemtime = $LocalETag["mtime"]; $AllowedAge = GetAllowedAge($LocalFile); if ($AllowedAge == "unknown") $AllowedTime = strtotime("-1 day", $CurrentTime); else $AllowedTime = strtotime("-$AllowedAge", $CurrentTime); # LogData("File $RequestedFile has mtime of " . date("Y-m-d-H:i:s", $Filemtime) . ", ctime of " . date("Y-m-d-H:i:s", $Filectime)); if ($Filectime < $AllowedTime) { # File is old enough to check. Test the ETag $RemoteETag = DownloadETag($RemoteFile); # LogData("RemoteETag data: " . $RemoteETag["ino"] . "-" . $RemoteETag["size"] . "-" . $RemoteETag["mtime"] . " (" . date("Y-m-d-H:i:s", hexdec($RemoteETag["mtime"])) . ")"); #LogData("LocalETag data: " . $LocalETag["ino"] . "-" . $LocalETag["size"] . "-" . $LocalETag["mtime"]); # test the etag, and if it's different, delete the file if (($RemoteETag["size"] != $LocalETag["size"]) || ($RemoteETag["mtime"] != $LocalETag["mtime"])) { # LogData("File $RequestedFile is " . ($CurrentTime - $Filemtime) . " seconds old, and ETag has changed. Deleting."); LogData("File $RequestedFile has new ETag. Deleting."); unlink($LocalFile); } } } clearstatcache(); if (! file_exists($LocalFile)) { LogData("Downloading $RemoteFile"); DownloadAndSendFile($RemoteFile, $LocalFile); touch($LocalFile, hexdec($RemoteETag["mtime"])); } else SendFile($LocalFile); } fclose($LogFile); ?>