Laravel 6 Unit Test file upload unable to find file at path - laravel

I'm writing a unit test in laravel 6 to test file uploading. I have a form that is creating a group and there is a file upload for covers.
My unit test is as follows
$this->WithoutExceptionHandling();
//login as admin
$admin = $this->signInAsAdmin();
Storage::persistentFake('public');
$attributes = [
'group_name' => $this->faker->name,
'group_description' => $this->faker->paragraph,
'group_privacy' => '0',
'group_cover' => $file = UploadedFile::fake()->image('random.jpg')
];
//create new group
$response = $this->post('/admin/groups', $attributes);
unset($attributes['group_cover']);
Storage::disk('public')->assertExists($file);
//check the data exists in database
$this->assertDatabaseHas('groups', $attributes);
//how is the uploaded file written to database
//check the data exists in database
$this->assertDatabaseHas('media', ['file_name' => $file]);
//make sure the title appears on the group list
$this->get('/admin/groups')->assertSee($attributes['group_name']);
The error I am getting is:
Unable to find a file at path [php624B.tmp].
Failed asserting that false is true.
I have also set in my php.ini file the upload_tmp_dir
upload_tmp_dir = C:\path_to_laravel_app\storage\tmp\uploads
What seems to be happening is that the faker library is not creating a temporary image. Doesn't matter what folder I set the tmp location to.
Any help would be appreciated
Danny

Related

Laravel Intervention - Unable to init from given binary data

I am using "intervention/image": "^2.5" in one of my projects. It is working well except for one part of the code where im retrieving an image.
I keep getting a Unable to init from given binary data error and i cant figure out why.
The file exists but i cant figure it out.
My code is as follows;
$path = '/image-storage/492/1/testimage.jpg';
$file = Storage::get($path);
ob_end_clean();
return Image::make($file)->response();
Below is my filesystem.php config for local
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
],
Storage::get($path) returns file contents as a string which may not be cast to valid binary data for Image::make() to be able to read.
You can try by passing the path to the image to the make method
//If testimage.jpg is located at storage/app/image-storage/492/1
$path = storage_path('app/image-storage/492/1/testimage.jpg');
//if testimage.jpg is located at storage/app/public/image-storage/492/1/, then
//$path = storage_path('app/public/image-storage/492/1/testimage.jpg');
return Image::make($path)->response();
OR you can create a new Illuminate\Http\File instance and then pass it to the make method
//If testimage.jpg is located at storage/app/image-storage/492/1
$path = storage_path('app/image-storage/492/1/testimage.jpg');
//if testimage.jpg is located at storage/app/public/image-storage/492/1/, then
//$path = storage_path('app/public/image-storage/492/1/testimage.jpg');
$file = new \Illuminate\Http\File($path);
Image::make($file)->response();
Intervention image accepts binary data or SplFileInfo instance. Illuminate\Http\File extends Symfony\Component\HttpFoundation\File\File which extends \SplFileInfo.
Intervention Image - Reading Images

Laravel: how to upload pdf file directly to Google Cloud Storage bucket without first saving it locally

I am using the google/cloud-storage package in an API and successfully uploading pdf files to a Google Cloud Storage bucket. However, the pdf files are first saved locally before they are uploaded to the Google Cloud Storage bucket.
How can I skip saving them locally and instead upload them directly to the Google Cloud Storage bucket? I am planning to host the API on Google App Engine.
This is the post for it.
This is what I am doing currently:
$filename = $request['firstname'] . '.pdf';
$fileStoragePath = '/storage/pdf/' . $filename;
$publicPath = public_path($fileStoragePath);
$pdf = App::make('dompdf.wrapper');
$pdf->loadView('pdfdocument', $validatedData)
$pdf->save($publicPath);
$googleConfigFile = file_get_contents(config_path('googlecloud.json'));
$storage = new StorageClient([
'keyFile' => json_decode($googleConfigFile, true)
]);
$storageBucketName = config('googlecloud.storage_bucket');
$bucket = $storage->bucket($storageBucketName);
$fileSource = fopen($publicPath, 'r');
$newFolderName = $request['firstname'].'_'.date("Y-m-d").'_'.date("H:i:s");
$googleCloudStoragePath = $newFolderName.'/'.$filename;
/*
* Upload a file to the bucket.
* Using Predefined ACLs to manage object permissions, you may
* upload a file and give read access to anyone with the URL.
*/
$bucket->upload($fileSource, [
'predefinedAcl' => 'publicRead',
'name' => $googleCloudStoragePath
]);
Is it possible to upload files to a Google Cloud Storage bucket without first saving them locally?
Thank you for your help.
I have not verified this code, but the class PDF member output() returns a string.
$pdf = App::make('dompdf.wrapper');
$pdf->loadView('pdfdocument', $validatedData)
...
$bucket->upload($pdf->output(), [
'predefinedAcl' => 'publicRead',
'name' => $googleCloudStoragePath
]);
You can simply the client code. Replace:
$googleConfigFile = file_get_contents(config_path('googlecloud.json'));
$storage = new StorageClient([
'keyFile' => json_decode($googleConfigFile, true)
]);
with
$storage = new StorageClient([
'keyFilePath' => config_path('googlecloud.json')
]);

Laravel default Storage path change

I want to save image in main public folder using laravel file storeAs method. Is there anyway to change the path in using this code?
$path = $request->img->storeAs('images', 'filename.jpg');
I'm already try add new disks in filesystems.php to this
'my' => [
'driver' => 'local',
'root' => public_path('app'),
'visibility' => 'public',
],
and store using this code
Storage::disk('my')->put('filename.jpg', $request->img);
but using above code it make new folder name 'filename.jpg' and save image inside that folder using random name. But I want to save that image name that 'filename.jpg'.
thank you.
You can do this very easily
$imageName = $request->file('image_name')->getClientOriginalName();
$directory = 'your/directory/path/';
$imageUrl = $directory . $imageName;
$productImage->move($directory, $imageName);
It is not in the documentation but if you check storeAs method implementation (https://github.com/laravel/framework/blob/7.x/src/Illuminate/Http/UploadedFile.php#L80) you'll see that it is possible to pass an array of options as the third parameter. The disk key is used to set witch should be used. So your code would be:
$path = $request->img->storeAs('images', 'filename.jpg', ['disk' => 'my');
Bear in mind that if you are storing in a path that does not exists it is necessary to give the parent folder permission to create new directories.

Laravel - IBM-Cloud Object Storage

I am trying to setup my Laravel application to use the Object Storage service from IBM-Cloud. What I want is to upload a file and get a static public URL foreach file, but I am currently having some trouble to access the file after upload.
Installed package:
league/flysystem-aws-s3-v3
Created a new service provider for the bluemix storage suggested in this post:
How to connect Laravel 5 app with object-storage bucket?
Within my controller I use the following call to upload the file:
Storage::disk('object-storage')->put($full_name,$file);
Upload works fine, and I can see the file in the bucket. The problem appears when I am trying to access the file.
According to the IBM documentation I need to set the ACL to public-read to be able to access the file publicly. After some research I modified the Filesystem call:
Storage::extend('object-storage', function($app, $config) {
$client = S3Client::factory([
'credentials' => [
'key' => $config['key'],
'secret' => $config['secret'],
],
'region' => $config['region'],
'version' => $config['version'],
'endpoint' => $config['endpoint'],
]);
$adapter = new AwsS3Adapter($client, $config['bucket_name']);
return new Filesystem($adapter,['ACL' => 'public-read']);
});
I have also tried to set the visibility trough the Storage call in the controller:
Storage::disk('object-storage')->setVisibility($full_name,'public-read');
Then I tried to access the file to read the visibility by using the getVisibility:
Storage::disk('object-storage')->getVisibility($full_name);
This gives me an 404 error on getObjectAcl with message:
The specified key does not exist on https://bucket-name.s3.eu-gb.objectstorage.softlayer.net/sApQNtdUvJYg7YWsL8IbCe26U6EK8v.png?acl
If I try to copy the URL address and paste it in my browser I get Access Denied error.
The authentication credentials that is used within the calls is set as Manager.
Is there anyone who has a solution for this problem, or does it exist any guide to upload and read the files using Laravel?
I did so.
$response = $filesystem->put($new_name, file_get_contents($file), ['ACL' => 'public-read'] );
try this
Storage::disk('object-storage')->put($full_name,$file, ['ACL' => 'public-read']);

Laravel : To rename an uploaded file automatically

I am allowing users to upload any kind of file on my page, but there might be a clash in names of files. So, I want to rename the file automatically, so that anytime any file gets uploaded, in the database and in the folder after upload, the name of the file gets changed also when other user downloads the same file, renamed file will get downloaded.
I tried:
if (Input::hasFile('file')){
echo "Uploaded</br>";
$file = Input::file('file');
$file ->move('uploads');
$fileName = Input::get('rename_to');
}
But, the name gets changed to something like:
php5DEB.php
phpCFEC.php
What can I do to maintain the file in the same type and format and just change its name?
I also want to know how can I show the recently uploaded file on the page and make other users download it??
For unique file Name saving
In 5.3 (best for me because use md5_file hashname in Illuminate\Http\UploadedFile):
public function saveFile(Request $request) {
$file = $request->file('your_input_name')->store('your_path','your_disk');
}
In 5.4 (use not unique Str::random(40) hashname in Illuminate\Http\UploadedFile). I Use this code to ensure unique name:
public function saveFile(Request $request) {
$md5Name = md5_file($request->file('your_input_name')->getRealPath());
$guessExtension = $request->file('your_input_name')->guessExtension();
$file = $request->file('your_input_name')->storeAs('your_path', $md5Name.'.'.$guessExtension ,'your_disk');
}
Use this one
$file->move($destinationPath, $fileName);
You can use php core function rename(oldname,newName) http://php.net/manual/en/function.rename.php
Find this tutorial helpful.
file uploads 101
Everything you need to know about file upload is there.
-- Edit --
I modified my answer as below after valuable input from #cpburnz and #Moinuddin Quadri. Thanks guys.
First your storage driver should look like this in /your-app/config/filesystems.php
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'), // hence /your-app/storage/app/public
'visibility' => 'public',
],
You can use other file drivers like s3 but for my example I'm working on local driver.
In your Controller you do the following.
$file = request()->file('file'); // Get the file from request
$yourModel->create([
'file' => $file->store('my_files', 'public'),
]);
Your file get uploaded to /your-app/storage/app/public/my_files/ and you can access the uploaded file like
asset('storage/'.$yourModel->image)
Make sure you do
php artisan storage:link
to generate a simlink in your /your-app/public/ that points to /your-app/storage/app/public so you could access your files publicly. More info on filesystem - the public disk.
By this approach you could persists the same file name as that is uploaded. And the great thing is Laravel generates an unique name for the file so there could be no duplicates.
To answer the second part of your question that is to show recently uploaded files, as you persist a reference for the file in the database, you could access them by your database record and make it ->orderBy('id', 'DESC');. You could use whatever your logic is and order by descending order.
You can rename your uploaded file as you want . you can use either move or storeAs method with appropiate param.
$destinationPath = 'uploads';
$file = $request->file('product_image');
foreach($file as $singleFile){
$original_name = strtolower(trim($singleFile->getClientOriginalName()));
$file_name = time().rand(100,999).$original_name;
// use one of following
// $singleFile->move($destinationPath,$file_name); public folder
// $singleFile->storeAs('product',$file_name); storage folder
$fileArray[] = $file_name;
}
print_r($fileArray);
correct usage.
$fileName = Input::get('rename_to');
Input::file('photo')->move($destinationPath, $fileName);
at the top after namespace
use Storage;
Just do something like this ....
// read files
$excel = $request->file('file');
// rename file
$excelName = time().$excel->getClientOriginalName();
// rename to anything
$excelName = substr($excelName, strpos($excelName, '.c'));
$excelName = 'Catss_NSE_'.date("M_D_Y_h:i_a_").$excelName;
$excel->move(public_path('equities'),$excelName);
This guy collect the extension only:
$excelName = substr($excelName, strpos($excelName, '.c'));
This guy rename its:
$excelName = 'Catss_NSE_'.date("M_D_Y_h:i_a_").$excelName;

Resources