Skip to content

Commit 661cd62

Browse files
committed
Support optional suffix arg in tempnam
1 parent 038b2ae commit 661cd62

7 files changed

+176
-15
lines changed

configure.ac

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,7 @@ lchown \
620620
memcntl \
621621
memmove \
622622
mkstemp \
623+
mkstemps \
623624
mmap \
624625
nice \
625626
nl_langinfo \

ext/standard/basic_functions.stub.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2803,7 +2803,7 @@ function rename(string $from, string $to, $context = null): bool {}
28032803
function copy(string $from, string $to, $context = null): bool {}
28042804

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

28082808
/**
28092809
* @return resource|false

ext/standard/basic_functions_arginfo.h

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/standard/file.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -692,29 +692,36 @@ PHP_FUNCTION(file)
692692
/* {{{ Create a unique filename in a directory */
693693
PHP_FUNCTION(tempnam)
694694
{
695-
char *dir, *prefix;
696-
size_t dir_len, prefix_len;
695+
char *dir, *prefix, *suffix = "";
696+
size_t dir_len, prefix_len, suffix_len = 0;
697697
zend_string *opened_path;
698698
int fd;
699-
zend_string *p;
699+
zend_string *p, *s;
700700

701-
ZEND_PARSE_PARAMETERS_START(2, 2)
701+
ZEND_PARSE_PARAMETERS_START(2, 3)
702702
Z_PARAM_PATH(dir, dir_len)
703703
Z_PARAM_PATH(prefix, prefix_len)
704+
Z_PARAM_OPTIONAL
705+
Z_PARAM_PATH(suffix, suffix_len)
704706
ZEND_PARSE_PARAMETERS_END();
705707

706708
p = php_basename(prefix, prefix_len, NULL, 0);
709+
s = php_basename(suffix, suffix_len, NULL, 0);
707710
if (ZSTR_LEN(p) >= 64) {
708711
ZSTR_VAL(p)[63] = '\0';
709712
}
713+
if (ZSTR_LEN(s) >= 64) {
714+
ZSTR_VAL(s)[63] = '\0';
715+
}
710716

711717
RETVAL_FALSE;
712718

713-
if ((fd = php_open_temporary_fd_ex(dir, ZSTR_VAL(p), &opened_path, PHP_TMP_FILE_OPEN_BASEDIR_CHECK_ALWAYS)) >= 0) {
719+
if ((fd = php_open_temporary_fd_ex2(dir, ZSTR_VAL(p), ZSTR_VAL(s), &opened_path, PHP_TMP_FILE_OPEN_BASEDIR_CHECK_ALWAYS)) >= 0) {
714720
close(fd);
715721
RETVAL_STR(opened_path);
716722
}
717723
zend_string_release_ex(p, 0);
724+
zend_string_release_ex(s, 0);
718725
}
719726
/* }}} */
720727

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
--TEST--
2+
Test tempnam() function: usage variations - provide optional suffix
3+
--SKIPIF--
4+
<?php
5+
if (PHP_OS_FAMILY === 'Windows') {
6+
die("skip Do not run on Windows");
7+
}
8+
?>
9+
--FILE--
10+
<?php
11+
/* Passing the optional $suffix arg */
12+
13+
echo "*** Testing tempnam() with suffixes ***\n";
14+
$file_path = __DIR__."/tempnamVar10";
15+
mkdir($file_path);
16+
$prefix = "prefix-";
17+
18+
/* An array of suffixes */
19+
$names_arr = array(
20+
"",
21+
"suffix",
22+
"-suffix",
23+
".ext",
24+
/* suffix with path separators should get basename to be consistent
25+
* with the prefix behavior */
26+
"/no/such/file/dir",
27+
"php/php",
28+
NULL,
29+
1,
30+
0,
31+
TRUE,
32+
FALSE,
33+
array(),
34+
" ",
35+
"\0",
36+
);
37+
38+
foreach($names_arr as $i=>$suffix) {
39+
echo "-- Iteration $i --\n";
40+
try {
41+
$file_name = tempnam("$file_path", $prefix, $suffix);
42+
} catch (Error $e) {
43+
echo $e->getMessage(), "\n";
44+
continue;
45+
}
46+
47+
/* creating the files in existing dir */
48+
if (file_exists($file_name)) {
49+
echo "File name is => ";
50+
print($file_name);
51+
echo "\n";
52+
53+
echo "File permissions are => ";
54+
printf("%o", fileperms($file_name) );
55+
echo "\n";
56+
57+
echo "File created in => ";
58+
$file_dir = dirname($file_name);
59+
60+
if ($file_dir == sys_get_temp_dir()) {
61+
echo "temp dir\n";
62+
}
63+
else if ($file_dir == $file_path) {
64+
echo "directory specified\n";
65+
}
66+
else {
67+
echo "unknown location\n";
68+
}
69+
70+
}
71+
else {
72+
echo "-- File is not created --\n";
73+
}
74+
75+
unlink($file_name);
76+
}
77+
78+
rmdir($file_path);
79+
?>
80+
--CLEAN--
81+
<?php
82+
$file_path = __DIR__."/tempnamVar10";
83+
if (file_exists($file_path)) {
84+
array_map('unlink', glob($file_path . "/*"));
85+
rmdir($file_path);
86+
}
87+
?>
88+
--EXPECTF--
89+
*** Testing tempnam() with suffixes ***
90+
-- Iteration 0 --
91+
File name is => %s%eprefix-%r.{6}%r
92+
File permissions are => 100600
93+
File created in => directory specified
94+
-- Iteration 1 --
95+
File name is => %s%eprefix-%r.{6}%rsuffix
96+
File permissions are => 100600
97+
File created in => directory specified
98+
-- Iteration 2 --
99+
File name is => %s%eprefix-%r.{6}%r-suffix
100+
File permissions are => 100600
101+
File created in => directory specified
102+
-- Iteration 3 --
103+
File name is => %s%eprefix-%r.{6}%r.ext
104+
File permissions are => 100600
105+
File created in => directory specified
106+
-- Iteration 4 --
107+
File name is => %s%eprefix-%r.{6}%rdir
108+
File permissions are => 100600
109+
File created in => directory specified
110+
-- Iteration 5 --
111+
File name is => %s%eprefix-%r.{6}%rphp
112+
File permissions are => 100600
113+
File created in => directory specified
114+
-- Iteration 6 --
115+
116+
Deprecated: tempnam(): Passing null to parameter #3 ($suffix) of type string is deprecated in %s on line %d
117+
File name is => %s%eprefix-%r.{6}%r
118+
File permissions are => 100600
119+
File created in => directory specified
120+
-- Iteration 7 --
121+
File name is => %s%eprefix-%r.{6}%r1
122+
File permissions are => 100600
123+
File created in => directory specified
124+
-- Iteration 8 --
125+
File name is => %s%eprefix-%r.{6}%r0
126+
File permissions are => 100600
127+
File created in => directory specified
128+
-- Iteration 9 --
129+
File name is => %s%eprefix-%r.{6}%r1
130+
File permissions are => 100600
131+
File created in => directory specified
132+
-- Iteration 10 --
133+
File name is => %s%eprefix-%r.{6}%r
134+
File permissions are => 100600
135+
File created in => directory specified
136+
-- Iteration 11 --
137+
tempnam(): Argument #3 ($suffix) must be of type string, array given
138+
-- Iteration 12 --
139+
File name is => %s%eprefix-%r.{6}%r
140+
File permissions are => 100600
141+
File created in => directory specified
142+
-- Iteration 13 --
143+
tempnam(): Argument #3 ($suffix) must not contain any null bytes

main/php_open_temporary_file.c

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@
8484
* SUCH DAMAGE.
8585
*/
8686

87-
static int php_do_open_temporary_file(const char *path, const char *pfx, zend_string **opened_path_p)
87+
static int php_do_open_temporary_file(const char *path, const char *pfx, const char *sfx, zend_string **opened_path_p)
8888
{
8989
#ifdef PHP_WIN32
9090
char *opened_path = NULL;
@@ -97,7 +97,7 @@ static int php_do_open_temporary_file(const char *path, const char *pfx, zend_st
9797
char cwd[MAXPATHLEN];
9898
cwd_state new_state;
9999
int fd = -1;
100-
#ifndef HAVE_MKSTEMP
100+
#ifndef HAVE_MKSTEMPS
101101
int open_flags = O_CREAT | O_TRUNC | O_RDWR
102102
#ifdef PHP_WIN32
103103
| _O_BINARY
@@ -135,7 +135,7 @@ static int php_do_open_temporary_file(const char *path, const char *pfx, zend_st
135135
trailing_slash = "/";
136136
}
137137

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

176176
free(cwdw);
177177
free(pfxw);
178-
#elif defined(HAVE_MKSTEMP)
179-
fd = mkstemp(opened_path);
178+
#elif defined(HAVE_MKSTEMPS)
179+
fd = mkstemps(opened_path, strlen(sfx));
180180
#else
181181
if (mktemp(opened_path)) {
182182
fd = VCWD_OPEN(opened_path, open_flags);
@@ -283,14 +283,17 @@ PHPAPI const char* php_get_temporary_directory(void)
283283
* This function should do its best to return a file pointer to a newly created
284284
* unique file, on every platform.
285285
*/
286-
PHPAPI int php_open_temporary_fd_ex(const char *dir, const char *pfx, zend_string **opened_path_p, uint32_t flags)
286+
PHPAPI int php_open_temporary_fd_ex2(const char *dir, const char *pfx, const char *sfx, zend_string **opened_path_p, uint32_t flags)
287287
{
288288
int fd;
289289
const char *temp_dir;
290290

291291
if (!pfx) {
292292
pfx = "tmp.";
293293
}
294+
if (!sfx) {
295+
sfx = "";
296+
}
294297
if (opened_path_p) {
295298
*opened_path_p = NULL;
296299
}
@@ -302,7 +305,7 @@ PHPAPI int php_open_temporary_fd_ex(const char *dir, const char *pfx, zend_strin
302305
if (temp_dir &&
303306
*temp_dir != '\0' &&
304307
(!(flags & PHP_TMP_FILE_OPEN_BASEDIR_CHECK_ON_FALLBACK) || !php_check_open_basedir(temp_dir))) {
305-
return php_do_open_temporary_file(temp_dir, pfx, opened_path_p);
308+
return php_do_open_temporary_file(temp_dir, pfx, sfx, opened_path_p);
306309
} else {
307310
return -1;
308311
}
@@ -313,7 +316,7 @@ PHPAPI int php_open_temporary_fd_ex(const char *dir, const char *pfx, zend_strin
313316
}
314317

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

330+
PHPAPI int php_open_temporary_fd_ex(const char *dir, const char *pfx, zend_string **opened_path_p, uint32_t flags)
331+
{
332+
return php_open_temporary_fd_ex2(dir, pfx, NULL, opened_path_p, flags);
333+
}
334+
327335
PHPAPI int php_open_temporary_fd(const char *dir, const char *pfx, zend_string **opened_path_p)
328336
{
329337
return php_open_temporary_fd_ex(dir, pfx, opened_path_p, PHP_TMP_FILE_DEFAULT);

main/php_open_temporary_file.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
BEGIN_EXTERN_C()
3232
PHPAPI FILE *php_open_temporary_file(const char *dir, const char *pfx, zend_string **opened_path_p);
3333
PHPAPI int php_open_temporary_fd_ex(const char *dir, const char *pfx, zend_string **opened_path_p, uint32_t flags);
34+
PHPAPI int php_open_temporary_fd_ex2(const char *dir, const char *pfx, const char *sfx, zend_string **opened_path_p, uint32_t flags);
3435
PHPAPI int php_open_temporary_fd(const char *dir, const char *pfx, zend_string **opened_path_p);
3536
PHPAPI const char *php_get_temporary_directory(void);
3637
END_EXTERN_C()

0 commit comments

Comments
 (0)