On 04.01.2016 at 00:37 Umberto Salsi wrote: > 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: > > error_reporting(-1); > ini_set("track_errors", "1"); > > > function my_error_handler($errno, $message) > { > throw new ErrorException($message); > } > > set_error_handler("my_error_handler"); > > > 1. fread() succeeds reading an unreadable file. While fopen() complains > immediately if it cannot read a file: > > fopen("/root/secret.txt", "r"); > --> 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: > http://unix.stackexchange.com/a/6302): > > $ 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 > tolerant: > > require("/proc/self/mem"); > 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'; > file_put_contents($fn, $compressed); > > 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: > > do { > $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 > goes wrong? I suggest that you file respective bug reports (unless that has already happened). -- Christoph M. Becker -- PHP General Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php