PHP Files & Directories
To take web applications beyond what we’ve done so far, we’ll need a method of storing and retrieving data. There are two basic ways of storing data using PHP: using a flat file, or using a database.
A flat file is a simple text file that stores one record per line. There are a couple of advantages of using a flat file over a database: you don’t have to learn specific knowledge about a database, and there’s no extra charge.
Disadvantages, however, are greater:
- when a file gets large, it can be very slow to work with
- searching a flat file is difficult and very slow
- allowing more than one user to access and modify flat files at the same time can be problematic
- files are processed sequentially, meaning it starts at the top and runs all the way through the last record
- it is difficult to allow different levels of access
In general, a database is much more efficient and much faster when working with any volume of information that needs to be stored and retrieved.
permissions
Permissions identify who can do what with a file or directory. For example, we may not want to give everyone permission to write something to the server. Yet we may want to give everyone permission to read what is stored in a file.
Permissions are generally divided into three groups:
- owner: the person who created the file to begin with. Normally, the owner has access to read from and write to a file
- groups: users can be organized into groups for better organization and administration
- others: everyone else
Besides being written to and read from, some files can also be executable. However, PHP is only a scripting language, not a programming language. Perl can be written as an executable file, while PHP generally cannot.
file processing
There are three steps to writing data to a file:
- Open the file. If it doesn’t already exist, create it
- Write data to the file
- Close the file
Likewise, there are three steps to reading data from a file:
- Open the file. If it cannot be opened for some reason, exit gracefully
- Read data from the file
- Close the file
opening a file
Use the fopen( ) function to open a file. fopen( ) takes 2 parameters (there is an optional third parameter), the file to be opened and the mode in which to open it.
Create a variable to hold the full path to the file. The superglobal
$_SERVER[ 'DOCUMENT_ROOT' ] contains the document root directory.
$doc_root = $_SERVER[ 'DOCUMENT_ROOT' ];
$file_name ="$doc_root/files/file_name.txt";
@ $fp = fopen( $file_name, "w" ) or die ( “Cannot open the file” );
The second parameter is the mode. Depending upon what you want to do with the file, the mode indicates how to open it. Choices you may need to make include:
- do I want to open the file for reading, writing, or both?
- if writing to the file, should the new data overwrite the old data, or should it be appended to the existing data?
File modes include:
r |
Read Mode: Open for reading only. Place the file pointer at the beginning of the file. |
r+ |
Read mode: Open for reading and writing. Place the file pointer at the beginning of the file. |
w |
Write Mode: Open for writing only. Place the file pointer at the beginning of the file. If the file already exists, delete the existing data. If the file does not exist, attempt to create it. |
w+ |
Write Mode: Open for writing and reading. Place the file pointer at the beginning of the file. If the file already exists, delete the existing data. If the file does not exist, attempt to create it. |
a |
Append mode: Open the file for appending only. Start from the end of the existing data. If the file does not exist, attempt to create it. |
a+ |
Append mode: Open the file for appending and reading. Start from the end of the existing data. If the file does not exist, attempt to create it. |
Assign the fopen( ) call to a file pointer. If the file opens successfully, a pointer to the file is returned. We will use the file pointer variable to refer to the file whenever we need to use it.
If the file cannot be opened for any reason, an error is generated. Notice the @ suppressing the error notice. Instead, we use the die( ) function to create our own error message and stop the execution of the script.
writing to a file
Writing to a file is relatively simple. We use the function fwrite( ). fwrite( ) takes 3 parameters – the third is optional.
The first parameter is the file pointer, which points to the file we are writing to. The second parameter is the string we are going to write.
fwrite( $fp, $string_output );
The third parameter, if specified, is the maximum number of bytes that can be written to the file. It is an integer value. PHP will truncate the output string if it exceeds the maximum length.
The way you format the file to be saved is completely up to you. You can separate the sections of data with the delimiter of your choice. However, if you are planning to use the data in another application, such as a spreadsheet, you must follow the rules of the other application.
The delimiter you choose should not be one which may occur in the user’s input. Otherwise, you should process the user input to remove or escape any occurrences of the delimiter character.
$string_output = “$last_name|$first_name|$gender|$height|$weight|$age\n”;
End the string with a record separator such as the newline character, so PHP can tell where each record ends.
close the file
When you are done using a file, close it using the fclose( ) function. Pass the file pointer as a parameter.
fclose( $fp );
reading from a file
To read from a file we follow the same steps as we did when writing to a file: open the file, read from the file, close the file.
To open the file we again use the fopen( ) function, but with a different mode.
$doc_root = $_SERVER[ 'DOCUMENT_ROOT' ];
$file_name ="$doc_root/files/file_name.txt";
@ $fp = fopen( $file_name, "r" ) or die ( “Cannot open the file” );
Then we read from the file.
if ( filesize("$doc_root/files/file_name.txt" != 0 ){
while( !feof( $fp ) ) {
$line = fgets( $fp, 1000 );
echo $line;
} //end while
} // end if
fclose( $fp );
If the file opens correctly we can run a while loop to read from the file until the end of the file is reached. We can use the feof( ) function. feof( ) returns TRUE when the file pointer is at the end of the file. Until it reaches the end of the file, it returns FALSE. feof( ) takes one parameter, the file pointer.
while( !feof( $fp ) ) {
When using feof( ) in a while loop be sure to check if the filesize isn't 0 bytes. If it is, there isn't an end of file, so it continuously loops until a timeout message appears. Or if there is a problem opening the file, feof( ) will always evaluate to TRUE, again resulting in an infinite loop.
The filesize( ) function returns the size of the file in bytes.
if ( filesize("$doc_root/files/file_name.txt" ! = 0 ){
Now we can use another function, fgets( ), to read from the file one line at a time. fgets( ) takes one or two parameters: the file pointer, and an optional integer value indicating the maximum number of bytes to be returned. Reading of the file ends when the integer length - 1 bytes have been read, when a newline (which is included in the return value) is reached, or when EOF is reached (whichever comes first). If no length is specified, the length defaults to 1K, or 1024 bytes
$line = fgets( $fp, 1000 );
While reading each line from the file, we can store it in an array, separate it into variables, echo the whole string, etc.
When finished reading the file, close it using the fclose( ) function.
fclose( $fp );
PHP offers a couple of other functions as alternatives to fgets( ).
fgetss( ) is similar to fgets( ), except that it strips all PHP and HTML tags found in the string. There is an optional third parameter which identifies allowable tags which will not be stripped.
You would use fgetss( ) for security reasons, so no malicious user can write unrestricted HTML or PHP to your server, thus presenting a security risk.
$line = fgetss( $fp, 1000 );
One other function is fgetscsv( ), which is another variation on fgets( ). It is used for splitting apart the line on a delimiting character, such as a pipe, comma, or tab. CSV stands for “Comma Separated Values”. After a line is separated into its smaller parts, the results are returned as an array.
$line_array = fgetcsv( $fp, 1000, “|” );
Instead of reading one line at a time, we can read the entire file using PHP functions.
readfile( ) opens the file, echoes the file to the browser, then closes the file. You do not need to manually open or close the file. readfile( ) does that automatically. Pass the function the path to the file to be read. Pass the path as an argument.
readfile( "$doc_root/files/file_name.txt" );
file( ) is identical to readfile( ), except that rather than echoing the file to the browser, it is returned as an array, one line per element. Pass the path as an argument.
$file_array = file( "$doc_root/files/file_name.txt" );
file_get_contents( ) is identical to readfile( ), except that rather than echoing the file to the browser, it is returned as a string. Pass the path as an argument.
$file_string = file_get_contents( "$doc_root/files/file_name.txt" );
fgetc( ) reads a file as a single character at a time. It takes one parameter, the file pointer. In addition to string characters, it will also read the newline and the eof characters. When using fgetc( ), you may want to test for the newline and the eof. Otherwise, browser output may not be what you expect. Pass the file pointer as an argument.
$char = fgetc( $fp );
file_exists( ) checks to see whether the file exists or not, without actually opening it. Returns TRUE if it exists, FALSE if it does not. Pass the path as an argument.
file_exists( "$doc_root/files/file_name.txt" );
unlink( ) deletes the file. Pass the path as an argument.
unlink( "$doc_root/files/file_name.txt" );
file locking
PHP also allows for file locking, in case two users try to open and modify the same file at the same time. To minimize problems, we can lock a file with the flock( ) function. flock( ) takes two parameters, the file pointer, and a constant indicating the kind of lock to acquire.
The types of locks include:
LOCK_SH |
Reading Lock: the file can be shared with other readers. |
LOCK_EX |
Writing Lock: the file cannot be shared. The lock is exclusive. |
LOCK_UN |
Unlock: release the existing lock. |
security
It is dangerous to allow files and directories that anyone can write to on your server. You should not have writeable directories which can be accessed directly from the web. It may be wise, therefore, to place a vulnerable directory above the document root directory. Generally, those directories are not accessible through the web.
To create the file in a directory above the document root directory, use the following code:
$doc_root = $_SERVER[ 'DOCUMENT_ROOT' ];
$file_name ="$doc_root/../files/file_name.txt";
$fp = fopen( $file_name, "w+" );
Notice the use of the two dots, which indicates one level above the root directory. Before you try to write a file, however, make sure the directory exists. fopen( ) will not create the directory for you.
It is a very bad idea to store sensitive information, such as passwords, in a flat file or database. The PHP function crypt( ) uses a one-way algorithm to encrypt a string value. There is no function to decrypt the string, so once a string is encrypted there is no way to change it back. Even the creator of the script cannot change it back.
crypt( ) takes two parameters, the second is optional. The first parameter is the string which needs to be encrypted. The second parameter is an optional salt string upon which the encryption is based. The salt is used to seed the encryption algorithm. If you do not supply a salt, PHP generates one automatically.
What makes crypt( ) so useful, is that given the same string and the same salt, the same encrypted result is returned each time. We don’t need to know the original value of the encrypted string. In the example of a password, all we need to do is compare the encrypted string residing in our file, to the password entered by the user, after we run it through the crypt function again.
if( crypt( $user_entered_password ) == $encrypted_password_stored_in_file ) {
// passwords match
}
If you plan on using the crypt( ) function, investigate the proper use of the salt, because it may function differently on different systems.

|