2
\$\begingroup\$

This CAPTCHA is not text but basically images of objects that the users has to identify between an array of options. My current code is kind-of slow because the query takes almost .7s to execute and it has to run three times.

I'm looking for a way to improve it and make it faster.

// Loop through to display the pictures and options
for ($i = 0; $i < 2; $i ++) {
    $answers = array();

    // Fill an array with 5 random objects unique objects
    $result = mysqli_query($link, "SELECT MAX(captcha_images.image_code) AS image_code, captcha_objects.name FROM captcha_objects LEFT JOIN captcha_images ON captcha_images.object_id = captcha_objects.id WHERE captcha_images.approved = 1 GROUP BY captcha_objects.name ORDER BY RAND() LIMIT 5") or die(mysqli_error($link));
    while($row = mysqli_fetch_assoc($result)) $answers[] = array("code" => $row['image_code'], "name" => $row['name']);

    // Pick the first one as the correct answer
    $_SESSION['captcha_ans'][] = $answers[0];
    $chosen_objects_id[] = mysqli_get_value("id", "captcha_objects", "name", $answers[0]['name'], false);

    // Shuffle 'em
    shuffle($answers);

    // show picture
    $image = ImageCreateFromString(base64_decode($_SESSION['captcha_ans'][$i]['code']));

    // Generate the output of the image, encode it and include it as a data URI
    ob_start();
    imagejpeg($image);
    $base64 = base64_encode(ob_get_contents());
    ob_end_clean();
    echo '<div><img src="data:image/jpeg;base64,'.$base64.'"><br><select name="answer[]"><option value=""></option>';

    // show answers
    foreach ($answers as $answer)
        echo '<option value="'.$answer['name'].'">'.$answer['name'].'</option>';

    // close options
    echo '</select></div>';
    unset($answers);
}
\$\endgroup\$
1
\$\begingroup\$

Performance

You didn't post the mysqli_get_value code, but I would assume that it interacts with the database. Is this call really necessary? You don't seem to use the result. But if you do need it somewhere else: couldn't you just retrieve the id in the initial query?

Have you tried storing the path to an image in the database instead of storing the whole image?

As to your main query: ORDER BY RAND() is quite slow. Check out this question for faster solutions to select random rows from a big table. If you google for mysql select random values from table you should find a lot more results as well (for example here).

Also, do captcha_images and captcha_objects really need to be different tables? I don't know your whole db schema, but it seems that it could all go into the same table, thus saving you a join.

Misc

  • a line length of 323 characters is way too long, it will not fit on any screen. I would aim for 80 (maybe 120).
  • use curly braces, even for one-line statements (for readability and to prevent bugs).
  • use spaces around . (I think that it really helps with readability).
| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.