File indexing completed on 2024-06-16 05:30:05

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_Form
0017  * @subpackage Element
0018  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0019  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0020  * @version    $Id$
0021  */
0022 
0023 /** @see Zend_Form_Element_Xhtml */
0024 // require_once 'Zend/Form/Element/Xhtml.php';
0025 
0026 /** @see Zend_Captcha_Adapter */
0027 // require_once 'Zend/Captcha/Adapter.php';
0028 
0029 /**
0030  * Generic captcha element
0031  *
0032  * This element allows to insert CAPTCHA into the form in order
0033  * to validate that human is submitting the form. The actual
0034  * logic is contained in the captcha adapter.
0035  *
0036  * @see http://en.wikipedia.org/wiki/Captcha
0037  *
0038  * @category   Zend
0039  * @package    Zend_Form
0040  * @subpackage Element
0041  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0042  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0043  */
0044 class Zend_Form_Element_Captcha extends Zend_Form_Element_Xhtml
0045 {
0046     /**
0047      * Captcha plugin type constant
0048      */
0049     const CAPTCHA = 'CAPTCHA';
0050 
0051     /**
0052      * Captcha adapter
0053      *
0054      * @var Zend_Captcha_Adapter
0055      */
0056     protected $_captcha;
0057 
0058     /**
0059      * Get captcha adapter
0060      *
0061      * @return Zend_Captcha_Adapter
0062      */
0063     public function getCaptcha()
0064     {
0065         return $this->_captcha;
0066     }
0067 
0068     /**
0069      * Set captcha adapter
0070      *
0071      * @param string|array|Zend_Captcha_Adapter $captcha
0072      * @param array $options
0073      */
0074     public function setCaptcha($captcha, $options = array())
0075     {
0076         if ($captcha instanceof Zend_Captcha_Adapter) {
0077             $instance = $captcha;
0078         } else {
0079             if (is_array($captcha)) {
0080                 if (array_key_exists('captcha', $captcha)) {
0081                     $name = $captcha['captcha'];
0082                     unset($captcha['captcha']);
0083                 } else {
0084                     $name = array_shift($captcha);
0085                 }
0086                 $options = array_merge($options, $captcha);
0087             } else {
0088                 $name = $captcha;
0089             }
0090 
0091             $name = $this->getPluginLoader(self::CAPTCHA)->load($name);
0092             if (empty($options)) {
0093                 $instance = new $name;
0094             } else {
0095                 $r = new ReflectionClass($name);
0096                 if ($r->hasMethod('__construct')) {
0097                     $instance = $r->newInstanceArgs(array($options));
0098                 } else {
0099                     $instance = $r->newInstance();
0100                 }
0101             }
0102         }
0103 
0104         $this->_captcha = $instance;
0105         $this->_captcha->setName($this->getName());
0106         return $this;
0107     }
0108 
0109     /**
0110      * Constructor
0111      *
0112      * $spec may be:
0113      * - string: name of element
0114      * - array: options with which to configure element
0115      * - Zend_Config: Zend_Config with options for configuring element
0116      *
0117      * @param  string|array|Zend_Config $spec
0118      * @return void
0119      */
0120     public function __construct($spec, $options = null)
0121     {
0122         parent::__construct($spec, $options);
0123         $this->setAllowEmpty(true)
0124              ->setRequired(true)
0125              ->setAutoInsertNotEmptyValidator(false)
0126              ->addValidator($this->getCaptcha(), true);
0127     }
0128 
0129     /**
0130      * Set options
0131      *
0132      * Overrides to allow passing captcha options
0133      *
0134      * @param  array $options
0135      * @return Zend_Form_Element_Captcha
0136      */
0137     public function setOptions(array $options)
0138     {
0139         $captcha        = null;
0140         $captchaOptions = array();
0141 
0142         if (array_key_exists('captcha', $options)) {
0143             $captcha = $options['captcha'];
0144             if (array_key_exists('captchaOptions', $options)) {
0145                 $captchaOptions = $options['captchaOptions'];
0146                 unset($options['captchaOptions']);
0147             }
0148             unset($options['captcha']);
0149         }
0150         parent::setOptions($options);
0151 
0152         if(null !== $captcha) {
0153             $this->setCaptcha($captcha, $captchaOptions);
0154         }
0155         return $this;
0156     }
0157 
0158     /**
0159      * Render form element
0160      *
0161      * @param  Zend_View_Interface $view
0162      * @return string
0163      */
0164     public function render(Zend_View_Interface $view = null)
0165     {
0166         $captcha    = $this->getCaptcha();
0167         $captcha->setName($this->getFullyQualifiedName());
0168 
0169         if (!$this->loadDefaultDecoratorsIsDisabled()) {
0170             $decorators = $this->getDecorators();
0171             $decorator  = $captcha->getDecorator();
0172             $key        = get_class($this->_getDecorator($decorator, null));
0173 
0174             if (!empty($decorator) && !array_key_exists($key, $decorators)) {
0175                 array_unshift($decorators, $decorator);
0176             }
0177 
0178             $decorator = array('Captcha', array('captcha' => $captcha));
0179             $key       = get_class($this->_getDecorator($decorator[0], $decorator[1]));
0180 
0181             if ($captcha instanceof Zend_Captcha_Word && !array_key_exists($key, $decorators)) {
0182                 array_unshift($decorators, $decorator);
0183             }
0184 
0185             $this->setDecorators($decorators);
0186         }
0187 
0188         $this->setValue($this->getCaptcha()->generate());
0189 
0190         return parent::render($view);
0191     }
0192 
0193     /**
0194      * Retrieve plugin loader for validator or filter chain
0195      *
0196      * Support for plugin loader for Captcha adapters
0197      *
0198      * @param  string $type
0199      * @return Zend_Loader_PluginLoader
0200      * @throws Zend_Loader_Exception on invalid type.
0201      */
0202     public function getPluginLoader($type)
0203     {
0204         $type = strtoupper($type);
0205         if ($type == self::CAPTCHA) {
0206             if (!isset($this->_loaders[$type])) {
0207                 // require_once 'Zend/Loader/PluginLoader.php';
0208                 $this->_loaders[$type] = new Zend_Loader_PluginLoader(
0209                     array('Zend_Captcha' => 'Zend/Captcha/')
0210                 );
0211             }
0212             return $this->_loaders[$type];
0213         } else {
0214             return parent::getPluginLoader($type);
0215         }
0216     }
0217 
0218     /**
0219      * Add prefix path for plugin loader for captcha adapters
0220      *
0221      * This method handles the captcha type, the rest is handled by
0222      * the parent
0223      * @param  string $prefix
0224      * @param  string $path
0225      * @param  string $type
0226      * @return Zend_Form_Element
0227      * @see Zend_Form_Element::addPrefixPath
0228      */
0229     public function addPrefixPath($prefix, $path, $type = null)
0230     {
0231         $type = strtoupper($type);
0232         switch ($type) {
0233             case null:
0234                 $loader = $this->getPluginLoader(self::CAPTCHA);
0235                 $nsSeparator = (false !== strpos($prefix, '\\'))?'\\':'_';
0236                 $cPrefix = rtrim($prefix, $nsSeparator) . $nsSeparator . 'Captcha';
0237                 $cPath   = rtrim($path, '/\\') . '/Captcha';
0238                 $loader->addPrefixPath($cPrefix, $cPath);
0239                 return parent::addPrefixPath($prefix, $path);
0240             case self::CAPTCHA:
0241                 $loader = $this->getPluginLoader($type);
0242                 $loader->addPrefixPath($prefix, $path);
0243                 return $this;
0244             default:
0245                 return parent::addPrefixPath($prefix, $path, $type);
0246         }
0247     }
0248 
0249     /**
0250      * Load default decorators
0251      *
0252      * @return Zend_Form_Element_Captcha
0253      */
0254     public function loadDefaultDecorators()
0255     {
0256         if ($this->loadDefaultDecoratorsIsDisabled()) {
0257             return $this;
0258         }
0259 
0260         $decorators = $this->getDecorators();
0261         if (empty($decorators)) {
0262             $this->addDecorator('Errors')
0263                  ->addDecorator('Description', array('tag' => 'p', 'class' => 'description'))
0264                  ->addDecorator('HtmlTag', array('tag' => 'dd', 'id' => $this->getName() . '-element'))
0265                  ->addDecorator('Label', array('tag' => 'dt'));
0266         }
0267         return $this;
0268     }
0269 
0270     /**
0271      * Is the captcha valid?
0272      *
0273      * @param  mixed $value
0274      * @param  mixed $context
0275      * @return boolean
0276      */
0277     public function isValid($value, $context = null)
0278     {
0279         $this->getCaptcha()->setName($this->getName());
0280         $belongsTo = $this->getBelongsTo();
0281         if (empty($belongsTo) || !is_array($context)) {
0282             return parent::isValid($value, $context);
0283         }
0284 
0285         $name     = $this->getFullyQualifiedName();
0286         $root     = substr($name, 0, strpos($name, '['));
0287         $segments = substr($name, strpos($name, '['));
0288         $segments = ltrim($segments, '[');
0289         $segments = rtrim($segments, ']');
0290         $segments = explode('][', $segments);
0291         array_unshift($segments, $root);
0292         array_pop($segments);
0293         $newContext = $context;
0294         foreach ($segments as $segment) {
0295             if (array_key_exists($segment, $newContext)) {
0296                 $newContext = $newContext[$segment];
0297             }
0298         }
0299 
0300         return parent::isValid($value, $newContext);
0301     }
0302 }