Yoshi2889 /
SMF2.1
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | /** |
||
| 4 | * This file deals with low-level graphics operations performed on images, |
||
| 5 | * specially as needed for avatars (uploaded avatars), attachments, or |
||
| 6 | * visual verification images. |
||
| 7 | * It uses, for gifs at least, Gif Util. For more information on that, |
||
| 8 | * please see its website. |
||
| 9 | * TrueType fonts supplied by www.LarabieFonts.com |
||
| 10 | * |
||
| 11 | * Simple Machines Forum (SMF) |
||
| 12 | * |
||
| 13 | * @package SMF |
||
| 14 | * @author Simple Machines http://www.simplemachines.org |
||
| 15 | * @copyright 2017 Simple Machines and individual contributors |
||
| 16 | * @license http://www.simplemachines.org/about/smf/license.php BSD |
||
| 17 | * |
||
| 18 | * @version 2.1 Beta 4 |
||
| 19 | */ |
||
| 20 | |||
| 21 | if (!defined('SMF')) |
||
| 22 | die('No direct access...'); |
||
| 23 | |||
| 24 | /** |
||
| 25 | * downloads a file from a url and stores it locally for avatar use by id_member. |
||
| 26 | * - supports GIF, JPG, PNG, BMP and WBMP formats. |
||
| 27 | * - detects if GD2 is available. |
||
| 28 | * - uses resizeImageFile() to resize to max_width by max_height, and saves the result to a file. |
||
| 29 | * - updates the database info for the member's avatar. |
||
| 30 | * - returns whether the download and resize was successful. |
||
| 31 | * |
||
| 32 | * @param string $url The full path to the temporary file |
||
| 33 | * @param int $memID The member ID |
||
| 34 | * @param int $max_width The maximum allowed width for the avatar |
||
| 35 | * @param int $max_height The maximum allowed height for the avatar |
||
| 36 | * @return boolean Whether the download and resize was successful. |
||
| 37 | * |
||
| 38 | */ |
||
| 39 | function downloadAvatar($url, $memID, $max_width, $max_height) |
||
| 40 | { |
||
| 41 | global $modSettings, $sourcedir, $smcFunc; |
||
| 42 | |||
| 43 | $ext = !empty($modSettings['avatar_download_png']) ? 'png' : 'jpeg'; |
||
| 44 | $destName = 'avatar_' . $memID . '_' . time() . '.' . $ext; |
||
| 45 | |||
| 46 | // Just making sure there is a non-zero member. |
||
| 47 | if (empty($memID)) |
||
| 48 | return false; |
||
| 49 | |||
| 50 | require_once($sourcedir . '/ManageAttachments.php'); |
||
| 51 | removeAttachments(array('id_member' => $memID)); |
||
| 52 | |||
| 53 | $id_folder = 1; |
||
| 54 | $avatar_hash = ''; |
||
| 55 | $attachID = $smcFunc['db_insert']('', |
||
| 56 | '{db_prefix}attachments', |
||
| 57 | array( |
||
| 58 | 'id_member' => 'int', 'attachment_type' => 'int', 'filename' => 'string-255', 'file_hash' => 'string-255', 'fileext' => 'string-8', 'size' => 'int', |
||
| 59 | 'id_folder' => 'int', |
||
| 60 | ), |
||
| 61 | array( |
||
| 62 | $memID, 1, $destName, $avatar_hash, $ext, 1, |
||
| 63 | $id_folder, |
||
| 64 | ), |
||
| 65 | array('id_attach'), |
||
| 66 | 1 |
||
| 67 | ); |
||
| 68 | |||
| 69 | // Retain this globally in case the script wants it. |
||
| 70 | $modSettings['new_avatar_data'] = array( |
||
| 71 | 'id' => $attachID, |
||
| 72 | 'filename' => $destName, |
||
| 73 | 'type' => 1, |
||
| 74 | ); |
||
| 75 | |||
| 76 | $destName = $modSettings['custom_avatar_dir'] . '/' . $destName . '.tmp'; |
||
| 77 | |||
| 78 | // Resize it. |
||
| 79 | View Code Duplication | if (!empty($modSettings['avatar_download_png'])) |
|
| 80 | $success = resizeImageFile($url, $destName, $max_width, $max_height, 3); |
||
| 81 | else |
||
| 82 | $success = resizeImageFile($url, $destName, $max_width, $max_height); |
||
| 83 | |||
| 84 | // Remove the .tmp extension. |
||
| 85 | $destName = substr($destName, 0, -4); |
||
| 86 | |||
| 87 | if ($success) |
||
| 88 | { |
||
| 89 | // Remove the .tmp extension from the attachment. |
||
| 90 | if (rename($destName . '.tmp', empty($avatar_hash) ? $destName : $path . '/' . $attachID . '_' . $avatar_hash . '.dat')) |
||
| 91 | { |
||
| 92 | $destName = empty($avatar_hash) ? $destName : $path . '/' . $attachID . '_' . $avatar_hash . '.dat'; |
||
|
0 ignored issues
–
show
|
|||
| 93 | list ($width, $height) = getimagesize($destName); |
||
| 94 | $mime_type = 'image/' . $ext; |
||
| 95 | |||
| 96 | // Write filesize in the database. |
||
| 97 | $smcFunc['db_query']('', ' |
||
| 98 | UPDATE {db_prefix}attachments |
||
| 99 | SET size = {int:filesize}, width = {int:width}, height = {int:height}, |
||
| 100 | mime_type = {string:mime_type} |
||
| 101 | WHERE id_attach = {int:current_attachment}', |
||
| 102 | array( |
||
| 103 | 'filesize' => filesize($destName), |
||
| 104 | 'width' => (int) $width, |
||
| 105 | 'height' => (int) $height, |
||
| 106 | 'current_attachment' => $attachID, |
||
| 107 | 'mime_type' => $mime_type, |
||
| 108 | ) |
||
| 109 | ); |
||
| 110 | return true; |
||
| 111 | } |
||
| 112 | else |
||
| 113 | return false; |
||
| 114 | } |
||
| 115 | else |
||
| 116 | { |
||
| 117 | $smcFunc['db_query']('', ' |
||
| 118 | DELETE FROM {db_prefix}attachments |
||
| 119 | WHERE id_attach = {int:current_attachment}', |
||
| 120 | array( |
||
| 121 | 'current_attachment' => $attachID, |
||
| 122 | ) |
||
| 123 | ); |
||
| 124 | |||
| 125 | @unlink($destName . '.tmp'); |
||
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
|
|||
| 126 | return false; |
||
| 127 | } |
||
| 128 | } |
||
| 129 | |||
| 130 | /** |
||
| 131 | * Create a thumbnail of the given source. |
||
| 132 | * |
||
| 133 | * @uses resizeImageFile() function to achieve the resize. |
||
| 134 | * |
||
| 135 | * @param string $source The name of the source image |
||
| 136 | * @param int $max_width The maximum allowed width |
||
| 137 | * @param int $max_height The maximum allowed height |
||
| 138 | * @return boolean Whether the thumbnail creation was successful. |
||
| 139 | */ |
||
| 140 | function createThumbnail($source, $max_width, $max_height) |
||
| 141 | { |
||
| 142 | global $modSettings; |
||
| 143 | |||
| 144 | $destName = $source . '_thumb.tmp'; |
||
| 145 | |||
| 146 | // Do the actual resize. |
||
| 147 | View Code Duplication | if (!empty($modSettings['attachment_thumb_png'])) |
|
| 148 | $success = resizeImageFile($source, $destName, $max_width, $max_height, 3); |
||
| 149 | else |
||
| 150 | $success = resizeImageFile($source, $destName, $max_width, $max_height); |
||
| 151 | |||
| 152 | // Okay, we're done with the temporary stuff. |
||
| 153 | $destName = substr($destName, 0, -4); |
||
| 154 | |||
| 155 | if ($success && @rename($destName . '.tmp', $destName)) |
||
| 156 | return true; |
||
| 157 | else |
||
| 158 | { |
||
| 159 | @unlink($destName . '.tmp'); |
||
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
|
|||
| 160 | @touch($destName); |
||
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
|
|||
| 161 | return false; |
||
| 162 | } |
||
| 163 | } |
||
| 164 | |||
| 165 | /** |
||
| 166 | * Used to re-econodes an image to a specified image format |
||
| 167 | * - creates a copy of the file at the same location as fileName. |
||
| 168 | * - the file would have the format preferred_format if possible, otherwise the default format is jpeg. |
||
| 169 | * - the function makes sure that all non-essential image contents are disposed. |
||
| 170 | * |
||
| 171 | * @param string $fileName The path to the file |
||
| 172 | * @param int $preferred_format The preferred format - 0 to automatically determine, 1 for gif, 2 for jpg, 3 for png, 6 for bmp and 15 for wbmp |
||
| 173 | * @return boolean Whether the reencoding was successful |
||
| 174 | */ |
||
| 175 | function reencodeImage($fileName, $preferred_format = 0) |
||
| 176 | { |
||
| 177 | if (!resizeImageFile($fileName, $fileName . '.tmp', null, null, $preferred_format)) |
||
| 178 | { |
||
| 179 | if (file_exists($fileName . '.tmp')) |
||
| 180 | unlink($fileName . '.tmp'); |
||
| 181 | |||
| 182 | return false; |
||
| 183 | } |
||
| 184 | |||
| 185 | if (!unlink($fileName)) |
||
| 186 | return false; |
||
| 187 | |||
| 188 | if (!rename($fileName . '.tmp', $fileName)) |
||
| 189 | return false; |
||
| 190 | } |
||
| 191 | |||
| 192 | /** |
||
| 193 | * Searches through the file to see if there's potentially harmful non-binary content. |
||
| 194 | * - if extensiveCheck is true, searches for asp/php short tags as well. |
||
| 195 | * |
||
| 196 | * @param string $fileName The path to the file |
||
| 197 | * @param bool $extensiveCheck Whether to perform extensive checks |
||
| 198 | * @return bool Whether the image appears to be safe |
||
| 199 | */ |
||
| 200 | function checkImageContents($fileName, $extensiveCheck = false) |
||
| 201 | { |
||
| 202 | $fp = fopen($fileName, 'rb'); |
||
| 203 | if (!$fp) |
||
| 204 | fatal_lang_error('attach_timeout'); |
||
| 205 | |||
| 206 | $prev_chunk = ''; |
||
| 207 | while (!feof($fp)) |
||
| 208 | { |
||
| 209 | $cur_chunk = fread($fp, 8192); |
||
| 210 | |||
| 211 | // Though not exhaustive lists, better safe than sorry. |
||
| 212 | if (!empty($extensiveCheck)) |
||
| 213 | { |
||
| 214 | // Paranoid check. Use this if you have reason to distrust your host's security config. |
||
| 215 | // Will result in MANY false positives, and is not suitable for photography sites. |
||
| 216 | if (preg_match('~(iframe|\\<\\?|\\<%|html|eval|body|script\W|(?-i)[CFZ]WS[\x01-\x0E])~i', $prev_chunk . $cur_chunk) === 1) |
||
| 217 | { |
||
| 218 | fclose($fp); |
||
| 219 | return false; |
||
| 220 | } |
||
| 221 | } |
||
| 222 | else |
||
| 223 | { |
||
| 224 | // Check for potential infection - focus on clues for inline php & flash. |
||
| 225 | // Will result in significantly fewer false positives than the paranoid check. |
||
| 226 | if (preg_match('~(\\<\\?php\s|(?-i)[CFZ]WS[\x01-\x0E])~i', $prev_chunk . $cur_chunk) === 1) |
||
| 227 | { |
||
| 228 | fclose($fp); |
||
| 229 | return false; |
||
| 230 | } |
||
| 231 | } |
||
| 232 | $prev_chunk = $cur_chunk; |
||
| 233 | } |
||
| 234 | fclose($fp); |
||
| 235 | |||
| 236 | return true; |
||
| 237 | } |
||
| 238 | |||
| 239 | /** |
||
| 240 | * Sets a global $gd2 variable needed by some functions to determine |
||
| 241 | * whether the GD2 library is present. |
||
| 242 | * |
||
| 243 | * @return bool Whether or not GD1 is available. |
||
| 244 | */ |
||
| 245 | function checkGD() |
||
| 246 | { |
||
| 247 | global $gd2; |
||
| 248 | |||
| 249 | // Check to see if GD is installed and what version. |
||
| 250 | if (($extensionFunctions = get_extension_funcs('gd')) === false) |
||
| 251 | return false; |
||
| 252 | |||
| 253 | // Also determine if GD2 is installed and store it in a global. |
||
| 254 | $gd2 = in_array('imagecreatetruecolor', $extensionFunctions) && function_exists('imagecreatetruecolor'); |
||
| 255 | |||
| 256 | return true; |
||
| 257 | } |
||
| 258 | |||
| 259 | /** |
||
| 260 | * Checks whether the Imagick class is present. |
||
| 261 | * |
||
| 262 | * @return bool Whether or not the Imagick extension is available. |
||
| 263 | */ |
||
| 264 | function checkImagick() |
||
| 265 | { |
||
| 266 | return class_exists('Imagick', false); |
||
| 267 | } |
||
| 268 | |||
| 269 | /** |
||
| 270 | * Checks whether the MagickWand extension is present. |
||
| 271 | * |
||
| 272 | * @return bool Whether or not the MagickWand extension is available. |
||
| 273 | */ |
||
| 274 | function checkMagickWand() |
||
| 275 | { |
||
| 276 | return function_exists('newMagickWand'); |
||
| 277 | } |
||
| 278 | |||
| 279 | /** |
||
| 280 | * See if we have enough memory to thumbnail an image |
||
| 281 | * |
||
| 282 | * @param array $sizes image size |
||
| 283 | * @return bool Whether we do |
||
| 284 | */ |
||
| 285 | function imageMemoryCheck($sizes) |
||
| 286 | { |
||
| 287 | global $modSettings; |
||
| 288 | |||
| 289 | // doing the old 'set it and hope' way? |
||
| 290 | if (empty($modSettings['attachment_thumb_memory'])) |
||
| 291 | { |
||
| 292 | setMemoryLimit('128M'); |
||
| 293 | return true; |
||
| 294 | } |
||
| 295 | |||
| 296 | // Determine the memory requirements for this image, note: if you want to use an image formula W x H x bits/8 x channels x Overhead factor |
||
| 297 | // you will need to account for single bit images as GD expands them to an 8 bit and will greatly overun the calculated value. The 5 is |
||
| 298 | // simply a shortcut of 8bpp, 3 channels, 1.66 overhead |
||
| 299 | $needed_memory = ($sizes[0] * $sizes[1] * 5); |
||
| 300 | |||
| 301 | // if we need more, lets try to get it |
||
| 302 | return setMemoryLimit($needed_memory, true); |
||
| 303 | } |
||
| 304 | |||
| 305 | /** |
||
| 306 | * Resizes an image from a remote location or a local file. |
||
| 307 | * Puts the resized image at the destination location. |
||
| 308 | * The file would have the format preferred_format if possible, |
||
| 309 | * otherwise the default format is jpeg. |
||
| 310 | * |
||
| 311 | * @param string $source The path to the source image |
||
| 312 | * @param string $destination The path to the destination image |
||
| 313 | * @param int $max_width The maximum allowed width |
||
| 314 | * @param int $max_height The maximum allowed height |
||
| 315 | * @param int $preferred_format - The preferred format (0 to use jpeg, 1 for gif, 2 to force jpeg, 3 for png, 6 for bmp and 15 for wbmp) |
||
| 316 | * @return bool Whether it succeeded. |
||
| 317 | */ |
||
| 318 | function resizeImageFile($source, $destination, $max_width, $max_height, $preferred_format = 0) |
||
| 319 | { |
||
| 320 | global $sourcedir; |
||
| 321 | |||
| 322 | // Nothing to do without GD or IM/MW |
||
| 323 | if (!checkGD() && !checkImagick() && !checkMagickWand()) |
||
| 324 | return false; |
||
| 325 | |||
| 326 | static $default_formats = array( |
||
| 327 | '1' => 'gif', |
||
| 328 | '2' => 'jpeg', |
||
| 329 | '3' => 'png', |
||
| 330 | '6' => 'bmp', |
||
| 331 | '15' => 'wbmp' |
||
| 332 | ); |
||
| 333 | |||
| 334 | require_once($sourcedir . '/Subs-Package.php'); |
||
| 335 | |||
| 336 | // Get the image file, we have to work with something after all |
||
| 337 | $fp_destination = fopen($destination, 'wb'); |
||
| 338 | if ($fp_destination && (substr($source, 0, 7) == 'http://' || substr($source, 0, 8) == 'https://')) |
||
| 339 | { |
||
| 340 | $fileContents = fetch_web_data($source); |
||
| 341 | |||
| 342 | fwrite($fp_destination, $fileContents); |
||
| 343 | fclose($fp_destination); |
||
| 344 | |||
| 345 | $sizes = @getimagesize($destination); |
||
| 346 | } |
||
| 347 | elseif ($fp_destination) |
||
| 348 | { |
||
| 349 | $sizes = @getimagesize($source); |
||
| 350 | |||
| 351 | $fp_source = fopen($source, 'rb'); |
||
| 352 | if ($fp_source !== false) |
||
| 353 | { |
||
| 354 | while (!feof($fp_source)) |
||
| 355 | fwrite($fp_destination, fread($fp_source, 8192)); |
||
| 356 | fclose($fp_source); |
||
| 357 | } |
||
| 358 | else |
||
| 359 | $sizes = array(-1, -1, -1); |
||
| 360 | fclose($fp_destination); |
||
| 361 | } |
||
| 362 | // We can't get to the file. |
||
| 363 | else |
||
| 364 | $sizes = array(-1, -1, -1); |
||
| 365 | |||
| 366 | // See if we have -or- can get the needed memory for this operation |
||
| 367 | // ImageMagick isn't subject to PHP's memory limits :) |
||
| 368 | if (!(checkIMagick() || checkMagickWand()) && checkGD() && !imageMemoryCheck($sizes)) |
||
| 369 | return false; |
||
| 370 | |||
| 371 | // A known and supported format? |
||
| 372 | // @todo test PSD and gif. |
||
| 373 | if ((checkImagick() || checkMagickWand()) && isset($default_formats[$sizes[2]])) |
||
| 374 | { |
||
| 375 | return resizeImage(null, $destination, null, null, $max_width, $max_height, true, $preferred_format); |
||
| 376 | } |
||
| 377 | elseif (checkGD() && isset($default_formats[$sizes[2]]) && function_exists('imagecreatefrom' . $default_formats[$sizes[2]])) |
||
| 378 | { |
||
| 379 | $imagecreatefrom = 'imagecreatefrom' . $default_formats[$sizes[2]]; |
||
| 380 | if ($src_img = @$imagecreatefrom($destination)) |
||
| 381 | { |
||
| 382 | return resizeImage($src_img, $destination, imagesx($src_img), imagesy($src_img), $max_width === null ? imagesx($src_img) : $max_width, $max_height === null ? imagesy($src_img) : $max_height, true, $preferred_format); |
||
| 383 | } |
||
| 384 | } |
||
| 385 | |||
| 386 | return false; |
||
| 387 | } |
||
| 388 | |||
| 389 | /** |
||
| 390 | * Resizes src_img proportionally to fit within max_width and max_height limits |
||
| 391 | * if it is too large. |
||
| 392 | * If GD2 is present, it'll use it to achieve better quality. |
||
| 393 | * It saves the new image to destination_filename, as preferred_format |
||
| 394 | * if possible, default is jpeg. |
||
| 395 | * @uses Imagemagick (IMagick or MagickWand extension) or GD |
||
| 396 | * |
||
| 397 | * @param resource $src_img The source image |
||
| 398 | * @param string $destName The path to the destination image |
||
| 399 | * @param int $src_width The width of the source image |
||
| 400 | * @param int $src_height The height of the source image |
||
| 401 | * @param int $max_width The maximum allowed width |
||
| 402 | * @param int $max_height The maximum allowed height |
||
| 403 | * @param bool $force_resize = false Whether to forcibly resize it |
||
| 404 | * @param int $preferred_format - 1 for gif, 2 for jpeg, 3 for png, 6 for bmp or 15 for wbmp |
||
| 405 | * @return bool Whether the resize was successful |
||
| 406 | */ |
||
| 407 | function resizeImage($src_img, $destName, $src_width, $src_height, $max_width, $max_height, $force_resize = false, $preferred_format = 0) |
||
| 408 | { |
||
| 409 | global $gd2, $modSettings; |
||
| 410 | |||
| 411 | if (checkImagick() || checkMagickWand()) |
||
| 412 | { |
||
| 413 | static $default_formats = array( |
||
| 414 | '1' => 'gif', |
||
| 415 | '2' => 'jpeg', |
||
| 416 | '3' => 'png', |
||
| 417 | '6' => 'bmp', |
||
| 418 | '15' => 'wbmp' |
||
| 419 | ); |
||
| 420 | $preferred_format = empty($preferred_format) || !isset($default_formats[$preferred_format]) ? 2 : $preferred_format; |
||
| 421 | |||
| 422 | if (checkImagick()) |
||
| 423 | { |
||
| 424 | $imagick = New Imagick($destName); |
||
| 425 | $src_width = empty($src_width) ? $imagick->getImageWidth() : $src_width; |
||
| 426 | $src_height = empty($src_height) ? $imagick->getImageHeight() : $src_height; |
||
| 427 | $dest_width = empty($max_width) ? $src_width : $max_width; |
||
| 428 | $dest_height = empty($max_height) ? $src_height : $max_height; |
||
| 429 | |||
| 430 | if ($default_formats[$preferred_format] == 'jpeg') |
||
| 431 | $imagick->setCompressionQuality(!empty($modSettings['avatar_jpeg_quality']) ? $modSettings['avatar_jpeg_quality'] : 82); |
||
| 432 | |||
| 433 | $imagick->setImageFormat($default_formats[$preferred_format]); |
||
| 434 | $imagick->resizeImage($dest_width, $dest_height, Imagick::FILTER_LANCZOS, 1, true); |
||
| 435 | $success = $imagick->writeImage($destName); |
||
| 436 | } |
||
| 437 | else |
||
| 438 | { |
||
| 439 | $magick_wand = newMagickWand(); |
||
| 440 | MagickReadImage($magick_wand, $destName); |
||
| 441 | $src_width = empty($src_width) ? MagickGetImageWidth($magick_wand) : $src_width; |
||
| 442 | $src_height = empty($src_height) ? MagickGetImageSize($magick_wand) : $src_height; |
||
| 443 | $dest_width = empty($max_width) ? $src_width : $max_width; |
||
| 444 | $dest_height = empty($max_height) ? $src_height : $max_height; |
||
| 445 | |||
| 446 | if ($default_formats[$preferred_format] == 'jpeg') |
||
| 447 | MagickSetCompressionQuality($magick_wand, !empty($modSettings['avatar_jpeg_quality']) ? $modSettings['avatar_jpeg_quality'] : 82); |
||
| 448 | |||
| 449 | MagickSetImageFormat($magick_wand, $default_formats[$preferred_format]); |
||
| 450 | MagickResizeImage($magick_wand, $dest_width, $dest_height, MW_LanczosFilter, 1, true); |
||
| 451 | $success = MagickWriteImage($magick_wand, $destName); |
||
| 452 | } |
||
| 453 | |||
| 454 | return !empty($success); |
||
| 455 | } |
||
| 456 | elseif (checkGD()) |
||
| 457 | { |
||
| 458 | $success = false; |
||
| 459 | |||
| 460 | // Determine whether to resize to max width or to max height (depending on the limits.) |
||
| 461 | if (!empty($max_width) || !empty($max_height)) |
||
| 462 | { |
||
| 463 | if (!empty($max_width) && (empty($max_height) || round($src_height * $max_width / $src_width) <= $max_height)) |
||
| 464 | { |
||
| 465 | $dst_width = $max_width; |
||
| 466 | $dst_height = round($src_height * $max_width / $src_width); |
||
| 467 | } |
||
| 468 | elseif (!empty($max_height)) |
||
| 469 | { |
||
| 470 | $dst_width = round($src_width * $max_height / $src_height); |
||
| 471 | $dst_height = $max_height; |
||
| 472 | } |
||
| 473 | |||
| 474 | // Don't bother resizing if it's already smaller... |
||
| 475 | if (!empty($dst_width) && !empty($dst_height) && ($dst_width < $src_width || $dst_height < $src_height || $force_resize)) |
||
| 476 | { |
||
| 477 | // (make a true color image, because it just looks better for resizing.) |
||
| 478 | if ($gd2) |
||
| 479 | { |
||
| 480 | $dst_img = imagecreatetruecolor($dst_width, $dst_height); |
||
| 481 | |||
| 482 | // Deal nicely with a PNG - because we can. |
||
| 483 | if ((!empty($preferred_format)) && ($preferred_format == 3)) |
||
| 484 | { |
||
| 485 | imagealphablending($dst_img, false); |
||
| 486 | if (function_exists('imagesavealpha')) |
||
| 487 | imagesavealpha($dst_img, true); |
||
| 488 | } |
||
| 489 | } |
||
| 490 | else |
||
| 491 | $dst_img = imagecreate($dst_width, $dst_height); |
||
| 492 | |||
| 493 | // Resize it! |
||
| 494 | if ($gd2) |
||
| 495 | imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $dst_width, $dst_height, $src_width, $src_height); |
||
| 496 | else |
||
| 497 | imagecopyresamplebicubic($dst_img, $src_img, 0, 0, 0, 0, $dst_width, $dst_height, $src_width, $src_height); |
||
| 498 | } |
||
| 499 | else |
||
| 500 | $dst_img = $src_img; |
||
| 501 | } |
||
| 502 | else |
||
| 503 | $dst_img = $src_img; |
||
| 504 | |||
| 505 | // Save the image as ... |
||
| 506 | if (!empty($preferred_format) && ($preferred_format == 3) && function_exists('imagepng')) |
||
| 507 | $success = imagepng($dst_img, $destName); |
||
| 508 | elseif (!empty($preferred_format) && ($preferred_format == 1) && function_exists('imagegif')) |
||
| 509 | $success = imagegif($dst_img, $destName); |
||
| 510 | elseif (function_exists('imagejpeg')) |
||
| 511 | $success = imagejpeg($dst_img, $destName, !empty($modSettings['avatar_jpeg_quality']) ? $modSettings['avatar_jpeg_quality'] : 82); |
||
| 512 | |||
| 513 | // Free the memory. |
||
| 514 | imagedestroy($src_img); |
||
| 515 | if ($dst_img != $src_img) |
||
| 516 | imagedestroy($dst_img); |
||
| 517 | |||
| 518 | return $success; |
||
| 519 | } |
||
| 520 | else |
||
| 521 | // Without GD, no image resizing at all. |
||
| 522 | return false; |
||
| 523 | } |
||
| 524 | |||
| 525 | /** |
||
| 526 | * Copy image. |
||
| 527 | * Used when imagecopyresample() is not available. |
||
| 528 | |||
| 529 | * @param resource $dst_img The destination image - a GD image resource |
||
| 530 | * @param resource $src_img The source image - a GD image resource |
||
| 531 | * @param int $dst_x The "x" coordinate of the destination image |
||
| 532 | * @param int $dst_y The "y" coordinate of the destination image |
||
| 533 | * @param int $src_x The "x" coordinate of the source image |
||
| 534 | * @param int $src_y The "y" coordinate of the source image |
||
| 535 | * @param int $dst_w The width of the destination image |
||
| 536 | * @param int $dst_h The height of the destination image |
||
| 537 | * @param int $src_w The width of the destination image |
||
| 538 | * @param int $src_h The height of the destination image |
||
| 539 | */ |
||
| 540 | function imagecopyresamplebicubic($dst_img, $src_img, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) |
||
| 541 | { |
||
| 542 | $palsize = imagecolorstotal($src_img); |
||
| 543 | for ($i = 0; $i < $palsize; $i++) |
||
| 544 | { |
||
| 545 | $colors = imagecolorsforindex($src_img, $i); |
||
| 546 | imagecolorallocate($dst_img, $colors['red'], $colors['green'], $colors['blue']); |
||
| 547 | } |
||
| 548 | |||
| 549 | $scaleX = ($src_w - 1) / $dst_w; |
||
| 550 | $scaleY = ($src_h - 1) / $dst_h; |
||
| 551 | |||
| 552 | $scaleX2 = (int) $scaleX / 2; |
||
| 553 | $scaleY2 = (int) $scaleY / 2; |
||
| 554 | |||
| 555 | for ($j = $src_y; $j < $dst_h; $j++) |
||
| 556 | { |
||
| 557 | $sY = (int) $j * $scaleY; |
||
| 558 | $y13 = $sY + $scaleY2; |
||
| 559 | |||
| 560 | for ($i = $src_x; $i < $dst_w; $i++) |
||
| 561 | { |
||
| 562 | $sX = (int) $i * $scaleX; |
||
| 563 | $x34 = $sX + $scaleX2; |
||
| 564 | |||
| 565 | $color1 = imagecolorsforindex($src_img, imagecolorat($src_img, $sX, $y13)); |
||
| 566 | $color2 = imagecolorsforindex($src_img, imagecolorat($src_img, $sX, $sY)); |
||
| 567 | $color3 = imagecolorsforindex($src_img, imagecolorat($src_img, $x34, $y13)); |
||
| 568 | $color4 = imagecolorsforindex($src_img, imagecolorat($src_img, $x34, $sY)); |
||
| 569 | |||
| 570 | $red = ($color1['red'] + $color2['red'] + $color3['red'] + $color4['red']) / 4; |
||
| 571 | $green = ($color1['green'] + $color2['green'] + $color3['green'] + $color4['green']) / 4; |
||
| 572 | $blue = ($color1['blue'] + $color2['blue'] + $color3['blue'] + $color4['blue']) / 4; |
||
| 573 | |||
| 574 | $color = imagecolorresolve($dst_img, $red, $green, $blue); |
||
| 575 | if ($color == -1) |
||
| 576 | { |
||
| 577 | if ($palsize++ < 256) |
||
| 578 | imagecolorallocate($dst_img, $red, $green, $blue); |
||
| 579 | $color = imagecolorclosest($dst_img, $red, $green, $blue); |
||
| 580 | } |
||
| 581 | |||
| 582 | imagesetpixel($dst_img, $i + $dst_x - $src_x, $j + $dst_y - $src_y, $color); |
||
| 583 | } |
||
| 584 | } |
||
| 585 | } |
||
| 586 | |||
| 587 | if (!function_exists('imagecreatefrombmp')) |
||
| 588 | { |
||
| 589 | /** |
||
| 590 | * It is set only if it doesn't already exist (for forwards compatiblity.) |
||
| 591 | * It only supports uncompressed bitmaps. |
||
| 592 | * |
||
| 593 | * @param string $filename The name of the file |
||
| 594 | * @return resource An image identifier representing the bitmap image |
||
| 595 | * obtained from the given filename. |
||
| 596 | */ |
||
| 597 | function imagecreatefrombmp($filename) |
||
| 598 | { |
||
| 599 | global $gd2; |
||
| 600 | |||
| 601 | $fp = fopen($filename, 'rb'); |
||
| 602 | |||
| 603 | $errors = error_reporting(0); |
||
| 604 | |||
| 605 | $header = unpack('vtype/Vsize/Vreserved/Voffset', fread($fp, 14)); |
||
| 606 | $info = unpack('Vsize/Vwidth/Vheight/vplanes/vbits/Vcompression/Vimagesize/Vxres/Vyres/Vncolor/Vcolorimportant', fread($fp, 40)); |
||
| 607 | |||
| 608 | if ($header['type'] != 0x4D42) |
||
| 609 | return false; |
||
| 610 | |||
| 611 | if ($gd2) |
||
| 612 | $dst_img = imagecreatetruecolor($info['width'], $info['height']); |
||
| 613 | else |
||
| 614 | $dst_img = imagecreate($info['width'], $info['height']); |
||
| 615 | |||
| 616 | $palette_size = $header['offset'] - 54; |
||
| 617 | $info['ncolor'] = $palette_size / 4; |
||
| 618 | |||
| 619 | $palette = array(); |
||
| 620 | |||
| 621 | $palettedata = fread($fp, $palette_size); |
||
| 622 | $n = 0; |
||
| 623 | for ($j = 0; $j < $palette_size; $j++) |
||
| 624 | { |
||
| 625 | $b = ord($palettedata{$j++}); |
||
| 626 | $g = ord($palettedata{$j++}); |
||
| 627 | $r = ord($palettedata{$j++}); |
||
| 628 | |||
| 629 | $palette[$n++] = imagecolorallocate($dst_img, $r, $g, $b); |
||
| 630 | } |
||
| 631 | |||
| 632 | $scan_line_size = ($info['bits'] * $info['width'] + 7) >> 3; |
||
| 633 | $scan_line_align = $scan_line_size & 3 ? 4 - ($scan_line_size & 3) : 0; |
||
| 634 | |||
| 635 | for ($y = 0, $l = $info['height'] - 1; $y < $info['height']; $y++, $l--) |
||
| 636 | { |
||
| 637 | fseek($fp, $header['offset'] + ($scan_line_size + $scan_line_align) * $l); |
||
| 638 | $scan_line = fread($fp, $scan_line_size); |
||
| 639 | |||
| 640 | if (strlen($scan_line) < $scan_line_size) |
||
| 641 | continue; |
||
| 642 | |||
| 643 | if ($info['bits'] == 32) |
||
| 644 | { |
||
| 645 | $x = 0; |
||
| 646 | View Code Duplication | for ($j = 0; $j < $scan_line_size; $x++) |
|
| 647 | { |
||
| 648 | $b = ord($scan_line{$j++}); |
||
| 649 | $g = ord($scan_line{$j++}); |
||
| 650 | $r = ord($scan_line{$j++}); |
||
| 651 | $j++; |
||
| 652 | |||
| 653 | $color = imagecolorexact($dst_img, $r, $g, $b); |
||
| 654 | if ($color == -1) |
||
| 655 | { |
||
| 656 | $color = imagecolorallocate($dst_img, $r, $g, $b); |
||
| 657 | |||
| 658 | // Gah! Out of colors? Stupid GD 1... try anyhow. |
||
| 659 | if ($color == -1) |
||
| 660 | $color = imagecolorclosest($dst_img, $r, $g, $b); |
||
| 661 | } |
||
| 662 | |||
| 663 | imagesetpixel($dst_img, $x, $y, $color); |
||
| 664 | } |
||
| 665 | } |
||
| 666 | elseif ($info['bits'] == 24) |
||
| 667 | { |
||
| 668 | $x = 0; |
||
| 669 | View Code Duplication | for ($j = 0; $j < $scan_line_size; $x++) |
|
| 670 | { |
||
| 671 | $b = ord($scan_line{$j++}); |
||
| 672 | $g = ord($scan_line{$j++}); |
||
| 673 | $r = ord($scan_line{$j++}); |
||
| 674 | |||
| 675 | $color = imagecolorexact($dst_img, $r, $g, $b); |
||
| 676 | if ($color == -1) |
||
| 677 | { |
||
| 678 | $color = imagecolorallocate($dst_img, $r, $g, $b); |
||
| 679 | |||
| 680 | // Gah! Out of colors? Stupid GD 1... try anyhow. |
||
| 681 | if ($color == -1) |
||
| 682 | $color = imagecolorclosest($dst_img, $r, $g, $b); |
||
| 683 | } |
||
| 684 | |||
| 685 | imagesetpixel($dst_img, $x, $y, $color); |
||
| 686 | } |
||
| 687 | } |
||
| 688 | elseif ($info['bits'] == 16) |
||
| 689 | { |
||
| 690 | $x = 0; |
||
| 691 | for ($j = 0; $j < $scan_line_size; $x++) |
||
| 692 | { |
||
| 693 | $b1 = ord($scan_line{$j++}); |
||
| 694 | $b2 = ord($scan_line{$j++}); |
||
| 695 | |||
| 696 | $word = $b2 * 256 + $b1; |
||
| 697 | |||
| 698 | $b = (($word & 31) * 255) / 31; |
||
| 699 | $g = ((($word >> 5) & 31) * 255) / 31; |
||
| 700 | $r = ((($word >> 10) & 31) * 255) / 31; |
||
| 701 | |||
| 702 | // Scale the image colors up properly. |
||
| 703 | $color = imagecolorexact($dst_img, $r, $g, $b); |
||
| 704 | if ($color == -1) |
||
| 705 | { |
||
| 706 | $color = imagecolorallocate($dst_img, $r, $g, $b); |
||
| 707 | |||
| 708 | // Gah! Out of colors? Stupid GD 1... try anyhow. |
||
| 709 | if ($color == -1) |
||
| 710 | $color = imagecolorclosest($dst_img, $r, $g, $b); |
||
| 711 | } |
||
| 712 | |||
| 713 | imagesetpixel($dst_img, $x, $y, $color); |
||
| 714 | } |
||
| 715 | } |
||
| 716 | elseif ($info['bits'] == 8) |
||
| 717 | { |
||
| 718 | $x = 0; |
||
| 719 | for ($j = 0; $j < $scan_line_size; $x++) |
||
| 720 | imagesetpixel($dst_img, $x, $y, $palette[ord($scan_line{$j++})]); |
||
| 721 | } |
||
| 722 | elseif ($info['bits'] == 4) |
||
| 723 | { |
||
| 724 | $x = 0; |
||
| 725 | for ($j = 0; $j < $scan_line_size; $x++) |
||
| 726 | { |
||
| 727 | $byte = ord($scan_line{$j++}); |
||
| 728 | |||
| 729 | imagesetpixel($dst_img, $x, $y, $palette[(int) ($byte / 16)]); |
||
| 730 | View Code Duplication | if (++$x < $info['width']) |
|
| 731 | imagesetpixel($dst_img, $x, $y, $palette[$byte & 15]); |
||
| 732 | } |
||
| 733 | } |
||
| 734 | elseif ($info['bits'] == 1) |
||
| 735 | { |
||
| 736 | $x = 0; |
||
| 737 | for ($j = 0; $j < $scan_line_size; $x++) |
||
| 738 | { |
||
| 739 | $byte = ord($scan_line{$j++}); |
||
| 740 | |||
| 741 | imagesetpixel($dst_img, $x, $y, $palette[(($byte) & 128) != 0]); |
||
| 742 | for ($shift = 1; $shift < 8; $shift++) { |
||
| 743 | View Code Duplication | if (++$x < $info['width']) imagesetpixel($dst_img, $x, $y, $palette[(($byte << $shift) & 128) != 0]); |
|
| 744 | } |
||
| 745 | } |
||
| 746 | } |
||
| 747 | } |
||
| 748 | |||
| 749 | fclose($fp); |
||
| 750 | |||
| 751 | error_reporting($errors); |
||
| 752 | |||
| 753 | return $dst_img; |
||
| 754 | } |
||
| 755 | } |
||
| 756 | |||
| 757 | /** |
||
| 758 | * Writes a gif file to disk as a png file. |
||
| 759 | |||
| 760 | * @param resource $gif A gif image resource |
||
| 761 | * @param string $lpszFileName The name of the file |
||
| 762 | * @param int $background_color The background color |
||
| 763 | * @return boolean Whether the operation was successful |
||
| 764 | */ |
||
| 765 | function gif_outputAsPng($gif, $lpszFileName, $background_color = -1) |
||
| 766 | { |
||
| 767 | if (!isset($gif) || @get_class($gif) != 'cgif' || !$gif->loaded || $lpszFileName == '') |
||
| 768 | return false; |
||
| 769 | |||
| 770 | $fd = $gif->get_png_data($background_color); |
||
|
0 ignored issues
–
show
|
|||
| 771 | if (strlen($fd) <= 0) |
||
| 772 | return false; |
||
| 773 | |||
| 774 | if (!($fh = @fopen($lpszFileName, 'wb'))) |
||
| 775 | return false; |
||
| 776 | |||
| 777 | @fwrite($fh, $fd, strlen($fd)); |
||
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
|
|||
| 778 | @fflush($fh); |
||
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
|
|||
| 779 | @fclose($fh); |
||
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
|
|||
| 780 | |||
| 781 | return true; |
||
| 782 | } |
||
| 783 | |||
| 784 | /** |
||
| 785 | * Show an image containing the visual verification code for registration. |
||
| 786 | * Requires the GD extension. |
||
| 787 | * Uses a random font for each letter from default_theme_dir/fonts. |
||
| 788 | * Outputs a gif or a png (depending on whether gif ix supported). |
||
| 789 | * |
||
| 790 | * @param string $code The code to display |
||
| 791 | * @return void|false False if something goes wrong. |
||
| 792 | */ |
||
| 793 | function showCodeImage($code) |
||
| 794 | { |
||
| 795 | global $gd2, $settings, $user_info, $modSettings; |
||
| 796 | |||
| 797 | // Note: The higher the value of visual_verification_type the harder the verification is - from 0 as disabled through to 4 as "Very hard". |
||
| 798 | |||
| 799 | // What type are we going to be doing? |
||
| 800 | $imageType = $modSettings['visual_verification_type']; |
||
| 801 | // Special case to allow the admin center to show samples. |
||
| 802 | if ($user_info['is_admin'] && isset($_GET['type'])) |
||
| 803 | $imageType = (int) $_GET['type']; |
||
| 804 | |||
| 805 | // Some quick references for what we do. |
||
| 806 | // Do we show no, low or high noise? |
||
| 807 | $noiseType = $imageType == 3 ? 'low' : ($imageType == 4 ? 'high' : ($imageType == 5 ? 'extreme' : 'none')); |
||
| 808 | // Can we have more than one font in use? |
||
| 809 | $varyFonts = $imageType > 3 ? true : false; |
||
| 810 | // Just a plain white background? |
||
| 811 | $simpleBGColor = $imageType < 3 ? true : false; |
||
| 812 | // Plain black foreground? |
||
| 813 | $simpleFGColor = $imageType == 0 ? true : false; |
||
| 814 | // High much to rotate each character. |
||
| 815 | $rotationType = $imageType == 1 ? 'none' : ($imageType > 3 ? 'low' : 'high'); |
||
| 816 | // Do we show some characters inversed? |
||
| 817 | $showReverseChars = $imageType > 3 ? true : false; |
||
| 818 | // Special case for not showing any characters. |
||
| 819 | $disableChars = $imageType == 0 ? true : false; |
||
| 820 | // What do we do with the font colors. Are they one color, close to one color or random? |
||
| 821 | $fontColorType = $imageType == 1 ? 'plain' : ($imageType > 3 ? 'random' : 'cyclic'); |
||
| 822 | // Are the fonts random sizes? |
||
| 823 | $fontSizeRandom = $imageType > 3 ? true : false; |
||
| 824 | // How much space between characters? |
||
| 825 | $fontHorSpace = $imageType > 3 ? 'high' : ($imageType == 1 ? 'medium' : 'minus'); |
||
| 826 | // Where do characters sit on the image? (Fixed position or random/very random) |
||
| 827 | $fontVerPos = $imageType == 1 ? 'fixed' : ($imageType > 3 ? 'vrandom' : 'random'); |
||
| 828 | // Make font semi-transparent? |
||
| 829 | $fontTrans = $imageType == 2 || $imageType == 3 ? true : false; |
||
| 830 | // Give the image a border? |
||
| 831 | $hasBorder = $simpleBGColor; |
||
| 832 | |||
| 833 | // The amount of pixels inbetween characters. |
||
| 834 | $character_spacing = 1; |
||
| 835 | |||
| 836 | // What color is the background - generally white unless we're on "hard". |
||
| 837 | if ($simpleBGColor) |
||
| 838 | $background_color = array(255, 255, 255); |
||
| 839 | else |
||
| 840 | $background_color = isset($settings['verification_background']) ? $settings['verification_background'] : array(236, 237, 243); |
||
| 841 | |||
| 842 | // The color of the characters shown (red, green, blue). |
||
| 843 | if ($simpleFGColor) |
||
| 844 | $foreground_color = array(0, 0, 0); |
||
| 845 | else |
||
| 846 | { |
||
| 847 | $foreground_color = array(64, 101, 136); |
||
| 848 | |||
| 849 | // Has the theme author requested a custom color? |
||
| 850 | if (isset($settings['verification_foreground'])) |
||
| 851 | $foreground_color = $settings['verification_foreground']; |
||
| 852 | } |
||
| 853 | |||
| 854 | if (!is_dir($settings['default_theme_dir'] . '/fonts')) |
||
| 855 | return false; |
||
| 856 | |||
| 857 | // Get a list of the available fonts. |
||
| 858 | $font_dir = dir($settings['default_theme_dir'] . '/fonts'); |
||
| 859 | $font_list = array(); |
||
| 860 | $ttfont_list = array(); |
||
| 861 | $endian = unpack('v', pack('S', 0x00FF)) === 0x00FF; |
||
| 862 | while ($entry = $font_dir->read()) |
||
| 863 | { |
||
| 864 | if (preg_match('~^(.+)\.gdf$~', $entry, $matches) === 1) |
||
| 865 | { |
||
| 866 | if ($endian ^ (strpos($entry, '_end.gdf') === false)) |
||
| 867 | $font_list[] = $entry; |
||
| 868 | } |
||
| 869 | elseif (preg_match('~^(.+)\.ttf$~', $entry, $matches) === 1) |
||
| 870 | $ttfont_list[] = $entry; |
||
| 871 | } |
||
| 872 | |||
| 873 | if (empty($font_list)) |
||
| 874 | return false; |
||
| 875 | |||
| 876 | // For non-hard things don't even change fonts. |
||
| 877 | if (!$varyFonts) |
||
| 878 | { |
||
| 879 | $font_list = array($font_list[0]); |
||
| 880 | // Try use Screenge if we can - it looks good! |
||
| 881 | if (in_array('AnonymousPro.ttf', $ttfont_list)) |
||
| 882 | $ttfont_list = array('AnonymousPro.ttf'); |
||
| 883 | else |
||
| 884 | $ttfont_list = empty($ttfont_list) ? array() : array($ttfont_list[0]); |
||
| 885 | |||
| 886 | } |
||
| 887 | |||
| 888 | // Create a list of characters to be shown. |
||
| 889 | $characters = array(); |
||
| 890 | $loaded_fonts = array(); |
||
| 891 | for ($i = 0; $i < strlen($code); $i++) |
||
| 892 | { |
||
| 893 | $characters[$i] = array( |
||
| 894 | 'id' => $code{$i}, |
||
| 895 | 'font' => array_rand($font_list), |
||
| 896 | ); |
||
| 897 | |||
| 898 | $loaded_fonts[$characters[$i]['font']] = null; |
||
| 899 | } |
||
| 900 | |||
| 901 | // Load all fonts and determine the maximum font height. |
||
| 902 | foreach ($loaded_fonts as $font_index => $dummy) |
||
| 903 | $loaded_fonts[$font_index] = imageloadfont($settings['default_theme_dir'] . '/fonts/' . $font_list[$font_index]); |
||
| 904 | |||
| 905 | // Determine the dimensions of each character. |
||
| 906 | if ($imageType == 4 || $imageType == 5) |
||
| 907 | $extra = 80; |
||
| 908 | else |
||
| 909 | $extra = 45; |
||
| 910 | |||
| 911 | $total_width = $character_spacing * strlen($code) + $extra; |
||
| 912 | $max_height = 0; |
||
| 913 | foreach ($characters as $char_index => $character) |
||
| 914 | { |
||
| 915 | $characters[$char_index]['width'] = imagefontwidth($loaded_fonts[$character['font']]); |
||
| 916 | $characters[$char_index]['height'] = imagefontheight($loaded_fonts[$character['font']]); |
||
| 917 | |||
| 918 | $max_height = max($characters[$char_index]['height'] + 5, $max_height); |
||
| 919 | $total_width += $characters[$char_index]['width']; |
||
| 920 | } |
||
| 921 | |||
| 922 | // Create an image. |
||
| 923 | $code_image = $gd2 ? imagecreatetruecolor($total_width, $max_height) : imagecreate($total_width, $max_height); |
||
| 924 | |||
| 925 | // Draw the background. |
||
| 926 | $bg_color = imagecolorallocate($code_image, $background_color[0], $background_color[1], $background_color[2]); |
||
| 927 | imagefilledrectangle($code_image, 0, 0, $total_width - 1, $max_height - 1, $bg_color); |
||
| 928 | |||
| 929 | // Randomize the foreground color a little. |
||
| 930 | for ($i = 0; $i < 3; $i++) |
||
| 931 | $foreground_color[$i] = mt_rand(max($foreground_color[$i] - 3, 0), min($foreground_color[$i] + 3, 255)); |
||
| 932 | $fg_color = imagecolorallocate($code_image, $foreground_color[0], $foreground_color[1], $foreground_color[2]); |
||
| 933 | |||
| 934 | // Color for the dots. |
||
| 935 | for ($i = 0; $i < 3; $i++) |
||
| 936 | $dotbgcolor[$i] = $background_color[$i] < $foreground_color[$i] ? mt_rand(0, max($foreground_color[$i] - 20, 0)) : mt_rand(min($foreground_color[$i] + 20, 255), 255); |
||
| 937 | $randomness_color = imagecolorallocate($code_image, $dotbgcolor[0], $dotbgcolor[1], $dotbgcolor[2]); |
||
|
0 ignored issues
–
show
The variable
$dotbgcolor does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
Loading history...
|
|||
| 938 | |||
| 939 | // Some squares/rectanges for new extreme level |
||
| 940 | if ($noiseType == 'extreme') |
||
| 941 | { |
||
| 942 | for ($i = 0; $i < mt_rand(1, 5); $i++) |
||
| 943 | { |
||
| 944 | $x1 = mt_rand(0, $total_width / 4); |
||
| 945 | $x2 = $x1 + round(rand($total_width / 4, $total_width)); |
||
| 946 | $y1 = mt_rand(0, $max_height); |
||
| 947 | $y2 = $y1 + round(rand(0, $max_height / 3)); |
||
| 948 | imagefilledrectangle($code_image, $x1, $y1, $x2, $y2, mt_rand(0, 1) ? $fg_color : $randomness_color); |
||
| 949 | } |
||
| 950 | } |
||
| 951 | |||
| 952 | // Fill in the characters. |
||
| 953 | if (!$disableChars) |
||
| 954 | { |
||
| 955 | $cur_x = 0; |
||
| 956 | foreach ($characters as $char_index => $character) |
||
| 957 | { |
||
| 958 | // Can we use true type fonts? |
||
| 959 | $can_do_ttf = function_exists('imagettftext'); |
||
| 960 | |||
| 961 | // How much rotation will we give? |
||
| 962 | if ($rotationType == 'none') |
||
| 963 | $angle = 0; |
||
| 964 | else |
||
| 965 | $angle = mt_rand(-100, 100) / ($rotationType == 'high' ? 6 : 10); |
||
| 966 | |||
| 967 | // What color shall we do it? |
||
| 968 | if ($fontColorType == 'cyclic') |
||
| 969 | { |
||
| 970 | // Here we'll pick from a set of acceptance types. |
||
| 971 | $colors = array( |
||
| 972 | array(10, 120, 95), |
||
| 973 | array(46, 81, 29), |
||
| 974 | array(4, 22, 154), |
||
| 975 | array(131, 9, 130), |
||
| 976 | array(0, 0, 0), |
||
| 977 | array(143, 39, 31), |
||
| 978 | ); |
||
| 979 | if (!isset($last_index)) |
||
| 980 | $last_index = -1; |
||
| 981 | $new_index = $last_index; |
||
| 982 | while ($last_index == $new_index) |
||
| 983 | $new_index = mt_rand(0, count($colors) - 1); |
||
| 984 | $char_fg_color = $colors[$new_index]; |
||
| 985 | $last_index = $new_index; |
||
| 986 | } |
||
| 987 | elseif ($fontColorType == 'random') |
||
| 988 | $char_fg_color = array(mt_rand(max($foreground_color[0] - 2, 0), $foreground_color[0]), mt_rand(max($foreground_color[1] - 2, 0), $foreground_color[1]), mt_rand(max($foreground_color[2] - 2, 0), $foreground_color[2])); |
||
| 989 | else |
||
| 990 | $char_fg_color = array($foreground_color[0], $foreground_color[1], $foreground_color[2]); |
||
| 991 | |||
| 992 | if (!empty($can_do_ttf)) |
||
| 993 | { |
||
| 994 | // GD2 handles font size differently. |
||
| 995 | if ($fontSizeRandom) |
||
| 996 | $font_size = $gd2 ? mt_rand(17, 19) : mt_rand(18, 25); |
||
| 997 | else |
||
| 998 | $font_size = $gd2 ? 18 : 24; |
||
| 999 | |||
| 1000 | // Work out the sizes - also fix the character width cause TTF not quite so wide! |
||
| 1001 | $font_x = $fontHorSpace == 'minus' && $cur_x > 0 ? $cur_x - 3 : $cur_x + 5; |
||
| 1002 | $font_y = $max_height - ($fontVerPos == 'vrandom' ? mt_rand(2, 8) : ($fontVerPos == 'random' ? mt_rand(3, 5) : 5)); |
||
| 1003 | |||
| 1004 | // What font face? |
||
| 1005 | if (!empty($ttfont_list)) |
||
| 1006 | $fontface = $settings['default_theme_dir'] . '/fonts/' . $ttfont_list[mt_rand(0, count($ttfont_list) - 1)]; |
||
| 1007 | |||
| 1008 | // What color are we to do it in? |
||
| 1009 | $is_reverse = $showReverseChars ? mt_rand(0, 1) : false; |
||
| 1010 | $char_color = function_exists('imagecolorallocatealpha') && $fontTrans ? imagecolorallocatealpha($code_image, $char_fg_color[0], $char_fg_color[1], $char_fg_color[2], 50) : imagecolorallocate($code_image, $char_fg_color[0], $char_fg_color[1], $char_fg_color[2]); |
||
| 1011 | |||
| 1012 | $fontcord = @imagettftext($code_image, $font_size, $angle, $font_x, $font_y, $char_color, $fontface, $character['id']); |
||
|
0 ignored issues
–
show
The variable
$fontface does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
Loading history...
|
|||
| 1013 | if (empty($fontcord)) |
||
| 1014 | $can_do_ttf = false; |
||
| 1015 | elseif ($is_reverse) |
||
|
0 ignored issues
–
show
The expression
$is_reverse of type integer|false is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For 0 == false // true
0 == null // true
123 == false // false
123 == null // false
// It is often better to use strict comparison
0 === false // false
0 === null // false
Loading history...
|
|||
| 1016 | { |
||
| 1017 | imagefilledpolygon($code_image, $fontcord, 4, $fg_color); |
||
| 1018 | // Put the character back! |
||
| 1019 | imagettftext($code_image, $font_size, $angle, $font_x, $font_y, $randomness_color, $fontface, $character['id']); |
||
| 1020 | } |
||
| 1021 | |||
| 1022 | if ($can_do_ttf) |
||
| 1023 | $cur_x = max($fontcord[2], $fontcord[4]) + ($angle == 0 ? 0 : 3); |
||
| 1024 | } |
||
| 1025 | |||
| 1026 | if (!$can_do_ttf) |
||
| 1027 | { |
||
| 1028 | // Rotating the characters a little... |
||
| 1029 | if (function_exists('imagerotate')) |
||
| 1030 | { |
||
| 1031 | $char_image = $gd2 ? imagecreatetruecolor($character['width'], $character['height']) : imagecreate($character['width'], $character['height']); |
||
| 1032 | $char_bgcolor = imagecolorallocate($char_image, $background_color[0], $background_color[1], $background_color[2]); |
||
| 1033 | imagefilledrectangle($char_image, 0, 0, $character['width'] - 1, $character['height'] - 1, $char_bgcolor); |
||
| 1034 | imagechar($char_image, $loaded_fonts[$character['font']], 0, 0, $character['id'], imagecolorallocate($char_image, $char_fg_color[0], $char_fg_color[1], $char_fg_color[2])); |
||
| 1035 | $rotated_char = imagerotate($char_image, mt_rand(-100, 100) / 10, $char_bgcolor); |
||
| 1036 | imagecopy($code_image, $rotated_char, $cur_x, 0, 0, 0, $character['width'], $character['height']); |
||
| 1037 | imagedestroy($rotated_char); |
||
| 1038 | imagedestroy($char_image); |
||
| 1039 | } |
||
| 1040 | |||
| 1041 | // Sorry, no rotation available. |
||
| 1042 | else |
||
| 1043 | imagechar($code_image, $loaded_fonts[$character['font']], $cur_x, floor(($max_height - $character['height']) / 2), $character['id'], imagecolorallocate($code_image, $char_fg_color[0], $char_fg_color[1], $char_fg_color[2])); |
||
| 1044 | $cur_x += $character['width'] + $character_spacing; |
||
| 1045 | } |
||
| 1046 | } |
||
| 1047 | } |
||
| 1048 | // If disabled just show a cross. |
||
| 1049 | else |
||
| 1050 | { |
||
| 1051 | imageline($code_image, 0, 0, $total_width, $max_height, $fg_color); |
||
| 1052 | imageline($code_image, 0, $max_height, $total_width, 0, $fg_color); |
||
| 1053 | } |
||
| 1054 | |||
| 1055 | // Make the background color transparent on the hard image. |
||
| 1056 | if (!$simpleBGColor) |
||
| 1057 | imagecolortransparent($code_image, $bg_color); |
||
| 1058 | if ($hasBorder) |
||
| 1059 | imagerectangle($code_image, 0, 0, $total_width - 1, $max_height - 1, $fg_color); |
||
| 1060 | |||
| 1061 | // Add some noise to the background? |
||
| 1062 | if ($noiseType != 'none') |
||
| 1063 | { |
||
| 1064 | for ($i = mt_rand(0, 2); $i < $max_height; $i += mt_rand(1, 2)) |
||
| 1065 | for ($j = mt_rand(0, 10); $j < $total_width; $j += mt_rand(1, 10)) |
||
| 1066 | imagesetpixel($code_image, $j, $i, mt_rand(0, 1) ? $fg_color : $randomness_color); |
||
| 1067 | |||
| 1068 | // Put in some lines too? |
||
| 1069 | if ($noiseType != 'extreme') |
||
| 1070 | { |
||
| 1071 | $num_lines = $noiseType == 'high' ? mt_rand(3, 7) : mt_rand(2, 5); |
||
| 1072 | for ($i = 0; $i < $num_lines; $i++) |
||
| 1073 | { |
||
| 1074 | if (mt_rand(0, 1)) |
||
| 1075 | { |
||
| 1076 | $x1 = mt_rand(0, $total_width); |
||
| 1077 | $x2 = mt_rand(0, $total_width); |
||
| 1078 | $y1 = 0; $y2 = $max_height; |
||
| 1079 | } |
||
| 1080 | else |
||
| 1081 | { |
||
| 1082 | $y1 = mt_rand(0, $max_height); |
||
| 1083 | $y2 = mt_rand(0, $max_height); |
||
| 1084 | $x1 = 0; $x2 = $total_width; |
||
| 1085 | } |
||
| 1086 | imagesetthickness($code_image, mt_rand(1, 2)); |
||
| 1087 | imageline($code_image, $x1, $y1, $x2, $y2, mt_rand(0, 1) ? $fg_color : $randomness_color); |
||
| 1088 | } |
||
| 1089 | } |
||
| 1090 | else |
||
| 1091 | { |
||
| 1092 | // Put in some ellipse |
||
| 1093 | $num_ellipse = $noiseType == 'extreme' ? mt_rand(6, 12) : mt_rand(2, 6); |
||
| 1094 | for ($i = 0; $i < $num_ellipse; $i++) |
||
| 1095 | { |
||
| 1096 | $x1 = round(rand(($total_width / 4) * -1, $total_width + ($total_width / 4))); |
||
| 1097 | $x2 = round(rand($total_width / 2, 2 * $total_width)); |
||
| 1098 | $y1 = round(rand(($max_height / 4) * -1, $max_height + ($max_height / 4))); |
||
| 1099 | $y2 = round(rand($max_height / 2, 2 * $max_height)); |
||
| 1100 | imageellipse($code_image, $x1, $y1, $x2, $y2, mt_rand(0, 1) ? $fg_color : $randomness_color); |
||
| 1101 | } |
||
| 1102 | } |
||
| 1103 | } |
||
| 1104 | |||
| 1105 | // Show the image. |
||
| 1106 | if (function_exists('imagegif')) |
||
| 1107 | { |
||
| 1108 | header('Content-type: image/gif'); |
||
| 1109 | imagegif($code_image); |
||
| 1110 | } |
||
| 1111 | else |
||
| 1112 | { |
||
| 1113 | header('Content-type: image/png'); |
||
| 1114 | imagepng($code_image); |
||
| 1115 | } |
||
| 1116 | |||
| 1117 | // Bail out. |
||
| 1118 | imagedestroy($code_image); |
||
| 1119 | die(); |
||
| 1120 | } |
||
| 1121 | |||
| 1122 | /** |
||
| 1123 | * Show a letter for the visual verification code. |
||
| 1124 | * Alternative function for showCodeImage() in case GD is missing. |
||
| 1125 | * Includes an image from a random sub directory of default_theme_dir/fonts. |
||
| 1126 | * |
||
| 1127 | * @param string $letter A letter to show as an image |
||
| 1128 | * @return void|false False if something went wrong |
||
| 1129 | */ |
||
| 1130 | function showLetterImage($letter) |
||
| 1131 | { |
||
| 1132 | global $settings; |
||
| 1133 | |||
| 1134 | if (!is_dir($settings['default_theme_dir'] . '/fonts')) |
||
| 1135 | return false; |
||
| 1136 | |||
| 1137 | // Get a list of the available font directories. |
||
| 1138 | $font_dir = dir($settings['default_theme_dir'] . '/fonts'); |
||
| 1139 | $font_list = array(); |
||
| 1140 | while ($entry = $font_dir->read()) |
||
| 1141 | if ($entry[0] !== '.' && is_dir($settings['default_theme_dir'] . '/fonts/' . $entry) && file_exists($settings['default_theme_dir'] . '/fonts/' . $entry . '.gdf')) |
||
| 1142 | $font_list[] = $entry; |
||
| 1143 | |||
| 1144 | if (empty($font_list)) |
||
| 1145 | return false; |
||
| 1146 | |||
| 1147 | // Pick a random font. |
||
| 1148 | $random_font = $font_list[array_rand($font_list)]; |
||
| 1149 | |||
| 1150 | // Check if the given letter exists. |
||
| 1151 | if (!file_exists($settings['default_theme_dir'] . '/fonts/' . $random_font . '/' . $letter . '.png')) |
||
| 1152 | return false; |
||
| 1153 | |||
| 1154 | // Include it! |
||
| 1155 | header('Content-type: image/png'); |
||
| 1156 | include($settings['default_theme_dir'] . '/fonts/' . $random_font . '/' . $letter . '.png'); |
||
| 1157 | |||
| 1158 | // Nothing more to come. |
||
| 1159 | die(); |
||
| 1160 | } |
||
| 1161 | |||
| 1162 | ?> |
This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.