1

I'm running Coldfusion8 and am uploading files to Amazon S3.

When displaying images, I want to check whether an image is available from S3 and if not show a fallback image. My problem is, don't know how to check for existing images.

If I list the link to an image, it's something like this:

http://s3.amazonaws.com/bucket/l_138a.jpg?AWSAccessKeyId=_key_&Expires=_exp_&Signature=_signature_

I'm trying to check for existing files like this:

<cfif fileExists("http://s3.amazonaws.com/bucket/s_" & items.filename)>
    <cfdump output="e:\website\test\dump.txt" label="catch" var="found!!!">
</cfif>

Question:
Do I always have to provide accesskey, expires and signature when checking for an image? If I enter the image path without credentials in the browser, the image is loaded, so I don't understand why my fileExist is not working. Any idea?

John Rotenstein
  • 241,921
  • 22
  • 380
  • 470
frequent
  • 27,643
  • 59
  • 181
  • 333
  • 1
    What about alternative solution: if `you` are uploading files, why not keep the list in database and check against it? – Sergey Galashyn Aug 14 '12 at 11:30
  • why do you hightlight `you`? It will be the user uploading, but I'm sitting on a upload-log table right now. I will only store userID, timestamp, type of upload and element. So in my element query, I will try to left join with the log in order to then check whether a type is submitted. This would avoid an additional database query and only ask S3 to deliver an image if one is there. What to you think? – frequent Aug 14 '12 at 11:41
  • 1
    I highlighted it because if there are other ways to upload files except your code (= you), this may not work. Problem with whole your idea of checking existence before displaying -- it will be slow as hell, both for HTTP and web-service checks. – Sergey Galashyn Aug 14 '12 at 12:14
  • So I was thinking if I fill my table when the files get `uploaded` I can query in my element search `left join` on my media log and then I will either have an info, that a file exists on S3 or an empty string, which enables me to show the image or show an alternative image. Don't see where this is slow right now. But I will try and repost – frequent Aug 14 '12 at 13:10
  • 1
    Querying database is not slow -- that's exactly what I've suggested. What is slow is network requests you'll need to perform for the availability checking, they are 10x (100x, ...) times slower than filesystem and database (even HEAD-only). – Sergey Galashyn Aug 14 '12 at 13:39
  • too bad you're using CF8, CF9+ supports checking URL with `FileExists()`: http://forums.adobe.com/thread/765614 – Henry Aug 14 '12 at 15:50
  • good to know, but I will be stuck with CF8 for a while I'm afraid – frequent Aug 14 '12 at 16:25

5 Answers5

5

You could use cfhttp if you have a site-wide page not found message set up.

<cfhttp url="http://a.espncdn.com/photo/2012/0813/nfl_u_flynn1x_203.jpg" method="head">
<cfdump var="#cfhttp.filecontent#">

returns object of java.io.ByteArrayOutputStream

<cfhttp url="http://a.espncdn.com/photo/20notanimage3.jpg" method="head">
<cfdump var="#cfhttp.filecontent#">

returns <html> <body> <h1>Error Processing Request</h1> </body> </html>

Can also check the statuscode returned by the server

<cfhttp url="http://a.file.exists.gif" method="head">
<cfdump var="#val(cfhttp.statuscode)#">

200 is ok, 404 is not found, etc

Matt Busche
  • 14,216
  • 5
  • 36
  • 61
3

I've used the getObjectInfo method in the S3.cfc to see if an object exists:

<cffunction name="getObjectInfo" access="public" output="false" returntype="string"
            description="Creates a bucket.">
    <cfargument name="bucketName" type="string" required="yes">
    <cfargument name="filekey" type="string" required="true" hint="" />


    <cfset var data = "">
    <cfset var content = "">
    <cfset var contents = "">
    <cfset var thisContent = "">
    <cfset var allContents = "">
    <cfset var dateTimeString = GetHTTPTimeString(Now())>

    <!--- Create a canonical string to send --->
    <cfset var cs = "HEAD\n\n\n#dateTimeString#\n/#arguments.bucketName#/#Arguments.filekey#">

    <!--- Create a proper signature --->
    <cfset var signature = createSignature(cs)>

    <!--- get the bucket via REST --->
    <cfhttp method="HEAD" url="http://s3.amazonaws.com/#arguments.bucketName#/#Arguments.filekey#">
        <cfhttpparam type="header" name="Date" value="#dateTimeString#">
        <cfhttpparam type="header" name="Authorization" value="AWS #variables.accessKeyId#:#signature#">
    </cfhttp>

    <cfreturn cfhttp.StatusCode />
</cffunction>

If I get a 200 status back, then I know the object exists.

Dan Short
  • 9,598
  • 2
  • 28
  • 53
  • nice! I will also try to give this a shot, although I need to do 24 requests per page to see whether an element exists, so I might go with the database alternative (see comments above) to avoid unneccessary calls to S3 – frequent Aug 14 '12 at 13:11
2

I haven't used Coldfusion for a long time, but I did a quick lookup and the fileExists method seems to be for filesystem lookups, not remote URLs.

There are other Coldfusion methods for requesting URLs. One forum discussion on the subject I just quickly found is here: http://forums.adobe.com/thread/765614

But, assuming you're generating HTML to be consumed by a web browser I would suggest doing an image check / fallback in HTML/CSS/JS rather than server side. You could do this with CSS background-image tricks, or directly load and check images with JS. One question dealing with this that I found is here (there are probably a bunch of similar questions on this stuff): Inputting a default image in case the src attribute of an html <img> is not valid?

Community
  • 1
  • 1
devlop
  • 1,168
  • 1
  • 8
  • 19
  • hm. sounds good. I'm using a [S3.cfc](https://github.com/joedanz/cf-amazon-s3/blob/master/s3.cfc), which does have a special function to check for existing items in a bucket, so I guess I will be trying this aswell. Thanks for the hints! – frequent Aug 13 '12 at 23:26
  • note that any S3 API calls you make will slow down your code a fair bit and Amazon will charge you for API usage also. – devlop Aug 13 '12 at 23:38
  • just thought about that, too. how about storing saved paths in a seperate s3 table, which i could then query for existing entries? – frequent Aug 13 '12 at 23:54
  • 1
    FYI, CF9+ supports checking remote url via `fileExists()` – Henry Aug 14 '12 at 16:30
1

CF9 +

<cfscript>
    FileExists('s3://#accessKey#:#secretKey#@[your bucket]/[your file]');
</cfscript>
Kevin Mansel
  • 2,351
  • 1
  • 16
  • 15
0

If using the popular ColdFusion library, https://github.com/jcberquist/aws-cfml: modify the (awscfml) library per your com object placement, then insert your bucket and object key.

Invoke getObjectMetadata to test for object existence.

isFileStored = awscfml.s3.getObjectMetadata(
    Bucket = "mybucket", 
    ObjectKey = "mykey");

storedFileStatus = (isFileStored.statusCode == 200) 
    ? True 
    : False;
myshyzile
  • 53
  • 5