php - pagina - Haciendo un directorio temporal para descomprimir un archivo zip en
descomprimir zip en filezilla (7)
Así que primero encontré una publicación de Ron Korving en PHP.net , que luego modifiqué para hacer un poco más seguro (de bucles infinitos, caracteres no válidos y direcciones de padres no grabables) y usar un poco más de entropía.
<?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;
}
?>
Por lo tanto, vamos a probarlo:
<?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));
?>
Resultado:
/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)
Tengo un script que comprueba un archivo zip que contiene varios archivos de texto + PDF coincidentes. Quiero desempaquetar, o de alguna manera leer los archivos de texto del archivo zip, y simplemente seleccionar información del archivo de texto para ver si la versión del archivo es correcta.
Estaba buscando en la función tempnam()
para encontrar un equivalente para hacer un tempdir, pero tal vez alguien tenga una mejor solución para el problema.
El archivo de índice se ve algo como esto. ( ->
es para caracteres TAB). He hecho la función para extraer la versión del archivo de texto y verificar si ya es correcta, solo estoy desempaquetando, tmpdir o alguna otra solución que esté buscando.
1000->filename->file version->program version->customer no->company no->distribution
2000->pagenumber->more info->more info->...
Bastante fácil (en parte lo tomé del manual de 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
Consulte: http://de.php.net/manual/en/function.tempnam.php
Por favor, mire la solución de Will a continuación.
=> Mi respuesta ya no debería ser la respuesta aceptada.
Hay muchas respuestas excesivas a esta pregunta. Una respuesta simple sería:
$tempdir = tempnam(sys_get_temp_dir()) . ''dir'';
mkdir($tempdir);
- Obtener un nombre de archivo temporal.
- Cree el directorio (agregue un sufijo al archivo temporal, para evitar la colisión del nombre del archivo).
- Hecho.
La función "mkdir" genera una advertencia si el directorio ya existe, por lo que puede detectarlo usando "@mkdir" y evitar cualquier condición de carrera:
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;
}
Otra opción si se ejecuta en Linux con mktemp
y el acceso a la función exec
es la siguiente:
<?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)
?>
Esto evita el problema de carrera potencial (aunque poco probable) anterior y tiene el mismo comportamiento que la función tempnam
.
Otra posibilidad es usar el archivo temporal como un tipo de semáforo para garantizar la unicidad del nombre del directorio. Luego, cree un directorio cuyo nombre se base en el nombre del archivo.
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);
}
/* ************************************************************************** */
Quería agregar un refinamiento a la respuesta de @Mario Mueller, ya que está sujeto a posibles condiciones de carrera, sin embargo, creo que lo siguiente no debería ser:
function tempdir(int $mode = 0700): string {
do { $tmp = sys_get_temp_dir() . ''/'' . mt_rand(); }
while (!@mkdir($tmp, $mode));
return $tmp;
}
Esto funciona porque mkdir
devuelve false
si ya existe $tmp
, lo que hace que el bucle se repita e intente con otro nombre.
Tenga en cuenta también que he agregado el manejo para $mode
, con un valor predeterminado que garantiza que el directorio sea accesible solo para el usuario actual, ya que el valor predeterminado de mkdir
es 0777
.
Se recomienda encarecidamente que utilice una función de apagado para asegurarse de que el directorio se elimine cuando ya no sea necesario, incluso si su script se cierra por medios inesperados *. Para facilitar esto, la función completa que uso lo hace automáticamente a menos que el argumento $auto_delete
esté establecido en 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;
}
Esto significa que, de forma predeterminada, cualquier directorio temporal creado por tempdir()
tendrá permisos de 0700
y se eliminará automáticamente (junto con su contenido) cuando finalice la secuencia de comandos.
NOTA : * Puede que este no sea el caso si se elimina la secuencia de comandos, ya que es posible que también deba registrar el registro de un controlador de señales.