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可以在你的系统上运行';
    ?>







  • posted @ 2012-01-23 16:32  稻草哥  阅读(4317)  评论(0)    收藏  举报