http force headers not working with above < 2GB files - php

I have a script which is used to download large files in pdf and media format. I can't download it it gives http internal error sometimes it give 500 internal server error sometimes.
<?php
//The directory where the download files are kept - keep outside of the web document root
$strDownloadFolder = "uploads/";
//If you can download a file more than once
$boolAllowMultipleDownload = 0;
// 1. Create a database connection
//connect to the DB
$resDB = mysql_connect("localhost", "root", "");
mysql_select_db("downloader", $resDB);
if(!empty($_GET['key'])){
//check the DB for the key
$resCheck = mysql_query("SELECT * FROM downloads WHERE downloadkey = '".mysql_real_escape_string($_GET['key'])."' LIMIT 1");
if($resCheck == FALSE) { echo "QUERY FAILED: " . mysql_error(); }
$arrCheck = mysql_fetch_assoc($resCheck);
if(!empty($arrCheck['file'])){
//check that the download time hasnt expired
if($arrCheck['expires']>=time()){
if(!$arrCheck['downloads'] OR $boolAllowMultipleDownload){
//everything is hunky dory - check the file exists and then let the user download it
$strDownload = $strDownloadFolder.$arrCheck['file'];
if(file_exists($strDownload)){
//get the file content
$strFile = file_get_contents($strDownload);
//set the headers to force a download
header("Content-type: application/force-download");
header("Content-Disposition: attachment; filename=\"".str_replace(" ", "_", $arrCheck['file'])."\"");
//echo the file to the user
echo $strFile;
//update the DB to say this file has been downloaded
mysql_query("UPDATE downloads SET downloads = downloads + 1 WHERE downloadkey = '".mysqli_real_escape_string($_GET['key'])."' LIMIT 1");
exit;
}else{
echo "We couldn't find the file to download.";
}
}else{
//this file has already been downloaded and multiple downloads are not allowed
echo "This file has already been downloaded.";
}
}else{
//this download has passed its expiry date
echo "This download has expired.";
}
}else{
//the download key given didnt match anything in the DB
echo "No file was found to download.";
}
}else{
//No download key wa provided to this script
echo "No download key was provided. Please return to the previous page and try again.";
}
?>
Since http force headers are not working for larger files... I wanna use href with download attribute so when user clicks on it it should have direct encrypted link! with token or limited session!

file_get_contents reads the entire file into memory. If the file is larger than the available memory, it fails.
Instead you can read the file contents directly to the output stream:
//read whole file into memory, whoops
//$strFile = file_get_contents($strDownload);
//set the headers to force a download
header("Content-type: application/force-download");
header("Content-Disposition: attachment; filename=\"".str_replace(" ", "_", $arrCheck['file'])."\"");
//read file to output stream
readfile($strDownload);
http://php.net/manual/en/function.readfile.php

Related

How can i do something after my header in php?

I want that my script will be executed after downloading a file so in the first part of this code it will get the .txt file and change word license to the database result, then i want that the download starts and after that i want to clear the .txt file for the next use. If i write it as below i don't get the database result in the text file because it executes first the whole code before it downloads. If i remove the last part it all works but it wont reset the text.
<?php
$userID= $_SESSION['user_id'];
$license=$dbConnection->getOne("SELECT license FROM valid_license where discordid = '$userID' ");
$license2 = $license['license'];
$zip = new ZipArchive;
$fileToModify = 'license.txt';
if ($zip->open('test.zip') === TRUE) {
$oldContents = $zip->getFromName($fileToModify);
$newContents = str_replace('license', $license2, $oldContents);
$zip->deleteName($fileToModify);
$zip->addFromString($fileToModify, $newContents);
$zip->close();
echo 'ok';
} else {
echo 'failed';
}
header("Location: test.zip");
$userID= $_SESSION['user_id'];
$license=$dbConnection->getOne("SELECT license FROM valid_license where discordid = '$userID' ");
$license2 = $license['license'];
$zip = new ZipArchive;
$fileToModify = 'license.txt';
if ($zip->open('test.zip') === TRUE) {
$oldContents = $zip->getFromName($fileToModify);
$newContents = str_replace($license2, 'license', $oldContents);
$zip->deleteName($fileToModify);
$zip->addFromString($fileToModify, $newContents);
$zip->close();
echo 'ok';
} else {
echo 'failed';
}
?>
There are two potential reasons why this is happening:
Your web server is waiting for PHP to finish executing before serving any response to the user, so the second half is overwriting the zip file before the header is ever sent.
Your web server is sending the Location: header without delay, but also your PHP code is still executing while that response and the subsequent request are in-flight, overwriting the data before the request for the file comes back.
Either of those will break your intended flow.
Instead of using a Location: header, set the appropriate Content-Type: header for a zip file, dump the data out to the user, and then clean up the file.
header("Content-Type: application/zip");
header("Content-Disposition: attachment; filename=$file_name");
header("Content-Length: " . filesize($yourfile));
readfile($yourfile);
Additionally, do not modify the original zip file like this. If you get two overlapping requests you'll wind up either serving the wrong license, or just corrupt the file for one or both or all subsequent.
Make a copy, modify the copy, serve the copy, delete the copy.

how to convert page to pdf in php

I have an html page like JsFiddle and I want convert this in pdf, i can't create the line to line pdf because the page is dinamically create, I use php for calling a fiel that connect to mysql and fill a template file like.
$_POST['IdQuestionario']=5;
$_POST['IdUtente']=10001;
$_POST['Visualizza']=true;
$_POST['IdImpianto']=1;
$_POST['Stampa']=true;
$_POST['TipoImpianto']='grande';
ob_start();
ob_clean();
require_once 'intro.php';
$tbl=ob_get_clean();
$html.=$tbl;
I'm trying with tcpf, mpdf , jsPDF but i cant obtain a discrete output because I use colgroup for table. anyone say me a method for render the page,if is possible whitout install software on server.
There a few that i know of - some have problems with tables, I would avoid DOMPDF - known issues with tables.
There's one that's recommended from cvision; i don't have a code sample, but you can download it free and even sample it online.
There's also a php-pdf product available from muhimbi (a little lesser-known!, but i think it's free)
<?php
// Include the generated proxy classes
require_once "documentConverterServices.php";
// Check the uploaded file
if ($_FILES["file"]["error"] > 0)
{
echo "Error uploading file: " . $_FILES["file"]["error"];
}
else
{
// Get the uploaded file content
$sourceFile = file_get_contents($_FILES["file"]["tmp_name"]);
// Create OpenOptions
$openOptions = new OpenOptions();
// set file name and extension
$openOptions->FileExtension = pathinfo($_FILES["file"]["name"], PATHINFO_EXTENSION);
$openOptions->OriginalFileName = $_FILES["file"]["name"];
// Create conversionSettings
$conversionSettings = new ConversionSettings();
// Set the output format
if(isset($_POST["outputFormat"]))
{
$conversionSettings->Format = $_POST["outputFormat"];
} else {
$conversionSettings->Format = "PDF";
}
// Set fidelity
$conversionSettings->Fidelity = "Full";
// These values must be set to empty strings or actual passwords when converting to non PDF formats
$conversionSettings->OpenPassword="";
$conversionSettings->OwnerPassword="";
// Set some of the other conversion settings. Completely optional and just an example
$conversionSettings->StartPage = 0;
$conversionSettings->EndPage = 0;
$conversionSettings->Range = "VisibleDocuments";
$conversionSettings->Quality = "OptimizeForPrint";
$conversionSettings->PDFProfile = "PDF_1_5";
$conversionSettings->GenerateBookmarks = "Automatic";
$conversionSettings->PageOrientation="Default";
// Create the Convert parameter that is send to the server
$convert = new Convert($sourceFile, $openOptions, $conversionSettings);
// Create the service client and point it to the correct Conversion Service
$url = "http://localhost:41734/Muhimbi.DocumentConverter.WebService/?wsdl";
$serviceClient = new DocumentConverterService(array(), $url);
// If you are expecting long running operations then consider longer timeouts
ini_set('default_socket_timeout', 60);
try
{
// Execute the web service call
$result = $serviceClient->Convert($convert)->ConvertResult;
// Send the resulting file to the client.
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"convert." . $conversionSettings->Format . "\"");
echo $result;
}
catch (Exception $e)
{
print "Error converting document: ".$e->getMessage();
}
}
?>
Also, you could investigate 'Snappy' (has dependencies)
You can try WKHTMLTOPDF.
Here is a Stackoverflow Thread on how to use it with PHP.
How do I get WKHTMLTOPDF to execute via PHP?
And here is a wrapper for PHP
https://github.com/mikehaertl/phpwkhtmltopdf
MPDF one of best library to convert pdf, try it
MPDF link : http://www.mpdf1.com/mpdf/index.php
Example link : http://mpdf1.com/common/mpdf/examples/

Restrict access of an uploaded file to only the original author in a web application

Ex: a user login to a website and uploads a profile pic. I want to restrict the access to only allow the user that uploads the pic gets to have access.
So, if a second person somehow gets the URL to the pic, he or she still can not access it because she or he doesn't have the right permission(https://example.com/profile_pic_mike_1). Right now i have it so that the user can upload a profile pic but then anyone that has the URL are able to type in the browser and see the pic. I dont want that.
This is a project for fun so all suggestions are welcome.
Create a script that's only accessible to logged in users. Have that script fetch the image and display on screen.
Your users access the following url:
example.com/image.php?name=image
You then have image.php fetch the file from disk/database, and return it to the user. A quick example assuming you're working with jpeg images (excluding error checking):
<?php
if(!logged_in())
die('Unauthorized');
$filename = '/path/to/images/' . $_GET['name'];
$handle = fopen($filename, "rb");
$contents = fread($handle, filesize($filename));
fclose($handle);
header('content-type: ' . image_type_to_mime_type(IMAGETYPE_JPEG));
echo $contents;
Other image mime types can be found here: image_type_to_mime_type
You can code a PHP file that will check if user is logged in, or if users have the permission to access the file.
I'll assume your public directory is public_html.
For the storage of images, you'll need to store them outside of the public directory (public_html).
Example Code (e.g. image.php?file=profile_pic_mike_1). image.php is in public_html and profile_pic_mike_1 will be in the directory that is not accessible to the public.
<?php
// checking for $_SESSION, change accordingly to your method
session_start();
if(!$_SESSION['logged_in']){
session_destroy();
header("Location:index.php");
}
// $_GET['file'] will be profile_pic_mike_1
if(isset($_GET['file'])){
$file_dir = "../";
$file = $file_dir . $_GET["file"];
// get if user has the permission
// if yes, assign `true` to $permission ($permission = true;)
if (!file_exists($file)) {
echo "File not found.";
} else if (!$permission) {
echo "You do not have the permission to view this image.";
} else {
// You'll need to change the Content-type accordingly
header("Content-type: image/png");
readfile($file);
exit;
}
}
?>
List of Content-type for images: http://php.net/manual/en/function.image-type-to-mime-type.php.
You'll need to check if the user has the permission to view the file, one way to do it by saving the permissions in a MySQL DB.
You'll have to write the functions and flesh out a bit, but it gives you an idea:
<?php
$username = get_username_from_url();
$user = get_logged_in_user();
if(!$user || ($username !== $user->name)) {
// access denied, send appropriate header and exit.
}
// keep your images outside your web root (not public).
// e.g. /path/to/app/data/uploads/unique_id.jpg
$avatar_path = get_avatar_file_path_by_user($user);
// send image file
header("Content-type: image/jpeg"); // or appropriate content type.
readfile($avatar_path);

error while downloading file in PHP

while downloading file im getting this error. specially pdf files.
and also program like download manger doesn't work on the downloading.
v?—x¢b(‏°®ه– ç‏zٍڈà÷µï½zTَکêùQïىxùSَ–‏jîآ·×Yï¹oف5KK÷¾oصتمح+¾¦œ:و†ƒloوnأ"گ ±Oّ•زـ¦§w8^uLٹé†-ئûpfچâ+أجشƒœر د؛-ںe•ؤ…¬RH¦ hْDyے#½=#'X'§¾ذXœtz”†رص0âLوٍ›“ء²{÷ڈے ½}f؛ِâB¦ک­ژ¯“كگyeطPeüpy,¥¼تِŒً•MR±wگCي¢âٹ‘¬}Fzى3¢e¾NAو^4è¬{j=¤ر³جسâل<¶–5Mz&#+­MYN1ُ¨Cںq)زêذش£M nj‍]T‡à*×h0ï3D¤­6غإQ.µg¬€ء¥w«ي|م+s“çكûmٍاe¯Œغ½وؤ~لà…½ں$/‡ھ(!·#‡]µظtحîز4»CQeں[°ظ5گ+è’ہù4›MQd™#ں|‡فژd؟×ë×F*xز‘ ¹’پ÷i·?ù×ـسخ½Mأ}ق¸َOe$ِ à'ظgءl”ƒ=fRن(rإهـPy¨2ش2ج:طQî49œt رA3kfفذ’){¯'7ذE=»نx¾ةLb|‘شاـ×s ل‡ةأجô‰—ثSùy¦y†uھc>‍ا/’›Zç9Vٍ·بش&¸ةq“s؟Yعlzگïگ_v¼ئ؟!؟د h=لّ’ےJ‏تْ…£ںبb÷U;Lآڑ›eڑƒ¨}كFپ ں›Uنvi>“]¤vçW†•Bڑˆˆ´!ج=¥4†é1حز ہحٹ‚é?“ل¢qع¬ ض4‹فلtڑgؤbوT§ةŒEچ8“س©#ôںآ‹EW9—ھr ‘8ژ§¦z$»±¸SW •¨xضث؛i›©سؤ™:pا¾YهسaکؤvC«صژkœچ “ژr\îW"Tùؤ'œ¥<غàû<§«،«ئ¶ —ًيFل¥رکً³ظ(WVتG{i®> stream xœه]ëڈeإqXXVثs1ث‚¹ ;†¹ôûAâDٹEت7[Hùùd'N"ضر’ے_JUWَُô¹sg¦w±#ygخمVWuWWW?~Oâ(صAàü‏ةف¯çüك»éد‡ےxW‏ë®4ٌ£;Hkز؟ے_ؤƒSر~ü÷»ےQ‍pئ¨C0؛{,=ƒ=َù‰ég”qً?™ïH،l{[:گJ›‏Uي¢؛ٍص,أوm)¤>ٌ6ف‍ے°R:^ùêî[ثٹ3¢¾m…ƒضŒ‡ إVeززF{{0BM‍ˆڑں°îùخVيئ[ّ هYPüG6Eàغn{[£´Rآدù•د¥·ءىفس¾¸÷‍‹~÷=ِ/
here is my php code for downloading
<?php
$company =$_GET['company'];
// Make sure an ID was passed
if(isset($_GET['id'])) {
// Get the ID
$id = intval($_GET['id']);
// Make sure the ID is in fact a valid ID
if($id <= 0) {
die('The ID is invalid!');
}
else {
// Connect to the database
$dbLink = new mysqli('localhost', 'sqldata', 'sqldata', 'balhaf');
if(mysqli_connect_errno()) {
die("MySQL connection failed: ". mysqli_connect_error());
}
// Fetch the file information
$query = "
SELECT mime, name, size, data
FROM $company
WHERE id = $id";
$result = $dbLink->query($query);
if($result) {
// Make sure the result is valid
if($result->num_rows == 1) {
// Get the row
$row = mysqli_fetch_assoc($result);
// Print headers
header("Content-Type: ". $row['mime']);
header("Content-Length: ". $row['size']);
header("Content-Disposition: attachment; filename=". $row['name']);
// Print data
echo $row['data'];
}
else {
echo 'Error! No image exists with that ID.';
}
// Free the mysqli resources
#mysqli_free_result($result);
}
else {
echo "Error! Query failed: <pre>{$dbLink->error}</pre>";
}
#mysqli_close($dbLink);
}
}
else {
echo 'Error! No ID was passed.';
}
?>
use BLOB in MySQL to prevent that the data is changed due to the encoding (there might be encoding issues which produce your errors, saving as BLOB is binary safe)
related to Binary Data in MySQL
it may be better to store a link as file reference in the database instead of saving the actual content of the file and retrieve the files using file_get_contents and other related functions to get the mimetype (or finfo) ...
take a look at Trying to download Blob via PHP / MySQL and http://www.sitepoint.com/forums/showthread.php?693871-Problem-using-PHP-to-pull-binary-files-from-a-BLOB-field-in-MYSQL
Try flushing the output buffer immediately before you start setting headers with ob_end_clean, and then exiting immediately after the echo. Take a look at the section of the PHP book on Output Control.
The other possibility is that you are running out of memory when attempting to echo the data, and the error is getting obfuscated by all the preceding binary. Try splitting the binary in to smaller chunks (substr is binary safe), iterating over them and returning them to the output buffer.

Why do images served from my web server not cache on the client?

I store all of my images behind the webroot (before /var/www/), which means that the web server is unable to send cache headers back for my pictures. What do I need to add to this to make the user's web cache work? Currently, this is getting hit every time by the same browser.
My <img> path on my pages look something like this:
<img src="pic.php?u=1134&i=13513&s=0">
Edit: Could it be that it is because "pic.php?u=1134&i=13513&s=0" is not a valid file name or something?
// pic.php
<?php
// open the file in a binary mode
$user = $_GET['u'];
$id = $_GET['i'];
$s = $_GET['s'];
if (!isset($user) && !isset($s) && $isset($id))
{
// display a lock!
exit(0);
}
require_once("bootstrap_minimal.php"); //setup db connection, etc
// does this image_id belong to the user?
$stmt = $db->query('SELECT image_id, user_id, file_name, private FROM images WHERE image_id = ?', $id);
$obj = $stmt->fetchObject();
if (is_object($obj))
{
// is the picture is the users?
if ($obj->user_id != $_SESSION['user_id'])
{
// is this a private picture?
if ($obj->private == 1)
{
// check permissions...
// display a lock in needed!
}
}
}
else
{
// display a error pic?!
exit(0);
}
if ($s == 0)
{
$picture = $common->getImagePathThumb($obj->file_name);
}
else
{
$picture = $common->getImagePath($obj->file_name);
}
// send the right headers
header("Content-Type: image/png");
header("Content-Length: " . filesize($picture));
$fp = fopen($picture, 'rb');
// dump the picture and stop the script
fpassthru($fp);
exit;
?>
You need to add something like:
$expiry = 3600*24*7; // A week
header('Expires: ' . gmdate('D, d M Y H:i:s' time() + $expiry) . ' GMT');
header('Cache-control: private, max-age=' . $expiry);
Apache only caches static files by default. You need to send a cache control header via the header() function. This article has a lot of information on the topic.
Alternatively, you could use the PHP file to redirect to the actual location of the image. (This is probably the easiest way if you don't know anything about headers.)
You might try:
header("Cache-Control: max-age=3600");
That should send a cache timeout of one hour on the file.
What I would do in your situation is to stream the bytes of the image using a .php file. Don't link to images directly; instead, link to a php file that:
- outputs the cache headers
- reads the file off of disk, from behind the webroot
- sends the image bits down the wire
Simple answer: you aren't telling your users' browser to cache it

Categories