I'm using CodeIgniter hooks, I'm trying to trigger an action before a controller to be executed(pre_controller) and another action after the controller to be executed. But I'm facing a weird situation, when I enable the hook in $config['enable_hooks'] = TRUE; it trigger automatic logout, I mean it kills the user session. Could some one helps me on this? May be I made a wrong configuration for the hook.
Here is the hooks configuration:
hooks.php
$hook['pre_controller'] = array(
'class' => 'Hookcall',
'function' => 'get_post_params',
'filename' => 'hookcall.php',
'filepath' => 'hooks'
);
/*
hook for saving fraude logs
*/
$hook['post_controller'] = array(
'class' => 'Hookcall',
'function' => 'save_logs',
'filename' => 'hookcall.php',
'filepath' => 'hooks'
);
Hookcall should NOT extend MY_Controller. It should be a simple class instead
class Hookcall
{
public function save_logs()
{
}
public function get_post_params()
{
}
private function get_files_superior_5_percent($params)
{
}
}
Related
I am using the Silex / Symfony security service and try to implement a automatic login when the specific parameters are passed in the request query.
I've looked into the modules and also search on the internet for a solution and always found something like the following:
$user = (new \Portal\UserProvider($app['databases']['read']))->loadUserByUsername($subscriber_id);
$token = new \Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken($user, $user->getPassword(), 'secured', $user->getRoles());
$app['security.token_storage']->setToken($token);
Unfortunately, this does not work for my app. I don't know whats wrong but the security module keeps redirecting me to /login/ as specified in the registration process:
/**
* Registers the security firewall.
*/
private function registerSecurity()
{
$this->register(new \Silex\Provider\SecurityServiceProvider(), array(
'security.firewalls' => array(
'login' => array(
'pattern' => '^/(login/|terms|imprint|animation|error)',
),
'secured' => array(
'pattern' => '^/',
'form' => array(
'login_path' => '/login/',
'check_path' => '/login_check'
),
'logout' => array(
'logout_path' => '/logout'
),
'users' => $this->share(function () {
return new \Portal\UserProvider($this['databases']['read']);
}),
),
'unsecured' => array(
'anonymous' => true
),
),
'security.encoder.digest' => $this->share(function () {
return new \Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder('sha1', false, 1);
}),
'security.access_rules' => array(
array('^/login', 'ROLE_GUEST'),
),
'security.role_hierarchy' => $this->share(function () {
return array();
})
));
$this->boot();
}
Is there anything I have to consider about
reloading
order of registering the SecurityServiceProvider, SessionServiceProvider
this manual token setting
?
You're using the 'form' authentication provider, but this won't work (or maybe I'm not understanding you correctly?). In order to be able to:
try to implement a automatic login when the specific parameters are passed in the request query
You need to hook into the Security service. In order to do that you have to create a Listener and register it. You'll also need a Provider
This is not an easy path as the security component works with many concepts.
You can see a working example in this repo (which implements an OAuth service)
If your security flow is easy and you don't need roles, you can just use a before middleware (and forget about the security component) like so:
<?php
$app->before(function (Request $request, Application $app) {
$session = $request->getSession();
if (false === $session->get('logged', false)) {
if (null !== $request->get('blah', null)) {
$session->set('logged', true);
}
else {
return new RedirectResponse('/login-url');
}
}
});
You could use Silex's guard. It works well with get Request. And standard form could be use as complement.
In your secured Security.firwall, add the guard parameter :
"guard" => array ("authenticator" => array("app.myauthenticator") )
And create your custom class, to validate login.
Just read the Silex cookbook.
I have the following hook config (in hooks.php)
$hook['post_controller_constructor'][] = array(
'class' => 'MY_DataCollection',
'function' => 'init',
'filename' => 'MY_DataCollection.php',
'filepath' => 'hooks'
);
$hook['post_controller'][] = array(
'class' => 'MY_DataCollection',
'function' => 'post_controller',
'filename' => 'MY_DataCollection.php',
'filepath' => 'hooks'
);
What I want to do is have the class instantiated in the post_controller_constructor and then have the init method run. Then for post_controller run the post_controller but using the very same instance. CodeIgniter is instantiating the class again however.
Next I tried something slightly clever I thought:
require_once APPPATH . 'hooks/MY_DataCollection.php';
$collection = new MY_DataCollection;
$hook['post_controller_constructor'][] = array(
'function' => array($collection, 'init'),
'filename' => 'MY_DataCollection.php',
'filepath' => 'hooks'
);
$hook['post_controller'][] = array(
'function' => array($collection, 'post_controller'),
'filename' => 'MY_DataCollection.php',
'filepath' => 'hooks'
);
That doesn't work, as the hook class in CI does a require and I get:
Fatal error: Cannot redeclare class MY_DataCollection in /var/www/application/hooks/MY_DataCollection.php on line 7
So I got rid of the file path info:
require_once APPPATH . 'hooks/MY_DataCollection.php';
$collection = new MY_DataCollection;
$hook['post_controller_constructor'][] = array(
'function' => array($collection, 'init')
);
$hook['post_controller'][] = array(
'function' => array($collection, 'post_controller')
);
Doesn't even attempt to run, as in the CI_Hooks class there is this check in _run_hook:
if ( ! isset($data['filepath']) OR ! isset($data['filename']))
{
return FALSE;
}
I think I'm going to have to override this function by extending this class, but I just can't believe that this situation hasn't been encountered by someone else before and that there's not any easier way of solving it.
Thanks
Hmmz, it seems you need to store the instance of the needed class somewhere.
Maybe you could do something like this:
class MyHooks
{
public static $object_you_need;
public function init()
{
$object = new MyObject();
$object->init();
self::$object_you_need = $object;
}
public function post_controller()
{
$object = self::$object_you_need;
// do stuff with that object
}
}
Doesn't feel pretty, but I think it works.
This issue is already solved on the CI3 here is how to fix it on CI2
Just create a MY_Hooks.php on your app/core directory
Copy the Hooks.php class on the CI 3 Repository and put it in your
MY_Hooks.php but the class name will be MY_Hooks Extends
CI_Hooks it is located on system/core/hooks.php
change the call_hook function to _call_hook (just add a underscore '_')
change the private _run_hook to public
next step, is lay back and drink beer
Here is to test if it is working
class Hook_hook{
private $init = 'function inits not called';
public function inits(){
$this->init = 'function inits called';
}
public function load(){
echo '<script>alert("'.$this->init.'")</script>';
}
}
Sample config on config/hooks.php
$hook['post_controller_constructor'][] = array(
'class' => 'Hook_hook',
'function' => 'inits',
'filename' => 'Hook_hook.php',
'filepath' => 'hooks'
);
$hook['post_controller'][] = array(
'class' => 'Hook_hook',
'function' => 'load',
'filename' => 'Hook_hook.php',
'filepath' => 'hooks'
);
I would like to make navigation buttons in my view, for example index.phtml but it's not working. I did know how to do it in Zend1 but in Zend2 I have a problem. My code looks like this (file index.phtml):
$container = new \Zend\Navigation\Navigation($tableActions);
var_dump($container);
echo '<div class="table-column">';
echo $this->navigation($container)->menu();
echo '</div>';
Variable $tableAction looks like this:
public $tableActions = array(
array(
'label' => 'On/Off',
'module' => 'import',
'controller' => 'import',
'action' => 'setstatus',
'params' => array('id' => null),
),
);
I did not get any error, just whole site die on this line. var_dump returns object(Zend\Navigation\Navigation) so it's fine so far. Problem is, how to show it...
The navigation pages have dependencies which aren't being met by just creating a new container class in a view. The Mvc page needs a RouteStackInterface (Router) instance and a RouteMatch instance. Similarly Uri pages need the current Request instance.
You can see this clearly if you take a look at the Zend\Navigation\Service\AbstractNavigationFactory and its preparePages and injectComponents methods.
The view is not the right place to be instantiating menus, instead put the menu configuration spec in your module.config.php...
<?php
return array(
'navigation' => array(
'table_actions' => array(
array(
'label' => 'On/Off',
'module' => 'import',
'controller' => 'import',
'action' => 'setstatus',
'params' => array('id' => null),
),
),
),
);
Write a factory extending the AbstractNavigationFactory class and implement the getName() method which returns the name of your menu spec key (table_actions in this example)
<?php
namespace Application\Navigation\Service;
use Zend\Navigation\Service\AbstractNavigationFactory;
class TableActionsFactory extends AbstractNavigationFactory
{
/**
* #return string
*/
protected function getName()
{
return 'table_actions';
}
}
Map the factory to a service name in the service_manager spec of module.config.php ...
<?php
return array(
'navigation' => array(// as above ... )
'service_manager' => array(
'factories' => array(
'TableActionsMenu' => 'Application\Navigation\Service\TableActionsFactory',
),
),
);
Now you can call the view helper using the service name TableActionsMenu you just mapped
<div class="table-column">
<?php echo $this->navigation('TableActionsMenu')->menu(); ?>
</div>
Finally, if, as I suspect, you need to change an attribute of the page depending on the view, you can do that too, navigation containers have find* methods which can be accessed from the navigation helper and used to retrieve pages.
Here's an example looking for the page with a matching page label, then changing it before rendering (obviously not an ideal search param, but it gives you the idea)
$page = $this->navigation('TableActionsMenu')->findOneByLabel('On/Off');
$page->setLabel('Off/On');
// and then render ...
echo $this->navigation('TableActionsMenu')->menu();
I want to check if the user has permission to access to the URL (controller/method) combination. It should check before any method called in called controller and method belongs to it.
As far as I understand, the hook should be pre_controller for the logic above but when I use it, I think it clashes with post_controller_constructor shown below. If I use post_controller instead then it works but this time logic is compromised.
How can I solve this problem?
Thanks
CONFIG/HOOKS
//Used to authenticate user session to decide whether to authenticate site or not
$hook['post_controller_constructor'] =
array(
'class' => 'site_authentication',
'function' => 'authenticate',
'filename' => 'site_authentication.php',
'filepath' => 'hooks',
'params' => null
);
//Used to authenticate permitted controllers
$hook['pre_controller'] =
array(
'class' => 'permitted_controllers',
'function' => 'authenticate',
'filename' => 'permitted_controllers.php',
'filepath' => 'hooks',
'params' => null
);
APPLICATION/HOOKS
//This works fine
class site_authentication
{
private $CI;
public function __construct()
{
$this->CI =& get_instance();
}
public function authenticate()
{
if (! $this->CI->session->userdata('site'))
{
redirect('to error page');
}
$user_session = $this->CI->session->userdata('site');
//Some more stuff here
}
}
//This doesn't work with pre_controller
class permitted_controllers
{
private $CI;
public function __construct()
{
$this->CI =& get_instance();
}
public function authenticate()
{
$user_session = $this->CI->session->userdata('site');
//Url is set here, ignore syntax error below
$url = $this->CI->uri->segment(1) . 2 . 3;
if (! in_array($url, $user_session['controllers']))
{
redirect('to error page');
}
}
}
If I combine them two, they work fine under post_controller_constructor but they won't work separately?
$hook['post_controller_constructor'] [] =
array(
'class' => 'site_authentication',
'function' => 'authenticate',
'filename' => 'site_authentication.php',
'filepath' => 'hooks',
'params' => null
);
$hook['post_controller_constructor'] [] =
array(
'class' => 'permitted_controllers',
'function' => 'authenticate',
'filename' => 'permitted_controllers.php',
'filepath' => 'hooks',
'params' => null
);
pre_controller hook is run before the super object has been constructed, so it is not a viable option for hooking into CI's normal syntax (such as $this->db->query()).
I'd suggest creating a base controller (aka MY_Controller or some other name) and adding the permission check to its constructor. Then, each controller that should run the permissions check will then extend MY_Controller instead of CI_Controller. Here's Phil Sturgeon's classic article about base controllers.
Hooks are called on every page load. If you don't need to check permissions somewhere, you need to either add that logic to your hook, or add logic somewhere else to try and disable it. Not very extendable. Using a base controller, adding the permission check is as simple as extending a different class.
The pre_controller hook executes before the super object has been fully constructed read more here
In module.config.php file, I have set value for 'password_has_type'. And in controller I want to access that. Here is my module.config.php file:
'auth' => array(
'password_hash_type' => 'sha512',
),
'di' => array(
'instance' => array(
'alias' => array(
'auth' => 'Auth\Controller\AuthController',
'auth_login_form' => 'Auth\Form\LoginForm',
),...
In controller, I have used
use Auth\Module
and in Action method I try to get access value by
echo Module::getOption('password_hash_type');
But I could not get any value?
So please can anybody help me to get that value ?
Please see my answer at Access to module config in Zend Framework 2.
But to make it more concrete to your question, you would do this:
$config = $this->getServiceLocator()->get('Config');
$pwht = $config['auth']['password_hash_type'];
I hope this helps!
You can do it with help of aliases and parameters. Put it into di->instance array:
'Auth\Controller\AuthController' => array(
'parameters' => array(
'passwordHashType' => 'sha512'
)
),
And it is your controller:
namespace Auth\Controller;
use Zend\Mvc\Controller\ActionController;
class AuthController extends ActionController
{
protected $passwordHashType;
public function indexAction()
{
echo $this->passwordHashType;
}
public function setPasswordHashType($passwordHashType)
{
$this->passwordHashType = $passwordHashType;
return $this;
}
}