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.
Related
If condition is true it should show an error message "already exits" or else a message "successful" should be displayed.
Is it possible to add a validation like this to the model part:
$name = $_POST["name"];
$validation_sql = "SELECT COUNT(*) > 0 FROM college WHERE status='2' AND name='$name'";
You can use hasAny() as the solution:
$conditions = array(
'status'=>'2',
'name'=>$name
);
if ($this->XXXXXXX->hasAny($conditions)){
//do something
}
hasAny will return true if found else false.
NOTE: hasAny is not available in version 3.x
You can add server validation in model like:
public $validate = array(
'name' => array(
'rule' => array('isUnique', array('name'), false),
'message' => 'This name has already been used.'
)
);
It is not recommended to use $_POST in CakePHP at all, rather use the Request Object in the controller to access the data given by a POST request:
$this->request->data['College']['name'];
This information can then be passed to the model where it is validated.
If the post request has been created by the CakePHP form helper you don't need to access it - you can directly pass the data to the save method of the model instance (see CakePHP Handbook - Saving your data).
if ($this->College->save($this->request->data)) {
// handle the success (Normally success flash)
}
debug($this->College->validationErrors); //Normally error flash - if FormHelper is used the error messages are automatically shown beside the input elements
The validations can be added with the Bake Console or manually by adding validation rules to the College Model code:
public $validate = array(
'name' => array(
'rule' => 'isUnique',
'message' => 'This username has already been taken.'
)
);
I am using DC User Plugin with activated "RememberMe" Cookie. If the session is expired and I reload a public page, it works fine (it gets the cookie and renews the session).
But if I reload a page (after session has expired) which is only allowed for logged-in users, it does not check the cookie and redirects me instead to the login page. But if I then click another (public) page and then go back to the user-only page - it works, too, without to have to login again.
So the RememberMe/Cookie Component itself seems to work fine.
My Code for the Auth check for the problematic user-only page is simple:
public function view() {
if (!$this->Auth->user()) {
$this->redirect('/users/login');
} else {
//do stuff
}
}
What do I have to add/change, so that it checks the User Cookie here, too, when the Session is expired? In the documentation of that Plugin I couldn't find that unfortunately.
Thank you so much for your help and sorry for my bad English.
Well I resolved by myself. Allthough I had added
$this->RememberMe->restoreLoginFromCookie();
to beforeFilter() function in Controller, the function always returned false, because the Cookie saves email+password, but Standard Auth expects username+password.
I added
public $components = array(
...
'Auth' => array(
'authenticate' => array(
'Form' => array(
'userModel' => 'User',
'fields' => array(
'username' => 'email',
'password' => 'password'
)
)
),
...
so it will check for the needed email field, and now it works.
I'm creating a plugin for my application (using CakePHP 2.6.0) that allows users to login into a user area using the same model as for the admin area, so I'm trying to get the same type of URI scheme as the admin area e.g. /admin/users/login but then for /special/users/login. I have the following route in my plugin's Config/routes.php and added the 'special' prefix to the 'Routing.prefixes' configuration:
Router::connect('/special/:controller/:action', array(
'special' => true,
'prefix' => 'special',
'plugin' => 'Special',
'controller' => ':controller',
'action' => ':action',
));
With above route and entering the following url /special/users/login it would make sense to me right now if Cake went for Plugin/Controller/SpecialUsersController.php (considering namespace conflicts with the main application's UsersController) but instead I get an error Error: Create the class UsersController.
Is there a built-in way for it to load a prefixed controller (without changing the url) based on the plugin? Or is there a better way to neatly extend my main application? Am I going about this the wrong way?
I could not find a built-in way for it to work as I wanted to so I changed the way URL strings were parsed using a custom route class in my app's Routing/Route/ folder:
App::uses('CakeRoute', 'Routing/Route');
/**
* Plugin route will make sure plugin routes get
* redirected to a prefixed controller.
*/
class PluginRoute extends CakeRoute {
/**
* Parses a string URL into an array.
*
* #param string $url The URL to parse
* #return bool False on failure
*/
public function parse($url) {
$params = parent::parse($url);
if($params && !empty($params['controller']) && !empty($params['plugin'])) {
$params['controller'] = $params['plugin'] . ucfirst($params['controller']);
}
return $params;
}
}
And then setting up my plugin routes as:
App::uses('PluginRoute', 'Routing/Route');
Router::connect('/special/:controller/:action', array(
'special' => true,
'prefix' => 'special',
'plugin' => 'Special',
'controller' => ':controller',
'action' => ':action',
), array(
'routeClass' => 'PluginRoute'
));
This resulted in /special/users/login creating the controller I wanted Plugin/Controller/SpecialUsersController.php, no side effects so far. Extending the main application's UsersController is a different story though.
Maybe someone else has use of this or knows a better solution?
I had downloaded the plugin from link
https://github.com/CakeDC/users
followed the steps given in the page. I have created the tables 'users' and 'details'. I have also registered the user and verfied the user, but while accessing the link www.mydomain/users/users/login this page is getting redirected to www.mydomain/users/login
which shows missing controller. I am new to cake and for me it is difficult to debug. I would be thank if some one help me.
Thank you for the response.
Yes, I have added the code given in the "cake\libs\controller\app_controller.php" file. In order to test this I have freshly downloaded the core files and setup the files in my local system. I have placed the plugins 'utils', 'search' and 'users' to my app/plugins folder and created the tables.
Now also I am able to register the user but not able to see the login page. ie. "while accessing the link www.mydomain/users/users/login this page is getting redirected to www.mydomain/users/login which shows missing controller".
Please let me know if I am missing anything or I am wrong.
Thank you.
This looks like a problem in the login redirection.
Did you add the beforeFilter() configuration to your app_controller?
if not you may need to add it.
Here is an example of how your app_controller should look like:
<?php
class AppController extends Controller {
var $components = array('RequestHandler', 'Session', 'Auth');
function beforeFilter(){
$this->Auth->fields = array('username' => 'email', 'password' => 'passwd');
$this->Auth->loginAction = array('plugin' => 'users', 'controller' => 'users', 'action' => 'login', 'admin' => false);
$this->Auth->loginRedirect = '/';
$this->Auth->logoutRedirect = '/';
$this->Auth->authError = __('Sorry, but you need to login to access this location.', true);
$this->Auth->loginError = __('Invalid e-mail / password combination. Please try again', true);
$this->Auth->autoRedirect = false;
$this->Auth->userModel = 'Users.User';
$this->Auth->userScope = array('User.active' => 1);
}
}
?>
Remember that the $this->Auth->loginAction MOST contain the 'plugin'=>'users', without it it will go to www.mydomain/users/login instead of www.mydomain/users/users/login
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!