<?php
/**
* [PHPFOX_HEADER]
*/
defined('PHPFOX') or exit('NO DICE!');
/**
*
*
* @copyright [PHPFOX_COPYRIGHT]
* @author Raymond Benc
* @package Module_Captcha
* @version $Id: captcha.class.php 6005 2013-06-06 14:12:12Z Raymond_Benc $
*/
class Captcha_Service_Captcha extends Phpfox_Service
{
/**
* @var object
*/
private $_oSession;
/**
* @var
*/
private $_hImg;
/**
* Class constructor
*/
public function __construct()
{
$this->_oSession = Log_Service_Session::instance();
}
/**
* @param null|string $sCode
*
* @return bool
*/
public function checkHash($sCode = null)
{
if (Phpfox::getParam('captcha.captcha_type') == 'recaptcha') {
$url = 'https://www.google.com/recaptcha/api/siteverify';
$gDataResponse = isset($_REQUEST['g-recaptcha-response']) ? $_REQUEST['g-recaptcha-response'] : '';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
'secret' => Phpfox::getParam('captcha.recaptcha_private_key'),
'response' => $gDataResponse,
'remoteip' => $_SERVER['REMOTE_ADDR'],
]));
$response = curl_exec($ch);
curl_close($ch);
if (!$response)
return false;
$response = json_decode($response, true);
if (isset($response['success']) && $response['success'] == true)
return true;
return false;
}
if (Phpfox::getParam('core.store_only_users_in_session')) {
$oSession = Phpfox::getLib('session');
$sSessionHash = $oSession->get('sessionhash');
$aRow = $this->database()->select('*')
->from(Phpfox::getT('log_session'))
->where('session_hash = \'' . $this->database()->escape($sSessionHash) . '\'')
->execute('getSlaveRow');
if (isset($aRow['session_hash']) && $this->_getHash(strtolower($sCode), $aRow['session_hash']) == $aRow['captcha_hash']) {
return true;
}
} else {
if ($this->_getHash(strtolower($sCode), $this->_oSession->getSessionId()) == $this->_oSession->get('captcha_hash')) {
return true;
}
}
return false;
}
/**
* @param string $sCode
*
* @return void
*/
public function setHash($sCode)
{
if (Phpfox::getParam('core.store_only_users_in_session')) {
$oRequest = Phpfox_Request::instance();
$oSession = Phpfox::getLib('session');
$sSessionHash = $oSession->get('sessionhash');
$bCreate = true;
if (!empty($sSessionHash)) {
$bCreate = false;
$aRow = $this->database()->select('*')
->from(Phpfox::getT('log_session'))
->where('session_hash = \'' . $this->database()->escape($sSessionHash) . '\'')
->execute('getSlaveRow');
if (isset($aRow['session_hash'])) {
$this->database()->update(Phpfox::getT('log_session'), array('captcha_hash' => $this->_getHash($sCode, $sSessionHash)), "session_hash = '" . $sSessionHash . "'");
} else {
$bCreate = true;
}
}
if ($bCreate) {
$sSessionHash = $oRequest->getSessionHash();
$this->database()->insert(Phpfox::getT('log_session'), array(
'session_hash' => $sSessionHash,
'id_hash' => $oRequest->getIdHash(),
'captcha_hash' => $this->_getHash($sCode, $sSessionHash),
'user_id' => Phpfox::getUserId(),
'last_activity' => PHPFOX_TIME,
'location' => '',
'is_forum' => '0',
'forum_id' => 0,
'im_hide' => 0,
'ip_address' => '',
'user_agent' => ''
)
);
$oSession->set('sessionhash', $sSessionHash);
}
} else {
$iId = $this->_oSession->getSessionId();
$this->database()->update(Phpfox::getT('log_session'), array('captcha_hash' => $this->_getHash($sCode, $iId)), "session_hash = '" . $iId . "'");
}
}
/**
* @param string $sText
*
* @return void
*/
public function displayCaptcha($sText)
{
while (ob_get_level()) {
ob_get_clean();
}
header("X-Content-Encoded-By: phpFox " . Phpfox::getVersion());
header("Pragma: no-cache");
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Content-Type: image/jpeg');
$sCaptchaType = Phpfox::getParam('captcha.captcha_type');
if ($sCaptchaType == 'qrcode') {
$this->generateQRCodeCaptchaImage($sText);
} else {
$this->generateDefaultCaptchaImage($sText);
}
}
/**
* @param string $sText
*
* @return void
*/
public function generateDefaultCaptchaImage($sText)
{
((Phpfox::getParam('captcha.captcha_use_font') && function_exists('imagettftext')) ? $this->_writeFromFont($sText) : $this->_writeFromString($sText));
imagejpeg($this->_hImg);
imagedestroy($this->_hImg);
}
/**
* @param string $sText
*
* @return void
*/
private function generateQRCodeCaptchaImage($sText)
{
$qrCode = new \Endroid\QrCode\QrCode();
$qrCode->setText($sText)
->setSize(60)
->setPadding(5)
->setErrorCorrection('high')
->setForegroundColor(array('r' => 0, 'g' => 0, 'b' => 0, 'a' => 0))
->setBackgroundColor(array('r' => 255, 'g' => 255, 'b' => 255, 'a' => 0))
->setLabelFontSize(16)
->render();
}
/**
* @param string $sCharacters
*
* @return string
*/
public function generateCode($sCharacters)
{
$sPossible = Phpfox::getParam('captcha.captcha_code');
$sCode = '';
$i = 0;
while ($i < $sCharacters) {
$sCode .= substr($sPossible, mt_rand(0, strlen($sPossible) - 1), 1);
$i++;
}
return strtolower($sCode);
}
/**
* If a call is made to an unknown method attempt to connect
* it to a specific plug-in with the same name thus allowing
* plug-in developers the ability to extend classes.
*
* @param string $sMethod is the name of the method
* @param array $aArguments is the array of arguments of being passed
*
* @return null
*/
public function __call($sMethod, $aArguments)
{
/**
* Check if such a plug-in exists and if it does call it.
*/
if ($sPlugin = Phpfox_Plugin::get('captcha.service_captcha__call')) {
eval($sPlugin);
return null;
}
/**
* No method or plug-in found we must throw a error.
*/
Phpfox_Error::trigger('Call to undefined method ' . __CLASS__ . '::' . $sMethod . '()', E_USER_ERROR);
}
/**
* @param string $sCode
* @param string $sSalt
*
* @return string
*/
private function _getHash($sCode, $sSalt)
{
return md5(md5($sCode) . $sSalt);
}
/**
* @param string $sText
*
* @return null
*/
private function _writeFromFont($sText)
{
$iString = strlen($sText);
$iWidth = (($iString + 5) * 10 * 2);
$iHeight = 65;
$iTextSize = 30;
$sFont = Phpfox::getParam('core.dir_static') . 'image/font/' . Phpfox::getParam('captcha.captcha_font');
if (!file_exists($sFont)) {
return $this->_writeFromString($sText);
}
$this->_imageCreate($iWidth, $iHeight);
imagecolorallocate($this->_hImg, 255, 255, 255);
$nTxtColor = imagecolorallocate($this->_hImg, 0, 0, 0);
if (!($aBox = @imagettfbbox($iTextSize, 0, $sFont, $sText))) {
return $this->_writeFromString($sText);
}
//Find out the width and height of the text box
$iTextW = $aBox[2] - $aBox[0];
$iTextH = $aBox[5] - $aBox[3];
if (function_exists('imagefilledellipse')) {
$nNoiseColor = imagecolorallocate($this->_hImg, 207, 181, 181);
for ($i = 0; $i < ($iWidth * $iHeight) / 3; $i++) {
imagefilledellipse($this->_hImg, mt_rand(0, $iWidth), mt_rand(0, $iHeight), 1, 1, $nNoiseColor);
}
}
$iImageLineColor = imagecolorallocate($this->_hImg, 207, 181, 181);
for ($i = 0; $i < ($iWidth * $iHeight) / 150; $i++) {
imageline($this->_hImg, mt_rand(0, $iWidth), mt_rand(0, $iHeight), mt_rand(0, $iWidth), mt_rand(0, $iHeight), $iImageLineColor);
}
// Calculate the positions
$positionLeft = (($iWidth - $iTextW) / 2) - (20 + $iString);
for ($i = 0; $i < $iString; $i++) {
if (!@imagettftext($this->_hImg, $iTextSize, 0, $positionLeft, 30, $nTxtColor, $sFont, $sText[$i])) {
return $this->_writeFromString($sText);
}
$positionLeft += 20;
}
return null;
}
/**
* @param string $sText
*
* @return null
*/
private function _writeFromString($sText)
{
$iString = strlen($sText);
$iWidth = (($iString + 5) * 6.4 * 2);
$iHeight = 40;
$this->_imageCreate($iWidth, $iHeight);
imagecolorallocate($this->_hImg, 255, 255, 255);
$nTxtColor = imagecolorallocate($this->_hImg, 0, 0, 0);
$positionLeft = 20;
for ($i = 0; $i < $iString; $i++) {
imagestring($this->_hImg, rand(3,8), $positionLeft, rand(8, 23), $sText[$i], $nTxtColor);
$positionLeft += rand(7,20);
}
return null;
}
/**
* @param int $iWidth
* @param int $iHeight
*/
private function _imageCreate($iWidth, $iHeight)
{
$this->_hImg = imagecreate($iWidth, $iHeight);
}
}