Создание временного каталога для распаковки zipfile в

У меня есть скрипт, который проверяет zipфайл, содержащий несколько подходящих файлов PDF + textfiles. Я хочу распаковать или каким-то образом прочитать текстовые файлы из zip-файла и просто выбрать некоторую информацию из текстового файла, чтобы убедиться, что версия файла верна.

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

Индексный файл выглядит примерно так. ( -> для символа TAB). Я сделал функцию для извлечения версии из текстового файла и для проверки ее правильности, ее только распаковка, tmpdir или какое-либо другое решение, которое они ищут.

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

довольно легко (я частично взял его из руководства 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

Помните, что в Linux-системе файл и каталог теоретически одно и то же. Остерегайтесь системы windows;)

Другой вариант, если работает в 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 .

Поэтому я впервые нашел сообщение Рона Корвига на 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, '/'); /* 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; } /* Attenot 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', $dir, $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) 

На этот вопрос много ответов. Один простой ответ:

 $tempdir = tempnam(sys_get_temp_dir()) . 'dir'; mkdir($tempdir); 
  1. Получить временное имя файла.
  2. Создайте каталог (добавьте суффикс в файл temp, чтобы избежать столкновения имени файла).
  3. Готово.

Я хотел добавить уточнение к ответу @Mario Mueller, так как он подвержен возможным условиям гонки, однако я считаю, что следующее не должно быть:

 function tempdir(int $mode = 0700): string { do { $tmp = tempnam(sys_get_temp_dir(),''); } while (!@mkdir($tmp, $mode)); return $tmp; } 

Это работает, потому что mkdir возвращает false если $tmp уже существует, заставляя цикл повторяться и попробовать другое имя.

Обратите также внимание на то, что я добавил обработку для $mode с по умолчанию, которая гарантирует, что каталог доступен только для текущего пользователя, так как по умолчанию mkdir0777 .

Настоятельно рекомендуется использовать функцию выключения, чтобы убедиться, что каталог удален, когда он больше не нужен, даже если ваш скрипт выходит неожиданными средствами *. Чтобы облегчить это, полная функция, которую я использую, делает это автоматически, если аргументу $auto_delete не присвоено $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 = tempnam(sys_get_temp_dir(),''); } while (!@mkdir($tmp, $mode)); if ($auto_delete) { register_shutdown_function(function() use ($tmp) { destroydir($tmp); }); } return $tmp; } 

Это означает, что по умолчанию любой временный каталог, созданный tempdir() будет иметь разрешения 0700 и будет автоматически удален (вместе с его содержимым), когда ваш скрипт закончится.

ПРИМЕЧАНИЕ . * Это может быть не так, если сценарий убит, для этого вам, возможно, потребуется также изучить регистратор сигналов.

Другая возможность – использовать временный файл как своего рода семафор, чтобы гарантировать единство имени каталога. Затем создайте каталог, имя которого основано на имени файла.

 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); } /* ************************************************************************** */ 

Функция «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; }