Learning Objectives – after this chapter you will be able to:
- Open, read, write, append and close files with
fopen(),fread(),fgets(),fgetc(),fwrite()andfclose(). - Use the file modes r, r+, w, w+, a, a+, x and x+.
- Use the shortcut functions
file_get_contents(),file_put_contents()andfile(). - Upload files from a form with
$_FILESandmove_uploaded_file(), with size and type restrictions.
Working with Files on the Server
One of the most useful features of a server-side language is its ability to work with the file system of the server that hosts the web site. This clearly distinguishes PHP from a client-side language such as JavaScript: JavaScript is sent to the visitor's browser and runs there, while PHP runs on the server and only the result is sent to the browser – so PHP can read and write the server's files. PHP works with both text files and database systems; this chapter covers files, Part IV covers databases.
To access a file you first establish a connection to it by opening it with fopen(). You give two parameters: the name of the file and the mode – how you want to use the file (reading, writing …). fopen() returns a file handle (a resource) that is used by the other file functions.
Opening a File
$handle = fopen(filename, mode);
| Mode | Description |
|---|---|
| r | Read only. Starts at the beginning of the file. |
| r+ | Read/Write. Starts at the beginning of the file. |
| w | Write only. Opens and clears the contents of the file, or creates a new file if it does not exist. |
| w+ | Read/Write. Opens and clears the file, or creates a new one. |
| a | Append. Opens and writes to the end of the file, or creates a new file if it does not exist. |
| a+ | Read/Append. Preserves the file content and writes to the end. |
| x | Write only. Creates a new file. Returns false and an error if the file already exists. |
| x+ | Read/Write. Creates a new file. Returns false and an error if the file already exists. |
If fopen() cannot open the file it returns false. The following example shows a message and stops if the file cannot be opened:
<html>
<body>
<?php
$file = fopen("welcome.txt", "r") or exit("Unable to open file!");
?>
</body>
</html>Warning: fopen(welcome.txt): Failed to open stream: No such file or directory in /opt/lampp/htdocs/phpbook/ch14/open.php on line 4 Unable to open file!
(The warning appears because welcome.txt does not exist yet; exit() then prints the message and ends the script.)
Closing a File
fclose() closes an open file and frees the handle:
$file = fopen("test.txt", "r");
// some code to be executed
fclose($file);Writing a File – fwrite() and fputs()
int fwrite(resource $handle, string $string [, int $length])
fwrite() writes the string to the file and returns the number of bytes written. fputs() is an alias of fwrite(). The example writes text received from a form into welcome.txt:
<?php
$file = fopen("welcome.txt", "w") or exit("Unable to create file!");
$text = $_POST["text"];
$bytes = fwrite($file, $text);
fclose($file);
echo "$bytes bytes written to welcome.txt";
?>84 bytes written to welcome.txt
The same with fputs(), this time appending with mode a:
<?php
$file = fopen("welcome.txt", "a") or exit("Unable to open file!");
fputs($file, "\nLine appended on " . date("d-m-Y"));
fclose($file);
echo "Line appended.";
?>Line appended.
Checking for End-of-File
feof() checks whether the end of file (EOF) has been reached. It is useful for looping through data of unknown length.
You cannot read from files opened in w, a or x mode!
Reading a File Line by Line – fgets()
fgets() reads a single line from a file. After the call the file pointer has moved to the next line.
<?php
$file = fopen("welcome.txt", "r") or exit("Unable to open file!");
// Output a line of the file until the end is reached
$n = 1;
while (!feof($file)) {
echo $n++ . ": " . fgets($file) . "<br>";
}
fclose($file);
?>1: Welcome to PHP file handling. 2: This is the second line. 3: And this is the third line. 4: Line appended on 22-10-2026
Reading a File Character by Character – fgetc()
fgetc() reads a single character. After the call the file pointer moves to the next character.
<?php
$file = fopen("welcome.txt", "r") or exit("Unable to open file!");
$count = 0;
while (($c = fgetc($file)) !== false) {
if ($c == "e") $count++;
}
fclose($file);
echo "The letter 'e' occurs $count times in welcome.txt";
?>The letter 'e' occurs 11 times in welcome.txt
Reading with fread()
string fread(resource $handle, int $length)
fread() reads up to length bytes. Reading stops as soon as length bytes have been read or the end of the file is reached. To read a whole file pass its size, obtained with filesize():
<?php
$file = fopen("welcome.txt", "r") or exit("Unable to open file!");
$text = fread($file, filesize("welcome.txt"));
fclose($file);
echo "<pre>" . htmlspecialchars($text) . "</pre>";
echo "File size: " . filesize("welcome.txt") . " bytes";
?>Welcome to PHP file handling. This is the second line. And this is the third line. Line appended on 22-10-2026 File size: 112 bytes
Shortcut Functions
| Function | Purpose |
|---|---|
| file_get_contents($f) | Reads the whole file into a string. |
| file_put_contents($f, $data) | Writes a string to a file (use FILE_APPEND to append). |
| file($f) | Reads a file into an array – one element per line. |
| file_exists($f) | Checks whether a file or folder exists. |
| unlink($f) | Deletes a file. |
| copy($a, $b) / rename($a, $b) | Copies / renames (moves) a file. |
<?php
file_put_contents("visitors.txt", "Asha\nRavi\n");
file_put_contents("visitors.txt", "Neha\n", FILE_APPEND);
echo "Content:<br>" . nl2br(file_get_contents("visitors.txt"));
$lines = file("visitors.txt", FILE_IGNORE_NEW_LINES);
echo "Number of visitors: " . count($lines) . "<br>";
echo "Exists? " . (file_exists("visitors.txt") ? "yes" : "no") . "<br>";
copy("visitors.txt", "backup.txt");
unlink("visitors.txt");
echo "After unlink, exists? " . (file_exists("visitors.txt") ? "yes" : "no");
?>Content: Asha Ravi Neha Number of visitors: 3 Exists? yes After unlink, exists? no
A simple hit counter
<?php $f = "hits.txt"; $hits = file_exists($f) ? (int) file_get_contents($f) : 0; $hits++; file_put_contents($f, $hits, LOCK_EX); echo "This page has been viewed $hits times."; ?>
This page has been viewed 3 times.
(The output above is the third visit.)
File Upload
Allowing users to upload files from a form is very useful. Look at the following HTML form for uploading files:
<html> <body> <form action="upload_file.php" method="post" enctype="multipart/form-data"> <label for="file">Filename:</label> <input type="file" name="file" id="file"> <br> <input type="submit" name="submit" value="Submit"> </form> </body> </html>

- The
enctypeattribute of the<form>tag specifies which content type is used when the form is submitted.multipart/form-datais required when a form sends binary data, like the contents of a file. - The
type="file"attribute of<input>makes the browser show a Browse/Choose File button. - The form must use
method="post".
Allowing users to upload files is a big security risk. Only permit trusted users to upload, restrict the file type and size, never trust the file name sent by the browser, and never store uploaded files where they could be executed as PHP.
Creating the upload script
By using the superglobal $_FILES array you receive files uploaded from a client computer. The first index is the form's input name and the second index can be:
| Element | Meaning |
|---|---|
| $_FILES["file"]["name"] | the original name of the uploaded file |
| $_FILES["file"]["type"] | the MIME type sent by the browser (e.g. image/gif) |
| $_FILES["file"]["size"] | the size of the file in bytes |
| $_FILES["file"]["tmp_name"] | the name of the temporary copy stored on the server |
| $_FILES["file"]["error"] | the error code resulting from the upload (0 = no error) |
<?php
if ($_FILES["file"]["error"] > 0) {
echo "Error: " . $_FILES["file"]["error"] . "<br>";
} else {
echo "Upload: " . $_FILES["file"]["name"] . "<br>";
echo "Type: " . $_FILES["file"]["type"] . "<br>";
echo "Size: " . round($_FILES["file"]["size"] / 1024, 2) . " Kb<br>";
echo "Stored in: " . $_FILES["file"]["tmp_name"];
}
?>Upload: logo.gif Type: image/gif Size: 0.83 Kb Stored in: /tmp/phprNckwr
Restrictions on upload
In this script we add restrictions: the user may only upload .gif or .jpeg files, and the file size must be under 20 KB:
<?php
if ((($_FILES["file"]["type"] == "image/gif")
|| ($_FILES["file"]["type"] == "image/jpeg")
|| ($_FILES["file"]["type"] == "image/pjpeg"))
&& ($_FILES["file"]["size"] < 20000)) {
if ($_FILES["file"]["error"] > 0) {
echo "Error: " . $_FILES["file"]["error"] . "<br>";
} else {
echo "Upload: " . $_FILES["file"]["name"] . "<br>";
echo "Type: " . $_FILES["file"]["type"] . "<br>";
echo "Size: " . round($_FILES["file"]["size"] / 1024, 2) . " Kb<br>";
}
} else {
echo "Invalid file";
}
?>Invalid file
(Old Internet Explorer versions sent JPEG files as image/pjpeg; modern browsers send image/jpeg.)
Saving the uploaded file
The examples above create a temporary copy of the uploaded file in PHP's temp folder (C:\xampp\tmp in XAMPP). The temporary file disappears when the script ends. To keep it we must move it to another location with move_uploaded_file():
<?php
$allowed = ["image/gif", "image/jpeg", "image/png"];
if (in_array($_FILES["file"]["type"], $allowed) && $_FILES["file"]["size"] < 20000) {
if ($_FILES["file"]["error"] > 0) {
echo "Return Code: " . $_FILES["file"]["error"] . "<br>";
} else {
echo "Upload: " . $_FILES["file"]["name"] . "<br>";
echo "Type: " . $_FILES["file"]["type"] . "<br>";
echo "Size: " . round($_FILES["file"]["size"] / 1024, 2) . " Kb<br>";
if (!is_dir("upload")) {
mkdir("upload");
}
$target = "upload/" . basename($_FILES["file"]["name"]);
if (file_exists($target)) {
echo $_FILES["file"]["name"] . " already exists.";
} else {
move_uploaded_file($_FILES["file"]["tmp_name"], $target);
echo "Stored in: " . $target;
}
}
} else {
echo "Invalid file";
}
?>Upload: logo.gif Type: image/gif Size: 0.83 Kb Stored in: upload/logo.gif
Uploading the same file a second time:
Upload: logo.gif Type: image/gif Size: 0.83 Kb logo.gif already exists.
The script checks whether the file already exists; if not, it moves the file into the upload folder. basename() removes any directory part from the name sent by the browser.
$_FILES["file"]["type"] is sent by the browser and can be faked. For important uploads check the content on the server: mime_content_type($_FILES["file"]["tmp_name"]) or getimagesize() for images, and give the stored file a new, safe name.
Upload error codes
| Constant | Value | Meaning |
|---|---|---|
| UPLOAD_ERR_OK | 0 | No error, the upload succeeded. |
| UPLOAD_ERR_INI_SIZE | 1 | File exceeds upload_max_filesize in php.ini. |
| UPLOAD_ERR_FORM_SIZE | 2 | File exceeds MAX_FILE_SIZE given in the form. |
| UPLOAD_ERR_PARTIAL | 3 | The file was only partially uploaded. |
| UPLOAD_ERR_NO_FILE | 4 | No file was uploaded. |
| UPLOAD_ERR_NO_TMP_DIR | 6 | The temporary folder is missing. |
| UPLOAD_ERR_CANT_WRITE | 7 | Failed to write the file to disk. |
Key Takeaways
fopen()opens a file in a mode (r, w, a, x, plus+variants) and returns a handle;fclose()closes it.fwrite()/fputs()write;fgets()reads a line,fgetc()a character,fread()a number of bytes;feof()detects the end.file_get_contents(),file_put_contents()andfile()do common jobs in one call.- Upload forms need
method="post"andenctype="multipart/form-data". $_FILESdescribes the upload;move_uploaded_file()saves it permanently.- Always restrict type and size and never trust the browser-supplied name or type.
Program File
Extract the ZIP into C:\xampp\htdocs. It creates the folder phpbook/ch14 used in the file labels above; open the programs at http://localhost/phpbook/… with Apache (and MySQL, where needed) started in the XAMPP Control Panel.
Question / Answer (15 questions)
MCQ Test : Check Your Understanding (5 questions)
Select an option and press Check Answer, or answer all questions and press Submit Test to see your score. Each answer comes with an explanation.
Bibliography/References
The notes on this page are the author’s own compilation from the e-book PHP: Basics to Advance. Every program was run on Apache with PHP 8 and MariaDB, and the output shown is the real result of that run. The works listed below were consulted and are cited for attribution and further reading. Product names and trademarks belong to their respective owners.
- The PHP Group. (n.d.). PHP Manual – fopen. https://www.php.net/manual/en/function.fopen.php
- The PHP Group. (n.d.). PHP Manual – Filesystem Functions. https://www.php.net/manual/en/ref.filesystem.php
- The PHP Group. (n.d.). PHP Manual – Handling file uploads. https://www.php.net/manual/en/features.file-upload.php
- The PHP Group. (n.d.). PHP Manual – Error Messages Explained (uploads). https://www.php.net/manual/en/features.file-upload.errors.php
- OWASP Foundation. (n.d.). File Upload Cheat Sheet. https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html