| PHP Programming Files | Images |
Working with files is an important part of any programming language, and PHP is no different. Whatever your reasons are for wanting to manipulate files, PHP will happily accommodate them through the use of a handful of functions. You should have read and be comfortable with the concepts presented in the first five sections of this book before beginning here.
To display the current directory: dirname().
To change the directory: chdir().
To make a new directory: mkdir().
fopen() is the basis for file manipulation. It opens a file in a certain mode (that you specify) and returns a handle. Using this handle you can read or write to the file, before closing it with thefclose() function.
<?php$handle=fopen('data.txt','r');// Open the file for readingfclose($handle);// Close the file?>
In the example above you can see the file is opened for reading by specifying 'r' as the mode. For a full list of all the modes available tofopen(), you can look at thePHP Manual page.
Opening and closing the file is all well and good, but to perform useful operations, you need to know aboutfread() andfwrite().
When a PHP script finishes executing, all open files are automatically closed. So although it is not strictly necessary to close a file after opening it, it is considered good programming practice to do so.
Reading can be done in a number of ways. If you just want all the contents of a file available to work with, you can use thefile_get_contents() function. If you want each line of the file in an array, you can use thefile() command. For total control over reading from files,fread() can be used.
These functions are usually interchangeable and each can be used to perform each other's function. The first two do not require that you first open the file withfopen() or then close it withfclose(). These are good for quick, one-time file operations. If you plan on performing multiple operations on a file it is best to usefopen() in conjunction withfread(),fwrite() andfclose() as it is more efficient.
<?php$contents=file_get_contents('data.txt');echo$contents;?>
I am the contents of data.txt
<?php$lines=file('data.txt');foreach($linesas$Key=>$line){$lineNum=$Key+1;echo"Line$lineNum:$line";}?>
Line 1: I am the first line of fileLine 2: I am the second line the of the fileLine 3: If I said I was the fourth line of the file, I'd be lying
<?php$handle=fopen('data.txt','r');$string=fread($handle,64);fclose($handle);echo$string;?>
I am the first 64 bytes of data.txt (if it was ASCII encoded). I
As you can see, with these three functions you are able to easily read data from a file into a form that is convenient to work with. The next part shows how these functions can be used to do the jobs of the others, but this is optional. You may skip it and move onto the writing section, if you are not interested.
<?php$file='data.txt';functiondetectLineEndings($contents){if(false!==strpos($contents,"\r\n"))return"\r\n";elseif(false!==strpos($contents,"\r"))return"\r";elsereturn"\n";}/* This is equivalent to file_get_contents($file), but is less efficient */$handle=fopen($file,'r');$contents=fread($handle,filesize($file));fclose($handle);/* This is equivalent to file($file), but requires you to check for the line-endingtype. Windows systems use \r\n, Macintosh \r and Unix \n. File($file) willautomatically detect line-endings whereas fread/file_get_contents won't */$lineEnding=detectLineEndings($contents);$contents=file_get_contents($file);$lines=explode($lineEnding,$contents);/* This is also equivalent to file_get_contents($file) */$lines=file($file);$contents=implode("\n",$lines);/* This is equivalent to fread($file, 64), if the file is ASCII encoded */$contents=file_get_contents($file);$string=substr($contents,0,64);?>
Writing to a file is done by using thefwrite() function in conjunction withfopen() andfclose(). As you can see, there aren't as many options for writing to a file as there are for reading from one. However, PHP 5 introduces the functionfile_put_contents() that simplifies the writing process somewhat. This function will be discussed later in the PHP 5 section, as it is fairly self-explanatory and does not require discussion here.
The extra options for writing don't come from the amount of functions, but from the modes available for opening the file. There are three different modes you can supply to thefopen() function, if you wish to write to a file. One mode, 'w', wipes the entire contents of the file, so anything you then write to the file will fully replace what was there before. The second mode, 'a', appends stuff to the file so anything you write to the file will appear just after the original contents of the file. The final mode 'x' only works for non-existent files. All three writing modes will attempt to create the file, if it doesn't exist whereas the 'r' mode will not.
<?php$handle=fopen('data.txt','w');// Open the file and delete its contents$data="I am new content\nspread across\nseveral lines.";fwrite($handle,$data);fclose($handle);echofile_get_contents('data.txt');?>
I am new contentspread acrossseveral lines.
<?php$handle=fopen('data.txt','a');// Open the file for appending$data="\n\nI am new content.";fwrite($handle,$data);fclose($handle);echofile_get_contents('data.txt');?>
I am the original content.I am new content.
<?php$handle=fopen('newfile.txt','x');// Open the file only, if it doesn't exist$data="I am this file's first ever content!";fwrite($handle,$data);fclose($handle);echofile_get_contents('newfile.txt');?>
I am this file's first ever content!
Of the three modes shown above, 'w' and 'a' are used the most, but the writing process is essentially the same for all the modes.
If you want to usefopen() to open a file for both readingand writing all you need to do is put a '+' on the end of the mode. For example, reading from a file requires the 'r' mode. If you want to read and write to/from that file you need to use 'r+' as a mode. Similarly you can read and write to/from a file using the 'w+' mode. However, this will also truncate the file to zero length. For a better description visit thefopen() page that has a very useful table describing all the modes available.
Error checking is important for any sort of programming, but when working with files in PHP it is especially important. This need for error checking arises mainly from the filesystem the files are on. The majority of webservers today are Unix-based and so, if you are using PHP to develop web-applications, you have to account for file permissions. In some cases PHP may not have permission to read the file and so, if you've written code to read a particular file, it will result in an ugly error. More likely is that PHP doesn't have permission to write to a file and that will again result in ugly errors. Also, the file's existence is (somewhat obviously) important. When attempting to read a file, you must make sure the file exists first. On the other side of that, if you're attempting to create and then write to a file using the 'x' mode, then you must make sure the filedoesn't exist first.
In short, when writing code to work with files, always assume the worst. Assume the file doesn't exist and you don't have permission to read from/write to it. In most cases this means you have to tell the users that, in order for the script to work, they need to adjust those file permissions so that PHP can create files and read from/write to them, but it also means that your script can adjust and perform an alternative operation.
There are two main ways of error checking. The first is by using the '@' operator to suppress any errors when working with the file and then checking, if the result isfalse or not. The second method involves using more functions likefile_exists(),is_readable() andis_writeable().
<?php$handle=@fopen('data.txt','r');if(!$handle){echo'PHP does not have permission to read this file or the file in question doesn\'t exist.';}else{$string=fread($handle,64);fclose($handle);}$handle=@fopen('data.txt','w');// The same applies for 'a'if(!$handle){echo'PHP either does not have permission to write to this file orit does not have permission to create this file in the current directory.';}else{fwrite($handle,'I can has content?');fclose($handle);}$handle=@fopen('data.txt','x');if(!$handle){echo'Either this file exists or PHP does not have permission tocreate this file in the current directory.';}else{fwrite($handle,'I can has content?');fclose($handle);}?>
<?php$file='data.txt';if(!file_exists($file)){// No point in reading since there is no content$contents='';// But might want to create the file instead$handle=@fopen($file,'x');// Still need to error-checkif(!$handle){echo'PHP does not have permission to create a file in the current directory.';}else{fwrite($handle,'Default data');fclose($handle);}}else{// The file does exist so we can try to read its contentsif(is_readable($file)){$contents=file_get_contents($file);}else{echo'PHP does not have permission to read that file.';}}if(file_exists($file)&&is_writeable($file)){$handle=fopen($file,'w');fwrite($handle,'I can has content?');fclose($handle);}?>
You can see by that last example that error-checking makes your code very robust. It allows it to be prepared for most situations and behave accordingly, which is an essential aspect of any program or script.
Line-endings were mentioned briefly in the final example in the 'Reading' section of this chapter and it is important to be aware of them when working with files. When reading from a text file, it is important to know what types of line-endings that file contains. 'Line-endings' are special characters that try to tell a program to display a new line. For example, Notepad will only move a piece of text to a new line, if it finds "\r\n" just before the new line (it will also display new lines, if you put word wrap on).
If someone writes a text file on a Windows system, the chances are that each line will end with "\r\n". Similarly, if they write the file on a Classic Macintosh (Mac OS 9 and under) system, each line will probably end with "\r". Finally, if they write the file on a Unix-based system (Mac OS X and GNU/Linux), each line will probably end with "\n".
Why is this important? Well, when you read a file into a string withfile_get_contents(), the string will be one long line with those line-endings all over the place. Sometimes they will get in the way of things you want to do with the string so you can remove them with:
<?php$string=str_replace(array("\n","\r"),'',$string);?>
Other times you may need to know what kind of line-ending is being used throughout the text in order to be consistent with any new text you add. Luckily, in 99% of cases, the line-endings will never change type throughout the text so the custom function 'detectLineEndings' can be used as a quick way of checking:
<?phpfunctiondetectLineEndings($string){if(false!==strpos($string,"\r\n"))return"\r\n";elseif(false!==strpos($string,"\r"))return"\r";elsereturn"\n";}?>
Most of the time though, it is just sufficient to be aware of their existence within the text so you can adjust your script to cope properly.
So far, all of the text seen in this chapter has been assumed to be encoded in some form of plaintext encoding such as UTF-8 or ASCII. Files do not have to be in this format, however, and in fact there exist a huge number of formats that aren't (such as pictures or executables). If you want to work with these files you have to ensure that the functions you are using are 'binary-safe'. Previously you would have to add 'b' to the end of the modes you used to tell PHP to treat the file as a binary file. Failing to do so would give unexpected results and generally 'weird-looking' data.
Since about PHP 4.3, this is no longer necessary as PHP will automatically detect, if it needs to open the file as a text file or a binary file and so you can still follow most of the examples shown here.
Working with binary data is a lot different to working with plaintext strings and characters and involves many more functions that are beyond the scope of this chapter. However, it is important you know about these differences.
Serialization is a technique used by programmers to preserve their working data in a format that can later be restored to its previous form. In simple cases this means converting a normal variable such as an array into a string and then storing it somewhere. That data can then be unserialized and the programmer will be able to work with the array once again.
There is a whole chapter devoted toSerialization in this book as it is a useful technique to know how to use effectively. It is mentioned here as one of the primary uses of serialization to store data on plain files when a database is not available. It is also used to store the state of a script and to cache data for quicker access later, and files are one of the preferred media for this storage.
In PHP, serialization is very easy to perform through use of theserialize() andunserialize() functions. Here follows an example of serialization used in conjunction with file functions.
<?php/* This part of the script saves the data to a file */$data=array('id'=>114,'first name'=>'Foo','last name'=>'Bartholomew','age'=>21,'country'=>'England');$string=serialize($data);$handle=fopen('data.dat','w');fwrite($handle,$string);fclose($handle);/* Then, later on, we retrieve the data from the file and output it */$string=file_get_contents('data.dat');$data=unserialize($string);$output='';foreach($dataas$key=>$datum){$field=ucwords($key);$output.="$field:$datum\n";}echo$output?>
Id: 114First Name: FooLast Name: BartholomewAge: 21Country: England
There is one particular function specific to files that was introduced in PHP 5. That was thefile_put_contents() function. It offers an alternative method of writing to files that does not exist in PHP 4. To see how it differs, it is easiest to just look at an example.
<?php$file='data.txt';$content='New content.';// PHP 4, overwrite entire file with data$handle=fopen($file,'w');fwrite($handle,$content);fclose($handle);// PHP 5file_put_contents($file,$content);// PHP 4, append to a file$handle=fopen($file,'a');fwrite($handle,$content);fclose($handle);// PHP 5file_put_contents($file,$content,FILE_APPEND);?>
file_put_contents() is almost always preferable over thefopen() method except when performing multiple operations on the same file. It is more preferable to use it for writing thanfile_get_contents() is for reading and for this reason, a function is provided here to emulate the behaviour offile_put_contents() for PHP 4:
<?phpif(!function_exists('file_put_contents')){functionfile_put_contents($file,$data,$append=false){if(!$append)$mode='w';else$mode='a';$handle=@fopen($file,$mode);if(!$handle)returnfalse;$bytes=fwrite($handle,$data);fclose($handle);return$bytes;}}?>
| PHP Programming Files | Images |