file_get_contents('notes.txt') đọc toàn bộ tệp và trả về nó dưới dạng một chuỗi. Nếu không đọc được tệp, hàm trả về false. Để ghi, dùng file_put_contents('notes.txt', $text), hàm này tạo tệp hoặc thay thế nội dung đang có trong đó.
Đầu ra:
Buy milk
Call Ada
Write docs
29 bytes
3 lines
Khối code ghi notes.txt trước rồi đọc lại, nên nó luôn có một tệp để làm việc. Một đường dẫn như 'notes.txt' là tương đối so với thư mục làm việc hiện tại; trong ứng dụng web, hãy tạo đường dẫn từ chính thư mục của script bằng __DIR__ . '/notes.txt'.
Ghi và ghi thêm với file_put_contents()
file_put_contents() trả về số byte đã ghi, hoặc false khi thất bại. Mặc định, hàm ghi đè lên tệp. Cờ FILE_APPEND thì thêm vào cuối, đó là cách các log đơn giản hoạt động, còn LOCK_EX ngăn hai request ghi vào cùng một thời điểm:
Đầu ra:
Wrote 8 bytes
started
step 1 done
step 2 done
replaced
abc
5 bytes
Để lưu một mảng và lấy lại đúng dạng mảng, hãy ghi nó dưới dạng JSON bằng json_encode() và đọc bằng json_decode().
Đọc tệp từng dòng với file()
file() đọc một tệp thành mảng, mỗi phần tử là một dòng. Mỗi dòng giữ ký tự xuống dòng ở cuối, trừ khi bạn truyền FILE_IGNORE_NEW_LINES, còn FILE_SKIP_EMPTY_LINES bỏ các dòng trống (nó chỉ hoạt động khi đi cùng FILE_IGNORE_NEW_LINES):
Đầu ra:
string(9) "Buy milk
"
1. Buy milk
2. Call Ada
3. Write docs
3 tasks
file() và file_get_contents() nạp toàn bộ tệp vào bộ nhớ. Điều đó ổn với tệp cấu hình và log vài megabyte. Với tệp hàng trăm megabyte, hãy đọc từng dòng một bằng fopen() và fgets().
Kiểm tra tệp có tồn tại trước khi đọc
Khi tệp không tồn tại, file_get_contents() trả về false và PHP in ra cảnh báo:
Warning: file_get_contents(missing.txt): Failed to open stream: No such file or directory in /home/index.php on line 2
Hãy kiểm tra trước bằng is_file() (một tệp có tồn tại và không phải thư mục) hoặc file_exists() (một tệp hoặc một thư mục), và luôn so sánh kết quả với === false, vì một tệp rỗng trả về "", cũng là giá trị falsy:
Đầu ra:
empty.txt exists file
missing.txt missing
. exists directory
Cannot read missing.txt, using defaults
bool(false)
bool(true)
0 bytes
Đừng che cảnh báo bằng @file_get_contents(). Kiểm tra trước, hoặc xử lý false, giúp lỗi vẫn hiện ra khi có chuyện khác xảy ra.
Đọc một phần của tệp
Đối số thứ tư và thứ năm là vị trí byte bắt đầu và số byte cần đọc. Vị trí âm được tính từ cuối tệp. Đối số có tên (named arguments) cho phép bạn bỏ qua hai đối số ở giữa:
Đầu ra:
HEADER
line 2
last line
Vị trí được tính theo byte, không phải ký tự. Trong UTF-8, một ký tự tiếng Nhật chiếm 3 byte, còn nhiều chữ cái tiếng Việt có dấu chiếm 2 hoặc 3 byte, nên một vị trí rơi vào giữa ký tự sẽ cắt đôi nó. Để làm việc theo ký tự, hãy đọc cả chuỗi rồi dùng mb_substr().
Hiển thị tệp văn bản trên trang web
Nội dung tệp là văn bản, và văn bản in vào HTML phải được escape, nếu không một dấu < trong tệp sẽ thành thẻ. htmlspecialchars() escape nó, còn nl2br() biến các dấu xuống dòng thành thẻ <br>. Hãy chạy rồi xem tab Trang:
Bỏ htmlspecialchars() rồi chạy lại: trang giờ dừng ở "v1.2: Fixed", vì trình duyệt hiểu <title> là một thẻ thật và nuốt mọi thứ sau đó làm tiêu đề trang. Trang htmlspecialchars() giải thích vì sao điều đó quan trọng với mọi thứ người dùng có thể viết.
Đọc URL với file_get_contents()
Khi allow_url_fopen được bật (mặc định trong php.ini), file_get_contents() cũng đọc được URL và trả về phần thân của response. Một stream context thêm phương thức, header, phần thân và thời gian chờ:
<?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
}
Để thử lại, chuyển hướng có giới hạn và mã lỗi rõ ràng, cURL hoặc một thư viện HTTP client như Guzzle là công cụ tốt hơn.
file_get_contents, file() và fopen()
| Bạn muốn | Dùng | Bộ nhớ |
|---|---|---|
| Cả tệp thành một chuỗi | file_get_contents() | Cả tệp |
| Các dòng thành một mảng | file($path, FILE_IGNORE_NEW_LINES) | Cả tệp |
| Ghi hoặc thay thế một tệp trong một lời gọi | file_put_contents() | Dữ liệu bạn ghi |
| Thêm một dòng vào log | file_put_contents($path, $line, FILE_APPEND | LOCK_EX) | Một dòng |
| Đọc tệp lớn từng dòng, hoặc từng hàng CSV | fopen() với fgets() hoặc fgetcsv() | Một dòng |
| Vừa đọc vừa ghi cùng một tệp đang mở | fopen() với r+, a+ hoặc c+ | Phần bạn đọc |
Các hàm một lời gọi tự mở, đọc hoặc ghi, rồi đóng tệp giúp bạn, nên chúng là lựa chọn mặc định đúng. Hãy dùng fopen() khi tệp quá lớn để giữ trong bộ nhớ hoặc bạn cần giữ tệp mở giữa các thao tác.
Câu hỏi thường gặp
Làm sao đọc một tệp thành chuỗi trong PHP?
Gọi file_get_contents('path/to/file.txt'). Hàm trả về toàn bộ tệp dưới dạng chuỗi, hoặc false nếu không đọc được tệp, nên hãy so sánh kết quả với === false trước khi dùng.
Làm sao ghi thêm vào cuối tệp trong PHP?
Truyền cờ FILE_APPEND: file_put_contents('log.txt', "new line\n", FILE_APPEND);. Nếu không có cờ này, file_put_contents() thay thế toàn bộ tệp. Thêm LOCK_EX (FILE_APPEND | LOCK_EX) khi nhiều request có thể ghi cùng lúc.
Làm sao đọc tệp từng dòng một trong PHP?
Với tệp nhỏ, file('data.txt', FILE_IGNORE_NEW_LINES) trả về một mảng, mỗi phần tử là một dòng. Với tệp lớn, hãy mở bằng fopen() và đọc từng dòng bằng fgets() trong vòng lặp while, cách này chỉ giữ một dòng trong bộ nhớ.
Vì sao file_get_contents trả về false?
Tệp không tồn tại, đường dẫn tương đối tính từ một thư mục khác với bạn nghĩ, hoặc PHP không có quyền đọc nó. PHP cũng in ra cảnh báo như Failed to open stream: No such file or directory. Hãy kiểm tra bằng is_file() và is_readable(), và tạo đường dẫn từ __DIR__.
file_get_contents có đọc được URL không?
Có, khi allow_url_fopen được bật trong php.ini: file_get_contents('https://example.com/') trả về phần thân của response. Để thêm header, dữ liệu POST hay thời gian chờ, hãy truyền một context tạo bằng stream_context_create(); với những việc phức tạp hơn, cURL xử lý lỗi tốt hơn.