Laravel 9 accessing AWS S3 - UnableToWriteFile at location - laravel

I have built a CRUD application with Laravel, but as I want it to be hosted on heroku, using the Laravel storage is not a solution, which is why I am trying to use AWS S3.
I followed a few tutorials, and it seemed pretty straight forward to do, however I get this error :
League \ Flysystem \ UnableToWriteFile
Unable to write file at location: nameOfMyPicture.jpg.
What I have done so far :
I have run the command composer require league/flysystem-aws-s3-v3.
I have run config:clear and cache:clear.
I have run multiple times composer update.
My .env file should have the right information as well.
I tried not using .env file and putting all the information directly in the filesystems.php file.
Here is the code in my query.
if ($request->hasfile('photo')) {
$file = $request->file('photo');
$name = time() . '.' . $file->getClientOriginalExtension();
$filePath = 'locations/' . $name;
Storage::disk('s3'))->put($filePath, file_get_contents($file);
return back()->with('msg', 'Image Uploaded successfully');
}
When using
if (Storage::disk('s3')->exists('my-file-name.jpg')) {
dd("hello");
}
I get the error message : Unable to check existence for: myFileName.
When I dd(Storage::disk('s3'))->put($filePath, file_get_contents($file));, the url is null, but I do get the right bucket name, the credentials from my env file, the right region etc... Here is the dd.
^ Illuminate\Filesystem\AwsS3V3Adapter {#1388 ▼
#driver: League\Flysystem\Filesystem {#1379 ▼
-adapter: League\Flysystem\AwsS3V3\AwsS3V3Adapter {#1382 ▶}
-config: League\Flysystem\Config {#1378 ▼
-options: array:1 [▼
"url" => null
]
}
-pathNormalizer: League\Flysystem\WhitespacePathNormalizer {#1374}
}
#adapter: League\Flysystem\AwsS3V3\AwsS3V3Adapter {#1382 ▼
-client: Aws\S3\S3Client {#1343 ▼
-aliases: null
-config: array:9 [▶]
-region: "eu-west-3"
-endpoint: GuzzleHttp\Psr7\Uri {#1450 ▼
-scheme: "https"
-userInfo: ""
-host: "s3.eu-west-3.amazonaws.com"
-port: null
-path: ""
-query: ""
-fragment: ""
-composedComponents: null
}
-api: Aws\Api\Service {#1355 ▼
#definition: array:4 [▶]
#shapeMap: Aws\Api\ShapeMap {#1356 ▶}
-apiProvider: Aws\Api\ApiProvider {#1354 ▶}
-serviceName: "s3"
-apiVersion: "2006-03-01"
-operations: []
-paginators: null
-waiters: null
}
-signatureProvider: Closure($version, $service, $region) {#1353 ▶}
-credentialProvider: Closure() {#1401 ▶}
-handlerList: Aws\HandlerList {#1350 ▶}
-defaultRequestOptions: []
}
-prefixer: League\Flysystem\PathPrefixer {#1376 ▶}
-bucket: "veville-images"
-visibility: League\Flysystem\AwsS3V3\PortableVisibilityConverter {#1339 ▶}
-mimeTypeDetector: League\MimeTypeDetection\FinfoMimeTypeDetector {#1381 ▶}
-options: []
-streamReads: false
}
#config: array:11 [▼
"driver" => "s3"
"key" => "keyFromEnvFile"
"secret" => "keyFromEnvFile"
"region" => "eu-west-3"
"bucket" => "veville-images"
"url" => null
"endpoint" => null
"use_path_style_endpoint" => false
"throw" => true
"version" => "latest"
"credentials" => array:2 [▼
"key" => "keyFromEnvFile"
"secret" => "keyFromEnvFile"
]
]
#prefixer: League\Flysystem\PathPrefixer {#1377 ▶}
#temporaryUrlCallback: null
#client: Aws\S3\S3Client {#1343 ▶}
The filesystems.php file concerning s3
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'url' => env('AWS_URL'),
'endpoint' => env('AWS_ENDPOINT'),
'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
'throw' => true,
],
My .env file
AWS_ACCESS_KEY_ID=rightkey
AWS_SECRET_ACCESS_KEY=rightsecret
AWS_DEFAULT_REGION=eu-west-3
AWS_BUCKET=veville-images
AWS_USE_PATH_STYLE_ENDPOINT=false
Here is the AWS User Permission policies : user_policy.
When using the terminal, using the same AWS credentials, I have access to my bucket, and can upload and download files. However I can't through Laravel.
I am at a complete loss here. Any help would be greatly appreciated.
Thank you in advance.

To anyone who might have the same problem. I managed to upload a file to my s3 bucket.
After looking around on the github, there was a commit not merged that would give the actual error which was :
'Error executing "PutObject" on "https://bucket.s3.region.amazonaws.com/file.ext"; AWS HTTP error: cURL error 60: SSL certificate problem: unable to get local issuer certificate (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) for https://bucket.s3.region.amazonaws.com/file.ext'
To resolve that issue :
I have a very Simple Solution to this problem. You can do this without any certificate file.
Go on Laravel Root Folder -> Vender -> guzzlehttp -> guzzle -> src
open Client.php
find $defaults Array . that looks like this way.
$defaults = [
'allow_redirects' => RedirectMiddleware::$defaultSettings,
'http_errors' => true,
'decode_content' => true,
'verify' => true,
'cookies' => false
];
Now main Job is to change value of verify key.
'verify' => false,
So After this, it will not check SSL Certificate for CURL Request. This Solution works for me. I find this solution after much research.
Note: 'verify' => false can create a security issue in any Live or Development server. Do not try this on Server. This solution is only for Local System.
Answer found here : AWS SSL security error : [curl] 60: SSL certificate prob...: unable to get local issuer certificate

Related

Laravel : Countries with Laravel Analytics

I'm using Laravel Analytics to get data of the visitors of my application.
In my Google Analytics dashboard, every page have it own visits numbers, unique visitors, countries of visitors etc .. like in this image :
In my web.php, I'm creating a route to test the package :
Route::get('/data', function () {
$analyticsData = Analytics::fetchMostVisitedPages(Period::days(7));
dd($analyticsData);
});
This route returns :
Illuminate\Support\Collection {#1564 ▼
#items: array:3 [▼
0 => array:3 [▼
"url" => "/new"
"pageTitle" => "test"
"pageViews" => 1534
]
1 => array:3 [▼
"url" => "/"
"pageTitle" => "test"
"pageViews" => 450
]
2 => array:3 [▼
"url" => "/customize/8"
"pageTitle" => "test"
"pageViews" => 196
]
As you can see the returned array have only url, pageTitle and pageViews. How can I add additional informations in the returned array such as countries or geographic localisation as shown in the first image ?
I've never used the package, but reading the docs, something like this will do.
The package docs state you can use any query you want, and the Google Analytics docs give an example of getting session by location.
public function myCustomMethod($maxResults = 20)
{
$response = $this->performQuery(
$period,
'ga:sessions', // metrics
[
'dimensions' => 'ga:country',
'sort' => '-ga:sessions',
'max-results' => $maxResults,
],
);
return collect($response['rows'] ?? [])->map(fn (array $pageRow) => [
// Do something with the rows that are returned.
// I'm not sure how they're returned from the main response.
]);
}
Note, this is completely untested, you might want to fiddle with some of the data here.
Assuming I understand the documentation, this will get all countries (dimensions), it will use sessions (ga:sessions from second parameter) to measure the countries data.
It'll then just sort and get a maximum number of results.
You could change the metrics to ga:pageviews, but it's ultimately down to you what queries you want to use.
I've linked the documentation so you can find them out yourself.
You're using spatie/laravel-analytics package.
As you can see here: spatie laravel analytics - Analytics.php the fetchMostVisitedPages method that you are calling only returns that data.
Please take a look in github to see more information about this package.
fetchMostVisitedPages method:
public function fetchMostVisitedPages(Period $period, int $maxResults = 20): Collection
{
$response = $this->performQuery(
$period,
'ga:pageviews',
[
'dimensions' => 'ga:pagePath,ga:pageTitle',
'sort' => '-ga:pageviews',
'max-results' => $maxResults,
],
);
return collect($response['rows'] ?? [])->map(fn (array $pageRow) => [
'url' => $pageRow[0],
'pageTitle' => $pageRow[1],
'pageViews' => (int) $pageRow[2],
]);
}

Laravel Microsoft Graph request how to solve Cannot use object of type?

I try to do a graph request in my laravel project to connect Microsoft API. All works fine, but I don't find a way to get single data from my request.
$info = $graph->createRequest("GET", "/groups/{id}/calendar/events?\$filter=start/dateTime ge '" . $todayDate . "T00:00' and end/dateTime lt '" . $todayDate . "T23:00'")
->addHeaders(array("Content-Type" => "application/json"))
->setReturnType(\Microsoft\Graph\Model\User::class)
->setTimeout("1000")
->execute();
Output is a large json with all information. If I just want to get $info[0]['attendees'];
I get error: Cannot use object of type Microsoft\Graph\Model\User as array in file
Why? And how to access? If I try load object like $info->attendees I got error: Trying to get property 'attendees' of non-object.
This is my output (not all) of dd($info) it includes attendees as array like "id"
array:10 [▼
0 => Microsoft\Graph\Model\Event {#1532 ▼
#_propDict: array:43 [▼
"#odata.etag" => "{tag}""
"id" => "{id}"
"createdDateTime" => "2021-03-19T10:36:08.0812445Z"
"lastModifiedDateTime" => "2021-03-19T10:36:11.9402917Z"
"attendees" => array:1 [▼
0 => array:3 [▼
"type" => "required"
"status" => array:2 [▶]
"emailAddress" => array:2 [▼
"name" => "name"
"address" => "mail"
]
]
]
It seems your array is returning an array of attendees, you have an extra level in your array. So to fetch the first attendees status, you need to use the following code:
Try this
foreach($info as $item){
foreach($item as $inf ){
$a = $inf->status
dd($a)
}
}

Facebook marketing API insights (Destination url)

I'm trying to get data using Facebook Marketing API.
$api = FacebookAds::init('TOKEN');
$start = Carbon::create(2018,11,16);
$end = Carbon::create(2018,11,16);
$period = Period::create($start,$end);
$in = $api->insights($period,'act_ID', 'ad',[
'fields' => ['impressions', 'objective', 'actions'....]
]);
I'm getting each ad actions like this:
"actions" => array:10 [▼
0 => array:2 [▼
"action_type" => "comment"
"value" => "1"
]
1 => array:2 [▼
"action_type" => "offsite_conversion.fb_pixel_purchase"
"value" => "1"
]
2 => array:2 [▼
"action_type" => "photo_view"
"value" => "114"
]....
]
My question is how to get each ad destination URL?
Thanks
You actually have to use AdCreative information to get the destination URL: https://developers.facebook.com/docs/marketing-api/reference/ad-creative/
I use the object_story_spec and match the AdCreative with the Ad by id ( they share the same ID ).
https://graph.facebook.com/v14.0/'adcreativeid'/?fields=object_story_spec
You can use this code. Destination URL will mentioned in link data -> link

Laravel: Test post with real file

I'm using laravel 5.6. I'm trying to test a post form that need a file.
So I wrote that
$file = new \Illuminate\Http\UploadedFile(base_path() . '/tests/samples/Cylinder.stl', 'Cylinder.stl');
$response = $this->post( route('attachments.store' ) , [
'file' => $file,
'attachable_id' => $this->threedviews->id,
'attachable_type' => 'App\ThreeDView',
]);
But when I dd( $this->app['session.store'] ), I get
#bags: array:1 [
"default" => Illuminate\Support\MessageBag {#1198
#messages: array:1 [
"file" => array:1 [
0 => "The file failed to upload."
]
]
#format: ":message"
}
]
When I use the form manualy, everything is working well.
Also the $file seems strange
Illuminate\Http\UploadedFile {#43
-test: false
-originalName: "Cylinder.stl"
-mimeType: "application/octet-stream"
-error: 0
...
}
The test flag is set to false, is it supposed to be like this?

Laravel creating a request instance with a url string

I am looking to create a request instance in Laravel using a url string. I have this piece of code which does the job, URL segments is wrong.
$previous_request = app('request')->create($previous_url);
The following is the URL segments from the manually created request.
array:7 [▼
0 => "developments"
1 => "tour"
2 => "public"
3 => "en"
4 => "admin"
5 => "products"
6 => "items"
]
The following is the example of the request provided from Laravel itself.
array:4 [▼
0 => "en"
1 => "admin"
2 => "products"
3 => "items"
]
Anyone have done similar things before and is able to help out?
It is located in the referrer in the request's header.
$referer = $request->header('referer');
or
$referer = Request::server('HTTP_REFERER');

Resources