Memperbarui
Saya memecahkan masalah dan mengirim jawaban. Namun, solusi saya tidak 100% ideal. Saya lebih suka hanya menghapus symlink
dari cache
dengan clearstatcache(true, $target)
atau clearstatcache(true, $link)
tetapi itu tidak berhasil.
Saya juga lebih suka mencegah caching symlink di tempat pertama atau menghapus symlink dari cache segera setelah membuatnya. Sayangnya, saya tidak beruntung dengan itu. Untuk beberapa alasan clearstatcache(true)
setelah membuat symlink tidak berfungsi, itu masih di-cache.
Saya akan dengan senang hati memberikan hadiah kepada siapa pun yang dapat meningkatkan jawaban saya dan menyelesaikan masalah-masalah itu.
Edit
Saya telah berusaha untuk mengoptimalkan kode saya dengan menghasilkan file setiap kali clearstatcache
dijalankan, sehingga saya hanya perlu menghapus cache sekali untuk setiap symlink. Untuk beberapa alasan, ini tidak berhasil. clearstatcache
perlu dipanggil setiap kali a symlink
termasuk di jalan, tapi mengapa? Pasti ada cara untuk mengoptimalkan solusi yang saya miliki.
Saya menggunakan PHP 7.3.5
dengan nginx/1.16.0
. Terkadang file_get_contents
mengembalikan nilai yang salah saat menggunakan a symlink
. Masalahnya adalah setelah menghapus dan menciptakan kembali symlink, nilainya yang lama tetap ada di cache. Terkadang nilai yang benar dikembalikan, terkadang nilai lama. Tampaknya acak.
Saya sudah mencoba menghapus cache atau mencegah caching dengan:
function symlink1($target, $link)
{
realpath_cache_size(0);
symlink($target, $link);
//clearstatcache(true);
}
Saya tidak benar-benar ingin menonaktifkan caching tetapi saya masih membutuhkan akurasi 100% dengan file_get_contents.
Edit
Saya tidak dapat memposting kode sumber saya, karena terlalu panjang dan rumit, jadi saya telah membuat contoh minimal yang dapat direproduksi (index.php) yang menciptakan masalah:
<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>
Tampaknya sangat mungkin menjadi masalah dengan Nginx
konfigurasi. Tidak memiliki garis-garis ini dapat menyebabkan masalah:
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
Ini adalah Nginx
konfigurasi saya (Anda dapat melihat saya telah menyertakan baris di atas):
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;
}
Saat ini saya memiliki contoh di atas secara langsung di https://www.websemantica.co.uk .
Coba tambahkan beberapa nilai dalam formulir. Itu harus ditampilkan Success!
dengan warna biru setiap kali. Terkadang ditampilkan Failure!
dalam warna merah. Mungkin diperlukan beberapa kali penyegaran halaman untuk berubah dari Success!
menjadi Failure!
atau sebaliknya. Akhirnya, itu akan ditampilkan Success!
setiap waktu, oleh karena itu harus ada semacam masalah caching.
realpath
halaman fungsi . Mungkin itu bisa membantu Anda.realpath
denganfile_get_conents
dan tidak berhasil. Kadang-kadang masih memuat dari cache.realpath
, tetapi sesuatu seperticlearstatcache(true); file_get_conents(realpath($fileName));
Jawaban:
Ini terlalu tergantung pada level OS. Jadi bagaimana kalau memikirkan kotak. Bagaimana kalau mencoba membaca lokasi file sebenarnya
readlink
, dan menggunakan jalur lokasi sebenarnya?sumber
Ini adalah perilaku yang diinginkan dari PHP Anda dapat melihat ini di sini karena PHP digunakan
realpath_cache
untuk menyimpan path file karena peningkatan kinerja sehingga dapat mengurangi Operasi Disk.Untuk menghindari perilaku ini, mungkin Anda dapat mencoba menghapusnya
realpath_cache
sebelum menggunakanget_file_contents
fungsinyaAnda dapat mencoba sesuatu seperti ini:
Anda dapat membaca lebih lanjut untuk clearstatcache di PHP doc.
sumber
Ada dua cache.
Pertama cache OS dan kemudian cache PHP.
Dalam sebagian besar kasus
clearstatcache(true)
sebelumfile_get_contents(...)
melakukan pekerjaan.Namun terkadang Anda juga perlu menghapus cache OS. Dalam kasus Linux, di sana saya bisa memikirkan dua tempat untuk dibersihkan. PageCache (1) dan gigi palsu / inode (2).
Ini membersihkan keduanya:
Catatan: Ini bagus untuk pemecahan masalah tetapi tidak untuk panggilan yang sering dalam produksi karena membersihkan seluruh cache OS dan biaya sistem beberapa saat cache re-populasi.
sumber
Bagaimana Anda menghapus symlink? Menghapus file (atau symlink) akan secara otomatis menghapus cache.
Kalau tidak, Anda bisa melihat apa yang terjadi jika Anda melakukannya:
Jika ini tidak menyelesaikan masalah, mungkinkah ini menjadi masalah dengan nginx seperti dalam masalah ini ?
Coba masuk semua operasi ke file log, untuk melihat apa yang sebenarnya terjadi.
atau mungkin...
... bisakah Anda melakukannya tanpa symlink sama sekali ? Misalnya, simpan dalam database, memcache, file SQLite, atau bahkan file JSON pemetaan antara "nama file" dan "target symlink yang sebenarnya". Menggunakan mis redis atau keystores lainnya, Anda dapat mengaitkan "nama file" dengan target symlink asli dan memotong resolusi OS sepenuhnya.
Bergantung pada use case, ini bahkan bisa berubah menjadi lebih cepat daripada menggunakan symlink.
sumber
Ada dua masalah yang menyebabkan masalah.
Masalah pertama
Saya sudah memposting dan mengedit dalam pertanyaan. Ini masalah dengan konfigurasi Nginx.
Garis-garis ini:
perlu diganti dengan:
Masalah kedua
Masalah kedua adalah saya harus menelepon
clearstatcache
sebelum meneleponfile_get_contents
. Saya hanya ingin meneleponclearstatcache
ketika itu benar-benar diperlukan, jadi saya menulis sebuah fungsi yang hanya membersihkan cache ketika direktori menyertakan asymlink
.sumber
Saya meninggalkan jawaban pertama saya karena masih merupakan jawaban yang valid. Saya memperbaiki jawaban @DanBray dengan menerapkan clearstatcache (true, $ filename).
Saya menguji kode di atas dengan server web saya dan ternyata berhasil.
sumber
file_get_contents1
merupakan bagian dari kerangka kerja yang telah saya buat, jadi ini banyak digunakan, yang membuat optimasi menjadi penting.$dir_go=readdir("$realPath")
mengembalikan nol.While($dir_go!==null)
@DanBrayCobalah menempatkan kode di dalam elemen yang terus disegarkan menggunakan Jquery serta memaksa validasi ulang dan menghapus tangkapan statis. Kode ini telah dimodifikasi dari jawaban asli @naveed .
form.php:
profile.php:
sumber