I would like to pass some site-wide validated variables before controller segment in URL.
Example:
Default URL would be:
www.mysite.com/controller/method/variable/
Sometimes I'd like to have also URL like this to refer to user created sub-configuration of this site (theme, menus, ...), so user could share this site URL nicely and others would see the site though his custom configurations.
www.mysite.com/username/controller/method/variable
Here username is custom part of base_url. It should be validated against database and set as session variable to use it later in my controllers and change theme for example. Also all the links on the site would start to use www.mysite.com/username as base_url after website is entered with this username in the URL.
One way to solve this would be routing it like this:
controller/method/variable_name1/variable_value1/user_conf/username
...and the add the implementation to every single controller in my project. But this is not an elegant solution.
Is this what you're after:
$route['(:any)/(:any)'] = '$2/$1';
where all your function definitions have the username as the last parameter:
class Controller{function page(var1, var2, ..., varn, username){}}
Or, if you only want in on one specific page you could do something like this:
$route['(:any)/controller/page/(:any)'] = 'controller/page/$2/$1'; //This will work for the above class.
Or, if you want it for a number of functions in a controller you could do this:
$route['(:any)/controller/([func1|func2|funcn]+)/(:any)'] = 'controller/$2/$3/$1';
After messing with this problem for a day I ended up with adding custom router class to my project. I'm working in CodeIgniter 2.0, so the location of this file should be application/core/MY_Router.php
My code is following:
class MY_Router extends CI_Router {
// --------------------------------------------------------------------
/**
* OVERRIDE
*
* Validates the supplied segments. Attempts to determine the path to
* the controller.
*
* #access private
* #param array
* #return array
*/
function _validate_request($segments)
{
if (count($segments) == 0)
{
return $segments;
}
// Does the requested controller exist in the root folder?
if (file_exists(APPPATH.'controllers/'.$segments[0].EXT))
{
return $segments;
}
$users["username"] = 1;
$users["minu_pood"] = 2;
// $users[...] = ...;
// ...
// Basically here I load all the
// possbile username values from DB, memcache, filesystem, ...
if (isset($users[$segments[0]])) {
// If my segments[0] is in this set
// then do the session actions or add cookie in my cast.
setcookie('username_is', $segments[0], time() + (86400 * 7));
// After that remove this segment so
// rounter could search for controller!
array_shift($segments);
return $segments;
}
// So segments[0] was not a controller and also not a username...
// Nothing else to do at this point but show a 404
show_404($segments[0]);
}
}
Related
I want to access route request parameters inside laravel form requests authorize. I cant find an example describing this.
// Works fine when you want id
dd($this->route('myResourceName'));
// How to do when I want something else???
dd($this->route('anotherAttribute'));
// Above give null probably because it is a resourceful controller
On a side note, I dont understand this design, whats the point?
$this->route('anyAttribute') would be the easiest, right?
Edit: more extensive example
class UpdateSlotAPIRequest extends APIRequest
{
public function __construct(){
parent::__construct();
$this->slot = Slot::find($this->route('slot'));
$this->access_token = $this->route('access_token'); // this is not working!
}
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
// If administrator is logged in all is good.
// If slot is free its ok.
// If its not free but you provide good access_token its also fine.
return Auth::check() || $this->slot->isAvailable() || $this->slot->isValidAccessToken($this->access_token);
}
...
```
$access_token = request()->input('access_token');
Found it in https://laravel.com/docs/5.4/helpers
Let's say I have a controller and I want to define some const variables that hold some messages (eg error messages etc).
Is there a way to make it so they are translated?
An example class is defined bellow:
<?php
namespace Test\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
class AccountController extends AbstractActionController
{
protected $testError = 'There was an error while testing some stuff';
public function testAction(){
// I know i can use the following approach but I don't want to
// since I want to use a variable for readability issues.
// $testError = $this->getTranslator()->translate('There was an error..');
return new ViewModel();
}
/**
* Retrieve the translator
*
* #return \Zend\I18n\Translator\Translator
*/
public function getTranslator()
{
if (!$this->translator) {
$this->setTranslator($this->getServiceLocator()->get('translator'));
}
return $this->translator;
}
/**
* Set the translator
*
* #param $translator
*/
public function setTranslator($translator)
{
$this->translator = $translator;
}
}
So I want to have the testError translated. I know I can just use the message and translate it via the zend translator without using a variable, but still I want to store it in a variable for readability issues. Any help or other approaches to this?
Simply create a translations.phtml file in any directory in your project root and fill it something like that:
<?php
// Colors
_('Black');
_('White');
_('Green');
_('Light Green');
_('Blue');
_('Orange');
_('Red');
_('Pink');
In poedit, check Catalog Properties > Source keywords list an be sure _ character is exists. (Alias of the gettext method). In application, use $this->translate($colorName) for example.
When poedit scanning your project directory to find the keywords which needs to be translated, translations.phtml file will be scanned too.
Another handy approach is using _ method (gettext alias) to improve code readability. Example:
$this->errorMsg = _('There was an error..');
But don't forget to set the global Locale object's default locale value too when you initialising your translator instance first time in a TranslatorServiceFactory or onBootstrap method of the module:
...
$translator = \Zend\Mvc\I18n\Translator\Translator::factory($config['translator']);
$locale = 'en_US';
$translator->setLocale($locale);
\Locale::setDefault($translator->getLocale());
return $translator;
...
I don't quite understand what you mean:
$errorMessage = 'FooBarBazBat";
return new ViewModel(array(
'error' => $this->getTranslator()->translate($errorMessage)
));
would be a way to store the message inside a variable. But i really don't understand where your problem is.
Or do you mean having the translator as variable?
$translator = $this->getServiceLocator()->get('viewhelpermanager')->get('translate');
$errorMessage = $translator('FooBarBazBat');
I am using Laravel 3 with two sets of login controllers - the main domain goes to login, all subdomains should route to portal/login#index
I am using the following code in my routes.php:
Route::filter('before', function()
{
$server = explode('.', Request::server('HTTP_HOST'));
if (count($server) == 3)
{
$account = Account::where('subdomain', '=', $server[0])->first();
Session::put('account_id', $account->id);
Route::get('login', 'portal.login#index');
Route::post('login', 'portal.login#index');
Route::get('logout/(:any)', 'portal.login#logout');
}
else
{
// some other stuff - no routing calls in here
}
}
This code works fine for capturing the subdomain & doing the other tasks (such as setting the $account_id), but seem to have no affect on the routing
test.mydomain.com/login should go to portal/login, but instead goes to the main login controller.
I've searched through to be sure there are no filters affecting this (it is an inherited app)
Is this the correct way to set this up, and if so, what else might be affecting this?
TIA!
It's because when you are inside
if (count($server) == 3)
{
// Here
}
The registering of new routes using get/post is not going to respond because the system has already done the route matching, in this case you can forward the request to a new route using
Route::forward($method, $uri);
Which is in laravel/routing/route.php file as given nelow
/**
* Calls the specified route and returns its response.
*
* #param string $method
* #param string $uri
* #return Response
*/
public static function forward($method, $uri)
{
return Router::route(strtoupper($method), $uri)->call();
}
So, if you want to create a request similar to Route::get('login', 'portal.login#index'); then you can do it as
Route::forward('GET', 'login');
In this case, you have keep this route registered just normally you register a route. So, register/add the requests in the routes.php that you want to create dynamically and use Route::forward() method inside
if (count($server) == 3)
{
Route::forward('GET', 'login'); // for a get request
Route::forward('POST', 'login'); // for a post request
}
That's it.
In my codeigniter config I have $config['global_xss_filtering'] = TRUE;. In my admin section I have a ckeditor which generates the frontend content.
Everything that is typed and placed inside the editor works fine, images are displayed nice, html is working. All except flash. Whenever I switch to html mode and paste a youtube code piece it is escaped and the code is visible on the frontpage instead of showing a youtube movie.
If I set $config['global_xss_filtering'] = FALSE; the youtube code is passed like it should. This is because 'object', 'embed' etc are flagged as "naughty" by CI and thus escaped.
How can I bypass the xss filtering for this one controller method?
Turn it off by default then enable it for places that really need it.
For example, I have it turned off for all my controllers, then enable it for comments, pages, etc.
One thing you can do is create a MY_Input (or MY_Security in CI 2) like the one in PyroCMS and override the xss_clean method with an exact copy, minus the object|embed| part of the regex.
http://github.com/pyrocms/pyrocms/blob/master/system/pyrocms/libraries/MY_Security.php
It's one hell of a long way around, but it works.
Perhaps we could create a config option could be created listing the bad elements for 2.0?
My case was that I wanted global_xss_filtering to be on by default but sometimes I needed the $_POST (pst you can do this to any global php array e.g. $_GET...) data to be raw as send from the browser, so my solution was to:
open index.php in root folder of the project
added the following line of code $unsanitized_post = $_POST; after $application_folder = 'application'; (line #92)
then whenever I needed the raw $_POST I would do the following:
global $unsanitized_post;
print_r($unsanitized_post);
In CodeIgniter 2.0 the best thing to do is to override the xss_clean on the core CI library, using MY_Security.php put this on application/core folder then using /application/config.php
$config['xss_exclude_uris'] = array('controller/method');
here's the MY_Security.php https://gist.github.com/slick2/39f54a5310e29c5a8387:
<?php
/**
* CodeIgniter version 2
* Note: Put this on your application/core folder
*/
class MY_Security extends CI_Security {
/**
* Method: __construct();
* magic
*/
function __construct()
{
parent::__construct();
}
function xss_clean($str, $is_image = FALSE)
{
$bypass = FALSE;
/**
* By pass controllers set in /application/config/config.php
* config.php
* $config['xss_exclude_uris'] = array('controller/method')
*/
$config = new CI_Config;
$uri = new CI_URI;
$uri->_fetch_uri_string();
$uri->_explode_segments();
$controllers_list = $config->item('xss_exclude_uris');
// we need controller class and method only
if (!empty($controllers_list))
{
$segments = array(0 => NULL, 1 => NULL);
$segments = $uri->segment_array();
if (!empty($segments))
{
if (!empty($segments[1]))
{
$action = $segments[0] . '/' . $segments[1];
}
else
{
$action = $segments[0];
}
if (in_array($action, $controllers_list))
{
$bypass = TRUE;
}
}
// we unset the variable
unset($config);
unset($uri);
}
if ($bypass)
{
return $str;
}
else
{
return parent::xss_clean($str, $is_image);
}
}
}
Simple do the following on the views when displaying embedded object code like from YouTube and etc:
echo str_replace(array('<', '>'), array('<', '>'), $embed_filed);
The global XSS Filtering is only escaping (or converting) certain "dangerous" html tags like <html>
Simple Workaround:
Set $config['global_xss_filtering'] = TRUE;
Run your POST data through HTMLPurifier to remove any nasty <script> tags or javascript.
HTMLPurifier Docs
HTMLPurifier Codeigniter Integration
On the page where you receive the forms POST data use html_entity_decode() to undo what XSS filtering did.
//by decoding first, we remove everything that XSS filter did
//then we encode all characters equally.
$content = html_entity_decode($this->input->post('template_content'))
Then immediately run it through htmlentities()
$content = htmlentities($content);
Store as a Blob in MySQL database
When you want to display the
information to the user for editing run html_entity_decode()
This is how I did it. If anyone knows of a major flaw in what I did, please tell me. It seems to be working fine for me. Haven't had any unexpected errors.
I have multiple blocks shown on the user profile page, user/uid
On each of them, I need to print the user name.
I've been doing a $user = user_load(arg(1)); print $user->name; on each block. Since there is no caching, as you can image the performance is HORRIBLE.
Is there either a way to get the user name more efficiently or to cache user_load.
Thanks.
Just add an intermediate function to provide the static caching yourself:
/**
* Proxy for user_load(), providing static caching
* NOTE: Only works for the common use of user_load($uid) - will NOT load by name or email
*
* #param int $uid - The uid of the user to load
* #param bool $reset - Wether to reset the static cache for the given uid, defaults to FALSE
* #return stdClass - A fully-loaded $user object upon successful user load or FALSE if user cannot be loaded.
*/
function yourModule_user_load_cached($uid, $reset = FALSE) {
static $users = array();
// Do we need to (re)load the user?
if (!isset($users[$uid]) || $reset) {
$users[$uid] = user_load($uid);
}
return $users[$uid];
}
Use menu_get_object() which is the proper way to retrieve an object (user, node, etc.) loaded from the URL of a properly declared page. It will return the user object that has already been loaded using the uid found at arg(1) for a menu item which use %user in its path (ie. $items['user/%user'], $items['user/%user/view'], etc. in user_menu().
$account = menu_get_object('user');
The user is a global.
function myfunction() {
global $user;
}