124 lines
3.9 KiB
PHP
124 lines
3.9 KiB
PHP
<?php
|
|
namespace nur\b\io;
|
|
|
|
use nur\v\http;
|
|
|
|
/**
|
|
* Class TmpfileWriter: écriture dans un fichier temporaire
|
|
*/
|
|
class TmpfileWriter extends FileWriter {
|
|
/** @var string */
|
|
private $output;
|
|
|
|
/** @var bool */
|
|
private $delete;
|
|
|
|
/** @throws IOException */
|
|
function __construct(?string $destdir=null, string $mode="w+") {
|
|
if ($destdir === null) $destdir = sys_get_temp_dir();
|
|
if (is_dir($destdir)) {
|
|
# si on spécifie un répertoire, créer un fichier temporaire dedans
|
|
$output = tempnam($destdir, "tmp_nur-base_");
|
|
$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
|
|
$output = $destdir;
|
|
$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");
|
|
}
|
|
$output = $destdir;
|
|
$this->delete = false;
|
|
}
|
|
$this->output = $output;
|
|
parent::__construct($output, $mode);
|
|
}
|
|
|
|
function __destruct() {
|
|
$this->close();
|
|
if ($this->delete) $this->delete();
|
|
}
|
|
|
|
/**
|
|
* obtenir une nouvelle instance de {@link FileReader} sur le fichier
|
|
*
|
|
* cette méthode est utile si le flux a été fermé, à condition que le fichier
|
|
* n'aie pas été supprimé ni renommé
|
|
*
|
|
* @throws IOException
|
|
*/
|
|
function getReader(): FileReader {
|
|
return new FileReader($this->output);
|
|
}
|
|
|
|
/**
|
|
* obtenir une nouvelle instance de FileWriter sur le fichier
|
|
*
|
|
* cette méthode est utile si le flux a été fermé, à condition que le fichier
|
|
* n'aie pas été supprimé ni renommé
|
|
*
|
|
* @throws IOException
|
|
*/
|
|
function getWriter(): FileWriter {
|
|
return new FileWriter($this->output);
|
|
}
|
|
|
|
/** supprimer le fichier. NB: le flux **n'est pas** fermé au préalable */
|
|
function delete(): self {
|
|
if (file_exists($this->output)) unlink($this->output);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* renommer le fichier. le flux est fermé d'abord
|
|
*
|
|
* @param int|null $default_mode 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 $set_owner 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 $default_mode=0644, bool $set_owner=true): void {
|
|
$this->close();
|
|
$output = $this->output;
|
|
if (file_exists($dest)) {
|
|
$mode = fileperms($dest);
|
|
if ($set_owner) {
|
|
$tmpowner = fileowner($output);
|
|
$owner = fileowner($dest);
|
|
$tmpgroup = filegroup($output);
|
|
$group = filegroup($dest);
|
|
} else {
|
|
$owner = $group = null;
|
|
}
|
|
} else {
|
|
$mode = $default_mode;
|
|
$owner = $group = null;
|
|
}
|
|
if (!rename($output, $dest)) {
|
|
throw new IOException("$output: unable to rename to $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();
|
|
}
|
|
|
|
/** streamer le contenu du fichier en sortie */
|
|
function readfile(?string $content_type=null, ?string $charset=null, ?string $filename=null, string $disposition=null): bool {
|
|
if ($content_type !== null) http::content_type($content_type, $charset);
|
|
if ($filename !== null) http::download_as($filename, $disposition);
|
|
return readfile($this->output) !== false;
|
|
}
|
|
}
|