I am trying to convert this cURL script to use it with PHP and Guzzle. I have been able to set the cookie as shown below but I cannot send the xml file I need to afterwards.
cURL Script
# First, we need to get the cookie
curl [-k] –dump-header <header_file> -F “action=login” -F “username=<username>” -F “password=<password>” https://<website_URL>
# Then, we can use that cookie to upload our orders
# XML Order Upload
curl -b <header_file> -F “import=#<order_file>” http://<website_URL>/importXMLOrder.php
This is what I have that sets the cookie. I am not sure what the next part is to actually send the xml file I have.
$client = new \GuzzleHttp\Client();
$response = $client->post('http://website/login.php', array(
'body' => array(
'username' => 'xxxxx',
'password' => 'xxxxxx'
))
);
I have also tried this. However, I get an error message:
Call to undefined method GuzzleHttp\Message\Response::send()
$request = $client->post('http://website.com/import.php', array(
'body' => array(
'file_filed' => fopen('orders.xml', 'r')
)));
$response = $request->send();
$data = $response->xml();
print_r($data);
Update
$request = $client->createRequest('POST','http://website.com/import.php', array(
'body' => array(
'file_filed' => file_get_contents('orders.xml', 'r')
)
));
$response = $client->send($request);
//var_dump($response); die;
$data = $response->xml();
echo '<pre>';
print_r($data);
It looks like you are calling send() from the wrong class. send() is a method of \GuzzleHttp\Client. So you need to do $client->send() instead.
However, $client->post() sends the request as soon as it creates it. If you want to use send() then you'll need to replace post() with createRequest(), as seen here: http://guzzle.readthedocs.org/en/latest/clients.html#creating-requests
You'll also have problems with the call to fopen() which returns a file handle instead of the contents. Try file_get_contents() instead.
Edit:
In order to set the auth cookie, you'll need a cookie jar. Try the following:
$client = new \GuzzleHttp\Client();
$auth = $client->post('http://website/login.php', array(
'body' => array(
'username' => 'xxxxx',
'password' => 'xxxxxx'
),
'cookies' => true
));
Using the same Client:
$request = $client->createRequest('POST','http://website.com/import.php', array(
'body' => array(
'file_filed' => file_get_contents('orders.xml')
),
'cookies' => true
));
$response = $client->send($request);
//var_dump($response); die;
$data = $response->xml();
echo '<pre>';
print_r($data);
Related
I'm writing API Client, but I can't send files via pecl_http. I wrote everything on http\Client. Most things by copy Postman things, but when I send I get null files. How should I send it? how I should put into this script my $_FILES variable with data?
<?php
$client = new http\Client;
$request = new http\Client\Request;
$body = new http\Message\Body;
$body->addForm(NULL, array(
array(
'name' => 'photo',
'type' => null,
'file' => 'user_path/2018-11-09 o 15.00.48.png',
'data' => null
)
));
$request->setRequestUrl('url');
$request->setRequestMethod('POST');
$request->setBody($body);
$request->setHeaders(array(
'Postman-Token' => 'f6154fff-46f4-47d0-a7c3-98d7de8d0f24',
'Cache-Control' => 'no-cache',
'Content-Type' => 'application/x-www-form-urlencoded'
));
$client->enqueue($request)->send();
$response = $client->getResponse();
echo $response->getBody();
Here is part of the code I found in: Pecl_http Tutorial
<?php
$r = new HttpRequest('http://dev.iworks.at/.print_request.php', HTTP_METH_POST);
// if redirects is set to true, a single redirect is allowed;
// one can set any reasonable count of allowed redirects
$r->setOptions(
array( 'cookies' => array('MyCookie' => 'has a value'),
'redirect' => true,
)
);
// common form data
$r->setPostFields(
array( 'name' => 'Mike',
'mail' => 'mike#php.net',
)
);
// add the file to post (form name, file name, file type)
touch('profile.jpg');
$r->addPostFile('image', 'profile.jpg', 'image/jpeg');
try {
print $r->send()->getBody();
} catch (HttpException $e) {
print $e;
}
?>
I'm using the Azure OCR Service to get the text of an image back (
https://learn.microsoft.com/de-de/azure/cognitive-services/Computer-vision/QuickStarts/PHP).
So far everything is up and running, but now I would like to use a local file instead of an already uploaded one.
$url->setQueryVariables($parameters);
$request->setMethod(HTTP_Request2::METHOD_POST);
// Request body
$request->setBody("{body}"); // Replace with the body, for example, "{"url": "http://www.example.com/images/image.jpg"}
Unfortunately I don't know how to pass the raw binary as the body of my POST request in PHP.
At first, when we refer local file, we should use 'Content-Type': 'application/octet-stream' in a header, then we can send requests that use a stream resource as the body.
Here's my working code using Guzzle for your reference:
<?php
require 'vendor/autoload.php';
$resource = fopen('./Shaki_waterfall.jpg', 'r');
$client = new \GuzzleHttp\Client();
$res = $client->request('POST', 'https://westus.api.cognitive.microsoft.com/vision/v1.0/analyze', [
'query' => [
'visualFeatures' => 'Categories',
'details' => '',
'language' => 'en'
],
'headers' => [
'Content-Type' => 'application/octet-stream',
'Ocp-Apim-Subscription-Key' => '<Ocp-Apim-Subscription-Key>'
],
'body' => $resource
]);
echo $res->getBody();
Using HTTP_Request2:
<?php
require_once 'HTTP/Request2.php';
$request = new Http_Request2('https://westus.api.cognitive.microsoft.com/vision/v1.0/analyze');
$url = $request->getUrl();
$headers = array(
'Content-Type' => 'application/octet-stream',
'Ocp-Apim-Subscription-Key' => '<Ocp-Apim-Subscription-Key>',
);
$request->setHeader($headers);
$parameters = array(
'visualFeatures' => 'Categories',
'details' => '',
'language' => 'en',
);
$url->setQueryVariables($parameters);
$request->setMethod(HTTP_Request2::METHOD_POST);
$request->setBody(fopen('./Shaki_waterfall.jpg', 'r'));
try {
$response = $request->send();
echo $response->getBody();
} catch (HttpException $ex) {
echo $ex;
}
I want to migrate from pure CURL to Guzzle, but the API calls are not being registered correctly.
Working CURL (Class from here: https://stackoverflow.com/a/7716768/8461611)
...
$Curl = new CURL(); // setting all curl_opts there
// creating session
$session = explode(";", $Curl->post("http://www.share-online.biz/upv3_session.php", "username=".$un."&password=".$pw));
$session_key = $session[0];
$upload_server = $session[1];
// upload
$vars = ... // see below
var_dump(explode(";",$Curl->post($upload_server, $vars))); // works
Now the Guzzle stuff
...
$Curl = new GuzzleHttp\Client();
$jar = new GuzzleHttp\Cookie\FileCookieJar("cookie.txt", true);
//creating session
$session = explode(";", $Curl->request('POST', "http://www.share-online.biz/upv3_session.php",
["form_params" => ["username" => $un, "password" => $pw], 'cookies' => $jar])->getBody());
$session_key = $session[0];
$upload_server = $session[1];
$vars = ["username" => $un,
"password" => $pw,
"upload_session" => $session_key,
"chunk_no" => 1,
"chunk_number" => 1,
"filesize" => filesize($file),
"fn" => new CurlFile(realpath($file)),
"finalize" => 1,
"name" => "test",
"contents" => $file,
];
var_dump(
explode(";",$Curl->request(
'POST', "http://".$upload_server, ["multipart" => [$vars], 'cookies' => $jar])
->getBody()));
// outputs *** EXCEPTION session creation/reuse failed - 09-3-2017, 3:05 am ***
I assume I'm doing something wrong with cookies. They are being set as var_dump($jar); shows. API Docs : http://www.share-online.biz/uploadapi
First of all, Guzzle is not curl and cannot behave like curl. The only caveat is that it uses curl behind the scenes.
Here is the solution:
use GuzzleHttp\Client;
$client = new Client([
// Base URI is used with relative requests
'base_uri' => 'http://www.share-online.biz/',
'timeout' => 2.0,
]);
$response = $client->request('POST', 'upv3_session.php',
[
'form_params' => [
"username" => $un,
"password" => $pw
]
]
);
Use the output of your request like so:
$code = $response->getStatusCode(); // 200 || 400 | 500 etc
$reason = $response->getReasonPhrase();
$body = $response->getBody();
$response = $request->getBody(); //Explicitly cast to string.
$json_response = json_decode($response); //here the string response has be decoded to json string.
I hope it helps others that facing this situation
First of all, you have to call ...->getBody()->getContents() to get a string. Or cast body object to a string: (string) ...->getBody().
Then, you cannot use CurlFile class. Use fopen() to get a file handle and pass it directly to Guzzle like in the docs. Pay attentions that for file uploads you have to use multipart instead of form_params.
I am using Guzzle (v6.1.1) in PHP to make a POST request to a server. It works fine. I am adding some logging functions to log what was sent and received and I can't figure out how to get the data that Guzzle sent to the server. I can get the response just fine, but how do I get the sent data? (Which would be the JSON string.)
Here is the relevant portion of my code:
$client = new GuzzleHttp\Client(['base_uri' => $serviceUrlPayments ]);
try {
$response = $client->request('POST', 'Charge', [
'auth' => [$securenetId, $secureKey],
'json' => [ "amount" => $amount,
"paymentVaultToken" => array(
"customerId" => $customerId,
"paymentMethodId" => $token,
"publicKey" => $publicKey
),
"extendedInformation" => array(
"typeOfGoods" => $typeOfGoods,
"userDefinedFields" => $udfs,
"notes" => $Notes
),
'developerApplication'=> $developerApplication
]
]);
} catch (ServerErrorResponseException $e) {
echo (string) $e->getResponse()->getBody();
}
echo $response->getBody(); // THIS CORRECTLY SHOWS THE SERVER RESPONSE
echo $client->getBody(); // This doesn't work
echo $client->request->getBody(); // nor does this
Any help would be appreciated. I did try to look in Guzzle sourcecode for a function similar to getBody() that would work with the request, but I'm not a PHP expert so I didn't come up with anything helpful. I also searched Google a lot but found only people talking about getting the response back from the server, which I have no trouble with.
You can do this work by creating a Middleware.
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use Psr\Http\Message\RequestInterface;
$stack = HandlerStack::create();
// my middleware
$stack->push(Middleware::mapRequest(function (RequestInterface $request) {
$contentsRequest = (string) $request->getBody();
//var_dump($contentsRequest);
return $request;
}));
$client = new Client([
'base_uri' => 'http://www.example.com/api/',
'handler' => $stack
]);
$response = $client->request('POST', 'itemupdate', [
'auth' => [$username, $password],
'json' => [
"key" => "value",
"key2" => "value",
]
]);
This, however, is triggered before to receive the response. You may want to do something like this:
$stack->push(function (callable $handler) {
return function (RequestInterface $request, array $options) use ($handler) {
return $handler($request, $options)->then(
function ($response) use ($request) {
// work here
$contentsRequest = (string) $request->getBody();
//var_dump($contentsRequest);
return $response;
}
);
};
});
Using Guzzle 6.2.
I've been struggling with this for the last couple days too, while trying to build a method for auditing HTTP interactions with different APIs. The solution in my case was to simply rewind the request body.
The the request's body is actually implemented as a stream. So when the request is sent, Guzzle reads from the stream. Reading the complete stream moves the stream's internal pointer to the end. So when you call getContents() after the request has been made, the internal pointer is already at the end of the stream and returns nothing.
The solution? Rewind the pointer to the beginning and read the stream again.
<?php
// ...
$body = $request->getBody();
echo $body->getContents(); // -->nothing
// Rewind the stream
$body->rewind();
echo $body->getContents(); // -->The request body :)
My solution for Laravel from 5.7:
MessageFormatter works with variable substitutions, see this: https://github.com/guzzle/guzzle/blob/master/src/MessageFormatter.php
$stack = HandlerStack::create();
$stack->push(
Middleware::log(
Log::channel('single'),
new MessageFormatter('Req Body: {request}')
)
);
$client = new Client();
$response = $client->request(
'POST',
'https://url.com/go',
[
'headers' => [
"Content-Type" => "application/json",
'Authorization' => 'Bearer 123'
],
'json' => $menu,
'handler' => $stack
]
);
You can reproduce the data string created by the request by doing
$data = array(
"key" => "value",
"key2" => "value",
);
$response = $client->request('POST', 'itemupdate', [
'auth' => [$username, $password],
'json' => $data,
]);
// ...
echo json_encode($data);
This will output your data as JSON string.
Documentation at http://php.net/manual/fr/function.json-encode.php
EDIT
Guzzle has a Request and a Response class (and many other).
Request has effectively a getQuery() method that returns an object containing your data as private, same as all other members.
Also you cannot access it.
This is why I think manually encode it is the easier solution.
If you want know what is done by Guzzle, it also have a Collection class that transform data and send it in request.
I have to send information to an external website using cURL. I set up Guzzle on my Laravel application. I have the basics set up, but according to the documentation of the website, there is an action that's required for the username and password. How can I pass the 'action' along with the credentials needed to log in and get access?
The website states:
curl [-k] –dump-header <header_file> -F “action=login” -F “username=<username>” -F “password=<password>” https://<website_URL>
My controller:
$client = new \GuzzleHttp\Client();
$response = $client->get('http://website.com/page/login/', array(
'auth' => array('username', 'password')
));
$xml = $response;
echo $xml;
The website will load on the echo, but it will only pull up the login screen. I need those credentials to bypass the login screen (with a successful login) to get to the portion of information I need for cURL.
curl -F submits a POST request instead of a GET request. So you'll need to modify your code accordingly, something like
$client = new \GuzzleHttp\Client();
$response = $client->post('http://website.com/page/login/', [
'body' => [
'username' => $username,
'password' => $password,
'action' => 'login'
],
'cookies' => true
]
);
$xml = $response;
echo $xml;
See http://guzzle.readthedocs.org/en/latest/quickstart.html#post-requests, http://curl.haxx.se/docs/manpage.html#-F
Edit:
Just add ['cookies' => true] to requests in order to use the auth cookie associated with this GuzzleHttp\Client(). http://guzzle.readthedocs.org/en/latest/clients.html#cookies
$response2 = $client->get('http://website.com/otherpage/', ['cookies' => true]);
I was having trouble getting #JeremiahWinsley's answer to work on newer version of Guzzle so I've updated their code to work as of Guzzle 5.x.
Three major changes are required
Using form_params instead of body to prevent the error "Passing in the "body" request option as an array to send a POST request has been deprecated."
Changing the cookies to use the CookieJar object
Use ->getBody()->getContents() to get the body of the request
Here is the updated code:
$client = new \GuzzleHttp\Client();
$cookieJar = new \GuzzleHttp\Cookie\CookieJar();
$response = $client->post('http://website.com/page/login/', [
'form_params' => [
'username' => $username,
'password' => $password,
'action' => 'login'
],
'cookies' => $cookieJar
]
);
$xml = $response->getBody()->getContents();
echo $xml;
And to continue using cookies in future requests, pass in the cookieJar to the request:
$response2 = $client->get('http://website.com/otherpage/', ['cookies' => $cookieJar]);
I was having trouble getting #JeremiahWinsley's and #Samsquanch's answer to work on newer version of Guzzle. So I've updated the code to work as of Guzzle 6.x.
Guzzle 6.x. documents: http://docs.guzzlephp.org/en/stable/index.html
Here is the updated code:
use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJar;
try {
$client = new Client();
$cookieJar = new CookieJar();
$response = $client->request('POST', 'http://website.com/page/login/', [
'form_params' => [
'username' => 'test#example.com',
'password' => '123456'
],
'cookies' => $cookieJar
]);
$response2 = $client->request('GET', 'http://website.com/otherpage/', [
'cookies' => $cookieJar
]);
if ($response2->getStatusCode() == 200) {
return $response2->getBody()->getContents();
} else {
return "Oops!";
}
} catch (\Exception $exception) {
return 'Caught exception: ', $exception->getMessage();
}