Lee
Lee

Reputation: 999

CFDirectory Create on S3?

Working on a simple uploader that calls for me to upload to 'user specific' folders, which would need to be created the first time a user uploads something. All storage is done on S3. The test code I have at the moment is this (mybucket.domain.name isn't the real bucket, obviously - changed that bit for this posting);

<cfif DirectoryExists("s3://mybucket.domain.name/test123/")> 
    <!--- The directory exists --->
<cfelse>
    <!--- Directory doesn't exist, so create it --->
    <cfdirectory action="CREATE" directory="s3://mybucket.domain.name/test123/" storelocation="US">
</cfif>

When I run this, no errors are returned - but it always reports the directory not to exist, and never actually creates it. I've scoured the docs and previous posts here, and as far as I can tell the syntax is correct.

Upvotes: 1

Views: 612

Answers (2)

Bryan
Bryan

Reputation: 43

If you want to create a "folder" on AWS S3 from ColdFusion, you have to create a 0-length file that has a trailing "/" at the end of its name.

The way I do it is simple using built-in support:

 <cffile action = "write"
file = "s3://yourS3bucket/folder_1/" output="">

After this is written to your bucket, AWS will report it as a directory and DirectoryExists will work with it (return true) or if you DirectoryList your bucket as a query, this object will be of type DIR. You can also DirectoryCopy to it (though "recurse" doesn't really work as expected with any subdirectories in the source directory.) Note: you will now have an object in your bucket whose key is "folder_1/"

Upvotes: 2

Dave Anderson
Dave Anderson

Reputation: 438

The main issue here is that S3 doesn't consider anything to be a "folder". There is no directory tree in S3 -- it's all just objects, and some of those objects happen to have / characters in their names.

There are a couple ways around this, but neither enables you to use directoryExists().

The first way is to evaluate whether the array returned by directoryList('s3://mybucket/foldername') contains any members.

Another way is to do all your S3 operations through a cfc. Here's one: https://github.com/joedanz/cf-amazon-s3

If you make your own component that extends that one, you can add to it this function I wrote to accomplish the same thing:

<cffunction name="folderExists" access="public" returntype="boolean" hint="folderPath = path/to/folder/ (with trailing slash and no leading slash)">
    <cfargument name="folderPath" type="string" />
    <cfset var objArr = getBucket(bucketName=variables.bucket,prefix='#arguments.folderPath#',delimiter='/') />
    <cfloop array="#objArr#" index="local.o">
        <cfif o.key EQ arguments.folderPath AND o.size EQ 0>
            <cfreturn true />
        </cfif>
    </cfloop>
    <cfreturn false />
</cffunction>

("folderPath" would be "/" if you're looking for a "folder" in the bucket's root.)

*another edit -- you might want this function, too:

<cffunction name="folderCreate" access="public" returntype="void">
    <cfargument name="folderPath" type="string" default="" />
    <cfargument name="bucket" type="string" default="#variables.bucket#" />
    <cfif len(folderPath)>
        <cfif right(folderPath,1) NEQ "/">
            <cfset folderPath &= "/" />
        </cfif>
        <cfset putObject(bucketName=bucket,uri=variables.finderPath&URLEncodedFormat(folderPath),contentType='binary/octet-stream') />
    </cfif>
</cffunction>

Explanation: most S3 clients I've seen get around the non-existence of folders by creating zero-length objects and interpreting them as folders.

Upvotes: 2

Related Questions