diff --git a/_test/tests/inc/io_readfile.test.php b/_test/tests/inc/io_readfile.test.php
new file mode 100644
index 0000000000000000000000000000000000000000..e3e90cd8d880a03618aa3a0aa5bb92154500b5fa
--- /dev/null
+++ b/_test/tests/inc/io_readfile.test.php
@@ -0,0 +1,53 @@
+<?php
+
+class io_readfile_test extends DokuWikiTest {
+
+    /*
+     * dependency for tests needing zlib extension to pass
+     */
+    public function test_ext_zlib() {
+        if (!extension_loaded('zlib')) {
+            $this->markTestSkipped('skipping all zlib tests.  Need zlib extension');
+        }
+    }
+
+    /*
+     * dependency for tests needing zlib extension to pass
+     */
+    public function test_ext_bz2() {
+        if (!extension_loaded('bz2')) {
+            $this->markTestSkipped('skipping all bzip2 tests.  Need bz2 extension');
+        }
+    }
+
+    function test_plain(){
+        // since git converts line endings, we can't check in this test file but have to create it ourselves
+        $plain = TMP_DIR.'/test.txt';
+        file_put_contents($plain, "The\015\012Test\015\012");
+
+        $this->assertEquals("The\012Test\012", io_readFile($plain));
+        $this->assertEquals("The\015\012Test\015\012", io_readFile($plain, false));
+        $this->assertEquals(false, io_readFile(__DIR__.'/io_readfile/nope.txt'));
+    }
+
+    /**
+     * @depends test_ext_zlib
+     */
+    function test_gzfiles(){
+        $this->assertEquals("The\012Test\012", io_readFile(__DIR__.'/io_readfile/test.txt.gz'));
+        $this->assertEquals("The\015\012Test\015\012", io_readFile(__DIR__.'/io_readfile/test.txt.gz', false));
+        $this->assertEquals(false, io_readFile(__DIR__.'/io_readfile/nope.txt.gz'));
+        $this->assertEquals(false, io_readFile(__DIR__.'/io_readfile/corrupt.txt.gz'));
+    }
+
+    /**
+     * @depends test_ext_bz2
+     */
+    function test_bzfiles(){
+        $this->assertEquals("The\012Test\012", io_readFile(__DIR__.'/io_readfile/test.txt.bz2'));
+        $this->assertEquals("The\015\012Test\015\012", io_readFile(__DIR__.'/io_readfile/test.txt.bz2', false));
+        $this->assertEquals(false, io_readFile(__DIR__.'/io_readfile/nope.txt.bz2'));
+        $this->assertEquals(false, io_readFile(__DIR__.'/io_readfile/corrupt.txt.bz2'));
+    }
+
+}
\ No newline at end of file
diff --git a/_test/tests/inc/io_readfile/corrupt.txt.bz2 b/_test/tests/inc/io_readfile/corrupt.txt.bz2
new file mode 100644
index 0000000000000000000000000000000000000000..97f742919a339644f786b24fa745851a560e3cc4
--- /dev/null
+++ b/_test/tests/inc/io_readfile/corrupt.txt.bz2
@@ -0,0 +1 @@
+BZh91AY&SYXHd¬
\ No newline at end of file
diff --git a/_test/tests/inc/io_readfile/corrupt.txt.gz b/_test/tests/inc/io_readfile/corrupt.txt.gz
new file mode 100644
index 0000000000000000000000000000000000000000..f7f5d3397f2e370afae7fda0d33a838b93a6b155
Binary files /dev/null and b/_test/tests/inc/io_readfile/corrupt.txt.gz differ
diff --git a/_test/tests/inc/io_readfile/test.txt.bz2 b/_test/tests/inc/io_readfile/test.txt.bz2
new file mode 100644
index 0000000000000000000000000000000000000000..3d4e1b226919d86934f6c95756e867b498ffa898
Binary files /dev/null and b/_test/tests/inc/io_readfile/test.txt.bz2 differ
diff --git a/_test/tests/inc/io_readfile/test.txt.gz b/_test/tests/inc/io_readfile/test.txt.gz
new file mode 100644
index 0000000000000000000000000000000000000000..8ac8f7d402263909ed35337fa8d9d68b7f4b165d
Binary files /dev/null and b/_test/tests/inc/io_readfile/test.txt.gz differ
diff --git a/inc/io.php b/inc/io.php
index 3ed2271622f5b5e86ae33d48d62e01c47331c3a1..0636a4b62503c76a7fd76b15f458acdcdc5e1f7d 100644
--- a/inc/io.php
+++ b/inc/io.php
@@ -101,7 +101,7 @@ function _io_readWikiPage_action($data) {
  *
  * @param string $file  filename
  * @param bool   $clean
- * @return string
+ * @return string|bool the file contents or false on error
  */
 function io_readFile($file,$clean=true){
     $ret = '';
@@ -114,7 +114,7 @@ function io_readFile($file,$clean=true){
             $ret = file_get_contents($file);
         }
     }
-    if($clean){
+    if($ret !== false && $clean){
         return cleanText($ret);
     }else{
         return $ret;
@@ -124,22 +124,28 @@ function io_readFile($file,$clean=true){
  * Returns the content of a .bz2 compressed file as string
  *
  * @author marcel senf <marcel@rucksackreinigung.de>
+ * @author  Andreas Gohr <andi@splitbrain.org>
  *
  * @param string $file filename
- * @return string content
+ * @return string|bool content or false on error
  */
 function bzfile($file){
     $bz = bzopen($file,"r");
+    if($bz === false) return false;
+
     $str = '';
     while (!feof($bz)){
         //8192 seems to be the maximum buffersize?
-        $str = $str . bzread($bz,8192);
+        $buffer = bzread($bz,8192);
+        if(($buffer === false) || (bzerrno($bz) !== 0)) {
+            return false;
+        }
+        $str = $str . $buffer;
     }
     bzclose($bz);
     return $str;
 }
 
-
 /**
  * Used to write out a DokuWiki page to file, and send IO_WIKIPAGE_WRITE events.
  *