Laravel validate float - php

I'm trying to validate float in my laravel app.
I'm using laravel validation and anything I try is not correct.
I tried something like
$validator = Validator::make($request->all(), [
'packages.*.real_price' => 'required|regex:/^\d*(\.\d{2})?$/'
]
I tried with numeric, integer, and basically everything that I can find on the internet, but every time I receive error like:
TypeError: Argument 6 passed to App\Http\Controllers\ProductController::createPackageInfo() must be of the type float, string given
As you can see I'm giving string to test it. Any suggestions?
I'm sending request like
{
"sku":"asd",
"slug":"admin#admin.com",
"category":"2",
"type":"accessory",
"product_info":[
{
"country":184,
"name":"asd",
"slug":"asd",
"description":"asd"
}
],
"packages":[
{
"country":98,
"name":"asd",
"slug":"asd",
"qty":"12",
"real_price":"123",
"sale_price":"asd",
"delivery_price":"123"
}
]
}
How am I calling this method?
try{
$createdPackageInfo = self::createPackageInfo($createdPackage, $country, $name, $slug, $real_price, $sale_price, $delivery_price, $image);
}catch (\Exception $e) {
Log::log('Something bad happened', 'POST', $e);
return response()->json(['response' => false, 'message' => 'Something went wrong with creating package info'], 400);
}
and function that I'm calling
private static function createPackageInfo(int $package_id, int $country_id, string $name, string $slug, float $real_price, float $sale_price, float $delivery_price, string $image)
{
$packageInfo = PackageInfo::create(['package_id' => $package_id, 'country_id' => $country_id, 'name' => $name, 'slug' => $slug, 'real_price' => $real_price, 'sale_price' => $sale_price, 'delivery_price' => $delivery_price, 'image' => $image]);
return $packageInfo->id;
}

The error is pretty clear, when you call your function createPackageInfo, you pass (I guess) the result of the string you showed.
I guess you typed your params in createPackageInfo() function, and in your JSON, we can you have :
"real_price":"123",
"sale_price":"asd",
Double quotes mean the values are STRING typed.
You can simply use :
$createdPackageInfo = self::createPackageInfo($createdPackage, $country, $name, $slug, (float) $real_price, (float) $sale_price, (float) $delivery_price, $image);

How about custom validating if the string is numeric, then do a type conversion of it everytime you pass it to the function
$validator = Validator::make($request->all(), [
'packages.*.real_price' => 'required|numeric'
]
And when you are calling this method, typecast it,
$typecasted_real_price = $real_price+ 0.0;
$createdPackageInfo = self::createPackageInfo($createdPackage, $country, $name, $slug, $typecasted_real_price, $sale_price, $delivery_price, $image);
// or
$createdPackageInfo = self::createPackageInfo($createdPackage, $country, $name, $slug, ($real_price+ 0.0), $sale_price, $delivery_price, $image);
Logic behind adding 0.0
$num = "1000";
// Performing mathematical operation to implicitly type conversion
echo $num + 0.0, "\n"; // value = 1000
echo gettype($num + 0.0), "\n"; // type = double

Related

Uploading Multipart Files with Uppy/Laravel/Vue

I'm using Uppy's Vue components to handle uploading large files and I'm having trouble getting it to work.
I've followed the suggestion by Janko here which involves setting the companionUrl in Uppy to point to my server, then write the necessary routes/functions to process the requests.
Everything is working until I try to fire the AWS "completeMultipartUpload" call.
$result = $client->completeMultipartUpload([
'Bucket' => 'bucket-name',
'Key' => $key,
'UploadId' => $uploadId,
'MultipartUpload' => [
'Parts' => $formattedParts,
],
]);
I get the following error:
"Error executing "CompleteMultipartUpload" on "https://bucket-name.s3.amazonaws.com/NewProject.png?uploadId=nlWLdbNgB9zgarpLBXnj17eOIGAmQM_xyBArymtwdM71fhbFvveggDmL6fz4blz.B95TLhMatDvodbMb5p2ZMKqdlLeLFoSW1qcu33aRQTlt6NbiP_dkDO90DFO.pWGH"; AWS HTTP error: Client error: `POST https://bucket-name.s3.amazonaws.com/NewProject.png?uploadId=nlWLdbNgB9zgarpLBXnj17eOIGAmQM_xyBArymtwdM71fhbFvveggDmL6fz4blz.B95TLhMatDvodbMb5p2ZMKqdlLeLFoSW1qcu33aRQTlt6NbiP_dkDO90DFO.pWGH` resulted in a `400 Bad Request` response:
<Error><Code>InvalidPart</Code><Message>One or more of the specified parts could not be found. The part may not have be (truncated...)
InvalidPart (client): One or more of the specified parts could not be found. The part may not have been uploaded, or the specified entity tag may not match the part's entity tag. - <Error><Code>InvalidPart</Code><Message>One or more of the specified parts could not be found. The part may not have been uploaded, or the specified entity tag may not match the part's en"
I think that the problem is I've tried translating the JS found here to PHP, but although it's returning a URL, it's not correct. The notable difference is that I'm not passing an "UploadId" or a "PartNumber".
I've scoured the AWS docs, Google, Stackoverflow, Ask Jeeves, etc and couldn't find a PHP equivalent of the "getSignedUrl" method
public function signPartUpload(Request $request, $uploadId, $partNumber)
{
$client = new S3Client([
'version' => 'latest',
'region' => 'us-east-1',
]);
$key = $request->has('key') ? $request->get('key') : null;
if (!is_string($key)) {
return response()->json(['error' => 's3: the object key must be passed as a query parameter. For example: "?key=abc.jpg"'], 400);
}
if (!intval($partNumber)) {
return response()->json(['error' => 's3: the part number must be a number between 1 and 10000.'], 400);
}
//Creating a presigned URL
$cmd = $client->getCommand('PutObject', [
'Bucket' => 'bucket-name',
'Key' => $key
]);
$response = $client->createPresignedRequest($cmd, '+20 minutes');
$presignedUrl = (string)$response->getUri();
return response()->json(['url' => $presignedUrl]);
}
Any help would be greatly appreciated!
I found the PHP equivalent of the getSignedUrl method.
$command = $this->client->getCommand('UploadPart', [
'Bucket' => $this->bucket,
'Key' => $key,
'PartNumber' => $partNumber,
'UploadId' => $uploadId,
'Body' => '',
]);
Here's my solution:
/**
* Create a pre-signed URL for parts to be uploaded to.
* #param Request $request
* #param string $uploadId
* #param int $partNumber
* #return JsonResponse
*/
public function signPartUpload(Request $request, string $uploadId, int $partNumber)
{
$key = $request->has('key') ? $request->get('key') : null;
// Check key
if (! is_string($key)) {
return response()->json(['error' => 's3: the object key must be passed as a query parameter. For example: "?key=abc.jpg"'], 400);
}
// Check part number
if (! intval($partNumber)) {
return response()->json(['error' => 's3: the part number must be a number between 1 and 10000.'], 400);
}
// Create the upload part command and get the pre-signed URL
try {
$command = $this->client->getCommand('UploadPart', [
'Bucket' => $this->bucket,
'Key' => $key,
'PartNumber' => $partNumber,
'UploadId' => $uploadId,
'Body' => '',
]);
$presignedUrl = $this->client->createPresignedRequest($command, '+20 minutes');
} catch (Exception $e) {
return response()->json(['error' => $e->getMessage()], 400);
}
// Convert the pre-signed URL to a string
$presignedUrlString = (string) $presignedUrl->getUri();
return response()->json(['url' => $presignedUrlString]);
}

Amazon Pay SDK InvalidSignatureError

I'm integrating Amazon Pay php SDK from documentation, but getting this error.
Here's my php implementation code:
$amazonpay_config = array(
'public_key_id' => 'XXXXXXXX',
'private_key' => 'my_private_key_path',
'region' => 'US',
'sandbox' => true
);
$payload = array(
'webCheckoutDetails' => array(
'checkoutReviewReturnUrl' => 'https://www.example.com/review',
'checkoutResultReturnUrl' => 'https://www.example.com/result'
),
'storeId' => 'amzn1.application-oa2-client.XXXXXXXXX'
);
$headers = array('x-amz-pay-Idempotency-Key' => uniqid());
$requestResult = [
'error' => 1,
'msg' => 'Error. Can not create checkout session.',
'checkoutSession' => null,
'payloadSign' => null
];
$client = new Client($amazonpay_config);
$resultCheckOut = $client->createCheckoutSession($payload, $headers);
$resultSignPayload = $client->generateButtonSignature($payload);
if($resultCheckOut['status'] !== 201) {
return json_encode($requestResult, true);
}
else {
$requestResult = [
'error' => 0,
'msg' => null,
'checkoutSession' => json_decode($resultCheckOut['response']),
'payloadSign' => $resultSignPayload
];
return $requestResult;
}
Here's JS implementation code for generating Amazon Pay button.
amazon.Pay.renderButton('#amazon-pay-btn', {
// set checkout environment
merchantId: 'XXXXXXXX',
ledgerCurrency: 'USD',
sandbox: true,
checkoutLanguage: 'en_US',
productType: 'PayOnly',
placement: 'Cart',
buttonColor: 'Gold',
createCheckoutSessionConfig: {
payloadJSON: jsonResult['checkoutSession'],
signature: jsonResult['payloadSign'],
publicKeyId: 'XXXXXXXXXXX'
}
});
Couple of problems with the code, mainly that you aren't passing the payload and signature to the front-end correctly. For the payload, you're using jsonResult['checkoutSession'], while it should be jsonResult['payloadSign']. This doesn't contain the payload though but from the PHP code it's apparently the signature that you have put in there. The full code sample should more like this (not tested).
Back-end:
$headers = array('x-amz-pay-Idempotency-Key' => uniqid());
$requestResult = [
'error' => 1,
'msg' => 'Error. Can not create checkout session.',
'signature' => null,
'payload' => null
];
$client = new Client($amazonpay_config);
$resultCheckOut = $client->createCheckoutSession($payload, $headers);
$resultSignature = $client->generateButtonSignature($payload);
if($resultCheckOut['status'] !== 201) {
return json_encode($requestResult, true);
}
else {
$requestResult = [
'error' => 0,
'msg' => null,
'signature' => $resultSignature,
'payload' => $payload
];
return json_encode($requestResult);
}
Front-end:
amazon.Pay.renderButton('#amazon-pay-btn', {
// set checkout environment
merchantId: 'XXXXXXXX',
ledgerCurrency: 'USD',
sandbox: true,
checkoutLanguage: 'en_US',
productType: 'PayOnly',
placement: 'Cart',
buttonColor: 'Gold',
createCheckoutSessionConfig: {
payloadJSON: JSON.stringify(jsonResult['payload']),
signature: jsonResult['signature'],
publicKeyId: 'XXXXXXXXXXX'
}
});
I'm not sure how you're passing $requestResult back to the front-end, potentially there's some additional JSON encoding/decoding required to get the right string. To prevent a signature mismatch error, please make sure that the payload string used for the signature generation in the backend, and the payload string assigned to the 'payloadJSON' parameter match exactly (especially pay attention to whitespaces, escape characters, line breaks, etc.).
Two comments about this issue:
I have defined the payload as an string (that's the way current AmazonPay doc states - Link).
$payload = '{
"webCheckoutDetails": {
"checkoutReviewReturnUrl": "https://www.example.com/review",
"checkoutResultReturnUrl": "https://www.example.com/result"
},
"storeId": "amzn1.application-oa2-client.XXXXXXXXX"
}';
instead of array
$payload = array(
'webCheckoutDetails' => array(
'checkoutReviewReturnUrl' => 'https://www.example.com/review',
'checkoutResultReturnUrl' => 'https://www.example.com/result'
),
'storeId' => 'amzn1.application-oa2-client.XXXXXXXXX'
);
The signature was created, but when rendering the button and clicking on it I get the following error.
Error Message: Signature Dk4qznkoiTVqjcY8Yn1l0iLbsoIj2pEAHWVtgYrphLtFXR9BKhJJPD53It4qYOswS1T/STYMHRy5jtCHGqvLntDjuy0MrhkpoHTpYEtwdOqGHA2qk+QnSGV5LoYldQ/UkAxSG7m8s2iOr11q2sWxUjrk2M3fgzAIxDeZRjJYeAr97eGANYva3jtGDfM6cJdieInBM4dEWWxKqGIh6HxOrY5K/ga26494vAwZAGvXRhZG48FOVp/XCr0mbu6V5pkEOzRJSc+hN5WKAs/c49UsfKPx75Ce7QbaBCZZT1UiczfyYx/mBuZuysUlGmnXPhLOLTPw4+SIizH/pOQyClOQyw== does not match signedString AMZN-PAY-RSASSA-PSS dfff7a87b93cfa78685a233f2dd59e18ad0451b2e3a90af11e500fcc0ceee924 for merchant XXXXXXXX
I was some time till I realized that this was the reason of the error. Actually, while writing this, the new lines in the string were the reason. If string is only in one line, it works.
The button only needs the payload and the signed payload. The $client->createCheckoutSession is not needed. More over, the checkoutSessionId of the resultCheckOut is different from the one obtained when the checkoutReviewReturnUrl is called.

Lumen doesn't return data when of all countries

Am trying to get list of all countries in lumen api but when i return all the data like this
echo json_encode([
'success' => true,
'data' => $results
]);
or
return json_encode([
'success' => true,
'data' => $results
]);
or
return response([
'success' => true,
'data' => $results
]);
i just get nothing no data no error
i only get data when i limit(15)
here is my function to get the list of countries
$output = [];
$database = \DB::table('country_t')
->select(['nameX3'])->get();
foreach ($database as $item) {
$name = $item->nameX3;
$toLowerCase = strtolower(trim($name));
$urlName = str_replace(' ', '-', $toLowerCase);
$output[] = [
'name' => $item->nameX3,
'url' => $urlName . '-simcards',
];
}
return response([
'success' => true,
'data' => $output
]);
So this function does not return anything except when i dd($output); or limit(15)
Please help
Thanks in advance.
Thanks to #porloscerros Ψ comment, I was able to get an error at least.
After I used return response()->json(['success' => true, 'data' => $output]); I got an error saying Malformed UTF-8 characters, possibly incorrectly encoded.
Issue is the data that is being encoded by json_encode contains even non-utf8 characters such as Russian words, etc.
To solve this issue I created a function that will encode this data using mb_convert_encoding, so I also had to make it handle even multidimensional array
function toUTF8( $mixed ) {
if (is_array($mixed)) {
foreach ($mixed as $key => $value) {
$mixed[$key] = toUTF8($value);
}
} elseif (is_string($mixed)) {
return mb_convert_encoding($mixed, "UTF-8", "UTF-8");
}
return $mixed;
}
Then calling the function
$this->toUTF8($output);
All in all if you have data that contains non-utf8 characters, you must encode the data.

Object of class could not be converted to int

I want to write phpunit test for save method at my repository. My repo code is:
public function saveCustomer(Custom $custom)
{
try
{
$custom->save();
return array(
'status' => true,
'customerId' => $custom->getId()
);
}
catch(\Exception $e)
{
return array(
'status' => false,
'customerId' => 0
);
}
}
I wrote this test:
public function testSaveNewUye()
{
$request = array(
'email' => 'www#www.com',
'phone' => '555 555 555',
'password' => '34636'
);
$repo = new CustomerRepository();
$result_actual = $this->$repo->saveCustomer($request);
$result_expected = array(
'status' => true,
'customerId' => \DB::table('custom')->select('id')->orderBy('id', 'DESC')->first() + 1
);
self::assertEquals($result_expected, $result_actual);
}
I got the error given below:
ErrorException: Object of class App\CustomerRepository could not be converted to int
Can you help me?
Problem is here:
$repo = new CustomerRepository();
$result_actual = $this->$repo->saveCustomer($request);
You are assigning and using variables not the same.
Try like this instead:
$this->repo = new CustomerRepository();
// ^------- assign to `$this`
$result_actual = $this->repo->saveCustomer($request);
// ^------- remove `$`
When doing $this->$repo-> PHP tries to convert the (object) $repo to a string $this->(object)-> which does not work.
Then you have a second error here:
\DB::table('custom')->select('id')->orderBy('id', 'DESC')->first() + 1
From the database you get an object (instanceof stdClass) which you cannot simply + 1.
The whole thing is probably something like
\DB::table('custom')->select('id')->orderBy('id', 'DESC')->first()->id + 1
(From the returned object, you want the property id.)

Laravel validation Error messages to string

I want to convert laravel validation error array to a comma separated string. This is to use in an api service for an ios application. So that the iOs developer can process error messages easily.
I tried,
$valArr = [];
foreach ($validator->errors() as $key => $value) {
$errStr = $key.' '.$value[0];
array_push($valArr, $errStr);
}
if(!empty($valArr)){
$errStrFinal = implode(',', $valArr);
}
But it is not working.
You should do like this :
$errorString = implode(",",$validator->messages()->all());
P.S. Assuming
$validator = Validator::make($dataToBeChecked,$validationArray,$messageArray)
The $validator->errors() returns a MessageBag,
see: https://laravel.com/api/5.3/Illuminate/Support/MessageBag.html.
You are close, you need to call the getMessages() function on errors(), so:
foreach ($validator->errors()->getMessages() as $key => $value) {
Hope this helps :)
You are not converting validation errors to array.Please use the below function and pass validation errors as parameter.
public function validationErrorsToString($errArray) {
$valArr = array();
foreach ($errArray->toArray() as $key => $value) {
$errStr = $key.' '.$value[0];
array_push($valArr, $errStr);
}
if(!empty($valArr)){
$errStrFinal = implode(',', $valArr);
}
return $errStrFinal;
}
//Function call.
$result = $this->validationErrorsToString($validator->errors());
If you are doing it like me without your validator and you are pulling messages from the exception you can use laravel helper Arr::flatten($array);
Link and code are for laravel 8.x but I tested this with 5.7 ;) It works.
From documentation:
use Illuminate\Support\Arr;
$array = ['name' => 'Joe', 'languages' => ['PHP', 'Ruby']];
$flattened = Arr::flatten($array);
// ['Joe', 'PHP', 'Ruby']
My code:
try {
$request->validate([
'test1' => 'required|integer',
'test2' => 'required|integer',
'test3' => 'required|string',
]);
} catch (ValidationException $validationException) {
return response()->json([
'type' => 'error',
'title' => $validationException->getMessage(),
'messages' => Arr::flatten($validationException->errors())
], $validationException->status);
} catch (\Exception $exception) {
return response()->json([
'type' => 'error',
'title' => $exception->getMessage(),
], $exception->getCode());
}
As you can see I am pulling the message and setting it as my title. Then I am using Arr::flatten($validationException->errors()) to get the validation messages and but to flatten my array for SweetAlert2 on the frontend.
I know I am late but I hope it will help someone that comes across these problems.
Greetings! :)

Categories