PageRenderTime 45ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/View/Helper/RecaptchaHelper.php

http://github.com/CakeDC/recaptcha
PHP | 272 lines | 127 code | 39 blank | 106 comment | 20 complexity | b9dd4c5a30159afe8ef851e5e6ac8572 MD5 | raw file
  1. <?php
  2. /**
  3. * Copyright 2009-2014, Cake Development Corporation (http://cakedc.com)
  4. *
  5. * Licensed under The MIT License
  6. * Redistributions of files must retain the above copyright notice.
  7. *
  8. * @copyright Copyright 2009-2014, Cake Development Corporation (http://cakedc.com)
  9. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  10. */
  11. /**
  12. * CakePHP Recaptcha helper
  13. *
  14. * @property HtmlHelper Html
  15. * @property FormHelper Form
  16. * @property View View
  17. * @package recaptcha
  18. * @subpackage recaptcha.views.helpers
  19. */
  20. class RecaptchaHelper extends AppHelper {
  21. /**
  22. * API Url
  23. *
  24. * @var string
  25. */
  26. public $apiUrl = 'https://www.google.com/recaptcha/api.js';
  27. /**
  28. * View helpers
  29. *
  30. * @var array
  31. */
  32. public $helpers = array('Form', 'Html');
  33. /**
  34. * Callback function name (fot explicit rendering)
  35. *
  36. * @var string
  37. */
  38. protected $callback = 'onRecaptchaLoadCallback';
  39. /**
  40. * Items to render explicitly
  41. *
  42. * @var array
  43. */
  44. protected $explicit = array();
  45. public function afterRender($viewFile) {
  46. if ($this->explicit) {
  47. $script = array();
  48. $script[] = sprintf("var %s = function() {", $this->callback);
  49. foreach ($this->explicit as $k => $v) {
  50. array_unshift($script, sprintf('var %s;', $k));
  51. $script[] = sprintf('%s = grecaptcha.render(\'%s\', %s);', $k, $k, json_encode($v));
  52. }
  53. $script[] = "}";
  54. $this->Html->scriptBlock(implode("\n", $script), array('block' => 'script'));
  55. }
  56. }
  57. /**
  58. * Displays the Recaptcha input
  59. *
  60. * @param array $options An array of options
  61. *
  62. * ### Options:
  63. *
  64. * - `element` String, name of the view element that can be used instead of the hardcoded HTML structure from this helper
  65. * - `explicit` reCAPTCHA rendering method. Set to true when rendering multiple reCAPTCHAs on a page
  66. * - `error` String, optional error message that is displayed using Form::error()
  67. * - `div` Array of options for the div tag the recaptcha is wrapped with, set to false if you want to disable it
  68. * - `lang` Forces the widget to render in a specific language
  69. * - `recaptchaOptions` assoc array of options to pass into RecaptchaOptions var, like 'sitekey' (default is read from Configure::read('Recaptcha.publicKey')), 'theme', 'type', 'size.
  70. *
  71. * @return string The resulting mark up
  72. * @access public
  73. */
  74. public function display($options = array()) {
  75. $defaults = array(
  76. 'element' => null,
  77. 'explicit' => false,
  78. 'error' => false,
  79. 'div' => array(
  80. 'class' => 'recaptcha',
  81. ),
  82. 'lang' => 'en',
  83. 'recaptchaOptions' => array(
  84. 'sitekey' => Configure::read('Recaptcha.publicKey'),
  85. 'theme' => 'light',
  86. ),
  87. );
  88. $options = Hash::merge($defaults, $options);
  89. if ($element = $options['element']) {
  90. $elementOptions = array();
  91. if (is_array($element)) {
  92. $keys = array_keys($element);
  93. $elementOptions = $element[$keys[0]];
  94. }
  95. return $this->View->element($element, $elementOptions);
  96. }
  97. if ($lang = Hash::get($options, 'recaptchaOptions.lang')) {
  98. // Backwards compatibility
  99. $options['lang'] = $lang;
  100. unset($options['recaptchaOptions']['lang']);
  101. }
  102. if ($publicKey = Hash::get($options, 'publicKey')) {
  103. // Backwards compatibility
  104. $options['recaptchaOptions']['sitekey'] = $publicKey;
  105. unset($options['publicKey']);
  106. }
  107. $query = array('hl' => $options['lang']);
  108. if ($options['explicit']) {
  109. $query = array_merge($query, array('onload' => $this->callback, 'render' => 'explicit'));
  110. $id = Hash::get($options, 'id', uniqid('recaptcha'));
  111. $this->explicit[$id] = $options['recaptchaOptions'];
  112. $output = $this->Html->tag('div', '', compact('id'));
  113. } else {
  114. $data = array_combine(
  115. array_map(
  116. function ($k) {
  117. return 'data-' . $k;
  118. },
  119. array_keys($options['recaptchaOptions'])
  120. ),
  121. $options['recaptchaOptions']
  122. );
  123. $data['class'] = 'g-recaptcha';
  124. $output = $this->Html->tag('div', '', $data);
  125. }
  126. if ($error = $options['error']) {
  127. $output .= $this->Form->error($error);
  128. }
  129. if ($options['div']) {
  130. $output = $this->Html->tag('div', $output, $options['div']);
  131. }
  132. $this->Form->unlockField('g-recaptcha-response');
  133. $apiUrl = $this->apiUrl . '?' . http_build_query($query);
  134. $this->Html->script($apiUrl, array('block' => 'script', 'async' => true, 'defer' => true, 'once' => true));
  135. return $output;
  136. }
  137. /**
  138. * Recaptcha signup URL
  139. *
  140. * @param string $appName An application name
  141. * @return string A signup url
  142. */
  143. public function signupUrl($appName = null) {
  144. return "https://www.google.com/recaptcha/admin?domain=" . WWW_ROOT . '&amp;app=' . urlencode($appName);
  145. }
  146. /**
  147. * AES Pad
  148. *
  149. * @param string $val A value to pad
  150. * @return string
  151. */
  152. private function __aesPad($val) {
  153. $blockSize = 16;
  154. $numpad = $blockSize - (strlen($val) % $blockSize);
  155. return str_pad($val, strlen($val) + $numpad, chr($numpad));
  156. }
  157. /**
  158. * AES Encryption
  159. *
  160. * @param string $value A value
  161. * @param string $key A key to use
  162. * @return string
  163. * @throws Exception
  164. */
  165. private function __aesEncrypt($value, $key) {
  166. if (!function_exists('mcrypt_encrypt')) {
  167. throw new Exception(__d('recaptcha', 'To use reCAPTCHA Mailhide, you need to have the mcrypt php module installed.', true));
  168. }
  169. $mode = MCRYPT_MODE_CBC;
  170. $encryption = MCRYPT_RIJNDAEL_128;
  171. $value = $this->__aesPad($value);
  172. return mcrypt_encrypt($encryption, $key, $value, $mode, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
  173. }
  174. /**
  175. * Mail-hide URL
  176. *
  177. * @param string $x An input string
  178. * @return string A base 64 encrypted string
  179. */
  180. private function __mailhideUrlbase64($x) {
  181. return strtr(base64_encode($x), '+/', '-_');
  182. }
  183. /**
  184. * Gets the reCAPTCHA Mailhide url for a given email
  185. *
  186. * @param string $email An email address
  187. * @return string
  188. * @throws Exception
  189. */
  190. public function mailHideUrl($email = null) {
  191. $publicKey = Configure::read('Recaptcha.mailHide.publicKey');
  192. $privateKey = Configure::read('Recaptcha.mailHide.privateKey');
  193. if ($publicKey == '' || $publicKey == null || $privateKey == "" || $privateKey == null) {
  194. throw new Exception(__d('recaptcha', "You need to set a private and public mail hide key. Please visit https://www.google.com/recaptcha/mailhide/apikey", true));
  195. }
  196. $key = pack('H*', $privateKey);
  197. $cryptmail = $this->__aesEncrypt($email, $key);
  198. return "http://mailhide.recaptcha.net/d?k=" . $publicKey . "&c=" . $this->__mailhideUrlbase64($cryptmail);
  199. }
  200. /**
  201. * Get a part of the email to show
  202. *
  203. * Given johndoe@example,com return ["john", "example.com"].
  204. * the email is then displayed as john...@example.com
  205. *
  206. * @param string $email an email address
  207. * @return array
  208. */
  209. private function __hideEmailParts($email) {
  210. $array = preg_split("/@/", $email );
  211. if (strlen($array[0]) <= 4) {
  212. $array[0] = substr($array[0], 0, 1);
  213. } elseif (strlen($array[0]) <= 6) {
  214. $array[0] = substr($array[0], 0, 3);
  215. } else {
  216. $array[0] = substr($array[0], 0, 4);
  217. }
  218. return $array;
  219. }
  220. /**
  221. * Gets html to display an email address given a public an private key to get a key go to:
  222. * https://www.google.com/recaptcha/mailhide/apikey
  223. *
  224. * @param string $email An email address
  225. * @return string
  226. */
  227. public function mailHide($email) {
  228. $emailparts = $this->__hideEmailParts($email);
  229. $url = $this->mailHideUrl($email);
  230. return htmlentities($emailparts[0]) . "<a href='" . htmlentities($url) .
  231. "' onclick=\"window.open('" . htmlentities($url) . "', '', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=500,height=300'); return false;\" title=\"Reveal this e-mail address\">...</a>@" . htmlentities($emailparts[1]);
  232. }
  233. }