diff --git a/.gitignore b/.gitignore index 485dee6..09122f6 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ -.idea +.idea/ +.vscode/ +vendor/ +.DS_Store \ No newline at end of file diff --git a/.ide-helper.php b/.ide-helper.php new file mode 100644 index 0000000..b1df0c6 --- /dev/null +++ b/.ide-helper.php @@ -0,0 +1,23 @@ +getCaptcha()->passCaptcha()) { + return false; + } + + return parent::send(); + } +} diff --git a/Application/Controller/DetailsController.php b/Application/Controller/DetailsController.php new file mode 100644 index 0000000..e1543b9 --- /dev/null +++ b/Application/Controller/DetailsController.php @@ -0,0 +1,23 @@ +getCaptcha()->passCaptcha(false)) { + $this->_iPriceAlarmStatus = 2; + + return; + } + + return parent::addme(); + } +} diff --git a/Application/Controller/ForgotPasswordController.php b/Application/Controller/ForgotPasswordController.php new file mode 100644 index 0000000..8dda74f --- /dev/null +++ b/Application/Controller/ForgotPasswordController.php @@ -0,0 +1,21 @@ +getCaptcha()->passCaptcha()) { + return false; + } + + return parent::forgotpassword(); + } +} diff --git a/Application/Controller/ImageGeneratorController.php b/Application/Controller/ImageGeneratorController.php new file mode 100644 index 0000000..e53422a --- /dev/null +++ b/Application/Controller/ImageGeneratorController.php @@ -0,0 +1,102 @@ +emac = Registry::getRequest()->getRequestEscapedParameter('e_mac', null); + if ($this->emac) { + $this->emac = $this->decodeEmac($this->emac); + } + } + + public function render() + { + parent::render(); + + try { + if (!$this->emac) { + throw new StandardException('No e_mac parameter given'); + } + $image = $this->generateVerificationImage(); + if (!$image) { + throw new StandardException('Image generation failed by returning NULL'); + } + header('Content-type: image/png'); + imagepng($image); + imagedestroy($image); + + exit; + } catch (Throwable $e) { + Registry::getLogger()->error(sprintf('%s() | %s', __METHOD__, $e->getMessage()), [$e]); + http_response_code(400); + + exit(1); + } + } + + protected function decodeEmac(string $emac): string + { + $decryptor = new \OxidEsales\Eshop\Core\Decryptor(); + + $key = $this->getOeCaptchaKey(); + + return $decryptor->decrypt($emac, $key); + } + + protected function generateVerificationImage() + { + $image = null; + + switch (true) { + case function_exists('imagecreatetruecolor'): + $image = imagecreatetruecolor($this->imageWidth, $this->imageHeight); + + break; + + case function_exists('imagecreate'): + $image = imagecreate($this->imageWidth, $this->imageHeight); + + break; + + default: + return null; + } + $textX = (int)ceil(($this->imageWidth - strlen($this->emac) * imagefontwidth($this->fontSize)) / 2); + $textY = (int)ceil(($this->imageHeight - imagefontheight($this->fontSize)) / 2) - 1; + + $colors = [ + 'text' => imagecolorallocate($image, 0, 0, 0), + 'shadow1' => imagecolorallocate($image, 200, 200, 200), + 'shadow2' => imagecolorallocate($image, 100, 100, 100), + 'background' => imagecolorallocate($image, 255, 255, 255), + 'border' => imagecolorallocate($image, 0, 0, 0), + ]; + + imagefill($image, 0, 0, $colors['background']); + imagerectangle($image, 0, 0, $this->imageWidth - 2, $this->imageHeight - 2, $colors['border']); + imagestring($image, $this->fontSize, $textX + 1, $textY + 0, $this->emac, $colors['shadow2']); + imagestring($image, $this->fontSize, $textX + 0, $textY + 1, $this->emac, $colors['shadow1']); + imagestring($image, $this->fontSize, $textX, $textY, $this->emac, $colors['text']); + + return $image; + } +} diff --git a/Application/Controller/InviteController.php b/Application/Controller/InviteController.php new file mode 100644 index 0000000..42e3e4d --- /dev/null +++ b/Application/Controller/InviteController.php @@ -0,0 +1,21 @@ +getCaptcha()->passCaptcha()) { + return false; + } + + return parent::send(); + } +} diff --git a/Application/Controller/NewsletterController.php b/Application/Controller/NewsletterController.php new file mode 100644 index 0000000..ddd78bd --- /dev/null +++ b/Application/Controller/NewsletterController.php @@ -0,0 +1,21 @@ +getCaptcha()->passCaptcha()) { + return false; + } + + return parent::send(); + } +} diff --git a/Application/Controller/PricealarmController.php b/Application/Controller/PricealarmController.php new file mode 100644 index 0000000..cc8c455 --- /dev/null +++ b/Application/Controller/PricealarmController.php @@ -0,0 +1,23 @@ +getCaptcha()->passCaptcha(false)) { + $this->_iPriceAlarmStatus = 2; + + return; + } + + return parent::addme(); + } +} diff --git a/core/oecaptcha.php b/Application/Core/Captcha.php similarity index 52% rename from core/oecaptcha.php rename to Application/Core/Captcha.php index 2959fc6..cba5d81 100644 --- a/core/oecaptcha.php +++ b/Application/Core/Captcha.php @@ -1,47 +1,55 @@ text) { $this->text = ''; - for ($i = 0; $i < $this->macLength; $i++) { + + for ($i = 0; $i < $this->macLength; ++$i) { $this->text .= strtolower($this->macChars[rand(0, strlen($this->macChars) - 1)]); } } @@ -58,38 +67,7 @@ class oeCaptcha extends oxSuperCfg } /** - * Returns text hash - * - * @param string $text User supplie text - * - * @return string - */ - public function getHash($text = null) - { - // inserting captcha record - $time = time() + $this->timeout; - $textHash = $this->getTextHash($text); - - // if session is started - storing captcha info here - $session = $this->getSession(); - if ($session->isSessionStarted()) { - $hash = oxUtilsObject::getInstance()->generateUID(); - $hashArray = $session->getVariable('captchaHashes'); - $hashArray[$hash] = array($textHash => $time); - $session->setVariable('captchaHashes', $hashArray); - } else { - $database = DatabaseProvider::getDb(); - $query = "insert into oecaptcha (oxhash, oxtime) values (" . - $database->quote($textHash) . ", " . $database->quote($time) . ")"; - $database->execute($query); - $hash = $database->getOne('select LAST_INSERT_ID()', false, false); - } - - return $hash; - } - - /** - * Returns given string captcha hash + * Returns given string captcha hash. * * @param string $text string to hash * @@ -105,38 +83,11 @@ class oeCaptcha extends oxSuperCfg return md5('ox' . $text); } - /** - * Returns url to CAPTCHA image generator. - * - * @return string - */ - public function getImageUrl() - { - $config = \OxidEsales\Eshop\Core\Registry::getConfig(); - $url = $config->getCurrentShopUrl() . 'modules/oe/captcha/core/utils/verificationimg.php?e_mac='; - $key = $config->getConfigParam('oecaptchakey'); - - $key = $key ? $key : $config->getConfigParam('sConfigKey'); - - $encryptor = new \OxidEsales\Eshop\Core\Encryptor(); - $url .= $encryptor->encrypt($this->getText(), $key); - - return $url; - } - - /** - * Checks if image could be generated - * - * @return bool - */ - public function isImageVisible() - { - return ((function_exists('imagecreatetruecolor') || function_exists('imagecreate')) && $this->getConfig()->getConfigParam('iUseGDVersion') > 1); - } - /** * Check if captcha is passed. * + * @param mixed $displayError + * * @return bool */ public function passCaptcha($displayError = true) @@ -144,8 +95,8 @@ class oeCaptcha extends oxSuperCfg $return = true; // spam spider prevention - $mac = $this->getConfig()->getRequestParameter('c_mac'); - $macHash = $this->getConfig()->getRequestParameter('c_mach'); + $mac = Registry::getRequest()->getRequestParameter('c_mac'); + $macHash = Registry::getRequest()->getRequestParameter('c_mach'); if (!$this->pass($mac, $macHash)) { $return = false; @@ -153,12 +104,139 @@ class oeCaptcha extends oxSuperCfg if (!$return && $displayError) { // even if there is no exception, use this as a default display method - oxRegistry::get('oxUtilsView')->addErrorToDisplay('MESSAGE_WRONG_VERIFICATION_CODE'); + Registry::getUtilsView()->addErrorToDisplay('MESSAGE_WRONG_VERIFICATION_CODE'); } return $return; } + /** + * Checks if image could be generated. + * + * @return bool + */ + public function isImageVisible() + { + return (function_exists('imagecreatetruecolor') || function_exists('imagecreate')) && Registry::getConfig()->getConfigParam('iUseGDVersion') > 1; + } + + /** + * Returns url to CAPTCHA image generator. + * + * @return string + */ + public function getImageUrl() + { + $config = Registry::getConfig(); + $key = $this->getOeCaptchaKey(); + $encryptor = new \OxidEsales\Eshop\Core\Encryptor(); + + return $config->getCurrentShopUrl() . sprintf('?cl=oe_captcha_generator&e_mac=%s&shp=%d', $encryptor->encrypt($this->getText(), $key), $config->getShopId()); + } + + /** + * Returns text hash. + * + * @param string $text User supplie text + * + * @return string + */ + public function getHash($text = null) + { + // inserting captcha record + $time = time() + $this->timeout; + $textHash = $this->getTextHash($text); + + // if session is started - storing captcha info here + $session = Registry::getSession(); + if ($session->isSessionStarted()) { + $hash = UtilsObject::getInstance()->generateUID(); + $hashArray = $session->getVariable('captchaHashes'); + $hashArray[$hash] = [$textHash => $time]; + $session->setVariable('captchaHashes', $hashArray); + } else { + $q = $this->getQueryBuilder(); + $q->insert('oecaptcha') + ->values( + [ + 'oxhash' => '?', + 'oxtime' => '?', + ] + )->setParameter(0, $textHash)->setParameter(1, $time); + $q->execute(); + $hash = $q->getConnection()->lastInsertId(); + } + + return $hash; + } + + /** + * Checks for DB captcha hash validity. + * + * @param int $macHash hash key + * @param string $hash captcha hash + * @param int $time check time + * + * @return bool + */ + protected function passFromDb($macHash, $hash, $time) + { + $q = $this->getQueryBuilder(); + $q->select('1') + ->from('oecaptcha') + ->where('oxid = :macHash') + ->andWhere('oxhash = :hash') + ->setParameter('macHash', $macHash) + ->setParameter('hash', $hash); + $pass = (bool) $q->execute()->fetchOne(); + if ($pass) { + // cleanup + $q = $this->getQueryBuilder() + ->delete('oecaptcha') + ->where('oxid = :macHash') + ->andWhere('oxhash = :hash') + ->setParameter('macHash', $macHash) + ->setParameter('hash', $hash); + $q->execute(); + } + + // garbage cleanup + $q = $this->getQueryBuilder() + ->delete('oecaptcha') + ->where('oxtime < :time') + ->setParameter('time', $time); + $q->execute(); + + return $pass; + } + + /** + * Checks for session captcha hash validity. + * + * @param string $macHash hash key + * @param string $hash captcha hash + * @param int $time check time + * + * @return bool + */ + protected function passFromSession($macHash, $hash, $time) + { + $pass = null; + $session = Registry::getSession(); + + if ($hashArray = $session->getVariable('captchaHashes')) { + $pass = (isset($hashArray[$macHash][$hash]) && $hashArray[$macHash][$hash] >= $time) ? true : false; + unset($hashArray[$macHash]); + if (!empty($hashArray)) { + $session->setVariable('captchaHashes', $hashArray); + } else { + $session->deleteVariable('captchaHashes'); + } + } + + return $pass; + } + /** * Verifies captcha input vs supplied hash. Returns true on success. * @@ -174,67 +252,10 @@ class oeCaptcha extends oxSuperCfg $pass = $this->passFromSession($macHash, $hash, $time); // if captcha info was NOT stored in session - if ($pass === null) { + if (null === $pass) { $pass = $this->passFromDb((int) $macHash, $hash, $time); } return (bool) $pass; } - - /** - * Checks for session captcha hash validity - * - * @param string $macHash hash key - * @param string $hash captcha hash - * @param int $time check time - * - * @return bool - */ - protected function passFromSession($macHash, $hash, $time) - { - $pass = null; - $session = $this->getSession(); - - if (($hashArray = $session->getVariable('captchaHashes'))) { - $pass = (isset($hashArray[$macHash][$hash]) && $hashArray[$macHash][$hash] >= $time) ? true : false; - unset($hashArray[$macHash]); - if (!empty($hashArray)) { - $session->setVariable('captchaHashes', $hashArray); - } else { - $session->deleteVariable('captchaHashes'); - } - } - - return $pass; - } - - /** - * Checks for DB captcha hash validity - * - * @param int $macHash hash key - * @param string $hash captcha hash - * @param int $time check time - * - * @return bool - */ - protected function passFromDb($macHash, $hash, $time) - { - $database = DatabaseProvider::getDb(); - $where = "where oxid = " . $database->quote($macHash) . " and oxhash = " . $database->quote($hash); - $query = "select 1 from oecaptcha " . $where; - $pass = (bool) $database->getOne($query, false, false); - - if ($pass) { - // cleanup - $query = "delete from oecaptcha " . $where; - $database->execute($query); - } - - // garbage cleanup - $query = "delete from oecaptcha where oxtime < $time"; - $database->execute($query); - - return $pass; - } - } diff --git a/Application/Core/Module.php b/Application/Core/Module.php new file mode 100644 index 0000000..7e7edbd --- /dev/null +++ b/Application/Core/Module.php @@ -0,0 +1,62 @@ +activate(); + } + + public static function onDeactivate(): void + { + static::getInstance()->deactivate(); + } + + public function createTable(): void + { + $this->getDb()->executeStatement(' + CREATE TABLE IF NOT EXISTS `oecaptcha` (' . + "`OXID` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Captcha id'," . + "`OXHASH` char(32) NOT NULL default '' COMMENT 'Hash'," . + "`OXTIME` int(11) NOT NULL COMMENT 'Validation time'," . + "`OXTIMESTAMP` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP COMMENT 'Timestamp'," . + 'PRIMARY KEY (`OXID`), ' . + 'KEY `OXID` (`OXID`,`OXHASH`), ' . + 'KEY `OXTIME` (`OXTIME`) ' . + ") ENGINE=MEMORY AUTO_INCREMENT=1 COMMENT 'If session is not available, this is where captcha information is stored'; + "); + } + + public function dropTable(): void + { + $this->getDb()->executeStatement('DROP TABLE IF EXISTS `oecaptcha`;'); + } + + public function activate(): void + { + $this->createTable(); + } + + public function deactivate(): void + { + $this->dropTable(); + } +} diff --git a/Application/Shared/Captcha.php b/Application/Shared/Captcha.php new file mode 100644 index 0000000..0ba062e --- /dev/null +++ b/Application/Shared/Captcha.php @@ -0,0 +1,17 @@ +oeCaptcha ??= CaptchaCore::getInstance(); + } +} diff --git a/Application/Shared/Connection.php b/Application/Shared/Connection.php new file mode 100644 index 0000000..625f1b3 --- /dev/null +++ b/Application/Shared/Connection.php @@ -0,0 +1,25 @@ +getContainer(); + + return $container->get(QueryBuilderFactoryInterface::class)->create(); + } + + public function getDb(): \Doctrine\DBAL\Connection + { + return ContainerFactory::getInstance()->getContainer()->get(ConnectionProviderInterface::class)->get(); + } +} diff --git a/Application/Shared/Options.php b/Application/Shared/Options.php new file mode 100644 index 0000000..1391e1e --- /dev/null +++ b/Application/Shared/Options.php @@ -0,0 +1,23 @@ +getContainer()->get(ModuleSettingServiceInterface::class); + $key = $bridge->getString('oecaptchakey', 'oecaptcha')->toString(); + if (!trim($key)) { + return Captcha::ENCRYPT_KEY; + } + + return $key; + } +} diff --git a/translations/de/oecaptcha_de_lang.php b/Application/translations/de/oecaptcha_de_lang.php old mode 100755 new mode 100644 similarity index 69% rename from translations/de/oecaptcha_de_lang.php rename to Application/translations/de/oecaptcha_de_lang.php index 0effcb4..02977fe --- a/translations/de/oecaptcha_de_lang.php +++ b/Application/translations/de/oecaptcha_de_lang.php @@ -1,17 +1,17 @@ 'UTF-8', - 'MESSAGE_WRONG_VERIFICATION_CODE' => 'Der Prüfcode, den Sie eingegeben haben, ist nicht korrekt. Bitte versuchen Sie es erneut!' -); + 'MESSAGE_WRONG_VERIFICATION_CODE' => 'Der Prüfcode, den Sie eingegeben haben, ist nicht korrekt. Bitte versuchen Sie es erneut!', + 'OECAPTCHA_PLACEHOLDER' => 'Enter verification code here', +]; diff --git a/Application/translations/en/oecaptcha_en_lang.php b/Application/translations/en/oecaptcha_en_lang.php new file mode 100644 index 0000000..0c84406 --- /dev/null +++ b/Application/translations/en/oecaptcha_en_lang.php @@ -0,0 +1,18 @@ + 'UTF-8', + 'MESSAGE_WRONG_VERIFICATION_CODE' => 'The verification code you entered is not correct. Please try again.', + 'OECAPTCHA_PLACEHOLDER' => 'Prüfcode hier eingeben', + +]; diff --git a/Application/views/admin_smarty/de/oe_captcha_admin_de_lang.php b/Application/views/admin_smarty/de/oe_captcha_admin_de_lang.php new file mode 100644 index 0000000..5b16ac8 --- /dev/null +++ b/Application/views/admin_smarty/de/oe_captcha_admin_de_lang.php @@ -0,0 +1,9 @@ + 'UTF-8', + 'SHOP_MODULE_GROUP_main' => 'Allgemein', + 'SHOP_MODULE_oecaptchakey' => 'Captcha Key', +]; diff --git a/Application/views/admin_smarty/en/oe_captcha_admin_en_lang.php b/Application/views/admin_smarty/en/oe_captcha_admin_en_lang.php new file mode 100644 index 0000000..2ecd391 --- /dev/null +++ b/Application/views/admin_smarty/en/oe_captcha_admin_en_lang.php @@ -0,0 +1,9 @@ + 'UTF-8', + 'SHOP_MODULE_GROUP_main' => 'General', + 'SHOP_MODULE_oecaptchakey' => 'Captcha Key', +]; diff --git a/Application/views/admin_twig/de/oe_captcha_admin_de_lang.php b/Application/views/admin_twig/de/oe_captcha_admin_de_lang.php new file mode 100644 index 0000000..5b16ac8 --- /dev/null +++ b/Application/views/admin_twig/de/oe_captcha_admin_de_lang.php @@ -0,0 +1,9 @@ + 'UTF-8', + 'SHOP_MODULE_GROUP_main' => 'Allgemein', + 'SHOP_MODULE_oecaptchakey' => 'Captcha Key', +]; diff --git a/Application/views/admin_twig/en/oe_captcha_admin_en_lang.php b/Application/views/admin_twig/en/oe_captcha_admin_en_lang.php new file mode 100644 index 0000000..2ecd391 --- /dev/null +++ b/Application/views/admin_twig/en/oe_captcha_admin_en_lang.php @@ -0,0 +1,9 @@ + 'UTF-8', + 'SHOP_MODULE_GROUP_main' => 'General', + 'SHOP_MODULE_oecaptchakey' => 'Captcha Key', +]; diff --git a/CHANGELOG.md b/CHANGELOG.md index ef2c2b6..67ffc35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,19 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Security +## [7.0.0] - 18 Jul 2023 +### Changed +- PHP 8.0 compatibility +- OXID 7.0 compatibility +- Twig & Smarty Support +- Major version bump to 7.0.0 to match OXID 7.0 compatibility +### Removed +- Suggest dropped out +- /docs folder (no relevant information) + +### Deprecated +- Tests won't work for this release and should be updated in the future. ## [2.0.4] - 22 Oct 2021 diff --git a/README.md b/README.md index dd83b41..3922987 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,9 @@ It is used to ensure that only a user who can read the distorted characters and can submit the following forms: - contact - invite - - pricealarm - - suggest + - pricealarm (not bound in twig) + - newsletter (not bound in twig) + - forgotpwd (not bound in twig) The captcha module then validates the submitted value against the expected one and then decides whether to process the request (e.g. send contact mail to shop administrator) or refuse and show an error message instead. @@ -24,29 +25,55 @@ Please proceed with one of the following ways to install the module: In order to install the module via composer, run the following commands in commandline of your shop base directory (where the shop's composer.json file resides). -``` +```bash composer require oxid-projects/captcha-module ``` ### Module installation via repository cloning Clone the module to your OXID eShop **modules/oe/** directory: -``` +```bash git clone https://github.com/OXIDprojects/captcha-module.git captcha ``` - -### Module installation from zip package - -* Make a new folder "captcha" in the **modules/oe/ directory** of your shop installation. -* Download the https://github.com/OXIDprojects/captcha-module/archive/master.zip file and unpack it into the created folder. +And add repository to root composer: +```bash +composer config repositories.oxid-projects/captcha-module path "source/modules/oe/captcha" +``` +And install module: +```bash +composer require oxid-projects/captcha-module +vendor/bin/oe-console oe:module:install source/modules/oe/captcha +``` ## Activate Module - Activate the module in the administration panel. +- Or use console +```bash +vendor/bin/oe-console oe:module:activate oecaptcha +vendor/bin/oe-console oe:cache:clear +``` ## Uninstall -Disable the module in administration area and delete the module folder. +Disable the module in administration area or by executing following shell command. +```bash +vendor/bin/oe-console oe:module:deactivate oecaptcha +``` +If installed over composer (packagist): +```bash +composer remove oxid-projects/captcha-module +vendor/bin/oe-console oe:cache:clear +``` +else if cloned: +```bash +vendor/bin/oe-console oe:module:uninstall oecaptcha +vendor/bin/oe-console oe:cache:clear +composer remove oxid-projects/captcha-module +composer config --unset repositories.oxid-projects/captcha-module +# and remove the source itself +rm -rf source/modules/oe/captcha +``` ## License diff --git a/application/component/widget/oecaptchawarticledetails.php b/application/component/widget/oecaptchawarticledetails.php deleted file mode 100644 index 773159e..0000000 --- a/application/component/widget/oecaptchawarticledetails.php +++ /dev/null @@ -1,30 +0,0 @@ -captcha === null) { - $this->captcha = oxNew('oeCaptcha'); - } - return $this->captcha; - } -} diff --git a/application/views/admin/de/module_options.php b/application/views/admin/de/module_options.php deleted file mode 100644 index 8440e95..0000000 --- a/application/views/admin/de/module_options.php +++ /dev/null @@ -1,13 +0,0 @@ - 'UTF-8', - 'SHOP_MODULE_GROUP_main' => 'Allgemein', - 'SHOP_MODULE_oecaptchakey' => 'Captcha Key', -); diff --git a/application/views/admin/en/module_options.php b/application/views/admin/en/module_options.php deleted file mode 100644 index b9b8e88..0000000 --- a/application/views/admin/en/module_options.php +++ /dev/null @@ -1,13 +0,0 @@ - 'UTF-8', - 'SHOP_MODULE_GROUP_main' => 'General', - 'SHOP_MODULE_oecaptchakey' => 'Captcha Key', -); diff --git a/application/views/blocks/captcha_form.tpl b/application/views/blocks/captcha_form.tpl deleted file mode 100644 index 531645c..0000000 --- a/application/views/blocks/captcha_form.tpl +++ /dev/null @@ -1,3 +0,0 @@ -[{$smarty.block.parent}] - -[{include file="oecaptcha.tpl" labelCssClass="col-lg-2" inputCssClass="col-lg-10"}] diff --git a/application/views/blocks/captcha_form_forgotpwd.tpl b/application/views/blocks/captcha_form_forgotpwd.tpl deleted file mode 100644 index 5171b71..0000000 --- a/application/views/blocks/captcha_form_forgotpwd.tpl +++ /dev/null @@ -1,3 +0,0 @@ -[{$smarty.block.parent}] - -[{include file="oecaptcha.tpl" labelCssClass="col-md-3" inputCssClass="col-md-9"}] diff --git a/application/views/tpl/oecaptcha.tpl b/application/views/tpl/oecaptcha.tpl deleted file mode 100644 index be78fb2..0000000 --- a/application/views/tpl/oecaptcha.tpl +++ /dev/null @@ -1,19 +0,0 @@ -[{assign var="oCaptcha" value=$oView->getCaptcha()}] - - -