From a9fdf3d6b47ba0bbb35f1bc5b0165574ce29f132 Mon Sep 17 00:00:00 2001 From: Mitch Hagstrand Date: Fri, 7 Apr 2017 16:52:12 -0700 Subject: [PATCH] Fix for Bug 74196: PharData->decompress() does not correctly support dot names 1. Fixed phar_rename_archive to no longer remove everything after a "." in the filename 2. Removed unused "zend_bool compress" parameter 3. Added Test 4. Fixed tests that had a work around for this problem --- NEWS | 2 + ext/phar/phar_object.c | 63 +++++++++++++++++--- ext/phar/tests/bug48377.2.phpt | 6 +- ext/phar/tests/bug74196.1.2.3.phar.tar.gz | Bin 0 -> 288 bytes ext/phar/tests/bug74196.phpt | 23 +++++++ ext/phar/tests/phar_convert_repeated.phpt | 6 +- ext/phar/tests/phar_convert_repeated_b.phpt | 10 ++-- ext/phar/tests/stat2_5.3.phpt | 4 +- 8 files changed, 94 insertions(+), 20 deletions(-) create mode 100644 ext/phar/tests/bug74196.1.2.3.phar.tar.gz create mode 100644 ext/phar/tests/bug74196.phpt diff --git a/NEWS b/NEWS index a69bdc846f..eae6a81288 100644 --- a/NEWS +++ b/NEWS @@ -140,6 +140,8 @@ PHP NEWS - phar: . Fixed bug #74383 phar method parameters reflection correction. (mhagstrand) + . Fixed bug #74196 (phar does not correctly handle names containing dots). + (mhagstrand) - PHPDBG . Added extended_value to opcode dump output. (Sara) diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 8e9233ae17..f5973b5b27 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -2019,7 +2019,7 @@ static int phar_copy_file_contents(phar_entry_info *entry, php_stream *fp) /* {{ } /* }}} */ -static zend_object *phar_rename_archive(phar_archive_data **sphar, char *ext, zend_bool compress) /* {{{ */ +static zend_object *phar_rename_archive(phar_archive_data **sphar, char *ext) /* {{{ */ { const char *oldname = NULL; phar_archive_data *phar = *sphar; @@ -2031,10 +2031,29 @@ static zend_object *phar_rename_archive(phar_archive_data **sphar, char *ext, ze char *error; const char *pcr_error; int ext_len = ext ? strlen(ext) : 0; - size_t new_len, oldname_len; + size_t new_len, oldname_len, phar_ext_len; phar_archive_data *pphar = NULL; php_stream_statbuf ssb; + int phar_ext_list_len, i = 0; + char *ext_pos = NULL; + /* Array of PHAR extensions, Must be in order, starting with longest + * ending with the shortest. */ + char *phar_ext_list[] = { + ".phar.tar.bz2", + ".phar.tar.gz", + ".phar.php", + ".phar.bz2", + ".phar.zip", + ".phar.tar", + ".phar.gz", + ".tar.bz2", + ".tar.gz", + ".phar", + ".tar", + ".zip" + }; + if (!ext) { if (phar->is_zip) { @@ -2091,9 +2110,6 @@ static zend_object *phar_rename_archive(phar_archive_data **sphar, char *ext, ze return NULL; } - if (ext[0] == '.') { - ++ext; - } oldpath = estrndup(phar->fname, phar->fname_len); if ((oldname = zend_memrchr(phar->fname, '/', phar->fname_len))) { @@ -2101,10 +2117,41 @@ static zend_object *phar_rename_archive(phar_archive_data **sphar, char *ext, ze } else { oldname = phar->fname; } - oldname_len = strlen(oldname); + oldname_len = strlen(oldname); + /* Copy the old name to create base for the new name */ basename = estrndup(oldname, oldname_len); - spprintf(&newname, 0, "%s.%s", strtok(basename, "."), ext); + + phar_ext_list_len = sizeof(phar_ext_list)/sizeof(phar_ext_list[0]); + /* Remove possible PHAR extensions */ + /* phar_ext_list must be in order of longest extension to shortest */ + for (i=0; i < phar_ext_list_len; i++) { + phar_ext_len = strlen(phar_ext_list[i]); + if (phar_ext_len && oldname_len > phar_ext_len) { + /* Check if the basename strings ends with the extension */ + if (memcmp(phar_ext_list[i], basename + (oldname_len - phar_ext_len), phar_ext_len) == 0) { + ext_pos = basename + (oldname_len - phar_ext_len); + ext_pos[0] = '\0'; + break; + } + } + ext_pos = NULL; + } + + /* If no default PHAR extension found remove the last extension */ + if (!ext_pos) { + ext_pos = strrchr(basename, '.'); + if (ext_pos) { + ext_pos[0] = '\0'; + } + } + ext_pos = NULL; + + if (ext[0] == '.') { + ++ext; + } + /* Append extension to the basename */ + spprintf(&newname, 0, "%s.%s", basename, ext); efree(basename); basepath = estrndup(oldpath, (strlen(oldpath) - oldname_len)); @@ -2321,7 +2368,7 @@ no_copy: phar_add_virtual_dirs(phar, newentry.filename, newentry.filename_len); } ZEND_HASH_FOREACH_END(); - if ((ret = phar_rename_archive(&phar, ext, 0))) { + if ((ret = phar_rename_archive(&phar, ext))) { return ret; } else { if(phar != NULL) { diff --git a/ext/phar/tests/bug48377.2.phpt b/ext/phar/tests/bug48377.2.phpt index be2a0e1036..380f3e381f 100644 --- a/ext/phar/tests/bug48377.2.phpt +++ b/ext/phar/tests/bug48377.2.phpt @@ -12,7 +12,7 @@ $fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.zip'; $phar = new PharData($fname); $phar['x'] = 'hi'; try { - $phar->convertToData(Phar::ZIP, Phar::NONE, '.2.phar.zip'); + $phar->convertToData(Phar::ZIP, Phar::NONE, 'phar.zip'); } catch (BadMethodCallException $e) { echo $e->getMessage(),"\n"; } @@ -21,5 +21,5 @@ try { --CLEAN-- --EXPECTF-- -data phar "%sbug48377.2.phar.zip" has invalid extension 2.phar.zip -===DONE=== \ No newline at end of file +data phar "%sbug48377.2.phar.zip" has invalid extension phar.zip +===DONE=== diff --git a/ext/phar/tests/bug74196.1.2.3.phar.tar.gz b/ext/phar/tests/bug74196.1.2.3.phar.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..e2ac1e008e40037a6ff88c48b67b00b83961c42c GIT binary patch literal 288 zcmV+*0pI=~iwFP!00000150F}Jumwnq#Q!K5ydaqlc956<%}4V; z9RNMze-sQ}pjVKQSfpQEQkn#070|{Gg8ARvgaMTI%?-@W4Ghgd;^s!CqxC;MfQ>yc z+7ZekYCBh6C-kQ7{Td!6+C7v;zR1_#sXJ7ytlj(tSk$ literal 0 HcmV?d00001 diff --git a/ext/phar/tests/bug74196.phpt b/ext/phar/tests/bug74196.phpt new file mode 100644 index 0000000000..7a8e9235a3 --- /dev/null +++ b/ext/phar/tests/bug74196.phpt @@ -0,0 +1,23 @@ +--TEST-- +PHP bug #74196: PharData->decompress() does not correctly support dot names +--SKIPIF-- + + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +decompress(); +var_dump(file_exists($decompressed_name)); +unlink($decompressed_name); + +?> +--EXPECTF-- +bool(true) +bool(true) diff --git a/ext/phar/tests/phar_convert_repeated.phpt b/ext/phar/tests/phar_convert_repeated.phpt index b2ef195ea7..2d22c70890 100644 --- a/ext/phar/tests/phar_convert_repeated.phpt +++ b/ext/phar/tests/phar_convert_repeated.phpt @@ -91,10 +91,10 @@ var_dump($phar->getAlias()); unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip'); unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar'); -unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.zip'); -unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.tar'); +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.2.phar.zip'); +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.2.2.phar.tar'); unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar'); -unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.3.phar.zip'); +unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.2.2.3.phar.zip'); unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.3.phar.tar'); unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.3.phar'); ?> diff --git a/ext/phar/tests/phar_convert_repeated_b.phpt b/ext/phar/tests/phar_convert_repeated_b.phpt index 10e6973254..647bb842d7 100644 --- a/ext/phar/tests/phar_convert_repeated_b.phpt +++ b/ext/phar/tests/phar_convert_repeated_b.phpt @@ -74,17 +74,19 @@ try { } catch(Exception $e) { echo $e->getMessage()."\n"; } - ?> ===DONE=== --CLEAN-- - --EXPECT-- =================== new PharData() ================== @@ -115,4 +117,4 @@ string(0) "" NULL ================= convertToPhar() ==================== Cannot write out executable phar archive, phar is read-only -===DONE=== \ No newline at end of file +===DONE=== diff --git a/ext/phar/tests/stat2_5.3.phpt b/ext/phar/tests/stat2_5.3.phpt index aba2a6417d..6a3f2bf2c8 100644 --- a/ext/phar/tests/stat2_5.3.phpt +++ b/ext/phar/tests/stat2_5.3.phpt @@ -17,7 +17,7 @@ $fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.tar'; $fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.tar'; copy(dirname(__FILE__) . '/tar/files/links.tar', $fname2); $a = new PharData($fname2); -$b = $a->convertToExecutable(Phar::TAR, Phar::NONE, '.3.phar.tar'); +$b = $a->convertToExecutable(Phar::TAR, Phar::NONE, '.phar.tar'); unset($a); Phar::unlinkArchive($fname2); $b['foo/stat.php'] = '