Vinelab / cdn

CDN Assets Manager Package for Laravel.
MIT License
214 stars 71 forks source link

Add key prefix as a configuation option #103

Open bubenkoff opened 7 years ago

bubenkoff commented 7 years ago

It's not uncommon to have single s3 bucket for multiple applications, connected to a single cloudfront domain, separated just by a key prefix, example:

static.example.com/app1/assets...
static.example.com/app2/assets...

ATM there's no easy way to implement this with this very nice package thanks!

Mulkave commented 7 years ago

@bubenkoff thanks for raising that point. Can you please suggest a suitable solution? I haven't faced that issue before so any details you can share are much appreciated!

thtg88 commented 7 years ago

I'm actually facing the same sort of problem on an S3/CloudFront environment as described by @bubenkoff , where I have just one bucket, hosting multiple apps' assets. At the moment I use just one app on the CDN, so I'm good having a public folder on the bucket's root directory, but this could potentially display the package issue if I decide to use the package on the other apps since, in a Laravel environment, you most likely always push content from the public directory, potentially overwriting every apps assets. A possible solution could be having a config variable in config/cdn.php containing the additional folder/path (defaulting to an empty string) e.g. 'app-folder' => '',, which will then get pushed to the AwsS3Provider'sdefault array. Then, considering the way you upload the assets (get all local's, compare with server's, remove the not modified from the array), and you are using the AWS PHP SDK putObject method, where the "destination" path is held in the Key key, we will need to prefix the Key key wth app-folder if the string is not empty and the file is brand new (not available on server). Considering this there will most likely be a bit of refactoring in the AwsS3Provider's upload and getFilesAlreadyOnBucket methods as follows:

  1. In the getFilesAlreadyOnBucket method add a line after 401: $item->IsModified = true; this way we know if the file has actually been modified instead of just created locally;
  2. In the upload method change line 207 to: 'Key' => ($this->default['providers']['aws']['s3']['app-folder'] !== '' && $file->IsModified !== null ? str_replace('\\', '/', $this->default['providers']['aws']['s3']['app-folder'].'/'.$file->getPathName()), : str_replace('\\', '/', $file->getPathName()). This way we'll add app-folder as a prefix to the the actual local app path, so the file gets uploaded where we want. You might not want to expose the variable itself though, and access it from a getter e.g. getAppFolder, so you could apply string transformation on it, as necessary (trim('/') off the top of my head).

I fear though that these edits could "break stuff" (very technical term), as you are most likely not allowed to add a custom key to $item at point 1, but is roughly my idea.

Apolgies if I've written something outrageous or haven't formatted the answer properly, but I'm very inexperienced with GitHub's issue tracker. What do you think?

Mulkave commented 7 years ago

@thtg88 Thanks for the details. I'm just afraid that would require too much config in the simple case where you only have one bucket per app. I always lean towards simplicity when it comes to config.

I was thinking whether Bucket in config can be bucket-name/app1, that should work IMO. Can you please give it a try?

thtg88 commented 7 years ago

@Mulkave Forgot to mention I tried that, unfortunately it throws an exception as the forward-slash '/' character gets urlencoded. I'm not at my PC right now but I can provide the Exception details if needed. thanks for your reply anyway

Mulkave commented 7 years ago

@thtg88 sure some more details on the exception would help. I'm also not able to try that atm.

thtg88 commented 7 years ago

Hi @Mulkave , apologies for the delay. You can find the exception message below:

[2016-11-19 14:38:49] local.ERROR: exception 'Aws\S3\Exception\S3Exception' with message 'Error executing "ListObjects" on "https://s3.amazonaws.com/the-s3-bucket-name%2Fthe-application-assets-subfolder-name?encoding-type=url"; AWS HTTP error: Client error: `GET https://s3.amazonaws.com/the-s3-bucket-name%2Fthe-application-assets-subfolder-name?encoding-type=url` resulted in a `403 Forbidden` response:
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calcul (truncated...)
 SignatureDoesNotMatch (client): The request signature we calculated does not match the signature you provided. Check your key and signing method. - <?xml version="1.0" encoding="UTF-8"?>
<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message><AWSAccessKeyId>AKIAIY7T2HVCCV34ZZVA</AWSAccessKeyId><StringToSign>AWS4-HMAC-SHA256
20161119T143848Z
20161119/us-east-1/s3/aws4_request
thestringtosign-omitted</StringToSign><SignatureProvided>thsignatureprovided-omitted</SignatureProvided><StringToSignBytes>thestringtosignbytes-omitted</StringToSignBytes><CanonicalRequest>GET
/the-s3-bucket-name/the-application-assets-subfolder-name
encoding-type=url
aws-sdk-invocation-id:60f4df8826b54f3ef8e7a99eb6361085
aws-sdk-retry:0/0
host:s3.amazonaws.com
x-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
x-amz-date:20161119T143848Z

aws-sdk-invocation-id;aws-sdk-retry;host;x-amz-content-sha256;x-amz-date
thecanonicalrequest-omitted</CanonicalRequest><CanonicalRequestBytes>thecanonicalrequestbytes-omitted</CanonicalRequestBytes><RequestId>032C69243B67DFE1</RequestId><HostId>thehostid-omitted</HostId></Error>'

exception 'GuzzleHttp\Exception\ClientException' with message 'Client error: `GET https://s3.amazonaws.com/the-s3-bucket-name%2Fthe-application-assets-subfolder-name?encoding-type=url` resulted in a `403 Forbidden` response:
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calcul (truncated...)
' in C:\Application\vendor\guzzlehttp\guzzle\src\Exception\RequestException.php:111

Should you need any other details, please let me know. Thanks!

maximkou commented 7 years ago

@Mulkave, Very actual problem! Maybe I propose PR for this?

linchpinstudios commented 7 years ago

I'm currently running into this issue. It would be good to have this feature available. The main reason is we have different branches being staged that need different CDN assets.