Reputation: 999
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
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
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