Ensure uniciy to url ¶
Many time for SEO porpouses is important that each page will have a unique address.
If, for example, we have a rule like:
'post/<id:\d+>'=>'post/read',
This url will be valid:
post/read/id/5
post/read?id=5
post/5
If we have a suffix, for example .html, also this url will be available:
post/read/id/5.html
post/read.html?id=5
post/5.html
A total of 6 url, that is not seo compliant.
The solution is quite simple, just write this in your controller:
public function beforeAction($action)
{
$normalizedUrl = CHtml::normalizeUrl(array_merge(array("/".$this->route), $_GET));
if (Yii::app()->request->url != $normalizedUrl && strpos($normalizedUrl, Yii::app()->errorHandler->errorAction) === false) {
$this->redirect($normalizedUrl, true, 301);
}
return parent::beforeAction($action);
}
This will redirect all alternative url to the one 'legal'. Using 301 instead 302 will make the browser (and, we hope, google bots) aware that the correct address is another one.
You can implement a master class for semplicity:
<?php
/**
* BlockController is a customized base controller class.
* All controller classes with unique url should extend from this base class.
*/
class BlockController extends Controller
{
public function beforeAction($action)
{
$normalizedUrl = CHtml::normalizeUrl(array_merge(array("/".$this->route), $_GET));
if (Yii::app()->request->url != $normalizedUrl && strpos($normalizedUrl, Yii::app()->errorHandler->errorAction) === false) {
$this->redirect($normalizedUrl, true, 301);
}
return parent::beforeAction($action);
}
}
Notice that you cannot add this rule for actionError and actionIndex, so if you want to make unique addresses in the site controller you cannot extend the master controller, but you have to implement a special method with exception for this two actions.
Strict parsing
One can enable CUrlManager::useStrictParsing to disallow such url variations.
nice, but does not work as expected...
Have found that this works:
$url = array_merge( array( "/" . $this->route ), $_GET ); if( Yii::app()->request->url != CHtml::normalizeUrl( $url ) ) { $this->redirect( $url, true, 301 ); }
Most important is "/" (slash) prepended to route as controller can be placed in module and in such case your code throws error.
Exception for error handler
You don't want to redirect when Yii is calling the error handler:
$normalizedUrl = CHtml::normalizeUrl(array_merge(array("/".$this->route), $_GET)); if (Yii::app()->request->url != $normalizedUrl && strpos($normalizedUrl, Yii::app()->errorHandler->errorAction) === false) { $this->redirect($normalizedUrl, true, 301); }
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.