PageRenderTime 59ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/security/ttnote/app/base/lib/tar.php

https://github.com/kenee/shopex_ts
PHP | 610 lines | 352 code | 102 blank | 156 comment | 62 complexity | f340a34e09c2e43270a18d5a0867572e MD5 | raw file
  1. <?php
  2. /*
  3. =======================================================================
  4. Name:
  5. tar Class
  6. Author:
  7. Josh Barger <joshb@npt.com>
  8. Description:
  9. This class reads and writes Tape-Archive (TAR) Files and Gzip
  10. compressed TAR files, which are mainly used on UNIX systems.
  11. This class works on both windows AND unix systems, and does
  12. NOT rely on external applications!! Woohoo!
  13. Usage:
  14. Copyright (C) 2002 Josh Barger
  15. This library is free software; you can redistribute it and/or
  16. modify it under the terms of the GNU Lesser General Public
  17. License as published by the Free Software Foundation; either
  18. version 2.1 of the License, or (at your option) any later version.
  19. This library is distributed in the hope that it will be useful,
  20. but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  22. Lesser General Public License for more details at:
  23. http://www.gnu.org/copyleft/lesser.html
  24. If you use this script in your application/website, please
  25. send me an e-mail letting me know about it :)
  26. Bugs:
  27. Please report any bugs you might find to my e-mail address
  28. at joshb@npt.com. If you have already created a fix/patch
  29. for the bug, please do send it to me so I can incorporate it into my release.
  30. Version History:
  31. 1.0 04/10/2002 - InitialRelease
  32. 2.0 04/11/2002 - Merged both tarReader and tarWriter
  33. classes into one
  34. - Added support for gzipped tar files
  35. Remember to name for .tar.gz or .tgz
  36. if you use gzip compression!
  37. :: THIS REQUIRES ZLIB EXTENSION ::
  38. - Added additional comments to
  39. functions to help users
  40. - Added ability to remove files and
  41. directories from archive
  42. 2.1 04/12/2002 - Fixed serious bug in generating tar
  43. - Created another example file
  44. - Added check to make sure ZLIB is
  45. installed before running GZIP
  46. compression on TAR
  47. 2.2 05/07/2002 - Added automatic detection of Gzipped
  48. tar files (Thanks go to Jrgen Falch
  49. for the idea)
  50. - Changed "private" functions to have
  51. special function names beginning with
  52. two underscores
  53. =======================================================================
  54. */
  55. class base_tar {
  56. // Unprocessed Archive Information
  57. var $filename;
  58. var $isGzipped;
  59. var $tar_file;
  60. // Processed Archive Information
  61. var $files;
  62. var $directories;
  63. var $numFiles;
  64. var $numDirectories;
  65. var $targetDirectory;
  66. var $tarFile;
  67. // Class Constructor -- Does nothing...
  68. // function tar() {
  69. // return true;
  70. // }
  71. // Computes the unsigned Checksum of a file's header
  72. // to try to ensure valid file
  73. // PRIVATE ACCESS FUNCTION
  74. function __computeUnsignedChecksum($bytestring) {
  75. for($i=0; $i<512; $i++)
  76. $unsigned_chksum += ord($bytestring[$i]);
  77. for($i=0; $i<8; $i++)
  78. $unsigned_chksum -= ord($bytestring[148 + $i]);
  79. $unsigned_chksum += ord(" ") * 8;
  80. return $unsigned_chksum;
  81. }
  82. // Converts a NULL padded string to a non-NULL padded string
  83. // PRIVATE ACCESS FUNCTION
  84. function __parseNullPaddedString($string) {
  85. $position = strpos($string,chr(0));
  86. return substr($string,0,$position);
  87. }
  88. function __fileSubstr(&$fp,$offset,$len){
  89. fseek($fp,$offset);
  90. return fread($fp,$len);
  91. }
  92. // This function parses the current TAR file
  93. // PRIVATE ACCESS FUNCTION
  94. function __parseTar() {
  95. if(!$this->tar_file_name) return false;
  96. // Read Files from archive
  97. $tar_length = sprintf("%u", filesize($this->tar_file_name));
  98. $main_offset = 0;
  99. $this->tar_file = fopen($this->tar_file_name,'r');
  100. while($main_offset < $tar_length) {
  101. // If we read a block of 512 nulls, we are at the end of the archive
  102. if($this->__fileSubstr($this->tar_file,$main_offset,512) == str_repeat(chr(0),512))
  103. break;
  104. // Parse file name
  105. $file_name = $this->__parseNullPaddedString($this->__fileSubstr($this->tar_file,$main_offset,100));
  106. // Parse the file mode
  107. $file_mode = $this->__fileSubstr($this->tar_file,$main_offset + 100,8);
  108. // Parse the file user ID
  109. $file_uid = octdec($this->__fileSubstr($this->tar_file,$main_offset + 108,8));
  110. // Parse the file group ID
  111. $file_gid = octdec($this->__fileSubstr($this->tar_file,$main_offset + 116,8));
  112. // Parse the file size
  113. $file_size = octdec($this->__fileSubstr($this->tar_file,$main_offset + 124,12));
  114. // Parse the file update time - unix timestamp format
  115. $file_time = octdec($this->__fileSubstr($this->tar_file,$main_offset + 136,12));
  116. // Parse Checksum
  117. $file_chksum = octdec($this->__fileSubstr($this->tar_file,$main_offset + 148,6));
  118. // Parse user name
  119. $file_uname = $this->__parseNullPaddedString($this->__fileSubstr($this->tar_file,$main_offset + 265,32));
  120. // Parse Group name
  121. $file_gname = $this->__parseNullPaddedString($this->__fileSubstr($this->tar_file,$main_offset + 297,32));
  122. // Make sure our file is valid
  123. if($this->__computeUnsignedChecksum($this->__fileSubstr($this->tar_file,$main_offset,512)) != $file_chksum)
  124. return false;
  125. // Parse File Contents
  126. //$file_contents = $this->__fileSubstr($this->tar_file,$main_offset + 512,$file_size);
  127. /* ### Unused Header Information ###
  128. $activeFile["typeflag"] = substr($this->tar_file,$main_offset + 156,1);
  129. $activeFile["linkname"] = substr($this->tar_file,$main_offset + 157,100);
  130. $activeFile["magic"] = substr($this->tar_file,$main_offset + 257,6);
  131. $activeFile["version"] = substr($this->tar_file,$main_offset + 263,2);
  132. $activeFile["devmajor"] = substr($this->tar_file,$main_offset + 329,8);
  133. $activeFile["devminor"] = substr($this->tar_file,$main_offset + 337,8);
  134. $activeFile["prefix"] = substr($this->tar_file,$main_offset + 345,155);
  135. $activeFile["endheader"] = substr($this->tar_file,$main_offset + 500,12);
  136. */
  137. if($file_size > 0) {
  138. // Increment number of files
  139. $this->numFiles++;
  140. // Create us a new file in our array
  141. $activeFile = &$this->files[];
  142. // Asign Values
  143. $activeFile["name"] = $file_name;
  144. $activeFile["mode"] = $file_mode;
  145. $activeFile["size"] = $file_size;
  146. $activeFile["time"] = $file_time;
  147. $activeFile["member_id"] = $file_uid;
  148. $activeFile["group_id"] = $file_gid;
  149. $activeFile["user_name"] = $file_uname;
  150. $activeFile["group_name"] = $file_gname;
  151. $activeFile["checksum"] = $file_chksum;
  152. $activeFile["offset"] = $main_offset + 512;
  153. //$activeFile["file"] = $file_contents;
  154. } else {
  155. // Increment number of directories
  156. $this->numDirectories++;
  157. // Create a new directory in our array
  158. $activeDir = &$this->directories[];
  159. $activeDir["name"] = $file_name;
  160. $activeDir["mode"] = $file_mode;
  161. $activeDir["time"] = $file_time;
  162. $activeDir["member_id"] = $file_uid;
  163. $activeDir["group_id"] = $file_gid;
  164. $activeDir["user_name"] = $file_uname;
  165. $activeDir["group_name"] = $file_gname;
  166. $activeDir["checksum"] = $file_chksum;
  167. }
  168. // Move our offset the number of blocks we have processed
  169. $main_offset += 512 + (ceil($file_size / 512) * 512);
  170. }
  171. return true;
  172. }
  173. // Read a non gzipped tar file in for processing
  174. // PRIVATE ACCESS FUNCTION
  175. function __readTar($filename='') {
  176. // Set the filename to load
  177. if(!$filename)
  178. $filename = $this->filename;
  179. // Read in the TAR file
  180. $fp = fopen($filename,'r');
  181. $header = fread($fp,3);
  182. fclose($fp);
  183. $this->tar_file_name = $filename;
  184. if($header[0] == chr(31) && $header[1] == chr(139) && $header == chr(8)) {
  185. return false;
  186. }
  187. // Parse the TAR file
  188. $this->__parseTar();
  189. return true;
  190. }
  191. // Generates a TAR file from the processed data
  192. // PRIVATE ACCESS FUNCTION
  193. function __generateTAR($type='file') {
  194. // Clear any data currently in $this->tar_file
  195. unset($this->tar_file);
  196. // Generate Records for each directory, if we have directories
  197. if($this->numDirectories > 0) {
  198. foreach($this->directories as $key => $information) {
  199. unset($header);
  200. // Generate tar header for this directory
  201. // Filename, Permissions, UID, GID, size, Time, checksum, typeflag, linkname, magic, version, user name, group name, devmajor, devminor, prefix, end
  202. $header .= str_pad($information["name"],100,chr(0));
  203. $header .= str_pad(decoct($information["mode"]),7,"0",STR_PAD_LEFT) . chr(0);
  204. $header .= str_pad(substr(decoct($information["member_id"]),0,7),7,"0",STR_PAD_LEFT) . chr(0);
  205. $header .= str_pad(decoct($information["group_id"]),7,"0",STR_PAD_LEFT) . chr(0);
  206. $header .= str_pad(decoct(0),11,"0",STR_PAD_LEFT) . chr(0);
  207. $header .= str_pad(decoct($information["time"]),11,"0",STR_PAD_LEFT) . chr(0);
  208. $header .= str_repeat(" ",8);
  209. $header .= "5";
  210. $header .= str_repeat(chr(0),100);
  211. $header .= str_pad("ustar",6,chr(32));
  212. $header .= chr(32) . chr(0);
  213. $header .= str_pad("",32,chr(0));
  214. $header .= str_pad("",32,chr(0));
  215. $header .= str_repeat(chr(0),8);
  216. $header .= str_repeat(chr(0),8);
  217. $header .= str_repeat(chr(0),155);
  218. $header .= str_repeat(chr(0),12);
  219. // Compute header checksum
  220. $checksum = str_pad(decoct($this->__computeUnsignedChecksum($header)),6,"0",STR_PAD_LEFT);
  221. for($i=0; $i<6; $i++) {
  222. $header[(148 + $i)] = substr($checksum,$i,1);
  223. }
  224. $header[154] = chr(0);
  225. $header[155] = chr(32);
  226. // Add new tar formatted data to tar file contents
  227. //$this->tar_file .= $header;
  228. $this->output($header,$type);
  229. }
  230. }
  231. // Generate Records for each file, if we have files (We should...)
  232. if($this->numFiles > 0) {
  233. foreach($this->files as $key => $information) {
  234. unset($header);
  235. // Generate the TAR header for this file
  236. // Filename, Permissions, UID, GID, size, Time, checksum, typeflag, linkname, magic, version, user name, group name, devmajor, devminor, prefix, end
  237. $header .= str_pad($information["name"],100,chr(0));
  238. $header .= str_pad(decoct($information["mode"]),7,"0",STR_PAD_LEFT) . chr(0);
  239. $header .= str_pad(substr(decoct($information["member_id"]),0,7),7,"0",STR_PAD_LEFT) . chr(0);
  240. $header .= str_pad(decoct($information["group_id"]),7,"0",STR_PAD_LEFT) . chr(0);
  241. $header .= str_pad(decoct($information["size"]),11,"0",STR_PAD_LEFT) . chr(0);
  242. $header .= str_pad(decoct($information["time"]),11,"0",STR_PAD_LEFT) . chr(0);
  243. $header .= str_repeat(" ",8);
  244. $header .= "0";
  245. $header .= str_repeat(chr(0),100);
  246. $header .= str_pad("ustar",6,chr(32));
  247. $header .= chr(32) . chr(0);
  248. $header .= str_pad($information["user_name"],32,chr(0)); // How do I get a file's user name from PHP?
  249. $header .= str_pad($information["group_name"],32,chr(0)); // How do I get a file's group name from PHP?
  250. $header .= str_repeat(chr(0),8);
  251. $header .= str_repeat(chr(0),8);
  252. $header .= str_repeat(chr(0),155);
  253. $header .= str_repeat(chr(0),12);
  254. // Compute header checksum
  255. $checksum = str_pad(decoct($this->__computeUnsignedChecksum($header)),6,"0",STR_PAD_LEFT);
  256. for($i=0; $i<6; $i++) {
  257. $header[(148 + $i)] = substr($checksum,$i,1);
  258. }
  259. $header[154] = chr(0);
  260. $header[155] = chr(32);
  261. // Pad file contents to byte count divisible by 512
  262. if($information["contents"]){
  263. $contents = $information["contents"];
  264. }elseif($information["srcfile"]){
  265. $contents = $this->_readFile($information["srcfile"]);
  266. }else{
  267. $contents = $this->_readFile(getcwd().'/'.$information["name"]);
  268. }
  269. $file_contents = str_pad($contents,(ceil($information["size"] / 512) * 512),chr(0));
  270. // Add new tar formatted data to tar file contents
  271. //$this->tar_file .= $header . $file_contents;
  272. $this->output($header . $file_contents,$type);
  273. }
  274. }
  275. // Add 512 bytes of NULLs to designate EOF
  276. //$this->tar_file .= str_repeat(chr(0),512);
  277. $this->output(str_repeat(chr(0),512),$type);
  278. return true;
  279. }
  280. function _readFile($file){
  281. if(is_file($file) && filesize($file)){
  282. $handle=fopen($file, "r");
  283. $contents = "";
  284. while (!feof($handle)) {
  285. $contents .= fread($handle, 500000);
  286. }
  287. fclose($handle);
  288. return $contents;
  289. }
  290. }
  291. function output($string,$type){
  292. switch($type){
  293. case 'file':
  294. if(!$this->tar_file) $this->tar_file = fopen($this->filename,'wb');
  295. fwrite($this->tar_file,$string);
  296. break;
  297. case 'var':
  298. $this->tar_file .=$string;
  299. break;
  300. case 'output':
  301. echo $string;
  302. break;
  303. }
  304. }
  305. // Open a TAR file
  306. function openTAR($filename,$target) {
  307. // Clear any values from previous tar archives
  308. unset($this->filename);
  309. unset($this->isGzipped);
  310. unset($this->tar_file);
  311. unset($this->files);
  312. unset($this->directories);
  313. unset($this->numFiles);
  314. unset($this->numDirectories);
  315. // If the tar file doesn't exist...
  316. if(!file_exists($filename))
  317. return false;
  318. $this->filename = $filename;
  319. // Parse this file
  320. $this->targetDirectory = $target;
  321. $this->__readTar();
  322. return true;
  323. }
  324. function closeTAR(){
  325. if($this->tar_file) fclose($this->tar_file);
  326. return true;
  327. }
  328. // Appends a tar file to the end of the currently opened tar file
  329. function appendTar($filename) {
  330. // If the tar file doesn't exist...
  331. if(!file_exists($filename))
  332. return false;
  333. $this->__readTar($filename);
  334. return true;
  335. }
  336. // Retrieves information about a file in the current tar archive
  337. function getFile($filename) {
  338. if($this->numFiles > 0) {
  339. foreach($this->files as $key => $information) {
  340. if($information["name"] == $filename)
  341. return $information;
  342. }
  343. }
  344. return false;
  345. }
  346. //Retrieves file contents
  347. function getContents($information){
  348. return $this->__fileSubstr($this->tar_file,$information['offset'],$information['size']);
  349. }
  350. // Retrieves information about a directory in the current tar archive
  351. function getDirectory($dirname) {
  352. if($this->numDirectories > 0) {
  353. foreach($this->directories as $key => $information) {
  354. if($information["name"] == $dirname)
  355. return $information;
  356. }
  357. }
  358. return false;
  359. }
  360. // Check if this tar archive contains a specific file
  361. function containsFile($filename) {
  362. if($this->numFiles > 0) {
  363. foreach($this->files as $key => $information) {
  364. if($information["name"] == $filename)
  365. return true;
  366. }
  367. }
  368. return false;
  369. }
  370. // Check if this tar archive contains a specific directory
  371. function containsDirectory($dirname) {
  372. if($this->numDirectories > 0) {
  373. foreach($this->directories as $key => $information) {
  374. if($information["name"] == $dirname)
  375. return true;
  376. }
  377. }
  378. return false;
  379. }
  380. // Add a directory to this tar archive
  381. function addDirectory($dirname) {
  382. if(!file_exists($dirname))
  383. return false;
  384. // Get directory information
  385. $file_information = stat($dirname);
  386. // Add directory to processed data
  387. $this->numDirectories++;
  388. $activeDir = &$this->directories[];
  389. $activeDir["name"] = $dirname;
  390. $activeDir["mode"] = $file_information["mode"];
  391. $activeDir["time"] = $file_information["time"];
  392. $activeDir["member_id"] = $file_information["uid"];
  393. $activeDir["group_id"] = $file_information["gid"];
  394. $activeDir["checksum"] = $checksum;
  395. return true;
  396. }
  397. // Add a file to the tar archive
  398. function addFile($filename,$file_contents=false,$file_information=null) {
  399. // Make sure the file we are adding exists!
  400. if(!file_exists($filename) && !$file_contents)
  401. return false;
  402. // Make sure there are no other files in the archive that have this same filename
  403. if($this->containsFile($filename))
  404. return false;
  405. // Read in the file's contents
  406. if(!$file_contents){
  407. $file_information = stat($filename);
  408. //$file_contents = file_get_contents($filename);
  409. }else{
  410. if(count($this->files)>0){
  411. $file_information = $this->files[0];
  412. }
  413. // $file_information['mode'] = 33188;
  414. $file_information['size'] = strlen($file_contents);
  415. $file_information['time'] = time();
  416. }
  417. // Add file to processed data
  418. $this->numFiles++;
  419. $activeFile = &$this->files[];
  420. $activeFile["name"] = $filename;
  421. $activeFile["mode"] = $file_information["mode"];
  422. $activeFile["member_id"] = $file_information["uid"];
  423. $activeFile["group_id"] = $file_information["gid"];
  424. $activeFile["size"] = $file_information["size"];
  425. $activeFile["time"] = $file_information["mtime"];
  426. $activeFile["checksum"] = $checksum;
  427. $activeFile["user_name"] = "";
  428. $activeFile["group_name"] = "";
  429. if($file_contents){
  430. $activeFile["contents"] = $file_contents;
  431. }
  432. return true;
  433. }
  434. // Remove a file from the tar archive
  435. function removeFile($filename) {
  436. if($this->numFiles > 0) {
  437. foreach($this->files as $key => $information) {
  438. if($information["name"] == $filename) {
  439. $this->numFiles--;
  440. unset($this->files[$key]);
  441. return true;
  442. }
  443. }
  444. }
  445. return false;
  446. }
  447. // Remove a directory from the tar archive
  448. function removeDirectory($dirname) {
  449. if($this->numDirectories > 0) {
  450. foreach($this->directories as $key => $information) {
  451. if($information["name"] == $dirname) {
  452. $this->numDirectories--;
  453. unset($this->directories[$key]);
  454. return true;
  455. }
  456. }
  457. }
  458. return false;
  459. }
  460. // Write the currently loaded tar archive to disk
  461. function saveTar() {
  462. if(!$this->filename)
  463. return false;
  464. // Write tar to current file using specified gzip compression
  465. //$this->toTar($this->filename,$this->isGzipped);
  466. $this->__generateTar();
  467. return true;
  468. }
  469. function getTar($type='output'){
  470. $this->__generateTar($type);
  471. if($type!='output') {
  472. return $this->tar_file;
  473. }
  474. }
  475. // Saves tar archive to a different file than the current file
  476. function toTar($filename,$useGzip) {
  477. if(!$filename)
  478. return false;
  479. return file_put_contents($filename,$this->getTar($useGzip));
  480. }
  481. function gzcompressfile($source,$level=false){
  482. $dest=$source.'.gz';
  483. $mode='wb'.$level;
  484. $error=false;
  485. if($fp_out=gzopen($dest,$mode)){
  486. if($fp_in=fopen($source,'rb')){
  487. while(!feof($fp_in))
  488. gzwrite($fp_out,fread($fp_in,1024*512));
  489. fclose($fp_in);
  490. }
  491. else $error=true;
  492. gzclose($fp_out);
  493. }
  494. else $error=true;
  495. if($error) return false;
  496. else return $dest;
  497. }
  498. }
  499. ?>