Php сохранить файл во временную папку

Making a temporary dir for unpacking a zipfile into

I have a script that checks a zipfile containing a number of matching PDF+textfiles. I want to unpack, or somehow read the textfiles from the zipfile, and just pick out some information from the textfile to see that the file version is correct. I was looking at the tempnam() function to find an equivalent to make a tempdir, but maybe someone has a better solution for the problem. The indexfile looks something like this. ( -> is for TAB char). I have made the function to extract the version from the textfile and to check if its correct already, its only the unpacking, tmpdir or some other solution im looking for.

1000->filename->file version->program version->customer no->company no->distribution 2000->pagenumber->more info->more info->. 

8 Answers 8

quite easy (I took partly it from the PHP manual):

 mkdir($tempfile); if (is_dir($tempfile)) < return $tempfile; >> /*example*/ echo tempdir(); // returns: /tmp/8e9MLi 

Please look at Will’s solution below.

=> My answer should not be the accepted answer anymore.

This implementation is subject to race condition. Between unlink and mkdir. Highly unlikely it’ll give you any issues, but something to note if it does.

Nice @MaxTsepkov! With a bit of luck, one can find an exploit to set $tmpfile to «/» and remove quite some files.

@PatrickAllaert if a malicious user has write access to code he already can execute rm -rf / with php privilege. It can be exploited if you still running register_globals on though in this case you most probably have outdated code and hence lot more issues.

So I first found a post by Ron Korving on PHP.net, which I then modified to make a bit safer (from endless loops, invalid characters, and unwritable parent dirs) and use a bit more entropy.

 /* Trim trailing slashes from $dir. */ $dir = rtrim($dir, DIRECTORY_SEPARATOR); /* If we don't have permission to create a directory, fail, otherwise we will * be stuck in an endless loop. */ if (!is_dir($dir) || !is_writable($dir)) < return false; >/* Make sure characters in prefix are safe. */ if (strpbrk($prefix, '\\/:*?"<>|') !== false) < return false; >/* Attempt to create a random directory until it works. Abort if we reach * $maxAttempts. Something screwy could be happening with the filesystem * and our loop could otherwise become endless. */ $attempts = 0; do < $path = sprintf('%s%s%s%s', $dir, DIRECTORY_SEPARATOR, $prefix, mt_rand(100000, mt_getrandmax())); >while ( !mkdir($path, $mode) && $attempts++ < $maxAttempts ); return $path; >?> 
/var/folders/v4/647wm24x2ysdjwx6z_f07_kw0000gp/T/tmp_900342820 bool(true) bool(true) bool(true) /tmp/stack_1102047767 bool(true) bool(true) bool(true) /var/folders/v4/647wm24x2ysdjwx6z_f07_kw0000gp/T/stack_638989419 bool(true) bool(true) bool(true) 

Care to comment on the downvote? I originally landed on this question attempting to solve the problem cleanly, and couldn’t find an answer I was satisfied with using in production, so I wanted to share what I wrote for others that end up here looking for the same thing. SO etiquette prefers that you leave a comment or suggest an edit or improvement when downvoting something.

I like your solution but if the code in the loop fails too many times it’ll just return the most-recently-attempted path rather than indicating that it failed to find a valid path, which could make code that uses this function fail.

Читайте также:  visibility

Another option if running on linux with mktemp and access to the exec function is the following:

XXXXXX"; if (($dir) && (is_dir($dir))) < $tmpdir = "--tmpdir=$dir"; >else < $tmpdir = '--tmpdir=' . sys_get_temp_dir(); >return exec("mktemp -d $tmpdir $template"); > /*example*/ $dir = tempdir(); echo "$dir\n"; rmdir($dir); $dir = tempdir('/tmp/foo', 'bar'); echo "$dir\n"; rmdir($dir); // returns: // /tmp/BN4Wcd // /tmp/foo/baruLWFsN (if /tmp/foo exists, /tmp/baruLWFsN otherwise) ?> 

This avoids the potential (although unlikely) race issue above and has the same behavior as the tempnam function.

I think this could blow up if $dir contained spaces. It would be safer to do $tmpdir = «—tmpdir=» . addslashes($dir);

I wanted to add a refinement to @Mario Mueller’s answer, as his is subject to possible race conditions, however I believe the following should not be:

function tempdir(int $mode = 0700): string < do < $tmp = sys_get_temp_dir() . '/' . mt_rand(); >while (!@mkdir($tmp, $mode)); return $tmp; > 

This works because mkdir returns false if $tmp already exists, causing the loop to repeat and try another name.

Note also that I’ve added handling for $mode , with a default that ensures the directory is accessible to the current user only, as mkdir ‘s default is 0777 otherwise.

It is strongly advised that you use a shutdown function to ensure the directory is removed when no longer needed, even if your script exits by unexpected means*. To facilitate this, the full function that I use does this automatically unless the $auto_delete argument is set to false .

// Deletes a non-empty directory function destroydir(string $dir): bool < if (!is_dir($dir)) < return false; >$files = array_diff(scandir($dir), ['.', '..']); foreach ($files as $file) < if (is_dir("$dir/$file")) < destroydir("$dir/$file"); >else < unlink("$dir/$file"); >> return rmdir($dir); > function tempdir(int $mode = 0700, bool $auto_delete = true): string < do < $tmp = sys_get_temp_dir() . '/' . mt_rand(); >while (!@mkdir($tmp, $mode)); if ($auto_delete) < register_shutdown_function(function() use ($tmp) < destroydir($tmp); >); > return $tmp; > 

This means that by default any temporary directory created by tempdir() will have permissions of 0700 and will be automatically deleted (along with its contents) when your script ends.

NOTE: *This may not be the case if the script is killed, for this you might need to look into registering a signal handler as well.

Источник

Create temporary file and auto removed

I am writing a anti-leeching download script, and my plan is to create a temporary file, which is named by session ID, then after the session expires, the file will be automatically deleted. Is it possible ? And can you give me some tips how to do that in PHP ? Thanks so much for any reply

Could you please be more specific about what you are trying to achieve? Anti-Leeching DL Script is a bit vague. What is the UseCase or problem the script is trying to solve?

Hi lkke, I just want to let the user download in his/her session only, like he can’t simply copy & paste the link to somebody else Hi Gordon, I want to force the users to download files from my site, control the speed. So, I think to create a temporary file in a temporary directory in HTTP docs so user can download them and then removed them (automatically) after session expires

7 Answers 7

PHP has a function for that name tmpfile. It creates a temporary file and returns a resource. The resource can be used like any other resource.

Читайте также:  Сумму всех значений javascript

E.g. the example from the manual:

The file is automatically removed when closed (using fclose()), or when the script ends. You can use any file functions on the resource. You can find these here. Hope this will help you?

Another solution would be to create the file in the regular way and use a cronjob to regular check if a session is expired. The expiration date and other session data could be stored in a database. Use the script to query that data and determine if a session is expired. If so, remove it physically from the disk. Make sure to run the script once an hour or so (depending on your timeout).

I don’t think that’s a solution for mrblue’s question cause the file is deleted on script end/fclose() and not when the session expires.

You’re right I guess. Must have been reading over that part. Added more information to my post. It’s now up to him 😉

Hi TheGrandWazoo, thanks for your answer. I have thought about that solution, but it couldn’t be possible due toe the performance issue if the site scales up and Philippe is right, my concern is that PHP supports «hook» function, like automatically called after the session expires or starts.

There is no need to involve a database when using a cronjob. When the dl files share the name of the session file for this user, the script called by cron just has to remove all dl files for which currently no sessionfile exists.

So we have one or more files available for download. Creating a temporary file for each download requests is not a good idea. Creating a symlink() for each file instead is a much better idea. This will save loads of disk space and keep down the server load.

Naming the symlink after the user’s session is a decent idea. A better idea is to generate a random symlink name & associate with the session, so the script can handle multiple downloads per session. You can use session_set_save_handler() (link) and register a custom read function that checks for expired sessions and removes symlinks when the session has expired.

Hi Philippe, Yes, I really want to user $_SESSION (actually I did), but I can’t find any document or topic to mention about something, like «hook» action, for example: we can make a function that the system automatically called after a session expire or start. That is my idea and concern. Thank for your time

go the other way. react when a new session is created (eg. $_SESSION is empty and you filled it previously), not when a session expires. the problem is, a session can expire without any action taken by the user (session is out of date and removed by the garbage collector). what are you trying to do exactly?

Ok, so we have the following requirements so far

  1. Let the user download in his/her session only
  2. no copy & paste the link to somebody else
  3. Users have to download from the site, e.g. no hotlinking
  4. Control speed
Читайте также:  Html input text font size css

Let’s see. This is not working code, but it should work along these lines:

Hi Gordon, That is nearly 90% that what I was writing in my code, but yours have a better security check with token. Much appreciated for that.

The token adds security, but it also makes that you dont have to symlink or copy your files anymore, because the token is unique for session+file. The token is basically what pygorex1 would create for a symlink name. Just instead of creating a symlink from it which you later would have to remove somehow, you just send the name/token with the regular fileId. Less maintenance.

I’d suggest you not to copy the file in the first place. I’d do the following: when user requests the file, you generate a random unique string to give him the link this way: dl.php?k=hd8DcjCjdCkk123 then put this string to a database, storing his IP address, maybe session and the time you’ve generated the link. Then another user request that file, make sure all the stuff (hash, ip and so on) matches and the link is not expired (e.g. not more that N hours have passed since the generation) and if everything is OK, use PHP to pipe the file. Set a cron job to look through the DB and remove the expired entries. What do you think?

Creates a temporary file with a unique name in read-write (w+) mode and returns a file handle. The file is automatically removed when closed (using fclose()), or when the script ends.

I don’t think that’s a solution for mrblue’s question cause the file is deleted on script end/fclose() and not when the session expires.

Hi roddik, Philippe was right, I thought about that solution, but it is not applicable in my circumstance especially the performance issue

Maybe it’s to late for answering but I’m try to share on feature googlize!

if you use CPanel there is a short and quick way for blocking external request on your hosted files which name is: HotLink.

you can Enable HotLinks on you Cpanel and be sure nobody can has request o your file from another hosting or use your files as a download reference.

To acheive this, I would make one file and protect it using chmod — making it unavailable to the public. Or, alternatively, save the contents in a database table row, fetch it whenever required.

Making it downloadable as a file. To do so, I would get the contents from the protected file, or if it is stored in a database table, fetch it and simply output it. Using php headers, I would, give it a desired name, extension, specify it’s type, and finally force the browser to download the output as a solid file.

This way, you only need to save data in one place either, in a protected file or in database. Force client browser to download it as many times as the the conditions meet e.g., as long as the user is logged-in and so on. Without having to worry about the disk space, making any temp file, cronJobs and or auto-deletion of the file.

Источник

Оцените статью