diff --git a/README.md b/README.md index 82cec28..a5e785a 100644 --- a/README.md +++ b/README.md @@ -32,32 +32,32 @@ var_dump($cab->getFileData('README.md')); ## CabArchive API All list of properties and methods of `CabArchive` is listed below. -- **$filesCount** - number of files in Cab-archive -- **__construct($filename)** - creates new instance from file, stream or socket -- **getCabHeader()** - returns header of Cab-archive as array -- **hasPreviousCab()** - checks that this cab has previous Cab in set -- **getPreviousCab()** - returns name of previous Cab -- **hasNextCab()** - checks that this cab has next Cab in set -- **getNextCab()** - returns name of next Cab -- **getSetId()** - returns set id (identical for all cab-archives from one set) -- **getInSetNumber()** - returns number of cab in set -- **getFileNames(): array** - retrives list of files from archive -- **getFileData($filename): object** - returns additional info of file as object. -- **getFileAttributes($filename): array** - returns list of file attributes. All available attributes: - - **CabArchive::ATTRIB_READONLY** - - **CabArchive::ATTRIB_HIDDEN** - - **CabArchive::ATTRIB_SYSTEM** - - **CabArchive::ATTRIB_EXEC** -- **getFileContent($filename): string** - returns raw content of file. -- **extract($output, array $nodes = [])** - _in development now_ - -### getFileNames() +- `$filesCount` - number of files in Cab-archive +- `__construct($filename)` - creates new instance from file, stream or socket +- `getCabHeader()` - returns header of Cab-archive as array +- `hasPreviousCab()` - checks that this cab has previous Cab in set +- `getPreviousCab()` - returns name of previous Cab +- `hasNextCab()` - checks that this cab has next Cab in set +- `getNextCab()` - returns name of next Cab +- `getSetId()` - returns set id (identical for all cab-archives from one set) +- `getInSetNumber()` - returns number of cab in set +- `getFileNames(): array` - retrives list of files from archive +- `getFileData($filename): object` - returns additional info of file as object. +- `getFileAttributes($filename): array` - returns list of file attributes. All available attributes: + - `CabArchive::ATTRIB_READONLY` + - `CabArchive::ATTRIB_HIDDEN` + - `CabArchive::ATTRIB_SYSTEM` + - `CabArchive::ATTRIB_EXEC` +- `getFileContent($filename): string` - returns raw content of file. +- `extract($output, array $files = []): bool|int` - _in development now_ + +### getFileNames ```php array getFileNames() ``` This method returns an array of file names compressed in cab. -### getFileData($filename) +### getFileData ```php object getFileData($filename) ``` @@ -68,11 +68,26 @@ This method returns an object with following fields: - **unixtime** - date&time of modification in unixtime format - **isCompressed** - is file compressed as _boolean_ -### getFileContent($filename) +### getFileContent ```php string getFileContent($filename) ``` -This method returns raw file content of `$filename`. Supports extracting from cab's without compression and with MSZip compression. LZX compression is not supported. +This method returns raw file content of `$filename`. +Supports extracting from cab's without compression and with MSZip compression. LZX compression is not supported. + +Works correctly only on PHP: + +- 7.0.22+ +- 7.1.8+ +- 7.2.0 + +### extract($outputDirectory, array $files = []) +```php +int|bool extract($outputDirectory, array $files = []) +``` +This method extracts passed files or the whole cab to `$outputDirectory`. + +Supports extracting from cab's without compression and with MSZip compression. LZX compression is not supported. Works correctly only on PHP: diff --git a/bin/cabfile b/bin/cabfile index 6cefadb..f8aec84 100755 --- a/bin/cabfile +++ b/bin/cabfile @@ -10,7 +10,8 @@ if (!isset($argv[1])) die('Usage: '.basename(__FILE__).' [] [-- .' - blocks - show all blocks within cab'.PHP_EOL .' - files - show files list within cab'.PHP_EOL .' - [filename] - show information about files within cab'.PHP_EOL - .' If you set --content option, it will print content of the file'.PHP_EOL); + .' If you set --content option, it will print content of the file'.PHP_EOL + .' If you set --extract option, it will extract file in current folder'.PHP_EOL); $width = TerminalInfo::isInteractive() ? (TerminalInfo::getWidth() - 30) : 50; @@ -46,5 +47,7 @@ switch ($mode) { var_dump($cab->getFileData($mode)); if (in_array('--content', $argv)) var_dump($cab->getFileContent($mode)); + else if (in_array('--extract', $argv)) + var_dump($cab->extract(getcwd(), [$mode])); break; } diff --git a/src/CabArchive.php b/src/CabArchive.php index 4c367b0..31d439a 100644 --- a/src/CabArchive.php +++ b/src/CabArchive.php @@ -24,6 +24,11 @@ class CabArchive { public $foldersCount = -1; public $blocksCount = -1; + /** + * CabArchive constructor. + * @param $filename + * @throws Exception + */ public function __construct($filename) { $this->filename = $filename; $this->stream = new BinaryStream($filename); @@ -32,6 +37,9 @@ public function __construct($filename) { $this->open(); } + /** + * + */ protected function setupReader() { $this->stream->saveGroup('header', [ 's:signature' => 4, @@ -65,6 +73,9 @@ protected function setupReader() { ]); } + /** + * @throws Exception + */ protected function open() { if (!$this->stream->compare(4, 'MSCF')) throw new Exception('This is not a cab-file'); @@ -142,42 +153,72 @@ protected function open() { } } + /** + * @return mixed + */ public function getCabHeader() { return $this->header; } + /** + * @return int + */ public function hasPreviousCab() { return $this->header['flags'] & 0x1; } + /** + * @return mixed + */ public function getPreviousCab() { return $this->header['cab_previous']; } + /** + * @return int + */ public function hasNextCab() { return $this->header['flags'] & 0x2; } + /** + * @return mixed + */ public function getNextCab() { return $this->header['cab_next']; } + /** + * @return mixed + */ public function getSetId() { return $this->header['setId']; } + /** + * @return mixed + */ public function getInSetNumber() { return $this->header['inSetNumber']; } + /** + * @return array + */ public function getCabFolders() { return $this->folders; } + /** + * @return array + */ public function getCabBlocks() { return $this->blocks; } + /** + * @return array + */ public function getFileNames() { $files = array(); foreach ($this->files as $file) { @@ -186,6 +227,10 @@ public function getFileNames() { return $files; } + /** + * @param $filename + * @return bool|object + */ public function getFileData($filename) { foreach ($this->files as $file) { if ($file['name'] == $filename) { @@ -214,7 +259,7 @@ public function getFileData($filename) { /** * List of attributes of file. * @param string $filename Name of stored file - * @return array An array that may containing following values: CabArchive::ATTRIB_READONLY, CabArchive::ATTRIB_HIDDEN, CabArchive::ATTRIB_SYSTEM, CabArchive::ATTRIB_EXEC + * @return array|bool An array that may containing following values: CabArchive::ATTRIB_READONLY, CabArchive::ATTRIB_HIDDEN, CabArchive::ATTRIB_SYSTEM, CabArchive::ATTRIB_EXEC */ public function getFileAttributes($filename) { foreach ($this->files as $file) { @@ -233,6 +278,7 @@ public function getFileAttributes($filename) { * Gets content of the file * @param string $filename Name of stored file * @return string|boolean Content of the file. False, if decompression is not supported. + * @throws Exception */ public function getFileContent($filename) { foreach ($this->files as $file) { @@ -272,8 +318,35 @@ public function getFileContent($filename) { return $content; } + /** + * Extracts file or files to specific folder + * @param $outputFolder + * @param array $files + * @return bool|int + * @throws Exception + */ + public function extract($outputFolder, $files = array()) + { + $extracted = 0; + $outputFolder = realpath($outputFolder); + + if (empty($files)) $files = $this->files; + + foreach ($files as $file) { + if (file_put_contents($outputFolder.'/'.$file, $this->getFileContent($file)) === false) + return false; + $extracted++; + } + + return $extracted; + } + /** * Returns list of block ids in which file stored + * @param $folderId + * @param $fileOffset + * @param $fileSize + * @return array */ protected function detectBlocksOfFile($folderId, $fileOffset, $fileSize) { $fileEnd = $fileOffset + $fileSize; @@ -293,6 +366,9 @@ protected function detectBlocksOfFile($folderId, $fileOffset, $fileSize) { /** * Decompresses folder with MS-ZIP compression + * @param $folderId + * @return bool + * @throws Exception */ protected function decompressMsZipFolder($folderId) { if (isset($this->foldersRaw[$folderId])) @@ -324,6 +400,9 @@ protected function decompressMsZipFolder($folderId) { /** * Decompresses folder with LZX compression. Not supported now + * @param $folderId + * @return bool + * @throws Exception */ protected function decompressLzxFolder($folderId) { if (isset($this->foldersRaw[$folderId])) @@ -333,6 +412,8 @@ protected function decompressLzxFolder($folderId) { /** * Reads folder without compression + * @param $folderId + * @return bool */ protected function readFolder($folderId) { if (isset($this->foldersRaw[$folderId])) @@ -359,6 +440,9 @@ protected function readNullTerminatedString() { /** * Calculates how B intersect with A + * @param array $rangeA + * @param array $rangeB + * @return float|int */ protected function calculateRangesIntersection(array $rangeA, array $rangeB) { $intersection = 100; diff --git a/src/TerminalInfo.php b/src/TerminalInfo.php index 9fd75d0..3a4fef7 100644 --- a/src/TerminalInfo.php +++ b/src/TerminalInfo.php @@ -4,6 +4,10 @@ class TerminalInfo { const WIDTH = 1; const HEIGHT = 2; + + /** + * @return bool + */ static public function isInteractive() { if (strncasecmp(PHP_OS, 'win', 3) === 0) { // windows has no test for that @@ -18,6 +22,9 @@ static public function isInteractive() { } } + /** + * @return string + */ static public function getWidth() { if (strncasecmp(PHP_OS, 'win', 3) === 0) { return self::getWindowsTerminalSize(self::WIDTH); @@ -26,6 +33,9 @@ static public function getWidth() { } } + /** + * @return string + */ static public function getHeight() { if (strncasecmp(PHP_OS, 'win', 3) === 0) { return self::getWindowsTerminalSize(self::HEIGHT); @@ -34,12 +44,20 @@ static public function getHeight() { } } + /** + * @param $param + * @return string + */ static protected function getWindowsTerminalSize($param) { - $output = explode("\n", shell_exec('mode')); + $output = explode("\n", shell_exec('mode con')); $line = explode(':', trim($param == self::WIDTH ? $output[4] : $output[3])); return trim($line[1]); } + /** + * @param $param + * @return string + */ static protected function getUnixTerminalSize($param) { return trim(shell_exec('tput '.($param == self::WIDTH ? 'cols' : 'linus'))); }