Create a PDF Certificate with Symfony PHP

You can capture a name and a quiz score to generate a certificate. You need to answer all questions correctly to print a certificate.

The code to save Riddle events to a session cookie

Place the code below on the page where you embedded your Riddle.

Most PDF generators use PHP. It is therefore easier to store the value from the form in a session cookie, which PHP can access. Normally we suggest storing Riddle event data in local storage, but to access local storage with PHP, you need to retrieve the values with JavaScript and pass them to PHP using POST. As many webservers have security in place to prevent POST data being passed to a page, using a session cookie is simpler as long as you limit the storage volume in the cookie to the allowed limit of 4KB (which is only about 1024 characters of Riddle data).

To use the data to print a PDF certificate, you need to create a second page, which you will use as an external result page in your Riddle. If you click through the Riddle on this page, it will take you to a custom result page. The code needed on that page is also pasted below, so please come back here later to read on.

// Clear the session cookie on page load.
document.cookie = "Participant_Name=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";

window.addEventListener("message", function (event) {
    if (event.data.type !== "riddleEvent") {
        return;
    }

    // event.data is already a JavaScript object, no need to parse it.
    var eventData = event.data.data;

    // Check if it is the 'Form_Submit' action - if it is, retrieve the name field.
    if (eventData.action === "Form_Submit") {
        // Find the name field in the form answers
        const formAnswers = eventData.formAnswers;
        const nameField = formAnswers.find((answer) => answer.blockType === "Name");
        const nameValue = nameField.data;

        // Store the answer value in a session cookie.
        document.cookie = "Participant_Name=" + nameValue + "; path=/;";

        // Write the value to the console for verification.
        console.log("Participant_Name stored: ", nameValue);

        // Push the url to the backend code of your certificate generator.
        window.riddleDataLayer.push({
            key: "redirect_url",
            value: "http://your-website.com/certificate/certificate.php"
        });
    }
});

Required Dependencies

setasign/fpdf
setasign/fpdi

PdfController.php

<?php

// src/Controller/PdfController.php

namespace App\Controller;

use setasign\Fpdi\Fpdi;
use setasign\Fpdi\PdfReader\PageBoundaries;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;

class PdfController extends AbstractController
{
    private Fpdi $fpdi;

    public function __construct()
    {
        $this->fpdi = new Fpdi();
    }

    #[Route('/api/certificate', name: 'pdf_index', methods: ['GET'])]
    public function index(Request $request): Response
    {
        $this->fpdi->setSourceFile($this->getParameter('kernel.project_dir') . '/public/riddle_certificate.pdf');
        $tplIdx = $this->fpdi->importPage(1, PageBoundaries::MEDIA_BOX);

        $this->fpdi->addPage();
        $this->fpdi->useTemplate($tplIdx, ['adjustPageSize' => true]);

        // Set the font and color.
        $this->fpdi->SetFont('Arial', 'B', 36);
        $this->fpdi->SetTextColor(19, 100, 123);

        // Set the Y position.
        $this->fpdi->SetY(145);

        // Get Participant Name from cookie Participant_Name.
        $Participant_name = $request->cookies->get('Participant_Name', 'Participant Name Not Found');

        // Add the Participant Name to the PDF.
        $this->fpdi->Cell($this->fpdi->GetPageWidth() - 20, 10, $Participant_name, 0, 1, 'C');

        // Create a temporary file to save the PDF.
        $pdfFile = tempnam(sys_get_temp_dir(), 'pdf');

        // Save the PDF to the temporary file.
        $this->fpdi->Output($pdfFile, 'F');

        // Create a response with the PDF content.
        return new Response(file_get_contents($pdfFile), 200, [
            'Content-Type' => 'application/pdf',
            'Content-Disposition' => 'inline; filename="riddle_certificate.pdf"',
        ]);
    }
}