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