Browse Source
Validator, captcha, form, #16
Validator, captcha, form, #16
git-svn-id: svn+ssh://code.netmonsters.ru/svn/majestic/branches/evo@141 4cb57b5f-5bbd-dd11-951b-001d605cbbc5master
pzinovkin
15 years ago
19 changed files with 660 additions and 9 deletions
-
79captcha/Captcha.php
-
21captcha/CaptchaImageAction.php
-
32captcha/CaptchaValidator.php
-
BINcaptcha/poh.ttf
-
3exception/ErrorHandler.php
-
119form/Form.php
-
173form/FormField.php
-
44form/FormViewHelper.php
-
17validator/EmailValidator.php
-
32validator/NotEmptyValidator.php
-
41validator/RegexValidator.php
-
65validator/Validator.php
-
16validator/iValidator.php
-
2view/PHPView.php
-
2view/helpers/BreadcrumbViewHelper.php
-
2view/helpers/GetViewHelper.php
-
2view/helpers/HeadViewHelper.php
-
17view/helpers/MsgViewHelper.php
-
2view/helpers/TitleViewHelper.php
@ -0,0 +1,79 @@ |
|||||
|
<?php |
||||
|
/** |
||||
|
* @copyright NetMonsters <team@netmonsters.ru> |
||||
|
* @link http://netmonsters.ru |
||||
|
* @package Majestic |
||||
|
* @subpackage captcha |
||||
|
* @since 2010-04-24 |
||||
|
* @version SVN: $Id$ |
||||
|
* @filesource $URL$ |
||||
|
*/ |
||||
|
|
||||
|
class Captcha |
||||
|
{ |
||||
|
|
||||
|
protected $font_size = 38; |
||||
|
protected $width = 200; |
||||
|
protected $height = 70; |
||||
|
|
||||
|
|
||||
|
public function getImage($token) |
||||
|
{ |
||||
|
$font = dirname(__FILE__) . '/poh.ttf'; |
||||
|
|
||||
|
$image = imagecreatetruecolor($this->width, $this->height); |
||||
|
// белый фон
|
||||
|
$background = imagecolorallocate($image, 255, 255, 255); |
||||
|
imagefilledrectangle($image, 0, 0, $this->width, $this->height, $background); |
||||
|
|
||||
|
// основная магия тут
|
||||
|
if (Session::get('_ctoken') == $token && Session::get('_ccode')) { |
||||
|
|
||||
|
$code = Session::get('_ccode'); |
||||
|
|
||||
|
$color = imagecolorallocate($image, 81, 81, 81); |
||||
|
|
||||
|
for ($j = 0; $j < 5; $j++) { |
||||
|
imageellipse($image, rand(-$this->width, $this->width * 2), |
||||
|
rand(-$this->height, $this->height * 2), |
||||
|
$this->width, $this->width, $color); |
||||
|
} |
||||
|
|
||||
|
$letters = preg_split("//u", strtoupper($code)); |
||||
|
$length = count($letters); |
||||
|
$step = floor($this->width / $length); |
||||
|
$i = 2; |
||||
|
|
||||
|
foreach ($letters as $key => $letter) { |
||||
|
imagettftext($image, $this->font_size, 0, |
||||
|
rand($i + 2, $i + 4), ($this->font_size + $this->height) / 2, |
||||
|
$color, $font, $letter); |
||||
|
$i = $i + $step ; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
ob_start(); |
||||
|
header("Cache-Control: no-store, no-cache, must-revalidate"); |
||||
|
header("Content-Type: image/jpg"); |
||||
|
imagejpeg($image, '', 100); |
||||
|
imagedestroy($image); |
||||
|
return ob_get_clean(); |
||||
|
} |
||||
|
|
||||
|
public function getToken() |
||||
|
{ |
||||
|
$token = md5(microtime() . uniqid()); |
||||
|
$code = strtoupper(substr(str_ireplace(array('0', 'O'), '', md5(time() . 'captcha' . rand(0, 1000))), 1, 5)); |
||||
|
Session::set('_ctoken', $token); |
||||
|
Session::set('_ccode', $code); |
||||
|
return $token; |
||||
|
} |
||||
|
|
||||
|
public function checkCode($token, $code) |
||||
|
{ |
||||
|
if (Session::get('_ctoken') == $token && Session::get('_ccode') == strtoupper($code)){ |
||||
|
return true; |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
} |
@ -0,0 +1,21 @@ |
|||||
|
<?php |
||||
|
/** |
||||
|
* @copyright NetMonsters <team@netmonsters.ru> |
||||
|
* @link http://netmonsters.ru |
||||
|
* @package Majestic |
||||
|
* @subpackage captcha |
||||
|
* @since 2010-04-24 |
||||
|
* @version SVN: $Id$ |
||||
|
* @filesource $URL$ |
||||
|
*/ |
||||
|
|
||||
|
class CaptchaImageAction |
||||
|
{ |
||||
|
|
||||
|
public function __construct() |
||||
|
{ |
||||
|
$captcha = new Captcha(); |
||||
|
echo $captcha->getImage(Env::Get('ctoken')); |
||||
|
exit(); |
||||
|
} |
||||
|
} |
@ -0,0 +1,32 @@ |
|||||
|
<?php |
||||
|
/** |
||||
|
* @copyright NetMonsters <team@netmonsters.ru> |
||||
|
* @link http://netmonsters.ru |
||||
|
* @package Majestic |
||||
|
* @subpackage validator |
||||
|
* @since 2010-04-26 |
||||
|
* @version SVN: $Id$ |
||||
|
* @filesource $URL$ |
||||
|
*/ |
||||
|
|
||||
|
class CaptchaValidator extends Validator |
||||
|
{ |
||||
|
|
||||
|
const WRONG_CODE = 'is_empty'; |
||||
|
|
||||
|
protected $templates = array(self::WRONG_CODE => 'Entered code wrong'); |
||||
|
|
||||
|
public function isValid($value, $context = null) |
||||
|
{ |
||||
|
if (!$context || !isset($context['ctoken']) || !isset($context['ccode'])) { |
||||
|
$this->error(); |
||||
|
return false; |
||||
|
} |
||||
|
$captcha = new Captcha(); |
||||
|
if ($captcha->checkCode($context['ctoken'], $context['ccode'])) { |
||||
|
return true; |
||||
|
} |
||||
|
$this->error(); |
||||
|
return false; |
||||
|
} |
||||
|
} |
@ -0,0 +1,119 @@ |
|||||
|
<?php |
||||
|
/** |
||||
|
* @copyright NetMonsters <team@netmonsters.ru> |
||||
|
* @link http://netmonsters.ru |
||||
|
* @package Majestic |
||||
|
* @subpackage form |
||||
|
* @since 2010-04-24 |
||||
|
* @version SVN: $Id$ |
||||
|
* @filesource $URL$ |
||||
|
*/ |
||||
|
|
||||
|
abstract class Form |
||||
|
{ |
||||
|
|
||||
|
const SUCCESS = 'success'; |
||||
|
const ERROR = 'error'; |
||||
|
|
||||
|
protected $fields = array(); |
||||
|
protected $messages = array(self::SUCCESS => 'Form data valid', |
||||
|
self::ERROR => 'Form data invalid'); |
||||
|
|
||||
|
protected $valid = true; |
||||
|
|
||||
|
public function __construct() |
||||
|
{ |
||||
|
$this->init(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @param string $name |
||||
|
* @return FormField |
||||
|
*/ |
||||
|
protected function addField($name, $message = false) |
||||
|
{ |
||||
|
$this->fields[$name] = new FormField($message); |
||||
|
return $this->fields[$name]; |
||||
|
} |
||||
|
|
||||
|
public function isValid($data) |
||||
|
{ |
||||
|
if (!is_array($data)) { |
||||
|
throw new Exception(__CLASS__ . '::' . __METHOD__ . ' expects an array'); |
||||
|
} |
||||
|
|
||||
|
foreach ($this->fields as $field_name => $field) { |
||||
|
if (isset($data[$field_name])) { |
||||
|
$this->valid &= $field->isValid($data[$field_name], $data); |
||||
|
} else { |
||||
|
$this->valid &= $field->isValid(null, $data); |
||||
|
} |
||||
|
} |
||||
|
if (!$this->valid) { |
||||
|
$this->fillHelperData(); |
||||
|
} |
||||
|
return $this->valid; |
||||
|
} |
||||
|
|
||||
|
public function getMessages() |
||||
|
{ |
||||
|
$messages = array(); |
||||
|
foreach ($this->fields as $name => $field) { |
||||
|
if ($mess = $field->getMessage()) { |
||||
|
$messages[$name] = $mess; |
||||
|
} |
||||
|
} |
||||
|
return $messages; |
||||
|
} |
||||
|
|
||||
|
public function getValues() |
||||
|
{ |
||||
|
$values = array(); |
||||
|
foreach ($this->fields as $key => $field) { |
||||
|
if (!$field->isIgnored()) { |
||||
|
$values[$key] = $field->getValue(); |
||||
|
} |
||||
|
} |
||||
|
return $values; |
||||
|
} |
||||
|
|
||||
|
public function getSourceValues() |
||||
|
{ |
||||
|
$values = array(); |
||||
|
foreach ($this->fields as $key => $field) { |
||||
|
$values[$key] = $field->getSourceValue(); |
||||
|
} |
||||
|
return $values; |
||||
|
} |
||||
|
|
||||
|
public function getMessageType() |
||||
|
{ |
||||
|
return ($this->valid) ? self::SUCCESS : self::ERROR; |
||||
|
} |
||||
|
|
||||
|
public function getMessage() |
||||
|
{ |
||||
|
return $this->messages[$this->getMessageType()]; |
||||
|
} |
||||
|
|
||||
|
public function setSuccessMessage($message) |
||||
|
{ |
||||
|
$this->messages[self::SUCCESS] = (string) $message; |
||||
|
return $this; |
||||
|
} |
||||
|
|
||||
|
public function setErrorMessage($message) |
||||
|
{ |
||||
|
$this->messages[self::ERROR] = (string) $message; |
||||
|
return $this; |
||||
|
} |
||||
|
|
||||
|
protected function fillHelperData() |
||||
|
{ |
||||
|
$data['messages'] = $this->getMessages(); |
||||
|
$data['values'] = $this->getSourceValues(); |
||||
|
Session::set(get_class($this), $data); |
||||
|
} |
||||
|
|
||||
|
abstract protected function init(); |
||||
|
} |
@ -0,0 +1,173 @@ |
|||||
|
<?php |
||||
|
/** |
||||
|
* @copyright NetMonsters <team@netmonsters.ru> |
||||
|
* @link http://netmonsters.ru |
||||
|
* @package Majestic |
||||
|
* @subpackage form |
||||
|
* @since 2010-04-25 |
||||
|
* @version SVN: $Id$ |
||||
|
* @filesource $URL$ |
||||
|
*/ |
||||
|
|
||||
|
class FormField |
||||
|
{ |
||||
|
|
||||
|
protected $validators = array(); |
||||
|
protected $filters = array(); |
||||
|
|
||||
|
/** |
||||
|
* Used instead message of validator if defined. |
||||
|
* |
||||
|
* @var string |
||||
|
*/ |
||||
|
protected $default_message = false; |
||||
|
protected $message = false; |
||||
|
protected $value; |
||||
|
|
||||
|
/* Flags */ |
||||
|
protected $required = true; |
||||
|
protected $ignored = false; |
||||
|
|
||||
|
|
||||
|
public function __construct($default_message = false) |
||||
|
{ |
||||
|
$this->default_message = $default_message; |
||||
|
} |
||||
|
|
||||
|
public function setRequired($flag) |
||||
|
{ |
||||
|
$this->required = (bool) $flag; |
||||
|
return $this; |
||||
|
} |
||||
|
|
||||
|
public function isRequired() |
||||
|
{ |
||||
|
return $this->required; |
||||
|
} |
||||
|
|
||||
|
public function setIgnored($flag) |
||||
|
{ |
||||
|
$this->ignored = (bool) $flag; |
||||
|
return $this; |
||||
|
} |
||||
|
|
||||
|
public function isIgnored() |
||||
|
{ |
||||
|
return $this->ignored; |
||||
|
} |
||||
|
|
||||
|
public function addValidators($validators) |
||||
|
{ |
||||
|
foreach ($validators as $validator) { |
||||
|
$this->addValidator($validator); |
||||
|
} |
||||
|
return $this; |
||||
|
} |
||||
|
|
||||
|
public function addValidator($validator) |
||||
|
{ |
||||
|
if ($validator instanceof iValidator) { |
||||
|
$name = get_class($validator); |
||||
|
} elseif (is_string($validator)) { |
||||
|
$name = $validator . 'Validator'; |
||||
|
$validator = new $name(); |
||||
|
} else { |
||||
|
throw new Exception('Invalid validator provided to addValidator; must be string or iValidator'); |
||||
|
} |
||||
|
$this->validators[$name] = $validator; |
||||
|
return $this; |
||||
|
} |
||||
|
|
||||
|
public function addFilters($filters) |
||||
|
{ |
||||
|
foreach ($filters as $filter) { |
||||
|
$this->addFilter($filter); |
||||
|
} |
||||
|
return $this; |
||||
|
} |
||||
|
|
||||
|
public function addFilter($filter) |
||||
|
{ |
||||
|
if ($filter instanceof iFilter) { |
||||
|
$name = get_class($filter); |
||||
|
} elseif (is_string($filter)) { |
||||
|
$name = $filter . 'Filter'; |
||||
|
$filter = new $name(); |
||||
|
} else { |
||||
|
throw new Exception('Invalid filter provided to addFilter; must be string or iFilter'); |
||||
|
} |
||||
|
$this->filters[$name] = $filter; |
||||
|
return $this; |
||||
|
} |
||||
|
|
||||
|
public function getValue() |
||||
|
{ |
||||
|
$value = $this->value; |
||||
|
if (is_array($value)) { |
||||
|
array_walk_recursive($value, array($this, 'filterValue')); |
||||
|
} else { |
||||
|
$this->filterValue($value, $value); |
||||
|
} |
||||
|
return $value; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* $value & $key for array_walk_recursive |
||||
|
* |
||||
|
* @param mixed $value |
||||
|
* @param mixed $key |
||||
|
*/ |
||||
|
protected function filterValue(&$value, &$key) |
||||
|
{ |
||||
|
foreach ($this->filters as $filter) { |
||||
|
$value = $filter->filter($value); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public function getSourceValue() |
||||
|
{ |
||||
|
return $this->value; |
||||
|
} |
||||
|
|
||||
|
public function isValid($value, $context = null) |
||||
|
{ |
||||
|
$this->value = $value; |
||||
|
// filtered value here
|
||||
|
$value = $this->getValue(); |
||||
|
|
||||
|
$valid = true; |
||||
|
|
||||
|
if ((($value === '') || ($value === null)) && !$this->isRequired()) { |
||||
|
return $valid; |
||||
|
} |
||||
|
|
||||
|
foreach ($this->validators as $validator) { |
||||
|
if (is_array($value)) { |
||||
|
foreach ($value as $val) { |
||||
|
if (!$validator->isValid($val, $context)) { |
||||
|
$valid = false; |
||||
|
if (!$this->default_message) { |
||||
|
throw new Exception('Define default message for array fields'); |
||||
|
} |
||||
|
$this->message = $this->default_message; |
||||
|
} |
||||
|
} |
||||
|
if ($valid) { |
||||
|
continue; |
||||
|
} |
||||
|
} elseif ($validator->isValid($value, $context)) { |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
$valid = false; |
||||
|
$this->message = ($this->default_message) ? $this->default_message : $validator->getMessage(); |
||||
|
break; |
||||
|
} |
||||
|
return $valid; |
||||
|
} |
||||
|
|
||||
|
public function getMessage() |
||||
|
{ |
||||
|
return $this->message; |
||||
|
} |
||||
|
} |
@ -0,0 +1,44 @@ |
|||||
|
<?php |
||||
|
/** |
||||
|
* @copyright NetMonsters <team@netmonsters.ru> |
||||
|
* @link http://netmonsters.ru |
||||
|
* @package Majestic |
||||
|
* @subpackage Form |
||||
|
* @since 2010-04-25 |
||||
|
* @version SVN: $Id$ |
||||
|
* @filesource $URL$ |
||||
|
*/ |
||||
|
|
||||
|
class FormViewHelper extends ViewHelper |
||||
|
{ |
||||
|
|
||||
|
protected $data = null; |
||||
|
|
||||
|
public function form($form = null) |
||||
|
{ |
||||
|
if ($this->data === null) { |
||||
|
if ($form == null) { |
||||
|
throw new Exception('Form name required for helper init'); |
||||
|
} |
||||
|
$this->data = Session::get($form, array()); |
||||
|
Session::del($form); |
||||
|
} |
||||
|
return $this; |
||||
|
} |
||||
|
|
||||
|
public function value($field) |
||||
|
{ |
||||
|
if (isset($this->data['values'][$field])) { |
||||
|
return $this->view->escape($this->data['values'][$field]); |
||||
|
} |
||||
|
return ''; |
||||
|
} |
||||
|
|
||||
|
public function message($field) |
||||
|
{ |
||||
|
if (isset($this->data['messages'][$field])) { |
||||
|
return '<span class="error">' . $this->view->escape($this->data['messages'][$field]) . '</span>'; |
||||
|
} |
||||
|
return ''; |
||||
|
} |
||||
|
} |
@ -0,0 +1,17 @@ |
|||||
|
<?php |
||||
|
/** |
||||
|
* @copyright NetMonsters <team@netmonsters.ru> |
||||
|
* @link http://netmonsters.ru |
||||
|
* @package Majestic |
||||
|
* @subpackage validator |
||||
|
* @since 2010-04-26 |
||||
|
* @version SVN: $Id$ |
||||
|
* @filesource $URL$ |
||||
|
*/ |
||||
|
|
||||
|
class EmailValidator extends RegexValidator |
||||
|
{ |
||||
|
protected $regex = '/^([a-z0-9._-]{2,23})\@([a-z0-9-]{2,22}\.)+\w{2,5}$/i'; |
||||
|
|
||||
|
public function __construct(){} |
||||
|
} |
@ -0,0 +1,32 @@ |
|||||
|
<?php |
||||
|
/** |
||||
|
* @copyright NetMonsters <team@netmonsters.ru> |
||||
|
* @link http://netmonsters.ru |
||||
|
* @package Majestic |
||||
|
* @subpackage validator |
||||
|
* @since 2010-04-26 |
||||
|
* @version SVN: $Id$ |
||||
|
* @filesource $URL$ |
||||
|
*/ |
||||
|
|
||||
|
class NotEmptyValidator extends Validator |
||||
|
{ |
||||
|
|
||||
|
const IS_EMPTY = 'is_empty'; |
||||
|
|
||||
|
protected $templates = array(self::IS_EMPTY => 'Value is required and can\'t be empty'); |
||||
|
|
||||
|
public function isValid($value, $context = null) |
||||
|
{ |
||||
|
$this->setValue($value); |
||||
|
|
||||
|
if (is_string($value) && $value === '') { |
||||
|
$this->error(); |
||||
|
return false; |
||||
|
} elseif (!is_string($value) && empty($value)) { |
||||
|
$this->error(); |
||||
|
return false; |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
} |
@ -0,0 +1,41 @@ |
|||||
|
<?php |
||||
|
/** |
||||
|
* @copyright NetMonsters <team@netmonsters.ru> |
||||
|
* @link http://netmonsters.ru |
||||
|
* @package Majestic |
||||
|
* @subpackage validator |
||||
|
* @since 2010-04-26 |
||||
|
* @version SVN: $Id$ |
||||
|
* @filesource $URL$ |
||||
|
*/ |
||||
|
|
||||
|
class RegexValidator extends Validator |
||||
|
{ |
||||
|
|
||||
|
const NOT_MATCH = 'regex_not_match'; |
||||
|
|
||||
|
protected $vars = array('regex'); |
||||
|
protected $templates = array(self::NOT_MATCH => '"%value%" does not match against regex "%regex%"'); |
||||
|
|
||||
|
protected $regex; |
||||
|
|
||||
|
public function __construct($regex) |
||||
|
{ |
||||
|
$this->regex = $regex; |
||||
|
} |
||||
|
|
||||
|
public function isValid($value, $context = null) |
||||
|
{ |
||||
|
$this->setValue($value); |
||||
|
|
||||
|
$status = preg_match($this->regex, $value); |
||||
|
if ($status === false) { |
||||
|
throw new Exception('Internal error matching regex "' . $this->regex . ' against value "' . $value . '"'); |
||||
|
} |
||||
|
if (!$status) { |
||||
|
$this->error(); |
||||
|
return false; |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
} |
@ -0,0 +1,65 @@ |
|||||
|
<?php |
||||
|
/** |
||||
|
* @copyright NetMonsters <team@netmonsters.ru> |
||||
|
* @link http://netmonsters.ru |
||||
|
* @package Majestic |
||||
|
* @subpackage validator |
||||
|
* @since 2010-04-24 |
||||
|
* @version SVN: $Id$ |
||||
|
* @filesource $URL$ |
||||
|
*/ |
||||
|
|
||||
|
abstract class Validator implements iValidator |
||||
|
{ |
||||
|
|
||||
|
protected $value; |
||||
|
protected $message; |
||||
|
protected $vars = array(); |
||||
|
protected $templates = array(); |
||||
|
|
||||
|
|
||||
|
public function getMessage() |
||||
|
{ |
||||
|
return $this->message; |
||||
|
} |
||||
|
|
||||
|
protected function setValue($value) |
||||
|
{ |
||||
|
$this->value = (string) $value; |
||||
|
$this->message = null; |
||||
|
} |
||||
|
|
||||
|
public function setMessage($key, $message) |
||||
|
{ |
||||
|
$this->templates[$key] = $message; |
||||
|
} |
||||
|
|
||||
|
protected function error($template = null, $value = null) |
||||
|
{ |
||||
|
if ($template === null) { |
||||
|
$template = current(array_keys($this->templates)); |
||||
|
} |
||||
|
if ($value === null) { |
||||
|
$value = $this->value; |
||||
|
} |
||||
|
$this->message = $this->createMessage($template, $value); |
||||
|
} |
||||
|
|
||||
|
protected function createMessage($template, $value) |
||||
|
{ |
||||
|
if (!isset($this->templates[$template])) { |
||||
|
throw new Exception('Message template "' . $template . '" unknown.'); |
||||
|
} |
||||
|
|
||||
|
$message = $this->templates[$template]; |
||||
|
if (strpos($message, '%') !== false) { |
||||
|
$message = str_replace('%value%', (string) $value, $message); |
||||
|
foreach ($this->vars as $property) { |
||||
|
if (property_exists($this, $property)) { |
||||
|
$message = str_replace("%$property%", (string) $this->$property, $message); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return $message; |
||||
|
} |
||||
|
} |
@ -0,0 +1,16 @@ |
|||||
|
<?php |
||||
|
/** |
||||
|
* @copyright NetMonsters <team@netmonsters.ru> |
||||
|
* @link http://netmonsters.ru |
||||
|
* @package Majestic |
||||
|
* @subpackage validator |
||||
|
* @since 2010-04-25 |
||||
|
* @version SVN: $Id$ |
||||
|
* @filesource $URL$ |
||||
|
*/ |
||||
|
|
||||
|
interface iValidator |
||||
|
{ |
||||
|
public function isValid($value, $context = null); |
||||
|
public function getMessage(); |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue