CakePHP get url params outside controller - cakephp

Anybody know, how to get url array params outside controller (for example bootstrap.php)?

CakePHP is still PHP at the end of the day, so you can use any valid PHP method to achieve this. Like:
if (!empty($_SERVER['QUERY_STRING'])) {
// A querystring was set...
}
Or
$url = parse_url($_SERVER['REQUEST_URI']);
if (!empty($url['query'])) {
// A querystring was set...
}
After that you can do anything else that you want to do.

Related

Looking to get the full site URL

I am looking to get the current site url in my apex class. I want the whole url, not just the domain Instead of https://google.com/ can it be something like https://google.com/page?something=something
I could only find how to put the domain without the full link. Thanks for your help in advance
To get the current URL of the Visualforce page you can use
PageReference pageRef = ApexPages.currentPage();
string currentUrl = pageRef.getUrl();
// Get or set query string parameters
string param1 = pageRef.getParameters().get('param1');
This only works in Visualforce.
When using Lightning, you should pass any additional parameters to the apex controller you need. You can use this JS to get the current page URL to send to the apex controller.
let currentUrl = window.location;
PageReference documentation

Cakephp 3 - CRUD plugin - Use id from auth component

Currently, I'm using the CRUD v4 plugin for Cakephp 3. For the edit function in my user controller it is important that only a user itself can alter his or her credentials. I want to make this possible by inserting the user id from the authentication component. The following controller method:
public function edit($id = null){
$this->Crud->on('beforeSave', function(\Cake\Event\Event $event) {
$event->subject()->entity->id = $this->Auth->user('id');
});
return $this->Crud->execute();
}
How can I make sure I don't need to give the id through the url? The standard implementation requires the url give like this: http://domain.com/api/users/edit/1.json through PUT request. What I want to do is that a user can just fill in http://domain.com/api/users/edit.json and send a JSON body with it.
I already tried several things under which:
$id = null when the parameter is given, like in the example above. Without giving any id in the url this will throw a 404 error which is caused by the _notFound method in the FindMethodTrait.php
Use beforeFind instead of beforeSave. This doesn't work either since this isn't the appropriate method for the edit function.
Give just a random id which doesn't exist in the database. This will through a 404 error. I think this is the most significant sign (combined with point 1) that there is something wrong. Since I try to overwrite this value, the CRUD plugin doesn't allow me to do that in a way that my inserting value is just totally ignored (overwriting the $event->subject()->entity->id).
Try to access the method with PUT through http://domain.com/api/users.json. This will try to route the action to the index method.
Just a few checks: the controllerTrait is used in my AppController and the crud edit function is not disabled.
Does anyone know what I'm doing wrong here? Is this a bug?
I personally would use the controller authorize in the Auth component to prevent anyone from updating someone else's information. That way you do not have to change up the crud code. Something like this...
Add this line to config of the Auth component (which is probably in your AppController):
'authorize' => ['Controller']
Then, inside the app controller create a function called isAuthorized:
public function isAuthorized($user) {
return true;
}
Then, inside your UsersController you can override the isAuthorized function:
public function isAuthorized($user) {
// The owner of an article can edit and delete it
if (in_array($this->request->action, ['edit'])) {
$userId = (int)$this->request->params['pass'][0];
if ($user['id'] !== $userId) {
return false;
}
}
return parent::isAuthorized($user);
}

What's the proper way to serve JSONP with CakePHP?

I want to serve JSONP content with CakePHP and was wondering what's the proper way of doing it so.
Currently I'm able to serve JSON content automatically by following this CakePHP guide.
Ok, I found a solution on this site. Basically you override the afterFilter method with:
public function afterFilter() {
parent::afterFilter();
if (empty($this->request->query['callback']) || $this->response->type() != 'application/json') {
return;
}
// jsonp response
App::uses('Sanitize', 'Utility');
$callbackFuncName = Sanitize::clean($this->request->query['callback']);
$out = $this->response->body();
$out = sprintf("%s(%s)", $callbackFuncName, $out);
$this->response->body($out);
}
I hope it helps someone else as well.
I've as yet not found a complete example of how to correctly return JSONP using CakePHP 2, so I'm going to write it down. OP asks for the correct way, but his answer doesn't use the native options available now in 2.4. For 2.4+, this is the correct method, straight from their documentation:
Set up your views to accept/use JSON (documentation):
Add Router::parseExtensions('json'); to your routes.php config file. This tells Cake to accept .json URI extensions
Add RequestHandler to the list of components in the controller you're going to be using
Cake gets smart here, and now offers you different views for normal requests and JSON/XML etc. requests, allowing you flexibility in how to return those results, if needed. You should now be able to access an action in your controller by:
using the URI /controller/action (which would use the view in /view/controller/action.ctp), OR
using the URI /controller/action.json (which would use the view in /view/controller/json/action.ctp)
If you don't want to define those views i.e. you don't need to do any further processing, and the response is ready to go, you can tell CakePHP to ignore the views and return the data immediately using _serialize. Using _serialize will tell Cake to format your response in the correct format (XML, JSON etc.), set the headers and return it as needed without you needing to do anything else (documentation). To take advantage of this magic:
Set the variables you want to return as you would a view variable i.e. $this->set('post', $post);
Tell Cake to serialize it into XML, JSON etc. by calling $this->set('_serialize', array('posts'));, where the parameter is the view variable you just set in the previous line
And that's it. All headers and responses will be taken over by Cake. This just leaves the JSONP to get working (documentation):
Tell Cake to consider the request a JSONP request by setting $this->set('_jsonp', true);, and Cake will go find the callback function name parameter, and format the response to work with that callback function name. Literally, setting that one parameter does all the work for you.
So, assuming you've set up Cake to accept .json requests, this is what your typical action could look like to work with JSONP:
public function getTheFirstPost()
$post = $this->Post->find('first');
$this->set(array(
'post' => $post, <-- Set the post in the view
'_serialize' => array('post'), <-- Tell cake to use that post
'_jsonp' => true <-- And wrap it in the callback function
)
);
And the JS:
$.ajax({
url: "/controller/get-the-first-post.json",
context: document.body,
dataType: 'jsonp'
}).done(function (data) {
console.log(data);
});
For CakePHP 2.4 and above, you can do this instead.
http://book.cakephp.org/2.0/en/views/json-and-xml-views.html#jsonp-response
So you can simply write:
$this->set('_jsonp', true);
in the relevant action.
Or you can simply write:
/**
*
* beforeRender method
*
* #return void
*/
public function beforeRender() {
parent::beforeRender();
$this->set('_jsonp', true);
}

Cakephp html2pdf auth problem

i am new with cake but i´ve somehow managed to get through so far. After i´ve figured out that html2pdf is a convienient way to produce pdf documents out of Cakephp, i´ve installed html2ps/pdf and after some minor problems it worked. So now i am coming now to the point that if i don´t modify my controllers beforeRender function like:
function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('download','view');
}
i just see my loginpage in the pdf i´ve created. Setting within my beforeRender function the $this->Auth->allow value opens obviously erveryone the way to get a perfect pdf without being authorized. The whole controller looks like this:
<?php
class DashboardController extends AppController {
var $name = 'Dashboard';
var $uses = array('Aircrafts','Trainingplans',
'Fstds','Flights','Properties','Person');
function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('download','view');
}
function view() {
/* set layout for print */
$this->layout = 'pdf';
/* change layout for browser */
if> (!isset($this->params['named']['print']))
$this->layout = 'dashboard';
/* aircrafts */
$this->Aircrafts->recursive = 0;
$aircrafts =$this->Aircrafts->find('all');
$this->set('aircrafts',$aircrafts);
.... and so on....
$this->set('person_properties',$person_properties);
}
function download($id = null) {
$download_link = 'dashboard/view/print:1';
// Include Component
App::import('Component', 'Pdf');
// Make instance
$Pdf = new PdfComponent();
// Invoice name (output name)
$Pdf->filename = 'dashboard-' . date("M");
// You can use download or browser here
$Pdf->output = 'download';
$Pdf->init();
// Render the view
$Pdf->process(Router::url('/', true) . $download_link);
$this->render(false);
}
}
?>
So in my opinion the $Pdf->process call get´s the data by calling more or less the view, but this process is not logged in, or in other words not authorized to get the data i want to render into the pdf. So the question is now how to get it done by not opening my application to everyone.
Best regards, cdjw
Edit:
You could do something like this:
if($this->Session->check('Auth.User')) {
// do your stuff
} else {
// do something else
}
You could check for 2 things before rendering /view:
a valid session (a user is logged in)
a valid security token that you pass from your download action as a named parameter
For the security token, just make up a long random string.
As the PDF is rendered on the same server, the token will never be known in the open and provide sufficient security.
Hope this is a working idea for you.
I had this similar issue, and this is how I handled it...
I first noticed that the process call of the PdfComponent was doing a request from the same server, so I tricked CakePHP on allowing the view only for requests being made from the server itself.. like this:
public function beforeFilter() {
if ($this->request->params['action']=='view'&&$_SERVER['SERVER_ADDR']==$_SERVER['REMOTE_ADDR']) { // for PDF access
$this->Auth->allow('view');
}
}
You should put
$this->Auth->allow('download','view');
inside AppController. rather than place where are you using now.
function beforeFilter() {
$this->Auth->allow('download','view');
....
}

Can I make CakePHP return a suitable status code based on certain conditions?

This question is slightly related to my old post Dealing with Alias URLs in CakePHP
After much thought, I am exploring the option of having a custom 404 script in my Cake App, that is reached when a URL does not map to any controllers/actions. This script would check $this->here and look it up in a database of redirects. If a match is found it would track a specific 'promo' code and redirect.
I'm thinking status codes. Can I make my script return a suitable status code based on certain conditions? For example:
URL matches a redirect - return a 301
URL really does not have a destination - return a 404.
Can I do this?
EDIT:
What about this? Anyone see any problems with it? I put it in app_controller.
function appError($method, $params) {
//do clever stuff here
}
This should work. Assuming you redirect 404's at a LegacyUrls::map() controller action. The code needs to be stored in app/app_error.php:
<?php
class AppError extends ErrorHandler{
function error404($params) {
$Dispatcher = new Dispatcher();
$Dispatcher->dispatch('/legacy_urls/map', array('broken-url' => '/'.$params['url']));
exit;
}
function missingController($params) {
$Dispatcher = new Dispatcher();
$Dispatcher->dispatch('/legacy_urls/map', array('broken-url' => '/'.$params['url']));
exit;
}
}
?>
Good luck!
I've always created app\views\errors\missing_action.ctp and app\views\errors\missing_controller.ctp
Cake will automatically display one of those views when a url does not map out to a controller or its methods.
Unless there is a certain need for the error codes that you did not give, this would work perfectly!
I'd like to augment felixge's answer.
This version outputs a 404 error to the browser:
class AppError extends ErrorHandler
{
function _outputMessage($template)
{
if ($template === 'error404') {
$Dispatcher = new Dispatcher();
$Dispatcher->dispatch('legacy_urls/map', array('broken-url' => '/'.$params['url']));
return;
}
parent::_outputMessage($template);
}
}

Resources