In a download page for a blob from a database, how would I make it so that no other output is sent? Right now it's sending the header, debug info, and a footer. How do I make it so that none of that is sent, just for that view?
you can create an clear layout (e.g. empty.ctp ) in you layouts folder, only with
<?php echo $content_for_layout ?>
and then in you action where you're getting your blob data use that layout
$this->layout = 'empty.ctp';
and also to disable debugging, in your controllers use
Configure::write('debug',0);
if you're unable to create new layout you could try this.
$this->layout = null;
$this->render("view_name");
If you're using this to download files, you should use the Media view in cakePHP
http://book.cakephp.org/view/1094/Media-Views
$this->view = 'Media';
$params = array(
'id' => 'example.zip',
'name' => 'example',
'download' => true,
'extension' => 'zip', // must be lower case
'path' => APP . 'files' . DS // don't forget terminal 'DS'
);
CakePhp 2.3 users :
use Sending files from the Book
CakePhp 2.x users :
use '$this->viewClass' instead of '$this->view'
copy-paste ready full solution, right in any controller file:
<?php
public function download($file) {
$fsTarget = APP.WEBROOT_DIR.DS.'files'.DS.$file; // files located in 'files' folder under webroot
if (false == file_exists($fsTarget)){
throw new NotFoundException(__('Invalid file'));
}
$pathinfo = pathinfo($fsTarget);
$this->viewClass = 'Media';
$params = array(
'id' => $file,
'name' => $pathinfo['filename'], // without extension
'download' => true,
'extension' => $pathinfo['extension'], // must be lower case
'path' => dirname($fsTarget) . DS // don't forget terminal 'DS'
);
$this->set($params);
}
Hope this helps!
Related
I have 4 different types of file to download image/doc/pdf/xls. I want to download the file once I clicked on file link.
//controller
public function sendFile($id) {
$file = $this->Attachment->getFile($id);
$this->response->file($file['path']);
// Return response object to prevent controller from trying to render
// a view
return $this->response;
}
//view
<?php echo $file->name; ?>
No need to return the response - see this.
Simply use
public function send_file($id = null) {
...
$this->autoRender = false;
$this->response->file($file['path']);
}
In your view you need to link to this controller action, though (if you think about it):
$this->Html->link('Download', array(
'controller' => 'controller_name', 'action' => 'send_file', $id
));
Also note the conventions I corrected for you - the docs tell you that as well.
just to complete and add some notes on Mark's answer
Simply use
public function send_file($file_name = null) {
//local machine to the file
//e.g. c:\wamp\www\project\...
$path_local = 'path to the file'.$file_name;
//live path to the file
//e.g. \var\...
$path_live = 'path to the file'.$file_name;
$this->autoRender = false;
//if you trying to test it from localhost set the localhost path
//other wise live path
$this->response->file($path_live or $path_local, array('download' => true));
}
In your view you need to link to this controller action, though (if you think about it):
$this->Html->link('Download', array(
'controller' => 'controller_name', 'action' => 'send_file', $file_name
));
Also note the conventions I corrected for you - the docs tell you that as well.
I have a simple form in a a view and I am trying to access the $this=>passedArgs but it is coming back empty.
I am actualy trying to use the cakeDC search plugin which uses the $this=>passedArgs. It must be something simple I have not done to get the results from the form submit.
find view
<?php
echo $this->Form->create('Member', array(
'url' => array_merge(array('action' => 'find'), $this->params['pass'])
));
echo $this->Form->input('name', array('div' => false));
echo $this->Form->submit(__('Search'), array('div' => false));
echo $this->Form->end();
?>
Controller
public function find() {
debug($this->passedArgs);
exit;
}
I have tried $this->request->params
array(
'plugin' => null,
'controller' => 'members',
'action' => 'find',
'named' => array(),
'pass' => array(),
'isAjax' => false
)
I have add method get to the form.
This question has been asked before but their solution of having lower cases in the public $uses = array('order', 'product'); when it should be public $uses = array('Order', 'Product'); did not work.
Cakephp version 2.3.5
Thanks for any help
Update:
I have set my form to method get and this is the url:
http://localhost/loyalty/members/find?name=searchtext
I have removed the plugin and I still do not get anything $this->passedArgs, but I now get data for $this->request->data['name']. Once I put public $components = array('Search.Prg'); I get noting again for $this->request->data['name'].
I have tried again $this->Prg->parsedParams() with the Search plugin and I just get array()
The documentation is pretty clear on that.
You cannot just debug something that has not been set yet.
So including the plugin itself (and its component) is not enough.
From the readme/documenation:
public function find() {
$this->Prg->commonProcess();
$this->paginate['conditions'] = $this->ModelName->parseCriteria($this->passedArgs);
$this->set('...', $this->paginate());
}
Note the commonProcess() call which then only makes passedArgs contain what you need.
I'm trying to render a view to a variable.
This variable will then be used to generate a pdf.
Then that pdf should be downloaded with the Media view.
Here's my controller code:
$dir = ROOT . '/app/tmp/evaluationpdf/';
$path = $dir . $evaluationid . '.pdf';
$evaluation = $this->SelfEvaluation->find('first', array(
'conditions' => array('SelfEvaluation.id' => $evaluationid),
'contain' => array('Submission' => array('Application'), 'Applicant', 'Member')));
$this->set(compact('evaluation'));
$this->output = '';
$this->layout = false;
$html = $this->render('/elements/self_evaluation_pdf');
$this->_generate_pdf($html, $path);
$this->view = 'Media';
$params = array(
'id' => $evaluationid . '.pdf',
'name' => $evaluationid,
'download' => true,
'extension' => 'pdf',
'path' => $dir,
);
$this->set($params);
The file is created as it should, but the first '$this->render' output is also sent to the browser.
The file is never downloaded.
Any idea on how to fix this?
The simple fix is to just set $this->output to '' after your first render() call.
The more correct way is to use requestAction() instead of render().
In CakePHP 2.x I did the following in order to use a view to generate a barcode label format:
$response = $this->render('/Labels/' . $printer['Printer']['model'] . '/manifest', 'ajax');
$body = $response->body();
$response->body('');
Which gave me the view data as $body. Then I could just redirect or if the request was ajax just set autoRender to false and return ''.
It kind of muddies the MVC waters but it is simple.
You just have to write the code below in self_evaluation_pdf.ctp
header("Content-Disposition: attachment; filename='downloaded.pdf'");
header('Content-type: application/pdf');
The dynamic content in this view will be downloaded as a PDF file on the client side.
I'm using the cakephp media plugin in my project using the monolithic style attachments table, i.e. all the attachments go in the one table with foreign_key, model, group etc. saved with the file details. So my model looks like:
class ProjectProfile extends AppModel {
var $name = 'ProjectProfile';
var $useDbConfig = 'default';
var $useTable = 'project_profiles';
var $actsAs = array('Media.Transfer', 'Media.Generator');
public $belongsTo = array(
'Project' => array(
'className' => 'Project',
'foreignKey' => 'pjID'
)
);
var $hasMany = array(
'Photo' => array(
'className' => 'Media.Attachment',
'order' => 'Photo.basename, Photo.id',
'foreignKey' => 'foreign_key',
'conditions' => array('Photo.model' => 'ProjectProfile', 'Photo.group' => 'Photo'),
'dependent' => true)
);
Then a saveAll in the controller when saving my record saves the attached file.
This all works fine, however I'd really like to be able to upload multiple files at once, which the plugin does support by doing this in the form:
echo $this->Form->hidden('Photo.0.model', array('value' => 'Photo'));
echo $this->Form->input('Photo.0.file', array('type' => 'file');
echo $this->Form->hidden('Photo.1.model', array('value' => 'Photo'));
echo $this->Form->input('Photo.1.file', array('type' => 'file');
echo $this->Form->hidden('Photo.2.model', array('value' => 'Photo'));
echo $this->Form->input('Photo.2.file', array('type' => 'file');
But I think you'd agree that's a bit cumbersome to have to click browse for each individual file. The simplist method I could see to to allow multiple file uploads was to use the HTML5 multiple file section option - http://bakery.cakephp.org/articles/veganista/2012/01/31/html_5_multiple_file_upload_with_cake :
echo $this->Form->input('files.', array('type' => 'file', 'multiple'));
This allows you to shift click in the file browser to select multiple files then puts the files into an array to save... however, this field format isn't handled by the media plugin. Also, there'd be no way to add the model, group etc. fields on the save as far as I could see.
So, does anybody know how I can handle multi file uploads with the media plugin using the monolithic model? I'm open to all suggestions.
Thanks in advance.
Will this CakePHP 2.x plugin - AjaxMultiUpload - work for you? I think that does exactly what you need it to.
I have created a feature to upload and download file in my site. But I want to validate the download feature. I want to allow a user to download file if user is already logged in to my site and given permission to download.
Help me. How to check whether session is present there or not?
I am uploading files in /app/webroot/documents/users/ path.
Download link generated is like this : http://localhost/my_project/documents/users/TGlnaHRob3VzZS5qcGcxMjc3ODIzMTAx.jpg
Thank you all.
The easiest way to deal with this is to use the AuthComponent for your authentication and the MediaView for handling the download prompt from a "download this file" link on the page.
An Example.
class SomeController extends AppController {
...
public $components = array(
'Auth' => array(
... auth settings ...
),
...
);
public function download( ){
$this->view = 'Media';
$this->set( array(
'id' => 'TGlnaHRob3VzZS5qcGcxMjc3ODIzMTAx.jpg',
'name' => 'TGlnaHRob3VzZS5qcGcxMjc3ODIzMTAx',
'download' => true,
'extension' => 'jpg',
'path' => join( DS, array(
APP, 'webroot', 'documents', 'users', ''
))
));
}
This assumes you have the download action as a restricted action with regards to the AuthComponent. If you have the download action allowed you can wrap the MediaView code in an Auth->user( ) check like so..
public function download( ){
if( $this->Auth->user( )){
$this->view = 'Media';
$this->set( array(
'id' => 'TGlnaHRob3VzZS5qcGcxMjc3ODIzMTAx.jpg',
'name' => 'TGlnaHRob3VzZS5qcGcxMjc3ODIzMTAx',
'download' => true,
'extension' => 'jpg',
'path' => join( DS, array(
APP, 'webroot', 'documents', 'users', ''
))
));
} else {
... do something else here ...
}
}
This just checks that Auth has a valid User object saved to the session. This should only occur when there is a User logged in.
A couple of notes:
I use a blank array entry at the end of the join( DS, array( 'path', 'parts', '' ) call to get the trailing slash required for the path. Do that however you want - I am partial to join myself when building repetitive strings or paths.
http://book.cakephp.org/view/489/Media-Views
http://book.cakephp.org/view/563/Setting-Auth-Component-Variables
I would probably set something up so you're not giving them a direct download link. I usually set up an AttachmentsController, with a download() method. Then you can run all the permissions checks you want (and keep stats on the files, etc.)
In that case you can have your controller check the session variable before enabling the download.
If you're using the Session component, you can check the user's status in your users action using something like this:
if($this->Session->read('Auth.User.id'))
{
//download file
}
How you serve your files is up to you though, but that session check should work inside whatever you use to serve the file, such as Travis Leleu's AttachmentsController.