The current Captcha class has a lot of responsibilities. It renders the captcha image, can check if a certain captcha type is a Google captcha, if a captcha is required for a certain email. The SubscriberSubscribeController is not only in charge of "controlling" the subscription process but also validates, whether a captcha is correct or not. This architecture made it difficult to extend the functionality and introduce the audio captcha feature. Therefore this commit refactors the captcha architecture and tries to seperate the different concerns into several classes and objects. Validation is now done by validators. The CaptchaPhrase now is in charge of keeping the captcha phrase consistent between the image and the new audio, so that you can renew the captcha and both captchas are in sync. [MAILPOET-4514]
84 lines
2.4 KiB
PHP
84 lines
2.4 KiB
PHP
<?php
|
|
|
|
namespace MailPoet\Subscription\Captcha;
|
|
|
|
use MailPoet\Config\Env;
|
|
use MailPoetVendor\Gregwar\Captcha\CaptchaBuilder;
|
|
|
|
class CaptchaRenderer {
|
|
|
|
|
|
private $phrase;
|
|
|
|
public function __construct(
|
|
CaptchaPhrase $phrase
|
|
) {
|
|
$this->phrase = $phrase;
|
|
}
|
|
|
|
public function isSupported() {
|
|
return extension_loaded('gd') && function_exists('imagettftext');
|
|
}
|
|
|
|
public function renderAudio($sessionId, $return = false) {
|
|
|
|
$audioPath = Env::$assetsPath . '/audio/';
|
|
$phrase = $this->phrase->getPhraseForType('audio', $sessionId);
|
|
$audio = null;
|
|
foreach (str_split($phrase) as $character) {
|
|
$file = $audioPath . strtolower($character) . '.mp3';
|
|
if (!file_exists($file)) {
|
|
throw new \RuntimeException("File not found.");
|
|
}
|
|
$audio .= file_get_contents($file);
|
|
}
|
|
|
|
if ($return) {
|
|
return $audio;
|
|
}
|
|
|
|
header("Cache-Control: no-store, no-cache, must-revalidate");
|
|
header('Content-Type: audio/mpeg');
|
|
|
|
//phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped, WordPressDotOrg.sniffs.OutputEscaping.UnescapedOutputParameter
|
|
echo $audio;
|
|
exit;
|
|
}
|
|
|
|
public function renderImage($width = null, $height = null, $sessionId = null, $return = false) {
|
|
if (!$this->isSupported()) {
|
|
return false;
|
|
}
|
|
|
|
$fontNumbers = array_merge(range(0, 3), [5]); // skip font #4
|
|
$fontNumber = $fontNumbers[mt_rand(0, count($fontNumbers) - 1)];
|
|
|
|
$reflector = new \ReflectionClass(CaptchaBuilder::class);
|
|
$captchaDirectory = dirname((string)$reflector->getFileName());
|
|
$font = $captchaDirectory . '/Font/captcha' . $fontNumber . '.ttf';
|
|
|
|
$phrase = $this->phrase->getPhraseForType('image', $sessionId);
|
|
$builder = CaptchaBuilder::create($phrase)
|
|
->setBackgroundColor(255, 255, 255)
|
|
->setTextColor(1, 1, 1)
|
|
->setMaxBehindLines(0)
|
|
->build($width ?: 220, $height ?: 60, $font);
|
|
|
|
if ($return) {
|
|
return $builder->get();
|
|
}
|
|
|
|
header("Expires: Sat, 01 Jan 2019 01:00:00 GMT"); // time in the past
|
|
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
|
|
header("Cache-Control: no-store, no-cache, must-revalidate");
|
|
header("Cache-Control: post-check=0, pre-check=0", false);
|
|
header("Pragma: no-cache");
|
|
header('X-Cache-Enabled: False');
|
|
header('X-LiteSpeed-Cache-Control: no-cache');
|
|
|
|
header('Content-Type: image/jpeg');
|
|
$builder->output();
|
|
exit;
|
|
}
|
|
}
|