Actualizar
Resolví el problema y publiqué una respuesta. Sin embargo, mi solución no es 100% ideal. Preferiría eliminar solo symlink
el cache
con clearstatcache(true, $target)
o clearstatcache(true, $link)
pero eso no funciona.
También preferiría evitar el almacenamiento en caché de enlaces simbólicos en primer lugar o eliminar el enlace simbólico del caché inmediatamente después de generarlo. Lamentablemente, no tuve suerte con eso. Por alguna razón, clearstatcache(true)
después de crear un enlace simbólico no funciona, todavía se almacena en caché.
Con mucho gusto otorgaré la recompensa a cualquiera que pueda mejorar mi respuesta y resolver esos problemas.
Editar
Intenté optimizar mi código generando un archivo cada vez que clearstatcache
se ejecuta, por lo que solo necesito borrar el caché una vez para cada enlace simbólico. Por alguna razón, esto no funciona. clearstatcache
necesita ser llamado cada vez que a symlink
está incluido en el camino, pero ¿por qué? Debe haber una manera de optimizar la solución que tengo.
Estoy usando PHP 7.3.5
con nginx/1.16.0
. A veces file_get_contents
devuelve el valor incorrecto cuando se usa a symlink
. El problema es que después de eliminar y recrear un enlace simbólico, su valor anterior permanece en la memoria caché. A veces se devuelve el valor correcto, a veces el valor anterior. Parece aleatorio.
Intenté borrar el caché o evitar el almacenamiento en caché con:
function symlink1($target, $link)
{
realpath_cache_size(0);
symlink($target, $link);
//clearstatcache(true);
}
Realmente no quiero deshabilitar el almacenamiento en caché, pero todavía necesito una precisión del 100% con file_get_contents.
Editar
No puedo publicar mi código fuente, ya que es demasiado largo y complejo, así que he creado un ejemplo mínimo y reproducible (index.php) que recrea el 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>
Parecía muy probable que fuera un problema con la Nginx
configuración. No tener estas líneas puede causar el problema:
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
Aquí está mi Nginx
configuración (puede ver que he incluido las líneas anteriores):
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;
}
Actualmente tengo el ejemplo anterior en vivo en https://www.websemantica.co.uk .
Intente agregar algunos valores en el formulario. Debería mostrarse Success!
en azul cada vez. A veces se muestra Failure!
en rojo. Se puede tomar un buen número de actualizaciones de página para cambiar de Success!
a Failure!
o viceversa. Eventualmente, se mostrará Success!
cada vez, por lo tanto, debe haber algún tipo de problema de almacenamiento en caché.
realpath
con file_get_conents
y sin suerte. Todavía a veces se carga desde el caché.
realpath
algo comoclearstatcache(true); file_get_conents(realpath($fileName));
realpath
página de funciones . Tal vez podría ayudarte.