captcha.php 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. <?php
  2. if(
  3. !isset($_GET["k"]) ||
  4. preg_match(
  5. '/^c\.[0-9]+$/',
  6. $_GET["k"]
  7. )
  8. ){
  9. header("Content-Type: text/plain");
  10. echo "Fuck you";
  11. die();
  12. }
  13. header("Content-Type: image/jpeg");
  14. $grid = apcu_fetch($_GET["k"]);
  15. if(
  16. $grid === false ||
  17. $grid[3] === true // has already been generated
  18. ){
  19. http_response_code(304); // not modified
  20. die();
  21. }
  22. header("Last-Modified: Thu, 01 Oct 1970 00:00:00 GMT");
  23. // only generate one captcha with this config
  24. apcu_store(
  25. $_GET["k"],
  26. [
  27. $grid[0],
  28. $grid[1],
  29. $grid[2],
  30. true // has captcha been generated?
  31. ],
  32. 120 // we give user another 2 minutes to solve
  33. );
  34. // generate image
  35. if(random_int(0,1) === 0){
  36. $theme = [
  37. "bg" => "#ebdbb2",
  38. "fg" => "#1d2021"
  39. ];
  40. }else{
  41. $theme = [
  42. "bg" => "#1d2021",
  43. "fg" => "#ebdbb2"
  44. ];
  45. }
  46. $im = new Imagick();
  47. $im->newImage(400, 400, $theme["bg"]);
  48. $im->setImageBackgroundColor($theme["bg"]);
  49. $im->setImageFormat("jpg");
  50. $noise = [
  51. imagick::NOISE_GAUSSIAN,
  52. imagick::NOISE_LAPLACIAN
  53. ];
  54. $distort = [
  55. imagick::DISTORTION_AFFINE,
  56. imagick::DISTORTION_SHEPARDS
  57. ];
  58. $i = 0;
  59. for($y=0; $y<4; $y++){
  60. for($x=0; $x<4; $x++){
  61. $tmp = new Imagick("./data/captcha/" . $grid[0][$i][0] . "/" . random_int(1, $grid[0][$i][1]) . ".png");
  62. // convert transparency correctly
  63. $tmp->setImageBackgroundColor("black");
  64. $tmp->setImageAlphaChannel(Imagick::ALPHACHANNEL_REMOVE);
  65. // distort $tmp
  66. $tmp->distortImage(
  67. $distort[random_int(0,1)],
  68. [
  69. 0, 0,
  70. random_int(-15, 15), random_int(-15, 15),
  71. 100, 0,
  72. random_int(80, 120), random_int(-15, 15),
  73. 100, 100,
  74. random_int(80, 120), random_int(80, 120),
  75. 0, 100,
  76. random_int(-15, 15), random_int(80, 120)
  77. ],
  78. false
  79. );
  80. // append image
  81. $im->compositeImage($tmp->getImage(), Imagick::COMPOSITE_DEFAULT, $x * 100, $y * 100);
  82. $i++;
  83. }
  84. }
  85. // add noise
  86. $im->addNoiseImage($noise[random_int(0, 1)]);
  87. // expand top of image
  88. $im->setImageGravity(Imagick::GRAVITY_SOUTH);
  89. $im->chopImage(0, -27, 400, 400);
  90. $im->extentImage(0, 0, 0, -27);
  91. // add text
  92. $draw = new ImagickDraw();
  93. $draw->setFontSize(20);
  94. $draw->setFillColor($theme["fg"]);
  95. //$draw->setTextAntialias(false);
  96. $draw->setFont("./data/captcha/font.ttf");
  97. $text = "Pick " . $grid[1] . " images of " . str_replace("_", " ", $grid[2]);
  98. $pos = 200 - ($im->queryFontMetrics($draw, $text)["textWidth"] / 2);
  99. for($i=0; $i<strlen($text); $i++){
  100. $im->annotateImage(
  101. $draw,
  102. $pos,
  103. 20,
  104. random_int(-15, 15),
  105. $text[$i]
  106. );
  107. $pos += $im->queryFontMetrics($draw, $text[$i])["textWidth"];
  108. }
  109. $im->setFormat("jpeg");
  110. $im->setImageCompressionQuality(90);
  111. $im->setImageCompression(Imagick::COMPRESSION_JPEG2000);
  112. echo $im->getImageBlob();