Browse Source

reecriture importante des lire_/ecrire_/supprimer_/fichier()

Fichier de test :
<?php

// test de inc_flock :
// #ab -c100 -n1000 http://...../test.php
include('ecrire/inc_version.php3');
supprimer_fichier('ecrire/data/test');
$contenu = "arhcatcl";
ecrire_fichier('ecrire/data/test', $contenu);
if (! lire_fichier('ecrire/data/test', $con))
	spip_log("echec lecture");
else if ($con <> $contenu)
	spip_log("grave: '$contenu' <> '$con'");

?>

Sur le Mac j'arrive à obtenir 1 erreur 'grave' (sur 1000 requetes dont 100 simultanées), et encore pas à chaque fois.
svn/attic/branches/spip-1.8.3/5636
Fil 17 years ago
parent
commit
c98f7282c8
  1. 222
      ecrire/inc_flock.php3
  2. 192
      ecrire/inc_version.php3

222
ecrire/inc_flock.php3

@ -0,0 +1,222 @@
<?php
//
// Ce fichier ne sera execute qu'une fois
if (defined("_ECRIRE_INC_FLOCK")) return;
define("_ECRIRE_INC_FLOCK", "1");
// flock() marche dans ce repertoire <=> j'ai le droit de flock() sur ce fichier
if (LOCK_UN!=3) {
define ('LOCK_SH', 1);
define ('LOCK_EX', 2);
define ('LOCK_UN', 3);
define ('LOCK_NB', 4);
}
function test_flock ($fichier, $fp=false) {
static $flock = array();
global $flag_flock;
if (!$flag_flock)
return false;
preg_match('|(.*)/([^/]*)$|', $fichier, $match);
$dir = $match[1];
if ($dir == '')
return false; // a la racine on ne fait que lire
// premier appel pour ce $dir ?
if (!isset($flock[$dir])) {
// si un fichier d'etat flock est la et pas trop vieux -- id est:
// pas recopie depuis une autre installation ! -- c'est ok.
if (@file_exists("$dir/.flock_ok")
AND (filemtime("$dir/.flock_ok") > time() - 3600))
$flock[$dir] = true;
else if (@file_exists("$dir/.flock_naze")
AND (filemtime("$dir/.flock_naze") > time() - 3600))
$flock[$dir] = false;
else {
// pas d'infos de flock, on va tester
$fichiertest = $dir.'/'
.substr(uniqid(@getmypid(), true),-6).".tmp";
if ($fp = @fopen($fichiertest, 'w')) {
if (@flock($fp, LOCK_SH)) {
@flock($fp, LOCK_UN);
$flock[$dir] = true;
@touch("$dir/.flock_ok");
@unlink("$dir/.flock_naze");
spip_log("test $dir: flock ok");
} else {
$flock[$dir] = false;
@touch("$dir/.flock_naze");
@unlink("$dir/.flock_ok");
spip_log("test $dir: flock naze");
}
@unlink($fichiertest);
} else {
spip_log("test $dir: echec du test sur $fichiertest !");
@touch("$dir/.flock_naze");
@unlink("$dir/.flock_ok");
}
}
}
return $flock[$dir];
}
// Si flock ne marche pas dans ce repertoire ou chez cet hebergeur,
// on renvoie OK pour ne pas bloquer
function spip_flock($filehandle, $mode, $fichier) {
if (!test_flock($fichier))
return true;
$r = flock($filehandle, $mode);
// demande de verrou ==> risque de sleep ==> forcer la relecture de l'etat
if ($mode == LOCK_EX)
clearstatcache();
return $r;
}
function spip_file_get_contents ($fichier) {
if (substr($fichier, -3) != '.gz') {
if (function_exists('file_get_contents')
AND $GLOBALS['os_serveur'] !='windows') # windows retourne ''
return @file_get_contents ($fichier);
else
return join('', @file($fichier));
} else
return join('', @gzfile($fichier));
}
// options = array(
// 'phpcheck' => 'oui' # verifier qu'on a bien du php
// dezippe automatiquement les fichiers .gz
function lire_fichier ($fichier, &$contenu, $options=false) {
$contenu = '';
if (!@file_exists($fichier))
return false;
#spip_timer('lire_fichier');
if ($fl = @fopen($fichier, 'r')) {
// verrou lecture
while (!spip_flock($fl, LOCK_SH, $fichier));
// a-t-il ete supprime par le locker ?
if (!@file_exists($fichier)) {
@fclose($fl);
return false;
}
// lire le fichier
$contenu = spip_file_get_contents($fichier);
// liberer le verrou
spip_flock($fl, LOCK_UN, $fichier);
@fclose($fl);
// Verifications
$ok = true;
if ($options['phpcheck'] == 'oui')
$ok &= (ereg("[?]>\n?$", $contenu));
#spip_log("$fread $fichier ".spip_timer('lire_fichier'));
if (!$ok)
spip_log("echec lecture $fichier");
return $ok;
}
}
//
// Ecrire un fichier de maniere un peu sure
//
// zippe les fichiers .gz
function ecrire_fichier ($fichier, $contenu) {
// Ne rien faire si on est en preview ou si une erreur
// grave s'est presentee (compilation du squelette, MySQL, etc)
if ($GLOBALS['var_preview'] OR defined('spip_erreur_fatale'))
return;
$gzip = (substr($fichier, -3) == '.gz');
if ($gzip) {
$fopen = gzopen;
$fputs = gzputs;
$fclose = gzclose;
} else {
$fopen = fopen;
$fputs = fputs;
$fclose = fclose;
}
#spip_timer('ecrire_fichier');
// verrouiller le fichier destination
if ($flock = test_flock($fichier)) {
if ($fp = @fopen($fichier, 'a'))
while (!spip_flock($fp, LOCK_EX, $fichier));
else
return false;
}
// ecrire les donnees, compressees le cas echeant
// (on ouvre un nouveau pointeur sur le fichier, ce qui a l'avantage
// de le recreer si le locker qui nous precede l'avait supprime...)
if ($fo = @$fopen($fichier, 'w'))
$s = @$fputs($fo, $contenu, $a = strlen($contenu));
else
return false;
$ok = ($s == $a);
if (!$ok)
spip_log("echec ecriture fichier $fichier");
#spip_log("$fputs $fichier ".spip_timer('ecrire_fichier'));
// fermer le fichier
@fclose($fo);
// liberer le verrou
if ($flock) {
spip_flock($fp, LOCK_UN, $fichier);
@fclose($fp);
}
return $ok;
}
//
// Supprimer le fichier de maniere sympa (flock)
//
function supprimer_fichier($fichier) {
if (!@file_exists($fichier))
return;
// verrouiller le fichier destination
if ($flock = test_flock($fichier)) {
if ($fp = @fopen($fichier, 'a'))
while (!spip_flock($fp, LOCK_EX, $fichier));
else
return;
}
// supprimer
@unlink($fichier);
// liberer le verrou
if ($flock) {
spip_flock($fp, LOCK_UN, $fichier);
@fclose($fp);
}
}
?>

192
ecrire/inc_version.php3

@ -807,197 +807,9 @@ function quote_amp ($url) {
//
// Lire un fichier de maniere un peu sure
// Module de lecture/ecriture/suppression de fichiers utilisant flock()
//
// flock() marche dans ce repertoire <=> j'ai le droit de flock() sur ce fichier
if (LOCK_UN!=3) {
define ('LOCK_SH', 1);
define ('LOCK_EX', 2);
define ('LOCK_UN', 3);
define ('LOCK_NB', 4);
}
function test_flock ($fichier, $fp=false) {
static $flock = array();
global $flag_flock, $os_serveur;
if (!$flag_flock
OR $os_serveur == 'windows') // sous win rename() plante avec fopen()
return false;
preg_match('|(.*)/([^/]*)$|', $fichier, $match);
$dir = $match[1];
if (!$dir) $dir = '.';
// premier appel pour ce $dir ?
if (!isset($flock[$dir])) {
// si on me passe un pointeur, je teste et j'ecris le resultat
if ($fp) {
if (@flock($fp, LOCK_SH)) {
@flock($fp, LOCK_UN);
@touch("$dir/.flock_ok");
} else
@unlink("$dir/.flock_ok");
}
// si le fichier est la et pas trop vieux -- id est:
// pas recopie depuis une autre installation ! -- c'est ok.
$flock[$dir] = (@file_exists("$dir/.flock_ok")
AND (filemtime("$dir/.flock_ok") > time() - 3600));
}
return $flock[$dir];
}
// Si flock ne marche pas dans ce repertoire ou chez cet hebergeur,
// on renvoie OK pour ne pas bloquer
function spip_flock($filehandle, $mode, $fichier) {
if (!test_flock($fichier))
return true;
$r = flock($filehandle, $mode);
// demande de verrou ==> risque de sleep ==> forcer la relecture de l'etat
if ($mode == LOCK_EX)
clearstatcache();
return $r;
}
function spip_file_get_contents ($fichier) {
global $os_serveur;
if (substr($fichier, -3) != '.gz') {
if (function_exists('file_get_contents')
AND $os_serveur !='windows') # windows retourne ''
return @file_get_contents ($fichier);
else
return join('', file($fichier));
} else
return join('', gzfile($fichier));
}
// options = array(
// 'phpcheck' => 'oui' # verifier qu'on a bien du php
// dezippe automatiquement les fichiers .gz
function lire_fichier ($fichier, &$contenu, $options=false) {
$contenu = '';
if (!@file_exists($fichier))
return false;
#spip_timer('lire_fichier');
if ($fl = @fopen($fichier, 'r')) {
// verrou lecture
while (!spip_flock($fl, LOCK_SH, $fichier));
// lire le fichier
$contenu = spip_file_get_contents($fichier);
// liberer le verrou
spip_flock($fl, LOCK_UN, $fichier);
@fclose($fl);
// Verifications
$ok = true;
if ($options['phpcheck'] == 'oui')
$ok &= (ereg("[?]>\n?$", $contenu));
#spip_log("$fread $fichier ".spip_timer('lire_fichier'));
if (!$ok)
spip_log("echec lecture $fichier");
return $ok;
}
}
//
// Ecrire un fichier de maniere un peu sure
//
// zippe les fichiers .gz
function ecrire_fichier ($fichier, $contenu) {
global $os_serveur;
// Ne rien faire si on est en preview ou si une erreur
// grave s'est presentee (compilation du squelette, MySQL, etc)
if ($GLOBALS['var_preview'] OR defined('spip_erreur_fatale'))
return;
// Ecriture dans un fichier temporaire
// dans le repertoire destination
preg_match('|(.*)/([^/]*)$|', $fichier, $match);
$dir = $match[1];
$fichiertmp = $dir.'/'
.uniqid(substr(md5($fichier),0,6).'-'.@getmypid()).".tmp";
$gzip = (substr($fichier, -3) == '.gz');
if ($gzip) {
$fopen = gzopen;
$fputs = gzputs;
$fclose = gzclose;
} else {
$fopen = fopen;
$fputs = fputs;
$fclose = fclose;
}
#spip_timer('ecrire_fichier');
if ($ft = @$fopen($fichiertmp, 'wb')) {
// on en profite pour tester flock()
$flock = test_flock($fichiertmp, $ft);
$s = @$fputs($ft, $contenu, $a = strlen($contenu));
@$fclose($ft);
$ok = ($s == $a);
}
if ($ok) {
// ouvrir et obtenir un verrou sur le fichier destination
if ($flock AND $fp = @fopen($fichier, 'a'))
while (!spip_flock($fp, LOCK_EX, $fichier));
// recopier le temporaire
if ($os_serveur == 'windows') @unlink("./".$fichier);
$ok = @rename("./".$fichiertmp, "./".$fichier);
// liberer le verrou
if ($flock AND $fp) {
spip_flock($fp, LOCK_UN, $fichier);
@fclose($fp);
}
}
// en cas d'echec effacer le temporaire
if (!$ok) {
spip_log("echec ecriture fichier $fichier");
@unlink($fichiertmp);
}
#spip_log("$fputs $fichier ".spip_timer('ecrire_fichier'));
return $ok;
}
//
// Supprimer un fichier en attendant d'abord de le spip_flock
//
function supprimer_fichier ($fichier) {
if (!@file_exists($fichier))
return false;
if (test_flock($fichier))
if ($fl = @fopen($fichier, 'r')) {
while(!spip_flock($fl, LOCK_EX, $fichier));
spip_flock($fl, LOCK_UN, $fichier);
@fclose($fl);
}
@unlink($fichier);
}
include_ecrire('inc_flock.php3');
//

Loading…
Cancel
Save