Php temp file windows

sys_get_temp_dir

(PHP 5 >= 5.2.1, PHP 7, PHP 8)

sys_get_temp_dir — Возвращает путь к директории временных файлов

Описание

Возвращает путь к директории, где PHP по умолчанию хранит временные файлы.

Возвращаемые значения

Возвращает путь к директории временных файлов.

Примеры

Пример #1 Пример использования sys_get_temp_dir()

// Создание временного файла в директории
// временных файлов, используя sys_get_temp_dir()
$temp_file = tempnam ( sys_get_temp_dir (), ‘Tux’ );

Результатом выполнения данного примера будет что-то подобное:

Смотрите также

  • tmpfile() — Создаёт временный файл
  • tempnam() — Создаёт файл с уникальным именем

User Contributed Notes 12 notes

It’s not documented but this function does not send the path with trailing spaces, actually it drops the slash if it exists.

A very helpful thing to note when on Linux:

If you are running PHP from the commandline you can use the environment variable: TMPDIR — to change the location without touching php.ini. — This should work on most versions of PHP.

Example file: test.php
echo sys_get_temp_dir () . PHP_EOL ;
?>

And then running:

php test.php
/tmp

TMPDIR=/custom/location php test.php
/custom/location

This function does not account for virtualhost-specific modifications to the temp path and/or open_basedir:

php_admin_value open_basedir /home/user
php_admin_value upload_tmp_dir /home/user/tmp
php_admin_value session.save_path /home/user/tmp

Within this config it still returns /tmp

That is important for the purposes of building paths through concatenation to know that sys_get_temp_dir does not include a path separator at the end.

So, sys_get_temp_dir() will return whatever your temp dir is set to, by default:

If you attempted to concatenate another dir name temp and use the following:

That would actually attempt to generate:
/tmpsome_dir

It would likely result in a permission error unless you are running a php script as a super user.

Instead you would want to do:
mkdir( sys_get_temp_dir() . DIRECTORY_SEPARATOR. ‘some_dir’ );

which would create:
/tmp/some_dir

I don’t know if Windows or other platforms include a directory separator at the end. So if you are writing something a bit more general you may want to check for the path separator at the end and if it is not there append it.

tmpfile

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

tmpfile — Создаёт временный файл

Описание

Создаёт временный файл с уникальным именем, открывая его в режиме чтения и записи (w+) и возвращает файловый указатель.

Этот файл автоматически удаляется после закрытия (например, путём вызова функции fclose() или если не осталось ни одной ссылки на указатель файла, возвращаемый tmpfile() ), или при завершении работы скрипта.

Если скрипт неожиданно завершится, временный файл не может быть удалён.

Возвращаемые значения

Возвращает дескриптор файла, аналогичный тому, который возвращает функция fopen() для новых файлов или false в случае возникновения ошибки.

Примеры

Пример #1 Пример использования функции tmpfile()

Результат выполнения данного примера:

Смотрите также

  • tempnam() — Создаёт файл с уникальным именем
  • sys_get_temp_dir() — Возвращает путь к директории временных файлов

User Contributed Notes 7 notes

To get the underlying file path of a tmpfile file pointer:

= tmpfile ();
$path = stream_get_meta_data ( $file )[ ‘uri’ ]; // eg: /tmp/phpFx0513a

I found this function useful when uploading a file through FTP. One of the files I was uploading was input from a textarea on the previous page, so really there was no «file» to upload, this solved the problem nicely:

# Upload setup.inc
$fSetup = tmpfile ();
fwrite ( $fSetup , $setup );
fseek ( $fSetup , 0 );
if (! ftp_fput ( $ftp , «inc/setup.inc» , $fSetup , FTP_ASCII )) <
echo «
Setup file NOT inserted

» ;
>
fclose ( $fSetup );
?>

The $setup variable is the contents of the textarea.

And I’m not sure if you need the fseek($temp,0); in there either, just leave it unless you know it doesn’t effect it.

Since this function may not be working in some environments, here is a simple workaround:

function temporaryFile($name, $content)
<
$file = DIRECTORY_SEPARATOR .
trim(sys_get_temp_dir(), DIRECTORY_SEPARATOR) .
DIRECTORY_SEPARATOR .
ltrim($name, DIRECTORY_SEPARATOR);

register_shutdown_function(function() use($file) <
unlink($file);
>);

at least on Windows 10 with php 7.3.7, and Debian Linux with php 7.4.2,

the mode is not (as the documentation states) ‘w+’ , it is ‘w+b’

(an important distinction when working on Windows systems)

No, the fseek() is necessary — after writing to the file, the file pointer (I’ll use «file pointer» to refer to the current position in the file, the thing you change with fseek()) is at the end of the file, and reading at the end of the file gives you EOF right away, which manifests itself as an empty upload.

Where you might be getting confused is in some systems’ requirement that one seek or flush between reading and writing the same file. fflush() satisfies that prerequisite, but it doesn’t do anything about the file pointer, and in this case the file pointer needs moving.

Читайте также:  Чистая установка windows 10 без загрузочной флешки

tempnam

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

tempnam — Create file with unique file name

Description

Creates a file with a unique filename, with access permission set to 0600, in the specified directory. If the directory does not exist or is not writable, tempnam() may generate a file in the system’s temporary directory, and return the full path to that file, including its name.

Parameters

The directory where the temporary filename will be created.

The prefix of the generated temporary filename.

Note: Only the first 63 characters of the prefix are used. Windows even uses only the first three characters of the prefix.

Return Values

Returns the new temporary filename (with path), or false on failure.

Examples

Example #1 tempnam() example

= tempnam ( «/tmp» , «FOO» );

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

// do here something

Notes

Note: If PHP cannot create a file in the specified directory parameter, it falls back on the system default. On NTFS this also happens if the specified directory contains more than 65534 files.

See Also

  • tmpfile() — Creates a temporary file
  • sys_get_temp_dir() — Returns directory path used for temporary files
  • unlink() — Deletes a file

User Contributed Notes 23 notes

Watch out using a blank $dir as a «trick» to create temporary files in the system temporary directory.

= 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:

= tempnam ( sys_get_temp_dir (), ‘FOO’ ); // good
?>

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:

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.

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.

?>

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)

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.

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.

isn’t transferred:
( tempnam ( sys_get_temp_dir ())); // NULL
?>
also the warning will be generated:
Warning: tempnam() expects exactly 2 parameters, 1 given in php shell code .

>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
if ( $newFileCreated ) <
unlink ( $sysFileName );
return $newFileName ;
>
?>
and get the same semantics as the windows version?

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.

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.

Читайте также:  Удалена служба windows update

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.

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:

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.

Как создать временный файл на PHP, когда функция tmpfile() не подходит

Когда PHP-программисту необходимо создать временный файл, он в мануале находит функцию tmpfile() и после изучения примеров начинает думать, как её лучше применить. Так было и со мной, когда мне потребовалось выгрузить данные сразу во временный файл, а не работать с ними через переменную. Но с файлом, созданным таким образом, в дальнейшем неудобно работать в силу того, что tmpfile() возвращает дескриптор, а не ссылку на локальный файл. Давайте немного углубимся в анатомию временного файла и рассмотрим подводные камни, с которыми мне пришлось столкнуться.

Временные файлы в PHP нужны, например, для загрузки большого количества данных из сети или выгрузки данных из БД. Сохранять мега- или гигабайты дынных в переменной не самая лучшая идея, поскольку потребление памяти интерпретатором и сервером ограничено. Лучшим вариантом является сохранение данных на диске и удаление их по результату обработки. Функция tmpfile() именно так и работает, но в PHP существуют и другие нативные способы, с помощью которых можно организовать работу с временными данными:

Временные данные, созданные через fopen() или tmpfile() , будут уничтожены самим PHP после завершения скрипта или когда вы принудительно закроете ресурс с помощью функции fclose() . Если будет брошено исключение, PHP всё равно уничтожит временные данные, но если вылетит фатальная ошибка или вы просто вызовете exit() , нет гарантий, что временные данные будут удалены.

Получаем URI временного файла

У вас может появиться необходимость «придержать» временные данные и поработать с ними на уровне физических файлов. Этого можно достичь, если открыть поток php://temp/maxmemory:0 или вызвать tmpfile() , а затем, до закрытия ресурса, воспользоваться stream_get_meta_data() , чтобы извлечь метаданные и узнать абсолютный путь к файлу для дальнейших манипуляций:

Какие значения возвращает stream_get_meta_data() хорошо описано в документации, но нас больше интересует абсолютный путь к файлу, связанный с потоком. Его можно извлечь по ключу uri из полученного массива:

В случае с php://temp/maxmemory:0 мы не сможем получить URI файла из метаданных потока, но фактически файл будет создан во временной папке. Функция stream_get_meta_data() по ключу uri будет возвращать название потока. Поэтому для получения URI временного файла на диске, нужно использовать функцию tmpfile() . Другого способа узнать, где физически хранится временный файл, не существует.

Существует класс SplTempFileObject, который является всего лишь ООП-обёрткой на потоком php://temp и не более. Данный класс наследуется от SplFileObject, а тот в свою очередь от SplFileInfo. Это значит, что у SplTempFileObject должны быть доступны такие методы, как getFilename() , getPathInfo() , getSize() , но они не отработают так, как ожидается. Начиная с версии 5.3 закрался баг, который возвращает false для вышеперечисленных методов. В версии 7.4 ничего не изменилось.

Получив абсолютный путь к временному файлу вы можете пользоваться привычными интерфейсами для работы с данными через файл: symfony/filesystem, symfony/http-foundation, thephpleague/flysystem или нативными PHP-функциями.

Проблемы функции tmpfile()

Когда вы получили URI временного файла и записали в него данные, может потребоваться сохранить этот файл в нужной вам папке на диске. Проще всего и правильнее сделать это через функцию rename() , т. е. просто переименовать файл вместо физического перемещения данных.

К сожалению, сохранить временный файл через rename() не получится, т. к. tmpfile() для Windows накладывает блокирующий режим и файл будет всё ещё занят другим процессом. В UNIX-системах такой проблемы нет, здесь временный файл можно удалять ещё до закрытия ресурса. Другими словами, для Windows вызов rename() до fclose() приведёт к ошибке:

Использовать rename() после fclose() не целесообразно, т. к. после закрытия ресурса PHP сразу же удалит временный файл. Тем не менее, мы можем сохранить временный файл через копирование, воспользовавшись функцией copy() . Этот способ рабочий, но при копировании временного файла на сервере будет храниться две копии файла до завершения скрипта.

Читайте также:  Collect system information windows

Создание временного файла

Для альтернативного решения создадим свой временный файл, который будет базироваться на функции tempnam() . Функция только создаёт файл с уникальным именем на диске, но автоматическое удаление файла не предусмотрено. Поэтому для его уничтожения нам понадобится написать свой обработчик. Жизненный цикл временного файла будет следующий: создание файла во временной папке -> манипуляции с файлом -> автоматическое удаление.

Первым аргументом указывается расположение временной папки через sys_get_temp_dir() , а вторым — префикс в имени файла. Такой файл доступен для чтения и записи только владельцу, т. к. создаётся с правами 0600 (rw-). Для реализации автоматического удаления файла можно перенести дальнейшую логику в класс, где с помощью __destruct() попробуем удалить файл:

Объект вернёт ссылку на файл, который создала функция tempnam() , т. к. в классе прописан __toString() . Таким образом, мы избавились от работы с ресурсом. Временный файл будет удалён при освобождении всех ссылок на объект или по завершению скрипта, но до того случая, пока не будет вызвана фатальная ошибка, брошено исключение или вызвана функция exit() .

Полагаться на __destruct() плохая идея, т. к. в языках с автоматическим управлением памятью, нельзя быть уверенным на 100% в том, когда он выполнится. Деструктор не должен оставлять объект в нестабильном состоянии, поэтому в PHP обработчики уничтожения и освобождения объекта отделены друг от друга. Обработчик освобождения вызывается, когда движок полностью уверен, что объект больше нигде не применяется.

Для гарантированного удаления временного файла мы можем зарегистрировать свою функцию, которая выполнится в любом случае после завершения скрипта. Делается это с помощью register_shutdown_function() в конструкторе нашего класса:

Мы вынесли обработчик удаления временного файла в статическое замыкание, чтобы отвязать все ссылки от объекта и сохранить вызов __destruct до register_shutdown_function :

Класс TmpFile избегает ситуации, когда на него по умолчанию открыт дескриптор. Теперь можно использовать rename() вместо copy() и не бояться, когда при сохранении временных данных в другой файл на диске хранится две копии до завершения скрипта. Главное не держать открытый дескриптор, чтобы rename() наверняка отработала в Windows.

Также мы получили возможность типизировать временный файл и декларировать его тип через конструктор или методы классов, чтобы быть увереным, что приходит временный файл, а не строка, т. к. в PHP нет валидации на тип resource в сигнатурах.

Пример с загрузкой файлов

Ниже реальный юзкейс, в котором функция tmpfile() не подходит в силу уничтожения временного файла после закрытия ресурса или невозможности использовать rename() для перемещения файла. В этом случае нужно было вернуть временный файл в объекте File из пакета symfony/http-foundation в код, у которого строгая зависимость от этого класса File. Код ниже загружает файл как временный, валидирует его и сохраняет на диске:

Бизнес-логика предполагала валидацию файла на другом уровне и здесь важно было позаботиться об удалении файла в самом начале его пути, если проверка будет провалена. С помощью функции register_shutdown_function() мы можем гарантировать, что временный файл будет удалён, когда скрипт завершится. В сниппете ниже приведён пример того, как был использован класс TmpFile вместо tmpfile() :

В коде создаётся объект временного файла, открывается на него дескриптор и через cURL выкачивается файл по ссылке. Обработка HTTP-статусов и другие параметры cURL в этом сниппете не указаны. В итоге мы закрываем все дескрипторы и отправляем временный файл в нужной обёртке. Решить этот юзкейс через функцию tmpfile() было бы невозможно.

Временный файл в CLI и try-finally

В вебе запросы пользователей живут относительно недолго, но в CLI скрипты могут выполняться бесконечно и гарантировать выполнение функции register_shutdown_function() мы не можем. Скрипт может быть убит на системном уровне или выполнятся так долго, что все временные файлы останутся лежать без их финальной обработки. В консоле лучшим способом удаления временных файлов является использование конструкции try-finally :

Здесь процесс удаления временного файла мы помещаем в блок finally , который выполнится сразу после выхода из коллбека. В долгоживущих консольных приложениях это самый оптимальный способ обработать удаление временного файла, но при фатальных ошибках код до finally не дойдёт, а использование register_shutdown_function() не желательно, поэтому не остаётся ничего другого, как писать валидный код в секции try .

Чем класс TmpFile отличается от tmpfile()

Ниже привожу сравнительную таблицу между new TmpFile() и tmpfile() . Основные отличия заключаются в удалении временного файла: TmpFile удаляет файл по завершению скрипта или при освобождении всех ссылок на него, а tmpfile() — сразу после закрытия ресурса.

На основе идей из этой статьи, я написал менеджер для управления временными файлами, который доступен в репозитории denisyukphp/tmpfile-manager. Менеджер умеет много полезного: 1) настраивать путь к папке с временными файлами; 2) задавать префикс временным файлам; 3) закрывать отрытые ресурсы на временные файлы; 4) автоматически или вручную очищать временные файлы; 5) запускать свой сборщик мусора.

Вы можете использовать TmpFile независимо от менеджера, но TmpFileManager позволяет получить больше контроля над временными файлами и может гарантировать их удаление.

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