A single PHP script can generate different PDF mark sheets by receiving a student ID through the query string. The ID is validated, used in a prepared PDO query and matched with a record in the sample student3 table.
URL: ?id=4
|
v
Validate student ID
|
v
PDO prepared query
|
v
Fetch one student record
|
v
FPDF
|
v
Student mark sheet PDF
Each student name below links to the same PDF-generating script. Only the id value in the query string changes.
| ID | Student Name | PDF Mark Sheet |
|---|---|---|
| 2 | Max Ruin | View PDF |
| 3 | Arnold | View PDF |
| 4 | Krish Star | View PDF |
| 5 | John Mike | View PDF |
| 6 | Alex John | View PDF |
| 7 | My John Rob | View PDF |
| 8 | Asruid | View PDF |
| 9 | Tes Qry | View PDF |
| 10 | Big John | View PDF |
For example, the following URL requests the student whose ID is 4:
pdf-data-student-mark-output.php?id=4
The value after ?id= identifies the student whose record is required.
?id=4
We should not use the query-string value directly in an SQL statement. First validate it, and then send it to a prepared PDO query.
The student ID should be a positive integer.
$id=filter_input(
INPUT_GET,
'id',
FILTER_VALIDATE_INT,
[
'options' => [
'min_range' => 1
]
]
);
if($id===false || $id===null){
http_response_code(400);
exit('Invalid student ID.');
}
This rejects missing IDs, non-numeric values and values below 1 before the database query is executed.
The query selects the student details and calculates the total marks inside SQL.
$sql="SELECT id,name,class,social,science,math,
(social + science + math) AS total
FROM student3
WHERE id=:id";
$stmt=$dbo->prepare($sql);
$stmt->bindValue(':id',$id,PDO::PARAM_INT);
$stmt->execute();
$row=$stmt->fetch(PDO::FETCH_ASSOC);
The value is bound as PDO::PARAM_INT, so the ID remains separate from the SQL statement.
If no matching student is found:
if(!$row){
http_response_code(404);
exit('Student record not found.');
}
After the database record has been successfully collected, create the FPDF document.
$pdf=new FPDF();
$pdf->AddPage();
$pdf->Image(
'../images/top2.jpg',
10,
10
);
$pdf->SetFont('Arial','BU',20);
$pdf->SetXY(80,50);
$pdf->Cell(
30,
10,
'MARK SHEET',
0,
0,
'L'
);
The ID, name and class can be stored in an array and displayed with a loop instead of repeating the same code three times.
$details=[
'ID:' => $row['id'],
'NAME:' => $row['name'],
'CLASS:' => $row['class']
];
$pdf->SetY(80);
foreach($details as $label=>$value){
$pdf->SetFont('Arial','B',16);
$pdf->Cell(
30,
10,
$label,
0,
0,
'L'
);
$pdf->SetFont('Arial','',14);
$pdf->Cell(
80,
10,
(string)$value,
0,
1,
'L'
);
}
The three subjects can also be stored in an array and displayed with one loop.
$subjects=[
'SOCIAL' => $row['social'],
'SCIENCE' => $row['science'],
'MATH' => $row['math']
];
$pdf->SetXY(30,130);
$pdf->SetFont('Arial','UB',16);
$pdf->Cell(
100,
10,
'SUBJECT',
0,
0,
'L'
);
$pdf->Cell(
50,
10,
'MARK',
0,
1,
'L'
);
$pdf->SetFont('Arial','',14);
foreach($subjects as $subject=>$mark){
$pdf->SetX(30);
$pdf->Cell(
100,
10,
$subject,
0,
0,
'L'
);
$pdf->Cell(
50,
10,
(string)$mark,
0,
1,
'L'
);
}
The total is already calculated by the SQL query:
$row['total']
<?php
require 'config.php';
require 'fpdf.php';
$id=filter_input(
INPUT_GET,
'id',
FILTER_VALIDATE_INT,
[
'options' => [
'min_range' => 1
]
]
);
if($id===false || $id===null){
http_response_code(400);
exit('Invalid student ID.');
}
try{
$sql="SELECT id,name,class,social,science,math,
(social + science + math) AS total
FROM student3
WHERE id=:id";
$stmt=$dbo->prepare($sql);
$stmt->bindValue(':id',$id,PDO::PARAM_INT);
$stmt->execute();
$row=$stmt->fetch(PDO::FETCH_ASSOC);
}catch(PDOException $e){
error_log($e->getMessage());
http_response_code(500);
exit('Unable to load the student record.');
}
if(!$row){
http_response_code(404);
exit('Student record not found.');
}
$pdf=new FPDF();
$pdf->AddPage();
$pdf->Image(
'../images/top2.jpg',
10,
10
);
$pdf->SetFont('Arial','BU',20);
$pdf->SetXY(80,50);
$pdf->Cell(
30,
10,
'MARK SHEET',
0,
0,
'L'
);
$details=[
'ID:' => $row['id'],
'NAME:' => $row['name'],
'CLASS:' => $row['class']
];
$pdf->SetY(80);
foreach($details as $label=>$value){
$pdf->SetFont('Arial','B',16);
$pdf->Cell(
30,
10,
$label,
0,
0,
'L'
);
$pdf->SetFont('Arial','',14);
$pdf->Cell(
80,
10,
(string)$value,
0,
1,
'L'
);
}
$pdf->Line(10,115,190,115);
$pdf->SetXY(30,130);
$pdf->SetFont('Arial','UB',16);
$pdf->Cell(
100,
10,
'SUBJECT',
0,
0,
'L'
);
$pdf->Cell(
50,
10,
'MARK',
0,
1,
'L'
);
$subjects=[
'SOCIAL' => $row['social'],
'SCIENCE' => $row['science'],
'MATH' => $row['math']
];
$pdf->SetFont('Arial','',14);
foreach($subjects as $subject=>$mark){
$pdf->SetX(30);
$pdf->Cell(
100,
10,
$subject,
0,
0,
'L'
);
$pdf->Cell(
50,
10,
(string)$mark,
0,
1,
'L'
);
}
$pdf->Line(30,170,150,170);
$pdf->SetX(30);
$pdf->SetFont('Arial','B',14);
$pdf->Cell(
100,
10,
'TOTAL',
0,
0,
'L'
);
$pdf->Cell(
50,
10,
(string)$row['total'],
0,
1,
'L'
);
$pdf->SetXY(150,220);
$pdf->SetFont('Arial','',14);
$pdf->Cell(
40,
10,
'Signature',
0,
1,
'C'
);
$pdf->Output(
'I',
'student-mark-sheet-'.$id.'.pdf'
);
The downloadable database-to-PDF project is available from the main student table tutorial. It includes the sample database, configuration and related PDF examples.
FPDF Database Project Installation and DownloadThe core lesson on this page is receiving the student ID, retrieving the matching database record and generating the PDF. QR-code generation can be added separately when required.
Plus2net also has a project that combines a MySQL record, certificate image and QR code:
Embed QR Code in a Certificate using MySQL DataValidate the query-string value before running the database query. The updated example accepts only a positive integer.
After fetch(), check whether a row was returned. An ID can be valid as an integer but still have no matching record in the database.
Do not display the complete PDO exception to the browser. Log the database error and return a short user-facing message.
The PDF-generating output script should not send HTML, debugging output or extra whitespace before calling FPDF Output().
A normal Cell() does not wrap long text. If variable-length content must wrap, use the FPDF MultiCell() tutorial.
The previous example depended on an external Google Charts QR endpoint. The updated mark-sheet example removes that dependency.
Pass the record ID to the PHP script, validate it, fetch the matching row with a prepared PDO query and use the returned values while creating the FPDF document.
The PDF script expects a positive integer ID. Validation rejects missing or invalid values before the database query is executed.
A prepared statement keeps the supplied ID separate from the SQL query and allows it to be bound as an integer.
The SQL query calculates the total by adding the social, science and math columns and returns the result with the alias total.
The script checks the result returned by fetch(). If no row is found, it stops before generating the PDF and returns a student-record-not-found message.
Yes. The same PHP script is reused. Changing the ID in the query string causes it to fetch a different database record and generate that student's PDF.
Use the multi-page database PDF example, which generates enough PDF pages to accommodate a larger result set.
Author & Instructor at plus2net
I write and maintain practical tutorials on Python, PHP, SQL, JavaScript, HTML, jQuery, and web development at plus2net. The tutorials focus on clear explanations, working examples, and code that readers can test and adapt while learning.