I am attempting to disable ACL/ACO checks in my local development environment because its time consuming to sync up the ACO table everytime I create a new method or controller. I am having problems figuring out how to do this conditionally. I attempted the following code in AppController but it did not work:
public function beforeFilter() {
parent::beforeFilter();
// disable ACL component in local development environments
if(preg_match('/\.local/',FULL_BASE_URL)){
unset($this->components['Acl']);
unset($this->components['Auth']['authorize']);
}
}
I am running CakePHP 2.x
You can probably achieve the same this way:
Add a configuration in your app/Config/core.php
Configure::write('Auth.enabled', 0);
Having an explicit configuration is generally preferred over 'auto-detecting' your environment.
Then, inside your AppController;
public function beforeFilter()
{
if(0 === Configure::read('Auth.enabled')) {
$this->Auth->allow();
}
}
See Making actions public
Or, to disable the component(s) altogether:
public function beforeFilter()
{
if(0 === Configure::read('Auth.enabled')) {
$this->Components->disable('Acl');
$this->Components->disable('Auth');
}
}
Related
I reconfigured my cakeEmail class to log to a specific type by rewriting the send method. I would like to use this override globally. My current single file setup uses /Lib/CustomCakeEmail.php with
App:uses('CustomCakeEmail', 'Lib');
CakePhp: Cake Email AfterSend event suggests a method to globally override using AppController but I have been unable to even trigger the debugger in
App::uses('CustomCakeEmail', 'Lib');
class AppController extends Controller {
public function getEmailInstance($config = null) {
CakeLog::write('debug', 'appcontroller triggered');
return new CustomCakeEmail($config);
}
What is the correct way to implement this global override?
CakePHP Version 2.8.4
I am trying to enable CSRF security in Cakephp 2.0
I have included the Security component in my controller.
public $components = array( 'Security');
I want to enable this component for only one function, say function test.
Other functions must be free of Security
I have tried to do like
$this->Security->requireSecure('test');
I have provided it like this as i want to enable security in test function alone.
In cakephp3.0 I found a option for enabling CSRF alone. But i need the solution for cakephp 2.0
I don't need any other securities validatePost, requirePost, requireDelete etc..
Awaiting for the feedbacks. Thanks in advance.
CSRF should be enabled in every action/form by default, and disabled for any action you want, not the backwards.
public $components = array('Security');
private $disabledCSRFForActions = array("test");
public function beforeFilter() {
parent::beforeFilter();
if (isset($this->Security) && in_array($this->action, $disabledCSRFForActions) {
$this->Security->validatePost = false;
$this->Security->enabled = false;
$this->Security->csrfCheck = false;
}
}
In CakePHP, how do I load a component in a shell?
To use a component in a controller, you include an array of components in a property called $components. That doesn't work for my Shell. Neither does the "on-the-fly" loading suggested in the documentation.
class MakePdfsShell extends Shell {
public $components = array('Document'); // <- this doesn't work
public function main()
{
$this->Document = $this->Components->load('Document'); // <- this doesnt work either
$this->Document->generate(); // <- this is what I want to do
}
...
I have some xml utilities that I use across some of my controllers. One of the controller launches a heavy task via the cake console, so that it can quietly run in the background via PHP CLI, while the user's request is immediately completed (once the task done, it will e-mail the results to the user).
The xml utilities are generic enough to be used in controller and shell, are too specific to the application to warrant them vendor status. The offered solution with the Lib folder does not work as in CakePhp v3 there seems to be no Lib folder.
After some quite some time spent, I managed to load my controller component to the shell task. Here is how to:
namespace App\Shell;
use Cake\Console\Shell;
use Cake\Core\App;
use Cake\Controller\Component;
use Cake\Controller\ComponentRegistry;
use App\Controller\Component\XmlUtilitiesComponent; // <- resides in your app's src/Controller/Component folder
class XmlCheckShell extends Shell
{
public function initialize() {
$this->Utilities = new XmlUtilitiesComponent(new ComponentRegistry());
}
...
$this->Utilities can now be used across my entire shell class.
You simply don't.
If you think you have to load a component in shell your application architecture is bad designed and should be refactored.
Technically it is possible but it doesn't make sense and can have pretty nasty side effects. Components are not made to run outside of the scope of a request. A component is thought to run within the scope of a HTTP request and a controller - which is obviously not present in a shell.
Putting things in the right place
Why does XML manipulation stuff have to go into a component? This is simply the wrong place. This should go into a class, maybe App\Utility\XmlUtils for example and have no dependencies at all to the request nor controller.
The logic is properly decoupled then and can be used in other places that need it. Also if you get incoming XML the right place to do this manipulation (by using your utility class) would be inside the model layer, not the controller.
You want to learn about Separation of Concerns and tight coupling
Because you've gone just against both principles.
https://en.wikipedia.org/wiki/Separation_of_concerns
What is the difference between loose coupling and tight coupling in the object oriented paradigm?
Search before asking
You could have tried to search via Google or on SO you would have found one of these:
using components in Cakephp 2+ Shell
CakePHP using Email component from Shell cronjob
Using a plugin component from shell class in cakephp 2.0.2
...
Be aware that some of them might encourage bad practice. I haven't checked them all.
I assume that you have a component named YourComponent:
<?php
App::uses('Component', 'Controller');
class YourComponent extends Component {
public function testMe() {
return 'success';
}
}
- with cake 2., you can load your component like this
App::uses('ComponentCollection', 'Controller');
App::uses('YourComponent', 'Controller/Component');
class YourShell extends AppShell {
public function startup() {
$collection = new ComponentCollection();
$this->yourComponent = $collection->load('Your');
}
public function main() {
$this->yourComponent->testMe();
}
}
- with cake 3. you can load your component like this
<?php
namespace App\Shell;
use App\Controller\Component\YourComponent;
use Cake\Console\Shell;
use Cake\Controller\ComponentRegistry;
class YourShell extends Shell {
public function initialize() {
parent::initialize();
$this->yourComponent = new YourComponent(new ComponentRegistry(), []);
}
public function main() {
$pages = $this->yourComponent->testMe();
}
}
If you are trying to access a custom XyzComponent from a shell, then you probably have commonly-useful functionality there. The right place for commonly-useful functionality (that is also accessible from shells) is in /Lib/.
You can just move your old XyzComponent class from /Controller/Component/XyzComponent.php to /Lib/Xyz/Xyz.php. (You should rename your class to remove the "Component" suffix, e.g., "XyzComponent" becomes "Xyz".)
To access the new location, in your controller, remove 'Xyz' from your class::$components array. At the top of your controller file, add
App::uses('Xyz', 'Xyz'); // that's ('ClassName', 'folder_under_/Lib/')
Now you just need to instantiate the class. In your method you can do $this->Xyz = new Xyz(); Now you're using the same code, but it can also be accessed from your Shell.
//TestShell.php
class TestShell extends AppShell{
public function test(){
//to load a component in dis function
App::import('Component', 'CsvImporter');
$CsvImporter = new CsvImporterComponent();
$data = $CsvImporter->get();
}
}
//CsvImporterComponent.php
App::uses('Component', 'Controller');
class CsvImporterComponent extends Component {
function get(){
//your code
}
}
I have a CakePHP application hosted on AWS Elastic Beanstalk. Because of the multiple EC2 instances I will use in the future I want to store my PHP sessions in a database. AWS provides a very nice library for storing PHP sessions in their DynamoDB database. See http://goo.gl/URoi3s
Now I putted the AWS SDK in my vendors folder and created an access wrapper for it (a plugin):
<?php
Configure::load('aws');
require_once VENDORS . 'autoload.php';
use Aws\Common\Aws;
class AwsComponent extends Component
{
private $_aws;
public function __construct()
{
$this->_aws = Aws::factory(array(
'key' => Configure::read('Aws.key'),
'secret' => Configure::read('Aws.secret'),
'region' => Configure::read('Aws.region')
));
}
public function getClient($service)
{
return $this->_aws->get($service);
}
}
The wrapper is working well, I already implemented some S3 stuff. Now for the session handler i added the following code to my AppController.php:
public $components = array('Aws.Aws');
public function beforeFilter()
{
$this->_setSessionStorage();
}
private function _setSessionStorage()
{
$client = $this->Aws->getClient('dynamodb');
$client->registerSessionHandler(array(
'table_name' => 'sessions'
));
}
The AWS's internal registerSessionHandler() is executed (tested it) but the session is not beeing stored into the DynamoDB table. Of course I created the table before and if I add the call to the AWS library directly to my webroot/index.php before dispatcher is loaded everything works fine.
I think the problem is that my code is executed after CakePHP calls session_start(). So what is the best way to implement that? http://goo.gl/kUFUIR doesn't help me, I don't want to rewrite the AWS library for beeing compatible with the CakePHP interface.
So what is the best way to implement that? http://goo.gl/kUFUIR
doesn't help me, I don't want to rewrite the AWS library for beeing
compatible with the CakePHP interface.
This is in fact the best way. And this does not mean to reinvent the wheel, abstraction in OOP means that you make things available in a generic interface that can be replaced with something else. You wrap a foreign API or code in an API compatible to your system, in this case a CakePHP application.
Wrap the vendor lib in a AwsSession adapter that implements the CakeSessionHandlerInterface. This way it's API compatible with other session adapters in the case you change it and it might be even solve your core problem, because CakeSession will take care of the initialization.
Your component is initialized after the session in CakePHP, when the controller is already instantiated and then is initializing all its components. So this happens at a pretty late time. Your alternative is to stop CakePHP from initializing the session, I never had a need to do so, so no idea without looking it up myself. Dig in CakeSession. Even if you manage to do so, other components like the default Auth adapter depends on being able to work with Sessions, so you have to take care of the issue that your component has to be loaded before Auth as well. Pretty fragile system with lots of possbile points of failure. Seriously, go for the Session adapter, guess its a lot less painful to get it working this way.
By a quick look at the DynamoDB Session documentation this seems to be pretty easy. Extend the regular session handler and overload only the init and garbage collection of it to add the Aws API calls there, no guarantee this is right but seems to be easy.
What I end up with in CakePHP 3.
src/Network/Session/DynamoDbSession.php
<?php
namespace App\Network\Session;
use Aws\DynamoDb\DynamoDbClient;
use Cake\Core\Configure;
class DynamoDbSession implements \SessionHandlerInterface
{
private $handler;
/**
* DynamoDbSession constructor.
*/
public function __construct()
{
$client = new DynamoDbClient(Configure::read('DynamoDbCredentials'));
$this->handler = $client->registerSessionHandler(array(
'table_name' => Configure::read('DynamoDbCredentials.session_table')
));
}
public function close()
{
return $this->handler->close();
}
public function destroy($session_id)
{
return $this->handler->destroy($session_id);
}
public function gc($maxlifetime)
{
return $this->handler->gc($maxlifetime);
}
public function open($save_path, $session_id)
{
return $this->handler->open($save_path, $session_id);
}
public function read($session_id)
{
return $this->handler->read($session_id);
}
public function write($session_id, $session_data)
{
return $this->handler->write($session_id, $session_data);
}
}
Activate it in config/app.php file:
'Session' => [
'defaults' => 'php',
'handler' => [
'engine' => 'DynamoDbSession'
],
'timeout' => (30 * 24 * 60)
]
Can we run shell scripts made with CakePHP on Browser?
This script can work perfectly as a CakePHP console based program (app/vendors/shells/test.php). But is it possible to run it on browser somehow?
class TestShell extends Shell {
function initialize() {
}
function main() {
echo "Test";
}
}
The reason I am asking is, I have some Cron jobs (made in cakephp), and it would be so much time saving to be able to run and debug them on browser.
Thanks
Yes, you should write a test case for it.
This way you can even see the mysql queries run.
place TestShellTest.php in \app\Test\Case\Console\Command\
App::uses('TestShell', 'Console/Command');
class TestShellTest extends CakeTestCase {
public $Test;
public function setUp() {
$this->Test = new TestShell();
}
public function tearDown() {
}
public function testObject() {
$this->assertIsA($this->Test, 'TestShell');
}
public function testRun() {
$this->Test->main();
//$this->assertEqual(...);
}
}
this is 2.0 syntax (1.3 is slightly different)