Unique and temporary file names in PHP?
I need to convert some files to PDF and then attach them to an email. I'm using Pear Mail for the email side of it and that's fine (mostly--still working out some issues) but as part of this I need to create temporary files. Now I could use the tempnam() function but it sounds like it creates a file on the filesystem, which isn't what I want.
I just want a name in the temporary file system (using sys_get_temp_dir()) that won't clash with someone else running the same script of the same user invoking the script more than once.
Suggestions?
I've used uniqid() in the past to generate a unique filename, but not actually create the file.
$filename = uniqid(rand(), true) . '.pdf';
The first parameter can be anything you want, but I used rand() here to make it even a bit more random. Using a set prefix, you could further avoid collisions with other temp files in the system.
$filename = uniqid('MyApp', true) . '.pdf';
From there, you just create the file. If all else fails, put it in a while loop and keep generating it until you get one that works.
while (true) {
$filename = uniqid('MyApp', true) . '.pdf';
if (!file_exists(sys_get_temp_dir() . $filename)) break;
}
Seriously, use tempnam(). Yes, this creates the file, but this is a very intentional security measure designed to prevent another process on your system from "stealing" your filename and causing your process to overwrite files you don't want.
I.e., consider this sequence:
- You generate a random name.
- You check the file system to make sure it doesn't exist. If it does, repeat the previous step.
- Another, evil, process creates a file with the same name as a hard link to a file Mr Evil wants you to accidentally overwrite.
- You open the file, thinking you're creating the file rather than opening an existing one in write mode and you start writing to it.
- You just overwrote something important.
PHP's tempnam() actually calls the system's mkstemp under the hood (that's for Linux... substitute the "best practice" function for other OSs), which goes through a process like this:
- Pick a filename
- Create the file with restrictive permissions, inside a directory that prevents others from removing files it doesn't own (that's what the sticky-bit does on /var/tmp and /tmp)
- Confirms that the file created still has the restrictive permissions.
- If any of the above fails, try again with a different name.
- Returns the filename created.
Now, you can do all of those things yourself, but why, when "the proper function" does everything that's required to create secure temporary files, and that almost always involves creating an empty file for you.
Exceptions:
- You're creating a temporary file in a directory that only your process can create/delete files in.
- Create a randomly generated temporary directory, which only your process can create/delete files in.