PHP函數-flock()與之替代方法的看法


首先還是來介紹一下flock()的這個函數:

函數原型

bool flock (resource fp, int operation [, int & wouldblock])


  • 要取得共享鎖定(讀取的程序),將 lock 設為 LOCK_SH(PHP 4.0.1 以前的版本設置為 1)。
  • 要取得獨占鎖定(寫入的程序),將 lock 設為 LOCK_EX(PHP 4.0.1 以前的版本中設置為 2)。
  • 要釋放鎖定(無論共享或獨占),將 lock 設為 LOCK_UN(PHP 4.0.1 以前的版本中設置為 3)。
  • 如果不希望 flock() 在鎖定時堵塞,則給 lock 加上 LOCK_NB(PHP 4.0.1 以前的版本中設置為 4)。(這是引用W3school的)

    <?php
    
    $file = fopen("test.txt","w+");
    
    // 排它性的鎖定
    if (flock($file,LOCK_EX))
      {
      fwrite($file,"Write something");
      // release lock
      flock($file,LOCK_UN);
      }
    else
      {
      echo "Error locking file!";
      }
    
    fclose($file);
    ?>
    這是一個一般判斷的的例子。

    對於實際的運用,必須將其添加到所有使用的文件腳本中

    但注意:其函數無法再NFS或其他網絡文件系統中使用也無法在多線程服務器API中使用。

    更一般的例子有

    $fp =fopen("$DOCUMENT_ROOT/../orders/order.txt",'ab');//這里要注意/../帶來的安全性問題
    flock($fp , LOCK_EX);
    fwrite($fp,$outputstring);
    flock($fp,LOCK_UN);
    fclose($fp);
    這里注意如有兩個腳本同時申請對一個文件加鎖,會導致競爭條件關系,這時候應用DBMS解決

    個人覺得使用flock()函數就是當有2個以上用戶同時對同一文件操作時,使用戶有序的排隊操作,避免出現混亂。

    不知道可否用此函數來避免同時提交導致的刷分的現象

    接下來看一個這個函數的代替用法

    /*FLOCK的不可靠讓處理文件IO時很頭疼
    這個函數降低了FLOCK的不可靠性
    注意使用函數前后要IGNOR USER ABOUT以免用戶突然關閉瀏覽器造成文件沒寫完.
    函數返回錯誤的幾種情況概率非常之小*/
    <?php
    
    //安全寫文件(不會沖突,不使用flock)請不斷刷新,數字會累加,不會錯過
    //一旦返回錯誤,將可能是屬性$lockfile非0777錯誤(這種可能性極小)
    //
    
    function safewrite($filename,$content)
    {
    
    $long=0;
    $lock_file=$filename.'.lock';
    
    while($long<2)
            {
            clearstatcache();
    if(file_exists($lock_file))
                    {
    
            usleep(100);
            $long=abs( date("s")-date ("s", filemtime($lock_file)));
            continue;
                    }
    else 
                    {
            @fclose(@fopen($lock_file,'w'));
            $fp=@fopen($filename,'w');//無法打開
            if($fp===FALSE)return FALSE;
            $s=@fwrite($fp        ,$content);
            if($s===FALSE)return FALSE; //無法寫入
            @fclose($fp);
            unlink($lock_file);
            return TRUE;
                    }
            }
            
            if(!unlink($lock_file))return FALSE;//無法刪除鎖文件
            @fclose(@fopen($lock_file,'w'));
            $fp=@fopen($filename,'w');
            if($fp===FALSE)return FALSE; //無法打開
            $s=@fwrite($fp        ,$content);
            if($s===FALSE)return FALSE;//無法寫入
            @fclose($fp);
            unlink($lock_file);
            return TRUE;
    }
            
    
    
    ignore_user_abort (TRUE);
    $n=file_get_contents('test');
    $n++;
    if(safewrite('test',$n))echo $n; else fopen('error','w');
    ignore_user_abort (FALSE);
    
    ?>
    但是

    /*本函數的缺陷是,當兩個進程同時發現$lockfile不存在,則同時建立文件,會造成沖突
    雖然概率很小
    數據庫有防死鎖機制,但目前PHP文件操作很難實現這個功能
    如果使用flock,請務必在你的系統下進行測試*/
    
    //可以這樣
    flock($fp,LOCK_EX);
    sleep(5);
    
    /*然后在5秒之內用瀏覽器開始另一個進程
    echo flock($fp,LOCK_SH);
    看是否能獲得獨占鎖(或共享鎖)
    如果不能獲得,則表明flock起作用*/
    還有一個測試方法

    <?php
    //本文件保存為flock.php,
    ignore_user_abort (TRUE);
    $fp=fopen('test','w');
    flock($fp,LOCK_EX);
    sleep(30);
    ignore_user_abort (FALSE);//這里還是請大神考慮下,有一定安全隱患
    ?>
    
    /*運行上文件后,30秒內運行下文件,即可判斷是否FLOCK正常;
    30秒后程序停止,之后文件自動解鎖*/
    
    <?php
    //本文件保存為get_flock.php,一定要在執行flock.php后執行
    
    $fp=fopen('test','w');
    if( flock($fp,LOCK_EX|LOCK_NB))echo '當前獲得鎖定!如果flock.php正在運行,說明flock在你的系統上不能運行';
    else  echo '不能獲得鎖定,flock可以在你的系統上運行';
    ?>








  • 免責聲明!

    本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



     
    粵ICP備18138465號   © 2018-2025 CODEPRJ.COM