plugins/content/classes/yf_captcha.class.php
<?php
/**
* Class to handle CAPTCHA images (to prevent auto-registering, flooding etc).
*
* @author YFix Team <yfix.dev@gmail.com>
* @version 1.0
*/
class yf_captcha
{
/** @var string Secret key (will be added to hash) */
public $secret_key = '';
/** @var bool Use cookies or session vars */
public $use_cookies = false;
/** @var bool Checking if once used */
public $already_used = false;
/** @var string Cookie var name */
public $var_name = 'image_hash';
/** @var int Cookie time-to-live (in seconds) */
public $cookie_ttl = 86400; // @var 24 * 3600 == 1 day
/** @var string Path to the True Type Font to use (could be array) */
public $ttf_font_path = '';
/** @var int Result image width (in pixels) */
public $image_width = 110;
/** @var int Result image height (in pixels) */
public $image_height = 30;
/** @var array Allowed symbols to use in randomizer */
public $symbols_array = [];
/** @var int Number of symbols to generate */
public $num_symbols = 5;
/** @var int Middle value (will be bounced randomly with +2 and -2) */
public $font_height = 16;
/** @var int Number of random rectangles to add */
public $add_rects = 15;
/** @var int Number of random lines to add */
public $add_lines = 15;
/** @var int Number of random ellipses to add */
public $add_ellipses = 10;
/** @var int Number of random pixels to add */
public $add_pixels = 500;
/** @var int @conf_skip Image background color */
public $bg_color = 0x00ffffff; // @var 0x AA RR GG BB (alpha, red, green, blue)
/** @var array @conf_skip Colors arrays */
public $text_colors = [
0x162A7C8F,
0x1628508C,
0x16A12F9B,
0x1619621D,
0x16622A19,
];
/** @var array @conf_skip */
public $rect_colors = [
0x702A7C8F,
0x7028508C,
0x70A12F9B,
0x7019621D,
0x70622A19,
];
/** @var array @conf_skip */
public $line_colors = [
0x202A7C8F,
0x2028508C,
];
/** @var array @conf_skip */
public $ellipse_colors = [
0x702A7C8F,
0x7028508C,
0x70A12F9B,
0x7019621D,
0x70622A19,
];
/** @var array @conf_skip */
public $pixel_colors = [
0x202A7C8F,
0x2028508C,
];
/** @var CAPTCHA enabled */
public $ENABLED = true;
/**
* Catch missing method call.
* @param mixed $name
* @param mixed $args
*/
public function __call($name, $args)
{
return main()->extend_call($this, $name, $args);
}
/**
* Framework constructor.
*/
public function _init()
{
$this->_is_enabled_hook();
if ( ! $this->ENABLED) {
return false;
}
$this->set_secret_key();
$lib_path = PROJECT_PATH . 'fonts/';
$fwork_path = dirname(__DIR__) . '/fonts/';
$path = file_exists($lib_path) ? $lib_path : $fwork_path;
$this->set_font_path([
$path . 'pioneer.ttf',
$path . 'banco.ttf',
$path . 'glast.ttf',
]);
$this->set_symbols_array(1);
}
/**
* Set secret key.
* @param mixed $input
*/
public function set_secret_key($input = '')
{
if (empty($input)) {
$this->secret_key = substr(md5(REAL_PATH), 8, -8);
} else {
$this->secret_key = $input;
}
}
/**
* Set font path ($input could be array or string).
* @param mixed $input
*/
public function set_font_path($input = '')
{
if ( ! empty($input)) {
$this->ttf_font_path = $input;
}
}
/**
* Set symbols array contetns.
* @param mixed $input
*/
public function set_symbols_array($input = [])
{
if (empty($input)) {
return false;
}
// Try to assign predefined arrays
if (is_numeric($input)) {
if ($input == 1) {
$this->symbols_array = range(0, 9);
} elseif ($input == 2) {
$this->symbols_array = array_flip(range('A', 'Z'));
} elseif ($input == 3) {
$this->symbols_array = array_merge(array_flip(range(0, 9)), array_flip(range('a', 'z')));
}
// Try to set custom array
} elseif (is_array($input)) {
$this->symbols_array = $input;
}
}
/**
* Set colors.
* @param mixed $name
* @param mixed $input
*/
public function set_colors($name = '', $input = '')
{
if ( ! empty($input) && in_array('text', 'rect', 'line', 'ellipse', 'pixel')) {
$this->{$name . '_colors'} = $input;
}
}
/**
* Set image size.
* @param mixed $width
* @param mixed $height
*/
public function set_image_size($width = '', $height = '')
{
if ( ! empty($width) && ! empty($height)) {
$this->image_width = $width;
$this->image_height = $height;
}
}
/**
* Set new var name to use in session or in cookie.
* @param mixed $new_name
*/
public function set_var_name($new_name = '')
{
if ( ! empty($new_name)) {
$this->var_name = $new_name;
}
}
/**
* Show HTML code for the CAPTCHA image.
* @param mixed $location
* @param mixed $add_style
*/
public function show_html($location = '', $add_style = ' border="1" ')
{
if ( ! $this->ENABLED) {
return false;
}
if (empty($location)) {
$location = process_url('./?object=' . __CLASS__ . '&action=show_image');
}
return '<img src="' . $location . '" ' . $add_style . ' />';
}
/**
* Show HTML block for the CAPTCHA image (complete, with input and it's validation).
* @param mixed $location
* @param mixed $stpl_name
* @param mixed $extra
*/
public function show_block($location = '', $stpl_name = '', $extra = [])
{
if ( ! $this->ENABLED) {
return false;
}
if (is_array($stpl_name)) {
$extra += $stpl_name;
$stpl_name = $extra['captcha_stpl_name'];
}
$stpl_name = $extra['captcha_stpl_name'] ?: $stpl_name;
if (empty($location)) {
$location = './?object=' . $_GET['object'] . '&action=show_image';
}
$uid = '__captcha_id__';
if (false === strpos($location, $uid)) {
$location .= '&id=' . $uid;
}
if (empty($stpl_name)) {
$stpl_name = 'system/captcha_block';
}
$replace = [
'img_src' => process_url($location),
'num_symbols' => (int) ($this->num_symbols),
'input_attrs' => $extra['input_attrs'],
//'value' => $extra['value'],
'value' => '',
];
return tpl()->parse($stpl_name, $replace);
}
/**
* Show image with text.
* @param mixed $field_in_form
* @param null|mixed $input
*/
public function check($field_in_form = 'image_numbers', $input = null)
{
if ( ! $this->ENABLED) {
return true;
}
$VALID_CODE = false;
if ($this->already_used) {
return true;
}
$this->already_used = true;
if ( ! isset($input)) {
$input = $_POST[$field_in_form] ?: $_GET[$field_in_form];
}
if (empty($input)) {
_re('Please enter code', $field_in_form);
} else {
$hash = md5($this->secret_key . $input);
if ($this->use_cookies) {
if ($hash != $_COOKIE[$this->var_name]) {
$code_incorrect = true;
}
} else {
if ($hash != $_SESSION[$this->var_name]) {
$code_incorrect = true;
}
}
if ($code_incorrect) {
_re('Code you entered is incorrect', $field_in_form);
} else {
$VALID_CODE = true;
}
}
if ($this->use_cookies) {
setcookie($this->var_name, '', time());
} else {
unset($_SESSION[$this->var_name]);
}
return $VALID_CODE;
}
/**
* Show image with text.
* @param mixed $no_header
* @param mixed $no_exit
*/
public function show_image($no_header = false, $no_exit = false)
{
if (function_exists('main')) {
main()->NO_GRAPHICS = true;
}
if ( ! $this->ENABLED) {
return false;
}
// Create image
$image = imagecreatetruecolor($this->image_width, $this->image_height);
// Calculate average width for the one font symbol
$font_width = $this->image_width / $this->num_symbols;
// Set font path
$ttf_font = is_array($this->ttf_font_path) ? array_rand(array_flip($this->ttf_font_path)) : $this->ttf_font_path;
// Set image background color
imagefilledrectangle($image, 0, 0, $this->image_width, $this->image_height, $this->bg_color);
// Draw text
for ($i = 0; $i < $this->num_symbols; $i++) {
$random_string .= array_rand($this->symbols_array);
imagettftext($image, round(rand($this->font_height - 2, $this->font_height + 2), 0), rand(-30, 30), $i * $font_width + 5 + rand(-2, 2), $this->image_height / 2 + 5 + rand(-4, 4), array_rand(array_flip($this->text_colors)), $ttf_font, $random_string[$i]);
}
// Draw random rectangles
for ($i = 0; $i < $this->add_rects; $i++) {
imagefilledrectangle($image, rand(-$this->image_width, $this->image_width), rand(-$this->image_height, $this->image_height), rand(-$this->image_width, $this->image_width), rand(-$this->image_height, $this->image_height), array_rand(array_flip($this->rect_colors)));
}
// Draw random lines
for ($i = 0; $i < $this->add_lines; $i++) {
imageline($image, rand(-$this->image_width, $this->image_width), rand(-$this->image_height, $this->image_height), rand(-$this->image_width, $this->image_width), rand(-$this->image_height, $this->image_height), array_rand(array_flip($this->line_colors)));
}
// Draw random ellipses
for ($i = 0; $i < $this->add_ellipses; $i++) {
imagefilledellipse($image, rand(-$this->image_height, $this->image_width), rand(-$this->image_height, $this->image_height), rand(20, $this->image_width), rand(10, $this->image_width), array_rand(array_flip($this->ellipse_colors)));
}
// Draw random pixels
for ($i = 0; $i < $this->add_pixels; $i++) {
imagesetpixel($image, rand(0, $this->image_width), rand(0, $this->image_height), array_rand(array_flip($this->pixel_colors)));
}
// Calculate hash
$hash = md5($this->secret_key . $random_string);
// Store secure data
if ($this->use_cookies) {
setcookie($this->var_name, $hash, time() + $this->cookie_ttl);
} else {
$_SESSION[$this->var_name] = $hash;
}
ob_start();
imagepng($image);
imagedestroy($image);
$data = ob_get_clean();
// Throw image to the user
if ( ! $no_header) {
header_remove('Set-Cookie');
header('Content-Type: image/png', true);
header('Content-Length: ' . strlen($data), true);
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT', true); // Date in the past
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT', true); // always modified
header('Cache-Control: private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0');
header('Pragma: no-cache', true); // HTTP/1.0
header('X-Robots-Tag: noindex,nofollow,noarchive,nosnippet', true);
}
echo $data;
if ( ! $no_exit) {
exit;
}
}
/**
* Allows you to override $this->ENABLED option for some cases.
*/
public function _is_enabled_hook()
{
//$this->ENABLED = false;
}
}