PHP Doku:: Erzeugt eine Datei mit eindeutigem Dateinamen - function.tempnam.html

Verlauf / Chronik / History: (1) anzeigen

Sie sind hier:
Doku-StartseitePHP-HandbuchFunktionsreferenzDateisystemrelevante ErweiterungenDateisystemDateisystem-Funktionentempnam

Ein Service von Reinhard Neidl - Webprogrammierung.

Dateisystem-Funktionen

<<symlink

tmpfile>>

tempnam

(PHP 4, PHP 5)

tempnamErzeugt eine Datei mit eindeutigem Dateinamen

Beschreibung

string tempnam ( string $dir , string $prefix )

Erzeugt eine Datei mit einem eindeutigen Dateinamen in dem angegebenen Verzeichnis, wobei die Zugriffsberechtigungen auf 0600 gesetzt werden. Wenn das Verzeichnis nicht existiert, erstellt tempnam() eine Datei im temporären Verzeichnis des Systems und gibt diesen Namen zurück.

Parameter-Liste

dir

Das Verzeichnis, in dem die temporäre Datei erstellt werden soll.

prefix

Der Präfix des genererierten temporären Dateinamens.

Hinweis: Windows nutzt nur die ersten drei Zeichen des Präfixes.

Rückgabewerte

Gibt den neuen temporären Dateinamen zurück, oder im Fehlerfall FALSE

Changelog

Version Beschreibung
4.0.6 Vor PHP 4.0.6 war das Verhalten der tempnam()-Funktion systemabhängig. Unter Windows wird die TMP-Umgebungsvariable den dir-Parameter überschreiben, unter Linux hat die TMPDIR-Umgebungsvariable Vorrang, während SVR4 immer den dir-Parameter verwendet, sofern das angegebene Verzeichnis existiert. Genauere Informationen finden Sie in Ihrem Systemhandbuch zur tempnam(3)-Funktion.
4.0.3 Das Verhalten dieser Funktion hat sich in Version 4.0.3 geändert. Die temporäre Datei wird auch erstellt, um eine "race condition" zu vermeiden, falls die Datei zwischen dem Zeitpunkt, an dem der String erzeugt wurde, und dem Zeitpunkt, an dem das Skript die Datei erzeugt, im Dateisystem auftaucht. Beachten Sie, dass Sie die Datei löschen müssen, wenn Sie sie nicht mehr benötigen; dies geschieht nicht automatisch.

Beispiele

Beispiel #1 tempnam()-Beispiel

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

$handle fopen($tmpfname"w");
fwrite($handle"schreiben in Temporärdatei");
fclose($handle);

// tue etwas

unlink($tmpfname);
?>

Anmerkungen

Hinweis: Wenn PHP die Datei nicht im angegebenen dir-Parameter erzeugen kann, fällt es auf den Systemstandardwert zurück. Unter NTFS geschieht dies auch, wenn dir mehr als 65534 Dateien enthält.

Siehe auch


27 BenutzerBeiträge:
- Beiträge aktualisieren...
tomas at slax dot org
3.06.2010 11:31
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.
anthon at piwik dot org
7.04.2010 1:20
The file created by tempnam() will have file permissions that reflect the current umask applied to the default (e.g., 0600 or -rw-------).  This is the case whether the umask is set before starting the web server process, or set by an earlier call to PHP's umask() function.

For example, if the current umask is 0022, the temporary file is created with permissions 0600 (read/write by owner).

Also, if the current umask is 0222, the temporary file is created with permissions 0400 (read-only by owner).  (This is problematic if your code then tries to open the temporary file for writing.)

It's important to remember that the umask revokes permissions.  In neither of the above examples are the group, other, or execute permissions set.

See:  umask(), chmod().
Artur Graniszewski
31.03.2010 20:57
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)
Chris
3.02.2010 22:16
I needed a function that allowed me to specify a filename suffix and a longer prefix:

<?php
function my_tempnam($prefix = null, $suffix = null, $dir = null)
{
   
func_num_args() > 3 and exit(__FUNCTION__.'(): passed '.func_num_args().' args, should pass 0, 1, 2, or 3 args.  Usage: '.__FUNCTION__.'(optional filename prefix, optional filename suffix, optional directory)');

   
$prefix = trim($prefix);
   
$suffix = trim($suffix);
   
$dir = trim($dir);

    empty(
$dir) and $dir = trim(sys_get_temp_dir());
    empty(
$dir) and exit(__FUNCTION__.'(): could not get system temp dir');
   
is_dir($dir) or exit(__FUNCTION__."(): \"$dir\" is not a directory");
   
   
//    posix valid filename characters. exclude "similar" characters 0, O, 1, l, I to enhance readability. add - _
   
$fn_chars = array_flip(array_diff(array_merge(range(50,57), range(65,90), range(97,122), array(95,45)), array(73,79,108)));

   
//  create random filename 20 chars long for security
   
for($fn = rtrim($dir, '/') . '/' . $prefix, $loop = 0, $x = 0; $x++ < 20; $fn .= chr(array_rand($fn_chars)));
    while (
file_exists($fn.$suffix))
    {
       
$fn .= chr(array_rand($fn_chars));
       
$loop++ > 10 and exit(__FUNCTION__."(): looped too many times trying to create a unique file name in directory \"$dir\"");
       
clearstatcache();
    }

   
$fn = $fn.$suffix;
   
touch($fn) or exit(__FUNCTION__."(): could not create tmp file \"$fn\"");
    return
$fn;
}
?>
koyama
31.08.2009 2:39
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
?>
hm2k at php dot net
28.01.2009 18:15
<?php

function tempdir($dir=false,$prefix='php') {
   
$tempfile=tempnam('','');
    if (
file_exists($tempfile)) { unlink($tempfile); }
   
mkdir($tempfile);
    if (
is_dir($tempfile)) { return $tempfile; }
}

/*example*/

echo tempdir();
// returns: /tmp/8e9MLi

?>
flat at serverart dot com
4.10.2007 12:17
It seems that in between 5.2.2 and 5.2.4 tempnam() changed how it handles a relative path:

In 5.2.2:
$file=tempnam('tmpdownload', 'Ergebnis_'.date(Y.m.d).'_').'.pdf';
echo $file;
tmpdownload/Ergebnis_20071004_xTfKzz.pdf

In 5.2.4:
$file=tempnam('tmpdownload', 'Ergebnis_'.date(Y.m.d).'_').'.pdf';
echo $file;
/var/www/html/tmpdownload/Ergebnis_20071004_Xbn6PY.pdf

This broke quite a lot of our webpages as we try to display those pdfs (and other files) via the webbrowser and the resulting URI is of course invalid and gets the user a 404 page.
dmhouse at gmail dot com
3.09.2007 12:51
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.
?>
Jason Pell
12.01.2007 13:47
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.
tux ARROBA cenobioracing PUNTO com
28.08.2006 2:19
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...
?>
Guillaume Paramelle
6.06.2006 15:46
On a windows server (php 5.1.2), tempnam() may not use the dir parameter, and create the file in $_ENV['TMP'].
I also had problem because the directory was relative.
Everything was solved using :

tempnam(realpath("../_cache/"), "prefix") ;
Ron Korving
3.02.2006 9:32
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;
  }
?>
KOmaSHOOTER at gmx dot de
18.09.2005 22:51
This Example makes a File called "user.txt"
in the dir www.XXXXX.XX/restricted/
<?php
$tmpfname
= tempnam($_ENV["DOCUMENT_ROOT"]."/restricted", "FOO");
$handle = fopen($tmpfname, "w");
fwrite($handle, "writing to tempfile");
fclose($handle);

// do here something
//echo($_ENV["DOCUMENT_ROOT"]);
copy($tmpfname,'user.txt');
 
?>
chris
13.06.2005 18:23
Use the following to create a temporary directory...

// Creates a directory with a unique name
// at the specified with the specified prefix.
// Returns directory name on success, false otherwise
function tmpdir($path, $prefix)
{
        // Use PHP's tmpfile function to create a temporary
        // directory name. Delete the file and keep the name.
        $tempname = tempnam($path,$prefix);
        if (!$tempname)
                return false;

        if (!unlink($tempname))
                return false;

        // Create the temporary directory and returns its name.
        if (mkdir($tempname))
                return $tempname;

        return false;
}
php at REMOVEMEkennel17 dot co dot uk
6.03.2005 7:10
Note that tempnam returns the full path to the temporary file, not just the filename.

17.02.2005 15:13
Regarding Typo3 and Safe mode "Generally, everything in TYPO3 can work under safe_mode and open_basedir as long as the script permissions are correct. Notice, this is not something TYPO3 can do better or worse; for a working TYPO3 system there must be access to writing files and directories in the filesystem and this is done by plain PHP functions."
Sebastian Kun
21.01.2005 22:03
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).
Nick Smith
20.01.2005 20:35
It is worth noting that if the 'dir' that you supply doesn't exist, then it is silently ignored and the system /tmp directory used. At least under Linux, PHP v4.1.2.

I had a script that appeared to work fine with safe mode switched off, but I didn't realise that my 'dir' parameter had a typo (so the files were going in /tmp), and once safe mode was switched on I started getting errors because the rest of the script couldn't read files from the system /tmp folder.
soletan at toxa dot de
2.12.2004 17:45
tempnam and SAFE MODE don't generally exclude each other - that link below just shows frustrating trials to find some meaning in SAFE MODE. However, SAFE MODE is good and I'd appreciate to find it used in more of contemporarily hyped projects like typo3 or similar, since many people don't seem to care about security that much, but get enraged by tens and hundreds of Spam-Mails a day.

Okay, that post from Feb-2004 and the "bug report" is unconditionally true for multi-hosted PHP environments where several users may have their individual scripts placed on same server machine. Just take a visit to one of your local webspace-providers, that give space for 5 € or less a month.

But the truth get conditional if you gain access to the server all by yourself and may set it up to have your script's and the web server's GID being same so you can "fall back" to GID-based SAFE MODE and use tempnam as desired. This is true for several local work, intranet-related projects in your company etc. Just take a look at how SAFE MODE _really_ works and why it's rockingly important to use it. You should do when you're developing a company tool for public access at least.

Never forget to take a moment to think about Unix-filesystem and access rights as well ... even if you're locally running Windows to have some great IDE or similar (like me :). PHP is available on both systems, but that's not succeeding to define your work as "portable".
andisplitbrainorg
8.08.2004 16:28
tempname ignores the current umask and always creates the file with permission 0600.
anakin dot skyw at gmx dot de
4.07.2004 17:20
>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?
bishop
1.05.2004 5:03
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.
kulpp at wsg dot net
3.02.2004 20:57
tempnam should not be used with SAFE MODE as of 4.3.4
see http://bugs.php.net/bug.php?id=27133
phpdoc at rickbradley dot com
26.11.2003 0:54
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.

23.07.2003 19:56
The tempnam() function will not let you specify a postfix to the filename created. Here is a function that will create a new filename with pre and post fix'es. Not returns false if it can't create in the dir specified where tempnam() creates in the systems temp dir.

function newtempnam($dir, $prefix, $postfix){
    /* Creates a new non-existant file with the specified post and pre fixes */
   
    if ($dir[strlen($dir) - 1] == '/') {
        $trailing_slash = "";
    } else {
        $trailing_slash = "/";
    }
    /*The PHP function is_dir returns true on files that have no extension.
    The filetype function will tell you correctly what the file is */
    if (!is_dir(realpath($dir)) || filetype(realpath($dir)) != "dir") {
        // The specified dir is not actualy a dir
        return false;
    }
    if (!is_writable($dir)){
        // The directory will not let us create a file there
        return false;
    }
   
    do{    $seed = substr(md5(microtime().posix_getpid()), 0, 8);
        $filename = $dir . $trailing_slash . $prefix . $seed . $postfix;
    } while (file_exists($filename));
    $fp = fopen($filename, "w");
    fclose($fp);
    return $filename;
}
lreilly at lanl dot gov
29.08.2002 2:54
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
seb at nospam dot 50carleton dot com
23.05.2001 2:24
In addition to a note previously posted, on Windows NT Server 4.0, I noticed that tempnam() only uses the first THREE characters of the specified prefix.



PHP Powered Diese Seite bei php.net
The PHP manual text and comments are covered by the Creative Commons Attribution 3.0 License © the PHP Documentation Group - Impressum - mail("TO:Reinhard Neidl",...)