Advertisement

An In-Depth Overview of File Operations in PHP

by

In this Tuts+ Premium tutorial we will learn how to work with file operations using PHP. This is one of the most fundamental subjects of server side programming in general. Files are used in web applications of all sizes. So let's learn how to read, write, create, move, copy, delete files and more.


Screencast Preview



Copying, Moving and Deleting Files

We are going to start learning with these operations first, because they are very simple one liners, and they do not involve dealing with file pointers.

Copying a file

 
	$file = "test.txt"; 
	$new_file = "test_copy.txt"; 
 
	copy($file, $newfile);

Moving a File

 
	$file = "test.txt"; 
	$new_file = "test_copy.txt"; 
 
	rename($file, $newfile);

Note that the function is called "rename" and not "move". Internally, renaming a file is the same as moving it to a new location.

Same code works when changing the directory of the file:

 
	$file = "test.txt"; 
	$new_file = "different/folder/test_copy.txt"; 
 
	rename($file, $newfile);

Deleting a File

There is no such function as "delete". Here we call the "unlink" function.

 
	$file = "test.txt"; 
 
	unlink($file, $newfile);

Opening and Reading a File

Now it is time to start dealing with some file pointers. There is more than one way of reading the contents of a file in PHP, but we are going to start with the most basic method first. Later in the article we will learn about the alternative methods.

There are three file functions we will use here: fopen, fread and fclose.

 
	$file = "test.txt"; 
 
	// open the file 
	$fp = fopen($file, "r"); 
 
	// read 5k data from the file 
	$contents = fread($fp, 5000); 
 
	// close the file 
	fclose($fp);

When opening the file, we include a second parameter, which determines the type of access. In this case "r" stands for "read only". There are other types that we need to use for writing and appending that we will cover later in the article.

The second important thing to pay attention to is the second parameter in the fread function. This determines the length of the data (in bytes) to read from the file. To read the entire contents of the file, we need to pass the total file size. The filesize function does the trick:

 
	$file = "test.txt"; 
 
	// open the file 
	$fp = fopen($file, "r"); 
 
	// read 5k data from the file 
	$contents = fread($fp, filesize($file)); 
 
	// close the file 
	fclose($fp);

Full Screencast



Understanding File Pointers

Since we started working with file pointers, let's take a moment and try to understand them better.

A file pointer, also known as a file "handle", is a variable that refers to a file. The exact value of this variable is unimportant; all we need to know is that it points to a specific file. The pointer is usually obtained by opening a file. In PHP we use the fopen function.

Even though PHP has an excellent garbage collector that closes all open file pointers at the end of a scripts execution, it is considered a good practice to close them manually using the fclose function.

 
	$fp = fopen($file, 'r'); 
	// ... 
 
	// always close files 
	fclose($fp);

Position in a File

The file pointer actually does more than just pointing to a file. It also points to a specific position inside that file. In most cases, when you open a file, the file pointer points to the beginning (or position 0) in that file. We will cover this concept in more detail when we talk about "seeking" later in the article.


Writing To a File

Just like reading files, there is more than one way of writing to a file. First we will see the basic way, and later in the article we will look at alternatives.

The following code writes the contents of the $data variable into the test.txt file.

 
	$file = "test.txt"; 
	$data = "0123456789abc"; 
 
	// open the file for writing 
	$fp = fopen($file, "w"); 
 
	// write data to the file 
	fwrite($fp, $data); 
 
	// close the file 
	fclose($fp);

This time we used a different flag for opening the file. The "w" flag opens the file for writing, and overwrites all existing data in the file. If there was anything in the test.txt file, it will be replaced with the string in $data.

The fwrite function was very simple, we just passed the file pointer and the data to be written to the file. There is an optional third parameter that determines the length of data to be written:

 
	$file = "test.txt"; 
	$data = "0123456789abc"; 
 
	// open the file for writing 
	$fp = fopen($file, "w"); 
 
	// write data to the file (only 5 bytes) 
	fwrite($fp, $data, 5); 
 
	// close the file 
	fclose($fp);

If you run the code above, the contents of test.txt will only be "01234".

Creating a New File

The examples above also work for creating new files. If the file test.txt does not exist, it will be created automatically, just by the fopen function call.

If all you want to do is to create a new blank file, without writing any data in it, this code will work:

 
	$file = "does_not_exist.txt"; 
 
	// creates and opens the file 
	$fp = fopen($file, "w"); 
 
	// close the file 
	fclose($fp);

Seeking

The act of moving the file pointers location is called "seeking". To seek we can use the function fseek, and to get the position of a given pointer, we can use the function ftell.

Before we use seeking, let's create a file with 10 bytes of data in it.

 
	$file = "test.txt"; 
	$data = "0123456789"; 
	$fp = fopen($file, "w"); 
	fwrite($fp, $data); 
	fclose($fp);

Now let's see how these functions behave. Here are a few different examples:

 
	$file = "test.txt"; 
 
	// opening for reading, pointer should be at 0 
	$fp = fopen($file, "r"); 
 
	echo "open: "; 
	// outputs 0 
	echo ftell($fp)."\n"; 
 
	// ----- 
 
	// seek to byte 4 
	fseek($fp, 4); 
 
	echo "seek 4: "; 
	// outputs 4 
	echo ftell($fp)."\n"; 
 
	// ----- 
 
	// you can go out of bounds 
	fseek($fp, 9000); 
 
	echo "out of bounds: "; 
	// outputs 9000 
	echo ftell($fp)."\n"; 
 
	// ---- 
 
	// this is how you get to the end 
	fseek($fp, 0, SEEK_END); 
 
	echo "end: "; 
	// outputs 10 
	echo ftell($fp)."\n"; 
 
	// ---- 
 
	// move relative to current position 
	// negative numbers work 
	fseek($fp, -3, SEEK_CUR); 
 
	echo "go back by 3: "; 
	// outputs 7 
	echo ftell($fp)."\n"; 
 
	// ---- 
 
	// or seek relative to the end 
	// again, negative works 
	fseek($fp, -3, SEEK_END); 
 
	echo "go back by 3 from the end: "; 
	// outputs 7 
	echo ftell($fp)."\n"; 
 
	// ---- 
 
	// does the same thing as seeking to 0 
	rewind($fp); 
 
	echo "rewind: "; 
	// outputs 0 
	echo ftell($fp)."\n"; 
 
	fclose($fp);

Other Operations Moving File Pointer Position

The file pointer position can move by operations other than fseek.

For example, reading moves the position:

 
	$file = "test.txt"; 
 
	$fp = fopen($file, "r"); 
 
	// reading 6 bytes 
	$data = fread($fp, 6); 
 
	// outputs 6 
	echo ftell($fp); 
 
	fclose($fp);

Writing also moves it:

 
	$file = "test.txt"; 
 
	$data = "0123456789"; 
 
	$fp = fopen($file, "w"); 
 
	// writing 10 bytes 
	fwrite($fp, $data); 
 
	// outputs 10 
	echo ftell($fp); 
 
	fclose($fp);

File Access Modes

Now that we are familiar with the reading, writing and seeking concepts, it is time better understand the different file access modes. When opening a file with the fopen function, the second parameter must be provided, which is the file access mode. There is a table in the PHP manual describing them:


By looking at these, you can see that we have more options than we talked about so far. Here are some important factors to consider about picking the right option:

  • Opening with 'r+' will fail, if the file is not writable, even if you just want to read and not write to it.
  • Both 'w' and 'w+' will completely delete the contents of an existing file as soon as you open it. If you intend to add data, you need to use 'a' or 'a+'.
  • If you want to create new files, and also prevent accidentally overwriting and existing file, use 'x' or 'x+'.
  • When working with binary files, such as images, add the letter 'b' after the mode. For example: 'rb' or 'r+b'

Getting File Information

There are many pieces of information we can obtain about a file besides just its contents (size, last access time, modify time etc...) The main function used for this is stat.

It returns the information in an array:

 
	$data = stat("test.txt"); 
 
	print_r($data); 
	/* prints: 
 
	Array 
	( 
	    [0] => 2 
	    [1] => 0 
	    [2] => 33206 
	    [3] => 1 
	    [4] => 0 
	    [5] => 0 
	    [6] => 2 
	    [7] => 10 
	    [8] => 1264374556 
	    [9] => 1264374556 
	    [10] => 1264373231 
	    [11] => -1 
	    [12] => -1 
	    [dev] => 2 
	    [ino] => 0 
	    [mode] => 33206 
	    [nlink] => 1 
	    [uid] => 0 
	    [gid] => 0 
	    [rdev] => 2 
	    [size] => 10 
	    [atime] => 1264374556 
	    [mtime] => 1264374556 
	    [ctime] => 1264373231 
	    [blksize] => -1 
	    [blocks] => -1 
	) 
 
	*/

The data is in 12 pieces and is repeated, first with numeric keys, and then again with string keys.

The PHP manual has a table explaining each of them:



Alternative Functions

As I mentioned earlier, there are other alternative functions that can be used for reading and writing files. Let's go over some of them.

file_get_contents

This function returns the entire contents of a given file. Also you do not need to deal with file pointers at all.

 
	$file = "test.txt"; 
 
	$contents = file_get_contents($file);

The function accepts four more additional parameters as described in the PHP manual. For example, to read only a portion of the file, you can set the fourth and fifth parameters:

 
	$file = "test.txt"; 
 
	// reads 5 bytes of data, starting at byte 3 
	$contents = file_get_contents($file, NULL, NULL, 3, 5);

file

Yes, this function is simply named file, and it again returns the entire contents of a file. But this time, the contents are split into an array, by the newline character.

Let's create a file with the following contents:

 
	abc 
	123 
	empty line after this 
 
	last line

Now use the function:

 
	$file = "test.txt"; 
 
	$contents = file($file); 
 
	print_r($contents); 
 
	/* prints 
 
	Array 
	( 
	    [0] => abc 
 
	    [1] => 123 
 
	    [2] => empty line after this 
 
	    [3] => 
 
	    [4] => last line 
	) 
 
 
	*/

It may not be obvious, but there is a newline character at the of each array element. If you don't want them, you can either trim them manually, or use the FILE_IGNORE_NEW_LINES flag:

 
	$file = "test.txt"; 
 
	$contents = file($file, FILE_IGNORE_NEW_LINES); 
 
	print_r($contents); 
 
	/* prints 
 
	Array 
	( 
	    [0] => abc 
	    [1] => 123 
	    [2] => empty line after this 
	    [3] => 
	    [4] => last line 
	) 
 
	*/

If you do not want the empty lines either, you can use the FILE_SKIP_EMPTY_LINES flag:

 
	$file = "test.txt"; 
 
	$contents = file($file, FILE_SKIP_EMPTY_LINES | FILE_IGNORE_NEW_LINES); 
 
	print_r($contents); 
 
	/* prints 
 
	Array 
	( 
	    [0] => abc 
	    [1] => 123 
	    [2] => empty line after this 
	    [3] => last line 
	) 
 
	*/

file_put_contents

Again, there is no need to use file pointers. This function simply writes the given data to the given file:

 
	$file = "test.txt"; 
	$data = "0123456789"; 
 
	file_put_contents($file, $data);

filesize, fileatime, filemtime

These are alternatives to the stat function for getting file information.

 
	$file = "test.txt"; 
 
	// gets the file size 
	echo filesize($file); 
 
	// gets the last time the file was modified 
	echo filemtime($file); 
 
	// gets the last time the file accessed 
	echo fileatime($file);

File Permissions

Unix-like systems have a quite detailed file permissions standard. Windows systems have it a little simpler. The whole subject of file permissions can be lengthy and a whole separate article can be written on it. So instead, we will only look at two simple concepts of file permissions: being "readable", and being "writable".

Checking for Permissions

Your script may or may not have read and/or write access to a file due to various reasons. Before attempting to open a file for reading or writing, it is wise to check if you have permission to do so:

 
	$file = "test.txt"; 
 
	if (is_readable($file)) { 
		// file is readable 
	} 
 
	if (is_writable($file)) { 
		// file is writable 
	}

Setting the Permissions

To set the permissions of a file, we use the chmod function:

 
	$file = "test.txt"; 
 
	// makes the file read-only 
	chmod($file, 0444); 
 
	// makes the file readable and writable 
	chmod($file, 0666);

The above code should work on both Unix and Windows systems. However, you may not be able to set the permissions, if you do not own the file or have any permissions to it in the first place.

To better understand chmod and file permissions in general, you can check out these links:


Using Loops for Big Files

Last thing we are going to talk about is a quick tip for handling big files. This has some performance implications.

Easiest way to read and output a file is this:

 
	$file = "test.txt"; 
 
	echo file_get_contents($file);

But that causes the entire contents of the file to be loaded into the memory. It will persist as long as it is being downloaded by the web surfer. If you have multiple people downloading files at the same time, this can consume your web servers memory very quickly.

A better idea for handling this would be to use a loop to read only small chunks of the file at a time. For the loop condition we will utilize the feof function:

 
	$file = "test.txt"; 
 
	$fp = fopen($file, 'r'); 
 
	while (!feof($fp)) { 
 
		echo fread($fp, 4092); 
 
	} 
 
	fclose($fp);

The code above will only load 4kb of data at once into the memory, and this will greatly reduce the memory usage for big file outputs. The feof function returns true when we reach the end of the file, and this breaks out of the loop.

Advertisement