diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 31d443cd43d07..da63ae08ffba6 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -2046,7 +2046,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; @@ -2058,10 +2058,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) { @@ -2118,9 +2137,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))) { @@ -2128,10 +2144,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)); @@ -2348,7 +2395,7 @@ static zend_object *phar_convert_to_other(phar_archive_data *source, int convert 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 be2a0e1036080..380f3e381f91d 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 0000000000000..e2ac1e008e400 Binary files /dev/null and b/ext/phar/tests/bug74196.1.2.3.phar.tar.gz differ diff --git a/ext/phar/tests/bug74196.phpt b/ext/phar/tests/bug74196.phpt new file mode 100644 index 0000000000000..7a8e9235a3dcd --- /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 e4b1fe41d770c..f84a4e690d128 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 10e6973254b6c..647bb842d78c5 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 aba2a6417de55..6a3f2bf2c81e1 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'] = '