Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check if File Exists on Amazon s3 Signed URL

I have create a signed $URL for Amazon s3 and it opens perfectly in the browser.

http://testbucket.com.s3.amazonaws.com/100-game-play-intro-1.m4v?AWSAccessKeyId=AKIAJUAjhkhkjhMO73BF5Q&Expires=1378465934&Signature=ttmsAUDgJjCXepwEXvl8JdFu%2F60%3D

**Bucket name and accesskey changed in this example

I am however trying to then use the function below to check (using curl) that the file exists. It fails the CURL connection. If I replace $URL above with the url of an image outside of s3 then this code works perfectly.

I know the file exists in amazon but can't work out why this code fails if using a signed url as above

Any ideas?

Thanks

Here is my code.

function remoteFileExists($url) {

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, false);
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

    //don't fetch the actual file, only get header to check if file exists
    curl_setopt($ch, CURLOPT_HEADER, 1);
    curl_setopt($ch, CURLOPT_NOBODY, true);

    $result = curl_exec($ch);
    curl_close($ch);



    if ($result !== false) {

        $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);  

        if ($statusCode == 200) {
            $ret = true;   
        } else {
            $ret = false;
        }

    } else {
        $ret='connection failed';
    }

    return $ret;

}
like image 561
Stephen Baugh Avatar asked Sep 05 '13 11:09

Stephen Baugh


2 Answers

When using CURLOPT_NOBODY, libcurl sends an HTTP HEAD request, not a GET request.

...the string to be signed is formed by appending the REST verb, content-md5 value, content-type value, expires parameter value, canonicalized x-amz headers (see recipe below), and the resource; all separated by newlines.

— http://s3.amazonaws.com/doc/s3-developer-guide/RESTAuthentication.html

The "REST verb" -- e.g., GET vs HEAD -- must be consistent between the signature you generate, and the request that make, so a signature that is valid for GET will not be valid for HEAD and vice versa.

You will need to sign a HEAD request instead of a GET request in order to validate a file in this way.

like image 171
Michael - sqlbot Avatar answered Sep 21 '22 14:09

Michael - sqlbot


You can check by the header part.

$full_url = 'https://www.example.com/image.jpg';
$file_headers = @get_headers($full_url);
if($file_headers && strpos($file_headers[0], '200 OK')){
    // enter code here
}

Or If you are using AWS S3 then you can also use this one.

if(!class_exists('S3')){
    require('../includes/s3/S3.php');
}
S3::setAuth(awsAccessKey, awsSecretKey);
$info = S3::getObjectInfo($bucketName, $s3_furl);
// check for $info value and apply your condition.
like image 20
manish1706 Avatar answered Sep 24 '22 14:09

manish1706