Our clients always come back and complain that CUrlValidator forces their users to type "http://" at the beginning of a website address.
So I wrote the following replacement for the URL validator:
<?php
/**
* GUrlValidator - a more relaxed alternative to CUrlValidator
*/
/**
* GUrlValidator validates that the attribute value is a valid http or https URL.
*
* This validator is more relaxed then CUrlValidator, accepting URLs with no protocol.
*/
class GUrlValidator extends CValidator
{
/**
* @var string the regular expression used to validates the attribute value.
*/
public $protocolPattern='/^(http|https)$/i';
/**
* @var string the regular expression used to validates the attribute value.
*/
public $uriPattern='/^(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)/i';
/**
* @var string default protocol for URLs with no protocol specified.
*
* Defaults to "http://", meaning "www.google.com" is considered valid. To perform
* strict URL validation, set this to null.
*/
public $defaultProtocol='http://';
/**
* @var boolean whether the attribute value can be null or empty. Defaults to true,
* meaning that if the attribute is empty, it is considered valid.
*/
public $allowEmpty=true;
/**
* Validates the attribute of the object.
*
* If there is any error, the error message is added to the object.
*
* If $defaultProtocol is enabled, and the URL does not contain a protocol, the attribute
* is updated with the default protocol applied to it.
*
* @param CModel the object being validated
* @param string the attribute being validated
*/
protected function validateAttribute($object,$attribute)
{
$value=$object->$attribute;
if($this->allowEmpty && $this->isEmpty($value))
return;
if($validated=$this->validateValue($value))
{
$object->$attribute=$validated;
}
else
{
$message=$this->message!==null?$this->message:Yii::t('yii','{attribute} is not a valid URL.');
$this->addError($object,$attribute,$message);
}
}
/**
* Validates a static value to see if it is a valid URL.
*
* Note that this method does not respect {@link allowEmpty} property.
* This method is provided so that you can call it directly without going through the model validation rule mechanism.
*
* @param mixed the value to be validated
* @return mixed the fully qualified URL (with protocol applied, if missing) or null, if the URL was invalid
*/
public function validateValue($value)
{
if (!is_string($value))
return false;
$parts=explode('://',$value,2);
if (count($parts)==1 && $this->defaultProtocol!==null)
return preg_match($this->uriPattern,$parts[0]) ? $this->defaultProtocol.$value : null;
else
return count($parts)==2 && preg_match($this->protocolPattern,$parts[0]) && preg_match($this->uriPattern,$parts[1]) ? $value : null;
}
}
This validator lets you specify a default protocol - and if the protocol part is missing from the input, it automatically goes back to the model and corrects the value during validation.
Enjoy