tag to enclose the reCAPTCHA code. Patch provided by Tom. |
+| | |* Changed to write log entries into "logs/recaptch.log". Patch provided by Tom. |
+| 1.0.0 | 2014-01-24 |* Initial release |
diff --git a/plugins/recaptcha/autoinstall.php b/plugins/recaptcha/autoinstall.php
new file mode 100644
index 000000000..fa3ff4813
--- /dev/null
+++ b/plugins/recaptcha/autoinstall.php
@@ -0,0 +1,99 @@
+ array(
+ 'pi_name' => 'recaptcha',
+ 'pi_display_name' => 'reCAPTCHA',
+ 'pi_version' => $_RECAPTCHA_CONF['pi_version'],
+ 'pi_gl_version' => $_RECAPTCHA_CONF['gl_version'],
+ 'pi_homepage' => $_RECAPTCHA_CONF['pi_url'],
+ ),
+ 'groups' => $_RECAPTCHA_CONF['GROUPS'],
+ 'features' => $_RECAPTCHA_CONF['FEATURES'],
+ 'mappings' => $_RECAPTCHA_CONF['MAPPINGS'],
+ 'tables' => array(),
+ );
+}
+
+/**
+ * Load plugin configuration from database
+ *
+ * @param string $pi_name Plugin name
+ * @return bool true on success, otherwise false
+ * @see plugin_initconfig_recaptcha
+ */
+function plugin_load_configuration_recaptcha($pi_name)
+{
+ require_once __DIR__ . '/install_defaults.php';
+
+ return plugin_initconfig_recaptcha();
+}
+
+/**
+ * Checks if the plugin is compatible with this Geeklog version
+ *
+ * @param string $pi_name Plugin name
+ * @return bool true: plugin compatible; false: not compatible
+ */
+function plugin_compatible_with_this_version_recaptcha($pi_name)
+{
+ global $_RECAPTCHA_CONF;
+
+ require_once __DIR__ . '/config.php';
+
+ $geeklogVersion = preg_replace('/[^0-9.]/', '', VERSION);
+
+ return version_compare(PHP_VERSION, '5.3.0', '>=') &&
+ version_compare($geeklogVersion, $_RECAPTCHA_CONF['gl_version'], '>=');
+}
diff --git a/plugins/recaptcha/config.php b/plugins/recaptcha/config.php
new file mode 100644
index 000000000..ac5d00a5c
--- /dev/null
+++ b/plugins/recaptcha/config.php
@@ -0,0 +1,57 @@
+ 'Users in this group can administer the ReCAPTCHA plugin',
+);
+$_RECAPTCHA_CONF['FEATURES'] = array(
+ 'recaptcha.edit' => 'Access to reCAPTCHA editor',
+);
+$_RECAPTCHA_CONF['MAPPINGS'] = array(
+ 'recaptcha.edit' => array('reCAPTCHA Admin'),
+);
+
+// Items the reCAPTCHA plugin supports
+$_RECAPTCHA_CONF['supported_items'] = array(
+ 'comment', 'story', 'registration', 'loginform', 'getpassword', 'contact',
+ 'emailstory', 'forum', 'mediagallery', 'rating', 'links', 'calendar',
+);
diff --git a/plugins/recaptcha/configuration_validation.php b/plugins/recaptcha/configuration_validation.php
new file mode 100644
index 000000000..ecc7419bc
--- /dev/null
+++ b/plugins/recaptcha/configuration_validation.php
@@ -0,0 +1,62 @@
+ array('rule' => 'stringOrEmpty'),
+ 'secret_key' => array('rule' => 'stringOrEmpty'),
+ 'invisible_site_key' => array('rule' => 'stringOrEmpty'),
+ 'invisible_secret_key' => array('rule' => 'stringOrEmpty'),
+ 'logging' => array('rule' => array('inList', array('0', '1'), true)),
+ 'anonymous_only' => array('rule' => array('inList', array('0', '1'), true)),
+ 'remoteusers' => array('rule' => array('inList', array('0', '1'), true)),
+
+ // '0' => Disabled, '1' => reCAPTCHA v2, '2' => Invisible reCAPTCHA
+ 'enable_comment' => array('rule' => array('inList', array('0', '1', '2'), true)),
+ 'enable_contact' => array('rule' => array('inList', array('0', '1', '2'), true)),
+ 'enable_emailstory' => array('rule' => array('inList', array('0', '1', '2'), true)),
+ 'enable_registration' => array('rule' => array('inList', array('0', '1', '2'), true)),
+ 'enable_getpassword' => array('rule' => array('inList', array('0', '1', '2'), true)),
+ 'enable_loginform' => array('rule' => array('inList', array('0', '1', '2'), true)),
+ 'enable_story' => array('rule' => array('inList', array('0', '1', '2'), true)),
+ 'enable_calendar' => array('rule' => array('inList', array('0', '1', '2'), true)),
+ 'enable_links' => array('rule' => array('inList', array('0', '1', '2'), true)),
+
+ // The plugins below still don't support Invisible reCAPTCHA
+ 'enable_forum' => array('rule' => array('inList', array('0', '1'), true)),
+ 'enable_mediagallery' => array('rule' => array('inList', array('0', '1'), true)),
+ 'enable_rating' => array('rule' => array('inList', array('0', '1'), true)),
+);
diff --git a/plugins/recaptcha/functions.inc b/plugins/recaptcha/functions.inc
new file mode 100644
index 000000000..7f01d4650
--- /dev/null
+++ b/plugins/recaptcha/functions.inc
@@ -0,0 +1,675 @@
+' . $pi_name . '!';
+ }
+
+ $admin_url = $_CONF['site_admin_url'] . '/plugins/recaptcha/index.php';
+ $icon_url = plugin_geticon_recaptcha();
+
+ return array($pi_name, $admin_url, $icon_url);
+ } else {
+ return array();
+ }
+}
+
+/**
+ * Returns the administrative option for this plugin
+ *
+ * @return array Array containing (plugin name, plugin admin url, # of items in plugin or '')
+ */
+function plugin_getadminoption_recaptcha()
+{
+ global $_CONF;
+
+ if (SEC_hasRights('recaptcha.edit')) {
+ $pi_name = RECAPTCHA_str('admin');
+
+ if (!RECAPTCHA_isRecaptchaEnabled() && !RECAPTCHA_isInvisibleRecaptchaEnabled()) {
+ $pi_name = '
' . $pi_name . '! ';
+ }
+
+ $admin_url = $_CONF['site_admin_url'] . '/plugins/recaptcha/index.php';
+ $num_items = '';
+
+ return array($pi_name, $admin_url, $num_items);
+ } else {
+ return array();
+ }
+}
+
+/**
+ * Returns the version for this plugin
+ *
+ * @return string plugin version no
+ */
+function plugin_chkVersion_recaptcha()
+{
+ global $_RECAPTCHA_CONF;
+
+ return $_RECAPTCHA_CONF['pi_version'];
+}
+
+/**
+ * Upgrades the plugin
+ *
+ * @return bool true (= success)
+ */
+function plugin_upgrade_recaptcha()
+{
+ global $_TABLES, $_RECAPTCHA_CONF;
+
+ $pluginVersionInDb = DB_getItem($_TABLES['plugins'], 'pi_version', "pi_name = 'recaptcha'");
+
+ // Does upgrading
+ while (version_compare($pluginVersionInDb, $_RECAPTCHA_CONF['pi_version'], '<')) {
+ switch ($pluginVersionInDb) {
+ case '1.0.0':
+ case '1.0.1':
+ case '1.1.0':
+ case '1.1.1':
+ case '1.1.2':
+ case '1.1.3':
+ case '1.1.4':
+ case '1.1.5':
+ require_once dirname(__FILE__) . '/install_updates.php';
+ recaptcha_update_ConfValues_1_1_5();
+ $pluginVersionInDb = '1.1.6';
+ break;
+
+ case '1.1.6':
+ require_once dirname(__FILE__) . '/install_updates.php';
+ recaptcha_update_ConfValues_1_1_6();
+ $pluginVersionInDb = '1.2.0';
+ break;
+
+ default:
+ $pluginVersionInDb = $_RECAPTCHA_CONF['pi_version'];
+ break;
+ }
+ }
+
+ // Updates plugin info
+ $sql = "UPDATE {$_TABLES['plugins']} SET pi_version = '{$_RECAPTCHA_CONF['pi_version']}' "
+ . "WHERE (pi_name = 'recaptcha') ";
+ DB_query($sql);
+ COM_errorLog("reCAPTCHA plugin was successfully updated to version {$_RECAPTCHA_CONF['pi_version']}.");
+
+ return true;
+}
+
+/**
+ * Automatic uninstall function for plugins
+ *
+ * @return array
+ */
+function plugin_autouninstall_recaptcha()
+{
+ global $_RECAPTCHA_CONF;
+
+ return array(
+ 'tables' => array(),
+ 'groups' => array('reCAPTCHA Admin'),
+ 'features' => $_RECAPTCHA_CONF['FEATURES'],
+ 'php_blocks' => array(),
+ 'vars' => array(),
+ );
+}
+
+/**
+ * Return the URL to a given document
+ *
+ * @return string
+ */
+function plugin_getdocumentationurl_recaptcha($file)
+{
+ global $_CONF;
+
+ $lang = COM_getLanguageName();
+ $path = $_CONF['path_html'] . 'admin/plugins/recaptcha/docs/' . $lang . '/' . $file . '.html';
+ clearstatcache();
+
+ if (!file_exists($path)) {
+ $lang = 'english';
+ }
+
+ $retval = $_CONF['site_admin_url'] . '/plugins/recaptcha/docs/' . $lang . '/' . $file . '.html';
+
+ return $retval;
+}
+
+/**
+ * Provides text for a Configuration tooltip
+ *
+ * @param string $id Id of config value
+ * @return mixed Text to use regular tooltip, null to use config tooltip hack, or empty string
+ * when not available
+ */
+function plugin_getconfigtooltip_recaptcha($id)
+{
+ // Use config tooltip hack where tooltip is read from the config documentation
+ return null;
+}
+
+/**
+ * Callback function to add HTML text for reCAPTCHA
+ *
+ * @param string $type
+ * @param Template $template a reference to a Template class object
+ */
+function plugin_templatesetvars_recaptcha($type, &$template)
+{
+ global $_RECAPTCHA_CONF, $_SCRIPTS;
+
+ if (RECAPTCHA_requireCaptcha($type)) {
+ $isInvisible = ($_RECAPTCHA_CONF['enable_' . $type] == 2);
+
+ if ($isInvisible) {
+ $formId = RECAPTCHA_getFormId($type);
+ $code = <<
setJavaScript($code, false, false);
+ }
+
+ $_SCRIPTS->setJavaScriptFile(
+ 'recaptcha',
+ 'https://www.google.com/recaptcha/api.js?hl=' . RECAPTCHA_getLangCode(),
+ true
+ );
+
+ if ($isInvisible) {
+ // Invisible reCAPTCHA
+ $template->set_var(
+ 'invisible_recaptcha',
+ sprintf(' data-sitekey="%s" data-callback="%s"', $_RECAPTCHA_CONF['invisible_site_key'], 'onFormSubmit')
+ );
+ $template->set_var('captcha', '');
+ } else {
+ // reCAPTCHA v2
+ $template->set_var('invisible_recaptcha', '');
+ $captcha = '
';
+ $template->set_var('captcha', $captcha);
+ }
+ }
+
+}
+
+/**
+ * Callback function to check the code entered by a user
+ *
+ * @param int $uid (not used in this function)
+ * @param string $title (not used in this function)
+ * @param string $comment (not used in this function)
+ * @param string $sid (not used in this function)
+ * @param int $pid (not used in this function)
+ * @param string $type (not used in this function)
+ * @param string $postMode (not used in this function)
+ * @return string empty = success
+ */
+function plugin_commentPreSave_recaptcha($uid, $title, $comment, $sid, $pid, $type, $postMode)
+{
+ return plugin_itemPreSave_recaptcha('comment', '');
+}
+
+/**
+ * Callback function to check the code entered by a user
+ *
+ * @param string $type item type
+ * @param string $content
+ * @return string empty = success
+ */
+function plugin_itemPreSave_recaptcha($type, $content = '')
+{
+ global $_RECAPTCHA_CONF;
+
+ $msg = '';
+
+ if (RECAPTCHA_requireCaptcha($type)) {
+ if ($_RECAPTCHA_CONF['enable_' . $type] == 1) {
+ $secretKey = $_RECAPTCHA_CONF['secret_key'];
+ } else {
+ $secretKey = $_RECAPTCHA_CONF['invisible_secret_key'];
+ }
+
+ if (is_callable('curl_init')) {
+ $recaptcha = new \ReCaptcha\ReCaptcha($secretKey, new \ReCaptcha\RequestMethod\CurlPost());
+ } elseif (@ini_get('allow_url_fopen')) {
+ $recaptcha = new \ReCaptcha\ReCaptcha($secretKey, new \ReCaptcha\RequestMethod\Post());
+ } else {
+ $recaptcha = new \ReCaptcha\ReCaptcha($secretKey, new \ReCaptcha\RequestMethod\SocketPost());
+ }
+
+ $resp = $recaptcha->verify(@$_POST['g-recaptcha-response'], RECAPTCHA_getIP());
+
+ if (!$resp->isSuccess()) {
+ $msg = implode(', ', $resp->getErrorCodes());
+
+ if ($_RECAPTCHA_CONF['logging']) {
+ $entry = sprintf(
+ RECAPTCHA_str('entry_error', true),
+ $type,
+ $_SERVER['REMOTE_ADDR'],
+ $msg
+ );
+ $entry = RECAPTCHA_esc($entry);
+ RECAPTCHA_errorLog($entry);
+ }
+ }
+ }
+
+ return $msg;
+}
+
+/**
+ * Writes an entry into a log file
+ *
+ * @param string $logEntry
+ * @param int $override
+ */
+function RECAPTCHA_errorLog($logEntry, $override = 0)
+{
+ global $_CONF, $_RECAPTCHA_CONF;
+
+ if (!isset($_RECAPTCHA_CONF['logging'])) {
+ $_RECAPTCHA_CONF['logging'] = 0;
+ }
+
+ if (($_RECAPTCHA_CONF['logging'] != 1) && ($override == 0)) {
+ return;
+ }
+
+ if (!empty($logEntry)) {
+ $timestamp = date('Y-m-d H:i:s');
+ $logfile = $_CONF['path_log'] . 'recaptcha.log';
+ $entry = "{$timestamp} - {$logEntry} " . PHP_EOL;
+ $isSuccess = false;
+
+ for ($i = 0; $i < 10; $i++) {
+ $isSuccess = (@file_put_contents($logfile, $entry, FILE_APPEND | LOCK_EX) !== false);
+
+ if ($isSuccess) {
+ break;
+ }
+ }
+
+ if (!$isSuccess) {
+ COM_errorLog(__FUNCTION__ . ': cannot open "' . $logfile . '"');
+ }
+ }
+}
+
+/**
+ * Loads config info with config.class.php
+ */
+function RECAPTCHA_loadConfig()
+{
+ global $_RECAPTCHA_CONF, $_RECAPTCHA_DEFAULT, $_TABLES;
+
+ $config = config::get_instance();
+
+ if ($config->group_exists('recaptcha')) {
+ $_RECAPTCHA_CONF = array_merge($_RECAPTCHA_CONF, $config->get_config('recaptcha'));
+ } else {
+ COM_errorLog(__FUNCTION__ . ': cannot load configuration. Using default settings instead');
+ require_once __DIR__ . '/install_defaults.php';
+ $_RECAPTCHA_CONF = $_RECAPTCHA_DEFAULT;
+ }
+
+ // Silently update the plugin
+ $pi_version = DB_getItem($_TABLES['plugins'], 'pi_version', "pi_name = 'recaptcha'");
+
+ if (version_compare($pi_version, $_RECAPTCHA_CONF['pi_version'], '<')) {
+ plugin_upgrade_recaptcha();
+ }
+}
+
+/**
+ * Returns a string escaped for HTML output
+ *
+ * @param string $str
+ * @return string
+ */
+function RECAPTCHA_esc($str)
+{
+ global $_CONF;
+
+ static $encoding = null;
+
+ if ($encoding === null) {
+ $encoding = is_callable('COM_getCharset')
+ ? COM_getCharset()
+ : $_CONF['default_charset'];
+ }
+
+ if (version_compare(PHP_VERSION, '5.2.3') >= 0) {
+ return htmlspecialchars($str, ENT_QUOTES, $encoding, false);
+ } else {
+ return str_replace(
+ array('&&', '&<', '&>', '&"', '&''),
+ array('&', '<:', '>', '"', '''),
+ htmlspecialchars($str, ENT_QUOTES, $encoding)
+ );
+ }
+}
+
+/**
+ * Return a lang var
+ *
+ * @param string $index
+ * @param bool $noEsc
+ * @return string
+ */
+function RECAPTCHA_str($index, $noEsc = false)
+{
+ global $LANG_RECAPTCHA;
+
+ if (isset($LANG_RECAPTCHA[$index])) {
+ return $noEsc ? $LANG_RECAPTCHA[$index] : RECAPTCHA_esc($LANG_RECAPTCHA[$index]);
+ } else {
+ COM_errorLog(__FUNCTION__ . ': undefined index: "' . $index . '"');
+
+ return '(undefined)';
+ }
+}
+
+/**
+ * Returns if the current type of item requires reCAPTCHA
+ *
+ * @param string $type item type
+ * @return bool true = requires reCAPTCHA
+ */
+function RECAPTCHA_requireCaptcha($type)
+{
+ global $_RECAPTCHA_CONF, $_USER;
+
+ // This item is not supported
+ if (!in_array($type, $_RECAPTCHA_CONF['supported_items'])) {
+ return false;
+ }
+
+ switch ($_RECAPTCHA_CONF['enable_' . $type]) {
+ case 0:
+ // Disabled for this item
+ return false;
+
+ case 1:
+ // reCAPTCHA v2 enabled
+ if (!RECAPTCHA_isRecaptchaEnabled()) {
+ return false;
+ }
+ break;
+
+ case 2:
+ // Invisible reCAPTCHA enabled
+ if (!RECAPTCHA_isInvisibleRecaptchaEnabled()) {
+ return false;
+ }
+ break;
+
+ }
+
+ if (!isset($_USER['uid'])) {
+ $_USER['uid'] = 1;
+ }
+
+ if (($_RECAPTCHA_CONF['anonymous_only'] && ($_USER['uid'] < 2)) ||
+ ($_RECAPTCHA_CONF['anonymous_only'] == 0) ||
+ (($_RECAPTCHA_CONF['remoteusers'] == 1) && SEC_inGroup('Remote Users'))) {
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Returns if reCAPTCHA keys are set
+ *
+ * @return bool true = OK
+ */
+function RECAPTCHA_isRecaptchaEnabled()
+{
+ global $_RECAPTCHA_CONF;
+
+ return ($_RECAPTCHA_CONF['secret_key'] !== '') && ($_RECAPTCHA_CONF['site_key'] !== '');
+}
+
+/**
+ * Returns if Invisible reCAPTCHA keys are set
+ *
+ * @return bool true = OK
+ */
+function RECAPTCHA_isInvisibleRecaptchaEnabled()
+{
+ global $_RECAPTCHA_CONF;
+
+ return ($_RECAPTCHA_CONF['invisible_site_key'] !== '') && ($_RECAPTCHA_CONF['invisible_secret_key'] !== '');
+}
+
+/**
+ * Return language codes used by Google
+ *
+ * @return string
+ * @link https://developers.google.com/recaptcha/docs/language
+ */
+function RECAPTCHA_getLangCode()
+{
+ $mapping = array(
+ // GL language name => Google language code
+ 'afrikaans' => 'af',
+ 'bosnian' => 'en', // Not supported by Google
+ 'bulgarian' => 'bg',
+ 'catalan' => 'ca',
+ 'chinese_simplified' => 'zh-CN',
+ 'chinese_traditional' => 'zh-TW',
+ 'croatian' => 'hr',
+ 'czech' => 'cs',
+ 'danish' => 'da',
+ 'dutch' => 'nl',
+ 'english' => 'en',
+ 'estonian' => 'et',
+ 'farsi' => 'fa',
+ 'finnish' => 'fi',
+ 'french_canada' => 'fr-CA',
+ 'french_france' => 'fr',
+ 'german' => 'de',
+ 'german_formal' => 'de',
+ 'hebrew' => 'iw',
+ 'hellenic' => 'el',
+ 'indonesian' => 'id',
+ 'italian' => 'it',
+ 'japanese' => 'ja',
+ 'korean' => 'ko',
+ 'norwegian' => 'no',
+ 'polish' => 'pl',
+ 'portuguese' => 'pt',
+ 'portuguese_brazil' => 'pt-BR',
+ 'romanian' => 'ro',
+ 'russian' => 'ru',
+ 'serbian' => 'sr',
+ 'slovak' => 'sk',
+ 'slovenian' => 'sl',
+ 'spanish' => 'es',
+ 'spanish_argentina' => 'es-419',
+ 'swedish' => 'sv',
+ 'turkish' => 'tr',
+ 'ukrainian' => 'uk',
+ 'ukrainian_koi8-u' => 'uk',
+ );
+
+ $langName = COM_getLanguage();
+ $langName = strtolower($langName);
+ $langName = str_replace('_utf-8', '', $langName);
+
+ return isset($mapping[$langName]) ? $mapping[$langName] : 'en';
+}
+
+/**
+ * Return IP address
+ *
+ * @return string
+ */
+function RECAPTCHA_getIP()
+{
+ if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
+ $ip = $_SERVER['HTTP_CLIENT_IP'];
+ } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
+ $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
+ } else {
+ $ip = $_SERVER['REMOTE_ADDR'];
+ }
+
+ return $ip;
+}
+
+/**
+ * Return the form id to which the user attaches Invisible reCAPTCHA
+ *
+ * @param string $type
+ * @return string
+ */
+function RECAPTCHA_getFormId($type) {
+ switch ($type) {
+ case 'comment':
+ $formId = 'commentform';
+ break;
+
+ case 'story':
+ $formId = 'submitstory';
+ break;
+
+ case 'registration':
+ $formId = 'registrationform';
+ break;
+
+ case 'loginform':
+ $formId = 'userloginform';
+ break;
+
+ case 'getpassword':
+ $formId = 'getpasswordform';
+ break;
+
+ case 'contact':
+ $formId = 'contactuserform';
+ break;
+
+ case 'emailstory':
+ $formId = 'contactauthorform';
+ break;
+
+ case 'links':
+ $formId = 'submitlink';
+ break;
+
+ case 'calendar':
+ $formId = 'submit_event_form';
+ break;
+
+ case 'forum':
+ $formId = '';
+ break;
+
+ case 'rating':
+ $formId = '';
+ break;
+
+ case 'mediagallery':
+ $formId = '';
+ break;
+
+ default:
+ $formId = '';
+ }
+
+ return $formId;
+}
diff --git a/plugins/recaptcha/install_defaults.php b/plugins/recaptcha/install_defaults.php
new file mode 100644
index 000000000..d97f8011b
--- /dev/null
+++ b/plugins/recaptcha/install_defaults.php
@@ -0,0 +1,146 @@
+ '',
+ 'secret_key' => '',
+ 'invisible_site_key' => '',
+ 'invisible_secret_key' => '',
+
+ 'logging' => 0,
+ 'anonymous_only' => 0,
+ 'remoteusers' => 0,
+
+ // 0 = disabled, 1 = reCAPTCHA v2, 2 = Invisible reCAPTCHA
+ 'enable_comment' => 1,
+ 'enable_contact' => 1,
+ 'enable_emailstory' => 1,
+ 'enable_forum' => 1,
+ 'enable_registration' => 1,
+ 'enable_loginform' => 1,
+ 'enable_getpassword' => 1,
+ 'enable_mediagallery' => 1,
+ 'enable_rating' => 1,
+ 'enable_story' => 1,
+ 'enable_calendar' => 1,
+ 'enable_links' => 1,
+);
+
+/**
+ * Initializes reCAPTCHA plugin configuration
+ *
+ * Creates the database entries for the configuration if they don't already
+ * exist. Initial values will be taken from $_RECAPTCHA_DEFAULT
+ * if available (e.g. from an old config.php), uses $_RECAPTCHA_DEFAULT
+ * otherwise.
+ *
+ * @return bool true: success, false: an error occurred
+ */
+function plugin_initconfig_recaptcha()
+{
+ global $_RECAPTCHA_DEFAULT;
+
+ $c = config::get_instance();
+ $me = 'recaptcha';
+ $so = 0;
+ $sg = 0;
+ $fs = 0;
+ $tab = 0;
+
+ if (!$c->group_exists($me)) {
+ // Subgroup = 0
+ $c->add('sg_main', null, 'subgroup', $sg, $fs, null, $so, true, $me, $tab);
+ $c->add('tab_general', null, 'tab', $sg, $fs, null, $so, true, $me, $tab);
+
+ // Subgroup = 0, Fieldset = 0, Tab = 0
+ $c->add('fs_system', null, 'fieldset', $sg, $fs, null, 0, true, $me, $tab);
+ $so += 10;
+ $c->add('site_key', $_RECAPTCHA_DEFAULT['site_key'], 'text', $sg, $fs, null, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('secret_key', $_RECAPTCHA_DEFAULT['secret_key'], 'text', $sg, $fs, null, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('invisible_site_key', $_RECAPTCHA_DEFAULT['inbisible_site_key'], 'text', $sg, $fs, null, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('invisible_secret_key', $_RECAPTCHA_DEFAULT['invisible_secret_key'], 'text', $sg, $fs, null, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('logging', $_RECAPTCHA_DEFAULT['logging'], 'select', $sg, $fs, 0, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('anonymous_only', $_RECAPTCHA_DEFAULT['anonymous_only'], 'select', $sg, $fs, 0, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('remoteusers', $_RECAPTCHA_DEFAULT['remoteusers'], 'select', $sg, $fs, 0, $so, true, $me, $tab);
+ $so += 10;
+
+ // Subgroup = 0, Fieldset = 0, Tab = 1
+ $tab++;
+ $c->add('tab_integration', null, 'tab', $sg, $fs, null, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('fs_integration', null, 'fieldset', $sg, $fs, null, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('enable_comment', $_RECAPTCHA_DEFAULT['enable_comment'], 'select', $sg, $fs, 2, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('enable_contact', $_RECAPTCHA_DEFAULT['enable_contact'], 'select', $sg, $fs, 2, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('enable_emailstory', $_RECAPTCHA_DEFAULT['enable_emailstory'], 'select', $sg, $fs, 2, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('enable_forum', $_RECAPTCHA_DEFAULT['enable_forum'], 'select', $sg, $fs, 2, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('enable_registration', $_RECAPTCHA_DEFAULT['enable_registration'], 'select', $sg, $fs, 2, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('enable_getpassword', $_RECAPTCHA_DEFAULT['enable_getpassword'], 'select', $sg, $fs, 2, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('enable_loginform', $_RECAPTCHA_DEFAULT['enable_loginform'], 'select', $sg, $fs, 2, $so, true, $me, $tab);
+ $c->add('enable_mediagallery', $_RECAPTCHA_DEFAULT['enable_mediagallery'], 'select', $sg, $fs, 2, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('enable_rating', $_RECAPTCHA_DEFAULT['enable_rating'], 'select', $sg, $fs, 2, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('enable_story', $_RECAPTCHA_DEFAULT['enable_story'], 'select', $sg, $fs, 2, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('enable_calendar', $_RECAPTCHA_DEFAULT['enable_calendar'], 'select', $sg, $fs, 2, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('enable_links', $_RECAPTCHA_DEFAULT['enable_links'], 'select', $sg, $fs, 2, $so, true, $me, $tab);
+ }
+
+ return true;
+}
diff --git a/plugins/recaptcha/install_updates.php b/plugins/recaptcha/install_updates.php
new file mode 100644
index 000000000..86e5ba2d3
--- /dev/null
+++ b/plugins/recaptcha/install_updates.php
@@ -0,0 +1,130 @@
+add('enable_getpassword', $_RECAPTCHA_DEFAULT['enable_getpassword'], 'select', $sg, $fs, 0, $so, true, $me, 0);
+ $so += 10;
+ $c->add('enable_loginform', $_RECAPTCHA_DEFAULT['enable_loginform'], 'select', $sg, $fs, 0, $so, true, $me, 0);
+
+ return true;
+}
+
+/**
+ * Update Configuration settings for reCAPTCHA plugin v1.1.6
+ *
+ * @return bool true on success, false otherwise
+ */
+function recaptcha_update_ConfValues_1_1_6()
+{
+ global $_RECAPTCHA_CONF, $_RECAPTCHA_DEFAULT, $_TABLES;
+
+ // Delete old configuration values
+ $sql = "DELETE FROM {$_TABLES['conf_values']} WHERE group_name = 'recaptcha'";
+ DB_query($sql);
+
+ $c = config::get_instance();
+ $me = 'recaptcha';
+ $so = 0;
+ $sg = 0;
+ $fs = 0;
+ $tab = 0;
+
+ // Subgroup = 0
+ $c->add('sg_main', null, 'subgroup', $sg, $fs, null, $so, true, $me, $tab);
+ $c->add('tab_general', null, 'tab', $sg, $fs, null, $so, true, $me, $tab);
+
+ // Subgroup = 0, Fieldset = 0, Tab = 0
+ $c->add('fs_system', null, 'fieldset', $sg, $fs, null, 0, true, $me, $tab);
+ $so += 10;
+ $c->add('site_key', $_RECAPTCHA_CONF['public_key'], 'text', $sg, $fs, null, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('secret_key', $_RECAPTCHA_CONF['secret_key'], 'text', $sg, $fs, null, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('invisible_site_key', '', 'text', $sg, $fs, null, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('invisible_secret_key', '', 'text', $sg, $fs, null, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('logging', $_RECAPTCHA_CONF['logging'], 'select', $sg, $fs, 0, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('anonymous_only', $_RECAPTCHA_CONF['anonymous_only'], 'select', $sg, $fs, 0, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('remoteusers', $_RECAPTCHA_CONF['remoteusers'], 'select', $sg, $fs, 0, $so, true, $me, $tab);
+ $so += 10;
+
+ // Subgroup = 0, Fieldset = 0, Tab = 1
+ $tab++;
+ $c->add('tab_integration', null, 'tab', $sg, $fs, null, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('fs_integration', null, 'fieldset', $sg, $fs, null, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('enable_comment', $_RECAPTCHA_CONF['enable_comment'], 'select', $sg, $fs, 2, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('enable_contact', $_RECAPTCHA_CONF['enable_contact'], 'select', $sg, $fs, 2, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('enable_emailstory', $_RECAPTCHA_CONF['enable_emailstory'], 'select', $sg, $fs, 2, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('enable_forum', $_RECAPTCHA_CONF['enable_forum'], 'select', $sg, $fs, 2, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('enable_registration', $_RECAPTCHA_CONF['enable_registration'], 'select', $sg, $fs, 2, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('enable_getpassword', $_RECAPTCHA_CONF['enable_getpassword'], 'select', $sg, $fs, 2, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('enable_loginform', $_RECAPTCHA_CONF['enable_loginform'], 'select', $sg, $fs, 2, $so, true, $me, $tab);
+ $c->add('enable_mediagallery', $_RECAPTCHA_CONF['enable_mediagallery'], 'select', $sg, $fs, 2, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('enable_rating', $_RECAPTCHA_CONF['enable_rating'], 'select', $sg, $fs, 2, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('enable_story', $_RECAPTCHA_CONF['enable_story'], 'select', $sg, $fs, 2, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('enable_calendar', $_RECAPTCHA_CONF['enable_calendar'], 'select', $sg, $fs, 2, $so, true, $me, $tab);
+ $so += 10;
+ $c->add('enable_links', $_RECAPTCHA_CONF['enable_links'], 'select', $sg, $fs, 2, $so, true, $me, $tab);
+
+ return true;
+}
diff --git a/plugins/recaptcha/language/english.php b/plugins/recaptcha/language/english.php
new file mode 100644
index 000000000..dbf6f8e06
--- /dev/null
+++ b/plugins/recaptcha/language/english.php
@@ -0,0 +1,88 @@
+ 'reCAPTCHA',
+ 'admin' => 'reCAPTCHA',
+ 'entry_error' => 'An invalid reCAPTCHA string was entered in %1s - IP Address: %2s - Error Codes: %3s', // %1s = $type, %2s = $ip, %3s = $errorCode
+);
+
+// Localization of the Admin Configuration UI
+$LANG_configsections['recaptcha'] = array(
+ 'label' => 'reCAPTCHA',
+ 'title' => 'reCAPTCHA Configuration',
+);
+
+$LANG_confignames['recaptcha'] = array(
+ 'site_key' => 'reCAPTCHA v2 Site Key',
+ 'secret_key' => 'reCAPTCHA v2 Secret Key',
+ 'invisible_site_key' => 'Invisible reCAPTCHA Site Key',
+ 'invisible_secret_key' => 'Invisible reCAPTCHA Secret Key',
+ 'logging' => 'Log invalid reCAPTCHA attempts',
+ 'anonymous_only' => 'Anonymous Only',
+ 'remoteusers' => 'Force reCAPTCHA for all Remote Users',
+ 'enable_comment' => 'Enable Comment Support',
+ 'enable_contact' => 'Enable Contact Support',
+ 'enable_emailstory' => 'Enable Email Story Support',
+ 'enable_forum' => 'Enable Forum Support',
+ 'enable_registration' => 'Enable Registration Support',
+ 'enable_loginform' => 'Enable Login Form Support',
+ 'enable_getpassword' => 'Enable Get Password Form Support',
+ 'enable_mediagallery' => 'Enable Media Gallery (Postcards) Support',
+ 'enable_rating' => 'Enable Rating Plugin Support',
+ 'enable_story' => 'Enable Story Support',
+ 'enable_calendar' => 'Enable Calendar Plugin Support',
+ 'enable_links' => 'Enable Links Plugin Support',
+);
+
+$LANG_configsubgroups['recaptcha'] = array(
+ 'sg_main' => 'Main Settings',
+);
+
+$LANG_tab['recaptcha'] = array(
+ 'tab_general' => 'reCAPTCHA Settings',
+ 'tab_integration' => 'Geeklog Integration',
+);
+
+$LANG_fs['recaptcha'] = array(
+ 'fs_system' => 'System',
+ 'fs_location' => 'Where to use reCAPTCHA',
+);
+
+// Note: entries 0, 1, 9, and 12 are the same as in $LANG_configselects['Core']
+$LANG_configselects['recaptcha'] = array(
+ 0 => array('Yes' => 1, 'No' => 0),
+ 2 => array('Disabled' => 0, 'reCAPTCHA v2' => 1, 'Invisible reCAPTCHA' => 2),
+);
diff --git a/plugins/recaptcha/language/french_france_utf-8.php b/plugins/recaptcha/language/french_france_utf-8.php
new file mode 100644
index 000000000..35beb41d6
--- /dev/null
+++ b/plugins/recaptcha/language/french_france_utf-8.php
@@ -0,0 +1,88 @@
+ 'reCAPTCHA',
+ 'admin' => 'reCAPTCHA',
+ 'entry_error' => 'An invalid reCAPTCHA string was entered in %1s - IP Address: %2s - Error Codes: %3s', // %1s = $type, %2s = $ip, %3s = $errorCode
+);
+
+// Localization of the Admin Configuration UI
+$LANG_configsections['recaptcha'] = array(
+ 'label' => 'reCAPTCHA',
+ 'title' => 'reCAPTCHA Configuration',
+);
+
+$LANG_confignames['recaptcha'] = array(
+ 'site_key' => 'reCAPTCHA v2 Site Key',
+ 'secret_key' => 'reCAPTCHA v2 Secret Key',
+ 'invisible_site_key' => 'Invisible reCAPTCHA Site Key',
+ 'invisible_secret_key' => 'Invisible reCAPTCHA Secret Key',
+ 'logging' => 'Log invalid reCAPTCHA attempts',
+ 'anonymous_only' => 'Anonymous Only',
+ 'remoteusers' => 'Force CAPTCHA for all Remote Users',
+ 'enable_comment' => 'Enable Comment Support',
+ 'enable_contact' => 'Enable Contact Support',
+ 'enable_emailstory' => 'Enable Email Story Support',
+ 'enable_forum' => 'Enable Forum Support',
+ 'enable_registration' => 'Enable Registration Support',
+ 'enable_loginform' => 'Enable Login Form Support',
+ 'enable_getpassword' => 'Enable Get Password Form Support',
+ 'enable_mediagallery' => 'Enable Media Gallery (Postcards) Support',
+ 'enable_rating' => 'Enable Rating Plugin Support',
+ 'enable_story' => 'Enable Story Support',
+ 'enable_calendar' => 'Enable Calendar Plugin Support',
+ 'enable_links' => 'Enable Links Plugin Support',
+);
+
+$LANG_configsubgroups['recaptcha'] = array(
+ 'sg_main' => 'Main Settings',
+);
+
+$LANG_tab['recaptcha'] = array(
+ 'tab_general' => 'reCAPTCHA Settings',
+ 'tab_integration' => 'Geeklog Integration',
+);
+
+$LANG_fs['recaptcha'] = array(
+ 'fs_system' => 'System',
+ 'fs_location' => 'Where to use reCAPTCHA',
+);
+
+// Note: entries 0, 1, 9, and 12 are the same as in $LANG_configselects['Core']
+$LANG_configselects['recaptcha'] = array(
+ 0 => array('Yes' => 1, 'No' => 0),
+ 2 => array('Disabled' => 0, 'reCAPTCHA v2' => 1, 'Invisible reCAPTCHA' => 2),
+);
diff --git a/plugins/recaptcha/language/japanese_utf-8.php b/plugins/recaptcha/language/japanese_utf-8.php
new file mode 100644
index 000000000..8175a9a12
--- /dev/null
+++ b/plugins/recaptcha/language/japanese_utf-8.php
@@ -0,0 +1,88 @@
+ 'reCAPTCHA',
+ 'admin' => 'reCAPTCHA',
+ 'entry_error' => '%1sで無効な入力を検出しました。IPアドレス: %2s エラーコード: %3s', // %1s = $type, %2s = $ip, %3s = $errorCode
+);
+
+// Localization of the Admin Configuration UI
+$LANG_configsections['recaptcha'] = array(
+ 'label' => 'reCAPTCHA',
+ 'title' => 'reCAPTCHAの設定',
+);
+
+$LANG_confignames['recaptcha'] = array(
+ 'site_key' => 'reCAPTCHA v2 Site Key',
+ 'secret_key' => 'reCAPTCHA v2 Secret Key',
+ 'invisible_site_key' => 'Invisible reCAPTCHA Site Key',
+ 'invisible_secret_key' => 'Invisible reCAPTCHA Secret Key',
+ 'logging' => '無効な入力をログファイルに記録する',
+ 'anonymous_only' => 'ゲストユーザーに対してのみ使用する',
+ 'remoteusers' => 'リモートユーザー全員に強制する',
+ 'enable_comment' => 'コメントをサポートする',
+ 'enable_contact' => 'メール送信をサポートする',
+ 'enable_emailstory' => '「記事をメールする」をサポートする',
+ 'enable_forum' => '掲示板プラグインをサポートする',
+ 'enable_registration' => 'ユーザー登録をサポートする',
+ 'enable_loginform' => 'ログインフォームをサポートする',
+ 'enable_getpassword' => 'パスワード再設定フォームをサポートする',
+ 'enable_mediagallery' => 'メディアギャラリープラグインをサポートする',
+ 'enable_rating' => 'レーティングプラグインをサポートする',
+ 'enable_story' => '記事投稿をサポートする',
+ 'enable_calendar' => 'カレンダープラグインをサポートする',
+ 'enable_links' => 'リンクプラグインをサポートする',
+);
+
+$LANG_configsubgroups['recaptcha'] = array(
+ 'sg_main' => '主要設定',
+);
+
+$LANG_tab['recaptcha'] = array(
+ 'tab_general' => 'reCAPTCHA設定',
+ 'tab_integration' => 'Geeklogへの統合',
+);
+
+$LANG_fs['recaptcha'] = array(
+ 'fs_system' => 'システム',
+ 'fs_location' => '使用箇所',
+);
+
+// Note: entries 0, 1, 9, and 12 are the same as in $LANG_configselects['Core']
+$LANG_configselects['recaptcha'] = array(
+ 0 => array('はい' => 1, 'いいえ' => 0),
+ 2 => array('無効' => 0, 'reCAPTCHA v2' => 1, 'Invisible reCAPTCHA' => 2),
+);
diff --git a/plugins/recaptcha/vendor/LICENSE b/plugins/recaptcha/vendor/LICENSE
new file mode 100644
index 000000000..f6412328f
--- /dev/null
+++ b/plugins/recaptcha/vendor/LICENSE
@@ -0,0 +1,29 @@
+Copyright 2014, Google Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/plugins/recaptcha/vendor/ReCaptcha/ReCaptcha.php b/plugins/recaptcha/vendor/ReCaptcha/ReCaptcha.php
new file mode 100644
index 000000000..c157dc9a3
--- /dev/null
+++ b/plugins/recaptcha/vendor/ReCaptcha/ReCaptcha.php
@@ -0,0 +1,98 @@
+secret = $secret;
+
+ if (!is_null($requestMethod)) {
+ $this->requestMethod = $requestMethod;
+ } else {
+ $this->requestMethod = new RequestMethod\Post();
+ }
+ }
+
+ /**
+ * Calls the reCAPTCHA siteverify API to verify whether the user passes
+ * CAPTCHA test.
+ *
+ * @param string $response The value of 'g-recaptcha-response' in the submitted form.
+ * @param string $remoteIp The end user's IP address.
+ * @return Response Response from the service.
+ */
+ public function verify($response, $remoteIp = null)
+ {
+ // Discard empty solution submissions
+ if (empty($response)) {
+ $recaptchaResponse = new Response(false, array('missing-input-response'));
+ return $recaptchaResponse;
+ }
+
+ $params = new RequestParameters($this->secret, $response, $remoteIp, self::VERSION);
+ $rawResponse = $this->requestMethod->submit($params);
+ return Response::fromJson($rawResponse);
+ }
+}
diff --git a/plugins/recaptcha/vendor/ReCaptcha/RequestMethod.php b/plugins/recaptcha/vendor/ReCaptcha/RequestMethod.php
new file mode 100644
index 000000000..fc4dde59c
--- /dev/null
+++ b/plugins/recaptcha/vendor/ReCaptcha/RequestMethod.php
@@ -0,0 +1,42 @@
+curl = $curl;
+ } else {
+ $this->curl = new Curl();
+ }
+ }
+
+ /**
+ * Submit the cURL request with the specified parameters.
+ *
+ * @param RequestParameters $params Request parameters
+ * @return string Body of the reCAPTCHA response
+ */
+ public function submit(RequestParameters $params)
+ {
+ $handle = $this->curl->init(self::SITE_VERIFY_URL);
+
+ $options = array(
+ CURLOPT_POST => true,
+ CURLOPT_POSTFIELDS => $params->toQueryString(),
+ CURLOPT_HTTPHEADER => array(
+ 'Content-Type: application/x-www-form-urlencoded'
+ ),
+ CURLINFO_HEADER_OUT => false,
+ CURLOPT_HEADER => false,
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_SSL_VERIFYPEER => true
+ );
+ $this->curl->setoptArray($handle, $options);
+
+ $response = $this->curl->exec($handle);
+ $this->curl->close($handle);
+
+ return $response;
+ }
+}
diff --git a/plugins/recaptcha/vendor/ReCaptcha/RequestMethod/Post.php b/plugins/recaptcha/vendor/ReCaptcha/RequestMethod/Post.php
new file mode 100644
index 000000000..01ab33b2d
--- /dev/null
+++ b/plugins/recaptcha/vendor/ReCaptcha/RequestMethod/Post.php
@@ -0,0 +1,70 @@
+ array(
+ 'header' => "Content-type: application/x-www-form-urlencoded\r\n",
+ 'method' => 'POST',
+ 'content' => $params->toQueryString(),
+ // Force the peer to validate (not needed in 5.6.0+, but still works)
+ 'verify_peer' => true,
+ // Force the peer validation to use www.google.com
+ $peer_key => 'www.google.com',
+ ),
+ );
+ $context = stream_context_create($options);
+ return file_get_contents(self::SITE_VERIFY_URL, false, $context);
+ }
+}
diff --git a/plugins/recaptcha/vendor/ReCaptcha/RequestMethod/Socket.php b/plugins/recaptcha/vendor/ReCaptcha/RequestMethod/Socket.php
new file mode 100644
index 000000000..f51f1239a
--- /dev/null
+++ b/plugins/recaptcha/vendor/ReCaptcha/RequestMethod/Socket.php
@@ -0,0 +1,104 @@
+handle = fsockopen($hostname, $port, $errno, $errstr, (is_null($timeout) ? ini_get("default_socket_timeout") : $timeout));
+
+ if ($this->handle != false && $errno === 0 && $errstr === '') {
+ return $this->handle;
+ }
+ return false;
+ }
+
+ /**
+ * fwrite
+ *
+ * @see http://php.net/fwrite
+ * @param string $string
+ * @param int $length
+ * @return int | bool
+ */
+ public function fwrite($string, $length = null)
+ {
+ return fwrite($this->handle, $string, (is_null($length) ? strlen($string) : $length));
+ }
+
+ /**
+ * fgets
+ *
+ * @see http://php.net/fgets
+ * @param int $length
+ * @return string
+ */
+ public function fgets($length = null)
+ {
+ return fgets($this->handle, $length);
+ }
+
+ /**
+ * feof
+ *
+ * @see http://php.net/feof
+ * @return bool
+ */
+ public function feof()
+ {
+ return feof($this->handle);
+ }
+
+ /**
+ * fclose
+ *
+ * @see http://php.net/fclose
+ * @return bool
+ */
+ public function fclose()
+ {
+ return fclose($this->handle);
+ }
+}
diff --git a/plugins/recaptcha/vendor/ReCaptcha/RequestMethod/SocketPost.php b/plugins/recaptcha/vendor/ReCaptcha/RequestMethod/SocketPost.php
new file mode 100644
index 000000000..47541215f
--- /dev/null
+++ b/plugins/recaptcha/vendor/ReCaptcha/RequestMethod/SocketPost.php
@@ -0,0 +1,121 @@
+socket = $socket;
+ } else {
+ $this->socket = new Socket();
+ }
+ }
+
+ /**
+ * Submit the POST request with the specified parameters.
+ *
+ * @param RequestParameters $params Request parameters
+ * @return string Body of the reCAPTCHA response
+ */
+ public function submit(RequestParameters $params)
+ {
+ $errno = 0;
+ $errstr = '';
+
+ if (false === $this->socket->fsockopen('ssl://' . self::RECAPTCHA_HOST, 443, $errno, $errstr, 30)) {
+ return self::BAD_REQUEST;
+ }
+
+ $content = $params->toQueryString();
+
+ $request = "POST " . self::SITE_VERIFY_PATH . " HTTP/1.1\r\n";
+ $request .= "Host: " . self::RECAPTCHA_HOST . "\r\n";
+ $request .= "Content-Type: application/x-www-form-urlencoded\r\n";
+ $request .= "Content-length: " . strlen($content) . "\r\n";
+ $request .= "Connection: close\r\n\r\n";
+ $request .= $content . "\r\n\r\n";
+
+ $this->socket->fwrite($request);
+ $response = '';
+
+ while (!$this->socket->feof()) {
+ $response .= $this->socket->fgets(4096);
+ }
+
+ $this->socket->fclose();
+
+ if (0 !== strpos($response, 'HTTP/1.1 200 OK')) {
+ return self::BAD_RESPONSE;
+ }
+
+ $parts = preg_split("#\n\s*\n#Uis", $response);
+
+ return $parts[1];
+ }
+}
diff --git a/plugins/recaptcha/vendor/ReCaptcha/RequestParameters.php b/plugins/recaptcha/vendor/ReCaptcha/RequestParameters.php
new file mode 100644
index 000000000..cb66f26cf
--- /dev/null
+++ b/plugins/recaptcha/vendor/ReCaptcha/RequestParameters.php
@@ -0,0 +1,103 @@
+secret = $secret;
+ $this->response = $response;
+ $this->remoteIp = $remoteIp;
+ $this->version = $version;
+ }
+
+ /**
+ * Array representation.
+ *
+ * @return array Array formatted parameters.
+ */
+ public function toArray()
+ {
+ $params = array('secret' => $this->secret, 'response' => $this->response);
+
+ if (!is_null($this->remoteIp)) {
+ $params['remoteip'] = $this->remoteIp;
+ }
+
+ if (!is_null($this->version)) {
+ $params['version'] = $this->version;
+ }
+
+ return $params;
+ }
+
+ /**
+ * Query string representation for HTTP request.
+ *
+ * @return string Query string formatted parameters.
+ */
+ public function toQueryString()
+ {
+ return http_build_query($this->toArray(), '', '&');
+ }
+}
diff --git a/plugins/recaptcha/vendor/ReCaptcha/Response.php b/plugins/recaptcha/vendor/ReCaptcha/Response.php
new file mode 100644
index 000000000..111df978a
--- /dev/null
+++ b/plugins/recaptcha/vendor/ReCaptcha/Response.php
@@ -0,0 +1,102 @@
+success = $success;
+ $this->errorCodes = $errorCodes;
+ }
+
+ /**
+ * Is success?
+ *
+ * @return boolean
+ */
+ public function isSuccess()
+ {
+ return $this->success;
+ }
+
+ /**
+ * Get error codes.
+ *
+ * @return array
+ */
+ public function getErrorCodes()
+ {
+ return $this->errorCodes;
+ }
+}
diff --git a/plugins/recaptcha/vendor/autoload.php b/plugins/recaptcha/vendor/autoload.php
new file mode 100644
index 000000000..5a7ee94c3
--- /dev/null
+++ b/plugins/recaptcha/vendor/autoload.php
@@ -0,0 +1,38 @@
+result = $this->_process($email, $_SERVER['REMOTE_ADDR']);
+ $this->result = $this->_process($commentAuthorEmail, $_SERVER['REMOTE_ADDR']);
return $this->result;
}
diff --git a/public_html/admin/plugins/recaptcha/docs/docstyle.css b/public_html/admin/plugins/recaptcha/docs/docstyle.css
new file mode 100644
index 000000000..58a44952d
--- /dev/null
+++ b/public_html/admin/plugins/recaptcha/docs/docstyle.css
@@ -0,0 +1,161 @@
+body {
+ margin: 1em 5%;
+ background: white;
+ color: black;
+ line-height: 1.5em;
+}
+
+h1 {
+ font-size: 1.4em;
+ border-left: solid 10px blue;
+ padding-left: 3px;
+}
+
+h2 {
+ font-size: 1.2em;
+ border-left: solid 10px blue;
+ padding-left: 3px;
+ margin-top: 30px;
+}
+
+h3 {
+ font-size: 1.0em;
+}
+
+h4 {
+ font-size: 0.8em;
+}
+
+img {
+ border: 0px;
+}
+
+p, ul, ol, li {
+ margin-top: 0.6em;
+ margin-bottom: 0.6em;
+}
+ul, ol {
+ margin-left: 0.9em;
+ padding-left: 0.9em;
+}
+
+code {
+ border: dotted 1px blue;
+ background-color: #ccffff;
+ padding: 3px;
+}
+
+table {
+ width: 100%;
+ border: solid 1px black;
+ border-collapse: collapse;
+}
+
+tr {
+ border: solid 1px black;
+}
+
+td, th {
+ vertical-align: middle;
+ padding: 4px;
+ line-height: 128%;
+ font-size: smaller;
+ border: solid 1px black;
+}
+
+th {
+ text-align: left;
+ background: silver;
+}
+
+.r2 {
+ background: rgb(240,240,240);
+}
+
+dt {
+ font-weight: bold;
+}
+
+
+.usual {
+ font-size: 100%;
+}
+
+.menu {
+ background: #dddddd;
+ color: black;
+ padding: 5px;
+}
+
+.footer {
+ font-size: 90%;
+ background: #dddddd;
+ color: black;
+ padding: 5px;
+ margin-top: 4em;
+}
+
+.comment {
+ font-size: 80%;
+}
+
+.codeheader {
+ font-family: Courier, "Courier New", monospace;
+}
+
+a:link,
+a:visited {
+ color: #2222FF;
+ background: transparent;
+}
+a:hover {
+ color: #5252FF;
+ background: transparent;
+}
+
+a:active {
+ color: #2222FF;
+ background: transparent;
+}
+
+/* this is to prevent Mozilla from applying :hover on */
+a[name] {
+ color: black;
+ background: transparent;
+}
+
+a.wikipedia {
+ text-decoration: none;
+ color: black;
+ border-bottom: 1px dotted black;
+}
+
+.geeklog {
+ background-color: yellow;
+}
+
+.public {
+ background-color: #99ff00;
+}
+
+.admin {
+ background-color: aqua;
+}
+
+.new {
+ color: white;
+ font-weight: bold;
+ background-color: #3333ff;
+}
+
+.fixed {
+ color: white;
+ font-weight: bold;
+ background-color: #ff0033;
+}
+
+.code {
+ color: white;
+ background: black;
+ padding: 5px;
+}
diff --git a/public_html/admin/plugins/recaptcha/docs/english/config.html b/public_html/admin/plugins/recaptcha/docs/english/config.html
new file mode 100644
index 000000000..a97a836ee
--- /dev/null
+++ b/public_html/admin/plugins/recaptcha/docs/english/config.html
@@ -0,0 +1,148 @@
+
+
+
+
+ Geeklog reCAPTCHA plugin - Configuration
+
+
+
+
+
+reCAPTCHA® Plugin Configuration
+
+
+
+
+
+
+
+
+
+ Variable
+ Default Value
+ Description
+
+
+ anonymous_only
+ No
+ If you set this to Yes, reCAPTCHA will be shown to anonymous users only.
+
+
+ remoteusers
+ No
+ If you set this to Yes, reCAPTCHA will be forced upon all Remote Users.
+
+
+ enable_comment
+ Yes
+ If you set this to Yes, reCAPTCHA will be enabled for comments.
+
+
+ enable_contact
+ Yes
+ If you set this to Yes, reCAPTCHA will be enabled for contact.
+
+
+ enable_emailstory
+ Yes
+ If you set this to Yes, reCAPTCHA will be enabled for emailing a story.
+
+
+ enable_forum
+ Yes
+ If you set this to Yes, reCAPTCHA will be enabled for the Forum plugin.
+
+
+ enable_registration
+ Yes
+ If you set this to Yes, reCAPTCHA will be enabled for user registration.
+
+
+ enable_mediagallery
+ Yes
+ If you set this to Yes, reCAPTCHA will be enabled for the Mediagallery plugin.
+
+
+ enable_rating
+ Yes
+ If you set this to Yes, reCAPTCHA will be enabled for the Rating plugin.
+
+
+ enable_story
+ Yes
+ If you set this to Yes, reCAPTCHA will be enabled for submitting a story.
+
+
+ enable_calendar
+ Yes
+ If you set this to Yes, reCAPTCHA will be enabled for the Calendar plugin.
+
+
+ enable_links
+ Yes
+ If you set this to Yes, reCAPTCHA will be enabled for the Links plugin.
+
+
+ enable_getpassword
+ Yes
+ If you set this to Yes, reCAPTCHA will be enabled for Forget Password Form.
+
+
+ enable_loginfotm
+ Yes
+ If you set this to Yes, reCAPTCHA will be enabled for Login Form.
+
+
+
+
+
+
+
diff --git a/public_html/admin/plugins/recaptcha/docs/english/install.html b/public_html/admin/plugins/recaptcha/docs/english/install.html
new file mode 100644
index 000000000..13249585b
--- /dev/null
+++ b/public_html/admin/plugins/recaptcha/docs/english/install.html
@@ -0,0 +1,179 @@
+
+
+
+
+
+
+ Geeklog reCAPTCHA plugin
+
+
+
+Install/Uninstall/Upgrade instruction for the Geeklog reCAPTCHA plugin
+
+What is reCAPTCHA?
+
+ReCAPTCHA® is a free anti-bot service providing powerful CAPTCHA . This
+ plugin makes it easy to use reCAPTCHA with Geeklog.
+
+System Requirements
+
+
+ Since v1.1.0, PHP-5.3.2 or later is required. Maybe PHP-5-3.0 or PHP-5.3.1
+ will do, but I am not sure.
+
+ Since v1.1.6, Geeklog 1.8.0 or newer is required.
+ Since v1.2.0, Geeklog 2.2.0 or newer is required.
+
+
+INSTALL
+
+In the following descriptions
+
+ <geeklog_dir> is the directory where the system config.php file resides
+ <admin> is the directory where the administration files reside (usually, under
+ <public_html> )
+
+
+
+
+ Uncompress the recaptcha plugin archive while in the <geeklog_dir> /plugins
+ directory. The archive will create a directory called recaptcha in the plugins directory.
+
+ Create the admin directory. Under your <admin> /plugins/ directory, create a
+ directory called recaptcha.
+
+ Change to your <geeklog_dir> /plugins/recaptcha/ directory. Copy the files in
+ the admin directory to the <admin> /plugins/recaptcha/ directory your created in
+ step 2.
+
+ Log in to your Geeklog as a root user, go to the plugin editor and click on reCAPTCHA. If the install failed,
+ examine Geeklog system errorlog for possible problems.
+
+ Important : Set up API keys. Go to the Configuration and
+ enter reCAPTCHA API Site Key and Secret Key that you can get at https://www.google.com/recaptcha/admin/create .
+ It is not until you set the API keys that you can use reCAPTCHA service.
+
+
+UNINSTALL
+
+
+ Log in to your Geeklog web site as a root user, go to the plugin editor and click on reCAPTCHA. If the unstall
+ failed, examine Geeklog system errorlog for possible problems.
+
+ Delete the two plugin directories created in the install process: <geeklog-dir> /plugins/recaptcha/ and <admin> /plugins/recaptcha/.
+
+
+
+UPGRADE
+
+
+ Log in to your Geeklog web site as a root user, go to the plugin editor and disable the reCAPTCHA plugin.
+ Uncompress the recaptcha plugin archive and upload the resulting files as you did when you installed the
+ plugin.
+
+ Go to the plugin editor and Enable the reCAPTCHA plugin. Then, upgrade the plugin.
+
+
+REVISION HISTORY
+
+
+
+ Version
+ Date(YYYY-MM-DD)
+ Description
+
+
+ 1.2.0
+ 2017-12-02
+
+
+ Added support for Invisible reCAPTCHA.
+ Requires Geeklog 2.2.0.
+
+
+
+
+ 1.1.6
+ 2017-11-27
+
+
+ Added support for Login Form.
+ Added support for Forget Password Form.
+ Added support for the demo mode introduced in Geeklog 2.2.0.
+
+
+
+
+ 1.1.5
+ 2017-04-12
+
+
+ Fixed a bug where reCAPTCHA failed to check for input when $_RECAPTCHA_CONF['logging'] is set to
+ off.
+
+
+
+
+
+ 1.1.4
+ 2017-01-18
+
+
+
+
+
+ 1.1.3
+ 2016-08-12
+
+
+ Replaced COM_siteHeader and COM_siteFooter with COM_createHTMLDocument.
+
+
+
+
+ 1.1.2
+ 2016-02-20
+
+
+ Upgraded reCAPTCHA library to v1.1.2.
+
+
+
+
+ 1.1.0
+ 2015-07-03
+
+
+ Upgraded to Google reCAPTCHA v2.
+ Added an error code to a log file(logs/recaptch.log) entry. Patch provided by Tom.
+
+
+
+
+ 1.0.1
+ 2014-01-26
+
+
+ Added a <div> tag to enclose the reCAPTCHA code. Patch provided by Tom.
+ Changed to write log entries into "logs/recaptch.log". Patch provided by Tom.
+
+
+
+
+ 1.0.0
+ 2014-01-24
+ Initial release.
+
+
+
+
+
+
+
diff --git a/public_html/admin/plugins/recaptcha/docs/japanese/config.html b/public_html/admin/plugins/recaptcha/docs/japanese/config.html
new file mode 100644
index 000000000..83cafdefe
--- /dev/null
+++ b/public_html/admin/plugins/recaptcha/docs/japanese/config.html
@@ -0,0 +1,141 @@
+
+
+
+
+ Geeklog reCAPTCHAプラグインの設定
+
+
+
+
+
+reCAPTCHA®プラグインの設定
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/public_html/admin/plugins/recaptcha/docs/japanese/install.html b/public_html/admin/plugins/recaptcha/docs/japanese/install.html
new file mode 100644
index 000000000..e5d1312ba
--- /dev/null
+++ b/public_html/admin/plugins/recaptcha/docs/japanese/install.html
@@ -0,0 +1,167 @@
+
+
+
+
+
+
+ Geeklog reCAPTCHAプラグイン
+
+
+
+Geeklog reCAPTCHAプラグインのインストール/アンインストール
+
+reCAPTCHAとは
+
+ReCAPTCHA®は強力なCAPTCHA を提供する無料の対ボットシステムです。このプラグインを使うことで、GeeklogでreCAPTCHAを簡単に利用できるようになります。
+
+
+システム要件
+
+
+ バージョン1.1.0以降、PHP-5.3.2が必要になりました。PHP-5-3.0やPHP-5.3.1でも動作すると思いますが、確認はしていません。
+
+ バージョン1.1.6以降、Geeklog 1.8.0以降が必要になりました。
+ バージョン1.2.0以降、Geeklog 2.2.0以降が必要になりました。
+
+
+インストール
+
+以下の説明で、
+
+ <geeklog_dir> は、システムのdb-config.php が存在するディレクトリ
+ <admin> は、管理者用ファイルが存在するディレクトリ(ふつうは、<public_html> ディレクトリの下)
+
+
+を表しています。
+
+
+ recaptchaプラグインのアーカイブを<geeklog_dir> /pluginsディレクトリに展開します。recaptchaという名前のディレクトリができます。
+
+ adminディレクトリを作ります。<admin> /plugins/ ディレクトリの下にrecaptchaという名前のディレクトリを作ります。
+ <geeklog_dir> /plugins/recaptcha/ ディレクトリに移動します。adminディレクトリの内容を、2.で作成した <admin> /plugins/recaptcha/ ディレクトリにコピーします。
+
+ 管理者としてログインし、プラグインエディタからインストールを実行します。失敗した場合には、エラーログ(error.log)を調べてください。
+ 重要 : APIキーを設定します。https://www.google.com/recaptcha/admin/create でサインアップして、APIキーを入手してください。取得したSite
+ KeyとSecret Keyをコンフィギュレーションで設定して初めて、reCAPTCHAを使用できるようになります 。
+
+
+
+アンインストール
+
+
+ プラグインエディタから、recaptchaプラグインをアンインストールします。
+ インストールの過程で作成した2つのディレクトリ(<geeklog-dir> /plugins/recaptcha/と<admin> /plugins/recaptcha/
+ を削除します。
+
+
+
+アップグレード
+
+
+ 管理者としてサイトにログインしてから、プラグインエディタでreCAPTCHAプラグインを無効にします。
+ インストール時と同様に、recaptchaプラグインのアーカイブを展開してからサーバーにアップロードします。
+ プラグインエディタでreCAPTCHAを有効にしてから、アップグレードします。
+
+
+更新履歴
+
+
+
+ バージョン
+ 日付(YYYY-MM-DD)
+ 説明
+
+
+ 1.2.0
+ 2017-12-02
+
+
+ Invisible reCAPTCHAをサポートしました。
+ Geeklog 2.2.0が必要になりました。
+
+
+
+
+ 1.1.6
+ 2017-11-27
+
+
+ パスワード再設定フォームをサポートしました。
+ ログインフォームをサポートしました。
+ Geeklog 2.2.0で導入されるデモモードをサポートしました。
+
+
+
+
+ 1.1.5
+ 2017-04-12
+
+
+ $_RECAPTCHA_CONF['logging']がfalseの場合に入力判定に失敗していたバグを修正しました。
+
+
+
+
+ 1.1.4
+ 2017-01-18
+
+
+
+
+
+ 1.1.3
+ 2016-08-12
+
+
+ COM_siteHeaderとCOM_siteFooterをCOM_createHTMLDocumentに置き換えました。
+
+
+
+
+ 1.1.2
+ 2016-02-20
+
+
+ reCAPTCHAのライブラリをv1.1.2にアップグレードしました。
+
+
+
+
+ 1.1.0
+ 2015-07-03
+
+
+ Google reCAPTCHA v2にアップグレードしました。
+ ログファイルの項目にエラーコードを追加しました。パッチ提供はTomさんです。
+
+
+
+
+ 1.0.1
+ 2014-01-26
+
+
+ reCAPTCHAのコードをくるむ<div>タグを追加しました。パッチ提供はTomさんです。
+ エラーログを"logs/recaptch.log"に書き込むようにしました。パッチ提供はTomさんです。
+
+
+
+
+ 1.0.0
+ 2014-01-24
+ 最初のリリースです。
+
+
+
+
+
+
+
diff --git a/public_html/admin/plugins/recaptcha/images/recaptcha.png b/public_html/admin/plugins/recaptcha/images/recaptcha.png
new file mode 100644
index 000000000..d27923202
Binary files /dev/null and b/public_html/admin/plugins/recaptcha/images/recaptcha.png differ
diff --git a/public_html/admin/plugins/recaptcha/index.php b/public_html/admin/plugins/recaptcha/index.php
new file mode 100644
index 000000000..2a399d16b
--- /dev/null
+++ b/public_html/admin/plugins/recaptcha/index.php
@@ -0,0 +1,49 @@
+
{!if allow_save}
- {lang_save}
+ {lang_save}
+
{!endif}
{lang_preview}
{!if allow_delete}
- {lang_delete}
+ {lang_delete}
+
{!endif}
{lang_cancel}
diff --git a/public_html/layout/denim/comment/commentform_advanced.thtml b/public_html/layout/denim/comment/commentform_advanced.thtml
index e496a3180..2a668fb73 100644
--- a/public_html/layout/denim/comment/commentform_advanced.thtml
+++ b/public_html/layout/denim/comment/commentform_advanced.thtml
@@ -59,11 +59,13 @@
{!if allow_save}
-
{lang_save}
+
{lang_save}
+
{!endif}
{lang_preview}
{!if allow_delete}
-
{lang_delete}
+
{lang_delete}
+
{!endif}
{lang_cancel}
diff --git a/public_html/layout/denim/profiles/contactauthorform.thtml b/public_html/layout/denim/profiles/contactauthorform.thtml
index f725ec4fb..fdf5e7588 100644
--- a/public_html/layout/denim/profiles/contactauthorform.thtml
+++ b/public_html/layout/denim/profiles/contactauthorform.thtml
@@ -34,7 +34,7 @@
- {lang_sendmessage}
+ {lang_sendmessage}
diff --git a/public_html/layout/denim/profiles/contactuserform.thtml b/public_html/layout/denim/profiles/contactuserform.thtml
index f30f059a6..12e59a12a 100644
--- a/public_html/layout/denim/profiles/contactuserform.thtml
+++ b/public_html/layout/denim/profiles/contactuserform.thtml
@@ -29,7 +29,7 @@
- {lang_submit}
+ {lang_submit}
diff --git a/public_html/layout/denim/submit/submitarticle.thtml b/public_html/layout/denim/submit/submitarticle.thtml
index df7527ab5..bb7d8f467 100644
--- a/public_html/layout/denim/submit/submitarticle.thtml
+++ b/public_html/layout/denim/submit/submitarticle.thtml
@@ -42,7 +42,10 @@