Laravel file not saved but recorded in database - php

I am accepting a file and some other parameters with it. I validate the file and the parameters and then I store the file while making a record in the database. Pretty standard stuff. The issue I have is that a majority of my files and records get saved but sometimes there exists a record in the database but there is no file associated with it saved. I have tried reproducing it but I haven't been able to. I don't know if the error is my code, or my server or if the user prematurely loses connection or some other issue of that nature.
I am running Laravel 7 on AWS Lightsail instance with Bitnami LAMP stack.
Store Method in Controller
public function store(StoreRequest $request)
{
$filePath = $request
->file('file')
->storeAs(
'path',
Str::upper($request->input('param1')) .
"_{$request->input('param2')}_{$request->input(
'param3'
)}_{$request->input('param4')}_{$request->input(
'param5'
)}_" .
now()->format('Ymd_Hi') .
".{$request->file('file')->getClientOriginalExtension()}",
'public'
);
Storage::setVisibility('public/' . $filePath, 'private');
$record = Model::create(
array_merge($request->all(), ['file' => $filePath])
);
return redirect()
->back()
->with('message', 'File submitted successfully');
}
Rules in StoreRequest
public function rules()
{
$rules = [
//rules for other parameters
'filetype' => ['required', 'string'],
];
if (request('filetype') === 'video') {
$rules['file'] = [
'required',
'file',
'mimetypes:video/*',
'max:200000',
];
} elseif (request('filetype') === 'image') {
$rules['file'] = ['required', 'file', 'image', 'max:20000'];
}
return $rules;
}
I have 259 records on the database but I have only received 247 files. Where could the error lie? I have tried on my development environment but I haven't been able to reproduce an error like this. Is it something to do with my php.ini settings? Is it something that the user is causing? How can the file not be saved when I am saving it before the record gets stored in the database?

You are using Ymd_Hi which would not allow for any records saved in the same minute, perhaps use a timestring or include seconds too, but be warned, if you use seconds you may face the same issue!

There are two options in pho.ini file. One is upload_max_filesize and another one post_max_size. While uploading the file I think it crosses the size that defined in ini file.
If your video size 200 MB then upload_max_size should be more than or equal 200 MB. post_max_size is total size of form that going to be submitted. It is safer to set size more than upload_max_size.

Related

Validating a large CSV file format in Laravel

I would like to validate a large (up to millions of rows) CSV file content without reading it twice : once in the validation request file, once when storing the content of the CSV file to the database. What's the best, clean and efficient approach?
Here is what I have so far:
CreateSymbolRequest.php:
public function rules()
{
return [
'prices' => [
'bail',
'required',
'file',
'max:8192',
new PriceFileExtensionsRule(['csv']),
new PriceFileHeadersRule,
new PriceFileDataFormatRule
],
'pair' => 'required|array',
'timeframe' => 'required|in:1S,1,1H,4H,1D,1W,1M',
'type' => 'required|in:spot,future',
'exchange' => 'required|in:FTX,binance',
'tx_fee' => 'required|numeric',
'm_fee' => 'required|numeric'
];
}
public function persist(): void
{
// checks if the Symbol already exists in the DB
if ($this->isSymbolDuplicate()) {
throw new Exception('Symbol already exists in the database.');
}
// Stores the Symbol in the DB
$this->persistSymbol();
// Stores the CSV content in the DB
$this->persistPrices();
}
SymbolsController:
public function store(CreateSymbolRequest $request)
{
$request->persist();
}
Of course, I could split the basic validation in CreateSymbolRequest.php and the more advanced validation in SymbolsController.php, but that would kind of defeat the purpose of having a separate Request file with the validation rules in it.
I was also thinking of passing a $content variable by reference to the Rule files but I don't think I can return anything from there and that feels very ugly anyway.

Laravel 5.4 file upload validation fails for python files

I'm trying to figure out what is wrong with my validation, but I'm not sure.
I have created a file upload that uploads the file to S3. Works fine except when I need to validate python files.
In my FileUploadController.php I have a store(FileStoreRequest $request) method that handles the upload. I added the $validatedData = $request->validate(); in it and it works.
I have also added the mimes.php in config folder with the following:
<?php
return [
'zip' => array('application/x-zip', 'application/zip', 'application/x-zip-compressed'),
'py' => array('text/plain', 'application/x-python' , 'application/octet-stream, application/x-python-code, text/x-python-script', 'text/x-python'),
];
And the rules() method inside my FileStoreRequest class is
public function rules()
{
return [
'preprocessor' => 'mimes:py',
];
}
Any time I try to upload the python file I get the error
The preprocessor must be a file of type: py.
When I remove the mimes check from the rules() it passes.
The rules work, because I tested it on another view for zip file upload.
Any ideas what could be wrong?
You can create custom validation like:
$input = $request->all();
if (isset($input["preprocessor"]) && !empty($input["preprocessor"])) {
$filesource = $input["preprocessor"];
$fileExtension = $filesource->getClientOriginalExtension();
$input["ext"] = $fileExtension;
}
$rules = array(
'ext' => 'nullable|in:py',
);

Laravel get path of saved file from upload

I have a laravel upload for file (along with other data that is passed to the database) Everything works. But I just can't figure out how to save the path of the file that is saved.
Here is my controller function:
public function store(Request $request)
{
request()->validate([
'name' => 'required',
'logo' => 'nullable',
'original_filename' => 'nullable',
]);
//This is where the file uploads?
if ($request->hasFile('logo')) {
$request->file('logo')->store('carrier_logo');
$request->merge([
'logo' => '',//TODO: get file location
'original_filename' => $request->file('logo')->getClientOriginalName(),
]);
}
Carrier::create($request->all());
return redirect()->route('carriers.index')->with('toast', 'Carrier created successfully.');
}
The thing I want to achieve:
I want logo to fill with something like carrier_logo/ZbCG0lnDkUiN690KEFpLrNcn2exPTB8mUdFDwAKN.png
The thing that happened every time I tried to fix it was that it placed the temp path in the database. Which ended up being something in the PHP install directory.
Just assign result to variable:
$path = $request->file('logo')->store('carrier_logo');
According to docs
Then you can do with $path variable whatever you want.
just assign the value like this.
$location=base_path('img/'.$filename);
and save it in db.
You could do this:
For FileName
$fileName = $request->file('test')->getClientOriginalName();
OR
$fileName = $request->user()->id.'.'.$request->file('logo')->getClientOriginalExtension();
$imageDirectory = 'logo_images';
$path = $request->file('logo')->storeAs($imageDirectory, $fileName);
dd($path);

YII2 XML file upload wont validate

I'm making a file upload controller to upload a bunch of XML files to a server.
However, some XML files don't have the <xml version="1.0" encoding="UTF-8"> tag and Yii validator fails to upload these files.
public $xmlFiles;
public function rules() {
return [
[['xmlFiles'], 'file', 'skipOnEmpty' => false, 'extensions' => 'xml', 'maxFiles' => 20],
];
}
public function upload($path) {
if (empty($path)) {
return false;
}
FileHelper::createDirectory($path);
if ($this->validate()) {
foreach ($this->xmlFiles as $file) {
$file->saveAs($path . $file->baseName . '.' . $file->extension);
}
return true;
}
else {
return false;
}
}
How can I change my validation rule to allow this kind of files?
You can always set checkExtensionByMimeType to false in your validation rule and see if it helps.
This one forces validator to not compare MIME type with file extension and thanks to this some files can pass (like plain text *.csv files or probably your *.xml files). Be aware that with this option user can send you any malicious file only by renaming its extension.
Edit:
You can set mimeTypes property in your rule to specific all the MIME types you want to be valid. In your case it might be something like:
['xmlFiles', 'file', 'skipOnEmpty' => false, 'mimeTypes' => ['application/xml'], 'maxFiles' => 20],
With extensions property removed only MIME type is being checked.
It is possible though that in your case MIME type is just text/plain (you should check this first). You can set this here but it will allow all plain text files which is still better than allowing everything.

Error while testing file uploads in laravel 5.4

I am trying to add a profile image feature in my app. I am using the TDD approach to do this. The test for uploading profile picture shows green. But when I run the test to update the profile picture, it gives an error. Below is the code:
Controller:
public function store(StoreAvatarRequest $request)
{
$path = $request->file('avatar')->store('avatars');
BasicInformation::updateOrCreate([
'user_id' => auth()->id(),
], [
'user_id' => auth()->id(),
'avatar' => $path,
]);
$this->showAlerts('alert-success', 'Profile Image uploaded successfully');
return redirect()->route('avatar.index');
}
public function update(StoreAvatarRequest $request, $id)
{
$basicProfile = BasicInformation::find($id)->first();
$oldAvatarPath = $basicProfile->avatar;
if ($basicProfile->user_id == auth()->id()) {
$path = $request->file('avatar')->store('avatars');
$basicProfile->avatar = $path;
$basicProfile->update();
Storage::delete($oldAvatarPath);
$this->showAlerts('alert-success', 'Profile Image Updated Successfully');
return redirect()->route('avatar.index');
} else {
// TODO :: Need to add logic here
}
}
Test Case:
public function can_update_profile_picture()
{
$this->actingAs($this->lawyer)->post(route('avatar.store'), [
'avatar' => UploadedFile::fake()->image('avatar.jpg', 600, 600)
]);
$oldImagePath = $this->lawyer->information->avatar;
$this->actingAs($this->lawyer)->put(route('avatar.update', ['id' => $this->lawyer->information->id]), [
'avatar' => UploadedFile::fake()->image('avatar1.jpg', 600, 600)
])
->assertRedirect(route('avatar.index'))
->assertSessionHas('status', 'Profile Image Updated Successfully');
Storage::disk('local')->assertExists($this->lawyer->information->avatar);
Storage::disk('local')->assertMissing($oldImagePath);
}
I am getting the following error when I run the test:
PHPUnit 5.7.19 by Sebastian Bergmann and contributors.
F 1 /
1 (100%)
Time: 298 ms, Memory: 20.00MB
There was 1 failure:
1) Tests\Feature\Dashboard\Lawyer\Account\ProfileImageTest::can_update_profile_picture
Unable to find a file at path [local/c5tjUUQDzU4iKHauJK68Z801I5iaYJ7e3cVQ5iA1.jpeg].
Failed asserting that false is true.
This is a matter of configuration and then preference for using store() or storeAs() methods.
First off you have to configure filesystems.phpto recognize your tests Storage disk as the fake() disk:
'testing' => [
'driver' => 'local',
'root' => storage_path('framework/testing/disks/'),
'visibility' => 'public',
Using that setup allows you to use your APP_ENV value in phpunit.xmlfor defaulting this disk for your tests.
Also, I use the use the storeAs()in my controller so that I can test against the filename I stored in the assertExists() method in my test.
$request->file('avatar')->storeAs('avatar', $request->file('avatar')->getClientOriginalName())
Storage::disk('avatar')->assertExists('avatar.jpg');
This is what works for me and the files are deleted before running each test and clean up is not an issue. You can also do a test for the hashName and use the store() method by getting the responsed and using baseName() to get the name of the new file.
I have added to phpunit.xml next line:
<env name="FILESYSTEM_DRIVER" value="uploads"/>
and while checking
$image = $response->original['logo']; // as the image name get changed in Controller
Storage::disk('uploads')->assertExists("public/uploads/$image");
Others codes are similar as Laravel Doc.
You may Like to check the discussion at Laracast.

Categories