php 多线程上下文中安全写文件实现代码

复制代码 代码如下:

  <?php

  /**

  * @usage: used to offer safe file write operation in multiple threads context, arbitory file type

  * @author: Rocky Zhang

  * @time: Nov. 11 2009

  * @demo[0]: $handler = mfopen($file, 'a+');

  * mfwrite($handler, $str);

  */

  function mfopen($file, $mode='w+') {

  $tempfile = generateTempfile('./tempdir', $file);

  preg_match('/b/i', $mode) || ($mode .= 'b'); // 'b' is recommended

  if (preg_match('/\w|a/i', $mode) && !is_writable($file)) {

  exit("{$file} is not writable!");

  }

  $filemtime = $filemtime2 = 0;

  $tempdir = dirname($tempfile);

  is_dir($tempdir) || mkdir($tempdir, 0777);

  do { // do-while used to avoid modify in a long time copy

  clearstatcache();

  $filemtime = filemtime($file);

  copy($file, $tempfile);

  $filemtime2 = filemtime($file);

  } while ( ($filemtime2 - $filemtime) != 0 );

  if (!$handler = fopen($tempfile, $mode)) {

  exit('Fail on opening tempfile, write authentication is must on temporary dir!');

  }

  return array(0=>$handler, 1=>$filemtime, 2=>$file, 3=>$tempfile, 4=>$mode);

  }

  // I do think that this function should be optimized further

  function mfwrite(&$handler, $str='') {

  if (strlen($str) > 0) {

  $num = fwrite($handler[0], $str);

  fflush($handler[0]);

  }

  clearstatcache();

  $mtime = filemtime($handler[2]);

  if ( $mtime == $handler[1] ) { // compare between source file and temporary file

  if ( $num && $num > 0 ) { // temporary file has been updated, copy to source file

  copy($handler[3], $handler[2]) || exit;

  $handler[1] = filemtime($handler[3]);

  touch($handler[2], $handler[1], $handler[1]);

  }

  } else { // source file has been modified, load source file to temporary file

  copy($handler[2], $handler[3]) || exit;

  touch($handler[3], $mtime, $mtime);

  $handler[1] = $mtime;

  }

  }

  function generateTempfile($tempdir='tempdir', $file) {

  $rand = md5(microtime());

  return "{$tempdir}/{$rand}_".$file;

  }

  ?>