質問

I'm using the following code to create and append data to a tar-archive in PHP. The problem is that phar does not use an exclusive lock on the tar-file causing problem when I have atomic writes to the same file.

function phar_put_contents($fname, $archive, $data) { 
  $i=0;
  do { 
    $fp = @fopen($archive.'.lock', 'w');
    if(!$fp) { 
      usleep(25);
      continue;
    } 
    if(flock($fp, LOCK_EX)) { 
      try{
        $myPhar = new PharData($archive.'.tar',0);
        $myPhar[$fname] = $data;
        $myPhar->stopBuffering();
        flock($fp, LOCK_UN) && @fclose($fp);
        @unlink($archive.'.lock');
        return true;
      } catch (Exception $e) { 
        error_log($e->getMessage()." in ".$e->getFile().":".$e->getLine(),0);
        unset($e);
        @flock($fp, LOCK_UN) && @fclose($fp);
      } 
    } 
  } while ($i++<8);
  return false;
}

Using a look file seems to be a "good" solution but it's not optimal since my archives gets currupted quite frequently.

役に立ちましたか?

解決

Ok, it seems like the Phar and PharData classes in PHP is somewhat unfinished, they neither have lock() nor close() making my approach for external locking nonworking..

The following code is what I used to try to have a function that appends data to a tar archive.

function phar_put_contents($fname, $archive, $data) { 
  $i=0;
  do { 
    $fp = @fopen($archive.'.lock', 'w');
    if(!$fp) { 
      usleep(25);
      continue;
    } 
    if(flock($fp, LOCK_EX)) { 
      try{
        file_put_contents('/tmp/'.$fname, $data);
        $tarCmd = "tar ". (file_exists($archive.".tar") ? "-rf ":"-cf ") .$archive.".tar  -C /tmp ".$fname;
        exec($tarCmd, $result, $status);
        if($status!=0)
          throw new Exception($tarCmd . implode($result, "\n"));
        @unlink('/tmp/'.$fname);
        flock($fp, LOCK_UN) && @fclose($fp);
        @unlink($archive.'.lock');
        return true;
      } catch (Exception $e) { 
        error_log($e->getMessage()." in ".$e->getFile().":".$e->getLine(),0);
        unset($e);
        @flock($fp, LOCK_UN) && @fclose($fp);
      } 
    } 
  } while ($i++<8);
  return false;
}

Note that I'm using exec() and calls the external version of tar. This were a necessity since Phar does very unreliable flushes to the archive, making the tar-file broken since two instances of the code can modify the same file at the same time.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top