Equation.php 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. <?php
  2. /**
  3. * Equation driver for Text_CAPTCHA.
  4. * Returns simple equations as string, e.g. "9 - 2"
  5. *
  6. * PHP version 5
  7. *
  8. * @category Text
  9. * @package Text_CAPTCHA
  10. * @author Christian Weiske <cweiske@php.net>
  11. * @author Christian Wenz <wenz@php.net>
  12. * @author Michael Cramer <michael@bigmichi1.de>
  13. * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  14. * @link http://pear.php.net/package/Text_CAPTCHA
  15. */
  16. /**
  17. * Equation driver for Text_CAPTCHA.
  18. * Returns simple equations as string, e.g. "9 - 2"
  19. *
  20. * @category Text
  21. * @package Text_CAPTCHA
  22. * @author Christian Weiske <cweiske@php.net>
  23. * @author Christian Wenz <wenz@php.net>
  24. * @author Michael Cramer <michael@bigmichi1.de>
  25. * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  26. * @link http://pear.php.net/package/Text_CAPTCHA
  27. */
  28. class Text_CAPTCHA_Driver_Equation extends Text_CAPTCHA_Driver_Base
  29. {
  30. /**
  31. * Operators that may be used in the equation. Two numbers have to be filled in,
  32. * and %s is needed since number2text conversion may be applied and strings
  33. * filled in.
  34. *
  35. * @var array
  36. */
  37. private $_operators = array(
  38. '%s * %s',
  39. '%s + %s',
  40. '%s - %s',
  41. 'min(%s, %s)',
  42. 'max(%s, %s)'
  43. );
  44. /**
  45. * Minimal number to use in an equation.
  46. *
  47. * @var int
  48. */
  49. private $_min = 1;
  50. /**
  51. * Maximum number to use in an equation.
  52. *
  53. * @var int
  54. */
  55. private $_max = 10;
  56. /**
  57. * Whether numbers shall be converted to text.
  58. *
  59. * @var bool
  60. */
  61. private $_numbersToText = false;
  62. /**
  63. * This variable holds the locale for Numbers_Words.
  64. *
  65. * @var string
  66. */
  67. private $_locale = '';
  68. /**
  69. * Complexity of the generated equations.<br>
  70. * 1 - simple ones such as "1 + 10"<br>
  71. * 2 - harder ones such as "(3-2)*(min(5,6))"
  72. *
  73. * @var int
  74. */
  75. private $_severity = 1;
  76. /**
  77. * Initialize the driver.
  78. *
  79. * @param array $options CAPTCHA options with these keys:<br>
  80. * min minimum numeric value
  81. * max maximum numeric value
  82. * numbersToText boolean for number to text conversion
  83. * locale locale for number to text conversion
  84. * severity number for complexity
  85. *
  86. * @return void
  87. * @throws Text_CAPTCHA_Exception when numbersToText is true, but Number_Words
  88. * package is not available
  89. */
  90. public function initDriver($options = array())
  91. {
  92. if (isset($options['min'])) {
  93. $this->_min = (int)$options['min'];
  94. } else {
  95. $this->_min = 1;
  96. }
  97. if (isset($options['max'])) {
  98. $this->_max = (int)$options['max'];
  99. } else {
  100. $this->_max = 10;
  101. }
  102. if (isset($options['numbersToText'])) {
  103. $this->_numbersToText = (bool)$options['numbersToText'];
  104. } else {
  105. $this->_numbersToText = false;
  106. }
  107. if (isset($options['locale'])) {
  108. $this->_locale = (string)$options['locale'];
  109. } else {
  110. $this->_locale = '';
  111. }
  112. if (isset($options['severity'])) {
  113. $this->_severity = (int)$options['severity'];
  114. } else {
  115. $this->_severity = 1;
  116. }
  117. if ($this->_numbersToText) {
  118. include_once 'Numbers/Words.php';
  119. if (!class_exists('Numbers_Words')) {
  120. throw new Text_CAPTCHA_Exception('Number_Words package required');
  121. }
  122. }
  123. }
  124. /**
  125. * Create random CAPTCHA equation.
  126. * This method creates a random equation.
  127. *
  128. * @return void
  129. * @throws Text_CAPTCHA_Exception when invalid severity is specified
  130. */
  131. public function createCAPTCHA()
  132. {
  133. switch ($this->_severity) {
  134. case 1:
  135. list($equation, $phrase) = $this->_createSimpleEquation();
  136. break;
  137. case 2:
  138. list($eq1, $sol1) = $this->_createSimpleEquation();
  139. list($eq2, $sol2) = $this->_createSimpleEquation();
  140. $op3 = $this->_operators[mt_rand(0, count($this->_operators) - 1)];
  141. list(, $phrase) = $this->_solveSimpleEquation($sol1, $sol2, $op3);
  142. $equation = sprintf($op3, '(' . $eq1 . ')', '(' . $eq2 . ')');
  143. break;
  144. default:
  145. throw new Text_CAPTCHA_Exception(
  146. 'Equation complexity of ' . $this->_severity . ' not supported'
  147. );
  148. }
  149. $this->setCaptcha($equation);
  150. $this->setPhrase($phrase);
  151. }
  152. /**
  153. * Creates a simple equation of type (number operator number).
  154. *
  155. * @return array Array with equation and solution
  156. */
  157. private function _createSimpleEquation()
  158. {
  159. $one = mt_rand($this->_min, $this->_max);
  160. $two = mt_rand($this->_min, $this->_max);
  161. $operator = $this->_operators[mt_rand(0, count($this->_operators) - 1)];
  162. return $this->_solveSimpleEquation($one, $two, $operator);
  163. }
  164. /**
  165. * Solves a simple equation with two given numbers and one operator as defined
  166. * in $this->_operators.
  167. * Also converts the numbers to words if required.
  168. *
  169. * @param int $one First number
  170. * @param int $two Second number
  171. * @param string $operator Operator used with those two numbers
  172. *
  173. * @return array Array with equation and solution
  174. */
  175. private function _solveSimpleEquation($one, $two, $operator)
  176. {
  177. $equation = sprintf($operator, $one, $two);
  178. $function = create_function('', 'return ' . $equation . ';');
  179. if ($this->_numbersToText) {
  180. $numberWords = new Numbers_Words();
  181. $equation = sprintf(
  182. $operator,
  183. $numberWords->toWords($one, $this->_locale),
  184. $numberWords->toWords($two, $this->_locale)
  185. );
  186. }
  187. return array($equation, $function());
  188. }
  189. /**
  190. * Creates the captcha. This method is a placeholder, since the equation is
  191. * created in createCAPTCHA()
  192. *
  193. * @return void
  194. * @see createCAPTCHA()
  195. */
  196. public function createPhrase()
  197. {
  198. $this->setPhrase(null);
  199. }
  200. }