57 Opening a File Figure 2.2 PHP will specifically warn you when a file can’t be opened. If you get this error, you need to make sure that the user that the script runs as has per- mission to access the file you are trying to use. Depending on how your server is set up, the script might be running as the Web server user or as the owner of the directory that the script is in. On most systems, the script will run as the Web server user. If your script was on a UNIX system in the ~/public_html/chapter2/ directory, you would create a world writeable directory in which to store the order by typing the following: mkdir ~/orders chmod 777 ~/orders Bear in mind that directories and files that anybody can write to are dangerous.You should not have directories that are accessible directly from the Web as writeable. For this reason, our orders directory is two subdirectories back, above the public_html directo- ry.We will talk more about security later in Chapter 13,“E-commerce Security Issues.” Incorrect permission settings is probably the most common thing that can go wrong when opening a file, but it’s not the only thing. If the file can’t be opened, you really need to know this so that you don’t try to read data from or write data to it. If the call to fopen() fails, the function will return false.You can deal with the error in a more user-friendly way by suppressing PHP’s error message and giving your own: 04 525x ch02 1/24/03 3:38 PM Page 57 58 Chapter 2 Storing and Retrieving Data @ $fp = fopen("$DOCUMENT_ROOT/ /orders/orders.txt", 'a', 1); if (!$fp) { echo '<p><strong> Your order could not be processed at this time. ' .'Please try again later.</strong></p></body></html>'; exit; } The @ symbol in front of the call to fopen() tells PHP to suppress any errors resulting from the function call. Usually it’s a good idea to know when things go wrong, but in this case we’re going to deal with that elsewhere. This line can also be written as follows $fp = @fopen("$DOCUMENT_ROOT/ /orders/orders.txt", "a", 1); but this does tend to make it less obvious that you are using the error suppression operator. You can read more about error reporting in Chapter 23,“Debugging.” The if statement tests the variable $fp to see if a valid file pointer was returned from the fopen call; if not, it prints an error message and ends script execution. Because the page will finish here, notice that we have closed the HTML tags to give valid HTML. The output when using this approach is shown in Figure 2.3. Figure 2.3 Using your own error messages instead of PHP’s can be more user friendly. 04 525x ch02 1/24/03 3:38 PM Page 58 59 Writing to a File Writing to a File Writing to a file in PHP is relatively simple.You can use either of the functions fwrite() (file write) or fputs() (file put string); fputs() is an alias to fwrite().We call fwrite() in the following: fwrite($fp, $outputstring); This tells PHP to write the string stored in $outputstring to the file pointed to by $fp.We’ll discuss fwrite() in more detail before we talk about the contents of $out- putstring. Parameters for fwrite() The function fwrite() actually takes three parameters but the third one is optional.The prototype for fwrite() is int fwrite ( int fp, string string [, int length]) The third parameter, length, is the maximum number of bytes to write. If this parameter is supplied, fwrite() will write string to the file pointed to by fp until it reaches the end of string or has written length bytes, whichever comes first. File Formats When you are creating a data file like the one in our example, the format in which you store the data is completely up to you. (However, if you are planning to use the data file in another application, you may have to follow that application’s rules.) Let’s construct a string that represents one record in our data file.We can do this as follows: $outputstring = $date."\t".$tireqty." tires \t".$oilqty." oil\t" .$sparkqty." spark plugs\t\$".$total ."\t". $address."\n"; In our simple example, we are storing each order record on a separate line in the file.We choose to write one record per line because this gives us a simple record separator in the newline character. Because newlines are invisible, we represent them with the control sequence "\n". We will write the data fields in the same order every time and separate fields with a tab character.Again, because a tab character is invisible, it is represented by the control sequence "\t".You may choose any sensible delimiter that is easy to read back. The separator or delimiter character should either be something that will certainly not occur in the input, or we should process the input to remove or escape out any instances of the delimiter.We will look at processing the input in Chapter 4,“String Manipulation and Regular Expressions.” For now, we will assume that nobody will place a tab into our order form. It is difficult, but not impossible, for a user to put a tab or newline into a single line HTML input field. 04 525x ch02 1/24/03 3:38 PM Page 59 60 Chapter 2 Storing and Retrieving Data Using a special field separator will allow us to split the data back into separate vari- ables more easily when we read the data back.We’ll cover this in Chapter 3,“Using Arrays,” and Chapter 4. For the time being, we’ll treat each order as a single string. After processing a few orders, the contents of the file will look something like the example shown in Listing 2.1. Listing 2.1 orders.txt—Example of What the Orders File Might Contain 15:42, 20th April 4 tires 1 oil 6 spark plugs $434.00 22 Short St, Smalltown 15:43, 20th April 1 tires 0 oil 0 spark plugs $100.00 33 Main Rd, Newtown 15:43, 20th April 0 tires 1 oil 4 spark plugs $26.00 127 Acacia St, Springfield Closing a File When you’ve finished using a file, you need to close it.You should do this with the fclose() function as follows: fclose($fp); This function will return true if the file was successfully closed, or false if it wasn’t. This is generally much less likely to go wrong than opening a file in the first place, so in this case we’ve chosen not to test it. Reading from a File Right now, Bob’s customers can leave their orders via the Web, but if Bob’s staff wants to look at the orders, they’ll have to open the files themselves. Let’s create a Web interface to let Bob’s staff read the files easily.The code for this interface is shown in Listing 2.2. Listing 2.2 vieworders.php—Staff Interface to the Orders File <?php //create short variable name $DOCUMENT_ROOT = $HTTP_SERVER_VARS['DOCUMENT_ROOT']; ?> <html> <head> <title>Bob's Auto Parts - Customer Orders</title> </head> <body> <h1>Bob's Auto Parts</h1> <h2>Customer Orders</h2> <?php 04 525x ch02 1/24/03 3:38 PM Page 60 61 Reading from a File @ $fp = fopen("$DOCUMENT_ROOT/ /orders/orders.txt", 'r'); if (!$fp) { echo '<p><strong>No orders pending.' .'Please try again later.</strong></p>'; exit; } while (!feof($fp)) { $order= fgets($fp, 999); echo $order.'<br />'; } fclose($fp); ?> </body> </html> This script follows the sequence we talked about earlier: open the file, read from the file, close the file.The output from this script using the data file from Listing 2.1 is shown in Figure 2.4. Listing 2.2 Continued Figure 2.4 The vieworders.php script displays all the orders currently in the orders.txt file in the browser window. Let’s look at the functions in this script in detail. 04 525x ch02 1/24/03 3:38 PM Page 61 . deal with the error in a more user-friendly way by suppressing PHP s error message and giving your own: 04 525x ch02 1/24/03 3:38 PM Page 57 58 Chapter 2 Storing and Retrieving Data @ $fp = fopen("$DOCUMENT_ROOT/. up, the script might be running as the Web server user or as the owner of the directory that the script is in. On most systems, the script will run as the Web server user. If your script was on. ~/orders Bear in mind that directories and files that anybody can write to are dangerous.You should not have directories that are accessible directly from the Web as writeable. For this reason, our