├── .gitignore ├── LICENSE ├── README.md ├── RarArchiver.php ├── composer.json └── example.php /.gitignore: -------------------------------------------------------------------------------- 1 | .vs 2 | .vs/* 3 | ./vendor 4 | .vsphpignore 5 | *.intellisense.cache 6 | *.phpproj 7 | *.sln 8 | *.puo 9 | php.ini -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | RarArchiver 2 | 3 | Copyright (c) 2015, Dmitry Mamontov . 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions 8 | are met: 9 | 10 | * Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in 15 | the documentation and/or other materials provided with the 16 | distribution. 17 | 18 | * Neither the name of Dmitry Mamontov nor the names of his 19 | contributors may be used to endorse or promote products derived 20 | from this software without specific prior written permission. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 | POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Latest Stable Version](https://poser.pugx.org/dmamontov/rararchiver/v/stable.svg)](https://packagist.org/packages/dmamontov/rararchiver) 2 | [![License](https://poser.pugx.org/dmamontov/rararchiver/license.svg)](https://packagist.org/packages/dmamontov/rararchiver) 3 | 4 | # In the process version 2.0. 5 | 6 | RarArchiver 7 | =========== 8 | 9 | Class for working with archives RAR. It allows you to add files to the directory, as well as extract, delete, rename, and get content. 10 | 11 | 12 | ## Requirements 13 | * PHP version ~5.5.11 14 | 15 | ## Installation 16 | 17 | 1) Install [composer](https://getcomposer.org/download/) 18 | 19 | 2) Follow in the project folder: 20 | ```bash 21 | composer require dmamontov/rararchiver ~1.0.0 22 | ``` 23 | 24 | In config `composer.json` your project will be added to the library `dmamontov/rararchiver`, who settled in the folder `vendor/`. In the absence of a config file or folder with vendors they will be created. 25 | 26 | If before your project is not used `composer`, connect the startup file vendors. To do this, enter the code in the project: 27 | ```php 28 | require 'path/to/vendor/autoload.php'; 29 | ``` 30 | 31 | ## Available methods 32 | 33 | ### RarArchiver::__construct 34 | 35 | #### Description 36 | ```php 37 | void RarArchiver::__construct ( string $file [, $flag = 0] ) 38 | ``` 39 | It creates or opens a file and initializes it. 40 | 41 | #### Parameters 42 | * `file` - The path to archive. 43 | * `flag` - An optional parameter. 44 | * `RarArchiver::CREATE` - It creates the archive if it is not found. 45 | * `RarArchiver::REPLACE` - Overwrites the archive if it is found, otherwise create it. 46 | 47 | #### Examples 48 | ```php 49 | $rar = new RarArchiver('example.rar', RarArchiver::CREATE); 50 | ``` 51 | 52 | ### RarArchiver::isRar 53 | 54 | #### Description 55 | ```php 56 | boolean RarArchiver::isRar ( void ) 57 | ``` 58 | Checks whether the file archive RAR. 59 | 60 | #### Return Values 61 | Returns TRUE on success or FALSE on failure. 62 | 63 | #### Examples 64 | ```php 65 | $rar = new RarArchiver('example.rar', RarArchiver::CREATE); 66 | 67 | if ($rar->isRar()) { 68 | echo 'ok'; 69 | } else { 70 | echo 'failed'; 71 | } 72 | ``` 73 | 74 | ### RarArchiver::getFileList 75 | 76 | #### Description 77 | ```php 78 | array RarArchiver::getFileList ( void ) 79 | ``` 80 | Gets a list of files in the archive. 81 | 82 | #### Return Values 83 | Returns the filled array on success, or an empty array on failure. 84 | 85 | #### Examples 86 | ```php 87 | $rar = new RarArchiver('example.rar', RarArchiver::CREATE); 88 | 89 | if (count($rar->getFileList()) > 0) { 90 | echo 'ok'; 91 | } else { 92 | echo 'failed'; 93 | } 94 | ``` 95 | 96 | ### RarArchiver::addEmptyDir 97 | 98 | #### Description 99 | ```php 100 | boolean RarArchiver::addEmptyDir ( string $dirname ) 101 | ``` 102 | Adds an empty directory in the archive. 103 | 104 | #### Parameters 105 | * `dirname` - The directory to add. 106 | 107 | #### Return Values 108 | Returns TRUE on success or FALSE on failure. 109 | 110 | #### Examples 111 | ```php 112 | $rar = new RarArchiver('example.rar', RarArchiver::CREATE); 113 | 114 | if ($rar->addEmptyDir('newEmptyDirectory')) { 115 | echo 'Created a new root directory'; 116 | } else { 117 | echo 'Could not create the directory'; 118 | } 119 | ``` 120 | 121 | ### RarArchiver::addFile 122 | 123 | #### Description 124 | ```php 125 | boolean RarArchiver::addFile ( string $filename [, string $localname = ''] ) 126 | ``` 127 | Adds a file to a RAR archive from a given path. 128 | 129 | #### Parameters 130 | * `filename` - The path to the file to add. 131 | * `localname` - If supplied, this is the local name inside the RAR archive that will override the `filename`. 132 | 133 | #### Return Values 134 | Returns TRUE on success or FALSE on failure. 135 | 136 | #### Examples 137 | ```php 138 | $rar = new RarArchiver('example.rar', RarArchiver::CREATE); 139 | 140 | if ($rar->addFile('/path/to/index.txt', 'newname.txt')) { 141 | echo 'ok'; 142 | } else { 143 | echo 'failed'; 144 | } 145 | ``` 146 | 147 | ### RarArchiver::addFromString 148 | 149 | #### Description 150 | ```php 151 | boolean RarArchiver::addFromString ( string $localname , string $contents ) 152 | ``` 153 | Add a file to a RAR archive using its contents. 154 | 155 | #### Parameters 156 | * `localname` - The name of the entry to create. 157 | * `contents` - The contents to use to create the entry. 158 | 159 | #### Return Values 160 | Returns TRUE on success or FALSE on failure. 161 | 162 | #### Examples 163 | ```php 164 | $rar = new RarArchiver('example.rar', RarArchiver::CREATE); 165 | 166 | if ($rar->addFromString('newname.txt', 'file content goes here')) { 167 | echo 'ok'; 168 | } else { 169 | echo 'failed'; 170 | } 171 | ``` 172 | 173 | ### RarArchiver::buildFromDirectory 174 | 175 | #### Description 176 | ```php 177 | void RarArchiver::buildFromDirectory ( string $path [, string $regex ] ) 178 | ``` 179 | Populate a RAR archive from directory contents. The optional second parameter is a regular expression (pcre) that is used to exclude files. 180 | 181 | #### Parameters 182 | * `path` - The full or relative path to the directory that contains all files to add to the archive. 183 | * `regex` - An optional pcre regular expression that is used to filter the list of files. Only file paths matching the regular expression will be included in the archive. 184 | 185 | #### Examples 186 | ```php 187 | $rar = new RarArchiver('example.rar', RarArchiver::CREATE); 188 | 189 | $rar->buildFromDirectory(dirname(__FILE__) . '/project'); 190 | // or 191 | $rar->buildFromDirectory(dirname(__FILE__) . '/project', '/\.php$/'); 192 | ``` 193 | 194 | ### RarArchiver::deleteIndex 195 | 196 | #### Description 197 | ```php 198 | boolean RarArchiver::deleteIndex ( int $index ) 199 | ``` 200 | Delete an entry in the archive using its index. 201 | 202 | #### Parameters 203 | * `index` - Index of the entry to delete. 204 | 205 | #### Return Values 206 | Returns TRUE on success or FALSE on failure. 207 | 208 | #### Examples 209 | ```php 210 | $rar = new RarArchiver('example.rar', RarArchiver::CREATE); 211 | 212 | if ($rar->deleteIndex(2)) { 213 | echo 'ok'; 214 | } else { 215 | echo 'failed'; 216 | } 217 | ``` 218 | 219 | ### RarArchiver::deleteName 220 | 221 | #### Description 222 | ```php 223 | boolean RarArchiver::deleteName ( string $name ) 224 | ``` 225 | Delete an entry in the archive using its name. 226 | 227 | #### Parameters 228 | * `name` - Name of the entry to delete. 229 | 230 | #### Return Values 231 | Returns TRUE on success or FALSE on failure. 232 | 233 | #### Examples 234 | ```php 235 | $rar = new RarArchiver('example.rar', RarArchiver::CREATE); 236 | 237 | if ($rar->deleteName('testfromfile.php')) { 238 | echo 'ok'; 239 | } else { 240 | echo 'failed'; 241 | } 242 | ``` 243 | 244 | ### RarArchiver::getFromIndex 245 | 246 | #### Description 247 | ```php 248 | string RarArchiver::getFromIndex ( int $index [, int $length = 0] ) 249 | ``` 250 | Returns the entry contents using its index. 251 | 252 | #### Parameters 253 | * `index` - Index of the entry. 254 | * `length` - The length to be read from the entry. If 0, then the entire entry is read. 255 | 256 | #### Return Values 257 | Returns the contents of the entry on success or FALSE on failure. 258 | 259 | #### Examples 260 | ```php 261 | $rar = new RarArchiver('example.rar', RarArchiver::CREATE); 262 | 263 | $rar->getFromIndex(2); 264 | // or 265 | $rar->getFromIndex(2, 100); 266 | ``` 267 | 268 | ### RarArchiver::getFromName 269 | 270 | #### Description 271 | ```php 272 | string RarArchiver::getFromName ( string $name [, int $length = 0] ) 273 | ``` 274 | Returns the entry contents using its name. 275 | 276 | #### Parameters 277 | * `name` - Name of the entry. 278 | * `length` - The length to be read from the entry. If 0, then the entire entry is read. 279 | 280 | #### Return Values 281 | Returns the contents of the entry on success or FALSE on failure. 282 | 283 | #### Examples 284 | ```php 285 | $rar = new RarArchiver('example.rar', RarArchiver::CREATE); 286 | 287 | $rar->getFromName('testfromfile.php'); 288 | // or 289 | $rar->getFromIndex('testfromfile.php', 100); 290 | ``` 291 | 292 | ### RarArchiver::getNameIndex 293 | 294 | #### Description 295 | ```php 296 | string RarArchiver::getNameIndex ( int $index ) 297 | ``` 298 | Returns the name of an entry using its index. 299 | 300 | #### Parameters 301 | * `index` - Index of the entry. 302 | 303 | #### Return Values 304 | Returns the name on success or FALSE on failure. 305 | 306 | #### Examples 307 | ```php 308 | $rar = new RarArchiver('example.rar', RarArchiver::CREATE); 309 | 310 | $rar->getNameIndex(2); 311 | ``` 312 | 313 | ### RarArchiver::renameIndex 314 | 315 | #### Description 316 | ```php 317 | boolean RarArchiver::renameIndex ( int $index , string $newname ) 318 | ``` 319 | Renames an entry defined by its index. 320 | 321 | #### Parameters 322 | * `index` - Index of the entry to rename. 323 | * `newname` - New name. 324 | 325 | #### Return Values 326 | Returns TRUE on success or FALSE on failure. 327 | 328 | #### Examples 329 | ```php 330 | $rar = new RarArchiver('example.rar', RarArchiver::CREATE); 331 | 332 | if ($rar->renameIndex(2, 'newname.php')) { 333 | echo 'ok'; 334 | } else { 335 | echo 'failed'; 336 | } 337 | ``` 338 | 339 | ### RarArchiver::renameName 340 | 341 | #### Description 342 | ```php 343 | boolean RarArchiver::renameName ( string $name , string $newname ) 344 | ``` 345 | Renames an entry defined by its name. 346 | 347 | #### Parameters 348 | * `name` - Name of the entry to rename. 349 | * `newname` - New name. 350 | 351 | #### Return Values 352 | Returns TRUE on success or FALSE on failure. 353 | 354 | #### Examples 355 | ```php 356 | $rar = new RarArchiver('example.rar', RarArchiver::CREATE); 357 | 358 | if ($rar->renameName('testfromfile.php', 'newname.php')) { 359 | echo 'ok'; 360 | } else { 361 | echo 'failed'; 362 | } 363 | ``` 364 | 365 | ### RarArchiver::extractTo 366 | 367 | #### Description 368 | ```php 369 | boolean RarArchiver::extractTo ( string $destination [, mixed $entries ] ) 370 | ``` 371 | Extract the complete archive or the given files to the specified destination. 372 | 373 | #### Parameters 374 | * `destination` - Location where to extract the files. 375 | * `entries` - The entries to extract. It accepts either a single entry name or an array of names. 376 | 377 | #### Return Values 378 | Returns TRUE on success or FALSE on failure. 379 | 380 | #### Examples 381 | ```php 382 | $rar = new RarArchiver('example.rar', RarArchiver::CREATE); 383 | 384 | if ($rar->extractTo('/my/destination/dir/')) { 385 | echo 'ok'; 386 | } else { 387 | echo 'failed'; 388 | } 389 | ``` 390 | -------------------------------------------------------------------------------- /RarArchiver.php: -------------------------------------------------------------------------------- 1 | . 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 12 | * * Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 15 | * * Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in 17 | * the documentation and/or other materials provided with the 18 | * distribution. 19 | * 20 | * * Neither the name of Dmitry Mamontov nor the names of his 21 | * contributors may be used to endorse or promote products derived 22 | * from this software without specific prior written permission. 23 | * 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 27 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 28 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 29 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 34 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | * 37 | * @package rararchiver 38 | * @author Dmitry Mamontov 39 | * @copyright 2015 Dmitry Mamontov 40 | * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License 41 | * @since File available since Release 1.0.0 42 | */ 43 | 44 | /** 45 | * RarArchiver - Class to create an archive Rar. 46 | * 47 | * @author Dmitry Mamontov 48 | * @copyright 2015 Dmitry Mamontov 49 | * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License 50 | * @version Release: 1.0.0 51 | * @link https://github.com/dmamontov/rararchiver 52 | * @since Class available since Release 1.0.0 53 | */ 54 | class RarArchiver 55 | { 56 | /** 57 | * Creates a new archive 58 | */ 59 | const CREATE = 1; 60 | 61 | /** 62 | * Substitution archive 63 | */ 64 | const REPLACE = 2; 65 | 66 | /** 67 | * Reading archive 68 | */ 69 | const READING = 'a+b'; 70 | 71 | /** 72 | * Record archive 73 | */ 74 | const RECORD = 'w+b'; 75 | 76 | /** 77 | * The object created or opened file 78 | * @var SplFileObject 79 | * @access private 80 | */ 81 | private $fileObject = null; 82 | 83 | /** 84 | * The name of the archive 85 | * @var string 86 | * @access private 87 | */ 88 | private $filename = null; 89 | 90 | /** 91 | * Files and directories have been added to the archive 92 | * @var array 93 | * @access private 94 | */ 95 | private $tree = array(); 96 | 97 | /** 98 | * Opens the archive 99 | * @param string $file 100 | * @param integer $flag 101 | * @return boolean 102 | * @access public 103 | * @final 104 | */ 105 | final public function __construct($file, $flag = 0) 106 | { 107 | if (version_compare(PHP_VERSION, '5.5.11', '<')) { 108 | throw new RuntimeException('PHP version must be not lower than 5.5.11.'); 109 | } 110 | 111 | if (file_exists($file) == false && $flag != self::CREATE && $flag == self::REPLACE) { 112 | throw new RuntimeException('This archive is not in the specified path.'); 113 | } 114 | 115 | $mode = self::READING; 116 | if ((file_exists($file) == false && $flag == self::CREATE) || (file_exists($file) && $flag == self::REPLACE)) { 117 | $mode = self::RECORD; 118 | } 119 | 120 | $this->filename = $file; 121 | $this->fileObject = new SplFileObject($file, $mode); 122 | 123 | if ($this->fileObject === false) { 124 | throw new RuntimeException('Unable to open or create a file.'); 125 | } 126 | 127 | if ($mode == self::RECORD && ($flag == self::CREATE || $flag == self::REPLACE)) { 128 | $this->writeHeader(0x72, 0x1a21); 129 | $this->writeHeader(0x73, 0x0000, array(array(0, 2), array(0, 4))); 130 | } elseif ($this->isRar() == false) { 131 | throw new RuntimeException('The file is not an archive RAR.'); 132 | } else { 133 | $this->tree = $this->getFileList(); 134 | } 135 | 136 | unset($mode, $file, $flag); 137 | } 138 | 139 | /** 140 | * Closes the file 141 | * @access public 142 | * @final 143 | */ 144 | final public function __destruct() 145 | { 146 | unset($this->fileObject); 147 | } 148 | 149 | /** 150 | * Add files to the archive. 151 | * @param string $filename 152 | * @param string $localname 153 | * @return boolean 154 | * @access public 155 | * @final 156 | */ 157 | final public function addFile($filename, $localname = '') 158 | { 159 | $filename = str_replace('\\', '/', $filename); 160 | 161 | if (file_exists($filename) == false) { 162 | return false; 163 | } 164 | 165 | if (is_null($localname) || empty($localname)) { 166 | $localname = $filename; 167 | } 168 | 169 | $file = new SplFileObject($filename, 'r'); 170 | $size = $file->getSize(); 171 | if ($size > 0) { 172 | $contents = $file->fread($size); 173 | } 174 | 175 | unset($size, $file, $filename); 176 | 177 | return $this->addFromString($localname, $contents); 178 | } 179 | 180 | /** 181 | * Adding content to the archive file line. 182 | * @param string $localname 183 | * @param string $contents 184 | * @return boolean 185 | * @access public 186 | * @final 187 | */ 188 | final public function addFromString($localname, $contents) 189 | { 190 | if (is_null($localname) || empty($localname) || is_null($contents) || empty($contents)) { 191 | return false; 192 | } 193 | 194 | $localname = str_replace('\\', '/', $localname); 195 | 196 | $localname = $this->clearSeparator($localname); 197 | 198 | $dirname = explode('/', $localname); 199 | if (count($dirname) > 1) { 200 | array_pop($dirname); 201 | $this->addEmptyDir(implode('/', $dirname)); 202 | unset($dirname); 203 | } 204 | 205 | $localname = str_replace('/', "\\", $localname); 206 | 207 | $add = $this->writeHeader(0x74, $this->setBits(array(15)), array( 208 | array(strlen($contents), 4), 209 | array(strlen($contents), 4), 210 | array(0, 1), 211 | array(crc32($contents), 4), 212 | array($this->getDateTime(), 4), 213 | array(20, 1), 214 | array(0x30, 1), 215 | array(strlen($localname), 2), 216 | array(0x20, 4), 217 | $localname, 218 | )); 219 | 220 | if ($add == true) { 221 | $this->fileObject->fwrite($contents); 222 | } 223 | 224 | unset($contents, $add, $localname, $dirname); 225 | 226 | return true; 227 | } 228 | 229 | /** 230 | * Add files to the archive. 231 | * @param string $dirname 232 | * @return boolean 233 | * @access public 234 | * @final 235 | */ 236 | final public function addEmptyDir($dirname) 237 | { 238 | $dirname = str_replace('\\', '/', $dirname); 239 | 240 | if (is_null($dirname) || empty($dirname) || stripos($dirname, '/') === false) { 241 | return false; 242 | } 243 | 244 | $dirname = $this->clearSeparator($dirname); 245 | 246 | $parts = explode('/', $dirname); 247 | $dirname = ''; 248 | for ($i = 0; $i < count($parts); $i++) { 249 | $dirname .= $parts[$i] . "\\"; 250 | 251 | if (in_array($parts[$i], $this->tree) !== false) { 252 | continue; 253 | } 254 | 255 | $this->writeHeader(0x74, $this->setBits(array(5, 6, 7, 15)), array( 256 | array(0, 4), 257 | array(0, 4), 258 | array(0, 1), 259 | array(0, 4), 260 | array($this->getDateTime(), 4), 261 | array(20, 1), 262 | array(0x30, 1), 263 | array(strlen(substr($dirname, 0, -1)), 2), 264 | array(0x10, 4), 265 | substr($dirname, 0, -1), 266 | )); 267 | } 268 | 269 | unset($dirname, $parts); 270 | 271 | return true; 272 | } 273 | 274 | /** 275 | * Adds all files and folders in the archive 276 | * @param string $path 277 | * @param string $regex 278 | * @access public 279 | * @final 280 | */ 281 | final public function buildFromDirectory($path, $regex = null) 282 | { 283 | $path = str_replace('\\', '/', realpath($path)); 284 | $files = new RecursiveIteratorIterator( 285 | new RecursiveDirectoryIterator($path), 286 | RecursiveIteratorIterator::SELF_FIRST 287 | ); 288 | 289 | foreach ($files as $file) { 290 | if (is_null($regex) == false && empty($regex) == false && preg_match($regex, $file) == false) { 291 | continue; 292 | } 293 | 294 | $file = str_replace('\\', '/', $file); 295 | 296 | if (in_array(substr($file, strrpos($file, '/') + 1), array('.', '..'))) { 297 | continue; 298 | } 299 | 300 | $file = realpath($file); 301 | 302 | if (is_dir($file) === true) { 303 | $this->addEmptyDir(str_replace($path . '/', '', $file)); 304 | } elseif (is_file($file) === true) { 305 | $this->addFile($file, str_replace($path . '/', '', $file)); 306 | } 307 | } 308 | 309 | unset($path, $regex, $files); 310 | } 311 | 312 | /** 313 | * Writes block header in accordance with the format 314 | * @param mixed $path 315 | * @param mixed $flags 316 | * @param array $data 317 | * @return boolean 318 | * @access private 319 | * @final 320 | */ 321 | final private function writeHeader($type, $flags, $data = array()) 322 | { 323 | if (in_array($type, array(0x72, 0x73, 0x74)) == false) { 324 | return false; 325 | } 326 | 327 | if (in_array($type, array(0x72, 0x73)) === false && is_string(end($data)) && in_array(end($data), $this->tree)) { 328 | return false; 329 | } 330 | 331 | if (is_string(end($data))) { 332 | array_push($this->tree, end($data)); 333 | } 334 | 335 | $size = 7; 336 | foreach ($data as $key => $value) { 337 | $size += is_array($value) ? $value[1] : strlen($value); 338 | } 339 | 340 | $bytes = array_merge(array($type, array($flags, 2), array($size, 2)), $data); 341 | $header = ''; 342 | for ($i = 0; $i < count($bytes); $i++) { 343 | if (is_array($bytes[$i])) { 344 | $header .= $this->getBytes($bytes[$i][0], $bytes[$i][1]); 345 | } else { 346 | $header .= $this->getBytes($bytes[$i]); 347 | } 348 | } 349 | 350 | $header = ($type == 0x72 ? "Ra" : $this->getCRC($header)) . $header; 351 | 352 | $this->fileObject->fwrite($header); 353 | 354 | unset($header, $type, $bytes, $flags, $size, $data); 355 | 356 | return true; 357 | } 358 | 359 | /** 360 | * Checks whether the file archive 361 | * @return boolean 362 | * @access private 363 | * @final 364 | */ 365 | final public function isRar() 366 | { 367 | $this->fileObject->rewind(); 368 | $head = ''; 369 | if ($this->fileObject->getSize() > 0) { 370 | $head = $this->fileObject->fread(7); 371 | } 372 | $this->fileObject->fseek(-1, SEEK_END); 373 | 374 | return bin2hex($head) == '526172211a0700'; 375 | } 376 | 377 | /** 378 | * Getting a list of files in the archive 379 | * @return array 380 | * @access public 381 | * @final 382 | */ 383 | final public function getFileList() 384 | { 385 | if ($this->skipHead() == false) { 386 | return array(); 387 | } 388 | 389 | $skipFolder = true; 390 | $debug = debug_backtrace(); 391 | if (isset($debug[1]) && isset($debug[1]['class']) && $debug[1]['class'] == 'RarArchiver') { 392 | $skipFolder = false; 393 | } 394 | 395 | $index = 0; 396 | $files = array(); 397 | while ($this->fileObject->eof() === false) { 398 | $block = $this->fileObject->fread(7); 399 | $headSize = $this->getBytes($block, 5, 2); 400 | if ($headSize <= 7) { 401 | break; 402 | } 403 | 404 | $block .= $this->fileObject->fread($headSize - 7); 405 | if (ord($block[2]) == 0x74) { 406 | $this->fileObject->fseek($this->getBytes($block, 7, 4), SEEK_CUR); 407 | 408 | $attr = $this->getBytes($block, 28, 4); 409 | if (($attr & 0x10 || $attr & 0x4000) && $skipFolder) { 410 | $index++; 411 | continue; 412 | } 413 | 414 | $files[$index] = substr($block, 32, $this->getBytes($block, 26, 2)); 415 | } elseif ($this->getBytes($block, 3, 2) & 0x8000) { 416 | $this->fileObject->fseek($this->getBytes($block, 7, 4), SEEK_CUR); 417 | } 418 | 419 | $index++; 420 | } 421 | 422 | $this->fileObject->fseek(-1, SEEK_END); 423 | 424 | unset($skipFolder, $debug, $block, $headSize, $attr, $index); 425 | 426 | return $files; 427 | } 428 | 429 | /** 430 | * Extract the archive contents 431 | * @param string $destination 432 | * @param mixed $entries 433 | * @return boolean 434 | * @access public 435 | * @final 436 | */ 437 | final public function extractTo($destination, $entries = null) 438 | { 439 | if (is_null($destination) || empty($destination)) { 440 | $destination = 'tmp'; 441 | } 442 | 443 | if (file_exists($destination) == false) { 444 | @mkdir($destination); 445 | } 446 | 447 | if ($this->skipHead() == false) { 448 | return false; 449 | } 450 | 451 | while ($this->fileObject->eof() === false) { 452 | $block = $this->fileObject->fread(7); 453 | $headSize = $this->getBytes($block, 5, 2); 454 | if ($headSize <= 7) { 455 | break; 456 | } 457 | 458 | $block .= $this->fileObject->fread($headSize - 7); 459 | 460 | if (ord($block[2]) == 0x74) { 461 | $fileSize = $this->getBytes($block, 7, 4); 462 | $name = $destination . '/' .str_replace('\\', '/', substr($block, 32, $this->getBytes($block, 26, 2))); 463 | 464 | if ((is_string($entries) && $name != $entries) || (is_array($entries) && in_array($name, $entries) === false)) { 465 | continue; 466 | } 467 | 468 | $attr = $this->getBytes($block, 28, 4); 469 | if ($attr & 0x10 || $attr & 0x4000) { 470 | @mkdir($name); 471 | } else { 472 | $dirname = explode('/', $name); 473 | array_pop($dirname); 474 | if (count($dirname) > 0) { 475 | @mkdir(implode('/', $dirname)); 476 | } 477 | 478 | $newFile = new SplFileObject($name, self::RECORD); 479 | $newFile->fwrite($this->fileObject->fread($fileSize)); 480 | } 481 | } elseif ($this->getBytes($block, 3, 2) & 0x8000) { 482 | $this->fileObject->fseek($this->getBytes($block, 7, 4), SEEK_CUR); 483 | } 484 | } 485 | 486 | $this->fileObject->fseek(-1, SEEK_END); 487 | 488 | unset($destination, $entries, $block, $headSize, $fileSize, $name, $attr, $dirname, $newFile); 489 | 490 | return true; 491 | } 492 | 493 | /** 494 | * Returns the entry contents using its index 495 | * @param integer $index 496 | * @param integer $length 497 | * @return mixed 498 | * @access public 499 | * @final 500 | */ 501 | final public function getFromIndex($index, $length = 0) 502 | { 503 | if (array_key_exists($index, $this->tree) === false || $length < 0 || is_integer($index) == false) { 504 | return false; 505 | } 506 | 507 | if ($this->skipHead() == false) { 508 | return false; 509 | } 510 | 511 | $content = ''; 512 | $indexes = 0; 513 | while ($this->fileObject->eof() === false) { 514 | $block = $this->fileObject->fread(7); 515 | $headSize = $this->getBytes($block, 5, 2); 516 | if ($headSize <= 7) { 517 | break; 518 | } 519 | 520 | $block .= $this->fileObject->fread($headSize - 7); 521 | 522 | if (ord($block[2]) == 0x74) { 523 | $fileSize = $this->getBytes($block, 7, 4); 524 | 525 | $attr = $this->getBytes($block, 28, 4); 526 | if (($attr & 0x10) == false && ($attr & 0x4000) == false && $indexes == $index) { 527 | if ($length == 0) { 528 | $length = $fileSize; 529 | } 530 | $content = $this->fileObject->fread($length); 531 | break; 532 | } 533 | 534 | $this->fileObject->fseek($fileSize, SEEK_CUR); 535 | } elseif ($this->getBytes($block, 3, 2) & 0x8000) { 536 | $this->fileObject->fseek($this->getBytes($block, 7, 4), SEEK_CUR); 537 | } 538 | 539 | $indexes++; 540 | } 541 | 542 | $this->fileObject->fseek(-1, SEEK_END); 543 | 544 | unset($index, $length, $indexes, $block, $headSize, $fileSize, $attr); 545 | 546 | return empty($content) ? false : $content; 547 | } 548 | 549 | /** 550 | * Returns the name of an entry using its index 551 | * @param integer $index 552 | * @return mixed 553 | * @access public 554 | * @final 555 | */ 556 | final public function getNameIndex($index) 557 | { 558 | if (array_key_exists($index, $this->tree) === false || $length < 0 || is_integer($index) == false) { 559 | return false; 560 | } 561 | 562 | if ($this->skipHead() == false) { 563 | return false; 564 | } 565 | 566 | $name = ''; 567 | $indexes = 0; 568 | while ($this->fileObject->eof() === false) { 569 | $block = $this->fileObject->fread(7); 570 | $headSize = $this->getBytes($block, 5, 2); 571 | if ($headSize <= 7) { 572 | break; 573 | } 574 | 575 | $block .= $this->fileObject->fread($headSize - 7); 576 | 577 | if (ord($block[2]) == 0x74) { 578 | $fileSize = $this->getBytes($block, 7, 4); 579 | $filename = str_replace('\\', '/', substr($block, 32, $this->getBytes($block, 26, 2))); 580 | 581 | $attr = $this->getBytes($block, 28, 4); 582 | if (($attr & 0x10) == false && ($attr & 0x4000) == false && $indexes == $index) { 583 | $name = $filename; 584 | break; 585 | } 586 | 587 | $this->fileObject->fseek($fileSize, SEEK_CUR); 588 | } elseif ($this->getBytes($block, 3, 2) & 0x8000) { 589 | $this->fileObject->fseek($this->getBytes($block, 7, 4), SEEK_CUR); 590 | } 591 | 592 | $indexes++; 593 | } 594 | 595 | $this->fileObject->fseek(-1, SEEK_END); 596 | 597 | unset($index, $indexes, $block, $headSize, $fileSize, $attr, $filename); 598 | 599 | return empty($name) ? false : $name; 600 | } 601 | 602 | /** 603 | * Returns the entry contents using its name 604 | * @param string $name 605 | * @param integer $length 606 | * @return mixed 607 | * @access public 608 | * @final 609 | */ 610 | final public function getFromName($name, $length = 0) 611 | { 612 | if (in_array($name, $this->tree) === false || $length < 0 || is_string($name) == false) { 613 | return false; 614 | } 615 | 616 | if ($this->skipHead() == false) { 617 | return false; 618 | } 619 | 620 | $name = str_replace('\\', '/', $name); 621 | 622 | $content = ''; 623 | while ($this->fileObject->eof() === false) { 624 | $block = $this->fileObject->fread(7); 625 | $headSize = $this->getBytes($block, 5, 2); 626 | if ($headSize <= 7) { 627 | break; 628 | } 629 | 630 | $block .= $this->fileObject->fread($headSize - 7); 631 | 632 | if (ord($block[2]) == 0x74) { 633 | $fileSize = $this->getBytes($block, 7, 4); 634 | $filename = str_replace('\\', '/', substr($block, 32, $this->getBytes($block, 26, 2))); 635 | 636 | $attr = $this->getBytes($block, 28, 4); 637 | if (($attr & 0x10) == false && ($attr & 0x4000) == false && $filename == $name) { 638 | if ($length == 0) { 639 | $length = $fileSize; 640 | } 641 | $content = $this->fileObject->fread($length); 642 | break; 643 | } 644 | 645 | $this->fileObject->fseek($fileSize, SEEK_CUR); 646 | } elseif ($this->getBytes($block, 3, 2) & 0x8000) { 647 | $this->fileObject->fseek($this->getBytes($block, 7, 4), SEEK_CUR); 648 | } 649 | } 650 | 651 | $this->fileObject->fseek(-1, SEEK_END); 652 | 653 | unset($name, $length, $block, $headSize, $fileSize, $attr, $filename); 654 | 655 | return empty($content) ? false : $content; 656 | } 657 | 658 | /** 659 | * Renames an entry defined by its index 660 | * @param integer $index 661 | * @param string $newname 662 | * @return boolean 663 | * @access public 664 | * @final 665 | */ 666 | final public function renameIndex($index, $newname) 667 | { 668 | if (array_key_exists($index, $this->tree) === false || is_integer($index) == false || empty($newname) || $this->fileObject->getSize() < 0) { 669 | return false; 670 | } 671 | 672 | $newname = $this->clearSeparator($newname); 673 | 674 | $currentFileObject = $this->fileObject; 675 | $currentFileObject->rewind(); 676 | 677 | $this->fileObject = new SplFileObject("{$this->filename}.tmp", self::RECORD); 678 | 679 | $this->fileObject->fwrite($currentFileObject->fread(7)); 680 | 681 | $mainHead = $currentFileObject->fread(7); 682 | if (ord($mainHead[2]) != 0x73) { 683 | $currentFileObject->fseek(-1, SEEK_END); 684 | $this->fileObject = $currentFileObject; 685 | @unlink("{$this->filename}.tmp"); 686 | 687 | return false; 688 | } 689 | $this->fileObject->fwrite($mainHead); 690 | 691 | $headSize = $this->getBytes($mainHead, 5, 2); 692 | $this->fileObject->fwrite($currentFileObject->fread($headSize - 7)); 693 | 694 | $newname = str_replace('/', '\\', $newname); 695 | 696 | $indexes = 0; 697 | while ($currentFileObject->eof() === false) { 698 | $block = $currentFileObject->fread(7); 699 | $headSize = $this->getBytes($block, 5, 2); 700 | if ($headSize <= 7) { 701 | break; 702 | } 703 | 704 | $block .= $currentFileObject->fread($headSize - 7); 705 | 706 | if (ord($block[2]) == 0x74) { 707 | $fileSize = $this->getBytes($block, 7, 4); 708 | 709 | $attr = $this->getBytes($block, 28, 4); 710 | if ($attr & 0x10 || $attr & 0x4000) { 711 | $this->fileObject->fwrite($block); 712 | } elseif ($indexes == $index) { 713 | $this->addFromString($newname, $currentFileObject->fread($fileSize)); 714 | } else { 715 | $this->fileObject->fwrite($block); 716 | $this->fileObject->fwrite($currentFileObject->fread($fileSize)); 717 | } 718 | } elseif ($this->getBytes($block, 3, 2) & 0x8000) { 719 | $this->fileObject->fwrite($currentFileObject->fread($this->getBytes($block, 7, 4))); 720 | } 721 | 722 | $indexes++; 723 | } 724 | 725 | @unlink($this->filename); 726 | @rename("{$this->filename}.tmp", $this->filename); 727 | 728 | $this->fileObject = new SplFileObject($this->filename, self::READING); 729 | $this->tree = $this->getFileList(); 730 | 731 | unset($index, $newname, $currentFileObject, $mainHead, $headSize, $block, $fileSize, $indexes); 732 | 733 | return $this->isRar() ? true : false; 734 | } 735 | 736 | /** 737 | * Renames an entry defined by its name 738 | * @param string $name 739 | * @param string $newname 740 | * @return boolean 741 | * @access public 742 | * @final 743 | */ 744 | final public function renameName($name, $newname) 745 | { 746 | if (in_array($name, $this->tree) === false || empty($name) || empty($newname) || $this->fileObject->getSize() < 0) { 747 | return false; 748 | } 749 | 750 | $name = $this->clearSeparator($name); 751 | $newname = $this->clearSeparator($newname); 752 | 753 | $currentFileObject = $this->fileObject; 754 | $currentFileObject->rewind(); 755 | 756 | $this->fileObject = new SplFileObject("{$this->filename}.tmp", self::RECORD); 757 | 758 | $this->fileObject->fwrite($currentFileObject->fread(7)); 759 | 760 | $mainHead = $currentFileObject->fread(7); 761 | if (ord($mainHead[2]) != 0x73) { 762 | $currentFileObject->fseek(-1, SEEK_END); 763 | $this->fileObject = $currentFileObject; 764 | @unlink("{$this->filename}.tmp"); 765 | 766 | return false; 767 | } 768 | $this->fileObject->fwrite($mainHead); 769 | 770 | $headSize = $this->getBytes($mainHead, 5, 2); 771 | $this->fileObject->fwrite($currentFileObject->fread($headSize - 7)); 772 | 773 | $name = str_replace('/', '\\', $name); 774 | $newname = str_replace('/', '\\', $newname); 775 | 776 | while ($currentFileObject->eof() === false) { 777 | $block = $currentFileObject->fread(7); 778 | $headSize = $this->getBytes($block, 5, 2); 779 | if ($headSize <= 7) { 780 | break; 781 | } 782 | 783 | $block .= $currentFileObject->fread($headSize - 7); 784 | 785 | if (ord($block[2]) == 0x74) { 786 | $fileSize = $this->getBytes($block, 7, 4); 787 | $filename = str_replace('/', '\\', substr($block, 32, $this->getBytes($block, 26, 2))); 788 | 789 | $attr = $this->getBytes($block, 28, 4); 790 | if ($attr & 0x10 || $attr & 0x4000) { 791 | $this->fileObject->fwrite($block); 792 | } elseif ($filename == $name) { 793 | $this->addFromString($newname, $currentFileObject->fread($fileSize)); 794 | } else { 795 | $this->fileObject->fwrite($block); 796 | $this->fileObject->fwrite($currentFileObject->fread($fileSize)); 797 | } 798 | } elseif ($this->getBytes($block, 3, 2) & 0x8000) { 799 | $this->fileObject->fwrite($currentFileObject->fread($this->getBytes($block, 7, 4))); 800 | } 801 | } 802 | 803 | @unlink($this->filename); 804 | @rename("{$this->filename}.tmp", $this->filename); 805 | 806 | $this->fileObject = new SplFileObject($this->filename, self::READING); 807 | $this->tree = $this->getFileList(); 808 | 809 | unset($name, $newname, $filename, $currentFileObject, $mainHead, $headSize, $block, $fileSize); 810 | 811 | return $this->isRar() ? true : false; 812 | } 813 | 814 | /** 815 | * Delete an entry in the archive using its index 816 | * @param integer $index 817 | * @return boolean 818 | * @access public 819 | * @final 820 | */ 821 | final public function deleteIndex($index) 822 | { 823 | if (array_key_exists($index, $this->tree) === false || is_integer($index) == false || $this->fileObject->getSize() < 0) { 824 | return false; 825 | } 826 | 827 | $currentFileObject = $this->fileObject; 828 | $currentFileObject->rewind(); 829 | 830 | $this->fileObject = new SplFileObject("{$this->filename}.tmp", self::RECORD); 831 | 832 | $this->fileObject->fwrite($currentFileObject->fread(7)); 833 | 834 | $mainHead = $currentFileObject->fread(7); 835 | if (ord($mainHead[2]) != 0x73) { 836 | $currentFileObject->fseek(-1, SEEK_END); 837 | $this->fileObject = $currentFileObject; 838 | @unlink("{$this->filename}.tmp"); 839 | 840 | return false; 841 | } 842 | $this->fileObject->fwrite($mainHead); 843 | 844 | $headSize = $this->getBytes($mainHead, 5, 2); 845 | $this->fileObject->fwrite($currentFileObject->fread($headSize - 7)); 846 | 847 | $indexes = 0; 848 | while ($currentFileObject->eof() === false) { 849 | $block = $currentFileObject->fread(7); 850 | $headSize = $this->getBytes($block, 5, 2); 851 | if ($headSize <= 7) { 852 | break; 853 | } 854 | 855 | $block .= $currentFileObject->fread($headSize - 7); 856 | 857 | if (ord($block[2]) == 0x74) { 858 | $fileSize = $this->getBytes($block, 7, 4); 859 | 860 | if ($indexes != $index) { 861 | $attr = $this->getBytes($block, 28, 4); 862 | if ($attr & 0x10 || $attr & 0x4000) { 863 | $this->fileObject->fwrite($block); 864 | } else { 865 | $this->fileObject->fwrite($block); 866 | $this->fileObject->fwrite($currentFileObject->fread($fileSize)); 867 | } 868 | } 869 | } elseif ($this->getBytes($block, 3, 2) & 0x8000) { 870 | $this->fileObject->fwrite($currentFileObject->fread($this->getBytes($block, 7, 4))); 871 | } 872 | 873 | $indexes++; 874 | } 875 | 876 | @unlink($this->filename); 877 | @rename("{$this->filename}.tmp", $this->filename); 878 | 879 | $this->fileObject = new SplFileObject($this->filename, self::READING); 880 | 881 | unset($this->tree[$index], $index, $currentFileObject, $mainHead, $headSize, $block, $fileSize, $indexes); 882 | 883 | return $this->isRar() ? true : false; 884 | } 885 | 886 | /** 887 | * Delete an entry in the archive using its name 888 | * @param string $name 889 | * @return boolean 890 | * @access public 891 | * @final 892 | */ 893 | final public function deleteName($name) 894 | { 895 | if (in_array($name, $this->tree) === false || empty($name) || $this->fileObject->getSize() < 0) { 896 | return false; 897 | } 898 | 899 | $name = $this->clearSeparator($name); 900 | 901 | $currentFileObject = $this->fileObject; 902 | $currentFileObject->rewind(); 903 | 904 | $this->fileObject = new SplFileObject("{$this->filename}.tmp", self::RECORD); 905 | 906 | $this->fileObject->fwrite($currentFileObject->fread(7)); 907 | 908 | $mainHead = $currentFileObject->fread(7); 909 | if (ord($mainHead[2]) != 0x73) { 910 | $currentFileObject->fseek(-1, SEEK_END); 911 | $this->fileObject = $currentFileObject; 912 | @unlink("{$this->filename}.tmp"); 913 | 914 | return false; 915 | } 916 | $this->fileObject->fwrite($mainHead); 917 | 918 | $headSize = $this->getBytes($mainHead, 5, 2); 919 | $this->fileObject->fwrite($currentFileObject->fread($headSize - 7)); 920 | 921 | $name = str_replace('/', '\\', $name); 922 | 923 | while ($currentFileObject->eof() === false) { 924 | $block = $currentFileObject->fread(7); 925 | $headSize = $this->getBytes($block, 5, 2); 926 | if ($headSize <= 7) { 927 | break; 928 | } 929 | 930 | $block .= $currentFileObject->fread($headSize - 7); 931 | 932 | if (ord($block[2]) == 0x74) { 933 | $fileSize = $this->getBytes($block, 7, 4); 934 | $filename = str_replace('/', '\\', substr($block, 32, $this->getBytes($block, 26, 2))); 935 | 936 | if ($name != $filename) { 937 | $attr = $this->getBytes($block, 28, 4); 938 | if ($attr & 0x10 || $attr & 0x4000) { 939 | $this->fileObject->fwrite($block); 940 | } else { 941 | $this->fileObject->fwrite($block); 942 | $this->fileObject->fwrite($currentFileObject->fread($fileSize)); 943 | } 944 | } 945 | } elseif ($this->getBytes($block, 3, 2) & 0x8000) { 946 | $this->fileObject->fwrite($currentFileObject->fread($this->getBytes($block, 7, 4))); 947 | } 948 | } 949 | 950 | @unlink($this->filename); 951 | @rename("{$this->filename}.tmp", $this->filename); 952 | 953 | $this->fileObject = new SplFileObject($this->filename, self::READING); 954 | if ($index = array_search($name, $this->tree)) { 955 | unset($this->tree[$index]); 956 | } 957 | 958 | unset($name, $filename, $currentFileObject, $mainHead, $headSize, $block, $fileSize, $index); 959 | 960 | return $this->isRar() ? true : false; 961 | } 962 | 963 | /** 964 | * It skips the file headers 965 | * @return boolean 966 | * @access private 967 | * @final 968 | */ 969 | final private function skipHead() 970 | { 971 | if ($this->fileObject->getSize() < 0) { 972 | return false; 973 | } 974 | 975 | $this->fileObject->rewind(); 976 | $this->fileObject->fseek(7, SEEK_CUR); 977 | 978 | $mainHead = $this->fileObject->fread(7); 979 | if (ord($mainHead[2]) != 0x73) { 980 | return false; 981 | } 982 | 983 | $headSize = $this->getBytes($mainHead, 5, 2); 984 | $this->fileObject->fseek($headSize - 7, SEEK_CUR); 985 | 986 | unset($mainHead, $headSize); 987 | 988 | return true; 989 | } 990 | 991 | /** 992 | * The calculation of CRC for the header block 993 | * @param string $string 994 | * @return string 995 | * @access private 996 | * @final 997 | */ 998 | final private function getCRC($string) 999 | { 1000 | $crc = crc32($string); 1001 | 1002 | return chr($crc & 0xFF) . chr(($crc >> 8) & 0xFF); 1003 | } 1004 | 1005 | /** 1006 | * Writing data in the reverse order 1007 | * @param string $data 1008 | * @param integer $bytes 1009 | * @param integer $count 1010 | * @return string 1011 | * @access private 1012 | * @final 1013 | */ 1014 | final private function getBytes($data, $bytes = 0, $count = 0) 1015 | { 1016 | $result = ""; 1017 | 1018 | if ($count > 0 && $bytes != false) { 1019 | $result = strrev(substr($data, $bytes, $count)); 1020 | 1021 | return hexdec(bin2hex($result)); 1022 | } 1023 | 1024 | if ($bytes == false) { 1025 | $bytes = strlen($bytes); 1026 | } 1027 | 1028 | if (is_numeric($data)) { 1029 | $data = sprintf("%0" . ($bytes * 2) . "x", $data); 1030 | for ($i = 0; $i < strlen($data); $i += 2) { 1031 | $result = chr(hexdec(substr($data, $i, 2))) . $result; 1032 | } 1033 | } else { 1034 | $result = $data; 1035 | } 1036 | 1037 | unset($data, $bytes, $count); 1038 | 1039 | return $result; 1040 | } 1041 | 1042 | /** 1043 | * Setting the appropriate bits in the number 1044 | * @param mixed $bits 1045 | * @return integer 1046 | * @access private 1047 | * @final 1048 | */ 1049 | final private function setBits($bits) 1050 | { 1051 | $result = 0; 1052 | 1053 | if (is_int($bits)) { 1054 | $bits[] = $bits; 1055 | } 1056 | 1057 | for ($i = 0; $i < count($bits); $i++) { 1058 | $result |= 1 << $bits[$i]; 1059 | } 1060 | 1061 | unset($bits); 1062 | 1063 | return $result; 1064 | } 1065 | 1066 | /** 1067 | * Removes superfluous separator out of the way 1068 | * @param string $path 1069 | * @return string 1070 | * @access private 1071 | * @final 1072 | */ 1073 | final private function clearSeparator($path) 1074 | { 1075 | if (substr($path, -1) == '/') { 1076 | $path = substr($path, 0, -1); 1077 | } 1078 | 1079 | if ($path[0] == '/') { 1080 | $path = substr($path, 1, strlen($path) - 1); 1081 | } 1082 | 1083 | return $path; 1084 | } 1085 | 1086 | /** 1087 | * Getting the date in the 4-bit format MSDOS 1088 | * @param integer $time 1089 | * @return integer 1090 | * @access private 1091 | * @final 1092 | */ 1093 | final private function getDateTime($time = null) 1094 | { 1095 | if (is_null($time)) { 1096 | $time = time(); 1097 | } 1098 | 1099 | $dateTime = getdate($time); 1100 | $dateTime = $dateTime["seconds"] | ($dateTime["minutes"] << 5) | 1101 | ($dateTime["hours"] << 11) | ($dateTime["mday"] << 16) | 1102 | ($dateTime["mon"] << 21) | (($dateTime["year"] - 1980) << 25); 1103 | 1104 | unset($time); 1105 | 1106 | return $dateTime; 1107 | } 1108 | } 1109 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dmamontov/rararchiver", 3 | "description": "Class for working with archives RAR.", 4 | "type": "library", 5 | "keywords": ["rar", "archives", "winrar", "archiver"], 6 | "version": "1.0.0", 7 | "license": "BSD-3-Clause", 8 | "homepage": "http://www.slobel.ru/", 9 | "authors": [ 10 | { 11 | "name": "Dmitry Mamontov", 12 | "email": "hello@slobel.ru", 13 | "role": "lead" 14 | } 15 | ], 16 | "require": { 17 | "php": ">=5.5.11" 18 | }, 19 | "support": { 20 | "email": "support@slobel.ru" 21 | }, 22 | "autoload": { 23 | "files": ["RarArchiver.php"] 24 | }, 25 | "extra": { 26 | "branch-alias": { 27 | "dev-master": "1.0.0.x-dev" 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /example.php: -------------------------------------------------------------------------------- 1 | . 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 12 | * * Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 15 | * * Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in 17 | * the documentation and/or other materials provided with the 18 | * distribution. 19 | * 20 | * * Neither the name of Dmitry Mamontov nor the names of his 21 | * contributors may be used to endorse or promote products derived 22 | * from this software without specific prior written permission. 23 | * 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 27 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 28 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 29 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 34 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | * 37 | * @package rararchiver 38 | * @author Dmitry Mamontov 39 | * @copyright 2015 Dmitry Mamontov 40 | * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License 41 | * @since File available since Release 1.0.0 42 | */ 43 | require_once 'vendor/autoload.php'; 44 | 45 | $rar = new RarArchiver('example.rar', RarArchiver::CREATE); 46 | if ($rar->isRar()) { 47 | $rar->buildFromDirectory('/var/www'); 48 | $rar->addEmptyDir('/example/'); 49 | $rar->addFile('/var/www/index.php', '/example/example.php'); 50 | $rar->addFromString('/example/example.txt', 'Example text'); 51 | 52 | $files = $rar->getFileList(); 53 | if (in_array('/example/example.txt', $files)) { 54 | $rar->renameName('/example/example.txt', '/example/rename-example.txt'); 55 | $rar->deleteName('/example/rename-example.txt'); 56 | } 57 | 58 | $rar->extractTo('tmp'); 59 | } 60 | ?> --------------------------------------------------------------------------------