I already uploaded a file and saved the path into my database, but the problem now is that I can't download it. I have already tested the PHP code and it works, but when I try to download it from the Angular side it doesn't. Instead I get this error in the console:
httpErrorResponse error: SyntaxError: Unexpected token p in JSON at position 0
at JSON.parse (<anonymous>)
at XMLHttpRequest.onLoad (localhost:4200/vendor.js:164415:51)
at ZoneDelegate.invokeTask (localhost:4200/polyfills.js:9799:31)
.........
ANGULAR SERVICE:
public getjointes(filepath:string){
const params = new HttpParams()
.set('filepath', filepath);
return this.http.get(url+'/download.php', {params: params });
}
TYPESCRIPT / function
telecharger(path:string) {
console.log(path);
this.stream.getjointes(path).subscribe(response => {
console.log(response);
});
}
PHP CODE:
$rest = $_GET['filepath'] ;
echo($rest);
$filepath = 'upload/' . $rest;
if (file_exists($filepath)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . basename($filepath));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize('upload/' . $rest));
readfile('upload/' . $rest);
header("Access-Control-Expose-Headers: Content-Disposition");
}
else{
echo ('noo');
}
Ok I'm going to assume the echo statements in your PHP are just for testing, based on the error messages you included in comments.
I think the problem you're having is that Angular assumes the response will be JSON and attempts to parse it. To avoid this behaviour, you can set the responseType parameter to "text" or "blob" (for binary data) in your code:
public getjointes(filepath:string) {
const params = new HttpParams()
.set('filepath', filepath);
return this.http.get(url+'/download.php', {params: params, responseType: "text"});
}
Note that any output before a call to header() will result in the HTTP header not getting set. Your PHP code calls header() after readfile(). That header will be ignored. In addition, if a file is not found you should say so with a proper 404 header. This way your client-side code can respond properly to failures. Your PHP should look like this:
$rest = $_GET['filepath'];
$filepath = 'upload/' . $rest;
if (file_exists($filepath) && is_readable($filepath)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . basename($filepath));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize('upload/' . $rest));
header("Access-Control-Expose-Headers: Content-Disposition");
readfile('upload/' . $rest);
} else {
header("HTTP/1.0 404 Not Found");
}
Related
I want to download a file using PHP from an absolute path using the header() and readfile() methods. It used to work before, but doesn't anymore.
I've tried changing the Content-type, but nothing worked.
$p = $_GET['plugin'];
$v = $_GET['version'];
if (isset($p) && isset($v)) {
if (in_array($p, getPlugins($_SESSION['username']))) {
$url = '/home/uploads/' . $p . '/' . $v . '.jar';
header('Content-Description: File Transfer');
header("Content-type: application/java-archive");
header('Content-Disposition: attachment; filename="' . $p . ' ' . $v . '.jar"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-length: ' . filesize($url));
readfile($url);
//header('Location: plugins.php');
exit();
}
}
It should download the jar file that should be named something like "MyPlugin Snapshot-1.0.0.jar". Instead, it prints the whole jar file to the page (see image)
Try using the following content type:
header("Content-type: application/octet-stream");
Did that do the trick?
I have to trigger a download of a zip file ( The Zip file is inside my data folder).
For this i am using the code,
$file = 'D:\php7\htdocs\Project\trunk\api\data\file.zip';
header('Content-Description: File Transfer');
header('Content-type: application/zip');
header('Content-disposition: attachment; filename=' . basename($file) );
readfile($file);`
This is working in core php as i expected. But when i am using the same code in the Zend prints a content like below,
PKYsVJ)~�� study.xlsPKYsVJs�����+
tutorial-point-Export.xlsPKYsVJn��� 8��Zabc.xlsP
In between the content i can see the name of all files in the zip. But it is not getting downloaded.
After i realised that this is not working i started searching about it and Found some solution from stack over flow
Try 1: Adding different header element and ob functions in every random lines
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: ' . $file_size);
ob_start();
ob_clean();
flush();
All these are tried from different stack overflow Question and answers and have the same result
Try 2:PHP is reading file instead of downloading . This question do not have any accepted answer (He was asking about the core php but i have the same issue with zend only) . I tried all of this but it was not working.
Try 3:Changing the .htaccess . After that i thought it was a problem with my .htaccess and found this answer for changing the .htaccess file.
<FilesMatch "\.(?i:zip)$">
ForceType application/octet-stream
Header set Content-Disposition attachment
</FilesMatch>
This also given me the same result.
Try 4:Using download functions in Zend . I have tried the all the zend functions in the answer of this question. But given me an empty output even the file was not read.
Try 5: Remove all the unwanted spaces before and after the php tag as per the answer
Is there any other way to trigger a download in ZF2 framework?
EDIT
Below is my exact function. This is GET(API) function,
public function getList(){
try{
//here i am getting the zip file name.
$exportFile = $this->getRequest()->getQuery('exportid','');
$file = 'D:\php7\htdocs\Project\trunk\api\data\\' . $exportFile . '.zip';
header('Content-Description: File Transfer');
header('Content-type: application/zip');
header('Content-disposition: attachment; filename=' . basename($file) );
readfile($file);
return new JsonModel(["status"=>"Success"]);
} catch(\Exception $e){
return new JsonModel(["status"=>"Failed"]);
}
}
There are two problems here:
your browser trying to open the file, instead of downloading it.
also, it is not opening the file correctly.
Both point to a Content-Type error. Verify that the Content-Type being received by the browser is correct (instead of being rewritten as, say, text/html).
If it is, change it to application/x-download. This might not work in Internet Explorer, which performs some aggressive Content-Type sniffing. You might try adding a nosniff directive.
Additionally, after a readfile (and you might be forced to return the file's contents instead of readfile()'ing - i.e., return file_get_contents($filename);), you should stop all output with return null;. ZIP file directory is at the very end, so if you attach a JSON message there, you risk the browser neither downloading the file, nor displaying it correctly.
As a last resort, you can go nuclear and do everything yourself. Extremely non-elegant, and all frameworks ought to provide an alternative, but just in case...
// Stop *all* buffering
while (ob_get_level()) {
ob_end_clean();
}
// Set headers using PHP functions instead of Response
header('Content-Type: application/x-download');
header('X-Content-Type-Options: nosniff');
header('Content-Length: ' . filesize($filename));
header('Content-Disposition: attachment; filename="whatever.zip"');
die(readfile($filename));
It's possible that some creative use of atexit handlers or destructor hooks might mess up even this last option, but I feel it's unlikely.
Based on this SO answer, you can try the following modification to your function.
public function getList(){
try{
//here i am getting the zip file name.
$exportFile = $this->getRequest()->getQuery('exportid','');
$file = 'D:\php7\htdocs\Project\trunk\api\data\\' . $exportFile . '.zip';
if (file_exists($file)) {
$response = new \Zend\Http\Response\Stream();
$response->setStream(fopen($file, 'r'));
$response->setStatusCode(200);
$response->setStreamName(basename($file));
$headers = new \Zend\Http\Headers();
$headers->addHeaders(array(
'Content-Description' => 'File Transfer',
'Content-Disposition' => 'attachment; filename="' . basename($file) .'"',
'Content-Type' => 'application/zip',
'Content-Length' => filesize($file)
));
$response->setHeaders($headers);
return $response;
//return new JsonModel(["status"=>"Success"]);
} else {
return new JsonModel(["status"=>"Failed. No such file in \"".$file."\""]);
}
} catch(\Exception $e){
return new JsonModel(["status"=>"Failed"]);
}
}
This worked for me!
ob_clean(); // Clear any previously written headers in the output buffer
$filepath = "some_file.zip";
$content_type = 'application/octet_stream';
$filetype = filetype($filepath);
$filename =$filepath;
if($filetype=='application/zip')
{
if(ini_get('zlib.output_compression'))
ini_set('zlib.output_compression', 'Off');
$fp = #fopen($filepath, 'rb');
if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE"))
{
header('Content-Type: '.$content_type);
header('Content-Disposition: attachment; filename="'.$filename.'"');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-Transfer-Encoding: binary");
header('Pragma: public');
header("Content-Length: ".filesize(trim($filepath)));
}
else
{
header('Content-Type: '.$content_type);
header('Content-Disposition: attachment; filename="'.$filename.'"');
header("Content-Transfer-Encoding: binary");
header('Expires: 0');
header('Pragma: no-cache');
header("Content-Length: ".filesize(trim($filepath)));
}
fpassthru($fp);
fclose($fp);
}
If you correct the capitalisation of the headers does it work? ie use Content-Disposition and Content-Type over Content-disposition and Content-type respectively?
Regardless, as standard debugging technique I would suggest using your browser dev tools to inspect the requests that are being made (inc headers) and comparing that to what ends up in your serverside code, and what is in the server side response and what ends up in the client. I would also validate this using a private-session (Incognito mode in Chrome etc) or a fresh profile / VM install just to eliminate anything else.
Also, why not use xsendfile and delegate the responsibility of sending the file to the web server so you aren't incurring the responsibility in your PHP code? You can do this with appropriate server configuration (sometimes through .htaccess, but in this day and age surely you have complete control anyway) and then simply setting the X-Sendfile header as per the example on the above link:
header("X-Sendfile: $path_to_somefile");
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"$somefile\"");
Because you are return JsonModel so your output will be a json with your message instead of buffering for downloading.
Edit: I notice that you was missing Content-Transfer-Encoding: Binary, tested on my os x - php5.6 env.
You should try this
public function getList(){
try{
//here i am getting the zip file name.
$exportFile = $this->getRequest()->getQuery('exportid','');
$file = 'D:\php7\htdocs\Project\trunk\api\data\\' . $exportFile . '.zip';
header('Content-Description: File Transfer');
header('Content-type: application/zip');
header('Content-disposition: attachment; filename=' . basename($file));
header("Content-Transfer-Encoding: Binary");
header("Content-length: " . filesize($file));
header("Pragma: no-cache");
header("Expires: 0");
readfile("$file");
} catch(\Exception $e){
return new JsonModel(["status"=>"Failed"]);
}
}
Just remove your JSonModel on response.
You can try this for downloading the file instead of readfile();
Server side -
file_put_contents("file.zip", fopen("http://someurl/file.zip", 'r'));
Client side -
<button>download file</button>
download file
in the localhost i get everything perfect but when i upload it to the server i get this error
Warning: Cannot modify header information - headers already sent by(
hier is my code
<?php
function download($file){
$dir = './download/';
$path = $dir.$file;
if(!file_exists($path)){
die('Error');
}else{
header('Content-Description : File Transfer');
header('Content-Disposition : attachment; filename='.basename($path));
header('Content-Type: application/octet-stream');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
ob_start();
flush();
readfile($path);
exit;
}
}
if (isset($_GET['download'])) {
if (!empty($_GET['download'])) {
$file = $_GET['download'];
download($file);
}
}
?>
<a class="download-template" href="example.php?download=Modern.rar">Download</a>
Remove the whitespace before the <?php
Like so
<?php
function download($file){
$dir = './download/';
$path = $dir.$file;
if(!file_exists($path)){
die('Error');
}else{
header('Content-Description : File Transfer');
header('Content-Disposition : attachment; filename='.basename($path));
header('Content-Type: application/octet-stream');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
ob_start();
flush();
readfile($path);
exit;
}
}
if (isset($_GET['download'])) {
if (!empty($_GET['download'])) {
$file = $_GET['download'];
download($file);
}
}
?>
<a class="download-template" href="example.php?download=Modern.rar">Download</a>
The error is telling you that you're outputting content before it should do.
If you output content then the page headers have already been sent, so your call to header() will fail because the headers have already gone. And headers are always sent first.
By removing the whitespace there is no content to send, so the headers are not sent, so the call to header will then work and not error.
Change the file encoding to "without BOM" (e.g. using notepad++) or remove the BOM before
Use the following code for download any type of file extensions(including .php,.html):
<?php
$filename = $test_data['test_name'];
$contenttype = "application/octet-stream";
header("Content-Type: " . $contenttype);
header("Content-Disposition: attachment; filename=\"" . basename($filename) . "\";");
readfile(ADMIN_ROOT.'modules/tests/test_pdfs/'.$filename);
exit();
?>
Or you can check in this link working example:
http://websamplenow.com/29/file_download
This question already has answers here:
Forcing to download a file using PHP
(10 answers)
Closed 9 years ago.
I am trying to use PHP to force a download on a client computer (with the file dialog- nothing sinister). I have found many pages that recommend I use the header() function to control the response from my PHP script, but I am having no luck with this. The code I have is as follows:
$file = $_POST['fname'];
if(!($baseDir . '\\AgcommandPortal\\agcommand\\php\\utils\\ISOxml\\' . $file)) {
die('File not found.');
} else {
header('Pragma: public');
header('Content-disposition: attachment; filename="tasks.zip"');
header('Content-type: application/force-download');
header('Content-Length: ' . filesize($file));
header('Content-Description: File Transfer');
header('Content-Transfer-Encoding: binary');
header('Connection: close');
ob_end_clean();
readfile($baseDir . '\\AgcommandPortal\\agcommand\\php\\utils\\ISOxml\\' . $file);
}
I am calling it using this JavaScript:
$.ajax({
url: url,
success: function(text) {
var req = new XMLHttpRequest();
req.open("POST", 'php/utils/getXMLfile.php', true);
req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
req.send('fname=' + encodeURIComponent(text));
}
});
This returns the contents of the file as text, but does not trigger a download dialog. Does anyone have any suggestions?
Instead of using AJAX, just redirect the browser to the relevant URL. When it receives the content-disposition:attachment header, it will download the file.
Few suggestions:
1.
if(!($baseDir . '\\AgcommandPortal\\agcommand\\php\\utils\\ISOxml\\' . $file)) {
Instead:
if(!file_exists($baseDir ....)){
2.Don't need size.
3.Try this one:
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($fullpath));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
ob_clean();
flush();
readfile($fullpath);
exit;
I would try sending a header from PHP like this, to replace your application/force-download header:
header("Content-type: application/octet-stream");
Kolink's answer worked for me (change the window location to the php file), but as I want to send POST variables along with the request, I ended up using a hidden form instead. The code I am using is as follows:
var url = 'php/utils/getXMLfile.php';
var form = $('<form action="' + url + '" method="post" style="display: none;">' +
'<input type="text" name="fname" value="' + text + '" />' +
'</form>');
$('body').append(form);
$(form).submit();
Thanks for all the answers!
First of all, I know this question has already been asked but I can't solve it anyway.
I need to set a link to download images(jpg).
I read various posts found here and with google but it's always the same results:
I can download the file but it's still the same error. The jpeg format is not correct.
Erreur d'interprétation du fichier
d'image JPEG (Not a JPEG file: starts
with 0x0a 0x20)
When I test this in a file without a controller, it's ok but the script in a controller doesn't work.
Here is the code for tests:
$file = '{document_root}/www/themes/default/images/common/background1.jpg';
if (file_exists($file))
{
header('Content-type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . basename($file));
header('Content-length: ' . filesize($file));
readfile($file);
exit;
}
This code works in a simple php file. I download the picture and can open it.
But within my controller, the file is not good.
I found that the tag ?> can add spaces but my controllers doesn't have this closing tag.
I've tested some code with the Zend objects found in various posts but it's the same error.
I've tried various way to read the file (file_get_content(), fread() ...) with the same result.
I assume there's something wrong with my Zend controller.
I'm now testing my file according to this post:
php file download: strange http header
Any clue will be really appreciated.
Thanks for your help and sorry for my bad english.
[EDIT: 21/06/2011 - 6h38]
Here is the code of the action
public function downloadAction()
{
$this->view->layout()->disableLayout();
$this->_helper->viewRenderer->setNoRender(true);
$img = $this->_getParam('img');
// Process the file
$config = Zend_Registry::get('config');
$width = $config->catalog->image->original->maxWidth;
$height = $config->catalog->image->original->maxHeight;
$prefix = $width . 'x' . $height . '_';
$filename = $prefix . $img;
$file = Zend_Registry::get('document_root') . '/data/images/catalog/products/' . $this->_getParam('pid') .'/'. $filename;
if (file_exists($file))
{
$this->getResponse()
->setHeader('Content-Disposition', 'attachment; filename='.$filename)
->setHeader('Content-Transfer-Encoding', 'binary')
->setHeader('Content-Length', filesize($file))
->setHeader('Content-type', 'image/jpeg');
$this->getResponse()->sendHeaders();
readfile($file);
exit;
}
}
This action is not called directly. I test if a parameter exists in the url.
If true then from the listAction, I call the downloadAction().
I've tried to disable the view and layout in both action but there's some html rendered.
I had the same problem sending content after decrypt file's content.
0x0a means new line. You probably have some new line after the ?> tag in some included class.
Put
ob_clean();
flush();
before
readfile($file);
something like this:
header('Content-type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . basename($file));
header('Content-length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
exit;
This work out fine for me. Hope it helps.
Regards
I codeing working zend framework :)
public function dowloadfileAction(){
$this->_helper->viewRenderer->setNoRender(true);
$this->_helper->layout->disableLayout();
if ($this->_user->isUserLogin()) {
$path_file = 'public/uploads/file/';
$filename = $this->_getParam('file');; // of course find the exact filename....
$file = $path_file.$filename;
//zfdebug(mime_content_type($file)); die();
if (file_exists($file)) {
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Cache-Control: private', false); // required for certain browsers
header('Content-Type: '.mime_content_type($file));
header('Content-Disposition: attachment; filename="'. basename($file) . '";');
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize($file));
readfile($file);
}else{
echo "File does not exist";
}
}else{
echo "Please Login";
}
exit;
}