diff --git a/phpBB/adm/style/acp_captcha.html b/phpBB/adm/style/acp_captcha.html index 8a067cda66..68909e4012 100644 --- a/phpBB/adm/style/acp_captcha.html +++ b/phpBB/adm/style/acp_captcha.html @@ -25,69 +25,33 @@

{L_VISUAL_CONFIRM_REFRESH_EXPLAIN}
-
+
- -
-

{L_CAPTCHA_GD_EXPLAIN}
-
-
-
-
-

{L_CAPTCHA_GD_FOREGROUND_NOISE_EXPLAIN}
-
-
-
-
-

{L_CAPTCHA_GD_X_GRID_EXPLAIN}
-
-
-
-

{L_CAPTCHA_GD_Y_GRID_EXPLAIN}
-
-
-
-

{L_CAPTCHA_GD_WAVE_EXPLAIN}
-
- -
-
-
-

{L_CAPTCHA_GD_3D_NOISE_EXPLAIN}
-
- -
-
-
-

{L_CAPTCHA_GD_FONTS_EXPLAIN}
-
- - - -
-
- - + +
+{L_AVAILABLE_CAPTCHAS} +
+

{L_CAPTCHA_SELECT_EXPLAIN}
+
+
+
+

{L_CAPTCHA_CONFIGURE_EXPLAIN}
+
+
+
+ +
{L_PREVIEW} - -
-

{L_WARNING}

-

{L_CAPTCHA_PREVIEW_MSG}

-
- -
-

{L_CAPTCHA_PREVIEW_EXPLAIN}
-
{L_PREVIEW}width="360" height="96" width="320" height="50" id="captcha_preview" />
-
+{CAPTCHA_PREVIEW}
+
{L_SUBMIT} -   -   - +   +   {S_FORM_TOKEN}
diff --git a/phpBB/adm/style/captcha_default_acp_demo.html b/phpBB/adm/style/captcha_default_acp_demo.html new file mode 100755 index 0000000000..a714386e51 --- /dev/null +++ b/phpBB/adm/style/captcha_default_acp_demo.html @@ -0,0 +1,5 @@ + +
+

{L_CAPTCHA_PREVIEW_EXPLAIN}
+
{L_PREVIEW}
+
\ No newline at end of file diff --git a/phpBB/adm/style/captcha_gd_acp.html b/phpBB/adm/style/captcha_gd_acp.html new file mode 100755 index 0000000000..ea7a851be3 --- /dev/null +++ b/phpBB/adm/style/captcha_gd_acp.html @@ -0,0 +1,74 @@ + + + + +

{L_ACP_VC_SETTINGS}

+ +

{L_ACP_VC_SETTINGS_EXPLAIN}

+ + +
+ +
+{L_GENERAL_OPTIONS} + +
+

{L_CAPTCHA_GD_FOREGROUND_NOISE_EXPLAIN}
+
+
+
+
+

{L_CAPTCHA_GD_X_GRID_EXPLAIN}
+
+
+
+

{L_CAPTCHA_GD_Y_GRID_EXPLAIN}
+
+
+
+

{L_CAPTCHA_GD_WAVE_EXPLAIN}
+
+ +
+
+
+

{L_CAPTCHA_GD_3D_NOISE_EXPLAIN}
+
+ +
+
+
+

{L_CAPTCHA_GD_FONTS_EXPLAIN}
+
+ + + +
+
+ +
+
+ {L_PREVIEW} + +
+

{L_WARNING}

+

{L_CAPTCHA_PREVIEW_MSG}

+
+ +{CAPTCHA_PREVIEW} +
+ +
+ {L_SUBMIT} +   +   +   + + + + + {S_FORM_TOKEN} +
+
+ + diff --git a/phpBB/adm/style/captcha_recaptcha.html b/phpBB/adm/style/captcha_recaptcha.html new file mode 100644 index 0000000000..f325c3727d --- /dev/null +++ b/phpBB/adm/style/captcha_recaptcha.html @@ -0,0 +1,19 @@ + +
+ + + +
+ +{L_RECAPTCHA_NOT_AVAILABLE} + \ No newline at end of file diff --git a/phpBB/adm/style/captcha_recaptcha_acp.html b/phpBB/adm/style/captcha_recaptcha_acp.html new file mode 100644 index 0000000000..07751d1d03 --- /dev/null +++ b/phpBB/adm/style/captcha_recaptcha_acp.html @@ -0,0 +1,48 @@ + + + + +

{L_ACP_VC_SETTINGS}

+ +

{L_ACP_VC_SETTINGS_EXPLAIN}

+ + +
+ +
+{L_GENERAL_OPTIONS} + +
+

{L_RECAPTCHA_PUBLIC_EXPLAIN}
+
+
+
+

{L_RECAPTCHA_PRIVATE_EXPLAIN}
+
+
+ + +
+
+ {L_PREVIEW} + +
+

{L_WARNING}

+

{L_CAPTCHA_PREVIEW_MSG}

+
+ +{CAPTCHA_PREVIEW} +
+ +
+ {L_SUBMIT} +   +   + + + + {S_FORM_TOKEN} +
+
+ + diff --git a/phpBB/docs/CHANGELOG.html b/phpBB/docs/CHANGELOG.html index 60a0b9ddfc..9f751c701a 100644 --- a/phpBB/docs/CHANGELOG.html +++ b/phpBB/docs/CHANGELOG.html @@ -53,6 +53,7 @@
  1. Changelog
      +
    1. Changes since 3.0.5
    2. Changes since 3.0.4
    3. Changes since 3.0.3
    4. Changes since 3.0.2
    5. @@ -84,7 +85,12 @@
      -

      1.i. Changes since 3.0.4

      +

      1.i. Changes since 3.0.5

      + +
        +
      • [Feature] Backported 3.2 cpatcha plugins.
      • +
      +

      1.ii. Changes since 3.0.4

      • [Fix] Delete user entry from ban list table upon user deletion (Bug #40015 - Patch by TerraFrost)
      • @@ -173,7 +179,7 @@
      • [Sec] Only use forum id supplied for posting if global announcement detected. (Reported by nickvergessen)
      -

      1.ii. Changes since 3.0.3

      +

      1.iii. Changes since 3.0.3

      • [Fix] Allow mixed-case template directories to be inherited (Bug #36725)
      • @@ -205,7 +211,7 @@
      • [Sec] Ask for forum password if post within passworded forum quoted in private message. (Reported by nickvergessen)
      -

      1.iii. Changes since 3.0.2

      +

      1.iv. Changes since 3.0.2

      • [Fix] Correctly set topic starter if first post in topic removed (Bug #30575 - Patch by blueray2048)
      • @@ -304,7 +310,7 @@
      • [Sec Precaution] Stricter validation of the HTTP_HOST header (Thanks to Techie-Micheal et al for pointing out possible issues in derived code)
      -

      1.iv. Changes since 3.0.1

      +

      1.v. Changes since 3.0.1

      • [Fix] Ability to set permissions on non-mysql dbms (Bug #24955)
      • @@ -352,7 +358,7 @@
      • [Sec] Only allow urls gone through redirect() being used within login_box(). (thanks nookieman)
      -

      1.v. Changes since 3.0.0

      +

      1.vi Changes since 3.0.0

      • [Change] Validate birthdays (Bug #15004)
      • @@ -423,7 +429,7 @@
      • [Fix] Find and display colliding usernames correctly when converting from one database to another (Bug #23925)
      -

      1.vi. Changes since 3.0.RC8

      +

      1.vii. Changes since 3.0.RC8

      • [Fix] Cleaned usernames contain only single spaces, so "a_name" and "a__name" are treated as the same name (Bug #15634)
      • @@ -432,7 +438,7 @@
      • [Fix] Call garbage_collection() within database updater to correctly close connections (affects Oracle for example)
      -

      1.vii. Changes since 3.0.RC7

      +

      1.viii. Changes since 3.0.RC7

      • [Fix] Fixed MSSQL related bug in the update system
      • @@ -467,7 +473,7 @@
      • [Fix] No duplication of active topics (Bug #15474)
      -

      1.viii. Changes since 3.0.RC6

      +

      1.ix. Changes since 3.0.RC6

      • [Fix] Submitting language changes using acp_language (Bug #14736)
      • @@ -477,7 +483,7 @@
      • [Fix] Able to request new password (Bug #14743)
      -

      1.ix. Changes since 3.0.RC5

      +

      1.x. Changes since 3.0.RC5

      • [Feature] Removing constant PHPBB_EMBEDDED in favor of using an exit_handler(); the constant was meant to achive this more or less.
      • @@ -540,7 +546,7 @@
      • [Sec] New password hashing mechanism for storing passwords (#i42)
      -

      1.x. Changes since 3.0.RC4

      +

      1.xi. Changes since 3.0.RC4

      • [Fix] MySQL, PostgreSQL and SQLite related database fixes (Bug #13862)
      • @@ -591,7 +597,7 @@
      • [Fix] odbc_autocommit causing existing result sets to be dropped (Bug #14182)
      -

      1.xi. Changes since 3.0.RC3

      +

      1.xii. Changes since 3.0.RC3

      • [Fix] Fixing some subsilver2 and prosilver style issues
      • @@ -700,7 +706,7 @@
      -

      1.xii. Changes since 3.0.RC2

      +

      1.xiii. Changes since 3.0.RC2

      • [Fix] Re-allow searching within the memberlist
      • @@ -746,7 +752,7 @@
      -

      1.xiii. Changes since 3.0.RC1

      +

      1.xiv. Changes since 3.0.RC1

      • [Fix] (X)HTML issues within the templates (Bug #11255, #11255)
      • diff --git a/phpBB/includes/acp/acp_captcha.php b/phpBB/includes/acp/acp_captcha.php index 93505e1590..ed2ccf6ccc 100644 --- a/phpBB/includes/acp/acp_captcha.php +++ b/phpBB/includes/acp/acp_captcha.php @@ -10,6 +10,8 @@ /** * @ignore */ + + if (!defined('IN_PHPBB')) { exit; @@ -28,108 +30,119 @@ class acp_captcha global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx; $user->add_lang('acp/board'); - $captcha_vars = array( - 'captcha_gd_x_grid' => 'CAPTCHA_GD_X_GRID', - 'captcha_gd_y_grid' => 'CAPTCHA_GD_Y_GRID', - 'captcha_gd_foreground_noise' => 'CAPTCHA_GD_FOREGROUND_NOISE', - 'captcha_gd' => 'CAPTCHA_GD_PREVIEWED', - 'captcha_gd_wave' => 'CAPTCHA_GD_WAVE', - 'captcha_gd_3d_noise' => 'CAPTCHA_GD_3D_NOISE', - 'captcha_gd_fonts' => 'CAPTCHA_GD_FONTS', - ); + include($phpbb_root_path . 'includes/captcha/captcha_factory.' . $phpEx); - if (isset($_GET['demo'])) + $selected = request_var('select_captcha', $config['captcha_plugin']); + $configure = request_var('configure', false); + + // Oh, they are just here for the view + if (isset($_GET['captcha_demo'])) { - $captcha_vars = array_keys($captcha_vars); - - foreach ($captcha_vars as $captcha_var) - { - $config[$captcha_var] = (isset($_REQUEST[$captcha_var])) ? request_var($captcha_var, 0) : $config[$captcha_var]; - } - - if ($config['captcha_gd']) - { - include($phpbb_root_path . 'includes/captcha/captcha_gd.' . $phpEx); - } - else - { - include($phpbb_root_path . 'includes/captcha/captcha_non_gd.' . $phpEx); - } - - $captcha = new captcha(); - $captcha->execute(gen_rand_string(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)), time()); - exit; + $this->deliver_demo($selected); } - - $config_vars = array( - 'enable_confirm' => 'REG_ENABLE', - 'enable_post_confirm' => 'POST_ENABLE', - 'confirm_refresh' => 'CONFIRM_REFRESH', - 'captcha_gd' => 'CAPTCHA_GD', - ); - - $this->tpl_name = 'acp_captcha'; - $this->page_title = 'ACP_VC_SETTINGS'; - $form_key = 'acp_captcha'; - add_form_key($form_key); - - $submit = request_var('submit', ''); - - if ($submit && check_form_key($form_key)) + + // Delegate + if ($configure) { - $config_vars = array_keys($config_vars); - - foreach ($config_vars as $config_var) - { - set_config($config_var, request_var($config_var, '')); - } - - $captcha_vars = array_keys($captcha_vars); - - foreach ($captcha_vars as $captcha_var) - { - $value = request_var($captcha_var, 0); - if ($value >= 0) - { - set_config($captcha_var, $value); - } - } - + $config_captcha = phpbb_captcha_factory::get_instance($selected); + $config_captcha->acp_page($id, $this); add_log('admin', 'LOG_CONFIG_VISUAL'); - trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action)); - } - else if ($submit) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action)); } else { - $preview_image_src = append_sid(append_sid("{$phpbb_admin_path}index.$phpEx", "i=$id&demo=demo")); + $captchas = phpbb_captcha_factory::get_captcha_types(); + $config_vars = array( + 'enable_confirm' => 'REG_ENABLE', + 'enable_post_confirm' => 'POST_ENABLE', + 'confirm_refresh' => 'CONFIRM_REFRESH', + ); - if (@extension_loaded('gd')) + $this->tpl_name = 'acp_captcha'; + $this->page_title = 'ACP_VC_SETTINGS'; + $form_key = 'acp_captcha'; + add_form_key($form_key); + + $submit = request_var('main_submit', false); + + if ($submit && check_form_key($form_key)) { - $template->assign_var('GD', true); + $config_vars = array_keys($config_vars); + foreach ($config_vars as $config_var) + { + set_config($config_var, request_var($config_var, false)); + } + if ($selected !== $config['captcha_plugin']) + { + // sanity check + if (isset($captchas['available'][$selected])) + { + $old_captcha = phpbb_captcha_factory::get_instance($config['captcha_plugin']); + $old_captcha->uninstall(); + set_config('captcha_plugin', $selected); + $new_captcha = phpbb_captcha_factory::get_instance($config['captcha_plugin']); + $old_captcha->install(); + add_log('admin', 'LOG_CONFIG_VISUAL'); + } + else + { + trigger_error($user->lang['CAPTCHA_UNAVAILABLE'] . adm_back_link($this->u_action)); + } + } + trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action)); + } + else if ($submit) + { + trigger_error($user->lang['FORM_INVALID'] . adm_back_link()); + } + else + { + $captcha_select = ''; + foreach ($captchas['available'] as $value => $title) + { + $current = ($selected !== false && $value == $selected) ? ' selected="selected"' : ''; + $captcha_select .= ''; + } + foreach ($captchas['unavailable'] as $value => $title) + { + $current = ($selected !== false && $value == $selected) ? ' selected="selected"' : ''; + $captcha_select .= ''; + } + + $demo_captcha = phpbb_captcha_factory::get_instance($selected); + + foreach ($config_vars as $config_var => $template_var) + { + $template->assign_var($template_var, (isset($_REQUEST[$config_var])) ? request_var($config_var, '') : $config[$config_var]) ; + } + + $template->assign_vars(array( + 'CAPTCHA_PREVIEW' => $demo_captcha->get_demo_template($id), + 'CAPTCHA_SELECT' => $captcha_select, + )); } - foreach ($config_vars as $config_var => $template_var) - { - $template->assign_var($template_var, (isset($_REQUEST[$config_var])) ? request_var($config_var, '') : $config[$config_var]) ; - } - - foreach ($captcha_vars as $captcha_var => $template_var) - { - $var = (isset($_REQUEST[$captcha_var])) ? request_var($captcha_var, 0) : $config[$captcha_var]; - $template->assign_var($template_var, $var); - $preview_image_src .= "&$captcha_var=" . $var; - } - - $template->assign_vars(array( - 'CAPTCHA_PREVIEW' => $preview_image_src, - 'PREVIEW' => isset($_POST['preview']), - )); } } + + + /** + * Entry point for delivering image CAPTCHAs in the ACP. + */ + function deliver_demo($selected) + { + global $db, $user, $config; + + $captcha = phpbb_captcha_factory::get_instance($selected); + $captcha->init(CONFIRM_REG); + $captcha->execute_demo(); + garbage_collection(); + exit_handler(); + } + + + + } ?> \ No newline at end of file diff --git a/phpBB/includes/auth/auth_db.php b/phpBB/includes/auth/auth_db.php index 24d4c56614..bdafefa70b 100644 --- a/phpBB/includes/auth/auth_db.php +++ b/phpBB/includes/auth/auth_db.php @@ -81,42 +81,15 @@ function login_db(&$username, &$password) } else { - global $user; - - $sql = 'SELECT code - FROM ' . CONFIRM_TABLE . " - WHERE confirm_id = '" . $db->sql_escape($confirm_id) . "' - AND session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_type = " . CONFIRM_LOGIN; - $result = $db->sql_query($sql); - $confirm_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($confirm_row) - { - if (strcasecmp($confirm_row['code'], $confirm_code) === 0) - { - $sql = 'DELETE FROM ' . CONFIRM_TABLE . " - WHERE confirm_id = '" . $db->sql_escape($confirm_id) . "' - AND session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_type = " . CONFIRM_LOGIN; - $db->sql_query($sql); - } - else - { - return array( - 'status' => LOGIN_ERROR_ATTEMPTS, - 'error_msg' => 'CONFIRM_CODE_WRONG', - 'user_row' => $row, - ); - } - } - else + $captcha = phpbb_captcha_factory::get_instance($config['captcha_plugin']); + $captcha->init(CONFIRM_LOGIN); + $vc_response = $captcha->validate(); + if ($vc_response) { return array( - 'status' => LOGIN_ERROR_ATTEMPTS, - 'error_msg' => 'CONFIRM_CODE_WRONG', - 'user_row' => $row, + 'status' => LOGIN_ERROR_ATTEMPTS, + 'error_msg' => 'LOGIN_ERROR_ATTEMPTS', + 'user_row' => $row, ); } } diff --git a/phpBB/includes/captcha/captcha_factory.php b/phpBB/includes/captcha/captcha_factory.php new file mode 100755 index 0000000000..e6f56172ec --- /dev/null +++ b/phpBB/includes/captcha/captcha_factory.php @@ -0,0 +1,92 @@ +width; + $img_y = $this->height; + + // Generate image + $img = imagecreatetruecolor($img_x, $img_y); + $x_grid = mt_rand(6, 10); + $y_grid = mt_rand(6, 10); + + // Ok, so lets cut to the chase. We could accurately represent this in 3d and + // do all the appropriate linear transforms. my questions is... why bother? + // The computational overhead is unnecessary when you consider the simple fact: + // we're not here to accurately represent a model, but to just show off some random-ish + // polygons + + // Conceive of 3 spaces. + // 1) planar-space (discrete "pixel" grid) + // 2) 3-space. (planar-space with z/height aspect) + // 3) image space (pixels on the screen) + // resolution of the planar-space we're embedding the text code in + $plane_x = 100; + $plane_y = 30; + + $subdivision_factor = 3; + // $box is the 4 points in img_space that correspond to the corners of the plane in 3-space + $box = array( + 'upper_left' => array( + 'x' => mt_rand(5, 15), + 'y' => mt_rand(10, 15) + ), + 'upper_right' => array( + 'x' => mt_rand($img_x - 35, $img_x - 19), + 'y' => mt_rand(10, 17) + ), + 'lower_left' => array( + 'x' => mt_rand($img_x - 5, $img_x - 45), + 'y' => mt_rand($img_y - 0, $img_y - 15) + ), + ); + $box['lower_right'] = array( + 'x' => $box['lower_left']['x'] + $box['upper_left']['x'] - $box['upper_right']['x'], + 'y' => $box['lower_left']['y'] + $box['upper_left']['y'] - $box['upper_right']['y'], + ); + + + // TODO + $background = imagecolorallocate($img, mt_rand(155, 255), mt_rand(155, 255), mt_rand(155, 255)); + imagefill($img, 0, 0, $background); + $black = imagecolorallocate($img, 0, 0, 0); + + $random = array(); + $fontcolors = array(); + + for ($i = 0; $i < 15; ++$i) + { + $random[$i] = imagecolorallocate($img, mt_rand(120, 255), mt_rand(120, 255), mt_rand(120, 255)); + } + + $fontcolors[0] = imagecolorallocate($img, mt_rand(0, 120), mt_rand(0, 120), mt_rand(0, 120)); + + $colors = array(); + + $minr = mt_rand(20, 30); + $ming = mt_rand(20, 30); + $minb = mt_rand(20, 30); + + $maxr = mt_rand(150, 230); + $maxg = mt_rand(150, 230); + $maxb = mt_rand(150, 230); + + for ($i = -30; $i <= 30; ++$i) + { + $coeff1 = ($i + 12) / 45; + $coeff2 = 1 - $coeff1; + $colors[$i] = imagecolorallocate($img, ($coeff2 * $maxr) + ($coeff1 * $minr), ($coeff2 * $maxg) + ($coeff1 * $ming), ($coeff2 * $maxb) + ($coeff1 * $minb)); + } + + // $img_buffer is the last row of 3-space positions (converted to img-space), cached + // (using this means we don't need to recalculate all 4 positions for each new polygon, + // merely the newest point that we're adding, which is then cached. + $img_buffer = array(array(), array()); + + // In image-space, the x- and y-offset necessary to move one unit in the x-direction in planar-space + $dxx = ($box['upper_right']['x'] - $box['upper_left']['x']) / ($subdivision_factor * $plane_x); + $dxy = ($box['upper_right']['y'] - $box['upper_left']['y']) / ($subdivision_factor * $plane_x); + + // In image-space, the x- and y-offset necessary to move one unit in the y-direction in planar-space + $dyx = ($box['lower_right']['x'] - $box['upper_left']['x']) / ($subdivision_factor * $plane_y); + $dyy = ($box['lower_right']['y'] - $box['upper_left']['y']) / ($subdivision_factor * $plane_y); + + // Initial captcha-letter offset in planar-space + $plane_offset_x = mt_rand(3, 8); + $plane_offset_y = mt_rand( 12, 15); + + // character map + $map = $this->captcha_bitmaps(); + + // matrix + $plane = array(); + + // for each character, we'll silkscreen it into our boolean pixel plane + for ($c = 0, $code_num = strlen($code); $c < $code_num; ++$c) + { + $letter = $code[$c]; + + for ($x = $map['width'] - 1; $x >= 0; --$x) + { + for ($y = $map['height'] - 1; $y >= 0; --$y) + { + if ($map['data'][$letter][$y][$x]) + { + $plane[$y + $plane_offset_y + (($c & 1) ? 1 : -1)][$x + $plane_offset_x] = true; + } + } + } + $plane_offset_x += 11; + } + + // calculate our first buffer, we can't actually draw polys with these yet + // img_pos_prev == screen x,y location to our immediate left. + // img_pos_cur == current screen x,y location + // we calculate screen position of our + // current cell based on the difference from the previous cell + // rather than recalculating from absolute coordinates + // What we cache into the $img_buffer contains the raised text coordinates. + $img_pos_prev = $img_buffer[0][0] = array($box['upper_left']['x'], $box['upper_left']['y']); + $cur_height = $prev_height = $this->wave_height(0, 0, $subdivision_factor); + $full_x = $plane_x * $subdivision_factor; + $full_y = $plane_y * $subdivision_factor; + + for ($x = 1; $x <= $full_x; ++$x) + { + $cur_height = $this->wave_height($x, 0, $subdivision_factor); + $offset = $cur_height - $prev_height; + $img_pos_cur = array($img_pos_prev[0] + $dxx, $img_pos_prev[1] + $dxy + $offset); + + $img_buffer[0][$x] = $img_pos_cur; + $img_pos_prev = $img_pos_cur; + $prev_height = $cur_height; + } + + for ($y = 1; $y <= $full_y; ++$y) + { + // swap buffers + $buffer_cur = $y & 1; + $buffer_prev = 1 - $buffer_cur; + + $prev_height = $this->wave_height(0, $y, $subdivision_factor); + $offset = $prev_height - $this->wave_height(0, $y - 1, $subdivision_factor); + $img_pos_cur = array($img_buffer[$buffer_prev][0][0] + $dyx, min($img_buffer[$buffer_prev][0][1] + $dyy + $offset, $img_y - 1)); + + // make sure we don't try to write off the page + $img_pos_prev = $img_pos_cur; + + $img_buffer[$buffer_cur][0] = $img_pos_cur; + + for ($x = 1; $x <= $full_x; ++$x) + { + $cur_height = $this->wave_height($x, $y, $subdivision_factor) + $this->grid_height($x, $y, 1, $x_grid, $y_grid); + + // height is a z-factor, not a y-factor + $offset = $cur_height - $prev_height; + $img_pos_cur = array($img_pos_prev[0] + $dxx, $img_pos_prev[1] + $dxy + $offset); + + // height is float, index it to an int, get closest color + $color = $colors[intval($cur_height)]; + $img_pos_prev = $img_pos_cur; + $prev_height = $cur_height; + + $y_index_old = intval(($y - 1) / $subdivision_factor); + $y_index_new = intval($y / $subdivision_factor); + $x_index_old = intval(($x - 1) / $subdivision_factor); + $x_index_new = intval($x / $subdivision_factor); + + if (!empty($plane[$y_index_new][$x_index_new])) + { + $img_pos_cur[1] += $this->wave_height($x, $y, $subdivision_factor, 1) - 30 - $cur_height; + $color = $colors[20]; + } + $img_pos_cur[1] = min($img_pos_cur[1], $img_y - 1); + $img_buffer[$buffer_cur][$x] = $img_pos_cur; + + // Smooth the edges as much as possible by having not more than one low<->high traingle per square + // Otherwise, just + $diag_down = (empty($plane[$y_index_old][$x_index_old]) == empty($plane[$y_index_new][$x_index_new])); + $diag_up = (empty($plane[$y_index_old][$x_index_new]) == empty($plane[$y_index_new][$x_index_old])); + + // natural switching + $mode = ($x + $y) & 1; + + // override if it requires it + if ($diag_down != $diag_up) + { + $mode = $diag_up; + } + + if ($mode) + { + // +-/ / + // 1 |/ 2 /| + // / /-+ + $poly1 = array_merge($img_buffer[$buffer_cur][$x - 1], $img_buffer[$buffer_prev][$x - 1], $img_buffer[$buffer_prev][$x]); + $poly2 = array_merge($img_buffer[$buffer_cur][$x - 1], $img_buffer[$buffer_cur][$x], $img_buffer[$buffer_prev][$x]); + } + else + { + // \ \-+ + // 1 |\ 2 \| + // +-\ \ + $poly1 = array_merge($img_buffer[$buffer_cur][$x - 1], $img_buffer[$buffer_prev][$x - 1], $img_buffer[$buffer_cur][$x]); + $poly2 = array_merge($img_buffer[$buffer_prev][$x - 1], $img_buffer[$buffer_prev][$x], $img_buffer[$buffer_cur][$x]); + } + + imagefilledpolygon($img, $poly1, 3, $color); + imagefilledpolygon($img, $poly2, 3, $color); + } + } + + // Output image + header('Content-Type: image/png'); + header('Cache-control: no-cache, no-store'); + //$mtime = explode(' ', microtime()); + //$totaltime = $mtime[0] + $mtime[1] - $starttime; + + //echo $totaltime . "
        \n"; + //echo memory_get_usage() - $tmp; + imagepng($img); + imagedestroy($img); + } + + function wave_height($x, $y, $factor = 1, $tweak = 0.7) + { + // stretch the wave. TODO: pretty it up + $x = $x/5 + 180; + $y = $y/4; + return ((sin($x / (3 * $factor)) + sin($y / (3 * $factor))) * 10 * $tweak); + } + + function grid_height($x, $y, $factor = 1, $x_grid, $y_grid) + { + return ((!($x % ($x_grid * $factor)) || !($y % ($y_grid * $factor))) ? 3 : 0); + } + + function captcha_bitmaps() + { + return array( + 'width' => 9, + 'height' => 13, + 'data' => array( + 'A' => array( + array(0,0,1,1,1,1,0,0,0), + array(0,1,0,0,0,0,1,0,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,1,1,1,1,1,1,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'B' => array( + array(1,1,1,1,1,1,0,0,0), + array(1,0,0,0,0,0,1,0,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,1,0,0), + array(1,1,1,1,1,1,0,0,0), + array(1,0,0,0,0,0,1,0,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,1,0,0), + array(1,1,1,1,1,1,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'C' => array( + array(0,0,1,1,1,1,1,0,0), + array(0,1,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,1,0), + array(0,0,1,1,1,1,1,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'D' => array( + array(1,1,1,1,1,1,1,0,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,1,0), + array(1,1,1,1,1,1,1,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'E' => array( + array(0,0,1,1,1,1,1,1,1), + array(0,1,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,1,1,1,1,1,1,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(0,1,0,0,0,0,0,0,0), + array(0,0,1,1,1,1,1,1,1), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'F' => array( + array(0,0,1,1,1,1,1,1,0), + array(0,1,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,1,1,1,1,1,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'G' => array( + array(0,0,1,1,1,1,1,0,0), + array(0,1,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,1,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,1,0), + array(0,0,1,1,1,1,1,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'H' => array( + array(1,0,0,0,0,0,1,0,0), + array(1,0,0,0,0,0,1,0,0), + array(1,0,0,0,0,0,1,0,0), + array(1,0,0,0,0,0,1,0,0), + array(1,0,0,0,0,0,1,0,0), + array(1,1,1,1,1,1,1,0,0), + array(1,0,0,0,0,0,1,0,0), + array(1,0,0,0,0,0,1,0,0), + array(1,0,0,0,0,0,1,0,0), + array(1,0,0,0,0,0,1,0,0), + array(1,0,0,0,0,0,1,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'I' => array( + array(0,1,1,1,1,1,1,1,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,1,1,1,1,1,1,1,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'J' => array( + array(0,0,0,0,0,0,1,1,1), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,0,1), + array(0,0,1,0,0,0,0,1,0), + array(0,0,0,1,1,1,1,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'K' => array( + array(1,0,0,0,0,0,1,0,0), + array(1,0,0,0,0,1,0,0,0), + array(1,0,0,0,1,0,0,0,0), + array(1,0,0,1,0,0,0,0,0), + array(1,0,1,0,0,0,0,0,0), + array(1,1,0,0,0,0,0,0,0), + array(1,0,1,0,0,0,0,0,0), + array(1,0,0,1,0,0,0,0,0), + array(1,0,0,0,1,0,0,0,0), + array(1,0,0,0,0,1,0,0,0), + array(1,0,0,0,0,0,1,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'L' => array( + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(0,1,0,0,0,0,0,0,0), + array(0,0,1,1,1,1,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'M' => array( + array(0,1,0,0,0,0,0,1,0), + array(0,1,1,0,0,0,1,1,0), + array(0,1,0,1,0,1,0,1,0), + array(0,1,0,0,1,0,0,1,0), + array(0,1,0,0,0,0,0,1,0), + array(0,1,0,0,0,0,0,1,0), + array(0,1,0,0,0,0,0,1,0), + array(0,1,0,0,0,0,0,1,0), + array(0,1,0,0,0,0,0,1,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'N' => array( + array(1,0,0,0,0,0,0,0,1), + array(1,1,0,0,0,0,0,0,1), + array(1,0,1,0,0,0,0,0,1), + array(1,0,0,1,0,0,0,0,1), + array(1,0,0,0,1,0,0,0,1), + array(1,0,0,0,0,1,0,0,1), + array(1,0,0,0,0,0,1,0,1), + array(1,0,0,0,0,0,0,1,1), + array(1,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'O' => array( + array(0,0,0,1,1,1,0,0,0), + array(0,0,1,0,0,0,1,0,0), + array(0,1,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,1,0), + array(0,0,1,0,0,0,1,0,0), + array(0,0,0,1,1,1,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'P' => array( + array(1,1,1,1,1,1,0,0,0), + array(1,0,0,0,0,0,1,0,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,1,0,0), + array(1,1,1,1,1,1,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'Q' => array( + array(0,0,1,1,1,1,0,0,0), + array(0,1,0,0,0,0,1,0,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,1,0,0,1,0), + array(1,0,0,0,0,1,0,1,0), + array(0,1,0,0,0,0,1,0,0), + array(0,0,1,1,1,1,0,1,0), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'R' => array( + array(1,1,1,1,1,1,0,0,0), + array(1,0,0,0,0,0,1,0,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,1,0,0), + array(1,1,1,1,1,1,0,0,0), + array(1,0,1,0,0,0,0,0,0), + array(1,0,0,1,0,0,0,0,0), + array(1,0,0,0,1,0,0,0,0), + array(1,0,0,0,0,1,0,0,0), + array(1,0,0,0,0,0,1,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'S' => array( + array(0,0,1,1,1,1,1,1,1), + array(0,1,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(0,1,0,0,0,0,0,0,0), + array(0,0,1,1,1,1,1,0,0), + array(0,0,0,0,0,0,0,1,0), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,1,0), + array(1,1,1,1,1,1,1,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'T' => array( + array(1,1,1,1,1,1,1,1,1), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'U' => array( + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,1,0), + array(0,0,1,1,1,1,1,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'V' => array( + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,1,0), + array(0,0,1,0,0,0,1,0,0), + array(0,0,0,1,0,1,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'W' => array( + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,1,0,0,0,1), + array(1,0,0,1,0,1,0,0,1), + array(1,0,1,0,0,0,1,0,1), + array(1,1,0,0,0,0,0,1,1), + array(1,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'X' => array( + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,1,0), + array(0,0,1,0,0,0,1,0,0), + array(0,0,0,1,0,1,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,1,0,1,0,0,0), + array(0,0,1,0,0,0,1,0,0), + array(0,1,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'Y' => array( + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,1,0), + array(0,0,1,0,0,0,1,0,0), + array(0,0,0,1,0,1,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'Z' => array( + array(1,1,1,1,1,1,1,1,1), + array(1,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,1,0), + array(0,0,0,0,0,0,1,0,0), + array(0,0,0,0,0,1,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,1,0,0,0,0,0), + array(0,0,1,0,0,0,0,0,0), + array(0,1,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,1), + array(1,1,1,1,1,1,1,1,1), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + '1' => array( + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,1,1,0,0,0,0), + array(0,0,1,0,1,0,0,0,0), + array(0,1,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,1,1,1,1,1,1,1,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + '2' => array( + array(0,0,0,1,1,1,0,0,0), + array(0,0,1,0,0,0,1,0,0), + array(0,1,0,0,0,0,0,1,0), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,1,0), + array(0,0,0,0,0,0,1,0,0), + array(0,0,0,0,0,1,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,1,0,0,0,0,0), + array(0,0,1,0,0,0,0,0,0), + array(0,1,1,1,1,1,1,1,1), + array(0,0,0,0,0,0,0,0,0), + ), + '3' => array( + array(0,0,0,1,1,1,1,0,0), + array(0,0,1,0,0,0,0,1,0), + array(0,1,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,1,0), + array(0,0,0,0,0,1,1,0,0), + array(0,0,0,0,0,0,0,1,0), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,0,1), + array(0,0,1,0,0,0,0,1,0), + array(0,0,0,1,1,1,1,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + '4' => array( + array(0,0,0,0,0,0,0,1,0), + array(0,0,0,0,0,0,1,1,0), + array(0,0,0,0,0,1,0,1,0), + array(0,0,0,0,1,0,0,1,0), + array(0,0,0,1,0,0,0,1,0), + array(0,0,1,0,0,0,0,1,0), + array(0,1,1,1,1,1,1,1,1), + array(0,0,0,0,0,0,0,1,0), + array(0,0,0,0,0,0,0,1,0), + array(0,0,0,0,0,0,0,1,0), + array(0,0,0,0,0,0,0,1,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + '5' => array( + array(1,1,1,1,1,1,1,1,1), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(0,1,0,0,0,0,0,0,0), + array(0,0,1,1,1,1,1,0,0), + array(0,0,0,0,0,0,0,1,0), + array(0,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,1,0), + array(0,0,1,1,1,1,1,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + '6' => array( + array(0,0,1,1,1,1,1,0,0), + array(0,1,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,1,1,1,1,0,0), + array(1,0,1,0,0,0,0,1,0), + array(1,1,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,1,0), + array(0,0,1,1,1,1,1,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + '7' => array( + array(1,1,1,1,1,1,1,1,1), + array(1,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,1,0), + array(0,0,0,0,0,0,1,0,0), + array(0,0,0,0,0,1,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + '8' => array( + array(0,0,1,1,1,1,1,0,0), + array(0,1,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,1,0), + array(0,0,1,1,1,1,1,0,0), + array(0,1,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,1,0), + array(0,0,1,1,1,1,1,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + '9' => array( + array(0,0,0,1,1,1,1,0,0), + array(0,0,1,0,0,0,0,1,0), + array(0,1,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,1,1), + array(0,0,1,1,1,1,1,0,1), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,0,1), + array(0,0,1,0,0,0,0,1,0), + array(0,0,0,1,1,1,1,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + ) + ); + } +} + +?> \ No newline at end of file diff --git a/phpBB/includes/captcha/captcha_plugin.php b/phpBB/includes/captcha/captcha_plugin.php new file mode 100755 index 0000000000..08a149764c --- /dev/null +++ b/phpBB/includes/captcha/captcha_plugin.php @@ -0,0 +1,97 @@ +confirm_id = request_var('confirm_id', ''); + $this->confirm_code = request_var('confirm_code', ''); + $refresh = request_var('refresh_vc', false) && $config['confirm_refresh']; + + $this->type = (int) $type; + + if (!strlen($this->confirm_id)) + { + // we have no confirm ID, better get ready to display something + $this->generate_code(); + } + else if ($refresh) + { + $this->regenerate_code(); + } + + } + + function execute_demo() + { + global $user; + + $this->code = gen_rand_string(mt_rand(5, 8)); + $this->seed = hexdec(substr(unique_id(), 4, 10)); + + // compute $seed % 0x7fffffff + $this->seed -= 0x7fffffff * floor($this->seed / 0x7fffffff); + + $captcha = new captcha(); + $captcha->execute($this->code, $this->seed); + } + + + function execute() + { + if (empty($this->code)) + { + if (!$this->load_code()) + { + // invalid request, bail out + return false; + } + } + $captcha = new captcha(); + $captcha->execute($this->code, $this->seed); + } + + + function get_template() + { + global $config, $user, $template, $phpEx, $phpbb_root_path; + + $template->set_filenames(array( + 'captcha' => 'captcha_default.html') + ); + + $template->assign_vars(array( + 'CONFIRM_IMAGE' => append_sid($phpbb_root_path . 'ucp.' . $phpEx . '?mode=confirm&confirm_id=' . $this->confirm_id . '&type=' . $this->type), + 'CONFIRM_ID' => $this->confirm_id, + 'S_REFRESH' => (bool) $config['confirm_refresh'], + + )); + + return $template->assign_display('captcha'); + } + + function get_demo_template($id) + { + global $config, $user, $template, $phpbb_admin_path, $phpEx; + + $template->set_filenames(array( + 'captcha_demo' => 'captcha_default_acp_demo.html') + ); + // acp_captcha has a delivery function; let's use it + $template->assign_vars(array( + 'CONFIRM_IMAGE' => append_sid($phpbb_admin_path . 'index.' . $phpEx . '?captcha_demo=1&mode=visual&i=' . $id . '&select_captcha=' . $this->get_class_name()), + 'CONFIRM_ID' => $this->confirm_id, + )); + + return $template->assign_display('captcha_demo'); + } + + function get_hidden_fields() + { + $hidden_fields = array(); + + // this is required for postig.php - otherwise we would forget about the captcha being already solved + if ($this->solved) + { + $hidden_fields['confirm_code'] = $this->confirm_code; + } + $hidden_fields['confirm_id'] = $this->confirm_id; + return $hidden_fields; + } + + function garbage_collect($type) + { + global $db, $config; + + $sql = 'SELECT DISTINCT c.session_id + FROM ' . CONFIRM_TABLE . ' c + LEFT JOIN ' . SESSIONS_TABLE . ' s ON (c.session_id = s.session_id) + WHERE s.session_id IS NULL' . + ((empty($type)) ? '' : ' AND c.confirm_type = ' . (int) $type); + $result = $db->sql_query($sql); + + if ($row = $db->sql_fetchrow($result)) + { + $sql_in = array(); + do + { + $sql_in[] = (string) $row['session_id']; + } + while ($row = $db->sql_fetchrow($result)); + + if (sizeof($sql_in)) + { + $sql = 'DELETE FROM ' . CONFIRM_TABLE . ' + WHERE ' . $db->sql_in_set('session_id', $sql_in); + $db->sql_query($sql); + } + } + $db->sql_freeresult($result); + } + + function uninstall() + { + self::garbage_collect(0); + } + + function install() + { + return; + } + + function validate() + { + global $config, $db, $user; + + $this->confirm_code = request_var('confirm_code', ''); + if (!$this->confirm_id) + { + $error = $user->lang['CONFIRM_CODE_WRONG']; + } + else + { + if ($this->check_code()) + { + // $this->delete_code(); commented out to allow posting.php to repeat the question + $this->solved = true; + } + else + { + $error = $user->lang['CONFIRM_CODE_WRONG']; + } + } + + if (strlen($error)) + { + // okay, inorect answer. Let's ask a new question + $this->generate_code(); + return $error; + } + else + { + return false; + } + } + + + /** + * The old way to generate code, suitable for GD and non-GD. Resets the internal state. + */ + function generate_code() + { + global $db, $user; + + $this->code = gen_rand_string(mt_rand(5, 8)); + $this->confirm_id = md5(unique_id($user->ip)); + $this->seed = hexdec(substr(unique_id(), 4, 10)); + $this->solved = false; + // compute $seed % 0x7fffffff + $this->seed -= 0x7fffffff * floor($this->seed / 0x7fffffff); + + $sql = 'INSERT INTO ' . CONFIRM_TABLE . ' ' . $db->sql_build_array('INSERT', array( + 'confirm_id' => (string) $this->confirm_id, + 'session_id' => (string) $user->session_id, + 'confirm_type' => (int) $this->type, + 'code' => (string) $this->code, + 'seed' => (int) $this->seed) + ); + $db->sql_query($sql); + } + + /** + * New Question, if desired. + */ + function regenerate_code() + { + global $db, $user; + + $this->code = gen_rand_string(mt_rand(5, 8)); + $this->seed = hexdec(substr(unique_id(), 4, 10)); + $this->solved = false; + // compute $seed % 0x7fffffff + $this->seed -= 0x7fffffff * floor($this->seed / 0x7fffffff); + $sql = 'UPDATE ' . CONFIRM_TABLE . ' SET ' . $db->sql_build_array('UPDATE', array( + 'code' => (string) $this->code, + 'seed' => (int) $this->seed)) . ' + WHERE + confirm_id = \'' . $db->sql_escape($this->confirm_id) . '\' AND + session_id = \'' . $db->sql_escape($user->session_id) . '\''; + $db->sql_query($sql); + } + + /** + * Look up everything we need for painting&checking. + */ + function load_code() + { + global $db, $user; + $sql = 'SELECT code, seed + FROM ' . CONFIRM_TABLE . " + WHERE confirm_id = '" . $db->sql_escape($this->confirm_id) . "' + AND session_id = '" . $db->sql_escape($user->session_id) . "' + AND confirm_type = " . $this->type; + $result = $db->sql_query($sql); + $row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + if ($row) + { + $this->code = $row['code']; + $this->seed = $row['seed']; + return true; + } + return false; + + } + + function check_code() + { + global $db; + + if (empty($this->code)) + { + if (!$this->load_code()) + { + return false; + } + } + return (strcasecmp($this->code, $this->confirm_code) === 0); + } + + function delete_code() + { + global $db, $user; + + $sql = 'DELETE FROM ' . CONFIRM_TABLE . " + WHERE confirm_id = '" . $db->sql_escape($confirm_id) . "' + AND session_id = '" . $db->sql_escape($user->session_id) . "' + AND confirm_type = " . $this->type; + $db->sql_query($sql); + } + + function get_attempt_count() + { + global $db, $user; + + $sql = 'SELECT COUNT(session_id) AS attempts + FROM ' . CONFIRM_TABLE . " + WHERE session_id = '" . $db->sql_escape($user->session_id) . "' + AND confirm_type = " . $this->type; + $result = $db->sql_query($sql); + $attempts = (int) $db->sql_fetchfield('attempts'); + $db->sql_freeresult($result); + + return $attempts; + } + + + function reset() + { + global $db, $user; + + $sql = 'DELETE FROM ' . CONFIRM_TABLE . " + WHERE session_id = '" . $db->sql_escape($user->session_id) . "' + AND confirm_type = " . (int) $this->type; + $db->sql_query($sql); + + // we leave the class usable by generating a new question + $this->generate_code(); + } + +} + diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_gd_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_gd_plugin.php new file mode 100755 index 0000000000..850794e133 --- /dev/null +++ b/phpBB/includes/captcha/plugins/phpbb_captcha_gd_plugin.php @@ -0,0 +1,122 @@ +add_lang('acp/board'); + $captcha_vars = array( + 'captcha_gd_x_grid' => 'CAPTCHA_GD_X_GRID', + 'captcha_gd_y_grid' => 'CAPTCHA_GD_Y_GRID', + 'captcha_gd_foreground_noise' => 'CAPTCHA_GD_FOREGROUND_NOISE', + 'captcha_gd' => 'CAPTCHA_GD_PREVIEWED', + 'captcha_gd_wave' => 'CAPTCHA_GD_WAVE', + 'captcha_gd_3d_noise' => 'CAPTCHA_GD_3D_NOISE', + 'captcha_gd_fonts' => 'CAPTCHA_GD_FONTS', + + ); + + $config_vars = array( + 'enable_confirm' => 'REG_ENABLE', + 'enable_post_confirm' => 'POST_ENABLE', + 'confirm_refresh' => 'CONFIRM_REFRESH', + 'captcha_gd' => 'CAPTCHA_GD', + ); + + + $module->tpl_name = 'captcha_gd_acp'; + $module->page_title = 'ACP_VC_SETTINGS'; + $form_key = 'acp_captcha'; + add_form_key($form_key); + + $submit = request_var('submit', ''); + + if ($submit && check_form_key($form_key)) + { + $captcha_vars = array_keys($captcha_vars); + foreach ($captcha_vars as $captcha_var) + { + $value = request_var($captcha_var, 0); + if ($value >= 0) + { + set_config($captcha_var, $value); + } + } + trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($module->u_action)); + } + else if ($submit) + { + trigger_error($user->lang['FORM_INVALID'] . adm_back_link($module->u_action)); + } + else + { + foreach ($captcha_vars as $captcha_var => $template_var) + { + $var = (isset($_REQUEST[$captcha_var])) ? request_var($captcha_var, 0) : $config[$captcha_var]; + $template->assign_var($template_var, $var); + } + $template->assign_vars(array( + 'CAPTCHA_PREVIEW' => $this->get_demo_template($id), + 'CAPTCHA_NAME' => $this->get_class_name(), + )); + + } + } +} + diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_gd_wave_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_gd_wave_plugin.php new file mode 100755 index 0000000000..769867655c --- /dev/null +++ b/phpBB/includes/captcha/plugins/phpbb_captcha_gd_wave_plugin.php @@ -0,0 +1,66 @@ +lang['CAPTCHA_NO_OPTIONS'] . adm_back_link($module->u_action)); + } +} + +?> \ No newline at end of file diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_nogd_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_nogd_plugin.php new file mode 100755 index 0000000000..c5a32137d7 --- /dev/null +++ b/phpBB/includes/captcha/plugins/phpbb_captcha_nogd_plugin.php @@ -0,0 +1,68 @@ +lang['CAPTCHA_NO_OPTIONS'] . adm_back_link($module->u_action)); + } +} + diff --git a/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php b/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php new file mode 100644 index 0000000000..7a3c406324 --- /dev/null +++ b/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php @@ -0,0 +1,312 @@ +add_lang('recaptcha'); + parent::init($type); + $this->challenge = request_var('recaptcha_challenge_field', ''); + $this->response = request_var('recaptcha_response_field', ''); + } + + + function get_instance() + { + return new phpbb_recaptcha(); + } + + function is_available() + { + global $config, $user; + $user->add_lang('recaptcha'); + return (isset($config['recaptcha_pubkey']) && !empty($config['recaptcha_pubkey'])); + } + + function get_name() + { + return 'CAPTCHA_RECAPTCHA'; + } + + function get_class_name() + { + return 'phpbb_recaptcha'; + } + + function acp_page($id, &$module) + { + global $config, $db, $template, $user; + + $captcha_vars = array( + 'recaptcha_pubkey' => 'RECAPTCHA_PUBKEY', + 'recaptcha_privkey' => 'RECAPTCHA_PRIVKEY', + ); + + $module->tpl_name = 'captcha_recaptcha_acp'; + $module->page_title = 'ACP_VC_SETTINGS'; + $form_key = 'acp_captcha'; + add_form_key($form_key); + + $submit = request_var('submit', ''); + + if ($submit && check_form_key($form_key)) + { + $captcha_vars = array_keys($captcha_vars); + foreach ($captcha_vars as $captcha_var) + { + $value = request_var($captcha_var, ''); + if ($value) + { + set_config($captcha_var, $value); + } + } + trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($module->u_action)); + } + else if ($submit) + { + trigger_error($user->lang['FORM_INVALID'] . adm_back_link($module->u_action)); + } + else + { + foreach ($captcha_vars as $captcha_var => $template_var) + { + $var = (isset($_REQUEST[$captcha_var])) ? request_var($captcha_var, '') : ((isset($config[$captcha_var])) ? $config[$captcha_var] : ''); + $template->assign_var($template_var, $var); + } + $template->assign_vars(array( + 'CAPTCHA_PREVIEW' => $this->get_demo_template($id), + 'CAPTCHA_NAME' => $this->get_class_name(), + )); + + } + } + + + // not needed + function execute_demo() + { + } + + + // not needed + function execute() + { + } + + + function get_template() + { + global $config, $user, $template; + + $template->set_filenames(array( + 'captcha' => 'captcha_recaptcha.html') + ); + + $template->assign_vars(array( + 'RECAPTCHA_SERVER' => $this->recaptcha_server, + 'RECAPTCHA_PUBKEY' => isset($config['recaptcha_pubkey']) ? $config['recaptcha_pubkey'] : '', + 'RECAPTCHA_ERRORGET' => '', + 'S_RECAPTCHA_AVAILABLE' => $this->is_available(), + )); + + return $template->assign_display('captcha'); + } + + function get_demo_template($id) + { + return $this->get_template(); + } + + function get_hidden_fields() + { + $hidden_fields = array(); + + // this is required for postig.php - otherwise we would forget about the captcha being already solved + if ($this->solved) + { + $hidden_fields['confirm_code'] = $this->confirm_code; + } + $hidden_fields['confirm_id'] = $this->confirm_id; + return $hidden_fields; + } + + function uninstall() + { + self::garbage_collect(0); + } + + function install() + { + return; + } + + function validate() + { + if (!parent::validate()) + { + return false; + } + else + { + return $this->recaptcha_check_answer(); + } + } + + +// Code from here on is based on recaptchalib.php +/* + * This is a PHP library that handles calling reCAPTCHA. + * - Documentation and latest version + * http://recaptcha.net/plugins/php/ + * - Get a reCAPTCHA API Key + * http://recaptcha.net/api/getkey + * - Discussion group + * http://groups.google.com/group/recaptcha + * + * Copyright (c) 2007 reCAPTCHA -- http://recaptcha.net + * AUTHORS: + * Mike Crawford + * Ben Maurer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + /** + * Submits an HTTP POST to a reCAPTCHA server + * @param string $host + * @param string $path + * @param array $data + * @param int port + * @return array response + */ + function _recaptcha_http_post($host, $path, $data, $port = 80) + { + $req = $this->_recaptcha_qsencode ($data); + + $http_request = "POST $path HTTP/1.0\r\n"; + $http_request .= "Host: $host\r\n"; + $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n"; + $http_request .= "Content-Length: " . strlen($req) . "\r\n"; + $http_request .= "User-Agent: reCAPTCHA/PHP/phpBB\r\n"; + $http_request .= "\r\n"; + $http_request .= $req; + + $response = ''; + if( false == ( $fs = @fsockopen($host, $port, $errno, $errstr, 10) ) ) { + die ('Could not open socket'); + } + + fwrite($fs, $http_request); + + while ( !feof($fs) ) + $response .= fgets($fs, 1160); // One TCP-IP packet + fclose($fs); + $response = explode("\r\n\r\n", $response, 2); + + return $response; + } + + + /** + * Calls an HTTP POST function to verify if the user's guess was correct + * @param array $extra_params an array of extra variables to post to the server + * @return ReCaptchaResponse + */ + function recaptcha_check_answer ($extra_params = array()) + { + global $config, $user; + //discard spam submissions + if ($this->challenge == null || strlen($this->challenge) == 0 || $this->response == null || strlen($this->response) == 0) + { + return $user->lang['RECAPTCHA_INCORRECT']; + } + + $response = $this->_recaptcha_http_post ($this->recaptcha_verify_server, "/verify", + array ( + 'privatekey' => $config['recaptcha_privkey'], + 'remoteip' => $user->ip, + 'challenge' => $this->challenge, + 'response' => $this->response + ) + $extra_params + ); + + $answers = explode ("\n", $response[1]); + + if (trim ($answers[0]) === 'true') + { + $this->solved = true; + return false; + } + else + { + if ($answers[1] === 'incorrect-captcha-sol') + { + return $user->lang['RECAPTCHA_INCORRECT']; + } + } + } + + /** + * Encodes the given data into a query string format + * @param $data - array of string elements to be encoded + * @return string - encoded request + */ + function _recaptcha_qsencode ($data) + { + $req = ''; + foreach ( $data as $key => $value ) + { + $req .= $key . '=' . urlencode( stripslashes($value) ) . '&'; + } + // Cut the last '&' + $req=substr($req,0,strlen($req)-1); + return $req; + } +} + diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 476565452c..58601be65b 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -2520,6 +2520,11 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa { global $db, $user, $template, $auth, $phpEx, $phpbb_root_path, $config; + if (!class_exists('phpbb_captcha_factory')) + { + include($phpbb_root_path . 'includes/captcha/captcha_factory.' . $phpEx); + } + $err = ''; // Make sure user->setup() has been called @@ -2630,34 +2635,14 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa { case LOGIN_ERROR_ATTEMPTS: - // Show confirm image - $sql = 'DELETE FROM ' . CONFIRM_TABLE . " - WHERE session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_type = " . CONFIRM_LOGIN; - $db->sql_query($sql); + $captcha = phpbb_captcha_factory::get_instance($config['captcha_plugin']); + $captcha->init(CONFIRM_LOGIN); + $captcha->reset(); - // Generate code - $code = gen_rand_string(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)); - $confirm_id = md5(unique_id($user->ip)); - $seed = hexdec(substr(unique_id(), 4, 10)); - - // compute $seed % 0x7fffffff - $seed -= 0x7fffffff * floor($seed / 0x7fffffff); - - $sql = 'INSERT INTO ' . CONFIRM_TABLE . ' ' . $db->sql_build_array('INSERT', array( - 'confirm_id' => (string) $confirm_id, - 'session_id' => (string) $user->session_id, - 'confirm_type' => (int) CONFIRM_LOGIN, - 'code' => (string) $code, - 'seed' => (int) $seed) - ); - $db->sql_query($sql); $template->assign_vars(array( 'S_CONFIRM_CODE' => true, - 'CONFIRM_ID' => $confirm_id, - 'CONFIRM_IMAGE' => '', - 'L_LOGIN_CONFIRM_EXPLAIN' => sprintf($user->lang['LOGIN_CONFIRM_EXPLAIN'], '', ''), + 'CONFIRM' => $captcha->get_template(''), )); $err = $user->lang[$result['error_msg']]; diff --git a/phpBB/includes/session.php b/phpBB/includes/session.php index 043a637584..e039fce6e1 100644 --- a/phpBB/includes/session.php +++ b/phpBB/includes/session.php @@ -891,7 +891,7 @@ class session */ function session_gc() { - global $db, $config; + global $db, $config, $phpbb_root_path, $phpEx; $batch_size = 10; @@ -949,42 +949,18 @@ class session WHERE last_login < ' . (time() - (86400 * (int) $config['max_autologin_time'])); $db->sql_query($sql); } - $this->confirm_gc(); + + // only called from CRON; should be a safe workaround until the infrastructure gets going + if (!class_exists('captcha_factory')) + { + include($phpbb_root_path . "includes/captcha/captcha_factory." . $phpEx); + } + captcha_factory::garbage_collect($config['captcha_plugin']); } return; } - function confirm_gc($type = 0) - { - global $db, $config; - - $sql = 'SELECT DISTINCT c.session_id - FROM ' . CONFIRM_TABLE . ' c - LEFT JOIN ' . SESSIONS_TABLE . ' s ON (c.session_id = s.session_id) - WHERE s.session_id IS NULL' . - ((empty($type)) ? '' : ' AND c.confirm_type = ' . (int) $type); - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - $sql_in = array(); - do - { - $sql_in[] = (string) $row['session_id']; - } - while ($row = $db->sql_fetchrow($result)); - - if (sizeof($sql_in)) - { - $sql = 'DELETE FROM ' . CONFIRM_TABLE . ' - WHERE ' . $db->sql_in_set('session_id', $sql_in); - $db->sql_query($sql); - } - } - $db->sql_freeresult($result); - } - /** * Sets a cookie diff --git a/phpBB/includes/ucp/ucp_confirm.php b/phpBB/includes/ucp/ucp_confirm.php index b91c88b7e8..445f7c7d2a 100644 --- a/phpBB/includes/ucp/ucp_confirm.php +++ b/phpBB/includes/ucp/ucp_confirm.php @@ -3,7 +3,7 @@ * * @package VC * @version $Id$ -* @copyright (c) 2005 phpBB Group +* @copyright (c) 2005 2008 phpBB Group * @license http://opensource.org/licenses/gpl-license.php GNU Public License * */ @@ -37,42 +37,10 @@ class ucp_confirm { global $db, $user, $phpbb_root_path, $config, $phpEx; - // Do we have an id? No, then just exit - $confirm_id = request_var('id', ''); - $type = request_var('type', 0); - - if (!$confirm_id || !$type) - { - exit; - } - - // Try and grab code for this id and session - $sql = 'SELECT code, seed - FROM ' . CONFIRM_TABLE . " - WHERE session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_id = '" . $db->sql_escape($confirm_id) . "' - AND confirm_type = $type"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - // If we have a row then grab data else create a new id - if (!$row) - { - exit; - } - - if ($config['captcha_gd']) - { - include($phpbb_root_path . 'includes/captcha/captcha_gd.' . $phpEx); - } - else - { - include($phpbb_root_path . 'includes/captcha/captcha_non_gd.' . $phpEx); - } - - $captcha = new captcha(); - $captcha->execute($row['code'], $row['seed']); + include($phpbb_root_path . 'includes/captcha/captcha_factory.' . $phpEx); + $captcha = phpbb_captcha_factory::get_instance($config['captcha_plugin']); + $captcha->init(request_var('type', 0)); + $captcha->execute(); garbage_collection(); exit_handler(); diff --git a/phpBB/includes/ucp/ucp_register.php b/phpBB/includes/ucp/ucp_register.php index e42ad8369d..958369a03e 100644 --- a/phpBB/includes/ucp/ucp_register.php +++ b/phpBB/includes/ucp/ucp_register.php @@ -37,14 +37,12 @@ class ucp_register include($phpbb_root_path . 'includes/functions_profile_fields.' . $phpEx); - $confirm_id = request_var('confirm_id', ''); - $confirm_refresh = (isset($_POST['confirm_refresh']) && $config['confirm_refresh']) ? ((!empty($_POST['confirm_refresh'])) ? 1 : 0) : false; - $coppa = (isset($_REQUEST['coppa'])) ? ((!empty($_REQUEST['coppa'])) ? 1 : 0) : false; - $agreed = (!empty($_POST['agreed'])) ? 1 : 0; - $submit = (isset($_POST['submit'])) ? true : false; - $change_lang = request_var('change_lang', ''); - $user_lang = request_var('lang', $user->lang_name); - + $coppa = (isset($_REQUEST['coppa'])) ? ((!empty($_REQUEST['coppa'])) ? 1 : 0) : false; + $agreed = (!empty($_POST['agreed'])) ? 1 : 0; + $submit = (isset($_POST['submit'])) ? true : false; + $change_lang = request_var('change_lang', ''); + $user_lang = request_var('lang', $user->lang_name); + $confirm_refresh = (isset($_POST['confirm_refresh']) && $config['confirm_refresh']) ? ((!empty($_POST['confirm_refresh'])) ? 1 : 0) : false; if ($agreed) { add_form_key('ucp_register'); @@ -54,7 +52,14 @@ class ucp_register add_form_key('ucp_register_terms'); } - + + if ($config['enable_confirm']) + { + include($phpbb_root_path . 'includes/captcha/captcha_factory.' . $phpEx); + $captcha = phpbb_captcha_factory::get_instance($config['captcha_plugin']); + $captcha->init(CONFIRM_REG); + } + if ($change_lang || $user_lang != $config['default_lang']) { $use_lang = ($change_lang) ? basename($change_lang) : basename($user_lang); @@ -89,8 +94,8 @@ class ucp_register { $add_lang = ($change_lang) ? '&change_lang=' . urlencode($change_lang) : ''; $add_coppa = ($coppa !== false) ? '&coppa=' . $coppa : ''; - - $s_hidden_fields = ($confirm_id) ? array('confirm_id' => $confirm_id) : array(); + + $s_hidden_fields = array(); // If we change the language, we want to pass on some more possible parameter. if ($change_lang) @@ -100,11 +105,14 @@ class ucp_register 'username' => utf8_normalize_nfc(request_var('username', '', true)), 'email' => strtolower(request_var('email', '')), 'email_confirm' => strtolower(request_var('email_confirm', '')), - 'confirm_code' => request_var('confirm_code', ''), - 'confirm_id' => request_var('confirm_id', ''), 'lang' => $user->lang_name, 'tz' => request_var('tz', (float) $config['board_timezone']), )); + + if ($config['enable_confirm']) + { + $s_hidden_fields = array_merge($s_hidden_fields, $captcha->get_hidden_fields()); + } } if ($coppa === false && $config['coppa_enable']) @@ -168,7 +176,6 @@ class ucp_register 'password_confirm' => request_var('password_confirm', '', true), 'email' => strtolower(request_var('email', '')), 'email_confirm' => strtolower(request_var('email_confirm', '')), - 'confirm_code' => request_var('confirm_code', ''), 'lang' => basename(request_var('lang', $user->lang_name)), 'tz' => request_var('tz', (float) $timezone), ); @@ -188,7 +195,6 @@ class ucp_register array('string', false, 6, 60), array('email')), 'email_confirm' => array('string', false, 6, 60), - 'confirm_code' => array('string', !$config['enable_confirm'], CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS), 'tz' => array('num', false, -14, 14), 'lang' => array('match', false, '#^[a-z_\-]{2,}$#i'), )); @@ -199,6 +205,22 @@ class ucp_register // Replace "error" strings with their real, localised form $error = preg_replace('#^([A-Z_]+)$#e', "(!empty(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '\\1'", $error); + if ($config['enable_confirm']) + { + $vc_response = $captcha->validate(); + if ($vc_response) + { + $error[] = $vc_response; + } + else + { + $captcha->reset(); + } + if ($config['max_reg_attempts'] && $captcha->get_attempt_count() > $config['max_reg_attempts']) + { + $error[] = $user->lang['TOO_MANY_REGISTERS']; + } + } // DNSBL check if ($config['check_dnsbl']) { @@ -211,50 +233,6 @@ class ucp_register // validate custom profile fields $cp->submit_cp_field('register', $user->get_iso_lang_id(), $cp_data, $error); - // Visual Confirmation handling - $wrong_confirm = false; - if ($config['enable_confirm']) - { - if (!$confirm_id) - { - $error[] = $user->lang['CONFIRM_CODE_WRONG']; - $wrong_confirm = true; - } - else - { - $sql = 'SELECT code - FROM ' . CONFIRM_TABLE . " - WHERE confirm_id = '" . $db->sql_escape($confirm_id) . "' - AND session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_type = " . CONFIRM_REG; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - if (strcasecmp($row['code'], $data['confirm_code']) === 0) - { - $sql = 'DELETE FROM ' . CONFIRM_TABLE . " - WHERE confirm_id = '" . $db->sql_escape($confirm_id) . "' - AND session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_type = " . CONFIRM_REG; - $db->sql_query($sql); - } - else - { - $error[] = $user->lang['CONFIRM_CODE_WRONG']; - $wrong_confirm = true; - } - } - else - { - $error[] = $user->lang['CONFIRM_CODE_WRONG']; - $wrong_confirm = true; - } - } - } - if (!sizeof($error)) { if ($data['new_password'] != $data['password_confirm']) @@ -452,74 +430,17 @@ class ucp_register if ($change_lang || $confirm_refresh) { $str = '&change_lang=' . $change_lang; - $sql = 'SELECT code - FROM ' . CONFIRM_TABLE . " - WHERE confirm_id = '" . $db->sql_escape($confirm_id) . "' - AND session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_type = " . CONFIRM_REG; - $result = $db->sql_query($sql); - if (!$row = $db->sql_fetchrow($result)) - { - $confirm_id = ''; - } - $db->sql_freeresult($result); } else { $str = ''; + } - if (!$change_lang || !$confirm_id || !$confirm_refresh) - { - $user->confirm_gc(CONFIRM_REG); + $template->assign_vars(array( + 'L_CONFIRM_EXPLAIN' => sprintf($user->lang['CONFIRM_EXPLAIN'], '', ''), + 'S_CAPTCHA' => $captcha->get_template(), + )); - $sql = 'SELECT COUNT(session_id) AS attempts - FROM ' . CONFIRM_TABLE . " - WHERE session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_type = " . CONFIRM_REG; - $result = $db->sql_query($sql); - $attempts = (int) $db->sql_fetchfield('attempts'); - $db->sql_freeresult($result); - - if ($config['max_reg_attempts'] && $attempts > $config['max_reg_attempts']) - { - trigger_error('TOO_MANY_REGISTERS'); - } - - $code = gen_rand_string(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)); - $confirm_id = md5(unique_id($user->ip)); - $seed = hexdec(substr(unique_id(), 4, 10)); - - // compute $seed % 0x7fffffff - $seed -= 0x7fffffff * floor($seed / 0x7fffffff); - - $sql = 'INSERT INTO ' . CONFIRM_TABLE . ' ' . $db->sql_build_array('INSERT', array( - 'confirm_id' => (string) $confirm_id, - 'session_id' => (string) $user->session_id, - 'confirm_type' => (int) CONFIRM_REG, - 'code' => (string) $code, - 'seed' => (int) $seed) - ); - $db->sql_query($sql); - } - else if ($confirm_refresh) - { - $code = gen_rand_string(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)); - $confirm_id = md5(unique_id($user->ip)); - $seed = hexdec(substr(unique_id(), 4, 10)); - // compute $seed % 0x7fffffff - $seed -= 0x7fffffff * floor($seed / 0x7fffffff); - $sql = 'UPDATE ' . CONFIRM_TABLE . ' SET ' . $db->sql_build_array('UPDATE', array( - 'confirm_type' => (int) CONFIRM_REG, - 'code' => (string) $code, - 'seed' => (int) $seed)) . " - WHERE - confirm_id = '" . $db->sql_escape($confirm_id) . "' AND - session_id = '" . $db->sql_escape($session_id) . "' AND - confirm_type = " . (int) CONFIRM_REG; - $db->sql_query($sql); - } - $confirm_image = ''; - $s_hidden_fields .= ''; } // @@ -534,7 +455,7 @@ class ucp_register $l_reg_cond = $user->lang['UCP_ADMIN_ACTIVATE']; break; } - + $template->assign_vars(array( 'ERROR' => (sizeof($error)) ? implode('
        ', $error) : '', 'USERNAME' => $data['username'], @@ -542,16 +463,13 @@ class ucp_register 'PASSWORD_CONFIRM' => $data['password_confirm'], 'EMAIL' => $data['email'], 'EMAIL_CONFIRM' => $data['email_confirm'], - 'CONFIRM_IMG' => $confirm_image, - 'L_CONFIRM_EXPLAIN' => sprintf($user->lang['CONFIRM_EXPLAIN'], '', ''), 'L_REG_COND' => $l_reg_cond, 'L_USERNAME_EXPLAIN' => sprintf($user->lang[$config['allow_name_chars'] . '_EXPLAIN'], $config['min_name_chars'], $config['max_name_chars']), 'L_PASSWORD_EXPLAIN' => sprintf($user->lang[$config['pass_complex'] . '_EXPLAIN'], $config['min_pass_chars'], $config['max_pass_chars']), 'S_LANG_OPTIONS' => language_select($data['lang']), 'S_TZ_OPTIONS' => tz_select($data['tz']), - 'S_CONFIRM_CODE' => ($config['enable_confirm']) ? true : false, 'S_CONFIRM_REFRESH' => ($config['enable_confirm'] && $config['confirm_refresh']) ? true : false, 'S_COPPA' => $coppa, 'S_HIDDEN_FIELDS' => $s_hidden_fields, diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index c66ac859cf..fe855496e4 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -8,7 +8,7 @@ * */ -$updates_to_version = '3.0.5'; +$updates_to_version = '3.0.6-dev'; // Enter any version to update from to test updates. The version within the db will not be updated. $debug_from_version = false; @@ -677,6 +677,9 @@ function database_update_info() // No changes from 3.0.5-RC1 to 3.0.5 '3.0.5-RC1' => array(), + + // No changes from 3.0.5 + '3.0.5' => array(), ); } @@ -1012,6 +1015,14 @@ function change_database_data(&$no_updates, $version) // No changes from 3.0.5-RC1 to 3.0.5 case '3.0.5-RC1': break; + + + + case '3.0.5': + // TODO: smarter detection here; problem without GD. + set_config('captcha_plugin', 'phpbb_captcha_nogd'); + + break; } } diff --git a/phpBB/install/install_install.php b/phpBB/install/install_install.php index adb0fb9623..5ce18b37cd 100644 --- a/phpBB/install/install_install.php +++ b/phpBB/install/install_install.php @@ -1373,8 +1373,8 @@ class install_install extends module if (@extension_loaded('gd') || can_load_dll('gd')) { $sql_ary[] = 'UPDATE ' . $data['table_prefix'] . "config - SET config_value = '1' - WHERE config_name = 'captcha_gd'"; + SET config_value = 'phpbb_captcha_gd' + WHERE config_name = 'captcha_plugin'"; } $ref = substr($referer, strpos($referer, '://') + 3); diff --git a/phpBB/install/schemas/schema_data.sql b/phpBB/install/schemas/schema_data.sql index 8b6c6d7189..e41cf6794c 100644 --- a/phpBB/install/schemas/schema_data.sql +++ b/phpBB/install/schemas/schema_data.sql @@ -60,7 +60,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('browser_check', '1 INSERT INTO phpbb_config (config_name, config_value) VALUES ('bump_interval', '10'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('bump_type', 'd'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('cache_gc', '7200'); -INSERT INTO phpbb_config (config_name, config_value) VALUES ('captcha_gd', '0'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('captcha_plugin', 'phpbb_captcha_nogd'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('captcha_gd_foreground_noise', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('captcha_gd_x_grid', '25'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('captcha_gd_y_grid', '25'); diff --git a/phpBB/language/en/acp/board.php b/phpBB/language/en/acp/board.php index 7c2f3a24bb..fec608ed80 100644 --- a/phpBB/language/en/acp/board.php +++ b/phpBB/language/en/acp/board.php @@ -233,9 +233,11 @@ $lang = array_merge($lang, array( // Visual Confirmation Settings $lang = array_merge($lang, array( - 'ACP_VC_SETTINGS_EXPLAIN' => 'Here you are able to define visual confirmation defaults and CAPTCHA settings.', - + 'ACP_VC_SETTINGS_EXPLAIN' => 'Here you are able to define visual confirmation defaults and CAPTCHA settings.', + 'AVAILABLE_CAPTCHAS' => 'Available plugins', + 'CAPTCHA_UNAVAILABLE' => 'The CAPTCHA cannot be selected as its requirements are not met.', 'CAPTCHA_GD' => 'GD CAPTCHA', + 'CAPTCHA_GD_WAVE' => 'GD Wave Captcha', 'CAPTCHA_GD_FOREGROUND_NOISE' => 'GD CAPTCHA foreground noise', 'CAPTCHA_GD_EXPLAIN' => 'Use GD to make a more advanced CAPTCHA.', 'CAPTCHA_GD_FOREGROUND_NOISE_EXPLAIN' => 'Use foreground noise to make the GD based CAPTCHA harder.', @@ -252,10 +254,16 @@ $lang = array_merge($lang, array( 'CAPTCHA_FONT_DEFAULT' => 'Default', 'CAPTCHA_FONT_NEW' => 'New Shapes', 'CAPTCHA_FONT_LOWER' => 'Also use lowercase', - - + 'CAPTCHA_NO_GD' => 'CAPTCHA without GD', 'CAPTCHA_PREVIEW_MSG' => 'Your changes to the visual confirmation setting were not saved. This is just a preview.', - 'CAPTCHA_PREVIEW_EXPLAIN' => 'The CAPTCHA as it will look like using the current settings. Use the preview button to refresh. Note that captchas are randomized and will differ from one view to the next.', + 'CAPTCHA_PREVIEW_EXPLAIN' => 'The CAPTCHA as it would look like using the current selection.', + + 'CAPTCHA_SELECT' => 'Installed CAPTCHA plugins', + 'CAPTCHA_SELECT_EXPLAIN' => 'The dropdown holds the CAPTCHA plugins recognized by the board. Gray entries are not available right now and might need configuration prior to use.', + 'CAPTCHA_CONFIGURE' => 'Configure CAPTCHAs', + 'CAPTCHA_CONFIGURE_EXPLAIN' => 'Change the settings for the selected CAPTCHA.', + 'CONFIGURE' => 'Configure', + 'CAPTCHA_NO_OPTIONS' => 'This CAPTCHA has no configuration options.', 'VISUAL_CONFIRM_POST' => 'Enable visual confirmation for guest postings', 'VISUAL_CONFIRM_POST_EXPLAIN' => 'Requires anonymous users to enter a random code matching an image to help prevent mass postings.', 'VISUAL_CONFIRM_REG' => 'Enable visual confirmation for registrations', diff --git a/phpBB/language/en/recaptcha.php b/phpBB/language/en/recaptcha.php new file mode 100644 index 0000000000..140e300b7b --- /dev/null +++ b/phpBB/language/en/recaptcha.php @@ -0,0 +1,51 @@ + 'en', + 'RECAPTCHA_NOT_AVAILABLE' => 'You have to register for reCaptcha at reCaptcha.net.', + 'CAPTCHA_RECAPTCHA' => 'reCaptcha', + 'RECAPTCHA_INCORRECT' => 'The entered visual confirmation was incorrect', + + 'RECAPTCHA_PUBLIC' => 'Public reCaptcha key', + 'RECAPTCHA_PUBLIC_EXPLAIN' => 'Your public reCaptcha key. You can obtain keys from reCaptcha.net.', + 'RECAPTCHA_PRIVATE' => 'Private reCaptcha key', + 'RECAPTCHA_PRIVATE_EXPLAIN' => 'Your private reCaptcha key. You can obtain keys from reCaptcha.net.', + +)); + +?> \ No newline at end of file diff --git a/phpBB/posting.php b/phpBB/posting.php index c16c55111a..18c5b2fa7c 100644 --- a/phpBB/posting.php +++ b/phpBB/posting.php @@ -45,7 +45,13 @@ $mode = ($delete && !$preview && !$refresh && $submit) ? 'delete' : request_var $error = $post_data = array(); $current_time = time(); - +if ($config['enable_post_confirm'] && !$user->data['is_registered']) +{ + include($phpbb_root_path . 'includes/captcha/captcha_factory.' . $phpEx); + $captcha = phpbb_captcha_factory::get_instance($config['captcha_plugin']); + $captcha->init(CONFIRM_POST); +} + // Was cancel pressed? If so then redirect to the appropriate page if ($cancel || ($current_time - $lastclick < 2 && $submit)) { @@ -763,21 +769,10 @@ if ($submit || $preview || $refresh) if ($config['enable_post_confirm'] && !$user->data['is_registered'] && in_array($mode, array('quote', 'post', 'reply'))) { - $confirm_id = request_var('confirm_id', ''); - $confirm_code = request_var('confirm_code', ''); - - $sql = 'SELECT code - FROM ' . CONFIRM_TABLE . " - WHERE confirm_id = '" . $db->sql_escape($confirm_id) . "' - AND session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_type = " . CONFIRM_POST; - $result = $db->sql_query($sql); - $confirm_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (empty($confirm_row['code']) || strcasecmp($confirm_row['code'], $confirm_code) !== 0) + $vc_response = $captcha->validate(); + if ($vc_response) { - $error[] = $user->lang['CONFIRM_CODE_WRONG']; + $error[] = $vc_response; } else { @@ -1021,7 +1016,10 @@ if ($submit || $preview || $refresh) } $redirect_url = submit_post($mode, $post_data['post_subject'], $post_data['username'], $post_data['topic_type'], $poll, $data, $update_message); - + if ($config['enable_post_confirm'] && !$user->data['is_registered'] && in_array($mode, array('quote', 'post', 'reply'))) + { + $captcha->reset(); + } // Check the permissions for post approval, as well as the queue trigger where users are put on approval with a post count lower than specified. Moderators are not affected. if ((($config['enable_queue_trigger'] && $user->data['user_posts'] < $config['queue_trigger_posts']) || !$auth->acl_get('f_noapprove', $data['forum_id'])) && !$auth->acl_get('m_approve', $data['forum_id'])) { @@ -1242,34 +1240,12 @@ generate_forum_rules($post_data); if ($config['enable_post_confirm'] && !$user->data['is_registered'] && $solved_captcha === false && ($mode == 'post' || $mode == 'reply' || $mode == 'quote')) { - // Show confirm image - $sql = 'DELETE FROM ' . CONFIRM_TABLE . " - WHERE session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_type = " . CONFIRM_POST; - $db->sql_query($sql); + $captcha->reset(); - // Generate code - $code = gen_rand_string(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)); - $confirm_id = md5(unique_id($user->ip)); - $seed = hexdec(substr(unique_id(), 4, 10)); - - // compute $seed % 0x7fffffff - $seed -= 0x7fffffff * floor($seed / 0x7fffffff); - - $sql = 'INSERT INTO ' . CONFIRM_TABLE . ' ' . $db->sql_build_array('INSERT', array( - 'confirm_id' => (string) $confirm_id, - 'session_id' => (string) $user->session_id, - 'confirm_type' => (int) CONFIRM_POST, - 'code' => (string) $code, - 'seed' => (int) $seed) - ); - $db->sql_query($sql); $template->assign_vars(array( 'S_CONFIRM_CODE' => true, - 'CONFIRM_ID' => $confirm_id, - 'CONFIRM_IMAGE' => '', - 'L_POST_CONFIRM_EXPLAIN' => sprintf($user->lang['POST_CONFIRM_EXPLAIN'], '', ''), + 'CONFIRM' => $captcha->get_template(), )); } @@ -1280,10 +1256,7 @@ $s_hidden_fields .= ($draft_id || isset($_REQUEST['draft_loaded'])) ? ' request_var('confirm_id', ''), - 'confirm_code' => request_var('confirm_code', '')) - ); + $s_hidden_fields .= build_hidden_fields($captcha->get_hidden_fields()); } $form_enctype = (@ini_get('file_uploads') == '0' || strtolower(@ini_get('file_uploads')) == 'off' || !$config['allow_attachments'] || !$auth->acl_get('u_attach') || !$auth->acl_get('f_attach', $forum_id)) ? '' : ' enctype="multipart/form-data"'; diff --git a/phpBB/styles/prosilver/template/captcha_default.html b/phpBB/styles/prosilver/template/captcha_default.html new file mode 100755 index 0000000000..399c978898 --- /dev/null +++ b/phpBB/styles/prosilver/template/captcha_default.html @@ -0,0 +1,9 @@ + +
        +
        +
        +
        + +
        +
        {L_CONFIRM_CODE_EXPLAIN}
        +
        \ No newline at end of file diff --git a/phpBB/styles/prosilver/template/captcha_recaptcha.html b/phpBB/styles/prosilver/template/captcha_recaptcha.html new file mode 100644 index 0000000000..f325c3727d --- /dev/null +++ b/phpBB/styles/prosilver/template/captcha_recaptcha.html @@ -0,0 +1,19 @@ + +
        + + + +
        + +{L_RECAPTCHA_NOT_AVAILABLE} + \ No newline at end of file diff --git a/phpBB/styles/prosilver/template/login_body.html b/phpBB/styles/prosilver/template/login_body.html index ac7ada28c9..a32c2d1e42 100644 --- a/phpBB/styles/prosilver/template/login_body.html +++ b/phpBB/styles/prosilver/template/login_body.html @@ -21,21 +21,16 @@
        {L_RESEND_ACTIVATION}
        - -
        -

        {L_CONFIRM_CODE_EXPLAIN}
        -
        {CONFIRM_IMAGE}
        -
        -
        + {CONFIRM} -
        +
         
        {S_HIDDEN_FIELDS}
        @@ -46,6 +41,7 @@
      +
      diff --git a/phpBB/styles/prosilver/template/posting_editor.html b/phpBB/styles/prosilver/template/posting_editor.html index 248d1ea72c..315fbaee2b 100644 --- a/phpBB/styles/prosilver/template/posting_editor.html +++ b/phpBB/styles/prosilver/template/posting_editor.html @@ -100,11 +100,7 @@
      -
      -

      {L_CONFIRM_CODE_EXPLAIN}
      -
      {CONFIRM_IMAGE}
      -
      -
      + {CONFIRM} diff --git a/phpBB/styles/prosilver/template/ucp_register.html b/phpBB/styles/prosilver/template/ucp_register.html index 3aeb92a5b0..468b131c4b 100644 --- a/phpBB/styles/prosilver/template/ucp_register.html +++ b/phpBB/styles/prosilver/template/ucp_register.html @@ -71,8 +71,7 @@ - - +
      @@ -83,16 +82,11 @@

      {L_CONFIRM_EXPLAIN}

      -
      -
      -
      {CONFIRM_IMG}
      -
      -
      {L_CONFIRM_CODE_EXPLAIN} {L_VC_REFRESH_EXPLAIN}
      -
      -
      -
      - + {S_CAPTCHA} + + + diff --git a/phpBB/styles/subsilver2/template/captcha_default.html b/phpBB/styles/subsilver2/template/captcha_default.html new file mode 100755 index 0000000000..a1bc6cd6dc --- /dev/null +++ b/phpBB/styles/subsilver2/template/captcha_default.html @@ -0,0 +1,19 @@ + + {L_CONFIRM_CODE} + + + {L_CONFIRM_CODE_EXPLAIN} + + + {L_CONFIRM_CODE} + + + + + {L_CONFIRM_CODE}:
      {L_CONFIRM_CODE_EXPLAIN} + + + + + + diff --git a/phpBB/styles/subsilver2/template/captcha_recaptcha.html b/phpBB/styles/subsilver2/template/captcha_recaptcha.html new file mode 100755 index 0000000000..106a5cce2a --- /dev/null +++ b/phpBB/styles/subsilver2/template/captcha_recaptcha.html @@ -0,0 +1,21 @@ + + + // + + + + + +{L_RECAPTCHA_NOT_AVAILABLE} + + + \ No newline at end of file diff --git a/phpBB/styles/subsilver2/template/login_body.html b/phpBB/styles/subsilver2/template/login_body.html index 86eed2dfc6..406ab3a293 100644 --- a/phpBB/styles/subsilver2/template/login_body.html +++ b/phpBB/styles/subsilver2/template/login_body.html @@ -65,26 +65,13 @@ - + - - - - - - - - - - - - - - + + {S_CAPTCHA} + + diff --git a/phpBB/styles/subsilver2/template/posting_body.html b/phpBB/styles/subsilver2/template/posting_body.html index da1fbf4e30..162227b7e5 100644 --- a/phpBB/styles/subsilver2/template/posting_body.html +++ b/phpBB/styles/subsilver2/template/posting_body.html @@ -332,24 +332,10 @@ - - - - - - - - - - - - - - - + + {S_CAPTCHA} + + diff --git a/phpBB/styles/subsilver2/template/ucp_register.html b/phpBB/styles/subsilver2/template/ucp_register.html index fd987f2d73..dc47323836 100644 --- a/phpBB/styles/subsilver2/template/ucp_register.html +++ b/phpBB/styles/subsilver2/template/ucp_register.html @@ -77,21 +77,9 @@ - - - - - - - - - - - - - - - + + {S_CAPTCHA} +
      {L_LOGIN_CONFIRMATION}
      {L_LOGIN_CONFIRM_EXPLAIN}
      - - {CONFIRM_IMAGE} -
      {L_CONFIRM_CODE}:
      {L_CONFIRM_CODE_EXPLAIN}
      colspan="2" align="center">{S_HIDDEN_FIELDS}
      {L_POST_CONFIRMATION}
      {L_POST_CONFIRM_EXPLAIN}
      - - {CONFIRM_IMAGE} -
      {L_CONFIRM_CODE}:
      {L_CONFIRM_CODE_EXPLAIN}
      {L_CONFIRMATION}
      {L_CONFIRM_EXPLAIN}
      {CONFIRM_IMG}
      {L_CONFIRM_CODE}:
      {L_CONFIRM_CODE_EXPLAIN} {L_VC_REFRESH_EXPLAIN}