space97
space97

Reputation: 303

How to test if S3 object does not exist AWS PHP SDK (Version 3)?

I have written an integration for the AWS SDK in PHP to send the keys for files on an S3 bucket and retrieve a pre-signed url, which more or less follows this example. This worked perfectly except I need to now check if the file exists on s3 and return empty string if it does not.

I am doing this with my code below:

<?php

public function getUrl($key, $region, $version, $fileBucket): string
{
    $this->s3Client = new Aws\S3\S3Client([
        'region' => $region,
        'version' => $version,
    ]);

    if ($this->s3Client->doesObjectExist($fileBucket, $key) === false) {
       return '';
    }

    $cmd = $this->s3Client->getCommand('GetObject', [
        'Bucket' => $fileBucket,
        'Key' => $key
    ]);

    $request = $this->s3Client->createPresignedRequest($cmd, $preSignedExpiration);

    $preSignedUrl = (string) $request->getUri();

    return $preSignedUrl ?? '';
}

My code returned the presigned urls perfectly until I added the if statement checking the method doesObjectExist(). doesObjectExist() returns false for all of my objects on S3, and not just the ones with a $key that does not exist in the S3 bucket. So that rules out the S3 keys, buckets or api keys being invalid, which has been the answer I have come across researching this issue primarily.

Also if you happen to know a better way to do this using what is returned in $cmd or $request, without having to call doesObjectExist() (if it is possible) that would simplify my code a bit.

Edit:

The policy for the IAM user I am accessing the AWS S3 API through looks like this:

{    
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:ListBucket",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::example-dev-us-east-1-111111111111",
                "arn:aws:s3:::example-dev-us-east-1-111111111111/*"
            ]
        }
    ]
}

And the s3 Bucket policy looks like:

       {
        "Sid": "dev-web-app-get-policy",
        "Effect": "Allow",
        "Principal": {
            "AWS": "arn:aws:iam::2222222222:role/example-dev-us-east-1-111111111111"
        },
        "Action": [
            "s3:GetObject",
            "s3:DeleteObject",
            "s3:ListBucket"
        ],
        "Resource": [
            "arn:aws:s3:::example-dev-us-east-1-111111111111",
            "arn:aws:s3:::example-dev-us-east-1-111111111111/*"
        ]
    }

So it would seem that I should be able to access the needed resources. I listed fake bucket names, for security. But I have checked that those mathc s3 in the console.

When have tried calling the the api for the HeadObject like this:

$this->s3Client->headObject([
    'Bucket' => $fileBucket,
    'Key' => $key
]);

And I get the following message:

"Error executing \"HeadObject\" on \"https://example-dev-us-east-1-111111111111/54bf7350-a819-41dd-9da3-3710eb8b095a-Screenshot_2021-03-09_20-15-12.png\"; AWS HTTP error: Client error: `HEAD https://example-dev-us-east-1-111111111111/54bf7350-a819-41dd-9da3-3710eb8b095a-Screenshot_2021-03-09_20-15-12.png` resulted in a `403 Forbidden` response  (client): 403 Forbidden (Request-ID: XR6W77BB817407K2) - ",
"url": "/files.json"

Not sure if that helps.

Thanks!

Upvotes: 1

Views: 2142

Answers (1)

jarmod
jarmod

Reputation: 78573

You need the s3:GetObject permission to invoke the HeadObject API, which is what the PHP SDK invokes when your code calls doesObjectExist().

If the object you request does not exist, the error Amazon S3 returns depends on whether you also have the s3:ListBucket permission.

  • If you have the s3:ListBucket permission on the bucket, Amazon S3 returns an HTTP status code 404 ("no such key") error.
  • If you don’t have the s3:ListBucket permission, Amazon S3 returns an HTTP status code 403 ("access denied") error.

So, you probably have s3:ListBucket but not s3:GetObject.

Upvotes: 2

Related Questions