Mise à jour
J'ai résolu le problème et publié une réponse. Cependant, ma solution n'est pas idéale à 100%. Je préfère de loin ne retirer que symlink
le cache
avec clearstatcache(true, $target)
ou clearstatcache(true, $link)
mais cela ne fonctionne pas.
Je préfère également empêcher la mise en cache des liens symboliques en premier lieu ou supprimer le lien symbolique du cache immédiatement après l'avoir généré. Malheureusement, je n'ai pas eu de chance avec ça. Pour une raison quelconque, la clearstatcache(true)
création d'un lien symbolique ne fonctionne pas, il est toujours mis en cache.
Je remettrai volontiers la prime à toute personne qui pourra améliorer ma réponse et résoudre ces problèmes.
Éditer
J'ai essayé d'optimiser mon code en générant un fichier à chaque clearstatcache
exécution, de sorte que je n'ai besoin d'effacer le cache qu'une seule fois pour chaque lien symbolique. Pour une raison quelconque, cela ne fonctionne pas. clearstatcache
doit être appelé à chaque fois que a symlink
est inclus dans le chemin, mais pourquoi? Il doit y avoir un moyen d'optimiser la solution que j'ai.
J'utilise PHP 7.3.5
avec nginx/1.16.0
. file_get_contents
Retourne parfois la mauvaise valeur lors de l'utilisation de a symlink
. Le problème est qu'après avoir supprimé et recréé un lien symbolique, son ancienne valeur reste dans le cache. Parfois, la valeur correcte est renvoyée, parfois l'ancienne valeur. Cela semble aléatoire.
J'ai essayé de vider le cache ou d'empêcher la mise en cache avec:
function symlink1($target, $link)
{
realpath_cache_size(0);
symlink($target, $link);
//clearstatcache(true);
}
Je ne veux pas vraiment désactiver la mise en cache mais j'ai toujours besoin d'une précision de 100% avec file_get_contents.
Éditer
Je ne peux pas poster mon code source, car il est beaucoup trop long et complexe, j'ai donc créé un exemple reproductible minimal (index.php) qui recrée le problème:
<h1>Symlink Problem</h1>
<?php
$dir = getcwd();
if (isset($_POST['clear-all']))
{
$nos = array_values(array_diff(scandir($dir.'/nos'), array('..', '.')));
foreach ($nos as $no)
{
unlink($dir.'/nos/'.$no.'/id.txt');
rmdir($dir.'/nos/'.$no);
}
foreach (array_values(array_diff(scandir($dir.'/ids'), array('..', '.'))) as $id)
unlink($dir.'/ids/'.$id);
}
if (!is_dir($dir.'/nos'))
mkdir($dir.'/nos');
if (!is_dir($dir.'/ids'))
mkdir($dir.'/ids');
if (isset($_POST['submit']) && !empty($_POST['id']) && ctype_digit($_POST['insert-after']) && ctype_alnum($_POST['id']))
{
$nos = array_values(array_diff(scandir($dir.'/nos'), array('..', '.')));
$total = count($nos);
if ($total <= 100)
{
for ($i = $total; $i >= $_POST['insert-after']; $i--)
{
$id = file_get_contents($dir.'/nos/'.$i.'/id.txt');
unlink($dir.'/ids/'.$id);
symlink($dir.'/nos/'.($i + 1), $dir.'/ids/'.$id);
rename($dir.'/nos/'.$i, $dir.'/nos/'.($i + 1));
}
echo '<br>';
mkdir($dir.'/nos/'.$_POST['insert-after']);
file_put_contents($dir.'/nos/'.$_POST['insert-after'].'/id.txt', $_POST['id']);
symlink($dir.'/nos/'.$_POST['insert-after'], $dir.'/ids/'.$_POST['id']);
}
}
$nos = array_values(array_diff(scandir($dir.'/nos'), array('..', '.')));
$total = count($nos) + 1;
echo '<h2>Ids from nos directory</h2>';
foreach ($nos as $no)
{
echo ($no + 1).':'.file_get_contents("$dir/nos/$no/id.txt").'<br>';
}
echo '<h2>Ids from using symlinks</h2>';
$ids = array_values(array_diff(scandir($dir.'/ids'), array('..', '.')));
if (count($ids) > 0)
{
$success = true;
foreach ($ids as $id)
{
$id1 = file_get_contents("$dir/ids/$id/id.txt");
echo $id.':'.$id1.'<br>';
if ($id !== $id1)
$success = false;
}
if ($success)
echo '<b><font color="blue">Success!</font></b><br>';
else
echo '<b><font color="red">Failure!</font></b><br>';
}
?>
<br>
<h2>Insert ID after</h2>
<form method="post" action="/">
<select name="insert-after">
<?php
for ($i = 0; $i < $total; $i++)
echo '<option value="'.$i.'">'.$i.'</option>';
?>
</select>
<input type="text" placeholder="ID" name="id"><br>
<input type="submit" name="submit" value="Insert"><br>
</form>
<h2>Clear all</h2>
<form method="post" action="/">
<input type="submit" name="clear-all" value="Clear All"><br>
</form>
<script>
if (window.history.replaceState)
{
window.history.replaceState( null, null, window.location.href );
}
</script>
Cela semblait très probablement être un problème de Nginx
configuration. Ne pas avoir ces lignes peut provoquer le problème:
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
Voici ma Nginx
configuration (vous pouvez voir que j'ai inclus les lignes ci-dessus):
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name www.websemantica.co.uk;
root "/path/to/site/root";
index index.php;
location / {
try_files $uri $uri/ $uri.php$is_args$query_string;
}
location ~* \.php$ {
try_files $uri =404;
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $realpath_root$fastcgi_path_info;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $realpath_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
fastcgi_param HTTPS $https;
# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param REDIRECT_STATUS 200;
fastcgi_index index.php;
fastcgi_read_timeout 3000;
}
if ($request_uri ~ (?i)^/([^?]*)\.php($|\?)) {
return 301 /$1$is_args$args;
}
rewrite ^/index$ / permanent;
rewrite ^/(.*)/$ /$1 permanent;
}
Actuellement, j'ai l'exemple ci-dessus en direct sur https://www.websemantica.co.uk .
Essayez d'ajouter quelques valeurs dans le formulaire. Il devrait s'afficher Success!
en bleu à chaque fois. Est parfois affiché Failure!
en rouge. Le changement de Success!
vers Failure!
ou vice-versa peut prendre quelques rafraîchissements de page . Finalement, il s'affichera à Success!
chaque fois, donc il doit y avoir une sorte de problème de mise en cache.
realpath
page de fonction . Cela pourrait peut-être vous aider.realpath
avecfile_get_conents
et pas de chance. Il se charge encore parfois à partir du cache.realpath
, mais quelque chose commeclearstatcache(true); file_get_conents(realpath($fileName));
Réponses:
Cela dépend trop du niveau du système d'exploitation. Alors que diriez-vous d'essayer de penser à la boîte. Que diriez-vous d'essayer de lire l'emplacement réel du fichier par
readlink
et d'utiliser ce chemin d'accès réel?la source
C'est le comportement souhaité de PHP, vous pouvez le voir ici parce que PHP utilise
realpath_cache
pour stocker les chemins de fichiers en raison des améliorations de performances afin de réduire les opérations sur disque.Pour éviter ce comportement, vous pouvez peut-être essayer de supprimer le
realpath_cache
avant d'utiliser leget_file_contents
fonctionVous pouvez essayer quelque chose comme ceci:
Vous pouvez en savoir plus pour clearstatcache sur PHP doc.
la source
Il y a deux caches.
D'abord le cache OS puis le cache PHP.
Dans la plupart des cas, le travail est effectué
clearstatcache(true)
auparavantfile_get_contents(...)
.Mais parfois, vous devez également vider le cache du système d'exploitation. Dans le cas de Linux, je peux penser à deux endroits à nettoyer. PageCache (1) et denteries / inodes (2).
Cela efface à la fois:
Remarque: Ceci est bon pour le dépannage mais pas pour les appels fréquents en production car il efface tout le cache du système d'exploitation et coûte au système quelques instants de re-remplissage du cache.
la source
Comment supprimez-vous le lien symbolique? La suppression d'un fichier (ou d'un lien symbolique) devrait automatiquement vider le cache.
Sinon, vous pourriez voir ce qui se passe si vous le faites:
Si cela ne résout pas le problème, pourrait-il s'agir d'un problème avec nginx comme dans ce problème ?
Essayez de consigner toutes les opérations dans un fichier journal pour voir ce qui se passe réellement .
ou peut-être...
... pourriez-vous vous passer complètement de liens symboliques ? Par exemple, stockez dans une base de données, memcache, un fichier SQLite ou même un fichier JSON le mappage entre "nom de fichier" et "cible de lien symbolique réel". En utilisant par exemple redis ou d'autres magasins de clés, vous pouvez associer le "nom de fichier" à la cible réelle du lien symbolique et contourner complètement la résolution du système d'exploitation.
Selon le cas d'utilisation, cela peut même s'avérer plus rapide que l'utilisation de liens symboliques.
la source
Deux problèmes ont causé le problème.
Premier numéro
J'ai déjà posté et édité dans la question. C'est un problème avec la configuration Nginx.
Ces lignes:
nécessaire remplacé par:
Deuxième numéro
Le deuxième problème était que je devais appeler
clearstatcache
avant d'appelerfile_get_contents
. Je ne veux appeler queclearstatcache
lorsque c'est absolument nécessaire, j'ai donc écrit une fonction qui n'efface le cache que lorsque le répertoire contient unsymlink
.la source
Je laisse ma première réponse car c'est toujours une réponse valide. J'améliore la réponse @DanBray en implémentant clearstatcache (true, $ filename).
J'ai testé le code ci-dessus avec mon serveur Web et cela a fonctionné.
la source
file_get_contents1
fait partie du cadre que j'ai créé, il est donc beaucoup utilisé, ce qui rend l'optimisation importante.$dir_go=readdir("$realPath")
renvoie null.While($dir_go!==null)
devoir être changé en @DanBrayEssayez de placer le code à l'intérieur d'un élément qui est constamment actualisé à l'aide de Jquery ainsi que de forcer la revalidation et d'effacer les captures statiques. Ce code a été modifié à partir de la réponse originale @naveed .
form.php:
profile.php:
la source