<?php
/**
* @author Tobias Marstaller
* @desc Provides an interface to exchange PHP numbers with arrays that represent their value in bit-format
*/
abstract class BigEndian {
public static function readInt($len, InputStream $from) {
if ($len%8!=0)
throw new Exception("Length must be a multiple of 8");
$bytes=array();
$len=$len/8;
for ($i=0;$i<$len;$i++) {
$b=$from->read();
if (!is_int($b)) $b=ord($b);
$bytes[]=$b;
}
$number=0;
$bytes=array_reverse($bytes);
for ($i=count($bytes)-1;$i>=0;$i--) {
$x=$bytes[$i]*(self::exp(256, $i));
$number+=$x;
}
return $number;
}
public static function writeInt($len, $int) {
if ($len%8!=0)
throw new Exception("Length must be a multiple of 8");
$len=$len/8;
$bytes=array();
for ($i=$len-1;$i>=0;$i--) {
$exp=self::exp(256, $i);
$x=floor($int/$exp);
$int-=$x*$exp;
$bytes[]=$x;
}
return $bytes;
}
public static function readInt16(InputStream $from) {
return self::readInt(16, $from);
}
public static function readInt32(InputStream $from) {
return self::readInt(32, $from);
}
public static function readInt64(InputStream $from) {
return self::readInt(64, $from);
}
public static function readInt128(InputStream $from) {
return self::readInt(128, $from);
}
public static function writeInt16($int) {
return self::writeInt(16, $int);
}
public static function writeInt32($int) {
return self::writeInt(32, $int);
}
public static function writeInt64($int) {
return self::writeInt(64, $int);
}
public static function writeInt128($int) {
return self::writeInt(128, $int);
}
private static function exp($a, $b) {
if ($b==0) return 1;
for ($i=1;$i<$b;$i++) {
$a*=$a;
}
return $a;
}
}
interface Closable {
public function close();
}
interface Flushable {
/**
* @throws IOException
*/
public function flush();
}
/**
* @desc Thrown whenever an error occures during an input/output action.
* @author Tobias Marstaller
*/
class IOException extends Exception {
}
interface FileFilter {
public function accept(File $file);
}
interface FilenameFilter {
public function accept(File $parent, $file);
}
/**
* @author Tobias Marstaller
* @descr Represents a temporary file
*/
class TemporaryFile extends File {
/**
* @desc The PHP-Handle to the file
* @param -resource $handle
*/
private $handle;
/**
* @desc Holds all information available about the file
* @param -array $streamMetaData
*/
private $streamMetaData;
public function __construct() {
super();
$this->handle=tmpfile();
$this->streamMetaData=stream_get_metadata($this->handle);
$this->path=$this->streamMetaData["uri"];
$this->readable=true;
$this->writable=true;
$this->executable=false;
$this->filename=basename($this->path);
$this->isFile=true;
$this->hidden=false;
}
public function __destruct() {
fclose($this->handle);
}
public static function createTmpFile() {
return;
}
/**
* @hidden
*/
public function getHandle() {
return $this->handle;
}
}
/**
* @author Tobias Marstaller
* @desc Represents a file in the physical file-system. It does not have to exist
*/
class File {
const FILE_SEPARATOR=DIRECTORY_SEPARATOR;
/**
* @param -String $path The absolute path to this file
* @param -String $filename The name of this file (not path and no extension)
* @param -boolean $isFile Weather this represents a file or a directory
* @param -boolean $executable
* @param -boolean $readable
* @param -boolean $writable
* @param -boolean $deleteOnExit If true, this file we be deleted when the execution is stopped
* @param -boolean $isFileOwner Wheather the user, php is ran under, owns this file
*/
protected $path;
protected $filename;
protected $isFile=true;
protected $executable=false;
protected $readable=false;
protected $writable=false;
protected $deleteOnExit=false;
protected $isFileOwner=false;
/*
File(String $path);
File(String $parent, String $child);
File(File $parent, String $child);
* @param -String/File $path Parent directory or path to the file
* @param -String $child Optional; File in the parent directory
*/
protected function __constrcut() {
// creates a null-file
}
public function __construct($path, $child=null) {
if ($path instanceof File) {
if ($child==null) {
throw new IOException("Missing second argument");
}
$parent=$path;
if (!$parent->isDirectory()) {
throw new IOException("File musst be a directory");
}
$path=$parent->getAbsolutePath();
$path.=$child;
$this->path=$path;
$this->filename=basename($path);
$this->isFile=!is_dir($path);
} else if (is_string($path)) {
if ($child!=null) {
if (!is_string($child)) {
throw new IOException("\$child must be a string");
}
if (!is_directory($path)) {
throw new IOException("\$path must be a directory");
}
$path=dirname($path).File::FILE_SEPARATOR.$child;
if ($this->exists()) {
$this->isFile=!is_directory($path);
} else {
$a=substr($path, strrpos($path, File::FILE_SEPARATOR));
$this->isFile=strpos($a, ".")!==false;
}
$this->path=$path;
$this->filename=basename($path);
} else {
$this->isFile=!is_dir($path);
if (!$this->isFile) {
$this->path=dirname($path);
} else {
$this->path=$path;
}
$this->filename=basename($path);
}
} else {
throw new IOException("Invalid argument \$path. Must be instance of File or String.");
}
// Absoluten Pfad erstellen
if (!preg_match("!^\w:\\\!", $this->path)
&& !preg_match("!^/!", $this->path)) {
$path=getcwd();
if (substr($path, strlen($path)-1)!=File::FILE_SEPARATOR) {
$path.=File::FILE_SEPARATOR;
}
$this->path=$path.$this->path;
}
if ($this->exists()) {
if (substr(PHP_OS, 0, 3)!="WIN") {
$rights="".fileperms($this->path);
$user_r=(int) substr($rights, 0, 1);
$group_r=(int) substr($rights, 1, 1);
$public_r=(int) substr($rights, 2, 1);
$owner=posix_getpwuid(fileowner($this->path));
$rights=0;
if ($owner["name"]==$_ENV["user"]) {
$rights=$user_r;
$this->isFileOwner=true;
} else if ($owner["gid"]==filegroup($this->path)) {
$rights=$group_r;
} else $rights=$public_r;
switch ($rights) {
case 1:
$this->executable=true;
break;
case 2:
$this->writable=true;
break;
case 3:
$this->writable=true;
$this->readable=false;
break;
case 4:
$this->readable=true;
break;
case 5:
$this->readable=true;
$this->executable=true;
break;
case 6:
$this->readable=true;
$this->writeable=true;
break;
case 7:
$this->readable=true;
$this->writable=true;
$this->executable=true;
break;
}
} else {
$this->executable=$this->readable=$this->writeable=true;
}
}
}
public function __destruct() {
if ($this->deleteOnExit) {
$this->delete();
}
}
/**
* @return boolean
* @desc Returns weather this file can be executed; Always true on Windows.
*/
public function canExecute() {
return $this->executeable;
}
/**
* @return boolean
* @desc Returns weather this file can be read; Always true on Windows.
*/
public function canRead() {
return $this->readable;
}
/**
* @return boolean
* @desc Returns weather this file can be written; Always true on Windows.
*/
public function canWrite() {
return $this->writable;
}
/**
* @return int
* @desc Compares the given file to this lexicographycally; Returns -1 if given less than this, 0 upon equal, 1 otherweise
* @param $f The File to compare to
*/
public function compareTo(File $f) {
$a=$this->path;
$b=$f->getAbsolutePath();
if (strlen($a)==strlen($b)) return 0;
if (strlen($a)<strlen($b)) {
$x=strlen($a);
$y=strlen($b);
for($i=$y-$x;$i<$y;$i++) {
$a[$x+$i]=chr(0);
}
} else if (strlen($b)<strlen($a)) {
$x=strlen($b);
$y=strlen($a);
for($i=$y-$x;$i<$y;$i++) {
$b[$x+$i]=chr(0);
}
}
$x=strlen($a);
for ($i=0;$i<$x;$i++) {
$c1=signedByteToUnsigned(ord($a[$i]));
$c2=signedByteToUnsigned(ord($b[$i]));
if ($c1==$c2) continue;
if ($c1>$c2) return -1;
if ($c1<$c2) return 1;
}
return 0;
}
/**
* @hidden
*/
private function signedByteToUnsigned($byte) {
if ($byte<0) {
return abs($byte)+128;
} else return $byte;
}
/**
* @desc Creates this file if it dosent already exist; Returns weather the file was created.
* @return boolean
* @throws IOException
*/
public function create() {
$this->createNewFile();
}
/**
* @desc Creates this file if it dosent already exist; Returns weather the file was created.
* @return boolean
*/
public function createNewFile() {
if ($this->exists()) {
return false;
}
@$fp=fopen($this->path, "w");
if (!$fp) {
throw new IOException("Could not create file.");
}
fclose($fp);
return true;
}
/**
* @descr Creates a temporary file. See class TemporaryFile.
* @return File
*/
public static function createTmpFile() {
return new TemporaryFile();
}
/**
@desc Deletes this file.
@return boolean
*/
public function delete() {
if (!$this->exists()) {
return false;
}
if ($this->isFile) {
$d=@unlink($this->path);
} else {
$d=@rmdir($this->path);
}
return $d;
}
/**
* @desc Once called, this file be deleted upon the end of the application
*/
public function deleteOnExit() {
$this->deleteOnExit=true;
}
/**
* @param -File/String $obj The file to compare to
* @desc Compares the paths of this and the given file
* @return boolean
*/
public function equals($obj) {
if ($obj instanceof File) {
return $this->path==$obj->getAbsolutePath();
} else if (is_string($obj)) {
return $this->path==$obj;
} else return false;
}
/**
* @desc Checks, weather this file exists
* @return boolean
*/
public function exists() {
return file_exists($this->path);
}
public function getAbsoluteFile() {
return $this;
}
public function getAbsolutePath() {
return $this->path;
}
public function getCanonicalFile() {
return $this;
}
public function getCanonicalPath() {
return $this->path;
}
/**
* @desc Returns the free disk space of the partition this file is stored in/pointing on.
* @return long
*/
public function getFreeSpace() {
return disk_free_space($this->path);
}
/**
* @desc Returns this Files name; e.g "/var/foo.txt" as path would return "foo.txt"
* @return String
*/
public function getName() {
return $this->filename;
}
/**
* @return String
* @desc Returns the parent directory if this file
*/
public function getParent() {
if ($this->isFile) {
return dirname($this->path);
} else {
$path=dirname($this->path);
if ($pos=strpos($path, File::FILE_SEPARATOR)===false) return null;
return substr($path, 0, $pos-1);
}
}
/**
* @return File
* @desc Returns the parent directory if this file
*/
public function getParentFile() {
$path=$this->getParent();
if ($path==null) return null;
return new File($path);
}
/**
* @desc Returns the space usable in the partition, this file is stored in/pointing on
* @return long
*/
public function getUsableSpace() {
return disk_free_space($this->path);
}
/**
* @return long
* @desc Returns the total space of the physical drive this file is stored on/pointing at
*/
public function getTotalSpace() {
return disk_total_space($this->path);
}
/**
* @return boolean
* @desc Always true
*/
public function isAbsolute() {
return true;
}
/**
* @return boolean
* @desc Returns weather this file is a directory
*/
public function isDirectory() {
return !$this->isFile;
}
/**
* @return boolean
* @desc Returns weather this file is a File
*/
public function isFile() {
return $this->isFile;
}
/**
* @return boolean
* @desc Returns weather this file is hidden; always true on Windows
*/
public function isHidden() {
if (substr(PHP_OS, 0, 3)=="WIN") {
return false;
} else {
return substr($this->filename, 0, 1)==".";
}
}
/**
* @return int
* @desc Returns the timestamp this file was last modified
*/
public function lastModified() {
return filemtime($this->path);
}
/**
* @return int
* @desc Returns this files size in bytes and 0 if it doesnt exist
*/
public function length() {
if (!$this->exists()) return 0;
return filesize($this->path);
}
/**
* @return String[]
* @desc Lists all files on this directory (including . and ..) and optionally using the filter to sort out.
* @param $filter The filter to use
* @throws IOException
*/
public function _list(FilenameFilter $filter=null) {
if ($this->isFile) {
throw new IOException("This File is not a directory");
}
@$dir=opendir($this->path);
if (!$dir) {
throw new IOException("Failed to open directory for reading");
}
$ar=array();
while ($file=readdir($dir)) {
if ($filter!=null) {
if ($filter->accept($this, $file)) {
$ar[]=$file;
}
} else {
$ar[]=$file;
}
}
@closedir($dir);
return $ar;
}
/**
* @return File[]
* @desc Lists all files on this directory (including . and ..) and optionally using the filter to sort out.
* @param -FileFilter/FilenamFilter $filter The filter to use
*/
public function listFiles($filter=null) {
if (!$filter instanceof FilenameFilter && !$filter instanceof FileFilter) {
throw new IOException("Illegal argument");
}
$ar=$this->_list();
$ar2=array();
foreach ($ar as $name) {
if ($filter!=null && $filter instanceof FilenameFilter) {
if (!$filter->accept($name)) {
continue;
}
}
$path=$this->path.$name;
$f=new File($path);
if ($filter!=null && $filter instanceof FileFilter) {
if (!$filter->accept($name)) {
continue;
}
}
$ar2[]=$f;
}
return $ar2;
}
/**
* @return File[]
* @desc In Windows: returns the drive this file is stored on; In Linux: Returns / and everything found in /media/
* @throws IOException
*/
public static function listRoots() {
if (substr(PHP_OS, 0, 3)=="WIN") {
return array(new File(substr(__FILE__, 0, 3)));
} else {
$roots=array(new File("/"));
@$dir=opendir("/media/");
if (!$dir) {
throw new IOException("Unable to open /media/; ".$php_errormsg);
}
while ($file=readdir($dir)) {
if ($file!="." && $file!="..") {
if (!is_file("/media/".$file)) {
$roots[]=new File("/media/", $file);
}
}
}
}
}
/**
* @return boolean
* @desc Creates this directory
*/
public function mkdir() {
$d=@mkdir($this->path);
return $d;
}
/**
* @return boolean
* @desc Creates this directory and all parental directories that dont exist
*/
public function mkdirs() {
$d=@mkdirs($this->path);
return $d;
}
/**
* @return boolean
* @desc Renames this file to the given one; May also move the file if the directories are different
*/
public function renameTo(File $target) {
@$r=rename($this->path, $name->getAbsolutePath());
if (!$r) {
throw new IOException("Unable to rename; ".$php_errormsg);
}
return $r;
}
/**
* @return octal Int
* @desc Creates the octal integer of this right-setup
* @param -boolean $read
* @param -boolean $write
* @param -boolean $exec
*/
public static function makePerms($read, $write, $exec) {
if (!$read && !$write && !$exec) {
return 0;
}
if (!$read && !$write && $exec) {
return 1;
}
if (!$read && $write && !$exec) {
return 2;
}
if ($read && !$write && $exec) {
return 3;
}
if ($read && !$write && !$exec) {
return 4;
}
if ($read && !$write && $exec) {
return 5;
}
if ($read && $write && !$exec) {
return 6;
}
if ($read && $write && $exec) {
return 7;
}
}
/**
* @return boolean[]
* @desc Returns the 3 permission-groups for this right-byte
* @param -octal_Int $int
*/
public static function getPerms($int) {
$exec=false;
$write=false;
$read=true;
switch ($int) {
case 1:
$exec=true;
break;
case 2:
$write=true;
break;
case 3:
$write=true;
$read=false;
break;
case 4:
$read=true;
break;
case 5:
$read=true;
$exec=true;
break;
case 6:
$read=true;
$write=true;
break;
case 7:
$read=true;
$write=true;
$exec=true;
break;
}
return array($read, $write, $exec);
}
/*
$right:
0 : read
1 : write
2 : execute
*/
/**
* @hidden
*/
private function setRight($right, $allowed, $ownerOnly=false) {
if (substr(PHP_OS, 0, 3)!="WIN" && !$this->isFileOwner) {
throw new IOException("Only the file owner (PHP is ran by ".$_ENV["USER"].") can change this");
}
if (!$this->exists()) {
throw new IOException("File not found");
}
if ($right<0 || $right>2) {
throw new Exception("Illegal argument \$right");
}
$rights="".fileperms($this->path);
$user_r=(int) substr($rights, 0, 1);
$group_r=(int) substr($rights, 1, 1);
$public_r=(int) substr($rights, 2, 1);
if ($ownerOnly) {
$rights=File::getPerms($user_r);
$rights[$right]=true;
$rights=(int) ("0".File::makePerms($rights[0], $rights[1], $rights[2])."".$group_r.$public_r);
chmod($this->path, $rights);
} else {
$rights=File::getPerms($user_r);
$rights[$right]=true;
$user_r=File::makePerms($rights[0], $rights[1], $rights[2]);
$rights=File::getPerms($group_r);
$rights[$right]=true;
$group_r=File::makePerms($rights[0], $rights[1], $rights[2]);
$rights=File::getPerms($public_r);
$rights[$right]=true;
$public_r=File::makePerms($rights[0], $rights[1], $rights[2]);
$rights=(int) ("0".$user_r.$group_r.$public_r);
chmod($this->path, $rights);
}
}
/**
* @desc Trys to set the execute-permission for this file
* @throws IOException
* @param -boolean $exec
* @param -boolean $owner If false, everyone will be able to execute this file
*/
public function setExecutable($exec, $owner=true) {
$this->setRight(2, $exec, $owner);
}
/**
* @desc Trys to set the write-permission for this file
* @throws IOException
* @param -boolean $write
* @param -boolean $owner If false, everyone will be able to write to this file
*/
public function setWritable($write, $owner=true) {
$this->setRight(1, $write, $owner);
}
/**
* @desc Trys to set the read-permission for this file
* @throws IOException
* @param -boolean $read
* @param -boolean $owner If false, everyone will be able to read this file
*/
public function setReadable($read, $owner=true) {
$this->setRight(0, $read, $owner);
}
/**
* @desc Trys to deny writing and executing for everyone
* @throws IOException
*/
public function setReadOnly() {
$this->setRight(2, false, false);
$this->setRight(1, false, false);
}
public function __toString() {
return $this->path;
}
}
/**
* @author Tobias Marstaller
* @desc Provides a simple interface to read raw bytes from a php-handle
*/
class RawInputStream implements InputStream {
protected $handle;
protected $available=false;
// PHP ftell() doesnt work properly
protected $pos=0;
protected $marker=0;
protected $streamMetaData;
public function __construct($handle) {
if (!$handle) {
throw new IOException("Invalid resource");
}
$this->handle=$handle;
@$this->streamMetaData=stream_get_meta_data($handle);
@$this->fullSize=filesize($this->streamMetaData["uri"]);
if ($this->fullSize!=0) {
$this->available=true;
}
}
public function read(array &$byte_array=null, $off=0, $len=0) {
if ($byte_array==null) {
return ord($this->readChar());
} else {
if ($len==0) $len=count($byte_array);
$target=$off+$len;
for (;$off<$target;$off++) {
$byte_array[$off]=ord($this->readChar());
}
}
}
public function readChar() {
@$char=fread($this->handle, 1);
if ($char===false) {
$this->available=false;
if (feof($this->handle)) {
return null;
} else {
throw new IOException("Unable to read from file; ".$php_errormsg);
}
}
$this->pos++;
return $char;
}
public function skip($long) {
if (!$this->streamMetaData["seekable"]) {
throw new IOException("This stream does not suppoer seek.");
}
$pos=$this->pos+=$long;
if ($pos>$this->fullSize) {
$skipped=$pos-$this->fullSize;
$pos=$this->pos+$skipped;
} else {
$skipped=$long;
}
@$seek=fseek($this->handle, $pos);
if (!$seek) {
throw new IOException("Failed to seek; Maybe not supported by this handle.");
}
$this->pos=$pos;
return $skipped;
}
public function available() {
return feof($this->handle);
}
public function markSupported() {
return $this->streamMetaData["seekable"];
}
public function markSeekable() {
return $this->streamMetaData["seekable"];
}
public function mark() {
if (!$this->streamMetaData["seekable"]) {
throw new IOException("Mark/Seek is not supported by this stream");
}
$this->marker=$this->pos;
}
public function reset() {
if (!$this->streamMetaData["seekable"]) {
throw new IOException("Mark/Seek is not supported by this stream");
}
$seek=fseek($this->handle, $this->marker);
if (!$seek) {
throw new IOException("Failed to seek; ".$php_errormsg);
}
$this->pos=$this->marker;
}
public function rewind() {
if (!$this->streamMetaData["seekable"]) {
throw new IOException("Seek is not supported by this stream");
}
$seek=fseek($this->handle, 0);
if (!$seek) {
throw new IOException("Failed to seek; ".$php_errormsg);
}
$this->pos=0;
}
}
/**
* @author Tobias Marstaller
* @desc Provides a simple interface to write raw bytes to a php-handle
*/
class RawOutputStream implements OutputStream {
protected $handle;
protected $closed=false;
/**
* @param -resource $r The stream to write to
* @param -boolean $append Weather to append all contents
*/
public function __construct($r) {
$this->handle=$r;
}
/**
* @desc Closes this stream; Temporary files will be deleted
* @throws IOException
*/
public function close() {
if ($this->closed()) {
throw new IOException("Stream already closed.");
}
@$c=fclose($this->handle);
$this->closed=true;
if (!$c) {
throw new IOException("Unable to close stream; ".$php_errormsg);
}
}
/**
* @desc writes the byte(s) $b to the stream
* @param -Byte/Byte[] $b
* @param -int $off Where in the array to start reading
* @param -int $len How much bytes to be read from the array
* @throws IOException
*/
public function write($b, $off=0, $len=0) {
if (is_double($b) || is_float($b)) {
$b=(int) round($b);
}
if (is_int($b)) {
if ($b<-128 || $b>257)
throw new IOException("Byte out of range.");
fwrite($this->handle, chr($b));
} else if (is_string($b)) {
if ($len==0)
$len=strlen($b);
$j=$len+$off;
for ($i=$off;$i<$j;$i++) {
$this->write(ord($b[$i]));
}
} else if (is_array($b)) {
if ($len==0)
$len=count($b);
$j=$len+$off;
for ($i=$off;$i<$j;$i++) {
$this->write($b[$i]);
}
}
}
protected function appendToBuffer(array $b) {
foreach($b as $byte) {
$this->buffer[]=$byte;
}
}
}
/**
* @author Tobias Marstaller
*/
interface InputStream {
/**
* @desc Read $len bytes from the stream and write them to $byte_array at the offset $off
* @param -int $off
* @param -int $len
* @throws IOException
*/
public function read(array &$byte_array=null, $off=0, $len=0);
/**
* @desc Skips the given amount of bytes in the stream. Returns the amount of bytes acutally skipped
* @param -long $bytes
* @return long
* @throws IOException
*/
public function skip($bytes);
/**
* @return boolean
* @desc Returns weather there is data available to be read or not
*/
public function available();
/**
* @return boolean
*/
public function markSupported();
/**
* @desc Marks a position in this stream
* @throws IOException
*/
public function mark();
/**
* @desc Sets the reading-position to the point marked with mark();
* @throws IOException
*/
public function reset();
}
/**
* @desc Provides the option to read characters from bytestreams using different charsets
* @author Tobias Marstaller
*/
class InputStreamReader implements Closable {
/**
* @param -int $maker The marked position in the underlaying stream
* @param -InputStream $stream The underlaying stream
* @param -Charset $charset The used charset
* @param -array $buffer
* @param -int $eof_offset The approximated distance to EOF
* @param -int $buffer_pos The current reading-position in the buffer
* @param -boolean $closed Weather this stream is closed
*/
private $marker;
private $stream;
private $charset;
private $buffer;
private $eof_offset=-1;
private $buffer_pos;
private $closed=false;
public function __construct(InputStream $source, Charset $charset=null) {
$this->stream=$source;
if ($charset==null)
$charset=new UTF8Charset();
$this->charset=$charset;
}
public function close() {
if ($this->closed)
throw new IOException("This stream has already been closed");
if ($this->stream instanceof Closable) {
$this->stream->close();
$this->buffer=null;
$this->closed=true;
}
}
public function read(array &$ar=null, $off=0, $len=0) {
if ($this->closed)
throw new IOException("This stream has been closed");
if ($this->buffer_pos==$this->eof_offset)
return null;
if ($this->buffer_pos==$this->charset->decodeBufferSize || $this->buffer==null) {
$this->buffer_pos=0;
$this->fillBuffer();
}
if ($ar!=null) {
if ($len==0)
$len=count($ar);
for ($off--;$off<$len;$off++) {
$ar[$off]=$this->read();
}
} else
return $this->buffer[$this->buffer_pos++];
}
/**
* @hidden
*/
private function fillBuffer() {
$ar=array();
for ($i=0;$i<$this->charset->decodeBufferSize;$i++) {
$x=$this->stream->read();
if ($x==null) {
$this->eof_offset=$this->charset->decodeBufferSize-$i;
for (;$i<$this->charset->decodeBufferSize;$i++) $ar[]=0;
break;
}
$ar[]=$x;
}
$this->buffer=$this->charset->decodeChars($ar);
}
}
/**
* @author Tobias Marstaller
* @desc Provides the option to read raw bytes from a file
*/
class FileInputStream extends RawInputStream implements InputStream, Closable {
protected $closed=false;
public function __construct($f) {
if (is_string($f)) {
$f=new File($f);
} else if (!$f instanceof File) {
throw new IOException("Illegal argument");
}
if (!$f->exists()) {
throw new IOException("File not found");
}
if ($f instanceof TemporaryFile) {
$handle=$f->getHandle();
} else {
if (substr(PHP_OS, 0, 3)=="WIN") {
@$handle=fopen($f->getAbsolutePath(), "rb");
} else {
@$handle=fopen($f->getAbsolutePath(), "r");
}
}
parent::__construct($handle);
}
public function close() {
if ($this->closed)
throw new IOException("This stream has already been closed.");
$this->closed=true;
@$c=fclose($this->handle);
$this->handle=null;
if (!$c) {
throw new IOException("Failed to close the stream;".$php_errormsg);
}
}
}
/**
* @author Tobias Marstaller
* @desc Buffers a php-native stream for performance increasements
*/
class BufferedReader implements Closable, InputStream {
private $stream;
private $bufferSize;
private $bufferPos;
private $localBufferMax=null;
private $buffer=array();
private $closed=false;
private $marker=0;
/**
* @param -int bufferSize Size of the buffer
*/
public function __construct($stream, $bufferSize=1024) {
$this->stream=$stream;
for ($i=0;$i<$bufferSize;$i++) {
$this->buffer[$i]=null;
}
$this->bufferSize=$bufferSize;
$this->bufferPos=0;
$this->fillBuffer();
}
public static function forFile(File $f, $bufferSize=1024) {
if (substr(PHP_OS, 0, 3)=="WIN") {
@$handle=fopen($f->getAbsolutePath(), "rb");
} else {
@$handle=fopen($f->getAbsolutePath(), "r");
}
return new BufferedReader($handle, $bufferSize);
}
/**
* @desc Fills the buffer
*/
private function fillBuffer() {
if ($this->closed)
throw new IOException("Stream closed.");
$str=fread($this->stream, $this->bufferSize);
if ($str===false) {
throw new IOException("Unable to fill buffer: ".$php_errmsg);
}
$length=strlen($str);
if ($length!=$this->bufferSize)
$this->localBufferMax=$length;
else $this->localBufferMax=null;
for ($i=0;$i<$length;$i++) {
$this->buffer[$i]=$str[$i];
}
for ($i=$this->bufferSize-$length;$i<$this->bufferSize;$i++) {
$this->buffer[$i]=null;
}
$this->bufferPos=0;
}
/**
* @param -int $off Offset in $ar to begin writing at
* @param -int $len Number of bytes to read to $ar
*/
public function read(array &$ar=null, $off=0, $len=null) {
if ($this->closed)
throw new IOException("Stream closed.");
if ($ar==null) {
if ($this->localBufferMax===null)
if ($this->bufferPos==$this->bufferSize-1) {
$this->fillBuffer();
}
else if ($this->bufferPos==$this->localBufferMax-1)
$this->fillBuffer();
return $this->buffer[$this->bufferPos++];
} else {
if ($len==null) $len=count($ar);
for (;$off<$len;$off++) {
$ar[$off]=$this->read();
}
}
}
/**
* @desc Skips the given amount of bytes in the stream. Returns the amount of bytes acutally skipped
* @param -long $bytes
* @return long
*/
public function skip($length) {
if ($this->closed)
throw new IOException("Stream closed.");
$max=$this->localBufferMax===null ? $this->bufferSize : $this->localBufferMax;
if ($length<$max) {
$this->bufferPos+=$length;
} else if ($length==$max) {
$this->fillBuffer();
} else {
$actual_skip=$length-$max;
fseek($this->stream, ftell($this->stream)+$actual_skip);
$this->fillBuffer();
}
}
/**
* @return boolean
* @desc Returns weather there is data available to be read or not
*/
public function available() {
if ($this->closed)
throw new IOException("Stream closed.");
if ($this->localBufferMax===null)
if ($this->bufferPos==$this->bufferSize-1) {
$this->fillBuffer();
}
else if ($this->bufferPos==$this->localBufferMax-1)
$this->fillBuffer();
return !$this->buffer[$this->bufferPos]===null;
}
/**
* @return boolean
*/
public function markSupported() {
return true;
}
/**
* @desc Marks a position in this stream
*/
public function mark() {
if ($this->closed)
throw new IOException("Stream closed.");
$this->marker=ftell($this->stream);
}
/**
* @desc Sets the reading-position to the point marked with mark();
*/
public function reset() {
if ($this->closed)
throw new IOException("Stream closed.");
fseek($this->stream, $this->marker);
$this->fillBuffer();
}
public function close() {
if ($this->closed)
throw new IOException("Stream closed.");
fclose($this->stream);
$this->closed=true;
$this->buffer=null;
}
}
/**
* @author Tobias Marstaller
*/
interface OutputStream {
/**
* @param -array/byte $bytes
* @param -int $off The offset to start at in the array $b
* @param -int $len How many bytes to read from $b
*/
public function write($bytes, $off=0, $len=0);
}
/**
* @author Tobias Marstaller
* @desc Provides the option to read complex data such as nested arrays and objects from a stream
*/
class DataInputStream extends RawInputStream implements Closable {
private $stream;
public function __construct(InputStream $s) {
$this->stream=$s;
}
public function __destruct() {
$this->close();
}
public function readObject() {
$size=BigEndian::readInt32($this->stream);
$obj=array();
for ($i=0;$i<$size;$i++) {
$b=$this->stream->read();
if (is_int($b)) $b=chr($b);
$obj[]=$b;
}
return unserialize(implode("", $obj));
}
public function close() {
$this->stream->close();
}
}
/**
* @author Tobias Marstaller
* @desc Provides the option to write complex data such as nested arrays and objects to a stream
*/
class DataOutputStream extends RawOutputStream implements Closable {
private $stream;
public function __construct(OutputStream $s) {
$this->stream=$s;
}
public function __destruct() {
$this->close();
}
public function writeObject($obj) {
$obj=serialize($obj);
$size=strlen($obj);
$this->stream->write(BigEndian::writeInt32($size));
$this->stream->write($obj);
}
public function write($b, $len=0, $off=0) {
if (is_array($b)) {
if ($len==0)
$len=count($b);
$j=$len+$off;
for ($i=$off;$i<$j;$i++) {
$this->writeObject($b[$i]);
}
} else {
$this->writeObject($b);
}
}
public function close() {
$this->stream->close();
}
}
/**
* @author Tobias Marstaller
* @desc Provides the option to write raw bytes to a file
*/
class FileOutputStream extends RawOutputStream implements OutputStream, Closable {
private $streamMetaData;
protected $closed=false;
/*
FileOutputStream(File $f);
FileOutputStream(TemporaryFile $f);
FileOutputStream(File $f, boolean $append);
FileOutputStream(TemporaryFile $f, boolean $append);
FileOutputStream(String $URI);
FileOutputStream(String $URI, boolean $apppend);
* @param -String/(Temporary)File $file The file/URI to write to
* @param -boolean $append Weather to append all contents
*/
public function __construct($file, $append=false) {
if (is_string($file)) {
$file=new File($file);
} else if (!$file instanceof File) {
throw new IOException("Illegal argument \$file");
}
if ($file->isDirectory()) {
throw new IOException("Given file is a directory");
}
if (!$file->exists()) {
$file->create();
}
if ($file instanceof TemporaryFile) {
$this->handle=$file->getHandle();
} else {
if ($append) {
$this->handle=fopen($file->getAbsolutePath(), "a");
} else {
if (substr(PHP_OS, 0, 3)=="WIN")
$this->handle=fopen($file->getAbsolutePath(), "w");
else
$this->handle=fopen($file->getAbsolutePath(), "w+");
}
}
$this->streamMetaData=stream_get_meta_data($this->handle);
if ($append && $file instanceof TemporaryFile)
fseek($this->handle, $this->streamMetaData["size"]);
}
public function close() {
if ($this->closed)
throw new IOException("This stream has already been closed.");
$this->closed=true;
@$c=fclose($this->handle);
$this->handle=null;
if (!$c) {
throw new IOException("Failed to close the stream;".$php_errormsg);
}
}
}
class EncryptedInputStream extends RawInputStream implements InputStream, Closable {
const DES=MCRYPT_DES;
const BLOWFISH=MCRYPT_BLOWFISH;
const GOST=MCRYPT_GOST;
const THREEWAY=MCRYPT_THREEWAY;
const WAKE=MCRYPT_WAKE;
const XTEA=MCRYPT_XTEA;
const SKIPJACK=MCRYPT_SKIPJACK;
const MODE_ECB="ecb";
const MODE_CBC="cbc";
const MODE_CFB="cfb";
const MODE_OFB="ofb";
const MODE_STREAM="stream";
private $cipher;
private $mode;
private $key;
private $iv;
private $stream;
private $readBufferSize;
private $storedBufferSize;
private $currentBufferPos=0;
private $buffer=array();
public static function createIV($algo, $mode) {
$iv_size=mcrypt_get_iv_size($algo, $mode);
return mcrypt_create_iv($iv_size, MCRYPT_RAND);
}
public function __construct(OutputStream $stream, $algo, $mode, $key, $iv=null, $bufferSize=32) {
$this->stream=$stream;
switch ($algo) {
default:
throw new CryptoException($algo, $mode, "Unknown algorithm");
case MCRYPT_DES: case MCRYPT_BLOWFISH: case MCRYPT_GOST: case MCRYPT_THREEWAY:
case MCRYPT_WAKE: case MCRYPT_XTEA: case MCRYPT_SKIPJACK:
$this->cipher=$algo;
}
switch ($mode) {
default:
throw new CryptoException($algo, $mode, "Unknwon mode");
case "ecb": case MCRYPT_MODE_ECB:
case "cbc": case MCRYPT_MODE_CBC:
case "cfb": case MCRYPT_MODE_CFB:
case "ofb": case MCRYPT_MODE_OFB:
case "stream": case MCRYPT_MODE_STREAM:
$this->mode=$mode;
}
$this->key=$key;
if ($iv==null) $iv=self::createIV($algo, $mode);
$this->iv=$iv;
$this->bufferSize=$bufferSize;
}
public function getIV() {
return $this->iv;
}
public function getAlgorithmUsed() {
return $this->cipher;
}
public function getMode() {
return $this->mode;
}
public function close() {
$this->key=null;
$this->iv=null;
$this->buffer=null;
$this->stream->close();
}
private function refillBuffer() {
$this->buffer=array();
$this->currentBufferPos=0;
for ($i=0;$i<$this->readBufferSize;$i++) {
$this->buffer[$i]=chr($this->stream->read());
}
$data=implode("", $this->buffer);
@$data=mcrypt_decrypt($this->cipher, $this->key, $data, $this->mode, $this->iv);
if ($data=="") {
throw new CryptoException($this->cipher, $this->mode, "Failed to decrypt: ".$php_errmsg);
}
$this->storedBufferSize=strlen($data);
for ($i=0;$i<$this->storedBufferSize;$i++) {
$this->buffer[$i]=$data[$i];
}
}
private function appendToBuffer($char) {
if ($this->currentBufferPos==$this->bufferSize) {
$this->flush();
}
$this->buffer[$this->currentBufferPos++]=$char;
}
public function read(array &$ar=null, $len=null, $off=0) {
if ($ar!=null) {
if (is_array($ar)) {
$j=$len+$off;
for ($i=$off;$i<$j;$i++) {
$ar[$i]=$this->read();
}
} else {
throw new IOException("Unsupported data-type ".gettype($char)."; Use DataOutputStream for this");
}
} else {
if ($this->currentBufferPos==$this->storedBufferSize) {
$this->refillBuffer();
}
return $this->buffer[$this->currentBufferPos++];
}
}
}
class EncryptedOutputStream implements OutputStream, Closable, Flushable {
const DES=MCRYPT_DES;
const BLOWFISH=MCRYPT_BLOWFISH;
const GOST=MCRYPT_GOST;
const THREEWAY=MCRYPT_THREEWAY;
const WAKE=MCRYPT_WAKE;
const XTEA=MCRYPT_XTEA;
const SKIPJACK=MCRYPT_SKIPJACK;
const MODE_ECB="ecb";
const MODE_CBC="cbc";
const MODE_CFB="cfb";
const MODE_OFB="ofb";
const MODE_STREAM="stream";
private $cipher;
private $mode;
private $key;
private $iv;
private $stream;
private $bufferSize;
private $currentBufferPos=0;
private $buffer=array();
public static function createIV($algo, $mode) {
$iv_size=mcrypt_get_iv_size($algo, $mode);
return mcrypt_create_iv($iv_size, MCRYPT_RAND);
}
public function __construct(OutputStream $stream, $algo, $mode, $key, $iv=null, $bufferSize=32) {
$this->stream=$stream;
switch ($algo) {
default:
throw new CryptoException($algo, $mode, "Unknown algorithm");
case MCRYPT_DES: case MCRYPT_BLOWFISH: case MCRYPT_GOST: case MCRYPT_THREEWAY:
case MCRYPT_WAKE: case MCRYPT_XTEA: case MCRYPT_SKIPJACK:
$this->cipher=$algo;
}
switch ($mode) {
default:
throw new CryptoException($algo, $mode, "Unknwon mode");
case "ecb": case MCRYPT_MODE_ECB:
case "cbc": case MCRYPT_MODE_CBC:
case "cfb": case MCRYPT_MODE_CFB:
case "ofb": case MCRYPT_MODE_OFB:
case "stream": case MCRYPT_MODE_STREAM:
$this->mode=$mode;
}
$this->key=$key;
if ($iv==null) $iv=self::createIV($algo, $mode);
$this->iv=$iv;
$this->bufferSize=$bufferSize;
}
public function getIV() {
return $this->iv;
}
public function getAlgorithmUsed() {
return $this->cipher;
}
public function getMode() {
return $this->mode;
}
public function close() {
$this->key=null;
$this->iv=null;
$this->buffer=null;
$this->stream->close();
}
private function resetBuffer() {
$this->buffer=array();
$this->currentBufferPos=0;
}
public function flush() {
$buffer=array_slice($this->buffer, 0, $this->currentBufferPos);
$data=implode("", $buffer);
@$data=mcrypt_encrypt($this->cipher, $this->key, $data, $this->mode, $this->iv);
if ($data=="") {
throw new CryptoException($this->cipher, $this->mode, "Failed to encrypt: ".$php_errmsg);
}
$j=strlen($data);
for ($i=0;$i<$j;$i++) {
$this->stream->write($data[$i]);
}
$this->resetBuffer();
}
private function appendToBuffer($char) {
if ($this->currentBufferPos==$this->bufferSize) {
$this->flush();
}
$this->buffer[$this->currentBufferPos++]=$char;
}
public function write($char, $len=null, $off=null) {
if ($off==null) $off=0;
if (is_string($char)) {
if (strlen($char)==1)
$this->appendToBuffer($char);
else {
if ($len==null) $len=strlen($char);
$j=$len+$off;
for ($i=$off;$i<$j;$i++) {
$this->appendToBuffer($char[$i]);
}
}
} elseif (is_int($char)) {
$this->appendToBuffer(chr($char));
} elseif (is_array($char)) {
$j=$len+$off;
for ($i=$off;$i<$j;$i++) {
$this->appendToBuffer($char[$i]);
}
} else {
throw new IOException("Unsupported data-type ".gettype($char)."; Use DataOutputStream for this");
}
}
public function setBufferSize($newsize) {
if ($newsize<$this->currentBufferPos) {
$this->flush();
}
$this->bufferSize=$newsize;
}
}
class CryptoException extends IOException {
protected $message;
public function __construct($algo, $mode, $message) {
$msg="";
switch ($algo) {
case MCRYPT_DES:
$msg="(DES;";
break;
case MCRYPT_BLOWFISH:
$msg="(Blowfish;";
break;
case MCRYPT_GOST:
$msg="(Gost;";
break;
case MCRYPT_THREEWAY:
$msg="(Threeway;";
break;
case MCRYPT_WAKE:
$msg="(Wake;";
break;
case MCRYPT_XTEA:
$msg="(XTEA;";
break;
case MCRYPT_SKIPJACK:
$msg="(Skipjack;";
break;
default:
if (is_string($algo))
$msg="(".$algo.";";
else
$msg="(unknwon;";
}
switch ($mode) {
case "ecb": case MCRYPT_MODE_ECB:
$msg.="ECB)";
break;
case "cbc": case MCRYPT_MODE_CBC:
$msg.="CBC)";
break;
case "cfb": case MCRYPT_MODE_CFB:
$msg.="CFB)";
break;
case "ofb": case MCRYPT_MODE_OFB:
$msg.="OFB)";
break;
case "stream": case MCRYPT_MODE_STREAM:
$msg.="STREAM)";
break;
default:
if (is_string($algo))
$msg.=$algo.")";
else
$msg.="unknwon)";
}
$this->message=$msg." ".$message;
}
}
/**
* @author Tobias Marstaller
* @desc Provides the option to write characters to a stream
*/
class PrintWriter implements Closable, Flushable {
/**
* @param -OutputStream $stream The stream the formatted bytes are written to
*/
private $stream;
/**
* @param -boolean $auto_flush Weather the buffer should be flushed immideiately
*/
private $auto_flush;
/**
* @param $buffer Contains chars
*/
protected $buffer=array();
/**
* @param -String/File/OutputStream $object If its a string, a file is constructed from it. If its a file, a stream is constructed from it.
* @param -boolean $autoflush Weather this stream should be immediately flushed
*/
public function __construct($object, $autoflush=true) {
if (is_string($object))
$object=new File($object);
if ($object instanceof File) {
if (!$object->exists()) {
throw new IOException("File not found.");
}
$object=new FileOutputStream($object);
}
if (!$object instanceof OutputStream) {
$object=new RawOutputStream($object);
}
if (!is_bool($autoflush))
throw new IOException("Illegal argument \$autoflush.");
$this->auto_flush=$autoflush;
$this->stream=$object;
}
/**
* @desc Closes the underlying stream without flushing it
*/
public function close() {
if ($this->stream instanceof Closable) {
$this->stream->close();
} else {
throw new IOException("This stream does not support closing.");
}
}
/**
* @desc Flushes the buffer (if filled) to the stream
*/
public function flush() {
$b=$this->buffer;
$this->buffer=array();
foreach ($b as $byte) {
if (!is_string($byte))
$byte=chr($byte);
$this->stream->write($byte);
}
}
/**
* @desc Writes a byte to the stream
* @param -byte $obj
*/
private function write($obj) {
if ($this->auto_flush)
$this->stream->write(chr($obj));
else {
$this->buffer[]=$obj;
if ($obj=='\n')
$this->flush();
}
}
/**
* @desc Writes a character/string to the underlaying stream
*/
public function _print($o) {
if ($o===true || $o===false)
$this->_print($o ? 'true' : 'false');
else if (is_string($o) || is_array($o)) {
if (is_string($o))
$j=strlen($o);
else
$j=count($o);
for ($i=0;$i<$j;$i++) {
$this->write(ord($o[$i]));
}
} else if (is_int($o) || is_long($o) || is_double($o)) {
$this->_print("".$o);
} else if (is_object($o)) {
if (method_exists($o, "__toString")) {
$this->_print($o->__toString());
} else
throw new IOException("Unable to convert instanceof ".get_class($o)." to string.");
} else {
throw new IOException("Illegal argument \$o.");
}
if ($this->auto_flush)
$this->flush();
}
/**
* @desc Writes a character/string to the underlaying stream and appends a new line
*/
public function println($obj=null) {
if ($obj!==null) {
$this->_print($obj);
}
$this->_print("\n");
}
}
/**
* @author Tobias Marstaller
* @desc Creates a Socket to the given computer/port and provides stream-interfaces.
*/
class Socket implements Closable {
/**
* @param -resourcce $handle The PHP-Socket
* @param -RawInputStream $in_stream A RawInputStream constructed from $handle
* @param -RawOutputStream $out_stream A RawOutputStream constructed from $handle
* @param -boolean $closed Weather this socket is closed
* @param -String $url The URI this Socket is connected to
* @param -int $port This sockets target port
*/
private $handle;
private $in_stream;
private $out_stream;
private $closed=true;
private $url;
private $port;
/**
* @param -String $URL The url/ip to connect to
* @param -int $port The target port to connect to
* @param -int $timeout The sockets connection timeout in milliseconds
*/
public function __construct($URL, $port, $timeout=-1) {
if ($port<0 || $port>65535)
throw new IOException("Invalid port number");
if ($timeout==-1)
$timeout=ini_get("default_socket_timeout");
$this->url=$URL;
$this->port=$port;
$error="";
$errnr=-1;
try {
$this->handle=fsockopen($URL, $port, $errnr, $error, $timeout);
if (!$this->handle) {
throw new IOException("(".$errnr.") ".$error);
}
$this->closed=false;
} catch (Exception $ex) {
throw new IOException("Invalid domain name");
}
}
public function __destruct() {
if (!$this->closed)
$this->close();
}
/**
* @desc Returns an InputStream to read information from
* @return InputStream
*/
public function getInputStream() {
if ($this->closed)
throw new IOException("Socket closed");
if ($this->in_stream==null)
$this->in_stream=new RawInputStream($this->handle);
return $this->in_stream;
}
/**
* @desc Returns an OutputSteam to write inforation to
* @return OutputStream
*/
public function getOutputStream() {
if ($this->closed)
throw new IOException("Socket closed");
if ($this->out_stream==null)
$this->out_stream=new RawOutputStream($this->handle);
return $this->out_stream;
}
/**
* @desc Closes this socket
*/
public function close() {
if ($this->closed)
throw new IOException("Socket closed");
$this->closed=true;
fclose($this->handle);
}
/**
* @desc Returns the port this socket is connected to
* @return int
*/
public function getPort() {
return $this->port;
}
/**
* @desc Returns the URI/IP this socket is connected to
* @return String
*/
public function getURI() {
return $this->url;
}
/**
* @return boolean;
*/
public function isConnected() {
return !$this->closed;
}
/**
* @desc E.g.: php.io.Socket[www.google.com:80]:connected or php.io.Socket[127.0.0.1:4185]:disconnected
*/
public function __toString() {
$str="php.io.Socket[".$this->url
.":".$this->port."]:";
if ($this->closed)
$str.="dis";
return $str."connected";
}
}
abstract class Charset {
public $decodeBufferSize=0;
public $encodeBufferSize=0;
/*
@desc Decodes the given bytes
@var -Array $buffer Array to decode; count($buffer) must be $instance->bufferSize
@return String
*/
public function decodeChars(array $buffer) {
if (count($buffer)!=$this->bufferSize)
throw new IOException("Illegal buffer size.");
return "";
}
public function encodeChar($char) {
return array(ord($char));
}
public function getName() {
return "CorruptInstance!";
}
public static function getInstance($encoding, $BOM=null) {
switch ($encoding) {
default:
throw new IOException("Invalid encoding given (".$encoding.")");
case "UTF-8":
return new UTF8Charset();
case "UTF-16BE":
return new UTF16BECharset();
case "UTF-16LE":
return new UTF16LECharset();
case "UTF-16":
if ($BOM===null)
throw new IOException("Byte order mark argument missing.");
return new UTF16Charset($BOM);
case "ASCII-7":
case "ISO646-US":
return new ASCII7Charset();
}
}
}
class UTF8Charset extends Charset {
public $encodeBufferSize=1;
public $decodeBufferSize=1;
public function decodeChars(array $buffer) {
return array(chr($buffer[0]));
}
public function encodeChars(array $chars) {
foreach ($chars as $key=>$char) {
$chars[$key]=ord($char);
}
return $chars;
}
public function getName() {
return "UTF-8";
}
}
class ASCII7Charset extends Charset {
public $decodeBufferSize=7;
public $encodeBufferSize=8;
public function decodeChars(array $bytes) {
if (count($bytes)!=7)
throw new IOException("Invalid input size.");
$bits="";
for ($i=0;$i<7;$i++) {
$str=decbin($bytes[$i]);
$append=strlen($str)-7;
if ($append>0) {
$str=str_repeat('0', $append).$str;
$bits.=$str;
}
$bits.=$str;
}
$ar=array();
for ($i=0;$i<8;$i++) {
$byte=substr($bits, $i*7, 7);
$ar[]=chr(bindec($byte));
}
return $ar;
}
public function encodeChars($bytes) {
if (is_array($bytes))
$bytes=implode("", $bytes);
if (!is_string($bytes))
throw new IOException("Invalid argument.");
$bits="";
for ($i=0;$i<8;$i++) {
$str=decbin(ord($bytes[$i]));
$append=strlen($str)-6;
if ($append>0) {
$str=str_repeat('0', $append).$str;
}
$bits.=$str;
}
$ar=array();
for ($i=0;$i<7;$i++) {
$byte=substr($bits, $i*8, 8);
$byte=substr($byte, 1);
$ar[]=bindec($byte);
}
return $ar;
}
}
?>
|