Click here to Skip to main content
15,891,253 members
Articles / Programming Languages / PHP

PHPIO [PHP In/Out Classes]

Rate me:
Please Sign up or sign in to vote.
4.11/5 (6 votes)
15 Jul 2011CPOL2 min read 20.4K   317   10   2
Basic PHP IO classes to provide easy access for reading and writing to files.

Introduction

PHPIO consists of classes that were made for easy access for reading and writing files from PHP. Nothing really fancy, but very easy to use!

Included in the 'Reader' class:

  • Reader construct
  • Reader open/close
  • Get/Set reader position
  • Get reader length
  • Get/Set file mode
  • Get file name
  • ReadByte (return byte)
  • ReadBytes (return byte array)
  • ReadHexString (return hex string)
  • ReadChar (return character)
  • ReadString (return string)
  • Supports Reading Integers in Big and Little Endian
  • ReadInt8 (return Int8)
  • ReadInt16 (return Int16)
  • ReadInt32 (return Int32)
  • ReadUInt8 (return UInt8)
  • ReadUInt16 (return UInt16)
  • ReadUInt32 (return UInt32)

Included in the 'Writer' class:

  • Writer construct
  • Writer open/close
  • Get/Set writer position
  • Get writer length
  • Get/Set file mode
  • Get file name
  • WriteByte (return byte count)
  • WriteBytes (return byte count)
  • WriteHexString (return length)
  • WriteChar (return length)
  • WriteString (return length)
  • Supports Writing Integers in Big and Little Endian
  • WriteInt8 (return byte count)
  • WriteInt16 (return byte count)
  • WriteInt32 (return byte count)
  • WriteUInt8 (return byte count)
  • WriteUInt16 (return byte count)
  • WriteUInt32 (return byte count)

Included in the 'Conversions' class:

  • Int8ToUInt8
  • Int16ToUInt16
  • Int32ToUInt32
  • UInt8ToInt8
  • UInt16ToInt16
  • UInt32ToInt32
  • Int8ToByte
  • Int16ToBytes
  • Int32ToBytes
  • UInt8ToByte
  • UInt16ToBytes
  • UInt32ToBytes
  • ByteToInt8
  • BytesToInt16
  • BytesToInt32
  • ByteToUInt8
  • BytesToUInt16
  • BytesToUInt32
  • BytesToAscii
  • BytesToHex
  • AsciiToBytes
  • AsciiToHex
  • HexToBytes
  • HexToAscii

Included in the 'EndianType' class:

  • BIG = 0
  • LITTLE = 1
  • GetValue
  • GetName

Using the Code

Using the classes is easy. You can either copy/paste into a PHP file or "include/require" from an external source into a PHP file.

Example #1

PHP
<?php
include "phpio.php"; //include the PHP Class from external source.
$filepath = "C:\TextFile.txt";
//declare a file to use. if it does not exist then the reader will throw an exception.

$writer = new Writer($filepath); //create a new writer with default settings.
//$writer = new Writer($filepath, "w+", 1337); //create a new writer with custom settings.
$writer->Open(); //opens the file using the writer with settings.
$writer->WriteByte(0x31); //write the byte '31' (1).
$writer->WriteBytes(array(0x32, 0x33, 0x34)); //write the bytes '32, 33, 34' (2, 3, 4).
$writer->WriteHexString("FFFFFFFF"); //write the hex string FFFFFFFF as bytes
$writer->Position(1337); //set the writer's position in the open file.
$writer->WriteChar("J"); //write the character 'J'.
$writer->WriteString("izzaBeez"); //write the string 'izzaBeez'.
$writer->Close();
//close the open file. but does not 'destroy' the writer,
//so it can be re-opened without declaring it again if wanted.

$reader = new Reader($filepath); //create a new reader with default settings.
//$reader = new Reader($filepath, "r+", 1337); //create a new reader with custom settings.
$reader->Open(); //opens the file using the reader with settings.
$reader->ReadByte(); //reads a byte and returns decimal.
$reader->ReadBytes(3); //read '3' bytes. returns decimal byte array.
$reader->ReadHexString(4); //read hex string.
$reader->Position(1337); //set the reader's position in the open file.
$reader->ReadChar(); //read a character.
$reader->ReadString(8); //read a string length of '8'.
$reader->Close();
//close the open file. but does not 'destroy' the reader,
//so it can be re-opened without declaring it again if wanted.
?>

Example #2

PHP
<?php
include "phpio.php"; //Include the PHP Classes file.
$filepath = "C:\TextFile.txt"; //declare a filepath to use

//..::Writer::..
try{
    echo "..::WRITER::.." . "<br />"; //just a title :)
    $writer = new Writer($filepath); //declares new Writer with default settings
    //$writer = new Writer($filepath, "r+", 0); //declares new Writer with custom settings
    //opens file with set filemode/position
    echo "Open (return resource) : " . $writer->Open() . "<br />";
    echo "FilePath (return filepath) : " . $filepath . "<br />"; //filepath of file
    echo "FileName (return filename) : " . 
         $writer->FileName() . "<br />"; //filename of open file
    echo "FileMode (return filemode) : " . 
         $writer->FileMode() . "<br />"; //filemode of open file
    echo "Position (return position) : " . 
         $writer->Position() . "<br />"; //position in open file
    echo "Length (return length) : " . 
         $writer->Length() . "<br />"; //length of file
    echo "WriteByte (return count) : " . $writer->WriteByte(0x31) . 
	"<br />"; //write dec byte
    echo "WriteBytes (return count) : " . 
         $writer->WriteBytes(array(0x32, 0x33, 0x34)) . "<br />"; //write dec byte array
    echo "WriteHexString (return count) : " . 
         $writer->WriteHexString("FFFFFFFF")) . "<br />"; //write hex string
    echo "Position (set & return position) : " . 
         $writer->Position(1337) . "<br />"; //change position in open file
    echo "WriteChar (return length) : " . 
         $writer->WriteChar("J") . "<br />"; //write character
    echo "WriteString (return length) : " . 
         $writer->WriteString("izzaBeez") . "<br />"; //write string set by length
    echo "Length (return updated length) : " . 
         $writer->Length() . "<br />"; //length of file
    echo "Close (return true/false) : " . $writer->Close() . 
         "<br />"; //closes the open file
    //must close then re-open the file to change modes!
    echo "FileMode (set & return filemode) : " . $writer->FileMode("r+") . "<br />";
    //opens file with set filemode/position
    echo "Open (return resource) : " . $writer->Open() . "<br />";
    echo "FileMode (return filemode) : " . 
         $writer->FileMode() . "<br />"; //filemode of open file
    echo "Position (return position) : " . 
         $writer->Position() . "<br />"; //position in open file
    echo "Close (return true/false) : " . 
         $writer->Close() . "<br />"; //closes the open file
}
catch (Exception $e) { //catch errors
    echo "Error: " . $e->getMessage() . "<br />"; //return error message
}

echo "<br />"; //just a new line :)

//..::Reader::..
try {
    echo "..::READER::.." . "<br />"; //just a title :)
    $reader = new Reader($filepath); //declares new Reader with default settings
    //declares new Reader with custom settings
    //$reader = new Reader($filepath, "r+", 0);
    //opens file with set filemode/position
    echo "Open (return resource) : " . $reader->Open() . "<br />";
    echo "FilePath (return filepath) : " . $filepath . "<br />"; //filepath of file
    echo "FileName (return filename) : " . 
         $reader->FileName() . "<br />"; //filename of open file
    echo "FileMode (return filemode) : " . 
         $reader->FileMode() . "<br />"; //filemode of open file
    echo "Position (return position) : " . 
         $reader->Position() . "<br />"; //position in open file
    echo "Length (return length) : " . $reader->Length() . "<br />"; //length of file
    echo "ReadByte (return dec byte) : " . $reader->ReadByte() . "<br />"; //read byte
    echo "ReadBytes (return dec byte array) : " . 
         $reader->ReadBytes(3) . "<br />"; //read bytes set by length
    echo "ReadHexString (return hex string) : " . 
         $reader->ReadHexString(4) . "<br />"; //read hex string set by length
    //change position in open file
    echo "Position (set & return position) : " . $reader->Position(1337) . "<br />";
    echo "ReadChar (return  character) : " . 
         $reader->ReadChar() . "<br />"; //read character
    echo "ReadString (return string) : " . 
         $reader->ReadString(8) . "<br />"; //read string set by length
    echo "Close (return true/false) : " . 
         $reader->Close() . "<br />"; //closes the open file
    //must close then re-open the file to change modes!
    echo "FileMode (set & return filemode) : " . $reader->FileMode("r+") . "<br />";
    //opens file with set filemode/position
    echo "Open (return resource) : " . $reader->Open() . "<br />";
    echo "FileMode (return filemode) : " . 
         $reader->FileMode() . "<br />"; //filemode of open file
    echo "Position (return position) : " . 
         $reader->Position() . "<br />"; //position in open file
    echo "Close (return true/false) : " . 
         $reader->Close() . "<br />"; //closes the open file
}
catch (Exception $e) { //catch errors
    echo "Error: " . $e->getMessage() . "<br />"; //return error message
}
?>

Text Output of Example #2

..::WRITER::..
Open (return resource) : Resource id #3
FilePath (return filepath) : C:\TextFile.txt
FileName (return filename) : TextFile.txt
FileMode (return filemode) : w
Position (return position) : 0
Length (return length) : 0
WriteByte (return count) : 1
WriteBytes (return count) : 3
WriteHexString (return count) : 4
Position (set & return position) : 1337
WriteChar (return length) : 1
WriteString (return length) : 8
Length (return updated length) : 1346
Close (return true/false) : 1
FileMode (set & return filemode) : r+
Open (return resource) : Resource id #4
FileMode (return filemode) : r+
Position (return position) : 1346
Close (return true/false) : 1

..::READER::..
Open (return resource) : Resource id #5
FilePath (return filepath) : C:\TextFile.txt
FileName (return filename) : TextFile.txt
FileMode (return filemode) : r
Position (return position) : 0
Length (return length) : 1346
ReadByte (return dec byte) : 49
ReadBytes (return dec byte array) : Array
ReadHexString (return hex string) : FFFFFFFF
Position (set & return position) : 1337
ReadChar (return character) : J
ReadString (return string) : izzaBeez
Close (return true/false) : 1
FileMode (set & return filemode) : r+
Open (return resource) : Resource id #6
FileMode (return filemode) : r+
Position (return position) : 1346
Close (return true/false) : 1

How to Select Endian for Read/Write

Big and Little Endians are supported for Integer Read/Write. To select one, just put a 0 or 1 in as the variable. Big = 0, Little = 1, Default = 0.

PHP
<?php
    $length = $reader->ReadInt32(0); //reads the integer as Big Endian
    
    $length = $reader->ReadInt32(1); //reads the integer as Little Endian
    
    $writer->WriteInt32(1337, 0); // writes the integer as Big Endian
    
    $writer->WriteInt32(1337, 1); // writes the integer as Little Endian
?>

PHPIO Source

Here is the complete source code:

PHP
<?php
// PHPIO: [PHP In/Out Classes]
// Version: 1.0.5.0
// Created by: JizzaBeez (jizzabeez@hotmail.com)
// Released: 07/13/2011

class Reader {
    private $filepath = "";
    private $openfile = "";
    private $filemode = "";
    private $position = 0;
    private $length = 0;

    public function __construct($filepath, $filemode = "r", $position = 0) {
        if (file_exists($filepath)) {
            $this->filepath = $filepath;
            $this->filemode = $filemode;
            $this->position = $position;
            $this->length = filesize($this->filepath);
        }
        else { throw new Exception("file does not exist"); }
    }
    
    function FileName() { return basename($this->filepath); }
    
    function FileMode($filemode) {
        if ($filemode != null) { $this->filemode = $filemode; } 
        return $this->filemode; 
    }
    
    function Length() {
        clearstatcache();
        $this->length = filesize($this->filepath);
        return $this->length;
    }
    
    function Position($position) {
        if ($position != null) { $this->position = $position; }
        return $this->position; 
    }
    
    function Open() {
        $this->openfile = fopen($this->filepath, $this->filemode) or 
			exit("could not open file");
        return $this->openfile;
    }
    
    function Close() {
        return fclose($this->openfile);
    }
    
    function ReadByte() {
        fseek($this->openfile, $this->position);
        $data = strtoupper(bin2hex(fread($this->openfile, 1)));
        $this->position = ftell($this->openfile);
        return hexdec($data);
    }
    
    function ReadBytes($length) {
        fseek($this->openfile, $this->position);
        $data = strtoupper(bin2hex(fread($this->openfile, $length)));
        $bytes = array(); $x = 0;
        for ($i = 0; $i < strlen($data); $i += 2) {
            $bytes[$x] = hexdec(substr($data, $i, 1) . substr($data, $i + 1, 1));
            $x += 1;
        }
        $this->position = ftell($this->openfile);
        return $bytes;
    }
    
    function ReadHexString($length) {
        fseek($this->openfile, $this->position);
        $data = strtoupper(bin2hex(fread($this->openfile, $length)));
        $this->position = ftell($this->openfile);
        return $data;
    }

    function ReadChar() {
        fseek($this->openfile, $this->position);
        $data = fread($this->openfile, 1);
        $this->position = ftell($this->openfile);
        return $data;
    }

    function ReadString($length) {
        fseek($this->openfile, $this->position);
        $data = fread($this->openfile, $length);
        $this->position = ftell($this->openfile);
        return $data;
    }
    
    function ReadInt8() {
        $conv = new Conversions;
        $bytes = $this->ReadByte();
        return $conv->ByteToInt8($bytes);
    }
    
    function ReadInt16($endian = 0) {
        $conv = new Conversions;
        $bytes = $this->ReadBytes(2);
        if ($endian == 1) { $bytes = array_reverse($bytes); }
        return $conv->BytesToInt16($bytes);
    }
    
    function ReadInt32($endian = 0) {
        $conv = new Conversions;
        $bytes = $this->ReadBytes(4);
        if ($endian == 1) { $bytes = array_reverse($bytes); }
        return $conv->BytesToInt32($bytes);
    }
    
    function ReadUInt8() {
        $conv = new Conversions;
        $bytes = $this->ReadByte();
        return $conv->ByteToUInt8($bytes);
    }
    
    function ReadUInt16($endian = 0) {
        $conv = new Conversions;
        $bytes = $this->ReadBytes(2);
        if ($endian == 1) { $bytes = array_reverse($bytes); }
        return $conv->BytesToUInt16($bytes);
    }
    
    function ReadUInt32($endian = 0) {
        $conv = new Conversions;
        $bytes = $this->ReadBytes(4);
        if ($endian == 1) { $bytes = array_reverse($bytes); }
        return $conv->BytesToUInt32($bytes);
    }
}

class Writer {
    private $filepath = "";
    private $openfile = "";
    private $filemode = "";
    private $position = 0;
    private $length = 0;
    
    public function __construct($filepath, $filemode = "w", $position = 0) {
        $this->filepath = $filepath;
        $this->filemode = $filemode;
        $this->position = $position;
        if (file_exists($this->filepath)) 
        { $this->length = filesize($this->filepath); }
        else { $this->length = 0; }
    }
    
    function FileName() { return basename($this->filepath); }
    
    function FileMode($filemode) {
        if ($filemode != null) { $this->filemode = $filemode; }
        return $this->filemode;
    }
    
    function Length() {
        clearstatcache();
        if (file_exists($this->filepath)) 
        { $this->length = filesize($this->filepath); }
        else { $this->length = 0; }
        return $this->length;
    }
    
    function Position($position) {
        if ($position != null) { $this->position = $position; }
        return $this->position; 
    }
    
    function Open() {
        $this->openfile = fopen($this->filepath, 
        $this->filemode) or exit("could not open file");
        return $this->openfile;
    }
    
    function Close() {
        return fclose($this->openfile);
    }
    
    function WriteByte($byte) {
        fseek($this->openfile, $this->position);
        $data = fwrite($this->openfile, chr($byte));
        $this->position = ftell($this->openfile);
        return $data;
    }

    function WriteBytes($bytes) {
        fseek($this->openfile, $this->position);
        $data = 0;
        for ($i = 0; $i < count($bytes); $i++) { 
            $data += fwrite($this->openfile, chr($bytes[$i])); 
        }
        $this->position = ftell($this->openfile);
        return $data;
    }
    
    function WriteHexString($str) {
        fseek($this->openfile, $this->position);
        $bytes = array(); $x = 0;
        for ($i = 0; $i < strlen($str); $i += 2) {
            $bytes[$x] = hexdec(substr($str, $i, 1) . substr($str, $i + 1, 1));
            $x += 1;
        }
        $data = 0;
        for ($i = 0; $i < count($bytes); $i++) { 
            $data += fwrite($this->openfile, chr($bytes[$i])); 
        }
        $this->position = ftell($this->openfile);
        return $data;
    }
    
    function WriteChar($char) {
        fseek($this->openfile, $this->position);
        $data = fwrite($this->openfile, $char);
        $this->position = ftell($this->openfile);
        return $data;
    }
    
    function WriteString($string) {
        fseek($this->openfile, $this->position);
        $data = fwrite($this->openfile, $string);
        $this->position = ftell($this->openfile);
        return $data;
    }
    
    function WriteInt8($dec) {
        $conv = new Conversions;
        $bytes = $conv->Int8ToByte($dec);
        return $this->WriteByte($bytes);
    }
    
    function WriteInt16($dec, $endian = 0) {
        $conv = new Conversions;
        $bytes = $conv->Int16ToBytes($dec);
        if ($endian == 1) { $bytes = array_reverse($bytes); }
        return $this->WriteBytes($bytes);
    }
    
    function WriteInt32($dec, $endian = 0) {
        $conv = new Conversions;
        $bytes = $conv->Int32ToBytes($dec);
        if ($endian == 1) { $bytes = array_reverse($bytes); }
        return $this->WriteBytes($bytes);
    }
    
    function WriteUInt8($dec) {
        $conv = new Conversions;
        $bytes = $conv->UInt8ToByte($dec);
        return $this->WriteByte($bytes);
    }
    
    function WriteUInt16($dec, $endian = 0) {
        $conv = new Conversions;
        $bytes = $conv->UInt16ToBytes($dec);
        if ($endian == 1) { $bytes = array_reverse($bytes); }
        return $this->WriteBytes($bytes);
    }
    
    function WriteUInt32($dec, $endian = 0) {
        $conv = new Conversions;
        $bytes = $conv->UInt32ToBytes($dec);
        if ($endian == 1) { $bytes = array_reverse($bytes); }
        return $this->WriteBytes($bytes);
    }
}

class EndianType {
    const BIG = 0;
    const LITTLE = 1;
    function GetValue($name) { $name = strtoupper($name); 
    return constant("EndianType::".$name); }
    function GetName($value) { switch ($value) 
    { case 0: return "BIG"; break; case 1: return "LITTLE"; 
    break; default: return "NOTHING"; } }
}

class Conversions {
    function UInt8ToInt8($dec) { if ($dec > 127) 
    { $dec = ($dec - 256); } return $dec; }
    function UInt16ToInt16($dec) { if ($dec > 32767) 
    { $dec = ($dec - 65536); } return $dec; }
    function UInt32ToInt32($dec) { if ($dec > 2147483647) 
    { $dec = ($dec - 4294967296); } return $dec; }
    function Int8ToUInt8($dec) { if ($dec < 0) 
    { $dec = ($dec + 256); } return $dec; }
    function Int16ToUInt16($dec) { if ($dec < 0) 
    { $dec = ($dec + 65536); } return $dec; }
    function Int32ToUInt32($dec) { if ($dec < 0) 
    { $dec = ($dec + 4294967296); } return $dec; }
    function BytesToAscii ($bytes) { $str = ""; 
    for ($i = 0; $i < count($bytes); $i ++) 
    { $str .= chr($bytes[$i]); } return $str; }
    function AsciiToBytes($str) { $bytes = array(); 
    for ($i = 0; $i < strlen($str); $i ++) 
    { $bytes[$i] = ord(substr($str, $i, 1)); } return $bytes; }
    function AsciiToHex($str) { return bin2hex($str); }
    function HexToAscii($str) { $data = ""; $byte = ""; 
    for ($i = 0; $i < strlen($str); $i += 2) 
    { $byte = hexdec($str[$i] . $str[$i + 1]); $data .= chr($byte); } return $data; }
    function HexToBytes($str) { if (strlen($str) == 0) 
    { return 0; } $bytes = array(); $x = 0; 
    for ($i = 0; $i < strlen($str); $i += 2) 
    { $bytes[$x] = hexdec(substr($str, $i, 1) . substr
    ($str, $i + 1, 1)); $x += 1; } return $bytes; }
    function BytesToHex($bytes) { if (!is_array($bytes)) 
    { return strtoupper(dechex($bytes)); } $hex = ''; 
    for ($i = 0; $i < count($bytes); $i ++) 
    { $hex .= dechex($bytes[$i]); } return strtoupper($hex); }
    function ByteToInt8($byte) { if (is_array($byte)) 
    { throw new Exception("invalid input"); } $conv = 
    new Conversions; return $conv->UInt8ToInt8($byte); }
    function BytesToInt16($bytes) { if (count($bytes) != 2) 
    { throw new Exception("invalid input"); } $dec = 
    (($bytes[0] << 8) + ($bytes[1])); 
    $conv = new Conversions; return $conv->UInt16ToInt16($dec); }
    function BytesToInt32($bytes) { if (count($bytes) != 4) 
    { throw new Exception("invalid input"); } 
    $dec = (($bytes[0] << 24) + ($bytes[1] << 16) + 
    ($bytes[2] << 8) + ($bytes[3])); 
    $conv = new Conversions; return $conv->UInt32ToInt32($dec); }
    function ByteToUInt8($byte) { if (is_array($byte)) 
    { throw new Exception("invalid input"); } 
    $conv = new Conversions; return $conv->Int8ToUInt8($byte); }
    function BytesToUInt16($bytes) { if (count($bytes) != 2) 
    { throw new Exception("invalid input"); } 
    $dec = (($bytes[0] << 8) + ($bytes[1])); 
    $conv = new Conversions; return $conv->Int16ToUInt16($dec); }
    function BytesToUInt32($bytes) { if (count($bytes) != 4) 
    { throw new Exception("invalid input"); } $dec = 
    (($bytes[0] << 24) + ($bytes[1] << 16) + 
    ($bytes[2] << 8) + ($bytes[3])); $conv = new Conversions; 
    return $conv->Int32ToUInt32($dec); }
    function Int8ToByte($dec) { if ($dec > 127 || $dec < -128) 
    { throw new Exception("invalid input"); } 
    $byte = ($dec & 0xFF); return $byte; }
    function Int16ToBytes($dec) { if ($dec > 32767 || 
    $dec < -32768) { throw new Exception("invalid input"); } 
    $bytes = array(); $bytes[0] = ($dec >> 8) & 0xFF; 
    $bytes[1] = ($dec) & 0xFF; return $bytes; }
    function Int32ToBytes($dec) { if ($dec > 2147483647 || 
    $dec < -2147483648) { throw new Exception("invalid input"); } 
    $bytes = array(); $bytes[0] = ($dec >> 24) & 0xFF; 
    $bytes[1] = ($dec >> 16) & 0xFF; $bytes[2] = ($dec >> 8) 
    & 0xFF; $bytes[3] = ($dec >> 0) & 0xFF; return $bytes; }
    function UInt8ToByte($dec) { if ($dec > 255 || $dec < 0) 
    { throw new Exception("invalid input"); } $byte = ($dec & 0xFF); return $byte; }
    function UInt16ToBytes($dec) { if ($dec > 65535 || $dec < 0) 
    { throw new Exception("invalid input"); } $bytes = array(); 
    $bytes[0] = ($dec >> 8) & 0xFF; $bytes[1] = ($dec) & 0xFF; return $bytes; }
    function UInt32ToBytes($dec) { if ($dec > 4294967295 || 
    $dec < 0) { throw new Exception("invalid input"); } 
    $bytes = array(); $bytes[0] = ($dec >> 24) & 0xFF; $bytes[1] = 
    ($dec >> 16) & 0xFF; $bytes[2] = ($dec >> 8) & 
    0xFF; $bytes[3] = ($dec) & 0xFF; return $bytes; }
    function ArrayReverse($array) { return array_reverse($array); }
}?>

History

  • 07/13/2011 - PHPIO version 1.0.5.0 released
  • 07/11/2011 - PHPIO version 1.0.0.5 released

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Other
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 5 Pin
maheshmahesh1112-Apr-12 18:42
maheshmahesh1112-Apr-12 18:42 
GeneralMy vote of 1 Pin
glushkin3-Mar-12 1:04
glushkin3-Mar-12 1:04 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.