F
IGURE 30.2
index.html asks the user to answer quiz questions.
Grading the Answers
When the user submits his answers to the questions in index.html, we need to grade him and
calculate a score. This is done by the script called
score.php. The code for this script is shown
in Listing 30.2.
L
ISTING 30.2
score.php—Script to Mark Exams
<?
// check that all the data was received
if($q1==’’||$q2==’’||$q3==’’||$name==’’)
{
echo “<h1><p align = center><img src = ‘rosette.gif’ alt = ‘’>
Generating Personalized Documents in Portable Document Format (PDF)
C
HAPTER 30
30
GENERATING
PERSONALIZED
DOCUMENTS IN
PDF
755
36 7842 CH30 3/6/01 3:40 PM Page 755
LISTING 30.2 Continued
Sorry:
<img src = ‘rosette.gif’ alt = ‘’></h1>”;
echo “<p>You need to fill in your name and answer all questions”;
}
else
{
//add up the scores
$score = 0;
if($q1 == 1) // the correct answer for q1 is 1
$score++;
if($q2 == 1) // the correct answer for q2 is 1
$score++;
if($q3 == 1) // the correct answer for q3 is 1
$score++;
//convert score to a percentage
$score = $score / 3 * 100;
if($score < 50)
{
// this person failed
echo “<h1><p align = center><img src = ‘rosette.gif’ alt = ‘’>
Sorry:
<img src = ‘rosette.gif’ alt = ‘’></h1>”;
echo “<p>You need to score at least 50% to pass the exam”;
}
else
{
// create a string containing the score to one decimal place
$score = number_format($score, 1);
echo “<h1><p align = center><img src = ‘rosette.gif’ alt = ‘’>
Congratulations
<img src = ‘rosette.gif’ alt = ‘’></h1>”;
echo “<p>Well done $name, with a score of $score%,
you have passed the exam. “;
// provide links to scripts that generate the certificates
echo “<p>Please click here to download your certificate as
a Microsoft Word (RTF) file. “;
echo “<form action = ‘rtf.php’ method = get>”;
echo “<center>
Building Practical PHP and MySQL Projects
P
ART V
756
36 7842 CH30 3/6/01 3:40 PM Page 756
LISTING 30.2 Continued
<input type = image src = ‘certificate.gif’ border = 0>
</center>”;
echo “<input type = hidden name = score value = ‘$score’>”;
echo “<input type = hidden name = name value = ‘$name’>”;
echo “</form>”;
echo “<p>Please click here to download your certificate as
a Portable Document Format (PDF) file. “;
echo “<form action = ‘pdf.php’ method = get>”;
echo “<center>
<input type = image src = ‘certificate.gif’ border = 0>
</center>”;
echo “<input type = hidden name = score value = ‘$score’>”;
echo “<input type = hidden name = name value = ‘$name’>”;
echo “</form>”;
echo “<p>Please click here to download your certificate as
a Portable Document Format (PDF) file generated with PDFLib. “;
echo “<form action = ‘pdflib.php’ method = get>”;
echo “<center>
<input type = image src = ‘certificate.gif’ border = 0>
</center>”;
echo “<input type = hidden name = score value = ‘$score’>”;
echo “<input type = hidden name = name value = ‘$name’>”;
echo “</form>”;
}
}
?>
This script will display a message if the user did not answer all questions or scored less than
our chosen pass mark.
If the user successfully answered the questions, he will be allowed to generate a certificate.
The output of a successful visit is shown in Figure 30.3.
From here, the user has three options. He can have an RTF certificate, or one of two PDF
certificates. We will look at the script responsible for each.
Generating Personalized Documents in Portable Document Format (PDF)
C
HAPTER 30
30
GENERATING
PERSONALIZED
DOCUMENTS IN
PDF
757
36 7842 CH30 3/6/01 3:40 PM Page 757
FIGURE 30.3
score.php presents successful visitors with the option to generate a certificate in one of three ways.
Generating an RTF Certificate
There is nothing to stop us from generating an RTF document by writing ASCII text to a file or
a string variable, but it would mean learning yet another set of syntax.
Here is a very simple RTF document:
{\rtf1
{\fonttbl {\f0 Arial;}{\f1 Times New Roman;}}
\f0\fs28 Heading\par
\f1\fs20 This is an rtf document.\par
}
This document sets up a font table with two fonts: Arial, to be referred to as f0, and Times
New Roman, to be referred to as f1. It then writes Heading using f0 (Arial) in size 28
(14 point). The control
\par indicates a paragraph break. We then write This is an rtf
document
using f1 (Times New Roman) at size 20 (10 point).
We could generate a document like this manually, but there are no labor saving functions built
in to PHP to make the hard parts, such as incorporating graphics, easier. Fortunately, in many
documents, the structure, style, and much of the text are static, and only small parts change
from person to person. A more efficient way to generate a document is using a template.
Building Practical PHP and MySQL Projects
P
ART V
758
36 7842 CH30 3/6/01 3:40 PM Page 758
We can build a complex document, such as the one shown in Figure 30.4, easily using a word
processor.
Generating Personalized Documents in Portable Document Format (PDF)
C
HAPTER 30
30
GENERATING
PERSONALIZED
DOCUMENTS IN
PDF
759
FIGURE 30.4
Using a word processor, we can create a complex, attractive template easily.
Our template includes placeholders such as <<NAME>> to mark the places where dynamic data
will be inserted. It is not important what these place holders look like. We are using a mean-
ingful description between two sets of angled braces. It is important that we choose placehold-
ers that are highly unlikely to accidentally appear in the rest of the document. It will help you
to lay out your template if the placeholders are roughly the same length as the data they will
be replaced with.
The placeholders in this document are <<NAME>>, <<Name>>, <<score>>, and <<mm/dd/yyyy>>.
Note that we are using both NAME and Name, because we intend to use a case sensitive
method to replace them.
Now that we have a template, we need a script to personalize it. This script is called rtf.php,
and its code is shown in Listing 30.3.
LISTING 30.3 rtf.php—Script to Produce a Personalized RTF Certificate
<?
// check we have the parameters we need
36 7842 CH30 3/6/01 3:40 PM Page 759
LISTING 30.3 Continued
if( !$name || !$score )
{
echo “<h1>Error:</h1>This page was called incorrectly”;
}
else
{
//generate the headers to help a browser choose the correct application
header( “Content-type: application/msword” );
header( “Content-Disposition: inline, filename=cert.rtf”);
$date = date( “F d, Y” );
// open our template file
$filename = “PHPCertification.rtf”;
$fp = fopen ( $filename, “r” );
//read our template into a variable
$output = fread( $fp, filesize( $filename ) );
fclose ( $fp );
// replace the place holders in the template with our data
$output = str_replace( “<<NAME>>”, strtoupper( $name ), $output );
$output = str_replace( “<<Name>>”, $name, $output );
$output = str_replace( “<<score>>”, $score, $output );
$output = str_replace( “<<mm/dd/yyyy>>”, $date, $output );
// send the generated document to the browser
echo $output;
}
?>
This script performs some basic error checking to make sure that all the user details have been
passed in, and then moves to the business of creating the certificate.
The output of this script will be an RTF file rather than an HTML file, so we need to alert the
user’s browser to this fact. This is important so that the browser can attempt to open the file
with the correct application, or give a Save As… type dialog box if it doesn’t recognize the
RTF extension.
We specify the MIME type of the file we are outputting using PHP’s header() function to
send the appropriate HTTP header as follows:
Building Practical PHP and MySQL Projects
P
ART V
760
36 7842 CH30 3/6/01 3:40 PM Page 760
header( “Content-type: application/msword” );
header( “Content-Disposition: inline, filename=cert.rtf”);
The first header tells the browser that we are sending a Microsoft Word file (not strictly true,
but the most likely helper application for opening the RTF file).
The second header tells the browser to automatically display the contents of the file, and that
its suggested filename is cert.rtf. This is the default filename the user will see if he tries to save
the file from within his browser.
After the headers are sent, we open and read our template RTF file into the $output variable,
and use the str_replace() function to replace our placeholders with the actual data that we
want to appear in the file. The line
$output = str_replace( “<<Name>>”, $name, $output );
will replace any occurrences of the placeholder <<Name>> with the contents of the variable
$name.
Having made our substitutions, it’s just a matter of echoing the output to the browser.
A sample result from this script is shown in Figure 30.5.
Generating Personalized Documents in Portable Document Format (PDF)
C
HAPTER 30
30
GENERATING
PERSONALIZED
DOCUMENTS IN
PDF
761
FIGURE 30.5
rtf.php generates a certificate from an RTF template.
36 7842 CH30 3/6/01 3:40 PM Page 761
This approach works very well. The calls to str_replace() run very quickly, even though our
template and therefore the contents of $output are fairly long. The main problem from the
point of view of this application is that the user will load the certificate in his word processor
in order to print it. This is probably an invitation for people to modify the output. RTF does not
allow us to make a read-only document.
Generating a PDF Certificate from a Template
The process of generating a PDF certificate from a template is very similar. The main differ-
ence is that when we create the PDF file, some of our placeholders might be interspersed with
formatting codes. For example, if we look in the certificate template file we have created, we
can see that the placeholders now look like this:
<<N)-13(AME)-10(>)-6(>
<<Na)-9(m)0(e)-18(>>
<)-11(<)1(sc)-17(or)-6(e)-6(>)-11(>
<)-11(<)1(m)-12(m)0(/d)-6(d)-19(/)1(yy)-13(yy)-13(>>
If you look through the file, you will see that, unlike RTF, this is not a format that humans can
easily read through.
There are a few different ways we can deal with this.
We could go through each of these placeholders and delete the formatting codes. This actually
makes fairly little difference to how the document looks in the end as the codes embedded in
the previous template indicate how much space should be left between the letters of the place-
holders that we are going to replace anyhow. However, if we take this approach, we must go
through and hand edit the PDF file and repeat this each time we change or update the file. This
is not a big deal when dealing with only four placeholders, but it becomes a nightmare when,
for example, you have multiple documents with many placeholders, and you decide to change
the letterhead on all the documents.
We can avoid this problem using a different technique. You can use Adobe Acrobat to create a
PDF form—similar to an HTML form with blank named fields. You can then use a PHP script
to create what is called an FDF (Forms Data Format) file, which is basically a set of data to be
merged with a template. You can create FDFs using PHP’s FDF function library: specifically,
the fdf_create() function to create a file; the fdf_set_value() function to set the field
values; and the fdf_set_file() function to set the associated template form file. You can
then pass this file back to the browser with the appropriate MIME type, in this case vnd.fdf,
and the browser’s Acrobat Reader plug-in should substitute the data into the form.
Building Practical PHP and MySQL Projects
P
ART V
762
36 7842 CH30 3/6/01 3:40 PM Page 762
This is a neat way of doing things, but it has two limitations. First, it assumes that you own a
copy of Acrobat. Second, it is difficult to substitute in text that is inline rather than text that
looks like a form field. This might or might not be a problem, depending on what you are
trying to do. We have largely used PDF generation for generating letters where many things
must be substituted inline. FDFs do not work well for this purpose. If you are auto-filling for
example, a tax form online, this will not be a problem.
You can read more about the FDF format at Adobe’s site:
/>You should also look at the FDF documentation in the PHP manual if you decide to use this
approach:
/>We turn now to our PDF solution to the previous problem.
We can still find and replace the placeholders in our PDF file if we recognize that the addi-
tional format codes consist solely of hyphens, digits, and parentheses and can therefore be
matched via a regular expression. We have written a function, pdf_replace(), to automatically
generate a matching regular expression for a placeholder and replace that placeholder with the
appropriate text.
Other than this addition, the code for generating the certificate via a PDF template is very
similar to the RTF version. This script is shown in Listing 30.4.
LISTING 30.4 pdf.php—Script to Produce Personalized PDF Certificate Via a Template
<?
set_time_limit( 180 ); // this script can be very slow
function pdf_replace( $pattern, $replacement, $string )
{
$len = strlen( $pattern );
$regexp = ‘’;
for ( $i = 0; $i<$len; $i++ )
{
$regexp .= $pattern[$i];
if ($i<$len-1)
$regexp .= “(\)\-{0,1}[0-9]*\(){0,1}”;
}
return ereg_replace ( $regexp, $replacement, $string );
}
Generating Personalized Documents in Portable Document Format (PDF)
C
HAPTER 30
30
GENERATING
PERSONALIZED
DOCUMENTS IN
PDF
763
36 7842 CH30 3/6/01 3:40 PM Page 763
LISTING 30.4 Continued
if(!$name||!$score)
{
echo “<h1>Error:</h1>This page was called incorrectly”;
}
else
{
//generate the headers to help a browser choose the correct application
header( “Content-Disposition: filename=cert.pdf”);
header( “Content-type: application/pdf” );
$date = date( “F d, Y” );
// open our template file
$filename = “PHPCertification.pdf”;
$fp = fopen ( $filename, “r” );
//read our template into a variable
$output = fread( $fp, filesize( $filename ) );
fclose ( $fp );
// replace the place holders in the template with our data
$output = pdf_replace( “<<NAME>>”, strtoupper( $name ), $output );
$output = pdf_replace( “<<Name>>”, $name, $output );
$output = pdf_replace( “<<score>>”, $score, $output );
$output = pdf_replace( “<<mm/dd/yyyy>>”, $date, $output );
// send the generated document to the browser
echo $output;
}
?>
This script produces a customized version of our PDF document. The document, shown in
Figure 30.6, will print reliably on numerous systems, and is harder for the recipient to modify
or edit. You can see that the PDF document in Figure 30.6 looks almost exactly like the RTF
document in Figure 30.5.
Building Practical PHP and MySQL Projects
P
ART V
764
36 7842 CH30 3/6/01 3:40 PM Page 764