1<?php 2/** 3 * CAPTCHA class For XOOPS 4 * 5 * You may not change or alter any portion of this comment or credits 6 * of supporting developers from this source code or any supporting source code 7 * which is considered copyrighted (c) material of the original comment or credit authors. 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 * 12 * @copyright (c) 2000-2016 XOOPS Project (www.xoops.org) 13 * @license GNU GPL 2 (http://www.gnu.org/licenses/gpl-2.0.html) 14 * @since 2.3.0 15 * @author Taiwen Jiang <phppp@users.sourceforge.net> 16 * @package class 17 * @subpackage CAPTCHA 18 */ 19 20include __DIR__ . '/../../../../mainfile.php'; 21 22error_reporting(0); 23$xoopsLogger->activated = false; 24 25/* 26if (empty($_SERVER['HTTP_REFERER']) || !preg_match("/^" . preg_quote(XOOPS_URL, '/') . "/", $_SERVER['HTTP_REFERER'])) { 27 exit(); 28} 29*/ 30 31/** 32 * Class XoopsCaptchaImageHandler 33 */ 34class XoopsCaptchaImageHandler 35{ 36 public $config = array(); 37 public $code; 38 public $mode = 'gd'; 39 public $invalid = false; 40 41 public $oImage; 42 public $font; 43 public $spacing; 44 public $width; 45 public $height; 46 47 public $captchaHandler; 48 49 /** 50 * 51 */ 52 public function __construct() 53 { 54 xoops_load('XoopsCaptcha'); 55 $this->captchaHandler = XoopsCaptcha::getInstance(); 56 $this->config = $this->captchaHandler->loadConfig('image'); 57 } 58 59 public function loadImage() 60 { 61 $this->generateCode(); 62 $this->createImage(); 63 } 64 65 /** 66 * Create Code 67 */ 68 public function generateCode() 69 { 70 if ($this->invalid) { 71 return false; 72 } 73 74 if ($this->mode === 'bmp') { 75 $this->config['num_chars'] = 4; 76 $this->code = mt_rand(pow(10, $this->config['num_chars'] - 1), (int)str_pad('9', $this->config['num_chars'], '9')); 77 } else { 78 $raw_code = md5(uniqid(mt_rand(), 1)); 79 if (!empty($this->config['skip_characters'])) { 80 $valid_code = str_replace($this->config['skip_characters'], '', $raw_code); 81 $this->code = substr($valid_code, 0, $this->config['num_chars']); 82 } else { 83 $this->code = substr($raw_code, 0, $this->config['num_chars']); 84 } 85 if (!$this->config['casesensitive']) { 86 $this->code = strtoupper($this->code); 87 } 88 } 89 $this->captchaHandler->setCode($this->code); 90 91 return true; 92 } 93 94 /** 95 * @return string|void 96 */ 97 public function createImage() 98 { 99 if ($this->invalid) { 100 header('Content-type: image/gif'); 101 readfile(XOOPS_ROOT_PATH . '/images/subject/icon2.gif'); 102 103 return null; 104 } 105 106 if ($this->mode === 'bmp') { 107 return $this->createImageBmp(); 108 } else { 109 return $this->createImageGd(); 110 } 111 } 112 113 /** 114 * @param string $name 115 * @param string $extension 116 * 117 * @return array|mixed 118 */ 119 public function getList($name, $extension = '') 120 { 121 $items = array(); 122 xoops_load('XoopsCache'); 123 if ($items = XoopsCache::read("captcha_captcha_{$name}")) { 124 return $items; 125 } 126 127 require_once XOOPS_ROOT_PATH . '/class/xoopslists.php'; 128 $file_path = XOOPS_ROOT_PATH . "/class/captcha/image/{$name}"; 129 $files = XoopsLists::getFileListAsArray($file_path); 130 foreach ($files as $item) { 131 if (empty($extension) || preg_match("/(\.{$extension})$/i", $item)) { 132 $items[] = $item; 133 } 134 } 135 XoopsCache::write("captcha_captcha_{$name}", $items); 136 137 return $items; 138 } 139 140 /**#@+ 141 * Create CAPTCHA iamge with GD 142 * Originated by DuGris' SecurityImage 143 */ 144 // --------------------------------------------------------------------------- // 145 // Class : SecurityImage 1.5 // 146 // Author: DuGris aka L. Jen <http://www.dugris.info> // 147 // Email : DuGris@wanadoo.fr // 148 // Licence: GNU // 149 // Project: The XOOPS Project // 150 // --------------------------------------------------------------------------- // 151 public function createImageGd() 152 { 153 $this->loadFont(); 154 $this->setImageSize(); 155 156 $this->oImage = imagecreatetruecolor($this->width, $this->height); 157 $background = imagecolorallocate($this->oImage, 255, 255, 255); 158 imagefilledrectangle($this->oImage, 0, 0, $this->width, $this->height, $background); 159 160 switch ($this->config['background_type']) { 161 default: 162 case 0: 163 $this->drawBars(); 164 break; 165 166 case 1: 167 $this->drawCircles(); 168 break; 169 170 case 2: 171 $this->drawLines(); 172 break; 173 174 case 3: 175 $this->drawRectangles(); 176 break; 177 178 case 4: 179 $this->drawEllipses(); 180 break; 181 182 case 5: 183 $this->drawPolygons(); 184 break; 185 186 case 100: 187 $this->createFromFile(); 188 break; 189 } 190 $this->drawBorder(); 191 $this->drawCode(); 192 193 header('Content-type: image/jpeg'); 194 imagejpeg($this->oImage); 195 imagedestroy($this->oImage); 196 } 197 198 public function loadFont() 199 { 200 $fonts = $this->getList('fonts', 'ttf'); 201 $this->font = XOOPS_ROOT_PATH . '/class/captcha/image/fonts/' . $fonts[array_rand($fonts)]; 202 } 203 204 public function setImageSize() 205 { 206 $MaxCharWidth = 0; 207 $MaxCharHeight = 0; 208 $oImage = imagecreatetruecolor(100, 100); 209 $text_color = imagecolorallocate($oImage, mt_rand(0, 100), mt_rand(0, 100), mt_rand(0, 100)); 210 $FontSize = $this->config['fontsize_max']; 211 for ($Angle = -30; $Angle <= 30; ++$Angle) { 212 for ($i = 65; $i <= 90; ++$i) { 213 $CharDetails = imageftbbox($FontSize, $Angle, $this->font, chr($i), array()); 214 $_MaxCharWidth = abs($CharDetails[0] + $CharDetails[2]); 215 if ($_MaxCharWidth > $MaxCharWidth) { 216 $MaxCharWidth = $_MaxCharWidth; 217 } 218 $_MaxCharHeight = abs($CharDetails[1] + $CharDetails[5]); 219 if ($_MaxCharHeight > $MaxCharHeight) { 220 $MaxCharHeight = $_MaxCharHeight; 221 } 222 } 223 } 224 imagedestroy($oImage); 225 226 $this->height = $MaxCharHeight + 2; 227 $this->spacing = (int)(($this->config['num_chars'] * $MaxCharWidth) / $this->config['num_chars']); 228 $this->width = ($this->config['num_chars'] * $MaxCharWidth) + ($this->spacing / 2); 229 } 230 231 /** 232 * Return random background 233 * 234 * @return array 235 */ 236 public function loadBackground() 237 { 238 $RandBackground = null; 239 if ($backgrounds = $this->getList('backgrounds', '(gif|jpg|png)')) { 240 $RandBackground = XOOPS_ROOT_PATH . '/class/captcha/image/backgrounds/' . $backgrounds[array_rand($backgrounds)]; 241 } 242 243 return $RandBackground; 244 } 245 246 /** 247 * Draw Image background 248 */ 249 public function createFromFile() 250 { 251 if ($RandImage = $this->loadBackground()) { 252 $ImageType = @getimagesize($RandImage); 253 switch (@$ImageType[2]) { 254 case 1: 255 $BackgroundImage = imagecreatefromgif($RandImage); 256 break; 257 258 case 2: 259 $BackgroundImage = imagecreatefromjpeg($RandImage); 260 break; 261 262 case 3: 263 $BackgroundImage = imagecreatefrompng($RandImage); 264 break; 265 } 266 } 267 if (!empty($BackgroundImage)) { 268 imagecopyresized($this->oImage, $BackgroundImage, 0, 0, 0, 0, imagesx($this->oImage), imagesy($this->oImage), imagesx($BackgroundImage), imagesy($BackgroundImage)); 269 imagedestroy($BackgroundImage); 270 } else { 271 $this->drawBars(); 272 } 273 } 274 275 /** 276 * Draw Code 277 */ 278 public function drawCode() 279 { 280 for ($i = 0; $i < $this->config['num_chars']; ++$i) { 281 // select random greyscale colour 282 $text_color = imagecolorallocate($this->oImage, mt_rand(0, 100), mt_rand(0, 100), mt_rand(0, 100)); 283 284 // write text to image 285 $Angle = mt_rand(10, 30); 286 if ($i % 2) { 287 $Angle = mt_rand(-10, -30); 288 } 289 290 // select random font size 291 $FontSize = mt_rand($this->config['fontsize_min'], $this->config['fontsize_max']); 292 293 $CharDetails = imageftbbox($FontSize, $Angle, $this->font, $this->code[$i], array()); 294 $CharHeight = abs($CharDetails[1] + $CharDetails[5]); 295 296 // calculate character starting coordinates 297 $posX = ($this->spacing / 2) + ($i * $this->spacing); 298 $posY = 2 + ($this->height / 2) + ($CharHeight / 4); 299 300 imagefttext($this->oImage, $FontSize, $Angle, $posX, $posY, $text_color, $this->font, $this->code[$i], array()); 301 } 302 } 303 304 /** 305 * Draw Border 306 */ 307 public function drawBorder() 308 { 309 $rgb = mt_rand(50, 150); 310 $border_color = imagecolorallocate($this->oImage, $rgb, $rgb, $rgb); 311 imagerectangle($this->oImage, 0, 0, $this->width - 1, $this->height - 1, $border_color); 312 } 313 314 /** 315 * Draw Circles background 316 */ 317 public function drawCircles() 318 { 319 for ($i = 1; $i <= $this->config['background_num']; ++$i) { 320 $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255)); 321 imagefilledellipse($this->oImage, mt_rand(0, $this->width - 10), mt_rand(0, $this->height - 3), mt_rand(10, 20), mt_rand(20, 30), $randomcolor); 322 } 323 } 324 325 /** 326 * Draw Lines background 327 */ 328 public function drawLines() 329 { 330 for ($i = 0; $i < $this->config['background_num']; ++$i) { 331 $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255)); 332 imageline($this->oImage, mt_rand(0, $this->width), mt_rand(0, $this->height), mt_rand(0, $this->width), mt_rand(0, $this->height), $randomcolor); 333 } 334 } 335 336 /** 337 * Draw Rectangles background 338 */ 339 public function drawRectangles() 340 { 341 for ($i = 1; $i <= $this->config['background_num']; ++$i) { 342 $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255)); 343 imagefilledrectangle($this->oImage, mt_rand(0, $this->width), mt_rand(0, $this->height), mt_rand(0, $this->width), mt_rand(0, $this->height), $randomcolor); 344 } 345 } 346 347 /** 348 * Draw Bars background 349 */ 350 public function drawBars() 351 { 352 for ($i = 0; $i <= $this->height;) { 353 $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255)); 354 imageline($this->oImage, 0, $i, $this->width, $i, $randomcolor); 355 $i += 2.5; 356 } 357 for ($i = 0; $i <= $this->width;) { 358 $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255)); 359 imageline($this->oImage, $i, 0, $i, $this->height, $randomcolor); 360 $i += 2.5; 361 } 362 } 363 364 /** 365 * Draw Ellipses background 366 */ 367 public function drawEllipses() 368 { 369 for ($i = 1; $i <= $this->config['background_num']; ++$i) { 370 $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255)); 371 imageellipse($this->oImage, mt_rand(0, $this->width), mt_rand(0, $this->height), mt_rand(0, $this->width), mt_rand(0, $this->height), $randomcolor); 372 } 373 } 374 375 /** 376 * Draw polygons background 377 */ 378 public function drawPolygons() 379 { 380 for ($i = 1; $i <= $this->config['background_num']; ++$i) { 381 $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255)); 382 $coords = array(); 383 for ($j = 1; $j <= $this->config['polygon_point']; ++$j) { 384 $coords[] = mt_rand(0, $this->width); 385 $coords[] = mt_rand(0, $this->height); 386 } 387 imagefilledpolygon($this->oImage, $coords, $this->config['polygon_point'], $randomcolor); 388 } 389 } 390 /**#@-*/ 391 392 /** 393 * Create CAPTCHA image with BMP 394 * 395 * TODO 396 * @param string $file 397 * @return string 398 */ 399 public function createImageBmp($file = '') 400 { 401 $image = ''; 402 403 if (empty($file)) { 404 header('Content-type: image/bmp'); 405 echo $image; 406 } else { 407 return $image; 408 } 409 return null; 410 } 411} 412 413$imageHandler = new XoopsCaptchaImageHandler(); 414$imageHandler->loadImage(); 415