Forced Download of a file like a .vcf
8 posts by 3 authors in: Forums > CMS Builder
Last Post: April 16, 2013 (RSS)
I've seen a few examples of php and .htaccess 'auto' or 'forced' download codes but can't seem to integrate them into my pages - or else it wants to download the entire page ( my ignorance in coding )
I want ( in this case ) the link to download the Contact Card, not display the code in the browser - ( or make the world change their browser settings )
So if I have this code:
<?php foreach ($attorneysRecord['vcard'] as $index => $upload): ?>
and php header of
<a href="<?php echo $upload['urlPath'] ?>"><img src="../images/vcard_logo.jpg" width="31" height="24" alt="Vcard" /></a>
<?php endforeach ?>
<?php header('Content-type: text/html; charset=utf-8'); ?>
What do I need?
As always, thanks for your help
Hi,
To force a user to download a file instead of viewing it, you need to change the header of your page to tell the browser that the file needs downloading. The best way to do this is to create a custom download page.
First I would create a separate multi record section to store the vcards in, with an upload field that allows one upload per record. Otherwise you have to let the download script have direct access to the download section which could be unsafe.
The download list page could look something like this:
<?php header('Content-type: text/html; charset=utf-8'); ?>
<?php
/* STEP 1: LOAD RECORDS - Copy this PHP code block near the TOP of your page */
// load viewer library
$libraryPath = 'cmsAdmin/lib/viewer_functions.php';
$dirsToCheck = array('C:/wamp/www/','','../','../../','../../../');
foreach ($dirsToCheck as $dir) { if (@include_once("$dir$libraryPath")) { break; }}
if (!function_exists('getRecords')) { die("Couldn't load viewer library, check filepath in sourcecode."); }
$whereString = '';
// load record from 'vcards'
list($vcards, $blogMetaData) = getRecords(array(
'tableName' => 'vcards',
'where' => $whereString,
'allowSearch' => false,
));
//List all of the vcards with uploads
foreach($vcards as $record){
if($upload = (@$record['uploads'][0])){
echo '<a href="download.php?num='.$record['num'].'" >'.$upload['info1'].'</a><br>';
}
}
So the script grabs all of the records for the vcards section, checks if the record has an uploaded file, and if it does it displays the download link, it's also passing over the vcards num value in the URL.
Next you need to create the download script, you can read more on how the system works here:
http://php.net/manual/en/function.readfile.php
The script should look something like this:
<?php header('Content-type: text/html; charset=utf-8');
// load viewer library
$libraryPath = 'cmsAdmin/lib/viewer_functions.php';
$dirsToCheck = array('C:/wamp/www/','','../','../../','../../../');
foreach ($dirsToCheck as $dir) { if (@include_once("$dir$libraryPath")) { break; }}
if (!function_exists('getRecords')) { die("Couldn't load viewer library, check filepath in sourcecode."); }
// load file
$productNum = (int) @$_REQUEST['num'];
list($fileRecords, $filesMetaData) = getRecords(array(
'tableName' => 'vcards',
'where' => whereRecordNumberInUrl(0),
'loadCreatedBy' => false,
'allowSearch' => false,
));
$file = @$fileRecords[0];
// get download path
$filePath = '';
if (is_array( @$file['uploads'] )) {
$download = array_pop($file['uploads']);
$filePath = $download['filePath'];
}
// error checking
$filesize = @filesize($filePath);
if (!$file) { die("Error: No file matches that record number!"); }
if (!$filePath) { die("Error: Can't find download file!"); }
if (!file_exists($filePath)) { die("Error: Filepath doesn't exist!"); }
if (!$filesize) { die("Error: File is zero bytes!"); }
// send download
header('Content-Description: File Transfer'); // headers from http://us3.php.net/manual/en/function.readfile.php
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' .basename($filePath). '"');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . $filesize);
readfile($filePath);
exit;
?>
The download script checks if there is a number value in the URL, and gets the appropriate vcard entry from the vcards section. Then it checks if there is an associated fie, finally the script creates the download headers.
I've attached the download script to this post.
Let me know if you have any questions.
Thanks!
Greg
PHP Programmer - interactivetools.com
That's one of the most complete solutions ever answered!
I have one slight twist on it however. Law Firm website, and the vcard is on a details page. For each person -one image, one vcard, one description etc
Here is a build page in progress http://khwebtemp.com/html/attorneys_details.php?Jeffrey-D.-Horst-1
Thanks as always,
Sean
Hi Sean,
The easiest way around this would be to add a drop-down list field to the person section where you can assign a vcard record to them. You can read how to do this here:
http://interactivetools.com.cmsb.me/kb/article.php?Populate-a-list-field-from-another-section-15
If you use the num field for the option values, then you can could create the download link like this:
<a href="download.php?num=<?php echo $attorneysRecord[' listFieldName']; ?>">Download Vcard</a>
Thanks!
Greg
PHP Programmer - interactivetools.com
<Files *.vcf>
ForceType application/octet-stream
Header set Content-Disposition attachment
</Files>
I ended up using .htaccess, not sure if it has problems but it certainly is the short answer......
I thank you for your help.
By Mikey - April 15, 2013
Greg,
Got any suggestions on how I can get to work on a category list page where as each category listed may have multiple downloadable files?
Thanks Zick
By Mikey - April 15, 2013
I'm trying to reproduce the force download to work with a "List Page Viewer", but using the code provided in this thread only produces results for the latest document uploaded and not multiple instances of each document uploaded per record.
Can anyone provide some guidance, suggestions or assistance with this so I can show all documents uploaded per record and make the force download work on all document uploads? Below is my code:
<?php header('Content-type: text/html; charset=utf-8'); ?>
<?php
// load viewer library
$libraryPath = 'cmsbuilder/lib/viewer_functions.php';
$dirsToCheck = array('/var/www/host/00.00.000.00/httpdocs/domain/','','../','../../','../../../');
foreach ($dirsToCheck as $dir) { if (@include_once("$dir$libraryPath")) { break; }}
if (!function_exists('getRecords')) { die("Couldn't load viewer library, check filepath in sourcecode."); }
// load records from 'white_papers'
list($white_papersRecords, $white_papersMetaData) = getRecords(array(
'tableName' => 'white_papers',
'loadUploads' => true,
'allowSearch' => false,
));
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
</head>
<body>
<h1>White Papers - List Page Viewer</h1>
<?php foreach ($white_papersRecords as $record): ?>
<h3><?php echo htmlencode($record['name']) ?></h3>
Content: <?php echo $record['content']; ?><br/>
<?php foreach ($record['documents'] as $index => $upload): ?>
<p><?php if($upload = (@$record['documents'][0])) {
echo '<a href="white_paper_downloads.php?num='.$record['num'].'" >'.$upload['info1'].'</a><br>'; } ?></p>
<?php endforeach ?>
<hr/>
<?php endforeach ?>
<?php if (!$white_papersRecords): ?>
No White Papers were found!<br/><br/>
<?php endif ?>
</body>
</html>
<?php header('Content-type: text/html; charset=utf-8'); ?>
<?php
// load viewer library
$libraryPath = 'cmsbuilder/lib/viewer_functions.php';
$dirsToCheck = array('/var/www/host/00.00.000.00/httpdocs/domain/','','../','../../','../../../');
foreach ($dirsToCheck as $dir) { if (@include_once("$dir$libraryPath")) { break; }}
if (!function_exists('getRecords')) { die("Couldn't load viewer library, check filepath in sourcecode."); }
// load file
$fileNum = (int) @$_REQUEST['num'];
list($fileRecords, $filesMetaData) = getRecords(array(
'tableName' => 'white_papers',
'where' => whereRecordNumberInUrl(0),
'loadCreatedBy' => false,
'allowSearch' => false,
));
$file = @$fileRecords[0];
//$file = @$fileRecords;
// get download path
$filePath = '';
if (is_array( @$file['documents'] )) {
$download = array_pop($file['documents']);
$filePath = $download['filePath'];
}
// error checking
$filesize = @filesize($filePath);
if (!$file) { die("Error: No file matches that record number!"); }
if (!$filePath) { die("Error: Can't find download file!"); }
if (!file_exists($filePath)) { die("Error: Filepath doesn't exist!"); }
if (!$filesize) { die("Error: File is zero bytes!"); }
// send download
header('Content-Description: File Transfer'); // headers from http://us3.php.net/manual/en/function.readfile.php
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' .basename($filePath). '"');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . $filesize);
readfile($filePath);
exit;
?>
By gregThomas - April 16, 2013
HI Zick.
I've spotted the problem, and amended the code below:
<?php header('Content-type: text/html; charset=utf-8'); ?>
<?php
// load viewer library
$libraryPath = 'cmsbuilder/lib/viewer_functions.php';
$dirsToCheck = array('/var/www/host/00.00.000.00/httpdocs/domain/','','../','../../','../../../');
foreach ($dirsToCheck as $dir) { if (@include_once("$dir$libraryPath")) { break; }}
if (!function_exists('getRecords')) { die("Couldn't load viewer library, check filepath in sourcecode."); }
// load records from 'white_papers'
list($white_papersRecords, $white_papersMetaData) = getRecords(array(
'tableName' => 'white_papers',
'loadUploads' => true,
'allowSearch' => false,
));
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
</head>
<body>
<h1>White Papers - List Page Viewer</h1>
<?php foreach ($white_papersRecords as $record): ?>
<h3><?php echo htmlencode($record['name']) ?></h3>
Content: <?php echo $record['content']; ?><br/>
<?php foreach ($record['documents'] as $index => $upload): ?>
<p><a href="white_paper_downloads.php?num=<?php echo $record['num']; ?>" ><?php echo $upload['info1']; ?></a><br>'; ?></p>
<?php endforeach ?>
<hr/>
<?php endforeach ?>
<?php if (!$white_papersRecords): ?>
No White Papers were found!<br/><br/>
<?php endif ?>
</body>
</html>
The problem is that the $upload variable in the foreach loop was being overwritten by the second $upload with this if statement: if($upload = (@$record['documents'][0])) { .
It looks as if you might also have to change the code for the download system as well, as at the moment it looks as if it just downloads the first file in the record as opposed to selecting the file that the user has selected.
Let me know if you have any questions.
Thanks!
Greg
PHP Programmer - interactivetools.com