[PHP] General file I/O reliability
- Date: Mon, 04 Jan 2016 00:37:48 +0100
- From: Umberto Salsi <salsi@xxxxxxxxxxxx>
- Subject: [PHP] General file I/O reliability
I'm desperately trying to build a reliable stream bzip2 decompressor, but
until now without much success. The problem is how to detect deconding
errors, which seem to be impossible (more follows).
In the meanwhile, I discovered several issues I was not aware of and
that I wouls share with you, with the premise that all the samples of
code below are run in a very safe environement where even the smallest
E_NOTICE causes an exception:
function my_error_handler($errno, $message)
throw new ErrorException($message);
1. fread() succeeds reading an unreadable file. While fopen() complains
immediately if it cannot read a file:
--> E_WARNING: fopen(/root/secret.txt): failed to open
stream: Permission denied
the fread() function seem much more tolerant reading an unreadable file.
For example, the /proc/self/mem file can be opened, but its first 512
bytes block cannot be read and causes an error (credits for this trick:
$ cat /proc/self/mem
cat: /proc/self/mem: Input/output error
Lets try with PHP what happens:
$f = fopen("/proc/self/mem", "r");
$bytes = fread($f, 1000);
echo "bytes="; var_dump($bytes);
--> displays bytes=string(0) "", no error whatsoever
The file seems empty, and no error whatsoever is shown.
2. Also the require*() and include*() family of functions seems very
echo "read myself!\n";
require("/root/secret.php"); # just to exsercise error reporting :-)
--> read myself!
E_WARNING: require(/root/secret.php): failed to open
stream: Permission denied
The first require() silently ignored. Bad feeling about safety.
3. Now back to the original question: BZIP2 stream decoding from a given
input resource. Lets start creating a corrupted BZIP2 file:
$plain = "The quick brown fox jumps over the lazy dog.";
$fn = "test.bz2";
$compressed = bzcompress($plain);
// Set a random byte in the middle of the compressed data
$compressed[strlen($compressed) - 15] = 'X';
Now I create the input resource filtered with the decompressor:
$r = fopen($fn, "r");
stream_filter_append($r, 'bzip2.decompress', STREAM_FILTER_READ);
and lets see what come back:
$s = fread($r, 10);
echo "read: "; var_dump($s);
} while(! feof($r));
--> read: string(0) ""
read: string(10) "bthes ohe "
read: string(10) "rpujumr.bt"
read: string(10) "hes ohe rp"
read: string(10) "ujumr.bthe"
read: string(3) "s o"
What?! Why is fread() returning garbage? and why it does not fails with
some E_WARNING telling me that the file is corrupted? And what if my
program blindly processes these "data"?
Now the big question is: can I trust file access under PHP anymore? If
yes (and I hope so) how can my applications be made aware when something
/_|_\ Umberto Salsi
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php