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