Browse Source

Validator, captcha, form, #16

git-svn-id: svn+ssh://code.netmonsters.ru/svn/majestic/branches/evo@141 4cb57b5f-5bbd-dd11-951b-001d605cbbc5
master
pzinovkin 15 years ago
parent
commit
c214b75d60
  1. 79
      captcha/Captcha.php
  2. 21
      captcha/CaptchaImageAction.php
  3. 32
      captcha/CaptchaValidator.php
  4. BIN
      captcha/poh.ttf
  5. 3
      exception/ErrorHandler.php
  6. 119
      form/Form.php
  7. 173
      form/FormField.php
  8. 44
      form/FormViewHelper.php
  9. 17
      validator/EmailValidator.php
  10. 32
      validator/NotEmptyValidator.php
  11. 41
      validator/RegexValidator.php
  12. 65
      validator/Validator.php
  13. 16
      validator/iValidator.php
  14. 2
      view/PHPView.php
  15. 2
      view/helpers/BreadcrumbViewHelper.php
  16. 2
      view/helpers/GetViewHelper.php
  17. 2
      view/helpers/HeadViewHelper.php
  18. 17
      view/helpers/MsgViewHelper.php
  19. 2
      view/helpers/TitleViewHelper.php

79
captcha/Captcha.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;
}
}

21
captcha/CaptchaImageAction.php

@ -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();
}
}

32
captcha/CaptchaValidator.php

@ -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;
}
}

BIN
captcha/poh.ttf

3
exception/ErrorHandler.php

@ -83,6 +83,7 @@ class ErrorHandler
$get = self::wrapArray(Env::Get(), 'GET');
$post = self::wrapArray(Env::Post(), 'POST');
$session = self::wrapArray(Session::get(), 'SESSION');
$files = self::wrapArray(Env::Files(), 'FILES');
$cookies = self::wrapArray(Env::Cookie(), 'COOKIE');
$server = self::wrapArray(Env::Server(), 'SERVER');
@ -174,6 +175,8 @@ class ErrorHandler
{$get}
<h3 id="post-info">POST</h3>
{$post}
<h3 id="session-info">SESSION</h3>
{$session}
<h3 id="files-info">FILES</h3>
{$files}
<h3 id="cookie-info">COOKIES</h3>

119
form/Form.php

@ -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();
}

173
form/FormField.php

@ -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;
}
}

44
form/FormViewHelper.php

@ -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 '';
}
}

17
validator/EmailValidator.php

@ -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(){}
}

32
validator/NotEmptyValidator.php

@ -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;
}
}

41
validator/RegexValidator.php

@ -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;
}
}

65
validator/Validator.php

@ -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;
}
}

16
validator/iValidator.php

@ -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();
}

2
view/PHPView.php

@ -119,7 +119,7 @@ class PHPView implements iView
protected function getHelper($name)
{
if (!isset($this->helpers[$name])) {
$class = 'ViewHelper' . ucfirst($name);
$class = ucfirst($name) . 'ViewHelper';
if (!class_exists($class)) {
throw new GeneralException('View helper "' . $class . '" not found.');
}

2
view/helpers/ViewHelperBreadcrumb.php → view/helpers/BreadcrumbViewHelper.php

@ -9,7 +9,7 @@
* @filesource $URL$
*/
class ViewHelperBreadcrumb extends ViewHelper
class BreadcrumbViewHelper extends ViewHelper
{
protected $separator = ' &gt; ';

2
view/helpers/ViewHelperGet.php → view/helpers/GetViewHelper.php

@ -9,7 +9,7 @@
* @filesource $URL$
*/
class ViewHelperGet extends ViewHelper
class GetViewHelper extends ViewHelper
{
protected $get;

2
view/helpers/ViewHelperHead.php → view/helpers/HeadViewHelper.php

@ -9,7 +9,7 @@
* @filesource $URL$
*/
class ViewHelperHead extends ViewHelper
class HeadViewHelper extends ViewHelper
{
public function head($string = false)

17
view/helpers/ViewHelperMsg.php → view/helpers/MsgViewHelper.php

@ -9,24 +9,33 @@
* @filesource $URL$
*/
class ViewHelperMsg extends ViewHelper
class MsgViewHelper extends ViewHelper
{
const SUCCESS = 'success';
const ERROR = 'error';
protected $get;
public function msg()
public function msg($msg = null, $type = null)
{
if ($msg && $type) {
if (!in_array($type, array(self::SUCCESS, self::ERROR))) {
throw new Exception('Unknown message type: "' . $type . '"');
}
Session::set(__CLASS__, array('message' => $msg, 'type' => $type));
}
return $this;
}
public function success($msg)
{
Session::set(__CLASS__, array('message' => $msg, 'type' => 'success'));
Session::set(__CLASS__, array('message' => $msg, 'type' => self::SUCCESS));
}
public function error($msg)
{
Session::set(__CLASS__, array('message' => $msg, 'type' => 'error'));
Session::set(__CLASS__, array('message' => $msg, 'type' => self::ERROR));
}
public function __toString()

2
view/helpers/ViewHelperTitle.php → view/helpers/TitleViewHelper.php

@ -9,7 +9,7 @@
* @filesource $URL$
*/
class ViewHelperTitle extends ViewHelper
class TitleViewHelper extends ViewHelper
{
protected $separator = ' - ';
Loading…
Cancel
Save