I have a Controller class that extends from AppController in CakePHP.
And this Controller class has a public function .. lets say testFunc()
class xyzController extends AppController {
..
..
public function testFunc($params, $auth_username)
{
..
..
}
}
I have made this function public since I need to call it from another Controller that too extending from AppController.
class abcController extends AppController {
..
..
public function callingFunc()
{
...
$controller = new xyzController($this->request, $this->response);
$controller->testFunc($params, $username);
}
..
..
}
But since I made it public, I see that testFunc() is accessible using curl command for the below https path
https://[ip_address]/xyz/testFunc/arg=test/root
As you can see, the above path takes "root" as argument to testFunc() and gives full access to anyone using the above path in curl command.
My requirement is to remove this security issue.
I am totally new to PHP and CakePHP. Can someone please give any pointers to how I can proceed?
"I need to call it from another Controller". This is almost never actually true, it usually indicates a flawed design. If testFunc is not meant to be accessed through a browser, then move it to somewhere that both controllers can access it without it being a public member. For example, make it a protected (or even private) member of your AppController, or if it's doing model-specific stuff, maybe it can be moved to that model's table class.
The solution is pretty simple.
public function _testFunc($params, $auth_usernmae) will do the magic.
In Cakephp, if the function has an underscore as prefix, then it cannot be accessed using URI but can be accessed internally from other functions.
Related
I am learning codeigniter 3
In my config.php:
$config['base_url'] = 'http://'.$_SERVER['HTTP_HOST'].'/ci3x/admin/';
In my routes.php:
$route['customer'] = 'customer/index';
In controllers/customer.php:
class Customer extends MY_Controller{
function index(){
// some code here
}
}
When I type: http://localhost/ci3x/admin/customer on brower, it back error 404.
I have no clue to fix, please help me to solve it.
Many thanks
As you are extending a Class and that class does have a constructor, your class needs a constructor that also calls the constructor of the extended class.
Else things won't get up and running correctly.
class Customer extends MY_Controller{
public function __construct() {
parent::__construct(); // Call the MY_Controller constructor
}
function index(){
// some code here
}
}
The same goes for your MY_Controller constructor as it will need to call CI_Controller constructor... It ripples down and everything gets initialised correctly (in simplistic terms) .
Note:
Be careful with your controller and method files names. If you read the user guide it will say that the file names for controllers and methods should start with a capital letter.
So your controllers/customer.php should be controllers/Customer.php. If you are running on Windows it won't care. If you are running on Linux it will definitely matter.
Im current trying to learn more about the core of OpenCart and how its classes actually work. Im also trying to advance my OOP skills in general as Im still learning in that area, so perhaps theres something obvious that Im not seeing.
Im wondering how a controller file knows how to find the cart class (for example).
E.g.
In catalog/controller/checkout cart there is (obviously with code removed)
class ControllerCheckoutCart extends Controller {
public function index() {
$this->cart->update();
}
}
The Controller class can be found in system/engine/controller.php
update() can be found system/library/cart.
I assumed that in the controller.php there would be a link to the cart class, or an object made from it. (Im basing that on the use of $this->).
So how is the cart class actually found from the controller?
Thank you
Firstly, your ControllerCheckoutCart extends the Controller class, so this is the class we need to focus on. You can find this class in /system/engine/controller.php.
Inside this class, there are two magic methods we are interested in. The first is the __construct, where the "registry" class is loaded (found in /system/engine/registry.php if you're interested in picking that apart - it's very simplistic).
You can think of this as a lookup of all the classes the store uses, such as model files, library files and so on. In the construct, the registry is passed to the controller so it has a reference to it
public function __construct($registry) {
$this->registry = $registry;
}
The second and more important magic method is the __get method. This is called when a classes property doesn't exist, for you to handle it yourself if you wish to do so. OpenCart uses this to try and get the class with that key from the registry
public function __get($key) {
return $this->registry->get($key);
}
So $this->cart in any controller would try to get the object with the key cart from the registry. If you look at the index.php file you will see this is allocated in there
// Cart
$registry->set('cart', new Cart($registry));
ControllerCheckoutCart extends Controller, which means it inherits all the code in Controller which you are not seeing here. Some code in Controller, likely in Controller::__construct, is creating the $this->cart object. Example:
class Controller {
public function __construct() {
$this->cart = new Cart;
}
}
Since this constructor is inherited by all child classes, they construct their own $this->cart as well and have access to it in their own methods.
As mentioned by Jay Gilford, you need to register your newly added library class file in the index.php and/or admin/index.php (depending on if you are using it in catalog or admin)
$registry->set('yourlibraryclass', new YourLibraryClass());
so that upon system loading, Opencart knows that your class exists, then you can call all its functions by:
$this->yourlibraryfilename->function();
Please note that your library file name is normally the same as your class name, hence it is used in the example here.
After the change has been done in the index.php files, you need to logout and login again to see the changes.
Should I not be using Index as the name for a controller class in CodeIgniter? I have an Index controller, and I'm seeing its methods being called multiple times. More specifically, I always see its index method called first, whether or not I'm visiting a path that should be routed there.
In application/controllers/index.php
class Index extends CI_Controller
{
public function index()
{
echo "index";
}
public function blah()
{
echo "blah";
}
}
When I visit index/blah, I see indexblah printed. When I visit index/index, I see indexindex. If I rename the controller to something else (e.g. Foo), it doesn't have a problem. That's the obvious workaround, but can anyone tell me why this is happening? Should I report this as a bug to CodeIgniter?
(Notes: I have no routes set up in configs/routes.php; my index.php is outside the CodeIgniter tree)
To further clarify what the issue is, in PHP4 Constructors were a function that had the same name as the Class...
example
class MyClass
{
public function MyClass()
{
// as a constructor, this function is called every
// time a new "MyClass" object is created
}
}
Now for the PHP5 version (Which codeigniter now, as of 2.0.x, holds as a system requirement)
class MyClass
{
public function __construct()
{
// as a constructor, this function is called every
// time a new "MyClass" object is created
}
}
So To answer the question that addresses the problem...
Should I not be using Index as the name for a controller class in CodeIgniter?
I believe it would be best to not choose Index as a controller name as the index() function has a reserved use in codeigniter. This could cause issues depending on your PHP configuration.
can anyone tell me why this is happening?
When your controller get's instantiated, index as the constructor is getting called.
Compare Constructors and DestructorsDocs:
For backwards compatibility, if PHP 5 cannot find a __construct() function for a given class, it will search for the old-style constructor function, by the name of the class . [highlighting by me]
In your case your Controller does not have any __construct() function but a function that has the same name as the class: index. It is getting called in the moment Codeigniter resolves and loads and then instantiates your Index Controller.
You can solve this by just adding the constructor to your Controller:
class Index extends CI_Controller
{
public function __construct() {}
public function index()
{
echo "index";
}
public function blah()
{
echo "blah";
}
}
After this change, it does not happen again.
Should I report this as a bug to CodeIgniter?
No, there is not really a need to report this as a bug, it's how the language work and as Codeigniter supports PHP 4 it must remain backwards compatible and needs to offer PHP 4 constructors. (Note: The Codeigniter project documents, they need server support for PHP version 5.1.6 or newer, but the actual code has PHP 4 compatiblity build in, I'm referring to the codebase here, not the documentation.)
Here is another solution using Codeigniter3
require_once 'Base.php';
class Index extends Base
{
public function __construct()
{
parent::index();
$classname=$this->router->fetch_class();
$actioname=$this->router->fetch_method();
if($actioname=='index' || $actioname == '')
{
$this->viewall();
}
}
}
And the viewall() had the following
$this->siteinfo['site_title'].=' | Welcome';
$this->load->view('templates/header', $this->siteinfo);
$this->load->view('templates/menu', $this->siteinfo);
$this->load->view('index/viewall', $data);
$this->load->view('templates/footer', $this->siteinfo);
The Base controller does all the library and helper loading for the entire application which is why it is being required in the default class
Basically from my short understanding of CodeIgniter, having a default action as index is a wrong. I found this out by using the printing the result of $this->router->fetch_method(); in the construct() of my index class. The default action by CodeIgniter is index, you may only set the default controller within application/config/routes.php and not the default action.
So my advice, never use index() as the default action especially if you are using index as the default controller
I know questions similar to this have been asked, but I have been searching through the internet and I can't seem to find exactly what I'm looking for.
The most common answer is to put it in the controller. I liked a particular solution from stackoverflow that had a SessionController and NonSessionController, both extending the main controller but with SessionController checking if the user is logged in before the dispatch.
Does this mean that the controller would look something like this?
class SessionController
{
...
function view()
{
//view thread stuff
}
function post()
{
if loggedin then
{
//post thread stuff
}
}
{
In this situation, it looks like NonSessionController is useless, and that model is only used when every action the controller handles is either strictly for users or non-users, unlike this forum example.
So I guess my question is, is the general concept of the controller above the most efficient way of dealing with login checks when using MVC?
I think the idea would be to have one controller which checks the session and login, and one that doesn't.
I would put the login check in the constructor of the session controller so that way every controller which extends it will check the login.
The session controller would look like
class SessionController
{
public function __construct()
{
if ( ! AuthenticationHelper::isLoggedIn() )
{
// User is not logged in
// Do something, maybe a redirect to login page
}
}
}
Then you can just extend that controller like
class HomeController extends SessionController
{
public function __construct()
{
parent::__construct();
}
public function index()
{
print "This page checks login status";
}
}
I would make a component. If you're writing your own MVC framework then this will be interesting to see how you implement this.
But, basically you need a class to check for session state. But, if you tie yourself to extending a class for logged in and a class for logged out I'd feel you have too much duplicate code. I also just personally don't think its very intuitive. I'd probably wind up losing track of whether or not a controller should extend the Session or NotSession.
I'm actually in the process of writing my own MVC framework and have thought about how I would solve this problem a little. I haven't gotten to where I've actually implemented code so it's more a working theory at this point. :)
Have one controller base class. That class has a property that we'll call $components. Let's make this an array and it can hold the name of classes for things you want to do in a lot of controllers, but doesn't really belong in the controller itself.
Since I'm using the Front Controller design pattern before the action requested is invoked I will gather the array of $components and load the appropriate class file for each entry.
As each $component file is being loaded I will dynamically add that component object to the controller properties. So that a component with name Session might refer to a class named SessionComponent and you can access it in your controller by using $this->Session->do_something() or $this->SessionComponent->do_something()
I kind-of-sort-of ripped the idea from CakePHP. I use Cake as my production PHP framework and a lot of my ideas for the custom built framework I'm working on is, obviously, inspired by Cake.
If you are inside your SessionController, then you shouldn't need to check the loggedin variable for every function, you should do that inside the constructor or the router, if you feel confident enough to manipulate. That way if the user is not logged in, the SessionController file and class would not be loaded at all.
Sorry, no english:
base controller
class Controller{
function handleLogin()
{
if(!Authentication::isLoggedIn())
{
//do stuff - redirect to login page?
}
}
}
someController
class someController extends Controller{
function someAction()
{
//check login
$this->handleLogin();
//do someAction stuff
}
}
In my CI system\libraries directory I have a new class named DD_Controller.php. This file looks like this:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class DD_Controller extends Controller
{
protected $ddauthentication;
function __construct()
{
parent::Controller();
$this->ddauthentication = "Authenticated";
}
}
?>
My application controller is defined like this:
class Inquiry extends DD_Controller
{...}
The Inquiry class works fine when I extend Controller, but I get a
Fatal error: Class 'DD_Controller' not
found in
C:\development\localhost\applications\inquiry\controllers\inquiry.php
on line 4
When I extend DD_Controller. In the config file I have the prefix defined as such:
$config['subclass_prefix'] = 'DD_';
Any idea of what I'm missing?
TIA
This is a better approach. Do the following:
Go to the following directory: your_ci_app/application/core/ and create a php file called MY_Controller.php (this file will be where your top parent classes will reside)
Open this the file you just created and add your multiple classes, like so:
class Admin_Parent extends CI_Controller {
public function __construct() {
parent::__construct();
}
public function test() {
var_dump("from Admin_Parent");
}
}
class User_Parent extends CI_Controller {
public function __construct() {
parent::__construct();
}
public function test(){
var_dump("from User_Parent");
}
}
Create your children controllers under this directory your_ci_app/application/controllers/ . I will call it adminchild.php
Open adminchild.php and create your controller code, make sure to extend the name of the parent class, like so:
class Adminchild extends Admin_Parent {
function __construct() {
parent::__construct();
}
function test() {
parent::test();
}
}
DD_Controller.php should be in /system/application/libraries/
If you're using the same CI for multiple apps, and you want them all to be able to extends their controllers to your custom one then you can extend the base Controller class in the same file.
In system/libraries/Controller.php below the Controller class:
class Mega_Controller extends Controller {
function Mega_Controller()
{
parent::Controller();
// anything you want to do in every controller, ye shall perform here.
}
}
Then you'll be able to do this in your app controllers:
class Home extends Mega_Controller {
....
Since the extended controller class you created will be available. I think this is better then overwriting the base controller, but that would work as well.
I recommend to avoid "cracking" CodeIgniter core files.
Better use its native extending possibilities and try to fit into them.
The same rule I would recommend for any PHP library / CMS.
This rule has few reasons:
- ability to quiclky upgrade without takint into account thousands of notes where and how was cracked in core files;
- portability;
- possibility to share your code - eg, this will be usable by both you and your friends in case of need, and it will help them to keep their library up to date, the same as you.
In other words, this is much more professional and it pays to you in the future by usability, portability and by update application possibility.
Regarding your personal question...
As for me, there is nothing bad to create your own library with everything you need to extend native CodeIgniter Controller, then load this library in Controller's constructor and you are done. The only thing to make better usability is to give short name to your library.
This way you can even divide what you need in different pieces and put into separate libraries:
WebFeatures
AdminFeatures
etc.
Then you just load needed libraries in your controller's constructor and you are done.
P.S. I know that proposed way does not fit into "right" OOP concept, but in the same time you must never forget about the integrity of the libraries used.
Everything above is just one more view of mine 7-years experience in professional web development, so I hope it will be helpful if not to follow, then at least to take into account.
Regards,
Anton