Создание временного каталога для распаковки zip-файла в
У меня есть скрипт, который проверяет zip-файл, содержащий несколько соответствующих PDF+ текстовых файлов. Я хочу распаковать или как-то прочитать текстовые файлы из zip-файла и просто выбрать некоторую информацию из текстового файла, чтобы убедиться, что версия файла правильная.
Я смотрел на tempnam()
функция, чтобы найти эквивалент для создания tempdir, но, возможно, у кого-то есть лучшее решение проблемы.
Индексный файл выглядит примерно так. (->
для TAB char). Я сделал функцию для извлечения версии из текстового файла и проверки ее правильности, только для распаковки, tmpdir или другого решения, которое я ищу.
1000->filename->file version->program version->customer no->company no->distribution
2000->pagenumber->more info->more info->...
8 ответов
Довольно легко (я частично взял это из руководства по PHP):
<?php
function tempdir() {
$tempfile=tempnam(sys_get_temp_dir(),'');
// you might want to reconsider this line when using this snippet.
// it "could" clash with an existing directory and this line will
// try to delete the existing one. Handle with caution.
if (file_exists($tempfile)) { unlink($tempfile); }
mkdir($tempfile);
if (is_dir($tempfile)) { return $tempfile; }
}
/*example*/
echo tempdir();
// returns: /tmp/8e9MLi
Смотрите: http://de.php.net/manual/en/function.tempnam.php
Пожалуйста, посмотрите на решение Уилла ниже.
=> Мой ответ больше не должен быть принятым ответом.
Итак, я сначала нашел пост Рона Корвинга на PHP.net, который затем изменил, чтобы сделать его немного более безопасным (из бесконечных циклов, недопустимых символов и непереписываемых родительских папок) и использовал немного больше энтропии.
<?php
/**
* Creates a random unique temporary directory, with specified parameters,
* that does not already exist (like tempnam(), but for dirs).
*
* Created dir will begin with the specified prefix, followed by random
* numbers.
*
* @link https://php.net/manual/en/function.tempnam.php
*
* @param string|null $dir Base directory under which to create temp dir.
* If null, the default system temp dir (sys_get_temp_dir()) will be
* used.
* @param string $prefix String with which to prefix created dirs.
* @param int $mode Octal file permission mask for the newly-created dir.
* Should begin with a 0.
* @param int $maxAttempts Maximum attempts before giving up (to prevent
* endless loops).
* @return string|bool Full path to newly-created dir, or false on failure.
*/
function tempdir($dir = null, $prefix = 'tmp_', $mode = 0700, $maxAttempts = 1000)
{
/* Use the system temp dir by default. */
if (is_null($dir))
{
$dir = sys_get_temp_dir();
}
/* 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;
}
?>
Итак, давайте попробуем это:
<?php
echo "\n";
$dir1 = tempdir();
echo $dir1, "\n";
var_dump(is_dir($dir1), is_writable($dir1));
var_dump(rmdir($dir1));
echo "\n";
$dir2 = tempdir('/tmp', 'stack_');
echo $dir2, "\n";
var_dump(is_dir($dir2), is_writable($dir2));
var_dump(rmdir($dir2));
echo "\n";
$dir3 = tempdir(null, 'stack_');
echo $dir3, "\n";
var_dump(is_dir($dir3), is_writable($dir3));
var_dump(rmdir($dir3));
?>
Результат:
/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)
Другой вариант, если работает на Linux с mktemp
и доступ к exec
Функция заключается в следующем:
<?php
function tempdir($dir=NULL,$prefix=NULL) {
$template = "{$prefix}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)
?>
Это позволяет избежать потенциальной (хотя и маловероятной) проблемы расы, описанной выше, и имеет то же поведение, что и tempnam
функция.
Я хотел добавить уточнение к ответу @Mario Mueller, поскольку он зависит от возможных условий гонки, однако я считаю, что следующее не должно быть:
function tempdir(int $mode = 0700): string {
do { $tmp = sys_get_temp_dir() . '/' . mt_rand(); }
while (!@mkdir($tmp, $mode));
return $tmp;
}
Это работает, потому что mkdir
возвращается false
если $tmp
уже существует, в результате чего цикл повторяется и попробуйте другое имя.
Обратите внимание, что я добавил обработку для $mode
со значением по умолчанию, обеспечивающим доступ к каталогу только текущему пользователю, так как mkdir
по умолчанию 0777
иначе.
Настоятельно рекомендуется использовать функцию завершения работы, чтобы обеспечить удаление каталога, когда он больше не нужен, даже если ваш скрипт завершает работу непредвиденным образом *. Чтобы облегчить это, полная функция, которую я использую, делает это автоматически, если $auto_delete
аргумент установлен в 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;
}
Это означает, что по умолчанию любой временный каталог, созданный tempdir()
будет иметь разрешения 0700
и будет автоматически удален (вместе с его содержимым), когда ваш скрипт закончится.
ПРИМЕЧАНИЕ: * Это может быть не так, если скрипт убит, для этого вам может понадобиться также зарегистрировать обработчик сигнала.
Функция "mkdir" выдает предупреждение, если каталог уже существует, так что вы можете перехватить это с помощью "@mkdir" и избежать любых условий гонки:
function tempDir($parent = null)
{
// Prechecks
if ($parent === null) {
$parent = sys_get_temp_dir();
}
$parent = rtrim($parent, '/');
if (!is_dir($parent) || !is_writeable($parent)) {
throw new Exception(sprintf('Parent directory is not writable: %s', $parent));
}
// Create directory
do {
$directory = $parent . '/' . mt_rand();
$success = @mkdir($directory);
}
while (!$success);
return $directory;
}
Есть много излишних ответов на этот вопрос. Один простой ответ будет:
$tempdir = tempnam(sys_get_temp_dir()) . 'dir';
mkdir($tempdir);
- Получить временное имя файла.
- Создайте каталог (добавьте суффикс к временному файлу, чтобы избежать конфликта имен файлов).
- Готово.
На рисунке я получу простой ответ. Просто установите префикс для конкретной строки вашего приложения
$tmpDir = sprintf('%s%sPREFIX-%s', sys_get_temp_dir(), DIRECTORY_SEPARATOR, mt_rand());
mkdir($tmpDir);
Другой возможностью является использование временного файла в качестве своего рода семафора, чтобы гарантировать уникальность имени каталога. Затем создайте каталог, имя которого основано на имени файла.
define ('TMP_DIR', '/tmp'); // sys_get_temp_dir() PHP 5 >= 5.2.1
define ('TMP_DIR_PREFIX', 'tmpdir_');
define ('TMP_DIR_SUFFIX', '.d');
/* ************************************************************************** */
function createTmpDir() {
$tmpFile = tempnam(TMP_DIR, TMP_DIR_PREFIX);
$tmpDir = $tmpFile.TMP_DIR_SUFFIX;
mkdir($tmpDir);
return $tmpDir;
}
function rmTmpDir($tmpDir) {
$offsetSuffix = -1 * strlen(TMP_DIR_SUFFIX);
assert(strcmp(substr($tmpDir, $offsetSuffix), TMP_DIR_SUFFIX) === 0);
$tmpFile = substr($tmpDir, 0, $offsetSuffix);
// Removes non-empty directory
$command = "rm -rf $tmpDir/";
exec($command);
// rmdir($tmpDir);
unlink($tmpFile);
}
/* ************************************************************************** */