Skip to content

Support optional suffix arg in tempnam #11685

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,7 @@ lchown \
memcntl \
memmove \
mkstemp \
mkstemps \
mmap \
nice \
nl_langinfo \
Expand Down
2 changes: 1 addition & 1 deletion ext/standard/basic_functions.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -2803,7 +2803,7 @@ function rename(string $from, string $to, $context = null): bool {}
function copy(string $from, string $to, $context = null): bool {}

/** @refcount 1 */
function tempnam(string $directory, string $prefix): string|false {}
function tempnam(string $directory, string $prefix, string $suffix = ""): string|false {}

/**
* @return resource|false
Expand Down
3 changes: 2 additions & 1 deletion ext/standard/basic_functions_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 12 additions & 5 deletions ext/standard/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -692,29 +692,36 @@ PHP_FUNCTION(file)
/* {{{ Create a unique filename in a directory */
PHP_FUNCTION(tempnam)
{
char *dir, *prefix;
size_t dir_len, prefix_len;
char *dir, *prefix, *suffix = "";
size_t dir_len, prefix_len, suffix_len = 0;
zend_string *opened_path;
int fd;
zend_string *p;
zend_string *p, *s;

ZEND_PARSE_PARAMETERS_START(2, 2)
ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_PATH(dir, dir_len)
Z_PARAM_PATH(prefix, prefix_len)
Z_PARAM_OPTIONAL
Z_PARAM_PATH(suffix, suffix_len)
ZEND_PARSE_PARAMETERS_END();

p = php_basename(prefix, prefix_len, NULL, 0);
s = php_basename(suffix, suffix_len, NULL, 0);
if (ZSTR_LEN(p) >= 64) {
ZSTR_VAL(p)[63] = '\0';
}
if (ZSTR_LEN(s) >= 64) {
ZSTR_VAL(s)[63] = '\0';
}

RETVAL_FALSE;

if ((fd = php_open_temporary_fd_ex(dir, ZSTR_VAL(p), &opened_path, PHP_TMP_FILE_OPEN_BASEDIR_CHECK_ALWAYS)) >= 0) {
if ((fd = php_open_temporary_fd_ex2(dir, ZSTR_VAL(p), ZSTR_VAL(s), &opened_path, PHP_TMP_FILE_OPEN_BASEDIR_CHECK_ALWAYS)) >= 0) {
close(fd);
RETVAL_STR(opened_path);
}
zend_string_release_ex(p, 0);
zend_string_release_ex(s, 0);
}
/* }}} */

Expand Down
143 changes: 143 additions & 0 deletions ext/standard/tests/file/tempnam_variation10.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
--TEST--
Test tempnam() function: usage variations - provide optional suffix
--SKIPIF--
<?php
if (PHP_OS_FAMILY === 'Windows') {
die("skip Do not run on Windows");
}
?>
--FILE--
<?php
/* Passing the optional $suffix arg */

echo "*** Testing tempnam() with suffixes ***\n";
$file_path = __DIR__."/tempnamVar10";
mkdir($file_path);
$prefix = "prefix-";

/* An array of suffixes */
$names_arr = array(
"",
"suffix",
"-suffix",
".ext",
/* suffix with path separators should get basename to be consistent
* with the prefix behavior */
"/no/such/file/dir",
"php/php",
NULL,
1,
0,
TRUE,
FALSE,
array(),
" ",
"\0",
);

foreach($names_arr as $i=>$suffix) {
echo "-- Iteration $i --\n";
try {
$file_name = tempnam("$file_path", $prefix, $suffix);
} catch (Error $e) {
echo $e->getMessage(), "\n";
continue;
}

/* creating the files in existing dir */
if (file_exists($file_name)) {
echo "File name is => ";
print($file_name);
echo "\n";

echo "File permissions are => ";
printf("%o", fileperms($file_name) );
echo "\n";

echo "File created in => ";
$file_dir = dirname($file_name);

if ($file_dir == sys_get_temp_dir()) {
echo "temp dir\n";
}
else if ($file_dir == $file_path) {
echo "directory specified\n";
}
else {
echo "unknown location\n";
}

}
else {
echo "-- File is not created --\n";
}

unlink($file_name);
}

rmdir($file_path);
?>
--CLEAN--
<?php
$file_path = __DIR__."/tempnamVar10";
if (file_exists($file_path)) {
array_map('unlink', glob($file_path . "/*"));
rmdir($file_path);
}
?>
--EXPECTF--
*** Testing tempnam() with suffixes ***
-- Iteration 0 --
File name is => %s%eprefix-%r.{6}%r
File permissions are => 100600
File created in => directory specified
-- Iteration 1 --
File name is => %s%eprefix-%r.{6}%rsuffix
File permissions are => 100600
File created in => directory specified
-- Iteration 2 --
File name is => %s%eprefix-%r.{6}%r-suffix
File permissions are => 100600
File created in => directory specified
-- Iteration 3 --
File name is => %s%eprefix-%r.{6}%r.ext
File permissions are => 100600
File created in => directory specified
-- Iteration 4 --
File name is => %s%eprefix-%r.{6}%rdir
File permissions are => 100600
File created in => directory specified
-- Iteration 5 --
File name is => %s%eprefix-%r.{6}%rphp
File permissions are => 100600
File created in => directory specified
-- Iteration 6 --

Deprecated: tempnam(): Passing null to parameter #3 ($suffix) of type string is deprecated in %s on line %d
File name is => %s%eprefix-%r.{6}%r
File permissions are => 100600
File created in => directory specified
-- Iteration 7 --
File name is => %s%eprefix-%r.{6}%r1
File permissions are => 100600
File created in => directory specified
-- Iteration 8 --
File name is => %s%eprefix-%r.{6}%r0
File permissions are => 100600
File created in => directory specified
-- Iteration 9 --
File name is => %s%eprefix-%r.{6}%r1
File permissions are => 100600
File created in => directory specified
-- Iteration 10 --
File name is => %s%eprefix-%r.{6}%r
File permissions are => 100600
File created in => directory specified
-- Iteration 11 --
tempnam(): Argument #3 ($suffix) must be of type string, array given
-- Iteration 12 --
File name is => %s%eprefix-%r.{6}%r
File permissions are => 100600
File created in => directory specified
-- Iteration 13 --
tempnam(): Argument #3 ($suffix) must not contain any null bytes
24 changes: 16 additions & 8 deletions main/php_open_temporary_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
* SUCH DAMAGE.
*/

static int php_do_open_temporary_file(const char *path, const char *pfx, zend_string **opened_path_p)
static int php_do_open_temporary_file(const char *path, const char *pfx, const char *sfx, zend_string **opened_path_p)
{
#ifdef PHP_WIN32
char *opened_path = NULL;
Expand All @@ -97,7 +97,7 @@ static int php_do_open_temporary_file(const char *path, const char *pfx, zend_st
char cwd[MAXPATHLEN];
cwd_state new_state;
int fd = -1;
#ifndef HAVE_MKSTEMP
#ifndef HAVE_MKSTEMPS
int open_flags = O_CREAT | O_TRUNC | O_RDWR
#ifdef PHP_WIN32
| _O_BINARY
Expand Down Expand Up @@ -135,7 +135,7 @@ static int php_do_open_temporary_file(const char *path, const char *pfx, zend_st
trailing_slash = "/";
}

if (snprintf(opened_path, MAXPATHLEN, "%s%s%sXXXXXX", new_state.cwd, trailing_slash, pfx) >= MAXPATHLEN) {
if (snprintf(opened_path, MAXPATHLEN, "%s%s%sXXXXXX%s", new_state.cwd, trailing_slash, pfx, sfx) >= MAXPATHLEN) {
efree(new_state.cwd);
return -1;
}
Expand Down Expand Up @@ -175,8 +175,8 @@ static int php_do_open_temporary_file(const char *path, const char *pfx, zend_st

free(cwdw);
free(pfxw);
#elif defined(HAVE_MKSTEMP)
fd = mkstemp(opened_path);
#elif defined(HAVE_MKSTEMPS)
fd = mkstemps(opened_path, strlen(sfx));
#else
if (mktemp(opened_path)) {
fd = VCWD_OPEN(opened_path, open_flags);
Expand Down Expand Up @@ -283,14 +283,17 @@ PHPAPI const char* php_get_temporary_directory(void)
* This function should do its best to return a file pointer to a newly created
* unique file, on every platform.
*/
PHPAPI int php_open_temporary_fd_ex(const char *dir, const char *pfx, zend_string **opened_path_p, uint32_t flags)
PHPAPI int php_open_temporary_fd_ex2(const char *dir, const char *pfx, const char *sfx, zend_string **opened_path_p, uint32_t flags)
{
int fd;
const char *temp_dir;

if (!pfx) {
pfx = "tmp.";
}
if (!sfx) {
sfx = "";
}
if (opened_path_p) {
*opened_path_p = NULL;
}
Expand All @@ -302,7 +305,7 @@ PHPAPI int php_open_temporary_fd_ex(const char *dir, const char *pfx, zend_strin
if (temp_dir &&
*temp_dir != '\0' &&
(!(flags & PHP_TMP_FILE_OPEN_BASEDIR_CHECK_ON_FALLBACK) || !php_check_open_basedir(temp_dir))) {
return php_do_open_temporary_file(temp_dir, pfx, opened_path_p);
return php_do_open_temporary_file(temp_dir, pfx, sfx, opened_path_p);
} else {
return -1;
}
Expand All @@ -313,7 +316,7 @@ PHPAPI int php_open_temporary_fd_ex(const char *dir, const char *pfx, zend_strin
}

/* Try the directory given as parameter. */
fd = php_do_open_temporary_file(dir, pfx, opened_path_p);
fd = php_do_open_temporary_file(dir, pfx, sfx, opened_path_p);
if (fd == -1) {
/* Use default temporary directory. */
if (!(flags & PHP_TMP_FILE_SILENT)) {
Expand All @@ -324,6 +327,11 @@ PHPAPI int php_open_temporary_fd_ex(const char *dir, const char *pfx, zend_strin
return fd;
}

PHPAPI int php_open_temporary_fd_ex(const char *dir, const char *pfx, zend_string **opened_path_p, uint32_t flags)
{
return php_open_temporary_fd_ex2(dir, pfx, NULL, opened_path_p, flags);
}

PHPAPI int php_open_temporary_fd(const char *dir, const char *pfx, zend_string **opened_path_p)
{
return php_open_temporary_fd_ex(dir, pfx, opened_path_p, PHP_TMP_FILE_DEFAULT);
Expand Down
1 change: 1 addition & 0 deletions main/php_open_temporary_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
BEGIN_EXTERN_C()
PHPAPI FILE *php_open_temporary_file(const char *dir, const char *pfx, zend_string **opened_path_p);
PHPAPI int php_open_temporary_fd_ex(const char *dir, const char *pfx, zend_string **opened_path_p, uint32_t flags);
PHPAPI int php_open_temporary_fd_ex2(const char *dir, const char *pfx, const char *sfx, zend_string **opened_path_p, uint32_t flags);
PHPAPI int php_open_temporary_fd(const char *dir, const char *pfx, zend_string **opened_path_p);
PHPAPI const char *php_get_temporary_directory(void);
END_EXTERN_C()
Expand Down