af86
af86

Reputation: 11

Laravel HTTP Client: Log in to website, then download file

I need to programmatically download a CSV file that is only available after you have logged in to a website.

When I try to accomplish this in Insomnia / Postman, it works perfectly, but I can't figure out how to accomplish this in Laravel. I suspect that I am not handling / utilizing my session cookie correctly.

This is what I do in Insomnia / Postman:

  1. I send a POST request to the website's login page, along with the username and password as multipart/form-data.
  2. I send a GET request the CSV file's URL and receive a long CSV string (content type: application/vnd.ms-excel)

This is EXACTLY what I need to do in Laravel, but I just can't seem to figure it out...

This is my code:

public static function getCSVFeed()
{
    $login = Http::withHeaders([
        "Content-Type" => "multipart/form-data",
    ])->post(config("csvfeed_login_url"), [
        "_username" => config("csvfeed_username"),
        "_password" => config("csvfeed_password"),
    ]);

    $sessionCookie = $login
        ->cookies()
        ->getCookieByName("PHPSESSID")
        ->toArray();

    $sessionCookieName = $sessionCookie["Name"];
    $sessionCookieValue = $sessionCookie["Value"];

    $response = Http::withHeaders([
        "Cookie" => $sessionCookieName . "=" . $sessionCookieValue,
    ])->get(config("csvfeed_url"));

    return $response;
}

When I execute this code, it does not return a CSV string, but the HTML of the website's 404 page, which suggests that I am not logged in.

Edit:

I did some more troubleshooting. I logged in manually in my browser and copied the 'PHPSESSID' cookie and hardcoded it in my GET request and I actually got a response that contained CSV!

This means that the login part is of my code is failing, even though I am doing the exact same thing I did in Insomnia / Postman.

When I go to Insomnia and copy my request as Curl, I get the following:

curl --request POST \
  --url **login URL** \
  --header 'Content-Type: multipart/form-data; boundary=---011000010111000001101001' \
  --form _username=**username** \
  --form '_password=**password**'

The only difference I can spot is the "boundary=---011000010111000001101001" part, but I do not know what that is or how to implement that in PHP.

Upvotes: 0

Views: 1411

Answers (1)

af86
af86

Reputation: 11

Credit goes to @CBroe

Turns out I was logging in incorrectly. The multipart/form-data header is not needed. I should have prefixed the post method with asForm() instead.

This is the working code:

public static function getCSVFeed(): array
{
    $login = Http::asForm()->post(config("csvfeed.login_url"), [
        "_username" => config("csvfeed.username"),
        "_password" => config("csvfeed.password"),
    ]);

    $sessionCookie = $login
        ->cookies()
        ->getCookieByName("PHPSESSID")
        ->toArray();

    $sessionCookieName = $sessionCookie["Name"];
    $sessionCookieValue = $sessionCookie["Value"];

    $response = Http::withHeaders([
        "Cookie" => $sessionCookieName . "=" . $sessionCookieValue,
    ])->get(config("csvfeed.url"));

    return str_getcsv($response, PHP_EOL);
}

Upvotes: 1

Related Questions