PHPのお勉強!

PHP TOP

tempnam

(PHP 4, PHP 5, PHP 7, PHP 8)

tempnam一意なファイル名を生成する

説明

tempnam(string $directory, string $prefix): string|false

一意なテンポラリファイル名を、パーミッションを 0600 に設定し、 指定したディレクトリに作成します。 指定したディレクトリが存在しない場合やディレクトリに書き込めない場合は、tempnam() はシステムのテンポラリディレクトリにあるファイル名を生成し、 そのファイルへのフルパスを (名前を含めて) 返します。

パラメータ

directory

テンポラリファイルを作成したいディレクトリ。

prefix

作成されるテンポラリファイルのプレフィックス。

注意: プレフィックスの最初の63文字のみを使用し、残りは無視されます。 Windows では、プレフィックスの最初の 3 文字のみを使用します。

戻り値

新しいテンポラリファイル名 (パスを含む) を返し、失敗した場合には false を返します。

変更履歴

バージョン 説明
7.1.0 tempnam() は、 システムのテンポラリディレクトリにフォールバックした場合に 警告を生成するようになりました。

例1 tempnam() の例

<?php
$tmpfname
= tempnam("/tmp", "FOO");

$handle = fopen($tmpfname, "w");
fwrite($handle, "writing to tempfile");
fclose($handle);

// ここで何か行う

unlink($tmpfname);
?>

注意

注意: PHP が指定されたパラメータ directory にファイルを生成することができない場合、 システム標準のフォールバックが実行されます。 NTFS では、指定した directory に 65534 を超える数のファイルが存在する場合にも同じことが起こります。

参考

  • tmpfile() - テンポラリファイルを作成する
  • sys_get_temp_dir() - 一時ファイル用に使用されるディレクトリのパスを返す
  • unlink() - ファイルを削除する

add a note

User Contributed Notes 22 notes

up
78
koyama
15 years ago
Watch out using a blank $dir as a "trick" to create temporary files in the system temporary directory.

<?php
$tmpfname
= tempnam('', 'FOO'); // not good
?>

If an open_basedir restriction is in effect, the trick will not work. You will get a warning message like

Warning: tempnam() [function.tempnam]: open_basedir restriction in effect.
File() is not within the allowed path(s): (/var/www/vhosts/example.com/httpdocs:/tmp)

What works is this:

<?php
$tmpfname
= tempnam(sys_get_temp_dir(), 'FOO'); // good
?>
up
25
Sebastian Kun
19 years ago
If you go to the linux man page for the C function tempnam(3), you will see at the end "Never use this function. Use mkstemp(3) instead." But php's tempnam() function doesn't actually use tmpnam(3), so there's no problem (under Linux, it will use mkstemp(3) if it's available).
up
15
php at REMOVEMEkennel17 dot co dot uk
19 years ago
Note that tempnam returns the full path to the temporary file, not just the filename.
up
15
stanislav dot eckert at vizson dot de
7 years ago
Please note that this function might throw a notice in PHP 7.1.0 and above. This was a bugfix: https://bugs.php.net/bug.php?id=69489

You can place an address operator (@) to sillence the notice:

<?php

if ($tmp = @tempnam() !== false) {
// ...
}

?>

Or you could try to set the "upload_tmp_dir" setting in your php.ini to the temporary folder path of your system. Not sure, if the last one prevents the notices.
up
7
Jason Pell
17 years ago
I want to guarantee that the file will be created in the specified directory or else the function should return FALSE, I have a simple function that works, but I am unsure if its a potential security issue.

function dir_tempnam($dir, $prefix)
{
$real_dir_path = realpath($dir);
if (substr($real_dir_path, -1) != '/')
$real_dir_path .= '/';

$tempfile = tempnam($real_dir_path, $prefix);
$name = basename($tempfile);

if(is_file($real_dir_path.$name))
return $name;
else
{
@unlink($name);
return FALSE;
}
}

This function returns just the name of the temporary file in the specified directory, or FALSE.

Obviously it could return the entire $tempfile, but in my case, I actually want the basename value seperate.
up
13
Artur Graniszewski
14 years ago
tempnam() function does not support custom stream wrappers registered by stream_register_wrapper().

For example if you'll try to use tempnam() on Windows platform, PHP will try to generate unique filename in %TMP% folder (usually: C:\WINDOWS\Temp) without any warning or notice.

<?php

// << ...custom stream wrapper goes somewhere here...>>

echo '<pre>';
error_reporting(E_ALL);
ini_set('display_errors', true);
clearstatcache();
stream_register_wrapper('test', 'MemoryStream');

mkdir('test://aaa');
mkdir('test://aaa/cc');
mkdir('test://aaa/dd');
echo
'PHP '.PHP_VERSION;
echo
'<br />node exists: '.file_exists('test://aaa/cc');
echo
'<br />node is writable: '.is_writable('test://aaa/cc');
echo
'<br />node is dir: '.is_dir('test://aaa/cc');
echo
'<br />tempnam in dir: '.tempnam('test://aaa/cc', 'tmp');
echo
"<br /></pre>";

?>

ouputs:
--------------------
PHP 5.2.13
node exists: 1
node is writable: 1
node is dir: 1
tempnam in dir: C:\Windows\Temp\tmp1D03.tmp

If you want to create temporary file, you have to create your own function (which will probably use opendir() and fopen($filename, "x") functions)
up
6
anakin dot skyw at gmx dot de
20 years ago
>Under UNIX (where you can rename onto an extant file and so I used link), you will have to remove both the link and the link's target.

Couldn't you do
<?php
if ($newFileCreated) {
unlink ($sysFileName);
return
$newFileName;
}
?>
and get the same semantics as the windows version?
up
9
Ron Korving
18 years ago
This function creates a temporary directory. The previous example given could bug if between the unlink() and mkdir() some process creates the same directory or file. This implementation is faster too.

<?php
function tempdir($dir, $prefix='', $mode=0700)
{
if (
substr($dir, -1) != '/') $dir .= '/';

do
{
$path = $dir.$prefix.mt_rand(0, 9999999);
} while (!
mkdir($path, $mode));

return
$path;
}
?>
up
8
bishop
20 years ago
Creating a temporary file with a specific extension is a common requirement on dynamic websites. Largely this need arises from Microsoft browsers that identify a downloaded file's mimetype based on the file's extension.

No single PHP function creates a temporary filename with a specific extension, and, as has been shown, there are race conditions involved unless you use the PHP atomic primitives.

I use only primitives below and exploit OS dependent behaviour to securely create a file with a specific postfix, prefix, and directory. Enjoy.

<?php
function secure_tmpname($postfix = '.tmp', $prefix = 'tmp', $dir = null) {
// validate arguments
if (! (isset($postfix) && is_string($postfix))) {
return
false;
}
if (! (isset(
$prefix) && is_string($prefix))) {
return
false;
}
if (! isset(
$dir)) {
$dir = getcwd();
}

// find a temporary name
$tries = 1;
do {
// get a known, unique temporary file name
$sysFileName = tempnam($dir, $prefix);
if (
$sysFileName === false) {
return
false;
}

// tack on the extension
$newFileName = $sysFileName . $postfix;
if (
$sysFileName == $newFileName) {
return
$sysFileName;
}

// move or point the created temporary file to the new filename
// NOTE: these fail if the new file name exist
$newFileCreated = (isWindows() ? @rename($sysFileName, $newFileName) : @link($sysFileName, $newFileName));
if (
$newFileCreated) {
return
$newFileName;
}

unlink ($sysFileName);
$tries++;
} while (
$tries <= 5);

return
false;
}
?>

The isWindows function is mostly left as an exercise for the reader. A starting point is below:

<?php
function isWindows() {
return (
DIRECTORY_SEPARATOR == '\\' ? true : false);
}
?>

Like tempnam(), this function requires you to cleanup your own files later. Under UNIX (where you can rename onto an extant file and so I used link), you will have to remove both the link and the link's target. Cleanup is left entirely to the reader.
up
8
divinity76+yaoiporn at gmail dot com
11 years ago
if you don't want to take care of deleting the file yourself, and you don't need a custom prefix, you can use
$file_location=stream_get_meta_data(tmpfile())['uri'];
file will be created automatically, and deleted automatically on script close (thanks to tmpfile()) i found this useful for CURLOPT_COOKIEFILE (which wants a file location, not a handle)
up
6
wapmorgan
10 years ago
Notice that tempnam will return NULL (not false) if the second parameter <prefix> isn't transferred:
<?php
var_dump
(tempnam(sys_get_temp_dir())); // NULL
?>
also the warning will be generated:
Warning: tempnam() expects exactly 2 parameters, 1 given in php shell code ...
up
4
tux ARROBA cenobioracing PUNTO com
18 years ago
Beware that on Windows NT and other windows, if you have, for example, a variable $work_dir with a path to some dir on your document root(or any other dir). Note the following:
<?php
$work_dir
= 'C:/some/path/to/document_root/dir';
file_exists($working_dir); // Returns true
is_writable($working_dir); // Returns true
$tempfile = tempnam($working_dir,'img');
//$temfile now contains a system wide temp directory file, like 'C:/WINNT.SBS/img444.tmp' instead of the directory we pass it
//Thats because we need to give I_USR (IIS user) user write permission to $working_dir although according to the aforementioned functions seemed it already had it...
//If you want to use just the system wide temp directory return by default by tempnam you will also need to give it write permission to I_USR user to be able to write to that file...
?>
up
5
tomas at slax dot org
14 years ago
Beware: functions are not atomic. If many processes call the same function at the same time, you may end up with unwanted behavior.

If you need your own variant of tempnam, use something like this:

<?php
function tempnam_sfx($path, $suffix)
{
do
{
$file = $path."/".mt_rand().$suffix;
$fp = @fopen($file, 'x');
}
while(!
$fp);

fclose($fp);
return
$file;
}

// call it like this:
$file = tempnam_sfx("/tmp", ".jpg");
?>

You may replace mt_rand() by some other random name generator, if needed.
up
4
lreilly at lanl dot gov
22 years ago
Be careful with you forward and back slashes. Innocent looking code like this...

$uploaddir = "C:/Program Files/Apache Group/Apache2/htdocs/sasdap/uploads/";
$tempFile = tempnam ($uploaddir, "TMPANAL");
$fp = fopen($tmpfname, "w");
fwrite($fp, $iqdata);
//fclose($fp);

... may show something odd when echoing $tempFile";

i.e. /Program Files/Apache Group/Apache2/htdocs/sasdap/uploads/\TMP3D.tmp

Must... remember... to... use... backslashes...

- Lee P. Reilly
up
2
Anonymous
12 years ago
tempnam will not create file in unauthorized area.
Meaning you need access permissions to the temp dir ($dir) in order to create a file there.
up
3
phpdoc at rickbradley dot com
21 years ago
The "newtempnam" recipe provided below (posted by "tempnam" on " 23-Jul-2003 08:56") has at least one race condition. The while loop checks to make sure that the file in question doesn't exist, and then goes and creates the file. In between the existence test and the fopen() call there is an opportunity for an attacker to create the file in question.

This is a classic race-condition, and while it seems difficult to exploit there are a number of well-known attacks against this kind of sloppy file creation.

The atomic primitives necessary to implement secure file creation are not available at the language level in PHP. This further underscores the need for PHP-language developers to rely on the language's security primitives (including tempnam() and tempfile()) instead of rolling their own.
up
3
dmhouse at gmail dot com
17 years ago
Guillaume Paramelle's comments below are worth underlining: tempnam() will not accept a relative path for its first directory. If you pass it one, it will (on Windows XP at least) create the temporary file in the system temp directory.

The easiest way to convert a relative path to an absolute path is to prepend getcwd():

<?php
$file
= tempnam('files/temp', 'tmp'); // Wrong!
$file = tempnam(getcwd() . 'files/tmp', 'tmp') // Right.
?>
up