2
0

Captcha.php 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Form
  17. * @subpackage Element
  18. * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. */
  21. /** Zend_Form_Element_Xhtml */
  22. require_once 'Zend/Form/Element/Xhtml.php';
  23. /** Zend_Captcha_Adapter */
  24. require_once 'Zend/Captcha/Adapter.php';
  25. /**
  26. * Generic captcha element
  27. *
  28. * This element allows to insert CAPTCHA into the form in order
  29. * to validate that human is submitting the form. The actual
  30. * logic is contained in the captcha adapter.
  31. *
  32. * @see http://en.wikipedia.org/wiki/Captcha
  33. *
  34. * @category Zend
  35. * @package Zend_Form
  36. * @subpackage Element
  37. * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
  38. * @license http://framework.zend.com/license/new-bsd New BSD License
  39. */
  40. class Zend_Form_Element_Captcha extends Zend_Form_Element_Xhtml
  41. {
  42. /**
  43. * @const string Captch plugin type constant
  44. */
  45. const CAPTCHA = 'CAPTCHA';
  46. /**
  47. * Captcha adapter
  48. *
  49. * @var Zend_Captcha_Adapter
  50. */
  51. protected $_captcha;
  52. /**
  53. * Get captcha adapter
  54. *
  55. * @return Zend_Captcha_Adapter
  56. */
  57. public function getCaptcha()
  58. {
  59. return $this->_captcha;
  60. }
  61. /**
  62. * Set captcha adapter
  63. *
  64. * @param string|array|Zend_Captcha_Adapter $captcha
  65. * @param array $options
  66. */
  67. public function setCaptcha($captcha, $options = array())
  68. {
  69. if ($captcha instanceof Zend_Captcha_Adapter) {
  70. $instance = $captcha;
  71. } else {
  72. if (is_array($captcha)) {
  73. if (array_key_exists('captcha', $captcha)) {
  74. $name = $captcha['captcha'];
  75. unset($captcha['captcha']);
  76. } else {
  77. $name = array_shift($captcha);
  78. }
  79. $options = array_merge($options, $captcha);
  80. } else {
  81. $name = $captcha;
  82. }
  83. $name = $this->getPluginLoader(self::CAPTCHA)->load($name);
  84. if (empty($options)) {
  85. $instance = new $name;
  86. } else {
  87. $r = new ReflectionClass($name);
  88. if ($r->hasMethod('__construct')) {
  89. $instance = $r->newInstanceArgs(array($options));
  90. } else {
  91. $instance = $r->newInstance();
  92. }
  93. }
  94. }
  95. $this->_captcha = $instance;
  96. $this->_captcha->setName($this->getName());
  97. return $this;
  98. }
  99. /**
  100. * Constructor
  101. *
  102. * $spec may be:
  103. * - string: name of element
  104. * - array: options with which to configure element
  105. * - Zend_Config: Zend_Config with options for configuring element
  106. *
  107. * @param string|array|Zend_Config $spec
  108. * @return void
  109. */
  110. public function __construct($spec, $options = null)
  111. {
  112. parent::__construct($spec, $options);
  113. $this->setAllowEmpty(true)
  114. ->setRequired(true)
  115. ->setAutoInsertNotEmptyValidator(false)
  116. ->addValidator($this->getCaptcha(), true);
  117. }
  118. /**
  119. * Return all attributes
  120. *
  121. * @return array
  122. */
  123. public function getAttribs()
  124. {
  125. $attribs = get_object_vars($this);
  126. unset($attribs['helper']);
  127. foreach ($attribs as $key => $value) {
  128. if ('_' == substr($key, 0, 1)) {
  129. unset($attribs[$key]);
  130. }
  131. }
  132. return $attribs;
  133. }
  134. /**
  135. * Set options
  136. *
  137. * Overrides to allow passing captcha options
  138. *
  139. * @param array $options
  140. * @return Zend_Form_Element_Captcha
  141. */
  142. public function setOptions(array $options)
  143. {
  144. if (array_key_exists('captcha', $options)) {
  145. if (array_key_exists('captchaOptions', $options)) {
  146. $this->setCaptcha($options['captcha'], $options['captchaOptions']);
  147. unset($options['captchaOptions']);
  148. } else {
  149. $this->setCaptcha($options['captcha']);
  150. }
  151. unset($options['captcha']);
  152. }
  153. return parent::setOptions($options);
  154. }
  155. /**
  156. * Render form element
  157. *
  158. * @param Zend_View_Interface $view
  159. * @return string
  160. */
  161. public function render(Zend_View_Interface $view = null)
  162. {
  163. $captcha = $this->getCaptcha();
  164. $captcha->setName($this->getFullyQualifiedName());
  165. $decorators = $this->getDecorators();
  166. $decorator = $captcha->getDecorator();
  167. if (!empty($decorator)) {
  168. array_unshift($decorators, $decorator);
  169. }
  170. $decorator = array('Captcha', array('captcha' => $captcha));
  171. array_unshift($decorators, $decorator);
  172. $this->setDecorators($decorators);
  173. $this->setValue($this->getCaptcha()->generate());
  174. return parent::render($view);
  175. }
  176. /**
  177. * Retrieve plugin loader for validator or filter chain
  178. *
  179. * Support for plugin loader for Captcha adapters
  180. *
  181. * @param string $type
  182. * @return Zend_Loader_PluginLoader
  183. * @throws Zend_Loader_Exception on invalid type.
  184. */
  185. public function getPluginLoader($type)
  186. {
  187. $type = strtoupper($type);
  188. if ($type == self::CAPTCHA) {
  189. if (!isset($this->_loaders[$type])) {
  190. require_once 'Zend/Loader/PluginLoader.php';
  191. $this->_loaders[$type] = new Zend_Loader_PluginLoader(
  192. array('Zend_Captcha' => 'Zend/Captcha/')
  193. );
  194. }
  195. return $this->_loaders[$type];
  196. } else {
  197. return parent::getPluginLoader($type);
  198. }
  199. }
  200. /**
  201. * Add prefix path for plugin loader for captcha adapters
  202. *
  203. * This method handles the captcha type, the rest is handled by
  204. * the parent
  205. *
  206. * @param string $path
  207. * @return Zend_Form_Element
  208. * @see Zend_Form_Element::addPrefixPath
  209. */
  210. public function addPrefixPath($prefix, $path, $type = null)
  211. {
  212. $type = strtoupper($type);
  213. switch ($type) {
  214. case null:
  215. $loader = $this->getPluginLoader(self::CAPTCHA);
  216. $cPrefix = rtrim($prefix, '_') . '_Captcha';
  217. $cPath = rtrim($path, '/\\') . '/Captcha';
  218. $loader->addPrefixPath($cPrefix, $cPath);
  219. return parent::addPrefixPath($prefix, $path);
  220. case self::CAPTCHA:
  221. $loader = $this->getPluginLoader($type);
  222. $loader->addPrefixPath($prefix, $path);
  223. return $this;
  224. default:
  225. return parent::addPrefixPath($prefix, $path, $type);
  226. }
  227. }
  228. /**
  229. * Load default decorators
  230. *
  231. * @return void
  232. */
  233. public function loadDefaultDecorators()
  234. {
  235. if ($this->loadDefaultDecoratorsIsDisabled()) {
  236. return;
  237. }
  238. $decorators = $this->getDecorators();
  239. if (empty($decorators)) {
  240. $this->addDecorator('Errors')
  241. ->addDecorator('Description', array('tag' => 'p', 'class' => 'description'))
  242. ->addDecorator('HtmlTag', array('tag' => 'dd'))
  243. ->addDecorator('Label', array('tag' => 'dt'));
  244. }
  245. }
  246. /**
  247. * Is the captcha valid?
  248. *
  249. * @param mixed $value
  250. * @param mixed $context
  251. * @return boolean
  252. */
  253. public function isValid($value, $context = null)
  254. {
  255. $this->getCaptcha()->setName($this->getName());
  256. $belongsTo = $this->getBelongsTo();
  257. if (empty($belongsTo) || !is_array($context)) {
  258. return parent::isValid($value, $context);
  259. }
  260. $name = $this->getFullyQualifiedName();
  261. $root = substr($name, 0, strpos($name, '['));
  262. $segments = substr($name, strpos($name, '['));
  263. $segments = ltrim($segments, '[');
  264. $segments = rtrim($segments, ']');
  265. $segments = explode('][', $segments);
  266. array_unshift($segments, $root);
  267. array_pop($segments);
  268. $newContext = $context;
  269. foreach ($segments as $segment) {
  270. if (array_key_exists($segment, $newContext)) {
  271. $newContext = $newContext[$segment];
  272. }
  273. }
  274. return parent::isValid($value, $newContext);
  275. }
  276. }