Atualizar
Resolvi o problema e postei uma resposta. No entanto, minha solução não é 100% ideal. Eu preferiria apenas remover o symlink
do cache
with clearstatcache(true, $target)
ou clearstatcache(true, $link)
mas isso não funciona.
Também prefiro evitar o cache de links simbólicos em primeiro lugar ou remover o link simbólico do cache imediatamente após gerá-lo. Infelizmente, não tive sorte com isso. Por algum motivo, clearstatcache(true)
após a criação de um link simbólico não funcionar, ele ainda é armazenado em cache.
Felizmente, darei a recompensa a qualquer pessoa que possa melhorar minha resposta e resolver esses problemas.
Editar
Tentei otimizar meu código gerando um arquivo sempre que clearstatcache
for executado, para que eu só precise limpar o cache uma vez para cada link simbólico. Por alguma razão, isso não funciona. clearstatcache
precisa ser chamado toda vez que um symlink
é incluído no caminho, mas por quê? Deve haver uma maneira de otimizar a solução que tenho.
Eu estou usando PHP 7.3.5
com nginx/1.16.0
. Às vezes, file_get_contents
retorna o valor errado ao usar a symlink
. O problema ocorre após excluir e recriar um link simbólico; seu valor antigo permanece no cache. Às vezes, o valor correto é retornado, às vezes o valor antigo. Parece aleatório.
Eu tentei limpar o cache ou impedir o cache com:
function symlink1($target, $link)
{
realpath_cache_size(0);
symlink($target, $link);
//clearstatcache(true);
}
Eu realmente não quero desativar o cache, mas ainda preciso de 100% de precisão com file_get_contents.
Editar
Não consigo postar meu código-fonte, pois é muito longo e complexo, por isso criei um exemplo mínimo e reproduzível (index.php) que recria o problema:
<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>
Parecia muito provável que fosse um problema com a Nginx
configuração. Não ter essas linhas pode causar o problema:
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
Aqui está minha Nginx
configuração (você pode ver que eu incluí as linhas acima):
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;
}
Atualmente, tenho o exemplo acima ao vivo em https://www.websemantica.co.uk .
Tente adicionar alguns valores no formulário. Ele deve aparecer Success!
em azul sempre. Às vezes é mostra Failure!
em vermelho. Pode levar algumas atualizações de página para mudar de Success!
para Failure!
ou vice-versa. Eventualmente, ele será exibido Success!
sempre, portanto, deve haver algum tipo de problema de armazenamento em cache.
realpath
página de funções . Talvez isso possa te ajudar.realpath
comfile_get_conents
e sem sorte. Às vezes, ainda é carregado do cache.realpath
, mas algo comoclearstatcache(true); file_get_conents(realpath($fileName));
Respostas:
Depende demais do nível do sistema operacional. Então, que tal tentar pensar fora da caixa. Que tal tentar ler a localização real do arquivo
readlink
e usar esse caminho de localização real?fonte
Este é o comportamento desejado do PHP, você pode ver isso aqui, porque o PHP usa
realpath_cache
para armazenar os caminhos de arquivo devido a aprimoramentos de desempenho, para que possa reduzir as Operações de Disco.Para evitar esse comportamento, talvez você possa tentar limpar o
realpath_cache
antes de usar aget_file_contents
funçãoVocê pode tentar algo como isto:
Você pode ler mais sobre o clearstatcache no PHP doc.
fonte
Existem dois caches.
Primeiro, o cache do sistema operacional e, em seguida, o cache do PHP.
Na maioria dos casos,
clearstatcache(true)
antesfile_get_contents(...)
faz o trabalho.Mas às vezes você também precisa limpar o cache do SO. No caso do Linux, lá posso pensar em dois lugares para limpar. PageCache (1) e dentries / inodes (2).
Isso limpa os dois:
Nota: Isso é bom para solucionar problemas, mas não para chamadas frequentes na produção, pois limpa todo o cache do SO e custa ao sistema alguns momentos de re-preenchimento do cache.
fonte
Como você exclui o link simbólico? A exclusão de um arquivo (ou um link simbólico) deve limpar automaticamente o cache.
Caso contrário, você poderá ver o que acontece se:
Se isso não resolver o problema, poderia ser um problema com o nginx, como nesta edição ?
Tente registrar todas as operações em um arquivo de log para ver o que realmente acontece.
ou talvez...
... você poderia fazer sem links simbólicos completamente ? Por exemplo, armazene em um banco de dados, memcache, arquivo SQLite ou mesmo em um arquivo JSON o mapeamento entre "nome do arquivo" e "destino real do link simbólico". Usando, por exemplo, redis ou outras lojas de chaves, você pode associar o "nome do arquivo" ao destino real do link simbólico e ignorar completamente a resolução do SO.
Dependendo do caso de uso, isso pode até ser mais rápido do que usar links simbólicos.
fonte
Houve dois problemas que causaram o problema.
Primeira edição
Eu já postei como e editei na pergunta. É um problema com a configuração do Nginx.
Estas linhas:
necessário substituído por:
Segunda edição
A segunda questão era que eu precisava ligar
clearstatcache
antes de ligarfile_get_contents
. Eu só quero chamarclearstatcache
quando for absolutamente necessário, então escrevi uma função que apenas limpa o cache quando o diretório inclui asymlink
.fonte
Estou deixando minha primeira resposta, pois ainda é uma resposta válida. Estou melhorando a resposta @DanBray implementando clearstatcache (true, $ filename).
Testei o código acima com meu servidor web e funcionou.
fonte
file_get_contents1
faz parte da estrutura que criei, por isso é muito utilizada, o que torna a otimização importante.$dir_go=readdir("$realPath")
retorna nulo.While($dir_go!==null)
@DanBrayTente colocar o código dentro de um elemento que é continuamente atualizado usando o Jquery, além de forçar a revalidação e limpar a captura estática. Este código foi modificado a partir da resposta original @naveed .
form.php:
profile.php:
fonte