15

I am using the official PHP SDK with the official service provider for laravel to upload an image to Amazon S3. The image is temporarily stored on my server and should be deleted after uploading. The following is the code I used to do my upload and delete.

$temp_path = "/screenshot_temp/testing.png";

$client = AWS::createClient('s3');
$result = $client->putObject(array(
        'Bucket'     => self::$bucketName,
        'Key'        => 'screenshot/testing.png',
        'SourceFile' => $temp_path,
        'ACL'    => 'public-read'
    ));
);

chown($temp_path, 777);
unlink($temp_path);

The upload is successful. I can see my image with the link return, and I can see it on the amazon console. The problem is that the delete fails, with the following error message:

ErrorException: unlink(... path of my file ...): Permission denied

I am sure my file permission setting is correct, and I am able to delete my file with the section of code for uploading to S3 comment out. So it should be the problem that the file is locked during uploading the file. Is there a way I can unlock and delete my file?

cytsunny
  • 4,838
  • 15
  • 62
  • 129

4 Answers4

10

Yes the stream upload locks the file till it finishes, Try either of 2,

$client = AWS::createClient('s3');
$fileContent = file_get_contents($temp_path);
$result = $client->putObject(array(
    'Bucket'     => self::$bucketName,
    'Key'        => 'screenshot/testing.png',
    'Body'       => $fileContent,
    'ACL'        => 'public-read'
));
);

unlink($temp_path);

or

$client = AWS::createClient('s3');
$fileContent = file_get_contents($temp_path);
$result = $client->putObject(array(
    'Bucket'     => self::$bucketName,
    'Key'        => 'screenshot/testing.png',
    'Body'       => $fileContent,
    'ACL'        => 'public-read'
));
);

gc_collect_cycles();
unlink($temp_path);
Vineesh
  • 467
  • 4
  • 11
  • First, I guess it should be `file_get_contents()`, else it would result in function not found. And even I change to file_get_contents, the code is not working. The function still take `$fileContent` as file path and return file not found. – cytsunny Jan 03 '17 at 02:24
  • Not sure for the second method, but the first one works for me. – cytsunny Jan 11 '17 at 00:47
7

When you're using SourceFile option at putObject S3Client opens a file, but doesn't close it after operation.

In most cases you just can unset $client and/or $result to close opened files. But unfortunately not in this case.

Use Body option instead of the SourceFile.

// temp file
$file = fopen($temp_path, "r");

// use resource, not a path
$result = $client->putObject(array(
        'Bucket'     => self::$bucketName,
        'Key'        => 'screenshot/testing.png',
        'Body'       => $file,
        'ACL'        => 'public-read'
    ));
);

fclose($file);

unlink($temp_path);
Leonid Shumakov
  • 1,319
  • 10
  • 7
  • This fixed my problem I had over here: https://stackoverflow.com/questions/54915084/calling-php-unlink-after-move-uploaded-file-on-moved-file-fails – cngodles Mar 08 '19 at 17:16
1

EDIT: I just noticed the string in your $temp_path begins with a "/" slash character. This beginning slash typically starts at the root directory of the website, are you sure this is the correct location? Use the getcwd() command in PHP to find out what folder PHP thinks it is inside of.

I understand you believe the permissions are correct but in light of the "Permission denied" error I still believe it is telling you something relevant.

I see you are trying to chown the directory, did you perhaps mean to chmod it? If you can SSH to your server and run this command you may have more luck:

chmod -R 777 /(your-website-dir/screenshot_temp

Or even try changing the "chown" to "chmod" in your PHP code.

C Hunter
  • 76
  • 3
  • This is a fake position for demo purpose. For security reason, I will not post the actual path. The actual path is not in root directory, and I am sure the path is correct as the upload is successful. – cytsunny Jan 03 '17 at 08:21
  • Ok for the path. But have you tried to replace the wrong chown command by chmod ? – Seb Jan 09 '17 at 14:32
  • I am sure it is correct too, as I can see the permission changed when I use the `ls` command. – cytsunny Jan 10 '17 at 01:54
1

I'm not a PHP guy, but I'd try popping that bad boy into a stream and then passing the stream to the SDK.

That way, you can explicitly close the stream and then delete the temp file. You may even be able to eliminate the temporary file altogether and deal solely with streams, if that's allowed by your specific use-case.

Looks like this SO post might set you on the right track.

Community
  • 1
  • 1
Garrett Clyde
  • 306
  • 3
  • 9
  • Yes, and this is the way other answer suggest. I am just surprised that a SDK written by Amazon doesn't provide a method to close the stream, or just close the stream by default..... – cytsunny Jan 10 '17 at 04:19