Home > Back-end >  Issues with API call
Issues with API call

Time:10-04

I am creating a quiz web app using Open trivia DB API and PHP. The issue I'm, having now is checking whether the option a user selected is the correct answer. I realized that the program is making another API call and getting a different set of questions entirely everytime so the options being checked with the selected options are totally different. Is there I can store the first result of the API and then check the selected with it instead of making a new call every time?

This is my Controller

public function callAPI($method, $url, $data){
    $curl = curl_init();
    switch ($method){
      case "POST":
         curl_setopt($curl, CURLOPT_POST, 1);
         if ($data)
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
         break;
      case "PUT":
         curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PUT");
         if ($data)
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);                              
         break;
      default:
         if ($data)
            $url = sprintf("%s?%s", $url, http_build_query($data));
   }
   curl_setopt($curl, CURLOPT_URL, $url);
   curl_setopt($curl, CURLOPT_HTTPHEADER, array(
      'APIKEY:xxxxxx',
      'Content-Type: application/json',
   ));
   curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
   curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
   $result = curl_exec($curl);
   if(!$result){die("Connection Failure");}
   curl_close($curl);
   return $result;
}

    public function quiz()
    {
        $get_data= $this->callAPI('GET', 'https://opentdb.com/api.php?amount=10&category=18', false);
$data = json_decode($get_data, true);
        if($_SERVER["REQUEST_METHOD"]=="POST")
            {
              $sum = 0;  
                 foreach ($data as $key => $value)
                 {
                    foreach ($value as $key => $k)
                    {
                        if($_POST[$key]== $k['correct_answer'])
                        {
                            $sum  ;
                        }
                        
echo"The question is ".$k['question']."you answered  $_POST[$key] and the correct answer is  ". $k['correct_answer']. " Your score is $sum"; // I used this line to find out that the problem.
                    }
                    
                 }
  
                    }
        else
        {
        $this->view('quiz', $data);
        }
    }
    

This is my view

<div >
    <form  id ="regForm" method="POST" action="">
        <div >
            <div >
                 <?
                 foreach ($data as $key => $value):
                    foreach ($value as $key => $k):?>
                         <div >
                             <span><p><? echo $key 1  ?></p></span>
                             <h4 > <? echo $k["question"] .  "<br>";?></h4>
                                 <? foreach ( $k["incorrect_answers"] as $incorrect):
                               ?>
        <div >
            <label  for="radio1"></label>
    <input type="radio"  id="radio1" name="<? echo $key ?>" value="<? echo " $incorrect"; ?>"> <? echo " $incorrect"; ?>
    
</div>
                    <?endforeach ?>
                   <input type="radio"  id="rad2" name="<? echo "$key" ?>" value="<? echo $k["correct_answer"]; ?>"> <? echo  $k["correct_answer"]; ?> 
                   
                <div style="overflow:auto;">
                    <div style="float:right;">
                    <button type="button"  id="prevBtn" onclick="nextPrev(-1)">Previous</button>
                     <button type="button" id="nextBtn" onclick="nextPrev(1)">Next</button>
                    </div>
             </div>
         </div> 
         
    <?endforeach ?>
 <?endforeach ?>
</div>

Any help I can get will be much appreciated. Thanks in advance.

CodePudding user response:

Okay, so you are doing an API request, render a page with questions and then when the user submits the answers want to re-use the result from the original API confirm that the answer is correct?

As the api does not allow you to retrieve the same questions using a request hash or question ID's, you will need to introduce a layer into your code that stores the information from the API request for use in the next request.

The easiest solution, looking at your coding level, would be to start using the $_SESSION global to store the array for questions into the session, then when the user submits their answers check for this session information.

Although I think you should have enough to look at documentation and move further, let's tear this down a little bit:

        public function callAPI($method, $url, $data){
    $curl = curl_init();
    switch ($method){
        case "POST":
            curl_setopt($curl, CURLOPT_POST, 1);
            if ($data)
                curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
            break;
        case "PUT":
            curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PUT");
            if ($data)
                curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
            break;
        default:
            if ($data)
                $url = sprintf("%s?%s", $url, http_build_query($data));
    }
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_HTTPHEADER, array(
        'APIKEY:xxxxxx',
        'Content-Type: application/json',
    ));
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
    $result = curl_exec($curl);
    if(!$result){die("Connection Failure");}
    curl_close($curl);
    $_SESSION['quizQuestions'] = $result;
    return $result;
}

public function quiz()
{
    if($_SERVER["REQUEST_METHOD"]=="POST" && isset($_SESSION['quizQuestions']))
    {
        $sum = 0;
        foreach ($_SESSION['quizQuestions'] as $key => $value)
        {
            foreach ($value as $key => $k)
            {
                if($_POST[$key]== $k['correct_answer'])
                {
                    $sum  ;
                }

                echo"The question is ".$k['question']."you answered  $_POST[$key] and the correct answer is  ". $k['correct_answer']. " Your score is $sum"; // I used this line to find out that the problem.
            }

        }
        $_SESSION['quizQuestions'] = null;
        // render view..
    }
    else
    {
        $get_data= $this->callAPI('GET', 'https://opentdb.com/api.php?amount=10&category=18', false);
        $data = json_decode($get_data, true);
        $this->view('quiz', $data);
    }
}

This obviously needs more work, but I hope you get the gist. Please also notice the fix in $_POST[key] key would be seen as a constant, not a variable.

CodePudding user response:

You question lacks clarity. I assume it should have said

I do an API request to get questions and answers. I create an HTML page with a <form> to ask the questions. The form then does a post request to a script where I check the answers. I need to store the answers to use when the player submits their answer.

According to the API documentation in your link, you can only do a GET request.
So the post fields are not applicable.

$request = array();
$request[] = "Accept: application/json";
$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTPHEADER, $request);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);    
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);   
curl_setopt($ch, CURLOPT_URL, 'https://opentdb.com/api.php?amount=10&category=21&difficulty=easy&type=multiple'); 
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_TIMEOUT,10);
curl_setopt($ch, CURLOPT_FAILONERROR,true);
curl_setopt($ch, CURLOPT_POST, false);
curl_setopt($ch, CURLOPT_HTTPGET, true);
curl_setopt($ch, CURLOPT_ENCODING,"");
curl_setopt($ch, CURLOPT_VERBOSE, true);

$response = json_decode(curl_exec($ch),true);
var_export($response);

The above returns this:

    array (
  'response_code' => 0,
  'results' => 
  array (
    0 => 
    array (
      'category' => 'Sports',
      'type' => 'multiple',
      'difficulty' => 'easy',
      'question' => 'In golf, what name is given to a hole score of two under par?',
      'correct_answer' => 'Eagle',
      'incorrect_answers' => 
      array (
        0 => 'Birdie',
        1 => 'Bogey',
        2 => 'Albatross',
      ),
    ),
    1 => 
    array (
      'category' => 'Sports',
      'type' => 'multiple',
      'difficulty' => 'easy',
      'question' => 'How many soccer players should be on the field at the same time?',
      'correct_answer' => '22',
      'incorrect_answers' => 
      array (
        0 => '20',
        1 => '24',
        2 => '26',
      ),
    ),
    2 => 
    array (
      'category' => 'Sports',
      'type' => 'multiple',
      'difficulty' => 'easy',
      'question' => 'Who won the 2015 Formula 1 World Championship?',
      'correct_answer' => 'Lewis Hamilton',
      'incorrect_answers' => 
      array (
        0 => 'Nico Rosberg',
        1 => 'Sebastian Vettel',
        2 => 'Jenson Button',
      ),
    ),
    3 => 
    array (
      'category' => 'Sports',
      'type' => 'multiple',
      'difficulty' => 'easy',
      'question' => 'When was the first official international game played?',
      'correct_answer' => '1872',
      'incorrect_answers' => 
      array (
        0 => '1880',
        1 => '1863',
        2 => '1865',
      ),
    ),
    4 => 
    array (
      'category' => 'Sports',
      'type' => 'multiple',
      'difficulty' => 'easy',
      'question' => 'Which boxer was banned for taking a bite out of Evander Holyfield\'s ear in 1997?',
      'correct_answer' => 'Mike Tyson',
      'incorrect_answers' => 
      array (
        0 => 'Roy Jones Jr.',
        1 => 'Evander Holyfield',
        2 => 'Lennox Lewis',
      ),
    ),
    5 => 
    array (
      'category' => 'Sports',
      'type' => 'multiple',
      'difficulty' => 'easy',
      'question' => 'Which African American is in part responsible for integrating Major League baseball?',
      'correct_answer' => 'Jackie Robinson',
      'incorrect_answers' => 
      array (
        0 => 'Curt Flood',
        1 => 'Roy Campanella',
        2 => 'Satchell Paige',
      ),
    ),
    6 => 
    array (
      'category' => 'Sports',
      'type' => 'multiple',
      'difficulty' => 'easy',
      'question' => 'Who won the premier league title in the 2015-2016 season following a fairy tale run?',
      'correct_answer' => 'Leicester City',
      'incorrect_answers' => 
      array (
        0 => 'Tottenham Hotspur',
        1 => 'Watford',
        2 => 'Stoke City',
      ),
    ),
    7 => 
    array (
      'category' => 'Sports',
      'type' => 'multiple',
      'difficulty' => 'easy',
      'question' => 'Who did Steven Gerrard win the Champions League with?',
      'correct_answer' => 'Liverpool',
      'incorrect_answers' => 
      array (
        0 => 'Real Madrid',
        1 => 'Chelsea',
        2 => 'Man City',
      ),
    ),
    8 => 
    array (
      'category' => 'Sports',
      'type' => 'multiple',
      'difficulty' => 'easy',
      'question' => 'Which country will host the 2022 FIFA World Cup?',
      'correct_answer' => 'Qatar',
      'incorrect_answers' => 
      array (
        0 => 'USA',
        1 => 'Japan',
        2 => 'Switzerland',
      ),
    ),
    9 => 
    array (
      'category' => 'Sports',
      'type' => 'multiple',
      'difficulty' => 'easy',
      'question' => 'In the 2014 FIFA World Cup, what was the final score in the match Brazil - Germany?',
      'correct_answer' => '1-7',
      'incorrect_answers' => 
      array (
        0 => '1-5',
        1 => '1-6',
        2 => '2-6',
      ),
    ),
  ),
)

I do not understand this:

$_SERVER["REQUEST_METHOD"] is superfluous.
It was not clear this was the player posting answers.
If there was no post, the script would not be running.

If you are using $_SERVER["REQUEST_METHOD"] as if your curl request will will set the value of $_SERVER["REQUEST_METHOD"], it will not.

This is wrong.

curl_setopt($curl, CURLOPT_HTTPHEADER, array(
      'APIKEY:xxxxxx',
      'Content-Type: application/json',
   ));

Content-Type: application/json is incorrect unless you have more documentation that is in your link.
What the API doc says is

Use of this API does not require a API Key, just generate the URL below use it in your own application to retrieve trivia questions.



And I could find no documentation that the request should be JSON.
The only request format I could find was this:

https://opentdb.com/api.php?amount=10&category=21&difficulty=medium&type=multiple

That is not a POST request, a JSON request, or a PUT request.
It is a GET request.

The way you unpack the result nested array is problematic.
This is incorrect.

 foreach ($data as $key => $value){
   foreach ($value as $key => $k){

It should probably look like this ($key is only used once)

 foreach ($data as $value){
   foreach ($value as $key => $k){

Still the first foreach should look like this:

foreach($data['results'] as $key => list(,,,$question,$correctAnswer,$incorrectAnswers){
  $data[$key]['question'] = $question; 
  $data[$key]['correctAnswer'] = $correctAnswer; 
  $data[$key]['incorrectAnserers'] = $incorrectAnswers; 

} You should have a player id, save the questions and answers with their id.
I often use their ip address as the user id.

$id= intval(str_replace('.','',$_SERVER['REMOTE_ADDR']));

$jsn = json_encode($data,true);
file_put_contents("$id.jsn",$jsn);

Then make the HTML form for the questions.
You really should have included the HTML for the form where the player enters their answers. So I will use a very simplified form. You then drop $form in the questions HTML

$form = '';
$form ."<form action="#" method="post>";
foreach($data as $number =>  list($question,$correctAnswer,$choices){
   $choices[] = $correctAnswer;
   shuffle($choices);
   $form .= "Q$number: $question<br>\n";
   $form .= "<input type=\"radio\" name=\"a$number\"  /> $choice[0]<br>\n";
   $form .= "<input type=\"radio\" name=\"a$number\"  /> $choice[1]<br>\n";       
   $form .= "<input type=\"radio\" name=\"a$number\"  /> $choice[2]<br>\n";       
   $form .= "<input type=\"radio\" name=\"a$number\"  /> $choice[3]<br>\n";
}
$form .= "<input type=\"hidden\" name=\"id\" value="$id\"\n";
$form .= "</form><br>\n";

Then when the answers are submitted get the questions and answers again.

$id = intval($_POST['id']);
$data = json_decode(file_get_contents("$is.jsn"),true);
  • Related