Magento: Language detection and url 404 error - magento

I've configured my magento index.php so it detects the browser language and redirects the user to the corresponding store view. That works fine. But there is a problem with this with url specific for each store view. For example, a have a product with the url:
./product-url-in-english --> English view
./product-url-in-catalan --> Catalan view
If my browser is configured in English and I go to the Catalan url, then I got a 404 error, because that url is only for the Catalan view, but given that I'm detecting the browser language and redirecting to the English view, the Catalan URL won't work.
If I use the paramenters from_store and store, it will work, but I don't know how to reflect that on my index.php file. The code that detects the browser language is the following:
/* Language detection */
function getLanguageCode()
{
$default_language_code = 'es';
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
foreach (explode(",", strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE'])) as $accept) {
if (preg_match("!([a-z-]+)(;q=([0-9.]+))?!", trim($accept), $found)) {
$langs[] = $found[1];
$quality[] = (isset($found[3]) ? (float) $found[3] : 1.0);
}
}
// Order the codes by quality
array_multisort($quality, SORT_NUMERIC, SORT_DESC, $langs);
// get list of stores and use the store code for the key
$stores = Mage::app()->getStores(false, true);
// iterate through languages found in the accept-language header
foreach ($langs as $lang) {
$lang = substr($lang,0,2);
if (isset($stores[$lang]) && $stores[$lang]->getIsActive())
return $lang;
}
}
return $default_language_code;
}
/* Store or website code */
if(isset($_SERVER['MAGE_RUN_CODE']))
$mageRunCode = $_SERVER['MAGE_RUN_CODE'];
else
$mageRunCode = getLanguageCode();
/* Run store or run website */
$mageRunType = isset($_SERVER['MAGE_RUN_TYPE']) ? $_SERVER['MAGE_RUN_TYPE'] : 'store';
Mage::run($mageRunCode, $mageRunType);
What do I need to change in my index.php file so I can handle url from all the store views and redirect to the specific page without getting a 404 error?
Thanks

Related

Laravel url previous return same page after page reload

I tried to access the previous URL on Laravel 5.3 Homestead by several methods but all times i got the right previous page at first request then i got the same page after i refresh the page.
I am using Middleware to check the language before accessing the page
URL::previous();
// or
back()->getTargetUrl();
Language middleware
public function handle($request, Closure $next, $guard = null) {
$locale = $request->locale;
$segments = $request->segments();
$lang_sess = $request->session()->get('language');
if (!array_key_exists($locale, Config::get('app.locales'))) :
if (count($segments) > 1):
$segments[0] = ($lang_sess == "") ? Config::get('app.fallback_locale') : $lang_sess;
$re_to = implode('/', $segments);
else:
$locale = $request->session()->get('language', 'en');
$re_to = "/$locale/" . implode('/', $segments);
endif;
return Redirect::to($re_to);
endif;
$request->session()->put('language', $locale);
App::setLocale($locale);
return $next($request);
}
[SOLVED]
as i still developing my web app, i didn't go the page through a 'href' link, i was entering it through copy and paste the URL into browser, and this causes the URL::previous to be changed after reload the page..
Case closed, thanks for all who replied and gave attention.
the 'previous URL' is stored in a session.Every time your URL changes, the session()->get('_previous')['url'] will change to previous url.
Doing the logic this way:
if (url()->current() == url()->previous()) {
url()->setPreviousUrl('xxx') // or other logic here
}
If you go to page A from B . Your previous page will be B . But if you refresh page then you are going from A to page A.
I suggest to use cookie in this case by checking previous page , if different change cookie otherwise keep it as it is.
$last_page = URL::previous();
if(Cookie::get("previous_page") == $last_page){
Cookie::make('previous_page',$last_page, 60);
}
Now you can use this cookie value Cookie::get ("previous_page") in your middleware
Not tested but this would guide you.

Laravel 4. Russian language as default

I adjusted app.php as per instruction:
'locale' => 'ru',
'fallback_locale' => 'en',
But on first visiting the site it always shows an english version. Thus russia based user always needs to click "Russian" button to view russian version of the site.(language switching was created with Session::put('lang', $lang) and redirect to /).
I also tried using handling session language in App::before filter but no luck: it shows in russian all the database content but all that in trans('message.<word>') remains in english (the code is now commented in filter.php).
The project is available on github (to look through files where you may suspect a reason).
The site address www.izutov.com (there are "English" and "Russian" buttons in the left top corner)
Thnx in advance!
This is what I have done to set language selection in Laravel 4 :
in app/filters.php
App::before(function($request) {
Route::matched(function($route, $request) {
if($route->getName() != 'admin') { // don't do it for admin area, (for example)
$language = $_ENV['FALLBACK_LOCALE'];
$lgs = explode(',', $_ENV['LANGUAGES']); // your set of languages
// get the default browser language with the $request object
$browserLg = substr($request->server->get('HTTP_ACCEPT_LANGUAGE'), 0, 2);
// language set from route (for example /en/some-url)
$requestLg = $request->segment(1);
# if the language called in url request matches your set of languages
if (null !== $requestLg && in_array($requestLg, $lgs)) {
$language = $requestLg;
# default browser lg
} else {
if(in_array($browserLg, $lgs)) {
$language = $browserLg;
}
}
// set the validated language
$_ENV['LOCALE'] = $language;
Config::set('locale',$language);
App::setLocale($language);
// share it with views if you want
View::share('locale', $language);
});
});

How to log Magento "404" pages

I'm running a Magento Community website (on version 1.5.1) and I'm having an issue with "404" pages.
We have users landing on our site from direct links and also google/bing search results. The pages they go to may not be correct as they may have changed. Magento uses MVC to route requests to the correct controller, but when there isn't a controller Magento displays a static CMS page (i.e. "404" page). The problem is that this page doesn't allow me to write custom PHP code on it so I can't log the URL that caused the 404.
If I can find the right point in the code prior to displaying the CMS 404 page then I can log the URL and use that to do the appropriate URL rewriting.
Can someone help me as to where the code is that finally gives up on any controller and displays the custom CMS "404" page?
Basically this is happening in Mage_Cms_IndexController::noRouteAction(). But you also could just have a look at your webservers log for entries with the 404 return code (404 is set in the same method).
Alex was spot-on with his answer. I thought I'd post the code I wrote to solve the problem based on his answer.
/**
* Render CMS 404 Not found page
*
* #param string $coreRoute
*/
public function noRouteAction($coreRoute = null)
{
$this->getResponse()->setHeader('HTTP/1.1','404 Not Found');
$this->getResponse()->setHeader('Status','404 File not found');
/* JCS */
$path = $this->getRequest()->getPathInfo();
if (!startsWith($path, '/media/')) {
if (!startsWith($path, '/images/')) {
if (!startsWith($path, '/ebay/')) {
if (!startsWith($path, '/app/')) {
Mage::log('JCS:noRouteAction:path:'.$path);
}
}
}
}
$pageId = Mage::getStoreConfig(Mage_Cms_Helper_Page::XML_PATH_NO_ROUTE_PAGE);
if (!Mage::helper('cms/page')->renderPage($this, $pageId)) {
$this->_forward('defaultNoRoute');
}
}
I also added a startsWith function:
/* JCS */
function startsWith($haystack, $needle)
{
$length = strlen($needle);
return (substr($haystack, 0, $length) === $needle);
}

Codeigniter global_xss_filtering

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.

Codeigniter - best routes configuration for CMS?

I would like to create a custom CMS within Codeigniter, and I need a mechanism to route general pages to a default controller - for instance:
mydomain.com/about
mydomain.com/services/maintenance
These would be routed through my pagehandler controller. The default routing behaviour in Codeigniter is of course to route to a matching controller and method, so with the above examples it would require an About controller and a Services controller. This is obviously not a practical or even sensible approach.
I've seen the following solution to place in routes.php:
$route['^(?!admin|products).*'] = "pagehandler/$0";
But this poses it's own problems I believe. For example, it simply looks for "products" in the request uri and if found routes to the Products controller - but what if we have services/products as a CMS page? Does this not then get routed to the products controller?
Is there a perfect approach to this? I don't wish to have a routing where all CMS content is prefixed with the controller name, but I also need to be able to generically override the routing for other controllers.
If you use CodeIgniter 2.0 (which has been stable enough to use for months) then you can use:
$route['404_override'] = 'pages';
This will send anything that isn't a controller, method or valid route to your pages controller. Then you can use whatever PHP you like to either show the page or show a much nicer 404 page.
Read me guide explaining how you upgrade to CodeIgniter 2.0. Also, you might be interested in using an existing CMS such as PyroCMS which is now nearing the final v1.0 and has a massive following.
You are in luck. I am developing a CMS myself and it took me ages to find a viable solution to this. Let me explain myself to make sure that we are on the same page here, but I am fairly certain that we area.
Your URLS can be formatted the following ways:
http://www.mydomain.com/about - a top level page with no category
http://www.mydomain.com/services/maintenance - a page with a parent category
http://www.mydomain.com/services/maintenace/server-maintenance - a page with a category and sub category.
In my pages controller I am using the _remap function that basically captures all requests to your controllers and lets you do what you want with them.
Here is my code, commented for your convenience:
<?php
class Pages extends Controller {
// Captures all calls to this controller
public function _remap()
{
// Get out URL segments
$segments = $this->uri->uri_string();
$segments = explode("/", $segments);
// Remove blank segments from array
foreach($segments as $key => $value) {
if($value == "" || $value == "NULL") {
unset($segments[$key]);
}
}
// Store our newly filtered array segments
$segments = array_values($segments);
// Works out what segments we have
switch (count($segments))
{
// We have a category/subcategory/page-name
case 3:
list($cat, $subcat, $page_name) = $segments;
break;
// We have a category/page-name
case 2:
list($cat, $page_name) = $segments;
$subcat = NULL;
break;
// We just have a page name, no categories. So /page-name
default:
list($page_name) = $segments;
$cat = $subcat = NULL;
break;
}
if ($cat == '' && $subcat == '') {
$page = $this->mpages->fetch_page('', '', $page_name);
} else if ($cat != '' && $subcat == '') {
$page = $this->mpages->fetch_page($cat, '', $page_name);
} else if ($category != "" && $sub_category != "") {
$page = $this->mpages->fetch_page($cat, $subcat, $page_name);
}
// $page contains your page data, do with it what you wish.
}
?>
You of course would need to modify your page fetching model function accept 3 parameters and then pass in info depending on what page type you are viewing.
In your application/config/routes.php file simply put what specific URL's you would like to route and at the very bottom put this:
/* Admin routes, login routes etc here first */
$route['(:any)'] = "pages"; // Redirect all requests except for ones defined above to the pages controller.
Let me know if you need any more clarification or downloadable example code.

Resources