Codeigniter one service with multiple access points, subdomains, htaccess - php

I am not exactly sure how to word this properly so I apologize in advance. I have a slightly unique setup, but at the same time not so unique. I want to have
api.domain.com
m.domain.com
domain.com
All working off the same codebase, but serving up different views, and working off different controller sets. However I do not want to duplicate my code base by making mirror copies of it in various directories specific to the sub domain itself. To me that is redundant, and the opposite of productive, since I would have to manage 3+ sets of models, libraries, and in some cases controllers. To maintain functionality across the various versions of the service.
Right now, what I have setup and working is through constant growth of the routes.php is a means of saying what controller is used when through a normal domain.
ie
domain.com
domain.com/m/
domains.com/api/
Which works for now, but I am trying to think of whats best for organization and future development of the service.
So in all my question is, how can I setup codeigniter to support this logic of using subdomains while keeping everything in one main code base. Is this plausible? If so how could it be achieved?

Ok, so after a comment made to my original post, pointing me to another post here on stack I came up with a nifty way of handling my issue. Its not exactly the answer found in the link more than a derivative there of based on the logic. As I have multiple sub domains I want to roll out each with its own set of functionality and needs, as well as controllers specific to its cause that should only be called from those subdomains.
That said my solution, for those who may stumble across it is, in the routes.php I ended up making a small function to get the HTTP_HOST split it up based on . and use it from there to my needs. My example is as follows.
Mind you I also replaced everything in the routes.php so its not just a straight line of $route['this/that'] = 'dir/controller';
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/*
| -------------------------------------------------------------------------
| URI ROUTING
| -------------------------------------------------------------------------
| This file lets you re-map URI requests to specific controller functions.
|
| Typically there is a one-to-one relationship between a URL string
| and its corresponding controller class/method. The segments in a
| URL normally follow this pattern:
|
| example.com/class/method/id/
|
| In some instances, however, you may want to remap this relationship
| so that a different class/function is called than the one
| corresponding to the URL.
|
| Please see the user guide for complete details:
|
| http://codeigniter.com/user_guide/general/routing.html
|
| -------------------------------------------------------------------------
| RESERVED ROUTES
| -------------------------------------------------------------------------
|
| There area two reserved routes:
|
| $route['default_controller'] = 'welcome';
|
| This route indicates which controller class should be loaded if the
| URI contains no data. In the above example, the "welcome" class
| would be loaded.
|
| $route['404_override'] = 'errors/page_missing';
|
| This route will tell the Router what URI segments to use if those provided
| in the URL cannot be matched to a valid route.
|
*/
function whichSubRoute()
{
$subs = array(
"api"=>"api/",
"m"=>"m/"
);
$curr = $_SERVER['HTTP_HOST'];
$curr = explode('.', $curr);
if(array_key_exists($curr[0], $subs))
{
return array($curr[0], $subs[$curr[0]]);
}
return false;
}
//due to the the way this setup works, some controller references
//can be found multiple times (and in no particular order).
//also note due to this setup, each method has its own default and 404
$choiceRoute = whichSubRoute();
if($choiceRoute !== false)
{
if($choiceRoute[0]=="api")
{
$route['default_controller'] = "welcome";
$route['404_override'] = '';
//start version 1 (mvp API)
$route['1.0/user/(:any)'] = $choiceRoute[1].'v1_userinfo/index/$1';
//controllers outside of "/api"
}
if($choiceRoute[0]=="m")
{
$route['default_controller'] = "welcome";
$route['404_override'] = '';
//start version 1 (mobile)
$route['welcome'] = $choiceRoute[1].'m_welcome';
$route['dashboard'] = $choiceRoute[1].'m_dashboard';
$route['user/(:any)'] = $choiceRoute[1].'m_userinfo/index/$1';
$route['reg'] =
//controllers outside of "/m"
$route['login/auth'] = 'login/auth';
$route['logout/mobile'] = 'logout/mobile';
//end version 1 (mobile)
}
}
else
{
$route['default_controller'] = "welcome";
$route['404_override'] = '';
}
/* End of file routes.php */
/* Location: ./application/config/routes.php */
Also keep in mind I do want default and 404 controllers for each subdomain

I suppose you can load different configs base on ENVIRONMENT constant.
http://ellislab.com/codeigniter/user-guide/libraries/config.html
You may load different configuration files depending on the current
environment. The ENVIRONMENT constant is defined in index.php, and is
described in detail in the Handling Environments section.
To create an environment-specific configuration file, create or copy a
configuration file in application/config/{ENVIRONMENT}/{FILENAME}.php
For example, to create a production-only config.php, you would:
Create the directory application/config/production/ Copy your existing
config.php into the above directory Edit
application/config/production/config.php so it contains your
production settings

Related

What are the downsides of an alternative Routing method that uses sub-controllers?

I am writing a PHP CMS and I'm having some doubts about implementing the routing
the system that loads the page controller and "handles" it
I've seen many others implement the route like this:
//these values are actually retrieved from a file
return [
['GET', '/', ['Controllers\Homepage', 'show']],
['GET', '/user/recover/{token}', ['Controllers\User\Recover', 'recover']],
['GET', '/recover/{token}', ['Controllers\User\Recover', 'recover']],
['POST', '/user/login', ['Controllers\User\Login', 'login']],
['POST', '/login', ['Controllers\User\Login', 'login']],
['POST', '/user/register', ['Controllers\User\Register', 'register']],
['GET', '/foo/bar', ['Controllers\Idk', 'show']],
];
But I don't really like it, here is why:
If I call example.com/user/recover/{token} and example.com/recover/{token} the Recover controller needs to differentiate the two urls when handling a request, since {token} is in different positions and also there is the extra step for loading the routes within the controllers.
Also I prefer the a specific root is related to its own controller.
So I came up with this idea:
The application checks only the first parameter in the url (https://example.com/firstparameter/secondparameter/third/etc)
and loads from the database the controller name associated with the first parameter.
# don't worry, this is actually optimized with db normalization
+----------------+---------------------+-------------------+--------+
| id | title | controller_name | active |
+----------------+---------------------+-------------------+--------+
| firstparameter | just the page title | mycontroller | (true) |
| user | user page | usercontroller | (true) |
| recover | recover | recovercontroller | (true) |
+----------------+---------------------+-------------------+--------+
Since the majority of the pages has its own title, description, etc. and all pages have a controller_name this database call almost always needs to made, independently by the routing method.
Therefore I don't see the need of using a file storing the routes when everything can be "togheter".
So if I call example.com/user/recover/{token}
Then the application loads usercontroller (constructs it with its dependencies) and then calls usercontroller->init().
(note: Here I am not using different/dynamic method names by choice of simplicity because those can just be handled by each page's controller. Anyway that could be easily implemented later)
The init() function in this controller handles its whole page root /user/* and loads accordingly its sub-pages/children if there are any
function init(){
if( secondparameter is user )
/* the second parameter becomes the first, so the
* recovercontroller doens't need to do magic to get the url token
* for the recovercontroller the request will be almost the same
* as calling example.com/recover/{token}
*/
currenturl = arrayshift(currenturl)
recover = new recovercontroller()
recovercontroller->init()
return
This seems complicated but it's actually more logic and simpler than the "traditional" routing method. Maybe someone has actually done this before.
What downsides does this method have compared to the traditional one?
More or less they do the same job.

Laravel Route resource named functions

I currently have routes like this
//Settings
Route::prefix('settings')->group(function(){
//Get all users settings
Route::resource('user', 'SettingsController');
});
Which will produce a list of routes like so
| POST | settings/user |user.store | App\Http\Controllers\SettingsController#store | web,auth,GlobalAdmin |
| GET|HEAD | settings/user |user.index | App\Http\Controllers\SettingsController#index | web,auth,GlobalAdmin |
| GET|HEAD | settings/user/create |user.create | App\Http\Controllers\SettingsController#create | web,auth,GlobalAdmin |
And so on.
My issue is that I want the settings controller to be able to control a list of different settings in 1 controller, not just 'users'.
How would I name the resource so that it names the functions at the end?
For example, the above code generates function names like SettingsController#store, how would i get it so that it auto builds the function name with a prefix like SettingsController#userstore?
You can't. Unless you go behind the scenes and actually hack into how Laravel handles the generation. What you can do however is use except on the resource route or use partial resource routes.
Once you have done one of the above, you can just add your routes manually such as
POST settings/user
POST settings/other
POST settings/general
And point them that way.
If you really want to have such behavior you can have it. You can extend the Illuminate\Routing\ResourceRegistrar class and bind your extended version to the container.
There is only one method that needs to be adjusted, which is the method that sets up the action for each of the routes of the resource, getResourceAction. This can be adjusted to check for a key passed in the options array the the ResourceRegistrar already uses. If a key is present you can enable the behavior you need, prefixing the method name with the resource name and uppercasing the first letter of the actual method.
class YourRegistrar extends \Illuminate\Routing\ResourceRegistrar
{
protected function getResourceAction($resource, $controller, $method, $options)
{
$name = $this->getResourceRouteName($resource, $method, $options);
// check if 'pre' option was set
$method = isset($options['pre']) ? $resource . ucfirst($method) : $method;
$action = ['as' => $name, 'uses' => $controller.'#'.$method];
if (isset($options['middleware'])) {
$action['middleware'] = $options['middleware'];
}
return $action;
}
}
In a Service Provider #register (binding your new class to the current ResourceRegistrar):
$this->app->bind(
\Illuminate\Routing\ResourceRegistrar::class,
\Where\Ever\YourResourceRegistrar::class
);
In a routes file:
Route::resource('user', 'SettingsController', ['pre' => true]);
// SettingsController#userIndex
// SettingsController#userShow
// ...
Route::resource('user', 'SettingsController');
// SettingsController#index
// SettingsController#show
// ... normal
The router checks to see if there is something bound to the name of the ResourceRegistrar on the container before newing up one. If there is a binding it asks the container to resolve one. This is how you can extend the ResourceRegistrar and the router uses your version.
In our version we are checking if the options key pre was set or not. If it was we adjust the method names for the routes accordingly. ($method = isset($options['pre']) ? $resource . ucfirst($method) : $method;)
You can read more on the ResourceRegistrar and more detail of what happened above in my blog article on the subject:
asklagbox blog - Resource Registrar - lets extend

Run a Project on browser from IntelliJ IDE

I have opened a project that I downloaded in IntelliJIDEA IDE. The project structure is as follows. I am trying to run the userAuthenticationController.php controller's index() method to view the login page.
According to this project's config.php File, the base_url is provided as follows.
config.php
$config['base_url'] = 'http://localhost:9080/Internship-Management/Sourcecode/Codeigniter/';
I tried running this address in Chrome but am getting the following error.
userAuthenticationController.php
// Show login page
public function index() {
$this->load->view('login/loginView');
}
routes.php
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
/*
| -------------------------------------------------------------------------
| URI ROUTING
| -------------------------------------------------------------------------
| This file lets you re-map URI requests to specific controller functions.
|
| Typically there is a one-to-one relationship between a URL string
| and its corresponding controller class/method. The segments in a
| URL normally follow this pattern:
|
| example.com/class/method/id/
|
| In some instances, however, you may want to remap this relationship
| so that a different class/function is called than the one
| corresponding to the URL.
|
| Please see the user guide for complete details:
|
| https://codeigniter.com/user_guide/general/routing.html
|
| -------------------------------------------------------------------------
| RESERVED ROUTES
| -------------------------------------------------------------------------
|
| There are three reserved routes:
|
| $route['default_controller'] = 'welcome';
|
| This route indicates which controller class should be loaded if the
| URI contains no data. In the above example, the "welcome" class
| would be loaded.
|
| $route['404_override'] = 'errors/page_missing';
|
| This route will tell the Router which controller/method to use if those
| provided in the URL cannot be matched to a valid route.
|
| $route['translate_uri_dashes'] = FALSE;
|
| This is not exactly a route, but allows you to automatically route
| controller and method names that contain dashes. '-' isn't a valid
| class or method name character, so it requires translation.
| When you set this option to TRUE, it will replace ALL dashes in the
| controller and method URI segments.
|
| Examples: my-controller/index -> my_controller/index
| my-controller/my-method -> my_controller/my_method
*/
$route['default_controller'] = 'welcome';
$route['404_override'] = '';
$route['translate_uri_dashes'] = FALSE;
Do I need to change the path that I am using to load the controller in my browser?
Any suggestions in this regard will be highly appreciated.
Unfortunately, opening a project in IDEA/PhpStorm is not enough.
You still need to:
Install Apache (I think using XAMPP would be the best shot for you)
Configure it to run on port 9080 (according to the config file you posted)
Deploy the project to the Apache web root (manually, or by using a PhpStorm/IDEA deployment configuration)

How do I block certain URLs using CodeIgniter?

Currently everything is working golden except for the fact that a user could manually put in a URL, which messes up how CI is setup for my site. For instance:
www.somesite.com/folder/
this folder in the controller should not be accessible... and needs to redirected to that folders index page, which will give them a 404 error. I've tried adding deny to all in the htaccess file, but it doesn't seem to do anything.
www.somesite.com/folder/index.html
I actually want all folders to function likes this. I do have an index.html file in the folder, but it doesn't get read. Is there a way to fix this in CI? I'm also having an issue with users being able to manually access the controller functions. I've tried to change them to private as people have suggested, but then my scripts can't access them. For instance:
www.somesite.com/controller_file/some_function
How do I block them from accessing this function?
You can create a whitelist sollution:
Open your application/config/routes.php
add the routes you want to allow.
add a catchall route .* And redirect it to a errot handler
Codeigniters trys to matches the route patterns in the order they are listed in the array so
whenever a user enters a route you did not explicitly allow it will allqays redirect him to the catchall route
user-guide on routing
EDIT:
You can create a blacklist logic by redirecting only requests matching a specific pattern, and keep the default behaviour for all others.
As far as denying access to the filesystem goes, your best bet would be to to place your Application and System folders outside of the webroot. Then edit your index.php to set the new path to each folder. My general set up looks like this:
+ Root
| - Application
| - System
| + Webroot
| | - js
| | - css
| | - index.php
| | - ...
+ - ...
As for your second question, to prevent certain functions from being accessed directly from the url you need to prepend them with an underbar.
So instead of
public function some_function() {...}
Use
public function _some_function() {...}
It can then be called in your controller with $this->_some_function();
If you have any AJAX functions, you'll need to drop the underbar from their name to make them accessible. You can stop users accessing them directly from the URL by wrapping your functions with the following conditional.
if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest')) {}
The above checks if the request is via AJAX.

CodeIgniter subfolders and URI routing

I’ve read the manual on URI routing and views and something is not clicking with me.
In my views folder, I have a subfolder called products. In there is a file called product_view. In my controller, I have:
function index() {
$data['title'] = 'Product Overview';
$data['main_content'] = 'products/product_view';
$this->load->view('templates/main.php', $data);
}
The template loads a header view, a footer view and a navigation view, plus the view as a main content variable.
In my URI routing, I have:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/*
| -------------------------------------------------------------------------
| URI ROUTING
| -------------------------------------------------------------------------
| This file lets you re-map URI requests to specific controller functions.
|
| Typically there is a one-to-one relationship between a URL string
| and its corresponding controller class/method. The segments in a
| URL normally follow this pattern:
|
| example.com/class/method/id/
|
| In some instances, however, you may want to remap this relationship
| so that a different class/function is called than the one
| corresponding to the URL.
|
| Please see the user guide for complete details:
|
| http://codeigniter.com/user_guide/general/routing.html
|
| -------------------------------------------------------------------------
| RESERVED ROUTES
| -------------------------------------------------------------------------
|
| There are two reserved routes:
|
| $route['default_controller'] = 'welcome';
|
| This route indicates which controller class should be loaded if the
| URI contains no data. In the above example, the "welcome" class
| would be loaded.
|
| $route['scaffolding_trigger'] = 'scaffolding';
|
| This route lets you set a "secret" word that will trigger the
| scaffolding feature for added security. Note: Scaffolding must be
| enabled in the controller in which you intend to use it. The reserved
| routes must come before any wildcard or regular expression routes.
|
*/
$route['default_controller'] = "index_controller";
$route['laser-configurator'] = "configurator";
$route['news-and-events'] = "news";
$route['products/product-overview'] = "products/product_view";
$route['scaffolding_trigger'] = "";
/* End of file routes.php */
/* Location: ./system/application/config/routes.php */
This causes a 404 error when I try to go to domain.com/products/product-overview. Do I need to do something with my .htaccess? If so, what? Here is my .htaccess:
Options +FollowSymLinks
Options -Indexes
DirectoryIndex index.php
RewriteEngine on
RewriteCond $1 !^(index\.php|resources|images|css|js|robots\.txt|favicon\.ico)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?/$1 [L,QSA]
I’d appreciate some specific help, as the documentation isn’t specific on how to address this. I’ve done a little searching in the forums, and didn’t see anything, but I’m posting this while I keep looking.
In CI URIs are routed by the name of your controller and the name of the method in the controller.
If the controller is named "products.php" the function for the corresponding view is called "index", the correct URI for that page is "/products".
So your code should be
$route['products/product-overview'] = 'products/index';
To use multi-level directory structure for your controllers use router extention talked about in this post, I have used it on occasion, and can vouch for it working.

Categories