PHP file_get_contents problem in PHP 7.1
Published: 20 January 2017 • Tags: php
I came across a strange issue with PHP’s file_get_contents
function recently, when upgrading to PHP 7.1. It seemed that the function was no longer working in some existing code, and returning a blank string. Here’s what happened and how to fix it.
The problem #
My first step was to check the files being read in case they were empty or there was a permissions problem. All was fine, so I double checked exactly how I was calling the file_get_contents
function. I had several calls like this:
$content = file_get_contents('filename', false, null, -1, 1000);
It should take only the first 1000 characters from the file. However, it appears the code was passing in -1 at the fourth argument - the offset. This is how many characters from the start of the file to begin reading from. So if it passed 100 as the offset it would skip the first 100 characters of the file and read the next 1000 characters after that.
PHP 7.1 introduced negative offsets, so passing in -1 now means “start reading from 1 character before the end”. Instead of reading the first 1000 characters it was only reading a single character - the last! More often than not the last character of a file is just a line break or other whitespace, which can be hard to detect (especially if trim()
is called on the result).
The solution #
The quick fix is to use 0 as the offset instead, to make it read from the start of the file:
$content = file_get_contents('filename', false, null, 0, 1000);
If you are upgrading to PHP 7.1 or later from an earlier version, check your PHP code for uses of this function.
The background #
However, this issue intrigued me. If we could have used 0 in the first place, why was the code using -1? After a bit of digging I found my answer.
The length argument comes last in the file_get_contents
function, so the previous arguments should use their defaults if they are not otherwise being used. I checked the function page in the PHP manual - here is what’s shown:
string file_get_contents ( string $filename [, bool $use_include_path = false [, resource $context [, int $offset = 0 [, int $maxlen ]]]] )
The offset is shown as 0, which is correct. But there is also a comment from a few years ago at the bottom of the page also using this incorrect offset of -1. I did some searching around on the internet, looking at help forums, code repositories and the like, and found several examples of people using -1 as that parameter. One of those answers even looked like a function signature from the manual, but with -1.
So I checked the Internet Archive (note: slow-loading page) and lo and behold, it turns out the PHP manual used to show -1 as the default value.
string file_get_contents ( string $filename [, bool $use_include_path = false [, resource $context [, int $offset = -1 [, int $maxlen ]]]] )
I can’t find anything that suggests -1 is - or was - a special value. It seems like any negative numbers in the past were just treated the same as 0. Today, 0 is correct default parameter, which makes sense since the default should be to start from the beginning.
So there we have it - a lesson in the value of correct documentation!