phpguzzlelaminas

Unable to post using GuzzleHttp: Error: Header value must be scalar or null but array provided


I'm trying to post the following html form using GuzzleHttp but I'm unable to do so because of the error while setting the form_params in the header. InvalidArgumentException: Header value must be scalar or null but array provided.

<form action="https://example.com/process" method="post">
 <input type="hidden" name="data" value="<?php echo $base64_encrypted_json; ?>”>
<?php foreach($items_encoded as $item) { ?>
 <input type="hidden" name="item_data[]" value="<?php echo $item; ?>”>
<?php } ?>
 <input type="hidden" name="rid" value="example">
 <input type="submit">
</form>

Here's my code in the constructor.

        $this->setRequest(
            new Request(
                "POST",
                $this->getConfig()->get(Module::MODULE_ENDPOINT_URL)["submit"]
            )
        );

        /** @var array $submitDataArray */
        $submitDataArray = $this->getConfig()->get(Module::MODULE_SUBMIT_REQUEST_DATA_CONFIG)->toArray();
        $submitDataArray["data"] = json_encode($submitDataArray["data"]);

        /** @var array $splitItemsData */
        $splitItemsData = str_split(json_encode($submitDataArray["itemData"], true), 800);
        /** @var array $itemDataEncoded */
        $itemDataEncoded = [];
        foreach ($splitItemsData as $itemDataString) {
            $itemDataEncoded[] = json_encode($itemDataString);
        }
        $submitDataArray["itemData"] = $itemDataEncoded;
        $submitDataModel = (new SubmitDataModel())->exchangeArray($submitDataArray);
        $this->setSubmitDataModel($submitDataModel);

And here's my init() method.

    public function init(): void
    {
        /** @var array $submitDataModel */
        $submitDataModel = $this->getSubmitDataModel()->exchangeArray();

        /** @var array $formParams */
        $formParams = array();
        $formParams["rid"] = $submitDataModel["rid"];
        $formParams["data"] = $submitDataModel["data"];
        $formParams["item_data"] = $submitDataModel["itemData"];

        $this->getRequest()->withHeader("Content-Type", "application/x-www-form-urlencoded");
        $this->getRequest()->withHeader("form_params", $formParams);
    }

The $submitDataArray is as below

rid = "sandbox"
data = "{"username":"sandbox","request_data":{"return_urls":{"abort":"https:\/\/example.com\/checkout\/abort","fail":"https:\/\/example.com\/checkout\/rejected","success":"https:\/\/example.com\/checkout\/success","return_data":"https:\/\/example.com\/c832jdafs94kb"},"request_type":"standard_finance_request","test_mode":1,"order_details":{"order_id":"","currency":"GBP"},"customer_details":{"firstnames":"","surname":"","email":"","phone":"","address":"","city":"","country":"","postcode":"","dob":"","delivery_address":"","delivery_city":"","delivery_postcode":"","delivery_country":"UK"}}}"
itemData = {array} [1]
 0 = ""[{\"description\":\"\",\"quantity\":0,\"price\":0}]""

I've skipped some unnecessary details for the sake of staying concise.

Update: I've also tried multipart to handle the array but still no help.

        $this->getRequest()->withHeader("Content-Type", "multipart/form-data");
        $this->getRequest()->withHeader("multipart", $formParams);

Solution

  • Thanks to @ITgoldman for the lead. I've refactored part of my code as below and it has worked for me.

            $this->getRequest()->withHeader("Content-Type", "application/x-www-form-urlencoded");
            $this->getRequest()->withBody(\GuzzleHttp\Psr7\Utils::Streamfor(http_build_query($formParams)));
    

    Here's how it works. http_build_query() function converts an array into a query string which can then be converted into a \Psr\Http\Message\StreamInterface using \GuzzleHttp\Psr7\Utils::Streamfor() method to be used with withBody() method.