CaptchaHelper.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. <?php
  2. App::uses('AppHelper', 'View/Helper');
  3. App::uses('CaptchaLib', 'Tools.Lib');
  4. if (!defined('BR')) {
  5. define('BR', '<br />');
  6. }
  7. /**
  8. * PHP5 / CakePHP2
  9. *
  10. * @author Mark Scherer
  11. * @link http://www.dereuromark.de
  12. * @package tools plugin
  13. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  14. */
  15. /**
  16. * works togehter with captcha behaviour/component
  17. * 2011-06-11 ms
  18. */
  19. class CaptchaHelper extends AppHelper {
  20. public $helpers = array('Form');
  21. protected $_defaults = array(
  22. 'difficulty' => 1, # initial diff. level (@see operator: + = 0, +- = 1, +-* = 2)
  23. 'raiseDifficulty' => 2, # number of failed trails, after the x. one the following one it will be more difficult
  24. );
  25. protected $numberConvert = null;
  26. protected $operatorConvert = null;
  27. public function __construct($View = null, $settings = array()) {
  28. parent::__construct($View, $settings);
  29. # First of all we are going to set up an array with the text equivalents of all the numbers we will be using.
  30. $this->numberConvert = array(0=>'zero', 1=>'one', 2=>'two', 3=>'three', 4=>'four', 5=>'five', 6=>'six', 7=>'seven', 8=>'eight', 9=>'nine', 10=>'ten');
  31. # Set up an array with the operators that we want to use. With difficulty=1 it is only subtraction and addition.
  32. $this->operatorConvert = array(0=>array('+',__('calcPlus')), 1=>array('-',__('calcMinus')), 2=>'*',__('calcTimes'));
  33. $this->settings = array_merge(CaptchaLib::$defaults, $this->_defaults);
  34. $settings = (array)Configure::read('Captcha');
  35. if (!empty($settings)) {
  36. $this->settings = array_merge($this->settings, $settings);
  37. }
  38. }
  39. /**
  40. * //TODO: move to Lib
  41. * shows the statusText of Relations
  42. *
  43. * @param int $difficulty: not build in yet
  44. * @return array
  45. * 2008-12-12 ms
  46. */
  47. protected function _generate($difficulty = null) {
  48. # Choose the first number randomly between 6 and 10. This is to stop the answer being negative.
  49. $numberOne = mt_rand(6, 10);
  50. # Choose the second number randomly between 0 and 5.
  51. $numberTwo = mt_rand(0, 5);
  52. # Choose the operator randomly from the array.
  53. $captchaOperatorSelection = $this->operatorConvert[mt_rand(0, 1)];
  54. $captchaOperator = $captchaOperatorSelection[mt_rand(0, 1)];
  55. # Get the equation in textual form to show to the user.
  56. $code = (mt_rand(0, 1) == 1 ? __($this->numberConvert[$numberOne]) : $numberOne) . ' ' . $captchaOperator . ' ' . (mt_rand(0, 1) == 1 ? __($this->numberConvert[$numberTwo]) : $numberTwo);
  57. # Evaluate the equation and get the result.
  58. eval('$result = ' . $numberOne . ' ' . $captchaOperatorSelection[0] . ' ' . $numberTwo . ';');
  59. return array('code'=>$code, 'result'=>$result);
  60. }
  61. /**
  62. * main captcha output (usually called from $this->input() automatically)
  63. * - hash-based
  64. * - session-based (not impl.)
  65. * - db-based (not impl.)
  66. *
  67. * @return string HTML
  68. * 2009-12-18 ms
  69. */
  70. public function captcha($modelName = null) {
  71. $captchaCode = $this->_generate();
  72. # Session-Way (only one form at a time) - must be a component then
  73. //$this->Session->write('Captcha.result', $result);
  74. # DB-Way (several forms possible, high security via IP-Based max limits)
  75. // the following should be done in a component and passed to the view/helper
  76. // $Captcha = ClassRegistry::init('Captcha');
  77. // $this->Captcha->new(); $this->Captcha->update(); etc
  78. # Timestamp-SessionID-Hash-Way (several forms possible, not as secure)
  79. $hash = $this->_buildHash($captchaCode);
  80. $return = '';
  81. if (in_array($this->settings['type'], array('active', 'both'))) {
  82. # //todo obscure html here?
  83. $fill = ''; //'<span></span>';
  84. $return .= '<span id="captchaCode">'.$fill.''.$captchaCode['code'].'</span>';
  85. }
  86. $field = $this->_fieldName($modelName);
  87. # add passive part on active forms as well
  88. $return .= '<div style="display:none">'.
  89. $this->Form->input($field.'_hash', array('value'=>$hash)).
  90. $this->Form->input($field.'_time', array('value'=>time())).
  91. $this->Form->input((!empty($modelName)?$modelName.'.':'').$this->settings['dummyField'], array('value'=>'')).
  92. '</div>';
  93. return $return;
  94. }
  95. /**
  96. * active math captcha
  97. * either combined with between=true (all in this one funtion)
  98. * or seperated by =false (needs input(false) and captcha() calls then)
  99. *
  100. * @param bool between: [default: true]
  101. * @return string HTML
  102. * 2010-01-08 ms
  103. */
  104. public function input($modelName = null, $options = array()) {
  105. $defaultOptions = array(
  106. 'type' => 'text',
  107. 'class' => 'captcha',
  108. 'value' => '',
  109. 'maxlength' => 3,
  110. 'label' => __('Captcha') . BR . __('captchaExplained'),
  111. 'combined' => true,
  112. 'autocomplete' => 'off',
  113. 'after' => __('captchaTip'),
  114. );
  115. $options = array_merge($defaultOptions, $options);
  116. if ($options['combined'] === true) {
  117. $options['between'] = $this->captcha($modelName);
  118. if (in_array($this->settings['type'], array('active', 'both'))) {
  119. $options['between'] .= ' = ';
  120. }
  121. }
  122. unset($options['combined']);
  123. $field = $this->_fieldName($modelName);
  124. return $this->Form->input($field.'', $options); // TODO: rename: _code
  125. }
  126. /**
  127. * passive captcha
  128. *
  129. * @return string HTML
  130. * 2010-01-08 ms
  131. */
  132. public function passive($modelName = null, $options = array()) {
  133. $tmp = $this->settings['type'];
  134. $this->settings['type'] = 'passive';
  135. $res = $this->captcha($modelName);
  136. $this->settings['type'] = $tmp;
  137. return $res;
  138. }
  139. /**
  140. * active captcha
  141. * (+ passive captcha right now)
  142. *
  143. * @return string Form input
  144. * 2010-01-08 ms
  145. */
  146. public function active($modelName = null, $options = array()) {
  147. return $this->input($modelName, $options);
  148. }
  149. /**
  150. * @param array $captchaCode
  151. * @return string Hash
  152. */
  153. protected function _buildHash($data) {
  154. return CaptchaLib::buildHash($data, $this->settings, true);
  155. }
  156. /**
  157. * @return string Field name
  158. */
  159. protected function _fieldName($modelName = null) {
  160. $fieldName = 'captcha';
  161. if (isSet($modelName)) {
  162. $fieldName = $modelName.'.'.$fieldName;
  163. }
  164. return $fieldName;
  165. }
  166. }