web-dev-qa-db-ja.com

php-リンク解除はエラーをスローします:リソースは一時的に利用できません

コードは次のとおりです。

_public function uploadPhoto(){
    $filename = '../storage/temp/image.jpg';  
    file_put_contents($filename,file_get_contents('http://example.com/image.jpg'));
    $photoService->uploadPhoto($filename);
    echo("If file exists: ".file_exists($filename));
    unlink($filename);
}
_

私は次のことをしようとしています:

  1. URLから写真を取得し、サーバーの一時フォルダーに保存します。これは正常に機能します。イメージファイルが作成され、echo("If file exists: ".file_exists('../storage/temp/image.jpg'));のときに_If file exists: 1_をエコーし​​ます。
  2. そのファイルを、Amazons3バケットへのファイルのアップロードを処理する別の関数に渡します。ファイルは私のs3バケットに保存されます。
  3. 一時フォルダに保存されている写真を削除します。 これは機能しません!次のようなエラーが発生します:

unlink(../ storage/temp/image.jpg):リソースが一時的に利用できません

rename($filename,'../storage/temp/renimage.jpg');の代わりにunlink($filename);を使用すると、エラーが発生します。

rename(../ storage/temp/image.jpg、../storage/temp/renimage.jpg):別のプロセスによって使用されているため、プロセスはファイルにアクセスできません。 (コード:32)

関数呼び出し$photoService->uploadPhoto($filename);を削除すると、すべてが完全に正常に機能します。

ファイルが別のプロセスで使用されている場合、プロセスが完了し、ファイルがどのプロセスでも使用されなくなった後、ファイルのリンクを解除するにはどうすればよいですか?タイマーは使いたくない。

助けてください!前もって感謝します。

7
Abhishek Reddy

同様のエラーに対処する必要がありました。

あなたの_$photoService_が何らかの理由で画像を保持しているようです...あなたは_$photoService_のコードを共有していなかったので、私の提案はこのようなことをすることです(あなたがそうしないと仮定して) _$photoService_がもう必要です):

_[...]
echo("If file exists: ".file_exists($filename));
unset($photoService);
unlink($filename);
}
_

unset()メソッドは、指定された変数/オブジェクトを破棄するため、ファイルを「使用」(または使用する)ことはできません。

4
Aimer

私はこの問題に1、2時間座って、ついに「一時的に利用できない」とは本当に「一時的に」を意味することに気づきました。

私の場合、同時PHPスクリプトは、書き込みまたは読み取りのいずれかでファイルにアクセスします。また、unlink()プロセスのタイミングが悪いと、すべてが失敗しました。

解決策は非常に単純でした。(通常はあまりお勧めできません)_@_を使用して、エラーがユーザーに表示されないようにし(確かに、エラーが印刷されないようにすることもできます)、もう一度試してください。

_$gone = false;
for ($trial=0; $trial<10; $trial++) {
    if ($gone = @unlink($filename)) {
        break;
    }
    // Wait a short time
    usleep(250000);
    // Maybe a concurrent script has deleted the file in the meantime
    clearstatcache();
    if (!file_exists($filename)) {
        $gone = true;
        break;
    }
}
if (!$gone) {
    trigger_error('Warning: Could not delete file '.htmlspecialchars($filename), E_USER_WARNING);
}
_

この問題を解決し、運をさらに推し進めた後、file_put_contents()を使用して「リソースが一時的に利用できません」という問題をトリガーすることもできます。同じ解決策で、今ではすべてが正常に機能します。

賢明であるか、将来リンク解除に失敗した場合は、_@_をob_start()に置き換えるので、エラーメッセージで正確なエラーを知ることができます。

3
BurninLeo

最も簡単な解決策:

gc_collect_cycles();
unlink($file);

私のためにそれをしますか! Amazon S3にファイルをアップロードした直後に、サーバー上のファイルを削除できます。

ここを参照してください: https://github.com/aws/aws-sdk-php/issues/841

GuzzleHttp\Streamオブジェクトは、その__destructメソッドが呼び出されるまでリソースハンドルを保持します。通常、これは、ストリームがスコープから外れるとすぐにリソースが解放されることを意味しますが、PHPバージョンと、スクリプトがガベージコレクターのバッファーをまだ満たしているかどうかによっては、ガベージコレクションがgc_collect_cyclesは、コレクターを強制的に実行し、到達不能なすべてのストリームオブジェクトに対して__destructを呼び出します。

:)

2
Hue Man

私も同じ問題を抱えていました。 S3クライアントは、リンク解除が実行される前にロックを解除したくないようです。内容を変数に抽出し、それをputObject配列の「body」として設定する場合:

$fileContent = file_get_contents($filepath);
$result = $s3->putObject(array(
    'Bucket'       => $bucket,
    'Key'          => $folderPath,
    'Body'         => $fileContent,
     //'SourceFile'   => $filepath,
    'ContentType'  => 'text/csv',
    'ACL'          => 'public-read'
));

この回答を参照してください: AWS S3ヘルパーがファイルをアップロードした後にファイルのロックを解除する方法は?

1
ephemeralCoder