Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

broken content-length header upon captureOrder PHP #30

Open
jarielbalberona opened this issue Jan 17, 2025 · 3 comments
Open

broken content-length header upon captureOrder PHP #30

jarielbalberona opened this issue Jan 17, 2025 · 3 comments

Comments

@jarielbalberona
Copy link

jarielbalberona commented Jan 17, 2025

Everything works fine on my local setup with the sandbox environment.
I deployed the changes to my server and used a live environment, the Paypal buttons works fine but the Paypal card fields does not upon captureOrder.

createOrder response ~ PHP
{ "data": { "id": "6Jxxxxxx1U", "status": "CREATED", "links": [ { "href": "https://api.paypal.com/v2/checkout/orders/6Jxxxxxx1U", "rel": "self", "method": "GET" }, { "href": "https://www.paypal.com/checkoutnow?token=6Jxxxxxx1U", "rel": "approve", "method": "GET" }, { "href": "https://api.paypal.com/v2/checkout/orders/6Jxxxxxx1U", "rel": "update", "method": "PATCH" }, { "href": "https://api.paypal.com/v2/checkout/orders/6Jxxxxxx1U/capture", "rel": "capture", "method": "POST" } ] }, "status_code": 201, "message": "Success" }

Confirm payment source ~ React Paypal package API call response
{ "id": "6Jxxxxxx1U", "intent": "CAPTURE", "status": "APPROVED", "payment_source": { "card": { "name": "Jaxxxxna", "last_digits": "XXXX", "expiry": "XXX-03", "brand": "MASTERCARD", "available_networks": [ "MASTERCARD" ], "type": "CREDIT", "bin_details": { "bin": "54xxxx89", "issuing_bank": "XXX", "bin_country_code": "XX", "products": [ "PLATINUM" ] } } }, "purchase_units": [ { "reference_id": "XXXXXX", "amount": { "currency_code": "USD", "value": "1.00", "breakdown": { "item_total": { "currency_code": "USD", "value": "1.00" } } }, "payee": { "email_address": "[email protected]", "merchant_id": "xxxxxx" }, "description": "XXXXXX", "custom_id": "xxxxxx", "soft_descriptor": "" } ], "links": [ { "href": "https://api.paypal.com/v2/checkout/orders/6Jxxxxxx1U", "rel": "self", "method": "GET" }, { "href": "https://api.paypal.com/v2/checkout/orders/6Jxxxxxx1U/capture", "rel": "capture", "method": "POST" } ] }

captureOrder response PH

{ "data": null, "status_code": 400, "message": "broken content-length header" }

Again, the setup works on my local with sandbox mode.

@jarielbalberona
Copy link
Author

I could do captureOrder without using this package via rest API cURL.

@asadali214
Copy link

asadali214 commented Jan 23, 2025

Hey @jarielbalberona Can you also share the code snippet you used to execute the CreateOrder and CaptureOrder API calls using the PHP SDKs?

I also wanted to reproduce this issue on my end and I am interested in the requests you are trying to send using this PHP SDK. I want to see why the API returns the status 400 i.e. Bad Request

@nnebuchi
Copy link

I integrated PayPal checkout on my laravel application using paypal/paypal-server-sdk. each time I make a payment, the payment capture phase works well in my localhost but not on live server. Below is the log I get during the failed capture process:

PaypalServerSdkLib\Http\ApiResponse {#346 ▼ // app/Http/Controllers/PaypalController.php:125 #request: PaypalServerSdkLib\Http \ HttpRequest {#342 ▼ -httpMethod: "Post" -headers: array:8 [▼ "user-agent" => "PayPal REST API PHP SDK, Version: 0.6.0, on OS Linux-3.10.0-1160.118.1.el7.x86_64" "Content-Type" => "application/json" "PayPal-Request-Id" => null "Prefer" => "return=minimal" "PayPal-Client-Metadata-Id" => null "PayPal-Auth-Assertion" => null "Authorization" => "Bearer A21AAJv5HHortyBpVPt4vdP1uiuwBRIRoLUG6iTkANPydZQe9rGYjdLFXrnlMB4xQ4u-nSrbnMO8nBpeRgkpP9KSCI5rX2fZQ" "Accept" => "application/json" ] -queryUrl: "https://api-m.sandbox.paypal.com/v2/checkout/orders/8WP62399PN517611X/capture" -parameters: [] } -statusCode: 400 -reasonPhrase: null -headers: array:5 [▼ 0 => "HTTP/1.1 400 Invalid Request" "Connection" => "close" "Content-Length" => "28" "content-type" => "text/plain; charset=utf-8" "x-served-by" => "cache-fra-etou8220171" ] -result: "broken content-length header" -body: "broken content-length header" }

Kindly note that on both local and live server I am using the sandbox API.

Below is the controller class handling the payment:

`<?php

namespace App\Http\Controllers;

use App\Events\OrderCreated;
use App\Models\Order;
use App\Models\Transaction;
use Illuminate\Http\Request;
use PaypalServerSdkLib\Authentication\ClientCredentialsAuthCredentialsBuilder;
use PaypalServerSdkLib\Environment;
use PaypalServerSdkLib\PaypalServerSdkClientBuilder;
use PaypalServerSdkLib\Models\Builders\OrderRequestBuilder;
use PaypalServerSdkLib\Models\CheckoutPaymentIntent;
use PaypalServerSdkLib\Models\Builders\PurchaseUnitRequestBuilder;
use PaypalServerSdkLib\Models\Builders\AmountWithBreakdownBuilder;
use Illuminate\Support\Facades\Validator;

class PaypalController extends Controller
{
protected $client;

public function __construct()
{
    $PAYPAL_CLIENT_ID = env('PAYPAL_CLIENT_ID');
    $PAYPAL_CLIENT_SECRET = env('PAYPAL_CLIENT_SECRET');

    $this->client = PaypalServerSdkClientBuilder::init()
        ->clientCredentialsAuthCredentials(
            ClientCredentialsAuthCredentialsBuilder::init(
                $PAYPAL_CLIENT_ID,
                $PAYPAL_CLIENT_SECRET
            )
        )
        ->environment(Environment::SANDBOX)
        ->build();
}

/**
 * Create an order to start the transaction.
 */

public function createOrder(Request $request)
{
    $validator = Validator::make($request->all(), [
        'amount'    => 'required|numeric',
        'meal_title'=> 'required|string',
        'quantity'  => 'required|numeric|min:1',
        'extra_info'=> 'nullable|string',
        'phone'     => 'required|string',
        'email'     => 'required|email',
        'meal_id'   => 'required|numeric'
    ]);

    if ($validator->fails()) {
        return response()->json(['status' => 'fail', 'error' => $validator->errors()], 400);
    }

    // Save the order in the database
    $order = new Order();
    $order->meal_id = $request->meal_id;
    $order->quantity = $request->quantity;
    $order->total_price = $request->amount;
    $order->email = $request->email;
    $order->phone = $request->phone;
    $order->address = $request->address;
    $order->extra_info = $request->extra_info;
    $order->save();

    // Save the transaction
    $transaction = new Transaction();
    $transaction->order_id = $order->id;
    $transaction->amount = $order->total_price;
    $transaction->status = 'pending';
    $transaction->save();

    // Prepare the PayPal order
    $orderBody = [
        'body' => OrderRequestBuilder::init(
            CheckoutPaymentIntent::CAPTURE,
            [
                PurchaseUnitRequestBuilder::init(
                    AmountWithBreakdownBuilder::init('USD', $request->amount)
                        ->build()
                )->build()
            ]
        )->build()
    ];

    try {
        $apiResponse = $this->client->getOrdersController()->ordersCreate($orderBody);

        // Extract the PayPal order ID
        // $payPalOrderID = $apiResponse->getResult()->id;
        $payPalOrderID = $apiResponse->getResult()->getId();


        if (!$payPalOrderID) {
            throw new \Exception('Failed to create order in PayPal.');
        }

        // Return both the database order ID and the PayPal order ID
        return response()->json([
            'status' => 'success',
            'orderID' => $payPalOrderID, // PayPal order ID
            'localOrderId' => $order->id // Your database order ID
        ], 200);
    } catch (\Exception $e) {
        return response()->json(['error' => $e->getMessage()], 500);
    }
}


/**
 * Capture payment for the created order to complete the transaction.
 */
public function captureOrder($orderID, $local_order_id)
{
    $captureBody = [
        'id' => $orderID
    ];

    try {
        $apiResponse = $this->client->getOrdersController()->ordersCapture($captureBody);
        // dd($apiResponse);
        $transaction = Transaction::where('order_id', $local_order_id)->first();
        $transaction->status = 'completed';
        $transaction->save();

        $order = Order::where('id', $local_order_id)->with('meal')->first();
        $order->status = 'paid';
        $order->save();
        // dd($order);
        OrderCreated::dispatch($order);
        // dd($apiResponse->getResult());
        return response()->json($this->handleResponse($apiResponse, $transaction), 200);
    } catch (\Exception $e) {
        return response()->json(['error' => $e->getMessage()], 500);
    }
}


/**
 * Handle API response.
 */
private function handleResponse($response, $extraData = null)
{   
    return [
        'jsonResponse' => $response->getResult(),
        'httpStatusCode' => $response->getStatusCode(),
        'extraData' => $extraData
    ];
}

/**
 * Health check endpoint.
 */
public function healthCheck()
{
    return response()->json(['message' => 'Server is running'], 200);
}

}
`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants