Apache read ZIP files instead of downloading - php

I have problem with my script, when i try to download ZIP files after creating - apache read them instead of downloading !!!
I use zipstream.php class (https://github.com/maennchen/ZipStream-PHP)
How to configure apache (running on Ubuntu) to let downloading this files with ZIP extension ?
Thank you !
Code i am using:
<?php
if($_GET['download'] == "ok")
{
$id = $_GET['id'];
$content = "TEST";
$mysql = $db_1->query("select result from testing where id='$id'");
$row = mysql_fetch_assoc($mysql);
$content .= $row['result'];
$file_opt = array(
'time' => time() - 2 * 3600,
'comment' => 'Simple Comment !',
);
$zip = new ZipStream('test.zip', array(
'comment' => 'Simple Comment !'
));
$zip->add_file('test.txt', $content, $file_opt);
$zip->finish();
exit;
}
Note: The problem is when i call the file from JQUERY he won't download, but when i browse it directly he download correctly !!

You're probably forgetting to set the zip header before echoing the content. Try this before you print the zip content:
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="myFileName.zip"');
Update: your lib seem to have a proper method to send the zip headers. Try to use this instead:
$zip = new ZipStream('test.zip', array(
'comment' => 'Simple Comment !',
'send_http_headers' => true,
));

This should work:
$filename = "test.zip";
header('Content-type: application/zip');
header('Content-Disposition: attachment; filename="' . $filename . '"');
readfile($filename);

Related

Laravel 5.1, export model to csv works but doesn't download

This is the route for my controller and method:
Route::post('exportarDireccionTodos','MyController#exportarDireccionTodos');
I'm calling that route from a click button with javascript:
$.ajax({
url: baseUrl+'exportarDireccionTodos',
type: 'POST',
data: {'id': optionsChecked},
success: function(response) {
//etc
MyController have this code:
$delimiter=";";
$array = MyModel::findMany($todos)->toArray();
$filename = "direcciones.csv";
header("Content-Transfer-Encoding: UTF-8");
header('Content-Type: application/csv');
header('Content-Disposition: attachment; filename="'.$filename.'";');
$f = fopen('php://output', 'wb');
foreach ($array as $line) {
fputcsv($f, $line, $delimiter);
}
fclose($f)
return response()->json([
'status' => 'success',
'mensaje' => 'Direcciones exportadas a CSV'
]);
I'm sending some id to my model then I'm creating a csv file, but I can't download it, I just see it pretty well made in the developer tools XHR, like this:
I've tried with:
header('Content-Type: application/force-download');
header('Content-Type: text/csv');
And with:
return Response::download($f, $filename, $headers); <-- here I got an error, Laravel 5.1 doesnt reconigze Response
same with:
return response()->download($f, $filename);
Always happens the same, the csv is made but can't download. I've tried 2 other ways to create the csv, but it always is well generated but can't be downloaded
You're missing the headers in your last call
return response()->download($f, $filename, $headers);
I'm using these headers on my laravel app to download a file
$headers = [
'Content-Type' => 'application/csv',
"Content-Description" => "File Transfer",
"Cache-Control" => "public",
'Content-Disposition' => 'attachment; filename="'.$filename.'"',
];
You may have better luck storing the file temporarily and generating a URL to download from
$fs = Storage::disk('local')->temporaryUrl($path, now()->addMinutes(5));
Well, the problem is my logic. I can't download a file with an ajax call.
I tried with Laravel-Excel but I had the same problem of coruse.
This thread fix my problem:
https://github.com/Maatwebsite/Laravel-Excel/issues/848
$response = array(
'name' => "das",
'file' => "data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,".base64_encode($archivo) //mime type of used format
);
and in the ajax:
var a = document.createElement("a");
a.href = response.file;
a.download = response.name;
document.body.appendChild(a);
a.click();
a.remove();

Downloading a zip file from a folder on my web server

I have an application that allows users to download mulitple files from a S3 bucket through an EC2 instance in one zip folder.
The process works fine, however, I would like the system to create a folder for each user when they want to download files, and then the files are downloaded to this folder and then put in a zip folder, within the user's folder, and then this zip folder is downloaded.
The files are downloading to this folder fine, and they are also zipping correctly, but my problem is that it is not downloading the zip file from the user's folder, and the download is showing as an empty zip file.
Below is my 'download all' code:
mkdir($userId);
$allName = $vshort . "v" . $number . "_All.zip";
$allName = str_replace(" ", "_", $allName);
if (isset($_POST['downloadAll']))
{
$zip = new ZipArchive();
$zip->open("{$userId}/{$allName}", ZipArchive::CREATE);
$s3->registerStreamWrapper();
foreach ($items as $item)
{
$fid = $item->item_file_id;
$file = ItemFile::locateId($fid);
$a = $file[0]->item_file_type;
$b = $file[0]->item_file_app;
$c = $file[0]->item_file_name;
$fileName = $a . "/" . $b . "/" . $c;
$download = $s3->getCommand('GetObject', [
'Bucket' => AWS_BUCKET,
'Key' => $fileName
]);
$streamFile = $c;
$user = User::locate($_SESSION['email']);
$uid = $user->user_id;
$cid = $user->user_company_id;
$history = new History();
$history->insert($fid, $uid, $cid);
$req = $s3->createPresignedRequest($download, '+1 minutes');
$link = (string)$req->getUri();
$stream = file_get_contents($link);
header($_SERVER["SERVER_PROTOCOL"] . " 200 OK");
header("Cache-Control: public"); // needed for internet explorer
header("Content-Type: application/'$a'");
header("Content-Disposition: attachment; filename='$c'");
file_put_contents($streamFile, $stream);
$zip->addFile($streamFile);
$downArray[] = $streamFile;
}
$zip->close();
$dLink = "https://mywebsite/" . $userId . "/" . $allName;
$size = filesize($allName);
header("Content-type: application/zip");
header("Content-Disposition: attachment; filename=$allName");
header("Content-length: " . $size);
header("Expires: 0");
ob_end_clean();
stream_context_set_default([
'ssl' => [
'verify_peer' => false,
'verify_peer_name' => false,
]
]);
readfile($dLink);
unlink($allName);
foreach ($downArray as $down)
{
unlink($down);
}
}
I have a feeling it is something to do with my headers but I'm not sure, any help will be greatly appreciated.
NOTE: I will be deleting the folder once the user has exited the page.
Below is what I am seeing on the web server
The folder '6' is the user id for the user in question
You appear to be calling readfile() on your download link ($dLink), which would serve the file throught HTTP. You probably meant to call readfile on $allName, the filesystem path of the same file. My guess is that your http request to $dLink is failing somehow. Also, you mkdir($userId), but never use that directory.
Apart from that, it seems your $allName variable contains the basename of the zipfile (i.e 'myzip-v-20_ALL.zip'). I would recommend opening your zipfile to a full path to your data directory, so you keep filesystem and http paths separate.
$allNameFilesystem = "{$userId}/{$allName}";
$allNameHttp = "https://mywebsite/{$userId}{$allName}";
// ...
$zip->open($allNameFilesystem, ZipArchive::CREATE);
// ...
// The download link is $allNameHttp
That is, if you actually need the http path. In this case, if you change readfile to use the filesystem path, you really don't use the http path anymore in your code.

Set mime-type of a file for the browser

I am creating a file using the function fopen and fwrite to write the content in it.
The data I am writing is binary (encrypted from a pdf file). Once the data is written, I check for the kind of the new file in my macbook and it says pdf, but when I run mime_content_type in my server, the output is text/plain.
The extension of the created file is pdf.
Code:
$fileurl = $targetFolder . '/' . $id . '.' . $filetype;
$blockCipher = BlockCipher::factory('openssl', array('algo' => 'aes'));
$blockCipher->setKey('test');
$create_file = fopen('./public' . $fileurl, 'w');
$file_content = file_get_contents($files[$fileKey]['tmp_name']);
$encrypted_file = $blockCipher->encrypt($file_content);
if( fwrite($create_file, $encrypted_file) ) {
chmod('./public' . $fileurl, 0644);
}
fclose($create_file);
Any idea on how to set the mime_content_type to application/pdf ?
Thank you
Check the http://php.net/manual/en/function.header.php function
<?php
// We'll be outputting a PDF
header('Content-Type: application/pdf');
// It will be called downloaded.pdf
header('Content-Disposition: attachment; filename="downloaded.pdf"');
// The PDF source is in original.pdf
readfile('original.pdf');
?>

Laravel download file from S3 route (not open in browser)

I have the following route that will load a file from the given URL, I need this to actually download the file (mp4, jpg, pdf) rather than open in the browsers in built viewer.
// Download from CDN Route
Route::get('cdn/{url}', function($url)
{
return Redirect::away($url);
})->where('url', '(.*)');
All files are stored externally so apparently Resource::download() wouldn't actually work.
All I have available to me is the Amazon URL: https://mybucket.s3.amazonaws.com/folder/filename.pdf
Any suggestions on how to force the browser to download the file from S3?
In my case simple anchor link is downloading the file ...
file name
Try this code.
Update composer with flysystem
$path = 'https://mybucket.s3.amazonaws.com/folder/filename.pdf';
if(Storage::disk('s3')->has($path)){
$data = Storage::disk('s3')->get($path);
$getMimeType = Storage::disk('s3')->getMimetype($path);
$newFileName = 'filename.pdf';
$headers = [
'Content-type' => $getMimeType,
'Content-Disposition'=>sprintf('attachment; filename="%s"', $newFileName)
];
return Response::make($data, 200, $headers);
}
pari answer download empty file.
$s3Client = AWS::createClient('s3');
$stream = $s3Client->getObject(
[
'Bucket' => 'bucket name',
'Key' => 'filename',
'SaveAs' => '/tmp'.filename
]);
return response($stream['Body'], 200)->withHeaders([
'Content-Type' => $stream['ContentType'],
'Content-Length' => $stream['ContentLength'],
'Content-Disposition' => 'attachment; filename="' .{filename with extention} . '"'
]);
How can we download a video with an external link from another server. It's not s3. It's a normal server, files are there, but it doesn't work. I have written this code
$filename = $video->video_id;
$tempFile = tempnam(sys_get_temp_dir(), $filename);
// dd($tempFile);
copy($video->path, $tempFile);
header("Content-Disposition: attachment; filename = ".$filename);
header("X-Accel-Redirect: ".$filename);
return response()->download($tempFile, $filename);

Laravel 5.1 - how to download pdf file from S3 bucket

I am using Laravel's Storage facade and I am able to upload the pdf to S3 and I am also able to get() its contents but I cannot display or download it to the end user as an actual pdf file. It just looks like raw data. Here is the code:
$file = Storage::disk($storageLocation)->get($urlToPDF);
header("Content-type: application/pdf");
header("Content-Disposition: attachment; filename='file.pdf'");
echo $file;
How can this be done? I have checked several articles (and SO) and none of them have worked for me.
I think something like this will do the job in L5.2:
public function download($path)
{
$fs = Storage::getDriver();
$stream = $fs->readStream($path);
return \Response::stream(function() use($stream) {
fpassthru($stream);
}, 200, [
"Content-Type" => $fs->getMimetype($path),
"Content-Length" => $fs->getSize($path),
"Content-disposition" => "attachment; filename=\"" .basename($path) . "\"",
]);
}
you can create a download url, using the getObjectUrl method
somthing like this:
$downloadUrl = $s3->getObjectUrl($bucketname, $file, '+5 minutes', array(
'ResponseContentDisposition' => 'attachment; filename=$file,'Content-Type' => 'application/octet-stream',
));
and pass that url to the user. that will direct the user to an amzon page which will start the file download (the link will be valid for 5 minutes - but you can change that)
another option, is first saving that file to your server, and then let the user download the file from your server
You can do with this code (replace with your directory and your file name) ....
Storage::disk('s3')->download('bucket-directory/filename');
If your bucket is private, this is the way to obtain a url to download the file.
$disk = \Storage::disk('s3');
if ($disk->exists($file)) {
$command = $disk->getDriver()->getAdapter()->getClient()->getCommand('GetObject', [
'Bucket' => \Config::get('filesystems.disks.s3.bucket'),
'Key' => $file,
'ResponseContentDisposition' => 'attachment;'
]);
$request = $disk->getDriver()->getAdapter()->getClient()->createPresignedRequest($command, '+5 minutes');
$url = (string)$request->getUri();
return response()->json([
'status' => 'success',
'url' => $url
]);
}
In Laravel 5.7 it can be done with streamDownload:
return response()->streamDownload(function() use ($attachment) {
echo Storage::get($attachment->path);
}, $attachment->name);
$filename = 'test.pdf';
$filePath = storage_path($filename);
$header = [
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'inline; filename="'.$filename.'"'
];
return Response::make(file_get_contents($filePath), 200, $header);
$d = file_full_path_here...
$d = str_replace(' ', '%20', $d); //remove the white space in url
ob_end_clean();
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=" . $d);
header("Content-Type: application/pdf");
return readfile($d);
I figured it out. Silly mistake. I had to remove the single quotes from filename.
Fix:
$file = Storage::disk($storageLocation)->get($urlToPDF);
header("Content-type: application/pdf");
header("Content-Disposition: attachment; filename=file.pdf");
echo $file;

Categories