diff --git a/.gitignore b/.gitignore index 8ef0e14..6f38042 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ vendor/ .idea/ +.vagrant/ diff --git a/composer.json b/composer.json index 9e93973..1094150 100644 --- a/composer.json +++ b/composer.json @@ -1,18 +1,19 @@ { - "name": "wikicaptcha/wikicaptcha-backend", - "type": "project", - "require": { - "zendframework/zend-httphandlerrunner": "^1.1", - "zendframework/zend-diactoros": "^2.2", - "psr/http-server-middleware": "^1.0", - "psr/http-message": "^1.0", - "nikic/fast-route": "^1.3", - "relay/relay": "^2.0" - }, - "autoload": - { - "psr-4": { - "Wikicaptcha\\Backend\\": "src/" - } + "name": "wikicaptcha/wikicaptcha-backend", + "type": "project", + "require": { + "zendframework/zend-httphandlerrunner": "^1.1", + "zendframework/zend-diactoros": "^2.2", + "psr/http-server-middleware": "^1.0", + "psr/http-message": "^1.0", + "nikic/fast-route": "^1.3", + "relay/relay": "^2.0", + "ext-pdo": "*", + "ext-json": "*" + }, + "autoload": { + "psr-4": { + "Wikicaptcha\\Backend\\": "src/" } + } } diff --git a/src/Database.php b/src/Database.php index 54b8491..410b475 100644 --- a/src/Database.php +++ b/src/Database.php @@ -1,16 +1,21 @@ pdo = new \PDO('mysql:host=192.168.1.22;dbname=wikicaptcha', 'wikicaptcha', 'wikicaptcha'); + $options = [ + \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, + \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC, + \PDO::ATTR_EMULATE_PREPARES => false, + ]; + $this->pdo = new \PDO('mysql:host=192.168.69.1;dbname=wikicaptcha', 'wikicaptcha', 'ahvahl8MefoaPh2vui8aewaNgiehei', $options); } public function getPdo() { return $this->pdo; } } diff --git a/src/QuestionDto.php b/src/QuestionDto.php index 1f4e4ba..5271f60 100644 --- a/src/QuestionDto.php +++ b/src/QuestionDto.php @@ -1,66 +1,66 @@ 'IMG', 'INPUT' => 'INPUT', // free text 'OPTIONS' => 'OPTIONS' ]; private function __consruct() { } protected $questionText; protected $questionId; protected $questionType; protected $answersAvailable; public static function fromParts(string $id, string $text, string $type, array $answersAvailable): QuestionDto { $that = new QuestionDto(); $that->questionId = $id; $that->questionText = $text; $that->setQuestionType($type); $that->setAnswersAvailable($answersAvailable); return $that; } protected function setQuestionType(string $questionType) { if(!isset(self::QUESTION_TYPES[$questionType])) { throw new InvalidArgumentException("$questionType is not a valid question type"); } $this->questionType = $questionType; } protected function setAnswersAvailable(array $answersAvailable) { foreach($answersAvailable as $item) { if(!($item instanceof AnswerDto)) { throw new InvalidArgumentException("answersAvailable must be instanceof AnswerDto"); } } $this->answersAvailable = $answersAvailable; } public static function fromArray(array $array): QuestionDto { $a = []; foreach($array['answersAvailable'] as $el) { $a[] = AnswerDto::fromArray($el); } return self::fromParts($array['questionId'], $array['questionText'], $array['questionType'], $a); } public function jsonSerialize() { $result = []; $result['questionText'] = $this->questionText; $result['questionId'] = $this->questionId; $result['questionType'] = $this->questionType; $result['answersAvailable'] = $this->answersAvailable; return $result; } } diff --git a/src/Questions.php b/src/Questions.php index 52be4ad..47b915c 100644 --- a/src/Questions.php +++ b/src/Questions.php @@ -1,39 +1,108 @@ getAttribute('ParsedBody', []); if(!isset($payload['language'])) { return new JsonResponse(['error' => 'Add language to request'], 400); } + if(!isset($payload['appid'])) { + return new JsonResponse(['error' => 'Add appid to request'], 400); + } + + $pdo = (new Database())->getPdo(); + $pdo->beginTransaction(); + + $ip = inet_pton($_SERVER['REMOTE_ADDR']); + $s = $pdo->prepare('INSERT INTO wcaptcha_session(session_ip, app_id) VALUES (?, ?)'); + $s->execute([$ip, (int) $payload['appid']]); + $id = $pdo->lastInsertId(); + + $pdo->commit(); - // TODO: query database - $id = 123; $questions = []; - for($i = 0; $i < 3; $i++) { + $challengeRows = $pdo->query('SELECT challenge_ID, challenge_type, challenge_text FROM wcaptcha_challenge ORDER BY RAND() LIMIT 2'); + $total = 9; + $actual = mt_rand(2, 8); + foreach($challengeRows as $challenge) { + switch($challenge['challenge_type']) { + case 'img': + $type = QuestionDto::QUESTION_TYPES['IMG']; + break; + case 'text': + default: + $type = QuestionDto::QUESTION_TYPES['INPUT']; + break; + case 'option': + $type = QuestionDto::QUESTION_TYPES['OPTIONS']; + break; + } + $answers = []; - $answers[0] = AnswerDto::fromParts('https://upload.wikimedia.org/wikipedia/commons/thumb/d/d4/George-W-Bush.jpeg/440px-George-W-Bush.jpeg', 'This is some text'); - $answers[1] = AnswerDto::fromParts('https://upload.wikimedia.org/wikipedia/commons/thumb/d/d4/George-W-Bush.jpeg/440px-George-W-Bush.jpeg', 'This is some text'); - $answers[2] = AnswerDto::fromParts('https://upload.wikimedia.org/wikipedia/commons/thumb/d/d4/George-W-Bush.jpeg/440px-George-W-Bush.jpeg', 'This is some text'); - $answers[3] = AnswerDto::fromParts('https://upload.wikimedia.org/wikipedia/commons/thumb/8/8d/President_Barack_Obama.jpg/440px-President_Barack_Obama.jpg', 'This is some text'); - $answers[4] = AnswerDto::fromParts('https://upload.wikimedia.org/wikipedia/commons/thumb/5/56/Donald_Trump_official_portrait.jpg/440px-Donald_Trump_official_portrait.jpg', 'This is some text'); - $answers[5] = AnswerDto::fromParts('https://upload.wikimedia.org/wikipedia/commons/thumb/5/56/Donald_Trump_official_portrait.jpg/440px-Donald_Trump_official_portrait.jpg', 'This is some text'); - $answers[6] = AnswerDto::fromParts('https://upload.wikimedia.org/wikipedia/commons/thumb/5/56/Donald_Trump_official_portrait.jpg/440px-Donald_Trump_official_portrait.jpg', 'This is some text'); - $answers[7] = AnswerDto::fromParts('https://upload.wikimedia.org/wikipedia/commons/thumb/5/56/Donald_Trump_official_portrait.jpg/440px-Donald_Trump_official_portrait.jpg', 'This is some text'); - $answers[8] = AnswerDto::fromParts('https://upload.wikimedia.org/wikipedia/commons/thumb/5/56/Donald_Trump_official_portrait.jpg/440px-Donald_Trump_official_portrait.jpg', 'This is some text'); - $questions[$i] = QuestionDto::fromParts('q' . mt_rand(100, 999), 'Which one of these persons is Barack Obama?', QuestionDto::QUESTION_TYPES['IMG'], $answers); + $already = []; + + if($type === QuestionDto::QUESTION_TYPES['IMG']) { + + // Actual images + + $imageRows = $pdo->prepare(' +SELECT image_ID, image_src +FROM wcaptcha_challenge_connotation +NATURAL JOIN wcaptcha_image_connotation +NATURAL JOIN wcaptcha_image +WHERE wcaptcha_challenge_connotation.challenge_ID = ? +GROUP BY image_ID, image_src +ORDER BY COUNT(*) DESC +LIMIT ? +'); + $imageRows->execute([$challenge['challenge_ID'], $actual]); + foreach($imageRows->fetchAll() as $image) { + $answers[] = AnswerDto::fromParts($image['image_src'], 'No text for you'); + $already[] = $image['image_ID']; + } + + $actual = count($already); + $random = $total - $actual; + + // Random images + + $questionMarks = []; + foreach($already as $ignored) { + $questionMarks[] = '?'; + } + unset($ignored); + + $stmt = ' +SELECT image_ID, image_src +FROM wcaptcha_image +WHERE image_ID NOT IN (' . implode(', ', $questionMarks) .') +ORDER BY RAND() +LIMIT ?'; + $params = array_merge($already, [$random]); + + $imageRows2 = $pdo->prepare($stmt); + $imageRows2->execute($params); + foreach($imageRows2->fetchAll() as $image) { + $answers[] = AnswerDto::fromParts($image['image_src'], 'No text for you'); + } + } else { + throw new \LogicException('Not implemented'); + } + + shuffle($answers); + $questions[] = QuestionDto::fromParts($challenge['challenge_ID'], $challenge['challenge_text'], $type, $answers); } return new JsonResponse(WikiApiDto::fromParts($id, $questions), 200); } }