4242
4343 /**
4444 * Note on Drupal 8 porting.
45- * This file origin is Tar.php, release 1.4.0 (stable) with some code
45+ * This file origin is Tar.php, release 1.4.5 (stable) with some code
4646 * from PEAR.php, release 1.9.5 (stable) both at http://pear.php.net.
4747 * To simplify future porting from pear of this file, you should not
4848 * do cosmetic or other non significant changes to this file.
@@ -151,6 +151,13 @@ class ArchiveTar
151151 */
152152 public $ error_object = null ;
153153
154+ /**
155+ * Format for data extraction
156+ *
157+ * @var string
158+ */
159+ public $ _fmt ='' ;
160+
154161 /**
155162 * Archive_Tar Class constructor. This flavour of the constructor only
156163 * declare a new Archive_Tar object, identifying it by the name of the
@@ -257,6 +264,18 @@ public function __construct($p_tarname, $p_compress = null)
257264 return false ;
258265 }
259266 }
267+
268+ if (version_compare (PHP_VERSION , "5.5.0-dev " ) < 0 ) {
269+ $ this ->_fmt = "a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/ " .
270+ "a8checksum/a1typeflag/a100link/a6magic/a2version/ " .
271+ "a32uname/a32gname/a8devmajor/a8devminor/a131prefix " ;
272+ } else {
273+ $ this ->_fmt = "Z100filename/Z8mode/Z8uid/Z8gid/Z12size/Z12mtime/ " .
274+ "Z8checksum/Z1typeflag/Z100link/Z6magic/Z2version/ " .
275+ "Z32uname/Z32gname/Z8devmajor/Z8devminor/Z131prefix " ;
276+ }
277+
278+
260279 }
261280
262281 public function __destruct ()
@@ -712,7 +731,7 @@ public function setAttribute()
712731 }
713732
714733 // ----- Get the arguments
715- $ v_att_list = & func_get_args ();
734+ $ v_att_list = func_get_args ();
716735
717736 // ----- Read the attributes
718737 $ i = 0 ;
@@ -1392,10 +1411,20 @@ public function _writeHeader($p_filename, $p_stored_filename)
13921411 if ($ p_stored_filename == '' ) {
13931412 $ p_stored_filename = $ p_filename ;
13941413 }
1395- $ v_reduce_filename = $ this ->_pathReduction ($ p_stored_filename );
1414+ $ v_reduced_filename = $ this ->_pathReduction ($ p_stored_filename );
13961415
1397- if (strlen ($ v_reduce_filename ) > 99 ) {
1398- if (!$ this ->_writeLongHeader ($ v_reduce_filename )) {
1416+ if (strlen ($ v_reduced_filename ) > 99 ) {
1417+ if (!$ this ->_writeLongHeader ($ v_reduced_filename , false )) {
1418+ return false ;
1419+ }
1420+ }
1421+
1422+ $ v_linkname = '' ;
1423+ if (@is_link ($ p_filename )) {
1424+ $ v_linkname = readlink ($ p_filename );
1425+ }
1426+ if (strlen ($ v_linkname ) > 99 ) {
1427+ if (!$ this ->_writeLongHeader ($ v_linkname , true )) {
13991428 return false ;
14001429 }
14011430 }
@@ -1404,14 +1433,10 @@ public function _writeHeader($p_filename, $p_stored_filename)
14041433 $ v_uid = sprintf ("%07s " , DecOct ($ v_info [4 ]));
14051434 $ v_gid = sprintf ("%07s " , DecOct ($ v_info [5 ]));
14061435 $ v_perms = sprintf ("%07s " , DecOct ($ v_info ['mode ' ] & 000777 ));
1407-
14081436 $ v_mtime = sprintf ("%011s " , DecOct ($ v_info ['mtime ' ]));
14091437
1410- $ v_linkname = '' ;
1411-
14121438 if (@is_link ($ p_filename )) {
14131439 $ v_typeflag = '2 ' ;
1414- $ v_linkname = readlink ($ p_filename );
14151440 $ v_size = sprintf ("%011s " , DecOct (0 ));
14161441 } elseif (@is_dir ($ p_filename )) {
14171442 $ v_typeflag = "5 " ;
@@ -1423,7 +1448,6 @@ public function _writeHeader($p_filename, $p_stored_filename)
14231448 }
14241449
14251450 $ v_magic = 'ustar ' ;
1426-
14271451 $ v_version = ' ' ;
14281452
14291453 if (function_exists ('posix_getpwuid ' )) {
@@ -1438,14 +1462,12 @@ public function _writeHeader($p_filename, $p_stored_filename)
14381462 }
14391463
14401464 $ v_devmajor = '' ;
1441-
14421465 $ v_devminor = '' ;
14431466
14441467 $ v_prefix = '' ;
14451468
14461469 $ v_binary_data_first = pack (
14471470 "a100a8a8a8a12a12 " ,
1448- $ v_reduce_filename ,
14491471 $ v_perms ,
14501472 $ v_uid ,
14511473 $ v_gid ,
@@ -1485,7 +1507,7 @@ public function _writeHeader($p_filename, $p_stored_filename)
14851507 $ this ->_writeBlock ($ v_binary_data_first , 148 );
14861508
14871509 // ----- Write the calculated checksum
1488- $ v_checksum = sprintf ("%06s " , DecOct ($ v_checksum ));
1510+ $ v_checksum = sprintf ("%06s \0 " , DecOct ($ v_checksum ));
14891511 $ v_binary_data = pack ("a8 " , $ v_checksum );
14901512 $ this ->_writeBlock ($ v_binary_data , 8 );
14911513
@@ -1517,7 +1539,7 @@ public function _writeHeaderBlock(
15171539 $ p_filename = $ this ->_pathReduction ($ p_filename );
15181540
15191541 if (strlen ($ p_filename ) > 99 ) {
1520- if (!$ this ->_writeLongHeader ($ p_filename )) {
1542+ if (!$ this ->_writeLongHeader ($ p_filename, false )) {
15211543 return false ;
15221544 }
15231545 }
@@ -1613,36 +1635,31 @@ public function _writeHeaderBlock(
16131635 * @param string $p_filename
16141636 * @return bool
16151637 */
1616- public function _writeLongHeader ($ p_filename )
1638+ public function _writeLongHeader ($ p_filename, $ is_link = false )
16171639 {
1618- $ v_size = sprintf ("%11s " , DecOct (strlen ($ p_filename )));
1619-
1620- $ v_typeflag = 'L ' ;
1621-
1640+ $ v_uid = sprintf ("%07s " , 0 );
1641+ $ v_gid = sprintf ("%07s " , 0 );
1642+ $ v_perms = sprintf ("%07s " , 0 );
1643+ $ v_size = sprintf ("%'011s " , DecOct (strlen ($ p_filename )));
1644+ $ v_mtime = sprintf ("%011s " , 0 );
1645+ $ v_typeflag = ($ is_link ? 'K ' : 'L ' );
16221646 $ v_linkname = '' ;
1623-
1624- $ v_magic = '' ;
1625-
1626- $ v_version = '' ;
1627-
1647+ $ v_magic = 'ustar ' ;
1648+ $ v_version = ' ' ;
16281649 $ v_uname = '' ;
1629-
16301650 $ v_gname = '' ;
1631-
16321651 $ v_devmajor = '' ;
1633-
16341652 $ v_devminor = '' ;
1635-
16361653 $ v_prefix = '' ;
16371654
16381655 $ v_binary_data_first = pack (
16391656 "a100a8a8a8a12a12 " ,
16401657 '././@LongLink ' ,
1641- 0 ,
1642- 0 ,
1643- 0 ,
1658+ $ v_perms ,
1659+ $ v_uid ,
1660+ $ v_gid ,
16441661 $ v_size ,
1645- 0
1662+ $ v_mtime
16461663 );
16471664 $ v_binary_data_last = pack (
16481665 "a1a100a6a2a32a32a8a8a155a12 " ,
@@ -1677,7 +1694,7 @@ public function _writeLongHeader($p_filename)
16771694 $ this ->_writeBlock ($ v_binary_data_first , 148 );
16781695
16791696 // ----- Write the calculated checksum
1680- $ v_checksum = sprintf ("%06s " , DecOct ($ v_checksum ));
1697+ $ v_checksum = sprintf ("%06s \0 " , DecOct ($ v_checksum ));
16811698 $ v_binary_data = pack ("a8 " , $ v_checksum );
16821699 $ this ->_writeBlock ($ v_binary_data , 8 );
16831700
@@ -1718,28 +1735,12 @@ public function _readHeader($v_binary_data, &$v_header)
17181735 // ----- Calculate the checksum
17191736 $ v_checksum = 0 ;
17201737 // ..... First part of the header
1721- for ($ i = 0 ; $ i < 148 ; $ i ++) {
1722- $ v_checksum += ord (substr ($ v_binary_data , $ i , 1 ));
1723- }
1724- // ..... Ignore the checksum value and replace it by ' ' (space)
1725- for ($ i = 148 ; $ i < 156 ; $ i ++) {
1726- $ v_checksum += ord (' ' );
1727- }
1728- // ..... Last part of the header
1729- for ($ i = 156 ; $ i < 512 ; $ i ++) {
1730- $ v_checksum += ord (substr ($ v_binary_data , $ i , 1 ));
1731- }
1738+ $ v_binary_split = str_split ($ v_binary_data );
1739+ $ v_checksum += array_sum (array_map ('ord ' , array_slice ($ v_binary_split , 0 , 148 )));
1740+ $ v_checksum += array_sum (array_map ('ord ' , array (' ' , ' ' , ' ' , ' ' , ' ' , ' ' , ' ' , ' ' ,)));
1741+ $ v_checksum += array_sum (array_map ('ord ' , array_slice ($ v_binary_split , 156 , 512 )));
17321742
1733- if (version_compare (PHP_VERSION , "5.5.0-dev " ) < 0 ) {
1734- $ fmt = "a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/ " .
1735- "a8checksum/a1typeflag/a100link/a6magic/a2version/ " .
1736- "a32uname/a32gname/a8devmajor/a8devminor/a131prefix " ;
1737- } else {
1738- $ fmt = "Z100filename/Z8mode/Z8uid/Z8gid/Z12size/Z12mtime/ " .
1739- "Z8checksum/Z1typeflag/Z100link/Z6magic/Z2version/ " .
1740- "Z32uname/Z32gname/Z8devmajor/Z8devminor/Z131prefix " ;
1741- }
1742- $ v_data = unpack ($ fmt , $ v_binary_data );
1743+ $ v_data = unpack ($ this ->_fmt , $ v_binary_data );
17431744
17441745 if (strlen ($ v_data ["prefix " ]) > 0 ) {
17451746 $ v_data ["filename " ] = "$ v_data [prefix]/ $ v_data [filename]" ;
@@ -1775,7 +1776,7 @@ public function _readHeader($v_binary_data, &$v_header)
17751776 $ v_header ['mode ' ] = OctDec (trim ($ v_data ['mode ' ]));
17761777 $ v_header ['uid ' ] = OctDec (trim ($ v_data ['uid ' ]));
17771778 $ v_header ['gid ' ] = OctDec (trim ($ v_data ['gid ' ]));
1778- $ v_header ['size ' ] = OctDec ( trim ( $ v_data ['size ' ]) );
1779+ $ v_header ['size ' ] = $ this -> _tarRecToSize ( $ v_data ['size ' ]);
17791780 $ v_header ['mtime ' ] = OctDec (trim ($ v_data ['mtime ' ]));
17801781 if (($ v_header ['typeflag ' ] = $ v_data ['typeflag ' ]) == "5 " ) {
17811782 $ v_header ['size ' ] = 0 ;
@@ -1794,6 +1795,41 @@ public function _readHeader($v_binary_data, &$v_header)
17941795 return true ;
17951796 }
17961797
1798+ /**
1799+ * Convert Tar record size to actual size
1800+ *
1801+ * @param string $tar_size
1802+ * @return size of tar record in bytes
1803+ */
1804+ private function _tarRecToSize ($ tar_size )
1805+ {
1806+ /*
1807+ * First byte of size has a special meaning if bit 7 is set.
1808+ *
1809+ * Bit 7 indicates base-256 encoding if set.
1810+ * Bit 6 is the sign bit.
1811+ * Bits 5:0 are most significant value bits.
1812+ */
1813+ $ ch = ord ($ tar_size [0 ]);
1814+ if ($ ch & 0x80 ) {
1815+ // Full 12-bytes record is required.
1816+ $ rec_str = $ tar_size . "\x00" ;
1817+
1818+ $ size = ($ ch & 0x40 ) ? -1 : 0 ;
1819+ $ size = ($ size << 6 ) | ($ ch & 0x3f );
1820+
1821+ for ($ num_ch = 1 ; $ num_ch < 12 ; ++$ num_ch ) {
1822+ $ size = ($ size * 256 ) + ord ($ rec_str [$ num_ch ]);
1823+ }
1824+
1825+ return $ size ;
1826+
1827+ } else {
1828+ return OctDec (trim ($ tar_size ));
1829+ }
1830+ }
1831+
1832+
17971833 /**
17981834 * Detect and report a malicious file name
17991835 *
@@ -1803,10 +1839,13 @@ public function _readHeader($v_binary_data, &$v_header)
18031839 */
18041840 private function _maliciousFilename ($ file )
18051841 {
1806- if (strpos ($ file , '/.. / ' ) !== false ) {
1842+ if (strpos ($ file , 'phar:/ / ' ) === 0 ) {
18071843 return true ;
18081844 }
1809- if (strpos ($ file , '../ ' ) === 0 ) {
1845+ if (strpos ($ file , DIRECTORY_SEPARATOR . '.. ' . DIRECTORY_SEPARATOR ) !== false ) {
1846+ return true ;
1847+ }
1848+ if (strpos ($ file , '.. ' . DIRECTORY_SEPARATOR ) === 0 ) {
18101849 return true ;
18111850 }
18121851 return false ;
@@ -1871,11 +1910,20 @@ private function _extractInString($p_filename)
18711910 continue ;
18721911 }
18731912
1874- // ----- Look for long filename
1875- if ($ v_header ['typeflag ' ] == 'L ' ) {
1876- if (!$ this ->_readLongHeader ($ v_header )) {
1877- return null ;
1878- }
1913+ switch ($ v_header ['typeflag ' ]) {
1914+ case 'L ' : {
1915+ if (!$ this ->_readLongHeader ($ v_header )) {
1916+ return null ;
1917+ }
1918+ } break ;
1919+
1920+ case 'K ' : {
1921+ $ v_link_header = $ v_header ;
1922+ if (!$ this ->_readLongHeader ($ v_link_header )) {
1923+ return null ;
1924+ }
1925+ $ v_header ['link ' ] = $ v_link_header ['filename ' ];
1926+ } break ;
18791927 }
18801928
18811929 if ($ v_header ['filename ' ] == $ p_filename ) {
@@ -1976,11 +2024,20 @@ public function _extractList(
19762024 continue ;
19772025 }
19782026
1979- // ----- Look for long filename
1980- if ($ v_header ['typeflag ' ] == 'L ' ) {
1981- if (!$ this ->_readLongHeader ($ v_header )) {
1982- return false ;
1983- }
2027+ switch ($ v_header ['typeflag ' ]) {
2028+ case 'L ' : {
2029+ if (!$ this ->_readLongHeader ($ v_header )) {
2030+ return null ;
2031+ }
2032+ } break ;
2033+
2034+ case 'K ' : {
2035+ $ v_link_header = $ v_header ;
2036+ if (!$ this ->_readLongHeader ($ v_link_header )) {
2037+ return null ;
2038+ }
2039+ $ v_header ['link ' ] = $ v_link_header ['filename ' ];
2040+ } break ;
19842041 }
19852042
19862043 // ignore extended / pax headers
0 commit comments