We will look at some of the parts of this script that are different from the previous examples. Visitors need to get their own details on a certificate, so we will create the document in mem- ory rather than in a file. If we wrote it to a file, we would need to worry about mechanisms to create unique filenames, stop people from snooping into others’ certificates, and determine a way to delete older certificate files to free up hard drive space on our server. In order to create a document in memory, we call pdf_open() without parameters as follows: $pdf = pdf_open(); Our simplified border will consist of three stripes: a fat border and two thin borders, one inside the main border and one outside. We will draw all of these as rectangles. To position the borders in such a way that we can easily alter the page size or the appearance of the borders, we will base all the border positions on the variables that we already have, $width and $height and a few new ones: $inset, $border, and $inner. We will use $inset to specify how many points wide the border at the edge of the page is, $border to specify the thickness of the main border, and $inner to specify how wide the gap between the main border and the thin borders will be. If you have drawn with another graphics API, drawing with PDFlib will present few surprises. If you haven’t read Chapter 19, “Generating Images,” you might find it helpful to do so, as drawing images with the gd library is quite similar to drawing them with PDFlib. The thin borders are easy. To create a rectangle, we use pdf_rect(), which requires as para- meters the PDF document identifier, the x and y coordinate of the rectangle’s lower left corner, and the width and height of the rectangle. Because we want our layout to be flexible, we calcu- late these from the variables we have set. pdf_rect($pdf, $inset-$inner, $inset-$inner, $width-2*($inset-$inner), $height-2*($inset-$inner)); The call to pdf_rect() sets up a path in the shape of a rectangle. In order to draw that shape, we need to call the pdf_stroke() function as follows: pdf_stroke($pdf); In order to draw the main border, we need to specify the line width. The default line width is 1 point. The following call to pdf_setlinewidth() will set it to $border (in this case 10) points: pdf_setlinewidth($pdf, $border); With the width set, we again create a rectangle with pdf_rect() and call pdf_stroke() to draw it. Generating Personalized Documents in Portable Document Format (PDF) C HAPTER 30 30 GENERATING PERSONALIZED DOCUMENTS IN PDF 775 36 7842 CH30 3/6/01 3:40 PM Page 775 pdf_rect($pdf, $inset+$border/2, $inset+$border/2, $width-2*($inset+$border/2), $height-2*($inset+$border/2)); pdf_stroke($pdf); After we have drawn our one wide line, we need to remember to set the line width back to 1 with this code: pdf_setlinewidth($pdf, 1.0); We are going to use pdf_show_xy() to position each line of text on the certificate. For most lines of text, we are using a configurable left margin ($startx) as the x coordinate and a value chosen by eye as the y coordinate. As we want the heading centered on the page, we need to know its width in order to position the left hand side of it. We can get the width using pdf_stringwidth(). The call pdf_stringwidth($pdf, “PHP Certification”); will return the width of the string “PHP Certification” in the current font and font size. As with the other versions of the certificate, we will include a signature as a scanned bitmap. The following three statements $signature = pdf_open_image_file($pdf, “tiff”, “/htdocs/book/chapter30/signature.tif”); pdf_place_image($pdf, $signature, 200, 75, 1); pdf_close_image($pdf, $signature); will open a TIFF file containing the signature, add the image to the page at the specified loca- tion, and close the TIFF file. Other file types can also be used. The only parameter that might not be self explanatory is the fifth parameter to pdf_place_image(). This function is not lim- ited to inserting the image at its original size. The fifth parameter is a scale factor. We have chosen to display the image at full size and used 1 as the scale factor, but could have used a larger number to enlarge the image, or a fraction to shrink it. The hardest item to add to our certificate using PDFlib is the rosette. We cannot automatically open and include a Windows Meta File containing the rosette we already have, but we are free to draw any shapes we like. In order to draw a filled shape such as one of the ribbons, we can write the following code. Here we set the stroke or line color to be black and the fill or interior color to be a navy blue: pdf_setrgbcolor_fill($pdf, 0, 0, .4); //dark blue pdf_setrgbcolor_stroke($pdf, 0, 0, 0); // black Here we set up a five-sided polygon to be one of our ribbons and then fill it: Building Practical PHP and MySQL Projects P ART V 776 36 7842 CH30 3/6/01 3:40 PM Page 776 pdf_moveto($pdf, 630, 150); pdf_lineto($pdf, 610, 55); pdf_lineto($pdf, 632, 69); pdf_lineto($pdf, 646, 49); pdf_lineto($pdf, 666, 150); pdf_closepath($pdf); pdf_fill($pdf); As we would like the polygon outlined as well, we need to set up the same path a second time, but call pdf_stroke() instead of pdf_fill(). As the multipointed star is a complex repetitive shape, we have written a function to calculate the locations in the path for us. Our function is called draw_star() and requires x and y coor- dinates for the center, the number of points required, the radius, the length of the points, a PDF document identifier, and a Boolean value to indicate if the star shape should be filled in or just an outline. The draw_star() function uses some basic trigonometry to calculate locations for a series of points to lay out a star. For each point we requested our star to have, we find a point on the radius of the star and a point on a smaller circle $point_size within the outer circle and draw a line between them. One thing worth noting is that PHP’s trigonometric functions such as cos() and sin() work in radians rather than degrees. Using a function and some mathematics, we can accurately generate a complex repetitive shape. Had we wanted a complicated pattern for our page border, we could have used a similar approach. When all our page elements are generated, we need to end the page and the document. Problems with Headers One minor thing to note in all these scripts is that we need to tell the browser what type of data we are going to send it. We have done this by sending a content-type HTTP header, for example header( “Content-type: application/msword” ); or header( “Content-type: application/pdf” ); One thing to be aware of is that browsers deal with these headers inconsistently. In particular, Internet Explorer often chooses to ignore the MIME type and attempt to automatically detect the type of file. Generating Personalized Documents in Portable Document Format (PDF) C HAPTER 30 30 GENERATING PERSONALIZED DOCUMENTS IN PDF 777 36 7842 CH30 3/6/01 3:40 PM Page 777 Some of our headers seemed to cause problems with session control headers. There are a few ways around this. We have found using GET parameters rather than POST or session variable parameters avoids the problem. Another solution is not to use an inline PDF but to get the user to download it instead as shown in the Hello World PDFlib example. You can also avoid problems if you are willing to write two slightly different versions of your code, one for Netscape and one for Internet Explorer. This issue is a known problem with the combination of Internet Explorer dynamically gener- ated PDF files and the Acrobat Reader plug-in. Adobe has a Technical Note on the subject at http://www.adobe.com/support/techdocs/3d76.htm Although it talks about generating the PDF with Active Server Pages, the problem is the same. Extending the Project Adding some more realistic assessment tasks to the examination obviously could extend this project, but it is really intended as an example of ways to deliver your own documents. Customized documents that you might want to deliver online could include legal documents, partially filled in order or application forms, or forms needed by government departments. Further Reading We suggest you visit Adobe’s site if you want to know more about the PDF (and FDF) formats. http://www.adobe.com Building Practical PHP and MySQL Projects P ART V 778 36 7842 CH30 3/6/01 3:40 PM Page 778 IN THIS PART A Installing PHP 4 and MySQL 781 B Web Resources 803 Appendixes PART VI 37 7842 part 6 3/6/01 3:35 PM Page 779 37 7842 part 6 3/6/01 3:35 PM Page 780 APPENDIX A Installing PHP 4 and MySQL 38 7842 app a 3/6/01 3:40 PM Page 781 Appendixes P ART VI 782 Apache, PHP, and MySQL are available for multiple operating systems and Web servers. In this appendix, we will explain how to set up Apache, PHP, and MySQL on various server plat- forms. We’ll cover the most common options available for UNIX and Windows NT. Topics we will cover in this appendix include • Running PHP as a CGI interpreter or as a module • Installing Apache, SSL, PHP, and MySQL under UNIX • Installing Apache, PHP, and MySQL under Windows • Testing that it’s working: phpinfo() • Adding PHP and MySQL to Internet Information Server • Adding PHP and MySQL to Personal Web Server • Considering other configurations Our goal in this appendix is to provide you with an installation guide for a Web server which will enable you to host multiple Web sites. Some sites, like in the examples covered, require Secure Socket Layer (SSL) for e-commerce solutions. And most are driven via scripts to con- nect to a database (DB) server and extract and process data. We have chosen Apache, PHP, and MySQL for the job because of their cost, reliability, performance, ease of integration, and functionality. Running PHP as a CGI Interpreter or Module PHP is a simple, yet powerful, server-side HTML-embedded scripting language that enables you to access files, execute commands, and open network connections on the server. The inter- preter can be run as either a module or as a separate CGI binary. Generally, the module version is used for performance reasons. However the CGI version enables Apache users to run differ- ent PHP-enabled pages under different user IDs. Although many of these actions pose a secu- rity threat by default, PHP is designed to be more secure for writing CGI programs than either Perl or C. PHP gives you a variety of configuration options to select the right combination of security and useability that you need. Yet, if you decide that you would like to run PHP as a CGI interpreter, then you should read the CERT Advisory CA-96.11. http://www.cert.org/advisories/CA-96.11.interpreters_in_cgi_bin_dir.html The default setup for the CGI option requires that you install an executable PHP binary to the Web server cgi-bin directory, whereas CERT recommends against this method. This is because most general-purpose interpreters (but not PHP) accessible via the cgi-bin directory allow remote users to execute any command that the interpreter can execute on that server. PHP does not allow attackers to exploit this hack. 38 7842 app a 3/6/01 3:40 PM Page 782 PHP accomplishes this by doing the following: • PHP refuses to interpret the command-line arguments, when invoked as a CGI binary. • PHP also prevents access to any Web documents without checking permission and access when invoked as a CGI binary. However, you must enable enable-force-cgi-redirect and set up the runtime configuration directives doc_root and user_dir. Of course, this is only relevant if you choose the default setup. If you choose to use the CGI method, an even more secure option is to put the PHP binary somewhere outside the Web tree. The typical location used would be the /usr/local/bin direc- tory for UNIX and c:\PHP-DIR\ for Windows. The downside to this option is that you will have to include a line to execute the PHP interpreter in all CGI scripts. For example, on a UNIX machine with the PHP interpreter at /usr/local/bin/php, the first line of each script would be #! /usr/local/bin/php You will also need to set any file permissions to make each script executable. That is, you will need to treat the PHP script as you would treat a CGI script written in Perl. In this appendix we will primarily cover the module option as the method to run PHP in a UNIX environment, and the CGI method with Windows systems. Installing Apache, PHP, and MySQL Under UNIX Let’s begin by installing Apache, PHP, and MySQL under a UNIX environment. First, we must decide what extra modules we will load under the trio. Because some of the examples covered in this book entail using a secure server for Web transactions, we will install the Secure Socket Layer (SSL) enabled server. Our PHP setup will be the default setup but will also cover enabling the following libraries under PHP. • http://curl.haxx.se/: Client URL Library functions • http://pspell.sourceforge.net/: Portable Spell Checker Libraries • http://www.pdflib.com/pdflib/index.html: Library for Generating PDF documents on-the-fly These are just three of the many libraries available for PHP. We are enabling them so you can get an idea of what it takes to enable extra libraries with PHP. It is recommended that you install all libraries on your machine before you compile the PHP module. We have already discussed the download and installation of these library programs in the rele- vant chapters, so this is not covered here. What will be covered is how you enable them under PHP during the compilation process. Installing PHP 4 and MySQL A PPENDIX A A INSTALLING PHP 4 AND MYSQL 783 38 7842 app a 3/6/01 3:40 PM Page 783 Our installation will be done on a Red Hat 6.2 Linux server, but will be generic enough to apply to other UNIX servers. Let’s start by listing out the tools for our installation process. • Apache (http://www.apache.org/): The Web Server • Mod_SSL (http://www.modssl.org/): The module for the Secure Sockets Layer • OpenSSL (http://www.openssl.org/): Open Source Toolkit (required for Mod_SSL) • RSARef (http://ftpsearch.lycos.com/): Only necessary for those in the US • MySQL ( http://www.mysql.com/): The relational database • PHP ( http://www.php.net/): The server-side scripting language We will assume that you have root access to the server and that you have the following tools installed on your system. • Perl (Preferably the newest version) • gzip or gunzip • gcc and GNU make If you don’t have these items installed, you’ll need to take the necessary steps to get them installed before any of the procedures will make sense. If you do not have root access, your options are • Ask your sysadmin to install PHP for you • Install and execute the PHP engine in your own user cgi-bin directory • Run your own PHP-enabled Web server on a non-standard port We will focus on the case in which you have root access. When you are ready to begin the installation process, you should start by downloading all tar file sources to a temp directory. Make sure you put them somewhere with plenty of space. In our case, we chose /tmp/download for the temporary directory. You should download them as root to avoid permissions problems. The directories that we chose for our trio are the following: • /usr/local/apache • /usr/local/mysql • /usr/local/ssl You can install to different directories by changing the prefix option before installation. Appendixes P ART VI 784 38 7842 app a 3/6/01 3:40 PM Page 784 . 780 APPENDIX A Installing PHP 4 and MySQL 38 7842 app a 3/6/01 3:40 PM Page 781 Appendixes P ART VI 782 Apache, PHP, and MySQL are available for multiple operating systems and Web servers. In this appendix, we. 3/6/01 3:40 PM Page 778 IN THIS PART A Installing PHP 4 and MySQL 781 B Web Resources 803 Appendixes PART VI 37 7842 part 6 3/6/01 3:35 PM Page 779 37 7842 part 6 3/6/01 3:35 PM Page 780 APPENDIX A Installing. PHP as a CGI interpreter or as a module • Installing Apache, SSL, PHP, and MySQL under UNIX • Installing Apache, PHP, and MySQL under Windows • Testing that it’s working: phpinfo() • Adding PHP