CakePHP 3, how to render without CTP - php

How do I render without my controller attempting to load a non-existent .ctp file.
This is my code:
//without this, I get an error trying to load a non-existent .ctp file. When I include it, the browser does not render the PNG file.
$this->autoRender = false;
//... get avatar code
if (!file_exists($avatarPath))
throw new Exception('Could not find file: '.$avatarPath);
$file = file_get_contents($avatarPath);
header('Content-Type: image/png');
if ($file === false)
throw new Exception('file_get_contents failed on avatarPath');
else
echo $file;
When I use $this->autoRender = false;, the header call appears to be ignored. Any ideas?

Read about how to send files with CakePHP. Let me quote the documentation for you:
There are times when you want to send files as responses for your requests. You can accomplish that by using
public function sendFile($id)
{
$file = $this->Attachments->getFile($id);
$this->response->file($file['path']);
// Return response object to prevent controller from trying to render
// a view.
return $this->response;
}
As shown in the above example, you must pass the file path to the method. CakePHP will send a proper content type header if it’s a known file type listed in Cake\Network\Reponse::$_mimeTypes. You can add new types prior to calling Cake\Network\Response::file() by using the Cake\Network\Response::type() method.
If you want, you can also force a file to be downloaded instead of displayed in the browser by specifying the options:
$this->response->file(
$file['path'],
['download' => true, 'name' => 'foo']
);

Related

Where am I doing wrong in downloading a file with '.CSV' format in CodeIgniter's controller?

I am new to CodeIgniter and was working on downloading a file. However, I want to download a file that resides on my local machine, I am able to locate the file by providing the path, also the file gets downloaded with a File type, However, I want my file to be in .csv format
Here goes my Controller's download function:
public function download()
{
$state_id=$this->input->post('state'); // gets me the state-id from viw's dropdown
$this->load->helper('download'); // Load download helper
$file="C:\\Users\usernew\\Desktop\\New folder\\".$state_id.".csv";
$filename=$state_id.'.csv';
if (file_exists($file))
{
$data = file_get_contents($file); //check file exists
force_download($fileName,$data);
}
else{
echo"not working!";
}
}
Where am I going wrong?
As the force_download() function accepts the file name to be set and the data to insert into that file, as you have the data in that file already, you just need to download it. so, You should use the for_download() function like this:
force_download($file,NULL);
This will solve your problem :)

Download json without creating a file or delete file after return

i am trying to let an user download a collection as a json file, but i don't know how to do it, without storing the file.
option 1: download without storing at all
i tried something like this
return response()->download(WorkPersonalReport::all(), 'zapis_prac.json');
this does not work, because it is not a file. can i make it a "pseudo file"?
option 2: create file, let the download happen, delete file
public function jsonExport() {
$wprs = WorkPersonalReport::all();
file_put_contents('assets/workPersonalReport.json', $wprs);
return response()->download('assets/workPersonalReport.json', 'zapis_prac.json');
}
with
public function index() {
unlink('assets/workPersonalReport.json');
}
is either of the options possible with optimal code?
first - just to create a temporary file, which will be deleted after the download goes through?
second - unlink() the file after return statement, instead of everytime index() is called?
Consider the following snippet;
return response(WorkPersonalReport::all(), 200, [
'Content-Disposition' => 'attachment; filename="collection.json"'
]);

The file "Resource id #11" does not exist

I'm trying to create a class that converts an array into plaintext and file. Plaintext works fine however when I try to save it as a tmpfile and share it I'm getting errors.
My controller looks like:
public method index() {
$props = ['foo'=>'bar']; //array of props;
return response()->download(MyClass::create($props);
// I've also tried using return response()->file(MyClass::create($props);
}
And my class looks like:
class MyClass
{
// transform array to plain text and save
public static function create($props)
{
// I've tried various read/write permissions here with no change.
$file = fopen(tempnam(sys_get_temp_dir(), 'prefix'), 'w');
fwrite($file, implode(PHP_EOL, $props));
return $file;
}
// I've also tried File::put('filename', implode(PHP_EOL, $props)) with the same results.
}
And I'm getting a file not found exception:
The file "Resource id #11" does not exist.
I've tried tmpfile, tempname and others and get the same exception. I've tried passing MyClass::create($props)['uri'] and I got
The file "" does not exist
Is this an error due to my env (valet) or am I doing this wrong?
Your code is mixing up usage of filenames and file handles:
tempnam() returns a string: the path to a newly created temporary file
fopen() accesses a file at a given path, and returns a "resource" - a special type in PHP used to refer to system resources; in this case, the resource is more specifically a "file handle"
if you use a resource where a string was expected, PHP will just give you a label describing the resource, such as "Resource id #11"; as far as I know, there is no way to get back the filename of an open file handle
In your create definition, $file is the result of fopen(), so is a "resource" value, the open file handle. Since you return $file, the result of MyClass::create($props) is also the file handle.
The Laravel response()->download(...) method is expecting a string, the filename to access; when given a resource, it silently converts it to string, resulting in the error seen.
To get the filename, you need to make two changes to your create function:
Put the result of tempnam(sys_get_temp_dir(), 'prefix') in a variable, e.g. $filename, before calling $file = fopen($filename, 'w');
Return $filename instead of $file
You should also add a call to fclose($file) before returning, to cleanly close the file after writing your data to it.

How Do I return a file for download in Laravel

I need to be able to give the user a file for download, and so I created a route (unless I can do the link for a specific user's CV in blade). My files are stored in storage/app/cv/ directory. I created a route as such:
Route::get('test', function() {
$destinationPath = config('app.CVDestinationPath') . "/static_file.pdf";
$uploaded = Storage::get($destinationPath);
return $uploaded;
}
However this route is giving me a weird output. I think it is the file but it is converting the file to html or something. Could anyone help me return the file (it could be pdf, doc, or docx, or plain text). My file is not stored in the public directory!
Because the file is not uploaded in the public directory, you are required to use a storage method for accessing it first before you return a response.
$destinationPath = config('app.CVDestinationPath') . "/static_file.pdf";
$uploaded = Storage::get($destinationPath);
return (new \Illuminate\Http\Response($uploaded))->header('Content-Type', 'application/pdf');
Make sure to return a header with the content type otherwise the file will not be in an acceptable format.
you can use "Response" to help you with the download headers:
<?php
use Illuminate\Support\Facades\Response;
Route::get('test', function() {
$destinationPath = config('app.CVDestinationPath') . "/static_file.pdf";
return response()->download($destinationPath);
}
?>
Checkout this link https://laravel.com/docs/5.5/responses#file-downloads to find out more e.g. response->file($destinationPath) forces the browser to display the file (.pdf in your case) to the user using its lokal plugins.

Removing file after delivering response with Silex/Symfony

I'm generating a pdf using Knp\Snappy\Pdf in my Silex application. the file name is random and saved to the tmp directory.
$filename = "/tmp/$random.pdf"
$snappy->generate('/tmp/body.html', $filename, array(), true);
I think return the pdf in the response,
$response = new Response(file_get_contents($filename));
$response->headers->set('Pragma', 'public');
$response->headers->set('Content-Type', 'application/pdf');
return $response;
The pdf is displayed in the web browser correctly. The file with the random filename still exists when the request is finished. I can't unlink the file before returning the response. I've tried registering a shutdown function with register_shutdown_function and unlinking the file from there. However that doesn't seem to work. Any ideas?
Even though this is old, figured if anyone googles this more recently like I did. This is the solution I found.
There is a deleteFileAfterSend() method on the BinaryFileResponse returned from sendFile in Silex.
So in your controller you can just do:
return $app ->sendFile($filepath)
->setContentDisposition(ResponseHeaderBag::DISPOSITION_INLINE, $fileName)
->deleteFileAfterSend(true);
You can use the finish middleware for that:
A finish application middleware allows you to execute tasks after the Response has been sent to the client (like sending emails or logging)
This is how it could look:
$app->finish(function (Request $request, Response $response) use ($app) {
if (isset($app["file_to_remove"])) {
unlink($app["file_to_remove"];
}
});
//in your controller
$app["file_to_remove"] = $filename;
Maerlyn is right, but in this case you can also unlink the file before returning the response, since the content of the file is already in the $response.

Categories