file_get_contents('notes.txt') reads the whole file and returns it as one string. If the file cannot be read it returns false. To write, use file_put_contents('notes.txt', $text), which creates the file or replaces what was in it.
Output:
Buy milk
Call Ada
Write docs
29 bytes
3 lines
The block writes notes.txt first and then reads it back, so it has a file to work with. A path like 'notes.txt' is relative to the current working directory; in a web app, build the path from the script's own folder with __DIR__ . '/notes.txt'.
Write and append with file_put_contents()
file_put_contents() returns the number of bytes written, or false on failure. By default it overwrites the file. The FILE_APPEND flag adds to the end instead, which is how simple logs work, and LOCK_EX stops two requests from writing at the same moment:
Output:
Wrote 8 bytes
started
step 1 done
step 2 done
replaced
abc
5 bytes
To store an array and get it back as an array, write it as JSON with json_encode() and read it with json_decode().
Read a file line by line with file()
file() reads a file into an array with one line per element. Each line keeps its newline at the end unless you pass FILE_IGNORE_NEW_LINES, and FILE_SKIP_EMPTY_LINES drops blank lines (it only works together with FILE_IGNORE_NEW_LINES):
Output:
string(9) "Buy milk
"
1. Buy milk
2. Call Ada
3. Write docs
3 tasks
file() and file_get_contents() load the whole file into memory. That is fine for config files and logs of a few megabytes. For a file of hundreds of megabytes, read it a line at a time with fopen() and fgets() instead.
Check if a file exists before reading it
When the file is missing, file_get_contents() returns false and PHP prints a warning:
Warning: file_get_contents(missing.txt): Failed to open stream: No such file or directory in /home/index.php on line 2
Check first with is_file() (a file that exists and is not a directory) or file_exists() (a file or a directory), and always compare the result with === false, because an empty file returns "", which is also falsy:
Output:
empty.txt exists file
missing.txt missing
. exists directory
Cannot read missing.txt, using defaults
bool(false)
bool(true)
0 bytes
Do not hide the warning with @file_get_contents(). Checking first, or handling false, keeps the error visible when something else goes wrong.
Read part of a file
The fourth and fifth arguments are the byte offset to start at and the number of bytes to read. A negative offset counts from the end of the file. Named arguments let you skip the two arguments in between:
Output:
HEADER
line 2
last line
Offsets count bytes, not characters. In UTF-8 a Japanese character is 3 bytes, so an offset in the middle of one cuts it in half. To work with characters, read the whole string and use mb_substr().
Show a text file on a web page
File contents are text, and text printed into HTML must be escaped, or a < in the file becomes a tag. htmlspecialchars() escapes it and nl2br() turns the newlines into <br> tags. Run it and look at the Page tab:
Remove htmlspecialchars() and run it again: the page now ends at "v1.2: Fixed", because the browser reads <title> as a real tag and swallows everything after it as the page title. The htmlspecialchars() page covers why that matters for anything a user can write.
Read a URL with file_get_contents()
With allow_url_fopen enabled (the default in php.ini), file_get_contents() also reads URLs and returns the response body. A stream context adds a method, headers, a body and a timeout:
<?php
$html = file_get_contents('https://example.com/');
$context = stream_context_create([
'http' => [
'method' => 'POST',
'header' => "Content-Type: application/json\r\n",
'content' => json_encode(['name' => 'Ada']),
'timeout' => 5,
'ignore_errors' => true, // return the body of 4xx/5xx responses too
],
]);
$response = file_get_contents('https://api.example.com/users', false, $context);
if ($response === false) {
// DNS failure, timeout, or a refused connection
}
For retries, redirects with limits, and clear error codes, cURL or an HTTP client library such as Guzzle is the better tool.
file_get_contents vs file() vs fopen()
| You want | Use | Memory |
|---|---|---|
| The whole file as one string | file_get_contents() | The whole file |
| The lines as an array | file($path, FILE_IGNORE_NEW_LINES) | The whole file |
| To write or replace a file in one call | file_put_contents() | The data you write |
| To add a line to a log | file_put_contents($path, $line, FILE_APPEND | LOCK_EX) | One line |
| To read a large file line by line, or CSV rows | fopen() with fgets() or fgetcsv() | One line |
| To read and write the same open file | fopen() with r+, a+ or c+ | What you read |
The one-call functions open, read or write, and close the file for you, so they are the right default. Reach for fopen() when the file is too big to hold in memory or you need to keep it open between operations.
Frequently Asked Questions
How do I read a file into a string in PHP?
Call file_get_contents('path/to/file.txt'). It returns the whole file as a string, or false if the file cannot be read, so compare the result with === false before using it.
How do I append to a file in PHP?
Pass the FILE_APPEND flag: file_put_contents('log.txt', "new line\n", FILE_APPEND);. Without it, file_put_contents() replaces the whole file. Add LOCK_EX (FILE_APPEND | LOCK_EX) when several requests may write at the same time.
How do I read a file line by line in PHP?
For small files, file('data.txt', FILE_IGNORE_NEW_LINES) returns an array with one line per element. For large files, open it with fopen() and read one line at a time with fgets() in a while loop, which keeps only one line in memory.
Why does file_get_contents return false?
The file does not exist, the path is relative to a different directory than you think, or PHP has no permission to read it. PHP also prints a warning such as Failed to open stream: No such file or directory. Check with is_file() and is_readable(), and build paths from __DIR__.
Can file_get_contents read a URL?
Yes, when allow_url_fopen is enabled in php.ini: file_get_contents('https://example.com/') returns the response body. For headers, POST data or a timeout, pass a context from stream_context_create(); for anything more involved, cURL gives better error handling.