nulib/php/src_file/base/TmpfileWriter.php

94 lines
3.1 KiB
PHP

<?php
namespace nulib\file\base;
use nulib\os\IOException;
use nulib\os\path;
/**
* Class TmpfileWriter: un fichier temporaire accédé en lecture/écriture
*/
class TmpfileWriter extends FileWriter {
const DEFAULT_MODE = "w+b";
function __construct(?string $destdir=null, ?string $mode=null, bool $throwOnError=true, ?bool $allowLocking=null) {
$tmpDir = sys_get_temp_dir();
if ($destdir === null) $destdir = $tmpDir;
if (is_dir($destdir)) {
# si on spécifie un répertoire, créer un fichier temporaire dedans
$file = tempnam($destdir, "tmp_nulib_");
$this->delete = true;
} elseif (is_file($destdir)) {
# si on spécifie un fichier qui existe le prendre comme "fichier
# temporaire" mais ne pas le supprimer automatiquement
$file = $destdir;
if (!path::is_qualified($file)) $file = path::join($tmpDir, $file);
$this->delete = false;
} else {
# un chemin qui n'existe pas: ne le sélectionner que si le répertoire
# existe. dans ce cas, le fichier sera créé automatiquement, mais pas
# supprimé
if (!is_dir(dirname($destdir))) {
throw new IOException("$destdir: no such file or directory");
}
$file = $destdir;
$this->delete = false;
}
parent::__construct($file, $mode, $throwOnError, $allowLocking);
}
/** @var bool */
protected $delete;
function __destruct() {
$this->close();
if ($this->delete) $this->delete();
}
/** supprimer le fichier. NB: le flux **n'est pas** fermé au préalable */
function delete(): self {
if (file_exists($this->file)) unlink($this->file);
return $this;
}
/**
* renommer le fichier. le flux est fermé d'abord
*
* @param int|null $defaultMode mode par défaut si le fichier destination
* n'existe pas. sinon, changer le mode du fichier temporaire à la valeur du
* fichier destination après renommage
* @param bool $setOwner si le propriétaire et/ou le groupe du fichier
* temporaire ne sont pas les mêmes que le fichier destination, tenter de
* changer le propriétaire et le groupe du fichier temporaire à la valeur
* du fichier destination après le renommage (nécessite les droits de root)
* @throws IOException
*/
function rename(string $dest, ?int $defaultMode=0644, bool $setOwner=true): void {
$this->close();
$file = $this->file;
if (file_exists($dest)) {
$mode = fileperms($dest);
if ($setOwner) {
$tmpowner = fileowner($file);
$owner = fileowner($dest);
$tmpgroup = filegroup($file);
$group = filegroup($dest);
} else {
$owner = $group = null;
}
} else {
$mode = $defaultMode;
$owner = $group = null;
}
if (!rename($file, $dest)) {
throw new IOException("$file: unable to rename to $dest");
}
$this->file = $dest;
if ($mode !== null) chmod($dest, $mode);
if ($owner !== null) {
if ($owner !== $tmpowner) chown($dest, $owner);
if ($group !== $tmpgroup) chgrp($dest, $group);
}
if ($mode !== null || $owner !== null) clearstatcache(true, $file);
}
}