mirror of
https://github.com/php/php-src.git
synced 2024-09-23 10:57:26 +00:00
Merge branch 'PHP-7.2'
This commit is contained in:
commit
d79a0bf748
@ -4346,21 +4346,51 @@ static int phar_extract_file(zend_bool overwrite, phar_entry_info *entry, char *
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static int extract_helper(phar_archive_data *archive, zend_string *search, char *pathto, size_t pathto_len, zend_bool overwrite, char **error) { /* {{{ */
|
||||
int extracted = 0;
|
||||
phar_entry_info *entry;
|
||||
|
||||
if (!search) {
|
||||
/* nothing to match -- extract all files */
|
||||
ZEND_HASH_FOREACH_PTR(&archive->manifest, entry) {
|
||||
if (FAILURE == phar_extract_file(overwrite, entry, pathto, pathto_len, error)) return -1;
|
||||
extracted++;
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
} else if ('/' == ZSTR_VAL(search)[ZSTR_LEN(search) - 1]) {
|
||||
/* ends in "/" -- extract all entries having that prefix */
|
||||
ZEND_HASH_FOREACH_PTR(&archive->manifest, entry) {
|
||||
if (0 != strncmp(ZSTR_VAL(search), entry->filename, ZSTR_LEN(search))) continue;
|
||||
if (FAILURE == phar_extract_file(overwrite, entry, pathto, pathto_len, error)) return -1;
|
||||
extracted++;
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
} else {
|
||||
/* otherwise, looking for an exact match */
|
||||
entry = zend_hash_find_ptr(&archive->manifest, search);
|
||||
if (NULL == entry) return 0;
|
||||
if (FAILURE == phar_extract_file(overwrite, entry, pathto, pathto_len, error)) return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return extracted;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto bool Phar::extractTo(string pathto[[, mixed files], bool overwrite])
|
||||
* Extract one or more file from a phar archive, optionally overwriting existing files
|
||||
*/
|
||||
PHP_METHOD(Phar, extractTo)
|
||||
{
|
||||
char *error = NULL;
|
||||
php_stream *fp;
|
||||
php_stream_statbuf ssb;
|
||||
phar_entry_info *entry;
|
||||
char *pathto, *filename;
|
||||
size_t pathto_len, filename_len;
|
||||
char *pathto;
|
||||
zend_string *filename;
|
||||
size_t pathto_len;
|
||||
int ret, i;
|
||||
int nelems;
|
||||
zval *zval_file;
|
||||
zval *zval_files = NULL;
|
||||
zend_bool overwrite = 0;
|
||||
char *error = NULL;
|
||||
|
||||
PHAR_ARCHIVE_OBJECT();
|
||||
|
||||
@ -4408,10 +4438,10 @@ PHP_METHOD(Phar, extractTo)
|
||||
if (zval_files) {
|
||||
switch (Z_TYPE_P(zval_files)) {
|
||||
case IS_NULL:
|
||||
goto all_files;
|
||||
filename = NULL;
|
||||
break;
|
||||
case IS_STRING:
|
||||
filename = Z_STRVAL_P(zval_files);
|
||||
filename_len = Z_STRLEN_P(zval_files);
|
||||
filename = Z_STR_P(zval_files);
|
||||
break;
|
||||
case IS_ARRAY:
|
||||
nelems = zend_hash_num_elements(Z_ARRVAL_P(zval_files));
|
||||
@ -4419,26 +4449,24 @@ PHP_METHOD(Phar, extractTo)
|
||||
RETURN_FALSE;
|
||||
}
|
||||
for (i = 0; i < nelems; i++) {
|
||||
zval *zval_file;
|
||||
if ((zval_file = zend_hash_index_find(Z_ARRVAL_P(zval_files), i)) != NULL) {
|
||||
switch (Z_TYPE_P(zval_file)) {
|
||||
case IS_STRING:
|
||||
break;
|
||||
default:
|
||||
zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0,
|
||||
"Invalid argument, array of filenames to extract contains non-string value");
|
||||
return;
|
||||
}
|
||||
if (NULL == (entry = zend_hash_find_ptr(&phar_obj->archive->manifest, Z_STR_P(zval_file)))) {
|
||||
zend_throw_exception_ex(phar_ce_PharException, 0,
|
||||
"Phar Error: attempted to extract non-existent file \"%s\" from phar \"%s\"", Z_STRVAL_P(zval_file), phar_obj->archive->fname);
|
||||
}
|
||||
if (FAILURE == phar_extract_file(overwrite, entry, pathto, pathto_len, &error)) {
|
||||
zend_throw_exception_ex(phar_ce_PharException, 0,
|
||||
"Extraction from phar \"%s\" failed: %s", phar_obj->archive->fname, error);
|
||||
efree(error);
|
||||
if (IS_STRING != Z_TYPE_P(zval_file)) {
|
||||
zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0,
|
||||
"Invalid argument, array of filenames to extract contains non-string value");
|
||||
return;
|
||||
}
|
||||
switch (extract_helper(phar_obj->archive, Z_STR_P(zval_file), pathto, pathto_len, overwrite, &error)) {
|
||||
case -1:
|
||||
zend_throw_exception_ex(phar_ce_PharException, 0, "Extraction from phar \"%s\" failed: %s",
|
||||
phar_obj->archive->fname, error);
|
||||
efree(error);
|
||||
return;
|
||||
case 0:
|
||||
zend_throw_exception_ex(phar_ce_PharException, 0,
|
||||
"Phar Error: attempted to extract non-existent file or directory \"%s\" from phar \"%s\"",
|
||||
ZSTR_VAL(Z_STR_P(zval_file)), phar_obj->archive->fname);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
RETURN_TRUE;
|
||||
@ -4447,38 +4475,22 @@ PHP_METHOD(Phar, extractTo)
|
||||
"Invalid argument, expected a filename (string) or array of filenames");
|
||||
return;
|
||||
}
|
||||
|
||||
if (NULL == (entry = zend_hash_str_find_ptr(&phar_obj->archive->manifest, filename, filename_len))) {
|
||||
zend_throw_exception_ex(phar_ce_PharException, 0,
|
||||
"Phar Error: attempted to extract non-existent file \"%s\" from phar \"%s\"", filename, phar_obj->archive->fname);
|
||||
return;
|
||||
}
|
||||
|
||||
if (FAILURE == phar_extract_file(overwrite, entry, pathto, pathto_len, &error)) {
|
||||
zend_throw_exception_ex(phar_ce_PharException, 0,
|
||||
"Extraction from phar \"%s\" failed: %s", phar_obj->archive->fname, error);
|
||||
efree(error);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
phar_archive_data *phar;
|
||||
all_files:
|
||||
phar = phar_obj->archive;
|
||||
/* Extract all files */
|
||||
if (!zend_hash_num_elements(&(phar->manifest))) {
|
||||
RETURN_TRUE;
|
||||
}
|
||||
|
||||
ZEND_HASH_FOREACH_PTR(&phar->manifest, entry) {
|
||||
if (FAILURE == phar_extract_file(overwrite, entry, pathto, pathto_len, &error)) {
|
||||
zend_throw_exception_ex(phar_ce_PharException, 0,
|
||||
"Extraction from phar \"%s\" failed: %s", phar->fname, error);
|
||||
efree(error);
|
||||
return;
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
filename = NULL;
|
||||
}
|
||||
|
||||
ret = extract_helper(phar_obj->archive, filename, pathto, pathto_len, overwrite, &error);
|
||||
if (-1 == ret) {
|
||||
zend_throw_exception_ex(phar_ce_PharException, 0, "Extraction from phar \"%s\" failed: %s",
|
||||
phar_obj->archive->fname, error);
|
||||
efree(error);
|
||||
} else if (0 == ret && NULL != filename) {
|
||||
zend_throw_exception_ex(phar_ce_PharException, 0,
|
||||
"Phar Error: attempted to extract non-existent file or directory \"%s\" from phar \"%s\"",
|
||||
ZSTR_VAL(filename), phar_obj->archive->fname);
|
||||
} else {
|
||||
RETURN_TRUE;
|
||||
}
|
||||
RETURN_TRUE;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
70
ext/phar/tests/bug54289.phpt
Normal file
70
ext/phar/tests/bug54289.phpt
Normal file
@ -0,0 +1,70 @@
|
||||
--TEST--
|
||||
Bug #54289 Phar::extractTo() does not accept specific directories to be extracted
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded("phar")) die("skip"); ?>
|
||||
--INI--
|
||||
phar.readonly = 0
|
||||
--FILE--
|
||||
<?php
|
||||
// put our test fixtures into a far
|
||||
$base = __DIR__.DIRECTORY_SEPARATOR.'bug54289'.DIRECTORY_SEPARATOR;
|
||||
$inDir = $base.'in';
|
||||
$phar = $base.'test.phar';
|
||||
$pharA = new Phar($phar);
|
||||
$pharA->buildFromDirectory($inDir);
|
||||
|
||||
// we should be able to pull out a directory that's there, but none that share
|
||||
// the same prefix
|
||||
$outDir = $base.'out';
|
||||
$pharB = new Phar($phar);
|
||||
$pharB->extractTo($outDir, 'dirA/', true);
|
||||
var_dump(file_exists($outDir.DIRECTORY_SEPARATOR.'dirA'.DIRECTORY_SEPARATOR.'fileA'));
|
||||
var_dump(file_exists($outDir.DIRECTORY_SEPARATOR.'dirA'.DIRECTORY_SEPARATOR.'fileB'));
|
||||
var_dump(is_dir($outDir.DIRECTORY_SEPARATOR.'dirAB'));
|
||||
|
||||
// should also not be able to pull out non-existent ones
|
||||
try {
|
||||
$pharB->extractTo($outDir, 'dirX/', true);
|
||||
echo 'failed to throw expected exception';
|
||||
} catch (PharException $ex) {
|
||||
}
|
||||
|
||||
// should also not be able to pull out /, because paths are not "rooted" that way
|
||||
try {
|
||||
$pharB->extractTo($outDir, '/', true);
|
||||
echo 'failed to throw expected exception';
|
||||
} catch (PharException $ex) {
|
||||
}
|
||||
|
||||
// should be able to do by array, too
|
||||
$pharB = new Phar($phar);
|
||||
$pharB->extractTo($outDir, [ 'dirA/', 'dirAB/' ], true);
|
||||
|
||||
// but not an array with a bad member in it
|
||||
try {
|
||||
$pharB = new Phar($phar);
|
||||
$pharB->extractTo($outDir, [ 'dirA/', 'dirX/' ], true);
|
||||
echo 'failed to throw expected exception';
|
||||
} catch (PharException $ex) {
|
||||
}
|
||||
|
||||
echo 'done';
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
$base = __DIR__.DIRECTORY_SEPARATOR.'bug54289'.DIRECTORY_SEPARATOR;
|
||||
$phar = $base.'test.phar';
|
||||
$outDir = $base.'out';
|
||||
unlink($phar);
|
||||
$iter = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(
|
||||
$outDir, \FilesystemIterator::SKIP_DOTS|\FilesystemIterator::UNIX_PATHS),
|
||||
\RecursiveIteratorIterator::CHILD_FIRST);
|
||||
foreach ($iter as $value) {
|
||||
$value->isFile() ? unlink($value) : rmdir($value);
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
bool(true)
|
||||
bool(true)
|
||||
bool(false)
|
||||
done
|
0
ext/phar/tests/bug54289/in/dirA/fileA
Normal file
0
ext/phar/tests/bug54289/in/dirA/fileA
Normal file
0
ext/phar/tests/bug54289/in/dirA/fileB
Normal file
0
ext/phar/tests/bug54289/in/dirA/fileB
Normal file
0
ext/phar/tests/bug54289/in/dirAB/file1
Normal file
0
ext/phar/tests/bug54289/in/dirAB/file1
Normal file
0
ext/phar/tests/bug54289/in/dirAB/file2
Normal file
0
ext/phar/tests/bug54289/in/dirAB/file2
Normal file
0
ext/phar/tests/bug54289/in/dirAB/file3
Normal file
0
ext/phar/tests/bug54289/in/dirAB/file3
Normal file
Loading…
Reference in New Issue
Block a user