file_get_contents को गलत परिणाम मिल रहे हैं


10

अपडेट करें

मैंने समस्या हल की और एक उत्तर पोस्ट किया। हालाँकि, मेरा समाधान 100% आदर्श नहीं है। मैं बहुत बल्कि केवल symlinkके cacheसाथ clearstatcache(true, $target)या से दूर होगा, clearstatcache(true, $link)लेकिन यह काम नहीं करता है।

मैं भी पहले से सहानुभूति के कैशिंग को रोकने के बजाय बहुत कुछ करूंगा या इसे उत्पन्न करने के तुरंत बाद कैश से सिमलिंक को हटा दूंगा। दुर्भाग्य से, मेरे पास कोई भाग्य नहीं था। किसी कारण के clearstatcache(true)बाद एक सिमलिंक बनाने से काम नहीं होता है, यह अभी भी कैश हो जाता है।

मैं खुशी-खुशी किसी को भी पुरस्कार दूंगा जो मेरे उत्तर को बेहतर बना सके और उन मुद्दों को हल कर सके।

संपादित करें

मैंने हर बार clearstatcacheचलाई गई फ़ाइल को जनरेट करके अपने कोड को ऑप्टिमाइज़ करने का प्रयास किया है, ताकि मुझे केवल प्रत्येक सिम्लिंक के लिए एक बार कैश साफ़ करने की आवश्यकता हो। किसी कारण से, यह काम नहीं करता है। पथ में शामिल होने के लिए clearstatcacheहर बार कॉल करने की आवश्यकता होती है symlink, लेकिन क्यों? मेरे पास जो समाधान है उसे अनुकूलित करने का एक तरीका होना चाहिए।


के PHP 7.3.5साथ उपयोग कर रहा हूं nginx/1.16.0। कभी-कभी file_get_contentsगलत मान लौटाता है जब a symlink। सिम्लिंक को हटाने और फिर से बनाने के बाद समस्या यह है कि इसका पुराना मूल्य कैश में रहता है। कभी-कभी सही मान वापस किया जाता है, कभी-कभी पुराना मूल्य। यह यादृच्छिक प्रतीत होता है।

मैंने कैश साफ़ करने या कैशिंग रोकने की कोशिश की है:

function symlink1($target, $link)
{
    realpath_cache_size(0);
    symlink($target, $link);
    //clearstatcache(true);
}

मैं वास्तव में कैशिंग को अक्षम नहीं करना चाहता, लेकिन मुझे अभी भी file_get_contents के साथ 100% सटीकता की आवश्यकता है।

संपादित करें

मैं अपने स्रोत कोड को पोस्ट करने में असमर्थ हूं, क्योंकि यह बहुत लंबा और जटिल है, इसलिए मैंने एक न्यूनतम, प्रतिलिपि प्रस्तुत करने योग्य उदाहरण (index.php) बनाया है जो समस्या को फिर से बनाता है:

<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>

यह Nginxविन्यास के साथ एक समस्या होने की बहुत संभावना थी । इन लाइनों के न होने से समस्या पैदा हो सकती है:

fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;

यहाँ मेरा Nginxविन्यास है (आप देख सकते हैं कि मैंने उपरोक्त पंक्तियों को शामिल किया है):

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;
}

वर्तमान में मेरे पास उपरोक्त उदाहरण https://www.websemantica.co.uk पर हैं

प्रपत्र में कुछ मान जोड़ने का प्रयास करें। इसे Success!हर बार नीले रंग में प्रदर्शित किया जाना चाहिए । कभी-कभी Failure!लाल रंग में दिखाता है। यह काफी कुछ पृष्ठ रीफ्रेश लेने से बदलने के लिए कर सकते हैं Success!करने के लिए Failure!या इसके विपरीत। आखिरकार, यह Success!हर बार दिखाई देगा , इसलिए किसी प्रकार की कैशिंग समस्या होनी चाहिए।


मैं एक ही मामले के आसपास देख रहा था और realpathफ़ंक्शन पेज पर बहुत उपयोगी टिप्पणी मिली । शायद यह आपकी मदद कर सके।
1325 बजे marv255

@ marv255 मैं उपयोग करने की कोशिश realpathके साथ file_get_conentsऔर कोई भाग्य। यह अभी भी कभी-कभी कैश से लोड होता है।
दान ब्रे

2
मेरा मतलब न केवल realpath, बल्कि कुछ ऐसा हैclearstatcache(true); file_get_conents(realpath($fileName));
marv255

लगातार कॉल के बीच कमांड चलाने का प्रयास करें linux.die.net/man/8/updatedb । हालांकि मुझे यकीन नहीं है कि अगर यह मामला है तो php में समस्या को कैसे हल किया जाए।
Jannes Botis

जवाबों:


3

यह बहुत हद तक OS के स्तर पर निर्भर करता है। तो कैसे बॉक्स के बारे में सोचने की कोशिश करें। कैसे के बारे में फ़ाइल के वास्तविक स्थान को पढ़ने की कोशिश करें readlink, और उस वास्तविक स्थान पथ का उपयोग करें?

$realPath = shell_exec("readlink " . $yourSymlink);
$fileContent = file_get_contents($realPath);

मुझे नहीं लगता कि यह पर्याप्त (आउट ऑफ बॉक्स) है, आखिरकार, रीडलिंक भी ओएस स्तर की कॉल पर निर्भर करता है और कैश से प्रभावित होता है।
बहराम अरदलन

3

यह PHP का वांछित व्यवहार है जिसे आप यहां देख सकते हैं क्योंकि PHP प्रदर्शन संवर्द्धन केrealpath_cache कारण फ़ाइल पथों को संग्रहीत करने के लिए उपयोग करता है ताकि यह डिस्क संचालन को कम कर सके।

इस व्यवहार से बचने के लिए शायद आप फ़ंक्शन realpath_cacheका उपयोग करने से पहले खाली करने की कोशिश कर सकते हैंget_file_contents

आप कुछ इस तरह की कोशिश कर सकते हैं:


clearstatcache();
$data = file_get_contents("Your File");

आप PHP डॉक पर क्लियरस्टैच के लिए और अधिक पढ़ सकते हैं ।


2

दो कैश हैं।

पहले OS कैश और फिर PHP कैश।

अधिकांश मामलों में clearstatcache(true)पहले file_get_contents(...)काम करता है।

लेकिन कभी-कभी आपको ओएस कैश को भी साफ करना होगा। लिनक्स के मामले में, मैं दो स्थानों को खाली करने के बारे में सोच सकता हूं। PageCache (1) और डेंट्री / इनोडेस (2)।

यह दोनों को साफ करता है:

shell_exec('echo 3 > /proc/sys/vm/drop_caches')

नोट: यह समस्या निवारण के लिए अच्छा है, लेकिन उत्पादन में लगातार कॉल के लिए नहीं क्योंकि यह पूरे OS कैश को साफ करता है और सिस्टम को फिर से कैश करने के कुछ पल खर्च करता है।


यह काम नहीं करता है, यह अभी भी कभी-कभी कैश्ड मूल्य को लोड करता है और मुझे एक समाधान की आवश्यकता होती है जो उत्पादन में लगातार कॉल के लिए अच्छा है।
डैन ब्रे

2
@DanBray, क्या आप कभी-कभी प्रकृति के बारे में अधिक जानने के लिए चीजों को लॉग इन कर सकते हैं ?
बहराम अरदलान

1
@DanBray, और आप पुराने मूल्य की उपस्थिति का पता कैसे लगाते हैं ? क्या ऐसा हो सकता है कि आपका परीक्षण अन्य परीक्षण शर्तों के कारण पुराना मान लौटाए, जबकि मूल्य वास्तव में बदल गया है?
बहराम अरदलन

2

"समस्या एक सिमलिंक को हटाने और पुनः बनाने के बाद है"

आप सिमलिंक को कैसे हटाते हैं? किसी फ़ाइल (या सिमिलिंक) को हटाना कैश को स्वचालित रूप से साफ़ कर देना चाहिए।

अन्यथा, आप देख सकते हैं कि अगर आप क्या करते हैं:

// This has "race condition" written all around it
unlink($link);
touch($link);
unlink($link); // Remove the empty file
symlink($target, $link);

इस समस्या को हल नहीं है, तो यह शायद के रूप में nginx के साथ एक समस्या हो सकती है इस मुद्दे ?

वास्तव में क्या होता है , यह देखने के लिए एक लॉग फ़ाइल में सभी ऑपरेशनों को लॉग इन करने का प्रयास करें ।

या हो सकता है...

... क्या आप पूरी तरह सहानुभूति के बिना कर सकते हैं ? उदाहरण के लिए, डेटाबेस, मेम्चे, SQLite फ़ाइल, या यहां तक ​​कि एक JSON फ़ाइल को "फ़ाइल नाम" और "वास्तविक सिमलिंक लक्ष्य" के बीच मैपिंग में संग्रहित करें। उदाहरण के लिए रेडिस या अन्य कीस्टोर्स का उपयोग करके, आप "फाइलनेम" को वास्तविक सिम्लिंक लक्ष्य के साथ जोड़ सकते हैं और ओएस रिज़ॉल्यूशन को पूरी तरह से बायपास कर सकते हैं।

उपयोग के मामले के आधार पर, यह सिम्बलिंक का उपयोग करने की तुलना में तेज़ हो सकता है।


मैं नहीं देख सकता कि यह कैसे nginx से संबंधित हो सकता है क्योंकि php प्रक्रिया और स्थानीय फ़ाइल सिस्टम के बीच कोई http चीज़ नहीं है। क्या माता-पिता की प्रक्रिया nginx को किसी भी तरह प्रासंगिक बनाती है?
बहराम अरदलान

@BahramArdalan तथ्य यह है, हम नहीं जानते कि समस्या का निदान कैसे किया गया या सहानुभूति क्या है या उनका उपयोग कैसे किया जाता है। इसलिए यह बोधगम्य है कि सामग्री बेमेल का पता नगीनक्स से नीचे की ओर लगा, और वास्तव में PHP से असंबंधित हो सकता है। एक SCCCE से बहुत मदद मिलेगी।
LSerni

हाँ। हमें उस "कैसे" चीज़ में थोड़ी खुदाई करनी होगी।
बहराम अरदलान

1

समस्या के कारण दो मुद्दे थे।

पहला मुद्दा

मैंने पहले से ही पोस्ट किया और प्रश्न में संपादित किया। यह Nginx कॉन्फ़िगरेशन के साथ एक समस्या है।

ये पंक्तियाँ:

fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $document_root;

जरूरत के साथ प्रतिस्थापित:

fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;

दूसरा अंक

दूसरा मुद्दा मुझे कॉल करने clearstatcacheसे पहले कॉल करने की आवश्यकता थी file_get_contents। मैं केवल clearstatcacheतब कॉल करना चाहता हूं जब यह बिल्कुल आवश्यक हो, इसलिए मैंने एक फ़ंक्शन लिखा जो केवल कैश को साफ़ करता है जब निर्देशिका में शामिल होता है ए symlink

function file_get_contents1($dir)
{
    $realPath = realpath($dir);
    if ($realPath === false)
        return '';
    if ($dir !== $realPath)
    {
        clearstatcache(true);
    }
    return file_get_contents($dir);
}

1

मैं अपना पहला उत्तर छोड़ रहा हूं क्योंकि यह अभी भी एक वैध उत्तर है। मैं clearstatcache (सही, $ फ़ाइल नाम) को लागू करके @DanBray उत्तर में सुधार कर रहा हूं।

समस्या के कारण दो मुद्दे थे।

पहला मुद्दा

मैंने पहले से ही पोस्ट किया और प्रश्न में संपादित किया। यह Nginx कॉन्फ़िगरेशन के साथ एक समस्या है।

ये पंक्तियाँ:

fastcgi_param SCRIPT_FILENAME $ document_root $ fastcgi_script_name; fastcgi_param DOCUMENT_ROOT $ document_root;

जरूरत के साथ प्रतिस्थापित:

fastcgi_param SCRIPT_FILENAME $ realpath_root $ fastcgi_script_name; fastcgi_param DOCUMENT_ROOT $ realpath_root;

दूसरा अंक

दूसरी समस्या यह थी कि मुझे file_get_contents को कॉल करने से पहले क्लीयरस्टेट को कॉल करने की आवश्यकता थी। मैं केवल तब ही स्पष्ट करना चाहता हूं जब यह बिल्कुल आवश्यक हो, इसलिए मैंने एक फ़ंक्शन लिखा है जो केवल कैश को साफ़ करता है जब निर्देशिका में एक सिम्लिंक शामिल होता है।

function file_get_contents1234_hard_drives($dir_go_1){
    $realPath = realpath($dir_go_1);
        $myDirectory=opendir(dirname($realPath));        
        while($entryName=readdir($myDirectory)) {
          $dirArray[]=$entryName;
        }

        /* Finds extensions of files used for my site theelectronichandbook.tech
        function findexts ($filename) {
          $filename=strtolower($filename);
          $exts=split("[/\\.]", $filename);
          $n=count($exts)-1;
          $exts=$exts[$n];
          return $exts;
        }*/

        // Closes directory
        closedir($myDirectory);

        // Counts elements in array
        $indexCount=count($dirArray);
        for($ArPos=1;$ArPos<=$indexCount;$ArPos++){
            /*used for my site theelectronichandbook.tech
            if($_SERVER['QUERY_STRING']=="hidden"){
                $H="";
                $af="./";
                $atext="Hide";
            }else{
                $H=".";
                $af="./?hidden";
                $at="Show";
            }*/
            if(strpos($dirArray[$ArPos], "Symlink") !== false){
                clearstatcache(true,$dir_go_1);
            }
        }
    return file_get_contents($dir_go_1);
}

मैंने अपने वेब-सर्वर के साथ उपरोक्त कोड का परीक्षण किया और यह काम कर गया।


1
दुर्भाग्य से, यह मेरे वेब-सर्वर पर मेरे लिए काम नहीं करता है।
डैन ब्रे

खैर मैं ड्रॉइंग बोर्ड में वापस जाऊंगा। @ डैनब्रे
जेटीएस

1
बहुत बहुत धन्यवाद, लेकिन दुर्भाग्य से, इनाम की अवधि समाप्त होने से पहले बहुत कम समय है। हालांकि, यदि आप समाधान के बारे में सोचते हैं तो मैं 100% खुश हूं, मैं एक अतिरिक्त इनाम दूंगा। इसके अलावा, file_get_contents1मैंने जो ढांचा बनाया है, उसका कुछ हिस्सा है, इसलिए इसका बहुत उपयोग किया जाता है, जो अनुकूलन को महत्वपूर्ण बनाता है।
दान ब्रे

$dir_go=readdir("$realPath")वापस आता है।
दान ब्रे

इसके लिए While($dir_go!==null)@DanBray
JTS

0

एक तत्व के अंदर कोड रखने की कोशिश करें जो लगातार जेक्वेरी का उपयोग करने के साथ-साथ पुन: सत्यापन और स्थैतिक पकड़ को मजबूर करने के लिए ताज़ा कर रहा है। यह कोड @naveed मूल उत्तर से संशोधित किया गया है ।

form.php:

 <meta http-equiv="Cache-Control" content="no-store, must-revalidate" />
 <meta http-equiv="Expires" content="0"/>
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
 <script> 
 jQuery(document).ready(function(){
    jQuery('.ajaxform').submit( function() {
        $.ajax({
            url     : $(this).attr('action'),
            type    : $(this).attr('method'),
            dataType: 'json',
            data    : $(this).serialize(),
            success : function( data ) {
                        // loop to set the result(value)
                        // in required div(key)
                        for(var id in data) {
                            jQuery('#' + id).html( data[id] );
                        }
                      }
        });
        return false;
    });
});
var timer, delay = 30;
timer = setInterval(function(){
    $.ajax({
      type    : 'POST',
      url     : 'profile.php',
      dataType: 'json',
      data    : $('.ajaxform').serialize(),
      success : function(data){
                  for(var id in data) {
                    jQuery('#' + id).html( data[id] );
                  }
                }
    }); }, delay);
 </script>
 <form action='profile.php' method='post' class='ajaxform'></form>
 <div id='result'></div>

profile.php:

 <?php
       // All form data is in $_POST
       // Now perform actions on form data here and create an result array something like this
       clearstatcache();
       $arr = array( 'result' => file_get_contents("./myfile.text") );
       echo json_encode( $arr );
 ?>
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.